codeam-cli 2.75.27 → 2.75.29

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,18 @@ 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.28] — 2026-09-25
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Preview proxy forwards to the address the dev server really serves (#820)
12
+
13
+ ## [2.75.27] — 2026-09-25
14
+
15
+ ### Fixed
16
+
17
+ - **cli:** On-demand Box session resume, link reporting, per-boot logs, MCP secrets off argv (#818)
18
+
7
19
  ## [2.75.26] — 2026-09-25
8
20
 
9
21
  ### Added
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.27" : "0.0.0-dev",
10519
+ cliVersion: true ? "2.75.29" : "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.27",
10761
+ version: "2.75.29",
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.27" ? { ideVersion: "2.75.27" } : {}
12091
+ ..."2.75.29" ? { ideVersion: "2.75.29" } : {}
12092
12092
  };
12093
12093
  try {
12094
12094
  const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body);
@@ -24273,6 +24273,18 @@ function injectAt(html, script) {
24273
24273
  }
24274
24274
  return null;
24275
24275
  }
24276
+ function upstreamRequestHeaders(headers, targetPort) {
24277
+ const out2 = { ...headers, host: `localhost:${targetPort}` };
24278
+ if (headers.host && !headers["x-forwarded-host"]) out2["x-forwarded-host"] = headers.host;
24279
+ if (!headers["x-forwarded-proto"]) out2["x-forwarded-proto"] = "https";
24280
+ return out2;
24281
+ }
24282
+ function publicLocation(location, targetPort) {
24283
+ if (!location) return location;
24284
+ const m = /^https?:\/\/(?:localhost|127\.0\.0\.1|\[::1\]):(\d+)(\/.*)?$/i.exec(location);
24285
+ if (!m || Number(m[1]) !== targetPort) return location;
24286
+ return m[2] ?? "/";
24287
+ }
24276
24288
  async function startInspectorProxy(opts) {
24277
24289
  const targetHost = opts.targetHost ?? "127.0.0.1";
24278
24290
  const upgraded = /* @__PURE__ */ new Set();
@@ -24283,12 +24295,14 @@ async function startInspectorProxy(opts) {
24283
24295
  secFetchDest: one(req.headers["sec-fetch-dest"]),
24284
24296
  secFetchMode: one(req.headers["sec-fetch-mode"])
24285
24297
  });
24286
- const headers = { ...req.headers };
24298
+ const headers = upstreamRequestHeaders(req.headers, opts.targetPort);
24287
24299
  if (inject) delete headers["accept-encoding"];
24288
24300
  const upstream = http8.request(
24289
24301
  { host: targetHost, port: opts.targetPort, method: req.method, path: req.url, headers },
24290
24302
  (originRes) => {
24291
24303
  const outHeaders = { ...originRes.headers };
24304
+ const location = publicLocation(originRes.headers.location, opts.targetPort);
24305
+ if (location !== void 0) outHeaders.location = location;
24292
24306
  const willInject = inject && isHtmlResponse(originRes.headers["content-type"]);
24293
24307
  if (willInject) delete outHeaders["content-length"];
24294
24308
  res.writeHead(originRes.statusCode ?? 502, outHeaders);
@@ -24334,7 +24348,7 @@ async function startInspectorProxy(opts) {
24334
24348
  upgraded.add(clientSocket);
24335
24349
  const upstream = net3.connect(opts.targetPort, targetHost, () => {
24336
24350
  const lines = [`${req.method} ${req.url} HTTP/1.1`];
24337
- for (const [k2, v] of Object.entries(req.headers)) {
24351
+ for (const [k2, v] of Object.entries(upstreamRequestHeaders(req.headers, opts.targetPort))) {
24338
24352
  for (const one of Array.isArray(v) ? v : [v]) {
24339
24353
  if (one !== void 0) lines.push(`${k2}: ${one}`);
24340
24354
  }
@@ -24868,9 +24882,10 @@ async function bringUpInspector(targetPort, deps = {}) {
24868
24882
  const start2 = deps.start ?? startInspectorProxy;
24869
24883
  const proxy = await start2({
24870
24884
  targetPort,
24885
+ ...deps.targetHost ? { targetHost: deps.targetHost } : {},
24871
24886
  script: inspectorClientSource({ allowedOrigins: resolveInspectorOrigins(env) })
24872
24887
  });
24873
- log2(`preview inspector proxy on :${proxy.port} \u2192 :${targetPort}`);
24888
+ log2(`preview inspector proxy on :${proxy.port} \u2192 ${deps.targetHost ?? "127.0.0.1"}:${targetPort}`);
24874
24889
  return { port: proxy.port, proxy };
24875
24890
  } catch (e) {
24876
24891
  log2(`preview inspector unavailable (${e.message}) \u2014 going direct`);
@@ -24878,6 +24893,39 @@ async function bringUpInspector(targetPort, deps = {}) {
24878
24893
  }
24879
24894
  }
24880
24895
 
24896
+ // src/services/preview/served-address.ts
24897
+ var LOOPBACK_HOSTS = ["127.0.0.1", "::1"];
24898
+ var ANSI_RE2 = /\x1b\[[0-9;]*m/g;
24899
+ var LOCAL_URL_RE = /https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1?\]|\[::\]):(\d{2,5})\b/gi;
24900
+ function announcedPorts(output) {
24901
+ const clean = output.replace(ANSI_RE2, "");
24902
+ const ports = [];
24903
+ for (const m of clean.matchAll(LOCAL_URL_RE)) {
24904
+ const port = Number(m[1]);
24905
+ if (port > 0 && port < 65536) ports.push(port);
24906
+ }
24907
+ return [...new Set(ports.reverse())];
24908
+ }
24909
+ async function resolveServedAddress(output, detectedPort, deps = {}) {
24910
+ const listening = deps.listening ?? isPortListening;
24911
+ const candidates = [.../* @__PURE__ */ new Set([...announcedPorts(output), detectedPort])];
24912
+ for (const port of candidates) {
24913
+ for (const host2 of LOOPBACK_HOSTS) {
24914
+ if (await listening(port, host2)) return { host: host2, port };
24915
+ }
24916
+ }
24917
+ return { host: "127.0.0.1", port: detectedPort };
24918
+ }
24919
+ async function announcedPortListening(output, deps = {}) {
24920
+ const listening = deps.listening ?? isPortListening;
24921
+ for (const port of announcedPorts(output)) {
24922
+ for (const host2 of LOOPBACK_HOSTS) {
24923
+ if (await listening(port, host2)) return true;
24924
+ }
24925
+ }
24926
+ return false;
24927
+ }
24928
+
24881
24929
  // src/services/preview/start-orchestrator.ts
24882
24930
  var INSTALL_TIMEOUT_MS2 = 5 * 6e4;
24883
24931
  var SETUP_TIMEOUT_MS = 2 * 6e4;
@@ -25186,7 +25234,10 @@ async function startDevServer(ctx, extraEnv = {}) {
25186
25234
  if (verdict.adopt) {
25187
25235
  log.info("preview", `adopting the dev server already serving on port ${detection.port}`);
25188
25236
  emitProgress("READY_DETECTED", `adopted the server already on port ${detection.port}`);
25189
- return { devServer: null };
25237
+ return {
25238
+ devServer: null,
25239
+ served: await resolveServedAddress("", detection.port)
25240
+ };
25190
25241
  }
25191
25242
  emit2(USER_EVENTS.PREVIEW_ERROR, {
25192
25243
  stage: "spawn",
@@ -25223,7 +25274,7 @@ async function startDevServer(ctx, extraEnv = {}) {
25223
25274
  "i"
25224
25275
  ) : compileReadyPattern(detection.ready_pattern);
25225
25276
  const isNextJs = /next/i.test(detection.framework);
25226
- const portProbe = isExpo ? () => waitForExpoManifest(detection.port, { timeoutMs: 1e3, intervalMs: 250 }) : isNextJs ? () => waitForPortListening(detection.port, { timeoutMs: 1e3, intervalMs: 250 }) : void 0;
25277
+ const portProbe = isExpo ? () => waitForExpoManifest(detection.port, { timeoutMs: 1e3, intervalMs: 250 }) : isNextJs ? () => waitForPortListening(detection.port, { timeoutMs: 1e3, intervalMs: 250 }) : () => announcedPortListening(outputTail);
25227
25278
  const outcome = await waitForDevServerReady(devServer, readyRe, {
25228
25279
  timeoutMs: devServerReadyTimeoutMs(detection),
25229
25280
  onChunk: (s) => {
@@ -25249,15 +25300,23 @@ async function startDevServer(ctx, extraEnv = {}) {
25249
25300
  });
25250
25301
  return null;
25251
25302
  }
25252
- emitProgress("READY_DETECTED", `port ${detection.port}`);
25253
- return { devServer };
25303
+ const served = await resolveServedAddress(outputTail, detection.port);
25304
+ if (served.port !== detection.port || served.host !== "127.0.0.1") {
25305
+ log.info(
25306
+ "preview",
25307
+ `dev server serves on ${served.host}:${served.port} (detection said :${detection.port})`
25308
+ );
25309
+ }
25310
+ emitProgress("READY_DETECTED", `port ${served.port}`);
25311
+ return { devServer, served };
25254
25312
  }
25255
25313
  var MAX_TUNNEL_ATTEMPTS = 3;
25256
25314
  async function establishTunnel(ctx, dev) {
25257
25315
  const { detection, emit: emit2, emitProgress } = ctx;
25258
25316
  const { devServer } = dev;
25259
25317
  emitProgress("TUNNEL_STARTING", "cloudflared quick tunnel");
25260
- const inspection = await bringUpInspector(detection.port, {
25318
+ const inspection = await bringUpInspector(dev.served.port, {
25319
+ targetHost: dev.served.host,
25261
25320
  log: (m) => log.info("preview", m)
25262
25321
  });
25263
25322
  const pub = await bringUpPublicUrl(ctx, inspection.port);
@@ -38354,10 +38413,10 @@ function completedReplyFailureBubble(opts) {
38354
38413
  }
38355
38414
  function houseAgentLimitMessage(text) {
38356
38415
  if (/temporarily (?:unavailable|disabled)/i.test(text)) {
38357
- return "\u23F3 **CodeAgent Cloud is temporarily unavailable \u2014 this one\u2019s on us, not your account.**\n\nThere\u2019s nothing to buy and nothing owed, and it isn\u2019t a problem with your login, so re-authenticating won\u2019t help. Send your message again in a bit, or connect your own agent (Claude Code, Codex, Cursor, Gemini) in **Profile \u203A Agents** to keep going now.";
38416
+ return "\u23F3 **Our agent service is temporarily unavailable \u2014 this one\u2019s on us, not your account.**\n\nThere\u2019s nothing to buy and nothing owed, and it isn\u2019t a problem with your login, so re-authenticating won\u2019t help. Send your message again in a bit, or connect your own agent (Claude Code, Codex, Cursor, Gemini) in **Profile \u203A Agents** to keep going now.";
38358
38417
  }
38359
38418
  const canUpgrade = /upgrade to pro/i.test(text);
38360
- return "\u{1F4CA} **You\u2019ve reached your daily CodeAgent Cloud limit.**\n\nThe free CodeAgent Cloud agent has a daily usage ceiling that resets at midnight UTC. This is a usage limit, not a problem with your login \u2014 re-authenticating won\u2019t change it. " + (canUpgrade ? "To keep going now, upgrade to **Pro** for a higher ceiling, or connect your own agent (Claude, Codex, \u2026) in **Profile \u203A Agents** to run without this limit." : "To keep going now, connect your own agent (Claude, Codex, \u2026) in **Profile \u203A Agents** to run without this limit, or wait for the reset.");
38419
+ return "\u{1F4CA} **You\u2019ve reached today\u2019s agent usage limit.**\n\nThe free agent has a daily usage ceiling that resets at midnight UTC. This is a usage limit, not a problem with your login \u2014 re-authenticating won\u2019t change it. " + (canUpgrade ? "To keep going now, upgrade to **Pro** for a higher ceiling, or connect your own agent (Claude, Codex, \u2026) in **Profile \u203A Agents** to run without this limit." : "To keep going now, connect your own agent (Claude, Codex, \u2026) in **Profile \u203A Agents** to run without this limit, or wait for the reset.");
38361
38420
  }
38362
38421
  var AUTH_FAILURE_MESSAGE = (
38363
38422
  // ⚠️ Do NOT name a status code here. This bubble fires for several
@@ -38387,10 +38446,10 @@ function agentStatusPage(agent, railWireId) {
38387
38446
  }
38388
38447
  function providerOutageMessage(agent, railWireId) {
38389
38448
  if (railWireId) {
38390
- const who2 = isManagedProviderId(railWireId) ? MANAGED_PROVIDER_DISPLAY_NAMES[railWireId] : HOUSE_AGENT_NAME;
38449
+ const who2 = isManagedProviderId(railWireId) ? `${MANAGED_PROVIDER_DISPLAY_NAMES[railWireId]} ` : "";
38391
38450
  return `\u{1F310} **CodeAgent's agent service is having a disruption \u2014 this isn't your session.**
38392
38451
 
38393
- Your ${who2} agent couldn't finish this turn because our provider returned an overload error. It usually clears up on its own \u2014 just send your message again in a bit.`;
38452
+ Your ${who2}agent couldn't finish this turn because our provider returned an overload error. It usually clears up on its own \u2014 just send your message again in a bit.`;
38394
38453
  }
38395
38454
  const info = agentStatusPage(agent);
38396
38455
  const who = info ? info.vendor : "The agent provider";
@@ -48578,7 +48637,7 @@ async function autoUpgradeBeforeCriticalCommand() {
48578
48637
  if (process.env.NODE_ENV === "test") return;
48579
48638
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
48580
48639
  if (process.env.CI) return;
48581
- const current2 = true ? "2.75.27" : null;
48640
+ const current2 = true ? "2.75.29" : null;
48582
48641
  if (!current2) return;
48583
48642
  const cache = readCache();
48584
48643
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -48595,7 +48654,7 @@ function checkForUpdates() {
48595
48654
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
48596
48655
  if (process.env.CI) return;
48597
48656
  if (!process.stdout.isTTY) return;
48598
- const current2 = true ? "2.75.27" : null;
48657
+ const current2 = true ? "2.75.29" : null;
48599
48658
  if (!current2) return;
48600
48659
  const cache = readCache();
48601
48660
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -48618,7 +48677,7 @@ var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
48618
48677
  var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
48619
48678
  var SUDO_PREFLIGHT_TIMEOUT_MS = 5e3;
48620
48679
  function currentCliVersion() {
48621
- return true ? "2.75.27" : null;
48680
+ return true ? "2.75.29" : null;
48622
48681
  }
48623
48682
  async function installedVersion(deps) {
48624
48683
  const ls = await deps.run(
@@ -50583,7 +50642,7 @@ function checkChokidar() {
50583
50642
  }
50584
50643
  async function doctor(args2 = []) {
50585
50644
  const json = args2.includes("--json");
50586
- const cliVersion = true ? "2.75.27" : "0.0.0-dev";
50645
+ const cliVersion = true ? "2.75.29" : "0.0.0-dev";
50587
50646
  const apiBase2 = resolveApiBaseUrl();
50588
50647
  const diagnosticId = (0, import_node_crypto13.randomUUID)();
50589
50648
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -51107,7 +51166,7 @@ async function mcpWarm(argv = [], opts = {}) {
51107
51166
  // src/commands/version.ts
51108
51167
  var import_picocolors15 = __toESM(require("picocolors"));
51109
51168
  function version2() {
51110
- const v = true ? "2.75.27" : "unknown";
51169
+ const v = true ? "2.75.29" : "unknown";
51111
51170
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
51112
51171
  }
51113
51172
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.75.27",
3
+ "version": "2.75.29",
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",