@buildautomaton/cli 0.1.24 → 0.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4065,8 +4065,8 @@ var init_parseUtil = __esm({
4065
4065
  init_errors();
4066
4066
  init_en();
4067
4067
  makeIssue = (params) => {
4068
- const { data, path: path34, errorMaps, issueData } = params;
4069
- const fullPath = [...path34, ...issueData.path || []];
4068
+ const { data, path: path35, errorMaps, issueData } = params;
4069
+ const fullPath = [...path35, ...issueData.path || []];
4070
4070
  const fullIssue = {
4071
4071
  ...issueData,
4072
4072
  path: fullPath
@@ -4374,11 +4374,11 @@ var init_types = __esm({
4374
4374
  init_parseUtil();
4375
4375
  init_util();
4376
4376
  ParseInputLazyPath = class {
4377
- constructor(parent, value, path34, key) {
4377
+ constructor(parent, value, path35, key) {
4378
4378
  this._cachedPath = [];
4379
4379
  this.parent = parent;
4380
4380
  this.data = value;
4381
- this._path = path34;
4381
+ this._path = path35;
4382
4382
  this._key = key;
4383
4383
  }
4384
4384
  get path() {
@@ -7993,10 +7993,10 @@ function assignProp(target, prop, value) {
7993
7993
  configurable: true
7994
7994
  });
7995
7995
  }
7996
- function getElementAtPath(obj, path34) {
7997
- if (!path34)
7996
+ function getElementAtPath(obj, path35) {
7997
+ if (!path35)
7998
7998
  return obj;
7999
- return path34.reduce((acc, key) => acc?.[key], obj);
7999
+ return path35.reduce((acc, key) => acc?.[key], obj);
8000
8000
  }
8001
8001
  function promiseAllObject(promisesObj) {
8002
8002
  const keys = Object.keys(promisesObj);
@@ -8245,11 +8245,11 @@ function aborted(x, startIndex = 0) {
8245
8245
  }
8246
8246
  return false;
8247
8247
  }
8248
- function prefixIssues(path34, issues) {
8248
+ function prefixIssues(path35, issues) {
8249
8249
  return issues.map((iss) => {
8250
8250
  var _a2;
8251
8251
  (_a2 = iss).path ?? (_a2.path = []);
8252
- iss.path.unshift(path34);
8252
+ iss.path.unshift(path35);
8253
8253
  return iss;
8254
8254
  });
8255
8255
  }
@@ -8438,7 +8438,7 @@ function treeifyError(error40, _mapper) {
8438
8438
  return issue2.message;
8439
8439
  };
8440
8440
  const result = { errors: [] };
8441
- const processError = (error41, path34 = []) => {
8441
+ const processError = (error41, path35 = []) => {
8442
8442
  var _a2, _b;
8443
8443
  for (const issue2 of error41.issues) {
8444
8444
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -8448,7 +8448,7 @@ function treeifyError(error40, _mapper) {
8448
8448
  } else if (issue2.code === "invalid_element") {
8449
8449
  processError({ issues: issue2.issues }, issue2.path);
8450
8450
  } else {
8451
- const fullpath = [...path34, ...issue2.path];
8451
+ const fullpath = [...path35, ...issue2.path];
8452
8452
  if (fullpath.length === 0) {
8453
8453
  result.errors.push(mapper(issue2));
8454
8454
  continue;
@@ -8478,9 +8478,9 @@ function treeifyError(error40, _mapper) {
8478
8478
  processError(error40);
8479
8479
  return result;
8480
8480
  }
8481
- function toDotPath(path34) {
8481
+ function toDotPath(path35) {
8482
8482
  const segs = [];
8483
- for (const seg of path34) {
8483
+ for (const seg of path35) {
8484
8484
  if (typeof seg === "number")
8485
8485
  segs.push(`[${seg}]`);
8486
8486
  else if (typeof seg === "symbol")
@@ -21669,7 +21669,7 @@ var require_has_flag = __commonJS({
21669
21669
  var require_supports_color = __commonJS({
21670
21670
  "../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports, module) {
21671
21671
  "use strict";
21672
- var os7 = __require("os");
21672
+ var os8 = __require("os");
21673
21673
  var tty = __require("tty");
21674
21674
  var hasFlag = require_has_flag();
21675
21675
  var { env } = process;
@@ -21717,7 +21717,7 @@ var require_supports_color = __commonJS({
21717
21717
  return min;
21718
21718
  }
21719
21719
  if (process.platform === "win32") {
21720
- const osRelease = os7.release().split(".");
21720
+ const osRelease = os8.release().split(".");
21721
21721
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
21722
21722
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
21723
21723
  }
@@ -21963,10 +21963,10 @@ var require_src2 = __commonJS({
21963
21963
  var fs_1 = __require("fs");
21964
21964
  var debug_1 = __importDefault(require_src());
21965
21965
  var log2 = debug_1.default("@kwsites/file-exists");
21966
- function check2(path34, isFile, isDirectory) {
21967
- log2(`checking %s`, path34);
21966
+ function check2(path35, isFile, isDirectory) {
21967
+ log2(`checking %s`, path35);
21968
21968
  try {
21969
- const stat2 = fs_1.statSync(path34);
21969
+ const stat2 = fs_1.statSync(path35);
21970
21970
  if (stat2.isFile() && isFile) {
21971
21971
  log2(`[OK] path represents a file`);
21972
21972
  return true;
@@ -21986,8 +21986,8 @@ var require_src2 = __commonJS({
21986
21986
  throw e;
21987
21987
  }
21988
21988
  }
21989
- function exists2(path34, type = exports.READABLE) {
21990
- return check2(path34, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
21989
+ function exists2(path35, type = exports.READABLE) {
21990
+ return check2(path35, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
21991
21991
  }
21992
21992
  exports.exists = exists2;
21993
21993
  exports.FILE = 1;
@@ -22189,6 +22189,309 @@ function sendWsMessage(ws, payload) {
22189
22189
  }
22190
22190
  }
22191
22191
 
22192
+ // src/lib/local-agent-auth.ts
22193
+ var LOCAL_AGENT_AUTH_ERROR_HINTS = {
22194
+ "kiro-acp": [/not logged in/i, /kiro-cli\s+login/i, /log in with kiro-cli/i],
22195
+ "cursor-cli": [/cursor_login/i, /authenticate.*cursor/i, /not logged in.*cursor/i, /run:\s*agent\s+login/i],
22196
+ "codex-acp": [
22197
+ /authentication failed/i,
22198
+ /not authenticated/i,
22199
+ /invalid.*api key/i,
22200
+ /sign in.*openai/i,
22201
+ /login.*openai/i,
22202
+ /unauthorized/i
22203
+ ],
22204
+ "claude-code": [
22205
+ /ANTHROPIC_API_KEY/i,
22206
+ /not authenticated/i,
22207
+ /authentication failed/i,
22208
+ /claude\s+login/i,
22209
+ /please run.*claude.*login/i
22210
+ ]
22211
+ };
22212
+ function localAgentErrorSuggestsAuth(agentType, errorText) {
22213
+ if (agentType == null || agentType === "" || errorText == null || !String(errorText).trim()) return false;
22214
+ const hints = LOCAL_AGENT_AUTH_ERROR_HINTS[agentType];
22215
+ if (!hints?.length) return false;
22216
+ return hints.some((re) => re.test(String(errorText)));
22217
+ }
22218
+
22219
+ // src/agents/acp/clients/sdk/sdk-stdio-acp-client.ts
22220
+ import { spawn } from "node:child_process";
22221
+ import { Readable, Writable } from "node:stream";
22222
+
22223
+ // src/files/cwd/bridge-root.ts
22224
+ import * as path from "node:path";
22225
+ var bridgeRootPath = null;
22226
+ function getBridgeRoot() {
22227
+ if (bridgeRootPath == null) {
22228
+ bridgeRootPath = path.resolve(process.cwd());
22229
+ }
22230
+ return bridgeRootPath;
22231
+ }
22232
+
22233
+ // src/agents/acp/clients/agent-stderr-capture.ts
22234
+ var STDERR_CAPTURE_MAX = 48e3;
22235
+ function createStderrCapture(child) {
22236
+ const chunks = [];
22237
+ let total = 0;
22238
+ return {
22239
+ append(chunk) {
22240
+ try {
22241
+ process.stderr.write(chunk);
22242
+ } catch {
22243
+ }
22244
+ if (total >= STDERR_CAPTURE_MAX) return;
22245
+ const n = Math.min(chunk.length, STDERR_CAPTURE_MAX - total);
22246
+ if (n <= 0) return;
22247
+ chunks.push(n === chunk.length ? chunk : chunk.subarray(0, n));
22248
+ total += n;
22249
+ },
22250
+ getText() {
22251
+ return Buffer.concat(chunks).toString("utf8").trim();
22252
+ }
22253
+ };
22254
+ }
22255
+ function formatJsonRpcStyleError(err) {
22256
+ if (err instanceof Error) return err.message;
22257
+ if (err != null && typeof err === "object") {
22258
+ const o = err;
22259
+ const msg = typeof o.message === "string" ? o.message : null;
22260
+ const code = o.code != null ? String(o.code) : "";
22261
+ if (msg) return code ? `[${code}] ${msg}` : msg;
22262
+ }
22263
+ if (typeof err === "string") return err;
22264
+ try {
22265
+ return JSON.stringify(err);
22266
+ } catch {
22267
+ return String(err);
22268
+ }
22269
+ }
22270
+ function mergeErrorWithStderr(primary, stderrText) {
22271
+ const s = stderrText.trim();
22272
+ const p = (primary ?? "").trim();
22273
+ if (!s) return p;
22274
+ if (!p) return s;
22275
+ if (p.includes(s) || s.includes(p)) return p.length >= s.length ? p : s;
22276
+ return `${p}
22277
+ ${s}`;
22278
+ }
22279
+
22280
+ // src/agents/acp/clients/kiro-sdk-ext-notifications.ts
22281
+ function createKiroSdkExtNotificationHandler(options) {
22282
+ const { onSessionUpdate } = options;
22283
+ return async (method, params) => {
22284
+ if (method === "_kiro.dev/metadata") {
22285
+ const p = params && typeof params === "object" ? params : {};
22286
+ const pct = p.contextUsagePercentage;
22287
+ if (typeof pct !== "number" || !Number.isFinite(pct) || !onSessionUpdate) return;
22288
+ onSessionUpdate({
22289
+ sessionUpdate: "context_usage",
22290
+ contextUsagePercentage: pct
22291
+ });
22292
+ return;
22293
+ }
22294
+ };
22295
+ }
22296
+
22297
+ // src/agents/acp/clients/sdk/sdk-stdio-ext-notifications.ts
22298
+ var noopExtNotification = async () => {
22299
+ };
22300
+ function createSdkStdioExtNotificationHandler(options) {
22301
+ const { backendAgentType, onSessionUpdate } = options;
22302
+ switch (backendAgentType) {
22303
+ case "kiro-acp":
22304
+ return createKiroSdkExtNotificationHandler({ onSessionUpdate });
22305
+ default:
22306
+ return noopExtNotification;
22307
+ }
22308
+ }
22309
+
22310
+ // src/agents/acp/enrich-acp-permission-rpc-result.ts
22311
+ var META_KEY = "permissionOptionKind";
22312
+ function optionRecordId(rec) {
22313
+ const raw = rec.optionId ?? rec.id;
22314
+ if (typeof raw === "string" && raw.trim() !== "") return raw.trim();
22315
+ if (typeof raw === "number" && Number.isFinite(raw)) return String(raw);
22316
+ return "";
22317
+ }
22318
+ function enrichAcpPermissionRpcResultFromRequestParams(result, params) {
22319
+ if (params == null || result == null || typeof result !== "object" || Array.isArray(result)) {
22320
+ return result;
22321
+ }
22322
+ const root = result;
22323
+ const outcome = root.outcome;
22324
+ if (outcome == null || typeof outcome !== "object" || Array.isArray(outcome)) return result;
22325
+ const o = outcome;
22326
+ if (o.outcome !== "selected" || typeof o.optionId !== "string" || o.optionId.trim() === "") {
22327
+ return result;
22328
+ }
22329
+ const selectedId = o.optionId.trim();
22330
+ const prevMeta = o._meta != null && typeof o._meta === "object" && !Array.isArray(o._meta) ? o._meta : {};
22331
+ if (typeof prevMeta[META_KEY] === "string" && prevMeta[META_KEY].trim() !== "") {
22332
+ return result;
22333
+ }
22334
+ const rawOpts = Array.isArray(params.options) ? params.options : [];
22335
+ let matchedKind;
22336
+ for (const item of rawOpts) {
22337
+ if (item == null || typeof item !== "object" || Array.isArray(item)) continue;
22338
+ const rec = item;
22339
+ const id = optionRecordId(rec);
22340
+ if (!id || id !== selectedId) continue;
22341
+ if (typeof rec.kind === "string" && rec.kind.trim() !== "") {
22342
+ matchedKind = rec.kind.trim();
22343
+ break;
22344
+ }
22345
+ }
22346
+ if (!matchedKind) return result;
22347
+ return {
22348
+ ...root,
22349
+ outcome: {
22350
+ ...o,
22351
+ _meta: { ...prevMeta, [META_KEY]: matchedKind }
22352
+ }
22353
+ };
22354
+ }
22355
+
22356
+ // src/cli-log-level.ts
22357
+ var verbosity = "info";
22358
+ function setCliLogVerbosity(level) {
22359
+ verbosity = level;
22360
+ }
22361
+ function getCliLogVerbosity() {
22362
+ return verbosity;
22363
+ }
22364
+ function isCliTrace() {
22365
+ return verbosity === "trace";
22366
+ }
22367
+
22368
+ // src/log.ts
22369
+ function timestampPrefix() {
22370
+ const time3 = (/* @__PURE__ */ new Date()).toISOString().slice(11, 19);
22371
+ return `[${time3}]`;
22372
+ }
22373
+ function log(line) {
22374
+ console.log(`${timestampPrefix()} ${line}`);
22375
+ }
22376
+ function logImmediate(line) {
22377
+ process.stdout.write(`${timestampPrefix()} ${line}
22378
+ `);
22379
+ }
22380
+ function logDebug(line) {
22381
+ const v = getCliLogVerbosity();
22382
+ if (v !== "debug" && v !== "trace") return;
22383
+ console.log(`${timestampPrefix()} [debug] ${line}`);
22384
+ }
22385
+ function logTrace(line) {
22386
+ if (getCliLogVerbosity() !== "trace") return;
22387
+ console.log(`${timestampPrefix()} [trace] ${line}`);
22388
+ }
22389
+
22390
+ // src/agents/acp/clients/shared/acp-fs-read-write.ts
22391
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
22392
+ import { dirname } from "node:path";
22393
+
22394
+ // src/files/diff/unified-diff.ts
22395
+ function computeLineDiff(oldText, newText) {
22396
+ const oldLines = oldText.split("\n");
22397
+ const newLines = newText.split("\n");
22398
+ const m = oldLines.length;
22399
+ const n = newLines.length;
22400
+ const dp = Array(m + 1);
22401
+ for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
22402
+ for (let i2 = 1; i2 <= m; i2++) {
22403
+ for (let j2 = 1; j2 <= n; j2++) {
22404
+ if (oldLines[i2 - 1] === newLines[j2 - 1]) {
22405
+ dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
22406
+ } else {
22407
+ dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
22408
+ }
22409
+ }
22410
+ }
22411
+ const result = [];
22412
+ let i = m;
22413
+ let j = n;
22414
+ while (i > 0 || j > 0) {
22415
+ if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
22416
+ result.unshift({ type: "context", line: oldLines[i - 1] });
22417
+ i--;
22418
+ j--;
22419
+ } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
22420
+ result.unshift({ type: "add", line: newLines[j - 1] });
22421
+ j--;
22422
+ } else {
22423
+ result.unshift({ type: "remove", line: oldLines[i - 1] });
22424
+ i--;
22425
+ }
22426
+ }
22427
+ return result;
22428
+ }
22429
+ function editSnippetToUnifiedDiff(filePath, oldText, newText) {
22430
+ const lines = computeLineDiff(oldText, newText);
22431
+ const out = [`--- ${filePath}`, `+++ ${filePath}`];
22432
+ for (const d of lines) {
22433
+ if (d.type === "add") out.push(`+${d.line}`);
22434
+ else if (d.type === "remove") out.push(`-${d.line}`);
22435
+ else out.push(` ${d.line}`);
22436
+ }
22437
+ return out.join("\n");
22438
+ }
22439
+
22440
+ // src/agents/acp/safe-fs-path.ts
22441
+ import * as path2 from "node:path";
22442
+ function resolveSafePathUnderCwd(cwd, filePath) {
22443
+ const trimmed2 = filePath.trim();
22444
+ if (!trimmed2) return null;
22445
+ const normalizedCwd = path2.resolve(cwd);
22446
+ const resolved = path2.isAbsolute(trimmed2) ? path2.normalize(trimmed2) : path2.resolve(normalizedCwd, trimmed2);
22447
+ const rel = path2.relative(normalizedCwd, resolved);
22448
+ if (rel.startsWith("..") || path2.isAbsolute(rel)) return null;
22449
+ return resolved;
22450
+ }
22451
+ function toDisplayPathRelativeToCwd(cwd, absolutePath) {
22452
+ const normalizedCwd = path2.resolve(cwd);
22453
+ const rel = path2.relative(normalizedCwd, path2.resolve(absolutePath));
22454
+ if (!rel || rel === "") return path2.basename(absolutePath);
22455
+ return rel.split(path2.sep).join("/");
22456
+ }
22457
+
22458
+ // src/agents/acp/clients/shared/acp-fs-read-write.ts
22459
+ function sliceFileContentForAcp(content, line, limit) {
22460
+ if (line == null && limit == null) return content;
22461
+ const lines = content.split("\n");
22462
+ const start = line != null && line > 0 ? line - 1 : 0;
22463
+ const end = limit != null && limit > 0 ? start + limit : lines.length;
22464
+ return lines.slice(start, end).join("\n");
22465
+ }
22466
+ function acpReadTextFileInProcess(ctx, filePath, line, limit) {
22467
+ const resolvedPath = resolveSafePathUnderCwd(ctx.cwd, filePath);
22468
+ if (!resolvedPath) throw new Error("Invalid or disallowed path");
22469
+ try {
22470
+ let content = readFileSync(resolvedPath, "utf8");
22471
+ content = sliceFileContentForAcp(content, line, limit);
22472
+ return { content };
22473
+ } catch (e) {
22474
+ if (e.code === "ENOENT") return { content: "" };
22475
+ throw e;
22476
+ }
22477
+ }
22478
+ function acpWriteTextFileInProcess(ctx, filePath, newText) {
22479
+ const resolvedPath = resolveSafePathUnderCwd(ctx.cwd, filePath);
22480
+ if (!resolvedPath) throw new Error("Invalid or disallowed path");
22481
+ let oldText = "";
22482
+ try {
22483
+ oldText = readFileSync(resolvedPath, "utf8");
22484
+ } catch (e) {
22485
+ if (e.code !== "ENOENT") throw e;
22486
+ }
22487
+ mkdirSync(dirname(resolvedPath), { recursive: true });
22488
+ writeFileSync(resolvedPath, newText, "utf8");
22489
+ const displayPath = toDisplayPathRelativeToCwd(ctx.cwd, resolvedPath);
22490
+ const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
22491
+ ctx.onFileChange?.({ path: displayPath, oldText, newText, patchContent });
22492
+ return {};
22493
+ }
22494
+
22192
22495
  // ../types/src/work-items.ts
22193
22496
  init_zod();
22194
22497
  var WorkItemStatusSchema = external_exports.enum(["backlog", "in-progress", "completed"]);
@@ -22489,9 +22792,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
22489
22792
  const rawPath = typeof o.path === "string" ? o.path.trim() : "";
22490
22793
  const summary = typeof o.summary === "string" ? o.summary.trim() : "";
22491
22794
  if (!rawPath || !summary) continue;
22492
- const path34 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
22493
- if (!path34) continue;
22494
- rows.push({ path: path34, summary: clampSummaryToAtMostTwoLines(summary) });
22795
+ const path35 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
22796
+ if (!path35) continue;
22797
+ rows.push({ path: path35, summary: clampSummaryToAtMostTwoLines(summary) });
22495
22798
  }
22496
22799
  return rows;
22497
22800
  }
@@ -22630,263 +22933,358 @@ function isClaudeCodePermissionMode(value) {
22630
22933
  return MODE_SET.has(value);
22631
22934
  }
22632
22935
 
22633
- // ../types/src/agent-config.ts
22634
- var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
22635
- function getClaudePermissionModeFromAgentConfig(config2) {
22636
- if (!config2) return null;
22637
- const raw = config2[AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY];
22638
- if (typeof raw !== "string") return null;
22936
+ // ../types/src/cli-permission-mode.ts
22937
+ var CLI_PERMISSION_MODE_DEFAULT = "default";
22938
+ var CLI_PERMISSION_MODE_DANGEROUS = "dangerous";
22939
+ function normalizeCliPermissionModeInput(raw) {
22940
+ if (typeof raw !== "string") return CLI_PERMISSION_MODE_DEFAULT;
22639
22941
  const t = raw.trim();
22640
- return isClaudeCodePermissionMode(t) ? t : null;
22942
+ if (t === CLI_PERMISSION_MODE_DANGEROUS) return CLI_PERMISSION_MODE_DANGEROUS;
22943
+ if (t === "standard") return CLI_PERMISSION_MODE_DEFAULT;
22944
+ return CLI_PERMISSION_MODE_DEFAULT;
22641
22945
  }
22642
22946
 
22643
- // src/lib/local-agent-auth.ts
22644
- var LOCAL_AGENT_AUTH_ERROR_HINTS = {
22645
- "kiro-acp": [/not logged in/i, /kiro-cli\s+login/i, /log in with kiro-cli/i],
22646
- "cursor-cli": [/cursor_login/i, /authenticate.*cursor/i, /not logged in.*cursor/i, /run:\s*agent\s+login/i],
22647
- "codex-acp": [
22648
- /authentication failed/i,
22649
- /not authenticated/i,
22650
- /invalid.*api key/i,
22651
- /sign in.*openai/i,
22652
- /login.*openai/i,
22653
- /unauthorized/i
22654
- ],
22655
- "claude-code": [
22656
- /ANTHROPIC_API_KEY/i,
22657
- /not authenticated/i,
22658
- /authentication failed/i,
22659
- /claude\s+login/i,
22660
- /please run.*claude.*login/i
22661
- ]
22662
- };
22663
- function localAgentErrorSuggestsAuth(agentType, errorText) {
22664
- if (agentType == null || agentType === "" || errorText == null || !String(errorText).trim()) return false;
22665
- const hints = LOCAL_AGENT_AUTH_ERROR_HINTS[agentType];
22666
- if (!hints?.length) return false;
22667
- return hints.some((re) => re.test(String(errorText)));
22947
+ // ../types/src/acp-permission-auto-approve.ts
22948
+ function isRejectKind(kind) {
22949
+ return kind === "reject_once" || kind === "reject_always";
22950
+ }
22951
+ function normalizeOptions(raw) {
22952
+ if (!Array.isArray(raw)) return [];
22953
+ const out = [];
22954
+ for (const item of raw) {
22955
+ if (item == null || typeof item !== "object" || Array.isArray(item)) continue;
22956
+ const o = item;
22957
+ const rawId = o.optionId ?? o.id;
22958
+ const optionId = typeof rawId === "string" && rawId.trim() !== "" ? rawId.trim() : typeof rawId === "number" && Number.isFinite(rawId) ? String(rawId) : "";
22959
+ if (!optionId) continue;
22960
+ const kind = typeof o.kind === "string" ? o.kind : void 0;
22961
+ out.push({ optionId, ...kind ? { kind } : {} });
22962
+ }
22963
+ return out;
22964
+ }
22965
+ function pickAllowOption(options) {
22966
+ const nonReject = options.filter((o) => !isRejectKind(o.kind));
22967
+ if (nonReject.length === 0) return null;
22968
+ const allowOnce = nonReject.find((o) => o.kind === "allow_once");
22969
+ if (allowOnce) return allowOnce;
22970
+ const notAlways = nonReject.filter((o) => o.kind !== "allow_always");
22971
+ if (notAlways.length > 0) return notAlways[0] ?? null;
22972
+ return nonReject.find((o) => o.kind === "allow_always") ?? nonReject[0] ?? null;
22973
+ }
22974
+ function firstNonEmptyOptionsArray(...candidates) {
22975
+ for (const c of candidates) {
22976
+ if (Array.isArray(c) && c.length > 0) return c;
22977
+ }
22978
+ const fallback = candidates[0];
22979
+ return Array.isArray(fallback) ? fallback : [];
22980
+ }
22981
+ function extractAcpPermissionRequestOptionArray(params) {
22982
+ const toolCall = params.toolCall;
22983
+ const fromToolCall = toolCall != null && typeof toolCall === "object" && !Array.isArray(toolCall) ? toolCall : null;
22984
+ return firstNonEmptyOptionsArray(
22985
+ params.options,
22986
+ params.permissionOptions,
22987
+ fromToolCall?.options,
22988
+ fromToolCall?.permissionOptions
22989
+ );
22990
+ }
22991
+ function buildCliAutoApprovedPermissionRpcResult(requestParams) {
22992
+ const opt = pickAllowOption(normalizeOptions(extractAcpPermissionRequestOptionArray(requestParams)));
22993
+ if (!opt) return null;
22994
+ const kind = opt.kind?.trim();
22995
+ return {
22996
+ outcome: {
22997
+ outcome: "selected",
22998
+ optionId: opt.optionId,
22999
+ ...kind ? { _meta: { permissionOptionKind: kind } } : {}
23000
+ }
23001
+ };
22668
23002
  }
22669
23003
 
22670
- // src/agents/acp/clients/sdk-stdio-acp-client.ts
22671
- import { spawn } from "node:child_process";
22672
- import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
22673
- import { dirname } from "node:path";
22674
- import { Readable, Writable } from "node:stream";
23004
+ // ../types/src/agent-config.ts
23005
+ var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
23006
+ var AGENT_CONFIG_CLI_PERMISSION_MODE_KEY = "cli_permission_mode";
23007
+ function getClaudePermissionModeFromAgentConfig(config2) {
23008
+ if (!config2) return null;
23009
+ const raw = config2[AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY];
23010
+ if (typeof raw !== "string") return null;
23011
+ const t = raw.trim();
23012
+ return isClaudeCodePermissionMode(t) ? t : null;
23013
+ }
23014
+ function getCliPermissionModeFromAgentConfig(config2) {
23015
+ if (!config2) return CLI_PERMISSION_MODE_DEFAULT;
23016
+ return normalizeCliPermissionModeInput(config2[AGENT_CONFIG_CLI_PERMISSION_MODE_KEY]);
23017
+ }
22675
23018
 
22676
- // src/files/diff/unified-diff.ts
22677
- function computeLineDiff(oldText, newText) {
22678
- const oldLines = oldText.split("\n");
22679
- const newLines = newText.split("\n");
22680
- const m = oldLines.length;
22681
- const n = newLines.length;
22682
- const dp = Array(m + 1);
22683
- for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
22684
- for (let i2 = 1; i2 <= m; i2++) {
22685
- for (let j2 = 1; j2 <= n; j2++) {
22686
- if (oldLines[i2 - 1] === newLines[j2 - 1]) {
22687
- dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
22688
- } else {
22689
- dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
23019
+ // src/agents/acp/claude-acp-permission-from-session.ts
23020
+ function flattenSelectOptions(options) {
23021
+ if (options == null || options.length === 0) return [];
23022
+ const first2 = options[0];
23023
+ if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
23024
+ return options.flatMap(
23025
+ (g) => Array.isArray(g.options) ? g.options : []
23026
+ );
23027
+ }
23028
+ return options;
23029
+ }
23030
+ function pickModeConfigOption(configOptions) {
23031
+ if (configOptions == null || configOptions.length === 0) return null;
23032
+ const byCategory = configOptions.find((o) => o.category === "mode");
23033
+ if (byCategory) return byCategory;
23034
+ return configOptions.find((o) => o.id === "mode") ?? null;
23035
+ }
23036
+ async function applyClaudePermissionFromAcpSession(params) {
23037
+ const { sessionId, agentConfig, configOptions, modes, setSessionConfigOption, setSessionMode, logDebug: logDebug2 } = params;
23038
+ const desiredMode = getClaudePermissionModeFromAgentConfig(agentConfig);
23039
+ if (desiredMode == null) return;
23040
+ const modeOpt = pickModeConfigOption(configOptions ?? null);
23041
+ if (modeOpt != null) {
23042
+ const flat = flattenSelectOptions(modeOpt.options);
23043
+ const allowed = flat.some((o) => o.value === desiredMode);
23044
+ if (allowed && modeOpt.currentValue !== desiredMode) {
23045
+ try {
23046
+ logDebug2(
23047
+ `[Agent] Claude Code: sending ACP session/set_config_option (permission mode) configId=${JSON.stringify(modeOpt.id)} value=${JSON.stringify(desiredMode)} was=${JSON.stringify(modeOpt.currentValue)} sessionId=${sessionId.slice(0, 8)}\u2026`
23048
+ );
23049
+ await setSessionConfigOption({ sessionId, configId: modeOpt.id, value: desiredMode });
23050
+ } catch (e) {
23051
+ logDebug2(
23052
+ `[Agent] Claude Code: session/set_config_option failed: ${e instanceof Error ? e.message : String(e)}`
23053
+ );
22690
23054
  }
22691
23055
  }
23056
+ return;
22692
23057
  }
22693
- const result = [];
22694
- let i = m;
22695
- let j = n;
22696
- while (i > 0 || j > 0) {
22697
- if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
22698
- result.unshift({ type: "context", line: oldLines[i - 1] });
22699
- i--;
22700
- j--;
22701
- } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
22702
- result.unshift({ type: "add", line: newLines[j - 1] });
22703
- j--;
22704
- } else {
22705
- result.unshift({ type: "remove", line: oldLines[i - 1] });
22706
- i--;
23058
+ if (modes?.availableModes?.length) {
23059
+ const allowed = modes.availableModes.some((m) => m.id === desiredMode);
23060
+ if (allowed && desiredMode !== modes.currentModeId) {
23061
+ try {
23062
+ logDebug2(
23063
+ `[Agent] Claude Code: sending ACP session/set_mode (permission mode) modeId=${JSON.stringify(desiredMode)} was=${JSON.stringify(modes.currentModeId ?? null)} sessionId=${sessionId.slice(0, 8)}\u2026`
23064
+ );
23065
+ await setSessionMode({ sessionId, modeId: desiredMode });
23066
+ } catch (e) {
23067
+ logDebug2(`[Agent] Claude Code: session/set_mode failed: ${e instanceof Error ? e.message : String(e)}`);
23068
+ }
22707
23069
  }
22708
23070
  }
22709
- return result;
22710
- }
22711
- function editSnippetToUnifiedDiff(filePath, oldText, newText) {
22712
- const lines = computeLineDiff(oldText, newText);
22713
- const out = [`--- ${filePath}`, `+++ ${filePath}`];
22714
- for (const d of lines) {
22715
- if (d.type === "add") out.push(`+${d.line}`);
22716
- else if (d.type === "remove") out.push(`-${d.line}`);
22717
- else out.push(` ${d.line}`);
22718
- }
22719
- return out.join("\n");
22720
23071
  }
22721
23072
 
22722
- // src/files/cwd/bridge-root.ts
22723
- import * as path from "node:path";
22724
- var bridgeRootPath = null;
22725
- function getBridgeRoot() {
22726
- if (bridgeRootPath == null) {
22727
- bridgeRootPath = path.resolve(process.cwd());
22728
- }
22729
- return bridgeRootPath;
23073
+ // src/agents/acp/clients/shared/config-options-for-permission.ts
23074
+ function configOptionsForPermission(getActive, established) {
23075
+ const mem = getActive?.();
23076
+ if (Array.isArray(mem) && mem.length > 0) return mem;
23077
+ return established ?? void 0;
22730
23078
  }
22731
23079
 
22732
- // src/agents/acp/safe-fs-path.ts
22733
- import * as path2 from "node:path";
22734
- function resolveSafePathUnderCwd(cwd, filePath) {
22735
- const trimmed2 = filePath.trim();
22736
- if (!trimmed2) return null;
22737
- const normalizedCwd = path2.resolve(cwd);
22738
- const resolved = path2.isAbsolute(trimmed2) ? path2.normalize(trimmed2) : path2.resolve(normalizedCwd, trimmed2);
22739
- const rel = path2.relative(normalizedCwd, resolved);
22740
- if (rel.startsWith("..") || path2.isAbsolute(rel)) return null;
22741
- return resolved;
23080
+ // src/agents/acp/clients/shared/establish-acp-session.ts
23081
+ function establishedFromResult(raw, sessionId) {
23082
+ const r = raw && typeof raw === "object" ? raw : {};
23083
+ return {
23084
+ sessionId,
23085
+ configOptions: Array.isArray(r.configOptions) ? r.configOptions : null,
23086
+ modes: r.modes ?? null
23087
+ };
22742
23088
  }
22743
- function toDisplayPathRelativeToCwd(cwd, absolutePath) {
22744
- const normalizedCwd = path2.resolve(cwd);
22745
- const rel = path2.relative(normalizedCwd, path2.resolve(absolutePath));
22746
- if (!rel || rel === "") return path2.basename(absolutePath);
22747
- return rel.split(path2.sep).join("/");
23089
+ function sessionIdFromNewSessionResult(raw) {
23090
+ const r = raw && typeof raw === "object" ? raw : {};
23091
+ return typeof r.sessionId === "string" ? r.sessionId : "";
22748
23092
  }
22749
-
22750
- // src/agents/acp/clients/agent-stderr-capture.ts
22751
- var STDERR_CAPTURE_MAX = 48e3;
22752
- function createStderrCapture(child) {
22753
- const chunks = [];
22754
- let total = 0;
22755
- return {
22756
- append(chunk) {
23093
+ async function establishAcpSessionWithTransport(transport, ctx, canResume, canLoad) {
23094
+ const { cwd, mcpServers, persistedAcpSessionId, agentLabel, suppressLoadReplay } = ctx;
23095
+ const prev = typeof persistedAcpSessionId === "string" && persistedAcpSessionId.trim() !== "" ? persistedAcpSessionId.trim() : "";
23096
+ if (prev) {
23097
+ if (canResume) {
22757
23098
  try {
22758
- process.stderr.write(chunk);
22759
- } catch {
23099
+ logDebug(`[Agent] ${agentLabel} ACP session/resume for stored session ${prev.slice(0, 8)}\u2026`);
23100
+ const result2 = await transport.resumeSession({ sessionId: prev, cwd, mcpServers });
23101
+ return establishedFromResult(result2, prev);
23102
+ } catch (e) {
23103
+ logDebug(`[Agent] ${agentLabel} ACP session/resume failed: ${e instanceof Error ? e.message : String(e)}`);
23104
+ }
23105
+ }
23106
+ if (canLoad) {
23107
+ suppressLoadReplay.value = true;
23108
+ try {
23109
+ logDebug(`[Agent] ${agentLabel} ACP session/load for stored session ${prev.slice(0, 8)}\u2026`);
23110
+ const result2 = await transport.loadSession({ sessionId: prev, cwd, mcpServers });
23111
+ return establishedFromResult(result2, prev);
23112
+ } catch (e) {
23113
+ logDebug(`[Agent] ${agentLabel} ACP session/load failed: ${e instanceof Error ? e.message : String(e)}`);
23114
+ } finally {
23115
+ suppressLoadReplay.value = false;
22760
23116
  }
22761
- if (total >= STDERR_CAPTURE_MAX) return;
22762
- const n = Math.min(chunk.length, STDERR_CAPTURE_MAX - total);
22763
- if (n <= 0) return;
22764
- chunks.push(n === chunk.length ? chunk : chunk.subarray(0, n));
22765
- total += n;
22766
- },
22767
- getText() {
22768
- return Buffer.concat(chunks).toString("utf8").trim();
22769
23117
  }
22770
- };
22771
- }
22772
- function formatJsonRpcStyleError(err) {
22773
- if (err instanceof Error) return err.message;
22774
- if (err != null && typeof err === "object") {
22775
- const o = err;
22776
- const msg = typeof o.message === "string" ? o.message : null;
22777
- const code = o.code != null ? String(o.code) : "";
22778
- if (msg) return code ? `[${code}] ${msg}` : msg;
22779
- }
22780
- if (typeof err === "string") return err;
22781
- try {
22782
- return JSON.stringify(err);
22783
- } catch {
22784
- return String(err);
22785
23118
  }
23119
+ const result = await transport.newSession({ cwd, mcpServers });
23120
+ const sid = sessionIdFromNewSessionResult(result);
23121
+ if (!sid) throw new Error(`${agentLabel} ACP session/new did not return sessionId`);
23122
+ return establishedFromResult(result, sid);
22786
23123
  }
22787
- function mergeErrorWithStderr(primary, stderrText) {
22788
- const s = stderrText.trim();
22789
- const p = (primary ?? "").trim();
22790
- if (!s) return p;
22791
- if (!p) return s;
22792
- if (p.includes(s) || s.includes(p)) return p.length >= s.length ? p : s;
22793
- return `${p}
22794
- ${s}`;
23124
+
23125
+ // src/agents/acp/clients/shared/parse-acp-init-capabilities.ts
23126
+ function parseAcpInitAgentCapabilities(initResult) {
23127
+ const agentCapabilities = initResult?.agentCapabilities;
23128
+ const canLoad = agentCapabilities?.loadSession === true;
23129
+ const sessionCaps = agentCapabilities?.sessionCapabilities;
23130
+ const canResume = Boolean(sessionCaps?.resume);
23131
+ return { canResume, canLoad };
22795
23132
  }
22796
23133
 
22797
- // src/agents/acp/clients/kiro-sdk-ext-notifications.ts
22798
- function createKiroSdkExtNotificationHandler(options) {
22799
- const { onSessionUpdate } = options;
22800
- return async (method, params) => {
22801
- if (method === "_kiro.dev/metadata") {
22802
- const p = params && typeof params === "object" ? params : {};
22803
- const pct = p.contextUsagePercentage;
22804
- if (typeof pct !== "number" || !Number.isFinite(pct) || !onSessionUpdate) return;
22805
- onSessionUpdate({
22806
- sessionUpdate: "context_usage",
22807
- contextUsagePercentage: pct
22808
- });
22809
- return;
22810
- }
22811
- };
23134
+ // src/agents/acp/clients/shared/bootstrap-acp-wire-session.ts
23135
+ async function bootstrapAcpWireSession(transport, ctx, initializeRequest) {
23136
+ const initResult = await transport.initialize(initializeRequest);
23137
+ const { canResume, canLoad } = parseAcpInitAgentCapabilities(initResult);
23138
+ await transport.afterInitialize?.();
23139
+ const established = await establishAcpSessionWithTransport(transport, ctx, canResume, canLoad);
23140
+ const sessionId = established.sessionId;
23141
+ ctx.onAcpSessionEstablished?.({
23142
+ acpSessionId: sessionId,
23143
+ configOptions: established.configOptions,
23144
+ modes: established.modes
23145
+ });
23146
+ if (ctx.backendAgentType === "claude-code") {
23147
+ const cfg = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
23148
+ const configOptionsTyped = established.configOptions;
23149
+ const modesTyped = established.modes;
23150
+ await applyClaudePermissionFromAcpSession({
23151
+ sessionId,
23152
+ agentConfig: cfg,
23153
+ configOptions: configOptionsForPermission(ctx.getActiveConfigOptions, configOptionsTyped),
23154
+ modes: modesTyped,
23155
+ setSessionConfigOption: transport.setSessionConfigOption ? (p) => transport.setSessionConfigOption(p) : async () => {
23156
+ },
23157
+ setSessionMode: transport.setSessionMode ? (p) => transport.setSessionMode(p) : async () => {
23158
+ },
23159
+ logDebug: ctx.logDebug
23160
+ });
23161
+ }
23162
+ return established;
22812
23163
  }
22813
23164
 
22814
- // src/agents/acp/clients/sdk-stdio-ext-notifications.ts
22815
- var noopExtNotification = async () => {
22816
- };
22817
- function createSdkStdioExtNotificationHandler(options) {
22818
- const { backendAgentType, onSessionUpdate } = options;
22819
- switch (backendAgentType) {
22820
- case "kiro-acp":
22821
- return createKiroSdkExtNotificationHandler({ onSessionUpdate });
22822
- default:
22823
- return noopExtNotification;
23165
+ // src/agents/acp/clients/shared/dispatch-session-update.ts
23166
+ function dispatchAcpSessionUpdate(opts) {
23167
+ const { flatPayload, onAcpConfigOptionsUpdated, onSessionUpdate, suppressLoadReplay } = opts;
23168
+ const su = flatPayload.sessionUpdate ?? flatPayload.session_update;
23169
+ if (su === "config_option_update") {
23170
+ const co = flatPayload.configOptions;
23171
+ if (Array.isArray(co)) onAcpConfigOptionsUpdated?.(co);
23172
+ return;
22824
23173
  }
23174
+ if (suppressLoadReplay()) return;
23175
+ onSessionUpdate?.(flatPayload);
22825
23176
  }
22826
23177
 
22827
- // src/agents/acp/enrich-acp-permission-rpc-result.ts
22828
- var META_KEY = "permissionOptionKind";
22829
- function optionRecordId(rec) {
22830
- const raw = rec.optionId ?? rec.id;
22831
- if (typeof raw === "string" && raw.trim() !== "") return raw.trim();
22832
- if (typeof raw === "number" && Number.isFinite(raw)) return String(raw);
22833
- return "";
23178
+ // src/agents/acp/clients/shared/flatten-sdk-session-notification.ts
23179
+ function flattenSdkSessionNotificationParams(params) {
23180
+ return { sessionId: params.sessionId, ...params.update };
22834
23181
  }
22835
- function enrichAcpPermissionRpcResultFromRequestParams(result, params) {
22836
- if (params == null || result == null || typeof result !== "object" || Array.isArray(result)) {
22837
- return result;
22838
- }
22839
- const root = result;
22840
- const outcome = root.outcome;
22841
- if (outcome == null || typeof outcome !== "object" || Array.isArray(outcome)) return result;
22842
- const o = outcome;
22843
- if (o.outcome !== "selected" || typeof o.optionId !== "string" || o.optionId.trim() === "") {
22844
- return result;
23182
+
23183
+ // src/agents/acp/clients/shared/normalize-acp-prompt-result.ts
23184
+ function normalizeAcpPromptTurnSuccess(opts) {
23185
+ const { stopReason, output, stderrCaptureText, backendAgentType } = opts;
23186
+ const mergedOutput = output || void 0;
23187
+ const stop = (stopReason ?? "").toLowerCase();
23188
+ const cancelled = stop === "cancelled";
23189
+ const refusal = stop === "refusal";
23190
+ const stderrEvaluated = Boolean(stderrCaptureText && backendAgentType);
23191
+ const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(backendAgentType, stderrCaptureText) : false;
23192
+ if (cancelled) {
23193
+ return {
23194
+ success: false,
23195
+ stopReason,
23196
+ output: mergedOutput,
23197
+ error: mergeErrorWithStderr("Stopped by user", stderrCaptureText)
23198
+ };
22845
23199
  }
22846
- const selectedId = o.optionId.trim();
22847
- const prevMeta = o._meta != null && typeof o._meta === "object" && !Array.isArray(o._meta) ? o._meta : {};
22848
- if (typeof prevMeta[META_KEY] === "string" && prevMeta[META_KEY].trim() !== "") {
22849
- return result;
23200
+ if (refusal) {
23201
+ return {
23202
+ success: false,
23203
+ stopReason,
23204
+ output: mergedOutput,
23205
+ error: mergeErrorWithStderr("The agent refused the request.", stderrCaptureText)
23206
+ };
22850
23207
  }
22851
- const rawOpts = Array.isArray(params.options) ? params.options : [];
22852
- let matchedKind;
22853
- for (const item of rawOpts) {
22854
- if (item == null || typeof item !== "object" || Array.isArray(item)) continue;
22855
- const rec = item;
22856
- const id = optionRecordId(rec);
22857
- if (!id || id !== selectedId) continue;
22858
- if (typeof rec.kind === "string" && rec.kind.trim() !== "") {
22859
- matchedKind = rec.kind.trim();
22860
- break;
22861
- }
23208
+ if (stderrSuggestsAuth) {
23209
+ return {
23210
+ success: false,
23211
+ stopReason,
23212
+ output: mergedOutput,
23213
+ error: stderrCaptureText
23214
+ };
22862
23215
  }
22863
- if (!matchedKind) return result;
22864
23216
  return {
22865
- ...root,
22866
- outcome: {
22867
- ...o,
22868
- _meta: { ...prevMeta, [META_KEY]: matchedKind }
23217
+ success: true,
23218
+ stopReason,
23219
+ output: mergedOutput
23220
+ };
23221
+ }
23222
+ function normalizeAcpPromptTurnFailure(err, stderrCaptureText) {
23223
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrCaptureText);
23224
+ return { success: false, error: merged };
23225
+ }
23226
+
23227
+ // src/agents/acp/clients/shared/send-acp-prompt-via-transport.ts
23228
+ async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText) {
23229
+ try {
23230
+ const response = await transport.prompt({
23231
+ sessionId,
23232
+ prompt: [{ type: "text", text: promptText }]
23233
+ });
23234
+ await new Promise((r2) => setImmediate(r2));
23235
+ const r = response;
23236
+ return normalizeAcpPromptTurnSuccess({
23237
+ stopReason: r?.stopReason,
23238
+ output: r?.output,
23239
+ stderrCaptureText: ctx.getStderrText(),
23240
+ backendAgentType: ctx.backendAgentType
23241
+ });
23242
+ } catch (err) {
23243
+ await new Promise((r) => setImmediate(r));
23244
+ return normalizeAcpPromptTurnFailure(err, ctx.getStderrText());
23245
+ }
23246
+ }
23247
+
23248
+ // src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
23249
+ function awaitSdkStdioPermissionRequestHandshake(params) {
23250
+ const { requestId, paramsRecord, pending, onRequest } = params;
23251
+ return new Promise((resolve16) => {
23252
+ pending.set(requestId, { resolve: resolve16, params: paramsRecord });
23253
+ try {
23254
+ onRequest?.({
23255
+ requestId,
23256
+ method: "session/request_permission",
23257
+ params: paramsRecord
23258
+ });
23259
+ } catch {
22869
23260
  }
23261
+ });
23262
+ }
23263
+
23264
+ // src/agents/acp/clients/sdk/sdk-acp-session-transport.ts
23265
+ function createSdkAcpSessionTransport(connection) {
23266
+ const c = connection;
23267
+ return {
23268
+ initialize: (request) => c.initialize(request),
23269
+ resumeSession: (p) => c.unstable_resumeSession(p),
23270
+ loadSession: (p) => c.loadSession(p),
23271
+ newSession: (p) => c.newSession(p),
23272
+ prompt: (p) => c.prompt(p),
23273
+ cancelSession: async (sessionId) => {
23274
+ await c.cancel({ sessionId });
23275
+ },
23276
+ setSessionConfigOption: c.setSessionConfigOption ? (p) => c.setSessionConfigOption(p) : void 0,
23277
+ setSessionMode: c.setSessionMode ? (p) => c.setSessionMode(p) : void 0
22870
23278
  };
22871
23279
  }
22872
23280
 
22873
- // src/agents/acp/clients/sdk-stdio-acp-client.ts
23281
+ // src/agents/acp/clients/sdk/sdk-stdio-acp-client.ts
22874
23282
  function formatSpawnError(err, command) {
22875
23283
  if (err.code === "ENOENT") {
22876
23284
  return `Command "${command}" not found. Install the agent (e.g. Cursor CLI) or add it to PATH.`;
22877
23285
  }
22878
23286
  return err.message || String(err);
22879
23287
  }
22880
- function sliceFileContentRange(content, line, limit) {
22881
- if (line == null && limit == null) return content;
22882
- const lines = content.split("\n");
22883
- const start = line != null && line > 0 ? line - 1 : 0;
22884
- const end = limit != null && limit > 0 ? start + limit : lines.length;
22885
- return lines.slice(start, end).join("\n");
22886
- }
22887
- function bridgePayloadFromSdkSessionNotification(params) {
22888
- return { sessionId: params.sessionId, ...params.update };
22889
- }
22890
23288
  async function createSdkStdioAcpClient(options) {
22891
23289
  const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
22892
23290
  const {
@@ -22898,7 +23296,11 @@ async function createSdkStdioAcpClient(options) {
22898
23296
  onFileChange,
22899
23297
  killSubprocessAfterCancelMs,
22900
23298
  onAgentSubprocessExit,
22901
- agentConfig
23299
+ agentConfig,
23300
+ persistedAcpSessionId,
23301
+ onAcpSessionEstablished,
23302
+ onAcpConfigOptionsUpdated,
23303
+ getActiveConfigOptions
22902
23304
  } = options;
22903
23305
  const isWindows = process.platform === "win32";
22904
23306
  const child = spawn(command[0], command.slice(1), {
@@ -22947,54 +23349,49 @@ async function createSdkStdioAcpClient(options) {
22947
23349
  backendAgentType,
22948
23350
  onSessionUpdate
22949
23351
  });
23352
+ const suppressLoadReplayRef = { value: false };
23353
+ const sessionCtx = {
23354
+ cwd,
23355
+ onFileChange,
23356
+ mcpServers: [],
23357
+ persistedAcpSessionId,
23358
+ agentLabel: "ACP",
23359
+ suppressLoadReplay: suppressLoadReplayRef,
23360
+ backendAgentType: backendAgentType ?? null,
23361
+ agentConfig,
23362
+ getActiveConfigOptions,
23363
+ onAcpSessionEstablished,
23364
+ onAcpConfigOptionsUpdated,
23365
+ logDebug,
23366
+ getStderrText: () => stderrCapture.getText()
23367
+ };
22950
23368
  let permissionSeq = 0;
22951
23369
  const pendingPermissionReplies = /* @__PURE__ */ new Map();
22952
23370
  const client = (_agent) => ({
22953
23371
  async requestPermission(params) {
22954
23372
  const requestId = `perm-${++permissionSeq}`;
22955
23373
  const paramsRecord = params != null && typeof params === "object" ? params : {};
22956
- try {
22957
- onRequest?.({
22958
- requestId,
22959
- method: "session/request_permission",
22960
- params: paramsRecord
22961
- });
22962
- } catch {
22963
- }
22964
- return await new Promise((resolve17) => {
22965
- pendingPermissionReplies.set(requestId, { resolve: resolve17, params: paramsRecord });
23374
+ return await awaitSdkStdioPermissionRequestHandshake({
23375
+ requestId,
23376
+ paramsRecord,
23377
+ pending: pendingPermissionReplies,
23378
+ onRequest
22966
23379
  });
22967
23380
  },
22968
23381
  async readTextFile(params) {
22969
- const resolvedPath = resolveSafePathUnderCwd(cwd, params.path);
22970
- if (!resolvedPath) throw new Error("Invalid or disallowed path");
22971
- try {
22972
- let content = readFileSync(resolvedPath, "utf8");
22973
- content = sliceFileContentRange(content, params.line, params.limit);
22974
- return { content };
22975
- } catch (e) {
22976
- if (e.code === "ENOENT") return { content: "" };
22977
- throw e;
22978
- }
23382
+ return acpReadTextFileInProcess(sessionCtx, params.path, params.line, params.limit);
22979
23383
  },
22980
23384
  async writeTextFile(params) {
22981
- const resolvedPath = resolveSafePathUnderCwd(cwd, params.path);
22982
- if (!resolvedPath) throw new Error("Invalid or disallowed path");
22983
- let oldText = "";
22984
- try {
22985
- oldText = readFileSync(resolvedPath, "utf8");
22986
- } catch (e) {
22987
- if (e.code !== "ENOENT") throw e;
22988
- }
22989
- mkdirSync(dirname(resolvedPath), { recursive: true });
22990
- writeFileSync(resolvedPath, params.content, "utf8");
22991
- const displayPath = toDisplayPathRelativeToCwd(cwd, resolvedPath);
22992
- const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, params.content);
22993
- onFileChange?.({ path: displayPath, oldText, newText: params.content, patchContent });
22994
- return {};
23385
+ return acpWriteTextFileInProcess(sessionCtx, params.path, params.content);
22995
23386
  },
22996
23387
  async sessionUpdate(params) {
22997
- onSessionUpdate?.(bridgePayloadFromSdkSessionNotification(params));
23388
+ const bridged = flattenSdkSessionNotificationParams(params);
23389
+ dispatchAcpSessionUpdate({
23390
+ flatPayload: bridged,
23391
+ onAcpConfigOptionsUpdated: sessionCtx.onAcpConfigOptionsUpdated,
23392
+ onSessionUpdate,
23393
+ suppressLoadReplay: () => sessionCtx.suppressLoadReplay.value
23394
+ });
22998
23395
  },
22999
23396
  async extNotification(method, params) {
23000
23397
  await extNotification(method, params);
@@ -23004,84 +23401,19 @@ async function createSdkStdioAcpClient(options) {
23004
23401
  connection.signal.addEventListener("abort", () => {
23005
23402
  child.kill();
23006
23403
  });
23007
- await connection.initialize({
23404
+ const transport = createSdkAcpSessionTransport(connection);
23405
+ const established = await bootstrapAcpWireSession(transport, sessionCtx, {
23008
23406
  protocolVersion: PROTOCOL_VERSION2,
23009
23407
  clientCapabilities: {
23010
23408
  fs: { readTextFile: true, writeTextFile: true }
23011
23409
  },
23012
23410
  clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
23013
23411
  });
23014
- const newSessionRes = await connection.newSession({ cwd, mcpServers: [] });
23015
- const sessionId = newSessionRes.sessionId;
23016
- if (backendAgentType === "claude-code") {
23017
- const cfg = agentConfig != null && typeof agentConfig === "object" && !Array.isArray(agentConfig) ? agentConfig : null;
23018
- const desiredMode = getClaudePermissionModeFromAgentConfig(cfg);
23019
- const modes = newSessionRes.modes;
23020
- if (desiredMode != null && modes?.availableModes?.length) {
23021
- const allowed = modes.availableModes.some((m) => m.id === desiredMode);
23022
- if (allowed && desiredMode !== modes.currentModeId) {
23023
- try {
23024
- await connection.setSessionMode({ sessionId, modeId: desiredMode });
23025
- } catch {
23026
- }
23027
- }
23028
- }
23029
- }
23412
+ const sessionId = established.sessionId;
23030
23413
  settleResolve({
23031
23414
  sessionId,
23032
23415
  async sendPrompt(prompt, _options) {
23033
- try {
23034
- const response = await connection.prompt({
23035
- sessionId,
23036
- prompt: [{ type: "text", text: prompt }]
23037
- });
23038
- await new Promise((r2) => setImmediate(r2));
23039
- const r = response;
23040
- const stopReason = (r?.stopReason ?? "").toLowerCase();
23041
- const cancelled = stopReason === "cancelled";
23042
- const refusal = stopReason === "refusal";
23043
- const stderrAfter = stderrCapture.getText();
23044
- const agentType = backendAgentType ?? null;
23045
- const stderrEvaluated = Boolean(stderrAfter && agentType);
23046
- const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
23047
- if (cancelled) {
23048
- return {
23049
- success: false,
23050
- stopReason: r?.stopReason,
23051
- output: r?.output,
23052
- error: mergeErrorWithStderr("Stopped by user", stderrAfter)
23053
- };
23054
- }
23055
- if (refusal) {
23056
- return {
23057
- success: false,
23058
- stopReason: r?.stopReason,
23059
- output: r?.output,
23060
- error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
23061
- };
23062
- }
23063
- if (stderrSuggestsAuth) {
23064
- return {
23065
- success: false,
23066
- stopReason: r?.stopReason,
23067
- output: r?.output,
23068
- error: stderrAfter
23069
- };
23070
- }
23071
- return {
23072
- success: true,
23073
- stopReason: r?.stopReason,
23074
- output: r?.output
23075
- };
23076
- } catch (err) {
23077
- await new Promise((r) => setImmediate(r));
23078
- const stderrAfter = stderrCapture.getText();
23079
- const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
23080
- return {
23081
- success: false,
23082
- error: merged
23083
- };
23084
- }
23416
+ return sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt);
23085
23417
  },
23086
23418
  async cancel() {
23087
23419
  for (const [id, entry] of [...pendingPermissionReplies.entries()]) {
@@ -23089,7 +23421,7 @@ async function createSdkStdioAcpClient(options) {
23089
23421
  entry.resolve({ outcome: { outcome: "cancelled" } });
23090
23422
  }
23091
23423
  try {
23092
- await connection.cancel({ sessionId });
23424
+ await transport.cancelSession(sessionId);
23093
23425
  } catch {
23094
23426
  }
23095
23427
  if (killSubprocessAfterCancelMs != null && killSubprocessAfterCancelMs >= 0) {
@@ -23315,8 +23647,8 @@ function randomSecret() {
23315
23647
  }
23316
23648
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
23317
23649
  }
23318
- async function requestPreviewApi(port, secret, method, path34, body) {
23319
- const url2 = `http://127.0.0.1:${port}${path34}`;
23650
+ async function requestPreviewApi(port, secret, method, path35, body) {
23651
+ const url2 = `http://127.0.0.1:${port}${path35}`;
23320
23652
  const headers = {
23321
23653
  [PREVIEW_SECRET_HEADER]: secret,
23322
23654
  "Content-Type": "application/json"
@@ -23328,7 +23660,7 @@ async function requestPreviewApi(port, secret, method, path34, body) {
23328
23660
  });
23329
23661
  const data = await res.json().catch(() => ({}));
23330
23662
  if (!res.ok) {
23331
- throw new Error(data?.error ?? `Preview API ${method} ${path34}: ${res.status}`);
23663
+ throw new Error(data?.error ?? `Preview API ${method} ${path35}: ${res.status}`);
23332
23664
  }
23333
23665
  return data;
23334
23666
  }
@@ -23471,40 +23803,6 @@ async function callSkill(skillId, operationId, params) {
23471
23803
  return skill.execute(operationId, params);
23472
23804
  }
23473
23805
 
23474
- // src/cli-log-level.ts
23475
- var verbosity = "info";
23476
- function setCliLogVerbosity(level) {
23477
- verbosity = level;
23478
- }
23479
- function getCliLogVerbosity() {
23480
- return verbosity;
23481
- }
23482
- function isCliTrace() {
23483
- return verbosity === "trace";
23484
- }
23485
-
23486
- // src/log.ts
23487
- function timestampPrefix() {
23488
- const time3 = (/* @__PURE__ */ new Date()).toISOString().slice(11, 19);
23489
- return `[${time3}]`;
23490
- }
23491
- function log(line) {
23492
- console.log(`${timestampPrefix()} ${line}`);
23493
- }
23494
- function logImmediate(line) {
23495
- process.stdout.write(`${timestampPrefix()} ${line}
23496
- `);
23497
- }
23498
- function logDebug(line) {
23499
- const v = getCliLogVerbosity();
23500
- if (v !== "debug" && v !== "trace") return;
23501
- console.log(`${timestampPrefix()} [debug] ${line}`);
23502
- }
23503
- function logTrace(line) {
23504
- if (getCliLogVerbosity() !== "trace") return;
23505
- console.log(`${timestampPrefix()} [trace] ${line}`);
23506
- }
23507
-
23508
23806
  // src/config.ts
23509
23807
  import fs from "node:fs";
23510
23808
  import path3 from "node:path";
@@ -23577,7 +23875,7 @@ function installBridgeProcessResilience() {
23577
23875
  }
23578
23876
 
23579
23877
  // src/cli-version.ts
23580
- var CLI_VERSION = "0.1.24".length > 0 ? "0.1.24" : "0.0.0-dev";
23878
+ var CLI_VERSION = "0.1.26".length > 0 ? "0.1.26" : "0.0.0-dev";
23581
23879
 
23582
23880
  // ../../node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
23583
23881
  import process7 from "node:process";
@@ -24741,8 +25039,8 @@ function pathspec(...paths) {
24741
25039
  cache.set(key, paths);
24742
25040
  return key;
24743
25041
  }
24744
- function isPathSpec(path34) {
24745
- return path34 instanceof String && cache.has(path34);
25042
+ function isPathSpec(path35) {
25043
+ return path35 instanceof String && cache.has(path35);
24746
25044
  }
24747
25045
  function toPaths(pathSpec) {
24748
25046
  return cache.get(pathSpec) || [];
@@ -24831,8 +25129,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
24831
25129
  function forEachLineWithContent(input, callback) {
24832
25130
  return toLinesWithContent(input, true).map((line) => callback(line));
24833
25131
  }
24834
- function folderExists(path34) {
24835
- return (0, import_file_exists.exists)(path34, import_file_exists.FOLDER);
25132
+ function folderExists(path35) {
25133
+ return (0, import_file_exists.exists)(path35, import_file_exists.FOLDER);
24836
25134
  }
24837
25135
  function append(target, item) {
24838
25136
  if (Array.isArray(target)) {
@@ -25236,8 +25534,8 @@ function checkIsRepoRootTask() {
25236
25534
  commands,
25237
25535
  format: "utf-8",
25238
25536
  onError,
25239
- parser(path34) {
25240
- return /^\.(git)?$/.test(path34.trim());
25537
+ parser(path35) {
25538
+ return /^\.(git)?$/.test(path35.trim());
25241
25539
  }
25242
25540
  };
25243
25541
  }
@@ -25671,11 +25969,11 @@ function parseGrep(grep) {
25671
25969
  const paths = /* @__PURE__ */ new Set();
25672
25970
  const results = {};
25673
25971
  forEachLineWithContent(grep, (input) => {
25674
- const [path34, line, preview] = input.split(NULL);
25675
- paths.add(path34);
25676
- (results[path34] = results[path34] || []).push({
25972
+ const [path35, line, preview] = input.split(NULL);
25973
+ paths.add(path35);
25974
+ (results[path35] = results[path35] || []).push({
25677
25975
  line: asNumber(line),
25678
- path: path34,
25976
+ path: path35,
25679
25977
  preview
25680
25978
  });
25681
25979
  });
@@ -26440,14 +26738,14 @@ var init_hash_object = __esm2({
26440
26738
  init_task();
26441
26739
  }
26442
26740
  });
26443
- function parseInit(bare, path34, text) {
26741
+ function parseInit(bare, path35, text) {
26444
26742
  const response = String(text).trim();
26445
26743
  let result;
26446
26744
  if (result = initResponseRegex.exec(response)) {
26447
- return new InitSummary(bare, path34, false, result[1]);
26745
+ return new InitSummary(bare, path35, false, result[1]);
26448
26746
  }
26449
26747
  if (result = reInitResponseRegex.exec(response)) {
26450
- return new InitSummary(bare, path34, true, result[1]);
26748
+ return new InitSummary(bare, path35, true, result[1]);
26451
26749
  }
26452
26750
  let gitDir = "";
26453
26751
  const tokens = response.split(" ");
@@ -26458,7 +26756,7 @@ function parseInit(bare, path34, text) {
26458
26756
  break;
26459
26757
  }
26460
26758
  }
26461
- return new InitSummary(bare, path34, /^re/i.test(response), gitDir);
26759
+ return new InitSummary(bare, path35, /^re/i.test(response), gitDir);
26462
26760
  }
26463
26761
  var InitSummary;
26464
26762
  var initResponseRegex;
@@ -26467,9 +26765,9 @@ var init_InitSummary = __esm2({
26467
26765
  "src/lib/responses/InitSummary.ts"() {
26468
26766
  "use strict";
26469
26767
  InitSummary = class {
26470
- constructor(bare, path34, existing, gitDir) {
26768
+ constructor(bare, path35, existing, gitDir) {
26471
26769
  this.bare = bare;
26472
- this.path = path34;
26770
+ this.path = path35;
26473
26771
  this.existing = existing;
26474
26772
  this.gitDir = gitDir;
26475
26773
  }
@@ -26481,7 +26779,7 @@ var init_InitSummary = __esm2({
26481
26779
  function hasBareCommand(command) {
26482
26780
  return command.includes(bareCommand);
26483
26781
  }
26484
- function initTask(bare = false, path34, customArgs) {
26782
+ function initTask(bare = false, path35, customArgs) {
26485
26783
  const commands = ["init", ...customArgs];
26486
26784
  if (bare && !hasBareCommand(commands)) {
26487
26785
  commands.splice(1, 0, bareCommand);
@@ -26490,7 +26788,7 @@ function initTask(bare = false, path34, customArgs) {
26490
26788
  commands,
26491
26789
  format: "utf-8",
26492
26790
  parser(text) {
26493
- return parseInit(commands.includes("--bare"), path34, text);
26791
+ return parseInit(commands.includes("--bare"), path35, text);
26494
26792
  }
26495
26793
  };
26496
26794
  }
@@ -27306,12 +27604,12 @@ var init_FileStatusSummary = __esm2({
27306
27604
  "use strict";
27307
27605
  fromPathRegex = /^(.+)\0(.+)$/;
27308
27606
  FileStatusSummary = class {
27309
- constructor(path34, index, working_dir) {
27310
- this.path = path34;
27607
+ constructor(path35, index, working_dir) {
27608
+ this.path = path35;
27311
27609
  this.index = index;
27312
27610
  this.working_dir = working_dir;
27313
27611
  if (index === "R" || working_dir === "R") {
27314
- const detail = fromPathRegex.exec(path34) || [null, path34, path34];
27612
+ const detail = fromPathRegex.exec(path35) || [null, path35, path35];
27315
27613
  this.from = detail[2] || "";
27316
27614
  this.path = detail[1] || "";
27317
27615
  }
@@ -27342,14 +27640,14 @@ function splitLine(result, lineStr) {
27342
27640
  default:
27343
27641
  return;
27344
27642
  }
27345
- function data(index, workingDir, path34) {
27643
+ function data(index, workingDir, path35) {
27346
27644
  const raw = `${index}${workingDir}`;
27347
27645
  const handler = parsers6.get(raw);
27348
27646
  if (handler) {
27349
- handler(result, path34);
27647
+ handler(result, path35);
27350
27648
  }
27351
27649
  if (raw !== "##" && raw !== "!!") {
27352
- result.files.push(new FileStatusSummary(path34, index, workingDir));
27650
+ result.files.push(new FileStatusSummary(path35, index, workingDir));
27353
27651
  }
27354
27652
  }
27355
27653
  }
@@ -27658,9 +27956,9 @@ var init_simple_git_api = __esm2({
27658
27956
  next
27659
27957
  );
27660
27958
  }
27661
- hashObject(path34, write) {
27959
+ hashObject(path35, write) {
27662
27960
  return this._runTask(
27663
- hashObjectTask(path34, write === true),
27961
+ hashObjectTask(path35, write === true),
27664
27962
  trailingFunctionArgument(arguments)
27665
27963
  );
27666
27964
  }
@@ -28013,8 +28311,8 @@ var init_branch = __esm2({
28013
28311
  }
28014
28312
  });
28015
28313
  function toPath(input) {
28016
- const path34 = input.trim().replace(/^["']|["']$/g, "");
28017
- return path34 && normalize2(path34);
28314
+ const path35 = input.trim().replace(/^["']|["']$/g, "");
28315
+ return path35 && normalize2(path35);
28018
28316
  }
28019
28317
  var parseCheckIgnore;
28020
28318
  var init_CheckIgnore = __esm2({
@@ -28328,8 +28626,8 @@ __export2(sub_module_exports, {
28328
28626
  subModuleTask: () => subModuleTask,
28329
28627
  updateSubModuleTask: () => updateSubModuleTask
28330
28628
  });
28331
- function addSubModuleTask(repo, path34) {
28332
- return subModuleTask(["add", repo, path34]);
28629
+ function addSubModuleTask(repo, path35) {
28630
+ return subModuleTask(["add", repo, path35]);
28333
28631
  }
28334
28632
  function initSubModuleTask(customArgs) {
28335
28633
  return subModuleTask(["init", ...customArgs]);
@@ -28662,8 +28960,8 @@ var require_git = __commonJS2({
28662
28960
  }
28663
28961
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
28664
28962
  };
28665
- Git2.prototype.submoduleAdd = function(repo, path34, then) {
28666
- return this._runTask(addSubModuleTask2(repo, path34), trailingFunctionArgument2(arguments));
28963
+ Git2.prototype.submoduleAdd = function(repo, path35, then) {
28964
+ return this._runTask(addSubModuleTask2(repo, path35), trailingFunctionArgument2(arguments));
28667
28965
  };
28668
28966
  Git2.prototype.submoduleUpdate = function(args, then) {
28669
28967
  return this._runTask(
@@ -29550,9 +29848,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
29550
29848
  // src/agents/acp/put-summarize-change-summaries.ts
29551
29849
  async function putEncryptedChangeSummaryRows(params) {
29552
29850
  const base = params.apiBaseUrl.replace(/\/+$/, "");
29553
- const entries = params.rows.map(({ path: path34, summary }) => {
29851
+ const entries = params.rows.map(({ path: path35, summary }) => {
29554
29852
  const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
29555
- return { path: path34, summary: JSON.stringify(enc) };
29853
+ return { path: path35, summary: JSON.stringify(enc) };
29556
29854
  });
29557
29855
  const res = await fetch(
29558
29856
  `${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
@@ -29734,8 +30032,8 @@ async function sendPromptToAgent(options) {
29734
30032
  }
29735
30033
 
29736
30034
  // src/agents/acp/ensure-acp-client.ts
29737
- import * as fs9 from "node:fs";
29738
- import * as path11 from "node:path";
30035
+ import * as fs10 from "node:fs";
30036
+ import * as path12 from "node:path";
29739
30037
 
29740
30038
  // src/error-message.ts
29741
30039
  function errorMessage(err) {
@@ -29825,7 +30123,7 @@ async function createCodexAcpClient(options) {
29825
30123
  return createSdkStdioAcpClient({ ...options, command });
29826
30124
  }
29827
30125
 
29828
- // src/agents/acp/clients/cursor-acp-client.ts
30126
+ // src/agents/acp/clients/cursor/cursor-acp-client.ts
29829
30127
  var cursor_acp_client_exports = {};
29830
30128
  __export(cursor_acp_client_exports, {
29831
30129
  BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE3,
@@ -29833,8 +30131,6 @@ __export(cursor_acp_client_exports, {
29833
30131
  createCursorAcpClient: () => createCursorAcpClient,
29834
30132
  detectLocalAgentPresence: () => detectLocalAgentPresence3
29835
30133
  });
29836
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
29837
- import { dirname as dirname3 } from "node:path";
29838
30134
  import { spawn as spawn4 } from "node:child_process";
29839
30135
  import * as readline from "node:readline";
29840
30136
 
@@ -29851,7 +30147,23 @@ function formatSessionUpdateKindForLog(kind) {
29851
30147
  return kind.split("_").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
29852
30148
  }
29853
30149
 
29854
- // src/agents/acp/clients/cursor-acp-client.ts
30150
+ // src/agents/acp/clients/cursor/cursor-json-rpc-acp-transport.ts
30151
+ function createCursorJsonRpcAcpTransport(deps) {
30152
+ const { send, cancelSessionNotification } = deps;
30153
+ return {
30154
+ initialize: (request) => send("initialize", request),
30155
+ afterInitialize: async () => {
30156
+ await send("authenticate", { methodId: "cursor_login" });
30157
+ },
30158
+ resumeSession: (p) => send("session/resume", p),
30159
+ loadSession: (p) => send("session/load", p),
30160
+ newSession: (p) => send("session/new", p),
30161
+ prompt: (p) => send("session/prompt", p),
30162
+ cancelSession: (sessionId) => cancelSessionNotification(sessionId)
30163
+ };
30164
+ }
30165
+
30166
+ // src/agents/acp/clients/cursor/cursor-acp-client.ts
29855
30167
  var FS_READ_METHODS = /* @__PURE__ */ new Set(["fs/read_text_file", "fs/readTextFile"]);
29856
30168
  var FS_WRITE_METHODS = /* @__PURE__ */ new Set(["fs/write_text_file", "fs/writeTextFile"]);
29857
30169
  function formatSpawnError2(err, command) {
@@ -29868,13 +30180,6 @@ function safeJsonParse(value) {
29868
30180
  return null;
29869
30181
  }
29870
30182
  }
29871
- function sliceLinesByRange(content, line, limit) {
29872
- if (line == null && limit == null) return content;
29873
- const lines = content.split("\n");
29874
- const start = line != null && line > 0 ? line - 1 : 0;
29875
- const end = limit != null && limit > 0 ? start + limit : lines.length;
29876
- return lines.slice(start, end).join("\n");
29877
- }
29878
30183
  function buildCursorAcpSpawnCommand(base, sessionMode) {
29879
30184
  if (!sessionMode) return [...base];
29880
30185
  const m = sessionMode.trim();
@@ -29888,7 +30193,11 @@ async function createCursorAcpClient(options) {
29888
30193
  backendAgentType,
29889
30194
  onSessionUpdate,
29890
30195
  onRequest,
29891
- onFileChange
30196
+ onFileChange,
30197
+ persistedAcpSessionId,
30198
+ onAcpSessionEstablished,
30199
+ onAcpConfigOptionsUpdated,
30200
+ onAgentSubprocessExit
29892
30201
  } = options;
29893
30202
  const dbgFs = process.env.BUILDAUTOMATON_DEBUG_ACP_FS === "1";
29894
30203
  const isWindows = process.platform === "win32";
@@ -29900,6 +30209,25 @@ async function createCursorAcpClient(options) {
29900
30209
  });
29901
30210
  const stderrCapture = createStderrCapture(child);
29902
30211
  child.stderr?.on("data", (chunk) => stderrCapture.append(chunk));
30212
+ child.once("close", (code, signal) => {
30213
+ onAgentSubprocessExit?.({ code, signal });
30214
+ });
30215
+ const suppressLoadReplayRef = { value: false };
30216
+ const sessionCtx = {
30217
+ cwd,
30218
+ onFileChange,
30219
+ mcpServers: [],
30220
+ persistedAcpSessionId,
30221
+ agentLabel: "Cursor",
30222
+ suppressLoadReplay: suppressLoadReplayRef,
30223
+ backendAgentType: backendAgentType ?? null,
30224
+ agentConfig: options.agentConfig,
30225
+ getActiveConfigOptions: options.getActiveConfigOptions,
30226
+ onAcpSessionEstablished,
30227
+ onAcpConfigOptionsUpdated,
30228
+ logDebug,
30229
+ getStderrText: () => stderrCapture.getText()
30230
+ };
29903
30231
  return new Promise((resolve16, reject) => {
29904
30232
  child.on("error", (err) => {
29905
30233
  child.kill();
@@ -29908,6 +30236,16 @@ async function createCursorAcpClient(options) {
29908
30236
  let nextId = 1;
29909
30237
  const pending = /* @__PURE__ */ new Map();
29910
30238
  const pendingRequests = /* @__PURE__ */ new Map();
30239
+ function cancelSessionNotification(sessionId) {
30240
+ const line = JSON.stringify({
30241
+ jsonrpc: "2.0",
30242
+ method: "session/cancel",
30243
+ params: { sessionId }
30244
+ }) + "\n";
30245
+ return new Promise((res, rej) => {
30246
+ child.stdin.write(line, (err) => err ? rej(err) : res());
30247
+ });
30248
+ }
29911
30249
  function send(method, params) {
29912
30250
  const id = nextId++;
29913
30251
  const line = JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n";
@@ -29931,7 +30269,6 @@ async function createCursorAcpClient(options) {
29931
30269
  respond(requestId, payload);
29932
30270
  pendingRequests.delete(requestId);
29933
30271
  }
29934
- let promptOutputBuffer = "";
29935
30272
  const rl = readline.createInterface({ input: child.stdout });
29936
30273
  rl.on("line", (line) => {
29937
30274
  const msg = safeJsonParse(line);
@@ -29960,11 +30297,12 @@ async function createCursorAcpClient(options) {
29960
30297
  `[acp] Received session update (${kindLabel}) tool=${toolName || "(none)"}`
29961
30298
  );
29962
30299
  }
29963
- const isTextChunk = sessionUpdate === "agent_message_chunk" && update.content?.text;
29964
- if (isTextChunk && update.content?.text) {
29965
- promptOutputBuffer += update.content.text;
29966
- }
29967
- onSessionUpdate?.(update);
30300
+ dispatchAcpSessionUpdate({
30301
+ flatPayload: update,
30302
+ onAcpConfigOptionsUpdated: sessionCtx.onAcpConfigOptionsUpdated,
30303
+ onSessionUpdate,
30304
+ suppressLoadReplay: () => sessionCtx.suppressLoadReplay.value
30305
+ });
29968
30306
  return;
29969
30307
  }
29970
30308
  if (method === "session/request_permission" && typeof id === "number") {
@@ -29984,21 +30322,13 @@ async function createCursorAcpClient(options) {
29984
30322
  if (dbgFs) {
29985
30323
  console.error(`[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""}`);
29986
30324
  }
29987
- const resolvedPath = resolveSafePathUnderCwd(cwd, filePath);
29988
- if (!resolvedPath) {
29989
- if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty)`);
29990
- respondJsonRpcError(id, -32602, "Invalid or disallowed path");
29991
- return;
29992
- }
29993
30325
  try {
29994
- let content = readFileSync3(resolvedPath, "utf8");
29995
- const line2 = typeof params.line === "number" ? params.line : void 0;
29996
- const limit = typeof params.limit === "number" ? params.limit : void 0;
29997
- content = sliceLinesByRange(content, line2, limit);
29998
- respond(id, { content });
30326
+ const lineNum = typeof params.line === "number" ? params.line : void 0;
30327
+ const limitNum = typeof params.limit === "number" ? params.limit : void 0;
30328
+ const out = acpReadTextFileInProcess(sessionCtx, filePath, lineNum, limitNum);
30329
+ respond(id, out);
29999
30330
  } catch (e) {
30000
- const code = e?.code;
30001
- if (code === "ENOENT") {
30331
+ if (e?.code === "ENOENT") {
30002
30332
  respond(id, { content: "" });
30003
30333
  } else {
30004
30334
  respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
@@ -30015,32 +30345,17 @@ async function createCursorAcpClient(options) {
30015
30345
  `[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""} newBytes=${newText.length}`
30016
30346
  );
30017
30347
  }
30018
- const resolvedPath = resolveSafePathUnderCwd(cwd, filePath);
30019
- if (!resolvedPath) {
30020
- if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty): ${filePath.slice(0, 120)}`);
30021
- respondJsonRpcError(id, -32602, "Invalid or disallowed path");
30022
- return;
30023
- }
30024
- let oldText = "";
30025
30348
  try {
30026
- oldText = readFileSync3(resolvedPath, "utf8");
30349
+ acpWriteTextFileInProcess(sessionCtx, filePath, newText);
30350
+ respond(id, null);
30027
30351
  } catch (e) {
30028
- if (e.code !== "ENOENT") {
30352
+ if (e.message === "Invalid or disallowed path") {
30353
+ if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty): ${filePath.slice(0, 120)}`);
30354
+ respondJsonRpcError(id, -32602, "Invalid or disallowed path");
30355
+ } else {
30029
30356
  respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
30030
- return;
30031
30357
  }
30032
30358
  }
30033
- try {
30034
- mkdirSync3(dirname3(resolvedPath), { recursive: true });
30035
- writeFileSync3(resolvedPath, newText, "utf8");
30036
- } catch (e) {
30037
- respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
30038
- return;
30039
- }
30040
- const displayPath = toDisplayPathRelativeToCwd(cwd, resolvedPath);
30041
- const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
30042
- onFileChange?.({ path: displayPath, oldText, newText, patchContent });
30043
- respond(id, null);
30044
30359
  return;
30045
30360
  }
30046
30361
  if (method === "cursor/create_plan" || method === "cursor/ask_question") {
@@ -30062,16 +30377,7 @@ async function createCursorAcpClient(options) {
30062
30377
  });
30063
30378
  (async () => {
30064
30379
  try {
30065
- let sendSessionCancelNotification2 = function() {
30066
- const line = JSON.stringify({
30067
- jsonrpc: "2.0",
30068
- method: "session/cancel",
30069
- params: { sessionId }
30070
- }) + "\n";
30071
- return new Promise((res, rej) => {
30072
- child.stdin.write(line, (err) => err ? rej(err) : res());
30073
- });
30074
- }, cancelPendingPermissionRequests2 = function() {
30380
+ let cancelPendingPermissionRequests2 = function() {
30075
30381
  for (const [reqId, pending2] of [...pendingRequests.entries()]) {
30076
30382
  if (pending2.method === "session/request_permission") {
30077
30383
  respond(reqId, { outcome: { outcome: "cancelled" } });
@@ -30079,76 +30385,25 @@ async function createCursorAcpClient(options) {
30079
30385
  }
30080
30386
  }
30081
30387
  };
30082
- var sendSessionCancelNotification = sendSessionCancelNotification2, cancelPendingPermissionRequests = cancelPendingPermissionRequests2;
30083
- await send("initialize", {
30388
+ var cancelPendingPermissionRequests = cancelPendingPermissionRequests2;
30389
+ const transport = createCursorJsonRpcAcpTransport({
30390
+ send,
30391
+ cancelSessionNotification
30392
+ });
30393
+ const established = await bootstrapAcpWireSession(transport, sessionCtx, {
30084
30394
  protocolVersion: 1,
30085
30395
  clientCapabilities: { fs: { readTextFile: true, writeTextFile: true }, terminal: false },
30086
30396
  clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
30087
30397
  });
30088
- await send("authenticate", { methodId: "cursor_login" });
30089
- const newResult = await send("session/new", { cwd, mcpServers: [] });
30090
- const sessionId = newResult?.sessionId ?? "";
30091
- if (!sessionId) throw new Error("Cursor ACP session/new did not return sessionId");
30398
+ const sessionId = established.sessionId;
30092
30399
  resolve16({
30093
30400
  sessionId,
30094
30401
  async sendPrompt(prompt, _options) {
30095
- promptOutputBuffer = "";
30096
- try {
30097
- const result = await send("session/prompt", {
30098
- sessionId,
30099
- prompt: [{ type: "text", text: prompt }]
30100
- });
30101
- await new Promise((r) => setImmediate(r));
30102
- const output = (result?.output ?? promptOutputBuffer) || void 0;
30103
- const stopReason = (result?.stopReason ?? "").toLowerCase();
30104
- const cancelled = stopReason === "cancelled";
30105
- const refusal = stopReason === "refusal";
30106
- const stderrAfter = stderrCapture.getText();
30107
- const agentType = backendAgentType ?? null;
30108
- const stderrEvaluated = Boolean(stderrAfter && agentType);
30109
- const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
30110
- if (cancelled) {
30111
- return {
30112
- success: false,
30113
- stopReason: result?.stopReason,
30114
- output: output || void 0,
30115
- error: mergeErrorWithStderr("Stopped by user", stderrAfter)
30116
- };
30117
- }
30118
- if (refusal) {
30119
- return {
30120
- success: false,
30121
- stopReason: result?.stopReason,
30122
- output: output || void 0,
30123
- error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
30124
- };
30125
- }
30126
- if (stderrSuggestsAuth) {
30127
- return {
30128
- success: false,
30129
- stopReason: result?.stopReason,
30130
- output: output || void 0,
30131
- error: stderrAfter
30132
- };
30133
- }
30134
- return {
30135
- success: true,
30136
- stopReason: result?.stopReason,
30137
- output: output || void 0
30138
- };
30139
- } catch (err) {
30140
- await new Promise((r) => setImmediate(r));
30141
- const stderrAfter = stderrCapture.getText();
30142
- const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
30143
- return {
30144
- success: false,
30145
- error: merged
30146
- };
30147
- }
30402
+ return sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt);
30148
30403
  },
30149
30404
  async cancel() {
30150
30405
  cancelPendingPermissionRequests2();
30151
- await sendSessionCancelNotification2();
30406
+ await transport.cancelSession(sessionId);
30152
30407
  },
30153
30408
  resolveRequest(requestId, result) {
30154
30409
  const numericId = Number(requestId);
@@ -30296,7 +30551,7 @@ function getGitRepoRootSync(startDir) {
30296
30551
 
30297
30552
  // src/agents/acp/workspace-files.ts
30298
30553
  import { execFileSync as execFileSync3 } from "node:child_process";
30299
- import { readFileSync as readFileSync4 } from "node:fs";
30554
+ import { readFileSync as readFileSync3 } from "node:fs";
30300
30555
  import * as path10 from "node:path";
30301
30556
  function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
30302
30557
  const trimmed2 = rawPath.trim();
@@ -30328,7 +30583,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
30328
30583
  const rel = path10.relative(gitRoot, resolvedPath2);
30329
30584
  if (!rel.startsWith("..") && !path10.isAbsolute(rel)) {
30330
30585
  try {
30331
- return readFileSync4(resolvedPath2, "utf8");
30586
+ return readFileSync3(resolvedPath2, "utf8");
30332
30587
  } catch {
30333
30588
  }
30334
30589
  }
@@ -30336,7 +30591,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
30336
30591
  const resolvedPath = resolveSafePathUnderCwd(sessionParentPath, displayPath);
30337
30592
  if (!resolvedPath) return "";
30338
30593
  try {
30339
- return readFileSync4(resolvedPath, "utf8");
30594
+ return readFileSync3(resolvedPath, "utf8");
30340
30595
  } catch {
30341
30596
  return "";
30342
30597
  }
@@ -30432,7 +30687,7 @@ function createBridgeOnFileChange(opts) {
30432
30687
 
30433
30688
  // src/agents/acp/hooks/bridge-on-request.ts
30434
30689
  function createBridgeOnRequest(opts) {
30435
- const { routing, getSendRequest, log: log2 } = opts;
30690
+ const { routing, getSendRequest, log: log2, getAutoApproveAcpPermissions, resolveAcpPermissionRequest } = opts;
30436
30691
  return (request) => {
30437
30692
  const runId = routing.runId;
30438
30693
  const sessionId = routing.sessionId;
@@ -30440,6 +30695,26 @@ function createBridgeOnRequest(opts) {
30440
30695
  if (!runId || !sendReq) return;
30441
30696
  const kind = request.method === "cursor/create_plan" ? "plan" : request.method === "session/request_permission" ? "permission" : "question";
30442
30697
  const sessionUpdate = request.method === "cursor/create_plan" ? "plan" : request.method === "session/request_permission" ? "permission" : "question";
30698
+ if (request.method === "session/request_permission" && getAutoApproveAcpPermissions() && resolveAcpPermissionRequest) {
30699
+ const params = request.params != null && typeof request.params === "object" && !Array.isArray(request.params) ? request.params : {};
30700
+ const auto = buildCliAutoApprovedPermissionRpcResult(params);
30701
+ if (auto != null) {
30702
+ try {
30703
+ resolveAcpPermissionRequest(request.requestId, auto);
30704
+ log2(
30705
+ `[Bridge service] CLI dangerous mode: auto-approved permission requestId=${request.requestId} runId=${runId}`
30706
+ );
30707
+ return;
30708
+ } catch (err) {
30709
+ log2(
30710
+ `[Bridge service] CLI dangerous mode: auto-approve failed (${errorMessage(err)}); forwarding permission`
30711
+ );
30712
+ }
30713
+ }
30714
+ log2(
30715
+ `[Bridge service] CLI dangerous mode: no allow option to auto-select; forwarding permission requestId=${request.requestId}`
30716
+ );
30717
+ }
30443
30718
  try {
30444
30719
  sendReq({
30445
30720
  type: "session_update",
@@ -30840,6 +31115,9 @@ function createBridgeOnSessionUpdate(opts) {
30840
31115
  const sentFileChangePaths = /* @__PURE__ */ new Set();
30841
31116
  const p = params;
30842
31117
  const updateKind = p.sessionUpdate ?? p.session_update ?? p.type ?? "update";
31118
+ if (updateKind === "config_option_update") {
31119
+ return;
31120
+ }
30843
31121
  const isCompletedToolCallUpdate = updateKind === "tool_call_update" && isCompletedToolStatus(p.status);
30844
31122
  const toolName = p.toolCall?.name ?? p.tool_call?.name ?? "";
30845
31123
  const isToolUpdate = updateKind === "tool_call" || updateKind === "tool_call_update" || typeof toolName === "string" && toolName.length > 0;
@@ -30926,14 +31204,73 @@ function buildAcpSessionBridgeHooks(opts) {
30926
31204
  };
30927
31205
  }
30928
31206
 
31207
+ // src/agents/acp/local-agent-session-file.ts
31208
+ import fs9 from "node:fs";
31209
+ import os3 from "node:os";
31210
+ import path11 from "node:path";
31211
+ var LOCAL_AGENT_SESSION_DIR = path11.join(os3.homedir(), ".buildautomaton", "agent-sessions");
31212
+ function safeFileSlug(cloudSessionId) {
31213
+ const t = cloudSessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
31214
+ return t.length > 0 ? t : "session";
31215
+ }
31216
+ function localAgentSessionFilePath(cloudSessionId) {
31217
+ return path11.join(LOCAL_AGENT_SESSION_DIR, `${safeFileSlug(cloudSessionId)}.json`);
31218
+ }
31219
+ function readLocalAgentSessionFile(cloudSessionId) {
31220
+ try {
31221
+ const p = localAgentSessionFilePath(cloudSessionId);
31222
+ const raw = fs9.readFileSync(p, "utf8");
31223
+ const parsed = JSON.parse(raw);
31224
+ if (parsed.v !== 1) return null;
31225
+ return {
31226
+ v: 1,
31227
+ acpSessionId: typeof parsed.acpSessionId === "string" ? parsed.acpSessionId : null,
31228
+ backendAgentType: typeof parsed.backendAgentType === "string" ? parsed.backendAgentType : null,
31229
+ configOptions: Array.isArray(parsed.configOptions) ? parsed.configOptions : null,
31230
+ updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString()
31231
+ };
31232
+ } catch {
31233
+ return null;
31234
+ }
31235
+ }
31236
+ function writeLocalAgentSessionFile(cloudSessionId, patch) {
31237
+ try {
31238
+ const dir = LOCAL_AGENT_SESSION_DIR;
31239
+ if (!fs9.existsSync(dir)) fs9.mkdirSync(dir, { recursive: true });
31240
+ const p = localAgentSessionFilePath(cloudSessionId);
31241
+ const prev = readLocalAgentSessionFile(cloudSessionId);
31242
+ const next = {
31243
+ v: 1,
31244
+ acpSessionId: patch.acpSessionId !== void 0 ? patch.acpSessionId : prev?.acpSessionId ?? null,
31245
+ backendAgentType: patch.backendAgentType !== void 0 ? patch.backendAgentType : prev?.backendAgentType ?? null,
31246
+ configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
31247
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
31248
+ };
31249
+ fs9.writeFileSync(p, JSON.stringify(next, null, 2), "utf8");
31250
+ } catch {
31251
+ }
31252
+ }
31253
+
30929
31254
  // src/agents/acp/ensure-acp-client.ts
30930
31255
  async function ensureAcpClient(options) {
30931
- const { state, preferredAgentType, mode, agentConfig, sessionParentPath, routing, sendSessionUpdate, sendRequest, log: log2 } = options;
31256
+ const {
31257
+ state,
31258
+ preferredAgentType,
31259
+ mode,
31260
+ agentConfig,
31261
+ sessionParentPath,
31262
+ routing,
31263
+ cloudSessionId,
31264
+ sendSessionUpdate,
31265
+ sendRequest,
31266
+ log: log2
31267
+ } = options;
31268
+ state.latestAgentConfigForBridgeHooks = agentConfig != null && typeof agentConfig === "object" && !Array.isArray(agentConfig) ? agentConfig : null;
30932
31269
  const targetSessionParentPath = resolveSessionParentPathForAgentProcess(sessionParentPath);
30933
31270
  if (state.acpStartPromise && !state.acpHandle) {
30934
31271
  await state.acpStartPromise;
30935
31272
  }
30936
- if (state.acpHandle && state.lastAcpCwd != null && path11.resolve(state.lastAcpCwd) !== path11.resolve(targetSessionParentPath)) {
31273
+ if (state.acpHandle && state.lastAcpCwd != null && path12.resolve(state.lastAcpCwd) !== path12.resolve(targetSessionParentPath)) {
30937
31274
  try {
30938
31275
  state.acpHandle.disconnect();
30939
31276
  } catch {
@@ -30941,6 +31278,7 @@ async function ensureAcpClient(options) {
30941
31278
  state.acpHandle = null;
30942
31279
  state.acpStartPromise = null;
30943
31280
  state.acpAgentKey = null;
31281
+ state.activeSessionConfigOptions = null;
30944
31282
  }
30945
31283
  const resolved = resolveAgentCommand(preferredAgentType);
30946
31284
  if (!resolved) {
@@ -30961,12 +31299,13 @@ async function ensureAcpClient(options) {
30961
31299
  state.acpHandle = null;
30962
31300
  state.acpStartPromise = null;
30963
31301
  state.acpAgentKey = null;
31302
+ state.activeSessionConfigOptions = null;
30964
31303
  }
30965
31304
  if (state.acpHandle) return state.acpHandle;
30966
31305
  if (!state.acpStartPromise) {
30967
31306
  let statOk = false;
30968
31307
  try {
30969
- const st = fs9.statSync(targetSessionParentPath);
31308
+ const st = fs10.statSync(targetSessionParentPath);
30970
31309
  statOk = st.isDirectory();
30971
31310
  if (!statOk) {
30972
31311
  state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
@@ -30984,17 +31323,47 @@ async function ensureAcpClient(options) {
30984
31323
  sessionParentPath: targetSessionParentPath,
30985
31324
  getSendSessionUpdate: () => sendSessionUpdate,
30986
31325
  getSendRequest: () => sendRequest,
30987
- log: log2
31326
+ log: log2,
31327
+ getAutoApproveAcpPermissions: () => getCliPermissionModeFromAgentConfig(state.latestAgentConfigForBridgeHooks) === CLI_PERMISSION_MODE_DANGEROUS,
31328
+ resolveAcpPermissionRequest: (requestId, result) => {
31329
+ state.acpHandle?.resolveRequest?.(requestId, result);
31330
+ }
30988
31331
  });
31332
+ const persisted = cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "" ? readLocalAgentSessionFile(cloudSessionId) : null;
31333
+ const persistedAcpSessionId = persisted && persisted.backendAgentType === preferredAgentType && typeof persisted.acpSessionId === "string" && persisted.acpSessionId.trim() !== "" ? persisted.acpSessionId.trim() : null;
31334
+ state.activeSessionConfigOptions = Array.isArray(persisted?.configOptions) ? persisted.configOptions : null;
30989
31335
  state.acpStartPromise = resolved.createClient({
30990
31336
  command: resolved.command,
30991
31337
  sessionMode: mode,
30992
31338
  agentConfig: agentConfig ?? null,
30993
31339
  backendAgentType: preferredAgentType,
31340
+ persistedAcpSessionId,
31341
+ getActiveConfigOptions: () => state.activeSessionConfigOptions,
31342
+ onAcpSessionEstablished: (info) => {
31343
+ state.activeSessionConfigOptions = info.configOptions ?? state.activeSessionConfigOptions;
31344
+ if (cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "") {
31345
+ writeLocalAgentSessionFile(cloudSessionId, {
31346
+ acpSessionId: info.acpSessionId,
31347
+ configOptions: info.configOptions,
31348
+ backendAgentType: preferredAgentType
31349
+ });
31350
+ }
31351
+ },
31352
+ onAcpConfigOptionsUpdated: (configOptions) => {
31353
+ state.activeSessionConfigOptions = configOptions;
31354
+ if (cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "") {
31355
+ writeLocalAgentSessionFile(cloudSessionId, {
31356
+ configOptions,
31357
+ backendAgentType: preferredAgentType
31358
+ });
31359
+ }
31360
+ },
30994
31361
  onAgentSubprocessExit: () => {
30995
31362
  state.acpHandle = null;
30996
31363
  state.acpStartPromise = null;
30997
31364
  state.acpAgentKey = null;
31365
+ state.activeSessionConfigOptions = null;
31366
+ state.latestAgentConfigForBridgeHooks = null;
30998
31367
  state.lastAcpStartError = "Agent subprocess exited";
30999
31368
  },
31000
31369
  ...hooks,
@@ -31024,7 +31393,9 @@ async function createAcpManager(options) {
31024
31393
  acpStartPromise: null,
31025
31394
  lastAcpStartError: null,
31026
31395
  lastAcpCwd: null,
31027
- acpAgentKey: null
31396
+ acpAgentKey: null,
31397
+ activeSessionConfigOptions: null,
31398
+ latestAgentConfigForBridgeHooks: null
31028
31399
  };
31029
31400
  let backendFallbackAgentType = null;
31030
31401
  const promptRouting = {};
@@ -31074,6 +31445,7 @@ async function createAcpManager(options) {
31074
31445
  agentConfig: agentConfig ?? null,
31075
31446
  sessionParentPath,
31076
31447
  routing: promptRouting,
31448
+ cloudSessionId: sessionId,
31077
31449
  sendSessionUpdate,
31078
31450
  sendRequest: sendSessionUpdate,
31079
31451
  log: log2
@@ -31164,6 +31536,8 @@ async function createAcpManager(options) {
31164
31536
  state.acpHandle = null;
31165
31537
  state.acpStartPromise = null;
31166
31538
  state.acpAgentKey = null;
31539
+ state.activeSessionConfigOptions = null;
31540
+ state.latestAgentConfigForBridgeHooks = null;
31167
31541
  }
31168
31542
  return {
31169
31543
  setPreferredAgentType,
@@ -31176,12 +31550,12 @@ async function createAcpManager(options) {
31176
31550
  }
31177
31551
 
31178
31552
  // src/worktrees/session-worktree-manager.ts
31179
- import * as path18 from "node:path";
31180
- import os4 from "node:os";
31553
+ import * as path19 from "node:path";
31554
+ import os5 from "node:os";
31181
31555
 
31182
31556
  // src/worktrees/prepare-new-session-worktrees.ts
31183
- import * as fs11 from "node:fs";
31184
- import * as path13 from "node:path";
31557
+ import * as fs12 from "node:fs";
31558
+ import * as path14 from "node:path";
31185
31559
 
31186
31560
  // src/git/worktree-add.ts
31187
31561
  async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
@@ -31190,12 +31564,12 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
31190
31564
  }
31191
31565
 
31192
31566
  // src/worktrees/worktree-layout-file.ts
31193
- import * as fs10 from "node:fs";
31194
- import * as path12 from "node:path";
31195
- import os3 from "node:os";
31567
+ import * as fs11 from "node:fs";
31568
+ import * as path13 from "node:path";
31569
+ import os4 from "node:os";
31196
31570
  var LAYOUT_FILENAME = "worktree-launcher-layout.json";
31197
31571
  function defaultWorktreeLayoutPath() {
31198
- return path12.join(os3.homedir(), ".buildautomaton", LAYOUT_FILENAME);
31572
+ return path13.join(os4.homedir(), ".buildautomaton", LAYOUT_FILENAME);
31199
31573
  }
31200
31574
  function normalizeLoadedLayout(raw) {
31201
31575
  if (raw && typeof raw === "object" && "launcherCwds" in raw) {
@@ -31207,8 +31581,8 @@ function normalizeLoadedLayout(raw) {
31207
31581
  function loadWorktreeLayout() {
31208
31582
  try {
31209
31583
  const p = defaultWorktreeLayoutPath();
31210
- if (!fs10.existsSync(p)) return { launcherCwds: [] };
31211
- const raw = JSON.parse(fs10.readFileSync(p, "utf8"));
31584
+ if (!fs11.existsSync(p)) return { launcherCwds: [] };
31585
+ const raw = JSON.parse(fs11.readFileSync(p, "utf8"));
31212
31586
  return normalizeLoadedLayout(raw);
31213
31587
  } catch {
31214
31588
  return { launcherCwds: [] };
@@ -31216,24 +31590,24 @@ function loadWorktreeLayout() {
31216
31590
  }
31217
31591
  function saveWorktreeLayout(layout) {
31218
31592
  try {
31219
- const dir = path12.dirname(defaultWorktreeLayoutPath());
31220
- fs10.mkdirSync(dir, { recursive: true });
31221
- fs10.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
31593
+ const dir = path13.dirname(defaultWorktreeLayoutPath());
31594
+ fs11.mkdirSync(dir, { recursive: true });
31595
+ fs11.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
31222
31596
  } catch {
31223
31597
  }
31224
31598
  }
31225
31599
  function baseNameSafe(pathString) {
31226
- return path12.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
31600
+ return path13.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
31227
31601
  }
31228
31602
  function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
31229
- const norm = path12.resolve(bridgeRootPath2);
31230
- const existing = layout.launcherCwds.find((e) => path12.resolve(e.absolutePath) === norm);
31603
+ const norm = path13.resolve(bridgeRootPath2);
31604
+ const existing = layout.launcherCwds.find((e) => path13.resolve(e.absolutePath) === norm);
31231
31605
  return existing?.dirName;
31232
31606
  }
31233
31607
  function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
31234
31608
  const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
31235
31609
  if (existing) return existing;
31236
- const norm = path12.resolve(bridgeRootPath2);
31610
+ const norm = path13.resolve(bridgeRootPath2);
31237
31611
  const base = baseNameSafe(norm);
31238
31612
  const used = new Set(layout.launcherCwds.map((e) => e.dirName));
31239
31613
  let name = base;
@@ -31250,10 +31624,10 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
31250
31624
  // src/worktrees/prepare-new-session-worktrees.ts
31251
31625
  async function prepareNewSessionWorktrees(options) {
31252
31626
  const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2 } = options;
31253
- const bridgeResolved = path13.resolve(bridgeRoot);
31627
+ const bridgeResolved = path14.resolve(bridgeRoot);
31254
31628
  const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
31255
- const bridgeKeyDir = path13.join(worktreesRootPath, cwdKey);
31256
- const sessionDir = path13.join(bridgeKeyDir, sessionId);
31629
+ const bridgeKeyDir = path14.join(worktreesRootPath, cwdKey);
31630
+ const sessionDir = path14.join(bridgeKeyDir, sessionId);
31257
31631
  const repos = await discoverGitReposUnderRoot(bridgeResolved);
31258
31632
  if (repos.length === 0) {
31259
31633
  log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
@@ -31261,14 +31635,14 @@ async function prepareNewSessionWorktrees(options) {
31261
31635
  }
31262
31636
  const branch = `session-${sessionId}`;
31263
31637
  const worktreePaths = [];
31264
- fs11.mkdirSync(sessionDir, { recursive: true });
31638
+ fs12.mkdirSync(sessionDir, { recursive: true });
31265
31639
  for (const repo of repos) {
31266
- let rel = path13.relative(bridgeResolved, repo.absolutePath);
31267
- if (rel.startsWith("..") || path13.isAbsolute(rel)) continue;
31640
+ let rel = path14.relative(bridgeResolved, repo.absolutePath);
31641
+ if (rel.startsWith("..") || path14.isAbsolute(rel)) continue;
31268
31642
  const relNorm = rel === "" ? "." : rel;
31269
- const wtPath = relNorm === "." ? sessionDir : path13.join(sessionDir, relNorm);
31643
+ const wtPath = relNorm === "." ? sessionDir : path14.join(sessionDir, relNorm);
31270
31644
  if (relNorm !== ".") {
31271
- fs11.mkdirSync(path13.dirname(wtPath), { recursive: true });
31645
+ fs12.mkdirSync(path14.dirname(wtPath), { recursive: true });
31272
31646
  }
31273
31647
  try {
31274
31648
  await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
@@ -31310,23 +31684,23 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
31310
31684
  }
31311
31685
 
31312
31686
  // src/worktrees/remove-session-worktrees.ts
31313
- import * as fs14 from "node:fs";
31687
+ import * as fs15 from "node:fs";
31314
31688
 
31315
31689
  // src/git/worktree-remove.ts
31316
- import * as fs13 from "node:fs";
31690
+ import * as fs14 from "node:fs";
31317
31691
 
31318
31692
  // src/git/resolve-main-repo-from-git-file.ts
31319
- import * as fs12 from "node:fs";
31320
- import * as path14 from "node:path";
31693
+ import * as fs13 from "node:fs";
31694
+ import * as path15 from "node:path";
31321
31695
  function resolveMainRepoFromWorktreeGitFile(wt) {
31322
- const gitDirFile = path14.join(wt, ".git");
31323
- if (!fs12.existsSync(gitDirFile) || !fs12.statSync(gitDirFile).isFile()) return "";
31324
- const first2 = fs12.readFileSync(gitDirFile, "utf8").trim();
31696
+ const gitDirFile = path15.join(wt, ".git");
31697
+ if (!fs13.existsSync(gitDirFile) || !fs13.statSync(gitDirFile).isFile()) return "";
31698
+ const first2 = fs13.readFileSync(gitDirFile, "utf8").trim();
31325
31699
  const m = first2.match(/^gitdir:\s*(.+)$/im);
31326
31700
  if (!m) return "";
31327
- const gitWorktreePath = path14.resolve(wt, m[1].trim());
31328
- const gitDir = path14.dirname(path14.dirname(gitWorktreePath));
31329
- return path14.dirname(gitDir);
31701
+ const gitWorktreePath = path15.resolve(wt, m[1].trim());
31702
+ const gitDir = path15.dirname(path15.dirname(gitWorktreePath));
31703
+ return path15.dirname(gitDir);
31330
31704
  }
31331
31705
 
31332
31706
  // src/git/worktree-remove.ts
@@ -31335,7 +31709,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
31335
31709
  if (mainRepo) {
31336
31710
  await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
31337
31711
  } else {
31338
- fs13.rmSync(worktreePath, { recursive: true, force: true });
31712
+ fs14.rmSync(worktreePath, { recursive: true, force: true });
31339
31713
  }
31340
31714
  }
31341
31715
 
@@ -31348,7 +31722,7 @@ async function removeSessionWorktrees(paths, log2) {
31348
31722
  } catch (e) {
31349
31723
  log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
31350
31724
  try {
31351
- fs14.rmSync(wt, { recursive: true, force: true });
31725
+ fs15.rmSync(wt, { recursive: true, force: true });
31352
31726
  } catch {
31353
31727
  }
31354
31728
  }
@@ -31568,7 +31942,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
31568
31942
  }
31569
31943
 
31570
31944
  // src/git/working-directory/changes/get-working-tree-change-repo-details.ts
31571
- import * as path16 from "node:path";
31945
+ import * as path17 from "node:path";
31572
31946
 
31573
31947
  // src/git/working-directory/changes/parse-git-status.ts
31574
31948
  function parseNameStatusLines(lines) {
@@ -31688,8 +32062,8 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
31688
32062
  }
31689
32063
 
31690
32064
  // src/git/working-directory/changes/list-changed-files-for-repo.ts
31691
- import * as fs16 from "node:fs";
31692
- import * as path15 from "node:path";
32065
+ import * as fs17 from "node:fs";
32066
+ import * as path16 from "node:path";
31693
32067
 
31694
32068
  // src/git/working-directory/changes/count-lines.ts
31695
32069
  import { createReadStream } from "node:fs";
@@ -31713,7 +32087,7 @@ async function countTextFileLines(filePath) {
31713
32087
  }
31714
32088
 
31715
32089
  // src/git/working-directory/changes/hydrate-patch.ts
31716
- import * as fs15 from "node:fs";
32090
+ import * as fs16 from "node:fs";
31717
32091
  var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
31718
32092
  var MAX_HYDRATE_LINES_PER_GAP = 8e3;
31719
32093
  var MAX_HYDRATE_LINES_PER_FILE = 8e4;
@@ -31728,7 +32102,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
31728
32102
  }
31729
32103
  async function readWorktreeFileLines(filePath) {
31730
32104
  try {
31731
- const raw = await fs15.promises.readFile(filePath, "utf8");
32105
+ const raw = await fs16.promises.readFile(filePath, "utf8");
31732
32106
  return raw.split(/\r?\n/);
31733
32107
  } catch {
31734
32108
  return null;
@@ -31863,7 +32237,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
31863
32237
  const rows = [];
31864
32238
  for (const pathInRepo of paths) {
31865
32239
  const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
31866
- const repoFilePath = path15.join(repoGitCwd, pathInRepo);
32240
+ const repoFilePath = path16.join(repoGitCwd, pathInRepo);
31867
32241
  const nums = numByPath.get(pathInRepo);
31868
32242
  let additions = nums?.additions ?? 0;
31869
32243
  let deletions = nums?.deletions ?? 0;
@@ -31876,7 +32250,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
31876
32250
  deletions = fromGit.deletions;
31877
32251
  } else {
31878
32252
  try {
31879
- const st = await fs16.promises.stat(repoFilePath);
32253
+ const st = await fs17.promises.stat(repoFilePath);
31880
32254
  if (st.isFile()) additions = await countTextFileLines(repoFilePath);
31881
32255
  else additions = 0;
31882
32256
  } catch {
@@ -31902,7 +32276,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
31902
32276
  } else {
31903
32277
  pathInRepo = row.pathRelLauncher;
31904
32278
  }
31905
- const filePath = path15.join(repoGitCwd, pathInRepo);
32279
+ const filePath = path16.join(repoGitCwd, pathInRepo);
31906
32280
  let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
31907
32281
  if (patch) {
31908
32282
  patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
@@ -31918,8 +32292,8 @@ function normRepoRel(p) {
31918
32292
  return x === "" ? "." : x;
31919
32293
  }
31920
32294
  async function getWorkingTreeChangeRepoDetails(options) {
31921
- const bridgeRoot = path16.resolve(getBridgeRoot());
31922
- const sessionWtRoot = options.sessionWorktreeRootPath ? path16.resolve(options.sessionWorktreeRootPath) : null;
32295
+ const bridgeRoot = path17.resolve(getBridgeRoot());
32296
+ const sessionWtRoot = options.sessionWorktreeRootPath ? path17.resolve(options.sessionWorktreeRootPath) : null;
31923
32297
  const legacyNested = options.legacyRepoNestedSessionLayout === true;
31924
32298
  const out = [];
31925
32299
  const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
@@ -31932,7 +32306,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
31932
32306
  }
31933
32307
  const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
31934
32308
  for (const target of options.commitTargetPaths) {
31935
- const t = path16.resolve(target);
32309
+ const t = path17.resolve(target);
31936
32310
  if (!await isGitRepoDirectory(t)) continue;
31937
32311
  const g = cliSimpleGit(t);
31938
32312
  let branch = "HEAD";
@@ -31945,8 +32319,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
31945
32319
  const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
31946
32320
  let repoRelPath;
31947
32321
  if (sessionWtRoot) {
31948
- const anchor = legacyNested ? path16.dirname(t) : t;
31949
- const relNorm = path16.relative(sessionWtRoot, anchor);
32322
+ const anchor = legacyNested ? path17.dirname(t) : t;
32323
+ const relNorm = path17.relative(sessionWtRoot, anchor);
31950
32324
  repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
31951
32325
  } else {
31952
32326
  let top = t;
@@ -31955,8 +32329,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
31955
32329
  } catch {
31956
32330
  top = t;
31957
32331
  }
31958
- const rel = path16.relative(bridgeRoot, path16.resolve(top)).replace(/\\/g, "/") || ".";
31959
- repoRelPath = rel.startsWith("..") ? path16.basename(path16.resolve(top)) : rel;
32332
+ const rel = path17.relative(bridgeRoot, path17.resolve(top)).replace(/\\/g, "/") || ".";
32333
+ repoRelPath = rel.startsWith("..") ? path17.basename(path17.resolve(top)) : rel;
31960
32334
  }
31961
32335
  const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
31962
32336
  if (filter && norm !== filter) continue;
@@ -32021,11 +32395,11 @@ async function commitSessionWorktrees(options) {
32021
32395
  }
32022
32396
 
32023
32397
  // src/worktrees/discover-session-worktree-on-disk.ts
32024
- import * as fs17 from "node:fs";
32025
- import * as path17 from "node:path";
32398
+ import * as fs18 from "node:fs";
32399
+ import * as path18 from "node:path";
32026
32400
  function isGitDir(dirPath) {
32027
32401
  try {
32028
- return fs17.existsSync(path17.join(dirPath, ".git"));
32402
+ return fs18.existsSync(path18.join(dirPath, ".git"));
32029
32403
  } catch {
32030
32404
  return false;
32031
32405
  }
@@ -32034,23 +32408,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
32034
32408
  const out = [];
32035
32409
  const walk = (dir) => {
32036
32410
  if (isGitDir(dir)) {
32037
- out.push(path17.resolve(dir));
32411
+ out.push(path18.resolve(dir));
32038
32412
  return;
32039
32413
  }
32040
32414
  let entries;
32041
32415
  try {
32042
- entries = fs17.readdirSync(dir, { withFileTypes: true });
32416
+ entries = fs18.readdirSync(dir, { withFileTypes: true });
32043
32417
  } catch {
32044
32418
  return;
32045
32419
  }
32046
32420
  for (const e of entries) {
32047
32421
  if (e.name.startsWith(".")) continue;
32048
- const full = path17.join(dir, e.name);
32422
+ const full = path18.join(dir, e.name);
32049
32423
  if (!e.isDirectory()) continue;
32050
32424
  walk(full);
32051
32425
  }
32052
32426
  };
32053
- walk(path17.resolve(rootPath));
32427
+ walk(path18.resolve(rootPath));
32054
32428
  return [...new Set(out)];
32055
32429
  }
32056
32430
  function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
@@ -32059,16 +32433,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
32059
32433
  if (depth > maxDepth) return;
32060
32434
  let entries;
32061
32435
  try {
32062
- entries = fs17.readdirSync(dir, { withFileTypes: true });
32436
+ entries = fs18.readdirSync(dir, { withFileTypes: true });
32063
32437
  } catch {
32064
32438
  return;
32065
32439
  }
32066
32440
  for (const e of entries) {
32067
32441
  if (e.name.startsWith(".")) continue;
32068
- const full = path17.join(dir, e.name);
32442
+ const full = path18.join(dir, e.name);
32069
32443
  if (!e.isDirectory()) continue;
32070
32444
  if (e.name === sessionId) {
32071
- if (isGitDir(full)) out.push(path17.resolve(full));
32445
+ if (isGitDir(full)) out.push(path18.resolve(full));
32072
32446
  } else {
32073
32447
  walk(full, depth + 1);
32074
32448
  }
@@ -32080,14 +32454,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
32080
32454
  function tryBindingFromSessionDirectory(sessionDir) {
32081
32455
  let st;
32082
32456
  try {
32083
- st = fs17.statSync(sessionDir);
32457
+ st = fs18.statSync(sessionDir);
32084
32458
  } catch {
32085
32459
  return null;
32086
32460
  }
32087
32461
  if (!st.isDirectory()) return null;
32088
32462
  const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
32089
32463
  if (worktreePaths.length === 0) return null;
32090
- const abs = path17.resolve(sessionDir);
32464
+ const abs = path18.resolve(sessionDir);
32091
32465
  return {
32092
32466
  sessionParentPath: abs,
32093
32467
  workingTreeRelRoot: abs,
@@ -32097,20 +32471,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
32097
32471
  function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
32098
32472
  const sid = sessionId.trim();
32099
32473
  if (!sid) return null;
32100
- const hintR = path17.resolve(checkoutPath);
32474
+ const hintR = path18.resolve(checkoutPath);
32101
32475
  let best = null;
32102
- let cur = path17.dirname(hintR);
32476
+ let cur = path18.dirname(hintR);
32103
32477
  for (let i = 0; i < 40; i++) {
32104
32478
  const paths = collectWorktreeRootsNamed(cur, sid, 24);
32105
- if (paths.some((p) => path17.resolve(p) === hintR)) {
32106
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path17.resolve(paths[0]);
32479
+ if (paths.some((p) => path18.resolve(p) === hintR)) {
32480
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path18.resolve(paths[0]);
32107
32481
  best = {
32108
- sessionParentPath: path17.resolve(isolated),
32109
- workingTreeRelRoot: path17.resolve(cur),
32110
- repoCheckoutPaths: paths.map((p) => path17.resolve(p))
32482
+ sessionParentPath: path18.resolve(isolated),
32483
+ workingTreeRelRoot: path18.resolve(cur),
32484
+ repoCheckoutPaths: paths.map((p) => path18.resolve(p))
32111
32485
  };
32112
32486
  }
32113
- const next = path17.dirname(cur);
32487
+ const next = path18.dirname(cur);
32114
32488
  if (next === cur) break;
32115
32489
  cur = next;
32116
32490
  }
@@ -32118,33 +32492,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
32118
32492
  }
32119
32493
  function discoverSessionWorktreeOnDisk(options) {
32120
32494
  const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
32121
- if (!sessionId.trim() || !fs17.existsSync(worktreesRootPath)) return null;
32495
+ if (!sessionId.trim() || !fs18.existsSync(worktreesRootPath)) return null;
32122
32496
  const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
32123
32497
  const keys = [];
32124
32498
  if (preferredKey) keys.push(preferredKey);
32125
32499
  try {
32126
- for (const name of fs17.readdirSync(worktreesRootPath)) {
32500
+ for (const name of fs18.readdirSync(worktreesRootPath)) {
32127
32501
  if (name.startsWith(".")) continue;
32128
- const p = path17.join(worktreesRootPath, name);
32129
- if (!fs17.statSync(p).isDirectory()) continue;
32502
+ const p = path18.join(worktreesRootPath, name);
32503
+ if (!fs18.statSync(p).isDirectory()) continue;
32130
32504
  if (name !== preferredKey) keys.push(name);
32131
32505
  }
32132
32506
  } catch {
32133
32507
  return null;
32134
32508
  }
32135
32509
  for (const key of keys) {
32136
- const layoutRoot = path17.join(worktreesRootPath, key);
32137
- if (!fs17.existsSync(layoutRoot) || !fs17.statSync(layoutRoot).isDirectory()) continue;
32138
- const sessionDir = path17.join(layoutRoot, sessionId);
32510
+ const layoutRoot = path18.join(worktreesRootPath, key);
32511
+ if (!fs18.existsSync(layoutRoot) || !fs18.statSync(layoutRoot).isDirectory()) continue;
32512
+ const sessionDir = path18.join(layoutRoot, sessionId);
32139
32513
  const nested = tryBindingFromSessionDirectory(sessionDir);
32140
32514
  if (nested) return nested;
32141
32515
  const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
32142
32516
  if (legacyPaths.length > 0) {
32143
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path17.resolve(legacyPaths[0]);
32517
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path18.resolve(legacyPaths[0]);
32144
32518
  return {
32145
- sessionParentPath: path17.resolve(isolated),
32146
- workingTreeRelRoot: path17.resolve(layoutRoot),
32147
- repoCheckoutPaths: legacyPaths.map((p) => path17.resolve(p))
32519
+ sessionParentPath: path18.resolve(isolated),
32520
+ workingTreeRelRoot: path18.resolve(layoutRoot),
32521
+ repoCheckoutPaths: legacyPaths.map((p) => path18.resolve(p))
32148
32522
  };
32149
32523
  }
32150
32524
  }
@@ -32153,12 +32527,12 @@ function discoverSessionWorktreeOnDisk(options) {
32153
32527
  function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
32154
32528
  const sid = sessionId.trim();
32155
32529
  if (!sid) return null;
32156
- const hint = path17.resolve(sessionWorktreeRootPathOrHint);
32157
- const underHint = tryBindingFromSessionDirectory(path17.join(hint, sid));
32530
+ const hint = path18.resolve(sessionWorktreeRootPathOrHint);
32531
+ const underHint = tryBindingFromSessionDirectory(path18.join(hint, sid));
32158
32532
  if (underHint) return underHint;
32159
32533
  const direct = tryBindingFromSessionDirectory(hint);
32160
32534
  if (direct) {
32161
- if (path17.basename(hint) === sid && isGitDir(hint)) {
32535
+ if (path18.basename(hint) === sid && isGitDir(hint)) {
32162
32536
  const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
32163
32537
  if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
32164
32538
  return legacyFromCheckout;
@@ -32166,24 +32540,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
32166
32540
  }
32167
32541
  return direct;
32168
32542
  }
32169
- if (path17.basename(hint) === sid && isGitDir(hint)) {
32543
+ if (path18.basename(hint) === sid && isGitDir(hint)) {
32170
32544
  const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
32171
32545
  if (legacyFromCheckout) return legacyFromCheckout;
32172
32546
  }
32173
32547
  let st;
32174
32548
  try {
32175
- st = fs17.statSync(hint);
32549
+ st = fs18.statSync(hint);
32176
32550
  } catch {
32177
32551
  return null;
32178
32552
  }
32179
32553
  if (!st.isDirectory()) return null;
32180
32554
  const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
32181
32555
  if (legacyPaths.length === 0) return null;
32182
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path17.resolve(legacyPaths[0]);
32556
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path18.resolve(legacyPaths[0]);
32183
32557
  return {
32184
- sessionParentPath: path17.resolve(isolated),
32558
+ sessionParentPath: path18.resolve(isolated),
32185
32559
  workingTreeRelRoot: hint,
32186
- repoCheckoutPaths: legacyPaths.map((p) => path17.resolve(p))
32560
+ repoCheckoutPaths: legacyPaths.map((p) => path18.resolve(p))
32187
32561
  };
32188
32562
  }
32189
32563
 
@@ -32206,10 +32580,10 @@ var SessionWorktreeManager = class {
32206
32580
  this.layout = loadWorktreeLayout();
32207
32581
  }
32208
32582
  rememberSessionWorktrees(sessionId, binding) {
32209
- const paths = binding.repoCheckoutPaths.map((p) => path18.resolve(p));
32583
+ const paths = binding.repoCheckoutPaths.map((p) => path19.resolve(p));
32210
32584
  this.sessionRepoCheckoutPaths.set(sessionId, paths);
32211
- this.sessionParentPathBySession.set(sessionId, path18.resolve(binding.sessionParentPath));
32212
- this.sessionWorkingTreeRelRootBySession.set(sessionId, path18.resolve(binding.workingTreeRelRoot));
32585
+ this.sessionParentPathBySession.set(sessionId, path19.resolve(binding.sessionParentPath));
32586
+ this.sessionWorkingTreeRelRootBySession.set(sessionId, path19.resolve(binding.workingTreeRelRoot));
32213
32587
  }
32214
32588
  sessionParentPathAfterRemember(sessionId) {
32215
32589
  return this.sessionParentPathBySession.get(sessionId);
@@ -32226,7 +32600,7 @@ var SessionWorktreeManager = class {
32226
32600
  const parent = this.sessionParentPathBySession.get(sessionId);
32227
32601
  const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
32228
32602
  if (!parent || !relRoot) return false;
32229
- return path18.resolve(parent) !== path18.resolve(relRoot);
32603
+ return path19.resolve(parent) !== path19.resolve(relRoot);
32230
32604
  }
32231
32605
  /**
32232
32606
  * Session parent path for `worktrees_root`: the per-session directory (new layout) or primary checkout (legacy).
@@ -32235,7 +32609,7 @@ var SessionWorktreeManager = class {
32235
32609
  if (!sessionId) return null;
32236
32610
  const sid = sessionId.trim();
32237
32611
  const cached2 = this.sessionParentPathBySession.get(sid);
32238
- if (cached2) return path18.resolve(cached2);
32612
+ if (cached2) return path19.resolve(cached2);
32239
32613
  const paths = this.ensureRepoCheckoutPathsForSession(sid) ?? this.getRepoCheckoutPathsForSession(sid);
32240
32614
  if (!paths?.length) return null;
32241
32615
  return resolveIsolatedSessionParentPathFromCheckouts(paths);
@@ -32249,7 +32623,7 @@ var SessionWorktreeManager = class {
32249
32623
  const sid = sessionId.trim();
32250
32624
  const parentPathRaw = opts.sessionParentPath?.trim();
32251
32625
  if (parentPathRaw) {
32252
- const resolved = path18.resolve(parentPathRaw);
32626
+ const resolved = path19.resolve(parentPathRaw);
32253
32627
  if (sid && parseSessionParent(opts.sessionParent) === "worktrees_root") {
32254
32628
  const diskFirst = this.tryDiscoverFromDisk(sid);
32255
32629
  if (diskFirst) {
@@ -32268,7 +32642,7 @@ var SessionWorktreeManager = class {
32268
32642
  this.rememberSessionWorktrees(sid, tryRoot);
32269
32643
  return this.sessionParentPathAfterRemember(sid);
32270
32644
  }
32271
- const next = path18.dirname(cur);
32645
+ const next = path19.dirname(cur);
32272
32646
  if (next === cur) break;
32273
32647
  cur = next;
32274
32648
  }
@@ -32421,15 +32795,15 @@ var SessionWorktreeManager = class {
32421
32795
  }
32422
32796
  };
32423
32797
  function defaultWorktreesRootPath() {
32424
- return path18.join(os4.homedir(), ".buildautomaton", "worktrees");
32798
+ return path19.join(os5.homedir(), ".buildautomaton", "worktrees");
32425
32799
  }
32426
32800
 
32427
32801
  // src/files/watch-file-index.ts
32428
32802
  import { watch } from "node:fs";
32429
- import path25 from "node:path";
32803
+ import path26 from "node:path";
32430
32804
 
32431
32805
  // src/files/index/build-file-index.ts
32432
- import path22 from "node:path";
32806
+ import path23 from "node:path";
32433
32807
 
32434
32808
  // src/runtime/yield-to-event-loop.ts
32435
32809
  function yieldToEventLoop() {
@@ -32437,14 +32811,14 @@ function yieldToEventLoop() {
32437
32811
  }
32438
32812
 
32439
32813
  // src/files/index/walk-workspace-tree.ts
32440
- import fs18 from "node:fs";
32441
- import path20 from "node:path";
32814
+ import fs19 from "node:fs";
32815
+ import path21 from "node:path";
32442
32816
 
32443
32817
  // src/files/index/constants.ts
32444
- import path19 from "node:path";
32445
- import os5 from "node:os";
32818
+ import path20 from "node:path";
32819
+ import os6 from "node:os";
32446
32820
  var INDEX_WORK_YIELD_EVERY = 256;
32447
- var INDEX_DIR = path19.join(os5.homedir(), ".buildautomaton");
32821
+ var INDEX_DIR = path20.join(os6.homedir(), ".buildautomaton");
32448
32822
  var INDEX_HASH_LEN = 16;
32449
32823
  var INDEX_VERSION = 2;
32450
32824
  var INDEX_LOG_PREFIX = "[file-index]";
@@ -32453,20 +32827,20 @@ var INDEX_LOG_PREFIX = "[file-index]";
32453
32827
  function walkWorkspaceTreeSync(dir, baseDir, out) {
32454
32828
  let names;
32455
32829
  try {
32456
- names = fs18.readdirSync(dir);
32830
+ names = fs19.readdirSync(dir);
32457
32831
  } catch {
32458
32832
  return;
32459
32833
  }
32460
32834
  for (const name of names) {
32461
32835
  if (name.startsWith(".")) continue;
32462
- const full = path20.join(dir, name);
32836
+ const full = path21.join(dir, name);
32463
32837
  let stat2;
32464
32838
  try {
32465
- stat2 = fs18.statSync(full);
32839
+ stat2 = fs19.statSync(full);
32466
32840
  } catch {
32467
32841
  continue;
32468
32842
  }
32469
- const relative5 = path20.relative(baseDir, full).replace(/\\/g, "/");
32843
+ const relative5 = path21.relative(baseDir, full).replace(/\\/g, "/");
32470
32844
  if (stat2.isDirectory()) {
32471
32845
  walkWorkspaceTreeSync(full, baseDir, out);
32472
32846
  } else if (stat2.isFile()) {
@@ -32477,7 +32851,7 @@ function walkWorkspaceTreeSync(dir, baseDir, out) {
32477
32851
  async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
32478
32852
  let names;
32479
32853
  try {
32480
- names = await fs18.promises.readdir(dir);
32854
+ names = await fs19.promises.readdir(dir);
32481
32855
  } catch {
32482
32856
  return;
32483
32857
  }
@@ -32487,14 +32861,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
32487
32861
  await yieldToEventLoop();
32488
32862
  }
32489
32863
  state.n++;
32490
- const full = path20.join(dir, name);
32864
+ const full = path21.join(dir, name);
32491
32865
  let stat2;
32492
32866
  try {
32493
- stat2 = await fs18.promises.stat(full);
32867
+ stat2 = await fs19.promises.stat(full);
32494
32868
  } catch {
32495
32869
  continue;
32496
32870
  }
32497
- const relative5 = path20.relative(baseDir, full).replace(/\\/g, "/");
32871
+ const relative5 = path21.relative(baseDir, full).replace(/\\/g, "/");
32498
32872
  if (stat2.isDirectory()) {
32499
32873
  await walkWorkspaceTreeAsync(full, baseDir, out, state);
32500
32874
  } else if (stat2.isFile()) {
@@ -32575,22 +32949,22 @@ async function buildTrigramMapForPathsAsync(paths) {
32575
32949
  }
32576
32950
 
32577
32951
  // src/files/index/write-index-file.ts
32578
- import fs19 from "node:fs";
32952
+ import fs20 from "node:fs";
32579
32953
 
32580
32954
  // src/files/index/paths.ts
32581
- import path21 from "node:path";
32955
+ import path22 from "node:path";
32582
32956
  import crypto2 from "node:crypto";
32583
32957
  function getIndexPathForCwd(resolvedCwd) {
32584
32958
  const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
32585
- return path21.join(INDEX_DIR, `.file-index-${hash}.json`);
32959
+ return path22.join(INDEX_DIR, `.file-index-${hash}.json`);
32586
32960
  }
32587
32961
 
32588
32962
  // src/files/index/write-index-file.ts
32589
32963
  function writeIndexFileSync(resolvedCwd, data) {
32590
32964
  const indexPath = getIndexPathForCwd(resolvedCwd);
32591
32965
  try {
32592
- if (!fs19.existsSync(INDEX_DIR)) fs19.mkdirSync(INDEX_DIR, { recursive: true });
32593
- fs19.writeFileSync(indexPath, JSON.stringify(data), "utf8");
32966
+ if (!fs20.existsSync(INDEX_DIR)) fs20.mkdirSync(INDEX_DIR, { recursive: true });
32967
+ fs20.writeFileSync(indexPath, JSON.stringify(data), "utf8");
32594
32968
  } catch (e) {
32595
32969
  console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
32596
32970
  }
@@ -32598,8 +32972,8 @@ function writeIndexFileSync(resolvedCwd, data) {
32598
32972
  async function writeIndexFileAsync(resolvedCwd, data) {
32599
32973
  const indexPath = getIndexPathForCwd(resolvedCwd);
32600
32974
  try {
32601
- await fs19.promises.mkdir(INDEX_DIR, { recursive: true });
32602
- await fs19.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
32975
+ await fs20.promises.mkdir(INDEX_DIR, { recursive: true });
32976
+ await fs20.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
32603
32977
  } catch (e) {
32604
32978
  console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
32605
32979
  }
@@ -32613,7 +32987,7 @@ function sortPaths(paths) {
32613
32987
  paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
32614
32988
  }
32615
32989
  function buildFileIndex(cwd) {
32616
- const resolved = path22.resolve(cwd);
32990
+ const resolved = path23.resolve(cwd);
32617
32991
  const paths = [];
32618
32992
  walkWorkspaceTreeSync(resolved, resolved, paths);
32619
32993
  sortPaths(paths);
@@ -32623,7 +32997,7 @@ function buildFileIndex(cwd) {
32623
32997
  return data;
32624
32998
  }
32625
32999
  async function buildFileIndexAsync(cwd) {
32626
- const resolved = path22.resolve(cwd);
33000
+ const resolved = path23.resolve(cwd);
32627
33001
  const paths = [];
32628
33002
  await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
32629
33003
  await yieldToEventLoop();
@@ -32635,13 +33009,13 @@ async function buildFileIndexAsync(cwd) {
32635
33009
  }
32636
33010
 
32637
33011
  // src/files/index/load-file-index.ts
32638
- import fs20 from "node:fs";
32639
- import path23 from "node:path";
33012
+ import fs21 from "node:fs";
33013
+ import path24 from "node:path";
32640
33014
  function loadFileIndex(cwd) {
32641
- const resolved = path23.resolve(cwd);
33015
+ const resolved = path24.resolve(cwd);
32642
33016
  const indexPath = getIndexPathForCwd(resolved);
32643
33017
  try {
32644
- const raw = fs20.readFileSync(indexPath, "utf8");
33018
+ const raw = fs21.readFileSync(indexPath, "utf8");
32645
33019
  const parsed = JSON.parse(raw);
32646
33020
  if (parsed !== null && typeof parsed === "object" && Array.isArray(parsed.paths)) {
32647
33021
  const obj = parsed;
@@ -32660,9 +33034,9 @@ function loadFileIndex(cwd) {
32660
33034
  }
32661
33035
 
32662
33036
  // src/files/index/ensure-file-index.ts
32663
- import path24 from "node:path";
33037
+ import path25 from "node:path";
32664
33038
  async function ensureFileIndexAsync(cwd) {
32665
- const resolved = path24.resolve(cwd);
33039
+ const resolved = path25.resolve(cwd);
32666
33040
  const cached2 = loadFileIndex(resolved);
32667
33041
  if (cached2 !== null) return { data: cached2, fromCache: true };
32668
33042
  const data = await buildFileIndexAsync(resolved);
@@ -32745,7 +33119,7 @@ function createFsWatcher(resolved, schedule) {
32745
33119
  }
32746
33120
  }
32747
33121
  function startFileIndexWatcher(cwd = getBridgeRoot()) {
32748
- const resolved = path25.resolve(cwd);
33122
+ const resolved = path26.resolve(cwd);
32749
33123
  void buildFileIndexAsync(resolved).catch((e) => {
32750
33124
  console.error("[file-index] Initial index build failed:", e);
32751
33125
  });
@@ -32773,7 +33147,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
32773
33147
  }
32774
33148
 
32775
33149
  // src/connection/create-bridge-connection.ts
32776
- import * as path33 from "node:path";
33150
+ import * as path34 from "node:path";
32777
33151
 
32778
33152
  // src/dev-servers/manager/dev-server-manager.ts
32779
33153
  import { rm as rm2 } from "node:fs/promises";
@@ -32817,7 +33191,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
32817
33191
  }
32818
33192
 
32819
33193
  // src/dev-servers/process/wire-dev-server-child-process.ts
32820
- import fs21 from "node:fs";
33194
+ import fs22 from "node:fs";
32821
33195
 
32822
33196
  // src/dev-servers/manager/forward-pipe.ts
32823
33197
  function forwardChildPipe(childReadable, terminal, onData) {
@@ -32853,7 +33227,7 @@ function wireDevServerChildProcess(d) {
32853
33227
  d.setPollInterval(void 0);
32854
33228
  return;
32855
33229
  }
32856
- fs21.readFile(d.mergedLogPath, (err, buf) => {
33230
+ fs22.readFile(d.mergedLogPath, (err, buf) => {
32857
33231
  if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
32858
33232
  if (buf.length <= d.mergedReadPos.value) return;
32859
33233
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
@@ -32891,7 +33265,7 @@ ${errTail}` : ""}`);
32891
33265
  d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
32892
33266
  };
32893
33267
  if (mergedPath) {
32894
- fs21.readFile(mergedPath, (err, buf) => {
33268
+ fs22.readFile(mergedPath, (err, buf) => {
32895
33269
  if (!err && buf.length > d.mergedReadPos.value) {
32896
33270
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
32897
33271
  if (chunk.length > 0) {
@@ -32993,13 +33367,13 @@ function parseDevServerDefs(servers) {
32993
33367
  }
32994
33368
 
32995
33369
  // src/dev-servers/manager/shell-spawn/utils.ts
32996
- import fs22 from "node:fs";
33370
+ import fs23 from "node:fs";
32997
33371
  function isSpawnEbadf(e) {
32998
33372
  return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
32999
33373
  }
33000
33374
  function rmDirQuiet(dir) {
33001
33375
  try {
33002
- fs22.rmSync(dir, { recursive: true, force: true });
33376
+ fs23.rmSync(dir, { recursive: true, force: true });
33003
33377
  } catch {
33004
33378
  }
33005
33379
  }
@@ -33007,7 +33381,7 @@ var cachedDevNullReadFd;
33007
33381
  function devNullReadFd() {
33008
33382
  if (cachedDevNullReadFd === void 0) {
33009
33383
  const devPath = process.platform === "win32" ? "nul" : "/dev/null";
33010
- cachedDevNullReadFd = fs22.openSync(devPath, "r");
33384
+ cachedDevNullReadFd = fs23.openSync(devPath, "r");
33011
33385
  }
33012
33386
  return cachedDevNullReadFd;
33013
33387
  }
@@ -33081,15 +33455,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
33081
33455
 
33082
33456
  // src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
33083
33457
  import { spawn as spawn7 } from "node:child_process";
33084
- import fs23 from "node:fs";
33458
+ import fs24 from "node:fs";
33085
33459
  import { tmpdir } from "node:os";
33086
- import path26 from "node:path";
33460
+ import path27 from "node:path";
33087
33461
  function trySpawnMergedLogFile(command, env, cwd, signal) {
33088
- const tmpRoot = fs23.mkdtempSync(path26.join(tmpdir(), "ba-devsrv-log-"));
33089
- const logPath = path26.join(tmpRoot, "combined.log");
33462
+ const tmpRoot = fs24.mkdtempSync(path27.join(tmpdir(), "ba-devsrv-log-"));
33463
+ const logPath = path27.join(tmpRoot, "combined.log");
33090
33464
  let logFd;
33091
33465
  try {
33092
- logFd = fs23.openSync(logPath, "a");
33466
+ logFd = fs24.openSync(logPath, "a");
33093
33467
  } catch {
33094
33468
  rmDirQuiet(tmpRoot);
33095
33469
  return null;
@@ -33108,7 +33482,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33108
33482
  } else {
33109
33483
  proc = spawn7("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
33110
33484
  }
33111
- fs23.closeSync(logFd);
33485
+ fs24.closeSync(logFd);
33112
33486
  return {
33113
33487
  proc,
33114
33488
  pipedStdoutStderr: true,
@@ -33117,7 +33491,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33117
33491
  };
33118
33492
  } catch (e) {
33119
33493
  try {
33120
- fs23.closeSync(logFd);
33494
+ fs24.closeSync(logFd);
33121
33495
  } catch {
33122
33496
  }
33123
33497
  rmDirQuiet(tmpRoot);
@@ -33128,22 +33502,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33128
33502
 
33129
33503
  // src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
33130
33504
  import { spawn as spawn8 } from "node:child_process";
33131
- import fs24 from "node:fs";
33505
+ import fs25 from "node:fs";
33132
33506
  import { tmpdir as tmpdir2 } from "node:os";
33133
- import path27 from "node:path";
33507
+ import path28 from "node:path";
33134
33508
  function shSingleQuote(s) {
33135
33509
  return `'${s.replace(/'/g, `'\\''`)}'`;
33136
33510
  }
33137
33511
  function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
33138
- const tmpRoot = fs24.mkdtempSync(path27.join(tmpdir2(), "ba-devsrv-sh-"));
33139
- const logPath = path27.join(tmpRoot, "combined.log");
33140
- const innerPath = path27.join(tmpRoot, "_cmd.sh");
33141
- const runnerPath = path27.join(tmpRoot, "_run.sh");
33512
+ const tmpRoot = fs25.mkdtempSync(path28.join(tmpdir2(), "ba-devsrv-sh-"));
33513
+ const logPath = path28.join(tmpRoot, "combined.log");
33514
+ const innerPath = path28.join(tmpRoot, "_cmd.sh");
33515
+ const runnerPath = path28.join(tmpRoot, "_run.sh");
33142
33516
  try {
33143
- fs24.writeFileSync(innerPath, `#!/bin/sh
33517
+ fs25.writeFileSync(innerPath, `#!/bin/sh
33144
33518
  ${command}
33145
33519
  `);
33146
- fs24.writeFileSync(
33520
+ fs25.writeFileSync(
33147
33521
  runnerPath,
33148
33522
  `#!/bin/sh
33149
33523
  cd ${shSingleQuote(cwd)}
@@ -33169,13 +33543,13 @@ cd ${shSingleQuote(cwd)}
33169
33543
  }
33170
33544
  }
33171
33545
  function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
33172
- const tmpRoot = fs24.mkdtempSync(path27.join(tmpdir2(), "ba-devsrv-sh-"));
33173
- const logPath = path27.join(tmpRoot, "combined.log");
33174
- const runnerPath = path27.join(tmpRoot, "_run.bat");
33546
+ const tmpRoot = fs25.mkdtempSync(path28.join(tmpdir2(), "ba-devsrv-sh-"));
33547
+ const logPath = path28.join(tmpRoot, "combined.log");
33548
+ const runnerPath = path28.join(tmpRoot, "_run.bat");
33175
33549
  const q = (p) => `"${p.replace(/"/g, '""')}"`;
33176
33550
  const com = process.env.ComSpec || "cmd.exe";
33177
33551
  try {
33178
- fs24.writeFileSync(
33552
+ fs25.writeFileSync(
33179
33553
  runnerPath,
33180
33554
  `@ECHO OFF\r
33181
33555
  CD /D ${q(cwd)}\r
@@ -33944,30 +34318,30 @@ function createOnBridgeIdentified(opts) {
33944
34318
  }
33945
34319
 
33946
34320
  // src/skills/discover-local-agent-skills.ts
33947
- import fs25 from "node:fs";
33948
- import path28 from "node:path";
34321
+ import fs26 from "node:fs";
34322
+ import path29 from "node:path";
33949
34323
  var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
33950
34324
  function discoverLocalSkills(cwd) {
33951
34325
  const out = [];
33952
34326
  const seenKeys = /* @__PURE__ */ new Set();
33953
34327
  for (const rel of SKILL_DISCOVERY_ROOTS) {
33954
- const base = path28.join(cwd, rel);
33955
- if (!fs25.existsSync(base) || !fs25.statSync(base).isDirectory()) continue;
34328
+ const base = path29.join(cwd, rel);
34329
+ if (!fs26.existsSync(base) || !fs26.statSync(base).isDirectory()) continue;
33956
34330
  let entries = [];
33957
34331
  try {
33958
- entries = fs25.readdirSync(base);
34332
+ entries = fs26.readdirSync(base);
33959
34333
  } catch {
33960
34334
  continue;
33961
34335
  }
33962
34336
  for (const name of entries) {
33963
- const dir = path28.join(base, name);
34337
+ const dir = path29.join(base, name);
33964
34338
  try {
33965
- if (!fs25.statSync(dir).isDirectory()) continue;
34339
+ if (!fs26.statSync(dir).isDirectory()) continue;
33966
34340
  } catch {
33967
34341
  continue;
33968
34342
  }
33969
- const skillMd = path28.join(dir, "SKILL.md");
33970
- if (!fs25.existsSync(skillMd)) continue;
34343
+ const skillMd = path29.join(dir, "SKILL.md");
34344
+ if (!fs26.existsSync(skillMd)) continue;
33971
34345
  const key = `${rel}/${name}`;
33972
34346
  if (seenKeys.has(key)) continue;
33973
34347
  seenKeys.add(key);
@@ -33979,23 +34353,23 @@ function discoverLocalSkills(cwd) {
33979
34353
  function discoverSkillLayoutRoots(cwd) {
33980
34354
  const roots = [];
33981
34355
  for (const rel of SKILL_DISCOVERY_ROOTS) {
33982
- const base = path28.join(cwd, rel);
33983
- if (!fs25.existsSync(base) || !fs25.statSync(base).isDirectory()) continue;
34356
+ const base = path29.join(cwd, rel);
34357
+ if (!fs26.existsSync(base) || !fs26.statSync(base).isDirectory()) continue;
33984
34358
  let entries = [];
33985
34359
  try {
33986
- entries = fs25.readdirSync(base);
34360
+ entries = fs26.readdirSync(base);
33987
34361
  } catch {
33988
34362
  continue;
33989
34363
  }
33990
34364
  const skills2 = [];
33991
34365
  for (const name of entries) {
33992
- const dir = path28.join(base, name);
34366
+ const dir = path29.join(base, name);
33993
34367
  try {
33994
- if (!fs25.statSync(dir).isDirectory()) continue;
34368
+ if (!fs26.statSync(dir).isDirectory()) continue;
33995
34369
  } catch {
33996
34370
  continue;
33997
34371
  }
33998
- if (!fs25.existsSync(path28.join(dir, "SKILL.md"))) continue;
34372
+ if (!fs26.existsSync(path29.join(dir, "SKILL.md"))) continue;
33999
34373
  const relPath = `${rel}/${name}`.replace(/\\/g, "/");
34000
34374
  skills2.push({ name, relPath });
34001
34375
  }
@@ -34177,7 +34551,7 @@ var handleAgentConfigMessage = (msg, deps) => {
34177
34551
  };
34178
34552
 
34179
34553
  // src/prompt-turn-queue/runner.ts
34180
- import fs28 from "node:fs";
34554
+ import fs29 from "node:fs";
34181
34555
 
34182
34556
  // src/prompt-turn-queue/client-report.ts
34183
34557
  function sendPromptQueueClientReport(ws, queues) {
@@ -34187,13 +34561,13 @@ function sendPromptQueueClientReport(ws, queues) {
34187
34561
  }
34188
34562
 
34189
34563
  // src/prompt-turn-queue/disk-store.ts
34190
- import fs27 from "node:fs";
34564
+ import fs28 from "node:fs";
34191
34565
 
34192
34566
  // src/prompt-turn-queue/paths.ts
34193
34567
  import crypto3 from "node:crypto";
34194
- import fs26 from "node:fs";
34195
- import path29 from "node:path";
34196
- import os6 from "node:os";
34568
+ import fs27 from "node:fs";
34569
+ import path30 from "node:path";
34570
+ import os7 from "node:os";
34197
34571
  var QUEUE_KEY_HEX_64 = /^[a-f0-9]{64}$/i;
34198
34572
  function queueStateFileSlug(queueKey) {
34199
34573
  if (QUEUE_KEY_HEX_64.test(queueKey)) return queueKey.toLowerCase();
@@ -34201,15 +34575,15 @@ function queueStateFileSlug(queueKey) {
34201
34575
  }
34202
34576
  function getPromptQueuesDirectory() {
34203
34577
  const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
34204
- if (override) return path29.resolve(override);
34205
- return path29.join(os6.homedir(), ".buildautomaton", "queues");
34578
+ if (override) return path30.resolve(override);
34579
+ return path30.join(os7.homedir(), ".buildautomaton", "queues");
34206
34580
  }
34207
34581
  function ensurePromptQueuesDirectory() {
34208
34582
  const dir = getPromptQueuesDirectory();
34209
- if (!fs26.existsSync(dir)) fs26.mkdirSync(dir, { recursive: true });
34583
+ if (!fs27.existsSync(dir)) fs27.mkdirSync(dir, { recursive: true });
34210
34584
  }
34211
34585
  function queueStateFilePath(queueKey) {
34212
- return path29.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
34586
+ return path30.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
34213
34587
  }
34214
34588
 
34215
34589
  // src/prompt-turn-queue/disk-store.ts
@@ -34234,7 +34608,7 @@ function parsePersistedQueueFile(raw) {
34234
34608
  function readPersistedQueue(queueKey) {
34235
34609
  const p = queueStateFilePath(queueKey);
34236
34610
  try {
34237
- return parsePersistedQueueFile(fs27.readFileSync(p, "utf8"));
34611
+ return parsePersistedQueueFile(fs28.readFileSync(p, "utf8"));
34238
34612
  } catch {
34239
34613
  return null;
34240
34614
  }
@@ -34242,7 +34616,7 @@ function readPersistedQueue(queueKey) {
34242
34616
  function writePersistedQueue(file2) {
34243
34617
  ensurePromptQueuesDirectory();
34244
34618
  const p = queueStateFilePath(file2.queueKey);
34245
- fs27.writeFileSync(p, JSON.stringify(file2, null, 2), "utf8");
34619
+ fs28.writeFileSync(p, JSON.stringify(file2, null, 2), "utf8");
34246
34620
  }
34247
34621
  function mergeServerQueueSnapshot(queueKey, serverTurns) {
34248
34622
  const prev = readPersistedQueue(queueKey);
@@ -34300,7 +34674,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
34300
34674
  const tid = typeof pl.snapshotRevertTurnId === "string" && pl.snapshotRevertTurnId.trim() !== "" ? pl.snapshotRevertTurnId.trim() : next.turnId;
34301
34675
  const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
34302
34676
  const file2 = snapshotFilePath(agentBase, tid);
34303
- if (!fs28.existsSync(file2)) {
34677
+ if (!fs29.existsSync(file2)) {
34304
34678
  deps.log(
34305
34679
  `[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
34306
34680
  );
@@ -34523,9 +34897,9 @@ function parseChangeSummarySnapshots(raw) {
34523
34897
  for (const item of raw) {
34524
34898
  if (!item || typeof item !== "object") continue;
34525
34899
  const o = item;
34526
- const path34 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
34527
- if (!path34) continue;
34528
- const row = { path: path34 };
34900
+ const path35 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
34901
+ if (!path35) continue;
34902
+ const row = { path: path35 };
34529
34903
  if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
34530
34904
  if (typeof o.oldText === "string") row.oldText = o.oldText;
34531
34905
  if (typeof o.newText === "string") row.newText = o.newText;
@@ -34756,15 +35130,15 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
34756
35130
  };
34757
35131
 
34758
35132
  // src/files/list-dir.ts
34759
- import fs29 from "node:fs";
34760
- import path31 from "node:path";
35133
+ import fs30 from "node:fs";
35134
+ import path32 from "node:path";
34761
35135
 
34762
35136
  // src/files/ensure-under-cwd.ts
34763
- import path30 from "node:path";
35137
+ import path31 from "node:path";
34764
35138
  function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
34765
- const normalized = path30.normalize(relativePath).replace(/^(\.\/)+/, "");
34766
- const resolved = path30.resolve(cwd, normalized);
34767
- if (!resolved.startsWith(cwd + path30.sep) && resolved !== cwd) {
35139
+ const normalized = path31.normalize(relativePath).replace(/^(\.\/)+/, "");
35140
+ const resolved = path31.resolve(cwd, normalized);
35141
+ if (!resolved.startsWith(cwd + path31.sep) && resolved !== cwd) {
34768
35142
  return null;
34769
35143
  }
34770
35144
  return resolved;
@@ -34778,7 +35152,7 @@ async function listDirAsync(relativePath) {
34778
35152
  return { error: "Path is outside working directory" };
34779
35153
  }
34780
35154
  try {
34781
- const names = await fs29.promises.readdir(resolved, { withFileTypes: true });
35155
+ const names = await fs30.promises.readdir(resolved, { withFileTypes: true });
34782
35156
  const visible = names.filter((d) => !d.name.startsWith("."));
34783
35157
  const entries = [];
34784
35158
  for (let i = 0; i < visible.length; i++) {
@@ -34786,12 +35160,12 @@ async function listDirAsync(relativePath) {
34786
35160
  await yieldToEventLoop();
34787
35161
  }
34788
35162
  const d = visible[i];
34789
- const entryPath = path31.join(relativePath || ".", d.name).replace(/\\/g, "/");
34790
- const fullPath = path31.join(resolved, d.name);
35163
+ const entryPath = path32.join(relativePath || ".", d.name).replace(/\\/g, "/");
35164
+ const fullPath = path32.join(resolved, d.name);
34791
35165
  let isDir = d.isDirectory();
34792
35166
  if (d.isSymbolicLink()) {
34793
35167
  try {
34794
- const targetStat = await fs29.promises.stat(fullPath);
35168
+ const targetStat = await fs30.promises.stat(fullPath);
34795
35169
  isDir = targetStat.isDirectory();
34796
35170
  } catch {
34797
35171
  isDir = false;
@@ -34816,25 +35190,25 @@ async function listDirAsync(relativePath) {
34816
35190
  }
34817
35191
 
34818
35192
  // src/files/read-file.ts
34819
- import fs30 from "node:fs";
35193
+ import fs31 from "node:fs";
34820
35194
  import { StringDecoder } from "node:string_decoder";
34821
35195
  function resolveFilePath(relativePath) {
34822
35196
  const resolved = ensureUnderCwd(relativePath, getBridgeRoot());
34823
35197
  if (!resolved) return { error: "Path is outside working directory" };
34824
35198
  let real;
34825
35199
  try {
34826
- real = fs30.realpathSync(resolved);
35200
+ real = fs31.realpathSync(resolved);
34827
35201
  } catch {
34828
35202
  real = resolved;
34829
35203
  }
34830
- const stat2 = fs30.statSync(real);
35204
+ const stat2 = fs31.statSync(real);
34831
35205
  if (!stat2.isFile()) return { error: "Not a file" };
34832
35206
  return real;
34833
35207
  }
34834
35208
  var LINE_CHUNK_SIZE = 64 * 1024;
34835
35209
  function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
34836
- const fileSize = fs30.statSync(filePath).size;
34837
- const fd = fs30.openSync(filePath, "r");
35210
+ const fileSize = fs31.statSync(filePath).size;
35211
+ const fd = fs31.openSync(filePath, "r");
34838
35212
  const bufSize = 64 * 1024;
34839
35213
  const buf = Buffer.alloc(bufSize);
34840
35214
  const decoder = new StringDecoder("utf8");
@@ -34847,7 +35221,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
34847
35221
  let line0Accum = "";
34848
35222
  try {
34849
35223
  let bytesRead;
34850
- while (!done && (bytesRead = fs30.readSync(fd, buf, 0, bufSize, null)) > 0) {
35224
+ while (!done && (bytesRead = fs31.readSync(fd, buf, 0, bufSize, null)) > 0) {
34851
35225
  const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
34852
35226
  partial2 = "";
34853
35227
  let lineStart = 0;
@@ -34982,7 +35356,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
34982
35356
  }
34983
35357
  return { content: resultLines.join("\n"), size: fileSize };
34984
35358
  } finally {
34985
- fs30.closeSync(fd);
35359
+ fs31.closeSync(fd);
34986
35360
  }
34987
35361
  }
34988
35362
  function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
@@ -34993,8 +35367,8 @@ function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize =
34993
35367
  if (hasRange) {
34994
35368
  return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
34995
35369
  }
34996
- const stat2 = fs30.statSync(result);
34997
- const raw = fs30.readFileSync(result, "utf8");
35370
+ const stat2 = fs31.statSync(result);
35371
+ const raw = fs31.readFileSync(result, "utf8");
34998
35372
  const lines = raw.split(/\r?\n/);
34999
35373
  return { content: raw, totalLines: lines.length, size: stat2.size };
35000
35374
  } catch (err) {
@@ -35112,8 +35486,8 @@ function handleSkillLayoutRequest(msg, deps) {
35112
35486
  }
35113
35487
 
35114
35488
  // src/skills/install-remote-skills.ts
35115
- import fs31 from "node:fs";
35116
- import path32 from "node:path";
35489
+ import fs32 from "node:fs";
35490
+ import path33 from "node:path";
35117
35491
  function installRemoteSkills(cwd, targetDir, items) {
35118
35492
  const installed2 = [];
35119
35493
  if (!Array.isArray(items)) {
@@ -35124,15 +35498,15 @@ function installRemoteSkills(cwd, targetDir, items) {
35124
35498
  if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
35125
35499
  continue;
35126
35500
  }
35127
- const skillDir = path32.join(cwd, targetDir, item.skillName);
35501
+ const skillDir = path33.join(cwd, targetDir, item.skillName);
35128
35502
  for (const f of item.files) {
35129
35503
  if (typeof f.path !== "string" || !f.text && !f.base64) continue;
35130
- const dest = path32.join(skillDir, f.path);
35131
- fs31.mkdirSync(path32.dirname(dest), { recursive: true });
35504
+ const dest = path33.join(skillDir, f.path);
35505
+ fs32.mkdirSync(path33.dirname(dest), { recursive: true });
35132
35506
  if (f.text !== void 0) {
35133
- fs31.writeFileSync(dest, f.text, "utf8");
35507
+ fs32.writeFileSync(dest, f.text, "utf8");
35134
35508
  } else if (f.base64) {
35135
- fs31.writeFileSync(dest, Buffer.from(f.base64, "base64"));
35509
+ fs32.writeFileSync(dest, Buffer.from(f.base64, "base64"));
35136
35510
  }
35137
35511
  }
35138
35512
  installed2.push({
@@ -35282,7 +35656,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
35282
35656
  };
35283
35657
 
35284
35658
  // src/routing/handlers/revert-turn-snapshot.ts
35285
- import * as fs32 from "node:fs";
35659
+ import * as fs33 from "node:fs";
35286
35660
  var handleRevertTurnSnapshotMessage = (msg, deps) => {
35287
35661
  const id = typeof msg.id === "string" ? msg.id : "";
35288
35662
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
@@ -35294,7 +35668,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
35294
35668
  if (!s) return;
35295
35669
  const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
35296
35670
  const file2 = snapshotFilePath(agentBase, turnId);
35297
- if (!fs32.existsSync(file2)) {
35671
+ if (!fs33.existsSync(file2)) {
35298
35672
  sendWsMessage(s, {
35299
35673
  type: "revert_turn_snapshot_result",
35300
35674
  id,
@@ -35735,8 +36109,8 @@ async function createBridgeConnection(options) {
35735
36109
  getCloudAccessToken: () => tokens.accessToken
35736
36110
  };
35737
36111
  const identifyReportedPaths = {
35738
- bridgeRootPath: path33.resolve(getBridgeRoot()),
35739
- worktreesRootPath: path33.resolve(worktreesRootPath)
36112
+ bridgeRootPath: path34.resolve(getBridgeRoot()),
36113
+ worktreesRootPath: path34.resolve(worktreesRootPath)
35740
36114
  };
35741
36115
  const { connect } = createMainBridgeWebSocketLifecycle({
35742
36116
  state,