@buildautomaton/cli 0.1.19 → 0.1.21

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
@@ -974,7 +974,7 @@ var require_command = __commonJS({
974
974
  var EventEmitter2 = __require("node:events").EventEmitter;
975
975
  var childProcess2 = __require("node:child_process");
976
976
  var path36 = __require("node:path");
977
- var fs32 = __require("node:fs");
977
+ var fs34 = __require("node:fs");
978
978
  var process8 = __require("node:process");
979
979
  var { Argument: Argument2, humanReadableArgName } = require_argument();
980
980
  var { CommanderError: CommanderError2 } = require_error();
@@ -1907,10 +1907,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
1907
1907
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1908
1908
  function findFile(baseDir, baseName) {
1909
1909
  const localBin = path36.resolve(baseDir, baseName);
1910
- if (fs32.existsSync(localBin)) return localBin;
1910
+ if (fs34.existsSync(localBin)) return localBin;
1911
1911
  if (sourceExt.includes(path36.extname(baseName))) return void 0;
1912
1912
  const foundExt = sourceExt.find(
1913
- (ext) => fs32.existsSync(`${localBin}${ext}`)
1913
+ (ext) => fs34.existsSync(`${localBin}${ext}`)
1914
1914
  );
1915
1915
  if (foundExt) return `${localBin}${foundExt}`;
1916
1916
  return void 0;
@@ -1922,7 +1922,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1922
1922
  if (this._scriptPath) {
1923
1923
  let resolvedScriptPath;
1924
1924
  try {
1925
- resolvedScriptPath = fs32.realpathSync(this._scriptPath);
1925
+ resolvedScriptPath = fs34.realpathSync(this._scriptPath);
1926
1926
  } catch (err) {
1927
1927
  resolvedScriptPath = this._scriptPath;
1928
1928
  }
@@ -5236,7 +5236,7 @@ var require_websocket = __commonJS({
5236
5236
  var http = __require("http");
5237
5237
  var net = __require("net");
5238
5238
  var tls = __require("tls");
5239
- var { randomBytes: randomBytes3, createHash: createHash3 } = __require("crypto");
5239
+ var { randomBytes: randomBytes3, createHash: createHash2 } = __require("crypto");
5240
5240
  var { Duplex, Readable: Readable2 } = __require("stream");
5241
5241
  var { URL: URL2 } = __require("url");
5242
5242
  var PerMessageDeflate = require_permessage_deflate();
@@ -5896,7 +5896,7 @@ var require_websocket = __commonJS({
5896
5896
  abortHandshake(websocket, socket, "Invalid Upgrade header");
5897
5897
  return;
5898
5898
  }
5899
- const digest = createHash3("sha1").update(key + GUID).digest("base64");
5899
+ const digest = createHash2("sha1").update(key + GUID).digest("base64");
5900
5900
  if (res.headers["sec-websocket-accept"] !== digest) {
5901
5901
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
5902
5902
  return;
@@ -6263,7 +6263,7 @@ var require_websocket_server = __commonJS({
6263
6263
  var EventEmitter2 = __require("events");
6264
6264
  var http = __require("http");
6265
6265
  var { Duplex } = __require("stream");
6266
- var { createHash: createHash3 } = __require("crypto");
6266
+ var { createHash: createHash2 } = __require("crypto");
6267
6267
  var extension = require_extension();
6268
6268
  var PerMessageDeflate = require_permessage_deflate();
6269
6269
  var subprotocol = require_subprotocol();
@@ -6564,7 +6564,7 @@ var require_websocket_server = __commonJS({
6564
6564
  );
6565
6565
  }
6566
6566
  if (this._state > RUNNING) return abortHandshake(socket, 503);
6567
- const digest = createHash3("sha1").update(key + GUID).digest("base64");
6567
+ const digest = createHash2("sha1").update(key + GUID).digest("base64");
6568
6568
  const headers = [
6569
6569
  "HTTP/1.1 101 Switching Protocols",
6570
6570
  "Upgrade: websocket",
@@ -7129,7 +7129,7 @@ var require_has_flag = __commonJS({
7129
7129
  var require_supports_color = __commonJS({
7130
7130
  "../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports, module) {
7131
7131
  "use strict";
7132
- var os6 = __require("os");
7132
+ var os7 = __require("os");
7133
7133
  var tty = __require("tty");
7134
7134
  var hasFlag = require_has_flag();
7135
7135
  var { env } = process;
@@ -7177,7 +7177,7 @@ var require_supports_color = __commonJS({
7177
7177
  return min;
7178
7178
  }
7179
7179
  if (process.platform === "win32") {
7180
- const osRelease = os6.release().split(".");
7180
+ const osRelease = os7.release().split(".");
7181
7181
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
7182
7182
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
7183
7183
  }
@@ -24800,8 +24800,8 @@ var init_acp = __esm({
24800
24800
  this.#requestHandler = requestHandler;
24801
24801
  this.#notificationHandler = notificationHandler;
24802
24802
  this.#stream = stream;
24803
- this.#closedPromise = new Promise((resolve19) => {
24804
- this.#abortController.signal.addEventListener("abort", () => resolve19());
24803
+ this.#closedPromise = new Promise((resolve18) => {
24804
+ this.#abortController.signal.addEventListener("abort", () => resolve18());
24805
24805
  });
24806
24806
  this.#receive();
24807
24807
  }
@@ -24950,8 +24950,8 @@ var init_acp = __esm({
24950
24950
  }
24951
24951
  async sendRequest(method, params) {
24952
24952
  const id = this.#nextRequestId++;
24953
- const responsePromise = new Promise((resolve19, reject) => {
24954
- this.#pendingResponses.set(id, { resolve: resolve19, reject });
24953
+ const responsePromise = new Promise((resolve18, reject) => {
24954
+ this.#pendingResponses.set(id, { resolve: resolve18, reject });
24955
24955
  });
24956
24956
  await this.#sendMessage({ jsonrpc: "2.0", id, method, params });
24957
24957
  return responsePromise;
@@ -25064,14 +25064,14 @@ var {
25064
25064
  } = import_index.default;
25065
25065
 
25066
25066
  // src/cli-version.ts
25067
- var CLI_VERSION = "0.1.19".length > 0 ? "0.1.19" : "0.0.0-dev";
25067
+ var CLI_VERSION = "0.1.21".length > 0 ? "0.1.21" : "0.0.0-dev";
25068
25068
 
25069
25069
  // src/cli/defaults.ts
25070
25070
  var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
25071
25071
  var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
25072
25072
 
25073
25073
  // src/cli/run-cli-action.ts
25074
- import * as fs31 from "node:fs";
25074
+ import * as fs33 from "node:fs";
25075
25075
  import * as path35 from "node:path";
25076
25076
 
25077
25077
  // src/config.ts
@@ -25428,17 +25428,17 @@ async function loadOrCreateE2eCertificates(directory) {
25428
25428
  };
25429
25429
  }
25430
25430
 
25431
- // src/files/cwd/bridge-workspace-directory.ts
25431
+ // src/files/cwd/bridge-root.ts
25432
25432
  import * as path3 from "node:path";
25433
- var bridgeWorkspaceDirectory = null;
25434
- function initBridgeWorkspaceDirectory() {
25435
- bridgeWorkspaceDirectory = path3.resolve(process.cwd());
25433
+ var bridgeRootPath = null;
25434
+ function initBridgeRoot() {
25435
+ bridgeRootPath = path3.resolve(process.cwd());
25436
25436
  }
25437
- function getBridgeWorkspaceDirectory() {
25438
- if (bridgeWorkspaceDirectory == null) {
25439
- bridgeWorkspaceDirectory = path3.resolve(process.cwd());
25437
+ function getBridgeRoot() {
25438
+ if (bridgeRootPath == null) {
25439
+ bridgeRootPath = path3.resolve(process.cwd());
25440
25440
  }
25441
- return bridgeWorkspaceDirectory;
25441
+ return bridgeRootPath;
25442
25442
  }
25443
25443
 
25444
25444
  // src/log.ts
@@ -26037,14 +26037,14 @@ var baseOpen = async (options) => {
26037
26037
  }
26038
26038
  const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
26039
26039
  if (options.wait) {
26040
- return new Promise((resolve19, reject) => {
26040
+ return new Promise((resolve18, reject) => {
26041
26041
  subprocess.once("error", reject);
26042
26042
  subprocess.once("close", (exitCode) => {
26043
26043
  if (!options.allowNonzeroExitCode && exitCode > 0) {
26044
26044
  reject(new Error(`Exited with code ${exitCode}`));
26045
26045
  return;
26046
26046
  }
26047
- resolve19(subprocess);
26047
+ resolve18(subprocess);
26048
26048
  });
26049
26049
  });
26050
26050
  }
@@ -26340,8 +26340,8 @@ function runPendingAuth(options) {
26340
26340
  let hasOpenedBrowser = false;
26341
26341
  let resolved = false;
26342
26342
  let resolveAuth;
26343
- const authPromise = new Promise((resolve19) => {
26344
- resolveAuth = resolve19;
26343
+ const authPromise = new Promise((resolve18) => {
26344
+ resolveAuth = resolve18;
26345
26345
  });
26346
26346
  let reconnectAttempt = 0;
26347
26347
  const signInQuiet = createEmptyReconnectQuietSlot();
@@ -26463,7 +26463,7 @@ function runPendingAuth(options) {
26463
26463
  async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
26464
26464
  const say = log2 ?? logImmediate;
26465
26465
  say("Cleaning up connections\u2026");
26466
- await new Promise((resolve19) => setImmediate(resolve19));
26466
+ await new Promise((resolve18) => setImmediate(resolve18));
26467
26467
  state.closedByUser = true;
26468
26468
  clearReconnectQuietTimer(state.mainQuiet);
26469
26469
  clearReconnectQuietTimer(state.firehoseQuiet);
@@ -26505,6 +26505,21 @@ async function closeBridgeConnection(state, acpManager, devServerManager, log2)
26505
26505
  say("Shutdown complete.");
26506
26506
  }
26507
26507
 
26508
+ // src/paths/session-layout-paths.ts
26509
+ import * as path5 from "node:path";
26510
+ function resolveIsolatedSessionParentPathFromCheckouts(worktreePaths) {
26511
+ const resolved = worktreePaths.map((p) => path5.resolve(p)).filter(Boolean);
26512
+ if (resolved.length === 0) return null;
26513
+ resolved.sort();
26514
+ return resolved[0];
26515
+ }
26516
+ function resolveSessionParentPathForAgentProcess(resolvedSessionParentPath) {
26517
+ if (resolvedSessionParentPath != null && String(resolvedSessionParentPath).trim() !== "") {
26518
+ return path5.resolve(String(resolvedSessionParentPath).trim());
26519
+ }
26520
+ return getBridgeRoot();
26521
+ }
26522
+
26508
26523
  // src/lib/local-agent-auth.ts
26509
26524
  var LOCAL_AGENT_AUTH_ERROR_HINTS = {
26510
26525
  "kiro-acp": [/not logged in/i, /kiro-cli\s+login/i, /log in with kiro-cli/i],
@@ -26536,17 +26551,17 @@ function localAgentErrorSuggestsAuth(agentType, errorText) {
26536
26551
  import { execFile as execFile7 } from "node:child_process";
26537
26552
  import { readFile as readFile2, stat as stat2 } from "node:fs/promises";
26538
26553
  import { promisify as promisify7 } from "node:util";
26539
- import * as path7 from "node:path";
26554
+ import * as path8 from "node:path";
26540
26555
 
26541
26556
  // src/git/pre-turn-snapshot.ts
26542
26557
  import * as fs9 from "node:fs";
26543
- import * as path6 from "node:path";
26558
+ import * as path7 from "node:path";
26544
26559
  import { execFile as execFile6 } from "node:child_process";
26545
26560
  import { promisify as promisify6 } from "node:util";
26546
26561
 
26547
26562
  // src/git/discover-repos.ts
26548
26563
  import * as fs8 from "node:fs";
26549
- import * as path5 from "node:path";
26564
+ import * as path6 from "node:path";
26550
26565
 
26551
26566
  // ../../node_modules/.pnpm/simple-git@3.32.3/node_modules/simple-git/dist/esm/index.js
26552
26567
  var import_file_exists = __toESM(require_dist(), 1);
@@ -31131,9 +31146,9 @@ async function isGitRepoDirectory(dirPath) {
31131
31146
  }
31132
31147
 
31133
31148
  // src/git/discover-repos.ts
31134
- async function discoverGitRepos(cwd = getBridgeWorkspaceDirectory()) {
31149
+ async function discoverGitRepos(cwd = getBridgeRoot()) {
31135
31150
  const result = [];
31136
- const cwdResolved = path5.resolve(cwd);
31151
+ const cwdResolved = path6.resolve(cwd);
31137
31152
  if (await isGitRepoDirectory(cwdResolved)) {
31138
31153
  const remoteUrl = await getRemoteOriginUrl(cwdResolved);
31139
31154
  result.push({ absolutePath: cwdResolved, remoteUrl });
@@ -31146,7 +31161,7 @@ async function discoverGitRepos(cwd = getBridgeWorkspaceDirectory()) {
31146
31161
  }
31147
31162
  for (const ent of entries) {
31148
31163
  if (!ent.isDirectory()) continue;
31149
- const childPath = path5.join(cwdResolved, ent.name);
31164
+ const childPath = path6.join(cwdResolved, ent.name);
31150
31165
  if (await isGitRepoDirectory(childPath)) {
31151
31166
  const remoteUrl = await getRemoteOriginUrl(childPath);
31152
31167
  result.push({ absolutePath: childPath, remoteUrl });
@@ -31154,12 +31169,12 @@ async function discoverGitRepos(cwd = getBridgeWorkspaceDirectory()) {
31154
31169
  }
31155
31170
  return result;
31156
31171
  }
31157
- async function discoverGitReposUnderRoot(rootAbs) {
31158
- const root = path5.resolve(rootAbs);
31172
+ async function discoverGitReposUnderRoot(rootPath) {
31173
+ const root = path6.resolve(rootPath);
31159
31174
  const roots = [];
31160
31175
  async function walk(dir) {
31161
31176
  if (await isGitRepoDirectory(dir)) {
31162
- roots.push(path5.resolve(dir));
31177
+ roots.push(path6.resolve(dir));
31163
31178
  return;
31164
31179
  }
31165
31180
  let entries;
@@ -31170,7 +31185,7 @@ async function discoverGitReposUnderRoot(rootAbs) {
31170
31185
  }
31171
31186
  for (const ent of entries) {
31172
31187
  if (!ent.isDirectory() || ent.name === ".git") continue;
31173
- await walk(path5.join(dir, ent.name));
31188
+ await walk(path6.join(dir, ent.name));
31174
31189
  }
31175
31190
  }
31176
31191
  await walk(root);
@@ -31186,7 +31201,7 @@ async function discoverGitReposUnderRoot(rootAbs) {
31186
31201
  // src/git/pre-turn-snapshot.ts
31187
31202
  var execFileAsync5 = promisify6(execFile6);
31188
31203
  function snapshotsDirForCwd(agentCwd) {
31189
- return path6.join(agentCwd, ".buildautomaton", "snapshots");
31204
+ return path7.join(agentCwd, ".buildautomaton", "snapshots");
31190
31205
  }
31191
31206
  async function gitStashCreate(repoRoot, log2) {
31192
31207
  try {
@@ -31213,14 +31228,20 @@ async function gitRun(repoRoot, args, log2, label) {
31213
31228
  }
31214
31229
  }
31215
31230
  async function resolveSnapshotRepoRoots(options) {
31216
- const { worktreePaths, fallbackCwd, log: log2 } = options;
31231
+ const { worktreePaths, fallbackCwd, sessionId, log: log2 } = options;
31217
31232
  if (worktreePaths?.length) {
31218
- const uniq = [...new Set(worktreePaths.map((p) => path6.resolve(p)))];
31233
+ const uniq = [...new Set(worktreePaths.map((p) => path7.resolve(p)))];
31219
31234
  return uniq;
31220
31235
  }
31221
31236
  try {
31222
31237
  const repos = await discoverGitReposUnderRoot(fallbackCwd);
31223
- return repos.map((r) => r.absolutePath);
31238
+ const mapped = repos.map((r) => r.absolutePath);
31239
+ const sid = sessionId?.trim();
31240
+ if (sid) {
31241
+ const filtered = mapped.filter((root) => path7.basename(root) === sid);
31242
+ if (filtered.length > 0) return filtered;
31243
+ }
31244
+ return mapped;
31224
31245
  } catch (e) {
31225
31246
  log2(`[snapshot] Discover repositories failed: ${e instanceof Error ? e.message : String(e)}`);
31226
31247
  return [];
@@ -31247,7 +31268,7 @@ async function capturePreTurnSnapshot(options) {
31247
31268
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
31248
31269
  repos
31249
31270
  };
31250
- const filePath = path6.join(dir, `${runId}.json`);
31271
+ const filePath = path7.join(dir, `${runId}.json`);
31251
31272
  try {
31252
31273
  fs9.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
31253
31274
  } catch (e) {
@@ -31285,7 +31306,7 @@ async function applyPreTurnSnapshot(filePath, log2) {
31285
31306
  return { ok: true };
31286
31307
  }
31287
31308
  function snapshotFilePath(agentCwd, runId) {
31288
- return path6.join(snapshotsDirForCwd(agentCwd), `${runId}.json`);
31309
+ return path7.join(snapshotsDirForCwd(agentCwd), `${runId}.json`);
31289
31310
  }
31290
31311
 
31291
31312
  // src/git/session-git-queue.ts
@@ -31334,7 +31355,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
31334
31355
  continue;
31335
31356
  }
31336
31357
  const lines = namesRaw.split("\n").map((l) => l.trim()).filter(Boolean);
31337
- const slug = path7.basename(repo.path).replace(/[^\w.-]+/g, "_") || "repo";
31358
+ const slug = path8.basename(repo.path).replace(/[^\w.-]+/g, "_") || "repo";
31338
31359
  for (const rel of lines) {
31339
31360
  if (rel.includes("..")) continue;
31340
31361
  try {
@@ -31348,8 +31369,8 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
31348
31369
  );
31349
31370
  if (!patchContent.trim()) continue;
31350
31371
  const displayPath = multiRepo ? `${slug}/${rel}` : rel;
31351
- const absFile = path7.join(repo.path, rel);
31352
- const newText = await readWorkspaceFileAsUtf8(absFile);
31372
+ const workspaceFilePath = path8.join(repo.path, rel);
31373
+ const newText = await readWorkspaceFileAsUtf8(workspaceFilePath);
31353
31374
  sendSessionUpdate({
31354
31375
  type: "session_file_change",
31355
31376
  sessionId,
@@ -31367,18 +31388,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
31367
31388
  }
31368
31389
  }
31369
31390
 
31370
- // ../types/dist/index.js
31371
- init_zod();
31372
- init_zod();
31373
- init_zod();
31374
- init_zod();
31375
- init_zod();
31376
- init_zod();
31377
- init_zod();
31378
- init_zod();
31379
- init_zod();
31380
- init_zod();
31381
- init_zod();
31391
+ // ../types/src/work-items.ts
31382
31392
  init_zod();
31383
31393
  var WorkItemStatusSchema = external_exports.enum(["backlog", "in-progress", "completed"]);
31384
31394
  var WorkItemProgressSchema = external_exports.object({
@@ -31419,6 +31429,9 @@ var WorkItemSchema = external_exports.object({
31419
31429
  dependencies: external_exports.array(WorkItemDependencySchema).default([]),
31420
31430
  assignedToUserId: external_exports.string().optional()
31421
31431
  });
31432
+
31433
+ // ../types/src/user-profiles.ts
31434
+ init_zod();
31422
31435
  var UserWorkspaceProfileSchema = external_exports.object({
31423
31436
  id: external_exports.string(),
31424
31437
  workspaceId: external_exports.string(),
@@ -31428,6 +31441,9 @@ var UserWorkspaceProfileSchema = external_exports.object({
31428
31441
  preferences: external_exports.record(external_exports.unknown()).optional(),
31429
31442
  learnings: external_exports.array(external_exports.string())
31430
31443
  });
31444
+
31445
+ // ../types/src/runtime.ts
31446
+ init_zod();
31431
31447
  var WorkspaceOwnerInfoSchema = external_exports.object({
31432
31448
  ownerId: external_exports.string(),
31433
31449
  ownerName: external_exports.string().optional(),
@@ -31441,6 +31457,9 @@ var WorkspaceRuntimeEntrySchema = external_exports.object({
31441
31457
  owner: WorkspaceOwnerInfoSchema.optional(),
31442
31458
  isOwner: external_exports.boolean().optional()
31443
31459
  });
31460
+
31461
+ // ../types/src/agent.ts
31462
+ init_zod();
31444
31463
  var ProjectContextSchema = external_exports.object({
31445
31464
  projectId: external_exports.string(),
31446
31465
  context: external_exports.record(external_exports.unknown()).default({}),
@@ -31465,6 +31484,9 @@ var WebSocketMessageSchema = external_exports.object({
31465
31484
  data: external_exports.any().optional(),
31466
31485
  error: external_exports.string().optional()
31467
31486
  });
31487
+
31488
+ // ../types/src/checkpoints.ts
31489
+ init_zod();
31468
31490
  var CheckpointKindSchema = external_exports.enum(["daily", "weekly", "overall"]);
31469
31491
  var CheckpointSummarySchema = external_exports.object({
31470
31492
  id: external_exports.string(),
@@ -31475,6 +31497,9 @@ var CheckpointSummarySchema = external_exports.object({
31475
31497
  createdAt: external_exports.string(),
31476
31498
  updatedAt: external_exports.string()
31477
31499
  });
31500
+
31501
+ // ../types/src/threads.ts
31502
+ init_zod();
31478
31503
  var ThreadMetaSchema = external_exports.object({
31479
31504
  threadId: external_exports.string(),
31480
31505
  workspaceId: external_exports.string(),
@@ -31502,6 +31527,9 @@ var ThreadMessageSchema = external_exports.object({
31502
31527
  var ThreadCheckpointSummarySchema = CheckpointSummarySchema.extend({
31503
31528
  threadId: external_exports.string()
31504
31529
  });
31530
+
31531
+ // ../types/src/content-items.ts
31532
+ init_zod();
31505
31533
  var ContentSourceSchema = external_exports.enum(["notion", "doc", "slack_thread", "other"]);
31506
31534
  var ContentItemMetaSchema = external_exports.object({
31507
31535
  contentId: external_exports.string(),
@@ -31523,6 +31551,9 @@ var ContentStorageRefSchema = external_exports.object({
31523
31551
  var ContentCheckpointSummarySchema = CheckpointSummarySchema.extend({
31524
31552
  contentId: external_exports.string()
31525
31553
  });
31554
+
31555
+ // ../types/src/stories.ts
31556
+ init_zod();
31526
31557
  var StoryMetaSchema = external_exports.object({
31527
31558
  storyId: external_exports.string(),
31528
31559
  workspaceId: external_exports.string(),
@@ -31545,6 +31576,9 @@ var StoryContentItemRefSchema = external_exports.object({
31545
31576
  var StoryCheckpointSummarySchema = CheckpointSummarySchema.extend({
31546
31577
  storyId: external_exports.string()
31547
31578
  });
31579
+
31580
+ // ../types/src/sessions.ts
31581
+ init_zod();
31548
31582
  var BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID = "__builtin_change_summary__";
31549
31583
  var SessionMetaSchema = external_exports.object({
31550
31584
  sessionId: external_exports.string(),
@@ -31587,6 +31621,8 @@ var SessionThreadRefSchema = external_exports.object({
31587
31621
  threadId: external_exports.string(),
31588
31622
  addedAt: external_exports.string()
31589
31623
  });
31624
+
31625
+ // ../types/src/change-summary-path.ts
31590
31626
  function normalizeRepoRelativePath(p) {
31591
31627
  let t = p.trim().replace(/\\/g, "/");
31592
31628
  while (t.startsWith("./")) t = t.slice(2);
@@ -31603,6 +31639,8 @@ function resolveChangeSummaryPathAgainstAllowed(rawPath, allowed) {
31603
31639
  }
31604
31640
  return null;
31605
31641
  }
31642
+
31643
+ // ../types/src/parse-change-summary-json.ts
31606
31644
  function clampSummaryToAtMostTwoLines(summary) {
31607
31645
  const lines = summary.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0);
31608
31646
  return lines.slice(0, 2).join("\n");
@@ -31645,6 +31683,8 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
31645
31683
  }
31646
31684
  return rows;
31647
31685
  }
31686
+
31687
+ // ../types/src/build-change-summary-prompt.ts
31648
31688
  var PATCH_PREVIEW_MAX = 12e3;
31649
31689
  function clip(s, max) {
31650
31690
  if (s.length <= max) return s;
@@ -31702,6 +31742,8 @@ function buildSessionChangeSummaryPrompt(files) {
31702
31742
  }
31703
31743
  return lines.join("\n");
31704
31744
  }
31745
+
31746
+ // ../types/src/dedupe-session-file-changes-by-path.ts
31705
31747
  function defaultRichness(c) {
31706
31748
  const patch = typeof c.patchContent === "string" ? c.patchContent.length : 0;
31707
31749
  const nt = typeof c.newText === "string" ? c.newText.length : 0;
@@ -31719,6 +31761,9 @@ function dedupeSessionFileChangesByPath(items, richness = (item) => defaultRichn
31719
31761
  }
31720
31762
  return Array.from(byPath.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([, v]) => v);
31721
31763
  }
31764
+
31765
+ // ../types/src/artifacts.ts
31766
+ init_zod();
31722
31767
  var ArtifactMetaSchema = external_exports.object({
31723
31768
  artifactId: external_exports.string(),
31724
31769
  workspaceId: external_exports.string(),
@@ -31732,6 +31777,9 @@ var ArtifactMetaSchema = external_exports.object({
31732
31777
  createdAt: external_exports.string(),
31733
31778
  updatedAt: external_exports.string()
31734
31779
  });
31780
+
31781
+ // ../types/src/templates.ts
31782
+ init_zod();
31735
31783
  var TemplateMetaSchema = external_exports.object({
31736
31784
  templateId: external_exports.string(),
31737
31785
  workspaceId: external_exports.string(),
@@ -31741,6 +31789,9 @@ var TemplateMetaSchema = external_exports.object({
31741
31789
  createdAt: external_exports.string(),
31742
31790
  updatedAt: external_exports.string()
31743
31791
  });
31792
+
31793
+ // ../types/src/git-repos.ts
31794
+ init_zod();
31744
31795
  var GitRepoMetaSchema = external_exports.object({
31745
31796
  /** Stable id for the repo (e.g. hash of normalized canonical URL). Used for DO idFromName. */
31746
31797
  repoId: external_exports.string(),
@@ -31934,7 +31985,7 @@ async function sendPromptToAgent(options) {
31934
31985
 
31935
31986
  // src/agents/acp/ensure-acp-client.ts
31936
31987
  import * as fs10 from "node:fs";
31937
- import * as path11 from "node:path";
31988
+ import * as path12 from "node:path";
31938
31989
 
31939
31990
  // src/error-message.ts
31940
31991
  function errorMessage(err) {
@@ -31973,7 +32024,7 @@ async function isCommandOnPath(command, timeoutMs = 4e3) {
31973
32024
  // src/agents/acp/clients/sdk-stdio-acp-client.ts
31974
32025
  import { spawn as spawn2 } from "node:child_process";
31975
32026
  import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
31976
- import { dirname } from "node:path";
32027
+ import { dirname as dirname2 } from "node:path";
31977
32028
  import { Readable, Writable } from "node:stream";
31978
32029
 
31979
32030
  // src/files/diff/unified-diff.ts
@@ -32023,21 +32074,21 @@ function editSnippetToUnifiedDiff(filePath, oldText, newText) {
32023
32074
  }
32024
32075
 
32025
32076
  // src/agents/acp/safe-fs-path.ts
32026
- import * as path8 from "node:path";
32077
+ import * as path9 from "node:path";
32027
32078
  function resolveSafePathUnderCwd(cwd, filePath) {
32028
32079
  const trimmed2 = filePath.trim();
32029
32080
  if (!trimmed2) return null;
32030
- const normalizedCwd = path8.resolve(cwd);
32031
- const resolved = path8.isAbsolute(trimmed2) ? path8.normalize(trimmed2) : path8.resolve(normalizedCwd, trimmed2);
32032
- const rel = path8.relative(normalizedCwd, resolved);
32033
- if (rel.startsWith("..") || path8.isAbsolute(rel)) return null;
32081
+ const normalizedCwd = path9.resolve(cwd);
32082
+ const resolved = path9.isAbsolute(trimmed2) ? path9.normalize(trimmed2) : path9.resolve(normalizedCwd, trimmed2);
32083
+ const rel = path9.relative(normalizedCwd, resolved);
32084
+ if (rel.startsWith("..") || path9.isAbsolute(rel)) return null;
32034
32085
  return resolved;
32035
32086
  }
32036
32087
  function toDisplayPathRelativeToCwd(cwd, absolutePath) {
32037
- const normalizedCwd = path8.resolve(cwd);
32038
- const rel = path8.relative(normalizedCwd, path8.resolve(absolutePath));
32039
- if (!rel || rel === "") return path8.basename(absolutePath);
32040
- return rel.split(path8.sep).join("/");
32088
+ const normalizedCwd = path9.resolve(cwd);
32089
+ const rel = path9.relative(normalizedCwd, path9.resolve(absolutePath));
32090
+ if (!rel || rel === "") return path9.basename(absolutePath);
32091
+ return rel.split(path9.sep).join("/");
32041
32092
  }
32042
32093
 
32043
32094
  // src/agents/acp/clients/agent-stderr-capture.ts
@@ -32117,6 +32168,52 @@ function createSdkStdioExtNotificationHandler(options) {
32117
32168
  }
32118
32169
  }
32119
32170
 
32171
+ // src/agents/acp/enrich-acp-permission-rpc-result.ts
32172
+ var META_KEY = "permissionOptionKind";
32173
+ function optionRecordId(rec) {
32174
+ const raw = rec.optionId ?? rec.id;
32175
+ if (typeof raw === "string" && raw.trim() !== "") return raw.trim();
32176
+ if (typeof raw === "number" && Number.isFinite(raw)) return String(raw);
32177
+ return "";
32178
+ }
32179
+ function enrichAcpPermissionRpcResultFromRequestParams(result, params) {
32180
+ if (params == null || result == null || typeof result !== "object" || Array.isArray(result)) {
32181
+ return result;
32182
+ }
32183
+ const root = result;
32184
+ const outcome = root.outcome;
32185
+ if (outcome == null || typeof outcome !== "object" || Array.isArray(outcome)) return result;
32186
+ const o = outcome;
32187
+ if (o.outcome !== "selected" || typeof o.optionId !== "string" || o.optionId.trim() === "") {
32188
+ return result;
32189
+ }
32190
+ const selectedId = o.optionId.trim();
32191
+ const prevMeta = o._meta != null && typeof o._meta === "object" && !Array.isArray(o._meta) ? o._meta : {};
32192
+ if (typeof prevMeta[META_KEY] === "string" && prevMeta[META_KEY].trim() !== "") {
32193
+ return result;
32194
+ }
32195
+ const rawOpts = Array.isArray(params.options) ? params.options : [];
32196
+ let matchedKind;
32197
+ for (const item of rawOpts) {
32198
+ if (item == null || typeof item !== "object" || Array.isArray(item)) continue;
32199
+ const rec = item;
32200
+ const id = optionRecordId(rec);
32201
+ if (!id || id !== selectedId) continue;
32202
+ if (typeof rec.kind === "string" && rec.kind.trim() !== "") {
32203
+ matchedKind = rec.kind.trim();
32204
+ break;
32205
+ }
32206
+ }
32207
+ if (!matchedKind) return result;
32208
+ return {
32209
+ ...root,
32210
+ outcome: {
32211
+ ...o,
32212
+ _meta: { ...prevMeta, [META_KEY]: matchedKind }
32213
+ }
32214
+ };
32215
+ }
32216
+
32120
32217
  // src/agents/acp/clients/sdk-stdio-acp-client.ts
32121
32218
  function formatSpawnError(err, command) {
32122
32219
  if (err.code === "ENOENT") {
@@ -32138,7 +32235,7 @@ async function createSdkStdioAcpClient(options) {
32138
32235
  const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
32139
32236
  const {
32140
32237
  command,
32141
- cwd = getBridgeWorkspaceDirectory(),
32238
+ cwd = getBridgeRoot(),
32142
32239
  backendAgentType,
32143
32240
  onSessionUpdate,
32144
32241
  onRequest,
@@ -32157,7 +32254,7 @@ async function createSdkStdioAcpClient(options) {
32157
32254
  child.once("close", (code, signal) => {
32158
32255
  onAgentSubprocessExit?.({ code, signal });
32159
32256
  });
32160
- return new Promise((resolve19, reject) => {
32257
+ return new Promise((resolve18, reject) => {
32161
32258
  let initSettled = false;
32162
32259
  const settleReject = (err) => {
32163
32260
  if (initSettled) return;
@@ -32171,7 +32268,7 @@ async function createSdkStdioAcpClient(options) {
32171
32268
  const settleResolve = (handle) => {
32172
32269
  if (initSettled) return;
32173
32270
  initSettled = true;
32174
- resolve19(handle);
32271
+ resolve18(handle);
32175
32272
  };
32176
32273
  child.on("error", (err) => {
32177
32274
  settleReject(new Error(formatSpawnError(err, command[0])));
@@ -32194,7 +32291,7 @@ async function createSdkStdioAcpClient(options) {
32194
32291
  onSessionUpdate
32195
32292
  });
32196
32293
  let permissionSeq = 0;
32197
- const pendingPermissionResolvers = /* @__PURE__ */ new Map();
32294
+ const pendingPermissionReplies = /* @__PURE__ */ new Map();
32198
32295
  const client = (_agent) => ({
32199
32296
  async requestPermission(params) {
32200
32297
  const requestId = `perm-${++permissionSeq}`;
@@ -32207,15 +32304,15 @@ async function createSdkStdioAcpClient(options) {
32207
32304
  });
32208
32305
  } catch {
32209
32306
  }
32210
- return await new Promise((resolve20) => {
32211
- pendingPermissionResolvers.set(requestId, resolve20);
32307
+ return await new Promise((resolve19) => {
32308
+ pendingPermissionReplies.set(requestId, { resolve: resolve19, params: paramsRecord });
32212
32309
  });
32213
32310
  },
32214
32311
  async readTextFile(params) {
32215
- const abs = resolveSafePathUnderCwd(cwd, params.path);
32216
- if (!abs) throw new Error("Invalid or disallowed path");
32312
+ const resolvedPath = resolveSafePathUnderCwd(cwd, params.path);
32313
+ if (!resolvedPath) throw new Error("Invalid or disallowed path");
32217
32314
  try {
32218
- let content = readFileSync2(abs, "utf8");
32315
+ let content = readFileSync2(resolvedPath, "utf8");
32219
32316
  content = sliceFileContentRange(content, params.line, params.limit);
32220
32317
  return { content };
32221
32318
  } catch (e) {
@@ -32224,17 +32321,17 @@ async function createSdkStdioAcpClient(options) {
32224
32321
  }
32225
32322
  },
32226
32323
  async writeTextFile(params) {
32227
- const abs = resolveSafePathUnderCwd(cwd, params.path);
32228
- if (!abs) throw new Error("Invalid or disallowed path");
32324
+ const resolvedPath = resolveSafePathUnderCwd(cwd, params.path);
32325
+ if (!resolvedPath) throw new Error("Invalid or disallowed path");
32229
32326
  let oldText = "";
32230
32327
  try {
32231
- oldText = readFileSync2(abs, "utf8");
32328
+ oldText = readFileSync2(resolvedPath, "utf8");
32232
32329
  } catch (e) {
32233
32330
  if (e.code !== "ENOENT") throw e;
32234
32331
  }
32235
- mkdirSync2(dirname(abs), { recursive: true });
32236
- writeFileSync2(abs, params.content, "utf8");
32237
- const displayPath = toDisplayPathRelativeToCwd(cwd, abs);
32332
+ mkdirSync2(dirname2(resolvedPath), { recursive: true });
32333
+ writeFileSync2(resolvedPath, params.content, "utf8");
32334
+ const displayPath = toDisplayPathRelativeToCwd(cwd, resolvedPath);
32238
32335
  const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, params.content);
32239
32336
  onFileChange?.({ path: displayPath, oldText, newText: params.content, patchContent });
32240
32337
  return {};
@@ -32316,9 +32413,9 @@ async function createSdkStdioAcpClient(options) {
32316
32413
  }
32317
32414
  },
32318
32415
  async cancel() {
32319
- for (const [id, resolve20] of [...pendingPermissionResolvers.entries()]) {
32320
- pendingPermissionResolvers.delete(id);
32321
- resolve20({ outcome: { outcome: "cancelled" } });
32416
+ for (const [id, entry] of [...pendingPermissionReplies.entries()]) {
32417
+ pendingPermissionReplies.delete(id);
32418
+ entry.resolve({ outcome: { outcome: "cancelled" } });
32322
32419
  }
32323
32420
  try {
32324
32421
  await connection.cancel({ sessionId });
@@ -32334,10 +32431,11 @@ async function createSdkStdioAcpClient(options) {
32334
32431
  }
32335
32432
  },
32336
32433
  resolveRequest(requestId, result) {
32337
- const resolve20 = pendingPermissionResolvers.get(requestId);
32338
- if (!resolve20) return;
32339
- pendingPermissionResolvers.delete(requestId);
32340
- resolve20(result);
32434
+ const entry = pendingPermissionReplies.get(requestId);
32435
+ if (!entry) return;
32436
+ pendingPermissionReplies.delete(requestId);
32437
+ const enriched = enrichAcpPermissionRpcResultFromRequestParams(result, entry.params);
32438
+ entry.resolve(enriched);
32341
32439
  },
32342
32440
  disconnect() {
32343
32441
  child.kill();
@@ -32422,7 +32520,7 @@ __export(cursor_acp_client_exports, {
32422
32520
  detectLocalAgentPresence: () => detectLocalAgentPresence3
32423
32521
  });
32424
32522
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
32425
- import { dirname as dirname2 } from "node:path";
32523
+ import { dirname as dirname3 } from "node:path";
32426
32524
  import { spawn as spawn3 } from "node:child_process";
32427
32525
  import * as readline from "node:readline";
32428
32526
 
@@ -32472,7 +32570,7 @@ function buildCursorAcpSpawnCommand(base, sessionMode) {
32472
32570
  async function createCursorAcpClient(options) {
32473
32571
  const command = buildCursorAcpSpawnCommand(options.command, options.sessionMode);
32474
32572
  const {
32475
- cwd = getBridgeWorkspaceDirectory(),
32573
+ cwd = getBridgeRoot(),
32476
32574
  backendAgentType,
32477
32575
  onSessionUpdate,
32478
32576
  onRequest,
@@ -32488,7 +32586,7 @@ async function createCursorAcpClient(options) {
32488
32586
  });
32489
32587
  const stderrCapture = createStderrCapture(child);
32490
32588
  child.stderr?.on("data", (chunk) => stderrCapture.append(chunk));
32491
- return new Promise((resolve19, reject) => {
32589
+ return new Promise((resolve18, reject) => {
32492
32590
  child.on("error", (err) => {
32493
32591
  child.kill();
32494
32592
  reject(new Error(formatSpawnError2(err, command[0])));
@@ -32514,7 +32612,9 @@ async function createCursorAcpClient(options) {
32514
32612
  child.stdin.write(JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } }) + "\n");
32515
32613
  }
32516
32614
  function resolveRequest(requestId, result) {
32517
- respond(requestId, result);
32615
+ const pending2 = pendingRequests.get(requestId);
32616
+ const payload = pending2?.method === "session/request_permission" ? enrichAcpPermissionRpcResultFromRequestParams(result, pending2.params) : result;
32617
+ respond(requestId, payload);
32518
32618
  pendingRequests.delete(requestId);
32519
32619
  }
32520
32620
  let promptOutputBuffer = "";
@@ -32570,14 +32670,14 @@ async function createCursorAcpClient(options) {
32570
32670
  if (dbgFs) {
32571
32671
  console.error(`[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""}`);
32572
32672
  }
32573
- const abs = resolveSafePathUnderCwd(cwd, filePath);
32574
- if (!abs) {
32673
+ const resolvedPath = resolveSafePathUnderCwd(cwd, filePath);
32674
+ if (!resolvedPath) {
32575
32675
  if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty)`);
32576
32676
  respondJsonRpcError(id, -32602, "Invalid or disallowed path");
32577
32677
  return;
32578
32678
  }
32579
32679
  try {
32580
- let content = readFileSync3(abs, "utf8");
32680
+ let content = readFileSync3(resolvedPath, "utf8");
32581
32681
  const line2 = typeof params.line === "number" ? params.line : void 0;
32582
32682
  const limit = typeof params.limit === "number" ? params.limit : void 0;
32583
32683
  content = sliceLinesByRange(content, line2, limit);
@@ -32601,15 +32701,15 @@ async function createCursorAcpClient(options) {
32601
32701
  `[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""} newBytes=${newText.length}`
32602
32702
  );
32603
32703
  }
32604
- const abs = resolveSafePathUnderCwd(cwd, filePath);
32605
- if (!abs) {
32704
+ const resolvedPath = resolveSafePathUnderCwd(cwd, filePath);
32705
+ if (!resolvedPath) {
32606
32706
  if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty): ${filePath.slice(0, 120)}`);
32607
32707
  respondJsonRpcError(id, -32602, "Invalid or disallowed path");
32608
32708
  return;
32609
32709
  }
32610
32710
  let oldText = "";
32611
32711
  try {
32612
- oldText = readFileSync3(abs, "utf8");
32712
+ oldText = readFileSync3(resolvedPath, "utf8");
32613
32713
  } catch (e) {
32614
32714
  if (e.code !== "ENOENT") {
32615
32715
  respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
@@ -32617,13 +32717,13 @@ async function createCursorAcpClient(options) {
32617
32717
  }
32618
32718
  }
32619
32719
  try {
32620
- mkdirSync3(dirname2(abs), { recursive: true });
32621
- writeFileSync3(abs, newText, "utf8");
32720
+ mkdirSync3(dirname3(resolvedPath), { recursive: true });
32721
+ writeFileSync3(resolvedPath, newText, "utf8");
32622
32722
  } catch (e) {
32623
32723
  respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
32624
32724
  return;
32625
32725
  }
32626
- const displayPath = toDisplayPathRelativeToCwd(cwd, abs);
32726
+ const displayPath = toDisplayPathRelativeToCwd(cwd, resolvedPath);
32627
32727
  const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
32628
32728
  onFileChange?.({ path: displayPath, oldText, newText, patchContent });
32629
32729
  respond(id, null);
@@ -32675,7 +32775,7 @@ async function createCursorAcpClient(options) {
32675
32775
  const newResult = await send("session/new", { cwd, mcpServers: [] });
32676
32776
  const sessionId = newResult?.sessionId ?? "";
32677
32777
  if (!sessionId) throw new Error("Cursor ACP session/new did not return sessionId");
32678
- resolve19({
32778
+ resolve18({
32679
32779
  sessionId,
32680
32780
  async sendPrompt(prompt, _options) {
32681
32781
  promptOutputBuffer = "";
@@ -32739,8 +32839,7 @@ async function createCursorAcpClient(options) {
32739
32839
  resolveRequest(requestId, result) {
32740
32840
  const numericId = Number(requestId);
32741
32841
  if (!Number.isFinite(numericId)) return;
32742
- const pendingRequest = pendingRequests.get(numericId);
32743
- if (!pendingRequest) return;
32842
+ if (!pendingRequests.get(numericId)) return;
32744
32843
  resolveRequest(numericId, result);
32745
32844
  },
32746
32845
  disconnect() {
@@ -32866,16 +32965,16 @@ import { existsSync, statSync } from "node:fs";
32866
32965
 
32867
32966
  // src/git/get-git-repo-root-sync.ts
32868
32967
  import { execFileSync as execFileSync2 } from "node:child_process";
32869
- import * as path9 from "node:path";
32968
+ import * as path10 from "node:path";
32870
32969
  function getGitRepoRootSync(startDir) {
32871
32970
  try {
32872
32971
  const out = execFileSync2("git", ["rev-parse", "--show-toplevel"], {
32873
- cwd: path9.resolve(startDir),
32972
+ cwd: path10.resolve(startDir),
32874
32973
  encoding: "utf8",
32875
32974
  stdio: ["ignore", "pipe", "ignore"],
32876
32975
  maxBuffer: 1024 * 1024
32877
32976
  }).trim();
32878
- return out ? path9.resolve(out) : null;
32977
+ return out ? path10.resolve(out) : null;
32879
32978
  } catch {
32880
32979
  return null;
32881
32980
  }
@@ -32884,64 +32983,64 @@ function getGitRepoRootSync(startDir) {
32884
32983
  // src/agents/acp/workspace-files.ts
32885
32984
  import { execFileSync as execFileSync3 } from "node:child_process";
32886
32985
  import { readFileSync as readFileSync4 } from "node:fs";
32887
- import * as path10 from "node:path";
32888
- function resolveWorkspaceFilePath(cwd, rawPath) {
32986
+ import * as path11 from "node:path";
32987
+ function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
32889
32988
  const trimmed2 = rawPath.trim();
32890
32989
  if (!trimmed2) return null;
32891
- const normalizedCwd = path10.resolve(cwd);
32892
- let abs = resolveSafePathUnderCwd(cwd, trimmed2);
32893
- if (!abs) {
32894
- const candidate = path10.isAbsolute(trimmed2) ? path10.normalize(trimmed2) : path10.normalize(path10.resolve(normalizedCwd, trimmed2));
32895
- const gitRoot2 = getGitRepoRootSync(cwd);
32990
+ const normalizedSessionParent = path11.resolve(sessionParentPath);
32991
+ let resolvedPath = resolveSafePathUnderCwd(sessionParentPath, trimmed2);
32992
+ if (!resolvedPath) {
32993
+ const candidate = path11.isAbsolute(trimmed2) ? path11.normalize(trimmed2) : path11.normalize(path11.resolve(normalizedSessionParent, trimmed2));
32994
+ const gitRoot2 = getGitRepoRootSync(sessionParentPath);
32896
32995
  if (!gitRoot2) return null;
32897
- const rel = path10.relative(gitRoot2, candidate);
32898
- if (rel.startsWith("..") || path10.isAbsolute(rel)) return null;
32899
- abs = candidate;
32996
+ const rel = path11.relative(gitRoot2, candidate);
32997
+ if (rel.startsWith("..") || path11.isAbsolute(rel)) return null;
32998
+ resolvedPath = candidate;
32900
32999
  }
32901
- const gitRoot = getGitRepoRootSync(cwd);
33000
+ const gitRoot = getGitRepoRootSync(sessionParentPath);
32902
33001
  if (gitRoot) {
32903
- const relFromRoot = path10.relative(gitRoot, abs);
32904
- if (!relFromRoot.startsWith("..") && !path10.isAbsolute(relFromRoot)) {
32905
- return { abs, display: relFromRoot.split(path10.sep).join("/") };
33002
+ const relFromRoot = path11.relative(gitRoot, resolvedPath);
33003
+ if (!relFromRoot.startsWith("..") && !path11.isAbsolute(relFromRoot)) {
33004
+ return { resolvedPath, display: relFromRoot.split(path11.sep).join("/") };
32906
33005
  }
32907
33006
  }
32908
- return { abs, display: toDisplayPathRelativeToCwd(cwd, abs) };
33007
+ return { resolvedPath, display: toDisplayPathRelativeToCwd(sessionParentPath, resolvedPath) };
32909
33008
  }
32910
- function readUtf8WorkspaceFile(cwd, displayPath) {
33009
+ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
32911
33010
  if (!displayPath || displayPath.includes("..")) return "";
32912
- const gitRoot = getGitRepoRootSync(cwd);
33011
+ const gitRoot = getGitRepoRootSync(sessionParentPath);
32913
33012
  if (gitRoot) {
32914
- const abs2 = path10.resolve(gitRoot, displayPath);
32915
- const rel = path10.relative(gitRoot, abs2);
32916
- if (!rel.startsWith("..") && !path10.isAbsolute(rel)) {
33013
+ const resolvedPath2 = path11.resolve(gitRoot, displayPath);
33014
+ const rel = path11.relative(gitRoot, resolvedPath2);
33015
+ if (!rel.startsWith("..") && !path11.isAbsolute(rel)) {
32917
33016
  try {
32918
- return readFileSync4(abs2, "utf8");
33017
+ return readFileSync4(resolvedPath2, "utf8");
32919
33018
  } catch {
32920
33019
  }
32921
33020
  }
32922
33021
  }
32923
- const abs = resolveSafePathUnderCwd(cwd, displayPath);
32924
- if (!abs) return "";
33022
+ const resolvedPath = resolveSafePathUnderCwd(sessionParentPath, displayPath);
33023
+ if (!resolvedPath) return "";
32925
33024
  try {
32926
- return readFileSync4(abs, "utf8");
33025
+ return readFileSync4(resolvedPath, "utf8");
32927
33026
  } catch {
32928
33027
  return "";
32929
33028
  }
32930
33029
  }
32931
- function tryWorkspaceDisplayToAbs(cwd, displayPath) {
33030
+ function tryWorkspaceDisplayToPath(sessionParentPath, displayPath) {
32932
33031
  if (!displayPath || displayPath.includes("..")) return null;
32933
- const gitRoot = getGitRepoRootSync(cwd);
33032
+ const gitRoot = getGitRepoRootSync(sessionParentPath);
32934
33033
  if (gitRoot) {
32935
- const abs = path10.resolve(gitRoot, displayPath);
32936
- const rel = path10.relative(gitRoot, abs);
32937
- if (!rel.startsWith("..") && !path10.isAbsolute(rel)) return abs;
33034
+ const resolvedPath = path11.resolve(gitRoot, displayPath);
33035
+ const rel = path11.relative(gitRoot, resolvedPath);
33036
+ if (!rel.startsWith("..") && !path11.isAbsolute(rel)) return resolvedPath;
32938
33037
  }
32939
- return resolveSafePathUnderCwd(cwd, displayPath);
33038
+ return resolveSafePathUnderCwd(sessionParentPath, displayPath);
32940
33039
  }
32941
- function readGitHeadBlob(cwd, displayPath) {
33040
+ function readGitHeadBlob(sessionParentPath, displayPath) {
32942
33041
  if (!displayPath || displayPath.includes("..")) return "";
32943
- const gitRoot = getGitRepoRootSync(cwd);
32944
- const execCwd = gitRoot ?? cwd;
33042
+ const gitRoot = getGitRepoRootSync(sessionParentPath);
33043
+ const execCwd = gitRoot ?? sessionParentPath;
32945
33044
  try {
32946
33045
  return execFileSync3("git", ["show", `HEAD:${displayPath}`], {
32947
33046
  cwd: execCwd,
@@ -32954,9 +33053,9 @@ function readGitHeadBlob(cwd, displayPath) {
32954
33053
  }
32955
33054
 
32956
33055
  // src/agents/acp/session-file-change-path-kind.ts
32957
- function gitHeadPathObjectType(cwd, displayPath) {
33056
+ function gitHeadPathObjectType(sessionParentPath, displayPath) {
32958
33057
  if (!displayPath || displayPath.includes("..")) return null;
32959
- const gitRoot = getGitRepoRootSync(cwd);
33058
+ const gitRoot = getGitRepoRootSync(sessionParentPath);
32960
33059
  if (!gitRoot) return null;
32961
33060
  try {
32962
33061
  return execFileSync4("git", ["cat-file", "-t", `HEAD:${displayPath}`], {
@@ -32967,11 +33066,11 @@ function gitHeadPathObjectType(cwd, displayPath) {
32967
33066
  return null;
32968
33067
  }
32969
33068
  }
32970
- function getSessionFileChangeDirectoryFlags(cwd, displayPath) {
32971
- const abs = tryWorkspaceDisplayToAbs(cwd, displayPath);
32972
- if (abs && existsSync(abs)) {
33069
+ function getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath) {
33070
+ const resolvedPath = tryWorkspaceDisplayToPath(sessionParentPath, displayPath);
33071
+ if (resolvedPath && existsSync(resolvedPath)) {
32973
33072
  try {
32974
- if (statSync(abs).isDirectory()) {
33073
+ if (statSync(resolvedPath).isDirectory()) {
32975
33074
  return { isDirectory: true, directoryRemoved: false };
32976
33075
  }
32977
33076
  return { isDirectory: false, directoryRemoved: false };
@@ -32979,7 +33078,7 @@ function getSessionFileChangeDirectoryFlags(cwd, displayPath) {
32979
33078
  return { isDirectory: false, directoryRemoved: false };
32980
33079
  }
32981
33080
  }
32982
- if (gitHeadPathObjectType(cwd, displayPath) === "tree") {
33081
+ if (gitHeadPathObjectType(sessionParentPath, displayPath) === "tree") {
32983
33082
  return { isDirectory: true, directoryRemoved: true };
32984
33083
  }
32985
33084
  return { isDirectory: false, directoryRemoved: false };
@@ -32987,7 +33086,7 @@ function getSessionFileChangeDirectoryFlags(cwd, displayPath) {
32987
33086
 
32988
33087
  // src/agents/acp/hooks/bridge-on-file-change.ts
32989
33088
  function createBridgeOnFileChange(opts) {
32990
- const { routing, getSendSessionUpdate, log: log2 } = opts;
33089
+ const { routing, getSendSessionUpdate, log: log2, sessionParentPath } = opts;
32991
33090
  return (evt) => {
32992
33091
  const runId = routing.runId;
32993
33092
  const sessionId = routing.sessionId;
@@ -32998,8 +33097,7 @@ function createBridgeOnFileChange(opts) {
32998
33097
  );
32999
33098
  return;
33000
33099
  }
33001
- const cwd = getBridgeWorkspaceDirectory();
33002
- const dirFlags = getSessionFileChangeDirectoryFlags(cwd, evt.path);
33100
+ const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, evt.path);
33003
33101
  try {
33004
33102
  send({
33005
33103
  type: "session_file_change",
@@ -33076,12 +33174,12 @@ function extractDiffPath(o) {
33076
33174
  }
33077
33175
 
33078
33176
  // src/agents/acp/hooks/extract-acp-file-diffs-from-update/push-diff.ts
33079
- function pushDiffIfComplete(o, cwd, out) {
33177
+ function pushDiffIfComplete(o, sessionParentPath, out) {
33080
33178
  const t = o.type;
33081
33179
  if (typeof t !== "string" || t.toLowerCase() !== "diff") return;
33082
33180
  const rawPath = extractDiffPath(o);
33083
33181
  if (!rawPath) return;
33084
- const resolved = resolveWorkspaceFilePath(cwd, rawPath);
33182
+ const resolved = resolveWorkspaceFilePath(sessionParentPath, rawPath);
33085
33183
  if (!resolved) return;
33086
33184
  const oldText = readOptionalTextField(o.oldText ?? o.old_text ?? o.before ?? o.oldContent);
33087
33185
  const newText = readOptionalTextField(o.newText ?? o.new_text ?? o.after ?? o.newContent);
@@ -33100,17 +33198,17 @@ var NEST_KEYS = [
33100
33198
  "data",
33101
33199
  "arguments"
33102
33200
  ];
33103
- function walkValue(value, cwd, depth, out) {
33201
+ function walkValue(value, sessionParentPath, depth, out) {
33104
33202
  if (depth > 12 || value == null) return;
33105
33203
  if (Array.isArray(value)) {
33106
- for (const x of value) walkValue(x, cwd, depth + 1, out);
33204
+ for (const x of value) walkValue(x, sessionParentPath, depth + 1, out);
33107
33205
  return;
33108
33206
  }
33109
33207
  if (typeof value !== "object") return;
33110
33208
  const o = value;
33111
- pushDiffIfComplete(o, cwd, out);
33209
+ pushDiffIfComplete(o, sessionParentPath, out);
33112
33210
  if (o.type === "content" && o.content != null && typeof o.content === "object") {
33113
- walkValue(o.content, cwd, depth + 1, out);
33211
+ walkValue(o.content, sessionParentPath, depth + 1, out);
33114
33212
  }
33115
33213
  for (const k of NEST_KEYS) {
33116
33214
  if (o.type === "content" && k === "content") continue;
@@ -33118,23 +33216,23 @@ function walkValue(value, cwd, depth, out) {
33118
33216
  if (v == null) continue;
33119
33217
  if (k === "arguments" && typeof v === "string") {
33120
33218
  try {
33121
- walkValue(JSON.parse(v), cwd, depth + 1, out);
33219
+ walkValue(JSON.parse(v), sessionParentPath, depth + 1, out);
33122
33220
  } catch {
33123
33221
  }
33124
33222
  continue;
33125
33223
  }
33126
- walkValue(v, cwd, depth + 1, out);
33224
+ walkValue(v, sessionParentPath, depth + 1, out);
33127
33225
  }
33128
33226
  }
33129
33227
 
33130
33228
  // src/agents/acp/hooks/extract-acp-file-diffs-from-update/extract.ts
33131
- function extractAcpFileDiffsFromUpdate(update, cwd) {
33229
+ function extractAcpFileDiffsFromUpdate(update, sessionParentPath) {
33132
33230
  if (!update || typeof update !== "object") return [];
33133
33231
  const u = update;
33134
33232
  const out = [];
33135
33233
  const content = u.content;
33136
33234
  if (Array.isArray(content)) {
33137
- for (const x of content) walkValue(x, cwd, 0, out);
33235
+ for (const x of content) walkValue(x, sessionParentPath, 0, out);
33138
33236
  }
33139
33237
  const byPath = /* @__PURE__ */ new Map();
33140
33238
  for (const d of out) byPath.set(d.path, d);
@@ -33142,18 +33240,18 @@ function extractAcpFileDiffsFromUpdate(update, cwd) {
33142
33240
  }
33143
33241
 
33144
33242
  // src/agents/acp/hooks/extract-tool-target-paths.ts
33145
- function addPath(cwd, raw, out) {
33243
+ function addPath(sessionParentPath, raw, out) {
33146
33244
  if (typeof raw !== "string") return;
33147
33245
  const trimmed2 = raw.trim();
33148
33246
  if (!trimmed2) return;
33149
- const resolved = resolveWorkspaceFilePath(cwd, trimmed2);
33247
+ const resolved = resolveWorkspaceFilePath(sessionParentPath, trimmed2);
33150
33248
  if (!resolved) return;
33151
33249
  out.add(resolved.display);
33152
33250
  }
33153
- function walkLocations(cwd, loc, out) {
33251
+ function walkLocations(sessionParentPath, loc, out) {
33154
33252
  if (!Array.isArray(loc)) return;
33155
33253
  for (const item of loc) {
33156
- if (item && typeof item === "object") addPath(cwd, item.path, out);
33254
+ if (item && typeof item === "object") addPath(sessionParentPath, item.path, out);
33157
33255
  }
33158
33256
  }
33159
33257
  var PATH_KEYS = [
@@ -33166,56 +33264,56 @@ var PATH_KEYS = [
33166
33264
  "file_path",
33167
33265
  "target_file"
33168
33266
  ];
33169
- function collectFromObject(cwd, obj, out, depth) {
33267
+ function collectFromObject(sessionParentPath, obj, out, depth) {
33170
33268
  if (depth > 10) return;
33171
33269
  for (const k of PATH_KEYS) {
33172
- if (k in obj) addPath(cwd, obj[k], out);
33270
+ if (k in obj) addPath(sessionParentPath, obj[k], out);
33173
33271
  }
33174
33272
  for (const v of Object.values(obj)) {
33175
- if (v != null && typeof v === "object") collectUnknown(cwd, v, out, depth + 1);
33273
+ if (v != null && typeof v === "object") collectUnknown(sessionParentPath, v, out, depth + 1);
33176
33274
  }
33177
33275
  }
33178
- function collectUnknown(cwd, v, out, depth) {
33276
+ function collectUnknown(sessionParentPath, v, out, depth) {
33179
33277
  if (depth > 10 || v == null) return;
33180
33278
  if (Array.isArray(v)) {
33181
- for (const x of v) collectUnknown(cwd, x, out, depth + 1);
33279
+ for (const x of v) collectUnknown(sessionParentPath, x, out, depth + 1);
33182
33280
  return;
33183
33281
  }
33184
- if (typeof v === "object") collectFromObject(cwd, v, out, depth);
33282
+ if (typeof v === "object") collectFromObject(sessionParentPath, v, out, depth);
33185
33283
  }
33186
- function walkContentArray(cwd, content, out) {
33284
+ function walkContentArray(sessionParentPath, content, out) {
33187
33285
  if (!Array.isArray(content)) return;
33188
33286
  for (const item of content) {
33189
33287
  if (!item || typeof item !== "object") continue;
33190
33288
  const o = item;
33191
33289
  if (typeof o.type === "string" && o.type.toLowerCase() === "diff") {
33192
- for (const k of PATH_KEYS) if (k in o) addPath(cwd, o[k], out);
33290
+ for (const k of PATH_KEYS) if (k in o) addPath(sessionParentPath, o[k], out);
33193
33291
  }
33194
33292
  if (o.type === "content" && o.content != null && typeof o.content === "object") {
33195
33293
  const inner = o.content;
33196
33294
  if (typeof inner.type === "string" && inner.type.toLowerCase() === "diff") {
33197
- for (const k of PATH_KEYS) if (k in inner) addPath(cwd, inner[k], out);
33295
+ for (const k of PATH_KEYS) if (k in inner) addPath(sessionParentPath, inner[k], out);
33198
33296
  }
33199
33297
  }
33200
33298
  }
33201
33299
  }
33202
- function extractToolTargetDisplayPaths(update, cwd) {
33300
+ function extractToolTargetDisplayPaths(update, sessionParentPath) {
33203
33301
  const out = /* @__PURE__ */ new Set();
33204
33302
  if (!update || typeof update !== "object") return [];
33205
33303
  const u = update;
33206
- walkLocations(cwd, u.locations, out);
33207
- walkLocations(cwd, u.fileLocations, out);
33208
- walkLocations(cwd, u.file_locations, out);
33304
+ walkLocations(sessionParentPath, u.locations, out);
33305
+ walkLocations(sessionParentPath, u.fileLocations, out);
33306
+ walkLocations(sessionParentPath, u.file_locations, out);
33209
33307
  const tc = u.toolCall ?? u.tool_call;
33210
33308
  if (tc && typeof tc.arguments === "string") {
33211
33309
  try {
33212
33310
  const parsed = JSON.parse(tc.arguments);
33213
- collectUnknown(cwd, parsed, out, 0);
33311
+ collectUnknown(sessionParentPath, parsed, out, 0);
33214
33312
  } catch {
33215
33313
  }
33216
33314
  }
33217
- walkContentArray(cwd, u.content, out);
33218
- collectFromObject(cwd, u, out, 0);
33315
+ walkContentArray(sessionParentPath, u.content, out);
33316
+ collectFromObject(sessionParentPath, u, out, 0);
33219
33317
  return [...out];
33220
33318
  }
33221
33319
 
@@ -33281,7 +33379,7 @@ var PathSnapshotTracker = class {
33281
33379
  this.beforeByToolKey.delete(toolKey);
33282
33380
  this.accumulatedPathsByToolKey.delete(toolKey);
33283
33381
  }
33284
- captureBeforeFromDisk(toolKey, paths, cwd) {
33382
+ captureBeforeFromDisk(toolKey, paths, sessionParentPath) {
33285
33383
  if (paths.length === 0) return;
33286
33384
  let m = this.beforeByToolKey.get(toolKey);
33287
33385
  if (!m) {
@@ -33290,10 +33388,10 @@ var PathSnapshotTracker = class {
33290
33388
  }
33291
33389
  for (const p of paths) {
33292
33390
  if (m.has(p)) continue;
33293
- m.set(p, readUtf8WorkspaceFile(cwd, p));
33391
+ m.set(p, readUtf8WorkspaceFile(sessionParentPath, p));
33294
33392
  }
33295
33393
  }
33296
- ensureBeforeFromHeadForMissing(toolKey, paths, cwd) {
33394
+ ensureBeforeFromHeadForMissing(toolKey, paths, sessionParentPath) {
33297
33395
  let m = this.beforeByToolKey.get(toolKey);
33298
33396
  if (!m) {
33299
33397
  m = /* @__PURE__ */ new Map();
@@ -33301,10 +33399,10 @@ var PathSnapshotTracker = class {
33301
33399
  }
33302
33400
  for (const p of paths) {
33303
33401
  if (m.has(p)) continue;
33304
- m.set(p, readGitHeadBlob(cwd, p));
33402
+ m.set(p, readGitHeadBlob(sessionParentPath, p));
33305
33403
  }
33306
33404
  }
33307
- flushPathSnapshots(toolKey, cwd, sentPaths, send, runId, sessionId, log2) {
33405
+ flushPathSnapshots(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2) {
33308
33406
  const t = this.debouncers.get(toolKey);
33309
33407
  if (t) clearTimeout(t);
33310
33408
  this.debouncers.delete(toolKey);
@@ -33313,10 +33411,10 @@ var PathSnapshotTracker = class {
33313
33411
  this.beforeByToolKey.delete(toolKey);
33314
33412
  if (!send || !runId || !sessionId) return;
33315
33413
  for (const [displayPath, oldText] of beforeMap) {
33316
- const newText = readUtf8WorkspaceFile(cwd, displayPath);
33414
+ const newText = readUtf8WorkspaceFile(sessionParentPath, displayPath);
33317
33415
  if (oldText === newText) continue;
33318
33416
  const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
33319
- const dirFlags = getSessionFileChangeDirectoryFlags(cwd, displayPath);
33417
+ const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath);
33320
33418
  try {
33321
33419
  send({
33322
33420
  type: "session_file_change",
@@ -33335,31 +33433,31 @@ var PathSnapshotTracker = class {
33335
33433
  }
33336
33434
  }
33337
33435
  }
33338
- scheduleDebouncedFlush(toolKey, cwd, sentPaths, send, runId, sessionId, log2) {
33436
+ scheduleDebouncedFlush(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2) {
33339
33437
  const prev = this.debouncers.get(toolKey);
33340
33438
  if (prev) clearTimeout(prev);
33341
33439
  this.debouncers.set(
33342
33440
  toolKey,
33343
33441
  setTimeout(() => {
33344
33442
  this.debouncers.delete(toolKey);
33345
- this.flushPathSnapshots(toolKey, cwd, sentPaths, send, runId, sessionId, log2);
33443
+ this.flushPathSnapshots(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2);
33346
33444
  }, PATH_SNAPSHOT_DEBOUNCE_MS)
33347
33445
  );
33348
33446
  }
33349
- handleToolCallLifecycle(updateKind, toolKey, toolPaths, status, cwd, sentPaths, send, runId, sessionId, log2) {
33447
+ handleToolCallLifecycle(updateKind, toolKey, toolPaths, status, sessionParentPath, sentPaths, send, runId, sessionId, log2) {
33350
33448
  if (updateKind === "tool_call") {
33351
33449
  this.resetToolSnapshots(toolKey);
33352
33450
  }
33353
33451
  if (updateKind === "tool_call") {
33354
- this.captureBeforeFromDisk(toolKey, toolPaths, cwd);
33452
+ this.captureBeforeFromDisk(toolKey, toolPaths, sessionParentPath);
33355
33453
  } else if (updateKind === "tool_call_update") {
33356
33454
  if (isCompletedToolStatus(status)) {
33357
- this.ensureBeforeFromHeadForMissing(toolKey, toolPaths, cwd);
33358
- this.flushPathSnapshots(toolKey, cwd, sentPaths, send, runId, sessionId, log2);
33455
+ this.ensureBeforeFromHeadForMissing(toolKey, toolPaths, sessionParentPath);
33456
+ this.flushPathSnapshots(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2);
33359
33457
  } else {
33360
- this.captureBeforeFromDisk(toolKey, toolPaths, cwd);
33458
+ this.captureBeforeFromDisk(toolKey, toolPaths, sessionParentPath);
33361
33459
  if (this.beforeByToolKey.has(toolKey)) {
33362
- this.scheduleDebouncedFlush(toolKey, cwd, sentPaths, send, runId, sessionId, log2);
33460
+ this.scheduleDebouncedFlush(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2);
33363
33461
  }
33364
33462
  }
33365
33463
  }
@@ -33367,11 +33465,11 @@ var PathSnapshotTracker = class {
33367
33465
  };
33368
33466
 
33369
33467
  // src/agents/acp/hooks/bridge-on-session-update/send-structured-file-changes.ts
33370
- function sendExtractedDiffsAsSessionFileChanges(diffs, send, cwd, sessionId, runId, sentPaths, log2) {
33468
+ function sendExtractedDiffsAsSessionFileChanges(diffs, send, sessionParentPath, sessionId, runId, sentPaths, log2) {
33371
33469
  for (const d of diffs) {
33372
33470
  try {
33373
33471
  const patchContent = editSnippetToUnifiedDiff(d.path, d.oldText, d.newText);
33374
- const dirFlags = getSessionFileChangeDirectoryFlags(cwd, d.path);
33472
+ const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, d.path);
33375
33473
  send({
33376
33474
  type: "session_file_change",
33377
33475
  sessionId,
@@ -33389,15 +33487,15 @@ function sendExtractedDiffsAsSessionFileChanges(diffs, send, cwd, sessionId, run
33389
33487
  }
33390
33488
  }
33391
33489
  }
33392
- function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send, cwd, sessionId, runId, log2) {
33490
+ function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send, sessionParentPath, sessionId, runId, log2) {
33393
33491
  for (const displayPath of mergedPaths) {
33394
33492
  if (sentPaths.has(displayPath)) continue;
33395
- const oldText = readGitHeadBlob(cwd, displayPath);
33396
- const newText = readUtf8WorkspaceFile(cwd, displayPath);
33493
+ const oldText = readGitHeadBlob(sessionParentPath, displayPath);
33494
+ const newText = readUtf8WorkspaceFile(sessionParentPath, displayPath);
33397
33495
  if (oldText === newText) continue;
33398
33496
  try {
33399
33497
  const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
33400
- const dirFlags = getSessionFileChangeDirectoryFlags(cwd, displayPath);
33498
+ const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath);
33401
33499
  send({
33402
33500
  type: "session_file_change",
33403
33501
  sessionId,
@@ -33418,13 +33516,12 @@ function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send, cwd, s
33418
33516
 
33419
33517
  // src/agents/acp/hooks/bridge-on-session-update/create-bridge-on-session-update.ts
33420
33518
  function createBridgeOnSessionUpdate(opts) {
33421
- const { routing, getSendSessionUpdate, log: log2 } = opts;
33519
+ const { routing, getSendSessionUpdate, log: log2, sessionParentPath } = opts;
33422
33520
  const pathTracker = new PathSnapshotTracker();
33423
33521
  return (params) => {
33424
33522
  const runId = routing.runId;
33425
33523
  const sessionId = routing.sessionId;
33426
33524
  pathTracker.onRunIdChanged(runId);
33427
- const cwd = getBridgeWorkspaceDirectory();
33428
33525
  const send = getSendSessionUpdate();
33429
33526
  const sentFileChangePaths = /* @__PURE__ */ new Set();
33430
33527
  const p = params;
@@ -33432,7 +33529,7 @@ function createBridgeOnSessionUpdate(opts) {
33432
33529
  const isCompletedToolCallUpdate = updateKind === "tool_call_update" && isCompletedToolStatus(p.status);
33433
33530
  const toolName = p.toolCall?.name ?? p.tool_call?.name ?? "";
33434
33531
  const isToolUpdate = updateKind === "tool_call" || updateKind === "tool_call_update" || typeof toolName === "string" && toolName.length > 0;
33435
- const toolPaths = isToolUpdate ? extractToolTargetDisplayPaths(params, cwd) : [];
33532
+ const toolPaths = isToolUpdate ? extractToolTargetDisplayPaths(params, sessionParentPath) : [];
33436
33533
  const toolKey = isToolUpdate ? pathTracker.resolveToolKey(params, updateKind) : "";
33437
33534
  if (updateKind === "tool_call") {
33438
33535
  pathTracker.resetToolSnapshots(toolKey);
@@ -33447,7 +33544,7 @@ function createBridgeOnSessionUpdate(opts) {
33447
33544
  toolKey,
33448
33545
  toolPaths,
33449
33546
  p.status,
33450
- cwd,
33547
+ sessionParentPath,
33451
33548
  sentFileChangePaths,
33452
33549
  deliver,
33453
33550
  runId ?? "",
@@ -33455,9 +33552,17 @@ function createBridgeOnSessionUpdate(opts) {
33455
33552
  log2
33456
33553
  );
33457
33554
  }
33458
- const diffs = extractAcpFileDiffsFromUpdate(params, cwd);
33555
+ const diffs = extractAcpFileDiffsFromUpdate(params, sessionParentPath);
33459
33556
  if (diffs.length > 0 && send && runId && sessionId) {
33460
- sendExtractedDiffsAsSessionFileChanges(diffs, send, cwd, sessionId, runId, sentFileChangePaths, log2);
33557
+ sendExtractedDiffsAsSessionFileChanges(
33558
+ diffs,
33559
+ send,
33560
+ sessionParentPath,
33561
+ sessionId,
33562
+ runId,
33563
+ sentFileChangePaths,
33564
+ log2
33565
+ );
33461
33566
  } else if (diffs.length > 0) {
33462
33567
  log2(
33463
33568
  `[Bridge service] Agent file diff(s) not forwarded (${diffs.length}): session or run not wired to the bridge.`
@@ -33466,7 +33571,15 @@ function createBridgeOnSessionUpdate(opts) {
33466
33571
  if (isCompletedToolCallUpdate && send && runId && sessionId) {
33467
33572
  const acc = pathTracker.accumulatedPathsByToolKey.get(toolKey);
33468
33573
  const merged = [.../* @__PURE__ */ new Set([...acc ? [...acc] : [], ...toolPaths])];
33469
- sendGitHeadVsWorkspaceForToolPaths(merged, sentFileChangePaths, send, cwd, sessionId, runId, log2);
33574
+ sendGitHeadVsWorkspaceForToolPaths(
33575
+ merged,
33576
+ sentFileChangePaths,
33577
+ send,
33578
+ sessionParentPath,
33579
+ sessionId,
33580
+ runId,
33581
+ log2
33582
+ );
33470
33583
  pathTracker.accumulatedPathsByToolKey.delete(toolKey);
33471
33584
  }
33472
33585
  if (runId && send) {
@@ -33501,11 +33614,12 @@ function buildAcpSessionBridgeHooks(opts) {
33501
33614
 
33502
33615
  // src/agents/acp/ensure-acp-client.ts
33503
33616
  async function ensureAcpClient(options) {
33504
- const { state, preferredAgentType, mode, cwd, routing, sendSessionUpdate, sendRequest, log: log2 } = options;
33505
- const targetCwd = path11.resolve(
33506
- cwd != null && String(cwd).trim() !== "" ? String(cwd).trim() : getBridgeWorkspaceDirectory()
33507
- );
33508
- if (state.acpHandle && state.lastAcpCwd != null && path11.resolve(state.lastAcpCwd) !== path11.resolve(targetCwd)) {
33617
+ const { state, preferredAgentType, mode, sessionParentPath, routing, sendSessionUpdate, sendRequest, log: log2 } = options;
33618
+ const targetSessionParentPath = resolveSessionParentPathForAgentProcess(sessionParentPath);
33619
+ if (state.acpStartPromise && !state.acpHandle) {
33620
+ await state.acpStartPromise;
33621
+ }
33622
+ if (state.acpHandle && state.lastAcpCwd != null && path12.resolve(state.lastAcpCwd) !== path12.resolve(targetSessionParentPath)) {
33509
33623
  try {
33510
33624
  state.acpHandle.disconnect();
33511
33625
  } catch {
@@ -33537,14 +33651,14 @@ async function ensureAcpClient(options) {
33537
33651
  if (!state.acpStartPromise) {
33538
33652
  let statOk = false;
33539
33653
  try {
33540
- const st = fs10.statSync(targetCwd);
33654
+ const st = fs10.statSync(targetSessionParentPath);
33541
33655
  statOk = st.isDirectory();
33542
33656
  if (!statOk) {
33543
- state.lastAcpStartError = `Agent cwd is not a directory: ${targetCwd}`;
33657
+ state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
33544
33658
  log2(`[Agent] ${state.lastAcpStartError}`);
33545
33659
  }
33546
33660
  } catch {
33547
- state.lastAcpStartError = `Agent cwd missing or inaccessible: ${targetCwd}`;
33661
+ state.lastAcpStartError = `Agent cwd missing or inaccessible: ${targetSessionParentPath}`;
33548
33662
  log2(`[Agent] ${state.lastAcpStartError}`);
33549
33663
  }
33550
33664
  if (!statOk) {
@@ -33552,6 +33666,7 @@ async function ensureAcpClient(options) {
33552
33666
  }
33553
33667
  const hooks = buildAcpSessionBridgeHooks({
33554
33668
  routing,
33669
+ sessionParentPath: targetSessionParentPath,
33555
33670
  getSendSessionUpdate: () => sendSessionUpdate,
33556
33671
  getSendRequest: () => sendRequest,
33557
33672
  log: log2
@@ -33559,7 +33674,6 @@ async function ensureAcpClient(options) {
33559
33674
  state.acpStartPromise = resolved.createClient({
33560
33675
  command: resolved.command,
33561
33676
  sessionMode: mode,
33562
- cwd: targetCwd,
33563
33677
  backendAgentType: preferredAgentType,
33564
33678
  onAgentSubprocessExit: () => {
33565
33679
  state.acpHandle = null;
@@ -33567,11 +33681,12 @@ async function ensureAcpClient(options) {
33567
33681
  state.acpAgentKey = null;
33568
33682
  state.lastAcpStartError = "Agent subprocess exited";
33569
33683
  },
33570
- ...hooks
33684
+ ...hooks,
33685
+ cwd: targetSessionParentPath
33571
33686
  }).then((h) => {
33572
33687
  state.lastAcpStartError = null;
33573
33688
  state.acpHandle = h;
33574
- state.lastAcpCwd = targetCwd;
33689
+ state.lastAcpCwd = targetSessionParentPath;
33575
33690
  state.acpAgentKey = agentKey;
33576
33691
  return h;
33577
33692
  }).catch((err) => {
@@ -33620,7 +33735,7 @@ async function createAcpManager(options) {
33620
33735
  runId,
33621
33736
  mode,
33622
33737
  agentType,
33623
- cwd,
33738
+ sessionParentPath,
33624
33739
  sendResult: sendResult2,
33625
33740
  sendSessionUpdate,
33626
33741
  followUpCatalogPromptId,
@@ -33639,7 +33754,7 @@ async function createAcpManager(options) {
33639
33754
  state,
33640
33755
  preferredAgentType: preferredForPrompt,
33641
33756
  mode,
33642
- cwd,
33757
+ sessionParentPath,
33643
33758
  routing: promptRouting,
33644
33759
  sendSessionUpdate,
33645
33760
  sendRequest: sendSessionUpdate,
@@ -33688,7 +33803,7 @@ async function createAcpManager(options) {
33688
33803
  sessionId,
33689
33804
  runId,
33690
33805
  agentType: preferredForPrompt,
33691
- agentCwd: cwd,
33806
+ agentCwd: resolveSessionParentPathForAgentProcess(sessionParentPath),
33692
33807
  sendResult: sendResult2,
33693
33808
  sendSessionUpdate,
33694
33809
  log: log2,
@@ -33743,12 +33858,12 @@ async function createAcpManager(options) {
33743
33858
  }
33744
33859
 
33745
33860
  // src/worktrees/session-worktree-manager.ts
33746
- import * as path18 from "node:path";
33861
+ import * as path19 from "node:path";
33747
33862
  import os4 from "node:os";
33748
33863
 
33749
33864
  // src/worktrees/prepare-new-session-worktrees.ts
33750
33865
  import * as fs12 from "node:fs";
33751
- import * as path13 from "node:path";
33866
+ import * as path14 from "node:path";
33752
33867
 
33753
33868
  // src/git/worktree-add.ts
33754
33869
  async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
@@ -33758,11 +33873,11 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
33758
33873
 
33759
33874
  // src/worktrees/worktree-layout-file.ts
33760
33875
  import * as fs11 from "node:fs";
33761
- import * as path12 from "node:path";
33876
+ import * as path13 from "node:path";
33762
33877
  import os3 from "node:os";
33763
33878
  var LAYOUT_FILENAME = "worktree-launcher-layout.json";
33764
33879
  function defaultWorktreeLayoutPath() {
33765
- return path12.join(os3.homedir(), ".buildautomaton", LAYOUT_FILENAME);
33880
+ return path13.join(os3.homedir(), ".buildautomaton", LAYOUT_FILENAME);
33766
33881
  }
33767
33882
  function normalizeLoadedLayout(raw) {
33768
33883
  if (raw && typeof raw === "object" && "launcherCwds" in raw) {
@@ -33783,24 +33898,24 @@ function loadWorktreeLayout() {
33783
33898
  }
33784
33899
  function saveWorktreeLayout(layout) {
33785
33900
  try {
33786
- const dir = path12.dirname(defaultWorktreeLayoutPath());
33901
+ const dir = path13.dirname(defaultWorktreeLayoutPath());
33787
33902
  fs11.mkdirSync(dir, { recursive: true });
33788
33903
  fs11.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
33789
33904
  } catch {
33790
33905
  }
33791
33906
  }
33792
- function baseNameSafe(abs) {
33793
- return path12.basename(abs).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
33907
+ function baseNameSafe(pathString) {
33908
+ return path13.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
33794
33909
  }
33795
- function getLauncherDirNameIfPresent(layout, launcherCwdAbs) {
33796
- const norm = path12.resolve(launcherCwdAbs);
33797
- const existing = layout.launcherCwds.find((e) => path12.resolve(e.absolutePath) === norm);
33910
+ function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
33911
+ const norm = path13.resolve(bridgeRootPath2);
33912
+ const existing = layout.launcherCwds.find((e) => path13.resolve(e.absolutePath) === norm);
33798
33913
  return existing?.dirName;
33799
33914
  }
33800
- function allocateDirNameForLauncherCwd(layout, launcherCwdAbs) {
33801
- const existing = getLauncherDirNameIfPresent(layout, launcherCwdAbs);
33915
+ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
33916
+ const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
33802
33917
  if (existing) return existing;
33803
- const norm = path12.resolve(launcherCwdAbs);
33918
+ const norm = path13.resolve(bridgeRootPath2);
33804
33919
  const base = baseNameSafe(norm);
33805
33920
  const used = new Set(layout.launcherCwds.map((e) => e.dirName));
33806
33921
  let name = base;
@@ -33816,24 +33931,27 @@ function allocateDirNameForLauncherCwd(layout, launcherCwdAbs) {
33816
33931
 
33817
33932
  // src/worktrees/prepare-new-session-worktrees.ts
33818
33933
  async function prepareNewSessionWorktrees(options) {
33819
- const { rootAbs, launcherCwd, sessionId, layout, log: log2 } = options;
33820
- const launcherResolved = path13.resolve(launcherCwd);
33821
- const cwdKey = allocateDirNameForLauncherCwd(layout, launcherResolved);
33822
- const agentMirrorRoot = path13.join(rootAbs, cwdKey);
33823
- const repos = await discoverGitReposUnderRoot(launcherResolved);
33934
+ const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2 } = options;
33935
+ const bridgeResolved = path14.resolve(bridgeRoot);
33936
+ const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
33937
+ const bridgeKeyDir = path14.join(worktreesRootPath, cwdKey);
33938
+ const sessionDir = path14.join(bridgeKeyDir, sessionId);
33939
+ const repos = await discoverGitReposUnderRoot(bridgeResolved);
33824
33940
  if (repos.length === 0) {
33825
- log2("[worktrees] No Git repositories under launcher working directory; skipping worktree creation.");
33941
+ log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
33826
33942
  return null;
33827
33943
  }
33828
33944
  const branch = `session-${sessionId}`;
33829
33945
  const worktreePaths = [];
33830
- fs12.mkdirSync(agentMirrorRoot, { recursive: true });
33946
+ fs12.mkdirSync(sessionDir, { recursive: true });
33831
33947
  for (const repo of repos) {
33832
- let rel = path13.relative(launcherResolved, repo.absolutePath);
33833
- if (rel.startsWith("..") || path13.isAbsolute(rel)) continue;
33948
+ let rel = path14.relative(bridgeResolved, repo.absolutePath);
33949
+ if (rel.startsWith("..") || path14.isAbsolute(rel)) continue;
33834
33950
  const relNorm = rel === "" ? "." : rel;
33835
- const wtPath = path13.join(agentMirrorRoot, relNorm, sessionId);
33836
- fs12.mkdirSync(path13.dirname(wtPath), { recursive: true });
33951
+ const wtPath = relNorm === "." ? sessionDir : path14.join(sessionDir, relNorm);
33952
+ if (relNorm !== ".") {
33953
+ fs12.mkdirSync(path14.dirname(wtPath), { recursive: true });
33954
+ }
33837
33955
  try {
33838
33956
  await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
33839
33957
  log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}).`);
@@ -33845,7 +33963,11 @@ async function prepareNewSessionWorktrees(options) {
33845
33963
  }
33846
33964
  }
33847
33965
  if (worktreePaths.length === 0) return null;
33848
- return { worktreePaths, agentCwd: agentMirrorRoot };
33966
+ return {
33967
+ worktreePaths,
33968
+ sessionParentPath: sessionDir,
33969
+ workingTreeRelRoot: sessionDir
33970
+ };
33849
33971
  }
33850
33972
 
33851
33973
  // src/git/rename-branch.ts
@@ -33877,16 +33999,16 @@ import * as fs14 from "node:fs";
33877
33999
 
33878
34000
  // src/git/resolve-main-repo-from-git-file.ts
33879
34001
  import * as fs13 from "node:fs";
33880
- import * as path14 from "node:path";
34002
+ import * as path15 from "node:path";
33881
34003
  function resolveMainRepoFromWorktreeGitFile(wt) {
33882
- const gitDirFile = path14.join(wt, ".git");
34004
+ const gitDirFile = path15.join(wt, ".git");
33883
34005
  if (!fs13.existsSync(gitDirFile) || !fs13.statSync(gitDirFile).isFile()) return "";
33884
34006
  const first2 = fs13.readFileSync(gitDirFile, "utf8").trim();
33885
34007
  const m = first2.match(/^gitdir:\s*(.+)$/im);
33886
34008
  if (!m) return "";
33887
- const gitWorktreePath = path14.resolve(wt, m[1].trim());
33888
- const gitDir = path14.dirname(path14.dirname(gitWorktreePath));
33889
- return path14.dirname(gitDir);
34009
+ const gitWorktreePath = path15.resolve(wt, m[1].trim());
34010
+ const gitDir = path15.dirname(path15.dirname(gitWorktreePath));
34011
+ return path15.dirname(gitDir);
33890
34012
  }
33891
34013
 
33892
34014
  // src/git/worktree-remove.ts
@@ -34128,7 +34250,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
34128
34250
  }
34129
34251
 
34130
34252
  // src/git/working-directory/changes/get-working-tree-change-repo-details.ts
34131
- import * as path16 from "node:path";
34253
+ import * as path17 from "node:path";
34132
34254
 
34133
34255
  // src/git/working-directory/changes/parse-git-status.ts
34134
34256
  function parseNameStatusLines(lines) {
@@ -34249,16 +34371,16 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
34249
34371
 
34250
34372
  // src/git/working-directory/changes/list-changed-files-for-repo.ts
34251
34373
  import * as fs17 from "node:fs";
34252
- import * as path15 from "node:path";
34374
+ import * as path16 from "node:path";
34253
34375
 
34254
34376
  // src/git/working-directory/changes/count-lines.ts
34255
34377
  import { createReadStream } from "node:fs";
34256
34378
  import * as readline2 from "node:readline";
34257
- async function countTextFileLines(absFile) {
34379
+ async function countTextFileLines(filePath) {
34258
34380
  let bytes = 0;
34259
34381
  const maxBytes = 512e3;
34260
34382
  let lines = 0;
34261
- const stream = createReadStream(absFile, { encoding: "utf8" });
34383
+ const stream = createReadStream(filePath, { encoding: "utf8" });
34262
34384
  const rl = readline2.createInterface({ input: stream, crlfDelay: Infinity });
34263
34385
  for await (const _line of rl) {
34264
34386
  lines += 1;
@@ -34286,15 +34408,15 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
34286
34408
  return null;
34287
34409
  }
34288
34410
  }
34289
- async function readWorktreeFileLines(abs) {
34411
+ async function readWorktreeFileLines(filePath) {
34290
34412
  try {
34291
- const raw = await fs16.promises.readFile(abs, "utf8");
34413
+ const raw = await fs16.promises.readFile(filePath, "utf8");
34292
34414
  return raw.split(/\r?\n/);
34293
34415
  } catch {
34294
34416
  return null;
34295
34417
  }
34296
34418
  }
34297
- async function hydrateUnifiedPatchWithFileContext(patch, absFile, repoGitCwd, pathInRepo, change) {
34419
+ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, change) {
34298
34420
  if (!patch.trim() || patch.includes("Binary files")) return patch;
34299
34421
  const all = patch.split("\n");
34300
34422
  const out = [];
@@ -34311,7 +34433,7 @@ async function hydrateUnifiedPatchWithFileContext(patch, absFile, repoGitCwd, pa
34311
34433
  };
34312
34434
  const diskLines = async () => {
34313
34435
  if (diskCache !== void 0) return diskCache;
34314
- diskCache = await readWorktreeFileLines(absFile);
34436
+ diskCache = await readWorktreeFileLines(filePath);
34315
34437
  return diskCache;
34316
34438
  };
34317
34439
  while (i < all.length) {
@@ -34423,7 +34545,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
34423
34545
  const rows = [];
34424
34546
  for (const pathInRepo of paths) {
34425
34547
  const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
34426
- const abs = path15.join(repoGitCwd, pathInRepo);
34548
+ const repoFilePath = path16.join(repoGitCwd, pathInRepo);
34427
34549
  const nums = numByPath.get(pathInRepo);
34428
34550
  let additions = nums?.additions ?? 0;
34429
34551
  let deletions = nums?.deletions ?? 0;
@@ -34436,8 +34558,8 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
34436
34558
  deletions = fromGit.deletions;
34437
34559
  } else {
34438
34560
  try {
34439
- const st = await fs17.promises.stat(abs);
34440
- if (st.isFile()) additions = await countTextFileLines(abs);
34561
+ const st = await fs17.promises.stat(repoFilePath);
34562
+ if (st.isFile()) additions = await countTextFileLines(repoFilePath);
34441
34563
  else additions = 0;
34442
34564
  } catch {
34443
34565
  additions = 0;
@@ -34462,10 +34584,10 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
34462
34584
  } else {
34463
34585
  pathInRepo = row.pathRelLauncher;
34464
34586
  }
34465
- const absFile = path15.join(repoGitCwd, pathInRepo);
34587
+ const filePath = path16.join(repoGitCwd, pathInRepo);
34466
34588
  let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
34467
34589
  if (patch) {
34468
- patch = await hydrateUnifiedPatchWithFileContext(patch, absFile, repoGitCwd, pathInRepo, row.change);
34590
+ patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
34469
34591
  }
34470
34592
  row.patchContent = patch;
34471
34593
  }
@@ -34478,8 +34600,9 @@ function normRepoRel(p) {
34478
34600
  return x === "" ? "." : x;
34479
34601
  }
34480
34602
  async function getWorkingTreeChangeRepoDetails(options) {
34481
- const launcher = path16.resolve(getBridgeWorkspaceDirectory());
34482
- const mirror = options.agentMirrorRootAbs ? path16.resolve(options.agentMirrorRootAbs) : null;
34603
+ const bridgeRoot = path17.resolve(getBridgeRoot());
34604
+ const sessionWtRoot = options.sessionWorktreeRootPath ? path17.resolve(options.sessionWorktreeRootPath) : null;
34605
+ const legacyNested = options.legacyRepoNestedSessionLayout === true;
34483
34606
  const out = [];
34484
34607
  const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
34485
34608
  const basisInput = options.basis ?? { kind: "working" };
@@ -34490,8 +34613,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
34490
34613
  throw new Error("commit sha is required for commit changes");
34491
34614
  }
34492
34615
  const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
34493
- for (const target of options.commitTargetAbsDirs) {
34494
- const t = path16.resolve(target);
34616
+ for (const target of options.commitTargetPaths) {
34617
+ const t = path17.resolve(target);
34495
34618
  if (!await isGitRepoDirectory(t)) continue;
34496
34619
  const g = simpleGit(t);
34497
34620
  let branch = "HEAD";
@@ -34503,8 +34626,9 @@ async function getWorkingTreeChangeRepoDetails(options) {
34503
34626
  const remoteUrl = await getRemoteOriginUrl(t);
34504
34627
  const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
34505
34628
  let repoRelPath;
34506
- if (mirror) {
34507
- const relNorm = path16.relative(mirror, path16.dirname(t));
34629
+ if (sessionWtRoot) {
34630
+ const anchor = legacyNested ? path17.dirname(t) : t;
34631
+ const relNorm = path17.relative(sessionWtRoot, anchor);
34508
34632
  repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
34509
34633
  } else {
34510
34634
  let top = t;
@@ -34513,8 +34637,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
34513
34637
  } catch {
34514
34638
  top = t;
34515
34639
  }
34516
- const rel = path16.relative(launcher, path16.resolve(top)).replace(/\\/g, "/") || ".";
34517
- repoRelPath = rel.startsWith("..") ? path16.basename(path16.resolve(top)) : rel;
34640
+ const rel = path17.relative(bridgeRoot, path17.resolve(top)).replace(/\\/g, "/") || ".";
34641
+ repoRelPath = rel.startsWith("..") ? path17.basename(path17.resolve(top)) : rel;
34518
34642
  }
34519
34643
  const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
34520
34644
  if (filter && norm !== filter) continue;
@@ -34580,14 +34704,37 @@ async function commitSessionWorktrees(options) {
34580
34704
 
34581
34705
  // src/worktrees/discover-session-worktree-on-disk.ts
34582
34706
  import * as fs18 from "node:fs";
34583
- import * as path17 from "node:path";
34584
- function isGitDir(abs) {
34707
+ import * as path18 from "node:path";
34708
+ function isGitDir(dirPath) {
34585
34709
  try {
34586
- return fs18.existsSync(path17.join(abs, ".git"));
34710
+ return fs18.existsSync(path18.join(dirPath, ".git"));
34587
34711
  } catch {
34588
34712
  return false;
34589
34713
  }
34590
34714
  }
34715
+ function collectGitRepoRootsUnderDirectory(rootPath) {
34716
+ const out = [];
34717
+ const walk = (dir) => {
34718
+ if (isGitDir(dir)) {
34719
+ out.push(path18.resolve(dir));
34720
+ return;
34721
+ }
34722
+ let entries;
34723
+ try {
34724
+ entries = fs18.readdirSync(dir, { withFileTypes: true });
34725
+ } catch {
34726
+ return;
34727
+ }
34728
+ for (const e of entries) {
34729
+ if (e.name.startsWith(".")) continue;
34730
+ const full = path18.join(dir, e.name);
34731
+ if (!e.isDirectory()) continue;
34732
+ walk(full);
34733
+ }
34734
+ };
34735
+ walk(path18.resolve(rootPath));
34736
+ return [...new Set(out)];
34737
+ }
34591
34738
  function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
34592
34739
  const out = [];
34593
34740
  const walk = (dir, depth) => {
@@ -34600,10 +34747,10 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
34600
34747
  }
34601
34748
  for (const e of entries) {
34602
34749
  if (e.name.startsWith(".")) continue;
34603
- const full = path17.join(dir, e.name);
34750
+ const full = path18.join(dir, e.name);
34604
34751
  if (!e.isDirectory()) continue;
34605
34752
  if (e.name === sessionId) {
34606
- if (isGitDir(full)) out.push(path17.resolve(full));
34753
+ if (isGitDir(full)) out.push(path18.resolve(full));
34607
34754
  } else {
34608
34755
  walk(full, depth + 1);
34609
34756
  }
@@ -34612,16 +34759,55 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
34612
34759
  walk(root, 0);
34613
34760
  return out;
34614
34761
  }
34762
+ function tryBindingFromSessionDirectory(sessionDir) {
34763
+ let st;
34764
+ try {
34765
+ st = fs18.statSync(sessionDir);
34766
+ } catch {
34767
+ return null;
34768
+ }
34769
+ if (!st.isDirectory()) return null;
34770
+ const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
34771
+ if (worktreePaths.length === 0) return null;
34772
+ const abs = path18.resolve(sessionDir);
34773
+ return {
34774
+ sessionParentPath: abs,
34775
+ workingTreeRelRoot: abs,
34776
+ repoCheckoutPaths: worktreePaths
34777
+ };
34778
+ }
34779
+ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
34780
+ const sid = sessionId.trim();
34781
+ if (!sid) return null;
34782
+ const hintR = path18.resolve(checkoutPath);
34783
+ let best = null;
34784
+ let cur = path18.dirname(hintR);
34785
+ for (let i = 0; i < 40; i++) {
34786
+ const paths = collectWorktreeRootsNamed(cur, sid, 24);
34787
+ if (paths.some((p) => path18.resolve(p) === hintR)) {
34788
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path18.resolve(paths[0]);
34789
+ best = {
34790
+ sessionParentPath: path18.resolve(isolated),
34791
+ workingTreeRelRoot: path18.resolve(cur),
34792
+ repoCheckoutPaths: paths.map((p) => path18.resolve(p))
34793
+ };
34794
+ }
34795
+ const next = path18.dirname(cur);
34796
+ if (next === cur) break;
34797
+ cur = next;
34798
+ }
34799
+ return best;
34800
+ }
34615
34801
  function discoverSessionWorktreeOnDisk(options) {
34616
- const { sessionId, worktreesRootAbs, layout, launcherCwd } = options;
34617
- if (!sessionId.trim() || !fs18.existsSync(worktreesRootAbs)) return null;
34618
- const preferredKey = getLauncherDirNameIfPresent(layout, launcherCwd);
34802
+ const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
34803
+ if (!sessionId.trim() || !fs18.existsSync(worktreesRootPath)) return null;
34804
+ const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
34619
34805
  const keys = [];
34620
34806
  if (preferredKey) keys.push(preferredKey);
34621
34807
  try {
34622
- for (const name of fs18.readdirSync(worktreesRootAbs)) {
34808
+ for (const name of fs18.readdirSync(worktreesRootPath)) {
34623
34809
  if (name.startsWith(".")) continue;
34624
- const p = path17.join(worktreesRootAbs, name);
34810
+ const p = path18.join(worktreesRootPath, name);
34625
34811
  if (!fs18.statSync(p).isDirectory()) continue;
34626
34812
  if (name !== preferredKey) keys.push(name);
34627
34813
  }
@@ -34629,26 +34815,58 @@ function discoverSessionWorktreeOnDisk(options) {
34629
34815
  return null;
34630
34816
  }
34631
34817
  for (const key of keys) {
34632
- const mirrorRoot = path17.join(worktreesRootAbs, key);
34633
- if (!fs18.existsSync(mirrorRoot) || !fs18.statSync(mirrorRoot).isDirectory()) continue;
34634
- const worktreePaths = collectWorktreeRootsNamed(mirrorRoot, sessionId, 24);
34635
- if (worktreePaths.length > 0) {
34636
- return { agentCwd: path17.resolve(mirrorRoot), worktreePaths };
34818
+ const layoutRoot = path18.join(worktreesRootPath, key);
34819
+ if (!fs18.existsSync(layoutRoot) || !fs18.statSync(layoutRoot).isDirectory()) continue;
34820
+ const sessionDir = path18.join(layoutRoot, sessionId);
34821
+ const nested = tryBindingFromSessionDirectory(sessionDir);
34822
+ if (nested) return nested;
34823
+ const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
34824
+ if (legacyPaths.length > 0) {
34825
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path18.resolve(legacyPaths[0]);
34826
+ return {
34827
+ sessionParentPath: path18.resolve(isolated),
34828
+ workingTreeRelRoot: path18.resolve(layoutRoot),
34829
+ repoCheckoutPaths: legacyPaths.map((p) => path18.resolve(p))
34830
+ };
34637
34831
  }
34638
34832
  }
34639
34833
  return null;
34640
34834
  }
34641
- function discoverSessionWorktreesUnderMirrorRoot(mirrorRootAbs, sessionId) {
34642
- const mirrorRoot = path17.resolve(mirrorRootAbs);
34643
- if (!sessionId.trim() || !fs18.existsSync(mirrorRoot)) return null;
34835
+ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
34836
+ const sid = sessionId.trim();
34837
+ if (!sid) return null;
34838
+ const hint = path18.resolve(sessionWorktreeRootPathOrHint);
34839
+ const underHint = tryBindingFromSessionDirectory(path18.join(hint, sid));
34840
+ if (underHint) return underHint;
34841
+ const direct = tryBindingFromSessionDirectory(hint);
34842
+ if (direct) {
34843
+ if (path18.basename(hint) === sid && isGitDir(hint)) {
34844
+ const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
34845
+ if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
34846
+ return legacyFromCheckout;
34847
+ }
34848
+ }
34849
+ return direct;
34850
+ }
34851
+ if (path18.basename(hint) === sid && isGitDir(hint)) {
34852
+ const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
34853
+ if (legacyFromCheckout) return legacyFromCheckout;
34854
+ }
34855
+ let st;
34644
34856
  try {
34645
- if (!fs18.statSync(mirrorRoot).isDirectory()) return null;
34857
+ st = fs18.statSync(hint);
34646
34858
  } catch {
34647
34859
  return null;
34648
34860
  }
34649
- const worktreePaths = collectWorktreeRootsNamed(mirrorRoot, sessionId, 24);
34650
- if (worktreePaths.length === 0) return null;
34651
- return { agentCwd: mirrorRoot, worktreePaths };
34861
+ if (!st.isDirectory()) return null;
34862
+ const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
34863
+ if (legacyPaths.length === 0) return null;
34864
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path18.resolve(legacyPaths[0]);
34865
+ return {
34866
+ sessionParentPath: path18.resolve(isolated),
34867
+ workingTreeRelRoot: hint,
34868
+ repoCheckoutPaths: legacyPaths.map((p) => path18.resolve(p))
34869
+ };
34652
34870
  }
34653
34871
 
34654
34872
  // src/worktrees/session-worktree-manager.ts
@@ -34658,42 +34876,86 @@ function parseSessionParent(v) {
34658
34876
  return null;
34659
34877
  }
34660
34878
  var SessionWorktreeManager = class {
34661
- rootAbs;
34879
+ worktreesRootPath;
34662
34880
  log;
34663
- sessionPaths = /* @__PURE__ */ new Map();
34664
- sessionAgentCwd = /* @__PURE__ */ new Map();
34881
+ sessionRepoCheckoutPaths = /* @__PURE__ */ new Map();
34882
+ sessionParentPathBySession = /* @__PURE__ */ new Map();
34883
+ sessionWorkingTreeRelRootBySession = /* @__PURE__ */ new Map();
34665
34884
  layout;
34666
34885
  constructor(options) {
34667
- this.rootAbs = options.worktreesRootAbs;
34886
+ this.worktreesRootPath = options.worktreesRootPath;
34668
34887
  this.log = options.log;
34669
34888
  this.layout = loadWorktreeLayout();
34670
34889
  }
34671
- rememberWorktrees(sessionId, agentCwd, worktreePaths) {
34672
- this.sessionPaths.set(sessionId, worktreePaths);
34673
- this.sessionAgentCwd.set(sessionId, path18.resolve(agentCwd));
34890
+ rememberSessionWorktrees(sessionId, binding) {
34891
+ const paths = binding.repoCheckoutPaths.map((p) => path19.resolve(p));
34892
+ this.sessionRepoCheckoutPaths.set(sessionId, paths);
34893
+ this.sessionParentPathBySession.set(sessionId, path19.resolve(binding.sessionParentPath));
34894
+ this.sessionWorkingTreeRelRootBySession.set(sessionId, path19.resolve(binding.workingTreeRelRoot));
34895
+ }
34896
+ sessionParentPathAfterRemember(sessionId) {
34897
+ return this.sessionParentPathBySession.get(sessionId);
34674
34898
  }
34675
34899
  tryDiscoverFromDisk(sessionId) {
34676
34900
  return discoverSessionWorktreeOnDisk({
34677
34901
  sessionId,
34678
- worktreesRootAbs: this.rootAbs,
34902
+ worktreesRootPath: this.worktreesRootPath,
34679
34903
  layout: this.layout,
34680
- launcherCwd: getBridgeWorkspaceDirectory()
34904
+ bridgeRoot: getBridgeRoot()
34681
34905
  });
34682
34906
  }
34907
+ isLegacyNestedLayout(sessionId) {
34908
+ const parent = this.sessionParentPathBySession.get(sessionId);
34909
+ const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
34910
+ if (!parent || !relRoot) return false;
34911
+ return path19.resolve(parent) !== path19.resolve(relRoot);
34912
+ }
34683
34913
  /**
34684
- * Returns cwd for the agent (mirror of launcher tree), or undefined to use the bridge workspace directory.
34914
+ * Session parent path for `worktrees_root`: the per-session directory (new layout) or primary checkout (legacy).
34685
34915
  */
34686
- async resolveCwdForPrompt(sessionId, opts) {
34916
+ getIsolatedSessionParentPathForSession(sessionId) {
34917
+ if (!sessionId) return null;
34918
+ const sid = sessionId.trim();
34919
+ const cached2 = this.sessionParentPathBySession.get(sid);
34920
+ if (cached2) return path19.resolve(cached2);
34921
+ const paths = this.ensureRepoCheckoutPathsForSession(sid) ?? this.getRepoCheckoutPathsForSession(sid);
34922
+ if (!paths?.length) return null;
34923
+ return resolveIsolatedSessionParentPathFromCheckouts(paths);
34924
+ }
34925
+ /**
34926
+ * Resolved **session parent path** for the agent: session directory in worktrees mode,
34927
+ * or `undefined` meaning use {@link getBridgeRoot}.
34928
+ */
34929
+ async resolveSessionParentPathForPrompt(sessionId, opts) {
34687
34930
  if (!sessionId) return void 0;
34931
+ const sid = sessionId.trim();
34688
34932
  const parentPathRaw = opts.sessionParentPath?.trim();
34689
34933
  if (parentPathRaw) {
34690
- const agentCwd = path18.resolve(parentPathRaw);
34691
- const sid = sessionId?.trim();
34934
+ const resolved = path19.resolve(parentPathRaw);
34692
34935
  if (sid && parseSessionParent(opts.sessionParent) === "worktrees_root") {
34693
- const fromMirror = discoverSessionWorktreesUnderMirrorRoot(agentCwd, sid);
34694
- if (fromMirror) this.rememberWorktrees(sid, fromMirror.agentCwd, fromMirror.worktreePaths);
34936
+ const diskFirst = this.tryDiscoverFromDisk(sid);
34937
+ if (diskFirst) {
34938
+ this.rememberSessionWorktrees(sid, diskFirst);
34939
+ return this.sessionParentPathAfterRemember(sid);
34940
+ }
34941
+ const fromRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(resolved, sid);
34942
+ if (fromRoot) {
34943
+ this.rememberSessionWorktrees(sid, fromRoot);
34944
+ return this.sessionParentPathAfterRemember(sid);
34945
+ }
34946
+ let cur = resolved;
34947
+ for (let i = 0; i < 16; i++) {
34948
+ const tryRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(cur, sid);
34949
+ if (tryRoot) {
34950
+ this.rememberSessionWorktrees(sid, tryRoot);
34951
+ return this.sessionParentPathAfterRemember(sid);
34952
+ }
34953
+ const next = path19.dirname(cur);
34954
+ if (next === cur) break;
34955
+ cur = next;
34956
+ }
34695
34957
  }
34696
- return agentCwd;
34958
+ return resolved;
34697
34959
  }
34698
34960
  const parentKind = parseSessionParent(opts.sessionParent);
34699
34961
  if (parentKind === "bridge_root") {
@@ -34701,78 +34963,102 @@ var SessionWorktreeManager = class {
34701
34963
  }
34702
34964
  if (parentKind === "worktrees_root") {
34703
34965
  if (!opts.isNewSession) {
34704
- const cached2 = this.sessionAgentCwd.get(sessionId);
34705
- if (cached2) return path18.resolve(cached2);
34706
- const disc = this.tryDiscoverFromDisk(sessionId);
34966
+ const cached2 = this.sessionParentPathAfterRemember(sid);
34967
+ if (cached2) return cached2;
34968
+ const disc = this.tryDiscoverFromDisk(sid);
34707
34969
  if (disc) {
34708
- this.rememberWorktrees(sessionId, disc.agentCwd, disc.worktreePaths);
34709
- return path18.resolve(disc.agentCwd);
34970
+ this.rememberSessionWorktrees(sid, disc);
34971
+ return this.sessionParentPathAfterRemember(sid);
34710
34972
  }
34711
34973
  return void 0;
34712
34974
  }
34713
34975
  const prep2 = await prepareNewSessionWorktrees({
34714
- rootAbs: this.rootAbs,
34715
- launcherCwd: getBridgeWorkspaceDirectory(),
34716
- sessionId,
34976
+ worktreesRootPath: this.worktreesRootPath,
34977
+ bridgeRoot: getBridgeRoot(),
34978
+ sessionId: sid,
34717
34979
  layout: this.layout,
34718
34980
  log: this.log
34719
34981
  });
34720
34982
  if (!prep2) return void 0;
34721
- this.rememberWorktrees(sessionId, prep2.agentCwd, prep2.worktreePaths);
34722
- return path18.resolve(prep2.agentCwd);
34983
+ this.rememberSessionWorktrees(sid, {
34984
+ sessionParentPath: prep2.sessionParentPath,
34985
+ workingTreeRelRoot: prep2.workingTreeRelRoot,
34986
+ repoCheckoutPaths: prep2.worktreePaths
34987
+ });
34988
+ return this.sessionParentPathAfterRemember(sid);
34723
34989
  }
34724
34990
  if (!opts.isNewSession) {
34725
- const cached2 = this.sessionAgentCwd.get(sessionId);
34726
- if (cached2) return path18.resolve(cached2);
34727
- const disc = this.tryDiscoverFromDisk(sessionId);
34991
+ const cached2 = this.sessionParentPathAfterRemember(sid);
34992
+ if (cached2) return cached2;
34993
+ const disc = this.tryDiscoverFromDisk(sid);
34728
34994
  if (disc) {
34729
- this.rememberWorktrees(sessionId, disc.agentCwd, disc.worktreePaths);
34730
- return path18.resolve(disc.agentCwd);
34995
+ this.rememberSessionWorktrees(sid, disc);
34996
+ return this.sessionParentPathAfterRemember(sid);
34731
34997
  }
34732
34998
  return void 0;
34733
34999
  }
34734
35000
  const prep = await prepareNewSessionWorktrees({
34735
- rootAbs: this.rootAbs,
34736
- launcherCwd: getBridgeWorkspaceDirectory(),
34737
- sessionId,
35001
+ worktreesRootPath: this.worktreesRootPath,
35002
+ bridgeRoot: getBridgeRoot(),
35003
+ sessionId: sid,
34738
35004
  layout: this.layout,
34739
35005
  log: this.log
34740
35006
  });
34741
35007
  if (!prep) return void 0;
34742
- this.rememberWorktrees(sessionId, prep.agentCwd, prep.worktreePaths);
34743
- return path18.resolve(prep.agentCwd);
35008
+ this.rememberSessionWorktrees(sid, {
35009
+ sessionParentPath: prep.sessionParentPath,
35010
+ workingTreeRelRoot: prep.workingTreeRelRoot,
35011
+ repoCheckoutPaths: prep.worktreePaths
35012
+ });
35013
+ return this.sessionParentPathAfterRemember(sid);
34744
35014
  }
34745
35015
  async renameSessionBranch(sessionId, newBranch) {
34746
- const paths = this.sessionPaths.get(sessionId);
35016
+ const paths = this.sessionRepoCheckoutPaths.get(sessionId);
34747
35017
  if (!paths?.length) return;
34748
35018
  await renameSessionWorktreeBranches(paths, newBranch, this.log);
34749
35019
  }
34750
- /** True when this session runs in an isolated worktree mirror (not launcher cwd). */
35020
+ /** True when this session uses an isolated worktree layout (not the bridge root). */
34751
35021
  usesWorktreeSession(sessionId) {
34752
35022
  if (!sessionId) return false;
34753
- return this.sessionAgentCwd.has(sessionId);
35023
+ return this.sessionParentPathBySession.has(sessionId);
34754
35024
  }
34755
- getWorktreePathsForSession(sessionId) {
35025
+ /** Per-repo git checkout directories for this session (for snapshots, commits, change lists). */
35026
+ getRepoCheckoutPathsForSession(sessionId) {
34756
35027
  if (!sessionId) return void 0;
34757
- const paths = this.sessionPaths.get(sessionId);
35028
+ const paths = this.sessionRepoCheckoutPaths.get(sessionId);
34758
35029
  return paths?.length ? [...paths] : void 0;
34759
35030
  }
34760
- /** Session mirror root (parent of per-repo worktrees), when using worktrees for this session. */
34761
- getAgentCwdForSession(sessionId) {
34762
- if (!sessionId) return null;
34763
- const c = this.sessionAgentCwd.get(sessionId);
34764
- return c ? path18.resolve(c) : null;
35031
+ /**
35032
+ * Same paths as {@link getRepoCheckoutPathsForSession}, but loads from disk into memory when the CLI
35033
+ * restarted or maps were not yet populated (avoids discovering every repo under the worktrees root).
35034
+ */
35035
+ ensureRepoCheckoutPathsForSession(sessionId) {
35036
+ if (!sessionId?.trim()) return void 0;
35037
+ const sid = sessionId.trim();
35038
+ const cached2 = this.sessionRepoCheckoutPaths.get(sid);
35039
+ if (cached2?.length) return [...cached2];
35040
+ const disc = this.tryDiscoverFromDisk(sid);
35041
+ if (disc?.repoCheckoutPaths.length) {
35042
+ this.rememberSessionWorktrees(sid, disc);
35043
+ return [...disc.repoCheckoutPaths];
35044
+ }
35045
+ return void 0;
35046
+ }
35047
+ /** Session parent directory when in worktrees mode; null otherwise (same as {@link getIsolatedSessionParentPathForSession} path). */
35048
+ getSessionWorktreeRootForSession(sessionId) {
35049
+ return this.getIsolatedSessionParentPathForSession(sessionId);
34765
35050
  }
34766
35051
  async removeSessionWorktrees(sessionId) {
34767
- const paths = this.sessionPaths.get(sessionId);
34768
- this.sessionPaths.delete(sessionId);
34769
- this.sessionAgentCwd.delete(sessionId);
35052
+ const paths = this.sessionRepoCheckoutPaths.get(sessionId);
35053
+ this.sessionRepoCheckoutPaths.delete(sessionId);
35054
+ this.sessionParentPathBySession.delete(sessionId);
35055
+ this.sessionWorkingTreeRelRootBySession.delete(sessionId);
34770
35056
  if (!paths?.length) return;
34771
35057
  await removeSessionWorktrees(paths, this.log);
34772
35058
  }
34773
35059
  async commitSession(params) {
34774
- const paths = this.sessionPaths.get(params.sessionId);
34775
- const targets = paths?.length ? paths : [getBridgeWorkspaceDirectory()];
35060
+ const paths = this.sessionRepoCheckoutPaths.get(params.sessionId);
35061
+ const targets = paths?.length ? paths : [getBridgeRoot()];
34776
35062
  return commitSessionWorktrees({
34777
35063
  paths: targets,
34778
35064
  branch: params.branch,
@@ -34781,14 +35067,14 @@ var SessionWorktreeManager = class {
34781
35067
  });
34782
35068
  }
34783
35069
  resolveCommitTargets(sessionId) {
34784
- const paths = this.sessionPaths.get(sessionId);
35070
+ const paths = this.sessionRepoCheckoutPaths.get(sessionId);
34785
35071
  if (paths?.length) return paths;
34786
35072
  const disc = this.tryDiscoverFromDisk(sessionId);
34787
- if (disc?.worktreePaths.length) {
34788
- this.rememberWorktrees(sessionId, disc.agentCwd, disc.worktreePaths);
34789
- return disc.worktreePaths;
35073
+ if (disc?.repoCheckoutPaths.length) {
35074
+ this.rememberSessionWorktrees(sessionId, disc);
35075
+ return disc.repoCheckoutPaths;
34790
35076
  }
34791
- return [getBridgeWorkspaceDirectory()];
35077
+ return [getBridgeRoot()];
34792
35078
  }
34793
35079
  async getSessionWorkingTreeStatus(sessionId) {
34794
35080
  return aggregateSessionPathsWorkingTreeStatus(this.resolveCommitTargets(sessionId));
@@ -34796,10 +35082,12 @@ var SessionWorktreeManager = class {
34796
35082
  /** Per-repo changed files vs HEAD (or a single commit vs parent) for the same git roots used for commit/push. */
34797
35083
  async getSessionWorkingTreeChangeDetails(sessionId, opts) {
34798
35084
  const targets = this.resolveCommitTargets(sessionId);
34799
- const mirror = this.getAgentCwdForSession(sessionId);
35085
+ const sessionWorkingTreeRelRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId) ?? null;
35086
+ const legacyNested = this.isLegacyNestedLayout(sessionId);
34800
35087
  return getWorkingTreeChangeRepoDetails({
34801
- commitTargetAbsDirs: targets,
34802
- agentMirrorRootAbs: mirror,
35088
+ commitTargetPaths: targets,
35089
+ sessionWorktreeRootPath: sessionWorkingTreeRelRoot,
35090
+ legacyRepoNestedSessionLayout: legacyNested,
34803
35091
  repoFilterRelPath: opts?.repoRelPath?.trim() ? opts.repoRelPath.trim() : null,
34804
35092
  basis: opts?.basis
34805
35093
  });
@@ -34814,31 +35102,31 @@ var SessionWorktreeManager = class {
34814
35102
  }
34815
35103
  }
34816
35104
  };
34817
- function defaultWorktreesRootAbs() {
34818
- return path18.join(os4.homedir(), ".buildautomaton", "worktrees");
35105
+ function defaultWorktreesRootPath() {
35106
+ return path19.join(os4.homedir(), ".buildautomaton", "worktrees");
34819
35107
  }
34820
35108
 
34821
35109
  // src/files/watch-file-index.ts
34822
35110
  import { watch } from "node:fs";
34823
- import path25 from "node:path";
35111
+ import path26 from "node:path";
34824
35112
 
34825
35113
  // src/files/index/build-file-index.ts
34826
- import path22 from "node:path";
35114
+ import path23 from "node:path";
34827
35115
 
34828
35116
  // src/runtime/yield-to-event-loop.ts
34829
35117
  function yieldToEventLoop() {
34830
- return new Promise((resolve19) => setImmediate(resolve19));
35118
+ return new Promise((resolve18) => setImmediate(resolve18));
34831
35119
  }
34832
35120
 
34833
35121
  // src/files/index/walk-workspace-tree.ts
34834
35122
  import fs19 from "node:fs";
34835
- import path20 from "node:path";
35123
+ import path21 from "node:path";
34836
35124
 
34837
35125
  // src/files/index/constants.ts
34838
- import path19 from "node:path";
35126
+ import path20 from "node:path";
34839
35127
  import os5 from "node:os";
34840
35128
  var INDEX_WORK_YIELD_EVERY = 256;
34841
- var INDEX_DIR = path19.join(os5.homedir(), ".buildautomaton");
35129
+ var INDEX_DIR = path20.join(os5.homedir(), ".buildautomaton");
34842
35130
  var INDEX_HASH_LEN = 16;
34843
35131
  var INDEX_VERSION = 2;
34844
35132
  var INDEX_LOG_PREFIX = "[file-index]";
@@ -34853,14 +35141,14 @@ function walkWorkspaceTreeSync(dir, baseDir, out) {
34853
35141
  }
34854
35142
  for (const name of names) {
34855
35143
  if (name.startsWith(".")) continue;
34856
- const full = path20.join(dir, name);
35144
+ const full = path21.join(dir, name);
34857
35145
  let stat3;
34858
35146
  try {
34859
35147
  stat3 = fs19.statSync(full);
34860
35148
  } catch {
34861
35149
  continue;
34862
35150
  }
34863
- const relative5 = path20.relative(baseDir, full).replace(/\\/g, "/");
35151
+ const relative5 = path21.relative(baseDir, full).replace(/\\/g, "/");
34864
35152
  if (stat3.isDirectory()) {
34865
35153
  walkWorkspaceTreeSync(full, baseDir, out);
34866
35154
  } else if (stat3.isFile()) {
@@ -34881,14 +35169,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
34881
35169
  await yieldToEventLoop();
34882
35170
  }
34883
35171
  state.n++;
34884
- const full = path20.join(dir, name);
35172
+ const full = path21.join(dir, name);
34885
35173
  let stat3;
34886
35174
  try {
34887
35175
  stat3 = await fs19.promises.stat(full);
34888
35176
  } catch {
34889
35177
  continue;
34890
35178
  }
34891
- const relative5 = path20.relative(baseDir, full).replace(/\\/g, "/");
35179
+ const relative5 = path21.relative(baseDir, full).replace(/\\/g, "/");
34892
35180
  if (stat3.isDirectory()) {
34893
35181
  await walkWorkspaceTreeAsync(full, baseDir, out, state);
34894
35182
  } else if (stat3.isFile()) {
@@ -34972,11 +35260,11 @@ async function buildTrigramMapForPathsAsync(paths) {
34972
35260
  import fs20 from "node:fs";
34973
35261
 
34974
35262
  // src/files/index/paths.ts
34975
- import path21 from "node:path";
35263
+ import path22 from "node:path";
34976
35264
  import crypto2 from "node:crypto";
34977
35265
  function getIndexPathForCwd(resolvedCwd) {
34978
35266
  const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
34979
- return path21.join(INDEX_DIR, `.file-index-${hash}.json`);
35267
+ return path22.join(INDEX_DIR, `.file-index-${hash}.json`);
34980
35268
  }
34981
35269
 
34982
35270
  // src/files/index/write-index-file.ts
@@ -35007,7 +35295,7 @@ function sortPaths(paths) {
35007
35295
  paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
35008
35296
  }
35009
35297
  function buildFileIndex(cwd) {
35010
- const resolved = path22.resolve(cwd);
35298
+ const resolved = path23.resolve(cwd);
35011
35299
  const paths = [];
35012
35300
  walkWorkspaceTreeSync(resolved, resolved, paths);
35013
35301
  sortPaths(paths);
@@ -35017,7 +35305,7 @@ function buildFileIndex(cwd) {
35017
35305
  return data;
35018
35306
  }
35019
35307
  async function buildFileIndexAsync(cwd) {
35020
- const resolved = path22.resolve(cwd);
35308
+ const resolved = path23.resolve(cwd);
35021
35309
  const paths = [];
35022
35310
  await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
35023
35311
  await yieldToEventLoop();
@@ -35030,9 +35318,9 @@ async function buildFileIndexAsync(cwd) {
35030
35318
 
35031
35319
  // src/files/index/load-file-index.ts
35032
35320
  import fs21 from "node:fs";
35033
- import path23 from "node:path";
35321
+ import path24 from "node:path";
35034
35322
  function loadFileIndex(cwd) {
35035
- const resolved = path23.resolve(cwd);
35323
+ const resolved = path24.resolve(cwd);
35036
35324
  const indexPath = getIndexPathForCwd(resolved);
35037
35325
  try {
35038
35326
  const raw = fs21.readFileSync(indexPath, "utf8");
@@ -35054,9 +35342,9 @@ function loadFileIndex(cwd) {
35054
35342
  }
35055
35343
 
35056
35344
  // src/files/index/ensure-file-index.ts
35057
- import path24 from "node:path";
35345
+ import path25 from "node:path";
35058
35346
  async function ensureFileIndexAsync(cwd) {
35059
- const resolved = path24.resolve(cwd);
35347
+ const resolved = path25.resolve(cwd);
35060
35348
  const cached2 = loadFileIndex(resolved);
35061
35349
  if (cached2 !== null) return { data: cached2, fromCache: true };
35062
35350
  const data = await buildFileIndexAsync(resolved);
@@ -35138,8 +35426,8 @@ function createFsWatcher(resolved, schedule) {
35138
35426
  throw e;
35139
35427
  }
35140
35428
  }
35141
- function startFileIndexWatcher(cwd = getBridgeWorkspaceDirectory()) {
35142
- const resolved = path25.resolve(cwd);
35429
+ function startFileIndexWatcher(cwd = getBridgeRoot()) {
35430
+ const resolved = path26.resolve(cwd);
35143
35431
  void buildFileIndexAsync(resolved).catch((e) => {
35144
35432
  console.error("[file-index] Initial index build failed:", e);
35145
35433
  });
@@ -35189,15 +35477,15 @@ function sendDevServerStatus(getWs, serverId, status, options) {
35189
35477
 
35190
35478
  // src/dev-servers/process/terminate-child-process.ts
35191
35479
  async function sigtermAndWaitForExit(proc, graceMs, log2, shortId) {
35192
- const exited = new Promise((resolve19) => {
35193
- proc.once("exit", () => resolve19());
35480
+ const exited = new Promise((resolve18) => {
35481
+ proc.once("exit", () => resolve18());
35194
35482
  });
35195
35483
  log2(`[dev-server] Sending SIGTERM to ${shortId} (pid=${proc.pid ?? "?"}).`);
35196
35484
  try {
35197
35485
  proc.kill("SIGTERM");
35198
35486
  } catch {
35199
35487
  }
35200
- await Promise.race([exited, new Promise((resolve19) => setTimeout(resolve19, graceMs))]);
35488
+ await Promise.race([exited, new Promise((resolve18) => setTimeout(resolve18, graceMs))]);
35201
35489
  }
35202
35490
  function forceKillChild(proc, log2, shortId, graceMs) {
35203
35491
  log2(
@@ -35477,10 +35765,10 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
35477
35765
  import { spawn as spawn6 } from "node:child_process";
35478
35766
  import fs24 from "node:fs";
35479
35767
  import { tmpdir } from "node:os";
35480
- import path26 from "node:path";
35768
+ import path27 from "node:path";
35481
35769
  function trySpawnMergedLogFile(command, env, cwd, signal) {
35482
- const tmpRoot = fs24.mkdtempSync(path26.join(tmpdir(), "ba-devsrv-log-"));
35483
- const logPath = path26.join(tmpRoot, "combined.log");
35770
+ const tmpRoot = fs24.mkdtempSync(path27.join(tmpdir(), "ba-devsrv-log-"));
35771
+ const logPath = path27.join(tmpRoot, "combined.log");
35484
35772
  let logFd;
35485
35773
  try {
35486
35774
  logFd = fs24.openSync(logPath, "a");
@@ -35524,15 +35812,15 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
35524
35812
  import { spawn as spawn7 } from "node:child_process";
35525
35813
  import fs25 from "node:fs";
35526
35814
  import { tmpdir as tmpdir2 } from "node:os";
35527
- import path27 from "node:path";
35815
+ import path28 from "node:path";
35528
35816
  function shSingleQuote(s) {
35529
35817
  return `'${s.replace(/'/g, `'\\''`)}'`;
35530
35818
  }
35531
35819
  function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
35532
- const tmpRoot = fs25.mkdtempSync(path27.join(tmpdir2(), "ba-devsrv-sh-"));
35533
- const logPath = path27.join(tmpRoot, "combined.log");
35534
- const innerPath = path27.join(tmpRoot, "_cmd.sh");
35535
- const runnerPath = path27.join(tmpRoot, "_run.sh");
35820
+ const tmpRoot = fs25.mkdtempSync(path28.join(tmpdir2(), "ba-devsrv-sh-"));
35821
+ const logPath = path28.join(tmpRoot, "combined.log");
35822
+ const innerPath = path28.join(tmpRoot, "_cmd.sh");
35823
+ const runnerPath = path28.join(tmpRoot, "_run.sh");
35536
35824
  try {
35537
35825
  fs25.writeFileSync(innerPath, `#!/bin/sh
35538
35826
  ${command}
@@ -35563,9 +35851,9 @@ cd ${shSingleQuote(cwd)}
35563
35851
  }
35564
35852
  }
35565
35853
  function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
35566
- const tmpRoot = fs25.mkdtempSync(path27.join(tmpdir2(), "ba-devsrv-sh-"));
35567
- const logPath = path27.join(tmpRoot, "combined.log");
35568
- const runnerPath = path27.join(tmpRoot, "_run.bat");
35854
+ const tmpRoot = fs25.mkdtempSync(path28.join(tmpdir2(), "ba-devsrv-sh-"));
35855
+ const logPath = path28.join(tmpRoot, "combined.log");
35856
+ const runnerPath = path28.join(tmpRoot, "_run.bat");
35569
35857
  const q = (p) => `"${p.replace(/"/g, '""')}"`;
35570
35858
  const com = process.env.ComSpec || "cmd.exe";
35571
35859
  try {
@@ -35775,13 +36063,13 @@ var DevServerManager = class {
35775
36063
  abortControllersByServerId = /* @__PURE__ */ new Map();
35776
36064
  getWs;
35777
36065
  log;
35778
- getBridgeCwd;
36066
+ getBridgeRoot;
35779
36067
  e2ee;
35780
36068
  firehoseSink;
35781
36069
  constructor(options) {
35782
36070
  this.getWs = options.getWs;
35783
36071
  this.log = options.log;
35784
- this.getBridgeCwd = options.getBridgeCwd ?? (() => process.cwd());
36072
+ this.getBridgeRoot = options.getBridgeRoot ?? (() => process.cwd());
35785
36073
  this.e2ee = options.e2ee;
35786
36074
  this.firehoseSink = new DevServerFirehoseSink({
35787
36075
  getTails: (serverId) => this.snapshotTails(serverId),
@@ -35870,7 +36158,7 @@ var DevServerManager = class {
35870
36158
  this.sendStatus(serverId, "starting", void 0, emptyTails());
35871
36159
  const ac = new AbortController();
35872
36160
  this.abortControllersByServerId.set(serverId, ac);
35873
- const cwd = this.getBridgeCwd();
36161
+ const cwd = this.getBridgeRoot();
35874
36162
  const childEnv = envForSpawn(process.env, def.env, def.ports);
35875
36163
  const cmd = substituteCommand(def.command.trim(), childEnv);
35876
36164
  const title = def.name.trim() || serverId.slice(0, 8);
@@ -36080,7 +36368,7 @@ async function proxyToLocal(request) {
36080
36368
  };
36081
36369
  const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
36082
36370
  for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
36083
- const once = await new Promise((resolve19) => {
36371
+ const once = await new Promise((resolve18) => {
36084
36372
  const req = mod.request(opts, (res) => {
36085
36373
  const chunks = [];
36086
36374
  res.on("data", (c) => chunks.push(c));
@@ -36091,7 +36379,7 @@ async function proxyToLocal(request) {
36091
36379
  if (typeof v === "string") headers[k] = v;
36092
36380
  else if (Array.isArray(v) && v[0]) headers[k] = v[0];
36093
36381
  }
36094
- resolve19({
36382
+ resolve18({
36095
36383
  id: request.id,
36096
36384
  statusCode: res.statusCode ?? 0,
36097
36385
  headers,
@@ -36100,7 +36388,7 @@ async function proxyToLocal(request) {
36100
36388
  });
36101
36389
  });
36102
36390
  req.on("error", (err) => {
36103
- resolve19({
36391
+ resolve18({
36104
36392
  id: request.id,
36105
36393
  statusCode: 0,
36106
36394
  headers: {},
@@ -36461,13 +36749,13 @@ function createOnBridgeIdentified(opts) {
36461
36749
 
36462
36750
  // src/skills/discover-local-agent-skills.ts
36463
36751
  import fs26 from "node:fs";
36464
- import path28 from "node:path";
36752
+ import path29 from "node:path";
36465
36753
  var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
36466
36754
  function discoverLocalSkills(cwd) {
36467
36755
  const out = [];
36468
36756
  const seenKeys = /* @__PURE__ */ new Set();
36469
36757
  for (const rel of SKILL_DISCOVERY_ROOTS) {
36470
- const base = path28.join(cwd, rel);
36758
+ const base = path29.join(cwd, rel);
36471
36759
  if (!fs26.existsSync(base) || !fs26.statSync(base).isDirectory()) continue;
36472
36760
  let entries = [];
36473
36761
  try {
@@ -36476,13 +36764,13 @@ function discoverLocalSkills(cwd) {
36476
36764
  continue;
36477
36765
  }
36478
36766
  for (const name of entries) {
36479
- const dir = path28.join(base, name);
36767
+ const dir = path29.join(base, name);
36480
36768
  try {
36481
36769
  if (!fs26.statSync(dir).isDirectory()) continue;
36482
36770
  } catch {
36483
36771
  continue;
36484
36772
  }
36485
- const skillMd = path28.join(dir, "SKILL.md");
36773
+ const skillMd = path29.join(dir, "SKILL.md");
36486
36774
  if (!fs26.existsSync(skillMd)) continue;
36487
36775
  const key = `${rel}/${name}`;
36488
36776
  if (seenKeys.has(key)) continue;
@@ -36495,7 +36783,7 @@ function discoverLocalSkills(cwd) {
36495
36783
  function discoverSkillLayoutRoots(cwd) {
36496
36784
  const roots = [];
36497
36785
  for (const rel of SKILL_DISCOVERY_ROOTS) {
36498
- const base = path28.join(cwd, rel);
36786
+ const base = path29.join(cwd, rel);
36499
36787
  if (!fs26.existsSync(base) || !fs26.statSync(base).isDirectory()) continue;
36500
36788
  let entries = [];
36501
36789
  try {
@@ -36505,13 +36793,13 @@ function discoverSkillLayoutRoots(cwd) {
36505
36793
  }
36506
36794
  const skills2 = [];
36507
36795
  for (const name of entries) {
36508
- const dir = path28.join(base, name);
36796
+ const dir = path29.join(base, name);
36509
36797
  try {
36510
36798
  if (!fs26.statSync(dir).isDirectory()) continue;
36511
36799
  } catch {
36512
36800
  continue;
36513
36801
  }
36514
- if (!fs26.existsSync(path28.join(dir, "SKILL.md"))) continue;
36802
+ if (!fs26.existsSync(path29.join(dir, "SKILL.md"))) continue;
36515
36803
  const relPath = `${rel}/${name}`.replace(/\\/g, "/");
36516
36804
  skills2.push({ name, relPath });
36517
36805
  }
@@ -36555,7 +36843,7 @@ function createSendLocalSkillsReport(getWs, logFn) {
36555
36843
  try {
36556
36844
  const socket = getWs();
36557
36845
  if (!socket || socket.readyState !== wrapper_default.OPEN) return;
36558
- const skills2 = discoverLocalSkills(getBridgeWorkspaceDirectory());
36846
+ const skills2 = discoverLocalSkills(getBridgeRoot());
36559
36847
  sendWsMessage(socket, { type: "local_skills", skills: skills2 });
36560
36848
  } catch (e) {
36561
36849
  logFn(
@@ -36616,6 +36904,7 @@ var API_TO_BRIDGE_MESSAGE_TYPES = [
36616
36904
  "dev_servers_config",
36617
36905
  "server_control",
36618
36906
  "agent_config",
36907
+ "prompt_queue_state",
36619
36908
  "prompt",
36620
36909
  "session_git_request",
36621
36910
  "rename_session_branch",
@@ -36692,8 +36981,178 @@ var handleAgentConfigMessage = (msg, deps) => {
36692
36981
  handleBridgeAgentConfig(msg, deps);
36693
36982
  };
36694
36983
 
36695
- // src/agents/acp/from-bridge/handle-bridge-prompt.ts
36696
- import * as path30 from "node:path";
36984
+ // src/prompt-turn-queue/client-report.ts
36985
+ function sendPromptQueueClientReport(ws, queues) {
36986
+ if (!ws) return false;
36987
+ sendWsMessage(ws, { type: "prompt_queue_client_report", queues });
36988
+ return true;
36989
+ }
36990
+
36991
+ // src/prompt-turn-queue/disk-store.ts
36992
+ import fs28 from "node:fs";
36993
+
36994
+ // src/prompt-turn-queue/paths.ts
36995
+ import crypto3 from "node:crypto";
36996
+ import fs27 from "node:fs";
36997
+ import path30 from "node:path";
36998
+ import os6 from "node:os";
36999
+ var QUEUE_KEY_HEX_64 = /^[a-f0-9]{64}$/i;
37000
+ function queueStateFileSlug(queueKey) {
37001
+ if (QUEUE_KEY_HEX_64.test(queueKey)) return queueKey.toLowerCase();
37002
+ return crypto3.createHash("sha256").update(queueKey, "utf8").digest("hex");
37003
+ }
37004
+ function getPromptQueuesDirectory() {
37005
+ const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
37006
+ if (override) return path30.resolve(override);
37007
+ return path30.join(os6.homedir(), ".buildautomaton", "queues");
37008
+ }
37009
+ function ensurePromptQueuesDirectory() {
37010
+ const dir = getPromptQueuesDirectory();
37011
+ if (!fs27.existsSync(dir)) fs27.mkdirSync(dir, { recursive: true });
37012
+ }
37013
+ function queueStateFilePath(queueKey) {
37014
+ return path30.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
37015
+ }
37016
+
37017
+ // src/prompt-turn-queue/disk-store.ts
37018
+ function parsePersistedQueueFile(raw) {
37019
+ try {
37020
+ const o = JSON.parse(raw);
37021
+ const queueKey = typeof o.queueKey === "string" ? o.queueKey : typeof o.queueKeyHash === "string" ? o.queueKeyHash : null;
37022
+ if (!queueKey || typeof o.updatedAt !== "string" || !Array.isArray(o.turns)) return null;
37023
+ return { queueKey, updatedAt: o.updatedAt, turns: o.turns };
37024
+ } catch {
37025
+ return null;
37026
+ }
37027
+ }
37028
+ function readPersistedQueue(queueKey) {
37029
+ const p = queueStateFilePath(queueKey);
37030
+ try {
37031
+ return parsePersistedQueueFile(fs28.readFileSync(p, "utf8"));
37032
+ } catch {
37033
+ return null;
37034
+ }
37035
+ }
37036
+ function writePersistedQueue(file2) {
37037
+ ensurePromptQueuesDirectory();
37038
+ const p = queueStateFilePath(file2.queueKey);
37039
+ fs28.writeFileSync(p, JSON.stringify(file2, null, 2), "utf8");
37040
+ }
37041
+ function mergeServerQueueSnapshot(queueKey, serverTurns) {
37042
+ const prev = readPersistedQueue(queueKey);
37043
+ const turns = [];
37044
+ for (const raw of serverTurns) {
37045
+ if (!raw || typeof raw !== "object") continue;
37046
+ const o = raw;
37047
+ const turnId = typeof o.turnId === "string" ? o.turnId : "";
37048
+ const sessionId = typeof o.sessionId === "string" ? o.sessionId : "";
37049
+ const turnOrd = typeof o.turnOrd === "number" ? o.turnOrd : Number(o.turnOrd) || 0;
37050
+ const serverState = o.serverState;
37051
+ const lastClientState = o.lastClientState ?? null;
37052
+ const payload = o.payload && typeof o.payload === "object" ? o.payload : {};
37053
+ if (!turnId || !sessionId) continue;
37054
+ if (serverState !== "queued" && serverState !== "stopping" && serverState !== "discarded") continue;
37055
+ const old = prev?.turns.find((t) => t.turnId === turnId);
37056
+ const mergedClient = old?.lastClientState === "running" && lastClientState == null ? "running" : lastClientState;
37057
+ turns.push({
37058
+ turnId,
37059
+ sessionId,
37060
+ turnOrd,
37061
+ serverState,
37062
+ lastClientState: mergedClient,
37063
+ payload
37064
+ });
37065
+ }
37066
+ turns.sort((a, b) => a.turnOrd - b.turnOrd);
37067
+ return { queueKey, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), turns };
37068
+ }
37069
+
37070
+ // src/prompt-turn-queue/runner.ts
37071
+ var runIdToQueueKey = /* @__PURE__ */ new Map();
37072
+ function pickNextRunnableTurn(turns) {
37073
+ for (const t of turns) {
37074
+ if (t.serverState === "discarded" || t.serverState === "stopping") continue;
37075
+ if (t.serverState !== "queued") continue;
37076
+ if (t.lastClientState === "running" || t.lastClientState === "stopped" || t.lastClientState === "failed") continue;
37077
+ return t;
37078
+ }
37079
+ return null;
37080
+ }
37081
+ function hasRunningTurn(turns) {
37082
+ return turns.some((t) => t.lastClientState === "running");
37083
+ }
37084
+ function dispatchLocalPrompt(next, deps) {
37085
+ const pl = next.payload;
37086
+ const rawParent = pl["sessionParent"];
37087
+ const sessionParent = rawParent === "bridge_root" || rawParent === "worktrees_root" ? rawParent : void 0;
37088
+ const rawParentPath = pl["sessionParentPath"];
37089
+ const sessionParentPath = typeof rawParentPath === "string" && rawParentPath.trim() !== "" ? rawParentPath.trim() : void 0;
37090
+ const msg = {
37091
+ type: "prompt",
37092
+ sessionId: next.sessionId,
37093
+ runId: next.turnId,
37094
+ prompt: pl.prompt,
37095
+ mode: typeof pl.mode === "string" ? pl.mode : "agent",
37096
+ isNewSession: pl.isNewSession === true,
37097
+ ...sessionParent ? { sessionParent } : {},
37098
+ ...sessionParentPath ? { sessionParentPath } : {},
37099
+ ...typeof pl.followUpCatalogPromptId === "string" ? { followUpCatalogPromptId: pl.followUpCatalogPromptId } : {},
37100
+ ...Array.isArray(pl.sessionChangeSummaryFilePaths) ? { sessionChangeSummaryFilePaths: pl.sessionChangeSummaryFilePaths } : {},
37101
+ ...Array.isArray(pl.sessionChangeSummaryFileSnapshots) ? { sessionChangeSummaryFileSnapshots: pl.sessionChangeSummaryFileSnapshots } : {},
37102
+ ...typeof pl.agentType === "string" && pl.agentType.trim() ? { agentType: pl.agentType.trim() } : {}
37103
+ };
37104
+ handleBridgePrompt(msg, deps);
37105
+ }
37106
+ function applyPromptQueueStateFromServer(msg, deps) {
37107
+ const raw = msg.queues;
37108
+ if (!raw || typeof raw !== "object") return;
37109
+ const getWs = deps.getWs;
37110
+ for (const [queueKey, serverTurns] of Object.entries(raw)) {
37111
+ if (!Array.isArray(serverTurns)) continue;
37112
+ const file2 = mergeServerQueueSnapshot(queueKey, serverTurns);
37113
+ writePersistedQueue(file2);
37114
+ }
37115
+ const report = {};
37116
+ const startedThisTick = /* @__PURE__ */ new Set();
37117
+ for (const [queueKey, serverTurns] of Object.entries(raw)) {
37118
+ if (!Array.isArray(serverTurns)) continue;
37119
+ const file2 = readPersistedQueue(queueKey);
37120
+ if (!file2) continue;
37121
+ if (hasRunningTurn(file2.turns)) continue;
37122
+ const next = pickNextRunnableTurn(file2.turns);
37123
+ if (!next) continue;
37124
+ next.lastClientState = "running";
37125
+ writePersistedQueue(file2);
37126
+ runIdToQueueKey.set(next.turnId, queueKey);
37127
+ startedThisTick.add(next.turnId);
37128
+ report[queueKey] = [{ turnId: next.turnId, clientState: "running" }];
37129
+ }
37130
+ if (Object.keys(report).length > 0) {
37131
+ sendPromptQueueClientReport(getWs(), report);
37132
+ }
37133
+ for (const [queueKey, serverTurns] of Object.entries(raw)) {
37134
+ if (!Array.isArray(serverTurns)) continue;
37135
+ const file2 = readPersistedQueue(queueKey);
37136
+ if (!file2) continue;
37137
+ const running = file2.turns.find((t) => t.lastClientState === "running");
37138
+ if (!running || !startedThisTick.has(running.turnId)) continue;
37139
+ if (runIdToQueueKey.get(running.turnId) !== queueKey) continue;
37140
+ dispatchLocalPrompt(running, deps);
37141
+ }
37142
+ }
37143
+ function finalizePromptTurnOnBridge(getWs, runId, success2) {
37144
+ if (!runId) return;
37145
+ const queueKey = runIdToQueueKey.get(runId);
37146
+ runIdToQueueKey.delete(runId);
37147
+ if (!queueKey) return;
37148
+ const f = readPersistedQueue(queueKey);
37149
+ if (!f) return;
37150
+ const t = f.turns.find((x) => x.turnId === runId);
37151
+ if (!t) return;
37152
+ t.lastClientState = success2 ? "stopped" : "failed";
37153
+ writePersistedQueue(f);
37154
+ sendPromptQueueClientReport(getWs(), { [queueKey]: [{ turnId: runId, clientState: t.lastClientState }] });
37155
+ }
36697
37156
 
36698
37157
  // src/agents/acp/from-bridge/bridge-prompt-wiring.ts
36699
37158
  function createBridgePromptSenders(deps, getWs) {
@@ -36708,6 +37167,9 @@ function createBridgePromptSenders(deps, getWs) {
36708
37167
  const skipEncryptForChangeSummaryFollowUp = result.type === "prompt_result" && result.followUpCatalogPromptId === BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID;
36709
37168
  const encryptedFields = result.type === "prompt_result" && !skipEncryptForChangeSummaryFollowUp ? ["output", "error"] : [];
36710
37169
  sendBridgeMessage(result, encryptedFields);
37170
+ if (result.type === "prompt_result") {
37171
+ finalizePromptTurnOnBridge(getWs, typeof result.runId === "string" ? result.runId : void 0, result.success === true);
37172
+ }
36711
37173
  };
36712
37174
  const sendSessionUpdate = (payload) => {
36713
37175
  const s = getWs();
@@ -36732,63 +37194,6 @@ function createBridgePromptSenders(deps, getWs) {
36732
37194
  // src/agents/acp/from-bridge/bridge-prompt-preamble.ts
36733
37195
  import { execFile as execFile10 } from "node:child_process";
36734
37196
  import { promisify as promisify10 } from "node:util";
36735
-
36736
- // src/git/bridge-queue-key.ts
36737
- import * as path29 from "node:path";
36738
- import { createHash as createHash2 } from "node:crypto";
36739
- function normalizeCanonicalGitUrl(url2) {
36740
- let s = url2.trim();
36741
- if (!s) return s;
36742
- if (s.toLowerCase().endsWith(".git")) {
36743
- s = s.slice(0, -4);
36744
- }
36745
- s = s.replace(/\/+$/, "");
36746
- const httpsMatch = /^(https?):\/\/([^/]+)(\/.*)?$/i.exec(s);
36747
- if (httpsMatch) {
36748
- const host = httpsMatch[2].toLowerCase();
36749
- const p = httpsMatch[3] ?? "";
36750
- s = `${httpsMatch[1].toLowerCase()}://${host}${p}`;
36751
- } else {
36752
- const sshMatch = /^git@([^:]+):(.+)$/i.exec(s);
36753
- if (sshMatch) {
36754
- const host = sshMatch[1].toLowerCase();
36755
- s = `git@${host}:${sshMatch[2]}`;
36756
- }
36757
- }
36758
- return s;
36759
- }
36760
- function canonicalUrlToRepoIdSync(url2) {
36761
- const normalized = normalizeCanonicalGitUrl(url2);
36762
- return createHash2("sha256").update(normalized).digest("hex").slice(0, 32);
36763
- }
36764
- function fallbackRepoIdFromPath(absPath) {
36765
- return createHash2("sha256").update(path29.resolve(absPath)).digest("hex").slice(0, 32);
36766
- }
36767
- async function resolveBridgeQueueBindFields(options) {
36768
- const { effectiveCwd, worktreePaths, primaryRepoRoots, log: log2 } = options;
36769
- const cwdAbs = worktreePaths.length > 0 ? path29.resolve(worktreePaths[0]) : path29.resolve(effectiveCwd);
36770
- if (!primaryRepoRoots.length) {
36771
- log2("[Bridge service] Prompt queue bind skipped: no Git repository roots under the working directory.");
36772
- return null;
36773
- }
36774
- let primaryRoot = primaryRepoRoots[0];
36775
- let remote = await getRemoteOriginUrl(primaryRoot);
36776
- if (!remote) {
36777
- for (const r of primaryRepoRoots.slice(1)) {
36778
- const u = await getRemoteOriginUrl(r);
36779
- if (u) {
36780
- primaryRoot = r;
36781
- remote = u;
36782
- break;
36783
- }
36784
- }
36785
- }
36786
- const repoId = remote ? canonicalUrlToRepoIdSync(remote) : fallbackRepoIdFromPath(primaryRoot);
36787
- const canonicalQueueKey = `repo:${repoId}::cwd:${cwdAbs}`;
36788
- return { canonicalQueueKey, repoId, cwdAbs };
36789
- }
36790
-
36791
- // src/agents/acp/from-bridge/bridge-prompt-preamble.ts
36792
37197
  var execFileAsync9 = promisify10(execFile10);
36793
37198
  async function readGitBranch(cwd) {
36794
37199
  try {
@@ -36802,40 +37207,24 @@ async function readGitBranch(cwd) {
36802
37207
  async function runBridgePromptPreamble(params) {
36803
37208
  const { getWs, log: log2, sessionWorktreeManager, sessionId, runId, effectiveCwd } = params;
36804
37209
  const s = getWs();
36805
- const worktreePaths = sessionWorktreeManager.getWorktreePathsForSession(sessionId) ?? [];
37210
+ const repoCheckoutPaths = sessionWorktreeManager.ensureRepoCheckoutPathsForSession(sessionId);
36806
37211
  const repoRoots = await resolveSnapshotRepoRoots({
36807
- worktreePaths,
37212
+ worktreePaths: repoCheckoutPaths,
36808
37213
  fallbackCwd: effectiveCwd,
37214
+ sessionId: sessionId?.trim() || void 0,
36809
37215
  log: log2
36810
37216
  });
36811
- if (s && sessionId) {
36812
- const bind = await resolveBridgeQueueBindFields({
36813
- effectiveCwd,
36814
- worktreePaths,
36815
- primaryRepoRoots: repoRoots,
36816
- log: log2
36817
- });
36818
- if (bind) {
36819
- sendWsMessage(s, {
36820
- type: "bridge_queue_bind",
36821
- sessionId,
36822
- canonicalQueueKey: bind.canonicalQueueKey,
36823
- repoId: bind.repoId,
36824
- cwdAbs: bind.cwdAbs
36825
- });
36826
- }
36827
- }
36828
37217
  if (s && sessionId) {
36829
37218
  const cliGitBranch = await readGitBranch(effectiveCwd);
36830
37219
  const usesWt = sessionWorktreeManager.usesWorktreeSession(sessionId);
36831
- const mirrorAbs = sessionWorktreeManager.getAgentCwdForSession(sessionId);
37220
+ const isolatedSessionParentPath = sessionWorktreeManager.getIsolatedSessionParentPathForSession(sessionId);
36832
37221
  sendWsMessage(s, {
36833
37222
  type: "session_git_context_report",
36834
37223
  sessionId,
36835
37224
  cliGitBranch,
36836
37225
  agentUsesWorktree: usesWt,
36837
37226
  sessionParent: usesWt ? "worktrees_root" : "bridge_root",
36838
- sessionParentPath: usesWt ? mirrorAbs : getBridgeWorkspaceDirectory()
37227
+ sessionParentPath: usesWt ? isolatedSessionParentPath ?? effectiveCwd : getBridgeRoot()
36839
37228
  });
36840
37229
  }
36841
37230
  if (s && sessionId && runId) {
@@ -36962,7 +37351,7 @@ function handleBridgePrompt(msg, deps) {
36962
37351
  const mode = typeof msg.mode === "string" && msg.mode.trim() ? msg.mode.trim() : void 0;
36963
37352
  acpManager.logPromptReceivedFromBridge({ agentType, mode });
36964
37353
  async function preambleAndPrompt(resolvedCwd) {
36965
- const effectiveCwd = path30.resolve(resolvedCwd ?? getBridgeWorkspaceDirectory());
37354
+ const effectiveCwd = resolveSessionParentPathForAgentProcess(resolvedCwd);
36966
37355
  await runBridgePromptPreamble({
36967
37356
  getWs,
36968
37357
  log: log2,
@@ -36995,7 +37384,7 @@ function handleBridgePrompt(msg, deps) {
36995
37384
  runId,
36996
37385
  mode,
36997
37386
  agentType,
36998
- cwd: effectiveCwd,
37387
+ sessionParentPath: effectiveCwd,
36999
37388
  sendResult: sendResult2,
37000
37389
  sendSessionUpdate,
37001
37390
  followUpCatalogPromptId,
@@ -37005,8 +37394,8 @@ function handleBridgePrompt(msg, deps) {
37005
37394
  e2ee: deps.e2ee
37006
37395
  });
37007
37396
  }
37008
- void sessionWorktreeManager.resolveCwdForPrompt(sessionId, { isNewSession, sessionParent, sessionParentPath }).then((cwd) => preambleAndPrompt(cwd)).catch((err) => {
37009
- log2(`[Agent] Worktree resolve failed: ${err instanceof Error ? err.message : String(err)}`);
37397
+ void sessionWorktreeManager.resolveSessionParentPathForPrompt(sessionId, { isNewSession, sessionParent, sessionParentPath }).then((cwd) => preambleAndPrompt(cwd)).catch((err) => {
37398
+ log2(`[Agent] Session parent path resolve failed: ${err instanceof Error ? err.message : String(err)}`);
37010
37399
  void preambleAndPrompt(void 0);
37011
37400
  });
37012
37401
  }
@@ -37016,6 +37405,11 @@ var handlePromptMessage = (msg, deps) => {
37016
37405
  handleBridgePrompt(msg, deps);
37017
37406
  };
37018
37407
 
37408
+ // src/bridge/routing/handlers/prompt-queue-state.ts
37409
+ var handlePromptQueueStateMessage = (msg, deps) => {
37410
+ applyPromptQueueStateFromServer(msg, deps);
37411
+ };
37412
+
37019
37413
  // src/agents/acp/from-bridge/handle-bridge-cancel-run.ts
37020
37414
  async function handleBridgeCancelRun(msg, { log: log2, acpManager, getWs }) {
37021
37415
  const runId = msg.runId;
@@ -37035,6 +37429,7 @@ async function handleBridgeCancelRun(msg, { log: log2, acpManager, getWs }) {
37035
37429
  error: "Stopped by user",
37036
37430
  stopReason: "no_local_run"
37037
37431
  });
37432
+ finalizePromptTurnOnBridge(getWs, runId, false);
37038
37433
  }
37039
37434
 
37040
37435
  // src/bridge/routing/handlers/cancel-run.ts
@@ -37134,7 +37529,7 @@ var previewSkill = {
37134
37529
  const exe = parts[0];
37135
37530
  const args = parts.slice(1);
37136
37531
  previewProcess = spawn9(isWindows && exe === "npm" ? "npm.cmd" : exe, args, {
37137
- cwd: getBridgeWorkspaceDirectory(),
37532
+ cwd: getBridgeRoot(),
37138
37533
  stdio: ["ignore", "pipe", "pipe"],
37139
37534
  env: {
37140
37535
  ...process.env,
@@ -37252,12 +37647,12 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
37252
37647
  };
37253
37648
 
37254
37649
  // src/files/list-dir.ts
37255
- import fs27 from "node:fs";
37650
+ import fs29 from "node:fs";
37256
37651
  import path32 from "node:path";
37257
37652
 
37258
37653
  // src/files/ensure-under-cwd.ts
37259
37654
  import path31 from "node:path";
37260
- function ensureUnderCwd(relativePath, cwd = getBridgeWorkspaceDirectory()) {
37655
+ function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
37261
37656
  const normalized = path31.normalize(relativePath).replace(/^(\.\/)+/, "");
37262
37657
  const resolved = path31.resolve(cwd, normalized);
37263
37658
  if (!resolved.startsWith(cwd + path31.sep) && resolved !== cwd) {
@@ -37269,12 +37664,12 @@ function ensureUnderCwd(relativePath, cwd = getBridgeWorkspaceDirectory()) {
37269
37664
  // src/files/list-dir.ts
37270
37665
  var LIST_DIR_YIELD_EVERY = 256;
37271
37666
  async function listDirAsync(relativePath) {
37272
- const resolved = ensureUnderCwd(relativePath || ".", getBridgeWorkspaceDirectory());
37667
+ const resolved = ensureUnderCwd(relativePath || ".", getBridgeRoot());
37273
37668
  if (!resolved) {
37274
37669
  return { error: "Path is outside working directory" };
37275
37670
  }
37276
37671
  try {
37277
- const names = await fs27.promises.readdir(resolved, { withFileTypes: true });
37672
+ const names = await fs29.promises.readdir(resolved, { withFileTypes: true });
37278
37673
  const visible = names.filter((d) => !d.name.startsWith("."));
37279
37674
  const entries = [];
37280
37675
  for (let i = 0; i < visible.length; i++) {
@@ -37287,7 +37682,7 @@ async function listDirAsync(relativePath) {
37287
37682
  let isDir = d.isDirectory();
37288
37683
  if (d.isSymbolicLink()) {
37289
37684
  try {
37290
- const targetStat = await fs27.promises.stat(fullPath);
37685
+ const targetStat = await fs29.promises.stat(fullPath);
37291
37686
  isDir = targetStat.isDirectory();
37292
37687
  } catch {
37293
37688
  isDir = false;
@@ -37312,25 +37707,25 @@ async function listDirAsync(relativePath) {
37312
37707
  }
37313
37708
 
37314
37709
  // src/files/read-file.ts
37315
- import fs28 from "node:fs";
37710
+ import fs30 from "node:fs";
37316
37711
  import { StringDecoder } from "node:string_decoder";
37317
37712
  function resolveFilePath(relativePath) {
37318
- const resolved = ensureUnderCwd(relativePath, getBridgeWorkspaceDirectory());
37713
+ const resolved = ensureUnderCwd(relativePath, getBridgeRoot());
37319
37714
  if (!resolved) return { error: "Path is outside working directory" };
37320
37715
  let real;
37321
37716
  try {
37322
- real = fs28.realpathSync(resolved);
37717
+ real = fs30.realpathSync(resolved);
37323
37718
  } catch {
37324
37719
  real = resolved;
37325
37720
  }
37326
- const stat3 = fs28.statSync(real);
37721
+ const stat3 = fs30.statSync(real);
37327
37722
  if (!stat3.isFile()) return { error: "Not a file" };
37328
37723
  return real;
37329
37724
  }
37330
37725
  var LINE_CHUNK_SIZE = 64 * 1024;
37331
37726
  function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
37332
- const fileSize = fs28.statSync(filePath).size;
37333
- const fd = fs28.openSync(filePath, "r");
37727
+ const fileSize = fs30.statSync(filePath).size;
37728
+ const fd = fs30.openSync(filePath, "r");
37334
37729
  const bufSize = 64 * 1024;
37335
37730
  const buf = Buffer.alloc(bufSize);
37336
37731
  const decoder = new StringDecoder("utf8");
@@ -37343,7 +37738,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
37343
37738
  let line0Accum = "";
37344
37739
  try {
37345
37740
  let bytesRead;
37346
- while (!done && (bytesRead = fs28.readSync(fd, buf, 0, bufSize, null)) > 0) {
37741
+ while (!done && (bytesRead = fs30.readSync(fd, buf, 0, bufSize, null)) > 0) {
37347
37742
  const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
37348
37743
  partial2 = "";
37349
37744
  let lineStart = 0;
@@ -37478,7 +37873,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
37478
37873
  }
37479
37874
  return { content: resultLines.join("\n"), size: fileSize };
37480
37875
  } finally {
37481
- fs28.closeSync(fd);
37876
+ fs30.closeSync(fd);
37482
37877
  }
37483
37878
  }
37484
37879
  function readFile3(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
@@ -37489,8 +37884,8 @@ function readFile3(relativePath, startLine, endLine, lineOffset, lineChunkSize =
37489
37884
  if (hasRange) {
37490
37885
  return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
37491
37886
  }
37492
- const stat3 = fs28.statSync(result);
37493
- const raw = fs28.readFileSync(result, "utf8");
37887
+ const stat3 = fs30.statSync(result);
37888
+ const raw = fs30.readFileSync(result, "utf8");
37494
37889
  const lines = raw.split(/\r?\n/);
37495
37890
  return { content: raw, totalLines: lines.length, size: stat3.size };
37496
37891
  } catch (err) {
@@ -37508,7 +37903,7 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
37508
37903
  void (async () => {
37509
37904
  await yieldToEventLoop();
37510
37905
  const q = typeof msg.q === "string" ? msg.q : "";
37511
- const cwd = getBridgeWorkspaceDirectory();
37906
+ const cwd = getBridgeRoot();
37512
37907
  const index = loadFileIndex(cwd);
37513
37908
  if (index === null) {
37514
37909
  const payload2 = {
@@ -37532,7 +37927,7 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
37532
37927
  }
37533
37928
  function triggerFileIndexBuild() {
37534
37929
  setImmediate(() => {
37535
- void ensureFileIndexAsync(getBridgeWorkspaceDirectory()).catch((e) => {
37930
+ void ensureFileIndexAsync(getBridgeRoot()).catch((e) => {
37536
37931
  console.error("[file-index] Background build failed:", e);
37537
37932
  });
37538
37933
  });
@@ -37601,14 +37996,14 @@ function handleFileBrowserSearchMessage(msg, { getWs, e2ee }) {
37601
37996
  function handleSkillLayoutRequest(msg, deps) {
37602
37997
  const socket = deps.getWs();
37603
37998
  const id = typeof msg.id === "string" ? msg.id : "";
37604
- const roots = discoverSkillLayoutRoots(getBridgeWorkspaceDirectory());
37999
+ const roots = discoverSkillLayoutRoots(getBridgeRoot());
37605
38000
  if (socket) {
37606
38001
  sendWsMessage(socket, { type: "skill_layout_response", id, roots });
37607
38002
  }
37608
38003
  }
37609
38004
 
37610
38005
  // src/skills/install-remote-skills.ts
37611
- import fs29 from "node:fs";
38006
+ import fs31 from "node:fs";
37612
38007
  import path33 from "node:path";
37613
38008
  function installRemoteSkills(cwd, targetDir, items) {
37614
38009
  const installed2 = [];
@@ -37624,11 +38019,11 @@ function installRemoteSkills(cwd, targetDir, items) {
37624
38019
  for (const f of item.files) {
37625
38020
  if (typeof f.path !== "string" || !f.text && !f.base64) continue;
37626
38021
  const dest = path33.join(skillDir, f.path);
37627
- fs29.mkdirSync(path33.dirname(dest), { recursive: true });
38022
+ fs31.mkdirSync(path33.dirname(dest), { recursive: true });
37628
38023
  if (f.text !== void 0) {
37629
- fs29.writeFileSync(dest, f.text, "utf8");
38024
+ fs31.writeFileSync(dest, f.text, "utf8");
37630
38025
  } else if (f.base64) {
37631
- fs29.writeFileSync(dest, Buffer.from(f.base64, "base64"));
38026
+ fs31.writeFileSync(dest, Buffer.from(f.base64, "base64"));
37632
38027
  }
37633
38028
  }
37634
38029
  installed2.push({
@@ -37649,7 +38044,7 @@ var handleInstallSkillsMessage = (msg, deps) => {
37649
38044
  const id = typeof msg.id === "string" ? msg.id : "";
37650
38045
  const targetDir = typeof msg.targetDir === "string" && msg.targetDir.trim() ? msg.targetDir.trim() : ".agents/skills";
37651
38046
  const rawItems = msg.items;
37652
- const cwd = getBridgeWorkspaceDirectory();
38047
+ const cwd = getBridgeRoot();
37653
38048
  const result = installRemoteSkills(cwd, targetDir, rawItems);
37654
38049
  if (!result.success) {
37655
38050
  const err = result.error ?? "Invalid items";
@@ -37778,7 +38173,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
37778
38173
  };
37779
38174
 
37780
38175
  // src/bridge/routing/handlers/revert-turn-snapshot.ts
37781
- import * as fs30 from "node:fs";
38176
+ import * as fs32 from "node:fs";
37782
38177
  var handleRevertTurnSnapshotMessage = (msg, deps) => {
37783
38178
  const id = typeof msg.id === "string" ? msg.id : "";
37784
38179
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
@@ -37788,9 +38183,9 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
37788
38183
  void (async () => {
37789
38184
  const s = getWs();
37790
38185
  if (!s) return;
37791
- const agentBase = sessionWorktreeManager.getAgentCwdForSession(sessionId) ?? getBridgeWorkspaceDirectory();
38186
+ const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
37792
38187
  const file2 = snapshotFilePath(agentBase, turnId);
37793
- if (!fs30.existsSync(file2)) {
38188
+ if (!fs32.existsSync(file2)) {
37794
38189
  sendWsMessage(s, {
37795
38190
  type: "revert_turn_snapshot_result",
37796
38191
  id,
@@ -37848,6 +38243,9 @@ function dispatchBridgeMessage(msg, deps) {
37848
38243
  case "agent_config":
37849
38244
  handleAgentConfigMessage(msg, deps);
37850
38245
  break;
38246
+ case "prompt_queue_state":
38247
+ handlePromptQueueStateMessage(msg, deps);
38248
+ break;
37851
38249
  case "prompt":
37852
38250
  handlePromptMessage(msg, deps);
37853
38251
  break;
@@ -38077,9 +38475,9 @@ async function createBridgeConnection(options) {
38077
38475
  firehoseGeneration: 0,
38078
38476
  firehoseQuiet: createEmptyReconnectQuietSlot()
38079
38477
  };
38080
- const worktreesRootAbs = options.worktreesRootAbs ?? defaultWorktreesRootAbs();
38478
+ const worktreesRootPath = options.worktreesRootPath ?? defaultWorktreesRootPath();
38081
38479
  const sessionWorktreeManager = new SessionWorktreeManager({
38082
- worktreesRootAbs,
38480
+ worktreesRootPath,
38083
38481
  log: logFn
38084
38482
  });
38085
38483
  const acpManager = await createAcpManager({ log: logFn });
@@ -38088,7 +38486,7 @@ async function createBridgeConnection(options) {
38088
38486
  return state.currentWs;
38089
38487
  }
38090
38488
  const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
38091
- const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeCwd: getBridgeWorkspaceDirectory, e2ee });
38489
+ const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeRoot, e2ee });
38092
38490
  const onBridgeIdentified = createOnBridgeIdentified({
38093
38491
  devServerManager,
38094
38492
  firehoseServerUrl,
@@ -38112,8 +38510,8 @@ async function createBridgeConnection(options) {
38112
38510
  getCloudAccessToken: () => tokens.accessToken
38113
38511
  };
38114
38512
  const identifyReportedPaths = {
38115
- bridgeRootPath: path34.resolve(getBridgeWorkspaceDirectory()),
38116
- worktreesRootPath: path34.resolve(worktreesRootAbs)
38513
+ bridgeRootPath: path34.resolve(getBridgeRoot()),
38514
+ worktreesRootPath: path34.resolve(worktreesRootPath)
38117
38515
  };
38118
38516
  const { connect } = createMainBridgeWebSocketLifecycle({
38119
38517
  state,
@@ -38130,7 +38528,7 @@ async function createBridgeConnection(options) {
38130
38528
  identifyReportedPaths
38131
38529
  });
38132
38530
  connect();
38133
- const stopFileIndexWatcher = startFileIndexWatcher(getBridgeWorkspaceDirectory());
38531
+ const stopFileIndexWatcher = startFileIndexWatcher(getBridgeRoot());
38134
38532
  return {
38135
38533
  close: async () => {
38136
38534
  stopFileIndexWatcher();
@@ -38200,7 +38598,7 @@ async function runConnectedBridge(options, restartWithoutAuth) {
38200
38598
  authToken,
38201
38599
  refreshToken,
38202
38600
  justAuthenticated,
38203
- worktreesRootAbs,
38601
+ worktreesRootPath,
38204
38602
  e2eCertificate
38205
38603
  } = options;
38206
38604
  const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
@@ -38212,7 +38610,7 @@ async function runConnectedBridge(options, restartWithoutAuth) {
38212
38610
  refreshToken,
38213
38611
  firehoseServerUrl,
38214
38612
  justAuthenticated,
38215
- worktreesRootAbs,
38613
+ worktreesRootPath,
38216
38614
  e2eCertificate,
38217
38615
  log,
38218
38616
  persistTokens: (t) => {
@@ -38227,7 +38625,7 @@ async function runConnectedBridge(options, restartWithoutAuth) {
38227
38625
  log("[Bridge service] Access token invalid or revoked; re-authenticating\u2026");
38228
38626
  clearConfigForApi(apiUrl);
38229
38627
  void handle.close().then(() => {
38230
- void restartWithoutAuth({ apiUrl, firehoseServerUrl, worktreesRootAbs, e2eCertificate });
38628
+ void restartWithoutAuth({ apiUrl, firehoseServerUrl, worktreesRootPath, e2eCertificate });
38231
38629
  });
38232
38630
  }
38233
38631
  });
@@ -38275,7 +38673,7 @@ async function runBridge(options) {
38275
38673
  workspaceId,
38276
38674
  authToken,
38277
38675
  bridgeName,
38278
- worktreesRootAbs,
38676
+ worktreesRootPath,
38279
38677
  e2eCertificate
38280
38678
  } = options;
38281
38679
  const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
@@ -38320,7 +38718,7 @@ async function runBridge(options) {
38320
38718
  firehoseServerUrl,
38321
38719
  bridgeName,
38322
38720
  justAuthenticated: true,
38323
- worktreesRootAbs,
38721
+ worktreesRootPath,
38324
38722
  e2eCertificate
38325
38723
  });
38326
38724
  return;
@@ -38344,30 +38742,31 @@ async function runCliAction(program2, opts) {
38344
38742
  let workspaceId = opts.workspaceId ?? "";
38345
38743
  let authToken = opts.token;
38346
38744
  const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
38347
- if (opts.cwd && typeof opts.cwd === "string" && opts.cwd.trim()) {
38348
- const resolvedCwd = path35.resolve(process.cwd(), opts.cwd.trim());
38745
+ 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);
38746
+ if (bridgeRootOpt) {
38747
+ const resolvedBridgeRoot = path35.resolve(process.cwd(), bridgeRootOpt);
38349
38748
  try {
38350
- const st = fs31.statSync(resolvedCwd);
38749
+ const st = fs33.statSync(resolvedBridgeRoot);
38351
38750
  if (!st.isDirectory()) {
38352
- console.error(`--cwd is not a directory: ${resolvedCwd}`);
38751
+ console.error(`Bridge root is not a directory: ${resolvedBridgeRoot}`);
38353
38752
  process.exit(1);
38354
38753
  }
38355
38754
  } catch {
38356
- console.error(`--cwd path does not exist or is not accessible: ${resolvedCwd}`);
38755
+ console.error(`Bridge root path does not exist or is not accessible: ${resolvedBridgeRoot}`);
38357
38756
  process.exit(1);
38358
38757
  }
38359
- process.chdir(resolvedCwd);
38758
+ process.chdir(resolvedBridgeRoot);
38360
38759
  }
38361
- initBridgeWorkspaceDirectory();
38760
+ initBridgeRoot();
38362
38761
  console.log(
38363
38762
  colorize(
38364
38763
  GOLDEN_YELLOW,
38365
- `[Workspace] Using ${getBridgeWorkspaceDirectory()} as the working directory for file access and agents.`
38764
+ `[Bridge] Using ${getBridgeRoot()} as the bridge root (repos, file index, agents, and bridge_root sessions).`
38366
38765
  )
38367
38766
  );
38368
- let worktreesRootAbs;
38767
+ let worktreesRootPath;
38369
38768
  if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
38370
- worktreesRootAbs = path35.resolve(opts.worktreesRoot.trim());
38769
+ worktreesRootPath = path35.resolve(opts.worktreesRoot.trim());
38371
38770
  }
38372
38771
  const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
38373
38772
  if (e2eCertificates) {
@@ -38402,7 +38801,7 @@ async function runCliAction(program2, opts) {
38402
38801
  refreshToken,
38403
38802
  firehoseServerUrl,
38404
38803
  bridgeName: opts.name?.trim() || void 0,
38405
- worktreesRootAbs,
38804
+ worktreesRootPath,
38406
38805
  e2eCertificate: e2eCertificates?.activeCertificate
38407
38806
  });
38408
38807
  }
@@ -38415,8 +38814,11 @@ async function main() {
38415
38814
  "Firehose server URL (default: Fly app; or BUILDAUTOMATON_FIREHOSE_URL / legacy BUILDAUTOMATON_PROXY_URL)",
38416
38815
  process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL
38417
38816
  ).option("--proxy-url <url>", "Deprecated alias for --firehose-url", void 0).option(
38817
+ "--bridge-root <path>",
38818
+ "Bridge root directory (absolute or relative to the current directory): git repos, skills, file index, and agent cwd for bridge_root sessions"
38819
+ ).option(
38418
38820
  "--cwd <path>",
38419
- "Working directory for the bridge (absolute or relative to the current directory); affects skills, git, file index, and agent cwd"
38821
+ "Deprecated: same as --bridge-root"
38420
38822
  ).option("-n, --name <name>", "Bridge name when creating via browser (alphanumeric and underscores only)").option(
38421
38823
  "--worktrees-root <path>",
38422
38824
  "Root directory for per-session git worktrees (default: ~/.buildautomaton/worktrees)."