codeam-cli 2.42.0 → 2.43.1

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/index.js +131 -13
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,36 @@ 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.43.0] — 2026-06-24
8
+
9
+ ### Added
10
+
11
+ - **cli:** Classify the 1M-context usage-credits error
12
+ - **cli:** Persist per-session disable1mContext flag
13
+ - **cli:** AcpClient accepts extraEnv for the adapter spawn
14
+ - **cli:** OneMContextRecovery offer + decision helper
15
+ - **cli:** OneMContextRecovery offer + decision helper + DI recovery factory
16
+ - **cli:** On-demand 1M-context disable recovery — offer action, re-spawn ACP with the knob, auto-rerun
17
+
18
+ ### Changed
19
+
20
+ - **cli:** Move 1M-context classifier into oneMContextRecovery (break runner import cycle)
21
+
22
+ ### Documentation
23
+
24
+ - **meta:** Record agent-failure-messaging + heartbeat + credential rules (AGENTS.md + CLAUDE.md)
25
+
26
+ ## [2.42.0] — 2026-06-24
27
+
28
+ ### Added
29
+
30
+ - **cli:** Confirm provider outage via status page on turn stall/failure (catch-all)
31
+
32
+ ### Fixed
33
+
34
+ - **cli:** Make agent-failure messaging honest — outage only on real provider error, re-auth on auth-notice replies
35
+ - **cli:** Keep the heartbeat punctual by detecting the git branch off the hot path
36
+
7
37
  ## [2.41.0] — 2026-06-24
8
38
 
9
39
  ### Added
package/dist/index.js CHANGED
@@ -476,6 +476,13 @@ function makeConfig(baseDir) {
476
476
  matches.sort((a, b) => b.pairedAt - a.pairedAt);
477
477
  return matches[0];
478
478
  }
479
+ function setDisable1mContext2(pluginId, value) {
480
+ const c2 = load();
481
+ const s = c2.sessions.find((x) => x.pluginId === pluginId);
482
+ if (!s) return;
483
+ s.disable1mContext = value;
484
+ save(c2);
485
+ }
479
486
  function clearAll2() {
480
487
  try {
481
488
  fs.unlinkSync(file);
@@ -488,7 +495,7 @@ function makeConfig(baseDir) {
488
495
  function loadCliConfig2() {
489
496
  return load();
490
497
  }
491
- return { getConfig: getConfig2, ensurePluginId: ensurePluginId2, addSession: addSession2, removeSession: removeSession2, setActiveSession: setActiveSession2, getActiveSession: getActiveSession2, getActiveSessionForAgent: getActiveSessionForAgent2, clearAll: clearAll2, saveCliConfig: saveCliConfig2, loadCliConfig: loadCliConfig2 };
498
+ return { getConfig: getConfig2, ensurePluginId: ensurePluginId2, addSession: addSession2, removeSession: removeSession2, setActiveSession: setActiveSession2, getActiveSession: getActiveSession2, getActiveSessionForAgent: getActiveSessionForAgent2, setDisable1mContext: setDisable1mContext2, clearAll: clearAll2, saveCliConfig: saveCliConfig2, loadCliConfig: loadCliConfig2 };
492
499
  }
493
500
  var CODESPACE_ENV_KEYS = [
494
501
  "PREVIEW_TUNNEL_TOKEN",
@@ -512,7 +519,7 @@ function loadCodespaceEnv() {
512
519
  }
513
520
  }
514
521
  var _default = makeConfig();
515
- var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, getActiveSession, getActiveSessionForAgent, clearAll, saveCliConfig, loadCliConfig } = _default;
522
+ var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, getActiveSession, getActiveSessionForAgent, setDisable1mContext, clearAll, saveCliConfig, loadCliConfig } = _default;
516
523
 
517
524
  // src/commands/pair-auto.ts
518
525
  var fs41 = __toESM(require("fs"));
@@ -5390,7 +5397,7 @@ function readAnonId() {
5390
5397
  }
5391
5398
  function superProperties() {
5392
5399
  return {
5393
- cliVersion: true ? "2.42.0" : "0.0.0-dev",
5400
+ cliVersion: true ? "2.43.1" : "0.0.0-dev",
5394
5401
  nodeVersion: process.version,
5395
5402
  platform: process.platform,
5396
5403
  arch: process.arch,
@@ -5571,7 +5578,7 @@ var os4 = __toESM(require("os"));
5571
5578
  // package.json
5572
5579
  var package_default = {
5573
5580
  name: "codeam-cli",
5574
- version: "2.42.0",
5581
+ version: "2.43.1",
5575
5582
  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.",
5576
5583
  type: "commonjs",
5577
5584
  main: "dist/index.js",
@@ -17804,7 +17811,7 @@ async function autoUpgradeBeforeCriticalCommand() {
17804
17811
  if (process.env.NODE_ENV === "test") return;
17805
17812
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17806
17813
  if (process.env.CI) return;
17807
- const current = true ? "2.42.0" : null;
17814
+ const current = true ? "2.43.1" : null;
17808
17815
  if (!current) return;
17809
17816
  const cache = readCache();
17810
17817
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17821,7 +17828,7 @@ function checkForUpdates() {
17821
17828
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17822
17829
  if (process.env.CI) return;
17823
17830
  if (!process.stdout.isTTY) return;
17824
- const current = true ? "2.42.0" : null;
17831
+ const current = true ? "2.43.1" : null;
17825
17832
  if (!current) return;
17826
17833
  const cache = readCache();
17827
17834
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -18259,7 +18266,7 @@ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process14.s
18259
18266
  detached: false
18260
18267
  });
18261
18268
  function currentCliVersion() {
18262
- return true ? "2.42.0" : null;
18269
+ return true ? "2.43.1" : null;
18263
18270
  }
18264
18271
  function runCmd(cmd, args2, timeoutMs) {
18265
18272
  return new Promise((resolve7) => {
@@ -22737,7 +22744,10 @@ var AcpClient = class {
22737
22744
  );
22738
22745
  const child = (0, import_node_child_process16.spawn)(adapter.command, adapter.args, {
22739
22746
  cwd,
22740
- env: { ...process.env, PATH: augmentedPath },
22747
+ // extraEnv (e.g. CLAUDE_CODE_DISABLE_1M_CONTEXT=1 on an on-demand
22748
+ // re-spawn) layers over process.env; PATH stays last so the augmented
22749
+ // PATH always wins.
22750
+ env: { ...process.env, ...this.opts.extraEnv ?? {}, PATH: augmentedPath },
22741
22751
  stdio: ["pipe", "pipe", "pipe"]
22742
22752
  });
22743
22753
  this.child = child;
@@ -23431,6 +23441,67 @@ function buildAcpPromptBlocks(payload) {
23431
23441
  return blocks;
23432
23442
  }
23433
23443
 
23444
+ // src/agents/acp/oneMContextRecovery.ts
23445
+ var ONE_M_CONTEXT_CREDITS_RE = /usage credits required for 1m context/i;
23446
+ function looksLike1mContextCreditsError(text) {
23447
+ return ONE_M_CONTEXT_CREDITS_RE.test(text);
23448
+ }
23449
+ var ONE_M_DISABLE_OPTION = "Disable 1M context and continue";
23450
+ function shouldOfferOneMRecovery(opts) {
23451
+ return looksLike1mContextCreditsError(opts.detail) || looksLike1mContextCreditsError(opts.recentStderr) || looksLike1mContextCreditsError(opts.finalText);
23452
+ }
23453
+ function oneMRecoverySelectPrompt() {
23454
+ return {
23455
+ question: "\u26A0\uFE0F This agent's Anthropic account needs usage credits for 1M context. You can disable 1M context (uses standard 200K context) and continue.",
23456
+ options: [ONE_M_DISABLE_OPTION]
23457
+ };
23458
+ }
23459
+ function createOneMRecovery(deps) {
23460
+ let pending = null;
23461
+ const sp = oneMRecoverySelectPrompt();
23462
+ return {
23463
+ offer: async (commandId, blocks) => {
23464
+ pending = { blocks };
23465
+ await deps.publishText(sp.question);
23466
+ await deps.publishSelectPrompt(sp.question, sp.options);
23467
+ await deps.publishAwaitingAnswer(sp.question, sp.options);
23468
+ deps.appendAgentReply(sp.question);
23469
+ deps.flushHistory();
23470
+ deps.log?.(`1M-context credits gate \u2014 recovery offered id=${commandId.slice(0, 8)}`);
23471
+ await deps.sendResult(commandId, "failed", {
23472
+ error: "1M context requires usage credits \u2014 recovery offered"
23473
+ });
23474
+ },
23475
+ tryRecover: async (commandId) => {
23476
+ if (!pending) return false;
23477
+ const blocks = pending.blocks;
23478
+ pending = null;
23479
+ deps.log?.("1M-context recovery \u2192 disable + reconnect + rerun");
23480
+ await deps.reconnectWith1mDisabled();
23481
+ await deps.beginTurn();
23482
+ try {
23483
+ const reply = await deps.promptAgent(blocks);
23484
+ const finalText = deps.getCurrentText();
23485
+ await deps.closeTurn();
23486
+ deps.appendAgentReply(finalText);
23487
+ deps.flushHistory();
23488
+ await deps.sendResult(commandId, "completed", { stopReason: reply.stopReason });
23489
+ } catch (err) {
23490
+ await deps.recoverFromFailedTurn();
23491
+ const d3 = deps.describeError(err);
23492
+ const b = deps.failureBubbleFor(d3);
23493
+ if (b) {
23494
+ await deps.publishText(b);
23495
+ deps.appendAgentReply(b);
23496
+ deps.flushHistory();
23497
+ }
23498
+ await deps.sendResult(commandId, "failed", { error: d3 });
23499
+ }
23500
+ return true;
23501
+ }
23502
+ };
23503
+ }
23504
+
23434
23505
  // src/agents/acp/reconcileDelta.ts
23435
23506
  function reconcileCumulative(existing, incoming) {
23436
23507
  if (incoming.length === 0) return existing;
@@ -24793,9 +24864,11 @@ async function runAcpSession(opts) {
24793
24864
  }
24794
24865
  });
24795
24866
  let updateCount = 0;
24796
- const client2 = new AcpClient({
24867
+ const disable1mContext = loadCliConfig().sessions.find((s) => s.pluginId === opts.pluginId)?.disable1mContext === true;
24868
+ const clientOptions = {
24797
24869
  adapter: opts.adapter,
24798
24870
  cwd: opts.cwd,
24871
+ extraEnv: disable1mContext ? { CLAUDE_CODE_DISABLE_1M_CONTEXT: "1" } : {},
24799
24872
  onSessionUpdate: (notification) => {
24800
24873
  updateCount += 1;
24801
24874
  const variant = notification.update?.sessionUpdate ?? "unknown";
@@ -24860,6 +24933,43 @@ async function runAcpSession(opts) {
24860
24933
  process.exit(1);
24861
24934
  })();
24862
24935
  }
24936
+ };
24937
+ let client2 = new AcpClient(clientOptions);
24938
+ const reconnectWith1mDisabled = async () => {
24939
+ setDisable1mContext(opts.pluginId, true);
24940
+ try {
24941
+ await client2.stop();
24942
+ } catch {
24943
+ }
24944
+ client2 = new AcpClient({ ...clientOptions, extraEnv: { CLAUDE_CODE_DISABLE_1M_CONTEXT: "1" } });
24945
+ await client2.start();
24946
+ };
24947
+ const oneMRecovery = createOneMRecovery({
24948
+ publishText: (text) => publisher.publishOutput({ type: "text", content: text, done: true }),
24949
+ publishSelectPrompt: (question, options) => publisher.publishOutput({
24950
+ type: "select_prompt",
24951
+ content: question,
24952
+ options,
24953
+ optionDescriptions: options.map(() => ""),
24954
+ currentIndex: 0,
24955
+ done: true
24956
+ }),
24957
+ // The button driver — mobile renders the tappable option from this
24958
+ // awaiting-answer event; the user's tap returns as a `select_option`
24959
+ // command, caught at the top of the select_option case by tryRecover.
24960
+ publishAwaitingAnswer: (prompt, options) => publisher.publishAwaitingAnswer({ questionId: (0, import_node_crypto7.randomUUID)(), prompt, options }),
24961
+ sendResult: (commandId, status2, result) => relay.sendResult(commandId, status2, result),
24962
+ appendAgentReply: (text) => history.appendAgentReply(text),
24963
+ flushHistory: () => void history.flush(),
24964
+ beginTurn: () => streaming.beginTurn(),
24965
+ getCurrentText: () => streaming.getCurrentText(),
24966
+ closeTurn: () => streaming.closeTurnWithInteractiveDetection(),
24967
+ recoverFromFailedTurn: () => recoverFromFailedTurn(client2, streaming),
24968
+ reconnectWith1mDisabled,
24969
+ promptAgent: (blocks) => client2.prompt(blocks),
24970
+ failureBubbleFor: (detail) => failureBubble({ detail, recentStderr: recentStderr.join("\n"), hadText: false, agent: opts.agent }),
24971
+ describeError,
24972
+ log: (msg) => log.info("acpRunner", msg)
24863
24973
  });
24864
24974
  showInfo(`Starting ${opts.agent} via ACP adapter (${opts.adapter.requiresAgentBinary})\u2026`);
24865
24975
  const {
@@ -24954,7 +25064,8 @@ async function runAcpSession(opts) {
24954
25064
  turnFiles,
24955
25065
  getBeads,
24956
25066
  publisher,
24957
- recentStderr
25067
+ recentStderr,
25068
+ oneMRecovery
24958
25069
  );
24959
25070
  },
24960
25071
  { id: opts.agent, name: opts.agent, displayName: opts.agent }
@@ -24978,7 +25089,7 @@ async function runAcpSession(opts) {
24978
25089
  await new Promise(() => {
24979
25090
  });
24980
25091
  }
24981
- async function handleCommand(cmd, client2, relay, acpSessionId, models, streaming, opts, history, jsonlHistory, agentCaps, turnFiles, getBeads, publisher, recentStderr) {
25092
+ async function handleCommand(cmd, client2, relay, acpSessionId, models, streaming, opts, history, jsonlHistory, agentCaps, turnFiles, getBeads, publisher, recentStderr, oneMRecovery) {
24982
25093
  switch (cmd.type) {
24983
25094
  case "beads_action": {
24984
25095
  const beads = getBeads();
@@ -25029,6 +25140,8 @@ async function handleCommand(cmd, client2, relay, acpSessionId, models, streamin
25029
25140
  void reportCredentialInvalid(opts);
25030
25141
  log.info("acpRunner", `start_task \u2190 auth-failure-in-reply id=${cmd.id.slice(0, 8)}`);
25031
25142
  await relay.sendResult(cmd.id, "failed", { error: "agent reply reported auth failure" });
25143
+ } else if (shouldOfferOneMRecovery({ detail: "", recentStderr: recentStderr.join("\n"), finalText })) {
25144
+ await oneMRecovery.offer(cmd.id, blocks);
25032
25145
  } else {
25033
25146
  await streaming.closeTurnWithInteractiveDetection();
25034
25147
  const replyLine = formatAgentReplyLine(finalText);
@@ -25048,6 +25161,10 @@ async function handleCommand(cmd, client2, relay, acpSessionId, models, streamin
25048
25161
  await recoverFromFailedTurn(client2, streaming);
25049
25162
  const detail = describeError(err);
25050
25163
  log.warn("acpRunner", `prompt failed: ${detail}`);
25164
+ if (shouldOfferOneMRecovery({ detail, recentStderr: recentStderr.join("\n"), finalText: "" })) {
25165
+ await oneMRecovery.offer(cmd.id, blocks);
25166
+ return;
25167
+ }
25051
25168
  const bubble = failureBubble({
25052
25169
  detail,
25053
25170
  recentStderr: recentStderr.join("\n"),
@@ -25142,6 +25259,7 @@ async function handleCommand(cmd, client2, relay, acpSessionId, models, streamin
25142
25259
  return;
25143
25260
  }
25144
25261
  case "select_option": {
25262
+ if (await oneMRecovery.tryRecover(cmd.id)) return;
25145
25263
  const payload = cmd.payload;
25146
25264
  const index = typeof payload?.index === "number" ? payload.index : 0;
25147
25265
  const offset = typeof payload?.from === "number" ? payload.from : 0;
@@ -29211,7 +29329,7 @@ function checkChokidar() {
29211
29329
  }
29212
29330
  async function doctor(args2 = []) {
29213
29331
  const json = args2.includes("--json");
29214
- const cliVersion = true ? "2.42.0" : "0.0.0-dev";
29332
+ const cliVersion = true ? "2.43.1" : "0.0.0-dev";
29215
29333
  const apiBase2 = resolveApiBaseUrl();
29216
29334
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
29217
29335
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -29410,7 +29528,7 @@ async function completion(args2) {
29410
29528
  // src/commands/version.ts
29411
29529
  var import_picocolors14 = __toESM(require("picocolors"));
29412
29530
  function version2() {
29413
- const v = true ? "2.42.0" : "unknown";
29531
+ const v = true ? "2.43.1" : "unknown";
29414
29532
  console.log(`${import_picocolors14.default.bold("codeam-cli")} ${import_picocolors14.default.cyan(v)}`);
29415
29533
  }
29416
29534
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.42.0",
3
+ "version": "2.43.1",
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",