codeam-cli 2.61.15 → 2.61.17

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 +112 -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.61.16] — 2026-07-17
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** ACP dispatch is registry-static — never silently downgrade an ACP agent to PTY
12
+
13
+ ## [2.61.15] — 2026-07-17
14
+
15
+ ### Added
16
+
17
+ - **shared:** Integration category field + getIntegrationsByCategory
18
+
7
19
  ## [2.61.14] — 2026-07-17
8
20
 
9
21
  ### Fixed
package/dist/index.js CHANGED
@@ -841,8 +841,8 @@ var HEADROOM_MODELS = [
841
841
  }
842
842
  ];
843
843
  function headroomSnapshotDownloadLine(model, opts = {}) {
844
- const sep7 = opts.spaceAfterComma ? ", " : ",";
845
- const patterns = model.allowPatterns.map((p2) => `"${p2}"`).join(sep7);
844
+ const sep6 = opts.spaceAfterComma ? ", " : ",";
845
+ const patterns = model.allowPatterns.map((p2) => `"${p2}"`).join(sep6);
846
846
  return `snapshot_download("${model.repo}", allow_patterns=[${patterns}])`;
847
847
  }
848
848
  function headroomModelPredownloadScript(opts = {}) {
@@ -6024,7 +6024,7 @@ function readAnonId() {
6024
6024
  }
6025
6025
  function superProperties() {
6026
6026
  return {
6027
- cliVersion: true ? "2.61.15" : "0.0.0-dev",
6027
+ cliVersion: true ? "2.61.17" : "0.0.0-dev",
6028
6028
  nodeVersion: process.version,
6029
6029
  platform: process.platform,
6030
6030
  arch: process.arch,
@@ -6205,7 +6205,7 @@ var os4 = __toESM(require("os"));
6205
6205
  // package.json
6206
6206
  var package_default = {
6207
6207
  name: "codeam-cli",
6208
- version: "2.61.15",
6208
+ version: "2.61.17",
6209
6209
  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.",
6210
6210
  type: "commonjs",
6211
6211
  main: "dist/index.js",
@@ -7348,7 +7348,7 @@ var CommandRelayService = class _CommandRelayService {
7348
7348
  // fresh + clear the "CLI update available" banner after a self-update
7349
7349
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
7350
7350
  // pair/reconnect). Older backends ignore the extra field.
7351
- ..."2.61.15" ? { ideVersion: "2.61.15" } : {}
7351
+ ..."2.61.17" ? { ideVersion: "2.61.17" } : {}
7352
7352
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
7353
7353
  }
7354
7354
  /**
@@ -12211,12 +12211,12 @@ function isAvailable() {
12211
12211
  }
12212
12212
  function augmentPath() {
12213
12213
  const dirs = probeInstallDirs();
12214
- const sep7 = path16.delimiter;
12214
+ const sep6 = path16.delimiter;
12215
12215
  const current = process.env.PATH ?? "";
12216
- const existing = new Set(current.split(sep7).filter(Boolean));
12216
+ const existing = new Set(current.split(sep6).filter(Boolean));
12217
12217
  const additions = dirs.filter((d3) => !existing.has(d3));
12218
12218
  if (additions.length === 0) return;
12219
- process.env.PATH = additions.join(sep7) + sep7 + current;
12219
+ process.env.PATH = additions.join(sep6) + sep6 + current;
12220
12220
  }
12221
12221
  function runInstaller() {
12222
12222
  const isWindows = process.platform === "win32";
@@ -17949,7 +17949,7 @@ async function autoUpgradeBeforeCriticalCommand() {
17949
17949
  if (process.env.NODE_ENV === "test") return;
17950
17950
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17951
17951
  if (process.env.CI) return;
17952
- const current = true ? "2.61.15" : null;
17952
+ const current = true ? "2.61.17" : null;
17953
17953
  if (!current) return;
17954
17954
  const cache = readCache();
17955
17955
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17966,7 +17966,7 @@ function checkForUpdates() {
17966
17966
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17967
17967
  if (process.env.CI) return;
17968
17968
  if (!process.stdout.isTTY) return;
17969
- const current = true ? "2.61.15" : null;
17969
+ const current = true ? "2.61.17" : null;
17970
17970
  if (!current) return;
17971
17971
  const cache = readCache();
17972
17972
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17986,7 +17986,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
17986
17986
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
17987
17987
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
17988
17988
  function currentCliVersion() {
17989
- return true ? "2.61.15" : null;
17989
+ return true ? "2.61.17" : null;
17990
17990
  }
17991
17991
  function runCmd(cmd, args2, timeoutMs) {
17992
17992
  return new Promise((resolve8) => {
@@ -22655,13 +22655,15 @@ function buildNpmInstallInvocation(opts) {
22655
22655
  const entryScript = opts?.entryScript ?? process.argv[1] ?? "";
22656
22656
  const execPath = opts?.execPath ?? process.execPath;
22657
22657
  const exists2 = opts?.existsSync ?? fs55.existsSync;
22658
- const normalized = entryScript.split(path59.sep).join("/");
22658
+ const platform3 = opts?.platform ?? process.platform;
22659
+ const p2 = platform3 === "win32" ? path59.win32 : path59.posix;
22660
+ const normalized = entryScript.split(/[\\/]/).join("/");
22659
22661
  const marker = "/lib/node_modules/codeam-cli/";
22660
22662
  const markerIdx = normalized.indexOf(marker);
22661
22663
  const prefix = markerIdx > 0 ? entryScript.slice(0, markerIdx) : null;
22662
- const siblingNpm = path59.join(
22663
- path59.dirname(execPath),
22664
- process.platform === "win32" ? "npm.cmd" : "npm"
22664
+ const siblingNpm = p2.join(
22665
+ p2.dirname(execPath),
22666
+ platform3 === "win32" ? "npm.cmd" : "npm"
22665
22667
  );
22666
22668
  const npmCommand = exists2(siblingNpm) ? siblingNpm : "npm";
22667
22669
  const npmArgs = prefix ? ["install", "-g", "--prefix", prefix, "codeam-cli@latest"] : ["install", "-g", "codeam-cli@latest"];
@@ -24490,12 +24492,43 @@ var REGISTRY = {
24490
24492
  }
24491
24493
  })
24492
24494
  };
24495
+ var resolvedAdapterCache = /* @__PURE__ */ new Map();
24493
24496
  function getAcpAdapter(agent) {
24497
+ const cached2 = resolvedAdapterCache.get(agent);
24498
+ if (cached2) return cached2;
24494
24499
  const factory = REGISTRY[agent];
24495
- return factory ? factory() : null;
24500
+ if (!factory) return null;
24501
+ const spec = factory();
24502
+ if (spec) resolvedAdapterCache.set(agent, spec);
24503
+ return spec;
24496
24504
  }
24497
24505
  function requiresAcp(agent) {
24498
- return getAcpAdapter(agent) !== null;
24506
+ return Object.prototype.hasOwnProperty.call(REGISTRY, agent);
24507
+ }
24508
+ var DEFAULT_ADAPTER_RETRY_TIMEOUT_MS = 8e3;
24509
+ var DEFAULT_ADAPTER_RETRY_POLL_MS = 750;
24510
+ async function resolveAcpAdapterWithRetry(agent, opts = {}) {
24511
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_ADAPTER_RETRY_TIMEOUT_MS;
24512
+ const pollMs = opts.pollMs ?? DEFAULT_ADAPTER_RETRY_POLL_MS;
24513
+ const now = opts.now ?? Date.now;
24514
+ const sleep5 = opts.sleep ?? ((ms) => new Promise((resolve9) => setTimeout(resolve9, ms)));
24515
+ const resolve8 = opts.resolve ?? getAcpAdapter;
24516
+ const attempt = () => {
24517
+ try {
24518
+ return resolve8(agent);
24519
+ } catch {
24520
+ return null;
24521
+ }
24522
+ };
24523
+ let spec = attempt();
24524
+ if (spec) return spec;
24525
+ const deadline = now() + timeoutMs;
24526
+ while (now() < deadline) {
24527
+ await sleep5(pollMs);
24528
+ spec = attempt();
24529
+ if (spec) return spec;
24530
+ }
24531
+ return null;
24499
24532
  }
24500
24533
 
24501
24534
  // src/agents/acp/runner.ts
@@ -31648,7 +31681,7 @@ async function startTaskH(ctx) {
31648
31681
  await relay.sendResult(cmd.id, "completed", { stopReason: reply.stopReason });
31649
31682
  }
31650
31683
  } catch (err) {
31651
- const hadText = streaming.getCurrentText().trim().length > 0;
31684
+ const hadText = streaming.hasVisibleProgress();
31652
31685
  const detail = describeError(err);
31653
31686
  log.warn("acpRunner", `prompt failed: ${detail}`);
31654
31687
  await cancelStuckTurn(client3);
@@ -32227,6 +32260,31 @@ var StreamingState = class {
32227
32260
  getCurrentText() {
32228
32261
  return this.text;
32229
32262
  }
32263
+ /**
32264
+ * True when the in-progress turn has ALREADY streamed VISIBLE content —
32265
+ * assistant text OR any thinking / tool_use / tool_result activity (the
32266
+ * SessionDetail rich feed). Deliberately BROADER than {@link getCurrentText}:
32267
+ * a long agentic turn can stream lots of tool/thinking progress and yet NOT
32268
+ * have emitted a final assistant `text` reply at the instant `client.prompt`
32269
+ * throws — the idle watchdog tripping just as the agent finishes its last
32270
+ * tool, or a trailing adapter error AFTER the work completed. Keying the
32271
+ * failure-bubble decision off `text` alone then mis-reads that visible work
32272
+ * as "nothing streamed" → fires the generic TURN_FAILURE_MESSAGE, and
32273
+ * {@link closeWithBubble} REPLACES the whole turn with it (overwriting the
32274
+ * durable snapshot) — an error wiping a fully-streamed transcript AND a false
32275
+ * "couldn't finish" (2026-07-17 incident). The catch path keys "don't clobber
32276
+ * — a partial reply already serves as the terminal frame" off THIS instead,
32277
+ * routing to the non-destructive {@link closeAll}. streamingChunks still holds
32278
+ * the turn's content at catch time (none of the close/flush methods have run
32279
+ * yet on the throw path), so this reflects the real streamed progress.
32280
+ */
32281
+ hasVisibleProgress() {
32282
+ if (this.text.trim().length > 0) return true;
32283
+ for (const { content } of this.streamingChunks.values()) {
32284
+ if (content.trim().length > 0) return true;
32285
+ }
32286
+ return false;
32287
+ }
32230
32288
  async beginTurn(opts) {
32231
32289
  this.text = "";
32232
32290
  this.streamingChunks.clear();
@@ -34759,7 +34817,7 @@ async function start(requestedAgent) {
34759
34817
  const depsReady = process.env.CODESPACES === "true" ? provisionProjectDependencies(cwd).catch(() => void 0) : Promise.resolve();
34760
34818
  if (process.env.CODESPACES === "true") {
34761
34819
  const GATE_TIMEOUT_MS = 24e4;
34762
- const acpAdapterForGate = getAcpAdapter(session.agent);
34820
+ const acpAdapterForGate = requiresAcp(session.agent) ? await resolveAcpAdapterWithRetry(session.agent) : null;
34763
34821
  const agentBinaryReady = acpAdapterForGate ? Promise.all([
34764
34822
  acpAdapterForGate.waitForBinary({ timeoutMs: GATE_TIMEOUT_MS }).catch(() => false),
34765
34823
  waitForAdapterModuleGraph(acpAdapterForGate.command, acpAdapterForGate.args, {
@@ -34780,7 +34838,7 @@ async function start(requestedAgent) {
34780
34838
  );
34781
34839
  }
34782
34840
  if (isLocalSession() && requiresAcp(session.agent)) {
34783
- const adapter = getAcpAdapter(session.agent);
34841
+ const adapter = await resolveAcpAdapterWithRetry(session.agent);
34784
34842
  const batonCapable = runtimeSupportsBaton(createRuntimeStrategy(session.agent));
34785
34843
  if (batonCapable && adapter && session.pluginAuthToken) {
34786
34844
  await runBatonSession({
@@ -34798,8 +34856,35 @@ async function start(requestedAgent) {
34798
34856
  }
34799
34857
  }
34800
34858
  if (requiresAcp(session.agent)) {
34801
- const adapter = getAcpAdapter(session.agent);
34802
- if (!adapter || !session.pluginAuthToken) {
34859
+ let adapter = getAcpAdapter(session.agent);
34860
+ if (!adapter) {
34861
+ adapter = await resolveAcpAdapterWithRetry(session.agent);
34862
+ }
34863
+ if (!adapter) {
34864
+ log.error(
34865
+ "acp",
34866
+ `[acp] REQUIRED adapter unresolvable \u2014 refusing PTY downgrade (agent=${session.agent})`
34867
+ );
34868
+ const failureMsg = `${AGENT_REGISTRY[session.agent].displayName}'s ACP adapter is unavailable \u2014 the session cannot start; redeploy or retry.`;
34869
+ if (session.pluginAuthToken) {
34870
+ await surfaceStartupFailure({
34871
+ agent: session.agent,
34872
+ pluginId,
34873
+ detail: failureMsg,
34874
+ recentStderr: "",
34875
+ publisher: new AcpPublisher({
34876
+ sessionId: session.id,
34877
+ pluginId,
34878
+ pluginAuthToken: session.pluginAuthToken,
34879
+ refreshAuthToken: () => fetchCurrentPluginAuthToken(session.id, pluginId, session.pollSecret)
34880
+ })
34881
+ });
34882
+ return;
34883
+ }
34884
+ showError(failureMsg);
34885
+ process.exit(1);
34886
+ }
34887
+ if (!session.pluginAuthToken) {
34803
34888
  showError(
34804
34889
  `${AGENT_REGISTRY[session.agent].displayName} requires a paired session with an auth token. Re-pair with \`codeam pair\` to continue.`
34805
34890
  );
@@ -34825,6 +34910,9 @@ async function start(requestedAgent) {
34825
34910
  });
34826
34911
  return;
34827
34912
  }
34913
+ if (requiresAcp(session.agent)) {
34914
+ log.error("acp", `[anomaly] acp-required agent on PTY runtime (agent=${session.agent})`);
34915
+ }
34828
34916
  const runtime = createRuntimeStrategy(session.agent);
34829
34917
  const historySvc = new HistoryService(runtime, pluginId, cwd, {
34830
34918
  pluginAuthToken: session.pluginAuthToken
@@ -37545,7 +37633,7 @@ function checkChokidar() {
37545
37633
  }
37546
37634
  async function doctor(args2 = []) {
37547
37635
  const json = args2.includes("--json");
37548
- const cliVersion = true ? "2.61.15" : "0.0.0-dev";
37636
+ const cliVersion = true ? "2.61.17" : "0.0.0-dev";
37549
37637
  const apiBase2 = resolveApiBaseUrl();
37550
37638
  const diagnosticId = (0, import_node_crypto12.randomUUID)();
37551
37639
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -38056,7 +38144,7 @@ async function mcpRun(args2) {
38056
38144
  // src/commands/version.ts
38057
38145
  var import_picocolors15 = __toESM(require("picocolors"));
38058
38146
  function version2() {
38059
- const v = true ? "2.61.15" : "unknown";
38147
+ const v = true ? "2.61.17" : "unknown";
38060
38148
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
38061
38149
  }
38062
38150
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.61.15",
3
+ "version": "2.61.17",
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",