codeam-cli 2.39.35 → 2.39.37

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 +67 -107
  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.39.36] — 2026-06-18
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Preview dev-server run command rewrites pnpm/bun → npm run
12
+
13
+ ## [2.39.35] — 2026-06-18
14
+
15
+ ### Fixed
16
+
17
+ - **cli:** Preview pre-flight installs with npm --legacy-peer-deps (not pnpm)
18
+
19
+ ### Tests
20
+
21
+ - **cli:** Integration regression for ACP reply-doubling (notification → mapper → runner)
22
+
7
23
  ## [2.39.34] — 2026-06-18
8
24
 
9
25
  ### Fixed
package/dist/index.js CHANGED
@@ -498,7 +498,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
498
498
  // package.json
499
499
  var package_default = {
500
500
  name: "codeam-cli",
501
- version: "2.39.35",
501
+ version: "2.39.37",
502
502
  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.",
503
503
  type: "commonjs",
504
504
  main: "dist/index.js",
@@ -5908,7 +5908,7 @@ function readAnonId() {
5908
5908
  }
5909
5909
  function superProperties() {
5910
5910
  return {
5911
- cliVersion: true ? "2.39.35" : "0.0.0-dev",
5911
+ cliVersion: true ? "2.39.37" : "0.0.0-dev",
5912
5912
  nodeVersion: process.version,
5913
5913
  platform: process.platform,
5914
5914
  arch: process.arch,
@@ -16538,34 +16538,6 @@ function downloadUrlForPlatform() {
16538
16538
  var import_child_process11 = require("child_process");
16539
16539
  var import_util3 = require("util");
16540
16540
  var execFileP4 = (0, import_util3.promisify)(import_child_process11.execFile);
16541
- function isCodespaceSession(env = process.env) {
16542
- return Boolean(env.CODESPACE_NAME);
16543
- }
16544
- function buildCodespaceUrl(codespaceName, port) {
16545
- return `https://${codespaceName}-${port}.app.github.dev`;
16546
- }
16547
- async function setPortPublic(codespaceName, port) {
16548
- await execFileP4("gh", [
16549
- "codespace",
16550
- "ports",
16551
- "visibility",
16552
- `${port}:public`,
16553
- "-c",
16554
- codespaceName
16555
- ]);
16556
- }
16557
- async function waitForCodespacePortReady(url, timeoutMs = 15e3) {
16558
- const start2 = Date.now();
16559
- while (Date.now() - start2 < timeoutMs) {
16560
- try {
16561
- const res = await fetch(url, { method: "HEAD" });
16562
- if (res.status < 500) return;
16563
- } catch {
16564
- }
16565
- await new Promise((r) => setTimeout(r, 500));
16566
- }
16567
- throw new Error(`Codespace forwarded URL ${url} not reachable after ${timeoutMs}ms.`);
16568
- }
16569
16541
 
16570
16542
  // src/services/preview/config-file.ts
16571
16543
  var import_promises4 = __toESM(require("fs/promises"));
@@ -18912,6 +18884,21 @@ async function waitForDevServerReady(devServer, readyRe, opts = {
18912
18884
  return { kind: "timeout" };
18913
18885
  }
18914
18886
  function normalizeDetectionForSpawn(detection, cwd) {
18887
+ if (detection.command === "pnpm" || detection.command === "bun") {
18888
+ const raw = detection.args ?? [];
18889
+ const verb = raw[0];
18890
+ if (verb && !["exec", "dlx", "x"].includes(verb)) {
18891
+ const rest = verb === "run" ? raw.slice(1) : raw;
18892
+ const [script, ...extra] = rest;
18893
+ if (script && !script.startsWith("-")) {
18894
+ return {
18895
+ ...detection,
18896
+ command: "npm",
18897
+ args: extra.length ? ["run", script, "--", ...extra] : ["run", script]
18898
+ };
18899
+ }
18900
+ }
18901
+ }
18915
18902
  if (detection.command !== "npx") return detection;
18916
18903
  const args2 = detection.args ?? [];
18917
18904
  if (args2.length === 0) return detection;
@@ -19100,7 +19087,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
19100
19087
  emitProgress("READY_DETECTED", `port ${detection.port}`);
19101
19088
  emitProgress(
19102
19089
  "TUNNEL_STARTING",
19103
- detection.framework === "Expo" ? "Expo (self-tunnelled)" : isCodespaceSession() ? "GitHub Codespaces public port" : "cloudflared quick tunnel"
19090
+ detection.framework === "Expo" ? "Expo (self-tunnelled)" : "cloudflared quick tunnel"
19104
19091
  );
19105
19092
  let tunnel = null;
19106
19093
  let url;
@@ -19126,41 +19113,6 @@ var previewStartH = (ctx, _cmd, parsed) => {
19126
19113
  return;
19127
19114
  }
19128
19115
  url = expoUrl;
19129
- } else if (isCodespaceSession()) {
19130
- const codespaceName = process.env.CODESPACE_NAME;
19131
- try {
19132
- await setPortPublic(codespaceName, detection.port);
19133
- } catch (e) {
19134
- try {
19135
- devServer.kill("SIGTERM");
19136
- } catch {
19137
- }
19138
- void postPreviewEvent({
19139
- sessionId: ctx.sessionId,
19140
- pluginId: ctx.pluginId,
19141
- pluginAuthToken,
19142
- type: "preview_error",
19143
- payload: { stage: "tunnel", message: `Failed to flip port public: ${e.message}` }
19144
- });
19145
- return;
19146
- }
19147
- url = buildCodespaceUrl(codespaceName, detection.port);
19148
- try {
19149
- await waitForCodespacePortReady(url, 15e3);
19150
- } catch (e) {
19151
- try {
19152
- devServer.kill("SIGTERM");
19153
- } catch {
19154
- }
19155
- void postPreviewEvent({
19156
- sessionId: ctx.sessionId,
19157
- pluginId: ctx.pluginId,
19158
- pluginAuthToken,
19159
- type: "preview_error",
19160
- payload: { stage: "tunnel", message: e.message }
19161
- });
19162
- return;
19163
- }
19164
19116
  } else {
19165
19117
  let bin;
19166
19118
  try {
@@ -19179,48 +19131,56 @@ var previewStartH = (ctx, _cmd, parsed) => {
19179
19131
  });
19180
19132
  return;
19181
19133
  }
19182
- tunnel = (0, import_child_process18.spawn)(bin, ["tunnel", "--url", `http://localhost:${detection.port}`], {
19183
- stdio: ["ignore", "pipe", "pipe"]
19184
- });
19134
+ const MAX_TUNNEL_ATTEMPTS = 3;
19185
19135
  let parsedUrl = null;
19186
- const onTunnelChunk = (chunk) => {
19187
- const s = chunk.toString();
19188
- if (!parsedUrl) parsedUrl = parseCloudflaredUrl(s);
19189
- const trimmed = s.replace(/\n+$/g, "");
19190
- if (trimmed.length > 0) log.info("preview", `cloudflared: ${trimmed}`);
19191
- };
19192
- tunnel.stderr.on("data", onTunnelChunk);
19193
- tunnel.stdout.on("data", onTunnelChunk);
19194
- const tunnelDeadline = Date.now() + 45e3;
19195
- while (!parsedUrl && Date.now() < tunnelDeadline) {
19196
- await new Promise((r) => setTimeout(r, 250));
19197
- }
19198
- if (!parsedUrl) {
19199
- try {
19200
- tunnel.kill("SIGTERM");
19201
- } catch {
19136
+ let lastTunnelErr = "cloudflared did not emit a URL within 45s";
19137
+ for (let attempt = 1; attempt <= MAX_TUNNEL_ATTEMPTS && !parsedUrl; attempt += 1) {
19138
+ if (attempt > 1) {
19139
+ emitProgress(
19140
+ "TUNNEL_STARTING",
19141
+ `cloudflared quick tunnel (retry ${attempt}/${MAX_TUNNEL_ATTEMPTS})`
19142
+ );
19202
19143
  }
19203
- try {
19204
- devServer.kill("SIGTERM");
19205
- } catch {
19144
+ const candidate = (0, import_child_process18.spawn)(
19145
+ bin,
19146
+ ["tunnel", "--url", `http://localhost:${detection.port}`],
19147
+ { stdio: ["ignore", "pipe", "pipe"] }
19148
+ );
19149
+ let candidateUrl = null;
19150
+ const onTunnelChunk = (chunk) => {
19151
+ const s = chunk.toString();
19152
+ if (!candidateUrl) candidateUrl = parseCloudflaredUrl(s);
19153
+ const trimmed = s.replace(/\n+$/g, "");
19154
+ if (trimmed.length > 0) log.info("preview", `cloudflared: ${trimmed}`);
19155
+ };
19156
+ candidate.stderr.on("data", onTunnelChunk);
19157
+ candidate.stdout.on("data", onTunnelChunk);
19158
+ const urlDeadline = Date.now() + 45e3;
19159
+ while (!candidateUrl && Date.now() < urlDeadline) {
19160
+ await new Promise((r) => setTimeout(r, 250));
19161
+ }
19162
+ if (!candidateUrl) {
19163
+ lastTunnelErr = "cloudflared did not emit a URL within 45s";
19164
+ try {
19165
+ candidate.kill("SIGTERM");
19166
+ } catch {
19167
+ }
19168
+ continue;
19206
19169
  }
19207
- void postPreviewEvent({
19208
- sessionId: ctx.sessionId,
19209
- pluginId: ctx.pluginId,
19210
- pluginAuthToken,
19211
- type: "preview_error",
19212
- payload: { stage: "tunnel", message: "cloudflared did not emit a URL within 45s." }
19213
- });
19214
- return;
19215
- }
19216
- try {
19217
- await waitForCloudflaredReady(parsedUrl, 6e4);
19218
- log.info("preview", `cloudflared probe: ${parsedUrl} reachable from CLI host`);
19219
- } catch (e) {
19220
19170
  try {
19221
- tunnel.kill("SIGTERM");
19222
- } catch {
19171
+ await waitForCloudflaredReady(candidateUrl, 4e4);
19172
+ log.info("preview", `cloudflared probe: ${candidateUrl} reachable from CLI host`);
19173
+ tunnel = candidate;
19174
+ parsedUrl = candidateUrl;
19175
+ } catch (e) {
19176
+ lastTunnelErr = e.message;
19177
+ try {
19178
+ candidate.kill("SIGTERM");
19179
+ } catch {
19180
+ }
19223
19181
  }
19182
+ }
19183
+ if (!parsedUrl) {
19224
19184
  try {
19225
19185
  devServer.kill("SIGTERM");
19226
19186
  } catch {
@@ -19232,7 +19192,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
19232
19192
  type: "preview_error",
19233
19193
  payload: {
19234
19194
  stage: "tunnel",
19235
- message: `Tunnel ${parsedUrl} did not become reachable within 60s (${e.message}). Cloudflare Quick Tunnels occasionally fail to register \u2014 retry usually succeeds.`
19195
+ message: `Tunnel did not become reachable after ${MAX_TUNNEL_ATTEMPTS} attempts (${lastTunnelErr}). Cloudflare Quick Tunnels occasionally fail to register \u2014 please retry.`
19236
19196
  }
19237
19197
  });
19238
19198
  return;
@@ -27172,7 +27132,7 @@ function checkChokidar() {
27172
27132
  }
27173
27133
  async function doctor(args2 = []) {
27174
27134
  const json = args2.includes("--json");
27175
- const cliVersion = true ? "2.39.35" : "0.0.0-dev";
27135
+ const cliVersion = true ? "2.39.37" : "0.0.0-dev";
27176
27136
  const apiBase2 = resolveApiBaseUrl();
27177
27137
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
27178
27138
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -27371,7 +27331,7 @@ async function completion(args2) {
27371
27331
  // src/commands/version.ts
27372
27332
  var import_picocolors13 = __toESM(require("picocolors"));
27373
27333
  function version2() {
27374
- const v = true ? "2.39.35" : "unknown";
27334
+ const v = true ? "2.39.37" : "unknown";
27375
27335
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
27376
27336
  }
27377
27337
 
@@ -27657,7 +27617,7 @@ function checkForUpdates() {
27657
27617
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
27658
27618
  if (process.env.CI) return;
27659
27619
  if (!process.stdout.isTTY) return;
27660
- const current = true ? "2.39.35" : null;
27620
+ const current = true ? "2.39.37" : null;
27661
27621
  if (!current) return;
27662
27622
  const cache = readCache();
27663
27623
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.39.35",
3
+ "version": "2.39.37",
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",