codeam-cli 2.60.46 → 2.60.48

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 +25 -0
  2. package/dist/index.js +835 -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";
@@ -790,11 +831,11 @@ function quiet(fn) {
790
831
  log.debug(TAG, "ignored sync error", err);
791
832
  }
792
833
  }
793
- function rmIfExistsQuiet(path72) {
834
+ function rmIfExistsQuiet(path73) {
794
835
  try {
795
- fs2.rmSync(path72, { force: true });
836
+ fs2.rmSync(path73, { force: true });
796
837
  } catch (err) {
797
- log.debug(TAG, `rmIfExists failed for ${path72}`, err);
838
+ log.debug(TAG, `rmIfExists failed for ${path73}`, err);
798
839
  }
799
840
  }
800
841
  function killQuiet(target, signal = "SIGTERM") {
@@ -940,9 +981,9 @@ var _default = makeConfig();
940
981
  var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, getActiveSession, getActiveSessionForAgent, setDisable1mContext, clearAll, saveCliConfig, loadCliConfig } = _default;
941
982
 
942
983
  // src/commands/pair-auto.ts
943
- var fs54 = __toESM(require("fs"));
944
- var os43 = __toESM(require("os"));
945
- var path58 = __toESM(require("path"));
984
+ var fs55 = __toESM(require("fs"));
985
+ var os44 = __toESM(require("os"));
986
+ var path59 = __toESM(require("path"));
946
987
  var import_crypto4 = require("crypto");
947
988
 
948
989
  // src/services/telemetry.service.ts
@@ -978,8 +1019,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
978
1019
  return decodedFile;
979
1020
  };
980
1021
  }
981
- function normalizeWindowsPath(path72) {
982
- return path72.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1022
+ function normalizeWindowsPath(path73) {
1023
+ return path73.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
983
1024
  }
984
1025
 
985
1026
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3459,9 +3500,9 @@ async function addSourceContext(frames) {
3459
3500
  LRU_FILE_CONTENTS_CACHE.reduce();
3460
3501
  return frames;
3461
3502
  }
3462
- function getContextLinesFromFile(path72, ranges, output) {
3503
+ function getContextLinesFromFile(path73, ranges, output) {
3463
3504
  return new Promise((resolve7) => {
3464
- const stream = (0, import_node_fs.createReadStream)(path72);
3505
+ const stream = (0, import_node_fs.createReadStream)(path73);
3465
3506
  const lineReaded = (0, import_node_readline.createInterface)({
3466
3507
  input: stream
3467
3508
  });
@@ -3476,7 +3517,7 @@ function getContextLinesFromFile(path72, ranges, output) {
3476
3517
  let rangeStart = range[0];
3477
3518
  let rangeEnd = range[1];
3478
3519
  function onStreamError() {
3479
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path72, 1);
3520
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path73, 1);
3480
3521
  lineReaded.close();
3481
3522
  lineReaded.removeAllListeners();
3482
3523
  destroyStreamAndResolve();
@@ -3537,8 +3578,8 @@ function clearLineContext(frame) {
3537
3578
  delete frame.context_line;
3538
3579
  delete frame.post_context;
3539
3580
  }
3540
- function shouldSkipContextLinesForFile(path72) {
3541
- 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:");
3542
3583
  }
3543
3584
  function shouldSkipContextLinesForFrame(frame) {
3544
3585
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -5692,7 +5733,7 @@ function readAnonId() {
5692
5733
  }
5693
5734
  function superProperties() {
5694
5735
  return {
5695
- cliVersion: true ? "2.60.46" : "0.0.0-dev",
5736
+ cliVersion: true ? "2.60.48" : "0.0.0-dev",
5696
5737
  nodeVersion: process.version,
5697
5738
  platform: process.platform,
5698
5739
  arch: process.arch,
@@ -5873,7 +5914,7 @@ var os4 = __toESM(require("os"));
5873
5914
  // package.json
5874
5915
  var package_default = {
5875
5916
  name: "codeam-cli",
5876
- version: "2.60.46",
5917
+ version: "2.60.48",
5877
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.",
5878
5919
  type: "commonjs",
5879
5920
  main: "dist/index.js",
@@ -6982,7 +7023,7 @@ var CommandRelayService = class {
6982
7023
  // fresh + clear the "CLI update available" banner after a self-update
6983
7024
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
6984
7025
  // pair/reconnect). Older backends ignore the extra field.
6985
- ..."2.60.46" ? { ideVersion: "2.60.46" } : {}
7026
+ ..."2.60.48" ? { ideVersion: "2.60.48" } : {}
6986
7027
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
6987
7028
  }
6988
7029
  /**
@@ -8356,9 +8397,9 @@ function closeAllTerminals() {
8356
8397
  }
8357
8398
 
8358
8399
  // src/commands/start/handlers.ts
8359
- var fs53 = __toESM(require("fs"));
8360
- var os42 = __toESM(require("os"));
8361
- var path57 = __toESM(require("path"));
8400
+ var fs54 = __toESM(require("fs"));
8401
+ var os43 = __toESM(require("os"));
8402
+ var path58 = __toESM(require("path"));
8362
8403
  var import_crypto3 = require("crypto");
8363
8404
  var import_child_process23 = require("child_process");
8364
8405
 
@@ -11815,10 +11856,10 @@ function buildForPlatform(platform3) {
11815
11856
  var import_node_crypto4 = require("crypto");
11816
11857
 
11817
11858
  // src/agents/claude/resolver.ts
11818
- function buildClaudeLaunch(extraArgs = [], os50 = createOsStrategy()) {
11819
- 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");
11820
11861
  if (!found) return null;
11821
- return os50.buildLaunch(found, extraArgs);
11862
+ return os51.buildLaunch(found, extraArgs);
11822
11863
  }
11823
11864
 
11824
11865
  // src/agents/claude/installer.ts
@@ -12408,8 +12449,8 @@ var ClaudeRuntimeStrategy = class {
12408
12449
  meta = getAgent("claude");
12409
12450
  mode = "interactive";
12410
12451
  os;
12411
- constructor(os50) {
12412
- this.os = os50;
12452
+ constructor(os51) {
12453
+ this.os = os51;
12413
12454
  }
12414
12455
  /**
12415
12456
  * Claude Code's react-ink TUI enables bracketed-paste mode at
@@ -13189,8 +13230,8 @@ function codexCredentialLocator() {
13189
13230
  function codexLoginLauncher() {
13190
13231
  return {
13191
13232
  async ensureInstalled() {
13192
- const os50 = createOsStrategy();
13193
- return os50.findInPath("codex") !== null;
13233
+ const os51 = createOsStrategy();
13234
+ return os51.findInPath("codex") !== null;
13194
13235
  },
13195
13236
  launch() {
13196
13237
  return (0, import_node_child_process4.spawn)("codex", ["login"], { stdio: "inherit" });
@@ -13213,8 +13254,8 @@ var CodexRuntimeStrategy = class {
13213
13254
  meta = getAgent("codex");
13214
13255
  mode = "interactive";
13215
13256
  os;
13216
- constructor(os50) {
13217
- this.os = os50;
13257
+ constructor(os51) {
13258
+ this.os = os51;
13218
13259
  }
13219
13260
  async prepareLaunch() {
13220
13261
  let binary = this.os.findInPath("codex");
@@ -13323,12 +13364,12 @@ var CodexRuntimeStrategy = class {
13323
13364
  });
13324
13365
  }
13325
13366
  };
13326
- function resolveNpm(os50) {
13327
- return os50.id === "win32" ? "npm.cmd" : "npm";
13367
+ function resolveNpm(os51) {
13368
+ return os51.id === "win32" ? "npm.cmd" : "npm";
13328
13369
  }
13329
- async function installCodexViaNpm(os50) {
13370
+ async function installCodexViaNpm(os51) {
13330
13371
  return new Promise((resolve7, reject) => {
13331
- 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"], {
13332
13373
  stdio: "inherit"
13333
13374
  });
13334
13375
  proc.on("close", (code) => {
@@ -13345,16 +13386,16 @@ async function installCodexViaNpm(os50) {
13345
13386
  });
13346
13387
  });
13347
13388
  }
13348
- function augmentNpmGlobalBin(os50) {
13389
+ function augmentNpmGlobalBin(os51) {
13349
13390
  try {
13350
- 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"], {
13351
13392
  stdio: ["ignore", "pipe", "ignore"]
13352
13393
  });
13353
13394
  if (result.status !== 0) return;
13354
13395
  const prefix = result.stdout.toString().trim();
13355
13396
  if (!prefix) return;
13356
- const binDir = os50.id === "win32" ? prefix : path24.join(prefix, "bin");
13357
- os50.augmentPath([binDir]);
13397
+ const binDir = os51.id === "win32" ? prefix : path24.join(prefix, "bin");
13398
+ os51.augmentPath([binDir]);
13358
13399
  } catch {
13359
13400
  }
13360
13401
  }
@@ -13438,9 +13479,9 @@ var import_node_child_process8 = require("child_process");
13438
13479
  // src/agents/coderabbit/installer.ts
13439
13480
  var import_node_child_process6 = require("child_process");
13440
13481
  var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
13441
- async function ensureCoderabbitInstalled(os50) {
13442
- if (os50.findInPath("coderabbit")) return true;
13443
- if (os50.id === "win32") {
13482
+ async function ensureCoderabbitInstalled(os51) {
13483
+ if (os51.findInPath("coderabbit")) return true;
13484
+ if (os51.id === "win32") {
13444
13485
  console.error(
13445
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"
13446
13487
  );
@@ -13455,8 +13496,8 @@ async function ensureCoderabbitInstalled(os50) {
13455
13496
  proc.on("error", () => resolve7(false));
13456
13497
  });
13457
13498
  if (!ok) return false;
13458
- os50.augmentPath([`${os50.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
13459
- return os50.findInPath("coderabbit") !== null;
13499
+ os51.augmentPath([`${os51.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
13500
+ return os51.findInPath("coderabbit") !== null;
13460
13501
  }
13461
13502
 
13462
13503
  // src/agents/coderabbit/link.ts
@@ -13491,10 +13532,10 @@ function coderabbitCredentialLocator() {
13491
13532
  validate: validateNonEmptyCredential
13492
13533
  };
13493
13534
  }
13494
- function coderabbitLoginLauncher(os50) {
13535
+ function coderabbitLoginLauncher(os51) {
13495
13536
  return {
13496
13537
  async ensureInstalled() {
13497
- return ensureCoderabbitInstalled(os50);
13538
+ return ensureCoderabbitInstalled(os51);
13498
13539
  },
13499
13540
  launch() {
13500
13541
  return (0, import_node_child_process7.spawn)("coderabbit", ["auth", "login"], { stdio: "inherit" });
@@ -13550,8 +13591,8 @@ function pickLine(obj) {
13550
13591
  function toHunk(raw, groupSeverity) {
13551
13592
  if (!raw || typeof raw !== "object") return null;
13552
13593
  const o = raw;
13553
- const path72 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
13554
- 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;
13555
13596
  const message = asString(
13556
13597
  pick(o, [
13557
13598
  "comment",
@@ -13568,7 +13609,7 @@ function toHunk(raw, groupSeverity) {
13568
13609
  const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
13569
13610
  const locObj = pick(o, ["location"]) ?? o;
13570
13611
  return {
13571
- path: path72.trim(),
13612
+ path: path73.trim(),
13572
13613
  line: pickLine(o) ?? pickLine(locObj),
13573
13614
  severity,
13574
13615
  message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
@@ -13651,10 +13692,10 @@ function parsePlain(stdout) {
13651
13692
  for (const line of stdout.split(/\r?\n/)) {
13652
13693
  const m = line.match(HUNK_LINE_RE);
13653
13694
  if (!m) continue;
13654
- const [, path72, lineNo, sevToken, message] = m;
13655
- if (!path72 || !lineNo || !message) continue;
13695
+ const [, path73, lineNo, sevToken, message] = m;
13696
+ if (!path73 || !lineNo || !message) continue;
13656
13697
  hunks.push({
13657
- path: path72.trim(),
13698
+ path: path73.trim(),
13658
13699
  line: Number(lineNo),
13659
13700
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
13660
13701
  message: message.trim().replace(/^[*-]\s+/, "")
@@ -13714,8 +13755,8 @@ var CoderabbitRuntimeStrategy = class {
13714
13755
  meta = getAgent("coderabbit");
13715
13756
  mode = "batch";
13716
13757
  os;
13717
- constructor(os50) {
13718
- this.os = os50;
13758
+ constructor(os51) {
13759
+ this.os = os51;
13719
13760
  }
13720
13761
  getDefaultArgs() {
13721
13762
  return ["review", "--agent"];
@@ -13986,10 +14027,10 @@ function cursorCredentialLocator() {
13986
14027
  validate: validateNonEmptyCredential
13987
14028
  };
13988
14029
  }
13989
- function cursorLoginLauncher(os50) {
14030
+ function cursorLoginLauncher(os51) {
13990
14031
  return {
13991
14032
  async ensureInstalled() {
13992
- if (os50.findInPath("cursor-agent")) return true;
14033
+ if (os51.findInPath("cursor-agent")) return true;
13993
14034
  console.error(
13994
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"
13995
14036
  );
@@ -14053,8 +14094,8 @@ var CursorRuntimeStrategy = class {
14053
14094
  meta = getAgent("cursor");
14054
14095
  mode = "interactive";
14055
14096
  os;
14056
- constructor(os50) {
14057
- this.os = os50;
14097
+ constructor(os51) {
14098
+ this.os = os51;
14058
14099
  }
14059
14100
  async prepareLaunch() {
14060
14101
  const binary = this.os.findInPath("cursor-agent");
@@ -14270,10 +14311,10 @@ function aiderCredentialLocator() {
14270
14311
  validate: validateNonEmptyCredential
14271
14312
  };
14272
14313
  }
14273
- function aiderLoginLauncher(os50) {
14314
+ function aiderLoginLauncher(os51) {
14274
14315
  return {
14275
14316
  async ensureInstalled() {
14276
- if (os50.findInPath("aider")) return true;
14317
+ if (os51.findInPath("aider")) return true;
14277
14318
  console.error(
14278
14319
  "\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
14279
14320
  );
@@ -14283,7 +14324,7 @@ function aiderLoginLauncher(os50) {
14283
14324
  console.error(
14284
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"
14285
14326
  );
14286
- 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"], {
14287
14328
  stdio: "ignore"
14288
14329
  });
14289
14330
  }
@@ -14355,8 +14396,8 @@ var AiderRuntimeStrategy = class {
14355
14396
  meta = getAgent("aider");
14356
14397
  mode = "interactive";
14357
14398
  os;
14358
- constructor(os50) {
14359
- this.os = os50;
14399
+ constructor(os51) {
14400
+ this.os = os51;
14360
14401
  }
14361
14402
  async prepareLaunch() {
14362
14403
  const binary = this.os.findInPath("aider");
@@ -14488,8 +14529,8 @@ function geminiCredentialLocator() {
14488
14529
  function geminiLoginLauncher() {
14489
14530
  return {
14490
14531
  async ensureInstalled() {
14491
- const os50 = createOsStrategy();
14492
- return os50.findInPath("gemini") !== null;
14532
+ const os51 = createOsStrategy();
14533
+ return os51.findInPath("gemini") !== null;
14493
14534
  },
14494
14535
  launch() {
14495
14536
  return (0, import_node_child_process12.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
@@ -14679,8 +14720,8 @@ var GeminiRuntimeStrategy = class {
14679
14720
  meta = getAgent("gemini");
14680
14721
  mode = "interactive";
14681
14722
  os;
14682
- constructor(os50) {
14683
- this.os = os50;
14723
+ constructor(os51) {
14724
+ this.os = os51;
14684
14725
  }
14685
14726
  async prepareLaunch() {
14686
14727
  const binary = this.os.findInPath("gemini");
@@ -14971,8 +15012,8 @@ var KimiRuntimeStrategy = class {
14971
15012
  meta = getAgent("kimi");
14972
15013
  mode = "interactive";
14973
15014
  os;
14974
- constructor(os50) {
14975
- this.os = os50;
15015
+ constructor(os51) {
15016
+ this.os = os51;
14976
15017
  }
14977
15018
  async prepareLaunch() {
14978
15019
  const binary = this.os.findInPath("kimi");
@@ -15085,19 +15126,19 @@ var KimiRuntimeStrategy = class {
15085
15126
 
15086
15127
  // src/agents/registry.ts
15087
15128
  var runtimeBuilders = {
15088
- claude: (os50) => new ClaudeRuntimeStrategy(os50),
15089
- codex: (os50) => new CodexRuntimeStrategy(os50),
15090
- coderabbit: (os50) => new CoderabbitRuntimeStrategy(os50),
15091
- cursor: (os50) => new CursorRuntimeStrategy(os50),
15092
- aider: (os50) => new AiderRuntimeStrategy(os50),
15093
- gemini: (os50) => new GeminiRuntimeStrategy(os50),
15094
- 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)
15095
15136
  };
15096
15137
  var deployBuilders = {
15097
15138
  claude: () => new ClaudeDeployStrategy(),
15098
15139
  codex: () => new CodexDeployStrategy()
15099
15140
  };
15100
- function createAgentStrategy(agent, os50 = createOsStrategy()) {
15141
+ function createAgentStrategy(agent, os51 = createOsStrategy()) {
15101
15142
  if (!AGENT_REGISTRY[agent]?.enabled) {
15102
15143
  throw new Error(
15103
15144
  `Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
@@ -15107,10 +15148,10 @@ function createAgentStrategy(agent, os50 = createOsStrategy()) {
15107
15148
  if (!build) {
15108
15149
  throw new Error(`No runtime strategy registered for agent "${agent}"`);
15109
15150
  }
15110
- return build(os50);
15151
+ return build(os51);
15111
15152
  }
15112
- function createInteractiveAgentStrategy(agent, os50 = createOsStrategy()) {
15113
- const s = createAgentStrategy(agent, os50);
15153
+ function createInteractiveAgentStrategy(agent, os51 = createOsStrategy()) {
15154
+ const s = createAgentStrategy(agent, os51);
15114
15155
  if (s.mode !== "interactive") {
15115
15156
  throw new Error(
15116
15157
  `Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
@@ -15802,26 +15843,26 @@ function restoreCoderabbitOauthBlob(value) {
15802
15843
  (0, import_node_fs5.writeFileSync)(path36.join(dir, file), contents, { mode: 384 });
15803
15844
  }
15804
15845
  async function configureCoderabbit(input, deps = {}) {
15805
- const os50 = deps.os ?? createOsStrategy();
15846
+ const os51 = deps.os ?? createOsStrategy();
15806
15847
  const ensureInstalled = deps.ensureInstalled ?? ensureCoderabbitInstalled;
15807
15848
  const isLoggedIn = deps.isLoggedIn ?? defaultIsLoggedIn;
15808
15849
  const runOAuth = deps.runOAuthLogin ?? runCoderabbitOAuthLogin;
15809
15850
  const snapshot = deps.snapshotDir ?? (() => snapshotCredentialDir());
15810
15851
  const capture2 = deps.captureCredential ?? ((b) => diffCapturedCredential(b));
15811
15852
  const loginWithApiKey = deps.loginWithApiKey ?? defaultLoginWithApiKey;
15812
- const home = os50.homeDir();
15813
- os50.augmentPath(
15814
- os50.id === "win32" ? [
15853
+ const home = os51.homeDir();
15854
+ os51.augmentPath(
15855
+ os51.id === "win32" ? [
15815
15856
  path36.join(home, ".local", "bin"),
15816
15857
  path36.join(process.env.APPDATA ?? path36.join(home, "AppData", "Roaming"), "npm"),
15817
15858
  path36.join(home, "scoop", "shims")
15818
15859
  ] : [path36.join(home, ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin"]
15819
15860
  );
15820
- const installed2 = os50.findInPath("coderabbit") !== null;
15861
+ const installed2 = os51.findInPath("coderabbit") !== null;
15821
15862
  const base = () => ({
15822
15863
  action: input.action,
15823
15864
  supported: true,
15824
- installed: os50.findInPath("coderabbit") !== null,
15865
+ installed: os51.findInPath("coderabbit") !== null,
15825
15866
  loggedIn: false
15826
15867
  });
15827
15868
  if (input.action === "status") {
@@ -15835,7 +15876,7 @@ async function configureCoderabbit(input, deps = {}) {
15835
15876
  const key = (input.apiKey ?? "").trim();
15836
15877
  if (!key) return { ...res2, error: "No API key provided" };
15837
15878
  if (!res2.installed) {
15838
- const ok = await ensureInstalled(os50);
15879
+ const ok = await ensureInstalled(os51);
15839
15880
  res2.installed = ok;
15840
15881
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
15841
15882
  }
@@ -15859,7 +15900,7 @@ async function configureCoderabbit(input, deps = {}) {
15859
15900
  }
15860
15901
  if (!res2.installed) {
15861
15902
  deps.onEvent?.({ kind: "installing" });
15862
- const ok = await ensureInstalled(os50);
15903
+ const ok = await ensureInstalled(os51);
15863
15904
  res2.installed = ok;
15864
15905
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
15865
15906
  }
@@ -15889,7 +15930,7 @@ async function configureCoderabbit(input, deps = {}) {
15889
15930
  const res2 = base();
15890
15931
  if (!installed2) {
15891
15932
  deps.onEvent?.({ kind: "installing" });
15892
- const ok = await ensureInstalled(os50);
15933
+ const ok = await ensureInstalled(os51);
15893
15934
  res2.installed = ok;
15894
15935
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
15895
15936
  }
@@ -15926,7 +15967,7 @@ async function configureCoderabbit(input, deps = {}) {
15926
15967
  }
15927
15968
  const res = base();
15928
15969
  if (!res.installed) {
15929
- const ok = await ensureInstalled(os50);
15970
+ const ok = await ensureInstalled(os51);
15930
15971
  res.installed = ok;
15931
15972
  if (!ok) return { ...res, error: "CodeRabbit CLI is not installed" };
15932
15973
  }
@@ -15955,14 +15996,14 @@ async function configureCoderabbit(input, deps = {}) {
15955
15996
 
15956
15997
  // src/commands/host-agent.ts
15957
15998
  var import_node_child_process23 = require("child_process");
15958
- var os35 = __toESM(require("os"));
15959
- var fs41 = __toESM(require("fs"));
15960
- var path44 = __toESM(require("path"));
15999
+ var os36 = __toESM(require("os"));
16000
+ var fs42 = __toESM(require("fs"));
16001
+ var path45 = __toESM(require("path"));
15961
16002
 
15962
- // src/commands/host/host-client.ts
15963
- var fs33 = __toESM(require("fs"));
15964
- var os29 = __toESM(require("os"));
15965
- 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"));
15966
16007
 
15967
16008
  // src/lib/restrict-to-owner.ts
15968
16009
  var import_node_fs6 = __toESM(require("fs"));
@@ -15997,11 +16038,49 @@ function restrictToOwner(filePath) {
15997
16038
  }
15998
16039
  }
15999
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
+
16000
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"));
16001
16080
  function sampleCpuTimes() {
16002
16081
  let idle = 0;
16003
16082
  let total = 0;
16004
- for (const cpu of os29.cpus()) {
16083
+ for (const cpu of os30.cpus()) {
16005
16084
  const t2 = cpu.times;
16006
16085
  idle += t2.idle;
16007
16086
  total += t2.user + t2.nice + t2.sys + t2.idle + t2.irq;
@@ -16020,8 +16099,8 @@ var MetricsCollector = class {
16020
16099
  const prev = this.prevCpu;
16021
16100
  this.prevCpu = current;
16022
16101
  if (!prev) {
16023
- const cores = os29.cpus().length || 1;
16024
- const proxy = os29.loadavg()[0] / cores * 100;
16102
+ const cores = os30.cpus().length || 1;
16103
+ const proxy = os30.loadavg()[0] / cores * 100;
16025
16104
  return Math.min(100, Math.max(0, Math.round(proxy)));
16026
16105
  }
16027
16106
  const idleDelta = current.idle - prev.idle;
@@ -16034,8 +16113,8 @@ var MetricsCollector = class {
16034
16113
  collect() {
16035
16114
  return {
16036
16115
  cpuPct: this.cpuPct(),
16037
- ramUsedMb: Math.round((os29.totalmem() - os29.freemem()) / 1048576),
16038
- ramTotalMb: Math.round(os29.totalmem() / 1048576),
16116
+ ramUsedMb: Math.round((os30.totalmem() - os30.freemem()) / 1048576),
16117
+ ramTotalMb: Math.round(os30.totalmem() / 1048576),
16039
16118
  latencyMs: this.lastLatencyMs
16040
16119
  };
16041
16120
  }
@@ -16044,19 +16123,19 @@ function apiBase() {
16044
16123
  return process.env.CODEAM_API_URL ?? resolveApiBaseUrl();
16045
16124
  }
16046
16125
  function hostIdentityPath() {
16047
- return path37.join(os29.homedir(), ".codeam", "host-agent.json");
16126
+ return path38.join(os30.homedir(), ".codeam", "host-agent.json");
16048
16127
  }
16049
16128
  function collectOsInfo() {
16050
16129
  return {
16051
- distro: os29.platform(),
16052
- arch: os29.arch(),
16053
- kernel: os29.release(),
16130
+ distro: os30.platform(),
16131
+ arch: os30.arch(),
16132
+ kernel: os30.release(),
16054
16133
  nodeVersion: process.versions.node
16055
16134
  };
16056
16135
  }
16057
16136
  function loadHostIdentity() {
16058
16137
  try {
16059
- const raw = fs33.readFileSync(hostIdentityPath(), "utf8");
16138
+ const raw = fs34.readFileSync(hostIdentityPath(), "utf8");
16060
16139
  const parsed = JSON.parse(raw);
16061
16140
  if (typeof parsed === "object" && parsed !== null && typeof parsed.hostId === "string" && typeof parsed.hostToken === "string" && typeof parsed.controlPluginId === "string") {
16062
16141
  const p2 = parsed;
@@ -16069,8 +16148,8 @@ function loadHostIdentity() {
16069
16148
  }
16070
16149
  function saveHostIdentity(identity) {
16071
16150
  const file = hostIdentityPath();
16072
- fs33.mkdirSync(path37.dirname(file), { recursive: true, mode: 448 });
16073
- 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), {
16074
16153
  encoding: "utf8",
16075
16154
  mode: 384
16076
16155
  });
@@ -16115,7 +16194,7 @@ function isTerminalEnrollError(err) {
16115
16194
  }
16116
16195
  function deleteHostIdentity() {
16117
16196
  try {
16118
- fs33.rmSync(hostIdentityPath(), { force: true });
16197
+ fs34.rmSync(hostIdentityPath(), { force: true });
16119
16198
  } catch {
16120
16199
  }
16121
16200
  }
@@ -16238,17 +16317,17 @@ async function reportDeployProgress(auth, deployId, step, message, sessionId) {
16238
16317
  }
16239
16318
 
16240
16319
  // src/commands/host/workspace.ts
16241
- var fs34 = __toESM(require("fs"));
16242
- var os30 = __toESM(require("os"));
16243
- var path38 = __toESM(require("path"));
16320
+ var fs35 = __toESM(require("fs"));
16321
+ var os31 = __toESM(require("os"));
16322
+ var path39 = __toESM(require("path"));
16244
16323
  var import_node_child_process17 = require("child_process");
16245
16324
  var import_node_util4 = require("util");
16246
16325
  var execFileP4 = (0, import_node_util4.promisify)(import_node_child_process17.execFile);
16247
16326
  function isAbsolutePathTarget(target) {
16248
- return path38.isAbsolute(target);
16327
+ return path39.isAbsolute(target);
16249
16328
  }
16250
16329
  function selfHostedWorkspaceRoot() {
16251
- return path38.join(os30.homedir(), ".codeam", "self-hosted");
16330
+ return path39.join(os31.homedir(), ".codeam", "self-hosted");
16252
16331
  }
16253
16332
  function nonInteractiveGitEnv() {
16254
16333
  return {
@@ -16301,13 +16380,13 @@ async function fetchGithubIdentity(token) {
16301
16380
  async function configureGitCredentials(dest, repoRef, cloneToken) {
16302
16381
  const gh = githubOwnerRepo(repoRef.trim());
16303
16382
  if (!gh || !cloneToken) return;
16304
- const credFile = path38.join(dest, ".git", "codeam-credentials");
16305
- 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
16306
16385
  `, { mode: 384 });
16307
16386
  restrictToOwner(credFile);
16308
16387
  const env = nonInteractiveGitEnv();
16309
16388
  const git2 = (args2) => execFileP4("git", ["-C", dest, ...args2], { timeout: 3e4, env });
16310
- const credFilePosix = credFile.split(path38.sep).join("/");
16389
+ const credFilePosix = credFile.split(path39.sep).join("/");
16311
16390
  await git2(["config", "--local", "--replace-all", "credential.helper", ""]).catch(() => {
16312
16391
  });
16313
16392
  await git2([
@@ -16343,17 +16422,17 @@ function maskToken(text, cloneToken) {
16343
16422
  }
16344
16423
  async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
16345
16424
  if (isAbsolutePathTarget(repoOrPath)) {
16346
- if (!fs34.existsSync(repoOrPath)) {
16425
+ if (!fs35.existsSync(repoOrPath)) {
16347
16426
  throw new Error(`deploy target path does not exist: ${repoOrPath}`);
16348
16427
  }
16349
16428
  return repoOrPath;
16350
16429
  }
16351
- const dest = path38.join(selfHostedWorkspaceRoot(), deployId);
16352
- if (fs34.existsSync(path38.join(dest, ".git"))) {
16430
+ const dest = path39.join(selfHostedWorkspaceRoot(), deployId);
16431
+ if (fs35.existsSync(path39.join(dest, ".git"))) {
16353
16432
  if (cloneToken) await configureGitCredentials(dest, repoOrPath, cloneToken);
16354
16433
  return dest;
16355
16434
  }
16356
- fs34.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
16435
+ fs35.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
16357
16436
  const cloneUrl = repoCloneUrl(repoOrPath, cloneToken);
16358
16437
  try {
16359
16438
  await execFileP4("git", ["clone", "--depth", "1", cloneUrl, dest], {
@@ -16370,9 +16449,9 @@ async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
16370
16449
  }
16371
16450
 
16372
16451
  // src/commands/host/agent-provisioning.ts
16373
- var fs35 = __toESM(require("fs"));
16374
- var os31 = __toESM(require("os"));
16375
- var path39 = __toESM(require("path"));
16452
+ var fs36 = __toESM(require("fs"));
16453
+ var os32 = __toESM(require("os"));
16454
+ var path40 = __toESM(require("path"));
16376
16455
  var PUBLIC_TO_INTERNAL_AGENT = {
16377
16456
  claude_code: "claude",
16378
16457
  claude: "claude",
@@ -16388,22 +16467,22 @@ function toInternalAgentId(publicAgentId) {
16388
16467
  return PUBLIC_TO_INTERNAL_AGENT[publicAgentId] ?? null;
16389
16468
  }
16390
16469
  function ensureDir(dir) {
16391
- fs35.mkdirSync(dir, { recursive: true, mode: 448 });
16470
+ fs36.mkdirSync(dir, { recursive: true, mode: 448 });
16392
16471
  }
16393
16472
  function writeFile0600(filePath, contents) {
16394
- ensureDir(path39.dirname(filePath));
16395
- fs35.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
16473
+ ensureDir(path40.dirname(filePath));
16474
+ fs36.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
16396
16475
  restrictToOwner(filePath);
16397
16476
  }
16398
16477
  function rmIfExists(filePath) {
16399
16478
  try {
16400
- fs35.rmSync(filePath, { force: true });
16479
+ fs36.rmSync(filePath, { force: true });
16401
16480
  } catch {
16402
16481
  }
16403
16482
  }
16404
16483
  var claudeProvisioner = {
16405
16484
  write(auth, home) {
16406
- const credentialsJson = path39.join(home, ".claude", ".credentials.json");
16485
+ const credentialsJson = path40.join(home, ".claude", ".credentials.json");
16407
16486
  if (auth.kind === "api_key") {
16408
16487
  rmIfExists(credentialsJson);
16409
16488
  return { ANTHROPIC_API_KEY: auth.value };
@@ -16415,8 +16494,8 @@ var claudeProvisioner = {
16415
16494
  } else {
16416
16495
  rmIfExists(credentialsJson);
16417
16496
  }
16418
- const claudeJson = path39.join(home, ".claude.json");
16419
- if (!fs35.existsSync(claudeJson)) {
16497
+ const claudeJson = path40.join(home, ".claude.json");
16498
+ if (!fs36.existsSync(claudeJson)) {
16420
16499
  writeFile0600(
16421
16500
  claudeJson,
16422
16501
  JSON.stringify({ hasCompletedOnboarding: true, customApiKeyResponses: { approved: [] } })
@@ -16427,7 +16506,7 @@ var claudeProvisioner = {
16427
16506
  };
16428
16507
  var codexProvisioner = {
16429
16508
  write(auth, home) {
16430
- const authJson = path39.join(home, ".codex", "auth.json");
16509
+ const authJson = path40.join(home, ".codex", "auth.json");
16431
16510
  if (auth.kind === "api_key") {
16432
16511
  rmIfExists(authJson);
16433
16512
  return { OPENAI_API_KEY: auth.value };
@@ -16438,8 +16517,8 @@ var codexProvisioner = {
16438
16517
  };
16439
16518
  var geminiProvisioner = {
16440
16519
  write(auth, home) {
16441
- const settingsJson = path39.join(home, ".gemini", "settings.json");
16442
- 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");
16443
16522
  if (auth.kind === "api_key") {
16444
16523
  rmIfExists(oauthCreds);
16445
16524
  writeFile0600(settingsJson, '{"security":{"auth":{"selectedType":"gemini-api-key"}}}');
@@ -16452,7 +16531,7 @@ var geminiProvisioner = {
16452
16531
  };
16453
16532
  var cursorProvisioner = {
16454
16533
  write(auth, home) {
16455
- const authJson = path39.join(home, ".config", "cursor", "auth.json");
16534
+ const authJson = path40.join(home, ".config", "cursor", "auth.json");
16456
16535
  if (auth.kind === "api_key") {
16457
16536
  rmIfExists(authJson);
16458
16537
  return { CURSOR_API_KEY: auth.value };
@@ -16478,8 +16557,8 @@ var cursorProvisioner = {
16478
16557
  var kimiProvisioner = {
16479
16558
  write(auth, home) {
16480
16559
  const credentialsFiles = [
16481
- path39.join(home, ".kimi", "credentials", "kimi-code.json"),
16482
- 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")
16483
16562
  ];
16484
16563
  if (auth.kind === "api_key") {
16485
16564
  credentialsFiles.forEach(rmIfExists);
@@ -16491,8 +16570,8 @@ var kimiProvisioner = {
16491
16570
  };
16492
16571
  var coderabbitProvisioner = {
16493
16572
  write(auth, home) {
16494
- const dir = path39.join(home, ".coderabbit");
16495
- const authJson = path39.join(dir, "auth.json");
16573
+ const dir = path40.join(home, ".coderabbit");
16574
+ const authJson = path40.join(dir, "auth.json");
16496
16575
  if (auth.kind === "api_key") {
16497
16576
  rmIfExists(authJson);
16498
16577
  return { CODERABBIT_API_KEY: auth.value };
@@ -16504,13 +16583,13 @@ var coderabbitProvisioner = {
16504
16583
  try {
16505
16584
  const parsed = JSON.parse(value);
16506
16585
  if (typeof parsed.file === "string" && typeof parsed.contents === "string") {
16507
- file = path39.basename(parsed.file);
16586
+ file = path40.basename(parsed.file);
16508
16587
  contents = parsed.contents;
16509
16588
  }
16510
16589
  } catch {
16511
16590
  }
16512
16591
  }
16513
- writeFile0600(path39.join(dir, file), contents);
16592
+ writeFile0600(path40.join(dir, file), contents);
16514
16593
  return {};
16515
16594
  }
16516
16595
  };
@@ -16530,7 +16609,7 @@ var UnsupportedAgentError = class extends Error {
16530
16609
  this.agentId = agentId;
16531
16610
  }
16532
16611
  };
16533
- function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os31.homedir()) {
16612
+ function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os32.homedir()) {
16534
16613
  const internal = toInternalAgentId(publicAgentId);
16535
16614
  if (!internal) throw new UnsupportedAgentError(publicAgentId);
16536
16615
  const provisioner = PROVISIONERS[internal];
@@ -16540,11 +16619,11 @@ function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os31.homedir(
16540
16619
 
16541
16620
  // src/commands/host/git-tooling.ts
16542
16621
  var import_node_child_process18 = require("child_process");
16543
- var fs36 = __toESM(require("fs"));
16544
- var os32 = __toESM(require("os"));
16545
- var path40 = __toESM(require("path"));
16622
+ var fs37 = __toESM(require("fs"));
16623
+ var os33 = __toESM(require("os"));
16624
+ var path41 = __toESM(require("path"));
16546
16625
  function codeamBinDir() {
16547
- 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");
16548
16627
  }
16549
16628
  var FALLBACK_GH_VERSION = "2.62.0";
16550
16629
  var RELEASE_API = "https://api.github.com/repos/cli/cli/releases/latest";
@@ -16576,7 +16655,7 @@ async function download(url, dest) {
16576
16655
  const res = await fetch(url, { headers: { "User-Agent": "codeam-cli" } });
16577
16656
  if (!res.ok || !res.body) return false;
16578
16657
  const buf = Buffer.from(await res.arrayBuffer());
16579
- fs36.writeFileSync(dest, buf);
16658
+ fs37.writeFileSync(dest, buf);
16580
16659
  return true;
16581
16660
  } catch {
16582
16661
  return false;
@@ -16599,8 +16678,8 @@ async function ensureGhCli(runner, token, deps = {}) {
16599
16678
  const version3 = await resolveVersionFn(token);
16600
16679
  const asset = `gh_${version3}_${osToken}_${arch2}`;
16601
16680
  const url = `https://github.com/cli/cli/releases/download/v${version3}/${asset}.${ext}`;
16602
- const tmpRoot = fs36.mkdtempSync(path40.join(os32.tmpdir(), "codeam-gh-"));
16603
- 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}`);
16604
16683
  if (!await downloadFn(url, archive)) {
16605
16684
  log.warn("host-agent", "gh download failed \u2014 skipping (git pull/push still work via the credential helper)");
16606
16685
  return null;
@@ -16610,16 +16689,16 @@ async function ensureGhCli(runner, token, deps = {}) {
16610
16689
  log.warn("host-agent", `gh archive extraction failed (code=${String(extract.code)}) \u2014 skipping`);
16611
16690
  return null;
16612
16691
  }
16613
- const extractedBin = path40.join(tmpRoot, asset, "bin", binaryName);
16614
- if (!fs36.existsSync(extractedBin)) {
16692
+ const extractedBin = path41.join(tmpRoot, asset, "bin", binaryName);
16693
+ if (!fs37.existsSync(extractedBin)) {
16615
16694
  log.warn("host-agent", "gh binary not found in the extracted archive \u2014 skipping");
16616
16695
  return null;
16617
16696
  }
16618
16697
  const binDir = codeamBinDir();
16619
- fs36.mkdirSync(binDir, { recursive: true });
16620
- const target = path40.join(binDir, binaryName);
16621
- fs36.copyFileSync(extractedBin, target);
16622
- 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);
16623
16702
  log.info("host-agent", `gh installed to ${target} (v${version3})`);
16624
16703
  return target;
16625
16704
  } catch (e) {
@@ -17106,23 +17185,23 @@ async function ensureModernPython(runner) {
17106
17185
  }
17107
17186
 
17108
17187
  // src/commands/host/headroom-bootstrap.ts
17109
- var fs38 = __toESM(require("fs"));
17110
- var path42 = __toESM(require("path"));
17188
+ var fs39 = __toESM(require("fs"));
17189
+ var path43 = __toESM(require("path"));
17111
17190
 
17112
17191
  // src/commands/host/headroom-config.ts
17113
- var fs37 = __toESM(require("fs"));
17114
- var os33 = __toESM(require("os"));
17115
- var path41 = __toESM(require("path"));
17192
+ var fs38 = __toESM(require("fs"));
17193
+ var os34 = __toESM(require("os"));
17194
+ var path42 = __toESM(require("path"));
17116
17195
  function headroomConfigPath() {
17117
- return path41.join(os33.homedir(), ".codeam", "headroom-config.json");
17196
+ return path42.join(os34.homedir(), ".codeam", "headroom-config.json");
17118
17197
  }
17119
17198
  function persistHeadroomConfig(config) {
17120
17199
  try {
17121
17200
  const file = headroomConfigPath();
17122
- fs37.mkdirSync(path41.dirname(file), { recursive: true, mode: 448 });
17201
+ fs38.mkdirSync(path42.dirname(file), { recursive: true, mode: 448 });
17123
17202
  const tmp = `${file}.tmp-${process.pid}`;
17124
- fs37.writeFileSync(tmp, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
17125
- fs37.renameSync(tmp, file);
17203
+ fs38.writeFileSync(tmp, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
17204
+ fs38.renameSync(tmp, file);
17126
17205
  restrictToOwner(file);
17127
17206
  } catch (err) {
17128
17207
  log.warn(
@@ -17132,21 +17211,21 @@ function persistHeadroomConfig(config) {
17132
17211
  }
17133
17212
  }
17134
17213
  function agentSettingsPath(kind) {
17135
- const home = os33.homedir();
17136
- if (kind === "claude") return path41.join(home, ".claude", "settings.json");
17137
- if (kind === "codex") return path41.join(home, ".codex", "auth.json");
17138
- 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");
17139
17218
  return null;
17140
17219
  }
17141
17220
  function backupAgentHeadroomConfig(kind) {
17142
17221
  const src = agentSettingsPath(kind);
17143
17222
  if (!src) return;
17144
17223
  try {
17145
- if (!fs37.existsSync(src)) return;
17146
- const dest = path41.join(os33.homedir(), ".codeam", `headroom-backup-${kind}.json`);
17147
- fs37.mkdirSync(path41.dirname(dest), { recursive: true, mode: 448 });
17148
- fs37.copyFileSync(src, dest);
17149
- 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);
17150
17229
  log.info("host-agent", `headroom config backup: ${src} \u2192 ${dest}`);
17151
17230
  } catch (err) {
17152
17231
  log.warn(
@@ -17158,12 +17237,12 @@ function backupAgentHeadroomConfig(kind) {
17158
17237
  function restoreAgentHeadroomConfig(kind) {
17159
17238
  const dest = agentSettingsPath(kind);
17160
17239
  if (!dest) return false;
17161
- const src = path41.join(os33.homedir(), ".codeam", `headroom-backup-${kind}.json`);
17162
- 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;
17163
17242
  try {
17164
- fs37.mkdirSync(path41.dirname(dest), { recursive: true, mode: 448 });
17165
- fs37.copyFileSync(src, dest);
17166
- fs37.chmodSync(dest, 384);
17243
+ fs38.mkdirSync(path42.dirname(dest), { recursive: true, mode: 448 });
17244
+ fs38.copyFileSync(src, dest);
17245
+ fs38.chmodSync(dest, 384);
17167
17246
  log.info("host-agent", `headroom config restored: ${src} \u2192 ${dest}`);
17168
17247
  return true;
17169
17248
  } catch (err) {
@@ -17176,7 +17255,7 @@ function restoreAgentHeadroomConfig(kind) {
17176
17255
  }
17177
17256
  function readHeadroomChildEnv() {
17178
17257
  try {
17179
- const raw = fs37.readFileSync(headroomConfigPath(), "utf8");
17258
+ const raw = fs38.readFileSync(headroomConfigPath(), "utf8");
17180
17259
  const parsed = JSON.parse(raw);
17181
17260
  if (typeof parsed !== "object" || parsed === null) return {};
17182
17261
  const o = parsed;
@@ -17212,37 +17291,37 @@ function bundledClaudeBinDir() {
17212
17291
  const roots = /* @__PURE__ */ new Set();
17213
17292
  let dir = __dirname;
17214
17293
  for (let i = 0; i < 6; i++) {
17215
- roots.add(path42.join(dir, "node_modules"));
17216
- const parent = path42.dirname(dir);
17294
+ roots.add(path43.join(dir, "node_modules"));
17295
+ const parent = path43.dirname(dir);
17217
17296
  if (parent === dir) break;
17218
17297
  dir = parent;
17219
17298
  }
17220
17299
  try {
17221
17300
  const main2 = require.resolve("@anthropic-ai/claude-agent-sdk");
17222
- const marker = `${path42.sep}@anthropic-ai${path42.sep}`;
17301
+ const marker = `${path43.sep}@anthropic-ai${path43.sep}`;
17223
17302
  const idx = main2.lastIndexOf(marker);
17224
17303
  if (idx !== -1) roots.add(main2.slice(0, idx));
17225
17304
  } catch {
17226
17305
  }
17227
17306
  for (const nm of roots) {
17228
- const atAnthropic = path42.join(nm, "@anthropic-ai");
17307
+ const atAnthropic = path43.join(nm, "@anthropic-ai");
17229
17308
  let entries;
17230
17309
  try {
17231
- entries = fs38.readdirSync(atAnthropic);
17310
+ entries = fs39.readdirSync(atAnthropic);
17232
17311
  } catch {
17233
17312
  continue;
17234
17313
  }
17235
17314
  for (const entry of entries) {
17236
17315
  if (!entry.startsWith("claude-agent-sdk-")) continue;
17237
- const bin = path42.join(atAnthropic, entry, "claude");
17238
- 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);
17239
17318
  }
17240
17319
  }
17241
17320
  return null;
17242
17321
  }
17243
17322
  async function getFreeDiskBytes(dir) {
17244
17323
  try {
17245
- const s = await fs38.promises.statfs(dir);
17324
+ const s = await fs39.promises.statfs(dir);
17246
17325
  return s.bsize * s.bavail;
17247
17326
  } catch {
17248
17327
  return null;
@@ -17304,7 +17383,7 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
17304
17383
  if (initKind === "claude") {
17305
17384
  const claudeDir = bundledClaudeBinDir();
17306
17385
  if (claudeDir) {
17307
- initEnv.PATH = `${claudeDir}${path42.delimiter}${process.env["PATH"] ?? ""}`;
17386
+ initEnv.PATH = `${claudeDir}${path43.delimiter}${process.env["PATH"] ?? ""}`;
17308
17387
  log.info("host-agent", `headroom init: bundled claude on PATH (${claudeDir})`);
17309
17388
  } else {
17310
17389
  log.warn("host-agent", "headroom init: bundled claude binary not found \u2014 init may fail");
@@ -17339,9 +17418,9 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
17339
17418
  var import_node_child_process21 = require("child_process");
17340
17419
 
17341
17420
  // src/lib/updateNotifier.ts
17342
- var fs39 = __toESM(require("fs"));
17343
- var os34 = __toESM(require("os"));
17344
- var path43 = __toESM(require("path"));
17421
+ var fs40 = __toESM(require("fs"));
17422
+ var os35 = __toESM(require("os"));
17423
+ var path44 = __toESM(require("path"));
17345
17424
  var https6 = __toESM(require("https"));
17346
17425
  var import_node_child_process20 = require("child_process");
17347
17426
  var import_picocolors3 = __toESM(require("picocolors"));
@@ -17350,12 +17429,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
17350
17429
  var TTL_MS = 24 * 60 * 60 * 1e3;
17351
17430
  var REQUEST_TIMEOUT_MS = 1500;
17352
17431
  function cachePath() {
17353
- const dir = path43.join(os34.homedir(), ".codeam");
17354
- return path43.join(dir, "update-check.json");
17432
+ const dir = path44.join(os35.homedir(), ".codeam");
17433
+ return path44.join(dir, "update-check.json");
17355
17434
  }
17356
17435
  function readCache() {
17357
17436
  try {
17358
- const raw = fs39.readFileSync(cachePath(), "utf8");
17437
+ const raw = fs40.readFileSync(cachePath(), "utf8");
17359
17438
  const parsed = JSON.parse(raw);
17360
17439
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
17361
17440
  return parsed;
@@ -17366,10 +17445,10 @@ function readCache() {
17366
17445
  function writeCache(cache) {
17367
17446
  try {
17368
17447
  const file = cachePath();
17369
- fs39.mkdirSync(path43.dirname(file), { recursive: true });
17448
+ fs40.mkdirSync(path44.dirname(file), { recursive: true });
17370
17449
  const tmp = `${file}.${process.pid}.tmp`;
17371
- fs39.writeFileSync(tmp, JSON.stringify(cache));
17372
- fs39.renameSync(tmp, file);
17450
+ fs40.writeFileSync(tmp, JSON.stringify(cache));
17451
+ fs40.renameSync(tmp, file);
17373
17452
  } catch {
17374
17453
  }
17375
17454
  }
@@ -17443,8 +17522,8 @@ function isLinkedInstall() {
17443
17522
  timeout: 2e3
17444
17523
  }).trim();
17445
17524
  if (!root) return false;
17446
- const pkgPath = path43.join(root, PKG_NAME);
17447
- return fs39.lstatSync(pkgPath).isSymbolicLink();
17525
+ const pkgPath = path44.join(root, PKG_NAME);
17526
+ return fs40.lstatSync(pkgPath).isSymbolicLink();
17448
17527
  } catch {
17449
17528
  return false;
17450
17529
  }
@@ -17480,7 +17559,7 @@ function maybeAutoUpdate(currentVersion, latest) {
17480
17559
  return;
17481
17560
  }
17482
17561
  try {
17483
- fs39.unlinkSync(cachePath());
17562
+ fs40.unlinkSync(cachePath());
17484
17563
  } catch {
17485
17564
  }
17486
17565
  process.stderr.write(` ${import_picocolors3.default.green("\u2713")} Updated. Resuming session...
@@ -17496,7 +17575,7 @@ async function autoUpgradeBeforeCriticalCommand() {
17496
17575
  if (process.env.NODE_ENV === "test") return;
17497
17576
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17498
17577
  if (process.env.CI) return;
17499
- const current = true ? "2.60.46" : null;
17578
+ const current = true ? "2.60.48" : null;
17500
17579
  if (!current) return;
17501
17580
  const cache = readCache();
17502
17581
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17513,7 +17592,7 @@ function checkForUpdates() {
17513
17592
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17514
17593
  if (process.env.CI) return;
17515
17594
  if (!process.stdout.isTTY) return;
17516
- const current = true ? "2.60.46" : null;
17595
+ const current = true ? "2.60.48" : null;
17517
17596
  if (!current) return;
17518
17597
  const cache = readCache();
17519
17598
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17533,7 +17612,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
17533
17612
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
17534
17613
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
17535
17614
  function currentCliVersion() {
17536
- return true ? "2.60.46" : null;
17615
+ return true ? "2.60.48" : null;
17537
17616
  }
17538
17617
  function runCmd(cmd, args2, timeoutMs) {
17539
17618
  return new Promise((resolve7) => {
@@ -17600,7 +17679,7 @@ async function runSelfUpdate() {
17600
17679
 
17601
17680
  // src/commands/host/teardown.ts
17602
17681
  var import_node_child_process22 = require("child_process");
17603
- var fs40 = __toESM(require("fs"));
17682
+ var fs41 = __toESM(require("fs"));
17604
17683
  var defaultDisableService = () => {
17605
17684
  try {
17606
17685
  (0, import_node_child_process22.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
@@ -17609,7 +17688,7 @@ var defaultDisableService = () => {
17609
17688
  };
17610
17689
  var defaultTeardownHeadroom = () => {
17611
17690
  try {
17612
- const kind = JSON.parse(fs40.readFileSync(headroomConfigPath(), "utf8")).agent;
17691
+ const kind = JSON.parse(fs41.readFileSync(headroomConfigPath(), "utf8")).agent;
17613
17692
  if (kind) {
17614
17693
  (0, import_node_child_process22.execFileSync)("headroom", ["unwrap", kind], { stdio: "ignore", timeout: 15e3 });
17615
17694
  }
@@ -17677,8 +17756,8 @@ function maybeResumeLocalHeadroomReporter(ctx) {
17677
17756
  if (process.env["HEADROOM_ENABLED"] === "1") return null;
17678
17757
  try {
17679
17758
  const file = headroomConfigPath();
17680
- if (!fs41.existsSync(file)) return null;
17681
- const cfg = JSON.parse(fs41.readFileSync(file, "utf8"));
17759
+ if (!fs42.existsSync(file)) return null;
17760
+ const cfg = JSON.parse(fs42.readFileSync(file, "utf8"));
17682
17761
  if (!cfg?.enabled) return null;
17683
17762
  const agent = cfg.agent ?? "claude";
17684
17763
  const ingestUrl = `${resolveApiBaseUrl()}/api/sessions/${ctx.sessionId}/headroom-savings`;
@@ -17751,6 +17830,9 @@ function isDeployPayload(p2) {
17751
17830
  if (p2.headroomSavingsIngestUrl !== void 0 && typeof p2.headroomSavingsIngestUrl !== "string") {
17752
17831
  return false;
17753
17832
  }
17833
+ if (p2.integrations !== void 0 && !Array.isArray(p2.integrations)) {
17834
+ return false;
17835
+ }
17754
17836
  const hasHouse = isHouseProxy(p2.houseProxy);
17755
17837
  const hasSealed = typeof p2.sealedAgentAuth === "string";
17756
17838
  return hasHouse || hasSealed;
@@ -18083,9 +18165,9 @@ var HostAgentSupervisor = class {
18083
18165
  API_TIMEOUT_MS: "3000000",
18084
18166
  CODEAM_AUTO_TOKEN: payload.autoPairToken
18085
18167
  };
18086
- const houseConfigDir = path44.join(os35.homedir(), ".codeam", "house-claude");
18168
+ const houseConfigDir = path45.join(os36.homedir(), ".codeam", "house-claude");
18087
18169
  try {
18088
- fs41.mkdirSync(houseConfigDir, { recursive: true, mode: 448 });
18170
+ fs42.mkdirSync(houseConfigDir, { recursive: true, mode: 448 });
18089
18171
  } catch {
18090
18172
  }
18091
18173
  childEnv.CLAUDE_CONFIG_DIR = houseConfigDir;
@@ -18103,14 +18185,14 @@ var HostAgentSupervisor = class {
18103
18185
  report("installing", "installing agent CLI");
18104
18186
  await this.runAgentInstall(payload.agentInstallScript);
18105
18187
  }
18106
- const home = process.env.HOME || os35.homedir();
18188
+ const home = process.env.HOME || os36.homedir();
18107
18189
  childEnv.PATH = `${home}/.local/bin:${process.env.PATH ?? ""}`;
18108
18190
  if (payload.cloneToken) {
18109
18191
  try {
18110
18192
  report("preparing", "configuring git tooling");
18111
18193
  const ghCmd = await ensureGhCli(defaultGitToolingRunner, payload.cloneToken);
18112
18194
  if (ghCmd) {
18113
- childEnv.PATH = `${codeamBinDir()}${path44.delimiter}${childEnv.PATH}`;
18195
+ childEnv.PATH = `${codeamBinDir()}${path45.delimiter}${childEnv.PATH}`;
18114
18196
  await ensureGhAuth(defaultGitToolingRunner, ghCmd, payload.cloneToken);
18115
18197
  }
18116
18198
  } catch (e) {
@@ -18126,7 +18208,7 @@ var HostAgentSupervisor = class {
18126
18208
  }
18127
18209
  if (payload.headroomEnabled && payload.headroomAgent && payload.headroomSavingsIngestUrl && isHeadroomSupportedAgent(payload.headroomAgent)) {
18128
18210
  report("headroom", "setting up Headroom proxy");
18129
- const freeBytes = await this.getFreeDisk(os35.homedir());
18211
+ const freeBytes = await this.getFreeDisk(os36.homedir());
18130
18212
  const alreadyInstalled = this.isHeadroomInstalled();
18131
18213
  if (!alreadyInstalled && freeBytes !== null && freeBytes < HEADROOM_MIN_FREE_DISK_BYTES) {
18132
18214
  const freeGb = (freeBytes / 1e9).toFixed(1);
@@ -18175,6 +18257,11 @@ var HostAgentSupervisor = class {
18175
18257
  );
18176
18258
  persistHeadroomConfig({ enabled: false });
18177
18259
  }
18260
+ if (payload.integrations?.length) {
18261
+ persistIntegrationsManifest({ integrations: payload.integrations });
18262
+ } else {
18263
+ clearIntegrationsManifest();
18264
+ }
18178
18265
  report("spawning", "starting agent");
18179
18266
  const proc = this.spawnSessionChild(childEnv, cwd, extraArgs);
18180
18267
  const child = {
@@ -18248,7 +18335,7 @@ var HostAgentSupervisor = class {
18248
18335
  */
18249
18336
  runAgentInstall(script) {
18250
18337
  return new Promise((resolve7) => {
18251
- const home = process.env.HOME || os35.homedir();
18338
+ const home = process.env.HOME || os36.homedir();
18252
18339
  const child = (0, import_node_child_process23.spawn)("sh", ["-c", script], {
18253
18340
  env: { ...process.env, HOME: home },
18254
18341
  stdio: ["ignore", "pipe", "pipe"]
@@ -18432,9 +18519,9 @@ async function configureHeadroom(action, ctx, deps) {
18432
18519
  }
18433
18520
 
18434
18521
  // src/services/headroom/budget-relaunch.ts
18435
- var fs42 = __toESM(require("fs"));
18436
- var os36 = __toESM(require("os"));
18437
- var path45 = __toESM(require("path"));
18522
+ var fs43 = __toESM(require("fs"));
18523
+ var os37 = __toESM(require("os"));
18524
+ var path46 = __toESM(require("path"));
18438
18525
  var import_child_process13 = require("child_process");
18439
18526
  function amendDeploymentManifestBudget(manifest, budget) {
18440
18527
  const rawArgs = manifest.proxy_args ?? [];
@@ -18468,7 +18555,7 @@ function amendDeploymentManifestBudget(manifest, budget) {
18468
18555
  return { ...manifest, proxy_args: newArgs, base_env: newEnv };
18469
18556
  }
18470
18557
  function findHeadroomDeployments(homeDir2, deps) {
18471
- const deployDir = path45.join(homeDir2, ".headroom", "deploy");
18558
+ const deployDir = path46.join(homeDir2, ".headroom", "deploy");
18472
18559
  let profiles;
18473
18560
  try {
18474
18561
  profiles = deps.readDir(deployDir);
@@ -18477,7 +18564,7 @@ function findHeadroomDeployments(homeDir2, deps) {
18477
18564
  }
18478
18565
  const results = [];
18479
18566
  for (const profile of profiles) {
18480
- const manifestPath = path45.join(deployDir, profile, "manifest.json");
18567
+ const manifestPath = path46.join(deployDir, profile, "manifest.json");
18481
18568
  let raw;
18482
18569
  try {
18483
18570
  raw = deps.readJson(manifestPath);
@@ -18509,8 +18596,8 @@ async function applyBudgetToHeadroom(budget, deps) {
18509
18596
  }
18510
18597
  function writeManifestReal(manifestPath, manifest) {
18511
18598
  const tmp = manifestPath + ".codeam.tmp";
18512
- fs42.writeFileSync(tmp, JSON.stringify(manifest, null, 2) + "\n", { mode: 384 });
18513
- fs42.renameSync(tmp, manifestPath);
18599
+ fs43.writeFileSync(tmp, JSON.stringify(manifest, null, 2) + "\n", { mode: 384 });
18600
+ fs43.renameSync(tmp, manifestPath);
18514
18601
  }
18515
18602
  function restartDeploymentReal(profile) {
18516
18603
  try {
@@ -18540,11 +18627,11 @@ function spawnProxyReal2(_budget) {
18540
18627
  });
18541
18628
  }
18542
18629
  function makeRealApplyBudgetDeps() {
18543
- const homeDir2 = os36.homedir();
18630
+ const homeDir2 = os37.homedir();
18544
18631
  return {
18545
18632
  findDeployments: () => findHeadroomDeployments(homeDir2, {
18546
- readDir: (dir) => fs42.readdirSync(dir),
18547
- readJson: (filePath) => JSON.parse(fs42.readFileSync(filePath, "utf8"))
18633
+ readDir: (dir) => fs43.readdirSync(dir),
18634
+ readJson: (filePath) => JSON.parse(fs43.readFileSync(filePath, "utf8"))
18548
18635
  }),
18549
18636
  writeManifest: writeManifestReal,
18550
18637
  restartDeployment: restartDeploymentReal,
@@ -19224,8 +19311,8 @@ function activePreviewSessionIds() {
19224
19311
 
19225
19312
  // src/services/preview/start-orchestrator.ts
19226
19313
  var import_child_process17 = require("child_process");
19227
- var fs47 = __toESM(require("fs"));
19228
- var path50 = __toESM(require("path"));
19314
+ var fs48 = __toESM(require("fs"));
19315
+ var path51 = __toESM(require("path"));
19229
19316
  var import_which2 = __toESM(require("which"));
19230
19317
  var INSTALL_TIMEOUT_MS = 5 * 6e4;
19231
19318
  var SETUP_TIMEOUT_MS = 2 * 6e4;
@@ -19292,8 +19379,8 @@ function normalizeDetectionForSpawn(detection, cwd) {
19292
19379
  if (args2.length === 0) return detection;
19293
19380
  const binName = args2[0];
19294
19381
  if (binName.startsWith("-")) return detection;
19295
- const binPath = path50.join(cwd, "node_modules", ".bin", binName);
19296
- if (!fs47.existsSync(binPath)) return detection;
19382
+ const binPath = path51.join(cwd, "node_modules", ".bin", binName);
19383
+ if (!fs48.existsSync(binPath)) return detection;
19297
19384
  return {
19298
19385
  ...detection,
19299
19386
  command: binPath,
@@ -19643,9 +19730,9 @@ async function establishTunnel(ctx, dev) {
19643
19730
 
19644
19731
  // src/beads/bd-adapter.ts
19645
19732
  var import_child_process18 = require("child_process");
19646
- var fs48 = __toESM(require("fs"));
19647
- var os38 = __toESM(require("os"));
19648
- var path51 = __toESM(require("path"));
19733
+ var fs49 = __toESM(require("fs"));
19734
+ var os39 = __toESM(require("os"));
19735
+ var path52 = __toESM(require("path"));
19649
19736
  var BD_PACKAGE = "@beads/bd";
19650
19737
  function resolveBundledBdBinary() {
19651
19738
  return _resolveSeam.resolveBundled();
@@ -19657,11 +19744,11 @@ function _defaultResolveBundled() {
19657
19744
  } catch {
19658
19745
  return null;
19659
19746
  }
19660
- const binDir = path51.join(path51.dirname(pkgJsonPath), "bin");
19747
+ const binDir = path52.join(path52.dirname(pkgJsonPath), "bin");
19661
19748
  const binaryName = process.platform === "win32" ? "bd.exe" : "bd";
19662
- const binaryPath = path51.join(binDir, binaryName);
19749
+ const binaryPath = path52.join(binDir, binaryName);
19663
19750
  try {
19664
- fs48.accessSync(binaryPath, fs48.constants.F_OK);
19751
+ fs49.accessSync(binaryPath, fs49.constants.F_OK);
19665
19752
  return binaryPath;
19666
19753
  } catch {
19667
19754
  return null;
@@ -19671,13 +19758,13 @@ function resolveBdOnPath() {
19671
19758
  return _resolveSeam.resolveOnPath();
19672
19759
  }
19673
19760
  function _defaultResolveOnPath() {
19674
- const dirs = (process.env.PATH ?? "").split(path51.delimiter).filter(Boolean);
19761
+ const dirs = (process.env.PATH ?? "").split(path52.delimiter).filter(Boolean);
19675
19762
  const candidates = process.platform === "win32" ? ["bd.exe", "bd.cmd", "bd"] : ["bd"];
19676
19763
  for (const dir of dirs) {
19677
19764
  for (const candidate of candidates) {
19678
- const full = path51.join(dir, candidate);
19765
+ const full = path52.join(dir, candidate);
19679
19766
  try {
19680
- fs48.accessSync(full, fs48.constants.F_OK);
19767
+ fs49.accessSync(full, fs49.constants.F_OK);
19681
19768
  return full;
19682
19769
  } catch {
19683
19770
  }
@@ -19762,7 +19849,7 @@ var BdAdapter = class {
19762
19849
  const env = { ...process.env };
19763
19850
  if (!env.HOME) {
19764
19851
  try {
19765
- const home = os38.homedir();
19852
+ const home = os39.homedir();
19766
19853
  if (home) env.HOME = home;
19767
19854
  } catch {
19768
19855
  }
@@ -19854,9 +19941,9 @@ function coerceIssue(row, projectKey) {
19854
19941
 
19855
19942
  // src/beads/provisioner.ts
19856
19943
  var import_child_process22 = require("child_process");
19857
- var fs51 = __toESM(require("fs"));
19858
- var os40 = __toESM(require("os"));
19859
- var path54 = __toESM(require("path"));
19944
+ var fs52 = __toESM(require("fs"));
19945
+ var os41 = __toESM(require("os"));
19946
+ var path55 = __toESM(require("path"));
19860
19947
 
19861
19948
  // src/beads/install-bd.ts
19862
19949
  var import_child_process19 = require("child_process");
@@ -19921,9 +20008,9 @@ async function installBd(platform3 = process.platform) {
19921
20008
 
19922
20009
  // src/beads/install-dolt.ts
19923
20010
  var import_child_process20 = require("child_process");
19924
- var fs49 = __toESM(require("fs"));
19925
- var os39 = __toESM(require("os"));
19926
- var path52 = __toESM(require("path"));
20011
+ var fs50 = __toESM(require("fs"));
20012
+ var os40 = __toESM(require("os"));
20013
+ var path53 = __toESM(require("path"));
19927
20014
  var DOLT_INSTALL_SH_URL = "https://github.com/dolthub/dolt/releases/latest/download/install.sh";
19928
20015
  var DOLT_MSI_URL = "https://github.com/dolthub/dolt/releases/latest/download/dolt-windows-amd64.msi";
19929
20016
  function resolveDoltInstallStrategy(platform3) {
@@ -19963,11 +20050,11 @@ function resolveDoltInstallStrategy(platform3) {
19963
20050
  }
19964
20051
  var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
19965
20052
  function doltPlatformTuple(platform3, arch2) {
19966
- const os50 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
20053
+ const os51 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
19967
20054
  const a = arch2 === "x64" ? "amd64" : arch2 === "arm64" ? "arm64" : null;
19968
20055
  if (!a) return null;
19969
- if (os50 === "windows" && a !== "amd64") return null;
19970
- return `${os50}-${a}`;
20056
+ if (os51 === "windows" && a !== "amd64") return null;
20057
+ return `${os51}-${a}`;
19971
20058
  }
19972
20059
  function resolveDoltTarballStrategy(targetDir, platform3, arch2) {
19973
20060
  const tuple = doltPlatformTuple(platform3, arch2);
@@ -20012,14 +20099,14 @@ async function installDoltToDir(targetDir, platform3 = process.platform, arch2 =
20012
20099
  return result;
20013
20100
  }
20014
20101
  var _doltPathSeam = {
20015
- homedir: () => os39.homedir(),
20102
+ homedir: () => os40.homedir(),
20016
20103
  getPath: () => process.env.PATH ?? "",
20017
20104
  setPath: (p2) => {
20018
20105
  process.env.PATH = p2;
20019
20106
  },
20020
20107
  exists: (p2) => {
20021
20108
  try {
20022
- fs49.accessSync(p2, fs49.constants.F_OK);
20109
+ fs50.accessSync(p2, fs50.constants.F_OK);
20023
20110
  return true;
20024
20111
  } catch {
20025
20112
  return false;
@@ -20030,7 +20117,7 @@ function doltBinaryNames(platform3) {
20030
20117
  return platform3 === "win32" ? ["dolt.exe", "dolt.cmd", "dolt"] : ["dolt"];
20031
20118
  }
20032
20119
  function knownDoltDirs(platform3) {
20033
- const P3 = platform3 === "win32" ? path52.win32 : path52.posix;
20120
+ const P3 = platform3 === "win32" ? path53.win32 : path53.posix;
20034
20121
  const home = _doltPathSeam.homedir();
20035
20122
  if (platform3 === "win32") {
20036
20123
  return [
@@ -20046,7 +20133,7 @@ function knownDoltDirs(platform3) {
20046
20133
  ].filter(Boolean);
20047
20134
  }
20048
20135
  function ensureDoltResolvable(platform3 = process.platform) {
20049
- const P3 = platform3 === "win32" ? path52.win32 : path52.posix;
20136
+ const P3 = platform3 === "win32" ? path53.win32 : path53.posix;
20050
20137
  const delim = platform3 === "win32" ? ";" : ":";
20051
20138
  const names = doltBinaryNames(platform3);
20052
20139
  const pathDirs = _doltPathSeam.getPath().split(delim).filter(Boolean);
@@ -20182,8 +20269,8 @@ async function ensureSharedServer(adapter, options = {}) {
20182
20269
  // src/beads/project-key.ts
20183
20270
  var import_child_process21 = require("child_process");
20184
20271
  var crypto2 = __toESM(require("crypto"));
20185
- var fs50 = __toESM(require("fs"));
20186
- var path53 = __toESM(require("path"));
20272
+ var fs51 = __toESM(require("fs"));
20273
+ var path54 = __toESM(require("path"));
20187
20274
  function normalizeOrigin(raw) {
20188
20275
  const trimmed = raw.trim();
20189
20276
  if (!trimmed) return null;
@@ -20209,17 +20296,17 @@ function normalizeOrigin(raw) {
20209
20296
  return `${host2}/${pathPart}`;
20210
20297
  }
20211
20298
  function findRepoRoot(cwd) {
20212
- let dir = path53.resolve(cwd);
20299
+ let dir = path54.resolve(cwd);
20213
20300
  const seen = /* @__PURE__ */ new Set();
20214
20301
  for (let i = 0; i < 256; i++) {
20215
20302
  if (seen.has(dir)) return null;
20216
20303
  seen.add(dir);
20217
20304
  try {
20218
- const stat3 = fs50.statSync(path53.join(dir, ".git"), { throwIfNoEntry: false });
20305
+ const stat3 = fs51.statSync(path54.join(dir, ".git"), { throwIfNoEntry: false });
20219
20306
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
20220
20307
  } catch {
20221
20308
  }
20222
- const parent = path53.dirname(dir);
20309
+ const parent = path54.dirname(dir);
20223
20310
  if (parent === dir) return null;
20224
20311
  dir = parent;
20225
20312
  }
@@ -20230,7 +20317,7 @@ var _execSeam2 = {
20230
20317
  const out2 = (0, import_child_process21.execFileSync)(file, args2, opts);
20231
20318
  return typeof out2 === "string" ? out2 : out2.toString("utf8");
20232
20319
  },
20233
- realpath: (p2) => fs50.realpathSync(p2)
20320
+ realpath: (p2) => fs51.realpathSync(p2)
20234
20321
  };
20235
20322
  function readOrigin(cwd) {
20236
20323
  try {
@@ -20259,7 +20346,7 @@ function deriveProjectIdentity(cwd = process.cwd()) {
20259
20346
  } catch {
20260
20347
  }
20261
20348
  const hash = crypto2.createHash("sha256").update(real).digest("hex");
20262
- return { projectKey: `path:${hash}`, projectLabel: path53.basename(real) || "project" };
20349
+ return { projectKey: `path:${hash}`, projectLabel: path54.basename(real) || "project" };
20263
20350
  }
20264
20351
 
20265
20352
  // src/beads/project-prefix.ts
@@ -20304,17 +20391,17 @@ var _provisionSeam = {
20304
20391
  };
20305
20392
  var _linkSeam = {
20306
20393
  platform: () => process.platform,
20307
- homedir: () => os40.homedir(),
20394
+ homedir: () => os41.homedir(),
20308
20395
  isWritableDir: (dir) => {
20309
20396
  try {
20310
- fs51.accessSync(dir, fs51.constants.W_OK);
20397
+ fs52.accessSync(dir, fs52.constants.W_OK);
20311
20398
  return true;
20312
20399
  } catch {
20313
20400
  return false;
20314
20401
  }
20315
20402
  },
20316
20403
  ensureDir: (dir) => {
20317
- fs51.mkdirSync(dir, { recursive: true });
20404
+ fs52.mkdirSync(dir, { recursive: true });
20318
20405
  },
20319
20406
  /**
20320
20407
  * A directory to symlink `bd` into so the AGENT's shell + Claude Code's
@@ -20335,9 +20422,9 @@ var _linkSeam = {
20335
20422
  * which `linkBdOntoPath` creates if missing.
20336
20423
  */
20337
20424
  cliBinDir: () => {
20338
- const pathDirs = (process.env.PATH ?? "").split(path54.delimiter).filter(Boolean);
20425
+ const pathDirs = (process.env.PATH ?? "").split(path55.delimiter).filter(Boolean);
20339
20426
  const home = _linkSeam.homedir();
20340
- const localBin = home ? path54.join(home, ".local", "bin") : null;
20427
+ const localBin = home ? path55.join(home, ".local", "bin") : null;
20341
20428
  if (localBin) {
20342
20429
  try {
20343
20430
  _linkSeam.ensureDir(localBin);
@@ -20347,16 +20434,16 @@ var _linkSeam = {
20347
20434
  const candidates = [];
20348
20435
  if (localBin) candidates.push(localBin);
20349
20436
  try {
20350
- candidates.push(path54.dirname(process.execPath));
20437
+ candidates.push(path55.dirname(process.execPath));
20351
20438
  } catch {
20352
20439
  }
20353
20440
  candidates.push("/usr/local/bin");
20354
20441
  const entry = process.argv[1];
20355
20442
  if (entry) {
20356
20443
  try {
20357
- candidates.push(path54.dirname(fs51.realpathSync(entry)));
20444
+ candidates.push(path55.dirname(fs52.realpathSync(entry)));
20358
20445
  } catch {
20359
- candidates.push(path54.dirname(entry));
20446
+ candidates.push(path55.dirname(entry));
20360
20447
  }
20361
20448
  }
20362
20449
  const onPathWritable = candidates.find(
@@ -20368,20 +20455,20 @@ var _linkSeam = {
20368
20455
  /** Current symlink target at `linkPath`, or null when absent / not a link. */
20369
20456
  readlink: (linkPath) => {
20370
20457
  try {
20371
- return fs51.readlinkSync(linkPath);
20458
+ return fs52.readlinkSync(linkPath);
20372
20459
  } catch {
20373
20460
  return null;
20374
20461
  }
20375
20462
  },
20376
- unlink: (linkPath) => fs51.unlinkSync(linkPath),
20377
- symlink: (target, linkPath) => fs51.symlinkSync(target, linkPath)
20463
+ unlink: (linkPath) => fs52.unlinkSync(linkPath),
20464
+ symlink: (target, linkPath) => fs52.symlinkSync(target, linkPath)
20378
20465
  };
20379
20466
  function linkBdOntoPath(binaryPath) {
20380
20467
  if (_linkSeam.platform() === "win32") return;
20381
20468
  const binDir = _linkSeam.cliBinDir();
20382
20469
  if (!binDir) return;
20383
20470
  _linkSeam.ensureDir(binDir);
20384
- const linkPath = path54.join(binDir, "bd");
20471
+ const linkPath = path55.join(binDir, "bd");
20385
20472
  if (linkPath === binaryPath) return;
20386
20473
  const current = _linkSeam.readlink(linkPath);
20387
20474
  if (current === binaryPath) return;
@@ -20576,7 +20663,7 @@ function dedupeRecipes(agents) {
20576
20663
 
20577
20664
  // src/beads/watcher.ts
20578
20665
  var crypto4 = __toESM(require("crypto"));
20579
- var path55 = __toESM(require("path"));
20666
+ var path56 = __toESM(require("path"));
20580
20667
  var API_BASE6 = resolveApiBaseUrl();
20581
20668
  var DEBOUNCE_MS2 = 400;
20582
20669
  var ZERO_SUMMARY = {
@@ -20600,7 +20687,7 @@ var BeadsWatcher = class {
20600
20687
  constructor(opts) {
20601
20688
  this.opts = opts;
20602
20689
  this.bd = opts.adapter ?? new BdAdapter({ cwd: opts.cwd, beadsDir: opts.beadsDir });
20603
- 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");
20604
20691
  this.apiBase = opts.apiBaseUrl ?? API_BASE6;
20605
20692
  }
20606
20693
  opts;
@@ -20851,15 +20938,15 @@ async function handleBeadsActionCommand(action, started) {
20851
20938
  }
20852
20939
 
20853
20940
  // src/beads/config-store.ts
20854
- var import_node_fs7 = __toESM(require("fs"));
20855
- var import_node_os6 = __toESM(require("os"));
20856
- 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"));
20857
20944
  function beadsConfigPath() {
20858
- 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");
20859
20946
  }
20860
20947
  function readBeadsEnabled() {
20861
20948
  try {
20862
- const raw = import_node_fs7.default.readFileSync(beadsConfigPath(), "utf8");
20949
+ const raw = import_node_fs8.default.readFileSync(beadsConfigPath(), "utf8");
20863
20950
  const cfg = JSON.parse(raw);
20864
20951
  return cfg.enabled !== false;
20865
20952
  } catch {
@@ -20868,10 +20955,10 @@ function readBeadsEnabled() {
20868
20955
  }
20869
20956
  function persistBeadsConfig(cfg) {
20870
20957
  const file = beadsConfigPath();
20871
- 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 });
20872
20959
  const tmp = `${file}.tmp`;
20873
- import_node_fs7.default.writeFileSync(tmp, JSON.stringify(cfg), { mode: 384 });
20874
- 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);
20875
20962
  restrictToOwner(file);
20876
20963
  }
20877
20964
 
@@ -21017,8 +21104,8 @@ function cleanupAttachmentTempFiles() {
21017
21104
  function saveFilesTemp(files) {
21018
21105
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
21019
21106
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
21020
- const tmpPath = path57.join(os42.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
21021
- 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"));
21022
21109
  pendingAttachmentFiles.add(tmpPath);
21023
21110
  return tmpPath;
21024
21111
  });
@@ -21230,9 +21317,9 @@ var listFiles = async (ctx, cmd, parsed) => {
21230
21317
  await ctx.relay.sendResult(cmd.id, "completed", result);
21231
21318
  };
21232
21319
  var envReadH = async (ctx, cmd) => {
21233
- const envPath = path57.join(process.cwd(), ".env");
21320
+ const envPath = path58.join(process.cwd(), ".env");
21234
21321
  try {
21235
- const raw = await fs53.promises.readFile(envPath, "utf8");
21322
+ const raw = await fs54.promises.readFile(envPath, "utf8");
21236
21323
  await ctx.relay.sendResult(cmd.id, "completed", {
21237
21324
  exists: true,
21238
21325
  vars: parseDotenv(raw)
@@ -21263,14 +21350,14 @@ var envWriteH = async (ctx, cmd, parsed) => {
21263
21350
  }
21264
21351
  seen.add(v.key);
21265
21352
  }
21266
- const envPath = path57.join(process.cwd(), ".env");
21267
- 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");
21268
21355
  try {
21269
- await fs53.promises.writeFile(tmpPath, serializeDotenv(vars), "utf8");
21270
- await fs53.promises.rename(tmpPath, envPath);
21356
+ await fs54.promises.writeFile(tmpPath, serializeDotenv(vars), "utf8");
21357
+ await fs54.promises.rename(tmpPath, envPath);
21271
21358
  await ctx.relay.sendResult(cmd.id, "completed", { ok: true, count: vars.length });
21272
21359
  } catch (err) {
21273
- await fs53.promises.rm(tmpPath, { force: true }).catch(() => void 0);
21360
+ await fs54.promises.rm(tmpPath, { force: true }).catch(() => void 0);
21274
21361
  await ctx.relay.sendResult(cmd.id, "failed", { error: err.message });
21275
21362
  }
21276
21363
  };
@@ -21314,7 +21401,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
21314
21401
  let configuredAgent = rawAgentId;
21315
21402
  if (!configuredAgent) {
21316
21403
  try {
21317
- const raw = JSON.parse(fs53.readFileSync(headroomConfigPath(), "utf8"));
21404
+ const raw = JSON.parse(fs54.readFileSync(headroomConfigPath(), "utf8"));
21318
21405
  configuredAgent = raw.agent ?? "";
21319
21406
  } catch {
21320
21407
  }
@@ -21348,7 +21435,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
21348
21435
  persist: persistHeadroomConfig,
21349
21436
  readEnabled: () => {
21350
21437
  try {
21351
- const raw = JSON.parse(fs53.readFileSync(headroomConfigPath(), "utf8"));
21438
+ const raw = JSON.parse(fs54.readFileSync(headroomConfigPath(), "utf8"));
21352
21439
  return raw.enabled === true;
21353
21440
  } catch {
21354
21441
  return false;
@@ -21595,7 +21682,7 @@ var headroomBudgetH = async (ctx, cmd) => {
21595
21682
  }
21596
21683
  let headroomActive = false;
21597
21684
  try {
21598
- const raw = JSON.parse(fs53.readFileSync(headroomConfigPath(), "utf8"));
21685
+ const raw = JSON.parse(fs54.readFileSync(headroomConfigPath(), "utf8"));
21599
21686
  headroomActive = raw.enabled === true;
21600
21687
  } catch {
21601
21688
  }
@@ -21605,7 +21692,7 @@ var headroomBudgetH = async (ctx, cmd) => {
21605
21692
  }
21606
21693
  let existingConfig = { enabled: true };
21607
21694
  try {
21608
- existingConfig = JSON.parse(fs53.readFileSync(headroomConfigPath(), "utf8"));
21695
+ existingConfig = JSON.parse(fs54.readFileSync(headroomConfigPath(), "utf8"));
21609
21696
  } catch {
21610
21697
  }
21611
21698
  if (payload.budgetEnabled && payload.budgetUsd != null) {
@@ -21718,13 +21805,13 @@ var CLI_UPDATE_MAX_ATTEMPTS = 3;
21718
21805
  function buildNpmInstallInvocation(opts) {
21719
21806
  const entryScript = opts?.entryScript ?? process.argv[1] ?? "";
21720
21807
  const execPath = opts?.execPath ?? process.execPath;
21721
- const exists2 = opts?.existsSync ?? fs53.existsSync;
21722
- const normalized = entryScript.split(path57.sep).join("/");
21808
+ const exists2 = opts?.existsSync ?? fs54.existsSync;
21809
+ const normalized = entryScript.split(path58.sep).join("/");
21723
21810
  const marker = "/lib/node_modules/codeam-cli/";
21724
21811
  const markerIdx = normalized.indexOf(marker);
21725
21812
  const prefix = markerIdx > 0 ? entryScript.slice(0, markerIdx) : null;
21726
- const siblingNpm = path57.join(
21727
- path57.dirname(execPath),
21813
+ const siblingNpm = path58.join(
21814
+ path58.dirname(execPath),
21728
21815
  process.platform === "win32" ? "npm.cmd" : "npm"
21729
21816
  );
21730
21817
  const command2 = exists2(siblingNpm) ? siblingNpm : "npm";
@@ -22591,11 +22678,11 @@ function resolveTokenValue(args2) {
22591
22678
  }
22592
22679
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
22593
22680
  if (fileFlag) {
22594
- const path72 = fileFlag.slice("--token-file=".length);
22681
+ const path73 = fileFlag.slice("--token-file=".length);
22595
22682
  try {
22596
- const content = fs54.readFileSync(path72, "utf8").trim();
22597
- if (content.length === 0) fail(`--token-file ${path72} is empty`);
22598
- rmIfExistsQuiet(path72);
22683
+ const content = fs55.readFileSync(path73, "utf8").trim();
22684
+ if (content.length === 0) fail(`--token-file ${path73} is empty`);
22685
+ rmIfExistsQuiet(path73);
22599
22686
  return content;
22600
22687
  } catch (err) {
22601
22688
  fail(`Could not read --token-file: ${err.message}`);
@@ -22624,7 +22711,7 @@ async function claimOnce(token, pluginId, pluginSecretHash) {
22624
22711
  pluginId,
22625
22712
  ideName: "codeam-cli (codespace)",
22626
22713
  ideVersion: process.env.npm_package_version ?? "unknown",
22627
- hostname: os43.hostname(),
22714
+ hostname: os44.hostname(),
22628
22715
  codespaceName: process.env.CODESPACE_NAME ?? "",
22629
22716
  // Current git branch of the codespace's working directory, so the
22630
22717
  // backend can populate `PairedSession.branch` for the codespace pair.
@@ -22685,7 +22772,7 @@ async function claim(token, pluginId, pluginSecretHash) {
22685
22772
  }
22686
22773
  }
22687
22774
  function pairAutoLockPath() {
22688
- return path58.join(os43.homedir(), ".codeam", "pair-auto.lock");
22775
+ return path59.join(os44.homedir(), ".codeam", "pair-auto.lock");
22689
22776
  }
22690
22777
  function isLivePairAuto(pid) {
22691
22778
  if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
@@ -22695,7 +22782,7 @@ function isLivePairAuto(pid) {
22695
22782
  if (e.code !== "EPERM") return false;
22696
22783
  }
22697
22784
  try {
22698
- return fs54.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
22785
+ return fs55.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
22699
22786
  } catch {
22700
22787
  return true;
22701
22788
  }
@@ -22705,24 +22792,24 @@ function isLiveCodeam(pid) {
22705
22792
  }
22706
22793
  function daemonLockPath(sessionId) {
22707
22794
  const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
22708
- return path58.join(os43.homedir(), ".codeam", `daemon-${safe}.lock`);
22795
+ return path59.join(os44.homedir(), ".codeam", `daemon-${safe}.lock`);
22709
22796
  }
22710
22797
  function acquireDaemonLock(sessionId) {
22711
22798
  const lockPath = daemonLockPath(sessionId);
22712
22799
  try {
22713
- fs54.mkdirSync(path58.dirname(lockPath), { recursive: true });
22800
+ fs55.mkdirSync(path59.dirname(lockPath), { recursive: true });
22714
22801
  try {
22715
- fs54.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
22802
+ fs55.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
22716
22803
  } catch (e) {
22717
22804
  if (e.code !== "EEXIST") throw e;
22718
- const holder = Number(fs54.readFileSync(lockPath, "utf8").trim());
22805
+ const holder = Number(fs55.readFileSync(lockPath, "utf8").trim());
22719
22806
  if (holder && holder !== process.pid && isLiveCodeam(holder)) return false;
22720
- fs54.writeFileSync(lockPath, String(process.pid));
22807
+ fs55.writeFileSync(lockPath, String(process.pid));
22721
22808
  }
22722
22809
  const release3 = () => {
22723
22810
  try {
22724
- if (fs54.existsSync(lockPath) && Number(fs54.readFileSync(lockPath, "utf8").trim()) === process.pid) {
22725
- fs54.unlinkSync(lockPath);
22811
+ if (fs55.existsSync(lockPath) && Number(fs55.readFileSync(lockPath, "utf8").trim()) === process.pid) {
22812
+ fs55.unlinkSync(lockPath);
22726
22813
  }
22727
22814
  } catch {
22728
22815
  }
@@ -22744,19 +22831,19 @@ function acquireDaemonLock(sessionId) {
22744
22831
  function acquireSingletonLock() {
22745
22832
  const lockPath = pairAutoLockPath();
22746
22833
  try {
22747
- fs54.mkdirSync(path58.dirname(lockPath), { recursive: true });
22834
+ fs55.mkdirSync(path59.dirname(lockPath), { recursive: true });
22748
22835
  try {
22749
- fs54.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
22836
+ fs55.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
22750
22837
  } catch (e) {
22751
22838
  if (e.code !== "EEXIST") throw e;
22752
- const holder = Number(fs54.readFileSync(lockPath, "utf8").trim());
22839
+ const holder = Number(fs55.readFileSync(lockPath, "utf8").trim());
22753
22840
  if (isLivePairAuto(holder)) return false;
22754
- fs54.writeFileSync(lockPath, String(process.pid));
22841
+ fs55.writeFileSync(lockPath, String(process.pid));
22755
22842
  }
22756
22843
  process.once("exit", () => {
22757
22844
  try {
22758
- if (fs54.existsSync(lockPath) && Number(fs54.readFileSync(lockPath, "utf8").trim()) === process.pid) {
22759
- fs54.unlinkSync(lockPath);
22845
+ if (fs55.existsSync(lockPath) && Number(fs55.readFileSync(lockPath, "utf8").trim()) === process.pid) {
22846
+ fs55.unlinkSync(lockPath);
22760
22847
  }
22761
22848
  } catch {
22762
22849
  }
@@ -23202,7 +23289,7 @@ var AgentService = class _AgentService {
23202
23289
  };
23203
23290
 
23204
23291
  // src/agents/acp/adapters.ts
23205
- var path60 = __toESM(require("path"));
23292
+ var path61 = __toESM(require("path"));
23206
23293
 
23207
23294
  // src/agents/acp/agent-binary.ts
23208
23295
  var import_fs4 = __toESM(require("fs"));
@@ -23378,11 +23465,11 @@ async function waitForAdapterModuleGraph(command2, args2, opts = {}) {
23378
23465
 
23379
23466
  // src/agents/kimi/installer.ts
23380
23467
  var import_node_child_process25 = require("child_process");
23381
- var import_node_os7 = require("os");
23382
- var import_node_path6 = require("path");
23468
+ var import_node_os8 = require("os");
23469
+ var import_node_path7 = require("path");
23383
23470
  var INSTALL_URL2 = "https://code.kimi.com/kimi-code/install.sh";
23384
23471
  function kimiBinDir() {
23385
- 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");
23386
23473
  }
23387
23474
  function kimiRuns() {
23388
23475
  const r = (0, import_node_child_process25.spawnSync)("kimi", ["--version"], { stdio: "ignore", timeout: 15e3 });
@@ -23445,13 +23532,13 @@ function resolveBin(pkgName, binName) {
23445
23532
  try {
23446
23533
  const manifestPath = require_.resolve(`${pkgName}/package.json`);
23447
23534
  const manifest = require_(`${pkgName}/package.json`);
23448
- const pkgDir = path60.dirname(manifestPath);
23535
+ const pkgDir = path61.dirname(manifestPath);
23449
23536
  const bin = manifest.bin;
23450
23537
  if (!bin) return null;
23451
- if (typeof bin === "string") return path60.resolve(pkgDir, bin);
23538
+ if (typeof bin === "string") return path61.resolve(pkgDir, bin);
23452
23539
  const target = binName ?? Object.keys(bin)[0];
23453
23540
  if (!target || !bin[target]) return null;
23454
- return path60.resolve(pkgDir, bin[target]);
23541
+ return path61.resolve(pkgDir, bin[target]);
23455
23542
  } catch {
23456
23543
  return null;
23457
23544
  }
@@ -23555,9 +23642,9 @@ function requiresAcp(agent) {
23555
23642
  var import_node_crypto10 = require("crypto");
23556
23643
 
23557
23644
  // src/services/history.service.ts
23558
- var fs56 = __toESM(require("fs"));
23559
- var path61 = __toESM(require("path"));
23560
- var os45 = __toESM(require("os"));
23645
+ var fs57 = __toESM(require("fs"));
23646
+ var path62 = __toESM(require("path"));
23647
+ var os46 = __toESM(require("os"));
23561
23648
  var https7 = __toESM(require("https"));
23562
23649
  var http6 = __toESM(require("http"));
23563
23650
  var import_zod2 = require("zod");
@@ -23584,7 +23671,7 @@ function parseJsonl(filePath) {
23584
23671
  const messages = [];
23585
23672
  let raw;
23586
23673
  try {
23587
- raw = fs56.readFileSync(filePath, "utf8");
23674
+ raw = fs57.readFileSync(filePath, "utf8");
23588
23675
  } catch (err) {
23589
23676
  if (err.code !== "ENOENT") {
23590
23677
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -23725,7 +23812,7 @@ var HistoryService = class _HistoryService {
23725
23812
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
23726
23813
  }
23727
23814
  get projectDir() {
23728
- 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));
23729
23816
  }
23730
23817
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
23731
23818
  setCurrentConversationId(id) {
@@ -23737,7 +23824,7 @@ var HistoryService = class _HistoryService {
23737
23824
  /** Return the current message count in the active conversation. */
23738
23825
  getCurrentMessageCount() {
23739
23826
  if (!this.currentConversationId) return 0;
23740
- const filePath = path61.join(this.projectDir, `${this.currentConversationId}.jsonl`);
23827
+ const filePath = path62.join(this.projectDir, `${this.currentConversationId}.jsonl`);
23741
23828
  return parseJsonl(filePath).length;
23742
23829
  }
23743
23830
  /**
@@ -23748,7 +23835,7 @@ var HistoryService = class _HistoryService {
23748
23835
  const deadline = Date.now() + timeoutMs;
23749
23836
  while (Date.now() < deadline) {
23750
23837
  if (!this.currentConversationId) return null;
23751
- const filePath = path61.join(this.projectDir, `${this.currentConversationId}.jsonl`);
23838
+ const filePath = path62.join(this.projectDir, `${this.currentConversationId}.jsonl`);
23752
23839
  const messages = parseJsonl(filePath);
23753
23840
  if (messages.length > previousCount) {
23754
23841
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -23774,16 +23861,16 @@ var HistoryService = class _HistoryService {
23774
23861
  const dir = this.projectDir;
23775
23862
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
23776
23863
  try {
23777
- 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) => {
23778
23865
  try {
23779
- const stat3 = fs56.statSync(path61.join(dir, e.name));
23866
+ const stat3 = fs57.statSync(path62.join(dir, e.name));
23780
23867
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
23781
23868
  } catch {
23782
23869
  return { name: e.name, mtime: 0, birthtime: 0 };
23783
23870
  }
23784
23871
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
23785
23872
  if (files.length > 0) {
23786
- this.currentConversationId = path61.basename(files[0].name, ".jsonl");
23873
+ this.currentConversationId = path62.basename(files[0].name, ".jsonl");
23787
23874
  }
23788
23875
  } catch {
23789
23876
  }
@@ -23817,13 +23904,13 @@ var HistoryService = class _HistoryService {
23817
23904
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
23818
23905
  let entries;
23819
23906
  try {
23820
- entries = fs56.readdirSync(dir, { withFileTypes: true });
23907
+ entries = fs57.readdirSync(dir, { withFileTypes: true });
23821
23908
  } catch {
23822
23909
  return null;
23823
23910
  }
23824
23911
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
23825
23912
  try {
23826
- const stat3 = fs56.statSync(path61.join(dir, e.name));
23913
+ const stat3 = fs57.statSync(path62.join(dir, e.name));
23827
23914
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
23828
23915
  } catch {
23829
23916
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -23832,12 +23919,12 @@ var HistoryService = class _HistoryService {
23832
23919
  if (files.length === 0) return null;
23833
23920
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
23834
23921
  if (!files.some((f) => f.name === targetFile)) return null;
23835
- return this.extractUsageFromFile(path61.join(dir, targetFile));
23922
+ return this.extractUsageFromFile(path62.join(dir, targetFile));
23836
23923
  }
23837
23924
  extractUsageFromFile(filePath) {
23838
23925
  let raw;
23839
23926
  try {
23840
- raw = fs56.readFileSync(filePath, "utf8");
23927
+ raw = fs57.readFileSync(filePath, "utf8");
23841
23928
  } catch {
23842
23929
  return null;
23843
23930
  }
@@ -23882,9 +23969,9 @@ var HistoryService = class _HistoryService {
23882
23969
  let totalCost = 0;
23883
23970
  let files;
23884
23971
  try {
23885
- files = fs56.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
23972
+ files = fs57.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
23886
23973
  try {
23887
- return fs56.statSync(path61.join(projectDir, f)).mtimeMs >= monthStartMs;
23974
+ return fs57.statSync(path62.join(projectDir, f)).mtimeMs >= monthStartMs;
23888
23975
  } catch {
23889
23976
  return false;
23890
23977
  }
@@ -23895,7 +23982,7 @@ var HistoryService = class _HistoryService {
23895
23982
  for (const file of files) {
23896
23983
  let raw;
23897
23984
  try {
23898
- raw = fs56.readFileSync(path61.join(projectDir, file), "utf8");
23985
+ raw = fs57.readFileSync(path62.join(projectDir, file), "utf8");
23899
23986
  } catch {
23900
23987
  continue;
23901
23988
  }
@@ -23974,7 +24061,7 @@ var HistoryService = class _HistoryService {
23974
24061
  if (this.runtime.resolveHistoryFile) {
23975
24062
  return this.runtime.resolveHistoryFile(this.cwd, sessionId);
23976
24063
  }
23977
- return path61.join(this.projectDir, `${sessionId}.jsonl`);
24064
+ return path62.join(this.projectDir, `${sessionId}.jsonl`);
23978
24065
  }
23979
24066
  /**
23980
24067
  * Parse a conversation's messages from disk, agent-aware. Claude uses the
@@ -24008,7 +24095,7 @@ var HistoryService = class _HistoryService {
24008
24095
  };
24009
24096
  });
24010
24097
  }
24011
- return parseJsonl(path61.join(this.projectDir, `${sessionId}.jsonl`));
24098
+ return parseJsonl(path62.join(this.projectDir, `${sessionId}.jsonl`));
24012
24099
  }
24013
24100
  async loadConversation(sessionId) {
24014
24101
  const messages = this.readConversation(sessionId);
@@ -24064,7 +24151,7 @@ var HistoryService = class _HistoryService {
24064
24151
  if (!filePath) return false;
24065
24152
  let mtimeMs;
24066
24153
  try {
24067
- mtimeMs = fs56.statSync(filePath).mtimeMs;
24154
+ mtimeMs = fs57.statSync(filePath).mtimeMs;
24068
24155
  } catch {
24069
24156
  return false;
24070
24157
  }
@@ -24133,10 +24220,10 @@ var HistoryService = class _HistoryService {
24133
24220
 
24134
24221
  // src/agents/acp/client.ts
24135
24222
  var import_node_child_process26 = require("child_process");
24136
- var fs57 = __toESM(require("fs/promises"));
24223
+ var fs58 = __toESM(require("fs/promises"));
24137
24224
  var fsSync = __toESM(require("fs"));
24138
- var os46 = __toESM(require("os"));
24139
- var path62 = __toESM(require("path"));
24225
+ var os47 = __toESM(require("os"));
24226
+ var path63 = __toESM(require("path"));
24140
24227
  var import_node_stream = require("stream");
24141
24228
 
24142
24229
  // ../../node_modules/@agentclientprotocol/sdk/dist/acp.js
@@ -26860,7 +26947,7 @@ var AcpClient = class {
26860
26947
  let newSession;
26861
26948
  try {
26862
26949
  newSession = await Promise.race([
26863
- this.connection.newSession({ cwd, mcpServers: [] }),
26950
+ this.connection.newSession({ cwd, mcpServers: this.opts.mcpServers ?? [] }),
26864
26951
  startupFailure,
26865
26952
  startAborted
26866
26953
  ]);
@@ -26999,7 +27086,7 @@ var AcpClient = class {
26999
27086
  await this.connection.loadSession({
27000
27087
  sessionId,
27001
27088
  cwd: this.opts.cwd,
27002
- mcpServers: []
27089
+ mcpServers: this.opts.mcpServers ?? []
27003
27090
  });
27004
27091
  this.sessionId = sessionId;
27005
27092
  log.info("acpClient", `loadSession \u2190 ok sessionId=${sessionId.slice(0, 8)}`);
@@ -27114,7 +27201,7 @@ var AcpClient = class {
27114
27201
  },
27115
27202
  readTextFile: async (params) => {
27116
27203
  try {
27117
- const content = await fs57.readFile(params.path, "utf8");
27204
+ const content = await fs58.readFile(params.path, "utf8");
27118
27205
  return applyLineRange(content, params.line ?? null, params.limit ?? null);
27119
27206
  } catch (err) {
27120
27207
  const code = err.code;
@@ -27134,7 +27221,7 @@ var AcpClient = class {
27134
27221
  },
27135
27222
  writeTextFile: async (params) => {
27136
27223
  try {
27137
- await fs57.writeFile(params.path, params.content, "utf8");
27224
+ await fs58.writeFile(params.path, params.content, "utf8");
27138
27225
  return {};
27139
27226
  } catch (err) {
27140
27227
  const code = err.code;
@@ -27183,29 +27270,29 @@ function applyLineRange(content, line, limit) {
27183
27270
  return { content: lines.slice(start2, end).join("\n") };
27184
27271
  }
27185
27272
  function knownAgentBinaryDirs() {
27186
- const home = os46.homedir();
27273
+ const home = os47.homedir();
27187
27274
  const out2 = [];
27188
27275
  out2.push("/tmp/codeam-node20/bin");
27189
27276
  for (const root of [
27190
27277
  "/usr/local/share/nvm/versions/node",
27191
- path62.join(home, ".nvm/versions/node")
27278
+ path63.join(home, ".nvm/versions/node")
27192
27279
  ]) {
27193
27280
  try {
27194
27281
  for (const child of fsSync.readdirSync(root)) {
27195
- out2.push(path62.join(root, child, "bin"));
27282
+ out2.push(path63.join(root, child, "bin"));
27196
27283
  }
27197
27284
  } catch {
27198
27285
  }
27199
27286
  }
27200
- out2.push(path62.join(home, ".volta/bin"));
27287
+ out2.push(path63.join(home, ".volta/bin"));
27201
27288
  out2.push("/usr/local/bin");
27202
27289
  out2.push("/usr/bin");
27203
- out2.push(path62.join(home, ".local/bin"));
27204
- out2.push(path62.join(home, "bin"));
27290
+ out2.push(path63.join(home, ".local/bin"));
27291
+ out2.push(path63.join(home, "bin"));
27205
27292
  if (process.platform === "win32") {
27206
27293
  const { LOCALAPPDATA, APPDATA } = process.env;
27207
- if (LOCALAPPDATA) out2.push(path62.join(LOCALAPPDATA, "cursor-agent"));
27208
- 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"));
27209
27296
  }
27210
27297
  return out2.filter((p2) => {
27211
27298
  try {
@@ -27217,7 +27304,7 @@ function knownAgentBinaryDirs() {
27217
27304
  }
27218
27305
  function expandPathForAgentBinaries(existingPath) {
27219
27306
  const existing = new Set(
27220
- existingPath.split(path62.delimiter).filter((p2) => p2.length > 0)
27307
+ existingPath.split(path63.delimiter).filter((p2) => p2.length > 0)
27221
27308
  );
27222
27309
  const additions = [];
27223
27310
  for (const dir of knownAgentBinaryDirs()) {
@@ -27227,7 +27314,7 @@ function expandPathForAgentBinaries(existingPath) {
27227
27314
  }
27228
27315
  }
27229
27316
  if (additions.length === 0) return existingPath;
27230
- return [...additions, existingPath].filter((p2) => p2.length > 0).join(path62.delimiter);
27317
+ return [...additions, existingPath].filter((p2) => p2.length > 0).join(path63.delimiter);
27231
27318
  }
27232
27319
 
27233
27320
  // src/agents/acp/headroom-budget-proxy.ts
@@ -27709,15 +27796,15 @@ function commonPrefixLength(a, b) {
27709
27796
 
27710
27797
  // src/agents/acp/onboarding.ts
27711
27798
  var import_child_process26 = require("child_process");
27712
- var fs58 = __toESM(require("fs"));
27713
- var os47 = __toESM(require("os"));
27714
- var path63 = __toESM(require("path"));
27799
+ var fs59 = __toESM(require("fs"));
27800
+ var os48 = __toESM(require("os"));
27801
+ var path64 = __toESM(require("path"));
27715
27802
  var _onboardingSeam = {
27716
- markerPath: (sessionId) => path63.join(os47.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
27717
- exists: (p2) => fs58.existsSync(p2),
27803
+ markerPath: (sessionId) => path64.join(os48.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
27804
+ exists: (p2) => fs59.existsSync(p2),
27718
27805
  write: (p2) => {
27719
- fs58.mkdirSync(path63.dirname(p2), { recursive: true });
27720
- fs58.writeFileSync(p2, "");
27806
+ fs59.mkdirSync(path64.dirname(p2), { recursive: true });
27807
+ fs59.writeFileSync(p2, "");
27721
27808
  },
27722
27809
  disabled: () => {
27723
27810
  const v = process.env.CODEAM_ONBOARDING_DISABLED;
@@ -27754,7 +27841,7 @@ function resolveRepoName(cwd) {
27754
27841
  if (name) return name;
27755
27842
  }
27756
27843
  }
27757
- const base = path63.basename(cwd || "");
27844
+ const base = path64.basename(cwd || "");
27758
27845
  if (base && !isUuid(base)) return base;
27759
27846
  return "this project";
27760
27847
  }
@@ -28006,8 +28093,8 @@ var import_crypto5 = require("crypto");
28006
28093
 
28007
28094
  // src/services/turn-files/git-changeset.ts
28008
28095
  var import_child_process27 = require("child_process");
28009
- var fs59 = __toESM(require("fs/promises"));
28010
- var path64 = __toESM(require("path"));
28096
+ var fs60 = __toESM(require("fs/promises"));
28097
+ var path65 = __toESM(require("path"));
28011
28098
  async function collectRepoChangeset(opts) {
28012
28099
  const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
28013
28100
  if (status2 === null) return null;
@@ -28025,7 +28112,7 @@ async function collectRepoChangeset(opts) {
28025
28112
  let stats;
28026
28113
  if (row.fileStatus === "added" && numstatEntry === void 0) {
28027
28114
  const lineCount = await readUntrackedLineCount(
28028
- path64.join(opts.repoRoot, row.filePath)
28115
+ path65.join(opts.repoRoot, row.filePath)
28029
28116
  );
28030
28117
  stats = { added: lineCount, removed: 0 };
28031
28118
  } else {
@@ -28056,7 +28143,7 @@ function readUntrackedLineCount(absPath) {
28056
28143
  }
28057
28144
  async function defaultReadUntrackedLineCount(absPath) {
28058
28145
  try {
28059
- const content = await fs59.readFile(absPath, "utf8");
28146
+ const content = await fs60.readFile(absPath, "utf8");
28060
28147
  let count = 0;
28061
28148
  let pos = -1;
28062
28149
  while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
@@ -28148,7 +28235,7 @@ function defaultRunGit(cwd, args2) {
28148
28235
  });
28149
28236
  }
28150
28237
  async function discoverRepos(workingDir, maxDepth = 4) {
28151
- const fs64 = await import("fs/promises");
28238
+ const fs65 = await import("fs/promises");
28152
28239
  const out2 = [];
28153
28240
  await walk(workingDir, 0);
28154
28241
  return out2;
@@ -28156,7 +28243,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
28156
28243
  if (depth > maxDepth) return;
28157
28244
  let entries = [];
28158
28245
  try {
28159
- const dirents = await fs64.readdir(dir, { withFileTypes: true });
28246
+ const dirents = await fs65.readdir(dir, { withFileTypes: true });
28160
28247
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
28161
28248
  } catch {
28162
28249
  return;
@@ -28167,8 +28254,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
28167
28254
  if (hasGit) {
28168
28255
  out2.push({
28169
28256
  repoRoot: dir,
28170
- repoPath: path64.relative(workingDir, dir),
28171
- repoName: path64.basename(dir)
28257
+ repoPath: path65.relative(workingDir, dir),
28258
+ repoName: path65.basename(dir)
28172
28259
  });
28173
28260
  return;
28174
28261
  }
@@ -28176,14 +28263,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
28176
28263
  if (!entry.isDirectory) continue;
28177
28264
  if (entry.name === "node_modules") continue;
28178
28265
  if (entry.name === "dist" || entry.name === "build") continue;
28179
- await walk(path64.join(dir, entry.name), depth + 1);
28266
+ await walk(path65.join(dir, entry.name), depth + 1);
28180
28267
  }
28181
28268
  }
28182
28269
  }
28183
28270
 
28184
28271
  // src/services/turn-files/files-outbox.ts
28185
- var fs60 = __toESM(require("fs/promises"));
28186
- var path65 = __toESM(require("path"));
28272
+ var fs61 = __toESM(require("fs/promises"));
28273
+ var path66 = __toESM(require("path"));
28187
28274
  var import_os11 = require("os");
28188
28275
  var HOME_OUTBOX_DIR = ".codeam/outbox";
28189
28276
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -28216,16 +28303,16 @@ var FilesOutbox = class {
28216
28303
  backoffIndex = 0;
28217
28304
  stopped = false;
28218
28305
  constructor(opts) {
28219
- const base = opts.baseDir ?? path65.join(homeDir(), HOME_OUTBOX_DIR);
28220
- 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`);
28221
28308
  this.post = opts.post;
28222
28309
  this.autoSchedule = opts.autoSchedule !== false;
28223
28310
  }
28224
28311
  /** Persist the entry to disk and trigger a flush. Returns once the
28225
28312
  * line is durable on disk (not once the POST succeeds). */
28226
28313
  async enqueue(entry) {
28227
- await fs60.mkdir(path65.dirname(this.filePath), { recursive: true });
28228
- 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");
28229
28316
  this.backoffIndex = 0;
28230
28317
  if (this.autoSchedule) this.scheduleFlush(0);
28231
28318
  }
@@ -28316,7 +28403,7 @@ var FilesOutbox = class {
28316
28403
  async readAll() {
28317
28404
  let raw = "";
28318
28405
  try {
28319
- raw = await fs60.readFile(this.filePath, "utf8");
28406
+ raw = await fs61.readFile(this.filePath, "utf8");
28320
28407
  } catch {
28321
28408
  return [];
28322
28409
  }
@@ -28340,12 +28427,12 @@ var FilesOutbox = class {
28340
28427
  async rewrite(entries) {
28341
28428
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
28342
28429
  if (entries.length === 0) {
28343
- await fs60.unlink(this.filePath).catch(() => void 0);
28430
+ await fs61.unlink(this.filePath).catch(() => void 0);
28344
28431
  return;
28345
28432
  }
28346
28433
  const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
28347
- await fs60.writeFile(tmpPath, payload, "utf8");
28348
- await fs60.rename(tmpPath, this.filePath);
28434
+ await fs61.writeFile(tmpPath, payload, "utf8");
28435
+ await fs61.rename(tmpPath, this.filePath);
28349
28436
  }
28350
28437
  };
28351
28438
  function applyJitter(ms) {
@@ -29843,6 +29930,7 @@ async function runAcpSession(opts) {
29843
29930
  adapter: opts.adapter,
29844
29931
  cwd: opts.cwd,
29845
29932
  extraEnv,
29933
+ mcpServers: opts.mcpServers,
29846
29934
  onSessionUpdate: (notification) => {
29847
29935
  updateCount += 1;
29848
29936
  const variant = notification.update?.sessionUpdate ?? "unknown";
@@ -31101,6 +31189,43 @@ function fetchQuotaUsage(runtime, historySvc) {
31101
31189
  });
31102
31190
  }
31103
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
+
31104
31229
  // src/baton/baton-controller.ts
31105
31230
  var BatonController = class {
31106
31231
  constructor(deps) {
@@ -31450,7 +31575,7 @@ var AcpDriver = class {
31450
31575
  };
31451
31576
 
31452
31577
  // src/baton/transcript-mirror.ts
31453
- var fs61 = __toESM(require("fs"));
31578
+ var fs62 = __toESM(require("fs"));
31454
31579
  var TranscriptMirror = class {
31455
31580
  constructor(deps) {
31456
31581
  this.deps = deps;
@@ -31517,7 +31642,7 @@ var TranscriptMirror = class {
31517
31642
  }
31518
31643
  };
31519
31644
  function defaultWatch(file, onChange) {
31520
- const w3 = fs61.watch(file, { persistent: false }, () => onChange());
31645
+ const w3 = fs62.watch(file, { persistent: false }, () => onChange());
31521
31646
  return () => w3.close();
31522
31647
  }
31523
31648
 
@@ -31617,6 +31742,7 @@ async function runBatonSession(opts) {
31617
31742
  const client2 = new AcpClient({
31618
31743
  adapter: opts.adapter,
31619
31744
  cwd: opts.cwd,
31745
+ mcpServers: opts.mcpServers,
31620
31746
  onSessionUpdate: (notification) => {
31621
31747
  for (const delta of mapSessionUpdate(notification)) streaming.append(delta);
31622
31748
  },
@@ -31647,7 +31773,8 @@ async function runBatonSession(opts) {
31647
31773
  adapter: opts.adapter,
31648
31774
  cwd: opts.cwd,
31649
31775
  getBeads: opts.getBeads,
31650
- pollSecret: opts.pollSecret
31776
+ pollSecret: opts.pollSecret,
31777
+ mcpServers: opts.mcpServers
31651
31778
  };
31652
31779
  const mobileDriver = new AcpDriver({
31653
31780
  client: client2,
@@ -31769,15 +31896,15 @@ function toEpochMs(ts) {
31769
31896
  }
31770
31897
 
31771
31898
  // src/agents/claude/onboarding.ts
31772
- var fs62 = __toESM(require("fs"));
31773
- var os48 = __toESM(require("os"));
31774
- var path66 = __toESM(require("path"));
31899
+ var fs63 = __toESM(require("fs"));
31900
+ var os49 = __toESM(require("os"));
31901
+ var path67 = __toESM(require("path"));
31775
31902
  function ensureClaudeOnboarded(cwd) {
31776
31903
  try {
31777
- const file = path66.join(os48.homedir(), ".claude.json");
31904
+ const file = path67.join(os49.homedir(), ".claude.json");
31778
31905
  let config = {};
31779
31906
  try {
31780
- config = JSON.parse(fs62.readFileSync(file, "utf8"));
31907
+ config = JSON.parse(fs63.readFileSync(file, "utf8"));
31781
31908
  } catch {
31782
31909
  }
31783
31910
  let changed = false;
@@ -31801,8 +31928,8 @@ function ensureClaudeOnboarded(cwd) {
31801
31928
  }
31802
31929
  }
31803
31930
  if (!changed) return;
31804
- fs62.mkdirSync(path66.dirname(file), { recursive: true });
31805
- 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));
31806
31933
  log.info(
31807
31934
  "claude",
31808
31935
  `pre-completed Claude onboarding${cwd ? ` + trusted workspace ${cwd}` : ""}`
@@ -31907,6 +32034,12 @@ async function start(requestedAgent) {
31907
32034
  beads = started;
31908
32035
  return started;
31909
32036
  });
32037
+ const mcpServers = buildMcpServersForStart({
32038
+ sessionId: session.id,
32039
+ pluginId,
32040
+ pluginAuthToken: session.pluginAuthToken ?? void 0,
32041
+ pollSecret: session.pollSecret
32042
+ });
31910
32043
  const depsReady = process.env.CODESPACES === "true" ? provisionProjectDependencies(cwd).catch(() => void 0) : Promise.resolve();
31911
32044
  if (process.env.CODESPACES === "true") {
31912
32045
  const GATE_TIMEOUT_MS = 24e4;
@@ -31942,7 +32075,8 @@ async function start(requestedAgent) {
31942
32075
  pollSecret: session.pollSecret,
31943
32076
  cwd,
31944
32077
  adapter,
31945
- getBeads
32078
+ getBeads,
32079
+ mcpServers
31946
32080
  });
31947
32081
  return;
31948
32082
  }
@@ -31964,6 +32098,7 @@ async function start(requestedAgent) {
31964
32098
  cwd,
31965
32099
  getBeads,
31966
32100
  pollSecret: session.pollSecret,
32101
+ mcpServers,
31967
32102
  // AUTO mode for headless, mobile-driven sessions: no human at the box
31968
32103
  // to answer permission prompts, so auto-approve them rather than stall
31969
32104
  // the turn (the agent-agnostic equivalent of
@@ -32480,7 +32615,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
32480
32615
  var import_child_process28 = require("child_process");
32481
32616
  var import_util4 = require("util");
32482
32617
  var import_picocolors9 = __toESM(require("picocolors"));
32483
- var path67 = __toESM(require("path"));
32618
+ var path68 = __toESM(require("path"));
32484
32619
  var execFileP6 = (0, import_util4.promisify)(import_child_process28.execFile);
32485
32620
  var MAX_BUFFER = 8 * 1024 * 1024;
32486
32621
  function resetStdinForChild() {
@@ -32969,7 +33104,7 @@ var GitHubCodespacesProvider = class {
32969
33104
  });
32970
33105
  }
32971
33106
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
32972
- const remoteDir = path67.posix.dirname(remotePath);
33107
+ const remoteDir = path68.posix.dirname(remotePath);
32973
33108
  const parts = [
32974
33109
  `mkdir -p ${shellQuote(remoteDir)}`,
32975
33110
  `cat > ${shellQuote(remotePath)}`
@@ -33039,7 +33174,7 @@ function shellQuote(s) {
33039
33174
  // src/services/providers/gitpod.ts
33040
33175
  var import_child_process29 = require("child_process");
33041
33176
  var import_util5 = require("util");
33042
- var path68 = __toESM(require("path"));
33177
+ var path69 = __toESM(require("path"));
33043
33178
  var import_picocolors10 = __toESM(require("picocolors"));
33044
33179
  var execFileP7 = (0, import_util5.promisify)(import_child_process29.execFile);
33045
33180
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -33279,7 +33414,7 @@ var GitpodProvider = class {
33279
33414
  });
33280
33415
  }
33281
33416
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
33282
- const remoteDir = path68.posix.dirname(remotePath);
33417
+ const remoteDir = path69.posix.dirname(remotePath);
33283
33418
  const parts = [
33284
33419
  `mkdir -p ${shellQuote2(remoteDir)}`,
33285
33420
  `cat > ${shellQuote2(remotePath)}`
@@ -33315,7 +33450,7 @@ function shellQuote2(s) {
33315
33450
  // src/services/providers/gitlab-workspaces.ts
33316
33451
  var import_child_process30 = require("child_process");
33317
33452
  var import_util6 = require("util");
33318
- var path69 = __toESM(require("path"));
33453
+ var path70 = __toESM(require("path"));
33319
33454
  var execFileP8 = (0, import_util6.promisify)(import_child_process30.execFile);
33320
33455
  var MAX_BUFFER3 = 8 * 1024 * 1024;
33321
33456
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -33575,7 +33710,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
33575
33710
  }
33576
33711
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
33577
33712
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
33578
- const remoteDir = path69.posix.dirname(remotePath);
33713
+ const remoteDir = path70.posix.dirname(remotePath);
33579
33714
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
33580
33715
  if (options.mode != null) {
33581
33716
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -33643,7 +33778,7 @@ function shellQuote3(s) {
33643
33778
  // src/services/providers/railway.ts
33644
33779
  var import_child_process31 = require("child_process");
33645
33780
  var import_util7 = require("util");
33646
- var path70 = __toESM(require("path"));
33781
+ var path71 = __toESM(require("path"));
33647
33782
  var execFileP9 = (0, import_util7.promisify)(import_child_process31.execFile);
33648
33783
  var MAX_BUFFER4 = 8 * 1024 * 1024;
33649
33784
  function resetStdinForChild4() {
@@ -33879,7 +34014,7 @@ var RailwayProvider = class {
33879
34014
  if (!projectId || !serviceId) {
33880
34015
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
33881
34016
  }
33882
- const remoteDir = path70.posix.dirname(remotePath);
34017
+ const remoteDir = path71.posix.dirname(remotePath);
33883
34018
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
33884
34019
  if (options.mode != null) {
33885
34020
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -34525,8 +34660,8 @@ async function invite() {
34525
34660
  var import_node_dns = require("dns");
34526
34661
  var import_node_util5 = require("util");
34527
34662
  var import_node_crypto12 = require("crypto");
34528
- var fs63 = __toESM(require("fs"));
34529
- var path71 = __toESM(require("path"));
34663
+ var fs64 = __toESM(require("fs"));
34664
+ var path72 = __toESM(require("path"));
34530
34665
  var import_picocolors14 = __toESM(require("picocolors"));
34531
34666
  var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
34532
34667
  async function checkDns(apiBase2) {
@@ -34582,13 +34717,13 @@ async function checkHealth(apiBase2) {
34582
34717
  }
34583
34718
  }
34584
34719
  function checkConfigDir() {
34585
- const dir = path71.join(require("os").homedir(), ".codeam");
34720
+ const dir = path72.join(require("os").homedir(), ".codeam");
34586
34721
  try {
34587
- fs63.mkdirSync(dir, { recursive: true, mode: 448 });
34588
- const probe = path71.join(dir, ".doctor-probe");
34589
- fs63.writeFileSync(probe, "ok", { mode: 384 });
34590
- const read2 = fs63.readFileSync(probe, "utf8");
34591
- 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);
34592
34727
  if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
34593
34728
  return {
34594
34729
  id: "config-dir",
@@ -34628,9 +34763,9 @@ function checkSessions() {
34628
34763
  }
34629
34764
  }
34630
34765
  function checkAgentBinaries() {
34631
- const os50 = createOsStrategy();
34766
+ const os51 = createOsStrategy();
34632
34767
  return getEnabledAgents().map((meta) => {
34633
- const found = os50.findInPath(meta.binaryName);
34768
+ const found = os51.findInPath(meta.binaryName);
34634
34769
  return {
34635
34770
  id: `agent-${meta.id}`,
34636
34771
  label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
@@ -34652,7 +34787,7 @@ function checkNodePty() {
34652
34787
  detail: "not required on this platform"
34653
34788
  };
34654
34789
  }
34655
- const vendoredPath = path71.join(__dirname, "vendor", "node-pty");
34790
+ const vendoredPath = path72.join(__dirname, "vendor", "node-pty");
34656
34791
  for (const target of [vendoredPath, "node-pty"]) {
34657
34792
  try {
34658
34793
  require(target);
@@ -34694,7 +34829,7 @@ function checkChokidar() {
34694
34829
  }
34695
34830
  async function doctor(args2 = []) {
34696
34831
  const json = args2.includes("--json");
34697
- const cliVersion = true ? "2.60.46" : "0.0.0-dev";
34832
+ const cliVersion = true ? "2.60.48" : "0.0.0-dev";
34698
34833
  const apiBase2 = resolveApiBaseUrl();
34699
34834
  const diagnosticId = (0, import_node_crypto12.randomUUID)();
34700
34835
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -34890,10 +35025,288 @@ async function completion(args2) {
34890
35025
  process.stdout.write(script);
34891
35026
  }
34892
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
+
34893
35306
  // src/commands/version.ts
34894
35307
  var import_picocolors15 = __toESM(require("picocolors"));
34895
35308
  function version2() {
34896
- const v = true ? "2.60.46" : "unknown";
35309
+ const v = true ? "2.60.48" : "unknown";
34897
35310
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
34898
35311
  }
34899
35312
 
@@ -35042,10 +35455,10 @@ var EXIT_CODE_NAMES = {
35042
35455
  };
35043
35456
 
35044
35457
  // src/index.ts
35045
- var os49 = __toESM(require("os"));
35458
+ var os50 = __toESM(require("os"));
35046
35459
  if (!process.env.HOME) {
35047
35460
  try {
35048
- const home = os49.homedir();
35461
+ const home = os50.homedir();
35049
35462
  if (home) process.env.HOME = home;
35050
35463
  } catch {
35051
35464
  }
@@ -35091,6 +35504,9 @@ async function main() {
35091
35504
  await commands[command]();
35092
35505
  return;
35093
35506
  }
35507
+ if (command === "mcp-run") {
35508
+ return mcpRun(args);
35509
+ }
35094
35510
  if (command === "deploy") {
35095
35511
  if (args[0] === "ls" || args[0] === "list") return deployList();
35096
35512
  if (args[0] === "stop" || args[0] === "remove") return deployStop();