codeam-cli 2.39.1 → 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.
Files changed (3) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/index.js +112 -41
  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.2] — 2026-06-12
8
+
9
+ ### Added
10
+
11
+ - **cli:** Pre-warm preview detection so the first Start Preview is instant
12
+
13
+ ## [2.39.1] — 2026-06-12
14
+
15
+ ### Fixed
16
+
17
+ - **cli:** Disable in-session auto-provision — it starved/killed sessions ⚠️ BREAKING CHANGE
18
+
7
19
  ## [2.39.0] — 2026-06-12
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.1",
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.1" : "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
@@ -19272,6 +19272,28 @@ var requestPreviewDetectH = (ctx) => {
19272
19272
  });
19273
19273
  })();
19274
19274
  };
19275
+ var previewPrewarmStarted = false;
19276
+ function prewarmPreviewDetection(runtime) {
19277
+ if (previewPrewarmStarted) return;
19278
+ previewPrewarmStarted = true;
19279
+ if (typeof runtime.generateOneShot !== "function") return;
19280
+ void (async () => {
19281
+ try {
19282
+ const cwd = process.cwd();
19283
+ if (await readPreviewConfig(cwd)) return;
19284
+ const raw = await runtime.generateOneShot(PREVIEW_DETECT_PROMPT).catch(() => null);
19285
+ const detection = safeParseDetection(raw);
19286
+ if (!detection || detection.framework === "unsupported") return;
19287
+ await writePreviewConfig(cwd, detection);
19288
+ log.info(
19289
+ "preview",
19290
+ `prewarm: cached detection (${detection.framework} on :${detection.port})`
19291
+ );
19292
+ } catch (err) {
19293
+ log.info("preview", `prewarm: skipped (${String(err)})`);
19294
+ }
19295
+ })();
19296
+ }
19275
19297
  function compileReadyPattern(pattern) {
19276
19298
  return new RegExp(pattern, "i");
19277
19299
  }
@@ -19869,10 +19891,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
19869
19891
  /[\\/]Start Menu([\\/]|$)/i,
19870
19892
  /[\\/]Templates([\\/]|$)/i
19871
19893
  ];
19872
- function isUnsafeWindowsWatchRoot(dir, homedir24) {
19894
+ function isUnsafeWindowsWatchRoot(dir, homedir25) {
19873
19895
  const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
19874
19896
  const cwd = norm(dir);
19875
- const home = norm(homedir24);
19897
+ const home = norm(homedir25);
19876
19898
  if (cwd === home) return true;
19877
19899
  if (/^[a-z]:$/.test(cwd)) return true;
19878
19900
  const sysRoots = [
@@ -21541,8 +21563,10 @@ async function runAcpSession(opts) {
21541
21563
  { id: opts.agent, name: opts.agent, displayName: opts.agent }
21542
21564
  );
21543
21565
  relay.start();
21566
+ const prewarmTimer = setTimeout(() => prewarmPreviewDetection(runtime), 2e4);
21544
21567
  const shutdown = async (signal) => {
21545
21568
  showInfo(`Shutting down ACP session (${signal})\u2026`);
21569
+ clearTimeout(prewarmTimer);
21546
21570
  relay.stop();
21547
21571
  void fileWatcher.stop();
21548
21572
  turnFiles.stop();
@@ -24081,6 +24105,7 @@ async function autoLinkAfterPair(opts) {
24081
24105
  // src/commands/pair-auto.ts
24082
24106
  var fs38 = __toESM(require("fs"));
24083
24107
  var os30 = __toESM(require("os"));
24108
+ var path46 = __toESM(require("path"));
24084
24109
  var import_crypto7 = require("crypto");
24085
24110
 
24086
24111
  // src/commands/start-infra-only.ts
@@ -24275,12 +24300,12 @@ function readTokenFromArgs(args2) {
24275
24300
  }
24276
24301
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
24277
24302
  if (fileFlag) {
24278
- const path52 = fileFlag.slice("--token-file=".length);
24303
+ const path53 = fileFlag.slice("--token-file=".length);
24279
24304
  try {
24280
- const content = fs38.readFileSync(path52, "utf8").trim();
24281
- 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`);
24282
24307
  try {
24283
- fs38.unlinkSync(path52);
24308
+ fs38.unlinkSync(path53);
24284
24309
  } catch {
24285
24310
  }
24286
24311
  return content;
@@ -24362,7 +24387,53 @@ async function claim(token, pluginId) {
24362
24387
  }
24363
24388
  }
24364
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
+ }
24365
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
+ }
24366
24437
  const token = readTokenFromArgs(args2);
24367
24438
  const pluginId = (0, import_crypto7.randomUUID)();
24368
24439
  capture("pair_auto_started", { pluginId });
@@ -24546,7 +24617,7 @@ var import_picocolors10 = __toESM(require("picocolors"));
24546
24617
  var import_child_process22 = require("child_process");
24547
24618
  var import_util4 = require("util");
24548
24619
  var import_picocolors8 = __toESM(require("picocolors"));
24549
- var path46 = __toESM(require("path"));
24620
+ var path47 = __toESM(require("path"));
24550
24621
  var execFileP5 = (0, import_util4.promisify)(import_child_process22.execFile);
24551
24622
  var MAX_BUFFER = 8 * 1024 * 1024;
24552
24623
  function resetStdinForChild() {
@@ -25035,7 +25106,7 @@ var GitHubCodespacesProvider = class {
25035
25106
  });
25036
25107
  }
25037
25108
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25038
- const remoteDir = path46.posix.dirname(remotePath);
25109
+ const remoteDir = path47.posix.dirname(remotePath);
25039
25110
  const parts = [
25040
25111
  `mkdir -p ${shellQuote(remoteDir)}`,
25041
25112
  `cat > ${shellQuote(remotePath)}`
@@ -25105,7 +25176,7 @@ function shellQuote(s) {
25105
25176
  // src/services/providers/gitpod.ts
25106
25177
  var import_child_process23 = require("child_process");
25107
25178
  var import_util5 = require("util");
25108
- var path47 = __toESM(require("path"));
25179
+ var path48 = __toESM(require("path"));
25109
25180
  var import_picocolors9 = __toESM(require("picocolors"));
25110
25181
  var execFileP6 = (0, import_util5.promisify)(import_child_process23.execFile);
25111
25182
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -25345,7 +25416,7 @@ var GitpodProvider = class {
25345
25416
  });
25346
25417
  }
25347
25418
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25348
- const remoteDir = path47.posix.dirname(remotePath);
25419
+ const remoteDir = path48.posix.dirname(remotePath);
25349
25420
  const parts = [
25350
25421
  `mkdir -p ${shellQuote2(remoteDir)}`,
25351
25422
  `cat > ${shellQuote2(remotePath)}`
@@ -25381,7 +25452,7 @@ function shellQuote2(s) {
25381
25452
  // src/services/providers/gitlab-workspaces.ts
25382
25453
  var import_child_process24 = require("child_process");
25383
25454
  var import_util6 = require("util");
25384
- var path48 = __toESM(require("path"));
25455
+ var path49 = __toESM(require("path"));
25385
25456
  var execFileP7 = (0, import_util6.promisify)(import_child_process24.execFile);
25386
25457
  var MAX_BUFFER3 = 8 * 1024 * 1024;
25387
25458
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -25641,7 +25712,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
25641
25712
  }
25642
25713
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25643
25714
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
25644
- const remoteDir = path48.posix.dirname(remotePath);
25715
+ const remoteDir = path49.posix.dirname(remotePath);
25645
25716
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
25646
25717
  if (options.mode != null) {
25647
25718
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -25709,7 +25780,7 @@ function shellQuote3(s) {
25709
25780
  // src/services/providers/railway.ts
25710
25781
  var import_child_process25 = require("child_process");
25711
25782
  var import_util7 = require("util");
25712
- var path49 = __toESM(require("path"));
25783
+ var path50 = __toESM(require("path"));
25713
25784
  var execFileP8 = (0, import_util7.promisify)(import_child_process25.execFile);
25714
25785
  var MAX_BUFFER4 = 8 * 1024 * 1024;
25715
25786
  function resetStdinForChild4() {
@@ -25945,7 +26016,7 @@ var RailwayProvider = class {
25945
26016
  if (!projectId || !serviceId) {
25946
26017
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
25947
26018
  }
25948
- const remoteDir = path49.posix.dirname(remotePath);
26019
+ const remoteDir = path50.posix.dirname(remotePath);
25949
26020
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
25950
26021
  if (options.mode != null) {
25951
26022
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -26489,7 +26560,7 @@ var import_node_dns = require("dns");
26489
26560
  var import_node_util4 = require("util");
26490
26561
  var import_node_crypto8 = require("crypto");
26491
26562
  var fs39 = __toESM(require("fs"));
26492
- var path50 = __toESM(require("path"));
26563
+ var path51 = __toESM(require("path"));
26493
26564
  var import_picocolors12 = __toESM(require("picocolors"));
26494
26565
  var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
26495
26566
  async function checkDns(apiBase) {
@@ -26545,10 +26616,10 @@ async function checkHealth(apiBase) {
26545
26616
  }
26546
26617
  }
26547
26618
  function checkConfigDir() {
26548
- const dir = path50.join(require("os").homedir(), ".codeam");
26619
+ const dir = path51.join(require("os").homedir(), ".codeam");
26549
26620
  try {
26550
26621
  fs39.mkdirSync(dir, { recursive: true, mode: 448 });
26551
- const probe = path50.join(dir, ".doctor-probe");
26622
+ const probe = path51.join(dir, ".doctor-probe");
26552
26623
  fs39.writeFileSync(probe, "ok", { mode: 384 });
26553
26624
  const read = fs39.readFileSync(probe, "utf8");
26554
26625
  fs39.unlinkSync(probe);
@@ -26615,7 +26686,7 @@ function checkNodePty() {
26615
26686
  detail: "not required on this platform"
26616
26687
  };
26617
26688
  }
26618
- const vendoredPath = path50.join(__dirname, "vendor", "node-pty");
26689
+ const vendoredPath = path51.join(__dirname, "vendor", "node-pty");
26619
26690
  for (const target of [vendoredPath, "node-pty"]) {
26620
26691
  try {
26621
26692
  require(target);
@@ -26657,7 +26728,7 @@ function checkChokidar() {
26657
26728
  }
26658
26729
  async function doctor(args2 = []) {
26659
26730
  const json = args2.includes("--json");
26660
- const cliVersion = true ? "2.39.1" : "0.0.0-dev";
26731
+ const cliVersion = true ? "2.39.3" : "0.0.0-dev";
26661
26732
  const apiBase = resolveApiBaseUrl();
26662
26733
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
26663
26734
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -26856,7 +26927,7 @@ async function completion(args2) {
26856
26927
  // src/commands/version.ts
26857
26928
  var import_picocolors13 = __toESM(require("picocolors"));
26858
26929
  function version2() {
26859
- const v = true ? "2.39.1" : "unknown";
26930
+ const v = true ? "2.39.3" : "unknown";
26860
26931
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
26861
26932
  }
26862
26933
 
@@ -26986,7 +27057,7 @@ var _subcommandHelpKeys = Object.keys(HELPS);
26986
27057
  // src/lib/updateNotifier.ts
26987
27058
  var fs40 = __toESM(require("fs"));
26988
27059
  var os31 = __toESM(require("os"));
26989
- var path51 = __toESM(require("path"));
27060
+ var path52 = __toESM(require("path"));
26990
27061
  var https8 = __toESM(require("https"));
26991
27062
  var import_node_child_process12 = require("child_process");
26992
27063
  var import_picocolors16 = __toESM(require("picocolors"));
@@ -26995,8 +27066,8 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
26995
27066
  var TTL_MS = 24 * 60 * 60 * 1e3;
26996
27067
  var REQUEST_TIMEOUT_MS = 1500;
26997
27068
  function cachePath() {
26998
- const dir = path51.join(os31.homedir(), ".codeam");
26999
- return path51.join(dir, "update-check.json");
27069
+ const dir = path52.join(os31.homedir(), ".codeam");
27070
+ return path52.join(dir, "update-check.json");
27000
27071
  }
27001
27072
  function readCache() {
27002
27073
  try {
@@ -27011,7 +27082,7 @@ function readCache() {
27011
27082
  function writeCache(cache) {
27012
27083
  try {
27013
27084
  const file = cachePath();
27014
- fs40.mkdirSync(path51.dirname(file), { recursive: true });
27085
+ fs40.mkdirSync(path52.dirname(file), { recursive: true });
27015
27086
  const tmp = `${file}.${process.pid}.tmp`;
27016
27087
  fs40.writeFileSync(tmp, JSON.stringify(cache));
27017
27088
  fs40.renameSync(tmp, file);
@@ -27088,7 +27159,7 @@ function isLinkedInstall() {
27088
27159
  timeout: 2e3
27089
27160
  }).trim();
27090
27161
  if (!root) return false;
27091
- const pkgPath = path51.join(root, PKG_NAME);
27162
+ const pkgPath = path52.join(root, PKG_NAME);
27092
27163
  return fs40.lstatSync(pkgPath).isSymbolicLink();
27093
27164
  } catch {
27094
27165
  return false;
@@ -27142,7 +27213,7 @@ function checkForUpdates() {
27142
27213
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
27143
27214
  if (process.env.CI) return;
27144
27215
  if (!process.stdout.isTTY) return;
27145
- const current = true ? "2.39.1" : null;
27216
+ const current = true ? "2.39.3" : null;
27146
27217
  if (!current) return;
27147
27218
  const cache = readCache();
27148
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.1",
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",