codeam-cli 2.60.20 → 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 +7 -0
- package/dist/index.js +113 -22
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@ 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
|
+
|
|
7
14
|
## [2.60.19] — 2026-07-09
|
|
8
15
|
|
|
9
16
|
### Fixed
|
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
|
/**
|
|
@@ -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
|
}
|
|
@@ -14473,7 +14564,7 @@ function scanBucketsForSession(sessionId) {
|
|
|
14473
14564
|
}
|
|
14474
14565
|
return null;
|
|
14475
14566
|
}
|
|
14476
|
-
async function
|
|
14567
|
+
async function discoverSessionId2(cwd, opts) {
|
|
14477
14568
|
const bucket = path33.join(kimiHome(), "sessions", workDirKey(cwd));
|
|
14478
14569
|
const floor = opts.sinceMs - 2e3;
|
|
14479
14570
|
const deadline = Date.now() + (opts.timeoutMs ?? 15e3);
|
|
@@ -14481,7 +14572,7 @@ async function discoverSessionId(cwd, opts) {
|
|
|
14481
14572
|
const id = newestSessionSince(bucket, floor);
|
|
14482
14573
|
if (id) return id;
|
|
14483
14574
|
if (Date.now() >= deadline) return null;
|
|
14484
|
-
await
|
|
14575
|
+
await sleep3(250);
|
|
14485
14576
|
}
|
|
14486
14577
|
}
|
|
14487
14578
|
function newestSessionSince(bucket, floorMs) {
|
|
@@ -14508,7 +14599,7 @@ function newestSessionSince(bucket, floorMs) {
|
|
|
14508
14599
|
}
|
|
14509
14600
|
return bestId;
|
|
14510
14601
|
}
|
|
14511
|
-
function
|
|
14602
|
+
function sleep3(ms) {
|
|
14512
14603
|
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
14513
14604
|
}
|
|
14514
14605
|
function joinTextParts(parts) {
|
|
@@ -14631,7 +14722,7 @@ var KimiRuntimeStrategy = class {
|
|
|
14631
14722
|
* have no baton), so the driver's optional call is inert for them.
|
|
14632
14723
|
*/
|
|
14633
14724
|
discoverSessionId(cwd, opts) {
|
|
14634
|
-
return
|
|
14725
|
+
return discoverSessionId2(cwd, opts);
|
|
14635
14726
|
}
|
|
14636
14727
|
getCurrentUsage(historyDir) {
|
|
14637
14728
|
return getCurrentUsage5(historyDir);
|
|
@@ -16642,7 +16733,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
16642
16733
|
if (process.env.NODE_ENV === "test") return;
|
|
16643
16734
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
16644
16735
|
if (process.env.CI) return;
|
|
16645
|
-
const current = true ? "2.60.
|
|
16736
|
+
const current = true ? "2.60.21" : null;
|
|
16646
16737
|
if (!current) return;
|
|
16647
16738
|
const cache = readCache();
|
|
16648
16739
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -16659,7 +16750,7 @@ function checkForUpdates() {
|
|
|
16659
16750
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
16660
16751
|
if (process.env.CI) return;
|
|
16661
16752
|
if (!process.stdout.isTTY) return;
|
|
16662
|
-
const current = true ? "2.60.
|
|
16753
|
+
const current = true ? "2.60.21" : null;
|
|
16663
16754
|
if (!current) return;
|
|
16664
16755
|
const cache = readCache();
|
|
16665
16756
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -16679,7 +16770,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
16679
16770
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
16680
16771
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
16681
16772
|
function currentCliVersion() {
|
|
16682
|
-
return true ? "2.60.
|
|
16773
|
+
return true ? "2.60.21" : null;
|
|
16683
16774
|
}
|
|
16684
16775
|
function runCmd(cmd, args2, timeoutMs) {
|
|
16685
16776
|
return new Promise((resolve7) => {
|
|
@@ -22211,7 +22302,7 @@ async function waitForClaudeNativeBinary(opts = {}) {
|
|
|
22211
22302
|
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
22212
22303
|
const pollMs = opts.pollMs ?? 500;
|
|
22213
22304
|
const now = opts.now ?? Date.now;
|
|
22214
|
-
const
|
|
22305
|
+
const sleep5 = opts.sleep ?? realSleep;
|
|
22215
22306
|
const deps = {
|
|
22216
22307
|
sdkDir: opts.sdkDir,
|
|
22217
22308
|
platformKey: opts.platformKey,
|
|
@@ -22221,7 +22312,7 @@ async function waitForClaudeNativeBinary(opts = {}) {
|
|
|
22221
22312
|
let found = resolveClaudeNativeBinary(deps);
|
|
22222
22313
|
if (found) return found;
|
|
22223
22314
|
while (now() < deadline) {
|
|
22224
|
-
await
|
|
22315
|
+
await sleep5(pollMs);
|
|
22225
22316
|
found = resolveClaudeNativeBinary(deps);
|
|
22226
22317
|
if (found) return found;
|
|
22227
22318
|
}
|
|
@@ -22243,13 +22334,13 @@ async function waitForCommandOnPath(cmd, opts = {}) {
|
|
|
22243
22334
|
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
22244
22335
|
const pollMs = opts.pollMs ?? 500;
|
|
22245
22336
|
const now = opts.now ?? Date.now;
|
|
22246
|
-
const
|
|
22337
|
+
const sleep5 = opts.sleep ?? realSleep;
|
|
22247
22338
|
const probe = opts.probe;
|
|
22248
22339
|
const check = () => isCommandOnPath(cmd, probe);
|
|
22249
22340
|
const deadline = now() + timeoutMs;
|
|
22250
22341
|
if (check()) return true;
|
|
22251
22342
|
while (now() < deadline) {
|
|
22252
|
-
await
|
|
22343
|
+
await sleep5(pollMs);
|
|
22253
22344
|
if (check()) return true;
|
|
22254
22345
|
}
|
|
22255
22346
|
return check();
|
|
@@ -22272,12 +22363,12 @@ async function waitForCursorAgent(opts = {}) {
|
|
|
22272
22363
|
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
22273
22364
|
const pollMs = opts.pollMs ?? 500;
|
|
22274
22365
|
const now = opts.now ?? Date.now;
|
|
22275
|
-
const
|
|
22366
|
+
const sleep5 = opts.sleep ?? realSleep;
|
|
22276
22367
|
const check = () => resolveCursorAgentBinary(opts) !== null || isCommandOnPath("cursor-agent", opts.probe);
|
|
22277
22368
|
const deadline = now() + timeoutMs;
|
|
22278
22369
|
if (check()) return true;
|
|
22279
22370
|
while (now() < deadline) {
|
|
22280
|
-
await
|
|
22371
|
+
await sleep5(pollMs);
|
|
22281
22372
|
if (check()) return true;
|
|
22282
22373
|
}
|
|
22283
22374
|
return check();
|
|
@@ -22326,12 +22417,12 @@ async function waitForAdapterModuleGraph(command2, args2, opts = {}) {
|
|
|
22326
22417
|
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
22327
22418
|
const pollMs = opts.pollMs ?? 500;
|
|
22328
22419
|
const now = opts.now ?? Date.now;
|
|
22329
|
-
const
|
|
22420
|
+
const sleep5 = opts.sleep ?? realSleep;
|
|
22330
22421
|
const probeOpts = { livenessMs: opts.livenessMs, spawnFn: opts.spawnFn };
|
|
22331
22422
|
const deadline = now() + timeoutMs;
|
|
22332
22423
|
if (await probeAdapterModuleGraph(command2, args2, probeOpts) === "ok") return true;
|
|
22333
22424
|
while (now() < deadline) {
|
|
22334
|
-
await
|
|
22425
|
+
await sleep5(pollMs);
|
|
22335
22426
|
if (await probeAdapterModuleGraph(command2, args2, probeOpts) === "ok") return true;
|
|
22336
22427
|
}
|
|
22337
22428
|
return false;
|
|
@@ -29939,12 +30030,12 @@ var StreamingEmitterService = class {
|
|
|
29939
30030
|
log.warn("streamingEmitter", `post error url=${url} attempt=${attempt + 1}`, err);
|
|
29940
30031
|
}
|
|
29941
30032
|
if (attempt < MAX_RETRIES2) {
|
|
29942
|
-
await
|
|
30033
|
+
await sleep4(RETRY_BACKOFF_MS3 * (attempt + 1));
|
|
29943
30034
|
}
|
|
29944
30035
|
}
|
|
29945
30036
|
}
|
|
29946
30037
|
};
|
|
29947
|
-
function
|
|
30038
|
+
function sleep4(ms) {
|
|
29948
30039
|
return new Promise((r) => setTimeout(r, ms));
|
|
29949
30040
|
}
|
|
29950
30041
|
var TREE_CONTINUATION_RE = /^\s*└/;
|
|
@@ -33541,7 +33632,7 @@ function checkChokidar() {
|
|
|
33541
33632
|
}
|
|
33542
33633
|
async function doctor(args2 = []) {
|
|
33543
33634
|
const json = args2.includes("--json");
|
|
33544
|
-
const cliVersion = true ? "2.60.
|
|
33635
|
+
const cliVersion = true ? "2.60.21" : "0.0.0-dev";
|
|
33545
33636
|
const apiBase2 = resolveApiBaseUrl();
|
|
33546
33637
|
const diagnosticId = (0, import_node_crypto12.randomUUID)();
|
|
33547
33638
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -33740,7 +33831,7 @@ async function completion(args2) {
|
|
|
33740
33831
|
// src/commands/version.ts
|
|
33741
33832
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
33742
33833
|
function version2() {
|
|
33743
|
-
const v = true ? "2.60.
|
|
33834
|
+
const v = true ? "2.60.21" : "unknown";
|
|
33744
33835
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
33745
33836
|
}
|
|
33746
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",
|