codeam-cli 2.39.39 → 2.39.41

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 +12 -0
  2. package/dist/index.js +171 -62
  3. package/package.json +1 -1
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.39.40] — 2026-06-19
8
+
9
+ ### Added
10
+
11
+ - **cli:** Run named preview tunnel via token, fallback to quick tunnel
12
+
13
+ ## [2.39.39] — 2026-06-19
14
+
15
+ ### Fixed
16
+
17
+ - **cli:** Gate preview tunnel on cloudflared 'Registered tunnel connection', not a host DNS probe
18
+
7
19
  ## [2.39.38] — 2026-06-19
8
20
 
9
21
  ### Added
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.39",
501
+ version: "2.39.41",
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.39" : "0.0.0-dev",
5911
+ cliVersion: true ? "2.39.41" : "0.0.0-dev",
5912
5912
  nodeVersion: process.version,
5913
5913
  platform: process.platform,
5914
5914
  arch: process.arch,
@@ -15259,7 +15259,8 @@ var fs35 = __toESM(require("fs"));
15259
15259
  var os28 = __toESM(require("os"));
15260
15260
  var path42 = __toESM(require("path"));
15261
15261
  var import_crypto3 = require("crypto");
15262
- var import_child_process18 = require("child_process");
15262
+ var import_child_process19 = require("child_process");
15263
+ var import_which2 = __toESM(require("which"));
15263
15264
 
15264
15265
  // src/lib/payload.ts
15265
15266
  var import_zod = require("zod");
@@ -16464,6 +16465,7 @@ async function linkDryRunPreflight(ctx) {
16464
16465
  }
16465
16466
 
16466
16467
  // src/services/preview/cloudflared.ts
16468
+ var import_child_process11 = require("child_process");
16467
16469
  var import_fs = require("fs");
16468
16470
  var import_promises = __toESM(require("fs/promises"));
16469
16471
  var import_os6 = __toESM(require("os"));
@@ -16516,11 +16518,38 @@ function downloadUrlForPlatform() {
16516
16518
  `cloudflared auto-install not supported on ${platform3}/${arch2}. Install manually from https://github.com/cloudflare/cloudflared/releases.`
16517
16519
  );
16518
16520
  }
16521
+ function decodeTunnelToken(token) {
16522
+ const decoded = JSON.parse(Buffer.from(token, "base64").toString("utf8"));
16523
+ if (!decoded.a || !decoded.t || !decoded.s) {
16524
+ throw new Error("cloudflared token missing accountTag/tunnelID/tunnelSecret");
16525
+ }
16526
+ return { AccountTag: decoded.a, TunnelID: decoded.t, TunnelSecret: decoded.s };
16527
+ }
16528
+ async function spawnNamedTunnel(bin, token, port) {
16529
+ const creds = decodeTunnelToken(token);
16530
+ const credDir = import_path4.default.join(import_os6.default.homedir(), ".codeam");
16531
+ await import_promises.default.mkdir(credDir, { recursive: true });
16532
+ const credFile = import_path4.default.join(credDir, `tunnel-${creds.TunnelID}.json`);
16533
+ await import_promises.default.writeFile(credFile, JSON.stringify(creds), { mode: 384 });
16534
+ return (0, import_child_process11.spawn)(
16535
+ bin,
16536
+ [
16537
+ "tunnel",
16538
+ "run",
16539
+ "--credentials-file",
16540
+ credFile,
16541
+ "--url",
16542
+ `http://localhost:${port}`,
16543
+ creds.TunnelID
16544
+ ],
16545
+ { stdio: ["ignore", "pipe", "pipe"] }
16546
+ );
16547
+ }
16519
16548
 
16520
16549
  // src/services/preview/codespace.ts
16521
- var import_child_process11 = require("child_process");
16550
+ var import_child_process12 = require("child_process");
16522
16551
  var import_util3 = require("util");
16523
- var execFileP4 = (0, import_util3.promisify)(import_child_process11.execFile);
16552
+ var execFileP4 = (0, import_util3.promisify)(import_child_process12.execFile);
16524
16553
 
16525
16554
  // src/services/preview/config-file.ts
16526
16555
  var import_promises3 = __toESM(require("fs/promises"));
@@ -16674,10 +16703,10 @@ var import_fs2 = require("fs");
16674
16703
  var import_path6 = __toESM(require("path"));
16675
16704
 
16676
16705
  // src/services/preview/run-setup.ts
16677
- var import_child_process12 = require("child_process");
16706
+ var import_child_process13 = require("child_process");
16678
16707
  function runSetupCommand(cmd, args2, cwd, env, opts) {
16679
16708
  return new Promise((resolve7) => {
16680
- const child = (0, import_child_process12.spawn)(cmd, args2, {
16709
+ const child = (0, import_child_process13.spawn)(cmd, args2, {
16681
16710
  cwd,
16682
16711
  env: { ...process.env, ...env ?? {} },
16683
16712
  stdio: ["ignore", "pipe", "pipe"]
@@ -16925,6 +16954,12 @@ function detectMissingNodeDeps(cwd) {
16925
16954
  }
16926
16955
  return { cmd: "npm", args: ["install", "--legacy-peer-deps"] };
16927
16956
  }
16957
+ async function ensureYarnInstalled(deps) {
16958
+ if (await deps.hasYarn()) return { ok: true, code: 0 };
16959
+ const res = await deps.installYarn();
16960
+ if (!res.ok) return res;
16961
+ return await deps.hasYarn() ? { ok: true, code: 0 } : { ok: false, code: res.code };
16962
+ }
16928
16963
  function isJsInstallCommand(cmd, args2) {
16929
16964
  const known = ["npm", "pnpm", "yarn", "bun"];
16930
16965
  if (!known.includes(cmd)) return false;
@@ -16974,7 +17009,7 @@ function activePreviewSessionIds() {
16974
17009
  }
16975
17010
 
16976
17011
  // src/beads/bd-adapter.ts
16977
- var import_child_process13 = require("child_process");
17012
+ var import_child_process14 = require("child_process");
16978
17013
  var fs31 = __toESM(require("fs"));
16979
17014
  var os25 = __toESM(require("os"));
16980
17015
  var path37 = __toESM(require("path"));
@@ -17028,7 +17063,7 @@ function _defaultSpawn(binaryPath, args2, opts) {
17028
17063
  return new Promise((resolve7) => {
17029
17064
  let proc;
17030
17065
  try {
17031
- proc = (0, import_child_process13.spawn)(binaryPath, args2, { cwd: opts.cwd, env: opts.env });
17066
+ proc = (0, import_child_process14.spawn)(binaryPath, args2, { cwd: opts.cwd, env: opts.env });
17032
17067
  } catch (err) {
17033
17068
  resolve7({ code: -1, stdout: "", stderr: err.message });
17034
17069
  return;
@@ -17182,13 +17217,13 @@ function coerceIssue(row, projectKey) {
17182
17217
  }
17183
17218
 
17184
17219
  // src/beads/provisioner.ts
17185
- var import_child_process17 = require("child_process");
17220
+ var import_child_process18 = require("child_process");
17186
17221
  var fs34 = __toESM(require("fs"));
17187
17222
  var os27 = __toESM(require("os"));
17188
17223
  var path40 = __toESM(require("path"));
17189
17224
 
17190
17225
  // src/beads/install-bd.ts
17191
- var import_child_process14 = require("child_process");
17226
+ var import_child_process15 = require("child_process");
17192
17227
  var INSTALL_SH_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/scripts/install.sh";
17193
17228
  var INSTALL_PS1_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/install.ps1";
17194
17229
  function resolveInstallStrategy(platform3) {
@@ -17219,7 +17254,7 @@ function _defaultInstallSpawn(strategy) {
17219
17254
  return new Promise((resolve7) => {
17220
17255
  let proc;
17221
17256
  try {
17222
- proc = (0, import_child_process14.spawn)(strategy.command, strategy.args, { env: process.env });
17257
+ proc = (0, import_child_process15.spawn)(strategy.command, strategy.args, { env: process.env });
17223
17258
  } catch (err) {
17224
17259
  resolve7({ ok: false, code: -1, stderr: err.message });
17225
17260
  return;
@@ -17249,7 +17284,7 @@ async function installBd(platform3 = process.platform) {
17249
17284
  }
17250
17285
 
17251
17286
  // src/beads/install-dolt.ts
17252
- var import_child_process15 = require("child_process");
17287
+ var import_child_process16 = require("child_process");
17253
17288
  var fs32 = __toESM(require("fs"));
17254
17289
  var os26 = __toESM(require("os"));
17255
17290
  var path38 = __toESM(require("path"));
@@ -17411,7 +17446,7 @@ function _defaultDoltInstallSpawn(strategy) {
17411
17446
  };
17412
17447
  let proc;
17413
17448
  try {
17414
- proc = (0, import_child_process15.spawn)(strategy.command, strategy.args, {
17449
+ proc = (0, import_child_process16.spawn)(strategy.command, strategy.args, {
17415
17450
  env: process.env,
17416
17451
  stdio: ["ignore", "pipe", "pipe"]
17417
17452
  });
@@ -17484,7 +17519,7 @@ async function ensureSharedServer(adapter) {
17484
17519
  }
17485
17520
 
17486
17521
  // src/beads/project-key.ts
17487
- var import_child_process16 = require("child_process");
17522
+ var import_child_process17 = require("child_process");
17488
17523
  var crypto2 = __toESM(require("crypto"));
17489
17524
  var fs33 = __toESM(require("fs"));
17490
17525
  var path39 = __toESM(require("path"));
@@ -17531,7 +17566,7 @@ function findRepoRoot(cwd) {
17531
17566
  }
17532
17567
  var _execSeam2 = {
17533
17568
  exec: (file, args2, opts) => {
17534
- const out2 = (0, import_child_process16.execFileSync)(file, args2, opts);
17569
+ const out2 = (0, import_child_process17.execFileSync)(file, args2, opts);
17535
17570
  return typeof out2 === "string" ? out2 : out2.toString("utf8");
17536
17571
  },
17537
17572
  realpath: (p2) => fs33.realpathSync(p2)
@@ -17691,7 +17726,7 @@ function linkBdOntoPath(binaryPath) {
17691
17726
  log.info("beads", `linked bd onto PATH: ${linkPath} -> ${binaryPath}`);
17692
17727
  }
17693
17728
  function setGitBeadsRole() {
17694
- (0, import_child_process17.execFileSync)("git", ["config", "--global", "beads.role", "contributor"], {
17729
+ (0, import_child_process18.execFileSync)("git", ["config", "--global", "beads.role", "contributor"], {
17695
17730
  stdio: "ignore"
17696
17731
  });
17697
17732
  }
@@ -18377,7 +18412,7 @@ var sessionTerminated = async (ctx, cmd) => {
18377
18412
  } catch {
18378
18413
  }
18379
18414
  try {
18380
- const proc = (0, import_child_process18.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
18415
+ const proc = (0, import_child_process19.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
18381
18416
  detached: true,
18382
18417
  stdio: "ignore"
18383
18418
  });
@@ -18399,7 +18434,7 @@ var shutdownSession = async (ctx, cmd) => {
18399
18434
  }
18400
18435
  if (ctx.keepAliveCtx.inCodespace && ctx.keepAliveCtx.codespaceName) {
18401
18436
  try {
18402
- const stopProc = (0, import_child_process18.spawn)(
18437
+ const stopProc = (0, import_child_process19.spawn)(
18403
18438
  "bash",
18404
18439
  ["-lc", `sleep 1; gh codespace stop -c ${JSON.stringify(ctx.keepAliveCtx.codespaceName)} >/dev/null 2>&1 || true`],
18405
18440
  { detached: true, stdio: "ignore" }
@@ -18409,7 +18444,7 @@ var shutdownSession = async (ctx, cmd) => {
18409
18444
  }
18410
18445
  }
18411
18446
  try {
18412
- const proc = (0, import_child_process18.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
18447
+ const proc = (0, import_child_process19.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
18413
18448
  detached: true,
18414
18449
  stdio: "ignore"
18415
18450
  });
@@ -18930,6 +18965,35 @@ var previewStartH = (ctx, _cmd, parsed) => {
18930
18965
  const missingDeps = detectMissingNodeDeps(process.cwd());
18931
18966
  let preflightRan = false;
18932
18967
  if (missingDeps) {
18968
+ if (missingDeps.cmd === "yarn") {
18969
+ const ensured = await ensureYarnInstalled({
18970
+ hasYarn: async () => Boolean(await (0, import_which2.default)("yarn", { nothrow: true })),
18971
+ installYarn: async () => {
18972
+ emitProgress("SETUP_RUN", "installing yarn (not found on PATH) \u2014 npm install -g yarn");
18973
+ const r = await runSetupCommand(
18974
+ "npm",
18975
+ ["install", "-g", "yarn"],
18976
+ process.cwd(),
18977
+ detection.env,
18978
+ { timeoutMs: INSTALL_TIMEOUT_MS }
18979
+ );
18980
+ return { ok: r.status === "ok", code: r.code };
18981
+ }
18982
+ });
18983
+ if (!ensured.ok) {
18984
+ void postPreviewEvent({
18985
+ sessionId: ctx.sessionId,
18986
+ pluginId: ctx.pluginId,
18987
+ pluginAuthToken,
18988
+ type: "preview_error",
18989
+ payload: {
18990
+ stage: "spawn",
18991
+ message: `This project uses yarn but yarn isn't installed, and installing it automatically failed (npm install -g yarn, exit ${ensured.code}). Install yarn in this environment and try the preview again.`
18992
+ }
18993
+ });
18994
+ return;
18995
+ }
18996
+ }
18933
18997
  emitProgress(
18934
18998
  "SETUP_RUN",
18935
18999
  `${missingDeps.cmd} ${missingDeps.args.join(" ")} (pre-flight \u2014 node_modules missing)`
@@ -19014,7 +19078,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
19014
19078
  "BOOT_SEQUENCE",
19015
19079
  `${spawnable.command} ${spawnable.args.join(" ")}`
19016
19080
  );
19017
- const devServer = (0, import_child_process18.spawn)(spawnable.command, spawnable.args, {
19081
+ const devServer = (0, import_child_process19.spawn)(spawnable.command, spawnable.args, {
19018
19082
  cwd: process.cwd(),
19019
19083
  env: { ...process.env, ...spawnable.env ?? {} },
19020
19084
  stdio: ["ignore", "pipe", "pipe"]
@@ -19117,6 +19181,47 @@ var previewStartH = (ctx, _cmd, parsed) => {
19117
19181
  const MAX_TUNNEL_ATTEMPTS = 3;
19118
19182
  let parsedUrl = null;
19119
19183
  let lastTunnelErr = "cloudflared did not emit a URL within 45s";
19184
+ const namedToken = process.env.PREVIEW_TUNNEL_TOKEN;
19185
+ const namedHostname = process.env.PREVIEW_TUNNEL_HOSTNAME;
19186
+ if (namedToken && namedHostname) {
19187
+ try {
19188
+ emitProgress("TUNNEL_STARTING", `named tunnel ${namedHostname}`);
19189
+ const candidate = await spawnNamedTunnel(bin, namedToken, detection.port);
19190
+ let registered = false;
19191
+ const onNamedChunk = (chunk) => {
19192
+ const s = chunk.toString();
19193
+ if (/Registered tunnel connection/i.test(s)) registered = true;
19194
+ const trimmed = s.replace(/\n+$/g, "");
19195
+ if (trimmed.length > 0) log.info("preview", `cloudflared: ${trimmed}`);
19196
+ };
19197
+ candidate.stderr.on("data", onNamedChunk);
19198
+ candidate.stdout.on("data", onNamedChunk);
19199
+ const namedDeadline = Date.now() + 45e3;
19200
+ while (!registered && Date.now() < namedDeadline) {
19201
+ await new Promise((r) => setTimeout(r, 250));
19202
+ }
19203
+ if (registered) {
19204
+ const namedUrl = `https://${namedHostname}`;
19205
+ log.info("preview", `named tunnel registered: ${namedUrl}`);
19206
+ tunnel = candidate;
19207
+ parsedUrl = namedUrl;
19208
+ } else {
19209
+ log.info(
19210
+ "preview",
19211
+ "named tunnel did not register within 45s \u2014 falling back to quick tunnel"
19212
+ );
19213
+ try {
19214
+ candidate.kill("SIGTERM");
19215
+ } catch {
19216
+ }
19217
+ }
19218
+ } catch (e) {
19219
+ log.info(
19220
+ "preview",
19221
+ `named tunnel failed (${e.message}) \u2014 falling back to quick tunnel`
19222
+ );
19223
+ }
19224
+ }
19120
19225
  for (let attempt = 1; attempt <= MAX_TUNNEL_ATTEMPTS && !parsedUrl; attempt += 1) {
19121
19226
  if (attempt > 1) {
19122
19227
  emitProgress(
@@ -19124,7 +19229,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
19124
19229
  `cloudflared quick tunnel (retry ${attempt}/${MAX_TUNNEL_ATTEMPTS})`
19125
19230
  );
19126
19231
  }
19127
- const candidate = (0, import_child_process18.spawn)(
19232
+ const candidate = (0, import_child_process19.spawn)(
19128
19233
  bin,
19129
19234
  ["tunnel", "--url", `http://localhost:${detection.port}`],
19130
19235
  { stdio: ["ignore", "pipe", "pipe"] }
@@ -19291,7 +19396,7 @@ async function dispatchCommand(ctx, cmd) {
19291
19396
  }
19292
19397
 
19293
19398
  // src/services/file-watcher.service.ts
19294
- var import_child_process19 = require("child_process");
19399
+ var import_child_process20 = require("child_process");
19295
19400
  var fs36 = __toESM(require("fs"));
19296
19401
  var os29 = __toESM(require("os"));
19297
19402
  var path43 = __toESM(require("path"));
@@ -20057,7 +20162,7 @@ async function _runGitImpl(cwd, args2, opts = {}) {
20057
20162
  return new Promise((resolve7) => {
20058
20163
  let proc;
20059
20164
  try {
20060
- proc = (0, import_child_process19.spawn)("git", args2, { cwd, env: process.env });
20165
+ proc = (0, import_child_process20.spawn)("git", args2, { cwd, env: process.env });
20061
20166
  } catch {
20062
20167
  resolve7(null);
20063
20168
  return;
@@ -20089,7 +20194,7 @@ function _runGit(cwd, args2, opts = {}) {
20089
20194
  var import_crypto4 = require("crypto");
20090
20195
 
20091
20196
  // src/services/turn-files/git-changeset.ts
20092
- var import_child_process20 = require("child_process");
20197
+ var import_child_process21 = require("child_process");
20093
20198
  var path44 = __toESM(require("path"));
20094
20199
  async function collectRepoChangeset(opts) {
20095
20200
  const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
@@ -20173,7 +20278,7 @@ function defaultRunGit(cwd, args2) {
20173
20278
  return new Promise((resolve7) => {
20174
20279
  let proc;
20175
20280
  try {
20176
- proc = (0, import_child_process20.spawn)("git", args2, { cwd, env: process.env });
20281
+ proc = (0, import_child_process21.spawn)("git", args2, { cwd, env: process.env });
20177
20282
  } catch {
20178
20283
  resolve7(null);
20179
20284
  return;
@@ -23182,13 +23287,13 @@ function fetchQuotaUsage(runtime, historySvc) {
23182
23287
  }
23183
23288
 
23184
23289
  // src/commands/start/keep-alive.ts
23185
- var import_child_process21 = require("child_process");
23290
+ var import_child_process22 = require("child_process");
23186
23291
  function buildKeepAlive(ctx) {
23187
23292
  let timer = null;
23188
23293
  async function setIdleTimeout(minutes) {
23189
23294
  if (!ctx.inCodespace || !ctx.codespaceName) return;
23190
23295
  await new Promise((resolve7) => {
23191
- const proc = (0, import_child_process21.spawn)(
23296
+ const proc = (0, import_child_process22.spawn)(
23192
23297
  "gh",
23193
23298
  [
23194
23299
  "api",
@@ -24255,11 +24360,11 @@ async function logout() {
24255
24360
  var import_picocolors10 = __toESM(require("picocolors"));
24256
24361
 
24257
24362
  // src/services/providers/github-codespaces.ts
24258
- var import_child_process22 = require("child_process");
24363
+ var import_child_process23 = require("child_process");
24259
24364
  var import_util4 = require("util");
24260
24365
  var import_picocolors8 = __toESM(require("picocolors"));
24261
24366
  var path49 = __toESM(require("path"));
24262
- var execFileP5 = (0, import_util4.promisify)(import_child_process22.execFile);
24367
+ var execFileP5 = (0, import_util4.promisify)(import_child_process23.execFile);
24263
24368
  var MAX_BUFFER = 8 * 1024 * 1024;
24264
24369
  function resetStdinForChild() {
24265
24370
  if (process.stdin.isTTY) {
@@ -24303,7 +24408,7 @@ var GitHubCodespacesProvider = class {
24303
24408
  if (!isAuthed) {
24304
24409
  resetStdinForChild();
24305
24410
  await new Promise((resolve7, reject) => {
24306
- const proc = (0, import_child_process22.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
24411
+ const proc = (0, import_child_process23.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
24307
24412
  stdio: "inherit"
24308
24413
  });
24309
24414
  proc.on("exit", (code) => {
@@ -24337,7 +24442,7 @@ var GitHubCodespacesProvider = class {
24337
24442
  wt(noteLines.join("\n"), "One more permission needed");
24338
24443
  resetStdinForChild();
24339
24444
  const refreshCode = await new Promise((resolve7, reject) => {
24340
- const proc = (0, import_child_process22.spawn)(
24445
+ const proc = (0, import_child_process23.spawn)(
24341
24446
  "gh",
24342
24447
  ["auth", "refresh", "-h", "github.com", "-s", "codespace"],
24343
24448
  { stdio: "inherit" }
@@ -24487,7 +24592,7 @@ var GitHubCodespacesProvider = class {
24487
24592
  O2.step(`Installing gh via ${installCmd.describe}\u2026`);
24488
24593
  resetStdinForChild();
24489
24594
  const ok = await new Promise((resolve7) => {
24490
- const proc = (0, import_child_process22.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
24595
+ const proc = (0, import_child_process23.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
24491
24596
  proc.on("exit", (code) => resolve7(code === 0));
24492
24597
  proc.on("error", () => resolve7(false));
24493
24598
  });
@@ -24514,7 +24619,7 @@ var GitHubCodespacesProvider = class {
24514
24619
  );
24515
24620
  resetStdinForChild();
24516
24621
  await new Promise((resolve7, reject) => {
24517
- const proc = (0, import_child_process22.spawn)(
24622
+ const proc = (0, import_child_process23.spawn)(
24518
24623
  "gh",
24519
24624
  ["auth", "refresh", "-h", "github.com", "-s", "repo,read:org"],
24520
24625
  { stdio: "inherit" }
@@ -24692,7 +24797,7 @@ var GitHubCodespacesProvider = class {
24692
24797
  async streamCommand(workspaceId, command2) {
24693
24798
  resetStdinForChild();
24694
24799
  return new Promise((resolve7, reject) => {
24695
- const proc = (0, import_child_process22.spawn)(
24800
+ const proc = (0, import_child_process23.spawn)(
24696
24801
  "gh",
24697
24802
  ["codespace", "ssh", "-c", workspaceId, "--", "-tt", command2],
24698
24803
  { stdio: "inherit" }
@@ -24719,11 +24824,11 @@ var GitHubCodespacesProvider = class {
24719
24824
  `mkdir -p ${shellQuote(remoteDir)} && tar -xzf - -C ${shellQuote(remoteDir)}`
24720
24825
  ];
24721
24826
  await new Promise((resolve7, reject) => {
24722
- const tar = (0, import_child_process22.spawn)("tar", tarArgs, {
24827
+ const tar = (0, import_child_process23.spawn)("tar", tarArgs, {
24723
24828
  stdio: ["ignore", "pipe", "pipe"],
24724
24829
  env: tarEnv
24725
24830
  });
24726
- const ssh = (0, import_child_process22.spawn)("gh", sshArgs, {
24831
+ const ssh = (0, import_child_process23.spawn)("gh", sshArgs, {
24727
24832
  stdio: [tar.stdout, "pipe", "pipe"]
24728
24833
  });
24729
24834
  let tarErr = "";
@@ -24757,7 +24862,7 @@ var GitHubCodespacesProvider = class {
24757
24862
  }
24758
24863
  const cmd = parts.join(" && ");
24759
24864
  await new Promise((resolve7, reject) => {
24760
- const proc = (0, import_child_process22.spawn)(
24865
+ const proc = (0, import_child_process23.spawn)(
24761
24866
  "gh",
24762
24867
  ["codespace", "ssh", "-c", workspaceId, "--", cmd],
24763
24868
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -24815,11 +24920,11 @@ function shellQuote(s) {
24815
24920
  }
24816
24921
 
24817
24922
  // src/services/providers/gitpod.ts
24818
- var import_child_process23 = require("child_process");
24923
+ var import_child_process24 = require("child_process");
24819
24924
  var import_util5 = require("util");
24820
24925
  var path50 = __toESM(require("path"));
24821
24926
  var import_picocolors9 = __toESM(require("picocolors"));
24822
- var execFileP6 = (0, import_util5.promisify)(import_child_process23.execFile);
24927
+ var execFileP6 = (0, import_util5.promisify)(import_child_process24.execFile);
24823
24928
  var MAX_BUFFER2 = 8 * 1024 * 1024;
24824
24929
  function resetStdinForChild2() {
24825
24930
  if (process.stdin.isTTY) {
@@ -24859,7 +24964,7 @@ var GitpodProvider = class {
24859
24964
  );
24860
24965
  resetStdinForChild2();
24861
24966
  await new Promise((resolve7, reject) => {
24862
- const proc = (0, import_child_process23.spawn)("gitpod", ["login"], { stdio: "inherit" });
24967
+ const proc = (0, import_child_process24.spawn)("gitpod", ["login"], { stdio: "inherit" });
24863
24968
  proc.on("exit", (code) => {
24864
24969
  if (code === 0) resolve7();
24865
24970
  else reject(new Error("gitpod login failed."));
@@ -25011,7 +25116,7 @@ var GitpodProvider = class {
25011
25116
  async streamCommand(workspaceId, command2) {
25012
25117
  resetStdinForChild2();
25013
25118
  return new Promise((resolve7, reject) => {
25014
- const proc = (0, import_child_process23.spawn)(
25119
+ const proc = (0, import_child_process24.spawn)(
25015
25120
  "gitpod",
25016
25121
  ["workspace", "ssh", workspaceId, "--", "-tt", command2],
25017
25122
  { stdio: "inherit" }
@@ -25031,11 +25136,11 @@ var GitpodProvider = class {
25031
25136
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
25032
25137
  const remoteCmd = `mkdir -p ${shellQuote2(remoteDir)} && tar -xzf - -C ${shellQuote2(remoteDir)}`;
25033
25138
  await new Promise((resolve7, reject) => {
25034
- const tar = (0, import_child_process23.spawn)("tar", tarArgs, {
25139
+ const tar = (0, import_child_process24.spawn)("tar", tarArgs, {
25035
25140
  stdio: ["ignore", "pipe", "pipe"],
25036
25141
  env: tarEnv
25037
25142
  });
25038
- const ssh = (0, import_child_process23.spawn)(
25143
+ const ssh = (0, import_child_process24.spawn)(
25039
25144
  "gitpod",
25040
25145
  ["workspace", "ssh", workspaceId, "--", remoteCmd],
25041
25146
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -25067,7 +25172,7 @@ var GitpodProvider = class {
25067
25172
  }
25068
25173
  const cmd = parts.join(" && ");
25069
25174
  await new Promise((resolve7, reject) => {
25070
- const proc = (0, import_child_process23.spawn)(
25175
+ const proc = (0, import_child_process24.spawn)(
25071
25176
  "gitpod",
25072
25177
  ["workspace", "ssh", workspaceId, "--", cmd],
25073
25178
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -25091,10 +25196,10 @@ function shellQuote2(s) {
25091
25196
  }
25092
25197
 
25093
25198
  // src/services/providers/gitlab-workspaces.ts
25094
- var import_child_process24 = require("child_process");
25199
+ var import_child_process25 = require("child_process");
25095
25200
  var import_util6 = require("util");
25096
25201
  var path51 = __toESM(require("path"));
25097
- var execFileP7 = (0, import_util6.promisify)(import_child_process24.execFile);
25202
+ var execFileP7 = (0, import_util6.promisify)(import_child_process25.execFile);
25098
25203
  var MAX_BUFFER3 = 8 * 1024 * 1024;
25099
25204
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
25100
25205
  function resetStdinForChild3() {
@@ -25136,7 +25241,7 @@ var GitLabWorkspacesProvider = class {
25136
25241
  );
25137
25242
  resetStdinForChild3();
25138
25243
  await new Promise((resolve7, reject) => {
25139
- const proc = (0, import_child_process24.spawn)(
25244
+ const proc = (0, import_child_process25.spawn)(
25140
25245
  "glab",
25141
25246
  ["auth", "login", "--scopes", "api,read_user,read_repository"],
25142
25247
  { stdio: "inherit" }
@@ -25308,7 +25413,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
25308
25413
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
25309
25414
  resetStdinForChild3();
25310
25415
  return new Promise((resolve7, reject) => {
25311
- const proc = (0, import_child_process24.spawn)(
25416
+ const proc = (0, import_child_process25.spawn)(
25312
25417
  "ssh",
25313
25418
  ["-tt", "-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, command2],
25314
25419
  { stdio: "inherit" }
@@ -25329,8 +25434,8 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
25329
25434
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
25330
25435
  const remoteCmd = `mkdir -p ${shellQuote3(remoteDir)} && tar -xzf - -C ${shellQuote3(remoteDir)}`;
25331
25436
  await new Promise((resolve7, reject) => {
25332
- const tar = (0, import_child_process24.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
25333
- const ssh = (0, import_child_process24.spawn)(
25437
+ const tar = (0, import_child_process25.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
25438
+ const ssh = (0, import_child_process25.spawn)(
25334
25439
  "ssh",
25335
25440
  ["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, remoteCmd],
25336
25441
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -25360,7 +25465,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
25360
25465
  }
25361
25466
  const cmd = parts.join(" && ");
25362
25467
  await new Promise((resolve7, reject) => {
25363
- const proc = (0, import_child_process24.spawn)(
25468
+ const proc = (0, import_child_process25.spawn)(
25364
25469
  "ssh",
25365
25470
  ["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, cmd],
25366
25471
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -25419,10 +25524,10 @@ function shellQuote3(s) {
25419
25524
  }
25420
25525
 
25421
25526
  // src/services/providers/railway.ts
25422
- var import_child_process25 = require("child_process");
25527
+ var import_child_process26 = require("child_process");
25423
25528
  var import_util7 = require("util");
25424
25529
  var path52 = __toESM(require("path"));
25425
- var execFileP8 = (0, import_util7.promisify)(import_child_process25.execFile);
25530
+ var execFileP8 = (0, import_util7.promisify)(import_child_process26.execFile);
25426
25531
  var MAX_BUFFER4 = 8 * 1024 * 1024;
25427
25532
  function resetStdinForChild4() {
25428
25533
  if (process.stdin.isTTY) {
@@ -25463,7 +25568,7 @@ var RailwayProvider = class {
25463
25568
  );
25464
25569
  resetStdinForChild4();
25465
25570
  await new Promise((resolve7, reject) => {
25466
- const proc = (0, import_child_process25.spawn)("railway", ["login"], { stdio: "inherit" });
25571
+ const proc = (0, import_child_process26.spawn)("railway", ["login"], { stdio: "inherit" });
25467
25572
  proc.on("exit", (code) => {
25468
25573
  if (code === 0) resolve7();
25469
25574
  else reject(new Error("railway login failed."));
@@ -25606,7 +25711,7 @@ var RailwayProvider = class {
25606
25711
  }
25607
25712
  resetStdinForChild4();
25608
25713
  return new Promise((resolve7, reject) => {
25609
- const proc = (0, import_child_process25.spawn)(
25714
+ const proc = (0, import_child_process26.spawn)(
25610
25715
  "railway",
25611
25716
  ["shell", "--project", projectId, "--service", serviceId, "--command", command2],
25612
25717
  { stdio: "inherit" }
@@ -25630,8 +25735,8 @@ var RailwayProvider = class {
25630
25735
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
25631
25736
  const remoteCmd = `mkdir -p ${shellQuote4(remoteDir)} && tar -xzf - -C ${shellQuote4(remoteDir)}`;
25632
25737
  await new Promise((resolve7, reject) => {
25633
- const tar = (0, import_child_process25.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
25634
- const sh = (0, import_child_process25.spawn)(
25738
+ const tar = (0, import_child_process26.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
25739
+ const sh = (0, import_child_process26.spawn)(
25635
25740
  "railway",
25636
25741
  ["shell", "--project", projectId, "--service", serviceId, "--command", remoteCmd],
25637
25742
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -25664,7 +25769,7 @@ var RailwayProvider = class {
25664
25769
  }
25665
25770
  const cmd = parts.join(" && ");
25666
25771
  await new Promise((resolve7, reject) => {
25667
- const proc = (0, import_child_process25.spawn)(
25772
+ const proc = (0, import_child_process26.spawn)(
25668
25773
  "railway",
25669
25774
  ["shell", "--project", projectId, "--service", serviceId, "--command", cmd],
25670
25775
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -26839,6 +26944,10 @@ var HostAgentSupervisor = class {
26839
26944
  }
26840
26945
  const home = process.env.HOME || os36.homedir();
26841
26946
  childEnv.PATH = `${home}/.local/bin:${process.env.PATH ?? ""}`;
26947
+ if (payload.previewTunnelToken && payload.previewHostname) {
26948
+ childEnv.PREVIEW_TUNNEL_TOKEN = payload.previewTunnelToken;
26949
+ childEnv.PREVIEW_TUNNEL_HOSTNAME = payload.previewHostname;
26950
+ }
26842
26951
  report("spawning", "starting agent");
26843
26952
  const proc = this.spawnChild(childEnv, cwd, extraArgs);
26844
26953
  const child = { deployId: payload.deployId, proc };
@@ -27167,7 +27276,7 @@ function checkChokidar() {
27167
27276
  }
27168
27277
  async function doctor(args2 = []) {
27169
27278
  const json = args2.includes("--json");
27170
- const cliVersion = true ? "2.39.39" : "0.0.0-dev";
27279
+ const cliVersion = true ? "2.39.41" : "0.0.0-dev";
27171
27280
  const apiBase2 = resolveApiBaseUrl();
27172
27281
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
27173
27282
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -27366,7 +27475,7 @@ async function completion(args2) {
27366
27475
  // src/commands/version.ts
27367
27476
  var import_picocolors13 = __toESM(require("picocolors"));
27368
27477
  function version2() {
27369
- const v = true ? "2.39.39" : "unknown";
27478
+ const v = true ? "2.39.41" : "unknown";
27370
27479
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
27371
27480
  }
27372
27481
 
@@ -27652,7 +27761,7 @@ function checkForUpdates() {
27652
27761
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
27653
27762
  if (process.env.CI) return;
27654
27763
  if (!process.stdout.isTTY) return;
27655
- const current = true ? "2.39.39" : null;
27764
+ const current = true ? "2.39.41" : null;
27656
27765
  if (!current) return;
27657
27766
  const cache = readCache();
27658
27767
  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.39",
3
+ "version": "2.39.41",
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",