codeam-cli 2.39.2 → 2.39.4

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,12 @@ 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.2] — 2026-06-12
8
+
9
+ ### Added
10
+
11
+ - **cli:** Pre-warm preview detection so the first Start Preview is instant
12
+
7
13
  ## [2.39.1] — 2026-06-12
8
14
 
9
15
  ### 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.2",
501
+ version: "2.39.4",
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",
@@ -1186,8 +1186,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
1186
1186
  return decodedFile;
1187
1187
  };
1188
1188
  }
1189
- function normalizeWindowsPath(path52) {
1190
- return path52.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1189
+ function normalizeWindowsPath(path53) {
1190
+ return path53.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1191
1191
  }
1192
1192
 
1193
1193
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3667,9 +3667,9 @@ async function addSourceContext(frames) {
3667
3667
  LRU_FILE_CONTENTS_CACHE.reduce();
3668
3668
  return frames;
3669
3669
  }
3670
- function getContextLinesFromFile(path52, ranges, output) {
3670
+ function getContextLinesFromFile(path53, ranges, output) {
3671
3671
  return new Promise((resolve7) => {
3672
- const stream = (0, import_node_fs.createReadStream)(path52);
3672
+ const stream = (0, import_node_fs.createReadStream)(path53);
3673
3673
  const lineReaded = (0, import_node_readline.createInterface)({
3674
3674
  input: stream
3675
3675
  });
@@ -3684,7 +3684,7 @@ function getContextLinesFromFile(path52, ranges, output) {
3684
3684
  let rangeStart = range[0];
3685
3685
  let rangeEnd = range[1];
3686
3686
  function onStreamError() {
3687
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path52, 1);
3687
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path53, 1);
3688
3688
  lineReaded.close();
3689
3689
  lineReaded.removeAllListeners();
3690
3690
  destroyStreamAndResolve();
@@ -3745,8 +3745,8 @@ function clearLineContext(frame) {
3745
3745
  delete frame.context_line;
3746
3746
  delete frame.post_context;
3747
3747
  }
3748
- function shouldSkipContextLinesForFile(path52) {
3749
- return path52.startsWith("node:") || path52.endsWith(".min.js") || path52.endsWith(".min.cjs") || path52.endsWith(".min.mjs") || path52.startsWith("data:");
3748
+ function shouldSkipContextLinesForFile(path53) {
3749
+ return path53.startsWith("node:") || path53.endsWith(".min.js") || path53.endsWith(".min.cjs") || path53.endsWith(".min.mjs") || path53.startsWith("data:");
3750
3750
  }
3751
3751
  function shouldSkipContextLinesForFrame(frame) {
3752
3752
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -5900,7 +5900,7 @@ function readAnonId() {
5900
5900
  }
5901
5901
  function superProperties() {
5902
5902
  return {
5903
- cliVersion: true ? "2.39.2" : "0.0.0-dev",
5903
+ cliVersion: true ? "2.39.4" : "0.0.0-dev",
5904
5904
  nodeVersion: process.version,
5905
5905
  platform: process.platform,
5906
5906
  arch: process.arch,
@@ -9978,13 +9978,13 @@ function detectStartupBanner(lines) {
9978
9978
  while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
9979
9979
  if (metaIdx - artStart < 2) return null;
9980
9980
  const pathLine = (lines[metaIdx + 1] ?? "").trim();
9981
- const path52 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
9981
+ const path53 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
9982
9982
  return {
9983
9983
  title: "",
9984
9984
  subtitle: lines[metaIdx].trim(),
9985
- path: path52,
9985
+ path: path53,
9986
9986
  startIdx: artStart,
9987
- endIdx: metaIdx + (path52 ? 1 : 0)
9987
+ endIdx: metaIdx + (path53 ? 1 : 0)
9988
9988
  };
9989
9989
  }
9990
9990
 
@@ -11342,11 +11342,11 @@ function parseReview(stdout) {
11342
11342
  for (const line of lines) {
11343
11343
  const m = line.match(HUNK_LINE_RE);
11344
11344
  if (!m) continue;
11345
- const [, path52, lineNo, sevToken, message] = m;
11346
- if (!path52 || !lineNo || !message) continue;
11345
+ const [, path53, lineNo, sevToken, message] = m;
11346
+ if (!path53 || !lineNo || !message) continue;
11347
11347
  const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
11348
11348
  hunks.push({
11349
- path: path52.trim(),
11349
+ path: path53.trim(),
11350
11350
  line: Number(lineNo),
11351
11351
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
11352
11352
  message: cleanedMessage
@@ -17598,8 +17598,9 @@ var BdAdapter = class {
17598
17598
  `bd ${args2.join(" ")} (cwd=${this.opts.cwd ?? process.cwd()}, shared-server)`
17599
17599
  );
17600
17600
  let res = await _spawnSeam.run(binary, args2, { cwd: this.opts.cwd, env });
17601
- for (let attempt = 1; attempt <= 3 && res.code === -1 && res.stderr.includes("ENOENT"); attempt++) {
17602
- log.info("beads", `bd ${args2[0]} spawn ENOENT (transient binary) \u2014 retry ${attempt}/3`);
17601
+ const TRANSIENT_SPAWN = /ENOENT|ETXTBSY/;
17602
+ for (let attempt = 1; attempt <= 5 && res.code === -1 && TRANSIENT_SPAWN.test(res.stderr); attempt++) {
17603
+ log.info("beads", `bd ${args2[0]} transient spawn failure (binary busy) \u2014 retry ${attempt}/5`);
17603
17604
  await _adapterSeam.sleep(750 * attempt);
17604
17605
  res = await _spawnSeam.run(binary, args2, { cwd: this.opts.cwd, env });
17605
17606
  }
@@ -19891,10 +19892,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
19891
19892
  /[\\/]Start Menu([\\/]|$)/i,
19892
19893
  /[\\/]Templates([\\/]|$)/i
19893
19894
  ];
19894
- function isUnsafeWindowsWatchRoot(dir, homedir24) {
19895
+ function isUnsafeWindowsWatchRoot(dir, homedir25) {
19895
19896
  const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
19896
19897
  const cwd = norm(dir);
19897
- const home = norm(homedir24);
19898
+ const home = norm(homedir25);
19898
19899
  if (cwd === home) return true;
19899
19900
  if (/^[a-z]:$/.test(cwd)) return true;
19900
19901
  const sysRoots = [
@@ -24105,6 +24106,7 @@ async function autoLinkAfterPair(opts) {
24105
24106
  // src/commands/pair-auto.ts
24106
24107
  var fs38 = __toESM(require("fs"));
24107
24108
  var os30 = __toESM(require("os"));
24109
+ var path46 = __toESM(require("path"));
24108
24110
  var import_crypto7 = require("crypto");
24109
24111
 
24110
24112
  // src/commands/start-infra-only.ts
@@ -24299,12 +24301,12 @@ function readTokenFromArgs(args2) {
24299
24301
  }
24300
24302
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
24301
24303
  if (fileFlag) {
24302
- const path52 = fileFlag.slice("--token-file=".length);
24304
+ const path53 = fileFlag.slice("--token-file=".length);
24303
24305
  try {
24304
- const content = fs38.readFileSync(path52, "utf8").trim();
24305
- if (content.length === 0) fail(`--token-file ${path52} is empty`);
24306
+ const content = fs38.readFileSync(path53, "utf8").trim();
24307
+ if (content.length === 0) fail(`--token-file ${path53} is empty`);
24306
24308
  try {
24307
- fs38.unlinkSync(path52);
24309
+ fs38.unlinkSync(path53);
24308
24310
  } catch {
24309
24311
  }
24310
24312
  return content;
@@ -24386,7 +24388,53 @@ async function claim(token, pluginId) {
24386
24388
  }
24387
24389
  }
24388
24390
  }
24391
+ function pairAutoLockPath() {
24392
+ return path46.join(os30.homedir(), ".codeam", "pair-auto.lock");
24393
+ }
24394
+ function isLivePairAuto(pid) {
24395
+ if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
24396
+ try {
24397
+ process.kill(pid, 0);
24398
+ } catch (e) {
24399
+ if (e.code !== "EPERM") return false;
24400
+ }
24401
+ try {
24402
+ return fs38.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
24403
+ } catch {
24404
+ return true;
24405
+ }
24406
+ }
24407
+ function acquireSingletonLock() {
24408
+ const lockPath = pairAutoLockPath();
24409
+ try {
24410
+ fs38.mkdirSync(path46.dirname(lockPath), { recursive: true });
24411
+ try {
24412
+ fs38.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
24413
+ } catch (e) {
24414
+ if (e.code !== "EEXIST") throw e;
24415
+ const holder = Number(fs38.readFileSync(lockPath, "utf8").trim());
24416
+ if (isLivePairAuto(holder)) return false;
24417
+ fs38.writeFileSync(lockPath, String(process.pid));
24418
+ }
24419
+ process.once("exit", () => {
24420
+ try {
24421
+ if (fs38.existsSync(lockPath) && Number(fs38.readFileSync(lockPath, "utf8").trim()) === process.pid) {
24422
+ fs38.unlinkSync(lockPath);
24423
+ }
24424
+ } catch {
24425
+ }
24426
+ });
24427
+ return true;
24428
+ } catch {
24429
+ return true;
24430
+ }
24431
+ }
24389
24432
  async function pairAuto(args2) {
24433
+ if (!acquireSingletonLock()) {
24434
+ capture("pair_auto_deferred_singleton", {});
24435
+ console.log(" A codeam session is already running here \u2014 deferring to it.");
24436
+ return;
24437
+ }
24390
24438
  const token = readTokenFromArgs(args2);
24391
24439
  const pluginId = (0, import_crypto7.randomUUID)();
24392
24440
  capture("pair_auto_started", { pluginId });
@@ -24570,7 +24618,7 @@ var import_picocolors10 = __toESM(require("picocolors"));
24570
24618
  var import_child_process22 = require("child_process");
24571
24619
  var import_util4 = require("util");
24572
24620
  var import_picocolors8 = __toESM(require("picocolors"));
24573
- var path46 = __toESM(require("path"));
24621
+ var path47 = __toESM(require("path"));
24574
24622
  var execFileP5 = (0, import_util4.promisify)(import_child_process22.execFile);
24575
24623
  var MAX_BUFFER = 8 * 1024 * 1024;
24576
24624
  function resetStdinForChild() {
@@ -25059,7 +25107,7 @@ var GitHubCodespacesProvider = class {
25059
25107
  });
25060
25108
  }
25061
25109
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25062
- const remoteDir = path46.posix.dirname(remotePath);
25110
+ const remoteDir = path47.posix.dirname(remotePath);
25063
25111
  const parts = [
25064
25112
  `mkdir -p ${shellQuote(remoteDir)}`,
25065
25113
  `cat > ${shellQuote(remotePath)}`
@@ -25129,7 +25177,7 @@ function shellQuote(s) {
25129
25177
  // src/services/providers/gitpod.ts
25130
25178
  var import_child_process23 = require("child_process");
25131
25179
  var import_util5 = require("util");
25132
- var path47 = __toESM(require("path"));
25180
+ var path48 = __toESM(require("path"));
25133
25181
  var import_picocolors9 = __toESM(require("picocolors"));
25134
25182
  var execFileP6 = (0, import_util5.promisify)(import_child_process23.execFile);
25135
25183
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -25369,7 +25417,7 @@ var GitpodProvider = class {
25369
25417
  });
25370
25418
  }
25371
25419
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25372
- const remoteDir = path47.posix.dirname(remotePath);
25420
+ const remoteDir = path48.posix.dirname(remotePath);
25373
25421
  const parts = [
25374
25422
  `mkdir -p ${shellQuote2(remoteDir)}`,
25375
25423
  `cat > ${shellQuote2(remotePath)}`
@@ -25405,7 +25453,7 @@ function shellQuote2(s) {
25405
25453
  // src/services/providers/gitlab-workspaces.ts
25406
25454
  var import_child_process24 = require("child_process");
25407
25455
  var import_util6 = require("util");
25408
- var path48 = __toESM(require("path"));
25456
+ var path49 = __toESM(require("path"));
25409
25457
  var execFileP7 = (0, import_util6.promisify)(import_child_process24.execFile);
25410
25458
  var MAX_BUFFER3 = 8 * 1024 * 1024;
25411
25459
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -25665,7 +25713,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
25665
25713
  }
25666
25714
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25667
25715
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
25668
- const remoteDir = path48.posix.dirname(remotePath);
25716
+ const remoteDir = path49.posix.dirname(remotePath);
25669
25717
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
25670
25718
  if (options.mode != null) {
25671
25719
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -25733,7 +25781,7 @@ function shellQuote3(s) {
25733
25781
  // src/services/providers/railway.ts
25734
25782
  var import_child_process25 = require("child_process");
25735
25783
  var import_util7 = require("util");
25736
- var path49 = __toESM(require("path"));
25784
+ var path50 = __toESM(require("path"));
25737
25785
  var execFileP8 = (0, import_util7.promisify)(import_child_process25.execFile);
25738
25786
  var MAX_BUFFER4 = 8 * 1024 * 1024;
25739
25787
  function resetStdinForChild4() {
@@ -25969,7 +26017,7 @@ var RailwayProvider = class {
25969
26017
  if (!projectId || !serviceId) {
25970
26018
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
25971
26019
  }
25972
- const remoteDir = path49.posix.dirname(remotePath);
26020
+ const remoteDir = path50.posix.dirname(remotePath);
25973
26021
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
25974
26022
  if (options.mode != null) {
25975
26023
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -26513,7 +26561,7 @@ var import_node_dns = require("dns");
26513
26561
  var import_node_util4 = require("util");
26514
26562
  var import_node_crypto8 = require("crypto");
26515
26563
  var fs39 = __toESM(require("fs"));
26516
- var path50 = __toESM(require("path"));
26564
+ var path51 = __toESM(require("path"));
26517
26565
  var import_picocolors12 = __toESM(require("picocolors"));
26518
26566
  var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
26519
26567
  async function checkDns(apiBase) {
@@ -26569,10 +26617,10 @@ async function checkHealth(apiBase) {
26569
26617
  }
26570
26618
  }
26571
26619
  function checkConfigDir() {
26572
- const dir = path50.join(require("os").homedir(), ".codeam");
26620
+ const dir = path51.join(require("os").homedir(), ".codeam");
26573
26621
  try {
26574
26622
  fs39.mkdirSync(dir, { recursive: true, mode: 448 });
26575
- const probe = path50.join(dir, ".doctor-probe");
26623
+ const probe = path51.join(dir, ".doctor-probe");
26576
26624
  fs39.writeFileSync(probe, "ok", { mode: 384 });
26577
26625
  const read = fs39.readFileSync(probe, "utf8");
26578
26626
  fs39.unlinkSync(probe);
@@ -26639,7 +26687,7 @@ function checkNodePty() {
26639
26687
  detail: "not required on this platform"
26640
26688
  };
26641
26689
  }
26642
- const vendoredPath = path50.join(__dirname, "vendor", "node-pty");
26690
+ const vendoredPath = path51.join(__dirname, "vendor", "node-pty");
26643
26691
  for (const target of [vendoredPath, "node-pty"]) {
26644
26692
  try {
26645
26693
  require(target);
@@ -26681,7 +26729,7 @@ function checkChokidar() {
26681
26729
  }
26682
26730
  async function doctor(args2 = []) {
26683
26731
  const json = args2.includes("--json");
26684
- const cliVersion = true ? "2.39.2" : "0.0.0-dev";
26732
+ const cliVersion = true ? "2.39.4" : "0.0.0-dev";
26685
26733
  const apiBase = resolveApiBaseUrl();
26686
26734
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
26687
26735
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -26880,7 +26928,7 @@ async function completion(args2) {
26880
26928
  // src/commands/version.ts
26881
26929
  var import_picocolors13 = __toESM(require("picocolors"));
26882
26930
  function version2() {
26883
- const v = true ? "2.39.2" : "unknown";
26931
+ const v = true ? "2.39.4" : "unknown";
26884
26932
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
26885
26933
  }
26886
26934
 
@@ -27010,7 +27058,7 @@ var _subcommandHelpKeys = Object.keys(HELPS);
27010
27058
  // src/lib/updateNotifier.ts
27011
27059
  var fs40 = __toESM(require("fs"));
27012
27060
  var os31 = __toESM(require("os"));
27013
- var path51 = __toESM(require("path"));
27061
+ var path52 = __toESM(require("path"));
27014
27062
  var https8 = __toESM(require("https"));
27015
27063
  var import_node_child_process12 = require("child_process");
27016
27064
  var import_picocolors16 = __toESM(require("picocolors"));
@@ -27019,8 +27067,8 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
27019
27067
  var TTL_MS = 24 * 60 * 60 * 1e3;
27020
27068
  var REQUEST_TIMEOUT_MS = 1500;
27021
27069
  function cachePath() {
27022
- const dir = path51.join(os31.homedir(), ".codeam");
27023
- return path51.join(dir, "update-check.json");
27070
+ const dir = path52.join(os31.homedir(), ".codeam");
27071
+ return path52.join(dir, "update-check.json");
27024
27072
  }
27025
27073
  function readCache() {
27026
27074
  try {
@@ -27035,7 +27083,7 @@ function readCache() {
27035
27083
  function writeCache(cache) {
27036
27084
  try {
27037
27085
  const file = cachePath();
27038
- fs40.mkdirSync(path51.dirname(file), { recursive: true });
27086
+ fs40.mkdirSync(path52.dirname(file), { recursive: true });
27039
27087
  const tmp = `${file}.${process.pid}.tmp`;
27040
27088
  fs40.writeFileSync(tmp, JSON.stringify(cache));
27041
27089
  fs40.renameSync(tmp, file);
@@ -27112,7 +27160,7 @@ function isLinkedInstall() {
27112
27160
  timeout: 2e3
27113
27161
  }).trim();
27114
27162
  if (!root) return false;
27115
- const pkgPath = path51.join(root, PKG_NAME);
27163
+ const pkgPath = path52.join(root, PKG_NAME);
27116
27164
  return fs40.lstatSync(pkgPath).isSymbolicLink();
27117
27165
  } catch {
27118
27166
  return false;
@@ -27166,7 +27214,7 @@ function checkForUpdates() {
27166
27214
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
27167
27215
  if (process.env.CI) return;
27168
27216
  if (!process.stdout.isTTY) return;
27169
- const current = true ? "2.39.2" : null;
27217
+ const current = true ? "2.39.4" : null;
27170
27218
  if (!current) return;
27171
27219
  const cache = readCache();
27172
27220
  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.2",
3
+ "version": "2.39.4",
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",