codeam-cli 2.60.19 → 2.60.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 +20 -0
  2. package/dist/index.js +111 -27
  3. package/package.json +1 -1
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.19] — 2026-07-09
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Baton — pre-mint Cursor session id via `create-chat`
12
+
13
+ ### Tests
14
+
15
+ - **cli:** De-flake adapter module-graph gate — crash synchronously in settling fixture
16
+
17
+ ## [2.60.18] — 2026-07-09
18
+
19
+ ### Added
20
+
21
+ - **cli:** Auto-install Kimi on local pair when the binary is missing
22
+
23
+ ### Fixed
24
+
25
+ - **cli:** Baton — discover Kimi's self-minted session id after spawn
26
+
7
27
  ## [2.60.17] — 2026-07-09
8
28
 
9
29
  ### Added
package/dist/index.js CHANGED
@@ -5680,7 +5680,7 @@ function readAnonId() {
5680
5680
  }
5681
5681
  function superProperties() {
5682
5682
  return {
5683
- cliVersion: true ? "2.60.19" : "0.0.0-dev",
5683
+ cliVersion: true ? "2.60.20" : "0.0.0-dev",
5684
5684
  nodeVersion: process.version,
5685
5685
  platform: process.platform,
5686
5686
  arch: process.arch,
@@ -5861,7 +5861,7 @@ var os4 = __toESM(require("os"));
5861
5861
  // package.json
5862
5862
  var package_default = {
5863
5863
  name: "codeam-cli",
5864
- version: "2.60.19",
5864
+ version: "2.60.20",
5865
5865
  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.",
5866
5866
  type: "commonjs",
5867
5867
  main: "dist/index.js",
@@ -6932,7 +6932,7 @@ var CommandRelayService = class {
6932
6932
  // fresh + clear the "CLI update available" banner after a self-update
6933
6933
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
6934
6934
  // pair/reconnect). Older backends ignore the extra field.
6935
- ..."2.60.19" ? { ideVersion: "2.60.19" } : {}
6935
+ ..."2.60.20" ? { ideVersion: "2.60.20" } : {}
6936
6936
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
6937
6937
  }
6938
6938
  /**
@@ -9089,7 +9089,7 @@ function findGitRoot2(startDir) {
9089
9089
  }
9090
9090
 
9091
9091
  // src/commands/link.ts
9092
- var import_node_crypto7 = require("crypto");
9092
+ var import_node_crypto8 = require("crypto");
9093
9093
  var fs30 = __toESM(require("fs"));
9094
9094
  var path34 = __toESM(require("path"));
9095
9095
  var import_chokidar = __toESM(require("chokidar"));
@@ -13444,7 +13444,70 @@ var CoderabbitRuntimeStrategy = class {
13444
13444
  var fs23 = __toESM(require("fs"));
13445
13445
  var os21 = __toESM(require("os"));
13446
13446
  var path27 = __toESM(require("path"));
13447
+ var import_node_crypto5 = require("crypto");
13447
13448
  var HISTORY_ROOT = path27.join(os21.homedir(), ".cursor", "projects");
13449
+ var CURSOR_HOME = path27.join(os21.homedir(), ".cursor");
13450
+ var STORE_FILES = ["store.db", "store.db-wal", "store.db-shm"];
13451
+ function acpSessionDir(sessionId) {
13452
+ return path27.join(CURSOR_HOME, "acp-sessions", sessionId);
13453
+ }
13454
+ function nativeStoreDir(cwd, sessionId) {
13455
+ const chatsRoot = path27.join(CURSOR_HOME, "chats");
13456
+ let buckets = [];
13457
+ try {
13458
+ buckets = fs23.readdirSync(chatsRoot);
13459
+ } catch {
13460
+ }
13461
+ for (const b of buckets) {
13462
+ const candidate = path27.join(chatsRoot, b, sessionId);
13463
+ if (fs23.existsSync(path27.join(candidate, "store.db"))) return candidate;
13464
+ }
13465
+ const computed = path27.join(chatsRoot, (0, import_node_crypto5.createHash)("md5").update(cwd).digest("hex"), sessionId);
13466
+ return fs23.existsSync(computed) ? computed : null;
13467
+ }
13468
+ function copyStoreFiles(srcDir, dstDir) {
13469
+ fs23.mkdirSync(dstDir, { recursive: true });
13470
+ for (const f of STORE_FILES) {
13471
+ const dst = path27.join(dstDir, f);
13472
+ if (fs23.existsSync(dst)) fs23.rmSync(dst, { force: true });
13473
+ }
13474
+ for (const f of STORE_FILES) {
13475
+ const src = path27.join(srcDir, f);
13476
+ if (fs23.existsSync(src)) fs23.copyFileSync(src, path27.join(dstDir, f));
13477
+ }
13478
+ }
13479
+ function bridgeNativeToAcp(cwd, sessionId) {
13480
+ try {
13481
+ const src = nativeStoreDir(cwd, sessionId);
13482
+ if (!src) {
13483
+ log.warn("cursor", `baton bridge: no native store for ${sessionId.slice(0, 8)} \u2014 skip`);
13484
+ return;
13485
+ }
13486
+ const dst = acpSessionDir(sessionId);
13487
+ copyStoreFiles(src, dst);
13488
+ fs23.writeFileSync(
13489
+ path27.join(dst, "meta.json"),
13490
+ JSON.stringify({ schemaVersion: 1, cwd })
13491
+ );
13492
+ log.info("cursor", `baton bridge native\u2192acp ok (${sessionId.slice(0, 8)})`);
13493
+ } catch (err) {
13494
+ log.warn("cursor", `baton bridge native\u2192acp failed: ${err instanceof Error ? err.message : String(err)}`);
13495
+ }
13496
+ }
13497
+ function bridgeAcpToNative(cwd, sessionId) {
13498
+ try {
13499
+ const src = acpSessionDir(sessionId);
13500
+ if (!fs23.existsSync(path27.join(src, "store.db"))) {
13501
+ log.warn("cursor", `baton bridge: no acp store for ${sessionId.slice(0, 8)} \u2014 skip`);
13502
+ return;
13503
+ }
13504
+ const dst = nativeStoreDir(cwd, sessionId) ?? path27.join(CURSOR_HOME, "chats", (0, import_node_crypto5.createHash)("md5").update(cwd).digest("hex"), sessionId);
13505
+ copyStoreFiles(src, dst);
13506
+ log.info("cursor", `baton bridge acp\u2192native ok (${sessionId.slice(0, 8)})`);
13507
+ } catch (err) {
13508
+ log.warn("cursor", `baton bridge acp\u2192native failed: ${err instanceof Error ? err.message : String(err)}`);
13509
+ }
13510
+ }
13448
13511
  function encodeCursorCwd(cwd) {
13449
13512
  return cwd.replace(/^[/\\]+/, "").replace(/[/\\:]/g, "-");
13450
13513
  }
@@ -13685,6 +13748,25 @@ var CursorRuntimeStrategy = class {
13685
13748
  parseHistoryFile(filePath) {
13686
13749
  return parseHistoryFile3(filePath);
13687
13750
  }
13751
+ /**
13752
+ * Baton Take Control (native TUI → mobile ACP). Cursor keeps native-TUI
13753
+ * conversations in `~/.cursor/chats/<md5(cwd)>/<id>` but ACP `session/load`
13754
+ * only reads `~/.cursor/acp-sessions/<id>` — so without this, loading the
13755
+ * native session id fails "not found". Bridge the native store into the ACP
13756
+ * store just before the load. Best-effort; verified live (identical
13757
+ * `blobs`+`meta` SQLite schema, raw file copy replays the conversation).
13758
+ */
13759
+ async syncTranscriptForAcpResume(cwd, sessionId) {
13760
+ bridgeNativeToAcp(cwd, sessionId);
13761
+ }
13762
+ /**
13763
+ * Baton hand-back (mobile ACP → native TUI). Copy the ACP conversation store
13764
+ * back into the native `~/.cursor/chats` store so `cursor-agent --resume <id>`
13765
+ * in the terminal picks up whatever mobile did. Best-effort.
13766
+ */
13767
+ async syncTranscriptForNativeResume(cwd, sessionId) {
13768
+ bridgeAcpToNative(cwd, sessionId);
13769
+ }
13688
13770
  getCurrentUsage(historyDir) {
13689
13771
  return getCurrentUsage3(historyDir);
13690
13772
  }
@@ -13957,7 +14039,7 @@ var AiderRuntimeStrategy = class {
13957
14039
  };
13958
14040
 
13959
14041
  // src/agents/gemini/runtime.ts
13960
- var import_node_crypto5 = require("crypto");
14042
+ var import_node_crypto6 = require("crypto");
13961
14043
 
13962
14044
  // src/agents/gemini/link.ts
13963
14045
  var import_node_child_process12 = require("child_process");
@@ -14222,7 +14304,7 @@ var GeminiRuntimeStrategy = class {
14222
14304
  "Gemini CLI is not on PATH. Install it with:\n npm install -g @google/gemini-cli\n Then run `codeam pair` again."
14223
14305
  );
14224
14306
  }
14225
- const sessionId = (0, import_node_crypto5.randomUUID)();
14307
+ const sessionId = (0, import_node_crypto6.randomUUID)();
14226
14308
  const launch = this.os.buildLaunch(binary, ["--session-id", sessionId]);
14227
14309
  log.info(
14228
14310
  "gemini",
@@ -14329,12 +14411,12 @@ var import_node_path4 = require("path");
14329
14411
  var fs29 = __toESM(require("fs"));
14330
14412
  var os26 = __toESM(require("os"));
14331
14413
  var path33 = __toESM(require("path"));
14332
- var import_node_crypto6 = require("crypto");
14414
+ var import_node_crypto7 = require("crypto");
14333
14415
  function kimiHome() {
14334
14416
  return process.env.KIMI_CODE_HOME || path33.join(os26.homedir(), ".kimi-code");
14335
14417
  }
14336
14418
  function workDirKey(cwd) {
14337
- const hash = (0, import_node_crypto6.createHash)("sha256").update(cwd).digest("hex").slice(0, 12);
14419
+ const hash = (0, import_node_crypto7.createHash)("sha256").update(cwd).digest("hex").slice(0, 12);
14338
14420
  return `wd_${path33.basename(cwd)}_${hash}`;
14339
14421
  }
14340
14422
  function resolveHistoryDir6(cwd) {
@@ -14727,9 +14809,9 @@ async function link(args2 = []) {
14727
14809
  await linkDryRunPreflight(ctx);
14728
14810
  return;
14729
14811
  }
14730
- const pluginId = (0, import_node_crypto7.randomUUID)();
14731
- const pollSecret = (0, import_node_crypto7.randomBytes)(32).toString("base64url");
14732
- const pluginSecretHash = (0, import_node_crypto7.createHash)("sha256").update(pollSecret).digest("hex");
14812
+ const pluginId = (0, import_node_crypto8.randomUUID)();
14813
+ const pollSecret = (0, import_node_crypto8.randomBytes)(32).toString("base64url");
14814
+ const pluginSecretHash = (0, import_node_crypto8.createHash)("sha256").update(pollSecret).digest("hex");
14733
14815
  const spin = dist_exports.spinner();
14734
14816
  spin.start("Requesting pairing code...");
14735
14817
  const pairing = await requestCode(pluginId, pluginSecretHash);
@@ -16560,7 +16642,7 @@ async function autoUpgradeBeforeCriticalCommand() {
16560
16642
  if (process.env.NODE_ENV === "test") return;
16561
16643
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
16562
16644
  if (process.env.CI) return;
16563
- const current = true ? "2.60.19" : null;
16645
+ const current = true ? "2.60.20" : null;
16564
16646
  if (!current) return;
16565
16647
  const cache = readCache();
16566
16648
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -16577,7 +16659,7 @@ function checkForUpdates() {
16577
16659
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
16578
16660
  if (process.env.CI) return;
16579
16661
  if (!process.stdout.isTTY) return;
16580
- const current = true ? "2.60.19" : null;
16662
+ const current = true ? "2.60.20" : null;
16581
16663
  if (!current) return;
16582
16664
  const cache = readCache();
16583
16665
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -16597,7 +16679,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
16597
16679
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
16598
16680
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
16599
16681
  function currentCliVersion() {
16600
- return true ? "2.60.19" : null;
16682
+ return true ? "2.60.20" : null;
16601
16683
  }
16602
16684
  function runCmd(cmd, args2, timeoutMs) {
16603
16685
  return new Promise((resolve7) => {
@@ -22431,7 +22513,7 @@ function requiresAcp(agent) {
22431
22513
  }
22432
22514
 
22433
22515
  // src/agents/acp/runner.ts
22434
- var import_node_crypto9 = require("crypto");
22516
+ var import_node_crypto10 = require("crypto");
22435
22517
 
22436
22518
  // src/services/history.service.ts
22437
22519
  var fs55 = __toESM(require("fs"));
@@ -26632,7 +26714,7 @@ async function runOnboardingTurn(opts) {
26632
26714
  }
26633
26715
 
26634
26716
  // src/agents/acp/mappers.ts
26635
- var import_node_crypto8 = require("crypto");
26717
+ var import_node_crypto9 = require("crypto");
26636
26718
  function mapSessionUpdate(notification) {
26637
26719
  const update = notification.update;
26638
26720
  switch (update.sessionUpdate) {
@@ -26695,7 +26777,7 @@ function mapPermissionRequest(request) {
26695
26777
  }
26696
26778
  return {
26697
26779
  event: {
26698
- questionId: (0, import_node_crypto8.randomUUID)(),
26780
+ questionId: (0, import_node_crypto9.randomUUID)(),
26699
26781
  prompt,
26700
26782
  options: labels.length > 0 ? labels : void 0
26701
26783
  },
@@ -26705,7 +26787,7 @@ function mapPermissionRequest(request) {
26705
26787
  }
26706
26788
  function messageChunkId(messageId) {
26707
26789
  if (typeof messageId === "string" && messageId.length > 0) return messageId;
26708
- return (0, import_node_crypto8.randomUUID)();
26790
+ return (0, import_node_crypto9.randomUUID)();
26709
26791
  }
26710
26792
  function extractText4(content) {
26711
26793
  if (!content || typeof content !== "object") return null;
@@ -28518,7 +28600,7 @@ var AcpHistory = class {
28518
28600
  this.summary = trimmed.length > 120 ? trimmed.slice(0, 117) + "\u2026" : trimmed;
28519
28601
  }
28520
28602
  this.messages.push({
28521
- id: (0, import_node_crypto9.randomUUID)(),
28603
+ id: (0, import_node_crypto10.randomUUID)(),
28522
28604
  role: "user",
28523
28605
  text,
28524
28606
  timestamp: Date.now()
@@ -28527,7 +28609,7 @@ var AcpHistory = class {
28527
28609
  appendAgentReply(text) {
28528
28610
  if (text.length === 0) return;
28529
28611
  this.messages.push({
28530
- id: (0, import_node_crypto9.randomUUID)(),
28612
+ id: (0, import_node_crypto10.randomUUID)(),
28531
28613
  role: "agent",
28532
28614
  text,
28533
28615
  timestamp: Date.now()
@@ -28733,7 +28815,7 @@ async function runAcpSession(opts) {
28733
28815
  currentIndex: 0,
28734
28816
  done: true
28735
28817
  }),
28736
- publishAwaitingAnswer: (prompt, options) => publisher.publishAwaitingAnswer({ questionId: (0, import_node_crypto9.randomUUID)(), prompt, options }),
28818
+ publishAwaitingAnswer: (prompt, options) => publisher.publishAwaitingAnswer({ questionId: (0, import_node_crypto10.randomUUID)(), prompt, options }),
28737
28819
  publishRawChunk: (chunk) => publisher.publishOutput(chunk),
28738
28820
  sendResult: (commandId, status2, result) => relay.sendResult(commandId, status2, result),
28739
28821
  appendAgentReply: (text) => history.appendAgentReply(text),
@@ -30041,6 +30123,7 @@ var NativeTuiDriver = class {
30041
30123
  keepAliveCtx;
30042
30124
  async start(resumeId) {
30043
30125
  if (resumeId !== void 0) {
30126
+ await this.deps.runtime.syncTranscriptForNativeResume?.(this.deps.opts.cwd, resumeId);
30044
30127
  await this.agent.restart(resumeId, false);
30045
30128
  return resumeId;
30046
30129
  }
@@ -30099,7 +30182,7 @@ var NativeTuiDriver = class {
30099
30182
  };
30100
30183
 
30101
30184
  // src/baton/acp-driver.ts
30102
- var import_node_crypto10 = require("crypto");
30185
+ var import_node_crypto11 = require("crypto");
30103
30186
  var AcpDriver = class {
30104
30187
  constructor(deps) {
30105
30188
  this.deps = deps;
@@ -30121,6 +30204,7 @@ var AcpDriver = class {
30121
30204
  try {
30122
30205
  started = await this.deps.client.start();
30123
30206
  if (resumeId !== void 0) {
30207
+ await this.deps.runtime.syncTranscriptForAcpResume?.(this.deps.opts.cwd, resumeId);
30124
30208
  this.deps.streaming.beginLoadReplay();
30125
30209
  try {
30126
30210
  await this.deps.client.loadSession(resumeId);
@@ -30192,7 +30276,7 @@ var AcpDriver = class {
30192
30276
  currentIndex: 0,
30193
30277
  done: true
30194
30278
  }),
30195
- publishAwaitingAnswer: (prompt, options) => publisher.publishAwaitingAnswer({ questionId: (0, import_node_crypto10.randomUUID)(), prompt, options }),
30279
+ publishAwaitingAnswer: (prompt, options) => publisher.publishAwaitingAnswer({ questionId: (0, import_node_crypto11.randomUUID)(), prompt, options }),
30196
30280
  publishRawChunk: (chunk) => publisher.publishOutput(chunk),
30197
30281
  sendResult: (commandId, status2, result) => relay.sendResult(commandId, status2, result),
30198
30282
  appendAgentReply: (text) => history.appendAgentReply(text),
@@ -33287,7 +33371,7 @@ async function invite() {
33287
33371
  // src/commands/doctor.ts
33288
33372
  var import_node_dns = require("dns");
33289
33373
  var import_node_util5 = require("util");
33290
- var import_node_crypto11 = require("crypto");
33374
+ var import_node_crypto12 = require("crypto");
33291
33375
  var fs62 = __toESM(require("fs"));
33292
33376
  var path69 = __toESM(require("path"));
33293
33377
  var import_picocolors14 = __toESM(require("picocolors"));
@@ -33457,9 +33541,9 @@ function checkChokidar() {
33457
33541
  }
33458
33542
  async function doctor(args2 = []) {
33459
33543
  const json = args2.includes("--json");
33460
- const cliVersion = true ? "2.60.19" : "0.0.0-dev";
33544
+ const cliVersion = true ? "2.60.20" : "0.0.0-dev";
33461
33545
  const apiBase2 = resolveApiBaseUrl();
33462
- const diagnosticId = (0, import_node_crypto11.randomUUID)();
33546
+ const diagnosticId = (0, import_node_crypto12.randomUUID)();
33463
33547
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
33464
33548
  const [dns, health] = await Promise.all([
33465
33549
  checkDns(apiBase2),
@@ -33656,7 +33740,7 @@ async function completion(args2) {
33656
33740
  // src/commands/version.ts
33657
33741
  var import_picocolors15 = __toESM(require("picocolors"));
33658
33742
  function version2() {
33659
- const v = true ? "2.60.19" : "unknown";
33743
+ const v = true ? "2.60.20" : "unknown";
33660
33744
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
33661
33745
  }
33662
33746
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.60.19",
3
+ "version": "2.60.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",