codeam-cli 2.75.7 → 2.75.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 +100 -16
- 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.75.7] — 2026-09-19
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Strip the retired Headroom proxy from ~/.claude/settings.json on start
|
|
12
|
+
- **cli:** Log.info takes (tag, msg) — caught by CI typecheck
|
|
13
|
+
|
|
7
14
|
## [2.75.6] — 2026-09-17
|
|
8
15
|
|
|
9
16
|
### CI
|
package/dist/index.js
CHANGED
|
@@ -10344,7 +10344,7 @@ function readAnonId() {
|
|
|
10344
10344
|
}
|
|
10345
10345
|
function superProperties() {
|
|
10346
10346
|
return {
|
|
10347
|
-
cliVersion: true ? "2.75.
|
|
10347
|
+
cliVersion: true ? "2.75.8" : "0.0.0-dev",
|
|
10348
10348
|
nodeVersion: process.version,
|
|
10349
10349
|
platform: process.platform,
|
|
10350
10350
|
arch: process.arch,
|
|
@@ -10586,7 +10586,7 @@ var http = __toESM(require("http"));
|
|
|
10586
10586
|
// package.json
|
|
10587
10587
|
var package_default = {
|
|
10588
10588
|
name: "codeam-cli",
|
|
10589
|
-
version: "2.75.
|
|
10589
|
+
version: "2.75.8",
|
|
10590
10590
|
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.",
|
|
10591
10591
|
type: "commonjs",
|
|
10592
10592
|
main: "dist/index.js",
|
|
@@ -11384,6 +11384,9 @@ var streamHost = new StreamHostSelector(
|
|
|
11384
11384
|
);
|
|
11385
11385
|
|
|
11386
11386
|
// src/services/command-relay.service.ts
|
|
11387
|
+
function isRecord2(v) {
|
|
11388
|
+
return typeof v === "object" && v !== null;
|
|
11389
|
+
}
|
|
11387
11390
|
function httpStatusOf(err) {
|
|
11388
11391
|
if (typeof err === "object" && err !== null && "statusCode" in err) {
|
|
11389
11392
|
const status2 = err.statusCode;
|
|
@@ -11394,6 +11397,8 @@ function httpStatusOf(err) {
|
|
|
11394
11397
|
var API_BASE2 = resolveApiBaseUrl();
|
|
11395
11398
|
var PENDING_STREAM_PATH = "/api/commands/pending/stream";
|
|
11396
11399
|
var SSE_LIVENESS_TIMEOUT_MS = 45e3;
|
|
11400
|
+
var HEARTBEAT_RETRY_MS = 3e3;
|
|
11401
|
+
var HEARTBEAT_WARN_INTERVAL_MS = 6e4;
|
|
11397
11402
|
var SSE_WATCHDOG_INTERVAL_MS = 1e4;
|
|
11398
11403
|
var CommandRelayService = class _CommandRelayService {
|
|
11399
11404
|
constructor(pluginId, onCommand, agentMeta, agentsOverride, explicitPollSecret, onHeartbeat) {
|
|
@@ -11412,6 +11417,18 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
11412
11417
|
onHeartbeat;
|
|
11413
11418
|
_running = false;
|
|
11414
11419
|
pairingInvalid = false;
|
|
11420
|
+
/**
|
|
11421
|
+
* Heartbeat health. Before 2026-09-23 a failed heartbeat was a `log.trace`,
|
|
11422
|
+
* i.e. INVISIBLE in a normal `~/.codeam/debug-*.log` — a user whose beats
|
|
11423
|
+
* never reached the origin (every other request did) spent a day on "Server
|
|
11424
|
+
* Failed to Start" with nothing in his log to show for it. Failures are now
|
|
11425
|
+
* WARN (rate-limited per streak) + a PostHog event, and the process exits
|
|
11426
|
+
* when the backend answers `paired:false`.
|
|
11427
|
+
*/
|
|
11428
|
+
heartbeatFailStreak = 0;
|
|
11429
|
+
heartbeatLastWarnAt = 0;
|
|
11430
|
+
sessionGone = false;
|
|
11431
|
+
onSessionGone;
|
|
11415
11432
|
heartbeatTimer = null;
|
|
11416
11433
|
agentsTimer = null;
|
|
11417
11434
|
/** Injectable for tests; defaults to real fs/fetch/spawn wiring. */
|
|
@@ -11530,6 +11547,17 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
11530
11547
|
stop() {
|
|
11531
11548
|
void this.stopAndFlush();
|
|
11532
11549
|
}
|
|
11550
|
+
/**
|
|
11551
|
+
* Called ONCE when a heartbeat answers `paired:false` — the backend no longer
|
|
11552
|
+
* has a live session for this pluginId (deleted / disconnected from the
|
|
11553
|
+
* app). The relay has already stopped itself by then; the owner should exit
|
|
11554
|
+
* the process like a Ctrl-C would. Backstop for a process whose
|
|
11555
|
+
* `session_terminated` command was consumed by a sibling on the same
|
|
11556
|
+
* pluginId (two `codeam start` on one saved session, 2026-09-23).
|
|
11557
|
+
*/
|
|
11558
|
+
setOnSessionGone(cb) {
|
|
11559
|
+
this.onSessionGone = cb;
|
|
11560
|
+
}
|
|
11533
11561
|
/**
|
|
11534
11562
|
* Same teardown as {@link stop}, but resolves only once the `online:false`
|
|
11535
11563
|
* heartbeat POST has settled — so a caller can `await` it before exiting.
|
|
@@ -11877,8 +11905,9 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
11877
11905
|
});
|
|
11878
11906
|
}
|
|
11879
11907
|
// ─── Heartbeat + agents ──────────────────────────────────────────
|
|
11880
|
-
async sendHeartbeat(online) {
|
|
11881
|
-
|
|
11908
|
+
async sendHeartbeat(online, attempt = 0) {
|
|
11909
|
+
if (this.sessionGone && online) return;
|
|
11910
|
+
const body = {
|
|
11882
11911
|
pluginId: this.pluginId,
|
|
11883
11912
|
online,
|
|
11884
11913
|
agentId: this.agentMeta.id,
|
|
@@ -11887,8 +11916,58 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
11887
11916
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
11888
11917
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
11889
11918
|
// pair/reconnect). Older backends ignore the extra field.
|
|
11890
|
-
..."2.75.
|
|
11891
|
-
}
|
|
11919
|
+
..."2.75.8" ? { ideVersion: "2.75.8" } : {}
|
|
11920
|
+
};
|
|
11921
|
+
try {
|
|
11922
|
+
const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body);
|
|
11923
|
+
this.heartbeatFailStreak = 0;
|
|
11924
|
+
log.trace("relay", `heartbeat ok online=${online}`);
|
|
11925
|
+
const data = res?.data;
|
|
11926
|
+
if (online && isRecord2(data) && data.paired === false) this.handleSessionGone();
|
|
11927
|
+
} catch (err) {
|
|
11928
|
+
if (!online) {
|
|
11929
|
+
log.trace("relay", "goodbye heartbeat failed", err);
|
|
11930
|
+
return;
|
|
11931
|
+
}
|
|
11932
|
+
this.heartbeatFailStreak += 1;
|
|
11933
|
+
this.noteHeartbeatFailure(err);
|
|
11934
|
+
if (attempt === 0 && this._running) {
|
|
11935
|
+
const t2 = setTimeout(() => {
|
|
11936
|
+
void this.sendHeartbeat(true, 1);
|
|
11937
|
+
}, HEARTBEAT_RETRY_MS);
|
|
11938
|
+
t2.unref?.();
|
|
11939
|
+
}
|
|
11940
|
+
}
|
|
11941
|
+
}
|
|
11942
|
+
noteHeartbeatFailure(err) {
|
|
11943
|
+
const status2 = httpStatusOf(err);
|
|
11944
|
+
const code = err?.code;
|
|
11945
|
+
const reason = status2 ? `status_${status2}` : typeof code === "string" ? code : (err instanceof Error ? err.message : String(err)).slice(0, 80);
|
|
11946
|
+
const now = Date.now();
|
|
11947
|
+
const firstOfStreak = this.heartbeatFailStreak === 1;
|
|
11948
|
+
if (!firstOfStreak && now - this.heartbeatLastWarnAt < HEARTBEAT_WARN_INTERVAL_MS) return;
|
|
11949
|
+
this.heartbeatLastWarnAt = now;
|
|
11950
|
+
log.warn(
|
|
11951
|
+
"relay",
|
|
11952
|
+
`heartbeat failed (${reason}, streak=${this.heartbeatFailStreak}) \u2014 two misses in a row and the app shows this session OFFLINE even though it is running`
|
|
11953
|
+
);
|
|
11954
|
+
capture("heartbeat_failed", {
|
|
11955
|
+
pluginId: this.pluginId,
|
|
11956
|
+
agentId: this.agentMeta.id,
|
|
11957
|
+
reason,
|
|
11958
|
+
streak: this.heartbeatFailStreak
|
|
11959
|
+
});
|
|
11960
|
+
}
|
|
11961
|
+
handleSessionGone() {
|
|
11962
|
+
if (this.sessionGone) return;
|
|
11963
|
+
log.warn("relay", "backend reports this session no longer exists (paired:false) \u2014 stopping");
|
|
11964
|
+
capture("session_gone_detected", { pluginId: this.pluginId, agentId: this.agentMeta.id });
|
|
11965
|
+
process.stderr.write(
|
|
11966
|
+
"[codeam] This session was deleted or disconnected from the app \u2014 exiting. Run `codeam pair` to start a new one.\n"
|
|
11967
|
+
);
|
|
11968
|
+
this.stop();
|
|
11969
|
+
this.sessionGone = true;
|
|
11970
|
+
this.onSessionGone?.();
|
|
11892
11971
|
}
|
|
11893
11972
|
/**
|
|
11894
11973
|
* Refresh {@link cachedBranch} without blocking the event loop.
|
|
@@ -31218,14 +31297,14 @@ var zGuardCreateElicitationResponseCancel = z7.object({
|
|
|
31218
31297
|
|
|
31219
31298
|
// ../../node_modules/@agentclientprotocol/sdk/dist/jsonrpc.js
|
|
31220
31299
|
var CANCEL_REQUEST_METHOD = "$/cancel_request";
|
|
31221
|
-
function
|
|
31300
|
+
function isRecord3(value) {
|
|
31222
31301
|
return typeof value === "object" && value !== null;
|
|
31223
31302
|
}
|
|
31224
31303
|
function isJsonRpcId(value) {
|
|
31225
31304
|
return value === null || typeof value === "string" || typeof value === "number" && Number.isFinite(value);
|
|
31226
31305
|
}
|
|
31227
31306
|
function cancelRequestId(params) {
|
|
31228
|
-
if (!
|
|
31307
|
+
if (!isRecord3(params) || !isJsonRpcId(params["requestId"])) {
|
|
31229
31308
|
return void 0;
|
|
31230
31309
|
}
|
|
31231
31310
|
return params["requestId"];
|
|
@@ -31657,7 +31736,7 @@ var Connection = class {
|
|
|
31657
31736
|
if (this.abortController.signal.aborted) {
|
|
31658
31737
|
return;
|
|
31659
31738
|
}
|
|
31660
|
-
if (!
|
|
31739
|
+
if (!isRecord3(message)) {
|
|
31661
31740
|
console.error("Invalid message", { message });
|
|
31662
31741
|
return;
|
|
31663
31742
|
}
|
|
@@ -31750,7 +31829,7 @@ var Connection = class {
|
|
|
31750
31829
|
pendingResponse.cleanup?.();
|
|
31751
31830
|
if ("result" in response) {
|
|
31752
31831
|
pendingResponse.resolve(response.result);
|
|
31753
|
-
} else if ("error" in response &&
|
|
31832
|
+
} else if ("error" in response && isRecord3(response.error)) {
|
|
31754
31833
|
const { code, message, data } = response.error;
|
|
31755
31834
|
pendingResponse.reject(new RequestError(code, message, data));
|
|
31756
31835
|
} else {
|
|
@@ -32023,7 +32102,7 @@ function ndJsonStream(output, input) {
|
|
|
32023
32102
|
if (trimmedLine) {
|
|
32024
32103
|
try {
|
|
32025
32104
|
const message = JSON.parse(trimmedLine);
|
|
32026
|
-
if (
|
|
32105
|
+
if (isRecord3(message)) {
|
|
32027
32106
|
controller.enqueue(message);
|
|
32028
32107
|
} else {
|
|
32029
32108
|
console.warn("Skipping JSON line that is not an object:", trimmedLine);
|
|
@@ -40600,6 +40679,7 @@ async function runAcpSession(opts) {
|
|
|
40600
40679
|
};
|
|
40601
40680
|
process.once("SIGINT", () => void shutdown("SIGINT"));
|
|
40602
40681
|
process.once("SIGTERM", () => void shutdown("SIGTERM"));
|
|
40682
|
+
relay.setOnSessionGone(() => void shutdown("SIGTERM"));
|
|
40603
40683
|
process.once("SIGHUP", () => void shutdown("SIGHUP"));
|
|
40604
40684
|
await new Promise(() => {
|
|
40605
40685
|
});
|
|
@@ -42730,6 +42810,7 @@ async function runBatonSession(opts) {
|
|
|
42730
42810
|
process.once("SIGINT", onSignal);
|
|
42731
42811
|
process.once("SIGTERM", onSignal);
|
|
42732
42812
|
process.once("SIGHUP", onSignal);
|
|
42813
|
+
relay.setOnSessionGone(onSignal);
|
|
42733
42814
|
showInfo(`Starting ${opts.agent} baton (local) \u2014 native TUI + mobile take-control\u2026`);
|
|
42734
42815
|
await controller.begin();
|
|
42735
42816
|
relay.start();
|
|
@@ -43170,6 +43251,9 @@ async function start(requestedAgent, presetSession) {
|
|
|
43170
43251
|
})
|
|
43171
43252
|
);
|
|
43172
43253
|
ctx.relay = relay;
|
|
43254
|
+
relay.setOnSessionGone(() => {
|
|
43255
|
+
void sigintHandler();
|
|
43256
|
+
});
|
|
43173
43257
|
void beadsReady.then((started) => {
|
|
43174
43258
|
ctx.beads = started;
|
|
43175
43259
|
});
|
|
@@ -46422,7 +46506,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
46422
46506
|
if (process.env.NODE_ENV === "test") return;
|
|
46423
46507
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
46424
46508
|
if (process.env.CI) return;
|
|
46425
|
-
const current2 = true ? "2.75.
|
|
46509
|
+
const current2 = true ? "2.75.8" : null;
|
|
46426
46510
|
if (!current2) return;
|
|
46427
46511
|
const cache = readCache();
|
|
46428
46512
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -46439,7 +46523,7 @@ function checkForUpdates() {
|
|
|
46439
46523
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
46440
46524
|
if (process.env.CI) return;
|
|
46441
46525
|
if (!process.stdout.isTTY) return;
|
|
46442
|
-
const current2 = true ? "2.75.
|
|
46526
|
+
const current2 = true ? "2.75.8" : null;
|
|
46443
46527
|
if (!current2) return;
|
|
46444
46528
|
const cache = readCache();
|
|
46445
46529
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -46462,7 +46546,7 @@ var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
|
46462
46546
|
var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
|
|
46463
46547
|
var SUDO_PREFLIGHT_TIMEOUT_MS = 5e3;
|
|
46464
46548
|
function currentCliVersion() {
|
|
46465
|
-
return true ? "2.75.
|
|
46549
|
+
return true ? "2.75.8" : null;
|
|
46466
46550
|
}
|
|
46467
46551
|
async function installedVersion(deps) {
|
|
46468
46552
|
const ls = await deps.run(
|
|
@@ -48202,7 +48286,7 @@ function checkChokidar() {
|
|
|
48202
48286
|
}
|
|
48203
48287
|
async function doctor(args2 = []) {
|
|
48204
48288
|
const json = args2.includes("--json");
|
|
48205
|
-
const cliVersion = true ? "2.75.
|
|
48289
|
+
const cliVersion = true ? "2.75.8" : "0.0.0-dev";
|
|
48206
48290
|
const apiBase2 = resolveApiBaseUrl();
|
|
48207
48291
|
const diagnosticId = (0, import_node_crypto12.randomUUID)();
|
|
48208
48292
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -48726,7 +48810,7 @@ async function mcpWarm(argv = [], opts = {}) {
|
|
|
48726
48810
|
// src/commands/version.ts
|
|
48727
48811
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
48728
48812
|
function version2() {
|
|
48729
|
-
const v = true ? "2.75.
|
|
48813
|
+
const v = true ? "2.75.8" : "unknown";
|
|
48730
48814
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
48731
48815
|
}
|
|
48732
48816
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.75.
|
|
3
|
+
"version": "2.75.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",
|