codeam-cli 2.39.29 → 2.39.30

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.29] — 2026-06-18
8
+
9
+ ### Added
10
+
11
+ - **cli:** Report host-agent enrollment progress to backend
12
+
7
13
  ## [2.39.28] — 2026-06-18
8
14
 
9
15
  ### Added
package/dist/index.js CHANGED
@@ -498,7 +498,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
498
498
  // package.json
499
499
  var package_default = {
500
500
  name: "codeam-cli",
501
- version: "2.39.29",
501
+ version: "2.39.30",
502
502
  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.",
503
503
  type: "commonjs",
504
504
  main: "dist/index.js",
@@ -5908,7 +5908,7 @@ function readAnonId() {
5908
5908
  }
5909
5909
  function superProperties() {
5910
5910
  return {
5911
- cliVersion: true ? "2.39.29" : "0.0.0-dev",
5911
+ cliVersion: true ? "2.39.30" : "0.0.0-dev",
5912
5912
  nodeVersion: process.version,
5913
5913
  platform: process.platform,
5914
5914
  arch: process.arch,
@@ -26205,6 +26205,48 @@ async function stopWorkspaceFromLocal(target) {
26205
26205
  var fs41 = __toESM(require("fs"));
26206
26206
  var os32 = __toESM(require("os"));
26207
26207
  var path53 = __toESM(require("path"));
26208
+ function sampleCpuTimes() {
26209
+ let idle = 0;
26210
+ let total = 0;
26211
+ for (const cpu of os32.cpus()) {
26212
+ const t2 = cpu.times;
26213
+ idle += t2.idle;
26214
+ total += t2.user + t2.nice + t2.sys + t2.idle + t2.irq;
26215
+ }
26216
+ return { idle, total };
26217
+ }
26218
+ var MetricsCollector = class {
26219
+ prevCpu = null;
26220
+ lastLatencyMs = 0;
26221
+ /** Record the measured round-trip of the heartbeat just sent. */
26222
+ recordLatency(latencyMs) {
26223
+ this.lastLatencyMs = Math.max(0, Math.round(latencyMs));
26224
+ }
26225
+ cpuPct() {
26226
+ const current = sampleCpuTimes();
26227
+ const prev = this.prevCpu;
26228
+ this.prevCpu = current;
26229
+ if (!prev) {
26230
+ const cores = os32.cpus().length || 1;
26231
+ const proxy = os32.loadavg()[0] / cores * 100;
26232
+ return Math.min(100, Math.max(0, Math.round(proxy)));
26233
+ }
26234
+ const idleDelta = current.idle - prev.idle;
26235
+ const totalDelta = current.total - prev.total;
26236
+ if (totalDelta <= 0) return 0;
26237
+ const busy = (1 - idleDelta / totalDelta) * 100;
26238
+ return Math.min(100, Math.max(0, Math.round(busy)));
26239
+ }
26240
+ /** Collect the current metrics snapshot for this beat. */
26241
+ collect() {
26242
+ return {
26243
+ cpuPct: this.cpuPct(),
26244
+ ramUsedMb: Math.round((os32.totalmem() - os32.freemem()) / 1048576),
26245
+ ramTotalMb: Math.round(os32.totalmem() / 1048576),
26246
+ latencyMs: this.lastLatencyMs
26247
+ };
26248
+ }
26249
+ };
26208
26250
  function apiBase() {
26209
26251
  return process.env.CODEAM_API_URL ?? resolveApiBaseUrl();
26210
26252
  }
@@ -26268,11 +26310,15 @@ async function redeemEnrollToken(token, label) {
26268
26310
  controlPluginId: data.controlPluginId
26269
26311
  };
26270
26312
  }
26271
- async function sendHostHeartbeat(identity) {
26313
+ async function sendHostHeartbeat(identity, metrics) {
26314
+ const start2 = process.hrtime.bigint();
26272
26315
  await postJson("/api/self-hosted/heartbeat", {
26273
26316
  hostId: identity.hostId,
26274
- hostToken: identity.hostToken
26317
+ hostToken: identity.hostToken,
26318
+ ...metrics ? { metrics } : {}
26275
26319
  });
26320
+ const elapsedNs = process.hrtime.bigint() - start2;
26321
+ return Math.round(Number(elapsedNs) / 1e6);
26276
26322
  }
26277
26323
  function isSealedEnvelope(v) {
26278
26324
  if (typeof v !== "object" || v === null) return false;
@@ -26515,6 +26561,7 @@ var HostAgentSupervisor = class {
26515
26561
  this.deps = deps;
26516
26562
  this.spawnChild = deps.spawnChild ?? defaultSpawner;
26517
26563
  this.resolveAgentAuth = deps.resolveAgentAuth ?? unsealAgentAuth;
26564
+ this.metrics = deps.metricsCollector ?? new MetricsCollector();
26518
26565
  }
26519
26566
  identity;
26520
26567
  deps;
@@ -26525,6 +26572,8 @@ var HostAgentSupervisor = class {
26525
26572
  heartbeatTimer = null;
26526
26573
  /** Guards the one-shot 'connected' telemetry on the first heartbeat. */
26527
26574
  reportedConnected = false;
26575
+ /** Live-metrics collector — stateful across beats (CPU delta + latency). */
26576
+ metrics;
26528
26577
  /** Open the control channel (reusing the relay) + start heartbeats. */
26529
26578
  start() {
26530
26579
  const make = this.deps.makeRelay ?? ((pluginId, onCommand, meta) => new CommandRelayService(pluginId, onCommand, meta));
@@ -26556,7 +26605,14 @@ var HostAgentSupervisor = class {
26556
26605
  }
26557
26606
  async beat() {
26558
26607
  try {
26559
- await sendHostHeartbeat(this.identity);
26608
+ let metrics;
26609
+ try {
26610
+ metrics = this.metrics.collect();
26611
+ } catch (err) {
26612
+ log.trace("host-agent", "metrics collection failed", err);
26613
+ }
26614
+ const latencyMs = await sendHostHeartbeat(this.identity, metrics);
26615
+ this.metrics.recordLatency(latencyMs);
26560
26616
  if (!this.reportedConnected) {
26561
26617
  this.reportedConnected = true;
26562
26618
  void reportProgress(
@@ -26875,7 +26931,7 @@ function checkChokidar() {
26875
26931
  }
26876
26932
  async function doctor(args2 = []) {
26877
26933
  const json = args2.includes("--json");
26878
- const cliVersion = true ? "2.39.29" : "0.0.0-dev";
26934
+ const cliVersion = true ? "2.39.30" : "0.0.0-dev";
26879
26935
  const apiBase2 = resolveApiBaseUrl();
26880
26936
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
26881
26937
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -27074,7 +27130,7 @@ async function completion(args2) {
27074
27130
  // src/commands/version.ts
27075
27131
  var import_picocolors13 = __toESM(require("picocolors"));
27076
27132
  function version2() {
27077
- const v = true ? "2.39.29" : "unknown";
27133
+ const v = true ? "2.39.30" : "unknown";
27078
27134
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
27079
27135
  }
27080
27136
 
@@ -27360,7 +27416,7 @@ function checkForUpdates() {
27360
27416
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
27361
27417
  if (process.env.CI) return;
27362
27418
  if (!process.stdout.isTTY) return;
27363
- const current = true ? "2.39.29" : null;
27419
+ const current = true ? "2.39.30" : null;
27364
27420
  if (!current) return;
27365
27421
  const cache = readCache();
27366
27422
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.39.29",
3
+ "version": "2.39.30",
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",