codeam-cli 2.76.28 → 2.76.29

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 CHANGED
@@ -4,6 +4,28 @@ 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.28] — 2026-10-13
8
+
9
+ ### Added
10
+
11
+ - **cli:** Let a fleet host run another registry tag of the Box image
12
+
13
+ ### CI
14
+
15
+ - **release:** Publish to npm next and promote to latest only after the journey canary
16
+
17
+ ## [2.76.27] — 2026-10-13
18
+
19
+ ### Fixed
20
+
21
+ - **cli:** No baton state before the local agent starts (04jp)
22
+
23
+ ## [2.76.26] — 2026-10-13
24
+
25
+ ### Fixed
26
+
27
+ - **both-plugins:** Report which agents can take a prompt from the phone
28
+
7
29
  ## [2.76.25] — 2026-10-12
8
30
 
9
31
  ### 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.28" : "0.0.0-dev",
10630
+ cliVersion: true ? "2.76.29" : "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.28",
10879
+ version: "2.76.29",
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",
@@ -12239,7 +12239,7 @@ var CommandRelayService = class _CommandRelayService {
12239
12239
  // fresh + clear the "CLI update available" banner after a self-update
12240
12240
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
12241
12241
  // pair/reconnect). Older backends ignore the extra field.
12242
- ..."2.76.28" ? { ideVersion: "2.76.28" } : {}
12242
+ ..."2.76.29" ? { ideVersion: "2.76.29" } : {}
12243
12243
  };
12244
12244
  try {
12245
12245
  const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body, this.pollSecretHeader());
@@ -25991,6 +25991,8 @@ var AUTH_FAILURE_MESSAGE = (
25991
25991
  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
25992
  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
25993
  var TURN_FAILURE_MESSAGE = "\u26A0\uFE0F **The agent hit an error and couldn\u2019t finish this turn.** Please send your message again.";
25994
+ 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.";
25995
+ var IDLE_TURN_RE = /ACP prompt idle/;
25994
25996
  function emptyReplyMessage(agent) {
25995
25997
  const label = isKnownAgentId(agent) ? AGENT_REGISTRY[agent].displayName : agent;
25996
25998
  const binary = isKnownAgentId(agent) ? AGENT_REGISTRY[agent].binaryName : agent;
@@ -26066,7 +26068,9 @@ ${opts.recentStderr}`);
26066
26068
  if (looksLikeProviderOutage(opts.detail) || looksLikeProviderOutage(opts.recentStderr)) {
26067
26069
  return providerOutageMessage(opts.agent, opts.railWireId);
26068
26070
  }
26069
- if (!opts.hadText) return TURN_FAILURE_MESSAGE;
26071
+ if (!opts.hadText) {
26072
+ return IDLE_TURN_RE.test(opts.detail) ? IDLE_TURN_FAILURE_MESSAGE : TURN_FAILURE_MESSAGE;
26073
+ }
26070
26074
  return null;
26071
26075
  }
26072
26076
  var WINDOWS_CONTROL_C_EXIT = 3221225786;
@@ -36993,6 +36997,7 @@ var AGENT_ENV_WITHHELD = ["PREVIEW_TUNNEL_TOKEN", "PREVIEW_TUNNEL_HOSTNAME"];
36993
36997
  var LOADSESSION_TIMEOUT_MS = 6e4;
36994
36998
  var PROMPT_IDLE_TIMEOUT_MS = 9e4;
36995
36999
  var PROMPT_ACTIVE_IDLE_TIMEOUT_MS = 6e5;
37000
+ var ABANDONED_TURN_SETTLE_MS = 1e4;
36996
37001
  var CLIENT_CAPABILITIES = {
36997
37002
  fs: { readTextFile: true, writeTextFile: true },
36998
37003
  terminal: false
@@ -37397,15 +37402,20 @@ var AcpClient = class {
37397
37402
  `prompt \u2192 session=${this.sessionId.slice(0, 8)} textChars=${textLen} imageBlocks=${imageCount}`
37398
37403
  );
37399
37404
  const t0 = Date.now();
37405
+ const sessionId = this.sessionId;
37400
37406
  const send = this.connection.prompt({
37401
- sessionId: this.sessionId,
37407
+ sessionId,
37402
37408
  prompt: blocks
37403
37409
  });
37410
+ let idleTripped = false;
37404
37411
  const idle = createIdleTimeout(
37405
37412
  PROMPT_IDLE_TIMEOUT_MS,
37406
- () => new Error(
37407
- `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.`
37408
- ),
37413
+ () => {
37414
+ idleTripped = true;
37415
+ return new Error(
37416
+ `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.`
37417
+ );
37418
+ },
37409
37419
  PROMPT_ACTIVE_IDLE_TIMEOUT_MS
37410
37420
  );
37411
37421
  this.promptIdle = idle;
@@ -37425,12 +37435,41 @@ var AcpClient = class {
37425
37435
  "acpClient",
37426
37436
  `prompt \u2190 failed elapsedMs=${Date.now() - t0} err=${err instanceof Error ? err.message : String(err)}`
37427
37437
  );
37438
+ if (idleTripped) await this.cancelAbandonedTurn(sessionId, send);
37428
37439
  throw err;
37429
37440
  } finally {
37430
37441
  idle.clear();
37431
37442
  this.promptIdle = null;
37432
37443
  }
37433
37444
  }
37445
+ /**
37446
+ * Cancel a turn the idle watchdog abandoned and wait, bounded, for the
37447
+ * adapter to answer its `session/prompt` — the proof the turn is over before
37448
+ * the next prompt is sent. Best-effort: a dead adapter can't hold the queue
37449
+ * longer than {@link ABANDONED_TURN_SETTLE_MS}.
37450
+ */
37451
+ async cancelAbandonedTurn(sessionId, send) {
37452
+ try {
37453
+ await this.connection?.cancel({ sessionId });
37454
+ } catch (err) {
37455
+ const msg = err instanceof Error ? err.message : String(err);
37456
+ log.warn("acpClient", `cancel of abandoned turn failed: ${msg}`);
37457
+ return;
37458
+ }
37459
+ let timer;
37460
+ const settled = await Promise.race([
37461
+ send.then(
37462
+ () => true,
37463
+ () => true
37464
+ ),
37465
+ new Promise((resolve13) => {
37466
+ timer = setTimeout(() => resolve13(false), ABANDONED_TURN_SETTLE_MS);
37467
+ timer.unref?.();
37468
+ })
37469
+ ]);
37470
+ clearTimeout(timer);
37471
+ log.info("acpClient", `abandoned turn cancelled settled=${settled}`);
37472
+ }
37434
37473
  /**
37435
37474
  * True when a `session/prompt` rejection is the "the agent closed its ACP
37436
37475
  * session between turns" fact — the kimi post-turn/idle close. Keyed on the
@@ -40626,6 +40665,27 @@ async function postCredentialSync(opts, fetchImpl = fetch) {
40626
40665
  }
40627
40666
  }
40628
40667
 
40668
+ // src/agents/acp/turn-queue.ts
40669
+ var TurnQueue = class {
40670
+ tail = Promise.resolve();
40671
+ active = 0;
40672
+ /** True while a turn runs or waits to run. */
40673
+ get busy() {
40674
+ return this.active > 0;
40675
+ }
40676
+ run(turn) {
40677
+ this.active += 1;
40678
+ const result = this.tail.then(turn).finally(() => {
40679
+ this.active -= 1;
40680
+ });
40681
+ this.tail = result.then(
40682
+ () => void 0,
40683
+ () => void 0
40684
+ );
40685
+ return result;
40686
+ }
40687
+ };
40688
+
40629
40689
  // src/services/active-conversation-marker.ts
40630
40690
  var import_node_crypto13 = require("crypto");
40631
40691
  var import_promises6 = __toESM(require("fs/promises"));
@@ -43188,7 +43248,7 @@ function reportTurn2(ctx, phase, errorCode) {
43188
43248
  });
43189
43249
  }
43190
43250
  async function startTaskH(ctx) {
43191
- const { cmd, relay, streaming, opts, turnFiles, publisher, recentStderr } = ctx;
43251
+ const { cmd, relay, streaming, opts } = ctx;
43192
43252
  const payload = cmd.payload;
43193
43253
  reportTurn2(ctx, "received");
43194
43254
  const requestedAgentId = typeof payload?.agentId === "string" ? payload.agentId.trim() : "";
@@ -43230,6 +43290,13 @@ async function startTaskH(ctx) {
43230
43290
  if (echoLine.length > 0) {
43231
43291
  showInfo(echoLine);
43232
43292
  }
43293
+ if (streaming.turns.busy) {
43294
+ log.info("acpRunner", `start_task queued behind the running turn id=${cmd.id.slice(0, 8)}`);
43295
+ }
43296
+ await streaming.turns.run(() => runStartTaskTurn(ctx, payload, blocks, promptText));
43297
+ }
43298
+ async function runStartTaskTurn(ctx, payload, blocks, promptText) {
43299
+ const { cmd, relay, streaming, opts, turnFiles, publisher, recentStderr } = ctx;
43233
43300
  await streaming.beginTurn();
43234
43301
  ctx.history.appendUserPrompt(promptText);
43235
43302
  maybePrefaceAgentStandard(blocks, opts.agent, opts.sessionId);
@@ -44123,6 +44190,8 @@ var StreamingState = class {
44123
44190
  * kinds that key purely off the adapter id.
44124
44191
  */
44125
44192
  turnSeq = 0;
44193
+ /** Runs this session's user turns one at a time (see {@link TurnQueue}). */
44194
+ turns = new TurnQueue();
44126
44195
  chatTextPublishIntervalMs;
44127
44196
  /**
44128
44197
  * Register a permission Promise. The Promise stays pending until
@@ -51344,7 +51413,7 @@ async function autoUpgradeBeforeCriticalCommand() {
51344
51413
  if (process.env.NODE_ENV === "test") return;
51345
51414
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
51346
51415
  if (process.env.CI) return;
51347
- const current2 = true ? "2.76.28" : null;
51416
+ const current2 = true ? "2.76.29" : null;
51348
51417
  if (!current2) return;
51349
51418
  const cache = readCache();
51350
51419
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -51361,7 +51430,7 @@ function checkForUpdates() {
51361
51430
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
51362
51431
  if (process.env.CI) return;
51363
51432
  if (!process.stdout.isTTY) return;
51364
- const current2 = true ? "2.76.28" : null;
51433
+ const current2 = true ? "2.76.29" : null;
51365
51434
  if (!current2) return;
51366
51435
  const cache = readCache();
51367
51436
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -51644,7 +51713,7 @@ var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
51644
51713
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
51645
51714
  var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
51646
51715
  function currentCliVersion() {
51647
- return true ? "2.76.28" : null;
51716
+ return true ? "2.76.29" : null;
51648
51717
  }
51649
51718
  async function installedVersion(deps) {
51650
51719
  const ls = await deps.run(
@@ -51855,7 +51924,7 @@ function signalHostReady(send = process.send?.bind(process)) {
51855
51924
  }
51856
51925
  function defaultDeps() {
51857
51926
  return {
51858
- ownVersion: true ? "2.76.28" : null,
51927
+ ownVersion: true ? "2.76.29" : null,
51859
51928
  root: cliVersionsRoot(),
51860
51929
  args: process.argv.slice(3),
51861
51930
  execPath: process.execPath,
@@ -54393,7 +54462,7 @@ function checkChokidar() {
54393
54462
  }
54394
54463
  async function doctor(args2 = []) {
54395
54464
  const json = args2.includes("--json");
54396
- const cliVersion = true ? "2.76.28" : "0.0.0-dev";
54465
+ const cliVersion = true ? "2.76.29" : "0.0.0-dev";
54397
54466
  const apiBase2 = resolveApiBaseUrl();
54398
54467
  const diagnosticId = (0, import_node_crypto17.randomUUID)();
54399
54468
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -54929,7 +54998,7 @@ async function mcpWarm(argv = [], opts = {}) {
54929
54998
  // src/commands/version.ts
54930
54999
  var import_picocolors15 = __toESM(require("picocolors"));
54931
55000
  function version2() {
54932
- const v = true ? "2.76.28" : "unknown";
55001
+ const v = true ? "2.76.29" : "unknown";
54933
55002
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
54934
55003
  }
54935
55004
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.76.28",
3
+ "version": "2.76.29",
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",