codeam-cli 2.72.0 → 2.73.0

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.
Files changed (2) hide show
  1. package/dist/index.js +117 -9
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1750,7 +1750,12 @@ var INTEGRATION_REGISTRY = {
1750
1750
  label: "Token",
1751
1751
  placeholder: "Your Trello token",
1752
1752
  secret: true,
1753
- help: 'On the API-key page, click the "Token" link to authorize + generate a token (scope read,write, never-expiring).'
1753
+ // WARNING - the Power-Up API-key page also shows a "Secret", and it is
1754
+ // NOT the token: both are 64 hex characters and look identical, so it
1755
+ // is the natural thing to copy. Pasting the Secret fails with Trello's
1756
+ // misleading `invalid key`, which then sends the user to regenerate a
1757
+ // perfectly good API key (owner report, 2026-09-01). Say so here.
1758
+ help: 'On that same API-key page, click the "Token" link to authorize and generate a token (read,write, never-expiring). NOT the "Secret" on that page - it looks identical but will not work.'
1754
1759
  }
1755
1760
  ]
1756
1761
  },
@@ -8092,7 +8097,7 @@ function readAnonId() {
8092
8097
  }
8093
8098
  function superProperties() {
8094
8099
  return {
8095
- cliVersion: true ? "2.72.0" : "0.0.0-dev",
8100
+ cliVersion: true ? "2.73.0" : "0.0.0-dev",
8096
8101
  nodeVersion: process.version,
8097
8102
  platform: process.platform,
8098
8103
  arch: process.arch,
@@ -8334,7 +8339,7 @@ var http = __toESM(require("http"));
8334
8339
  // package.json
8335
8340
  var package_default = {
8336
8341
  name: "codeam-cli",
8337
- version: "2.72.0",
8342
+ version: "2.73.0",
8338
8343
  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.",
8339
8344
  type: "commonjs",
8340
8345
  main: "dist/index.js",
@@ -9927,7 +9932,7 @@ var CommandRelayService = class _CommandRelayService {
9927
9932
  // fresh + clear the "CLI update available" banner after a self-update
9928
9933
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
9929
9934
  // pair/reconnect). Older backends ignore the extra field.
9930
- ..."2.72.0" ? { ideVersion: "2.72.0" } : {}
9935
+ ..."2.73.0" ? { ideVersion: "2.73.0" } : {}
9931
9936
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
9932
9937
  }
9933
9938
  /**
@@ -22193,7 +22198,7 @@ async function autoUpgradeBeforeCriticalCommand() {
22193
22198
  if (process.env.NODE_ENV === "test") return;
22194
22199
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
22195
22200
  if (process.env.CI) return;
22196
- const current2 = true ? "2.72.0" : null;
22201
+ const current2 = true ? "2.73.0" : null;
22197
22202
  if (!current2) return;
22198
22203
  const cache = readCache();
22199
22204
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -22210,7 +22215,7 @@ function checkForUpdates() {
22210
22215
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
22211
22216
  if (process.env.CI) return;
22212
22217
  if (!process.stdout.isTTY) return;
22213
- const current2 = true ? "2.72.0" : null;
22218
+ const current2 = true ? "2.73.0" : null;
22214
22219
  if (!current2) return;
22215
22220
  const cache = readCache();
22216
22221
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -22233,7 +22238,7 @@ var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
22233
22238
  var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
22234
22239
  var SUDO_PREFLIGHT_TIMEOUT_MS = 5e3;
22235
22240
  function currentCliVersion() {
22236
- return true ? "2.72.0" : null;
22241
+ return true ? "2.73.0" : null;
22237
22242
  }
22238
22243
  async function installedVersion(deps) {
22239
22244
  const ls = await deps.run(
@@ -22526,6 +22531,14 @@ function isFleetLimits(v) {
22526
22531
  function isFleetCreateBoxPayload(p2) {
22527
22532
  return typeof p2.boxId === "string" && isFleetContainerName(p2.containerName) && typeof p2.enrollToken === "string" && p2.enrollToken.length > 0 && typeof p2.apiOrigin === "string" && p2.apiOrigin.length > 0 && isFleetLimits(p2.limits);
22528
22533
  }
22534
+ function isFleetMigrateBoxImagePayload(p2) {
22535
+ return typeof p2.boxId === "string" && isFleetContainerName(p2.containerName) && typeof p2.apiOrigin === "string" && p2.apiOrigin.length > 0 && isFleetLimits(p2.limits) && // ⚠️ REJECT a token outright rather than ignoring it. A migrate that
22536
+ // carried one would bake a 15-minute credential into a container that may
22537
+ // not start for days — a terminal 4xx at boot, i.e. a box that never comes
22538
+ // back. If a future backend starts sending one, this must fail loudly here
22539
+ // rather than silently produce that box.
22540
+ p2.enrollToken === void 0;
22541
+ }
22529
22542
  function isFleetBoxRefPayload(p2) {
22530
22543
  if (typeof p2.boxId !== "string") return false;
22531
22544
  if (!isFleetContainerName(p2.containerName)) return false;
@@ -22557,6 +22570,9 @@ function isMissingVolumeError(stderr) {
22557
22570
  function resolveFleetBoxImage() {
22558
22571
  return process.env.CODEAM_FLEET_BOX_IMAGE || "ghcr.io/edgar-durand/codeam-box:latest";
22559
22572
  }
22573
+ function buildFleetBoxMigrateArgs(p2) {
22574
+ return buildFleetBoxRunArgs(p2).map((a) => a === "run" ? "create" : a).filter((a) => a !== "--pull=always" && a !== "-d");
22575
+ }
22560
22576
  function buildFleetBoxRunArgs(p2) {
22561
22577
  const userId = fleetUserIdFromContainerName(p2.containerName);
22562
22578
  const image = resolveFleetBoxImage();
@@ -22956,6 +22972,14 @@ var HostAgentSupervisor = class {
22956
22972
  await this.fleetCreateBox(cmd.payload);
22957
22973
  return;
22958
22974
  }
22975
+ if (cmd.type === "fleet_migrate_box_image") {
22976
+ if (!isFleetMigrateBoxImagePayload(cmd.payload)) {
22977
+ log.warn("host-agent", `ignoring malformed fleet_migrate_box_image id=${cmd.id}`);
22978
+ return;
22979
+ }
22980
+ await this.fleetMigrateBoxImage(cmd.payload);
22981
+ return;
22982
+ }
22959
22983
  if (cmd.type === "fleet_start_box") {
22960
22984
  if (!isFleetBoxRefPayload(cmd.payload)) {
22961
22985
  log.warn("host-agent", `ignoring malformed fleet_start_box id=${cmd.id}`);
@@ -23126,6 +23150,90 @@ var HostAgentSupervisor = class {
23126
23150
  }
23127
23151
  /** `fleet_start_box` — wake a sleeping box (`docker start`). Idempotent: a
23128
23152
  * container the host already removed is treated as success. */
23153
+ /**
23154
+ * `fleet_migrate_box_image` — re-point a SLEEPING box at the current
23155
+ * `:latest` without waking it, so the version it was pinned to becomes
23156
+ * reclaimable by the (already automated) dangling-image prune.
23157
+ *
23158
+ * WHY THIS IS NEEDED AT ALL. Boxes are created with `--pull=always` on
23159
+ * purpose, so each stays pinned to the image it was born on, and Docker
23160
+ * refuses to delete an image any container references INCLUDING stopped
23161
+ * ones — which is precisely what stops the prune from destroying a sleeping
23162
+ * user's box. So every image release strands ~7.7 GB per lagging box until it
23163
+ * wakes or is reaped on day 7 (fleet-1, 2026-09-02: 9 boxes across 4
23164
+ * versions, ~31 GB held).
23165
+ *
23166
+ * ⚠️ THE HOST RE-CHECKS THAT THE BOX IS STOPPED, even though the backend only
23167
+ * selects `status: 'SLEEPING'`. The DB's view can lag the host by a sweep —
23168
+ * a box that woke seconds ago is still SLEEPING in the row — and re-creating
23169
+ * a RUNNING container kills a live agent mid-turn. The authority on whether a
23170
+ * container is running is the daemon, so we ask it here and refuse rather
23171
+ * than trust the payload.
23172
+ *
23173
+ * ⚠️ `docker create`, and NO enroll token. `run` would start the container,
23174
+ * so migrating the sleeping set in a batch would wake all of them (9 ×
23175
+ * 1536 MB on a 16 GB host) only for the sleep sweep to re-sleep them 30
23176
+ * minutes later. And a token would be a 15-minute credential baked into a
23177
+ * container that may not start for days — a terminal 4xx at boot, i.e. a box
23178
+ * that never comes back. The sealed identity is in the named volume, which
23179
+ * `rm` WITHOUT `-v` preserves.
23180
+ *
23181
+ * Idempotent and best-effort: a box already on `:latest` is skipped, a
23182
+ * missing container is success (a concurrent reap), and nothing here may
23183
+ * throw into the relay — this is housekeeping.
23184
+ */
23185
+ async fleetMigrateBoxImage(payload) {
23186
+ const { containerName } = payload;
23187
+ const state = await this.docker.run([
23188
+ "inspect",
23189
+ "--format",
23190
+ "{{.State.Running}}",
23191
+ containerName
23192
+ ]);
23193
+ if (state.code !== 0) {
23194
+ if (isMissingContainerError(state.stderr)) return;
23195
+ log.warn(
23196
+ "host-agent",
23197
+ `fleet_migrate_box_image: inspect of ${containerName} failed (code=${state.code}) \u2014 skipping`
23198
+ );
23199
+ return;
23200
+ }
23201
+ if (state.stdout.trim() === "true") {
23202
+ log.info(
23203
+ "host-agent",
23204
+ `fleet_migrate_box_image: ${containerName} is RUNNING \u2014 skipping (never touch a live box)`
23205
+ );
23206
+ return;
23207
+ }
23208
+ if (!await this.fleetBoxImageStale(containerName)) {
23209
+ log.info("host-agent", `fleet_migrate_box_image: ${containerName} already current`);
23210
+ return;
23211
+ }
23212
+ const rm = await this.docker.run(["rm", "-f", containerName], {
23213
+ timeoutMs: DOCKER_RUN_TIMEOUT_MS
23214
+ });
23215
+ if (rm.code !== 0 && !isMissingContainerError(rm.stderr)) {
23216
+ log.warn(
23217
+ "host-agent",
23218
+ `fleet_migrate_box_image: rm of ${containerName} failed (code=${rm.code}): ${rm.stderr.trim().slice(-200)} \u2014 NOT creating a replacement`
23219
+ );
23220
+ return;
23221
+ }
23222
+ const res = await this.docker.run(buildFleetBoxMigrateArgs(payload), {
23223
+ timeoutMs: DOCKER_RUN_TIMEOUT_MS
23224
+ });
23225
+ if (res.code !== 0) {
23226
+ log.warn(
23227
+ "host-agent",
23228
+ `fleet_migrate_box_image: create of ${containerName} failed (code=${res.code}): ${res.stderr.trim().slice(-200)}`
23229
+ );
23230
+ return;
23231
+ }
23232
+ log.info(
23233
+ "host-agent",
23234
+ `fleet_migrate_box_image: ${containerName} re-pointed at :latest (still stopped)`
23235
+ );
23236
+ }
23129
23237
  async fleetStartBox(payload) {
23130
23238
  const { containerName } = payload;
23131
23239
  if (fleetRefCanRecreate(payload) && await this.fleetBoxImageStale(containerName)) {
@@ -46905,7 +47013,7 @@ function checkChokidar() {
46905
47013
  }
46906
47014
  async function doctor(args2 = []) {
46907
47015
  const json = args2.includes("--json");
46908
- const cliVersion = true ? "2.72.0" : "0.0.0-dev";
47016
+ const cliVersion = true ? "2.73.0" : "0.0.0-dev";
46909
47017
  const apiBase2 = resolveApiBaseUrl();
46910
47018
  const diagnosticId = (0, import_node_crypto13.randomUUID)();
46911
47019
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -47296,7 +47404,7 @@ async function mcpRun(args2) {
47296
47404
  // src/commands/version.ts
47297
47405
  var import_picocolors15 = __toESM(require("picocolors"));
47298
47406
  function version2() {
47299
- const v = true ? "2.72.0" : "unknown";
47407
+ const v = true ? "2.73.0" : "unknown";
47300
47408
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
47301
47409
  }
47302
47410
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.72.0",
3
+ "version": "2.73.0",
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",