codeam-cli 2.76.33 → 2.76.35
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 +14 -0
- package/dist/index.js +193 -33
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@ 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.76.34] — 2026-10-21
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Collect old versioned installs on every self-update tick (#983)
|
|
12
|
+
- **cli:** Migrate the beads schema on start and pin bd to 1.3.1 in CLI and Box (#984)
|
|
13
|
+
|
|
14
|
+
## [2.76.33] — 2026-10-14
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **box:** Bake PHP CLI + Composer into the Box image
|
|
19
|
+
- **cli:** Composer pre-flight + PHP guidance for in-app Preview
|
|
20
|
+
|
|
7
21
|
## [2.76.32] — 2026-10-14
|
|
8
22
|
|
|
9
23
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -10636,7 +10636,7 @@ function readAnonId() {
|
|
|
10636
10636
|
}
|
|
10637
10637
|
function superProperties() {
|
|
10638
10638
|
return {
|
|
10639
|
-
cliVersion: true ? "2.76.
|
|
10639
|
+
cliVersion: true ? "2.76.35" : "0.0.0-dev",
|
|
10640
10640
|
nodeVersion: process.version,
|
|
10641
10641
|
platform: process.platform,
|
|
10642
10642
|
arch: process.arch,
|
|
@@ -10885,7 +10885,7 @@ var http = __toESM(require("http"));
|
|
|
10885
10885
|
// package.json
|
|
10886
10886
|
var package_default = {
|
|
10887
10887
|
name: "codeam-cli",
|
|
10888
|
-
version: "2.76.
|
|
10888
|
+
version: "2.76.35",
|
|
10889
10889
|
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.",
|
|
10890
10890
|
type: "commonjs",
|
|
10891
10891
|
main: "dist/index.js",
|
|
@@ -10973,7 +10973,7 @@ var package_default = {
|
|
|
10973
10973
|
zod: "^4.3.6"
|
|
10974
10974
|
},
|
|
10975
10975
|
optionalDependencies: {
|
|
10976
|
-
"@beads/bd": "1.
|
|
10976
|
+
"@beads/bd": "1.3.1"
|
|
10977
10977
|
},
|
|
10978
10978
|
devDependencies: {
|
|
10979
10979
|
"@codeam/shared": "*",
|
|
@@ -12261,7 +12261,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
12261
12261
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
12262
12262
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
12263
12263
|
// pair/reconnect). Older backends ignore the extra field.
|
|
12264
|
-
..."2.76.
|
|
12264
|
+
..."2.76.35" ? { ideVersion: "2.76.35" } : {}
|
|
12265
12265
|
};
|
|
12266
12266
|
try {
|
|
12267
12267
|
const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body, this.pollSecretHeader());
|
|
@@ -26033,6 +26033,18 @@ var ONE_M_CREDITS_MESSAGE = "\u{1F504} **Reconnect your Claude subscription to c
|
|
|
26033
26033
|
var TURN_FAILURE_MESSAGE = "\u26A0\uFE0F **The agent hit an error and couldn\u2019t finish this turn.** Please send your message again.";
|
|
26034
26034
|
var IDLE_TURN_FAILURE_MESSAGE = "\u26A0\uFE0F **The agent stopped responding, so this turn was ended.** Your message wasn\u2019t answered \u2014 send it again.";
|
|
26035
26035
|
var IDLE_TURN_RE = /ACP prompt idle/;
|
|
26036
|
+
var AGENT_FREE_LIMIT_RE = /Free usage limit reached/i;
|
|
26037
|
+
function looksLikeAgentFreeLimit(text) {
|
|
26038
|
+
return AGENT_FREE_LIMIT_RE.test(text);
|
|
26039
|
+
}
|
|
26040
|
+
var AGENT_FREE_LIMIT_MESSAGE = [
|
|
26041
|
+
"\u26A0\uFE0F **OpenCode\u2019s free models have hit their usage limit, so this message wasn\u2019t answered.**",
|
|
26042
|
+
"",
|
|
26043
|
+
"Messages will keep failing until the limit resets. To keep going now:",
|
|
26044
|
+
"\u2022 add your own provider key for opencode in **Profile \u203A Agents** (OpenRouter, Anthropic, OpenAI, \u2026),",
|
|
26045
|
+
"\u2022 switch this session to another agent, or",
|
|
26046
|
+
"\u2022 subscribe to OpenCode Go: [opencode.ai/go](https://opencode.ai/go)."
|
|
26047
|
+
].join("\n");
|
|
26036
26048
|
function emptyReplyMessage(agent) {
|
|
26037
26049
|
const label = isKnownAgentId(agent) ? AGENT_REGISTRY[agent].displayName : agent;
|
|
26038
26050
|
const binary = isKnownAgentId(agent) ? AGENT_REGISTRY[agent].binaryName : agent;
|
|
@@ -26096,6 +26108,9 @@ function failureBubble(opts) {
|
|
|
26096
26108
|
return houseAgentLimitMessage(`${opts.detail}
|
|
26097
26109
|
${opts.recentStderr}`);
|
|
26098
26110
|
}
|
|
26111
|
+
if (looksLikeAgentFreeLimit(opts.detail) || looksLikeAgentFreeLimit(opts.recentStderr)) {
|
|
26112
|
+
return AGENT_FREE_LIMIT_MESSAGE;
|
|
26113
|
+
}
|
|
26099
26114
|
if (looksLikeByoProviderBilling(opts.detail, env) || looksLikeByoProviderBilling(opts.recentStderr, env)) {
|
|
26100
26115
|
return byoProviderBillingMessage(byoProviderName({ env, agent: opts.agent }));
|
|
26101
26116
|
}
|
|
@@ -27509,6 +27524,43 @@ var import_child_process21 = require("child_process");
|
|
|
27509
27524
|
var fs59 = __toESM(require("fs"));
|
|
27510
27525
|
var os40 = __toESM(require("os"));
|
|
27511
27526
|
var path67 = __toESM(require("path"));
|
|
27527
|
+
|
|
27528
|
+
// src/beads/schema-migrate.ts
|
|
27529
|
+
var SCHEMA_SKEW_RE = /Error 1146|table not found|refusing to auto-apply \d+ pending schema migration/i;
|
|
27530
|
+
function isSchemaSkew(text) {
|
|
27531
|
+
return SCHEMA_SKEW_RE.test(text);
|
|
27532
|
+
}
|
|
27533
|
+
var APPLIED_RE = /applying (\d+) pending schema migration/i;
|
|
27534
|
+
var REMOTE_GATE_RE = /remote-backed database/i;
|
|
27535
|
+
async function migrateSchema(bd) {
|
|
27536
|
+
let forced = false;
|
|
27537
|
+
let res = await bd.run(["migrate", "schema"]);
|
|
27538
|
+
if (res.code !== 0 && REMOTE_GATE_RE.test(res.stderr + res.stdout)) {
|
|
27539
|
+
log.info("beads", "schema migrate refused for a remote-backed DB \u2014 migrating with --force");
|
|
27540
|
+
forced = true;
|
|
27541
|
+
res = await bd.run(["migrate", "schema", "--force"]);
|
|
27542
|
+
}
|
|
27543
|
+
const text = `${res.stderr}
|
|
27544
|
+
${res.stdout}`;
|
|
27545
|
+
if (res.code !== 0) {
|
|
27546
|
+
const detail = (res.stderr || res.stdout).trim().slice(0, 200);
|
|
27547
|
+
log.warn("beads", `bd migrate schema failed (code=${res.code}): ${detail}`);
|
|
27548
|
+
return { status: "failed", detail };
|
|
27549
|
+
}
|
|
27550
|
+
const applied = APPLIED_RE.exec(text);
|
|
27551
|
+
if (applied) {
|
|
27552
|
+
const count = Number(applied[1]);
|
|
27553
|
+
log.info(
|
|
27554
|
+
"beads",
|
|
27555
|
+
`bd migrate schema applied ${count} migration(s)${forced ? " (--force)" : ""}`
|
|
27556
|
+
);
|
|
27557
|
+
return { status: "applied", count, forced };
|
|
27558
|
+
}
|
|
27559
|
+
log.trace("beads", "bd migrate schema: already current");
|
|
27560
|
+
return { status: "current" };
|
|
27561
|
+
}
|
|
27562
|
+
|
|
27563
|
+
// src/beads/bd-adapter.ts
|
|
27512
27564
|
var BD_PACKAGE = "@beads/bd";
|
|
27513
27565
|
function resolveBundledBdBinary() {
|
|
27514
27566
|
return _resolveSeam.resolveBundled();
|
|
@@ -27586,6 +27638,8 @@ var BdAdapter = class {
|
|
|
27586
27638
|
}
|
|
27587
27639
|
opts;
|
|
27588
27640
|
resolved;
|
|
27641
|
+
/** Set when a bd call failed on schema skew; read + cleared by `takeSchemaSkew`. */
|
|
27642
|
+
schemaSkewSeen = false;
|
|
27589
27643
|
/**
|
|
27590
27644
|
* Resolve the bd binary lazily, caching the result. Order:
|
|
27591
27645
|
* bundled @beads/bd → PATH. Returns null when neither is available — the
|
|
@@ -27641,8 +27695,20 @@ var BdAdapter = class {
|
|
|
27641
27695
|
await _adapterSeam.sleep(750 * attempt);
|
|
27642
27696
|
res = await _spawnSeam.run(binary, args2, { cwd, env });
|
|
27643
27697
|
}
|
|
27698
|
+
if (res.code !== 0 && isSchemaSkew(res.stderr + res.stdout)) this.schemaSkewSeen = true;
|
|
27644
27699
|
return res;
|
|
27645
27700
|
}
|
|
27701
|
+
/**
|
|
27702
|
+
* Whether a bd call since the last check failed because the project DB is
|
|
27703
|
+
* behind this bd's schema (see `schema-migrate.ts`). `listIssues` /
|
|
27704
|
+
* `statusSummary` swallow failures into []/null, so this is how the watcher
|
|
27705
|
+
* learns the cause. Clears the flag.
|
|
27706
|
+
*/
|
|
27707
|
+
takeSchemaSkew() {
|
|
27708
|
+
const seen2 = this.schemaSkewSeen;
|
|
27709
|
+
this.schemaSkewSeen = false;
|
|
27710
|
+
return seen2;
|
|
27711
|
+
}
|
|
27646
27712
|
/**
|
|
27647
27713
|
* `bd ready --json` → typed issue array. `bd list --json` shares the shape,
|
|
27648
27714
|
* so `listIssues` reuses the same parser. Bad JSON / non-zero exit → [].
|
|
@@ -28208,7 +28274,8 @@ async function provisionBeads(opts = {}) {
|
|
|
28208
28274
|
prefix: null,
|
|
28209
28275
|
initialized: false,
|
|
28210
28276
|
exportEnabled: false,
|
|
28211
|
-
agentsWired: []
|
|
28277
|
+
agentsWired: [],
|
|
28278
|
+
schemaMigrate: null
|
|
28212
28279
|
};
|
|
28213
28280
|
if (!bd.isAvailable()) {
|
|
28214
28281
|
log.info("beads", "bd binary missing \u2014 running OS installer fallback");
|
|
@@ -28290,6 +28357,7 @@ async function provisionBeads(opts = {}) {
|
|
|
28290
28357
|
log.warn("beads", "shared dolt sql-server not up \u2014 beads disabled this run");
|
|
28291
28358
|
return result;
|
|
28292
28359
|
}
|
|
28360
|
+
result.schemaMigrate = await migrateSchemaSafely(bd);
|
|
28293
28361
|
try {
|
|
28294
28362
|
if (!await projectDbReachable(bd)) {
|
|
28295
28363
|
log.info(
|
|
@@ -28305,6 +28373,8 @@ async function provisionBeads(opts = {}) {
|
|
|
28305
28373
|
"beads",
|
|
28306
28374
|
`bd bootstrap failed (code=${boot.code}): ${boot.stderr.slice(0, 200)} \u2014 prefix DB may be absent`
|
|
28307
28375
|
);
|
|
28376
|
+
} else {
|
|
28377
|
+
result.schemaMigrate = await migrateSchemaSafely(bd);
|
|
28308
28378
|
}
|
|
28309
28379
|
}
|
|
28310
28380
|
if (!await projectDbReachable(bd)) {
|
|
@@ -28356,10 +28426,25 @@ async function provisionBeads(opts = {}) {
|
|
|
28356
28426
|
result.agentsWired = await setupAgents(bd, opts.agents ?? []);
|
|
28357
28427
|
log.info(
|
|
28358
28428
|
"beads",
|
|
28359
|
-
`provision done dolt=${result.doltAvailable} server=${result.serverUp} prefix=${result.prefix} initialized=${result.initialized} export=${result.exportEnabled} agentsWired=[${result.agentsWired.join(",")}]`
|
|
28429
|
+
`provision done dolt=${result.doltAvailable} server=${result.serverUp} prefix=${result.prefix} initialized=${result.initialized} schema=${describeSchemaMigrate(result.schemaMigrate)} export=${result.exportEnabled} agentsWired=[${result.agentsWired.join(",")}]`
|
|
28360
28430
|
);
|
|
28361
28431
|
return result;
|
|
28362
28432
|
}
|
|
28433
|
+
async function migrateSchemaSafely(bd) {
|
|
28434
|
+
try {
|
|
28435
|
+
return await migrateSchema(bd);
|
|
28436
|
+
} catch (err) {
|
|
28437
|
+
log.warn("beads", "bd migrate schema threw (non-fatal)", err);
|
|
28438
|
+
return { status: "failed", detail: err.message };
|
|
28439
|
+
}
|
|
28440
|
+
}
|
|
28441
|
+
function describeSchemaMigrate(outcome) {
|
|
28442
|
+
if (!outcome) return "skipped";
|
|
28443
|
+
if (outcome.status === "applied") {
|
|
28444
|
+
return `applied:${outcome.count}${outcome.forced ? ":forced" : ""}`;
|
|
28445
|
+
}
|
|
28446
|
+
return outcome.status;
|
|
28447
|
+
}
|
|
28363
28448
|
async function projectDbReachable(bd) {
|
|
28364
28449
|
const ping = await bd.run(["ping"]);
|
|
28365
28450
|
return ping.code === 0;
|
|
@@ -28455,6 +28540,8 @@ var BeadsWatcher = class {
|
|
|
28455
28540
|
debounceTimer = null;
|
|
28456
28541
|
stopped = false;
|
|
28457
28542
|
lastPushedHash = null;
|
|
28543
|
+
/** One schema-heal attempt per watcher — a failing migrate must not loop. */
|
|
28544
|
+
schemaHealTried = false;
|
|
28458
28545
|
bd;
|
|
28459
28546
|
feedPath;
|
|
28460
28547
|
apiBase;
|
|
@@ -28523,10 +28610,15 @@ var BeadsWatcher = class {
|
|
|
28523
28610
|
async syncNow() {
|
|
28524
28611
|
if (this.stopped) return;
|
|
28525
28612
|
const { projectKey, projectLabel } = deriveProjectIdentity(this.opts.cwd);
|
|
28526
|
-
|
|
28527
|
-
|
|
28528
|
-
this.
|
|
28529
|
-
|
|
28613
|
+
let [issues, summary] = await this.readSnapshot(projectKey);
|
|
28614
|
+
if (!this.schemaHealTried && this.bd.takeSchemaSkew()) {
|
|
28615
|
+
this.schemaHealTried = true;
|
|
28616
|
+
log.info("beads", "snapshot hit schema skew \u2014 running bd migrate schema once");
|
|
28617
|
+
const outcome = await migrateSchema(this.bd);
|
|
28618
|
+
if (outcome.status !== "failed") {
|
|
28619
|
+
[issues, summary] = await this.readSnapshot(projectKey);
|
|
28620
|
+
}
|
|
28621
|
+
}
|
|
28530
28622
|
const payload = {
|
|
28531
28623
|
sessionId: this.opts.sessionId,
|
|
28532
28624
|
pluginId: this.opts.pluginId,
|
|
@@ -28565,6 +28657,9 @@ var BeadsWatcher = class {
|
|
|
28565
28657
|
log.warn("beads", "ingest POST error", err);
|
|
28566
28658
|
}
|
|
28567
28659
|
}
|
|
28660
|
+
readSnapshot(projectKey) {
|
|
28661
|
+
return Promise.all([this.bd.listIssues(projectKey), this.bd.statusSummary()]);
|
|
28662
|
+
}
|
|
28568
28663
|
headers() {
|
|
28569
28664
|
return {
|
|
28570
28665
|
"Content-Type": "application/json",
|
|
@@ -31765,6 +31860,7 @@ function isLocalSession(env = process.env) {
|
|
|
31765
31860
|
|
|
31766
31861
|
// src/agents/acp/adapters.ts
|
|
31767
31862
|
var require_ = require;
|
|
31863
|
+
var OPENCODE_FATAL_TURN_STDERR_RE = /message="stream error".*error\.error="[^"]*(Free usage limit reached|insufficient[_ ]quota|invalid[_ ]api[_ ]key|incorrect api key|unauthorized)/i;
|
|
31768
31864
|
function claudeBinaryWaiter(opts = {}) {
|
|
31769
31865
|
return waitForClaudeNativeBinary(opts).then((p2) => p2 !== null);
|
|
31770
31866
|
}
|
|
@@ -31924,8 +32020,12 @@ var REGISTRY = {
|
|
|
31924
32020
|
// the ACP client spawns the adapter with `env: { ...process.env, ...extraEnv }`.
|
|
31925
32021
|
opencode: () => ({
|
|
31926
32022
|
command: "opencode",
|
|
31927
|
-
|
|
32023
|
+
// `--print-logs --log-level ERROR`: opencode writes its provider errors only
|
|
32024
|
+
// to its own log file, so without these flags they never reach the adapter
|
|
32025
|
+
// stderr we read (see OPENCODE_FATAL_TURN_STDERR_RE).
|
|
32026
|
+
args: ["acp", "--print-logs", "--log-level", "ERROR"],
|
|
31928
32027
|
requiresAgentBinary: "opencode",
|
|
32028
|
+
fatalTurnStderr: OPENCODE_FATAL_TURN_STDERR_RE,
|
|
31929
32029
|
waitForBinary: async (o) => {
|
|
31930
32030
|
if (isLocalSession()) await ensureOpencodeInstalled();
|
|
31931
32031
|
augmentOpencodePath();
|
|
@@ -37052,6 +37152,9 @@ var _acpStartSeam = {
|
|
|
37052
37152
|
var PROTOCOL_VERSION3 = 1;
|
|
37053
37153
|
var FATAL_STARTUP_RE = /IneligibleTierError|UNSUPPORTED_CLIENT|no longer supported for Gemini Code Assist|not eligible for Gemini Code Assist|Error authenticating|ProjectIdRequiredError/i;
|
|
37054
37154
|
var NEWSESSION_TIMEOUT_MS = 12e4;
|
|
37155
|
+
function agentErrorOf(line) {
|
|
37156
|
+
return /error\.error="([^"]+)"/.exec(line)?.[1] ?? line;
|
|
37157
|
+
}
|
|
37055
37158
|
var MCP_STARTUP_TIMEOUT_MS = NEWSESSION_TIMEOUT_MS - 3e4;
|
|
37056
37159
|
var AGENT_ENV_WITHHELD = ["PREVIEW_TUNNEL_TOKEN", "PREVIEW_TUNNEL_HOSTNAME"];
|
|
37057
37160
|
var LOADSESSION_TIMEOUT_MS = 6e4;
|
|
@@ -37157,6 +37260,12 @@ var AcpClient = class {
|
|
|
37157
37260
|
* engages; with it, the crash rejects immediately → retry respawns once the
|
|
37158
37261
|
* install settles. Broader than {@link startupFailureReject} (newSession-only). */
|
|
37159
37262
|
startAbortReject = null;
|
|
37263
|
+
/** The adapter's {@link AdapterSpec.fatalTurnStderr}, set at spawn. */
|
|
37264
|
+
fatalTurnStderr = null;
|
|
37265
|
+
/** Set while a `session/prompt` is in flight; the stderr watcher calls it on
|
|
37266
|
+
* a {@link fatalTurnStderr} line to end the turn now (opencode keeps a turn
|
|
37267
|
+
* open forever after a terminal provider error — see the adapter spec). */
|
|
37268
|
+
turnFailureReject = null;
|
|
37160
37269
|
/**
|
|
37161
37270
|
* Spawn the adapter + handshake, retrying a TRANSIENT in-adapter spawn race.
|
|
37162
37271
|
*
|
|
@@ -37245,6 +37354,7 @@ var AcpClient = class {
|
|
|
37245
37354
|
"acpClient",
|
|
37246
37355
|
`provider routing ${formatProviderRouting(describeProviderRouting(childEnv, { cwd }), adapter.command)}`
|
|
37247
37356
|
);
|
|
37357
|
+
this.fatalTurnStderr = adapter.fatalTurnStderr ?? null;
|
|
37248
37358
|
const child = (0, import_node_child_process28.spawn)(adapter.command, adapter.args, {
|
|
37249
37359
|
cwd,
|
|
37250
37360
|
env: childEnv,
|
|
@@ -37270,16 +37380,7 @@ var AcpClient = class {
|
|
|
37270
37380
|
child.stderr?.on("data", (chunk) => {
|
|
37271
37381
|
for (const line of chunk.split(/\r?\n/)) {
|
|
37272
37382
|
const trimmed = line.trim();
|
|
37273
|
-
if (trimmed)
|
|
37274
|
-
log.info("acpAdapter", trimmed);
|
|
37275
|
-
this.opts.onStderr?.(trimmed);
|
|
37276
|
-
this.recentStderr.push(trimmed);
|
|
37277
|
-
if (this.recentStderr.length > 12) this.recentStderr.shift();
|
|
37278
|
-
if (this.startupFailureReject && FATAL_STARTUP_RE.test(trimmed)) {
|
|
37279
|
-
this.startupFailureReject(new Error(`AGENT_STARTUP_FAILED: ${trimmed}`));
|
|
37280
|
-
this.startupFailureReject = null;
|
|
37281
|
-
}
|
|
37282
|
-
}
|
|
37383
|
+
if (trimmed) this.onAdapterStderrLine(trimmed);
|
|
37283
37384
|
}
|
|
37284
37385
|
});
|
|
37285
37386
|
child.on("exit", (code, signal) => {
|
|
@@ -37479,9 +37580,16 @@ var AcpClient = class {
|
|
|
37479
37580
|
PROMPT_ACTIVE_IDLE_TIMEOUT_MS
|
|
37480
37581
|
);
|
|
37481
37582
|
this.promptIdle = idle;
|
|
37583
|
+
let fatalTripped = false;
|
|
37584
|
+
const fatal = new Promise((_2, reject) => {
|
|
37585
|
+
this.turnFailureReject = (err) => {
|
|
37586
|
+
fatalTripped = true;
|
|
37587
|
+
reject(err);
|
|
37588
|
+
};
|
|
37589
|
+
});
|
|
37482
37590
|
this.pendingToolCalls.clear();
|
|
37483
37591
|
try {
|
|
37484
|
-
const result = await Promise.race([send, idle.promise]);
|
|
37592
|
+
const result = await Promise.race([send, idle.promise, fatal]);
|
|
37485
37593
|
await new Promise((resolve13) => setImmediate(resolve13));
|
|
37486
37594
|
log.info(
|
|
37487
37595
|
"acpClient",
|
|
@@ -37495,15 +37603,32 @@ var AcpClient = class {
|
|
|
37495
37603
|
"acpClient",
|
|
37496
37604
|
`prompt \u2190 failed elapsedMs=${Date.now() - t0} err=${err instanceof Error ? err.message : String(err)}`
|
|
37497
37605
|
);
|
|
37498
|
-
if (idleTripped) await this.cancelAbandonedTurn(sessionId, send);
|
|
37606
|
+
if (idleTripped || fatalTripped) await this.cancelAbandonedTurn(sessionId, send);
|
|
37499
37607
|
throw err;
|
|
37500
37608
|
} finally {
|
|
37501
37609
|
idle.clear();
|
|
37502
37610
|
this.promptIdle = null;
|
|
37611
|
+
this.turnFailureReject = null;
|
|
37612
|
+
}
|
|
37613
|
+
}
|
|
37614
|
+
/** One non-empty adapter stderr line: logged, kept in the ring, and checked
|
|
37615
|
+
* for the fatal startup / fatal turn errors that end a stuck RPC early. */
|
|
37616
|
+
onAdapterStderrLine(trimmed) {
|
|
37617
|
+
log.info("acpAdapter", trimmed);
|
|
37618
|
+
this.opts.onStderr?.(trimmed);
|
|
37619
|
+
this.recentStderr.push(trimmed);
|
|
37620
|
+
if (this.recentStderr.length > 12) this.recentStderr.shift();
|
|
37621
|
+
if (this.startupFailureReject && FATAL_STARTUP_RE.test(trimmed)) {
|
|
37622
|
+
this.startupFailureReject(new Error(`AGENT_STARTUP_FAILED: ${trimmed}`));
|
|
37623
|
+
this.startupFailureReject = null;
|
|
37624
|
+
}
|
|
37625
|
+
if (this.turnFailureReject && this.fatalTurnStderr?.test(trimmed)) {
|
|
37626
|
+
this.turnFailureReject(new Error(`AGENT_TURN_FAILED: ${agentErrorOf(trimmed)}`));
|
|
37627
|
+
this.turnFailureReject = null;
|
|
37503
37628
|
}
|
|
37504
37629
|
}
|
|
37505
37630
|
/**
|
|
37506
|
-
* Cancel a turn the idle watchdog abandoned and wait, bounded, for the
|
|
37631
|
+
* Cancel a turn the idle watchdog (or a fatal stderr error) abandoned and wait, bounded, for the
|
|
37507
37632
|
* adapter to answer its `session/prompt` — the proof the turn is over before
|
|
37508
37633
|
* the next prompt is sent. Best-effort: a dead adapter can't hold the queue
|
|
37509
37634
|
* longer than {@link ABANDONED_TURN_SETTLE_MS}.
|
|
@@ -43598,7 +43723,7 @@ async function runStartTaskTurn(ctx, payload, blocks, promptText) {
|
|
|
43598
43723
|
reportTurn2(
|
|
43599
43724
|
ctx,
|
|
43600
43725
|
"failed",
|
|
43601
|
-
bubble === AUTH_FAILURE_MESSAGE ? "AUTH_FAILED" : bubble === ONE_M_CREDITS_MESSAGE ? "ONE_M_CREDITS" : failed.partialReplyKept ? "TURN_ERROR_PARTIAL" : "TURN_ERROR"
|
|
43726
|
+
bubble === AUTH_FAILURE_MESSAGE ? "AUTH_FAILED" : bubble === ONE_M_CREDITS_MESSAGE ? "ONE_M_CREDITS" : bubble === AGENT_FREE_LIMIT_MESSAGE ? "AGENT_FREE_LIMIT" : failed.partialReplyKept ? "TURN_ERROR_PARTIAL" : "TURN_ERROR"
|
|
43602
43727
|
);
|
|
43603
43728
|
if (bubble === AUTH_FAILURE_MESSAGE || bubble === ONE_M_CREDITS_MESSAGE) {
|
|
43604
43729
|
void reportCredentialInvalid(opts);
|
|
@@ -51542,7 +51667,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
51542
51667
|
if (process.env.NODE_ENV === "test") return;
|
|
51543
51668
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
51544
51669
|
if (process.env.CI) return;
|
|
51545
|
-
const current2 = true ? "2.76.
|
|
51670
|
+
const current2 = true ? "2.76.35" : null;
|
|
51546
51671
|
if (!current2) return;
|
|
51547
51672
|
const cache = readCache();
|
|
51548
51673
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -51559,7 +51684,7 @@ function checkForUpdates() {
|
|
|
51559
51684
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
51560
51685
|
if (process.env.CI) return;
|
|
51561
51686
|
if (!process.stdout.isTTY) return;
|
|
51562
|
-
const current2 = true ? "2.76.
|
|
51687
|
+
const current2 = true ? "2.76.35" : null;
|
|
51563
51688
|
if (!current2) return;
|
|
51564
51689
|
const cache = readCache();
|
|
51565
51690
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -51735,14 +51860,37 @@ function pidAlive3(pid) {
|
|
|
51735
51860
|
return err.code === "EPERM";
|
|
51736
51861
|
}
|
|
51737
51862
|
}
|
|
51863
|
+
var CLK_TCK = 100;
|
|
51864
|
+
function processStartMs(pid) {
|
|
51865
|
+
try {
|
|
51866
|
+
const stat3 = fs96.readFileSync(`/proc/${pid}/stat`, "utf8");
|
|
51867
|
+
const ticks = Number(stat3.slice(stat3.lastIndexOf(")") + 2).split(" ")[19]);
|
|
51868
|
+
const btime = /^btime (\d+)$/m.exec(fs96.readFileSync("/proc/stat", "utf8"))?.[1];
|
|
51869
|
+
if (!Number.isFinite(ticks) || !btime) return null;
|
|
51870
|
+
return Number(btime) * 1e3 + ticks * 1e3 / CLK_TCK;
|
|
51871
|
+
} catch {
|
|
51872
|
+
return null;
|
|
51873
|
+
}
|
|
51874
|
+
}
|
|
51875
|
+
var PID_REUSE_SLACK_MS = 2e3;
|
|
51738
51876
|
function livePids(versionDir) {
|
|
51877
|
+
const dir = path109.join(versionDir, ".pids");
|
|
51739
51878
|
let names;
|
|
51740
51879
|
try {
|
|
51741
|
-
names = fs96.readdirSync(
|
|
51880
|
+
names = fs96.readdirSync(dir);
|
|
51742
51881
|
} catch {
|
|
51743
51882
|
return [];
|
|
51744
51883
|
}
|
|
51745
|
-
return names.map(Number).filter((pid) =>
|
|
51884
|
+
return names.map(Number).filter((pid) => {
|
|
51885
|
+
if (!Number.isInteger(pid) || pid <= 0 || !pidAlive3(pid)) return false;
|
|
51886
|
+
const started = processStartMs(pid);
|
|
51887
|
+
if (started === null) return true;
|
|
51888
|
+
try {
|
|
51889
|
+
return started <= fs96.statSync(path109.join(dir, String(pid))).mtimeMs + PID_REUSE_SLACK_MS;
|
|
51890
|
+
} catch {
|
|
51891
|
+
return true;
|
|
51892
|
+
}
|
|
51893
|
+
});
|
|
51746
51894
|
}
|
|
51747
51895
|
function registerRunningVersion(root = cliVersionsRoot(), entry = process.argv[1]) {
|
|
51748
51896
|
const dir = versionDirContaining(root, entry);
|
|
@@ -51842,7 +51990,7 @@ var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
|
51842
51990
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
51843
51991
|
var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
|
|
51844
51992
|
function currentCliVersion() {
|
|
51845
|
-
return true ? "2.76.
|
|
51993
|
+
return true ? "2.76.35" : null;
|
|
51846
51994
|
}
|
|
51847
51995
|
async function installedVersion(deps) {
|
|
51848
51996
|
const ls = await deps.run(
|
|
@@ -51927,6 +52075,7 @@ async function runSelfUpdateWith(deps) {
|
|
|
51927
52075
|
}
|
|
51928
52076
|
if (compareSemver(latest, current2) <= 0) {
|
|
51929
52077
|
log.info("host-agent", `self-update: running ${current2}, npm latest ${latest} \u2014 up to date`);
|
|
52078
|
+
if (versionedModeSupported(deps.platform)) collectOldVersions(root);
|
|
51930
52079
|
return { status: "current" };
|
|
51931
52080
|
}
|
|
51932
52081
|
if (!versionedModeSupported(deps.platform)) {
|
|
@@ -51943,6 +52092,17 @@ async function runSelfUpdateWith(deps) {
|
|
|
51943
52092
|
return { status: "skipped" };
|
|
51944
52093
|
}
|
|
51945
52094
|
}
|
|
52095
|
+
function collectOldVersions(root) {
|
|
52096
|
+
const release3 = acquireInstallLock(root);
|
|
52097
|
+
if (!release3) return [];
|
|
52098
|
+
try {
|
|
52099
|
+
const removed = gcVersions(root);
|
|
52100
|
+
if (removed.length) log.info("host-agent", `self-update: gc removed ${removed.join(", ")}`);
|
|
52101
|
+
return removed;
|
|
52102
|
+
} finally {
|
|
52103
|
+
release3();
|
|
52104
|
+
}
|
|
52105
|
+
}
|
|
51946
52106
|
var VERIFY_TIMEOUT_MS = 3e4;
|
|
51947
52107
|
async function installVersioned(deps, root, latest, running2) {
|
|
51948
52108
|
const node = deps.nodePath ?? process.execPath;
|
|
@@ -52053,7 +52213,7 @@ function signalHostReady(send = process.send?.bind(process)) {
|
|
|
52053
52213
|
}
|
|
52054
52214
|
function defaultDeps() {
|
|
52055
52215
|
return {
|
|
52056
|
-
ownVersion: true ? "2.76.
|
|
52216
|
+
ownVersion: true ? "2.76.35" : null,
|
|
52057
52217
|
root: cliVersionsRoot(),
|
|
52058
52218
|
args: process.argv.slice(3),
|
|
52059
52219
|
execPath: process.execPath,
|
|
@@ -54591,7 +54751,7 @@ function checkChokidar() {
|
|
|
54591
54751
|
}
|
|
54592
54752
|
async function doctor(args2 = []) {
|
|
54593
54753
|
const json = args2.includes("--json");
|
|
54594
|
-
const cliVersion = true ? "2.76.
|
|
54754
|
+
const cliVersion = true ? "2.76.35" : "0.0.0-dev";
|
|
54595
54755
|
const apiBase2 = resolveApiBaseUrl();
|
|
54596
54756
|
const diagnosticId = (0, import_node_crypto17.randomUUID)();
|
|
54597
54757
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -55127,7 +55287,7 @@ async function mcpWarm(argv = [], opts = {}) {
|
|
|
55127
55287
|
// src/commands/version.ts
|
|
55128
55288
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
55129
55289
|
function version2() {
|
|
55130
|
-
const v = true ? "2.76.
|
|
55290
|
+
const v = true ? "2.76.35" : "unknown";
|
|
55131
55291
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
55132
55292
|
}
|
|
55133
55293
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.76.
|
|
3
|
+
"version": "2.76.35",
|
|
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",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"zod": "^4.3.6"
|
|
89
89
|
},
|
|
90
90
|
"optionalDependencies": {
|
|
91
|
-
"@beads/bd": "1.
|
|
91
|
+
"@beads/bd": "1.3.1"
|
|
92
92
|
},
|
|
93
93
|
"devDependencies": {
|
|
94
94
|
"@codeam/shared": "*",
|