codeam-cli 2.60.19 → 2.60.21
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 +27 -0
- package/dist/index.js +216 -41
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,33 @@ 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.20] — 2026-07-09
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Baton — pre-mint Cursor session id via `create-chat`
|
|
12
|
+
- **cli:** Baton Take Control for Cursor — bridge native↔ACP session stores
|
|
13
|
+
|
|
14
|
+
## [2.60.19] — 2026-07-09
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- **cli:** Baton — pre-mint Cursor session id via `create-chat`
|
|
19
|
+
|
|
20
|
+
### Tests
|
|
21
|
+
|
|
22
|
+
- **cli:** De-flake adapter module-graph gate — crash synchronously in settling fixture
|
|
23
|
+
|
|
24
|
+
## [2.60.18] — 2026-07-09
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- **cli:** Auto-install Kimi on local pair when the binary is missing
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- **cli:** Baton — discover Kimi's self-minted session id after spawn
|
|
33
|
+
|
|
7
34
|
## [2.60.17] — 2026-07-09
|
|
8
35
|
|
|
9
36
|
### 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.
|
|
5683
|
+
cliVersion: true ? "2.60.21" : "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.
|
|
5864
|
+
version: "2.60.21",
|
|
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.
|
|
6935
|
+
..."2.60.21" ? { ideVersion: "2.60.21" } : {}
|
|
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
|
|
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"));
|
|
@@ -12931,6 +12931,87 @@ function resolveHistoryFile2(cwd, sessionId, homeOverride) {
|
|
|
12931
12931
|
}
|
|
12932
12932
|
return null;
|
|
12933
12933
|
}
|
|
12934
|
+
async function discoverSessionId(cwd, opts, homeOverride) {
|
|
12935
|
+
const home = homeOverride ?? import_node_os.default.homedir();
|
|
12936
|
+
const sessionsRoot = import_node_path2.default.join(home, ".codex", "sessions");
|
|
12937
|
+
const floor = opts.sinceMs - 2e3;
|
|
12938
|
+
const deadline = Date.now() + (opts.timeoutMs ?? 24e4);
|
|
12939
|
+
let resolvedCurrent;
|
|
12940
|
+
try {
|
|
12941
|
+
resolvedCurrent = import_node_fs3.default.realpathSync(cwd);
|
|
12942
|
+
} catch {
|
|
12943
|
+
resolvedCurrent = import_node_path2.default.resolve(cwd);
|
|
12944
|
+
}
|
|
12945
|
+
for (; ; ) {
|
|
12946
|
+
const id = newestRolloutIdSince(sessionsRoot, resolvedCurrent, floor);
|
|
12947
|
+
if (id) return id;
|
|
12948
|
+
if (Date.now() >= deadline) return null;
|
|
12949
|
+
await sleep2(500);
|
|
12950
|
+
}
|
|
12951
|
+
}
|
|
12952
|
+
function newestRolloutIdSince(sessionsRoot, resolvedCwd, floorMs) {
|
|
12953
|
+
if (!import_node_fs3.default.existsSync(sessionsRoot)) return null;
|
|
12954
|
+
const now = /* @__PURE__ */ new Date();
|
|
12955
|
+
let bestId = null;
|
|
12956
|
+
let bestMtime = -1;
|
|
12957
|
+
for (let dayOffset = 0; dayOffset < 2; dayOffset += 1) {
|
|
12958
|
+
const d3 = new Date(now.getTime() - dayOffset * 24 * 60 * 60 * 1e3);
|
|
12959
|
+
const yyyy = String(d3.getUTCFullYear());
|
|
12960
|
+
const mm = String(d3.getUTCMonth() + 1).padStart(2, "0");
|
|
12961
|
+
const dd = String(d3.getUTCDate()).padStart(2, "0");
|
|
12962
|
+
const dayDir = import_node_path2.default.join(sessionsRoot, yyyy, mm, dd);
|
|
12963
|
+
let dayFiles;
|
|
12964
|
+
try {
|
|
12965
|
+
dayFiles = import_node_fs3.default.readdirSync(dayDir, { withFileTypes: true });
|
|
12966
|
+
} catch {
|
|
12967
|
+
continue;
|
|
12968
|
+
}
|
|
12969
|
+
for (const entry of dayFiles) {
|
|
12970
|
+
if (!entry.isFile()) continue;
|
|
12971
|
+
if (!entry.name.startsWith("rollout-") || !entry.name.endsWith(".jsonl")) continue;
|
|
12972
|
+
const filePath = import_node_path2.default.join(dayDir, entry.name);
|
|
12973
|
+
let mtime;
|
|
12974
|
+
try {
|
|
12975
|
+
mtime = import_node_fs3.default.statSync(filePath).mtimeMs;
|
|
12976
|
+
} catch {
|
|
12977
|
+
continue;
|
|
12978
|
+
}
|
|
12979
|
+
if (mtime < floorMs || mtime <= bestMtime) continue;
|
|
12980
|
+
let metaCwd;
|
|
12981
|
+
let metaId;
|
|
12982
|
+
try {
|
|
12983
|
+
const raw = import_node_fs3.default.readFileSync(filePath, "utf8");
|
|
12984
|
+
for (const line of raw.split("\n")) {
|
|
12985
|
+
if (!line.trim()) continue;
|
|
12986
|
+
const rec = parseLine(line);
|
|
12987
|
+
if (!rec) continue;
|
|
12988
|
+
if (rec.type === "session_meta") {
|
|
12989
|
+
const meta = rec.payload;
|
|
12990
|
+
metaCwd = typeof meta?.cwd === "string" ? meta.cwd : void 0;
|
|
12991
|
+
metaId = typeof meta?.id === "string" ? meta.id : void 0;
|
|
12992
|
+
}
|
|
12993
|
+
break;
|
|
12994
|
+
}
|
|
12995
|
+
} catch {
|
|
12996
|
+
continue;
|
|
12997
|
+
}
|
|
12998
|
+
if (!metaId || !metaCwd) continue;
|
|
12999
|
+
let resolvedMeta;
|
|
13000
|
+
try {
|
|
13001
|
+
resolvedMeta = import_node_fs3.default.realpathSync(metaCwd);
|
|
13002
|
+
} catch {
|
|
13003
|
+
resolvedMeta = import_node_path2.default.resolve(metaCwd);
|
|
13004
|
+
}
|
|
13005
|
+
if (resolvedMeta !== resolvedCwd) continue;
|
|
13006
|
+
bestMtime = mtime;
|
|
13007
|
+
bestId = metaId;
|
|
13008
|
+
}
|
|
13009
|
+
}
|
|
13010
|
+
return bestId;
|
|
13011
|
+
}
|
|
13012
|
+
function sleep2(ms) {
|
|
13013
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
13014
|
+
}
|
|
12934
13015
|
function getCurrentUsage2(historyDir) {
|
|
12935
13016
|
if (!import_node_fs3.default.existsSync(historyDir)) return null;
|
|
12936
13017
|
const files = import_node_fs3.default.readdirSync(historyDir).filter((f) => f.startsWith("rollout-") && f.endsWith(".jsonl")).map((f) => ({ name: f, full: import_node_path2.default.join(historyDir, f) })).map((e) => ({ ...e, mtime: import_node_fs3.default.statSync(e.full).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
@@ -13098,6 +13179,16 @@ var CodexRuntimeStrategy = class {
|
|
|
13098
13179
|
resolveHistoryFile(cwd, sessionId) {
|
|
13099
13180
|
return resolveHistoryFile2(cwd, sessionId);
|
|
13100
13181
|
}
|
|
13182
|
+
/**
|
|
13183
|
+
* Codex mints its own session id (into a `rollout-*.jsonl` at TUI boot) and
|
|
13184
|
+
* neither accepts a pre-set one nor prints it — so, like Kimi, the baton's
|
|
13185
|
+
* NativeTuiDriver discovers it post-spawn. Codex shares that rollout store with
|
|
13186
|
+
* its ACP adapter, so discovery alone is enough (no cross-store bridge). The
|
|
13187
|
+
* TUI boots slowly, hence the generous poll budget inside.
|
|
13188
|
+
*/
|
|
13189
|
+
discoverSessionId(cwd, opts) {
|
|
13190
|
+
return discoverSessionId(cwd, opts);
|
|
13191
|
+
}
|
|
13101
13192
|
getCurrentUsage(historyDir) {
|
|
13102
13193
|
return getCurrentUsage2(historyDir);
|
|
13103
13194
|
}
|
|
@@ -13444,7 +13535,70 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
13444
13535
|
var fs23 = __toESM(require("fs"));
|
|
13445
13536
|
var os21 = __toESM(require("os"));
|
|
13446
13537
|
var path27 = __toESM(require("path"));
|
|
13538
|
+
var import_node_crypto5 = require("crypto");
|
|
13447
13539
|
var HISTORY_ROOT = path27.join(os21.homedir(), ".cursor", "projects");
|
|
13540
|
+
var CURSOR_HOME = path27.join(os21.homedir(), ".cursor");
|
|
13541
|
+
var STORE_FILES = ["store.db", "store.db-wal", "store.db-shm"];
|
|
13542
|
+
function acpSessionDir(sessionId) {
|
|
13543
|
+
return path27.join(CURSOR_HOME, "acp-sessions", sessionId);
|
|
13544
|
+
}
|
|
13545
|
+
function nativeStoreDir(cwd, sessionId) {
|
|
13546
|
+
const chatsRoot = path27.join(CURSOR_HOME, "chats");
|
|
13547
|
+
let buckets = [];
|
|
13548
|
+
try {
|
|
13549
|
+
buckets = fs23.readdirSync(chatsRoot);
|
|
13550
|
+
} catch {
|
|
13551
|
+
}
|
|
13552
|
+
for (const b of buckets) {
|
|
13553
|
+
const candidate = path27.join(chatsRoot, b, sessionId);
|
|
13554
|
+
if (fs23.existsSync(path27.join(candidate, "store.db"))) return candidate;
|
|
13555
|
+
}
|
|
13556
|
+
const computed = path27.join(chatsRoot, (0, import_node_crypto5.createHash)("md5").update(cwd).digest("hex"), sessionId);
|
|
13557
|
+
return fs23.existsSync(computed) ? computed : null;
|
|
13558
|
+
}
|
|
13559
|
+
function copyStoreFiles(srcDir, dstDir) {
|
|
13560
|
+
fs23.mkdirSync(dstDir, { recursive: true });
|
|
13561
|
+
for (const f of STORE_FILES) {
|
|
13562
|
+
const dst = path27.join(dstDir, f);
|
|
13563
|
+
if (fs23.existsSync(dst)) fs23.rmSync(dst, { force: true });
|
|
13564
|
+
}
|
|
13565
|
+
for (const f of STORE_FILES) {
|
|
13566
|
+
const src = path27.join(srcDir, f);
|
|
13567
|
+
if (fs23.existsSync(src)) fs23.copyFileSync(src, path27.join(dstDir, f));
|
|
13568
|
+
}
|
|
13569
|
+
}
|
|
13570
|
+
function bridgeNativeToAcp(cwd, sessionId) {
|
|
13571
|
+
try {
|
|
13572
|
+
const src = nativeStoreDir(cwd, sessionId);
|
|
13573
|
+
if (!src) {
|
|
13574
|
+
log.warn("cursor", `baton bridge: no native store for ${sessionId.slice(0, 8)} \u2014 skip`);
|
|
13575
|
+
return;
|
|
13576
|
+
}
|
|
13577
|
+
const dst = acpSessionDir(sessionId);
|
|
13578
|
+
copyStoreFiles(src, dst);
|
|
13579
|
+
fs23.writeFileSync(
|
|
13580
|
+
path27.join(dst, "meta.json"),
|
|
13581
|
+
JSON.stringify({ schemaVersion: 1, cwd })
|
|
13582
|
+
);
|
|
13583
|
+
log.info("cursor", `baton bridge native\u2192acp ok (${sessionId.slice(0, 8)})`);
|
|
13584
|
+
} catch (err) {
|
|
13585
|
+
log.warn("cursor", `baton bridge native\u2192acp failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
13586
|
+
}
|
|
13587
|
+
}
|
|
13588
|
+
function bridgeAcpToNative(cwd, sessionId) {
|
|
13589
|
+
try {
|
|
13590
|
+
const src = acpSessionDir(sessionId);
|
|
13591
|
+
if (!fs23.existsSync(path27.join(src, "store.db"))) {
|
|
13592
|
+
log.warn("cursor", `baton bridge: no acp store for ${sessionId.slice(0, 8)} \u2014 skip`);
|
|
13593
|
+
return;
|
|
13594
|
+
}
|
|
13595
|
+
const dst = nativeStoreDir(cwd, sessionId) ?? path27.join(CURSOR_HOME, "chats", (0, import_node_crypto5.createHash)("md5").update(cwd).digest("hex"), sessionId);
|
|
13596
|
+
copyStoreFiles(src, dst);
|
|
13597
|
+
log.info("cursor", `baton bridge acp\u2192native ok (${sessionId.slice(0, 8)})`);
|
|
13598
|
+
} catch (err) {
|
|
13599
|
+
log.warn("cursor", `baton bridge acp\u2192native failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
13600
|
+
}
|
|
13601
|
+
}
|
|
13448
13602
|
function encodeCursorCwd(cwd) {
|
|
13449
13603
|
return cwd.replace(/^[/\\]+/, "").replace(/[/\\:]/g, "-");
|
|
13450
13604
|
}
|
|
@@ -13685,6 +13839,25 @@ var CursorRuntimeStrategy = class {
|
|
|
13685
13839
|
parseHistoryFile(filePath) {
|
|
13686
13840
|
return parseHistoryFile3(filePath);
|
|
13687
13841
|
}
|
|
13842
|
+
/**
|
|
13843
|
+
* Baton Take Control (native TUI → mobile ACP). Cursor keeps native-TUI
|
|
13844
|
+
* conversations in `~/.cursor/chats/<md5(cwd)>/<id>` but ACP `session/load`
|
|
13845
|
+
* only reads `~/.cursor/acp-sessions/<id>` — so without this, loading the
|
|
13846
|
+
* native session id fails "not found". Bridge the native store into the ACP
|
|
13847
|
+
* store just before the load. Best-effort; verified live (identical
|
|
13848
|
+
* `blobs`+`meta` SQLite schema, raw file copy replays the conversation).
|
|
13849
|
+
*/
|
|
13850
|
+
async syncTranscriptForAcpResume(cwd, sessionId) {
|
|
13851
|
+
bridgeNativeToAcp(cwd, sessionId);
|
|
13852
|
+
}
|
|
13853
|
+
/**
|
|
13854
|
+
* Baton hand-back (mobile ACP → native TUI). Copy the ACP conversation store
|
|
13855
|
+
* back into the native `~/.cursor/chats` store so `cursor-agent --resume <id>`
|
|
13856
|
+
* in the terminal picks up whatever mobile did. Best-effort.
|
|
13857
|
+
*/
|
|
13858
|
+
async syncTranscriptForNativeResume(cwd, sessionId) {
|
|
13859
|
+
bridgeAcpToNative(cwd, sessionId);
|
|
13860
|
+
}
|
|
13688
13861
|
getCurrentUsage(historyDir) {
|
|
13689
13862
|
return getCurrentUsage3(historyDir);
|
|
13690
13863
|
}
|
|
@@ -13957,7 +14130,7 @@ var AiderRuntimeStrategy = class {
|
|
|
13957
14130
|
};
|
|
13958
14131
|
|
|
13959
14132
|
// src/agents/gemini/runtime.ts
|
|
13960
|
-
var
|
|
14133
|
+
var import_node_crypto6 = require("crypto");
|
|
13961
14134
|
|
|
13962
14135
|
// src/agents/gemini/link.ts
|
|
13963
14136
|
var import_node_child_process12 = require("child_process");
|
|
@@ -14222,7 +14395,7 @@ var GeminiRuntimeStrategy = class {
|
|
|
14222
14395
|
"Gemini CLI is not on PATH. Install it with:\n npm install -g @google/gemini-cli\n Then run `codeam pair` again."
|
|
14223
14396
|
);
|
|
14224
14397
|
}
|
|
14225
|
-
const sessionId = (0,
|
|
14398
|
+
const sessionId = (0, import_node_crypto6.randomUUID)();
|
|
14226
14399
|
const launch = this.os.buildLaunch(binary, ["--session-id", sessionId]);
|
|
14227
14400
|
log.info(
|
|
14228
14401
|
"gemini",
|
|
@@ -14329,12 +14502,12 @@ var import_node_path4 = require("path");
|
|
|
14329
14502
|
var fs29 = __toESM(require("fs"));
|
|
14330
14503
|
var os26 = __toESM(require("os"));
|
|
14331
14504
|
var path33 = __toESM(require("path"));
|
|
14332
|
-
var
|
|
14505
|
+
var import_node_crypto7 = require("crypto");
|
|
14333
14506
|
function kimiHome() {
|
|
14334
14507
|
return process.env.KIMI_CODE_HOME || path33.join(os26.homedir(), ".kimi-code");
|
|
14335
14508
|
}
|
|
14336
14509
|
function workDirKey(cwd) {
|
|
14337
|
-
const hash = (0,
|
|
14510
|
+
const hash = (0, import_node_crypto7.createHash)("sha256").update(cwd).digest("hex").slice(0, 12);
|
|
14338
14511
|
return `wd_${path33.basename(cwd)}_${hash}`;
|
|
14339
14512
|
}
|
|
14340
14513
|
function resolveHistoryDir6(cwd) {
|
|
@@ -14391,7 +14564,7 @@ function scanBucketsForSession(sessionId) {
|
|
|
14391
14564
|
}
|
|
14392
14565
|
return null;
|
|
14393
14566
|
}
|
|
14394
|
-
async function
|
|
14567
|
+
async function discoverSessionId2(cwd, opts) {
|
|
14395
14568
|
const bucket = path33.join(kimiHome(), "sessions", workDirKey(cwd));
|
|
14396
14569
|
const floor = opts.sinceMs - 2e3;
|
|
14397
14570
|
const deadline = Date.now() + (opts.timeoutMs ?? 15e3);
|
|
@@ -14399,7 +14572,7 @@ async function discoverSessionId(cwd, opts) {
|
|
|
14399
14572
|
const id = newestSessionSince(bucket, floor);
|
|
14400
14573
|
if (id) return id;
|
|
14401
14574
|
if (Date.now() >= deadline) return null;
|
|
14402
|
-
await
|
|
14575
|
+
await sleep3(250);
|
|
14403
14576
|
}
|
|
14404
14577
|
}
|
|
14405
14578
|
function newestSessionSince(bucket, floorMs) {
|
|
@@ -14426,7 +14599,7 @@ function newestSessionSince(bucket, floorMs) {
|
|
|
14426
14599
|
}
|
|
14427
14600
|
return bestId;
|
|
14428
14601
|
}
|
|
14429
|
-
function
|
|
14602
|
+
function sleep3(ms) {
|
|
14430
14603
|
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
14431
14604
|
}
|
|
14432
14605
|
function joinTextParts(parts) {
|
|
@@ -14549,7 +14722,7 @@ var KimiRuntimeStrategy = class {
|
|
|
14549
14722
|
* have no baton), so the driver's optional call is inert for them.
|
|
14550
14723
|
*/
|
|
14551
14724
|
discoverSessionId(cwd, opts) {
|
|
14552
|
-
return
|
|
14725
|
+
return discoverSessionId2(cwd, opts);
|
|
14553
14726
|
}
|
|
14554
14727
|
getCurrentUsage(historyDir) {
|
|
14555
14728
|
return getCurrentUsage5(historyDir);
|
|
@@ -14727,9 +14900,9 @@ async function link(args2 = []) {
|
|
|
14727
14900
|
await linkDryRunPreflight(ctx);
|
|
14728
14901
|
return;
|
|
14729
14902
|
}
|
|
14730
|
-
const pluginId = (0,
|
|
14731
|
-
const pollSecret = (0,
|
|
14732
|
-
const pluginSecretHash = (0,
|
|
14903
|
+
const pluginId = (0, import_node_crypto8.randomUUID)();
|
|
14904
|
+
const pollSecret = (0, import_node_crypto8.randomBytes)(32).toString("base64url");
|
|
14905
|
+
const pluginSecretHash = (0, import_node_crypto8.createHash)("sha256").update(pollSecret).digest("hex");
|
|
14733
14906
|
const spin = dist_exports.spinner();
|
|
14734
14907
|
spin.start("Requesting pairing code...");
|
|
14735
14908
|
const pairing = await requestCode(pluginId, pluginSecretHash);
|
|
@@ -16560,7 +16733,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
16560
16733
|
if (process.env.NODE_ENV === "test") return;
|
|
16561
16734
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
16562
16735
|
if (process.env.CI) return;
|
|
16563
|
-
const current = true ? "2.60.
|
|
16736
|
+
const current = true ? "2.60.21" : null;
|
|
16564
16737
|
if (!current) return;
|
|
16565
16738
|
const cache = readCache();
|
|
16566
16739
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -16577,7 +16750,7 @@ function checkForUpdates() {
|
|
|
16577
16750
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
16578
16751
|
if (process.env.CI) return;
|
|
16579
16752
|
if (!process.stdout.isTTY) return;
|
|
16580
|
-
const current = true ? "2.60.
|
|
16753
|
+
const current = true ? "2.60.21" : null;
|
|
16581
16754
|
if (!current) return;
|
|
16582
16755
|
const cache = readCache();
|
|
16583
16756
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -16597,7 +16770,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
16597
16770
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
16598
16771
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
16599
16772
|
function currentCliVersion() {
|
|
16600
|
-
return true ? "2.60.
|
|
16773
|
+
return true ? "2.60.21" : null;
|
|
16601
16774
|
}
|
|
16602
16775
|
function runCmd(cmd, args2, timeoutMs) {
|
|
16603
16776
|
return new Promise((resolve7) => {
|
|
@@ -22129,7 +22302,7 @@ async function waitForClaudeNativeBinary(opts = {}) {
|
|
|
22129
22302
|
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
22130
22303
|
const pollMs = opts.pollMs ?? 500;
|
|
22131
22304
|
const now = opts.now ?? Date.now;
|
|
22132
|
-
const
|
|
22305
|
+
const sleep5 = opts.sleep ?? realSleep;
|
|
22133
22306
|
const deps = {
|
|
22134
22307
|
sdkDir: opts.sdkDir,
|
|
22135
22308
|
platformKey: opts.platformKey,
|
|
@@ -22139,7 +22312,7 @@ async function waitForClaudeNativeBinary(opts = {}) {
|
|
|
22139
22312
|
let found = resolveClaudeNativeBinary(deps);
|
|
22140
22313
|
if (found) return found;
|
|
22141
22314
|
while (now() < deadline) {
|
|
22142
|
-
await
|
|
22315
|
+
await sleep5(pollMs);
|
|
22143
22316
|
found = resolveClaudeNativeBinary(deps);
|
|
22144
22317
|
if (found) return found;
|
|
22145
22318
|
}
|
|
@@ -22161,13 +22334,13 @@ async function waitForCommandOnPath(cmd, opts = {}) {
|
|
|
22161
22334
|
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
22162
22335
|
const pollMs = opts.pollMs ?? 500;
|
|
22163
22336
|
const now = opts.now ?? Date.now;
|
|
22164
|
-
const
|
|
22337
|
+
const sleep5 = opts.sleep ?? realSleep;
|
|
22165
22338
|
const probe = opts.probe;
|
|
22166
22339
|
const check = () => isCommandOnPath(cmd, probe);
|
|
22167
22340
|
const deadline = now() + timeoutMs;
|
|
22168
22341
|
if (check()) return true;
|
|
22169
22342
|
while (now() < deadline) {
|
|
22170
|
-
await
|
|
22343
|
+
await sleep5(pollMs);
|
|
22171
22344
|
if (check()) return true;
|
|
22172
22345
|
}
|
|
22173
22346
|
return check();
|
|
@@ -22190,12 +22363,12 @@ async function waitForCursorAgent(opts = {}) {
|
|
|
22190
22363
|
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
22191
22364
|
const pollMs = opts.pollMs ?? 500;
|
|
22192
22365
|
const now = opts.now ?? Date.now;
|
|
22193
|
-
const
|
|
22366
|
+
const sleep5 = opts.sleep ?? realSleep;
|
|
22194
22367
|
const check = () => resolveCursorAgentBinary(opts) !== null || isCommandOnPath("cursor-agent", opts.probe);
|
|
22195
22368
|
const deadline = now() + timeoutMs;
|
|
22196
22369
|
if (check()) return true;
|
|
22197
22370
|
while (now() < deadline) {
|
|
22198
|
-
await
|
|
22371
|
+
await sleep5(pollMs);
|
|
22199
22372
|
if (check()) return true;
|
|
22200
22373
|
}
|
|
22201
22374
|
return check();
|
|
@@ -22244,12 +22417,12 @@ async function waitForAdapterModuleGraph(command2, args2, opts = {}) {
|
|
|
22244
22417
|
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
22245
22418
|
const pollMs = opts.pollMs ?? 500;
|
|
22246
22419
|
const now = opts.now ?? Date.now;
|
|
22247
|
-
const
|
|
22420
|
+
const sleep5 = opts.sleep ?? realSleep;
|
|
22248
22421
|
const probeOpts = { livenessMs: opts.livenessMs, spawnFn: opts.spawnFn };
|
|
22249
22422
|
const deadline = now() + timeoutMs;
|
|
22250
22423
|
if (await probeAdapterModuleGraph(command2, args2, probeOpts) === "ok") return true;
|
|
22251
22424
|
while (now() < deadline) {
|
|
22252
|
-
await
|
|
22425
|
+
await sleep5(pollMs);
|
|
22253
22426
|
if (await probeAdapterModuleGraph(command2, args2, probeOpts) === "ok") return true;
|
|
22254
22427
|
}
|
|
22255
22428
|
return false;
|
|
@@ -22431,7 +22604,7 @@ function requiresAcp(agent) {
|
|
|
22431
22604
|
}
|
|
22432
22605
|
|
|
22433
22606
|
// src/agents/acp/runner.ts
|
|
22434
|
-
var
|
|
22607
|
+
var import_node_crypto10 = require("crypto");
|
|
22435
22608
|
|
|
22436
22609
|
// src/services/history.service.ts
|
|
22437
22610
|
var fs55 = __toESM(require("fs"));
|
|
@@ -26632,7 +26805,7 @@ async function runOnboardingTurn(opts) {
|
|
|
26632
26805
|
}
|
|
26633
26806
|
|
|
26634
26807
|
// src/agents/acp/mappers.ts
|
|
26635
|
-
var
|
|
26808
|
+
var import_node_crypto9 = require("crypto");
|
|
26636
26809
|
function mapSessionUpdate(notification) {
|
|
26637
26810
|
const update = notification.update;
|
|
26638
26811
|
switch (update.sessionUpdate) {
|
|
@@ -26695,7 +26868,7 @@ function mapPermissionRequest(request) {
|
|
|
26695
26868
|
}
|
|
26696
26869
|
return {
|
|
26697
26870
|
event: {
|
|
26698
|
-
questionId: (0,
|
|
26871
|
+
questionId: (0, import_node_crypto9.randomUUID)(),
|
|
26699
26872
|
prompt,
|
|
26700
26873
|
options: labels.length > 0 ? labels : void 0
|
|
26701
26874
|
},
|
|
@@ -26705,7 +26878,7 @@ function mapPermissionRequest(request) {
|
|
|
26705
26878
|
}
|
|
26706
26879
|
function messageChunkId(messageId) {
|
|
26707
26880
|
if (typeof messageId === "string" && messageId.length > 0) return messageId;
|
|
26708
|
-
return (0,
|
|
26881
|
+
return (0, import_node_crypto9.randomUUID)();
|
|
26709
26882
|
}
|
|
26710
26883
|
function extractText4(content) {
|
|
26711
26884
|
if (!content || typeof content !== "object") return null;
|
|
@@ -28518,7 +28691,7 @@ var AcpHistory = class {
|
|
|
28518
28691
|
this.summary = trimmed.length > 120 ? trimmed.slice(0, 117) + "\u2026" : trimmed;
|
|
28519
28692
|
}
|
|
28520
28693
|
this.messages.push({
|
|
28521
|
-
id: (0,
|
|
28694
|
+
id: (0, import_node_crypto10.randomUUID)(),
|
|
28522
28695
|
role: "user",
|
|
28523
28696
|
text,
|
|
28524
28697
|
timestamp: Date.now()
|
|
@@ -28527,7 +28700,7 @@ var AcpHistory = class {
|
|
|
28527
28700
|
appendAgentReply(text) {
|
|
28528
28701
|
if (text.length === 0) return;
|
|
28529
28702
|
this.messages.push({
|
|
28530
|
-
id: (0,
|
|
28703
|
+
id: (0, import_node_crypto10.randomUUID)(),
|
|
28531
28704
|
role: "agent",
|
|
28532
28705
|
text,
|
|
28533
28706
|
timestamp: Date.now()
|
|
@@ -28733,7 +28906,7 @@ async function runAcpSession(opts) {
|
|
|
28733
28906
|
currentIndex: 0,
|
|
28734
28907
|
done: true
|
|
28735
28908
|
}),
|
|
28736
|
-
publishAwaitingAnswer: (prompt, options) => publisher.publishAwaitingAnswer({ questionId: (0,
|
|
28909
|
+
publishAwaitingAnswer: (prompt, options) => publisher.publishAwaitingAnswer({ questionId: (0, import_node_crypto10.randomUUID)(), prompt, options }),
|
|
28737
28910
|
publishRawChunk: (chunk) => publisher.publishOutput(chunk),
|
|
28738
28911
|
sendResult: (commandId, status2, result) => relay.sendResult(commandId, status2, result),
|
|
28739
28912
|
appendAgentReply: (text) => history.appendAgentReply(text),
|
|
@@ -29857,12 +30030,12 @@ var StreamingEmitterService = class {
|
|
|
29857
30030
|
log.warn("streamingEmitter", `post error url=${url} attempt=${attempt + 1}`, err);
|
|
29858
30031
|
}
|
|
29859
30032
|
if (attempt < MAX_RETRIES2) {
|
|
29860
|
-
await
|
|
30033
|
+
await sleep4(RETRY_BACKOFF_MS3 * (attempt + 1));
|
|
29861
30034
|
}
|
|
29862
30035
|
}
|
|
29863
30036
|
}
|
|
29864
30037
|
};
|
|
29865
|
-
function
|
|
30038
|
+
function sleep4(ms) {
|
|
29866
30039
|
return new Promise((r) => setTimeout(r, ms));
|
|
29867
30040
|
}
|
|
29868
30041
|
var TREE_CONTINUATION_RE = /^\s*└/;
|
|
@@ -30041,6 +30214,7 @@ var NativeTuiDriver = class {
|
|
|
30041
30214
|
keepAliveCtx;
|
|
30042
30215
|
async start(resumeId) {
|
|
30043
30216
|
if (resumeId !== void 0) {
|
|
30217
|
+
await this.deps.runtime.syncTranscriptForNativeResume?.(this.deps.opts.cwd, resumeId);
|
|
30044
30218
|
await this.agent.restart(resumeId, false);
|
|
30045
30219
|
return resumeId;
|
|
30046
30220
|
}
|
|
@@ -30099,7 +30273,7 @@ var NativeTuiDriver = class {
|
|
|
30099
30273
|
};
|
|
30100
30274
|
|
|
30101
30275
|
// src/baton/acp-driver.ts
|
|
30102
|
-
var
|
|
30276
|
+
var import_node_crypto11 = require("crypto");
|
|
30103
30277
|
var AcpDriver = class {
|
|
30104
30278
|
constructor(deps) {
|
|
30105
30279
|
this.deps = deps;
|
|
@@ -30121,6 +30295,7 @@ var AcpDriver = class {
|
|
|
30121
30295
|
try {
|
|
30122
30296
|
started = await this.deps.client.start();
|
|
30123
30297
|
if (resumeId !== void 0) {
|
|
30298
|
+
await this.deps.runtime.syncTranscriptForAcpResume?.(this.deps.opts.cwd, resumeId);
|
|
30124
30299
|
this.deps.streaming.beginLoadReplay();
|
|
30125
30300
|
try {
|
|
30126
30301
|
await this.deps.client.loadSession(resumeId);
|
|
@@ -30192,7 +30367,7 @@ var AcpDriver = class {
|
|
|
30192
30367
|
currentIndex: 0,
|
|
30193
30368
|
done: true
|
|
30194
30369
|
}),
|
|
30195
|
-
publishAwaitingAnswer: (prompt, options) => publisher.publishAwaitingAnswer({ questionId: (0,
|
|
30370
|
+
publishAwaitingAnswer: (prompt, options) => publisher.publishAwaitingAnswer({ questionId: (0, import_node_crypto11.randomUUID)(), prompt, options }),
|
|
30196
30371
|
publishRawChunk: (chunk) => publisher.publishOutput(chunk),
|
|
30197
30372
|
sendResult: (commandId, status2, result) => relay.sendResult(commandId, status2, result),
|
|
30198
30373
|
appendAgentReply: (text) => history.appendAgentReply(text),
|
|
@@ -33287,7 +33462,7 @@ async function invite() {
|
|
|
33287
33462
|
// src/commands/doctor.ts
|
|
33288
33463
|
var import_node_dns = require("dns");
|
|
33289
33464
|
var import_node_util5 = require("util");
|
|
33290
|
-
var
|
|
33465
|
+
var import_node_crypto12 = require("crypto");
|
|
33291
33466
|
var fs62 = __toESM(require("fs"));
|
|
33292
33467
|
var path69 = __toESM(require("path"));
|
|
33293
33468
|
var import_picocolors14 = __toESM(require("picocolors"));
|
|
@@ -33457,9 +33632,9 @@ function checkChokidar() {
|
|
|
33457
33632
|
}
|
|
33458
33633
|
async function doctor(args2 = []) {
|
|
33459
33634
|
const json = args2.includes("--json");
|
|
33460
|
-
const cliVersion = true ? "2.60.
|
|
33635
|
+
const cliVersion = true ? "2.60.21" : "0.0.0-dev";
|
|
33461
33636
|
const apiBase2 = resolveApiBaseUrl();
|
|
33462
|
-
const diagnosticId = (0,
|
|
33637
|
+
const diagnosticId = (0, import_node_crypto12.randomUUID)();
|
|
33463
33638
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
33464
33639
|
const [dns, health] = await Promise.all([
|
|
33465
33640
|
checkDns(apiBase2),
|
|
@@ -33656,7 +33831,7 @@ async function completion(args2) {
|
|
|
33656
33831
|
// src/commands/version.ts
|
|
33657
33832
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
33658
33833
|
function version2() {
|
|
33659
|
-
const v = true ? "2.60.
|
|
33834
|
+
const v = true ? "2.60.21" : "unknown";
|
|
33660
33835
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
33661
33836
|
}
|
|
33662
33837
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.60.
|
|
3
|
+
"version": "2.60.21",
|
|
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",
|