@buildautomaton/cli 0.1.57 → 0.1.59

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,7 +973,7 @@ 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 path75 = __require("node:path");
976
+ var path76 = __require("node:path");
977
977
  var fs53 = __require("node:fs");
978
978
  var process8 = __require("node:process");
979
979
  var { Argument: Argument2, humanReadableArgName } = require_argument();
@@ -1906,9 +1906,9 @@ 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 = path75.resolve(baseDir, baseName);
1909
+ const localBin = path76.resolve(baseDir, baseName);
1910
1910
  if (fs53.existsSync(localBin)) return localBin;
1911
- if (sourceExt.includes(path75.extname(baseName))) return void 0;
1911
+ if (sourceExt.includes(path76.extname(baseName))) return void 0;
1912
1912
  const foundExt = sourceExt.find(
1913
1913
  (ext) => fs53.existsSync(`${localBin}${ext}`)
1914
1914
  );
@@ -1926,17 +1926,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
1926
1926
  } catch (err) {
1927
1927
  resolvedScriptPath = this._scriptPath;
1928
1928
  }
1929
- executableDir = path75.resolve(
1930
- path75.dirname(resolvedScriptPath),
1929
+ executableDir = path76.resolve(
1930
+ path76.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 = path75.basename(
1937
+ const legacyName = path76.basename(
1938
1938
  this._scriptPath,
1939
- path75.extname(this._scriptPath)
1939
+ path76.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(path75.extname(executableFile));
1950
+ launchWithNode = sourceExt.includes(path76.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 = path75.basename(filename, path75.extname(filename));
2790
+ this._name = path76.basename(filename, path76.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(path76) {
2805
- if (path76 === void 0) return this._executableDir;
2806
- this._executableDir = path76;
2804
+ executableDir(path77) {
2805
+ if (path77 === void 0) return this._executableDir;
2806
+ this._executableDir = path77;
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: path75, errorMaps, issueData } = params;
7065
- const fullPath = [...path75, ...issueData.path || []];
7064
+ const { data, path: path76, errorMaps, issueData } = params;
7065
+ const fullPath = [...path76, ...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, path75, key) {
7373
+ constructor(parent, value, path76, key) {
7374
7374
  this._cachedPath = [];
7375
7375
  this.parent = parent;
7376
7376
  this.data = value;
7377
- this._path = path75;
7377
+ this._path = path76;
7378
7378
  this._key = key;
7379
7379
  }
7380
7380
  get path() {
@@ -11099,10 +11099,10 @@ function assignProp(target, prop, value) {
11099
11099
  configurable: true
11100
11100
  });
11101
11101
  }
11102
- function getElementAtPath(obj, path75) {
11103
- if (!path75)
11102
+ function getElementAtPath(obj, path76) {
11103
+ if (!path76)
11104
11104
  return obj;
11105
- return path75.reduce((acc, key) => acc?.[key], obj);
11105
+ return path76.reduce((acc, key) => acc?.[key], obj);
11106
11106
  }
11107
11107
  function promiseAllObject(promisesObj) {
11108
11108
  const keys = Object.keys(promisesObj);
@@ -11351,11 +11351,11 @@ function aborted(x, startIndex = 0) {
11351
11351
  }
11352
11352
  return false;
11353
11353
  }
11354
- function prefixIssues(path75, issues) {
11354
+ function prefixIssues(path76, issues) {
11355
11355
  return issues.map((iss) => {
11356
11356
  var _a2;
11357
11357
  (_a2 = iss).path ?? (_a2.path = []);
11358
- iss.path.unshift(path75);
11358
+ iss.path.unshift(path76);
11359
11359
  return iss;
11360
11360
  });
11361
11361
  }
@@ -11544,7 +11544,7 @@ function treeifyError(error40, _mapper) {
11544
11544
  return issue2.message;
11545
11545
  };
11546
11546
  const result = { errors: [] };
11547
- const processError = (error41, path75 = []) => {
11547
+ const processError = (error41, path76 = []) => {
11548
11548
  var _a2, _b;
11549
11549
  for (const issue2 of error41.issues) {
11550
11550
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -11554,7 +11554,7 @@ function treeifyError(error40, _mapper) {
11554
11554
  } else if (issue2.code === "invalid_element") {
11555
11555
  processError({ issues: issue2.issues }, issue2.path);
11556
11556
  } else {
11557
- const fullpath = [...path75, ...issue2.path];
11557
+ const fullpath = [...path76, ...issue2.path];
11558
11558
  if (fullpath.length === 0) {
11559
11559
  result.errors.push(mapper(issue2));
11560
11560
  continue;
@@ -11584,9 +11584,9 @@ function treeifyError(error40, _mapper) {
11584
11584
  processError(error40);
11585
11585
  return result;
11586
11586
  }
11587
- function toDotPath(path75) {
11587
+ function toDotPath(path76) {
11588
11588
  const segs = [];
11589
- for (const seg of path75) {
11589
+ for (const seg of path76) {
11590
11590
  if (typeof seg === "number")
11591
11591
  segs.push(`[${seg}]`);
11592
11592
  else if (typeof seg === "symbol")
@@ -24592,7 +24592,7 @@ var require_ignore = __commonJS({
24592
24592
  // path matching.
24593
24593
  // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
24594
24594
  // @returns {TestResult} true if a file is ignored
24595
- test(path75, checkUnignored, mode) {
24595
+ test(path76, checkUnignored, mode) {
24596
24596
  let ignored = false;
24597
24597
  let unignored = false;
24598
24598
  let matchedRule;
@@ -24601,7 +24601,7 @@ var require_ignore = __commonJS({
24601
24601
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
24602
24602
  return;
24603
24603
  }
24604
- const matched = rule[mode].test(path75);
24604
+ const matched = rule[mode].test(path76);
24605
24605
  if (!matched) {
24606
24606
  return;
24607
24607
  }
@@ -24622,17 +24622,17 @@ var require_ignore = __commonJS({
24622
24622
  var throwError = (message, Ctor) => {
24623
24623
  throw new Ctor(message);
24624
24624
  };
24625
- var checkPath = (path75, originalPath, doThrow) => {
24626
- if (!isString(path75)) {
24625
+ var checkPath = (path76, originalPath, doThrow) => {
24626
+ if (!isString(path76)) {
24627
24627
  return doThrow(
24628
24628
  `path must be a string, but got \`${originalPath}\``,
24629
24629
  TypeError
24630
24630
  );
24631
24631
  }
24632
- if (!path75) {
24632
+ if (!path76) {
24633
24633
  return doThrow(`path must not be empty`, TypeError);
24634
24634
  }
24635
- if (checkPath.isNotRelative(path75)) {
24635
+ if (checkPath.isNotRelative(path76)) {
24636
24636
  const r = "`path.relative()`d";
24637
24637
  return doThrow(
24638
24638
  `path should be a ${r} string, but got "${originalPath}"`,
@@ -24641,7 +24641,7 @@ var require_ignore = __commonJS({
24641
24641
  }
24642
24642
  return true;
24643
24643
  };
24644
- var isNotRelative = (path75) => REGEX_TEST_INVALID_PATH.test(path75);
24644
+ var isNotRelative = (path76) => REGEX_TEST_INVALID_PATH.test(path76);
24645
24645
  checkPath.isNotRelative = isNotRelative;
24646
24646
  checkPath.convert = (p) => p;
24647
24647
  var Ignore = class {
@@ -24671,19 +24671,19 @@ var require_ignore = __commonJS({
24671
24671
  }
24672
24672
  // @returns {TestResult}
24673
24673
  _test(originalPath, cache2, checkUnignored, slices) {
24674
- const path75 = originalPath && checkPath.convert(originalPath);
24674
+ const path76 = originalPath && checkPath.convert(originalPath);
24675
24675
  checkPath(
24676
- path75,
24676
+ path76,
24677
24677
  originalPath,
24678
24678
  this._strictPathCheck ? throwError : RETURN_FALSE
24679
24679
  );
24680
- return this._t(path75, cache2, checkUnignored, slices);
24680
+ return this._t(path76, cache2, checkUnignored, slices);
24681
24681
  }
24682
- checkIgnore(path75) {
24683
- if (!REGEX_TEST_TRAILING_SLASH.test(path75)) {
24684
- return this.test(path75);
24682
+ checkIgnore(path76) {
24683
+ if (!REGEX_TEST_TRAILING_SLASH.test(path76)) {
24684
+ return this.test(path76);
24685
24685
  }
24686
- const slices = path75.split(SLASH).filter(Boolean);
24686
+ const slices = path76.split(SLASH).filter(Boolean);
24687
24687
  slices.pop();
24688
24688
  if (slices.length) {
24689
24689
  const parent = this._t(
@@ -24696,18 +24696,18 @@ var require_ignore = __commonJS({
24696
24696
  return parent;
24697
24697
  }
24698
24698
  }
24699
- return this._rules.test(path75, false, MODE_CHECK_IGNORE);
24699
+ return this._rules.test(path76, false, MODE_CHECK_IGNORE);
24700
24700
  }
24701
- _t(path75, cache2, checkUnignored, slices) {
24702
- if (path75 in cache2) {
24703
- return cache2[path75];
24701
+ _t(path76, cache2, checkUnignored, slices) {
24702
+ if (path76 in cache2) {
24703
+ return cache2[path76];
24704
24704
  }
24705
24705
  if (!slices) {
24706
- slices = path75.split(SLASH).filter(Boolean);
24706
+ slices = path76.split(SLASH).filter(Boolean);
24707
24707
  }
24708
24708
  slices.pop();
24709
24709
  if (!slices.length) {
24710
- return cache2[path75] = this._rules.test(path75, checkUnignored, MODE_IGNORE);
24710
+ return cache2[path76] = this._rules.test(path76, checkUnignored, MODE_IGNORE);
24711
24711
  }
24712
24712
  const parent = this._t(
24713
24713
  slices.join(SLASH) + SLASH,
@@ -24715,29 +24715,29 @@ var require_ignore = __commonJS({
24715
24715
  checkUnignored,
24716
24716
  slices
24717
24717
  );
24718
- return cache2[path75] = parent.ignored ? parent : this._rules.test(path75, checkUnignored, MODE_IGNORE);
24718
+ return cache2[path76] = parent.ignored ? parent : this._rules.test(path76, checkUnignored, MODE_IGNORE);
24719
24719
  }
24720
- ignores(path75) {
24721
- return this._test(path75, this._ignoreCache, false).ignored;
24720
+ ignores(path76) {
24721
+ return this._test(path76, this._ignoreCache, false).ignored;
24722
24722
  }
24723
24723
  createFilter() {
24724
- return (path75) => !this.ignores(path75);
24724
+ return (path76) => !this.ignores(path76);
24725
24725
  }
24726
24726
  filter(paths) {
24727
24727
  return makeArray(paths).filter(this.createFilter());
24728
24728
  }
24729
24729
  // @returns {TestResult}
24730
- test(path75) {
24731
- return this._test(path75, this._testCache, true);
24730
+ test(path76) {
24731
+ return this._test(path76, this._testCache, true);
24732
24732
  }
24733
24733
  };
24734
24734
  var factory = (options) => new Ignore(options);
24735
- var isPathValid = (path75) => checkPath(path75 && checkPath.convert(path75), path75, RETURN_FALSE);
24735
+ var isPathValid = (path76) => checkPath(path76 && checkPath.convert(path76), path76, RETURN_FALSE);
24736
24736
  var setupWindows = () => {
24737
24737
  const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
24738
24738
  checkPath.convert = makePosix;
24739
24739
  const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
24740
- checkPath.isNotRelative = (path75) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path75) || isNotRelative(path75);
24740
+ checkPath.isNotRelative = (path76) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path76) || isNotRelative(path76);
24741
24741
  };
24742
24742
  if (
24743
24743
  // Detect `process` so that it can run in browsers.
@@ -25526,10 +25526,10 @@ var require_src2 = __commonJS({
25526
25526
  var fs_1 = __require("fs");
25527
25527
  var debug_1 = __importDefault(require_src());
25528
25528
  var log2 = debug_1.default("@kwsites/file-exists");
25529
- function check2(path75, isFile, isDirectory) {
25530
- log2(`checking %s`, path75);
25529
+ function check2(path76, isFile, isDirectory) {
25530
+ log2(`checking %s`, path76);
25531
25531
  try {
25532
- const stat3 = fs_1.statSync(path75);
25532
+ const stat3 = fs_1.statSync(path76);
25533
25533
  if (stat3.isFile() && isFile) {
25534
25534
  log2(`[OK] path represents a file`);
25535
25535
  return true;
@@ -25549,8 +25549,8 @@ var require_src2 = __commonJS({
25549
25549
  throw e;
25550
25550
  }
25551
25551
  }
25552
- function exists2(path75, type = exports.READABLE) {
25553
- return check2(path75, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
25552
+ function exists2(path76, type = exports.READABLE) {
25553
+ return check2(path76, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
25554
25554
  }
25555
25555
  exports.exists = exists2;
25556
25556
  exports.FILE = 1;
@@ -25631,7 +25631,7 @@ var {
25631
25631
  } = import_index.default;
25632
25632
 
25633
25633
  // src/cli-version.ts
25634
- var CLI_VERSION = "0.1.57".length > 0 ? "0.1.57" : "0.0.0-dev";
25634
+ var CLI_VERSION = "0.1.59".length > 0 ? "0.1.59" : "0.0.0-dev";
25635
25635
 
25636
25636
  // src/cli/defaults.ts
25637
25637
  var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
@@ -25639,7 +25639,7 @@ var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
25639
25639
 
25640
25640
  // src/cli/run-cli-action.ts
25641
25641
  import * as fs52 from "node:fs";
25642
- import * as path74 from "node:path";
25642
+ import * as path75 from "node:path";
25643
25643
 
25644
25644
  // src/cli-log-level.ts
25645
25645
  var verbosity = "info";
@@ -27859,7 +27859,7 @@ function readMigrationSql(filename, ...searchSubdirs) {
27859
27859
  join2(moduleDir, "..", sub, filename),
27860
27860
  join2(moduleDir, "..", "..", "dist", sub, filename)
27861
27861
  ]);
27862
- const resolved = candidates.find((path75) => existsSync(path75));
27862
+ const resolved = candidates.find((path76) => existsSync(path76));
27863
27863
  if (!resolved) {
27864
27864
  throw new Error(`Missing SQLite migration SQL: ${filename} (searched ${searchSubdirs.join(", ")})`);
27865
27865
  }
@@ -28757,6 +28757,81 @@ function isUserEndedSessionTurnErrorText(errorText) {
28757
28757
  // ../types/src/session-kind.ts
28758
28758
  var SESSION_KINDS = ["regular", "planning", "planned"];
28759
28759
  var SESSION_KIND_SET = new Set(SESSION_KINDS);
28760
+ function parseSessionKind(raw) {
28761
+ if (raw === "todo") return "planned";
28762
+ if (typeof raw === "string" && SESSION_KIND_SET.has(raw)) return raw;
28763
+ return "regular";
28764
+ }
28765
+
28766
+ // ../types/src/planning-todo.ts
28767
+ function planningTodoTitle(item) {
28768
+ return item.content.title;
28769
+ }
28770
+
28771
+ // ../types/src/parse-planning-todo-agent-json.ts
28772
+ function parsePlanningTodoAgentJson(raw) {
28773
+ if (raw == null || raw.trim() === "") return [];
28774
+ let text = raw.trim();
28775
+ const fence = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
28776
+ if (fence?.[1]) text = fence[1].trim();
28777
+ let parsed;
28778
+ try {
28779
+ parsed = JSON.parse(text);
28780
+ } catch {
28781
+ const start = text.indexOf("[");
28782
+ const end = text.lastIndexOf("]");
28783
+ if (start < 0 || end <= start) return [];
28784
+ try {
28785
+ parsed = JSON.parse(text.slice(start, end + 1));
28786
+ } catch {
28787
+ return [];
28788
+ }
28789
+ }
28790
+ if (!Array.isArray(parsed)) return [];
28791
+ const rows = [];
28792
+ for (const item of parsed) {
28793
+ if (!item || typeof item !== "object" || Array.isArray(item)) continue;
28794
+ const o = item;
28795
+ const title = typeof o.title === "string" ? o.title.trim() : "";
28796
+ const prompt = typeof o.prompt === "string" ? o.prompt.trim() : typeof o.promptText === "string" ? o.promptText.trim() : "";
28797
+ if (!title || !prompt) continue;
28798
+ rows.push({ title, prompt });
28799
+ }
28800
+ return rows;
28801
+ }
28802
+
28803
+ // ../types/src/build-planning-session-agent-prompt.ts
28804
+ var PLANNING_INSTRUCTIONS = [
28805
+ "PLANNING MODE: You must NOT make any changes to the codebase, filesystem, or environment.",
28806
+ "Do not run tools that modify files or execute commands that change state.",
28807
+ "Your only task is to analyze and produce a plan.",
28808
+ "",
28809
+ "Respond with ONLY a single JSON array \u2014 no markdown fences, no other text before or after.",
28810
+ "Each array element must be an object with exactly:",
28811
+ '- "title": a one-line summary of the task',
28812
+ '- "prompt": the full prompt to use when creating a new draft session from this todo',
28813
+ "",
28814
+ "Example:",
28815
+ '[{"title":"Add user login","prompt":"Implement a login form with email and password..."}]'
28816
+ ].join("\n");
28817
+ function buildPlanningSessionAgentPrompt(userPrompt) {
28818
+ return [PLANNING_INSTRUCTIONS, "", "User request:", userPrompt.trim()].join("\n");
28819
+ }
28820
+ function buildPlanningSessionFollowUpAgentPrompt(userPrompt, existingTodos) {
28821
+ const todoLines = existingTodos.length > 0 ? existingTodos.map((t) => {
28822
+ const status = t.plannedSessionId ? "DONE (draft session already created)" : "OPEN";
28823
+ return `- [${status}] ${planningTodoTitle(t)}`;
28824
+ }).join("\n") : "(none yet)";
28825
+ return [
28826
+ PLANNING_INSTRUCTIONS,
28827
+ "",
28828
+ "Existing todo items from this planning session (consider these when responding; do not duplicate completed items):",
28829
+ todoLines,
28830
+ "",
28831
+ "User follow-up:",
28832
+ userPrompt.trim()
28833
+ ].join("\n");
28834
+ }
28760
28835
 
28761
28836
  // ../types/src/change-summary-path.ts
28762
28837
  function normalizeRepoRelativePath(p) {
@@ -28813,9 +28888,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
28813
28888
  const rawPath = typeof o.path === "string" ? o.path.trim() : "";
28814
28889
  const summary = typeof o.summary === "string" ? o.summary.trim() : "";
28815
28890
  if (!rawPath || !summary) continue;
28816
- const path75 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
28817
- if (!path75) continue;
28818
- rows.push({ path: path75, summary: clampSummaryToAtMostTwoLines(summary) });
28891
+ const path76 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
28892
+ if (!path76) continue;
28893
+ rows.push({ path: path76, summary: clampSummaryToAtMostTwoLines(summary) });
28819
28894
  }
28820
28895
  return rows;
28821
28896
  }
@@ -29140,6 +29215,19 @@ function buildCliAutoApprovedPermissionRpcResult(requestParams) {
29140
29215
  };
29141
29216
  }
29142
29217
 
29218
+ // ../types/src/acp-agent-text-stream-bucket.ts
29219
+ function resolveAgentTextStreamBucket(params) {
29220
+ const k = params.transcriptRowKind;
29221
+ const su = params.sessionUpdate;
29222
+ if (k === "agent_thought_chunk" || su === "agent_thought_chunk" || k === "thinking" || su === "thinking") {
29223
+ return "thought";
29224
+ }
29225
+ if (k === "agent_message_chunk" || su === "agent_message_chunk" || k === "update" || su === "update") {
29226
+ return "message";
29227
+ }
29228
+ return null;
29229
+ }
29230
+
29143
29231
  // ../types/src/agent-config.ts
29144
29232
  var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
29145
29233
  var AGENT_CONFIG_CLI_PERMISSION_MODE_KEY = "cli_permission_mode";
@@ -34109,176 +34197,6 @@ function createBridgeOnRequest(opts) {
34109
34197
  };
34110
34198
  }
34111
34199
 
34112
- // src/agents/acp/hooks/extract-acp-file-diffs-from-update/paths-and-text.ts
34113
- import { fileURLToPath as fileURLToPath5 } from "node:url";
34114
- function readOptionalTextField(v) {
34115
- if (v === null || v === void 0) return "";
34116
- if (typeof v === "string") return v;
34117
- return "";
34118
- }
34119
- function normalizePathField(raw) {
34120
- const t = raw.trim();
34121
- if (t.startsWith("file://")) {
34122
- try {
34123
- return fileURLToPath5(t);
34124
- } catch {
34125
- return t;
34126
- }
34127
- }
34128
- return t;
34129
- }
34130
- function extractDiffPath(o) {
34131
- for (const k of ["path", "file", "filePath", "filepath", "target_path", "targetPath"]) {
34132
- const v = o[k];
34133
- if (typeof v === "string" && v.trim()) return normalizePathField(v);
34134
- }
34135
- return null;
34136
- }
34137
-
34138
- // src/agents/acp/hooks/extract-acp-file-diffs-from-update/push-diff.ts
34139
- function pushDiffIfComplete(o, sessionParentPath, out) {
34140
- const t = o.type;
34141
- if (typeof t !== "string" || t.toLowerCase() !== "diff") return;
34142
- const rawPath = extractDiffPath(o);
34143
- if (!rawPath) return;
34144
- const resolved = resolveWorkspaceFilePath(sessionParentPath, rawPath);
34145
- if (!resolved) return;
34146
- const oldText = readOptionalTextField(o.oldText ?? o.old_text ?? o.before ?? o.oldContent);
34147
- const newText = readOptionalTextField(o.newText ?? o.new_text ?? o.after ?? o.newContent);
34148
- out.push({ path: resolved.display, oldText, newText });
34149
- }
34150
-
34151
- // src/agents/acp/hooks/extract-acp-file-diffs-from-update/walk-update-for-diffs.ts
34152
- var NEST_KEYS = [
34153
- "content",
34154
- "contents",
34155
- "result",
34156
- "output",
34157
- "delta",
34158
- "toolResult",
34159
- "tool_result",
34160
- "data",
34161
- "arguments"
34162
- ];
34163
- function walkValue(value, sessionParentPath, depth, out) {
34164
- if (depth > 12 || value == null) return;
34165
- if (Array.isArray(value)) {
34166
- for (const x of value) walkValue(x, sessionParentPath, depth + 1, out);
34167
- return;
34168
- }
34169
- if (typeof value !== "object") return;
34170
- const o = value;
34171
- pushDiffIfComplete(o, sessionParentPath, out);
34172
- if (o.type === "content" && o.content != null && typeof o.content === "object") {
34173
- walkValue(o.content, sessionParentPath, depth + 1, out);
34174
- }
34175
- for (const k of NEST_KEYS) {
34176
- if (o.type === "content" && k === "content") continue;
34177
- const v = o[k];
34178
- if (v == null) continue;
34179
- if (k === "arguments" && typeof v === "string") {
34180
- try {
34181
- walkValue(JSON.parse(v), sessionParentPath, depth + 1, out);
34182
- } catch {
34183
- }
34184
- continue;
34185
- }
34186
- walkValue(v, sessionParentPath, depth + 1, out);
34187
- }
34188
- }
34189
-
34190
- // src/agents/acp/hooks/extract-acp-file-diffs-from-update/extract.ts
34191
- function extractAcpFileDiffsFromUpdate(update, sessionParentPath) {
34192
- if (!update || typeof update !== "object") return [];
34193
- const u = update;
34194
- const out = [];
34195
- const content = u.content;
34196
- if (Array.isArray(content)) {
34197
- for (const x of content) walkValue(x, sessionParentPath, 0, out);
34198
- }
34199
- const byPath = /* @__PURE__ */ new Map();
34200
- for (const d of out) byPath.set(d.path, d);
34201
- return [...byPath.values()];
34202
- }
34203
-
34204
- // src/agents/acp/hooks/extract-tool-target-paths.ts
34205
- function addPath(sessionParentPath, raw, out) {
34206
- if (typeof raw !== "string") return;
34207
- const trimmed2 = raw.trim();
34208
- if (!trimmed2) return;
34209
- const resolved = resolveWorkspaceFilePath(sessionParentPath, trimmed2);
34210
- if (!resolved) return;
34211
- out.add(resolved.display);
34212
- }
34213
- function walkLocations(sessionParentPath, loc, out) {
34214
- if (!Array.isArray(loc)) return;
34215
- for (const item of loc) {
34216
- if (item && typeof item === "object") addPath(sessionParentPath, item.path, out);
34217
- }
34218
- }
34219
- var PATH_KEYS = [
34220
- "path",
34221
- "file",
34222
- "filePath",
34223
- "filepath",
34224
- "target_path",
34225
- "targetPath",
34226
- "file_path",
34227
- "target_file"
34228
- ];
34229
- function collectFromObject(sessionParentPath, obj, out, depth) {
34230
- if (depth > 10) return;
34231
- for (const k of PATH_KEYS) {
34232
- if (k in obj) addPath(sessionParentPath, obj[k], out);
34233
- }
34234
- for (const v of Object.values(obj)) {
34235
- if (v != null && typeof v === "object") collectUnknown(sessionParentPath, v, out, depth + 1);
34236
- }
34237
- }
34238
- function collectUnknown(sessionParentPath, v, out, depth) {
34239
- if (depth > 10 || v == null) return;
34240
- if (Array.isArray(v)) {
34241
- for (const x of v) collectUnknown(sessionParentPath, x, out, depth + 1);
34242
- return;
34243
- }
34244
- if (typeof v === "object") collectFromObject(sessionParentPath, v, out, depth);
34245
- }
34246
- function walkContentArray(sessionParentPath, content, out) {
34247
- if (!Array.isArray(content)) return;
34248
- for (const item of content) {
34249
- if (!item || typeof item !== "object") continue;
34250
- const o = item;
34251
- if (typeof o.type === "string" && o.type.toLowerCase() === "diff") {
34252
- for (const k of PATH_KEYS) if (k in o) addPath(sessionParentPath, o[k], out);
34253
- }
34254
- if (o.type === "content" && o.content != null && typeof o.content === "object") {
34255
- const inner = o.content;
34256
- if (typeof inner.type === "string" && inner.type.toLowerCase() === "diff") {
34257
- for (const k of PATH_KEYS) if (k in inner) addPath(sessionParentPath, inner[k], out);
34258
- }
34259
- }
34260
- }
34261
- }
34262
- function extractToolTargetDisplayPaths(update, sessionParentPath) {
34263
- const out = /* @__PURE__ */ new Set();
34264
- if (!update || typeof update !== "object") return [];
34265
- const u = update;
34266
- walkLocations(sessionParentPath, u.locations, out);
34267
- walkLocations(sessionParentPath, u.fileLocations, out);
34268
- walkLocations(sessionParentPath, u.file_locations, out);
34269
- const tc = u.toolCall ?? u.tool_call;
34270
- if (tc && typeof tc.arguments === "string") {
34271
- try {
34272
- const parsed = JSON.parse(tc.arguments);
34273
- collectUnknown(sessionParentPath, parsed, out, 0);
34274
- } catch {
34275
- }
34276
- }
34277
- walkContentArray(sessionParentPath, u.content, out);
34278
- collectFromObject(sessionParentPath, u, out, 0);
34279
- return [...out];
34280
- }
34281
-
34282
34200
  // src/agents/acp/hooks/bridge-on-session-update/constants.ts
34283
34201
  var PATH_SNAPSHOT_DEBOUNCE_MS = 500;
34284
34202
 
@@ -34426,56 +34344,6 @@ var PathSnapshotTracker = class {
34426
34344
  }
34427
34345
  };
34428
34346
 
34429
- // src/agents/acp/hooks/bridge-on-session-update/send-structured-file-changes.ts
34430
- function sendExtractedDiffsAsSessionFileChanges(diffs, send, sessionParentPath, sessionId, runId, sentPaths, log2) {
34431
- for (const d of diffs) {
34432
- try {
34433
- const patchContent = editSnippetToUnifiedDiff(d.path, d.oldText, d.newText);
34434
- const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, d.path);
34435
- send({
34436
- type: "session_file_change",
34437
- sessionId,
34438
- runId,
34439
- path: d.path,
34440
- oldText: d.oldText,
34441
- newText: d.newText,
34442
- patchContent,
34443
- isDirectory: dirFlags.isDirectory,
34444
- directoryRemoved: dirFlags.directoryRemoved
34445
- });
34446
- sentPaths.add(d.path);
34447
- } catch (err) {
34448
- log2(`[Bridge service] Session file change failed for ${d.path}: ${errorMessage(err)}`);
34449
- }
34450
- }
34451
- }
34452
- function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send, sessionParentPath, sessionId, runId, log2) {
34453
- for (const displayPath of mergedPaths) {
34454
- if (sentPaths.has(displayPath)) continue;
34455
- const oldText = readGitHeadBlob(sessionParentPath, displayPath);
34456
- const newText = readUtf8WorkspaceFile(sessionParentPath, displayPath);
34457
- if (oldText === newText) continue;
34458
- try {
34459
- const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
34460
- const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath);
34461
- send({
34462
- type: "session_file_change",
34463
- sessionId,
34464
- runId,
34465
- path: displayPath,
34466
- oldText,
34467
- newText,
34468
- patchContent,
34469
- isDirectory: dirFlags.isDirectory,
34470
- directoryRemoved: dirFlags.directoryRemoved
34471
- });
34472
- sentPaths.add(displayPath);
34473
- } catch (err) {
34474
- log2(`[Bridge service] Session file change failed for ${displayPath}: ${errorMessage(err)}`);
34475
- }
34476
- }
34477
- }
34478
-
34479
34347
  // src/agents/acp/hooks/bridge-on-session-update/send-session-info-title-update.ts
34480
34348
  function extractSessionInfoTitle(params) {
34481
34349
  if (!params || typeof params !== "object") return null;
@@ -34498,6 +34366,391 @@ function sendSessionInfoTitleUpdate(params) {
34498
34366
  }
34499
34367
  }
34500
34368
 
34369
+ // src/agents/acp/hooks/bridge-on-session-update/parse-bridge-session-update.ts
34370
+ function parseBridgeSessionUpdate(params) {
34371
+ const p = params;
34372
+ const updateKind = p.sessionUpdate ?? p.session_update ?? p.type ?? "update";
34373
+ const isCompletedToolCallUpdate = updateKind === "tool_call_update" && isCompletedToolStatus(p.status);
34374
+ const toolName = p.toolCall?.name ?? p.tool_call?.name ?? "";
34375
+ const isToolUpdate = updateKind === "tool_call" || updateKind === "tool_call_update" || typeof toolName === "string" && toolName.length > 0;
34376
+ return { updateKind, toolName, isToolUpdate, isCompletedToolCallUpdate };
34377
+ }
34378
+
34379
+ // src/agents/acp/hooks/extract-acp-file-diffs-from-update/paths-and-text.ts
34380
+ import { fileURLToPath as fileURLToPath5 } from "node:url";
34381
+ function readOptionalTextField(v) {
34382
+ if (v === null || v === void 0) return "";
34383
+ if (typeof v === "string") return v;
34384
+ return "";
34385
+ }
34386
+ function normalizePathField(raw) {
34387
+ const t = raw.trim();
34388
+ if (t.startsWith("file://")) {
34389
+ try {
34390
+ return fileURLToPath5(t);
34391
+ } catch {
34392
+ return t;
34393
+ }
34394
+ }
34395
+ return t;
34396
+ }
34397
+ function extractDiffPath(o) {
34398
+ for (const k of ["path", "file", "filePath", "filepath", "target_path", "targetPath"]) {
34399
+ const v = o[k];
34400
+ if (typeof v === "string" && v.trim()) return normalizePathField(v);
34401
+ }
34402
+ return null;
34403
+ }
34404
+
34405
+ // src/agents/acp/hooks/extract-acp-file-diffs-from-update/push-diff.ts
34406
+ function pushDiffIfComplete(o, sessionParentPath, out) {
34407
+ const t = o.type;
34408
+ if (typeof t !== "string" || t.toLowerCase() !== "diff") return;
34409
+ const rawPath = extractDiffPath(o);
34410
+ if (!rawPath) return;
34411
+ const resolved = resolveWorkspaceFilePath(sessionParentPath, rawPath);
34412
+ if (!resolved) return;
34413
+ const oldText = readOptionalTextField(o.oldText ?? o.old_text ?? o.before ?? o.oldContent);
34414
+ const newText = readOptionalTextField(o.newText ?? o.new_text ?? o.after ?? o.newContent);
34415
+ out.push({ path: resolved.display, oldText, newText });
34416
+ }
34417
+
34418
+ // src/agents/acp/hooks/extract-acp-file-diffs-from-update/walk-update-for-diffs.ts
34419
+ var NEST_KEYS = [
34420
+ "content",
34421
+ "contents",
34422
+ "result",
34423
+ "output",
34424
+ "delta",
34425
+ "toolResult",
34426
+ "tool_result",
34427
+ "data",
34428
+ "arguments"
34429
+ ];
34430
+ function walkValue(value, sessionParentPath, depth, out) {
34431
+ if (depth > 12 || value == null) return;
34432
+ if (Array.isArray(value)) {
34433
+ for (const x of value) walkValue(x, sessionParentPath, depth + 1, out);
34434
+ return;
34435
+ }
34436
+ if (typeof value !== "object") return;
34437
+ const o = value;
34438
+ pushDiffIfComplete(o, sessionParentPath, out);
34439
+ if (o.type === "content" && o.content != null && typeof o.content === "object") {
34440
+ walkValue(o.content, sessionParentPath, depth + 1, out);
34441
+ }
34442
+ for (const k of NEST_KEYS) {
34443
+ if (o.type === "content" && k === "content") continue;
34444
+ const v = o[k];
34445
+ if (v == null) continue;
34446
+ if (k === "arguments" && typeof v === "string") {
34447
+ try {
34448
+ walkValue(JSON.parse(v), sessionParentPath, depth + 1, out);
34449
+ } catch {
34450
+ }
34451
+ continue;
34452
+ }
34453
+ walkValue(v, sessionParentPath, depth + 1, out);
34454
+ }
34455
+ }
34456
+
34457
+ // src/agents/acp/hooks/extract-acp-file-diffs-from-update/extract.ts
34458
+ function extractAcpFileDiffsFromUpdate(update, sessionParentPath) {
34459
+ if (!update || typeof update !== "object") return [];
34460
+ const u = update;
34461
+ const out = [];
34462
+ const content = u.content;
34463
+ if (Array.isArray(content)) {
34464
+ for (const x of content) walkValue(x, sessionParentPath, 0, out);
34465
+ }
34466
+ const byPath = /* @__PURE__ */ new Map();
34467
+ for (const d of out) byPath.set(d.path, d);
34468
+ return [...byPath.values()];
34469
+ }
34470
+
34471
+ // src/agents/acp/hooks/extract-tool-target-paths.ts
34472
+ function addPath(sessionParentPath, raw, out) {
34473
+ if (typeof raw !== "string") return;
34474
+ const trimmed2 = raw.trim();
34475
+ if (!trimmed2) return;
34476
+ const resolved = resolveWorkspaceFilePath(sessionParentPath, trimmed2);
34477
+ if (!resolved) return;
34478
+ out.add(resolved.display);
34479
+ }
34480
+ function walkLocations(sessionParentPath, loc, out) {
34481
+ if (!Array.isArray(loc)) return;
34482
+ for (const item of loc) {
34483
+ if (item && typeof item === "object") addPath(sessionParentPath, item.path, out);
34484
+ }
34485
+ }
34486
+ var PATH_KEYS = [
34487
+ "path",
34488
+ "file",
34489
+ "filePath",
34490
+ "filepath",
34491
+ "target_path",
34492
+ "targetPath",
34493
+ "file_path",
34494
+ "target_file"
34495
+ ];
34496
+ function collectFromObject(sessionParentPath, obj, out, depth) {
34497
+ if (depth > 10) return;
34498
+ for (const k of PATH_KEYS) {
34499
+ if (k in obj) addPath(sessionParentPath, obj[k], out);
34500
+ }
34501
+ for (const v of Object.values(obj)) {
34502
+ if (v != null && typeof v === "object") collectUnknown(sessionParentPath, v, out, depth + 1);
34503
+ }
34504
+ }
34505
+ function collectUnknown(sessionParentPath, v, out, depth) {
34506
+ if (depth > 10 || v == null) return;
34507
+ if (Array.isArray(v)) {
34508
+ for (const x of v) collectUnknown(sessionParentPath, x, out, depth + 1);
34509
+ return;
34510
+ }
34511
+ if (typeof v === "object") collectFromObject(sessionParentPath, v, out, depth);
34512
+ }
34513
+ function walkContentArray(sessionParentPath, content, out) {
34514
+ if (!Array.isArray(content)) return;
34515
+ for (const item of content) {
34516
+ if (!item || typeof item !== "object") continue;
34517
+ const o = item;
34518
+ if (typeof o.type === "string" && o.type.toLowerCase() === "diff") {
34519
+ for (const k of PATH_KEYS) if (k in o) addPath(sessionParentPath, o[k], out);
34520
+ }
34521
+ if (o.type === "content" && o.content != null && typeof o.content === "object") {
34522
+ const inner = o.content;
34523
+ if (typeof inner.type === "string" && inner.type.toLowerCase() === "diff") {
34524
+ for (const k of PATH_KEYS) if (k in inner) addPath(sessionParentPath, inner[k], out);
34525
+ }
34526
+ }
34527
+ }
34528
+ }
34529
+ function extractToolTargetDisplayPaths(update, sessionParentPath) {
34530
+ const out = /* @__PURE__ */ new Set();
34531
+ if (!update || typeof update !== "object") return [];
34532
+ const u = update;
34533
+ walkLocations(sessionParentPath, u.locations, out);
34534
+ walkLocations(sessionParentPath, u.fileLocations, out);
34535
+ walkLocations(sessionParentPath, u.file_locations, out);
34536
+ const tc = u.toolCall ?? u.tool_call;
34537
+ if (tc && typeof tc.arguments === "string") {
34538
+ try {
34539
+ const parsed = JSON.parse(tc.arguments);
34540
+ collectUnknown(sessionParentPath, parsed, out, 0);
34541
+ } catch {
34542
+ }
34543
+ }
34544
+ walkContentArray(sessionParentPath, u.content, out);
34545
+ collectFromObject(sessionParentPath, u, out, 0);
34546
+ return [...out];
34547
+ }
34548
+
34549
+ // src/agents/acp/hooks/bridge-on-session-update/send-structured-file-changes.ts
34550
+ function sendExtractedDiffsAsSessionFileChanges(diffs, send, sessionParentPath, sessionId, runId, sentPaths, log2) {
34551
+ for (const d of diffs) {
34552
+ try {
34553
+ const patchContent = editSnippetToUnifiedDiff(d.path, d.oldText, d.newText);
34554
+ const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, d.path);
34555
+ send({
34556
+ type: "session_file_change",
34557
+ sessionId,
34558
+ runId,
34559
+ path: d.path,
34560
+ oldText: d.oldText,
34561
+ newText: d.newText,
34562
+ patchContent,
34563
+ isDirectory: dirFlags.isDirectory,
34564
+ directoryRemoved: dirFlags.directoryRemoved
34565
+ });
34566
+ sentPaths.add(d.path);
34567
+ } catch (err) {
34568
+ log2(`[Bridge service] Session file change failed for ${d.path}: ${errorMessage(err)}`);
34569
+ }
34570
+ }
34571
+ }
34572
+ function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send, sessionParentPath, sessionId, runId, log2) {
34573
+ for (const displayPath of mergedPaths) {
34574
+ if (sentPaths.has(displayPath)) continue;
34575
+ const oldText = readGitHeadBlob(sessionParentPath, displayPath);
34576
+ const newText = readUtf8WorkspaceFile(sessionParentPath, displayPath);
34577
+ if (oldText === newText) continue;
34578
+ try {
34579
+ const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
34580
+ const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath);
34581
+ send({
34582
+ type: "session_file_change",
34583
+ sessionId,
34584
+ runId,
34585
+ path: displayPath,
34586
+ oldText,
34587
+ newText,
34588
+ patchContent,
34589
+ isDirectory: dirFlags.isDirectory,
34590
+ directoryRemoved: dirFlags.directoryRemoved
34591
+ });
34592
+ sentPaths.add(displayPath);
34593
+ } catch (err) {
34594
+ log2(`[Bridge service] Session file change failed for ${displayPath}: ${errorMessage(err)}`);
34595
+ }
34596
+ }
34597
+ }
34598
+
34599
+ // src/agents/acp/hooks/bridge-on-session-update/handle-bridge-tool-session-update.ts
34600
+ function handleBridgeToolSessionUpdate(params) {
34601
+ const {
34602
+ params: updateParams,
34603
+ updateKind,
34604
+ isToolUpdate,
34605
+ isCompletedToolCallUpdate,
34606
+ toolKey,
34607
+ toolPaths,
34608
+ status,
34609
+ sessionParentPath,
34610
+ pathTracker,
34611
+ sentFileChangePaths,
34612
+ send,
34613
+ runId,
34614
+ sessionId,
34615
+ log: log2
34616
+ } = params;
34617
+ if (updateKind === "tool_call") {
34618
+ pathTracker.resetToolSnapshots(toolKey);
34619
+ }
34620
+ if (isToolUpdate) {
34621
+ accumulateToolPaths(toolKey, toolPaths, pathTracker.accumulatedPathsByToolKey);
34622
+ }
34623
+ if (isToolUpdate) {
34624
+ const deliver = send && runId && sessionId ? (msg) => send(msg) : null;
34625
+ pathTracker.handleToolCallLifecycle(
34626
+ updateKind,
34627
+ toolKey,
34628
+ toolPaths,
34629
+ status,
34630
+ sessionParentPath,
34631
+ sentFileChangePaths,
34632
+ deliver,
34633
+ runId,
34634
+ sessionId,
34635
+ log2
34636
+ );
34637
+ }
34638
+ const diffs = extractAcpFileDiffsFromUpdate(updateParams, sessionParentPath);
34639
+ if (diffs.length > 0 && send && runId && sessionId) {
34640
+ sendExtractedDiffsAsSessionFileChanges(
34641
+ diffs,
34642
+ send,
34643
+ sessionParentPath,
34644
+ sessionId,
34645
+ runId,
34646
+ sentFileChangePaths,
34647
+ log2
34648
+ );
34649
+ } else if (diffs.length > 0) {
34650
+ log2(
34651
+ `[Bridge service] Agent file diff(s) not forwarded (${diffs.length}): session or run not wired to the bridge.`
34652
+ );
34653
+ }
34654
+ if (isCompletedToolCallUpdate && send && runId && sessionId) {
34655
+ const acc = pathTracker.accumulatedPathsByToolKey.get(toolKey);
34656
+ const merged = [.../* @__PURE__ */ new Set([...acc ? [...acc] : [], ...toolPaths])];
34657
+ sendGitHeadVsWorkspaceForToolPaths(
34658
+ merged,
34659
+ sentFileChangePaths,
34660
+ send,
34661
+ sessionParentPath,
34662
+ sessionId,
34663
+ runId,
34664
+ log2
34665
+ );
34666
+ pathTracker.accumulatedPathsByToolKey.delete(toolKey);
34667
+ }
34668
+ }
34669
+ function resolveBridgeToolPaths(params, isToolUpdate, sessionParentPath) {
34670
+ return isToolUpdate ? extractToolTargetDisplayPaths(params, sessionParentPath) : [];
34671
+ }
34672
+
34673
+ // src/agents/planning/extract-session-update-message-text.ts
34674
+ function extractSessionUpdateMessageText(params) {
34675
+ if (params == null || typeof params !== "object" || Array.isArray(params)) return null;
34676
+ const o = params;
34677
+ if (typeof o.text === "string" && o.text.length > 0) return o.text;
34678
+ const content = o.content;
34679
+ if (typeof content === "string" && content.length > 0) return content;
34680
+ if (content != null && typeof content === "object" && !Array.isArray(content)) {
34681
+ const c = content;
34682
+ if (typeof c.text === "string" && c.text.length > 0) return c.text;
34683
+ }
34684
+ const update = o.update;
34685
+ if (typeof update === "string" && update.length > 0) return update;
34686
+ if (update != null && typeof update === "object" && !Array.isArray(update)) {
34687
+ const u = update;
34688
+ const innerContent = u.content;
34689
+ if (typeof innerContent === "string" && innerContent.length > 0) return innerContent;
34690
+ if (innerContent != null && typeof innerContent === "object" && !Array.isArray(innerContent)) {
34691
+ const ic = innerContent;
34692
+ if (typeof ic.text === "string" && ic.text.length > 0) return ic.text;
34693
+ }
34694
+ }
34695
+ return null;
34696
+ }
34697
+
34698
+ // src/agents/planning/planning-session-turn-buffer.ts
34699
+ var buffersByRunId = /* @__PURE__ */ new Map();
34700
+ function registerPlanningSessionTurn(runId) {
34701
+ buffersByRunId.set(runId, { messageBuffer: "" });
34702
+ }
34703
+ function clearPlanningSessionTurn(runId) {
34704
+ buffersByRunId.delete(runId);
34705
+ }
34706
+ function capturePlanningSessionUpdate(params) {
34707
+ const state = buffersByRunId.get(params.runId);
34708
+ if (!state) return false;
34709
+ const sessionUpdate = params.payload != null && typeof params.payload === "object" && !Array.isArray(params.payload) ? params.payload.sessionUpdate ?? params.payload.session_update : void 0;
34710
+ const bucket = resolveAgentTextStreamBucket({
34711
+ transcriptRowKind: params.updateKind,
34712
+ sessionUpdate: typeof sessionUpdate === "string" ? sessionUpdate : void 0
34713
+ });
34714
+ if (bucket !== "message") return false;
34715
+ const text = extractSessionUpdateMessageText(params.payload);
34716
+ if (text) state.messageBuffer += text;
34717
+ return true;
34718
+ }
34719
+ function getPlanningSessionTurnOutput(runId) {
34720
+ return buffersByRunId.get(runId)?.messageBuffer ?? "";
34721
+ }
34722
+ function consumePlanningSessionTurnOutput(runId) {
34723
+ const state = buffersByRunId.get(runId);
34724
+ buffersByRunId.delete(runId);
34725
+ return state?.messageBuffer ?? "";
34726
+ }
34727
+
34728
+ // src/agents/acp/hooks/bridge-on-session-update/forward-bridge-session-update.ts
34729
+ function forwardBridgeSessionUpdate(params) {
34730
+ const { runId, sessionId, updateKind, payload, send, nextTranscriptStreamSeq, log: log2 } = params;
34731
+ if (updateKind === "permission") {
34732
+ return;
34733
+ }
34734
+ if (capturePlanningSessionUpdate({ runId, updateKind, payload })) {
34735
+ return;
34736
+ }
34737
+ try {
34738
+ const transcriptStreamSeq = nextTranscriptStreamSeq?.(runId);
34739
+ send({
34740
+ type: "session_update",
34741
+ ...sessionId ? { sessionId } : {},
34742
+ runId,
34743
+ kind: updateKind,
34744
+ payload,
34745
+ ...transcriptStreamSeq != null ? { transcriptStreamSeq } : {}
34746
+ });
34747
+ } catch (err) {
34748
+ log2(
34749
+ `[Bridge service] Session update send failed (${formatSessionUpdateKindForLog(updateKind)}): ${errorMessage(err)}`
34750
+ );
34751
+ }
34752
+ }
34753
+
34501
34754
  // src/agents/acp/hooks/bridge-on-session-update/create-bridge-on-session-update.ts
34502
34755
  function createBridgeOnSessionUpdate(opts) {
34503
34756
  const { resolveRouting, getSendSessionUpdate, log: log2, sessionParentPath, nextTranscriptStreamSeq } = opts;
@@ -34509,8 +34762,7 @@ function createBridgeOnSessionUpdate(opts) {
34509
34762
  pathTracker.onRunIdChanged(runId);
34510
34763
  const send = getSendSessionUpdate();
34511
34764
  const sentFileChangePaths = /* @__PURE__ */ new Set();
34512
- const p = params;
34513
- const updateKind = p.sessionUpdate ?? p.session_update ?? p.type ?? "update";
34765
+ const { updateKind, isToolUpdate, isCompletedToolCallUpdate } = parseBridgeSessionUpdate(params);
34514
34766
  if (updateKind === "config_option_update") {
34515
34767
  return;
34516
34768
  }
@@ -34518,81 +34770,35 @@ function createBridgeOnSessionUpdate(opts) {
34518
34770
  sendSessionInfoTitleUpdate({ payload: params, runId, sessionId, send, log: log2 });
34519
34771
  return;
34520
34772
  }
34521
- const isCompletedToolCallUpdate = updateKind === "tool_call_update" && isCompletedToolStatus(p.status);
34522
- const toolName = p.toolCall?.name ?? p.tool_call?.name ?? "";
34523
- const isToolUpdate = updateKind === "tool_call" || updateKind === "tool_call_update" || typeof toolName === "string" && toolName.length > 0;
34524
- const toolPaths = isToolUpdate ? extractToolTargetDisplayPaths(params, sessionParentPath) : [];
34773
+ const toolPaths = resolveBridgeToolPaths(params, isToolUpdate, sessionParentPath);
34525
34774
  const toolKey = isToolUpdate ? pathTracker.resolveToolKey(params, updateKind) : "";
34526
- if (updateKind === "tool_call") {
34527
- pathTracker.resetToolSnapshots(toolKey);
34528
- }
34529
- if (isToolUpdate) {
34530
- accumulateToolPaths(toolKey, toolPaths, pathTracker.accumulatedPathsByToolKey);
34531
- }
34532
- if (isToolUpdate) {
34533
- const deliver = send && runId && sessionId ? (msg) => send(msg) : null;
34534
- pathTracker.handleToolCallLifecycle(
34535
- updateKind,
34536
- toolKey,
34537
- toolPaths,
34538
- p.status,
34539
- sessionParentPath,
34540
- sentFileChangePaths,
34541
- deliver,
34542
- runId ?? "",
34543
- sessionId ?? "",
34544
- log2
34545
- );
34546
- }
34547
- const diffs = extractAcpFileDiffsFromUpdate(params, sessionParentPath);
34548
- if (diffs.length > 0 && send && runId && sessionId) {
34549
- sendExtractedDiffsAsSessionFileChanges(
34550
- diffs,
34551
- send,
34552
- sessionParentPath,
34553
- sessionId,
34775
+ const status = params.status;
34776
+ handleBridgeToolSessionUpdate({
34777
+ params,
34778
+ updateKind,
34779
+ isToolUpdate,
34780
+ isCompletedToolCallUpdate,
34781
+ toolKey,
34782
+ toolPaths,
34783
+ status,
34784
+ sessionParentPath,
34785
+ pathTracker,
34786
+ sentFileChangePaths,
34787
+ send,
34788
+ runId: runId ?? "",
34789
+ sessionId: sessionId ?? "",
34790
+ log: log2
34791
+ });
34792
+ if (runId && send) {
34793
+ forwardBridgeSessionUpdate({
34554
34794
  runId,
34555
- sentFileChangePaths,
34556
- log2
34557
- );
34558
- } else if (diffs.length > 0) {
34559
- log2(
34560
- `[Bridge service] Agent file diff(s) not forwarded (${diffs.length}): session or run not wired to the bridge.`
34561
- );
34562
- }
34563
- if (isCompletedToolCallUpdate && send && runId && sessionId) {
34564
- const acc = pathTracker.accumulatedPathsByToolKey.get(toolKey);
34565
- const merged = [.../* @__PURE__ */ new Set([...acc ? [...acc] : [], ...toolPaths])];
34566
- sendGitHeadVsWorkspaceForToolPaths(
34567
- merged,
34568
- sentFileChangePaths,
34569
- send,
34570
- sessionParentPath,
34571
34795
  sessionId,
34572
- runId,
34573
- log2
34574
- );
34575
- pathTracker.accumulatedPathsByToolKey.delete(toolKey);
34576
- }
34577
- if (runId && send) {
34578
- if (updateKind === "permission") {
34579
- return;
34580
- }
34581
- try {
34582
- const transcriptStreamSeq = nextTranscriptStreamSeq?.(runId);
34583
- send({
34584
- type: "session_update",
34585
- ...sessionId ? { sessionId } : {},
34586
- runId,
34587
- kind: updateKind,
34588
- payload: params,
34589
- ...transcriptStreamSeq != null ? { transcriptStreamSeq } : {}
34590
- });
34591
- } catch (err) {
34592
- log2(
34593
- `[Bridge service] Session update send failed (${formatSessionUpdateKindForLog(updateKind)}): ${errorMessage(err)}`
34594
- );
34595
- }
34796
+ updateKind,
34797
+ payload: params,
34798
+ send,
34799
+ nextTranscriptStreamSeq,
34800
+ log: log2
34801
+ });
34596
34802
  }
34597
34803
  };
34598
34804
  }
@@ -34932,6 +35138,40 @@ async function disconnectAll(ctx) {
34932
35138
  ctx.pendingCancelRunIds.clear();
34933
35139
  }
34934
35140
 
35141
+ // src/agents/acp/manager/resolve-prompt-run-context.ts
35142
+ function resolvePromptRunContext(ctx, opts) {
35143
+ const { runId, mode, agentType, agentConfig, sessionId } = opts;
35144
+ const preferredForPrompt = agentType ?? ctx.backendFallbackAgentType ?? null;
35145
+ if (!runId) {
35146
+ ctx.log("[Agent] Prompt ignored: missing runId (cannot route session updates).");
35147
+ return null;
35148
+ }
35149
+ const acpAgentKey = computeAcpAgentKey(preferredForPrompt, mode, agentConfig ?? null);
35150
+ if (!acpAgentKey) {
35151
+ return null;
35152
+ }
35153
+ const activeAcpSessionAgentKey = computeAcpSessionAgentKey(sessionId, acpAgentKey);
35154
+ ctx.pendingCancelRunIds.delete(runId);
35155
+ ctx.promptRouting.registerRun({ sessionId, runId });
35156
+ ctx.runDispatch.set(runId, { acpSessionAgentKey: activeAcpSessionAgentKey });
35157
+ return {
35158
+ activeRunId: runId,
35159
+ activeAcpAgentKey: acpAgentKey,
35160
+ activeAcpSessionAgentKey,
35161
+ preferredForPrompt
35162
+ };
35163
+ }
35164
+
35165
+ // src/agents/acp/send-prompt-result-augment.ts
35166
+ function augmentPromptResultAuthFields(agentType, errorText) {
35167
+ const err = errorText ?? "";
35168
+ const at = agentType ?? null;
35169
+ const evaluated = Boolean(at && err.trim());
35170
+ const suggestsAuth = evaluated && at ? localAgentErrorSuggestsAuth(at, err) : false;
35171
+ if (!suggestsAuth || !agentType) return {};
35172
+ return { agentAuthRequired: true, agentType };
35173
+ }
35174
+
34935
35175
  // src/git/git-runtime.ts
34936
35176
  var activeGitChildProcesses = /* @__PURE__ */ new Set();
34937
35177
  function abortActiveGitChildProcesses() {
@@ -35006,8 +35246,8 @@ async function execGitFile(args, options) {
35006
35246
  }
35007
35247
 
35008
35248
  // src/git/changes/parse/normalize-git-diff-path.ts
35009
- function normalizeGitDiffPath(path75) {
35010
- return path75.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
35249
+ function normalizeGitDiffPath(path76) {
35250
+ return path76.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
35011
35251
  }
35012
35252
 
35013
35253
  // src/git/changes/parse/parse-name-status-entries.ts
@@ -35294,9 +35534,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
35294
35534
  // src/agents/acp/put-summarize-change-summaries.ts
35295
35535
  async function putEncryptedChangeSummaryRows(params) {
35296
35536
  const base = params.apiBaseUrl.replace(/\/+$/, "");
35297
- const entries = params.rows.map(({ path: path75, summary }) => {
35537
+ const entries = params.rows.map(({ path: path76, summary }) => {
35298
35538
  const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
35299
- return { path: path75, summary: JSON.stringify(enc) };
35539
+ return { path: path76, summary: JSON.stringify(enc) };
35300
35540
  });
35301
35541
  const res = await fetch(
35302
35542
  `${base}/internal/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
@@ -35387,104 +35627,136 @@ async function maybeUploadE2eeSessionChangeSummariesAfterAgentSuccess(params) {
35387
35627
  }
35388
35628
  }
35389
35629
 
35390
- // src/agents/acp/send-prompt-result-augment.ts
35391
- function augmentPromptResultAuthFields(agentType, errorText) {
35392
- const err = errorText ?? "";
35393
- const at = agentType ?? null;
35394
- const evaluated = Boolean(at && err.trim());
35395
- const suggestsAuth = evaluated && at ? localAgentErrorSuggestsAuth(at, err) : false;
35396
- if (!suggestsAuth || !agentType) return {};
35397
- return { agentAuthRequired: true, agentType };
35630
+ // src/agents/planning/submit-planning-todos-for-turn.ts
35631
+ async function submitPlanningTodosForTurn(params) {
35632
+ const token = params.getCloudAccessToken();
35633
+ if (!token.trim()) return { ok: false, error: "Missing cloud access token" };
35634
+ const base = params.cloudApiBaseUrl.replace(/\/$/, "");
35635
+ const url2 = `${base}/internal/sessions/todos/submit`;
35636
+ const res = await fetch(url2, {
35637
+ method: "POST",
35638
+ headers: {
35639
+ Authorization: `Bearer ${token}`,
35640
+ "Content-Type": "application/json"
35641
+ },
35642
+ body: JSON.stringify({
35643
+ sessionId: params.sessionId,
35644
+ turnId: params.turnId,
35645
+ items: params.items
35646
+ })
35647
+ });
35648
+ if (!res.ok) {
35649
+ const body = await res.json().catch(() => null);
35650
+ return { ok: false, error: body?.error ?? `Planning todo submit failed (${res.status})` };
35651
+ }
35652
+ return { ok: true };
35398
35653
  }
35399
35654
 
35400
- // src/agents/acp/fetch-session-attachments.ts
35401
- function metaSaysEncrypted(meta) {
35402
- if (!meta) return false;
35403
- const e = meta.encrypted;
35404
- return e === true || e === "true" || e === 1;
35405
- }
35406
- function warnIfDecodedImageMagicUnexpected(buf, mimeType, idShort) {
35407
- const m = mimeType.toLowerCase();
35408
- if (!m.startsWith("image/") || buf.length < 4) return;
35409
- const b0 = buf[0];
35410
- const b1 = buf[1];
35411
- const b2 = buf[2];
35412
- const b3 = buf[3];
35413
- let looksOk = false;
35414
- if (m.includes("png") && b0 === 137 && b1 === 80 && b2 === 78 && b3 === 71) looksOk = true;
35415
- else if ((m.includes("jpeg") || m.includes("jpg")) && b0 === 255 && b1 === 216 && b2 === 255) looksOk = true;
35416
- else if (m.includes("gif") && b0 === 71 && b1 === 73 && b2 === 70) looksOk = true;
35417
- else if (m.includes("webp") && buf.length >= 12 && buf.subarray(0, 4).toString("ascii") === "RIFF" && buf.subarray(8, 12).toString("ascii") === "WEBP")
35418
- looksOk = true;
35419
- else if (!/(png|jpe?g|gif|webp)/i.test(m)) looksOk = true;
35420
- if (!looksOk) {
35421
- logDebug(
35422
- `[Agent] Attachment ${idShort} (${mimeType}): decoded bytes do not match common image signatures \u2014 wrong E2EE key, corrupt blob, or metadata mismatch. First 12 bytes (hex): ${buf.subarray(0, Math.min(12, buf.length)).toString("hex")}`
35423
- );
35655
+ // src/agents/planning/maybe-submit-planning-todos-after-agent-success.ts
35656
+ async function maybeSubmitPlanningTodosAfterAgentSuccess(params) {
35657
+ const { sessionId, runId, resultSuccess, output, cloudApiBaseUrl, getCloudAccessToken, log: log2 } = params;
35658
+ const buffered = runId ? getPlanningSessionTurnOutput(runId) : "";
35659
+ const outputFromResult = typeof output === "string" ? output : "";
35660
+ const outputStr = buffered.trim() !== "" ? buffered : outputFromResult;
35661
+ if (!sessionId || !runId || !resultSuccess || outputStr.trim() === "") {
35662
+ return { submitted: false, suppressOutput: false };
35424
35663
  }
35425
- }
35426
- async function fetchSessionAttachmentPayloadsForAgent(params) {
35427
- const { attachments, sessionId, cloudApiBaseUrl, getCloudAccessToken, e2ee, log: log2 } = params;
35428
- const token = getCloudAccessToken();
35429
- if (!token) {
35430
- return { ok: false, error: "Missing cloud access token; cannot download attachments." };
35664
+ if (!cloudApiBaseUrl || !getCloudAccessToken) {
35665
+ return { submitted: false, suppressOutput: false };
35431
35666
  }
35432
- const wantedCount = attachments.filter((a) => typeof a.attachmentId === "string" && a.attachmentId.trim() !== "").length;
35433
- if (wantedCount === 0) {
35434
- return { ok: false, error: "No valid attachment ids in prompt." };
35667
+ const items = parsePlanningTodoAgentJson(outputStr);
35668
+ if (items.length === 0) {
35669
+ return { submitted: false, suppressOutput: false };
35435
35670
  }
35436
- const base = cloudApiBaseUrl.replace(/\/+$/, "");
35437
- const out = [];
35438
- for (const a of attachments) {
35439
- const id = typeof a.attachmentId === "string" ? a.attachmentId.trim() : "";
35440
- if (!id) continue;
35441
- const metaUrl = `${base}/internal/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/meta`;
35442
- const blobUrl = `${base}/internal/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/blob`;
35443
- const metaRes = await fetch(metaUrl, { headers: { Authorization: `Bearer ${token}` } });
35444
- if (!metaRes.ok) {
35445
- const t = await metaRes.text().catch(() => "");
35446
- log2(`[Agent] Attachment meta fetch failed ${metaRes.status}: ${t.slice(0, 200)}`);
35447
- return { ok: false, error: `Could not load attachment (${id.slice(0, 8)}\u2026): ${metaRes.status}` };
35448
- }
35449
- const meta = await metaRes.json().catch(() => null);
35450
- const mimeType = typeof meta?.mimeType === "string" && meta.mimeType.trim() ? meta.mimeType.trim() : a.mimeType;
35451
- const blobRes = await fetch(blobUrl, { headers: { Authorization: `Bearer ${token}` } });
35452
- if (!blobRes.ok) {
35453
- const t = await blobRes.text().catch(() => "");
35454
- log2(`[Agent] Attachment blob fetch failed ${blobRes.status}: ${t.slice(0, 200)}`);
35455
- return { ok: false, error: `Could not load attachment data (${id.slice(0, 8)}\u2026): ${blobRes.status}` };
35456
- }
35457
- const buf = Buffer.from(await blobRes.arrayBuffer());
35458
- let imageBytes;
35459
- const encrypted = metaSaysEncrypted(meta);
35460
- if (encrypted) {
35461
- if (!e2ee) {
35462
- return { ok: false, error: "Encrypted attachments require E2EE keys on this bridge." };
35463
- }
35464
- const k = typeof meta?.k === "string" ? meta.k : "";
35465
- const n = typeof meta?.n === "string" ? meta.n : "";
35466
- if (!k || !n) {
35467
- return { ok: false, error: "Invalid encrypted attachment metadata (missing key id or nonce)." };
35468
- }
35469
- const c = base64UrlEncode(buf);
35470
- imageBytes = e2ee.decryptEnvelopeToBuffer({ k, n, c });
35671
+ const result = await submitPlanningTodosForTurn({
35672
+ sessionId,
35673
+ turnId: runId,
35674
+ items,
35675
+ cloudApiBaseUrl,
35676
+ getCloudAccessToken
35677
+ });
35678
+ if (!result.ok) {
35679
+ log2(`[Agent] Planning todo submit failed: ${result.error}`);
35680
+ return { submitted: false, suppressOutput: false };
35681
+ }
35682
+ if (runId) consumePlanningSessionTurnOutput(runId);
35683
+ log2(`[Agent] Planning session: stored ${items.length} todo(s) via internal API`);
35684
+ return { submitted: true, suppressOutput: true };
35685
+ }
35686
+
35687
+ // src/agents/acp/prompts/finalize-and-send-prompt-result.ts
35688
+ async function finalizeAndSendPromptResult(params) {
35689
+ const {
35690
+ result,
35691
+ sessionId,
35692
+ runId,
35693
+ promptId,
35694
+ agentType,
35695
+ agentCwd,
35696
+ isPlanningSession,
35697
+ followUpCatalogPromptId,
35698
+ sessionChangeSummaryFilePaths,
35699
+ cloudApiBaseUrl,
35700
+ getCloudAccessToken,
35701
+ e2ee,
35702
+ sendResult,
35703
+ sendSessionUpdate,
35704
+ log: log2
35705
+ } = params;
35706
+ if (sessionId && runId && sendSessionUpdate && agentCwd && result.success) {
35707
+ await collectTurnGitDiffFromPreTurnSnapshot({
35708
+ sessionId,
35709
+ runId,
35710
+ agentCwd,
35711
+ sendSessionUpdate,
35712
+ log: log2
35713
+ });
35714
+ }
35715
+ await maybeUploadE2eeSessionChangeSummariesAfterAgentSuccess({
35716
+ sessionId,
35717
+ runId,
35718
+ resultSuccess: result.success === true,
35719
+ output: result.output,
35720
+ e2ee,
35721
+ cloudApiBaseUrl,
35722
+ getCloudAccessToken,
35723
+ followUpCatalogPromptId,
35724
+ sessionChangeSummaryFilePaths,
35725
+ log: log2
35726
+ });
35727
+ const planningTodosSubmit = await maybeSubmitPlanningTodosAfterAgentSuccess({
35728
+ sessionId,
35729
+ runId,
35730
+ resultSuccess: result.success === true,
35731
+ output: result.output,
35732
+ cloudApiBaseUrl,
35733
+ getCloudAccessToken,
35734
+ log: log2
35735
+ });
35736
+ const errStr = typeof result.error === "string" ? result.error : void 0;
35737
+ const resultStop = typeof result.stopReason === "string" ? result.stopReason.trim() : "";
35738
+ const cancelledByAgent = resultStop.toLowerCase() === "cancelled" || errStr != null && isUserEndedSessionTurnErrorText(errStr);
35739
+ const planningFallbackOutput = !planningTodosSubmit.suppressOutput && isPlanningSession && runId ? consumePlanningSessionTurnOutput(runId) : "";
35740
+ sendResult({
35741
+ type: "prompt_result",
35742
+ id: promptId,
35743
+ ...sessionId ? { sessionId } : {},
35744
+ ...runId ? { runId } : {},
35745
+ ...result,
35746
+ ...planningTodosSubmit.suppressOutput ? { output: void 0 } : planningFallbackOutput.trim() !== "" ? { output: planningFallbackOutput } : {},
35747
+ ...followUpCatalogPromptId != null && followUpCatalogPromptId !== "" ? { followUpCatalogPromptId } : {},
35748
+ ...augmentPromptResultAuthFields(agentType, errStr),
35749
+ ...!result.success && cancelledByAgent ? { stopReason: "cancelled" } : {}
35750
+ });
35751
+ if (!result.success) {
35752
+ if (cancelledByAgent) {
35753
+ log2("[Agent] Run ended after stop request (stopped by user).");
35471
35754
  } else {
35472
- imageBytes = buf;
35755
+ log2(
35756
+ `[Agent] Prompt did not run successfully on the agent (no successful start/completion): ${result.error ?? "Unknown error"}`
35757
+ );
35473
35758
  }
35474
- warnIfDecodedImageMagicUnexpected(imageBytes, mimeType, id.slice(0, 8));
35475
- logDebug(
35476
- `[Agent] Loaded prompt image ${id.slice(0, 8)}\u2026: ${imageBytes.length} bytes, mime=${mimeType}, ${encrypted ? "E2EE decrypted" : "plaintext from storage"}`
35477
- );
35478
- const dataBase64 = imageBytes.toString("base64");
35479
- out.push({ mimeType, dataBase64 });
35480
35759
  }
35481
- if (out.length !== wantedCount) {
35482
- return {
35483
- ok: false,
35484
- error: `Expected ${wantedCount} image attachment(s) but only loaded ${out.length} (check attachment ids and empty rows).`
35485
- };
35486
- }
35487
- return { ok: true, images: out };
35488
35760
  }
35489
35761
 
35490
35762
  // src/agents/acp/build-forked-session-agent-prompt.ts
@@ -35675,7 +35947,213 @@ function enrichIntegrationContentPromptForAgent(params) {
35675
35947
  return injectIntegrationContentAgentPromptNote(params.agentPromptText, params.sessionId);
35676
35948
  }
35677
35949
 
35678
- // src/agents/acp/send-prompt-to-agent.ts
35950
+ // src/agents/planning/enrich-planning-session-prompt-for-agent.ts
35951
+ async function enrichPlanningSessionPromptForAgent(params) {
35952
+ const meta = await fetchCloudSessionMeta({
35953
+ sessionId: params.sessionId,
35954
+ cloudApiBaseUrl: params.cloudApiBaseUrl,
35955
+ getCloudAccessToken: params.getCloudAccessToken
35956
+ });
35957
+ if (!meta.ok) return { promptText: params.promptText, isPlanningSession: false };
35958
+ const sessionKind = parseSessionKind(meta.data.sessionKind);
35959
+ if (sessionKind !== "planning") return { promptText: params.promptText, isPlanningSession: false };
35960
+ const todos = Array.isArray(meta.data.planningTodos) ? meta.data.planningTodos : [];
35961
+ if (params.isNewSession || todos.length === 0) {
35962
+ return {
35963
+ promptText: buildPlanningSessionAgentPrompt(params.promptText),
35964
+ isPlanningSession: true
35965
+ };
35966
+ }
35967
+ return {
35968
+ promptText: buildPlanningSessionFollowUpAgentPrompt(params.promptText, todos),
35969
+ isPlanningSession: true
35970
+ };
35971
+ }
35972
+
35973
+ // src/agents/acp/prompts/prepare-agent-prompt-text.ts
35974
+ async function prepareAgentPromptText(params) {
35975
+ const { promptText, sessionId, runId, isNewSession, cloudApiBaseUrl, getCloudAccessToken } = params;
35976
+ let agentPromptText = promptText;
35977
+ let isPlanningSession = false;
35978
+ if (sessionId && cloudApiBaseUrl && getCloudAccessToken) {
35979
+ agentPromptText = await enrichForkedSessionPromptForAgent({
35980
+ sessionId,
35981
+ promptText,
35982
+ cloudApiBaseUrl,
35983
+ getCloudAccessToken
35984
+ });
35985
+ const planningEnriched = await enrichPlanningSessionPromptForAgent({
35986
+ sessionId,
35987
+ promptText: agentPromptText,
35988
+ isNewSession,
35989
+ cloudApiBaseUrl,
35990
+ getCloudAccessToken
35991
+ });
35992
+ agentPromptText = planningEnriched.promptText;
35993
+ isPlanningSession = planningEnriched.isPlanningSession;
35994
+ }
35995
+ if (isPlanningSession && runId) {
35996
+ registerPlanningSessionTurn(runId);
35997
+ }
35998
+ if (sessionId) {
35999
+ agentPromptText = enrichIntegrationContentPromptForAgent({
36000
+ sessionId,
36001
+ originalPromptText: promptText,
36002
+ agentPromptText
36003
+ });
36004
+ }
36005
+ return { agentPromptText, isPlanningSession };
36006
+ }
36007
+
36008
+ // src/agents/acp/fetch-session-attachments.ts
36009
+ function metaSaysEncrypted(meta) {
36010
+ if (!meta) return false;
36011
+ const e = meta.encrypted;
36012
+ return e === true || e === "true" || e === 1;
36013
+ }
36014
+ function warnIfDecodedImageMagicUnexpected(buf, mimeType, idShort) {
36015
+ const m = mimeType.toLowerCase();
36016
+ if (!m.startsWith("image/") || buf.length < 4) return;
36017
+ const b0 = buf[0];
36018
+ const b1 = buf[1];
36019
+ const b2 = buf[2];
36020
+ const b3 = buf[3];
36021
+ let looksOk = false;
36022
+ if (m.includes("png") && b0 === 137 && b1 === 80 && b2 === 78 && b3 === 71) looksOk = true;
36023
+ else if ((m.includes("jpeg") || m.includes("jpg")) && b0 === 255 && b1 === 216 && b2 === 255) looksOk = true;
36024
+ else if (m.includes("gif") && b0 === 71 && b1 === 73 && b2 === 70) looksOk = true;
36025
+ else if (m.includes("webp") && buf.length >= 12 && buf.subarray(0, 4).toString("ascii") === "RIFF" && buf.subarray(8, 12).toString("ascii") === "WEBP")
36026
+ looksOk = true;
36027
+ else if (!/(png|jpe?g|gif|webp)/i.test(m)) looksOk = true;
36028
+ if (!looksOk) {
36029
+ logDebug(
36030
+ `[Agent] Attachment ${idShort} (${mimeType}): decoded bytes do not match common image signatures \u2014 wrong E2EE key, corrupt blob, or metadata mismatch. First 12 bytes (hex): ${buf.subarray(0, Math.min(12, buf.length)).toString("hex")}`
36031
+ );
36032
+ }
36033
+ }
36034
+ async function fetchSessionAttachmentPayloadsForAgent(params) {
36035
+ const { attachments, sessionId, cloudApiBaseUrl, getCloudAccessToken, e2ee, log: log2 } = params;
36036
+ const token = getCloudAccessToken();
36037
+ if (!token) {
36038
+ return { ok: false, error: "Missing cloud access token; cannot download attachments." };
36039
+ }
36040
+ const wantedCount = attachments.filter((a) => typeof a.attachmentId === "string" && a.attachmentId.trim() !== "").length;
36041
+ if (wantedCount === 0) {
36042
+ return { ok: false, error: "No valid attachment ids in prompt." };
36043
+ }
36044
+ const base = cloudApiBaseUrl.replace(/\/+$/, "");
36045
+ const out = [];
36046
+ for (const a of attachments) {
36047
+ const id = typeof a.attachmentId === "string" ? a.attachmentId.trim() : "";
36048
+ if (!id) continue;
36049
+ const metaUrl = `${base}/internal/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/meta`;
36050
+ const blobUrl = `${base}/internal/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/blob`;
36051
+ const metaRes = await fetch(metaUrl, { headers: { Authorization: `Bearer ${token}` } });
36052
+ if (!metaRes.ok) {
36053
+ const t = await metaRes.text().catch(() => "");
36054
+ log2(`[Agent] Attachment meta fetch failed ${metaRes.status}: ${t.slice(0, 200)}`);
36055
+ return { ok: false, error: `Could not load attachment (${id.slice(0, 8)}\u2026): ${metaRes.status}` };
36056
+ }
36057
+ const meta = await metaRes.json().catch(() => null);
36058
+ const mimeType = typeof meta?.mimeType === "string" && meta.mimeType.trim() ? meta.mimeType.trim() : a.mimeType;
36059
+ const blobRes = await fetch(blobUrl, { headers: { Authorization: `Bearer ${token}` } });
36060
+ if (!blobRes.ok) {
36061
+ const t = await blobRes.text().catch(() => "");
36062
+ log2(`[Agent] Attachment blob fetch failed ${blobRes.status}: ${t.slice(0, 200)}`);
36063
+ return { ok: false, error: `Could not load attachment data (${id.slice(0, 8)}\u2026): ${blobRes.status}` };
36064
+ }
36065
+ const buf = Buffer.from(await blobRes.arrayBuffer());
36066
+ let imageBytes;
36067
+ const encrypted = metaSaysEncrypted(meta);
36068
+ if (encrypted) {
36069
+ if (!e2ee) {
36070
+ return { ok: false, error: "Encrypted attachments require E2EE keys on this bridge." };
36071
+ }
36072
+ const k = typeof meta?.k === "string" ? meta.k : "";
36073
+ const n = typeof meta?.n === "string" ? meta.n : "";
36074
+ if (!k || !n) {
36075
+ return { ok: false, error: "Invalid encrypted attachment metadata (missing key id or nonce)." };
36076
+ }
36077
+ const c = base64UrlEncode(buf);
36078
+ imageBytes = e2ee.decryptEnvelopeToBuffer({ k, n, c });
36079
+ } else {
36080
+ imageBytes = buf;
36081
+ }
36082
+ warnIfDecodedImageMagicUnexpected(imageBytes, mimeType, id.slice(0, 8));
36083
+ logDebug(
36084
+ `[Agent] Loaded prompt image ${id.slice(0, 8)}\u2026: ${imageBytes.length} bytes, mime=${mimeType}, ${encrypted ? "E2EE decrypted" : "plaintext from storage"}`
36085
+ );
36086
+ const dataBase64 = imageBytes.toString("base64");
36087
+ out.push({ mimeType, dataBase64 });
36088
+ }
36089
+ if (out.length !== wantedCount) {
36090
+ return {
36091
+ ok: false,
36092
+ error: `Expected ${wantedCount} image attachment(s) but only loaded ${out.length} (check attachment ids and empty rows).`
36093
+ };
36094
+ }
36095
+ return { ok: true, images: out };
36096
+ }
36097
+
36098
+ // src/agents/acp/prompts/resolve-send-prompt-images.ts
36099
+ async function resolveSendPromptImages(params) {
36100
+ const {
36101
+ attachments,
36102
+ sessionId,
36103
+ promptId,
36104
+ runId,
36105
+ agentType,
36106
+ followUpCatalogPromptId,
36107
+ cloudApiBaseUrl,
36108
+ getCloudAccessToken,
36109
+ e2ee,
36110
+ log: log2
36111
+ } = params;
36112
+ if (!attachments || attachments.length === 0) {
36113
+ return { ok: true, sendOpts: {} };
36114
+ }
36115
+ if (!sessionId || !cloudApiBaseUrl || !getCloudAccessToken) {
36116
+ return {
36117
+ ok: false,
36118
+ errorResult: {
36119
+ type: "prompt_result",
36120
+ id: promptId,
36121
+ ...sessionId ? { sessionId } : {},
36122
+ ...runId ? { runId } : {},
36123
+ success: false,
36124
+ error: "Prompt includes images but the bridge is not configured with a cloud API URL and token to fetch them.",
36125
+ ...followUpCatalogPromptId != null && followUpCatalogPromptId !== "" ? { followUpCatalogPromptId } : {},
36126
+ ...augmentPromptResultAuthFields(agentType, "missing cloud for images download")
36127
+ }
36128
+ };
36129
+ }
36130
+ const resolved = await fetchSessionAttachmentPayloadsForAgent({
36131
+ attachments,
36132
+ sessionId,
36133
+ cloudApiBaseUrl,
36134
+ getCloudAccessToken,
36135
+ e2ee,
36136
+ log: log2
36137
+ });
36138
+ if (!resolved.ok) {
36139
+ return {
36140
+ ok: false,
36141
+ errorResult: {
36142
+ type: "prompt_result",
36143
+ id: promptId,
36144
+ ...sessionId ? { sessionId } : {},
36145
+ ...runId ? { runId } : {},
36146
+ success: false,
36147
+ error: resolved.error,
36148
+ ...followUpCatalogPromptId != null && followUpCatalogPromptId !== "" ? { followUpCatalogPromptId } : {},
36149
+ ...augmentPromptResultAuthFields(agentType, resolved.error)
36150
+ }
36151
+ };
36152
+ }
36153
+ return { ok: true, sendOpts: { images: resolved.images } };
36154
+ }
36155
+
36156
+ // src/agents/acp/prompts/send-prompt-to-agent.ts
35679
36157
  async function sendPromptToAgent(options) {
35680
36158
  const {
35681
36159
  handle,
@@ -35693,107 +36171,54 @@ async function sendPromptToAgent(options) {
35693
36171
  cloudApiBaseUrl,
35694
36172
  getCloudAccessToken,
35695
36173
  e2ee,
35696
- attachments
36174
+ attachments,
36175
+ isNewSession = false
35697
36176
  } = options;
36177
+ let isPlanningSession = false;
35698
36178
  try {
35699
- let agentPromptText = promptText;
35700
- if (sessionId && cloudApiBaseUrl && getCloudAccessToken) {
35701
- agentPromptText = await enrichForkedSessionPromptForAgent({
35702
- sessionId,
35703
- promptText,
35704
- cloudApiBaseUrl,
35705
- getCloudAccessToken
35706
- });
35707
- }
35708
- if (sessionId) {
35709
- agentPromptText = enrichIntegrationContentPromptForAgent({
35710
- sessionId,
35711
- originalPromptText: promptText,
35712
- agentPromptText
35713
- });
35714
- }
35715
- let sendOpts = {};
35716
- if (attachments && attachments.length > 0) {
35717
- if (!sessionId || !cloudApiBaseUrl || !getCloudAccessToken) {
35718
- sendResult({
35719
- type: "prompt_result",
35720
- id: promptId,
35721
- ...sessionId ? { sessionId } : {},
35722
- ...runId ? { runId } : {},
35723
- success: false,
35724
- error: "Prompt includes images but the bridge is not configured with a cloud API URL and token to fetch them.",
35725
- ...followUpCatalogPromptId != null && followUpCatalogPromptId !== "" ? { followUpCatalogPromptId } : {},
35726
- ...augmentPromptResultAuthFields(agentType, "missing cloud for images download")
35727
- });
35728
- return;
35729
- }
35730
- const resolved = await fetchSessionAttachmentPayloadsForAgent({
35731
- attachments,
35732
- sessionId,
35733
- cloudApiBaseUrl,
35734
- getCloudAccessToken,
35735
- e2ee,
35736
- log: log2
35737
- });
35738
- if (!resolved.ok) {
35739
- sendResult({
35740
- type: "prompt_result",
35741
- id: promptId,
35742
- ...sessionId ? { sessionId } : {},
35743
- ...runId ? { runId } : {},
35744
- success: false,
35745
- error: resolved.error,
35746
- ...followUpCatalogPromptId != null && followUpCatalogPromptId !== "" ? { followUpCatalogPromptId } : {},
35747
- ...augmentPromptResultAuthFields(agentType, resolved.error)
35748
- });
35749
- return;
35750
- }
35751
- sendOpts = { images: resolved.images };
35752
- }
35753
- const result = await handle.sendPrompt(agentPromptText, sendOpts);
35754
- if (sessionId && runId && sendSessionUpdate && agentCwd && result.success) {
35755
- await collectTurnGitDiffFromPreTurnSnapshot({
35756
- sessionId,
35757
- runId,
35758
- agentCwd,
35759
- sendSessionUpdate,
35760
- log: log2
35761
- });
35762
- }
35763
- await maybeUploadE2eeSessionChangeSummariesAfterAgentSuccess({
36179
+ const prepared = await prepareAgentPromptText({
36180
+ promptText,
35764
36181
  sessionId,
35765
36182
  runId,
35766
- resultSuccess: result.success === true,
35767
- output: result.output,
35768
- e2ee,
36183
+ isNewSession,
36184
+ cloudApiBaseUrl,
36185
+ getCloudAccessToken
36186
+ });
36187
+ isPlanningSession = prepared.isPlanningSession;
36188
+ const imagesResolved = await resolveSendPromptImages({
36189
+ attachments,
36190
+ sessionId,
36191
+ promptId,
36192
+ runId,
36193
+ agentType,
36194
+ followUpCatalogPromptId,
35769
36195
  cloudApiBaseUrl,
35770
36196
  getCloudAccessToken,
36197
+ e2ee,
36198
+ log: log2
36199
+ });
36200
+ if (!imagesResolved.ok) {
36201
+ sendResult(imagesResolved.errorResult);
36202
+ return;
36203
+ }
36204
+ const result = await handle.sendPrompt(prepared.agentPromptText, imagesResolved.sendOpts);
36205
+ await finalizeAndSendPromptResult({
36206
+ result,
36207
+ sessionId,
36208
+ runId,
36209
+ promptId,
36210
+ agentType,
36211
+ agentCwd,
36212
+ isPlanningSession,
35771
36213
  followUpCatalogPromptId,
35772
36214
  sessionChangeSummaryFilePaths,
36215
+ cloudApiBaseUrl,
36216
+ getCloudAccessToken,
36217
+ e2ee,
36218
+ sendResult,
36219
+ sendSessionUpdate,
35773
36220
  log: log2
35774
36221
  });
35775
- const errStr = typeof result.error === "string" ? result.error : void 0;
35776
- const resultStop = typeof result.stopReason === "string" ? result.stopReason.trim() : "";
35777
- const cancelledByAgent = resultStop.toLowerCase() === "cancelled" || errStr != null && isUserEndedSessionTurnErrorText(errStr);
35778
- sendResult({
35779
- type: "prompt_result",
35780
- id: promptId,
35781
- ...sessionId ? { sessionId } : {},
35782
- ...runId ? { runId } : {},
35783
- ...result,
35784
- ...followUpCatalogPromptId != null && followUpCatalogPromptId !== "" ? { followUpCatalogPromptId } : {},
35785
- ...augmentPromptResultAuthFields(agentType, errStr),
35786
- ...!result.success && cancelledByAgent ? { stopReason: "cancelled" } : {}
35787
- });
35788
- if (!result.success) {
35789
- if (cancelledByAgent) {
35790
- log2("[Agent] Run ended after stop request (stopped by user).");
35791
- } else {
35792
- log2(
35793
- `[Agent] Prompt did not run successfully on the agent (no successful start/completion): ${result.error ?? "Unknown error"}`
35794
- );
35795
- }
35796
- }
35797
36222
  } catch (err) {
35798
36223
  const errMsg = err instanceof Error ? err.message : String(err);
35799
36224
  log2(`[Agent] Send failed: ${errMsg}`);
@@ -35807,6 +36232,8 @@ async function sendPromptToAgent(options) {
35807
36232
  ...followUpCatalogPromptId != null && followUpCatalogPromptId !== "" ? { followUpCatalogPromptId } : {},
35808
36233
  ...augmentPromptResultAuthFields(agentType, errMsg)
35809
36234
  });
36235
+ } finally {
36236
+ if (runId && isPlanningSession) clearPlanningSessionTurn(runId);
35810
36237
  }
35811
36238
  }
35812
36239
 
@@ -35820,15 +36247,36 @@ function getAcpSessionAgentState(ctx, acpSessionAgentKey) {
35820
36247
  return state;
35821
36248
  }
35822
36249
 
35823
- // src/agents/acp/manager/handle-prompt.ts
35824
- function handlePrompt(ctx, opts) {
36250
+ // src/agents/acp/manager/handle-pending-prompt-cancel.ts
36251
+ async function handlePendingPromptCancel(params) {
36252
+ const { ctx, activeRunId, promptId, sessionId, handle, sendResult } = params;
36253
+ if (!ctx.pendingCancelRunIds.has(activeRunId)) {
36254
+ return false;
36255
+ }
36256
+ ctx.pendingCancelRunIds.delete(activeRunId);
36257
+ try {
36258
+ await handle.cancel?.();
36259
+ } catch {
36260
+ }
36261
+ sendResult({
36262
+ type: "prompt_result",
36263
+ id: promptId,
36264
+ ...sessionId ? { sessionId } : {},
36265
+ runId: activeRunId,
36266
+ success: false,
36267
+ error: "Stopped by user",
36268
+ stopReason: "cancelled"
36269
+ });
36270
+ return true;
36271
+ }
36272
+
36273
+ // src/agents/acp/manager/run-acp-prompt.ts
36274
+ async function runAcpPrompt(ctx, runCtx, opts) {
35825
36275
  const {
35826
36276
  promptText,
35827
36277
  promptId,
35828
36278
  sessionId,
35829
- runId,
35830
36279
  mode,
35831
- agentType,
35832
36280
  agentConfig,
35833
36281
  sessionParentPath,
35834
36282
  sendResult,
@@ -35838,109 +36286,99 @@ function handlePrompt(ctx, opts) {
35838
36286
  cloudApiBaseUrl,
35839
36287
  getCloudAccessToken,
35840
36288
  e2ee,
35841
- attachments
36289
+ attachments,
36290
+ isNewSession
35842
36291
  } = opts;
35843
- const preferredForPrompt = agentType ?? ctx.backendFallbackAgentType ?? null;
35844
- if (!runId) {
35845
- ctx.log("[Agent] Prompt ignored: missing runId (cannot route session updates).");
35846
- return;
35847
- }
35848
- const activeRunId = runId;
35849
- const acpAgentKey = computeAcpAgentKey(preferredForPrompt, mode, agentConfig ?? null);
35850
- if (!acpAgentKey) {
36292
+ const { activeRunId, activeAcpAgentKey, activeAcpSessionAgentKey, preferredForPrompt } = runCtx;
36293
+ const acpAgentState = getAcpSessionAgentState(ctx, activeAcpSessionAgentKey);
36294
+ const handle = await ensureAcpClient({
36295
+ state: acpAgentState,
36296
+ acpAgentKey: activeAcpAgentKey,
36297
+ preferredAgentType: preferredForPrompt,
36298
+ mode,
36299
+ agentConfig: agentConfig ?? null,
36300
+ sessionParentPath,
36301
+ resolveRouting: () => ctx.promptRouting.resolveRouting(activeAcpSessionAgentKey),
36302
+ cloudSessionId: sessionId,
36303
+ bridgeAccessPort: ctx.getBridgeAccessPort(),
36304
+ sendSessionUpdate,
36305
+ sendRequest: sendSessionUpdate,
36306
+ log: ctx.log,
36307
+ reportAgentCapabilities: ctx.reportAgentCapabilities
36308
+ });
36309
+ if (!handle) {
36310
+ const errMsg = acpAgentState.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app.";
36311
+ const evaluated = Boolean(preferredForPrompt && errMsg.trim());
36312
+ const suggestsAuth = evaluated ? localAgentErrorSuggestsAuth(preferredForPrompt, errMsg) : false;
36313
+ const auth = suggestsAuth && preferredForPrompt ? { agentAuthRequired: true, agentType: preferredForPrompt } : {};
35851
36314
  sendResult({
35852
36315
  type: "prompt_result",
35853
36316
  id: promptId,
35854
36317
  ...sessionId ? { sessionId } : {},
35855
36318
  runId: activeRunId,
35856
36319
  success: false,
35857
- error: "No agent type: ensure the app sends agentType on prompts or agent_config for this bridge."
36320
+ error: errMsg,
36321
+ ...auth
35858
36322
  });
35859
36323
  return;
35860
36324
  }
35861
- const activeAcpAgentKey = acpAgentKey;
35862
- const activeAcpSessionAgentKey = computeAcpSessionAgentKey(sessionId, activeAcpAgentKey);
35863
- ctx.pendingCancelRunIds.delete(activeRunId);
35864
- ctx.promptRouting.registerRun({ sessionId, runId: activeRunId });
35865
- ctx.runDispatch.set(activeRunId, { acpSessionAgentKey: activeAcpSessionAgentKey });
35866
- async function run() {
35867
- const acpAgentState = getAcpSessionAgentState(ctx, activeAcpSessionAgentKey);
35868
- const handle = await ensureAcpClient({
35869
- state: acpAgentState,
35870
- acpAgentKey: activeAcpAgentKey,
35871
- preferredAgentType: preferredForPrompt,
35872
- mode,
35873
- agentConfig: agentConfig ?? null,
35874
- sessionParentPath,
35875
- resolveRouting: () => ctx.promptRouting.resolveRouting(activeAcpSessionAgentKey),
35876
- cloudSessionId: sessionId,
35877
- bridgeAccessPort: ctx.getBridgeAccessPort(),
36325
+ if (!ctx.promptRouting.isRegisteredRun(activeRunId)) {
36326
+ return;
36327
+ }
36328
+ const cancelled = await handlePendingPromptCancel({
36329
+ ctx,
36330
+ activeRunId,
36331
+ promptId,
36332
+ sessionId,
36333
+ handle,
36334
+ sendResult
36335
+ });
36336
+ if (cancelled) return;
36337
+ ctx.promptRouting.setStreamingRunId(activeAcpSessionAgentKey, activeRunId);
36338
+ try {
36339
+ await sendPromptToAgent({
36340
+ handle,
36341
+ promptText,
36342
+ promptId,
36343
+ sessionId,
36344
+ runId: activeRunId,
36345
+ agentType: preferredForPrompt,
36346
+ agentCwd: resolveSessionParentPathForAgentProcess(sessionParentPath),
36347
+ sendResult,
35878
36348
  sendSessionUpdate,
35879
- sendRequest: sendSessionUpdate,
35880
36349
  log: ctx.log,
35881
- reportAgentCapabilities: ctx.reportAgentCapabilities
36350
+ followUpCatalogPromptId,
36351
+ sessionChangeSummaryFilePaths,
36352
+ cloudApiBaseUrl,
36353
+ getCloudAccessToken,
36354
+ e2ee,
36355
+ attachments,
36356
+ isNewSession
35882
36357
  });
35883
- if (!handle) {
35884
- const errMsg = acpAgentState.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app.";
35885
- const evaluated = Boolean(preferredForPrompt && errMsg.trim());
35886
- const suggestsAuth = evaluated ? localAgentErrorSuggestsAuth(preferredForPrompt, errMsg) : false;
35887
- const auth = suggestsAuth && preferredForPrompt ? { agentAuthRequired: true, agentType: preferredForPrompt } : {};
35888
- sendResult({
35889
- type: "prompt_result",
35890
- id: promptId,
35891
- ...sessionId ? { sessionId } : {},
35892
- runId: activeRunId,
35893
- success: false,
35894
- error: errMsg,
35895
- ...auth
35896
- });
35897
- return;
35898
- }
35899
- if (!ctx.promptRouting.isRegisteredRun(activeRunId)) {
35900
- return;
35901
- }
35902
- if (ctx.pendingCancelRunIds.has(activeRunId)) {
35903
- ctx.pendingCancelRunIds.delete(activeRunId);
35904
- try {
35905
- await handle.cancel?.();
35906
- } catch {
35907
- }
36358
+ } finally {
36359
+ ctx.promptRouting.clearStreamingRunId(activeAcpSessionAgentKey, activeRunId);
36360
+ }
36361
+ }
36362
+
36363
+ // src/agents/acp/manager/handle-prompt.ts
36364
+ function handlePrompt(ctx, opts) {
36365
+ const { promptId, sessionId, runId, mode, agentType, agentConfig, sendResult } = opts;
36366
+ const runCtx = resolvePromptRunContext(ctx, { runId, mode, agentType, agentConfig, sessionId });
36367
+ if (!runCtx) {
36368
+ if (runId) {
35908
36369
  sendResult({
35909
36370
  type: "prompt_result",
35910
36371
  id: promptId,
35911
36372
  ...sessionId ? { sessionId } : {},
35912
- runId: activeRunId,
36373
+ runId,
35913
36374
  success: false,
35914
- error: "Stopped by user",
35915
- stopReason: "cancelled"
35916
- });
35917
- return;
35918
- }
35919
- ctx.promptRouting.setStreamingRunId(activeAcpSessionAgentKey, activeRunId);
35920
- try {
35921
- await sendPromptToAgent({
35922
- handle,
35923
- promptText,
35924
- promptId,
35925
- sessionId,
35926
- runId: activeRunId,
35927
- agentType: preferredForPrompt,
35928
- agentCwd: resolveSessionParentPathForAgentProcess(sessionParentPath),
35929
- sendResult,
35930
- sendSessionUpdate,
35931
- log: ctx.log,
35932
- followUpCatalogPromptId,
35933
- sessionChangeSummaryFilePaths,
35934
- cloudApiBaseUrl,
35935
- getCloudAccessToken,
35936
- e2ee,
35937
- attachments
36375
+ error: "No agent type: ensure the app sends agentType on prompts or agent_config for this bridge."
35938
36376
  });
35939
- } finally {
35940
- ctx.promptRouting.clearStreamingRunId(activeAcpSessionAgentKey, activeRunId);
35941
36377
  }
36378
+ return;
35942
36379
  }
35943
- void run().finally(() => {
36380
+ const { activeRunId } = runCtx;
36381
+ void runAcpPrompt(ctx, runCtx, opts).finally(() => {
35944
36382
  ctx.promptRouting.unregisterRun(activeRunId);
35945
36383
  ctx.runDispatch.delete(activeRunId);
35946
36384
  ctx.pendingCancelRunIds.delete(activeRunId);
@@ -36131,8 +36569,8 @@ function pathspec(...paths) {
36131
36569
  cache.set(key, paths);
36132
36570
  return key;
36133
36571
  }
36134
- function isPathSpec(path75) {
36135
- return path75 instanceof String && cache.has(path75);
36572
+ function isPathSpec(path76) {
36573
+ return path76 instanceof String && cache.has(path76);
36136
36574
  }
36137
36575
  function toPaths(pathSpec) {
36138
36576
  return cache.get(pathSpec) || [];
@@ -36221,8 +36659,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
36221
36659
  function forEachLineWithContent(input, callback) {
36222
36660
  return toLinesWithContent(input, true).map((line) => callback(line));
36223
36661
  }
36224
- function folderExists(path75) {
36225
- return (0, import_file_exists.exists)(path75, import_file_exists.FOLDER);
36662
+ function folderExists(path76) {
36663
+ return (0, import_file_exists.exists)(path76, import_file_exists.FOLDER);
36226
36664
  }
36227
36665
  function append(target, item) {
36228
36666
  if (Array.isArray(target)) {
@@ -36626,8 +37064,8 @@ function checkIsRepoRootTask() {
36626
37064
  commands,
36627
37065
  format: "utf-8",
36628
37066
  onError,
36629
- parser(path75) {
36630
- return /^\.(git)?$/.test(path75.trim());
37067
+ parser(path76) {
37068
+ return /^\.(git)?$/.test(path76.trim());
36631
37069
  }
36632
37070
  };
36633
37071
  }
@@ -37061,11 +37499,11 @@ function parseGrep(grep) {
37061
37499
  const paths = /* @__PURE__ */ new Set();
37062
37500
  const results = {};
37063
37501
  forEachLineWithContent(grep, (input) => {
37064
- const [path75, line, preview] = input.split(NULL);
37065
- paths.add(path75);
37066
- (results[path75] = results[path75] || []).push({
37502
+ const [path76, line, preview] = input.split(NULL);
37503
+ paths.add(path76);
37504
+ (results[path76] = results[path76] || []).push({
37067
37505
  line: asNumber(line),
37068
- path: path75,
37506
+ path: path76,
37069
37507
  preview
37070
37508
  });
37071
37509
  });
@@ -37830,14 +38268,14 @@ var init_hash_object = __esm2({
37830
38268
  init_task();
37831
38269
  }
37832
38270
  });
37833
- function parseInit(bare, path75, text) {
38271
+ function parseInit(bare, path76, text) {
37834
38272
  const response = String(text).trim();
37835
38273
  let result;
37836
38274
  if (result = initResponseRegex.exec(response)) {
37837
- return new InitSummary(bare, path75, false, result[1]);
38275
+ return new InitSummary(bare, path76, false, result[1]);
37838
38276
  }
37839
38277
  if (result = reInitResponseRegex.exec(response)) {
37840
- return new InitSummary(bare, path75, true, result[1]);
38278
+ return new InitSummary(bare, path76, true, result[1]);
37841
38279
  }
37842
38280
  let gitDir = "";
37843
38281
  const tokens = response.split(" ");
@@ -37848,7 +38286,7 @@ function parseInit(bare, path75, text) {
37848
38286
  break;
37849
38287
  }
37850
38288
  }
37851
- return new InitSummary(bare, path75, /^re/i.test(response), gitDir);
38289
+ return new InitSummary(bare, path76, /^re/i.test(response), gitDir);
37852
38290
  }
37853
38291
  var InitSummary;
37854
38292
  var initResponseRegex;
@@ -37857,9 +38295,9 @@ var init_InitSummary = __esm2({
37857
38295
  "src/lib/responses/InitSummary.ts"() {
37858
38296
  "use strict";
37859
38297
  InitSummary = class {
37860
- constructor(bare, path75, existing, gitDir) {
38298
+ constructor(bare, path76, existing, gitDir) {
37861
38299
  this.bare = bare;
37862
- this.path = path75;
38300
+ this.path = path76;
37863
38301
  this.existing = existing;
37864
38302
  this.gitDir = gitDir;
37865
38303
  }
@@ -37871,7 +38309,7 @@ var init_InitSummary = __esm2({
37871
38309
  function hasBareCommand(command) {
37872
38310
  return command.includes(bareCommand);
37873
38311
  }
37874
- function initTask(bare = false, path75, customArgs) {
38312
+ function initTask(bare = false, path76, customArgs) {
37875
38313
  const commands = ["init", ...customArgs];
37876
38314
  if (bare && !hasBareCommand(commands)) {
37877
38315
  commands.splice(1, 0, bareCommand);
@@ -37880,7 +38318,7 @@ function initTask(bare = false, path75, customArgs) {
37880
38318
  commands,
37881
38319
  format: "utf-8",
37882
38320
  parser(text) {
37883
- return parseInit(commands.includes("--bare"), path75, text);
38321
+ return parseInit(commands.includes("--bare"), path76, text);
37884
38322
  }
37885
38323
  };
37886
38324
  }
@@ -38696,12 +39134,12 @@ var init_FileStatusSummary = __esm2({
38696
39134
  "use strict";
38697
39135
  fromPathRegex = /^(.+)\0(.+)$/;
38698
39136
  FileStatusSummary = class {
38699
- constructor(path75, index, working_dir) {
38700
- this.path = path75;
39137
+ constructor(path76, index, working_dir) {
39138
+ this.path = path76;
38701
39139
  this.index = index;
38702
39140
  this.working_dir = working_dir;
38703
39141
  if (index === "R" || working_dir === "R") {
38704
- const detail = fromPathRegex.exec(path75) || [null, path75, path75];
39142
+ const detail = fromPathRegex.exec(path76) || [null, path76, path76];
38705
39143
  this.from = detail[2] || "";
38706
39144
  this.path = detail[1] || "";
38707
39145
  }
@@ -38732,14 +39170,14 @@ function splitLine(result, lineStr) {
38732
39170
  default:
38733
39171
  return;
38734
39172
  }
38735
- function data(index, workingDir, path75) {
39173
+ function data(index, workingDir, path76) {
38736
39174
  const raw = `${index}${workingDir}`;
38737
39175
  const handler = parsers6.get(raw);
38738
39176
  if (handler) {
38739
- handler(result, path75);
39177
+ handler(result, path76);
38740
39178
  }
38741
39179
  if (raw !== "##" && raw !== "!!") {
38742
- result.files.push(new FileStatusSummary(path75, index, workingDir));
39180
+ result.files.push(new FileStatusSummary(path76, index, workingDir));
38743
39181
  }
38744
39182
  }
38745
39183
  }
@@ -39048,9 +39486,9 @@ var init_simple_git_api = __esm2({
39048
39486
  next
39049
39487
  );
39050
39488
  }
39051
- hashObject(path75, write) {
39489
+ hashObject(path76, write) {
39052
39490
  return this._runTask(
39053
- hashObjectTask(path75, write === true),
39491
+ hashObjectTask(path76, write === true),
39054
39492
  trailingFunctionArgument(arguments)
39055
39493
  );
39056
39494
  }
@@ -39403,8 +39841,8 @@ var init_branch = __esm2({
39403
39841
  }
39404
39842
  });
39405
39843
  function toPath(input) {
39406
- const path75 = input.trim().replace(/^["']|["']$/g, "");
39407
- return path75 && normalize3(path75);
39844
+ const path76 = input.trim().replace(/^["']|["']$/g, "");
39845
+ return path76 && normalize3(path76);
39408
39846
  }
39409
39847
  var parseCheckIgnore;
39410
39848
  var init_CheckIgnore = __esm2({
@@ -39718,8 +40156,8 @@ __export2(sub_module_exports, {
39718
40156
  subModuleTask: () => subModuleTask,
39719
40157
  updateSubModuleTask: () => updateSubModuleTask
39720
40158
  });
39721
- function addSubModuleTask(repo, path75) {
39722
- return subModuleTask(["add", repo, path75]);
40159
+ function addSubModuleTask(repo, path76) {
40160
+ return subModuleTask(["add", repo, path76]);
39723
40161
  }
39724
40162
  function initSubModuleTask(customArgs) {
39725
40163
  return subModuleTask(["init", ...customArgs]);
@@ -40052,8 +40490,8 @@ var require_git = __commonJS2({
40052
40490
  }
40053
40491
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
40054
40492
  };
40055
- Git2.prototype.submoduleAdd = function(repo, path75, then) {
40056
- return this._runTask(addSubModuleTask2(repo, path75), trailingFunctionArgument2(arguments));
40493
+ Git2.prototype.submoduleAdd = function(repo, path76, then) {
40494
+ return this._runTask(addSubModuleTask2(repo, path76), trailingFunctionArgument2(arguments));
40057
40495
  };
40058
40496
  Git2.prototype.submoduleUpdate = function(args, then) {
40059
40497
  return this._runTask(
@@ -40789,8 +41227,8 @@ function parseNumstatEntries(lines) {
40789
41227
  }
40790
41228
  function parseNumstat(lines) {
40791
41229
  const m = /* @__PURE__ */ new Map();
40792
- for (const [path75, entry] of parseNumstatEntries(lines)) {
40793
- m.set(path75, { additions: entry.additions, deletions: entry.deletions });
41230
+ for (const [path76, entry] of parseNumstatEntries(lines)) {
41231
+ m.set(path76, { additions: entry.additions, deletions: entry.deletions });
40794
41232
  }
40795
41233
  return m;
40796
41234
  }
@@ -42097,18 +42535,32 @@ import * as fs28 from "node:fs";
42097
42535
  // src/git/worktrees/worktree-remove.ts
42098
42536
  import * as fs27 from "node:fs";
42099
42537
 
42538
+ // src/worktrees/is-removable-session-worktree-checkout-path.ts
42539
+ import path43 from "node:path";
42540
+ function isBridgeRootCheckoutPath(checkoutPath) {
42541
+ return normalizeResolvedPath(checkoutPath) === normalizeResolvedPath(getBridgeRoot());
42542
+ }
42543
+ function isRemovableSessionWorktreeCheckoutPath(checkoutPath, worktreesRootPath) {
42544
+ if (isBridgeRootCheckoutPath(checkoutPath)) return false;
42545
+ const normalized = normalizeResolvedPath(checkoutPath);
42546
+ const worktreesRoot = normalizeResolvedPath(worktreesRootPath);
42547
+ const rel = path43.relative(worktreesRoot, normalized);
42548
+ if (rel === "" || rel.startsWith("..") || path43.isAbsolute(rel)) return false;
42549
+ return true;
42550
+ }
42551
+
42100
42552
  // src/git/worktrees/resolve-main-repo-from-git-file.ts
42101
42553
  import * as fs26 from "node:fs";
42102
- import * as path43 from "node:path";
42554
+ import * as path44 from "node:path";
42103
42555
  function resolveMainRepoFromWorktreeGitFile(wt) {
42104
- const gitDirFile = path43.join(wt, ".git");
42556
+ const gitDirFile = path44.join(wt, ".git");
42105
42557
  if (!fs26.existsSync(gitDirFile) || !fs26.statSync(gitDirFile).isFile()) return "";
42106
42558
  const first2 = fs26.readFileSync(gitDirFile, "utf8").trim();
42107
42559
  const m = first2.match(/^gitdir:\s*(.+)$/im);
42108
42560
  if (!m) return "";
42109
- const gitWorktreePath = path43.resolve(wt, m[1].trim());
42110
- const gitDir = path43.dirname(path43.dirname(gitWorktreePath));
42111
- return path43.dirname(gitDir);
42561
+ const gitWorktreePath = path44.resolve(wt, m[1].trim());
42562
+ const gitDir = path44.dirname(path44.dirname(gitWorktreePath));
42563
+ return path44.dirname(gitDir);
42112
42564
  }
42113
42565
 
42114
42566
  // src/git/worktrees/worktree-remove.ts
@@ -42116,32 +42568,44 @@ async function gitWorktreeRemoveForce(worktreePath) {
42116
42568
  const mainRepo = resolveMainRepoFromWorktreeGitFile(worktreePath);
42117
42569
  if (mainRepo) {
42118
42570
  await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
42119
- } else {
42120
- fs27.rmSync(worktreePath, { recursive: true, force: true });
42571
+ return true;
42121
42572
  }
42573
+ if (isBridgeRootCheckoutPath(worktreePath)) return false;
42574
+ fs27.rmSync(worktreePath, { recursive: true, force: true });
42575
+ return true;
42122
42576
  }
42123
42577
 
42124
42578
  // src/worktrees/remove-session-worktrees.ts
42125
- async function removeSessionWorktrees(paths, log2) {
42579
+ async function removeSessionWorktrees(paths, worktreesRootPath, log2) {
42126
42580
  for (const wt of paths) {
42581
+ if (!isRemovableSessionWorktreeCheckoutPath(wt, worktreesRootPath)) {
42582
+ log2(`[worktrees] Skipping removal of ${wt} (bridge root or outside worktrees root).`);
42583
+ continue;
42584
+ }
42127
42585
  try {
42128
- await gitWorktreeRemoveForce(wt);
42129
- log2(`[worktrees] Removed worktree ${wt}`);
42586
+ const removed = await gitWorktreeRemoveForce(wt);
42587
+ if (removed) {
42588
+ log2(`[worktrees] Removed worktree ${wt}`);
42589
+ } else {
42590
+ log2(`[worktrees] Skipping removal of ${wt} (bridge root).`);
42591
+ }
42130
42592
  } catch (e) {
42131
42593
  log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
42132
- try {
42133
- fs28.rmSync(wt, { recursive: true, force: true });
42134
- } catch {
42594
+ if (isRemovableSessionWorktreeCheckoutPath(wt, worktreesRootPath)) {
42595
+ try {
42596
+ fs28.rmSync(wt, { recursive: true, force: true });
42597
+ } catch {
42598
+ }
42135
42599
  }
42136
42600
  }
42137
42601
  }
42138
42602
  }
42139
42603
 
42140
42604
  // src/worktrees/manager/git/remove-session-worktree-checkouts.ts
42141
- async function removeSessionWorktreeCheckouts(cache2, sessionId, log2) {
42605
+ async function removeSessionWorktreeCheckouts(cache2, sessionId, worktreesRootPath, log2) {
42142
42606
  const paths = cache2.clearSession(sessionId);
42143
42607
  if (!paths?.length) return;
42144
- await removeSessionWorktrees(paths, log2);
42608
+ await removeSessionWorktrees(paths, worktreesRootPath, log2);
42145
42609
  }
42146
42610
 
42147
42611
  // src/git/branches/rename-branch.ts
@@ -42174,11 +42638,11 @@ async function renameSessionWorktreeBranch(cache2, sessionId, newBranch, log2) {
42174
42638
 
42175
42639
  // src/worktrees/discovery/discover-session-worktree-on-disk.ts
42176
42640
  import * as fs32 from "node:fs";
42177
- import * as path48 from "node:path";
42641
+ import * as path49 from "node:path";
42178
42642
 
42179
42643
  // src/worktrees/discovery/collect-worktree-paths.ts
42180
42644
  import * as fs30 from "node:fs";
42181
- import * as path45 from "node:path";
42645
+ import * as path46 from "node:path";
42182
42646
 
42183
42647
  // src/worktrees/discovery/disk-walk-constants.ts
42184
42648
  var DISK_WALK_YIELD_EVERY = 64;
@@ -42207,7 +42671,7 @@ function shouldSkipDiskWalkEntry(name) {
42207
42671
 
42208
42672
  // src/worktrees/discovery/disk-walk-utils.ts
42209
42673
  import * as fs29 from "node:fs";
42210
- import * as path44 from "node:path";
42674
+ import * as path45 from "node:path";
42211
42675
  async function yieldDuringDiskWalk(state) {
42212
42676
  state.entries++;
42213
42677
  if (state.entries % DISK_WALK_YIELD_EVERY !== 0) return true;
@@ -42217,7 +42681,7 @@ async function yieldDuringDiskWalk(state) {
42217
42681
  }
42218
42682
  async function isGitDir(dirPath) {
42219
42683
  try {
42220
- await fs29.promises.access(path44.join(dirPath, ".git"));
42684
+ await fs29.promises.access(path45.join(dirPath, ".git"));
42221
42685
  return true;
42222
42686
  } catch {
42223
42687
  return false;
@@ -42231,7 +42695,7 @@ async function collectGitRepoRootsUnderDirectory(rootPath) {
42231
42695
  const walk = async (dir) => {
42232
42696
  if (!await yieldDuringDiskWalk(state)) return;
42233
42697
  if (await isGitDir(dir)) {
42234
- out.push(path45.resolve(dir));
42698
+ out.push(path46.resolve(dir));
42235
42699
  return;
42236
42700
  }
42237
42701
  let entries;
@@ -42242,12 +42706,12 @@ async function collectGitRepoRootsUnderDirectory(rootPath) {
42242
42706
  }
42243
42707
  for (const e of entries) {
42244
42708
  if (shouldSkipDiskWalkEntry(e.name)) continue;
42245
- const full = path45.join(dir, e.name);
42709
+ const full = path46.join(dir, e.name);
42246
42710
  if (!e.isDirectory()) continue;
42247
42711
  await walk(full);
42248
42712
  }
42249
42713
  };
42250
- await walk(path45.resolve(rootPath));
42714
+ await walk(path46.resolve(rootPath));
42251
42715
  return { paths: [...new Set(out)], entriesVisited: state.entries };
42252
42716
  }
42253
42717
  async function collectWorktreeRootsNamed(root, sessionId, maxDepth = LEGACY_WALK_MAX_DEPTH) {
@@ -42264,10 +42728,10 @@ async function collectWorktreeRootsNamed(root, sessionId, maxDepth = LEGACY_WALK
42264
42728
  }
42265
42729
  for (const e of entries) {
42266
42730
  if (shouldSkipDiskWalkEntry(e.name)) continue;
42267
- const full = path45.join(dir, e.name);
42731
+ const full = path46.join(dir, e.name);
42268
42732
  if (!e.isDirectory()) continue;
42269
42733
  if (e.name === sessionId) {
42270
- if (await isGitDir(full)) out.push(path45.resolve(full));
42734
+ if (await isGitDir(full)) out.push(path46.resolve(full));
42271
42735
  continue;
42272
42736
  }
42273
42737
  if (await isGitDir(full)) continue;
@@ -42279,14 +42743,14 @@ async function collectWorktreeRootsNamed(root, sessionId, maxDepth = LEGACY_WALK
42279
42743
  }
42280
42744
 
42281
42745
  // src/worktrees/discovery/layout-keys-for-bridge-root.ts
42282
- import * as path46 from "node:path";
42746
+ import * as path47 from "node:path";
42283
42747
  function layoutKeysForBridgeRoot(layout, bridgeRoot, keysOnDisk) {
42284
- const bridge = path46.resolve(bridgeRoot);
42748
+ const bridge = path47.resolve(bridgeRoot);
42285
42749
  const preferred = getLauncherDirNameIfPresent(layout, bridgeRoot);
42286
42750
  const relevant = layout.launcherCwds.filter((e) => {
42287
- const entry = path46.resolve(e.absolutePath);
42288
- return bridge === entry || bridge.startsWith(entry + path46.sep) || entry.startsWith(bridge + path46.sep);
42289
- }).sort((a, b) => path46.resolve(b.absolutePath).length - path46.resolve(a.absolutePath).length).map((e) => e.dirName).filter((name) => keysOnDisk.includes(name));
42751
+ const entry = path47.resolve(e.absolutePath);
42752
+ return bridge === entry || bridge.startsWith(entry + path47.sep) || entry.startsWith(bridge + path47.sep);
42753
+ }).sort((a, b) => path47.resolve(b.absolutePath).length - path47.resolve(a.absolutePath).length).map((e) => e.dirName).filter((name) => keysOnDisk.includes(name));
42290
42754
  const ordered = [];
42291
42755
  const seen = /* @__PURE__ */ new Set();
42292
42756
  const add = (k) => {
@@ -42305,7 +42769,7 @@ function layoutKeysForBridgeRoot(layout, bridgeRoot, keysOnDisk) {
42305
42769
 
42306
42770
  // src/worktrees/discovery/try-binding-from-session-directory.ts
42307
42771
  import * as fs31 from "node:fs";
42308
- import * as path47 from "node:path";
42772
+ import * as path48 from "node:path";
42309
42773
  async function tryBindingFromSessionDirectory(sessionDir) {
42310
42774
  let st;
42311
42775
  try {
@@ -42316,7 +42780,7 @@ async function tryBindingFromSessionDirectory(sessionDir) {
42316
42780
  if (!st.isDirectory()) return null;
42317
42781
  const { paths: worktreePaths } = await collectGitRepoRootsUnderDirectory(sessionDir);
42318
42782
  if (worktreePaths.length === 0) return null;
42319
- const abs = path47.resolve(sessionDir);
42783
+ const abs = path48.resolve(sessionDir);
42320
42784
  return {
42321
42785
  sessionParentPath: abs,
42322
42786
  workingTreeRelRoot: abs,
@@ -42340,7 +42804,7 @@ async function discoverSessionWorktreeOnDisk(options) {
42340
42804
  try {
42341
42805
  for (const name of await fs32.promises.readdir(worktreesRootPath)) {
42342
42806
  if (name.startsWith(".")) continue;
42343
- const p = path48.join(worktreesRootPath, name);
42807
+ const p = path49.join(worktreesRootPath, name);
42344
42808
  let st;
42345
42809
  try {
42346
42810
  st = await fs32.promises.stat(p);
@@ -42357,7 +42821,7 @@ async function discoverSessionWorktreeOnDisk(options) {
42357
42821
  for (const key of keys) {
42358
42822
  if (isCliImmediateShutdownRequested()) return null;
42359
42823
  await yieldToEventLoop();
42360
- const layoutRoot = path48.join(worktreesRootPath, key);
42824
+ const layoutRoot = path49.join(worktreesRootPath, key);
42361
42825
  let layoutSt;
42362
42826
  try {
42363
42827
  layoutSt = await fs32.promises.stat(layoutRoot);
@@ -42365,16 +42829,16 @@ async function discoverSessionWorktreeOnDisk(options) {
42365
42829
  continue;
42366
42830
  }
42367
42831
  if (!layoutSt.isDirectory()) continue;
42368
- const sessionDir = path48.join(layoutRoot, sid);
42832
+ const sessionDir = path49.join(layoutRoot, sid);
42369
42833
  const nested = await tryBindingFromSessionDirectory(sessionDir);
42370
42834
  if (nested) return nested;
42371
42835
  const legacy = await collectWorktreeRootsNamed(layoutRoot, sid);
42372
42836
  if (legacy.paths.length > 0) {
42373
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacy.paths) ?? path48.resolve(legacy.paths[0]);
42837
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacy.paths) ?? path49.resolve(legacy.paths[0]);
42374
42838
  return {
42375
- sessionParentPath: path48.resolve(isolated),
42376
- workingTreeRelRoot: path48.resolve(layoutRoot),
42377
- repoCheckoutPaths: legacy.paths.map((p) => path48.resolve(p))
42839
+ sessionParentPath: path49.resolve(isolated),
42840
+ workingTreeRelRoot: path49.resolve(layoutRoot),
42841
+ repoCheckoutPaths: legacy.paths.map((p) => path49.resolve(p))
42378
42842
  };
42379
42843
  }
42380
42844
  }
@@ -42383,29 +42847,29 @@ async function discoverSessionWorktreeOnDisk(options) {
42383
42847
 
42384
42848
  // src/worktrees/discovery/discover-session-worktrees-under-session-worktree-root.ts
42385
42849
  import * as fs33 from "node:fs";
42386
- import * as path50 from "node:path";
42850
+ import * as path51 from "node:path";
42387
42851
 
42388
42852
  // src/worktrees/discovery/discover-legacy-binding-ascending-from-checkout.ts
42389
- import * as path49 from "node:path";
42853
+ import * as path50 from "node:path";
42390
42854
  async function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
42391
42855
  const sid = sessionId.trim();
42392
42856
  if (!sid) return null;
42393
- const hintR = path49.resolve(checkoutPath);
42857
+ const hintR = path50.resolve(checkoutPath);
42394
42858
  let best = null;
42395
- let cur = path49.dirname(hintR);
42859
+ let cur = path50.dirname(hintR);
42396
42860
  for (let i = 0; i < 40; i++) {
42397
42861
  if (isCliImmediateShutdownRequested()) return best;
42398
42862
  await yieldToEventLoop();
42399
42863
  const paths = await collectWorktreeRootsNamed(cur, sid);
42400
- if (paths.paths.some((p) => path49.resolve(p) === hintR)) {
42401
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths.paths) ?? path49.resolve(paths.paths[0]);
42864
+ if (paths.paths.some((p) => path50.resolve(p) === hintR)) {
42865
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths.paths) ?? path50.resolve(paths.paths[0]);
42402
42866
  best = {
42403
- sessionParentPath: path49.resolve(isolated),
42404
- workingTreeRelRoot: path49.resolve(cur),
42405
- repoCheckoutPaths: paths.paths.map((p) => path49.resolve(p))
42867
+ sessionParentPath: path50.resolve(isolated),
42868
+ workingTreeRelRoot: path50.resolve(cur),
42869
+ repoCheckoutPaths: paths.paths.map((p) => path50.resolve(p))
42406
42870
  };
42407
42871
  }
42408
- const next = path49.dirname(cur);
42872
+ const next = path50.dirname(cur);
42409
42873
  if (next === cur) break;
42410
42874
  cur = next;
42411
42875
  }
@@ -42416,12 +42880,12 @@ async function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPat
42416
42880
  async function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
42417
42881
  const sid = sessionId.trim();
42418
42882
  if (!sid) return null;
42419
- const hint = path50.resolve(sessionWorktreeRootPathOrHint);
42420
- const underHint = await tryBindingFromSessionDirectory(path50.join(hint, sid));
42883
+ const hint = path51.resolve(sessionWorktreeRootPathOrHint);
42884
+ const underHint = await tryBindingFromSessionDirectory(path51.join(hint, sid));
42421
42885
  if (underHint) return underHint;
42422
42886
  const direct = await tryBindingFromSessionDirectory(hint);
42423
42887
  if (direct) {
42424
- if (path50.basename(hint) === sid && await isGitDir(hint)) {
42888
+ if (path51.basename(hint) === sid && await isGitDir(hint)) {
42425
42889
  const legacyFromCheckout = await discoverLegacyBindingAscendingFromCheckout(sid, hint);
42426
42890
  if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
42427
42891
  return legacyFromCheckout;
@@ -42429,7 +42893,7 @@ async function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeR
42429
42893
  }
42430
42894
  return direct;
42431
42895
  }
42432
- if (path50.basename(hint) === sid && await isGitDir(hint)) {
42896
+ if (path51.basename(hint) === sid && await isGitDir(hint)) {
42433
42897
  const legacyFromCheckout = await discoverLegacyBindingAscendingFromCheckout(sid, hint);
42434
42898
  if (legacyFromCheckout) return legacyFromCheckout;
42435
42899
  }
@@ -42442,11 +42906,11 @@ async function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeR
42442
42906
  if (!st.isDirectory()) return null;
42443
42907
  const legacyPaths = await collectWorktreeRootsNamed(hint, sid);
42444
42908
  if (legacyPaths.paths.length === 0) return null;
42445
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths.paths) ?? path50.resolve(legacyPaths.paths[0]);
42909
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths.paths) ?? path51.resolve(legacyPaths.paths[0]);
42446
42910
  return {
42447
- sessionParentPath: path50.resolve(isolated),
42911
+ sessionParentPath: path51.resolve(isolated),
42448
42912
  workingTreeRelRoot: hint,
42449
- repoCheckoutPaths: legacyPaths.paths.map((p) => path50.resolve(p))
42913
+ repoCheckoutPaths: legacyPaths.paths.map((p) => path51.resolve(p))
42450
42914
  };
42451
42915
  }
42452
42916
 
@@ -42508,11 +42972,11 @@ function parseSessionParent(v) {
42508
42972
 
42509
42973
  // src/worktrees/prepare-new-session-worktrees.ts
42510
42974
  import * as fs35 from "node:fs";
42511
- import * as path52 from "node:path";
42975
+ import * as path53 from "node:path";
42512
42976
 
42513
42977
  // src/git/discover-repos.ts
42514
42978
  import * as fs34 from "node:fs";
42515
- import * as path51 from "node:path";
42979
+ import * as path52 from "node:path";
42516
42980
  var GIT_DISCOVER_YIELD_EVERY = 32;
42517
42981
  async function yieldGitDiscoverWork(entryCount) {
42518
42982
  if (entryCount > 0 && entryCount % GIT_DISCOVER_YIELD_EVERY === 0) {
@@ -42521,7 +42985,7 @@ async function yieldGitDiscoverWork(entryCount) {
42521
42985
  }
42522
42986
  async function discoverGitRepos(cwd = getBridgeRoot()) {
42523
42987
  const result = [];
42524
- const cwdResolved = path51.resolve(cwd);
42988
+ const cwdResolved = path52.resolve(cwd);
42525
42989
  if (await isGitRepoDirectory(cwdResolved)) {
42526
42990
  const remoteUrl = await getRemoteOriginUrl(cwdResolved);
42527
42991
  result.push({ absolutePath: cwdResolved, remoteUrl });
@@ -42536,7 +43000,7 @@ async function discoverGitRepos(cwd = getBridgeRoot()) {
42536
43000
  await yieldGitDiscoverWork(i + 1);
42537
43001
  const ent = entries[i];
42538
43002
  if (!ent.isDirectory()) continue;
42539
- const childPath2 = path51.join(cwdResolved, ent.name);
43003
+ const childPath2 = path52.join(cwdResolved, ent.name);
42540
43004
  if (await isGitRepoDirectory(childPath2)) {
42541
43005
  const remoteUrl = await getRemoteOriginUrl(childPath2);
42542
43006
  result.push({ absolutePath: childPath2, remoteUrl });
@@ -42545,12 +43009,12 @@ async function discoverGitRepos(cwd = getBridgeRoot()) {
42545
43009
  return result;
42546
43010
  }
42547
43011
  async function discoverGitReposUnderRoot(rootPath) {
42548
- const root = path51.resolve(rootPath);
43012
+ const root = path52.resolve(rootPath);
42549
43013
  const roots = [];
42550
43014
  let walkEntries = 0;
42551
43015
  async function walk(dir) {
42552
43016
  if (await isGitRepoDirectory(dir)) {
42553
- roots.push(path51.resolve(dir));
43017
+ roots.push(path52.resolve(dir));
42554
43018
  return;
42555
43019
  }
42556
43020
  let entries;
@@ -42563,7 +43027,7 @@ async function discoverGitReposUnderRoot(rootPath) {
42563
43027
  await yieldGitDiscoverWork(++walkEntries);
42564
43028
  const ent = entries[i];
42565
43029
  if (!ent.isDirectory() || ent.name === ".git") continue;
42566
- await walk(path51.join(dir, ent.name));
43030
+ await walk(path52.join(dir, ent.name));
42567
43031
  }
42568
43032
  }
42569
43033
  await walk(root);
@@ -42598,10 +43062,10 @@ function resolveBaseRefForRepo(relNorm, baseBranches) {
42598
43062
  }
42599
43063
  async function prepareNewSessionWorktrees(options) {
42600
43064
  const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2, worktreeBaseBranches } = options;
42601
- const bridgeResolved = path52.resolve(bridgeRoot);
43065
+ const bridgeResolved = path53.resolve(bridgeRoot);
42602
43066
  const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
42603
- const bridgeKeyDir = path52.join(worktreesRootPath, cwdKey);
42604
- const sessionDir = path52.join(bridgeKeyDir, sessionId);
43067
+ const bridgeKeyDir = path53.join(worktreesRootPath, cwdKey);
43068
+ const sessionDir = path53.join(bridgeKeyDir, sessionId);
42605
43069
  const repos = await discoverGitReposUnderRoot(bridgeResolved);
42606
43070
  if (repos.length === 0) {
42607
43071
  log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
@@ -42611,12 +43075,12 @@ async function prepareNewSessionWorktrees(options) {
42611
43075
  const worktreePaths = [];
42612
43076
  fs35.mkdirSync(sessionDir, { recursive: true });
42613
43077
  for (const repo of repos) {
42614
- let rel = path52.relative(bridgeResolved, repo.absolutePath);
42615
- if (rel.startsWith("..") || path52.isAbsolute(rel)) continue;
43078
+ let rel = path53.relative(bridgeResolved, repo.absolutePath);
43079
+ if (rel.startsWith("..") || path53.isAbsolute(rel)) continue;
42616
43080
  const relNorm = normalizeRepoRelPath2(rel === "" ? "." : rel);
42617
- const wtPath = relNorm === "." ? sessionDir : path52.join(sessionDir, relNorm);
43081
+ const wtPath = relNorm === "." ? sessionDir : path53.join(sessionDir, relNorm);
42618
43082
  if (relNorm !== ".") {
42619
- fs35.mkdirSync(path52.dirname(wtPath), { recursive: true });
43083
+ fs35.mkdirSync(path53.dirname(wtPath), { recursive: true });
42620
43084
  }
42621
43085
  const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
42622
43086
  try {
@@ -42669,9 +43133,9 @@ async function resolveExistingSessionParentPath(sessionId, cache2, discover) {
42669
43133
  }
42670
43134
 
42671
43135
  // src/worktrees/manager/resolve-explicit-session-parent-path.ts
42672
- import * as path53 from "node:path";
43136
+ import * as path54 from "node:path";
42673
43137
  async function resolveExplicitSessionParentPath(params) {
42674
- const resolved = path53.resolve(params.parentPathRaw);
43138
+ const resolved = path54.resolve(params.parentPathRaw);
42675
43139
  if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
42676
43140
  return resolved;
42677
43141
  }
@@ -42688,7 +43152,7 @@ async function resolveExplicitSessionParentPath(params) {
42688
43152
  await yieldToEventLoop();
42689
43153
  const tryRoot = await discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
42690
43154
  if (tryRoot) return rememberAndReturn(tryRoot);
42691
- const next = path53.dirname(cur);
43155
+ const next = path54.dirname(cur);
42692
43156
  if (next === cur) break;
42693
43157
  cur = next;
42694
43158
  }
@@ -42798,7 +43262,7 @@ function createSessionWorktreeGitApi(ctx) {
42798
43262
  await renameSessionWorktreeBranch(ctx.cache, sessionId, newBranch, ctx.log);
42799
43263
  },
42800
43264
  async removeSessionWorktrees(sessionId) {
42801
- await removeSessionWorktreeCheckouts(ctx.cache, sessionId, ctx.log);
43265
+ await removeSessionWorktreeCheckouts(ctx.cache, sessionId, ctx.worktreesRootPath, ctx.log);
42802
43266
  },
42803
43267
  async commitSession(params) {
42804
43268
  return commitSessionWorktree(ctx.cache, params);
@@ -42827,17 +43291,17 @@ var SessionWorktreeManager = class {
42827
43291
  };
42828
43292
 
42829
43293
  // src/worktrees/manager/default-worktrees-root-path.ts
42830
- import * as path54 from "node:path";
43294
+ import * as path55 from "node:path";
42831
43295
  import os9 from "node:os";
42832
43296
  function defaultWorktreesRootPath() {
42833
- return path54.join(os9.homedir(), ".buildautomaton", "worktrees");
43297
+ return path55.join(os9.homedir(), ".buildautomaton", "worktrees");
42834
43298
  }
42835
43299
 
42836
43300
  // src/files/watch-file-index.ts
42837
- import path59 from "node:path";
43301
+ import path60 from "node:path";
42838
43302
 
42839
43303
  // src/files/index/build-file-index.ts
42840
- import path55 from "node:path";
43304
+ import path56 from "node:path";
42841
43305
 
42842
43306
  // src/files/index/file-index-sqlite-lock.ts
42843
43307
  var fileIndexChain = Promise.resolve();
@@ -42928,7 +43392,7 @@ function assertNotShutdown2() {
42928
43392
  if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
42929
43393
  }
42930
43394
  async function buildFileIndexAsync(cwd) {
42931
- const resolved = path55.resolve(cwd);
43395
+ const resolved = path56.resolve(cwd);
42932
43396
  await yieldToEventLoop();
42933
43397
  assertNotShutdown2();
42934
43398
  const paths = await collectWorkspacePathsAsync(resolved);
@@ -42941,7 +43405,7 @@ async function buildFileIndexAsync(cwd) {
42941
43405
  }
42942
43406
 
42943
43407
  // src/files/index/ensure-file-index.ts
42944
- import path56 from "node:path";
43408
+ import path57 from "node:path";
42945
43409
 
42946
43410
  // src/files/index/search-file-index.ts
42947
43411
  function escapeLikePattern(fragment) {
@@ -42993,7 +43457,7 @@ async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
42993
43457
 
42994
43458
  // src/files/index/ensure-file-index.ts
42995
43459
  async function ensureFileIndexAsync(cwd) {
42996
- const resolved = path56.resolve(cwd);
43460
+ const resolved = path57.resolve(cwd);
42997
43461
  if (await bridgeFileIndexIsPopulated(resolved)) {
42998
43462
  return { fromCache: true, pathCount: await bridgeFileIndexPathCount(resolved) };
42999
43463
  }
@@ -43042,10 +43506,10 @@ function createFileIndexFsWatcher(resolved, schedule) {
43042
43506
 
43043
43507
  // src/files/index/file-index-incremental-symbol-updates.ts
43044
43508
  import fs36 from "node:fs";
43045
- import path57 from "node:path";
43509
+ import path58 from "node:path";
43046
43510
  async function applyIncrementalSymbolIndexUpdates(resolved, relPaths) {
43047
43511
  for (const rel of relPaths) {
43048
- const absPath = path57.join(resolved, rel);
43512
+ const absPath = path58.join(resolved, rel);
43049
43513
  try {
43050
43514
  const stat3 = await fs36.promises.stat(absPath);
43051
43515
  if (stat3.isFile()) {
@@ -43065,9 +43529,9 @@ async function applyIncrementalSymbolIndexUpdates(resolved, relPaths) {
43065
43529
  }
43066
43530
 
43067
43531
  // src/files/index/file-index-initial-builds.ts
43068
- import path58 from "node:path";
43532
+ import path59 from "node:path";
43069
43533
  async function runInitialIndexBuilds(cwd = getBridgeRoot()) {
43070
- const resolved = path58.resolve(cwd);
43534
+ const resolved = path59.resolve(cwd);
43071
43535
  try {
43072
43536
  await buildFileIndexAsync(resolved);
43073
43537
  await buildSymbolIndexAsync(resolved);
@@ -43085,7 +43549,7 @@ function scheduleInitialIndexBuilds(cwd = getBridgeRoot()) {
43085
43549
  // src/files/watch-file-index.ts
43086
43550
  var MAX_INCREMENTAL_SYMBOL_UPDATES = 512;
43087
43551
  function startFileIndexWatcher(cwd = getBridgeRoot()) {
43088
- const resolved = path59.resolve(cwd);
43552
+ const resolved = path60.resolve(cwd);
43089
43553
  let timer = null;
43090
43554
  const pendingSymbolUpdates = /* @__PURE__ */ new Set();
43091
43555
  let needsFullSymbolRebuild = false;
@@ -43147,7 +43611,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
43147
43611
  }
43148
43612
 
43149
43613
  // src/connection/create-bridge-connection.ts
43150
- import * as path73 from "node:path";
43614
+ import * as path74 from "node:path";
43151
43615
 
43152
43616
  // src/dev-servers/manager/dev-server-manager.ts
43153
43617
  import { rm as rm2 } from "node:fs/promises";
@@ -43457,10 +43921,10 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
43457
43921
  import { spawn as spawn7 } from "node:child_process";
43458
43922
  import fs39 from "node:fs";
43459
43923
  import { tmpdir } from "node:os";
43460
- import path60 from "node:path";
43924
+ import path61 from "node:path";
43461
43925
  function trySpawnMergedLogFile(command, env, cwd, signal) {
43462
- const tmpRoot = fs39.mkdtempSync(path60.join(tmpdir(), "ba-devsrv-log-"));
43463
- const logPath = path60.join(tmpRoot, "combined.log");
43926
+ const tmpRoot = fs39.mkdtempSync(path61.join(tmpdir(), "ba-devsrv-log-"));
43927
+ const logPath = path61.join(tmpRoot, "combined.log");
43464
43928
  let logFd;
43465
43929
  try {
43466
43930
  logFd = fs39.openSync(logPath, "a");
@@ -43504,15 +43968,15 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
43504
43968
  import { spawn as spawn8 } from "node:child_process";
43505
43969
  import fs40 from "node:fs";
43506
43970
  import { tmpdir as tmpdir2 } from "node:os";
43507
- import path61 from "node:path";
43971
+ import path62 from "node:path";
43508
43972
  function shSingleQuote(s) {
43509
43973
  return `'${s.replace(/'/g, `'\\''`)}'`;
43510
43974
  }
43511
43975
  function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
43512
- const tmpRoot = fs40.mkdtempSync(path61.join(tmpdir2(), "ba-devsrv-sh-"));
43513
- const logPath = path61.join(tmpRoot, "combined.log");
43514
- const innerPath = path61.join(tmpRoot, "_cmd.sh");
43515
- const runnerPath = path61.join(tmpRoot, "_run.sh");
43976
+ const tmpRoot = fs40.mkdtempSync(path62.join(tmpdir2(), "ba-devsrv-sh-"));
43977
+ const logPath = path62.join(tmpRoot, "combined.log");
43978
+ const innerPath = path62.join(tmpRoot, "_cmd.sh");
43979
+ const runnerPath = path62.join(tmpRoot, "_run.sh");
43516
43980
  try {
43517
43981
  fs40.writeFileSync(innerPath, `#!/bin/sh
43518
43982
  ${command}
@@ -43543,9 +44007,9 @@ cd ${shSingleQuote(cwd)}
43543
44007
  }
43544
44008
  }
43545
44009
  function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
43546
- const tmpRoot = fs40.mkdtempSync(path61.join(tmpdir2(), "ba-devsrv-sh-"));
43547
- const logPath = path61.join(tmpRoot, "combined.log");
43548
- const runnerPath = path61.join(tmpRoot, "_run.bat");
44010
+ const tmpRoot = fs40.mkdtempSync(path62.join(tmpdir2(), "ba-devsrv-sh-"));
44011
+ const logPath = path62.join(tmpRoot, "combined.log");
44012
+ const runnerPath = path62.join(tmpRoot, "_run.bat");
43549
44013
  const q = (p) => `"${p.replace(/"/g, '""')}"`;
43550
44014
  const com = process.env.ComSpec || "cmd.exe";
43551
44015
  try {
@@ -44495,15 +44959,15 @@ async function yieldSkillDiscoveryWork(entryCount) {
44495
44959
 
44496
44960
  // src/skills/discovery/discover-local-skills.ts
44497
44961
  import fs41 from "node:fs";
44498
- import path62 from "node:path";
44962
+ import path63 from "node:path";
44499
44963
  function collectSkillFromDir(rel, base, name, seenKeys, out) {
44500
- const dir = path62.join(base, name);
44964
+ const dir = path63.join(base, name);
44501
44965
  try {
44502
44966
  if (!fs41.statSync(dir).isDirectory()) return;
44503
44967
  } catch {
44504
44968
  return;
44505
44969
  }
44506
- const skillMd = path62.join(dir, "SKILL.md");
44970
+ const skillMd = path63.join(dir, "SKILL.md");
44507
44971
  if (!fs41.existsSync(skillMd)) return;
44508
44972
  const key = `${rel}/${name}`;
44509
44973
  if (seenKeys.has(key)) return;
@@ -44516,7 +44980,7 @@ async function discoverLocalSkillsAsync(cwd) {
44516
44980
  let work = 0;
44517
44981
  for (const rel of SKILL_DISCOVERY_ROOTS) {
44518
44982
  await yieldSkillDiscoveryWork(++work);
44519
- const base = path62.join(cwd, rel);
44983
+ const base = path63.join(cwd, rel);
44520
44984
  if (!fs41.existsSync(base) || !fs41.statSync(base).isDirectory()) continue;
44521
44985
  let entries = [];
44522
44986
  try {
@@ -44534,15 +44998,15 @@ async function discoverLocalSkillsAsync(cwd) {
44534
44998
 
44535
44999
  // src/skills/discovery/discover-skill-layout-roots.ts
44536
45000
  import fs42 from "node:fs";
44537
- import path63 from "node:path";
45001
+ import path64 from "node:path";
44538
45002
  function collectLayoutSkill(rel, base, name, skills2) {
44539
- const dir = path63.join(base, name);
45003
+ const dir = path64.join(base, name);
44540
45004
  try {
44541
45005
  if (!fs42.statSync(dir).isDirectory()) return;
44542
45006
  } catch {
44543
45007
  return;
44544
45008
  }
44545
- if (!fs42.existsSync(path63.join(dir, "SKILL.md"))) return;
45009
+ if (!fs42.existsSync(path64.join(dir, "SKILL.md"))) return;
44546
45010
  const relPath = `${rel}/${name}`.replace(/\\/g, "/");
44547
45011
  skills2.push({ name, relPath });
44548
45012
  }
@@ -44551,7 +45015,7 @@ async function discoverSkillLayoutRootsAsync(cwd) {
44551
45015
  let work = 0;
44552
45016
  for (const rel of SKILL_DISCOVERY_ROOTS) {
44553
45017
  await yieldSkillDiscoveryWork(++work);
44554
- const base = path63.join(cwd, rel);
45018
+ const base = path64.join(cwd, rel);
44555
45019
  if (!fs42.existsSync(base) || !fs42.statSync(base).isDirectory()) continue;
44556
45020
  let entries = [];
44557
45021
  try {
@@ -44903,7 +45367,7 @@ import fs44 from "node:fs";
44903
45367
 
44904
45368
  // src/git/snapshot/capture.ts
44905
45369
  import * as fs43 from "node:fs";
44906
- import * as path64 from "node:path";
45370
+ import * as path65 from "node:path";
44907
45371
 
44908
45372
  // src/git/snapshot/git.ts
44909
45373
  async function gitStashCreate(repoRoot, log2) {
@@ -44943,7 +45407,7 @@ async function gitRun(repoRoot, args, log2, label) {
44943
45407
  async function resolveSnapshotRepoRoots(options) {
44944
45408
  const { worktreePaths, fallbackCwd, sessionId, log: log2 } = options;
44945
45409
  if (worktreePaths?.length) {
44946
- const uniq = [...new Set(worktreePaths.map((p) => path64.resolve(p)))];
45410
+ const uniq = [...new Set(worktreePaths.map((p) => path65.resolve(p)))];
44947
45411
  return uniq;
44948
45412
  }
44949
45413
  try {
@@ -44951,7 +45415,7 @@ async function resolveSnapshotRepoRoots(options) {
44951
45415
  const mapped = repos.map((r) => r.absolutePath);
44952
45416
  const sid = sessionId?.trim();
44953
45417
  if (sid) {
44954
- const filtered = mapped.filter((root) => path64.basename(root) === sid);
45418
+ const filtered = mapped.filter((root) => path65.basename(root) === sid);
44955
45419
  if (filtered.length > 0) return filtered;
44956
45420
  }
44957
45421
  return mapped;
@@ -44982,7 +45446,7 @@ async function capturePreTurnSnapshot(options) {
44982
45446
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
44983
45447
  repos
44984
45448
  };
44985
- const filePath = path64.join(dir, `${runId}.json`);
45449
+ const filePath = path65.join(dir, `${runId}.json`);
44986
45450
  try {
44987
45451
  fs43.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
44988
45452
  } catch (e) {
@@ -45325,9 +45789,9 @@ function parseChangeSummarySnapshots(raw) {
45325
45789
  for (const item of raw) {
45326
45790
  if (!item || typeof item !== "object") continue;
45327
45791
  const o = item;
45328
- const path75 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
45329
- if (!path75) continue;
45330
- const row = { path: path75 };
45792
+ const path76 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
45793
+ if (!path76) continue;
45794
+ const row = { path: path76 };
45331
45795
  if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
45332
45796
  if (typeof o.oldText === "string") row.oldText = o.oldText;
45333
45797
  if (typeof o.newText === "string") row.newText = o.newText;
@@ -45406,7 +45870,8 @@ async function runPreambleAndPrompt(params) {
45406
45870
  cloudApiBaseUrl: deps.cloudApiBaseUrl,
45407
45871
  getCloudAccessToken: deps.getCloudAccessToken,
45408
45872
  e2ee: deps.e2ee,
45409
- ...attachments.length > 0 ? { attachments } : {}
45873
+ ...attachments.length > 0 ? { attachments } : {},
45874
+ isNewSession: msg.isNewSession === true
45410
45875
  });
45411
45876
  }
45412
45877
 
@@ -45537,8 +46002,8 @@ function randomSecret() {
45537
46002
  }
45538
46003
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
45539
46004
  }
45540
- async function requestPreviewApi(port, secret, method, path75, body) {
45541
- const url2 = `http://127.0.0.1:${port}${path75}`;
46005
+ async function requestPreviewApi(port, secret, method, path76, body) {
46006
+ const url2 = `http://127.0.0.1:${port}${path76}`;
45542
46007
  const headers = {
45543
46008
  [PREVIEW_SECRET_HEADER]: secret,
45544
46009
  "Content-Type": "application/json"
@@ -45550,7 +46015,7 @@ async function requestPreviewApi(port, secret, method, path75, body) {
45550
46015
  });
45551
46016
  const data = await res.json().catch(() => ({}));
45552
46017
  if (!res.ok) {
45553
- throw new Error(data?.error ?? `Preview API ${method} ${path75}: ${res.status}`);
46018
+ throw new Error(data?.error ?? `Preview API ${method} ${path76}: ${res.status}`);
45554
46019
  }
45555
46020
  return data;
45556
46021
  }
@@ -45729,11 +46194,11 @@ async function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId
45729
46194
  import fs46 from "node:fs";
45730
46195
 
45731
46196
  // src/files/ensure-under-cwd.ts
45732
- import path65 from "node:path";
46197
+ import path66 from "node:path";
45733
46198
  function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
45734
- const normalized = path65.normalize(relativePath).replace(/^(\.\/)+/, "");
45735
- const resolved = path65.resolve(cwd, normalized);
45736
- if (!resolved.startsWith(cwd + path65.sep) && resolved !== cwd) {
46199
+ const normalized = path66.normalize(relativePath).replace(/^(\.\/)+/, "");
46200
+ const resolved = path66.resolve(cwd, normalized);
46201
+ if (!resolved.startsWith(cwd + path66.sep) && resolved !== cwd) {
45737
46202
  return null;
45738
46203
  }
45739
46204
  return resolved;
@@ -45743,11 +46208,11 @@ function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
45743
46208
  var LIST_DIR_YIELD_EVERY = 256;
45744
46209
 
45745
46210
  // src/files/list-dir/map-dir-entry.ts
45746
- import path66 from "node:path";
46211
+ import path67 from "node:path";
45747
46212
  import fs45 from "node:fs";
45748
46213
  async function mapDirEntry(d, relativePath, resolved) {
45749
- const entryPath = path66.join(relativePath || ".", d.name).replace(/\\/g, "/");
45750
- const fullPath = path66.join(resolved, d.name);
46214
+ const entryPath = path67.join(relativePath || ".", d.name).replace(/\\/g, "/");
46215
+ const fullPath = path67.join(resolved, d.name);
45751
46216
  let isDir = d.isDirectory();
45752
46217
  if (d.isSymbolicLink()) {
45753
46218
  try {
@@ -45797,13 +46262,13 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
45797
46262
  }
45798
46263
 
45799
46264
  // src/files/handle-file-browser-search.ts
45800
- import path67 from "node:path";
46265
+ import path68 from "node:path";
45801
46266
  var SEARCH_LIMIT = 100;
45802
46267
  function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
45803
46268
  void (async () => {
45804
46269
  await yieldToEventLoop();
45805
46270
  const q = typeof msg.q === "string" ? msg.q : "";
45806
- const sessionParentPath = path67.resolve(
46271
+ const sessionParentPath = path68.resolve(
45807
46272
  sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
45808
46273
  );
45809
46274
  if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
@@ -46013,13 +46478,13 @@ function triggerSymbolIndexBuild(parentPath) {
46013
46478
  }
46014
46479
 
46015
46480
  // src/git/tree/resolve-repo-abs-path.ts
46016
- import * as path68 from "node:path";
46481
+ import * as path69 from "node:path";
46017
46482
  function resolveRepoAbsPathFromBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
46018
- const bridgeResolved = path68.resolve(bridgeRoot);
46483
+ const bridgeResolved = path69.resolve(bridgeRoot);
46019
46484
  const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
46020
- const repoPath = rel === "" ? bridgeResolved : path68.join(bridgeResolved, rel);
46021
- const resolved = path68.resolve(repoPath);
46022
- if (!resolved.startsWith(bridgeResolved + path68.sep) && resolved !== bridgeResolved) {
46485
+ const repoPath = rel === "" ? bridgeResolved : path69.join(bridgeResolved, rel);
46486
+ const resolved = path69.resolve(repoPath);
46487
+ if (!resolved.startsWith(bridgeResolved + path69.sep) && resolved !== bridgeResolved) {
46023
46488
  return null;
46024
46489
  }
46025
46490
  return resolved;
@@ -46802,7 +47267,7 @@ function isValidRemoteSkillInstallItem(item) {
46802
47267
 
46803
47268
  // src/skills/install/install-remote-skills-async.ts
46804
47269
  import fs50 from "node:fs";
46805
- import path69 from "node:path";
47270
+ import path70 from "node:path";
46806
47271
 
46807
47272
  // src/skills/install/constants.ts
46808
47273
  var INSTALL_SKILLS_YIELD_EVERY = 16;
@@ -46813,8 +47278,8 @@ async function writeInstallFileAsync(skillDir, f, filesWritten) {
46813
47278
  if (++filesWritten.count % INSTALL_SKILLS_YIELD_EVERY === 0) {
46814
47279
  await yieldToEventLoop();
46815
47280
  }
46816
- const dest = path69.join(skillDir, f.path);
46817
- await fs50.promises.mkdir(path69.dirname(dest), { recursive: true });
47281
+ const dest = path70.join(skillDir, f.path);
47282
+ await fs50.promises.mkdir(path70.dirname(dest), { recursive: true });
46818
47283
  if (f.text !== void 0) {
46819
47284
  await fs50.promises.writeFile(dest, f.text, "utf8");
46820
47285
  } else if (f.base64) {
@@ -46830,7 +47295,7 @@ async function installRemoteSkillsAsync(cwd, targetDir, items) {
46830
47295
  try {
46831
47296
  for (const item of items) {
46832
47297
  if (!isValidRemoteSkillInstallItem(item)) continue;
46833
- const skillDir = path69.join(cwd, targetDir, item.skillName);
47298
+ const skillDir = path70.join(cwd, targetDir, item.skillName);
46834
47299
  for (const f of item.files) {
46835
47300
  await writeInstallFileAsync(skillDir, f, filesWritten);
46836
47301
  }
@@ -47169,7 +47634,7 @@ var handleDevServersConfig = (msg, deps) => {
47169
47634
  };
47170
47635
 
47171
47636
  // src/git/bridge-git-context.ts
47172
- import * as path70 from "node:path";
47637
+ import * as path71 from "node:path";
47173
47638
 
47174
47639
  // src/git/branches/get-current-branch.ts
47175
47640
  async function getCurrentBranch(repoPath) {
@@ -47219,12 +47684,12 @@ async function listRepoBranchRefs(repoPath) {
47219
47684
  // src/git/bridge-git-context.ts
47220
47685
  function folderNameForRelPath(relPath, bridgeRoot) {
47221
47686
  if (relPath === "." || relPath === "") {
47222
- return path70.basename(path70.resolve(bridgeRoot)) || "repo";
47687
+ return path71.basename(path71.resolve(bridgeRoot)) || "repo";
47223
47688
  }
47224
- return path70.basename(relPath) || relPath;
47689
+ return path71.basename(relPath) || relPath;
47225
47690
  }
47226
47691
  async function discoverGitReposForBridgeContext(bridgeRoot) {
47227
- const root = path70.resolve(bridgeRoot);
47692
+ const root = path71.resolve(bridgeRoot);
47228
47693
  if (await isGitRepoDirectory(root)) {
47229
47694
  const remoteUrl = await getRemoteOriginUrl(root);
47230
47695
  return [{ absolutePath: root, remoteUrl }];
@@ -47232,19 +47697,19 @@ async function discoverGitReposForBridgeContext(bridgeRoot) {
47232
47697
  const [deep, shallow] = await Promise.all([discoverGitReposUnderRoot(root), discoverGitRepos(root)]);
47233
47698
  const byPath = /* @__PURE__ */ new Map();
47234
47699
  for (const repo of [...deep, ...shallow]) {
47235
- byPath.set(path70.resolve(repo.absolutePath), repo);
47700
+ byPath.set(path71.resolve(repo.absolutePath), repo);
47236
47701
  }
47237
47702
  return [...byPath.values()];
47238
47703
  }
47239
47704
  async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
47240
- const bridgeResolved = path70.resolve(bridgeRoot);
47705
+ const bridgeResolved = path71.resolve(bridgeRoot);
47241
47706
  const repos = await discoverGitReposForBridgeContext(bridgeResolved);
47242
47707
  const rows = [];
47243
47708
  for (let i = 0; i < repos.length; i++) {
47244
47709
  if (i > 0) await yieldToEventLoop();
47245
47710
  const repo = repos[i];
47246
- let rel = path70.relative(bridgeResolved, repo.absolutePath);
47247
- if (rel.startsWith("..") || path70.isAbsolute(rel)) continue;
47711
+ let rel = path71.relative(bridgeResolved, repo.absolutePath);
47712
+ if (rel.startsWith("..") || path71.isAbsolute(rel)) continue;
47248
47713
  const relPath = rel === "" ? "." : rel.replace(/\\/g, "/");
47249
47714
  const currentBranch = await getCurrentBranch(repo.absolutePath);
47250
47715
  const remoteUrl = repo.remoteUrl.trim() || null;
@@ -47259,11 +47724,11 @@ async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
47259
47724
  return rows;
47260
47725
  }
47261
47726
  async function listRepoBranchesForBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
47262
- const bridgeResolved = path70.resolve(bridgeRoot);
47727
+ const bridgeResolved = path71.resolve(bridgeRoot);
47263
47728
  const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
47264
- const repoPath = rel === "" ? bridgeResolved : path70.join(bridgeResolved, rel);
47265
- const resolved = path70.resolve(repoPath);
47266
- if (!resolved.startsWith(bridgeResolved + path70.sep) && resolved !== bridgeResolved) {
47729
+ const repoPath = rel === "" ? bridgeResolved : path71.join(bridgeResolved, rel);
47730
+ const resolved = path71.resolve(repoPath);
47731
+ if (!resolved.startsWith(bridgeResolved + path71.sep) && resolved !== bridgeResolved) {
47267
47732
  return [];
47268
47733
  }
47269
47734
  return listRepoBranchRefs(resolved);
@@ -48140,7 +48605,7 @@ async function createBridgeAccessState(options = {}) {
48140
48605
  }
48141
48606
 
48142
48607
  // src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
48143
- import * as path72 from "node:path";
48608
+ import * as path73 from "node:path";
48144
48609
 
48145
48610
  // src/sqlite/hash-json-sha256.ts
48146
48611
  import { createHash as createHash2 } from "node:crypto";
@@ -48207,7 +48672,7 @@ function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
48207
48672
  }
48208
48673
 
48209
48674
  // src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
48210
- import * as path71 from "node:path";
48675
+ import * as path72 from "node:path";
48211
48676
  async function probeOneAgentTypeForCapabilities(params) {
48212
48677
  const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true, shouldContinue } = params;
48213
48678
  const canContinue = () => shouldContinue?.() !== false;
@@ -48245,7 +48710,7 @@ async function probeOneAgentTypeForCapabilities(params) {
48245
48710
  if (!canContinue()) return false;
48246
48711
  handle = await resolved.createClient({
48247
48712
  command: resolved.command,
48248
- cwd: path71.resolve(cwd),
48713
+ cwd: path72.resolve(cwd),
48249
48714
  backendAgentType: agentType,
48250
48715
  sessionMode: "agent",
48251
48716
  persistedAcpSessionId: null,
@@ -48323,7 +48788,7 @@ async function warmupAgentCapabilitiesOnConnect(params) {
48323
48788
  const { workspaceId, log: log2, getWs } = params;
48324
48789
  const isCurrent = beginAgentCapabilityWarmupRun();
48325
48790
  if (!isCurrent()) return;
48326
- const cwd = path72.resolve(getBridgeRoot());
48791
+ const cwd = path73.resolve(getBridgeRoot());
48327
48792
  async function sendBatchFromCache() {
48328
48793
  if (!isCurrent()) return;
48329
48794
  const socket = getWs();
@@ -48558,8 +49023,8 @@ async function createBridgeConnection(options) {
48558
49023
  getCloudAccessToken: () => tokens.accessToken
48559
49024
  });
48560
49025
  const identifyReportedPaths = {
48561
- bridgeRootPath: path73.resolve(getBridgeRoot()),
48562
- worktreesRootPath: path73.resolve(worktreesRootPath)
49026
+ bridgeRootPath: path74.resolve(getBridgeRoot()),
49027
+ worktreesRootPath: path74.resolve(worktreesRootPath)
48563
49028
  };
48564
49029
  const { connect } = createMainBridgeWebSocketLifecycle({
48565
49030
  state,
@@ -48816,7 +49281,7 @@ async function runCliAction(program2, opts) {
48816
49281
  const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
48817
49282
  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);
48818
49283
  if (bridgeRootOpt) {
48819
- const resolvedBridgeRoot = path74.resolve(process.cwd(), bridgeRootOpt);
49284
+ const resolvedBridgeRoot = path75.resolve(process.cwd(), bridgeRootOpt);
48820
49285
  try {
48821
49286
  const st = fs52.statSync(resolvedBridgeRoot);
48822
49287
  if (!st.isDirectory()) {
@@ -48838,7 +49303,7 @@ async function runCliAction(program2, opts) {
48838
49303
  );
48839
49304
  let worktreesRootPath;
48840
49305
  if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
48841
- worktreesRootPath = path74.resolve(opts.worktreesRoot.trim());
49306
+ worktreesRootPath = path75.resolve(opts.worktreesRoot.trim());
48842
49307
  }
48843
49308
  const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
48844
49309
  if (e2eCertificates) {