codeam-cli 2.60.6 → 2.60.8
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 +26 -0
- package/dist/index.js +85 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,32 @@ 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.7] — 2026-07-08
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Retry ACP start on the adapter's transient in-binary spawn ETXTBSY
|
|
12
|
+
|
|
13
|
+
## [2.60.6] — 2026-07-08
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **cli:** Serialize ACP prompts so a 2nd in-flight turn can't clobber the watchdog
|
|
18
|
+
|
|
19
|
+
## [2.60.5] — 2026-07-08
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **cli:** Baton support for cursor + gate to agents with a resumable transcript
|
|
24
|
+
|
|
25
|
+
### Documentation
|
|
26
|
+
|
|
27
|
+
- **cli:** Document the Session Baton (native TUI <-> mobile ACP) architecture + hand-off invariants
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- **cli:** Serialize baton state POSTs so handback never sticks on "Switching…"
|
|
32
|
+
|
|
7
33
|
## [2.60.4] — 2026-07-08
|
|
8
34
|
|
|
9
35
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -5653,7 +5653,7 @@ function readAnonId() {
|
|
|
5653
5653
|
}
|
|
5654
5654
|
function superProperties() {
|
|
5655
5655
|
return {
|
|
5656
|
-
cliVersion: true ? "2.60.
|
|
5656
|
+
cliVersion: true ? "2.60.8" : "0.0.0-dev",
|
|
5657
5657
|
nodeVersion: process.version,
|
|
5658
5658
|
platform: process.platform,
|
|
5659
5659
|
arch: process.arch,
|
|
@@ -5834,7 +5834,7 @@ var os4 = __toESM(require("os"));
|
|
|
5834
5834
|
// package.json
|
|
5835
5835
|
var package_default = {
|
|
5836
5836
|
name: "codeam-cli",
|
|
5837
|
-
version: "2.60.
|
|
5837
|
+
version: "2.60.8",
|
|
5838
5838
|
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.",
|
|
5839
5839
|
type: "commonjs",
|
|
5840
5840
|
main: "dist/index.js",
|
|
@@ -6905,7 +6905,7 @@ var CommandRelayService = class {
|
|
|
6905
6905
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
6906
6906
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
6907
6907
|
// pair/reconnect). Older backends ignore the extra field.
|
|
6908
|
-
..."2.60.
|
|
6908
|
+
..."2.60.8" ? { ideVersion: "2.60.8" } : {}
|
|
6909
6909
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
6910
6910
|
}
|
|
6911
6911
|
/**
|
|
@@ -12703,6 +12703,26 @@ function mapRole(codexRole) {
|
|
|
12703
12703
|
if (codexRole === "assistant") return "agent";
|
|
12704
12704
|
return "system";
|
|
12705
12705
|
}
|
|
12706
|
+
function messageFromPayload(payload) {
|
|
12707
|
+
if (!payload || typeof payload !== "object") return null;
|
|
12708
|
+
const p2 = payload;
|
|
12709
|
+
if (p2.type === "message" && Array.isArray(p2.content)) {
|
|
12710
|
+
return {
|
|
12711
|
+
role: typeof p2.role === "string" ? p2.role : void 0,
|
|
12712
|
+
content: p2.content
|
|
12713
|
+
};
|
|
12714
|
+
}
|
|
12715
|
+
if (p2.Message && typeof p2.Message === "object") return p2.Message;
|
|
12716
|
+
return null;
|
|
12717
|
+
}
|
|
12718
|
+
function isSyntheticCodexTurn(role, text) {
|
|
12719
|
+
if (role === "developer" || role === "system") return true;
|
|
12720
|
+
const trimmed = text.trim();
|
|
12721
|
+
if (trimmed.startsWith("<environment_context>")) return true;
|
|
12722
|
+
if (trimmed.startsWith("<turn_aborted>")) return true;
|
|
12723
|
+
if (/^(<<ccr:[^>]*>>\s*)+$/.test(trimmed)) return true;
|
|
12724
|
+
return false;
|
|
12725
|
+
}
|
|
12706
12726
|
function parseHistoryFile2(filePath) {
|
|
12707
12727
|
const raw = import_node_fs3.default.readFileSync(filePath, "utf8");
|
|
12708
12728
|
const lines = raw.split("\n").filter(Boolean);
|
|
@@ -12734,11 +12754,11 @@ function parseHistoryFile2(filePath) {
|
|
|
12734
12754
|
const rec = parseLine(line);
|
|
12735
12755
|
if (!rec) continue;
|
|
12736
12756
|
if (rec.type !== "response_item") continue;
|
|
12737
|
-
const
|
|
12738
|
-
const msg = payload?.Message;
|
|
12757
|
+
const msg = messageFromPayload(rec.payload);
|
|
12739
12758
|
if (!msg) continue;
|
|
12740
12759
|
const text = extractMessageText(msg.content);
|
|
12741
12760
|
if (!text) continue;
|
|
12761
|
+
if (isSyntheticCodexTurn(msg.role, text)) continue;
|
|
12742
12762
|
out2.push({
|
|
12743
12763
|
id: `rollout:${idx}`,
|
|
12744
12764
|
role: mapRole(msg.role),
|
|
@@ -12801,11 +12821,10 @@ function listResumableSessions2(cwd, homeOverride) {
|
|
|
12801
12821
|
continue;
|
|
12802
12822
|
}
|
|
12803
12823
|
if (!summary && rec.type === "response_item") {
|
|
12804
|
-
const
|
|
12805
|
-
const msg = payload?.Message;
|
|
12824
|
+
const msg = messageFromPayload(rec.payload);
|
|
12806
12825
|
if (msg && msg.role === "user") {
|
|
12807
12826
|
const text = extractMessageText(msg.content).trim();
|
|
12808
|
-
if (text) summary = text.slice(0, 120);
|
|
12827
|
+
if (text && !isSyntheticCodexTurn(msg.role, text)) summary = text.slice(0, 120);
|
|
12809
12828
|
}
|
|
12810
12829
|
}
|
|
12811
12830
|
if (metaCwd !== void 0 && summary) break;
|
|
@@ -15986,7 +16005,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
15986
16005
|
if (process.env.NODE_ENV === "test") return;
|
|
15987
16006
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
15988
16007
|
if (process.env.CI) return;
|
|
15989
|
-
const current = true ? "2.60.
|
|
16008
|
+
const current = true ? "2.60.8" : null;
|
|
15990
16009
|
if (!current) return;
|
|
15991
16010
|
const cache = readCache();
|
|
15992
16011
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -16003,7 +16022,7 @@ function checkForUpdates() {
|
|
|
16003
16022
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
16004
16023
|
if (process.env.CI) return;
|
|
16005
16024
|
if (!process.stdout.isTTY) return;
|
|
16006
|
-
const current = true ? "2.60.
|
|
16025
|
+
const current = true ? "2.60.8" : null;
|
|
16007
16026
|
if (!current) return;
|
|
16008
16027
|
const cache = readCache();
|
|
16009
16028
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -16023,7 +16042,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
16023
16042
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
16024
16043
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
16025
16044
|
function currentCliVersion() {
|
|
16026
|
-
return true ? "2.60.
|
|
16045
|
+
return true ? "2.60.8" : null;
|
|
16027
16046
|
}
|
|
16028
16047
|
function runCmd(cmd, args2, timeoutMs) {
|
|
16029
16048
|
return new Promise((resolve7) => {
|
|
@@ -24850,6 +24869,11 @@ function createIdleTimeout(idleMs, makeError) {
|
|
|
24850
24869
|
}
|
|
24851
24870
|
|
|
24852
24871
|
// src/agents/acp/client.ts
|
|
24872
|
+
var TRANSIENT_ADAPTER_SPAWN_RE = /ETXTBSY|ENOENT/;
|
|
24873
|
+
var MAX_START_ATTEMPTS = 5;
|
|
24874
|
+
var _acpStartSeam = {
|
|
24875
|
+
sleep: (ms) => new Promise((r) => setTimeout(r, ms))
|
|
24876
|
+
};
|
|
24853
24877
|
var PROTOCOL_VERSION2 = 1;
|
|
24854
24878
|
var FATAL_STARTUP_RE = /IneligibleTierError|UNSUPPORTED_CLIENT|no longer supported for Gemini Code Assist|not eligible for Gemini Code Assist|Error authenticating|ProjectIdRequiredError/i;
|
|
24855
24879
|
var NEWSESSION_TIMEOUT_MS = 12e4;
|
|
@@ -24895,15 +24919,57 @@ var AcpClient = class {
|
|
|
24895
24919
|
* so without this the session hangs forever ("loading… / offline"). */
|
|
24896
24920
|
startupFailureReject = null;
|
|
24897
24921
|
/**
|
|
24898
|
-
* Spawn the adapter +
|
|
24899
|
-
*
|
|
24900
|
-
*
|
|
24901
|
-
*
|
|
24902
|
-
*
|
|
24903
|
-
*
|
|
24922
|
+
* Spawn the adapter + handshake, retrying a TRANSIENT in-adapter spawn race.
|
|
24923
|
+
*
|
|
24924
|
+
* The adapter itself execs the real agent binary (claude-agent-acp spawns the
|
|
24925
|
+
* ~250MB SDK-bundled `claude` during newSession). On a fresh/waking codespace
|
|
24926
|
+
* that binary is momentarily open-for-write → the adapter rejects newSession
|
|
24927
|
+
* with `-32603 … spawn ETXTBSY` (or ENOENT before it lands). Both clear within
|
|
24928
|
+
* ms, so we respawn the adapter + re-handshake up to {@link MAX_START_ATTEMPTS}
|
|
24929
|
+
* times. `startOnce` fully cleans up on failure (see cleanupAfterFailedStart),
|
|
24930
|
+
* so each retry starts from a clean slate. Non-transient failures throw on the
|
|
24931
|
+
* first attempt — no masking of real auth/outage errors.
|
|
24904
24932
|
*/
|
|
24905
24933
|
async start() {
|
|
24934
|
+
let lastErr;
|
|
24935
|
+
for (let attempt = 1; attempt <= MAX_START_ATTEMPTS; attempt += 1) {
|
|
24936
|
+
try {
|
|
24937
|
+
return await this.startOnce();
|
|
24938
|
+
} catch (err) {
|
|
24939
|
+
lastErr = err;
|
|
24940
|
+
if (attempt < MAX_START_ATTEMPTS && this.isTransientAdapterSpawn(err)) {
|
|
24941
|
+
log.info(
|
|
24942
|
+
"acpClient",
|
|
24943
|
+
`adapter hit a transient spawn race (binary busy) \u2014 retrying start ${attempt + 1}/${MAX_START_ATTEMPTS}`
|
|
24944
|
+
);
|
|
24945
|
+
await _acpStartSeam.sleep(400 * attempt);
|
|
24946
|
+
continue;
|
|
24947
|
+
}
|
|
24948
|
+
throw err;
|
|
24949
|
+
}
|
|
24950
|
+
}
|
|
24951
|
+
throw lastErr;
|
|
24952
|
+
}
|
|
24953
|
+
/** True when a failed {@link startOnce} was caused by the adapter's OWN
|
|
24954
|
+
* transient spawn of the agent binary (ETXTBSY/ENOENT). Checks the thrown
|
|
24955
|
+
* error's message/data AND the adapter stderr ring — the adapter logs the
|
|
24956
|
+
* real cause to stderr while returning a generic `-32603 Internal error`. */
|
|
24957
|
+
isTransientAdapterSpawn(err) {
|
|
24958
|
+
const parts = [...this.recentStderr];
|
|
24959
|
+
if (err instanceof Error) parts.push(err.message);
|
|
24960
|
+
if (err && typeof err === "object") {
|
|
24961
|
+
const e = err;
|
|
24962
|
+
try {
|
|
24963
|
+
parts.push(JSON.stringify(e.data));
|
|
24964
|
+
} catch {
|
|
24965
|
+
}
|
|
24966
|
+
if (typeof e.details === "string") parts.push(e.details);
|
|
24967
|
+
}
|
|
24968
|
+
return TRANSIENT_ADAPTER_SPAWN_RE.test(parts.join(" "));
|
|
24969
|
+
}
|
|
24970
|
+
async startOnce() {
|
|
24906
24971
|
if (this.child) throw new Error("AcpClient already started");
|
|
24972
|
+
this.recentStderr.length = 0;
|
|
24907
24973
|
const { adapter, cwd } = this.opts;
|
|
24908
24974
|
const augmentedPath = expandPathForAgentBinaries(process.env.PATH ?? "");
|
|
24909
24975
|
log.info(
|
|
@@ -32755,7 +32821,7 @@ function checkChokidar() {
|
|
|
32755
32821
|
}
|
|
32756
32822
|
async function doctor(args2 = []) {
|
|
32757
32823
|
const json = args2.includes("--json");
|
|
32758
|
-
const cliVersion = true ? "2.60.
|
|
32824
|
+
const cliVersion = true ? "2.60.8" : "0.0.0-dev";
|
|
32759
32825
|
const apiBase2 = resolveApiBaseUrl();
|
|
32760
32826
|
const diagnosticId = (0, import_node_crypto9.randomUUID)();
|
|
32761
32827
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -32954,7 +33020,7 @@ async function completion(args2) {
|
|
|
32954
33020
|
// src/commands/version.ts
|
|
32955
33021
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
32956
33022
|
function version2() {
|
|
32957
|
-
const v = true ? "2.60.
|
|
33023
|
+
const v = true ? "2.60.8" : "unknown";
|
|
32958
33024
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
32959
33025
|
}
|
|
32960
33026
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.60.
|
|
3
|
+
"version": "2.60.8",
|
|
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",
|