codeam-cli 2.39.77 → 2.39.79

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 CHANGED
@@ -4,6 +4,12 @@ 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.77] — 2026-06-21
8
+
9
+ ### Added
10
+
11
+ - **cli:** Report runtime 401 to mark the credential invalid
12
+
7
13
  ## [2.39.76] — 2026-06-21
8
14
 
9
15
  ### Added
package/dist/index.js CHANGED
@@ -5390,7 +5390,7 @@ function readAnonId() {
5390
5390
  }
5391
5391
  function superProperties() {
5392
5392
  return {
5393
- cliVersion: true ? "2.39.77" : "0.0.0-dev",
5393
+ cliVersion: true ? "2.39.79" : "0.0.0-dev",
5394
5394
  nodeVersion: process.version,
5395
5395
  platform: process.platform,
5396
5396
  arch: process.arch,
@@ -5549,7 +5549,7 @@ var os4 = __toESM(require("os"));
5549
5549
  // package.json
5550
5550
  var package_default = {
5551
5551
  name: "codeam-cli",
5552
- version: "2.39.77",
5552
+ version: "2.39.79",
5553
5553
  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.",
5554
5554
  type: "commonjs",
5555
5555
  main: "dist/index.js",
@@ -17224,14 +17224,17 @@ var ZERO = {
17224
17224
  retrieveHops: 0,
17225
17225
  cacheReadTokens: 0,
17226
17226
  cacheSavingsUsd: 0,
17227
- compressionSavingsUsd: 0
17227
+ compressionTokens: 0,
17228
+ compressionSavingsUsd: 0,
17229
+ compressionPct: 0
17228
17230
  };
17229
17231
  function read(stats, inputPricePerMillion) {
17230
17232
  const totals = stats.agent_usage?.totals;
17231
17233
  const compression = stats.summary?.compression;
17232
17234
  const rawTokensEst = totals?.before_tokens ?? compression?.total_tokens_before_with_cli_filtering ?? 0;
17233
17235
  const sentTokensEst = totals?.after_tokens ?? rawTokensEst - (compression?.total_tokens_removed ?? 0);
17234
- const compressionSavingsUsd = Math.max(0, rawTokensEst - sentTokensEst) / 1e6 * inputPricePerMillion;
17236
+ const compressionTokens = compression?.total_tokens_saved_with_cli_filtering ?? compression?.total_tokens_removed ?? Math.max(0, rawTokensEst - sentTokensEst);
17237
+ const compressionSavingsUsd = stats.summary?.cost?.breakdown?.compression_savings_usd ?? Math.max(0, compressionTokens) / 1e6 * inputPricePerMillion;
17235
17238
  return {
17236
17239
  rawTokensEst,
17237
17240
  sentTokensEst,
@@ -17239,7 +17242,9 @@ function read(stats, inputPricePerMillion) {
17239
17242
  retrieveHops: stats.summary?.mcp?.retrievals ?? 0,
17240
17243
  cacheReadTokens: stats.prefix_cache?.totals?.cache_read_tokens ?? 0,
17241
17244
  cacheSavingsUsd: stats.summary?.cost?.breakdown?.cache_savings_usd ?? 0,
17242
- compressionSavingsUsd
17245
+ compressionTokens,
17246
+ compressionSavingsUsd,
17247
+ compressionPct: compression?.avg_compression_pct ?? 0
17243
17248
  };
17244
17249
  }
17245
17250
  function mapStatsToSavings(stats, prev, inputPricePerMillion = DEFAULT_INPUT_PRICE_PER_MILLION) {
@@ -17252,7 +17257,10 @@ function mapStatsToSavings(stats, prev, inputPricePerMillion = DEFAULT_INPUT_PRI
17252
17257
  retrieveHops: d3(next.retrieveHops, prev.retrieveHops),
17253
17258
  cacheReadTokens: d3(next.cacheReadTokens, prev.cacheReadTokens),
17254
17259
  cacheSavingsUsd: d3(next.cacheSavingsUsd, prev.cacheSavingsUsd),
17255
- compressionSavingsUsd: d3(next.compressionSavingsUsd, prev.compressionSavingsUsd)
17260
+ compressionTokens: d3(next.compressionTokens, prev.compressionTokens),
17261
+ compressionSavingsUsd: d3(next.compressionSavingsUsd, prev.compressionSavingsUsd),
17262
+ // RATE — carry the latest absolute value through, never diff it.
17263
+ compressionPct: next.compressionPct
17256
17264
  };
17257
17265
  return { next, delta };
17258
17266
  }
@@ -17275,7 +17283,7 @@ var HeadroomStatsReporter = class {
17275
17283
  this.deps.inputPricePerMillionUsd ?? DEFAULT_INPUT_PRICE_PER_MILLION
17276
17284
  );
17277
17285
  this.prev = next;
17278
- if (delta.rawTokensEst > 0 || delta.cacheReadTokens > 0 || delta.cacheSavingsUsd > 0 || delta.compressionSavingsUsd > 0) {
17286
+ if (delta.compressionTokens > 0 || delta.compressionSavingsUsd > 0 || delta.rawTokensEst > 0 || delta.cacheReadTokens > 0 || delta.cacheSavingsUsd > 0) {
17279
17287
  await this.deps.postSavings(delta);
17280
17288
  }
17281
17289
  } catch {
@@ -17448,7 +17456,7 @@ function checkForUpdates() {
17448
17456
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17449
17457
  if (process.env.CI) return;
17450
17458
  if (!process.stdout.isTTY) return;
17451
- const current = true ? "2.39.77" : null;
17459
+ const current = true ? "2.39.79" : null;
17452
17460
  if (!current) return;
17453
17461
  const cache = readCache();
17454
17462
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17504,7 +17512,10 @@ function maybeStartHeadroomReporter(ctx) {
17504
17512
  reporter.start();
17505
17513
  return reporter;
17506
17514
  } catch (err) {
17507
- log.warn("headroom", `failed to start Headroom reporter (best-effort): ${err instanceof Error ? err.message : String(err)}`);
17515
+ log.warn(
17516
+ "headroom",
17517
+ `failed to start Headroom reporter (best-effort): ${err instanceof Error ? err.message : String(err)}`
17518
+ );
17508
17519
  return null;
17509
17520
  }
17510
17521
  }
@@ -17584,7 +17595,10 @@ var defaultHeadroomRunner = {
17584
17595
  let timer;
17585
17596
  if (timeoutMs !== void 0) {
17586
17597
  timer = setTimeout(() => {
17587
- log.warn("host-agent", `headroom[${cmd}] timed out after ${timeoutMs / 1e3}s \u2014 aborting`);
17598
+ log.warn(
17599
+ "host-agent",
17600
+ `headroom[${cmd}] timed out after ${timeoutMs / 1e3}s \u2014 aborting`
17601
+ );
17588
17602
  try {
17589
17603
  child.kill("SIGTERM");
17590
17604
  } catch {
@@ -17615,7 +17629,16 @@ var PACKAGE_MANAGERS = [
17615
17629
  var PROVISION_RECIPES = {
17616
17630
  "apt-get": {
17617
17631
  update: ["apt-get", "update"],
17618
- install: ["apt-get", "install", "-y", "python3", "python3-pip", "python3-venv", "ca-certificates", "curl"]
17632
+ install: [
17633
+ "apt-get",
17634
+ "install",
17635
+ "-y",
17636
+ "python3",
17637
+ "python3-pip",
17638
+ "python3-venv",
17639
+ "ca-certificates",
17640
+ "curl"
17641
+ ]
17619
17642
  },
17620
17643
  apk: {
17621
17644
  install: ["apk", "add", "--no-cache", "python3", "py3-pip", "ca-certificates", "curl"]
@@ -17630,7 +17653,15 @@ var PROVISION_RECIPES = {
17630
17653
  install: ["pacman", "-Sy", "--noconfirm", "python", "python-pip", "ca-certificates", "curl"]
17631
17654
  },
17632
17655
  zypper: {
17633
- install: ["zypper", "--non-interactive", "install", "python3", "python3-pip", "ca-certificates", "curl"]
17656
+ install: [
17657
+ "zypper",
17658
+ "--non-interactive",
17659
+ "install",
17660
+ "python3",
17661
+ "python3-pip",
17662
+ "ca-certificates",
17663
+ "curl"
17664
+ ]
17634
17665
  }
17635
17666
  };
17636
17667
  function detectPackageManager(runner) {
@@ -17821,17 +17852,22 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner)
17821
17852
  }
17822
17853
  }
17823
17854
  const initOk = await new Promise((resolve7) => {
17824
- (0, import_node_child_process13.execFile)("headroom", ["init", "--global", initKind], { env: initEnv }, (initErr, stdout, stderr) => {
17825
- if (initErr) {
17826
- const detail = (stderr || initErr.message).replace(/\n+$/g, "");
17827
- log.warn("host-agent", `headroom init failed (best-effort): ${detail}`);
17828
- resolve7(false);
17829
- } else {
17830
- if (stdout.trim()) log.info("host-agent", `headroom init: ${stdout.trim()}`);
17831
- log.info("host-agent", "headroom init --global succeeded");
17832
- resolve7(true);
17855
+ (0, import_node_child_process13.execFile)(
17856
+ "headroom",
17857
+ ["init", "--global", initKind],
17858
+ { env: initEnv },
17859
+ (initErr, stdout, stderr) => {
17860
+ if (initErr) {
17861
+ const detail = (stderr || initErr.message).replace(/\n+$/g, "");
17862
+ log.warn("host-agent", `headroom init failed (best-effort): ${detail}`);
17863
+ resolve7(false);
17864
+ } else {
17865
+ if (stdout.trim()) log.info("host-agent", `headroom init: ${stdout.trim()}`);
17866
+ log.info("host-agent", "headroom init --global succeeded");
17867
+ resolve7(true);
17868
+ }
17833
17869
  }
17834
- });
17870
+ );
17835
17871
  });
17836
17872
  if (!initOk) {
17837
17873
  return false;
@@ -17844,7 +17880,10 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner)
17844
17880
  });
17845
17881
  proxy.unref();
17846
17882
  } catch (e) {
17847
- log.warn("host-agent", `headroom proxy warm-start failed (best-effort): ${e instanceof Error ? e.message : String(e)}`);
17883
+ log.warn(
17884
+ "host-agent",
17885
+ `headroom proxy warm-start failed (best-effort): ${e instanceof Error ? e.message : String(e)}`
17886
+ );
17848
17887
  }
17849
17888
  return true;
17850
17889
  }
@@ -17855,7 +17894,7 @@ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process13.s
17855
17894
  detached: false
17856
17895
  });
17857
17896
  function currentCliVersion() {
17858
- return true ? "2.39.77" : null;
17897
+ return true ? "2.39.79" : null;
17859
17898
  }
17860
17899
  function runCmd(cmd, args2, timeoutMs) {
17861
17900
  return new Promise((resolve7) => {
@@ -17872,7 +17911,11 @@ async function runSelfUpdate() {
17872
17911
  log.trace("host-agent", "self-update: no __CLI_VERSION__ \u2014 skipping");
17873
17912
  return { status: "skipped" };
17874
17913
  }
17875
- const view = await runCmd("npm", ["view", SELF_UPDATE_PKG, "version"], SELF_UPDATE_VIEW_TIMEOUT_MS);
17914
+ const view = await runCmd(
17915
+ "npm",
17916
+ ["view", SELF_UPDATE_PKG, "version"],
17917
+ SELF_UPDATE_VIEW_TIMEOUT_MS
17918
+ );
17876
17919
  if (view.code !== 0) {
17877
17920
  log.trace("host-agent", `self-update: npm view exited ${String(view.code)} \u2014 skipping`);
17878
17921
  return { status: "skipped" };
@@ -17900,7 +17943,11 @@ async function runSelfUpdate() {
17900
17943
  );
17901
17944
  return { status: "skipped" };
17902
17945
  }
17903
- const after = await runCmd("npm", ["view", SELF_UPDATE_PKG, "version"], SELF_UPDATE_VIEW_TIMEOUT_MS);
17946
+ const after = await runCmd(
17947
+ "npm",
17948
+ ["view", SELF_UPDATE_PKG, "version"],
17949
+ SELF_UPDATE_VIEW_TIMEOUT_MS
17950
+ );
17904
17951
  const installed = after.code === 0 ? after.stdout.trim() || latest : latest;
17905
17952
  return { status: "updated", version: installed };
17906
17953
  } catch (err) {
@@ -17947,6 +17994,8 @@ var HostAgentSupervisor = class {
17947
17994
  this.spawnChild = deps.spawnChild ?? defaultSpawner;
17948
17995
  this.resolveAgentAuth = deps.resolveAgentAuth ?? unsealAgentAuth;
17949
17996
  this.setupHeadroom = deps.setupHeadroom ?? setupHeadroomForSelfHosted;
17997
+ this.isHeadroomInstalled = deps.isHeadroomInstalled ?? (() => defaultHeadroomRunner.which("headroom"));
17998
+ this.getFreeDisk = deps.getFreeDisk ?? getFreeDiskBytes;
17950
17999
  this.metrics = deps.metricsCollector ?? new MetricsCollector();
17951
18000
  this.onIdentityRejected = deps.onIdentityRejected ?? defaultOnIdentityRejected;
17952
18001
  this.disableService = deps.disableService ?? defaultDisableService;
@@ -17960,6 +18009,10 @@ var HostAgentSupervisor = class {
17960
18009
  spawnChild;
17961
18010
  resolveAgentAuth;
17962
18011
  setupHeadroom;
18012
+ /** Probe whether Headroom is already installed (defaults to `which headroom`). */
18013
+ isHeadroomInstalled;
18014
+ /** Free-disk reader for the install preflight (defaults to getFreeDiskBytes). */
18015
+ getFreeDisk;
17963
18016
  relay = null;
17964
18017
  heartbeatTimer = null;
17965
18018
  /** Periodic self-update timer (npm check + install + restart). */
@@ -18258,8 +18311,9 @@ var HostAgentSupervisor = class {
18258
18311
  }
18259
18312
  if (payload.headroomEnabled && payload.headroomAgent && payload.headroomSavingsIngestUrl) {
18260
18313
  report("headroom", "setting up Headroom proxy");
18261
- const freeBytes = await getFreeDiskBytes(os32.homedir());
18262
- if (freeBytes !== null && freeBytes < HEADROOM_MIN_FREE_DISK_BYTES) {
18314
+ const freeBytes = await this.getFreeDisk(os32.homedir());
18315
+ const alreadyInstalled = this.isHeadroomInstalled();
18316
+ if (!alreadyInstalled && freeBytes !== null && freeBytes < HEADROOM_MIN_FREE_DISK_BYTES) {
18263
18317
  const freeGb = (freeBytes / 1e9).toFixed(1);
18264
18318
  const needGb = Math.round(HEADROOM_MIN_FREE_DISK_BYTES / 1e9);
18265
18319
  report(
@@ -18272,6 +18326,12 @@ var HostAgentSupervisor = class {
18272
18326
  );
18273
18327
  persistHeadroomConfig({ enabled: false });
18274
18328
  } else {
18329
+ if (alreadyInstalled && freeBytes !== null && freeBytes < HEADROOM_MIN_FREE_DISK_BYTES) {
18330
+ log.info(
18331
+ "host-agent",
18332
+ `Headroom already installed \u2014 bypassing install disk gate (free=${(freeBytes / 1e9).toFixed(1)}GB); reporting stays enabled`
18333
+ );
18334
+ }
18275
18335
  const headroomOk = await this.setupHeadroom(payload.headroomAgent);
18276
18336
  if (headroomOk) {
18277
18337
  persistHeadroomConfig({
@@ -18279,10 +18339,16 @@ var HostAgentSupervisor = class {
18279
18339
  agent: agentIdToHeadroomKind(payload.headroomAgent),
18280
18340
  ingestUrl: payload.headroomSavingsIngestUrl
18281
18341
  });
18282
- log.info("host-agent", "Headroom proxy ready; persisted headroom config for child spawns");
18342
+ log.info(
18343
+ "host-agent",
18344
+ "Headroom proxy ready; persisted headroom config for child spawns"
18345
+ );
18283
18346
  } else {
18284
18347
  persistHeadroomConfig({ enabled: false });
18285
- log.warn("host-agent", "Headroom setup failed (best-effort) \u2014 child will run without Headroom");
18348
+ log.warn(
18349
+ "host-agent",
18350
+ "Headroom setup failed (best-effort) \u2014 child will run without Headroom"
18351
+ );
18286
18352
  }
18287
18353
  }
18288
18354
  } else if (payload.headroomEnabled === false) {
@@ -18313,7 +18379,9 @@ var HostAgentSupervisor = class {
18313
18379
  void reportSessionEvent(
18314
18380
  { hostId: this.identity.hostId, hostToken: this.identity.hostToken },
18315
18381
  { event: "ended", deployId: payload.deployId }
18316
- ).catch((err) => log.trace("host-agent", "session ended report failed (best-effort)", err));
18382
+ ).catch(
18383
+ (err) => log.trace("host-agent", "session ended report failed (best-effort)", err)
18384
+ );
18317
18385
  }
18318
18386
  if (tracked && typeof code === "number" && code !== 0) {
18319
18387
  const detail = tail.trim().slice(-500);
@@ -18377,7 +18445,10 @@ var HostAgentSupervisor = class {
18377
18445
  resolve7();
18378
18446
  };
18379
18447
  const timer = setTimeout(() => {
18380
- log.warn("host-agent", "agent install timed out (180s) \u2014 preview detection may be unavailable");
18448
+ log.warn(
18449
+ "host-agent",
18450
+ "agent install timed out (180s) \u2014 preview detection may be unavailable"
18451
+ );
18381
18452
  try {
18382
18453
  child.kill("SIGTERM");
18383
18454
  } catch {
@@ -18387,7 +18458,10 @@ var HostAgentSupervisor = class {
18387
18458
  child.once("exit", (code) => {
18388
18459
  clearTimeout(timer);
18389
18460
  if (code !== 0) {
18390
- log.warn("host-agent", `agent install exited code=${code} \u2014 preview detection may be unavailable; agent still runs`);
18461
+ log.warn(
18462
+ "host-agent",
18463
+ `agent install exited code=${code} \u2014 preview detection may be unavailable; agent still runs`
18464
+ );
18391
18465
  } else {
18392
18466
  log.info("host-agent", "agent CLI installed");
18393
18467
  }
@@ -28525,7 +28599,7 @@ function checkChokidar() {
28525
28599
  }
28526
28600
  async function doctor(args2 = []) {
28527
28601
  const json = args2.includes("--json");
28528
- const cliVersion = true ? "2.39.77" : "0.0.0-dev";
28602
+ const cliVersion = true ? "2.39.79" : "0.0.0-dev";
28529
28603
  const apiBase2 = resolveApiBaseUrl();
28530
28604
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
28531
28605
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -28724,7 +28798,7 @@ async function completion(args2) {
28724
28798
  // src/commands/version.ts
28725
28799
  var import_picocolors14 = __toESM(require("picocolors"));
28726
28800
  function version2() {
28727
- const v = true ? "2.39.77" : "unknown";
28801
+ const v = true ? "2.39.79" : "unknown";
28728
28802
  console.log(`${import_picocolors14.default.bold("codeam-cli")} ${import_picocolors14.default.cyan(v)}`);
28729
28803
  }
28730
28804
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.39.77",
3
+ "version": "2.39.79",
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",