codeam-cli 2.75.32 → 2.75.33

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.75.32] — 2026-09-26
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Clear a preview that died with its machine on the first heartbeat (#828)
12
+
7
13
  ## [2.75.31] — 2026-09-26
8
14
 
9
15
  ### Fixed
package/dist/index.js CHANGED
@@ -10516,7 +10516,7 @@ function readAnonId() {
10516
10516
  }
10517
10517
  function superProperties() {
10518
10518
  return {
10519
- cliVersion: true ? "2.75.32" : "0.0.0-dev",
10519
+ cliVersion: true ? "2.75.33" : "0.0.0-dev",
10520
10520
  nodeVersion: process.version,
10521
10521
  platform: process.platform,
10522
10522
  arch: process.arch,
@@ -10758,7 +10758,7 @@ var http = __toESM(require("http"));
10758
10758
  // package.json
10759
10759
  var package_default = {
10760
10760
  name: "codeam-cli",
10761
- version: "2.75.32",
10761
+ version: "2.75.33",
10762
10762
  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.",
10763
10763
  type: "commonjs",
10764
10764
  main: "dist/index.js",
@@ -12088,7 +12088,7 @@ var CommandRelayService = class _CommandRelayService {
12088
12088
  // fresh + clear the "CLI update available" banner after a self-update
12089
12089
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
12090
12090
  // pair/reconnect). Older backends ignore the extra field.
12091
- ..."2.75.32" ? { ideVersion: "2.75.32" } : {}
12091
+ ..."2.75.33" ? { ideVersion: "2.75.33" } : {}
12092
12092
  };
12093
12093
  try {
12094
12094
  const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body);
@@ -36325,10 +36325,33 @@ var codexProvisioner = {
36325
36325
  writeFile0600(authJson, JSON.stringify({ auth_mode: "apikey", OPENAI_API_KEY: auth.value }));
36326
36326
  return { OPENAI_API_KEY: auth.value };
36327
36327
  }
36328
- writeFile0600(authJson, auth.value);
36328
+ if (!keepsFresherCodexLogin(authJson, auth.value)) writeFile0600(authJson, auth.value);
36329
36329
  return {};
36330
36330
  }
36331
36331
  };
36332
+ function codexLoginStamp(raw) {
36333
+ try {
36334
+ const blob = JSON.parse(raw);
36335
+ const refreshedAt = typeof blob.last_refresh === "string" ? Date.parse(blob.last_refresh) : NaN;
36336
+ const accountId = blob.tokens?.account_id;
36337
+ if (!Number.isFinite(refreshedAt) || typeof accountId !== "string" || !accountId) return null;
36338
+ return { refreshedAt, accountId };
36339
+ } catch {
36340
+ return null;
36341
+ }
36342
+ }
36343
+ function keepsFresherCodexLogin(authJsonPath, incoming) {
36344
+ let onDisk;
36345
+ try {
36346
+ onDisk = fs58.readFileSync(authJsonPath, "utf8");
36347
+ } catch {
36348
+ return false;
36349
+ }
36350
+ const current2 = codexLoginStamp(onDisk);
36351
+ const next = codexLoginStamp(incoming);
36352
+ if (!current2 || !next) return false;
36353
+ return current2.accountId === next.accountId && current2.refreshedAt > next.refreshedAt;
36354
+ }
36332
36355
  var geminiProvisioner = {
36333
36356
  write(auth, home) {
36334
36357
  const settingsJson = path68.join(home, ".gemini", "settings.json");
@@ -47897,6 +47920,15 @@ function loadHostIdentity() {
47897
47920
  return null;
47898
47921
  }
47899
47922
  }
47923
+ function pollSecretHash(secret) {
47924
+ return (0, import_node_crypto12.createHash)("sha256").update(secret).digest("hex");
47925
+ }
47926
+ function ensureControlPollSecret(identity, save = saveHostIdentity) {
47927
+ if (!identity || identity.controlPollSecret) return identity;
47928
+ const upgraded = { ...identity, controlPollSecret: (0, import_node_crypto12.randomBytes)(32).toString("base64url") };
47929
+ save(upgraded);
47930
+ return upgraded;
47931
+ }
47900
47932
  function saveHostIdentity(identity) {
47901
47933
  const file = hostIdentityPath();
47902
47934
  fs75.mkdirSync(path89.dirname(file), { recursive: true, mode: 448 });
@@ -47995,7 +48027,11 @@ async function sendHostHeartbeat(identity, metrics) {
47995
48027
  await postJson("/api/self-hosted/heartbeat", {
47996
48028
  hostId: identity.hostId,
47997
48029
  hostToken: identity.hostToken,
47998
- ...metrics ? { metrics } : {}
48030
+ ...metrics ? { metrics } : {},
48031
+ // The backend enrols this ONLY if the control plugin has no secret yet
48032
+ // (first writer wins), so re-sending it every beat is idempotent — and it
48033
+ // is the one way a host that never had one (or lost it) gets it back.
48034
+ ...identity.controlPollSecret ? { pluginSecretHash: pollSecretHash(identity.controlPollSecret) } : {}
47999
48035
  });
48000
48036
  const elapsedNs = process.hrtime.bigint() - start2;
48001
48037
  return Math.round(Number(elapsedNs) / 1e6);
@@ -48674,7 +48710,7 @@ async function autoUpgradeBeforeCriticalCommand() {
48674
48710
  if (process.env.NODE_ENV === "test") return;
48675
48711
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
48676
48712
  if (process.env.CI) return;
48677
- const current2 = true ? "2.75.32" : null;
48713
+ const current2 = true ? "2.75.33" : null;
48678
48714
  if (!current2) return;
48679
48715
  const cache = readCache();
48680
48716
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -48691,7 +48727,7 @@ function checkForUpdates() {
48691
48727
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
48692
48728
  if (process.env.CI) return;
48693
48729
  if (!process.stdout.isTTY) return;
48694
- const current2 = true ? "2.75.32" : null;
48730
+ const current2 = true ? "2.75.33" : null;
48695
48731
  if (!current2) return;
48696
48732
  const cache = readCache();
48697
48733
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -48714,7 +48750,7 @@ var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
48714
48750
  var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
48715
48751
  var SUDO_PREFLIGHT_TIMEOUT_MS = 5e3;
48716
48752
  function currentCliVersion() {
48717
- return true ? "2.75.32" : null;
48753
+ return true ? "2.75.33" : null;
48718
48754
  }
48719
48755
  async function installedVersion(deps) {
48720
48756
  const ls = await deps.run(
@@ -50386,7 +50422,7 @@ var HostAgentSupervisor = class {
50386
50422
  }
50387
50423
  };
50388
50424
  async function resolveHostIdentity(enrollToken) {
50389
- const existing = loadHostIdentity();
50425
+ const existing = ensureControlPollSecret(loadHostIdentity());
50390
50426
  if (enrollToken) {
50391
50427
  await reportProgress({ enrollToken }, "redeeming", "redeeming enrollment token\u2026");
50392
50428
  try {
@@ -50679,7 +50715,7 @@ function checkChokidar() {
50679
50715
  }
50680
50716
  async function doctor(args2 = []) {
50681
50717
  const json = args2.includes("--json");
50682
- const cliVersion = true ? "2.75.32" : "0.0.0-dev";
50718
+ const cliVersion = true ? "2.75.33" : "0.0.0-dev";
50683
50719
  const apiBase2 = resolveApiBaseUrl();
50684
50720
  const diagnosticId = (0, import_node_crypto13.randomUUID)();
50685
50721
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -51203,7 +51239,7 @@ async function mcpWarm(argv = [], opts = {}) {
51203
51239
  // src/commands/version.ts
51204
51240
  var import_picocolors15 = __toESM(require("picocolors"));
51205
51241
  function version2() {
51206
- const v = true ? "2.75.32" : "unknown";
51242
+ const v = true ? "2.75.33" : "unknown";
51207
51243
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
51208
51244
  }
51209
51245
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.75.32",
3
+ "version": "2.75.33",
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",