@buildautomaton/cli 0.1.46 → 0.1.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -973,8 +973,8 @@ var require_command = __commonJS({
973
973
  "../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports) {
974
974
  var EventEmitter2 = __require("node:events").EventEmitter;
975
975
  var childProcess2 = __require("node:child_process");
976
- var path46 = __require("node:path");
977
- var fs41 = __require("node:fs");
976
+ var path48 = __require("node:path");
977
+ var fs42 = __require("node:fs");
978
978
  var process8 = __require("node:process");
979
979
  var { Argument: Argument2, humanReadableArgName } = require_argument();
980
980
  var { CommanderError: CommanderError2 } = require_error();
@@ -1906,11 +1906,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
1906
1906
  let launchWithNode = false;
1907
1907
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1908
1908
  function findFile(baseDir, baseName) {
1909
- const localBin = path46.resolve(baseDir, baseName);
1910
- if (fs41.existsSync(localBin)) return localBin;
1911
- if (sourceExt.includes(path46.extname(baseName))) return void 0;
1909
+ const localBin = path48.resolve(baseDir, baseName);
1910
+ if (fs42.existsSync(localBin)) return localBin;
1911
+ if (sourceExt.includes(path48.extname(baseName))) return void 0;
1912
1912
  const foundExt = sourceExt.find(
1913
- (ext) => fs41.existsSync(`${localBin}${ext}`)
1913
+ (ext) => fs42.existsSync(`${localBin}${ext}`)
1914
1914
  );
1915
1915
  if (foundExt) return `${localBin}${foundExt}`;
1916
1916
  return void 0;
@@ -1922,21 +1922,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
1922
1922
  if (this._scriptPath) {
1923
1923
  let resolvedScriptPath;
1924
1924
  try {
1925
- resolvedScriptPath = fs41.realpathSync(this._scriptPath);
1925
+ resolvedScriptPath = fs42.realpathSync(this._scriptPath);
1926
1926
  } catch (err) {
1927
1927
  resolvedScriptPath = this._scriptPath;
1928
1928
  }
1929
- executableDir = path46.resolve(
1930
- path46.dirname(resolvedScriptPath),
1929
+ executableDir = path48.resolve(
1930
+ path48.dirname(resolvedScriptPath),
1931
1931
  executableDir
1932
1932
  );
1933
1933
  }
1934
1934
  if (executableDir) {
1935
1935
  let localFile = findFile(executableDir, executableFile);
1936
1936
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
1937
- const legacyName = path46.basename(
1937
+ const legacyName = path48.basename(
1938
1938
  this._scriptPath,
1939
- path46.extname(this._scriptPath)
1939
+ path48.extname(this._scriptPath)
1940
1940
  );
1941
1941
  if (legacyName !== this._name) {
1942
1942
  localFile = findFile(
@@ -1947,7 +1947,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1947
1947
  }
1948
1948
  executableFile = localFile || executableFile;
1949
1949
  }
1950
- launchWithNode = sourceExt.includes(path46.extname(executableFile));
1950
+ launchWithNode = sourceExt.includes(path48.extname(executableFile));
1951
1951
  let proc;
1952
1952
  if (process8.platform !== "win32") {
1953
1953
  if (launchWithNode) {
@@ -2787,7 +2787,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2787
2787
  * @return {Command}
2788
2788
  */
2789
2789
  nameFromFilename(filename) {
2790
- this._name = path46.basename(filename, path46.extname(filename));
2790
+ this._name = path48.basename(filename, path48.extname(filename));
2791
2791
  return this;
2792
2792
  }
2793
2793
  /**
@@ -2801,9 +2801,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2801
2801
  * @param {string} [path]
2802
2802
  * @return {(string|null|Command)}
2803
2803
  */
2804
- executableDir(path47) {
2805
- if (path47 === void 0) return this._executableDir;
2806
- this._executableDir = path47;
2804
+ executableDir(path49) {
2805
+ if (path49 === void 0) return this._executableDir;
2806
+ this._executableDir = path49;
2807
2807
  return this;
2808
2808
  }
2809
2809
  /**
@@ -7061,8 +7061,8 @@ var init_parseUtil = __esm({
7061
7061
  init_errors();
7062
7062
  init_en();
7063
7063
  makeIssue = (params) => {
7064
- const { data, path: path46, errorMaps, issueData } = params;
7065
- const fullPath = [...path46, ...issueData.path || []];
7064
+ const { data, path: path48, errorMaps, issueData } = params;
7065
+ const fullPath = [...path48, ...issueData.path || []];
7066
7066
  const fullIssue = {
7067
7067
  ...issueData,
7068
7068
  path: fullPath
@@ -7370,11 +7370,11 @@ var init_types = __esm({
7370
7370
  init_parseUtil();
7371
7371
  init_util();
7372
7372
  ParseInputLazyPath = class {
7373
- constructor(parent, value, path46, key) {
7373
+ constructor(parent, value, path48, key) {
7374
7374
  this._cachedPath = [];
7375
7375
  this.parent = parent;
7376
7376
  this.data = value;
7377
- this._path = path46;
7377
+ this._path = path48;
7378
7378
  this._key = key;
7379
7379
  }
7380
7380
  get path() {
@@ -11099,15 +11099,15 @@ function assignProp(target, prop, value) {
11099
11099
  configurable: true
11100
11100
  });
11101
11101
  }
11102
- function getElementAtPath(obj, path46) {
11103
- if (!path46)
11102
+ function getElementAtPath(obj, path48) {
11103
+ if (!path48)
11104
11104
  return obj;
11105
- return path46.reduce((acc, key) => acc?.[key], obj);
11105
+ return path48.reduce((acc, key) => acc?.[key], obj);
11106
11106
  }
11107
11107
  function promiseAllObject(promisesObj) {
11108
11108
  const keys = Object.keys(promisesObj);
11109
- const promises5 = keys.map((key) => promisesObj[key]);
11110
- return Promise.all(promises5).then((results) => {
11109
+ const promises6 = keys.map((key) => promisesObj[key]);
11110
+ return Promise.all(promises6).then((results) => {
11111
11111
  const resolvedObj = {};
11112
11112
  for (let i = 0; i < keys.length; i++) {
11113
11113
  resolvedObj[keys[i]] = results[i];
@@ -11351,11 +11351,11 @@ function aborted(x, startIndex = 0) {
11351
11351
  }
11352
11352
  return false;
11353
11353
  }
11354
- function prefixIssues(path46, issues) {
11354
+ function prefixIssues(path48, issues) {
11355
11355
  return issues.map((iss) => {
11356
11356
  var _a2;
11357
11357
  (_a2 = iss).path ?? (_a2.path = []);
11358
- iss.path.unshift(path46);
11358
+ iss.path.unshift(path48);
11359
11359
  return iss;
11360
11360
  });
11361
11361
  }
@@ -11544,7 +11544,7 @@ function treeifyError(error40, _mapper) {
11544
11544
  return issue2.message;
11545
11545
  };
11546
11546
  const result = { errors: [] };
11547
- const processError = (error41, path46 = []) => {
11547
+ const processError = (error41, path48 = []) => {
11548
11548
  var _a2, _b;
11549
11549
  for (const issue2 of error41.issues) {
11550
11550
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -11554,7 +11554,7 @@ function treeifyError(error40, _mapper) {
11554
11554
  } else if (issue2.code === "invalid_element") {
11555
11555
  processError({ issues: issue2.issues }, issue2.path);
11556
11556
  } else {
11557
- const fullpath = [...path46, ...issue2.path];
11557
+ const fullpath = [...path48, ...issue2.path];
11558
11558
  if (fullpath.length === 0) {
11559
11559
  result.errors.push(mapper(issue2));
11560
11560
  continue;
@@ -11584,9 +11584,9 @@ function treeifyError(error40, _mapper) {
11584
11584
  processError(error40);
11585
11585
  return result;
11586
11586
  }
11587
- function toDotPath(path46) {
11587
+ function toDotPath(path48) {
11588
11588
  const segs = [];
11589
- for (const seg of path46) {
11589
+ for (const seg of path48) {
11590
11590
  if (typeof seg === "number")
11591
11591
  segs.push(`[${seg}]`);
11592
11592
  else if (typeof seg === "symbol")
@@ -25069,10 +25069,10 @@ var require_src2 = __commonJS({
25069
25069
  var fs_1 = __require("fs");
25070
25070
  var debug_1 = __importDefault(require_src());
25071
25071
  var log2 = debug_1.default("@kwsites/file-exists");
25072
- function check2(path46, isFile, isDirectory) {
25073
- log2(`checking %s`, path46);
25072
+ function check2(path48, isFile, isDirectory) {
25073
+ log2(`checking %s`, path48);
25074
25074
  try {
25075
- const stat3 = fs_1.statSync(path46);
25075
+ const stat3 = fs_1.statSync(path48);
25076
25076
  if (stat3.isFile() && isFile) {
25077
25077
  log2(`[OK] path represents a file`);
25078
25078
  return true;
@@ -25092,8 +25092,8 @@ var require_src2 = __commonJS({
25092
25092
  throw e;
25093
25093
  }
25094
25094
  }
25095
- function exists2(path46, type = exports.READABLE) {
25096
- return check2(path46, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
25095
+ function exists2(path48, type = exports.READABLE) {
25096
+ return check2(path48, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
25097
25097
  }
25098
25098
  exports.exists = exists2;
25099
25099
  exports.FILE = 1;
@@ -25174,15 +25174,15 @@ var {
25174
25174
  } = import_index.default;
25175
25175
 
25176
25176
  // src/cli-version.ts
25177
- var CLI_VERSION = "0.1.46".length > 0 ? "0.1.46" : "0.0.0-dev";
25177
+ var CLI_VERSION = "0.1.48".length > 0 ? "0.1.48" : "0.0.0-dev";
25178
25178
 
25179
25179
  // src/cli/defaults.ts
25180
25180
  var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
25181
25181
  var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
25182
25182
 
25183
25183
  // src/cli/run-cli-action.ts
25184
- import * as fs40 from "node:fs";
25185
- import * as path45 from "node:path";
25184
+ import * as fs41 from "node:fs";
25185
+ import * as path47 from "node:path";
25186
25186
 
25187
25187
  // src/cli-log-level.ts
25188
25188
  var verbosity = "info";
@@ -25477,6 +25477,72 @@ function createCliE2eeRuntime(key) {
25477
25477
  };
25478
25478
  }
25479
25479
 
25480
+ // src/lib/e2ee/decrypt-stored-e2ee-content.ts
25481
+ function parseJsonObject(raw) {
25482
+ try {
25483
+ const parsed = JSON.parse(raw);
25484
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
25485
+ return parsed;
25486
+ }
25487
+ } catch {
25488
+ return null;
25489
+ }
25490
+ return null;
25491
+ }
25492
+ function storedStringHasE2eeEnvelope(raw) {
25493
+ const record2 = parseJsonObject(raw);
25494
+ return record2 != null && isE2eeEnvelope(record2.ee);
25495
+ }
25496
+ function e2eeKeyIdFromStoredString(raw) {
25497
+ const record2 = parseJsonObject(raw);
25498
+ if (record2 != null && isE2eeEnvelope(record2.ee)) return record2.ee.k;
25499
+ return null;
25500
+ }
25501
+ function decryptStoredE2eeRecord(record2, e2ee) {
25502
+ if (!isE2eeEnvelope(record2.ee)) return record2;
25503
+ if (!e2ee) {
25504
+ throw new Error(`E2EE_REQUIRED:${record2.ee.k}`);
25505
+ }
25506
+ if (record2.ee.k !== e2ee.keyId) {
25507
+ throw new Error(`E2EE_KEY_MISMATCH:encrypted=${record2.ee.k}:cli=${e2ee.keyId}`);
25508
+ }
25509
+ return e2ee.decryptMessage(record2);
25510
+ }
25511
+ function formatCliE2eeDecryptError(error40, e2ee) {
25512
+ const message = error40 instanceof Error ? error40.message : String(error40);
25513
+ const required2 = /^E2EE_REQUIRED:(.+)$/.exec(message.trim());
25514
+ if (required2) {
25515
+ const keyId = required2[1]?.trim() || "unknown";
25516
+ return `Parent session content is encrypted (key ${keyId}) but this bridge was not started with E2EE certificates. Restart the CLI with your E2EE certificate to read fork parent history.`;
25517
+ }
25518
+ const mismatch = /^E2EE_KEY_MISMATCH:encrypted=(.+):cli=(.*)$/.exec(message.trim());
25519
+ if (mismatch) {
25520
+ const encryptedKeyId = mismatch[1]?.trim() || "unknown";
25521
+ const cliKeyId = mismatch[2]?.trim() || e2ee?.keyId || "none";
25522
+ return `Parent session content is encrypted with key ${encryptedKeyId}, but this bridge certificate key is ${cliKeyId}. Use the same E2EE certificate that was used for the parent session.`;
25523
+ }
25524
+ if (message.includes("E2EE key mismatch")) {
25525
+ return `Parent session content could not be decrypted: ${message}`;
25526
+ }
25527
+ return `Parent session content could not be decrypted: ${message}`;
25528
+ }
25529
+ function decryptCliE2eeTranscriptPayload(payload, e2ee) {
25530
+ const record2 = parseJsonObject(payload);
25531
+ if (!record2 || !isE2eeEnvelope(record2.ee)) return payload;
25532
+ const decrypted = decryptStoredE2eeRecord(record2, e2ee);
25533
+ if (typeof decrypted.payload === "string") return decrypted.payload;
25534
+ return JSON.stringify(decrypted.payload ?? decrypted);
25535
+ }
25536
+ function decryptCliE2eeMessageField(payload, field, e2ee) {
25537
+ if (payload == null) return null;
25538
+ const record2 = parseJsonObject(payload);
25539
+ if (!record2 || !isE2eeEnvelope(record2.ee)) return payload;
25540
+ const decrypted = decryptStoredE2eeRecord(record2, e2ee);
25541
+ const value = decrypted[field];
25542
+ if (value == null) return null;
25543
+ return typeof value === "string" ? value : JSON.stringify(value);
25544
+ }
25545
+
25480
25546
  // src/e2e-certificates/certificates.ts
25481
25547
  var E2E_CERTIFICATE_ALGORITHM = "A1";
25482
25548
  var CERTIFICATE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".pem", ".key", ".crt"]);
@@ -27819,9 +27885,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
27819
27885
  const rawPath = typeof o.path === "string" ? o.path.trim() : "";
27820
27886
  const summary = typeof o.summary === "string" ? o.summary.trim() : "";
27821
27887
  if (!rawPath || !summary) continue;
27822
- const path46 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
27823
- if (!path46) continue;
27824
- rows.push({ path: path46, summary: clampSummaryToAtMostTwoLines(summary) });
27888
+ const path48 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
27889
+ if (!path48) continue;
27890
+ rows.push({ path: path48, summary: clampSummaryToAtMostTwoLines(summary) });
27825
27891
  }
27826
27892
  return rows;
27827
27893
  }
@@ -30981,8 +31047,8 @@ function pathspec(...paths) {
30981
31047
  cache.set(key, paths);
30982
31048
  return key;
30983
31049
  }
30984
- function isPathSpec(path46) {
30985
- return path46 instanceof String && cache.has(path46);
31050
+ function isPathSpec(path48) {
31051
+ return path48 instanceof String && cache.has(path48);
30986
31052
  }
30987
31053
  function toPaths(pathSpec) {
30988
31054
  return cache.get(pathSpec) || [];
@@ -31071,8 +31137,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
31071
31137
  function forEachLineWithContent(input, callback) {
31072
31138
  return toLinesWithContent(input, true).map((line) => callback(line));
31073
31139
  }
31074
- function folderExists(path46) {
31075
- return (0, import_file_exists.exists)(path46, import_file_exists.FOLDER);
31140
+ function folderExists(path48) {
31141
+ return (0, import_file_exists.exists)(path48, import_file_exists.FOLDER);
31076
31142
  }
31077
31143
  function append(target, item) {
31078
31144
  if (Array.isArray(target)) {
@@ -31476,8 +31542,8 @@ function checkIsRepoRootTask() {
31476
31542
  commands,
31477
31543
  format: "utf-8",
31478
31544
  onError,
31479
- parser(path46) {
31480
- return /^\.(git)?$/.test(path46.trim());
31545
+ parser(path48) {
31546
+ return /^\.(git)?$/.test(path48.trim());
31481
31547
  }
31482
31548
  };
31483
31549
  }
@@ -31911,11 +31977,11 @@ function parseGrep(grep) {
31911
31977
  const paths = /* @__PURE__ */ new Set();
31912
31978
  const results = {};
31913
31979
  forEachLineWithContent(grep, (input) => {
31914
- const [path46, line, preview] = input.split(NULL);
31915
- paths.add(path46);
31916
- (results[path46] = results[path46] || []).push({
31980
+ const [path48, line, preview] = input.split(NULL);
31981
+ paths.add(path48);
31982
+ (results[path48] = results[path48] || []).push({
31917
31983
  line: asNumber(line),
31918
- path: path46,
31984
+ path: path48,
31919
31985
  preview
31920
31986
  });
31921
31987
  });
@@ -32680,14 +32746,14 @@ var init_hash_object = __esm2({
32680
32746
  init_task();
32681
32747
  }
32682
32748
  });
32683
- function parseInit(bare, path46, text) {
32749
+ function parseInit(bare, path48, text) {
32684
32750
  const response = String(text).trim();
32685
32751
  let result;
32686
32752
  if (result = initResponseRegex.exec(response)) {
32687
- return new InitSummary(bare, path46, false, result[1]);
32753
+ return new InitSummary(bare, path48, false, result[1]);
32688
32754
  }
32689
32755
  if (result = reInitResponseRegex.exec(response)) {
32690
- return new InitSummary(bare, path46, true, result[1]);
32756
+ return new InitSummary(bare, path48, true, result[1]);
32691
32757
  }
32692
32758
  let gitDir = "";
32693
32759
  const tokens = response.split(" ");
@@ -32698,7 +32764,7 @@ function parseInit(bare, path46, text) {
32698
32764
  break;
32699
32765
  }
32700
32766
  }
32701
- return new InitSummary(bare, path46, /^re/i.test(response), gitDir);
32767
+ return new InitSummary(bare, path48, /^re/i.test(response), gitDir);
32702
32768
  }
32703
32769
  var InitSummary;
32704
32770
  var initResponseRegex;
@@ -32707,9 +32773,9 @@ var init_InitSummary = __esm2({
32707
32773
  "src/lib/responses/InitSummary.ts"() {
32708
32774
  "use strict";
32709
32775
  InitSummary = class {
32710
- constructor(bare, path46, existing, gitDir) {
32776
+ constructor(bare, path48, existing, gitDir) {
32711
32777
  this.bare = bare;
32712
- this.path = path46;
32778
+ this.path = path48;
32713
32779
  this.existing = existing;
32714
32780
  this.gitDir = gitDir;
32715
32781
  }
@@ -32721,7 +32787,7 @@ var init_InitSummary = __esm2({
32721
32787
  function hasBareCommand(command) {
32722
32788
  return command.includes(bareCommand);
32723
32789
  }
32724
- function initTask(bare = false, path46, customArgs) {
32790
+ function initTask(bare = false, path48, customArgs) {
32725
32791
  const commands = ["init", ...customArgs];
32726
32792
  if (bare && !hasBareCommand(commands)) {
32727
32793
  commands.splice(1, 0, bareCommand);
@@ -32730,7 +32796,7 @@ function initTask(bare = false, path46, customArgs) {
32730
32796
  commands,
32731
32797
  format: "utf-8",
32732
32798
  parser(text) {
32733
- return parseInit(commands.includes("--bare"), path46, text);
32799
+ return parseInit(commands.includes("--bare"), path48, text);
32734
32800
  }
32735
32801
  };
32736
32802
  }
@@ -33546,12 +33612,12 @@ var init_FileStatusSummary = __esm2({
33546
33612
  "use strict";
33547
33613
  fromPathRegex = /^(.+)\0(.+)$/;
33548
33614
  FileStatusSummary = class {
33549
- constructor(path46, index, working_dir) {
33550
- this.path = path46;
33615
+ constructor(path48, index, working_dir) {
33616
+ this.path = path48;
33551
33617
  this.index = index;
33552
33618
  this.working_dir = working_dir;
33553
33619
  if (index === "R" || working_dir === "R") {
33554
- const detail = fromPathRegex.exec(path46) || [null, path46, path46];
33620
+ const detail = fromPathRegex.exec(path48) || [null, path48, path48];
33555
33621
  this.from = detail[2] || "";
33556
33622
  this.path = detail[1] || "";
33557
33623
  }
@@ -33582,14 +33648,14 @@ function splitLine(result, lineStr) {
33582
33648
  default:
33583
33649
  return;
33584
33650
  }
33585
- function data(index, workingDir, path46) {
33651
+ function data(index, workingDir, path48) {
33586
33652
  const raw = `${index}${workingDir}`;
33587
33653
  const handler = parsers6.get(raw);
33588
33654
  if (handler) {
33589
- handler(result, path46);
33655
+ handler(result, path48);
33590
33656
  }
33591
33657
  if (raw !== "##" && raw !== "!!") {
33592
- result.files.push(new FileStatusSummary(path46, index, workingDir));
33658
+ result.files.push(new FileStatusSummary(path48, index, workingDir));
33593
33659
  }
33594
33660
  }
33595
33661
  }
@@ -33898,9 +33964,9 @@ var init_simple_git_api = __esm2({
33898
33964
  next
33899
33965
  );
33900
33966
  }
33901
- hashObject(path46, write) {
33967
+ hashObject(path48, write) {
33902
33968
  return this._runTask(
33903
- hashObjectTask(path46, write === true),
33969
+ hashObjectTask(path48, write === true),
33904
33970
  trailingFunctionArgument(arguments)
33905
33971
  );
33906
33972
  }
@@ -34253,8 +34319,8 @@ var init_branch = __esm2({
34253
34319
  }
34254
34320
  });
34255
34321
  function toPath(input) {
34256
- const path46 = input.trim().replace(/^["']|["']$/g, "");
34257
- return path46 && normalize3(path46);
34322
+ const path48 = input.trim().replace(/^["']|["']$/g, "");
34323
+ return path48 && normalize3(path48);
34258
34324
  }
34259
34325
  var parseCheckIgnore;
34260
34326
  var init_CheckIgnore = __esm2({
@@ -34568,8 +34634,8 @@ __export2(sub_module_exports, {
34568
34634
  subModuleTask: () => subModuleTask,
34569
34635
  updateSubModuleTask: () => updateSubModuleTask
34570
34636
  });
34571
- function addSubModuleTask(repo, path46) {
34572
- return subModuleTask(["add", repo, path46]);
34637
+ function addSubModuleTask(repo, path48) {
34638
+ return subModuleTask(["add", repo, path48]);
34573
34639
  }
34574
34640
  function initSubModuleTask(customArgs) {
34575
34641
  return subModuleTask(["init", ...customArgs]);
@@ -34902,8 +34968,8 @@ var require_git = __commonJS2({
34902
34968
  }
34903
34969
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
34904
34970
  };
34905
- Git2.prototype.submoduleAdd = function(repo, path46, then) {
34906
- return this._runTask(addSubModuleTask2(repo, path46), trailingFunctionArgument2(arguments));
34971
+ Git2.prototype.submoduleAdd = function(repo, path48, then) {
34972
+ return this._runTask(addSubModuleTask2(repo, path48), trailingFunctionArgument2(arguments));
34907
34973
  };
34908
34974
  Git2.prototype.submoduleUpdate = function(args, then) {
34909
34975
  return this._runTask(
@@ -35866,9 +35932,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
35866
35932
  // src/agents/acp/put-summarize-change-summaries.ts
35867
35933
  async function putEncryptedChangeSummaryRows(params) {
35868
35934
  const base = params.apiBaseUrl.replace(/\/+$/, "");
35869
- const entries = params.rows.map(({ path: path46, summary }) => {
35935
+ const entries = params.rows.map(({ path: path48, summary }) => {
35870
35936
  const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
35871
- return { path: path46, summary: JSON.stringify(enc) };
35937
+ return { path: path48, summary: JSON.stringify(enc) };
35872
35938
  });
35873
35939
  const res = await fetch(
35874
35940
  `${base}/internal/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
@@ -36081,54 +36147,101 @@ function buildForkedSessionAgentPrompt(userPrompt, childSessionId, parentSession
36081
36147
  ].join("\n");
36082
36148
  }
36083
36149
 
36084
- // src/mcp/tools/session-history/fetch-parent-session-cloud.ts
36150
+ // src/mcp/tools/session-history/cloud/internal-api.ts
36085
36151
  function internalApiBase(cloudApiBaseUrl) {
36086
36152
  return cloudApiBaseUrl.replace(/\/+$/, "");
36087
36153
  }
36088
- async function fetchCloudSessionMeta(params) {
36154
+ async function fetchInternalApiJson(params) {
36089
36155
  const token = params.getCloudAccessToken();
36090
36156
  if (!token) return { ok: false, error: "Missing cloud access token." };
36091
- const url2 = `${internalApiBase(params.cloudApiBaseUrl)}/internal/sessions/${encodeURIComponent(params.sessionId)}/meta`;
36157
+ const url2 = `${internalApiBase(params.cloudApiBaseUrl)}${params.path}`;
36092
36158
  const res = await fetch(url2, { headers: { Authorization: `Bearer ${token}` } });
36093
36159
  if (!res.ok) {
36094
36160
  const t = await res.text().catch(() => "");
36095
- return { ok: false, error: `Session meta fetch failed (${res.status}): ${t.slice(0, 200)}` };
36161
+ return { ok: false, error: `${params.errorLabel} (${res.status}): ${t.slice(0, 200)}` };
36096
36162
  }
36097
36163
  const data = await res.json().catch(() => null);
36098
- if (!data) return { ok: false, error: "Invalid session meta response." };
36164
+ if (!data) return { ok: false, error: `Invalid ${params.errorLabel.toLowerCase()} response.` };
36099
36165
  return { ok: true, data };
36100
36166
  }
36101
- async function fetchCloudParentSessionPrompts(params) {
36102
- const token = params.getCloudAccessToken();
36103
- if (!token) return { ok: false, error: "Missing cloud access token." };
36104
- const url2 = `${internalApiBase(params.cloudApiBaseUrl)}/internal/sessions/${encodeURIComponent(params.childSessionId)}/parent/prompts`;
36105
- const res = await fetch(url2, { headers: { Authorization: `Bearer ${token}` } });
36106
- if (!res.ok) {
36107
- const t = await res.text().catch(() => "");
36108
- return { ok: false, error: `Parent prompts fetch failed (${res.status}): ${t.slice(0, 200)}` };
36167
+
36168
+ // src/mcp/tools/session-history/cloud/fetch-session-meta.ts
36169
+ async function fetchCloudSessionMeta(params) {
36170
+ return fetchInternalApiJson({
36171
+ ...params,
36172
+ path: `/internal/sessions/${encodeURIComponent(params.sessionId)}/meta`,
36173
+ errorLabel: "Session meta fetch failed"
36174
+ });
36175
+ }
36176
+
36177
+ // src/mcp/tools/session-history/cloud/decrypt-parent-prompt-turns.ts
36178
+ function assertE2eeRuntimeForEnvelope(raw, e2ee) {
36179
+ if (storedStringHasE2eeEnvelope(raw) && !e2ee) {
36180
+ throw new Error(`E2EE_REQUIRED:${e2eeKeyIdFromStoredString(raw) ?? "unknown"}`);
36109
36181
  }
36110
- const data = await res.json().catch(() => null);
36111
- if (!data) return { ok: false, error: "Invalid parent prompts response." };
36112
- return { ok: true, data };
36113
36182
  }
36114
- async function fetchCloudParentTurnTranscript(params) {
36115
- const token = params.getCloudAccessToken();
36116
- if (!token) return { ok: false, error: "Missing cloud access token." };
36117
- const url2 = `${internalApiBase(params.cloudApiBaseUrl)}/internal/sessions/${encodeURIComponent(params.childSessionId)}/parent/turns/${encodeURIComponent(params.turnId)}/transcript`;
36118
- const res = await fetch(url2, { headers: { Authorization: `Bearer ${token}` } });
36119
- if (!res.ok) {
36120
- const t = await res.text().catch(() => "");
36121
- return { ok: false, error: `Transcript fetch failed (${res.status}): ${t.slice(0, 200)}` };
36183
+ function decryptParentPromptTurns(turns, e2ee) {
36184
+ return turns.map((turn) => {
36185
+ const promptRaw = typeof turn.promptText === "string" ? turn.promptText : null;
36186
+ const titleRaw = typeof turn.title === "string" ? turn.title : null;
36187
+ if (promptRaw) assertE2eeRuntimeForEnvelope(promptRaw, e2ee);
36188
+ if (titleRaw) assertE2eeRuntimeForEnvelope(titleRaw, e2ee);
36189
+ return {
36190
+ ...turn,
36191
+ promptText: decryptCliE2eeMessageField(promptRaw, "prompt", e2ee),
36192
+ title: decryptCliE2eeMessageField(titleRaw, "title", e2ee)
36193
+ };
36194
+ });
36195
+ }
36196
+
36197
+ // src/mcp/tools/session-history/cloud/fetch-parent-prompts.ts
36198
+ async function fetchCloudParentSessionPrompts(params) {
36199
+ const fetched = await fetchInternalApiJson({
36200
+ ...params,
36201
+ path: `/internal/sessions/${encodeURIComponent(params.childSessionId)}/parent/prompts`,
36202
+ errorLabel: "Parent prompts fetch failed"
36203
+ });
36204
+ if (!fetched.ok) return fetched;
36205
+ const turns = Array.isArray(fetched.data.turns) ? fetched.data.turns : [];
36206
+ try {
36207
+ const decryptedTurns = decryptParentPromptTurns(turns, params.e2ee);
36208
+ return { ok: true, data: { ...fetched.data, turns: decryptedTurns } };
36209
+ } catch (error40) {
36210
+ return { ok: false, error: formatCliE2eeDecryptError(error40, params.e2ee) };
36122
36211
  }
36123
- const data = await res.json().catch(() => null);
36124
- const rows = Array.isArray(data?.transcript) ? data.transcript : [];
36212
+ }
36213
+
36214
+ // src/mcp/tools/session-history/cloud/format-parent-transcript-text.ts
36215
+ function formatParentTranscriptText(rows, e2ee) {
36125
36216
  const lines = rows.map((row) => {
36126
36217
  const kind = typeof row.kind === "string" ? row.kind : "event";
36127
- const payload = typeof row.payload === "string" ? row.payload : JSON.stringify(row.payload ?? "");
36218
+ const rawPayload = typeof row.payload === "string" ? row.payload : JSON.stringify(row.payload ?? "");
36219
+ if (storedStringHasE2eeEnvelope(rawPayload) && !e2ee) {
36220
+ throw new Error(`E2EE_REQUIRED:${e2eeKeyIdFromStoredString(rawPayload) ?? "unknown"}`);
36221
+ }
36222
+ const payload = decryptCliE2eeTranscriptPayload(rawPayload, e2ee);
36128
36223
  return `[${kind}] ${payload}`;
36129
36224
  });
36130
- return { ok: true, text: lines.join("\n") };
36225
+ return lines.join("\n");
36131
36226
  }
36227
+
36228
+ // src/mcp/tools/session-history/cloud/fetch-parent-transcript.ts
36229
+ async function fetchCloudParentTurnTranscript(params) {
36230
+ const fetched = await fetchInternalApiJson({
36231
+ ...params,
36232
+ path: `/internal/sessions/${encodeURIComponent(params.childSessionId)}/parent/turns/${encodeURIComponent(params.turnId)}/transcript`,
36233
+ errorLabel: "Transcript fetch failed"
36234
+ });
36235
+ if (!fetched.ok) return fetched;
36236
+ const rows = Array.isArray(fetched.data.transcript) ? fetched.data.transcript : [];
36237
+ try {
36238
+ return { ok: true, text: formatParentTranscriptText(rows, params.e2ee) };
36239
+ } catch (error40) {
36240
+ return { ok: false, error: formatCliE2eeDecryptError(error40, params.e2ee) };
36241
+ }
36242
+ }
36243
+
36244
+ // src/mcp/tools/session-history/cloud/resolve-parent-session-id.ts
36132
36245
  async function resolveParentSessionIdForChild(params) {
36133
36246
  const meta = await fetchCloudSessionMeta({
36134
36247
  sessionId: params.childSessionId,
@@ -36462,7 +36575,7 @@ async function createAcpManager(options) {
36462
36575
  // src/git/changes/types.ts
36463
36576
  var MAX_PATCH_CHARS = 35e4;
36464
36577
 
36465
- // src/git/changes/lib/repo-format.ts
36578
+ // src/git/changes/paths/repo-format.ts
36466
36579
  function posixJoinDirFile(dir, file2) {
36467
36580
  const d = dir === "." || dir === "" ? "" : dir.replace(/\\/g, "/").replace(/\/+$/, "");
36468
36581
  const f = file2.replace(/\\/g, "/").replace(/^\/+/, "");
@@ -36517,7 +36630,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
36517
36630
  }
36518
36631
 
36519
36632
  // src/git/changes/get-working-tree-change-repo-details.ts
36520
- import * as path21 from "node:path";
36633
+ import * as path23 from "node:path";
36521
36634
 
36522
36635
  // src/git/commits/resolve-remote-tracking.ts
36523
36636
  async function tryConfigGet(g, key) {
@@ -36687,9 +36800,232 @@ async function listRecentCommits(repoDir, limitInput) {
36687
36800
  }
36688
36801
  }
36689
36802
 
36690
- // src/git/changes/lib/parse-git-status.ts
36691
- function parseNameStatusLines(lines) {
36692
- const m = /* @__PURE__ */ new Map();
36803
+ // src/git/changes/parse/normalize-git-diff-path.ts
36804
+ function normalizeGitDiffPath(path48) {
36805
+ return path48.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
36806
+ }
36807
+
36808
+ // src/git/changes/parse/expand-git-rename-numstat-path.ts
36809
+ function expandGitRenameNumstatPath(rawPath) {
36810
+ const open2 = rawPath.indexOf("{");
36811
+ const arrow = rawPath.indexOf("=>");
36812
+ const close = rawPath.lastIndexOf("}");
36813
+ if (open2 === -1 || arrow === -1 || close === -1 || open2 > arrow || arrow > close) {
36814
+ return null;
36815
+ }
36816
+ const prefix = rawPath.slice(0, open2);
36817
+ const suffix = rawPath.slice(close + 1);
36818
+ const oldPart = rawPath.slice(open2 + 1, arrow).trim();
36819
+ const newPart = rawPath.slice(arrow + 2, close).trim();
36820
+ return {
36821
+ oldPath: normalizeGitDiffPath(`${prefix}${oldPart}${suffix}`),
36822
+ newPath: normalizeGitDiffPath(`${prefix}${newPart}${suffix}`)
36823
+ };
36824
+ }
36825
+ function isGitRenameNumstatPath(rawPath) {
36826
+ return expandGitRenameNumstatPath(rawPath) != null;
36827
+ }
36828
+
36829
+ // src/git/changes/rows/build-changed-file-row.ts
36830
+ function buildChangedFileRow(options) {
36831
+ const pathInRepo = normalizeGitDiffPath(options.pathInRepo);
36832
+ const relLauncher = posixJoinDirFile(options.repoRelPath, pathInRepo);
36833
+ const additions = options.numEntry?.additions ?? 0;
36834
+ const deletions = options.numEntry?.deletions ?? 0;
36835
+ let change = options.nameEntry?.change ?? "modified";
36836
+ let movedFromPathRelLauncher;
36837
+ let movedFromPathInRepo;
36838
+ const oldPathInRepo = options.nameEntry?.oldPathInRepo ?? options.numEntry?.oldPathInRepo;
36839
+ if (change === "moved" && oldPathInRepo) {
36840
+ movedFromPathInRepo = normalizeGitDiffPath(oldPathInRepo);
36841
+ movedFromPathRelLauncher = posixJoinDirFile(options.repoRelPath, movedFromPathInRepo);
36842
+ } else if (oldPathInRepo && change === "modified") {
36843
+ change = "moved";
36844
+ movedFromPathInRepo = normalizeGitDiffPath(oldPathInRepo);
36845
+ movedFromPathRelLauncher = posixJoinDirFile(options.repoRelPath, movedFromPathInRepo);
36846
+ }
36847
+ if (options.untracked && !options.nameEntry) {
36848
+ change = "added";
36849
+ } else if (!options.nameEntry && options.numEntry && change !== "moved") {
36850
+ if (additions > 0 && deletions === 0) change = "added";
36851
+ else if (deletions > 0 && additions === 0) change = "removed";
36852
+ else change = "modified";
36853
+ }
36854
+ return {
36855
+ pathRelLauncher: relLauncher,
36856
+ additions,
36857
+ deletions,
36858
+ change,
36859
+ ...movedFromPathRelLauncher ? { movedFromPathRelLauncher } : {},
36860
+ ...movedFromPathInRepo ? { movedFromPathInRepo } : {}
36861
+ };
36862
+ }
36863
+
36864
+ // src/git/changes/listing/build-changed-file-rows.ts
36865
+ async function buildChangedFileRowsFromPaths(options) {
36866
+ const rows = [];
36867
+ await forEachWithGitYield([...options.paths], async (pathInRepo) => {
36868
+ if (isGitRenameNumstatPath(pathInRepo)) return;
36869
+ if (options.movedSourcePaths.has(pathInRepo)) return;
36870
+ const nameEntry = options.nameByPath.get(pathInRepo);
36871
+ const numEntry = options.numByPath.get(pathInRepo);
36872
+ const row = buildChangedFileRow({
36873
+ pathInRepo,
36874
+ repoRelPath: options.repoRelPath,
36875
+ nameEntry,
36876
+ numEntry,
36877
+ untracked: options.untrackedSet?.has(pathInRepo)
36878
+ });
36879
+ if (options.applyUntrackedStats) {
36880
+ await options.applyUntrackedStats(row, pathInRepo);
36881
+ }
36882
+ rows.push(row);
36883
+ });
36884
+ return rows;
36885
+ }
36886
+
36887
+ // src/git/changes/patch/patch-truncate.ts
36888
+ function truncatePatch(s) {
36889
+ if (s.length <= MAX_PATCH_CHARS) return s;
36890
+ return `${s.slice(0, MAX_PATCH_CHARS)}
36891
+
36892
+ \u2026 (diff truncated)`;
36893
+ }
36894
+
36895
+ // src/git/changes/patch/unified-diff-for-file.ts
36896
+ function patchTextFromGitDiffOutput(raw) {
36897
+ if (raw.trim() === "") return void 0;
36898
+ return normalizePatchContent(raw);
36899
+ }
36900
+ async function unifiedDiffForFile(repoCwd, pathInRepo, change, movedFromPathInRepo) {
36901
+ const g = cliSimpleGit(repoCwd);
36902
+ const renameArgs = ["-M", "--find-renames"];
36903
+ const args = change === "moved" && movedFromPathInRepo ? ["diff", "--no-color", ...renameArgs, "HEAD", "--", movedFromPathInRepo, pathInRepo] : change === "removed" ? ["diff", "--no-color", ...renameArgs, "HEAD", "--", pathInRepo] : ["diff", "--no-color", ...renameArgs, "HEAD", "--", pathInRepo];
36904
+ const raw = await g.raw([...args]).catch(() => "");
36905
+ const patch = patchTextFromGitDiffOutput(String(raw));
36906
+ return patch ? truncatePatch(patch) : void 0;
36907
+ }
36908
+ async function unifiedDiffForFileInRange(repoCwd, range, pathInRepo, change, movedFromPathInRepo) {
36909
+ const g = cliSimpleGit(repoCwd);
36910
+ const renameArgs = ["-M", "--find-renames"];
36911
+ const args = change === "moved" && movedFromPathInRepo ? ["diff", "--no-color", ...renameArgs, "-U20000", range, "--", movedFromPathInRepo, pathInRepo] : ["diff", "--no-color", ...renameArgs, "-U20000", range, "--", pathInRepo];
36912
+ const raw = await g.raw([...args]).catch(() => "");
36913
+ const patch = patchTextFromGitDiffOutput(String(raw));
36914
+ return patch ? truncatePatch(patch) : void 0;
36915
+ }
36916
+
36917
+ // src/git/changes/total-lines/resolve-changed-file-total-lines.ts
36918
+ import * as fs17 from "node:fs";
36919
+ import * as path20 from "node:path";
36920
+
36921
+ // src/git/changes/lines/count-lines.ts
36922
+ import { createReadStream } from "node:fs";
36923
+ import * as readline2 from "node:readline";
36924
+ function countLinesInText(text) {
36925
+ return splitTextIntoDiffLines(text).length;
36926
+ }
36927
+ async function countTextFileLines(filePath) {
36928
+ let bytes = 0;
36929
+ const maxBytes = 512e3;
36930
+ let lines = 0;
36931
+ const stream = createReadStream(filePath, { encoding: "utf8" });
36932
+ const rl = readline2.createInterface({ input: stream, crlfDelay: Infinity });
36933
+ for await (const _line of rl) {
36934
+ lines += 1;
36935
+ bytes += Buffer.byteLength(String(_line), "utf8") + 1;
36936
+ if (bytes > maxBytes) {
36937
+ rl.close();
36938
+ stream.destroy();
36939
+ return lines;
36940
+ }
36941
+ }
36942
+ return lines;
36943
+ }
36944
+
36945
+ // src/git/changes/total-lines/resolve-changed-file-total-lines.ts
36946
+ var MAX_BYTES = 512e3;
36947
+ async function countLinesInGitRef(repoGitCwd, ref, pathInRepo) {
36948
+ const spec = `${ref}:${pathInRepo}`;
36949
+ const g = cliSimpleGit(repoGitCwd);
36950
+ try {
36951
+ await g.raw(["cat-file", "-e", spec]);
36952
+ } catch {
36953
+ return null;
36954
+ }
36955
+ try {
36956
+ const raw = String(await g.raw(["show", spec]));
36957
+ const capped = raw.length > MAX_BYTES ? raw.slice(0, MAX_BYTES) : raw;
36958
+ return countLinesInText(capped);
36959
+ } catch {
36960
+ return null;
36961
+ }
36962
+ }
36963
+ async function resolveWorkingTreeFileTotalLines(options) {
36964
+ if (options.isBinary) return null;
36965
+ const filePath = path20.join(options.repoGitCwd, options.pathInRepo);
36966
+ if (options.change === "removed") {
36967
+ return countLinesInGitRef(options.repoGitCwd, "HEAD", options.pathInRepo);
36968
+ }
36969
+ if (options.change === "moved" || options.change === "modified") {
36970
+ try {
36971
+ const st = await fs17.promises.stat(filePath);
36972
+ if (!st.isFile()) return null;
36973
+ return await countTextFileLines(filePath);
36974
+ } catch {
36975
+ return null;
36976
+ }
36977
+ }
36978
+ return null;
36979
+ }
36980
+ async function resolveCommitFileTotalLines(options) {
36981
+ if (options.isBinary) return null;
36982
+ if (options.change === "removed") {
36983
+ return countLinesInGitRef(options.repoGitCwd, options.parentSha, options.pathInRepo);
36984
+ }
36985
+ if (options.change === "moved" || options.change === "modified") {
36986
+ return countLinesInGitRef(options.repoGitCwd, options.commitSha, options.pathInRepo);
36987
+ }
36988
+ return null;
36989
+ }
36990
+
36991
+ // src/git/changes/listing/path-in-repo-from-launcher.ts
36992
+ function pathInRepoFromLauncher(pathRelLauncher, repoRelPath) {
36993
+ const normRel = repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
36994
+ if (normRel === ".") return pathRelLauncher;
36995
+ if (pathRelLauncher.startsWith(`${normRel}/`)) {
36996
+ return pathRelLauncher.slice(normRel.length + 1);
36997
+ }
36998
+ return pathRelLauncher;
36999
+ }
37000
+ function normalizeRepoRelPath(repoRelPath) {
37001
+ return repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
37002
+ }
37003
+
37004
+ // src/git/changes/listing/enrich-commit-file-rows.ts
37005
+ async function enrichCommitFileRows(options) {
37006
+ await forEachWithGitYield(options.rows, async (row) => {
37007
+ const pathInRepo = pathInRepoFromLauncher(row.pathRelLauncher, options.repoRelPath);
37008
+ row.patchContent = await unifiedDiffForFileInRange(
37009
+ options.repoGitCwd,
37010
+ options.range,
37011
+ pathInRepo,
37012
+ row.change,
37013
+ row.movedFromPathInRepo
37014
+ );
37015
+ row.totalLines = await resolveCommitFileTotalLines({
37016
+ repoGitCwd: options.repoGitCwd,
37017
+ pathInRepo,
37018
+ change: row.change,
37019
+ commitSha: options.commitSha,
37020
+ parentSha: options.parentSha,
37021
+ isBinary: options.binaryByPath.has(pathInRepo)
37022
+ });
37023
+ });
37024
+ }
37025
+
37026
+ // src/git/changes/parse/parse-name-status-entries.ts
37027
+ function parseNameStatusEntries(lines) {
37028
+ const entries = [];
36693
37029
  for (const line of lines) {
36694
37030
  if (!line.trim()) continue;
36695
37031
  const tabParts = line.split(" ");
@@ -36697,58 +37033,143 @@ function parseNameStatusLines(lines) {
36697
37033
  const status = tabParts[0].trim();
36698
37034
  const code = status[0];
36699
37035
  if (code === "A") {
36700
- m.set(tabParts[tabParts.length - 1], "added");
37036
+ entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "added" });
36701
37037
  } else if (code === "D") {
36702
- m.set(tabParts[tabParts.length - 1], "removed");
37038
+ entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "removed" });
36703
37039
  } else if (code === "R" || code === "C") {
36704
- if (tabParts.length >= 3) m.set(tabParts[tabParts.length - 1], "modified");
37040
+ if (tabParts.length >= 3) {
37041
+ entries.push({
37042
+ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]),
37043
+ oldPathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 2]),
37044
+ change: "moved"
37045
+ });
37046
+ }
36705
37047
  } else if (code === "M" || code === "U" || code === "T") {
36706
- m.set(tabParts[tabParts.length - 1], "modified");
37048
+ entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "modified" });
36707
37049
  }
36708
37050
  }
37051
+ return entries;
37052
+ }
37053
+ function parseNameStatusLines(lines) {
37054
+ const m = /* @__PURE__ */ new Map();
37055
+ for (const entry of parseNameStatusEntries(lines)) {
37056
+ m.set(entry.pathInRepo, entry.change);
37057
+ }
36709
37058
  return m;
36710
37059
  }
36711
- function parseNumstatFirstLine(line) {
37060
+
37061
+ // src/git/changes/parse/parse-numstat-entries.ts
37062
+ function parseNumstatCounts(parts) {
37063
+ const [a, d] = parts;
37064
+ return {
37065
+ additions: a === "-" ? 0 : parseInt(String(a), 10) || 0,
37066
+ deletions: d === "-" ? 0 : parseInt(String(d), 10) || 0
37067
+ };
37068
+ }
37069
+ function parseNumstatLine(line) {
36712
37070
  const parts = line.split(" ");
36713
37071
  if (parts.length < 3) return null;
36714
- const [a, d] = parts;
36715
- const additions = a === "-" ? 0 : parseInt(String(a), 10) || 0;
36716
- const deletions = d === "-" ? 0 : parseInt(String(d), 10) || 0;
36717
- return { additions, deletions };
37072
+ const rawPath = parts[parts.length - 1];
37073
+ const { additions, deletions } = parseNumstatCounts(parts);
37074
+ const expanded = expandGitRenameNumstatPath(rawPath);
37075
+ const pathInRepo = normalizeGitDiffPath(expanded?.newPath ?? rawPath);
37076
+ return {
37077
+ pathInRepo,
37078
+ additions,
37079
+ deletions,
37080
+ ...expanded ? { oldPathInRepo: expanded.oldPath } : {}
37081
+ };
36718
37082
  }
36719
- function parseNumstat(lines) {
37083
+ function parseNumstatEntries(lines) {
36720
37084
  const m = /* @__PURE__ */ new Map();
36721
37085
  for (const line of lines) {
36722
37086
  if (!line.trim()) continue;
36723
37087
  const parts = line.split(" ");
36724
37088
  if (parts.length < 3) continue;
36725
- const [a, d, p] = parts;
36726
- const additions = a === "-" ? 0 : parseInt(String(a), 10) || 0;
36727
- const deletions = d === "-" ? 0 : parseInt(String(d), 10) || 0;
36728
- m.set(p, { additions, deletions });
37089
+ const rawPath = parts[parts.length - 1];
37090
+ const expanded = expandGitRenameNumstatPath(rawPath);
37091
+ const entry = parseNumstatLine(line);
37092
+ if (!entry) continue;
37093
+ const existing = m.get(entry.pathInRepo);
37094
+ if (!existing || expanded) {
37095
+ m.set(entry.pathInRepo, entry);
37096
+ }
36729
37097
  }
36730
37098
  return m;
36731
37099
  }
37100
+ function parseNumstat(lines) {
37101
+ const m = /* @__PURE__ */ new Map();
37102
+ for (const [path48, entry] of parseNumstatEntries(lines)) {
37103
+ m.set(path48, { additions: entry.additions, deletions: entry.deletions });
37104
+ }
37105
+ return m;
37106
+ }
37107
+
37108
+ // src/git/changes/parse/numstat-from-git-no-index.ts
36732
37109
  async function numstatFromGitNoIndex(g, pathInRepo) {
36733
37110
  const devNull = process.platform === "win32" ? "NUL" : "/dev/null";
36734
37111
  try {
36735
37112
  const out = await g.raw(["diff", "--numstat", "--no-index", "--", devNull, pathInRepo]);
36736
37113
  const first2 = String(out).split("\n").find((l) => l.trim()) ?? "";
36737
- return parseNumstatFirstLine(first2);
37114
+ const parsed = parseNumstatLine(first2);
37115
+ if (!parsed) return null;
37116
+ return { additions: parsed.additions, deletions: parsed.deletions };
36738
37117
  } catch {
36739
37118
  return null;
36740
37119
  }
36741
37120
  }
36742
37121
 
36743
- // src/git/changes/lib/patch-truncate.ts
36744
- function truncatePatch(s) {
36745
- if (s.length <= MAX_PATCH_CHARS) return s;
36746
- return `${s.slice(0, MAX_PATCH_CHARS)}
37122
+ // src/git/changes/rows/collect-moved-source-paths.ts
37123
+ function collectMovedSourcePaths(nameEntries, numByPath) {
37124
+ const sources = /* @__PURE__ */ new Set();
37125
+ for (const entry of nameEntries) {
37126
+ if (entry.change === "moved" && entry.oldPathInRepo) sources.add(entry.oldPathInRepo);
37127
+ }
37128
+ for (const entry of numByPath.values()) {
37129
+ if (entry.oldPathInRepo) sources.add(entry.oldPathInRepo);
37130
+ }
37131
+ return sources;
37132
+ }
36747
37133
 
36748
- \u2026 (diff truncated)`;
37134
+ // src/git/changes/numstat/is-binary-numstat-line.ts
37135
+ function isBinaryNumstatLine(line) {
37136
+ const parts = line.split(" ");
37137
+ if (parts.length < 3) return false;
37138
+ return parts[0] === "-" || parts[1] === "-";
37139
+ }
37140
+
37141
+ // src/git/changes/listing/collect-binary-paths-from-numstat.ts
37142
+ function collectBinaryPathsFromNumstat(numstatRaw) {
37143
+ const binaryByPath = /* @__PURE__ */ new Set();
37144
+ for (const line of numstatRaw.split("\n")) {
37145
+ if (!line.trim()) continue;
37146
+ const parts = line.split(" ");
37147
+ if (parts.length < 3) continue;
37148
+ const rawPath = parts[parts.length - 1];
37149
+ const expanded = expandGitRenameNumstatPath(rawPath);
37150
+ if (isBinaryNumstatLine(line)) binaryByPath.add(expanded?.newPath ?? rawPath);
37151
+ }
37152
+ return binaryByPath;
37153
+ }
37154
+
37155
+ // src/git/changes/listing/parse-diff-output.ts
37156
+ function parseDiffOutput(nameStatusRaw, numstatRaw) {
37157
+ const nameEntries = parseNameStatusEntries(nameStatusRaw.split("\n"));
37158
+ const nameByPath = new Map(nameEntries.map((entry) => [entry.pathInRepo, entry]));
37159
+ const numByPath = parseNumstatEntries(numstatRaw.split("\n"));
37160
+ const movedSourcePaths = collectMovedSourcePaths(nameEntries, numByPath);
37161
+ const binaryByPath = collectBinaryPathsFromNumstat(numstatRaw);
37162
+ return { nameEntries, nameByPath, numByPath, movedSourcePaths, binaryByPath };
37163
+ }
37164
+ function collectChangedPaths(options) {
37165
+ const paths = /* @__PURE__ */ new Set();
37166
+ for (const entry of options.nameEntries) paths.add(entry.pathInRepo);
37167
+ for (const pathInRepo of options.numByPath.keys()) paths.add(pathInRepo);
37168
+ for (const pathInRepo of options.untracked ?? []) paths.add(pathInRepo);
37169
+ return paths;
36749
37170
  }
36750
37171
 
36751
- // src/git/commits/list-changed-files-for-commit.ts
37172
+ // src/git/changes/listing/parent-for-commit-diff.ts
36752
37173
  var EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
36753
37174
  async function parentForCommitDiff(g, sha) {
36754
37175
  try {
@@ -36761,76 +37182,112 @@ async function parentForCommitDiff(g, sha) {
36761
37182
  }
36762
37183
  }
36763
37184
  }
37185
+
37186
+ // src/git/changes/listing/rename-diff-args.ts
37187
+ var RENAME_DIFF_ARGS = ["-M", "--find-renames"];
37188
+
37189
+ // src/git/changes/rows/pick-preferred-changed-file-row.ts
37190
+ function rowRank(row) {
37191
+ if (row.change === "moved") return 3;
37192
+ if (row.change === "modified") return 2;
37193
+ if (row.change === "added") return 1;
37194
+ return 0;
37195
+ }
37196
+ function pickPreferredChangedFileRow(a, b) {
37197
+ if (rowRank(a) !== rowRank(b)) return rowRank(a) > rowRank(b) ? a : b;
37198
+ const aHasPatch = Boolean(a.patchContent?.trim());
37199
+ const bHasPatch = Boolean(b.patchContent?.trim());
37200
+ if (aHasPatch !== bHasPatch) return aHasPatch ? a : b;
37201
+ const aHasMoveMeta = Boolean(a.movedFromPathInRepo || a.movedFromPathRelLauncher);
37202
+ const bHasMoveMeta = Boolean(b.movedFromPathInRepo || b.movedFromPathRelLauncher);
37203
+ if (aHasMoveMeta !== bHasMoveMeta) return aHasMoveMeta ? a : b;
37204
+ return a;
37205
+ }
37206
+
37207
+ // src/git/changes/rows/dedupe-changed-file-rows.ts
37208
+ function dedupeChangedFileRows(rows) {
37209
+ const byPath = /* @__PURE__ */ new Map();
37210
+ for (const row of rows) {
37211
+ const key = normalizeGitDiffPath(row.pathRelLauncher);
37212
+ const normalizedRow = key === row.pathRelLauncher ? row : { ...row, pathRelLauncher: key };
37213
+ const existing = byPath.get(key);
37214
+ if (!existing) {
37215
+ byPath.set(key, normalizedRow);
37216
+ continue;
37217
+ }
37218
+ const preferRow = pickPreferredChangedFileRow(existing, normalizedRow);
37219
+ byPath.set(key, { ...preferRow, pathRelLauncher: key });
37220
+ }
37221
+ return [...byPath.values()];
37222
+ }
37223
+
37224
+ // src/git/changes/listing/list-changed-files-for-commit.ts
36764
37225
  async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
36765
37226
  const g = cliSimpleGit(repoGitCwd);
36766
37227
  const parent = await parentForCommitDiff(g, commitSha);
36767
37228
  const range = `${parent}..${commitSha}`;
36768
37229
  const [nameStatusRaw, numstatRaw] = await Promise.all([
36769
- g.raw(["diff", "--name-status", range]).catch(() => ""),
36770
- g.raw(["diff", "--numstat", range]).catch(() => "")
37230
+ g.raw(["diff", ...RENAME_DIFF_ARGS, "--name-status", range]).catch(() => ""),
37231
+ g.raw(["diff", ...RENAME_DIFF_ARGS, "--numstat", range]).catch(() => "")
36771
37232
  ]);
36772
- const kindByPath = parseNameStatusLines(String(nameStatusRaw).split("\n"));
36773
- const numByPath = parseNumstat(String(numstatRaw).split("\n"));
36774
- const paths = new Set([...kindByPath.keys(), ...numByPath.keys()].filter(Boolean));
36775
- const rows = [];
36776
- const normRel = repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
36777
- await forEachWithGitYield([...paths], async (pathInRepo) => {
36778
- const relLauncher = posixJoinDirFile(normRel, pathInRepo.replace(/\\/g, "/"));
36779
- const nums = numByPath.get(pathInRepo);
36780
- let additions = nums?.additions ?? 0;
36781
- let deletions = nums?.deletions ?? 0;
36782
- let change = kindByPath.get(pathInRepo) ?? "modified";
36783
- if (!kindByPath.has(pathInRepo) && nums) {
36784
- if (additions > 0 && deletions === 0) change = "added";
36785
- else if (deletions > 0 && additions === 0) change = "removed";
36786
- else change = "modified";
36787
- }
36788
- rows.push({ pathRelLauncher: relLauncher, additions, deletions, change });
36789
- });
36790
- await forEachWithGitYield(rows, async (row) => {
36791
- let pathInRepo;
36792
- if (normRel === ".") {
36793
- pathInRepo = row.pathRelLauncher;
36794
- } else if (row.pathRelLauncher.startsWith(`${normRel}/`)) {
36795
- pathInRepo = row.pathRelLauncher.slice(normRel.length + 1);
36796
- } else {
36797
- pathInRepo = row.pathRelLauncher;
36798
- }
36799
- const raw = await g.raw(["diff", "-U20000", range, "--", pathInRepo]).catch(() => "");
36800
- const t = String(raw).trim();
36801
- row.patchContent = t ? truncatePatch(t) : void 0;
37233
+ const parsed = parseDiffOutput(String(nameStatusRaw), String(numstatRaw));
37234
+ const normRel = normalizeRepoRelPath(repoRelPath);
37235
+ const paths = collectChangedPaths({
37236
+ nameEntries: parsed.nameEntries,
37237
+ numByPath: parsed.numByPath
36802
37238
  });
36803
- rows.sort((a, b) => a.pathRelLauncher.localeCompare(b.pathRelLauncher));
36804
- return rows;
36805
- }
36806
-
36807
- // src/git/changes/list-changed-files-for-repo.ts
37239
+ let rows = await buildChangedFileRowsFromPaths({
37240
+ paths,
37241
+ repoRelPath: normRel,
37242
+ nameByPath: parsed.nameByPath,
37243
+ numByPath: parsed.numByPath,
37244
+ movedSourcePaths: parsed.movedSourcePaths
37245
+ });
37246
+ rows = dedupeChangedFileRows(rows);
37247
+ await enrichCommitFileRows({
37248
+ rows,
37249
+ repoGitCwd,
37250
+ repoRelPath: normRel,
37251
+ range,
37252
+ commitSha,
37253
+ parentSha: parent,
37254
+ binaryByPath: parsed.binaryByPath
37255
+ });
37256
+ const finalRows = dedupeChangedFileRows(rows);
37257
+ finalRows.sort((a, b) => a.pathRelLauncher.localeCompare(b.pathRelLauncher));
37258
+ return finalRows;
37259
+ }
37260
+
37261
+ // src/git/changes/listing/apply-untracked-file-stats.ts
36808
37262
  import * as fs18 from "node:fs";
36809
- import * as path20 from "node:path";
36810
-
36811
- // src/git/changes/lib/count-lines.ts
36812
- import { createReadStream } from "node:fs";
36813
- import * as readline2 from "node:readline";
36814
- async function countTextFileLines(filePath) {
36815
- let bytes = 0;
36816
- const maxBytes = 512e3;
36817
- let lines = 0;
36818
- const stream = createReadStream(filePath, { encoding: "utf8" });
36819
- const rl = readline2.createInterface({ input: stream, crlfDelay: Infinity });
36820
- for await (const _line of rl) {
36821
- lines += 1;
36822
- bytes += Buffer.byteLength(String(_line), "utf8") + 1;
36823
- if (bytes > maxBytes) {
36824
- rl.close();
36825
- stream.destroy();
36826
- return lines;
37263
+ import * as path21 from "node:path";
37264
+ function createUntrackedStatsApplier(options) {
37265
+ return async (row, pathInRepo) => {
37266
+ if (!options.untrackedSet.has(pathInRepo)) return;
37267
+ if (options.nameByPath.has(pathInRepo)) return;
37268
+ if (row.change === "moved") return;
37269
+ const repoFilePath = path21.join(options.repoGitCwd, pathInRepo);
37270
+ const fromGit = await numstatFromGitNoIndex(options.g, pathInRepo);
37271
+ if (fromGit) {
37272
+ row.additions = fromGit.additions;
37273
+ row.deletions = fromGit.deletions;
37274
+ return;
36827
37275
  }
36828
- }
36829
- return lines;
37276
+ try {
37277
+ const st = await fs18.promises.stat(repoFilePath);
37278
+ row.additions = st.isFile() ? await countTextFileLines(repoFilePath) : 0;
37279
+ } catch {
37280
+ row.additions = 0;
37281
+ }
37282
+ row.deletions = 0;
37283
+ };
36830
37284
  }
36831
37285
 
36832
- // src/git/changes/hydrate-patch.ts
36833
- import * as fs17 from "node:fs";
37286
+ // src/git/changes/listing/enrich-working-tree-file-rows.ts
37287
+ import * as path22 from "node:path";
37288
+
37289
+ // src/git/changes/patch/hydrate-patch.ts
37290
+ import * as fs19 from "node:fs";
36834
37291
  var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
36835
37292
  var MAX_HYDRATE_LINES_PER_GAP = 8e3;
36836
37293
  var MAX_HYDRATE_LINES_PER_FILE = 8e4;
@@ -36845,7 +37302,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
36845
37302
  }
36846
37303
  async function readWorktreeFileLines(filePath) {
36847
37304
  try {
36848
- const raw = await fs17.promises.readFile(filePath, "utf8");
37305
+ const raw = await fs19.promises.readFile(filePath, "utf8");
36849
37306
  return raw.split(/\r?\n/);
36850
37307
  } catch {
36851
37308
  return null;
@@ -36945,82 +37402,70 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
36945
37402
  return truncatePatch(out.join("\n"));
36946
37403
  }
36947
37404
 
36948
- // src/git/changes/unified-diff-for-file.ts
36949
- function patchTextFromGitDiffOutput(raw) {
36950
- if (raw.trim() === "") return void 0;
36951
- return normalizePatchContent(raw);
36952
- }
36953
- async function unifiedDiffForFile(repoCwd, pathInRepo, change) {
36954
- const g = cliSimpleGit(repoCwd);
36955
- const args = change === "added" ? ["diff", "--no-color", "HEAD", "--", pathInRepo] : change === "removed" ? ["diff", "--no-color", "HEAD", "--", pathInRepo] : ["diff", "--no-color", "HEAD", "--", pathInRepo];
36956
- const raw = await g.raw([...args]).catch(() => "");
36957
- const patch = patchTextFromGitDiffOutput(String(raw));
36958
- return patch ? truncatePatch(patch) : void 0;
37405
+ // src/git/changes/listing/enrich-working-tree-file-rows.ts
37406
+ async function enrichWorkingTreeFileRows(options) {
37407
+ await forEachWithGitYield(options.rows, async (row) => {
37408
+ const pathInRepo = pathInRepoFromLauncher(row.pathRelLauncher, options.repoRelPath);
37409
+ const filePath = path22.join(options.repoGitCwd, pathInRepo);
37410
+ const hydrateKind = row.change === "moved" ? "modified" : row.change;
37411
+ let patch = await unifiedDiffForFile(options.repoGitCwd, pathInRepo, row.change, row.movedFromPathInRepo);
37412
+ if (patch) {
37413
+ patch = await hydrateUnifiedPatchWithFileContext(
37414
+ patch,
37415
+ filePath,
37416
+ options.repoGitCwd,
37417
+ pathInRepo,
37418
+ hydrateKind
37419
+ );
37420
+ }
37421
+ row.patchContent = patch;
37422
+ row.totalLines = await resolveWorkingTreeFileTotalLines({
37423
+ repoGitCwd: options.repoGitCwd,
37424
+ pathInRepo,
37425
+ change: row.change,
37426
+ isBinary: options.binaryByPath.has(pathInRepo)
37427
+ });
37428
+ });
36959
37429
  }
36960
37430
 
36961
- // src/git/changes/list-changed-files-for-repo.ts
37431
+ // src/git/changes/listing/list-changed-files-for-repo.ts
36962
37432
  async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
36963
37433
  const g = cliSimpleGit(repoGitCwd);
36964
37434
  const [nameStatusRaw, numstatRaw, untrackedRaw] = await Promise.all([
36965
- g.raw(["diff", "--name-status", "HEAD"]).catch(() => ""),
36966
- g.raw(["diff", "HEAD", "--numstat"]).catch(() => ""),
37435
+ g.raw(["diff", ...RENAME_DIFF_ARGS, "--name-status", "HEAD"]).catch(() => ""),
37436
+ g.raw(["diff", ...RENAME_DIFF_ARGS, "HEAD", "--numstat"]).catch(() => ""),
36967
37437
  g.raw(["ls-files", "--others", "--exclude-standard"]).catch(() => "")
36968
37438
  ]);
36969
- const kindByPath = parseNameStatusLines(String(nameStatusRaw).split("\n"));
36970
- const numByPath = parseNumstat(String(numstatRaw).split("\n"));
36971
- const paths = /* @__PURE__ */ new Set([...kindByPath.keys(), ...numByPath.keys()]);
37439
+ const parsed = parseDiffOutput(String(nameStatusRaw), String(numstatRaw));
36972
37440
  const untracked = String(untrackedRaw).split("\n").map((s) => s.trim()).filter(Boolean);
36973
- for (const p of untracked) paths.add(p);
36974
- const rows = [];
36975
- await forEachWithGitYield([...paths], async (pathInRepo) => {
36976
- const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
36977
- const repoFilePath = path20.join(repoGitCwd, pathInRepo);
36978
- const nums = numByPath.get(pathInRepo);
36979
- let additions = nums?.additions ?? 0;
36980
- let deletions = nums?.deletions ?? 0;
36981
- let change = kindByPath.get(pathInRepo) ?? "modified";
36982
- if (untracked.includes(pathInRepo) && !kindByPath.has(pathInRepo)) {
36983
- change = "added";
36984
- const fromGit = await numstatFromGitNoIndex(g, pathInRepo);
36985
- if (fromGit) {
36986
- additions = fromGit.additions;
36987
- deletions = fromGit.deletions;
36988
- } else {
36989
- try {
36990
- const st = await fs18.promises.stat(repoFilePath);
36991
- if (st.isFile()) additions = await countTextFileLines(repoFilePath);
36992
- else additions = 0;
36993
- } catch {
36994
- additions = 0;
36995
- }
36996
- deletions = 0;
36997
- }
36998
- }
36999
- if (!kindByPath.has(pathInRepo) && nums) {
37000
- if (additions > 0 && deletions === 0) change = "added";
37001
- else if (deletions > 0 && additions === 0) change = "removed";
37002
- else change = "modified";
37003
- }
37004
- rows.push({ pathRelLauncher: relLauncher, additions, deletions, change });
37441
+ const untrackedSet = new Set(untracked);
37442
+ const paths = collectChangedPaths({
37443
+ nameEntries: parsed.nameEntries,
37444
+ numByPath: parsed.numByPath,
37445
+ untracked
37005
37446
  });
37006
- const normRel = repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
37007
- await forEachWithGitYield(rows, async (row) => {
37008
- let pathInRepo;
37009
- if (normRel === ".") {
37010
- pathInRepo = row.pathRelLauncher;
37011
- } else if (row.pathRelLauncher.startsWith(`${normRel}/`)) {
37012
- pathInRepo = row.pathRelLauncher.slice(normRel.length + 1);
37013
- } else {
37014
- pathInRepo = row.pathRelLauncher;
37015
- }
37016
- const filePath = path20.join(repoGitCwd, pathInRepo);
37017
- let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
37018
- if (patch) {
37019
- patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
37020
- }
37021
- row.patchContent = patch;
37447
+ let rows = await buildChangedFileRowsFromPaths({
37448
+ paths,
37449
+ repoRelPath,
37450
+ nameByPath: parsed.nameByPath,
37451
+ numByPath: parsed.numByPath,
37452
+ movedSourcePaths: parsed.movedSourcePaths,
37453
+ untrackedSet,
37454
+ applyUntrackedStats: createUntrackedStatsApplier({
37455
+ g,
37456
+ repoGitCwd,
37457
+ untrackedSet,
37458
+ nameByPath: parsed.nameByPath
37459
+ })
37022
37460
  });
37023
- return rows;
37461
+ rows = dedupeChangedFileRows(rows);
37462
+ await enrichWorkingTreeFileRows({
37463
+ rows,
37464
+ repoGitCwd,
37465
+ repoRelPath,
37466
+ binaryByPath: parsed.binaryByPath
37467
+ });
37468
+ return dedupeChangedFileRows(rows);
37024
37469
  }
37025
37470
 
37026
37471
  // src/git/changes/get-working-tree-change-repo-details.ts
@@ -37029,8 +37474,8 @@ function normRepoRel(p) {
37029
37474
  return x === "" ? "." : x;
37030
37475
  }
37031
37476
  async function getWorkingTreeChangeRepoDetails(options) {
37032
- const bridgeRoot = path21.resolve(getBridgeRoot());
37033
- const sessionWtRoot = options.sessionWorktreeRootPath ? path21.resolve(options.sessionWorktreeRootPath) : null;
37477
+ const bridgeRoot = path23.resolve(getBridgeRoot());
37478
+ const sessionWtRoot = options.sessionWorktreeRootPath ? path23.resolve(options.sessionWorktreeRootPath) : null;
37034
37479
  const legacyNested = options.legacyRepoNestedSessionLayout === true;
37035
37480
  const out = [];
37036
37481
  const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
@@ -37045,7 +37490,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
37045
37490
  for (let i = 0; i < options.commitTargetPaths.length; i++) {
37046
37491
  if (i > 0) await yieldToEventLoop2();
37047
37492
  const target = options.commitTargetPaths[i];
37048
- const t = path21.resolve(target);
37493
+ const t = path23.resolve(target);
37049
37494
  if (!await isGitRepoDirectory(t)) continue;
37050
37495
  const g = cliSimpleGit(t);
37051
37496
  let branch = "HEAD";
@@ -37058,8 +37503,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
37058
37503
  const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
37059
37504
  let repoRelPath;
37060
37505
  if (sessionWtRoot) {
37061
- const anchor = legacyNested ? path21.dirname(t) : t;
37062
- const relNorm = path21.relative(sessionWtRoot, anchor);
37506
+ const anchor = legacyNested ? path23.dirname(t) : t;
37507
+ const relNorm = path23.relative(sessionWtRoot, anchor);
37063
37508
  repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
37064
37509
  } else {
37065
37510
  let top = t;
@@ -37068,8 +37513,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
37068
37513
  } catch {
37069
37514
  top = t;
37070
37515
  }
37071
- const rel = path21.relative(bridgeRoot, path21.resolve(top)).replace(/\\/g, "/") || ".";
37072
- repoRelPath = rel.startsWith("..") ? path21.basename(path21.resolve(top)) : rel;
37516
+ const rel = path23.relative(bridgeRoot, path23.resolve(top)).replace(/\\/g, "/") || ".";
37517
+ repoRelPath = rel.startsWith("..") ? path23.basename(path23.resolve(top)) : rel;
37073
37518
  }
37074
37519
  const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
37075
37520
  if (filter && norm !== filter) continue;
@@ -37101,7 +37546,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
37101
37546
  return out;
37102
37547
  }
37103
37548
 
37104
- // src/git/changes/lib/working-tree-changed-path-count.ts
37549
+ // src/git/changes/status/working-tree-changed-path-count.ts
37105
37550
  function workingTreeChangedPathCount(nameStatusLines, numstatLines, untrackedLines) {
37106
37551
  const kindByPath = parseNameStatusLines(nameStatusLines);
37107
37552
  const numByPath = parseNumstat(numstatLines);
@@ -37197,23 +37642,23 @@ async function commitSessionWorktrees(options) {
37197
37642
  }
37198
37643
 
37199
37644
  // src/worktrees/remove-session-worktrees.ts
37200
- import * as fs21 from "node:fs";
37645
+ import * as fs22 from "node:fs";
37201
37646
 
37202
37647
  // src/git/worktrees/worktree-remove.ts
37203
- import * as fs20 from "node:fs";
37648
+ import * as fs21 from "node:fs";
37204
37649
 
37205
37650
  // src/git/worktrees/resolve-main-repo-from-git-file.ts
37206
- import * as fs19 from "node:fs";
37207
- import * as path22 from "node:path";
37651
+ import * as fs20 from "node:fs";
37652
+ import * as path24 from "node:path";
37208
37653
  function resolveMainRepoFromWorktreeGitFile(wt) {
37209
- const gitDirFile = path22.join(wt, ".git");
37210
- if (!fs19.existsSync(gitDirFile) || !fs19.statSync(gitDirFile).isFile()) return "";
37211
- const first2 = fs19.readFileSync(gitDirFile, "utf8").trim();
37654
+ const gitDirFile = path24.join(wt, ".git");
37655
+ if (!fs20.existsSync(gitDirFile) || !fs20.statSync(gitDirFile).isFile()) return "";
37656
+ const first2 = fs20.readFileSync(gitDirFile, "utf8").trim();
37212
37657
  const m = first2.match(/^gitdir:\s*(.+)$/im);
37213
37658
  if (!m) return "";
37214
- const gitWorktreePath = path22.resolve(wt, m[1].trim());
37215
- const gitDir = path22.dirname(path22.dirname(gitWorktreePath));
37216
- return path22.dirname(gitDir);
37659
+ const gitWorktreePath = path24.resolve(wt, m[1].trim());
37660
+ const gitDir = path24.dirname(path24.dirname(gitWorktreePath));
37661
+ return path24.dirname(gitDir);
37217
37662
  }
37218
37663
 
37219
37664
  // src/git/worktrees/worktree-remove.ts
@@ -37222,7 +37667,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
37222
37667
  if (mainRepo) {
37223
37668
  await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
37224
37669
  } else {
37225
- fs20.rmSync(worktreePath, { recursive: true, force: true });
37670
+ fs21.rmSync(worktreePath, { recursive: true, force: true });
37226
37671
  }
37227
37672
  }
37228
37673
 
@@ -37235,7 +37680,7 @@ async function removeSessionWorktrees(paths, log2) {
37235
37680
  } catch (e) {
37236
37681
  log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
37237
37682
  try {
37238
- fs21.rmSync(wt, { recursive: true, force: true });
37683
+ fs22.rmSync(wt, { recursive: true, force: true });
37239
37684
  } catch {
37240
37685
  }
37241
37686
  }
@@ -37264,12 +37709,12 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
37264
37709
  }
37265
37710
 
37266
37711
  // src/worktrees/worktree-layout-file.ts
37267
- import * as fs22 from "node:fs";
37268
- import * as path23 from "node:path";
37712
+ import * as fs23 from "node:fs";
37713
+ import * as path25 from "node:path";
37269
37714
  import os7 from "node:os";
37270
37715
  var LAYOUT_FILENAME = "worktree-launcher-layout.json";
37271
37716
  function defaultWorktreeLayoutPath() {
37272
- return path23.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
37717
+ return path25.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
37273
37718
  }
37274
37719
  function normalizeLoadedLayout(raw) {
37275
37720
  if (raw && typeof raw === "object" && "launcherCwds" in raw) {
@@ -37281,8 +37726,8 @@ function normalizeLoadedLayout(raw) {
37281
37726
  function loadWorktreeLayout() {
37282
37727
  try {
37283
37728
  const p = defaultWorktreeLayoutPath();
37284
- if (!fs22.existsSync(p)) return { launcherCwds: [] };
37285
- const raw = JSON.parse(fs22.readFileSync(p, "utf8"));
37729
+ if (!fs23.existsSync(p)) return { launcherCwds: [] };
37730
+ const raw = JSON.parse(fs23.readFileSync(p, "utf8"));
37286
37731
  return normalizeLoadedLayout(raw);
37287
37732
  } catch {
37288
37733
  return { launcherCwds: [] };
@@ -37290,24 +37735,24 @@ function loadWorktreeLayout() {
37290
37735
  }
37291
37736
  function saveWorktreeLayout(layout) {
37292
37737
  try {
37293
- const dir = path23.dirname(defaultWorktreeLayoutPath());
37294
- fs22.mkdirSync(dir, { recursive: true });
37295
- fs22.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
37738
+ const dir = path25.dirname(defaultWorktreeLayoutPath());
37739
+ fs23.mkdirSync(dir, { recursive: true });
37740
+ fs23.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
37296
37741
  } catch {
37297
37742
  }
37298
37743
  }
37299
37744
  function baseNameSafe(pathString) {
37300
- return path23.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
37745
+ return path25.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
37301
37746
  }
37302
37747
  function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
37303
- const norm = path23.resolve(bridgeRootPath2);
37304
- const existing = layout.launcherCwds.find((e) => path23.resolve(e.absolutePath) === norm);
37748
+ const norm = path25.resolve(bridgeRootPath2);
37749
+ const existing = layout.launcherCwds.find((e) => path25.resolve(e.absolutePath) === norm);
37305
37750
  return existing?.dirName;
37306
37751
  }
37307
37752
  function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
37308
37753
  const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
37309
37754
  if (existing) return existing;
37310
- const norm = path23.resolve(bridgeRootPath2);
37755
+ const norm = path25.resolve(bridgeRootPath2);
37311
37756
  const base = baseNameSafe(norm);
37312
37757
  const used = new Set(layout.launcherCwds.map((e) => e.dirName));
37313
37758
  let name = base;
@@ -37322,11 +37767,11 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
37322
37767
  }
37323
37768
 
37324
37769
  // src/worktrees/discover-session-worktree-on-disk.ts
37325
- import * as fs23 from "node:fs";
37326
- import * as path24 from "node:path";
37770
+ import * as fs24 from "node:fs";
37771
+ import * as path26 from "node:path";
37327
37772
  function isGitDir(dirPath) {
37328
37773
  try {
37329
- return fs23.existsSync(path24.join(dirPath, ".git"));
37774
+ return fs24.existsSync(path26.join(dirPath, ".git"));
37330
37775
  } catch {
37331
37776
  return false;
37332
37777
  }
@@ -37335,23 +37780,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
37335
37780
  const out = [];
37336
37781
  const walk = (dir) => {
37337
37782
  if (isGitDir(dir)) {
37338
- out.push(path24.resolve(dir));
37783
+ out.push(path26.resolve(dir));
37339
37784
  return;
37340
37785
  }
37341
37786
  let entries;
37342
37787
  try {
37343
- entries = fs23.readdirSync(dir, { withFileTypes: true });
37788
+ entries = fs24.readdirSync(dir, { withFileTypes: true });
37344
37789
  } catch {
37345
37790
  return;
37346
37791
  }
37347
37792
  for (const e of entries) {
37348
37793
  if (e.name.startsWith(".")) continue;
37349
- const full = path24.join(dir, e.name);
37794
+ const full = path26.join(dir, e.name);
37350
37795
  if (!e.isDirectory()) continue;
37351
37796
  walk(full);
37352
37797
  }
37353
37798
  };
37354
- walk(path24.resolve(rootPath));
37799
+ walk(path26.resolve(rootPath));
37355
37800
  return [...new Set(out)];
37356
37801
  }
37357
37802
  function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
@@ -37360,16 +37805,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
37360
37805
  if (depth > maxDepth) return;
37361
37806
  let entries;
37362
37807
  try {
37363
- entries = fs23.readdirSync(dir, { withFileTypes: true });
37808
+ entries = fs24.readdirSync(dir, { withFileTypes: true });
37364
37809
  } catch {
37365
37810
  return;
37366
37811
  }
37367
37812
  for (const e of entries) {
37368
37813
  if (e.name.startsWith(".")) continue;
37369
- const full = path24.join(dir, e.name);
37814
+ const full = path26.join(dir, e.name);
37370
37815
  if (!e.isDirectory()) continue;
37371
37816
  if (e.name === sessionId) {
37372
- if (isGitDir(full)) out.push(path24.resolve(full));
37817
+ if (isGitDir(full)) out.push(path26.resolve(full));
37373
37818
  } else {
37374
37819
  walk(full, depth + 1);
37375
37820
  }
@@ -37381,14 +37826,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
37381
37826
  function tryBindingFromSessionDirectory(sessionDir) {
37382
37827
  let st;
37383
37828
  try {
37384
- st = fs23.statSync(sessionDir);
37829
+ st = fs24.statSync(sessionDir);
37385
37830
  } catch {
37386
37831
  return null;
37387
37832
  }
37388
37833
  if (!st.isDirectory()) return null;
37389
37834
  const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
37390
37835
  if (worktreePaths.length === 0) return null;
37391
- const abs = path24.resolve(sessionDir);
37836
+ const abs = path26.resolve(sessionDir);
37392
37837
  return {
37393
37838
  sessionParentPath: abs,
37394
37839
  workingTreeRelRoot: abs,
@@ -37398,20 +37843,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
37398
37843
  function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
37399
37844
  const sid = sessionId.trim();
37400
37845
  if (!sid) return null;
37401
- const hintR = path24.resolve(checkoutPath);
37846
+ const hintR = path26.resolve(checkoutPath);
37402
37847
  let best = null;
37403
- let cur = path24.dirname(hintR);
37848
+ let cur = path26.dirname(hintR);
37404
37849
  for (let i = 0; i < 40; i++) {
37405
37850
  const paths = collectWorktreeRootsNamed(cur, sid, 24);
37406
- if (paths.some((p) => path24.resolve(p) === hintR)) {
37407
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path24.resolve(paths[0]);
37851
+ if (paths.some((p) => path26.resolve(p) === hintR)) {
37852
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path26.resolve(paths[0]);
37408
37853
  best = {
37409
- sessionParentPath: path24.resolve(isolated),
37410
- workingTreeRelRoot: path24.resolve(cur),
37411
- repoCheckoutPaths: paths.map((p) => path24.resolve(p))
37854
+ sessionParentPath: path26.resolve(isolated),
37855
+ workingTreeRelRoot: path26.resolve(cur),
37856
+ repoCheckoutPaths: paths.map((p) => path26.resolve(p))
37412
37857
  };
37413
37858
  }
37414
- const next = path24.dirname(cur);
37859
+ const next = path26.dirname(cur);
37415
37860
  if (next === cur) break;
37416
37861
  cur = next;
37417
37862
  }
@@ -37419,33 +37864,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
37419
37864
  }
37420
37865
  function discoverSessionWorktreeOnDisk(options) {
37421
37866
  const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
37422
- if (!sessionId.trim() || !fs23.existsSync(worktreesRootPath)) return null;
37867
+ if (!sessionId.trim() || !fs24.existsSync(worktreesRootPath)) return null;
37423
37868
  const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
37424
37869
  const keys = [];
37425
37870
  if (preferredKey) keys.push(preferredKey);
37426
37871
  try {
37427
- for (const name of fs23.readdirSync(worktreesRootPath)) {
37872
+ for (const name of fs24.readdirSync(worktreesRootPath)) {
37428
37873
  if (name.startsWith(".")) continue;
37429
- const p = path24.join(worktreesRootPath, name);
37430
- if (!fs23.statSync(p).isDirectory()) continue;
37874
+ const p = path26.join(worktreesRootPath, name);
37875
+ if (!fs24.statSync(p).isDirectory()) continue;
37431
37876
  if (name !== preferredKey) keys.push(name);
37432
37877
  }
37433
37878
  } catch {
37434
37879
  return null;
37435
37880
  }
37436
37881
  for (const key of keys) {
37437
- const layoutRoot = path24.join(worktreesRootPath, key);
37438
- if (!fs23.existsSync(layoutRoot) || !fs23.statSync(layoutRoot).isDirectory()) continue;
37439
- const sessionDir = path24.join(layoutRoot, sessionId);
37882
+ const layoutRoot = path26.join(worktreesRootPath, key);
37883
+ if (!fs24.existsSync(layoutRoot) || !fs24.statSync(layoutRoot).isDirectory()) continue;
37884
+ const sessionDir = path26.join(layoutRoot, sessionId);
37440
37885
  const nested = tryBindingFromSessionDirectory(sessionDir);
37441
37886
  if (nested) return nested;
37442
37887
  const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
37443
37888
  if (legacyPaths.length > 0) {
37444
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path24.resolve(legacyPaths[0]);
37889
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path26.resolve(legacyPaths[0]);
37445
37890
  return {
37446
- sessionParentPath: path24.resolve(isolated),
37447
- workingTreeRelRoot: path24.resolve(layoutRoot),
37448
- repoCheckoutPaths: legacyPaths.map((p) => path24.resolve(p))
37891
+ sessionParentPath: path26.resolve(isolated),
37892
+ workingTreeRelRoot: path26.resolve(layoutRoot),
37893
+ repoCheckoutPaths: legacyPaths.map((p) => path26.resolve(p))
37449
37894
  };
37450
37895
  }
37451
37896
  }
@@ -37454,12 +37899,12 @@ function discoverSessionWorktreeOnDisk(options) {
37454
37899
  function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
37455
37900
  const sid = sessionId.trim();
37456
37901
  if (!sid) return null;
37457
- const hint = path24.resolve(sessionWorktreeRootPathOrHint);
37458
- const underHint = tryBindingFromSessionDirectory(path24.join(hint, sid));
37902
+ const hint = path26.resolve(sessionWorktreeRootPathOrHint);
37903
+ const underHint = tryBindingFromSessionDirectory(path26.join(hint, sid));
37459
37904
  if (underHint) return underHint;
37460
37905
  const direct = tryBindingFromSessionDirectory(hint);
37461
37906
  if (direct) {
37462
- if (path24.basename(hint) === sid && isGitDir(hint)) {
37907
+ if (path26.basename(hint) === sid && isGitDir(hint)) {
37463
37908
  const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
37464
37909
  if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
37465
37910
  return legacyFromCheckout;
@@ -37467,24 +37912,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
37467
37912
  }
37468
37913
  return direct;
37469
37914
  }
37470
- if (path24.basename(hint) === sid && isGitDir(hint)) {
37915
+ if (path26.basename(hint) === sid && isGitDir(hint)) {
37471
37916
  const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
37472
37917
  if (legacyFromCheckout) return legacyFromCheckout;
37473
37918
  }
37474
37919
  let st;
37475
37920
  try {
37476
- st = fs23.statSync(hint);
37921
+ st = fs24.statSync(hint);
37477
37922
  } catch {
37478
37923
  return null;
37479
37924
  }
37480
37925
  if (!st.isDirectory()) return null;
37481
37926
  const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
37482
37927
  if (legacyPaths.length === 0) return null;
37483
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path24.resolve(legacyPaths[0]);
37928
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path26.resolve(legacyPaths[0]);
37484
37929
  return {
37485
- sessionParentPath: path24.resolve(isolated),
37930
+ sessionParentPath: path26.resolve(isolated),
37486
37931
  workingTreeRelRoot: hint,
37487
- repoCheckoutPaths: legacyPaths.map((p) => path24.resolve(p))
37932
+ repoCheckoutPaths: legacyPaths.map((p) => path26.resolve(p))
37488
37933
  };
37489
37934
  }
37490
37935
 
@@ -37541,8 +37986,8 @@ function parseSessionParent(v) {
37541
37986
  }
37542
37987
 
37543
37988
  // src/worktrees/prepare-new-session-worktrees.ts
37544
- import * as fs24 from "node:fs";
37545
- import * as path25 from "node:path";
37989
+ import * as fs25 from "node:fs";
37990
+ import * as path27 from "node:path";
37546
37991
 
37547
37992
  // src/git/worktrees/worktree-add.ts
37548
37993
  async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
@@ -37552,7 +37997,7 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef
37552
37997
  }
37553
37998
 
37554
37999
  // src/worktrees/prepare-new-session-worktrees.ts
37555
- function normalizeRepoRelPath(rel) {
38000
+ function normalizeRepoRelPath2(rel) {
37556
38001
  return rel === "" ? "." : rel.replace(/\\/g, "/");
37557
38002
  }
37558
38003
  function resolveBaseRefForRepo(relNorm, baseBranches) {
@@ -37564,10 +38009,10 @@ function resolveBaseRefForRepo(relNorm, baseBranches) {
37564
38009
  }
37565
38010
  async function prepareNewSessionWorktrees(options) {
37566
38011
  const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2, worktreeBaseBranches } = options;
37567
- const bridgeResolved = path25.resolve(bridgeRoot);
38012
+ const bridgeResolved = path27.resolve(bridgeRoot);
37568
38013
  const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
37569
- const bridgeKeyDir = path25.join(worktreesRootPath, cwdKey);
37570
- const sessionDir = path25.join(bridgeKeyDir, sessionId);
38014
+ const bridgeKeyDir = path27.join(worktreesRootPath, cwdKey);
38015
+ const sessionDir = path27.join(bridgeKeyDir, sessionId);
37571
38016
  const repos = await discoverGitReposUnderRoot(bridgeResolved);
37572
38017
  if (repos.length === 0) {
37573
38018
  log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
@@ -37575,14 +38020,14 @@ async function prepareNewSessionWorktrees(options) {
37575
38020
  }
37576
38021
  const branch = `session-${sessionId}`;
37577
38022
  const worktreePaths = [];
37578
- fs24.mkdirSync(sessionDir, { recursive: true });
38023
+ fs25.mkdirSync(sessionDir, { recursive: true });
37579
38024
  for (const repo of repos) {
37580
- let rel = path25.relative(bridgeResolved, repo.absolutePath);
37581
- if (rel.startsWith("..") || path25.isAbsolute(rel)) continue;
37582
- const relNorm = normalizeRepoRelPath(rel === "" ? "." : rel);
37583
- const wtPath = relNorm === "." ? sessionDir : path25.join(sessionDir, relNorm);
38025
+ let rel = path27.relative(bridgeResolved, repo.absolutePath);
38026
+ if (rel.startsWith("..") || path27.isAbsolute(rel)) continue;
38027
+ const relNorm = normalizeRepoRelPath2(rel === "" ? "." : rel);
38028
+ const wtPath = relNorm === "." ? sessionDir : path27.join(sessionDir, relNorm);
37584
38029
  if (relNorm !== ".") {
37585
- fs24.mkdirSync(path25.dirname(wtPath), { recursive: true });
38030
+ fs25.mkdirSync(path27.dirname(wtPath), { recursive: true });
37586
38031
  }
37587
38032
  const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
37588
38033
  try {
@@ -37635,9 +38080,9 @@ function resolveExistingSessionParentPath(sessionId, cache2, discover) {
37635
38080
  }
37636
38081
 
37637
38082
  // src/worktrees/manager/resolve-explicit-session-parent-path.ts
37638
- import * as path26 from "node:path";
38083
+ import * as path28 from "node:path";
37639
38084
  function resolveExplicitSessionParentPath(params) {
37640
- const resolved = path26.resolve(params.parentPathRaw);
38085
+ const resolved = path28.resolve(params.parentPathRaw);
37641
38086
  if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
37642
38087
  return resolved;
37643
38088
  }
@@ -37653,7 +38098,7 @@ function resolveExplicitSessionParentPath(params) {
37653
38098
  for (let i = 0; i < 16; i++) {
37654
38099
  const tryRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
37655
38100
  if (tryRoot) return rememberAndReturn(tryRoot);
37656
- const next = path26.dirname(cur);
38101
+ const next = path28.dirname(cur);
37657
38102
  if (next === cur) break;
37658
38103
  cur = next;
37659
38104
  }
@@ -37705,16 +38150,16 @@ async function resolveSessionParentPathForPrompt(params) {
37705
38150
  }
37706
38151
 
37707
38152
  // src/worktrees/manager/session-worktree-cache.ts
37708
- import * as path27 from "node:path";
38153
+ import * as path29 from "node:path";
37709
38154
  var SessionWorktreeCache = class {
37710
38155
  sessionRepoCheckoutPaths = /* @__PURE__ */ new Map();
37711
38156
  sessionParentPathBySession = /* @__PURE__ */ new Map();
37712
38157
  sessionWorkingTreeRelRootBySession = /* @__PURE__ */ new Map();
37713
38158
  remember(sessionId, binding) {
37714
- const paths = binding.repoCheckoutPaths.map((p) => path27.resolve(p));
38159
+ const paths = binding.repoCheckoutPaths.map((p) => path29.resolve(p));
37715
38160
  this.sessionRepoCheckoutPaths.set(sessionId, paths);
37716
- this.sessionParentPathBySession.set(sessionId, path27.resolve(binding.sessionParentPath));
37717
- this.sessionWorkingTreeRelRootBySession.set(sessionId, path27.resolve(binding.workingTreeRelRoot));
38161
+ this.sessionParentPathBySession.set(sessionId, path29.resolve(binding.sessionParentPath));
38162
+ this.sessionWorkingTreeRelRootBySession.set(sessionId, path29.resolve(binding.workingTreeRelRoot));
37718
38163
  }
37719
38164
  clearSession(sessionId) {
37720
38165
  const paths = this.sessionRepoCheckoutPaths.get(sessionId);
@@ -37744,7 +38189,7 @@ var SessionWorktreeCache = class {
37744
38189
  const parent = this.sessionParentPathBySession.get(sessionId);
37745
38190
  const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
37746
38191
  if (!parent || !relRoot) return false;
37747
- return path27.resolve(parent) !== path27.resolve(relRoot);
38192
+ return path29.resolve(parent) !== path29.resolve(relRoot);
37748
38193
  }
37749
38194
  };
37750
38195
 
@@ -37848,29 +38293,29 @@ var SessionWorktreeManager = class {
37848
38293
  };
37849
38294
 
37850
38295
  // src/worktrees/manager/default-worktrees-root-path.ts
37851
- import * as path28 from "node:path";
38296
+ import * as path30 from "node:path";
37852
38297
  import os8 from "node:os";
37853
38298
  function defaultWorktreesRootPath() {
37854
- return path28.join(os8.homedir(), ".buildautomaton", "worktrees");
38299
+ return path30.join(os8.homedir(), ".buildautomaton", "worktrees");
37855
38300
  }
37856
38301
 
37857
38302
  // src/files/watch-file-index.ts
37858
38303
  import { watch } from "node:fs";
37859
- import path33 from "node:path";
38304
+ import path35 from "node:path";
37860
38305
 
37861
38306
  // src/files/index/paths.ts
37862
- import path29 from "node:path";
38307
+ import path31 from "node:path";
37863
38308
  import crypto2 from "node:crypto";
37864
38309
  function getCwdHashForFileIndex(resolvedCwd) {
37865
- return crypto2.createHash("sha256").update(path29.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
38310
+ return crypto2.createHash("sha256").update(path31.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
37866
38311
  }
37867
38312
 
37868
38313
  // src/files/index/build-file-index.ts
37869
- import path31 from "node:path";
38314
+ import path33 from "node:path";
37870
38315
 
37871
38316
  // src/files/index/walk-workspace-tree.ts
37872
- import fs25 from "node:fs";
37873
- import path30 from "node:path";
38317
+ import fs26 from "node:fs";
38318
+ import path32 from "node:path";
37874
38319
  var DEPENDENCY_INSTALL_DIR_NAMES = /* @__PURE__ */ new Set([
37875
38320
  "node_modules",
37876
38321
  "bower_components",
@@ -37887,7 +38332,7 @@ function shouldSkipWorkspaceWalkEntry(name) {
37887
38332
  async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
37888
38333
  let names;
37889
38334
  try {
37890
- names = await fs25.promises.readdir(dir);
38335
+ names = await fs26.promises.readdir(dir);
37891
38336
  } catch {
37892
38337
  return;
37893
38338
  }
@@ -37899,14 +38344,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
37899
38344
  if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
37900
38345
  }
37901
38346
  state.n++;
37902
- const full = path30.join(dir, name);
38347
+ const full = path32.join(dir, name);
37903
38348
  let stat3;
37904
38349
  try {
37905
- stat3 = await fs25.promises.stat(full);
38350
+ stat3 = await fs26.promises.stat(full);
37906
38351
  } catch {
37907
38352
  continue;
37908
38353
  }
37909
- const relative6 = path30.relative(baseDir, full).replace(/\\/g, "/");
38354
+ const relative6 = path32.relative(baseDir, full).replace(/\\/g, "/");
37910
38355
  if (stat3.isDirectory()) {
37911
38356
  await walkWorkspaceTreeAsync(full, baseDir, onFile, state);
37912
38357
  } else if (stat3.isFile()) {
@@ -37919,7 +38364,7 @@ function createWalkYieldState() {
37919
38364
  }
37920
38365
 
37921
38366
  // src/files/index/file-index-sqlite-lock.ts
37922
- import fs26 from "node:fs";
38367
+ import fs27 from "node:fs";
37923
38368
  function isSqliteCorruptError(e) {
37924
38369
  const msg = e instanceof Error ? e.message : String(e);
37925
38370
  return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
@@ -37933,7 +38378,7 @@ function withFileIndexSqliteLock(fn) {
37933
38378
  if (!isSqliteCorruptError(e)) throw e;
37934
38379
  closeAllCliSqliteConnections();
37935
38380
  try {
37936
- fs26.unlinkSync(getCliSqlitePath());
38381
+ fs27.unlinkSync(getCliSqlitePath());
37937
38382
  } catch {
37938
38383
  }
37939
38384
  chain = Promise.resolve();
@@ -38008,7 +38453,7 @@ async function collectWorkspacePathsAsync(resolved) {
38008
38453
  }
38009
38454
  async function buildFileIndexAsync(cwd) {
38010
38455
  return withFileIndexSqliteLock(async () => {
38011
- const resolved = path31.resolve(cwd);
38456
+ const resolved = path33.resolve(cwd);
38012
38457
  await yieldToEventLoop();
38013
38458
  assertNotShutdown();
38014
38459
  const paths = await collectWorkspacePathsAsync(resolved);
@@ -38020,7 +38465,7 @@ async function buildFileIndexAsync(cwd) {
38020
38465
  }
38021
38466
 
38022
38467
  // src/files/index/ensure-file-index.ts
38023
- import path32 from "node:path";
38468
+ import path34 from "node:path";
38024
38469
 
38025
38470
  // src/files/index/search-file-index.ts
38026
38471
  function escapeLikePattern(fragment) {
@@ -38072,7 +38517,7 @@ async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
38072
38517
 
38073
38518
  // src/files/index/ensure-file-index.ts
38074
38519
  async function ensureFileIndexAsync(cwd) {
38075
- const resolved = path32.resolve(cwd);
38520
+ const resolved = path34.resolve(cwd);
38076
38521
  if (await bridgeFileIndexIsPopulated(resolved)) {
38077
38522
  return { fromCache: true, pathCount: await bridgeFileIndexPathCount(resolved) };
38078
38523
  }
@@ -38116,7 +38561,7 @@ function createFsWatcher(resolved, schedule) {
38116
38561
  }
38117
38562
  }
38118
38563
  function startFileIndexWatcher(cwd = getBridgeRoot()) {
38119
- const resolved = path33.resolve(cwd);
38564
+ const resolved = path35.resolve(cwd);
38120
38565
  void buildFileIndexAsync(resolved).catch((e) => {
38121
38566
  if (e instanceof CliSqliteInterrupted) return;
38122
38567
  console.error("[file-index] Initial index build failed:", e);
@@ -38146,7 +38591,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
38146
38591
  }
38147
38592
 
38148
38593
  // src/connection/create-bridge-connection.ts
38149
- import * as path44 from "node:path";
38594
+ import * as path46 from "node:path";
38150
38595
 
38151
38596
  // src/dev-servers/manager/dev-server-manager.ts
38152
38597
  import { rm as rm2 } from "node:fs/promises";
@@ -38190,7 +38635,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
38190
38635
  }
38191
38636
 
38192
38637
  // src/dev-servers/process/wire-dev-server-child-process.ts
38193
- import fs27 from "node:fs";
38638
+ import fs28 from "node:fs";
38194
38639
 
38195
38640
  // src/dev-servers/manager/forward-pipe.ts
38196
38641
  function forwardChildPipe(childReadable, terminal, onData) {
@@ -38226,7 +38671,7 @@ function wireDevServerChildProcess(d) {
38226
38671
  d.setPollInterval(void 0);
38227
38672
  return;
38228
38673
  }
38229
- fs27.readFile(d.mergedLogPath, (err, buf) => {
38674
+ fs28.readFile(d.mergedLogPath, (err, buf) => {
38230
38675
  if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
38231
38676
  if (buf.length <= d.mergedReadPos.value) return;
38232
38677
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
@@ -38264,7 +38709,7 @@ ${errTail}` : ""}`);
38264
38709
  d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
38265
38710
  };
38266
38711
  if (mergedPath) {
38267
- fs27.readFile(mergedPath, (err, buf) => {
38712
+ fs28.readFile(mergedPath, (err, buf) => {
38268
38713
  if (!err && buf.length > d.mergedReadPos.value) {
38269
38714
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
38270
38715
  if (chunk.length > 0) {
@@ -38366,13 +38811,13 @@ function parseDevServerDefs(servers) {
38366
38811
  }
38367
38812
 
38368
38813
  // src/dev-servers/manager/shell-spawn/utils.ts
38369
- import fs28 from "node:fs";
38814
+ import fs29 from "node:fs";
38370
38815
  function isSpawnEbadf(e) {
38371
38816
  return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
38372
38817
  }
38373
38818
  function rmDirQuiet(dir) {
38374
38819
  try {
38375
- fs28.rmSync(dir, { recursive: true, force: true });
38820
+ fs29.rmSync(dir, { recursive: true, force: true });
38376
38821
  } catch {
38377
38822
  }
38378
38823
  }
@@ -38380,7 +38825,7 @@ var cachedDevNullReadFd;
38380
38825
  function devNullReadFd() {
38381
38826
  if (cachedDevNullReadFd === void 0) {
38382
38827
  const devPath = process.platform === "win32" ? "nul" : "/dev/null";
38383
- cachedDevNullReadFd = fs28.openSync(devPath, "r");
38828
+ cachedDevNullReadFd = fs29.openSync(devPath, "r");
38384
38829
  }
38385
38830
  return cachedDevNullReadFd;
38386
38831
  }
@@ -38454,15 +38899,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
38454
38899
 
38455
38900
  // src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
38456
38901
  import { spawn as spawn7 } from "node:child_process";
38457
- import fs29 from "node:fs";
38902
+ import fs30 from "node:fs";
38458
38903
  import { tmpdir } from "node:os";
38459
- import path34 from "node:path";
38904
+ import path36 from "node:path";
38460
38905
  function trySpawnMergedLogFile(command, env, cwd, signal) {
38461
- const tmpRoot = fs29.mkdtempSync(path34.join(tmpdir(), "ba-devsrv-log-"));
38462
- const logPath = path34.join(tmpRoot, "combined.log");
38906
+ const tmpRoot = fs30.mkdtempSync(path36.join(tmpdir(), "ba-devsrv-log-"));
38907
+ const logPath = path36.join(tmpRoot, "combined.log");
38463
38908
  let logFd;
38464
38909
  try {
38465
- logFd = fs29.openSync(logPath, "a");
38910
+ logFd = fs30.openSync(logPath, "a");
38466
38911
  } catch {
38467
38912
  rmDirQuiet(tmpRoot);
38468
38913
  return null;
@@ -38481,7 +38926,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
38481
38926
  } else {
38482
38927
  proc = spawn7("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
38483
38928
  }
38484
- fs29.closeSync(logFd);
38929
+ fs30.closeSync(logFd);
38485
38930
  return {
38486
38931
  proc,
38487
38932
  pipedStdoutStderr: true,
@@ -38490,7 +38935,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
38490
38935
  };
38491
38936
  } catch (e) {
38492
38937
  try {
38493
- fs29.closeSync(logFd);
38938
+ fs30.closeSync(logFd);
38494
38939
  } catch {
38495
38940
  }
38496
38941
  rmDirQuiet(tmpRoot);
@@ -38501,22 +38946,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
38501
38946
 
38502
38947
  // src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
38503
38948
  import { spawn as spawn8 } from "node:child_process";
38504
- import fs30 from "node:fs";
38949
+ import fs31 from "node:fs";
38505
38950
  import { tmpdir as tmpdir2 } from "node:os";
38506
- import path35 from "node:path";
38951
+ import path37 from "node:path";
38507
38952
  function shSingleQuote(s) {
38508
38953
  return `'${s.replace(/'/g, `'\\''`)}'`;
38509
38954
  }
38510
38955
  function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
38511
- const tmpRoot = fs30.mkdtempSync(path35.join(tmpdir2(), "ba-devsrv-sh-"));
38512
- const logPath = path35.join(tmpRoot, "combined.log");
38513
- const innerPath = path35.join(tmpRoot, "_cmd.sh");
38514
- const runnerPath = path35.join(tmpRoot, "_run.sh");
38956
+ const tmpRoot = fs31.mkdtempSync(path37.join(tmpdir2(), "ba-devsrv-sh-"));
38957
+ const logPath = path37.join(tmpRoot, "combined.log");
38958
+ const innerPath = path37.join(tmpRoot, "_cmd.sh");
38959
+ const runnerPath = path37.join(tmpRoot, "_run.sh");
38515
38960
  try {
38516
- fs30.writeFileSync(innerPath, `#!/bin/sh
38961
+ fs31.writeFileSync(innerPath, `#!/bin/sh
38517
38962
  ${command}
38518
38963
  `);
38519
- fs30.writeFileSync(
38964
+ fs31.writeFileSync(
38520
38965
  runnerPath,
38521
38966
  `#!/bin/sh
38522
38967
  cd ${shSingleQuote(cwd)}
@@ -38542,13 +38987,13 @@ cd ${shSingleQuote(cwd)}
38542
38987
  }
38543
38988
  }
38544
38989
  function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
38545
- const tmpRoot = fs30.mkdtempSync(path35.join(tmpdir2(), "ba-devsrv-sh-"));
38546
- const logPath = path35.join(tmpRoot, "combined.log");
38547
- const runnerPath = path35.join(tmpRoot, "_run.bat");
38990
+ const tmpRoot = fs31.mkdtempSync(path37.join(tmpdir2(), "ba-devsrv-sh-"));
38991
+ const logPath = path37.join(tmpRoot, "combined.log");
38992
+ const runnerPath = path37.join(tmpRoot, "_run.bat");
38548
38993
  const q = (p) => `"${p.replace(/"/g, '""')}"`;
38549
38994
  const com = process.env.ComSpec || "cmd.exe";
38550
38995
  try {
38551
- fs30.writeFileSync(
38996
+ fs31.writeFileSync(
38552
38997
  runnerPath,
38553
38998
  `@ECHO OFF\r
38554
38999
  CD /D ${q(cwd)}\r
@@ -39485,30 +39930,30 @@ function createOnBridgeIdentified(opts) {
39485
39930
  }
39486
39931
 
39487
39932
  // src/skills/discover-local-agent-skills.ts
39488
- import fs31 from "node:fs";
39489
- import path36 from "node:path";
39933
+ import fs32 from "node:fs";
39934
+ import path38 from "node:path";
39490
39935
  var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
39491
39936
  function discoverLocalSkills(cwd) {
39492
39937
  const out = [];
39493
39938
  const seenKeys = /* @__PURE__ */ new Set();
39494
39939
  for (const rel of SKILL_DISCOVERY_ROOTS) {
39495
- const base = path36.join(cwd, rel);
39496
- if (!fs31.existsSync(base) || !fs31.statSync(base).isDirectory()) continue;
39940
+ const base = path38.join(cwd, rel);
39941
+ if (!fs32.existsSync(base) || !fs32.statSync(base).isDirectory()) continue;
39497
39942
  let entries = [];
39498
39943
  try {
39499
- entries = fs31.readdirSync(base);
39944
+ entries = fs32.readdirSync(base);
39500
39945
  } catch {
39501
39946
  continue;
39502
39947
  }
39503
39948
  for (const name of entries) {
39504
- const dir = path36.join(base, name);
39949
+ const dir = path38.join(base, name);
39505
39950
  try {
39506
- if (!fs31.statSync(dir).isDirectory()) continue;
39951
+ if (!fs32.statSync(dir).isDirectory()) continue;
39507
39952
  } catch {
39508
39953
  continue;
39509
39954
  }
39510
- const skillMd = path36.join(dir, "SKILL.md");
39511
- if (!fs31.existsSync(skillMd)) continue;
39955
+ const skillMd = path38.join(dir, "SKILL.md");
39956
+ if (!fs32.existsSync(skillMd)) continue;
39512
39957
  const key = `${rel}/${name}`;
39513
39958
  if (seenKeys.has(key)) continue;
39514
39959
  seenKeys.add(key);
@@ -39520,23 +39965,23 @@ function discoverLocalSkills(cwd) {
39520
39965
  function discoverSkillLayoutRoots(cwd) {
39521
39966
  const roots = [];
39522
39967
  for (const rel of SKILL_DISCOVERY_ROOTS) {
39523
- const base = path36.join(cwd, rel);
39524
- if (!fs31.existsSync(base) || !fs31.statSync(base).isDirectory()) continue;
39968
+ const base = path38.join(cwd, rel);
39969
+ if (!fs32.existsSync(base) || !fs32.statSync(base).isDirectory()) continue;
39525
39970
  let entries = [];
39526
39971
  try {
39527
- entries = fs31.readdirSync(base);
39972
+ entries = fs32.readdirSync(base);
39528
39973
  } catch {
39529
39974
  continue;
39530
39975
  }
39531
39976
  const skills2 = [];
39532
39977
  for (const name of entries) {
39533
- const dir = path36.join(base, name);
39978
+ const dir = path38.join(base, name);
39534
39979
  try {
39535
- if (!fs31.statSync(dir).isDirectory()) continue;
39980
+ if (!fs32.statSync(dir).isDirectory()) continue;
39536
39981
  } catch {
39537
39982
  continue;
39538
39983
  }
39539
- if (!fs31.existsSync(path36.join(dir, "SKILL.md"))) continue;
39984
+ if (!fs32.existsSync(path38.join(dir, "SKILL.md"))) continue;
39540
39985
  const relPath = `${rel}/${name}`.replace(/\\/g, "/");
39541
39986
  skills2.push({ name, relPath });
39542
39987
  }
@@ -39892,7 +40337,7 @@ function syncRunningTurnQueueKeys(turns, queueKey) {
39892
40337
  }
39893
40338
 
39894
40339
  // src/prompt-turn-queue/runner/run-local-revert-before-queued-prompt.ts
39895
- import fs32 from "node:fs";
40340
+ import fs33 from "node:fs";
39896
40341
  async function runLocalRevertBeforeQueuedPrompt(next, deps) {
39897
40342
  if (next.serverState !== "requeued_with_revert") return true;
39898
40343
  const sid = next.sessionId;
@@ -39901,7 +40346,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
39901
40346
  const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
39902
40347
  const file2 = snapshotFilePath(agentBase, tid);
39903
40348
  try {
39904
- await fs32.promises.access(file2, fs32.constants.F_OK);
40349
+ await fs33.promises.access(file2, fs33.constants.F_OK);
39905
40350
  } catch {
39906
40351
  deps.log(
39907
40352
  `[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
@@ -40189,9 +40634,9 @@ function parseChangeSummarySnapshots(raw) {
40189
40634
  for (const item of raw) {
40190
40635
  if (!item || typeof item !== "object") continue;
40191
40636
  const o = item;
40192
- const path46 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
40193
- if (!path46) continue;
40194
- const row = { path: path46 };
40637
+ const path48 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
40638
+ if (!path48) continue;
40639
+ const row = { path: path48 };
40195
40640
  if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
40196
40641
  if (typeof o.oldText === "string") row.oldText = o.oldText;
40197
40642
  if (typeof o.newText === "string") row.newText = o.newText;
@@ -40401,8 +40846,8 @@ function randomSecret() {
40401
40846
  }
40402
40847
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
40403
40848
  }
40404
- async function requestPreviewApi(port, secret, method, path46, body) {
40405
- const url2 = `http://127.0.0.1:${port}${path46}`;
40849
+ async function requestPreviewApi(port, secret, method, path48, body) {
40850
+ const url2 = `http://127.0.0.1:${port}${path48}`;
40406
40851
  const headers = {
40407
40852
  [PREVIEW_SECRET_HEADER]: secret,
40408
40853
  "Content-Type": "application/json"
@@ -40414,7 +40859,7 @@ async function requestPreviewApi(port, secret, method, path46, body) {
40414
40859
  });
40415
40860
  const data = await res.json().catch(() => ({}));
40416
40861
  if (!res.ok) {
40417
- throw new Error(data?.error ?? `Preview API ${method} ${path46}: ${res.status}`);
40862
+ throw new Error(data?.error ?? `Preview API ${method} ${path48}: ${res.status}`);
40418
40863
  }
40419
40864
  return data;
40420
40865
  }
@@ -40579,14 +41024,14 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
40579
41024
  };
40580
41025
 
40581
41026
  // src/files/list-dir/index.ts
40582
- import fs34 from "node:fs";
41027
+ import fs35 from "node:fs";
40583
41028
 
40584
41029
  // src/files/ensure-under-cwd.ts
40585
- import path37 from "node:path";
41030
+ import path39 from "node:path";
40586
41031
  function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
40587
- const normalized = path37.normalize(relativePath).replace(/^(\.\/)+/, "");
40588
- const resolved = path37.resolve(cwd, normalized);
40589
- if (!resolved.startsWith(cwd + path37.sep) && resolved !== cwd) {
41032
+ const normalized = path39.normalize(relativePath).replace(/^(\.\/)+/, "");
41033
+ const resolved = path39.resolve(cwd, normalized);
41034
+ if (!resolved.startsWith(cwd + path39.sep) && resolved !== cwd) {
40590
41035
  return null;
40591
41036
  }
40592
41037
  return resolved;
@@ -40596,15 +41041,15 @@ function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
40596
41041
  var LIST_DIR_YIELD_EVERY = 256;
40597
41042
 
40598
41043
  // src/files/list-dir/map-dir-entry.ts
40599
- import path38 from "node:path";
40600
- import fs33 from "node:fs";
41044
+ import path40 from "node:path";
41045
+ import fs34 from "node:fs";
40601
41046
  async function mapDirEntry(d, relativePath, resolved) {
40602
- const entryPath = path38.join(relativePath || ".", d.name).replace(/\\/g, "/");
40603
- const fullPath = path38.join(resolved, d.name);
41047
+ const entryPath = path40.join(relativePath || ".", d.name).replace(/\\/g, "/");
41048
+ const fullPath = path40.join(resolved, d.name);
40604
41049
  let isDir = d.isDirectory();
40605
41050
  if (d.isSymbolicLink()) {
40606
41051
  try {
40607
- const targetStat = await fs33.promises.stat(fullPath);
41052
+ const targetStat = await fs34.promises.stat(fullPath);
40608
41053
  isDir = targetStat.isDirectory();
40609
41054
  } catch {
40610
41055
  isDir = false;
@@ -40634,7 +41079,7 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
40634
41079
  return { error: "Path is outside working directory" };
40635
41080
  }
40636
41081
  try {
40637
- const names = await fs34.promises.readdir(resolved, { withFileTypes: true });
41082
+ const names = await fs35.promises.readdir(resolved, { withFileTypes: true });
40638
41083
  const entries = [];
40639
41084
  for (let i = 0; i < names.length; i++) {
40640
41085
  if (i > 0 && i % LIST_DIR_YIELD_EVERY === 0) {
@@ -40654,18 +41099,18 @@ var LINE_CHUNK_SIZE = 64 * 1024;
40654
41099
  var READ_RANGE_YIELD_EVERY_BYTES = 256 * 1024;
40655
41100
 
40656
41101
  // src/files/read-file/resolve-file-path.ts
40657
- import fs35 from "node:fs";
41102
+ import fs36 from "node:fs";
40658
41103
  async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeRoot()) {
40659
41104
  const resolved = ensureUnderCwd(relativePath, sessionParentPath);
40660
41105
  if (!resolved) return { error: "Path is outside working directory" };
40661
41106
  let real;
40662
41107
  try {
40663
- real = await fs35.promises.realpath(resolved);
41108
+ real = await fs36.promises.realpath(resolved);
40664
41109
  } catch {
40665
41110
  real = resolved;
40666
41111
  }
40667
41112
  try {
40668
- const stat3 = await fs35.promises.stat(real);
41113
+ const stat3 = await fs36.promises.stat(real);
40669
41114
  if (!stat3.isFile()) return { error: "Not a file" };
40670
41115
  return real;
40671
41116
  } catch (err) {
@@ -40674,11 +41119,11 @@ async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeR
40674
41119
  }
40675
41120
 
40676
41121
  // src/files/read-file/read-file-range-async.ts
40677
- import fs36 from "node:fs";
41122
+ import fs37 from "node:fs";
40678
41123
  import { StringDecoder } from "node:string_decoder";
40679
41124
  async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
40680
- const fileSize = (await fs36.promises.stat(filePath)).size;
40681
- const fd = await fs36.promises.open(filePath, "r");
41125
+ const fileSize = (await fs37.promises.stat(filePath)).size;
41126
+ const fd = await fs37.promises.open(filePath, "r");
40682
41127
  const bufSize = 64 * 1024;
40683
41128
  const buf = Buffer.alloc(bufSize);
40684
41129
  const decoder = new StringDecoder("utf8");
@@ -40840,11 +41285,11 @@ async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, li
40840
41285
  }
40841
41286
 
40842
41287
  // src/files/read-file/read-file-buffer-full-async.ts
40843
- import fs37 from "node:fs";
41288
+ import fs38 from "node:fs";
40844
41289
  var READ_CHUNK_BYTES = 256 * 1024;
40845
41290
  async function readFileBufferFullAsync(filePath) {
40846
- const stat3 = await fs37.promises.stat(filePath);
40847
- const fd = await fs37.promises.open(filePath, "r");
41291
+ const stat3 = await fs38.promises.stat(filePath);
41292
+ const fd = await fs38.promises.open(filePath, "r");
40848
41293
  const chunks = [];
40849
41294
  let position = 0;
40850
41295
  let bytesSinceYield = 0;
@@ -40951,13 +41396,13 @@ function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
40951
41396
  }
40952
41397
 
40953
41398
  // src/files/handle-file-browser-search.ts
40954
- import path39 from "node:path";
41399
+ import path41 from "node:path";
40955
41400
  var SEARCH_LIMIT = 100;
40956
41401
  function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
40957
41402
  void (async () => {
40958
41403
  await yieldToEventLoop();
40959
41404
  const q = typeof msg.q === "string" ? msg.q : "";
40960
- const sessionParentPath = path39.resolve(
41405
+ const sessionParentPath = path41.resolve(
40961
41406
  sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
40962
41407
  );
40963
41408
  if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
@@ -41076,8 +41521,8 @@ function handleSkillLayoutRequest(msg, deps) {
41076
41521
  }
41077
41522
 
41078
41523
  // src/skills/install-remote-skills.ts
41079
- import fs38 from "node:fs";
41080
- import path40 from "node:path";
41524
+ import fs39 from "node:fs";
41525
+ import path42 from "node:path";
41081
41526
  function installRemoteSkills(cwd, targetDir, items) {
41082
41527
  const installed2 = [];
41083
41528
  if (!Array.isArray(items)) {
@@ -41088,15 +41533,15 @@ function installRemoteSkills(cwd, targetDir, items) {
41088
41533
  if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
41089
41534
  continue;
41090
41535
  }
41091
- const skillDir = path40.join(cwd, targetDir, item.skillName);
41536
+ const skillDir = path42.join(cwd, targetDir, item.skillName);
41092
41537
  for (const f of item.files) {
41093
41538
  if (typeof f.path !== "string" || !f.text && !f.base64) continue;
41094
- const dest = path40.join(skillDir, f.path);
41095
- fs38.mkdirSync(path40.dirname(dest), { recursive: true });
41539
+ const dest = path42.join(skillDir, f.path);
41540
+ fs39.mkdirSync(path42.dirname(dest), { recursive: true });
41096
41541
  if (f.text !== void 0) {
41097
- fs38.writeFileSync(dest, f.text, "utf8");
41542
+ fs39.writeFileSync(dest, f.text, "utf8");
41098
41543
  } else if (f.base64) {
41099
- fs38.writeFileSync(dest, Buffer.from(f.base64, "base64"));
41544
+ fs39.writeFileSync(dest, Buffer.from(f.base64, "base64"));
41100
41545
  }
41101
41546
  }
41102
41547
  installed2.push({
@@ -41254,7 +41699,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
41254
41699
  };
41255
41700
 
41256
41701
  // src/routing/handlers/revert-turn-snapshot.ts
41257
- import * as fs39 from "node:fs";
41702
+ import * as fs40 from "node:fs";
41258
41703
  var handleRevertTurnSnapshotMessage = (msg, deps) => {
41259
41704
  const id = typeof msg.id === "string" ? msg.id : "";
41260
41705
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
@@ -41267,7 +41712,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
41267
41712
  const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
41268
41713
  const file2 = snapshotFilePath(agentBase, turnId);
41269
41714
  try {
41270
- await fs39.promises.access(file2, fs39.constants.F_OK);
41715
+ await fs40.promises.access(file2, fs40.constants.F_OK);
41271
41716
  } catch {
41272
41717
  sendWsMessage(s, {
41273
41718
  type: "revert_turn_snapshot_result",
@@ -41309,7 +41754,7 @@ var handleDevServersConfig = (msg, deps) => {
41309
41754
  };
41310
41755
 
41311
41756
  // src/git/bridge-git-context.ts
41312
- import * as path41 from "node:path";
41757
+ import * as path43 from "node:path";
41313
41758
 
41314
41759
  // src/git/branches/get-current-branch.ts
41315
41760
  async function getCurrentBranch(repoPath) {
@@ -41359,12 +41804,12 @@ async function listRepoBranchRefs(repoPath) {
41359
41804
  // src/git/bridge-git-context.ts
41360
41805
  function folderNameForRelPath(relPath, bridgeRoot) {
41361
41806
  if (relPath === "." || relPath === "") {
41362
- return path41.basename(path41.resolve(bridgeRoot)) || "repo";
41807
+ return path43.basename(path43.resolve(bridgeRoot)) || "repo";
41363
41808
  }
41364
- return path41.basename(relPath) || relPath;
41809
+ return path43.basename(relPath) || relPath;
41365
41810
  }
41366
41811
  async function discoverGitReposForBridgeContext(bridgeRoot) {
41367
- const root = path41.resolve(bridgeRoot);
41812
+ const root = path43.resolve(bridgeRoot);
41368
41813
  if (await isGitRepoDirectory(root)) {
41369
41814
  const remoteUrl = await getRemoteOriginUrl(root);
41370
41815
  return [{ absolutePath: root, remoteUrl }];
@@ -41372,17 +41817,17 @@ async function discoverGitReposForBridgeContext(bridgeRoot) {
41372
41817
  const [deep, shallow] = await Promise.all([discoverGitReposUnderRoot(root), discoverGitRepos(root)]);
41373
41818
  const byPath = /* @__PURE__ */ new Map();
41374
41819
  for (const repo of [...deep, ...shallow]) {
41375
- byPath.set(path41.resolve(repo.absolutePath), repo);
41820
+ byPath.set(path43.resolve(repo.absolutePath), repo);
41376
41821
  }
41377
41822
  return [...byPath.values()];
41378
41823
  }
41379
41824
  async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
41380
- const bridgeResolved = path41.resolve(bridgeRoot);
41825
+ const bridgeResolved = path43.resolve(bridgeRoot);
41381
41826
  const repos = await discoverGitReposForBridgeContext(bridgeResolved);
41382
41827
  const rows = [];
41383
41828
  for (const repo of repos) {
41384
- let rel = path41.relative(bridgeResolved, repo.absolutePath);
41385
- if (rel.startsWith("..") || path41.isAbsolute(rel)) continue;
41829
+ let rel = path43.relative(bridgeResolved, repo.absolutePath);
41830
+ if (rel.startsWith("..") || path43.isAbsolute(rel)) continue;
41386
41831
  const relPath = rel === "" ? "." : rel.replace(/\\/g, "/");
41387
41832
  const currentBranch = await getCurrentBranch(repo.absolutePath);
41388
41833
  const remoteUrl = repo.remoteUrl.trim() || null;
@@ -41397,11 +41842,11 @@ async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
41397
41842
  return rows;
41398
41843
  }
41399
41844
  async function listRepoBranchesForBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
41400
- const bridgeResolved = path41.resolve(bridgeRoot);
41845
+ const bridgeResolved = path43.resolve(bridgeRoot);
41401
41846
  const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
41402
- const repoPath = rel === "" ? bridgeResolved : path41.join(bridgeResolved, rel);
41403
- const resolved = path41.resolve(repoPath);
41404
- if (!resolved.startsWith(bridgeResolved + path41.sep) && resolved !== bridgeResolved) {
41847
+ const repoPath = rel === "" ? bridgeResolved : path43.join(bridgeResolved, rel);
41848
+ const resolved = path43.resolve(repoPath);
41849
+ if (!resolved.startsWith(bridgeResolved + path43.sep) && resolved !== bridgeResolved) {
41405
41850
  return [];
41406
41851
  }
41407
41852
  return listRepoBranchRefs(resolved);
@@ -41906,10 +42351,10 @@ function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
41906
42351
  }
41907
42352
 
41908
42353
  // src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
41909
- import * as path43 from "node:path";
42354
+ import * as path45 from "node:path";
41910
42355
 
41911
42356
  // src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
41912
- import * as path42 from "node:path";
42357
+ import * as path44 from "node:path";
41913
42358
  async function probeOneAgentTypeForCapabilities(params) {
41914
42359
  const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true, shouldContinue } = params;
41915
42360
  const canContinue = () => shouldContinue?.() !== false;
@@ -41947,7 +42392,7 @@ async function probeOneAgentTypeForCapabilities(params) {
41947
42392
  if (!canContinue()) return false;
41948
42393
  handle = await resolved.createClient({
41949
42394
  command: resolved.command,
41950
- cwd: path42.resolve(cwd),
42395
+ cwd: path44.resolve(cwd),
41951
42396
  backendAgentType: agentType,
41952
42397
  sessionMode: "agent",
41953
42398
  persistedAcpSessionId: null,
@@ -42025,7 +42470,7 @@ async function warmupAgentCapabilitiesOnConnect(params) {
42025
42470
  const { workspaceId, log: log2, getWs } = params;
42026
42471
  const isCurrent = beginAgentCapabilityWarmupRun();
42027
42472
  if (!isCurrent()) return;
42028
- const cwd = path43.resolve(getBridgeRoot());
42473
+ const cwd = path45.resolve(getBridgeRoot());
42029
42474
  async function sendBatchFromCache() {
42030
42475
  if (!isCurrent()) return;
42031
42476
  const socket = getWs();
@@ -42091,9 +42536,74 @@ async function warmupAgentCapabilitiesOnConnect(params) {
42091
42536
  })();
42092
42537
  }
42093
42538
 
42094
- // src/mcp/tools/session-history/fork-session-mcp-tools.ts
42539
+ // src/mcp/tools/session-history/fork/mcp-text-result.ts
42540
+ function mcpTextResult(text, isError = false) {
42541
+ return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
42542
+ }
42543
+
42544
+ // src/mcp/tools/session-history/fork/call-get-parent-session-turn-transcript.ts
42545
+ async function callGetParentSessionTurnTranscriptTool(ctx, cloud, childSessionId, args) {
42546
+ const turnId = typeof args.turnId === "string" ? args.turnId.trim() : "";
42547
+ if (!turnId) return mcpTextResult("turnId is required.", true);
42548
+ const transcript = await fetchCloudParentTurnTranscript({
42549
+ childSessionId,
42550
+ turnId,
42551
+ cloudApiBaseUrl: cloud.cloudApiBaseUrl,
42552
+ getCloudAccessToken: cloud.getCloudAccessToken,
42553
+ e2ee: ctx.e2ee
42554
+ });
42555
+ if (!transcript.ok) return mcpTextResult(transcript.error, true);
42556
+ return mcpTextResult(transcript.text);
42557
+ }
42558
+
42559
+ // src/mcp/tools/session-history/fork/call-list-parent-session-prompts.ts
42560
+ async function callListParentSessionPromptsTool(ctx, cloud, childSessionId, parentSessionId) {
42561
+ const detail = await fetchCloudParentSessionPrompts({
42562
+ childSessionId,
42563
+ cloudApiBaseUrl: cloud.cloudApiBaseUrl,
42564
+ getCloudAccessToken: cloud.getCloudAccessToken,
42565
+ e2ee: ctx.e2ee
42566
+ });
42567
+ if (!detail.ok) return mcpTextResult(detail.error, true);
42568
+ const turns = Array.isArray(detail.data.turns) ? detail.data.turns : [];
42569
+ const payload = turns.map((t) => ({
42570
+ turnId: typeof t.turnId === "string" ? t.turnId : "",
42571
+ title: typeof t.title === "string" ? t.title : null,
42572
+ status: typeof t.status === "string" ? t.status : null,
42573
+ promptText: typeof t.promptText === "string" ? t.promptText : null
42574
+ }));
42575
+ return mcpTextResult(JSON.stringify({ parentSessionId, turns: payload }, null, 2));
42576
+ }
42577
+
42578
+ // src/mcp/tools/session-history/fork/tool-names.ts
42095
42579
  var LIST_PARENT_SESSION_PROMPTS_TOOL = "list_parent_session_prompts";
42096
42580
  var GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL = "get_parent_session_turn_transcript";
42581
+
42582
+ // src/mcp/tools/session-history/fork/call-fork-session-mcp-tool.ts
42583
+ async function callForkSessionMcpTool(ctx, cloud, name, args) {
42584
+ const childSessionId = ctx.sessionId.trim();
42585
+ if (!childSessionId) {
42586
+ return mcpTextResult("sessionId is required.", true);
42587
+ }
42588
+ const parentResolved = await resolveParentSessionIdForChild({
42589
+ childSessionId,
42590
+ cloudApiBaseUrl: cloud.cloudApiBaseUrl,
42591
+ getCloudAccessToken: cloud.getCloudAccessToken
42592
+ });
42593
+ if (!parentResolved.ok) {
42594
+ return mcpTextResult(parentResolved.error, true);
42595
+ }
42596
+ const parentSessionId = parentResolved.parentSessionId;
42597
+ if (name === LIST_PARENT_SESSION_PROMPTS_TOOL) {
42598
+ return callListParentSessionPromptsTool(ctx, cloud, childSessionId, parentSessionId);
42599
+ }
42600
+ if (name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL) {
42601
+ return callGetParentSessionTurnTranscriptTool(ctx, cloud, childSessionId, args);
42602
+ }
42603
+ return mcpTextResult(`Unknown fork session tool: ${name}`, true);
42604
+ }
42605
+
42606
+ // src/mcp/tools/session-history/fork/tool-definitions.ts
42097
42607
  var SESSION_ID_SCHEMA = {
42098
42608
  type: "string",
42099
42609
  description: "Id of this forked (child) session \u2014 not the parent session id. Required on every tool call."
@@ -42123,57 +42633,11 @@ var FORK_SESSION_MCP_TOOL_DEFINITIONS = [
42123
42633
  }
42124
42634
  }
42125
42635
  ];
42126
- function textResult(text, isError = false) {
42127
- return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
42128
- }
42636
+
42637
+ // src/mcp/tools/session-history/fork/is-fork-session-mcp-tool-name.ts
42129
42638
  function isForkSessionMcpToolName(name) {
42130
42639
  return name === LIST_PARENT_SESSION_PROMPTS_TOOL || name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL;
42131
42640
  }
42132
- async function callForkSessionMcpTool(ctx, cloud, name, args) {
42133
- const childSessionId = ctx.sessionId.trim();
42134
- if (!childSessionId) {
42135
- return textResult("sessionId is required.", true);
42136
- }
42137
- const parentResolved = await resolveParentSessionIdForChild({
42138
- childSessionId,
42139
- cloudApiBaseUrl: cloud.cloudApiBaseUrl,
42140
- getCloudAccessToken: cloud.getCloudAccessToken
42141
- });
42142
- if (!parentResolved.ok) {
42143
- return textResult(parentResolved.error, true);
42144
- }
42145
- const parentSessionId = parentResolved.parentSessionId;
42146
- if (name === LIST_PARENT_SESSION_PROMPTS_TOOL) {
42147
- const detail = await fetchCloudParentSessionPrompts({
42148
- childSessionId,
42149
- cloudApiBaseUrl: cloud.cloudApiBaseUrl,
42150
- getCloudAccessToken: cloud.getCloudAccessToken
42151
- });
42152
- if (!detail.ok) return textResult(detail.error, true);
42153
- const turns = Array.isArray(detail.data.turns) ? detail.data.turns : [];
42154
- const payload = turns.map((t) => ({
42155
- turnId: typeof t.turnId === "string" ? t.turnId : "",
42156
- title: typeof t.title === "string" ? t.title : null,
42157
- status: typeof t.status === "string" ? t.status : null,
42158
- promptText: typeof t.promptText === "string" ? t.promptText : null
42159
- }));
42160
- return textResult(JSON.stringify({ parentSessionId, turns: payload }, null, 2));
42161
- }
42162
- if (name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL) {
42163
- const turnId = typeof args.turnId === "string" ? args.turnId.trim() : "";
42164
- if (!turnId) return textResult("turnId is required.", true);
42165
- const transcript = await fetchCloudParentTurnTranscript({
42166
- childSessionId,
42167
- turnId,
42168
- cloudApiBaseUrl: cloud.cloudApiBaseUrl,
42169
- getCloudAccessToken: cloud.getCloudAccessToken,
42170
- e2ee: ctx.e2ee
42171
- });
42172
- if (!transcript.ok) return textResult(transcript.error, true);
42173
- return textResult(transcript.text);
42174
- }
42175
- return textResult(`Unknown fork session tool: ${name}`, true);
42176
- }
42177
42641
 
42178
42642
  // src/mcp/bridge-mcp-tools.ts
42179
42643
  function requireCloud(shared) {
@@ -42430,8 +42894,8 @@ async function createBridgeConnection(options) {
42430
42894
  getCloudAccessToken: () => tokens.accessToken
42431
42895
  };
42432
42896
  const identifyReportedPaths = {
42433
- bridgeRootPath: path44.resolve(getBridgeRoot()),
42434
- worktreesRootPath: path44.resolve(worktreesRootPath)
42897
+ bridgeRootPath: path46.resolve(getBridgeRoot()),
42898
+ worktreesRootPath: path46.resolve(worktreesRootPath)
42435
42899
  };
42436
42900
  const { connect } = createMainBridgeWebSocketLifecycle({
42437
42901
  state,
@@ -42686,9 +43150,9 @@ async function runCliAction(program2, opts) {
42686
43150
  const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
42687
43151
  const bridgeRootOpt = (opts.bridgeRoot && typeof opts.bridgeRoot === "string" && opts.bridgeRoot.trim() ? opts.bridgeRoot.trim() : null) ?? (opts.cwd && typeof opts.cwd === "string" && opts.cwd.trim() ? opts.cwd.trim() : null);
42688
43152
  if (bridgeRootOpt) {
42689
- const resolvedBridgeRoot = path45.resolve(process.cwd(), bridgeRootOpt);
43153
+ const resolvedBridgeRoot = path47.resolve(process.cwd(), bridgeRootOpt);
42690
43154
  try {
42691
- const st = fs40.statSync(resolvedBridgeRoot);
43155
+ const st = fs41.statSync(resolvedBridgeRoot);
42692
43156
  if (!st.isDirectory()) {
42693
43157
  console.error(`Bridge root is not a directory: ${resolvedBridgeRoot}`);
42694
43158
  process.exit(1);
@@ -42708,7 +43172,7 @@ async function runCliAction(program2, opts) {
42708
43172
  );
42709
43173
  let worktreesRootPath;
42710
43174
  if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
42711
- worktreesRootPath = path45.resolve(opts.worktreesRoot.trim());
43175
+ worktreesRootPath = path47.resolve(opts.worktreesRoot.trim());
42712
43176
  }
42713
43177
  const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
42714
43178
  if (e2eCertificates) {