codeam-cli 2.65.7 → 2.65.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 +7 -0
- package/dist/index.js +78 -19
- 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.8" : "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.8",
|
|
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.8" ? { ideVersion: "2.65.8" } : {}
|
|
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.8" : 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.8" : 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.8" : null;
|
|
21708
21731
|
}
|
|
21709
21732
|
function runCmd(cmd, args2, timeoutMs) {
|
|
21710
21733
|
return new Promise((resolve9) => {
|
|
@@ -41009,6 +41032,17 @@ var BatonController = class {
|
|
|
41009
41032
|
get conversationId() {
|
|
41010
41033
|
return this._conversationId;
|
|
41011
41034
|
}
|
|
41035
|
+
/** The exact triple the last `publishState` emitted — the CLI's current view
|
|
41036
|
+
* of who holds the baton. Read by the heartbeat re-affirmation rider
|
|
41037
|
+
* ({@link makeBatonHeartbeatReaffirm}), which re-posts it periodically so the
|
|
41038
|
+
* backend's 1 h Redis snapshot never expires under a live session. */
|
|
41039
|
+
currentState() {
|
|
41040
|
+
return {
|
|
41041
|
+
state: this._state,
|
|
41042
|
+
driver: this._active,
|
|
41043
|
+
conversationId: this._conversationId
|
|
41044
|
+
};
|
|
41045
|
+
}
|
|
41012
41046
|
async begin() {
|
|
41013
41047
|
this._conversationId = await this.deps.local.start(void 0);
|
|
41014
41048
|
this._active = "local_tui";
|
|
@@ -41484,6 +41518,21 @@ function makeSerializedBatonPoster(post2) {
|
|
|
41484
41518
|
void chain;
|
|
41485
41519
|
};
|
|
41486
41520
|
}
|
|
41521
|
+
var BATON_REAFFIRM_INTERVAL_MS = 5 * 6e4;
|
|
41522
|
+
function makeBatonHeartbeatReaffirm(deps) {
|
|
41523
|
+
const now = deps.now ?? Date.now;
|
|
41524
|
+
const intervalMs = deps.intervalMs ?? BATON_REAFFIRM_INTERVAL_MS;
|
|
41525
|
+
let lastAffirmedAt = null;
|
|
41526
|
+
return ({ firstAfterConnect }) => {
|
|
41527
|
+
const current2 = deps.currentState();
|
|
41528
|
+
if (!current2) return;
|
|
41529
|
+
if (current2.state === "SWITCHING") return;
|
|
41530
|
+
const at3 = now();
|
|
41531
|
+
if (!firstAfterConnect && lastAffirmedAt !== null && at3 - lastAffirmedAt < intervalMs) return;
|
|
41532
|
+
lastAffirmedAt = at3;
|
|
41533
|
+
deps.publish(current2.state, current2.driver, current2.conversationId);
|
|
41534
|
+
};
|
|
41535
|
+
}
|
|
41487
41536
|
async function runBatonSession(opts) {
|
|
41488
41537
|
const publisher = new AcpPublisher({
|
|
41489
41538
|
sessionId: opts.sessionId,
|
|
@@ -41595,18 +41644,21 @@ async function runBatonSession(opts) {
|
|
|
41595
41644
|
mirror.start();
|
|
41596
41645
|
};
|
|
41597
41646
|
const postBatonState = makeSerializedBatonPoster(postBatonEvent);
|
|
41647
|
+
const publishBatonState = (state, driver, conversationId) => {
|
|
41648
|
+
postBatonState({
|
|
41649
|
+
sessionId: opts.sessionId,
|
|
41650
|
+
pluginId: opts.pluginId,
|
|
41651
|
+
pluginAuthToken: opts.pluginAuthToken,
|
|
41652
|
+
state,
|
|
41653
|
+
driver,
|
|
41654
|
+
conversationId
|
|
41655
|
+
});
|
|
41656
|
+
};
|
|
41598
41657
|
const controller = new BatonController({
|
|
41599
41658
|
local: nativeDriver,
|
|
41600
41659
|
mobile: mobileDriver,
|
|
41601
41660
|
publishState: (state, driver, conversationId) => {
|
|
41602
|
-
|
|
41603
|
-
sessionId: opts.sessionId,
|
|
41604
|
-
pluginId: opts.pluginId,
|
|
41605
|
-
pluginAuthToken: opts.pluginAuthToken,
|
|
41606
|
-
state,
|
|
41607
|
-
driver,
|
|
41608
|
-
conversationId
|
|
41609
|
-
});
|
|
41661
|
+
publishBatonState(state, driver, conversationId);
|
|
41610
41662
|
if (state === "LOCAL_DRIVE" && conversationId) {
|
|
41611
41663
|
startMirror(conversationId, firstLocalDrive);
|
|
41612
41664
|
firstLocalDrive = false;
|
|
@@ -41616,6 +41668,7 @@ async function runBatonSession(opts) {
|
|
|
41616
41668
|
}
|
|
41617
41669
|
});
|
|
41618
41670
|
const dispatchActive = (cmd) => controller.activeSessionDriver.dispatch(cmd);
|
|
41671
|
+
let torn = false;
|
|
41619
41672
|
relay = new CommandRelayService(
|
|
41620
41673
|
opts.pluginId,
|
|
41621
41674
|
makeOnCommand({
|
|
@@ -41623,9 +41676,15 @@ async function runBatonSession(opts) {
|
|
|
41623
41676
|
dispatchActive,
|
|
41624
41677
|
ack: (id, status2, result) => relay.sendResult(id, status2, result)
|
|
41625
41678
|
}),
|
|
41626
|
-
runtime.meta
|
|
41679
|
+
runtime.meta,
|
|
41680
|
+
void 0,
|
|
41681
|
+
void 0,
|
|
41682
|
+
makeBatonHeartbeatReaffirm({
|
|
41683
|
+
// Nothing to affirm once the session is torn down.
|
|
41684
|
+
currentState: () => torn ? null : controller.currentState(),
|
|
41685
|
+
publish: publishBatonState
|
|
41686
|
+
})
|
|
41627
41687
|
);
|
|
41628
|
-
let torn = false;
|
|
41629
41688
|
function teardown() {
|
|
41630
41689
|
if (torn) return;
|
|
41631
41690
|
torn = true;
|
|
@@ -44678,7 +44737,7 @@ function checkChokidar() {
|
|
|
44678
44737
|
}
|
|
44679
44738
|
async function doctor(args2 = []) {
|
|
44680
44739
|
const json = args2.includes("--json");
|
|
44681
|
-
const cliVersion = true ? "2.65.
|
|
44740
|
+
const cliVersion = true ? "2.65.8" : "0.0.0-dev";
|
|
44682
44741
|
const apiBase2 = resolveApiBaseUrl();
|
|
44683
44742
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
44684
44743
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -45069,7 +45128,7 @@ async function mcpRun(args2) {
|
|
|
45069
45128
|
// src/commands/version.ts
|
|
45070
45129
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
45071
45130
|
function version2() {
|
|
45072
|
-
const v = true ? "2.65.
|
|
45131
|
+
const v = true ? "2.65.8" : "unknown";
|
|
45073
45132
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
45074
45133
|
}
|
|
45075
45134
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.65.
|
|
3
|
+
"version": "2.65.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",
|