codeam-cli 2.76.28 → 2.76.30
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 +28 -0
- package/dist/index.js +96 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,34 @@ 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.76.29] — 2026-10-13
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Run a queued message only after the running turn closes
|
|
12
|
+
|
|
13
|
+
## [2.76.28] — 2026-10-13
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **cli:** Let a fleet host run another registry tag of the Box image
|
|
18
|
+
|
|
19
|
+
### CI
|
|
20
|
+
|
|
21
|
+
- **release:** Publish to npm next and promote to latest only after the journey canary
|
|
22
|
+
|
|
23
|
+
## [2.76.27] — 2026-10-13
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **cli:** No baton state before the local agent starts (04jp)
|
|
28
|
+
|
|
29
|
+
## [2.76.26] — 2026-10-13
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- **both-plugins:** Report which agents can take a prompt from the phone
|
|
34
|
+
|
|
7
35
|
## [2.76.25] — 2026-10-12
|
|
8
36
|
|
|
9
37
|
### CI
|
package/dist/index.js
CHANGED
|
@@ -10627,7 +10627,7 @@ function readAnonId() {
|
|
|
10627
10627
|
}
|
|
10628
10628
|
function superProperties() {
|
|
10629
10629
|
return {
|
|
10630
|
-
cliVersion: true ? "2.76.
|
|
10630
|
+
cliVersion: true ? "2.76.30" : "0.0.0-dev",
|
|
10631
10631
|
nodeVersion: process.version,
|
|
10632
10632
|
platform: process.platform,
|
|
10633
10633
|
arch: process.arch,
|
|
@@ -10876,7 +10876,7 @@ var http = __toESM(require("http"));
|
|
|
10876
10876
|
// package.json
|
|
10877
10877
|
var package_default = {
|
|
10878
10878
|
name: "codeam-cli",
|
|
10879
|
-
version: "2.76.
|
|
10879
|
+
version: "2.76.30",
|
|
10880
10880
|
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.",
|
|
10881
10881
|
type: "commonjs",
|
|
10882
10882
|
main: "dist/index.js",
|
|
@@ -11064,7 +11064,9 @@ async function fetchCurrentPluginAuthToken(sessionId, pluginId, pollSecret, onUs
|
|
|
11064
11064
|
const data = result?.data;
|
|
11065
11065
|
if (!data?.paired) return null;
|
|
11066
11066
|
if (onUserId && typeof data.userId === "string" && data.userId.length > 0) {
|
|
11067
|
-
|
|
11067
|
+
const user = data.user;
|
|
11068
|
+
const plan = typeof user === "object" && user !== null && "plan" in user && typeof user.plan === "string" ? user.plan : void 0;
|
|
11069
|
+
onUserId(data.userId, plan);
|
|
11068
11070
|
}
|
|
11069
11071
|
const token = data.pluginAuthToken;
|
|
11070
11072
|
return typeof token === "string" && token.length > 0 ? token : null;
|
|
@@ -12239,7 +12241,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
12239
12241
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
12240
12242
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
12241
12243
|
// pair/reconnect). Older backends ignore the extra field.
|
|
12242
|
-
..."2.76.
|
|
12244
|
+
..."2.76.30" ? { ideVersion: "2.76.30" } : {}
|
|
12243
12245
|
};
|
|
12244
12246
|
try {
|
|
12245
12247
|
const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body, this.pollSecretHeader());
|
|
@@ -25991,6 +25993,8 @@ var AUTH_FAILURE_MESSAGE = (
|
|
|
25991
25993
|
var CURSOR_UPGRADE_MESSAGE = "\u26A1 **Cursor needs a paid plan to run the agent.**\n\nThe headless Cursor Agent requires Cursor **Pro** \u2014 your Free plan\u2019s included usage does NOT cover Agent runs, even with quota left. This is your Cursor account (not CodeAgent). Upgrade, then send your message again:\n\n[Upgrade to Cursor Pro \u2192](https://cursor.com/dashboard)";
|
|
25992
25994
|
var ONE_M_CREDITS_MESSAGE = "\u{1F504} **Reconnect your Claude subscription to continue.**\n\nClaude requested 1M-context but your account doesn\u2019t have the usage credits for it on this credential. Reconnecting refreshes your subscription so the agent can keep going \u2014 disabling 1M context won\u2019t fix a credits gate.\n\nTap [Reconnect this agent](codeam://reauth) to reconnect your Claude subscription in Profile \u203A Agents, then send your message again.";
|
|
25993
25995
|
var TURN_FAILURE_MESSAGE = "\u26A0\uFE0F **The agent hit an error and couldn\u2019t finish this turn.** Please send your message again.";
|
|
25996
|
+
var IDLE_TURN_FAILURE_MESSAGE = "\u26A0\uFE0F **The agent stopped responding, so this turn was ended.** Your message wasn\u2019t answered \u2014 send it again.";
|
|
25997
|
+
var IDLE_TURN_RE = /ACP prompt idle/;
|
|
25994
25998
|
function emptyReplyMessage(agent) {
|
|
25995
25999
|
const label = isKnownAgentId(agent) ? AGENT_REGISTRY[agent].displayName : agent;
|
|
25996
26000
|
const binary = isKnownAgentId(agent) ? AGENT_REGISTRY[agent].binaryName : agent;
|
|
@@ -26066,7 +26070,9 @@ ${opts.recentStderr}`);
|
|
|
26066
26070
|
if (looksLikeProviderOutage(opts.detail) || looksLikeProviderOutage(opts.recentStderr)) {
|
|
26067
26071
|
return providerOutageMessage(opts.agent, opts.railWireId);
|
|
26068
26072
|
}
|
|
26069
|
-
if (!opts.hadText)
|
|
26073
|
+
if (!opts.hadText) {
|
|
26074
|
+
return IDLE_TURN_RE.test(opts.detail) ? IDLE_TURN_FAILURE_MESSAGE : TURN_FAILURE_MESSAGE;
|
|
26075
|
+
}
|
|
26070
26076
|
return null;
|
|
26071
26077
|
}
|
|
26072
26078
|
var WINDOWS_CONTROL_C_EXIT = 3221225786;
|
|
@@ -30337,6 +30343,7 @@ function prewarmPreviewDetection(runtime) {
|
|
|
30337
30343
|
try {
|
|
30338
30344
|
const cwd = process.cwd();
|
|
30339
30345
|
if (await readPreviewConfig(cwd)) return;
|
|
30346
|
+
if (isEmptyScratchProject(cwd)) return;
|
|
30340
30347
|
const { raw } = await runDetectOneShot(generateOneShot);
|
|
30341
30348
|
const detection = safeParseDetection(raw);
|
|
30342
30349
|
if (!detection) {
|
|
@@ -36993,6 +37000,7 @@ var AGENT_ENV_WITHHELD = ["PREVIEW_TUNNEL_TOKEN", "PREVIEW_TUNNEL_HOSTNAME"];
|
|
|
36993
37000
|
var LOADSESSION_TIMEOUT_MS = 6e4;
|
|
36994
37001
|
var PROMPT_IDLE_TIMEOUT_MS = 9e4;
|
|
36995
37002
|
var PROMPT_ACTIVE_IDLE_TIMEOUT_MS = 6e5;
|
|
37003
|
+
var ABANDONED_TURN_SETTLE_MS = 1e4;
|
|
36996
37004
|
var CLIENT_CAPABILITIES = {
|
|
36997
37005
|
fs: { readTextFile: true, writeTextFile: true },
|
|
36998
37006
|
terminal: false
|
|
@@ -37397,15 +37405,20 @@ var AcpClient = class {
|
|
|
37397
37405
|
`prompt \u2192 session=${this.sessionId.slice(0, 8)} textChars=${textLen} imageBlocks=${imageCount}`
|
|
37398
37406
|
);
|
|
37399
37407
|
const t0 = Date.now();
|
|
37408
|
+
const sessionId = this.sessionId;
|
|
37400
37409
|
const send = this.connection.prompt({
|
|
37401
|
-
sessionId
|
|
37410
|
+
sessionId,
|
|
37402
37411
|
prompt: blocks
|
|
37403
37412
|
});
|
|
37413
|
+
let idleTripped = false;
|
|
37404
37414
|
const idle = createIdleTimeout(
|
|
37405
37415
|
PROMPT_IDLE_TIMEOUT_MS,
|
|
37406
|
-
() =>
|
|
37407
|
-
|
|
37408
|
-
|
|
37416
|
+
() => {
|
|
37417
|
+
idleTripped = true;
|
|
37418
|
+
return new Error(
|
|
37419
|
+
`ACP prompt idle \u2014 adapter sent no updates for the idle window (${PROMPT_IDLE_TIMEOUT_MS / 1e3}s silent-from-start / ${PROMPT_ACTIVE_IDLE_TIMEOUT_MS / 1e3}s once active). Likely the underlying agent's auth or network is misconfigured; check the adapter stderr lines above (acpAdapter tag) for the actual error.`
|
|
37420
|
+
);
|
|
37421
|
+
},
|
|
37409
37422
|
PROMPT_ACTIVE_IDLE_TIMEOUT_MS
|
|
37410
37423
|
);
|
|
37411
37424
|
this.promptIdle = idle;
|
|
@@ -37425,12 +37438,41 @@ var AcpClient = class {
|
|
|
37425
37438
|
"acpClient",
|
|
37426
37439
|
`prompt \u2190 failed elapsedMs=${Date.now() - t0} err=${err instanceof Error ? err.message : String(err)}`
|
|
37427
37440
|
);
|
|
37441
|
+
if (idleTripped) await this.cancelAbandonedTurn(sessionId, send);
|
|
37428
37442
|
throw err;
|
|
37429
37443
|
} finally {
|
|
37430
37444
|
idle.clear();
|
|
37431
37445
|
this.promptIdle = null;
|
|
37432
37446
|
}
|
|
37433
37447
|
}
|
|
37448
|
+
/**
|
|
37449
|
+
* Cancel a turn the idle watchdog abandoned and wait, bounded, for the
|
|
37450
|
+
* adapter to answer its `session/prompt` — the proof the turn is over before
|
|
37451
|
+
* the next prompt is sent. Best-effort: a dead adapter can't hold the queue
|
|
37452
|
+
* longer than {@link ABANDONED_TURN_SETTLE_MS}.
|
|
37453
|
+
*/
|
|
37454
|
+
async cancelAbandonedTurn(sessionId, send) {
|
|
37455
|
+
try {
|
|
37456
|
+
await this.connection?.cancel({ sessionId });
|
|
37457
|
+
} catch (err) {
|
|
37458
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
37459
|
+
log.warn("acpClient", `cancel of abandoned turn failed: ${msg}`);
|
|
37460
|
+
return;
|
|
37461
|
+
}
|
|
37462
|
+
let timer;
|
|
37463
|
+
const settled = await Promise.race([
|
|
37464
|
+
send.then(
|
|
37465
|
+
() => true,
|
|
37466
|
+
() => true
|
|
37467
|
+
),
|
|
37468
|
+
new Promise((resolve13) => {
|
|
37469
|
+
timer = setTimeout(() => resolve13(false), ABANDONED_TURN_SETTLE_MS);
|
|
37470
|
+
timer.unref?.();
|
|
37471
|
+
})
|
|
37472
|
+
]);
|
|
37473
|
+
clearTimeout(timer);
|
|
37474
|
+
log.info("acpClient", `abandoned turn cancelled settled=${settled}`);
|
|
37475
|
+
}
|
|
37434
37476
|
/**
|
|
37435
37477
|
* True when a `session/prompt` rejection is the "the agent closed its ACP
|
|
37436
37478
|
* session between turns" fact — the kimi post-turn/idle close. Keyed on the
|
|
@@ -40626,6 +40668,27 @@ async function postCredentialSync(opts, fetchImpl = fetch) {
|
|
|
40626
40668
|
}
|
|
40627
40669
|
}
|
|
40628
40670
|
|
|
40671
|
+
// src/agents/acp/turn-queue.ts
|
|
40672
|
+
var TurnQueue = class {
|
|
40673
|
+
tail = Promise.resolve();
|
|
40674
|
+
active = 0;
|
|
40675
|
+
/** True while a turn runs or waits to run. */
|
|
40676
|
+
get busy() {
|
|
40677
|
+
return this.active > 0;
|
|
40678
|
+
}
|
|
40679
|
+
run(turn) {
|
|
40680
|
+
this.active += 1;
|
|
40681
|
+
const result = this.tail.then(turn).finally(() => {
|
|
40682
|
+
this.active -= 1;
|
|
40683
|
+
});
|
|
40684
|
+
this.tail = result.then(
|
|
40685
|
+
() => void 0,
|
|
40686
|
+
() => void 0
|
|
40687
|
+
);
|
|
40688
|
+
return result;
|
|
40689
|
+
}
|
|
40690
|
+
};
|
|
40691
|
+
|
|
40629
40692
|
// src/services/active-conversation-marker.ts
|
|
40630
40693
|
var import_node_crypto13 = require("crypto");
|
|
40631
40694
|
var import_promises6 = __toESM(require("fs/promises"));
|
|
@@ -43188,7 +43251,7 @@ function reportTurn2(ctx, phase, errorCode) {
|
|
|
43188
43251
|
});
|
|
43189
43252
|
}
|
|
43190
43253
|
async function startTaskH(ctx) {
|
|
43191
|
-
const { cmd, relay, streaming, opts
|
|
43254
|
+
const { cmd, relay, streaming, opts } = ctx;
|
|
43192
43255
|
const payload = cmd.payload;
|
|
43193
43256
|
reportTurn2(ctx, "received");
|
|
43194
43257
|
const requestedAgentId = typeof payload?.agentId === "string" ? payload.agentId.trim() : "";
|
|
@@ -43230,6 +43293,13 @@ async function startTaskH(ctx) {
|
|
|
43230
43293
|
if (echoLine.length > 0) {
|
|
43231
43294
|
showInfo(echoLine);
|
|
43232
43295
|
}
|
|
43296
|
+
if (streaming.turns.busy) {
|
|
43297
|
+
log.info("acpRunner", `start_task queued behind the running turn id=${cmd.id.slice(0, 8)}`);
|
|
43298
|
+
}
|
|
43299
|
+
await streaming.turns.run(() => runStartTaskTurn(ctx, payload, blocks, promptText));
|
|
43300
|
+
}
|
|
43301
|
+
async function runStartTaskTurn(ctx, payload, blocks, promptText) {
|
|
43302
|
+
const { cmd, relay, streaming, opts, turnFiles, publisher, recentStderr } = ctx;
|
|
43233
43303
|
await streaming.beginTurn();
|
|
43234
43304
|
ctx.history.appendUserPrompt(promptText);
|
|
43235
43305
|
maybePrefaceAgentStandard(blocks, opts.agent, opts.sessionId);
|
|
@@ -44123,6 +44193,8 @@ var StreamingState = class {
|
|
|
44123
44193
|
* kinds that key purely off the adapter id.
|
|
44124
44194
|
*/
|
|
44125
44195
|
turnSeq = 0;
|
|
44196
|
+
/** Runs this session's user turns one at a time (see {@link TurnQueue}). */
|
|
44197
|
+
turns = new TurnQueue();
|
|
44126
44198
|
chatTextPublishIntervalMs;
|
|
44127
44199
|
/**
|
|
44128
44200
|
* Register a permission Promise. The Promise stays pending until
|
|
@@ -47723,12 +47795,14 @@ async function start(requestedAgent, presetSession) {
|
|
|
47723
47795
|
`);
|
|
47724
47796
|
const cwd = process.cwd();
|
|
47725
47797
|
let reconnectUserId;
|
|
47798
|
+
let reconnectPlan;
|
|
47726
47799
|
const refreshed = await fetchCurrentPluginAuthToken(
|
|
47727
47800
|
session.id,
|
|
47728
47801
|
pluginId,
|
|
47729
47802
|
session.pollSecret,
|
|
47730
|
-
(userId) => {
|
|
47803
|
+
(userId, plan) => {
|
|
47731
47804
|
reconnectUserId = userId;
|
|
47805
|
+
reconnectPlan = plan;
|
|
47732
47806
|
}
|
|
47733
47807
|
);
|
|
47734
47808
|
if (refreshed && refreshed !== session.pluginAuthToken) {
|
|
@@ -47738,8 +47812,11 @@ async function start(requestedAgent, presetSession) {
|
|
|
47738
47812
|
} else if (refreshed) {
|
|
47739
47813
|
showInfo("Reconnected previous session.");
|
|
47740
47814
|
}
|
|
47741
|
-
|
|
47742
|
-
|
|
47815
|
+
const staleUserId = !!reconnectUserId && reconnectUserId !== session.userId;
|
|
47816
|
+
const stalePlan = !!reconnectPlan && reconnectPlan !== session.plan;
|
|
47817
|
+
if (staleUserId || stalePlan) {
|
|
47818
|
+
if (reconnectUserId) session.userId = reconnectUserId;
|
|
47819
|
+
if (reconnectPlan) session.plan = reconnectPlan;
|
|
47743
47820
|
addSession({ ...session });
|
|
47744
47821
|
}
|
|
47745
47822
|
if (session.userId) {
|
|
@@ -51344,7 +51421,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
51344
51421
|
if (process.env.NODE_ENV === "test") return;
|
|
51345
51422
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
51346
51423
|
if (process.env.CI) return;
|
|
51347
|
-
const current2 = true ? "2.76.
|
|
51424
|
+
const current2 = true ? "2.76.30" : null;
|
|
51348
51425
|
if (!current2) return;
|
|
51349
51426
|
const cache = readCache();
|
|
51350
51427
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -51361,7 +51438,7 @@ function checkForUpdates() {
|
|
|
51361
51438
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
51362
51439
|
if (process.env.CI) return;
|
|
51363
51440
|
if (!process.stdout.isTTY) return;
|
|
51364
|
-
const current2 = true ? "2.76.
|
|
51441
|
+
const current2 = true ? "2.76.30" : null;
|
|
51365
51442
|
if (!current2) return;
|
|
51366
51443
|
const cache = readCache();
|
|
51367
51444
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -51644,7 +51721,7 @@ var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
|
51644
51721
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
51645
51722
|
var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
|
|
51646
51723
|
function currentCliVersion() {
|
|
51647
|
-
return true ? "2.76.
|
|
51724
|
+
return true ? "2.76.30" : null;
|
|
51648
51725
|
}
|
|
51649
51726
|
async function installedVersion(deps) {
|
|
51650
51727
|
const ls = await deps.run(
|
|
@@ -51855,7 +51932,7 @@ function signalHostReady(send = process.send?.bind(process)) {
|
|
|
51855
51932
|
}
|
|
51856
51933
|
function defaultDeps() {
|
|
51857
51934
|
return {
|
|
51858
|
-
ownVersion: true ? "2.76.
|
|
51935
|
+
ownVersion: true ? "2.76.30" : null,
|
|
51859
51936
|
root: cliVersionsRoot(),
|
|
51860
51937
|
args: process.argv.slice(3),
|
|
51861
51938
|
execPath: process.execPath,
|
|
@@ -54393,7 +54470,7 @@ function checkChokidar() {
|
|
|
54393
54470
|
}
|
|
54394
54471
|
async function doctor(args2 = []) {
|
|
54395
54472
|
const json = args2.includes("--json");
|
|
54396
|
-
const cliVersion = true ? "2.76.
|
|
54473
|
+
const cliVersion = true ? "2.76.30" : "0.0.0-dev";
|
|
54397
54474
|
const apiBase2 = resolveApiBaseUrl();
|
|
54398
54475
|
const diagnosticId = (0, import_node_crypto17.randomUUID)();
|
|
54399
54476
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -54929,7 +55006,7 @@ async function mcpWarm(argv = [], opts = {}) {
|
|
|
54929
55006
|
// src/commands/version.ts
|
|
54930
55007
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
54931
55008
|
function version2() {
|
|
54932
|
-
const v = true ? "2.76.
|
|
55009
|
+
const v = true ? "2.76.30" : "unknown";
|
|
54933
55010
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
54934
55011
|
}
|
|
54935
55012
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.76.
|
|
3
|
+
"version": "2.76.30",
|
|
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",
|