codeam-cli 2.51.3 → 2.52.1

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 (3) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/index.js +127 -11
  3. 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.52.0] — 2026-06-29
8
+
9
+ ### Added
10
+
11
+ - **cli:** Add cli_self_update relay command handler (tap-to-update)
12
+
13
+ ### Fixed
14
+
15
+ - **cli:** Treat codespace as no-self-relaunch in cli_self_update
16
+
17
+ ## [2.51.3] — 2026-06-29
18
+
19
+ ### Fixed
20
+
21
+ - **cli:** Stop retrying on terminal enroll-token 4xx (ENROLL_TOKEN_EXPIRED / ENROLL_TOKEN_INVALID)
22
+
7
23
  ## [2.51.2] — 2026-06-29
8
24
 
9
25
  ### Fixed
package/dist/index.js CHANGED
@@ -5397,7 +5397,7 @@ function readAnonId() {
5397
5397
  }
5398
5398
  function superProperties() {
5399
5399
  return {
5400
- cliVersion: true ? "2.51.3" : "0.0.0-dev",
5400
+ cliVersion: true ? "2.52.1" : "0.0.0-dev",
5401
5401
  nodeVersion: process.version,
5402
5402
  platform: process.platform,
5403
5403
  arch: process.arch,
@@ -5578,7 +5578,7 @@ var os4 = __toESM(require("os"));
5578
5578
  // package.json
5579
5579
  var package_default = {
5580
5580
  name: "codeam-cli",
5581
- version: "2.51.3",
5581
+ version: "2.52.1",
5582
5582
  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.",
5583
5583
  type: "commonjs",
5584
5584
  main: "dist/index.js",
@@ -5734,7 +5734,17 @@ async function fetchCurrentPluginAuthToken(sessionId, pluginId, pollSecret) {
5734
5734
  try {
5735
5735
  const result = await _transport.postJson(
5736
5736
  `${API_BASE}/api/pairing/reconnect`,
5737
- { sessionId, pluginId },
5737
+ {
5738
+ sessionId,
5739
+ pluginId,
5740
+ // Send the running CLI version so the backend keeps
5741
+ // PairedSession.ideVersion current across restarts. This fixes the
5742
+ // stale "CLI update available" banner that showed an outdated version
5743
+ // after the CLI restarted on a new release and took the reconnect
5744
+ // path (which previously never updated ideVersion). Backends older
5745
+ // than the matching fix ignore the unknown field (backward-compat).
5746
+ ideVersion: package_default.version
5747
+ },
5738
5748
  // SEC: prove possession so the gated /reconnect returns the token.
5739
5749
  // Omitted for legacy sessions (no secret) → backend legacy path.
5740
5750
  pollSecret ? { "X-Plugin-Poll-Secret": pollSecret } : void 0
@@ -5893,6 +5903,30 @@ async function postBeadsEvent(input) {
5893
5903
  };
5894
5904
  }
5895
5905
  }
5906
+ async function postCliUpdateEvent(input) {
5907
+ try {
5908
+ const payload = { phase: input.phase };
5909
+ if (input.error) payload.error = input.error;
5910
+ await _transport.postJsonAuthed(
5911
+ `${API_BASE}/api/agents/cli-update/events`,
5912
+ {
5913
+ sessionId: input.sessionId,
5914
+ pluginId: input.pluginId,
5915
+ phase: input.phase,
5916
+ ...input.error ? { error: input.error } : {}
5917
+ },
5918
+ input.pluginAuthToken
5919
+ );
5920
+ return { ok: true };
5921
+ } catch (err) {
5922
+ const e = err;
5923
+ return {
5924
+ ok: false,
5925
+ status: typeof e.statusCode === "number" ? e.statusCode : 0,
5926
+ message: e.message || "unknown"
5927
+ };
5928
+ }
5929
+ }
5896
5930
  async function postBeadsProvisioning(input) {
5897
5931
  try {
5898
5932
  await _transport.postJsonAuthed(
@@ -14829,7 +14863,7 @@ async function autoUpgradeBeforeCriticalCommand() {
14829
14863
  if (process.env.NODE_ENV === "test") return;
14830
14864
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
14831
14865
  if (process.env.CI) return;
14832
- const current = true ? "2.51.3" : null;
14866
+ const current = true ? "2.52.1" : null;
14833
14867
  if (!current) return;
14834
14868
  const cache = readCache();
14835
14869
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -14846,7 +14880,7 @@ function checkForUpdates() {
14846
14880
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
14847
14881
  if (process.env.CI) return;
14848
14882
  if (!process.stdout.isTTY) return;
14849
- const current = true ? "2.51.3" : null;
14883
+ const current = true ? "2.52.1" : null;
14850
14884
  if (!current) return;
14851
14885
  const cache = readCache();
14852
14886
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -15548,7 +15582,7 @@ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process15.s
15548
15582
  detached: false
15549
15583
  });
15550
15584
  function currentCliVersion() {
15551
- return true ? "2.51.3" : null;
15585
+ return true ? "2.52.1" : null;
15552
15586
  }
15553
15587
  function runCmd(cmd, args2, timeoutMs) {
15554
15588
  return new Promise((resolve7) => {
@@ -18946,6 +18980,87 @@ var beadsConfigureH = async (ctx, cmd, parsed) => {
18946
18980
  const result = await configureBeads(action, { agent: rawAgentId, cwd: process.cwd(), pluginAuthToken: ctx.pluginAuthToken }, deps);
18947
18981
  await ctx.relay.sendResult(cmd.id, "completed", result);
18948
18982
  };
18983
+ var defaultCliUpdateDeps = {
18984
+ install: () => runNpmInstallLatest(),
18985
+ // "Don't self-relaunch" gate — leave this process running and let the
18986
+ // on-disk update apply on the next natural restart, instead of killing it:
18987
+ // - self-hosted (CODEAM_AUTO_APPROVE=1): the HostAgentSupervisor does NOT
18988
+ // auto-restart children on exit, so exiting would orphan the session.
18989
+ // - codespace (CODESPACES=true): the pair-auto daemon owns a daemon lock +
18990
+ // the relay connection; a naive detached re-exec does NOT replicate the
18991
+ // careful setsid/lock-aware restart the install flow uses, so a failed
18992
+ // respawn would leave the mobile session permanently OFFLINE. Codespaces
18993
+ // sleep/resume often, so the update lands on next wake — safe + non-fatal.
18994
+ // Only a truly local `codeam start` (neither marker) re-execs in place below.
18995
+ isSupervised: () => process.env["CODEAM_AUTO_APPROVE"] === "1" || process.env["CODESPACES"] === "true",
18996
+ relaunch: (args2) => {
18997
+ const entry = process.argv[1];
18998
+ const child = (0, import_child_process21.spawn)(process.execPath, [entry, ...args2], {
18999
+ detached: true,
19000
+ stdio: "inherit"
19001
+ });
19002
+ child.unref();
19003
+ process.exit(0);
19004
+ }
19005
+ };
19006
+ var CLI_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
19007
+ var CLI_UPDATE_MAX_ATTEMPTS = 3;
19008
+ async function runNpmInstallLatest() {
19009
+ let lastError = "";
19010
+ for (let attempt = 1; attempt <= CLI_UPDATE_MAX_ATTEMPTS; attempt++) {
19011
+ const result = await new Promise((resolve7) => {
19012
+ (0, import_child_process21.execFile)(
19013
+ "npm",
19014
+ ["install", "-g", "codeam-cli@latest"],
19015
+ { timeout: CLI_UPDATE_INSTALL_TIMEOUT_MS },
19016
+ (err, _stdout, stderr) => {
19017
+ if (!err) {
19018
+ resolve7({ ok: true });
19019
+ } else {
19020
+ resolve7({ ok: false, error: (stderr || err.message).slice(0, 300) });
19021
+ }
19022
+ }
19023
+ );
19024
+ });
19025
+ if (result.ok) return { ok: true };
19026
+ lastError = result.error ?? "unknown";
19027
+ if (attempt < CLI_UPDATE_MAX_ATTEMPTS) {
19028
+ await new Promise((r) => setTimeout(r, 1e3 * attempt));
19029
+ }
19030
+ }
19031
+ return { ok: false, error: lastError };
19032
+ }
19033
+ var cliSelfUpdateH = (deps = defaultCliUpdateDeps) => async (ctx, cmd) => {
19034
+ const report = async (phase, error) => {
19035
+ if (!ctx.pluginAuthToken) return;
19036
+ try {
19037
+ await postCliUpdateEvent({
19038
+ sessionId: ctx.sessionId,
19039
+ pluginId: ctx.pluginId,
19040
+ pluginAuthToken: ctx.pluginAuthToken,
19041
+ phase,
19042
+ error
19043
+ });
19044
+ } catch {
19045
+ }
19046
+ };
19047
+ await report("updating");
19048
+ const result = await deps.install();
19049
+ if (!result.ok) {
19050
+ await report("failed", result.error?.slice(0, 200));
19051
+ await ctx.relay.sendResult(cmd.id, "completed", { updated: false });
19052
+ return;
19053
+ }
19054
+ await report("relaunching");
19055
+ await ctx.relay.sendResult(cmd.id, "completed", { updated: true });
19056
+ if (deps.isSupervised()) {
19057
+ log.info("cli-update", "supervised context \u2014 update installed, applies on next restart");
19058
+ return;
19059
+ }
19060
+ const origArgs = process.argv.slice(2);
19061
+ log.info("cli-update", `re-execing ${process.argv[1]} with args: ${origArgs.join(" ")}`);
19062
+ deps.relaunch(origArgs);
19063
+ };
18949
19064
  var terminalOpenH = async (ctx, cmd, parsed) => {
18950
19065
  const r = openTerminal({
18951
19066
  cols: typeof parsed.cols === "number" ? parsed.cols : void 0,
@@ -19933,7 +20048,8 @@ var handlers = {
19933
20048
  env_write: envWriteH,
19934
20049
  headroom_configure: headroomConfigureH,
19935
20050
  headroom_budget: headroomBudgetH,
19936
- beads_configure: beadsConfigureH
20051
+ beads_configure: beadsConfigureH,
20052
+ cli_self_update: cliSelfUpdateH()
19937
20053
  };
19938
20054
  async function dispatchCommand(ctx, cmd) {
19939
20055
  if (cmd.type === "beads_action") {
@@ -30802,9 +30918,9 @@ async function probeCodeamPair(provider, workspace) {
30802
30918
  }
30803
30919
  async function stopWorkspaceFromLocal(target) {
30804
30920
  if (target.provider.id === "github-codespaces") {
30805
- const { execFile: execFile13 } = await import("child_process");
30921
+ const { execFile: execFile14 } = await import("child_process");
30806
30922
  const { promisify: promisify11 } = await import("util");
30807
- const execFileP10 = promisify11(execFile13);
30923
+ const execFileP10 = promisify11(execFile14);
30808
30924
  await execFileP10("gh", ["codespace", "stop", "-c", target.id], { maxBuffer: 8 * 1024 * 1024 });
30809
30925
  return;
30810
30926
  }
@@ -31086,7 +31202,7 @@ function checkChokidar() {
31086
31202
  }
31087
31203
  async function doctor(args2 = []) {
31088
31204
  const json = args2.includes("--json");
31089
- const cliVersion = true ? "2.51.3" : "0.0.0-dev";
31205
+ const cliVersion = true ? "2.52.1" : "0.0.0-dev";
31090
31206
  const apiBase2 = resolveApiBaseUrl();
31091
31207
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
31092
31208
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -31285,7 +31401,7 @@ async function completion(args2) {
31285
31401
  // src/commands/version.ts
31286
31402
  var import_picocolors15 = __toESM(require("picocolors"));
31287
31403
  function version2() {
31288
- const v = true ? "2.51.3" : "unknown";
31404
+ const v = true ? "2.52.1" : "unknown";
31289
31405
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
31290
31406
  }
31291
31407
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.51.3",
3
+ "version": "2.52.1",
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",