codeam-cli 2.61.84 → 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 +12 -0
- package/dist/index.js +300 -210
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ 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
|
+
|
|
13
|
+
## [2.61.84] — 2026-08-05
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **cli:** Internal-path guard no longer denies the self-hosted workspace (#587)
|
|
18
|
+
|
|
7
19
|
## [2.61.83] — 2026-08-05
|
|
8
20
|
|
|
9
21
|
### 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) => {
|
|
@@ -21283,6 +21557,21 @@ var HostAgentSupervisor = class {
|
|
|
21283
21557
|
persistOrClearSkillsFromPayload(
|
|
21284
21558
|
payload.skills
|
|
21285
21559
|
);
|
|
21560
|
+
if (!payload.suppressOnboardingWelcome) {
|
|
21561
|
+
try {
|
|
21562
|
+
const cfgDir = childEnv.CLAUDE_CONFIG_DIR || path48.join(os39.homedir(), ".claude");
|
|
21563
|
+
const projectDir = path48.join(cfgDir, "projects", encodeCwd(cwd));
|
|
21564
|
+
const hasPriorConversation = fs45.existsSync(projectDir) && fs45.readdirSync(projectDir).some((f) => f.endsWith(".jsonl"));
|
|
21565
|
+
if (hasPriorConversation) {
|
|
21566
|
+
childEnv.CODEAM_RESUME_LATEST = "1";
|
|
21567
|
+
log.info(
|
|
21568
|
+
"host-agent",
|
|
21569
|
+
`deploy: prior conversation in ${projectDir} \u2014 resuming latest for continuity`
|
|
21570
|
+
);
|
|
21571
|
+
}
|
|
21572
|
+
} catch {
|
|
21573
|
+
}
|
|
21574
|
+
}
|
|
21286
21575
|
report("spawning", "starting agent");
|
|
21287
21576
|
const proc = this.spawnSessionChild(childEnv, cwd, extraArgs);
|
|
21288
21577
|
const child = {
|
|
@@ -25499,13 +25788,13 @@ function resolveGlobalNodeModulesDir(opts) {
|
|
|
25499
25788
|
var STALE_STAGING_AGE_MS = CLI_UPDATE_INSTALL_TIMEOUT_MS;
|
|
25500
25789
|
function sweepStaleCliStagingDirs(nodeModulesDir, now = Date.now(), deps) {
|
|
25501
25790
|
if (!nodeModulesDir) return 0;
|
|
25502
|
-
const
|
|
25791
|
+
const readdirSync13 = deps?.readdirSync ?? fs61.readdirSync;
|
|
25503
25792
|
const statSync17 = deps?.statSync ?? fs61.statSync;
|
|
25504
25793
|
const rmSync9 = deps?.rmSync ?? fs61.rmSync;
|
|
25505
25794
|
let removed = 0;
|
|
25506
25795
|
let entries;
|
|
25507
25796
|
try {
|
|
25508
|
-
entries =
|
|
25797
|
+
entries = readdirSync13(nodeModulesDir);
|
|
25509
25798
|
} catch {
|
|
25510
25799
|
return 0;
|
|
25511
25800
|
}
|
|
@@ -41198,7 +41487,7 @@ function checkChokidar() {
|
|
|
41198
41487
|
}
|
|
41199
41488
|
async function doctor(args2 = []) {
|
|
41200
41489
|
const json = args2.includes("--json");
|
|
41201
|
-
const cliVersion = true ? "2.61.
|
|
41490
|
+
const cliVersion = true ? "2.61.86" : "0.0.0-dev";
|
|
41202
41491
|
const apiBase2 = resolveApiBaseUrl();
|
|
41203
41492
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
41204
41493
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -41450,207 +41739,8 @@ var IntegrationTokenClient = class {
|
|
|
41450
41739
|
}
|
|
41451
41740
|
};
|
|
41452
41741
|
|
|
41453
|
-
// src/integrations/stdio-proxy.ts
|
|
41454
|
-
var import_node_child_process31 = require("child_process");
|
|
41455
|
-
var import_node_readline3 = __toESM(require("readline"));
|
|
41456
|
-
var RESTART_CHECK_INTERVAL_MS = 3e4;
|
|
41457
|
-
var SIGKILL_ESCALATION_MS = 2e3;
|
|
41458
|
-
var TOOL_CALL_TIMEOUT_MS = (() => {
|
|
41459
|
-
const raw = Number(process.env.CODEAM_MCP_TOOL_TIMEOUT_MS);
|
|
41460
|
-
return Number.isFinite(raw) && raw > 0 ? raw : 12e4;
|
|
41461
|
-
})();
|
|
41462
|
-
var REPLAY_INIT_ID = "__codeam_replay_init__";
|
|
41463
|
-
var RestartableStdioProxy = class {
|
|
41464
|
-
constructor(opts) {
|
|
41465
|
-
this.opts = opts;
|
|
41466
|
-
}
|
|
41467
|
-
opts;
|
|
41468
|
-
child = null;
|
|
41469
|
-
childRl = null;
|
|
41470
|
-
initializeLine = null;
|
|
41471
|
-
inflight = /* @__PURE__ */ new Set();
|
|
41472
|
-
/** Per-`tools/call` request-id watchdog timers (see TOOL_CALL_TIMEOUT_MS). */
|
|
41473
|
-
toolTimers = /* @__PURE__ */ new Map();
|
|
41474
|
-
stdout = null;
|
|
41475
|
-
swapping = false;
|
|
41476
|
-
pendingClientLines = [];
|
|
41477
|
-
ended = () => void 0;
|
|
41478
|
-
async start() {
|
|
41479
|
-
const stdin = this.opts.stdin ?? process.stdin;
|
|
41480
|
-
const stdout = this.opts.stdout ?? process.stdout;
|
|
41481
|
-
this.stdout = stdout;
|
|
41482
|
-
await this.spawnChild(stdout);
|
|
41483
|
-
const rl = import_node_readline3.default.createInterface({ input: stdin, crlfDelay: Infinity });
|
|
41484
|
-
rl.on("line", (line) => this.onClientLine(line));
|
|
41485
|
-
rl.on("close", () => this.child?.stdin?.end());
|
|
41486
|
-
const timer = setInterval(() => this.checkRestart(stdout), RESTART_CHECK_INTERVAL_MS);
|
|
41487
|
-
timer.unref();
|
|
41488
|
-
return new Promise((resolve9) => {
|
|
41489
|
-
this.ended = (code) => {
|
|
41490
|
-
clearInterval(timer);
|
|
41491
|
-
process.exitCode = code;
|
|
41492
|
-
resolve9();
|
|
41493
|
-
};
|
|
41494
|
-
});
|
|
41495
|
-
}
|
|
41496
|
-
onClientLine(line) {
|
|
41497
|
-
if (this.swapping) {
|
|
41498
|
-
this.pendingClientLines.push(line);
|
|
41499
|
-
return;
|
|
41500
|
-
}
|
|
41501
|
-
try {
|
|
41502
|
-
const msg = JSON.parse(line);
|
|
41503
|
-
if (msg.method === "initialize" && this.initializeLine === null) {
|
|
41504
|
-
this.initializeLine = line;
|
|
41505
|
-
}
|
|
41506
|
-
if (msg.method === "notifications/cancelled") {
|
|
41507
|
-
const requestId = msg.params?.requestId;
|
|
41508
|
-
if (requestId !== void 0) {
|
|
41509
|
-
this.inflight.delete(requestId);
|
|
41510
|
-
this.clearToolTimeout(requestId);
|
|
41511
|
-
}
|
|
41512
|
-
}
|
|
41513
|
-
if (msg.id !== void 0 && msg.method !== void 0) {
|
|
41514
|
-
this.inflight.add(msg.id);
|
|
41515
|
-
if (msg.method === "tools/call") this.armToolTimeout(msg.id);
|
|
41516
|
-
}
|
|
41517
|
-
} catch {
|
|
41518
|
-
}
|
|
41519
|
-
this.child?.stdin?.write(line + "\n");
|
|
41520
|
-
}
|
|
41521
|
-
onChildLine(line, stdout) {
|
|
41522
|
-
try {
|
|
41523
|
-
const msg = JSON.parse(line);
|
|
41524
|
-
if (msg.id !== void 0 && msg.method === void 0) {
|
|
41525
|
-
if (msg.id === REPLAY_INIT_ID) {
|
|
41526
|
-
return;
|
|
41527
|
-
}
|
|
41528
|
-
this.inflight.delete(msg.id);
|
|
41529
|
-
this.clearToolTimeout(msg.id);
|
|
41530
|
-
}
|
|
41531
|
-
} catch {
|
|
41532
|
-
}
|
|
41533
|
-
stdout.write(line + "\n");
|
|
41534
|
-
if (this.inflight.size === 0) this.checkRestart(stdout);
|
|
41535
|
-
}
|
|
41536
|
-
/**
|
|
41537
|
-
* Arm a per-`tools/call` watchdog. If the server never answers this request
|
|
41538
|
-
* id within {@link TOOL_CALL_TIMEOUT_MS}, synthesize a JSON-RPC error response
|
|
41539
|
-
* to the client so the agent's turn unblocks (clean tool error) instead of
|
|
41540
|
-
* hanging forever with no Stop. Idempotent per id.
|
|
41541
|
-
*/
|
|
41542
|
-
armToolTimeout(id) {
|
|
41543
|
-
const existing = this.toolTimers.get(id);
|
|
41544
|
-
if (existing) clearTimeout(existing);
|
|
41545
|
-
const t2 = setTimeout(() => {
|
|
41546
|
-
this.toolTimers.delete(id);
|
|
41547
|
-
if (!this.inflight.has(id)) return;
|
|
41548
|
-
this.inflight.delete(id);
|
|
41549
|
-
process.stderr.write(
|
|
41550
|
-
`[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
|
|
41551
|
-
`
|
|
41552
|
-
);
|
|
41553
|
-
const errResponse = {
|
|
41554
|
-
jsonrpc: "2.0",
|
|
41555
|
-
id,
|
|
41556
|
-
error: {
|
|
41557
|
-
code: -32001,
|
|
41558
|
-
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\`).`
|
|
41559
|
-
}
|
|
41560
|
-
};
|
|
41561
|
-
(this.stdout ?? process.stdout).write(JSON.stringify(errResponse) + "\n");
|
|
41562
|
-
}, TOOL_CALL_TIMEOUT_MS);
|
|
41563
|
-
t2.unref();
|
|
41564
|
-
this.toolTimers.set(id, t2);
|
|
41565
|
-
}
|
|
41566
|
-
clearToolTimeout(id) {
|
|
41567
|
-
const t2 = this.toolTimers.get(id);
|
|
41568
|
-
if (t2) {
|
|
41569
|
-
clearTimeout(t2);
|
|
41570
|
-
this.toolTimers.delete(id);
|
|
41571
|
-
}
|
|
41572
|
-
}
|
|
41573
|
-
clearAllToolTimeouts() {
|
|
41574
|
-
for (const t2 of this.toolTimers.values()) clearTimeout(t2);
|
|
41575
|
-
this.toolTimers.clear();
|
|
41576
|
-
}
|
|
41577
|
-
/**
|
|
41578
|
-
* Failsafe wrapper for the fire-and-forget call sites (post-response check
|
|
41579
|
-
* + the 30 s timer): `maybeRestart` handles the token-fetch failure itself,
|
|
41580
|
-
* but nothing that escapes it may become an unhandled rejection — that
|
|
41581
|
-
* would kill the whole shim process.
|
|
41582
|
-
*/
|
|
41583
|
-
checkRestart(stdout) {
|
|
41584
|
-
this.maybeRestart(stdout).catch((err) => {
|
|
41585
|
-
process.stderr.write(
|
|
41586
|
-
`[codeam mcp-run] restart check failed (will retry): ${err instanceof Error ? err.message : String(err)}
|
|
41587
|
-
`
|
|
41588
|
-
);
|
|
41589
|
-
});
|
|
41590
|
-
}
|
|
41591
|
-
async maybeRestart(stdout) {
|
|
41592
|
-
if (this.swapping || !this.opts.shouldRestartNow()) return;
|
|
41593
|
-
if (this.inflight.size > 0 || this.initializeLine === null || !this.child) return;
|
|
41594
|
-
this.swapping = true;
|
|
41595
|
-
let spec;
|
|
41596
|
-
try {
|
|
41597
|
-
spec = await this.opts.spawnSpec();
|
|
41598
|
-
} catch (err) {
|
|
41599
|
-
process.stderr.write(
|
|
41600
|
-
`[codeam mcp-run] token refresh failed, keeping current server (will retry): ${err instanceof Error ? err.message : String(err)}
|
|
41601
|
-
`
|
|
41602
|
-
);
|
|
41603
|
-
this.swapping = false;
|
|
41604
|
-
for (const l of this.pendingClientLines.splice(0)) this.onClientLine(l);
|
|
41605
|
-
return;
|
|
41606
|
-
}
|
|
41607
|
-
const old = this.child;
|
|
41608
|
-
const oldRl = this.childRl;
|
|
41609
|
-
this.child = null;
|
|
41610
|
-
this.childRl = null;
|
|
41611
|
-
oldRl?.close();
|
|
41612
|
-
old.kill("SIGTERM");
|
|
41613
|
-
const escalation = setTimeout(() => {
|
|
41614
|
-
if (!old.killed || old.exitCode === null) old.kill("SIGKILL");
|
|
41615
|
-
}, SIGKILL_ESCALATION_MS);
|
|
41616
|
-
escalation.unref();
|
|
41617
|
-
try {
|
|
41618
|
-
await this.spawnChild(stdout, spec);
|
|
41619
|
-
const replayed = JSON.parse(this.initializeLine);
|
|
41620
|
-
this.child.stdin.write(JSON.stringify({ ...replayed, id: REPLAY_INIT_ID }) + "\n");
|
|
41621
|
-
this.child.stdin.write(
|
|
41622
|
-
JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" }) + "\n"
|
|
41623
|
-
);
|
|
41624
|
-
} finally {
|
|
41625
|
-
this.swapping = false;
|
|
41626
|
-
for (const l of this.pendingClientLines.splice(0)) this.onClientLine(l);
|
|
41627
|
-
}
|
|
41628
|
-
}
|
|
41629
|
-
async spawnChild(stdout, preResolved) {
|
|
41630
|
-
const spec = preResolved ?? await this.opts.spawnSpec();
|
|
41631
|
-
const spawn44 = this.opts.spawnImpl ?? import_node_child_process31.spawn;
|
|
41632
|
-
const child = spawn44(spec.command, spec.args, {
|
|
41633
|
-
env: { ...process.env, ...spec.env },
|
|
41634
|
-
// env only — never argv
|
|
41635
|
-
stdio: ["pipe", "pipe", "inherit"]
|
|
41636
|
-
});
|
|
41637
|
-
this.child = child;
|
|
41638
|
-
child.stdin?.on("error", () => void 0);
|
|
41639
|
-
const rl = import_node_readline3.default.createInterface({ input: child.stdout, crlfDelay: Infinity });
|
|
41640
|
-
this.childRl = rl;
|
|
41641
|
-
rl.on("line", (line) => {
|
|
41642
|
-
if (child !== this.child) return;
|
|
41643
|
-
this.onChildLine(line, stdout);
|
|
41644
|
-
});
|
|
41645
|
-
child.on("exit", (code) => {
|
|
41646
|
-
if (child !== this.child) return;
|
|
41647
|
-
this.clearAllToolTimeouts();
|
|
41648
|
-
this.ended(code ?? 1);
|
|
41649
|
-
});
|
|
41650
|
-
}
|
|
41651
|
-
};
|
|
41652
|
-
|
|
41653
41742
|
// src/integrations/mcp-run.ts
|
|
41743
|
+
init_stdio_proxy();
|
|
41654
41744
|
var RESTART_AHEAD_MS = 5 * 60 * 1e3;
|
|
41655
41745
|
function resolveDelivery(id) {
|
|
41656
41746
|
const fromRegistry = isKnownIntegrationId(id) ? getIntegration(id).delivery.mcp ?? null : null;
|
|
@@ -41788,7 +41878,7 @@ async function mcpRun(args2) {
|
|
|
41788
41878
|
// src/commands/version.ts
|
|
41789
41879
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
41790
41880
|
function version2() {
|
|
41791
|
-
const v = true ? "2.61.
|
|
41881
|
+
const v = true ? "2.61.86" : "unknown";
|
|
41792
41882
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
41793
41883
|
}
|
|
41794
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",
|