@buildautomaton/cli 0.1.68 → 0.1.70

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.
package/dist/index.js CHANGED
@@ -4208,8 +4208,8 @@ var init_parseUtil = __esm({
4208
4208
  init_errors();
4209
4209
  init_en();
4210
4210
  makeIssue = (params) => {
4211
- const { data, path: path80, errorMaps, issueData } = params;
4212
- const fullPath = [...path80, ...issueData.path || []];
4211
+ const { data, path: path82, errorMaps, issueData } = params;
4212
+ const fullPath = [...path82, ...issueData.path || []];
4213
4213
  const fullIssue = {
4214
4214
  ...issueData,
4215
4215
  path: fullPath
@@ -4517,11 +4517,11 @@ var init_types = __esm({
4517
4517
  init_parseUtil();
4518
4518
  init_util();
4519
4519
  ParseInputLazyPath = class {
4520
- constructor(parent, value, path80, key) {
4520
+ constructor(parent, value, path82, key) {
4521
4521
  this._cachedPath = [];
4522
4522
  this.parent = parent;
4523
4523
  this.data = value;
4524
- this._path = path80;
4524
+ this._path = path82;
4525
4525
  this._key = key;
4526
4526
  }
4527
4527
  get path() {
@@ -8182,10 +8182,10 @@ function assignProp(target, prop, value) {
8182
8182
  configurable: true
8183
8183
  });
8184
8184
  }
8185
- function getElementAtPath(obj, path80) {
8186
- if (!path80)
8185
+ function getElementAtPath(obj, path82) {
8186
+ if (!path82)
8187
8187
  return obj;
8188
- return path80.reduce((acc, key) => acc?.[key], obj);
8188
+ return path82.reduce((acc, key) => acc?.[key], obj);
8189
8189
  }
8190
8190
  function promiseAllObject(promisesObj) {
8191
8191
  const keys = Object.keys(promisesObj);
@@ -8434,11 +8434,11 @@ function aborted(x, startIndex = 0) {
8434
8434
  }
8435
8435
  return false;
8436
8436
  }
8437
- function prefixIssues(path80, issues) {
8437
+ function prefixIssues(path82, issues) {
8438
8438
  return issues.map((iss) => {
8439
8439
  var _a2;
8440
8440
  (_a2 = iss).path ?? (_a2.path = []);
8441
- iss.path.unshift(path80);
8441
+ iss.path.unshift(path82);
8442
8442
  return iss;
8443
8443
  });
8444
8444
  }
@@ -8627,7 +8627,7 @@ function treeifyError(error40, _mapper) {
8627
8627
  return issue2.message;
8628
8628
  };
8629
8629
  const result = { errors: [] };
8630
- const processError = (error41, path80 = []) => {
8630
+ const processError = (error41, path82 = []) => {
8631
8631
  var _a2, _b;
8632
8632
  for (const issue2 of error41.issues) {
8633
8633
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -8637,7 +8637,7 @@ function treeifyError(error40, _mapper) {
8637
8637
  } else if (issue2.code === "invalid_element") {
8638
8638
  processError({ issues: issue2.issues }, issue2.path);
8639
8639
  } else {
8640
- const fullpath = [...path80, ...issue2.path];
8640
+ const fullpath = [...path82, ...issue2.path];
8641
8641
  if (fullpath.length === 0) {
8642
8642
  result.errors.push(mapper(issue2));
8643
8643
  continue;
@@ -8667,9 +8667,9 @@ function treeifyError(error40, _mapper) {
8667
8667
  processError(error40);
8668
8668
  return result;
8669
8669
  }
8670
- function toDotPath(path80) {
8670
+ function toDotPath(path82) {
8671
8671
  const segs = [];
8672
- for (const seg of path80) {
8672
+ for (const seg of path82) {
8673
8673
  if (typeof seg === "number")
8674
8674
  segs.push(`[${seg}]`);
8675
8675
  else if (typeof seg === "symbol")
@@ -22376,7 +22376,7 @@ function readMigrationSql(filename, ...searchSubdirs) {
22376
22376
  join(moduleDir, "..", sub, filename),
22377
22377
  join(moduleDir, "..", "..", "dist", sub, filename)
22378
22378
  ]);
22379
- const resolved = candidates.find((path80) => existsSync(path80));
22379
+ const resolved = candidates.find((path82) => existsSync(path82));
22380
22380
  if (!resolved) {
22381
22381
  throw new Error(`Missing SQLite migration SQL: ${filename} (searched ${searchSubdirs.join(", ")})`);
22382
22382
  }
@@ -23447,7 +23447,7 @@ var require_ignore = __commonJS({
23447
23447
  // path matching.
23448
23448
  // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
23449
23449
  // @returns {TestResult} true if a file is ignored
23450
- test(path80, checkUnignored, mode) {
23450
+ test(path82, checkUnignored, mode) {
23451
23451
  let ignored = false;
23452
23452
  let unignored = false;
23453
23453
  let matchedRule;
@@ -23456,7 +23456,7 @@ var require_ignore = __commonJS({
23456
23456
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
23457
23457
  return;
23458
23458
  }
23459
- const matched = rule[mode].test(path80);
23459
+ const matched = rule[mode].test(path82);
23460
23460
  if (!matched) {
23461
23461
  return;
23462
23462
  }
@@ -23477,17 +23477,17 @@ var require_ignore = __commonJS({
23477
23477
  var throwError = (message, Ctor) => {
23478
23478
  throw new Ctor(message);
23479
23479
  };
23480
- var checkPath = (path80, originalPath, doThrow) => {
23481
- if (!isString(path80)) {
23480
+ var checkPath = (path82, originalPath, doThrow) => {
23481
+ if (!isString(path82)) {
23482
23482
  return doThrow(
23483
23483
  `path must be a string, but got \`${originalPath}\``,
23484
23484
  TypeError
23485
23485
  );
23486
23486
  }
23487
- if (!path80) {
23487
+ if (!path82) {
23488
23488
  return doThrow(`path must not be empty`, TypeError);
23489
23489
  }
23490
- if (checkPath.isNotRelative(path80)) {
23490
+ if (checkPath.isNotRelative(path82)) {
23491
23491
  const r = "`path.relative()`d";
23492
23492
  return doThrow(
23493
23493
  `path should be a ${r} string, but got "${originalPath}"`,
@@ -23496,7 +23496,7 @@ var require_ignore = __commonJS({
23496
23496
  }
23497
23497
  return true;
23498
23498
  };
23499
- var isNotRelative = (path80) => REGEX_TEST_INVALID_PATH.test(path80);
23499
+ var isNotRelative = (path82) => REGEX_TEST_INVALID_PATH.test(path82);
23500
23500
  checkPath.isNotRelative = isNotRelative;
23501
23501
  checkPath.convert = (p) => p;
23502
23502
  var Ignore = class {
@@ -23526,19 +23526,19 @@ var require_ignore = __commonJS({
23526
23526
  }
23527
23527
  // @returns {TestResult}
23528
23528
  _test(originalPath, cache2, checkUnignored, slices) {
23529
- const path80 = originalPath && checkPath.convert(originalPath);
23529
+ const path82 = originalPath && checkPath.convert(originalPath);
23530
23530
  checkPath(
23531
- path80,
23531
+ path82,
23532
23532
  originalPath,
23533
23533
  this._strictPathCheck ? throwError : RETURN_FALSE
23534
23534
  );
23535
- return this._t(path80, cache2, checkUnignored, slices);
23535
+ return this._t(path82, cache2, checkUnignored, slices);
23536
23536
  }
23537
- checkIgnore(path80) {
23538
- if (!REGEX_TEST_TRAILING_SLASH.test(path80)) {
23539
- return this.test(path80);
23537
+ checkIgnore(path82) {
23538
+ if (!REGEX_TEST_TRAILING_SLASH.test(path82)) {
23539
+ return this.test(path82);
23540
23540
  }
23541
- const slices = path80.split(SLASH).filter(Boolean);
23541
+ const slices = path82.split(SLASH).filter(Boolean);
23542
23542
  slices.pop();
23543
23543
  if (slices.length) {
23544
23544
  const parent = this._t(
@@ -23551,18 +23551,18 @@ var require_ignore = __commonJS({
23551
23551
  return parent;
23552
23552
  }
23553
23553
  }
23554
- return this._rules.test(path80, false, MODE_CHECK_IGNORE);
23554
+ return this._rules.test(path82, false, MODE_CHECK_IGNORE);
23555
23555
  }
23556
- _t(path80, cache2, checkUnignored, slices) {
23557
- if (path80 in cache2) {
23558
- return cache2[path80];
23556
+ _t(path82, cache2, checkUnignored, slices) {
23557
+ if (path82 in cache2) {
23558
+ return cache2[path82];
23559
23559
  }
23560
23560
  if (!slices) {
23561
- slices = path80.split(SLASH).filter(Boolean);
23561
+ slices = path82.split(SLASH).filter(Boolean);
23562
23562
  }
23563
23563
  slices.pop();
23564
23564
  if (!slices.length) {
23565
- return cache2[path80] = this._rules.test(path80, checkUnignored, MODE_IGNORE);
23565
+ return cache2[path82] = this._rules.test(path82, checkUnignored, MODE_IGNORE);
23566
23566
  }
23567
23567
  const parent = this._t(
23568
23568
  slices.join(SLASH) + SLASH,
@@ -23570,29 +23570,29 @@ var require_ignore = __commonJS({
23570
23570
  checkUnignored,
23571
23571
  slices
23572
23572
  );
23573
- return cache2[path80] = parent.ignored ? parent : this._rules.test(path80, checkUnignored, MODE_IGNORE);
23573
+ return cache2[path82] = parent.ignored ? parent : this._rules.test(path82, checkUnignored, MODE_IGNORE);
23574
23574
  }
23575
- ignores(path80) {
23576
- return this._test(path80, this._ignoreCache, false).ignored;
23575
+ ignores(path82) {
23576
+ return this._test(path82, this._ignoreCache, false).ignored;
23577
23577
  }
23578
23578
  createFilter() {
23579
- return (path80) => !this.ignores(path80);
23579
+ return (path82) => !this.ignores(path82);
23580
23580
  }
23581
23581
  filter(paths) {
23582
23582
  return makeArray(paths).filter(this.createFilter());
23583
23583
  }
23584
23584
  // @returns {TestResult}
23585
- test(path80) {
23586
- return this._test(path80, this._testCache, true);
23585
+ test(path82) {
23586
+ return this._test(path82, this._testCache, true);
23587
23587
  }
23588
23588
  };
23589
23589
  var factory = (options) => new Ignore(options);
23590
- var isPathValid = (path80) => checkPath(path80 && checkPath.convert(path80), path80, RETURN_FALSE);
23590
+ var isPathValid = (path82) => checkPath(path82 && checkPath.convert(path82), path82, RETURN_FALSE);
23591
23591
  var setupWindows = () => {
23592
23592
  const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
23593
23593
  checkPath.convert = makePosix;
23594
23594
  const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
23595
- checkPath.isNotRelative = (path80) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path80) || isNotRelative(path80);
23595
+ checkPath.isNotRelative = (path82) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path82) || isNotRelative(path82);
23596
23596
  };
23597
23597
  if (
23598
23598
  // Detect `process` so that it can run in browsers.
@@ -27960,10 +27960,10 @@ var require_src2 = __commonJS({
27960
27960
  var fs_1 = __require("fs");
27961
27961
  var debug_1 = __importDefault(require_src());
27962
27962
  var log2 = debug_1.default("@kwsites/file-exists");
27963
- function check2(path80, isFile, isDirectory) {
27964
- log2(`checking %s`, path80);
27963
+ function check2(path82, isFile, isDirectory) {
27964
+ log2(`checking %s`, path82);
27965
27965
  try {
27966
- const stat2 = fs_1.statSync(path80);
27966
+ const stat2 = fs_1.statSync(path82);
27967
27967
  if (stat2.isFile() && isFile) {
27968
27968
  log2(`[OK] path represents a file`);
27969
27969
  return true;
@@ -27983,8 +27983,8 @@ var require_src2 = __commonJS({
27983
27983
  throw e;
27984
27984
  }
27985
27985
  }
27986
- function exists2(path80, type = exports.READABLE) {
27987
- return check2(path80, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
27986
+ function exists2(path82, type = exports.READABLE) {
27987
+ return check2(path82, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
27988
27988
  }
27989
27989
  exports.exists = exists2;
27990
27990
  exports.FILE = 1;
@@ -29341,6 +29341,18 @@ function getAgentModelFromAgentConfig(config2) {
29341
29341
  return t !== "" ? t : null;
29342
29342
  }
29343
29343
 
29344
+ // ../types/src/overview/heatmap/constants.ts
29345
+ var HOUR_MS = 36e5;
29346
+ var DAY_MS = 24 * HOUR_MS;
29347
+
29348
+ // ../types/src/bridges/agents/types.ts
29349
+ var INSTALLABLE_BRIDGE_AGENTS = [
29350
+ { value: "claude-code", label: "Anthropic Claude Code", tokenLabel: "Anthropic API key", tokenEnvVar: "ANTHROPIC_API_KEY" },
29351
+ { value: "codex-acp", label: "Codex", tokenLabel: "OpenAI API key", tokenEnvVar: "OPENAI_API_KEY" },
29352
+ { value: "cursor-cli", label: "Cursor CLI agent", tokenLabel: "Cursor API key", tokenEnvVar: "CURSOR_API_KEY" },
29353
+ { value: "opencode", label: "OpenCode agent", tokenLabel: "Provider API key", tokenEnvVar: "OPENCODE_API_KEY" }
29354
+ ];
29355
+
29344
29356
  // src/agents/acp/safe-fs-path.ts
29345
29357
  import * as path2 from "node:path";
29346
29358
  function resolveSafePathUnderCwd(cwd, filePath) {
@@ -30338,8 +30350,8 @@ function randomSecret() {
30338
30350
  }
30339
30351
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
30340
30352
  }
30341
- async function requestPreviewApi(port, secret, method, path80, body) {
30342
- const url2 = `http://127.0.0.1:${port}${path80}`;
30353
+ async function requestPreviewApi(port, secret, method, path82, body) {
30354
+ const url2 = `http://127.0.0.1:${port}${path82}`;
30343
30355
  const headers = {
30344
30356
  [PREVIEW_SECRET_HEADER]: secret,
30345
30357
  "Content-Type": "application/json"
@@ -30351,7 +30363,7 @@ async function requestPreviewApi(port, secret, method, path80, body) {
30351
30363
  });
30352
30364
  const data = await res.json().catch(() => ({}));
30353
30365
  if (!res.ok) {
30354
- throw new Error(data?.error ?? `Preview API ${method} ${path80}: ${res.status}`);
30366
+ throw new Error(data?.error ?? `Preview API ${method} ${path82}: ${res.status}`);
30355
30367
  }
30356
30368
  return data;
30357
30369
  }
@@ -30574,7 +30586,7 @@ function installBridgeProcessResilience() {
30574
30586
  }
30575
30587
 
30576
30588
  // src/cli-version.ts
30577
- var CLI_VERSION = "0.1.68".length > 0 ? "0.1.68" : "0.0.0-dev";
30589
+ var CLI_VERSION = "0.1.70".length > 0 ? "0.1.70" : "0.0.0-dev";
30578
30590
 
30579
30591
  // src/connection/heartbeat/constants.ts
30580
30592
  var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
@@ -34971,8 +34983,8 @@ async function execGitFile(args, options) {
34971
34983
  }
34972
34984
 
34973
34985
  // src/git/changes/parse/normalize-git-diff-path.ts
34974
- function normalizeGitDiffPath(path80) {
34975
- return path80.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
34986
+ function normalizeGitDiffPath(path82) {
34987
+ return path82.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
34976
34988
  }
34977
34989
 
34978
34990
  // src/git/changes/parse/parse-name-status-entries.ts
@@ -36481,6 +36493,21 @@ function createBridgeMcpToolRegistry(shared) {
36481
36493
  // src/mcp/bridge-access/start-server.ts
36482
36494
  import * as http from "node:http";
36483
36495
 
36496
+ // src/http/close-http-server.ts
36497
+ function isServerNotRunningError(err) {
36498
+ return err.code === "ERR_SERVER_NOT_RUNNING";
36499
+ }
36500
+ function closeHttpServer(server) {
36501
+ if (!server) return Promise.resolve();
36502
+ return new Promise((resolve35) => {
36503
+ server.close((err) => {
36504
+ if (err && !isServerNotRunningError(err)) {
36505
+ }
36506
+ resolve35();
36507
+ });
36508
+ });
36509
+ }
36510
+
36484
36511
  // src/mcp/bridge-access/read-json-body.ts
36485
36512
  function readJsonBody(req) {
36486
36513
  return new Promise((resolve35, reject) => {
@@ -36562,9 +36589,7 @@ function startBridgeAccessServer(registry2) {
36562
36589
  }
36563
36590
  resolve35({
36564
36591
  port: addr.port,
36565
- close: () => new Promise((closeResolve, closeReject) => {
36566
- server.close((err) => err ? closeReject(err) : closeResolve());
36567
- })
36592
+ close: () => closeHttpServer(server)
36568
36593
  });
36569
36594
  });
36570
36595
  });
@@ -39169,8 +39194,8 @@ function pathspec(...paths) {
39169
39194
  cache.set(key, paths);
39170
39195
  return key;
39171
39196
  }
39172
- function isPathSpec(path80) {
39173
- return path80 instanceof String && cache.has(path80);
39197
+ function isPathSpec(path82) {
39198
+ return path82 instanceof String && cache.has(path82);
39174
39199
  }
39175
39200
  function toPaths(pathSpec) {
39176
39201
  return cache.get(pathSpec) || [];
@@ -39259,8 +39284,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
39259
39284
  function forEachLineWithContent(input, callback) {
39260
39285
  return toLinesWithContent(input, true).map((line) => callback(line));
39261
39286
  }
39262
- function folderExists(path80) {
39263
- return (0, import_file_exists.exists)(path80, import_file_exists.FOLDER);
39287
+ function folderExists(path82) {
39288
+ return (0, import_file_exists.exists)(path82, import_file_exists.FOLDER);
39264
39289
  }
39265
39290
  function append(target, item) {
39266
39291
  if (Array.isArray(target)) {
@@ -39664,8 +39689,8 @@ function checkIsRepoRootTask() {
39664
39689
  commands,
39665
39690
  format: "utf-8",
39666
39691
  onError,
39667
- parser(path80) {
39668
- return /^\.(git)?$/.test(path80.trim());
39692
+ parser(path82) {
39693
+ return /^\.(git)?$/.test(path82.trim());
39669
39694
  }
39670
39695
  };
39671
39696
  }
@@ -40099,11 +40124,11 @@ function parseGrep(grep) {
40099
40124
  const paths = /* @__PURE__ */ new Set();
40100
40125
  const results = {};
40101
40126
  forEachLineWithContent(grep, (input) => {
40102
- const [path80, line, preview] = input.split(NULL);
40103
- paths.add(path80);
40104
- (results[path80] = results[path80] || []).push({
40127
+ const [path82, line, preview] = input.split(NULL);
40128
+ paths.add(path82);
40129
+ (results[path82] = results[path82] || []).push({
40105
40130
  line: asNumber(line),
40106
- path: path80,
40131
+ path: path82,
40107
40132
  preview
40108
40133
  });
40109
40134
  });
@@ -40868,14 +40893,14 @@ var init_hash_object = __esm2({
40868
40893
  init_task();
40869
40894
  }
40870
40895
  });
40871
- function parseInit(bare, path80, text) {
40896
+ function parseInit(bare, path82, text) {
40872
40897
  const response = String(text).trim();
40873
40898
  let result;
40874
40899
  if (result = initResponseRegex.exec(response)) {
40875
- return new InitSummary(bare, path80, false, result[1]);
40900
+ return new InitSummary(bare, path82, false, result[1]);
40876
40901
  }
40877
40902
  if (result = reInitResponseRegex.exec(response)) {
40878
- return new InitSummary(bare, path80, true, result[1]);
40903
+ return new InitSummary(bare, path82, true, result[1]);
40879
40904
  }
40880
40905
  let gitDir = "";
40881
40906
  const tokens = response.split(" ");
@@ -40886,7 +40911,7 @@ function parseInit(bare, path80, text) {
40886
40911
  break;
40887
40912
  }
40888
40913
  }
40889
- return new InitSummary(bare, path80, /^re/i.test(response), gitDir);
40914
+ return new InitSummary(bare, path82, /^re/i.test(response), gitDir);
40890
40915
  }
40891
40916
  var InitSummary;
40892
40917
  var initResponseRegex;
@@ -40895,9 +40920,9 @@ var init_InitSummary = __esm2({
40895
40920
  "src/lib/responses/InitSummary.ts"() {
40896
40921
  "use strict";
40897
40922
  InitSummary = class {
40898
- constructor(bare, path80, existing, gitDir) {
40923
+ constructor(bare, path82, existing, gitDir) {
40899
40924
  this.bare = bare;
40900
- this.path = path80;
40925
+ this.path = path82;
40901
40926
  this.existing = existing;
40902
40927
  this.gitDir = gitDir;
40903
40928
  }
@@ -40909,7 +40934,7 @@ var init_InitSummary = __esm2({
40909
40934
  function hasBareCommand(command) {
40910
40935
  return command.includes(bareCommand);
40911
40936
  }
40912
- function initTask(bare = false, path80, customArgs) {
40937
+ function initTask(bare = false, path82, customArgs) {
40913
40938
  const commands = ["init", ...customArgs];
40914
40939
  if (bare && !hasBareCommand(commands)) {
40915
40940
  commands.splice(1, 0, bareCommand);
@@ -40918,7 +40943,7 @@ function initTask(bare = false, path80, customArgs) {
40918
40943
  commands,
40919
40944
  format: "utf-8",
40920
40945
  parser(text) {
40921
- return parseInit(commands.includes("--bare"), path80, text);
40946
+ return parseInit(commands.includes("--bare"), path82, text);
40922
40947
  }
40923
40948
  };
40924
40949
  }
@@ -41734,12 +41759,12 @@ var init_FileStatusSummary = __esm2({
41734
41759
  "use strict";
41735
41760
  fromPathRegex = /^(.+)\0(.+)$/;
41736
41761
  FileStatusSummary = class {
41737
- constructor(path80, index, working_dir) {
41738
- this.path = path80;
41762
+ constructor(path82, index, working_dir) {
41763
+ this.path = path82;
41739
41764
  this.index = index;
41740
41765
  this.working_dir = working_dir;
41741
41766
  if (index === "R" || working_dir === "R") {
41742
- const detail = fromPathRegex.exec(path80) || [null, path80, path80];
41767
+ const detail = fromPathRegex.exec(path82) || [null, path82, path82];
41743
41768
  this.from = detail[2] || "";
41744
41769
  this.path = detail[1] || "";
41745
41770
  }
@@ -41770,14 +41795,14 @@ function splitLine(result, lineStr) {
41770
41795
  default:
41771
41796
  return;
41772
41797
  }
41773
- function data(index, workingDir, path80) {
41798
+ function data(index, workingDir, path82) {
41774
41799
  const raw = `${index}${workingDir}`;
41775
41800
  const handler = parsers6.get(raw);
41776
41801
  if (handler) {
41777
- handler(result, path80);
41802
+ handler(result, path82);
41778
41803
  }
41779
41804
  if (raw !== "##" && raw !== "!!") {
41780
- result.files.push(new FileStatusSummary(path80, index, workingDir));
41805
+ result.files.push(new FileStatusSummary(path82, index, workingDir));
41781
41806
  }
41782
41807
  }
41783
41808
  }
@@ -42086,9 +42111,9 @@ var init_simple_git_api = __esm2({
42086
42111
  next
42087
42112
  );
42088
42113
  }
42089
- hashObject(path80, write) {
42114
+ hashObject(path82, write) {
42090
42115
  return this._runTask(
42091
- hashObjectTask(path80, write === true),
42116
+ hashObjectTask(path82, write === true),
42092
42117
  trailingFunctionArgument(arguments)
42093
42118
  );
42094
42119
  }
@@ -42441,8 +42466,8 @@ var init_branch = __esm2({
42441
42466
  }
42442
42467
  });
42443
42468
  function toPath(input) {
42444
- const path80 = input.trim().replace(/^["']|["']$/g, "");
42445
- return path80 && normalize3(path80);
42469
+ const path82 = input.trim().replace(/^["']|["']$/g, "");
42470
+ return path82 && normalize3(path82);
42446
42471
  }
42447
42472
  var parseCheckIgnore;
42448
42473
  var init_CheckIgnore = __esm2({
@@ -42756,8 +42781,8 @@ __export2(sub_module_exports, {
42756
42781
  subModuleTask: () => subModuleTask,
42757
42782
  updateSubModuleTask: () => updateSubModuleTask
42758
42783
  });
42759
- function addSubModuleTask(repo, path80) {
42760
- return subModuleTask(["add", repo, path80]);
42784
+ function addSubModuleTask(repo, path82) {
42785
+ return subModuleTask(["add", repo, path82]);
42761
42786
  }
42762
42787
  function initSubModuleTask(customArgs) {
42763
42788
  return subModuleTask(["init", ...customArgs]);
@@ -43090,8 +43115,8 @@ var require_git = __commonJS2({
43090
43115
  }
43091
43116
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
43092
43117
  };
43093
- Git2.prototype.submoduleAdd = function(repo, path80, then) {
43094
- return this._runTask(addSubModuleTask2(repo, path80), trailingFunctionArgument2(arguments));
43118
+ Git2.prototype.submoduleAdd = function(repo, path82, then) {
43119
+ return this._runTask(addSubModuleTask2(repo, path82), trailingFunctionArgument2(arguments));
43095
43120
  };
43096
43121
  Git2.prototype.submoduleUpdate = function(args, then) {
43097
43122
  return this._runTask(
@@ -43830,8 +43855,8 @@ function parseNumstatEntries(lines) {
43830
43855
  }
43831
43856
  function parseNumstat(lines) {
43832
43857
  const m = /* @__PURE__ */ new Map();
43833
- for (const [path80, entry] of parseNumstatEntries(lines)) {
43834
- m.set(path80, { additions: entry.additions, deletions: entry.deletions });
43858
+ for (const [path82, entry] of parseNumstatEntries(lines)) {
43859
+ m.set(path82, { additions: entry.additions, deletions: entry.deletions });
43835
43860
  }
43836
43861
  return m;
43837
43862
  }
@@ -45626,9 +45651,8 @@ function parseSessionParent(v) {
45626
45651
  return null;
45627
45652
  }
45628
45653
 
45629
- // src/worktrees/prepare-new-isolated-worktrees.ts
45630
- import * as fs44 from "node:fs";
45631
- import * as path64 from "node:path";
45654
+ // src/worktrees/prepare/prepare-new-isolated-worktrees.ts
45655
+ import * as fs46 from "node:fs";
45632
45656
 
45633
45657
  // src/git/discover-repos.ts
45634
45658
  import * as fs43 from "node:fs";
@@ -45699,6 +45723,10 @@ async function discoverGitReposUnderRoot(rootPath) {
45699
45723
  return out;
45700
45724
  }
45701
45725
 
45726
+ // src/worktrees/prepare/add-isolated-repo-worktree.ts
45727
+ import * as fs45 from "node:fs";
45728
+ import * as path65 from "node:path";
45729
+
45702
45730
  // src/git/worktrees/worktree-add.ts
45703
45731
  async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
45704
45732
  const mainGit = cliSimpleGit(mainRepoPath);
@@ -45712,6 +45740,100 @@ async function gitWorktreeAddExistingBranch(mainRepoPath, worktreePath, branch)
45712
45740
  await mainGit.raw(["worktree", "add", worktreePath, branch]);
45713
45741
  }
45714
45742
 
45743
+ // src/worktrees/prepare/copy-bridge-files-along-worktree-path.ts
45744
+ import * as fs44 from "node:fs";
45745
+ import * as path64 from "node:path";
45746
+ var BRIDGE_FILES_ALONG_WORKTREE_PATH = ["AGENTS.md"];
45747
+ function copyBridgeFilesAlongWorktreePath(options) {
45748
+ const { bridgeRoot, scopeDir, repoPathRelativeToBridgeRoot, log: log2 } = options;
45749
+ const fileNames = options.fileNames ?? BRIDGE_FILES_ALONG_WORKTREE_PATH;
45750
+ if (repoPathRelativeToBridgeRoot === ".") return;
45751
+ const segments = repoPathRelativeToBridgeRoot.split("/").filter(Boolean);
45752
+ for (let i = 0; i < segments.length; i++) {
45753
+ const prefix = segments.slice(0, i).join("/");
45754
+ const bridgeDir = prefix ? path64.join(bridgeRoot, prefix) : bridgeRoot;
45755
+ const destDir = prefix ? path64.join(scopeDir, prefix) : scopeDir;
45756
+ for (const fileName of fileNames) {
45757
+ copyFileIfPresent(bridgeDir, destDir, fileName, log2);
45758
+ }
45759
+ }
45760
+ }
45761
+ function copyFileIfPresent(srcDir, destDir, fileName, log2) {
45762
+ const src = path64.join(srcDir, fileName);
45763
+ if (!fs44.existsSync(src)) return;
45764
+ const dest = path64.join(destDir, fileName);
45765
+ try {
45766
+ fs44.copyFileSync(src, dest);
45767
+ log2?.(`[worktrees] Copied ${fileName} to ${dest}`);
45768
+ } catch (e) {
45769
+ log2?.(
45770
+ `[worktrees] Failed to copy ${fileName} to ${dest}: ${e instanceof Error ? e.message : String(e)}`
45771
+ );
45772
+ }
45773
+ }
45774
+
45775
+ // src/worktrees/prepare/resolve-base-ref-for-repo.ts
45776
+ function resolveBaseRefForRepo(repoPathRelativeToBridgeRoot, baseBranches) {
45777
+ if (!baseBranches) return "HEAD";
45778
+ const direct = baseBranches[repoPathRelativeToBridgeRoot]?.trim();
45779
+ if (direct) return direct;
45780
+ if (repoPathRelativeToBridgeRoot !== "." && baseBranches["."]?.trim()) {
45781
+ return baseBranches["."].trim();
45782
+ }
45783
+ return "HEAD";
45784
+ }
45785
+
45786
+ // src/worktrees/prepare/add-isolated-repo-worktree.ts
45787
+ async function addIsolatedRepoWorktree(options) {
45788
+ const {
45789
+ kind,
45790
+ bridgeResolved,
45791
+ scopeDir,
45792
+ repoAbsolutePath,
45793
+ branch,
45794
+ existingBranch,
45795
+ worktreeBaseBranches,
45796
+ log: log2
45797
+ } = options;
45798
+ const repoPathRelativeToBridgeRootRaw = path65.relative(bridgeResolved, repoAbsolutePath);
45799
+ if (repoPathRelativeToBridgeRootRaw.startsWith("..") || path65.isAbsolute(repoPathRelativeToBridgeRootRaw)) {
45800
+ return null;
45801
+ }
45802
+ const repoPathRelativeToBridgeRoot = normalizeRepoPathRelativeToWorkspaceRoot(
45803
+ repoPathRelativeToBridgeRootRaw === "" ? "." : repoPathRelativeToBridgeRootRaw
45804
+ );
45805
+ const worktreePath = repoPathRelativeToBridgeRoot === "." ? scopeDir : path65.join(scopeDir, repoPathRelativeToBridgeRoot);
45806
+ if (repoPathRelativeToBridgeRoot !== ".") {
45807
+ fs45.mkdirSync(path65.dirname(worktreePath), { recursive: true });
45808
+ copyBridgeFilesAlongWorktreePath({
45809
+ bridgeRoot: bridgeResolved,
45810
+ scopeDir,
45811
+ repoPathRelativeToBridgeRoot,
45812
+ log: log2
45813
+ });
45814
+ }
45815
+ const checkoutBranch = existingBranch?.trim() || branch;
45816
+ try {
45817
+ if (existingBranch?.trim()) {
45818
+ await gitWorktreeAddExistingBranch(repoAbsolutePath, worktreePath, checkoutBranch);
45819
+ log2(`[worktrees] Added ${kind} worktree ${worktreePath} (existing branch ${checkoutBranch}).`);
45820
+ } else {
45821
+ const baseRef = resolveBaseRefForRepo(repoPathRelativeToBridgeRoot, worktreeBaseBranches);
45822
+ await gitWorktreeAddBranch(repoAbsolutePath, worktreePath, branch, baseRef);
45823
+ log2(`[worktrees] Added ${kind} worktree ${worktreePath} (branch ${branch}, base ${baseRef}).`);
45824
+ }
45825
+ return worktreePath;
45826
+ } catch (e) {
45827
+ log2(
45828
+ `[worktrees] Worktree add failed for ${repoAbsolutePath}: ${e instanceof Error ? e.message : String(e)}`
45829
+ );
45830
+ return null;
45831
+ }
45832
+ }
45833
+
45834
+ // src/worktrees/prepare/resolve-isolated-scope-dir.ts
45835
+ import * as path66 from "node:path";
45836
+
45715
45837
  // src/worktrees/worktree-layout-kind.ts
45716
45838
  function sanitizeWorktreeBranchSegment(value) {
45717
45839
  return value.replace(/[^a-zA-Z0-9/_-]+/g, "-").slice(0, 80) || "worktree";
@@ -45738,16 +45860,16 @@ function previewDeployBranchName(environmentId) {
45738
45860
  return `preview-deploy-${sanitizeWorktreeBranchSegment(environmentId.trim())}`;
45739
45861
  }
45740
45862
 
45741
- // src/worktrees/prepare-new-isolated-worktrees.ts
45742
- function resolveBaseRefForRepo(repoPathRelativeToBridgeRoot, baseBranches) {
45743
- if (!baseBranches) return "HEAD";
45744
- const direct = baseBranches[repoPathRelativeToBridgeRoot]?.trim();
45745
- if (direct) return direct;
45746
- if (repoPathRelativeToBridgeRoot !== "." && baseBranches["."]?.trim()) {
45747
- return baseBranches["."].trim();
45748
- }
45749
- return "HEAD";
45863
+ // src/worktrees/prepare/resolve-isolated-scope-dir.ts
45864
+ function resolveIsolatedScopeDir(options) {
45865
+ const bridgeResolved = path66.resolve(options.bridgeRoot);
45866
+ const cwdKey = allocateDirNameForLauncherCwd(options.layout, bridgeResolved);
45867
+ const bridgeKeyDir = path66.join(options.worktreesRootPath, cwdKey);
45868
+ const scopeDir = path66.join(bridgeKeyDir, ...layoutDirSegments(options.kind, options.scopeId));
45869
+ return { bridgeResolved, scopeDir };
45750
45870
  }
45871
+
45872
+ // src/worktrees/prepare/prepare-new-isolated-worktrees.ts
45751
45873
  async function prepareNewIsolatedWorktrees(options) {
45752
45874
  const {
45753
45875
  kind,
@@ -45760,45 +45882,32 @@ async function prepareNewIsolatedWorktrees(options) {
45760
45882
  worktreeBaseBranches,
45761
45883
  existingBranch
45762
45884
  } = options;
45763
- const bridgeResolved = path64.resolve(bridgeRoot);
45764
- const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
45765
- const bridgeKeyDir = path64.join(worktreesRootPath, cwdKey);
45766
- const scopeDir = path64.join(bridgeKeyDir, ...layoutDirSegments(kind, scopeId));
45885
+ const { bridgeResolved, scopeDir } = resolveIsolatedScopeDir({
45886
+ worktreesRootPath,
45887
+ bridgeRoot,
45888
+ kind,
45889
+ scopeId,
45890
+ layout
45891
+ });
45767
45892
  const repos = await discoverGitReposUnderRoot(bridgeResolved);
45768
45893
  if (repos.length === 0) {
45769
45894
  log2(`[worktrees] No Git repositories under bridge root; skipping ${kind} worktree creation.`);
45770
45895
  return null;
45771
45896
  }
45772
45897
  const worktreePaths = [];
45773
- fs44.mkdirSync(scopeDir, { recursive: true });
45898
+ fs46.mkdirSync(scopeDir, { recursive: true });
45774
45899
  await forEachWithGitYield(repos, async (repo) => {
45775
- const repoPathRelativeToBridgeRootRaw = path64.relative(bridgeResolved, repo.absolutePath);
45776
- if (repoPathRelativeToBridgeRootRaw.startsWith("..") || path64.isAbsolute(repoPathRelativeToBridgeRootRaw)) {
45777
- return;
45778
- }
45779
- const repoPathRelativeToBridgeRoot = normalizeRepoPathRelativeToWorkspaceRoot(
45780
- repoPathRelativeToBridgeRootRaw === "" ? "." : repoPathRelativeToBridgeRootRaw
45781
- );
45782
- const worktreePath = repoPathRelativeToBridgeRoot === "." ? scopeDir : path64.join(scopeDir, repoPathRelativeToBridgeRoot);
45783
- if (repoPathRelativeToBridgeRoot !== ".") {
45784
- fs44.mkdirSync(path64.dirname(worktreePath), { recursive: true });
45785
- }
45786
- const checkoutBranch = existingBranch?.trim() || branch;
45787
- try {
45788
- if (existingBranch?.trim()) {
45789
- await gitWorktreeAddExistingBranch(repo.absolutePath, worktreePath, checkoutBranch);
45790
- log2(`[worktrees] Added ${kind} worktree ${worktreePath} (existing branch ${checkoutBranch}).`);
45791
- } else {
45792
- const baseRef = resolveBaseRefForRepo(repoPathRelativeToBridgeRoot, worktreeBaseBranches);
45793
- await gitWorktreeAddBranch(repo.absolutePath, worktreePath, branch, baseRef);
45794
- log2(`[worktrees] Added ${kind} worktree ${worktreePath} (branch ${branch}, base ${baseRef}).`);
45795
- }
45796
- worktreePaths.push(worktreePath);
45797
- } catch (e) {
45798
- log2(
45799
- `[worktrees] Worktree add failed for ${repo.absolutePath}: ${e instanceof Error ? e.message : String(e)}`
45800
- );
45801
- }
45900
+ const worktreePath = await addIsolatedRepoWorktree({
45901
+ kind,
45902
+ bridgeResolved,
45903
+ scopeDir,
45904
+ repoAbsolutePath: repo.absolutePath,
45905
+ branch,
45906
+ existingBranch,
45907
+ worktreeBaseBranches,
45908
+ log: log2
45909
+ });
45910
+ if (worktreePath) worktreePaths.push(worktreePath);
45802
45911
  });
45803
45912
  if (worktreePaths.length === 0) return null;
45804
45913
  return {
@@ -45858,10 +45967,10 @@ async function resolveExistingSessionParentPath(sessionId, cache2, discover) {
45858
45967
  }
45859
45968
 
45860
45969
  // src/worktrees/manager/resolve-explicit-session-parent-path.ts
45861
- import * as path65 from "node:path";
45970
+ import * as path67 from "node:path";
45862
45971
  init_yield_to_event_loop();
45863
45972
  async function resolveExplicitSessionParentPath(params) {
45864
- const resolved = path65.resolve(params.parentPathRaw);
45973
+ const resolved = path67.resolve(params.parentPathRaw);
45865
45974
  if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
45866
45975
  return resolved;
45867
45976
  }
@@ -45878,7 +45987,7 @@ async function resolveExplicitSessionParentPath(params) {
45878
45987
  await yieldToEventLoop();
45879
45988
  const tryRoot = await discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
45880
45989
  if (tryRoot) return rememberAndReturn(tryRoot);
45881
- const next = path65.dirname(cur);
45990
+ const next = path67.dirname(cur);
45882
45991
  if (next === cur) break;
45883
45992
  cur = next;
45884
45993
  }
@@ -46026,15 +46135,15 @@ var SessionWorktreeManager = class {
46026
46135
  };
46027
46136
 
46028
46137
  // src/worktrees/discovery/discover-preview-worktree-on-disk.ts
46029
- import * as fs45 from "node:fs";
46030
- import * as path66 from "node:path";
46138
+ import * as fs47 from "node:fs";
46139
+ import * as path68 from "node:path";
46031
46140
  init_yield_to_event_loop();
46032
46141
  async function discoverPreviewWorktreeOnDisk(options) {
46033
46142
  const { environmentId, worktreesRootPath, layout, bridgeRoot } = options;
46034
46143
  const eid = environmentId.trim();
46035
46144
  if (!eid) return null;
46036
46145
  try {
46037
- await fs45.promises.access(worktreesRootPath);
46146
+ await fs47.promises.access(worktreesRootPath);
46038
46147
  } catch {
46039
46148
  return null;
46040
46149
  }
@@ -46043,13 +46152,13 @@ async function discoverPreviewWorktreeOnDisk(options) {
46043
46152
  if (preferredKey) keysOnDisk.push(preferredKey);
46044
46153
  const scanState = { entries: 0 };
46045
46154
  try {
46046
- for (const name of await fs45.promises.readdir(worktreesRootPath)) {
46155
+ for (const name of await fs47.promises.readdir(worktreesRootPath)) {
46047
46156
  if (!await yieldDuringDiskWalk(scanState)) break;
46048
46157
  if (name.startsWith(".")) continue;
46049
- const p = path66.join(worktreesRootPath, name);
46158
+ const p = path68.join(worktreesRootPath, name);
46050
46159
  let st;
46051
46160
  try {
46052
- st = await fs45.promises.stat(p);
46161
+ st = await fs47.promises.stat(p);
46053
46162
  } catch {
46054
46163
  continue;
46055
46164
  }
@@ -46063,7 +46172,7 @@ async function discoverPreviewWorktreeOnDisk(options) {
46063
46172
  const previewDirRel = layoutDirSegments("preview_environment", eid);
46064
46173
  for (const key of keys) {
46065
46174
  await yieldToEventLoop();
46066
- const previewDir = path66.join(worktreesRootPath, key, ...previewDirRel);
46175
+ const previewDir = path68.join(worktreesRootPath, key, ...previewDirRel);
46067
46176
  const binding = await tryBindingFromIsolatedDirectory(previewDir);
46068
46177
  if (binding) return binding;
46069
46178
  }
@@ -46190,7 +46299,7 @@ var PreviewWorktreeManager = class {
46190
46299
  };
46191
46300
 
46192
46301
  // src/worktrees/deploy/deploy-session-to-preview-environment.ts
46193
- import * as path70 from "node:path";
46302
+ import * as path72 from "node:path";
46194
46303
 
46195
46304
  // src/git/worktrees/reset-worktree-to-branch.ts
46196
46305
  async function gitResetWorktreeToBranch(worktreePath, branch) {
@@ -46201,8 +46310,8 @@ async function gitResetWorktreeToBranch(worktreePath, branch) {
46201
46310
  }
46202
46311
 
46203
46312
  // src/worktrees/deploy/capture-and-apply-wip.ts
46204
- import * as fs46 from "node:fs";
46205
- import * as path67 from "node:path";
46313
+ import * as fs48 from "node:fs";
46314
+ import * as path69 from "node:path";
46206
46315
 
46207
46316
  // src/git/snapshot/git.ts
46208
46317
  async function gitStashCreate(repoRoot, log2) {
@@ -46250,12 +46359,12 @@ async function applyWorkingTreeWip(targetRepoPath, sourceRepoPath, wip, log2) {
46250
46359
  if (!ap.ok) return ap;
46251
46360
  }
46252
46361
  await forEachWithGitYield(wip.untrackedPaths, async (rel) => {
46253
- const src = path67.join(sourceRepoPath, rel);
46254
- const dst = path67.join(targetRepoPath, rel);
46362
+ const src = path69.join(sourceRepoPath, rel);
46363
+ const dst = path69.join(targetRepoPath, rel);
46255
46364
  try {
46256
- if (!fs46.existsSync(src)) return;
46257
- fs46.mkdirSync(path67.dirname(dst), { recursive: true });
46258
- fs46.copyFileSync(src, dst);
46365
+ if (!fs48.existsSync(src)) return;
46366
+ fs48.mkdirSync(path69.dirname(dst), { recursive: true });
46367
+ fs48.copyFileSync(src, dst);
46259
46368
  } catch (e) {
46260
46369
  log2(
46261
46370
  `[worktrees] Failed to copy untracked ${rel}: ${e instanceof Error ? e.message : String(e)}`
@@ -46266,14 +46375,14 @@ async function applyWorkingTreeWip(targetRepoPath, sourceRepoPath, wip, log2) {
46266
46375
  }
46267
46376
 
46268
46377
  // src/worktrees/deploy/resolve-isolated-checkout-for-repo-path-relative-to-workspace-root.ts
46269
- import * as path68 from "node:path";
46378
+ import * as path70 from "node:path";
46270
46379
  async function resolveIsolatedCheckoutForRepoPathRelativeToWorkspaceRoot(options) {
46271
46380
  const { checkoutPaths, sessionParentPath, bridgeRoot, repoPathRelativeToWorkspaceRoot } = options;
46272
- const resolvedSessionParentPath = sessionParentPath ? path68.resolve(sessionParentPath) : null;
46381
+ const resolvedSessionParentPath = sessionParentPath ? path70.resolve(sessionParentPath) : null;
46273
46382
  let match = null;
46274
46383
  await forEachWithGitYield(checkoutPaths, async (checkoutPath) => {
46275
46384
  if (match) return;
46276
- const resolvedCheckoutPath = path68.resolve(checkoutPath);
46385
+ const resolvedCheckoutPath = path70.resolve(checkoutPath);
46277
46386
  if (!await isGitRepoDirectory(resolvedCheckoutPath)) return;
46278
46387
  const resolvedRepoPathRelativeToWorkspaceRoot = await resolveRepoPathRelativeToWorkspaceRoot({
46279
46388
  checkoutPath: resolvedCheckoutPath,
@@ -46327,7 +46436,7 @@ async function applySessionWipToPreviewCheckouts(options) {
46327
46436
  }
46328
46437
 
46329
46438
  // src/worktrees/deploy/collect-session-repo-deploy-states.ts
46330
- import * as path69 from "node:path";
46439
+ import * as path71 from "node:path";
46331
46440
 
46332
46441
  // src/git/branches/create-or-update-branch.ts
46333
46442
  async function gitCreateOrUpdateBranch(repoPath, branch, startRef, options) {
@@ -46364,19 +46473,19 @@ async function collectSessionRepoDeployStates(options) {
46364
46473
  const sessionParentPath = sessionWorktreeManager.getSessionParentPath(sid);
46365
46474
  const states = [];
46366
46475
  await forEachWithGitYield(sessionTargets, async (sessionCheckout) => {
46367
- const checkoutPath = path69.resolve(sessionCheckout);
46476
+ const checkoutPath = path71.resolve(sessionCheckout);
46368
46477
  if (!await isGitRepoDirectory(checkoutPath)) return;
46369
46478
  const repoPathRelativeToWorkspaceRoot = await resolveRepoPathRelativeToWorkspaceRoot({
46370
46479
  checkoutPath,
46371
46480
  bridgeRoot,
46372
- sessionParentPath: sessionParentPath ? path69.resolve(sessionParentPath) : null
46481
+ sessionParentPath: sessionParentPath ? path71.resolve(sessionParentPath) : null
46373
46482
  });
46374
46483
  if (!repoPathRelativeToWorkspaceRoot) return;
46375
46484
  const mainRepoPath = resolveMainRepoPath(checkoutPath);
46376
46485
  const headSha = (await cliSimpleGit(checkoutPath).revparse(["HEAD"])).trim();
46377
46486
  const previewCheckout = previewCheckoutPaths.length > 0 ? await resolveIsolatedCheckoutForRepoPathRelativeToWorkspaceRoot({
46378
46487
  checkoutPaths: previewCheckoutPaths,
46379
- sessionParentPath: previewParentPath ? path69.resolve(previewParentPath) : null,
46488
+ sessionParentPath: previewParentPath ? path71.resolve(previewParentPath) : null,
46380
46489
  bridgeRoot,
46381
46490
  repoPathRelativeToWorkspaceRoot
46382
46491
  }) : null;
@@ -46396,7 +46505,7 @@ async function deploySessionToPreviewEnvironment(options) {
46396
46505
  const eid = options.environmentId.trim();
46397
46506
  if (!sid || !eid) return { ok: false, error: "sessionId and environmentId are required" };
46398
46507
  const deployBranch = previewDeployBranchName(eid);
46399
- const bridgeRoot = path70.resolve(getBridgeRoot());
46508
+ const bridgeRoot = path72.resolve(getBridgeRoot());
46400
46509
  await previewWorktreeManager.ensureCached(eid);
46401
46510
  const existingPreviewParentPath = previewWorktreeManager.getPreviewParentPath(eid) ?? null;
46402
46511
  const existingPreviewCheckoutPaths = previewWorktreeManager.getRepoCheckoutPaths(eid) ?? [];
@@ -46436,10 +46545,10 @@ async function deploySessionToPreviewEnvironment(options) {
46436
46545
  }
46437
46546
 
46438
46547
  // src/worktrees/manager/default-worktrees-root-path.ts
46439
- import * as path71 from "node:path";
46548
+ import * as path73 from "node:path";
46440
46549
  import os9 from "node:os";
46441
46550
  function defaultWorktreesRootPath() {
46442
- return path71.join(os9.homedir(), ".buildautomaton", "worktrees");
46551
+ return path73.join(os9.homedir(), ".buildautomaton", "worktrees");
46443
46552
  }
46444
46553
 
46445
46554
  // src/connection/create-bridge-worktree-managers.ts
@@ -46569,14 +46678,14 @@ function assertBridgeWorkspace(ctx) {
46569
46678
  }
46570
46679
 
46571
46680
  // src/files/list-dir/index.ts
46572
- import fs48 from "node:fs";
46681
+ import fs50 from "node:fs";
46573
46682
 
46574
46683
  // src/files/ensure-under-cwd.ts
46575
- import path72 from "node:path";
46684
+ import path74 from "node:path";
46576
46685
  function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
46577
- const normalized = path72.normalize(relativePath).replace(/^(\.\/)+/, "");
46578
- const resolved = path72.resolve(cwd, normalized);
46579
- if (!resolved.startsWith(cwd + path72.sep) && resolved !== cwd) {
46686
+ const normalized = path74.normalize(relativePath).replace(/^(\.\/)+/, "");
46687
+ const resolved = path74.resolve(cwd, normalized);
46688
+ if (!resolved.startsWith(cwd + path74.sep) && resolved !== cwd) {
46580
46689
  return null;
46581
46690
  }
46582
46691
  return resolved;
@@ -46589,15 +46698,15 @@ init_yield_to_event_loop();
46589
46698
  var LIST_DIR_YIELD_EVERY = 256;
46590
46699
 
46591
46700
  // src/files/list-dir/map-dir-entry.ts
46592
- import path73 from "node:path";
46593
- import fs47 from "node:fs";
46701
+ import path75 from "node:path";
46702
+ import fs49 from "node:fs";
46594
46703
  async function mapDirEntry(d, relativePath, resolved) {
46595
- const entryPath = path73.join(relativePath || ".", d.name).replace(/\\/g, "/");
46596
- const fullPath = path73.join(resolved, d.name);
46704
+ const entryPath = path75.join(relativePath || ".", d.name).replace(/\\/g, "/");
46705
+ const fullPath = path75.join(resolved, d.name);
46597
46706
  let isDir = d.isDirectory();
46598
46707
  if (d.isSymbolicLink()) {
46599
46708
  try {
46600
- const targetStat = await fs47.promises.stat(fullPath);
46709
+ const targetStat = await fs49.promises.stat(fullPath);
46601
46710
  isDir = targetStat.isDirectory();
46602
46711
  } catch {
46603
46712
  isDir = false;
@@ -46627,7 +46736,7 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
46627
46736
  return { error: "Path is outside working directory" };
46628
46737
  }
46629
46738
  try {
46630
- const names = await fs48.promises.readdir(resolved, { withFileTypes: true });
46739
+ const names = await fs50.promises.readdir(resolved, { withFileTypes: true });
46631
46740
  const entries = [];
46632
46741
  for (let i = 0; i < names.length; i++) {
46633
46742
  if (i > 0 && i % LIST_DIR_YIELD_EVERY === 0) {
@@ -46643,13 +46752,13 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
46643
46752
  }
46644
46753
 
46645
46754
  // src/git/tree/resolve-repo-abs-path.ts
46646
- import * as path74 from "node:path";
46755
+ import * as path76 from "node:path";
46647
46756
  function resolveRepoAbsPathFromBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
46648
- const bridgeResolved = path74.resolve(bridgeRoot);
46757
+ const bridgeResolved = path76.resolve(bridgeRoot);
46649
46758
  const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
46650
- const repoPath = rel === "" ? bridgeResolved : path74.join(bridgeResolved, rel);
46651
- const resolved = path74.resolve(repoPath);
46652
- if (!resolved.startsWith(bridgeResolved + path74.sep) && resolved !== bridgeResolved) {
46759
+ const repoPath = rel === "" ? bridgeResolved : path76.join(bridgeResolved, rel);
46760
+ const resolved = path76.resolve(repoPath);
46761
+ if (!resolved.startsWith(bridgeResolved + path76.sep) && resolved !== bridgeResolved) {
46653
46762
  return null;
46654
46763
  }
46655
46764
  return resolved;
@@ -47130,25 +47239,25 @@ async function GET2(ctx) {
47130
47239
  init_in_flight();
47131
47240
 
47132
47241
  // src/files/read/read-file-async.ts
47133
- import fs54 from "node:fs";
47242
+ import fs56 from "node:fs";
47134
47243
  init_yield_to_event_loop();
47135
47244
 
47136
47245
  // src/files/read/resolve-file-cache.ts
47137
- import fs49 from "node:fs";
47138
- import path75 from "node:path";
47246
+ import fs51 from "node:fs";
47247
+ import path77 from "node:path";
47139
47248
  var RESOLVE_CACHE_MAX = 4096;
47140
47249
  var resolveCache = /* @__PURE__ */ new Map();
47141
47250
  function resolveCacheKey(sessionParentPath, relativePath) {
47142
47251
  return `${sessionParentPath}\0${relativePath}`;
47143
47252
  }
47144
47253
  function pathStaysUnderParent(filePath, sessionParentPath) {
47145
- const parent = path75.resolve(sessionParentPath);
47146
- const resolved = path75.resolve(filePath);
47147
- return resolved === parent || resolved.startsWith(`${parent}${path75.sep}`);
47254
+ const parent = path77.resolve(sessionParentPath);
47255
+ const resolved = path77.resolve(filePath);
47256
+ return resolved === parent || resolved.startsWith(`${parent}${path77.sep}`);
47148
47257
  }
47149
47258
  function statMatchesCacheSync(entry) {
47150
47259
  try {
47151
- const stat2 = fs49.statSync(entry.path);
47260
+ const stat2 = fs51.statSync(entry.path);
47152
47261
  return stat2.isFile() && stat2.mtimeMs === entry.mtimeMs && stat2.size === entry.size;
47153
47262
  } catch {
47154
47263
  return false;
@@ -47181,7 +47290,7 @@ function joinInflightResolve(cacheKey, factory) {
47181
47290
  }
47182
47291
 
47183
47292
  // src/files/read/resolve-file-for-read-core.ts
47184
- import fs50 from "node:fs";
47293
+ import fs52 from "node:fs";
47185
47294
  import { isMainThread as isMainThread4 } from "node:worker_threads";
47186
47295
  function resolveFileForReadImplSync(relativePath, sessionParentPath) {
47187
47296
  const cacheKey = resolveCacheKey(sessionParentPath, relativePath);
@@ -47191,13 +47300,13 @@ function resolveFileForReadImplSync(relativePath, sessionParentPath) {
47191
47300
  let size;
47192
47301
  let mtimeMs;
47193
47302
  try {
47194
- const lstat = fs50.lstatSync(resolved);
47303
+ const lstat = fs52.lstatSync(resolved);
47195
47304
  if (lstat.isSymbolicLink()) {
47196
- real = fs50.realpathSync(resolved);
47305
+ real = fs52.realpathSync(resolved);
47197
47306
  if (!pathStaysUnderParent(real, sessionParentPath)) {
47198
47307
  return { error: "Path is outside working directory" };
47199
47308
  }
47200
- const stat2 = fs50.statSync(real);
47309
+ const stat2 = fs52.statSync(real);
47201
47310
  if (!stat2.isFile()) return { error: "Not a file" };
47202
47311
  size = stat2.size;
47203
47312
  mtimeMs = stat2.mtimeMs;
@@ -47225,13 +47334,13 @@ async function resolveFileForReadImpl(relativePath, sessionParentPath) {
47225
47334
  let size;
47226
47335
  let mtimeMs;
47227
47336
  try {
47228
- const lstat = await fs50.promises.lstat(resolved);
47337
+ const lstat = await fs52.promises.lstat(resolved);
47229
47338
  if (lstat.isSymbolicLink()) {
47230
- real = await fs50.promises.realpath(resolved);
47339
+ real = await fs52.promises.realpath(resolved);
47231
47340
  if (!pathStaysUnderParent(real, sessionParentPath)) {
47232
47341
  return { error: "Path is outside working directory" };
47233
47342
  }
47234
- const stat2 = await fs50.promises.stat(real);
47343
+ const stat2 = await fs52.promises.stat(real);
47235
47344
  if (!stat2.isFile()) return { error: "Not a file" };
47236
47345
  size = stat2.size;
47237
47346
  mtimeMs = stat2.mtimeMs;
@@ -47280,7 +47389,7 @@ async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeR
47280
47389
 
47281
47390
  // src/files/read/read-file-range-async.ts
47282
47391
  init_yield_to_event_loop();
47283
- import fs51 from "node:fs";
47392
+ import fs53 from "node:fs";
47284
47393
  import { StringDecoder as StringDecoder2 } from "node:string_decoder";
47285
47394
 
47286
47395
  // src/files/read/read-file-range-line-zero.ts
@@ -47394,8 +47503,8 @@ function finishLineZeroTail(state, tail, resultLines, fileSize, lineChunkSize, l
47394
47503
 
47395
47504
  // src/files/read/read-file-range-async.ts
47396
47505
  async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE, fileSizeIn) {
47397
- const fileSize = fileSizeIn ?? (await fs51.promises.stat(filePath)).size;
47398
- const fd = await fs51.promises.open(filePath, "r");
47506
+ const fileSize = fileSizeIn ?? (await fs53.promises.stat(filePath)).size;
47507
+ const fd = await fs53.promises.open(filePath, "r");
47399
47508
  const bufSize = 64 * 1024;
47400
47509
  const buf = Buffer.alloc(bufSize);
47401
47510
  const decoder = new StringDecoder2("utf8");
@@ -47496,7 +47605,7 @@ async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, li
47496
47605
  }
47497
47606
 
47498
47607
  // src/files/read/read-small-file-range-async.ts
47499
- import fs52 from "node:fs";
47608
+ import fs54 from "node:fs";
47500
47609
  import { isMainThread as isMainThread5 } from "node:worker_threads";
47501
47610
  var SMALL_FILE_RANGE_MAX_BYTES = 512 * 1024;
47502
47611
  function sliceLineRange(lines, startLine, endLine, lineOffsetIn, lineChunkSize, fileSize) {
@@ -47526,7 +47635,7 @@ function sliceLineRange(lines, startLine, endLine, lineOffsetIn, lineChunkSize,
47526
47635
  };
47527
47636
  }
47528
47637
  function readSmallFileRangeSync(filePath, fileSize, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
47529
- const raw = fs52.readFileSync(filePath, "utf8");
47638
+ const raw = fs54.readFileSync(filePath, "utf8");
47530
47639
  const lines = raw.split(/\r?\n/);
47531
47640
  return sliceLineRange(lines, startLine, endLine, lineOffsetIn, lineChunkSize, fileSize);
47532
47641
  }
@@ -47534,28 +47643,28 @@ async function readSmallFileRangeAsync(filePath, fileSize, startLine, endLine, l
47534
47643
  if (isMainThread5) {
47535
47644
  return readSmallFileRangeSync(filePath, fileSize, startLine, endLine, lineOffsetIn, lineChunkSize);
47536
47645
  }
47537
- const raw = await fs52.promises.readFile(filePath, "utf8");
47646
+ const raw = await fs54.promises.readFile(filePath, "utf8");
47538
47647
  const lines = raw.split(/\r?\n/);
47539
47648
  return sliceLineRange(lines, startLine, endLine, lineOffsetIn, lineChunkSize, fileSize);
47540
47649
  }
47541
47650
 
47542
47651
  // src/files/read/read-file-buffer-full-async.ts
47543
47652
  init_yield_to_event_loop();
47544
- import fs53 from "node:fs";
47653
+ import fs55 from "node:fs";
47545
47654
  import { isMainThread as isMainThread6 } from "node:worker_threads";
47546
47655
  var READ_CHUNK_BYTES = 256 * 1024;
47547
47656
  var MAIN_THREAD_SYNC_READ_MAX_BYTES = 512 * 1024;
47548
47657
  async function readFileBufferFullAsync(filePath, knownSize) {
47549
47658
  if (isMainThread6) {
47550
- const size2 = knownSize ?? fs53.statSync(filePath).size;
47659
+ const size2 = knownSize ?? fs55.statSync(filePath).size;
47551
47660
  if (size2 <= MAIN_THREAD_SYNC_READ_MAX_BYTES) {
47552
47661
  await yieldToEventLoop();
47553
- const buffer = fs53.readFileSync(filePath);
47662
+ const buffer = fs55.readFileSync(filePath);
47554
47663
  return { buffer, size: buffer.length };
47555
47664
  }
47556
47665
  }
47557
- const size = knownSize ?? (await fs53.promises.stat(filePath)).size;
47558
- const fd = await fs53.promises.open(filePath, "r");
47666
+ const size = knownSize ?? (await fs55.promises.stat(filePath)).size;
47667
+ const fd = await fs55.promises.open(filePath, "r");
47559
47668
  const chunks = [];
47560
47669
  let position = 0;
47561
47670
  let bytesSinceYield = 0;
@@ -47658,7 +47767,7 @@ async function readFileAsync(relativePath, startLine, endLine, lineOffset, lineC
47658
47767
  }
47659
47768
  if (hasRange) {
47660
47769
  if (fileSize == null) {
47661
- const stat2 = await fs54.promises.stat(resolvedPath);
47770
+ const stat2 = await fs56.promises.stat(resolvedPath);
47662
47771
  fileSize = stat2.size;
47663
47772
  }
47664
47773
  const read2 = fileSize <= SMALL_FILE_RANGE_MAX_BYTES ? await readSmallFileRangeAsync(
@@ -47956,12 +48065,12 @@ function parseOptionalInt2(raw) {
47956
48065
  return Number.isInteger(parsed) ? parsed : void 0;
47957
48066
  }
47958
48067
  function parseCodeNavParams(url2) {
47959
- const path80 = url2.searchParams.get("path") ?? "";
48068
+ const path82 = url2.searchParams.get("path") ?? "";
47960
48069
  const opRaw = url2.searchParams.get("op")?.trim();
47961
48070
  const op = opRaw === "references" ? "references" : opRaw === "symbols" ? "symbols" : opRaw === "definitions" ? "definitions" : "definition";
47962
48071
  const line = parseOptionalInt2(url2.searchParams.get("line")) ?? 1;
47963
48072
  const column = parseOptionalInt2(url2.searchParams.get("column")) ?? 0;
47964
- return { path: path80, op, line, column };
48073
+ return { path: path82, op, line, column };
47965
48074
  }
47966
48075
  function parseCodeNavPath(url2) {
47967
48076
  const raw = url2.searchParams.get("path")?.trim();
@@ -48149,12 +48258,6 @@ function listenOnPort(server, port) {
48149
48258
  });
48150
48259
  });
48151
48260
  }
48152
- function closeServer(server) {
48153
- if (!server) return Promise.resolve();
48154
- return new Promise((resolve35, reject) => {
48155
- server.close((err) => err ? reject(err) : resolve35());
48156
- });
48157
- }
48158
48261
  function delay3(ms) {
48159
48262
  return new Promise((resolve35) => setTimeout(resolve35, ms));
48160
48263
  }
@@ -48179,8 +48282,7 @@ function startLocalShortcutServer(ctx) {
48179
48282
  if (restartAttempts >= MAX_RESTART_ATTEMPTS) return;
48180
48283
  restartAttempts += 1;
48181
48284
  restarting = (async () => {
48182
- await closeServer(currentServer).catch(() => {
48183
- });
48285
+ await closeHttpServer(currentServer);
48184
48286
  currentServer = null;
48185
48287
  if (closed) return;
48186
48288
  await delay3(RESTART_DELAY_MS);
@@ -48200,7 +48302,7 @@ function startLocalShortcutServer(ctx) {
48200
48302
  token: ctx.token,
48201
48303
  close: async () => {
48202
48304
  closed = true;
48203
- await closeServer(currentServer);
48305
+ await closeHttpServer(currentServer);
48204
48306
  currentServer = null;
48205
48307
  }
48206
48308
  }));
@@ -48353,6 +48455,7 @@ var API_TO_BRIDGE_MESSAGE_TYPES = [
48353
48455
  "code_nav",
48354
48456
  "skill_layout_request",
48355
48457
  "install_skills",
48458
+ "install_agent",
48356
48459
  "refresh_local_skills",
48357
48460
  "bridge_git_context_request",
48358
48461
  "list_repo_branches_request"
@@ -48428,6 +48531,100 @@ var handleBridgeHeartbeatAck = (msg, deps) => {
48428
48531
  deps.onBridgeHeartbeatAck?.(Math.trunc(raw));
48429
48532
  };
48430
48533
 
48534
+ // src/routing/dispatch/connection.ts
48535
+ function dispatchBridgeConnectionMessage(msg, deps) {
48536
+ switch (msg.type) {
48537
+ case "auth_token":
48538
+ handleAuthToken(msg, deps);
48539
+ break;
48540
+ case "bridge_identified":
48541
+ handleBridgeIdentified(msg, deps);
48542
+ break;
48543
+ case "ha":
48544
+ handleBridgeHeartbeatAck(msg, deps);
48545
+ break;
48546
+ }
48547
+ }
48548
+
48549
+ // src/routing/handlers/preview-environment-control.ts
48550
+ var handlePreviewEnvironmentControl = (msg, deps) => {
48551
+ let wire;
48552
+ try {
48553
+ wire = deps.e2ee ? deps.e2ee.decryptMessage(msg) : msg;
48554
+ } catch (e) {
48555
+ deps.log(`[E2EE] Could not decrypt preview environment command: ${e instanceof Error ? e.message : String(e)}`);
48556
+ return;
48557
+ }
48558
+ const environmentId = typeof wire.environmentId === "string" ? wire.environmentId : "";
48559
+ const action = wire.action === "start" || wire.action === "stop" ? wire.action : null;
48560
+ if (!environmentId || !action) return;
48561
+ deps.previewEnvironmentManager?.handleControl(environmentId, action);
48562
+ };
48563
+
48564
+ // src/routing/handlers/preview-environments-config.ts
48565
+ var VALID_PORT = (p) => typeof p === "number" && Number.isInteger(p) && p > 0 && p < 65536;
48566
+ var handlePreviewEnvironmentsConfig = (msg, deps) => {
48567
+ const previewEnvironments = msg.previewEnvironments;
48568
+ const proxyPorts = Array.isArray(msg.proxyPorts) ? msg.proxyPorts.filter(VALID_PORT) : void 0;
48569
+ setImmediate(() => {
48570
+ deps.previewEnvironmentManager?.applyConfig(previewEnvironments ?? []);
48571
+ const environmentIds = parsePreviewEnvironmentDefs(previewEnvironments ?? []).map((d) => d.environmentId);
48572
+ void deps.previewWorktreeManager?.syncConfiguredEnvironments(environmentIds);
48573
+ if (proxyPorts !== void 0) {
48574
+ deps.updateFirehoseProxyPorts?.(proxyPorts);
48575
+ }
48576
+ });
48577
+ };
48578
+
48579
+ // src/routing/handlers/send-deploy-session-to-preview-result.ts
48580
+ function sendDeploySessionToPreviewResult(ws, id, payload) {
48581
+ if (!ws) return;
48582
+ sendWsMessage(ws, { type: "deploy_session_to_preview_result", id, ...payload });
48583
+ }
48584
+
48585
+ // src/routing/handlers/deploy-session-to-preview.ts
48586
+ var handleDeploySessionToPreviewMessage = (msg, deps) => {
48587
+ if (typeof msg.id !== "string") return;
48588
+ const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
48589
+ const environmentId = typeof msg.environmentId === "string" ? msg.environmentId : "";
48590
+ if (!sessionId || !environmentId) return;
48591
+ void (async () => {
48592
+ const ws = deps.getWs();
48593
+ const reply = (payload) => sendDeploySessionToPreviewResult(ws, msg.id, payload);
48594
+ try {
48595
+ if (!deps.previewWorktreeManager) {
48596
+ reply({ ok: false, error: "Preview worktree manager unavailable" });
48597
+ return;
48598
+ }
48599
+ const result = await deploySessionToPreviewEnvironment({
48600
+ sessionWorktreeManager: deps.sessionWorktreeManager,
48601
+ previewWorktreeManager: deps.previewWorktreeManager,
48602
+ sessionId,
48603
+ environmentId,
48604
+ log: deps.log
48605
+ });
48606
+ reply(result);
48607
+ } catch (e) {
48608
+ reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
48609
+ }
48610
+ })();
48611
+ };
48612
+
48613
+ // src/routing/dispatch/preview.ts
48614
+ function dispatchBridgePreviewMessage(msg, deps) {
48615
+ switch (msg.type) {
48616
+ case "preview_environments_config":
48617
+ handlePreviewEnvironmentsConfig(msg, deps);
48618
+ break;
48619
+ case "preview_environment_control":
48620
+ handlePreviewEnvironmentControl(msg, deps);
48621
+ break;
48622
+ case "deploy_session_to_preview":
48623
+ handleDeploySessionToPreviewMessage(msg, deps);
48624
+ break;
48625
+ }
48626
+ }
48627
+
48431
48628
  // src/agents/acp/from-bridge/handle-bridge-agent-config.ts
48432
48629
  function handleBridgeAgentConfig(msg, { acpManager }) {
48433
48630
  if (!Array.isArray(msg.agents) || msg.agents.length === 0) return;
@@ -48577,15 +48774,15 @@ function syncRunningTurnQueueKeys(turns, queueKey) {
48577
48774
  }
48578
48775
 
48579
48776
  // src/prompt-turn-queue/runner/run-local-revert-before-queued-prompt.ts
48580
- import fs56 from "node:fs";
48777
+ import fs58 from "node:fs";
48581
48778
 
48582
48779
  // src/git/snapshot/capture.ts
48583
- import * as fs55 from "node:fs";
48584
- import * as path76 from "node:path";
48780
+ import * as fs57 from "node:fs";
48781
+ import * as path78 from "node:path";
48585
48782
  async function resolveSnapshotRepoRoots(options) {
48586
48783
  const { worktreePaths, fallbackCwd, sessionId, log: log2 } = options;
48587
48784
  if (worktreePaths?.length) {
48588
- const uniq = [...new Set(worktreePaths.map((p) => path76.resolve(p)))];
48785
+ const uniq = [...new Set(worktreePaths.map((p) => path78.resolve(p)))];
48589
48786
  return uniq;
48590
48787
  }
48591
48788
  try {
@@ -48593,7 +48790,7 @@ async function resolveSnapshotRepoRoots(options) {
48593
48790
  const mapped = repos.map((r) => r.absolutePath);
48594
48791
  const sid = sessionId?.trim();
48595
48792
  if (sid) {
48596
- const filtered = mapped.filter((root) => path76.basename(root) === sid);
48793
+ const filtered = mapped.filter((root) => path78.basename(root) === sid);
48597
48794
  if (filtered.length > 0) return filtered;
48598
48795
  }
48599
48796
  return mapped;
@@ -48615,7 +48812,7 @@ async function capturePreTurnSnapshot(options) {
48615
48812
  });
48616
48813
  const dir = snapshotsDirForCwd(agentCwd);
48617
48814
  try {
48618
- fs55.mkdirSync(dir, { recursive: true });
48815
+ fs57.mkdirSync(dir, { recursive: true });
48619
48816
  } catch (e) {
48620
48817
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
48621
48818
  }
@@ -48624,9 +48821,9 @@ async function capturePreTurnSnapshot(options) {
48624
48821
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
48625
48822
  repos
48626
48823
  };
48627
- const filePath = path76.join(dir, `${runId}.json`);
48824
+ const filePath = path78.join(dir, `${runId}.json`);
48628
48825
  try {
48629
- fs55.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
48826
+ fs57.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
48630
48827
  } catch (e) {
48631
48828
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
48632
48829
  }
@@ -48639,7 +48836,7 @@ async function capturePreTurnSnapshot(options) {
48639
48836
  async function applyPreTurnSnapshot(filePath, log2) {
48640
48837
  let data;
48641
48838
  try {
48642
- const raw = fs55.readFileSync(filePath, "utf8");
48839
+ const raw = fs57.readFileSync(filePath, "utf8");
48643
48840
  data = JSON.parse(raw);
48644
48841
  } catch (e) {
48645
48842
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
@@ -48679,7 +48876,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
48679
48876
  const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
48680
48877
  const file2 = snapshotFilePath(agentBase, tid);
48681
48878
  try {
48682
- await fs56.promises.access(file2, fs56.constants.F_OK);
48879
+ await fs58.promises.access(file2, fs58.constants.F_OK);
48683
48880
  } catch {
48684
48881
  deps.log(
48685
48882
  `[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
@@ -49066,290 +49263,6 @@ var handleSessionRequestResponseMessage = (msg, deps) => {
49066
49263
  handleBridgeSessionRequestResponse(msg, deps);
49067
49264
  };
49068
49265
 
49069
- // src/skills/handle-skill-call.ts
49070
- function handleSkillCall(msg, socket, log2) {
49071
- callSkill(msg.skillId, msg.operationId, msg.params ?? {}).then((result) => {
49072
- sendWsMessage(socket, { type: "skill_result", id: msg.id, result });
49073
- }).catch((err) => {
49074
- sendWsMessage(socket, { type: "skill_result", id: msg.id, error: String(err) });
49075
- log2(`[Bridge service] Skill invocation failed (${msg.skillId}/${msg.operationId}): ${err}`);
49076
- });
49077
- }
49078
-
49079
- // src/routing/handlers/skill-call.ts
49080
- var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
49081
- const skillId = typeof msg.skillId === "string" ? msg.skillId : "";
49082
- const operationId = typeof msg.operationId === "string" ? msg.operationId : "";
49083
- if (!skillId || !operationId) return;
49084
- const socket = getWs();
49085
- if (!socket) return;
49086
- handleSkillCall(
49087
- { id: msg.id, skillId, operationId, params: msg.params },
49088
- socket,
49089
- log2
49090
- );
49091
- };
49092
-
49093
- // src/files/browser/send-file-browser-message.ts
49094
- function sendFileBrowserMessage(socket, e2ee, payload) {
49095
- sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["entries", "content", "totalLines", "size", "lineOffset"]) : payload);
49096
- }
49097
-
49098
- // src/files/browser/handle-file-browser-list.ts
49099
- async function handleFileBrowserList(socket, e2ee, id, reqPath, sessionParentPath, gitScope) {
49100
- const result = await executeFileBrowserList({ reqPath, sessionParentPath, gitScope });
49101
- if ("error" in result) {
49102
- sendWsMessage(socket, { type: "file_browser_response", id, error: result.error });
49103
- return;
49104
- }
49105
- sendFileBrowserMessage(socket, e2ee, { type: "file_browser_response", id, entries: result.entries });
49106
- }
49107
-
49108
- // src/files/browser/handle-file-browser-read.ts
49109
- async function handleFileBrowserRead(socket, e2ee, msg, reqPath, sessionParentPath, gitScope) {
49110
- const result = await executeFileBrowserRead({ msg, reqPath, sessionParentPath, gitScope });
49111
- if ("error" in result) {
49112
- sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: result.error });
49113
- return;
49114
- }
49115
- const payload = {
49116
- type: "file_browser_response",
49117
- id: msg.id,
49118
- content: result.content,
49119
- totalLines: result.totalLines,
49120
- size: result.size
49121
- };
49122
- if (result.lineOffset != null) payload.lineOffset = result.lineOffset;
49123
- if (result.mimeType != null) payload.mimeType = result.mimeType;
49124
- if (result.resolvedPath != null) payload.resolvedPath = result.resolvedPath;
49125
- sendFileBrowserMessage(socket, e2ee, payload);
49126
- }
49127
-
49128
- // src/files/browser/index.ts
49129
- init_in_flight();
49130
- function handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager) {
49131
- beginFileBrowserRequest();
49132
- void (async () => {
49133
- try {
49134
- const reqPath = msg.path.replace(/^\/+/, "") || ".";
49135
- const sessionParentPath = sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : void 0;
49136
- const gitScope = resolveGitBranchScope(msg);
49137
- if (msg.source === "git_branch" && typeof msg.repoRelPath === "string" && typeof msg.branch === "string" && msg.branch.trim().length > 0 && !gitScope) {
49138
- sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: "Invalid repository path" });
49139
- return;
49140
- }
49141
- if (msg.op === "read") {
49142
- await handleFileBrowserRead(socket, e2ee, msg, reqPath, sessionParentPath, gitScope);
49143
- } else {
49144
- await handleFileBrowserList(socket, e2ee, msg.id, reqPath, sessionParentPath, gitScope);
49145
- }
49146
- } finally {
49147
- endFileBrowserRequest();
49148
- }
49149
- })();
49150
- }
49151
-
49152
- // src/files/handle-file-browser-search.ts
49153
- init_yield_to_event_loop();
49154
- import path77 from "node:path";
49155
- var SEARCH_LIMIT = 100;
49156
- function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
49157
- void (async () => {
49158
- await yieldToEventLoop();
49159
- const q = typeof msg.q === "string" ? msg.q : "";
49160
- const sessionParentPath = path77.resolve(
49161
- sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
49162
- );
49163
- if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
49164
- triggerFileIndexBuild(sessionParentPath);
49165
- const payload2 = {
49166
- type: "file_browser_search_response",
49167
- id: msg.id,
49168
- paths: [],
49169
- indexReady: false
49170
- };
49171
- sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload2, ["paths"]) : payload2);
49172
- return;
49173
- }
49174
- const results = await searchBridgeFilePathsAsync(sessionParentPath, q, SEARCH_LIMIT);
49175
- const payload = {
49176
- type: "file_browser_search_response",
49177
- id: msg.id,
49178
- paths: results,
49179
- indexReady: true
49180
- };
49181
- sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["paths"]) : payload);
49182
- })();
49183
- }
49184
- function triggerFileIndexBuild(sessionParentPath = getBridgeRoot()) {
49185
- setImmediate(() => {
49186
- void ensureFileIndexAsync(sessionParentPath).catch((e) => {
49187
- console.error("[file-index] Background build failed:", e);
49188
- });
49189
- });
49190
- }
49191
-
49192
- // src/routing/handlers/file-browser-messages.ts
49193
- function handleFileBrowserRequestMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
49194
- if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
49195
- const socket = getWs();
49196
- if (!socket) return;
49197
- handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager);
49198
- }
49199
- function handleFileBrowserSearchMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
49200
- if (typeof msg.id !== "string") return;
49201
- const socket = getWs();
49202
- if (!socket) return;
49203
- handleFileBrowserSearch(
49204
- msg,
49205
- socket,
49206
- e2ee,
49207
- sessionWorktreeManager
49208
- );
49209
- }
49210
-
49211
- // src/code-nav/handlers/send-code-nav-response.ts
49212
- var ENCRYPTED_FIELDS = ["definition", "definitions", "references", "symbols", "confidentTarget"];
49213
- function sendCodeNavResponse(socket, e2ee, payload) {
49214
- const fieldsToEncrypt = ENCRYPTED_FIELDS.filter((field) => field in payload && payload[field] !== void 0);
49215
- sendWsMessage(
49216
- socket,
49217
- e2ee && fieldsToEncrypt.length > 0 ? e2ee.encryptFields(payload, [...fieldsToEncrypt]) : payload
49218
- );
49219
- }
49220
-
49221
- // src/code-nav/handlers/handle-code-nav-request.ts
49222
- function handleCodeNavRequest(msg, socket, e2ee, sessionWorktreeManager) {
49223
- void (async () => {
49224
- const body = await executeCodeNavRequest(msg, sessionWorktreeManager);
49225
- sendCodeNavResponse(socket, e2ee, {
49226
- type: "code_nav_response",
49227
- id: msg.id,
49228
- ...body
49229
- });
49230
- })();
49231
- }
49232
-
49233
- // src/code-nav/handlers/trigger-symbol-index-build.ts
49234
- init_normalize_resolved_path();
49235
-
49236
- // src/routing/handlers/code-nav-messages.ts
49237
- function handleFileBrowserCodeNavMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
49238
- if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
49239
- const socket = getWs();
49240
- if (!socket) return;
49241
- handleCodeNavRequest(
49242
- {
49243
- id: msg.id,
49244
- type: "code_nav",
49245
- op: msg.op === "references" ? "references" : msg.op === "symbols" ? "symbols" : msg.op === "definitions" ? "definitions" : "definition",
49246
- path: msg.path,
49247
- line: typeof msg.line === "number" ? msg.line : 1,
49248
- column: typeof msg.column === "number" ? msg.column : 0,
49249
- sessionId: msg.sessionId
49250
- },
49251
- socket,
49252
- e2ee,
49253
- sessionWorktreeManager
49254
- );
49255
- }
49256
-
49257
- // src/routing/handlers/skill-layout-request.ts
49258
- function handleSkillLayoutRequest(msg, deps) {
49259
- const id = typeof msg.id === "string" ? msg.id : "";
49260
- void (async () => {
49261
- const socket = deps.getWs();
49262
- const roots = await discoverSkillLayoutRootsAsync(getBridgeRoot());
49263
- if (socket) {
49264
- sendWsMessage(socket, { type: "skill_layout_response", id, roots });
49265
- }
49266
- })();
49267
- }
49268
-
49269
- // src/skills/install/is-valid-install-item.ts
49270
- function isValidRemoteSkillInstallItem(item) {
49271
- if (item === null || typeof item !== "object") return false;
49272
- const o = item;
49273
- return typeof o.sourceId === "string" && typeof o.skillName === "string" && typeof o.versionHash === "string" && Array.isArray(o.files);
49274
- }
49275
-
49276
- // src/skills/install/install-remote-skills-async.ts
49277
- init_yield_to_event_loop();
49278
- import fs57 from "node:fs";
49279
- import path78 from "node:path";
49280
-
49281
- // src/skills/install/constants.ts
49282
- var INSTALL_SKILLS_YIELD_EVERY = 16;
49283
-
49284
- // src/skills/install/install-remote-skills-async.ts
49285
- async function writeInstallFileAsync(skillDir, f, filesWritten) {
49286
- if (typeof f.path !== "string" || !f.text && !f.base64) return;
49287
- if (++filesWritten.count % INSTALL_SKILLS_YIELD_EVERY === 0) {
49288
- await yieldToEventLoop();
49289
- }
49290
- const dest = path78.join(skillDir, f.path);
49291
- await fs57.promises.mkdir(path78.dirname(dest), { recursive: true });
49292
- if (f.text !== void 0) {
49293
- await fs57.promises.writeFile(dest, f.text, "utf8");
49294
- } else if (f.base64) {
49295
- await fs57.promises.writeFile(dest, Buffer.from(f.base64, "base64"));
49296
- }
49297
- }
49298
- async function installRemoteSkillsAsync(cwd, targetDir, items) {
49299
- const installed2 = [];
49300
- if (!Array.isArray(items)) {
49301
- return { success: false, error: "Invalid items" };
49302
- }
49303
- const filesWritten = { count: 0 };
49304
- try {
49305
- for (const item of items) {
49306
- if (!isValidRemoteSkillInstallItem(item)) continue;
49307
- const skillDir = path78.join(cwd, targetDir, item.skillName);
49308
- for (const f of item.files) {
49309
- await writeInstallFileAsync(skillDir, f, filesWritten);
49310
- }
49311
- installed2.push({
49312
- sourceId: item.sourceId,
49313
- skillName: item.skillName,
49314
- versionHash: item.versionHash
49315
- });
49316
- }
49317
- return { success: true, installed: installed2 };
49318
- } catch (e) {
49319
- return { success: false, error: e instanceof Error ? e.message : String(e) };
49320
- }
49321
- }
49322
-
49323
- // src/routing/handlers/install-skills.ts
49324
- var handleInstallSkillsMessage = (msg, deps) => {
49325
- const id = typeof msg.id === "string" ? msg.id : "";
49326
- const targetDir = typeof msg.targetDir === "string" && msg.targetDir.trim() ? msg.targetDir.trim() : ".agents/skills";
49327
- const rawItems = msg.items;
49328
- const cwd = getBridgeRoot();
49329
- void (async () => {
49330
- const socket = deps.getWs();
49331
- const result = await installRemoteSkillsAsync(cwd, targetDir, rawItems);
49332
- if (!result.success) {
49333
- const err = result.error ?? "Invalid items";
49334
- deps.log(`[Bridge service] Install skills failed: ${err}`);
49335
- if (socket) {
49336
- sendWsMessage(socket, { type: "install_skills_result", id, success: false, error: err });
49337
- }
49338
- return;
49339
- }
49340
- if (socket) {
49341
- sendWsMessage(socket, { type: "install_skills_result", id, success: true, installed: result.installed });
49342
- }
49343
- })();
49344
- };
49345
-
49346
- // src/routing/handlers/refresh-local-skills.ts
49347
- var handleRefreshLocalSkills = (_msg, deps) => {
49348
- setImmediate(() => {
49349
- deps.sendLocalSkillsReport?.();
49350
- });
49351
- };
49352
-
49353
49266
  // src/routing/handlers/git/handle-session-git-commit.ts
49354
49267
  async function handleSessionGitCommitAction(deps, sessionId, msg, reply) {
49355
49268
  const branch = typeof msg.branch === "string" ? msg.branch : "";
@@ -49586,7 +49499,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
49586
49499
  };
49587
49500
 
49588
49501
  // src/routing/handlers/revert-turn-snapshot.ts
49589
- import * as fs58 from "node:fs";
49502
+ import * as fs59 from "node:fs";
49590
49503
  var handleRevertTurnSnapshotMessage = (msg, deps) => {
49591
49504
  const id = typeof msg.id === "string" ? msg.id : "";
49592
49505
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
@@ -49599,7 +49512,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
49599
49512
  const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
49600
49513
  const file2 = snapshotFilePath(agentBase, turnId);
49601
49514
  try {
49602
- await fs58.promises.access(file2, fs58.constants.F_OK);
49515
+ await fs59.promises.access(file2, fs59.constants.F_OK);
49603
49516
  } catch {
49604
49517
  sendWsMessage(s, {
49605
49518
  type: "revert_turn_snapshot_result",
@@ -49619,72 +49532,490 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
49619
49532
  })();
49620
49533
  };
49621
49534
 
49622
- // src/routing/handlers/preview-environment-control.ts
49623
- var handlePreviewEnvironmentControl = (msg, deps) => {
49624
- let wire;
49535
+ // src/routing/dispatch/session.ts
49536
+ function dispatchBridgeSessionMessage(msg, deps) {
49537
+ switch (msg.type) {
49538
+ case "agent_config":
49539
+ handleAgentConfigMessage(msg, deps);
49540
+ break;
49541
+ case "prompt_queue_state":
49542
+ handlePromptQueueStateMessage(msg, deps);
49543
+ break;
49544
+ case "prompt":
49545
+ handlePromptMessage(msg, deps);
49546
+ break;
49547
+ case "session_git_request":
49548
+ handleSessionGitRequestMessage(msg, deps);
49549
+ break;
49550
+ case "rename_session_branch":
49551
+ handleRenameSessionBranchMessage(msg, deps);
49552
+ break;
49553
+ case "session_archived":
49554
+ handleSessionArchivedMessage(msg, deps);
49555
+ break;
49556
+ case "session_discarded":
49557
+ handleSessionDiscardedMessage(msg, deps);
49558
+ break;
49559
+ case "revert_turn_snapshot":
49560
+ handleRevertTurnSnapshotMessage(msg, deps);
49561
+ break;
49562
+ case "cursor_request_response":
49563
+ handleSessionRequestResponseMessage(msg, deps);
49564
+ break;
49565
+ }
49566
+ }
49567
+
49568
+ // src/skills/handle-skill-call.ts
49569
+ function handleSkillCall(msg, socket, log2) {
49570
+ callSkill(msg.skillId, msg.operationId, msg.params ?? {}).then((result) => {
49571
+ sendWsMessage(socket, { type: "skill_result", id: msg.id, result });
49572
+ }).catch((err) => {
49573
+ sendWsMessage(socket, { type: "skill_result", id: msg.id, error: String(err) });
49574
+ log2(`[Bridge service] Skill invocation failed (${msg.skillId}/${msg.operationId}): ${err}`);
49575
+ });
49576
+ }
49577
+
49578
+ // src/routing/handlers/skill-call.ts
49579
+ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
49580
+ const skillId = typeof msg.skillId === "string" ? msg.skillId : "";
49581
+ const operationId = typeof msg.operationId === "string" ? msg.operationId : "";
49582
+ if (!skillId || !operationId) return;
49583
+ const socket = getWs();
49584
+ if (!socket) return;
49585
+ handleSkillCall(
49586
+ { id: msg.id, skillId, operationId, params: msg.params },
49587
+ socket,
49588
+ log2
49589
+ );
49590
+ };
49591
+
49592
+ // src/routing/handlers/skill-layout-request.ts
49593
+ function handleSkillLayoutRequest(msg, deps) {
49594
+ const id = typeof msg.id === "string" ? msg.id : "";
49595
+ void (async () => {
49596
+ const socket = deps.getWs();
49597
+ const roots = await discoverSkillLayoutRootsAsync(getBridgeRoot());
49598
+ if (socket) {
49599
+ sendWsMessage(socket, { type: "skill_layout_response", id, roots });
49600
+ }
49601
+ })();
49602
+ }
49603
+
49604
+ // src/skills/install/is-valid-install-item.ts
49605
+ function isValidRemoteSkillInstallItem(item) {
49606
+ if (item === null || typeof item !== "object") return false;
49607
+ const o = item;
49608
+ return typeof o.sourceId === "string" && typeof o.skillName === "string" && typeof o.versionHash === "string" && Array.isArray(o.files);
49609
+ }
49610
+
49611
+ // src/skills/install/install-remote-skills-async.ts
49612
+ init_yield_to_event_loop();
49613
+ import fs60 from "node:fs";
49614
+ import path79 from "node:path";
49615
+
49616
+ // src/skills/install/constants.ts
49617
+ var INSTALL_SKILLS_YIELD_EVERY = 16;
49618
+
49619
+ // src/skills/install/install-remote-skills-async.ts
49620
+ async function writeInstallFileAsync(skillDir, f, filesWritten) {
49621
+ if (typeof f.path !== "string" || !f.text && !f.base64) return;
49622
+ if (++filesWritten.count % INSTALL_SKILLS_YIELD_EVERY === 0) {
49623
+ await yieldToEventLoop();
49624
+ }
49625
+ const dest = path79.join(skillDir, f.path);
49626
+ await fs60.promises.mkdir(path79.dirname(dest), { recursive: true });
49627
+ if (f.text !== void 0) {
49628
+ await fs60.promises.writeFile(dest, f.text, "utf8");
49629
+ } else if (f.base64) {
49630
+ await fs60.promises.writeFile(dest, Buffer.from(f.base64, "base64"));
49631
+ }
49632
+ }
49633
+ async function installRemoteSkillsAsync(cwd, targetDir, items) {
49634
+ const installed2 = [];
49635
+ if (!Array.isArray(items)) {
49636
+ return { success: false, error: "Invalid items" };
49637
+ }
49638
+ const filesWritten = { count: 0 };
49625
49639
  try {
49626
- wire = deps.e2ee ? deps.e2ee.decryptMessage(msg) : msg;
49640
+ for (const item of items) {
49641
+ if (!isValidRemoteSkillInstallItem(item)) continue;
49642
+ const skillDir = path79.join(cwd, targetDir, item.skillName);
49643
+ for (const f of item.files) {
49644
+ await writeInstallFileAsync(skillDir, f, filesWritten);
49645
+ }
49646
+ installed2.push({
49647
+ sourceId: item.sourceId,
49648
+ skillName: item.skillName,
49649
+ versionHash: item.versionHash
49650
+ });
49651
+ }
49652
+ return { success: true, installed: installed2 };
49627
49653
  } catch (e) {
49628
- deps.log(`[E2EE] Could not decrypt preview environment command: ${e instanceof Error ? e.message : String(e)}`);
49629
- return;
49654
+ return { success: false, error: e instanceof Error ? e.message : String(e) };
49630
49655
  }
49631
- const environmentId = typeof wire.environmentId === "string" ? wire.environmentId : "";
49632
- const action = wire.action === "start" || wire.action === "stop" ? wire.action : null;
49633
- if (!environmentId || !action) return;
49634
- deps.previewEnvironmentManager?.handleControl(environmentId, action);
49656
+ }
49657
+
49658
+ // src/routing/handlers/install-skills.ts
49659
+ var handleInstallSkillsMessage = (msg, deps) => {
49660
+ const id = typeof msg.id === "string" ? msg.id : "";
49661
+ const targetDir = typeof msg.targetDir === "string" && msg.targetDir.trim() ? msg.targetDir.trim() : ".agents/skills";
49662
+ const rawItems = msg.items;
49663
+ const cwd = getBridgeRoot();
49664
+ void (async () => {
49665
+ const socket = deps.getWs();
49666
+ const result = await installRemoteSkillsAsync(cwd, targetDir, rawItems);
49667
+ if (!result.success) {
49668
+ const err = result.error ?? "Invalid items";
49669
+ deps.log(`[Bridge service] Install skills failed: ${err}`);
49670
+ if (socket) {
49671
+ sendWsMessage(socket, { type: "install_skills_result", id, success: false, error: err });
49672
+ }
49673
+ return;
49674
+ }
49675
+ if (socket) {
49676
+ sendWsMessage(socket, { type: "install_skills_result", id, success: true, installed: result.installed });
49677
+ }
49678
+ })();
49635
49679
  };
49636
49680
 
49637
- // src/routing/handlers/preview-environments-config.ts
49638
- var VALID_PORT = (p) => typeof p === "number" && Number.isInteger(p) && p > 0 && p < 65536;
49639
- var handlePreviewEnvironmentsConfig = (msg, deps) => {
49640
- const previewEnvironments = msg.previewEnvironments;
49641
- const proxyPorts = Array.isArray(msg.proxyPorts) ? msg.proxyPorts.filter(VALID_PORT) : void 0;
49642
- setImmediate(() => {
49643
- deps.previewEnvironmentManager?.applyConfig(previewEnvironments ?? []);
49644
- const environmentIds = parsePreviewEnvironmentDefs(previewEnvironments ?? []).map((d) => d.environmentId);
49645
- void deps.previewWorktreeManager?.syncConfiguredEnvironments(environmentIds);
49646
- if (proxyPorts !== void 0) {
49647
- deps.updateFirehoseProxyPorts?.(proxyPorts);
49681
+ // src/agents/install/commands/run-npm-global-install.ts
49682
+ import { execFile as execFile9 } from "node:child_process";
49683
+ import { promisify as promisify10 } from "node:util";
49684
+ var execFileAsync8 = promisify10(execFile9);
49685
+ async function runNpmGlobalInstall(packageName, env, timeoutMs = 3e5) {
49686
+ await execFileAsync8("npm", ["install", "-g", packageName], { timeout: timeoutMs, env });
49687
+ }
49688
+
49689
+ // src/agents/install/commands/claude-code.ts
49690
+ var claudeCodeInstallCommand = {
49691
+ agentType: "claude-code",
49692
+ detectCommand: "claude",
49693
+ async install(ctx) {
49694
+ ctx.onProgress?.("Installing Anthropic Claude Code");
49695
+ await runNpmGlobalInstall("@anthropic-ai/claude-code", {
49696
+ ...ctx.env,
49697
+ ANTHROPIC_API_KEY: ctx.authToken
49698
+ });
49699
+ }
49700
+ };
49701
+
49702
+ // src/agents/install/commands/codex-acp.ts
49703
+ var codexAcpInstallCommand = {
49704
+ agentType: "codex-acp",
49705
+ detectCommand: "codex",
49706
+ async install(ctx) {
49707
+ ctx.onProgress?.("Installing Codex");
49708
+ await runNpmGlobalInstall("@openai/codex", {
49709
+ ...ctx.env,
49710
+ OPENAI_API_KEY: ctx.authToken
49711
+ });
49712
+ }
49713
+ };
49714
+
49715
+ // src/agents/install/commands/cursor-cli.ts
49716
+ import { execFile as execFile10 } from "node:child_process";
49717
+ import { promisify as promisify11 } from "node:util";
49718
+ var execFileAsync9 = promisify11(execFile10);
49719
+ var cursorCliInstallCommand = {
49720
+ agentType: "cursor-cli",
49721
+ detectCommand: "agent",
49722
+ async install(ctx) {
49723
+ ctx.onProgress?.("Installing Cursor CLI");
49724
+ await execFileAsync9("bash", ["-lc", "curl -fsSL https://cursor.com/install | bash"], {
49725
+ timeout: 3e5,
49726
+ env: { ...ctx.env, CURSOR_API_KEY: ctx.authToken }
49727
+ });
49728
+ }
49729
+ };
49730
+
49731
+ // src/agents/install/commands/opencode.ts
49732
+ var opencodeInstallCommand = {
49733
+ agentType: "opencode",
49734
+ detectCommand: "opencode",
49735
+ async install(ctx) {
49736
+ ctx.onProgress?.("Installing OpenCode");
49737
+ await runNpmGlobalInstall("opencode-ai", {
49738
+ ...ctx.env,
49739
+ OPENCODE_API_KEY: ctx.authToken
49740
+ });
49741
+ }
49742
+ };
49743
+
49744
+ // src/agents/install/commands/index.ts
49745
+ var COMMANDS = [
49746
+ claudeCodeInstallCommand,
49747
+ codexAcpInstallCommand,
49748
+ cursorCliInstallCommand,
49749
+ opencodeInstallCommand
49750
+ ];
49751
+ var byType = new Map(COMMANDS.map((c) => [c.agentType, c]));
49752
+ function getAgentInstallCommand(agentType) {
49753
+ return byType.get(agentType);
49754
+ }
49755
+
49756
+ // src/agents/install/install-local-agent.ts
49757
+ async function installLocalAgentOnBridge(params) {
49758
+ const spec = INSTALLABLE_BRIDGE_AGENTS.find((a) => a.value === params.agentType);
49759
+ if (!spec) return { success: false, error: `Unsupported agent type: ${params.agentType}` };
49760
+ const command = getAgentInstallCommand(params.agentType);
49761
+ if (!command) return { success: false, error: `No install command for ${params.agentType}` };
49762
+ params.onProgress?.(`Configuring ${spec.label} credentials`);
49763
+ try {
49764
+ await command.install({
49765
+ authToken: params.authToken,
49766
+ onProgress: params.onProgress,
49767
+ env: { ...process.env, [spec.tokenEnvVar]: params.authToken }
49768
+ });
49769
+ } catch (e) {
49770
+ const msg = e instanceof Error ? e.message : String(e);
49771
+ return { success: false, error: msg };
49772
+ }
49773
+ const found = await isCommandOnPath(command.detectCommand);
49774
+ if (!found) {
49775
+ return { success: false, error: `${command.detectCommand} not found on PATH after install` };
49776
+ }
49777
+ return { success: true };
49778
+ }
49779
+
49780
+ // src/routing/handlers/install-agent.ts
49781
+ var handleInstallAgentMessage = (msg, deps) => {
49782
+ const processId = typeof msg.processId === "string" ? msg.processId : "";
49783
+ const agentId = typeof msg.agentId === "string" ? msg.agentId : "";
49784
+ const tokenId = typeof msg.tokenId === "string" ? msg.tokenId : "";
49785
+ const agentType = typeof msg.agentType === "string" ? msg.agentType : "";
49786
+ const authToken = typeof msg.authToken === "string" ? msg.authToken : "";
49787
+ if (!processId || !agentId || !tokenId || !agentType || !authToken) return;
49788
+ void (async () => {
49789
+ const socket = deps.getWs();
49790
+ const report = (step, message) => {
49791
+ if (socket) {
49792
+ sendWsMessage(socket, {
49793
+ type: "install_agent_progress",
49794
+ processId,
49795
+ agentId,
49796
+ tokenId,
49797
+ agentType,
49798
+ step,
49799
+ message
49800
+ });
49801
+ }
49802
+ };
49803
+ const result = await installLocalAgentOnBridge({
49804
+ agentType,
49805
+ authToken,
49806
+ onProgress: (message) => report("agent_install_package", message)
49807
+ });
49808
+ if (socket) {
49809
+ sendWsMessage(socket, {
49810
+ type: "install_agent_result",
49811
+ processId,
49812
+ agentId,
49813
+ tokenId,
49814
+ agentType,
49815
+ success: result.success,
49816
+ error: result.error
49817
+ });
49818
+ }
49819
+ if (!result.success) {
49820
+ deps.log(`[Bridge service] Install agent failed: ${result.error ?? "unknown"}`);
49648
49821
  }
49822
+ })();
49823
+ };
49824
+
49825
+ // src/routing/handlers/refresh-local-skills.ts
49826
+ var handleRefreshLocalSkills = (_msg, deps) => {
49827
+ setImmediate(() => {
49828
+ deps.sendLocalSkillsReport?.();
49649
49829
  });
49650
49830
  };
49651
49831
 
49652
- // src/routing/handlers/send-deploy-session-to-preview-result.ts
49653
- function sendDeploySessionToPreviewResult(ws, id, payload) {
49654
- if (!ws) return;
49655
- sendWsMessage(ws, { type: "deploy_session_to_preview_result", id, ...payload });
49832
+ // src/routing/dispatch/skills.ts
49833
+ function dispatchBridgeSkillsMessage(msg, deps) {
49834
+ switch (msg.type) {
49835
+ case "skill_call":
49836
+ handleSkillCallMessage(msg, deps);
49837
+ break;
49838
+ case "skill_layout_request":
49839
+ handleSkillLayoutRequest(msg, deps);
49840
+ break;
49841
+ case "install_skills":
49842
+ handleInstallSkillsMessage(msg, deps);
49843
+ break;
49844
+ case "install_agent":
49845
+ handleInstallAgentMessage(msg, deps);
49846
+ break;
49847
+ case "refresh_local_skills":
49848
+ handleRefreshLocalSkills(msg, deps);
49849
+ break;
49850
+ }
49656
49851
  }
49657
49852
 
49658
- // src/routing/handlers/deploy-session-to-preview.ts
49659
- var handleDeploySessionToPreviewMessage = (msg, deps) => {
49660
- if (typeof msg.id !== "string") return;
49661
- const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
49662
- const environmentId = typeof msg.environmentId === "string" ? msg.environmentId : "";
49663
- if (!sessionId || !environmentId) return;
49853
+ // src/files/browser/send-file-browser-message.ts
49854
+ function sendFileBrowserMessage(socket, e2ee, payload) {
49855
+ sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["entries", "content", "totalLines", "size", "lineOffset"]) : payload);
49856
+ }
49857
+
49858
+ // src/files/browser/handle-file-browser-list.ts
49859
+ async function handleFileBrowserList(socket, e2ee, id, reqPath, sessionParentPath, gitScope) {
49860
+ const result = await executeFileBrowserList({ reqPath, sessionParentPath, gitScope });
49861
+ if ("error" in result) {
49862
+ sendWsMessage(socket, { type: "file_browser_response", id, error: result.error });
49863
+ return;
49864
+ }
49865
+ sendFileBrowserMessage(socket, e2ee, { type: "file_browser_response", id, entries: result.entries });
49866
+ }
49867
+
49868
+ // src/files/browser/handle-file-browser-read.ts
49869
+ async function handleFileBrowserRead(socket, e2ee, msg, reqPath, sessionParentPath, gitScope) {
49870
+ const result = await executeFileBrowserRead({ msg, reqPath, sessionParentPath, gitScope });
49871
+ if ("error" in result) {
49872
+ sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: result.error });
49873
+ return;
49874
+ }
49875
+ const payload = {
49876
+ type: "file_browser_response",
49877
+ id: msg.id,
49878
+ content: result.content,
49879
+ totalLines: result.totalLines,
49880
+ size: result.size
49881
+ };
49882
+ if (result.lineOffset != null) payload.lineOffset = result.lineOffset;
49883
+ if (result.mimeType != null) payload.mimeType = result.mimeType;
49884
+ if (result.resolvedPath != null) payload.resolvedPath = result.resolvedPath;
49885
+ sendFileBrowserMessage(socket, e2ee, payload);
49886
+ }
49887
+
49888
+ // src/files/browser/index.ts
49889
+ init_in_flight();
49890
+ function handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager) {
49891
+ beginFileBrowserRequest();
49664
49892
  void (async () => {
49665
- const ws = deps.getWs();
49666
- const reply = (payload) => sendDeploySessionToPreviewResult(ws, msg.id, payload);
49667
49893
  try {
49668
- if (!deps.previewWorktreeManager) {
49669
- reply({ ok: false, error: "Preview worktree manager unavailable" });
49894
+ const reqPath = msg.path.replace(/^\/+/, "") || ".";
49895
+ const sessionParentPath = sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : void 0;
49896
+ const gitScope = resolveGitBranchScope(msg);
49897
+ if (msg.source === "git_branch" && typeof msg.repoRelPath === "string" && typeof msg.branch === "string" && msg.branch.trim().length > 0 && !gitScope) {
49898
+ sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: "Invalid repository path" });
49670
49899
  return;
49671
49900
  }
49672
- const result = await deploySessionToPreviewEnvironment({
49673
- sessionWorktreeManager: deps.sessionWorktreeManager,
49674
- previewWorktreeManager: deps.previewWorktreeManager,
49675
- sessionId,
49676
- environmentId,
49677
- log: deps.log
49678
- });
49679
- reply(result);
49680
- } catch (e) {
49681
- reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
49901
+ if (msg.op === "read") {
49902
+ await handleFileBrowserRead(socket, e2ee, msg, reqPath, sessionParentPath, gitScope);
49903
+ } else {
49904
+ await handleFileBrowserList(socket, e2ee, msg.id, reqPath, sessionParentPath, gitScope);
49905
+ }
49906
+ } finally {
49907
+ endFileBrowserRequest();
49682
49908
  }
49683
49909
  })();
49684
- };
49910
+ }
49911
+
49912
+ // src/files/handle-file-browser-search.ts
49913
+ init_yield_to_event_loop();
49914
+ import path80 from "node:path";
49915
+ var SEARCH_LIMIT = 100;
49916
+ function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
49917
+ void (async () => {
49918
+ await yieldToEventLoop();
49919
+ const q = typeof msg.q === "string" ? msg.q : "";
49920
+ const sessionParentPath = path80.resolve(
49921
+ sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
49922
+ );
49923
+ if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
49924
+ triggerFileIndexBuild(sessionParentPath);
49925
+ const payload2 = {
49926
+ type: "file_browser_search_response",
49927
+ id: msg.id,
49928
+ paths: [],
49929
+ indexReady: false
49930
+ };
49931
+ sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload2, ["paths"]) : payload2);
49932
+ return;
49933
+ }
49934
+ const results = await searchBridgeFilePathsAsync(sessionParentPath, q, SEARCH_LIMIT);
49935
+ const payload = {
49936
+ type: "file_browser_search_response",
49937
+ id: msg.id,
49938
+ paths: results,
49939
+ indexReady: true
49940
+ };
49941
+ sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["paths"]) : payload);
49942
+ })();
49943
+ }
49944
+ function triggerFileIndexBuild(sessionParentPath = getBridgeRoot()) {
49945
+ setImmediate(() => {
49946
+ void ensureFileIndexAsync(sessionParentPath).catch((e) => {
49947
+ console.error("[file-index] Background build failed:", e);
49948
+ });
49949
+ });
49950
+ }
49951
+
49952
+ // src/routing/handlers/file-browser-messages.ts
49953
+ function handleFileBrowserRequestMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
49954
+ if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
49955
+ const socket = getWs();
49956
+ if (!socket) return;
49957
+ handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager);
49958
+ }
49959
+ function handleFileBrowserSearchMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
49960
+ if (typeof msg.id !== "string") return;
49961
+ const socket = getWs();
49962
+ if (!socket) return;
49963
+ handleFileBrowserSearch(
49964
+ msg,
49965
+ socket,
49966
+ e2ee,
49967
+ sessionWorktreeManager
49968
+ );
49969
+ }
49970
+
49971
+ // src/code-nav/handlers/send-code-nav-response.ts
49972
+ var ENCRYPTED_FIELDS = ["definition", "definitions", "references", "symbols", "confidentTarget"];
49973
+ function sendCodeNavResponse(socket, e2ee, payload) {
49974
+ const fieldsToEncrypt = ENCRYPTED_FIELDS.filter((field) => field in payload && payload[field] !== void 0);
49975
+ sendWsMessage(
49976
+ socket,
49977
+ e2ee && fieldsToEncrypt.length > 0 ? e2ee.encryptFields(payload, [...fieldsToEncrypt]) : payload
49978
+ );
49979
+ }
49980
+
49981
+ // src/code-nav/handlers/handle-code-nav-request.ts
49982
+ function handleCodeNavRequest(msg, socket, e2ee, sessionWorktreeManager) {
49983
+ void (async () => {
49984
+ const body = await executeCodeNavRequest(msg, sessionWorktreeManager);
49985
+ sendCodeNavResponse(socket, e2ee, {
49986
+ type: "code_nav_response",
49987
+ id: msg.id,
49988
+ ...body
49989
+ });
49990
+ })();
49991
+ }
49992
+
49993
+ // src/code-nav/handlers/trigger-symbol-index-build.ts
49994
+ init_normalize_resolved_path();
49995
+
49996
+ // src/routing/handlers/code-nav-messages.ts
49997
+ function handleFileBrowserCodeNavMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
49998
+ if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
49999
+ const socket = getWs();
50000
+ if (!socket) return;
50001
+ handleCodeNavRequest(
50002
+ {
50003
+ id: msg.id,
50004
+ type: "code_nav",
50005
+ op: msg.op === "references" ? "references" : msg.op === "symbols" ? "symbols" : msg.op === "definitions" ? "definitions" : "definition",
50006
+ path: msg.path,
50007
+ line: typeof msg.line === "number" ? msg.line : 1,
50008
+ column: typeof msg.column === "number" ? msg.column : 0,
50009
+ sessionId: msg.sessionId
50010
+ },
50011
+ socket,
50012
+ e2ee,
50013
+ sessionWorktreeManager
50014
+ );
50015
+ }
49685
50016
 
49686
50017
  // src/git/bridge-git-context.ts
49687
- import * as path79 from "node:path";
50018
+ import * as path81 from "node:path";
49688
50019
  init_yield_to_event_loop();
49689
50020
 
49690
50021
  // src/git/branches/get-current-branch.ts
@@ -49735,12 +50066,12 @@ async function listRepoBranchRefs(repoPath) {
49735
50066
  // src/git/bridge-git-context.ts
49736
50067
  function folderNameForRelPath(relPath, bridgeRoot) {
49737
50068
  if (relPath === "." || relPath === "") {
49738
- return path79.basename(path79.resolve(bridgeRoot)) || "repo";
50069
+ return path81.basename(path81.resolve(bridgeRoot)) || "repo";
49739
50070
  }
49740
- return path79.basename(relPath) || relPath;
50071
+ return path81.basename(relPath) || relPath;
49741
50072
  }
49742
50073
  async function discoverGitReposForBridgeContext(bridgeRoot) {
49743
- const root = path79.resolve(bridgeRoot);
50074
+ const root = path81.resolve(bridgeRoot);
49744
50075
  if (await isGitRepoDirectory(root)) {
49745
50076
  const remoteUrl = await getRemoteOriginUrl(root);
49746
50077
  return [{ absolutePath: root, remoteUrl }];
@@ -49748,19 +50079,19 @@ async function discoverGitReposForBridgeContext(bridgeRoot) {
49748
50079
  const [deep, shallow] = await Promise.all([discoverGitReposUnderRoot(root), discoverGitRepos(root)]);
49749
50080
  const byPath = /* @__PURE__ */ new Map();
49750
50081
  for (const repo of [...deep, ...shallow]) {
49751
- byPath.set(path79.resolve(repo.absolutePath), repo);
50082
+ byPath.set(path81.resolve(repo.absolutePath), repo);
49752
50083
  }
49753
50084
  return [...byPath.values()];
49754
50085
  }
49755
50086
  async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
49756
- const bridgeResolved = path79.resolve(bridgeRoot);
50087
+ const bridgeResolved = path81.resolve(bridgeRoot);
49757
50088
  const repos = await discoverGitReposForBridgeContext(bridgeResolved);
49758
50089
  const rows = [];
49759
50090
  for (let i = 0; i < repos.length; i++) {
49760
50091
  if (i > 0) await yieldToEventLoop();
49761
50092
  const repo = repos[i];
49762
- let rel = path79.relative(bridgeResolved, repo.absolutePath);
49763
- if (rel.startsWith("..") || path79.isAbsolute(rel)) continue;
50093
+ let rel = path81.relative(bridgeResolved, repo.absolutePath);
50094
+ if (rel.startsWith("..") || path81.isAbsolute(rel)) continue;
49764
50095
  const relPath = rel === "" ? "." : rel.replace(/\\/g, "/");
49765
50096
  const currentBranch = await getCurrentBranch(repo.absolutePath);
49766
50097
  const remoteUrl = repo.remoteUrl.trim() || null;
@@ -49775,11 +50106,11 @@ async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
49775
50106
  return rows;
49776
50107
  }
49777
50108
  async function listRepoBranchesForBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
49778
- const bridgeResolved = path79.resolve(bridgeRoot);
50109
+ const bridgeResolved = path81.resolve(bridgeRoot);
49779
50110
  const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
49780
- const repoPath = rel === "" ? bridgeResolved : path79.join(bridgeResolved, rel);
49781
- const resolved = path79.resolve(repoPath);
49782
- if (!resolved.startsWith(bridgeResolved + path79.sep) && resolved !== bridgeResolved) {
50111
+ const repoPath = rel === "" ? bridgeResolved : path81.join(bridgeResolved, rel);
50112
+ const resolved = path81.resolve(repoPath);
50113
+ if (!resolved.startsWith(bridgeResolved + path81.sep) && resolved !== bridgeResolved) {
49783
50114
  return [];
49784
50115
  }
49785
50116
  return listRepoBranchRefs(resolved);
@@ -49828,80 +50159,64 @@ function handleListRepoBranchesRequestMessage(msg, getWs) {
49828
50159
  })();
49829
50160
  }
49830
50161
 
49831
- // src/routing/dispatch-bridge-message.ts
50162
+ // src/routing/dispatch/file-browser.ts
50163
+ function dispatchBridgeFileBrowserMessage(msg, deps) {
50164
+ switch (msg.type) {
50165
+ case "file_browser_request":
50166
+ handleFileBrowserRequestMessage(msg, deps);
50167
+ break;
50168
+ case "file_browser_search":
50169
+ handleFileBrowserSearchMessage(msg, deps);
50170
+ break;
50171
+ case "code_nav":
50172
+ handleFileBrowserCodeNavMessage(msg, deps);
50173
+ break;
50174
+ case "bridge_git_context_request":
50175
+ handleBridgeGitContextRequestMessage(msg, deps.getWs);
50176
+ break;
50177
+ case "list_repo_branches_request":
50178
+ handleListRepoBranchesRequestMessage(msg, deps.getWs);
50179
+ break;
50180
+ }
50181
+ }
50182
+
50183
+ // src/routing/dispatch/index.ts
49832
50184
  function dispatchBridgeMessage(msg, deps) {
49833
50185
  switch (msg.type) {
49834
50186
  case "auth_token":
49835
- handleAuthToken(msg, deps);
49836
- break;
49837
50187
  case "bridge_identified":
49838
- handleBridgeIdentified(msg, deps);
49839
- break;
49840
50188
  case "ha":
49841
- handleBridgeHeartbeatAck(msg, deps);
50189
+ dispatchBridgeConnectionMessage(msg, deps);
49842
50190
  break;
49843
50191
  case "preview_environments_config":
49844
- handlePreviewEnvironmentsConfig(msg, deps);
49845
- break;
49846
50192
  case "preview_environment_control":
49847
- handlePreviewEnvironmentControl(msg, deps);
49848
- break;
49849
50193
  case "deploy_session_to_preview":
49850
- handleDeploySessionToPreviewMessage(msg, deps);
50194
+ dispatchBridgePreviewMessage(msg, deps);
49851
50195
  break;
49852
50196
  case "agent_config":
49853
- handleAgentConfigMessage(msg, deps);
49854
- break;
49855
50197
  case "prompt_queue_state":
49856
- handlePromptQueueStateMessage(msg, deps);
49857
- break;
49858
50198
  case "prompt":
49859
- handlePromptMessage(msg, deps);
49860
- break;
49861
50199
  case "session_git_request":
49862
- handleSessionGitRequestMessage(msg, deps);
49863
- break;
49864
50200
  case "rename_session_branch":
49865
- handleRenameSessionBranchMessage(msg, deps);
49866
- break;
49867
50201
  case "session_archived":
49868
- handleSessionArchivedMessage(msg, deps);
49869
- break;
49870
50202
  case "session_discarded":
49871
- handleSessionDiscardedMessage(msg, deps);
49872
- break;
49873
50203
  case "revert_turn_snapshot":
49874
- handleRevertTurnSnapshotMessage(msg, deps);
49875
- break;
49876
50204
  case "cursor_request_response":
49877
- handleSessionRequestResponseMessage(msg, deps);
50205
+ dispatchBridgeSessionMessage(msg, deps);
49878
50206
  break;
49879
50207
  case "skill_call":
49880
- handleSkillCallMessage(msg, deps);
49881
- break;
49882
- case "file_browser_request":
49883
- handleFileBrowserRequestMessage(msg, deps);
49884
- break;
49885
- case "file_browser_search":
49886
- handleFileBrowserSearchMessage(msg, deps);
49887
- break;
49888
- case "code_nav":
49889
- handleFileBrowserCodeNavMessage(msg, deps);
49890
- break;
49891
50208
  case "skill_layout_request":
49892
- handleSkillLayoutRequest(msg, deps);
49893
- break;
49894
50209
  case "install_skills":
49895
- handleInstallSkillsMessage(msg, deps);
49896
- break;
50210
+ case "install_agent":
49897
50211
  case "refresh_local_skills":
49898
- handleRefreshLocalSkills(msg, deps);
50212
+ dispatchBridgeSkillsMessage(msg, deps);
49899
50213
  break;
50214
+ case "file_browser_request":
50215
+ case "file_browser_search":
50216
+ case "code_nav":
49900
50217
  case "bridge_git_context_request":
49901
- handleBridgeGitContextRequestMessage(msg, deps.getWs);
49902
- break;
49903
50218
  case "list_repo_branches_request":
49904
- handleListRepoBranchesRequestMessage(msg, deps.getWs);
50219
+ dispatchBridgeFileBrowserMessage(msg, deps);
49905
50220
  break;
49906
50221
  }
49907
50222
  }
@@ -50295,15 +50610,18 @@ async function runConnectedBridge(options, restartWithoutAuth) {
50295
50610
  const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
50296
50611
  let cleanupKeyCommand;
50297
50612
  let bridgeClose = null;
50613
+ let shutdownStarted = false;
50298
50614
  const onSignal = (kind) => {
50299
50615
  requestCliImmediateShutdown();
50300
50616
  abortActiveGitChildProcesses();
50301
50617
  cleanupKeyCommand?.();
50618
+ if (shutdownStarted) return;
50619
+ shutdownStarted = true;
50302
50620
  logImmediate(
50303
50621
  kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
50304
50622
  );
50305
50623
  if (bridgeClose) {
50306
- void bridgeClose().then(() => process.exit(0));
50624
+ void bridgeClose().finally(() => process.exit(0));
50307
50625
  return;
50308
50626
  }
50309
50627
  process.exit(0);