codeam-cli 2.39.2 → 2.39.3

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.3",
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.3" : "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
@@ -19891,10 +19891,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
19891
19891
  /[\\/]Start Menu([\\/]|$)/i,
19892
19892
  /[\\/]Templates([\\/]|$)/i
19893
19893
  ];
19894
- function isUnsafeWindowsWatchRoot(dir, homedir24) {
19894
+ function isUnsafeWindowsWatchRoot(dir, homedir25) {
19895
19895
  const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
19896
19896
  const cwd = norm(dir);
19897
- const home = norm(homedir24);
19897
+ const home = norm(homedir25);
19898
19898
  if (cwd === home) return true;
19899
19899
  if (/^[a-z]:$/.test(cwd)) return true;
19900
19900
  const sysRoots = [
@@ -24105,6 +24105,7 @@ async function autoLinkAfterPair(opts) {
24105
24105
  // src/commands/pair-auto.ts
24106
24106
  var fs38 = __toESM(require("fs"));
24107
24107
  var os30 = __toESM(require("os"));
24108
+ var path46 = __toESM(require("path"));
24108
24109
  var import_crypto7 = require("crypto");
24109
24110
 
24110
24111
  // src/commands/start-infra-only.ts
@@ -24299,12 +24300,12 @@ function readTokenFromArgs(args2) {
24299
24300
  }
24300
24301
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
24301
24302
  if (fileFlag) {
24302
- const path52 = fileFlag.slice("--token-file=".length);
24303
+ const path53 = fileFlag.slice("--token-file=".length);
24303
24304
  try {
24304
- const content = fs38.readFileSync(path52, "utf8").trim();
24305
- if (content.length === 0) fail(`--token-file ${path52} is empty`);
24305
+ const content = fs38.readFileSync(path53, "utf8").trim();
24306
+ if (content.length === 0) fail(`--token-file ${path53} is empty`);
24306
24307
  try {
24307
- fs38.unlinkSync(path52);
24308
+ fs38.unlinkSync(path53);
24308
24309
  } catch {
24309
24310
  }
24310
24311
  return content;
@@ -24386,7 +24387,53 @@ async function claim(token, pluginId) {
24386
24387
  }
24387
24388
  }
24388
24389
  }
24390
+ function pairAutoLockPath() {
24391
+ return path46.join(os30.homedir(), ".codeam", "pair-auto.lock");
24392
+ }
24393
+ function isLivePairAuto(pid) {
24394
+ if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
24395
+ try {
24396
+ process.kill(pid, 0);
24397
+ } catch (e) {
24398
+ if (e.code !== "EPERM") return false;
24399
+ }
24400
+ try {
24401
+ return fs38.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
24402
+ } catch {
24403
+ return true;
24404
+ }
24405
+ }
24406
+ function acquireSingletonLock() {
24407
+ const lockPath = pairAutoLockPath();
24408
+ try {
24409
+ fs38.mkdirSync(path46.dirname(lockPath), { recursive: true });
24410
+ try {
24411
+ fs38.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
24412
+ } catch (e) {
24413
+ if (e.code !== "EEXIST") throw e;
24414
+ const holder = Number(fs38.readFileSync(lockPath, "utf8").trim());
24415
+ if (isLivePairAuto(holder)) return false;
24416
+ fs38.writeFileSync(lockPath, String(process.pid));
24417
+ }
24418
+ process.once("exit", () => {
24419
+ try {
24420
+ if (fs38.existsSync(lockPath) && Number(fs38.readFileSync(lockPath, "utf8").trim()) === process.pid) {
24421
+ fs38.unlinkSync(lockPath);
24422
+ }
24423
+ } catch {
24424
+ }
24425
+ });
24426
+ return true;
24427
+ } catch {
24428
+ return true;
24429
+ }
24430
+ }
24389
24431
  async function pairAuto(args2) {
24432
+ if (!acquireSingletonLock()) {
24433
+ capture("pair_auto_deferred_singleton", {});
24434
+ console.log(" A codeam session is already running here \u2014 deferring to it.");
24435
+ return;
24436
+ }
24390
24437
  const token = readTokenFromArgs(args2);
24391
24438
  const pluginId = (0, import_crypto7.randomUUID)();
24392
24439
  capture("pair_auto_started", { pluginId });
@@ -24570,7 +24617,7 @@ var import_picocolors10 = __toESM(require("picocolors"));
24570
24617
  var import_child_process22 = require("child_process");
24571
24618
  var import_util4 = require("util");
24572
24619
  var import_picocolors8 = __toESM(require("picocolors"));
24573
- var path46 = __toESM(require("path"));
24620
+ var path47 = __toESM(require("path"));
24574
24621
  var execFileP5 = (0, import_util4.promisify)(import_child_process22.execFile);
24575
24622
  var MAX_BUFFER = 8 * 1024 * 1024;
24576
24623
  function resetStdinForChild() {
@@ -25059,7 +25106,7 @@ var GitHubCodespacesProvider = class {
25059
25106
  });
25060
25107
  }
25061
25108
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25062
- const remoteDir = path46.posix.dirname(remotePath);
25109
+ const remoteDir = path47.posix.dirname(remotePath);
25063
25110
  const parts = [
25064
25111
  `mkdir -p ${shellQuote(remoteDir)}`,
25065
25112
  `cat > ${shellQuote(remotePath)}`
@@ -25129,7 +25176,7 @@ function shellQuote(s) {
25129
25176
  // src/services/providers/gitpod.ts
25130
25177
  var import_child_process23 = require("child_process");
25131
25178
  var import_util5 = require("util");
25132
- var path47 = __toESM(require("path"));
25179
+ var path48 = __toESM(require("path"));
25133
25180
  var import_picocolors9 = __toESM(require("picocolors"));
25134
25181
  var execFileP6 = (0, import_util5.promisify)(import_child_process23.execFile);
25135
25182
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -25369,7 +25416,7 @@ var GitpodProvider = class {
25369
25416
  });
25370
25417
  }
25371
25418
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25372
- const remoteDir = path47.posix.dirname(remotePath);
25419
+ const remoteDir = path48.posix.dirname(remotePath);
25373
25420
  const parts = [
25374
25421
  `mkdir -p ${shellQuote2(remoteDir)}`,
25375
25422
  `cat > ${shellQuote2(remotePath)}`
@@ -25405,7 +25452,7 @@ function shellQuote2(s) {
25405
25452
  // src/services/providers/gitlab-workspaces.ts
25406
25453
  var import_child_process24 = require("child_process");
25407
25454
  var import_util6 = require("util");
25408
- var path48 = __toESM(require("path"));
25455
+ var path49 = __toESM(require("path"));
25409
25456
  var execFileP7 = (0, import_util6.promisify)(import_child_process24.execFile);
25410
25457
  var MAX_BUFFER3 = 8 * 1024 * 1024;
25411
25458
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -25665,7 +25712,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
25665
25712
  }
25666
25713
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25667
25714
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
25668
- const remoteDir = path48.posix.dirname(remotePath);
25715
+ const remoteDir = path49.posix.dirname(remotePath);
25669
25716
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
25670
25717
  if (options.mode != null) {
25671
25718
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -25733,7 +25780,7 @@ function shellQuote3(s) {
25733
25780
  // src/services/providers/railway.ts
25734
25781
  var import_child_process25 = require("child_process");
25735
25782
  var import_util7 = require("util");
25736
- var path49 = __toESM(require("path"));
25783
+ var path50 = __toESM(require("path"));
25737
25784
  var execFileP8 = (0, import_util7.promisify)(import_child_process25.execFile);
25738
25785
  var MAX_BUFFER4 = 8 * 1024 * 1024;
25739
25786
  function resetStdinForChild4() {
@@ -25969,7 +26016,7 @@ var RailwayProvider = class {
25969
26016
  if (!projectId || !serviceId) {
25970
26017
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
25971
26018
  }
25972
- const remoteDir = path49.posix.dirname(remotePath);
26019
+ const remoteDir = path50.posix.dirname(remotePath);
25973
26020
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
25974
26021
  if (options.mode != null) {
25975
26022
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -26513,7 +26560,7 @@ var import_node_dns = require("dns");
26513
26560
  var import_node_util4 = require("util");
26514
26561
  var import_node_crypto8 = require("crypto");
26515
26562
  var fs39 = __toESM(require("fs"));
26516
- var path50 = __toESM(require("path"));
26563
+ var path51 = __toESM(require("path"));
26517
26564
  var import_picocolors12 = __toESM(require("picocolors"));
26518
26565
  var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
26519
26566
  async function checkDns(apiBase) {
@@ -26569,10 +26616,10 @@ async function checkHealth(apiBase) {
26569
26616
  }
26570
26617
  }
26571
26618
  function checkConfigDir() {
26572
- const dir = path50.join(require("os").homedir(), ".codeam");
26619
+ const dir = path51.join(require("os").homedir(), ".codeam");
26573
26620
  try {
26574
26621
  fs39.mkdirSync(dir, { recursive: true, mode: 448 });
26575
- const probe = path50.join(dir, ".doctor-probe");
26622
+ const probe = path51.join(dir, ".doctor-probe");
26576
26623
  fs39.writeFileSync(probe, "ok", { mode: 384 });
26577
26624
  const read = fs39.readFileSync(probe, "utf8");
26578
26625
  fs39.unlinkSync(probe);
@@ -26639,7 +26686,7 @@ function checkNodePty() {
26639
26686
  detail: "not required on this platform"
26640
26687
  };
26641
26688
  }
26642
- const vendoredPath = path50.join(__dirname, "vendor", "node-pty");
26689
+ const vendoredPath = path51.join(__dirname, "vendor", "node-pty");
26643
26690
  for (const target of [vendoredPath, "node-pty"]) {
26644
26691
  try {
26645
26692
  require(target);
@@ -26681,7 +26728,7 @@ function checkChokidar() {
26681
26728
  }
26682
26729
  async function doctor(args2 = []) {
26683
26730
  const json = args2.includes("--json");
26684
- const cliVersion = true ? "2.39.2" : "0.0.0-dev";
26731
+ const cliVersion = true ? "2.39.3" : "0.0.0-dev";
26685
26732
  const apiBase = resolveApiBaseUrl();
26686
26733
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
26687
26734
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -26880,7 +26927,7 @@ async function completion(args2) {
26880
26927
  // src/commands/version.ts
26881
26928
  var import_picocolors13 = __toESM(require("picocolors"));
26882
26929
  function version2() {
26883
- const v = true ? "2.39.2" : "unknown";
26930
+ const v = true ? "2.39.3" : "unknown";
26884
26931
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
26885
26932
  }
26886
26933
 
@@ -27010,7 +27057,7 @@ var _subcommandHelpKeys = Object.keys(HELPS);
27010
27057
  // src/lib/updateNotifier.ts
27011
27058
  var fs40 = __toESM(require("fs"));
27012
27059
  var os31 = __toESM(require("os"));
27013
- var path51 = __toESM(require("path"));
27060
+ var path52 = __toESM(require("path"));
27014
27061
  var https8 = __toESM(require("https"));
27015
27062
  var import_node_child_process12 = require("child_process");
27016
27063
  var import_picocolors16 = __toESM(require("picocolors"));
@@ -27019,8 +27066,8 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
27019
27066
  var TTL_MS = 24 * 60 * 60 * 1e3;
27020
27067
  var REQUEST_TIMEOUT_MS = 1500;
27021
27068
  function cachePath() {
27022
- const dir = path51.join(os31.homedir(), ".codeam");
27023
- return path51.join(dir, "update-check.json");
27069
+ const dir = path52.join(os31.homedir(), ".codeam");
27070
+ return path52.join(dir, "update-check.json");
27024
27071
  }
27025
27072
  function readCache() {
27026
27073
  try {
@@ -27035,7 +27082,7 @@ function readCache() {
27035
27082
  function writeCache(cache) {
27036
27083
  try {
27037
27084
  const file = cachePath();
27038
- fs40.mkdirSync(path51.dirname(file), { recursive: true });
27085
+ fs40.mkdirSync(path52.dirname(file), { recursive: true });
27039
27086
  const tmp = `${file}.${process.pid}.tmp`;
27040
27087
  fs40.writeFileSync(tmp, JSON.stringify(cache));
27041
27088
  fs40.renameSync(tmp, file);
@@ -27112,7 +27159,7 @@ function isLinkedInstall() {
27112
27159
  timeout: 2e3
27113
27160
  }).trim();
27114
27161
  if (!root) return false;
27115
- const pkgPath = path51.join(root, PKG_NAME);
27162
+ const pkgPath = path52.join(root, PKG_NAME);
27116
27163
  return fs40.lstatSync(pkgPath).isSymbolicLink();
27117
27164
  } catch {
27118
27165
  return false;
@@ -27166,7 +27213,7 @@ function checkForUpdates() {
27166
27213
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
27167
27214
  if (process.env.CI) return;
27168
27215
  if (!process.stdout.isTTY) return;
27169
- const current = true ? "2.39.2" : null;
27216
+ const current = true ? "2.39.3" : null;
27170
27217
  if (!current) return;
27171
27218
  const cache = readCache();
27172
27219
  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.3",
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",