codeam-cli 2.76.18 → 2.76.20

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 +12 -0
  2. package/dist/index.js +101 -24
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ 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.19] — 2026-10-09
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Send sessionId on turn-events so PluginAuthGuard stops 401ing them (#929)
12
+
13
+ ## [2.76.18] — 2026-10-09
14
+
15
+ ### Fixed
16
+
17
+ - **box:** Pull the node base image from mirror.gcr.io (Docker Hub 429) (#927)
18
+
7
19
  ## [2.76.17] — 2026-10-09
8
20
 
9
21
  ### Added
package/dist/index.js CHANGED
@@ -10617,7 +10617,7 @@ function readAnonId() {
10617
10617
  }
10618
10618
  function superProperties() {
10619
10619
  return {
10620
- cliVersion: true ? "2.76.18" : "0.0.0-dev",
10620
+ cliVersion: true ? "2.76.20" : "0.0.0-dev",
10621
10621
  nodeVersion: process.version,
10622
10622
  platform: process.platform,
10623
10623
  arch: process.arch,
@@ -10866,7 +10866,7 @@ var http = __toESM(require("http"));
10866
10866
  // package.json
10867
10867
  var package_default = {
10868
10868
  name: "codeam-cli",
10869
- version: "2.76.18",
10869
+ version: "2.76.20",
10870
10870
  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.",
10871
10871
  type: "commonjs",
10872
10872
  main: "dist/index.js",
@@ -11246,6 +11246,7 @@ async function postTurnEvent(input) {
11246
11246
  await _transport.postJsonAuthed(
11247
11247
  `${API_BASE}/api/commands/turn-events`,
11248
11248
  {
11249
+ sessionId: input.sessionId,
11249
11250
  pluginId: input.pluginId,
11250
11251
  commandId: input.commandId,
11251
11252
  phase: input.phase,
@@ -12228,7 +12229,7 @@ var CommandRelayService = class _CommandRelayService {
12228
12229
  // fresh + clear the "CLI update available" banner after a self-update
12229
12230
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
12230
12231
  // pair/reconnect). Older backends ignore the extra field.
12231
- ..."2.76.18" ? { ideVersion: "2.76.18" } : {}
12232
+ ..."2.76.20" ? { ideVersion: "2.76.20" } : {}
12232
12233
  };
12233
12234
  try {
12234
12235
  const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body, this.pollSecretHeader());
@@ -28965,8 +28966,9 @@ var startTask = async (ctx, cmd, parsed) => {
28965
28966
  reportTurn(ctx, cmd.id, "started");
28966
28967
  };
28967
28968
  function reportTurn(ctx, commandId, phase, errorCode) {
28968
- if (!ctx.pluginId || !ctx.pluginAuthToken) return;
28969
+ if (!ctx.sessionId || !ctx.pluginId || !ctx.pluginAuthToken) return;
28969
28970
  void postTurnEvent({
28971
+ sessionId: ctx.sessionId,
28970
28972
  pluginId: ctx.pluginId,
28971
28973
  pluginAuthToken: ctx.pluginAuthToken,
28972
28974
  commandId,
@@ -38472,7 +38474,7 @@ var coderabbitProvisioner = {
38472
38474
  return {};
38473
38475
  }
38474
38476
  };
38475
- var opencodeProvisioner = {
38477
+ var providerKeyProvisioner = {
38476
38478
  write(auth) {
38477
38479
  const key = auth.value.trim();
38478
38480
  const envName = key.startsWith("sk-ant-") ? "ANTHROPIC_API_KEY" : key.startsWith("AIza") ? "GEMINI_API_KEY" : "OPENAI_API_KEY";
@@ -38486,7 +38488,11 @@ var PROVISIONERS = {
38486
38488
  gemini: geminiProvisioner,
38487
38489
  cursor: cursorProvisioner,
38488
38490
  coderabbit: coderabbitProvisioner,
38489
- opencode: opencodeProvisioner
38491
+ opencode: providerKeyProvisioner,
38492
+ // ⚠️ Was missing: every self-hosted / fleet-Box aider deploy failed with
38493
+ // "Self-hosted provisioning is not implemented for agent "aider"" (23 in
38494
+ // prod Cloud Run, 2026-09-10..10-08).
38495
+ aider: providerKeyProvisioner
38490
38496
  };
38491
38497
  var UnsupportedAgentError = class extends Error {
38492
38498
  agentId;
@@ -43058,8 +43064,9 @@ function recordCoderabbitTurn(ctx, prompt, replySummary) {
43058
43064
  }
43059
43065
  function reportTurn2(ctx, phase, errorCode) {
43060
43066
  const { opts, cmd } = ctx;
43061
- if (!opts.pluginId || !opts.pluginAuthToken) return;
43067
+ if (!opts.sessionId || !opts.pluginId || !opts.pluginAuthToken) return;
43062
43068
  void postTurnEvent({
43069
+ sessionId: opts.sessionId,
43063
43070
  pluginId: opts.pluginId,
43064
43071
  pluginAuthToken: opts.pluginAuthToken,
43065
43072
  commandId: cmd.id,
@@ -44482,12 +44489,14 @@ var AcpHistory = class {
44482
44489
  */
44483
44490
  appendAgentReply(text, agentId = this.opts.agent) {
44484
44491
  if (text.length === 0) return;
44492
+ const blocker = failureBlocker(text);
44485
44493
  this.messages.push({
44486
44494
  id: (0, import_node_crypto15.randomUUID)(),
44487
44495
  role: "agent",
44488
44496
  text,
44489
44497
  timestamp: Date.now(),
44490
- agentId
44498
+ agentId,
44499
+ ...blocker ? { blocker } : {}
44491
44500
  });
44492
44501
  }
44493
44502
  /**
@@ -51215,7 +51224,7 @@ async function autoUpgradeBeforeCriticalCommand() {
51215
51224
  if (process.env.NODE_ENV === "test") return;
51216
51225
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
51217
51226
  if (process.env.CI) return;
51218
- const current2 = true ? "2.76.18" : null;
51227
+ const current2 = true ? "2.76.20" : null;
51219
51228
  if (!current2) return;
51220
51229
  const cache = readCache();
51221
51230
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -51232,7 +51241,7 @@ function checkForUpdates() {
51232
51241
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
51233
51242
  if (process.env.CI) return;
51234
51243
  if (!process.stdout.isTTY) return;
51235
- const current2 = true ? "2.76.18" : null;
51244
+ const current2 = true ? "2.76.20" : null;
51236
51245
  if (!current2) return;
51237
51246
  const cache = readCache();
51238
51247
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -51514,7 +51523,7 @@ var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
51514
51523
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
51515
51524
  var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
51516
51525
  function currentCliVersion() {
51517
- return true ? "2.76.18" : null;
51526
+ return true ? "2.76.20" : null;
51518
51527
  }
51519
51528
  async function installedVersion(deps) {
51520
51529
  const ls = await deps.run(
@@ -51725,7 +51734,7 @@ function signalHostReady(send = process.send?.bind(process)) {
51725
51734
  }
51726
51735
  function defaultDeps() {
51727
51736
  return {
51728
- ownVersion: true ? "2.76.18" : null,
51737
+ ownVersion: true ? "2.76.20" : null,
51729
51738
  root: cliVersionsRoot(),
51730
51739
  args: process.argv.slice(3),
51731
51740
  execPath: process.execPath,
@@ -52304,6 +52313,15 @@ var HostAgentSupervisor = class {
52304
52313
  * one session's crash-loop must not spend another's retry budget).
52305
52314
  */
52306
52315
  resumeStates = /* @__PURE__ */ new Map();
52316
+ /**
52317
+ * Env-delivered agent credentials per deploy (the `api_key` path:
52318
+ * ANTHROPIC_API_KEY / GEMINI_API_KEY / CURSOR_API_KEY / OPENAI_API_KEY).
52319
+ * Such a key lives ONLY in the child's spawn env — nothing on disk carries
52320
+ * it — so every re-spawn of the session (crash respawn, resume, a re-link
52321
+ * restart) must re-inject it. Memory only: credential plaintext is never
52322
+ * persisted by the host-agent (codeagent-5m12).
52323
+ */
52324
+ credentialEnvByDeploy = /* @__PURE__ */ new Map();
52307
52325
  /** Set once the bounded retries exhaust → heartbeat-ridden slow re-probe. */
52308
52326
  /** True after stop() — no resume retries may be scheduled past teardown. */
52309
52327
  stopped = false;
@@ -52824,6 +52842,7 @@ var HostAgentSupervisor = class {
52824
52842
  async fleetMigrateBoxImage(payload) {
52825
52843
  const { containerName } = payload;
52826
52844
  const state = await this.docker.run([
52845
+ "container",
52827
52846
  "inspect",
52828
52847
  "--format",
52829
52848
  "{{.State.Running}}",
@@ -52936,7 +52955,13 @@ var HostAgentSupervisor = class {
52936
52955
  async fleetBoxImageStale(containerName) {
52937
52956
  if (process.env.CODEAM_FLEET_BOX_IMAGE) return false;
52938
52957
  const image = resolveFleetBoxImage();
52939
- const cur = await this.docker.run(["inspect", "--format", "{{.Image}}", containerName]);
52958
+ const cur = await this.docker.run([
52959
+ "container",
52960
+ "inspect",
52961
+ "--format",
52962
+ "{{.Image}}",
52963
+ containerName
52964
+ ]);
52940
52965
  if (cur.code !== 0) {
52941
52966
  return isMissingContainerError(cur.stderr);
52942
52967
  }
@@ -53213,6 +53238,8 @@ var HostAgentSupervisor = class {
53213
53238
  } else {
53214
53239
  const auth = await this.resolveAgentAuth(this.identity, payload.sealedAgentAuth);
53215
53240
  const credEnv = provisionAgentCredentials(payload.agentId, auth, void 0);
53241
+ if (Object.keys(credEnv).length > 0) this.credentialEnvByDeploy.set(payload.deployId, credEnv);
53242
+ else this.credentialEnvByDeploy.delete(payload.deployId);
53216
53243
  childEnv = {
53217
53244
  ...credEnv,
53218
53245
  CODEAM_AUTO_TOKEN: payload.autoPairToken
@@ -53610,7 +53637,11 @@ var HostAgentSupervisor = class {
53610
53637
  `resume: session ${session.id.slice(0, 8)} deploy=${deployId.slice(0, 8)} cwd=${cwd}`
53611
53638
  );
53612
53639
  const proc = this.resumeSpawner(
53613
- { ...readHouseProxyChildEnv(deployId), CODEAM_RESUME_SESSION_ID: session.id },
53640
+ {
53641
+ ...readHouseProxyChildEnv(deployId),
53642
+ ...this.credentialEnvByDeploy.get(deployId) ?? {},
53643
+ CODEAM_RESUME_SESSION_ID: session.id
53644
+ },
53614
53645
  cwd
53615
53646
  );
53616
53647
  const child = {
@@ -53818,6 +53849,7 @@ var HostAgentSupervisor = class {
53818
53849
  */
53819
53850
  cleanupWorkspace(deployId) {
53820
53851
  const short = deployId.slice(0, 8);
53852
+ this.credentialEnvByDeploy.delete(deployId);
53821
53853
  const child = this.children.get(deployId);
53822
53854
  if (child) {
53823
53855
  try {
@@ -53844,20 +53876,43 @@ var HostAgentSupervisor = class {
53844
53876
  }
53845
53877
  /**
53846
53878
  * Handle `self_hosted_refresh_credentials` (the user re-linked the agent).
53847
- * Unseal the fresh credential and re-provision the agent's on-disk auth IN
53848
- * PLACE (`provisionAgentCredentials` rewrites `~/.claude/.credentials.json`
53849
- * etc.). The running pair-auto child re-reads its auth file on the next API
53850
- * call, so a 401'd session recovers WITHOUT a restart — the self-hosted
53851
- * parallel to the codespace `refreshAgentCredentialsOnly` sweep. Best-effort:
53852
- * a failure is logged, never throws (the relay dispatch must not crash).
53879
+ * Unseal the fresh credential and re-provision the agent's auth IN PLACE.
53880
+ *
53881
+ * Two delivery shapes, two outcomes (codeagent-5m12):
53882
+ * - **Login-state FILE** (`oauth_token`; `provisionAgentCredentials`
53883
+ * returns `{}`): the file is rewritten and running children are left
53884
+ * alone. Claude Code and Codex re-read their auth file on a 401 (Claude's
53885
+ * `oauth_401_recovered_from_disk`, Codex's `UnauthorizedRecovery` Reload
53886
+ * step), so a 401'd session recovers without losing its turn.
53887
+ * - **Env var** (`api_key`; it returns e.g. `{ ANTHROPIC_API_KEY }`): the
53888
+ * key exists only in each child's spawn env, which a rewrite cannot reach
53889
+ * — the old key keeps 401ing until the process is replaced. Every running
53890
+ * child of THIS agent is restarted through the resume path with the new
53891
+ * env (same conversation, `CODEAM_RESUME_SESSION_ID`).
53892
+ *
53893
+ * Best-effort: a failure is logged, never throws (the relay dispatch must
53894
+ * not crash).
53853
53895
  */
53854
53896
  async refreshCredentials(payload) {
53855
53897
  try {
53856
53898
  const auth = await this.resolveAgentAuth(this.identity, payload.sealedAgentAuth);
53857
- provisionAgentCredentials(payload.agentId, auth, void 0);
53899
+ const credEnv = provisionAgentCredentials(payload.agentId, auth, void 0);
53900
+ const affected = [...this.children.values()].filter((c2) => c2.agent === payload.agentId);
53901
+ if (Object.keys(credEnv).length === 0) {
53902
+ for (const c2 of affected) this.credentialEnvByDeploy.delete(c2.deployId);
53903
+ log.info(
53904
+ "host-agent",
53905
+ `refreshed credentials in place for agent=${payload.agentId} (${this.children.size} active child(ren))`
53906
+ );
53907
+ return;
53908
+ }
53909
+ for (const child of affected) {
53910
+ this.credentialEnvByDeploy.set(child.deployId, credEnv);
53911
+ this.restartWithFreshCredentials(child);
53912
+ }
53858
53913
  log.info(
53859
53914
  "host-agent",
53860
- `refreshed credentials in place for agent=${payload.agentId} (${this.children.size} active child(ren))`
53915
+ `refreshed env credential for agent=${payload.agentId}; restarted ${affected.length} child(ren)`
53861
53916
  );
53862
53917
  } catch (err) {
53863
53918
  log.warn(
@@ -53866,6 +53921,28 @@ var HostAgentSupervisor = class {
53866
53921
  );
53867
53922
  }
53868
53923
  }
53924
+ /**
53925
+ * Replace one session child so it picks up a re-linked env credential.
53926
+ * Kill THEN untrack (an intentional stop, so its exit handler neither
53927
+ * reports `ended` nor crash-respawns), then resume the same conversation;
53928
+ * `resumeOne` waits out the dying daemon if it still holds the session.
53929
+ */
53930
+ restartWithFreshCredentials(child) {
53931
+ const session = pickSavedSessionForWorkspace(this.listSavedSessions(), child.cwd, child.deployId);
53932
+ if (!session) {
53933
+ log.warn(
53934
+ "host-agent",
53935
+ `credential refresh: no saved pairing for deploy=${child.deployId.slice(0, 8)} \u2014 it keeps the old key until its next restart`
53936
+ );
53937
+ return;
53938
+ }
53939
+ try {
53940
+ child.proc.kill("SIGTERM");
53941
+ } catch {
53942
+ }
53943
+ this.untrackChild(child.deployId);
53944
+ this.resumeOne({ deployId: child.deployId, cwd: child.cwd, session, agent: child.agent });
53945
+ }
53869
53946
  };
53870
53947
  async function resolveHostIdentity(enrollToken) {
53871
53948
  const existing = ensureControlPollSecret(loadHostIdentity());
@@ -54168,7 +54245,7 @@ function checkChokidar() {
54168
54245
  }
54169
54246
  async function doctor(args2 = []) {
54170
54247
  const json = args2.includes("--json");
54171
- const cliVersion = true ? "2.76.18" : "0.0.0-dev";
54248
+ const cliVersion = true ? "2.76.20" : "0.0.0-dev";
54172
54249
  const apiBase2 = resolveApiBaseUrl();
54173
54250
  const diagnosticId = (0, import_node_crypto17.randomUUID)();
54174
54251
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -54704,7 +54781,7 @@ async function mcpWarm(argv = [], opts = {}) {
54704
54781
  // src/commands/version.ts
54705
54782
  var import_picocolors15 = __toESM(require("picocolors"));
54706
54783
  function version2() {
54707
- const v = true ? "2.76.18" : "unknown";
54784
+ const v = true ? "2.76.20" : "unknown";
54708
54785
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
54709
54786
  }
54710
54787
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.76.18",
3
+ "version": "2.76.20",
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",