codeam-cli 2.65.7 → 2.65.9
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 +109 -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.65.7] — 2026-08-15
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Honest credential/empty-turn errors + partial-fence holdback
|
|
12
|
+
- **cli:** Credential error propagation matches the real transport error shape
|
|
13
|
+
|
|
7
14
|
## [2.65.6] — 2026-08-15
|
|
8
15
|
|
|
9
16
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -8079,7 +8079,7 @@ function readAnonId() {
|
|
|
8079
8079
|
}
|
|
8080
8080
|
function superProperties() {
|
|
8081
8081
|
return {
|
|
8082
|
-
cliVersion: true ? "2.65.
|
|
8082
|
+
cliVersion: true ? "2.65.9" : "0.0.0-dev",
|
|
8083
8083
|
nodeVersion: process.version,
|
|
8084
8084
|
platform: process.platform,
|
|
8085
8085
|
arch: process.arch,
|
|
@@ -8260,7 +8260,7 @@ var os4 = __toESM(require("os"));
|
|
|
8260
8260
|
// package.json
|
|
8261
8261
|
var package_default = {
|
|
8262
8262
|
name: "codeam-cli",
|
|
8263
|
-
version: "2.65.
|
|
8263
|
+
version: "2.65.9",
|
|
8264
8264
|
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.",
|
|
8265
8265
|
type: "commonjs",
|
|
8266
8266
|
main: "dist/index.js",
|
|
@@ -9358,18 +9358,20 @@ var API_BASE2 = resolveApiBaseUrl();
|
|
|
9358
9358
|
var SSE_LIVENESS_TIMEOUT_MS = 45e3;
|
|
9359
9359
|
var SSE_WATCHDOG_INTERVAL_MS = 1e4;
|
|
9360
9360
|
var CommandRelayService = class _CommandRelayService {
|
|
9361
|
-
constructor(pluginId, onCommand, agentMeta, agentsOverride, explicitPollSecret) {
|
|
9361
|
+
constructor(pluginId, onCommand, agentMeta, agentsOverride, explicitPollSecret, onHeartbeat) {
|
|
9362
9362
|
this.pluginId = pluginId;
|
|
9363
9363
|
this.onCommand = onCommand;
|
|
9364
9364
|
this.agentMeta = agentMeta;
|
|
9365
9365
|
this.agentsOverride = agentsOverride;
|
|
9366
9366
|
this.explicitPollSecret = explicitPollSecret;
|
|
9367
|
+
this.onHeartbeat = onHeartbeat;
|
|
9367
9368
|
}
|
|
9368
9369
|
pluginId;
|
|
9369
9370
|
onCommand;
|
|
9370
9371
|
agentMeta;
|
|
9371
9372
|
agentsOverride;
|
|
9372
9373
|
explicitPollSecret;
|
|
9374
|
+
onHeartbeat;
|
|
9373
9375
|
_running = false;
|
|
9374
9376
|
pairingInvalid = false;
|
|
9375
9377
|
heartbeatTimer = null;
|
|
@@ -9432,16 +9434,35 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9432
9434
|
* freshness, and a punctual heartbeat matters far more.
|
|
9433
9435
|
*/
|
|
9434
9436
|
cachedBranch = null;
|
|
9437
|
+
/**
|
|
9438
|
+
* Set whenever the command channel is (re-)established; consumed by the
|
|
9439
|
+
* next {@link emitHeartbeatTick}. See the `onHeartbeat` ctor param.
|
|
9440
|
+
*/
|
|
9441
|
+
heartbeatFirstAfterConnect = true;
|
|
9442
|
+
/** Invoke the heartbeat rider (if any) exactly once per beat. Never throws. */
|
|
9443
|
+
emitHeartbeatTick() {
|
|
9444
|
+
if (!this.onHeartbeat) return;
|
|
9445
|
+
const firstAfterConnect = this.heartbeatFirstAfterConnect;
|
|
9446
|
+
this.heartbeatFirstAfterConnect = false;
|
|
9447
|
+
try {
|
|
9448
|
+
this.onHeartbeat({ firstAfterConnect });
|
|
9449
|
+
} catch (err) {
|
|
9450
|
+
log.trace("relay", "heartbeat rider threw (ignored)", err);
|
|
9451
|
+
}
|
|
9452
|
+
}
|
|
9435
9453
|
start() {
|
|
9436
9454
|
this.cleanup();
|
|
9437
9455
|
this._running = true;
|
|
9456
|
+
this.heartbeatFirstAfterConnect = true;
|
|
9438
9457
|
this.agentsRegistered = false;
|
|
9439
9458
|
log.info("relay", `start pluginId=${this.pluginId.slice(0, 8)} agent=${this.agentMeta.id}`);
|
|
9440
9459
|
this.cachedBranch = detectCurrentBranch();
|
|
9441
9460
|
this.sendHeartbeat(true);
|
|
9461
|
+
this.emitHeartbeatTick();
|
|
9442
9462
|
this.heartbeatTimer = setInterval(() => {
|
|
9443
9463
|
void this.refreshBranch();
|
|
9444
9464
|
this.sendHeartbeat(true);
|
|
9465
|
+
this.emitHeartbeatTick();
|
|
9445
9466
|
}, 2e4);
|
|
9446
9467
|
this.agentsTimer = setInterval(() => {
|
|
9447
9468
|
if (this._running && !this.agentsRegistered) this.reportAgents();
|
|
@@ -9525,6 +9546,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9525
9546
|
}
|
|
9526
9547
|
log.info("relay", "sse connected");
|
|
9527
9548
|
this.sseFailures = 0;
|
|
9549
|
+
this.heartbeatFirstAfterConnect = true;
|
|
9528
9550
|
this.armSseWatchdog();
|
|
9529
9551
|
let buffer = "";
|
|
9530
9552
|
res.setEncoding("utf8");
|
|
@@ -9642,6 +9664,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9642
9664
|
// ─── Polling fallback ────────────────────────────────────────────
|
|
9643
9665
|
startPollingFallback() {
|
|
9644
9666
|
if (this.pollTimer) return;
|
|
9667
|
+
this.heartbeatFirstAfterConnect = true;
|
|
9645
9668
|
void this.pollLoop();
|
|
9646
9669
|
}
|
|
9647
9670
|
async pollLoop() {
|
|
@@ -9738,7 +9761,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9738
9761
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
9739
9762
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
9740
9763
|
// pair/reconnect). Older backends ignore the extra field.
|
|
9741
|
-
..."2.65.
|
|
9764
|
+
..."2.65.9" ? { ideVersion: "2.65.9" } : {}
|
|
9742
9765
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
9743
9766
|
}
|
|
9744
9767
|
/**
|
|
@@ -21667,7 +21690,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
21667
21690
|
if (process.env.NODE_ENV === "test") return;
|
|
21668
21691
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21669
21692
|
if (process.env.CI) return;
|
|
21670
|
-
const current2 = true ? "2.65.
|
|
21693
|
+
const current2 = true ? "2.65.9" : null;
|
|
21671
21694
|
if (!current2) return;
|
|
21672
21695
|
const cache = readCache();
|
|
21673
21696
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -21684,7 +21707,7 @@ function checkForUpdates() {
|
|
|
21684
21707
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21685
21708
|
if (process.env.CI) return;
|
|
21686
21709
|
if (!process.stdout.isTTY) return;
|
|
21687
|
-
const current2 = true ? "2.65.
|
|
21710
|
+
const current2 = true ? "2.65.9" : null;
|
|
21688
21711
|
if (!current2) return;
|
|
21689
21712
|
const cache = readCache();
|
|
21690
21713
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -21704,7 +21727,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
21704
21727
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
21705
21728
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
21706
21729
|
function currentCliVersion() {
|
|
21707
|
-
return true ? "2.65.
|
|
21730
|
+
return true ? "2.65.9" : null;
|
|
21708
21731
|
}
|
|
21709
21732
|
function runCmd(cmd, args2, timeoutMs) {
|
|
21710
21733
|
return new Promise((resolve9) => {
|
|
@@ -36690,6 +36713,11 @@ ${tail}` : detail].join(
|
|
|
36690
36713
|
"\n"
|
|
36691
36714
|
);
|
|
36692
36715
|
}
|
|
36716
|
+
function startupCredentialInvalidReason(agent, detail, recentStderr) {
|
|
36717
|
+
const haystack2 = `${detail}
|
|
36718
|
+
${recentStderr}`;
|
|
36719
|
+
return agentHooks(agent)?.classifyStartupFailure?.(haystack2) === "ineligible_tier" ? "ineligible_tier" : null;
|
|
36720
|
+
}
|
|
36693
36721
|
function budgetBubbleMessage(agent, period) {
|
|
36694
36722
|
return `\u{1F4B8} **Headroom budget reached for the ${period} period.**
|
|
36695
36723
|
|
|
@@ -36729,7 +36757,11 @@ function adapterExitMessage(opts) {
|
|
|
36729
36757
|
// src/agents/acp/backend-reports.ts
|
|
36730
36758
|
async function reportCredentialInvalid(opts, fetchImpl = fetch) {
|
|
36731
36759
|
const url2 = `${resolveApiBaseUrl()}/api/plugin/agents/${encodeURIComponent(opts.agent)}/credential-invalid`;
|
|
36732
|
-
const body = JSON.stringify({
|
|
36760
|
+
const body = JSON.stringify({
|
|
36761
|
+
sessionId: opts.sessionId,
|
|
36762
|
+
pluginId: opts.pluginId,
|
|
36763
|
+
...opts.reason ? { reason: opts.reason } : {}
|
|
36764
|
+
});
|
|
36733
36765
|
try {
|
|
36734
36766
|
const makeHeaders = (token) => ({
|
|
36735
36767
|
"Content-Type": "application/json",
|
|
@@ -39308,8 +39340,21 @@ var AcpHistory = class {
|
|
|
39308
39340
|
]);
|
|
39309
39341
|
}
|
|
39310
39342
|
};
|
|
39343
|
+
var _startupCredentialReportGuard = { reported: false };
|
|
39311
39344
|
async function surfaceStartupFailure(opts) {
|
|
39312
39345
|
const msg = startupFailureMessage(opts.agent, opts.detail, opts.recentStderr);
|
|
39346
|
+
const reason = startupCredentialInvalidReason(opts.agent, opts.detail, opts.recentStderr);
|
|
39347
|
+
if (reason !== null && !_startupCredentialReportGuard.reported && opts.sessionId && opts.pluginAuthToken) {
|
|
39348
|
+
_startupCredentialReportGuard.reported = true;
|
|
39349
|
+
void reportCredentialInvalid({
|
|
39350
|
+
agent: opts.agent,
|
|
39351
|
+
sessionId: opts.sessionId,
|
|
39352
|
+
pluginId: opts.pluginId,
|
|
39353
|
+
pluginAuthToken: opts.pluginAuthToken,
|
|
39354
|
+
pollSecret: opts.pollSecret,
|
|
39355
|
+
reason
|
|
39356
|
+
});
|
|
39357
|
+
}
|
|
39313
39358
|
const publish = async () => {
|
|
39314
39359
|
try {
|
|
39315
39360
|
await opts.publisher.publishOutput({ type: "new_turn", done: false });
|
|
@@ -39514,7 +39559,10 @@ async function runAcpSession(opts) {
|
|
|
39514
39559
|
pluginId: opts.pluginId,
|
|
39515
39560
|
detail,
|
|
39516
39561
|
recentStderr: recentStderr.join("\n"),
|
|
39517
|
-
publisher
|
|
39562
|
+
publisher,
|
|
39563
|
+
sessionId: opts.sessionId,
|
|
39564
|
+
pluginAuthToken: opts.pluginAuthToken,
|
|
39565
|
+
pollSecret: opts.pollSecret
|
|
39518
39566
|
});
|
|
39519
39567
|
return;
|
|
39520
39568
|
}
|
|
@@ -41009,6 +41057,17 @@ var BatonController = class {
|
|
|
41009
41057
|
get conversationId() {
|
|
41010
41058
|
return this._conversationId;
|
|
41011
41059
|
}
|
|
41060
|
+
/** The exact triple the last `publishState` emitted — the CLI's current view
|
|
41061
|
+
* of who holds the baton. Read by the heartbeat re-affirmation rider
|
|
41062
|
+
* ({@link makeBatonHeartbeatReaffirm}), which re-posts it periodically so the
|
|
41063
|
+
* backend's 1 h Redis snapshot never expires under a live session. */
|
|
41064
|
+
currentState() {
|
|
41065
|
+
return {
|
|
41066
|
+
state: this._state,
|
|
41067
|
+
driver: this._active,
|
|
41068
|
+
conversationId: this._conversationId
|
|
41069
|
+
};
|
|
41070
|
+
}
|
|
41012
41071
|
async begin() {
|
|
41013
41072
|
this._conversationId = await this.deps.local.start(void 0);
|
|
41014
41073
|
this._active = "local_tui";
|
|
@@ -41484,6 +41543,21 @@ function makeSerializedBatonPoster(post2) {
|
|
|
41484
41543
|
void chain;
|
|
41485
41544
|
};
|
|
41486
41545
|
}
|
|
41546
|
+
var BATON_REAFFIRM_INTERVAL_MS = 5 * 6e4;
|
|
41547
|
+
function makeBatonHeartbeatReaffirm(deps) {
|
|
41548
|
+
const now = deps.now ?? Date.now;
|
|
41549
|
+
const intervalMs = deps.intervalMs ?? BATON_REAFFIRM_INTERVAL_MS;
|
|
41550
|
+
let lastAffirmedAt = null;
|
|
41551
|
+
return ({ firstAfterConnect }) => {
|
|
41552
|
+
const current2 = deps.currentState();
|
|
41553
|
+
if (!current2) return;
|
|
41554
|
+
if (current2.state === "SWITCHING") return;
|
|
41555
|
+
const at3 = now();
|
|
41556
|
+
if (!firstAfterConnect && lastAffirmedAt !== null && at3 - lastAffirmedAt < intervalMs) return;
|
|
41557
|
+
lastAffirmedAt = at3;
|
|
41558
|
+
deps.publish(current2.state, current2.driver, current2.conversationId);
|
|
41559
|
+
};
|
|
41560
|
+
}
|
|
41487
41561
|
async function runBatonSession(opts) {
|
|
41488
41562
|
const publisher = new AcpPublisher({
|
|
41489
41563
|
sessionId: opts.sessionId,
|
|
@@ -41595,18 +41669,21 @@ async function runBatonSession(opts) {
|
|
|
41595
41669
|
mirror.start();
|
|
41596
41670
|
};
|
|
41597
41671
|
const postBatonState = makeSerializedBatonPoster(postBatonEvent);
|
|
41672
|
+
const publishBatonState = (state, driver, conversationId) => {
|
|
41673
|
+
postBatonState({
|
|
41674
|
+
sessionId: opts.sessionId,
|
|
41675
|
+
pluginId: opts.pluginId,
|
|
41676
|
+
pluginAuthToken: opts.pluginAuthToken,
|
|
41677
|
+
state,
|
|
41678
|
+
driver,
|
|
41679
|
+
conversationId
|
|
41680
|
+
});
|
|
41681
|
+
};
|
|
41598
41682
|
const controller = new BatonController({
|
|
41599
41683
|
local: nativeDriver,
|
|
41600
41684
|
mobile: mobileDriver,
|
|
41601
41685
|
publishState: (state, driver, conversationId) => {
|
|
41602
|
-
|
|
41603
|
-
sessionId: opts.sessionId,
|
|
41604
|
-
pluginId: opts.pluginId,
|
|
41605
|
-
pluginAuthToken: opts.pluginAuthToken,
|
|
41606
|
-
state,
|
|
41607
|
-
driver,
|
|
41608
|
-
conversationId
|
|
41609
|
-
});
|
|
41686
|
+
publishBatonState(state, driver, conversationId);
|
|
41610
41687
|
if (state === "LOCAL_DRIVE" && conversationId) {
|
|
41611
41688
|
startMirror(conversationId, firstLocalDrive);
|
|
41612
41689
|
firstLocalDrive = false;
|
|
@@ -41616,6 +41693,7 @@ async function runBatonSession(opts) {
|
|
|
41616
41693
|
}
|
|
41617
41694
|
});
|
|
41618
41695
|
const dispatchActive = (cmd) => controller.activeSessionDriver.dispatch(cmd);
|
|
41696
|
+
let torn = false;
|
|
41619
41697
|
relay = new CommandRelayService(
|
|
41620
41698
|
opts.pluginId,
|
|
41621
41699
|
makeOnCommand({
|
|
@@ -41623,9 +41701,15 @@ async function runBatonSession(opts) {
|
|
|
41623
41701
|
dispatchActive,
|
|
41624
41702
|
ack: (id, status2, result) => relay.sendResult(id, status2, result)
|
|
41625
41703
|
}),
|
|
41626
|
-
runtime.meta
|
|
41704
|
+
runtime.meta,
|
|
41705
|
+
void 0,
|
|
41706
|
+
void 0,
|
|
41707
|
+
makeBatonHeartbeatReaffirm({
|
|
41708
|
+
// Nothing to affirm once the session is torn down.
|
|
41709
|
+
currentState: () => torn ? null : controller.currentState(),
|
|
41710
|
+
publish: publishBatonState
|
|
41711
|
+
})
|
|
41627
41712
|
);
|
|
41628
|
-
let torn = false;
|
|
41629
41713
|
function teardown() {
|
|
41630
41714
|
if (torn) return;
|
|
41631
41715
|
torn = true;
|
|
@@ -41922,7 +42006,10 @@ async function start(requestedAgent, presetSession) {
|
|
|
41922
42006
|
pluginId,
|
|
41923
42007
|
pluginAuthToken: session.pluginAuthToken,
|
|
41924
42008
|
refreshAuthToken: () => fetchCurrentPluginAuthToken(session.id, pluginId, session.pollSecret)
|
|
41925
|
-
})
|
|
42009
|
+
}),
|
|
42010
|
+
sessionId: session.id,
|
|
42011
|
+
pluginAuthToken: session.pluginAuthToken,
|
|
42012
|
+
pollSecret: session.pollSecret
|
|
41926
42013
|
});
|
|
41927
42014
|
return;
|
|
41928
42015
|
}
|
|
@@ -44678,7 +44765,7 @@ function checkChokidar() {
|
|
|
44678
44765
|
}
|
|
44679
44766
|
async function doctor(args2 = []) {
|
|
44680
44767
|
const json = args2.includes("--json");
|
|
44681
|
-
const cliVersion = true ? "2.65.
|
|
44768
|
+
const cliVersion = true ? "2.65.9" : "0.0.0-dev";
|
|
44682
44769
|
const apiBase2 = resolveApiBaseUrl();
|
|
44683
44770
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
44684
44771
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -45069,7 +45156,7 @@ async function mcpRun(args2) {
|
|
|
45069
45156
|
// src/commands/version.ts
|
|
45070
45157
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
45071
45158
|
function version2() {
|
|
45072
|
-
const v = true ? "2.65.
|
|
45159
|
+
const v = true ? "2.65.9" : "unknown";
|
|
45073
45160
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
45074
45161
|
}
|
|
45075
45162
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.65.
|
|
3
|
+
"version": "2.65.9",
|
|
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",
|