codeam-cli 2.60.45 → 2.60.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/index.js +838 -419
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -475,6 +475,47 @@ function headroomKindFor(agentId) {
475
475
  return null;
476
476
  }
477
477
 
478
+ // ../../packages/shared/src/integrations/registry.ts
479
+ var INTEGRATION_REGISTRY = {
480
+ jira: {
481
+ id: "jira",
482
+ name: "Jira",
483
+ icon: "jira",
484
+ enabled: true,
485
+ auth: {
486
+ kind: "oauth_redirect",
487
+ scopes: ["read:jira-work", "write:jira-work", "offline_access"]
488
+ },
489
+ delivery: {
490
+ mcp: {
491
+ // mcp-atlassian in BYO-token mode (headless; credentials via env only).
492
+ // Version PINNED to the exact release verified headless by Plan 2's
493
+ // Docker integration test (apps/cli mcp-shim.int.test.ts).
494
+ command: "uvx",
495
+ args: ["mcp-atlassian==0.22.1"],
496
+ envMapping: {
497
+ ATLASSIAN_OAUTH_ACCESS_TOKEN: "accessToken",
498
+ ATLASSIAN_OAUTH_CLOUD_ID: "cloudId"
499
+ },
500
+ // Without ATLASSIAN_OAUTH_ENABLE=true, JiraConfig.from_env() raises
501
+ // "Missing required JIRA_URL" (swallowed at server startup) and the
502
+ // server silently registers ZERO Jira tools. The flag activates
503
+ // mcp-atlassian's "minimal OAuth config for user-provided tokens"
504
+ // mode — the BYO-token path the broker feeds. Static + non-secret.
505
+ staticEnv: { ATLASSIAN_OAUTH_ENABLE: "true" }
506
+ }
507
+ }
508
+ }
509
+ };
510
+ function getIntegration(id) {
511
+ const meta = INTEGRATION_REGISTRY[id];
512
+ if (!meta) throw new Error(`Unknown integration id: ${id}`);
513
+ return meta;
514
+ }
515
+ function isKnownIntegrationId(id) {
516
+ return id in INTEGRATION_REGISTRY;
517
+ }
518
+
478
519
  // ../../packages/shared/src/api-url.ts
479
520
  var DEFAULT_API_BASE_URL = "https://api.codeagent-mobile.com";
480
521
  var DEV_API_BASE_URL = "https://dev-api.codeagent-mobile.com";
@@ -592,6 +633,9 @@ var USER_EVENTS = {
592
633
  CLI_UPDATE_PROGRESS: "cli_update_progress",
593
634
  CLI_UPDATE_FAILED: "cli_update_failed",
594
635
  BATON_STATE: "baton_state",
636
+ INTEGRATION_LINKED: "integration_linked",
637
+ INTEGRATION_UNLINKED: "integration_unlinked",
638
+ INTEGRATION_CREDENTIAL_INVALID: "integration_credential_invalid",
595
639
  // CodeRabbit reviewer — the CLI posts these to /api/coderabbit/events; the
596
640
  // backend re-publishes them on the per-user SSE bus (mirrored in repo A).
597
641
  CODERABBIT_PROGRESS: "coderabbit_progress",
@@ -787,11 +831,11 @@ function quiet(fn) {
787
831
  log.debug(TAG, "ignored sync error", err);
788
832
  }
789
833
  }
790
- function rmIfExistsQuiet(path72) {
834
+ function rmIfExistsQuiet(path73) {
791
835
  try {
792
- fs2.rmSync(path72, { force: true });
836
+ fs2.rmSync(path73, { force: true });
793
837
  } catch (err) {
794
- log.debug(TAG, `rmIfExists failed for ${path72}`, err);
838
+ log.debug(TAG, `rmIfExists failed for ${path73}`, err);
795
839
  }
796
840
  }
797
841
  function killQuiet(target, signal = "SIGTERM") {
@@ -937,9 +981,9 @@ var _default = makeConfig();
937
981
  var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, getActiveSession, getActiveSessionForAgent, setDisable1mContext, clearAll, saveCliConfig, loadCliConfig } = _default;
938
982
 
939
983
  // src/commands/pair-auto.ts
940
- var fs54 = __toESM(require("fs"));
941
- var os43 = __toESM(require("os"));
942
- var path58 = __toESM(require("path"));
984
+ var fs55 = __toESM(require("fs"));
985
+ var os44 = __toESM(require("os"));
986
+ var path59 = __toESM(require("path"));
943
987
  var import_crypto4 = require("crypto");
944
988
 
945
989
  // src/services/telemetry.service.ts
@@ -975,8 +1019,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
975
1019
  return decodedFile;
976
1020
  };
977
1021
  }
978
- function normalizeWindowsPath(path72) {
979
- return path72.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1022
+ function normalizeWindowsPath(path73) {
1023
+ return path73.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
980
1024
  }
981
1025
 
982
1026
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3456,9 +3500,9 @@ async function addSourceContext(frames) {
3456
3500
  LRU_FILE_CONTENTS_CACHE.reduce();
3457
3501
  return frames;
3458
3502
  }
3459
- function getContextLinesFromFile(path72, ranges, output) {
3503
+ function getContextLinesFromFile(path73, ranges, output) {
3460
3504
  return new Promise((resolve7) => {
3461
- const stream = (0, import_node_fs.createReadStream)(path72);
3505
+ const stream = (0, import_node_fs.createReadStream)(path73);
3462
3506
  const lineReaded = (0, import_node_readline.createInterface)({
3463
3507
  input: stream
3464
3508
  });
@@ -3473,7 +3517,7 @@ function getContextLinesFromFile(path72, ranges, output) {
3473
3517
  let rangeStart = range[0];
3474
3518
  let rangeEnd = range[1];
3475
3519
  function onStreamError() {
3476
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path72, 1);
3520
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path73, 1);
3477
3521
  lineReaded.close();
3478
3522
  lineReaded.removeAllListeners();
3479
3523
  destroyStreamAndResolve();
@@ -3534,8 +3578,8 @@ function clearLineContext(frame) {
3534
3578
  delete frame.context_line;
3535
3579
  delete frame.post_context;
3536
3580
  }
3537
- function shouldSkipContextLinesForFile(path72) {
3538
- return path72.startsWith("node:") || path72.endsWith(".min.js") || path72.endsWith(".min.cjs") || path72.endsWith(".min.mjs") || path72.startsWith("data:");
3581
+ function shouldSkipContextLinesForFile(path73) {
3582
+ return path73.startsWith("node:") || path73.endsWith(".min.js") || path73.endsWith(".min.cjs") || path73.endsWith(".min.mjs") || path73.startsWith("data:");
3539
3583
  }
3540
3584
  function shouldSkipContextLinesForFrame(frame) {
3541
3585
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -5689,7 +5733,7 @@ function readAnonId() {
5689
5733
  }
5690
5734
  function superProperties() {
5691
5735
  return {
5692
- cliVersion: true ? "2.60.45" : "0.0.0-dev",
5736
+ cliVersion: true ? "2.60.47" : "0.0.0-dev",
5693
5737
  nodeVersion: process.version,
5694
5738
  platform: process.platform,
5695
5739
  arch: process.arch,
@@ -5870,7 +5914,7 @@ var os4 = __toESM(require("os"));
5870
5914
  // package.json
5871
5915
  var package_default = {
5872
5916
  name: "codeam-cli",
5873
- version: "2.60.45",
5917
+ version: "2.60.47",
5874
5918
  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.",
5875
5919
  type: "commonjs",
5876
5920
  main: "dist/index.js",
@@ -6979,7 +7023,7 @@ var CommandRelayService = class {
6979
7023
  // fresh + clear the "CLI update available" banner after a self-update
6980
7024
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
6981
7025
  // pair/reconnect). Older backends ignore the extra field.
6982
- ..."2.60.45" ? { ideVersion: "2.60.45" } : {}
7026
+ ..."2.60.47" ? { ideVersion: "2.60.47" } : {}
6983
7027
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
6984
7028
  }
6985
7029
  /**
@@ -8353,9 +8397,9 @@ function closeAllTerminals() {
8353
8397
  }
8354
8398
 
8355
8399
  // src/commands/start/handlers.ts
8356
- var fs53 = __toESM(require("fs"));
8357
- var os42 = __toESM(require("os"));
8358
- var path57 = __toESM(require("path"));
8400
+ var fs54 = __toESM(require("fs"));
8401
+ var os43 = __toESM(require("os"));
8402
+ var path58 = __toESM(require("path"));
8359
8403
  var import_crypto3 = require("crypto");
8360
8404
  var import_child_process23 = require("child_process");
8361
8405
 
@@ -11812,10 +11856,10 @@ function buildForPlatform(platform3) {
11812
11856
  var import_node_crypto4 = require("crypto");
11813
11857
 
11814
11858
  // src/agents/claude/resolver.ts
11815
- function buildClaudeLaunch(extraArgs = [], os50 = createOsStrategy()) {
11816
- const found = os50.findInPath("claude") ?? os50.findInPath("claude-code");
11859
+ function buildClaudeLaunch(extraArgs = [], os51 = createOsStrategy()) {
11860
+ const found = os51.findInPath("claude") ?? os51.findInPath("claude-code");
11817
11861
  if (!found) return null;
11818
- return os50.buildLaunch(found, extraArgs);
11862
+ return os51.buildLaunch(found, extraArgs);
11819
11863
  }
11820
11864
 
11821
11865
  // src/agents/claude/installer.ts
@@ -12405,8 +12449,8 @@ var ClaudeRuntimeStrategy = class {
12405
12449
  meta = getAgent("claude");
12406
12450
  mode = "interactive";
12407
12451
  os;
12408
- constructor(os50) {
12409
- this.os = os50;
12452
+ constructor(os51) {
12453
+ this.os = os51;
12410
12454
  }
12411
12455
  /**
12412
12456
  * Claude Code's react-ink TUI enables bracketed-paste mode at
@@ -13186,8 +13230,8 @@ function codexCredentialLocator() {
13186
13230
  function codexLoginLauncher() {
13187
13231
  return {
13188
13232
  async ensureInstalled() {
13189
- const os50 = createOsStrategy();
13190
- return os50.findInPath("codex") !== null;
13233
+ const os51 = createOsStrategy();
13234
+ return os51.findInPath("codex") !== null;
13191
13235
  },
13192
13236
  launch() {
13193
13237
  return (0, import_node_child_process4.spawn)("codex", ["login"], { stdio: "inherit" });
@@ -13210,8 +13254,8 @@ var CodexRuntimeStrategy = class {
13210
13254
  meta = getAgent("codex");
13211
13255
  mode = "interactive";
13212
13256
  os;
13213
- constructor(os50) {
13214
- this.os = os50;
13257
+ constructor(os51) {
13258
+ this.os = os51;
13215
13259
  }
13216
13260
  async prepareLaunch() {
13217
13261
  let binary = this.os.findInPath("codex");
@@ -13320,12 +13364,12 @@ var CodexRuntimeStrategy = class {
13320
13364
  });
13321
13365
  }
13322
13366
  };
13323
- function resolveNpm(os50) {
13324
- return os50.id === "win32" ? "npm.cmd" : "npm";
13367
+ function resolveNpm(os51) {
13368
+ return os51.id === "win32" ? "npm.cmd" : "npm";
13325
13369
  }
13326
- async function installCodexViaNpm(os50) {
13370
+ async function installCodexViaNpm(os51) {
13327
13371
  return new Promise((resolve7, reject) => {
13328
- const proc = (0, import_node_child_process5.spawn)(resolveNpm(os50), ["install", "-g", "@openai/codex"], {
13372
+ const proc = (0, import_node_child_process5.spawn)(resolveNpm(os51), ["install", "-g", "@openai/codex"], {
13329
13373
  stdio: "inherit"
13330
13374
  });
13331
13375
  proc.on("close", (code) => {
@@ -13342,16 +13386,16 @@ async function installCodexViaNpm(os50) {
13342
13386
  });
13343
13387
  });
13344
13388
  }
13345
- function augmentNpmGlobalBin(os50) {
13389
+ function augmentNpmGlobalBin(os51) {
13346
13390
  try {
13347
- const result = (0, import_node_child_process5.spawnSync)(resolveNpm(os50), ["prefix", "-g"], {
13391
+ const result = (0, import_node_child_process5.spawnSync)(resolveNpm(os51), ["prefix", "-g"], {
13348
13392
  stdio: ["ignore", "pipe", "ignore"]
13349
13393
  });
13350
13394
  if (result.status !== 0) return;
13351
13395
  const prefix = result.stdout.toString().trim();
13352
13396
  if (!prefix) return;
13353
- const binDir = os50.id === "win32" ? prefix : path24.join(prefix, "bin");
13354
- os50.augmentPath([binDir]);
13397
+ const binDir = os51.id === "win32" ? prefix : path24.join(prefix, "bin");
13398
+ os51.augmentPath([binDir]);
13355
13399
  } catch {
13356
13400
  }
13357
13401
  }
@@ -13435,9 +13479,9 @@ var import_node_child_process8 = require("child_process");
13435
13479
  // src/agents/coderabbit/installer.ts
13436
13480
  var import_node_child_process6 = require("child_process");
13437
13481
  var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
13438
- async function ensureCoderabbitInstalled(os50) {
13439
- if (os50.findInPath("coderabbit")) return true;
13440
- if (os50.id === "win32") {
13482
+ async function ensureCoderabbitInstalled(os51) {
13483
+ if (os51.findInPath("coderabbit")) return true;
13484
+ if (os51.id === "win32") {
13441
13485
  console.error(
13442
13486
  "\n \u2717 CodeRabbit on Windows requires WSL.\n Install the CLI inside your WSL distribution\n (curl -fsSL https://cli.coderabbit.ai/install.sh | sh)\n then re-run `codeam link coderabbit` from WSL.\n"
13443
13487
  );
@@ -13452,8 +13496,8 @@ async function ensureCoderabbitInstalled(os50) {
13452
13496
  proc.on("error", () => resolve7(false));
13453
13497
  });
13454
13498
  if (!ok) return false;
13455
- os50.augmentPath([`${os50.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
13456
- return os50.findInPath("coderabbit") !== null;
13499
+ os51.augmentPath([`${os51.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
13500
+ return os51.findInPath("coderabbit") !== null;
13457
13501
  }
13458
13502
 
13459
13503
  // src/agents/coderabbit/link.ts
@@ -13488,10 +13532,10 @@ function coderabbitCredentialLocator() {
13488
13532
  validate: validateNonEmptyCredential
13489
13533
  };
13490
13534
  }
13491
- function coderabbitLoginLauncher(os50) {
13535
+ function coderabbitLoginLauncher(os51) {
13492
13536
  return {
13493
13537
  async ensureInstalled() {
13494
- return ensureCoderabbitInstalled(os50);
13538
+ return ensureCoderabbitInstalled(os51);
13495
13539
  },
13496
13540
  launch() {
13497
13541
  return (0, import_node_child_process7.spawn)("coderabbit", ["auth", "login"], { stdio: "inherit" });
@@ -13547,8 +13591,8 @@ function pickLine(obj) {
13547
13591
  function toHunk(raw, groupSeverity) {
13548
13592
  if (!raw || typeof raw !== "object") return null;
13549
13593
  const o = raw;
13550
- const path72 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
13551
- if (!path72) return null;
13594
+ const path73 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
13595
+ if (!path73) return null;
13552
13596
  const message = asString(
13553
13597
  pick(o, [
13554
13598
  "comment",
@@ -13565,7 +13609,7 @@ function toHunk(raw, groupSeverity) {
13565
13609
  const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
13566
13610
  const locObj = pick(o, ["location"]) ?? o;
13567
13611
  return {
13568
- path: path72.trim(),
13612
+ path: path73.trim(),
13569
13613
  line: pickLine(o) ?? pickLine(locObj),
13570
13614
  severity,
13571
13615
  message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
@@ -13648,10 +13692,10 @@ function parsePlain(stdout) {
13648
13692
  for (const line of stdout.split(/\r?\n/)) {
13649
13693
  const m = line.match(HUNK_LINE_RE);
13650
13694
  if (!m) continue;
13651
- const [, path72, lineNo, sevToken, message] = m;
13652
- if (!path72 || !lineNo || !message) continue;
13695
+ const [, path73, lineNo, sevToken, message] = m;
13696
+ if (!path73 || !lineNo || !message) continue;
13653
13697
  hunks.push({
13654
- path: path72.trim(),
13698
+ path: path73.trim(),
13655
13699
  line: Number(lineNo),
13656
13700
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
13657
13701
  message: message.trim().replace(/^[*-]\s+/, "")
@@ -13711,8 +13755,8 @@ var CoderabbitRuntimeStrategy = class {
13711
13755
  meta = getAgent("coderabbit");
13712
13756
  mode = "batch";
13713
13757
  os;
13714
- constructor(os50) {
13715
- this.os = os50;
13758
+ constructor(os51) {
13759
+ this.os = os51;
13716
13760
  }
13717
13761
  getDefaultArgs() {
13718
13762
  return ["review", "--agent"];
@@ -13983,10 +14027,10 @@ function cursorCredentialLocator() {
13983
14027
  validate: validateNonEmptyCredential
13984
14028
  };
13985
14029
  }
13986
- function cursorLoginLauncher(os50) {
14030
+ function cursorLoginLauncher(os51) {
13987
14031
  return {
13988
14032
  async ensureInstalled() {
13989
- if (os50.findInPath("cursor-agent")) return true;
14033
+ if (os51.findInPath("cursor-agent")) return true;
13990
14034
  console.error(
13991
14035
  "\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"
13992
14036
  );
@@ -14050,8 +14094,8 @@ var CursorRuntimeStrategy = class {
14050
14094
  meta = getAgent("cursor");
14051
14095
  mode = "interactive";
14052
14096
  os;
14053
- constructor(os50) {
14054
- this.os = os50;
14097
+ constructor(os51) {
14098
+ this.os = os51;
14055
14099
  }
14056
14100
  async prepareLaunch() {
14057
14101
  const binary = this.os.findInPath("cursor-agent");
@@ -14267,10 +14311,10 @@ function aiderCredentialLocator() {
14267
14311
  validate: validateNonEmptyCredential
14268
14312
  };
14269
14313
  }
14270
- function aiderLoginLauncher(os50) {
14314
+ function aiderLoginLauncher(os51) {
14271
14315
  return {
14272
14316
  async ensureInstalled() {
14273
- if (os50.findInPath("aider")) return true;
14317
+ if (os51.findInPath("aider")) return true;
14274
14318
  console.error(
14275
14319
  "\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
14276
14320
  );
@@ -14280,7 +14324,7 @@ function aiderLoginLauncher(os50) {
14280
14324
  console.error(
14281
14325
  "\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"
14282
14326
  );
14283
- return (0, import_node_child_process11.spawn)(os50.id === "win32" ? "cmd.exe" : "sh", os50.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
14327
+ return (0, import_node_child_process11.spawn)(os51.id === "win32" ? "cmd.exe" : "sh", os51.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
14284
14328
  stdio: "ignore"
14285
14329
  });
14286
14330
  }
@@ -14352,8 +14396,8 @@ var AiderRuntimeStrategy = class {
14352
14396
  meta = getAgent("aider");
14353
14397
  mode = "interactive";
14354
14398
  os;
14355
- constructor(os50) {
14356
- this.os = os50;
14399
+ constructor(os51) {
14400
+ this.os = os51;
14357
14401
  }
14358
14402
  async prepareLaunch() {
14359
14403
  const binary = this.os.findInPath("aider");
@@ -14485,8 +14529,8 @@ function geminiCredentialLocator() {
14485
14529
  function geminiLoginLauncher() {
14486
14530
  return {
14487
14531
  async ensureInstalled() {
14488
- const os50 = createOsStrategy();
14489
- return os50.findInPath("gemini") !== null;
14532
+ const os51 = createOsStrategy();
14533
+ return os51.findInPath("gemini") !== null;
14490
14534
  },
14491
14535
  launch() {
14492
14536
  return (0, import_node_child_process12.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
@@ -14676,8 +14720,8 @@ var GeminiRuntimeStrategy = class {
14676
14720
  meta = getAgent("gemini");
14677
14721
  mode = "interactive";
14678
14722
  os;
14679
- constructor(os50) {
14680
- this.os = os50;
14723
+ constructor(os51) {
14724
+ this.os = os51;
14681
14725
  }
14682
14726
  async prepareLaunch() {
14683
14727
  const binary = this.os.findInPath("gemini");
@@ -14968,8 +15012,8 @@ var KimiRuntimeStrategy = class {
14968
15012
  meta = getAgent("kimi");
14969
15013
  mode = "interactive";
14970
15014
  os;
14971
- constructor(os50) {
14972
- this.os = os50;
15015
+ constructor(os51) {
15016
+ this.os = os51;
14973
15017
  }
14974
15018
  async prepareLaunch() {
14975
15019
  const binary = this.os.findInPath("kimi");
@@ -15082,19 +15126,19 @@ var KimiRuntimeStrategy = class {
15082
15126
 
15083
15127
  // src/agents/registry.ts
15084
15128
  var runtimeBuilders = {
15085
- claude: (os50) => new ClaudeRuntimeStrategy(os50),
15086
- codex: (os50) => new CodexRuntimeStrategy(os50),
15087
- coderabbit: (os50) => new CoderabbitRuntimeStrategy(os50),
15088
- cursor: (os50) => new CursorRuntimeStrategy(os50),
15089
- aider: (os50) => new AiderRuntimeStrategy(os50),
15090
- gemini: (os50) => new GeminiRuntimeStrategy(os50),
15091
- kimi: (os50) => new KimiRuntimeStrategy(os50)
15129
+ claude: (os51) => new ClaudeRuntimeStrategy(os51),
15130
+ codex: (os51) => new CodexRuntimeStrategy(os51),
15131
+ coderabbit: (os51) => new CoderabbitRuntimeStrategy(os51),
15132
+ cursor: (os51) => new CursorRuntimeStrategy(os51),
15133
+ aider: (os51) => new AiderRuntimeStrategy(os51),
15134
+ gemini: (os51) => new GeminiRuntimeStrategy(os51),
15135
+ kimi: (os51) => new KimiRuntimeStrategy(os51)
15092
15136
  };
15093
15137
  var deployBuilders = {
15094
15138
  claude: () => new ClaudeDeployStrategy(),
15095
15139
  codex: () => new CodexDeployStrategy()
15096
15140
  };
15097
- function createAgentStrategy(agent, os50 = createOsStrategy()) {
15141
+ function createAgentStrategy(agent, os51 = createOsStrategy()) {
15098
15142
  if (!AGENT_REGISTRY[agent]?.enabled) {
15099
15143
  throw new Error(
15100
15144
  `Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
@@ -15104,10 +15148,10 @@ function createAgentStrategy(agent, os50 = createOsStrategy()) {
15104
15148
  if (!build) {
15105
15149
  throw new Error(`No runtime strategy registered for agent "${agent}"`);
15106
15150
  }
15107
- return build(os50);
15151
+ return build(os51);
15108
15152
  }
15109
- function createInteractiveAgentStrategy(agent, os50 = createOsStrategy()) {
15110
- const s = createAgentStrategy(agent, os50);
15153
+ function createInteractiveAgentStrategy(agent, os51 = createOsStrategy()) {
15154
+ const s = createAgentStrategy(agent, os51);
15111
15155
  if (s.mode !== "interactive") {
15112
15156
  throw new Error(
15113
15157
  `Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
@@ -15799,26 +15843,26 @@ function restoreCoderabbitOauthBlob(value) {
15799
15843
  (0, import_node_fs5.writeFileSync)(path36.join(dir, file), contents, { mode: 384 });
15800
15844
  }
15801
15845
  async function configureCoderabbit(input, deps = {}) {
15802
- const os50 = deps.os ?? createOsStrategy();
15846
+ const os51 = deps.os ?? createOsStrategy();
15803
15847
  const ensureInstalled = deps.ensureInstalled ?? ensureCoderabbitInstalled;
15804
15848
  const isLoggedIn = deps.isLoggedIn ?? defaultIsLoggedIn;
15805
15849
  const runOAuth = deps.runOAuthLogin ?? runCoderabbitOAuthLogin;
15806
15850
  const snapshot = deps.snapshotDir ?? (() => snapshotCredentialDir());
15807
15851
  const capture2 = deps.captureCredential ?? ((b) => diffCapturedCredential(b));
15808
15852
  const loginWithApiKey = deps.loginWithApiKey ?? defaultLoginWithApiKey;
15809
- const home = os50.homeDir();
15810
- os50.augmentPath(
15811
- os50.id === "win32" ? [
15853
+ const home = os51.homeDir();
15854
+ os51.augmentPath(
15855
+ os51.id === "win32" ? [
15812
15856
  path36.join(home, ".local", "bin"),
15813
15857
  path36.join(process.env.APPDATA ?? path36.join(home, "AppData", "Roaming"), "npm"),
15814
15858
  path36.join(home, "scoop", "shims")
15815
15859
  ] : [path36.join(home, ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin"]
15816
15860
  );
15817
- const installed2 = os50.findInPath("coderabbit") !== null;
15861
+ const installed2 = os51.findInPath("coderabbit") !== null;
15818
15862
  const base = () => ({
15819
15863
  action: input.action,
15820
15864
  supported: true,
15821
- installed: os50.findInPath("coderabbit") !== null,
15865
+ installed: os51.findInPath("coderabbit") !== null,
15822
15866
  loggedIn: false
15823
15867
  });
15824
15868
  if (input.action === "status") {
@@ -15832,7 +15876,7 @@ async function configureCoderabbit(input, deps = {}) {
15832
15876
  const key = (input.apiKey ?? "").trim();
15833
15877
  if (!key) return { ...res2, error: "No API key provided" };
15834
15878
  if (!res2.installed) {
15835
- const ok = await ensureInstalled(os50);
15879
+ const ok = await ensureInstalled(os51);
15836
15880
  res2.installed = ok;
15837
15881
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
15838
15882
  }
@@ -15856,7 +15900,7 @@ async function configureCoderabbit(input, deps = {}) {
15856
15900
  }
15857
15901
  if (!res2.installed) {
15858
15902
  deps.onEvent?.({ kind: "installing" });
15859
- const ok = await ensureInstalled(os50);
15903
+ const ok = await ensureInstalled(os51);
15860
15904
  res2.installed = ok;
15861
15905
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
15862
15906
  }
@@ -15886,7 +15930,7 @@ async function configureCoderabbit(input, deps = {}) {
15886
15930
  const res2 = base();
15887
15931
  if (!installed2) {
15888
15932
  deps.onEvent?.({ kind: "installing" });
15889
- const ok = await ensureInstalled(os50);
15933
+ const ok = await ensureInstalled(os51);
15890
15934
  res2.installed = ok;
15891
15935
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
15892
15936
  }
@@ -15923,7 +15967,7 @@ async function configureCoderabbit(input, deps = {}) {
15923
15967
  }
15924
15968
  const res = base();
15925
15969
  if (!res.installed) {
15926
- const ok = await ensureInstalled(os50);
15970
+ const ok = await ensureInstalled(os51);
15927
15971
  res.installed = ok;
15928
15972
  if (!ok) return { ...res, error: "CodeRabbit CLI is not installed" };
15929
15973
  }
@@ -15952,14 +15996,14 @@ async function configureCoderabbit(input, deps = {}) {
15952
15996
 
15953
15997
  // src/commands/host-agent.ts
15954
15998
  var import_node_child_process23 = require("child_process");
15955
- var os35 = __toESM(require("os"));
15956
- var fs41 = __toESM(require("fs"));
15957
- var path44 = __toESM(require("path"));
15999
+ var os36 = __toESM(require("os"));
16000
+ var fs42 = __toESM(require("fs"));
16001
+ var path45 = __toESM(require("path"));
15958
16002
 
15959
- // src/commands/host/host-client.ts
15960
- var fs33 = __toESM(require("fs"));
15961
- var os29 = __toESM(require("os"));
15962
- var path37 = __toESM(require("path"));
16003
+ // src/integrations/manifest.ts
16004
+ var import_node_fs7 = __toESM(require("fs"));
16005
+ var import_node_os6 = __toESM(require("os"));
16006
+ var import_node_path5 = __toESM(require("path"));
15963
16007
 
15964
16008
  // src/lib/restrict-to-owner.ts
15965
16009
  var import_node_fs6 = __toESM(require("fs"));
@@ -15994,11 +16038,49 @@ function restrictToOwner(filePath) {
15994
16038
  }
15995
16039
  }
15996
16040
 
16041
+ // src/integrations/manifest.ts
16042
+ function integrationsManifestPath() {
16043
+ return import_node_path5.default.join(import_node_os6.default.homedir(), ".codeam", "integrations.json");
16044
+ }
16045
+ function readIntegrationsManifest() {
16046
+ try {
16047
+ const raw = JSON.parse(import_node_fs7.default.readFileSync(integrationsManifestPath(), "utf8"));
16048
+ if (!Array.isArray(raw?.integrations)) return null;
16049
+ return raw;
16050
+ } catch {
16051
+ return null;
16052
+ }
16053
+ }
16054
+ function persistIntegrationsManifest(m) {
16055
+ try {
16056
+ const file = integrationsManifestPath();
16057
+ import_node_fs7.default.mkdirSync(import_node_path5.default.dirname(file), { recursive: true, mode: 448 });
16058
+ const tmp = `${file}.tmp-${process.pid}`;
16059
+ import_node_fs7.default.writeFileSync(tmp, JSON.stringify(m, null, 2), { encoding: "utf8", mode: 384 });
16060
+ import_node_fs7.default.renameSync(tmp, file);
16061
+ restrictToOwner(file);
16062
+ } catch (err) {
16063
+ log.warn(
16064
+ "integrations",
16065
+ `failed to persist integrations manifest (best-effort): ${err instanceof Error ? err.message : String(err)}`
16066
+ );
16067
+ }
16068
+ }
16069
+ function clearIntegrationsManifest() {
16070
+ try {
16071
+ import_node_fs7.default.rmSync(integrationsManifestPath(), { force: true });
16072
+ } catch {
16073
+ }
16074
+ }
16075
+
15997
16076
  // src/commands/host/host-client.ts
16077
+ var fs34 = __toESM(require("fs"));
16078
+ var os30 = __toESM(require("os"));
16079
+ var path38 = __toESM(require("path"));
15998
16080
  function sampleCpuTimes() {
15999
16081
  let idle = 0;
16000
16082
  let total = 0;
16001
- for (const cpu of os29.cpus()) {
16083
+ for (const cpu of os30.cpus()) {
16002
16084
  const t2 = cpu.times;
16003
16085
  idle += t2.idle;
16004
16086
  total += t2.user + t2.nice + t2.sys + t2.idle + t2.irq;
@@ -16017,8 +16099,8 @@ var MetricsCollector = class {
16017
16099
  const prev = this.prevCpu;
16018
16100
  this.prevCpu = current;
16019
16101
  if (!prev) {
16020
- const cores = os29.cpus().length || 1;
16021
- const proxy = os29.loadavg()[0] / cores * 100;
16102
+ const cores = os30.cpus().length || 1;
16103
+ const proxy = os30.loadavg()[0] / cores * 100;
16022
16104
  return Math.min(100, Math.max(0, Math.round(proxy)));
16023
16105
  }
16024
16106
  const idleDelta = current.idle - prev.idle;
@@ -16031,8 +16113,8 @@ var MetricsCollector = class {
16031
16113
  collect() {
16032
16114
  return {
16033
16115
  cpuPct: this.cpuPct(),
16034
- ramUsedMb: Math.round((os29.totalmem() - os29.freemem()) / 1048576),
16035
- ramTotalMb: Math.round(os29.totalmem() / 1048576),
16116
+ ramUsedMb: Math.round((os30.totalmem() - os30.freemem()) / 1048576),
16117
+ ramTotalMb: Math.round(os30.totalmem() / 1048576),
16036
16118
  latencyMs: this.lastLatencyMs
16037
16119
  };
16038
16120
  }
@@ -16041,19 +16123,19 @@ function apiBase() {
16041
16123
  return process.env.CODEAM_API_URL ?? resolveApiBaseUrl();
16042
16124
  }
16043
16125
  function hostIdentityPath() {
16044
- return path37.join(os29.homedir(), ".codeam", "host-agent.json");
16126
+ return path38.join(os30.homedir(), ".codeam", "host-agent.json");
16045
16127
  }
16046
16128
  function collectOsInfo() {
16047
16129
  return {
16048
- distro: os29.platform(),
16049
- arch: os29.arch(),
16050
- kernel: os29.release(),
16130
+ distro: os30.platform(),
16131
+ arch: os30.arch(),
16132
+ kernel: os30.release(),
16051
16133
  nodeVersion: process.versions.node
16052
16134
  };
16053
16135
  }
16054
16136
  function loadHostIdentity() {
16055
16137
  try {
16056
- const raw = fs33.readFileSync(hostIdentityPath(), "utf8");
16138
+ const raw = fs34.readFileSync(hostIdentityPath(), "utf8");
16057
16139
  const parsed = JSON.parse(raw);
16058
16140
  if (typeof parsed === "object" && parsed !== null && typeof parsed.hostId === "string" && typeof parsed.hostToken === "string" && typeof parsed.controlPluginId === "string") {
16059
16141
  const p2 = parsed;
@@ -16066,8 +16148,8 @@ function loadHostIdentity() {
16066
16148
  }
16067
16149
  function saveHostIdentity(identity) {
16068
16150
  const file = hostIdentityPath();
16069
- fs33.mkdirSync(path37.dirname(file), { recursive: true, mode: 448 });
16070
- fs33.writeFileSync(file, JSON.stringify(identity, null, 2), {
16151
+ fs34.mkdirSync(path38.dirname(file), { recursive: true, mode: 448 });
16152
+ fs34.writeFileSync(file, JSON.stringify(identity, null, 2), {
16071
16153
  encoding: "utf8",
16072
16154
  mode: 384
16073
16155
  });
@@ -16112,7 +16194,7 @@ function isTerminalEnrollError(err) {
16112
16194
  }
16113
16195
  function deleteHostIdentity() {
16114
16196
  try {
16115
- fs33.rmSync(hostIdentityPath(), { force: true });
16197
+ fs34.rmSync(hostIdentityPath(), { force: true });
16116
16198
  } catch {
16117
16199
  }
16118
16200
  }
@@ -16235,17 +16317,17 @@ async function reportDeployProgress(auth, deployId, step, message, sessionId) {
16235
16317
  }
16236
16318
 
16237
16319
  // src/commands/host/workspace.ts
16238
- var fs34 = __toESM(require("fs"));
16239
- var os30 = __toESM(require("os"));
16240
- var path38 = __toESM(require("path"));
16320
+ var fs35 = __toESM(require("fs"));
16321
+ var os31 = __toESM(require("os"));
16322
+ var path39 = __toESM(require("path"));
16241
16323
  var import_node_child_process17 = require("child_process");
16242
16324
  var import_node_util4 = require("util");
16243
16325
  var execFileP4 = (0, import_node_util4.promisify)(import_node_child_process17.execFile);
16244
16326
  function isAbsolutePathTarget(target) {
16245
- return path38.isAbsolute(target);
16327
+ return path39.isAbsolute(target);
16246
16328
  }
16247
16329
  function selfHostedWorkspaceRoot() {
16248
- return path38.join(os30.homedir(), ".codeam", "self-hosted");
16330
+ return path39.join(os31.homedir(), ".codeam", "self-hosted");
16249
16331
  }
16250
16332
  function nonInteractiveGitEnv() {
16251
16333
  return {
@@ -16298,13 +16380,13 @@ async function fetchGithubIdentity(token) {
16298
16380
  async function configureGitCredentials(dest, repoRef, cloneToken) {
16299
16381
  const gh = githubOwnerRepo(repoRef.trim());
16300
16382
  if (!gh || !cloneToken) return;
16301
- const credFile = path38.join(dest, ".git", "codeam-credentials");
16302
- fs34.writeFileSync(credFile, `https://x-access-token:${cloneToken}@github.com
16383
+ const credFile = path39.join(dest, ".git", "codeam-credentials");
16384
+ fs35.writeFileSync(credFile, `https://x-access-token:${cloneToken}@github.com
16303
16385
  `, { mode: 384 });
16304
16386
  restrictToOwner(credFile);
16305
16387
  const env = nonInteractiveGitEnv();
16306
16388
  const git2 = (args2) => execFileP4("git", ["-C", dest, ...args2], { timeout: 3e4, env });
16307
- const credFilePosix = credFile.split(path38.sep).join("/");
16389
+ const credFilePosix = credFile.split(path39.sep).join("/");
16308
16390
  await git2(["config", "--local", "--replace-all", "credential.helper", ""]).catch(() => {
16309
16391
  });
16310
16392
  await git2([
@@ -16340,17 +16422,17 @@ function maskToken(text, cloneToken) {
16340
16422
  }
16341
16423
  async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
16342
16424
  if (isAbsolutePathTarget(repoOrPath)) {
16343
- if (!fs34.existsSync(repoOrPath)) {
16425
+ if (!fs35.existsSync(repoOrPath)) {
16344
16426
  throw new Error(`deploy target path does not exist: ${repoOrPath}`);
16345
16427
  }
16346
16428
  return repoOrPath;
16347
16429
  }
16348
- const dest = path38.join(selfHostedWorkspaceRoot(), deployId);
16349
- if (fs34.existsSync(path38.join(dest, ".git"))) {
16430
+ const dest = path39.join(selfHostedWorkspaceRoot(), deployId);
16431
+ if (fs35.existsSync(path39.join(dest, ".git"))) {
16350
16432
  if (cloneToken) await configureGitCredentials(dest, repoOrPath, cloneToken);
16351
16433
  return dest;
16352
16434
  }
16353
- fs34.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
16435
+ fs35.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
16354
16436
  const cloneUrl = repoCloneUrl(repoOrPath, cloneToken);
16355
16437
  try {
16356
16438
  await execFileP4("git", ["clone", "--depth", "1", cloneUrl, dest], {
@@ -16367,9 +16449,9 @@ async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
16367
16449
  }
16368
16450
 
16369
16451
  // src/commands/host/agent-provisioning.ts
16370
- var fs35 = __toESM(require("fs"));
16371
- var os31 = __toESM(require("os"));
16372
- var path39 = __toESM(require("path"));
16452
+ var fs36 = __toESM(require("fs"));
16453
+ var os32 = __toESM(require("os"));
16454
+ var path40 = __toESM(require("path"));
16373
16455
  var PUBLIC_TO_INTERNAL_AGENT = {
16374
16456
  claude_code: "claude",
16375
16457
  claude: "claude",
@@ -16385,22 +16467,22 @@ function toInternalAgentId(publicAgentId) {
16385
16467
  return PUBLIC_TO_INTERNAL_AGENT[publicAgentId] ?? null;
16386
16468
  }
16387
16469
  function ensureDir(dir) {
16388
- fs35.mkdirSync(dir, { recursive: true, mode: 448 });
16470
+ fs36.mkdirSync(dir, { recursive: true, mode: 448 });
16389
16471
  }
16390
16472
  function writeFile0600(filePath, contents) {
16391
- ensureDir(path39.dirname(filePath));
16392
- fs35.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
16473
+ ensureDir(path40.dirname(filePath));
16474
+ fs36.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
16393
16475
  restrictToOwner(filePath);
16394
16476
  }
16395
16477
  function rmIfExists(filePath) {
16396
16478
  try {
16397
- fs35.rmSync(filePath, { force: true });
16479
+ fs36.rmSync(filePath, { force: true });
16398
16480
  } catch {
16399
16481
  }
16400
16482
  }
16401
16483
  var claudeProvisioner = {
16402
16484
  write(auth, home) {
16403
- const credentialsJson = path39.join(home, ".claude", ".credentials.json");
16485
+ const credentialsJson = path40.join(home, ".claude", ".credentials.json");
16404
16486
  if (auth.kind === "api_key") {
16405
16487
  rmIfExists(credentialsJson);
16406
16488
  return { ANTHROPIC_API_KEY: auth.value };
@@ -16412,8 +16494,8 @@ var claudeProvisioner = {
16412
16494
  } else {
16413
16495
  rmIfExists(credentialsJson);
16414
16496
  }
16415
- const claudeJson = path39.join(home, ".claude.json");
16416
- if (!fs35.existsSync(claudeJson)) {
16497
+ const claudeJson = path40.join(home, ".claude.json");
16498
+ if (!fs36.existsSync(claudeJson)) {
16417
16499
  writeFile0600(
16418
16500
  claudeJson,
16419
16501
  JSON.stringify({ hasCompletedOnboarding: true, customApiKeyResponses: { approved: [] } })
@@ -16424,7 +16506,7 @@ var claudeProvisioner = {
16424
16506
  };
16425
16507
  var codexProvisioner = {
16426
16508
  write(auth, home) {
16427
- const authJson = path39.join(home, ".codex", "auth.json");
16509
+ const authJson = path40.join(home, ".codex", "auth.json");
16428
16510
  if (auth.kind === "api_key") {
16429
16511
  rmIfExists(authJson);
16430
16512
  return { OPENAI_API_KEY: auth.value };
@@ -16435,8 +16517,8 @@ var codexProvisioner = {
16435
16517
  };
16436
16518
  var geminiProvisioner = {
16437
16519
  write(auth, home) {
16438
- const settingsJson = path39.join(home, ".gemini", "settings.json");
16439
- const oauthCreds = path39.join(home, ".gemini", "oauth_creds.json");
16520
+ const settingsJson = path40.join(home, ".gemini", "settings.json");
16521
+ const oauthCreds = path40.join(home, ".gemini", "oauth_creds.json");
16440
16522
  if (auth.kind === "api_key") {
16441
16523
  rmIfExists(oauthCreds);
16442
16524
  writeFile0600(settingsJson, '{"security":{"auth":{"selectedType":"gemini-api-key"}}}');
@@ -16449,7 +16531,7 @@ var geminiProvisioner = {
16449
16531
  };
16450
16532
  var cursorProvisioner = {
16451
16533
  write(auth, home) {
16452
- const authJson = path39.join(home, ".config", "cursor", "auth.json");
16534
+ const authJson = path40.join(home, ".config", "cursor", "auth.json");
16453
16535
  if (auth.kind === "api_key") {
16454
16536
  rmIfExists(authJson);
16455
16537
  return { CURSOR_API_KEY: auth.value };
@@ -16475,8 +16557,8 @@ var cursorProvisioner = {
16475
16557
  var kimiProvisioner = {
16476
16558
  write(auth, home) {
16477
16559
  const credentialsFiles = [
16478
- path39.join(home, ".kimi", "credentials", "kimi-code.json"),
16479
- path39.join(home, ".kimi-code", "credentials", "kimi-code.json")
16560
+ path40.join(home, ".kimi", "credentials", "kimi-code.json"),
16561
+ path40.join(home, ".kimi-code", "credentials", "kimi-code.json")
16480
16562
  ];
16481
16563
  if (auth.kind === "api_key") {
16482
16564
  credentialsFiles.forEach(rmIfExists);
@@ -16488,8 +16570,8 @@ var kimiProvisioner = {
16488
16570
  };
16489
16571
  var coderabbitProvisioner = {
16490
16572
  write(auth, home) {
16491
- const dir = path39.join(home, ".coderabbit");
16492
- const authJson = path39.join(dir, "auth.json");
16573
+ const dir = path40.join(home, ".coderabbit");
16574
+ const authJson = path40.join(dir, "auth.json");
16493
16575
  if (auth.kind === "api_key") {
16494
16576
  rmIfExists(authJson);
16495
16577
  return { CODERABBIT_API_KEY: auth.value };
@@ -16501,13 +16583,13 @@ var coderabbitProvisioner = {
16501
16583
  try {
16502
16584
  const parsed = JSON.parse(value);
16503
16585
  if (typeof parsed.file === "string" && typeof parsed.contents === "string") {
16504
- file = path39.basename(parsed.file);
16586
+ file = path40.basename(parsed.file);
16505
16587
  contents = parsed.contents;
16506
16588
  }
16507
16589
  } catch {
16508
16590
  }
16509
16591
  }
16510
- writeFile0600(path39.join(dir, file), contents);
16592
+ writeFile0600(path40.join(dir, file), contents);
16511
16593
  return {};
16512
16594
  }
16513
16595
  };
@@ -16527,7 +16609,7 @@ var UnsupportedAgentError = class extends Error {
16527
16609
  this.agentId = agentId;
16528
16610
  }
16529
16611
  };
16530
- function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os31.homedir()) {
16612
+ function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os32.homedir()) {
16531
16613
  const internal = toInternalAgentId(publicAgentId);
16532
16614
  if (!internal) throw new UnsupportedAgentError(publicAgentId);
16533
16615
  const provisioner = PROVISIONERS[internal];
@@ -16537,11 +16619,11 @@ function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os31.homedir(
16537
16619
 
16538
16620
  // src/commands/host/git-tooling.ts
16539
16621
  var import_node_child_process18 = require("child_process");
16540
- var fs36 = __toESM(require("fs"));
16541
- var os32 = __toESM(require("os"));
16542
- var path40 = __toESM(require("path"));
16622
+ var fs37 = __toESM(require("fs"));
16623
+ var os33 = __toESM(require("os"));
16624
+ var path41 = __toESM(require("path"));
16543
16625
  function codeamBinDir() {
16544
- return process.env.CODEAM_BIN_DIR ?? path40.join(os32.homedir(), ".codeam", "bin");
16626
+ return process.env.CODEAM_BIN_DIR ?? path41.join(os33.homedir(), ".codeam", "bin");
16545
16627
  }
16546
16628
  var FALLBACK_GH_VERSION = "2.62.0";
16547
16629
  var RELEASE_API = "https://api.github.com/repos/cli/cli/releases/latest";
@@ -16573,7 +16655,7 @@ async function download(url, dest) {
16573
16655
  const res = await fetch(url, { headers: { "User-Agent": "codeam-cli" } });
16574
16656
  if (!res.ok || !res.body) return false;
16575
16657
  const buf = Buffer.from(await res.arrayBuffer());
16576
- fs36.writeFileSync(dest, buf);
16658
+ fs37.writeFileSync(dest, buf);
16577
16659
  return true;
16578
16660
  } catch {
16579
16661
  return false;
@@ -16596,8 +16678,8 @@ async function ensureGhCli(runner, token, deps = {}) {
16596
16678
  const version3 = await resolveVersionFn(token);
16597
16679
  const asset = `gh_${version3}_${osToken}_${arch2}`;
16598
16680
  const url = `https://github.com/cli/cli/releases/download/v${version3}/${asset}.${ext}`;
16599
- const tmpRoot = fs36.mkdtempSync(path40.join(os32.tmpdir(), "codeam-gh-"));
16600
- const archive = path40.join(tmpRoot, `${asset}.${ext}`);
16681
+ const tmpRoot = fs37.mkdtempSync(path41.join(os33.tmpdir(), "codeam-gh-"));
16682
+ const archive = path41.join(tmpRoot, `${asset}.${ext}`);
16601
16683
  if (!await downloadFn(url, archive)) {
16602
16684
  log.warn("host-agent", "gh download failed \u2014 skipping (git pull/push still work via the credential helper)");
16603
16685
  return null;
@@ -16607,16 +16689,16 @@ async function ensureGhCli(runner, token, deps = {}) {
16607
16689
  log.warn("host-agent", `gh archive extraction failed (code=${String(extract.code)}) \u2014 skipping`);
16608
16690
  return null;
16609
16691
  }
16610
- const extractedBin = path40.join(tmpRoot, asset, "bin", binaryName);
16611
- if (!fs36.existsSync(extractedBin)) {
16692
+ const extractedBin = path41.join(tmpRoot, asset, "bin", binaryName);
16693
+ if (!fs37.existsSync(extractedBin)) {
16612
16694
  log.warn("host-agent", "gh binary not found in the extracted archive \u2014 skipping");
16613
16695
  return null;
16614
16696
  }
16615
16697
  const binDir = codeamBinDir();
16616
- fs36.mkdirSync(binDir, { recursive: true });
16617
- const target = path40.join(binDir, binaryName);
16618
- fs36.copyFileSync(extractedBin, target);
16619
- fs36.chmodSync(target, 493);
16698
+ fs37.mkdirSync(binDir, { recursive: true });
16699
+ const target = path41.join(binDir, binaryName);
16700
+ fs37.copyFileSync(extractedBin, target);
16701
+ fs37.chmodSync(target, 493);
16620
16702
  log.info("host-agent", `gh installed to ${target} (v${version3})`);
16621
16703
  return target;
16622
16704
  } catch (e) {
@@ -17103,23 +17185,23 @@ async function ensureModernPython(runner) {
17103
17185
  }
17104
17186
 
17105
17187
  // src/commands/host/headroom-bootstrap.ts
17106
- var fs38 = __toESM(require("fs"));
17107
- var path42 = __toESM(require("path"));
17188
+ var fs39 = __toESM(require("fs"));
17189
+ var path43 = __toESM(require("path"));
17108
17190
 
17109
17191
  // src/commands/host/headroom-config.ts
17110
- var fs37 = __toESM(require("fs"));
17111
- var os33 = __toESM(require("os"));
17112
- var path41 = __toESM(require("path"));
17192
+ var fs38 = __toESM(require("fs"));
17193
+ var os34 = __toESM(require("os"));
17194
+ var path42 = __toESM(require("path"));
17113
17195
  function headroomConfigPath() {
17114
- return path41.join(os33.homedir(), ".codeam", "headroom-config.json");
17196
+ return path42.join(os34.homedir(), ".codeam", "headroom-config.json");
17115
17197
  }
17116
17198
  function persistHeadroomConfig(config) {
17117
17199
  try {
17118
17200
  const file = headroomConfigPath();
17119
- fs37.mkdirSync(path41.dirname(file), { recursive: true, mode: 448 });
17201
+ fs38.mkdirSync(path42.dirname(file), { recursive: true, mode: 448 });
17120
17202
  const tmp = `${file}.tmp-${process.pid}`;
17121
- fs37.writeFileSync(tmp, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
17122
- fs37.renameSync(tmp, file);
17203
+ fs38.writeFileSync(tmp, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
17204
+ fs38.renameSync(tmp, file);
17123
17205
  restrictToOwner(file);
17124
17206
  } catch (err) {
17125
17207
  log.warn(
@@ -17129,21 +17211,21 @@ function persistHeadroomConfig(config) {
17129
17211
  }
17130
17212
  }
17131
17213
  function agentSettingsPath(kind) {
17132
- const home = os33.homedir();
17133
- if (kind === "claude") return path41.join(home, ".claude", "settings.json");
17134
- if (kind === "codex") return path41.join(home, ".codex", "auth.json");
17135
- if (kind === "copilot") return path41.join(home, ".config", "github-copilot", "hosts.json");
17214
+ const home = os34.homedir();
17215
+ if (kind === "claude") return path42.join(home, ".claude", "settings.json");
17216
+ if (kind === "codex") return path42.join(home, ".codex", "auth.json");
17217
+ if (kind === "copilot") return path42.join(home, ".config", "github-copilot", "hosts.json");
17136
17218
  return null;
17137
17219
  }
17138
17220
  function backupAgentHeadroomConfig(kind) {
17139
17221
  const src = agentSettingsPath(kind);
17140
17222
  if (!src) return;
17141
17223
  try {
17142
- if (!fs37.existsSync(src)) return;
17143
- const dest = path41.join(os33.homedir(), ".codeam", `headroom-backup-${kind}.json`);
17144
- fs37.mkdirSync(path41.dirname(dest), { recursive: true, mode: 448 });
17145
- fs37.copyFileSync(src, dest);
17146
- fs37.chmodSync(dest, 384);
17224
+ if (!fs38.existsSync(src)) return;
17225
+ const dest = path42.join(os34.homedir(), ".codeam", `headroom-backup-${kind}.json`);
17226
+ fs38.mkdirSync(path42.dirname(dest), { recursive: true, mode: 448 });
17227
+ fs38.copyFileSync(src, dest);
17228
+ fs38.chmodSync(dest, 384);
17147
17229
  log.info("host-agent", `headroom config backup: ${src} \u2192 ${dest}`);
17148
17230
  } catch (err) {
17149
17231
  log.warn(
@@ -17155,12 +17237,12 @@ function backupAgentHeadroomConfig(kind) {
17155
17237
  function restoreAgentHeadroomConfig(kind) {
17156
17238
  const dest = agentSettingsPath(kind);
17157
17239
  if (!dest) return false;
17158
- const src = path41.join(os33.homedir(), ".codeam", `headroom-backup-${kind}.json`);
17159
- if (!fs37.existsSync(src)) return false;
17240
+ const src = path42.join(os34.homedir(), ".codeam", `headroom-backup-${kind}.json`);
17241
+ if (!fs38.existsSync(src)) return false;
17160
17242
  try {
17161
- fs37.mkdirSync(path41.dirname(dest), { recursive: true, mode: 448 });
17162
- fs37.copyFileSync(src, dest);
17163
- fs37.chmodSync(dest, 384);
17243
+ fs38.mkdirSync(path42.dirname(dest), { recursive: true, mode: 448 });
17244
+ fs38.copyFileSync(src, dest);
17245
+ fs38.chmodSync(dest, 384);
17164
17246
  log.info("host-agent", `headroom config restored: ${src} \u2192 ${dest}`);
17165
17247
  return true;
17166
17248
  } catch (err) {
@@ -17173,7 +17255,7 @@ function restoreAgentHeadroomConfig(kind) {
17173
17255
  }
17174
17256
  function readHeadroomChildEnv() {
17175
17257
  try {
17176
- const raw = fs37.readFileSync(headroomConfigPath(), "utf8");
17258
+ const raw = fs38.readFileSync(headroomConfigPath(), "utf8");
17177
17259
  const parsed = JSON.parse(raw);
17178
17260
  if (typeof parsed !== "object" || parsed === null) return {};
17179
17261
  const o = parsed;
@@ -17209,37 +17291,37 @@ function bundledClaudeBinDir() {
17209
17291
  const roots = /* @__PURE__ */ new Set();
17210
17292
  let dir = __dirname;
17211
17293
  for (let i = 0; i < 6; i++) {
17212
- roots.add(path42.join(dir, "node_modules"));
17213
- const parent = path42.dirname(dir);
17294
+ roots.add(path43.join(dir, "node_modules"));
17295
+ const parent = path43.dirname(dir);
17214
17296
  if (parent === dir) break;
17215
17297
  dir = parent;
17216
17298
  }
17217
17299
  try {
17218
17300
  const main2 = require.resolve("@anthropic-ai/claude-agent-sdk");
17219
- const marker = `${path42.sep}@anthropic-ai${path42.sep}`;
17301
+ const marker = `${path43.sep}@anthropic-ai${path43.sep}`;
17220
17302
  const idx = main2.lastIndexOf(marker);
17221
17303
  if (idx !== -1) roots.add(main2.slice(0, idx));
17222
17304
  } catch {
17223
17305
  }
17224
17306
  for (const nm of roots) {
17225
- const atAnthropic = path42.join(nm, "@anthropic-ai");
17307
+ const atAnthropic = path43.join(nm, "@anthropic-ai");
17226
17308
  let entries;
17227
17309
  try {
17228
- entries = fs38.readdirSync(atAnthropic);
17310
+ entries = fs39.readdirSync(atAnthropic);
17229
17311
  } catch {
17230
17312
  continue;
17231
17313
  }
17232
17314
  for (const entry of entries) {
17233
17315
  if (!entry.startsWith("claude-agent-sdk-")) continue;
17234
- const bin = path42.join(atAnthropic, entry, "claude");
17235
- if (fs38.existsSync(bin)) return path42.dirname(bin);
17316
+ const bin = path43.join(atAnthropic, entry, "claude");
17317
+ if (fs39.existsSync(bin)) return path43.dirname(bin);
17236
17318
  }
17237
17319
  }
17238
17320
  return null;
17239
17321
  }
17240
17322
  async function getFreeDiskBytes(dir) {
17241
17323
  try {
17242
- const s = await fs38.promises.statfs(dir);
17324
+ const s = await fs39.promises.statfs(dir);
17243
17325
  return s.bsize * s.bavail;
17244
17326
  } catch {
17245
17327
  return null;
@@ -17301,7 +17383,7 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
17301
17383
  if (initKind === "claude") {
17302
17384
  const claudeDir = bundledClaudeBinDir();
17303
17385
  if (claudeDir) {
17304
- initEnv.PATH = `${claudeDir}${path42.delimiter}${process.env["PATH"] ?? ""}`;
17386
+ initEnv.PATH = `${claudeDir}${path43.delimiter}${process.env["PATH"] ?? ""}`;
17305
17387
  log.info("host-agent", `headroom init: bundled claude on PATH (${claudeDir})`);
17306
17388
  } else {
17307
17389
  log.warn("host-agent", "headroom init: bundled claude binary not found \u2014 init may fail");
@@ -17336,9 +17418,9 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
17336
17418
  var import_node_child_process21 = require("child_process");
17337
17419
 
17338
17420
  // src/lib/updateNotifier.ts
17339
- var fs39 = __toESM(require("fs"));
17340
- var os34 = __toESM(require("os"));
17341
- var path43 = __toESM(require("path"));
17421
+ var fs40 = __toESM(require("fs"));
17422
+ var os35 = __toESM(require("os"));
17423
+ var path44 = __toESM(require("path"));
17342
17424
  var https6 = __toESM(require("https"));
17343
17425
  var import_node_child_process20 = require("child_process");
17344
17426
  var import_picocolors3 = __toESM(require("picocolors"));
@@ -17347,12 +17429,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
17347
17429
  var TTL_MS = 24 * 60 * 60 * 1e3;
17348
17430
  var REQUEST_TIMEOUT_MS = 1500;
17349
17431
  function cachePath() {
17350
- const dir = path43.join(os34.homedir(), ".codeam");
17351
- return path43.join(dir, "update-check.json");
17432
+ const dir = path44.join(os35.homedir(), ".codeam");
17433
+ return path44.join(dir, "update-check.json");
17352
17434
  }
17353
17435
  function readCache() {
17354
17436
  try {
17355
- const raw = fs39.readFileSync(cachePath(), "utf8");
17437
+ const raw = fs40.readFileSync(cachePath(), "utf8");
17356
17438
  const parsed = JSON.parse(raw);
17357
17439
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
17358
17440
  return parsed;
@@ -17363,10 +17445,10 @@ function readCache() {
17363
17445
  function writeCache(cache) {
17364
17446
  try {
17365
17447
  const file = cachePath();
17366
- fs39.mkdirSync(path43.dirname(file), { recursive: true });
17448
+ fs40.mkdirSync(path44.dirname(file), { recursive: true });
17367
17449
  const tmp = `${file}.${process.pid}.tmp`;
17368
- fs39.writeFileSync(tmp, JSON.stringify(cache));
17369
- fs39.renameSync(tmp, file);
17450
+ fs40.writeFileSync(tmp, JSON.stringify(cache));
17451
+ fs40.renameSync(tmp, file);
17370
17452
  } catch {
17371
17453
  }
17372
17454
  }
@@ -17440,8 +17522,8 @@ function isLinkedInstall() {
17440
17522
  timeout: 2e3
17441
17523
  }).trim();
17442
17524
  if (!root) return false;
17443
- const pkgPath = path43.join(root, PKG_NAME);
17444
- return fs39.lstatSync(pkgPath).isSymbolicLink();
17525
+ const pkgPath = path44.join(root, PKG_NAME);
17526
+ return fs40.lstatSync(pkgPath).isSymbolicLink();
17445
17527
  } catch {
17446
17528
  return false;
17447
17529
  }
@@ -17477,7 +17559,7 @@ function maybeAutoUpdate(currentVersion, latest) {
17477
17559
  return;
17478
17560
  }
17479
17561
  try {
17480
- fs39.unlinkSync(cachePath());
17562
+ fs40.unlinkSync(cachePath());
17481
17563
  } catch {
17482
17564
  }
17483
17565
  process.stderr.write(` ${import_picocolors3.default.green("\u2713")} Updated. Resuming session...
@@ -17493,7 +17575,7 @@ async function autoUpgradeBeforeCriticalCommand() {
17493
17575
  if (process.env.NODE_ENV === "test") return;
17494
17576
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17495
17577
  if (process.env.CI) return;
17496
- const current = true ? "2.60.45" : null;
17578
+ const current = true ? "2.60.47" : null;
17497
17579
  if (!current) return;
17498
17580
  const cache = readCache();
17499
17581
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17510,7 +17592,7 @@ function checkForUpdates() {
17510
17592
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17511
17593
  if (process.env.CI) return;
17512
17594
  if (!process.stdout.isTTY) return;
17513
- const current = true ? "2.60.45" : null;
17595
+ const current = true ? "2.60.47" : null;
17514
17596
  if (!current) return;
17515
17597
  const cache = readCache();
17516
17598
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17530,7 +17612,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
17530
17612
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
17531
17613
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
17532
17614
  function currentCliVersion() {
17533
- return true ? "2.60.45" : null;
17615
+ return true ? "2.60.47" : null;
17534
17616
  }
17535
17617
  function runCmd(cmd, args2, timeoutMs) {
17536
17618
  return new Promise((resolve7) => {
@@ -17597,7 +17679,7 @@ async function runSelfUpdate() {
17597
17679
 
17598
17680
  // src/commands/host/teardown.ts
17599
17681
  var import_node_child_process22 = require("child_process");
17600
- var fs40 = __toESM(require("fs"));
17682
+ var fs41 = __toESM(require("fs"));
17601
17683
  var defaultDisableService = () => {
17602
17684
  try {
17603
17685
  (0, import_node_child_process22.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
@@ -17606,7 +17688,7 @@ var defaultDisableService = () => {
17606
17688
  };
17607
17689
  var defaultTeardownHeadroom = () => {
17608
17690
  try {
17609
- const kind = JSON.parse(fs40.readFileSync(headroomConfigPath(), "utf8")).agent;
17691
+ const kind = JSON.parse(fs41.readFileSync(headroomConfigPath(), "utf8")).agent;
17610
17692
  if (kind) {
17611
17693
  (0, import_node_child_process22.execFileSync)("headroom", ["unwrap", kind], { stdio: "ignore", timeout: 15e3 });
17612
17694
  }
@@ -17674,8 +17756,8 @@ function maybeResumeLocalHeadroomReporter(ctx) {
17674
17756
  if (process.env["HEADROOM_ENABLED"] === "1") return null;
17675
17757
  try {
17676
17758
  const file = headroomConfigPath();
17677
- if (!fs41.existsSync(file)) return null;
17678
- const cfg = JSON.parse(fs41.readFileSync(file, "utf8"));
17759
+ if (!fs42.existsSync(file)) return null;
17760
+ const cfg = JSON.parse(fs42.readFileSync(file, "utf8"));
17679
17761
  if (!cfg?.enabled) return null;
17680
17762
  const agent = cfg.agent ?? "claude";
17681
17763
  const ingestUrl = `${resolveApiBaseUrl()}/api/sessions/${ctx.sessionId}/headroom-savings`;
@@ -17748,6 +17830,9 @@ function isDeployPayload(p2) {
17748
17830
  if (p2.headroomSavingsIngestUrl !== void 0 && typeof p2.headroomSavingsIngestUrl !== "string") {
17749
17831
  return false;
17750
17832
  }
17833
+ if (p2.integrations !== void 0 && !Array.isArray(p2.integrations)) {
17834
+ return false;
17835
+ }
17751
17836
  const hasHouse = isHouseProxy(p2.houseProxy);
17752
17837
  const hasSealed = typeof p2.sealedAgentAuth === "string";
17753
17838
  return hasHouse || hasSealed;
@@ -18080,9 +18165,9 @@ var HostAgentSupervisor = class {
18080
18165
  API_TIMEOUT_MS: "3000000",
18081
18166
  CODEAM_AUTO_TOKEN: payload.autoPairToken
18082
18167
  };
18083
- const houseConfigDir = path44.join(os35.homedir(), ".codeam", "house-claude");
18168
+ const houseConfigDir = path45.join(os36.homedir(), ".codeam", "house-claude");
18084
18169
  try {
18085
- fs41.mkdirSync(houseConfigDir, { recursive: true, mode: 448 });
18170
+ fs42.mkdirSync(houseConfigDir, { recursive: true, mode: 448 });
18086
18171
  } catch {
18087
18172
  }
18088
18173
  childEnv.CLAUDE_CONFIG_DIR = houseConfigDir;
@@ -18100,14 +18185,14 @@ var HostAgentSupervisor = class {
18100
18185
  report("installing", "installing agent CLI");
18101
18186
  await this.runAgentInstall(payload.agentInstallScript);
18102
18187
  }
18103
- const home = process.env.HOME || os35.homedir();
18188
+ const home = process.env.HOME || os36.homedir();
18104
18189
  childEnv.PATH = `${home}/.local/bin:${process.env.PATH ?? ""}`;
18105
18190
  if (payload.cloneToken) {
18106
18191
  try {
18107
18192
  report("preparing", "configuring git tooling");
18108
18193
  const ghCmd = await ensureGhCli(defaultGitToolingRunner, payload.cloneToken);
18109
18194
  if (ghCmd) {
18110
- childEnv.PATH = `${codeamBinDir()}${path44.delimiter}${childEnv.PATH}`;
18195
+ childEnv.PATH = `${codeamBinDir()}${path45.delimiter}${childEnv.PATH}`;
18111
18196
  await ensureGhAuth(defaultGitToolingRunner, ghCmd, payload.cloneToken);
18112
18197
  }
18113
18198
  } catch (e) {
@@ -18123,7 +18208,7 @@ var HostAgentSupervisor = class {
18123
18208
  }
18124
18209
  if (payload.headroomEnabled && payload.headroomAgent && payload.headroomSavingsIngestUrl && isHeadroomSupportedAgent(payload.headroomAgent)) {
18125
18210
  report("headroom", "setting up Headroom proxy");
18126
- const freeBytes = await this.getFreeDisk(os35.homedir());
18211
+ const freeBytes = await this.getFreeDisk(os36.homedir());
18127
18212
  const alreadyInstalled = this.isHeadroomInstalled();
18128
18213
  if (!alreadyInstalled && freeBytes !== null && freeBytes < HEADROOM_MIN_FREE_DISK_BYTES) {
18129
18214
  const freeGb = (freeBytes / 1e9).toFixed(1);
@@ -18172,6 +18257,11 @@ var HostAgentSupervisor = class {
18172
18257
  );
18173
18258
  persistHeadroomConfig({ enabled: false });
18174
18259
  }
18260
+ if (payload.integrations?.length) {
18261
+ persistIntegrationsManifest({ integrations: payload.integrations });
18262
+ } else {
18263
+ clearIntegrationsManifest();
18264
+ }
18175
18265
  report("spawning", "starting agent");
18176
18266
  const proc = this.spawnSessionChild(childEnv, cwd, extraArgs);
18177
18267
  const child = {
@@ -18245,7 +18335,7 @@ var HostAgentSupervisor = class {
18245
18335
  */
18246
18336
  runAgentInstall(script) {
18247
18337
  return new Promise((resolve7) => {
18248
- const home = process.env.HOME || os35.homedir();
18338
+ const home = process.env.HOME || os36.homedir();
18249
18339
  const child = (0, import_node_child_process23.spawn)("sh", ["-c", script], {
18250
18340
  env: { ...process.env, HOME: home },
18251
18341
  stdio: ["ignore", "pipe", "pipe"]
@@ -18429,9 +18519,9 @@ async function configureHeadroom(action, ctx, deps) {
18429
18519
  }
18430
18520
 
18431
18521
  // src/services/headroom/budget-relaunch.ts
18432
- var fs42 = __toESM(require("fs"));
18433
- var os36 = __toESM(require("os"));
18434
- var path45 = __toESM(require("path"));
18522
+ var fs43 = __toESM(require("fs"));
18523
+ var os37 = __toESM(require("os"));
18524
+ var path46 = __toESM(require("path"));
18435
18525
  var import_child_process13 = require("child_process");
18436
18526
  function amendDeploymentManifestBudget(manifest, budget) {
18437
18527
  const rawArgs = manifest.proxy_args ?? [];
@@ -18465,7 +18555,7 @@ function amendDeploymentManifestBudget(manifest, budget) {
18465
18555
  return { ...manifest, proxy_args: newArgs, base_env: newEnv };
18466
18556
  }
18467
18557
  function findHeadroomDeployments(homeDir2, deps) {
18468
- const deployDir = path45.join(homeDir2, ".headroom", "deploy");
18558
+ const deployDir = path46.join(homeDir2, ".headroom", "deploy");
18469
18559
  let profiles;
18470
18560
  try {
18471
18561
  profiles = deps.readDir(deployDir);
@@ -18474,7 +18564,7 @@ function findHeadroomDeployments(homeDir2, deps) {
18474
18564
  }
18475
18565
  const results = [];
18476
18566
  for (const profile of profiles) {
18477
- const manifestPath = path45.join(deployDir, profile, "manifest.json");
18567
+ const manifestPath = path46.join(deployDir, profile, "manifest.json");
18478
18568
  let raw;
18479
18569
  try {
18480
18570
  raw = deps.readJson(manifestPath);
@@ -18506,8 +18596,8 @@ async function applyBudgetToHeadroom(budget, deps) {
18506
18596
  }
18507
18597
  function writeManifestReal(manifestPath, manifest) {
18508
18598
  const tmp = manifestPath + ".codeam.tmp";
18509
- fs42.writeFileSync(tmp, JSON.stringify(manifest, null, 2) + "\n", { mode: 384 });
18510
- fs42.renameSync(tmp, manifestPath);
18599
+ fs43.writeFileSync(tmp, JSON.stringify(manifest, null, 2) + "\n", { mode: 384 });
18600
+ fs43.renameSync(tmp, manifestPath);
18511
18601
  }
18512
18602
  function restartDeploymentReal(profile) {
18513
18603
  try {
@@ -18537,11 +18627,11 @@ function spawnProxyReal2(_budget) {
18537
18627
  });
18538
18628
  }
18539
18629
  function makeRealApplyBudgetDeps() {
18540
- const homeDir2 = os36.homedir();
18630
+ const homeDir2 = os37.homedir();
18541
18631
  return {
18542
18632
  findDeployments: () => findHeadroomDeployments(homeDir2, {
18543
- readDir: (dir) => fs42.readdirSync(dir),
18544
- readJson: (filePath) => JSON.parse(fs42.readFileSync(filePath, "utf8"))
18633
+ readDir: (dir) => fs43.readdirSync(dir),
18634
+ readJson: (filePath) => JSON.parse(fs43.readFileSync(filePath, "utf8"))
18545
18635
  }),
18546
18636
  writeManifest: writeManifestReal,
18547
18637
  restartDeployment: restartDeploymentReal,
@@ -19221,8 +19311,8 @@ function activePreviewSessionIds() {
19221
19311
 
19222
19312
  // src/services/preview/start-orchestrator.ts
19223
19313
  var import_child_process17 = require("child_process");
19224
- var fs47 = __toESM(require("fs"));
19225
- var path50 = __toESM(require("path"));
19314
+ var fs48 = __toESM(require("fs"));
19315
+ var path51 = __toESM(require("path"));
19226
19316
  var import_which2 = __toESM(require("which"));
19227
19317
  var INSTALL_TIMEOUT_MS = 5 * 6e4;
19228
19318
  var SETUP_TIMEOUT_MS = 2 * 6e4;
@@ -19289,8 +19379,8 @@ function normalizeDetectionForSpawn(detection, cwd) {
19289
19379
  if (args2.length === 0) return detection;
19290
19380
  const binName = args2[0];
19291
19381
  if (binName.startsWith("-")) return detection;
19292
- const binPath = path50.join(cwd, "node_modules", ".bin", binName);
19293
- if (!fs47.existsSync(binPath)) return detection;
19382
+ const binPath = path51.join(cwd, "node_modules", ".bin", binName);
19383
+ if (!fs48.existsSync(binPath)) return detection;
19294
19384
  return {
19295
19385
  ...detection,
19296
19386
  command: binPath,
@@ -19640,9 +19730,9 @@ async function establishTunnel(ctx, dev) {
19640
19730
 
19641
19731
  // src/beads/bd-adapter.ts
19642
19732
  var import_child_process18 = require("child_process");
19643
- var fs48 = __toESM(require("fs"));
19644
- var os38 = __toESM(require("os"));
19645
- var path51 = __toESM(require("path"));
19733
+ var fs49 = __toESM(require("fs"));
19734
+ var os39 = __toESM(require("os"));
19735
+ var path52 = __toESM(require("path"));
19646
19736
  var BD_PACKAGE = "@beads/bd";
19647
19737
  function resolveBundledBdBinary() {
19648
19738
  return _resolveSeam.resolveBundled();
@@ -19654,11 +19744,11 @@ function _defaultResolveBundled() {
19654
19744
  } catch {
19655
19745
  return null;
19656
19746
  }
19657
- const binDir = path51.join(path51.dirname(pkgJsonPath), "bin");
19747
+ const binDir = path52.join(path52.dirname(pkgJsonPath), "bin");
19658
19748
  const binaryName = process.platform === "win32" ? "bd.exe" : "bd";
19659
- const binaryPath = path51.join(binDir, binaryName);
19749
+ const binaryPath = path52.join(binDir, binaryName);
19660
19750
  try {
19661
- fs48.accessSync(binaryPath, fs48.constants.F_OK);
19751
+ fs49.accessSync(binaryPath, fs49.constants.F_OK);
19662
19752
  return binaryPath;
19663
19753
  } catch {
19664
19754
  return null;
@@ -19668,13 +19758,13 @@ function resolveBdOnPath() {
19668
19758
  return _resolveSeam.resolveOnPath();
19669
19759
  }
19670
19760
  function _defaultResolveOnPath() {
19671
- const dirs = (process.env.PATH ?? "").split(path51.delimiter).filter(Boolean);
19761
+ const dirs = (process.env.PATH ?? "").split(path52.delimiter).filter(Boolean);
19672
19762
  const candidates = process.platform === "win32" ? ["bd.exe", "bd.cmd", "bd"] : ["bd"];
19673
19763
  for (const dir of dirs) {
19674
19764
  for (const candidate of candidates) {
19675
- const full = path51.join(dir, candidate);
19765
+ const full = path52.join(dir, candidate);
19676
19766
  try {
19677
- fs48.accessSync(full, fs48.constants.F_OK);
19767
+ fs49.accessSync(full, fs49.constants.F_OK);
19678
19768
  return full;
19679
19769
  } catch {
19680
19770
  }
@@ -19759,7 +19849,7 @@ var BdAdapter = class {
19759
19849
  const env = { ...process.env };
19760
19850
  if (!env.HOME) {
19761
19851
  try {
19762
- const home = os38.homedir();
19852
+ const home = os39.homedir();
19763
19853
  if (home) env.HOME = home;
19764
19854
  } catch {
19765
19855
  }
@@ -19851,9 +19941,9 @@ function coerceIssue(row, projectKey) {
19851
19941
 
19852
19942
  // src/beads/provisioner.ts
19853
19943
  var import_child_process22 = require("child_process");
19854
- var fs51 = __toESM(require("fs"));
19855
- var os40 = __toESM(require("os"));
19856
- var path54 = __toESM(require("path"));
19944
+ var fs52 = __toESM(require("fs"));
19945
+ var os41 = __toESM(require("os"));
19946
+ var path55 = __toESM(require("path"));
19857
19947
 
19858
19948
  // src/beads/install-bd.ts
19859
19949
  var import_child_process19 = require("child_process");
@@ -19918,9 +20008,9 @@ async function installBd(platform3 = process.platform) {
19918
20008
 
19919
20009
  // src/beads/install-dolt.ts
19920
20010
  var import_child_process20 = require("child_process");
19921
- var fs49 = __toESM(require("fs"));
19922
- var os39 = __toESM(require("os"));
19923
- var path52 = __toESM(require("path"));
20011
+ var fs50 = __toESM(require("fs"));
20012
+ var os40 = __toESM(require("os"));
20013
+ var path53 = __toESM(require("path"));
19924
20014
  var DOLT_INSTALL_SH_URL = "https://github.com/dolthub/dolt/releases/latest/download/install.sh";
19925
20015
  var DOLT_MSI_URL = "https://github.com/dolthub/dolt/releases/latest/download/dolt-windows-amd64.msi";
19926
20016
  function resolveDoltInstallStrategy(platform3) {
@@ -19960,11 +20050,11 @@ function resolveDoltInstallStrategy(platform3) {
19960
20050
  }
19961
20051
  var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
19962
20052
  function doltPlatformTuple(platform3, arch2) {
19963
- const os50 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
20053
+ const os51 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
19964
20054
  const a = arch2 === "x64" ? "amd64" : arch2 === "arm64" ? "arm64" : null;
19965
20055
  if (!a) return null;
19966
- if (os50 === "windows" && a !== "amd64") return null;
19967
- return `${os50}-${a}`;
20056
+ if (os51 === "windows" && a !== "amd64") return null;
20057
+ return `${os51}-${a}`;
19968
20058
  }
19969
20059
  function resolveDoltTarballStrategy(targetDir, platform3, arch2) {
19970
20060
  const tuple = doltPlatformTuple(platform3, arch2);
@@ -20009,14 +20099,14 @@ async function installDoltToDir(targetDir, platform3 = process.platform, arch2 =
20009
20099
  return result;
20010
20100
  }
20011
20101
  var _doltPathSeam = {
20012
- homedir: () => os39.homedir(),
20102
+ homedir: () => os40.homedir(),
20013
20103
  getPath: () => process.env.PATH ?? "",
20014
20104
  setPath: (p2) => {
20015
20105
  process.env.PATH = p2;
20016
20106
  },
20017
20107
  exists: (p2) => {
20018
20108
  try {
20019
- fs49.accessSync(p2, fs49.constants.F_OK);
20109
+ fs50.accessSync(p2, fs50.constants.F_OK);
20020
20110
  return true;
20021
20111
  } catch {
20022
20112
  return false;
@@ -20027,7 +20117,7 @@ function doltBinaryNames(platform3) {
20027
20117
  return platform3 === "win32" ? ["dolt.exe", "dolt.cmd", "dolt"] : ["dolt"];
20028
20118
  }
20029
20119
  function knownDoltDirs(platform3) {
20030
- const P3 = platform3 === "win32" ? path52.win32 : path52.posix;
20120
+ const P3 = platform3 === "win32" ? path53.win32 : path53.posix;
20031
20121
  const home = _doltPathSeam.homedir();
20032
20122
  if (platform3 === "win32") {
20033
20123
  return [
@@ -20043,7 +20133,7 @@ function knownDoltDirs(platform3) {
20043
20133
  ].filter(Boolean);
20044
20134
  }
20045
20135
  function ensureDoltResolvable(platform3 = process.platform) {
20046
- const P3 = platform3 === "win32" ? path52.win32 : path52.posix;
20136
+ const P3 = platform3 === "win32" ? path53.win32 : path53.posix;
20047
20137
  const delim = platform3 === "win32" ? ";" : ":";
20048
20138
  const names = doltBinaryNames(platform3);
20049
20139
  const pathDirs = _doltPathSeam.getPath().split(delim).filter(Boolean);
@@ -20179,8 +20269,8 @@ async function ensureSharedServer(adapter, options = {}) {
20179
20269
  // src/beads/project-key.ts
20180
20270
  var import_child_process21 = require("child_process");
20181
20271
  var crypto2 = __toESM(require("crypto"));
20182
- var fs50 = __toESM(require("fs"));
20183
- var path53 = __toESM(require("path"));
20272
+ var fs51 = __toESM(require("fs"));
20273
+ var path54 = __toESM(require("path"));
20184
20274
  function normalizeOrigin(raw) {
20185
20275
  const trimmed = raw.trim();
20186
20276
  if (!trimmed) return null;
@@ -20206,17 +20296,17 @@ function normalizeOrigin(raw) {
20206
20296
  return `${host2}/${pathPart}`;
20207
20297
  }
20208
20298
  function findRepoRoot(cwd) {
20209
- let dir = path53.resolve(cwd);
20299
+ let dir = path54.resolve(cwd);
20210
20300
  const seen = /* @__PURE__ */ new Set();
20211
20301
  for (let i = 0; i < 256; i++) {
20212
20302
  if (seen.has(dir)) return null;
20213
20303
  seen.add(dir);
20214
20304
  try {
20215
- const stat3 = fs50.statSync(path53.join(dir, ".git"), { throwIfNoEntry: false });
20305
+ const stat3 = fs51.statSync(path54.join(dir, ".git"), { throwIfNoEntry: false });
20216
20306
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
20217
20307
  } catch {
20218
20308
  }
20219
- const parent = path53.dirname(dir);
20309
+ const parent = path54.dirname(dir);
20220
20310
  if (parent === dir) return null;
20221
20311
  dir = parent;
20222
20312
  }
@@ -20227,7 +20317,7 @@ var _execSeam2 = {
20227
20317
  const out2 = (0, import_child_process21.execFileSync)(file, args2, opts);
20228
20318
  return typeof out2 === "string" ? out2 : out2.toString("utf8");
20229
20319
  },
20230
- realpath: (p2) => fs50.realpathSync(p2)
20320
+ realpath: (p2) => fs51.realpathSync(p2)
20231
20321
  };
20232
20322
  function readOrigin(cwd) {
20233
20323
  try {
@@ -20256,7 +20346,7 @@ function deriveProjectIdentity(cwd = process.cwd()) {
20256
20346
  } catch {
20257
20347
  }
20258
20348
  const hash = crypto2.createHash("sha256").update(real).digest("hex");
20259
- return { projectKey: `path:${hash}`, projectLabel: path53.basename(real) || "project" };
20349
+ return { projectKey: `path:${hash}`, projectLabel: path54.basename(real) || "project" };
20260
20350
  }
20261
20351
 
20262
20352
  // src/beads/project-prefix.ts
@@ -20301,17 +20391,17 @@ var _provisionSeam = {
20301
20391
  };
20302
20392
  var _linkSeam = {
20303
20393
  platform: () => process.platform,
20304
- homedir: () => os40.homedir(),
20394
+ homedir: () => os41.homedir(),
20305
20395
  isWritableDir: (dir) => {
20306
20396
  try {
20307
- fs51.accessSync(dir, fs51.constants.W_OK);
20397
+ fs52.accessSync(dir, fs52.constants.W_OK);
20308
20398
  return true;
20309
20399
  } catch {
20310
20400
  return false;
20311
20401
  }
20312
20402
  },
20313
20403
  ensureDir: (dir) => {
20314
- fs51.mkdirSync(dir, { recursive: true });
20404
+ fs52.mkdirSync(dir, { recursive: true });
20315
20405
  },
20316
20406
  /**
20317
20407
  * A directory to symlink `bd` into so the AGENT's shell + Claude Code's
@@ -20332,9 +20422,9 @@ var _linkSeam = {
20332
20422
  * which `linkBdOntoPath` creates if missing.
20333
20423
  */
20334
20424
  cliBinDir: () => {
20335
- const pathDirs = (process.env.PATH ?? "").split(path54.delimiter).filter(Boolean);
20425
+ const pathDirs = (process.env.PATH ?? "").split(path55.delimiter).filter(Boolean);
20336
20426
  const home = _linkSeam.homedir();
20337
- const localBin = home ? path54.join(home, ".local", "bin") : null;
20427
+ const localBin = home ? path55.join(home, ".local", "bin") : null;
20338
20428
  if (localBin) {
20339
20429
  try {
20340
20430
  _linkSeam.ensureDir(localBin);
@@ -20344,16 +20434,16 @@ var _linkSeam = {
20344
20434
  const candidates = [];
20345
20435
  if (localBin) candidates.push(localBin);
20346
20436
  try {
20347
- candidates.push(path54.dirname(process.execPath));
20437
+ candidates.push(path55.dirname(process.execPath));
20348
20438
  } catch {
20349
20439
  }
20350
20440
  candidates.push("/usr/local/bin");
20351
20441
  const entry = process.argv[1];
20352
20442
  if (entry) {
20353
20443
  try {
20354
- candidates.push(path54.dirname(fs51.realpathSync(entry)));
20444
+ candidates.push(path55.dirname(fs52.realpathSync(entry)));
20355
20445
  } catch {
20356
- candidates.push(path54.dirname(entry));
20446
+ candidates.push(path55.dirname(entry));
20357
20447
  }
20358
20448
  }
20359
20449
  const onPathWritable = candidates.find(
@@ -20365,20 +20455,20 @@ var _linkSeam = {
20365
20455
  /** Current symlink target at `linkPath`, or null when absent / not a link. */
20366
20456
  readlink: (linkPath) => {
20367
20457
  try {
20368
- return fs51.readlinkSync(linkPath);
20458
+ return fs52.readlinkSync(linkPath);
20369
20459
  } catch {
20370
20460
  return null;
20371
20461
  }
20372
20462
  },
20373
- unlink: (linkPath) => fs51.unlinkSync(linkPath),
20374
- symlink: (target, linkPath) => fs51.symlinkSync(target, linkPath)
20463
+ unlink: (linkPath) => fs52.unlinkSync(linkPath),
20464
+ symlink: (target, linkPath) => fs52.symlinkSync(target, linkPath)
20375
20465
  };
20376
20466
  function linkBdOntoPath(binaryPath) {
20377
20467
  if (_linkSeam.platform() === "win32") return;
20378
20468
  const binDir = _linkSeam.cliBinDir();
20379
20469
  if (!binDir) return;
20380
20470
  _linkSeam.ensureDir(binDir);
20381
- const linkPath = path54.join(binDir, "bd");
20471
+ const linkPath = path55.join(binDir, "bd");
20382
20472
  if (linkPath === binaryPath) return;
20383
20473
  const current = _linkSeam.readlink(linkPath);
20384
20474
  if (current === binaryPath) return;
@@ -20573,7 +20663,7 @@ function dedupeRecipes(agents) {
20573
20663
 
20574
20664
  // src/beads/watcher.ts
20575
20665
  var crypto4 = __toESM(require("crypto"));
20576
- var path55 = __toESM(require("path"));
20666
+ var path56 = __toESM(require("path"));
20577
20667
  var API_BASE6 = resolveApiBaseUrl();
20578
20668
  var DEBOUNCE_MS2 = 400;
20579
20669
  var ZERO_SUMMARY = {
@@ -20597,7 +20687,7 @@ var BeadsWatcher = class {
20597
20687
  constructor(opts) {
20598
20688
  this.opts = opts;
20599
20689
  this.bd = opts.adapter ?? new BdAdapter({ cwd: opts.cwd, beadsDir: opts.beadsDir });
20600
- this.feedPath = opts.feedPath ?? path55.join(opts.cwd ?? process.cwd(), ".beads", "last-touched");
20690
+ this.feedPath = opts.feedPath ?? path56.join(opts.cwd ?? process.cwd(), ".beads", "last-touched");
20601
20691
  this.apiBase = opts.apiBaseUrl ?? API_BASE6;
20602
20692
  }
20603
20693
  opts;
@@ -20848,15 +20938,15 @@ async function handleBeadsActionCommand(action, started) {
20848
20938
  }
20849
20939
 
20850
20940
  // src/beads/config-store.ts
20851
- var import_node_fs7 = __toESM(require("fs"));
20852
- var import_node_os6 = __toESM(require("os"));
20853
- var import_node_path5 = __toESM(require("path"));
20941
+ var import_node_fs8 = __toESM(require("fs"));
20942
+ var import_node_os7 = __toESM(require("os"));
20943
+ var import_node_path6 = __toESM(require("path"));
20854
20944
  function beadsConfigPath() {
20855
- return import_node_path5.default.join(import_node_os6.default.homedir(), ".codeam", "beads-config.json");
20945
+ return import_node_path6.default.join(import_node_os7.default.homedir(), ".codeam", "beads-config.json");
20856
20946
  }
20857
20947
  function readBeadsEnabled() {
20858
20948
  try {
20859
- const raw = import_node_fs7.default.readFileSync(beadsConfigPath(), "utf8");
20949
+ const raw = import_node_fs8.default.readFileSync(beadsConfigPath(), "utf8");
20860
20950
  const cfg = JSON.parse(raw);
20861
20951
  return cfg.enabled !== false;
20862
20952
  } catch {
@@ -20865,10 +20955,10 @@ function readBeadsEnabled() {
20865
20955
  }
20866
20956
  function persistBeadsConfig(cfg) {
20867
20957
  const file = beadsConfigPath();
20868
- import_node_fs7.default.mkdirSync(import_node_path5.default.dirname(file), { recursive: true });
20958
+ import_node_fs8.default.mkdirSync(import_node_path6.default.dirname(file), { recursive: true });
20869
20959
  const tmp = `${file}.tmp`;
20870
- import_node_fs7.default.writeFileSync(tmp, JSON.stringify(cfg), { mode: 384 });
20871
- import_node_fs7.default.renameSync(tmp, file);
20960
+ import_node_fs8.default.writeFileSync(tmp, JSON.stringify(cfg), { mode: 384 });
20961
+ import_node_fs8.default.renameSync(tmp, file);
20872
20962
  restrictToOwner(file);
20873
20963
  }
20874
20964
 
@@ -21014,8 +21104,8 @@ function cleanupAttachmentTempFiles() {
21014
21104
  function saveFilesTemp(files) {
21015
21105
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
21016
21106
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
21017
- const tmpPath = path57.join(os42.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
21018
- fs53.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
21107
+ const tmpPath = path58.join(os43.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
21108
+ fs54.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
21019
21109
  pendingAttachmentFiles.add(tmpPath);
21020
21110
  return tmpPath;
21021
21111
  });
@@ -21227,9 +21317,9 @@ var listFiles = async (ctx, cmd, parsed) => {
21227
21317
  await ctx.relay.sendResult(cmd.id, "completed", result);
21228
21318
  };
21229
21319
  var envReadH = async (ctx, cmd) => {
21230
- const envPath = path57.join(process.cwd(), ".env");
21320
+ const envPath = path58.join(process.cwd(), ".env");
21231
21321
  try {
21232
- const raw = await fs53.promises.readFile(envPath, "utf8");
21322
+ const raw = await fs54.promises.readFile(envPath, "utf8");
21233
21323
  await ctx.relay.sendResult(cmd.id, "completed", {
21234
21324
  exists: true,
21235
21325
  vars: parseDotenv(raw)
@@ -21260,14 +21350,14 @@ var envWriteH = async (ctx, cmd, parsed) => {
21260
21350
  }
21261
21351
  seen.add(v.key);
21262
21352
  }
21263
- const envPath = path57.join(process.cwd(), ".env");
21264
- const tmpPath = path57.join(process.cwd(), ".env.codeam.tmp");
21353
+ const envPath = path58.join(process.cwd(), ".env");
21354
+ const tmpPath = path58.join(process.cwd(), ".env.codeam.tmp");
21265
21355
  try {
21266
- await fs53.promises.writeFile(tmpPath, serializeDotenv(vars), "utf8");
21267
- await fs53.promises.rename(tmpPath, envPath);
21356
+ await fs54.promises.writeFile(tmpPath, serializeDotenv(vars), "utf8");
21357
+ await fs54.promises.rename(tmpPath, envPath);
21268
21358
  await ctx.relay.sendResult(cmd.id, "completed", { ok: true, count: vars.length });
21269
21359
  } catch (err) {
21270
- await fs53.promises.rm(tmpPath, { force: true }).catch(() => void 0);
21360
+ await fs54.promises.rm(tmpPath, { force: true }).catch(() => void 0);
21271
21361
  await ctx.relay.sendResult(cmd.id, "failed", { error: err.message });
21272
21362
  }
21273
21363
  };
@@ -21311,7 +21401,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
21311
21401
  let configuredAgent = rawAgentId;
21312
21402
  if (!configuredAgent) {
21313
21403
  try {
21314
- const raw = JSON.parse(fs53.readFileSync(headroomConfigPath(), "utf8"));
21404
+ const raw = JSON.parse(fs54.readFileSync(headroomConfigPath(), "utf8"));
21315
21405
  configuredAgent = raw.agent ?? "";
21316
21406
  } catch {
21317
21407
  }
@@ -21345,7 +21435,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
21345
21435
  persist: persistHeadroomConfig,
21346
21436
  readEnabled: () => {
21347
21437
  try {
21348
- const raw = JSON.parse(fs53.readFileSync(headroomConfigPath(), "utf8"));
21438
+ const raw = JSON.parse(fs54.readFileSync(headroomConfigPath(), "utf8"));
21349
21439
  return raw.enabled === true;
21350
21440
  } catch {
21351
21441
  return false;
@@ -21592,7 +21682,7 @@ var headroomBudgetH = async (ctx, cmd) => {
21592
21682
  }
21593
21683
  let headroomActive = false;
21594
21684
  try {
21595
- const raw = JSON.parse(fs53.readFileSync(headroomConfigPath(), "utf8"));
21685
+ const raw = JSON.parse(fs54.readFileSync(headroomConfigPath(), "utf8"));
21596
21686
  headroomActive = raw.enabled === true;
21597
21687
  } catch {
21598
21688
  }
@@ -21602,7 +21692,7 @@ var headroomBudgetH = async (ctx, cmd) => {
21602
21692
  }
21603
21693
  let existingConfig = { enabled: true };
21604
21694
  try {
21605
- existingConfig = JSON.parse(fs53.readFileSync(headroomConfigPath(), "utf8"));
21695
+ existingConfig = JSON.parse(fs54.readFileSync(headroomConfigPath(), "utf8"));
21606
21696
  } catch {
21607
21697
  }
21608
21698
  if (payload.budgetEnabled && payload.budgetUsd != null) {
@@ -21715,13 +21805,13 @@ var CLI_UPDATE_MAX_ATTEMPTS = 3;
21715
21805
  function buildNpmInstallInvocation(opts) {
21716
21806
  const entryScript = opts?.entryScript ?? process.argv[1] ?? "";
21717
21807
  const execPath = opts?.execPath ?? process.execPath;
21718
- const exists2 = opts?.existsSync ?? fs53.existsSync;
21719
- const normalized = entryScript.split(path57.sep).join("/");
21808
+ const exists2 = opts?.existsSync ?? fs54.existsSync;
21809
+ const normalized = entryScript.split(path58.sep).join("/");
21720
21810
  const marker = "/lib/node_modules/codeam-cli/";
21721
21811
  const markerIdx = normalized.indexOf(marker);
21722
21812
  const prefix = markerIdx > 0 ? entryScript.slice(0, markerIdx) : null;
21723
- const siblingNpm = path57.join(
21724
- path57.dirname(execPath),
21813
+ const siblingNpm = path58.join(
21814
+ path58.dirname(execPath),
21725
21815
  process.platform === "win32" ? "npm.cmd" : "npm"
21726
21816
  );
21727
21817
  const command2 = exists2(siblingNpm) ? siblingNpm : "npm";
@@ -22588,11 +22678,11 @@ function resolveTokenValue(args2) {
22588
22678
  }
22589
22679
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
22590
22680
  if (fileFlag) {
22591
- const path72 = fileFlag.slice("--token-file=".length);
22681
+ const path73 = fileFlag.slice("--token-file=".length);
22592
22682
  try {
22593
- const content = fs54.readFileSync(path72, "utf8").trim();
22594
- if (content.length === 0) fail(`--token-file ${path72} is empty`);
22595
- rmIfExistsQuiet(path72);
22683
+ const content = fs55.readFileSync(path73, "utf8").trim();
22684
+ if (content.length === 0) fail(`--token-file ${path73} is empty`);
22685
+ rmIfExistsQuiet(path73);
22596
22686
  return content;
22597
22687
  } catch (err) {
22598
22688
  fail(`Could not read --token-file: ${err.message}`);
@@ -22621,7 +22711,7 @@ async function claimOnce(token, pluginId, pluginSecretHash) {
22621
22711
  pluginId,
22622
22712
  ideName: "codeam-cli (codespace)",
22623
22713
  ideVersion: process.env.npm_package_version ?? "unknown",
22624
- hostname: os43.hostname(),
22714
+ hostname: os44.hostname(),
22625
22715
  codespaceName: process.env.CODESPACE_NAME ?? "",
22626
22716
  // Current git branch of the codespace's working directory, so the
22627
22717
  // backend can populate `PairedSession.branch` for the codespace pair.
@@ -22682,7 +22772,7 @@ async function claim(token, pluginId, pluginSecretHash) {
22682
22772
  }
22683
22773
  }
22684
22774
  function pairAutoLockPath() {
22685
- return path58.join(os43.homedir(), ".codeam", "pair-auto.lock");
22775
+ return path59.join(os44.homedir(), ".codeam", "pair-auto.lock");
22686
22776
  }
22687
22777
  function isLivePairAuto(pid) {
22688
22778
  if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
@@ -22692,7 +22782,7 @@ function isLivePairAuto(pid) {
22692
22782
  if (e.code !== "EPERM") return false;
22693
22783
  }
22694
22784
  try {
22695
- return fs54.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
22785
+ return fs55.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
22696
22786
  } catch {
22697
22787
  return true;
22698
22788
  }
@@ -22702,24 +22792,24 @@ function isLiveCodeam(pid) {
22702
22792
  }
22703
22793
  function daemonLockPath(sessionId) {
22704
22794
  const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
22705
- return path58.join(os43.homedir(), ".codeam", `daemon-${safe}.lock`);
22795
+ return path59.join(os44.homedir(), ".codeam", `daemon-${safe}.lock`);
22706
22796
  }
22707
22797
  function acquireDaemonLock(sessionId) {
22708
22798
  const lockPath = daemonLockPath(sessionId);
22709
22799
  try {
22710
- fs54.mkdirSync(path58.dirname(lockPath), { recursive: true });
22800
+ fs55.mkdirSync(path59.dirname(lockPath), { recursive: true });
22711
22801
  try {
22712
- fs54.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
22802
+ fs55.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
22713
22803
  } catch (e) {
22714
22804
  if (e.code !== "EEXIST") throw e;
22715
- const holder = Number(fs54.readFileSync(lockPath, "utf8").trim());
22805
+ const holder = Number(fs55.readFileSync(lockPath, "utf8").trim());
22716
22806
  if (holder && holder !== process.pid && isLiveCodeam(holder)) return false;
22717
- fs54.writeFileSync(lockPath, String(process.pid));
22807
+ fs55.writeFileSync(lockPath, String(process.pid));
22718
22808
  }
22719
22809
  const release3 = () => {
22720
22810
  try {
22721
- if (fs54.existsSync(lockPath) && Number(fs54.readFileSync(lockPath, "utf8").trim()) === process.pid) {
22722
- fs54.unlinkSync(lockPath);
22811
+ if (fs55.existsSync(lockPath) && Number(fs55.readFileSync(lockPath, "utf8").trim()) === process.pid) {
22812
+ fs55.unlinkSync(lockPath);
22723
22813
  }
22724
22814
  } catch {
22725
22815
  }
@@ -22741,19 +22831,19 @@ function acquireDaemonLock(sessionId) {
22741
22831
  function acquireSingletonLock() {
22742
22832
  const lockPath = pairAutoLockPath();
22743
22833
  try {
22744
- fs54.mkdirSync(path58.dirname(lockPath), { recursive: true });
22834
+ fs55.mkdirSync(path59.dirname(lockPath), { recursive: true });
22745
22835
  try {
22746
- fs54.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
22836
+ fs55.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
22747
22837
  } catch (e) {
22748
22838
  if (e.code !== "EEXIST") throw e;
22749
- const holder = Number(fs54.readFileSync(lockPath, "utf8").trim());
22839
+ const holder = Number(fs55.readFileSync(lockPath, "utf8").trim());
22750
22840
  if (isLivePairAuto(holder)) return false;
22751
- fs54.writeFileSync(lockPath, String(process.pid));
22841
+ fs55.writeFileSync(lockPath, String(process.pid));
22752
22842
  }
22753
22843
  process.once("exit", () => {
22754
22844
  try {
22755
- if (fs54.existsSync(lockPath) && Number(fs54.readFileSync(lockPath, "utf8").trim()) === process.pid) {
22756
- fs54.unlinkSync(lockPath);
22845
+ if (fs55.existsSync(lockPath) && Number(fs55.readFileSync(lockPath, "utf8").trim()) === process.pid) {
22846
+ fs55.unlinkSync(lockPath);
22757
22847
  }
22758
22848
  } catch {
22759
22849
  }
@@ -23199,7 +23289,7 @@ var AgentService = class _AgentService {
23199
23289
  };
23200
23290
 
23201
23291
  // src/agents/acp/adapters.ts
23202
- var path60 = __toESM(require("path"));
23292
+ var path61 = __toESM(require("path"));
23203
23293
 
23204
23294
  // src/agents/acp/agent-binary.ts
23205
23295
  var import_fs4 = __toESM(require("fs"));
@@ -23375,11 +23465,11 @@ async function waitForAdapterModuleGraph(command2, args2, opts = {}) {
23375
23465
 
23376
23466
  // src/agents/kimi/installer.ts
23377
23467
  var import_node_child_process25 = require("child_process");
23378
- var import_node_os7 = require("os");
23379
- var import_node_path6 = require("path");
23468
+ var import_node_os8 = require("os");
23469
+ var import_node_path7 = require("path");
23380
23470
  var INSTALL_URL2 = "https://code.kimi.com/kimi-code/install.sh";
23381
23471
  function kimiBinDir() {
23382
- return (0, import_node_path6.join)(process.env.KIMI_CODE_HOME || (0, import_node_path6.join)((0, import_node_os7.homedir)(), ".kimi-code"), "bin");
23472
+ return (0, import_node_path7.join)(process.env.KIMI_CODE_HOME || (0, import_node_path7.join)((0, import_node_os8.homedir)(), ".kimi-code"), "bin");
23383
23473
  }
23384
23474
  function kimiRuns() {
23385
23475
  const r = (0, import_node_child_process25.spawnSync)("kimi", ["--version"], { stdio: "ignore", timeout: 15e3 });
@@ -23442,13 +23532,13 @@ function resolveBin(pkgName, binName) {
23442
23532
  try {
23443
23533
  const manifestPath = require_.resolve(`${pkgName}/package.json`);
23444
23534
  const manifest = require_(`${pkgName}/package.json`);
23445
- const pkgDir = path60.dirname(manifestPath);
23535
+ const pkgDir = path61.dirname(manifestPath);
23446
23536
  const bin = manifest.bin;
23447
23537
  if (!bin) return null;
23448
- if (typeof bin === "string") return path60.resolve(pkgDir, bin);
23538
+ if (typeof bin === "string") return path61.resolve(pkgDir, bin);
23449
23539
  const target = binName ?? Object.keys(bin)[0];
23450
23540
  if (!target || !bin[target]) return null;
23451
- return path60.resolve(pkgDir, bin[target]);
23541
+ return path61.resolve(pkgDir, bin[target]);
23452
23542
  } catch {
23453
23543
  return null;
23454
23544
  }
@@ -23552,9 +23642,9 @@ function requiresAcp(agent) {
23552
23642
  var import_node_crypto10 = require("crypto");
23553
23643
 
23554
23644
  // src/services/history.service.ts
23555
- var fs56 = __toESM(require("fs"));
23556
- var path61 = __toESM(require("path"));
23557
- var os45 = __toESM(require("os"));
23645
+ var fs57 = __toESM(require("fs"));
23646
+ var path62 = __toESM(require("path"));
23647
+ var os46 = __toESM(require("os"));
23558
23648
  var https7 = __toESM(require("https"));
23559
23649
  var http6 = __toESM(require("http"));
23560
23650
  var import_zod2 = require("zod");
@@ -23581,7 +23671,7 @@ function parseJsonl(filePath) {
23581
23671
  const messages = [];
23582
23672
  let raw;
23583
23673
  try {
23584
- raw = fs56.readFileSync(filePath, "utf8");
23674
+ raw = fs57.readFileSync(filePath, "utf8");
23585
23675
  } catch (err) {
23586
23676
  if (err.code !== "ENOENT") {
23587
23677
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -23722,7 +23812,7 @@ var HistoryService = class _HistoryService {
23722
23812
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
23723
23813
  }
23724
23814
  get projectDir() {
23725
- return this.runtime.resolveHistoryDir(this.cwd) ?? path61.join(os45.homedir(), ".claude", "projects", encodeCwd(this.cwd));
23815
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path62.join(os46.homedir(), ".claude", "projects", encodeCwd(this.cwd));
23726
23816
  }
23727
23817
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
23728
23818
  setCurrentConversationId(id) {
@@ -23734,7 +23824,7 @@ var HistoryService = class _HistoryService {
23734
23824
  /** Return the current message count in the active conversation. */
23735
23825
  getCurrentMessageCount() {
23736
23826
  if (!this.currentConversationId) return 0;
23737
- const filePath = path61.join(this.projectDir, `${this.currentConversationId}.jsonl`);
23827
+ const filePath = path62.join(this.projectDir, `${this.currentConversationId}.jsonl`);
23738
23828
  return parseJsonl(filePath).length;
23739
23829
  }
23740
23830
  /**
@@ -23745,7 +23835,7 @@ var HistoryService = class _HistoryService {
23745
23835
  const deadline = Date.now() + timeoutMs;
23746
23836
  while (Date.now() < deadline) {
23747
23837
  if (!this.currentConversationId) return null;
23748
- const filePath = path61.join(this.projectDir, `${this.currentConversationId}.jsonl`);
23838
+ const filePath = path62.join(this.projectDir, `${this.currentConversationId}.jsonl`);
23749
23839
  const messages = parseJsonl(filePath);
23750
23840
  if (messages.length > previousCount) {
23751
23841
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -23771,16 +23861,16 @@ var HistoryService = class _HistoryService {
23771
23861
  const dir = this.projectDir;
23772
23862
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
23773
23863
  try {
23774
- const files = fs56.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
23864
+ const files = fs57.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
23775
23865
  try {
23776
- const stat3 = fs56.statSync(path61.join(dir, e.name));
23866
+ const stat3 = fs57.statSync(path62.join(dir, e.name));
23777
23867
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
23778
23868
  } catch {
23779
23869
  return { name: e.name, mtime: 0, birthtime: 0 };
23780
23870
  }
23781
23871
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
23782
23872
  if (files.length > 0) {
23783
- this.currentConversationId = path61.basename(files[0].name, ".jsonl");
23873
+ this.currentConversationId = path62.basename(files[0].name, ".jsonl");
23784
23874
  }
23785
23875
  } catch {
23786
23876
  }
@@ -23814,13 +23904,13 @@ var HistoryService = class _HistoryService {
23814
23904
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
23815
23905
  let entries;
23816
23906
  try {
23817
- entries = fs56.readdirSync(dir, { withFileTypes: true });
23907
+ entries = fs57.readdirSync(dir, { withFileTypes: true });
23818
23908
  } catch {
23819
23909
  return null;
23820
23910
  }
23821
23911
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
23822
23912
  try {
23823
- const stat3 = fs56.statSync(path61.join(dir, e.name));
23913
+ const stat3 = fs57.statSync(path62.join(dir, e.name));
23824
23914
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
23825
23915
  } catch {
23826
23916
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -23829,12 +23919,12 @@ var HistoryService = class _HistoryService {
23829
23919
  if (files.length === 0) return null;
23830
23920
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
23831
23921
  if (!files.some((f) => f.name === targetFile)) return null;
23832
- return this.extractUsageFromFile(path61.join(dir, targetFile));
23922
+ return this.extractUsageFromFile(path62.join(dir, targetFile));
23833
23923
  }
23834
23924
  extractUsageFromFile(filePath) {
23835
23925
  let raw;
23836
23926
  try {
23837
- raw = fs56.readFileSync(filePath, "utf8");
23927
+ raw = fs57.readFileSync(filePath, "utf8");
23838
23928
  } catch {
23839
23929
  return null;
23840
23930
  }
@@ -23879,9 +23969,9 @@ var HistoryService = class _HistoryService {
23879
23969
  let totalCost = 0;
23880
23970
  let files;
23881
23971
  try {
23882
- files = fs56.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
23972
+ files = fs57.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
23883
23973
  try {
23884
- return fs56.statSync(path61.join(projectDir, f)).mtimeMs >= monthStartMs;
23974
+ return fs57.statSync(path62.join(projectDir, f)).mtimeMs >= monthStartMs;
23885
23975
  } catch {
23886
23976
  return false;
23887
23977
  }
@@ -23892,7 +23982,7 @@ var HistoryService = class _HistoryService {
23892
23982
  for (const file of files) {
23893
23983
  let raw;
23894
23984
  try {
23895
- raw = fs56.readFileSync(path61.join(projectDir, file), "utf8");
23985
+ raw = fs57.readFileSync(path62.join(projectDir, file), "utf8");
23896
23986
  } catch {
23897
23987
  continue;
23898
23988
  }
@@ -23971,7 +24061,7 @@ var HistoryService = class _HistoryService {
23971
24061
  if (this.runtime.resolveHistoryFile) {
23972
24062
  return this.runtime.resolveHistoryFile(this.cwd, sessionId);
23973
24063
  }
23974
- return path61.join(this.projectDir, `${sessionId}.jsonl`);
24064
+ return path62.join(this.projectDir, `${sessionId}.jsonl`);
23975
24065
  }
23976
24066
  /**
23977
24067
  * Parse a conversation's messages from disk, agent-aware. Claude uses the
@@ -24005,7 +24095,7 @@ var HistoryService = class _HistoryService {
24005
24095
  };
24006
24096
  });
24007
24097
  }
24008
- return parseJsonl(path61.join(this.projectDir, `${sessionId}.jsonl`));
24098
+ return parseJsonl(path62.join(this.projectDir, `${sessionId}.jsonl`));
24009
24099
  }
24010
24100
  async loadConversation(sessionId) {
24011
24101
  const messages = this.readConversation(sessionId);
@@ -24061,7 +24151,7 @@ var HistoryService = class _HistoryService {
24061
24151
  if (!filePath) return false;
24062
24152
  let mtimeMs;
24063
24153
  try {
24064
- mtimeMs = fs56.statSync(filePath).mtimeMs;
24154
+ mtimeMs = fs57.statSync(filePath).mtimeMs;
24065
24155
  } catch {
24066
24156
  return false;
24067
24157
  }
@@ -24130,10 +24220,10 @@ var HistoryService = class _HistoryService {
24130
24220
 
24131
24221
  // src/agents/acp/client.ts
24132
24222
  var import_node_child_process26 = require("child_process");
24133
- var fs57 = __toESM(require("fs/promises"));
24223
+ var fs58 = __toESM(require("fs/promises"));
24134
24224
  var fsSync = __toESM(require("fs"));
24135
- var os46 = __toESM(require("os"));
24136
- var path62 = __toESM(require("path"));
24225
+ var os47 = __toESM(require("os"));
24226
+ var path63 = __toESM(require("path"));
24137
24227
  var import_node_stream = require("stream");
24138
24228
 
24139
24229
  // ../../node_modules/@agentclientprotocol/sdk/dist/acp.js
@@ -26857,7 +26947,7 @@ var AcpClient = class {
26857
26947
  let newSession;
26858
26948
  try {
26859
26949
  newSession = await Promise.race([
26860
- this.connection.newSession({ cwd, mcpServers: [] }),
26950
+ this.connection.newSession({ cwd, mcpServers: this.opts.mcpServers ?? [] }),
26861
26951
  startupFailure,
26862
26952
  startAborted
26863
26953
  ]);
@@ -26996,7 +27086,7 @@ var AcpClient = class {
26996
27086
  await this.connection.loadSession({
26997
27087
  sessionId,
26998
27088
  cwd: this.opts.cwd,
26999
- mcpServers: []
27089
+ mcpServers: this.opts.mcpServers ?? []
27000
27090
  });
27001
27091
  this.sessionId = sessionId;
27002
27092
  log.info("acpClient", `loadSession \u2190 ok sessionId=${sessionId.slice(0, 8)}`);
@@ -27111,7 +27201,7 @@ var AcpClient = class {
27111
27201
  },
27112
27202
  readTextFile: async (params) => {
27113
27203
  try {
27114
- const content = await fs57.readFile(params.path, "utf8");
27204
+ const content = await fs58.readFile(params.path, "utf8");
27115
27205
  return applyLineRange(content, params.line ?? null, params.limit ?? null);
27116
27206
  } catch (err) {
27117
27207
  const code = err.code;
@@ -27131,7 +27221,7 @@ var AcpClient = class {
27131
27221
  },
27132
27222
  writeTextFile: async (params) => {
27133
27223
  try {
27134
- await fs57.writeFile(params.path, params.content, "utf8");
27224
+ await fs58.writeFile(params.path, params.content, "utf8");
27135
27225
  return {};
27136
27226
  } catch (err) {
27137
27227
  const code = err.code;
@@ -27180,29 +27270,29 @@ function applyLineRange(content, line, limit) {
27180
27270
  return { content: lines.slice(start2, end).join("\n") };
27181
27271
  }
27182
27272
  function knownAgentBinaryDirs() {
27183
- const home = os46.homedir();
27273
+ const home = os47.homedir();
27184
27274
  const out2 = [];
27185
27275
  out2.push("/tmp/codeam-node20/bin");
27186
27276
  for (const root of [
27187
27277
  "/usr/local/share/nvm/versions/node",
27188
- path62.join(home, ".nvm/versions/node")
27278
+ path63.join(home, ".nvm/versions/node")
27189
27279
  ]) {
27190
27280
  try {
27191
27281
  for (const child of fsSync.readdirSync(root)) {
27192
- out2.push(path62.join(root, child, "bin"));
27282
+ out2.push(path63.join(root, child, "bin"));
27193
27283
  }
27194
27284
  } catch {
27195
27285
  }
27196
27286
  }
27197
- out2.push(path62.join(home, ".volta/bin"));
27287
+ out2.push(path63.join(home, ".volta/bin"));
27198
27288
  out2.push("/usr/local/bin");
27199
27289
  out2.push("/usr/bin");
27200
- out2.push(path62.join(home, ".local/bin"));
27201
- out2.push(path62.join(home, "bin"));
27290
+ out2.push(path63.join(home, ".local/bin"));
27291
+ out2.push(path63.join(home, "bin"));
27202
27292
  if (process.platform === "win32") {
27203
27293
  const { LOCALAPPDATA, APPDATA } = process.env;
27204
- if (LOCALAPPDATA) out2.push(path62.join(LOCALAPPDATA, "cursor-agent"));
27205
- if (APPDATA) out2.push(path62.join(APPDATA, "npm"));
27294
+ if (LOCALAPPDATA) out2.push(path63.join(LOCALAPPDATA, "cursor-agent"));
27295
+ if (APPDATA) out2.push(path63.join(APPDATA, "npm"));
27206
27296
  }
27207
27297
  return out2.filter((p2) => {
27208
27298
  try {
@@ -27214,7 +27304,7 @@ function knownAgentBinaryDirs() {
27214
27304
  }
27215
27305
  function expandPathForAgentBinaries(existingPath) {
27216
27306
  const existing = new Set(
27217
- existingPath.split(path62.delimiter).filter((p2) => p2.length > 0)
27307
+ existingPath.split(path63.delimiter).filter((p2) => p2.length > 0)
27218
27308
  );
27219
27309
  const additions = [];
27220
27310
  for (const dir of knownAgentBinaryDirs()) {
@@ -27224,7 +27314,7 @@ function expandPathForAgentBinaries(existingPath) {
27224
27314
  }
27225
27315
  }
27226
27316
  if (additions.length === 0) return existingPath;
27227
- return [...additions, existingPath].filter((p2) => p2.length > 0).join(path62.delimiter);
27317
+ return [...additions, existingPath].filter((p2) => p2.length > 0).join(path63.delimiter);
27228
27318
  }
27229
27319
 
27230
27320
  // src/agents/acp/headroom-budget-proxy.ts
@@ -27706,15 +27796,15 @@ function commonPrefixLength(a, b) {
27706
27796
 
27707
27797
  // src/agents/acp/onboarding.ts
27708
27798
  var import_child_process26 = require("child_process");
27709
- var fs58 = __toESM(require("fs"));
27710
- var os47 = __toESM(require("os"));
27711
- var path63 = __toESM(require("path"));
27799
+ var fs59 = __toESM(require("fs"));
27800
+ var os48 = __toESM(require("os"));
27801
+ var path64 = __toESM(require("path"));
27712
27802
  var _onboardingSeam = {
27713
- markerPath: (sessionId) => path63.join(os47.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
27714
- exists: (p2) => fs58.existsSync(p2),
27803
+ markerPath: (sessionId) => path64.join(os48.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
27804
+ exists: (p2) => fs59.existsSync(p2),
27715
27805
  write: (p2) => {
27716
- fs58.mkdirSync(path63.dirname(p2), { recursive: true });
27717
- fs58.writeFileSync(p2, "");
27806
+ fs59.mkdirSync(path64.dirname(p2), { recursive: true });
27807
+ fs59.writeFileSync(p2, "");
27718
27808
  },
27719
27809
  disabled: () => {
27720
27810
  const v = process.env.CODEAM_ONBOARDING_DISABLED;
@@ -27751,7 +27841,7 @@ function resolveRepoName(cwd) {
27751
27841
  if (name) return name;
27752
27842
  }
27753
27843
  }
27754
- const base = path63.basename(cwd || "");
27844
+ const base = path64.basename(cwd || "");
27755
27845
  if (base && !isUuid(base)) return base;
27756
27846
  return "this project";
27757
27847
  }
@@ -28003,8 +28093,8 @@ var import_crypto5 = require("crypto");
28003
28093
 
28004
28094
  // src/services/turn-files/git-changeset.ts
28005
28095
  var import_child_process27 = require("child_process");
28006
- var fs59 = __toESM(require("fs/promises"));
28007
- var path64 = __toESM(require("path"));
28096
+ var fs60 = __toESM(require("fs/promises"));
28097
+ var path65 = __toESM(require("path"));
28008
28098
  async function collectRepoChangeset(opts) {
28009
28099
  const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
28010
28100
  if (status2 === null) return null;
@@ -28022,7 +28112,7 @@ async function collectRepoChangeset(opts) {
28022
28112
  let stats;
28023
28113
  if (row.fileStatus === "added" && numstatEntry === void 0) {
28024
28114
  const lineCount = await readUntrackedLineCount(
28025
- path64.join(opts.repoRoot, row.filePath)
28115
+ path65.join(opts.repoRoot, row.filePath)
28026
28116
  );
28027
28117
  stats = { added: lineCount, removed: 0 };
28028
28118
  } else {
@@ -28053,7 +28143,7 @@ function readUntrackedLineCount(absPath) {
28053
28143
  }
28054
28144
  async function defaultReadUntrackedLineCount(absPath) {
28055
28145
  try {
28056
- const content = await fs59.readFile(absPath, "utf8");
28146
+ const content = await fs60.readFile(absPath, "utf8");
28057
28147
  let count = 0;
28058
28148
  let pos = -1;
28059
28149
  while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
@@ -28145,7 +28235,7 @@ function defaultRunGit(cwd, args2) {
28145
28235
  });
28146
28236
  }
28147
28237
  async function discoverRepos(workingDir, maxDepth = 4) {
28148
- const fs64 = await import("fs/promises");
28238
+ const fs65 = await import("fs/promises");
28149
28239
  const out2 = [];
28150
28240
  await walk(workingDir, 0);
28151
28241
  return out2;
@@ -28153,7 +28243,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
28153
28243
  if (depth > maxDepth) return;
28154
28244
  let entries = [];
28155
28245
  try {
28156
- const dirents = await fs64.readdir(dir, { withFileTypes: true });
28246
+ const dirents = await fs65.readdir(dir, { withFileTypes: true });
28157
28247
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
28158
28248
  } catch {
28159
28249
  return;
@@ -28164,8 +28254,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
28164
28254
  if (hasGit) {
28165
28255
  out2.push({
28166
28256
  repoRoot: dir,
28167
- repoPath: path64.relative(workingDir, dir),
28168
- repoName: path64.basename(dir)
28257
+ repoPath: path65.relative(workingDir, dir),
28258
+ repoName: path65.basename(dir)
28169
28259
  });
28170
28260
  return;
28171
28261
  }
@@ -28173,14 +28263,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
28173
28263
  if (!entry.isDirectory) continue;
28174
28264
  if (entry.name === "node_modules") continue;
28175
28265
  if (entry.name === "dist" || entry.name === "build") continue;
28176
- await walk(path64.join(dir, entry.name), depth + 1);
28266
+ await walk(path65.join(dir, entry.name), depth + 1);
28177
28267
  }
28178
28268
  }
28179
28269
  }
28180
28270
 
28181
28271
  // src/services/turn-files/files-outbox.ts
28182
- var fs60 = __toESM(require("fs/promises"));
28183
- var path65 = __toESM(require("path"));
28272
+ var fs61 = __toESM(require("fs/promises"));
28273
+ var path66 = __toESM(require("path"));
28184
28274
  var import_os11 = require("os");
28185
28275
  var HOME_OUTBOX_DIR = ".codeam/outbox";
28186
28276
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -28213,16 +28303,16 @@ var FilesOutbox = class {
28213
28303
  backoffIndex = 0;
28214
28304
  stopped = false;
28215
28305
  constructor(opts) {
28216
- const base = opts.baseDir ?? path65.join(homeDir(), HOME_OUTBOX_DIR);
28217
- this.filePath = path65.join(base, `${opts.sessionId}.jsonl`);
28306
+ const base = opts.baseDir ?? path66.join(homeDir(), HOME_OUTBOX_DIR);
28307
+ this.filePath = path66.join(base, `${opts.sessionId}.jsonl`);
28218
28308
  this.post = opts.post;
28219
28309
  this.autoSchedule = opts.autoSchedule !== false;
28220
28310
  }
28221
28311
  /** Persist the entry to disk and trigger a flush. Returns once the
28222
28312
  * line is durable on disk (not once the POST succeeds). */
28223
28313
  async enqueue(entry) {
28224
- await fs60.mkdir(path65.dirname(this.filePath), { recursive: true });
28225
- await fs60.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
28314
+ await fs61.mkdir(path66.dirname(this.filePath), { recursive: true });
28315
+ await fs61.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
28226
28316
  this.backoffIndex = 0;
28227
28317
  if (this.autoSchedule) this.scheduleFlush(0);
28228
28318
  }
@@ -28313,7 +28403,7 @@ var FilesOutbox = class {
28313
28403
  async readAll() {
28314
28404
  let raw = "";
28315
28405
  try {
28316
- raw = await fs60.readFile(this.filePath, "utf8");
28406
+ raw = await fs61.readFile(this.filePath, "utf8");
28317
28407
  } catch {
28318
28408
  return [];
28319
28409
  }
@@ -28337,12 +28427,12 @@ var FilesOutbox = class {
28337
28427
  async rewrite(entries) {
28338
28428
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
28339
28429
  if (entries.length === 0) {
28340
- await fs60.unlink(this.filePath).catch(() => void 0);
28430
+ await fs61.unlink(this.filePath).catch(() => void 0);
28341
28431
  return;
28342
28432
  }
28343
28433
  const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
28344
- await fs60.writeFile(tmpPath, payload, "utf8");
28345
- await fs60.rename(tmpPath, this.filePath);
28434
+ await fs61.writeFile(tmpPath, payload, "utf8");
28435
+ await fs61.rename(tmpPath, this.filePath);
28346
28436
  }
28347
28437
  };
28348
28438
  function applyJitter(ms) {
@@ -29840,6 +29930,7 @@ async function runAcpSession(opts) {
29840
29930
  adapter: opts.adapter,
29841
29931
  cwd: opts.cwd,
29842
29932
  extraEnv,
29933
+ mcpServers: opts.mcpServers,
29843
29934
  onSessionUpdate: (notification) => {
29844
29935
  updateCount += 1;
29845
29936
  const variant = notification.update?.sessionUpdate ?? "unknown";
@@ -31098,6 +31189,43 @@ function fetchQuotaUsage(runtime, historySvc) {
31098
31189
  });
31099
31190
  }
31100
31191
 
31192
+ // src/integrations/provision.ts
31193
+ function buildMcpServersForStart(ctx) {
31194
+ const manifest = readIntegrationsManifest();
31195
+ if (!manifest || manifest.integrations.length === 0) return [];
31196
+ if (!ctx.pluginAuthToken) {
31197
+ log.warn("integrations", "manifest present but no plugin auth token \u2014 skipping MCP injection");
31198
+ return [];
31199
+ }
31200
+ const servers = [];
31201
+ for (const entry of manifest.integrations) {
31202
+ if (!entry.delivery.mcp) continue;
31203
+ const env = [
31204
+ { name: "CODEAM_MCP_INTEGRATION_ID", value: entry.id },
31205
+ { name: "CODEAM_MCP_SESSION_ID", value: ctx.sessionId },
31206
+ { name: "CODEAM_MCP_PLUGIN_ID", value: ctx.pluginId },
31207
+ // Plugin token in ENV, never argv — argv is visible via `ps`.
31208
+ { name: "CODEAM_MCP_PLUGIN_TOKEN", value: ctx.pluginAuthToken },
31209
+ ...ctx.pollSecret ? [{ name: "CODEAM_MCP_POLL_SECRET", value: ctx.pollSecret }] : []
31210
+ ];
31211
+ servers.push({
31212
+ name: entry.id,
31213
+ // Never trust the agent's PATH for the shim binary (beads v2.39.5
31214
+ // lesson) — re-invoke this same Node runtime + CLI entrypoint.
31215
+ command: process.execPath,
31216
+ args: [process.argv[1], "mcp-run", entry.id],
31217
+ env
31218
+ });
31219
+ }
31220
+ if (servers.length) {
31221
+ log.info(
31222
+ "integrations",
31223
+ `injecting ${servers.length} MCP server(s): ${servers.map((s) => s.name).join(", ")}`
31224
+ );
31225
+ }
31226
+ return servers;
31227
+ }
31228
+
31101
31229
  // src/baton/baton-controller.ts
31102
31230
  var BatonController = class {
31103
31231
  constructor(deps) {
@@ -31447,7 +31575,7 @@ var AcpDriver = class {
31447
31575
  };
31448
31576
 
31449
31577
  // src/baton/transcript-mirror.ts
31450
- var fs61 = __toESM(require("fs"));
31578
+ var fs62 = __toESM(require("fs"));
31451
31579
  var TranscriptMirror = class {
31452
31580
  constructor(deps) {
31453
31581
  this.deps = deps;
@@ -31514,7 +31642,7 @@ var TranscriptMirror = class {
31514
31642
  }
31515
31643
  };
31516
31644
  function defaultWatch(file, onChange) {
31517
- const w3 = fs61.watch(file, { persistent: false }, () => onChange());
31645
+ const w3 = fs62.watch(file, { persistent: false }, () => onChange());
31518
31646
  return () => w3.close();
31519
31647
  }
31520
31648
 
@@ -31614,6 +31742,7 @@ async function runBatonSession(opts) {
31614
31742
  const client2 = new AcpClient({
31615
31743
  adapter: opts.adapter,
31616
31744
  cwd: opts.cwd,
31745
+ mcpServers: opts.mcpServers,
31617
31746
  onSessionUpdate: (notification) => {
31618
31747
  for (const delta of mapSessionUpdate(notification)) streaming.append(delta);
31619
31748
  },
@@ -31644,7 +31773,8 @@ async function runBatonSession(opts) {
31644
31773
  adapter: opts.adapter,
31645
31774
  cwd: opts.cwd,
31646
31775
  getBeads: opts.getBeads,
31647
- pollSecret: opts.pollSecret
31776
+ pollSecret: opts.pollSecret,
31777
+ mcpServers: opts.mcpServers
31648
31778
  };
31649
31779
  const mobileDriver = new AcpDriver({
31650
31780
  client: client2,
@@ -31766,15 +31896,15 @@ function toEpochMs(ts) {
31766
31896
  }
31767
31897
 
31768
31898
  // src/agents/claude/onboarding.ts
31769
- var fs62 = __toESM(require("fs"));
31770
- var os48 = __toESM(require("os"));
31771
- var path66 = __toESM(require("path"));
31899
+ var fs63 = __toESM(require("fs"));
31900
+ var os49 = __toESM(require("os"));
31901
+ var path67 = __toESM(require("path"));
31772
31902
  function ensureClaudeOnboarded(cwd) {
31773
31903
  try {
31774
- const file = path66.join(os48.homedir(), ".claude.json");
31904
+ const file = path67.join(os49.homedir(), ".claude.json");
31775
31905
  let config = {};
31776
31906
  try {
31777
- config = JSON.parse(fs62.readFileSync(file, "utf8"));
31907
+ config = JSON.parse(fs63.readFileSync(file, "utf8"));
31778
31908
  } catch {
31779
31909
  }
31780
31910
  let changed = false;
@@ -31798,8 +31928,8 @@ function ensureClaudeOnboarded(cwd) {
31798
31928
  }
31799
31929
  }
31800
31930
  if (!changed) return;
31801
- fs62.mkdirSync(path66.dirname(file), { recursive: true });
31802
- fs62.writeFileSync(file, JSON.stringify(config, null, 2));
31931
+ fs63.mkdirSync(path67.dirname(file), { recursive: true });
31932
+ fs63.writeFileSync(file, JSON.stringify(config, null, 2));
31803
31933
  log.info(
31804
31934
  "claude",
31805
31935
  `pre-completed Claude onboarding${cwd ? ` + trusted workspace ${cwd}` : ""}`
@@ -31904,6 +32034,12 @@ async function start(requestedAgent) {
31904
32034
  beads = started;
31905
32035
  return started;
31906
32036
  });
32037
+ const mcpServers = buildMcpServersForStart({
32038
+ sessionId: session.id,
32039
+ pluginId,
32040
+ pluginAuthToken: session.pluginAuthToken ?? void 0,
32041
+ pollSecret: session.pollSecret
32042
+ });
31907
32043
  const depsReady = process.env.CODESPACES === "true" ? provisionProjectDependencies(cwd).catch(() => void 0) : Promise.resolve();
31908
32044
  if (process.env.CODESPACES === "true") {
31909
32045
  const GATE_TIMEOUT_MS = 24e4;
@@ -31939,7 +32075,8 @@ async function start(requestedAgent) {
31939
32075
  pollSecret: session.pollSecret,
31940
32076
  cwd,
31941
32077
  adapter,
31942
- getBeads
32078
+ getBeads,
32079
+ mcpServers
31943
32080
  });
31944
32081
  return;
31945
32082
  }
@@ -31961,6 +32098,7 @@ async function start(requestedAgent) {
31961
32098
  cwd,
31962
32099
  getBeads,
31963
32100
  pollSecret: session.pollSecret,
32101
+ mcpServers,
31964
32102
  // AUTO mode for headless, mobile-driven sessions: no human at the box
31965
32103
  // to answer permission prompts, so auto-approve them rather than stall
31966
32104
  // the turn (the agent-agnostic equivalent of
@@ -32477,7 +32615,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
32477
32615
  var import_child_process28 = require("child_process");
32478
32616
  var import_util4 = require("util");
32479
32617
  var import_picocolors9 = __toESM(require("picocolors"));
32480
- var path67 = __toESM(require("path"));
32618
+ var path68 = __toESM(require("path"));
32481
32619
  var execFileP6 = (0, import_util4.promisify)(import_child_process28.execFile);
32482
32620
  var MAX_BUFFER = 8 * 1024 * 1024;
32483
32621
  function resetStdinForChild() {
@@ -32966,7 +33104,7 @@ var GitHubCodespacesProvider = class {
32966
33104
  });
32967
33105
  }
32968
33106
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
32969
- const remoteDir = path67.posix.dirname(remotePath);
33107
+ const remoteDir = path68.posix.dirname(remotePath);
32970
33108
  const parts = [
32971
33109
  `mkdir -p ${shellQuote(remoteDir)}`,
32972
33110
  `cat > ${shellQuote(remotePath)}`
@@ -33036,7 +33174,7 @@ function shellQuote(s) {
33036
33174
  // src/services/providers/gitpod.ts
33037
33175
  var import_child_process29 = require("child_process");
33038
33176
  var import_util5 = require("util");
33039
- var path68 = __toESM(require("path"));
33177
+ var path69 = __toESM(require("path"));
33040
33178
  var import_picocolors10 = __toESM(require("picocolors"));
33041
33179
  var execFileP7 = (0, import_util5.promisify)(import_child_process29.execFile);
33042
33180
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -33276,7 +33414,7 @@ var GitpodProvider = class {
33276
33414
  });
33277
33415
  }
33278
33416
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
33279
- const remoteDir = path68.posix.dirname(remotePath);
33417
+ const remoteDir = path69.posix.dirname(remotePath);
33280
33418
  const parts = [
33281
33419
  `mkdir -p ${shellQuote2(remoteDir)}`,
33282
33420
  `cat > ${shellQuote2(remotePath)}`
@@ -33312,7 +33450,7 @@ function shellQuote2(s) {
33312
33450
  // src/services/providers/gitlab-workspaces.ts
33313
33451
  var import_child_process30 = require("child_process");
33314
33452
  var import_util6 = require("util");
33315
- var path69 = __toESM(require("path"));
33453
+ var path70 = __toESM(require("path"));
33316
33454
  var execFileP8 = (0, import_util6.promisify)(import_child_process30.execFile);
33317
33455
  var MAX_BUFFER3 = 8 * 1024 * 1024;
33318
33456
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -33572,7 +33710,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
33572
33710
  }
33573
33711
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
33574
33712
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
33575
- const remoteDir = path69.posix.dirname(remotePath);
33713
+ const remoteDir = path70.posix.dirname(remotePath);
33576
33714
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
33577
33715
  if (options.mode != null) {
33578
33716
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -33640,7 +33778,7 @@ function shellQuote3(s) {
33640
33778
  // src/services/providers/railway.ts
33641
33779
  var import_child_process31 = require("child_process");
33642
33780
  var import_util7 = require("util");
33643
- var path70 = __toESM(require("path"));
33781
+ var path71 = __toESM(require("path"));
33644
33782
  var execFileP9 = (0, import_util7.promisify)(import_child_process31.execFile);
33645
33783
  var MAX_BUFFER4 = 8 * 1024 * 1024;
33646
33784
  function resetStdinForChild4() {
@@ -33876,7 +34014,7 @@ var RailwayProvider = class {
33876
34014
  if (!projectId || !serviceId) {
33877
34015
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
33878
34016
  }
33879
- const remoteDir = path70.posix.dirname(remotePath);
34017
+ const remoteDir = path71.posix.dirname(remotePath);
33880
34018
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
33881
34019
  if (options.mode != null) {
33882
34020
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -34522,8 +34660,8 @@ async function invite() {
34522
34660
  var import_node_dns = require("dns");
34523
34661
  var import_node_util5 = require("util");
34524
34662
  var import_node_crypto12 = require("crypto");
34525
- var fs63 = __toESM(require("fs"));
34526
- var path71 = __toESM(require("path"));
34663
+ var fs64 = __toESM(require("fs"));
34664
+ var path72 = __toESM(require("path"));
34527
34665
  var import_picocolors14 = __toESM(require("picocolors"));
34528
34666
  var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
34529
34667
  async function checkDns(apiBase2) {
@@ -34579,13 +34717,13 @@ async function checkHealth(apiBase2) {
34579
34717
  }
34580
34718
  }
34581
34719
  function checkConfigDir() {
34582
- const dir = path71.join(require("os").homedir(), ".codeam");
34720
+ const dir = path72.join(require("os").homedir(), ".codeam");
34583
34721
  try {
34584
- fs63.mkdirSync(dir, { recursive: true, mode: 448 });
34585
- const probe = path71.join(dir, ".doctor-probe");
34586
- fs63.writeFileSync(probe, "ok", { mode: 384 });
34587
- const read2 = fs63.readFileSync(probe, "utf8");
34588
- fs63.unlinkSync(probe);
34722
+ fs64.mkdirSync(dir, { recursive: true, mode: 448 });
34723
+ const probe = path72.join(dir, ".doctor-probe");
34724
+ fs64.writeFileSync(probe, "ok", { mode: 384 });
34725
+ const read2 = fs64.readFileSync(probe, "utf8");
34726
+ fs64.unlinkSync(probe);
34589
34727
  if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
34590
34728
  return {
34591
34729
  id: "config-dir",
@@ -34625,9 +34763,9 @@ function checkSessions() {
34625
34763
  }
34626
34764
  }
34627
34765
  function checkAgentBinaries() {
34628
- const os50 = createOsStrategy();
34766
+ const os51 = createOsStrategy();
34629
34767
  return getEnabledAgents().map((meta) => {
34630
- const found = os50.findInPath(meta.binaryName);
34768
+ const found = os51.findInPath(meta.binaryName);
34631
34769
  return {
34632
34770
  id: `agent-${meta.id}`,
34633
34771
  label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
@@ -34649,7 +34787,7 @@ function checkNodePty() {
34649
34787
  detail: "not required on this platform"
34650
34788
  };
34651
34789
  }
34652
- const vendoredPath = path71.join(__dirname, "vendor", "node-pty");
34790
+ const vendoredPath = path72.join(__dirname, "vendor", "node-pty");
34653
34791
  for (const target of [vendoredPath, "node-pty"]) {
34654
34792
  try {
34655
34793
  require(target);
@@ -34691,7 +34829,7 @@ function checkChokidar() {
34691
34829
  }
34692
34830
  async function doctor(args2 = []) {
34693
34831
  const json = args2.includes("--json");
34694
- const cliVersion = true ? "2.60.45" : "0.0.0-dev";
34832
+ const cliVersion = true ? "2.60.47" : "0.0.0-dev";
34695
34833
  const apiBase2 = resolveApiBaseUrl();
34696
34834
  const diagnosticId = (0, import_node_crypto12.randomUUID)();
34697
34835
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -34887,10 +35025,288 @@ async function completion(args2) {
34887
35025
  process.stdout.write(script);
34888
35026
  }
34889
35027
 
35028
+ // src/integrations/mcp-run.ts
35029
+ var import_node_child_process28 = require("child_process");
35030
+
35031
+ // src/integrations/token-client.ts
35032
+ var REFRESH_AHEAD_MS = 5 * 60 * 1e3;
35033
+ var IntegrationTokenClient = class {
35034
+ constructor(ctx, fetchImpl = fetch) {
35035
+ this.ctx = ctx;
35036
+ this.fetchImpl = fetchImpl;
35037
+ this.token = ctx.pluginAuthToken;
35038
+ }
35039
+ ctx;
35040
+ fetchImpl;
35041
+ cache = /* @__PURE__ */ new Map();
35042
+ token;
35043
+ /**
35044
+ * Fetch (or return the cached) broker token for `integrationId`.
35045
+ * Throws `Error(<code>)` on a non-retryable / still-failing 4xx-5xx.
35046
+ */
35047
+ async getToken(integrationId) {
35048
+ const cached2 = this.cache.get(integrationId);
35049
+ if (cached2 && new Date(cached2.expiresAt).getTime() - Date.now() > REFRESH_AHEAD_MS) {
35050
+ return cached2;
35051
+ }
35052
+ const url = `${resolveApiBaseUrl()}/api/plugin/integrations/${encodeURIComponent(integrationId)}/token`;
35053
+ const body = JSON.stringify({ sessionId: this.ctx.sessionId, pluginId: this.ctx.pluginId });
35054
+ const post2 = (tok) => this.fetchImpl(url, {
35055
+ method: "POST",
35056
+ headers: { "Content-Type": "application/json", "X-Plugin-Auth-Token": tok },
35057
+ body
35058
+ });
35059
+ let resp = await post2(this.token);
35060
+ if (resp.status === 401 || resp.status === 403) {
35061
+ const fresh = await fetchCurrentPluginAuthToken(
35062
+ this.ctx.sessionId,
35063
+ this.ctx.pluginId,
35064
+ this.ctx.pollSecret
35065
+ );
35066
+ if (fresh !== null) {
35067
+ this.token = fresh;
35068
+ resp = await post2(fresh);
35069
+ }
35070
+ }
35071
+ if (!resp.ok) {
35072
+ const detail = await resp.text().catch(() => "");
35073
+ throw new Error(`INTEGRATION_TOKEN_FAILED status=${resp.status} ${detail.slice(0, 200)}`.trim());
35074
+ }
35075
+ const parsed = await resp.json();
35076
+ this.cache.set(integrationId, parsed.data);
35077
+ return parsed.data;
35078
+ }
35079
+ };
35080
+
35081
+ // src/integrations/stdio-proxy.ts
35082
+ var import_node_child_process27 = require("child_process");
35083
+ var import_node_readline3 = __toESM(require("readline"));
35084
+ var RESTART_CHECK_INTERVAL_MS = 3e4;
35085
+ var SIGKILL_ESCALATION_MS = 2e3;
35086
+ var REPLAY_INIT_ID = "__codeam_replay_init__";
35087
+ var RestartableStdioProxy = class {
35088
+ constructor(opts) {
35089
+ this.opts = opts;
35090
+ }
35091
+ opts;
35092
+ child = null;
35093
+ childRl = null;
35094
+ initializeLine = null;
35095
+ inflight = /* @__PURE__ */ new Set();
35096
+ swapping = false;
35097
+ pendingClientLines = [];
35098
+ ended = () => void 0;
35099
+ async start() {
35100
+ const stdin = this.opts.stdin ?? process.stdin;
35101
+ const stdout = this.opts.stdout ?? process.stdout;
35102
+ await this.spawnChild(stdout);
35103
+ const rl = import_node_readline3.default.createInterface({ input: stdin, crlfDelay: Infinity });
35104
+ rl.on("line", (line) => this.onClientLine(line));
35105
+ rl.on("close", () => this.child?.stdin?.end());
35106
+ const timer = setInterval(() => this.checkRestart(stdout), RESTART_CHECK_INTERVAL_MS);
35107
+ timer.unref();
35108
+ return new Promise((resolve7) => {
35109
+ this.ended = (code) => {
35110
+ clearInterval(timer);
35111
+ process.exitCode = code;
35112
+ resolve7();
35113
+ };
35114
+ });
35115
+ }
35116
+ onClientLine(line) {
35117
+ if (this.swapping) {
35118
+ this.pendingClientLines.push(line);
35119
+ return;
35120
+ }
35121
+ try {
35122
+ const msg = JSON.parse(line);
35123
+ if (msg.method === "initialize" && this.initializeLine === null) {
35124
+ this.initializeLine = line;
35125
+ }
35126
+ if (msg.method === "notifications/cancelled") {
35127
+ const requestId = msg.params?.requestId;
35128
+ if (requestId !== void 0) this.inflight.delete(requestId);
35129
+ }
35130
+ if (msg.id !== void 0 && msg.method !== void 0) this.inflight.add(msg.id);
35131
+ } catch {
35132
+ }
35133
+ this.child?.stdin?.write(line + "\n");
35134
+ }
35135
+ onChildLine(line, stdout) {
35136
+ try {
35137
+ const msg = JSON.parse(line);
35138
+ if (msg.id !== void 0 && msg.method === void 0) {
35139
+ if (msg.id === REPLAY_INIT_ID) {
35140
+ return;
35141
+ }
35142
+ this.inflight.delete(msg.id);
35143
+ }
35144
+ } catch {
35145
+ }
35146
+ stdout.write(line + "\n");
35147
+ if (this.inflight.size === 0) this.checkRestart(stdout);
35148
+ }
35149
+ /**
35150
+ * Failsafe wrapper for the fire-and-forget call sites (post-response check
35151
+ * + the 30 s timer): `maybeRestart` handles the token-fetch failure itself,
35152
+ * but nothing that escapes it may become an unhandled rejection — that
35153
+ * would kill the whole shim process.
35154
+ */
35155
+ checkRestart(stdout) {
35156
+ this.maybeRestart(stdout).catch((err) => {
35157
+ process.stderr.write(
35158
+ `[codeam mcp-run] restart check failed (will retry): ${err instanceof Error ? err.message : String(err)}
35159
+ `
35160
+ );
35161
+ });
35162
+ }
35163
+ async maybeRestart(stdout) {
35164
+ if (this.swapping || !this.opts.shouldRestartNow()) return;
35165
+ if (this.inflight.size > 0 || this.initializeLine === null || !this.child) return;
35166
+ this.swapping = true;
35167
+ let spec;
35168
+ try {
35169
+ spec = await this.opts.spawnSpec();
35170
+ } catch (err) {
35171
+ process.stderr.write(
35172
+ `[codeam mcp-run] token refresh failed, keeping current server (will retry): ${err instanceof Error ? err.message : String(err)}
35173
+ `
35174
+ );
35175
+ this.swapping = false;
35176
+ for (const l of this.pendingClientLines.splice(0)) this.onClientLine(l);
35177
+ return;
35178
+ }
35179
+ const old = this.child;
35180
+ const oldRl = this.childRl;
35181
+ this.child = null;
35182
+ this.childRl = null;
35183
+ oldRl?.close();
35184
+ old.kill("SIGTERM");
35185
+ const escalation = setTimeout(() => {
35186
+ if (!old.killed || old.exitCode === null) old.kill("SIGKILL");
35187
+ }, SIGKILL_ESCALATION_MS);
35188
+ escalation.unref();
35189
+ try {
35190
+ await this.spawnChild(stdout, spec);
35191
+ const replayed = JSON.parse(this.initializeLine);
35192
+ this.child.stdin.write(JSON.stringify({ ...replayed, id: REPLAY_INIT_ID }) + "\n");
35193
+ this.child.stdin.write(
35194
+ JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" }) + "\n"
35195
+ );
35196
+ } finally {
35197
+ this.swapping = false;
35198
+ for (const l of this.pendingClientLines.splice(0)) this.onClientLine(l);
35199
+ }
35200
+ }
35201
+ async spawnChild(stdout, preResolved) {
35202
+ const spec = preResolved ?? await this.opts.spawnSpec();
35203
+ const spawn41 = this.opts.spawnImpl ?? import_node_child_process27.spawn;
35204
+ const child = spawn41(spec.command, spec.args, {
35205
+ env: { ...process.env, ...spec.env },
35206
+ // env only — never argv
35207
+ stdio: ["pipe", "pipe", "inherit"]
35208
+ });
35209
+ this.child = child;
35210
+ child.stdin?.on("error", () => void 0);
35211
+ const rl = import_node_readline3.default.createInterface({ input: child.stdout, crlfDelay: Infinity });
35212
+ this.childRl = rl;
35213
+ rl.on("line", (line) => {
35214
+ if (child !== this.child) return;
35215
+ this.onChildLine(line, stdout);
35216
+ });
35217
+ child.on("exit", (code) => {
35218
+ if (child !== this.child) return;
35219
+ this.ended(code ?? 1);
35220
+ });
35221
+ }
35222
+ };
35223
+
35224
+ // src/integrations/mcp-run.ts
35225
+ var RESTART_AHEAD_MS = 5 * 60 * 1e3;
35226
+ function resolveDelivery(id) {
35227
+ const fromRegistry = isKnownIntegrationId(id) ? getIntegration(id).delivery.mcp ?? null : null;
35228
+ const fromManifest = readIntegrationsManifest()?.integrations.find((e) => e.id === id)?.delivery.mcp;
35229
+ if (fromManifest) {
35230
+ if (fromRegistry?.staticEnv) {
35231
+ return {
35232
+ ...fromManifest,
35233
+ staticEnv: { ...fromRegistry.staticEnv, ...fromManifest.staticEnv }
35234
+ };
35235
+ }
35236
+ return fromManifest;
35237
+ }
35238
+ return fromRegistry;
35239
+ }
35240
+ function commandExists(command2) {
35241
+ try {
35242
+ const probe = process.platform === "win32" ? "where" : "which";
35243
+ (0, import_node_child_process28.execFileSync)(probe, [command2], { stdio: "ignore" });
35244
+ return true;
35245
+ } catch {
35246
+ return false;
35247
+ }
35248
+ }
35249
+ function ensureCommand(command2) {
35250
+ if (commandExists(command2)) return;
35251
+ if (process.platform === "win32") {
35252
+ process.stderr.write(
35253
+ `[codeam mcp-run] '${command2}' not found on PATH \u2014 install it and retry.
35254
+ `
35255
+ );
35256
+ return;
35257
+ }
35258
+ if (command2 === "uvx") {
35259
+ try {
35260
+ (0, import_node_child_process28.execSync)("python3 -m pip install --user --quiet uv", {
35261
+ stdio: ["ignore", process.stderr, process.stderr],
35262
+ timeout: 18e4
35263
+ });
35264
+ } catch {
35265
+ }
35266
+ }
35267
+ }
35268
+ async function mcpRun(args2) {
35269
+ const id = args2[0] ?? process.env.CODEAM_MCP_INTEGRATION_ID;
35270
+ const sessionId = process.env.CODEAM_MCP_SESSION_ID;
35271
+ const pluginId = process.env.CODEAM_MCP_PLUGIN_ID;
35272
+ const pluginAuthToken = process.env.CODEAM_MCP_PLUGIN_TOKEN;
35273
+ if (!id || !sessionId || !pluginId || !pluginAuthToken) {
35274
+ process.stderr.write("[codeam mcp-run] missing integration id or session credentials in env\n");
35275
+ process.exit(1);
35276
+ }
35277
+ const delivery = resolveDelivery(id);
35278
+ if (!delivery) {
35279
+ process.stderr.write(`[codeam mcp-run] no mcp delivery for '${id}'
35280
+ `);
35281
+ process.exit(1);
35282
+ }
35283
+ ensureCommand(delivery.command);
35284
+ const client2 = new IntegrationTokenClient({
35285
+ sessionId,
35286
+ pluginId,
35287
+ pluginAuthToken,
35288
+ pollSecret: process.env.CODEAM_MCP_POLL_SECRET
35289
+ });
35290
+ let current = null;
35291
+ const proxy = new RestartableStdioProxy({
35292
+ spawnSpec: async () => {
35293
+ current = await client2.getToken(id);
35294
+ const env = { ...delivery.staticEnv };
35295
+ for (const [envVar, field] of Object.entries(delivery.envMapping)) {
35296
+ const value = current[field];
35297
+ if (typeof value === "string" && value) env[envVar] = value;
35298
+ }
35299
+ return { command: delivery.command, args: delivery.args, env };
35300
+ },
35301
+ shouldRestartNow: () => current !== null && new Date(current.expiresAt).getTime() - Date.now() < RESTART_AHEAD_MS
35302
+ });
35303
+ await proxy.start();
35304
+ }
35305
+
34890
35306
  // src/commands/version.ts
34891
35307
  var import_picocolors15 = __toESM(require("picocolors"));
34892
35308
  function version2() {
34893
- const v = true ? "2.60.45" : "unknown";
35309
+ const v = true ? "2.60.47" : "unknown";
34894
35310
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
34895
35311
  }
34896
35312
 
@@ -35039,10 +35455,10 @@ var EXIT_CODE_NAMES = {
35039
35455
  };
35040
35456
 
35041
35457
  // src/index.ts
35042
- var os49 = __toESM(require("os"));
35458
+ var os50 = __toESM(require("os"));
35043
35459
  if (!process.env.HOME) {
35044
35460
  try {
35045
- const home = os49.homedir();
35461
+ const home = os50.homedir();
35046
35462
  if (home) process.env.HOME = home;
35047
35463
  } catch {
35048
35464
  }
@@ -35088,6 +35504,9 @@ async function main() {
35088
35504
  await commands[command]();
35089
35505
  return;
35090
35506
  }
35507
+ if (command === "mcp-run") {
35508
+ return mcpRun(args);
35509
+ }
35091
35510
  if (command === "deploy") {
35092
35511
  if (args[0] === "ls" || args[0] === "list") return deployList();
35093
35512
  if (args[0] === "stop" || args[0] === "remove") return deployStop();