codeam-cli 2.61.85 → 2.61.86
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/CHANGELOG.md +6 -0
- package/dist/index.js +283 -208
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to `codeam-cli` are documented here.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [2.61.85] — 2026-08-06
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Resume the prior conversation on a warm re-launch into an existing workspace (#591)
|
|
12
|
+
|
|
7
13
|
## [2.61.84] — 2026-08-05
|
|
8
14
|
|
|
9
15
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -89,6 +89,212 @@ var require_src = __commonJS({
|
|
|
89
89
|
}
|
|
90
90
|
});
|
|
91
91
|
|
|
92
|
+
// src/integrations/stdio-proxy.ts
|
|
93
|
+
var import_node_child_process31, import_node_readline3, RESTART_CHECK_INTERVAL_MS, SIGKILL_ESCALATION_MS, TOOL_CALL_TIMEOUT_MS, REPLAY_INIT_ID, RestartableStdioProxy;
|
|
94
|
+
var init_stdio_proxy = __esm({
|
|
95
|
+
"src/integrations/stdio-proxy.ts"() {
|
|
96
|
+
"use strict";
|
|
97
|
+
import_node_child_process31 = require("child_process");
|
|
98
|
+
import_node_readline3 = __toESM(require("readline"));
|
|
99
|
+
RESTART_CHECK_INTERVAL_MS = 3e4;
|
|
100
|
+
SIGKILL_ESCALATION_MS = 2e3;
|
|
101
|
+
TOOL_CALL_TIMEOUT_MS = (() => {
|
|
102
|
+
const raw = Number(process.env.CODEAM_MCP_TOOL_TIMEOUT_MS);
|
|
103
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 12e4;
|
|
104
|
+
})();
|
|
105
|
+
REPLAY_INIT_ID = "__codeam_replay_init__";
|
|
106
|
+
RestartableStdioProxy = class {
|
|
107
|
+
constructor(opts) {
|
|
108
|
+
this.opts = opts;
|
|
109
|
+
}
|
|
110
|
+
opts;
|
|
111
|
+
child = null;
|
|
112
|
+
childRl = null;
|
|
113
|
+
initializeLine = null;
|
|
114
|
+
inflight = /* @__PURE__ */ new Set();
|
|
115
|
+
/** Per-`tools/call` request-id watchdog timers (see TOOL_CALL_TIMEOUT_MS). */
|
|
116
|
+
toolTimers = /* @__PURE__ */ new Map();
|
|
117
|
+
stdout = null;
|
|
118
|
+
swapping = false;
|
|
119
|
+
pendingClientLines = [];
|
|
120
|
+
ended = () => void 0;
|
|
121
|
+
async start() {
|
|
122
|
+
const stdin = this.opts.stdin ?? process.stdin;
|
|
123
|
+
const stdout = this.opts.stdout ?? process.stdout;
|
|
124
|
+
this.stdout = stdout;
|
|
125
|
+
await this.spawnChild(stdout);
|
|
126
|
+
const rl = import_node_readline3.default.createInterface({ input: stdin, crlfDelay: Infinity });
|
|
127
|
+
rl.on("line", (line) => this.onClientLine(line));
|
|
128
|
+
rl.on("close", () => this.child?.stdin?.end());
|
|
129
|
+
const timer = setInterval(() => this.checkRestart(stdout), RESTART_CHECK_INTERVAL_MS);
|
|
130
|
+
timer.unref();
|
|
131
|
+
return new Promise((resolve9) => {
|
|
132
|
+
this.ended = (code) => {
|
|
133
|
+
clearInterval(timer);
|
|
134
|
+
process.exitCode = code;
|
|
135
|
+
resolve9();
|
|
136
|
+
};
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
onClientLine(line) {
|
|
140
|
+
if (this.swapping) {
|
|
141
|
+
this.pendingClientLines.push(line);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const msg = JSON.parse(line);
|
|
146
|
+
if (msg.method === "initialize" && this.initializeLine === null) {
|
|
147
|
+
this.initializeLine = line;
|
|
148
|
+
}
|
|
149
|
+
if (msg.method === "notifications/cancelled") {
|
|
150
|
+
const requestId = msg.params?.requestId;
|
|
151
|
+
if (requestId !== void 0) {
|
|
152
|
+
this.inflight.delete(requestId);
|
|
153
|
+
this.clearToolTimeout(requestId);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (msg.id !== void 0 && msg.method !== void 0) {
|
|
157
|
+
this.inflight.add(msg.id);
|
|
158
|
+
if (msg.method === "tools/call") this.armToolTimeout(msg.id);
|
|
159
|
+
}
|
|
160
|
+
} catch {
|
|
161
|
+
}
|
|
162
|
+
this.child?.stdin?.write(line + "\n");
|
|
163
|
+
}
|
|
164
|
+
onChildLine(line, stdout) {
|
|
165
|
+
try {
|
|
166
|
+
const msg = JSON.parse(line);
|
|
167
|
+
if (msg.id !== void 0 && msg.method === void 0) {
|
|
168
|
+
if (msg.id === REPLAY_INIT_ID) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
this.inflight.delete(msg.id);
|
|
172
|
+
this.clearToolTimeout(msg.id);
|
|
173
|
+
}
|
|
174
|
+
} catch {
|
|
175
|
+
}
|
|
176
|
+
stdout.write(line + "\n");
|
|
177
|
+
if (this.inflight.size === 0) this.checkRestart(stdout);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Arm a per-`tools/call` watchdog. If the server never answers this request
|
|
181
|
+
* id within {@link TOOL_CALL_TIMEOUT_MS}, synthesize a JSON-RPC error response
|
|
182
|
+
* to the client so the agent's turn unblocks (clean tool error) instead of
|
|
183
|
+
* hanging forever with no Stop. Idempotent per id.
|
|
184
|
+
*/
|
|
185
|
+
armToolTimeout(id) {
|
|
186
|
+
const existing = this.toolTimers.get(id);
|
|
187
|
+
if (existing) clearTimeout(existing);
|
|
188
|
+
const t2 = setTimeout(() => {
|
|
189
|
+
this.toolTimers.delete(id);
|
|
190
|
+
if (!this.inflight.has(id)) return;
|
|
191
|
+
this.inflight.delete(id);
|
|
192
|
+
process.stderr.write(
|
|
193
|
+
`[codeam mcp-run] tools/call id=${String(id)} timed out after ${TOOL_CALL_TIMEOUT_MS}ms \u2014 server did not respond; failing the call so the turn can proceed
|
|
194
|
+
`
|
|
195
|
+
);
|
|
196
|
+
const errResponse = {
|
|
197
|
+
jsonrpc: "2.0",
|
|
198
|
+
id,
|
|
199
|
+
error: {
|
|
200
|
+
code: -32001,
|
|
201
|
+
message: `MCP tool call timed out after ${Math.round(TOOL_CALL_TIMEOUT_MS / 1e3)}s \u2014 the server did not respond. The target service/deployment may be unreachable (e.g. a Convex dev deployment is only reachable while \`convex dev\` is running \u2014 use a production deploy key or start \`convex dev\`).`
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
(this.stdout ?? process.stdout).write(JSON.stringify(errResponse) + "\n");
|
|
205
|
+
}, TOOL_CALL_TIMEOUT_MS);
|
|
206
|
+
t2.unref();
|
|
207
|
+
this.toolTimers.set(id, t2);
|
|
208
|
+
}
|
|
209
|
+
clearToolTimeout(id) {
|
|
210
|
+
const t2 = this.toolTimers.get(id);
|
|
211
|
+
if (t2) {
|
|
212
|
+
clearTimeout(t2);
|
|
213
|
+
this.toolTimers.delete(id);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
clearAllToolTimeouts() {
|
|
217
|
+
for (const t2 of this.toolTimers.values()) clearTimeout(t2);
|
|
218
|
+
this.toolTimers.clear();
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Failsafe wrapper for the fire-and-forget call sites (post-response check
|
|
222
|
+
* + the 30 s timer): `maybeRestart` handles the token-fetch failure itself,
|
|
223
|
+
* but nothing that escapes it may become an unhandled rejection — that
|
|
224
|
+
* would kill the whole shim process.
|
|
225
|
+
*/
|
|
226
|
+
checkRestart(stdout) {
|
|
227
|
+
this.maybeRestart(stdout).catch((err) => {
|
|
228
|
+
process.stderr.write(
|
|
229
|
+
`[codeam mcp-run] restart check failed (will retry): ${err instanceof Error ? err.message : String(err)}
|
|
230
|
+
`
|
|
231
|
+
);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
async maybeRestart(stdout) {
|
|
235
|
+
if (this.swapping || !this.opts.shouldRestartNow()) return;
|
|
236
|
+
if (this.inflight.size > 0 || this.initializeLine === null || !this.child) return;
|
|
237
|
+
this.swapping = true;
|
|
238
|
+
let spec;
|
|
239
|
+
try {
|
|
240
|
+
spec = await this.opts.spawnSpec();
|
|
241
|
+
} catch (err) {
|
|
242
|
+
process.stderr.write(
|
|
243
|
+
`[codeam mcp-run] token refresh failed, keeping current server (will retry): ${err instanceof Error ? err.message : String(err)}
|
|
244
|
+
`
|
|
245
|
+
);
|
|
246
|
+
this.swapping = false;
|
|
247
|
+
for (const l of this.pendingClientLines.splice(0)) this.onClientLine(l);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const old = this.child;
|
|
251
|
+
const oldRl = this.childRl;
|
|
252
|
+
this.child = null;
|
|
253
|
+
this.childRl = null;
|
|
254
|
+
oldRl?.close();
|
|
255
|
+
old.kill("SIGTERM");
|
|
256
|
+
const escalation = setTimeout(() => {
|
|
257
|
+
if (!old.killed || old.exitCode === null) old.kill("SIGKILL");
|
|
258
|
+
}, SIGKILL_ESCALATION_MS);
|
|
259
|
+
escalation.unref();
|
|
260
|
+
try {
|
|
261
|
+
await this.spawnChild(stdout, spec);
|
|
262
|
+
const replayed = JSON.parse(this.initializeLine);
|
|
263
|
+
this.child.stdin.write(JSON.stringify({ ...replayed, id: REPLAY_INIT_ID }) + "\n");
|
|
264
|
+
this.child.stdin.write(
|
|
265
|
+
JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" }) + "\n"
|
|
266
|
+
);
|
|
267
|
+
} finally {
|
|
268
|
+
this.swapping = false;
|
|
269
|
+
for (const l of this.pendingClientLines.splice(0)) this.onClientLine(l);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
async spawnChild(stdout, preResolved) {
|
|
273
|
+
const spec = preResolved ?? await this.opts.spawnSpec();
|
|
274
|
+
const spawn44 = this.opts.spawnImpl ?? import_node_child_process31.spawn;
|
|
275
|
+
const child = spawn44(spec.command, spec.args, {
|
|
276
|
+
env: { ...process.env, ...spec.env },
|
|
277
|
+
// env only — never argv
|
|
278
|
+
stdio: ["pipe", "pipe", "inherit"]
|
|
279
|
+
});
|
|
280
|
+
this.child = child;
|
|
281
|
+
child.stdin?.on("error", () => void 0);
|
|
282
|
+
const rl = import_node_readline3.default.createInterface({ input: child.stdout, crlfDelay: Infinity });
|
|
283
|
+
this.childRl = rl;
|
|
284
|
+
rl.on("line", (line) => {
|
|
285
|
+
if (child !== this.child) return;
|
|
286
|
+
this.onChildLine(line, stdout);
|
|
287
|
+
});
|
|
288
|
+
child.on("exit", (code) => {
|
|
289
|
+
if (child !== this.child) return;
|
|
290
|
+
this.clearAllToolTimeouts();
|
|
291
|
+
this.ended(code ?? 1);
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
|
|
92
298
|
// src/integrations/convex-admin-mcp.ts
|
|
93
299
|
var convex_admin_mcp_exports = {};
|
|
94
300
|
__export(convex_admin_mcp_exports, {
|
|
@@ -248,6 +454,64 @@ var init_convex_admin_mcp = __esm({
|
|
|
248
454
|
}
|
|
249
455
|
});
|
|
250
456
|
|
|
457
|
+
// src/integrations/mcp-tool-watchdog.ts
|
|
458
|
+
function createToolCallWatchdog(deps) {
|
|
459
|
+
const setTimer = deps.setTimer ?? ((fn, ms) => {
|
|
460
|
+
const t2 = setTimeout(fn, ms);
|
|
461
|
+
t2.unref?.();
|
|
462
|
+
return t2;
|
|
463
|
+
});
|
|
464
|
+
const clearTimer = deps.clearTimer ?? ((t2) => clearTimeout(t2));
|
|
465
|
+
const timers = /* @__PURE__ */ new Map();
|
|
466
|
+
const answered = /* @__PURE__ */ new Set();
|
|
467
|
+
const clear = (id) => {
|
|
468
|
+
const t2 = timers.get(id);
|
|
469
|
+
if (t2) {
|
|
470
|
+
clearTimer(t2);
|
|
471
|
+
timers.delete(id);
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
return {
|
|
475
|
+
onClientMessage(msg) {
|
|
476
|
+
const m = msg;
|
|
477
|
+
if (m.method !== "tools/call" || m.id === void 0) return;
|
|
478
|
+
const id = m.id;
|
|
479
|
+
clear(id);
|
|
480
|
+
const timer = setTimer(() => {
|
|
481
|
+
timers.delete(id);
|
|
482
|
+
answered.add(id);
|
|
483
|
+
deps.sendToAgent({
|
|
484
|
+
jsonrpc: "2.0",
|
|
485
|
+
id,
|
|
486
|
+
error: {
|
|
487
|
+
code: -32001,
|
|
488
|
+
message: `The ${deps.integrationId} tool did not respond within ${Math.round(
|
|
489
|
+
deps.timeoutMs / 1e3
|
|
490
|
+
)}s (remote MCP unresponsive). The request was aborted \u2014 try again or use a different tool.`
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
}, deps.timeoutMs);
|
|
494
|
+
timers.set(id, timer);
|
|
495
|
+
},
|
|
496
|
+
onServerMessage(msg) {
|
|
497
|
+
const m = msg;
|
|
498
|
+
if (m.id === void 0 || m.method !== void 0) return false;
|
|
499
|
+
clear(m.id);
|
|
500
|
+
return answered.delete(m.id);
|
|
501
|
+
},
|
|
502
|
+
dispose() {
|
|
503
|
+
for (const t2 of timers.values()) clearTimer(t2);
|
|
504
|
+
timers.clear();
|
|
505
|
+
answered.clear();
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
var init_mcp_tool_watchdog = __esm({
|
|
510
|
+
"src/integrations/mcp-tool-watchdog.ts"() {
|
|
511
|
+
"use strict";
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
|
|
251
515
|
// src/integrations/http-relay.ts
|
|
252
516
|
var http_relay_exports = {};
|
|
253
517
|
__export(http_relay_exports, {
|
|
@@ -280,21 +544,29 @@ async function runHttpRelay(delivery, client3, id) {
|
|
|
280
544
|
const stdioTransport = new StdioServerTransport();
|
|
281
545
|
await new Promise((resolve9, reject) => {
|
|
282
546
|
let done = false;
|
|
547
|
+
const watchdog = createToolCallWatchdog({
|
|
548
|
+
timeoutMs: TOOL_CALL_TIMEOUT_MS,
|
|
549
|
+
integrationId: id,
|
|
550
|
+
sendToAgent: (m) => void stdioTransport.send(m).catch(() => void 0)
|
|
551
|
+
});
|
|
283
552
|
const finish = (err) => {
|
|
284
553
|
if (done) return;
|
|
285
554
|
done = true;
|
|
555
|
+
watchdog.dispose();
|
|
286
556
|
void httpTransport.close().catch(() => void 0);
|
|
287
557
|
void stdioTransport.close().catch(() => void 0);
|
|
288
558
|
if (err) reject(err);
|
|
289
559
|
else resolve9();
|
|
290
560
|
};
|
|
291
561
|
stdioTransport.onmessage = (msg) => {
|
|
562
|
+
watchdog.onClientMessage(msg);
|
|
292
563
|
void httpTransport.send(msg).catch((e) => {
|
|
293
564
|
process.stderr.write(`[mcp-run http] send\u2192remote failed: ${String(e)}
|
|
294
565
|
`);
|
|
295
566
|
});
|
|
296
567
|
};
|
|
297
568
|
httpTransport.onmessage = (msg) => {
|
|
569
|
+
if (watchdog.onServerMessage(msg)) return;
|
|
298
570
|
void stdioTransport.send(msg).catch(() => void 0);
|
|
299
571
|
};
|
|
300
572
|
stdioTransport.onclose = () => finish();
|
|
@@ -311,6 +583,8 @@ async function runHttpRelay(delivery, client3, id) {
|
|
|
311
583
|
var init_http_relay = __esm({
|
|
312
584
|
"src/integrations/http-relay.ts"() {
|
|
313
585
|
"use strict";
|
|
586
|
+
init_stdio_proxy();
|
|
587
|
+
init_mcp_tool_watchdog();
|
|
314
588
|
}
|
|
315
589
|
});
|
|
316
590
|
|
|
@@ -7526,7 +7800,7 @@ function readAnonId() {
|
|
|
7526
7800
|
}
|
|
7527
7801
|
function superProperties() {
|
|
7528
7802
|
return {
|
|
7529
|
-
cliVersion: true ? "2.61.
|
|
7803
|
+
cliVersion: true ? "2.61.86" : "0.0.0-dev",
|
|
7530
7804
|
nodeVersion: process.version,
|
|
7531
7805
|
platform: process.platform,
|
|
7532
7806
|
arch: process.arch,
|
|
@@ -7707,7 +7981,7 @@ var os4 = __toESM(require("os"));
|
|
|
7707
7981
|
// package.json
|
|
7708
7982
|
var package_default = {
|
|
7709
7983
|
name: "codeam-cli",
|
|
7710
|
-
version: "2.61.
|
|
7984
|
+
version: "2.61.86",
|
|
7711
7985
|
description: "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device \u2014 async. The terminal companion for CodeAgent Mobile.",
|
|
7712
7986
|
type: "commonjs",
|
|
7713
7987
|
main: "dist/index.js",
|
|
@@ -8983,7 +9257,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
8983
9257
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
8984
9258
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
8985
9259
|
// pair/reconnect). Older backends ignore the extra field.
|
|
8986
|
-
..."2.61.
|
|
9260
|
+
..."2.61.86" ? { ideVersion: "2.61.86" } : {}
|
|
8987
9261
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
8988
9262
|
}
|
|
8989
9263
|
/**
|
|
@@ -20156,7 +20430,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
20156
20430
|
if (process.env.NODE_ENV === "test") return;
|
|
20157
20431
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
20158
20432
|
if (process.env.CI) return;
|
|
20159
|
-
const current = true ? "2.61.
|
|
20433
|
+
const current = true ? "2.61.86" : null;
|
|
20160
20434
|
if (!current) return;
|
|
20161
20435
|
const cache = readCache();
|
|
20162
20436
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -20173,7 +20447,7 @@ function checkForUpdates() {
|
|
|
20173
20447
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
20174
20448
|
if (process.env.CI) return;
|
|
20175
20449
|
if (!process.stdout.isTTY) return;
|
|
20176
|
-
const current = true ? "2.61.
|
|
20450
|
+
const current = true ? "2.61.86" : null;
|
|
20177
20451
|
if (!current) return;
|
|
20178
20452
|
const cache = readCache();
|
|
20179
20453
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -20193,7 +20467,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
20193
20467
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
20194
20468
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
20195
20469
|
function currentCliVersion() {
|
|
20196
|
-
return true ? "2.61.
|
|
20470
|
+
return true ? "2.61.86" : null;
|
|
20197
20471
|
}
|
|
20198
20472
|
function runCmd(cmd, args2, timeoutMs) {
|
|
20199
20473
|
return new Promise((resolve9) => {
|
|
@@ -41213,7 +41487,7 @@ function checkChokidar() {
|
|
|
41213
41487
|
}
|
|
41214
41488
|
async function doctor(args2 = []) {
|
|
41215
41489
|
const json = args2.includes("--json");
|
|
41216
|
-
const cliVersion = true ? "2.61.
|
|
41490
|
+
const cliVersion = true ? "2.61.86" : "0.0.0-dev";
|
|
41217
41491
|
const apiBase2 = resolveApiBaseUrl();
|
|
41218
41492
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
41219
41493
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -41465,207 +41739,8 @@ var IntegrationTokenClient = class {
|
|
|
41465
41739
|
}
|
|
41466
41740
|
};
|
|
41467
41741
|
|
|
41468
|
-
// src/integrations/stdio-proxy.ts
|
|
41469
|
-
var import_node_child_process31 = require("child_process");
|
|
41470
|
-
var import_node_readline3 = __toESM(require("readline"));
|
|
41471
|
-
var RESTART_CHECK_INTERVAL_MS = 3e4;
|
|
41472
|
-
var SIGKILL_ESCALATION_MS = 2e3;
|
|
41473
|
-
var TOOL_CALL_TIMEOUT_MS = (() => {
|
|
41474
|
-
const raw = Number(process.env.CODEAM_MCP_TOOL_TIMEOUT_MS);
|
|
41475
|
-
return Number.isFinite(raw) && raw > 0 ? raw : 12e4;
|
|
41476
|
-
})();
|
|
41477
|
-
var REPLAY_INIT_ID = "__codeam_replay_init__";
|
|
41478
|
-
var RestartableStdioProxy = class {
|
|
41479
|
-
constructor(opts) {
|
|
41480
|
-
this.opts = opts;
|
|
41481
|
-
}
|
|
41482
|
-
opts;
|
|
41483
|
-
child = null;
|
|
41484
|
-
childRl = null;
|
|
41485
|
-
initializeLine = null;
|
|
41486
|
-
inflight = /* @__PURE__ */ new Set();
|
|
41487
|
-
/** Per-`tools/call` request-id watchdog timers (see TOOL_CALL_TIMEOUT_MS). */
|
|
41488
|
-
toolTimers = /* @__PURE__ */ new Map();
|
|
41489
|
-
stdout = null;
|
|
41490
|
-
swapping = false;
|
|
41491
|
-
pendingClientLines = [];
|
|
41492
|
-
ended = () => void 0;
|
|
41493
|
-
async start() {
|
|
41494
|
-
const stdin = this.opts.stdin ?? process.stdin;
|
|
41495
|
-
const stdout = this.opts.stdout ?? process.stdout;
|
|
41496
|
-
this.stdout = stdout;
|
|
41497
|
-
await this.spawnChild(stdout);
|
|
41498
|
-
const rl = import_node_readline3.default.createInterface({ input: stdin, crlfDelay: Infinity });
|
|
41499
|
-
rl.on("line", (line) => this.onClientLine(line));
|
|
41500
|
-
rl.on("close", () => this.child?.stdin?.end());
|
|
41501
|
-
const timer = setInterval(() => this.checkRestart(stdout), RESTART_CHECK_INTERVAL_MS);
|
|
41502
|
-
timer.unref();
|
|
41503
|
-
return new Promise((resolve9) => {
|
|
41504
|
-
this.ended = (code) => {
|
|
41505
|
-
clearInterval(timer);
|
|
41506
|
-
process.exitCode = code;
|
|
41507
|
-
resolve9();
|
|
41508
|
-
};
|
|
41509
|
-
});
|
|
41510
|
-
}
|
|
41511
|
-
onClientLine(line) {
|
|
41512
|
-
if (this.swapping) {
|
|
41513
|
-
this.pendingClientLines.push(line);
|
|
41514
|
-
return;
|
|
41515
|
-
}
|
|
41516
|
-
try {
|
|
41517
|
-
const msg = JSON.parse(line);
|
|
41518
|
-
if (msg.method === "initialize" && this.initializeLine === null) {
|
|
41519
|
-
this.initializeLine = line;
|
|
41520
|
-
}
|
|
41521
|
-
if (msg.method === "notifications/cancelled") {
|
|
41522
|
-
const requestId = msg.params?.requestId;
|
|
41523
|
-
if (requestId !== void 0) {
|
|
41524
|
-
this.inflight.delete(requestId);
|
|
41525
|
-
this.clearToolTimeout(requestId);
|
|
41526
|
-
}
|
|
41527
|
-
}
|
|
41528
|
-
if (msg.id !== void 0 && msg.method !== void 0) {
|
|
41529
|
-
this.inflight.add(msg.id);
|
|
41530
|
-
if (msg.method === "tools/call") this.armToolTimeout(msg.id);
|
|
41531
|
-
}
|
|
41532
|
-
} catch {
|
|
41533
|
-
}
|
|
41534
|
-
this.child?.stdin?.write(line + "\n");
|
|
41535
|
-
}
|
|
41536
|
-
onChildLine(line, stdout) {
|
|
41537
|
-
try {
|
|
41538
|
-
const msg = JSON.parse(line);
|
|
41539
|
-
if (msg.id !== void 0 && msg.method === void 0) {
|
|
41540
|
-
if (msg.id === REPLAY_INIT_ID) {
|
|
41541
|
-
return;
|
|
41542
|
-
}
|
|
41543
|
-
this.inflight.delete(msg.id);
|
|
41544
|
-
this.clearToolTimeout(msg.id);
|
|
41545
|
-
}
|
|
41546
|
-
} catch {
|
|
41547
|
-
}
|
|
41548
|
-
stdout.write(line + "\n");
|
|
41549
|
-
if (this.inflight.size === 0) this.checkRestart(stdout);
|
|
41550
|
-
}
|
|
41551
|
-
/**
|
|
41552
|
-
* Arm a per-`tools/call` watchdog. If the server never answers this request
|
|
41553
|
-
* id within {@link TOOL_CALL_TIMEOUT_MS}, synthesize a JSON-RPC error response
|
|
41554
|
-
* to the client so the agent's turn unblocks (clean tool error) instead of
|
|
41555
|
-
* hanging forever with no Stop. Idempotent per id.
|
|
41556
|
-
*/
|
|
41557
|
-
armToolTimeout(id) {
|
|
41558
|
-
const existing = this.toolTimers.get(id);
|
|
41559
|
-
if (existing) clearTimeout(existing);
|
|
41560
|
-
const t2 = setTimeout(() => {
|
|
41561
|
-
this.toolTimers.delete(id);
|
|
41562
|
-
if (!this.inflight.has(id)) return;
|
|
41563
|
-
this.inflight.delete(id);
|
|
41564
|
-
process.stderr.write(
|
|
41565
|
-
`[codeam mcp-run] tools/call id=${String(id)} timed out after ${TOOL_CALL_TIMEOUT_MS}ms \u2014 server did not respond; failing the call so the turn can proceed
|
|
41566
|
-
`
|
|
41567
|
-
);
|
|
41568
|
-
const errResponse = {
|
|
41569
|
-
jsonrpc: "2.0",
|
|
41570
|
-
id,
|
|
41571
|
-
error: {
|
|
41572
|
-
code: -32001,
|
|
41573
|
-
message: `MCP tool call timed out after ${Math.round(TOOL_CALL_TIMEOUT_MS / 1e3)}s \u2014 the server did not respond. The target service/deployment may be unreachable (e.g. a Convex dev deployment is only reachable while \`convex dev\` is running \u2014 use a production deploy key or start \`convex dev\`).`
|
|
41574
|
-
}
|
|
41575
|
-
};
|
|
41576
|
-
(this.stdout ?? process.stdout).write(JSON.stringify(errResponse) + "\n");
|
|
41577
|
-
}, TOOL_CALL_TIMEOUT_MS);
|
|
41578
|
-
t2.unref();
|
|
41579
|
-
this.toolTimers.set(id, t2);
|
|
41580
|
-
}
|
|
41581
|
-
clearToolTimeout(id) {
|
|
41582
|
-
const t2 = this.toolTimers.get(id);
|
|
41583
|
-
if (t2) {
|
|
41584
|
-
clearTimeout(t2);
|
|
41585
|
-
this.toolTimers.delete(id);
|
|
41586
|
-
}
|
|
41587
|
-
}
|
|
41588
|
-
clearAllToolTimeouts() {
|
|
41589
|
-
for (const t2 of this.toolTimers.values()) clearTimeout(t2);
|
|
41590
|
-
this.toolTimers.clear();
|
|
41591
|
-
}
|
|
41592
|
-
/**
|
|
41593
|
-
* Failsafe wrapper for the fire-and-forget call sites (post-response check
|
|
41594
|
-
* + the 30 s timer): `maybeRestart` handles the token-fetch failure itself,
|
|
41595
|
-
* but nothing that escapes it may become an unhandled rejection — that
|
|
41596
|
-
* would kill the whole shim process.
|
|
41597
|
-
*/
|
|
41598
|
-
checkRestart(stdout) {
|
|
41599
|
-
this.maybeRestart(stdout).catch((err) => {
|
|
41600
|
-
process.stderr.write(
|
|
41601
|
-
`[codeam mcp-run] restart check failed (will retry): ${err instanceof Error ? err.message : String(err)}
|
|
41602
|
-
`
|
|
41603
|
-
);
|
|
41604
|
-
});
|
|
41605
|
-
}
|
|
41606
|
-
async maybeRestart(stdout) {
|
|
41607
|
-
if (this.swapping || !this.opts.shouldRestartNow()) return;
|
|
41608
|
-
if (this.inflight.size > 0 || this.initializeLine === null || !this.child) return;
|
|
41609
|
-
this.swapping = true;
|
|
41610
|
-
let spec;
|
|
41611
|
-
try {
|
|
41612
|
-
spec = await this.opts.spawnSpec();
|
|
41613
|
-
} catch (err) {
|
|
41614
|
-
process.stderr.write(
|
|
41615
|
-
`[codeam mcp-run] token refresh failed, keeping current server (will retry): ${err instanceof Error ? err.message : String(err)}
|
|
41616
|
-
`
|
|
41617
|
-
);
|
|
41618
|
-
this.swapping = false;
|
|
41619
|
-
for (const l of this.pendingClientLines.splice(0)) this.onClientLine(l);
|
|
41620
|
-
return;
|
|
41621
|
-
}
|
|
41622
|
-
const old = this.child;
|
|
41623
|
-
const oldRl = this.childRl;
|
|
41624
|
-
this.child = null;
|
|
41625
|
-
this.childRl = null;
|
|
41626
|
-
oldRl?.close();
|
|
41627
|
-
old.kill("SIGTERM");
|
|
41628
|
-
const escalation = setTimeout(() => {
|
|
41629
|
-
if (!old.killed || old.exitCode === null) old.kill("SIGKILL");
|
|
41630
|
-
}, SIGKILL_ESCALATION_MS);
|
|
41631
|
-
escalation.unref();
|
|
41632
|
-
try {
|
|
41633
|
-
await this.spawnChild(stdout, spec);
|
|
41634
|
-
const replayed = JSON.parse(this.initializeLine);
|
|
41635
|
-
this.child.stdin.write(JSON.stringify({ ...replayed, id: REPLAY_INIT_ID }) + "\n");
|
|
41636
|
-
this.child.stdin.write(
|
|
41637
|
-
JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" }) + "\n"
|
|
41638
|
-
);
|
|
41639
|
-
} finally {
|
|
41640
|
-
this.swapping = false;
|
|
41641
|
-
for (const l of this.pendingClientLines.splice(0)) this.onClientLine(l);
|
|
41642
|
-
}
|
|
41643
|
-
}
|
|
41644
|
-
async spawnChild(stdout, preResolved) {
|
|
41645
|
-
const spec = preResolved ?? await this.opts.spawnSpec();
|
|
41646
|
-
const spawn44 = this.opts.spawnImpl ?? import_node_child_process31.spawn;
|
|
41647
|
-
const child = spawn44(spec.command, spec.args, {
|
|
41648
|
-
env: { ...process.env, ...spec.env },
|
|
41649
|
-
// env only — never argv
|
|
41650
|
-
stdio: ["pipe", "pipe", "inherit"]
|
|
41651
|
-
});
|
|
41652
|
-
this.child = child;
|
|
41653
|
-
child.stdin?.on("error", () => void 0);
|
|
41654
|
-
const rl = import_node_readline3.default.createInterface({ input: child.stdout, crlfDelay: Infinity });
|
|
41655
|
-
this.childRl = rl;
|
|
41656
|
-
rl.on("line", (line) => {
|
|
41657
|
-
if (child !== this.child) return;
|
|
41658
|
-
this.onChildLine(line, stdout);
|
|
41659
|
-
});
|
|
41660
|
-
child.on("exit", (code) => {
|
|
41661
|
-
if (child !== this.child) return;
|
|
41662
|
-
this.clearAllToolTimeouts();
|
|
41663
|
-
this.ended(code ?? 1);
|
|
41664
|
-
});
|
|
41665
|
-
}
|
|
41666
|
-
};
|
|
41667
|
-
|
|
41668
41742
|
// src/integrations/mcp-run.ts
|
|
41743
|
+
init_stdio_proxy();
|
|
41669
41744
|
var RESTART_AHEAD_MS = 5 * 60 * 1e3;
|
|
41670
41745
|
function resolveDelivery(id) {
|
|
41671
41746
|
const fromRegistry = isKnownIntegrationId(id) ? getIntegration(id).delivery.mcp ?? null : null;
|
|
@@ -41803,7 +41878,7 @@ async function mcpRun(args2) {
|
|
|
41803
41878
|
// src/commands/version.ts
|
|
41804
41879
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
41805
41880
|
function version2() {
|
|
41806
|
-
const v = true ? "2.61.
|
|
41881
|
+
const v = true ? "2.61.86" : "unknown";
|
|
41807
41882
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
41808
41883
|
}
|
|
41809
41884
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.61.
|
|
3
|
+
"version": "2.61.86",
|
|
4
4
|
"description": "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device — async. The terminal companion for CodeAgent Mobile.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "dist/index.js",
|