@chatpanel/bridge 0.10.4 → 0.10.6
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/package.json +1 -1
- package/src/engines/cli-agents.js +9 -2
- package/src/engines/custom.js +59 -2
- package/src/env.js +2 -2
- package/src/server.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chatpanel/bridge",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Local bridge that exposes the AI coding agents installed on your machine — Claude Code (CLI), Codex (CLI), and Gemini CLI — to the ChatPanel Chrome extension over a localhost SSE endpoint. Bring your own agent.",
|
|
6
6
|
"keywords": [
|
|
@@ -15,7 +15,9 @@ import { findAgentBin } from '../env.js';
|
|
|
15
15
|
function makeCliAgent(command, spec, notFoundHint) {
|
|
16
16
|
let installed = false;
|
|
17
17
|
let lastProbe = 0;
|
|
18
|
+
const resolvedSpec = { ...spec, command };
|
|
18
19
|
return {
|
|
20
|
+
spec: resolvedSpec,
|
|
19
21
|
async available() {
|
|
20
22
|
// Cache a positive result; re-probe (throttled) while not found so it
|
|
21
23
|
// self-heals once the CLI appears on PATH.
|
|
@@ -33,7 +35,7 @@ function makeCliAgent(command, spec, notFoundHint) {
|
|
|
33
35
|
return listSpecModels(command, spec.listModelsArgs, options.workingDir);
|
|
34
36
|
},
|
|
35
37
|
chat(input, emit) {
|
|
36
|
-
return runSpec(
|
|
38
|
+
return runSpec(resolvedSpec, input, emit);
|
|
37
39
|
},
|
|
38
40
|
};
|
|
39
41
|
}
|
|
@@ -67,6 +69,7 @@ export const opencode = makeCliAgent(
|
|
|
67
69
|
// with `opencode mcp add chatpanel --url http://127.0.0.1:4319/mcp` (opencode
|
|
68
70
|
// only loads MCP from its global config, not a per-run file).
|
|
69
71
|
requiresStableMcp: true,
|
|
72
|
+
stableMcpConfigCheck: 'opencode',
|
|
70
73
|
listModelsArgs: 'models',
|
|
71
74
|
label: 'OpenCode',
|
|
72
75
|
},
|
|
@@ -76,9 +79,13 @@ export const opencode = makeCliAgent(
|
|
|
76
79
|
export const kiro = makeCliAgent(
|
|
77
80
|
'kiro-cli',
|
|
78
81
|
{
|
|
79
|
-
args: 'chat --no-interactive',
|
|
82
|
+
args: 'chat --no-interactive --require-mcp-startup',
|
|
80
83
|
promptVia: 'arg',
|
|
81
84
|
modelArg: '--model {model}',
|
|
85
|
+
trustToolsArg: '--trust-tools={tools}',
|
|
86
|
+
requiresStableMcp: true,
|
|
87
|
+
stableMcpConfigCheck: 'kiro',
|
|
88
|
+
stableMcpSetupCommand: 'kiro-cli mcp add --scope global --name chatpanel_browser --url http://127.0.0.1:4319/mcp --force',
|
|
82
89
|
listModelsArgs: '--list-models',
|
|
83
90
|
label: 'Kiro',
|
|
84
91
|
},
|
package/src/engines/custom.js
CHANGED
|
@@ -66,6 +66,7 @@ const IDLE_MS = Number(process.env.CHATPANEL_CUSTOM_TIMEOUT_MS) || 180_000;
|
|
|
66
66
|
const ANSI_RE = /\u001b\[[0-9;?]*[ -/]*[@-~]/g;
|
|
67
67
|
const stripAnsi = (s) => s.replace(ANSI_RE, '');
|
|
68
68
|
const OPENCODE_STABLE_MCP_URL = 'http://127.0.0.1:4319/mcp';
|
|
69
|
+
const CHATPANEL_STABLE_MCP_URL = 'http://127.0.0.1:4319/mcp';
|
|
69
70
|
|
|
70
71
|
export async function available() {
|
|
71
72
|
// The engine ships in every bridge; individual custom agents are user-defined
|
|
@@ -139,6 +140,21 @@ export function piToolArgs(extensionFile, mcp) {
|
|
|
139
140
|
return ['--extension', extensionFile];
|
|
140
141
|
}
|
|
141
142
|
|
|
143
|
+
export function trustToolArgs(template, mcp) {
|
|
144
|
+
const tmpl = String(template || '').trim();
|
|
145
|
+
const names = mcpToolSpecs(mcp).map((s) => s.name).filter(Boolean);
|
|
146
|
+
if (!tmpl || !names.length) return [];
|
|
147
|
+
const value = names.join(',');
|
|
148
|
+
return tmpl.includes('{tools}')
|
|
149
|
+
? tmpl.replaceAll('{tools}', value).split(/\s+/).filter(Boolean)
|
|
150
|
+
: [...tmpl.split(/\s+/).filter(Boolean), value];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function stableMcpSetupCommand(spec = {}) {
|
|
154
|
+
if (spec.stableMcpSetupCommand) return spec.stableMcpSetupCommand;
|
|
155
|
+
return `opencode mcp add chatpanel --url ${CHATPANEL_STABLE_MCP_URL}`;
|
|
156
|
+
}
|
|
157
|
+
|
|
142
158
|
export function buildPiExtensionSource(mcp) {
|
|
143
159
|
const specs = mcpToolSpecs(mcp);
|
|
144
160
|
const declarations = specs.map((spec, index) => {
|
|
@@ -240,6 +256,44 @@ async function opencodeHasStableMcpConfig() {
|
|
|
240
256
|
return false;
|
|
241
257
|
}
|
|
242
258
|
|
|
259
|
+
async function commandStdout(command, args, cwd) {
|
|
260
|
+
const resolved = resolveCommand(command);
|
|
261
|
+
if (!resolved) return '';
|
|
262
|
+
const [bin, argv, opts] = buildSpawnSpec(resolved, args, cwd || null);
|
|
263
|
+
return new Promise((resolve) => {
|
|
264
|
+
const child = spawn(bin, argv, opts);
|
|
265
|
+
let out = '';
|
|
266
|
+
const timer = setTimeout(() => {
|
|
267
|
+
child.kill('SIGKILL');
|
|
268
|
+
resolve(out);
|
|
269
|
+
}, 4000);
|
|
270
|
+
child.stdout.on('data', (d) => (out += d.toString()));
|
|
271
|
+
child.on('error', () => {
|
|
272
|
+
clearTimeout(timer);
|
|
273
|
+
resolve('');
|
|
274
|
+
});
|
|
275
|
+
child.on('close', () => {
|
|
276
|
+
clearTimeout(timer);
|
|
277
|
+
resolve(out);
|
|
278
|
+
});
|
|
279
|
+
try { child.stdin.end(); } catch { /* ignore */ }
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async function kiroHasStableMcpConfig(command, cwd) {
|
|
284
|
+
for (const scope of ['workspace', 'global', 'default']) {
|
|
285
|
+
const out = await commandStdout(command, ['mcp', 'list', scope], cwd);
|
|
286
|
+
if (out.includes(CHATPANEL_STABLE_MCP_URL) || /chatpanel_browser/i.test(out)) return true;
|
|
287
|
+
}
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async function hasStableMcpConfig(spec, cwd) {
|
|
292
|
+
if (spec.stableMcpConfigCheck === 'kiro') return kiroHasStableMcpConfig(spec.command || 'kiro-cli', cwd);
|
|
293
|
+
if (spec.stableMcpConfigCheck === 'opencode') return opencodeHasStableMcpConfig();
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
|
|
243
297
|
export async function chat({ messages, system, options, images }, emit) {
|
|
244
298
|
// Pro gate — verified, not just UI. No valid signed entitlement → no run.
|
|
245
299
|
if (!(await isProEntitled(options.entitlement))) {
|
|
@@ -319,14 +373,17 @@ export async function runSpec(spec, { messages, system, options = {}, images },
|
|
|
319
373
|
: [...tmpl.split(/\s+/).filter(Boolean), cfgFile];
|
|
320
374
|
args = [...tokens, ...args];
|
|
321
375
|
}
|
|
376
|
+
if (options.mcp?.url && spec.trustToolsArg) {
|
|
377
|
+
args.push(...trustToolArgs(spec.trustToolsArg, options.mcp));
|
|
378
|
+
}
|
|
322
379
|
// NOTE: opencode only loads MCP from its GLOBAL config (~/.config/opencode),
|
|
323
380
|
// never a per-run/project file — so we can't inject it here. opencode reaches
|
|
324
381
|
// the browser tools via the bridge's STABLE /mcp endpoint, registered once with
|
|
325
382
|
// `opencode mcp add chatpanel --url http://127.0.0.1:4319/mcp`.
|
|
326
|
-
if (options.mcp?.url && spec.requiresStableMcp && !(await
|
|
383
|
+
if (options.mcp?.url && spec.requiresStableMcp && !(await hasStableMcpConfig(spec, cwd))) {
|
|
327
384
|
emit({
|
|
328
385
|
type: 'status',
|
|
329
|
-
text:
|
|
386
|
+
text: `${label} needs one-time browser-tool setup: ${stableMcpSetupCommand(spec)}`,
|
|
330
387
|
});
|
|
331
388
|
}
|
|
332
389
|
|
package/src/env.js
CHANGED
|
@@ -67,7 +67,7 @@ function shellWhich(name) {
|
|
|
67
67
|
if (process.platform === 'win32') return '';
|
|
68
68
|
try {
|
|
69
69
|
const shell = process.env.SHELL || '/bin/zsh';
|
|
70
|
-
const r = spawnSync(shell, ['-
|
|
70
|
+
const r = spawnSync(shell, ['-lc', `command -v ${name} 2>/dev/null`], {
|
|
71
71
|
encoding: 'utf8',
|
|
72
72
|
timeout: 4000,
|
|
73
73
|
});
|
|
@@ -319,7 +319,7 @@ export function enrichPath() {
|
|
|
319
319
|
let shellPath = '';
|
|
320
320
|
try {
|
|
321
321
|
const shell = process.env.SHELL || '/bin/zsh';
|
|
322
|
-
const r = spawnSync(shell, ['-
|
|
322
|
+
const r = spawnSync(shell, ['-lc', 'command -p echo "$PATH"'], {
|
|
323
323
|
encoding: 'utf8',
|
|
324
324
|
timeout: 4000,
|
|
325
325
|
});
|
package/src/server.js
CHANGED
|
@@ -30,7 +30,7 @@ import { callLocalMcp } from './mcp-local.js';
|
|
|
30
30
|
// Hardcoded (not read from package.json) so it survives Bun's single-file
|
|
31
31
|
// --compile, where package.json isn't on a readable FS. CI fails the publish if
|
|
32
32
|
// this drifts from package.json, so the two can't silently diverge.
|
|
33
|
-
const VERSION = '0.10.
|
|
33
|
+
const VERSION = '0.10.6';
|
|
34
34
|
const HOST = process.env.CHATPANEL_BRIDGE_HOST || '127.0.0.1';
|
|
35
35
|
const PORT = Number(process.env.CHATPANEL_BRIDGE_PORT) || 4319;
|
|
36
36
|
|