@buildautomaton/cli 0.1.46 → 0.1.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.47".length > 0 ? "0.1.47" : "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";
@@ -27819,9 +27819,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
27819
27819
  const rawPath = typeof o.path === "string" ? o.path.trim() : "";
27820
27820
  const summary = typeof o.summary === "string" ? o.summary.trim() : "";
27821
27821
  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) });
27822
+ const path48 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
27823
+ if (!path48) continue;
27824
+ rows.push({ path: path48, summary: clampSummaryToAtMostTwoLines(summary) });
27825
27825
  }
27826
27826
  return rows;
27827
27827
  }
@@ -30981,8 +30981,8 @@ function pathspec(...paths) {
30981
30981
  cache.set(key, paths);
30982
30982
  return key;
30983
30983
  }
30984
- function isPathSpec(path46) {
30985
- return path46 instanceof String && cache.has(path46);
30984
+ function isPathSpec(path48) {
30985
+ return path48 instanceof String && cache.has(path48);
30986
30986
  }
30987
30987
  function toPaths(pathSpec) {
30988
30988
  return cache.get(pathSpec) || [];
@@ -31071,8 +31071,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
31071
31071
  function forEachLineWithContent(input, callback) {
31072
31072
  return toLinesWithContent(input, true).map((line) => callback(line));
31073
31073
  }
31074
- function folderExists(path46) {
31075
- return (0, import_file_exists.exists)(path46, import_file_exists.FOLDER);
31074
+ function folderExists(path48) {
31075
+ return (0, import_file_exists.exists)(path48, import_file_exists.FOLDER);
31076
31076
  }
31077
31077
  function append(target, item) {
31078
31078
  if (Array.isArray(target)) {
@@ -31476,8 +31476,8 @@ function checkIsRepoRootTask() {
31476
31476
  commands,
31477
31477
  format: "utf-8",
31478
31478
  onError,
31479
- parser(path46) {
31480
- return /^\.(git)?$/.test(path46.trim());
31479
+ parser(path48) {
31480
+ return /^\.(git)?$/.test(path48.trim());
31481
31481
  }
31482
31482
  };
31483
31483
  }
@@ -31911,11 +31911,11 @@ function parseGrep(grep) {
31911
31911
  const paths = /* @__PURE__ */ new Set();
31912
31912
  const results = {};
31913
31913
  forEachLineWithContent(grep, (input) => {
31914
- const [path46, line, preview] = input.split(NULL);
31915
- paths.add(path46);
31916
- (results[path46] = results[path46] || []).push({
31914
+ const [path48, line, preview] = input.split(NULL);
31915
+ paths.add(path48);
31916
+ (results[path48] = results[path48] || []).push({
31917
31917
  line: asNumber(line),
31918
- path: path46,
31918
+ path: path48,
31919
31919
  preview
31920
31920
  });
31921
31921
  });
@@ -32680,14 +32680,14 @@ var init_hash_object = __esm2({
32680
32680
  init_task();
32681
32681
  }
32682
32682
  });
32683
- function parseInit(bare, path46, text) {
32683
+ function parseInit(bare, path48, text) {
32684
32684
  const response = String(text).trim();
32685
32685
  let result;
32686
32686
  if (result = initResponseRegex.exec(response)) {
32687
- return new InitSummary(bare, path46, false, result[1]);
32687
+ return new InitSummary(bare, path48, false, result[1]);
32688
32688
  }
32689
32689
  if (result = reInitResponseRegex.exec(response)) {
32690
- return new InitSummary(bare, path46, true, result[1]);
32690
+ return new InitSummary(bare, path48, true, result[1]);
32691
32691
  }
32692
32692
  let gitDir = "";
32693
32693
  const tokens = response.split(" ");
@@ -32698,7 +32698,7 @@ function parseInit(bare, path46, text) {
32698
32698
  break;
32699
32699
  }
32700
32700
  }
32701
- return new InitSummary(bare, path46, /^re/i.test(response), gitDir);
32701
+ return new InitSummary(bare, path48, /^re/i.test(response), gitDir);
32702
32702
  }
32703
32703
  var InitSummary;
32704
32704
  var initResponseRegex;
@@ -32707,9 +32707,9 @@ var init_InitSummary = __esm2({
32707
32707
  "src/lib/responses/InitSummary.ts"() {
32708
32708
  "use strict";
32709
32709
  InitSummary = class {
32710
- constructor(bare, path46, existing, gitDir) {
32710
+ constructor(bare, path48, existing, gitDir) {
32711
32711
  this.bare = bare;
32712
- this.path = path46;
32712
+ this.path = path48;
32713
32713
  this.existing = existing;
32714
32714
  this.gitDir = gitDir;
32715
32715
  }
@@ -32721,7 +32721,7 @@ var init_InitSummary = __esm2({
32721
32721
  function hasBareCommand(command) {
32722
32722
  return command.includes(bareCommand);
32723
32723
  }
32724
- function initTask(bare = false, path46, customArgs) {
32724
+ function initTask(bare = false, path48, customArgs) {
32725
32725
  const commands = ["init", ...customArgs];
32726
32726
  if (bare && !hasBareCommand(commands)) {
32727
32727
  commands.splice(1, 0, bareCommand);
@@ -32730,7 +32730,7 @@ function initTask(bare = false, path46, customArgs) {
32730
32730
  commands,
32731
32731
  format: "utf-8",
32732
32732
  parser(text) {
32733
- return parseInit(commands.includes("--bare"), path46, text);
32733
+ return parseInit(commands.includes("--bare"), path48, text);
32734
32734
  }
32735
32735
  };
32736
32736
  }
@@ -33546,12 +33546,12 @@ var init_FileStatusSummary = __esm2({
33546
33546
  "use strict";
33547
33547
  fromPathRegex = /^(.+)\0(.+)$/;
33548
33548
  FileStatusSummary = class {
33549
- constructor(path46, index, working_dir) {
33550
- this.path = path46;
33549
+ constructor(path48, index, working_dir) {
33550
+ this.path = path48;
33551
33551
  this.index = index;
33552
33552
  this.working_dir = working_dir;
33553
33553
  if (index === "R" || working_dir === "R") {
33554
- const detail = fromPathRegex.exec(path46) || [null, path46, path46];
33554
+ const detail = fromPathRegex.exec(path48) || [null, path48, path48];
33555
33555
  this.from = detail[2] || "";
33556
33556
  this.path = detail[1] || "";
33557
33557
  }
@@ -33582,14 +33582,14 @@ function splitLine(result, lineStr) {
33582
33582
  default:
33583
33583
  return;
33584
33584
  }
33585
- function data(index, workingDir, path46) {
33585
+ function data(index, workingDir, path48) {
33586
33586
  const raw = `${index}${workingDir}`;
33587
33587
  const handler = parsers6.get(raw);
33588
33588
  if (handler) {
33589
- handler(result, path46);
33589
+ handler(result, path48);
33590
33590
  }
33591
33591
  if (raw !== "##" && raw !== "!!") {
33592
- result.files.push(new FileStatusSummary(path46, index, workingDir));
33592
+ result.files.push(new FileStatusSummary(path48, index, workingDir));
33593
33593
  }
33594
33594
  }
33595
33595
  }
@@ -33898,9 +33898,9 @@ var init_simple_git_api = __esm2({
33898
33898
  next
33899
33899
  );
33900
33900
  }
33901
- hashObject(path46, write) {
33901
+ hashObject(path48, write) {
33902
33902
  return this._runTask(
33903
- hashObjectTask(path46, write === true),
33903
+ hashObjectTask(path48, write === true),
33904
33904
  trailingFunctionArgument(arguments)
33905
33905
  );
33906
33906
  }
@@ -34253,8 +34253,8 @@ var init_branch = __esm2({
34253
34253
  }
34254
34254
  });
34255
34255
  function toPath(input) {
34256
- const path46 = input.trim().replace(/^["']|["']$/g, "");
34257
- return path46 && normalize3(path46);
34256
+ const path48 = input.trim().replace(/^["']|["']$/g, "");
34257
+ return path48 && normalize3(path48);
34258
34258
  }
34259
34259
  var parseCheckIgnore;
34260
34260
  var init_CheckIgnore = __esm2({
@@ -34568,8 +34568,8 @@ __export2(sub_module_exports, {
34568
34568
  subModuleTask: () => subModuleTask,
34569
34569
  updateSubModuleTask: () => updateSubModuleTask
34570
34570
  });
34571
- function addSubModuleTask(repo, path46) {
34572
- return subModuleTask(["add", repo, path46]);
34571
+ function addSubModuleTask(repo, path48) {
34572
+ return subModuleTask(["add", repo, path48]);
34573
34573
  }
34574
34574
  function initSubModuleTask(customArgs) {
34575
34575
  return subModuleTask(["init", ...customArgs]);
@@ -34902,8 +34902,8 @@ var require_git = __commonJS2({
34902
34902
  }
34903
34903
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
34904
34904
  };
34905
- Git2.prototype.submoduleAdd = function(repo, path46, then) {
34906
- return this._runTask(addSubModuleTask2(repo, path46), trailingFunctionArgument2(arguments));
34905
+ Git2.prototype.submoduleAdd = function(repo, path48, then) {
34906
+ return this._runTask(addSubModuleTask2(repo, path48), trailingFunctionArgument2(arguments));
34907
34907
  };
34908
34908
  Git2.prototype.submoduleUpdate = function(args, then) {
34909
34909
  return this._runTask(
@@ -35866,9 +35866,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
35866
35866
  // src/agents/acp/put-summarize-change-summaries.ts
35867
35867
  async function putEncryptedChangeSummaryRows(params) {
35868
35868
  const base = params.apiBaseUrl.replace(/\/+$/, "");
35869
- const entries = params.rows.map(({ path: path46, summary }) => {
35869
+ const entries = params.rows.map(({ path: path48, summary }) => {
35870
35870
  const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
35871
- return { path: path46, summary: JSON.stringify(enc) };
35871
+ return { path: path48, summary: JSON.stringify(enc) };
35872
35872
  });
35873
35873
  const res = await fetch(
35874
35874
  `${base}/internal/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
@@ -36462,7 +36462,7 @@ async function createAcpManager(options) {
36462
36462
  // src/git/changes/types.ts
36463
36463
  var MAX_PATCH_CHARS = 35e4;
36464
36464
 
36465
- // src/git/changes/lib/repo-format.ts
36465
+ // src/git/changes/paths/repo-format.ts
36466
36466
  function posixJoinDirFile(dir, file2) {
36467
36467
  const d = dir === "." || dir === "" ? "" : dir.replace(/\\/g, "/").replace(/\/+$/, "");
36468
36468
  const f = file2.replace(/\\/g, "/").replace(/^\/+/, "");
@@ -36517,7 +36517,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
36517
36517
  }
36518
36518
 
36519
36519
  // src/git/changes/get-working-tree-change-repo-details.ts
36520
- import * as path21 from "node:path";
36520
+ import * as path23 from "node:path";
36521
36521
 
36522
36522
  // src/git/commits/resolve-remote-tracking.ts
36523
36523
  async function tryConfigGet(g, key) {
@@ -36687,9 +36687,232 @@ async function listRecentCommits(repoDir, limitInput) {
36687
36687
  }
36688
36688
  }
36689
36689
 
36690
- // src/git/changes/lib/parse-git-status.ts
36691
- function parseNameStatusLines(lines) {
36692
- const m = /* @__PURE__ */ new Map();
36690
+ // src/git/changes/parse/normalize-git-diff-path.ts
36691
+ function normalizeGitDiffPath(path48) {
36692
+ return path48.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
36693
+ }
36694
+
36695
+ // src/git/changes/parse/expand-git-rename-numstat-path.ts
36696
+ function expandGitRenameNumstatPath(rawPath) {
36697
+ const open2 = rawPath.indexOf("{");
36698
+ const arrow = rawPath.indexOf("=>");
36699
+ const close = rawPath.lastIndexOf("}");
36700
+ if (open2 === -1 || arrow === -1 || close === -1 || open2 > arrow || arrow > close) {
36701
+ return null;
36702
+ }
36703
+ const prefix = rawPath.slice(0, open2);
36704
+ const suffix = rawPath.slice(close + 1);
36705
+ const oldPart = rawPath.slice(open2 + 1, arrow).trim();
36706
+ const newPart = rawPath.slice(arrow + 2, close).trim();
36707
+ return {
36708
+ oldPath: normalizeGitDiffPath(`${prefix}${oldPart}${suffix}`),
36709
+ newPath: normalizeGitDiffPath(`${prefix}${newPart}${suffix}`)
36710
+ };
36711
+ }
36712
+ function isGitRenameNumstatPath(rawPath) {
36713
+ return expandGitRenameNumstatPath(rawPath) != null;
36714
+ }
36715
+
36716
+ // src/git/changes/rows/build-changed-file-row.ts
36717
+ function buildChangedFileRow(options) {
36718
+ const pathInRepo = normalizeGitDiffPath(options.pathInRepo);
36719
+ const relLauncher = posixJoinDirFile(options.repoRelPath, pathInRepo);
36720
+ const additions = options.numEntry?.additions ?? 0;
36721
+ const deletions = options.numEntry?.deletions ?? 0;
36722
+ let change = options.nameEntry?.change ?? "modified";
36723
+ let movedFromPathRelLauncher;
36724
+ let movedFromPathInRepo;
36725
+ const oldPathInRepo = options.nameEntry?.oldPathInRepo ?? options.numEntry?.oldPathInRepo;
36726
+ if (change === "moved" && oldPathInRepo) {
36727
+ movedFromPathInRepo = normalizeGitDiffPath(oldPathInRepo);
36728
+ movedFromPathRelLauncher = posixJoinDirFile(options.repoRelPath, movedFromPathInRepo);
36729
+ } else if (oldPathInRepo && change === "modified") {
36730
+ change = "moved";
36731
+ movedFromPathInRepo = normalizeGitDiffPath(oldPathInRepo);
36732
+ movedFromPathRelLauncher = posixJoinDirFile(options.repoRelPath, movedFromPathInRepo);
36733
+ }
36734
+ if (options.untracked && !options.nameEntry) {
36735
+ change = "added";
36736
+ } else if (!options.nameEntry && options.numEntry && change !== "moved") {
36737
+ if (additions > 0 && deletions === 0) change = "added";
36738
+ else if (deletions > 0 && additions === 0) change = "removed";
36739
+ else change = "modified";
36740
+ }
36741
+ return {
36742
+ pathRelLauncher: relLauncher,
36743
+ additions,
36744
+ deletions,
36745
+ change,
36746
+ ...movedFromPathRelLauncher ? { movedFromPathRelLauncher } : {},
36747
+ ...movedFromPathInRepo ? { movedFromPathInRepo } : {}
36748
+ };
36749
+ }
36750
+
36751
+ // src/git/changes/listing/build-changed-file-rows.ts
36752
+ async function buildChangedFileRowsFromPaths(options) {
36753
+ const rows = [];
36754
+ await forEachWithGitYield([...options.paths], async (pathInRepo) => {
36755
+ if (isGitRenameNumstatPath(pathInRepo)) return;
36756
+ if (options.movedSourcePaths.has(pathInRepo)) return;
36757
+ const nameEntry = options.nameByPath.get(pathInRepo);
36758
+ const numEntry = options.numByPath.get(pathInRepo);
36759
+ const row = buildChangedFileRow({
36760
+ pathInRepo,
36761
+ repoRelPath: options.repoRelPath,
36762
+ nameEntry,
36763
+ numEntry,
36764
+ untracked: options.untrackedSet?.has(pathInRepo)
36765
+ });
36766
+ if (options.applyUntrackedStats) {
36767
+ await options.applyUntrackedStats(row, pathInRepo);
36768
+ }
36769
+ rows.push(row);
36770
+ });
36771
+ return rows;
36772
+ }
36773
+
36774
+ // src/git/changes/patch/patch-truncate.ts
36775
+ function truncatePatch(s) {
36776
+ if (s.length <= MAX_PATCH_CHARS) return s;
36777
+ return `${s.slice(0, MAX_PATCH_CHARS)}
36778
+
36779
+ \u2026 (diff truncated)`;
36780
+ }
36781
+
36782
+ // src/git/changes/patch/unified-diff-for-file.ts
36783
+ function patchTextFromGitDiffOutput(raw) {
36784
+ if (raw.trim() === "") return void 0;
36785
+ return normalizePatchContent(raw);
36786
+ }
36787
+ async function unifiedDiffForFile(repoCwd, pathInRepo, change, movedFromPathInRepo) {
36788
+ const g = cliSimpleGit(repoCwd);
36789
+ const renameArgs = ["-M", "--find-renames"];
36790
+ 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];
36791
+ const raw = await g.raw([...args]).catch(() => "");
36792
+ const patch = patchTextFromGitDiffOutput(String(raw));
36793
+ return patch ? truncatePatch(patch) : void 0;
36794
+ }
36795
+ async function unifiedDiffForFileInRange(repoCwd, range, pathInRepo, change, movedFromPathInRepo) {
36796
+ const g = cliSimpleGit(repoCwd);
36797
+ const renameArgs = ["-M", "--find-renames"];
36798
+ const args = change === "moved" && movedFromPathInRepo ? ["diff", "--no-color", ...renameArgs, "-U20000", range, "--", movedFromPathInRepo, pathInRepo] : ["diff", "--no-color", ...renameArgs, "-U20000", range, "--", pathInRepo];
36799
+ const raw = await g.raw([...args]).catch(() => "");
36800
+ const patch = patchTextFromGitDiffOutput(String(raw));
36801
+ return patch ? truncatePatch(patch) : void 0;
36802
+ }
36803
+
36804
+ // src/git/changes/total-lines/resolve-changed-file-total-lines.ts
36805
+ import * as fs17 from "node:fs";
36806
+ import * as path20 from "node:path";
36807
+
36808
+ // src/git/changes/lines/count-lines.ts
36809
+ import { createReadStream } from "node:fs";
36810
+ import * as readline2 from "node:readline";
36811
+ function countLinesInText(text) {
36812
+ return splitTextIntoDiffLines(text).length;
36813
+ }
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;
36827
+ }
36828
+ }
36829
+ return lines;
36830
+ }
36831
+
36832
+ // src/git/changes/total-lines/resolve-changed-file-total-lines.ts
36833
+ var MAX_BYTES = 512e3;
36834
+ async function countLinesInGitRef(repoGitCwd, ref, pathInRepo) {
36835
+ const spec = `${ref}:${pathInRepo}`;
36836
+ const g = cliSimpleGit(repoGitCwd);
36837
+ try {
36838
+ await g.raw(["cat-file", "-e", spec]);
36839
+ } catch {
36840
+ return null;
36841
+ }
36842
+ try {
36843
+ const raw = String(await g.raw(["show", spec]));
36844
+ const capped = raw.length > MAX_BYTES ? raw.slice(0, MAX_BYTES) : raw;
36845
+ return countLinesInText(capped);
36846
+ } catch {
36847
+ return null;
36848
+ }
36849
+ }
36850
+ async function resolveWorkingTreeFileTotalLines(options) {
36851
+ if (options.isBinary) return null;
36852
+ const filePath = path20.join(options.repoGitCwd, options.pathInRepo);
36853
+ if (options.change === "removed") {
36854
+ return countLinesInGitRef(options.repoGitCwd, "HEAD", options.pathInRepo);
36855
+ }
36856
+ if (options.change === "moved" || options.change === "modified") {
36857
+ try {
36858
+ const st = await fs17.promises.stat(filePath);
36859
+ if (!st.isFile()) return null;
36860
+ return await countTextFileLines(filePath);
36861
+ } catch {
36862
+ return null;
36863
+ }
36864
+ }
36865
+ return null;
36866
+ }
36867
+ async function resolveCommitFileTotalLines(options) {
36868
+ if (options.isBinary) return null;
36869
+ if (options.change === "removed") {
36870
+ return countLinesInGitRef(options.repoGitCwd, options.parentSha, options.pathInRepo);
36871
+ }
36872
+ if (options.change === "moved" || options.change === "modified") {
36873
+ return countLinesInGitRef(options.repoGitCwd, options.commitSha, options.pathInRepo);
36874
+ }
36875
+ return null;
36876
+ }
36877
+
36878
+ // src/git/changes/listing/path-in-repo-from-launcher.ts
36879
+ function pathInRepoFromLauncher(pathRelLauncher, repoRelPath) {
36880
+ const normRel = repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
36881
+ if (normRel === ".") return pathRelLauncher;
36882
+ if (pathRelLauncher.startsWith(`${normRel}/`)) {
36883
+ return pathRelLauncher.slice(normRel.length + 1);
36884
+ }
36885
+ return pathRelLauncher;
36886
+ }
36887
+ function normalizeRepoRelPath(repoRelPath) {
36888
+ return repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
36889
+ }
36890
+
36891
+ // src/git/changes/listing/enrich-commit-file-rows.ts
36892
+ async function enrichCommitFileRows(options) {
36893
+ await forEachWithGitYield(options.rows, async (row) => {
36894
+ const pathInRepo = pathInRepoFromLauncher(row.pathRelLauncher, options.repoRelPath);
36895
+ row.patchContent = await unifiedDiffForFileInRange(
36896
+ options.repoGitCwd,
36897
+ options.range,
36898
+ pathInRepo,
36899
+ row.change,
36900
+ row.movedFromPathInRepo
36901
+ );
36902
+ row.totalLines = await resolveCommitFileTotalLines({
36903
+ repoGitCwd: options.repoGitCwd,
36904
+ pathInRepo,
36905
+ change: row.change,
36906
+ commitSha: options.commitSha,
36907
+ parentSha: options.parentSha,
36908
+ isBinary: options.binaryByPath.has(pathInRepo)
36909
+ });
36910
+ });
36911
+ }
36912
+
36913
+ // src/git/changes/parse/parse-name-status-entries.ts
36914
+ function parseNameStatusEntries(lines) {
36915
+ const entries = [];
36693
36916
  for (const line of lines) {
36694
36917
  if (!line.trim()) continue;
36695
36918
  const tabParts = line.split(" ");
@@ -36697,58 +36920,143 @@ function parseNameStatusLines(lines) {
36697
36920
  const status = tabParts[0].trim();
36698
36921
  const code = status[0];
36699
36922
  if (code === "A") {
36700
- m.set(tabParts[tabParts.length - 1], "added");
36923
+ entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "added" });
36701
36924
  } else if (code === "D") {
36702
- m.set(tabParts[tabParts.length - 1], "removed");
36925
+ entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "removed" });
36703
36926
  } else if (code === "R" || code === "C") {
36704
- if (tabParts.length >= 3) m.set(tabParts[tabParts.length - 1], "modified");
36927
+ if (tabParts.length >= 3) {
36928
+ entries.push({
36929
+ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]),
36930
+ oldPathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 2]),
36931
+ change: "moved"
36932
+ });
36933
+ }
36705
36934
  } else if (code === "M" || code === "U" || code === "T") {
36706
- m.set(tabParts[tabParts.length - 1], "modified");
36935
+ entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "modified" });
36707
36936
  }
36708
36937
  }
36938
+ return entries;
36939
+ }
36940
+ function parseNameStatusLines(lines) {
36941
+ const m = /* @__PURE__ */ new Map();
36942
+ for (const entry of parseNameStatusEntries(lines)) {
36943
+ m.set(entry.pathInRepo, entry.change);
36944
+ }
36709
36945
  return m;
36710
36946
  }
36711
- function parseNumstatFirstLine(line) {
36947
+
36948
+ // src/git/changes/parse/parse-numstat-entries.ts
36949
+ function parseNumstatCounts(parts) {
36950
+ const [a, d] = parts;
36951
+ return {
36952
+ additions: a === "-" ? 0 : parseInt(String(a), 10) || 0,
36953
+ deletions: d === "-" ? 0 : parseInt(String(d), 10) || 0
36954
+ };
36955
+ }
36956
+ function parseNumstatLine(line) {
36712
36957
  const parts = line.split(" ");
36713
36958
  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 };
36959
+ const rawPath = parts[parts.length - 1];
36960
+ const { additions, deletions } = parseNumstatCounts(parts);
36961
+ const expanded = expandGitRenameNumstatPath(rawPath);
36962
+ const pathInRepo = normalizeGitDiffPath(expanded?.newPath ?? rawPath);
36963
+ return {
36964
+ pathInRepo,
36965
+ additions,
36966
+ deletions,
36967
+ ...expanded ? { oldPathInRepo: expanded.oldPath } : {}
36968
+ };
36718
36969
  }
36719
- function parseNumstat(lines) {
36970
+ function parseNumstatEntries(lines) {
36720
36971
  const m = /* @__PURE__ */ new Map();
36721
36972
  for (const line of lines) {
36722
36973
  if (!line.trim()) continue;
36723
36974
  const parts = line.split(" ");
36724
36975
  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 });
36976
+ const rawPath = parts[parts.length - 1];
36977
+ const expanded = expandGitRenameNumstatPath(rawPath);
36978
+ const entry = parseNumstatLine(line);
36979
+ if (!entry) continue;
36980
+ const existing = m.get(entry.pathInRepo);
36981
+ if (!existing || expanded) {
36982
+ m.set(entry.pathInRepo, entry);
36983
+ }
36729
36984
  }
36730
36985
  return m;
36731
36986
  }
36987
+ function parseNumstat(lines) {
36988
+ const m = /* @__PURE__ */ new Map();
36989
+ for (const [path48, entry] of parseNumstatEntries(lines)) {
36990
+ m.set(path48, { additions: entry.additions, deletions: entry.deletions });
36991
+ }
36992
+ return m;
36993
+ }
36994
+
36995
+ // src/git/changes/parse/numstat-from-git-no-index.ts
36732
36996
  async function numstatFromGitNoIndex(g, pathInRepo) {
36733
36997
  const devNull = process.platform === "win32" ? "NUL" : "/dev/null";
36734
36998
  try {
36735
36999
  const out = await g.raw(["diff", "--numstat", "--no-index", "--", devNull, pathInRepo]);
36736
37000
  const first2 = String(out).split("\n").find((l) => l.trim()) ?? "";
36737
- return parseNumstatFirstLine(first2);
37001
+ const parsed = parseNumstatLine(first2);
37002
+ if (!parsed) return null;
37003
+ return { additions: parsed.additions, deletions: parsed.deletions };
36738
37004
  } catch {
36739
37005
  return null;
36740
37006
  }
36741
37007
  }
36742
37008
 
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)}
37009
+ // src/git/changes/rows/collect-moved-source-paths.ts
37010
+ function collectMovedSourcePaths(nameEntries, numByPath) {
37011
+ const sources = /* @__PURE__ */ new Set();
37012
+ for (const entry of nameEntries) {
37013
+ if (entry.change === "moved" && entry.oldPathInRepo) sources.add(entry.oldPathInRepo);
37014
+ }
37015
+ for (const entry of numByPath.values()) {
37016
+ if (entry.oldPathInRepo) sources.add(entry.oldPathInRepo);
37017
+ }
37018
+ return sources;
37019
+ }
36747
37020
 
36748
- \u2026 (diff truncated)`;
37021
+ // src/git/changes/numstat/is-binary-numstat-line.ts
37022
+ function isBinaryNumstatLine(line) {
37023
+ const parts = line.split(" ");
37024
+ if (parts.length < 3) return false;
37025
+ return parts[0] === "-" || parts[1] === "-";
36749
37026
  }
36750
37027
 
36751
- // src/git/commits/list-changed-files-for-commit.ts
37028
+ // src/git/changes/listing/collect-binary-paths-from-numstat.ts
37029
+ function collectBinaryPathsFromNumstat(numstatRaw) {
37030
+ const binaryByPath = /* @__PURE__ */ new Set();
37031
+ for (const line of numstatRaw.split("\n")) {
37032
+ if (!line.trim()) continue;
37033
+ const parts = line.split(" ");
37034
+ if (parts.length < 3) continue;
37035
+ const rawPath = parts[parts.length - 1];
37036
+ const expanded = expandGitRenameNumstatPath(rawPath);
37037
+ if (isBinaryNumstatLine(line)) binaryByPath.add(expanded?.newPath ?? rawPath);
37038
+ }
37039
+ return binaryByPath;
37040
+ }
37041
+
37042
+ // src/git/changes/listing/parse-diff-output.ts
37043
+ function parseDiffOutput(nameStatusRaw, numstatRaw) {
37044
+ const nameEntries = parseNameStatusEntries(nameStatusRaw.split("\n"));
37045
+ const nameByPath = new Map(nameEntries.map((entry) => [entry.pathInRepo, entry]));
37046
+ const numByPath = parseNumstatEntries(numstatRaw.split("\n"));
37047
+ const movedSourcePaths = collectMovedSourcePaths(nameEntries, numByPath);
37048
+ const binaryByPath = collectBinaryPathsFromNumstat(numstatRaw);
37049
+ return { nameEntries, nameByPath, numByPath, movedSourcePaths, binaryByPath };
37050
+ }
37051
+ function collectChangedPaths(options) {
37052
+ const paths = /* @__PURE__ */ new Set();
37053
+ for (const entry of options.nameEntries) paths.add(entry.pathInRepo);
37054
+ for (const pathInRepo of options.numByPath.keys()) paths.add(pathInRepo);
37055
+ for (const pathInRepo of options.untracked ?? []) paths.add(pathInRepo);
37056
+ return paths;
37057
+ }
37058
+
37059
+ // src/git/changes/listing/parent-for-commit-diff.ts
36752
37060
  var EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
36753
37061
  async function parentForCommitDiff(g, sha) {
36754
37062
  try {
@@ -36761,76 +37069,112 @@ async function parentForCommitDiff(g, sha) {
36761
37069
  }
36762
37070
  }
36763
37071
  }
37072
+
37073
+ // src/git/changes/listing/rename-diff-args.ts
37074
+ var RENAME_DIFF_ARGS = ["-M", "--find-renames"];
37075
+
37076
+ // src/git/changes/rows/pick-preferred-changed-file-row.ts
37077
+ function rowRank(row) {
37078
+ if (row.change === "moved") return 3;
37079
+ if (row.change === "modified") return 2;
37080
+ if (row.change === "added") return 1;
37081
+ return 0;
37082
+ }
37083
+ function pickPreferredChangedFileRow(a, b) {
37084
+ if (rowRank(a) !== rowRank(b)) return rowRank(a) > rowRank(b) ? a : b;
37085
+ const aHasPatch = Boolean(a.patchContent?.trim());
37086
+ const bHasPatch = Boolean(b.patchContent?.trim());
37087
+ if (aHasPatch !== bHasPatch) return aHasPatch ? a : b;
37088
+ const aHasMoveMeta = Boolean(a.movedFromPathInRepo || a.movedFromPathRelLauncher);
37089
+ const bHasMoveMeta = Boolean(b.movedFromPathInRepo || b.movedFromPathRelLauncher);
37090
+ if (aHasMoveMeta !== bHasMoveMeta) return aHasMoveMeta ? a : b;
37091
+ return a;
37092
+ }
37093
+
37094
+ // src/git/changes/rows/dedupe-changed-file-rows.ts
37095
+ function dedupeChangedFileRows(rows) {
37096
+ const byPath = /* @__PURE__ */ new Map();
37097
+ for (const row of rows) {
37098
+ const key = normalizeGitDiffPath(row.pathRelLauncher);
37099
+ const normalizedRow = key === row.pathRelLauncher ? row : { ...row, pathRelLauncher: key };
37100
+ const existing = byPath.get(key);
37101
+ if (!existing) {
37102
+ byPath.set(key, normalizedRow);
37103
+ continue;
37104
+ }
37105
+ const preferRow = pickPreferredChangedFileRow(existing, normalizedRow);
37106
+ byPath.set(key, { ...preferRow, pathRelLauncher: key });
37107
+ }
37108
+ return [...byPath.values()];
37109
+ }
37110
+
37111
+ // src/git/changes/listing/list-changed-files-for-commit.ts
36764
37112
  async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
36765
37113
  const g = cliSimpleGit(repoGitCwd);
36766
37114
  const parent = await parentForCommitDiff(g, commitSha);
36767
37115
  const range = `${parent}..${commitSha}`;
36768
37116
  const [nameStatusRaw, numstatRaw] = await Promise.all([
36769
- g.raw(["diff", "--name-status", range]).catch(() => ""),
36770
- g.raw(["diff", "--numstat", range]).catch(() => "")
37117
+ g.raw(["diff", ...RENAME_DIFF_ARGS, "--name-status", range]).catch(() => ""),
37118
+ g.raw(["diff", ...RENAME_DIFF_ARGS, "--numstat", range]).catch(() => "")
36771
37119
  ]);
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;
37120
+ const parsed = parseDiffOutput(String(nameStatusRaw), String(numstatRaw));
37121
+ const normRel = normalizeRepoRelPath(repoRelPath);
37122
+ const paths = collectChangedPaths({
37123
+ nameEntries: parsed.nameEntries,
37124
+ numByPath: parsed.numByPath
36802
37125
  });
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
37126
+ let rows = await buildChangedFileRowsFromPaths({
37127
+ paths,
37128
+ repoRelPath: normRel,
37129
+ nameByPath: parsed.nameByPath,
37130
+ numByPath: parsed.numByPath,
37131
+ movedSourcePaths: parsed.movedSourcePaths
37132
+ });
37133
+ rows = dedupeChangedFileRows(rows);
37134
+ await enrichCommitFileRows({
37135
+ rows,
37136
+ repoGitCwd,
37137
+ repoRelPath: normRel,
37138
+ range,
37139
+ commitSha,
37140
+ parentSha: parent,
37141
+ binaryByPath: parsed.binaryByPath
37142
+ });
37143
+ const finalRows = dedupeChangedFileRows(rows);
37144
+ finalRows.sort((a, b) => a.pathRelLauncher.localeCompare(b.pathRelLauncher));
37145
+ return finalRows;
37146
+ }
37147
+
37148
+ // src/git/changes/listing/apply-untracked-file-stats.ts
36808
37149
  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;
37150
+ import * as path21 from "node:path";
37151
+ function createUntrackedStatsApplier(options) {
37152
+ return async (row, pathInRepo) => {
37153
+ if (!options.untrackedSet.has(pathInRepo)) return;
37154
+ if (options.nameByPath.has(pathInRepo)) return;
37155
+ if (row.change === "moved") return;
37156
+ const repoFilePath = path21.join(options.repoGitCwd, pathInRepo);
37157
+ const fromGit = await numstatFromGitNoIndex(options.g, pathInRepo);
37158
+ if (fromGit) {
37159
+ row.additions = fromGit.additions;
37160
+ row.deletions = fromGit.deletions;
37161
+ return;
36827
37162
  }
36828
- }
36829
- return lines;
37163
+ try {
37164
+ const st = await fs18.promises.stat(repoFilePath);
37165
+ row.additions = st.isFile() ? await countTextFileLines(repoFilePath) : 0;
37166
+ } catch {
37167
+ row.additions = 0;
37168
+ }
37169
+ row.deletions = 0;
37170
+ };
36830
37171
  }
36831
37172
 
36832
- // src/git/changes/hydrate-patch.ts
36833
- import * as fs17 from "node:fs";
37173
+ // src/git/changes/listing/enrich-working-tree-file-rows.ts
37174
+ import * as path22 from "node:path";
37175
+
37176
+ // src/git/changes/patch/hydrate-patch.ts
37177
+ import * as fs19 from "node:fs";
36834
37178
  var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
36835
37179
  var MAX_HYDRATE_LINES_PER_GAP = 8e3;
36836
37180
  var MAX_HYDRATE_LINES_PER_FILE = 8e4;
@@ -36845,7 +37189,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
36845
37189
  }
36846
37190
  async function readWorktreeFileLines(filePath) {
36847
37191
  try {
36848
- const raw = await fs17.promises.readFile(filePath, "utf8");
37192
+ const raw = await fs19.promises.readFile(filePath, "utf8");
36849
37193
  return raw.split(/\r?\n/);
36850
37194
  } catch {
36851
37195
  return null;
@@ -36945,82 +37289,70 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
36945
37289
  return truncatePatch(out.join("\n"));
36946
37290
  }
36947
37291
 
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;
37292
+ // src/git/changes/listing/enrich-working-tree-file-rows.ts
37293
+ async function enrichWorkingTreeFileRows(options) {
37294
+ await forEachWithGitYield(options.rows, async (row) => {
37295
+ const pathInRepo = pathInRepoFromLauncher(row.pathRelLauncher, options.repoRelPath);
37296
+ const filePath = path22.join(options.repoGitCwd, pathInRepo);
37297
+ const hydrateKind = row.change === "moved" ? "modified" : row.change;
37298
+ let patch = await unifiedDiffForFile(options.repoGitCwd, pathInRepo, row.change, row.movedFromPathInRepo);
37299
+ if (patch) {
37300
+ patch = await hydrateUnifiedPatchWithFileContext(
37301
+ patch,
37302
+ filePath,
37303
+ options.repoGitCwd,
37304
+ pathInRepo,
37305
+ hydrateKind
37306
+ );
37307
+ }
37308
+ row.patchContent = patch;
37309
+ row.totalLines = await resolveWorkingTreeFileTotalLines({
37310
+ repoGitCwd: options.repoGitCwd,
37311
+ pathInRepo,
37312
+ change: row.change,
37313
+ isBinary: options.binaryByPath.has(pathInRepo)
37314
+ });
37315
+ });
36959
37316
  }
36960
37317
 
36961
- // src/git/changes/list-changed-files-for-repo.ts
37318
+ // src/git/changes/listing/list-changed-files-for-repo.ts
36962
37319
  async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
36963
37320
  const g = cliSimpleGit(repoGitCwd);
36964
37321
  const [nameStatusRaw, numstatRaw, untrackedRaw] = await Promise.all([
36965
- g.raw(["diff", "--name-status", "HEAD"]).catch(() => ""),
36966
- g.raw(["diff", "HEAD", "--numstat"]).catch(() => ""),
37322
+ g.raw(["diff", ...RENAME_DIFF_ARGS, "--name-status", "HEAD"]).catch(() => ""),
37323
+ g.raw(["diff", ...RENAME_DIFF_ARGS, "HEAD", "--numstat"]).catch(() => ""),
36967
37324
  g.raw(["ls-files", "--others", "--exclude-standard"]).catch(() => "")
36968
37325
  ]);
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()]);
37326
+ const parsed = parseDiffOutput(String(nameStatusRaw), String(numstatRaw));
36972
37327
  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 });
37328
+ const untrackedSet = new Set(untracked);
37329
+ const paths = collectChangedPaths({
37330
+ nameEntries: parsed.nameEntries,
37331
+ numByPath: parsed.numByPath,
37332
+ untracked
37005
37333
  });
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;
37334
+ let rows = await buildChangedFileRowsFromPaths({
37335
+ paths,
37336
+ repoRelPath,
37337
+ nameByPath: parsed.nameByPath,
37338
+ numByPath: parsed.numByPath,
37339
+ movedSourcePaths: parsed.movedSourcePaths,
37340
+ untrackedSet,
37341
+ applyUntrackedStats: createUntrackedStatsApplier({
37342
+ g,
37343
+ repoGitCwd,
37344
+ untrackedSet,
37345
+ nameByPath: parsed.nameByPath
37346
+ })
37022
37347
  });
37023
- return rows;
37348
+ rows = dedupeChangedFileRows(rows);
37349
+ await enrichWorkingTreeFileRows({
37350
+ rows,
37351
+ repoGitCwd,
37352
+ repoRelPath,
37353
+ binaryByPath: parsed.binaryByPath
37354
+ });
37355
+ return dedupeChangedFileRows(rows);
37024
37356
  }
37025
37357
 
37026
37358
  // src/git/changes/get-working-tree-change-repo-details.ts
@@ -37029,8 +37361,8 @@ function normRepoRel(p) {
37029
37361
  return x === "" ? "." : x;
37030
37362
  }
37031
37363
  async function getWorkingTreeChangeRepoDetails(options) {
37032
- const bridgeRoot = path21.resolve(getBridgeRoot());
37033
- const sessionWtRoot = options.sessionWorktreeRootPath ? path21.resolve(options.sessionWorktreeRootPath) : null;
37364
+ const bridgeRoot = path23.resolve(getBridgeRoot());
37365
+ const sessionWtRoot = options.sessionWorktreeRootPath ? path23.resolve(options.sessionWorktreeRootPath) : null;
37034
37366
  const legacyNested = options.legacyRepoNestedSessionLayout === true;
37035
37367
  const out = [];
37036
37368
  const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
@@ -37045,7 +37377,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
37045
37377
  for (let i = 0; i < options.commitTargetPaths.length; i++) {
37046
37378
  if (i > 0) await yieldToEventLoop2();
37047
37379
  const target = options.commitTargetPaths[i];
37048
- const t = path21.resolve(target);
37380
+ const t = path23.resolve(target);
37049
37381
  if (!await isGitRepoDirectory(t)) continue;
37050
37382
  const g = cliSimpleGit(t);
37051
37383
  let branch = "HEAD";
@@ -37058,8 +37390,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
37058
37390
  const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
37059
37391
  let repoRelPath;
37060
37392
  if (sessionWtRoot) {
37061
- const anchor = legacyNested ? path21.dirname(t) : t;
37062
- const relNorm = path21.relative(sessionWtRoot, anchor);
37393
+ const anchor = legacyNested ? path23.dirname(t) : t;
37394
+ const relNorm = path23.relative(sessionWtRoot, anchor);
37063
37395
  repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
37064
37396
  } else {
37065
37397
  let top = t;
@@ -37068,8 +37400,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
37068
37400
  } catch {
37069
37401
  top = t;
37070
37402
  }
37071
- const rel = path21.relative(bridgeRoot, path21.resolve(top)).replace(/\\/g, "/") || ".";
37072
- repoRelPath = rel.startsWith("..") ? path21.basename(path21.resolve(top)) : rel;
37403
+ const rel = path23.relative(bridgeRoot, path23.resolve(top)).replace(/\\/g, "/") || ".";
37404
+ repoRelPath = rel.startsWith("..") ? path23.basename(path23.resolve(top)) : rel;
37073
37405
  }
37074
37406
  const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
37075
37407
  if (filter && norm !== filter) continue;
@@ -37101,7 +37433,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
37101
37433
  return out;
37102
37434
  }
37103
37435
 
37104
- // src/git/changes/lib/working-tree-changed-path-count.ts
37436
+ // src/git/changes/status/working-tree-changed-path-count.ts
37105
37437
  function workingTreeChangedPathCount(nameStatusLines, numstatLines, untrackedLines) {
37106
37438
  const kindByPath = parseNameStatusLines(nameStatusLines);
37107
37439
  const numByPath = parseNumstat(numstatLines);
@@ -37197,23 +37529,23 @@ async function commitSessionWorktrees(options) {
37197
37529
  }
37198
37530
 
37199
37531
  // src/worktrees/remove-session-worktrees.ts
37200
- import * as fs21 from "node:fs";
37532
+ import * as fs22 from "node:fs";
37201
37533
 
37202
37534
  // src/git/worktrees/worktree-remove.ts
37203
- import * as fs20 from "node:fs";
37535
+ import * as fs21 from "node:fs";
37204
37536
 
37205
37537
  // src/git/worktrees/resolve-main-repo-from-git-file.ts
37206
- import * as fs19 from "node:fs";
37207
- import * as path22 from "node:path";
37538
+ import * as fs20 from "node:fs";
37539
+ import * as path24 from "node:path";
37208
37540
  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();
37541
+ const gitDirFile = path24.join(wt, ".git");
37542
+ if (!fs20.existsSync(gitDirFile) || !fs20.statSync(gitDirFile).isFile()) return "";
37543
+ const first2 = fs20.readFileSync(gitDirFile, "utf8").trim();
37212
37544
  const m = first2.match(/^gitdir:\s*(.+)$/im);
37213
37545
  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);
37546
+ const gitWorktreePath = path24.resolve(wt, m[1].trim());
37547
+ const gitDir = path24.dirname(path24.dirname(gitWorktreePath));
37548
+ return path24.dirname(gitDir);
37217
37549
  }
37218
37550
 
37219
37551
  // src/git/worktrees/worktree-remove.ts
@@ -37222,7 +37554,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
37222
37554
  if (mainRepo) {
37223
37555
  await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
37224
37556
  } else {
37225
- fs20.rmSync(worktreePath, { recursive: true, force: true });
37557
+ fs21.rmSync(worktreePath, { recursive: true, force: true });
37226
37558
  }
37227
37559
  }
37228
37560
 
@@ -37235,7 +37567,7 @@ async function removeSessionWorktrees(paths, log2) {
37235
37567
  } catch (e) {
37236
37568
  log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
37237
37569
  try {
37238
- fs21.rmSync(wt, { recursive: true, force: true });
37570
+ fs22.rmSync(wt, { recursive: true, force: true });
37239
37571
  } catch {
37240
37572
  }
37241
37573
  }
@@ -37264,12 +37596,12 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
37264
37596
  }
37265
37597
 
37266
37598
  // src/worktrees/worktree-layout-file.ts
37267
- import * as fs22 from "node:fs";
37268
- import * as path23 from "node:path";
37599
+ import * as fs23 from "node:fs";
37600
+ import * as path25 from "node:path";
37269
37601
  import os7 from "node:os";
37270
37602
  var LAYOUT_FILENAME = "worktree-launcher-layout.json";
37271
37603
  function defaultWorktreeLayoutPath() {
37272
- return path23.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
37604
+ return path25.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
37273
37605
  }
37274
37606
  function normalizeLoadedLayout(raw) {
37275
37607
  if (raw && typeof raw === "object" && "launcherCwds" in raw) {
@@ -37281,8 +37613,8 @@ function normalizeLoadedLayout(raw) {
37281
37613
  function loadWorktreeLayout() {
37282
37614
  try {
37283
37615
  const p = defaultWorktreeLayoutPath();
37284
- if (!fs22.existsSync(p)) return { launcherCwds: [] };
37285
- const raw = JSON.parse(fs22.readFileSync(p, "utf8"));
37616
+ if (!fs23.existsSync(p)) return { launcherCwds: [] };
37617
+ const raw = JSON.parse(fs23.readFileSync(p, "utf8"));
37286
37618
  return normalizeLoadedLayout(raw);
37287
37619
  } catch {
37288
37620
  return { launcherCwds: [] };
@@ -37290,24 +37622,24 @@ function loadWorktreeLayout() {
37290
37622
  }
37291
37623
  function saveWorktreeLayout(layout) {
37292
37624
  try {
37293
- const dir = path23.dirname(defaultWorktreeLayoutPath());
37294
- fs22.mkdirSync(dir, { recursive: true });
37295
- fs22.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
37625
+ const dir = path25.dirname(defaultWorktreeLayoutPath());
37626
+ fs23.mkdirSync(dir, { recursive: true });
37627
+ fs23.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
37296
37628
  } catch {
37297
37629
  }
37298
37630
  }
37299
37631
  function baseNameSafe(pathString) {
37300
- return path23.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
37632
+ return path25.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
37301
37633
  }
37302
37634
  function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
37303
- const norm = path23.resolve(bridgeRootPath2);
37304
- const existing = layout.launcherCwds.find((e) => path23.resolve(e.absolutePath) === norm);
37635
+ const norm = path25.resolve(bridgeRootPath2);
37636
+ const existing = layout.launcherCwds.find((e) => path25.resolve(e.absolutePath) === norm);
37305
37637
  return existing?.dirName;
37306
37638
  }
37307
37639
  function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
37308
37640
  const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
37309
37641
  if (existing) return existing;
37310
- const norm = path23.resolve(bridgeRootPath2);
37642
+ const norm = path25.resolve(bridgeRootPath2);
37311
37643
  const base = baseNameSafe(norm);
37312
37644
  const used = new Set(layout.launcherCwds.map((e) => e.dirName));
37313
37645
  let name = base;
@@ -37322,11 +37654,11 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
37322
37654
  }
37323
37655
 
37324
37656
  // src/worktrees/discover-session-worktree-on-disk.ts
37325
- import * as fs23 from "node:fs";
37326
- import * as path24 from "node:path";
37657
+ import * as fs24 from "node:fs";
37658
+ import * as path26 from "node:path";
37327
37659
  function isGitDir(dirPath) {
37328
37660
  try {
37329
- return fs23.existsSync(path24.join(dirPath, ".git"));
37661
+ return fs24.existsSync(path26.join(dirPath, ".git"));
37330
37662
  } catch {
37331
37663
  return false;
37332
37664
  }
@@ -37335,23 +37667,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
37335
37667
  const out = [];
37336
37668
  const walk = (dir) => {
37337
37669
  if (isGitDir(dir)) {
37338
- out.push(path24.resolve(dir));
37670
+ out.push(path26.resolve(dir));
37339
37671
  return;
37340
37672
  }
37341
37673
  let entries;
37342
37674
  try {
37343
- entries = fs23.readdirSync(dir, { withFileTypes: true });
37675
+ entries = fs24.readdirSync(dir, { withFileTypes: true });
37344
37676
  } catch {
37345
37677
  return;
37346
37678
  }
37347
37679
  for (const e of entries) {
37348
37680
  if (e.name.startsWith(".")) continue;
37349
- const full = path24.join(dir, e.name);
37681
+ const full = path26.join(dir, e.name);
37350
37682
  if (!e.isDirectory()) continue;
37351
37683
  walk(full);
37352
37684
  }
37353
37685
  };
37354
- walk(path24.resolve(rootPath));
37686
+ walk(path26.resolve(rootPath));
37355
37687
  return [...new Set(out)];
37356
37688
  }
37357
37689
  function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
@@ -37360,16 +37692,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
37360
37692
  if (depth > maxDepth) return;
37361
37693
  let entries;
37362
37694
  try {
37363
- entries = fs23.readdirSync(dir, { withFileTypes: true });
37695
+ entries = fs24.readdirSync(dir, { withFileTypes: true });
37364
37696
  } catch {
37365
37697
  return;
37366
37698
  }
37367
37699
  for (const e of entries) {
37368
37700
  if (e.name.startsWith(".")) continue;
37369
- const full = path24.join(dir, e.name);
37701
+ const full = path26.join(dir, e.name);
37370
37702
  if (!e.isDirectory()) continue;
37371
37703
  if (e.name === sessionId) {
37372
- if (isGitDir(full)) out.push(path24.resolve(full));
37704
+ if (isGitDir(full)) out.push(path26.resolve(full));
37373
37705
  } else {
37374
37706
  walk(full, depth + 1);
37375
37707
  }
@@ -37381,14 +37713,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
37381
37713
  function tryBindingFromSessionDirectory(sessionDir) {
37382
37714
  let st;
37383
37715
  try {
37384
- st = fs23.statSync(sessionDir);
37716
+ st = fs24.statSync(sessionDir);
37385
37717
  } catch {
37386
37718
  return null;
37387
37719
  }
37388
37720
  if (!st.isDirectory()) return null;
37389
37721
  const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
37390
37722
  if (worktreePaths.length === 0) return null;
37391
- const abs = path24.resolve(sessionDir);
37723
+ const abs = path26.resolve(sessionDir);
37392
37724
  return {
37393
37725
  sessionParentPath: abs,
37394
37726
  workingTreeRelRoot: abs,
@@ -37398,20 +37730,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
37398
37730
  function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
37399
37731
  const sid = sessionId.trim();
37400
37732
  if (!sid) return null;
37401
- const hintR = path24.resolve(checkoutPath);
37733
+ const hintR = path26.resolve(checkoutPath);
37402
37734
  let best = null;
37403
- let cur = path24.dirname(hintR);
37735
+ let cur = path26.dirname(hintR);
37404
37736
  for (let i = 0; i < 40; i++) {
37405
37737
  const paths = collectWorktreeRootsNamed(cur, sid, 24);
37406
- if (paths.some((p) => path24.resolve(p) === hintR)) {
37407
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path24.resolve(paths[0]);
37738
+ if (paths.some((p) => path26.resolve(p) === hintR)) {
37739
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path26.resolve(paths[0]);
37408
37740
  best = {
37409
- sessionParentPath: path24.resolve(isolated),
37410
- workingTreeRelRoot: path24.resolve(cur),
37411
- repoCheckoutPaths: paths.map((p) => path24.resolve(p))
37741
+ sessionParentPath: path26.resolve(isolated),
37742
+ workingTreeRelRoot: path26.resolve(cur),
37743
+ repoCheckoutPaths: paths.map((p) => path26.resolve(p))
37412
37744
  };
37413
37745
  }
37414
- const next = path24.dirname(cur);
37746
+ const next = path26.dirname(cur);
37415
37747
  if (next === cur) break;
37416
37748
  cur = next;
37417
37749
  }
@@ -37419,33 +37751,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
37419
37751
  }
37420
37752
  function discoverSessionWorktreeOnDisk(options) {
37421
37753
  const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
37422
- if (!sessionId.trim() || !fs23.existsSync(worktreesRootPath)) return null;
37754
+ if (!sessionId.trim() || !fs24.existsSync(worktreesRootPath)) return null;
37423
37755
  const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
37424
37756
  const keys = [];
37425
37757
  if (preferredKey) keys.push(preferredKey);
37426
37758
  try {
37427
- for (const name of fs23.readdirSync(worktreesRootPath)) {
37759
+ for (const name of fs24.readdirSync(worktreesRootPath)) {
37428
37760
  if (name.startsWith(".")) continue;
37429
- const p = path24.join(worktreesRootPath, name);
37430
- if (!fs23.statSync(p).isDirectory()) continue;
37761
+ const p = path26.join(worktreesRootPath, name);
37762
+ if (!fs24.statSync(p).isDirectory()) continue;
37431
37763
  if (name !== preferredKey) keys.push(name);
37432
37764
  }
37433
37765
  } catch {
37434
37766
  return null;
37435
37767
  }
37436
37768
  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);
37769
+ const layoutRoot = path26.join(worktreesRootPath, key);
37770
+ if (!fs24.existsSync(layoutRoot) || !fs24.statSync(layoutRoot).isDirectory()) continue;
37771
+ const sessionDir = path26.join(layoutRoot, sessionId);
37440
37772
  const nested = tryBindingFromSessionDirectory(sessionDir);
37441
37773
  if (nested) return nested;
37442
37774
  const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
37443
37775
  if (legacyPaths.length > 0) {
37444
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path24.resolve(legacyPaths[0]);
37776
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path26.resolve(legacyPaths[0]);
37445
37777
  return {
37446
- sessionParentPath: path24.resolve(isolated),
37447
- workingTreeRelRoot: path24.resolve(layoutRoot),
37448
- repoCheckoutPaths: legacyPaths.map((p) => path24.resolve(p))
37778
+ sessionParentPath: path26.resolve(isolated),
37779
+ workingTreeRelRoot: path26.resolve(layoutRoot),
37780
+ repoCheckoutPaths: legacyPaths.map((p) => path26.resolve(p))
37449
37781
  };
37450
37782
  }
37451
37783
  }
@@ -37454,12 +37786,12 @@ function discoverSessionWorktreeOnDisk(options) {
37454
37786
  function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
37455
37787
  const sid = sessionId.trim();
37456
37788
  if (!sid) return null;
37457
- const hint = path24.resolve(sessionWorktreeRootPathOrHint);
37458
- const underHint = tryBindingFromSessionDirectory(path24.join(hint, sid));
37789
+ const hint = path26.resolve(sessionWorktreeRootPathOrHint);
37790
+ const underHint = tryBindingFromSessionDirectory(path26.join(hint, sid));
37459
37791
  if (underHint) return underHint;
37460
37792
  const direct = tryBindingFromSessionDirectory(hint);
37461
37793
  if (direct) {
37462
- if (path24.basename(hint) === sid && isGitDir(hint)) {
37794
+ if (path26.basename(hint) === sid && isGitDir(hint)) {
37463
37795
  const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
37464
37796
  if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
37465
37797
  return legacyFromCheckout;
@@ -37467,24 +37799,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
37467
37799
  }
37468
37800
  return direct;
37469
37801
  }
37470
- if (path24.basename(hint) === sid && isGitDir(hint)) {
37802
+ if (path26.basename(hint) === sid && isGitDir(hint)) {
37471
37803
  const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
37472
37804
  if (legacyFromCheckout) return legacyFromCheckout;
37473
37805
  }
37474
37806
  let st;
37475
37807
  try {
37476
- st = fs23.statSync(hint);
37808
+ st = fs24.statSync(hint);
37477
37809
  } catch {
37478
37810
  return null;
37479
37811
  }
37480
37812
  if (!st.isDirectory()) return null;
37481
37813
  const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
37482
37814
  if (legacyPaths.length === 0) return null;
37483
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path24.resolve(legacyPaths[0]);
37815
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path26.resolve(legacyPaths[0]);
37484
37816
  return {
37485
- sessionParentPath: path24.resolve(isolated),
37817
+ sessionParentPath: path26.resolve(isolated),
37486
37818
  workingTreeRelRoot: hint,
37487
- repoCheckoutPaths: legacyPaths.map((p) => path24.resolve(p))
37819
+ repoCheckoutPaths: legacyPaths.map((p) => path26.resolve(p))
37488
37820
  };
37489
37821
  }
37490
37822
 
@@ -37541,8 +37873,8 @@ function parseSessionParent(v) {
37541
37873
  }
37542
37874
 
37543
37875
  // src/worktrees/prepare-new-session-worktrees.ts
37544
- import * as fs24 from "node:fs";
37545
- import * as path25 from "node:path";
37876
+ import * as fs25 from "node:fs";
37877
+ import * as path27 from "node:path";
37546
37878
 
37547
37879
  // src/git/worktrees/worktree-add.ts
37548
37880
  async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
@@ -37552,7 +37884,7 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef
37552
37884
  }
37553
37885
 
37554
37886
  // src/worktrees/prepare-new-session-worktrees.ts
37555
- function normalizeRepoRelPath(rel) {
37887
+ function normalizeRepoRelPath2(rel) {
37556
37888
  return rel === "" ? "." : rel.replace(/\\/g, "/");
37557
37889
  }
37558
37890
  function resolveBaseRefForRepo(relNorm, baseBranches) {
@@ -37564,10 +37896,10 @@ function resolveBaseRefForRepo(relNorm, baseBranches) {
37564
37896
  }
37565
37897
  async function prepareNewSessionWorktrees(options) {
37566
37898
  const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2, worktreeBaseBranches } = options;
37567
- const bridgeResolved = path25.resolve(bridgeRoot);
37899
+ const bridgeResolved = path27.resolve(bridgeRoot);
37568
37900
  const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
37569
- const bridgeKeyDir = path25.join(worktreesRootPath, cwdKey);
37570
- const sessionDir = path25.join(bridgeKeyDir, sessionId);
37901
+ const bridgeKeyDir = path27.join(worktreesRootPath, cwdKey);
37902
+ const sessionDir = path27.join(bridgeKeyDir, sessionId);
37571
37903
  const repos = await discoverGitReposUnderRoot(bridgeResolved);
37572
37904
  if (repos.length === 0) {
37573
37905
  log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
@@ -37575,14 +37907,14 @@ async function prepareNewSessionWorktrees(options) {
37575
37907
  }
37576
37908
  const branch = `session-${sessionId}`;
37577
37909
  const worktreePaths = [];
37578
- fs24.mkdirSync(sessionDir, { recursive: true });
37910
+ fs25.mkdirSync(sessionDir, { recursive: true });
37579
37911
  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);
37912
+ let rel = path27.relative(bridgeResolved, repo.absolutePath);
37913
+ if (rel.startsWith("..") || path27.isAbsolute(rel)) continue;
37914
+ const relNorm = normalizeRepoRelPath2(rel === "" ? "." : rel);
37915
+ const wtPath = relNorm === "." ? sessionDir : path27.join(sessionDir, relNorm);
37584
37916
  if (relNorm !== ".") {
37585
- fs24.mkdirSync(path25.dirname(wtPath), { recursive: true });
37917
+ fs25.mkdirSync(path27.dirname(wtPath), { recursive: true });
37586
37918
  }
37587
37919
  const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
37588
37920
  try {
@@ -37635,9 +37967,9 @@ function resolveExistingSessionParentPath(sessionId, cache2, discover) {
37635
37967
  }
37636
37968
 
37637
37969
  // src/worktrees/manager/resolve-explicit-session-parent-path.ts
37638
- import * as path26 from "node:path";
37970
+ import * as path28 from "node:path";
37639
37971
  function resolveExplicitSessionParentPath(params) {
37640
- const resolved = path26.resolve(params.parentPathRaw);
37972
+ const resolved = path28.resolve(params.parentPathRaw);
37641
37973
  if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
37642
37974
  return resolved;
37643
37975
  }
@@ -37653,7 +37985,7 @@ function resolveExplicitSessionParentPath(params) {
37653
37985
  for (let i = 0; i < 16; i++) {
37654
37986
  const tryRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
37655
37987
  if (tryRoot) return rememberAndReturn(tryRoot);
37656
- const next = path26.dirname(cur);
37988
+ const next = path28.dirname(cur);
37657
37989
  if (next === cur) break;
37658
37990
  cur = next;
37659
37991
  }
@@ -37705,16 +38037,16 @@ async function resolveSessionParentPathForPrompt(params) {
37705
38037
  }
37706
38038
 
37707
38039
  // src/worktrees/manager/session-worktree-cache.ts
37708
- import * as path27 from "node:path";
38040
+ import * as path29 from "node:path";
37709
38041
  var SessionWorktreeCache = class {
37710
38042
  sessionRepoCheckoutPaths = /* @__PURE__ */ new Map();
37711
38043
  sessionParentPathBySession = /* @__PURE__ */ new Map();
37712
38044
  sessionWorkingTreeRelRootBySession = /* @__PURE__ */ new Map();
37713
38045
  remember(sessionId, binding) {
37714
- const paths = binding.repoCheckoutPaths.map((p) => path27.resolve(p));
38046
+ const paths = binding.repoCheckoutPaths.map((p) => path29.resolve(p));
37715
38047
  this.sessionRepoCheckoutPaths.set(sessionId, paths);
37716
- this.sessionParentPathBySession.set(sessionId, path27.resolve(binding.sessionParentPath));
37717
- this.sessionWorkingTreeRelRootBySession.set(sessionId, path27.resolve(binding.workingTreeRelRoot));
38048
+ this.sessionParentPathBySession.set(sessionId, path29.resolve(binding.sessionParentPath));
38049
+ this.sessionWorkingTreeRelRootBySession.set(sessionId, path29.resolve(binding.workingTreeRelRoot));
37718
38050
  }
37719
38051
  clearSession(sessionId) {
37720
38052
  const paths = this.sessionRepoCheckoutPaths.get(sessionId);
@@ -37744,7 +38076,7 @@ var SessionWorktreeCache = class {
37744
38076
  const parent = this.sessionParentPathBySession.get(sessionId);
37745
38077
  const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
37746
38078
  if (!parent || !relRoot) return false;
37747
- return path27.resolve(parent) !== path27.resolve(relRoot);
38079
+ return path29.resolve(parent) !== path29.resolve(relRoot);
37748
38080
  }
37749
38081
  };
37750
38082
 
@@ -37848,29 +38180,29 @@ var SessionWorktreeManager = class {
37848
38180
  };
37849
38181
 
37850
38182
  // src/worktrees/manager/default-worktrees-root-path.ts
37851
- import * as path28 from "node:path";
38183
+ import * as path30 from "node:path";
37852
38184
  import os8 from "node:os";
37853
38185
  function defaultWorktreesRootPath() {
37854
- return path28.join(os8.homedir(), ".buildautomaton", "worktrees");
38186
+ return path30.join(os8.homedir(), ".buildautomaton", "worktrees");
37855
38187
  }
37856
38188
 
37857
38189
  // src/files/watch-file-index.ts
37858
38190
  import { watch } from "node:fs";
37859
- import path33 from "node:path";
38191
+ import path35 from "node:path";
37860
38192
 
37861
38193
  // src/files/index/paths.ts
37862
- import path29 from "node:path";
38194
+ import path31 from "node:path";
37863
38195
  import crypto2 from "node:crypto";
37864
38196
  function getCwdHashForFileIndex(resolvedCwd) {
37865
- return crypto2.createHash("sha256").update(path29.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
38197
+ return crypto2.createHash("sha256").update(path31.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
37866
38198
  }
37867
38199
 
37868
38200
  // src/files/index/build-file-index.ts
37869
- import path31 from "node:path";
38201
+ import path33 from "node:path";
37870
38202
 
37871
38203
  // src/files/index/walk-workspace-tree.ts
37872
- import fs25 from "node:fs";
37873
- import path30 from "node:path";
38204
+ import fs26 from "node:fs";
38205
+ import path32 from "node:path";
37874
38206
  var DEPENDENCY_INSTALL_DIR_NAMES = /* @__PURE__ */ new Set([
37875
38207
  "node_modules",
37876
38208
  "bower_components",
@@ -37887,7 +38219,7 @@ function shouldSkipWorkspaceWalkEntry(name) {
37887
38219
  async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
37888
38220
  let names;
37889
38221
  try {
37890
- names = await fs25.promises.readdir(dir);
38222
+ names = await fs26.promises.readdir(dir);
37891
38223
  } catch {
37892
38224
  return;
37893
38225
  }
@@ -37899,14 +38231,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
37899
38231
  if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
37900
38232
  }
37901
38233
  state.n++;
37902
- const full = path30.join(dir, name);
38234
+ const full = path32.join(dir, name);
37903
38235
  let stat3;
37904
38236
  try {
37905
- stat3 = await fs25.promises.stat(full);
38237
+ stat3 = await fs26.promises.stat(full);
37906
38238
  } catch {
37907
38239
  continue;
37908
38240
  }
37909
- const relative6 = path30.relative(baseDir, full).replace(/\\/g, "/");
38241
+ const relative6 = path32.relative(baseDir, full).replace(/\\/g, "/");
37910
38242
  if (stat3.isDirectory()) {
37911
38243
  await walkWorkspaceTreeAsync(full, baseDir, onFile, state);
37912
38244
  } else if (stat3.isFile()) {
@@ -37919,7 +38251,7 @@ function createWalkYieldState() {
37919
38251
  }
37920
38252
 
37921
38253
  // src/files/index/file-index-sqlite-lock.ts
37922
- import fs26 from "node:fs";
38254
+ import fs27 from "node:fs";
37923
38255
  function isSqliteCorruptError(e) {
37924
38256
  const msg = e instanceof Error ? e.message : String(e);
37925
38257
  return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
@@ -37933,7 +38265,7 @@ function withFileIndexSqliteLock(fn) {
37933
38265
  if (!isSqliteCorruptError(e)) throw e;
37934
38266
  closeAllCliSqliteConnections();
37935
38267
  try {
37936
- fs26.unlinkSync(getCliSqlitePath());
38268
+ fs27.unlinkSync(getCliSqlitePath());
37937
38269
  } catch {
37938
38270
  }
37939
38271
  chain = Promise.resolve();
@@ -38008,7 +38340,7 @@ async function collectWorkspacePathsAsync(resolved) {
38008
38340
  }
38009
38341
  async function buildFileIndexAsync(cwd) {
38010
38342
  return withFileIndexSqliteLock(async () => {
38011
- const resolved = path31.resolve(cwd);
38343
+ const resolved = path33.resolve(cwd);
38012
38344
  await yieldToEventLoop();
38013
38345
  assertNotShutdown();
38014
38346
  const paths = await collectWorkspacePathsAsync(resolved);
@@ -38020,7 +38352,7 @@ async function buildFileIndexAsync(cwd) {
38020
38352
  }
38021
38353
 
38022
38354
  // src/files/index/ensure-file-index.ts
38023
- import path32 from "node:path";
38355
+ import path34 from "node:path";
38024
38356
 
38025
38357
  // src/files/index/search-file-index.ts
38026
38358
  function escapeLikePattern(fragment) {
@@ -38072,7 +38404,7 @@ async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
38072
38404
 
38073
38405
  // src/files/index/ensure-file-index.ts
38074
38406
  async function ensureFileIndexAsync(cwd) {
38075
- const resolved = path32.resolve(cwd);
38407
+ const resolved = path34.resolve(cwd);
38076
38408
  if (await bridgeFileIndexIsPopulated(resolved)) {
38077
38409
  return { fromCache: true, pathCount: await bridgeFileIndexPathCount(resolved) };
38078
38410
  }
@@ -38116,7 +38448,7 @@ function createFsWatcher(resolved, schedule) {
38116
38448
  }
38117
38449
  }
38118
38450
  function startFileIndexWatcher(cwd = getBridgeRoot()) {
38119
- const resolved = path33.resolve(cwd);
38451
+ const resolved = path35.resolve(cwd);
38120
38452
  void buildFileIndexAsync(resolved).catch((e) => {
38121
38453
  if (e instanceof CliSqliteInterrupted) return;
38122
38454
  console.error("[file-index] Initial index build failed:", e);
@@ -38146,7 +38478,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
38146
38478
  }
38147
38479
 
38148
38480
  // src/connection/create-bridge-connection.ts
38149
- import * as path44 from "node:path";
38481
+ import * as path46 from "node:path";
38150
38482
 
38151
38483
  // src/dev-servers/manager/dev-server-manager.ts
38152
38484
  import { rm as rm2 } from "node:fs/promises";
@@ -38190,7 +38522,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
38190
38522
  }
38191
38523
 
38192
38524
  // src/dev-servers/process/wire-dev-server-child-process.ts
38193
- import fs27 from "node:fs";
38525
+ import fs28 from "node:fs";
38194
38526
 
38195
38527
  // src/dev-servers/manager/forward-pipe.ts
38196
38528
  function forwardChildPipe(childReadable, terminal, onData) {
@@ -38226,7 +38558,7 @@ function wireDevServerChildProcess(d) {
38226
38558
  d.setPollInterval(void 0);
38227
38559
  return;
38228
38560
  }
38229
- fs27.readFile(d.mergedLogPath, (err, buf) => {
38561
+ fs28.readFile(d.mergedLogPath, (err, buf) => {
38230
38562
  if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
38231
38563
  if (buf.length <= d.mergedReadPos.value) return;
38232
38564
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
@@ -38264,7 +38596,7 @@ ${errTail}` : ""}`);
38264
38596
  d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
38265
38597
  };
38266
38598
  if (mergedPath) {
38267
- fs27.readFile(mergedPath, (err, buf) => {
38599
+ fs28.readFile(mergedPath, (err, buf) => {
38268
38600
  if (!err && buf.length > d.mergedReadPos.value) {
38269
38601
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
38270
38602
  if (chunk.length > 0) {
@@ -38366,13 +38698,13 @@ function parseDevServerDefs(servers) {
38366
38698
  }
38367
38699
 
38368
38700
  // src/dev-servers/manager/shell-spawn/utils.ts
38369
- import fs28 from "node:fs";
38701
+ import fs29 from "node:fs";
38370
38702
  function isSpawnEbadf(e) {
38371
38703
  return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
38372
38704
  }
38373
38705
  function rmDirQuiet(dir) {
38374
38706
  try {
38375
- fs28.rmSync(dir, { recursive: true, force: true });
38707
+ fs29.rmSync(dir, { recursive: true, force: true });
38376
38708
  } catch {
38377
38709
  }
38378
38710
  }
@@ -38380,7 +38712,7 @@ var cachedDevNullReadFd;
38380
38712
  function devNullReadFd() {
38381
38713
  if (cachedDevNullReadFd === void 0) {
38382
38714
  const devPath = process.platform === "win32" ? "nul" : "/dev/null";
38383
- cachedDevNullReadFd = fs28.openSync(devPath, "r");
38715
+ cachedDevNullReadFd = fs29.openSync(devPath, "r");
38384
38716
  }
38385
38717
  return cachedDevNullReadFd;
38386
38718
  }
@@ -38454,15 +38786,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
38454
38786
 
38455
38787
  // src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
38456
38788
  import { spawn as spawn7 } from "node:child_process";
38457
- import fs29 from "node:fs";
38789
+ import fs30 from "node:fs";
38458
38790
  import { tmpdir } from "node:os";
38459
- import path34 from "node:path";
38791
+ import path36 from "node:path";
38460
38792
  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");
38793
+ const tmpRoot = fs30.mkdtempSync(path36.join(tmpdir(), "ba-devsrv-log-"));
38794
+ const logPath = path36.join(tmpRoot, "combined.log");
38463
38795
  let logFd;
38464
38796
  try {
38465
- logFd = fs29.openSync(logPath, "a");
38797
+ logFd = fs30.openSync(logPath, "a");
38466
38798
  } catch {
38467
38799
  rmDirQuiet(tmpRoot);
38468
38800
  return null;
@@ -38481,7 +38813,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
38481
38813
  } else {
38482
38814
  proc = spawn7("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
38483
38815
  }
38484
- fs29.closeSync(logFd);
38816
+ fs30.closeSync(logFd);
38485
38817
  return {
38486
38818
  proc,
38487
38819
  pipedStdoutStderr: true,
@@ -38490,7 +38822,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
38490
38822
  };
38491
38823
  } catch (e) {
38492
38824
  try {
38493
- fs29.closeSync(logFd);
38825
+ fs30.closeSync(logFd);
38494
38826
  } catch {
38495
38827
  }
38496
38828
  rmDirQuiet(tmpRoot);
@@ -38501,22 +38833,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
38501
38833
 
38502
38834
  // src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
38503
38835
  import { spawn as spawn8 } from "node:child_process";
38504
- import fs30 from "node:fs";
38836
+ import fs31 from "node:fs";
38505
38837
  import { tmpdir as tmpdir2 } from "node:os";
38506
- import path35 from "node:path";
38838
+ import path37 from "node:path";
38507
38839
  function shSingleQuote(s) {
38508
38840
  return `'${s.replace(/'/g, `'\\''`)}'`;
38509
38841
  }
38510
38842
  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");
38843
+ const tmpRoot = fs31.mkdtempSync(path37.join(tmpdir2(), "ba-devsrv-sh-"));
38844
+ const logPath = path37.join(tmpRoot, "combined.log");
38845
+ const innerPath = path37.join(tmpRoot, "_cmd.sh");
38846
+ const runnerPath = path37.join(tmpRoot, "_run.sh");
38515
38847
  try {
38516
- fs30.writeFileSync(innerPath, `#!/bin/sh
38848
+ fs31.writeFileSync(innerPath, `#!/bin/sh
38517
38849
  ${command}
38518
38850
  `);
38519
- fs30.writeFileSync(
38851
+ fs31.writeFileSync(
38520
38852
  runnerPath,
38521
38853
  `#!/bin/sh
38522
38854
  cd ${shSingleQuote(cwd)}
@@ -38542,13 +38874,13 @@ cd ${shSingleQuote(cwd)}
38542
38874
  }
38543
38875
  }
38544
38876
  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");
38877
+ const tmpRoot = fs31.mkdtempSync(path37.join(tmpdir2(), "ba-devsrv-sh-"));
38878
+ const logPath = path37.join(tmpRoot, "combined.log");
38879
+ const runnerPath = path37.join(tmpRoot, "_run.bat");
38548
38880
  const q = (p) => `"${p.replace(/"/g, '""')}"`;
38549
38881
  const com = process.env.ComSpec || "cmd.exe";
38550
38882
  try {
38551
- fs30.writeFileSync(
38883
+ fs31.writeFileSync(
38552
38884
  runnerPath,
38553
38885
  `@ECHO OFF\r
38554
38886
  CD /D ${q(cwd)}\r
@@ -39485,30 +39817,30 @@ function createOnBridgeIdentified(opts) {
39485
39817
  }
39486
39818
 
39487
39819
  // src/skills/discover-local-agent-skills.ts
39488
- import fs31 from "node:fs";
39489
- import path36 from "node:path";
39820
+ import fs32 from "node:fs";
39821
+ import path38 from "node:path";
39490
39822
  var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
39491
39823
  function discoverLocalSkills(cwd) {
39492
39824
  const out = [];
39493
39825
  const seenKeys = /* @__PURE__ */ new Set();
39494
39826
  for (const rel of SKILL_DISCOVERY_ROOTS) {
39495
- const base = path36.join(cwd, rel);
39496
- if (!fs31.existsSync(base) || !fs31.statSync(base).isDirectory()) continue;
39827
+ const base = path38.join(cwd, rel);
39828
+ if (!fs32.existsSync(base) || !fs32.statSync(base).isDirectory()) continue;
39497
39829
  let entries = [];
39498
39830
  try {
39499
- entries = fs31.readdirSync(base);
39831
+ entries = fs32.readdirSync(base);
39500
39832
  } catch {
39501
39833
  continue;
39502
39834
  }
39503
39835
  for (const name of entries) {
39504
- const dir = path36.join(base, name);
39836
+ const dir = path38.join(base, name);
39505
39837
  try {
39506
- if (!fs31.statSync(dir).isDirectory()) continue;
39838
+ if (!fs32.statSync(dir).isDirectory()) continue;
39507
39839
  } catch {
39508
39840
  continue;
39509
39841
  }
39510
- const skillMd = path36.join(dir, "SKILL.md");
39511
- if (!fs31.existsSync(skillMd)) continue;
39842
+ const skillMd = path38.join(dir, "SKILL.md");
39843
+ if (!fs32.existsSync(skillMd)) continue;
39512
39844
  const key = `${rel}/${name}`;
39513
39845
  if (seenKeys.has(key)) continue;
39514
39846
  seenKeys.add(key);
@@ -39520,23 +39852,23 @@ function discoverLocalSkills(cwd) {
39520
39852
  function discoverSkillLayoutRoots(cwd) {
39521
39853
  const roots = [];
39522
39854
  for (const rel of SKILL_DISCOVERY_ROOTS) {
39523
- const base = path36.join(cwd, rel);
39524
- if (!fs31.existsSync(base) || !fs31.statSync(base).isDirectory()) continue;
39855
+ const base = path38.join(cwd, rel);
39856
+ if (!fs32.existsSync(base) || !fs32.statSync(base).isDirectory()) continue;
39525
39857
  let entries = [];
39526
39858
  try {
39527
- entries = fs31.readdirSync(base);
39859
+ entries = fs32.readdirSync(base);
39528
39860
  } catch {
39529
39861
  continue;
39530
39862
  }
39531
39863
  const skills2 = [];
39532
39864
  for (const name of entries) {
39533
- const dir = path36.join(base, name);
39865
+ const dir = path38.join(base, name);
39534
39866
  try {
39535
- if (!fs31.statSync(dir).isDirectory()) continue;
39867
+ if (!fs32.statSync(dir).isDirectory()) continue;
39536
39868
  } catch {
39537
39869
  continue;
39538
39870
  }
39539
- if (!fs31.existsSync(path36.join(dir, "SKILL.md"))) continue;
39871
+ if (!fs32.existsSync(path38.join(dir, "SKILL.md"))) continue;
39540
39872
  const relPath = `${rel}/${name}`.replace(/\\/g, "/");
39541
39873
  skills2.push({ name, relPath });
39542
39874
  }
@@ -39892,7 +40224,7 @@ function syncRunningTurnQueueKeys(turns, queueKey) {
39892
40224
  }
39893
40225
 
39894
40226
  // src/prompt-turn-queue/runner/run-local-revert-before-queued-prompt.ts
39895
- import fs32 from "node:fs";
40227
+ import fs33 from "node:fs";
39896
40228
  async function runLocalRevertBeforeQueuedPrompt(next, deps) {
39897
40229
  if (next.serverState !== "requeued_with_revert") return true;
39898
40230
  const sid = next.sessionId;
@@ -39901,7 +40233,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
39901
40233
  const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
39902
40234
  const file2 = snapshotFilePath(agentBase, tid);
39903
40235
  try {
39904
- await fs32.promises.access(file2, fs32.constants.F_OK);
40236
+ await fs33.promises.access(file2, fs33.constants.F_OK);
39905
40237
  } catch {
39906
40238
  deps.log(
39907
40239
  `[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
@@ -40189,9 +40521,9 @@ function parseChangeSummarySnapshots(raw) {
40189
40521
  for (const item of raw) {
40190
40522
  if (!item || typeof item !== "object") continue;
40191
40523
  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 };
40524
+ const path48 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
40525
+ if (!path48) continue;
40526
+ const row = { path: path48 };
40195
40527
  if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
40196
40528
  if (typeof o.oldText === "string") row.oldText = o.oldText;
40197
40529
  if (typeof o.newText === "string") row.newText = o.newText;
@@ -40401,8 +40733,8 @@ function randomSecret() {
40401
40733
  }
40402
40734
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
40403
40735
  }
40404
- async function requestPreviewApi(port, secret, method, path46, body) {
40405
- const url2 = `http://127.0.0.1:${port}${path46}`;
40736
+ async function requestPreviewApi(port, secret, method, path48, body) {
40737
+ const url2 = `http://127.0.0.1:${port}${path48}`;
40406
40738
  const headers = {
40407
40739
  [PREVIEW_SECRET_HEADER]: secret,
40408
40740
  "Content-Type": "application/json"
@@ -40414,7 +40746,7 @@ async function requestPreviewApi(port, secret, method, path46, body) {
40414
40746
  });
40415
40747
  const data = await res.json().catch(() => ({}));
40416
40748
  if (!res.ok) {
40417
- throw new Error(data?.error ?? `Preview API ${method} ${path46}: ${res.status}`);
40749
+ throw new Error(data?.error ?? `Preview API ${method} ${path48}: ${res.status}`);
40418
40750
  }
40419
40751
  return data;
40420
40752
  }
@@ -40579,14 +40911,14 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
40579
40911
  };
40580
40912
 
40581
40913
  // src/files/list-dir/index.ts
40582
- import fs34 from "node:fs";
40914
+ import fs35 from "node:fs";
40583
40915
 
40584
40916
  // src/files/ensure-under-cwd.ts
40585
- import path37 from "node:path";
40917
+ import path39 from "node:path";
40586
40918
  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) {
40919
+ const normalized = path39.normalize(relativePath).replace(/^(\.\/)+/, "");
40920
+ const resolved = path39.resolve(cwd, normalized);
40921
+ if (!resolved.startsWith(cwd + path39.sep) && resolved !== cwd) {
40590
40922
  return null;
40591
40923
  }
40592
40924
  return resolved;
@@ -40596,15 +40928,15 @@ function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
40596
40928
  var LIST_DIR_YIELD_EVERY = 256;
40597
40929
 
40598
40930
  // src/files/list-dir/map-dir-entry.ts
40599
- import path38 from "node:path";
40600
- import fs33 from "node:fs";
40931
+ import path40 from "node:path";
40932
+ import fs34 from "node:fs";
40601
40933
  async function mapDirEntry(d, relativePath, resolved) {
40602
- const entryPath = path38.join(relativePath || ".", d.name).replace(/\\/g, "/");
40603
- const fullPath = path38.join(resolved, d.name);
40934
+ const entryPath = path40.join(relativePath || ".", d.name).replace(/\\/g, "/");
40935
+ const fullPath = path40.join(resolved, d.name);
40604
40936
  let isDir = d.isDirectory();
40605
40937
  if (d.isSymbolicLink()) {
40606
40938
  try {
40607
- const targetStat = await fs33.promises.stat(fullPath);
40939
+ const targetStat = await fs34.promises.stat(fullPath);
40608
40940
  isDir = targetStat.isDirectory();
40609
40941
  } catch {
40610
40942
  isDir = false;
@@ -40634,7 +40966,7 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
40634
40966
  return { error: "Path is outside working directory" };
40635
40967
  }
40636
40968
  try {
40637
- const names = await fs34.promises.readdir(resolved, { withFileTypes: true });
40969
+ const names = await fs35.promises.readdir(resolved, { withFileTypes: true });
40638
40970
  const entries = [];
40639
40971
  for (let i = 0; i < names.length; i++) {
40640
40972
  if (i > 0 && i % LIST_DIR_YIELD_EVERY === 0) {
@@ -40654,18 +40986,18 @@ var LINE_CHUNK_SIZE = 64 * 1024;
40654
40986
  var READ_RANGE_YIELD_EVERY_BYTES = 256 * 1024;
40655
40987
 
40656
40988
  // src/files/read-file/resolve-file-path.ts
40657
- import fs35 from "node:fs";
40989
+ import fs36 from "node:fs";
40658
40990
  async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeRoot()) {
40659
40991
  const resolved = ensureUnderCwd(relativePath, sessionParentPath);
40660
40992
  if (!resolved) return { error: "Path is outside working directory" };
40661
40993
  let real;
40662
40994
  try {
40663
- real = await fs35.promises.realpath(resolved);
40995
+ real = await fs36.promises.realpath(resolved);
40664
40996
  } catch {
40665
40997
  real = resolved;
40666
40998
  }
40667
40999
  try {
40668
- const stat3 = await fs35.promises.stat(real);
41000
+ const stat3 = await fs36.promises.stat(real);
40669
41001
  if (!stat3.isFile()) return { error: "Not a file" };
40670
41002
  return real;
40671
41003
  } catch (err) {
@@ -40674,11 +41006,11 @@ async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeR
40674
41006
  }
40675
41007
 
40676
41008
  // src/files/read-file/read-file-range-async.ts
40677
- import fs36 from "node:fs";
41009
+ import fs37 from "node:fs";
40678
41010
  import { StringDecoder } from "node:string_decoder";
40679
41011
  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");
41012
+ const fileSize = (await fs37.promises.stat(filePath)).size;
41013
+ const fd = await fs37.promises.open(filePath, "r");
40682
41014
  const bufSize = 64 * 1024;
40683
41015
  const buf = Buffer.alloc(bufSize);
40684
41016
  const decoder = new StringDecoder("utf8");
@@ -40840,11 +41172,11 @@ async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, li
40840
41172
  }
40841
41173
 
40842
41174
  // src/files/read-file/read-file-buffer-full-async.ts
40843
- import fs37 from "node:fs";
41175
+ import fs38 from "node:fs";
40844
41176
  var READ_CHUNK_BYTES = 256 * 1024;
40845
41177
  async function readFileBufferFullAsync(filePath) {
40846
- const stat3 = await fs37.promises.stat(filePath);
40847
- const fd = await fs37.promises.open(filePath, "r");
41178
+ const stat3 = await fs38.promises.stat(filePath);
41179
+ const fd = await fs38.promises.open(filePath, "r");
40848
41180
  const chunks = [];
40849
41181
  let position = 0;
40850
41182
  let bytesSinceYield = 0;
@@ -40951,13 +41283,13 @@ function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
40951
41283
  }
40952
41284
 
40953
41285
  // src/files/handle-file-browser-search.ts
40954
- import path39 from "node:path";
41286
+ import path41 from "node:path";
40955
41287
  var SEARCH_LIMIT = 100;
40956
41288
  function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
40957
41289
  void (async () => {
40958
41290
  await yieldToEventLoop();
40959
41291
  const q = typeof msg.q === "string" ? msg.q : "";
40960
- const sessionParentPath = path39.resolve(
41292
+ const sessionParentPath = path41.resolve(
40961
41293
  sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
40962
41294
  );
40963
41295
  if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
@@ -41076,8 +41408,8 @@ function handleSkillLayoutRequest(msg, deps) {
41076
41408
  }
41077
41409
 
41078
41410
  // src/skills/install-remote-skills.ts
41079
- import fs38 from "node:fs";
41080
- import path40 from "node:path";
41411
+ import fs39 from "node:fs";
41412
+ import path42 from "node:path";
41081
41413
  function installRemoteSkills(cwd, targetDir, items) {
41082
41414
  const installed2 = [];
41083
41415
  if (!Array.isArray(items)) {
@@ -41088,15 +41420,15 @@ function installRemoteSkills(cwd, targetDir, items) {
41088
41420
  if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
41089
41421
  continue;
41090
41422
  }
41091
- const skillDir = path40.join(cwd, targetDir, item.skillName);
41423
+ const skillDir = path42.join(cwd, targetDir, item.skillName);
41092
41424
  for (const f of item.files) {
41093
41425
  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 });
41426
+ const dest = path42.join(skillDir, f.path);
41427
+ fs39.mkdirSync(path42.dirname(dest), { recursive: true });
41096
41428
  if (f.text !== void 0) {
41097
- fs38.writeFileSync(dest, f.text, "utf8");
41429
+ fs39.writeFileSync(dest, f.text, "utf8");
41098
41430
  } else if (f.base64) {
41099
- fs38.writeFileSync(dest, Buffer.from(f.base64, "base64"));
41431
+ fs39.writeFileSync(dest, Buffer.from(f.base64, "base64"));
41100
41432
  }
41101
41433
  }
41102
41434
  installed2.push({
@@ -41254,7 +41586,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
41254
41586
  };
41255
41587
 
41256
41588
  // src/routing/handlers/revert-turn-snapshot.ts
41257
- import * as fs39 from "node:fs";
41589
+ import * as fs40 from "node:fs";
41258
41590
  var handleRevertTurnSnapshotMessage = (msg, deps) => {
41259
41591
  const id = typeof msg.id === "string" ? msg.id : "";
41260
41592
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
@@ -41267,7 +41599,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
41267
41599
  const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
41268
41600
  const file2 = snapshotFilePath(agentBase, turnId);
41269
41601
  try {
41270
- await fs39.promises.access(file2, fs39.constants.F_OK);
41602
+ await fs40.promises.access(file2, fs40.constants.F_OK);
41271
41603
  } catch {
41272
41604
  sendWsMessage(s, {
41273
41605
  type: "revert_turn_snapshot_result",
@@ -41309,7 +41641,7 @@ var handleDevServersConfig = (msg, deps) => {
41309
41641
  };
41310
41642
 
41311
41643
  // src/git/bridge-git-context.ts
41312
- import * as path41 from "node:path";
41644
+ import * as path43 from "node:path";
41313
41645
 
41314
41646
  // src/git/branches/get-current-branch.ts
41315
41647
  async function getCurrentBranch(repoPath) {
@@ -41359,12 +41691,12 @@ async function listRepoBranchRefs(repoPath) {
41359
41691
  // src/git/bridge-git-context.ts
41360
41692
  function folderNameForRelPath(relPath, bridgeRoot) {
41361
41693
  if (relPath === "." || relPath === "") {
41362
- return path41.basename(path41.resolve(bridgeRoot)) || "repo";
41694
+ return path43.basename(path43.resolve(bridgeRoot)) || "repo";
41363
41695
  }
41364
- return path41.basename(relPath) || relPath;
41696
+ return path43.basename(relPath) || relPath;
41365
41697
  }
41366
41698
  async function discoverGitReposForBridgeContext(bridgeRoot) {
41367
- const root = path41.resolve(bridgeRoot);
41699
+ const root = path43.resolve(bridgeRoot);
41368
41700
  if (await isGitRepoDirectory(root)) {
41369
41701
  const remoteUrl = await getRemoteOriginUrl(root);
41370
41702
  return [{ absolutePath: root, remoteUrl }];
@@ -41372,17 +41704,17 @@ async function discoverGitReposForBridgeContext(bridgeRoot) {
41372
41704
  const [deep, shallow] = await Promise.all([discoverGitReposUnderRoot(root), discoverGitRepos(root)]);
41373
41705
  const byPath = /* @__PURE__ */ new Map();
41374
41706
  for (const repo of [...deep, ...shallow]) {
41375
- byPath.set(path41.resolve(repo.absolutePath), repo);
41707
+ byPath.set(path43.resolve(repo.absolutePath), repo);
41376
41708
  }
41377
41709
  return [...byPath.values()];
41378
41710
  }
41379
41711
  async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
41380
- const bridgeResolved = path41.resolve(bridgeRoot);
41712
+ const bridgeResolved = path43.resolve(bridgeRoot);
41381
41713
  const repos = await discoverGitReposForBridgeContext(bridgeResolved);
41382
41714
  const rows = [];
41383
41715
  for (const repo of repos) {
41384
- let rel = path41.relative(bridgeResolved, repo.absolutePath);
41385
- if (rel.startsWith("..") || path41.isAbsolute(rel)) continue;
41716
+ let rel = path43.relative(bridgeResolved, repo.absolutePath);
41717
+ if (rel.startsWith("..") || path43.isAbsolute(rel)) continue;
41386
41718
  const relPath = rel === "" ? "." : rel.replace(/\\/g, "/");
41387
41719
  const currentBranch = await getCurrentBranch(repo.absolutePath);
41388
41720
  const remoteUrl = repo.remoteUrl.trim() || null;
@@ -41397,11 +41729,11 @@ async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
41397
41729
  return rows;
41398
41730
  }
41399
41731
  async function listRepoBranchesForBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
41400
- const bridgeResolved = path41.resolve(bridgeRoot);
41732
+ const bridgeResolved = path43.resolve(bridgeRoot);
41401
41733
  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) {
41734
+ const repoPath = rel === "" ? bridgeResolved : path43.join(bridgeResolved, rel);
41735
+ const resolved = path43.resolve(repoPath);
41736
+ if (!resolved.startsWith(bridgeResolved + path43.sep) && resolved !== bridgeResolved) {
41405
41737
  return [];
41406
41738
  }
41407
41739
  return listRepoBranchRefs(resolved);
@@ -41906,10 +42238,10 @@ function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
41906
42238
  }
41907
42239
 
41908
42240
  // src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
41909
- import * as path43 from "node:path";
42241
+ import * as path45 from "node:path";
41910
42242
 
41911
42243
  // src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
41912
- import * as path42 from "node:path";
42244
+ import * as path44 from "node:path";
41913
42245
  async function probeOneAgentTypeForCapabilities(params) {
41914
42246
  const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true, shouldContinue } = params;
41915
42247
  const canContinue = () => shouldContinue?.() !== false;
@@ -41947,7 +42279,7 @@ async function probeOneAgentTypeForCapabilities(params) {
41947
42279
  if (!canContinue()) return false;
41948
42280
  handle = await resolved.createClient({
41949
42281
  command: resolved.command,
41950
- cwd: path42.resolve(cwd),
42282
+ cwd: path44.resolve(cwd),
41951
42283
  backendAgentType: agentType,
41952
42284
  sessionMode: "agent",
41953
42285
  persistedAcpSessionId: null,
@@ -42025,7 +42357,7 @@ async function warmupAgentCapabilitiesOnConnect(params) {
42025
42357
  const { workspaceId, log: log2, getWs } = params;
42026
42358
  const isCurrent = beginAgentCapabilityWarmupRun();
42027
42359
  if (!isCurrent()) return;
42028
- const cwd = path43.resolve(getBridgeRoot());
42360
+ const cwd = path45.resolve(getBridgeRoot());
42029
42361
  async function sendBatchFromCache() {
42030
42362
  if (!isCurrent()) return;
42031
42363
  const socket = getWs();
@@ -42430,8 +42762,8 @@ async function createBridgeConnection(options) {
42430
42762
  getCloudAccessToken: () => tokens.accessToken
42431
42763
  };
42432
42764
  const identifyReportedPaths = {
42433
- bridgeRootPath: path44.resolve(getBridgeRoot()),
42434
- worktreesRootPath: path44.resolve(worktreesRootPath)
42765
+ bridgeRootPath: path46.resolve(getBridgeRoot()),
42766
+ worktreesRootPath: path46.resolve(worktreesRootPath)
42435
42767
  };
42436
42768
  const { connect } = createMainBridgeWebSocketLifecycle({
42437
42769
  state,
@@ -42686,9 +43018,9 @@ async function runCliAction(program2, opts) {
42686
43018
  const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
42687
43019
  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
43020
  if (bridgeRootOpt) {
42689
- const resolvedBridgeRoot = path45.resolve(process.cwd(), bridgeRootOpt);
43021
+ const resolvedBridgeRoot = path47.resolve(process.cwd(), bridgeRootOpt);
42690
43022
  try {
42691
- const st = fs40.statSync(resolvedBridgeRoot);
43023
+ const st = fs41.statSync(resolvedBridgeRoot);
42692
43024
  if (!st.isDirectory()) {
42693
43025
  console.error(`Bridge root is not a directory: ${resolvedBridgeRoot}`);
42694
43026
  process.exit(1);
@@ -42708,7 +43040,7 @@ async function runCliAction(program2, opts) {
42708
43040
  );
42709
43041
  let worktreesRootPath;
42710
43042
  if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
42711
- worktreesRootPath = path45.resolve(opts.worktreesRoot.trim());
43043
+ worktreesRootPath = path47.resolve(opts.worktreesRoot.trim());
42712
43044
  }
42713
43045
  const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
42714
43046
  if (e2eCertificates) {