codeam-cli 2.60.6 → 2.60.7

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,26 @@ 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.60.6] — 2026-07-08
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Serialize ACP prompts so a 2nd in-flight turn can't clobber the watchdog
12
+
13
+ ## [2.60.5] — 2026-07-08
14
+
15
+ ### Added
16
+
17
+ - **cli:** Baton support for cursor + gate to agents with a resumable transcript
18
+
19
+ ### Documentation
20
+
21
+ - **cli:** Document the Session Baton (native TUI <-> mobile ACP) architecture + hand-off invariants
22
+
23
+ ### Fixed
24
+
25
+ - **cli:** Serialize baton state POSTs so handback never sticks on "Switching…"
26
+
7
27
  ## [2.60.4] — 2026-07-08
8
28
 
9
29
  ### Fixed
package/dist/index.js CHANGED
@@ -5653,7 +5653,7 @@ function readAnonId() {
5653
5653
  }
5654
5654
  function superProperties() {
5655
5655
  return {
5656
- cliVersion: true ? "2.60.6" : "0.0.0-dev",
5656
+ cliVersion: true ? "2.60.7" : "0.0.0-dev",
5657
5657
  nodeVersion: process.version,
5658
5658
  platform: process.platform,
5659
5659
  arch: process.arch,
@@ -5834,7 +5834,7 @@ var os4 = __toESM(require("os"));
5834
5834
  // package.json
5835
5835
  var package_default = {
5836
5836
  name: "codeam-cli",
5837
- version: "2.60.6",
5837
+ version: "2.60.7",
5838
5838
  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.",
5839
5839
  type: "commonjs",
5840
5840
  main: "dist/index.js",
@@ -6905,7 +6905,7 @@ var CommandRelayService = class {
6905
6905
  // fresh + clear the "CLI update available" banner after a self-update
6906
6906
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
6907
6907
  // pair/reconnect). Older backends ignore the extra field.
6908
- ..."2.60.6" ? { ideVersion: "2.60.6" } : {}
6908
+ ..."2.60.7" ? { ideVersion: "2.60.7" } : {}
6909
6909
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
6910
6910
  }
6911
6911
  /**
@@ -15986,7 +15986,7 @@ async function autoUpgradeBeforeCriticalCommand() {
15986
15986
  if (process.env.NODE_ENV === "test") return;
15987
15987
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
15988
15988
  if (process.env.CI) return;
15989
- const current = true ? "2.60.6" : null;
15989
+ const current = true ? "2.60.7" : null;
15990
15990
  if (!current) return;
15991
15991
  const cache = readCache();
15992
15992
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -16003,7 +16003,7 @@ function checkForUpdates() {
16003
16003
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
16004
16004
  if (process.env.CI) return;
16005
16005
  if (!process.stdout.isTTY) return;
16006
- const current = true ? "2.60.6" : null;
16006
+ const current = true ? "2.60.7" : null;
16007
16007
  if (!current) return;
16008
16008
  const cache = readCache();
16009
16009
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -16023,7 +16023,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
16023
16023
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
16024
16024
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
16025
16025
  function currentCliVersion() {
16026
- return true ? "2.60.6" : null;
16026
+ return true ? "2.60.7" : null;
16027
16027
  }
16028
16028
  function runCmd(cmd, args2, timeoutMs) {
16029
16029
  return new Promise((resolve7) => {
@@ -24850,6 +24850,11 @@ function createIdleTimeout(idleMs, makeError) {
24850
24850
  }
24851
24851
 
24852
24852
  // src/agents/acp/client.ts
24853
+ var TRANSIENT_ADAPTER_SPAWN_RE = /ETXTBSY|ENOENT/;
24854
+ var MAX_START_ATTEMPTS = 5;
24855
+ var _acpStartSeam = {
24856
+ sleep: (ms) => new Promise((r) => setTimeout(r, ms))
24857
+ };
24853
24858
  var PROTOCOL_VERSION2 = 1;
24854
24859
  var FATAL_STARTUP_RE = /IneligibleTierError|UNSUPPORTED_CLIENT|no longer supported for Gemini Code Assist|not eligible for Gemini Code Assist|Error authenticating|ProjectIdRequiredError/i;
24855
24860
  var NEWSESSION_TIMEOUT_MS = 12e4;
@@ -24895,15 +24900,57 @@ var AcpClient = class {
24895
24900
  * so without this the session hangs forever ("loading… / offline"). */
24896
24901
  startupFailureReject = null;
24897
24902
  /**
24898
- * Spawn the adapter + perform the initial handshake (initialize
24899
- * → newSession). Returns the ACP-assigned sessionId so the caller
24900
- * can route subsequent prompts, plus optional model + tier that
24901
- * some adapters (codex-acp today) surface on the newSession
24902
- * response used by the runner to enrich the welcome card
24903
- * subtitle without an extra round-trip.
24903
+ * Spawn the adapter + handshake, retrying a TRANSIENT in-adapter spawn race.
24904
+ *
24905
+ * The adapter itself execs the real agent binary (claude-agent-acp spawns the
24906
+ * ~250MB SDK-bundled `claude` during newSession). On a fresh/waking codespace
24907
+ * that binary is momentarily open-for-write the adapter rejects newSession
24908
+ * with `-32603 spawn ETXTBSY` (or ENOENT before it lands). Both clear within
24909
+ * ms, so we respawn the adapter + re-handshake up to {@link MAX_START_ATTEMPTS}
24910
+ * times. `startOnce` fully cleans up on failure (see cleanupAfterFailedStart),
24911
+ * so each retry starts from a clean slate. Non-transient failures throw on the
24912
+ * first attempt — no masking of real auth/outage errors.
24904
24913
  */
24905
24914
  async start() {
24915
+ let lastErr;
24916
+ for (let attempt = 1; attempt <= MAX_START_ATTEMPTS; attempt += 1) {
24917
+ try {
24918
+ return await this.startOnce();
24919
+ } catch (err) {
24920
+ lastErr = err;
24921
+ if (attempt < MAX_START_ATTEMPTS && this.isTransientAdapterSpawn(err)) {
24922
+ log.info(
24923
+ "acpClient",
24924
+ `adapter hit a transient spawn race (binary busy) \u2014 retrying start ${attempt + 1}/${MAX_START_ATTEMPTS}`
24925
+ );
24926
+ await _acpStartSeam.sleep(400 * attempt);
24927
+ continue;
24928
+ }
24929
+ throw err;
24930
+ }
24931
+ }
24932
+ throw lastErr;
24933
+ }
24934
+ /** True when a failed {@link startOnce} was caused by the adapter's OWN
24935
+ * transient spawn of the agent binary (ETXTBSY/ENOENT). Checks the thrown
24936
+ * error's message/data AND the adapter stderr ring — the adapter logs the
24937
+ * real cause to stderr while returning a generic `-32603 Internal error`. */
24938
+ isTransientAdapterSpawn(err) {
24939
+ const parts = [...this.recentStderr];
24940
+ if (err instanceof Error) parts.push(err.message);
24941
+ if (err && typeof err === "object") {
24942
+ const e = err;
24943
+ try {
24944
+ parts.push(JSON.stringify(e.data));
24945
+ } catch {
24946
+ }
24947
+ if (typeof e.details === "string") parts.push(e.details);
24948
+ }
24949
+ return TRANSIENT_ADAPTER_SPAWN_RE.test(parts.join(" "));
24950
+ }
24951
+ async startOnce() {
24906
24952
  if (this.child) throw new Error("AcpClient already started");
24953
+ this.recentStderr.length = 0;
24907
24954
  const { adapter, cwd } = this.opts;
24908
24955
  const augmentedPath = expandPathForAgentBinaries(process.env.PATH ?? "");
24909
24956
  log.info(
@@ -32755,7 +32802,7 @@ function checkChokidar() {
32755
32802
  }
32756
32803
  async function doctor(args2 = []) {
32757
32804
  const json = args2.includes("--json");
32758
- const cliVersion = true ? "2.60.6" : "0.0.0-dev";
32805
+ const cliVersion = true ? "2.60.7" : "0.0.0-dev";
32759
32806
  const apiBase2 = resolveApiBaseUrl();
32760
32807
  const diagnosticId = (0, import_node_crypto9.randomUUID)();
32761
32808
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -32954,7 +33001,7 @@ async function completion(args2) {
32954
33001
  // src/commands/version.ts
32955
33002
  var import_picocolors15 = __toESM(require("picocolors"));
32956
33003
  function version2() {
32957
- const v = true ? "2.60.6" : "unknown";
33004
+ const v = true ? "2.60.7" : "unknown";
32958
33005
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
32959
33006
  }
32960
33007
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.60.6",
3
+ "version": "2.60.7",
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",