blyuecode 0.3.1 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ui/Chat.js CHANGED
@@ -8,6 +8,7 @@ import { Agent } from '../core/agent.js';
8
8
  import { permissions } from '../core/permission.js';
9
9
  import { InputBar } from './InputBar.js';
10
10
  import { ModelPicker } from './ModelPicker.js';
11
+ import { McpPanel } from './McpPanel.js';
11
12
  import { Settings } from './Settings.js';
12
13
  import { PermissionPrompt } from './PermissionPrompt.js';
13
14
  import { Spinner } from './Spinner.js';
@@ -127,6 +128,11 @@ export const Chat = ({ resumedCount = 0 }) => {
127
128
  setOverlay('settings');
128
129
  return;
129
130
  }
131
+ if (trimmed === '/mcp') {
132
+ setInput('');
133
+ setOverlay('mcp');
134
+ return;
135
+ }
130
136
  if (trimmed === '/debug') {
131
137
  setInput('');
132
138
  const lines = readDebug();
@@ -172,6 +178,7 @@ export const Chat = ({ resumedCount = 0 }) => {
172
178
  mkItem('tool', 'Commands:'),
173
179
  mkItem('tool', ' /model switch model (Ctrl+L)'),
174
180
  mkItem('tool', ' /settings open settings (Ctrl+O)'),
181
+ mkItem('tool', ' /mcp show MCP servers and tools'),
175
182
  mkItem('tool', ' /compact summarize history to free context'),
176
183
  mkItem('tool', ' /debug show last request to provider'),
177
184
  mkItem('tool', ' /clear clear session and permissions'),
@@ -246,6 +253,9 @@ export const Chat = ({ resumedCount = 0 }) => {
246
253
  if (overlay === 'model') {
247
254
  return (_jsx(Box, { flexDirection: "column", children: _jsx(ModelPicker, { current: currentModel, onSelect: handleModelSelect, onCancel: () => setOverlay('none') }) }));
248
255
  }
256
+ if (overlay === 'mcp') {
257
+ return (_jsx(Box, { flexDirection: "column", children: _jsx(McpPanel, { onClose: () => setOverlay('none') }) }));
258
+ }
249
259
  if (overlay === 'settings') {
250
260
  return (_jsx(Box, { flexDirection: "column", children: _jsx(Settings, { onClose: () => setOverlay('none'), onModelChange: (m) => {
251
261
  setCurrentModel(m);
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState, useEffect } from 'react';
3
+ import { Box, Text, useInput, useStdout } from 'ink';
4
+ import { listMcpServers, initMcpRegistry, closeAllMcp, } from '../core/mcpRegistry.js';
5
+ import { mcpConfigPath } from '../core/mcp.js';
6
+ import { theme } from './theme.js';
7
+ export const McpPanel = ({ onClose }) => {
8
+ const { stdout } = useStdout();
9
+ const width = Math.max(40, stdout?.columns ?? 60);
10
+ const inner = width - 4;
11
+ const [servers, setServers] = useState(() => listMcpServers());
12
+ const [reloading, setReloading] = useState(false);
13
+ const [msg, setMsg] = useState(null);
14
+ // Refresh list on mount in case registry changed since last render.
15
+ useEffect(() => {
16
+ setServers(listMcpServers());
17
+ }, []);
18
+ const reload = async () => {
19
+ setReloading(true);
20
+ setMsg(null);
21
+ try {
22
+ await closeAllMcp();
23
+ await initMcpRegistry();
24
+ setServers(listMcpServers());
25
+ setMsg('✓ reloaded');
26
+ }
27
+ catch (err) {
28
+ setMsg('✗ ' + err.message);
29
+ }
30
+ setReloading(false);
31
+ };
32
+ useInput((input, key) => {
33
+ if (key.escape)
34
+ return onClose();
35
+ if (input === 'r' || input === 'R') {
36
+ if (!reloading)
37
+ void reload();
38
+ }
39
+ });
40
+ const label = 'mcp servers';
41
+ const topPad = Math.max(1, inner - label.length - 4);
42
+ const totalTools = servers.reduce((n, s) => n + s.toolCount, 0);
43
+ const healthy = servers.filter((s) => !s.error).length;
44
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children: [_jsx(Text, { color: theme.muted, children: '╭─ ' }), _jsx(Text, { color: theme.accent, bold: true, children: label }), _jsx(Text, { color: theme.muted, children: ' ' + '─'.repeat(topPad) + '╮' })] }), _jsxs(Text, { children: [_jsx(Text, { color: theme.muted, children: '│ ' }), _jsxs(Text, { color: theme.muted, children: ["config: ", mcpConfigPath()] })] }), _jsxs(Text, { children: [_jsx(Text, { color: theme.muted, children: '│ ' }), _jsxs(Text, { color: theme.muted, children: [servers.length, " server", servers.length === 1 ? '' : 's', " \u00B7", ' '] }), _jsxs(Text, { color: healthy === servers.length ? theme.success : theme.warning, children: [healthy, " connected"] }), _jsxs(Text, { color: theme.muted, children: [" \u00B7 ", totalTools, " tools"] })] }), _jsx(Text, { color: theme.muted, children: '│ ' + '─'.repeat(Math.max(1, inner - 2)) }), servers.length === 0 ? (_jsxs(_Fragment, { children: [_jsxs(Text, { children: [_jsx(Text, { color: theme.muted, children: '│ ' }), _jsx(Text, { color: theme.warning, children: "no MCP servers configured" })] }), _jsxs(Text, { children: [_jsx(Text, { color: theme.muted, children: '│ ' }), _jsxs(Text, { color: theme.muted, children: ["add one to ", mcpConfigPath(), " then press [r]"] })] })] })) : (servers.map((s) => {
45
+ const status = s.error ? '✗' : '●';
46
+ const statusColor = s.error ? theme.error : theme.success;
47
+ const autoTag = s.autoAllow ? ' [auto]' : '';
48
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children: [_jsx(Text, { color: theme.muted, children: '│ ' }), _jsx(Text, { color: statusColor, children: status + ' ' }), _jsx(Text, { color: theme.text, bold: true, children: s.name }), _jsxs(Text, { color: theme.muted, children: [autoTag, " \u00B7 ", s.toolCount, " tool", s.toolCount === 1 ? '' : 's'] })] }), s.error ? (_jsxs(Text, { children: [_jsx(Text, { color: theme.muted, children: '│ ' }), _jsx(Text, { color: theme.error, children: s.error.slice(0, inner - 6) })] })) : (s.toolNames.slice(0, 4).map((t) => (_jsxs(Text, { children: [_jsx(Text, { color: theme.muted, children: '│ · ' }), _jsx(Text, { color: theme.muted, children: t })] }, t)))), !s.error && s.toolNames.length > 4 && (_jsx(Text, { children: _jsx(Text, { color: theme.muted, children: '│ · +' + (s.toolNames.length - 4) + ' more' }) }))] }, s.name));
49
+ })), _jsx(Text, { color: theme.muted, children: '╰' + '─'.repeat(inner) + '╯' }), _jsxs(Text, { children: [_jsx(Text, { color: theme.muted, children: " [" }), _jsx(Text, { color: theme.accent, children: "r" }), _jsx(Text, { color: theme.muted, children: "] reload \u00B7 [" }), _jsx(Text, { color: theme.accent, children: "esc" }), _jsx(Text, { color: theme.muted, children: "] close" }), reloading && _jsx(Text, { color: theme.warning, children: " \u00B7 reloading\u2026" }), msg && _jsxs(Text, { color: theme.success, children: [" \u00B7 ", msg] })] })] }));
50
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blyuecode",
3
- "version": "0.3.1",
3
+ "version": "0.3.4",
4
4
  "description": "BLYUE Code — a coding agent by Lumen",
5
5
  "type": "module",
6
6
  "license": "MIT",