codeam-cli 2.76.34 → 2.76.35

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,13 @@ 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.34] — 2026-10-21
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Collect old versioned installs on every self-update tick (#983)
12
+ - **cli:** Migrate the beads schema on start and pin bd to 1.3.1 in CLI and Box (#984)
13
+
7
14
  ## [2.76.33] — 2026-10-14
8
15
 
9
16
  ### Added
package/dist/index.js CHANGED
@@ -10636,7 +10636,7 @@ function readAnonId() {
10636
10636
  }
10637
10637
  function superProperties() {
10638
10638
  return {
10639
- cliVersion: true ? "2.76.34" : "0.0.0-dev",
10639
+ cliVersion: true ? "2.76.35" : "0.0.0-dev",
10640
10640
  nodeVersion: process.version,
10641
10641
  platform: process.platform,
10642
10642
  arch: process.arch,
@@ -10885,7 +10885,7 @@ var http = __toESM(require("http"));
10885
10885
  // package.json
10886
10886
  var package_default = {
10887
10887
  name: "codeam-cli",
10888
- version: "2.76.34",
10888
+ version: "2.76.35",
10889
10889
  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.",
10890
10890
  type: "commonjs",
10891
10891
  main: "dist/index.js",
@@ -12261,7 +12261,7 @@ var CommandRelayService = class _CommandRelayService {
12261
12261
  // fresh + clear the "CLI update available" banner after a self-update
12262
12262
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
12263
12263
  // pair/reconnect). Older backends ignore the extra field.
12264
- ..."2.76.34" ? { ideVersion: "2.76.34" } : {}
12264
+ ..."2.76.35" ? { ideVersion: "2.76.35" } : {}
12265
12265
  };
12266
12266
  try {
12267
12267
  const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body, this.pollSecretHeader());
@@ -26033,6 +26033,18 @@ var ONE_M_CREDITS_MESSAGE = "\u{1F504} **Reconnect your Claude subscription to c
26033
26033
  var TURN_FAILURE_MESSAGE = "\u26A0\uFE0F **The agent hit an error and couldn\u2019t finish this turn.** Please send your message again.";
26034
26034
  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.";
26035
26035
  var IDLE_TURN_RE = /ACP prompt idle/;
26036
+ var AGENT_FREE_LIMIT_RE = /Free usage limit reached/i;
26037
+ function looksLikeAgentFreeLimit(text) {
26038
+ return AGENT_FREE_LIMIT_RE.test(text);
26039
+ }
26040
+ var AGENT_FREE_LIMIT_MESSAGE = [
26041
+ "\u26A0\uFE0F **OpenCode\u2019s free models have hit their usage limit, so this message wasn\u2019t answered.**",
26042
+ "",
26043
+ "Messages will keep failing until the limit resets. To keep going now:",
26044
+ "\u2022 add your own provider key for opencode in **Profile \u203A Agents** (OpenRouter, Anthropic, OpenAI, \u2026),",
26045
+ "\u2022 switch this session to another agent, or",
26046
+ "\u2022 subscribe to OpenCode Go: [opencode.ai/go](https://opencode.ai/go)."
26047
+ ].join("\n");
26036
26048
  function emptyReplyMessage(agent) {
26037
26049
  const label = isKnownAgentId(agent) ? AGENT_REGISTRY[agent].displayName : agent;
26038
26050
  const binary = isKnownAgentId(agent) ? AGENT_REGISTRY[agent].binaryName : agent;
@@ -26096,6 +26108,9 @@ function failureBubble(opts) {
26096
26108
  return houseAgentLimitMessage(`${opts.detail}
26097
26109
  ${opts.recentStderr}`);
26098
26110
  }
26111
+ if (looksLikeAgentFreeLimit(opts.detail) || looksLikeAgentFreeLimit(opts.recentStderr)) {
26112
+ return AGENT_FREE_LIMIT_MESSAGE;
26113
+ }
26099
26114
  if (looksLikeByoProviderBilling(opts.detail, env) || looksLikeByoProviderBilling(opts.recentStderr, env)) {
26100
26115
  return byoProviderBillingMessage(byoProviderName({ env, agent: opts.agent }));
26101
26116
  }
@@ -31845,6 +31860,7 @@ function isLocalSession(env = process.env) {
31845
31860
 
31846
31861
  // src/agents/acp/adapters.ts
31847
31862
  var require_ = require;
31863
+ var OPENCODE_FATAL_TURN_STDERR_RE = /message="stream error".*error\.error="[^"]*(Free usage limit reached|insufficient[_ ]quota|invalid[_ ]api[_ ]key|incorrect api key|unauthorized)/i;
31848
31864
  function claudeBinaryWaiter(opts = {}) {
31849
31865
  return waitForClaudeNativeBinary(opts).then((p2) => p2 !== null);
31850
31866
  }
@@ -32004,8 +32020,12 @@ var REGISTRY = {
32004
32020
  // the ACP client spawns the adapter with `env: { ...process.env, ...extraEnv }`.
32005
32021
  opencode: () => ({
32006
32022
  command: "opencode",
32007
- args: ["acp"],
32023
+ // `--print-logs --log-level ERROR`: opencode writes its provider errors only
32024
+ // to its own log file, so without these flags they never reach the adapter
32025
+ // stderr we read (see OPENCODE_FATAL_TURN_STDERR_RE).
32026
+ args: ["acp", "--print-logs", "--log-level", "ERROR"],
32008
32027
  requiresAgentBinary: "opencode",
32028
+ fatalTurnStderr: OPENCODE_FATAL_TURN_STDERR_RE,
32009
32029
  waitForBinary: async (o) => {
32010
32030
  if (isLocalSession()) await ensureOpencodeInstalled();
32011
32031
  augmentOpencodePath();
@@ -37132,6 +37152,9 @@ var _acpStartSeam = {
37132
37152
  var PROTOCOL_VERSION3 = 1;
37133
37153
  var FATAL_STARTUP_RE = /IneligibleTierError|UNSUPPORTED_CLIENT|no longer supported for Gemini Code Assist|not eligible for Gemini Code Assist|Error authenticating|ProjectIdRequiredError/i;
37134
37154
  var NEWSESSION_TIMEOUT_MS = 12e4;
37155
+ function agentErrorOf(line) {
37156
+ return /error\.error="([^"]+)"/.exec(line)?.[1] ?? line;
37157
+ }
37135
37158
  var MCP_STARTUP_TIMEOUT_MS = NEWSESSION_TIMEOUT_MS - 3e4;
37136
37159
  var AGENT_ENV_WITHHELD = ["PREVIEW_TUNNEL_TOKEN", "PREVIEW_TUNNEL_HOSTNAME"];
37137
37160
  var LOADSESSION_TIMEOUT_MS = 6e4;
@@ -37237,6 +37260,12 @@ var AcpClient = class {
37237
37260
  * engages; with it, the crash rejects immediately → retry respawns once the
37238
37261
  * install settles. Broader than {@link startupFailureReject} (newSession-only). */
37239
37262
  startAbortReject = null;
37263
+ /** The adapter's {@link AdapterSpec.fatalTurnStderr}, set at spawn. */
37264
+ fatalTurnStderr = null;
37265
+ /** Set while a `session/prompt` is in flight; the stderr watcher calls it on
37266
+ * a {@link fatalTurnStderr} line to end the turn now (opencode keeps a turn
37267
+ * open forever after a terminal provider error — see the adapter spec). */
37268
+ turnFailureReject = null;
37240
37269
  /**
37241
37270
  * Spawn the adapter + handshake, retrying a TRANSIENT in-adapter spawn race.
37242
37271
  *
@@ -37325,6 +37354,7 @@ var AcpClient = class {
37325
37354
  "acpClient",
37326
37355
  `provider routing ${formatProviderRouting(describeProviderRouting(childEnv, { cwd }), adapter.command)}`
37327
37356
  );
37357
+ this.fatalTurnStderr = adapter.fatalTurnStderr ?? null;
37328
37358
  const child = (0, import_node_child_process28.spawn)(adapter.command, adapter.args, {
37329
37359
  cwd,
37330
37360
  env: childEnv,
@@ -37350,16 +37380,7 @@ var AcpClient = class {
37350
37380
  child.stderr?.on("data", (chunk) => {
37351
37381
  for (const line of chunk.split(/\r?\n/)) {
37352
37382
  const trimmed = line.trim();
37353
- if (trimmed) {
37354
- log.info("acpAdapter", trimmed);
37355
- this.opts.onStderr?.(trimmed);
37356
- this.recentStderr.push(trimmed);
37357
- if (this.recentStderr.length > 12) this.recentStderr.shift();
37358
- if (this.startupFailureReject && FATAL_STARTUP_RE.test(trimmed)) {
37359
- this.startupFailureReject(new Error(`AGENT_STARTUP_FAILED: ${trimmed}`));
37360
- this.startupFailureReject = null;
37361
- }
37362
- }
37383
+ if (trimmed) this.onAdapterStderrLine(trimmed);
37363
37384
  }
37364
37385
  });
37365
37386
  child.on("exit", (code, signal) => {
@@ -37559,9 +37580,16 @@ var AcpClient = class {
37559
37580
  PROMPT_ACTIVE_IDLE_TIMEOUT_MS
37560
37581
  );
37561
37582
  this.promptIdle = idle;
37583
+ let fatalTripped = false;
37584
+ const fatal = new Promise((_2, reject) => {
37585
+ this.turnFailureReject = (err) => {
37586
+ fatalTripped = true;
37587
+ reject(err);
37588
+ };
37589
+ });
37562
37590
  this.pendingToolCalls.clear();
37563
37591
  try {
37564
- const result = await Promise.race([send, idle.promise]);
37592
+ const result = await Promise.race([send, idle.promise, fatal]);
37565
37593
  await new Promise((resolve13) => setImmediate(resolve13));
37566
37594
  log.info(
37567
37595
  "acpClient",
@@ -37575,15 +37603,32 @@ var AcpClient = class {
37575
37603
  "acpClient",
37576
37604
  `prompt \u2190 failed elapsedMs=${Date.now() - t0} err=${err instanceof Error ? err.message : String(err)}`
37577
37605
  );
37578
- if (idleTripped) await this.cancelAbandonedTurn(sessionId, send);
37606
+ if (idleTripped || fatalTripped) await this.cancelAbandonedTurn(sessionId, send);
37579
37607
  throw err;
37580
37608
  } finally {
37581
37609
  idle.clear();
37582
37610
  this.promptIdle = null;
37611
+ this.turnFailureReject = null;
37612
+ }
37613
+ }
37614
+ /** One non-empty adapter stderr line: logged, kept in the ring, and checked
37615
+ * for the fatal startup / fatal turn errors that end a stuck RPC early. */
37616
+ onAdapterStderrLine(trimmed) {
37617
+ log.info("acpAdapter", trimmed);
37618
+ this.opts.onStderr?.(trimmed);
37619
+ this.recentStderr.push(trimmed);
37620
+ if (this.recentStderr.length > 12) this.recentStderr.shift();
37621
+ if (this.startupFailureReject && FATAL_STARTUP_RE.test(trimmed)) {
37622
+ this.startupFailureReject(new Error(`AGENT_STARTUP_FAILED: ${trimmed}`));
37623
+ this.startupFailureReject = null;
37624
+ }
37625
+ if (this.turnFailureReject && this.fatalTurnStderr?.test(trimmed)) {
37626
+ this.turnFailureReject(new Error(`AGENT_TURN_FAILED: ${agentErrorOf(trimmed)}`));
37627
+ this.turnFailureReject = null;
37583
37628
  }
37584
37629
  }
37585
37630
  /**
37586
- * Cancel a turn the idle watchdog abandoned and wait, bounded, for the
37631
+ * Cancel a turn the idle watchdog (or a fatal stderr error) abandoned and wait, bounded, for the
37587
37632
  * adapter to answer its `session/prompt` — the proof the turn is over before
37588
37633
  * the next prompt is sent. Best-effort: a dead adapter can't hold the queue
37589
37634
  * longer than {@link ABANDONED_TURN_SETTLE_MS}.
@@ -43678,7 +43723,7 @@ async function runStartTaskTurn(ctx, payload, blocks, promptText) {
43678
43723
  reportTurn2(
43679
43724
  ctx,
43680
43725
  "failed",
43681
- bubble === AUTH_FAILURE_MESSAGE ? "AUTH_FAILED" : bubble === ONE_M_CREDITS_MESSAGE ? "ONE_M_CREDITS" : failed.partialReplyKept ? "TURN_ERROR_PARTIAL" : "TURN_ERROR"
43726
+ bubble === AUTH_FAILURE_MESSAGE ? "AUTH_FAILED" : bubble === ONE_M_CREDITS_MESSAGE ? "ONE_M_CREDITS" : bubble === AGENT_FREE_LIMIT_MESSAGE ? "AGENT_FREE_LIMIT" : failed.partialReplyKept ? "TURN_ERROR_PARTIAL" : "TURN_ERROR"
43682
43727
  );
43683
43728
  if (bubble === AUTH_FAILURE_MESSAGE || bubble === ONE_M_CREDITS_MESSAGE) {
43684
43729
  void reportCredentialInvalid(opts);
@@ -51622,7 +51667,7 @@ async function autoUpgradeBeforeCriticalCommand() {
51622
51667
  if (process.env.NODE_ENV === "test") return;
51623
51668
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
51624
51669
  if (process.env.CI) return;
51625
- const current2 = true ? "2.76.34" : null;
51670
+ const current2 = true ? "2.76.35" : null;
51626
51671
  if (!current2) return;
51627
51672
  const cache = readCache();
51628
51673
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -51639,7 +51684,7 @@ function checkForUpdates() {
51639
51684
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
51640
51685
  if (process.env.CI) return;
51641
51686
  if (!process.stdout.isTTY) return;
51642
- const current2 = true ? "2.76.34" : null;
51687
+ const current2 = true ? "2.76.35" : null;
51643
51688
  if (!current2) return;
51644
51689
  const cache = readCache();
51645
51690
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -51945,7 +51990,7 @@ var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
51945
51990
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
51946
51991
  var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
51947
51992
  function currentCliVersion() {
51948
- return true ? "2.76.34" : null;
51993
+ return true ? "2.76.35" : null;
51949
51994
  }
51950
51995
  async function installedVersion(deps) {
51951
51996
  const ls = await deps.run(
@@ -52168,7 +52213,7 @@ function signalHostReady(send = process.send?.bind(process)) {
52168
52213
  }
52169
52214
  function defaultDeps() {
52170
52215
  return {
52171
- ownVersion: true ? "2.76.34" : null,
52216
+ ownVersion: true ? "2.76.35" : null,
52172
52217
  root: cliVersionsRoot(),
52173
52218
  args: process.argv.slice(3),
52174
52219
  execPath: process.execPath,
@@ -54706,7 +54751,7 @@ function checkChokidar() {
54706
54751
  }
54707
54752
  async function doctor(args2 = []) {
54708
54753
  const json = args2.includes("--json");
54709
- const cliVersion = true ? "2.76.34" : "0.0.0-dev";
54754
+ const cliVersion = true ? "2.76.35" : "0.0.0-dev";
54710
54755
  const apiBase2 = resolveApiBaseUrl();
54711
54756
  const diagnosticId = (0, import_node_crypto17.randomUUID)();
54712
54757
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -55242,7 +55287,7 @@ async function mcpWarm(argv = [], opts = {}) {
55242
55287
  // src/commands/version.ts
55243
55288
  var import_picocolors15 = __toESM(require("picocolors"));
55244
55289
  function version2() {
55245
- const v = true ? "2.76.34" : "unknown";
55290
+ const v = true ? "2.76.35" : "unknown";
55246
55291
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
55247
55292
  }
55248
55293
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.76.34",
3
+ "version": "2.76.35",
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",