codeam-cli 2.61.24 → 2.61.26

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,28 @@ 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.61.25] — 2026-07-23
8
+
9
+ ### Fixed
10
+
11
+ - **host-agent:** Enrol + present a control-channel poll secret (self-hosted deploy root fix)
12
+
13
+ ## [2.61.24] — 2026-07-22
14
+
15
+ ### Chore
16
+
17
+ - **cli:** Declare yaml as devDependency (skills materialize test)
18
+ - **deps:** Bump actions/setup-node from 4 to 7 (#452)
19
+ - **deps-dev:** Bump typescript from 6.0.3 to 7.0.2 in /apps/cli (#432)
20
+ - **deps-dev:** Bump typescript from 6.0.3 to 7.0.2 in /apps/vsc-plugin (#430)
21
+ - **deps:** Bump org.jetbrains.kotlin.jvm in /apps/jetbrains-plugin (#453)
22
+ - **deps:** Bump ignore from 5.3.2 to 7.0.6 in /apps/cli (#323)
23
+ - **deps:** Bump org.jetbrains.intellij.platform (#454)
24
+
25
+ ### Fixed
26
+
27
+ - **cli:** Break self-hosted enroll-token crash-loop on identity self-heal
28
+
7
29
  ## [2.61.23] — 2026-07-20
8
30
 
9
31
  ### Added
package/dist/index.js CHANGED
@@ -6117,7 +6117,7 @@ function readAnonId() {
6117
6117
  }
6118
6118
  function superProperties() {
6119
6119
  return {
6120
- cliVersion: true ? "2.61.24" : "0.0.0-dev",
6120
+ cliVersion: true ? "2.61.26" : "0.0.0-dev",
6121
6121
  nodeVersion: process.version,
6122
6122
  platform: process.platform,
6123
6123
  arch: process.arch,
@@ -6298,7 +6298,7 @@ var os4 = __toESM(require("os"));
6298
6298
  // package.json
6299
6299
  var package_default = {
6300
6300
  name: "codeam-cli",
6301
- version: "2.61.24",
6301
+ version: "2.61.26",
6302
6302
  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.",
6303
6303
  type: "commonjs",
6304
6304
  main: "dist/index.js",
@@ -7089,16 +7089,18 @@ var API_BASE2 = resolveApiBaseUrl();
7089
7089
  var SSE_LIVENESS_TIMEOUT_MS = 45e3;
7090
7090
  var SSE_WATCHDOG_INTERVAL_MS = 1e4;
7091
7091
  var CommandRelayService = class _CommandRelayService {
7092
- constructor(pluginId, onCommand, agentMeta, agentsOverride) {
7092
+ constructor(pluginId, onCommand, agentMeta, agentsOverride, explicitPollSecret) {
7093
7093
  this.pluginId = pluginId;
7094
7094
  this.onCommand = onCommand;
7095
7095
  this.agentMeta = agentMeta;
7096
7096
  this.agentsOverride = agentsOverride;
7097
+ this.explicitPollSecret = explicitPollSecret;
7097
7098
  }
7098
7099
  pluginId;
7099
7100
  onCommand;
7100
7101
  agentMeta;
7101
7102
  agentsOverride;
7103
+ explicitPollSecret;
7102
7104
  _running = false;
7103
7105
  pairingInvalid = false;
7104
7106
  heartbeatTimer = null;
@@ -7390,6 +7392,10 @@ var CommandRelayService = class _CommandRelayService {
7390
7392
  // backends (which ignore it).
7391
7393
  pollSecretHeader() {
7392
7394
  const headers = { "X-Codeam-Cmd-Ack": "1" };
7395
+ if (this.explicitPollSecret) {
7396
+ headers["X-Plugin-Poll-Secret"] = this.explicitPollSecret;
7397
+ return headers;
7398
+ }
7393
7399
  try {
7394
7400
  const secret = loadCliConfig().sessions.find(
7395
7401
  (s) => s.pluginId === this.pluginId
@@ -7463,7 +7469,7 @@ var CommandRelayService = class _CommandRelayService {
7463
7469
  // fresh + clear the "CLI update available" banner after a self-update
7464
7470
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
7465
7471
  // pair/reconnect). Older backends ignore the extra field.
7466
- ..."2.61.24" ? { ideVersion: "2.61.24" } : {}
7472
+ ..."2.61.26" ? { ideVersion: "2.61.26" } : {}
7467
7473
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
7468
7474
  }
7469
7475
  /**
@@ -16791,6 +16797,7 @@ function describeReason(reason) {
16791
16797
  var fs35 = __toESM(require("fs"));
16792
16798
  var os31 = __toESM(require("os"));
16793
16799
  var path39 = __toESM(require("path"));
16800
+ var import_node_crypto9 = require("crypto");
16794
16801
  function sampleCpuTimes() {
16795
16802
  let idle = 0;
16796
16803
  let total = 0;
@@ -16853,7 +16860,13 @@ function loadHostIdentity() {
16853
16860
  const parsed = JSON.parse(raw);
16854
16861
  if (typeof parsed === "object" && parsed !== null && typeof parsed.hostId === "string" && typeof parsed.hostToken === "string" && typeof parsed.controlPluginId === "string") {
16855
16862
  const p2 = parsed;
16856
- return { hostId: p2.hostId, hostToken: p2.hostToken, controlPluginId: p2.controlPluginId };
16863
+ return {
16864
+ hostId: p2.hostId,
16865
+ hostToken: p2.hostToken,
16866
+ controlPluginId: p2.controlPluginId,
16867
+ // Optional — absent on identities sealed by a pre-secret CLI.
16868
+ ...typeof p2.controlPollSecret === "string" ? { controlPollSecret: p2.controlPollSecret } : {}
16869
+ };
16857
16870
  }
16858
16871
  return null;
16859
16872
  } catch {
@@ -16936,15 +16949,21 @@ function resolveHostLabel(label) {
16936
16949
  return resolved.slice(0, 80);
16937
16950
  }
16938
16951
  async function redeemEnrollToken(token, label) {
16952
+ const controlPollSecret = (0, import_node_crypto9.randomBytes)(32).toString("base64url");
16953
+ const pluginSecretHash = (0, import_node_crypto9.createHash)("sha256").update(controlPollSecret).digest("hex");
16939
16954
  const data = await postJson("/api/self-hosted/redeem", {
16940
16955
  token,
16941
16956
  label: resolveHostLabel(label),
16942
- osInfo: collectOsInfo()
16957
+ osInfo: collectOsInfo(),
16958
+ // OPTIONAL + backward-compatible: older backends ignore the unknown field
16959
+ // and keep the pre-existing (no-secret) control-channel behavior.
16960
+ pluginSecretHash
16943
16961
  });
16944
16962
  return {
16945
16963
  hostId: data.hostId,
16946
16964
  hostToken: data.hostToken,
16947
- controlPluginId: data.controlPluginId
16965
+ controlPluginId: data.controlPluginId,
16966
+ controlPollSecret
16948
16967
  };
16949
16968
  }
16950
16969
  async function sendHostHeartbeat(identity, metrics) {
@@ -18312,7 +18331,7 @@ async function autoUpgradeBeforeCriticalCommand() {
18312
18331
  if (process.env.NODE_ENV === "test") return;
18313
18332
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
18314
18333
  if (process.env.CI) return;
18315
- const current = true ? "2.61.24" : null;
18334
+ const current = true ? "2.61.26" : null;
18316
18335
  if (!current) return;
18317
18336
  const cache = readCache();
18318
18337
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -18329,7 +18348,7 @@ function checkForUpdates() {
18329
18348
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
18330
18349
  if (process.env.CI) return;
18331
18350
  if (!process.stdout.isTTY) return;
18332
- const current = true ? "2.61.24" : null;
18351
+ const current = true ? "2.61.26" : null;
18333
18352
  if (!current) return;
18334
18353
  const cache = readCache();
18335
18354
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -18349,7 +18368,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
18349
18368
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
18350
18369
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
18351
18370
  function currentCliVersion() {
18352
- return true ? "2.61.24" : null;
18371
+ return true ? "2.61.26" : null;
18353
18372
  }
18354
18373
  function runCmd(cmd, args2, timeoutMs) {
18355
18374
  return new Promise((resolve8) => {
@@ -18761,11 +18780,12 @@ var HostAgentSupervisor = class {
18761
18780
  }
18762
18781
  /** Open the control channel (reusing the relay) + start heartbeats. */
18763
18782
  start() {
18764
- const make = this.deps.makeRelay ?? ((pluginId, onCommand, meta) => new CommandRelayService(pluginId, onCommand, meta));
18783
+ const make = this.deps.makeRelay ?? ((pluginId, onCommand, meta, pollSecret) => new CommandRelayService(pluginId, onCommand, meta, void 0, pollSecret));
18765
18784
  this.relay = make(
18766
18785
  this.identity.controlPluginId,
18767
18786
  (cmd) => this.handleCommand(cmd),
18768
- CONTROL_AGENT_META
18787
+ CONTROL_AGENT_META,
18788
+ this.identity.controlPollSecret
18769
18789
  );
18770
18790
  this.relay.start();
18771
18791
  void this.beat();
@@ -25029,7 +25049,7 @@ async function resolveAcpAdapterWithRetry(agent, opts = {}) {
25029
25049
  }
25030
25050
 
25031
25051
  // src/agents/acp/runner.ts
25032
- var import_node_crypto10 = require("crypto");
25052
+ var import_node_crypto11 = require("crypto");
25033
25053
 
25034
25054
  // src/services/history.service.ts
25035
25055
  var fs60 = __toESM(require("fs"));
@@ -31130,7 +31150,7 @@ async function runOnboardingTurn(opts) {
31130
31150
  }
31131
31151
 
31132
31152
  // src/agents/acp/mappers.ts
31133
- var import_node_crypto9 = require("crypto");
31153
+ var import_node_crypto10 = require("crypto");
31134
31154
  function mapSessionUpdate(notification) {
31135
31155
  const update = notification.update;
31136
31156
  switch (update.sessionUpdate) {
@@ -31193,7 +31213,7 @@ function mapPermissionRequest(request) {
31193
31213
  }
31194
31214
  return {
31195
31215
  event: {
31196
- questionId: (0, import_node_crypto9.randomUUID)(),
31216
+ questionId: (0, import_node_crypto10.randomUUID)(),
31197
31217
  prompt,
31198
31218
  options: labels.length > 0 ? labels : void 0
31199
31219
  },
@@ -31203,7 +31223,7 @@ function mapPermissionRequest(request) {
31203
31223
  }
31204
31224
  function messageChunkId(messageId) {
31205
31225
  if (typeof messageId === "string" && messageId.length > 0) return messageId;
31206
- return (0, import_node_crypto9.randomUUID)();
31226
+ return (0, import_node_crypto10.randomUUID)();
31207
31227
  }
31208
31228
  function extractText4(content) {
31209
31229
  if (!content || typeof content !== "object") return null;
@@ -31998,7 +32018,7 @@ function describeError(err) {
31998
32018
  if (err instanceof Error) return err.message;
31999
32019
  return String(err);
32000
32020
  }
32001
- var AUTH_FAILURE_RE = /invalid authentication credentials|authentication[_ ](?:error|required)|please run \/login|\bunauthorized\b|\binvalid x-api-key\b|oauth token (?:expired|revoked)|(?:api error|http|status)[:\s]+401|\b401\b[^\n]{0,40}(?:unauthor|authenticat|credential|api[_ ]?key|login)/i;
32021
+ var AUTH_FAILURE_RE = /invalid authentication credentials|failed to authenticate|authentication[_ ](?:error|required)|please run \/login|\bunauthorized\b|\binvalid x-api-key\b|oauth (?:token|session) (?:expired|revoked)|(?:session|token|credentials?|oauth)[^\n]{0,40}could not be refreshed|(?:api error|http|status)[:\s]+401|\b401\b[^\n]{0,40}(?:unauthor|authenticat|credential|api[_ ]?key|login)/i;
32002
32022
  function looksLikeAuthFailure(text) {
32003
32023
  return AUTH_FAILURE_RE.test(text);
32004
32024
  }
@@ -33197,7 +33217,7 @@ var AcpHistory = class {
33197
33217
  this.summary = trimmed.length > 120 ? trimmed.slice(0, 117) + "\u2026" : trimmed;
33198
33218
  }
33199
33219
  this.messages.push({
33200
- id: (0, import_node_crypto10.randomUUID)(),
33220
+ id: (0, import_node_crypto11.randomUUID)(),
33201
33221
  role: "user",
33202
33222
  text,
33203
33223
  timestamp: Date.now()
@@ -33206,7 +33226,7 @@ var AcpHistory = class {
33206
33226
  appendAgentReply(text) {
33207
33227
  if (text.length === 0) return;
33208
33228
  this.messages.push({
33209
- id: (0, import_node_crypto10.randomUUID)(),
33229
+ id: (0, import_node_crypto11.randomUUID)(),
33210
33230
  role: "agent",
33211
33231
  text,
33212
33232
  timestamp: Date.now()
@@ -33424,7 +33444,7 @@ async function runAcpSession(opts) {
33424
33444
  currentIndex: 0,
33425
33445
  done: true
33426
33446
  }),
33427
- publishAwaitingAnswer: (prompt, options) => publisher.publishAwaitingAnswer({ questionId: (0, import_node_crypto10.randomUUID)(), prompt, options }),
33447
+ publishAwaitingAnswer: (prompt, options) => publisher.publishAwaitingAnswer({ questionId: (0, import_node_crypto11.randomUUID)(), prompt, options }),
33428
33448
  publishRawChunk: (chunk) => publisher.publishOutput(chunk),
33429
33449
  sendResult: (commandId, status2, result) => relay.sendResult(commandId, status2, result),
33430
33450
  appendAgentReply: (text) => history.appendAgentReply(text),
@@ -34911,7 +34931,7 @@ var NativeTuiDriver = class _NativeTuiDriver {
34911
34931
  };
34912
34932
 
34913
34933
  // src/baton/acp-driver.ts
34914
- var import_node_crypto11 = require("crypto");
34934
+ var import_node_crypto12 = require("crypto");
34915
34935
  var AcpDriver = class {
34916
34936
  constructor(deps) {
34917
34937
  this.deps = deps;
@@ -35004,7 +35024,7 @@ var AcpDriver = class {
35004
35024
  currentIndex: 0,
35005
35025
  done: true
35006
35026
  }),
35007
- publishAwaitingAnswer: (prompt, options) => publisher.publishAwaitingAnswer({ questionId: (0, import_node_crypto11.randomUUID)(), prompt, options }),
35027
+ publishAwaitingAnswer: (prompt, options) => publisher.publishAwaitingAnswer({ questionId: (0, import_node_crypto12.randomUUID)(), prompt, options }),
35008
35028
  publishRawChunk: (chunk) => publisher.publishOutput(chunk),
35009
35029
  sendResult: (commandId, status2, result) => relay.sendResult(commandId, status2, result),
35010
35030
  appendAgentReply: (text) => history.appendAgentReply(text),
@@ -38171,7 +38191,7 @@ async function invite() {
38171
38191
  // src/commands/doctor.ts
38172
38192
  var import_node_dns = require("dns");
38173
38193
  var import_node_util5 = require("util");
38174
- var import_node_crypto12 = require("crypto");
38194
+ var import_node_crypto13 = require("crypto");
38175
38195
  var fs68 = __toESM(require("fs"));
38176
38196
  var path76 = __toESM(require("path"));
38177
38197
  var import_picocolors14 = __toESM(require("picocolors"));
@@ -38341,9 +38361,9 @@ function checkChokidar() {
38341
38361
  }
38342
38362
  async function doctor(args2 = []) {
38343
38363
  const json = args2.includes("--json");
38344
- const cliVersion = true ? "2.61.24" : "0.0.0-dev";
38364
+ const cliVersion = true ? "2.61.26" : "0.0.0-dev";
38345
38365
  const apiBase2 = resolveApiBaseUrl();
38346
- const diagnosticId = (0, import_node_crypto12.randomUUID)();
38366
+ const diagnosticId = (0, import_node_crypto13.randomUUID)();
38347
38367
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
38348
38368
  const [dns, health] = await Promise.all([
38349
38369
  checkDns(apiBase2),
@@ -38852,7 +38872,7 @@ async function mcpRun(args2) {
38852
38872
  // src/commands/version.ts
38853
38873
  var import_picocolors15 = __toESM(require("picocolors"));
38854
38874
  function version2() {
38855
- const v = true ? "2.61.24" : "unknown";
38875
+ const v = true ? "2.61.26" : "unknown";
38856
38876
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
38857
38877
  }
38858
38878
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.61.24",
3
+ "version": "2.61.26",
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",