codeam-cli 2.75.25 → 2.75.27

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 +14 -0
  2. package/dist/index.js +1563 -765
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -357,8 +357,8 @@ function defaultSpawn(timeoutMs) {
357
357
  });
358
358
  }
359
359
  function resolveConvexBin(cwd) {
360
- const local = path94.join(cwd, "node_modules", ".bin", process.platform === "win32" ? "convex.cmd" : "convex");
361
- if (fs80.existsSync(local)) return { cmd: local, args: [] };
360
+ const local = path95.join(cwd, "node_modules", ".bin", process.platform === "win32" ? "convex.cmd" : "convex");
361
+ if (fs81.existsSync(local)) return { cmd: local, args: [] };
362
362
  return { cmd: "npx", args: ["--yes", "convex"] };
363
363
  }
364
364
  function redact(text, key) {
@@ -489,13 +489,13 @@ async function runConvexAdminMcp(client3, id) {
489
489
  });
490
490
  await server.connect(new StdioServerTransport());
491
491
  }
492
- var import_node_child_process32, fs80, path94, TOOLS;
492
+ var import_node_child_process32, fs81, path95, TOOLS;
493
493
  var init_convex_admin_mcp = __esm({
494
494
  "src/integrations/convex-admin-mcp.ts"() {
495
495
  "use strict";
496
496
  import_node_child_process32 = require("child_process");
497
- fs80 = __toESM(require("fs"));
498
- path94 = __toESM(require("path"));
497
+ fs81 = __toESM(require("fs"));
498
+ path95 = __toESM(require("path"));
499
499
  TOOLS = [
500
500
  {
501
501
  name: "tables",
@@ -3248,6 +3248,9 @@ var USER_EVENTS = {
3248
3248
  PREVIEW_STOPPED: "preview_stopped",
3249
3249
  PREVIEW_ERROR: "preview_error",
3250
3250
  PREVIEW_PROGRESS: "preview_progress",
3251
+ /** The agent points at an element of the running preview (`highlight_element`
3252
+ * MCP tool) — the inspector client draws the agent's mark over it. */
3253
+ PREVIEW_AGENT_HIGHLIGHT: "preview_agent_highlight",
3251
3254
  BEADS_STATE_CHANGED: "beads_state_changed",
3252
3255
  BEADS_PROVISIONING: "beads_provisioning",
3253
3256
  BEADS_TEAM_MEMORY_CHANGED: "beads_team_memory_changed",
@@ -3428,6 +3431,9 @@ function maybeRotate() {
3428
3431
  } catch {
3429
3432
  return;
3430
3433
  }
3434
+ rotateNow();
3435
+ }
3436
+ function rotateNow() {
3431
3437
  const archivePath = (n) => n === 0 ? `${debugFilePath}.old` : `${debugFilePath}.${n}`;
3432
3438
  for (let i = MAX_ARCHIVES - 1; i >= 0; i--) {
3433
3439
  const src = archivePath(i);
@@ -3451,6 +3457,7 @@ function appendToFile(line) {
3451
3457
  try {
3452
3458
  if (!fileInitialized) {
3453
3459
  fs.mkdirSync(path.dirname(debugFilePath), { recursive: true, mode: 448 });
3460
+ if (fs.existsSync(debugFilePath)) rotateNow();
3454
3461
  const header = jsonMode ? `${JSON.stringify({
3455
3462
  ts: (/* @__PURE__ */ new Date()).toISOString(),
3456
3463
  level: "info",
@@ -3525,11 +3532,11 @@ function quiet(fn) {
3525
3532
  log.debug(TAG, "ignored sync error", err);
3526
3533
  }
3527
3534
  }
3528
- function rmIfExistsQuiet(path96) {
3535
+ function rmIfExistsQuiet(path97) {
3529
3536
  try {
3530
- fs2.rmSync(path96, { force: true });
3537
+ fs2.rmSync(path97, { force: true });
3531
3538
  } catch (err) {
3532
- log.debug(TAG, `rmIfExists failed for ${path96}`, err);
3539
+ log.debug(TAG, `rmIfExists failed for ${path97}`, err);
3533
3540
  }
3534
3541
  }
3535
3542
  function killQuiet(target, signal = "SIGTERM") {
@@ -3733,8 +3740,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
3733
3740
  return decodedFile;
3734
3741
  };
3735
3742
  }
3736
- function normalizeWindowsPath(path96) {
3737
- return path96.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
3743
+ function normalizeWindowsPath(path97) {
3744
+ return path97.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
3738
3745
  }
3739
3746
 
3740
3747
  // ../../node_modules/@posthog/core/dist/error-tracking/index.mjs
@@ -6467,13 +6474,13 @@ var PostHogCoreStateless = class {
6467
6474
  sentFromRoute += batchMessages.length;
6468
6475
  }
6469
6476
  }
6470
- async _sendOtlpBatch({ path: path96, payload }) {
6477
+ async _sendOtlpBatch({ path: path97, payload }) {
6471
6478
  if (this.disabled) return {
6472
6479
  kind: "fatal",
6473
6480
  error: new Error("The client is disabled")
6474
6481
  };
6475
6482
  const serialized = JSON.stringify(payload);
6476
- const url2 = `${this.host}/i/v1/${path96}?token=${encodeURIComponent(this.apiKey)}`;
6483
+ const url2 = `${this.host}/i/v1/${path97}?token=${encodeURIComponent(this.apiKey)}`;
6477
6484
  const gzippedPayload = this.disableCompression ? null : await this.compressPayload(serialized);
6478
6485
  const fetchOptions = {
6479
6486
  method: "POST",
@@ -7713,14 +7720,14 @@ async function addSourceContext(frames, openSourceFile = import_promises.open, l
7713
7720
  LRU_FILE_CONTENTS_CACHE.reduce();
7714
7721
  return frames;
7715
7722
  }
7716
- async function openRegularSourceFile(path96, openSourceFile, logger) {
7723
+ async function openRegularSourceFile(path97, openSourceFile, logger) {
7717
7724
  let fileHandle;
7718
7725
  let isValid = false;
7719
7726
  try {
7720
- fileHandle = await openSourceFile(path96, import_node_fs.constants.O_RDONLY | import_node_fs.constants.O_NONBLOCK);
7727
+ fileHandle = await openSourceFile(path97, import_node_fs.constants.O_RDONLY | import_node_fs.constants.O_NONBLOCK);
7721
7728
  const fileStat = await fileHandle.stat();
7722
7729
  if (!fileStat.isFile()) return;
7723
- if (fileStat.size > MAX_CONTEXTLINES_FILE_SIZE) return void logger?.debug(`Skipping source context for oversized file ${path96}: ${fileStat.size} bytes exceeds ${MAX_CONTEXTLINES_FILE_SIZE}`);
7730
+ if (fileStat.size > MAX_CONTEXTLINES_FILE_SIZE) return void logger?.debug(`Skipping source context for oversized file ${path97}: ${fileStat.size} bytes exceeds ${MAX_CONTEXTLINES_FILE_SIZE}`);
7724
7731
  isValid = true;
7725
7732
  return fileHandle;
7726
7733
  } catch {
@@ -7730,8 +7737,8 @@ async function openRegularSourceFile(path96, openSourceFile, logger) {
7730
7737
  });
7731
7738
  }
7732
7739
  }
7733
- async function getContextLinesFromFile(path96, ranges, output, cacheKey, openSourceFile, logger) {
7734
- const fileHandle = await openRegularSourceFile(path96, openSourceFile, logger);
7740
+ async function getContextLinesFromFile(path97, ranges, output, cacheKey, openSourceFile, logger) {
7741
+ const fileHandle = await openRegularSourceFile(path97, openSourceFile, logger);
7735
7742
  if (void 0 === fileHandle) return void LRU_FILE_CONTENTS_FS_READ_FAILED.set(cacheKey, 1);
7736
7743
  const openedFileHandle = fileHandle;
7737
7744
  return new Promise((resolve12) => {
@@ -7833,22 +7840,22 @@ function clearLineContext(frame) {
7833
7840
  delete frame.context_line;
7834
7841
  delete frame.post_context;
7835
7842
  }
7836
- function shouldSkipContextLinesForFile(path96) {
7837
- return path96.startsWith("node:") || path96.endsWith(".min.js") || path96.endsWith(".min.cjs") || path96.endsWith(".min.mjs") || path96.startsWith("data:");
7843
+ function shouldSkipContextLinesForFile(path97) {
7844
+ return path97.startsWith("node:") || path97.endsWith(".min.js") || path97.endsWith(".min.cjs") || path97.endsWith(".min.mjs") || path97.startsWith("data:");
7838
7845
  }
7839
7846
  function shouldSkipContextLinesForFrame(frame) {
7840
7847
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
7841
7848
  if (void 0 !== frame.colno && frame.colno > MAX_CONTEXTLINES_COLNO) return true;
7842
7849
  return false;
7843
7850
  }
7844
- function makeSourceCacheKey(path96, basePath) {
7845
- if ((0, import_node_path.isAbsolute)(path96)) return JSON.stringify([
7851
+ function makeSourceCacheKey(path97, basePath) {
7852
+ if ((0, import_node_path.isAbsolute)(path97)) return JSON.stringify([
7846
7853
  null,
7847
- path96
7854
+ path97
7848
7855
  ]);
7849
7856
  return void 0 === basePath ? void 0 : JSON.stringify([
7850
7857
  basePath,
7851
- path96
7858
+ path97
7852
7859
  ]);
7853
7860
  }
7854
7861
  function rangeExistsInContentCache(cacheKey, range) {
@@ -10509,7 +10516,7 @@ function readAnonId() {
10509
10516
  }
10510
10517
  function superProperties() {
10511
10518
  return {
10512
- cliVersion: true ? "2.75.25" : "0.0.0-dev",
10519
+ cliVersion: true ? "2.75.27" : "0.0.0-dev",
10513
10520
  nodeVersion: process.version,
10514
10521
  platform: process.platform,
10515
10522
  arch: process.arch,
@@ -10751,7 +10758,7 @@ var http = __toESM(require("http"));
10751
10758
  // package.json
10752
10759
  var package_default = {
10753
10760
  name: "codeam-cli",
10754
- version: "2.75.25",
10761
+ version: "2.75.27",
10755
10762
  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.",
10756
10763
  type: "commonjs",
10757
10764
  main: "dist/index.js",
@@ -12081,7 +12088,7 @@ var CommandRelayService = class _CommandRelayService {
12081
12088
  // fresh + clear the "CLI update available" banner after a self-update
12082
12089
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
12083
12090
  // pair/reconnect). Older backends ignore the extra field.
12084
- ..."2.75.25" ? { ideVersion: "2.75.25" } : {}
12091
+ ..."2.75.27" ? { ideVersion: "2.75.27" } : {}
12085
12092
  };
12086
12093
  try {
12087
12094
  const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body);
@@ -12387,10 +12394,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
12387
12394
  /[\\/]Start Menu([\\/]|$)/i,
12388
12395
  /[\\/]Templates([\\/]|$)/i
12389
12396
  ];
12390
- function isUnsafeWindowsWatchRoot(dir, homedir51) {
12397
+ function isUnsafeWindowsWatchRoot(dir, homedir52) {
12391
12398
  const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
12392
12399
  const cwd = norm(dir);
12393
- const home = norm(homedir51);
12400
+ const home = norm(homedir52);
12394
12401
  if (cwd === home) return true;
12395
12402
  if (/^[a-z]:$/.test(cwd)) return true;
12396
12403
  const sysRoots = [
@@ -17120,10 +17127,10 @@ function buildForPlatform(platform3) {
17120
17127
  var import_node_crypto4 = require("crypto");
17121
17128
 
17122
17129
  // src/agents/claude/resolver.ts
17123
- function buildClaudeLaunch(extraArgs = [], os65 = createOsStrategy()) {
17124
- const found = os65.findInPath("claude") ?? os65.findInPath("claude-code");
17130
+ function buildClaudeLaunch(extraArgs = [], os66 = createOsStrategy()) {
17131
+ const found = os66.findInPath("claude") ?? os66.findInPath("claude-code");
17125
17132
  if (!found) return null;
17126
- return os65.buildLaunch(found, extraArgs);
17133
+ return os66.buildLaunch(found, extraArgs);
17127
17134
  }
17128
17135
 
17129
17136
  // src/agents/claude/installer.ts
@@ -17901,8 +17908,8 @@ var ClaudeRuntimeStrategy = class {
17901
17908
  meta = getAgent("claude");
17902
17909
  mode = "interactive";
17903
17910
  os;
17904
- constructor(os65) {
17905
- this.os = os65;
17911
+ constructor(os66) {
17912
+ this.os = os66;
17906
17913
  }
17907
17914
  /**
17908
17915
  * Claude Code's react-ink TUI enables bracketed-paste mode at
@@ -18996,8 +19003,8 @@ function codexCredentialLocator() {
18996
19003
  function codexLoginLauncher() {
18997
19004
  return {
18998
19005
  async ensureInstalled() {
18999
- const os65 = createOsStrategy();
19000
- return os65.findInPath("codex") !== null;
19006
+ const os66 = createOsStrategy();
19007
+ return os66.findInPath("codex") !== null;
19001
19008
  },
19002
19009
  launch() {
19003
19010
  return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
@@ -19020,8 +19027,8 @@ var CodexRuntimeStrategy = class {
19020
19027
  meta = getAgent("codex");
19021
19028
  mode = "interactive";
19022
19029
  os;
19023
- constructor(os65) {
19024
- this.os = os65;
19030
+ constructor(os66) {
19031
+ this.os = os66;
19025
19032
  }
19026
19033
  async prepareLaunch() {
19027
19034
  let binary = this.os.findInPath("codex");
@@ -19131,12 +19138,12 @@ var CodexRuntimeStrategy = class {
19131
19138
  });
19132
19139
  }
19133
19140
  };
19134
- function resolveNpm(os65) {
19135
- return os65.id === "win32" ? "npm.cmd" : "npm";
19141
+ function resolveNpm(os66) {
19142
+ return os66.id === "win32" ? "npm.cmd" : "npm";
19136
19143
  }
19137
- async function installCodexViaNpm(os65) {
19144
+ async function installCodexViaNpm(os66) {
19138
19145
  return new Promise((resolve12, reject) => {
19139
- const proc = (0, import_node_child_process4.spawn)(resolveNpm(os65), ["install", "-g", "@openai/codex"], {
19146
+ const proc = (0, import_node_child_process4.spawn)(resolveNpm(os66), ["install", "-g", "@openai/codex"], {
19140
19147
  stdio: "inherit"
19141
19148
  });
19142
19149
  proc.on("close", (code) => {
@@ -19153,16 +19160,16 @@ async function installCodexViaNpm(os65) {
19153
19160
  });
19154
19161
  });
19155
19162
  }
19156
- function augmentNpmGlobalBin(os65) {
19163
+ function augmentNpmGlobalBin(os66) {
19157
19164
  try {
19158
- const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os65), ["prefix", "-g"], {
19165
+ const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os66), ["prefix", "-g"], {
19159
19166
  stdio: ["ignore", "pipe", "ignore"]
19160
19167
  });
19161
19168
  if (result.status !== 0) return;
19162
19169
  const prefix = result.stdout.toString().trim();
19163
19170
  if (!prefix) return;
19164
- const binDir = os65.id === "win32" ? prefix : path24.join(prefix, "bin");
19165
- os65.augmentPath([binDir]);
19171
+ const binDir = os66.id === "win32" ? prefix : path24.join(prefix, "bin");
19172
+ os66.augmentPath([binDir]);
19166
19173
  } catch {
19167
19174
  }
19168
19175
  }
@@ -19356,10 +19363,10 @@ function manualInstallHint(runner, tools) {
19356
19363
  const argv = osPackageInstallArgv(detectPackageManager(runner), [...tools]);
19357
19364
  return argv ? `\`sudo ${argv.join(" ")}\`` : `your package manager (e.g. \`${pkgs}\`)`;
19358
19365
  }
19359
- function writeUnzipShim(os65, runner) {
19366
+ function writeUnzipShim(os66, runner) {
19360
19367
  const python = ["python3", "python"].find((p2) => runner.which(p2));
19361
19368
  if (!python) return null;
19362
- const dir = os65.scratchPath("codeam-cr-prereq");
19369
+ const dir = os66.scratchPath("codeam-cr-prereq");
19363
19370
  const shim = path26.join(dir, "unzip");
19364
19371
  const script = `#!/bin/sh
19365
19372
  set -e
@@ -19381,9 +19388,9 @@ exec ${python} -m zipfile -e "$archive" "$dest"
19381
19388
  (0, import_node_fs5.chmodSync)(shim, 448);
19382
19389
  return dir;
19383
19390
  }
19384
- async function ensureInstallPrerequisites(os65, deps = {}) {
19391
+ async function ensureInstallPrerequisites(os66, deps = {}) {
19385
19392
  const runner = deps.runner ?? defaultOsRunner;
19386
- const missing = REQUIRED_TOOLS.filter((t2) => os65.findInPath(t2) === null);
19393
+ const missing = REQUIRED_TOOLS.filter((t2) => os66.findInPath(t2) === null);
19387
19394
  if (missing.length === 0) return { ok: true, extraPath: [] };
19388
19395
  log.info(
19389
19396
  "coderabbit",
@@ -19402,10 +19409,10 @@ async function ensureInstallPrerequisites(os65, deps = {}) {
19402
19409
  );
19403
19410
  }
19404
19411
  }
19405
- const stillMissing = REQUIRED_TOOLS.filter((t2) => os65.findInPath(t2) === null);
19412
+ const stillMissing = REQUIRED_TOOLS.filter((t2) => os66.findInPath(t2) === null);
19406
19413
  if (stillMissing.length === 0) return { ok: true, extraPath: [] };
19407
19414
  if (stillMissing.length === 1 && stillMissing[0] === "unzip") {
19408
- const shimDir = writeUnzipShim(os65, runner);
19415
+ const shimDir = writeUnzipShim(os66, runner);
19409
19416
  if (shimDir) {
19410
19417
  log.info("coderabbit", "unzip is unavailable \u2014 using a scoped python zipfile shim");
19411
19418
  return { ok: true, extraPath: [shimDir] };
@@ -19468,15 +19475,15 @@ function summarizeInstallFailure(output) {
19468
19475
  }
19469
19476
  return lines.length > 0 ? lines[lines.length - 1] : null;
19470
19477
  }
19471
- async function ensureCoderabbitInstalled(os65, deps = {}) {
19472
- if (os65.findInPath("coderabbit")) return { ok: true };
19473
- if (os65.id === "win32") {
19478
+ async function ensureCoderabbitInstalled(os66, deps = {}) {
19479
+ if (os66.findInPath("coderabbit")) return { ok: true };
19480
+ if (os66.id === "win32") {
19474
19481
  return {
19475
19482
  ok: false,
19476
19483
  error: "CodeRabbit on Windows requires WSL. Install the CLI inside your WSL distribution (curl -fsSL https://cli.coderabbit.ai/install.sh | sh), then try again."
19477
19484
  };
19478
19485
  }
19479
- const prereq = await ensureInstallPrerequisites(os65, deps);
19486
+ const prereq = await ensureInstallPrerequisites(os66, deps);
19480
19487
  if (!prereq.ok) return { ok: false, error: prereq.error };
19481
19488
  const env = { ...process.env };
19482
19489
  if (prereq.extraPath.length > 0) {
@@ -19485,8 +19492,8 @@ async function ensureCoderabbitInstalled(os65, deps = {}) {
19485
19492
  log.info("coderabbit", "CodeRabbit CLI not found \u2014 installing via the official script");
19486
19493
  const run = deps.runInstallScript ?? defaultRunInstallScript;
19487
19494
  const { code, output } = await run(env);
19488
- os65.augmentPath([`${os65.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
19489
- const binary = os65.findInPath("coderabbit");
19495
+ os66.augmentPath([`${os66.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
19496
+ const binary = os66.findInPath("coderabbit");
19490
19497
  const detail = summarizeInstallFailure(output);
19491
19498
  if (binary !== null) {
19492
19499
  if (code === 0) return { ok: true };
@@ -19540,10 +19547,10 @@ function coderabbitCredentialLocator() {
19540
19547
  validate: validateNonEmptyCredential
19541
19548
  };
19542
19549
  }
19543
- function coderabbitLoginLauncher(os65) {
19550
+ function coderabbitLoginLauncher(os66) {
19544
19551
  return {
19545
19552
  async ensureInstalled() {
19546
- const result = await ensureCoderabbitInstalled(os65);
19553
+ const result = await ensureCoderabbitInstalled(os66);
19547
19554
  if (!result.ok && result.error) console.error(`
19548
19555
  \u2717 ${result.error}
19549
19556
  `);
@@ -19603,8 +19610,8 @@ function pickLine(obj) {
19603
19610
  function toHunk(raw, groupSeverity) {
19604
19611
  if (!raw || typeof raw !== "object") return null;
19605
19612
  const o = raw;
19606
- const path96 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
19607
- if (!path96) return null;
19613
+ const path97 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
19614
+ if (!path97) return null;
19608
19615
  const message = asString(
19609
19616
  pick(o, [
19610
19617
  "comment",
@@ -19621,7 +19628,7 @@ function toHunk(raw, groupSeverity) {
19621
19628
  const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
19622
19629
  const locObj = pick(o, ["location"]) ?? o;
19623
19630
  return {
19624
- path: path96.trim(),
19631
+ path: path97.trim(),
19625
19632
  line: pickLine(o) ?? pickLine(locObj),
19626
19633
  severity,
19627
19634
  message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
@@ -19704,10 +19711,10 @@ function parsePlain(stdout) {
19704
19711
  for (const line of stdout.split(/\r?\n/)) {
19705
19712
  const m = line.match(HUNK_LINE_RE);
19706
19713
  if (!m) continue;
19707
- const [, path96, lineNo, sevToken, message] = m;
19708
- if (!path96 || !lineNo || !message) continue;
19714
+ const [, path97, lineNo, sevToken, message] = m;
19715
+ if (!path97 || !lineNo || !message) continue;
19709
19716
  hunks.push({
19710
- path: path96.trim(),
19717
+ path: path97.trim(),
19711
19718
  line: Number(lineNo),
19712
19719
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
19713
19720
  message: message.trim().replace(/^[*-]\s+/, "")
@@ -19767,8 +19774,8 @@ var CoderabbitRuntimeStrategy = class {
19767
19774
  meta = getAgent("coderabbit");
19768
19775
  mode = "batch";
19769
19776
  os;
19770
- constructor(os65) {
19771
- this.os = os65;
19777
+ constructor(os66) {
19778
+ this.os = os66;
19772
19779
  }
19773
19780
  getDefaultArgs() {
19774
19781
  return ["review", "--agent"];
@@ -20039,10 +20046,10 @@ function cursorCredentialLocator() {
20039
20046
  validate: validateNonEmptyCredential
20040
20047
  };
20041
20048
  }
20042
- function cursorLoginLauncher(os65) {
20049
+ function cursorLoginLauncher(os66) {
20043
20050
  return {
20044
20051
  async ensureInstalled() {
20045
- if (os65.findInPath("cursor-agent")) return true;
20052
+ if (os66.findInPath("cursor-agent")) return true;
20046
20053
  console.error(
20047
20054
  "\n \u2717 cursor-agent binary not on PATH.\n Install Cursor (https://cursor.com/) and ensure the CLI\n plugin is enabled, then re-run `codeam link cursor`.\n"
20048
20055
  );
@@ -20106,8 +20113,8 @@ var CursorRuntimeStrategy = class {
20106
20113
  meta = getAgent("cursor");
20107
20114
  mode = "interactive";
20108
20115
  os;
20109
- constructor(os65) {
20110
- this.os = os65;
20116
+ constructor(os66) {
20117
+ this.os = os66;
20111
20118
  }
20112
20119
  async prepareLaunch() {
20113
20120
  const binary = this.os.findInPath("cursor-agent");
@@ -20324,10 +20331,10 @@ function aiderCredentialLocator() {
20324
20331
  validate: validateNonEmptyCredential
20325
20332
  };
20326
20333
  }
20327
- function aiderLoginLauncher(os65) {
20334
+ function aiderLoginLauncher(os66) {
20328
20335
  return {
20329
20336
  async ensureInstalled() {
20330
- if (os65.findInPath("aider")) return true;
20337
+ if (os66.findInPath("aider")) return true;
20331
20338
  console.error(
20332
20339
  "\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
20333
20340
  );
@@ -20337,7 +20344,7 @@ function aiderLoginLauncher(os65) {
20337
20344
  console.error(
20338
20345
  "\n Aider has no interactive login flow.\n Set ANTHROPIC_API_KEY or OPENAI_API_KEY in your shell,\n or re-run `codeam link aider --api-key=<your-key>`.\n"
20339
20346
  );
20340
- return (0, import_node_child_process11.spawn)(os65.id === "win32" ? "cmd.exe" : "sh", os65.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
20347
+ return (0, import_node_child_process11.spawn)(os66.id === "win32" ? "cmd.exe" : "sh", os66.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
20341
20348
  stdio: "ignore"
20342
20349
  });
20343
20350
  }
@@ -20426,14 +20433,14 @@ function defaultSdkDir() {
20426
20433
  return resolveSdkDirViaRequire();
20427
20434
  }
20428
20435
  function resolveClaudeNativeBinary(deps = {}) {
20429
- const existsSync28 = deps.existsSync ?? import_fs.default.existsSync;
20436
+ const existsSync30 = deps.existsSync ?? import_fs.default.existsSync;
20430
20437
  const platformKey = deps.platformKey ?? currentPlatformKey();
20431
20438
  const sdkDir = deps.sdkDir !== void 0 ? deps.sdkDir : defaultSdkDir();
20432
20439
  if (!sdkDir) return null;
20433
20440
  const scopeDir = import_path4.default.dirname(sdkDir);
20434
20441
  const binName = platformKey.startsWith("win32-") ? "claude.exe" : "claude";
20435
20442
  const candidate = import_path4.default.join(scopeDir, `claude-agent-sdk-${platformKey}`, binName);
20436
- return existsSync28(candidate) ? candidate : null;
20443
+ return existsSync30(candidate) ? candidate : null;
20437
20444
  }
20438
20445
  var realSleep = (ms) => new Promise((resolve12) => setTimeout(resolve12, ms));
20439
20446
  async function waitForClaudeNativeBinary(opts = {}) {
@@ -20515,18 +20522,18 @@ function augmentUserLocalBinPaths(deps = {}) {
20515
20522
  env.PATH = [...additions, ...parts].join(p2.delimiter);
20516
20523
  }
20517
20524
  function resolveCursorAgentBinary(deps = {}) {
20518
- const existsSync28 = deps.existsSync ?? import_fs.default.existsSync;
20525
+ const existsSync30 = deps.existsSync ?? import_fs.default.existsSync;
20519
20526
  const platform3 = deps.platform ?? process.platform;
20520
20527
  const env = deps.env ?? process.env;
20521
20528
  if (platform3 === "win32") {
20522
20529
  const localAppData = env.LOCALAPPDATA;
20523
20530
  if (!localAppData) return null;
20524
20531
  const exe = import_path4.default.win32.join(localAppData, "cursor-agent", "cursor-agent.exe");
20525
- return existsSync28(exe) ? exe : null;
20532
+ return existsSync30(exe) ? exe : null;
20526
20533
  }
20527
20534
  const home = deps.homedir ?? import_os4.default.homedir();
20528
20535
  const unix = import_path4.default.posix.join(home, ".local", "bin", "cursor-agent");
20529
- return existsSync28(unix) ? unix : null;
20536
+ return existsSync30(unix) ? unix : null;
20530
20537
  }
20531
20538
  async function waitForCursorAgent(opts = {}) {
20532
20539
  const timeoutMs = opts.timeoutMs ?? 18e4;
@@ -20612,8 +20619,8 @@ var AiderRuntimeStrategy = class {
20612
20619
  meta = getAgent("aider");
20613
20620
  mode = "interactive";
20614
20621
  os;
20615
- constructor(os65) {
20616
- this.os = os65;
20622
+ constructor(os66) {
20623
+ this.os = os66;
20617
20624
  }
20618
20625
  async prepareLaunch() {
20619
20626
  augmentUserLocalBinPaths();
@@ -20746,8 +20753,8 @@ function geminiCredentialLocator() {
20746
20753
  function geminiLoginLauncher() {
20747
20754
  return {
20748
20755
  async ensureInstalled() {
20749
- const os65 = createOsStrategy();
20750
- return os65.findInPath("gemini") !== null;
20756
+ const os66 = createOsStrategy();
20757
+ return os66.findInPath("gemini") !== null;
20751
20758
  },
20752
20759
  launch() {
20753
20760
  return (0, import_node_child_process12.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
@@ -20937,8 +20944,8 @@ var GeminiRuntimeStrategy = class {
20937
20944
  meta = getAgent("gemini");
20938
20945
  mode = "interactive";
20939
20946
  os;
20940
- constructor(os65) {
20941
- this.os = os65;
20947
+ constructor(os66) {
20948
+ this.os = os66;
20942
20949
  }
20943
20950
  async prepareLaunch() {
20944
20951
  const binary = this.os.findInPath("gemini");
@@ -21230,8 +21237,8 @@ var KimiRuntimeStrategy = class {
21230
21237
  meta = getAgent("kimi");
21231
21238
  mode = "interactive";
21232
21239
  os;
21233
- constructor(os65) {
21234
- this.os = os65;
21240
+ constructor(os66) {
21241
+ this.os = os66;
21235
21242
  }
21236
21243
  async prepareLaunch() {
21237
21244
  const binary = this.os.findInPath("kimi");
@@ -21374,8 +21381,8 @@ var OpencodeRuntimeStrategy = class {
21374
21381
  meta = getAgent("opencode");
21375
21382
  mode = "interactive";
21376
21383
  os;
21377
- constructor(os65) {
21378
- this.os = os65;
21384
+ constructor(os66) {
21385
+ this.os = os66;
21379
21386
  }
21380
21387
  async prepareLaunch() {
21381
21388
  const binary = this.os.findInPath("opencode");
@@ -21460,20 +21467,20 @@ var OpencodeRuntimeStrategy = class {
21460
21467
 
21461
21468
  // src/agents/registry.ts
21462
21469
  var runtimeBuilders = {
21463
- claude: (os65) => new ClaudeRuntimeStrategy(os65),
21464
- codex: (os65) => new CodexRuntimeStrategy(os65),
21465
- coderabbit: (os65) => new CoderabbitRuntimeStrategy(os65),
21466
- cursor: (os65) => new CursorRuntimeStrategy(os65),
21467
- aider: (os65) => new AiderRuntimeStrategy(os65),
21468
- gemini: (os65) => new GeminiRuntimeStrategy(os65),
21469
- kimi: (os65) => new KimiRuntimeStrategy(os65),
21470
- opencode: (os65) => new OpencodeRuntimeStrategy(os65)
21470
+ claude: (os66) => new ClaudeRuntimeStrategy(os66),
21471
+ codex: (os66) => new CodexRuntimeStrategy(os66),
21472
+ coderabbit: (os66) => new CoderabbitRuntimeStrategy(os66),
21473
+ cursor: (os66) => new CursorRuntimeStrategy(os66),
21474
+ aider: (os66) => new AiderRuntimeStrategy(os66),
21475
+ gemini: (os66) => new GeminiRuntimeStrategy(os66),
21476
+ kimi: (os66) => new KimiRuntimeStrategy(os66),
21477
+ opencode: (os66) => new OpencodeRuntimeStrategy(os66)
21471
21478
  };
21472
21479
  var deployBuilders = {
21473
21480
  claude: () => new ClaudeDeployStrategy(),
21474
21481
  codex: () => new CodexDeployStrategy()
21475
21482
  };
21476
- function createAgentStrategy(agent, os65 = createOsStrategy()) {
21483
+ function createAgentStrategy(agent, os66 = createOsStrategy()) {
21477
21484
  if (!AGENT_REGISTRY[agent]?.enabled) {
21478
21485
  throw new Error(
21479
21486
  `Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
@@ -21483,10 +21490,10 @@ function createAgentStrategy(agent, os65 = createOsStrategy()) {
21483
21490
  if (!build) {
21484
21491
  throw new Error(`No runtime strategy registered for agent "${agent}"`);
21485
21492
  }
21486
- return build(os65);
21493
+ return build(os66);
21487
21494
  }
21488
- function createInteractiveAgentStrategy(agent, os65 = createOsStrategy()) {
21489
- const s = createAgentStrategy(agent, os65);
21495
+ function createInteractiveAgentStrategy(agent, os66 = createOsStrategy()) {
21496
+ const s = createAgentStrategy(agent, os66);
21490
21497
  if (s.mode !== "interactive") {
21491
21498
  throw new Error(
21492
21499
  `Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
@@ -22196,8 +22203,8 @@ function collectChangedFiles(cwd) {
22196
22203
  }
22197
22204
  return [...byPath.values()];
22198
22205
  }
22199
- function restoreCoderabbitOauthBlob(os65, value) {
22200
- const dir = path38.join(os65.homeDir(), ".coderabbit");
22206
+ function restoreCoderabbitOauthBlob(os66, value) {
22207
+ const dir = path38.join(os66.homeDir(), ".coderabbit");
22201
22208
  (0, import_node_fs6.mkdirSync)(dir, { recursive: true });
22202
22209
  let file = "auth.json";
22203
22210
  let contents = value.trim();
@@ -22217,26 +22224,26 @@ function installFailureMessage(result) {
22217
22224
  return result.error ?? "CodeRabbit CLI could not be installed";
22218
22225
  }
22219
22226
  async function configureCoderabbit(input, deps = {}) {
22220
- const os65 = deps.os ?? createOsStrategy();
22227
+ const os66 = deps.os ?? createOsStrategy();
22221
22228
  const ensureInstalled = deps.ensureInstalled ?? ensureCoderabbitInstalled;
22222
22229
  const isLoggedIn = deps.isLoggedIn ?? defaultIsLoggedIn;
22223
22230
  const runOAuth = deps.runOAuthLogin ?? runCoderabbitOAuthLogin;
22224
22231
  const snapshot = deps.snapshotDir ?? (() => snapshotCredentialDir());
22225
22232
  const capture2 = deps.captureCredential ?? ((b) => diffCapturedCredential(b));
22226
22233
  const loginWithApiKey = deps.loginWithApiKey ?? defaultLoginWithApiKey;
22227
- const home = os65.homeDir();
22228
- os65.augmentPath(
22229
- os65.id === "win32" ? [
22234
+ const home = os66.homeDir();
22235
+ os66.augmentPath(
22236
+ os66.id === "win32" ? [
22230
22237
  path38.join(home, ".local", "bin"),
22231
22238
  path38.join(process.env.APPDATA ?? path38.join(home, "AppData", "Roaming"), "npm"),
22232
22239
  path38.join(home, "scoop", "shims")
22233
22240
  ] : [path38.join(home, ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin"]
22234
22241
  );
22235
- const installed2 = os65.findInPath("coderabbit") !== null;
22242
+ const installed2 = os66.findInPath("coderabbit") !== null;
22236
22243
  const base = () => ({
22237
22244
  action: input.action,
22238
22245
  supported: true,
22239
- installed: os65.findInPath("coderabbit") !== null,
22246
+ installed: os66.findInPath("coderabbit") !== null,
22240
22247
  loggedIn: false
22241
22248
  });
22242
22249
  if (input.action === "status") {
@@ -22250,7 +22257,7 @@ async function configureCoderabbit(input, deps = {}) {
22250
22257
  const key = (input.apiKey ?? "").trim();
22251
22258
  if (!key) return { ...res2, error: "No API key provided" };
22252
22259
  if (!res2.installed) {
22253
- const inst = await ensureInstalled(os65);
22260
+ const inst = await ensureInstalled(os66);
22254
22261
  res2.installed = inst.ok;
22255
22262
  if (!inst.ok) return { ...res2, error: installFailureMessage(inst) };
22256
22263
  }
@@ -22274,7 +22281,7 @@ async function configureCoderabbit(input, deps = {}) {
22274
22281
  }
22275
22282
  if (!res2.installed) {
22276
22283
  deps.onEvent?.({ kind: "installing" });
22277
- const inst = await ensureInstalled(os65);
22284
+ const inst = await ensureInstalled(os66);
22278
22285
  res2.installed = inst.ok;
22279
22286
  if (!inst.ok) return { ...res2, error: installFailureMessage(inst) };
22280
22287
  }
@@ -22291,7 +22298,7 @@ async function configureCoderabbit(input, deps = {}) {
22291
22298
  return { ...res2, loggedIn: true, linked: true };
22292
22299
  }
22293
22300
  try {
22294
- restoreCoderabbitOauthBlob(os65, cred.credential);
22301
+ restoreCoderabbitOauthBlob(os66, cred.credential);
22295
22302
  } catch (err) {
22296
22303
  return {
22297
22304
  ...res2,
@@ -22315,7 +22322,7 @@ async function configureCoderabbit(input, deps = {}) {
22315
22322
  const res2 = base();
22316
22323
  if (!installed2) {
22317
22324
  deps.onEvent?.({ kind: "installing" });
22318
- const inst = await ensureInstalled(os65);
22325
+ const inst = await ensureInstalled(os66);
22319
22326
  res2.installed = inst.ok;
22320
22327
  if (!inst.ok) return { ...res2, error: installFailureMessage(inst) };
22321
22328
  }
@@ -22355,7 +22362,7 @@ async function configureCoderabbit(input, deps = {}) {
22355
22362
  }
22356
22363
  const res = base();
22357
22364
  if (!res.installed) {
22358
- const inst = await ensureInstalled(os65);
22365
+ const inst = await ensureInstalled(os66);
22359
22366
  res.installed = inst.ok;
22360
22367
  if (!inst.ok) return { ...res, error: installFailureMessage(inst) };
22361
22368
  }
@@ -24628,6 +24635,145 @@ function inspectorClientSource(opts) {
24628
24635
  redrawMarks();
24629
24636
  }
24630
24637
 
24638
+ /**
24639
+ * Las marcas del AGENTE \u2014 la herramienta highlight_element.
24640
+ *
24641
+ * Van aparte de las del usuario a proposito: no se numeran, no se pueden
24642
+ * borrar desde el composer y no dependen de que el modo inspector este
24643
+ * encendido. Son el agente SE\xD1ALANDO algo, y el usuario las ve aunque no
24644
+ * haya tocado nada: un cursor que viaja hasta el elemento, lo centra en
24645
+ * pantalla y deja una caja con su etiqueta.
24646
+ *
24647
+ * Mismo anclaje que las marcas fijadas (coordenadas de documento), asi que
24648
+ * acompa\xF1an al scroll. Un selector que no encuentra nada no pinta nada: el
24649
+ * agente ya sabe por la herramienta que puede fallar.
24650
+ */
24651
+ var AGENT = '#22d3ee';
24652
+ var agentMarks = [];
24653
+ var agentHost = null;
24654
+ var agentCursor = null;
24655
+ var agentStyle = null;
24656
+ var agentListening = false;
24657
+
24658
+ function ensureAgentStyle() {
24659
+ if (agentStyle && agentStyle.parentNode) return;
24660
+ agentStyle = document.createElement('style');
24661
+ agentStyle.setAttribute('data-codeam', 'agent-style');
24662
+ agentStyle.textContent =
24663
+ '@keyframes codeam-agent-pulse{0%{box-shadow:0 0 0 0 rgba(34,211,238,.55)}' +
24664
+ '70%{box-shadow:0 0 0 10px rgba(34,211,238,0)}100%{box-shadow:0 0 0 0 rgba(34,211,238,0)}}' +
24665
+ '@keyframes codeam-agent-in{from{opacity:0;transform:scale(1.06)}to{opacity:1;transform:scale(1)}}';
24666
+ (document.head || document.documentElement).appendChild(agentStyle);
24667
+ }
24668
+
24669
+ function ensureAgentCursor() {
24670
+ if (agentCursor && agentCursor.parentNode) return agentCursor;
24671
+ agentCursor = document.createElement('div');
24672
+ agentCursor.setAttribute('data-codeam', 'agent-cursor');
24673
+ agentCursor.style.cssText = [
24674
+ 'position:fixed', 'pointer-events:none', 'z-index:2147483647',
24675
+ 'left:' + Math.round(window.innerWidth / 2) + 'px', 'top:' + Math.round(window.innerHeight - 40) + 'px',
24676
+ 'transition:left .6s cubic-bezier(.22,1,.36,1),top .6s cubic-bezier(.22,1,.36,1),opacity .3s',
24677
+ 'opacity:0'
24678
+ ].join(';');
24679
+ agentCursor.innerHTML =
24680
+ '<svg width="22" height="22" viewBox="0 0 24 24" style="display:block;filter:drop-shadow(0 1px 2px rgba(0,0,0,.5))">' +
24681
+ '<path d="M4 2l15 8.5-6.6 1.6L9 18.5z" fill="' + AGENT + '" stroke="#000" stroke-width="1.2"/></svg>' +
24682
+ '<div style="margin:2px 0 0 14px;background:' + AGENT + ';color:#000;font:700 10px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;' +
24683
+ 'padding:1px 6px;border-radius:8px;white-space:nowrap">Agent</div>';
24684
+ document.body.appendChild(agentCursor);
24685
+ return agentCursor;
24686
+ }
24687
+
24688
+ function redrawAgentMarks() {
24689
+ if (agentMarks.length === 0) {
24690
+ if (agentHost && agentHost.parentNode) agentHost.parentNode.removeChild(agentHost);
24691
+ agentHost = null;
24692
+ return;
24693
+ }
24694
+ if (!agentHost || !agentHost.parentNode) {
24695
+ agentHost = document.createElement('div');
24696
+ agentHost.setAttribute('data-codeam', 'agent-marks');
24697
+ agentHost.style.cssText = 'position:absolute;left:0;top:0;width:0;height:0;z-index:2147483646';
24698
+ document.body.appendChild(agentHost);
24699
+ }
24700
+ agentHost.innerHTML = '';
24701
+ var sx = window.scrollX || window.pageXOffset || 0;
24702
+ var sy = window.scrollY || window.pageYOffset || 0;
24703
+ for (var i = 0; i < agentMarks.length; i++) {
24704
+ var m = agentMarks[i];
24705
+ if (!m.el.isConnected) continue;
24706
+ var r = m.el.getBoundingClientRect();
24707
+ var box = document.createElement('div');
24708
+ box.setAttribute('data-codeam', 'agent-mark');
24709
+ box.style.cssText = [
24710
+ 'position:absolute', 'pointer-events:none', 'box-sizing:border-box',
24711
+ 'border:2px solid ' + AGENT, 'background:rgba(34,211,238,0.10)', 'border-radius:4px',
24712
+ 'left:' + (r.left + sx - 3) + 'px', 'top:' + (r.top + sy - 3) + 'px',
24713
+ 'width:' + (r.width + 6) + 'px', 'height:' + (r.height + 6) + 'px',
24714
+ 'animation:codeam-agent-in .25s ease-out,codeam-agent-pulse 1.6s ease-out 3'
24715
+ ].join(';');
24716
+ if (m.label) {
24717
+ var tag = document.createElement('div');
24718
+ tag.setAttribute('data-codeam', 'agent-mark-label');
24719
+ tag.style.cssText = [
24720
+ 'position:absolute', 'left:-2px', (r.top >= 22 ? 'top:-22px' : 'bottom:-22px'),
24721
+ 'background:' + AGENT, 'color:#000', 'font:700 11px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace',
24722
+ 'padding:0 6px', 'border-radius:3px', 'white-space:nowrap', 'max-width:260px',
24723
+ 'overflow:hidden', 'text-overflow:ellipsis'
24724
+ ].join(';');
24725
+ tag.textContent = m.label;
24726
+ box.appendChild(tag);
24727
+ }
24728
+ agentHost.appendChild(box);
24729
+ }
24730
+ }
24731
+
24732
+ function listenAgentLayout() {
24733
+ if (agentListening) return;
24734
+ agentListening = true;
24735
+ window.addEventListener('scroll', redrawAgentMarks, true);
24736
+ window.addEventListener('resize', redrawAgentMarks);
24737
+ }
24738
+
24739
+ function agentHighlight(selector, labelText) {
24740
+ var el = null;
24741
+ try { el = document.querySelector(String(selector)); } catch (e) { el = null; }
24742
+ if (!el || !el.getBoundingClientRect) return false;
24743
+ ensureAgentStyle();
24744
+ listenAgentLayout();
24745
+ try { el.scrollIntoView({ block: 'center', inline: 'nearest', behavior: 'smooth' }); } catch (e) { /* viejo */ }
24746
+ var cursor = ensureAgentCursor();
24747
+ // Tras el scroll suave: el cursor viaja al centro del elemento y, al
24748
+ // llegar, aparece la caja. El orden es lo que se lee como \xABel agente
24749
+ // lo esta se\xF1alando\xBB y no como un recuadro que salta.
24750
+ setTimeout(function () {
24751
+ var r = el.getBoundingClientRect();
24752
+ cursor.style.opacity = '1';
24753
+ cursor.style.left = Math.round(r.left + Math.min(r.width / 2, 40)) + 'px';
24754
+ cursor.style.top = Math.round(r.top + Math.min(r.height / 2, 24)) + 'px';
24755
+ setTimeout(function () {
24756
+ agentMarks.push({ el: el, label: labelText ? String(labelText).slice(0, 80) : '' });
24757
+ redrawAgentMarks();
24758
+ }, 620);
24759
+ }, 380);
24760
+ return true;
24761
+ }
24762
+
24763
+ function agentClear() {
24764
+ agentMarks = [];
24765
+ redrawAgentMarks();
24766
+ if (agentCursor && agentCursor.parentNode) agentCursor.parentNode.removeChild(agentCursor);
24767
+ agentCursor = null;
24768
+ if (agentStyle && agentStyle.parentNode) agentStyle.parentNode.removeChild(agentStyle);
24769
+ agentStyle = null;
24770
+ if (agentListening) {
24771
+ window.removeEventListener('scroll', redrawAgentMarks, true);
24772
+ window.removeEventListener('resize', redrawAgentMarks);
24773
+ agentListening = false;
24774
+ }
24775
+ }
24776
+
24631
24777
  function enable(origin) {
24632
24778
  if (enabled) return;
24633
24779
  enabled = true;
@@ -24661,6 +24807,8 @@ function inspectorClientSource(opts) {
24661
24807
  if (data.type === 'enable') enable(e.origin);
24662
24808
  else if (data.type === 'disable') disable();
24663
24809
  else if (data.type === 'marks' && data.ids) syncMarks(data.ids);
24810
+ else if (data.type === 'agent-highlight' && data.selector) agentHighlight(data.selector, data.label);
24811
+ else if (data.type === 'agent-clear') agentClear();
24664
24812
  });
24665
24813
 
24666
24814
  /**
@@ -24679,6 +24827,11 @@ function inspectorClientSource(opts) {
24679
24827
  window.__codeamInspector = {
24680
24828
  enable: function () { enable('react-native'); },
24681
24829
  disable: disable,
24830
+ // La app movil ya llamaba \`marks\` al borrar un chip y no existia:
24831
+ // la marca se quedaba pintada en la pagina.
24832
+ marks: function (ids) { if (ids && ids.length !== undefined) syncMarks(ids); },
24833
+ highlight: function (selector, text) { return agentHighlight(selector, text); },
24834
+ clear: agentClear,
24682
24835
  };
24683
24836
  }
24684
24837
  } catch (e) {
@@ -25518,11 +25671,11 @@ function resolveDoltInstallStrategy(platform3) {
25518
25671
  }
25519
25672
  var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
25520
25673
  function doltPlatformTuple(platform3, arch2) {
25521
- const os65 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
25674
+ const os66 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
25522
25675
  const a = arch2 === "x64" ? "amd64" : arch2 === "arm64" ? "arm64" : null;
25523
25676
  if (!a) return null;
25524
- if (os65 === "windows" && a !== "amd64") return null;
25525
- return `${os65}-${a}`;
25677
+ if (os66 === "windows" && a !== "amd64") return null;
25678
+ return `${os66}-${a}`;
25526
25679
  }
25527
25680
  function resolveDoltTarballStrategy(targetDir, platform3, arch2) {
25528
25681
  const tuple = doltPlatformTuple(platform3, arch2);
@@ -26518,9 +26671,9 @@ async function configureBeads(action, ctx, deps) {
26518
26671
  return { enabled: false, running: false };
26519
26672
  }
26520
26673
  const p3 = await deps.probe();
26521
- const running2 = p3.serverUp && p3.bdAvailable;
26522
- deps.emit({ type: "beads_status", state: running2 ? "enabled" : "disabled", running: running2, ...p3 });
26523
- return { enabled: running2, running: running2, ...p3 };
26674
+ const running3 = p3.serverUp && p3.bdAvailable;
26675
+ deps.emit({ type: "beads_status", state: running3 ? "enabled" : "disabled", running: running3, ...p3 });
26676
+ return { enabled: running3, running: running3, ...p3 };
26524
26677
  }
26525
26678
  if (action === "disable") {
26526
26679
  deps.persist({ enabled: false });
@@ -26537,9 +26690,9 @@ async function configureBeads(action, ctx, deps) {
26537
26690
  return { enabled: false, ...p2 };
26538
26691
  }
26539
26692
  await deps.startWatcher().catch(() => void 0);
26540
- const running = true;
26541
- deps.emit({ type: "beads_status", state: "enabled", running, ...p2 });
26542
- return { enabled: true, running, ...p2 };
26693
+ const running2 = true;
26694
+ deps.emit({ type: "beads_status", state: "enabled", running: running2, ...p2 });
26695
+ return { enabled: true, running: running2, ...p2 };
26543
26696
  }
26544
26697
 
26545
26698
  // src/skills/configure.ts
@@ -27211,7 +27364,7 @@ var vcsAgentReviewH = async (ctx, cmd, parsed) => {
27211
27364
  });
27212
27365
  const token = ctx.pluginAuthToken;
27213
27366
  void (async () => {
27214
- const os65 = createOsStrategy();
27367
+ const os66 = createOsStrategy();
27215
27368
  try {
27216
27369
  const report = await reviewPullRequest(
27217
27370
  {
@@ -27220,7 +27373,7 @@ var vcsAgentReviewH = async (ctx, cmd, parsed) => {
27220
27373
  baseBranch: parsed.baseBranch
27221
27374
  },
27222
27375
  {
27223
- runReview: (input) => new CoderabbitRuntimeStrategy(os65).runOneShot(input),
27376
+ runReview: (input) => new CoderabbitRuntimeStrategy(os66).runOneShot(input),
27224
27377
  runGh: (args2) => defaultRunGh(args2),
27225
27378
  postReport: async (r) => {
27226
27379
  if (!token) return;
@@ -27358,13 +27511,13 @@ function resolveGlobalNodeModulesDir(opts) {
27358
27511
  var STALE_STAGING_AGE_MS = CLI_UPDATE_INSTALL_TIMEOUT_MS;
27359
27512
  function sweepStaleCliStagingDirs(nodeModulesDir, now = Date.now(), deps) {
27360
27513
  if (!nodeModulesDir) return 0;
27361
- const readdirSync13 = deps?.readdirSync ?? fs51.readdirSync;
27514
+ const readdirSync14 = deps?.readdirSync ?? fs51.readdirSync;
27362
27515
  const statSync15 = deps?.statSync ?? fs51.statSync;
27363
27516
  const rmSync9 = deps?.rmSync ?? fs51.rmSync;
27364
27517
  let removed = 0;
27365
27518
  let entries;
27366
27519
  try {
27367
- entries = readdirSync13(nodeModulesDir);
27520
+ entries = readdirSync14(nodeModulesDir);
27368
27521
  } catch {
27369
27522
  return 0;
27370
27523
  }
@@ -27759,105 +27912,88 @@ async function runDetectOneShot(generate, timeoutMs = PREVIEW_DETECT_TIMEOUT_MS)
27759
27912
  if (timer) clearTimeout(timer);
27760
27913
  }
27761
27914
  }
27762
- var requestPreviewDetectH = (ctx) => {
27763
- if (!ctx.pluginAuthToken) {
27764
- log.info("preview", "no pluginAuthToken \u2014 skipping detect");
27765
- return;
27766
- }
27767
- if (typeof ctx.runtime.generateOneShot !== "function") {
27768
- log.info("preview", `runtime ${ctx.runtime.id} has no generateOneShot \u2014 emitting unsupported`);
27915
+ function originPayload(payload, origin) {
27916
+ if (origin !== "agent") return payload;
27917
+ return { ...payload ?? {}, origin };
27918
+ }
27919
+ async function resolvePreviewDetection(args2) {
27920
+ const { ctx, runtime, pluginAuthToken, origin } = args2;
27921
+ const emit2 = (type, payload) => {
27769
27922
  emitPreviewEvent({
27770
27923
  sessionId: ctx.sessionId,
27771
27924
  pluginId: ctx.pluginId,
27772
- pluginAuthToken: ctx.pluginAuthToken,
27773
- type: USER_EVENTS.PREVIEW_ERROR,
27774
- payload: {
27775
- stage: "detection",
27776
- message: `Preview detection isn't available on ${ctx.runtime.id} sessions yet \u2014 link a Claude or Codex agent.`
27777
- }
27925
+ pluginAuthToken,
27926
+ type,
27927
+ payload: originPayload(payload, origin)
27778
27928
  });
27779
- return;
27929
+ };
27930
+ if (typeof runtime.generateOneShot !== "function") {
27931
+ log.info("preview", `runtime ${runtime.id} has no generateOneShot \u2014 emitting unsupported`);
27932
+ emit2(USER_EVENTS.PREVIEW_ERROR, {
27933
+ stage: "detection",
27934
+ message: `Preview detection isn't available on ${runtime.id} sessions yet \u2014 link a Claude or Codex agent.`
27935
+ });
27936
+ return null;
27780
27937
  }
27781
- const pluginAuthToken = ctx.pluginAuthToken;
27782
- const generateOneShot = ctx.runtime.generateOneShot.bind(ctx.runtime);
27783
- void (async () => {
27784
- const fromFile = await readPreviewConfig(process.cwd());
27785
- if (fromFile) {
27786
- log.info("preview", `detect: using .codeam/preview.json (${fromFile.framework})`);
27787
- emitPreviewEvent({
27788
- sessionId: ctx.sessionId,
27789
- pluginId: ctx.pluginId,
27790
- pluginAuthToken,
27791
- type: USER_EVENTS.PREVIEW_DETECTION_READY,
27792
- payload: { detection: withScriptCandidates(fromFile) }
27793
- });
27794
- return;
27795
- }
27796
- emitPreviewEvent({
27797
- sessionId: ctx.sessionId,
27798
- pluginId: ctx.pluginId,
27799
- pluginAuthToken,
27800
- type: USER_EVENTS.PREVIEW_DETECTION_PENDING
27938
+ const generateOneShot = runtime.generateOneShot.bind(runtime);
27939
+ const fromFile = await readPreviewConfig(process.cwd());
27940
+ if (fromFile) {
27941
+ log.info("preview", `detect: using .codeam/preview.json (${fromFile.framework})`);
27942
+ return fromFile;
27943
+ }
27944
+ emit2(USER_EVENTS.PREVIEW_DETECTION_PENDING);
27945
+ log.info("preview", "detect: invoking generateOneShot");
27946
+ const startedAt = Date.now();
27947
+ const { raw, timedOut, stderr } = await runDetectOneShot(generateOneShot);
27948
+ const tookMs = Date.now() - startedAt;
27949
+ if (timedOut) {
27950
+ log.info("preview", `detect: timed out after ${tookMs}ms \u2014 emitting preview_error`);
27951
+ emit2(USER_EVENTS.PREVIEW_ERROR, {
27952
+ stage: "detection",
27953
+ message: `Project detection timed out after ${Math.round(PREVIEW_DETECT_TIMEOUT_MS / 1e3)} s \u2014 the agent did not answer. Try again, or add a .codeam/preview.json override.`
27801
27954
  });
27802
- log.info("preview", "detect: invoking generateOneShot");
27803
- const startedAt = Date.now();
27804
- const { raw, timedOut, stderr } = await runDetectOneShot(generateOneShot);
27805
- const tookMs = Date.now() - startedAt;
27806
- if (timedOut) {
27807
- log.info("preview", `detect: timed out after ${tookMs}ms \u2014 emitting preview_error`);
27808
- emitPreviewEvent({
27809
- sessionId: ctx.sessionId,
27810
- pluginId: ctx.pluginId,
27811
- pluginAuthToken,
27812
- type: USER_EVENTS.PREVIEW_ERROR,
27813
- payload: {
27814
- stage: "detection",
27815
- message: `Project detection timed out after ${Math.round(PREVIEW_DETECT_TIMEOUT_MS / 1e3)} s \u2014 the agent did not answer. Try again, or add a .codeam/preview.json override.`
27816
- }
27817
- });
27818
- return;
27819
- }
27820
- const detection = safeParseDetection(raw);
27821
- if (!detection) {
27822
- const failure = describeDetectionFailure(raw);
27823
- log.info(
27824
- "preview",
27825
- `detect: failed after ${tookMs}ms reason=${failure?.reason ?? "unknown"}` + (failure?.missing ? ` missing=${failure.missing.join(",")}` : "") + `
27955
+ return null;
27956
+ }
27957
+ const detection = safeParseDetection(raw);
27958
+ if (!detection) {
27959
+ const failure = describeDetectionFailure(raw);
27960
+ log.info(
27961
+ "preview",
27962
+ `detect: failed after ${tookMs}ms reason=${failure?.reason ?? "unknown"}` + (failure?.missing ? ` missing=${failure.missing.join(",")}` : "") + `
27826
27963
  --- salida cruda del agente (acotada) ---
27827
27964
  ${failure?.rawExcerpt ?? ""}`
27828
- );
27829
- emitPreviewEvent({
27830
- sessionId: ctx.sessionId,
27831
- pluginId: ctx.pluginId,
27832
- pluginAuthToken,
27833
- type: USER_EVENTS.PREVIEW_ERROR,
27834
- payload: {
27835
- stage: "detection",
27836
- // El mensaje sale del diagnostico: decir "JSON invalido" cuando el
27837
- // agente no contesto manda al usuario a mirar un JSON que no existe.
27838
- message: (failure?.reason === "no_output" ? describeOneShotAgentError(stderr) : null) ?? failure?.message ?? "Agent returned invalid JSON. Try again, or add a .codeam/preview.json override."
27839
- }
27840
- });
27841
- return;
27842
- }
27843
- if (isUnsupportedDetection(detection)) {
27844
- log.info("preview", "detect: framework=unsupported");
27845
- emitPreviewEvent({
27846
- sessionId: ctx.sessionId,
27847
- pluginId: ctx.pluginId,
27848
- pluginAuthToken,
27849
- type: USER_EVENTS.PREVIEW_ERROR,
27850
- payload: {
27851
- stage: "unsupported",
27852
- message: detection.notes ?? "No dev server applies to this project."
27853
- }
27854
- });
27855
- return;
27856
- }
27857
- log.info("preview", `detect: ${detection.framework} on :${detection.port} (took ${tookMs}ms)`);
27858
- void writePreviewConfig(process.cwd(), detection).catch((err) => {
27859
- log.info("preview", `detect: writePreviewConfig failed (non-fatal): ${String(err)}`);
27965
+ );
27966
+ emit2(USER_EVENTS.PREVIEW_ERROR, {
27967
+ stage: "detection",
27968
+ // El mensaje sale del diagnostico: decir "JSON invalido" cuando el
27969
+ // agente no contesto manda al usuario a mirar un JSON que no existe.
27970
+ message: (failure?.reason === "no_output" ? describeOneShotAgentError(stderr) : null) ?? failure?.message ?? "Agent returned invalid JSON. Try again, or add a .codeam/preview.json override."
27971
+ });
27972
+ return null;
27973
+ }
27974
+ if (isUnsupportedDetection(detection)) {
27975
+ log.info("preview", "detect: framework=unsupported");
27976
+ emit2(USER_EVENTS.PREVIEW_ERROR, {
27977
+ stage: "unsupported",
27978
+ message: detection.notes ?? "No dev server applies to this project."
27860
27979
  });
27980
+ return null;
27981
+ }
27982
+ log.info("preview", `detect: ${detection.framework} on :${detection.port} (took ${tookMs}ms)`);
27983
+ void writePreviewConfig(process.cwd(), detection).catch((err) => {
27984
+ log.info("preview", `detect: writePreviewConfig failed (non-fatal): ${String(err)}`);
27985
+ });
27986
+ return detection;
27987
+ }
27988
+ var requestPreviewDetectH = (ctx) => {
27989
+ if (!ctx.pluginAuthToken) {
27990
+ log.info("preview", "no pluginAuthToken \u2014 skipping detect");
27991
+ return;
27992
+ }
27993
+ const pluginAuthToken = ctx.pluginAuthToken;
27994
+ void (async () => {
27995
+ const detection = await resolvePreviewDetection({ ctx, runtime: ctx.runtime, pluginAuthToken });
27996
+ if (!detection) return;
27861
27997
  emitPreviewEvent({
27862
27998
  sessionId: ctx.sessionId,
27863
27999
  pluginId: ctx.pluginId,
@@ -27940,19 +28076,21 @@ var previewStartH = (ctx, _cmd, parsed) => {
27940
28076
  log.info("preview", "start: no detection in payload");
27941
28077
  return;
27942
28078
  }
27943
- startPreviewFromDetection(ctx, rawDetection, ctx.pluginAuthToken);
28079
+ void startPreviewFromDetection(ctx, rawDetection, ctx.pluginAuthToken);
27944
28080
  };
27945
- function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
28081
+ function startPreviewFromDetection(ctx, detection, pluginAuthToken, opts = {}) {
27946
28082
  const emit2 = (type, payload) => {
28083
+ const tagged = originPayload(payload, opts.origin) ?? {};
28084
+ opts.onEvent?.(type, tagged);
27947
28085
  emitPreviewEvent({
27948
28086
  sessionId: ctx.sessionId,
27949
28087
  pluginId: ctx.pluginId,
27950
28088
  pluginAuthToken,
27951
28089
  type,
27952
- payload
28090
+ payload: tagged
27953
28091
  });
27954
28092
  };
27955
- runPreviewStart({
28093
+ return runPreviewStart({
27956
28094
  sessionId: ctx.sessionId,
27957
28095
  detection,
27958
28096
  cwd: process.cwd(),
@@ -27983,7 +28121,7 @@ function maybeAttachBuildHeal(ctx, pluginAuthToken) {
27983
28121
  if (!activePreviews.has(ctx.sessionId)) return;
27984
28122
  await killPreview(ctx.sessionId);
27985
28123
  await new Promise((r) => setTimeout(r, 150));
27986
- startPreviewFromDetection(ctx, preview.detection, pluginAuthToken);
28124
+ void startPreviewFromDetection(ctx, preview.detection, pluginAuthToken);
27987
28125
  })();
27988
28126
  },
27989
28127
  notify: (message) => {
@@ -28029,7 +28167,7 @@ var previewRestartH = async (ctx, cmd) => {
28029
28167
  }
28030
28168
  await killPreview(ctx.sessionId);
28031
28169
  await new Promise((r) => setTimeout(r, 150));
28032
- startPreviewFromDetection(ctx, preview.detection, ctx.pluginAuthToken);
28170
+ void startPreviewFromDetection(ctx, preview.detection, ctx.pluginAuthToken);
28033
28171
  await ctx.relay.sendResult(cmd.id, "completed", { restarted: true });
28034
28172
  };
28035
28173
  var savePreviewConfigH = (_ctx, _cmd, parsed) => {
@@ -28402,11 +28540,11 @@ function resolveTokenValue(args2) {
28402
28540
  }
28403
28541
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
28404
28542
  if (fileFlag) {
28405
- const path96 = fileFlag.slice("--token-file=".length);
28543
+ const path97 = fileFlag.slice("--token-file=".length);
28406
28544
  try {
28407
- const content = fs52.readFileSync(path96, "utf8").trim();
28408
- if (content.length === 0) fail(`--token-file ${path96} is empty`);
28409
- rmIfExistsQuiet(path96);
28545
+ const content = fs52.readFileSync(path97, "utf8").trim();
28546
+ if (content.length === 0) fail(`--token-file ${path97} is empty`);
28547
+ rmIfExistsQuiet(path97);
28410
28548
  return content;
28411
28549
  } catch (err) {
28412
28550
  fail(`Could not read --token-file: ${err.message}`);
@@ -29338,32 +29476,200 @@ async function resolveAcpAdapterWithRetry(agent, opts = {}) {
29338
29476
  return null;
29339
29477
  }
29340
29478
 
29479
+ // src/commands/host/workspace.ts
29480
+ var fs53 = __toESM(require("fs"));
29481
+ var os41 = __toESM(require("os"));
29482
+ var path62 = __toESM(require("path"));
29483
+ var import_node_child_process21 = require("child_process");
29484
+ var import_node_util5 = require("util");
29485
+ var execFileP5 = (0, import_node_util5.promisify)(import_node_child_process21.execFile);
29486
+ function isAbsolutePathTarget(target) {
29487
+ return path62.isAbsolute(target);
29488
+ }
29489
+ function selfHostedWorkspaceRoot() {
29490
+ return path62.join(os41.homedir(), ".codeam", "self-hosted");
29491
+ }
29492
+ function deployIdFromWorkspace(cwd) {
29493
+ if (!cwd) return null;
29494
+ const root = selfHostedWorkspaceRoot();
29495
+ const resolved = path62.resolve(cwd);
29496
+ const rel = path62.relative(root, resolved);
29497
+ if (!rel || rel.startsWith("..") || path62.isAbsolute(rel)) return null;
29498
+ const parts = rel.split(path62.sep).filter(Boolean);
29499
+ if (parts.length !== 1) return null;
29500
+ return parts[0];
29501
+ }
29502
+ function nonInteractiveGitEnv() {
29503
+ return {
29504
+ ...process.env,
29505
+ GIT_TERMINAL_PROMPT: "0",
29506
+ GIT_ASKPASS: "",
29507
+ GCM_INTERACTIVE: "never"
29508
+ };
29509
+ }
29510
+ function githubOwnerRepo(repoRef) {
29511
+ const trimmed = repoRef.trim();
29512
+ const shorthand = /^([^/\s]+)\/([^/\s]+?)(?:\.git)?$/.exec(trimmed);
29513
+ if (shorthand && !/^https?:\/\//.test(trimmed) && !trimmed.startsWith("git@")) {
29514
+ return { owner: shorthand[1], repo: shorthand[2] };
29515
+ }
29516
+ const httpsMatch = /^https?:\/\/github\.com\/([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/.exec(trimmed);
29517
+ if (httpsMatch) return { owner: httpsMatch[1], repo: httpsMatch[2] };
29518
+ return null;
29519
+ }
29520
+ function gitlabProjectPath(repoRef) {
29521
+ const trimmed = repoRef.trim();
29522
+ const https9 = /^https?:\/\/gitlab\.com\/(.+?)(?:\.git)?\/?$/.exec(trimmed);
29523
+ if (https9) return https9[1];
29524
+ if (!/^https?:\/\//.test(trimmed) && !trimmed.startsWith("git@") && trimmed.includes("/")) {
29525
+ return trimmed.replace(/\.git$/, "");
29526
+ }
29527
+ return null;
29528
+ }
29529
+ function repoCloneUrl(repoRef, cloneToken, provider = "github") {
29530
+ const trimmed = repoRef.trim();
29531
+ if (provider === "gitlab") {
29532
+ const glPath = gitlabProjectPath(trimmed);
29533
+ if (glPath) {
29534
+ return cloneToken ? `https://oauth2:${cloneToken}@gitlab.com/${glPath}.git` : `https://gitlab.com/${glPath}.git`;
29535
+ }
29536
+ if (/^https?:\/\//.test(trimmed) || trimmed.startsWith("git@")) return trimmed;
29537
+ }
29538
+ if (cloneToken) {
29539
+ const gh = githubOwnerRepo(trimmed);
29540
+ if (gh) {
29541
+ return `https://x-access-token:${cloneToken}@github.com/${gh.owner}/${gh.repo}.git`;
29542
+ }
29543
+ }
29544
+ if (/^https?:\/\//.test(trimmed) || trimmed.startsWith("git@")) return trimmed;
29545
+ return `https://github.com/${trimmed.replace(/\.git$/, "")}.git`;
29546
+ }
29547
+ function maskCloneUrl(url2) {
29548
+ return url2.replace(/(https?:\/\/)[^@/]+@/, "$1***@");
29549
+ }
29550
+ async function fetchGithubIdentity(token) {
29551
+ try {
29552
+ const res = await fetch("https://api.github.com/user", {
29553
+ headers: {
29554
+ Authorization: `Bearer ${token}`,
29555
+ "User-Agent": "codeam-cli",
29556
+ Accept: "application/vnd.github+json"
29557
+ }
29558
+ });
29559
+ if (!res.ok) return null;
29560
+ const body = await res.json();
29561
+ return { login: body.login, email: body.email ?? void 0 };
29562
+ } catch {
29563
+ return null;
29564
+ }
29565
+ }
29566
+ async function configureGitCredentials(dest, repoRef, cloneToken, provider = "github") {
29567
+ const isGitlab = provider === "gitlab";
29568
+ if (isGitlab ? !gitlabProjectPath(repoRef.trim()) : !githubOwnerRepo(repoRef.trim())) return;
29569
+ if (!cloneToken) return;
29570
+ const credFile = path62.join(dest, ".git", "codeam-credentials");
29571
+ const credLine = isGitlab ? `https://oauth2:${cloneToken}@gitlab.com
29572
+ ` : `https://x-access-token:${cloneToken}@github.com
29573
+ `;
29574
+ fs53.writeFileSync(credFile, credLine, { mode: 384 });
29575
+ restrictToOwner(credFile);
29576
+ const env = nonInteractiveGitEnv();
29577
+ const git2 = (args2) => execFileP5("git", ["-C", dest, ...args2], { timeout: 3e4, env });
29578
+ const credFilePosix = credFile.split(path62.sep).join("/");
29579
+ await git2(["config", "--local", "--replace-all", "credential.helper", ""]).catch(() => {
29580
+ });
29581
+ await git2([
29582
+ "config",
29583
+ "--local",
29584
+ "--add",
29585
+ "credential.helper",
29586
+ `store --file=${credFilePosix}`
29587
+ ]).catch(() => {
29588
+ });
29589
+ await git2(["remote", "set-url", "origin", repoCloneUrl(repoRef, void 0, provider)]).catch(() => {
29590
+ });
29591
+ const hasIdentity = await git2(["config", "user.email"]).then(() => true).catch(() => false);
29592
+ if (!hasIdentity) {
29593
+ const who = isGitlab ? null : await fetchGithubIdentity(cloneToken);
29594
+ const login = who?.login ?? "CodeAgent";
29595
+ await git2(["config", "--local", "user.name", login]).catch(() => {
29596
+ });
29597
+ const email = who?.email ?? (isGitlab ? "agent@codeagent-mobile.com" : `${login}@users.noreply.github.com`);
29598
+ await git2(["config", "--local", "user.email", email]).catch(() => {
29599
+ });
29600
+ }
29601
+ }
29602
+ function maskToken(text, cloneToken) {
29603
+ const masked = maskCloneUrl(text);
29604
+ if (cloneToken && cloneToken.length > 0) {
29605
+ return masked.split(cloneToken).join("***");
29606
+ }
29607
+ return masked;
29608
+ }
29609
+ async function prepareWorkspace(repoOrPath, deployId, cloneToken, provider = "github", branch) {
29610
+ if (isAbsolutePathTarget(repoOrPath)) {
29611
+ if (!fs53.existsSync(repoOrPath)) {
29612
+ throw new Error(`deploy target path does not exist: ${repoOrPath}`);
29613
+ }
29614
+ return repoOrPath;
29615
+ }
29616
+ const dest = path62.join(selfHostedWorkspaceRoot(), deployId);
29617
+ if (fs53.existsSync(path62.join(dest, ".git"))) {
29618
+ if (cloneToken) await configureGitCredentials(dest, repoOrPath, cloneToken, provider);
29619
+ return dest;
29620
+ }
29621
+ fs53.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
29622
+ const cloneUrl = repoCloneUrl(repoOrPath, cloneToken, provider);
29623
+ const cloneArgs = branch ? ["clone", "--depth", "1", "--branch", branch, cloneUrl, dest] : ["clone", "--depth", "1", cloneUrl, dest];
29624
+ try {
29625
+ await execFileP5("git", cloneArgs, {
29626
+ timeout: 12e4,
29627
+ maxBuffer: 16 * 1024 * 1024,
29628
+ env: nonInteractiveGitEnv()
29629
+ });
29630
+ } catch (err) {
29631
+ const reason = err instanceof Error ? err.message : String(err);
29632
+ throw new Error(`git clone failed for ${maskCloneUrl(cloneUrl)}: ${maskToken(reason, cloneToken)}`);
29633
+ }
29634
+ if (cloneToken) await configureGitCredentials(dest, repoOrPath, cloneToken, provider);
29635
+ return dest;
29636
+ }
29637
+
29341
29638
  // src/agents/acp/runner.ts
29342
- var import_node_crypto10 = require("crypto");
29343
- var fs69 = __toESM(require("fs"));
29344
- var os53 = __toESM(require("os"));
29345
- var path80 = __toESM(require("path"));
29639
+ var import_node_crypto11 = require("crypto");
29640
+ var fs71 = __toESM(require("fs"));
29641
+ var os55 = __toESM(require("os"));
29642
+ var path82 = __toESM(require("path"));
29346
29643
 
29347
29644
  // src/lib/provider-routing.ts
29645
+ var fs55 = __toESM(require("fs"));
29646
+ var os43 = __toESM(require("os"));
29647
+ var path64 = __toESM(require("path"));
29648
+
29649
+ // src/commands/host/house-proxy-config.ts
29348
29650
  var fs54 = __toESM(require("fs"));
29349
29651
  var os42 = __toESM(require("os"));
29350
29652
  var path63 = __toESM(require("path"));
29351
-
29352
- // src/commands/host/house-proxy-config.ts
29353
- var fs53 = __toESM(require("fs"));
29354
- var os41 = __toESM(require("os"));
29355
- var path62 = __toESM(require("path"));
29356
29653
  function houseProxyConfigPath() {
29357
- return path62.join(os41.homedir(), ".codeam", "house-proxy.json");
29654
+ return path63.join(os42.homedir(), ".codeam", "house-proxy.json");
29655
+ }
29656
+ var DEPLOY_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
29657
+ function deployHouseProxyConfigPath(deployId) {
29658
+ if (!DEPLOY_ID_RE.test(deployId) || deployId.includes("..")) return null;
29659
+ return path63.join(os42.homedir(), ".codeam", "house-proxy", `${deployId}.json`);
29660
+ }
29661
+ function writeJson0600(file, value) {
29662
+ fs54.mkdirSync(path63.dirname(file), { recursive: true, mode: 448 });
29663
+ const tmp = `${file}.tmp-${process.pid}`;
29664
+ fs54.writeFileSync(tmp, JSON.stringify(value, null, 2), { encoding: "utf8", mode: 384 });
29665
+ fs54.renameSync(tmp, file);
29666
+ restrictToOwner(file);
29358
29667
  }
29359
- function persistHouseProxyConfig(config) {
29668
+ function persistHouseProxyConfig(config, deployId) {
29360
29669
  try {
29361
- const file = houseProxyConfigPath();
29362
- fs53.mkdirSync(path62.dirname(file), { recursive: true, mode: 448 });
29363
- const tmp = `${file}.tmp-${process.pid}`;
29364
- fs53.writeFileSync(tmp, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
29365
- fs53.renameSync(tmp, file);
29366
- restrictToOwner(file);
29670
+ const perDeploy = deployId ? deployHouseProxyConfigPath(deployId) : null;
29671
+ if (perDeploy) writeJson0600(perDeploy, config);
29672
+ writeJson0600(houseProxyConfigPath(), config);
29367
29673
  } catch (err) {
29368
29674
  log.warn(
29369
29675
  "host-agent",
@@ -29371,18 +29677,23 @@ function persistHouseProxyConfig(config) {
29371
29677
  );
29372
29678
  }
29373
29679
  }
29374
- function clearHouseProxyConfig() {
29680
+ function clearHouseProxyConfig(deployId) {
29375
29681
  try {
29376
- fs53.rmSync(houseProxyConfigPath(), { force: true });
29682
+ fs54.rmSync(houseProxyConfigPath(), { force: true });
29683
+ const perDeploy = deployId ? deployHouseProxyConfigPath(deployId) : null;
29684
+ if (perDeploy) writeJson0600(perDeploy, { none: true });
29377
29685
  } catch {
29378
29686
  }
29379
29687
  }
29380
- function readHouseProxyChildEnv() {
29688
+ function readHouseProxyChildEnv(deployId) {
29381
29689
  try {
29382
- const raw = fs53.readFileSync(houseProxyConfigPath(), "utf8");
29690
+ const perDeploy = deployId ? deployHouseProxyConfigPath(deployId) : null;
29691
+ const file = perDeploy && fs54.existsSync(perDeploy) ? perDeploy : houseProxyConfigPath();
29692
+ const raw = fs54.readFileSync(file, "utf8");
29383
29693
  const parsed = JSON.parse(raw);
29384
29694
  if (typeof parsed !== "object" || parsed === null) return {};
29385
29695
  const o = parsed;
29696
+ if (o.none === true) return {};
29386
29697
  if (typeof o.baseUrl !== "string" || !o.baseUrl) return {};
29387
29698
  if (typeof o.token !== "string" || !o.token) return {};
29388
29699
  return buildHouseProxyChildEnv({
@@ -29505,15 +29816,15 @@ function redactUrlToOrigin(raw) {
29505
29816
  }
29506
29817
  }
29507
29818
  function readOpencodeProviderOrigins(opts = {}) {
29508
- const home = opts.homeDir ?? os42.homedir();
29509
- const readFile7 = opts.readFile ?? ((f) => fs54.readFileSync(f, "utf8"));
29819
+ const home = opts.homeDir ?? os43.homedir();
29820
+ const readFile7 = opts.readFile ?? ((f) => fs55.readFileSync(f, "utf8"));
29510
29821
  const candidates = [];
29511
29822
  if (opts.cwd) {
29512
- candidates.push(path63.join(opts.cwd, "opencode.json"), path63.join(opts.cwd, "opencode.jsonc"));
29823
+ candidates.push(path64.join(opts.cwd, "opencode.json"), path64.join(opts.cwd, "opencode.jsonc"));
29513
29824
  }
29514
29825
  candidates.push(
29515
- path63.join(home, ".config", "opencode", "opencode.json"),
29516
- path63.join(home, ".config", "opencode", "opencode.jsonc")
29826
+ path64.join(home, ".config", "opencode", "opencode.json"),
29827
+ path64.join(home, ".config", "opencode", "opencode.jsonc")
29517
29828
  );
29518
29829
  const out2 = [];
29519
29830
  const seen2 = /* @__PURE__ */ new Set();
@@ -29620,9 +29931,9 @@ function noteProviderBillingSignal(opts) {
29620
29931
  }
29621
29932
 
29622
29933
  // src/services/history.service.ts
29623
- var fs55 = __toESM(require("fs"));
29624
- var path64 = __toESM(require("path"));
29625
- var os43 = __toESM(require("os"));
29934
+ var fs56 = __toESM(require("fs"));
29935
+ var path65 = __toESM(require("path"));
29936
+ var os44 = __toESM(require("os"));
29626
29937
  var https6 = __toESM(require("https"));
29627
29938
  var http9 = __toESM(require("http"));
29628
29939
  var import_zod2 = require("zod");
@@ -29683,7 +29994,7 @@ function parseJsonl(filePath) {
29683
29994
  const messages = [];
29684
29995
  let raw;
29685
29996
  try {
29686
- raw = fs55.readFileSync(filePath, "utf8");
29997
+ raw = fs56.readFileSync(filePath, "utf8");
29687
29998
  } catch (err) {
29688
29999
  if (err.code !== "ENOENT") {
29689
30000
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -29837,7 +30148,7 @@ var HistoryService = class _HistoryService {
29837
30148
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
29838
30149
  }
29839
30150
  get projectDir() {
29840
- return this.runtime.resolveHistoryDir(this.cwd) ?? path64.join(os43.homedir(), ".claude", "projects", encodeCwd(this.cwd));
30151
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path65.join(os44.homedir(), ".claude", "projects", encodeCwd(this.cwd));
29841
30152
  }
29842
30153
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
29843
30154
  setCurrentConversationId(id) {
@@ -29849,7 +30160,7 @@ var HistoryService = class _HistoryService {
29849
30160
  /** Return the current message count in the active conversation. */
29850
30161
  getCurrentMessageCount() {
29851
30162
  if (!this.currentConversationId) return 0;
29852
- const filePath = path64.join(this.projectDir, `${this.currentConversationId}.jsonl`);
30163
+ const filePath = path65.join(this.projectDir, `${this.currentConversationId}.jsonl`);
29853
30164
  return parseJsonl(filePath).length;
29854
30165
  }
29855
30166
  /**
@@ -29860,7 +30171,7 @@ var HistoryService = class _HistoryService {
29860
30171
  const deadline = Date.now() + timeoutMs;
29861
30172
  while (Date.now() < deadline) {
29862
30173
  if (!this.currentConversationId) return null;
29863
- const filePath = path64.join(this.projectDir, `${this.currentConversationId}.jsonl`);
30174
+ const filePath = path65.join(this.projectDir, `${this.currentConversationId}.jsonl`);
29864
30175
  const messages = parseJsonl(filePath);
29865
30176
  if (messages.length > previousCount) {
29866
30177
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -29886,16 +30197,16 @@ var HistoryService = class _HistoryService {
29886
30197
  const dir = this.projectDir;
29887
30198
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
29888
30199
  try {
29889
- const files = fs55.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
30200
+ const files = fs56.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
29890
30201
  try {
29891
- const stat3 = fs55.statSync(path64.join(dir, e.name));
30202
+ const stat3 = fs56.statSync(path65.join(dir, e.name));
29892
30203
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
29893
30204
  } catch {
29894
30205
  return { name: e.name, mtime: 0, birthtime: 0 };
29895
30206
  }
29896
30207
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
29897
30208
  if (files.length > 0) {
29898
- this.currentConversationId = path64.basename(files[0].name, ".jsonl");
30209
+ this.currentConversationId = path65.basename(files[0].name, ".jsonl");
29899
30210
  }
29900
30211
  } catch {
29901
30212
  }
@@ -29929,13 +30240,13 @@ var HistoryService = class _HistoryService {
29929
30240
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
29930
30241
  let entries;
29931
30242
  try {
29932
- entries = fs55.readdirSync(dir, { withFileTypes: true });
30243
+ entries = fs56.readdirSync(dir, { withFileTypes: true });
29933
30244
  } catch {
29934
30245
  return null;
29935
30246
  }
29936
30247
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
29937
30248
  try {
29938
- const stat3 = fs55.statSync(path64.join(dir, e.name));
30249
+ const stat3 = fs56.statSync(path65.join(dir, e.name));
29939
30250
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
29940
30251
  } catch {
29941
30252
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -29944,12 +30255,12 @@ var HistoryService = class _HistoryService {
29944
30255
  if (files.length === 0) return null;
29945
30256
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
29946
30257
  if (!files.some((f) => f.name === targetFile)) return null;
29947
- return this.extractUsageFromFile(path64.join(dir, targetFile));
30258
+ return this.extractUsageFromFile(path65.join(dir, targetFile));
29948
30259
  }
29949
30260
  extractUsageFromFile(filePath) {
29950
30261
  let raw;
29951
30262
  try {
29952
- raw = fs55.readFileSync(filePath, "utf8");
30263
+ raw = fs56.readFileSync(filePath, "utf8");
29953
30264
  } catch {
29954
30265
  return null;
29955
30266
  }
@@ -30001,9 +30312,9 @@ var HistoryService = class _HistoryService {
30001
30312
  let totalCost = 0;
30002
30313
  let files;
30003
30314
  try {
30004
- files = fs55.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
30315
+ files = fs56.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
30005
30316
  try {
30006
- return fs55.statSync(path64.join(projectDir, f)).mtimeMs >= monthStartMs;
30317
+ return fs56.statSync(path65.join(projectDir, f)).mtimeMs >= monthStartMs;
30007
30318
  } catch {
30008
30319
  return false;
30009
30320
  }
@@ -30014,7 +30325,7 @@ var HistoryService = class _HistoryService {
30014
30325
  for (const file of files) {
30015
30326
  let raw;
30016
30327
  try {
30017
- raw = fs55.readFileSync(path64.join(projectDir, file), "utf8");
30328
+ raw = fs56.readFileSync(path65.join(projectDir, file), "utf8");
30018
30329
  } catch {
30019
30330
  continue;
30020
30331
  }
@@ -30093,7 +30404,7 @@ var HistoryService = class _HistoryService {
30093
30404
  if (this.runtime.resolveHistoryFile) {
30094
30405
  return this.runtime.resolveHistoryFile(this.cwd, sessionId);
30095
30406
  }
30096
- return path64.join(this.projectDir, `${sessionId}.jsonl`);
30407
+ return path65.join(this.projectDir, `${sessionId}.jsonl`);
30097
30408
  }
30098
30409
  /**
30099
30410
  * Parse a conversation's messages from disk, agent-aware. Claude uses the
@@ -30131,7 +30442,7 @@ var HistoryService = class _HistoryService {
30131
30442
  };
30132
30443
  });
30133
30444
  }
30134
- return parseJsonl(path64.join(this.projectDir, `${sessionId}.jsonl`));
30445
+ return parseJsonl(path65.join(this.projectDir, `${sessionId}.jsonl`));
30135
30446
  }
30136
30447
  /** One in-flight full upload per conversation — the baton mirror and a
30137
30448
  * `get_conversation` used to upload the same transcript concurrently. */
@@ -30213,7 +30524,7 @@ var HistoryService = class _HistoryService {
30213
30524
  if (!filePath) return false;
30214
30525
  let mtimeMs;
30215
30526
  try {
30216
- mtimeMs = fs55.statSync(filePath).mtimeMs;
30527
+ mtimeMs = fs56.statSync(filePath).mtimeMs;
30217
30528
  } catch {
30218
30529
  return false;
30219
30530
  }
@@ -30287,11 +30598,11 @@ var HistoryService = class _HistoryService {
30287
30598
  };
30288
30599
 
30289
30600
  // src/agents/acp/client.ts
30290
- var import_node_child_process21 = require("child_process");
30291
- var fs56 = __toESM(require("fs/promises"));
30601
+ var import_node_child_process22 = require("child_process");
30602
+ var fs57 = __toESM(require("fs/promises"));
30292
30603
  var fsSync = __toESM(require("fs"));
30293
- var os45 = __toESM(require("os"));
30294
- var path66 = __toESM(require("path"));
30604
+ var os46 = __toESM(require("os"));
30605
+ var path67 = __toESM(require("path"));
30295
30606
  var import_node_stream = require("stream");
30296
30607
 
30297
30608
  // ../../node_modules/@agentclientprotocol/sdk/dist/schema/index.js
@@ -34317,8 +34628,8 @@ function createIdleTimeout(idleMs, makeError, activeIdleMs = idleMs) {
34317
34628
  }
34318
34629
 
34319
34630
  // src/agents/acp/internal-paths.ts
34320
- var path65 = __toESM(require("path"));
34321
- var os44 = __toESM(require("os"));
34631
+ var path66 = __toESM(require("path"));
34632
+ var os45 = __toESM(require("os"));
34322
34633
  var INTERNAL_TOKENS = [".codeam", "house-claude"];
34323
34634
  var PROSE_ONLY_TOOL_KINDS = /* @__PURE__ */ new Set(["think", "switch_mode"]);
34324
34635
  function isProseOnlyToolKind(kind) {
@@ -34330,13 +34641,13 @@ function textReferencesInternal(text) {
34330
34641
  const scrubbed = text.replace(SELF_HOSTED_WORKSPACE_RE, " ");
34331
34642
  return INTERNAL_TOKENS.some((t2) => scrubbed.includes(t2));
34332
34643
  }
34333
- function pathIsInternal(p2, homeDir2 = os44.homedir()) {
34644
+ function pathIsInternal(p2, homeDir2 = os45.homedir()) {
34334
34645
  if (!p2) return false;
34335
- const abs = path65.resolve(p2);
34336
- const home = path65.resolve(homeDir2);
34337
- const within = (root) => abs === root || abs.startsWith(root + path65.sep);
34338
- if (within(path65.join(home, ".codeam", "self-hosted"))) return false;
34339
- return within(path65.join(home, ".codeam")) || within(path65.join(home, ".beads")) || abs === path65.join(home, ".codeam-host.log") || abs.includes(`${path65.sep}house-claude${path65.sep}`) || abs.endsWith(`${path65.sep}house-claude`);
34646
+ const abs = path66.resolve(p2);
34647
+ const home = path66.resolve(homeDir2);
34648
+ const within = (root) => abs === root || abs.startsWith(root + path66.sep);
34649
+ if (within(path66.join(home, ".codeam", "self-hosted"))) return false;
34650
+ return within(path66.join(home, ".codeam")) || within(path66.join(home, ".beads")) || abs === path66.join(home, ".codeam-host.log") || abs.includes(`${path66.sep}house-claude${path66.sep}`) || abs.endsWith(`${path66.sep}house-claude`);
34340
34651
  }
34341
34652
  function toolCallReferencesInternal(call, homeDir2) {
34342
34653
  if (call.locations?.some((l) => pathIsInternal(l.path, homeDir2))) return true;
@@ -34664,7 +34975,7 @@ var AcpClient = class {
34664
34975
  "acpClient",
34665
34976
  `provider routing ${formatProviderRouting(describeProviderRouting(childEnv, { cwd }), adapter.command)}`
34666
34977
  );
34667
- const child = (0, import_node_child_process21.spawn)(adapter.command, adapter.args, {
34978
+ const child = (0, import_node_child_process22.spawn)(adapter.command, adapter.args, {
34668
34979
  cwd,
34669
34980
  env: childEnv,
34670
34981
  stdio: ["pipe", "pipe", "pipe"],
@@ -35349,7 +35660,7 @@ var AcpClient = class {
35349
35660
  try {
35350
35661
  const pid = child.pid;
35351
35662
  if (process.platform === "win32") {
35352
- if (pid) (0, import_node_child_process21.spawnSync)("taskkill", ["/F", "/T", "/PID", String(pid)], { stdio: "ignore" });
35663
+ if (pid) (0, import_node_child_process22.spawnSync)("taskkill", ["/F", "/T", "/PID", String(pid)], { stdio: "ignore" });
35353
35664
  } else if (pid) {
35354
35665
  killQuiet(-pid, "SIGTERM");
35355
35666
  } else {
@@ -35431,7 +35742,7 @@ var AcpClient = class {
35431
35742
  throw new RequestError(-32002, GUARDRAIL_SECRET_READ_BLOCK_REASON, { uri: params.path });
35432
35743
  }
35433
35744
  try {
35434
- const content = await fs56.readFile(params.path, "utf8");
35745
+ const content = await fs57.readFile(params.path, "utf8");
35435
35746
  return applyLineRange(content, params.line ?? null, params.limit ?? null);
35436
35747
  } catch (err) {
35437
35748
  const code = err.code;
@@ -35452,7 +35763,7 @@ var AcpClient = class {
35452
35763
  throw new RequestError(-32002, INTERNAL_BLOCK_REASON, { uri: params.path });
35453
35764
  }
35454
35765
  try {
35455
- await fs56.writeFile(params.path, params.content, "utf8");
35766
+ await fs57.writeFile(params.path, params.content, "utf8");
35456
35767
  return {};
35457
35768
  } catch (err) {
35458
35769
  const code = err.code;
@@ -35540,30 +35851,30 @@ function applyLineRange(content, line, limit) {
35540
35851
  return { content: lines.slice(start2, end).join("\n") };
35541
35852
  }
35542
35853
  function knownAgentBinaryDirs() {
35543
- const home = os45.homedir();
35854
+ const home = os46.homedir();
35544
35855
  const out2 = [];
35545
35856
  out2.push("/tmp/codeam-node20/bin");
35546
35857
  for (const root of [
35547
35858
  "/usr/local/share/nvm/versions/node",
35548
- path66.join(home, ".nvm/versions/node")
35859
+ path67.join(home, ".nvm/versions/node")
35549
35860
  ]) {
35550
35861
  try {
35551
35862
  for (const child of fsSync.readdirSync(root)) {
35552
- out2.push(path66.join(root, child, "bin"));
35863
+ out2.push(path67.join(root, child, "bin"));
35553
35864
  }
35554
35865
  } catch {
35555
35866
  }
35556
35867
  }
35557
- out2.push(path66.join(home, ".volta/bin"));
35868
+ out2.push(path67.join(home, ".volta/bin"));
35558
35869
  out2.push("/usr/local/bin");
35559
35870
  out2.push("/usr/bin");
35560
- out2.push(path66.join(home, ".local/bin"));
35561
- out2.push(path66.join(home, "bin"));
35871
+ out2.push(path67.join(home, ".local/bin"));
35872
+ out2.push(path67.join(home, "bin"));
35562
35873
  out2.push(...agentInstallBinDirs());
35563
35874
  if (process.platform === "win32") {
35564
35875
  const { LOCALAPPDATA, APPDATA } = process.env;
35565
- if (LOCALAPPDATA) out2.push(path66.join(LOCALAPPDATA, "cursor-agent"));
35566
- if (APPDATA) out2.push(path66.join(APPDATA, "npm"));
35876
+ if (LOCALAPPDATA) out2.push(path67.join(LOCALAPPDATA, "cursor-agent"));
35877
+ if (APPDATA) out2.push(path67.join(APPDATA, "npm"));
35567
35878
  }
35568
35879
  return out2.filter((p2) => {
35569
35880
  try {
@@ -35574,7 +35885,7 @@ function knownAgentBinaryDirs() {
35574
35885
  });
35575
35886
  }
35576
35887
  function expandPathForAgentBinaries(existingPath) {
35577
- const existing = new Set(existingPath.split(path66.delimiter).filter((p2) => p2.length > 0));
35888
+ const existing = new Set(existingPath.split(path67.delimiter).filter((p2) => p2.length > 0));
35578
35889
  const additions = [];
35579
35890
  for (const dir of knownAgentBinaryDirs()) {
35580
35891
  if (!existing.has(dir)) {
@@ -35583,17 +35894,17 @@ function expandPathForAgentBinaries(existingPath) {
35583
35894
  }
35584
35895
  }
35585
35896
  if (additions.length === 0) return existingPath;
35586
- return [...additions, existingPath].filter((p2) => p2.length > 0).join(path66.delimiter);
35897
+ return [...additions, existingPath].filter((p2) => p2.length > 0).join(path67.delimiter);
35587
35898
  }
35588
35899
 
35589
35900
  // src/commands/host/agent-install.ts
35590
35901
  var import_child_process27 = require("child_process");
35591
- var os46 = __toESM(require("os"));
35902
+ var os47 = __toESM(require("os"));
35592
35903
  function runAgentInstallScript(script, opts = {}) {
35593
35904
  const timeoutMs = opts.timeoutMs ?? 18e4;
35594
35905
  const scope = opts.logScope ?? "agent-install";
35595
35906
  return new Promise((resolve12) => {
35596
- const home = process.env.HOME || os46.homedir();
35907
+ const home = process.env.HOME || os47.homedir();
35597
35908
  const child = (0, import_child_process27.spawn)("sh", ["-c", script], {
35598
35909
  env: { ...process.env, HOME: home },
35599
35910
  stdio: ["ignore", "pipe", "pipe"]
@@ -35855,9 +36166,9 @@ async function performAgentSwitch(deps, rawAgentId, fastPath = {}) {
35855
36166
  }
35856
36167
 
35857
36168
  // src/commands/host/agent-provisioning.ts
35858
- var fs57 = __toESM(require("fs"));
35859
- var os47 = __toESM(require("os"));
35860
- var path67 = __toESM(require("path"));
36169
+ var fs58 = __toESM(require("fs"));
36170
+ var os48 = __toESM(require("os"));
36171
+ var path68 = __toESM(require("path"));
35861
36172
  var PUBLIC_TO_INTERNAL_AGENT = {
35862
36173
  claude_code: "claude",
35863
36174
  claude: "claude",
@@ -35874,22 +36185,22 @@ function toInternalAgentId(publicAgentId) {
35874
36185
  return PUBLIC_TO_INTERNAL_AGENT[publicAgentId] ?? null;
35875
36186
  }
35876
36187
  function ensureDir(dir) {
35877
- fs57.mkdirSync(dir, { recursive: true, mode: 448 });
36188
+ fs58.mkdirSync(dir, { recursive: true, mode: 448 });
35878
36189
  }
35879
36190
  function writeFile0600(filePath, contents) {
35880
- ensureDir(path67.dirname(filePath));
35881
- fs57.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
36191
+ ensureDir(path68.dirname(filePath));
36192
+ fs58.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
35882
36193
  restrictToOwner(filePath);
35883
36194
  }
35884
36195
  function rmIfExists(filePath) {
35885
36196
  try {
35886
- fs57.rmSync(filePath, { force: true });
36197
+ fs58.rmSync(filePath, { force: true });
35887
36198
  } catch {
35888
36199
  }
35889
36200
  }
35890
36201
  var claudeProvisioner = {
35891
36202
  write(auth, home) {
35892
- const credentialsJson = path67.join(home, ".claude", ".credentials.json");
36203
+ const credentialsJson = path68.join(home, ".claude", ".credentials.json");
35893
36204
  if (auth.kind === "api_key") {
35894
36205
  rmIfExists(credentialsJson);
35895
36206
  return { ANTHROPIC_API_KEY: auth.value };
@@ -35901,8 +36212,8 @@ var claudeProvisioner = {
35901
36212
  } else {
35902
36213
  rmIfExists(credentialsJson);
35903
36214
  }
35904
- const claudeJson = path67.join(home, ".claude.json");
35905
- if (!fs57.existsSync(claudeJson)) {
36215
+ const claudeJson = path68.join(home, ".claude.json");
36216
+ if (!fs58.existsSync(claudeJson)) {
35906
36217
  writeFile0600(
35907
36218
  claudeJson,
35908
36219
  JSON.stringify({ hasCompletedOnboarding: true, customApiKeyResponses: { approved: [] } })
@@ -35913,7 +36224,7 @@ var claudeProvisioner = {
35913
36224
  };
35914
36225
  var codexProvisioner = {
35915
36226
  write(auth, home) {
35916
- const authJson = path67.join(home, ".codex", "auth.json");
36227
+ const authJson = path68.join(home, ".codex", "auth.json");
35917
36228
  if (auth.kind === "api_key") {
35918
36229
  writeFile0600(authJson, JSON.stringify({ auth_mode: "apikey", OPENAI_API_KEY: auth.value }));
35919
36230
  return { OPENAI_API_KEY: auth.value };
@@ -35924,8 +36235,8 @@ var codexProvisioner = {
35924
36235
  };
35925
36236
  var geminiProvisioner = {
35926
36237
  write(auth, home) {
35927
- const settingsJson = path67.join(home, ".gemini", "settings.json");
35928
- const oauthCreds = path67.join(home, ".gemini", "oauth_creds.json");
36238
+ const settingsJson = path68.join(home, ".gemini", "settings.json");
36239
+ const oauthCreds = path68.join(home, ".gemini", "oauth_creds.json");
35929
36240
  if (auth.kind === "api_key") {
35930
36241
  rmIfExists(oauthCreds);
35931
36242
  writeFile0600(settingsJson, '{"security":{"auth":{"selectedType":"gemini-api-key"}}}');
@@ -35938,7 +36249,7 @@ var geminiProvisioner = {
35938
36249
  };
35939
36250
  var cursorProvisioner = {
35940
36251
  write(auth, home) {
35941
- const authJson = path67.join(home, ".config", "cursor", "auth.json");
36252
+ const authJson = path68.join(home, ".config", "cursor", "auth.json");
35942
36253
  if (auth.kind === "api_key") {
35943
36254
  rmIfExists(authJson);
35944
36255
  return { CURSOR_API_KEY: auth.value };
@@ -35980,22 +36291,22 @@ max_context_size = 262144
35980
36291
  var kimiProvisioner = {
35981
36292
  write(auth, home) {
35982
36293
  const credentialsFiles = [
35983
- path67.join(home, ".kimi", "credentials", "kimi-code.json"),
35984
- path67.join(home, ".kimi-code", "credentials", "kimi-code.json")
36294
+ path68.join(home, ".kimi", "credentials", "kimi-code.json"),
36295
+ path68.join(home, ".kimi-code", "credentials", "kimi-code.json")
35985
36296
  ];
35986
36297
  if (auth.kind === "api_key") {
35987
36298
  credentialsFiles.forEach(rmIfExists);
35988
36299
  return { KIMI_API_KEY: auth.value };
35989
36300
  }
35990
36301
  credentialsFiles.forEach((f) => writeFile0600(f, auth.value));
35991
- writeFile0600(path67.join(home, ".kimi-code", "config.toml"), KIMI_MANAGED_CONFIG_TOML);
36302
+ writeFile0600(path68.join(home, ".kimi-code", "config.toml"), KIMI_MANAGED_CONFIG_TOML);
35992
36303
  return {};
35993
36304
  }
35994
36305
  };
35995
36306
  var coderabbitProvisioner = {
35996
36307
  write(auth, home) {
35997
- const dir = path67.join(home, ".coderabbit");
35998
- const authJson = path67.join(dir, "auth.json");
36308
+ const dir = path68.join(home, ".coderabbit");
36309
+ const authJson = path68.join(dir, "auth.json");
35999
36310
  if (auth.kind === "api_key") {
36000
36311
  rmIfExists(authJson);
36001
36312
  return { CODERABBIT_API_KEY: auth.value };
@@ -36007,13 +36318,13 @@ var coderabbitProvisioner = {
36007
36318
  try {
36008
36319
  const parsed = JSON.parse(value);
36009
36320
  if (typeof parsed.file === "string" && typeof parsed.contents === "string") {
36010
- file = path67.basename(parsed.file);
36321
+ file = path68.basename(parsed.file);
36011
36322
  contents = parsed.contents;
36012
36323
  }
36013
36324
  } catch {
36014
36325
  }
36015
36326
  }
36016
- writeFile0600(path67.join(dir, file), contents);
36327
+ writeFile0600(path68.join(dir, file), contents);
36017
36328
  return {};
36018
36329
  }
36019
36330
  };
@@ -36041,7 +36352,7 @@ var UnsupportedAgentError = class extends Error {
36041
36352
  this.agentId = agentId;
36042
36353
  }
36043
36354
  };
36044
- function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os47.homedir()) {
36355
+ function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os48.homedir()) {
36045
36356
  const internal = toInternalAgentId(publicAgentId);
36046
36357
  if (!internal) throw new UnsupportedAgentError(publicAgentId);
36047
36358
  const provisioner = PROVISIONERS[internal];
@@ -36050,16 +36361,16 @@ function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os47.homedir(
36050
36361
  }
36051
36362
 
36052
36363
  // src/beads/workflow-hint.ts
36053
- var fs58 = __toESM(require("fs"));
36054
- var path69 = __toESM(require("path"));
36364
+ var fs59 = __toESM(require("fs"));
36365
+ var path70 = __toESM(require("path"));
36055
36366
 
36056
36367
  // src/agents/claude-memory-file.ts
36057
- var os48 = __toESM(require("os"));
36058
- var path68 = __toESM(require("path"));
36368
+ var os49 = __toESM(require("os"));
36369
+ var path69 = __toESM(require("path"));
36059
36370
  function claudeMemoryFile(homeDir2, env = process.env) {
36060
- if (homeDir2) return path68.join(homeDir2, ".claude", "CLAUDE.md");
36371
+ if (homeDir2) return path69.join(homeDir2, ".claude", "CLAUDE.md");
36061
36372
  const configDir = env.CLAUDE_CONFIG_DIR?.trim();
36062
- return configDir ? path68.join(configDir, "CLAUDE.md") : path68.join(os48.homedir(), ".claude", "CLAUDE.md");
36373
+ return configDir ? path69.join(configDir, "CLAUDE.md") : path69.join(os49.homedir(), ".claude", "CLAUDE.md");
36063
36374
  }
36064
36375
 
36065
36376
  // src/beads/workflow-hint.ts
@@ -36089,11 +36400,11 @@ function ensureBeadsWorkflowHint(homeDir2, file = claudeMemoryFile(homeDir2)) {
36089
36400
  try {
36090
36401
  let existing = "";
36091
36402
  try {
36092
- existing = fs58.readFileSync(file, "utf8");
36403
+ existing = fs59.readFileSync(file, "utf8");
36093
36404
  } catch {
36094
36405
  }
36095
36406
  if (existing.includes(BEADS_HINT)) return;
36096
- fs58.mkdirSync(path69.dirname(file), { recursive: true });
36407
+ fs59.mkdirSync(path70.dirname(file), { recursive: true });
36097
36408
  let next;
36098
36409
  const open = existing.indexOf(BEADS_HINT_MARKER);
36099
36410
  const close = open === -1 ? -1 : existing.indexOf(BEADS_HINT_MARKER, open + BEADS_HINT_MARKER.length);
@@ -36106,40 +36417,40 @@ ${BEADS_HINT}
36106
36417
  ` : `${BEADS_HINT}
36107
36418
  `;
36108
36419
  }
36109
- fs58.writeFileSync(file, next);
36420
+ fs59.writeFileSync(file, next);
36110
36421
  } catch {
36111
36422
  }
36112
36423
  }
36113
36424
 
36114
36425
  // src/agents/agent-standard.ts
36115
- var fs59 = __toESM(require("fs"));
36116
- var path70 = __toESM(require("path"));
36117
- var os49 = __toESM(require("os"));
36426
+ var fs60 = __toESM(require("fs"));
36427
+ var path71 = __toESM(require("path"));
36428
+ var os50 = __toESM(require("os"));
36118
36429
  function ensureAgentStandard(homeDir2, file = claudeMemoryFile(homeDir2)) {
36119
36430
  try {
36120
36431
  let existing = "";
36121
36432
  try {
36122
- existing = fs59.readFileSync(file, "utf8");
36433
+ existing = fs60.readFileSync(file, "utf8");
36123
36434
  } catch {
36124
36435
  }
36125
36436
  if (existing.includes(AGENT_STANDARD_MARKER)) return;
36126
- fs59.mkdirSync(path70.dirname(file), { recursive: true });
36437
+ fs60.mkdirSync(path71.dirname(file), { recursive: true });
36127
36438
  const next = existing.trim() ? `${existing.trimEnd()}
36128
36439
 
36129
36440
  ${AGENT_STANDARD_BLOCK}
36130
36441
  ` : `${AGENT_STANDARD_BLOCK}
36131
36442
  `;
36132
- fs59.writeFileSync(file, next);
36443
+ fs60.writeFileSync(file, next);
36133
36444
  } catch {
36134
36445
  }
36135
36446
  }
36136
36447
  var _agentStandardSeam = {
36137
36448
  isLocalSession: () => isLocalSession(),
36138
- markerPath: (sessionId) => path70.join(os49.homedir(), ".codeam", "agent-standard", `${sessionId}.done`),
36139
- exists: (p2) => fs59.existsSync(p2),
36449
+ markerPath: (sessionId) => path71.join(os50.homedir(), ".codeam", "agent-standard", `${sessionId}.done`),
36450
+ exists: (p2) => fs60.existsSync(p2),
36140
36451
  write: (p2) => {
36141
- fs59.mkdirSync(path70.dirname(p2), { recursive: true });
36142
- fs59.writeFileSync(p2, "");
36452
+ fs60.mkdirSync(path71.dirname(p2), { recursive: true });
36453
+ fs60.writeFileSync(p2, "");
36143
36454
  }
36144
36455
  };
36145
36456
  function isClaude(agent) {
@@ -36832,15 +37143,15 @@ function withholdTrailingPartialFenceMarker(text) {
36832
37143
 
36833
37144
  // src/agents/acp/onboarding.ts
36834
37145
  var import_child_process28 = require("child_process");
36835
- var fs60 = __toESM(require("fs"));
36836
- var os50 = __toESM(require("os"));
36837
- var path71 = __toESM(require("path"));
37146
+ var fs61 = __toESM(require("fs"));
37147
+ var os51 = __toESM(require("os"));
37148
+ var path72 = __toESM(require("path"));
36838
37149
  var _onboardingSeam = {
36839
- markerPath: (sessionId) => path71.join(os50.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
36840
- exists: (p2) => fs60.existsSync(p2),
37150
+ markerPath: (sessionId) => path72.join(os51.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
37151
+ exists: (p2) => fs61.existsSync(p2),
36841
37152
  write: (p2) => {
36842
- fs60.mkdirSync(path71.dirname(p2), { recursive: true });
36843
- fs60.writeFileSync(p2, "");
37153
+ fs61.mkdirSync(path72.dirname(p2), { recursive: true });
37154
+ fs61.writeFileSync(p2, "");
36844
37155
  },
36845
37156
  disabled: () => {
36846
37157
  const v = process.env.CODEAM_ONBOARDING_DISABLED;
@@ -36877,7 +37188,7 @@ function resolveRepoName(cwd) {
36877
37188
  if (name) return name;
36878
37189
  }
36879
37190
  }
36880
- const base = path71.basename(cwd || "");
37191
+ const base = path72.basename(cwd || "");
36881
37192
  if (base && !isUuid(base)) return base;
36882
37193
  return "this project";
36883
37194
  }
@@ -37269,13 +37580,13 @@ var import_crypto4 = require("crypto");
37269
37580
 
37270
37581
  // src/services/turn-files/git-changeset.ts
37271
37582
  var import_child_process29 = require("child_process");
37272
- var fs62 = __toESM(require("fs/promises"));
37273
- var path73 = __toESM(require("path"));
37583
+ var fs63 = __toESM(require("fs/promises"));
37584
+ var path74 = __toESM(require("path"));
37274
37585
 
37275
37586
  // src/services/turn-files/review-ignore.ts
37276
37587
  var import_ignore2 = __toESM(require("ignore"));
37277
- var fs61 = __toESM(require("fs"));
37278
- var path72 = __toESM(require("path"));
37588
+ var fs62 = __toESM(require("fs"));
37589
+ var path73 = __toESM(require("path"));
37279
37590
  var CURATED_REVIEW_IGNORE = [
37280
37591
  // Google Cloud SDK (the incident) — installs a huge python tree.
37281
37592
  "google-cloud-sdk/",
@@ -37314,7 +37625,7 @@ var CURATED_REVIEW_IGNORE = [
37314
37625
  function makeReviewIgnore(repoRoot) {
37315
37626
  const ig = (0, import_ignore2.default)().add(CURATED_REVIEW_IGNORE);
37316
37627
  try {
37317
- const custom = fs61.readFileSync(path72.join(repoRoot, ".codeam", "reviewignore"), "utf8");
37628
+ const custom = fs62.readFileSync(path73.join(repoRoot, ".codeam", "reviewignore"), "utf8");
37318
37629
  ig.add(custom);
37319
37630
  } catch {
37320
37631
  }
@@ -37359,7 +37670,7 @@ async function collectRepoChangeset(opts) {
37359
37670
  let stats;
37360
37671
  if (!truncated && row.fileStatus === "added" && numstatEntry === void 0) {
37361
37672
  const lineCount = await readUntrackedLineCount(
37362
- path73.join(opts.repoRoot, row.filePath)
37673
+ path74.join(opts.repoRoot, row.filePath)
37363
37674
  );
37364
37675
  stats = { added: lineCount, removed: 0 };
37365
37676
  } else {
@@ -37390,7 +37701,7 @@ function readUntrackedLineCount(absPath) {
37390
37701
  }
37391
37702
  async function defaultReadUntrackedLineCount(absPath) {
37392
37703
  try {
37393
- const content = await fs62.readFile(absPath, "utf8");
37704
+ const content = await fs63.readFile(absPath, "utf8");
37394
37705
  let count = 0;
37395
37706
  let pos = -1;
37396
37707
  while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
@@ -37482,7 +37793,7 @@ function defaultRunGit(cwd, args2) {
37482
37793
  });
37483
37794
  }
37484
37795
  async function discoverRepos(workingDir, maxDepth = 4) {
37485
- const fs81 = await import("fs/promises");
37796
+ const fs82 = await import("fs/promises");
37486
37797
  const out2 = [];
37487
37798
  await walk(workingDir, 0);
37488
37799
  return out2;
@@ -37490,7 +37801,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
37490
37801
  if (depth > maxDepth) return;
37491
37802
  let entries = [];
37492
37803
  try {
37493
- const dirents = await fs81.readdir(dir, { withFileTypes: true });
37804
+ const dirents = await fs82.readdir(dir, { withFileTypes: true });
37494
37805
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
37495
37806
  } catch {
37496
37807
  return;
@@ -37501,8 +37812,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
37501
37812
  if (hasGit) {
37502
37813
  out2.push({
37503
37814
  repoRoot: dir,
37504
- repoPath: path73.relative(workingDir, dir),
37505
- repoName: path73.basename(dir)
37815
+ repoPath: path74.relative(workingDir, dir),
37816
+ repoName: path74.basename(dir)
37506
37817
  });
37507
37818
  return;
37508
37819
  }
@@ -37510,14 +37821,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
37510
37821
  if (!entry.isDirectory) continue;
37511
37822
  if (entry.name === "node_modules") continue;
37512
37823
  if (entry.name === "dist" || entry.name === "build") continue;
37513
- await walk(path73.join(dir, entry.name), depth + 1);
37824
+ await walk(path74.join(dir, entry.name), depth + 1);
37514
37825
  }
37515
37826
  }
37516
37827
  }
37517
37828
 
37518
37829
  // src/services/turn-files/files-outbox.ts
37519
- var fs63 = __toESM(require("fs/promises"));
37520
- var path74 = __toESM(require("path"));
37830
+ var fs64 = __toESM(require("fs/promises"));
37831
+ var path75 = __toESM(require("path"));
37521
37832
  var import_os12 = require("os");
37522
37833
  var HOME_OUTBOX_DIR = ".codeam/outbox";
37523
37834
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -37550,16 +37861,16 @@ var FilesOutbox = class {
37550
37861
  backoffIndex = 0;
37551
37862
  stopped = false;
37552
37863
  constructor(opts) {
37553
- const base = opts.baseDir ?? path74.join(homeDir(), HOME_OUTBOX_DIR);
37554
- this.filePath = path74.join(base, `${opts.sessionId}.jsonl`);
37864
+ const base = opts.baseDir ?? path75.join(homeDir(), HOME_OUTBOX_DIR);
37865
+ this.filePath = path75.join(base, `${opts.sessionId}.jsonl`);
37555
37866
  this.post = opts.post;
37556
37867
  this.autoSchedule = opts.autoSchedule !== false;
37557
37868
  }
37558
37869
  /** Persist the entry to disk and trigger a flush. Returns once the
37559
37870
  * line is durable on disk (not once the POST succeeds). */
37560
37871
  async enqueue(entry) {
37561
- await fs63.mkdir(path74.dirname(this.filePath), { recursive: true });
37562
- await fs63.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
37872
+ await fs64.mkdir(path75.dirname(this.filePath), { recursive: true });
37873
+ await fs64.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
37563
37874
  this.backoffIndex = 0;
37564
37875
  if (this.autoSchedule) this.scheduleFlush(0);
37565
37876
  }
@@ -37650,7 +37961,7 @@ var FilesOutbox = class {
37650
37961
  async readAll() {
37651
37962
  let raw = "";
37652
37963
  try {
37653
- raw = await fs63.readFile(this.filePath, "utf8");
37964
+ raw = await fs64.readFile(this.filePath, "utf8");
37654
37965
  } catch {
37655
37966
  return [];
37656
37967
  }
@@ -37674,12 +37985,12 @@ var FilesOutbox = class {
37674
37985
  async rewrite(entries) {
37675
37986
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
37676
37987
  if (entries.length === 0) {
37677
- await fs63.unlink(this.filePath).catch(() => void 0);
37988
+ await fs64.unlink(this.filePath).catch(() => void 0);
37678
37989
  return;
37679
37990
  }
37680
37991
  const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
37681
- await fs63.writeFile(tmpPath, payload, "utf8");
37682
- await fs63.rename(tmpPath, this.filePath);
37992
+ await fs64.writeFile(tmpPath, payload, "utf8");
37993
+ await fs64.rename(tmpPath, this.filePath);
37683
37994
  }
37684
37995
  };
37685
37996
  function applyJitter(ms) {
@@ -38226,11 +38537,11 @@ async function postCredentialSync(opts, fetchImpl = fetch) {
38226
38537
  }
38227
38538
 
38228
38539
  // src/packs/gates.ts
38229
- var import_node_child_process22 = require("child_process");
38230
- var fs64 = __toESM(require("fs"));
38231
- var path75 = __toESM(require("path"));
38540
+ var import_node_child_process23 = require("child_process");
38541
+ var fs65 = __toESM(require("fs"));
38542
+ var path76 = __toESM(require("path"));
38232
38543
  var defaultCommandRunner = (file, args2, cwd, timeoutMs, env) => new Promise((resolve12) => {
38233
- (0, import_node_child_process22.execFile)(
38544
+ (0, import_node_child_process23.execFile)(
38234
38545
  file,
38235
38546
  args2,
38236
38547
  {
@@ -38278,7 +38589,7 @@ async function changedFiles(run, cwd, from, to) {
38278
38589
  }
38279
38590
  function readWorkspaceFile(cwd, relPath) {
38280
38591
  try {
38281
- return fs64.readFileSync(path75.join(cwd, relPath), "utf8");
38592
+ return fs65.readFileSync(path76.join(cwd, relPath), "utf8");
38282
38593
  } catch {
38283
38594
  return null;
38284
38595
  }
@@ -38287,14 +38598,14 @@ var NO_TEST_PLACEHOLDER = 'echo "Error: no test specified"';
38287
38598
  var CHECKS_TIMEOUT_MS = 5 * 6e4;
38288
38599
  function detectChecksCommand(cwd) {
38289
38600
  try {
38290
- const cfg = JSON.parse(fs64.readFileSync(path75.join(cwd, ".codeam", "pack.json"), "utf8"));
38601
+ const cfg = JSON.parse(fs65.readFileSync(path76.join(cwd, ".codeam", "pack.json"), "utf8"));
38291
38602
  if (typeof cfg.checksCommand === "string" && cfg.checksCommand.trim().length > 0) {
38292
38603
  return cfg.checksCommand.trim();
38293
38604
  }
38294
38605
  } catch {
38295
38606
  }
38296
38607
  try {
38297
- const pkg = JSON.parse(fs64.readFileSync(path75.join(cwd, "package.json"), "utf8"));
38608
+ const pkg = JSON.parse(fs65.readFileSync(path76.join(cwd, "package.json"), "utf8"));
38298
38609
  const test = pkg.scripts?.test;
38299
38610
  if (typeof test === "string" && test.trim().length > 0 && !test.includes(NO_TEST_PLACEHOLDER)) {
38300
38611
  return "npm test";
@@ -38312,39 +38623,39 @@ ${res.stderr}`.trim();
38312
38623
  }
38313
38624
 
38314
38625
  // src/packs/run-store.ts
38315
- var fs65 = __toESM(require("fs"));
38316
- var path76 = __toESM(require("path"));
38626
+ var fs66 = __toESM(require("fs"));
38627
+ var path77 = __toESM(require("path"));
38317
38628
  var crypto5 = __toESM(require("crypto"));
38318
38629
  function packsDir(cwd) {
38319
- return path76.join(cwd, ".codeam", "packs");
38630
+ return path77.join(cwd, ".codeam", "packs");
38320
38631
  }
38321
38632
  function runDir(cwd, runId) {
38322
- return path76.join(packsDir(cwd), runId);
38633
+ return path77.join(packsDir(cwd), runId);
38323
38634
  }
38324
38635
  function newRunId() {
38325
38636
  return `pk_${Date.now().toString(36)}_${crypto5.randomBytes(4).toString("hex")}`;
38326
38637
  }
38327
38638
  function writeJsonAtomic(file, value) {
38328
- fs65.mkdirSync(path76.dirname(file), { recursive: true });
38639
+ fs66.mkdirSync(path77.dirname(file), { recursive: true });
38329
38640
  const tmp = `${file}.tmp`;
38330
- fs65.writeFileSync(tmp, JSON.stringify(value, null, 2));
38331
- fs65.renameSync(tmp, file);
38641
+ fs66.writeFileSync(tmp, JSON.stringify(value, null, 2));
38642
+ fs66.renameSync(tmp, file);
38332
38643
  }
38333
38644
  function saveRun(cwd, state) {
38334
- writeJsonAtomic(path76.join(runDir(cwd, state.runId), "run.json"), state);
38645
+ writeJsonAtomic(path77.join(runDir(cwd, state.runId), "run.json"), state);
38335
38646
  }
38336
38647
  function saveStageHandoff(cwd, runId, stageIndex, role, handoff) {
38337
38648
  const name = `${String(stageIndex + 1).padStart(2, "0")}-${role}.json`;
38338
- writeJsonAtomic(path76.join(runDir(cwd, runId), name), handoff);
38649
+ writeJsonAtomic(path77.join(runDir(cwd, runId), name), handoff);
38339
38650
  }
38340
38651
  function loadLatestRun(cwd) {
38341
38652
  try {
38342
38653
  const dir = packsDir(cwd);
38343
- const entries = fs65.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
38654
+ const entries = fs66.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
38344
38655
  for (let i = entries.length - 1; i >= 0; i--) {
38345
- const file = path76.join(dir, entries[i], "run.json");
38656
+ const file = path77.join(dir, entries[i], "run.json");
38346
38657
  try {
38347
- const parsed = JSON.parse(fs65.readFileSync(file, "utf8"));
38658
+ const parsed = JSON.parse(fs66.readFileSync(file, "utf8"));
38348
38659
  if (parsed && typeof parsed.runId === "string") return parsed;
38349
38660
  } catch {
38350
38661
  }
@@ -38355,17 +38666,17 @@ function loadLatestRun(cwd) {
38355
38666
  }
38356
38667
  function ensureLedgerIgnored(cwd) {
38357
38668
  try {
38358
- const gitDir = path76.join(cwd, ".git");
38359
- if (!fs65.existsSync(gitDir)) return;
38360
- const exclude = path76.join(gitDir, "info", "exclude");
38669
+ const gitDir = path77.join(cwd, ".git");
38670
+ if (!fs66.existsSync(gitDir)) return;
38671
+ const exclude = path77.join(gitDir, "info", "exclude");
38361
38672
  let existing = "";
38362
38673
  try {
38363
- existing = fs65.readFileSync(exclude, "utf8");
38674
+ existing = fs66.readFileSync(exclude, "utf8");
38364
38675
  } catch {
38365
38676
  }
38366
38677
  if (existing.includes(".codeam/packs/")) return;
38367
- fs65.mkdirSync(path76.dirname(exclude), { recursive: true });
38368
- fs65.writeFileSync(exclude, `${existing.trimEnd()}
38678
+ fs66.mkdirSync(path77.dirname(exclude), { recursive: true });
38679
+ fs66.writeFileSync(exclude, `${existing.trimEnd()}
38369
38680
  .codeam/packs/
38370
38681
  `.trimStart());
38371
38682
  } catch {
@@ -39345,8 +39656,267 @@ async function mcpRouter() {
39345
39656
  });
39346
39657
  }
39347
39658
 
39659
+ // src/integrations/mcp-secrets.ts
39660
+ var fs68 = __toESM(require("fs"));
39661
+ var os53 = __toESM(require("os"));
39662
+ var path79 = __toESM(require("path"));
39663
+ var MCP_SECRETS_FILE_ENV = "CODEAM_MCP_SECRETS_FILE";
39664
+ function mcpSecretsDir() {
39665
+ return path79.join(os53.homedir(), ".codeam", "mcp-secrets");
39666
+ }
39667
+ function mcpSecretsPath(scope, pid = process.pid) {
39668
+ return path79.join(mcpSecretsDir(), `${pid}-${scope}.json`);
39669
+ }
39670
+ var registeredForCleanup = /* @__PURE__ */ new Set();
39671
+ function readFileVars(file) {
39672
+ try {
39673
+ const parsed = JSON.parse(fs68.readFileSync(file, "utf8"));
39674
+ if (!parsed || typeof parsed !== "object") return {};
39675
+ const out2 = {};
39676
+ for (const [k2, v] of Object.entries(parsed)) {
39677
+ if (typeof v === "string") out2[k2] = v;
39678
+ }
39679
+ return out2;
39680
+ } catch {
39681
+ return {};
39682
+ }
39683
+ }
39684
+ function pidAlive(pid) {
39685
+ try {
39686
+ process.kill(pid, 0);
39687
+ return true;
39688
+ } catch (err) {
39689
+ return err.code === "EPERM";
39690
+ }
39691
+ }
39692
+ function pruneStale(dir) {
39693
+ let names = [];
39694
+ try {
39695
+ names = fs68.readdirSync(dir);
39696
+ } catch {
39697
+ return;
39698
+ }
39699
+ for (const name of names) {
39700
+ const m = /^(\d+)-[a-z]+\.json$/.exec(name);
39701
+ if (!m) continue;
39702
+ const pid = Number(m[1]);
39703
+ if (pid === process.pid || pidAlive(pid)) continue;
39704
+ try {
39705
+ fs68.unlinkSync(path79.join(dir, name));
39706
+ } catch {
39707
+ }
39708
+ }
39709
+ }
39710
+ function writeMcpSecrets(vars, file) {
39711
+ try {
39712
+ const dir = path79.dirname(file);
39713
+ fs68.mkdirSync(dir, { recursive: true, mode: 448 });
39714
+ pruneStale(dir);
39715
+ const tmp = `${file}.${process.pid}.tmp`;
39716
+ fs68.writeFileSync(tmp, JSON.stringify(vars), { mode: 384 });
39717
+ fs68.renameSync(tmp, file);
39718
+ fs68.chmodSync(file, 384);
39719
+ if (!registeredForCleanup.has(file)) {
39720
+ registeredForCleanup.add(file);
39721
+ process.once("exit", () => {
39722
+ try {
39723
+ fs68.unlinkSync(file);
39724
+ } catch {
39725
+ }
39726
+ });
39727
+ }
39728
+ return file;
39729
+ } catch {
39730
+ return null;
39731
+ }
39732
+ }
39733
+ function mcpSecretEnv(scope, vars) {
39734
+ const file = writeMcpSecrets(vars, mcpSecretsPath(scope));
39735
+ if (file) return [{ name: MCP_SECRETS_FILE_ENV, value: file }];
39736
+ return Object.entries(vars).map(([name, value]) => ({ name, value }));
39737
+ }
39738
+ function loadMcpSecrets(env = process.env) {
39739
+ const file = env[MCP_SECRETS_FILE_ENV];
39740
+ if (!file) return;
39741
+ for (const [k2, v] of Object.entries(readFileVars(file))) {
39742
+ if (env[k2] === void 0) env[k2] = v;
39743
+ }
39744
+ }
39745
+
39746
+ // src/commands/preview-mcp.ts
39747
+ var PREVIEW_MCP_SERVER_NAME = "codeagent_preview";
39748
+ var PREVIEW_IPC_URL_ENV = "CODEAM_PREVIEW_IPC_URL";
39749
+ var PREVIEW_IPC_TOKEN_ENV = "CODEAM_PREVIEW_IPC_TOKEN";
39750
+ var START_TIMEOUT_MS = 27e4;
39751
+ var SHORT_TIMEOUT_MS = 2e4;
39752
+ var PREVIEW_TOOLS = [
39753
+ {
39754
+ name: "start_preview",
39755
+ description: "Open this project's live Preview in the user's CodeAgent app \u2014 the same thing as their Preview button: it installs dependencies if needed, starts the dev server, publishes it on a public URL and switches the user's screen to it. Use it after you change anything visual (UI, styles, layout, copy) so you and the user can check the result, or whenever the user asks to see the app. Returns the public URL (you can curl it) or the exact error. Reuses a preview that is already running. Usually leave the arguments out: the project is detected automatically. Pass command/args/port only if you know the exact dev command.",
39756
+ inputSchema: {
39757
+ type: "object",
39758
+ properties: {
39759
+ command: { type: "string", description: 'Dev server executable, e.g. "npm". Optional.' },
39760
+ args: { type: "array", items: { type: "string" }, description: 'e.g. ["run","dev"]. Optional.' },
39761
+ port: { type: "number", description: "Port the dev server listens on. Required with command." },
39762
+ framework: { type: "string", description: 'Label shown to the user, e.g. "next". Optional.' }
39763
+ },
39764
+ additionalProperties: false
39765
+ }
39766
+ },
39767
+ {
39768
+ name: "preview_status",
39769
+ description: "Current state of the Preview: running (with its URL), starting, error (with the reason) or idle. Use it when start_preview answered that the preview is still starting.",
39770
+ inputSchema: { type: "object", properties: {}, additionalProperties: false }
39771
+ },
39772
+ {
39773
+ name: "highlight_element",
39774
+ description: 'Point at an element in the running Preview: the user sees your cursor move to it and a labelled box drawn around it, scrolled into view. Use it to show the user exactly what you changed or what you are talking about ("this button", "the header spacing"). Takes a CSS selector (prefer ids, data-testid or specific classes you saw in the code). Several calls add several marks; clear_highlights removes them.',
39775
+ inputSchema: {
39776
+ type: "object",
39777
+ properties: {
39778
+ selector: { type: "string", description: 'CSS selector, e.g. "#checkout" or "[data-testid=hero-cta]".' },
39779
+ label: { type: "string", description: 'Short caption on the mark, e.g. "New CTA". Optional.' }
39780
+ },
39781
+ required: ["selector"],
39782
+ additionalProperties: false
39783
+ }
39784
+ },
39785
+ {
39786
+ name: "clear_highlights",
39787
+ description: "Remove every mark you drew in the Preview with highlight_element.",
39788
+ inputSchema: { type: "object", properties: {}, additionalProperties: false }
39789
+ },
39790
+ {
39791
+ name: "stop_preview",
39792
+ description: "Stop the Preview (dev server + public URL). Only when the user asks, or to restart it cleanly.",
39793
+ inputSchema: { type: "object", properties: {}, additionalProperties: false }
39794
+ }
39795
+ ];
39796
+ function previewMcpServer(bridge) {
39797
+ if (!bridge) return null;
39798
+ return {
39799
+ name: PREVIEW_MCP_SERVER_NAME,
39800
+ // Same runtime + entrypoint as this CLI — never trust the agent's PATH.
39801
+ command: process.execPath,
39802
+ args: [process.argv[1], "preview-mcp"],
39803
+ // The token rides the owner-only secrets file, never this env: the
39804
+ // claude ACP adapter copies MCP env onto argv (codeagent-5bew).
39805
+ env: [{ name: PREVIEW_IPC_URL_ENV, value: bridge.url }, ...mcpSecretEnv("preview", { [PREVIEW_IPC_TOKEN_ENV]: bridge.token })]
39806
+ };
39807
+ }
39808
+ function httpCall(baseUrl, token) {
39809
+ return async (path97, method, body, timeoutMs) => {
39810
+ const ac = new AbortController();
39811
+ const timer = setTimeout(() => ac.abort(), timeoutMs);
39812
+ try {
39813
+ const res = await fetch(`${baseUrl}${path97}`, {
39814
+ method,
39815
+ headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
39816
+ ...method === "POST" ? { body: JSON.stringify(body ?? {}) } : {},
39817
+ signal: ac.signal
39818
+ });
39819
+ return await res.json();
39820
+ } finally {
39821
+ clearTimeout(timer);
39822
+ }
39823
+ };
39824
+ }
39825
+ async function runPreviewTool(name, args2, call) {
39826
+ switch (name) {
39827
+ case "start_preview":
39828
+ return describeResult(await call("/preview/start", "POST", args2, START_TIMEOUT_MS));
39829
+ case "preview_status":
39830
+ return describeResult(await call("/preview/status", "GET", void 0, SHORT_TIMEOUT_MS));
39831
+ case "highlight_element":
39832
+ return describeAck(await call("/preview/highlight", "POST", args2, SHORT_TIMEOUT_MS));
39833
+ case "clear_highlights":
39834
+ return describeAck(await call("/preview/highlight", "POST", { clear: true }, SHORT_TIMEOUT_MS));
39835
+ case "stop_preview":
39836
+ return describeAck(await call("/preview/stop", "POST", {}, SHORT_TIMEOUT_MS));
39837
+ default:
39838
+ return { text: `Unknown tool: ${name}`, isError: true };
39839
+ }
39840
+ }
39841
+ function describeResult(raw) {
39842
+ const r = raw && typeof raw === "object" ? raw : {};
39843
+ switch (r.status) {
39844
+ case "running": {
39845
+ const inspector = r.inspector ? " You can point at elements with highlight_element." : " (No element highlighting for this framework.)";
39846
+ return {
39847
+ text: `Preview ${r.reused ? "already running" : "is live"}: ${String(r.url)} (${String(r.framework)}). The user's app is showing it now.${inspector}`,
39848
+ isError: false
39849
+ };
39850
+ }
39851
+ case "starting":
39852
+ return { text: String(r.message ?? "The preview is starting."), isError: false };
39853
+ case "idle":
39854
+ return { text: "No preview is running.", isError: false };
39855
+ case "error":
39856
+ return {
39857
+ text: `Preview failed at ${String(r.stage)}: ${String(r.message)}`,
39858
+ isError: true
39859
+ };
39860
+ default:
39861
+ return { text: `Unexpected answer from the preview bridge: ${JSON.stringify(raw)}`, isError: true };
39862
+ }
39863
+ }
39864
+ function describeAck(raw) {
39865
+ const r = raw && typeof raw === "object" ? raw : {};
39866
+ return { text: String(r.message ?? r.error ?? "done"), isError: r.ok !== true };
39867
+ }
39868
+ async function previewMcp() {
39869
+ const url2 = process.env[PREVIEW_IPC_URL_ENV];
39870
+ const token = process.env[PREVIEW_IPC_TOKEN_ENV];
39871
+ const { Server } = await import("@modelcontextprotocol/sdk/server/index.js");
39872
+ const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
39873
+ const { ListToolsRequestSchema, CallToolRequestSchema } = await import("@modelcontextprotocol/sdk/types.js");
39874
+ const call = url2 && token ? httpCall(url2, token) : null;
39875
+ const server = new Server({ name: PREVIEW_MCP_SERVER_NAME, version: "1.0.0" }, { capabilities: { tools: {} } });
39876
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: PREVIEW_TOOLS }));
39877
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
39878
+ if (!call) {
39879
+ return {
39880
+ content: [{ type: "text", text: "Preview is not available in this session." }],
39881
+ isError: true
39882
+ };
39883
+ }
39884
+ try {
39885
+ const { text, isError: isError2 } = await runPreviewTool(
39886
+ req.params.name,
39887
+ req.params.arguments ?? {},
39888
+ call
39889
+ );
39890
+ return { content: [{ type: "text", text }], isError: isError2 };
39891
+ } catch (err) {
39892
+ const aborted = err instanceof Error && err.name === "AbortError";
39893
+ return {
39894
+ content: [
39895
+ {
39896
+ type: "text",
39897
+ text: aborted ? "The preview is taking long \u2014 it keeps going in the background; call preview_status shortly." : `Preview bridge unreachable: ${err instanceof Error ? err.message : String(err)}`
39898
+ }
39899
+ ],
39900
+ isError: !aborted
39901
+ };
39902
+ }
39903
+ });
39904
+ await server.connect(new StdioServerTransport());
39905
+ }
39906
+
39348
39907
  // src/integrations/provision.ts
39908
+ function secretVars(ctx) {
39909
+ return {
39910
+ ...ctx.pluginAuthToken ? { CODEAM_MCP_PLUGIN_TOKEN: ctx.pluginAuthToken } : {},
39911
+ ...ctx.pollSecret ? { CODEAM_MCP_POLL_SECRET: ctx.pollSecret } : {}
39912
+ };
39913
+ }
39349
39914
  function buildMcpServersForStart(ctx) {
39915
+ const servers = buildIntegrationMcpServers(ctx);
39916
+ const preview = previewMcpServer(ctx.preview ?? null);
39917
+ return preview ? [...servers, preview] : servers;
39918
+ }
39919
+ function buildIntegrationMcpServers(ctx) {
39350
39920
  const manifest = readIntegrationsManifest();
39351
39921
  if (!manifest || manifest.integrations.length === 0) return [];
39352
39922
  if (!ctx.pluginAuthToken) {
@@ -39360,9 +39930,10 @@ function buildMcpServersForStart(ctx) {
39360
39930
  { name: "CODEAM_MCP_INTEGRATION_ID", value: entry.id },
39361
39931
  { name: "CODEAM_MCP_SESSION_ID", value: ctx.sessionId },
39362
39932
  { name: "CODEAM_MCP_PLUGIN_ID", value: ctx.pluginId },
39363
- // Plugin token in ENV, never argv — argv is visible via `ps`.
39364
- { name: "CODEAM_MCP_PLUGIN_TOKEN", value: ctx.pluginAuthToken },
39365
- ...ctx.pollSecret ? [{ name: "CODEAM_MCP_POLL_SECRET", value: ctx.pollSecret }] : []
39933
+ // ⚠️ Secrets via an owner-only FILE, not env values: the claude ACP
39934
+ // adapter copies this env onto the agent's argv (`--mcp-config`), where
39935
+ // `ps` shows it (codeagent-5bew). See `mcp-secrets.ts`.
39936
+ ...mcpSecretEnv("integrations", secretVars(ctx))
39366
39937
  ];
39367
39938
  servers.push({
39368
39939
  name: entry.id,
@@ -39391,8 +39962,7 @@ function buildMcpServersForStart(ctx) {
39391
39962
  env: [
39392
39963
  { name: "CODEAM_MCP_SESSION_ID", value: ctx.sessionId },
39393
39964
  { name: "CODEAM_MCP_PLUGIN_ID", value: ctx.pluginId },
39394
- { name: "CODEAM_MCP_PLUGIN_TOKEN", value: ctx.pluginAuthToken },
39395
- ...ctx.pollSecret ? [{ name: "CODEAM_MCP_POLL_SECRET", value: ctx.pollSecret }] : []
39965
+ ...mcpSecretEnv("integrations", secretVars(ctx))
39396
39966
  ]
39397
39967
  }
39398
39968
  ];
@@ -39518,6 +40088,299 @@ function mergeWithLocalMcpServers(integrationServers) {
39518
40088
  return merged;
39519
40089
  }
39520
40090
 
40091
+ // src/commands/start/agent-preview-bridge.ts
40092
+ var http11 = __toESM(require("http"));
40093
+ var import_node_crypto10 = require("crypto");
40094
+ var START_WAIT_MS = 24e4;
40095
+ var MAX_SELECTOR = 500;
40096
+ var MAX_LABEL = 80;
40097
+ var AgentPreviewBridge = class {
40098
+ server = null;
40099
+ listening = null;
40100
+ token = (0, import_node_crypto10.randomBytes)(24).toString("hex");
40101
+ ctx = null;
40102
+ /** The bring-up in flight, so two tool calls never start two dev servers. */
40103
+ inflight = null;
40104
+ lastError = null;
40105
+ bound = null;
40106
+ /** Start the loopback server once. `null` when it could not bind — the
40107
+ * preview tools are then simply absent, never a failed session. */
40108
+ listen() {
40109
+ if (this.listening) return this.listening;
40110
+ this.listening = new Promise((resolve12) => {
40111
+ const server = http11.createServer((req, res) => {
40112
+ void this.handle(req, res);
40113
+ });
40114
+ server.on("error", (err) => {
40115
+ log.warn("agent-preview", `bridge failed to listen: ${String(err)}`);
40116
+ resolve12(null);
40117
+ });
40118
+ server.listen(0, "127.0.0.1", () => {
40119
+ const addr = server.address();
40120
+ if (!addr || typeof addr === "string") {
40121
+ resolve12(null);
40122
+ return;
40123
+ }
40124
+ server.unref();
40125
+ this.server = server;
40126
+ this.bound = { url: `http://127.0.0.1:${addr.port}`, token: this.token };
40127
+ resolve12(this.bound);
40128
+ });
40129
+ });
40130
+ return this.listening;
40131
+ }
40132
+ /** The bound address once {@link listen} resolved, else null (sync, for
40133
+ * the MCP list rebuilds that happen mid-session). */
40134
+ address() {
40135
+ return this.bound;
40136
+ }
40137
+ /** Bind the live session. Tool calls before this answer "still starting". */
40138
+ attach(ctx) {
40139
+ this.ctx = ctx;
40140
+ }
40141
+ close() {
40142
+ this.server?.close();
40143
+ this.server = null;
40144
+ }
40145
+ // ─── Operations (public for tests) ─────────────────────────────────────
40146
+ async start(override, waitMs = START_WAIT_MS) {
40147
+ const ctx = this.ctx;
40148
+ if (!ctx?.pluginAuthToken) {
40149
+ return {
40150
+ status: "error",
40151
+ stage: "session",
40152
+ message: "The session is still starting (or has no pairing token) \u2014 try again in a few seconds."
40153
+ };
40154
+ }
40155
+ if (!this.inflight) {
40156
+ const run = this.launch(ctx, ctx.pluginAuthToken, override);
40157
+ this.inflight = run;
40158
+ void run.finally(() => {
40159
+ if (this.inflight === run) this.inflight = null;
40160
+ });
40161
+ }
40162
+ const inflight = this.inflight;
40163
+ let timer;
40164
+ const pending = new Promise((resolve12) => {
40165
+ timer = setTimeout(
40166
+ () => resolve12({
40167
+ status: "starting",
40168
+ message: "The preview is still coming up (dependencies or a slow dev server). It keeps going in the background \u2014 call preview_status in a minute."
40169
+ }),
40170
+ waitMs
40171
+ );
40172
+ timer.unref?.();
40173
+ });
40174
+ try {
40175
+ return await Promise.race([inflight, pending]);
40176
+ } finally {
40177
+ if (timer) clearTimeout(timer);
40178
+ }
40179
+ }
40180
+ status() {
40181
+ const ctx = this.ctx;
40182
+ if (!ctx) return { status: "idle" };
40183
+ const active2 = serving(ctx.sessionId);
40184
+ if (active2) return running(active2, true);
40185
+ if (this.inflight) return { status: "starting", message: "The preview is starting." };
40186
+ if (this.lastError) return { status: "error", ...this.lastError };
40187
+ return { status: "idle" };
40188
+ }
40189
+ async highlight(input) {
40190
+ const ctx = this.ctx;
40191
+ if (!ctx?.pluginAuthToken) return { ok: false, message: "The session is still starting." };
40192
+ const active2 = serving(ctx.sessionId);
40193
+ if (!active2) {
40194
+ return { ok: false, message: "No preview is running \u2014 call start_preview first." };
40195
+ }
40196
+ if (!active2.inspector) {
40197
+ return {
40198
+ ok: false,
40199
+ message: `Element highlighting needs the web inspector, which ${active2.framework} previews don't have.`
40200
+ };
40201
+ }
40202
+ let payload;
40203
+ if (input.clear === true) {
40204
+ payload = { clear: true };
40205
+ } else {
40206
+ const selector = typeof input.selector === "string" ? input.selector.trim() : "";
40207
+ if (!selector || selector.length > MAX_SELECTOR) {
40208
+ return { ok: false, message: `selector must be a CSS selector of 1-${MAX_SELECTOR} characters.` };
40209
+ }
40210
+ const label = typeof input.label === "string" ? input.label.trim().slice(0, MAX_LABEL) : "";
40211
+ payload = label ? { selector, label } : { selector };
40212
+ }
40213
+ const res = await postPreviewEvent({
40214
+ sessionId: ctx.sessionId,
40215
+ pluginId: ctx.pluginId,
40216
+ pluginAuthToken: ctx.pluginAuthToken,
40217
+ type: USER_EVENTS.PREVIEW_AGENT_HIGHLIGHT,
40218
+ payload
40219
+ });
40220
+ if (!res.ok) {
40221
+ return { ok: false, message: `Could not reach the app (${res.status}): ${res.message}` };
40222
+ }
40223
+ return {
40224
+ ok: true,
40225
+ message: payload.clear === true ? "Cleared your marks from the preview." : `Marked ${String(payload.selector)} in the user's preview. If the selector matches nothing, no mark appears.`
40226
+ };
40227
+ }
40228
+ async stop() {
40229
+ const ctx = this.ctx;
40230
+ if (!ctx?.pluginAuthToken) return { ok: false, message: "The session is still starting." };
40231
+ if (!activePreviews.has(ctx.sessionId)) return { ok: true, message: "No preview was running." };
40232
+ await killPreview(ctx.sessionId);
40233
+ resetBuildHealState(ctx.sessionId);
40234
+ await postPreviewEvent({
40235
+ sessionId: ctx.sessionId,
40236
+ pluginId: ctx.pluginId,
40237
+ pluginAuthToken: ctx.pluginAuthToken,
40238
+ type: USER_EVENTS.PREVIEW_STOPPED,
40239
+ payload: { reason: "user", origin: "agent" }
40240
+ });
40241
+ return { ok: true, message: "Preview stopped." };
40242
+ }
40243
+ // ─── Internals ─────────────────────────────────────────────────────────
40244
+ async launch(ctx, pluginAuthToken, override) {
40245
+ this.lastError = null;
40246
+ const already = serving(ctx.sessionId);
40247
+ if (already) {
40248
+ await postPreviewEvent({
40249
+ sessionId: ctx.sessionId,
40250
+ pluginId: ctx.pluginId,
40251
+ pluginAuthToken,
40252
+ type: USER_EVENTS.PREVIEW_READY,
40253
+ payload: {
40254
+ url: already.url,
40255
+ framework: already.framework,
40256
+ port: already.detection.port,
40257
+ origin: "agent"
40258
+ }
40259
+ });
40260
+ return running(already, true);
40261
+ }
40262
+ void postPreviewEvent({
40263
+ sessionId: ctx.sessionId,
40264
+ pluginId: ctx.pluginId,
40265
+ pluginAuthToken,
40266
+ type: USER_EVENTS.PREVIEW_DETECTION_PENDING,
40267
+ payload: { origin: "agent" }
40268
+ });
40269
+ const detection = (override && detectionFromOverride(override)) ?? await resolvePreviewDetection({ ctx, runtime: ctx.getRuntime(), pluginAuthToken, origin: "agent" });
40270
+ if (!detection) {
40271
+ const err2 = { stage: "detection", message: "Could not work out how to start this project." };
40272
+ this.lastError = err2;
40273
+ return { status: "error", ...err2 };
40274
+ }
40275
+ let failure = null;
40276
+ await startPreviewFromDetection(ctx, detection, pluginAuthToken, {
40277
+ origin: "agent",
40278
+ onEvent: (type, payload) => {
40279
+ if (type === USER_EVENTS.PREVIEW_ERROR) {
40280
+ failure = {
40281
+ stage: String(payload.stage ?? "spawn"),
40282
+ message: String(payload.message ?? "The preview failed to start.")
40283
+ };
40284
+ }
40285
+ }
40286
+ });
40287
+ const up = serving(ctx.sessionId);
40288
+ if (up) return running(up, false);
40289
+ const err = failure ?? { stage: "spawn", message: "The preview did not come up." };
40290
+ this.lastError = err;
40291
+ return { status: "error", ...err };
40292
+ }
40293
+ async handle(req, res) {
40294
+ const reply = (code, body) => {
40295
+ res.writeHead(code, { "content-type": "application/json" });
40296
+ res.end(JSON.stringify(body));
40297
+ };
40298
+ if (!authorized(req.headers.authorization, this.token)) return reply(401, { error: "unauthorized" });
40299
+ try {
40300
+ const body = req.method === "POST" ? await readJson(req) : {};
40301
+ switch (`${req.method} ${req.url}`) {
40302
+ case "POST /preview/start":
40303
+ return reply(200, await this.start(overrideFrom(body)));
40304
+ case "GET /preview/status":
40305
+ return reply(200, this.status());
40306
+ case "POST /preview/highlight":
40307
+ return reply(200, await this.highlight(body));
40308
+ case "POST /preview/stop":
40309
+ return reply(200, await this.stop());
40310
+ default:
40311
+ return reply(404, { error: "not found" });
40312
+ }
40313
+ } catch (err) {
40314
+ log.warn("agent-preview", `bridge request failed: ${String(err)}`);
40315
+ return reply(500, { error: err instanceof Error ? err.message : String(err) });
40316
+ }
40317
+ }
40318
+ };
40319
+ function serving(sessionId) {
40320
+ const active2 = activePreviews.get(sessionId);
40321
+ if (!active2 || active2.devServer && active2.devServer.exitCode !== null) return null;
40322
+ return active2;
40323
+ }
40324
+ function running(active2, reused) {
40325
+ return {
40326
+ status: "running",
40327
+ url: active2.url,
40328
+ framework: active2.framework,
40329
+ ...reused ? { reused: true } : {},
40330
+ inspector: Boolean(active2.inspector)
40331
+ };
40332
+ }
40333
+ function detectionFromOverride(o) {
40334
+ if (!o.command || !Number.isInteger(o.port) || o.port <= 0 || o.port > 65535) return null;
40335
+ return {
40336
+ framework: o.framework?.trim() || "custom",
40337
+ command: o.command,
40338
+ args: Array.isArray(o.args) ? o.args.map(String) : [],
40339
+ port: o.port,
40340
+ // Any Local/ready/listening line; the TCP probe is the real fallback.
40341
+ ready_pattern: o.ready_pattern?.trim() || "(ready|local:|listening|started server|compiled)"
40342
+ };
40343
+ }
40344
+ function overrideFrom(body) {
40345
+ if (typeof body.command !== "string" || typeof body.port !== "number") return void 0;
40346
+ return {
40347
+ command: body.command,
40348
+ args: Array.isArray(body.args) ? body.args.map(String) : void 0,
40349
+ port: body.port,
40350
+ framework: typeof body.framework === "string" ? body.framework : void 0,
40351
+ ready_pattern: typeof body.ready_pattern === "string" ? body.ready_pattern : void 0
40352
+ };
40353
+ }
40354
+ function authorized(header, token) {
40355
+ const presented = Buffer.from((header ?? "").replace(/^Bearer\s+/i, ""));
40356
+ const expected = Buffer.from(token);
40357
+ return presented.length === expected.length && (0, import_node_crypto10.timingSafeEqual)(presented, expected);
40358
+ }
40359
+ function readJson(req) {
40360
+ return new Promise((resolve12, reject) => {
40361
+ let raw = "";
40362
+ req.setEncoding("utf8");
40363
+ req.on("data", (chunk) => {
40364
+ raw += chunk;
40365
+ if (raw.length > 64e3) {
40366
+ reject(new Error("body too large"));
40367
+ req.destroy();
40368
+ }
40369
+ });
40370
+ req.on("end", () => {
40371
+ if (!raw) return resolve12({});
40372
+ try {
40373
+ const parsed = JSON.parse(raw);
40374
+ resolve12(parsed && typeof parsed === "object" ? parsed : {});
40375
+ } catch {
40376
+ reject(new Error("invalid JSON"));
40377
+ }
40378
+ });
40379
+ req.on("error", reject);
40380
+ });
40381
+ }
40382
+ var agentPreviewBridge = new AgentPreviewBridge();
40383
+
39521
40384
  // src/integrations/detect-stack.ts
39522
40385
  var import_node_fs13 = __toESM(require("fs"));
39523
40386
  var import_node_path13 = __toESM(require("path"));
@@ -39669,7 +40532,7 @@ function logMentionOutcome(result) {
39669
40532
  }
39670
40533
 
39671
40534
  // src/agents/acp/command-handlers.ts
39672
- var import_node_child_process23 = require("child_process");
40535
+ var import_node_child_process24 = require("child_process");
39673
40536
 
39674
40537
  // src/agents/acp/buildAcpPromptBlocks.ts
39675
40538
  var MIME_FROM_EXT = {
@@ -40631,7 +41494,7 @@ async function prewarmNewMcpEntries(manifest, previousIds) {
40631
41494
  fresh.map(
40632
41495
  (e) => new Promise((resolve12) => {
40633
41496
  const mcp = e.delivery.mcp;
40634
- const child = (0, import_node_child_process23.execFile)(
41497
+ const child = (0, import_node_child_process24.execFile)(
40635
41498
  mcp.command,
40636
41499
  [...mcp.args, "--help"],
40637
41500
  { timeout: 9e4 },
@@ -40658,7 +41521,8 @@ async function integrationsSyncH(ctx) {
40658
41521
  sessionId: opts.sessionId,
40659
41522
  pluginId: opts.pluginId,
40660
41523
  pluginAuthToken: opts.pluginAuthToken,
40661
- pollSecret: opts.pollSecret
41524
+ pollSecret: opts.pollSecret,
41525
+ preview: agentPreviewBridge.address()
40662
41526
  })
40663
41527
  );
40664
41528
  const applied = await client3.reprovisionMcp(servers);
@@ -41295,7 +42159,7 @@ var AcpHistory = class {
41295
42159
  this.summary = trimmed.length > 120 ? trimmed.slice(0, 117) + "\u2026" : trimmed;
41296
42160
  }
41297
42161
  this.messages.push({
41298
- id: (0, import_node_crypto10.randomUUID)(),
42162
+ id: (0, import_node_crypto11.randomUUID)(),
41299
42163
  role: "user",
41300
42164
  text,
41301
42165
  timestamp: Date.now(),
@@ -41311,7 +42175,7 @@ var AcpHistory = class {
41311
42175
  appendAgentReply(text, agentId = this.opts.agent) {
41312
42176
  if (text.length === 0) return;
41313
42177
  this.messages.push({
41314
- id: (0, import_node_crypto10.randomUUID)(),
42178
+ id: (0, import_node_crypto11.randomUUID)(),
41315
42179
  role: "agent",
41316
42180
  text,
41317
42181
  timestamp: Date.now(),
@@ -41799,11 +42663,11 @@ async function runAcpSession(opts) {
41799
42663
  if (swapOpts.house) {
41800
42664
  houseWireId = swapOpts.wireId ?? HOUSE_AGENT_ID;
41801
42665
  if (pendingHouseConfig) {
41802
- persistHouseProxyConfig(pendingHouseConfig);
42666
+ persistHouseProxyConfig(pendingHouseConfig, deployIdFromWorkspace(process.cwd()) ?? void 0);
41803
42667
  pendingHouseConfig = null;
41804
42668
  }
41805
42669
  } else if (wasHouse) {
41806
- clearHouseProxyConfig();
42670
+ clearHouseProxyConfig(deployIdFromWorkspace(process.cwd()) ?? void 0);
41807
42671
  }
41808
42672
  const managedBanner = swapOpts.house && isManagedProviderId(houseWireId) ? houseWireId : null;
41809
42673
  void publisher.publishOutput({
@@ -41842,17 +42706,17 @@ async function runAcpSession(opts) {
41842
42706
  switchCredentialEnv = provisionAgentCredentials(agentId, auth);
41843
42707
  },
41844
42708
  provisionHouseProxy: ({ baseUrl, token, model, managedAgentId }) => {
41845
- const claudeConfigDir = path80.join(
41846
- os53.homedir(),
42709
+ const claudeConfigDir = path82.join(
42710
+ os55.homedir(),
41847
42711
  ".codeam",
41848
42712
  "house-claude",
41849
42713
  `switch-${opts.pluginId}`
41850
42714
  );
41851
42715
  try {
41852
- fs69.mkdirSync(claudeConfigDir, { recursive: true, mode: 448 });
42716
+ fs71.mkdirSync(claudeConfigDir, { recursive: true, mode: 448 });
41853
42717
  } catch {
41854
42718
  }
41855
- const memoryFile = path80.join(claudeConfigDir, "CLAUDE.md");
42719
+ const memoryFile = path82.join(claudeConfigDir, "CLAUDE.md");
41856
42720
  ensureBeadsWorkflowHint(void 0, memoryFile);
41857
42721
  ensureAgentStandard(void 0, memoryFile);
41858
42722
  const cfg = {
@@ -43075,9 +43939,9 @@ function pickPinnedSession(pinnedId, listSessions2) {
43075
43939
  }
43076
43940
 
43077
43941
  // src/agents/retired-proxy-cleanup.ts
43078
- var fs70 = __toESM(require("fs"));
43079
- var path81 = __toESM(require("path"));
43080
- var os54 = __toESM(require("os"));
43942
+ var fs72 = __toESM(require("fs"));
43943
+ var path83 = __toESM(require("path"));
43944
+ var os56 = __toESM(require("os"));
43081
43945
  var RETIRED_PROXY_RE = /^https?:\/\/(?:127\.0\.0\.1|localhost|\[::1\]):8787(?:[/?#]|$)/i;
43082
43946
  var HEADROOM_CMD_RE = /(^|[\s/"'])headroom(\s|$)/i;
43083
43947
  var MARKETPLACE_KEY = "headroom-marketplace";
@@ -43086,12 +43950,12 @@ function isHeadroomHook(group) {
43086
43950
  (h) => typeof h?.command === "string" && HEADROOM_CMD_RE.test(h.command)
43087
43951
  );
43088
43952
  }
43089
- function sanitizeRetiredProxyConfig(homeDir2 = os54.homedir()) {
43953
+ function sanitizeRetiredProxyConfig(homeDir2 = os56.homedir()) {
43090
43954
  const out2 = { inspected: false, changed: false, removed: [] };
43091
- const file = path81.join(homeDir2, ".claude", "settings.json");
43955
+ const file = path83.join(homeDir2, ".claude", "settings.json");
43092
43956
  let parsed;
43093
43957
  try {
43094
- parsed = JSON.parse(fs70.readFileSync(file, "utf8"));
43958
+ parsed = JSON.parse(fs72.readFileSync(file, "utf8"));
43095
43959
  } catch {
43096
43960
  return out2;
43097
43961
  }
@@ -43133,9 +43997,9 @@ function sanitizeRetiredProxyConfig(homeDir2 = os54.homedir()) {
43133
43997
  if (!out2.changed) return out2;
43134
43998
  try {
43135
43999
  const tmp = `${file}.codeam.tmp`;
43136
- fs70.writeFileSync(tmp, `${JSON.stringify(parsed, null, 2)}
44000
+ fs72.writeFileSync(tmp, `${JSON.stringify(parsed, null, 2)}
43137
44001
  `, { mode: 384 });
43138
- fs70.renameSync(tmp, file);
44002
+ fs72.renameSync(tmp, file);
43139
44003
  } catch {
43140
44004
  out2.changed = false;
43141
44005
  }
@@ -43667,7 +44531,7 @@ var AcpDriver = class {
43667
44531
  };
43668
44532
 
43669
44533
  // src/baton/transcript-mirror.ts
43670
- var fs71 = __toESM(require("fs"));
44534
+ var fs73 = __toESM(require("fs"));
43671
44535
  var TranscriptMirror = class {
43672
44536
  constructor(deps) {
43673
44537
  this.deps = deps;
@@ -43761,7 +44625,7 @@ var TranscriptMirror = class {
43761
44625
  }
43762
44626
  };
43763
44627
  function defaultWatch(file, onChange) {
43764
- const w3 = fs71.watch(file, { persistent: false }, () => onChange());
44628
+ const w3 = fs73.watch(file, { persistent: false }, () => onChange());
43765
44629
  return () => w3.close();
43766
44630
  }
43767
44631
 
@@ -44071,7 +44935,7 @@ function toEpochMs(ts) {
44071
44935
  }
44072
44936
 
44073
44937
  // src/services/keep-awake.ts
44074
- var import_node_child_process24 = require("child_process");
44938
+ var import_node_child_process25 = require("child_process");
44075
44939
  function keepDeviceAwake(deps = {}) {
44076
44940
  const env = deps.env ?? process.env;
44077
44941
  const isLocal = deps.isLocal ?? isLocalSession(env);
@@ -44081,7 +44945,7 @@ function keepDeviceAwake(deps = {}) {
44081
44945
  if (env.CODEAM_NO_KEEP_AWAKE === "1") return noop;
44082
44946
  const command2 = deps.command !== void 0 ? deps.command : createOsStrategy().keepAwakeCommand(deps.pid ?? process.pid);
44083
44947
  if (!command2) return noop;
44084
- const spawnFn = deps.spawnFn ?? import_node_child_process24.spawn;
44948
+ const spawnFn = deps.spawnFn ?? import_node_child_process25.spawn;
44085
44949
  let child = null;
44086
44950
  try {
44087
44951
  child = spawnFn(command2.cmd, command2.args, { stdio: "ignore", detached: true });
@@ -44107,16 +44971,16 @@ function keepDeviceAwake(deps = {}) {
44107
44971
  }
44108
44972
 
44109
44973
  // src/agents/claude/onboarding.ts
44110
- var fs72 = __toESM(require("fs"));
44111
- var os56 = __toESM(require("os"));
44112
- var path82 = __toESM(require("path"));
44974
+ var fs74 = __toESM(require("fs"));
44975
+ var os58 = __toESM(require("os"));
44976
+ var path84 = __toESM(require("path"));
44113
44977
  var ONBOARDING_VERSION_SENTINEL = "9999.0.0";
44114
44978
  function ensureClaudeOnboarded(cwd) {
44115
44979
  try {
44116
- const file = path82.join(os56.homedir(), ".claude.json");
44980
+ const file = path84.join(os58.homedir(), ".claude.json");
44117
44981
  let config = {};
44118
44982
  try {
44119
- config = JSON.parse(fs72.readFileSync(file, "utf8"));
44983
+ config = JSON.parse(fs74.readFileSync(file, "utf8"));
44120
44984
  } catch {
44121
44985
  }
44122
44986
  let changed = false;
@@ -44141,8 +45005,8 @@ function ensureClaudeOnboarded(cwd) {
44141
45005
  }
44142
45006
  }
44143
45007
  if (!changed) return;
44144
- fs72.mkdirSync(path82.dirname(file), { recursive: true });
44145
- fs72.writeFileSync(file, JSON.stringify(config, null, 2));
45008
+ fs74.mkdirSync(path84.dirname(file), { recursive: true });
45009
+ fs74.writeFileSync(file, JSON.stringify(config, null, 2));
44146
45010
  log.info(
44147
45011
  "claude",
44148
45012
  `pre-completed Claude onboarding${cwd ? ` + trusted workspace ${cwd}` : ""}`
@@ -44265,12 +45129,20 @@ async function start(requestedAgent, presetSession) {
44265
45129
  agent: isHouseProxyEnv(process.env) ? houseRailWireId(process.env) : session.agent
44266
45130
  });
44267
45131
  }
45132
+ const previewBridge = await agentPreviewBridge.listen();
45133
+ agentPreviewBridge.attach({
45134
+ sessionId: session.id,
45135
+ pluginId,
45136
+ pluginAuthToken: session.pluginAuthToken ?? void 0,
45137
+ getRuntime: () => createInteractiveAgentStrategy(session.agent, createOsStrategy())
45138
+ });
44268
45139
  const mcpServers = mergeWithLocalMcpServers(
44269
45140
  buildMcpServersForStart({
44270
45141
  sessionId: session.id,
44271
45142
  pluginId,
44272
45143
  pluginAuthToken: session.pluginAuthToken ?? void 0,
44273
- pollSecret: session.pollSecret
45144
+ pollSecret: session.pollSecret,
45145
+ preview: previewBridge
44274
45146
  })
44275
45147
  );
44276
45148
  provisionSkillsForStart();
@@ -44911,8 +45783,8 @@ var import_picocolors10 = __toESM(require("picocolors"));
44911
45783
  var import_child_process30 = require("child_process");
44912
45784
  var import_util4 = require("util");
44913
45785
  var import_picocolors8 = __toESM(require("picocolors"));
44914
- var path83 = __toESM(require("path"));
44915
- var execFileP5 = (0, import_util4.promisify)(import_child_process30.execFile);
45786
+ var path85 = __toESM(require("path"));
45787
+ var execFileP6 = (0, import_util4.promisify)(import_child_process30.execFile);
44916
45788
  var MAX_BUFFER = 8 * 1024 * 1024;
44917
45789
  function resetStdinForChild() {
44918
45790
  if (process.stdin.isTTY) {
@@ -44929,11 +45801,11 @@ var GitHubCodespacesProvider = class {
44929
45801
  available = true;
44930
45802
  async authorize() {
44931
45803
  try {
44932
- await execFileP5("gh", ["--version"], { maxBuffer: MAX_BUFFER });
45804
+ await execFileP6("gh", ["--version"], { maxBuffer: MAX_BUFFER });
44933
45805
  } catch {
44934
45806
  await this.tryInstallGh();
44935
45807
  try {
44936
- await execFileP5("gh", ["--version"], { maxBuffer: MAX_BUFFER });
45808
+ await execFileP6("gh", ["--version"], { maxBuffer: MAX_BUFFER });
44937
45809
  } catch {
44938
45810
  throw new Error(
44939
45811
  [
@@ -44949,7 +45821,7 @@ var GitHubCodespacesProvider = class {
44949
45821
  }
44950
45822
  let isAuthed = false;
44951
45823
  try {
44952
- await execFileP5("gh", ["auth", "status"], { maxBuffer: MAX_BUFFER });
45824
+ await execFileP6("gh", ["auth", "status"], { maxBuffer: MAX_BUFFER });
44953
45825
  isAuthed = true;
44954
45826
  } catch {
44955
45827
  }
@@ -45025,7 +45897,7 @@ var GitHubCodespacesProvider = class {
45025
45897
  */
45026
45898
  async getActiveGhUser() {
45027
45899
  try {
45028
- const { stdout } = await execFileP5(
45900
+ const { stdout } = await execFileP6(
45029
45901
  "gh",
45030
45902
  ["api", "user", "--jq", ".login"],
45031
45903
  { maxBuffer: MAX_BUFFER }
@@ -45045,7 +45917,7 @@ var GitHubCodespacesProvider = class {
45045
45917
  */
45046
45918
  async hasCodespaceScope() {
45047
45919
  try {
45048
- const { stdout } = await execFileP5(
45920
+ const { stdout } = await execFileP6(
45049
45921
  "gh",
45050
45922
  ["api", "-i", "user"],
45051
45923
  { maxBuffer: MAX_BUFFER }
@@ -45094,7 +45966,7 @@ var GitHubCodespacesProvider = class {
45094
45966
  let installCmd = null;
45095
45967
  if (platform3 === "darwin") {
45096
45968
  try {
45097
- await execFileP5("brew", ["--version"], { maxBuffer: MAX_BUFFER });
45969
+ await execFileP6("brew", ["--version"], { maxBuffer: MAX_BUFFER });
45098
45970
  } catch {
45099
45971
  wt(
45100
45972
  [
@@ -45113,7 +45985,7 @@ var GitHubCodespacesProvider = class {
45113
45985
  };
45114
45986
  } else if (platform3 === "win32") {
45115
45987
  try {
45116
- await execFileP5("winget", ["--version"], { maxBuffer: MAX_BUFFER });
45988
+ await execFileP6("winget", ["--version"], { maxBuffer: MAX_BUFFER });
45117
45989
  } catch {
45118
45990
  wt(
45119
45991
  [
@@ -45192,7 +46064,7 @@ var GitHubCodespacesProvider = class {
45192
46064
  "200"
45193
46065
  );
45194
46066
  try {
45195
- const { stdout } = await execFileP5("gh", args2, { maxBuffer: MAX_BUFFER });
46067
+ const { stdout } = await execFileP6("gh", args2, { maxBuffer: MAX_BUFFER });
45196
46068
  return JSON.parse(stdout);
45197
46069
  } catch {
45198
46070
  return [];
@@ -45201,7 +46073,7 @@ var GitHubCodespacesProvider = class {
45201
46073
  const own = await fetchRepos();
45202
46074
  let orgRepos = [];
45203
46075
  try {
45204
- const { stdout } = await execFileP5(
46076
+ const { stdout } = await execFileP6(
45205
46077
  "gh",
45206
46078
  ["api", "--paginate", "user/orgs", "--jq", ".[].login"],
45207
46079
  { maxBuffer: MAX_BUFFER }
@@ -45238,7 +46110,7 @@ var GitHubCodespacesProvider = class {
45238
46110
  */
45239
46111
  async listMachineTypes(projectId) {
45240
46112
  try {
45241
- const { stdout } = await execFileP5(
46113
+ const { stdout } = await execFileP6(
45242
46114
  "gh",
45243
46115
  ["api", `/repos/${projectId}/codespaces/machines`],
45244
46116
  { maxBuffer: MAX_BUFFER }
@@ -45269,7 +46141,7 @@ var GitHubCodespacesProvider = class {
45269
46141
  const machine = machineTypeId ?? await this.pickDefaultMachine(projectId);
45270
46142
  const args2 = ["codespace", "create", "-R", projectId, "--default-permissions"];
45271
46143
  if (machine) args2.push("-m", machine);
45272
- const { stdout } = await execFileP5(
46144
+ const { stdout } = await execFileP6(
45273
46145
  "gh",
45274
46146
  args2,
45275
46147
  { maxBuffer: MAX_BUFFER, timeout: 12e4 }
@@ -45309,7 +46181,7 @@ var GitHubCodespacesProvider = class {
45309
46181
  async waitUntilAvailable(name) {
45310
46182
  const deadline = Date.now() + 5 * 60 * 1e3;
45311
46183
  while (Date.now() < deadline) {
45312
- const { stdout } = await execFileP5(
46184
+ const { stdout } = await execFileP6(
45313
46185
  "gh",
45314
46186
  ["codespace", "list", "--json", "name,state"],
45315
46187
  { maxBuffer: MAX_BUFFER }
@@ -45327,7 +46199,7 @@ var GitHubCodespacesProvider = class {
45327
46199
  }
45328
46200
  async exec(workspaceId, command2) {
45329
46201
  try {
45330
- const { stdout, stderr } = await execFileP5(
46202
+ const { stdout, stderr } = await execFileP6(
45331
46203
  "gh",
45332
46204
  ["codespace", "ssh", "-c", workspaceId, "--", command2],
45333
46205
  { maxBuffer: MAX_BUFFER, timeout: 6e5 }
@@ -45400,7 +46272,7 @@ var GitHubCodespacesProvider = class {
45400
46272
  });
45401
46273
  }
45402
46274
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
45403
- const remoteDir = path83.posix.dirname(remotePath);
46275
+ const remoteDir = path85.posix.dirname(remotePath);
45404
46276
  const parts = [
45405
46277
  `mkdir -p ${shellQuote(remoteDir)}`,
45406
46278
  `cat > ${shellQuote(remotePath)}`
@@ -45432,7 +46304,7 @@ var GitHubCodespacesProvider = class {
45432
46304
  try {
45433
46305
  const args2 = ["codespace", "list", "--json", "name,displayName,state,lastUsedAt"];
45434
46306
  if (projectId) args2.push("--repo", projectId);
45435
- const { stdout } = await execFileP5("gh", args2, { maxBuffer: MAX_BUFFER });
46307
+ const { stdout } = await execFileP6("gh", args2, { maxBuffer: MAX_BUFFER });
45436
46308
  const list = JSON.parse(stdout);
45437
46309
  return list.map((c2) => ({
45438
46310
  id: c2.name,
@@ -45447,7 +46319,7 @@ var GitHubCodespacesProvider = class {
45447
46319
  }
45448
46320
  async startWorkspace(workspaceId) {
45449
46321
  try {
45450
- await execFileP5(
46322
+ await execFileP6(
45451
46323
  "gh",
45452
46324
  ["api", "-X", "POST", `/user/codespaces/${workspaceId}/start`],
45453
46325
  { maxBuffer: MAX_BUFFER, timeout: 6e4 }
@@ -45470,9 +46342,9 @@ function shellQuote(s) {
45470
46342
  // src/services/providers/gitpod.ts
45471
46343
  var import_child_process31 = require("child_process");
45472
46344
  var import_util5 = require("util");
45473
- var path84 = __toESM(require("path"));
46345
+ var path86 = __toESM(require("path"));
45474
46346
  var import_picocolors9 = __toESM(require("picocolors"));
45475
- var execFileP6 = (0, import_util5.promisify)(import_child_process31.execFile);
46347
+ var execFileP7 = (0, import_util5.promisify)(import_child_process31.execFile);
45476
46348
  var MAX_BUFFER2 = 8 * 1024 * 1024;
45477
46349
  function resetStdinForChild2() {
45478
46350
  if (process.stdin.isTTY) {
@@ -45489,7 +46361,7 @@ var GitpodProvider = class {
45489
46361
  available = true;
45490
46362
  async authorize() {
45491
46363
  try {
45492
- await execFileP6("gitpod", ["--version"], { maxBuffer: MAX_BUFFER2 });
46364
+ await execFileP7("gitpod", ["--version"], { maxBuffer: MAX_BUFFER2 });
45493
46365
  } catch {
45494
46366
  throw new Error(
45495
46367
  [
@@ -45502,7 +46374,7 @@ var GitpodProvider = class {
45502
46374
  );
45503
46375
  }
45504
46376
  try {
45505
- await execFileP6("gitpod", ["whoami"], { maxBuffer: MAX_BUFFER2 });
46377
+ await execFileP7("gitpod", ["whoami"], { maxBuffer: MAX_BUFFER2 });
45506
46378
  return;
45507
46379
  } catch {
45508
46380
  }
@@ -45522,7 +46394,7 @@ var GitpodProvider = class {
45522
46394
  }
45523
46395
  async listProjects() {
45524
46396
  try {
45525
- const { stdout } = await execFileP6(
46397
+ const { stdout } = await execFileP7(
45526
46398
  "gitpod",
45527
46399
  ["workspace", "list", "--output", "json", "--limit", "200"],
45528
46400
  { maxBuffer: MAX_BUFFER2 }
@@ -45555,7 +46427,7 @@ var GitpodProvider = class {
45555
46427
  async createWorkspace(projectId, machineTypeId) {
45556
46428
  const args2 = ["workspace", "create", projectId, "--start", "--output", "json"];
45557
46429
  if (machineTypeId) args2.push("--class", machineTypeId);
45558
- const { stdout } = await execFileP6("gitpod", args2, {
46430
+ const { stdout } = await execFileP7("gitpod", args2, {
45559
46431
  maxBuffer: MAX_BUFFER2,
45560
46432
  timeout: 3e5
45561
46433
  });
@@ -45579,7 +46451,7 @@ var GitpodProvider = class {
45579
46451
  const deadline = Date.now() + 5 * 60 * 1e3;
45580
46452
  while (Date.now() < deadline) {
45581
46453
  try {
45582
- const { stdout } = await execFileP6(
46454
+ const { stdout } = await execFileP7(
45583
46455
  "gitpod",
45584
46456
  ["workspace", "get", workspaceId, "--output", "json"],
45585
46457
  { maxBuffer: MAX_BUFFER2 }
@@ -45597,7 +46469,7 @@ var GitpodProvider = class {
45597
46469
  }
45598
46470
  async listMachineTypes(_projectId) {
45599
46471
  try {
45600
- const { stdout } = await execFileP6(
46472
+ const { stdout } = await execFileP7(
45601
46473
  "gitpod",
45602
46474
  ["organization", "list-classes", "--output", "json"],
45603
46475
  { maxBuffer: MAX_BUFFER2 }
@@ -45615,7 +46487,7 @@ var GitpodProvider = class {
45615
46487
  async listExistingWorkspaces(projectId) {
45616
46488
  try {
45617
46489
  const args2 = ["workspace", "list", "--output", "json", "--limit", "200"];
45618
- const { stdout } = await execFileP6("gitpod", args2, { maxBuffer: MAX_BUFFER2 });
46490
+ const { stdout } = await execFileP7("gitpod", args2, { maxBuffer: MAX_BUFFER2 });
45619
46491
  const list = JSON.parse(stdout);
45620
46492
  return list.filter((w3) => !projectId || w3.contextUrl === projectId).map((w3) => ({
45621
46493
  id: w3.id,
@@ -45630,7 +46502,7 @@ var GitpodProvider = class {
45630
46502
  }
45631
46503
  async startWorkspace(workspaceId) {
45632
46504
  try {
45633
- await execFileP6(
46505
+ await execFileP7(
45634
46506
  "gitpod",
45635
46507
  ["workspace", "start", workspaceId],
45636
46508
  { maxBuffer: MAX_BUFFER2, timeout: 6e4 }
@@ -45646,7 +46518,7 @@ var GitpodProvider = class {
45646
46518
  }
45647
46519
  async exec(workspaceId, command2) {
45648
46520
  try {
45649
- const { stdout, stderr } = await execFileP6(
46521
+ const { stdout, stderr } = await execFileP7(
45650
46522
  "gitpod",
45651
46523
  ["workspace", "ssh", workspaceId, "--", command2],
45652
46524
  { maxBuffer: MAX_BUFFER2, timeout: 6e5 }
@@ -45710,7 +46582,7 @@ var GitpodProvider = class {
45710
46582
  });
45711
46583
  }
45712
46584
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
45713
- const remoteDir = path84.posix.dirname(remotePath);
46585
+ const remoteDir = path86.posix.dirname(remotePath);
45714
46586
  const parts = [
45715
46587
  `mkdir -p ${shellQuote2(remoteDir)}`,
45716
46588
  `cat > ${shellQuote2(remotePath)}`
@@ -45746,8 +46618,8 @@ function shellQuote2(s) {
45746
46618
  // src/services/providers/gitlab-workspaces.ts
45747
46619
  var import_child_process32 = require("child_process");
45748
46620
  var import_util6 = require("util");
45749
- var path85 = __toESM(require("path"));
45750
- var execFileP7 = (0, import_util6.promisify)(import_child_process32.execFile);
46621
+ var path87 = __toESM(require("path"));
46622
+ var execFileP8 = (0, import_util6.promisify)(import_child_process32.execFile);
45751
46623
  var MAX_BUFFER3 = 8 * 1024 * 1024;
45752
46624
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
45753
46625
  function resetStdinForChild3() {
@@ -45765,7 +46637,7 @@ var GitLabWorkspacesProvider = class {
45765
46637
  available = true;
45766
46638
  async authorize() {
45767
46639
  try {
45768
- await execFileP7("glab", ["--version"], { maxBuffer: MAX_BUFFER3 });
46640
+ await execFileP8("glab", ["--version"], { maxBuffer: MAX_BUFFER3 });
45769
46641
  } catch {
45770
46642
  throw new Error(
45771
46643
  [
@@ -45779,7 +46651,7 @@ var GitLabWorkspacesProvider = class {
45779
46651
  );
45780
46652
  }
45781
46653
  try {
45782
- await execFileP7("glab", ["auth", "status"], { maxBuffer: MAX_BUFFER3 });
46654
+ await execFileP8("glab", ["auth", "status"], { maxBuffer: MAX_BUFFER3 });
45783
46655
  return;
45784
46656
  } catch {
45785
46657
  }
@@ -45803,7 +46675,7 @@ var GitLabWorkspacesProvider = class {
45803
46675
  }
45804
46676
  async listProjects() {
45805
46677
  try {
45806
- const { stdout } = await execFileP7(
46678
+ const { stdout } = await execFileP8(
45807
46679
  "glab",
45808
46680
  ["repo", "list", "--per-page", "200", "--output", "json"],
45809
46681
  { maxBuffer: MAX_BUFFER3 }
@@ -45935,7 +46807,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
45935
46807
  async exec(workspaceId, command2) {
45936
46808
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
45937
46809
  try {
45938
- const { stdout, stderr } = await execFileP7(
46810
+ const { stdout, stderr } = await execFileP8(
45939
46811
  "ssh",
45940
46812
  [
45941
46813
  "-o",
@@ -46006,7 +46878,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
46006
46878
  }
46007
46879
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
46008
46880
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
46009
- const remoteDir = path85.posix.dirname(remotePath);
46881
+ const remoteDir = path87.posix.dirname(remotePath);
46010
46882
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
46011
46883
  if (options.mode != null) {
46012
46884
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -46038,7 +46910,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
46038
46910
  */
46039
46911
  async getGlabToken() {
46040
46912
  try {
46041
- const { stdout, stderr } = await execFileP7(
46913
+ const { stdout, stderr } = await execFileP8(
46042
46914
  "glab",
46043
46915
  ["auth", "status", "--show-token"],
46044
46916
  { maxBuffer: MAX_BUFFER3 }
@@ -46074,8 +46946,8 @@ function shellQuote3(s) {
46074
46946
  // src/services/providers/railway.ts
46075
46947
  var import_child_process33 = require("child_process");
46076
46948
  var import_util7 = require("util");
46077
- var path86 = __toESM(require("path"));
46078
- var execFileP8 = (0, import_util7.promisify)(import_child_process33.execFile);
46949
+ var path88 = __toESM(require("path"));
46950
+ var execFileP9 = (0, import_util7.promisify)(import_child_process33.execFile);
46079
46951
  var MAX_BUFFER4 = 8 * 1024 * 1024;
46080
46952
  function resetStdinForChild4() {
46081
46953
  if (process.stdin.isTTY) {
@@ -46092,7 +46964,7 @@ var RailwayProvider = class {
46092
46964
  available = true;
46093
46965
  async authorize() {
46094
46966
  try {
46095
- await execFileP8("railway", ["--version"], { maxBuffer: MAX_BUFFER4 });
46967
+ await execFileP9("railway", ["--version"], { maxBuffer: MAX_BUFFER4 });
46096
46968
  } catch {
46097
46969
  throw new Error(
46098
46970
  [
@@ -46106,7 +46978,7 @@ var RailwayProvider = class {
46106
46978
  );
46107
46979
  }
46108
46980
  try {
46109
- await execFileP8("railway", ["whoami"], { maxBuffer: MAX_BUFFER4 });
46981
+ await execFileP9("railway", ["whoami"], { maxBuffer: MAX_BUFFER4 });
46110
46982
  return;
46111
46983
  } catch {
46112
46984
  }
@@ -46126,7 +46998,7 @@ var RailwayProvider = class {
46126
46998
  }
46127
46999
  async listProjects() {
46128
47000
  try {
46129
- const { stdout } = await execFileP8(
47001
+ const { stdout } = await execFileP9(
46130
47002
  "railway",
46131
47003
  ["list", "--json"],
46132
47004
  { maxBuffer: MAX_BUFFER4 }
@@ -46142,7 +47014,7 @@ var RailwayProvider = class {
46142
47014
  }));
46143
47015
  } catch {
46144
47016
  try {
46145
- const { stdout } = await execFileP8("railway", ["list"], { maxBuffer: MAX_BUFFER4 });
47017
+ const { stdout } = await execFileP9("railway", ["list"], { maxBuffer: MAX_BUFFER4 });
46146
47018
  const projects = [];
46147
47019
  for (const line of stdout.split("\n")) {
46148
47020
  const trimmed = line.trim();
@@ -46193,7 +47065,7 @@ var RailwayProvider = class {
46193
47065
  async listExistingWorkspaces(projectId) {
46194
47066
  if (!projectId) return [];
46195
47067
  try {
46196
- const { stdout } = await execFileP8(
47068
+ const { stdout } = await execFileP9(
46197
47069
  "railway",
46198
47070
  ["service", "list", "--project", projectId, "--json"],
46199
47071
  { maxBuffer: MAX_BUFFER4 }
@@ -46218,7 +47090,7 @@ var RailwayProvider = class {
46218
47090
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
46219
47091
  }
46220
47092
  try {
46221
- await execFileP8(
47093
+ await execFileP9(
46222
47094
  "railway",
46223
47095
  ["service", "restart", "--service", serviceId, "--project", projectId],
46224
47096
  { maxBuffer: MAX_BUFFER4, timeout: 6e4 }
@@ -46237,7 +47109,7 @@ var RailwayProvider = class {
46237
47109
  };
46238
47110
  }
46239
47111
  try {
46240
- const { stdout, stderr } = await execFileP8(
47112
+ const { stdout, stderr } = await execFileP9(
46241
47113
  "railway",
46242
47114
  ["run", "--project", projectId, "--service", serviceId, "--", "bash", "-lc", command2],
46243
47115
  { maxBuffer: MAX_BUFFER4, timeout: 6e5 }
@@ -46310,7 +47182,7 @@ var RailwayProvider = class {
46310
47182
  if (!projectId || !serviceId) {
46311
47183
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
46312
47184
  }
46313
- const remoteDir = path86.posix.dirname(remotePath);
47185
+ const remoteDir = path88.posix.dirname(remotePath);
46314
47186
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
46315
47187
  if (options.mode != null) {
46316
47188
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -46850,14 +47722,14 @@ async function stopWorkspaceFromLocal(target) {
46850
47722
  }
46851
47723
 
46852
47724
  // src/commands/host/host-client.ts
46853
- var fs73 = __toESM(require("fs"));
46854
- var os57 = __toESM(require("os"));
46855
- var path87 = __toESM(require("path"));
46856
- var import_node_crypto11 = require("crypto");
47725
+ var fs75 = __toESM(require("fs"));
47726
+ var os59 = __toESM(require("os"));
47727
+ var path89 = __toESM(require("path"));
47728
+ var import_node_crypto12 = require("crypto");
46857
47729
  function sampleCpuTimes() {
46858
47730
  let idle = 0;
46859
47731
  let total = 0;
46860
- for (const cpu of os57.cpus()) {
47732
+ for (const cpu of os59.cpus()) {
46861
47733
  const t2 = cpu.times;
46862
47734
  idle += t2.idle;
46863
47735
  total += t2.user + t2.nice + t2.sys + t2.idle + t2.irq;
@@ -46876,8 +47748,8 @@ var MetricsCollector = class {
46876
47748
  const prev = this.prevCpu;
46877
47749
  this.prevCpu = current2;
46878
47750
  if (!prev) {
46879
- const cores = os57.cpus().length || 1;
46880
- const proxy = os57.loadavg()[0] / cores * 100;
47751
+ const cores = os59.cpus().length || 1;
47752
+ const proxy = os59.loadavg()[0] / cores * 100;
46881
47753
  return Math.min(100, Math.max(0, Math.round(proxy)));
46882
47754
  }
46883
47755
  const idleDelta = current2.idle - prev.idle;
@@ -46890,8 +47762,8 @@ var MetricsCollector = class {
46890
47762
  collect() {
46891
47763
  return {
46892
47764
  cpuPct: this.cpuPct(),
46893
- ramUsedMb: Math.round((os57.totalmem() - os57.freemem()) / 1048576),
46894
- ramTotalMb: Math.round(os57.totalmem() / 1048576),
47765
+ ramUsedMb: Math.round((os59.totalmem() - os59.freemem()) / 1048576),
47766
+ ramTotalMb: Math.round(os59.totalmem() / 1048576),
46895
47767
  latencyMs: this.lastLatencyMs
46896
47768
  };
46897
47769
  }
@@ -46900,19 +47772,19 @@ function apiBase() {
46900
47772
  return process.env.CODEAM_API_URL ?? resolveApiBaseUrl();
46901
47773
  }
46902
47774
  function hostIdentityPath() {
46903
- return path87.join(os57.homedir(), ".codeam", "host-agent.json");
47775
+ return path89.join(os59.homedir(), ".codeam", "host-agent.json");
46904
47776
  }
46905
47777
  function collectOsInfo() {
46906
47778
  return {
46907
- distro: os57.platform(),
46908
- arch: os57.arch(),
46909
- kernel: os57.release(),
47779
+ distro: os59.platform(),
47780
+ arch: os59.arch(),
47781
+ kernel: os59.release(),
46910
47782
  nodeVersion: process.versions.node
46911
47783
  };
46912
47784
  }
46913
47785
  function loadHostIdentity() {
46914
47786
  try {
46915
- const raw = fs73.readFileSync(hostIdentityPath(), "utf8");
47787
+ const raw = fs75.readFileSync(hostIdentityPath(), "utf8");
46916
47788
  const parsed = JSON.parse(raw);
46917
47789
  if (typeof parsed === "object" && parsed !== null && typeof parsed.hostId === "string" && typeof parsed.hostToken === "string" && typeof parsed.controlPluginId === "string") {
46918
47790
  const p2 = parsed;
@@ -46931,8 +47803,8 @@ function loadHostIdentity() {
46931
47803
  }
46932
47804
  function saveHostIdentity(identity) {
46933
47805
  const file = hostIdentityPath();
46934
- fs73.mkdirSync(path87.dirname(file), { recursive: true, mode: 448 });
46935
- fs73.writeFileSync(file, JSON.stringify(identity, null, 2), {
47806
+ fs75.mkdirSync(path89.dirname(file), { recursive: true, mode: 448 });
47807
+ fs75.writeFileSync(file, JSON.stringify(identity, null, 2), {
46936
47808
  encoding: "utf8",
46937
47809
  mode: 384
46938
47810
  });
@@ -46977,7 +47849,7 @@ function isTerminalEnrollError(err) {
46977
47849
  }
46978
47850
  function deleteHostIdentity() {
46979
47851
  try {
46980
- fs73.rmSync(hostIdentityPath(), { force: true });
47852
+ fs75.rmSync(hostIdentityPath(), { force: true });
46981
47853
  } catch {
46982
47854
  }
46983
47855
  }
@@ -47001,12 +47873,12 @@ async function postJson(pathname, body) {
47001
47873
  function resolveHostLabel(label) {
47002
47874
  const explicit = label?.trim();
47003
47875
  const envLabel = process.env.CODEAM_HOST_LABEL?.trim();
47004
- const resolved = explicit || envLabel || os57.hostname();
47876
+ const resolved = explicit || envLabel || os59.hostname();
47005
47877
  return resolved.slice(0, 80);
47006
47878
  }
47007
47879
  async function redeemEnrollToken(token, label) {
47008
- const controlPollSecret = (0, import_node_crypto11.randomBytes)(32).toString("base64url");
47009
- const pluginSecretHash = (0, import_node_crypto11.createHash)("sha256").update(controlPollSecret).digest("hex");
47880
+ const controlPollSecret = (0, import_node_crypto12.randomBytes)(32).toString("base64url");
47881
+ const pluginSecretHash = (0, import_node_crypto12.createHash)("sha256").update(controlPollSecret).digest("hex");
47010
47882
  const data = await postJson("/api/self-hosted/redeem", {
47011
47883
  token,
47012
47884
  label: resolveHostLabel(label),
@@ -47190,9 +48062,9 @@ async function host(args2) {
47190
48062
 
47191
48063
  // src/commands/host-agent.ts
47192
48064
  var import_node_child_process30 = require("child_process");
47193
- var os62 = __toESM(require("os"));
47194
- var fs78 = __toESM(require("fs"));
47195
- var path92 = __toESM(require("path"));
48065
+ var os63 = __toESM(require("os"));
48066
+ var fs79 = __toESM(require("fs"));
48067
+ var path93 = __toESM(require("path"));
47196
48068
 
47197
48069
  // src/skills/persist-from-payload.ts
47198
48070
  function persistOrClearSkillsFromPayload(skills) {
@@ -47201,13 +48073,13 @@ function persistOrClearSkillsFromPayload(skills) {
47201
48073
  }
47202
48074
 
47203
48075
  // src/commands/host/session-state.ts
47204
- var fs74 = __toESM(require("fs"));
47205
- var os58 = __toESM(require("os"));
47206
- var path88 = __toESM(require("path"));
48076
+ var fs76 = __toESM(require("fs"));
48077
+ var os60 = __toESM(require("os"));
48078
+ var path90 = __toESM(require("path"));
47207
48079
  function hostSessionStatePath(env = process.env) {
47208
48080
  const override = env.CODEAM_HOST_SESSION_STATE_FILE;
47209
48081
  if (override && override.trim()) return override.trim();
47210
- return path88.join(os58.homedir(), ".codeam", "host-agent-sessions.json");
48082
+ return path90.join(os60.homedir(), ".codeam", "host-agent-sessions.json");
47211
48083
  }
47212
48084
  function isRecord5(v) {
47213
48085
  if (typeof v !== "object" || v === null) return false;
@@ -47218,7 +48090,7 @@ function fileSessionChildStore(file = hostSessionStatePath()) {
47218
48090
  return {
47219
48091
  load() {
47220
48092
  try {
47221
- const raw = JSON.parse(fs74.readFileSync(file, "utf8"));
48093
+ const raw = JSON.parse(fs76.readFileSync(file, "utf8"));
47222
48094
  return Array.isArray(raw?.sessions) ? raw.sessions.filter(isRecord5) : [];
47223
48095
  } catch {
47224
48096
  return [];
@@ -47226,18 +48098,18 @@ function fileSessionChildStore(file = hostSessionStatePath()) {
47226
48098
  },
47227
48099
  save(list) {
47228
48100
  try {
47229
- fs74.mkdirSync(path88.dirname(file), { recursive: true, mode: 448 });
48101
+ fs76.mkdirSync(path90.dirname(file), { recursive: true, mode: 448 });
47230
48102
  const tmp = `${file}.${process.pid}.tmp`;
47231
- fs74.writeFileSync(tmp, JSON.stringify({ version: 1, sessions: list }, null, 2), {
48103
+ fs76.writeFileSync(tmp, JSON.stringify({ version: 1, sessions: list }, null, 2), {
47232
48104
  mode: 384
47233
48105
  });
47234
- fs74.renameSync(tmp, file);
48106
+ fs76.renameSync(tmp, file);
47235
48107
  } catch {
47236
48108
  }
47237
48109
  },
47238
48110
  clear() {
47239
48111
  try {
47240
- fs74.rmSync(file, { force: true });
48112
+ fs76.rmSync(file, { force: true });
47241
48113
  } catch {
47242
48114
  }
47243
48115
  }
@@ -47260,181 +48132,22 @@ function planSessionResume(records, max) {
47260
48132
  return { resume: ordered.slice(0, bound), dropped: ordered.slice(bound) };
47261
48133
  }
47262
48134
  function pickSavedSessionForWorkspace(sessions3, cwd) {
47263
- const target = path88.resolve(cwd);
48135
+ const target = path90.resolve(cwd);
47264
48136
  const matches = sessions3.filter(
47265
- (s) => !!s.cwd && path88.resolve(s.cwd) === target && !!s.pluginId && !!s.pollSecret && !!s.agent
48137
+ (s) => !!s.cwd && path90.resolve(s.cwd) === target && !!s.pluginId && !!s.pollSecret && !!s.agent
47266
48138
  );
47267
48139
  if (matches.length === 0) return null;
47268
48140
  matches.sort((a, b) => b.pairedAt - a.pairedAt);
47269
48141
  return matches[0];
47270
48142
  }
47271
48143
 
47272
- // src/commands/host/workspace.ts
47273
- var fs75 = __toESM(require("fs"));
47274
- var os59 = __toESM(require("os"));
47275
- var path89 = __toESM(require("path"));
47276
- var import_node_child_process25 = require("child_process");
47277
- var import_node_util5 = require("util");
47278
- var execFileP9 = (0, import_node_util5.promisify)(import_node_child_process25.execFile);
47279
- function isAbsolutePathTarget(target) {
47280
- return path89.isAbsolute(target);
47281
- }
47282
- function selfHostedWorkspaceRoot() {
47283
- return path89.join(os59.homedir(), ".codeam", "self-hosted");
47284
- }
47285
- function deployIdFromWorkspace(cwd) {
47286
- if (!cwd) return null;
47287
- const root = selfHostedWorkspaceRoot();
47288
- const resolved = path89.resolve(cwd);
47289
- const rel = path89.relative(root, resolved);
47290
- if (!rel || rel.startsWith("..") || path89.isAbsolute(rel)) return null;
47291
- const parts = rel.split(path89.sep).filter(Boolean);
47292
- if (parts.length !== 1) return null;
47293
- return parts[0];
47294
- }
47295
- function nonInteractiveGitEnv() {
47296
- return {
47297
- ...process.env,
47298
- GIT_TERMINAL_PROMPT: "0",
47299
- GIT_ASKPASS: "",
47300
- GCM_INTERACTIVE: "never"
47301
- };
47302
- }
47303
- function githubOwnerRepo(repoRef) {
47304
- const trimmed = repoRef.trim();
47305
- const shorthand = /^([^/\s]+)\/([^/\s]+?)(?:\.git)?$/.exec(trimmed);
47306
- if (shorthand && !/^https?:\/\//.test(trimmed) && !trimmed.startsWith("git@")) {
47307
- return { owner: shorthand[1], repo: shorthand[2] };
47308
- }
47309
- const httpsMatch = /^https?:\/\/github\.com\/([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/.exec(trimmed);
47310
- if (httpsMatch) return { owner: httpsMatch[1], repo: httpsMatch[2] };
47311
- return null;
47312
- }
47313
- function gitlabProjectPath(repoRef) {
47314
- const trimmed = repoRef.trim();
47315
- const https9 = /^https?:\/\/gitlab\.com\/(.+?)(?:\.git)?\/?$/.exec(trimmed);
47316
- if (https9) return https9[1];
47317
- if (!/^https?:\/\//.test(trimmed) && !trimmed.startsWith("git@") && trimmed.includes("/")) {
47318
- return trimmed.replace(/\.git$/, "");
47319
- }
47320
- return null;
47321
- }
47322
- function repoCloneUrl(repoRef, cloneToken, provider = "github") {
47323
- const trimmed = repoRef.trim();
47324
- if (provider === "gitlab") {
47325
- const glPath = gitlabProjectPath(trimmed);
47326
- if (glPath) {
47327
- return cloneToken ? `https://oauth2:${cloneToken}@gitlab.com/${glPath}.git` : `https://gitlab.com/${glPath}.git`;
47328
- }
47329
- if (/^https?:\/\//.test(trimmed) || trimmed.startsWith("git@")) return trimmed;
47330
- }
47331
- if (cloneToken) {
47332
- const gh = githubOwnerRepo(trimmed);
47333
- if (gh) {
47334
- return `https://x-access-token:${cloneToken}@github.com/${gh.owner}/${gh.repo}.git`;
47335
- }
47336
- }
47337
- if (/^https?:\/\//.test(trimmed) || trimmed.startsWith("git@")) return trimmed;
47338
- return `https://github.com/${trimmed.replace(/\.git$/, "")}.git`;
47339
- }
47340
- function maskCloneUrl(url2) {
47341
- return url2.replace(/(https?:\/\/)[^@/]+@/, "$1***@");
47342
- }
47343
- async function fetchGithubIdentity(token) {
47344
- try {
47345
- const res = await fetch("https://api.github.com/user", {
47346
- headers: {
47347
- Authorization: `Bearer ${token}`,
47348
- "User-Agent": "codeam-cli",
47349
- Accept: "application/vnd.github+json"
47350
- }
47351
- });
47352
- if (!res.ok) return null;
47353
- const body = await res.json();
47354
- return { login: body.login, email: body.email ?? void 0 };
47355
- } catch {
47356
- return null;
47357
- }
47358
- }
47359
- async function configureGitCredentials(dest, repoRef, cloneToken, provider = "github") {
47360
- const isGitlab = provider === "gitlab";
47361
- if (isGitlab ? !gitlabProjectPath(repoRef.trim()) : !githubOwnerRepo(repoRef.trim())) return;
47362
- if (!cloneToken) return;
47363
- const credFile = path89.join(dest, ".git", "codeam-credentials");
47364
- const credLine = isGitlab ? `https://oauth2:${cloneToken}@gitlab.com
47365
- ` : `https://x-access-token:${cloneToken}@github.com
47366
- `;
47367
- fs75.writeFileSync(credFile, credLine, { mode: 384 });
47368
- restrictToOwner(credFile);
47369
- const env = nonInteractiveGitEnv();
47370
- const git2 = (args2) => execFileP9("git", ["-C", dest, ...args2], { timeout: 3e4, env });
47371
- const credFilePosix = credFile.split(path89.sep).join("/");
47372
- await git2(["config", "--local", "--replace-all", "credential.helper", ""]).catch(() => {
47373
- });
47374
- await git2([
47375
- "config",
47376
- "--local",
47377
- "--add",
47378
- "credential.helper",
47379
- `store --file=${credFilePosix}`
47380
- ]).catch(() => {
47381
- });
47382
- await git2(["remote", "set-url", "origin", repoCloneUrl(repoRef, void 0, provider)]).catch(() => {
47383
- });
47384
- const hasIdentity = await git2(["config", "user.email"]).then(() => true).catch(() => false);
47385
- if (!hasIdentity) {
47386
- const who = isGitlab ? null : await fetchGithubIdentity(cloneToken);
47387
- const login = who?.login ?? "CodeAgent";
47388
- await git2(["config", "--local", "user.name", login]).catch(() => {
47389
- });
47390
- const email = who?.email ?? (isGitlab ? "agent@codeagent-mobile.com" : `${login}@users.noreply.github.com`);
47391
- await git2(["config", "--local", "user.email", email]).catch(() => {
47392
- });
47393
- }
47394
- }
47395
- function maskToken(text, cloneToken) {
47396
- const masked = maskCloneUrl(text);
47397
- if (cloneToken && cloneToken.length > 0) {
47398
- return masked.split(cloneToken).join("***");
47399
- }
47400
- return masked;
47401
- }
47402
- async function prepareWorkspace(repoOrPath, deployId, cloneToken, provider = "github", branch) {
47403
- if (isAbsolutePathTarget(repoOrPath)) {
47404
- if (!fs75.existsSync(repoOrPath)) {
47405
- throw new Error(`deploy target path does not exist: ${repoOrPath}`);
47406
- }
47407
- return repoOrPath;
47408
- }
47409
- const dest = path89.join(selfHostedWorkspaceRoot(), deployId);
47410
- if (fs75.existsSync(path89.join(dest, ".git"))) {
47411
- if (cloneToken) await configureGitCredentials(dest, repoOrPath, cloneToken, provider);
47412
- return dest;
47413
- }
47414
- fs75.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
47415
- const cloneUrl = repoCloneUrl(repoOrPath, cloneToken, provider);
47416
- const cloneArgs = branch ? ["clone", "--depth", "1", "--branch", branch, cloneUrl, dest] : ["clone", "--depth", "1", cloneUrl, dest];
47417
- try {
47418
- await execFileP9("git", cloneArgs, {
47419
- timeout: 12e4,
47420
- maxBuffer: 16 * 1024 * 1024,
47421
- env: nonInteractiveGitEnv()
47422
- });
47423
- } catch (err) {
47424
- const reason = err instanceof Error ? err.message : String(err);
47425
- throw new Error(`git clone failed for ${maskCloneUrl(cloneUrl)}: ${maskToken(reason, cloneToken)}`);
47426
- }
47427
- if (cloneToken) await configureGitCredentials(dest, repoOrPath, cloneToken, provider);
47428
- return dest;
47429
- }
47430
-
47431
48144
  // src/commands/host/git-tooling.ts
47432
48145
  var import_node_child_process26 = require("child_process");
47433
- var fs76 = __toESM(require("fs"));
47434
- var os60 = __toESM(require("os"));
47435
- var path90 = __toESM(require("path"));
48146
+ var fs77 = __toESM(require("fs"));
48147
+ var os61 = __toESM(require("os"));
48148
+ var path91 = __toESM(require("path"));
47436
48149
  function codeamBinDir() {
47437
- return process.env.CODEAM_BIN_DIR ?? path90.join(os60.homedir(), ".codeam", "bin");
48150
+ return process.env.CODEAM_BIN_DIR ?? path91.join(os61.homedir(), ".codeam", "bin");
47438
48151
  }
47439
48152
  var FALLBACK_GH_VERSION = "2.62.0";
47440
48153
  var RELEASE_API = "https://api.github.com/repos/cli/cli/releases/latest";
@@ -47466,7 +48179,7 @@ async function download(url2, dest) {
47466
48179
  const res = await fetch(url2, { headers: { "User-Agent": "codeam-cli" } });
47467
48180
  if (!res.ok || !res.body) return false;
47468
48181
  const buf = Buffer.from(await res.arrayBuffer());
47469
- fs76.writeFileSync(dest, buf);
48182
+ fs77.writeFileSync(dest, buf);
47470
48183
  return true;
47471
48184
  } catch {
47472
48185
  return false;
@@ -47489,8 +48202,8 @@ async function ensureGhCli(runner, token, deps = {}) {
47489
48202
  const version3 = await resolveVersionFn(token);
47490
48203
  const asset = `gh_${version3}_${osToken}_${arch2}`;
47491
48204
  const url2 = `https://github.com/cli/cli/releases/download/v${version3}/${asset}.${ext}`;
47492
- const tmpRoot = fs76.mkdtempSync(path90.join(os60.tmpdir(), "codeam-gh-"));
47493
- const archive = path90.join(tmpRoot, `${asset}.${ext}`);
48205
+ const tmpRoot = fs77.mkdtempSync(path91.join(os61.tmpdir(), "codeam-gh-"));
48206
+ const archive = path91.join(tmpRoot, `${asset}.${ext}`);
47494
48207
  if (!await downloadFn(url2, archive)) {
47495
48208
  log.warn("host-agent", "gh download failed \u2014 skipping (git pull/push still work via the credential helper)");
47496
48209
  return null;
@@ -47500,16 +48213,16 @@ async function ensureGhCli(runner, token, deps = {}) {
47500
48213
  log.warn("host-agent", `gh archive extraction failed (code=${String(extract.code)}) \u2014 skipping`);
47501
48214
  return null;
47502
48215
  }
47503
- const extractedBin = path90.join(tmpRoot, asset, "bin", binaryName);
47504
- if (!fs76.existsSync(extractedBin)) {
48216
+ const extractedBin = path91.join(tmpRoot, asset, "bin", binaryName);
48217
+ if (!fs77.existsSync(extractedBin)) {
47505
48218
  log.warn("host-agent", "gh binary not found in the extracted archive \u2014 skipping");
47506
48219
  return null;
47507
48220
  }
47508
48221
  const binDir = codeamBinDir();
47509
- fs76.mkdirSync(binDir, { recursive: true });
47510
- const target = path90.join(binDir, binaryName);
47511
- fs76.copyFileSync(extractedBin, target);
47512
- fs76.chmodSync(target, 493);
48222
+ fs77.mkdirSync(binDir, { recursive: true });
48223
+ const target = path91.join(binDir, binaryName);
48224
+ fs77.copyFileSync(extractedBin, target);
48225
+ fs77.chmodSync(target, 493);
47513
48226
  log.info("host-agent", `gh installed to ${target} (v${version3})`);
47514
48227
  return target;
47515
48228
  } catch (e) {
@@ -47546,19 +48259,19 @@ async function ensureGhAuth(runner, ghCmd, token) {
47546
48259
  }
47547
48260
  function ghConfigDir() {
47548
48261
  if (process.env.GH_CONFIG_DIR) return process.env.GH_CONFIG_DIR;
47549
- if (process.env.XDG_CONFIG_HOME) return path90.join(process.env.XDG_CONFIG_HOME, "gh");
48262
+ if (process.env.XDG_CONFIG_HOME) return path91.join(process.env.XDG_CONFIG_HOME, "gh");
47550
48263
  if (process.platform === "win32" && process.env.APPDATA) {
47551
- return path90.join(process.env.APPDATA, "GitHub CLI");
48264
+ return path91.join(process.env.APPDATA, "GitHub CLI");
47552
48265
  }
47553
- return path90.join(os60.homedir(), ".config", "gh");
48266
+ return path91.join(os61.homedir(), ".config", "gh");
47554
48267
  }
47555
48268
  function writeGhHostsToken(token) {
47556
48269
  try {
47557
48270
  const dir = ghConfigDir();
47558
- const file = path90.join(dir, "hosts.yml");
47559
- if (fs76.existsSync(file)) return false;
47560
- fs76.mkdirSync(dir, { recursive: true, mode: 448 });
47561
- fs76.writeFileSync(
48271
+ const file = path91.join(dir, "hosts.yml");
48272
+ if (fs77.existsSync(file)) return false;
48273
+ fs77.mkdirSync(dir, { recursive: true, mode: 448 });
48274
+ fs77.writeFileSync(
47562
48275
  file,
47563
48276
  `github.com:
47564
48277
  oauth_token: ${token}
@@ -47601,8 +48314,8 @@ async function ensureGlabCli(runner, deps = {}) {
47601
48314
  const version3 = await resolveLatestGlabVersion();
47602
48315
  const asset = `glab_${version3}_${osToken}_${arch2}`;
47603
48316
  const url2 = `https://gitlab.com/gitlab-org/cli/-/releases/v${version3}/downloads/${asset}.${ext}`;
47604
- const tmpRoot = fs76.mkdtempSync(path90.join(os60.tmpdir(), "codeam-glab-"));
47605
- const archive = path90.join(tmpRoot, `${asset}.${ext}`);
48317
+ const tmpRoot = fs77.mkdtempSync(path91.join(os61.tmpdir(), "codeam-glab-"));
48318
+ const archive = path91.join(tmpRoot, `${asset}.${ext}`);
47606
48319
  if (!await downloadFn(url2, archive)) {
47607
48320
  log.warn("host-agent", "glab download failed \u2014 skipping (git push/pull still work)");
47608
48321
  return null;
@@ -47613,20 +48326,20 @@ async function ensureGlabCli(runner, deps = {}) {
47613
48326
  return null;
47614
48327
  }
47615
48328
  const candidates = [
47616
- path90.join(tmpRoot, "bin", binaryName),
47617
- path90.join(tmpRoot, asset, "bin", binaryName),
47618
- path90.join(tmpRoot, binaryName)
48329
+ path91.join(tmpRoot, "bin", binaryName),
48330
+ path91.join(tmpRoot, asset, "bin", binaryName),
48331
+ path91.join(tmpRoot, binaryName)
47619
48332
  ];
47620
- const extractedBin = candidates.find((c2) => fs76.existsSync(c2));
48333
+ const extractedBin = candidates.find((c2) => fs77.existsSync(c2));
47621
48334
  if (!extractedBin) {
47622
48335
  log.warn("host-agent", "glab binary not found in the extracted archive \u2014 skipping");
47623
48336
  return null;
47624
48337
  }
47625
48338
  const binDir = codeamBinDir();
47626
- fs76.mkdirSync(binDir, { recursive: true });
47627
- const target = path90.join(binDir, binaryName);
47628
- fs76.copyFileSync(extractedBin, target);
47629
- fs76.chmodSync(target, 493);
48339
+ fs77.mkdirSync(binDir, { recursive: true });
48340
+ const target = path91.join(binDir, binaryName);
48341
+ fs77.copyFileSync(extractedBin, target);
48342
+ fs77.chmodSync(target, 493);
47630
48343
  log.info("host-agent", `glab installed to ${target} (v${version3})`);
47631
48344
  return target;
47632
48345
  } catch (e) {
@@ -47708,9 +48421,9 @@ var defaultGitToolingRunner = {
47708
48421
  var import_node_child_process28 = require("child_process");
47709
48422
 
47710
48423
  // src/lib/updateNotifier.ts
47711
- var fs77 = __toESM(require("fs"));
47712
- var os61 = __toESM(require("os"));
47713
- var path91 = __toESM(require("path"));
48424
+ var fs78 = __toESM(require("fs"));
48425
+ var os62 = __toESM(require("os"));
48426
+ var path92 = __toESM(require("path"));
47714
48427
  var https8 = __toESM(require("https"));
47715
48428
  var import_node_child_process27 = require("child_process");
47716
48429
  var import_picocolors12 = __toESM(require("picocolors"));
@@ -47719,12 +48432,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
47719
48432
  var TTL_MS = 24 * 60 * 60 * 1e3;
47720
48433
  var REQUEST_TIMEOUT_MS = 1500;
47721
48434
  function cachePath() {
47722
- const dir = path91.join(os61.homedir(), ".codeam");
47723
- return path91.join(dir, "update-check.json");
48435
+ const dir = path92.join(os62.homedir(), ".codeam");
48436
+ return path92.join(dir, "update-check.json");
47724
48437
  }
47725
48438
  function readCache() {
47726
48439
  try {
47727
- const raw = fs77.readFileSync(cachePath(), "utf8");
48440
+ const raw = fs78.readFileSync(cachePath(), "utf8");
47728
48441
  const parsed = JSON.parse(raw);
47729
48442
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
47730
48443
  return parsed;
@@ -47735,10 +48448,10 @@ function readCache() {
47735
48448
  function writeCache(cache) {
47736
48449
  try {
47737
48450
  const file = cachePath();
47738
- fs77.mkdirSync(path91.dirname(file), { recursive: true });
48451
+ fs78.mkdirSync(path92.dirname(file), { recursive: true });
47739
48452
  const tmp = `${file}.${process.pid}.tmp`;
47740
- fs77.writeFileSync(tmp, JSON.stringify(cache));
47741
- fs77.renameSync(tmp, file);
48453
+ fs78.writeFileSync(tmp, JSON.stringify(cache));
48454
+ fs78.renameSync(tmp, file);
47742
48455
  } catch {
47743
48456
  }
47744
48457
  }
@@ -47812,8 +48525,8 @@ function isLinkedInstall() {
47812
48525
  timeout: 2e3
47813
48526
  }).trim();
47814
48527
  if (!root) return false;
47815
- const pkgPath = path91.join(root, PKG_NAME);
47816
- return fs77.lstatSync(pkgPath).isSymbolicLink();
48528
+ const pkgPath = path92.join(root, PKG_NAME);
48529
+ return fs78.lstatSync(pkgPath).isSymbolicLink();
47817
48530
  } catch {
47818
48531
  return false;
47819
48532
  }
@@ -47849,7 +48562,7 @@ function maybeAutoUpdate(currentVersion, latest) {
47849
48562
  return;
47850
48563
  }
47851
48564
  try {
47852
- fs77.unlinkSync(cachePath());
48565
+ fs78.unlinkSync(cachePath());
47853
48566
  } catch {
47854
48567
  }
47855
48568
  process.stderr.write(` ${import_picocolors12.default.green("\u2713")} Updated. Resuming session...
@@ -47865,7 +48578,7 @@ async function autoUpgradeBeforeCriticalCommand() {
47865
48578
  if (process.env.NODE_ENV === "test") return;
47866
48579
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
47867
48580
  if (process.env.CI) return;
47868
- const current2 = true ? "2.75.25" : null;
48581
+ const current2 = true ? "2.75.27" : null;
47869
48582
  if (!current2) return;
47870
48583
  const cache = readCache();
47871
48584
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -47882,7 +48595,7 @@ function checkForUpdates() {
47882
48595
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
47883
48596
  if (process.env.CI) return;
47884
48597
  if (!process.stdout.isTTY) return;
47885
- const current2 = true ? "2.75.25" : null;
48598
+ const current2 = true ? "2.75.27" : null;
47886
48599
  if (!current2) return;
47887
48600
  const cache = readCache();
47888
48601
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -47905,7 +48618,7 @@ var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
47905
48618
  var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
47906
48619
  var SUDO_PREFLIGHT_TIMEOUT_MS = 5e3;
47907
48620
  function currentCliVersion() {
47908
- return true ? "2.75.25" : null;
48621
+ return true ? "2.75.27" : null;
47909
48622
  }
47910
48623
  async function installedVersion(deps) {
47911
48624
  const ls = await deps.run(
@@ -48054,6 +48767,9 @@ function isDeployPayload(p2) {
48054
48767
  function isStopPayload(p2) {
48055
48768
  return typeof p2.sessionId === "string";
48056
48769
  }
48770
+ function isResumePayload(p2) {
48771
+ return typeof p2.sessionId === "string" && p2.sessionId.length > 0;
48772
+ }
48057
48773
  function isCleanupPayload(p2) {
48058
48774
  return typeof p2.deployId === "string" && p2.deployId.length > 0;
48059
48775
  }
@@ -48342,10 +49058,7 @@ var HostAgentSupervisor = class {
48342
49058
  this.heartbeatTimer = setInterval(() => void this.beat(), HEARTBEAT_INTERVAL_MS);
48343
49059
  this.heartbeatTimer.unref?.();
48344
49060
  this.resumePersistedSessions();
48345
- void reportSessionEvent(
48346
- { hostId: this.identity.hostId, hostToken: this.identity.hostToken },
48347
- { event: "reconcile", activeDeployIds: this.activeSessions().map((s) => s.id) }
48348
- ).catch((err) => log.trace("host-agent", "boot reconcile failed (best-effort)", err));
49061
+ this.reportLiveSet("boot");
48349
49062
  const updateMs = this.selfUpdateIntervalMs();
48350
49063
  if (updateMs > 0) {
48351
49064
  this.selfUpdateTimer = setInterval(() => void this.selfUpdateTick(), updateMs);
@@ -48591,6 +49304,14 @@ var HostAgentSupervisor = class {
48591
49304
  this.stopChild(cmd.payload.sessionId);
48592
49305
  return;
48593
49306
  }
49307
+ if (cmd.type === "self_hosted_resume") {
49308
+ if (!isResumePayload(cmd.payload)) {
49309
+ log.warn("host-agent", `ignoring malformed self_hosted_resume id=${cmd.id}`);
49310
+ return;
49311
+ }
49312
+ this.resumeSavedSession(cmd.payload.sessionId);
49313
+ return;
49314
+ }
48594
49315
  if (cmd.type === "self_hosted_cleanup") {
48595
49316
  if (!isCleanupPayload(cmd.payload)) {
48596
49317
  log.warn("host-agent", `ignoring malformed self_hosted_cleanup id=${cmd.id}`);
@@ -48638,13 +49359,13 @@ var HostAgentSupervisor = class {
48638
49359
  const relay = this.relay;
48639
49360
  if (!relay) return;
48640
49361
  const raw = cmd.payload?.path;
48641
- const target = typeof raw === "string" && raw.trim() ? path92.resolve(raw.trim()) : os62.homedir();
49362
+ const target = typeof raw === "string" && raw.trim() ? path93.resolve(raw.trim()) : os63.homedir();
48642
49363
  try {
48643
- const dirents = await fs78.promises.readdir(target, { withFileTypes: true });
49364
+ const dirents = await fs79.promises.readdir(target, { withFileTypes: true });
48644
49365
  const entries = dirents.filter((d3) => !d3.name.startsWith(".")).map((d3) => ({ name: d3.name, isDir: d3.isDirectory() })).sort(
48645
49366
  (a, b) => a.isDir === b.isDir ? a.name.localeCompare(b.name) : a.isDir ? -1 : 1
48646
49367
  );
48647
- const parent = path92.dirname(target);
49368
+ const parent = path93.dirname(target);
48648
49369
  await relay.sendResult(cmd.id, "completed", {
48649
49370
  path: target,
48650
49371
  // null at the filesystem root so the UI can hide the ".." affordance.
@@ -48991,14 +49712,14 @@ var HostAgentSupervisor = class {
48991
49712
  ...buildHouseProxyChildEnv({ baseUrl, token, openRouter: openRouter === true }),
48992
49713
  CODEAM_AUTO_TOKEN: payload.autoPairToken
48993
49714
  };
48994
- const houseConfigDir = path92.join(
48995
- os62.homedir(),
49715
+ const houseConfigDir = path93.join(
49716
+ os63.homedir(),
48996
49717
  ".codeam",
48997
49718
  "house-claude",
48998
49719
  payload.deployId
48999
49720
  );
49000
49721
  try {
49001
- fs78.mkdirSync(houseConfigDir, { recursive: true, mode: 448 });
49722
+ fs79.mkdirSync(houseConfigDir, { recursive: true, mode: 448 });
49002
49723
  } catch {
49003
49724
  }
49004
49725
  childEnv.CLAUDE_CONFIG_DIR = houseConfigDir;
@@ -49008,7 +49729,7 @@ var HostAgentSupervisor = class {
49008
49729
  token,
49009
49730
  openRouter: !!openRouter,
49010
49731
  claudeConfigDir: houseConfigDir
49011
- });
49732
+ }, payload.deployId);
49012
49733
  } else {
49013
49734
  const auth = await this.resolveAgentAuth(this.identity, payload.sealedAgentAuth);
49014
49735
  const credEnv = provisionAgentCredentials(payload.agentId, auth, void 0);
@@ -49016,7 +49737,7 @@ var HostAgentSupervisor = class {
49016
49737
  ...credEnv,
49017
49738
  CODEAM_AUTO_TOKEN: payload.autoPairToken
49018
49739
  };
49019
- clearHouseProxyConfig();
49740
+ clearHouseProxyConfig(payload.deployId);
49020
49741
  }
49021
49742
  childEnv = { ...childEnv, CODEAM_AUTO_APPROVE: "1" };
49022
49743
  childEnv = { ...childEnv, CODEAM_HOST_AGENT_CHILD: "1" };
@@ -49024,7 +49745,7 @@ var HostAgentSupervisor = class {
49024
49745
  report("installing", "installing agent CLI");
49025
49746
  await this.runAgentInstall(payload.agentInstallScript);
49026
49747
  }
49027
- const home = process.env.HOME || os62.homedir();
49748
+ const home = process.env.HOME || os63.homedir();
49028
49749
  childEnv.PATH = `${home}/.local/bin:${process.env.PATH ?? ""}`;
49029
49750
  if (payload.cloneToken) {
49030
49751
  try {
@@ -49032,13 +49753,13 @@ var HostAgentSupervisor = class {
49032
49753
  if ((payload.repoProvider ?? "github") === "gitlab") {
49033
49754
  const glabCmd = await ensureGlabCli(defaultGitToolingRunner);
49034
49755
  if (glabCmd) {
49035
- childEnv.PATH = `${codeamBinDir()}${path92.delimiter}${childEnv.PATH}`;
49756
+ childEnv.PATH = `${codeamBinDir()}${path93.delimiter}${childEnv.PATH}`;
49036
49757
  await ensureGlabAuth(defaultGitToolingRunner, glabCmd, payload.cloneToken);
49037
49758
  }
49038
49759
  } else {
49039
49760
  const ghCmd = await ensureGhCli(defaultGitToolingRunner, payload.cloneToken);
49040
49761
  if (ghCmd) {
49041
- childEnv.PATH = `${codeamBinDir()}${path92.delimiter}${childEnv.PATH}`;
49762
+ childEnv.PATH = `${codeamBinDir()}${path93.delimiter}${childEnv.PATH}`;
49042
49763
  await ensureGhAuth(defaultGitToolingRunner, ghCmd, payload.cloneToken);
49043
49764
  }
49044
49765
  }
@@ -49066,9 +49787,9 @@ var HostAgentSupervisor = class {
49066
49787
  );
49067
49788
  if (!payload.suppressOnboardingWelcome) {
49068
49789
  try {
49069
- const cfgDir = childEnv.CLAUDE_CONFIG_DIR || path92.join(os62.homedir(), ".claude");
49070
- const projectDir = path92.join(cfgDir, "projects", encodeCwd(cwd));
49071
- const hasPriorConversation = fs78.existsSync(projectDir) && fs78.readdirSync(projectDir).some((f) => f.endsWith(".jsonl"));
49790
+ const cfgDir = childEnv.CLAUDE_CONFIG_DIR || path93.join(os63.homedir(), ".claude");
49791
+ const projectDir = path93.join(cfgDir, "projects", encodeCwd(cwd));
49792
+ const hasPriorConversation = fs79.existsSync(projectDir) && fs79.readdirSync(projectDir).some((f) => f.endsWith(".jsonl"));
49072
49793
  if (hasPriorConversation) {
49073
49794
  childEnv.CODEAM_RESUME_LATEST = "1";
49074
49795
  log.info(
@@ -49196,7 +49917,7 @@ var HostAgentSupervisor = class {
49196
49917
  );
49197
49918
  continue;
49198
49919
  }
49199
- this.resumeOne({ deployId: rec.deployId, cwd: rec.cwd, session });
49920
+ this.resumeOne({ deployId: rec.deployId, cwd: rec.cwd, session, agent: rec.agent });
49200
49921
  resumed += 1;
49201
49922
  }
49202
49923
  log.info(
@@ -49219,7 +49940,7 @@ var HostAgentSupervisor = class {
49219
49940
  fallbackResumeTarget() {
49220
49941
  const session = getActiveSession();
49221
49942
  if (!session || !session.pluginId || !session.pollSecret || !session.agent) return null;
49222
- const cwd = session.cwd && fs78.existsSync(session.cwd) ? session.cwd : process.cwd();
49943
+ const cwd = session.cwd && fs79.existsSync(session.cwd) ? session.cwd : process.cwd();
49223
49944
  const deployId = deployIdFromWorkspace(session.cwd) ?? session.id;
49224
49945
  return { deployId, cwd, session };
49225
49946
  }
@@ -49233,23 +49954,94 @@ var HostAgentSupervisor = class {
49233
49954
  }
49234
49955
  return st3;
49235
49956
  }
49957
+ /**
49958
+ * `self_hosted_resume` — the user opened (or reconnected) a session this box
49959
+ * is not running. A boot resumes only the children that were LIVE when the
49960
+ * box went down, so any other saved session was a dead card: the app said
49961
+ * "waking up — your message is queued", the box woke, and the session never
49962
+ * came back (codeagent-o7lm, QA box 2026-09-25: 4 saved sessions, 2 resumed).
49963
+ *
49964
+ * Resumes it through the same `resumeOne` a boot uses (bounded retries,
49965
+ * house-proxy env, persisted into the live set), then re-reports the live
49966
+ * set so the backend restores the session's host link. No-op when the
49967
+ * session is unknown, lacks its pairing, or its workspace is gone — the app
49968
+ * then keeps its offline state instead of a phantom "waking".
49969
+ */
49970
+ resumeSavedSession(sessionId) {
49971
+ const session = this.listSavedSessions().find((s) => s.id === sessionId);
49972
+ if (!session || !session.pluginId || !session.pollSecret || !session.agent) {
49973
+ log.warn("host-agent", `self_hosted_resume ${sessionId.slice(0, 8)}: no saved pairing on this box`);
49974
+ return;
49975
+ }
49976
+ if (!session.cwd || !fs79.existsSync(session.cwd)) {
49977
+ log.warn("host-agent", `self_hosted_resume ${sessionId.slice(0, 8)}: workspace is gone`);
49978
+ return;
49979
+ }
49980
+ const deployId = deployIdFromWorkspace(session.cwd) ?? session.id;
49981
+ if (this.children.has(deployId)) {
49982
+ log.info("host-agent", `self_hosted_resume ${sessionId.slice(0, 8)}: already live`);
49983
+ return;
49984
+ }
49985
+ this.resumeOne({ deployId, cwd: session.cwd, session });
49986
+ this.reportLiveSet("resume");
49987
+ }
49988
+ /**
49989
+ * Tell the backend exactly which sessions this host runs. `activeSessions`
49990
+ * (additive) carries the PairedSession id of every child that knows it, so a
49991
+ * link lost to host-identity churn is rebuilt instead of the session
49992
+ * rendering as LOCAL with a reconnect the user cannot perform.
49993
+ */
49994
+ reportLiveSet(why) {
49995
+ const children = [...this.children.values()];
49996
+ void reportSessionEvent(
49997
+ { hostId: this.identity.hostId, hostToken: this.identity.hostToken },
49998
+ {
49999
+ event: "reconcile",
50000
+ activeDeployIds: children.map((c2) => c2.deployId),
50001
+ activeSessions: children.filter((c2) => typeof c2.sessionId === "string").map((c2) => ({ deployId: c2.deployId, sessionId: c2.sessionId, agent: c2.agent })),
50002
+ knownSessions: this.knownSavedSessions()
50003
+ }
50004
+ ).catch((err) => log.trace("host-agent", `${why} reconcile failed (best-effort)`, err));
50005
+ }
50006
+ /**
50007
+ * Every saved session this host could resume — a pairing whose deploy
50008
+ * workspace is still on disk — live or not. The backend links the non-live
50009
+ * ones too, so the app knows they belong to THIS box and wakes + resumes it
50010
+ * when the user opens one, instead of showing a LOCAL session with a
50011
+ * "run codeam in your terminal" the user cannot do (codeagent-bbou).
50012
+ */
50013
+ knownSavedSessions() {
50014
+ try {
50015
+ const persisted = new Map(this.sessionStore.load().map((r) => [r.deployId, r.agent]));
50016
+ for (const c2 of this.children.values()) persisted.set(c2.deployId, c2.agent);
50017
+ return this.listSavedSessions().map((s) => ({ s, deployId: deployIdFromWorkspace(s.cwd) })).filter(
50018
+ (x) => x.deployId !== null && !!x.s.cwd && fs79.existsSync(x.s.cwd)
50019
+ ).map(({ s, deployId }) => {
50020
+ const agent = persisted.get(deployId);
50021
+ return { deployId, sessionId: s.id, ...agent ? { agent } : {} };
50022
+ });
50023
+ } catch {
50024
+ return [];
50025
+ }
50026
+ }
49236
50027
  /** Spawn ONE resume child for `target` (boot, retry, or re-probe). */
49237
50028
  resumeOne(target) {
49238
50029
  const { session, deployId } = target;
49239
50030
  if (this.children.has(deployId)) return;
49240
50031
  const st3 = this.resumeStateFor(target);
49241
50032
  try {
49242
- const cwd = fs78.existsSync(target.cwd) ? target.cwd : process.cwd();
50033
+ const cwd = fs79.existsSync(target.cwd) ? target.cwd : process.cwd();
49243
50034
  const proc = this.resumeSpawner(
49244
- { ...readHouseProxyChildEnv(), CODEAM_RESUME_SESSION_ID: session.id },
50035
+ { ...readHouseProxyChildEnv(deployId), CODEAM_RESUME_SESSION_ID: session.id },
49245
50036
  cwd
49246
50037
  );
49247
50038
  const child = {
49248
50039
  deployId,
49249
50040
  proc,
49250
50041
  cwd,
49251
- agent: session.agent,
49252
- startedAt: Date.now()
50042
+ agent: target.agent ?? session.agent,
50043
+ startedAt: Date.now(),
50044
+ sessionId: session.id
49253
50045
  };
49254
50046
  this.trackChild(child);
49255
50047
  let tail = "";
@@ -49265,7 +50057,7 @@ var HostAgentSupervisor = class {
49265
50057
  return;
49266
50058
  }
49267
50059
  if (tracked && signal) {
49268
- this.onResumeChildExit(target, 128 + (os62.constants.signals[signal] ?? 9), `signal ${signal}`);
50060
+ this.onResumeChildExit(target, 128 + (os63.constants.signals[signal] ?? 9), `signal ${signal}`);
49269
50061
  return;
49270
50062
  }
49271
50063
  log.warn(
@@ -49308,7 +50100,7 @@ var HostAgentSupervisor = class {
49308
50100
  if (Date.now() - child.startedAt < CRASH_RESPAWN_MIN_UPTIME_MS) return false;
49309
50101
  const session = pickSavedSessionForWorkspace(this.listSavedSessions(), child.cwd);
49310
50102
  if (!session) return false;
49311
- const exitCode = typeof code === "number" ? code : 128 + (signal ? os62.constants.signals[signal] ?? 9 : 9);
50103
+ const exitCode = typeof code === "number" ? code : 128 + (signal ? os63.constants.signals[signal] ?? 9 : 9);
49312
50104
  log.warn(
49313
50105
  "host-agent",
49314
50106
  `session deploy=${child.deployId.slice(0, 8)} died (${signal ?? code}) after ${Math.round((Date.now() - child.startedAt) / 1e3)}s \u2014 respawning it (resume)`
@@ -49457,12 +50249,12 @@ var HostAgentSupervisor = class {
49457
50249
  this.untrackChild(deployId);
49458
50250
  }
49459
50251
  const dirs = [
49460
- path92.join(selfHostedWorkspaceRoot(), deployId),
49461
- path92.join(os62.homedir(), ".codeam", "house-claude", deployId)
50252
+ path93.join(selfHostedWorkspaceRoot(), deployId),
50253
+ path93.join(os63.homedir(), ".codeam", "house-claude", deployId)
49462
50254
  ];
49463
50255
  for (const dir of dirs) {
49464
50256
  try {
49465
- fs78.rmSync(dir, { recursive: true, force: true });
50257
+ fs79.rmSync(dir, { recursive: true, force: true });
49466
50258
  } catch (err) {
49467
50259
  log.warn(
49468
50260
  "host-agent",
@@ -49621,9 +50413,9 @@ async function invite() {
49621
50413
  // src/commands/doctor.ts
49622
50414
  var import_node_dns = require("dns");
49623
50415
  var import_node_util6 = require("util");
49624
- var import_node_crypto12 = require("crypto");
49625
- var fs79 = __toESM(require("fs"));
49626
- var path93 = __toESM(require("path"));
50416
+ var import_node_crypto13 = require("crypto");
50417
+ var fs80 = __toESM(require("fs"));
50418
+ var path94 = __toESM(require("path"));
49627
50419
  var import_picocolors14 = __toESM(require("picocolors"));
49628
50420
  var dnsResolveP = (0, import_node_util6.promisify)(import_node_dns.resolve);
49629
50421
  async function checkDns(apiBase2) {
@@ -49679,13 +50471,13 @@ async function checkHealth(apiBase2) {
49679
50471
  }
49680
50472
  }
49681
50473
  function checkConfigDir() {
49682
- const dir = path93.join(require("os").homedir(), ".codeam");
50474
+ const dir = path94.join(require("os").homedir(), ".codeam");
49683
50475
  try {
49684
- fs79.mkdirSync(dir, { recursive: true, mode: 448 });
49685
- const probe = path93.join(dir, ".doctor-probe");
49686
- fs79.writeFileSync(probe, "ok", { mode: 384 });
49687
- const read = fs79.readFileSync(probe, "utf8");
49688
- fs79.unlinkSync(probe);
50476
+ fs80.mkdirSync(dir, { recursive: true, mode: 448 });
50477
+ const probe = path94.join(dir, ".doctor-probe");
50478
+ fs80.writeFileSync(probe, "ok", { mode: 384 });
50479
+ const read = fs80.readFileSync(probe, "utf8");
50480
+ fs80.unlinkSync(probe);
49689
50481
  if (read !== "ok") throw new Error("write/read round-trip mismatch");
49690
50482
  return {
49691
50483
  id: "config-dir",
@@ -49725,9 +50517,9 @@ function checkSessions() {
49725
50517
  }
49726
50518
  }
49727
50519
  function checkAgentBinaries() {
49728
- const os65 = createOsStrategy();
50520
+ const os66 = createOsStrategy();
49729
50521
  return getEnabledAgents().map((meta) => {
49730
- const found = os65.findInPath(meta.binaryName);
50522
+ const found = os66.findInPath(meta.binaryName);
49731
50523
  return {
49732
50524
  id: `agent-${meta.id}`,
49733
50525
  label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
@@ -49749,7 +50541,7 @@ function checkNodePty() {
49749
50541
  detail: "not required on this platform"
49750
50542
  };
49751
50543
  }
49752
- const vendoredPath = path93.join(__dirname, "vendor", "node-pty");
50544
+ const vendoredPath = path94.join(__dirname, "vendor", "node-pty");
49753
50545
  for (const target of [vendoredPath, "node-pty"]) {
49754
50546
  try {
49755
50547
  require(target);
@@ -49791,9 +50583,9 @@ function checkChokidar() {
49791
50583
  }
49792
50584
  async function doctor(args2 = []) {
49793
50585
  const json = args2.includes("--json");
49794
- const cliVersion = true ? "2.75.25" : "0.0.0-dev";
50586
+ const cliVersion = true ? "2.75.27" : "0.0.0-dev";
49795
50587
  const apiBase2 = resolveApiBaseUrl();
49796
- const diagnosticId = (0, import_node_crypto12.randomUUID)();
50588
+ const diagnosticId = (0, import_node_crypto13.randomUUID)();
49797
50589
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
49798
50590
  const [dns, health] = await Promise.all([
49799
50591
  checkDns(apiBase2),
@@ -50315,7 +51107,7 @@ async function mcpWarm(argv = [], opts = {}) {
50315
51107
  // src/commands/version.ts
50316
51108
  var import_picocolors15 = __toESM(require("picocolors"));
50317
51109
  function version2() {
50318
- const v = true ? "2.75.25" : "unknown";
51110
+ const v = true ? "2.75.27" : "unknown";
50319
51111
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
50320
51112
  }
50321
51113
 
@@ -50464,10 +51256,10 @@ var EXIT_CODE_NAMES = {
50464
51256
  };
50465
51257
 
50466
51258
  // src/index.ts
50467
- var os64 = __toESM(require("os"));
51259
+ var os65 = __toESM(require("os"));
50468
51260
  if (!process.env.HOME) {
50469
51261
  try {
50470
- const home = os64.homedir();
51262
+ const home = os65.homedir();
50471
51263
  if (home) process.env.HOME = home;
50472
51264
  } catch {
50473
51265
  }
@@ -50513,9 +51305,15 @@ async function main() {
50513
51305
  await commands[command]();
50514
51306
  return;
50515
51307
  }
51308
+ if (command === "mcp-run" || command === "mcp-router" || command === "preview-mcp") {
51309
+ loadMcpSecrets();
51310
+ }
50516
51311
  if (command === "mcp-run") {
50517
51312
  return mcpRun(args);
50518
51313
  }
51314
+ if (command === "preview-mcp") {
51315
+ return previewMcp();
51316
+ }
50519
51317
  if (command === "mcp-warm") {
50520
51318
  await mcpWarm(args);
50521
51319
  return;