@chatpanel/bridge 0.10.40 → 0.10.41
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/cli-errors.js +64 -0
- package/src/engines/antigravity.js +2 -1
- package/src/engines/claude.js +2 -1
- package/src/engines/codex.js +2 -1
- package/src/engines/custom.js +1 -1
- 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.41",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Local bridge that exposes the AI coding agents installed on your machine \u2014 Claude Code (CLI), Codex (CLI), and Antigravity CLI (formerly Gemini CLI, which remains available for business/enterprise) \u2014 to the ChatPanel Chrome extension over a localhost SSE endpoint. Bring your own agent.",
|
|
6
6
|
"keywords": [
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Turning a CLI agent's dying breath into something a person can act on.
|
|
2
|
+
//
|
|
3
|
+
// When an agent exits non-zero we used to surface its raw stderr. For a crash that is fine;
|
|
4
|
+
// for the common real failure — one of the AGENT'S OWN MCP servers refusing to authenticate —
|
|
5
|
+
// it is not: those servers answer with an HTML error page, so the user got kilobytes of
|
|
6
|
+
// markup, inline CSS and an SVG logo in the chat, with the one useful sentence buried inside.
|
|
7
|
+
//
|
|
8
|
+
// The failure is also usually not ChatPanel's to fix. Saying whose it is, and naming the
|
|
9
|
+
// server, is the difference between "something broke" and "re-auth that server".
|
|
10
|
+
|
|
11
|
+
const NOISE = [
|
|
12
|
+
/^\s*$/,
|
|
13
|
+
/^\s*at\s+/, // stack frames
|
|
14
|
+
/^\s*[.#]?[\w-]+\s*\{/, // CSS rules
|
|
15
|
+
/^\s*[\w-]+:\s*[^;]+;$/,// CSS declarations
|
|
16
|
+
/^\s*<\//, // closing tags
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
// Strip HTML/CSS/SVG so an error page collapses to whatever prose it contained.
|
|
20
|
+
export function stripMarkup(text) {
|
|
21
|
+
return String(text || '')
|
|
22
|
+
.replace(/<script[\s\S]*?<\/script>/gi, ' ')
|
|
23
|
+
.replace(/<style[\s\S]*?<\/style>/gi, ' ')
|
|
24
|
+
.replace(/<svg[\s\S]*?<\/svg>/gi, ' ')
|
|
25
|
+
.replace(/<[^>]+>/g, ' ')
|
|
26
|
+
.replace(/ /g, ' ')
|
|
27
|
+
.replace(/[ \t]+/g, ' ');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// The named causes worth translating. Each returns a sentence that says what to DO.
|
|
31
|
+
function knownCause(text) {
|
|
32
|
+
const server = /refresh OAuth tokens for server ([\w.-]+)/i.exec(text)?.[1]
|
|
33
|
+
|| /server ['"]?([\w.-]+)['"]? (?:requires|failed) auth/i.exec(text)?.[1];
|
|
34
|
+
if (/refresh token (?:does not exist|was rejected)|invalid_grant/i.test(text)) {
|
|
35
|
+
return `${server ? `its MCP server "${server}"` : 'one of its MCP servers'} needs re-authentication — its saved OAuth token has expired or been revoked. Re-login to that server in the agent's own config; ChatPanel can't refresh it.`;
|
|
36
|
+
}
|
|
37
|
+
if (/invalid_token|AuthRequired|www-authenticate|\b401\b/i.test(text)) {
|
|
38
|
+
return `${server ? `its MCP server "${server}"` : 'one of its MCP servers'} rejected the agent's token (401/invalid_token). Re-authenticate that server in the agent, then retry.`;
|
|
39
|
+
}
|
|
40
|
+
if (/HTTP 403|\b403\b/.test(text)) {
|
|
41
|
+
return `${server ? `its MCP server "${server}"` : 'one of its MCP servers'} returned 403 and an error page — that server is refusing requests or is temporarily down. This is outside ChatPanel; retry when it recovers.`;
|
|
42
|
+
}
|
|
43
|
+
if (/ENOENT|command not found/i.test(text)) return 'the command could not be found on PATH.';
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* A short, actionable summary of why a CLI agent exited. Never returns markup, and never more
|
|
49
|
+
* than a couple of lines — the full output stays in the bridge log for anyone debugging.
|
|
50
|
+
*/
|
|
51
|
+
export function summarizeCliError(label, code, stderr, stdout = '') {
|
|
52
|
+
const raw = `${stderr || ''}\n${stdout || ''}`;
|
|
53
|
+
const cause = knownCause(raw);
|
|
54
|
+
if (cause) return `${label} exited ${code}: ${cause}`;
|
|
55
|
+
|
|
56
|
+
const lines = stripMarkup(raw)
|
|
57
|
+
.split('\n')
|
|
58
|
+
.map((l) => l.trim())
|
|
59
|
+
.filter((l) => l && !NOISE.some((re) => re.test(l)));
|
|
60
|
+
// Prefer the last line that reads like an error, else the last line at all.
|
|
61
|
+
const errish = lines.filter((l) => /error|fail|fatal|panic|refused|denied|timeout/i.test(l));
|
|
62
|
+
const pick = (errish.length ? errish : lines).pop() || 'failed';
|
|
63
|
+
return `${label} exited ${code}: ${pick.length > 300 ? `${pick.slice(0, 300)}…` : pick}`;
|
|
64
|
+
}
|
|
@@ -16,6 +16,7 @@ import os from 'node:os';
|
|
|
16
16
|
import path from 'node:path';
|
|
17
17
|
import { findAgentBin } from '../env.js';
|
|
18
18
|
import { buildCliPrompt } from './prompt.js';
|
|
19
|
+
import { summarizeCliError } from '../cli-errors.js';
|
|
19
20
|
import { killOnAbort, spawnGroupOpts } from '../proc.js';
|
|
20
21
|
import { pushExtraArgs, FORBIDDEN } from './args.js';
|
|
21
22
|
import { resolveWorkdir } from '../workdir.js';
|
|
@@ -153,7 +154,7 @@ export async function chat({ messages, system, options, images }, emit, { signal
|
|
|
153
154
|
emit({ type: 'done', text: '' });
|
|
154
155
|
resolve();
|
|
155
156
|
} else {
|
|
156
|
-
reject(new Error(
|
|
157
|
+
reject(new Error(summarizeCliError('Antigravity', code, err, out)));
|
|
157
158
|
}
|
|
158
159
|
});
|
|
159
160
|
});
|
package/src/engines/claude.js
CHANGED
|
@@ -19,6 +19,7 @@ import os from 'node:os';
|
|
|
19
19
|
import path from 'node:path';
|
|
20
20
|
import { resolveClaude, buildSpawnSpec, isCompiledBinary, selfMcpStdio } from '../env.js';
|
|
21
21
|
import { buildCliPrompt } from './prompt.js';
|
|
22
|
+
import { summarizeCliError } from '../cli-errors.js';
|
|
22
23
|
import { killOnAbort } from '../proc.js';
|
|
23
24
|
import { pushExtraArgs, FORBIDDEN } from './args.js';
|
|
24
25
|
import { displayPath, resolveWorkdir } from '../workdir.js';
|
|
@@ -160,7 +161,7 @@ function runClaude({ prompt, args, cwd, emit, signal }) {
|
|
|
160
161
|
detach();
|
|
161
162
|
if (signal?.aborted) { resolve({ streamedAny, resultText }); return; } // Stop pressed — end quietly
|
|
162
163
|
if (code === 0) resolve({ streamedAny, resultText });
|
|
163
|
-
else reject(new Error(
|
|
164
|
+
else reject(new Error(summarizeCliError('Claude Code', code, stderr)));
|
|
164
165
|
});
|
|
165
166
|
|
|
166
167
|
child.stdin.write(prompt);
|
package/src/engines/codex.js
CHANGED
|
@@ -24,6 +24,7 @@ import { findAgentBin, selfMcpStdio } from '../env.js';
|
|
|
24
24
|
import { buildCliPrompt } from './prompt.js';
|
|
25
25
|
import { pushExtraArgs, FORBIDDEN } from './args.js';
|
|
26
26
|
import { resolveWorkdir } from '../workdir.js';
|
|
27
|
+
import { summarizeCliError } from '../cli-errors.js';
|
|
27
28
|
|
|
28
29
|
// Idle timeout: re-armed on every stdout/stderr chunk, so a long run that keeps
|
|
29
30
|
// streaming never trips it — only true silence does. Override with
|
|
@@ -238,7 +239,7 @@ export async function chat({ messages, system, options, images }, emit, { signal
|
|
|
238
239
|
emit({ type: 'done', text: '' });
|
|
239
240
|
resolve();
|
|
240
241
|
} else {
|
|
241
|
-
reject(new Error(
|
|
242
|
+
reject(new Error(summarizeCliError('Codex', code, stderr)));
|
|
242
243
|
}
|
|
243
244
|
});
|
|
244
245
|
|
package/src/engines/custom.js
CHANGED
|
@@ -621,7 +621,7 @@ export async function runSpec(spec, { messages, system, options = {}, images },
|
|
|
621
621
|
emit({ type: 'done', text: parser.streamed ? '' : parser.finish() });
|
|
622
622
|
resolve();
|
|
623
623
|
} else {
|
|
624
|
-
reject(new Error(
|
|
624
|
+
reject(new Error(summarizeCliError(label, code, stderr)));
|
|
625
625
|
}
|
|
626
626
|
});
|
|
627
627
|
|
package/src/server.js
CHANGED
|
@@ -67,7 +67,7 @@ import {
|
|
|
67
67
|
// Hardcoded (not read from package.json) so it survives Bun's single-file
|
|
68
68
|
// --compile, where package.json isn't on a readable FS. CI fails the publish if
|
|
69
69
|
// this drifts from package.json, so the two can't silently diverge.
|
|
70
|
-
const VERSION = '0.10.
|
|
70
|
+
const VERSION = '0.10.41';
|
|
71
71
|
const HOST = process.env.CHATPANEL_BRIDGE_HOST || '127.0.0.1';
|
|
72
72
|
const PORT = Number(process.env.CHATPANEL_BRIDGE_PORT) || 4319;
|
|
73
73
|
|