@buildautomaton/cli 0.1.24 → 0.1.26

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 path36 = __require("node:path");
977
- var fs35 = __require("node:fs");
976
+ var path37 = __require("node:path");
977
+ var fs36 = __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 = path36.resolve(baseDir, baseName);
1910
- if (fs35.existsSync(localBin)) return localBin;
1911
- if (sourceExt.includes(path36.extname(baseName))) return void 0;
1909
+ const localBin = path37.resolve(baseDir, baseName);
1910
+ if (fs36.existsSync(localBin)) return localBin;
1911
+ if (sourceExt.includes(path37.extname(baseName))) return void 0;
1912
1912
  const foundExt = sourceExt.find(
1913
- (ext) => fs35.existsSync(`${localBin}${ext}`)
1913
+ (ext) => fs36.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 = fs35.realpathSync(this._scriptPath);
1925
+ resolvedScriptPath = fs36.realpathSync(this._scriptPath);
1926
1926
  } catch (err) {
1927
1927
  resolvedScriptPath = this._scriptPath;
1928
1928
  }
1929
- executableDir = path36.resolve(
1930
- path36.dirname(resolvedScriptPath),
1929
+ executableDir = path37.resolve(
1930
+ path37.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 = path36.basename(
1937
+ const legacyName = path37.basename(
1938
1938
  this._scriptPath,
1939
- path36.extname(this._scriptPath)
1939
+ path37.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(path36.extname(executableFile));
1950
+ launchWithNode = sourceExt.includes(path37.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 = path36.basename(filename, path36.extname(filename));
2790
+ this._name = path37.basename(filename, path37.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(path37) {
2805
- if (path37 === void 0) return this._executableDir;
2806
- this._executableDir = path37;
2804
+ executableDir(path38) {
2805
+ if (path38 === void 0) return this._executableDir;
2806
+ this._executableDir = path38;
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: path36, errorMaps, issueData } = params;
7065
- const fullPath = [...path36, ...issueData.path || []];
7064
+ const { data, path: path37, errorMaps, issueData } = params;
7065
+ const fullPath = [...path37, ...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, path36, key) {
7373
+ constructor(parent, value, path37, key) {
7374
7374
  this._cachedPath = [];
7375
7375
  this.parent = parent;
7376
7376
  this.data = value;
7377
- this._path = path36;
7377
+ this._path = path37;
7378
7378
  this._key = key;
7379
7379
  }
7380
7380
  get path() {
@@ -11235,7 +11235,7 @@ var require_has_flag = __commonJS({
11235
11235
  var require_supports_color = __commonJS({
11236
11236
  "../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports, module) {
11237
11237
  "use strict";
11238
- var os7 = __require("os");
11238
+ var os8 = __require("os");
11239
11239
  var tty = __require("tty");
11240
11240
  var hasFlag = require_has_flag();
11241
11241
  var { env } = process;
@@ -11283,7 +11283,7 @@ var require_supports_color = __commonJS({
11283
11283
  return min;
11284
11284
  }
11285
11285
  if (process.platform === "win32") {
11286
- const osRelease = os7.release().split(".");
11286
+ const osRelease = os8.release().split(".");
11287
11287
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
11288
11288
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
11289
11289
  }
@@ -11529,10 +11529,10 @@ var require_src2 = __commonJS({
11529
11529
  var fs_1 = __require("fs");
11530
11530
  var debug_1 = __importDefault(require_src());
11531
11531
  var log2 = debug_1.default("@kwsites/file-exists");
11532
- function check2(path36, isFile, isDirectory) {
11533
- log2(`checking %s`, path36);
11532
+ function check2(path37, isFile, isDirectory) {
11533
+ log2(`checking %s`, path37);
11534
11534
  try {
11535
- const stat3 = fs_1.statSync(path36);
11535
+ const stat3 = fs_1.statSync(path37);
11536
11536
  if (stat3.isFile() && isFile) {
11537
11537
  log2(`[OK] path represents a file`);
11538
11538
  return true;
@@ -11552,8 +11552,8 @@ var require_src2 = __commonJS({
11552
11552
  throw e;
11553
11553
  }
11554
11554
  }
11555
- function exists2(path36, type = exports.READABLE) {
11556
- return check2(path36, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
11555
+ function exists2(path37, type = exports.READABLE) {
11556
+ return check2(path37, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
11557
11557
  }
11558
11558
  exports.exists = exists2;
11559
11559
  exports.FILE = 1;
@@ -11850,10 +11850,10 @@ function assignProp(target, prop, value) {
11850
11850
  configurable: true
11851
11851
  });
11852
11852
  }
11853
- function getElementAtPath(obj, path36) {
11854
- if (!path36)
11853
+ function getElementAtPath(obj, path37) {
11854
+ if (!path37)
11855
11855
  return obj;
11856
- return path36.reduce((acc, key) => acc?.[key], obj);
11856
+ return path37.reduce((acc, key) => acc?.[key], obj);
11857
11857
  }
11858
11858
  function promiseAllObject(promisesObj) {
11859
11859
  const keys = Object.keys(promisesObj);
@@ -12102,11 +12102,11 @@ function aborted(x, startIndex = 0) {
12102
12102
  }
12103
12103
  return false;
12104
12104
  }
12105
- function prefixIssues(path36, issues) {
12105
+ function prefixIssues(path37, issues) {
12106
12106
  return issues.map((iss) => {
12107
12107
  var _a2;
12108
12108
  (_a2 = iss).path ?? (_a2.path = []);
12109
- iss.path.unshift(path36);
12109
+ iss.path.unshift(path37);
12110
12110
  return iss;
12111
12111
  });
12112
12112
  }
@@ -12295,7 +12295,7 @@ function treeifyError(error40, _mapper) {
12295
12295
  return issue2.message;
12296
12296
  };
12297
12297
  const result = { errors: [] };
12298
- const processError = (error41, path36 = []) => {
12298
+ const processError = (error41, path37 = []) => {
12299
12299
  var _a2, _b;
12300
12300
  for (const issue2 of error41.issues) {
12301
12301
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -12305,7 +12305,7 @@ function treeifyError(error40, _mapper) {
12305
12305
  } else if (issue2.code === "invalid_element") {
12306
12306
  processError({ issues: issue2.issues }, issue2.path);
12307
12307
  } else {
12308
- const fullpath = [...path36, ...issue2.path];
12308
+ const fullpath = [...path37, ...issue2.path];
12309
12309
  if (fullpath.length === 0) {
12310
12310
  result.errors.push(mapper(issue2));
12311
12311
  continue;
@@ -12335,9 +12335,9 @@ function treeifyError(error40, _mapper) {
12335
12335
  processError(error40);
12336
12336
  return result;
12337
12337
  }
12338
- function toDotPath(path36) {
12338
+ function toDotPath(path37) {
12339
12339
  const segs = [];
12340
- for (const seg of path36) {
12340
+ for (const seg of path37) {
12341
12341
  if (typeof seg === "number")
12342
12342
  segs.push(`[${seg}]`);
12343
12343
  else if (typeof seg === "symbol")
@@ -25064,15 +25064,15 @@ var {
25064
25064
  } = import_index.default;
25065
25065
 
25066
25066
  // src/cli-version.ts
25067
- var CLI_VERSION = "0.1.24".length > 0 ? "0.1.24" : "0.0.0-dev";
25067
+ var CLI_VERSION = "0.1.26".length > 0 ? "0.1.26" : "0.0.0-dev";
25068
25068
 
25069
25069
  // src/cli/defaults.ts
25070
25070
  var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
25071
25071
  var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
25072
25072
 
25073
25073
  // src/cli/run-cli-action.ts
25074
- import * as fs34 from "node:fs";
25075
- import * as path35 from "node:path";
25074
+ import * as fs35 from "node:fs";
25075
+ import * as path36 from "node:path";
25076
25076
 
25077
25077
  // src/cli-log-level.ts
25078
25078
  var verbosity = "info";
@@ -25465,6 +25465,11 @@ function logImmediate(line) {
25465
25465
  process.stdout.write(`${timestampPrefix()} ${line}
25466
25466
  `);
25467
25467
  }
25468
+ function logDebug(line) {
25469
+ const v = getCliLogVerbosity();
25470
+ if (v !== "debug" && v !== "trace") return;
25471
+ console.log(`${timestampPrefix()} [debug] ${line}`);
25472
+ }
25468
25473
  function logTrace(line) {
25469
25474
  if (getCliLogVerbosity() !== "trace") return;
25470
25475
  console.log(`${timestampPrefix()} [trace] ${line}`);
@@ -27058,9 +27063,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
27058
27063
  const rawPath = typeof o.path === "string" ? o.path.trim() : "";
27059
27064
  const summary = typeof o.summary === "string" ? o.summary.trim() : "";
27060
27065
  if (!rawPath || !summary) continue;
27061
- const path36 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
27062
- if (!path36) continue;
27063
- rows.push({ path: path36, summary: clampSummaryToAtMostTwoLines(summary) });
27066
+ const path37 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
27067
+ if (!path37) continue;
27068
+ rows.push({ path: path37, summary: clampSummaryToAtMostTwoLines(summary) });
27064
27069
  }
27065
27070
  return rows;
27066
27071
  }
@@ -27199,8 +27204,77 @@ function isClaudeCodePermissionMode(value) {
27199
27204
  return MODE_SET.has(value);
27200
27205
  }
27201
27206
 
27207
+ // ../types/src/cli-permission-mode.ts
27208
+ var CLI_PERMISSION_MODE_DEFAULT = "default";
27209
+ var CLI_PERMISSION_MODE_DANGEROUS = "dangerous";
27210
+ function normalizeCliPermissionModeInput(raw) {
27211
+ if (typeof raw !== "string") return CLI_PERMISSION_MODE_DEFAULT;
27212
+ const t = raw.trim();
27213
+ if (t === CLI_PERMISSION_MODE_DANGEROUS) return CLI_PERMISSION_MODE_DANGEROUS;
27214
+ if (t === "standard") return CLI_PERMISSION_MODE_DEFAULT;
27215
+ return CLI_PERMISSION_MODE_DEFAULT;
27216
+ }
27217
+
27218
+ // ../types/src/acp-permission-auto-approve.ts
27219
+ function isRejectKind(kind) {
27220
+ return kind === "reject_once" || kind === "reject_always";
27221
+ }
27222
+ function normalizeOptions(raw) {
27223
+ if (!Array.isArray(raw)) return [];
27224
+ const out = [];
27225
+ for (const item of raw) {
27226
+ if (item == null || typeof item !== "object" || Array.isArray(item)) continue;
27227
+ const o = item;
27228
+ const rawId = o.optionId ?? o.id;
27229
+ const optionId = typeof rawId === "string" && rawId.trim() !== "" ? rawId.trim() : typeof rawId === "number" && Number.isFinite(rawId) ? String(rawId) : "";
27230
+ if (!optionId) continue;
27231
+ const kind = typeof o.kind === "string" ? o.kind : void 0;
27232
+ out.push({ optionId, ...kind ? { kind } : {} });
27233
+ }
27234
+ return out;
27235
+ }
27236
+ function pickAllowOption(options) {
27237
+ const nonReject = options.filter((o) => !isRejectKind(o.kind));
27238
+ if (nonReject.length === 0) return null;
27239
+ const allowOnce = nonReject.find((o) => o.kind === "allow_once");
27240
+ if (allowOnce) return allowOnce;
27241
+ const notAlways = nonReject.filter((o) => o.kind !== "allow_always");
27242
+ if (notAlways.length > 0) return notAlways[0] ?? null;
27243
+ return nonReject.find((o) => o.kind === "allow_always") ?? nonReject[0] ?? null;
27244
+ }
27245
+ function firstNonEmptyOptionsArray(...candidates) {
27246
+ for (const c of candidates) {
27247
+ if (Array.isArray(c) && c.length > 0) return c;
27248
+ }
27249
+ const fallback = candidates[0];
27250
+ return Array.isArray(fallback) ? fallback : [];
27251
+ }
27252
+ function extractAcpPermissionRequestOptionArray(params) {
27253
+ const toolCall = params.toolCall;
27254
+ const fromToolCall = toolCall != null && typeof toolCall === "object" && !Array.isArray(toolCall) ? toolCall : null;
27255
+ return firstNonEmptyOptionsArray(
27256
+ params.options,
27257
+ params.permissionOptions,
27258
+ fromToolCall?.options,
27259
+ fromToolCall?.permissionOptions
27260
+ );
27261
+ }
27262
+ function buildCliAutoApprovedPermissionRpcResult(requestParams) {
27263
+ const opt = pickAllowOption(normalizeOptions(extractAcpPermissionRequestOptionArray(requestParams)));
27264
+ if (!opt) return null;
27265
+ const kind = opt.kind?.trim();
27266
+ return {
27267
+ outcome: {
27268
+ outcome: "selected",
27269
+ optionId: opt.optionId,
27270
+ ...kind ? { _meta: { permissionOptionKind: kind } } : {}
27271
+ }
27272
+ };
27273
+ }
27274
+
27202
27275
  // ../types/src/agent-config.ts
27203
27276
  var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
27277
+ var AGENT_CONFIG_CLI_PERMISSION_MODE_KEY = "cli_permission_mode";
27204
27278
  function getClaudePermissionModeFromAgentConfig(config2) {
27205
27279
  if (!config2) return null;
27206
27280
  const raw = config2[AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY];
@@ -27208,6 +27282,10 @@ function getClaudePermissionModeFromAgentConfig(config2) {
27208
27282
  const t = raw.trim();
27209
27283
  return isClaudeCodePermissionMode(t) ? t : null;
27210
27284
  }
27285
+ function getCliPermissionModeFromAgentConfig(config2) {
27286
+ if (!config2) return CLI_PERMISSION_MODE_DEFAULT;
27287
+ return normalizeCliPermissionModeInput(config2[AGENT_CONFIG_CLI_PERMISSION_MODE_KEY]);
27288
+ }
27211
27289
 
27212
27290
  // src/git/session-git-queue.ts
27213
27291
  import { execFile as execFile7 } from "node:child_process";
@@ -27262,8 +27340,8 @@ function pathspec(...paths) {
27262
27340
  cache.set(key, paths);
27263
27341
  return key;
27264
27342
  }
27265
- function isPathSpec(path36) {
27266
- return path36 instanceof String && cache.has(path36);
27343
+ function isPathSpec(path37) {
27344
+ return path37 instanceof String && cache.has(path37);
27267
27345
  }
27268
27346
  function toPaths(pathSpec) {
27269
27347
  return cache.get(pathSpec) || [];
@@ -27352,8 +27430,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
27352
27430
  function forEachLineWithContent(input, callback) {
27353
27431
  return toLinesWithContent(input, true).map((line) => callback(line));
27354
27432
  }
27355
- function folderExists(path36) {
27356
- return (0, import_file_exists.exists)(path36, import_file_exists.FOLDER);
27433
+ function folderExists(path37) {
27434
+ return (0, import_file_exists.exists)(path37, import_file_exists.FOLDER);
27357
27435
  }
27358
27436
  function append(target, item) {
27359
27437
  if (Array.isArray(target)) {
@@ -27757,8 +27835,8 @@ function checkIsRepoRootTask() {
27757
27835
  commands,
27758
27836
  format: "utf-8",
27759
27837
  onError,
27760
- parser(path36) {
27761
- return /^\.(git)?$/.test(path36.trim());
27838
+ parser(path37) {
27839
+ return /^\.(git)?$/.test(path37.trim());
27762
27840
  }
27763
27841
  };
27764
27842
  }
@@ -28192,11 +28270,11 @@ function parseGrep(grep) {
28192
28270
  const paths = /* @__PURE__ */ new Set();
28193
28271
  const results = {};
28194
28272
  forEachLineWithContent(grep, (input) => {
28195
- const [path36, line, preview] = input.split(NULL);
28196
- paths.add(path36);
28197
- (results[path36] = results[path36] || []).push({
28273
+ const [path37, line, preview] = input.split(NULL);
28274
+ paths.add(path37);
28275
+ (results[path37] = results[path37] || []).push({
28198
28276
  line: asNumber(line),
28199
- path: path36,
28277
+ path: path37,
28200
28278
  preview
28201
28279
  });
28202
28280
  });
@@ -28961,14 +29039,14 @@ var init_hash_object = __esm2({
28961
29039
  init_task();
28962
29040
  }
28963
29041
  });
28964
- function parseInit(bare, path36, text) {
29042
+ function parseInit(bare, path37, text) {
28965
29043
  const response = String(text).trim();
28966
29044
  let result;
28967
29045
  if (result = initResponseRegex.exec(response)) {
28968
- return new InitSummary(bare, path36, false, result[1]);
29046
+ return new InitSummary(bare, path37, false, result[1]);
28969
29047
  }
28970
29048
  if (result = reInitResponseRegex.exec(response)) {
28971
- return new InitSummary(bare, path36, true, result[1]);
29049
+ return new InitSummary(bare, path37, true, result[1]);
28972
29050
  }
28973
29051
  let gitDir = "";
28974
29052
  const tokens = response.split(" ");
@@ -28979,7 +29057,7 @@ function parseInit(bare, path36, text) {
28979
29057
  break;
28980
29058
  }
28981
29059
  }
28982
- return new InitSummary(bare, path36, /^re/i.test(response), gitDir);
29060
+ return new InitSummary(bare, path37, /^re/i.test(response), gitDir);
28983
29061
  }
28984
29062
  var InitSummary;
28985
29063
  var initResponseRegex;
@@ -28988,9 +29066,9 @@ var init_InitSummary = __esm2({
28988
29066
  "src/lib/responses/InitSummary.ts"() {
28989
29067
  "use strict";
28990
29068
  InitSummary = class {
28991
- constructor(bare, path36, existing, gitDir) {
29069
+ constructor(bare, path37, existing, gitDir) {
28992
29070
  this.bare = bare;
28993
- this.path = path36;
29071
+ this.path = path37;
28994
29072
  this.existing = existing;
28995
29073
  this.gitDir = gitDir;
28996
29074
  }
@@ -29002,7 +29080,7 @@ var init_InitSummary = __esm2({
29002
29080
  function hasBareCommand(command) {
29003
29081
  return command.includes(bareCommand);
29004
29082
  }
29005
- function initTask(bare = false, path36, customArgs) {
29083
+ function initTask(bare = false, path37, customArgs) {
29006
29084
  const commands = ["init", ...customArgs];
29007
29085
  if (bare && !hasBareCommand(commands)) {
29008
29086
  commands.splice(1, 0, bareCommand);
@@ -29011,7 +29089,7 @@ function initTask(bare = false, path36, customArgs) {
29011
29089
  commands,
29012
29090
  format: "utf-8",
29013
29091
  parser(text) {
29014
- return parseInit(commands.includes("--bare"), path36, text);
29092
+ return parseInit(commands.includes("--bare"), path37, text);
29015
29093
  }
29016
29094
  };
29017
29095
  }
@@ -29827,12 +29905,12 @@ var init_FileStatusSummary = __esm2({
29827
29905
  "use strict";
29828
29906
  fromPathRegex = /^(.+)\0(.+)$/;
29829
29907
  FileStatusSummary = class {
29830
- constructor(path36, index, working_dir) {
29831
- this.path = path36;
29908
+ constructor(path37, index, working_dir) {
29909
+ this.path = path37;
29832
29910
  this.index = index;
29833
29911
  this.working_dir = working_dir;
29834
29912
  if (index === "R" || working_dir === "R") {
29835
- const detail = fromPathRegex.exec(path36) || [null, path36, path36];
29913
+ const detail = fromPathRegex.exec(path37) || [null, path37, path37];
29836
29914
  this.from = detail[2] || "";
29837
29915
  this.path = detail[1] || "";
29838
29916
  }
@@ -29863,14 +29941,14 @@ function splitLine(result, lineStr) {
29863
29941
  default:
29864
29942
  return;
29865
29943
  }
29866
- function data(index, workingDir, path36) {
29944
+ function data(index, workingDir, path37) {
29867
29945
  const raw = `${index}${workingDir}`;
29868
29946
  const handler = parsers6.get(raw);
29869
29947
  if (handler) {
29870
- handler(result, path36);
29948
+ handler(result, path37);
29871
29949
  }
29872
29950
  if (raw !== "##" && raw !== "!!") {
29873
- result.files.push(new FileStatusSummary(path36, index, workingDir));
29951
+ result.files.push(new FileStatusSummary(path37, index, workingDir));
29874
29952
  }
29875
29953
  }
29876
29954
  }
@@ -30179,9 +30257,9 @@ var init_simple_git_api = __esm2({
30179
30257
  next
30180
30258
  );
30181
30259
  }
30182
- hashObject(path36, write) {
30260
+ hashObject(path37, write) {
30183
30261
  return this._runTask(
30184
- hashObjectTask(path36, write === true),
30262
+ hashObjectTask(path37, write === true),
30185
30263
  trailingFunctionArgument(arguments)
30186
30264
  );
30187
30265
  }
@@ -30534,8 +30612,8 @@ var init_branch = __esm2({
30534
30612
  }
30535
30613
  });
30536
30614
  function toPath(input) {
30537
- const path36 = input.trim().replace(/^["']|["']$/g, "");
30538
- return path36 && normalize(path36);
30615
+ const path37 = input.trim().replace(/^["']|["']$/g, "");
30616
+ return path37 && normalize(path37);
30539
30617
  }
30540
30618
  var parseCheckIgnore;
30541
30619
  var init_CheckIgnore = __esm2({
@@ -30849,8 +30927,8 @@ __export2(sub_module_exports, {
30849
30927
  subModuleTask: () => subModuleTask,
30850
30928
  updateSubModuleTask: () => updateSubModuleTask
30851
30929
  });
30852
- function addSubModuleTask(repo, path36) {
30853
- return subModuleTask(["add", repo, path36]);
30930
+ function addSubModuleTask(repo, path37) {
30931
+ return subModuleTask(["add", repo, path37]);
30854
30932
  }
30855
30933
  function initSubModuleTask(customArgs) {
30856
30934
  return subModuleTask(["init", ...customArgs]);
@@ -31183,8 +31261,8 @@ var require_git = __commonJS2({
31183
31261
  }
31184
31262
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
31185
31263
  };
31186
- Git2.prototype.submoduleAdd = function(repo, path36, then) {
31187
- return this._runTask(addSubModuleTask2(repo, path36), trailingFunctionArgument2(arguments));
31264
+ Git2.prototype.submoduleAdd = function(repo, path37, then) {
31265
+ return this._runTask(addSubModuleTask2(repo, path37), trailingFunctionArgument2(arguments));
31188
31266
  };
31189
31267
  Git2.prototype.submoduleUpdate = function(args, then) {
31190
31268
  return this._runTask(
@@ -32071,9 +32149,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
32071
32149
  // src/agents/acp/put-summarize-change-summaries.ts
32072
32150
  async function putEncryptedChangeSummaryRows(params) {
32073
32151
  const base = params.apiBaseUrl.replace(/\/+$/, "");
32074
- const entries = params.rows.map(({ path: path36, summary }) => {
32152
+ const entries = params.rows.map(({ path: path37, summary }) => {
32075
32153
  const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
32076
- return { path: path36, summary: JSON.stringify(enc) };
32154
+ return { path: path37, summary: JSON.stringify(enc) };
32077
32155
  });
32078
32156
  const res = await fetch(
32079
32157
  `${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
@@ -32255,8 +32333,8 @@ async function sendPromptToAgent(options) {
32255
32333
  }
32256
32334
 
32257
32335
  // src/agents/acp/ensure-acp-client.ts
32258
- import * as fs10 from "node:fs";
32259
- import * as path12 from "node:path";
32336
+ import * as fs11 from "node:fs";
32337
+ import * as path13 from "node:path";
32260
32338
 
32261
32339
  // src/error-message.ts
32262
32340
  function errorMessage(err) {
@@ -32292,76 +32370,10 @@ async function isCommandOnPath(command, timeoutMs = 4e3) {
32292
32370
  }
32293
32371
  }
32294
32372
 
32295
- // src/agents/acp/clients/sdk-stdio-acp-client.ts
32373
+ // src/agents/acp/clients/sdk/sdk-stdio-acp-client.ts
32296
32374
  import { spawn as spawn2 } from "node:child_process";
32297
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
32298
- import { dirname as dirname2 } from "node:path";
32299
32375
  import { Readable, Writable } from "node:stream";
32300
32376
 
32301
- // src/files/diff/unified-diff.ts
32302
- function computeLineDiff(oldText, newText) {
32303
- const oldLines = oldText.split("\n");
32304
- const newLines = newText.split("\n");
32305
- const m = oldLines.length;
32306
- const n = newLines.length;
32307
- const dp = Array(m + 1);
32308
- for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
32309
- for (let i2 = 1; i2 <= m; i2++) {
32310
- for (let j2 = 1; j2 <= n; j2++) {
32311
- if (oldLines[i2 - 1] === newLines[j2 - 1]) {
32312
- dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
32313
- } else {
32314
- dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
32315
- }
32316
- }
32317
- }
32318
- const result = [];
32319
- let i = m;
32320
- let j = n;
32321
- while (i > 0 || j > 0) {
32322
- if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
32323
- result.unshift({ type: "context", line: oldLines[i - 1] });
32324
- i--;
32325
- j--;
32326
- } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
32327
- result.unshift({ type: "add", line: newLines[j - 1] });
32328
- j--;
32329
- } else {
32330
- result.unshift({ type: "remove", line: oldLines[i - 1] });
32331
- i--;
32332
- }
32333
- }
32334
- return result;
32335
- }
32336
- function editSnippetToUnifiedDiff(filePath, oldText, newText) {
32337
- const lines = computeLineDiff(oldText, newText);
32338
- const out = [`--- ${filePath}`, `+++ ${filePath}`];
32339
- for (const d of lines) {
32340
- if (d.type === "add") out.push(`+${d.line}`);
32341
- else if (d.type === "remove") out.push(`-${d.line}`);
32342
- else out.push(` ${d.line}`);
32343
- }
32344
- return out.join("\n");
32345
- }
32346
-
32347
- // src/agents/acp/safe-fs-path.ts
32348
- import * as path9 from "node:path";
32349
- function resolveSafePathUnderCwd(cwd, filePath) {
32350
- const trimmed2 = filePath.trim();
32351
- if (!trimmed2) return null;
32352
- const normalizedCwd = path9.resolve(cwd);
32353
- const resolved = path9.isAbsolute(trimmed2) ? path9.normalize(trimmed2) : path9.resolve(normalizedCwd, trimmed2);
32354
- const rel = path9.relative(normalizedCwd, resolved);
32355
- if (rel.startsWith("..") || path9.isAbsolute(rel)) return null;
32356
- return resolved;
32357
- }
32358
- function toDisplayPathRelativeToCwd(cwd, absolutePath) {
32359
- const normalizedCwd = path9.resolve(cwd);
32360
- const rel = path9.relative(normalizedCwd, path9.resolve(absolutePath));
32361
- if (!rel || rel === "") return path9.basename(absolutePath);
32362
- return rel.split(path9.sep).join("/");
32363
- }
32364
-
32365
32377
  // src/agents/acp/clients/agent-stderr-capture.ts
32366
32378
  var STDERR_CAPTURE_MAX = 48e3;
32367
32379
  function createStderrCapture(child) {
@@ -32426,7 +32438,7 @@ function createKiroSdkExtNotificationHandler(options) {
32426
32438
  };
32427
32439
  }
32428
32440
 
32429
- // src/agents/acp/clients/sdk-stdio-ext-notifications.ts
32441
+ // src/agents/acp/clients/sdk/sdk-stdio-ext-notifications.ts
32430
32442
  var noopExtNotification = async () => {
32431
32443
  };
32432
32444
  function createSdkStdioExtNotificationHandler(options) {
@@ -32485,23 +32497,380 @@ function enrichAcpPermissionRpcResultFromRequestParams(result, params) {
32485
32497
  };
32486
32498
  }
32487
32499
 
32488
- // src/agents/acp/clients/sdk-stdio-acp-client.ts
32489
- function formatSpawnError(err, command) {
32490
- if (err.code === "ENOENT") {
32491
- return `Command "${command}" not found. Install the agent (e.g. Cursor CLI) or add it to PATH.`;
32500
+ // src/agents/acp/clients/shared/acp-fs-read-write.ts
32501
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
32502
+ import { dirname as dirname2 } from "node:path";
32503
+
32504
+ // src/files/diff/unified-diff.ts
32505
+ function computeLineDiff(oldText, newText) {
32506
+ const oldLines = oldText.split("\n");
32507
+ const newLines = newText.split("\n");
32508
+ const m = oldLines.length;
32509
+ const n = newLines.length;
32510
+ const dp = Array(m + 1);
32511
+ for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
32512
+ for (let i2 = 1; i2 <= m; i2++) {
32513
+ for (let j2 = 1; j2 <= n; j2++) {
32514
+ if (oldLines[i2 - 1] === newLines[j2 - 1]) {
32515
+ dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
32516
+ } else {
32517
+ dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
32518
+ }
32519
+ }
32492
32520
  }
32493
- return err.message || String(err);
32521
+ const result = [];
32522
+ let i = m;
32523
+ let j = n;
32524
+ while (i > 0 || j > 0) {
32525
+ if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
32526
+ result.unshift({ type: "context", line: oldLines[i - 1] });
32527
+ i--;
32528
+ j--;
32529
+ } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
32530
+ result.unshift({ type: "add", line: newLines[j - 1] });
32531
+ j--;
32532
+ } else {
32533
+ result.unshift({ type: "remove", line: oldLines[i - 1] });
32534
+ i--;
32535
+ }
32536
+ }
32537
+ return result;
32538
+ }
32539
+ function editSnippetToUnifiedDiff(filePath, oldText, newText) {
32540
+ const lines = computeLineDiff(oldText, newText);
32541
+ const out = [`--- ${filePath}`, `+++ ${filePath}`];
32542
+ for (const d of lines) {
32543
+ if (d.type === "add") out.push(`+${d.line}`);
32544
+ else if (d.type === "remove") out.push(`-${d.line}`);
32545
+ else out.push(` ${d.line}`);
32546
+ }
32547
+ return out.join("\n");
32548
+ }
32549
+
32550
+ // src/agents/acp/safe-fs-path.ts
32551
+ import * as path9 from "node:path";
32552
+ function resolveSafePathUnderCwd(cwd, filePath) {
32553
+ const trimmed2 = filePath.trim();
32554
+ if (!trimmed2) return null;
32555
+ const normalizedCwd = path9.resolve(cwd);
32556
+ const resolved = path9.isAbsolute(trimmed2) ? path9.normalize(trimmed2) : path9.resolve(normalizedCwd, trimmed2);
32557
+ const rel = path9.relative(normalizedCwd, resolved);
32558
+ if (rel.startsWith("..") || path9.isAbsolute(rel)) return null;
32559
+ return resolved;
32494
32560
  }
32495
- function sliceFileContentRange(content, line, limit) {
32561
+ function toDisplayPathRelativeToCwd(cwd, absolutePath) {
32562
+ const normalizedCwd = path9.resolve(cwd);
32563
+ const rel = path9.relative(normalizedCwd, path9.resolve(absolutePath));
32564
+ if (!rel || rel === "") return path9.basename(absolutePath);
32565
+ return rel.split(path9.sep).join("/");
32566
+ }
32567
+
32568
+ // src/agents/acp/clients/shared/acp-fs-read-write.ts
32569
+ function sliceFileContentForAcp(content, line, limit) {
32496
32570
  if (line == null && limit == null) return content;
32497
32571
  const lines = content.split("\n");
32498
32572
  const start = line != null && line > 0 ? line - 1 : 0;
32499
32573
  const end = limit != null && limit > 0 ? start + limit : lines.length;
32500
32574
  return lines.slice(start, end).join("\n");
32501
32575
  }
32502
- function bridgePayloadFromSdkSessionNotification(params) {
32576
+ function acpReadTextFileInProcess(ctx, filePath, line, limit) {
32577
+ const resolvedPath = resolveSafePathUnderCwd(ctx.cwd, filePath);
32578
+ if (!resolvedPath) throw new Error("Invalid or disallowed path");
32579
+ try {
32580
+ let content = readFileSync2(resolvedPath, "utf8");
32581
+ content = sliceFileContentForAcp(content, line, limit);
32582
+ return { content };
32583
+ } catch (e) {
32584
+ if (e.code === "ENOENT") return { content: "" };
32585
+ throw e;
32586
+ }
32587
+ }
32588
+ function acpWriteTextFileInProcess(ctx, filePath, newText) {
32589
+ const resolvedPath = resolveSafePathUnderCwd(ctx.cwd, filePath);
32590
+ if (!resolvedPath) throw new Error("Invalid or disallowed path");
32591
+ let oldText = "";
32592
+ try {
32593
+ oldText = readFileSync2(resolvedPath, "utf8");
32594
+ } catch (e) {
32595
+ if (e.code !== "ENOENT") throw e;
32596
+ }
32597
+ mkdirSync2(dirname2(resolvedPath), { recursive: true });
32598
+ writeFileSync2(resolvedPath, newText, "utf8");
32599
+ const displayPath = toDisplayPathRelativeToCwd(ctx.cwd, resolvedPath);
32600
+ const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
32601
+ ctx.onFileChange?.({ path: displayPath, oldText, newText, patchContent });
32602
+ return {};
32603
+ }
32604
+
32605
+ // src/agents/acp/claude-acp-permission-from-session.ts
32606
+ function flattenSelectOptions(options) {
32607
+ if (options == null || options.length === 0) return [];
32608
+ const first2 = options[0];
32609
+ if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
32610
+ return options.flatMap(
32611
+ (g) => Array.isArray(g.options) ? g.options : []
32612
+ );
32613
+ }
32614
+ return options;
32615
+ }
32616
+ function pickModeConfigOption(configOptions) {
32617
+ if (configOptions == null || configOptions.length === 0) return null;
32618
+ const byCategory = configOptions.find((o) => o.category === "mode");
32619
+ if (byCategory) return byCategory;
32620
+ return configOptions.find((o) => o.id === "mode") ?? null;
32621
+ }
32622
+ async function applyClaudePermissionFromAcpSession(params) {
32623
+ const { sessionId, agentConfig, configOptions, modes, setSessionConfigOption, setSessionMode, logDebug: logDebug2 } = params;
32624
+ const desiredMode = getClaudePermissionModeFromAgentConfig(agentConfig);
32625
+ if (desiredMode == null) return;
32626
+ const modeOpt = pickModeConfigOption(configOptions ?? null);
32627
+ if (modeOpt != null) {
32628
+ const flat = flattenSelectOptions(modeOpt.options);
32629
+ const allowed = flat.some((o) => o.value === desiredMode);
32630
+ if (allowed && modeOpt.currentValue !== desiredMode) {
32631
+ try {
32632
+ logDebug2(
32633
+ `[Agent] Claude Code: sending ACP session/set_config_option (permission mode) configId=${JSON.stringify(modeOpt.id)} value=${JSON.stringify(desiredMode)} was=${JSON.stringify(modeOpt.currentValue)} sessionId=${sessionId.slice(0, 8)}\u2026`
32634
+ );
32635
+ await setSessionConfigOption({ sessionId, configId: modeOpt.id, value: desiredMode });
32636
+ } catch (e) {
32637
+ logDebug2(
32638
+ `[Agent] Claude Code: session/set_config_option failed: ${e instanceof Error ? e.message : String(e)}`
32639
+ );
32640
+ }
32641
+ }
32642
+ return;
32643
+ }
32644
+ if (modes?.availableModes?.length) {
32645
+ const allowed = modes.availableModes.some((m) => m.id === desiredMode);
32646
+ if (allowed && desiredMode !== modes.currentModeId) {
32647
+ try {
32648
+ logDebug2(
32649
+ `[Agent] Claude Code: sending ACP session/set_mode (permission mode) modeId=${JSON.stringify(desiredMode)} was=${JSON.stringify(modes.currentModeId ?? null)} sessionId=${sessionId.slice(0, 8)}\u2026`
32650
+ );
32651
+ await setSessionMode({ sessionId, modeId: desiredMode });
32652
+ } catch (e) {
32653
+ logDebug2(`[Agent] Claude Code: session/set_mode failed: ${e instanceof Error ? e.message : String(e)}`);
32654
+ }
32655
+ }
32656
+ }
32657
+ }
32658
+
32659
+ // src/agents/acp/clients/shared/config-options-for-permission.ts
32660
+ function configOptionsForPermission(getActive, established) {
32661
+ const mem = getActive?.();
32662
+ if (Array.isArray(mem) && mem.length > 0) return mem;
32663
+ return established ?? void 0;
32664
+ }
32665
+
32666
+ // src/agents/acp/clients/shared/establish-acp-session.ts
32667
+ function establishedFromResult(raw, sessionId) {
32668
+ const r = raw && typeof raw === "object" ? raw : {};
32669
+ return {
32670
+ sessionId,
32671
+ configOptions: Array.isArray(r.configOptions) ? r.configOptions : null,
32672
+ modes: r.modes ?? null
32673
+ };
32674
+ }
32675
+ function sessionIdFromNewSessionResult(raw) {
32676
+ const r = raw && typeof raw === "object" ? raw : {};
32677
+ return typeof r.sessionId === "string" ? r.sessionId : "";
32678
+ }
32679
+ async function establishAcpSessionWithTransport(transport, ctx, canResume, canLoad) {
32680
+ const { cwd, mcpServers, persistedAcpSessionId, agentLabel, suppressLoadReplay } = ctx;
32681
+ const prev = typeof persistedAcpSessionId === "string" && persistedAcpSessionId.trim() !== "" ? persistedAcpSessionId.trim() : "";
32682
+ if (prev) {
32683
+ if (canResume) {
32684
+ try {
32685
+ logDebug(`[Agent] ${agentLabel} ACP session/resume for stored session ${prev.slice(0, 8)}\u2026`);
32686
+ const result2 = await transport.resumeSession({ sessionId: prev, cwd, mcpServers });
32687
+ return establishedFromResult(result2, prev);
32688
+ } catch (e) {
32689
+ logDebug(`[Agent] ${agentLabel} ACP session/resume failed: ${e instanceof Error ? e.message : String(e)}`);
32690
+ }
32691
+ }
32692
+ if (canLoad) {
32693
+ suppressLoadReplay.value = true;
32694
+ try {
32695
+ logDebug(`[Agent] ${agentLabel} ACP session/load for stored session ${prev.slice(0, 8)}\u2026`);
32696
+ const result2 = await transport.loadSession({ sessionId: prev, cwd, mcpServers });
32697
+ return establishedFromResult(result2, prev);
32698
+ } catch (e) {
32699
+ logDebug(`[Agent] ${agentLabel} ACP session/load failed: ${e instanceof Error ? e.message : String(e)}`);
32700
+ } finally {
32701
+ suppressLoadReplay.value = false;
32702
+ }
32703
+ }
32704
+ }
32705
+ const result = await transport.newSession({ cwd, mcpServers });
32706
+ const sid = sessionIdFromNewSessionResult(result);
32707
+ if (!sid) throw new Error(`${agentLabel} ACP session/new did not return sessionId`);
32708
+ return establishedFromResult(result, sid);
32709
+ }
32710
+
32711
+ // src/agents/acp/clients/shared/parse-acp-init-capabilities.ts
32712
+ function parseAcpInitAgentCapabilities(initResult) {
32713
+ const agentCapabilities = initResult?.agentCapabilities;
32714
+ const canLoad = agentCapabilities?.loadSession === true;
32715
+ const sessionCaps = agentCapabilities?.sessionCapabilities;
32716
+ const canResume = Boolean(sessionCaps?.resume);
32717
+ return { canResume, canLoad };
32718
+ }
32719
+
32720
+ // src/agents/acp/clients/shared/bootstrap-acp-wire-session.ts
32721
+ async function bootstrapAcpWireSession(transport, ctx, initializeRequest) {
32722
+ const initResult = await transport.initialize(initializeRequest);
32723
+ const { canResume, canLoad } = parseAcpInitAgentCapabilities(initResult);
32724
+ await transport.afterInitialize?.();
32725
+ const established = await establishAcpSessionWithTransport(transport, ctx, canResume, canLoad);
32726
+ const sessionId = established.sessionId;
32727
+ ctx.onAcpSessionEstablished?.({
32728
+ acpSessionId: sessionId,
32729
+ configOptions: established.configOptions,
32730
+ modes: established.modes
32731
+ });
32732
+ if (ctx.backendAgentType === "claude-code") {
32733
+ const cfg = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
32734
+ const configOptionsTyped = established.configOptions;
32735
+ const modesTyped = established.modes;
32736
+ await applyClaudePermissionFromAcpSession({
32737
+ sessionId,
32738
+ agentConfig: cfg,
32739
+ configOptions: configOptionsForPermission(ctx.getActiveConfigOptions, configOptionsTyped),
32740
+ modes: modesTyped,
32741
+ setSessionConfigOption: transport.setSessionConfigOption ? (p) => transport.setSessionConfigOption(p) : async () => {
32742
+ },
32743
+ setSessionMode: transport.setSessionMode ? (p) => transport.setSessionMode(p) : async () => {
32744
+ },
32745
+ logDebug: ctx.logDebug
32746
+ });
32747
+ }
32748
+ return established;
32749
+ }
32750
+
32751
+ // src/agents/acp/clients/shared/dispatch-session-update.ts
32752
+ function dispatchAcpSessionUpdate(opts) {
32753
+ const { flatPayload, onAcpConfigOptionsUpdated, onSessionUpdate, suppressLoadReplay } = opts;
32754
+ const su = flatPayload.sessionUpdate ?? flatPayload.session_update;
32755
+ if (su === "config_option_update") {
32756
+ const co = flatPayload.configOptions;
32757
+ if (Array.isArray(co)) onAcpConfigOptionsUpdated?.(co);
32758
+ return;
32759
+ }
32760
+ if (suppressLoadReplay()) return;
32761
+ onSessionUpdate?.(flatPayload);
32762
+ }
32763
+
32764
+ // src/agents/acp/clients/shared/flatten-sdk-session-notification.ts
32765
+ function flattenSdkSessionNotificationParams(params) {
32503
32766
  return { sessionId: params.sessionId, ...params.update };
32504
32767
  }
32768
+
32769
+ // src/agents/acp/clients/shared/normalize-acp-prompt-result.ts
32770
+ function normalizeAcpPromptTurnSuccess(opts) {
32771
+ const { stopReason, output, stderrCaptureText, backendAgentType } = opts;
32772
+ const mergedOutput = output || void 0;
32773
+ const stop = (stopReason ?? "").toLowerCase();
32774
+ const cancelled = stop === "cancelled";
32775
+ const refusal = stop === "refusal";
32776
+ const stderrEvaluated = Boolean(stderrCaptureText && backendAgentType);
32777
+ const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(backendAgentType, stderrCaptureText) : false;
32778
+ if (cancelled) {
32779
+ return {
32780
+ success: false,
32781
+ stopReason,
32782
+ output: mergedOutput,
32783
+ error: mergeErrorWithStderr("Stopped by user", stderrCaptureText)
32784
+ };
32785
+ }
32786
+ if (refusal) {
32787
+ return {
32788
+ success: false,
32789
+ stopReason,
32790
+ output: mergedOutput,
32791
+ error: mergeErrorWithStderr("The agent refused the request.", stderrCaptureText)
32792
+ };
32793
+ }
32794
+ if (stderrSuggestsAuth) {
32795
+ return {
32796
+ success: false,
32797
+ stopReason,
32798
+ output: mergedOutput,
32799
+ error: stderrCaptureText
32800
+ };
32801
+ }
32802
+ return {
32803
+ success: true,
32804
+ stopReason,
32805
+ output: mergedOutput
32806
+ };
32807
+ }
32808
+ function normalizeAcpPromptTurnFailure(err, stderrCaptureText) {
32809
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrCaptureText);
32810
+ return { success: false, error: merged };
32811
+ }
32812
+
32813
+ // src/agents/acp/clients/shared/send-acp-prompt-via-transport.ts
32814
+ async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText) {
32815
+ try {
32816
+ const response = await transport.prompt({
32817
+ sessionId,
32818
+ prompt: [{ type: "text", text: promptText }]
32819
+ });
32820
+ await new Promise((r2) => setImmediate(r2));
32821
+ const r = response;
32822
+ return normalizeAcpPromptTurnSuccess({
32823
+ stopReason: r?.stopReason,
32824
+ output: r?.output,
32825
+ stderrCaptureText: ctx.getStderrText(),
32826
+ backendAgentType: ctx.backendAgentType
32827
+ });
32828
+ } catch (err) {
32829
+ await new Promise((r) => setImmediate(r));
32830
+ return normalizeAcpPromptTurnFailure(err, ctx.getStderrText());
32831
+ }
32832
+ }
32833
+
32834
+ // src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
32835
+ function awaitSdkStdioPermissionRequestHandshake(params) {
32836
+ const { requestId, paramsRecord, pending, onRequest } = params;
32837
+ return new Promise((resolve18) => {
32838
+ pending.set(requestId, { resolve: resolve18, params: paramsRecord });
32839
+ try {
32840
+ onRequest?.({
32841
+ requestId,
32842
+ method: "session/request_permission",
32843
+ params: paramsRecord
32844
+ });
32845
+ } catch {
32846
+ }
32847
+ });
32848
+ }
32849
+
32850
+ // src/agents/acp/clients/sdk/sdk-acp-session-transport.ts
32851
+ function createSdkAcpSessionTransport(connection) {
32852
+ const c = connection;
32853
+ return {
32854
+ initialize: (request) => c.initialize(request),
32855
+ resumeSession: (p) => c.unstable_resumeSession(p),
32856
+ loadSession: (p) => c.loadSession(p),
32857
+ newSession: (p) => c.newSession(p),
32858
+ prompt: (p) => c.prompt(p),
32859
+ cancelSession: async (sessionId) => {
32860
+ await c.cancel({ sessionId });
32861
+ },
32862
+ setSessionConfigOption: c.setSessionConfigOption ? (p) => c.setSessionConfigOption(p) : void 0,
32863
+ setSessionMode: c.setSessionMode ? (p) => c.setSessionMode(p) : void 0
32864
+ };
32865
+ }
32866
+
32867
+ // src/agents/acp/clients/sdk/sdk-stdio-acp-client.ts
32868
+ function formatSpawnError(err, command) {
32869
+ if (err.code === "ENOENT") {
32870
+ return `Command "${command}" not found. Install the agent (e.g. Cursor CLI) or add it to PATH.`;
32871
+ }
32872
+ return err.message || String(err);
32873
+ }
32505
32874
  async function createSdkStdioAcpClient(options) {
32506
32875
  const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
32507
32876
  const {
@@ -32513,7 +32882,11 @@ async function createSdkStdioAcpClient(options) {
32513
32882
  onFileChange,
32514
32883
  killSubprocessAfterCancelMs,
32515
32884
  onAgentSubprocessExit,
32516
- agentConfig
32885
+ agentConfig,
32886
+ persistedAcpSessionId,
32887
+ onAcpSessionEstablished,
32888
+ onAcpConfigOptionsUpdated,
32889
+ getActiveConfigOptions
32517
32890
  } = options;
32518
32891
  const isWindows = process.platform === "win32";
32519
32892
  const child = spawn2(command[0], command.slice(1), {
@@ -32562,54 +32935,49 @@ async function createSdkStdioAcpClient(options) {
32562
32935
  backendAgentType,
32563
32936
  onSessionUpdate
32564
32937
  });
32938
+ const suppressLoadReplayRef = { value: false };
32939
+ const sessionCtx = {
32940
+ cwd,
32941
+ onFileChange,
32942
+ mcpServers: [],
32943
+ persistedAcpSessionId,
32944
+ agentLabel: "ACP",
32945
+ suppressLoadReplay: suppressLoadReplayRef,
32946
+ backendAgentType: backendAgentType ?? null,
32947
+ agentConfig,
32948
+ getActiveConfigOptions,
32949
+ onAcpSessionEstablished,
32950
+ onAcpConfigOptionsUpdated,
32951
+ logDebug,
32952
+ getStderrText: () => stderrCapture.getText()
32953
+ };
32565
32954
  let permissionSeq = 0;
32566
32955
  const pendingPermissionReplies = /* @__PURE__ */ new Map();
32567
32956
  const client = (_agent) => ({
32568
32957
  async requestPermission(params) {
32569
32958
  const requestId = `perm-${++permissionSeq}`;
32570
32959
  const paramsRecord = params != null && typeof params === "object" ? params : {};
32571
- try {
32572
- onRequest?.({
32573
- requestId,
32574
- method: "session/request_permission",
32575
- params: paramsRecord
32576
- });
32577
- } catch {
32578
- }
32579
- return await new Promise((resolve19) => {
32580
- pendingPermissionReplies.set(requestId, { resolve: resolve19, params: paramsRecord });
32960
+ return await awaitSdkStdioPermissionRequestHandshake({
32961
+ requestId,
32962
+ paramsRecord,
32963
+ pending: pendingPermissionReplies,
32964
+ onRequest
32581
32965
  });
32582
32966
  },
32583
32967
  async readTextFile(params) {
32584
- const resolvedPath = resolveSafePathUnderCwd(cwd, params.path);
32585
- if (!resolvedPath) throw new Error("Invalid or disallowed path");
32586
- try {
32587
- let content = readFileSync2(resolvedPath, "utf8");
32588
- content = sliceFileContentRange(content, params.line, params.limit);
32589
- return { content };
32590
- } catch (e) {
32591
- if (e.code === "ENOENT") return { content: "" };
32592
- throw e;
32593
- }
32968
+ return acpReadTextFileInProcess(sessionCtx, params.path, params.line, params.limit);
32594
32969
  },
32595
32970
  async writeTextFile(params) {
32596
- const resolvedPath = resolveSafePathUnderCwd(cwd, params.path);
32597
- if (!resolvedPath) throw new Error("Invalid or disallowed path");
32598
- let oldText = "";
32599
- try {
32600
- oldText = readFileSync2(resolvedPath, "utf8");
32601
- } catch (e) {
32602
- if (e.code !== "ENOENT") throw e;
32603
- }
32604
- mkdirSync2(dirname2(resolvedPath), { recursive: true });
32605
- writeFileSync2(resolvedPath, params.content, "utf8");
32606
- const displayPath = toDisplayPathRelativeToCwd(cwd, resolvedPath);
32607
- const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, params.content);
32608
- onFileChange?.({ path: displayPath, oldText, newText: params.content, patchContent });
32609
- return {};
32971
+ return acpWriteTextFileInProcess(sessionCtx, params.path, params.content);
32610
32972
  },
32611
32973
  async sessionUpdate(params) {
32612
- onSessionUpdate?.(bridgePayloadFromSdkSessionNotification(params));
32974
+ const bridged = flattenSdkSessionNotificationParams(params);
32975
+ dispatchAcpSessionUpdate({
32976
+ flatPayload: bridged,
32977
+ onAcpConfigOptionsUpdated: sessionCtx.onAcpConfigOptionsUpdated,
32978
+ onSessionUpdate,
32979
+ suppressLoadReplay: () => sessionCtx.suppressLoadReplay.value
32980
+ });
32613
32981
  },
32614
32982
  async extNotification(method, params) {
32615
32983
  await extNotification(method, params);
@@ -32619,84 +32987,19 @@ async function createSdkStdioAcpClient(options) {
32619
32987
  connection.signal.addEventListener("abort", () => {
32620
32988
  child.kill();
32621
32989
  });
32622
- await connection.initialize({
32990
+ const transport = createSdkAcpSessionTransport(connection);
32991
+ const established = await bootstrapAcpWireSession(transport, sessionCtx, {
32623
32992
  protocolVersion: PROTOCOL_VERSION2,
32624
32993
  clientCapabilities: {
32625
32994
  fs: { readTextFile: true, writeTextFile: true }
32626
32995
  },
32627
32996
  clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
32628
32997
  });
32629
- const newSessionRes = await connection.newSession({ cwd, mcpServers: [] });
32630
- const sessionId = newSessionRes.sessionId;
32631
- if (backendAgentType === "claude-code") {
32632
- const cfg = agentConfig != null && typeof agentConfig === "object" && !Array.isArray(agentConfig) ? agentConfig : null;
32633
- const desiredMode = getClaudePermissionModeFromAgentConfig(cfg);
32634
- const modes = newSessionRes.modes;
32635
- if (desiredMode != null && modes?.availableModes?.length) {
32636
- const allowed = modes.availableModes.some((m) => m.id === desiredMode);
32637
- if (allowed && desiredMode !== modes.currentModeId) {
32638
- try {
32639
- await connection.setSessionMode({ sessionId, modeId: desiredMode });
32640
- } catch {
32641
- }
32642
- }
32643
- }
32644
- }
32998
+ const sessionId = established.sessionId;
32645
32999
  settleResolve({
32646
33000
  sessionId,
32647
33001
  async sendPrompt(prompt, _options) {
32648
- try {
32649
- const response = await connection.prompt({
32650
- sessionId,
32651
- prompt: [{ type: "text", text: prompt }]
32652
- });
32653
- await new Promise((r2) => setImmediate(r2));
32654
- const r = response;
32655
- const stopReason = (r?.stopReason ?? "").toLowerCase();
32656
- const cancelled = stopReason === "cancelled";
32657
- const refusal = stopReason === "refusal";
32658
- const stderrAfter = stderrCapture.getText();
32659
- const agentType = backendAgentType ?? null;
32660
- const stderrEvaluated = Boolean(stderrAfter && agentType);
32661
- const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
32662
- if (cancelled) {
32663
- return {
32664
- success: false,
32665
- stopReason: r?.stopReason,
32666
- output: r?.output,
32667
- error: mergeErrorWithStderr("Stopped by user", stderrAfter)
32668
- };
32669
- }
32670
- if (refusal) {
32671
- return {
32672
- success: false,
32673
- stopReason: r?.stopReason,
32674
- output: r?.output,
32675
- error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
32676
- };
32677
- }
32678
- if (stderrSuggestsAuth) {
32679
- return {
32680
- success: false,
32681
- stopReason: r?.stopReason,
32682
- output: r?.output,
32683
- error: stderrAfter
32684
- };
32685
- }
32686
- return {
32687
- success: true,
32688
- stopReason: r?.stopReason,
32689
- output: r?.output
32690
- };
32691
- } catch (err) {
32692
- await new Promise((r) => setImmediate(r));
32693
- const stderrAfter = stderrCapture.getText();
32694
- const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
32695
- return {
32696
- success: false,
32697
- error: merged
32698
- };
32699
- }
33002
+ return sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt);
32700
33003
  },
32701
33004
  async cancel() {
32702
33005
  for (const [id, entry] of [...pendingPermissionReplies.entries()]) {
@@ -32704,7 +33007,7 @@ async function createSdkStdioAcpClient(options) {
32704
33007
  entry.resolve({ outcome: { outcome: "cancelled" } });
32705
33008
  }
32706
33009
  try {
32707
- await connection.cancel({ sessionId });
33010
+ await transport.cancelSession(sessionId);
32708
33011
  } catch {
32709
33012
  }
32710
33013
  if (killSubprocessAfterCancelMs != null && killSubprocessAfterCancelMs >= 0) {
@@ -32795,7 +33098,7 @@ async function createCodexAcpClient(options) {
32795
33098
  return createSdkStdioAcpClient({ ...options, command });
32796
33099
  }
32797
33100
 
32798
- // src/agents/acp/clients/cursor-acp-client.ts
33101
+ // src/agents/acp/clients/cursor/cursor-acp-client.ts
32799
33102
  var cursor_acp_client_exports = {};
32800
33103
  __export(cursor_acp_client_exports, {
32801
33104
  BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE3,
@@ -32803,8 +33106,6 @@ __export(cursor_acp_client_exports, {
32803
33106
  createCursorAcpClient: () => createCursorAcpClient,
32804
33107
  detectLocalAgentPresence: () => detectLocalAgentPresence3
32805
33108
  });
32806
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
32807
- import { dirname as dirname3 } from "node:path";
32808
33109
  import { spawn as spawn3 } from "node:child_process";
32809
33110
  import * as readline from "node:readline";
32810
33111
 
@@ -32821,7 +33122,23 @@ function formatSessionUpdateKindForLog(kind) {
32821
33122
  return kind.split("_").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
32822
33123
  }
32823
33124
 
32824
- // src/agents/acp/clients/cursor-acp-client.ts
33125
+ // src/agents/acp/clients/cursor/cursor-json-rpc-acp-transport.ts
33126
+ function createCursorJsonRpcAcpTransport(deps) {
33127
+ const { send, cancelSessionNotification } = deps;
33128
+ return {
33129
+ initialize: (request) => send("initialize", request),
33130
+ afterInitialize: async () => {
33131
+ await send("authenticate", { methodId: "cursor_login" });
33132
+ },
33133
+ resumeSession: (p) => send("session/resume", p),
33134
+ loadSession: (p) => send("session/load", p),
33135
+ newSession: (p) => send("session/new", p),
33136
+ prompt: (p) => send("session/prompt", p),
33137
+ cancelSession: (sessionId) => cancelSessionNotification(sessionId)
33138
+ };
33139
+ }
33140
+
33141
+ // src/agents/acp/clients/cursor/cursor-acp-client.ts
32825
33142
  var FS_READ_METHODS = /* @__PURE__ */ new Set(["fs/read_text_file", "fs/readTextFile"]);
32826
33143
  var FS_WRITE_METHODS = /* @__PURE__ */ new Set(["fs/write_text_file", "fs/writeTextFile"]);
32827
33144
  function formatSpawnError2(err, command) {
@@ -32838,13 +33155,6 @@ function safeJsonParse(value) {
32838
33155
  return null;
32839
33156
  }
32840
33157
  }
32841
- function sliceLinesByRange(content, line, limit) {
32842
- if (line == null && limit == null) return content;
32843
- const lines = content.split("\n");
32844
- const start = line != null && line > 0 ? line - 1 : 0;
32845
- const end = limit != null && limit > 0 ? start + limit : lines.length;
32846
- return lines.slice(start, end).join("\n");
32847
- }
32848
33158
  function buildCursorAcpSpawnCommand(base, sessionMode) {
32849
33159
  if (!sessionMode) return [...base];
32850
33160
  const m = sessionMode.trim();
@@ -32858,7 +33168,11 @@ async function createCursorAcpClient(options) {
32858
33168
  backendAgentType,
32859
33169
  onSessionUpdate,
32860
33170
  onRequest,
32861
- onFileChange
33171
+ onFileChange,
33172
+ persistedAcpSessionId,
33173
+ onAcpSessionEstablished,
33174
+ onAcpConfigOptionsUpdated,
33175
+ onAgentSubprocessExit
32862
33176
  } = options;
32863
33177
  const dbgFs = process.env.BUILDAUTOMATON_DEBUG_ACP_FS === "1";
32864
33178
  const isWindows = process.platform === "win32";
@@ -32870,6 +33184,25 @@ async function createCursorAcpClient(options) {
32870
33184
  });
32871
33185
  const stderrCapture = createStderrCapture(child);
32872
33186
  child.stderr?.on("data", (chunk) => stderrCapture.append(chunk));
33187
+ child.once("close", (code, signal) => {
33188
+ onAgentSubprocessExit?.({ code, signal });
33189
+ });
33190
+ const suppressLoadReplayRef = { value: false };
33191
+ const sessionCtx = {
33192
+ cwd,
33193
+ onFileChange,
33194
+ mcpServers: [],
33195
+ persistedAcpSessionId,
33196
+ agentLabel: "Cursor",
33197
+ suppressLoadReplay: suppressLoadReplayRef,
33198
+ backendAgentType: backendAgentType ?? null,
33199
+ agentConfig: options.agentConfig,
33200
+ getActiveConfigOptions: options.getActiveConfigOptions,
33201
+ onAcpSessionEstablished,
33202
+ onAcpConfigOptionsUpdated,
33203
+ logDebug,
33204
+ getStderrText: () => stderrCapture.getText()
33205
+ };
32873
33206
  return new Promise((resolve18, reject) => {
32874
33207
  child.on("error", (err) => {
32875
33208
  child.kill();
@@ -32878,6 +33211,16 @@ async function createCursorAcpClient(options) {
32878
33211
  let nextId = 1;
32879
33212
  const pending = /* @__PURE__ */ new Map();
32880
33213
  const pendingRequests = /* @__PURE__ */ new Map();
33214
+ function cancelSessionNotification(sessionId) {
33215
+ const line = JSON.stringify({
33216
+ jsonrpc: "2.0",
33217
+ method: "session/cancel",
33218
+ params: { sessionId }
33219
+ }) + "\n";
33220
+ return new Promise((res, rej) => {
33221
+ child.stdin.write(line, (err) => err ? rej(err) : res());
33222
+ });
33223
+ }
32881
33224
  function send(method, params) {
32882
33225
  const id = nextId++;
32883
33226
  const line = JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n";
@@ -32901,7 +33244,6 @@ async function createCursorAcpClient(options) {
32901
33244
  respond(requestId, payload);
32902
33245
  pendingRequests.delete(requestId);
32903
33246
  }
32904
- let promptOutputBuffer = "";
32905
33247
  const rl = readline.createInterface({ input: child.stdout });
32906
33248
  rl.on("line", (line) => {
32907
33249
  const msg = safeJsonParse(line);
@@ -32930,11 +33272,12 @@ async function createCursorAcpClient(options) {
32930
33272
  `[acp] Received session update (${kindLabel}) tool=${toolName || "(none)"}`
32931
33273
  );
32932
33274
  }
32933
- const isTextChunk = sessionUpdate === "agent_message_chunk" && update.content?.text;
32934
- if (isTextChunk && update.content?.text) {
32935
- promptOutputBuffer += update.content.text;
32936
- }
32937
- onSessionUpdate?.(update);
33275
+ dispatchAcpSessionUpdate({
33276
+ flatPayload: update,
33277
+ onAcpConfigOptionsUpdated: sessionCtx.onAcpConfigOptionsUpdated,
33278
+ onSessionUpdate,
33279
+ suppressLoadReplay: () => sessionCtx.suppressLoadReplay.value
33280
+ });
32938
33281
  return;
32939
33282
  }
32940
33283
  if (method === "session/request_permission" && typeof id === "number") {
@@ -32954,21 +33297,13 @@ async function createCursorAcpClient(options) {
32954
33297
  if (dbgFs) {
32955
33298
  console.error(`[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""}`);
32956
33299
  }
32957
- const resolvedPath = resolveSafePathUnderCwd(cwd, filePath);
32958
- if (!resolvedPath) {
32959
- if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty)`);
32960
- respondJsonRpcError(id, -32602, "Invalid or disallowed path");
32961
- return;
32962
- }
32963
33300
  try {
32964
- let content = readFileSync3(resolvedPath, "utf8");
32965
- const line2 = typeof params.line === "number" ? params.line : void 0;
32966
- const limit = typeof params.limit === "number" ? params.limit : void 0;
32967
- content = sliceLinesByRange(content, line2, limit);
32968
- respond(id, { content });
33301
+ const lineNum = typeof params.line === "number" ? params.line : void 0;
33302
+ const limitNum = typeof params.limit === "number" ? params.limit : void 0;
33303
+ const out = acpReadTextFileInProcess(sessionCtx, filePath, lineNum, limitNum);
33304
+ respond(id, out);
32969
33305
  } catch (e) {
32970
- const code = e?.code;
32971
- if (code === "ENOENT") {
33306
+ if (e?.code === "ENOENT") {
32972
33307
  respond(id, { content: "" });
32973
33308
  } else {
32974
33309
  respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
@@ -32985,32 +33320,17 @@ async function createCursorAcpClient(options) {
32985
33320
  `[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""} newBytes=${newText.length}`
32986
33321
  );
32987
33322
  }
32988
- const resolvedPath = resolveSafePathUnderCwd(cwd, filePath);
32989
- if (!resolvedPath) {
32990
- if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty): ${filePath.slice(0, 120)}`);
32991
- respondJsonRpcError(id, -32602, "Invalid or disallowed path");
32992
- return;
32993
- }
32994
- let oldText = "";
32995
33323
  try {
32996
- oldText = readFileSync3(resolvedPath, "utf8");
33324
+ acpWriteTextFileInProcess(sessionCtx, filePath, newText);
33325
+ respond(id, null);
32997
33326
  } catch (e) {
32998
- if (e.code !== "ENOENT") {
33327
+ if (e.message === "Invalid or disallowed path") {
33328
+ if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty): ${filePath.slice(0, 120)}`);
33329
+ respondJsonRpcError(id, -32602, "Invalid or disallowed path");
33330
+ } else {
32999
33331
  respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
33000
- return;
33001
33332
  }
33002
33333
  }
33003
- try {
33004
- mkdirSync3(dirname3(resolvedPath), { recursive: true });
33005
- writeFileSync3(resolvedPath, newText, "utf8");
33006
- } catch (e) {
33007
- respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
33008
- return;
33009
- }
33010
- const displayPath = toDisplayPathRelativeToCwd(cwd, resolvedPath);
33011
- const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
33012
- onFileChange?.({ path: displayPath, oldText, newText, patchContent });
33013
- respond(id, null);
33014
33334
  return;
33015
33335
  }
33016
33336
  if (method === "cursor/create_plan" || method === "cursor/ask_question") {
@@ -33032,16 +33352,7 @@ async function createCursorAcpClient(options) {
33032
33352
  });
33033
33353
  (async () => {
33034
33354
  try {
33035
- let sendSessionCancelNotification2 = function() {
33036
- const line = JSON.stringify({
33037
- jsonrpc: "2.0",
33038
- method: "session/cancel",
33039
- params: { sessionId }
33040
- }) + "\n";
33041
- return new Promise((res, rej) => {
33042
- child.stdin.write(line, (err) => err ? rej(err) : res());
33043
- });
33044
- }, cancelPendingPermissionRequests2 = function() {
33355
+ let cancelPendingPermissionRequests2 = function() {
33045
33356
  for (const [reqId, pending2] of [...pendingRequests.entries()]) {
33046
33357
  if (pending2.method === "session/request_permission") {
33047
33358
  respond(reqId, { outcome: { outcome: "cancelled" } });
@@ -33049,76 +33360,25 @@ async function createCursorAcpClient(options) {
33049
33360
  }
33050
33361
  }
33051
33362
  };
33052
- var sendSessionCancelNotification = sendSessionCancelNotification2, cancelPendingPermissionRequests = cancelPendingPermissionRequests2;
33053
- await send("initialize", {
33363
+ var cancelPendingPermissionRequests = cancelPendingPermissionRequests2;
33364
+ const transport = createCursorJsonRpcAcpTransport({
33365
+ send,
33366
+ cancelSessionNotification
33367
+ });
33368
+ const established = await bootstrapAcpWireSession(transport, sessionCtx, {
33054
33369
  protocolVersion: 1,
33055
33370
  clientCapabilities: { fs: { readTextFile: true, writeTextFile: true }, terminal: false },
33056
33371
  clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
33057
33372
  });
33058
- await send("authenticate", { methodId: "cursor_login" });
33059
- const newResult = await send("session/new", { cwd, mcpServers: [] });
33060
- const sessionId = newResult?.sessionId ?? "";
33061
- if (!sessionId) throw new Error("Cursor ACP session/new did not return sessionId");
33373
+ const sessionId = established.sessionId;
33062
33374
  resolve18({
33063
33375
  sessionId,
33064
33376
  async sendPrompt(prompt, _options) {
33065
- promptOutputBuffer = "";
33066
- try {
33067
- const result = await send("session/prompt", {
33068
- sessionId,
33069
- prompt: [{ type: "text", text: prompt }]
33070
- });
33071
- await new Promise((r) => setImmediate(r));
33072
- const output = (result?.output ?? promptOutputBuffer) || void 0;
33073
- const stopReason = (result?.stopReason ?? "").toLowerCase();
33074
- const cancelled = stopReason === "cancelled";
33075
- const refusal = stopReason === "refusal";
33076
- const stderrAfter = stderrCapture.getText();
33077
- const agentType = backendAgentType ?? null;
33078
- const stderrEvaluated = Boolean(stderrAfter && agentType);
33079
- const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
33080
- if (cancelled) {
33081
- return {
33082
- success: false,
33083
- stopReason: result?.stopReason,
33084
- output: output || void 0,
33085
- error: mergeErrorWithStderr("Stopped by user", stderrAfter)
33086
- };
33087
- }
33088
- if (refusal) {
33089
- return {
33090
- success: false,
33091
- stopReason: result?.stopReason,
33092
- output: output || void 0,
33093
- error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
33094
- };
33095
- }
33096
- if (stderrSuggestsAuth) {
33097
- return {
33098
- success: false,
33099
- stopReason: result?.stopReason,
33100
- output: output || void 0,
33101
- error: stderrAfter
33102
- };
33103
- }
33104
- return {
33105
- success: true,
33106
- stopReason: result?.stopReason,
33107
- output: output || void 0
33108
- };
33109
- } catch (err) {
33110
- await new Promise((r) => setImmediate(r));
33111
- const stderrAfter = stderrCapture.getText();
33112
- const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
33113
- return {
33114
- success: false,
33115
- error: merged
33116
- };
33117
- }
33377
+ return sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt);
33118
33378
  },
33119
33379
  async cancel() {
33120
33380
  cancelPendingPermissionRequests2();
33121
- await sendSessionCancelNotification2();
33381
+ await transport.cancelSession(sessionId);
33122
33382
  },
33123
33383
  resolveRequest(requestId, result) {
33124
33384
  const numericId = Number(requestId);
@@ -33266,7 +33526,7 @@ function getGitRepoRootSync(startDir) {
33266
33526
 
33267
33527
  // src/agents/acp/workspace-files.ts
33268
33528
  import { execFileSync as execFileSync3 } from "node:child_process";
33269
- import { readFileSync as readFileSync4 } from "node:fs";
33529
+ import { readFileSync as readFileSync3 } from "node:fs";
33270
33530
  import * as path11 from "node:path";
33271
33531
  function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
33272
33532
  const trimmed2 = rawPath.trim();
@@ -33298,7 +33558,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
33298
33558
  const rel = path11.relative(gitRoot, resolvedPath2);
33299
33559
  if (!rel.startsWith("..") && !path11.isAbsolute(rel)) {
33300
33560
  try {
33301
- return readFileSync4(resolvedPath2, "utf8");
33561
+ return readFileSync3(resolvedPath2, "utf8");
33302
33562
  } catch {
33303
33563
  }
33304
33564
  }
@@ -33306,7 +33566,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
33306
33566
  const resolvedPath = resolveSafePathUnderCwd(sessionParentPath, displayPath);
33307
33567
  if (!resolvedPath) return "";
33308
33568
  try {
33309
- return readFileSync4(resolvedPath, "utf8");
33569
+ return readFileSync3(resolvedPath, "utf8");
33310
33570
  } catch {
33311
33571
  return "";
33312
33572
  }
@@ -33402,7 +33662,7 @@ function createBridgeOnFileChange(opts) {
33402
33662
 
33403
33663
  // src/agents/acp/hooks/bridge-on-request.ts
33404
33664
  function createBridgeOnRequest(opts) {
33405
- const { routing, getSendRequest, log: log2 } = opts;
33665
+ const { routing, getSendRequest, log: log2, getAutoApproveAcpPermissions, resolveAcpPermissionRequest } = opts;
33406
33666
  return (request) => {
33407
33667
  const runId = routing.runId;
33408
33668
  const sessionId = routing.sessionId;
@@ -33410,6 +33670,26 @@ function createBridgeOnRequest(opts) {
33410
33670
  if (!runId || !sendReq) return;
33411
33671
  const kind = request.method === "cursor/create_plan" ? "plan" : request.method === "session/request_permission" ? "permission" : "question";
33412
33672
  const sessionUpdate = request.method === "cursor/create_plan" ? "plan" : request.method === "session/request_permission" ? "permission" : "question";
33673
+ if (request.method === "session/request_permission" && getAutoApproveAcpPermissions() && resolveAcpPermissionRequest) {
33674
+ const params = request.params != null && typeof request.params === "object" && !Array.isArray(request.params) ? request.params : {};
33675
+ const auto = buildCliAutoApprovedPermissionRpcResult(params);
33676
+ if (auto != null) {
33677
+ try {
33678
+ resolveAcpPermissionRequest(request.requestId, auto);
33679
+ log2(
33680
+ `[Bridge service] CLI dangerous mode: auto-approved permission requestId=${request.requestId} runId=${runId}`
33681
+ );
33682
+ return;
33683
+ } catch (err) {
33684
+ log2(
33685
+ `[Bridge service] CLI dangerous mode: auto-approve failed (${errorMessage(err)}); forwarding permission`
33686
+ );
33687
+ }
33688
+ }
33689
+ log2(
33690
+ `[Bridge service] CLI dangerous mode: no allow option to auto-select; forwarding permission requestId=${request.requestId}`
33691
+ );
33692
+ }
33413
33693
  try {
33414
33694
  sendReq({
33415
33695
  type: "session_update",
@@ -33810,6 +34090,9 @@ function createBridgeOnSessionUpdate(opts) {
33810
34090
  const sentFileChangePaths = /* @__PURE__ */ new Set();
33811
34091
  const p = params;
33812
34092
  const updateKind = p.sessionUpdate ?? p.session_update ?? p.type ?? "update";
34093
+ if (updateKind === "config_option_update") {
34094
+ return;
34095
+ }
33813
34096
  const isCompletedToolCallUpdate = updateKind === "tool_call_update" && isCompletedToolStatus(p.status);
33814
34097
  const toolName = p.toolCall?.name ?? p.tool_call?.name ?? "";
33815
34098
  const isToolUpdate = updateKind === "tool_call" || updateKind === "tool_call_update" || typeof toolName === "string" && toolName.length > 0;
@@ -33896,14 +34179,73 @@ function buildAcpSessionBridgeHooks(opts) {
33896
34179
  };
33897
34180
  }
33898
34181
 
34182
+ // src/agents/acp/local-agent-session-file.ts
34183
+ import fs10 from "node:fs";
34184
+ import os3 from "node:os";
34185
+ import path12 from "node:path";
34186
+ var LOCAL_AGENT_SESSION_DIR = path12.join(os3.homedir(), ".buildautomaton", "agent-sessions");
34187
+ function safeFileSlug(cloudSessionId) {
34188
+ const t = cloudSessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
34189
+ return t.length > 0 ? t : "session";
34190
+ }
34191
+ function localAgentSessionFilePath(cloudSessionId) {
34192
+ return path12.join(LOCAL_AGENT_SESSION_DIR, `${safeFileSlug(cloudSessionId)}.json`);
34193
+ }
34194
+ function readLocalAgentSessionFile(cloudSessionId) {
34195
+ try {
34196
+ const p = localAgentSessionFilePath(cloudSessionId);
34197
+ const raw = fs10.readFileSync(p, "utf8");
34198
+ const parsed = JSON.parse(raw);
34199
+ if (parsed.v !== 1) return null;
34200
+ return {
34201
+ v: 1,
34202
+ acpSessionId: typeof parsed.acpSessionId === "string" ? parsed.acpSessionId : null,
34203
+ backendAgentType: typeof parsed.backendAgentType === "string" ? parsed.backendAgentType : null,
34204
+ configOptions: Array.isArray(parsed.configOptions) ? parsed.configOptions : null,
34205
+ updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString()
34206
+ };
34207
+ } catch {
34208
+ return null;
34209
+ }
34210
+ }
34211
+ function writeLocalAgentSessionFile(cloudSessionId, patch) {
34212
+ try {
34213
+ const dir = LOCAL_AGENT_SESSION_DIR;
34214
+ if (!fs10.existsSync(dir)) fs10.mkdirSync(dir, { recursive: true });
34215
+ const p = localAgentSessionFilePath(cloudSessionId);
34216
+ const prev = readLocalAgentSessionFile(cloudSessionId);
34217
+ const next = {
34218
+ v: 1,
34219
+ acpSessionId: patch.acpSessionId !== void 0 ? patch.acpSessionId : prev?.acpSessionId ?? null,
34220
+ backendAgentType: patch.backendAgentType !== void 0 ? patch.backendAgentType : prev?.backendAgentType ?? null,
34221
+ configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
34222
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
34223
+ };
34224
+ fs10.writeFileSync(p, JSON.stringify(next, null, 2), "utf8");
34225
+ } catch {
34226
+ }
34227
+ }
34228
+
33899
34229
  // src/agents/acp/ensure-acp-client.ts
33900
34230
  async function ensureAcpClient(options) {
33901
- const { state, preferredAgentType, mode, agentConfig, sessionParentPath, routing, sendSessionUpdate, sendRequest, log: log2 } = options;
34231
+ const {
34232
+ state,
34233
+ preferredAgentType,
34234
+ mode,
34235
+ agentConfig,
34236
+ sessionParentPath,
34237
+ routing,
34238
+ cloudSessionId,
34239
+ sendSessionUpdate,
34240
+ sendRequest,
34241
+ log: log2
34242
+ } = options;
34243
+ state.latestAgentConfigForBridgeHooks = agentConfig != null && typeof agentConfig === "object" && !Array.isArray(agentConfig) ? agentConfig : null;
33902
34244
  const targetSessionParentPath = resolveSessionParentPathForAgentProcess(sessionParentPath);
33903
34245
  if (state.acpStartPromise && !state.acpHandle) {
33904
34246
  await state.acpStartPromise;
33905
34247
  }
33906
- if (state.acpHandle && state.lastAcpCwd != null && path12.resolve(state.lastAcpCwd) !== path12.resolve(targetSessionParentPath)) {
34248
+ if (state.acpHandle && state.lastAcpCwd != null && path13.resolve(state.lastAcpCwd) !== path13.resolve(targetSessionParentPath)) {
33907
34249
  try {
33908
34250
  state.acpHandle.disconnect();
33909
34251
  } catch {
@@ -33911,6 +34253,7 @@ async function ensureAcpClient(options) {
33911
34253
  state.acpHandle = null;
33912
34254
  state.acpStartPromise = null;
33913
34255
  state.acpAgentKey = null;
34256
+ state.activeSessionConfigOptions = null;
33914
34257
  }
33915
34258
  const resolved = resolveAgentCommand(preferredAgentType);
33916
34259
  if (!resolved) {
@@ -33931,12 +34274,13 @@ async function ensureAcpClient(options) {
33931
34274
  state.acpHandle = null;
33932
34275
  state.acpStartPromise = null;
33933
34276
  state.acpAgentKey = null;
34277
+ state.activeSessionConfigOptions = null;
33934
34278
  }
33935
34279
  if (state.acpHandle) return state.acpHandle;
33936
34280
  if (!state.acpStartPromise) {
33937
34281
  let statOk = false;
33938
34282
  try {
33939
- const st = fs10.statSync(targetSessionParentPath);
34283
+ const st = fs11.statSync(targetSessionParentPath);
33940
34284
  statOk = st.isDirectory();
33941
34285
  if (!statOk) {
33942
34286
  state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
@@ -33954,17 +34298,47 @@ async function ensureAcpClient(options) {
33954
34298
  sessionParentPath: targetSessionParentPath,
33955
34299
  getSendSessionUpdate: () => sendSessionUpdate,
33956
34300
  getSendRequest: () => sendRequest,
33957
- log: log2
34301
+ log: log2,
34302
+ getAutoApproveAcpPermissions: () => getCliPermissionModeFromAgentConfig(state.latestAgentConfigForBridgeHooks) === CLI_PERMISSION_MODE_DANGEROUS,
34303
+ resolveAcpPermissionRequest: (requestId, result) => {
34304
+ state.acpHandle?.resolveRequest?.(requestId, result);
34305
+ }
33958
34306
  });
34307
+ const persisted = cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "" ? readLocalAgentSessionFile(cloudSessionId) : null;
34308
+ const persistedAcpSessionId = persisted && persisted.backendAgentType === preferredAgentType && typeof persisted.acpSessionId === "string" && persisted.acpSessionId.trim() !== "" ? persisted.acpSessionId.trim() : null;
34309
+ state.activeSessionConfigOptions = Array.isArray(persisted?.configOptions) ? persisted.configOptions : null;
33959
34310
  state.acpStartPromise = resolved.createClient({
33960
34311
  command: resolved.command,
33961
34312
  sessionMode: mode,
33962
34313
  agentConfig: agentConfig ?? null,
33963
34314
  backendAgentType: preferredAgentType,
34315
+ persistedAcpSessionId,
34316
+ getActiveConfigOptions: () => state.activeSessionConfigOptions,
34317
+ onAcpSessionEstablished: (info) => {
34318
+ state.activeSessionConfigOptions = info.configOptions ?? state.activeSessionConfigOptions;
34319
+ if (cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "") {
34320
+ writeLocalAgentSessionFile(cloudSessionId, {
34321
+ acpSessionId: info.acpSessionId,
34322
+ configOptions: info.configOptions,
34323
+ backendAgentType: preferredAgentType
34324
+ });
34325
+ }
34326
+ },
34327
+ onAcpConfigOptionsUpdated: (configOptions) => {
34328
+ state.activeSessionConfigOptions = configOptions;
34329
+ if (cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "") {
34330
+ writeLocalAgentSessionFile(cloudSessionId, {
34331
+ configOptions,
34332
+ backendAgentType: preferredAgentType
34333
+ });
34334
+ }
34335
+ },
33964
34336
  onAgentSubprocessExit: () => {
33965
34337
  state.acpHandle = null;
33966
34338
  state.acpStartPromise = null;
33967
34339
  state.acpAgentKey = null;
34340
+ state.activeSessionConfigOptions = null;
34341
+ state.latestAgentConfigForBridgeHooks = null;
33968
34342
  state.lastAcpStartError = "Agent subprocess exited";
33969
34343
  },
33970
34344
  ...hooks,
@@ -33994,7 +34368,9 @@ async function createAcpManager(options) {
33994
34368
  acpStartPromise: null,
33995
34369
  lastAcpStartError: null,
33996
34370
  lastAcpCwd: null,
33997
- acpAgentKey: null
34371
+ acpAgentKey: null,
34372
+ activeSessionConfigOptions: null,
34373
+ latestAgentConfigForBridgeHooks: null
33998
34374
  };
33999
34375
  let backendFallbackAgentType = null;
34000
34376
  const promptRouting = {};
@@ -34044,6 +34420,7 @@ async function createAcpManager(options) {
34044
34420
  agentConfig: agentConfig ?? null,
34045
34421
  sessionParentPath,
34046
34422
  routing: promptRouting,
34423
+ cloudSessionId: sessionId,
34047
34424
  sendSessionUpdate,
34048
34425
  sendRequest: sendSessionUpdate,
34049
34426
  log: log2
@@ -34134,6 +34511,8 @@ async function createAcpManager(options) {
34134
34511
  state.acpHandle = null;
34135
34512
  state.acpStartPromise = null;
34136
34513
  state.acpAgentKey = null;
34514
+ state.activeSessionConfigOptions = null;
34515
+ state.latestAgentConfigForBridgeHooks = null;
34137
34516
  }
34138
34517
  return {
34139
34518
  setPreferredAgentType,
@@ -34146,12 +34525,12 @@ async function createAcpManager(options) {
34146
34525
  }
34147
34526
 
34148
34527
  // src/worktrees/session-worktree-manager.ts
34149
- import * as path19 from "node:path";
34150
- import os4 from "node:os";
34528
+ import * as path20 from "node:path";
34529
+ import os5 from "node:os";
34151
34530
 
34152
34531
  // src/worktrees/prepare-new-session-worktrees.ts
34153
- import * as fs12 from "node:fs";
34154
- import * as path14 from "node:path";
34532
+ import * as fs13 from "node:fs";
34533
+ import * as path15 from "node:path";
34155
34534
 
34156
34535
  // src/git/worktree-add.ts
34157
34536
  async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
@@ -34160,12 +34539,12 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
34160
34539
  }
34161
34540
 
34162
34541
  // src/worktrees/worktree-layout-file.ts
34163
- import * as fs11 from "node:fs";
34164
- import * as path13 from "node:path";
34165
- import os3 from "node:os";
34542
+ import * as fs12 from "node:fs";
34543
+ import * as path14 from "node:path";
34544
+ import os4 from "node:os";
34166
34545
  var LAYOUT_FILENAME = "worktree-launcher-layout.json";
34167
34546
  function defaultWorktreeLayoutPath() {
34168
- return path13.join(os3.homedir(), ".buildautomaton", LAYOUT_FILENAME);
34547
+ return path14.join(os4.homedir(), ".buildautomaton", LAYOUT_FILENAME);
34169
34548
  }
34170
34549
  function normalizeLoadedLayout(raw) {
34171
34550
  if (raw && typeof raw === "object" && "launcherCwds" in raw) {
@@ -34177,8 +34556,8 @@ function normalizeLoadedLayout(raw) {
34177
34556
  function loadWorktreeLayout() {
34178
34557
  try {
34179
34558
  const p = defaultWorktreeLayoutPath();
34180
- if (!fs11.existsSync(p)) return { launcherCwds: [] };
34181
- const raw = JSON.parse(fs11.readFileSync(p, "utf8"));
34559
+ if (!fs12.existsSync(p)) return { launcherCwds: [] };
34560
+ const raw = JSON.parse(fs12.readFileSync(p, "utf8"));
34182
34561
  return normalizeLoadedLayout(raw);
34183
34562
  } catch {
34184
34563
  return { launcherCwds: [] };
@@ -34186,24 +34565,24 @@ function loadWorktreeLayout() {
34186
34565
  }
34187
34566
  function saveWorktreeLayout(layout) {
34188
34567
  try {
34189
- const dir = path13.dirname(defaultWorktreeLayoutPath());
34190
- fs11.mkdirSync(dir, { recursive: true });
34191
- fs11.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
34568
+ const dir = path14.dirname(defaultWorktreeLayoutPath());
34569
+ fs12.mkdirSync(dir, { recursive: true });
34570
+ fs12.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
34192
34571
  } catch {
34193
34572
  }
34194
34573
  }
34195
34574
  function baseNameSafe(pathString) {
34196
- return path13.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
34575
+ return path14.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
34197
34576
  }
34198
34577
  function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
34199
- const norm = path13.resolve(bridgeRootPath2);
34200
- const existing = layout.launcherCwds.find((e) => path13.resolve(e.absolutePath) === norm);
34578
+ const norm = path14.resolve(bridgeRootPath2);
34579
+ const existing = layout.launcherCwds.find((e) => path14.resolve(e.absolutePath) === norm);
34201
34580
  return existing?.dirName;
34202
34581
  }
34203
34582
  function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
34204
34583
  const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
34205
34584
  if (existing) return existing;
34206
- const norm = path13.resolve(bridgeRootPath2);
34585
+ const norm = path14.resolve(bridgeRootPath2);
34207
34586
  const base = baseNameSafe(norm);
34208
34587
  const used = new Set(layout.launcherCwds.map((e) => e.dirName));
34209
34588
  let name = base;
@@ -34220,10 +34599,10 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
34220
34599
  // src/worktrees/prepare-new-session-worktrees.ts
34221
34600
  async function prepareNewSessionWorktrees(options) {
34222
34601
  const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2 } = options;
34223
- const bridgeResolved = path14.resolve(bridgeRoot);
34602
+ const bridgeResolved = path15.resolve(bridgeRoot);
34224
34603
  const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
34225
- const bridgeKeyDir = path14.join(worktreesRootPath, cwdKey);
34226
- const sessionDir = path14.join(bridgeKeyDir, sessionId);
34604
+ const bridgeKeyDir = path15.join(worktreesRootPath, cwdKey);
34605
+ const sessionDir = path15.join(bridgeKeyDir, sessionId);
34227
34606
  const repos = await discoverGitReposUnderRoot(bridgeResolved);
34228
34607
  if (repos.length === 0) {
34229
34608
  log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
@@ -34231,14 +34610,14 @@ async function prepareNewSessionWorktrees(options) {
34231
34610
  }
34232
34611
  const branch = `session-${sessionId}`;
34233
34612
  const worktreePaths = [];
34234
- fs12.mkdirSync(sessionDir, { recursive: true });
34613
+ fs13.mkdirSync(sessionDir, { recursive: true });
34235
34614
  for (const repo of repos) {
34236
- let rel = path14.relative(bridgeResolved, repo.absolutePath);
34237
- if (rel.startsWith("..") || path14.isAbsolute(rel)) continue;
34615
+ let rel = path15.relative(bridgeResolved, repo.absolutePath);
34616
+ if (rel.startsWith("..") || path15.isAbsolute(rel)) continue;
34238
34617
  const relNorm = rel === "" ? "." : rel;
34239
- const wtPath = relNorm === "." ? sessionDir : path14.join(sessionDir, relNorm);
34618
+ const wtPath = relNorm === "." ? sessionDir : path15.join(sessionDir, relNorm);
34240
34619
  if (relNorm !== ".") {
34241
- fs12.mkdirSync(path14.dirname(wtPath), { recursive: true });
34620
+ fs13.mkdirSync(path15.dirname(wtPath), { recursive: true });
34242
34621
  }
34243
34622
  try {
34244
34623
  await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
@@ -34280,23 +34659,23 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
34280
34659
  }
34281
34660
 
34282
34661
  // src/worktrees/remove-session-worktrees.ts
34283
- import * as fs15 from "node:fs";
34662
+ import * as fs16 from "node:fs";
34284
34663
 
34285
34664
  // src/git/worktree-remove.ts
34286
- import * as fs14 from "node:fs";
34665
+ import * as fs15 from "node:fs";
34287
34666
 
34288
34667
  // src/git/resolve-main-repo-from-git-file.ts
34289
- import * as fs13 from "node:fs";
34290
- import * as path15 from "node:path";
34668
+ import * as fs14 from "node:fs";
34669
+ import * as path16 from "node:path";
34291
34670
  function resolveMainRepoFromWorktreeGitFile(wt) {
34292
- const gitDirFile = path15.join(wt, ".git");
34293
- if (!fs13.existsSync(gitDirFile) || !fs13.statSync(gitDirFile).isFile()) return "";
34294
- const first2 = fs13.readFileSync(gitDirFile, "utf8").trim();
34671
+ const gitDirFile = path16.join(wt, ".git");
34672
+ if (!fs14.existsSync(gitDirFile) || !fs14.statSync(gitDirFile).isFile()) return "";
34673
+ const first2 = fs14.readFileSync(gitDirFile, "utf8").trim();
34295
34674
  const m = first2.match(/^gitdir:\s*(.+)$/im);
34296
34675
  if (!m) return "";
34297
- const gitWorktreePath = path15.resolve(wt, m[1].trim());
34298
- const gitDir = path15.dirname(path15.dirname(gitWorktreePath));
34299
- return path15.dirname(gitDir);
34676
+ const gitWorktreePath = path16.resolve(wt, m[1].trim());
34677
+ const gitDir = path16.dirname(path16.dirname(gitWorktreePath));
34678
+ return path16.dirname(gitDir);
34300
34679
  }
34301
34680
 
34302
34681
  // src/git/worktree-remove.ts
@@ -34305,7 +34684,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
34305
34684
  if (mainRepo) {
34306
34685
  await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
34307
34686
  } else {
34308
- fs14.rmSync(worktreePath, { recursive: true, force: true });
34687
+ fs15.rmSync(worktreePath, { recursive: true, force: true });
34309
34688
  }
34310
34689
  }
34311
34690
 
@@ -34318,7 +34697,7 @@ async function removeSessionWorktrees(paths, log2) {
34318
34697
  } catch (e) {
34319
34698
  log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
34320
34699
  try {
34321
- fs15.rmSync(wt, { recursive: true, force: true });
34700
+ fs16.rmSync(wt, { recursive: true, force: true });
34322
34701
  } catch {
34323
34702
  }
34324
34703
  }
@@ -34538,7 +34917,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
34538
34917
  }
34539
34918
 
34540
34919
  // src/git/working-directory/changes/get-working-tree-change-repo-details.ts
34541
- import * as path17 from "node:path";
34920
+ import * as path18 from "node:path";
34542
34921
 
34543
34922
  // src/git/working-directory/changes/parse-git-status.ts
34544
34923
  function parseNameStatusLines(lines) {
@@ -34658,8 +35037,8 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
34658
35037
  }
34659
35038
 
34660
35039
  // src/git/working-directory/changes/list-changed-files-for-repo.ts
34661
- import * as fs17 from "node:fs";
34662
- import * as path16 from "node:path";
35040
+ import * as fs18 from "node:fs";
35041
+ import * as path17 from "node:path";
34663
35042
 
34664
35043
  // src/git/working-directory/changes/count-lines.ts
34665
35044
  import { createReadStream } from "node:fs";
@@ -34683,7 +35062,7 @@ async function countTextFileLines(filePath) {
34683
35062
  }
34684
35063
 
34685
35064
  // src/git/working-directory/changes/hydrate-patch.ts
34686
- import * as fs16 from "node:fs";
35065
+ import * as fs17 from "node:fs";
34687
35066
  var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
34688
35067
  var MAX_HYDRATE_LINES_PER_GAP = 8e3;
34689
35068
  var MAX_HYDRATE_LINES_PER_FILE = 8e4;
@@ -34698,7 +35077,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
34698
35077
  }
34699
35078
  async function readWorktreeFileLines(filePath) {
34700
35079
  try {
34701
- const raw = await fs16.promises.readFile(filePath, "utf8");
35080
+ const raw = await fs17.promises.readFile(filePath, "utf8");
34702
35081
  return raw.split(/\r?\n/);
34703
35082
  } catch {
34704
35083
  return null;
@@ -34833,7 +35212,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
34833
35212
  const rows = [];
34834
35213
  for (const pathInRepo of paths) {
34835
35214
  const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
34836
- const repoFilePath = path16.join(repoGitCwd, pathInRepo);
35215
+ const repoFilePath = path17.join(repoGitCwd, pathInRepo);
34837
35216
  const nums = numByPath.get(pathInRepo);
34838
35217
  let additions = nums?.additions ?? 0;
34839
35218
  let deletions = nums?.deletions ?? 0;
@@ -34846,7 +35225,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
34846
35225
  deletions = fromGit.deletions;
34847
35226
  } else {
34848
35227
  try {
34849
- const st = await fs17.promises.stat(repoFilePath);
35228
+ const st = await fs18.promises.stat(repoFilePath);
34850
35229
  if (st.isFile()) additions = await countTextFileLines(repoFilePath);
34851
35230
  else additions = 0;
34852
35231
  } catch {
@@ -34872,7 +35251,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
34872
35251
  } else {
34873
35252
  pathInRepo = row.pathRelLauncher;
34874
35253
  }
34875
- const filePath = path16.join(repoGitCwd, pathInRepo);
35254
+ const filePath = path17.join(repoGitCwd, pathInRepo);
34876
35255
  let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
34877
35256
  if (patch) {
34878
35257
  patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
@@ -34888,8 +35267,8 @@ function normRepoRel(p) {
34888
35267
  return x === "" ? "." : x;
34889
35268
  }
34890
35269
  async function getWorkingTreeChangeRepoDetails(options) {
34891
- const bridgeRoot = path17.resolve(getBridgeRoot());
34892
- const sessionWtRoot = options.sessionWorktreeRootPath ? path17.resolve(options.sessionWorktreeRootPath) : null;
35270
+ const bridgeRoot = path18.resolve(getBridgeRoot());
35271
+ const sessionWtRoot = options.sessionWorktreeRootPath ? path18.resolve(options.sessionWorktreeRootPath) : null;
34893
35272
  const legacyNested = options.legacyRepoNestedSessionLayout === true;
34894
35273
  const out = [];
34895
35274
  const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
@@ -34902,7 +35281,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
34902
35281
  }
34903
35282
  const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
34904
35283
  for (const target of options.commitTargetPaths) {
34905
- const t = path17.resolve(target);
35284
+ const t = path18.resolve(target);
34906
35285
  if (!await isGitRepoDirectory(t)) continue;
34907
35286
  const g = cliSimpleGit(t);
34908
35287
  let branch = "HEAD";
@@ -34915,8 +35294,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
34915
35294
  const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
34916
35295
  let repoRelPath;
34917
35296
  if (sessionWtRoot) {
34918
- const anchor = legacyNested ? path17.dirname(t) : t;
34919
- const relNorm = path17.relative(sessionWtRoot, anchor);
35297
+ const anchor = legacyNested ? path18.dirname(t) : t;
35298
+ const relNorm = path18.relative(sessionWtRoot, anchor);
34920
35299
  repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
34921
35300
  } else {
34922
35301
  let top = t;
@@ -34925,8 +35304,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
34925
35304
  } catch {
34926
35305
  top = t;
34927
35306
  }
34928
- const rel = path17.relative(bridgeRoot, path17.resolve(top)).replace(/\\/g, "/") || ".";
34929
- repoRelPath = rel.startsWith("..") ? path17.basename(path17.resolve(top)) : rel;
35307
+ const rel = path18.relative(bridgeRoot, path18.resolve(top)).replace(/\\/g, "/") || ".";
35308
+ repoRelPath = rel.startsWith("..") ? path18.basename(path18.resolve(top)) : rel;
34930
35309
  }
34931
35310
  const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
34932
35311
  if (filter && norm !== filter) continue;
@@ -34991,11 +35370,11 @@ async function commitSessionWorktrees(options) {
34991
35370
  }
34992
35371
 
34993
35372
  // src/worktrees/discover-session-worktree-on-disk.ts
34994
- import * as fs18 from "node:fs";
34995
- import * as path18 from "node:path";
35373
+ import * as fs19 from "node:fs";
35374
+ import * as path19 from "node:path";
34996
35375
  function isGitDir(dirPath) {
34997
35376
  try {
34998
- return fs18.existsSync(path18.join(dirPath, ".git"));
35377
+ return fs19.existsSync(path19.join(dirPath, ".git"));
34999
35378
  } catch {
35000
35379
  return false;
35001
35380
  }
@@ -35004,23 +35383,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
35004
35383
  const out = [];
35005
35384
  const walk = (dir) => {
35006
35385
  if (isGitDir(dir)) {
35007
- out.push(path18.resolve(dir));
35386
+ out.push(path19.resolve(dir));
35008
35387
  return;
35009
35388
  }
35010
35389
  let entries;
35011
35390
  try {
35012
- entries = fs18.readdirSync(dir, { withFileTypes: true });
35391
+ entries = fs19.readdirSync(dir, { withFileTypes: true });
35013
35392
  } catch {
35014
35393
  return;
35015
35394
  }
35016
35395
  for (const e of entries) {
35017
35396
  if (e.name.startsWith(".")) continue;
35018
- const full = path18.join(dir, e.name);
35397
+ const full = path19.join(dir, e.name);
35019
35398
  if (!e.isDirectory()) continue;
35020
35399
  walk(full);
35021
35400
  }
35022
35401
  };
35023
- walk(path18.resolve(rootPath));
35402
+ walk(path19.resolve(rootPath));
35024
35403
  return [...new Set(out)];
35025
35404
  }
35026
35405
  function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
@@ -35029,16 +35408,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
35029
35408
  if (depth > maxDepth) return;
35030
35409
  let entries;
35031
35410
  try {
35032
- entries = fs18.readdirSync(dir, { withFileTypes: true });
35411
+ entries = fs19.readdirSync(dir, { withFileTypes: true });
35033
35412
  } catch {
35034
35413
  return;
35035
35414
  }
35036
35415
  for (const e of entries) {
35037
35416
  if (e.name.startsWith(".")) continue;
35038
- const full = path18.join(dir, e.name);
35417
+ const full = path19.join(dir, e.name);
35039
35418
  if (!e.isDirectory()) continue;
35040
35419
  if (e.name === sessionId) {
35041
- if (isGitDir(full)) out.push(path18.resolve(full));
35420
+ if (isGitDir(full)) out.push(path19.resolve(full));
35042
35421
  } else {
35043
35422
  walk(full, depth + 1);
35044
35423
  }
@@ -35050,14 +35429,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
35050
35429
  function tryBindingFromSessionDirectory(sessionDir) {
35051
35430
  let st;
35052
35431
  try {
35053
- st = fs18.statSync(sessionDir);
35432
+ st = fs19.statSync(sessionDir);
35054
35433
  } catch {
35055
35434
  return null;
35056
35435
  }
35057
35436
  if (!st.isDirectory()) return null;
35058
35437
  const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
35059
35438
  if (worktreePaths.length === 0) return null;
35060
- const abs = path18.resolve(sessionDir);
35439
+ const abs = path19.resolve(sessionDir);
35061
35440
  return {
35062
35441
  sessionParentPath: abs,
35063
35442
  workingTreeRelRoot: abs,
@@ -35067,20 +35446,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
35067
35446
  function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
35068
35447
  const sid = sessionId.trim();
35069
35448
  if (!sid) return null;
35070
- const hintR = path18.resolve(checkoutPath);
35449
+ const hintR = path19.resolve(checkoutPath);
35071
35450
  let best = null;
35072
- let cur = path18.dirname(hintR);
35451
+ let cur = path19.dirname(hintR);
35073
35452
  for (let i = 0; i < 40; i++) {
35074
35453
  const paths = collectWorktreeRootsNamed(cur, sid, 24);
35075
- if (paths.some((p) => path18.resolve(p) === hintR)) {
35076
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path18.resolve(paths[0]);
35454
+ if (paths.some((p) => path19.resolve(p) === hintR)) {
35455
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path19.resolve(paths[0]);
35077
35456
  best = {
35078
- sessionParentPath: path18.resolve(isolated),
35079
- workingTreeRelRoot: path18.resolve(cur),
35080
- repoCheckoutPaths: paths.map((p) => path18.resolve(p))
35457
+ sessionParentPath: path19.resolve(isolated),
35458
+ workingTreeRelRoot: path19.resolve(cur),
35459
+ repoCheckoutPaths: paths.map((p) => path19.resolve(p))
35081
35460
  };
35082
35461
  }
35083
- const next = path18.dirname(cur);
35462
+ const next = path19.dirname(cur);
35084
35463
  if (next === cur) break;
35085
35464
  cur = next;
35086
35465
  }
@@ -35088,33 +35467,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
35088
35467
  }
35089
35468
  function discoverSessionWorktreeOnDisk(options) {
35090
35469
  const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
35091
- if (!sessionId.trim() || !fs18.existsSync(worktreesRootPath)) return null;
35470
+ if (!sessionId.trim() || !fs19.existsSync(worktreesRootPath)) return null;
35092
35471
  const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
35093
35472
  const keys = [];
35094
35473
  if (preferredKey) keys.push(preferredKey);
35095
35474
  try {
35096
- for (const name of fs18.readdirSync(worktreesRootPath)) {
35475
+ for (const name of fs19.readdirSync(worktreesRootPath)) {
35097
35476
  if (name.startsWith(".")) continue;
35098
- const p = path18.join(worktreesRootPath, name);
35099
- if (!fs18.statSync(p).isDirectory()) continue;
35477
+ const p = path19.join(worktreesRootPath, name);
35478
+ if (!fs19.statSync(p).isDirectory()) continue;
35100
35479
  if (name !== preferredKey) keys.push(name);
35101
35480
  }
35102
35481
  } catch {
35103
35482
  return null;
35104
35483
  }
35105
35484
  for (const key of keys) {
35106
- const layoutRoot = path18.join(worktreesRootPath, key);
35107
- if (!fs18.existsSync(layoutRoot) || !fs18.statSync(layoutRoot).isDirectory()) continue;
35108
- const sessionDir = path18.join(layoutRoot, sessionId);
35485
+ const layoutRoot = path19.join(worktreesRootPath, key);
35486
+ if (!fs19.existsSync(layoutRoot) || !fs19.statSync(layoutRoot).isDirectory()) continue;
35487
+ const sessionDir = path19.join(layoutRoot, sessionId);
35109
35488
  const nested = tryBindingFromSessionDirectory(sessionDir);
35110
35489
  if (nested) return nested;
35111
35490
  const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
35112
35491
  if (legacyPaths.length > 0) {
35113
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path18.resolve(legacyPaths[0]);
35492
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path19.resolve(legacyPaths[0]);
35114
35493
  return {
35115
- sessionParentPath: path18.resolve(isolated),
35116
- workingTreeRelRoot: path18.resolve(layoutRoot),
35117
- repoCheckoutPaths: legacyPaths.map((p) => path18.resolve(p))
35494
+ sessionParentPath: path19.resolve(isolated),
35495
+ workingTreeRelRoot: path19.resolve(layoutRoot),
35496
+ repoCheckoutPaths: legacyPaths.map((p) => path19.resolve(p))
35118
35497
  };
35119
35498
  }
35120
35499
  }
@@ -35123,12 +35502,12 @@ function discoverSessionWorktreeOnDisk(options) {
35123
35502
  function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
35124
35503
  const sid = sessionId.trim();
35125
35504
  if (!sid) return null;
35126
- const hint = path18.resolve(sessionWorktreeRootPathOrHint);
35127
- const underHint = tryBindingFromSessionDirectory(path18.join(hint, sid));
35505
+ const hint = path19.resolve(sessionWorktreeRootPathOrHint);
35506
+ const underHint = tryBindingFromSessionDirectory(path19.join(hint, sid));
35128
35507
  if (underHint) return underHint;
35129
35508
  const direct = tryBindingFromSessionDirectory(hint);
35130
35509
  if (direct) {
35131
- if (path18.basename(hint) === sid && isGitDir(hint)) {
35510
+ if (path19.basename(hint) === sid && isGitDir(hint)) {
35132
35511
  const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
35133
35512
  if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
35134
35513
  return legacyFromCheckout;
@@ -35136,24 +35515,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
35136
35515
  }
35137
35516
  return direct;
35138
35517
  }
35139
- if (path18.basename(hint) === sid && isGitDir(hint)) {
35518
+ if (path19.basename(hint) === sid && isGitDir(hint)) {
35140
35519
  const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
35141
35520
  if (legacyFromCheckout) return legacyFromCheckout;
35142
35521
  }
35143
35522
  let st;
35144
35523
  try {
35145
- st = fs18.statSync(hint);
35524
+ st = fs19.statSync(hint);
35146
35525
  } catch {
35147
35526
  return null;
35148
35527
  }
35149
35528
  if (!st.isDirectory()) return null;
35150
35529
  const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
35151
35530
  if (legacyPaths.length === 0) return null;
35152
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path18.resolve(legacyPaths[0]);
35531
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path19.resolve(legacyPaths[0]);
35153
35532
  return {
35154
- sessionParentPath: path18.resolve(isolated),
35533
+ sessionParentPath: path19.resolve(isolated),
35155
35534
  workingTreeRelRoot: hint,
35156
- repoCheckoutPaths: legacyPaths.map((p) => path18.resolve(p))
35535
+ repoCheckoutPaths: legacyPaths.map((p) => path19.resolve(p))
35157
35536
  };
35158
35537
  }
35159
35538
 
@@ -35176,10 +35555,10 @@ var SessionWorktreeManager = class {
35176
35555
  this.layout = loadWorktreeLayout();
35177
35556
  }
35178
35557
  rememberSessionWorktrees(sessionId, binding) {
35179
- const paths = binding.repoCheckoutPaths.map((p) => path19.resolve(p));
35558
+ const paths = binding.repoCheckoutPaths.map((p) => path20.resolve(p));
35180
35559
  this.sessionRepoCheckoutPaths.set(sessionId, paths);
35181
- this.sessionParentPathBySession.set(sessionId, path19.resolve(binding.sessionParentPath));
35182
- this.sessionWorkingTreeRelRootBySession.set(sessionId, path19.resolve(binding.workingTreeRelRoot));
35560
+ this.sessionParentPathBySession.set(sessionId, path20.resolve(binding.sessionParentPath));
35561
+ this.sessionWorkingTreeRelRootBySession.set(sessionId, path20.resolve(binding.workingTreeRelRoot));
35183
35562
  }
35184
35563
  sessionParentPathAfterRemember(sessionId) {
35185
35564
  return this.sessionParentPathBySession.get(sessionId);
@@ -35196,7 +35575,7 @@ var SessionWorktreeManager = class {
35196
35575
  const parent = this.sessionParentPathBySession.get(sessionId);
35197
35576
  const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
35198
35577
  if (!parent || !relRoot) return false;
35199
- return path19.resolve(parent) !== path19.resolve(relRoot);
35578
+ return path20.resolve(parent) !== path20.resolve(relRoot);
35200
35579
  }
35201
35580
  /**
35202
35581
  * Session parent path for `worktrees_root`: the per-session directory (new layout) or primary checkout (legacy).
@@ -35205,7 +35584,7 @@ var SessionWorktreeManager = class {
35205
35584
  if (!sessionId) return null;
35206
35585
  const sid = sessionId.trim();
35207
35586
  const cached2 = this.sessionParentPathBySession.get(sid);
35208
- if (cached2) return path19.resolve(cached2);
35587
+ if (cached2) return path20.resolve(cached2);
35209
35588
  const paths = this.ensureRepoCheckoutPathsForSession(sid) ?? this.getRepoCheckoutPathsForSession(sid);
35210
35589
  if (!paths?.length) return null;
35211
35590
  return resolveIsolatedSessionParentPathFromCheckouts(paths);
@@ -35219,7 +35598,7 @@ var SessionWorktreeManager = class {
35219
35598
  const sid = sessionId.trim();
35220
35599
  const parentPathRaw = opts.sessionParentPath?.trim();
35221
35600
  if (parentPathRaw) {
35222
- const resolved = path19.resolve(parentPathRaw);
35601
+ const resolved = path20.resolve(parentPathRaw);
35223
35602
  if (sid && parseSessionParent(opts.sessionParent) === "worktrees_root") {
35224
35603
  const diskFirst = this.tryDiscoverFromDisk(sid);
35225
35604
  if (diskFirst) {
@@ -35238,7 +35617,7 @@ var SessionWorktreeManager = class {
35238
35617
  this.rememberSessionWorktrees(sid, tryRoot);
35239
35618
  return this.sessionParentPathAfterRemember(sid);
35240
35619
  }
35241
- const next = path19.dirname(cur);
35620
+ const next = path20.dirname(cur);
35242
35621
  if (next === cur) break;
35243
35622
  cur = next;
35244
35623
  }
@@ -35391,15 +35770,15 @@ var SessionWorktreeManager = class {
35391
35770
  }
35392
35771
  };
35393
35772
  function defaultWorktreesRootPath() {
35394
- return path19.join(os4.homedir(), ".buildautomaton", "worktrees");
35773
+ return path20.join(os5.homedir(), ".buildautomaton", "worktrees");
35395
35774
  }
35396
35775
 
35397
35776
  // src/files/watch-file-index.ts
35398
35777
  import { watch } from "node:fs";
35399
- import path26 from "node:path";
35778
+ import path27 from "node:path";
35400
35779
 
35401
35780
  // src/files/index/build-file-index.ts
35402
- import path23 from "node:path";
35781
+ import path24 from "node:path";
35403
35782
 
35404
35783
  // src/runtime/yield-to-event-loop.ts
35405
35784
  function yieldToEventLoop() {
@@ -35407,14 +35786,14 @@ function yieldToEventLoop() {
35407
35786
  }
35408
35787
 
35409
35788
  // src/files/index/walk-workspace-tree.ts
35410
- import fs19 from "node:fs";
35411
- import path21 from "node:path";
35789
+ import fs20 from "node:fs";
35790
+ import path22 from "node:path";
35412
35791
 
35413
35792
  // src/files/index/constants.ts
35414
- import path20 from "node:path";
35415
- import os5 from "node:os";
35793
+ import path21 from "node:path";
35794
+ import os6 from "node:os";
35416
35795
  var INDEX_WORK_YIELD_EVERY = 256;
35417
- var INDEX_DIR = path20.join(os5.homedir(), ".buildautomaton");
35796
+ var INDEX_DIR = path21.join(os6.homedir(), ".buildautomaton");
35418
35797
  var INDEX_HASH_LEN = 16;
35419
35798
  var INDEX_VERSION = 2;
35420
35799
  var INDEX_LOG_PREFIX = "[file-index]";
@@ -35423,20 +35802,20 @@ var INDEX_LOG_PREFIX = "[file-index]";
35423
35802
  function walkWorkspaceTreeSync(dir, baseDir, out) {
35424
35803
  let names;
35425
35804
  try {
35426
- names = fs19.readdirSync(dir);
35805
+ names = fs20.readdirSync(dir);
35427
35806
  } catch {
35428
35807
  return;
35429
35808
  }
35430
35809
  for (const name of names) {
35431
35810
  if (name.startsWith(".")) continue;
35432
- const full = path21.join(dir, name);
35811
+ const full = path22.join(dir, name);
35433
35812
  let stat3;
35434
35813
  try {
35435
- stat3 = fs19.statSync(full);
35814
+ stat3 = fs20.statSync(full);
35436
35815
  } catch {
35437
35816
  continue;
35438
35817
  }
35439
- const relative5 = path21.relative(baseDir, full).replace(/\\/g, "/");
35818
+ const relative5 = path22.relative(baseDir, full).replace(/\\/g, "/");
35440
35819
  if (stat3.isDirectory()) {
35441
35820
  walkWorkspaceTreeSync(full, baseDir, out);
35442
35821
  } else if (stat3.isFile()) {
@@ -35447,7 +35826,7 @@ function walkWorkspaceTreeSync(dir, baseDir, out) {
35447
35826
  async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
35448
35827
  let names;
35449
35828
  try {
35450
- names = await fs19.promises.readdir(dir);
35829
+ names = await fs20.promises.readdir(dir);
35451
35830
  } catch {
35452
35831
  return;
35453
35832
  }
@@ -35457,14 +35836,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
35457
35836
  await yieldToEventLoop();
35458
35837
  }
35459
35838
  state.n++;
35460
- const full = path21.join(dir, name);
35839
+ const full = path22.join(dir, name);
35461
35840
  let stat3;
35462
35841
  try {
35463
- stat3 = await fs19.promises.stat(full);
35842
+ stat3 = await fs20.promises.stat(full);
35464
35843
  } catch {
35465
35844
  continue;
35466
35845
  }
35467
- const relative5 = path21.relative(baseDir, full).replace(/\\/g, "/");
35846
+ const relative5 = path22.relative(baseDir, full).replace(/\\/g, "/");
35468
35847
  if (stat3.isDirectory()) {
35469
35848
  await walkWorkspaceTreeAsync(full, baseDir, out, state);
35470
35849
  } else if (stat3.isFile()) {
@@ -35545,22 +35924,22 @@ async function buildTrigramMapForPathsAsync(paths) {
35545
35924
  }
35546
35925
 
35547
35926
  // src/files/index/write-index-file.ts
35548
- import fs20 from "node:fs";
35927
+ import fs21 from "node:fs";
35549
35928
 
35550
35929
  // src/files/index/paths.ts
35551
- import path22 from "node:path";
35930
+ import path23 from "node:path";
35552
35931
  import crypto2 from "node:crypto";
35553
35932
  function getIndexPathForCwd(resolvedCwd) {
35554
35933
  const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
35555
- return path22.join(INDEX_DIR, `.file-index-${hash}.json`);
35934
+ return path23.join(INDEX_DIR, `.file-index-${hash}.json`);
35556
35935
  }
35557
35936
 
35558
35937
  // src/files/index/write-index-file.ts
35559
35938
  function writeIndexFileSync(resolvedCwd, data) {
35560
35939
  const indexPath = getIndexPathForCwd(resolvedCwd);
35561
35940
  try {
35562
- if (!fs20.existsSync(INDEX_DIR)) fs20.mkdirSync(INDEX_DIR, { recursive: true });
35563
- fs20.writeFileSync(indexPath, JSON.stringify(data), "utf8");
35941
+ if (!fs21.existsSync(INDEX_DIR)) fs21.mkdirSync(INDEX_DIR, { recursive: true });
35942
+ fs21.writeFileSync(indexPath, JSON.stringify(data), "utf8");
35564
35943
  } catch (e) {
35565
35944
  console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
35566
35945
  }
@@ -35568,8 +35947,8 @@ function writeIndexFileSync(resolvedCwd, data) {
35568
35947
  async function writeIndexFileAsync(resolvedCwd, data) {
35569
35948
  const indexPath = getIndexPathForCwd(resolvedCwd);
35570
35949
  try {
35571
- await fs20.promises.mkdir(INDEX_DIR, { recursive: true });
35572
- await fs20.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
35950
+ await fs21.promises.mkdir(INDEX_DIR, { recursive: true });
35951
+ await fs21.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
35573
35952
  } catch (e) {
35574
35953
  console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
35575
35954
  }
@@ -35583,7 +35962,7 @@ function sortPaths(paths) {
35583
35962
  paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
35584
35963
  }
35585
35964
  function buildFileIndex(cwd) {
35586
- const resolved = path23.resolve(cwd);
35965
+ const resolved = path24.resolve(cwd);
35587
35966
  const paths = [];
35588
35967
  walkWorkspaceTreeSync(resolved, resolved, paths);
35589
35968
  sortPaths(paths);
@@ -35593,7 +35972,7 @@ function buildFileIndex(cwd) {
35593
35972
  return data;
35594
35973
  }
35595
35974
  async function buildFileIndexAsync(cwd) {
35596
- const resolved = path23.resolve(cwd);
35975
+ const resolved = path24.resolve(cwd);
35597
35976
  const paths = [];
35598
35977
  await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
35599
35978
  await yieldToEventLoop();
@@ -35605,13 +35984,13 @@ async function buildFileIndexAsync(cwd) {
35605
35984
  }
35606
35985
 
35607
35986
  // src/files/index/load-file-index.ts
35608
- import fs21 from "node:fs";
35609
- import path24 from "node:path";
35987
+ import fs22 from "node:fs";
35988
+ import path25 from "node:path";
35610
35989
  function loadFileIndex(cwd) {
35611
- const resolved = path24.resolve(cwd);
35990
+ const resolved = path25.resolve(cwd);
35612
35991
  const indexPath = getIndexPathForCwd(resolved);
35613
35992
  try {
35614
- const raw = fs21.readFileSync(indexPath, "utf8");
35993
+ const raw = fs22.readFileSync(indexPath, "utf8");
35615
35994
  const parsed = JSON.parse(raw);
35616
35995
  if (parsed !== null && typeof parsed === "object" && Array.isArray(parsed.paths)) {
35617
35996
  const obj = parsed;
@@ -35630,9 +36009,9 @@ function loadFileIndex(cwd) {
35630
36009
  }
35631
36010
 
35632
36011
  // src/files/index/ensure-file-index.ts
35633
- import path25 from "node:path";
36012
+ import path26 from "node:path";
35634
36013
  async function ensureFileIndexAsync(cwd) {
35635
- const resolved = path25.resolve(cwd);
36014
+ const resolved = path26.resolve(cwd);
35636
36015
  const cached2 = loadFileIndex(resolved);
35637
36016
  if (cached2 !== null) return { data: cached2, fromCache: true };
35638
36017
  const data = await buildFileIndexAsync(resolved);
@@ -35715,7 +36094,7 @@ function createFsWatcher(resolved, schedule) {
35715
36094
  }
35716
36095
  }
35717
36096
  function startFileIndexWatcher(cwd = getBridgeRoot()) {
35718
- const resolved = path26.resolve(cwd);
36097
+ const resolved = path27.resolve(cwd);
35719
36098
  void buildFileIndexAsync(resolved).catch((e) => {
35720
36099
  console.error("[file-index] Initial index build failed:", e);
35721
36100
  });
@@ -35743,7 +36122,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
35743
36122
  }
35744
36123
 
35745
36124
  // src/connection/create-bridge-connection.ts
35746
- import * as path34 from "node:path";
36125
+ import * as path35 from "node:path";
35747
36126
 
35748
36127
  // src/dev-servers/manager/dev-server-manager.ts
35749
36128
  import { rm as rm2 } from "node:fs/promises";
@@ -35787,7 +36166,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
35787
36166
  }
35788
36167
 
35789
36168
  // src/dev-servers/process/wire-dev-server-child-process.ts
35790
- import fs22 from "node:fs";
36169
+ import fs23 from "node:fs";
35791
36170
 
35792
36171
  // src/dev-servers/manager/forward-pipe.ts
35793
36172
  function forwardChildPipe(childReadable, terminal, onData) {
@@ -35823,7 +36202,7 @@ function wireDevServerChildProcess(d) {
35823
36202
  d.setPollInterval(void 0);
35824
36203
  return;
35825
36204
  }
35826
- fs22.readFile(d.mergedLogPath, (err, buf) => {
36205
+ fs23.readFile(d.mergedLogPath, (err, buf) => {
35827
36206
  if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
35828
36207
  if (buf.length <= d.mergedReadPos.value) return;
35829
36208
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
@@ -35861,7 +36240,7 @@ ${errTail}` : ""}`);
35861
36240
  d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
35862
36241
  };
35863
36242
  if (mergedPath) {
35864
- fs22.readFile(mergedPath, (err, buf) => {
36243
+ fs23.readFile(mergedPath, (err, buf) => {
35865
36244
  if (!err && buf.length > d.mergedReadPos.value) {
35866
36245
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
35867
36246
  if (chunk.length > 0) {
@@ -35963,13 +36342,13 @@ function parseDevServerDefs(servers) {
35963
36342
  }
35964
36343
 
35965
36344
  // src/dev-servers/manager/shell-spawn/utils.ts
35966
- import fs23 from "node:fs";
36345
+ import fs24 from "node:fs";
35967
36346
  function isSpawnEbadf(e) {
35968
36347
  return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
35969
36348
  }
35970
36349
  function rmDirQuiet(dir) {
35971
36350
  try {
35972
- fs23.rmSync(dir, { recursive: true, force: true });
36351
+ fs24.rmSync(dir, { recursive: true, force: true });
35973
36352
  } catch {
35974
36353
  }
35975
36354
  }
@@ -35977,7 +36356,7 @@ var cachedDevNullReadFd;
35977
36356
  function devNullReadFd() {
35978
36357
  if (cachedDevNullReadFd === void 0) {
35979
36358
  const devPath = process.platform === "win32" ? "nul" : "/dev/null";
35980
- cachedDevNullReadFd = fs23.openSync(devPath, "r");
36359
+ cachedDevNullReadFd = fs24.openSync(devPath, "r");
35981
36360
  }
35982
36361
  return cachedDevNullReadFd;
35983
36362
  }
@@ -36051,15 +36430,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
36051
36430
 
36052
36431
  // src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
36053
36432
  import { spawn as spawn6 } from "node:child_process";
36054
- import fs24 from "node:fs";
36433
+ import fs25 from "node:fs";
36055
36434
  import { tmpdir } from "node:os";
36056
- import path27 from "node:path";
36435
+ import path28 from "node:path";
36057
36436
  function trySpawnMergedLogFile(command, env, cwd, signal) {
36058
- const tmpRoot = fs24.mkdtempSync(path27.join(tmpdir(), "ba-devsrv-log-"));
36059
- const logPath = path27.join(tmpRoot, "combined.log");
36437
+ const tmpRoot = fs25.mkdtempSync(path28.join(tmpdir(), "ba-devsrv-log-"));
36438
+ const logPath = path28.join(tmpRoot, "combined.log");
36060
36439
  let logFd;
36061
36440
  try {
36062
- logFd = fs24.openSync(logPath, "a");
36441
+ logFd = fs25.openSync(logPath, "a");
36063
36442
  } catch {
36064
36443
  rmDirQuiet(tmpRoot);
36065
36444
  return null;
@@ -36078,7 +36457,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
36078
36457
  } else {
36079
36458
  proc = spawn6("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
36080
36459
  }
36081
- fs24.closeSync(logFd);
36460
+ fs25.closeSync(logFd);
36082
36461
  return {
36083
36462
  proc,
36084
36463
  pipedStdoutStderr: true,
@@ -36087,7 +36466,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
36087
36466
  };
36088
36467
  } catch (e) {
36089
36468
  try {
36090
- fs24.closeSync(logFd);
36469
+ fs25.closeSync(logFd);
36091
36470
  } catch {
36092
36471
  }
36093
36472
  rmDirQuiet(tmpRoot);
@@ -36098,22 +36477,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
36098
36477
 
36099
36478
  // src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
36100
36479
  import { spawn as spawn7 } from "node:child_process";
36101
- import fs25 from "node:fs";
36480
+ import fs26 from "node:fs";
36102
36481
  import { tmpdir as tmpdir2 } from "node:os";
36103
- import path28 from "node:path";
36482
+ import path29 from "node:path";
36104
36483
  function shSingleQuote(s) {
36105
36484
  return `'${s.replace(/'/g, `'\\''`)}'`;
36106
36485
  }
36107
36486
  function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
36108
- const tmpRoot = fs25.mkdtempSync(path28.join(tmpdir2(), "ba-devsrv-sh-"));
36109
- const logPath = path28.join(tmpRoot, "combined.log");
36110
- const innerPath = path28.join(tmpRoot, "_cmd.sh");
36111
- const runnerPath = path28.join(tmpRoot, "_run.sh");
36487
+ const tmpRoot = fs26.mkdtempSync(path29.join(tmpdir2(), "ba-devsrv-sh-"));
36488
+ const logPath = path29.join(tmpRoot, "combined.log");
36489
+ const innerPath = path29.join(tmpRoot, "_cmd.sh");
36490
+ const runnerPath = path29.join(tmpRoot, "_run.sh");
36112
36491
  try {
36113
- fs25.writeFileSync(innerPath, `#!/bin/sh
36492
+ fs26.writeFileSync(innerPath, `#!/bin/sh
36114
36493
  ${command}
36115
36494
  `);
36116
- fs25.writeFileSync(
36495
+ fs26.writeFileSync(
36117
36496
  runnerPath,
36118
36497
  `#!/bin/sh
36119
36498
  cd ${shSingleQuote(cwd)}
@@ -36139,13 +36518,13 @@ cd ${shSingleQuote(cwd)}
36139
36518
  }
36140
36519
  }
36141
36520
  function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
36142
- const tmpRoot = fs25.mkdtempSync(path28.join(tmpdir2(), "ba-devsrv-sh-"));
36143
- const logPath = path28.join(tmpRoot, "combined.log");
36144
- const runnerPath = path28.join(tmpRoot, "_run.bat");
36521
+ const tmpRoot = fs26.mkdtempSync(path29.join(tmpdir2(), "ba-devsrv-sh-"));
36522
+ const logPath = path29.join(tmpRoot, "combined.log");
36523
+ const runnerPath = path29.join(tmpRoot, "_run.bat");
36145
36524
  const q = (p) => `"${p.replace(/"/g, '""')}"`;
36146
36525
  const com = process.env.ComSpec || "cmd.exe";
36147
36526
  try {
36148
- fs25.writeFileSync(
36527
+ fs26.writeFileSync(
36149
36528
  runnerPath,
36150
36529
  `@ECHO OFF\r
36151
36530
  CD /D ${q(cwd)}\r
@@ -37082,30 +37461,30 @@ function createOnBridgeIdentified(opts) {
37082
37461
  }
37083
37462
 
37084
37463
  // src/skills/discover-local-agent-skills.ts
37085
- import fs26 from "node:fs";
37086
- import path29 from "node:path";
37464
+ import fs27 from "node:fs";
37465
+ import path30 from "node:path";
37087
37466
  var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
37088
37467
  function discoverLocalSkills(cwd) {
37089
37468
  const out = [];
37090
37469
  const seenKeys = /* @__PURE__ */ new Set();
37091
37470
  for (const rel of SKILL_DISCOVERY_ROOTS) {
37092
- const base = path29.join(cwd, rel);
37093
- if (!fs26.existsSync(base) || !fs26.statSync(base).isDirectory()) continue;
37471
+ const base = path30.join(cwd, rel);
37472
+ if (!fs27.existsSync(base) || !fs27.statSync(base).isDirectory()) continue;
37094
37473
  let entries = [];
37095
37474
  try {
37096
- entries = fs26.readdirSync(base);
37475
+ entries = fs27.readdirSync(base);
37097
37476
  } catch {
37098
37477
  continue;
37099
37478
  }
37100
37479
  for (const name of entries) {
37101
- const dir = path29.join(base, name);
37480
+ const dir = path30.join(base, name);
37102
37481
  try {
37103
- if (!fs26.statSync(dir).isDirectory()) continue;
37482
+ if (!fs27.statSync(dir).isDirectory()) continue;
37104
37483
  } catch {
37105
37484
  continue;
37106
37485
  }
37107
- const skillMd = path29.join(dir, "SKILL.md");
37108
- if (!fs26.existsSync(skillMd)) continue;
37486
+ const skillMd = path30.join(dir, "SKILL.md");
37487
+ if (!fs27.existsSync(skillMd)) continue;
37109
37488
  const key = `${rel}/${name}`;
37110
37489
  if (seenKeys.has(key)) continue;
37111
37490
  seenKeys.add(key);
@@ -37117,23 +37496,23 @@ function discoverLocalSkills(cwd) {
37117
37496
  function discoverSkillLayoutRoots(cwd) {
37118
37497
  const roots = [];
37119
37498
  for (const rel of SKILL_DISCOVERY_ROOTS) {
37120
- const base = path29.join(cwd, rel);
37121
- if (!fs26.existsSync(base) || !fs26.statSync(base).isDirectory()) continue;
37499
+ const base = path30.join(cwd, rel);
37500
+ if (!fs27.existsSync(base) || !fs27.statSync(base).isDirectory()) continue;
37122
37501
  let entries = [];
37123
37502
  try {
37124
- entries = fs26.readdirSync(base);
37503
+ entries = fs27.readdirSync(base);
37125
37504
  } catch {
37126
37505
  continue;
37127
37506
  }
37128
37507
  const skills2 = [];
37129
37508
  for (const name of entries) {
37130
- const dir = path29.join(base, name);
37509
+ const dir = path30.join(base, name);
37131
37510
  try {
37132
- if (!fs26.statSync(dir).isDirectory()) continue;
37511
+ if (!fs27.statSync(dir).isDirectory()) continue;
37133
37512
  } catch {
37134
37513
  continue;
37135
37514
  }
37136
- if (!fs26.existsSync(path29.join(dir, "SKILL.md"))) continue;
37515
+ if (!fs27.existsSync(path30.join(dir, "SKILL.md"))) continue;
37137
37516
  const relPath = `${rel}/${name}`.replace(/\\/g, "/");
37138
37517
  skills2.push({ name, relPath });
37139
37518
  }
@@ -37315,7 +37694,7 @@ var handleAgentConfigMessage = (msg, deps) => {
37315
37694
  };
37316
37695
 
37317
37696
  // src/prompt-turn-queue/runner.ts
37318
- import fs29 from "node:fs";
37697
+ import fs30 from "node:fs";
37319
37698
 
37320
37699
  // src/prompt-turn-queue/client-report.ts
37321
37700
  function sendPromptQueueClientReport(ws, queues) {
@@ -37325,13 +37704,13 @@ function sendPromptQueueClientReport(ws, queues) {
37325
37704
  }
37326
37705
 
37327
37706
  // src/prompt-turn-queue/disk-store.ts
37328
- import fs28 from "node:fs";
37707
+ import fs29 from "node:fs";
37329
37708
 
37330
37709
  // src/prompt-turn-queue/paths.ts
37331
37710
  import crypto3 from "node:crypto";
37332
- import fs27 from "node:fs";
37333
- import path30 from "node:path";
37334
- import os6 from "node:os";
37711
+ import fs28 from "node:fs";
37712
+ import path31 from "node:path";
37713
+ import os7 from "node:os";
37335
37714
  var QUEUE_KEY_HEX_64 = /^[a-f0-9]{64}$/i;
37336
37715
  function queueStateFileSlug(queueKey) {
37337
37716
  if (QUEUE_KEY_HEX_64.test(queueKey)) return queueKey.toLowerCase();
@@ -37339,15 +37718,15 @@ function queueStateFileSlug(queueKey) {
37339
37718
  }
37340
37719
  function getPromptQueuesDirectory() {
37341
37720
  const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
37342
- if (override) return path30.resolve(override);
37343
- return path30.join(os6.homedir(), ".buildautomaton", "queues");
37721
+ if (override) return path31.resolve(override);
37722
+ return path31.join(os7.homedir(), ".buildautomaton", "queues");
37344
37723
  }
37345
37724
  function ensurePromptQueuesDirectory() {
37346
37725
  const dir = getPromptQueuesDirectory();
37347
- if (!fs27.existsSync(dir)) fs27.mkdirSync(dir, { recursive: true });
37726
+ if (!fs28.existsSync(dir)) fs28.mkdirSync(dir, { recursive: true });
37348
37727
  }
37349
37728
  function queueStateFilePath(queueKey) {
37350
- return path30.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
37729
+ return path31.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
37351
37730
  }
37352
37731
 
37353
37732
  // src/prompt-turn-queue/disk-store.ts
@@ -37372,7 +37751,7 @@ function parsePersistedQueueFile(raw) {
37372
37751
  function readPersistedQueue(queueKey) {
37373
37752
  const p = queueStateFilePath(queueKey);
37374
37753
  try {
37375
- return parsePersistedQueueFile(fs28.readFileSync(p, "utf8"));
37754
+ return parsePersistedQueueFile(fs29.readFileSync(p, "utf8"));
37376
37755
  } catch {
37377
37756
  return null;
37378
37757
  }
@@ -37380,7 +37759,7 @@ function readPersistedQueue(queueKey) {
37380
37759
  function writePersistedQueue(file2) {
37381
37760
  ensurePromptQueuesDirectory();
37382
37761
  const p = queueStateFilePath(file2.queueKey);
37383
- fs28.writeFileSync(p, JSON.stringify(file2, null, 2), "utf8");
37762
+ fs29.writeFileSync(p, JSON.stringify(file2, null, 2), "utf8");
37384
37763
  }
37385
37764
  function mergeServerQueueSnapshot(queueKey, serverTurns) {
37386
37765
  const prev = readPersistedQueue(queueKey);
@@ -37438,7 +37817,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
37438
37817
  const tid = typeof pl.snapshotRevertTurnId === "string" && pl.snapshotRevertTurnId.trim() !== "" ? pl.snapshotRevertTurnId.trim() : next.turnId;
37439
37818
  const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
37440
37819
  const file2 = snapshotFilePath(agentBase, tid);
37441
- if (!fs29.existsSync(file2)) {
37820
+ if (!fs30.existsSync(file2)) {
37442
37821
  deps.log(
37443
37822
  `[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
37444
37823
  );
@@ -37661,9 +38040,9 @@ function parseChangeSummarySnapshots(raw) {
37661
38040
  for (const item of raw) {
37662
38041
  if (!item || typeof item !== "object") continue;
37663
38042
  const o = item;
37664
- const path36 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
37665
- if (!path36) continue;
37666
- const row = { path: path36 };
38043
+ const path37 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
38044
+ if (!path37) continue;
38045
+ const row = { path: path37 };
37667
38046
  if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
37668
38047
  if (typeof o.oldText === "string") row.oldText = o.oldText;
37669
38048
  if (typeof o.newText === "string") row.newText = o.newText;
@@ -37864,8 +38243,8 @@ function randomSecret() {
37864
38243
  }
37865
38244
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
37866
38245
  }
37867
- async function requestPreviewApi(port, secret, method, path36, body) {
37868
- const url2 = `http://127.0.0.1:${port}${path36}`;
38246
+ async function requestPreviewApi(port, secret, method, path37, body) {
38247
+ const url2 = `http://127.0.0.1:${port}${path37}`;
37869
38248
  const headers = {
37870
38249
  [PREVIEW_SECRET_HEADER]: secret,
37871
38250
  "Content-Type": "application/json"
@@ -37877,7 +38256,7 @@ async function requestPreviewApi(port, secret, method, path36, body) {
37877
38256
  });
37878
38257
  const data = await res.json().catch(() => ({}));
37879
38258
  if (!res.ok) {
37880
- throw new Error(data?.error ?? `Preview API ${method} ${path36}: ${res.status}`);
38259
+ throw new Error(data?.error ?? `Preview API ${method} ${path37}: ${res.status}`);
37881
38260
  }
37882
38261
  return data;
37883
38262
  }
@@ -38042,15 +38421,15 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
38042
38421
  };
38043
38422
 
38044
38423
  // src/files/list-dir.ts
38045
- import fs30 from "node:fs";
38046
- import path32 from "node:path";
38424
+ import fs31 from "node:fs";
38425
+ import path33 from "node:path";
38047
38426
 
38048
38427
  // src/files/ensure-under-cwd.ts
38049
- import path31 from "node:path";
38428
+ import path32 from "node:path";
38050
38429
  function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
38051
- const normalized = path31.normalize(relativePath).replace(/^(\.\/)+/, "");
38052
- const resolved = path31.resolve(cwd, normalized);
38053
- if (!resolved.startsWith(cwd + path31.sep) && resolved !== cwd) {
38430
+ const normalized = path32.normalize(relativePath).replace(/^(\.\/)+/, "");
38431
+ const resolved = path32.resolve(cwd, normalized);
38432
+ if (!resolved.startsWith(cwd + path32.sep) && resolved !== cwd) {
38054
38433
  return null;
38055
38434
  }
38056
38435
  return resolved;
@@ -38064,7 +38443,7 @@ async function listDirAsync(relativePath) {
38064
38443
  return { error: "Path is outside working directory" };
38065
38444
  }
38066
38445
  try {
38067
- const names = await fs30.promises.readdir(resolved, { withFileTypes: true });
38446
+ const names = await fs31.promises.readdir(resolved, { withFileTypes: true });
38068
38447
  const visible = names.filter((d) => !d.name.startsWith("."));
38069
38448
  const entries = [];
38070
38449
  for (let i = 0; i < visible.length; i++) {
@@ -38072,12 +38451,12 @@ async function listDirAsync(relativePath) {
38072
38451
  await yieldToEventLoop();
38073
38452
  }
38074
38453
  const d = visible[i];
38075
- const entryPath = path32.join(relativePath || ".", d.name).replace(/\\/g, "/");
38076
- const fullPath = path32.join(resolved, d.name);
38454
+ const entryPath = path33.join(relativePath || ".", d.name).replace(/\\/g, "/");
38455
+ const fullPath = path33.join(resolved, d.name);
38077
38456
  let isDir = d.isDirectory();
38078
38457
  if (d.isSymbolicLink()) {
38079
38458
  try {
38080
- const targetStat = await fs30.promises.stat(fullPath);
38459
+ const targetStat = await fs31.promises.stat(fullPath);
38081
38460
  isDir = targetStat.isDirectory();
38082
38461
  } catch {
38083
38462
  isDir = false;
@@ -38102,25 +38481,25 @@ async function listDirAsync(relativePath) {
38102
38481
  }
38103
38482
 
38104
38483
  // src/files/read-file.ts
38105
- import fs31 from "node:fs";
38484
+ import fs32 from "node:fs";
38106
38485
  import { StringDecoder } from "node:string_decoder";
38107
38486
  function resolveFilePath(relativePath) {
38108
38487
  const resolved = ensureUnderCwd(relativePath, getBridgeRoot());
38109
38488
  if (!resolved) return { error: "Path is outside working directory" };
38110
38489
  let real;
38111
38490
  try {
38112
- real = fs31.realpathSync(resolved);
38491
+ real = fs32.realpathSync(resolved);
38113
38492
  } catch {
38114
38493
  real = resolved;
38115
38494
  }
38116
- const stat3 = fs31.statSync(real);
38495
+ const stat3 = fs32.statSync(real);
38117
38496
  if (!stat3.isFile()) return { error: "Not a file" };
38118
38497
  return real;
38119
38498
  }
38120
38499
  var LINE_CHUNK_SIZE = 64 * 1024;
38121
38500
  function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
38122
- const fileSize = fs31.statSync(filePath).size;
38123
- const fd = fs31.openSync(filePath, "r");
38501
+ const fileSize = fs32.statSync(filePath).size;
38502
+ const fd = fs32.openSync(filePath, "r");
38124
38503
  const bufSize = 64 * 1024;
38125
38504
  const buf = Buffer.alloc(bufSize);
38126
38505
  const decoder = new StringDecoder("utf8");
@@ -38133,7 +38512,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
38133
38512
  let line0Accum = "";
38134
38513
  try {
38135
38514
  let bytesRead;
38136
- while (!done && (bytesRead = fs31.readSync(fd, buf, 0, bufSize, null)) > 0) {
38515
+ while (!done && (bytesRead = fs32.readSync(fd, buf, 0, bufSize, null)) > 0) {
38137
38516
  const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
38138
38517
  partial2 = "";
38139
38518
  let lineStart = 0;
@@ -38268,7 +38647,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
38268
38647
  }
38269
38648
  return { content: resultLines.join("\n"), size: fileSize };
38270
38649
  } finally {
38271
- fs31.closeSync(fd);
38650
+ fs32.closeSync(fd);
38272
38651
  }
38273
38652
  }
38274
38653
  function readFile3(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
@@ -38279,8 +38658,8 @@ function readFile3(relativePath, startLine, endLine, lineOffset, lineChunkSize =
38279
38658
  if (hasRange) {
38280
38659
  return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
38281
38660
  }
38282
- const stat3 = fs31.statSync(result);
38283
- const raw = fs31.readFileSync(result, "utf8");
38661
+ const stat3 = fs32.statSync(result);
38662
+ const raw = fs32.readFileSync(result, "utf8");
38284
38663
  const lines = raw.split(/\r?\n/);
38285
38664
  return { content: raw, totalLines: lines.length, size: stat3.size };
38286
38665
  } catch (err) {
@@ -38398,8 +38777,8 @@ function handleSkillLayoutRequest(msg, deps) {
38398
38777
  }
38399
38778
 
38400
38779
  // src/skills/install-remote-skills.ts
38401
- import fs32 from "node:fs";
38402
- import path33 from "node:path";
38780
+ import fs33 from "node:fs";
38781
+ import path34 from "node:path";
38403
38782
  function installRemoteSkills(cwd, targetDir, items) {
38404
38783
  const installed2 = [];
38405
38784
  if (!Array.isArray(items)) {
@@ -38410,15 +38789,15 @@ function installRemoteSkills(cwd, targetDir, items) {
38410
38789
  if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
38411
38790
  continue;
38412
38791
  }
38413
- const skillDir = path33.join(cwd, targetDir, item.skillName);
38792
+ const skillDir = path34.join(cwd, targetDir, item.skillName);
38414
38793
  for (const f of item.files) {
38415
38794
  if (typeof f.path !== "string" || !f.text && !f.base64) continue;
38416
- const dest = path33.join(skillDir, f.path);
38417
- fs32.mkdirSync(path33.dirname(dest), { recursive: true });
38795
+ const dest = path34.join(skillDir, f.path);
38796
+ fs33.mkdirSync(path34.dirname(dest), { recursive: true });
38418
38797
  if (f.text !== void 0) {
38419
- fs32.writeFileSync(dest, f.text, "utf8");
38798
+ fs33.writeFileSync(dest, f.text, "utf8");
38420
38799
  } else if (f.base64) {
38421
- fs32.writeFileSync(dest, Buffer.from(f.base64, "base64"));
38800
+ fs33.writeFileSync(dest, Buffer.from(f.base64, "base64"));
38422
38801
  }
38423
38802
  }
38424
38803
  installed2.push({
@@ -38568,7 +38947,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
38568
38947
  };
38569
38948
 
38570
38949
  // src/routing/handlers/revert-turn-snapshot.ts
38571
- import * as fs33 from "node:fs";
38950
+ import * as fs34 from "node:fs";
38572
38951
  var handleRevertTurnSnapshotMessage = (msg, deps) => {
38573
38952
  const id = typeof msg.id === "string" ? msg.id : "";
38574
38953
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
@@ -38580,7 +38959,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
38580
38959
  if (!s) return;
38581
38960
  const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
38582
38961
  const file2 = snapshotFilePath(agentBase, turnId);
38583
- if (!fs33.existsSync(file2)) {
38962
+ if (!fs34.existsSync(file2)) {
38584
38963
  sendWsMessage(s, {
38585
38964
  type: "revert_turn_snapshot_result",
38586
38965
  id,
@@ -38953,8 +39332,8 @@ async function createBridgeConnection(options) {
38953
39332
  getCloudAccessToken: () => tokens.accessToken
38954
39333
  };
38955
39334
  const identifyReportedPaths = {
38956
- bridgeRootPath: path34.resolve(getBridgeRoot()),
38957
- worktreesRootPath: path34.resolve(worktreesRootPath)
39335
+ bridgeRootPath: path35.resolve(getBridgeRoot()),
39336
+ worktreesRootPath: path35.resolve(worktreesRootPath)
38958
39337
  };
38959
39338
  const { connect } = createMainBridgeWebSocketLifecycle({
38960
39339
  state,
@@ -39190,9 +39569,9 @@ async function runCliAction(program2, opts) {
39190
39569
  const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
39191
39570
  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);
39192
39571
  if (bridgeRootOpt) {
39193
- const resolvedBridgeRoot = path35.resolve(process.cwd(), bridgeRootOpt);
39572
+ const resolvedBridgeRoot = path36.resolve(process.cwd(), bridgeRootOpt);
39194
39573
  try {
39195
- const st = fs34.statSync(resolvedBridgeRoot);
39574
+ const st = fs35.statSync(resolvedBridgeRoot);
39196
39575
  if (!st.isDirectory()) {
39197
39576
  console.error(`Bridge root is not a directory: ${resolvedBridgeRoot}`);
39198
39577
  process.exit(1);
@@ -39212,7 +39591,7 @@ async function runCliAction(program2, opts) {
39212
39591
  );
39213
39592
  let worktreesRootPath;
39214
39593
  if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
39215
- worktreesRootPath = path35.resolve(opts.worktreesRoot.trim());
39594
+ worktreesRootPath = path36.resolve(opts.worktreesRoot.trim());
39216
39595
  }
39217
39596
  const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
39218
39597
  if (e2eCertificates) {