@buildautomaton/cli 0.1.24 → 0.1.25

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
  }
@@ -22640,253 +22943,259 @@ function getClaudePermissionModeFromAgentConfig(config2) {
22640
22943
  return isClaudeCodePermissionMode(t) ? t : null;
22641
22944
  }
22642
22945
 
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)));
22668
- }
22669
-
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";
22675
-
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]);
22946
+ // src/agents/acp/claude-acp-permission-from-session.ts
22947
+ function flattenSelectOptions(options) {
22948
+ if (options == null || options.length === 0) return [];
22949
+ const first2 = options[0];
22950
+ if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
22951
+ return options.flatMap(
22952
+ (g) => Array.isArray(g.options) ? g.options : []
22953
+ );
22954
+ }
22955
+ return options;
22956
+ }
22957
+ function pickModeConfigOption(configOptions) {
22958
+ if (configOptions == null || configOptions.length === 0) return null;
22959
+ const byCategory = configOptions.find((o) => o.category === "mode");
22960
+ if (byCategory) return byCategory;
22961
+ return configOptions.find((o) => o.id === "mode") ?? null;
22962
+ }
22963
+ async function applyClaudePermissionFromAcpSession(params) {
22964
+ const { sessionId, agentConfig, configOptions, modes, setSessionConfigOption, setSessionMode, logDebug: logDebug2 } = params;
22965
+ const desiredMode = getClaudePermissionModeFromAgentConfig(agentConfig);
22966
+ if (desiredMode == null) return;
22967
+ const modeOpt = pickModeConfigOption(configOptions ?? null);
22968
+ if (modeOpt != null) {
22969
+ const flat = flattenSelectOptions(modeOpt.options);
22970
+ const allowed = flat.some((o) => o.value === desiredMode);
22971
+ if (allowed && modeOpt.currentValue !== desiredMode) {
22972
+ try {
22973
+ logDebug2(
22974
+ `[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`
22975
+ );
22976
+ await setSessionConfigOption({ sessionId, configId: modeOpt.id, value: desiredMode });
22977
+ } catch (e) {
22978
+ logDebug2(
22979
+ `[Agent] Claude Code: session/set_config_option failed: ${e instanceof Error ? e.message : String(e)}`
22980
+ );
22690
22981
  }
22691
22982
  }
22983
+ return;
22692
22984
  }
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--;
22985
+ if (modes?.availableModes?.length) {
22986
+ const allowed = modes.availableModes.some((m) => m.id === desiredMode);
22987
+ if (allowed && desiredMode !== modes.currentModeId) {
22988
+ try {
22989
+ logDebug2(
22990
+ `[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`
22991
+ );
22992
+ await setSessionMode({ sessionId, modeId: desiredMode });
22993
+ } catch (e) {
22994
+ logDebug2(`[Agent] Claude Code: session/set_mode failed: ${e instanceof Error ? e.message : String(e)}`);
22995
+ }
22707
22996
  }
22708
22997
  }
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
22998
  }
22721
22999
 
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;
23000
+ // src/agents/acp/clients/shared/config-options-for-permission.ts
23001
+ function configOptionsForPermission(getActive, established) {
23002
+ const mem = getActive?.();
23003
+ if (Array.isArray(mem) && mem.length > 0) return mem;
23004
+ return established ?? void 0;
22730
23005
  }
22731
23006
 
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;
23007
+ // src/agents/acp/clients/shared/establish-acp-session.ts
23008
+ function establishedFromResult(raw, sessionId) {
23009
+ const r = raw && typeof raw === "object" ? raw : {};
23010
+ return {
23011
+ sessionId,
23012
+ configOptions: Array.isArray(r.configOptions) ? r.configOptions : null,
23013
+ modes: r.modes ?? null
23014
+ };
22742
23015
  }
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("/");
23016
+ function sessionIdFromNewSessionResult(raw) {
23017
+ const r = raw && typeof raw === "object" ? raw : {};
23018
+ return typeof r.sessionId === "string" ? r.sessionId : "";
22748
23019
  }
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) {
23020
+ async function establishAcpSessionWithTransport(transport, ctx, canResume, canLoad) {
23021
+ const { cwd, mcpServers, persistedAcpSessionId, agentLabel, suppressLoadReplay } = ctx;
23022
+ const prev = typeof persistedAcpSessionId === "string" && persistedAcpSessionId.trim() !== "" ? persistedAcpSessionId.trim() : "";
23023
+ if (prev) {
23024
+ if (canResume) {
22757
23025
  try {
22758
- process.stderr.write(chunk);
22759
- } catch {
23026
+ logDebug(`[Agent] ${agentLabel} ACP session/resume for stored session ${prev.slice(0, 8)}\u2026`);
23027
+ const result2 = await transport.resumeSession({ sessionId: prev, cwd, mcpServers });
23028
+ return establishedFromResult(result2, prev);
23029
+ } catch (e) {
23030
+ logDebug(`[Agent] ${agentLabel} ACP session/resume failed: ${e instanceof Error ? e.message : String(e)}`);
23031
+ }
23032
+ }
23033
+ if (canLoad) {
23034
+ suppressLoadReplay.value = true;
23035
+ try {
23036
+ logDebug(`[Agent] ${agentLabel} ACP session/load for stored session ${prev.slice(0, 8)}\u2026`);
23037
+ const result2 = await transport.loadSession({ sessionId: prev, cwd, mcpServers });
23038
+ return establishedFromResult(result2, prev);
23039
+ } catch (e) {
23040
+ logDebug(`[Agent] ${agentLabel} ACP session/load failed: ${e instanceof Error ? e.message : String(e)}`);
23041
+ } finally {
23042
+ suppressLoadReplay.value = false;
22760
23043
  }
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
23044
  }
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
23045
  }
23046
+ const result = await transport.newSession({ cwd, mcpServers });
23047
+ const sid = sessionIdFromNewSessionResult(result);
23048
+ if (!sid) throw new Error(`${agentLabel} ACP session/new did not return sessionId`);
23049
+ return establishedFromResult(result, sid);
22786
23050
  }
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}`;
23051
+
23052
+ // src/agents/acp/clients/shared/parse-acp-init-capabilities.ts
23053
+ function parseAcpInitAgentCapabilities(initResult) {
23054
+ const agentCapabilities = initResult?.agentCapabilities;
23055
+ const canLoad = agentCapabilities?.loadSession === true;
23056
+ const sessionCaps = agentCapabilities?.sessionCapabilities;
23057
+ const canResume = Boolean(sessionCaps?.resume);
23058
+ return { canResume, canLoad };
22795
23059
  }
22796
23060
 
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
- };
23061
+ // src/agents/acp/clients/shared/bootstrap-acp-wire-session.ts
23062
+ async function bootstrapAcpWireSession(transport, ctx, initializeRequest) {
23063
+ const initResult = await transport.initialize(initializeRequest);
23064
+ const { canResume, canLoad } = parseAcpInitAgentCapabilities(initResult);
23065
+ await transport.afterInitialize?.();
23066
+ const established = await establishAcpSessionWithTransport(transport, ctx, canResume, canLoad);
23067
+ const sessionId = established.sessionId;
23068
+ ctx.onAcpSessionEstablished?.({
23069
+ acpSessionId: sessionId,
23070
+ configOptions: established.configOptions,
23071
+ modes: established.modes
23072
+ });
23073
+ if (ctx.backendAgentType === "claude-code") {
23074
+ const cfg = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
23075
+ const configOptionsTyped = established.configOptions;
23076
+ const modesTyped = established.modes;
23077
+ await applyClaudePermissionFromAcpSession({
23078
+ sessionId,
23079
+ agentConfig: cfg,
23080
+ configOptions: configOptionsForPermission(ctx.getActiveConfigOptions, configOptionsTyped),
23081
+ modes: modesTyped,
23082
+ setSessionConfigOption: transport.setSessionConfigOption ? (p) => transport.setSessionConfigOption(p) : async () => {
23083
+ },
23084
+ setSessionMode: transport.setSessionMode ? (p) => transport.setSessionMode(p) : async () => {
23085
+ },
23086
+ logDebug: ctx.logDebug
23087
+ });
23088
+ }
23089
+ return established;
22812
23090
  }
22813
23091
 
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;
23092
+ // src/agents/acp/clients/shared/dispatch-session-update.ts
23093
+ function dispatchAcpSessionUpdate(opts) {
23094
+ const { flatPayload, onAcpConfigOptionsUpdated, onSessionUpdate, suppressLoadReplay } = opts;
23095
+ const su = flatPayload.sessionUpdate ?? flatPayload.session_update;
23096
+ if (su === "config_option_update") {
23097
+ const co = flatPayload.configOptions;
23098
+ if (Array.isArray(co)) onAcpConfigOptionsUpdated?.(co);
23099
+ return;
22824
23100
  }
23101
+ if (suppressLoadReplay()) return;
23102
+ onSessionUpdate?.(flatPayload);
22825
23103
  }
22826
23104
 
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 "";
23105
+ // src/agents/acp/clients/shared/flatten-sdk-session-notification.ts
23106
+ function flattenSdkSessionNotificationParams(params) {
23107
+ return { sessionId: params.sessionId, ...params.update };
22834
23108
  }
22835
- function enrichAcpPermissionRpcResultFromRequestParams(result, params) {
22836
- if (params == null || result == null || typeof result !== "object" || Array.isArray(result)) {
22837
- return result;
23109
+
23110
+ // src/agents/acp/clients/shared/normalize-acp-prompt-result.ts
23111
+ function normalizeAcpPromptTurnSuccess(opts) {
23112
+ const { stopReason, output, stderrCaptureText, backendAgentType } = opts;
23113
+ const mergedOutput = output || void 0;
23114
+ const stop = (stopReason ?? "").toLowerCase();
23115
+ const cancelled = stop === "cancelled";
23116
+ const refusal = stop === "refusal";
23117
+ const stderrEvaluated = Boolean(stderrCaptureText && backendAgentType);
23118
+ const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(backendAgentType, stderrCaptureText) : false;
23119
+ if (cancelled) {
23120
+ return {
23121
+ success: false,
23122
+ stopReason,
23123
+ output: mergedOutput,
23124
+ error: mergeErrorWithStderr("Stopped by user", stderrCaptureText)
23125
+ };
22838
23126
  }
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;
23127
+ if (refusal) {
23128
+ return {
23129
+ success: false,
23130
+ stopReason,
23131
+ output: mergedOutput,
23132
+ error: mergeErrorWithStderr("The agent refused the request.", stderrCaptureText)
23133
+ };
22845
23134
  }
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;
23135
+ if (stderrSuggestsAuth) {
23136
+ return {
23137
+ success: false,
23138
+ stopReason,
23139
+ output: mergedOutput,
23140
+ error: stderrCaptureText
23141
+ };
22850
23142
  }
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
- }
23143
+ return {
23144
+ success: true,
23145
+ stopReason,
23146
+ output: mergedOutput
23147
+ };
23148
+ }
23149
+ function normalizeAcpPromptTurnFailure(err, stderrCaptureText) {
23150
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrCaptureText);
23151
+ return { success: false, error: merged };
23152
+ }
23153
+
23154
+ // src/agents/acp/clients/shared/send-acp-prompt-via-transport.ts
23155
+ async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText) {
23156
+ try {
23157
+ const response = await transport.prompt({
23158
+ sessionId,
23159
+ prompt: [{ type: "text", text: promptText }]
23160
+ });
23161
+ await new Promise((r2) => setImmediate(r2));
23162
+ const r = response;
23163
+ return normalizeAcpPromptTurnSuccess({
23164
+ stopReason: r?.stopReason,
23165
+ output: r?.output,
23166
+ stderrCaptureText: ctx.getStderrText(),
23167
+ backendAgentType: ctx.backendAgentType
23168
+ });
23169
+ } catch (err) {
23170
+ await new Promise((r) => setImmediate(r));
23171
+ return normalizeAcpPromptTurnFailure(err, ctx.getStderrText());
22862
23172
  }
22863
- if (!matchedKind) return result;
23173
+ }
23174
+
23175
+ // src/agents/acp/clients/sdk/sdk-acp-session-transport.ts
23176
+ function createSdkAcpSessionTransport(connection) {
23177
+ const c = connection;
22864
23178
  return {
22865
- ...root,
22866
- outcome: {
22867
- ...o,
22868
- _meta: { ...prevMeta, [META_KEY]: matchedKind }
22869
- }
23179
+ initialize: (request) => c.initialize(request),
23180
+ resumeSession: (p) => c.unstable_resumeSession(p),
23181
+ loadSession: (p) => c.loadSession(p),
23182
+ newSession: (p) => c.newSession(p),
23183
+ prompt: (p) => c.prompt(p),
23184
+ cancelSession: async (sessionId) => {
23185
+ await c.cancel({ sessionId });
23186
+ },
23187
+ setSessionConfigOption: c.setSessionConfigOption ? (p) => c.setSessionConfigOption(p) : void 0,
23188
+ setSessionMode: c.setSessionMode ? (p) => c.setSessionMode(p) : void 0
22870
23189
  };
22871
23190
  }
22872
23191
 
22873
- // src/agents/acp/clients/sdk-stdio-acp-client.ts
23192
+ // src/agents/acp/clients/sdk/sdk-stdio-acp-client.ts
22874
23193
  function formatSpawnError(err, command) {
22875
23194
  if (err.code === "ENOENT") {
22876
23195
  return `Command "${command}" not found. Install the agent (e.g. Cursor CLI) or add it to PATH.`;
22877
23196
  }
22878
23197
  return err.message || String(err);
22879
23198
  }
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
23199
  async function createSdkStdioAcpClient(options) {
22891
23200
  const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
22892
23201
  const {
@@ -22898,7 +23207,11 @@ async function createSdkStdioAcpClient(options) {
22898
23207
  onFileChange,
22899
23208
  killSubprocessAfterCancelMs,
22900
23209
  onAgentSubprocessExit,
22901
- agentConfig
23210
+ agentConfig,
23211
+ persistedAcpSessionId,
23212
+ onAcpSessionEstablished,
23213
+ onAcpConfigOptionsUpdated,
23214
+ getActiveConfigOptions
22902
23215
  } = options;
22903
23216
  const isWindows = process.platform === "win32";
22904
23217
  const child = spawn(command[0], command.slice(1), {
@@ -22947,6 +23260,22 @@ async function createSdkStdioAcpClient(options) {
22947
23260
  backendAgentType,
22948
23261
  onSessionUpdate
22949
23262
  });
23263
+ const suppressLoadReplayRef = { value: false };
23264
+ const sessionCtx = {
23265
+ cwd,
23266
+ onFileChange,
23267
+ mcpServers: [],
23268
+ persistedAcpSessionId,
23269
+ agentLabel: "ACP",
23270
+ suppressLoadReplay: suppressLoadReplayRef,
23271
+ backendAgentType: backendAgentType ?? null,
23272
+ agentConfig,
23273
+ getActiveConfigOptions,
23274
+ onAcpSessionEstablished,
23275
+ onAcpConfigOptionsUpdated,
23276
+ logDebug,
23277
+ getStderrText: () => stderrCapture.getText()
23278
+ };
22950
23279
  let permissionSeq = 0;
22951
23280
  const pendingPermissionReplies = /* @__PURE__ */ new Map();
22952
23281
  const client = (_agent) => ({
@@ -22966,35 +23295,19 @@ async function createSdkStdioAcpClient(options) {
22966
23295
  });
22967
23296
  },
22968
23297
  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
- }
23298
+ return acpReadTextFileInProcess(sessionCtx, params.path, params.line, params.limit);
22979
23299
  },
22980
23300
  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 {};
23301
+ return acpWriteTextFileInProcess(sessionCtx, params.path, params.content);
22995
23302
  },
22996
23303
  async sessionUpdate(params) {
22997
- onSessionUpdate?.(bridgePayloadFromSdkSessionNotification(params));
23304
+ const bridged = flattenSdkSessionNotificationParams(params);
23305
+ dispatchAcpSessionUpdate({
23306
+ flatPayload: bridged,
23307
+ onAcpConfigOptionsUpdated: sessionCtx.onAcpConfigOptionsUpdated,
23308
+ onSessionUpdate,
23309
+ suppressLoadReplay: () => sessionCtx.suppressLoadReplay.value
23310
+ });
22998
23311
  },
22999
23312
  async extNotification(method, params) {
23000
23313
  await extNotification(method, params);
@@ -23004,84 +23317,19 @@ async function createSdkStdioAcpClient(options) {
23004
23317
  connection.signal.addEventListener("abort", () => {
23005
23318
  child.kill();
23006
23319
  });
23007
- await connection.initialize({
23320
+ const transport = createSdkAcpSessionTransport(connection);
23321
+ const established = await bootstrapAcpWireSession(transport, sessionCtx, {
23008
23322
  protocolVersion: PROTOCOL_VERSION2,
23009
23323
  clientCapabilities: {
23010
23324
  fs: { readTextFile: true, writeTextFile: true }
23011
23325
  },
23012
23326
  clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
23013
23327
  });
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
- }
23328
+ const sessionId = established.sessionId;
23030
23329
  settleResolve({
23031
23330
  sessionId,
23032
23331
  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
- }
23332
+ return sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt);
23085
23333
  },
23086
23334
  async cancel() {
23087
23335
  for (const [id, entry] of [...pendingPermissionReplies.entries()]) {
@@ -23089,7 +23337,7 @@ async function createSdkStdioAcpClient(options) {
23089
23337
  entry.resolve({ outcome: { outcome: "cancelled" } });
23090
23338
  }
23091
23339
  try {
23092
- await connection.cancel({ sessionId });
23340
+ await transport.cancelSession(sessionId);
23093
23341
  } catch {
23094
23342
  }
23095
23343
  if (killSubprocessAfterCancelMs != null && killSubprocessAfterCancelMs >= 0) {
@@ -23315,8 +23563,8 @@ function randomSecret() {
23315
23563
  }
23316
23564
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
23317
23565
  }
23318
- async function requestPreviewApi(port, secret, method, path34, body) {
23319
- const url2 = `http://127.0.0.1:${port}${path34}`;
23566
+ async function requestPreviewApi(port, secret, method, path35, body) {
23567
+ const url2 = `http://127.0.0.1:${port}${path35}`;
23320
23568
  const headers = {
23321
23569
  [PREVIEW_SECRET_HEADER]: secret,
23322
23570
  "Content-Type": "application/json"
@@ -23328,7 +23576,7 @@ async function requestPreviewApi(port, secret, method, path34, body) {
23328
23576
  });
23329
23577
  const data = await res.json().catch(() => ({}));
23330
23578
  if (!res.ok) {
23331
- throw new Error(data?.error ?? `Preview API ${method} ${path34}: ${res.status}`);
23579
+ throw new Error(data?.error ?? `Preview API ${method} ${path35}: ${res.status}`);
23332
23580
  }
23333
23581
  return data;
23334
23582
  }
@@ -23471,40 +23719,6 @@ async function callSkill(skillId, operationId, params) {
23471
23719
  return skill.execute(operationId, params);
23472
23720
  }
23473
23721
 
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
23722
  // src/config.ts
23509
23723
  import fs from "node:fs";
23510
23724
  import path3 from "node:path";
@@ -23577,7 +23791,7 @@ function installBridgeProcessResilience() {
23577
23791
  }
23578
23792
 
23579
23793
  // src/cli-version.ts
23580
- var CLI_VERSION = "0.1.24".length > 0 ? "0.1.24" : "0.0.0-dev";
23794
+ var CLI_VERSION = "0.1.25".length > 0 ? "0.1.25" : "0.0.0-dev";
23581
23795
 
23582
23796
  // ../../node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
23583
23797
  import process7 from "node:process";
@@ -24741,8 +24955,8 @@ function pathspec(...paths) {
24741
24955
  cache.set(key, paths);
24742
24956
  return key;
24743
24957
  }
24744
- function isPathSpec(path34) {
24745
- return path34 instanceof String && cache.has(path34);
24958
+ function isPathSpec(path35) {
24959
+ return path35 instanceof String && cache.has(path35);
24746
24960
  }
24747
24961
  function toPaths(pathSpec) {
24748
24962
  return cache.get(pathSpec) || [];
@@ -24831,8 +25045,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
24831
25045
  function forEachLineWithContent(input, callback) {
24832
25046
  return toLinesWithContent(input, true).map((line) => callback(line));
24833
25047
  }
24834
- function folderExists(path34) {
24835
- return (0, import_file_exists.exists)(path34, import_file_exists.FOLDER);
25048
+ function folderExists(path35) {
25049
+ return (0, import_file_exists.exists)(path35, import_file_exists.FOLDER);
24836
25050
  }
24837
25051
  function append(target, item) {
24838
25052
  if (Array.isArray(target)) {
@@ -25236,8 +25450,8 @@ function checkIsRepoRootTask() {
25236
25450
  commands,
25237
25451
  format: "utf-8",
25238
25452
  onError,
25239
- parser(path34) {
25240
- return /^\.(git)?$/.test(path34.trim());
25453
+ parser(path35) {
25454
+ return /^\.(git)?$/.test(path35.trim());
25241
25455
  }
25242
25456
  };
25243
25457
  }
@@ -25671,11 +25885,11 @@ function parseGrep(grep) {
25671
25885
  const paths = /* @__PURE__ */ new Set();
25672
25886
  const results = {};
25673
25887
  forEachLineWithContent(grep, (input) => {
25674
- const [path34, line, preview] = input.split(NULL);
25675
- paths.add(path34);
25676
- (results[path34] = results[path34] || []).push({
25888
+ const [path35, line, preview] = input.split(NULL);
25889
+ paths.add(path35);
25890
+ (results[path35] = results[path35] || []).push({
25677
25891
  line: asNumber(line),
25678
- path: path34,
25892
+ path: path35,
25679
25893
  preview
25680
25894
  });
25681
25895
  });
@@ -26440,14 +26654,14 @@ var init_hash_object = __esm2({
26440
26654
  init_task();
26441
26655
  }
26442
26656
  });
26443
- function parseInit(bare, path34, text) {
26657
+ function parseInit(bare, path35, text) {
26444
26658
  const response = String(text).trim();
26445
26659
  let result;
26446
26660
  if (result = initResponseRegex.exec(response)) {
26447
- return new InitSummary(bare, path34, false, result[1]);
26661
+ return new InitSummary(bare, path35, false, result[1]);
26448
26662
  }
26449
26663
  if (result = reInitResponseRegex.exec(response)) {
26450
- return new InitSummary(bare, path34, true, result[1]);
26664
+ return new InitSummary(bare, path35, true, result[1]);
26451
26665
  }
26452
26666
  let gitDir = "";
26453
26667
  const tokens = response.split(" ");
@@ -26458,7 +26672,7 @@ function parseInit(bare, path34, text) {
26458
26672
  break;
26459
26673
  }
26460
26674
  }
26461
- return new InitSummary(bare, path34, /^re/i.test(response), gitDir);
26675
+ return new InitSummary(bare, path35, /^re/i.test(response), gitDir);
26462
26676
  }
26463
26677
  var InitSummary;
26464
26678
  var initResponseRegex;
@@ -26467,9 +26681,9 @@ var init_InitSummary = __esm2({
26467
26681
  "src/lib/responses/InitSummary.ts"() {
26468
26682
  "use strict";
26469
26683
  InitSummary = class {
26470
- constructor(bare, path34, existing, gitDir) {
26684
+ constructor(bare, path35, existing, gitDir) {
26471
26685
  this.bare = bare;
26472
- this.path = path34;
26686
+ this.path = path35;
26473
26687
  this.existing = existing;
26474
26688
  this.gitDir = gitDir;
26475
26689
  }
@@ -26481,7 +26695,7 @@ var init_InitSummary = __esm2({
26481
26695
  function hasBareCommand(command) {
26482
26696
  return command.includes(bareCommand);
26483
26697
  }
26484
- function initTask(bare = false, path34, customArgs) {
26698
+ function initTask(bare = false, path35, customArgs) {
26485
26699
  const commands = ["init", ...customArgs];
26486
26700
  if (bare && !hasBareCommand(commands)) {
26487
26701
  commands.splice(1, 0, bareCommand);
@@ -26490,7 +26704,7 @@ function initTask(bare = false, path34, customArgs) {
26490
26704
  commands,
26491
26705
  format: "utf-8",
26492
26706
  parser(text) {
26493
- return parseInit(commands.includes("--bare"), path34, text);
26707
+ return parseInit(commands.includes("--bare"), path35, text);
26494
26708
  }
26495
26709
  };
26496
26710
  }
@@ -27306,12 +27520,12 @@ var init_FileStatusSummary = __esm2({
27306
27520
  "use strict";
27307
27521
  fromPathRegex = /^(.+)\0(.+)$/;
27308
27522
  FileStatusSummary = class {
27309
- constructor(path34, index, working_dir) {
27310
- this.path = path34;
27523
+ constructor(path35, index, working_dir) {
27524
+ this.path = path35;
27311
27525
  this.index = index;
27312
27526
  this.working_dir = working_dir;
27313
27527
  if (index === "R" || working_dir === "R") {
27314
- const detail = fromPathRegex.exec(path34) || [null, path34, path34];
27528
+ const detail = fromPathRegex.exec(path35) || [null, path35, path35];
27315
27529
  this.from = detail[2] || "";
27316
27530
  this.path = detail[1] || "";
27317
27531
  }
@@ -27342,14 +27556,14 @@ function splitLine(result, lineStr) {
27342
27556
  default:
27343
27557
  return;
27344
27558
  }
27345
- function data(index, workingDir, path34) {
27559
+ function data(index, workingDir, path35) {
27346
27560
  const raw = `${index}${workingDir}`;
27347
27561
  const handler = parsers6.get(raw);
27348
27562
  if (handler) {
27349
- handler(result, path34);
27563
+ handler(result, path35);
27350
27564
  }
27351
27565
  if (raw !== "##" && raw !== "!!") {
27352
- result.files.push(new FileStatusSummary(path34, index, workingDir));
27566
+ result.files.push(new FileStatusSummary(path35, index, workingDir));
27353
27567
  }
27354
27568
  }
27355
27569
  }
@@ -27658,9 +27872,9 @@ var init_simple_git_api = __esm2({
27658
27872
  next
27659
27873
  );
27660
27874
  }
27661
- hashObject(path34, write) {
27875
+ hashObject(path35, write) {
27662
27876
  return this._runTask(
27663
- hashObjectTask(path34, write === true),
27877
+ hashObjectTask(path35, write === true),
27664
27878
  trailingFunctionArgument(arguments)
27665
27879
  );
27666
27880
  }
@@ -28013,8 +28227,8 @@ var init_branch = __esm2({
28013
28227
  }
28014
28228
  });
28015
28229
  function toPath(input) {
28016
- const path34 = input.trim().replace(/^["']|["']$/g, "");
28017
- return path34 && normalize2(path34);
28230
+ const path35 = input.trim().replace(/^["']|["']$/g, "");
28231
+ return path35 && normalize2(path35);
28018
28232
  }
28019
28233
  var parseCheckIgnore;
28020
28234
  var init_CheckIgnore = __esm2({
@@ -28328,8 +28542,8 @@ __export2(sub_module_exports, {
28328
28542
  subModuleTask: () => subModuleTask,
28329
28543
  updateSubModuleTask: () => updateSubModuleTask
28330
28544
  });
28331
- function addSubModuleTask(repo, path34) {
28332
- return subModuleTask(["add", repo, path34]);
28545
+ function addSubModuleTask(repo, path35) {
28546
+ return subModuleTask(["add", repo, path35]);
28333
28547
  }
28334
28548
  function initSubModuleTask(customArgs) {
28335
28549
  return subModuleTask(["init", ...customArgs]);
@@ -28662,8 +28876,8 @@ var require_git = __commonJS2({
28662
28876
  }
28663
28877
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
28664
28878
  };
28665
- Git2.prototype.submoduleAdd = function(repo, path34, then) {
28666
- return this._runTask(addSubModuleTask2(repo, path34), trailingFunctionArgument2(arguments));
28879
+ Git2.prototype.submoduleAdd = function(repo, path35, then) {
28880
+ return this._runTask(addSubModuleTask2(repo, path35), trailingFunctionArgument2(arguments));
28667
28881
  };
28668
28882
  Git2.prototype.submoduleUpdate = function(args, then) {
28669
28883
  return this._runTask(
@@ -29550,9 +29764,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
29550
29764
  // src/agents/acp/put-summarize-change-summaries.ts
29551
29765
  async function putEncryptedChangeSummaryRows(params) {
29552
29766
  const base = params.apiBaseUrl.replace(/\/+$/, "");
29553
- const entries = params.rows.map(({ path: path34, summary }) => {
29767
+ const entries = params.rows.map(({ path: path35, summary }) => {
29554
29768
  const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
29555
- return { path: path34, summary: JSON.stringify(enc) };
29769
+ return { path: path35, summary: JSON.stringify(enc) };
29556
29770
  });
29557
29771
  const res = await fetch(
29558
29772
  `${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
@@ -29734,8 +29948,8 @@ async function sendPromptToAgent(options) {
29734
29948
  }
29735
29949
 
29736
29950
  // src/agents/acp/ensure-acp-client.ts
29737
- import * as fs9 from "node:fs";
29738
- import * as path11 from "node:path";
29951
+ import * as fs10 from "node:fs";
29952
+ import * as path12 from "node:path";
29739
29953
 
29740
29954
  // src/error-message.ts
29741
29955
  function errorMessage(err) {
@@ -29825,7 +30039,7 @@ async function createCodexAcpClient(options) {
29825
30039
  return createSdkStdioAcpClient({ ...options, command });
29826
30040
  }
29827
30041
 
29828
- // src/agents/acp/clients/cursor-acp-client.ts
30042
+ // src/agents/acp/clients/cursor/cursor-acp-client.ts
29829
30043
  var cursor_acp_client_exports = {};
29830
30044
  __export(cursor_acp_client_exports, {
29831
30045
  BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE3,
@@ -29833,8 +30047,6 @@ __export(cursor_acp_client_exports, {
29833
30047
  createCursorAcpClient: () => createCursorAcpClient,
29834
30048
  detectLocalAgentPresence: () => detectLocalAgentPresence3
29835
30049
  });
29836
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
29837
- import { dirname as dirname3 } from "node:path";
29838
30050
  import { spawn as spawn4 } from "node:child_process";
29839
30051
  import * as readline from "node:readline";
29840
30052
 
@@ -29851,7 +30063,23 @@ function formatSessionUpdateKindForLog(kind) {
29851
30063
  return kind.split("_").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
29852
30064
  }
29853
30065
 
29854
- // src/agents/acp/clients/cursor-acp-client.ts
30066
+ // src/agents/acp/clients/cursor/cursor-json-rpc-acp-transport.ts
30067
+ function createCursorJsonRpcAcpTransport(deps) {
30068
+ const { send, cancelSessionNotification } = deps;
30069
+ return {
30070
+ initialize: (request) => send("initialize", request),
30071
+ afterInitialize: async () => {
30072
+ await send("authenticate", { methodId: "cursor_login" });
30073
+ },
30074
+ resumeSession: (p) => send("session/resume", p),
30075
+ loadSession: (p) => send("session/load", p),
30076
+ newSession: (p) => send("session/new", p),
30077
+ prompt: (p) => send("session/prompt", p),
30078
+ cancelSession: (sessionId) => cancelSessionNotification(sessionId)
30079
+ };
30080
+ }
30081
+
30082
+ // src/agents/acp/clients/cursor/cursor-acp-client.ts
29855
30083
  var FS_READ_METHODS = /* @__PURE__ */ new Set(["fs/read_text_file", "fs/readTextFile"]);
29856
30084
  var FS_WRITE_METHODS = /* @__PURE__ */ new Set(["fs/write_text_file", "fs/writeTextFile"]);
29857
30085
  function formatSpawnError2(err, command) {
@@ -29868,13 +30096,6 @@ function safeJsonParse(value) {
29868
30096
  return null;
29869
30097
  }
29870
30098
  }
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
30099
  function buildCursorAcpSpawnCommand(base, sessionMode) {
29879
30100
  if (!sessionMode) return [...base];
29880
30101
  const m = sessionMode.trim();
@@ -29888,7 +30109,11 @@ async function createCursorAcpClient(options) {
29888
30109
  backendAgentType,
29889
30110
  onSessionUpdate,
29890
30111
  onRequest,
29891
- onFileChange
30112
+ onFileChange,
30113
+ persistedAcpSessionId,
30114
+ onAcpSessionEstablished,
30115
+ onAcpConfigOptionsUpdated,
30116
+ onAgentSubprocessExit
29892
30117
  } = options;
29893
30118
  const dbgFs = process.env.BUILDAUTOMATON_DEBUG_ACP_FS === "1";
29894
30119
  const isWindows = process.platform === "win32";
@@ -29900,6 +30125,25 @@ async function createCursorAcpClient(options) {
29900
30125
  });
29901
30126
  const stderrCapture = createStderrCapture(child);
29902
30127
  child.stderr?.on("data", (chunk) => stderrCapture.append(chunk));
30128
+ child.once("close", (code, signal) => {
30129
+ onAgentSubprocessExit?.({ code, signal });
30130
+ });
30131
+ const suppressLoadReplayRef = { value: false };
30132
+ const sessionCtx = {
30133
+ cwd,
30134
+ onFileChange,
30135
+ mcpServers: [],
30136
+ persistedAcpSessionId,
30137
+ agentLabel: "Cursor",
30138
+ suppressLoadReplay: suppressLoadReplayRef,
30139
+ backendAgentType: backendAgentType ?? null,
30140
+ agentConfig: options.agentConfig,
30141
+ getActiveConfigOptions: options.getActiveConfigOptions,
30142
+ onAcpSessionEstablished,
30143
+ onAcpConfigOptionsUpdated,
30144
+ logDebug,
30145
+ getStderrText: () => stderrCapture.getText()
30146
+ };
29903
30147
  return new Promise((resolve16, reject) => {
29904
30148
  child.on("error", (err) => {
29905
30149
  child.kill();
@@ -29908,6 +30152,16 @@ async function createCursorAcpClient(options) {
29908
30152
  let nextId = 1;
29909
30153
  const pending = /* @__PURE__ */ new Map();
29910
30154
  const pendingRequests = /* @__PURE__ */ new Map();
30155
+ function cancelSessionNotification(sessionId) {
30156
+ const line = JSON.stringify({
30157
+ jsonrpc: "2.0",
30158
+ method: "session/cancel",
30159
+ params: { sessionId }
30160
+ }) + "\n";
30161
+ return new Promise((res, rej) => {
30162
+ child.stdin.write(line, (err) => err ? rej(err) : res());
30163
+ });
30164
+ }
29911
30165
  function send(method, params) {
29912
30166
  const id = nextId++;
29913
30167
  const line = JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n";
@@ -29931,7 +30185,6 @@ async function createCursorAcpClient(options) {
29931
30185
  respond(requestId, payload);
29932
30186
  pendingRequests.delete(requestId);
29933
30187
  }
29934
- let promptOutputBuffer = "";
29935
30188
  const rl = readline.createInterface({ input: child.stdout });
29936
30189
  rl.on("line", (line) => {
29937
30190
  const msg = safeJsonParse(line);
@@ -29960,11 +30213,12 @@ async function createCursorAcpClient(options) {
29960
30213
  `[acp] Received session update (${kindLabel}) tool=${toolName || "(none)"}`
29961
30214
  );
29962
30215
  }
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);
30216
+ dispatchAcpSessionUpdate({
30217
+ flatPayload: update,
30218
+ onAcpConfigOptionsUpdated: sessionCtx.onAcpConfigOptionsUpdated,
30219
+ onSessionUpdate,
30220
+ suppressLoadReplay: () => sessionCtx.suppressLoadReplay.value
30221
+ });
29968
30222
  return;
29969
30223
  }
29970
30224
  if (method === "session/request_permission" && typeof id === "number") {
@@ -29984,21 +30238,13 @@ async function createCursorAcpClient(options) {
29984
30238
  if (dbgFs) {
29985
30239
  console.error(`[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""}`);
29986
30240
  }
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
30241
  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 });
30242
+ const lineNum = typeof params.line === "number" ? params.line : void 0;
30243
+ const limitNum = typeof params.limit === "number" ? params.limit : void 0;
30244
+ const out = acpReadTextFileInProcess(sessionCtx, filePath, lineNum, limitNum);
30245
+ respond(id, out);
29999
30246
  } catch (e) {
30000
- const code = e?.code;
30001
- if (code === "ENOENT") {
30247
+ if (e?.code === "ENOENT") {
30002
30248
  respond(id, { content: "" });
30003
30249
  } else {
30004
30250
  respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
@@ -30015,32 +30261,17 @@ async function createCursorAcpClient(options) {
30015
30261
  `[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""} newBytes=${newText.length}`
30016
30262
  );
30017
30263
  }
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
30264
  try {
30026
- oldText = readFileSync3(resolvedPath, "utf8");
30265
+ acpWriteTextFileInProcess(sessionCtx, filePath, newText);
30266
+ respond(id, null);
30027
30267
  } catch (e) {
30028
- if (e.code !== "ENOENT") {
30268
+ if (e.message === "Invalid or disallowed path") {
30269
+ if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty): ${filePath.slice(0, 120)}`);
30270
+ respondJsonRpcError(id, -32602, "Invalid or disallowed path");
30271
+ } else {
30029
30272
  respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
30030
- return;
30031
30273
  }
30032
30274
  }
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
30275
  return;
30045
30276
  }
30046
30277
  if (method === "cursor/create_plan" || method === "cursor/ask_question") {
@@ -30062,16 +30293,7 @@ async function createCursorAcpClient(options) {
30062
30293
  });
30063
30294
  (async () => {
30064
30295
  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() {
30296
+ let cancelPendingPermissionRequests2 = function() {
30075
30297
  for (const [reqId, pending2] of [...pendingRequests.entries()]) {
30076
30298
  if (pending2.method === "session/request_permission") {
30077
30299
  respond(reqId, { outcome: { outcome: "cancelled" } });
@@ -30079,76 +30301,25 @@ async function createCursorAcpClient(options) {
30079
30301
  }
30080
30302
  }
30081
30303
  };
30082
- var sendSessionCancelNotification = sendSessionCancelNotification2, cancelPendingPermissionRequests = cancelPendingPermissionRequests2;
30083
- await send("initialize", {
30304
+ var cancelPendingPermissionRequests = cancelPendingPermissionRequests2;
30305
+ const transport = createCursorJsonRpcAcpTransport({
30306
+ send,
30307
+ cancelSessionNotification
30308
+ });
30309
+ const established = await bootstrapAcpWireSession(transport, sessionCtx, {
30084
30310
  protocolVersion: 1,
30085
30311
  clientCapabilities: { fs: { readTextFile: true, writeTextFile: true }, terminal: false },
30086
30312
  clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
30087
30313
  });
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");
30314
+ const sessionId = established.sessionId;
30092
30315
  resolve16({
30093
30316
  sessionId,
30094
30317
  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
- }
30318
+ return sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt);
30148
30319
  },
30149
30320
  async cancel() {
30150
30321
  cancelPendingPermissionRequests2();
30151
- await sendSessionCancelNotification2();
30322
+ await transport.cancelSession(sessionId);
30152
30323
  },
30153
30324
  resolveRequest(requestId, result) {
30154
30325
  const numericId = Number(requestId);
@@ -30296,7 +30467,7 @@ function getGitRepoRootSync(startDir) {
30296
30467
 
30297
30468
  // src/agents/acp/workspace-files.ts
30298
30469
  import { execFileSync as execFileSync3 } from "node:child_process";
30299
- import { readFileSync as readFileSync4 } from "node:fs";
30470
+ import { readFileSync as readFileSync3 } from "node:fs";
30300
30471
  import * as path10 from "node:path";
30301
30472
  function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
30302
30473
  const trimmed2 = rawPath.trim();
@@ -30328,7 +30499,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
30328
30499
  const rel = path10.relative(gitRoot, resolvedPath2);
30329
30500
  if (!rel.startsWith("..") && !path10.isAbsolute(rel)) {
30330
30501
  try {
30331
- return readFileSync4(resolvedPath2, "utf8");
30502
+ return readFileSync3(resolvedPath2, "utf8");
30332
30503
  } catch {
30333
30504
  }
30334
30505
  }
@@ -30336,7 +30507,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
30336
30507
  const resolvedPath = resolveSafePathUnderCwd(sessionParentPath, displayPath);
30337
30508
  if (!resolvedPath) return "";
30338
30509
  try {
30339
- return readFileSync4(resolvedPath, "utf8");
30510
+ return readFileSync3(resolvedPath, "utf8");
30340
30511
  } catch {
30341
30512
  return "";
30342
30513
  }
@@ -30840,6 +31011,9 @@ function createBridgeOnSessionUpdate(opts) {
30840
31011
  const sentFileChangePaths = /* @__PURE__ */ new Set();
30841
31012
  const p = params;
30842
31013
  const updateKind = p.sessionUpdate ?? p.session_update ?? p.type ?? "update";
31014
+ if (updateKind === "config_option_update") {
31015
+ return;
31016
+ }
30843
31017
  const isCompletedToolCallUpdate = updateKind === "tool_call_update" && isCompletedToolStatus(p.status);
30844
31018
  const toolName = p.toolCall?.name ?? p.tool_call?.name ?? "";
30845
31019
  const isToolUpdate = updateKind === "tool_call" || updateKind === "tool_call_update" || typeof toolName === "string" && toolName.length > 0;
@@ -30926,14 +31100,72 @@ function buildAcpSessionBridgeHooks(opts) {
30926
31100
  };
30927
31101
  }
30928
31102
 
31103
+ // src/agents/acp/local-agent-session-file.ts
31104
+ import fs9 from "node:fs";
31105
+ import os3 from "node:os";
31106
+ import path11 from "node:path";
31107
+ var LOCAL_AGENT_SESSION_DIR = path11.join(os3.homedir(), ".buildautomaton", "agent-sessions");
31108
+ function safeFileSlug(cloudSessionId) {
31109
+ const t = cloudSessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
31110
+ return t.length > 0 ? t : "session";
31111
+ }
31112
+ function localAgentSessionFilePath(cloudSessionId) {
31113
+ return path11.join(LOCAL_AGENT_SESSION_DIR, `${safeFileSlug(cloudSessionId)}.json`);
31114
+ }
31115
+ function readLocalAgentSessionFile(cloudSessionId) {
31116
+ try {
31117
+ const p = localAgentSessionFilePath(cloudSessionId);
31118
+ const raw = fs9.readFileSync(p, "utf8");
31119
+ const parsed = JSON.parse(raw);
31120
+ if (parsed.v !== 1) return null;
31121
+ return {
31122
+ v: 1,
31123
+ acpSessionId: typeof parsed.acpSessionId === "string" ? parsed.acpSessionId : null,
31124
+ backendAgentType: typeof parsed.backendAgentType === "string" ? parsed.backendAgentType : null,
31125
+ configOptions: Array.isArray(parsed.configOptions) ? parsed.configOptions : null,
31126
+ updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString()
31127
+ };
31128
+ } catch {
31129
+ return null;
31130
+ }
31131
+ }
31132
+ function writeLocalAgentSessionFile(cloudSessionId, patch) {
31133
+ try {
31134
+ const dir = LOCAL_AGENT_SESSION_DIR;
31135
+ if (!fs9.existsSync(dir)) fs9.mkdirSync(dir, { recursive: true });
31136
+ const p = localAgentSessionFilePath(cloudSessionId);
31137
+ const prev = readLocalAgentSessionFile(cloudSessionId);
31138
+ const next = {
31139
+ v: 1,
31140
+ acpSessionId: patch.acpSessionId !== void 0 ? patch.acpSessionId : prev?.acpSessionId ?? null,
31141
+ backendAgentType: patch.backendAgentType !== void 0 ? patch.backendAgentType : prev?.backendAgentType ?? null,
31142
+ configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
31143
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
31144
+ };
31145
+ fs9.writeFileSync(p, JSON.stringify(next, null, 2), "utf8");
31146
+ } catch {
31147
+ }
31148
+ }
31149
+
30929
31150
  // src/agents/acp/ensure-acp-client.ts
30930
31151
  async function ensureAcpClient(options) {
30931
- const { state, preferredAgentType, mode, agentConfig, sessionParentPath, routing, sendSessionUpdate, sendRequest, log: log2 } = options;
31152
+ const {
31153
+ state,
31154
+ preferredAgentType,
31155
+ mode,
31156
+ agentConfig,
31157
+ sessionParentPath,
31158
+ routing,
31159
+ cloudSessionId,
31160
+ sendSessionUpdate,
31161
+ sendRequest,
31162
+ log: log2
31163
+ } = options;
30932
31164
  const targetSessionParentPath = resolveSessionParentPathForAgentProcess(sessionParentPath);
30933
31165
  if (state.acpStartPromise && !state.acpHandle) {
30934
31166
  await state.acpStartPromise;
30935
31167
  }
30936
- if (state.acpHandle && state.lastAcpCwd != null && path11.resolve(state.lastAcpCwd) !== path11.resolve(targetSessionParentPath)) {
31168
+ if (state.acpHandle && state.lastAcpCwd != null && path12.resolve(state.lastAcpCwd) !== path12.resolve(targetSessionParentPath)) {
30937
31169
  try {
30938
31170
  state.acpHandle.disconnect();
30939
31171
  } catch {
@@ -30941,6 +31173,7 @@ async function ensureAcpClient(options) {
30941
31173
  state.acpHandle = null;
30942
31174
  state.acpStartPromise = null;
30943
31175
  state.acpAgentKey = null;
31176
+ state.activeSessionConfigOptions = null;
30944
31177
  }
30945
31178
  const resolved = resolveAgentCommand(preferredAgentType);
30946
31179
  if (!resolved) {
@@ -30961,12 +31194,13 @@ async function ensureAcpClient(options) {
30961
31194
  state.acpHandle = null;
30962
31195
  state.acpStartPromise = null;
30963
31196
  state.acpAgentKey = null;
31197
+ state.activeSessionConfigOptions = null;
30964
31198
  }
30965
31199
  if (state.acpHandle) return state.acpHandle;
30966
31200
  if (!state.acpStartPromise) {
30967
31201
  let statOk = false;
30968
31202
  try {
30969
- const st = fs9.statSync(targetSessionParentPath);
31203
+ const st = fs10.statSync(targetSessionParentPath);
30970
31204
  statOk = st.isDirectory();
30971
31205
  if (!statOk) {
30972
31206
  state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
@@ -30986,15 +31220,40 @@ async function ensureAcpClient(options) {
30986
31220
  getSendRequest: () => sendRequest,
30987
31221
  log: log2
30988
31222
  });
31223
+ const persisted = cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "" ? readLocalAgentSessionFile(cloudSessionId) : null;
31224
+ const persistedAcpSessionId = persisted && persisted.backendAgentType === preferredAgentType && typeof persisted.acpSessionId === "string" && persisted.acpSessionId.trim() !== "" ? persisted.acpSessionId.trim() : null;
31225
+ state.activeSessionConfigOptions = Array.isArray(persisted?.configOptions) ? persisted.configOptions : null;
30989
31226
  state.acpStartPromise = resolved.createClient({
30990
31227
  command: resolved.command,
30991
31228
  sessionMode: mode,
30992
31229
  agentConfig: agentConfig ?? null,
30993
31230
  backendAgentType: preferredAgentType,
31231
+ persistedAcpSessionId,
31232
+ getActiveConfigOptions: () => state.activeSessionConfigOptions,
31233
+ onAcpSessionEstablished: (info) => {
31234
+ state.activeSessionConfigOptions = info.configOptions ?? state.activeSessionConfigOptions;
31235
+ if (cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "") {
31236
+ writeLocalAgentSessionFile(cloudSessionId, {
31237
+ acpSessionId: info.acpSessionId,
31238
+ configOptions: info.configOptions,
31239
+ backendAgentType: preferredAgentType
31240
+ });
31241
+ }
31242
+ },
31243
+ onAcpConfigOptionsUpdated: (configOptions) => {
31244
+ state.activeSessionConfigOptions = configOptions;
31245
+ if (cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "") {
31246
+ writeLocalAgentSessionFile(cloudSessionId, {
31247
+ configOptions,
31248
+ backendAgentType: preferredAgentType
31249
+ });
31250
+ }
31251
+ },
30994
31252
  onAgentSubprocessExit: () => {
30995
31253
  state.acpHandle = null;
30996
31254
  state.acpStartPromise = null;
30997
31255
  state.acpAgentKey = null;
31256
+ state.activeSessionConfigOptions = null;
30998
31257
  state.lastAcpStartError = "Agent subprocess exited";
30999
31258
  },
31000
31259
  ...hooks,
@@ -31024,7 +31283,8 @@ async function createAcpManager(options) {
31024
31283
  acpStartPromise: null,
31025
31284
  lastAcpStartError: null,
31026
31285
  lastAcpCwd: null,
31027
- acpAgentKey: null
31286
+ acpAgentKey: null,
31287
+ activeSessionConfigOptions: null
31028
31288
  };
31029
31289
  let backendFallbackAgentType = null;
31030
31290
  const promptRouting = {};
@@ -31074,6 +31334,7 @@ async function createAcpManager(options) {
31074
31334
  agentConfig: agentConfig ?? null,
31075
31335
  sessionParentPath,
31076
31336
  routing: promptRouting,
31337
+ cloudSessionId: sessionId,
31077
31338
  sendSessionUpdate,
31078
31339
  sendRequest: sendSessionUpdate,
31079
31340
  log: log2
@@ -31164,6 +31425,7 @@ async function createAcpManager(options) {
31164
31425
  state.acpHandle = null;
31165
31426
  state.acpStartPromise = null;
31166
31427
  state.acpAgentKey = null;
31428
+ state.activeSessionConfigOptions = null;
31167
31429
  }
31168
31430
  return {
31169
31431
  setPreferredAgentType,
@@ -31176,12 +31438,12 @@ async function createAcpManager(options) {
31176
31438
  }
31177
31439
 
31178
31440
  // src/worktrees/session-worktree-manager.ts
31179
- import * as path18 from "node:path";
31180
- import os4 from "node:os";
31441
+ import * as path19 from "node:path";
31442
+ import os5 from "node:os";
31181
31443
 
31182
31444
  // src/worktrees/prepare-new-session-worktrees.ts
31183
- import * as fs11 from "node:fs";
31184
- import * as path13 from "node:path";
31445
+ import * as fs12 from "node:fs";
31446
+ import * as path14 from "node:path";
31185
31447
 
31186
31448
  // src/git/worktree-add.ts
31187
31449
  async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
@@ -31190,12 +31452,12 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
31190
31452
  }
31191
31453
 
31192
31454
  // 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";
31455
+ import * as fs11 from "node:fs";
31456
+ import * as path13 from "node:path";
31457
+ import os4 from "node:os";
31196
31458
  var LAYOUT_FILENAME = "worktree-launcher-layout.json";
31197
31459
  function defaultWorktreeLayoutPath() {
31198
- return path12.join(os3.homedir(), ".buildautomaton", LAYOUT_FILENAME);
31460
+ return path13.join(os4.homedir(), ".buildautomaton", LAYOUT_FILENAME);
31199
31461
  }
31200
31462
  function normalizeLoadedLayout(raw) {
31201
31463
  if (raw && typeof raw === "object" && "launcherCwds" in raw) {
@@ -31207,8 +31469,8 @@ function normalizeLoadedLayout(raw) {
31207
31469
  function loadWorktreeLayout() {
31208
31470
  try {
31209
31471
  const p = defaultWorktreeLayoutPath();
31210
- if (!fs10.existsSync(p)) return { launcherCwds: [] };
31211
- const raw = JSON.parse(fs10.readFileSync(p, "utf8"));
31472
+ if (!fs11.existsSync(p)) return { launcherCwds: [] };
31473
+ const raw = JSON.parse(fs11.readFileSync(p, "utf8"));
31212
31474
  return normalizeLoadedLayout(raw);
31213
31475
  } catch {
31214
31476
  return { launcherCwds: [] };
@@ -31216,24 +31478,24 @@ function loadWorktreeLayout() {
31216
31478
  }
31217
31479
  function saveWorktreeLayout(layout) {
31218
31480
  try {
31219
- const dir = path12.dirname(defaultWorktreeLayoutPath());
31220
- fs10.mkdirSync(dir, { recursive: true });
31221
- fs10.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
31481
+ const dir = path13.dirname(defaultWorktreeLayoutPath());
31482
+ fs11.mkdirSync(dir, { recursive: true });
31483
+ fs11.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
31222
31484
  } catch {
31223
31485
  }
31224
31486
  }
31225
31487
  function baseNameSafe(pathString) {
31226
- return path12.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
31488
+ return path13.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
31227
31489
  }
31228
31490
  function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
31229
- const norm = path12.resolve(bridgeRootPath2);
31230
- const existing = layout.launcherCwds.find((e) => path12.resolve(e.absolutePath) === norm);
31491
+ const norm = path13.resolve(bridgeRootPath2);
31492
+ const existing = layout.launcherCwds.find((e) => path13.resolve(e.absolutePath) === norm);
31231
31493
  return existing?.dirName;
31232
31494
  }
31233
31495
  function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
31234
31496
  const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
31235
31497
  if (existing) return existing;
31236
- const norm = path12.resolve(bridgeRootPath2);
31498
+ const norm = path13.resolve(bridgeRootPath2);
31237
31499
  const base = baseNameSafe(norm);
31238
31500
  const used = new Set(layout.launcherCwds.map((e) => e.dirName));
31239
31501
  let name = base;
@@ -31250,10 +31512,10 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
31250
31512
  // src/worktrees/prepare-new-session-worktrees.ts
31251
31513
  async function prepareNewSessionWorktrees(options) {
31252
31514
  const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2 } = options;
31253
- const bridgeResolved = path13.resolve(bridgeRoot);
31515
+ const bridgeResolved = path14.resolve(bridgeRoot);
31254
31516
  const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
31255
- const bridgeKeyDir = path13.join(worktreesRootPath, cwdKey);
31256
- const sessionDir = path13.join(bridgeKeyDir, sessionId);
31517
+ const bridgeKeyDir = path14.join(worktreesRootPath, cwdKey);
31518
+ const sessionDir = path14.join(bridgeKeyDir, sessionId);
31257
31519
  const repos = await discoverGitReposUnderRoot(bridgeResolved);
31258
31520
  if (repos.length === 0) {
31259
31521
  log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
@@ -31261,14 +31523,14 @@ async function prepareNewSessionWorktrees(options) {
31261
31523
  }
31262
31524
  const branch = `session-${sessionId}`;
31263
31525
  const worktreePaths = [];
31264
- fs11.mkdirSync(sessionDir, { recursive: true });
31526
+ fs12.mkdirSync(sessionDir, { recursive: true });
31265
31527
  for (const repo of repos) {
31266
- let rel = path13.relative(bridgeResolved, repo.absolutePath);
31267
- if (rel.startsWith("..") || path13.isAbsolute(rel)) continue;
31528
+ let rel = path14.relative(bridgeResolved, repo.absolutePath);
31529
+ if (rel.startsWith("..") || path14.isAbsolute(rel)) continue;
31268
31530
  const relNorm = rel === "" ? "." : rel;
31269
- const wtPath = relNorm === "." ? sessionDir : path13.join(sessionDir, relNorm);
31531
+ const wtPath = relNorm === "." ? sessionDir : path14.join(sessionDir, relNorm);
31270
31532
  if (relNorm !== ".") {
31271
- fs11.mkdirSync(path13.dirname(wtPath), { recursive: true });
31533
+ fs12.mkdirSync(path14.dirname(wtPath), { recursive: true });
31272
31534
  }
31273
31535
  try {
31274
31536
  await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
@@ -31310,23 +31572,23 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
31310
31572
  }
31311
31573
 
31312
31574
  // src/worktrees/remove-session-worktrees.ts
31313
- import * as fs14 from "node:fs";
31575
+ import * as fs15 from "node:fs";
31314
31576
 
31315
31577
  // src/git/worktree-remove.ts
31316
- import * as fs13 from "node:fs";
31578
+ import * as fs14 from "node:fs";
31317
31579
 
31318
31580
  // src/git/resolve-main-repo-from-git-file.ts
31319
- import * as fs12 from "node:fs";
31320
- import * as path14 from "node:path";
31581
+ import * as fs13 from "node:fs";
31582
+ import * as path15 from "node:path";
31321
31583
  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();
31584
+ const gitDirFile = path15.join(wt, ".git");
31585
+ if (!fs13.existsSync(gitDirFile) || !fs13.statSync(gitDirFile).isFile()) return "";
31586
+ const first2 = fs13.readFileSync(gitDirFile, "utf8").trim();
31325
31587
  const m = first2.match(/^gitdir:\s*(.+)$/im);
31326
31588
  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);
31589
+ const gitWorktreePath = path15.resolve(wt, m[1].trim());
31590
+ const gitDir = path15.dirname(path15.dirname(gitWorktreePath));
31591
+ return path15.dirname(gitDir);
31330
31592
  }
31331
31593
 
31332
31594
  // src/git/worktree-remove.ts
@@ -31335,7 +31597,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
31335
31597
  if (mainRepo) {
31336
31598
  await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
31337
31599
  } else {
31338
- fs13.rmSync(worktreePath, { recursive: true, force: true });
31600
+ fs14.rmSync(worktreePath, { recursive: true, force: true });
31339
31601
  }
31340
31602
  }
31341
31603
 
@@ -31348,7 +31610,7 @@ async function removeSessionWorktrees(paths, log2) {
31348
31610
  } catch (e) {
31349
31611
  log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
31350
31612
  try {
31351
- fs14.rmSync(wt, { recursive: true, force: true });
31613
+ fs15.rmSync(wt, { recursive: true, force: true });
31352
31614
  } catch {
31353
31615
  }
31354
31616
  }
@@ -31568,7 +31830,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
31568
31830
  }
31569
31831
 
31570
31832
  // src/git/working-directory/changes/get-working-tree-change-repo-details.ts
31571
- import * as path16 from "node:path";
31833
+ import * as path17 from "node:path";
31572
31834
 
31573
31835
  // src/git/working-directory/changes/parse-git-status.ts
31574
31836
  function parseNameStatusLines(lines) {
@@ -31688,8 +31950,8 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
31688
31950
  }
31689
31951
 
31690
31952
  // 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";
31953
+ import * as fs17 from "node:fs";
31954
+ import * as path16 from "node:path";
31693
31955
 
31694
31956
  // src/git/working-directory/changes/count-lines.ts
31695
31957
  import { createReadStream } from "node:fs";
@@ -31713,7 +31975,7 @@ async function countTextFileLines(filePath) {
31713
31975
  }
31714
31976
 
31715
31977
  // src/git/working-directory/changes/hydrate-patch.ts
31716
- import * as fs15 from "node:fs";
31978
+ import * as fs16 from "node:fs";
31717
31979
  var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
31718
31980
  var MAX_HYDRATE_LINES_PER_GAP = 8e3;
31719
31981
  var MAX_HYDRATE_LINES_PER_FILE = 8e4;
@@ -31728,7 +31990,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
31728
31990
  }
31729
31991
  async function readWorktreeFileLines(filePath) {
31730
31992
  try {
31731
- const raw = await fs15.promises.readFile(filePath, "utf8");
31993
+ const raw = await fs16.promises.readFile(filePath, "utf8");
31732
31994
  return raw.split(/\r?\n/);
31733
31995
  } catch {
31734
31996
  return null;
@@ -31863,7 +32125,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
31863
32125
  const rows = [];
31864
32126
  for (const pathInRepo of paths) {
31865
32127
  const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
31866
- const repoFilePath = path15.join(repoGitCwd, pathInRepo);
32128
+ const repoFilePath = path16.join(repoGitCwd, pathInRepo);
31867
32129
  const nums = numByPath.get(pathInRepo);
31868
32130
  let additions = nums?.additions ?? 0;
31869
32131
  let deletions = nums?.deletions ?? 0;
@@ -31876,7 +32138,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
31876
32138
  deletions = fromGit.deletions;
31877
32139
  } else {
31878
32140
  try {
31879
- const st = await fs16.promises.stat(repoFilePath);
32141
+ const st = await fs17.promises.stat(repoFilePath);
31880
32142
  if (st.isFile()) additions = await countTextFileLines(repoFilePath);
31881
32143
  else additions = 0;
31882
32144
  } catch {
@@ -31902,7 +32164,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
31902
32164
  } else {
31903
32165
  pathInRepo = row.pathRelLauncher;
31904
32166
  }
31905
- const filePath = path15.join(repoGitCwd, pathInRepo);
32167
+ const filePath = path16.join(repoGitCwd, pathInRepo);
31906
32168
  let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
31907
32169
  if (patch) {
31908
32170
  patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
@@ -31918,8 +32180,8 @@ function normRepoRel(p) {
31918
32180
  return x === "" ? "." : x;
31919
32181
  }
31920
32182
  async function getWorkingTreeChangeRepoDetails(options) {
31921
- const bridgeRoot = path16.resolve(getBridgeRoot());
31922
- const sessionWtRoot = options.sessionWorktreeRootPath ? path16.resolve(options.sessionWorktreeRootPath) : null;
32183
+ const bridgeRoot = path17.resolve(getBridgeRoot());
32184
+ const sessionWtRoot = options.sessionWorktreeRootPath ? path17.resolve(options.sessionWorktreeRootPath) : null;
31923
32185
  const legacyNested = options.legacyRepoNestedSessionLayout === true;
31924
32186
  const out = [];
31925
32187
  const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
@@ -31932,7 +32194,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
31932
32194
  }
31933
32195
  const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
31934
32196
  for (const target of options.commitTargetPaths) {
31935
- const t = path16.resolve(target);
32197
+ const t = path17.resolve(target);
31936
32198
  if (!await isGitRepoDirectory(t)) continue;
31937
32199
  const g = cliSimpleGit(t);
31938
32200
  let branch = "HEAD";
@@ -31945,8 +32207,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
31945
32207
  const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
31946
32208
  let repoRelPath;
31947
32209
  if (sessionWtRoot) {
31948
- const anchor = legacyNested ? path16.dirname(t) : t;
31949
- const relNorm = path16.relative(sessionWtRoot, anchor);
32210
+ const anchor = legacyNested ? path17.dirname(t) : t;
32211
+ const relNorm = path17.relative(sessionWtRoot, anchor);
31950
32212
  repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
31951
32213
  } else {
31952
32214
  let top = t;
@@ -31955,8 +32217,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
31955
32217
  } catch {
31956
32218
  top = t;
31957
32219
  }
31958
- const rel = path16.relative(bridgeRoot, path16.resolve(top)).replace(/\\/g, "/") || ".";
31959
- repoRelPath = rel.startsWith("..") ? path16.basename(path16.resolve(top)) : rel;
32220
+ const rel = path17.relative(bridgeRoot, path17.resolve(top)).replace(/\\/g, "/") || ".";
32221
+ repoRelPath = rel.startsWith("..") ? path17.basename(path17.resolve(top)) : rel;
31960
32222
  }
31961
32223
  const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
31962
32224
  if (filter && norm !== filter) continue;
@@ -32021,11 +32283,11 @@ async function commitSessionWorktrees(options) {
32021
32283
  }
32022
32284
 
32023
32285
  // src/worktrees/discover-session-worktree-on-disk.ts
32024
- import * as fs17 from "node:fs";
32025
- import * as path17 from "node:path";
32286
+ import * as fs18 from "node:fs";
32287
+ import * as path18 from "node:path";
32026
32288
  function isGitDir(dirPath) {
32027
32289
  try {
32028
- return fs17.existsSync(path17.join(dirPath, ".git"));
32290
+ return fs18.existsSync(path18.join(dirPath, ".git"));
32029
32291
  } catch {
32030
32292
  return false;
32031
32293
  }
@@ -32034,23 +32296,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
32034
32296
  const out = [];
32035
32297
  const walk = (dir) => {
32036
32298
  if (isGitDir(dir)) {
32037
- out.push(path17.resolve(dir));
32299
+ out.push(path18.resolve(dir));
32038
32300
  return;
32039
32301
  }
32040
32302
  let entries;
32041
32303
  try {
32042
- entries = fs17.readdirSync(dir, { withFileTypes: true });
32304
+ entries = fs18.readdirSync(dir, { withFileTypes: true });
32043
32305
  } catch {
32044
32306
  return;
32045
32307
  }
32046
32308
  for (const e of entries) {
32047
32309
  if (e.name.startsWith(".")) continue;
32048
- const full = path17.join(dir, e.name);
32310
+ const full = path18.join(dir, e.name);
32049
32311
  if (!e.isDirectory()) continue;
32050
32312
  walk(full);
32051
32313
  }
32052
32314
  };
32053
- walk(path17.resolve(rootPath));
32315
+ walk(path18.resolve(rootPath));
32054
32316
  return [...new Set(out)];
32055
32317
  }
32056
32318
  function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
@@ -32059,16 +32321,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
32059
32321
  if (depth > maxDepth) return;
32060
32322
  let entries;
32061
32323
  try {
32062
- entries = fs17.readdirSync(dir, { withFileTypes: true });
32324
+ entries = fs18.readdirSync(dir, { withFileTypes: true });
32063
32325
  } catch {
32064
32326
  return;
32065
32327
  }
32066
32328
  for (const e of entries) {
32067
32329
  if (e.name.startsWith(".")) continue;
32068
- const full = path17.join(dir, e.name);
32330
+ const full = path18.join(dir, e.name);
32069
32331
  if (!e.isDirectory()) continue;
32070
32332
  if (e.name === sessionId) {
32071
- if (isGitDir(full)) out.push(path17.resolve(full));
32333
+ if (isGitDir(full)) out.push(path18.resolve(full));
32072
32334
  } else {
32073
32335
  walk(full, depth + 1);
32074
32336
  }
@@ -32080,14 +32342,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
32080
32342
  function tryBindingFromSessionDirectory(sessionDir) {
32081
32343
  let st;
32082
32344
  try {
32083
- st = fs17.statSync(sessionDir);
32345
+ st = fs18.statSync(sessionDir);
32084
32346
  } catch {
32085
32347
  return null;
32086
32348
  }
32087
32349
  if (!st.isDirectory()) return null;
32088
32350
  const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
32089
32351
  if (worktreePaths.length === 0) return null;
32090
- const abs = path17.resolve(sessionDir);
32352
+ const abs = path18.resolve(sessionDir);
32091
32353
  return {
32092
32354
  sessionParentPath: abs,
32093
32355
  workingTreeRelRoot: abs,
@@ -32097,20 +32359,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
32097
32359
  function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
32098
32360
  const sid = sessionId.trim();
32099
32361
  if (!sid) return null;
32100
- const hintR = path17.resolve(checkoutPath);
32362
+ const hintR = path18.resolve(checkoutPath);
32101
32363
  let best = null;
32102
- let cur = path17.dirname(hintR);
32364
+ let cur = path18.dirname(hintR);
32103
32365
  for (let i = 0; i < 40; i++) {
32104
32366
  const paths = collectWorktreeRootsNamed(cur, sid, 24);
32105
- if (paths.some((p) => path17.resolve(p) === hintR)) {
32106
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path17.resolve(paths[0]);
32367
+ if (paths.some((p) => path18.resolve(p) === hintR)) {
32368
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path18.resolve(paths[0]);
32107
32369
  best = {
32108
- sessionParentPath: path17.resolve(isolated),
32109
- workingTreeRelRoot: path17.resolve(cur),
32110
- repoCheckoutPaths: paths.map((p) => path17.resolve(p))
32370
+ sessionParentPath: path18.resolve(isolated),
32371
+ workingTreeRelRoot: path18.resolve(cur),
32372
+ repoCheckoutPaths: paths.map((p) => path18.resolve(p))
32111
32373
  };
32112
32374
  }
32113
- const next = path17.dirname(cur);
32375
+ const next = path18.dirname(cur);
32114
32376
  if (next === cur) break;
32115
32377
  cur = next;
32116
32378
  }
@@ -32118,33 +32380,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
32118
32380
  }
32119
32381
  function discoverSessionWorktreeOnDisk(options) {
32120
32382
  const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
32121
- if (!sessionId.trim() || !fs17.existsSync(worktreesRootPath)) return null;
32383
+ if (!sessionId.trim() || !fs18.existsSync(worktreesRootPath)) return null;
32122
32384
  const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
32123
32385
  const keys = [];
32124
32386
  if (preferredKey) keys.push(preferredKey);
32125
32387
  try {
32126
- for (const name of fs17.readdirSync(worktreesRootPath)) {
32388
+ for (const name of fs18.readdirSync(worktreesRootPath)) {
32127
32389
  if (name.startsWith(".")) continue;
32128
- const p = path17.join(worktreesRootPath, name);
32129
- if (!fs17.statSync(p).isDirectory()) continue;
32390
+ const p = path18.join(worktreesRootPath, name);
32391
+ if (!fs18.statSync(p).isDirectory()) continue;
32130
32392
  if (name !== preferredKey) keys.push(name);
32131
32393
  }
32132
32394
  } catch {
32133
32395
  return null;
32134
32396
  }
32135
32397
  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);
32398
+ const layoutRoot = path18.join(worktreesRootPath, key);
32399
+ if (!fs18.existsSync(layoutRoot) || !fs18.statSync(layoutRoot).isDirectory()) continue;
32400
+ const sessionDir = path18.join(layoutRoot, sessionId);
32139
32401
  const nested = tryBindingFromSessionDirectory(sessionDir);
32140
32402
  if (nested) return nested;
32141
32403
  const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
32142
32404
  if (legacyPaths.length > 0) {
32143
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path17.resolve(legacyPaths[0]);
32405
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path18.resolve(legacyPaths[0]);
32144
32406
  return {
32145
- sessionParentPath: path17.resolve(isolated),
32146
- workingTreeRelRoot: path17.resolve(layoutRoot),
32147
- repoCheckoutPaths: legacyPaths.map((p) => path17.resolve(p))
32407
+ sessionParentPath: path18.resolve(isolated),
32408
+ workingTreeRelRoot: path18.resolve(layoutRoot),
32409
+ repoCheckoutPaths: legacyPaths.map((p) => path18.resolve(p))
32148
32410
  };
32149
32411
  }
32150
32412
  }
@@ -32153,12 +32415,12 @@ function discoverSessionWorktreeOnDisk(options) {
32153
32415
  function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
32154
32416
  const sid = sessionId.trim();
32155
32417
  if (!sid) return null;
32156
- const hint = path17.resolve(sessionWorktreeRootPathOrHint);
32157
- const underHint = tryBindingFromSessionDirectory(path17.join(hint, sid));
32418
+ const hint = path18.resolve(sessionWorktreeRootPathOrHint);
32419
+ const underHint = tryBindingFromSessionDirectory(path18.join(hint, sid));
32158
32420
  if (underHint) return underHint;
32159
32421
  const direct = tryBindingFromSessionDirectory(hint);
32160
32422
  if (direct) {
32161
- if (path17.basename(hint) === sid && isGitDir(hint)) {
32423
+ if (path18.basename(hint) === sid && isGitDir(hint)) {
32162
32424
  const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
32163
32425
  if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
32164
32426
  return legacyFromCheckout;
@@ -32166,24 +32428,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
32166
32428
  }
32167
32429
  return direct;
32168
32430
  }
32169
- if (path17.basename(hint) === sid && isGitDir(hint)) {
32431
+ if (path18.basename(hint) === sid && isGitDir(hint)) {
32170
32432
  const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
32171
32433
  if (legacyFromCheckout) return legacyFromCheckout;
32172
32434
  }
32173
32435
  let st;
32174
32436
  try {
32175
- st = fs17.statSync(hint);
32437
+ st = fs18.statSync(hint);
32176
32438
  } catch {
32177
32439
  return null;
32178
32440
  }
32179
32441
  if (!st.isDirectory()) return null;
32180
32442
  const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
32181
32443
  if (legacyPaths.length === 0) return null;
32182
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path17.resolve(legacyPaths[0]);
32444
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path18.resolve(legacyPaths[0]);
32183
32445
  return {
32184
- sessionParentPath: path17.resolve(isolated),
32446
+ sessionParentPath: path18.resolve(isolated),
32185
32447
  workingTreeRelRoot: hint,
32186
- repoCheckoutPaths: legacyPaths.map((p) => path17.resolve(p))
32448
+ repoCheckoutPaths: legacyPaths.map((p) => path18.resolve(p))
32187
32449
  };
32188
32450
  }
32189
32451
 
@@ -32206,10 +32468,10 @@ var SessionWorktreeManager = class {
32206
32468
  this.layout = loadWorktreeLayout();
32207
32469
  }
32208
32470
  rememberSessionWorktrees(sessionId, binding) {
32209
- const paths = binding.repoCheckoutPaths.map((p) => path18.resolve(p));
32471
+ const paths = binding.repoCheckoutPaths.map((p) => path19.resolve(p));
32210
32472
  this.sessionRepoCheckoutPaths.set(sessionId, paths);
32211
- this.sessionParentPathBySession.set(sessionId, path18.resolve(binding.sessionParentPath));
32212
- this.sessionWorkingTreeRelRootBySession.set(sessionId, path18.resolve(binding.workingTreeRelRoot));
32473
+ this.sessionParentPathBySession.set(sessionId, path19.resolve(binding.sessionParentPath));
32474
+ this.sessionWorkingTreeRelRootBySession.set(sessionId, path19.resolve(binding.workingTreeRelRoot));
32213
32475
  }
32214
32476
  sessionParentPathAfterRemember(sessionId) {
32215
32477
  return this.sessionParentPathBySession.get(sessionId);
@@ -32226,7 +32488,7 @@ var SessionWorktreeManager = class {
32226
32488
  const parent = this.sessionParentPathBySession.get(sessionId);
32227
32489
  const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
32228
32490
  if (!parent || !relRoot) return false;
32229
- return path18.resolve(parent) !== path18.resolve(relRoot);
32491
+ return path19.resolve(parent) !== path19.resolve(relRoot);
32230
32492
  }
32231
32493
  /**
32232
32494
  * Session parent path for `worktrees_root`: the per-session directory (new layout) or primary checkout (legacy).
@@ -32235,7 +32497,7 @@ var SessionWorktreeManager = class {
32235
32497
  if (!sessionId) return null;
32236
32498
  const sid = sessionId.trim();
32237
32499
  const cached2 = this.sessionParentPathBySession.get(sid);
32238
- if (cached2) return path18.resolve(cached2);
32500
+ if (cached2) return path19.resolve(cached2);
32239
32501
  const paths = this.ensureRepoCheckoutPathsForSession(sid) ?? this.getRepoCheckoutPathsForSession(sid);
32240
32502
  if (!paths?.length) return null;
32241
32503
  return resolveIsolatedSessionParentPathFromCheckouts(paths);
@@ -32249,7 +32511,7 @@ var SessionWorktreeManager = class {
32249
32511
  const sid = sessionId.trim();
32250
32512
  const parentPathRaw = opts.sessionParentPath?.trim();
32251
32513
  if (parentPathRaw) {
32252
- const resolved = path18.resolve(parentPathRaw);
32514
+ const resolved = path19.resolve(parentPathRaw);
32253
32515
  if (sid && parseSessionParent(opts.sessionParent) === "worktrees_root") {
32254
32516
  const diskFirst = this.tryDiscoverFromDisk(sid);
32255
32517
  if (diskFirst) {
@@ -32268,7 +32530,7 @@ var SessionWorktreeManager = class {
32268
32530
  this.rememberSessionWorktrees(sid, tryRoot);
32269
32531
  return this.sessionParentPathAfterRemember(sid);
32270
32532
  }
32271
- const next = path18.dirname(cur);
32533
+ const next = path19.dirname(cur);
32272
32534
  if (next === cur) break;
32273
32535
  cur = next;
32274
32536
  }
@@ -32421,15 +32683,15 @@ var SessionWorktreeManager = class {
32421
32683
  }
32422
32684
  };
32423
32685
  function defaultWorktreesRootPath() {
32424
- return path18.join(os4.homedir(), ".buildautomaton", "worktrees");
32686
+ return path19.join(os5.homedir(), ".buildautomaton", "worktrees");
32425
32687
  }
32426
32688
 
32427
32689
  // src/files/watch-file-index.ts
32428
32690
  import { watch } from "node:fs";
32429
- import path25 from "node:path";
32691
+ import path26 from "node:path";
32430
32692
 
32431
32693
  // src/files/index/build-file-index.ts
32432
- import path22 from "node:path";
32694
+ import path23 from "node:path";
32433
32695
 
32434
32696
  // src/runtime/yield-to-event-loop.ts
32435
32697
  function yieldToEventLoop() {
@@ -32437,14 +32699,14 @@ function yieldToEventLoop() {
32437
32699
  }
32438
32700
 
32439
32701
  // src/files/index/walk-workspace-tree.ts
32440
- import fs18 from "node:fs";
32441
- import path20 from "node:path";
32702
+ import fs19 from "node:fs";
32703
+ import path21 from "node:path";
32442
32704
 
32443
32705
  // src/files/index/constants.ts
32444
- import path19 from "node:path";
32445
- import os5 from "node:os";
32706
+ import path20 from "node:path";
32707
+ import os6 from "node:os";
32446
32708
  var INDEX_WORK_YIELD_EVERY = 256;
32447
- var INDEX_DIR = path19.join(os5.homedir(), ".buildautomaton");
32709
+ var INDEX_DIR = path20.join(os6.homedir(), ".buildautomaton");
32448
32710
  var INDEX_HASH_LEN = 16;
32449
32711
  var INDEX_VERSION = 2;
32450
32712
  var INDEX_LOG_PREFIX = "[file-index]";
@@ -32453,20 +32715,20 @@ var INDEX_LOG_PREFIX = "[file-index]";
32453
32715
  function walkWorkspaceTreeSync(dir, baseDir, out) {
32454
32716
  let names;
32455
32717
  try {
32456
- names = fs18.readdirSync(dir);
32718
+ names = fs19.readdirSync(dir);
32457
32719
  } catch {
32458
32720
  return;
32459
32721
  }
32460
32722
  for (const name of names) {
32461
32723
  if (name.startsWith(".")) continue;
32462
- const full = path20.join(dir, name);
32724
+ const full = path21.join(dir, name);
32463
32725
  let stat2;
32464
32726
  try {
32465
- stat2 = fs18.statSync(full);
32727
+ stat2 = fs19.statSync(full);
32466
32728
  } catch {
32467
32729
  continue;
32468
32730
  }
32469
- const relative5 = path20.relative(baseDir, full).replace(/\\/g, "/");
32731
+ const relative5 = path21.relative(baseDir, full).replace(/\\/g, "/");
32470
32732
  if (stat2.isDirectory()) {
32471
32733
  walkWorkspaceTreeSync(full, baseDir, out);
32472
32734
  } else if (stat2.isFile()) {
@@ -32477,7 +32739,7 @@ function walkWorkspaceTreeSync(dir, baseDir, out) {
32477
32739
  async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
32478
32740
  let names;
32479
32741
  try {
32480
- names = await fs18.promises.readdir(dir);
32742
+ names = await fs19.promises.readdir(dir);
32481
32743
  } catch {
32482
32744
  return;
32483
32745
  }
@@ -32487,14 +32749,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
32487
32749
  await yieldToEventLoop();
32488
32750
  }
32489
32751
  state.n++;
32490
- const full = path20.join(dir, name);
32752
+ const full = path21.join(dir, name);
32491
32753
  let stat2;
32492
32754
  try {
32493
- stat2 = await fs18.promises.stat(full);
32755
+ stat2 = await fs19.promises.stat(full);
32494
32756
  } catch {
32495
32757
  continue;
32496
32758
  }
32497
- const relative5 = path20.relative(baseDir, full).replace(/\\/g, "/");
32759
+ const relative5 = path21.relative(baseDir, full).replace(/\\/g, "/");
32498
32760
  if (stat2.isDirectory()) {
32499
32761
  await walkWorkspaceTreeAsync(full, baseDir, out, state);
32500
32762
  } else if (stat2.isFile()) {
@@ -32575,22 +32837,22 @@ async function buildTrigramMapForPathsAsync(paths) {
32575
32837
  }
32576
32838
 
32577
32839
  // src/files/index/write-index-file.ts
32578
- import fs19 from "node:fs";
32840
+ import fs20 from "node:fs";
32579
32841
 
32580
32842
  // src/files/index/paths.ts
32581
- import path21 from "node:path";
32843
+ import path22 from "node:path";
32582
32844
  import crypto2 from "node:crypto";
32583
32845
  function getIndexPathForCwd(resolvedCwd) {
32584
32846
  const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
32585
- return path21.join(INDEX_DIR, `.file-index-${hash}.json`);
32847
+ return path22.join(INDEX_DIR, `.file-index-${hash}.json`);
32586
32848
  }
32587
32849
 
32588
32850
  // src/files/index/write-index-file.ts
32589
32851
  function writeIndexFileSync(resolvedCwd, data) {
32590
32852
  const indexPath = getIndexPathForCwd(resolvedCwd);
32591
32853
  try {
32592
- if (!fs19.existsSync(INDEX_DIR)) fs19.mkdirSync(INDEX_DIR, { recursive: true });
32593
- fs19.writeFileSync(indexPath, JSON.stringify(data), "utf8");
32854
+ if (!fs20.existsSync(INDEX_DIR)) fs20.mkdirSync(INDEX_DIR, { recursive: true });
32855
+ fs20.writeFileSync(indexPath, JSON.stringify(data), "utf8");
32594
32856
  } catch (e) {
32595
32857
  console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
32596
32858
  }
@@ -32598,8 +32860,8 @@ function writeIndexFileSync(resolvedCwd, data) {
32598
32860
  async function writeIndexFileAsync(resolvedCwd, data) {
32599
32861
  const indexPath = getIndexPathForCwd(resolvedCwd);
32600
32862
  try {
32601
- await fs19.promises.mkdir(INDEX_DIR, { recursive: true });
32602
- await fs19.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
32863
+ await fs20.promises.mkdir(INDEX_DIR, { recursive: true });
32864
+ await fs20.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
32603
32865
  } catch (e) {
32604
32866
  console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
32605
32867
  }
@@ -32613,7 +32875,7 @@ function sortPaths(paths) {
32613
32875
  paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
32614
32876
  }
32615
32877
  function buildFileIndex(cwd) {
32616
- const resolved = path22.resolve(cwd);
32878
+ const resolved = path23.resolve(cwd);
32617
32879
  const paths = [];
32618
32880
  walkWorkspaceTreeSync(resolved, resolved, paths);
32619
32881
  sortPaths(paths);
@@ -32623,7 +32885,7 @@ function buildFileIndex(cwd) {
32623
32885
  return data;
32624
32886
  }
32625
32887
  async function buildFileIndexAsync(cwd) {
32626
- const resolved = path22.resolve(cwd);
32888
+ const resolved = path23.resolve(cwd);
32627
32889
  const paths = [];
32628
32890
  await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
32629
32891
  await yieldToEventLoop();
@@ -32635,13 +32897,13 @@ async function buildFileIndexAsync(cwd) {
32635
32897
  }
32636
32898
 
32637
32899
  // src/files/index/load-file-index.ts
32638
- import fs20 from "node:fs";
32639
- import path23 from "node:path";
32900
+ import fs21 from "node:fs";
32901
+ import path24 from "node:path";
32640
32902
  function loadFileIndex(cwd) {
32641
- const resolved = path23.resolve(cwd);
32903
+ const resolved = path24.resolve(cwd);
32642
32904
  const indexPath = getIndexPathForCwd(resolved);
32643
32905
  try {
32644
- const raw = fs20.readFileSync(indexPath, "utf8");
32906
+ const raw = fs21.readFileSync(indexPath, "utf8");
32645
32907
  const parsed = JSON.parse(raw);
32646
32908
  if (parsed !== null && typeof parsed === "object" && Array.isArray(parsed.paths)) {
32647
32909
  const obj = parsed;
@@ -32660,9 +32922,9 @@ function loadFileIndex(cwd) {
32660
32922
  }
32661
32923
 
32662
32924
  // src/files/index/ensure-file-index.ts
32663
- import path24 from "node:path";
32925
+ import path25 from "node:path";
32664
32926
  async function ensureFileIndexAsync(cwd) {
32665
- const resolved = path24.resolve(cwd);
32927
+ const resolved = path25.resolve(cwd);
32666
32928
  const cached2 = loadFileIndex(resolved);
32667
32929
  if (cached2 !== null) return { data: cached2, fromCache: true };
32668
32930
  const data = await buildFileIndexAsync(resolved);
@@ -32745,7 +33007,7 @@ function createFsWatcher(resolved, schedule) {
32745
33007
  }
32746
33008
  }
32747
33009
  function startFileIndexWatcher(cwd = getBridgeRoot()) {
32748
- const resolved = path25.resolve(cwd);
33010
+ const resolved = path26.resolve(cwd);
32749
33011
  void buildFileIndexAsync(resolved).catch((e) => {
32750
33012
  console.error("[file-index] Initial index build failed:", e);
32751
33013
  });
@@ -32773,7 +33035,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
32773
33035
  }
32774
33036
 
32775
33037
  // src/connection/create-bridge-connection.ts
32776
- import * as path33 from "node:path";
33038
+ import * as path34 from "node:path";
32777
33039
 
32778
33040
  // src/dev-servers/manager/dev-server-manager.ts
32779
33041
  import { rm as rm2 } from "node:fs/promises";
@@ -32817,7 +33079,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
32817
33079
  }
32818
33080
 
32819
33081
  // src/dev-servers/process/wire-dev-server-child-process.ts
32820
- import fs21 from "node:fs";
33082
+ import fs22 from "node:fs";
32821
33083
 
32822
33084
  // src/dev-servers/manager/forward-pipe.ts
32823
33085
  function forwardChildPipe(childReadable, terminal, onData) {
@@ -32853,7 +33115,7 @@ function wireDevServerChildProcess(d) {
32853
33115
  d.setPollInterval(void 0);
32854
33116
  return;
32855
33117
  }
32856
- fs21.readFile(d.mergedLogPath, (err, buf) => {
33118
+ fs22.readFile(d.mergedLogPath, (err, buf) => {
32857
33119
  if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
32858
33120
  if (buf.length <= d.mergedReadPos.value) return;
32859
33121
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
@@ -32891,7 +33153,7 @@ ${errTail}` : ""}`);
32891
33153
  d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
32892
33154
  };
32893
33155
  if (mergedPath) {
32894
- fs21.readFile(mergedPath, (err, buf) => {
33156
+ fs22.readFile(mergedPath, (err, buf) => {
32895
33157
  if (!err && buf.length > d.mergedReadPos.value) {
32896
33158
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
32897
33159
  if (chunk.length > 0) {
@@ -32993,13 +33255,13 @@ function parseDevServerDefs(servers) {
32993
33255
  }
32994
33256
 
32995
33257
  // src/dev-servers/manager/shell-spawn/utils.ts
32996
- import fs22 from "node:fs";
33258
+ import fs23 from "node:fs";
32997
33259
  function isSpawnEbadf(e) {
32998
33260
  return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
32999
33261
  }
33000
33262
  function rmDirQuiet(dir) {
33001
33263
  try {
33002
- fs22.rmSync(dir, { recursive: true, force: true });
33264
+ fs23.rmSync(dir, { recursive: true, force: true });
33003
33265
  } catch {
33004
33266
  }
33005
33267
  }
@@ -33007,7 +33269,7 @@ var cachedDevNullReadFd;
33007
33269
  function devNullReadFd() {
33008
33270
  if (cachedDevNullReadFd === void 0) {
33009
33271
  const devPath = process.platform === "win32" ? "nul" : "/dev/null";
33010
- cachedDevNullReadFd = fs22.openSync(devPath, "r");
33272
+ cachedDevNullReadFd = fs23.openSync(devPath, "r");
33011
33273
  }
33012
33274
  return cachedDevNullReadFd;
33013
33275
  }
@@ -33081,15 +33343,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
33081
33343
 
33082
33344
  // src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
33083
33345
  import { spawn as spawn7 } from "node:child_process";
33084
- import fs23 from "node:fs";
33346
+ import fs24 from "node:fs";
33085
33347
  import { tmpdir } from "node:os";
33086
- import path26 from "node:path";
33348
+ import path27 from "node:path";
33087
33349
  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");
33350
+ const tmpRoot = fs24.mkdtempSync(path27.join(tmpdir(), "ba-devsrv-log-"));
33351
+ const logPath = path27.join(tmpRoot, "combined.log");
33090
33352
  let logFd;
33091
33353
  try {
33092
- logFd = fs23.openSync(logPath, "a");
33354
+ logFd = fs24.openSync(logPath, "a");
33093
33355
  } catch {
33094
33356
  rmDirQuiet(tmpRoot);
33095
33357
  return null;
@@ -33108,7 +33370,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33108
33370
  } else {
33109
33371
  proc = spawn7("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
33110
33372
  }
33111
- fs23.closeSync(logFd);
33373
+ fs24.closeSync(logFd);
33112
33374
  return {
33113
33375
  proc,
33114
33376
  pipedStdoutStderr: true,
@@ -33117,7 +33379,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33117
33379
  };
33118
33380
  } catch (e) {
33119
33381
  try {
33120
- fs23.closeSync(logFd);
33382
+ fs24.closeSync(logFd);
33121
33383
  } catch {
33122
33384
  }
33123
33385
  rmDirQuiet(tmpRoot);
@@ -33128,22 +33390,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33128
33390
 
33129
33391
  // src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
33130
33392
  import { spawn as spawn8 } from "node:child_process";
33131
- import fs24 from "node:fs";
33393
+ import fs25 from "node:fs";
33132
33394
  import { tmpdir as tmpdir2 } from "node:os";
33133
- import path27 from "node:path";
33395
+ import path28 from "node:path";
33134
33396
  function shSingleQuote(s) {
33135
33397
  return `'${s.replace(/'/g, `'\\''`)}'`;
33136
33398
  }
33137
33399
  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");
33400
+ const tmpRoot = fs25.mkdtempSync(path28.join(tmpdir2(), "ba-devsrv-sh-"));
33401
+ const logPath = path28.join(tmpRoot, "combined.log");
33402
+ const innerPath = path28.join(tmpRoot, "_cmd.sh");
33403
+ const runnerPath = path28.join(tmpRoot, "_run.sh");
33142
33404
  try {
33143
- fs24.writeFileSync(innerPath, `#!/bin/sh
33405
+ fs25.writeFileSync(innerPath, `#!/bin/sh
33144
33406
  ${command}
33145
33407
  `);
33146
- fs24.writeFileSync(
33408
+ fs25.writeFileSync(
33147
33409
  runnerPath,
33148
33410
  `#!/bin/sh
33149
33411
  cd ${shSingleQuote(cwd)}
@@ -33169,13 +33431,13 @@ cd ${shSingleQuote(cwd)}
33169
33431
  }
33170
33432
  }
33171
33433
  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");
33434
+ const tmpRoot = fs25.mkdtempSync(path28.join(tmpdir2(), "ba-devsrv-sh-"));
33435
+ const logPath = path28.join(tmpRoot, "combined.log");
33436
+ const runnerPath = path28.join(tmpRoot, "_run.bat");
33175
33437
  const q = (p) => `"${p.replace(/"/g, '""')}"`;
33176
33438
  const com = process.env.ComSpec || "cmd.exe";
33177
33439
  try {
33178
- fs24.writeFileSync(
33440
+ fs25.writeFileSync(
33179
33441
  runnerPath,
33180
33442
  `@ECHO OFF\r
33181
33443
  CD /D ${q(cwd)}\r
@@ -33944,30 +34206,30 @@ function createOnBridgeIdentified(opts) {
33944
34206
  }
33945
34207
 
33946
34208
  // src/skills/discover-local-agent-skills.ts
33947
- import fs25 from "node:fs";
33948
- import path28 from "node:path";
34209
+ import fs26 from "node:fs";
34210
+ import path29 from "node:path";
33949
34211
  var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
33950
34212
  function discoverLocalSkills(cwd) {
33951
34213
  const out = [];
33952
34214
  const seenKeys = /* @__PURE__ */ new Set();
33953
34215
  for (const rel of SKILL_DISCOVERY_ROOTS) {
33954
- const base = path28.join(cwd, rel);
33955
- if (!fs25.existsSync(base) || !fs25.statSync(base).isDirectory()) continue;
34216
+ const base = path29.join(cwd, rel);
34217
+ if (!fs26.existsSync(base) || !fs26.statSync(base).isDirectory()) continue;
33956
34218
  let entries = [];
33957
34219
  try {
33958
- entries = fs25.readdirSync(base);
34220
+ entries = fs26.readdirSync(base);
33959
34221
  } catch {
33960
34222
  continue;
33961
34223
  }
33962
34224
  for (const name of entries) {
33963
- const dir = path28.join(base, name);
34225
+ const dir = path29.join(base, name);
33964
34226
  try {
33965
- if (!fs25.statSync(dir).isDirectory()) continue;
34227
+ if (!fs26.statSync(dir).isDirectory()) continue;
33966
34228
  } catch {
33967
34229
  continue;
33968
34230
  }
33969
- const skillMd = path28.join(dir, "SKILL.md");
33970
- if (!fs25.existsSync(skillMd)) continue;
34231
+ const skillMd = path29.join(dir, "SKILL.md");
34232
+ if (!fs26.existsSync(skillMd)) continue;
33971
34233
  const key = `${rel}/${name}`;
33972
34234
  if (seenKeys.has(key)) continue;
33973
34235
  seenKeys.add(key);
@@ -33979,23 +34241,23 @@ function discoverLocalSkills(cwd) {
33979
34241
  function discoverSkillLayoutRoots(cwd) {
33980
34242
  const roots = [];
33981
34243
  for (const rel of SKILL_DISCOVERY_ROOTS) {
33982
- const base = path28.join(cwd, rel);
33983
- if (!fs25.existsSync(base) || !fs25.statSync(base).isDirectory()) continue;
34244
+ const base = path29.join(cwd, rel);
34245
+ if (!fs26.existsSync(base) || !fs26.statSync(base).isDirectory()) continue;
33984
34246
  let entries = [];
33985
34247
  try {
33986
- entries = fs25.readdirSync(base);
34248
+ entries = fs26.readdirSync(base);
33987
34249
  } catch {
33988
34250
  continue;
33989
34251
  }
33990
34252
  const skills2 = [];
33991
34253
  for (const name of entries) {
33992
- const dir = path28.join(base, name);
34254
+ const dir = path29.join(base, name);
33993
34255
  try {
33994
- if (!fs25.statSync(dir).isDirectory()) continue;
34256
+ if (!fs26.statSync(dir).isDirectory()) continue;
33995
34257
  } catch {
33996
34258
  continue;
33997
34259
  }
33998
- if (!fs25.existsSync(path28.join(dir, "SKILL.md"))) continue;
34260
+ if (!fs26.existsSync(path29.join(dir, "SKILL.md"))) continue;
33999
34261
  const relPath = `${rel}/${name}`.replace(/\\/g, "/");
34000
34262
  skills2.push({ name, relPath });
34001
34263
  }
@@ -34177,7 +34439,7 @@ var handleAgentConfigMessage = (msg, deps) => {
34177
34439
  };
34178
34440
 
34179
34441
  // src/prompt-turn-queue/runner.ts
34180
- import fs28 from "node:fs";
34442
+ import fs29 from "node:fs";
34181
34443
 
34182
34444
  // src/prompt-turn-queue/client-report.ts
34183
34445
  function sendPromptQueueClientReport(ws, queues) {
@@ -34187,13 +34449,13 @@ function sendPromptQueueClientReport(ws, queues) {
34187
34449
  }
34188
34450
 
34189
34451
  // src/prompt-turn-queue/disk-store.ts
34190
- import fs27 from "node:fs";
34452
+ import fs28 from "node:fs";
34191
34453
 
34192
34454
  // src/prompt-turn-queue/paths.ts
34193
34455
  import crypto3 from "node:crypto";
34194
- import fs26 from "node:fs";
34195
- import path29 from "node:path";
34196
- import os6 from "node:os";
34456
+ import fs27 from "node:fs";
34457
+ import path30 from "node:path";
34458
+ import os7 from "node:os";
34197
34459
  var QUEUE_KEY_HEX_64 = /^[a-f0-9]{64}$/i;
34198
34460
  function queueStateFileSlug(queueKey) {
34199
34461
  if (QUEUE_KEY_HEX_64.test(queueKey)) return queueKey.toLowerCase();
@@ -34201,15 +34463,15 @@ function queueStateFileSlug(queueKey) {
34201
34463
  }
34202
34464
  function getPromptQueuesDirectory() {
34203
34465
  const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
34204
- if (override) return path29.resolve(override);
34205
- return path29.join(os6.homedir(), ".buildautomaton", "queues");
34466
+ if (override) return path30.resolve(override);
34467
+ return path30.join(os7.homedir(), ".buildautomaton", "queues");
34206
34468
  }
34207
34469
  function ensurePromptQueuesDirectory() {
34208
34470
  const dir = getPromptQueuesDirectory();
34209
- if (!fs26.existsSync(dir)) fs26.mkdirSync(dir, { recursive: true });
34471
+ if (!fs27.existsSync(dir)) fs27.mkdirSync(dir, { recursive: true });
34210
34472
  }
34211
34473
  function queueStateFilePath(queueKey) {
34212
- return path29.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
34474
+ return path30.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
34213
34475
  }
34214
34476
 
34215
34477
  // src/prompt-turn-queue/disk-store.ts
@@ -34234,7 +34496,7 @@ function parsePersistedQueueFile(raw) {
34234
34496
  function readPersistedQueue(queueKey) {
34235
34497
  const p = queueStateFilePath(queueKey);
34236
34498
  try {
34237
- return parsePersistedQueueFile(fs27.readFileSync(p, "utf8"));
34499
+ return parsePersistedQueueFile(fs28.readFileSync(p, "utf8"));
34238
34500
  } catch {
34239
34501
  return null;
34240
34502
  }
@@ -34242,7 +34504,7 @@ function readPersistedQueue(queueKey) {
34242
34504
  function writePersistedQueue(file2) {
34243
34505
  ensurePromptQueuesDirectory();
34244
34506
  const p = queueStateFilePath(file2.queueKey);
34245
- fs27.writeFileSync(p, JSON.stringify(file2, null, 2), "utf8");
34507
+ fs28.writeFileSync(p, JSON.stringify(file2, null, 2), "utf8");
34246
34508
  }
34247
34509
  function mergeServerQueueSnapshot(queueKey, serverTurns) {
34248
34510
  const prev = readPersistedQueue(queueKey);
@@ -34300,7 +34562,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
34300
34562
  const tid = typeof pl.snapshotRevertTurnId === "string" && pl.snapshotRevertTurnId.trim() !== "" ? pl.snapshotRevertTurnId.trim() : next.turnId;
34301
34563
  const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
34302
34564
  const file2 = snapshotFilePath(agentBase, tid);
34303
- if (!fs28.existsSync(file2)) {
34565
+ if (!fs29.existsSync(file2)) {
34304
34566
  deps.log(
34305
34567
  `[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
34306
34568
  );
@@ -34523,9 +34785,9 @@ function parseChangeSummarySnapshots(raw) {
34523
34785
  for (const item of raw) {
34524
34786
  if (!item || typeof item !== "object") continue;
34525
34787
  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 };
34788
+ const path35 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
34789
+ if (!path35) continue;
34790
+ const row = { path: path35 };
34529
34791
  if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
34530
34792
  if (typeof o.oldText === "string") row.oldText = o.oldText;
34531
34793
  if (typeof o.newText === "string") row.newText = o.newText;
@@ -34756,15 +35018,15 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
34756
35018
  };
34757
35019
 
34758
35020
  // src/files/list-dir.ts
34759
- import fs29 from "node:fs";
34760
- import path31 from "node:path";
35021
+ import fs30 from "node:fs";
35022
+ import path32 from "node:path";
34761
35023
 
34762
35024
  // src/files/ensure-under-cwd.ts
34763
- import path30 from "node:path";
35025
+ import path31 from "node:path";
34764
35026
  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) {
35027
+ const normalized = path31.normalize(relativePath).replace(/^(\.\/)+/, "");
35028
+ const resolved = path31.resolve(cwd, normalized);
35029
+ if (!resolved.startsWith(cwd + path31.sep) && resolved !== cwd) {
34768
35030
  return null;
34769
35031
  }
34770
35032
  return resolved;
@@ -34778,7 +35040,7 @@ async function listDirAsync(relativePath) {
34778
35040
  return { error: "Path is outside working directory" };
34779
35041
  }
34780
35042
  try {
34781
- const names = await fs29.promises.readdir(resolved, { withFileTypes: true });
35043
+ const names = await fs30.promises.readdir(resolved, { withFileTypes: true });
34782
35044
  const visible = names.filter((d) => !d.name.startsWith("."));
34783
35045
  const entries = [];
34784
35046
  for (let i = 0; i < visible.length; i++) {
@@ -34786,12 +35048,12 @@ async function listDirAsync(relativePath) {
34786
35048
  await yieldToEventLoop();
34787
35049
  }
34788
35050
  const d = visible[i];
34789
- const entryPath = path31.join(relativePath || ".", d.name).replace(/\\/g, "/");
34790
- const fullPath = path31.join(resolved, d.name);
35051
+ const entryPath = path32.join(relativePath || ".", d.name).replace(/\\/g, "/");
35052
+ const fullPath = path32.join(resolved, d.name);
34791
35053
  let isDir = d.isDirectory();
34792
35054
  if (d.isSymbolicLink()) {
34793
35055
  try {
34794
- const targetStat = await fs29.promises.stat(fullPath);
35056
+ const targetStat = await fs30.promises.stat(fullPath);
34795
35057
  isDir = targetStat.isDirectory();
34796
35058
  } catch {
34797
35059
  isDir = false;
@@ -34816,25 +35078,25 @@ async function listDirAsync(relativePath) {
34816
35078
  }
34817
35079
 
34818
35080
  // src/files/read-file.ts
34819
- import fs30 from "node:fs";
35081
+ import fs31 from "node:fs";
34820
35082
  import { StringDecoder } from "node:string_decoder";
34821
35083
  function resolveFilePath(relativePath) {
34822
35084
  const resolved = ensureUnderCwd(relativePath, getBridgeRoot());
34823
35085
  if (!resolved) return { error: "Path is outside working directory" };
34824
35086
  let real;
34825
35087
  try {
34826
- real = fs30.realpathSync(resolved);
35088
+ real = fs31.realpathSync(resolved);
34827
35089
  } catch {
34828
35090
  real = resolved;
34829
35091
  }
34830
- const stat2 = fs30.statSync(real);
35092
+ const stat2 = fs31.statSync(real);
34831
35093
  if (!stat2.isFile()) return { error: "Not a file" };
34832
35094
  return real;
34833
35095
  }
34834
35096
  var LINE_CHUNK_SIZE = 64 * 1024;
34835
35097
  function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
34836
- const fileSize = fs30.statSync(filePath).size;
34837
- const fd = fs30.openSync(filePath, "r");
35098
+ const fileSize = fs31.statSync(filePath).size;
35099
+ const fd = fs31.openSync(filePath, "r");
34838
35100
  const bufSize = 64 * 1024;
34839
35101
  const buf = Buffer.alloc(bufSize);
34840
35102
  const decoder = new StringDecoder("utf8");
@@ -34847,7 +35109,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
34847
35109
  let line0Accum = "";
34848
35110
  try {
34849
35111
  let bytesRead;
34850
- while (!done && (bytesRead = fs30.readSync(fd, buf, 0, bufSize, null)) > 0) {
35112
+ while (!done && (bytesRead = fs31.readSync(fd, buf, 0, bufSize, null)) > 0) {
34851
35113
  const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
34852
35114
  partial2 = "";
34853
35115
  let lineStart = 0;
@@ -34982,7 +35244,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
34982
35244
  }
34983
35245
  return { content: resultLines.join("\n"), size: fileSize };
34984
35246
  } finally {
34985
- fs30.closeSync(fd);
35247
+ fs31.closeSync(fd);
34986
35248
  }
34987
35249
  }
34988
35250
  function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
@@ -34993,8 +35255,8 @@ function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize =
34993
35255
  if (hasRange) {
34994
35256
  return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
34995
35257
  }
34996
- const stat2 = fs30.statSync(result);
34997
- const raw = fs30.readFileSync(result, "utf8");
35258
+ const stat2 = fs31.statSync(result);
35259
+ const raw = fs31.readFileSync(result, "utf8");
34998
35260
  const lines = raw.split(/\r?\n/);
34999
35261
  return { content: raw, totalLines: lines.length, size: stat2.size };
35000
35262
  } catch (err) {
@@ -35112,8 +35374,8 @@ function handleSkillLayoutRequest(msg, deps) {
35112
35374
  }
35113
35375
 
35114
35376
  // src/skills/install-remote-skills.ts
35115
- import fs31 from "node:fs";
35116
- import path32 from "node:path";
35377
+ import fs32 from "node:fs";
35378
+ import path33 from "node:path";
35117
35379
  function installRemoteSkills(cwd, targetDir, items) {
35118
35380
  const installed2 = [];
35119
35381
  if (!Array.isArray(items)) {
@@ -35124,15 +35386,15 @@ function installRemoteSkills(cwd, targetDir, items) {
35124
35386
  if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
35125
35387
  continue;
35126
35388
  }
35127
- const skillDir = path32.join(cwd, targetDir, item.skillName);
35389
+ const skillDir = path33.join(cwd, targetDir, item.skillName);
35128
35390
  for (const f of item.files) {
35129
35391
  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 });
35392
+ const dest = path33.join(skillDir, f.path);
35393
+ fs32.mkdirSync(path33.dirname(dest), { recursive: true });
35132
35394
  if (f.text !== void 0) {
35133
- fs31.writeFileSync(dest, f.text, "utf8");
35395
+ fs32.writeFileSync(dest, f.text, "utf8");
35134
35396
  } else if (f.base64) {
35135
- fs31.writeFileSync(dest, Buffer.from(f.base64, "base64"));
35397
+ fs32.writeFileSync(dest, Buffer.from(f.base64, "base64"));
35136
35398
  }
35137
35399
  }
35138
35400
  installed2.push({
@@ -35282,7 +35544,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
35282
35544
  };
35283
35545
 
35284
35546
  // src/routing/handlers/revert-turn-snapshot.ts
35285
- import * as fs32 from "node:fs";
35547
+ import * as fs33 from "node:fs";
35286
35548
  var handleRevertTurnSnapshotMessage = (msg, deps) => {
35287
35549
  const id = typeof msg.id === "string" ? msg.id : "";
35288
35550
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
@@ -35294,7 +35556,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
35294
35556
  if (!s) return;
35295
35557
  const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
35296
35558
  const file2 = snapshotFilePath(agentBase, turnId);
35297
- if (!fs32.existsSync(file2)) {
35559
+ if (!fs33.existsSync(file2)) {
35298
35560
  sendWsMessage(s, {
35299
35561
  type: "revert_turn_snapshot_result",
35300
35562
  id,
@@ -35735,8 +35997,8 @@ async function createBridgeConnection(options) {
35735
35997
  getCloudAccessToken: () => tokens.accessToken
35736
35998
  };
35737
35999
  const identifyReportedPaths = {
35738
- bridgeRootPath: path33.resolve(getBridgeRoot()),
35739
- worktreesRootPath: path33.resolve(worktreesRootPath)
36000
+ bridgeRootPath: path34.resolve(getBridgeRoot()),
36001
+ worktreesRootPath: path34.resolve(worktreesRootPath)
35740
36002
  };
35741
36003
  const { connect } = createMainBridgeWebSocketLifecycle({
35742
36004
  state,