codeam-cli 2.39.68 → 2.39.71
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 +16 -0
- package/dist/index.js +95 -71
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ 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.39.69] — 2026-06-21
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** Report Headroom prompt-cache savings, not just compression
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **cli:** Make the pairing code more legible (letter-spacing + bold + contrast)
|
|
16
|
+
|
|
17
|
+
## [2.39.68] — 2026-06-20
|
|
18
|
+
|
|
19
|
+
### Tests
|
|
20
|
+
|
|
21
|
+
- **host-agent:** Don't leak a heartbeat timer in the self_hosted_stop test
|
|
22
|
+
|
|
7
23
|
## [2.39.66] — 2026-06-20
|
|
8
24
|
|
|
9
25
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -1084,12 +1084,12 @@ var PromiseQueue = class {
|
|
|
1084
1084
|
return promise;
|
|
1085
1085
|
}
|
|
1086
1086
|
async join() {
|
|
1087
|
-
let
|
|
1088
|
-
let length =
|
|
1087
|
+
let promises2 = Object.values(this.promiseByIds);
|
|
1088
|
+
let length = promises2.length;
|
|
1089
1089
|
while (length > 0) {
|
|
1090
|
-
await Promise.all(
|
|
1091
|
-
|
|
1092
|
-
length =
|
|
1090
|
+
await Promise.all(promises2);
|
|
1091
|
+
promises2 = Object.values(this.promiseByIds);
|
|
1092
|
+
length = promises2.length;
|
|
1093
1093
|
}
|
|
1094
1094
|
}
|
|
1095
1095
|
get length() {
|
|
@@ -1427,8 +1427,8 @@ function safeSetTimeout(fn, timeout) {
|
|
|
1427
1427
|
return t2;
|
|
1428
1428
|
}
|
|
1429
1429
|
var isError = (x) => x instanceof Error;
|
|
1430
|
-
function allSettled(
|
|
1431
|
-
return Promise.all(
|
|
1430
|
+
function allSettled(promises2) {
|
|
1431
|
+
return Promise.all(promises2.map((p2) => (p2 ?? Promise.resolve()).then((value) => ({
|
|
1432
1432
|
status: "fulfilled",
|
|
1433
1433
|
value
|
|
1434
1434
|
}), (reason) => ({
|
|
@@ -5388,7 +5388,7 @@ function readAnonId() {
|
|
|
5388
5388
|
}
|
|
5389
5389
|
function superProperties() {
|
|
5390
5390
|
return {
|
|
5391
|
-
cliVersion: true ? "2.39.
|
|
5391
|
+
cliVersion: true ? "2.39.71" : "0.0.0-dev",
|
|
5392
5392
|
nodeVersion: process.version,
|
|
5393
5393
|
platform: process.platform,
|
|
5394
5394
|
arch: process.arch,
|
|
@@ -5547,7 +5547,7 @@ var os4 = __toESM(require("os"));
|
|
|
5547
5547
|
// package.json
|
|
5548
5548
|
var package_default = {
|
|
5549
5549
|
name: "codeam-cli",
|
|
5550
|
-
version: "2.39.
|
|
5550
|
+
version: "2.39.71",
|
|
5551
5551
|
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.",
|
|
5552
5552
|
type: "commonjs",
|
|
5553
5553
|
main: "dist/index.js",
|
|
@@ -8281,10 +8281,12 @@ function boxRow(content, visibleLength) {
|
|
|
8281
8281
|
return ` \u2502${content}${pad}\u2502`;
|
|
8282
8282
|
}
|
|
8283
8283
|
function showPairingCode(code) {
|
|
8284
|
+
const spaced = code.split("").join(" ");
|
|
8284
8285
|
console.log(BOX_BORDER_TOP);
|
|
8285
|
-
const
|
|
8286
|
+
const label = " Code: ";
|
|
8287
|
+
const codeVisible = `${label}${spaced}`.length;
|
|
8286
8288
|
console.log(
|
|
8287
|
-
boxRow(
|
|
8289
|
+
boxRow(`${label}${import_picocolors.default.bold(import_picocolors.default.yellow(spaced))}`, codeVisible)
|
|
8288
8290
|
);
|
|
8289
8291
|
console.log(BOX_BORDER_BOT);
|
|
8290
8292
|
console.log("");
|
|
@@ -17181,7 +17183,14 @@ function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os30.homedir(
|
|
|
17181
17183
|
}
|
|
17182
17184
|
|
|
17183
17185
|
// src/services/headroom/stats-reporter.ts
|
|
17184
|
-
var ZERO = {
|
|
17186
|
+
var ZERO = {
|
|
17187
|
+
rawTokensEst: 0,
|
|
17188
|
+
sentTokensEst: 0,
|
|
17189
|
+
cachedTokens: 0,
|
|
17190
|
+
retrieveHops: 0,
|
|
17191
|
+
cacheReadTokens: 0,
|
|
17192
|
+
cacheSavingsUsd: 0
|
|
17193
|
+
};
|
|
17185
17194
|
function read(stats) {
|
|
17186
17195
|
const totals = stats.agent_usage?.totals;
|
|
17187
17196
|
const compression = stats.summary?.compression;
|
|
@@ -17191,7 +17200,9 @@ function read(stats) {
|
|
|
17191
17200
|
rawTokensEst,
|
|
17192
17201
|
sentTokensEst,
|
|
17193
17202
|
cachedTokens: 0,
|
|
17194
|
-
retrieveHops: stats.summary?.mcp?.retrievals ?? 0
|
|
17203
|
+
retrieveHops: stats.summary?.mcp?.retrievals ?? 0,
|
|
17204
|
+
cacheReadTokens: stats.prefix_cache?.totals?.cache_read_tokens ?? 0,
|
|
17205
|
+
cacheSavingsUsd: stats.summary?.cost?.breakdown?.cache_savings_usd ?? 0
|
|
17195
17206
|
};
|
|
17196
17207
|
}
|
|
17197
17208
|
function mapStatsToSavings(stats, prev) {
|
|
@@ -17201,7 +17212,9 @@ function mapStatsToSavings(stats, prev) {
|
|
|
17201
17212
|
rawTokensEst: d3(next.rawTokensEst, prev.rawTokensEst),
|
|
17202
17213
|
sentTokensEst: d3(next.sentTokensEst, prev.sentTokensEst),
|
|
17203
17214
|
cachedTokens: d3(next.cachedTokens, prev.cachedTokens),
|
|
17204
|
-
retrieveHops: d3(next.retrieveHops, prev.retrieveHops)
|
|
17215
|
+
retrieveHops: d3(next.retrieveHops, prev.retrieveHops),
|
|
17216
|
+
cacheReadTokens: d3(next.cacheReadTokens, prev.cacheReadTokens),
|
|
17217
|
+
cacheSavingsUsd: d3(next.cacheSavingsUsd, prev.cacheSavingsUsd)
|
|
17205
17218
|
};
|
|
17206
17219
|
return { next, delta };
|
|
17207
17220
|
}
|
|
@@ -17220,7 +17233,9 @@ var HeadroomStatsReporter = class {
|
|
|
17220
17233
|
try {
|
|
17221
17234
|
const { next, delta } = mapStatsToSavings(await this.deps.fetchStats(), this.prev);
|
|
17222
17235
|
this.prev = next;
|
|
17223
|
-
if (delta.rawTokensEst > 0
|
|
17236
|
+
if (delta.rawTokensEst > 0 || delta.cacheReadTokens > 0 || delta.cacheSavingsUsd > 0) {
|
|
17237
|
+
await this.deps.postSavings(delta);
|
|
17238
|
+
}
|
|
17224
17239
|
} catch {
|
|
17225
17240
|
}
|
|
17226
17241
|
}
|
|
@@ -17391,7 +17406,7 @@ function checkForUpdates() {
|
|
|
17391
17406
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
17392
17407
|
if (process.env.CI) return;
|
|
17393
17408
|
if (!process.stdout.isTTY) return;
|
|
17394
|
-
const current = true ? "2.39.
|
|
17409
|
+
const current = true ? "2.39.71" : null;
|
|
17395
17410
|
if (!current) return;
|
|
17396
17411
|
const cache = readCache();
|
|
17397
17412
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -17484,7 +17499,8 @@ var CONTROL_AGENT_META = {
|
|
|
17484
17499
|
};
|
|
17485
17500
|
var PEP668_MARKER = "externally-managed-environment";
|
|
17486
17501
|
var PM_INSTALL_TIMEOUT_MS = 18e4;
|
|
17487
|
-
var
|
|
17502
|
+
var ENGINE_INSTALL_TIMEOUT_MS = 36e4;
|
|
17503
|
+
var HEADROOM_MIN_FREE_DISK_BYTES = 3 * 1024 * 1024 * 1024;
|
|
17488
17504
|
var defaultHeadroomRunner = {
|
|
17489
17505
|
which(cmd) {
|
|
17490
17506
|
try {
|
|
@@ -17696,57 +17712,50 @@ function bundledClaudeBinDir() {
|
|
|
17696
17712
|
}
|
|
17697
17713
|
return null;
|
|
17698
17714
|
}
|
|
17715
|
+
async function getFreeDiskBytes(dir) {
|
|
17716
|
+
try {
|
|
17717
|
+
const s = await fs39.promises.statfs(dir);
|
|
17718
|
+
return s.bsize * s.bavail;
|
|
17719
|
+
} catch {
|
|
17720
|
+
return null;
|
|
17721
|
+
}
|
|
17722
|
+
}
|
|
17699
17723
|
async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner) {
|
|
17700
|
-
const
|
|
17701
|
-
"headroom-ai",
|
|
17702
|
-
"fastapi",
|
|
17703
|
-
"uvicorn",
|
|
17704
|
-
"httpx[http2]",
|
|
17705
|
-
"websockets",
|
|
17706
|
-
"zstandard"
|
|
17707
|
-
];
|
|
17724
|
+
const SERVER_DEPS = ["fastapi", "uvicorn", "httpx[http2]", "websockets", "zstandard"];
|
|
17708
17725
|
const pipAvailable = await ensurePip(runner);
|
|
17709
17726
|
if (!pipAvailable) {
|
|
17710
17727
|
return false;
|
|
17711
17728
|
}
|
|
17712
|
-
const
|
|
17713
|
-
const
|
|
17714
|
-
const
|
|
17715
|
-
|
|
17716
|
-
|
|
17717
|
-
|
|
17718
|
-
|
|
17719
|
-
return true;
|
|
17720
|
-
}
|
|
17721
|
-
if (firstResult.stderr.includes(PEP668_MARKER)) {
|
|
17722
|
-
log.info(
|
|
17723
|
-
"host-agent",
|
|
17724
|
-
"PEP 668 externally-managed-environment detected \u2014 retrying with --break-system-packages"
|
|
17725
|
-
);
|
|
17726
|
-
const retryResult = await runner.run(
|
|
17727
|
-
"python3",
|
|
17728
|
-
[...baseArgs, "--break-system-packages"],
|
|
17729
|
-
{ timeoutMs: PIP_INSTALL_TIMEOUT_MS }
|
|
17730
|
-
);
|
|
17731
|
-
if (retryResult.code === 0) {
|
|
17732
|
-
log.info("host-agent", "headroom pip install succeeded (--break-system-packages)");
|
|
17733
|
-
return true;
|
|
17734
|
-
}
|
|
17735
|
-
log.warn(
|
|
17736
|
-
"host-agent",
|
|
17737
|
-
`headroom pip install failed even with --break-system-packages (code=${String(retryResult.code)}) \u2014 skipping Headroom`
|
|
17738
|
-
);
|
|
17739
|
-
return false;
|
|
17729
|
+
const pipInstall = async (pkgs, extraArgs, timeoutMs) => {
|
|
17730
|
+
const base = ["-m", "pip", "install", "--quiet", ...extraArgs, ...pkgs];
|
|
17731
|
+
const r = await runner.run("python3", base, { timeoutMs });
|
|
17732
|
+
if (r.code === 0) return true;
|
|
17733
|
+
if (r.stderr.includes(PEP668_MARKER)) {
|
|
17734
|
+
const r2 = await runner.run("python3", [...base, "--break-system-packages"], { timeoutMs });
|
|
17735
|
+
return r2.code === 0;
|
|
17740
17736
|
}
|
|
17741
|
-
log.warn(
|
|
17742
|
-
"host-agent",
|
|
17743
|
-
`headroom pip install exited code=${String(firstResult.code)} \u2014 skipping Headroom`
|
|
17744
|
-
);
|
|
17745
17737
|
return false;
|
|
17746
|
-
}
|
|
17738
|
+
};
|
|
17739
|
+
const torchOk = await pipInstall(
|
|
17740
|
+
["torch"],
|
|
17741
|
+
["--index-url", "https://download.pytorch.org/whl/cpu"],
|
|
17742
|
+
ENGINE_INSTALL_TIMEOUT_MS
|
|
17743
|
+
);
|
|
17744
|
+
log.info(
|
|
17745
|
+
"host-agent",
|
|
17746
|
+
torchOk ? "CPU-only PyTorch installed \u2014 Kompress (ML) compressor available" : "CPU torch install failed \u2014 installing code-aware engine only (Kompress unavailable)"
|
|
17747
|
+
);
|
|
17748
|
+
const headroomPkg = torchOk ? "headroom-ai[code,ml]" : "headroom-ai[code]";
|
|
17749
|
+
const installOk = await pipInstall(
|
|
17750
|
+
[headroomPkg, ...SERVER_DEPS],
|
|
17751
|
+
[],
|
|
17752
|
+
ENGINE_INSTALL_TIMEOUT_MS
|
|
17753
|
+
);
|
|
17747
17754
|
if (!installOk) {
|
|
17755
|
+
log.warn("host-agent", `headroom engine install failed (${headroomPkg}) \u2014 skipping Headroom`);
|
|
17748
17756
|
return false;
|
|
17749
17757
|
}
|
|
17758
|
+
log.info("host-agent", `headroom + engines installed (${headroomPkg})`);
|
|
17750
17759
|
if (!runner.which("headroom")) {
|
|
17751
17760
|
log.warn("host-agent", "headroom not found on PATH after install \u2014 skipping init");
|
|
17752
17761
|
return false;
|
|
@@ -17796,7 +17805,7 @@ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process13.s
|
|
|
17796
17805
|
detached: false
|
|
17797
17806
|
});
|
|
17798
17807
|
function currentCliVersion() {
|
|
17799
|
-
return true ? "2.39.
|
|
17808
|
+
return true ? "2.39.71" : null;
|
|
17800
17809
|
}
|
|
17801
17810
|
function runCmd(cmd, args2, timeoutMs) {
|
|
17802
17811
|
return new Promise((resolve7) => {
|
|
@@ -18199,17 +18208,32 @@ var HostAgentSupervisor = class {
|
|
|
18199
18208
|
}
|
|
18200
18209
|
if (payload.headroomEnabled && payload.headroomAgent && payload.headroomSavingsIngestUrl) {
|
|
18201
18210
|
report("headroom", "setting up Headroom proxy");
|
|
18202
|
-
const
|
|
18203
|
-
if (
|
|
18204
|
-
|
|
18205
|
-
|
|
18206
|
-
|
|
18207
|
-
|
|
18208
|
-
|
|
18209
|
-
|
|
18210
|
-
|
|
18211
|
+
const freeBytes = await getFreeDiskBytes(os32.homedir());
|
|
18212
|
+
if (freeBytes !== null && freeBytes < HEADROOM_MIN_FREE_DISK_BYTES) {
|
|
18213
|
+
const freeGb = (freeBytes / 1e9).toFixed(1);
|
|
18214
|
+
const needGb = Math.round(HEADROOM_MIN_FREE_DISK_BYTES / 1e9);
|
|
18215
|
+
report(
|
|
18216
|
+
"headroom",
|
|
18217
|
+
`Token-saving optimizer skipped \u2014 needs ~${needGb} GB free, host has ${freeGb} GB. The agent runs normally without it.`
|
|
18218
|
+
);
|
|
18219
|
+
log.warn(
|
|
18220
|
+
"host-agent",
|
|
18221
|
+
`Headroom skipped: insufficient disk (free=${freeGb}GB < ${needGb}GB)`
|
|
18222
|
+
);
|
|
18211
18223
|
persistHeadroomConfig({ enabled: false });
|
|
18212
|
-
|
|
18224
|
+
} else {
|
|
18225
|
+
const headroomOk = await this.setupHeadroom(payload.headroomAgent);
|
|
18226
|
+
if (headroomOk) {
|
|
18227
|
+
persistHeadroomConfig({
|
|
18228
|
+
enabled: true,
|
|
18229
|
+
agent: agentIdToHeadroomKind(payload.headroomAgent),
|
|
18230
|
+
ingestUrl: payload.headroomSavingsIngestUrl
|
|
18231
|
+
});
|
|
18232
|
+
log.info("host-agent", "Headroom proxy ready; persisted headroom config for child spawns");
|
|
18233
|
+
} else {
|
|
18234
|
+
persistHeadroomConfig({ enabled: false });
|
|
18235
|
+
log.warn("host-agent", "Headroom setup failed (best-effort) \u2014 child will run without Headroom");
|
|
18236
|
+
}
|
|
18213
18237
|
}
|
|
18214
18238
|
} else if (payload.headroomEnabled === false) {
|
|
18215
18239
|
persistHeadroomConfig({ enabled: false });
|
|
@@ -28435,7 +28459,7 @@ function checkChokidar() {
|
|
|
28435
28459
|
}
|
|
28436
28460
|
async function doctor(args2 = []) {
|
|
28437
28461
|
const json = args2.includes("--json");
|
|
28438
|
-
const cliVersion = true ? "2.39.
|
|
28462
|
+
const cliVersion = true ? "2.39.71" : "0.0.0-dev";
|
|
28439
28463
|
const apiBase2 = resolveApiBaseUrl();
|
|
28440
28464
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
28441
28465
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -28634,7 +28658,7 @@ async function completion(args2) {
|
|
|
28634
28658
|
// src/commands/version.ts
|
|
28635
28659
|
var import_picocolors14 = __toESM(require("picocolors"));
|
|
28636
28660
|
function version2() {
|
|
28637
|
-
const v = true ? "2.39.
|
|
28661
|
+
const v = true ? "2.39.71" : "unknown";
|
|
28638
28662
|
console.log(`${import_picocolors14.default.bold("codeam-cli")} ${import_picocolors14.default.cyan(v)}`);
|
|
28639
28663
|
}
|
|
28640
28664
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.39.
|
|
3
|
+
"version": "2.39.71",
|
|
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",
|