codeam-cli 2.38.0 → 2.39.0

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 +11 -0
  2. package/dist/index.js +365 -156
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,17 @@ 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.38.0] — 2026-06-12
8
+
9
+ ### Added
10
+
11
+ - **cli:** Inherit team memories into the active repo's Beads DB (P3b)
12
+
13
+ ### Chore
14
+
15
+ - **deps:** Bump com.squareup.okhttp3:okhttp in /apps/jetbrains-plugin (#326)
16
+ - **deps-dev:** Bump @vscode/test-electron from 2.5.2 to 3.0.0 in /apps/vsc-plugin (#322)
17
+
7
18
  ## [2.37.3] — 2026-06-11
8
19
 
9
20
  ### 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.38.0",
501
+ version: "2.39.0",
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.38.0" : "0.0.0-dev",
5903
+ cliVersion: true ? "2.39.0" : "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
@@ -15911,9 +15911,9 @@ function extractSelectPrompt(text) {
15911
15911
  }
15912
15912
 
15913
15913
  // src/commands/start/handlers.ts
15914
- var fs34 = __toESM(require("fs"));
15914
+ var fs35 = __toESM(require("fs"));
15915
15915
  var os27 = __toESM(require("os"));
15916
- var path41 = __toESM(require("path"));
15916
+ var path42 = __toESM(require("path"));
15917
15917
  var import_crypto3 = require("crypto");
15918
15918
  var import_child_process18 = require("child_process");
15919
15919
 
@@ -17364,6 +17364,10 @@ async function waitForPortListening(port, opts) {
17364
17364
  }
17365
17365
  }
17366
17366
 
17367
+ // src/services/preview/provision-deps.ts
17368
+ var import_fs2 = require("fs");
17369
+ var import_path6 = __toESM(require("path"));
17370
+
17367
17371
  // src/services/preview/run-setup.ts
17368
17372
  var import_child_process12 = require("child_process");
17369
17373
  function runSetupCommand(cmd, args2, cwd, env, opts) {
@@ -17408,19 +17412,215 @@ function runSetupCommand(cmd, args2, cwd, env, opts) {
17408
17412
  });
17409
17413
  }
17410
17414
 
17415
+ // src/services/preview/provision-deps.ts
17416
+ var COMPOSE_FILES = [
17417
+ "docker-compose.yml",
17418
+ "docker-compose.yaml",
17419
+ "compose.yaml",
17420
+ "compose.yml"
17421
+ ];
17422
+ var ENV_SAMPLES = [".env.example", ".env.sample", ".env.local.example", ".env.template"];
17423
+ var POSTGRES = {
17424
+ name: "postgres",
17425
+ image: "postgres:16",
17426
+ port: 5432,
17427
+ environment: { POSTGRES_USER: "postgres", POSTGRES_PASSWORD: "postgres", POSTGRES_DB: "app" },
17428
+ healthTest: ["CMD-SHELL", "pg_isready -U postgres"],
17429
+ envLines: [
17430
+ "DATABASE_URL=postgresql://postgres:postgres@localhost:5432/app",
17431
+ "DB_HOST=localhost",
17432
+ "DB_PORT=5432",
17433
+ "DB_USERNAME=postgres",
17434
+ "DB_PASSWORD=postgres",
17435
+ "DB_NAME=app"
17436
+ ]
17437
+ };
17438
+ var MYSQL = {
17439
+ name: "mysql",
17440
+ image: "mysql:8",
17441
+ port: 3306,
17442
+ environment: { MYSQL_ROOT_PASSWORD: "mysql", MYSQL_DATABASE: "app" },
17443
+ healthTest: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-pmysql"],
17444
+ envLines: ["DATABASE_URL=mysql://root:mysql@localhost:3306/app"]
17445
+ };
17446
+ var MONGO = {
17447
+ name: "mongo",
17448
+ image: "mongo:7",
17449
+ port: 27017,
17450
+ environment: {},
17451
+ healthTest: ["CMD", "mongosh", "--eval", 'db.adminCommand("ping")'],
17452
+ envLines: ["MONGODB_URI=mongodb://localhost:27017/app", "MONGO_URL=mongodb://localhost:27017/app"]
17453
+ };
17454
+ var REDIS = {
17455
+ name: "redis",
17456
+ image: "redis:7",
17457
+ port: 6379,
17458
+ environment: {},
17459
+ healthTest: ["CMD", "redis-cli", "ping"],
17460
+ envLines: ["REDIS_URL=redis://localhost:6379", "REDIS_HOST=localhost", "REDIS_PORT=6379"]
17461
+ };
17462
+ function detectServicesFromDeps(pkg) {
17463
+ const deps = /* @__PURE__ */ new Set([
17464
+ ...Object.keys(pkg.dependencies ?? {}),
17465
+ ...Object.keys(pkg.devDependencies ?? {})
17466
+ ]);
17467
+ const has = (...names) => names.some((n) => deps.has(n));
17468
+ const out2 = [];
17469
+ if (has("pg", "typeorm", "@nestjs/typeorm", "sequelize", "postgres", "postgres.js", "pg-promise"))
17470
+ out2.push(POSTGRES);
17471
+ if (has("mysql", "mysql2")) out2.push(MYSQL);
17472
+ if (has("mongoose", "mongodb")) out2.push(MONGO);
17473
+ if (has("ioredis", "redis", "cache-manager-ioredis-yet", "cache-manager-redis-store"))
17474
+ out2.push(REDIS);
17475
+ return out2;
17476
+ }
17477
+ function renderComposeYaml(services) {
17478
+ const blocks = services.map((s) => {
17479
+ const env = Object.entries(s.environment);
17480
+ const envYaml = env.length ? " environment:\n" + env.map(([k2, v]) => ` ${k2}: "${v}"`).join("\n") + "\n" : "";
17481
+ const health = JSON.stringify(s.healthTest);
17482
+ return ` ${s.name}:
17483
+ image: ${s.image}
17484
+ restart: unless-stopped
17485
+ ports:
17486
+ - "${s.port}:${s.port}"
17487
+ ` + envYaml + ` healthcheck:
17488
+ test: ${health}
17489
+ interval: 5s
17490
+ timeout: 3s
17491
+ retries: 12
17492
+ `;
17493
+ });
17494
+ return `# Generated by codeam \u2014 auto-provisioned project dependencies.
17495
+ # Do not edit; regenerated on each provision. See .codeam/provision/.
17496
+ services:
17497
+ ${blocks.join("")}`;
17498
+ }
17499
+ function pickMigrationScript(scripts) {
17500
+ const preferred = [
17501
+ "migration:run",
17502
+ "db:migrate",
17503
+ "migrate:deploy",
17504
+ "migrate:latest",
17505
+ "migrate:up",
17506
+ "prisma:migrate",
17507
+ "migrate"
17508
+ ];
17509
+ for (const k2 of preferred) if (scripts[k2]) return k2;
17510
+ for (const k2 of Object.keys(scripts)) {
17511
+ if (/migrat/i.test(k2) && /(run|deploy|latest|up)/i.test(k2) && !/(generate|create|revert|rollback|undo|down|reset|drop)/i.test(k2)) {
17512
+ return k2;
17513
+ }
17514
+ }
17515
+ return null;
17516
+ }
17517
+ async function exists(p2) {
17518
+ try {
17519
+ await import_fs2.promises.access(p2);
17520
+ return true;
17521
+ } catch {
17522
+ return false;
17523
+ }
17524
+ }
17525
+ async function firstExisting(cwd, names) {
17526
+ for (const n of names) if (await exists(import_path6.default.join(cwd, n))) return n;
17527
+ return null;
17528
+ }
17529
+ async function ensureEnvFile(cwd, generated) {
17530
+ if (await exists(import_path6.default.join(cwd, ".env"))) {
17531
+ log.info("provision", ".env already present \u2014 leaving it untouched");
17532
+ return;
17533
+ }
17534
+ const sample = await firstExisting(cwd, ENV_SAMPLES);
17535
+ if (sample) {
17536
+ const body = await import_fs2.promises.readFile(import_path6.default.join(cwd, sample), "utf8");
17537
+ await import_fs2.promises.writeFile(import_path6.default.join(cwd, ".env"), body);
17538
+ log.info("provision", `wrote .env from ${sample}`);
17539
+ return;
17540
+ }
17541
+ if (generated.length > 0) {
17542
+ const body = "# Generated by codeam \u2014 points at the auto-provisioned local services.\n" + generated.flatMap((s) => s.envLines).join("\n") + "\n";
17543
+ await import_fs2.promises.writeFile(import_path6.default.join(cwd, ".env"), body);
17544
+ log.info("provision", `generated .env for ${generated.map((s) => s.name).join("+")}`);
17545
+ }
17546
+ }
17547
+ async function readPackageJson(cwd) {
17548
+ try {
17549
+ return JSON.parse(await import_fs2.promises.readFile(import_path6.default.join(cwd, "package.json"), "utf8"));
17550
+ } catch {
17551
+ return null;
17552
+ }
17553
+ }
17554
+ async function runMigrationsIfPresent(cwd, scripts) {
17555
+ const script = pickMigrationScript(scripts);
17556
+ if (!script) return;
17557
+ log.info("provision", `running migrations: npm run ${script}`);
17558
+ const res = await runSetupCommand("npm", ["run", script], cwd, void 0, { timeoutMs: 12e4 });
17559
+ if (res.status !== "ok") log.warn("provision", `migration script "${script}" \u2192 ${res.status} (non-fatal)`);
17560
+ }
17561
+ async function provisionProjectDependencies(cwd) {
17562
+ try {
17563
+ const docker = await runSetupCommand("docker", ["info"], cwd, void 0, { timeoutMs: 15e3 });
17564
+ if (docker.status !== "ok") {
17565
+ log.info("provision", "docker not usable \u2014 skipping dependency provisioning");
17566
+ return;
17567
+ }
17568
+ const pkg = await readPackageJson(cwd);
17569
+ let started = false;
17570
+ let generated = [];
17571
+ const composeFile = await firstExisting(cwd, COMPOSE_FILES);
17572
+ if (composeFile) {
17573
+ log.info("provision", `compose found (${composeFile}) \u2014 docker compose up -d --wait`);
17574
+ const up = await runSetupCommand("docker", ["compose", "up", "-d", "--wait"], cwd, void 0, {
17575
+ timeoutMs: 18e4
17576
+ });
17577
+ started = up.status === "ok";
17578
+ if (!started) log.warn("provision", `compose up \u2192 ${up.status} (non-fatal)`);
17579
+ } else if (pkg) {
17580
+ generated = detectServicesFromDeps(pkg);
17581
+ if (generated.length > 0) {
17582
+ const dir = import_path6.default.join(cwd, ".codeam", "provision");
17583
+ await import_fs2.promises.mkdir(dir, { recursive: true });
17584
+ const file = import_path6.default.join(dir, "compose.generated.yaml");
17585
+ await import_fs2.promises.writeFile(file, renderComposeYaml(generated));
17586
+ log.info(
17587
+ "provision",
17588
+ `no compose in repo \u2014 generated ${generated.map((s) => s.name).join("+")}`
17589
+ );
17590
+ const up = await runSetupCommand(
17591
+ "docker",
17592
+ ["compose", "-f", file, "up", "-d", "--wait"],
17593
+ cwd,
17594
+ void 0,
17595
+ { timeoutMs: 18e4 }
17596
+ );
17597
+ started = up.status === "ok";
17598
+ if (!started) log.warn("provision", `generated compose up \u2192 ${up.status} (non-fatal)`);
17599
+ } else {
17600
+ log.info("provision", "no compose + no known service deps \u2014 nothing to provision");
17601
+ }
17602
+ }
17603
+ await ensureEnvFile(cwd, generated);
17604
+ if (started && pkg?.scripts) await runMigrationsIfPresent(cwd, pkg.scripts);
17605
+ log.info("provision", "project dependency provisioning complete");
17606
+ } catch (err) {
17607
+ log.warn("provision", "provisionProjectDependencies failed (non-fatal)", err);
17608
+ }
17609
+ }
17610
+
17411
17611
  // src/services/preview/setup-deps.ts
17412
- var import_fs2 = __toESM(require("fs"));
17413
- var import_path6 = __toESM(require("path"));
17612
+ var import_fs3 = __toESM(require("fs"));
17613
+ var import_path7 = __toESM(require("path"));
17414
17614
  function detectMissingNodeDeps(cwd) {
17415
- if (!import_fs2.default.existsSync(import_path6.default.join(cwd, "package.json"))) return null;
17416
- if (import_fs2.default.existsSync(import_path6.default.join(cwd, "node_modules"))) return null;
17417
- if (import_fs2.default.existsSync(import_path6.default.join(cwd, "pnpm-lock.yaml"))) {
17615
+ if (!import_fs3.default.existsSync(import_path7.default.join(cwd, "package.json"))) return null;
17616
+ if (import_fs3.default.existsSync(import_path7.default.join(cwd, "node_modules"))) return null;
17617
+ if (import_fs3.default.existsSync(import_path7.default.join(cwd, "pnpm-lock.yaml"))) {
17418
17618
  return { cmd: "pnpm", args: ["install"] };
17419
17619
  }
17420
- if (import_fs2.default.existsSync(import_path6.default.join(cwd, "yarn.lock"))) {
17620
+ if (import_fs3.default.existsSync(import_path7.default.join(cwd, "yarn.lock"))) {
17421
17621
  return { cmd: "yarn", args: ["install"] };
17422
17622
  }
17423
- if (import_fs2.default.existsSync(import_path6.default.join(cwd, "bun.lockb")) || import_fs2.default.existsSync(import_path6.default.join(cwd, "bun.lock"))) {
17623
+ if (import_fs3.default.existsSync(import_path7.default.join(cwd, "bun.lockb")) || import_fs3.default.existsSync(import_path7.default.join(cwd, "bun.lock"))) {
17424
17624
  return { cmd: "bun", args: ["install"] };
17425
17625
  }
17426
17626
  return { cmd: "npm", args: ["install"] };
@@ -17475,8 +17675,8 @@ function activePreviewSessionIds() {
17475
17675
 
17476
17676
  // src/beads/bd-adapter.ts
17477
17677
  var import_child_process13 = require("child_process");
17478
- var fs30 = __toESM(require("fs"));
17479
- var path36 = __toESM(require("path"));
17678
+ var fs31 = __toESM(require("fs"));
17679
+ var path37 = __toESM(require("path"));
17480
17680
  var BD_PACKAGE = "@beads/bd";
17481
17681
  function resolveBundledBdBinary() {
17482
17682
  return _resolveSeam.resolveBundled();
@@ -17488,11 +17688,11 @@ function _defaultResolveBundled() {
17488
17688
  } catch {
17489
17689
  return null;
17490
17690
  }
17491
- const binDir = path36.join(path36.dirname(pkgJsonPath), "bin");
17691
+ const binDir = path37.join(path37.dirname(pkgJsonPath), "bin");
17492
17692
  const binaryName = process.platform === "win32" ? "bd.exe" : "bd";
17493
- const binaryPath = path36.join(binDir, binaryName);
17693
+ const binaryPath = path37.join(binDir, binaryName);
17494
17694
  try {
17495
- fs30.accessSync(binaryPath, fs30.constants.F_OK);
17695
+ fs31.accessSync(binaryPath, fs31.constants.F_OK);
17496
17696
  return binaryPath;
17497
17697
  } catch {
17498
17698
  return null;
@@ -17502,13 +17702,13 @@ function resolveBdOnPath() {
17502
17702
  return _resolveSeam.resolveOnPath();
17503
17703
  }
17504
17704
  function _defaultResolveOnPath() {
17505
- const dirs = (process.env.PATH ?? "").split(path36.delimiter).filter(Boolean);
17705
+ const dirs = (process.env.PATH ?? "").split(path37.delimiter).filter(Boolean);
17506
17706
  const candidates = process.platform === "win32" ? ["bd.exe", "bd.cmd", "bd"] : ["bd"];
17507
17707
  for (const dir of dirs) {
17508
17708
  for (const candidate of candidates) {
17509
- const full = path36.join(dir, candidate);
17709
+ const full = path37.join(dir, candidate);
17510
17710
  try {
17511
- fs30.accessSync(full, fs30.constants.F_OK);
17711
+ fs31.accessSync(full, fs31.constants.F_OK);
17512
17712
  return full;
17513
17713
  } catch {
17514
17714
  }
@@ -17674,9 +17874,9 @@ function coerceIssue(row, projectKey) {
17674
17874
 
17675
17875
  // src/beads/provisioner.ts
17676
17876
  var import_child_process17 = require("child_process");
17677
- var fs33 = __toESM(require("fs"));
17877
+ var fs34 = __toESM(require("fs"));
17678
17878
  var os26 = __toESM(require("os"));
17679
- var path39 = __toESM(require("path"));
17879
+ var path40 = __toESM(require("path"));
17680
17880
 
17681
17881
  // src/beads/install-bd.ts
17682
17882
  var import_child_process14 = require("child_process");
@@ -17741,9 +17941,9 @@ async function installBd(platform2 = process.platform) {
17741
17941
 
17742
17942
  // src/beads/install-dolt.ts
17743
17943
  var import_child_process15 = require("child_process");
17744
- var fs31 = __toESM(require("fs"));
17944
+ var fs32 = __toESM(require("fs"));
17745
17945
  var os25 = __toESM(require("os"));
17746
- var path37 = __toESM(require("path"));
17946
+ var path38 = __toESM(require("path"));
17747
17947
  var DOLT_INSTALL_SH_URL = "https://github.com/dolthub/dolt/releases/latest/download/install.sh";
17748
17948
  var DOLT_MSI_URL = "https://github.com/dolthub/dolt/releases/latest/download/dolt-windows-amd64.msi";
17749
17949
  function resolveDoltInstallStrategy(platform2) {
@@ -17839,7 +18039,7 @@ var _doltPathSeam = {
17839
18039
  },
17840
18040
  exists: (p2) => {
17841
18041
  try {
17842
- fs31.accessSync(p2, fs31.constants.F_OK);
18042
+ fs32.accessSync(p2, fs32.constants.F_OK);
17843
18043
  return true;
17844
18044
  } catch {
17845
18045
  return false;
@@ -17850,7 +18050,7 @@ function doltBinaryNames(platform2) {
17850
18050
  return platform2 === "win32" ? ["dolt.exe", "dolt.cmd", "dolt"] : ["dolt"];
17851
18051
  }
17852
18052
  function knownDoltDirs(platform2) {
17853
- const P3 = platform2 === "win32" ? path37.win32 : path37.posix;
18053
+ const P3 = platform2 === "win32" ? path38.win32 : path38.posix;
17854
18054
  const home = _doltPathSeam.homedir();
17855
18055
  if (platform2 === "win32") {
17856
18056
  return [
@@ -17866,7 +18066,7 @@ function knownDoltDirs(platform2) {
17866
18066
  ].filter(Boolean);
17867
18067
  }
17868
18068
  function ensureDoltResolvable(platform2 = process.platform) {
17869
- const P3 = platform2 === "win32" ? path37.win32 : path37.posix;
18069
+ const P3 = platform2 === "win32" ? path38.win32 : path38.posix;
17870
18070
  const delim = platform2 === "win32" ? ";" : ":";
17871
18071
  const names = doltBinaryNames(platform2);
17872
18072
  const pathDirs = _doltPathSeam.getPath().split(delim).filter(Boolean);
@@ -17977,8 +18177,8 @@ async function ensureSharedServer(adapter) {
17977
18177
  // src/beads/project-key.ts
17978
18178
  var import_child_process16 = require("child_process");
17979
18179
  var crypto2 = __toESM(require("crypto"));
17980
- var fs32 = __toESM(require("fs"));
17981
- var path38 = __toESM(require("path"));
18180
+ var fs33 = __toESM(require("fs"));
18181
+ var path39 = __toESM(require("path"));
17982
18182
  function normalizeOrigin(raw) {
17983
18183
  const trimmed = raw.trim();
17984
18184
  if (!trimmed) return null;
@@ -18004,17 +18204,17 @@ function normalizeOrigin(raw) {
18004
18204
  return `${host}/${pathPart}`;
18005
18205
  }
18006
18206
  function findRepoRoot(cwd) {
18007
- let dir = path38.resolve(cwd);
18207
+ let dir = path39.resolve(cwd);
18008
18208
  const seen = /* @__PURE__ */ new Set();
18009
18209
  for (let i = 0; i < 256; i++) {
18010
18210
  if (seen.has(dir)) return null;
18011
18211
  seen.add(dir);
18012
18212
  try {
18013
- const stat3 = fs32.statSync(path38.join(dir, ".git"), { throwIfNoEntry: false });
18213
+ const stat3 = fs33.statSync(path39.join(dir, ".git"), { throwIfNoEntry: false });
18014
18214
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
18015
18215
  } catch {
18016
18216
  }
18017
- const parent = path38.dirname(dir);
18217
+ const parent = path39.dirname(dir);
18018
18218
  if (parent === dir) return null;
18019
18219
  dir = parent;
18020
18220
  }
@@ -18025,7 +18225,7 @@ var _execSeam2 = {
18025
18225
  const out2 = (0, import_child_process16.execFileSync)(file, args2, opts);
18026
18226
  return typeof out2 === "string" ? out2 : out2.toString("utf8");
18027
18227
  },
18028
- realpath: (p2) => fs32.realpathSync(p2)
18228
+ realpath: (p2) => fs33.realpathSync(p2)
18029
18229
  };
18030
18230
  function readOrigin(cwd) {
18031
18231
  try {
@@ -18054,7 +18254,7 @@ function deriveProjectIdentity(cwd = process.cwd()) {
18054
18254
  } catch {
18055
18255
  }
18056
18256
  const hash = crypto2.createHash("sha256").update(real).digest("hex");
18057
- return { projectKey: `path:${hash}`, projectLabel: path38.basename(real) || "project" };
18257
+ return { projectKey: `path:${hash}`, projectLabel: path39.basename(real) || "project" };
18058
18258
  }
18059
18259
 
18060
18260
  // src/beads/project-prefix.ts
@@ -18099,14 +18299,14 @@ var _linkSeam = {
18099
18299
  homedir: () => os26.homedir(),
18100
18300
  isWritableDir: (dir) => {
18101
18301
  try {
18102
- fs33.accessSync(dir, fs33.constants.W_OK);
18302
+ fs34.accessSync(dir, fs34.constants.W_OK);
18103
18303
  return true;
18104
18304
  } catch {
18105
18305
  return false;
18106
18306
  }
18107
18307
  },
18108
18308
  ensureDir: (dir) => {
18109
- fs33.mkdirSync(dir, { recursive: true });
18309
+ fs34.mkdirSync(dir, { recursive: true });
18110
18310
  },
18111
18311
  /**
18112
18312
  * A directory to symlink `bd` into so the AGENT's shell + Claude Code's
@@ -18127,12 +18327,12 @@ var _linkSeam = {
18127
18327
  * which `linkBdOntoPath` creates if missing.
18128
18328
  */
18129
18329
  cliBinDir: () => {
18130
- const pathDirs = (process.env.PATH ?? "").split(path39.delimiter).filter(Boolean);
18330
+ const pathDirs = (process.env.PATH ?? "").split(path40.delimiter).filter(Boolean);
18131
18331
  const home = _linkSeam.homedir();
18132
- const localBin = home ? path39.join(home, ".local", "bin") : null;
18332
+ const localBin = home ? path40.join(home, ".local", "bin") : null;
18133
18333
  const candidates = [];
18134
18334
  try {
18135
- candidates.push(path39.dirname(process.execPath));
18335
+ candidates.push(path40.dirname(process.execPath));
18136
18336
  } catch {
18137
18337
  }
18138
18338
  if (localBin) candidates.push(localBin);
@@ -18140,9 +18340,9 @@ var _linkSeam = {
18140
18340
  const entry = process.argv[1];
18141
18341
  if (entry) {
18142
18342
  try {
18143
- candidates.push(path39.dirname(fs33.realpathSync(entry)));
18343
+ candidates.push(path40.dirname(fs34.realpathSync(entry)));
18144
18344
  } catch {
18145
- candidates.push(path39.dirname(entry));
18345
+ candidates.push(path40.dirname(entry));
18146
18346
  }
18147
18347
  }
18148
18348
  const onPathWritable = candidates.find(
@@ -18154,20 +18354,20 @@ var _linkSeam = {
18154
18354
  /** Current symlink target at `linkPath`, or null when absent / not a link. */
18155
18355
  readlink: (linkPath) => {
18156
18356
  try {
18157
- return fs33.readlinkSync(linkPath);
18357
+ return fs34.readlinkSync(linkPath);
18158
18358
  } catch {
18159
18359
  return null;
18160
18360
  }
18161
18361
  },
18162
- unlink: (linkPath) => fs33.unlinkSync(linkPath),
18163
- symlink: (target, linkPath) => fs33.symlinkSync(target, linkPath)
18362
+ unlink: (linkPath) => fs34.unlinkSync(linkPath),
18363
+ symlink: (target, linkPath) => fs34.symlinkSync(target, linkPath)
18164
18364
  };
18165
18365
  function linkBdOntoPath(binaryPath) {
18166
18366
  if (_linkSeam.platform() === "win32") return;
18167
18367
  const binDir = _linkSeam.cliBinDir();
18168
18368
  if (!binDir) return;
18169
18369
  _linkSeam.ensureDir(binDir);
18170
- const linkPath = path39.join(binDir, "bd");
18370
+ const linkPath = path40.join(binDir, "bd");
18171
18371
  if (linkPath === binaryPath) return;
18172
18372
  const current = _linkSeam.readlink(linkPath);
18173
18373
  if (current === binaryPath) return;
@@ -18308,7 +18508,7 @@ function dedupeRecipes(agents) {
18308
18508
 
18309
18509
  // src/beads/watcher.ts
18310
18510
  var crypto4 = __toESM(require("crypto"));
18311
- var path40 = __toESM(require("path"));
18511
+ var path41 = __toESM(require("path"));
18312
18512
 
18313
18513
  // src/services/file-watcher/transport.ts
18314
18514
  var http5 = __toESM(require("http"));
@@ -18383,7 +18583,7 @@ var BeadsWatcher = class {
18383
18583
  constructor(opts) {
18384
18584
  this.opts = opts;
18385
18585
  this.bd = opts.adapter ?? new BdAdapter({ cwd: opts.cwd, beadsDir: opts.beadsDir });
18386
- this.feedPath = opts.feedPath ?? path40.join(opts.cwd ?? process.cwd(), ".beads", "issues.jsonl");
18586
+ this.feedPath = opts.feedPath ?? path41.join(opts.cwd ?? process.cwd(), ".beads", "issues.jsonl");
18387
18587
  this.apiBase = opts.apiBaseUrl ?? API_BASE4;
18388
18588
  }
18389
18589
  opts;
@@ -18706,7 +18906,7 @@ var pendingAttachmentFiles = /* @__PURE__ */ new Set();
18706
18906
  function cleanupAttachmentTempFiles() {
18707
18907
  for (const p2 of pendingAttachmentFiles) {
18708
18908
  try {
18709
- fs34.unlinkSync(p2);
18909
+ fs35.unlinkSync(p2);
18710
18910
  } catch {
18711
18911
  }
18712
18912
  }
@@ -18715,8 +18915,8 @@ function cleanupAttachmentTempFiles() {
18715
18915
  function saveFilesTemp(files) {
18716
18916
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
18717
18917
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
18718
- const tmpPath = path41.join(os27.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
18719
- fs34.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
18918
+ const tmpPath = path42.join(os27.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
18919
+ fs35.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
18720
18920
  pendingAttachmentFiles.add(tmpPath);
18721
18921
  return tmpPath;
18722
18922
  });
@@ -18736,7 +18936,7 @@ var startTask = (ctx, _cmd, parsed) => {
18736
18936
  setTimeout(() => {
18737
18937
  for (const p2 of paths) {
18738
18938
  try {
18739
- fs34.unlinkSync(p2);
18939
+ fs35.unlinkSync(p2);
18740
18940
  } catch {
18741
18941
  }
18742
18942
  pendingAttachmentFiles.delete(p2);
@@ -19319,8 +19519,8 @@ function normalizeDetectionForSpawn(detection, cwd) {
19319
19519
  if (args2.length === 0) return detection;
19320
19520
  const binName = args2[0];
19321
19521
  if (binName.startsWith("-")) return detection;
19322
- const binPath = path41.join(cwd, "node_modules", ".bin", binName);
19323
- if (!fs34.existsSync(binPath)) return detection;
19522
+ const binPath = path42.join(cwd, "node_modules", ".bin", binName);
19523
+ if (!fs35.existsSync(binPath)) return detection;
19324
19524
  return {
19325
19525
  ...detection,
19326
19526
  command: binPath,
@@ -19454,11 +19654,13 @@ var previewStartH = (ctx, _cmd, parsed) => {
19454
19654
  emitProgress("BIND_PORT", String(detection.port));
19455
19655
  emitProgress("WAITING_FOR_READY", detection.ready_pattern);
19456
19656
  let expoUrl = null;
19657
+ let outputTail = "";
19457
19658
  const readyRe = compileReadyPattern(detection.ready_pattern);
19458
19659
  const isNextJs = /next/i.test(detection.framework);
19459
19660
  const outcome = await waitForDevServerReady(devServer, readyRe, {
19460
19661
  timeoutMs: 12e4,
19461
19662
  onChunk: (s) => {
19663
+ outputTail = (outputTail + s).slice(-4e3);
19462
19664
  if (!expoUrl && detection.framework === "Expo") {
19463
19665
  expoUrl = parseExpoUrl(s);
19464
19666
  }
@@ -19473,7 +19675,8 @@ var previewStartH = (ctx, _cmd, parsed) => {
19473
19675
  type: "preview_error",
19474
19676
  payload: {
19475
19677
  stage: "spawn",
19476
- message: `Dev server exited (code ${outcome.code}).`
19678
+ message: `The dev server exited (code ${outcome.code}) before it was ready. It may need a database or other services.`,
19679
+ stderrTail: outputTail.slice(-2e3)
19477
19680
  }
19478
19681
  });
19479
19682
  return;
@@ -19488,7 +19691,11 @@ var previewStartH = (ctx, _cmd, parsed) => {
19488
19691
  pluginId: ctx.pluginId,
19489
19692
  pluginAuthToken,
19490
19693
  type: "preview_error",
19491
- payload: { stage: "ready_timeout", message: "Server didn't signal ready in 120s." }
19694
+ payload: {
19695
+ stage: "ready_timeout",
19696
+ message: "The dev server didn't become ready in time. It may be stuck waiting on a database or other service.",
19697
+ stderrTail: outputTail.slice(-2e3)
19698
+ }
19492
19699
  });
19493
19700
  return;
19494
19701
  }
@@ -19750,9 +19957,9 @@ async function dispatchCommand(ctx, cmd) {
19750
19957
 
19751
19958
  // src/services/file-watcher.service.ts
19752
19959
  var import_child_process19 = require("child_process");
19753
- var fs35 = __toESM(require("fs"));
19960
+ var fs36 = __toESM(require("fs"));
19754
19961
  var os28 = __toESM(require("os"));
19755
- var path42 = __toESM(require("path"));
19962
+ var path43 = __toESM(require("path"));
19756
19963
  var import_ignore = __toESM(require("ignore"));
19757
19964
 
19758
19965
  // src/services/file-watcher/diff-parser.ts
@@ -19895,18 +20102,18 @@ var _findGitRootSeam = {
19895
20102
  resolve: _defaultFindGitRoot
19896
20103
  };
19897
20104
  function _defaultFindGitRoot(startDir) {
19898
- let dir = path42.resolve(startDir);
20105
+ let dir = path43.resolve(startDir);
19899
20106
  const seen = /* @__PURE__ */ new Set();
19900
20107
  for (let i = 0; i < 256; i++) {
19901
20108
  if (seen.has(dir)) return null;
19902
20109
  seen.add(dir);
19903
20110
  try {
19904
- const gitPath = path42.join(dir, ".git");
19905
- const stat3 = fs35.statSync(gitPath, { throwIfNoEntry: false });
20111
+ const gitPath = path43.join(dir, ".git");
20112
+ const stat3 = fs36.statSync(gitPath, { throwIfNoEntry: false });
19906
20113
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
19907
20114
  } catch {
19908
20115
  }
19909
- const parent = path42.dirname(dir);
20116
+ const parent = path43.dirname(dir);
19910
20117
  if (parent === dir) return null;
19911
20118
  dir = parent;
19912
20119
  }
@@ -20151,7 +20358,7 @@ var FileWatcherService = class {
20151
20358
  }
20152
20359
  async emitForFile(absPath, changeType) {
20153
20360
  if (this.stopped) return;
20154
- const fileDir = path42.dirname(absPath);
20361
+ const fileDir = path43.dirname(absPath);
20155
20362
  let gitRoot = this.gitRootByDir.get(fileDir);
20156
20363
  if (gitRoot === void 0) {
20157
20364
  gitRoot = findGitRoot2(fileDir);
@@ -20164,19 +20371,19 @@ var FileWatcherService = class {
20164
20371
  );
20165
20372
  return;
20166
20373
  }
20167
- const relPathInRepo = path42.relative(gitRoot, absPath);
20374
+ const relPathInRepo = path43.relative(gitRoot, absPath);
20168
20375
  if (!relPathInRepo || relPathInRepo.startsWith("..")) return;
20169
20376
  const matcher = this.getGitIgnoreMatcher(gitRoot);
20170
20377
  if (matcher && matcher.ignores(relPathInRepo)) {
20171
20378
  log.trace(
20172
20379
  "fileWatcher",
20173
- `${relPathInRepo} ignored by ${path42.basename(gitRoot)}/.gitignore \u2014 suppressing emit`
20380
+ `${relPathInRepo} ignored by ${path43.basename(gitRoot)}/.gitignore \u2014 suppressing emit`
20174
20381
  );
20175
20382
  return;
20176
20383
  }
20177
20384
  this.opts.onRepoDirty?.(gitRoot);
20178
- const repoPath = path42.relative(this.opts.workingDir, gitRoot);
20179
- const repoName = path42.basename(gitRoot);
20385
+ const repoPath = path43.relative(this.opts.workingDir, gitRoot);
20386
+ const repoName = path43.basename(gitRoot);
20180
20387
  let diffText = "";
20181
20388
  let fileStatus = "modified";
20182
20389
  if (changeType === "unlink") {
@@ -20351,7 +20558,7 @@ var FileWatcherService = class {
20351
20558
  collectGitignoreFiles(repoRoot, dir, matcher) {
20352
20559
  let entries;
20353
20560
  try {
20354
- entries = fs35.readdirSync(dir, { withFileTypes: true });
20561
+ entries = fs36.readdirSync(dir, { withFileTypes: true });
20355
20562
  } catch {
20356
20563
  return;
20357
20564
  }
@@ -20360,16 +20567,16 @@ var FileWatcherService = class {
20360
20567
  );
20361
20568
  if (gitignoreEntry) {
20362
20569
  try {
20363
- const body = fs35.readFileSync(path42.join(dir, ".gitignore"), "utf8");
20364
- const rel = path42.relative(repoRoot, dir).replace(/\\/g, "/");
20570
+ const body = fs36.readFileSync(path43.join(dir, ".gitignore"), "utf8");
20571
+ const rel = path43.relative(repoRoot, dir).replace(/\\/g, "/");
20365
20572
  const prefixed = body.split(/\r?\n/).map((line) => {
20366
20573
  const trimmed = line.trim();
20367
20574
  if (!trimmed || trimmed.startsWith("#")) return line;
20368
20575
  if (!rel) return line;
20369
20576
  if (trimmed.startsWith("!")) {
20370
- return "!" + path42.posix.join(rel, trimmed.slice(1));
20577
+ return "!" + path43.posix.join(rel, trimmed.slice(1));
20371
20578
  }
20372
- return path42.posix.join(rel, trimmed);
20579
+ return path43.posix.join(rel, trimmed);
20373
20580
  }).join("\n");
20374
20581
  matcher.add(prefixed);
20375
20582
  } catch {
@@ -20378,7 +20585,7 @@ var FileWatcherService = class {
20378
20585
  for (const entry of entries) {
20379
20586
  if (!entry.isDirectory()) continue;
20380
20587
  if (entry.name === ".git") continue;
20381
- const childAbs = path42.join(dir, entry.name);
20588
+ const childAbs = path43.join(dir, entry.name);
20382
20589
  if (isIgnoredFilePath(childAbs)) continue;
20383
20590
  this.collectGitignoreFiles(repoRoot, childAbs, matcher);
20384
20591
  }
@@ -20548,7 +20755,7 @@ var import_crypto4 = require("crypto");
20548
20755
 
20549
20756
  // src/services/turn-files/git-changeset.ts
20550
20757
  var import_child_process20 = require("child_process");
20551
- var path43 = __toESM(require("path"));
20758
+ var path44 = __toESM(require("path"));
20552
20759
  async function collectRepoChangeset(opts) {
20553
20760
  const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
20554
20761
  if (status2 === null) return null;
@@ -20659,7 +20866,7 @@ function defaultRunGit(cwd, args2) {
20659
20866
  });
20660
20867
  }
20661
20868
  async function discoverRepos(workingDir, maxDepth = 4) {
20662
- const fs41 = await import("fs/promises");
20869
+ const fs42 = await import("fs/promises");
20663
20870
  const out2 = [];
20664
20871
  await walk(workingDir, 0);
20665
20872
  return out2;
@@ -20667,7 +20874,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
20667
20874
  if (depth > maxDepth) return;
20668
20875
  let entries = [];
20669
20876
  try {
20670
- const dirents = await fs41.readdir(dir, { withFileTypes: true });
20877
+ const dirents = await fs42.readdir(dir, { withFileTypes: true });
20671
20878
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
20672
20879
  } catch {
20673
20880
  return;
@@ -20678,8 +20885,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
20678
20885
  if (hasGit) {
20679
20886
  out2.push({
20680
20887
  repoRoot: dir,
20681
- repoPath: path43.relative(workingDir, dir),
20682
- repoName: path43.basename(dir)
20888
+ repoPath: path44.relative(workingDir, dir),
20889
+ repoName: path44.basename(dir)
20683
20890
  });
20684
20891
  return;
20685
20892
  }
@@ -20687,14 +20894,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
20687
20894
  if (!entry.isDirectory) continue;
20688
20895
  if (entry.name === "node_modules") continue;
20689
20896
  if (entry.name === "dist" || entry.name === "build") continue;
20690
- await walk(path43.join(dir, entry.name), depth + 1);
20897
+ await walk(path44.join(dir, entry.name), depth + 1);
20691
20898
  }
20692
20899
  }
20693
20900
  }
20694
20901
 
20695
20902
  // src/services/turn-files/files-outbox.ts
20696
- var fs36 = __toESM(require("fs/promises"));
20697
- var path44 = __toESM(require("path"));
20903
+ var fs37 = __toESM(require("fs/promises"));
20904
+ var path45 = __toESM(require("path"));
20698
20905
  var import_os7 = require("os");
20699
20906
  var HOME_OUTBOX_DIR = ".codeam/outbox";
20700
20907
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -20727,16 +20934,16 @@ var FilesOutbox = class {
20727
20934
  backoffIndex = 0;
20728
20935
  stopped = false;
20729
20936
  constructor(opts) {
20730
- const base = opts.baseDir ?? path44.join(homeDir(), HOME_OUTBOX_DIR);
20731
- this.filePath = path44.join(base, `${opts.sessionId}.jsonl`);
20937
+ const base = opts.baseDir ?? path45.join(homeDir(), HOME_OUTBOX_DIR);
20938
+ this.filePath = path45.join(base, `${opts.sessionId}.jsonl`);
20732
20939
  this.post = opts.post;
20733
20940
  this.autoSchedule = opts.autoSchedule !== false;
20734
20941
  }
20735
20942
  /** Persist the entry to disk and trigger a flush. Returns once the
20736
20943
  * line is durable on disk (not once the POST succeeds). */
20737
20944
  async enqueue(entry) {
20738
- await fs36.mkdir(path44.dirname(this.filePath), { recursive: true });
20739
- await fs36.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
20945
+ await fs37.mkdir(path45.dirname(this.filePath), { recursive: true });
20946
+ await fs37.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
20740
20947
  this.backoffIndex = 0;
20741
20948
  if (this.autoSchedule) this.scheduleFlush(0);
20742
20949
  }
@@ -20825,7 +21032,7 @@ var FilesOutbox = class {
20825
21032
  async readAll() {
20826
21033
  let raw = "";
20827
21034
  try {
20828
- raw = await fs36.readFile(this.filePath, "utf8");
21035
+ raw = await fs37.readFile(this.filePath, "utf8");
20829
21036
  } catch {
20830
21037
  return [];
20831
21038
  }
@@ -20849,12 +21056,12 @@ var FilesOutbox = class {
20849
21056
  async rewrite(entries) {
20850
21057
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
20851
21058
  if (entries.length === 0) {
20852
- await fs36.unlink(this.filePath).catch(() => void 0);
21059
+ await fs37.unlink(this.filePath).catch(() => void 0);
20853
21060
  return;
20854
21061
  }
20855
21062
  const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
20856
- await fs36.writeFile(tmpPath, payload, "utf8");
20857
- await fs36.rename(tmpPath, this.filePath);
21063
+ await fs37.writeFile(tmpPath, payload, "utf8");
21064
+ await fs37.rename(tmpPath, this.filePath);
20858
21065
  }
20859
21066
  };
20860
21067
  function applyJitter(ms) {
@@ -21951,10 +22158,10 @@ var ChromeStepTracker = class {
21951
22158
  const visible = lines.map((l) => parseLine2(l)).filter((s) => s !== null);
21952
22159
  if (visible.length === 0) return;
21953
22160
  for (const step of visible) {
21954
- const exists = this.history.some(
22161
+ const exists2 = this.history.some(
21955
22162
  (s) => s.tool === step.tool && s.label === step.label
21956
22163
  );
21957
- if (!exists) this.history.push(step);
22164
+ if (!exists2) this.history.push(step);
21958
22165
  }
21959
22166
  }
21960
22167
  /**
@@ -22699,8 +22906,8 @@ var OutputService = class _OutputService {
22699
22906
  };
22700
22907
 
22701
22908
  // src/services/history.service.ts
22702
- var fs37 = __toESM(require("fs"));
22703
- var path45 = __toESM(require("path"));
22909
+ var fs38 = __toESM(require("fs"));
22910
+ var path46 = __toESM(require("path"));
22704
22911
  var os29 = __toESM(require("os"));
22705
22912
  var https7 = __toESM(require("https"));
22706
22913
  var http7 = __toESM(require("http"));
@@ -22728,7 +22935,7 @@ function parseJsonl(filePath) {
22728
22935
  const messages = [];
22729
22936
  let raw;
22730
22937
  try {
22731
- raw = fs37.readFileSync(filePath, "utf8");
22938
+ raw = fs38.readFileSync(filePath, "utf8");
22732
22939
  } catch (err) {
22733
22940
  if (err.code !== "ENOENT") {
22734
22941
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -22863,7 +23070,7 @@ var HistoryService = class _HistoryService {
22863
23070
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
22864
23071
  }
22865
23072
  get projectDir() {
22866
- return this.runtime.resolveHistoryDir(this.cwd) ?? path45.join(os29.homedir(), ".claude", "projects", encodeCwd(this.cwd));
23073
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path46.join(os29.homedir(), ".claude", "projects", encodeCwd(this.cwd));
22867
23074
  }
22868
23075
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
22869
23076
  setCurrentConversationId(id) {
@@ -22875,7 +23082,7 @@ var HistoryService = class _HistoryService {
22875
23082
  /** Return the current message count in the active conversation. */
22876
23083
  getCurrentMessageCount() {
22877
23084
  if (!this.currentConversationId) return 0;
22878
- const filePath = path45.join(this.projectDir, `${this.currentConversationId}.jsonl`);
23085
+ const filePath = path46.join(this.projectDir, `${this.currentConversationId}.jsonl`);
22879
23086
  return parseJsonl(filePath).length;
22880
23087
  }
22881
23088
  /**
@@ -22886,7 +23093,7 @@ var HistoryService = class _HistoryService {
22886
23093
  const deadline = Date.now() + timeoutMs;
22887
23094
  while (Date.now() < deadline) {
22888
23095
  if (!this.currentConversationId) return null;
22889
- const filePath = path45.join(this.projectDir, `${this.currentConversationId}.jsonl`);
23096
+ const filePath = path46.join(this.projectDir, `${this.currentConversationId}.jsonl`);
22890
23097
  const messages = parseJsonl(filePath);
22891
23098
  if (messages.length > previousCount) {
22892
23099
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -22912,16 +23119,16 @@ var HistoryService = class _HistoryService {
22912
23119
  const dir = this.projectDir;
22913
23120
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
22914
23121
  try {
22915
- const files = fs37.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
23122
+ const files = fs38.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
22916
23123
  try {
22917
- const stat3 = fs37.statSync(path45.join(dir, e.name));
23124
+ const stat3 = fs38.statSync(path46.join(dir, e.name));
22918
23125
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
22919
23126
  } catch {
22920
23127
  return { name: e.name, mtime: 0, birthtime: 0 };
22921
23128
  }
22922
23129
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
22923
23130
  if (files.length > 0) {
22924
- this.currentConversationId = path45.basename(files[0].name, ".jsonl");
23131
+ this.currentConversationId = path46.basename(files[0].name, ".jsonl");
22925
23132
  }
22926
23133
  } catch {
22927
23134
  }
@@ -22955,13 +23162,13 @@ var HistoryService = class _HistoryService {
22955
23162
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
22956
23163
  let entries;
22957
23164
  try {
22958
- entries = fs37.readdirSync(dir, { withFileTypes: true });
23165
+ entries = fs38.readdirSync(dir, { withFileTypes: true });
22959
23166
  } catch {
22960
23167
  return null;
22961
23168
  }
22962
23169
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
22963
23170
  try {
22964
- const stat3 = fs37.statSync(path45.join(dir, e.name));
23171
+ const stat3 = fs38.statSync(path46.join(dir, e.name));
22965
23172
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
22966
23173
  } catch {
22967
23174
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -22970,12 +23177,12 @@ var HistoryService = class _HistoryService {
22970
23177
  if (files.length === 0) return null;
22971
23178
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
22972
23179
  if (!files.some((f) => f.name === targetFile)) return null;
22973
- return this.extractUsageFromFile(path45.join(dir, targetFile));
23180
+ return this.extractUsageFromFile(path46.join(dir, targetFile));
22974
23181
  }
22975
23182
  extractUsageFromFile(filePath) {
22976
23183
  let raw;
22977
23184
  try {
22978
- raw = fs37.readFileSync(filePath, "utf8");
23185
+ raw = fs38.readFileSync(filePath, "utf8");
22979
23186
  } catch {
22980
23187
  return null;
22981
23188
  }
@@ -23020,9 +23227,9 @@ var HistoryService = class _HistoryService {
23020
23227
  let totalCost = 0;
23021
23228
  let files;
23022
23229
  try {
23023
- files = fs37.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
23230
+ files = fs38.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
23024
23231
  try {
23025
- return fs37.statSync(path45.join(projectDir, f)).mtimeMs >= monthStartMs;
23232
+ return fs38.statSync(path46.join(projectDir, f)).mtimeMs >= monthStartMs;
23026
23233
  } catch {
23027
23234
  return false;
23028
23235
  }
@@ -23033,7 +23240,7 @@ var HistoryService = class _HistoryService {
23033
23240
  for (const file of files) {
23034
23241
  let raw;
23035
23242
  try {
23036
- raw = fs37.readFileSync(path45.join(projectDir, file), "utf8");
23243
+ raw = fs38.readFileSync(path46.join(projectDir, file), "utf8");
23037
23244
  } catch {
23038
23245
  continue;
23039
23246
  }
@@ -23097,7 +23304,7 @@ var HistoryService = class _HistoryService {
23097
23304
  * showing an empty conversation.
23098
23305
  */
23099
23306
  async loadConversation(sessionId) {
23100
- const filePath = path45.join(this.projectDir, `${sessionId}.jsonl`);
23307
+ const filePath = path46.join(this.projectDir, `${sessionId}.jsonl`);
23101
23308
  const messages = parseJsonl(filePath);
23102
23309
  if (messages.length === 0) return;
23103
23310
  const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
@@ -23151,7 +23358,7 @@ var HistoryService = class _HistoryService {
23151
23358
  if (!this.currentConversationId) return 0;
23152
23359
  }
23153
23360
  const sessionId = this.currentConversationId;
23154
- const filePath = path45.join(this.projectDir, `${sessionId}.jsonl`);
23361
+ const filePath = path46.join(this.projectDir, `${sessionId}.jsonl`);
23155
23362
  const messages = parseJsonl(filePath);
23156
23363
  if (messages.length === 0) return 0;
23157
23364
  const marker = this.lastUploadedUuid.get(sessionId);
@@ -24072,7 +24279,7 @@ async function autoLinkAfterPair(opts) {
24072
24279
  }
24073
24280
 
24074
24281
  // src/commands/pair-auto.ts
24075
- var fs38 = __toESM(require("fs"));
24282
+ var fs39 = __toESM(require("fs"));
24076
24283
  var os30 = __toESM(require("os"));
24077
24284
  var import_crypto7 = require("crypto");
24078
24285
 
@@ -24268,12 +24475,12 @@ function readTokenFromArgs(args2) {
24268
24475
  }
24269
24476
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
24270
24477
  if (fileFlag) {
24271
- const path52 = fileFlag.slice("--token-file=".length);
24478
+ const path53 = fileFlag.slice("--token-file=".length);
24272
24479
  try {
24273
- const content = fs38.readFileSync(path52, "utf8").trim();
24274
- if (content.length === 0) fail(`--token-file ${path52} is empty`);
24480
+ const content = fs39.readFileSync(path53, "utf8").trim();
24481
+ if (content.length === 0) fail(`--token-file ${path53} is empty`);
24275
24482
  try {
24276
- fs38.unlinkSync(path52);
24483
+ fs39.unlinkSync(path53);
24277
24484
  } catch {
24278
24485
  }
24279
24486
  return content;
@@ -24391,6 +24598,8 @@ async function pairAuto(args2) {
24391
24598
  codespaceName: process.env.CODESPACE_NAME ?? void 0
24392
24599
  });
24393
24600
  console.log(` Paired with ${claimed.user.name} (${claimed.user.plan})`);
24601
+ void provisionProjectDependencies(process.cwd()).catch(() => {
24602
+ });
24394
24603
  if (process.env.CODEAM_SKIP_AGENT_LAUNCH === "true") {
24395
24604
  capture("pair_auto_skipped_launch", {
24396
24605
  sessionId: claimed.sessionId,
@@ -24539,7 +24748,7 @@ var import_picocolors10 = __toESM(require("picocolors"));
24539
24748
  var import_child_process22 = require("child_process");
24540
24749
  var import_util4 = require("util");
24541
24750
  var import_picocolors8 = __toESM(require("picocolors"));
24542
- var path46 = __toESM(require("path"));
24751
+ var path47 = __toESM(require("path"));
24543
24752
  var execFileP5 = (0, import_util4.promisify)(import_child_process22.execFile);
24544
24753
  var MAX_BUFFER = 8 * 1024 * 1024;
24545
24754
  function resetStdinForChild() {
@@ -25028,7 +25237,7 @@ var GitHubCodespacesProvider = class {
25028
25237
  });
25029
25238
  }
25030
25239
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25031
- const remoteDir = path46.posix.dirname(remotePath);
25240
+ const remoteDir = path47.posix.dirname(remotePath);
25032
25241
  const parts = [
25033
25242
  `mkdir -p ${shellQuote(remoteDir)}`,
25034
25243
  `cat > ${shellQuote(remotePath)}`
@@ -25098,7 +25307,7 @@ function shellQuote(s) {
25098
25307
  // src/services/providers/gitpod.ts
25099
25308
  var import_child_process23 = require("child_process");
25100
25309
  var import_util5 = require("util");
25101
- var path47 = __toESM(require("path"));
25310
+ var path48 = __toESM(require("path"));
25102
25311
  var import_picocolors9 = __toESM(require("picocolors"));
25103
25312
  var execFileP6 = (0, import_util5.promisify)(import_child_process23.execFile);
25104
25313
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -25338,7 +25547,7 @@ var GitpodProvider = class {
25338
25547
  });
25339
25548
  }
25340
25549
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25341
- const remoteDir = path47.posix.dirname(remotePath);
25550
+ const remoteDir = path48.posix.dirname(remotePath);
25342
25551
  const parts = [
25343
25552
  `mkdir -p ${shellQuote2(remoteDir)}`,
25344
25553
  `cat > ${shellQuote2(remotePath)}`
@@ -25374,7 +25583,7 @@ function shellQuote2(s) {
25374
25583
  // src/services/providers/gitlab-workspaces.ts
25375
25584
  var import_child_process24 = require("child_process");
25376
25585
  var import_util6 = require("util");
25377
- var path48 = __toESM(require("path"));
25586
+ var path49 = __toESM(require("path"));
25378
25587
  var execFileP7 = (0, import_util6.promisify)(import_child_process24.execFile);
25379
25588
  var MAX_BUFFER3 = 8 * 1024 * 1024;
25380
25589
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -25634,7 +25843,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
25634
25843
  }
25635
25844
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25636
25845
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
25637
- const remoteDir = path48.posix.dirname(remotePath);
25846
+ const remoteDir = path49.posix.dirname(remotePath);
25638
25847
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
25639
25848
  if (options.mode != null) {
25640
25849
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -25702,7 +25911,7 @@ function shellQuote3(s) {
25702
25911
  // src/services/providers/railway.ts
25703
25912
  var import_child_process25 = require("child_process");
25704
25913
  var import_util7 = require("util");
25705
- var path49 = __toESM(require("path"));
25914
+ var path50 = __toESM(require("path"));
25706
25915
  var execFileP8 = (0, import_util7.promisify)(import_child_process25.execFile);
25707
25916
  var MAX_BUFFER4 = 8 * 1024 * 1024;
25708
25917
  function resetStdinForChild4() {
@@ -25938,7 +26147,7 @@ var RailwayProvider = class {
25938
26147
  if (!projectId || !serviceId) {
25939
26148
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
25940
26149
  }
25941
- const remoteDir = path49.posix.dirname(remotePath);
26150
+ const remoteDir = path50.posix.dirname(remotePath);
25942
26151
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
25943
26152
  if (options.mode != null) {
25944
26153
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -26481,8 +26690,8 @@ async function stopWorkspaceFromLocal(target) {
26481
26690
  var import_node_dns = require("dns");
26482
26691
  var import_node_util4 = require("util");
26483
26692
  var import_node_crypto8 = require("crypto");
26484
- var fs39 = __toESM(require("fs"));
26485
- var path50 = __toESM(require("path"));
26693
+ var fs40 = __toESM(require("fs"));
26694
+ var path51 = __toESM(require("path"));
26486
26695
  var import_picocolors12 = __toESM(require("picocolors"));
26487
26696
  var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
26488
26697
  async function checkDns(apiBase) {
@@ -26538,13 +26747,13 @@ async function checkHealth(apiBase) {
26538
26747
  }
26539
26748
  }
26540
26749
  function checkConfigDir() {
26541
- const dir = path50.join(require("os").homedir(), ".codeam");
26750
+ const dir = path51.join(require("os").homedir(), ".codeam");
26542
26751
  try {
26543
- fs39.mkdirSync(dir, { recursive: true, mode: 448 });
26544
- const probe = path50.join(dir, ".doctor-probe");
26545
- fs39.writeFileSync(probe, "ok", { mode: 384 });
26546
- const read = fs39.readFileSync(probe, "utf8");
26547
- fs39.unlinkSync(probe);
26752
+ fs40.mkdirSync(dir, { recursive: true, mode: 448 });
26753
+ const probe = path51.join(dir, ".doctor-probe");
26754
+ fs40.writeFileSync(probe, "ok", { mode: 384 });
26755
+ const read = fs40.readFileSync(probe, "utf8");
26756
+ fs40.unlinkSync(probe);
26548
26757
  if (read !== "ok") throw new Error("write/read round-trip mismatch");
26549
26758
  return {
26550
26759
  id: "config-dir",
@@ -26608,7 +26817,7 @@ function checkNodePty() {
26608
26817
  detail: "not required on this platform"
26609
26818
  };
26610
26819
  }
26611
- const vendoredPath = path50.join(__dirname, "vendor", "node-pty");
26820
+ const vendoredPath = path51.join(__dirname, "vendor", "node-pty");
26612
26821
  for (const target of [vendoredPath, "node-pty"]) {
26613
26822
  try {
26614
26823
  require(target);
@@ -26650,7 +26859,7 @@ function checkChokidar() {
26650
26859
  }
26651
26860
  async function doctor(args2 = []) {
26652
26861
  const json = args2.includes("--json");
26653
- const cliVersion = true ? "2.38.0" : "0.0.0-dev";
26862
+ const cliVersion = true ? "2.39.0" : "0.0.0-dev";
26654
26863
  const apiBase = resolveApiBaseUrl();
26655
26864
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
26656
26865
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -26849,7 +27058,7 @@ async function completion(args2) {
26849
27058
  // src/commands/version.ts
26850
27059
  var import_picocolors13 = __toESM(require("picocolors"));
26851
27060
  function version2() {
26852
- const v = true ? "2.38.0" : "unknown";
27061
+ const v = true ? "2.39.0" : "unknown";
26853
27062
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
26854
27063
  }
26855
27064
 
@@ -26977,9 +27186,9 @@ function tryShowSubcommandHelp(cmd, args2) {
26977
27186
  var _subcommandHelpKeys = Object.keys(HELPS);
26978
27187
 
26979
27188
  // src/lib/updateNotifier.ts
26980
- var fs40 = __toESM(require("fs"));
27189
+ var fs41 = __toESM(require("fs"));
26981
27190
  var os31 = __toESM(require("os"));
26982
- var path51 = __toESM(require("path"));
27191
+ var path52 = __toESM(require("path"));
26983
27192
  var https8 = __toESM(require("https"));
26984
27193
  var import_node_child_process12 = require("child_process");
26985
27194
  var import_picocolors16 = __toESM(require("picocolors"));
@@ -26988,12 +27197,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
26988
27197
  var TTL_MS = 24 * 60 * 60 * 1e3;
26989
27198
  var REQUEST_TIMEOUT_MS = 1500;
26990
27199
  function cachePath() {
26991
- const dir = path51.join(os31.homedir(), ".codeam");
26992
- return path51.join(dir, "update-check.json");
27200
+ const dir = path52.join(os31.homedir(), ".codeam");
27201
+ return path52.join(dir, "update-check.json");
26993
27202
  }
26994
27203
  function readCache() {
26995
27204
  try {
26996
- const raw = fs40.readFileSync(cachePath(), "utf8");
27205
+ const raw = fs41.readFileSync(cachePath(), "utf8");
26997
27206
  const parsed = JSON.parse(raw);
26998
27207
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
26999
27208
  return parsed;
@@ -27004,10 +27213,10 @@ function readCache() {
27004
27213
  function writeCache(cache) {
27005
27214
  try {
27006
27215
  const file = cachePath();
27007
- fs40.mkdirSync(path51.dirname(file), { recursive: true });
27216
+ fs41.mkdirSync(path52.dirname(file), { recursive: true });
27008
27217
  const tmp = `${file}.${process.pid}.tmp`;
27009
- fs40.writeFileSync(tmp, JSON.stringify(cache));
27010
- fs40.renameSync(tmp, file);
27218
+ fs41.writeFileSync(tmp, JSON.stringify(cache));
27219
+ fs41.renameSync(tmp, file);
27011
27220
  } catch {
27012
27221
  }
27013
27222
  }
@@ -27081,8 +27290,8 @@ function isLinkedInstall() {
27081
27290
  timeout: 2e3
27082
27291
  }).trim();
27083
27292
  if (!root) return false;
27084
- const pkgPath = path51.join(root, PKG_NAME);
27085
- return fs40.lstatSync(pkgPath).isSymbolicLink();
27293
+ const pkgPath = path52.join(root, PKG_NAME);
27294
+ return fs41.lstatSync(pkgPath).isSymbolicLink();
27086
27295
  } catch {
27087
27296
  return false;
27088
27297
  }
@@ -27118,7 +27327,7 @@ function maybeAutoUpdate(currentVersion, latest) {
27118
27327
  return;
27119
27328
  }
27120
27329
  try {
27121
- fs40.unlinkSync(cachePath());
27330
+ fs41.unlinkSync(cachePath());
27122
27331
  } catch {
27123
27332
  }
27124
27333
  process.stderr.write(` ${import_picocolors16.default.green("\u2713")} Updated. Resuming session...
@@ -27135,7 +27344,7 @@ function checkForUpdates() {
27135
27344
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
27136
27345
  if (process.env.CI) return;
27137
27346
  if (!process.stdout.isTTY) return;
27138
- const current = true ? "2.38.0" : null;
27347
+ const current = true ? "2.39.0" : null;
27139
27348
  if (!current) return;
27140
27349
  const cache = readCache();
27141
27350
  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.38.0",
3
+ "version": "2.39.0",
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",