@buildautomaton/cli 0.1.28 → 0.1.29

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: path35, errorMaps, issueData } = params;
4069
- const fullPath = [...path35, ...issueData.path || []];
4068
+ const { data, path: path39, errorMaps, issueData } = params;
4069
+ const fullPath = [...path39, ...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, path35, key) {
4377
+ constructor(parent, value, path39, key) {
4378
4378
  this._cachedPath = [];
4379
4379
  this.parent = parent;
4380
4380
  this.data = value;
4381
- this._path = path35;
4381
+ this._path = path39;
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, path35) {
7997
- if (!path35)
7996
+ function getElementAtPath(obj, path39) {
7997
+ if (!path39)
7998
7998
  return obj;
7999
- return path35.reduce((acc, key) => acc?.[key], obj);
7999
+ return path39.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(path35, issues) {
8248
+ function prefixIssues(path39, issues) {
8249
8249
  return issues.map((iss) => {
8250
8250
  var _a2;
8251
8251
  (_a2 = iss).path ?? (_a2.path = []);
8252
- iss.path.unshift(path35);
8252
+ iss.path.unshift(path39);
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, path35 = []) => {
8441
+ const processError = (error41, path39 = []) => {
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 = [...path35, ...issue2.path];
8451
+ const fullpath = [...path39, ...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(path35) {
8481
+ function toDotPath(path39) {
8482
8482
  const segs = [];
8483
- for (const seg of path35) {
8483
+ for (const seg of path39) {
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 os8 = __require("os");
21672
+ var os9 = __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 = os8.release().split(".");
21720
+ const osRelease = os9.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(path35, isFile, isDirectory) {
21967
- log2(`checking %s`, path35);
21966
+ function check2(path39, isFile, isDirectory) {
21967
+ log2(`checking %s`, path39);
21968
21968
  try {
21969
- const stat2 = fs_1.statSync(path35);
21969
+ const stat2 = fs_1.statSync(path39);
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(path35, type = exports.READABLE) {
21990
- return check2(path35, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
21989
+ function exists2(path39, type = exports.READABLE) {
21990
+ return check2(path39, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
21991
21991
  }
21992
21992
  exports.exists = exists2;
21993
21993
  exports.FILE = 1;
@@ -22792,9 +22792,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
22792
22792
  const rawPath = typeof o.path === "string" ? o.path.trim() : "";
22793
22793
  const summary = typeof o.summary === "string" ? o.summary.trim() : "";
22794
22794
  if (!rawPath || !summary) continue;
22795
- const path35 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
22796
- if (!path35) continue;
22797
- rows.push({ path: path35, summary: clampSummaryToAtMostTwoLines(summary) });
22795
+ const path39 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
22796
+ if (!path39) continue;
22797
+ rows.push({ path: path39, summary: clampSummaryToAtMostTwoLines(summary) });
22798
22798
  }
22799
22799
  return rows;
22800
22800
  }
@@ -23668,8 +23668,8 @@ function randomSecret() {
23668
23668
  }
23669
23669
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
23670
23670
  }
23671
- async function requestPreviewApi(port, secret, method, path35, body) {
23672
- const url2 = `http://127.0.0.1:${port}${path35}`;
23671
+ async function requestPreviewApi(port, secret, method, path39, body) {
23672
+ const url2 = `http://127.0.0.1:${port}${path39}`;
23673
23673
  const headers = {
23674
23674
  [PREVIEW_SECRET_HEADER]: secret,
23675
23675
  "Content-Type": "application/json"
@@ -23681,7 +23681,7 @@ async function requestPreviewApi(port, secret, method, path35, body) {
23681
23681
  });
23682
23682
  const data = await res.json().catch(() => ({}));
23683
23683
  if (!res.ok) {
23684
- throw new Error(data?.error ?? `Preview API ${method} ${path35}: ${res.status}`);
23684
+ throw new Error(data?.error ?? `Preview API ${method} ${path39}: ${res.status}`);
23685
23685
  }
23686
23686
  return data;
23687
23687
  }
@@ -23896,7 +23896,7 @@ function installBridgeProcessResilience() {
23896
23896
  }
23897
23897
 
23898
23898
  // src/cli-version.ts
23899
- var CLI_VERSION = "0.1.28".length > 0 ? "0.1.28" : "0.0.0-dev";
23899
+ var CLI_VERSION = "0.1.29".length > 0 ? "0.1.29" : "0.0.0-dev";
23900
23900
 
23901
23901
  // src/connection/heartbeat/constants.ts
23902
23902
  var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
@@ -24956,6 +24956,321 @@ function runPendingAuth(options) {
24956
24956
  };
24957
24957
  }
24958
24958
 
24959
+ // src/sqlite/cli-database.ts
24960
+ import sqliteWasm from "node-sqlite3-wasm";
24961
+
24962
+ // src/sqlite/cli-sqlite-paths.ts
24963
+ import fs7 from "node:fs";
24964
+ import path5 from "node:path";
24965
+ import os3 from "node:os";
24966
+ function getCliSqlitePath() {
24967
+ const override = process.env.BUILDAMATON_CLI_SQLITE_PATH?.trim();
24968
+ if (override) return path5.resolve(override);
24969
+ return path5.join(os3.homedir(), ".buildautomaton", "cli.sqlite");
24970
+ }
24971
+ function ensureCliSqliteParentDir(sqlitePath) {
24972
+ const dir = path5.dirname(sqlitePath);
24973
+ if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
24974
+ }
24975
+
24976
+ // src/sqlite/legacy_migration/import-cli-legacy-disk-data.ts
24977
+ import fs12 from "node:fs";
24978
+
24979
+ // src/files/index/constants.ts
24980
+ import path6 from "node:path";
24981
+ import os4 from "node:os";
24982
+ var INDEX_WORK_YIELD_EVERY = 256;
24983
+ var INDEX_DIR = path6.join(os4.homedir(), ".buildautomaton");
24984
+ var INDEX_HASH_LEN = 16;
24985
+
24986
+ // src/prompt-turn-queue/paths.ts
24987
+ import path7 from "node:path";
24988
+ import os5 from "node:os";
24989
+ function getPromptQueuesDirectory() {
24990
+ const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
24991
+ if (override) return path7.resolve(override);
24992
+ return path7.join(os5.homedir(), ".buildautomaton", "queues");
24993
+ }
24994
+
24995
+ // src/sqlite/legacy_migration/archive-file-index-json.ts
24996
+ import fs9 from "node:fs";
24997
+ import path9 from "node:path";
24998
+
24999
+ // src/sqlite/legacy_migration/archive-to-old-version.ts
25000
+ import fs8 from "node:fs";
25001
+ import path8 from "node:path";
25002
+ var OLD_VERSION_DIR = path8.join(INDEX_DIR, "old-version");
25003
+ function moveLegacyFileToOldVersionBackup(category, sourcePath) {
25004
+ const destDir = path8.join(OLD_VERSION_DIR, category);
25005
+ fs8.mkdirSync(destDir, { recursive: true });
25006
+ const base = path8.basename(sourcePath);
25007
+ let dest = path8.join(destDir, base);
25008
+ if (fs8.existsSync(dest)) {
25009
+ const ext = path8.extname(base);
25010
+ const stem = ext ? base.slice(0, -ext.length) : base;
25011
+ dest = path8.join(destDir, `${stem}-${Date.now()}${ext}`);
25012
+ }
25013
+ fs8.renameSync(sourcePath, dest);
25014
+ }
25015
+
25016
+ // src/sqlite/legacy_migration/archive-file-index-json.ts
25017
+ function archiveLegacyFileIndexJsonFiles() {
25018
+ try {
25019
+ if (!fs9.existsSync(INDEX_DIR)) return;
25020
+ for (const name of fs9.readdirSync(INDEX_DIR)) {
25021
+ if (name.startsWith(".file-index-") && name.endsWith(".json")) {
25022
+ const full = path9.join(INDEX_DIR, name);
25023
+ try {
25024
+ moveLegacyFileToOldVersionBackup("file-index", full);
25025
+ } catch (err) {
25026
+ console.error(`[cli-sqlite] legacy import: could not archive ${name}`, err);
25027
+ }
25028
+ }
25029
+ }
25030
+ } catch (e) {
25031
+ console.error("[cli-sqlite] legacy import: archive file-index json failed", e);
25032
+ }
25033
+ }
25034
+
25035
+ // src/sqlite/legacy_migration/import-agent-sessions-from-disk.ts
25036
+ import fs10 from "node:fs";
25037
+ import path10 from "node:path";
25038
+ import os6 from "node:os";
25039
+ var LEGACY_AGENT_SESSION_DIR = path10.join(os6.homedir(), ".buildautomaton", "agent-sessions");
25040
+ function importLegacyAgentSessionsFromDisk(db) {
25041
+ try {
25042
+ if (!fs10.existsSync(LEGACY_AGENT_SESSION_DIR)) return;
25043
+ const names = fs10.readdirSync(LEGACY_AGENT_SESSION_DIR).filter((n) => n.endsWith(".json"));
25044
+ for (const name of names) {
25045
+ const sessionKey = name.slice(0, -".json".length);
25046
+ const full = path10.join(LEGACY_AGENT_SESSION_DIR, name);
25047
+ let raw;
25048
+ try {
25049
+ raw = fs10.readFileSync(full, "utf8");
25050
+ } catch {
25051
+ continue;
25052
+ }
25053
+ let parsed;
25054
+ try {
25055
+ parsed = JSON.parse(raw);
25056
+ } catch {
25057
+ continue;
25058
+ }
25059
+ if (parsed.v !== 1) continue;
25060
+ const acpSessionId = typeof parsed.acpSessionId === "string" ? parsed.acpSessionId : null;
25061
+ const backendAgentType = typeof parsed.backendAgentType === "string" ? parsed.backendAgentType : null;
25062
+ const configOptionsJson = Array.isArray(parsed.configOptions) ? JSON.stringify(parsed.configOptions) : null;
25063
+ const updatedAt = typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString();
25064
+ db.run(
25065
+ `INSERT OR REPLACE INTO agent_session (session_key, acp_session_id, backend_agent_type, config_options_json, updated_at)
25066
+ VALUES (?, ?, ?, ?, ?)`,
25067
+ [sessionKey, acpSessionId, backendAgentType, configOptionsJson, updatedAt]
25068
+ );
25069
+ try {
25070
+ moveLegacyFileToOldVersionBackup("agent-sessions", full);
25071
+ } catch {
25072
+ }
25073
+ }
25074
+ } catch (e) {
25075
+ console.error("[cli-sqlite] legacy import: agent_sessions from disk failed", e);
25076
+ }
25077
+ }
25078
+
25079
+ // src/sqlite/legacy_migration/import-prompt-queues-from-disk.ts
25080
+ import fs11 from "node:fs";
25081
+ import path11 from "node:path";
25082
+
25083
+ // src/sqlite/legacy_migration/parse-persisted-queue-json.ts
25084
+ function parsePersistedQueueFromJson(raw) {
25085
+ try {
25086
+ const o = JSON.parse(raw);
25087
+ const queueKey = typeof o.queueKey === "string" ? o.queueKey : typeof o.queueKeyHash === "string" ? o.queueKeyHash : null;
25088
+ if (!queueKey || typeof o.updatedAt !== "string" || !Array.isArray(o.turns)) return null;
25089
+ return { queueKey, updatedAt: o.updatedAt, turns: o.turns };
25090
+ } catch {
25091
+ return null;
25092
+ }
25093
+ }
25094
+
25095
+ // src/sqlite/legacy_migration/import-prompt-queues-from-disk.ts
25096
+ function importLegacyPromptQueuesFromDisk(db) {
25097
+ try {
25098
+ const dir = getPromptQueuesDirectory();
25099
+ if (!fs11.existsSync(dir)) return;
25100
+ for (const name of fs11.readdirSync(dir)) {
25101
+ if (!name.endsWith(".json")) continue;
25102
+ const full = path11.join(dir, name);
25103
+ let raw;
25104
+ try {
25105
+ raw = fs11.readFileSync(full, "utf8");
25106
+ } catch {
25107
+ continue;
25108
+ }
25109
+ const file2 = parsePersistedQueueFromJson(raw);
25110
+ if (!file2) continue;
25111
+ db.run(
25112
+ `INSERT OR REPLACE INTO prompt_queue (queue_key, updated_at, turns_json) VALUES (?, ?, ?)`,
25113
+ [file2.queueKey, file2.updatedAt, JSON.stringify(file2.turns)]
25114
+ );
25115
+ try {
25116
+ moveLegacyFileToOldVersionBackup("queues", full);
25117
+ } catch {
25118
+ }
25119
+ }
25120
+ } catch (e) {
25121
+ console.error("[cli-sqlite] legacy import: prompt queues from disk failed", e);
25122
+ }
25123
+ }
25124
+
25125
+ // src/sqlite/legacy_migration/import-cli-legacy-disk-data.ts
25126
+ function legacyCliDiskMigrationIsPending() {
25127
+ try {
25128
+ if (fs12.existsSync(INDEX_DIR)) {
25129
+ for (const name of fs12.readdirSync(INDEX_DIR)) {
25130
+ if (name.startsWith(".file-index-") && name.endsWith(".json")) return true;
25131
+ }
25132
+ }
25133
+ } catch {
25134
+ }
25135
+ try {
25136
+ if (fs12.existsSync(LEGACY_AGENT_SESSION_DIR)) {
25137
+ if (fs12.readdirSync(LEGACY_AGENT_SESSION_DIR).some((n) => n.endsWith(".json"))) return true;
25138
+ }
25139
+ } catch {
25140
+ }
25141
+ try {
25142
+ const dir = getPromptQueuesDirectory();
25143
+ if (fs12.existsSync(dir) && fs12.readdirSync(dir).some((n) => n.endsWith(".json"))) return true;
25144
+ } catch {
25145
+ }
25146
+ return false;
25147
+ }
25148
+ function importCliSqliteLegacyDiskData(db, log2) {
25149
+ const pending = legacyCliDiskMigrationIsPending();
25150
+ if (pending && log2) {
25151
+ log2("Migrating legacy on-disk CLI data to SQLite\u2026");
25152
+ }
25153
+ archiveLegacyFileIndexJsonFiles();
25154
+ importLegacyAgentSessionsFromDisk(db);
25155
+ importLegacyPromptQueuesFromDisk(db);
25156
+ if (pending && log2) {
25157
+ log2("Legacy on-disk CLI data migration finished.");
25158
+ }
25159
+ }
25160
+
25161
+ // src/sqlite/load-cli-migration-sql.ts
25162
+ import { existsSync, readFileSync as readFileSync2 } from "node:fs";
25163
+ import { dirname as dirname2, join } from "node:path";
25164
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
25165
+ function readCliSqliteMigrationSql(filename) {
25166
+ const dir = dirname2(fileURLToPath2(import.meta.url));
25167
+ const resolved = join(dir, "migrations", filename);
25168
+ if (!existsSync(resolved)) {
25169
+ throw new Error(`Missing CLI SQLite migration SQL: ${resolved}`);
25170
+ }
25171
+ return readFileSync2(resolved, "utf8");
25172
+ }
25173
+
25174
+ // src/sqlite/migrate-cli-sqlite.ts
25175
+ function checkpointSatisfiedByLegacyChain(applied2, replacesLegacyMigrations) {
25176
+ return Array.isArray(replacesLegacyMigrations) && replacesLegacyMigrations.length > 0 && replacesLegacyMigrations.every((n) => applied2.has(n));
25177
+ }
25178
+ function recordMigrationAndPruneCheckpointLegacy(db, migration, applied2) {
25179
+ db.run("INSERT INTO __migrations (name) VALUES (?)", [migration.name]);
25180
+ applied2.add(migration.name);
25181
+ if (migration.checkpoint !== true) return;
25182
+ const legacy = migration.replacesLegacyMigrations;
25183
+ if (!legacy?.length) return;
25184
+ for (const legacyName of legacy) {
25185
+ if (legacyName === migration.name) continue;
25186
+ db.run("DELETE FROM __migrations WHERE name = ?", [legacyName]);
25187
+ applied2.delete(legacyName);
25188
+ }
25189
+ }
25190
+ var CHECKPOINT_V1 = "001_cli_sqlite_checkpoint_v1";
25191
+ var CHECKPOINT_V1_SQL = readCliSqliteMigrationSql("001_cli_sqlite_checkpoint_v1.sql");
25192
+ var CLI_SQLITE_MIGRATIONS = [
25193
+ {
25194
+ name: CHECKPOINT_V1,
25195
+ checkpoint: true,
25196
+ migrate: (db) => {
25197
+ db.exec(CHECKPOINT_V1_SQL);
25198
+ }
25199
+ }
25200
+ ];
25201
+ function migrateCliSqlite(db) {
25202
+ db.exec(readCliSqliteMigrationSql("000_bootstrap_migrations_table.sql"));
25203
+ const appliedRows = db.all("SELECT name FROM __migrations");
25204
+ const applied2 = new Set(appliedRows.map((r) => r.name));
25205
+ for (const migration of CLI_SQLITE_MIGRATIONS) {
25206
+ if (applied2.has(migration.name)) continue;
25207
+ if (migration.checkpoint === true && checkpointSatisfiedByLegacyChain(applied2, migration.replacesLegacyMigrations)) {
25208
+ recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
25209
+ continue;
25210
+ }
25211
+ if (migration.alreadyApplied?.(db)) {
25212
+ recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
25213
+ continue;
25214
+ }
25215
+ try {
25216
+ migration.migrate(db);
25217
+ recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
25218
+ } catch (e) {
25219
+ console.error(`[cli-sqlite] Migration failed: ${migration.name}`, e);
25220
+ throw e;
25221
+ }
25222
+ }
25223
+ }
25224
+
25225
+ // src/sqlite/cli-database.ts
25226
+ var { Database: SqliteDatabase } = sqliteWasm;
25227
+ var openDatabases = /* @__PURE__ */ new Map();
25228
+ var processExitCloseRegistered = false;
25229
+ function registerProcessExitSqliteClose() {
25230
+ if (processExitCloseRegistered) return;
25231
+ processExitCloseRegistered = true;
25232
+ process.once("exit", () => {
25233
+ for (const db of openDatabases.values()) {
25234
+ safeCloseCliSqliteDatabase(db);
25235
+ }
25236
+ openDatabases.clear();
25237
+ });
25238
+ }
25239
+ function safeCloseCliSqliteDatabase(db) {
25240
+ if (db == null) return;
25241
+ try {
25242
+ if (db.isOpen) db.close();
25243
+ } catch {
25244
+ }
25245
+ }
25246
+ function closeAllCliSqliteConnections() {
25247
+ for (const db of openDatabases.values()) {
25248
+ safeCloseCliSqliteDatabase(db);
25249
+ }
25250
+ openDatabases.clear();
25251
+ }
25252
+ function getCliDatabase(options) {
25253
+ const sqlitePath = getCliSqlitePath();
25254
+ const existing = openDatabases.get(sqlitePath);
25255
+ if (existing?.isOpen) return existing;
25256
+ if (existing && !existing.isOpen) {
25257
+ safeCloseCliSqliteDatabase(existing);
25258
+ openDatabases.delete(sqlitePath);
25259
+ }
25260
+ ensureCliSqliteParentDir(sqlitePath);
25261
+ const db = new SqliteDatabase(sqlitePath);
25262
+ try {
25263
+ migrateCliSqlite(db);
25264
+ importCliSqliteLegacyDiskData(db, options?.logLegacyMigration);
25265
+ } catch (e) {
25266
+ safeCloseCliSqliteDatabase(db);
25267
+ throw e;
25268
+ }
25269
+ openDatabases.set(sqlitePath, db);
25270
+ registerProcessExitSqliteClose();
25271
+ return db;
25272
+ }
25273
+
24959
25274
  // src/connection/close-bridge-connection.ts
24960
25275
  async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
24961
25276
  const say = log2 ?? logImmediate;
@@ -24999,20 +25314,24 @@ async function closeBridgeConnection(state, acpManager, devServerManager, log2)
24999
25314
  say("Stopping local dev server processes\u2026");
25000
25315
  await devServerManager.shutdownAllGraceful();
25001
25316
  }
25317
+ try {
25318
+ closeAllCliSqliteConnections();
25319
+ } catch {
25320
+ }
25002
25321
  say("Shutdown complete.");
25003
25322
  }
25004
25323
 
25005
25324
  // src/paths/session-layout-paths.ts
25006
- import * as path5 from "node:path";
25325
+ import * as path12 from "node:path";
25007
25326
  function resolveIsolatedSessionParentPathFromCheckouts(worktreePaths) {
25008
- const resolved = worktreePaths.map((p) => path5.resolve(p)).filter(Boolean);
25327
+ const resolved = worktreePaths.map((p) => path12.resolve(p)).filter(Boolean);
25009
25328
  if (resolved.length === 0) return null;
25010
25329
  resolved.sort();
25011
25330
  return resolved[0];
25012
25331
  }
25013
25332
  function resolveSessionParentPathForAgentProcess(resolvedSessionParentPath) {
25014
25333
  if (resolvedSessionParentPath != null && String(resolvedSessionParentPath).trim() !== "") {
25015
- return path5.resolve(String(resolvedSessionParentPath).trim());
25334
+ return path12.resolve(String(resolvedSessionParentPath).trim());
25016
25335
  }
25017
25336
  return getBridgeRoot();
25018
25337
  }
@@ -25021,17 +25340,17 @@ function resolveSessionParentPathForAgentProcess(resolvedSessionParentPath) {
25021
25340
  import { execFile as execFile7 } from "node:child_process";
25022
25341
  import { readFile, stat } from "node:fs/promises";
25023
25342
  import { promisify as promisify7 } from "node:util";
25024
- import * as path8 from "node:path";
25343
+ import * as path15 from "node:path";
25025
25344
 
25026
25345
  // src/git/pre-turn-snapshot.ts
25027
- import * as fs8 from "node:fs";
25028
- import * as path7 from "node:path";
25346
+ import * as fs14 from "node:fs";
25347
+ import * as path14 from "node:path";
25029
25348
  import { execFile as execFile6 } from "node:child_process";
25030
25349
  import { promisify as promisify6 } from "node:util";
25031
25350
 
25032
25351
  // src/git/discover-repos.ts
25033
- import * as fs7 from "node:fs";
25034
- import * as path6 from "node:path";
25352
+ import * as fs13 from "node:fs";
25353
+ import * as path13 from "node:path";
25035
25354
 
25036
25355
  // ../../node_modules/.pnpm/simple-git@3.32.3/node_modules/simple-git/dist/esm/index.js
25037
25356
  var import_file_exists = __toESM(require_dist(), 1);
@@ -25070,8 +25389,8 @@ function pathspec(...paths) {
25070
25389
  cache.set(key, paths);
25071
25390
  return key;
25072
25391
  }
25073
- function isPathSpec(path35) {
25074
- return path35 instanceof String && cache.has(path35);
25392
+ function isPathSpec(path39) {
25393
+ return path39 instanceof String && cache.has(path39);
25075
25394
  }
25076
25395
  function toPaths(pathSpec) {
25077
25396
  return cache.get(pathSpec) || [];
@@ -25160,8 +25479,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
25160
25479
  function forEachLineWithContent(input, callback) {
25161
25480
  return toLinesWithContent(input, true).map((line) => callback(line));
25162
25481
  }
25163
- function folderExists(path35) {
25164
- return (0, import_file_exists.exists)(path35, import_file_exists.FOLDER);
25482
+ function folderExists(path39) {
25483
+ return (0, import_file_exists.exists)(path39, import_file_exists.FOLDER);
25165
25484
  }
25166
25485
  function append(target, item) {
25167
25486
  if (Array.isArray(target)) {
@@ -25565,8 +25884,8 @@ function checkIsRepoRootTask() {
25565
25884
  commands,
25566
25885
  format: "utf-8",
25567
25886
  onError,
25568
- parser(path35) {
25569
- return /^\.(git)?$/.test(path35.trim());
25887
+ parser(path39) {
25888
+ return /^\.(git)?$/.test(path39.trim());
25570
25889
  }
25571
25890
  };
25572
25891
  }
@@ -26000,11 +26319,11 @@ function parseGrep(grep) {
26000
26319
  const paths = /* @__PURE__ */ new Set();
26001
26320
  const results = {};
26002
26321
  forEachLineWithContent(grep, (input) => {
26003
- const [path35, line, preview] = input.split(NULL);
26004
- paths.add(path35);
26005
- (results[path35] = results[path35] || []).push({
26322
+ const [path39, line, preview] = input.split(NULL);
26323
+ paths.add(path39);
26324
+ (results[path39] = results[path39] || []).push({
26006
26325
  line: asNumber(line),
26007
- path: path35,
26326
+ path: path39,
26008
26327
  preview
26009
26328
  });
26010
26329
  });
@@ -26769,14 +27088,14 @@ var init_hash_object = __esm2({
26769
27088
  init_task();
26770
27089
  }
26771
27090
  });
26772
- function parseInit(bare, path35, text) {
27091
+ function parseInit(bare, path39, text) {
26773
27092
  const response = String(text).trim();
26774
27093
  let result;
26775
27094
  if (result = initResponseRegex.exec(response)) {
26776
- return new InitSummary(bare, path35, false, result[1]);
27095
+ return new InitSummary(bare, path39, false, result[1]);
26777
27096
  }
26778
27097
  if (result = reInitResponseRegex.exec(response)) {
26779
- return new InitSummary(bare, path35, true, result[1]);
27098
+ return new InitSummary(bare, path39, true, result[1]);
26780
27099
  }
26781
27100
  let gitDir = "";
26782
27101
  const tokens = response.split(" ");
@@ -26787,7 +27106,7 @@ function parseInit(bare, path35, text) {
26787
27106
  break;
26788
27107
  }
26789
27108
  }
26790
- return new InitSummary(bare, path35, /^re/i.test(response), gitDir);
27109
+ return new InitSummary(bare, path39, /^re/i.test(response), gitDir);
26791
27110
  }
26792
27111
  var InitSummary;
26793
27112
  var initResponseRegex;
@@ -26796,9 +27115,9 @@ var init_InitSummary = __esm2({
26796
27115
  "src/lib/responses/InitSummary.ts"() {
26797
27116
  "use strict";
26798
27117
  InitSummary = class {
26799
- constructor(bare, path35, existing, gitDir) {
27118
+ constructor(bare, path39, existing, gitDir) {
26800
27119
  this.bare = bare;
26801
- this.path = path35;
27120
+ this.path = path39;
26802
27121
  this.existing = existing;
26803
27122
  this.gitDir = gitDir;
26804
27123
  }
@@ -26810,7 +27129,7 @@ var init_InitSummary = __esm2({
26810
27129
  function hasBareCommand(command) {
26811
27130
  return command.includes(bareCommand);
26812
27131
  }
26813
- function initTask(bare = false, path35, customArgs) {
27132
+ function initTask(bare = false, path39, customArgs) {
26814
27133
  const commands = ["init", ...customArgs];
26815
27134
  if (bare && !hasBareCommand(commands)) {
26816
27135
  commands.splice(1, 0, bareCommand);
@@ -26819,7 +27138,7 @@ function initTask(bare = false, path35, customArgs) {
26819
27138
  commands,
26820
27139
  format: "utf-8",
26821
27140
  parser(text) {
26822
- return parseInit(commands.includes("--bare"), path35, text);
27141
+ return parseInit(commands.includes("--bare"), path39, text);
26823
27142
  }
26824
27143
  };
26825
27144
  }
@@ -27635,12 +27954,12 @@ var init_FileStatusSummary = __esm2({
27635
27954
  "use strict";
27636
27955
  fromPathRegex = /^(.+)\0(.+)$/;
27637
27956
  FileStatusSummary = class {
27638
- constructor(path35, index, working_dir) {
27639
- this.path = path35;
27957
+ constructor(path39, index, working_dir) {
27958
+ this.path = path39;
27640
27959
  this.index = index;
27641
27960
  this.working_dir = working_dir;
27642
27961
  if (index === "R" || working_dir === "R") {
27643
- const detail = fromPathRegex.exec(path35) || [null, path35, path35];
27962
+ const detail = fromPathRegex.exec(path39) || [null, path39, path39];
27644
27963
  this.from = detail[2] || "";
27645
27964
  this.path = detail[1] || "";
27646
27965
  }
@@ -27671,14 +27990,14 @@ function splitLine(result, lineStr) {
27671
27990
  default:
27672
27991
  return;
27673
27992
  }
27674
- function data(index, workingDir, path35) {
27993
+ function data(index, workingDir, path39) {
27675
27994
  const raw = `${index}${workingDir}`;
27676
27995
  const handler = parsers6.get(raw);
27677
27996
  if (handler) {
27678
- handler(result, path35);
27997
+ handler(result, path39);
27679
27998
  }
27680
27999
  if (raw !== "##" && raw !== "!!") {
27681
- result.files.push(new FileStatusSummary(path35, index, workingDir));
28000
+ result.files.push(new FileStatusSummary(path39, index, workingDir));
27682
28001
  }
27683
28002
  }
27684
28003
  }
@@ -27951,15 +28270,15 @@ var init_simple_git_api = __esm2({
27951
28270
  this._executor = _executor;
27952
28271
  }
27953
28272
  _runTask(task, then) {
27954
- const chain = this._executor.chain();
27955
- const promise2 = chain.push(task);
28273
+ const chain2 = this._executor.chain();
28274
+ const promise2 = chain2.push(task);
27956
28275
  if (then) {
27957
28276
  taskCallback(task, promise2, then);
27958
28277
  }
27959
28278
  return Object.create(this, {
27960
28279
  then: { value: promise2.then.bind(promise2) },
27961
28280
  catch: { value: promise2.catch.bind(promise2) },
27962
- _executor: { value: chain }
28281
+ _executor: { value: chain2 }
27963
28282
  });
27964
28283
  }
27965
28284
  add(files) {
@@ -27987,9 +28306,9 @@ var init_simple_git_api = __esm2({
27987
28306
  next
27988
28307
  );
27989
28308
  }
27990
- hashObject(path35, write) {
28309
+ hashObject(path39, write) {
27991
28310
  return this._runTask(
27992
- hashObjectTask(path35, write === true),
28311
+ hashObjectTask(path39, write === true),
27993
28312
  trailingFunctionArgument(arguments)
27994
28313
  );
27995
28314
  }
@@ -28342,8 +28661,8 @@ var init_branch = __esm2({
28342
28661
  }
28343
28662
  });
28344
28663
  function toPath(input) {
28345
- const path35 = input.trim().replace(/^["']|["']$/g, "");
28346
- return path35 && normalize2(path35);
28664
+ const path39 = input.trim().replace(/^["']|["']$/g, "");
28665
+ return path39 && normalize2(path39);
28347
28666
  }
28348
28667
  var parseCheckIgnore;
28349
28668
  var init_CheckIgnore = __esm2({
@@ -28657,8 +28976,8 @@ __export2(sub_module_exports, {
28657
28976
  subModuleTask: () => subModuleTask,
28658
28977
  updateSubModuleTask: () => updateSubModuleTask
28659
28978
  });
28660
- function addSubModuleTask(repo, path35) {
28661
- return subModuleTask(["add", repo, path35]);
28979
+ function addSubModuleTask(repo, path39) {
28980
+ return subModuleTask(["add", repo, path39]);
28662
28981
  }
28663
28982
  function initSubModuleTask(customArgs) {
28664
28983
  return subModuleTask(["init", ...customArgs]);
@@ -28991,8 +29310,8 @@ var require_git = __commonJS2({
28991
29310
  }
28992
29311
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
28993
29312
  };
28994
- Git2.prototype.submoduleAdd = function(repo, path35, then) {
28995
- return this._runTask(addSubModuleTask2(repo, path35), trailingFunctionArgument2(arguments));
29313
+ Git2.prototype.submoduleAdd = function(repo, path39, then) {
29314
+ return this._runTask(addSubModuleTask2(repo, path39), trailingFunctionArgument2(arguments));
28996
29315
  };
28997
29316
  Git2.prototype.submoduleUpdate = function(args, then) {
28998
29317
  return this._runTask(
@@ -29636,20 +29955,20 @@ async function isGitRepoDirectory(dirPath) {
29636
29955
  // src/git/discover-repos.ts
29637
29956
  async function discoverGitRepos(cwd = getBridgeRoot()) {
29638
29957
  const result = [];
29639
- const cwdResolved = path6.resolve(cwd);
29958
+ const cwdResolved = path13.resolve(cwd);
29640
29959
  if (await isGitRepoDirectory(cwdResolved)) {
29641
29960
  const remoteUrl = await getRemoteOriginUrl(cwdResolved);
29642
29961
  result.push({ absolutePath: cwdResolved, remoteUrl });
29643
29962
  }
29644
29963
  let entries;
29645
29964
  try {
29646
- entries = fs7.readdirSync(cwdResolved, { withFileTypes: true });
29965
+ entries = fs13.readdirSync(cwdResolved, { withFileTypes: true });
29647
29966
  } catch {
29648
29967
  return result;
29649
29968
  }
29650
29969
  for (const ent of entries) {
29651
29970
  if (!ent.isDirectory()) continue;
29652
- const childPath = path6.join(cwdResolved, ent.name);
29971
+ const childPath = path13.join(cwdResolved, ent.name);
29653
29972
  if (await isGitRepoDirectory(childPath)) {
29654
29973
  const remoteUrl = await getRemoteOriginUrl(childPath);
29655
29974
  result.push({ absolutePath: childPath, remoteUrl });
@@ -29658,22 +29977,22 @@ async function discoverGitRepos(cwd = getBridgeRoot()) {
29658
29977
  return result;
29659
29978
  }
29660
29979
  async function discoverGitReposUnderRoot(rootPath) {
29661
- const root = path6.resolve(rootPath);
29980
+ const root = path13.resolve(rootPath);
29662
29981
  const roots = [];
29663
29982
  async function walk(dir) {
29664
29983
  if (await isGitRepoDirectory(dir)) {
29665
- roots.push(path6.resolve(dir));
29984
+ roots.push(path13.resolve(dir));
29666
29985
  return;
29667
29986
  }
29668
29987
  let entries;
29669
29988
  try {
29670
- entries = fs7.readdirSync(dir, { withFileTypes: true });
29989
+ entries = fs13.readdirSync(dir, { withFileTypes: true });
29671
29990
  } catch {
29672
29991
  return;
29673
29992
  }
29674
29993
  for (const ent of entries) {
29675
29994
  if (!ent.isDirectory() || ent.name === ".git") continue;
29676
- await walk(path6.join(dir, ent.name));
29995
+ await walk(path13.join(dir, ent.name));
29677
29996
  }
29678
29997
  }
29679
29998
  await walk(root);
@@ -29689,7 +30008,7 @@ async function discoverGitReposUnderRoot(rootPath) {
29689
30008
  // src/git/pre-turn-snapshot.ts
29690
30009
  var execFileAsync5 = promisify6(execFile6);
29691
30010
  function snapshotsDirForCwd(agentCwd) {
29692
- return path7.join(agentCwd, ".buildautomaton", "snapshots");
30011
+ return path14.join(agentCwd, ".buildautomaton", "snapshots");
29693
30012
  }
29694
30013
  async function gitStashCreate(repoRoot, log2) {
29695
30014
  try {
@@ -29718,7 +30037,7 @@ async function gitRun(repoRoot, args, log2, label) {
29718
30037
  async function resolveSnapshotRepoRoots(options) {
29719
30038
  const { worktreePaths, fallbackCwd, sessionId, log: log2 } = options;
29720
30039
  if (worktreePaths?.length) {
29721
- const uniq = [...new Set(worktreePaths.map((p) => path7.resolve(p)))];
30040
+ const uniq = [...new Set(worktreePaths.map((p) => path14.resolve(p)))];
29722
30041
  return uniq;
29723
30042
  }
29724
30043
  try {
@@ -29726,7 +30045,7 @@ async function resolveSnapshotRepoRoots(options) {
29726
30045
  const mapped = repos.map((r) => r.absolutePath);
29727
30046
  const sid = sessionId?.trim();
29728
30047
  if (sid) {
29729
- const filtered = mapped.filter((root) => path7.basename(root) === sid);
30048
+ const filtered = mapped.filter((root) => path14.basename(root) === sid);
29730
30049
  if (filtered.length > 0) return filtered;
29731
30050
  }
29732
30051
  return mapped;
@@ -29747,7 +30066,7 @@ async function capturePreTurnSnapshot(options) {
29747
30066
  }
29748
30067
  const dir = snapshotsDirForCwd(agentCwd);
29749
30068
  try {
29750
- fs8.mkdirSync(dir, { recursive: true });
30069
+ fs14.mkdirSync(dir, { recursive: true });
29751
30070
  } catch (e) {
29752
30071
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
29753
30072
  }
@@ -29756,9 +30075,9 @@ async function capturePreTurnSnapshot(options) {
29756
30075
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
29757
30076
  repos
29758
30077
  };
29759
- const filePath = path7.join(dir, `${runId}.json`);
30078
+ const filePath = path14.join(dir, `${runId}.json`);
29760
30079
  try {
29761
- fs8.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
30080
+ fs14.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
29762
30081
  } catch (e) {
29763
30082
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
29764
30083
  }
@@ -29771,7 +30090,7 @@ async function capturePreTurnSnapshot(options) {
29771
30090
  async function applyPreTurnSnapshot(filePath, log2) {
29772
30091
  let data;
29773
30092
  try {
29774
- const raw = fs8.readFileSync(filePath, "utf8");
30093
+ const raw = fs14.readFileSync(filePath, "utf8");
29775
30094
  data = JSON.parse(raw);
29776
30095
  } catch (e) {
29777
30096
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
@@ -29794,7 +30113,7 @@ async function applyPreTurnSnapshot(filePath, log2) {
29794
30113
  return { ok: true };
29795
30114
  }
29796
30115
  function snapshotFilePath(agentCwd, runId) {
29797
- return path7.join(snapshotsDirForCwd(agentCwd), `${runId}.json`);
30116
+ return path14.join(snapshotsDirForCwd(agentCwd), `${runId}.json`);
29798
30117
  }
29799
30118
 
29800
30119
  // src/git/session-git-queue.ts
@@ -29843,7 +30162,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
29843
30162
  continue;
29844
30163
  }
29845
30164
  const lines = namesRaw.split("\n").map((l) => l.trim()).filter(Boolean);
29846
- const slug = path8.basename(repo.path).replace(/[^\w.-]+/g, "_") || "repo";
30165
+ const slug = path15.basename(repo.path).replace(/[^\w.-]+/g, "_") || "repo";
29847
30166
  for (const rel of lines) {
29848
30167
  if (rel.includes("..")) continue;
29849
30168
  try {
@@ -29857,7 +30176,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
29857
30176
  );
29858
30177
  if (!patchContent.trim()) continue;
29859
30178
  const displayPath = multiRepo ? `${slug}/${rel}` : rel;
29860
- const workspaceFilePath = path8.join(repo.path, rel);
30179
+ const workspaceFilePath = path15.join(repo.path, rel);
29861
30180
  const newText = await readWorkspaceFileAsUtf8(workspaceFilePath);
29862
30181
  sendSessionUpdate({
29863
30182
  type: "session_file_change",
@@ -29879,9 +30198,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
29879
30198
  // src/agents/acp/put-summarize-change-summaries.ts
29880
30199
  async function putEncryptedChangeSummaryRows(params) {
29881
30200
  const base = params.apiBaseUrl.replace(/\/+$/, "");
29882
- const entries = params.rows.map(({ path: path35, summary }) => {
30201
+ const entries = params.rows.map(({ path: path39, summary }) => {
29883
30202
  const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
29884
- return { path: path35, summary: JSON.stringify(enc) };
30203
+ return { path: path39, summary: JSON.stringify(enc) };
29885
30204
  });
29886
30205
  const res = await fetch(
29887
30206
  `${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
@@ -30218,8 +30537,8 @@ async function sendPromptToAgent(options) {
30218
30537
  }
30219
30538
 
30220
30539
  // src/agents/acp/ensure-acp-client.ts
30221
- import * as fs10 from "node:fs";
30222
- import * as path12 from "node:path";
30540
+ import * as fs15 from "node:fs";
30541
+ import * as path18 from "node:path";
30223
30542
 
30224
30543
  // src/error-message.ts
30225
30544
  function errorMessage(err) {
@@ -30721,20 +31040,20 @@ function resolveAgentCommand(preferredAgentType) {
30721
31040
 
30722
31041
  // src/agents/acp/session-file-change-path-kind.ts
30723
31042
  import { execFileSync as execFileSync4 } from "node:child_process";
30724
- import { existsSync, statSync } from "node:fs";
31043
+ import { existsSync as existsSync2, statSync } from "node:fs";
30725
31044
 
30726
31045
  // src/git/get-git-repo-root-sync.ts
30727
31046
  import { execFileSync as execFileSync2 } from "node:child_process";
30728
- import * as path9 from "node:path";
31047
+ import * as path16 from "node:path";
30729
31048
  function getGitRepoRootSync(startDir) {
30730
31049
  try {
30731
31050
  const out = execFileSync2("git", ["rev-parse", "--show-toplevel"], {
30732
- cwd: path9.resolve(startDir),
31051
+ cwd: path16.resolve(startDir),
30733
31052
  encoding: "utf8",
30734
31053
  stdio: ["ignore", "pipe", "ignore"],
30735
31054
  maxBuffer: 1024 * 1024
30736
31055
  }).trim();
30737
- return out ? path9.resolve(out) : null;
31056
+ return out ? path16.resolve(out) : null;
30738
31057
  } catch {
30739
31058
  return null;
30740
31059
  }
@@ -30742,26 +31061,26 @@ function getGitRepoRootSync(startDir) {
30742
31061
 
30743
31062
  // src/agents/acp/workspace-files.ts
30744
31063
  import { execFileSync as execFileSync3 } from "node:child_process";
30745
- import { readFileSync as readFileSync3 } from "node:fs";
30746
- import * as path10 from "node:path";
31064
+ import { readFileSync as readFileSync4 } from "node:fs";
31065
+ import * as path17 from "node:path";
30747
31066
  function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
30748
31067
  const trimmed2 = rawPath.trim();
30749
31068
  if (!trimmed2) return null;
30750
- const normalizedSessionParent = path10.resolve(sessionParentPath);
31069
+ const normalizedSessionParent = path17.resolve(sessionParentPath);
30751
31070
  let resolvedPath = resolveSafePathUnderCwd(sessionParentPath, trimmed2);
30752
31071
  if (!resolvedPath) {
30753
- const candidate = path10.isAbsolute(trimmed2) ? path10.normalize(trimmed2) : path10.normalize(path10.resolve(normalizedSessionParent, trimmed2));
31072
+ const candidate = path17.isAbsolute(trimmed2) ? path17.normalize(trimmed2) : path17.normalize(path17.resolve(normalizedSessionParent, trimmed2));
30754
31073
  const gitRoot2 = getGitRepoRootSync(sessionParentPath);
30755
31074
  if (!gitRoot2) return null;
30756
- const rel = path10.relative(gitRoot2, candidate);
30757
- if (rel.startsWith("..") || path10.isAbsolute(rel)) return null;
31075
+ const rel = path17.relative(gitRoot2, candidate);
31076
+ if (rel.startsWith("..") || path17.isAbsolute(rel)) return null;
30758
31077
  resolvedPath = candidate;
30759
31078
  }
30760
31079
  const gitRoot = getGitRepoRootSync(sessionParentPath);
30761
31080
  if (gitRoot) {
30762
- const relFromRoot = path10.relative(gitRoot, resolvedPath);
30763
- if (!relFromRoot.startsWith("..") && !path10.isAbsolute(relFromRoot)) {
30764
- return { resolvedPath, display: relFromRoot.split(path10.sep).join("/") };
31081
+ const relFromRoot = path17.relative(gitRoot, resolvedPath);
31082
+ if (!relFromRoot.startsWith("..") && !path17.isAbsolute(relFromRoot)) {
31083
+ return { resolvedPath, display: relFromRoot.split(path17.sep).join("/") };
30765
31084
  }
30766
31085
  }
30767
31086
  return { resolvedPath, display: toDisplayPathRelativeToCwd(sessionParentPath, resolvedPath) };
@@ -30770,11 +31089,11 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
30770
31089
  if (!displayPath || displayPath.includes("..")) return "";
30771
31090
  const gitRoot = getGitRepoRootSync(sessionParentPath);
30772
31091
  if (gitRoot) {
30773
- const resolvedPath2 = path10.resolve(gitRoot, displayPath);
30774
- const rel = path10.relative(gitRoot, resolvedPath2);
30775
- if (!rel.startsWith("..") && !path10.isAbsolute(rel)) {
31092
+ const resolvedPath2 = path17.resolve(gitRoot, displayPath);
31093
+ const rel = path17.relative(gitRoot, resolvedPath2);
31094
+ if (!rel.startsWith("..") && !path17.isAbsolute(rel)) {
30776
31095
  try {
30777
- return readFileSync3(resolvedPath2, "utf8");
31096
+ return readFileSync4(resolvedPath2, "utf8");
30778
31097
  } catch {
30779
31098
  }
30780
31099
  }
@@ -30782,7 +31101,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
30782
31101
  const resolvedPath = resolveSafePathUnderCwd(sessionParentPath, displayPath);
30783
31102
  if (!resolvedPath) return "";
30784
31103
  try {
30785
- return readFileSync3(resolvedPath, "utf8");
31104
+ return readFileSync4(resolvedPath, "utf8");
30786
31105
  } catch {
30787
31106
  return "";
30788
31107
  }
@@ -30791,9 +31110,9 @@ function tryWorkspaceDisplayToPath(sessionParentPath, displayPath) {
30791
31110
  if (!displayPath || displayPath.includes("..")) return null;
30792
31111
  const gitRoot = getGitRepoRootSync(sessionParentPath);
30793
31112
  if (gitRoot) {
30794
- const resolvedPath = path10.resolve(gitRoot, displayPath);
30795
- const rel = path10.relative(gitRoot, resolvedPath);
30796
- if (!rel.startsWith("..") && !path10.isAbsolute(rel)) return resolvedPath;
31113
+ const resolvedPath = path17.resolve(gitRoot, displayPath);
31114
+ const rel = path17.relative(gitRoot, resolvedPath);
31115
+ if (!rel.startsWith("..") && !path17.isAbsolute(rel)) return resolvedPath;
30797
31116
  }
30798
31117
  return resolveSafePathUnderCwd(sessionParentPath, displayPath);
30799
31118
  }
@@ -30828,7 +31147,7 @@ function gitHeadPathObjectType(sessionParentPath, displayPath) {
30828
31147
  }
30829
31148
  function getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath) {
30830
31149
  const resolvedPath = tryWorkspaceDisplayToPath(sessionParentPath, displayPath);
30831
- if (resolvedPath && existsSync(resolvedPath)) {
31150
+ if (resolvedPath && existsSync2(resolvedPath)) {
30832
31151
  try {
30833
31152
  if (statSync(resolvedPath).isDirectory()) {
30834
31153
  return { isDirectory: true, directoryRemoved: false };
@@ -30928,7 +31247,7 @@ function createBridgeOnRequest(opts) {
30928
31247
  }
30929
31248
 
30930
31249
  // src/agents/acp/hooks/extract-acp-file-diffs-from-update/paths-and-text.ts
30931
- import { fileURLToPath as fileURLToPath2 } from "node:url";
31250
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
30932
31251
  function readOptionalTextField(v) {
30933
31252
  if (v === null || v === void 0) return "";
30934
31253
  if (typeof v === "string") return v;
@@ -30938,7 +31257,7 @@ function normalizePathField(raw) {
30938
31257
  const t = raw.trim();
30939
31258
  if (t.startsWith("file://")) {
30940
31259
  try {
30941
- return fileURLToPath2(t);
31260
+ return fileURLToPath3(t);
30942
31261
  } catch {
30943
31262
  return t;
30944
31263
  }
@@ -31396,29 +31715,34 @@ function buildAcpSessionBridgeHooks(opts) {
31396
31715
  }
31397
31716
 
31398
31717
  // src/agents/acp/local-agent-session-file.ts
31399
- import fs9 from "node:fs";
31400
- import os3 from "node:os";
31401
- import path11 from "node:path";
31402
- var LOCAL_AGENT_SESSION_DIR = path11.join(os3.homedir(), ".buildautomaton", "agent-sessions");
31403
- function safeFileSlug(cloudSessionId) {
31718
+ function sessionKeyForCloudSessionId(cloudSessionId) {
31404
31719
  const t = cloudSessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
31405
31720
  return t.length > 0 ? t : "session";
31406
31721
  }
31407
- function localAgentSessionFilePath(cloudSessionId) {
31408
- return path11.join(LOCAL_AGENT_SESSION_DIR, `${safeFileSlug(cloudSessionId)}.json`);
31409
- }
31410
31722
  function readLocalAgentSessionFile(cloudSessionId) {
31411
31723
  try {
31412
- const p = localAgentSessionFilePath(cloudSessionId);
31413
- const raw = fs9.readFileSync(p, "utf8");
31414
- const parsed = JSON.parse(raw);
31415
- if (parsed.v !== 1) return null;
31724
+ const db = getCliDatabase();
31725
+ const key = sessionKeyForCloudSessionId(cloudSessionId);
31726
+ const row = db.get(
31727
+ "SELECT acp_session_id, backend_agent_type, config_options_json, updated_at FROM agent_session WHERE session_key = ?",
31728
+ [key]
31729
+ );
31730
+ if (!row) return null;
31731
+ let configOptions = null;
31732
+ if (row.config_options_json != null && row.config_options_json !== "") {
31733
+ try {
31734
+ const parsed = JSON.parse(row.config_options_json);
31735
+ configOptions = Array.isArray(parsed) ? parsed : null;
31736
+ } catch {
31737
+ configOptions = null;
31738
+ }
31739
+ }
31416
31740
  return {
31417
31741
  v: 1,
31418
- acpSessionId: typeof parsed.acpSessionId === "string" ? parsed.acpSessionId : null,
31419
- backendAgentType: typeof parsed.backendAgentType === "string" ? parsed.backendAgentType : null,
31420
- configOptions: Array.isArray(parsed.configOptions) ? parsed.configOptions : null,
31421
- updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString()
31742
+ acpSessionId: row.acp_session_id,
31743
+ backendAgentType: row.backend_agent_type,
31744
+ configOptions,
31745
+ updatedAt: row.updated_at
31422
31746
  };
31423
31747
  } catch {
31424
31748
  return null;
@@ -31426,9 +31750,8 @@ function readLocalAgentSessionFile(cloudSessionId) {
31426
31750
  }
31427
31751
  function writeLocalAgentSessionFile(cloudSessionId, patch) {
31428
31752
  try {
31429
- const dir = LOCAL_AGENT_SESSION_DIR;
31430
- if (!fs9.existsSync(dir)) fs9.mkdirSync(dir, { recursive: true });
31431
- const p = localAgentSessionFilePath(cloudSessionId);
31753
+ const db = getCliDatabase();
31754
+ const key = sessionKeyForCloudSessionId(cloudSessionId);
31432
31755
  const prev = readLocalAgentSessionFile(cloudSessionId);
31433
31756
  const next = {
31434
31757
  v: 1,
@@ -31437,7 +31760,17 @@ function writeLocalAgentSessionFile(cloudSessionId, patch) {
31437
31760
  configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
31438
31761
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
31439
31762
  };
31440
- fs9.writeFileSync(p, JSON.stringify(next, null, 2), "utf8");
31763
+ const configJson = next.configOptions != null ? JSON.stringify(next.configOptions) : null;
31764
+ db.run(
31765
+ `INSERT INTO agent_session (session_key, acp_session_id, backend_agent_type, config_options_json, updated_at)
31766
+ VALUES (?, ?, ?, ?, ?)
31767
+ ON CONFLICT(session_key) DO UPDATE SET
31768
+ acp_session_id = excluded.acp_session_id,
31769
+ backend_agent_type = excluded.backend_agent_type,
31770
+ config_options_json = excluded.config_options_json,
31771
+ updated_at = excluded.updated_at`,
31772
+ [key, next.acpSessionId, next.backendAgentType, configJson, next.updatedAt]
31773
+ );
31441
31774
  } catch {
31442
31775
  }
31443
31776
  }
@@ -31461,7 +31794,7 @@ async function ensureAcpClient(options) {
31461
31794
  if (state.acpStartPromise && !state.acpHandle) {
31462
31795
  await state.acpStartPromise;
31463
31796
  }
31464
- if (state.acpHandle && state.lastAcpCwd != null && path12.resolve(state.lastAcpCwd) !== path12.resolve(targetSessionParentPath)) {
31797
+ if (state.acpHandle && state.lastAcpCwd != null && path18.resolve(state.lastAcpCwd) !== path18.resolve(targetSessionParentPath)) {
31465
31798
  try {
31466
31799
  state.acpHandle.disconnect();
31467
31800
  } catch {
@@ -31496,7 +31829,7 @@ async function ensureAcpClient(options) {
31496
31829
  if (!state.acpStartPromise) {
31497
31830
  let statOk = false;
31498
31831
  try {
31499
- const st = fs10.statSync(targetSessionParentPath);
31832
+ const st = fs15.statSync(targetSessionParentPath);
31500
31833
  statOk = st.isDirectory();
31501
31834
  if (!statOk) {
31502
31835
  state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
@@ -31743,12 +32076,12 @@ async function createAcpManager(options) {
31743
32076
  }
31744
32077
 
31745
32078
  // src/worktrees/session-worktree-manager.ts
31746
- import * as path19 from "node:path";
31747
- import os5 from "node:os";
32079
+ import * as path25 from "node:path";
32080
+ import os8 from "node:os";
31748
32081
 
31749
32082
  // src/worktrees/prepare-new-session-worktrees.ts
31750
- import * as fs12 from "node:fs";
31751
- import * as path14 from "node:path";
32083
+ import * as fs17 from "node:fs";
32084
+ import * as path20 from "node:path";
31752
32085
 
31753
32086
  // src/git/worktree-add.ts
31754
32087
  async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
@@ -31757,12 +32090,12 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
31757
32090
  }
31758
32091
 
31759
32092
  // src/worktrees/worktree-layout-file.ts
31760
- import * as fs11 from "node:fs";
31761
- import * as path13 from "node:path";
31762
- import os4 from "node:os";
32093
+ import * as fs16 from "node:fs";
32094
+ import * as path19 from "node:path";
32095
+ import os7 from "node:os";
31763
32096
  var LAYOUT_FILENAME = "worktree-launcher-layout.json";
31764
32097
  function defaultWorktreeLayoutPath() {
31765
- return path13.join(os4.homedir(), ".buildautomaton", LAYOUT_FILENAME);
32098
+ return path19.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
31766
32099
  }
31767
32100
  function normalizeLoadedLayout(raw) {
31768
32101
  if (raw && typeof raw === "object" && "launcherCwds" in raw) {
@@ -31774,8 +32107,8 @@ function normalizeLoadedLayout(raw) {
31774
32107
  function loadWorktreeLayout() {
31775
32108
  try {
31776
32109
  const p = defaultWorktreeLayoutPath();
31777
- if (!fs11.existsSync(p)) return { launcherCwds: [] };
31778
- const raw = JSON.parse(fs11.readFileSync(p, "utf8"));
32110
+ if (!fs16.existsSync(p)) return { launcherCwds: [] };
32111
+ const raw = JSON.parse(fs16.readFileSync(p, "utf8"));
31779
32112
  return normalizeLoadedLayout(raw);
31780
32113
  } catch {
31781
32114
  return { launcherCwds: [] };
@@ -31783,24 +32116,24 @@ function loadWorktreeLayout() {
31783
32116
  }
31784
32117
  function saveWorktreeLayout(layout) {
31785
32118
  try {
31786
- const dir = path13.dirname(defaultWorktreeLayoutPath());
31787
- fs11.mkdirSync(dir, { recursive: true });
31788
- fs11.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
32119
+ const dir = path19.dirname(defaultWorktreeLayoutPath());
32120
+ fs16.mkdirSync(dir, { recursive: true });
32121
+ fs16.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
31789
32122
  } catch {
31790
32123
  }
31791
32124
  }
31792
32125
  function baseNameSafe(pathString) {
31793
- return path13.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
32126
+ return path19.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
31794
32127
  }
31795
32128
  function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
31796
- const norm = path13.resolve(bridgeRootPath2);
31797
- const existing = layout.launcherCwds.find((e) => path13.resolve(e.absolutePath) === norm);
32129
+ const norm = path19.resolve(bridgeRootPath2);
32130
+ const existing = layout.launcherCwds.find((e) => path19.resolve(e.absolutePath) === norm);
31798
32131
  return existing?.dirName;
31799
32132
  }
31800
32133
  function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
31801
32134
  const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
31802
32135
  if (existing) return existing;
31803
- const norm = path13.resolve(bridgeRootPath2);
32136
+ const norm = path19.resolve(bridgeRootPath2);
31804
32137
  const base = baseNameSafe(norm);
31805
32138
  const used = new Set(layout.launcherCwds.map((e) => e.dirName));
31806
32139
  let name = base;
@@ -31817,10 +32150,10 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
31817
32150
  // src/worktrees/prepare-new-session-worktrees.ts
31818
32151
  async function prepareNewSessionWorktrees(options) {
31819
32152
  const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2 } = options;
31820
- const bridgeResolved = path14.resolve(bridgeRoot);
32153
+ const bridgeResolved = path20.resolve(bridgeRoot);
31821
32154
  const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
31822
- const bridgeKeyDir = path14.join(worktreesRootPath, cwdKey);
31823
- const sessionDir = path14.join(bridgeKeyDir, sessionId);
32155
+ const bridgeKeyDir = path20.join(worktreesRootPath, cwdKey);
32156
+ const sessionDir = path20.join(bridgeKeyDir, sessionId);
31824
32157
  const repos = await discoverGitReposUnderRoot(bridgeResolved);
31825
32158
  if (repos.length === 0) {
31826
32159
  log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
@@ -31828,14 +32161,14 @@ async function prepareNewSessionWorktrees(options) {
31828
32161
  }
31829
32162
  const branch = `session-${sessionId}`;
31830
32163
  const worktreePaths = [];
31831
- fs12.mkdirSync(sessionDir, { recursive: true });
32164
+ fs17.mkdirSync(sessionDir, { recursive: true });
31832
32165
  for (const repo of repos) {
31833
- let rel = path14.relative(bridgeResolved, repo.absolutePath);
31834
- if (rel.startsWith("..") || path14.isAbsolute(rel)) continue;
32166
+ let rel = path20.relative(bridgeResolved, repo.absolutePath);
32167
+ if (rel.startsWith("..") || path20.isAbsolute(rel)) continue;
31835
32168
  const relNorm = rel === "" ? "." : rel;
31836
- const wtPath = relNorm === "." ? sessionDir : path14.join(sessionDir, relNorm);
32169
+ const wtPath = relNorm === "." ? sessionDir : path20.join(sessionDir, relNorm);
31837
32170
  if (relNorm !== ".") {
31838
- fs12.mkdirSync(path14.dirname(wtPath), { recursive: true });
32171
+ fs17.mkdirSync(path20.dirname(wtPath), { recursive: true });
31839
32172
  }
31840
32173
  try {
31841
32174
  await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
@@ -31877,23 +32210,23 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
31877
32210
  }
31878
32211
 
31879
32212
  // src/worktrees/remove-session-worktrees.ts
31880
- import * as fs15 from "node:fs";
32213
+ import * as fs20 from "node:fs";
31881
32214
 
31882
32215
  // src/git/worktree-remove.ts
31883
- import * as fs14 from "node:fs";
32216
+ import * as fs19 from "node:fs";
31884
32217
 
31885
32218
  // src/git/resolve-main-repo-from-git-file.ts
31886
- import * as fs13 from "node:fs";
31887
- import * as path15 from "node:path";
32219
+ import * as fs18 from "node:fs";
32220
+ import * as path21 from "node:path";
31888
32221
  function resolveMainRepoFromWorktreeGitFile(wt) {
31889
- const gitDirFile = path15.join(wt, ".git");
31890
- if (!fs13.existsSync(gitDirFile) || !fs13.statSync(gitDirFile).isFile()) return "";
31891
- const first2 = fs13.readFileSync(gitDirFile, "utf8").trim();
32222
+ const gitDirFile = path21.join(wt, ".git");
32223
+ if (!fs18.existsSync(gitDirFile) || !fs18.statSync(gitDirFile).isFile()) return "";
32224
+ const first2 = fs18.readFileSync(gitDirFile, "utf8").trim();
31892
32225
  const m = first2.match(/^gitdir:\s*(.+)$/im);
31893
32226
  if (!m) return "";
31894
- const gitWorktreePath = path15.resolve(wt, m[1].trim());
31895
- const gitDir = path15.dirname(path15.dirname(gitWorktreePath));
31896
- return path15.dirname(gitDir);
32227
+ const gitWorktreePath = path21.resolve(wt, m[1].trim());
32228
+ const gitDir = path21.dirname(path21.dirname(gitWorktreePath));
32229
+ return path21.dirname(gitDir);
31897
32230
  }
31898
32231
 
31899
32232
  // src/git/worktree-remove.ts
@@ -31902,7 +32235,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
31902
32235
  if (mainRepo) {
31903
32236
  await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
31904
32237
  } else {
31905
- fs14.rmSync(worktreePath, { recursive: true, force: true });
32238
+ fs19.rmSync(worktreePath, { recursive: true, force: true });
31906
32239
  }
31907
32240
  }
31908
32241
 
@@ -31915,7 +32248,7 @@ async function removeSessionWorktrees(paths, log2) {
31915
32248
  } catch (e) {
31916
32249
  log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
31917
32250
  try {
31918
- fs15.rmSync(wt, { recursive: true, force: true });
32251
+ fs20.rmSync(wt, { recursive: true, force: true });
31919
32252
  } catch {
31920
32253
  }
31921
32254
  }
@@ -32135,7 +32468,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
32135
32468
  }
32136
32469
 
32137
32470
  // src/git/working-directory/changes/get-working-tree-change-repo-details.ts
32138
- import * as path17 from "node:path";
32471
+ import * as path23 from "node:path";
32139
32472
 
32140
32473
  // src/git/working-directory/changes/parse-git-status.ts
32141
32474
  function parseNameStatusLines(lines) {
@@ -32255,8 +32588,8 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
32255
32588
  }
32256
32589
 
32257
32590
  // src/git/working-directory/changes/list-changed-files-for-repo.ts
32258
- import * as fs17 from "node:fs";
32259
- import * as path16 from "node:path";
32591
+ import * as fs22 from "node:fs";
32592
+ import * as path22 from "node:path";
32260
32593
 
32261
32594
  // src/git/working-directory/changes/count-lines.ts
32262
32595
  import { createReadStream } from "node:fs";
@@ -32280,7 +32613,7 @@ async function countTextFileLines(filePath) {
32280
32613
  }
32281
32614
 
32282
32615
  // src/git/working-directory/changes/hydrate-patch.ts
32283
- import * as fs16 from "node:fs";
32616
+ import * as fs21 from "node:fs";
32284
32617
  var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
32285
32618
  var MAX_HYDRATE_LINES_PER_GAP = 8e3;
32286
32619
  var MAX_HYDRATE_LINES_PER_FILE = 8e4;
@@ -32295,7 +32628,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
32295
32628
  }
32296
32629
  async function readWorktreeFileLines(filePath) {
32297
32630
  try {
32298
- const raw = await fs16.promises.readFile(filePath, "utf8");
32631
+ const raw = await fs21.promises.readFile(filePath, "utf8");
32299
32632
  return raw.split(/\r?\n/);
32300
32633
  } catch {
32301
32634
  return null;
@@ -32430,7 +32763,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
32430
32763
  const rows = [];
32431
32764
  for (const pathInRepo of paths) {
32432
32765
  const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
32433
- const repoFilePath = path16.join(repoGitCwd, pathInRepo);
32766
+ const repoFilePath = path22.join(repoGitCwd, pathInRepo);
32434
32767
  const nums = numByPath.get(pathInRepo);
32435
32768
  let additions = nums?.additions ?? 0;
32436
32769
  let deletions = nums?.deletions ?? 0;
@@ -32443,7 +32776,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
32443
32776
  deletions = fromGit.deletions;
32444
32777
  } else {
32445
32778
  try {
32446
- const st = await fs17.promises.stat(repoFilePath);
32779
+ const st = await fs22.promises.stat(repoFilePath);
32447
32780
  if (st.isFile()) additions = await countTextFileLines(repoFilePath);
32448
32781
  else additions = 0;
32449
32782
  } catch {
@@ -32469,7 +32802,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
32469
32802
  } else {
32470
32803
  pathInRepo = row.pathRelLauncher;
32471
32804
  }
32472
- const filePath = path16.join(repoGitCwd, pathInRepo);
32805
+ const filePath = path22.join(repoGitCwd, pathInRepo);
32473
32806
  let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
32474
32807
  if (patch) {
32475
32808
  patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
@@ -32485,8 +32818,8 @@ function normRepoRel(p) {
32485
32818
  return x === "" ? "." : x;
32486
32819
  }
32487
32820
  async function getWorkingTreeChangeRepoDetails(options) {
32488
- const bridgeRoot = path17.resolve(getBridgeRoot());
32489
- const sessionWtRoot = options.sessionWorktreeRootPath ? path17.resolve(options.sessionWorktreeRootPath) : null;
32821
+ const bridgeRoot = path23.resolve(getBridgeRoot());
32822
+ const sessionWtRoot = options.sessionWorktreeRootPath ? path23.resolve(options.sessionWorktreeRootPath) : null;
32490
32823
  const legacyNested = options.legacyRepoNestedSessionLayout === true;
32491
32824
  const out = [];
32492
32825
  const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
@@ -32499,7 +32832,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
32499
32832
  }
32500
32833
  const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
32501
32834
  for (const target of options.commitTargetPaths) {
32502
- const t = path17.resolve(target);
32835
+ const t = path23.resolve(target);
32503
32836
  if (!await isGitRepoDirectory(t)) continue;
32504
32837
  const g = cliSimpleGit(t);
32505
32838
  let branch = "HEAD";
@@ -32512,8 +32845,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
32512
32845
  const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
32513
32846
  let repoRelPath;
32514
32847
  if (sessionWtRoot) {
32515
- const anchor = legacyNested ? path17.dirname(t) : t;
32516
- const relNorm = path17.relative(sessionWtRoot, anchor);
32848
+ const anchor = legacyNested ? path23.dirname(t) : t;
32849
+ const relNorm = path23.relative(sessionWtRoot, anchor);
32517
32850
  repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
32518
32851
  } else {
32519
32852
  let top = t;
@@ -32522,8 +32855,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
32522
32855
  } catch {
32523
32856
  top = t;
32524
32857
  }
32525
- const rel = path17.relative(bridgeRoot, path17.resolve(top)).replace(/\\/g, "/") || ".";
32526
- repoRelPath = rel.startsWith("..") ? path17.basename(path17.resolve(top)) : rel;
32858
+ const rel = path23.relative(bridgeRoot, path23.resolve(top)).replace(/\\/g, "/") || ".";
32859
+ repoRelPath = rel.startsWith("..") ? path23.basename(path23.resolve(top)) : rel;
32527
32860
  }
32528
32861
  const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
32529
32862
  if (filter && norm !== filter) continue;
@@ -32588,11 +32921,11 @@ async function commitSessionWorktrees(options) {
32588
32921
  }
32589
32922
 
32590
32923
  // src/worktrees/discover-session-worktree-on-disk.ts
32591
- import * as fs18 from "node:fs";
32592
- import * as path18 from "node:path";
32924
+ import * as fs23 from "node:fs";
32925
+ import * as path24 from "node:path";
32593
32926
  function isGitDir(dirPath) {
32594
32927
  try {
32595
- return fs18.existsSync(path18.join(dirPath, ".git"));
32928
+ return fs23.existsSync(path24.join(dirPath, ".git"));
32596
32929
  } catch {
32597
32930
  return false;
32598
32931
  }
@@ -32601,23 +32934,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
32601
32934
  const out = [];
32602
32935
  const walk = (dir) => {
32603
32936
  if (isGitDir(dir)) {
32604
- out.push(path18.resolve(dir));
32937
+ out.push(path24.resolve(dir));
32605
32938
  return;
32606
32939
  }
32607
32940
  let entries;
32608
32941
  try {
32609
- entries = fs18.readdirSync(dir, { withFileTypes: true });
32942
+ entries = fs23.readdirSync(dir, { withFileTypes: true });
32610
32943
  } catch {
32611
32944
  return;
32612
32945
  }
32613
32946
  for (const e of entries) {
32614
32947
  if (e.name.startsWith(".")) continue;
32615
- const full = path18.join(dir, e.name);
32948
+ const full = path24.join(dir, e.name);
32616
32949
  if (!e.isDirectory()) continue;
32617
32950
  walk(full);
32618
32951
  }
32619
32952
  };
32620
- walk(path18.resolve(rootPath));
32953
+ walk(path24.resolve(rootPath));
32621
32954
  return [...new Set(out)];
32622
32955
  }
32623
32956
  function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
@@ -32626,16 +32959,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
32626
32959
  if (depth > maxDepth) return;
32627
32960
  let entries;
32628
32961
  try {
32629
- entries = fs18.readdirSync(dir, { withFileTypes: true });
32962
+ entries = fs23.readdirSync(dir, { withFileTypes: true });
32630
32963
  } catch {
32631
32964
  return;
32632
32965
  }
32633
32966
  for (const e of entries) {
32634
32967
  if (e.name.startsWith(".")) continue;
32635
- const full = path18.join(dir, e.name);
32968
+ const full = path24.join(dir, e.name);
32636
32969
  if (!e.isDirectory()) continue;
32637
32970
  if (e.name === sessionId) {
32638
- if (isGitDir(full)) out.push(path18.resolve(full));
32971
+ if (isGitDir(full)) out.push(path24.resolve(full));
32639
32972
  } else {
32640
32973
  walk(full, depth + 1);
32641
32974
  }
@@ -32647,14 +32980,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
32647
32980
  function tryBindingFromSessionDirectory(sessionDir) {
32648
32981
  let st;
32649
32982
  try {
32650
- st = fs18.statSync(sessionDir);
32983
+ st = fs23.statSync(sessionDir);
32651
32984
  } catch {
32652
32985
  return null;
32653
32986
  }
32654
32987
  if (!st.isDirectory()) return null;
32655
32988
  const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
32656
32989
  if (worktreePaths.length === 0) return null;
32657
- const abs = path18.resolve(sessionDir);
32990
+ const abs = path24.resolve(sessionDir);
32658
32991
  return {
32659
32992
  sessionParentPath: abs,
32660
32993
  workingTreeRelRoot: abs,
@@ -32664,20 +32997,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
32664
32997
  function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
32665
32998
  const sid = sessionId.trim();
32666
32999
  if (!sid) return null;
32667
- const hintR = path18.resolve(checkoutPath);
33000
+ const hintR = path24.resolve(checkoutPath);
32668
33001
  let best = null;
32669
- let cur = path18.dirname(hintR);
33002
+ let cur = path24.dirname(hintR);
32670
33003
  for (let i = 0; i < 40; i++) {
32671
33004
  const paths = collectWorktreeRootsNamed(cur, sid, 24);
32672
- if (paths.some((p) => path18.resolve(p) === hintR)) {
32673
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path18.resolve(paths[0]);
33005
+ if (paths.some((p) => path24.resolve(p) === hintR)) {
33006
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path24.resolve(paths[0]);
32674
33007
  best = {
32675
- sessionParentPath: path18.resolve(isolated),
32676
- workingTreeRelRoot: path18.resolve(cur),
32677
- repoCheckoutPaths: paths.map((p) => path18.resolve(p))
33008
+ sessionParentPath: path24.resolve(isolated),
33009
+ workingTreeRelRoot: path24.resolve(cur),
33010
+ repoCheckoutPaths: paths.map((p) => path24.resolve(p))
32678
33011
  };
32679
33012
  }
32680
- const next = path18.dirname(cur);
33013
+ const next = path24.dirname(cur);
32681
33014
  if (next === cur) break;
32682
33015
  cur = next;
32683
33016
  }
@@ -32685,33 +33018,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
32685
33018
  }
32686
33019
  function discoverSessionWorktreeOnDisk(options) {
32687
33020
  const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
32688
- if (!sessionId.trim() || !fs18.existsSync(worktreesRootPath)) return null;
33021
+ if (!sessionId.trim() || !fs23.existsSync(worktreesRootPath)) return null;
32689
33022
  const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
32690
33023
  const keys = [];
32691
33024
  if (preferredKey) keys.push(preferredKey);
32692
33025
  try {
32693
- for (const name of fs18.readdirSync(worktreesRootPath)) {
33026
+ for (const name of fs23.readdirSync(worktreesRootPath)) {
32694
33027
  if (name.startsWith(".")) continue;
32695
- const p = path18.join(worktreesRootPath, name);
32696
- if (!fs18.statSync(p).isDirectory()) continue;
33028
+ const p = path24.join(worktreesRootPath, name);
33029
+ if (!fs23.statSync(p).isDirectory()) continue;
32697
33030
  if (name !== preferredKey) keys.push(name);
32698
33031
  }
32699
33032
  } catch {
32700
33033
  return null;
32701
33034
  }
32702
33035
  for (const key of keys) {
32703
- const layoutRoot = path18.join(worktreesRootPath, key);
32704
- if (!fs18.existsSync(layoutRoot) || !fs18.statSync(layoutRoot).isDirectory()) continue;
32705
- const sessionDir = path18.join(layoutRoot, sessionId);
33036
+ const layoutRoot = path24.join(worktreesRootPath, key);
33037
+ if (!fs23.existsSync(layoutRoot) || !fs23.statSync(layoutRoot).isDirectory()) continue;
33038
+ const sessionDir = path24.join(layoutRoot, sessionId);
32706
33039
  const nested = tryBindingFromSessionDirectory(sessionDir);
32707
33040
  if (nested) return nested;
32708
33041
  const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
32709
33042
  if (legacyPaths.length > 0) {
32710
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path18.resolve(legacyPaths[0]);
33043
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path24.resolve(legacyPaths[0]);
32711
33044
  return {
32712
- sessionParentPath: path18.resolve(isolated),
32713
- workingTreeRelRoot: path18.resolve(layoutRoot),
32714
- repoCheckoutPaths: legacyPaths.map((p) => path18.resolve(p))
33045
+ sessionParentPath: path24.resolve(isolated),
33046
+ workingTreeRelRoot: path24.resolve(layoutRoot),
33047
+ repoCheckoutPaths: legacyPaths.map((p) => path24.resolve(p))
32715
33048
  };
32716
33049
  }
32717
33050
  }
@@ -32720,12 +33053,12 @@ function discoverSessionWorktreeOnDisk(options) {
32720
33053
  function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
32721
33054
  const sid = sessionId.trim();
32722
33055
  if (!sid) return null;
32723
- const hint = path18.resolve(sessionWorktreeRootPathOrHint);
32724
- const underHint = tryBindingFromSessionDirectory(path18.join(hint, sid));
33056
+ const hint = path24.resolve(sessionWorktreeRootPathOrHint);
33057
+ const underHint = tryBindingFromSessionDirectory(path24.join(hint, sid));
32725
33058
  if (underHint) return underHint;
32726
33059
  const direct = tryBindingFromSessionDirectory(hint);
32727
33060
  if (direct) {
32728
- if (path18.basename(hint) === sid && isGitDir(hint)) {
33061
+ if (path24.basename(hint) === sid && isGitDir(hint)) {
32729
33062
  const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
32730
33063
  if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
32731
33064
  return legacyFromCheckout;
@@ -32733,24 +33066,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
32733
33066
  }
32734
33067
  return direct;
32735
33068
  }
32736
- if (path18.basename(hint) === sid && isGitDir(hint)) {
33069
+ if (path24.basename(hint) === sid && isGitDir(hint)) {
32737
33070
  const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
32738
33071
  if (legacyFromCheckout) return legacyFromCheckout;
32739
33072
  }
32740
33073
  let st;
32741
33074
  try {
32742
- st = fs18.statSync(hint);
33075
+ st = fs23.statSync(hint);
32743
33076
  } catch {
32744
33077
  return null;
32745
33078
  }
32746
33079
  if (!st.isDirectory()) return null;
32747
33080
  const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
32748
33081
  if (legacyPaths.length === 0) return null;
32749
- const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path18.resolve(legacyPaths[0]);
33082
+ const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path24.resolve(legacyPaths[0]);
32750
33083
  return {
32751
- sessionParentPath: path18.resolve(isolated),
33084
+ sessionParentPath: path24.resolve(isolated),
32752
33085
  workingTreeRelRoot: hint,
32753
- repoCheckoutPaths: legacyPaths.map((p) => path18.resolve(p))
33086
+ repoCheckoutPaths: legacyPaths.map((p) => path24.resolve(p))
32754
33087
  };
32755
33088
  }
32756
33089
 
@@ -32773,10 +33106,10 @@ var SessionWorktreeManager = class {
32773
33106
  this.layout = loadWorktreeLayout();
32774
33107
  }
32775
33108
  rememberSessionWorktrees(sessionId, binding) {
32776
- const paths = binding.repoCheckoutPaths.map((p) => path19.resolve(p));
33109
+ const paths = binding.repoCheckoutPaths.map((p) => path25.resolve(p));
32777
33110
  this.sessionRepoCheckoutPaths.set(sessionId, paths);
32778
- this.sessionParentPathBySession.set(sessionId, path19.resolve(binding.sessionParentPath));
32779
- this.sessionWorkingTreeRelRootBySession.set(sessionId, path19.resolve(binding.workingTreeRelRoot));
33111
+ this.sessionParentPathBySession.set(sessionId, path25.resolve(binding.sessionParentPath));
33112
+ this.sessionWorkingTreeRelRootBySession.set(sessionId, path25.resolve(binding.workingTreeRelRoot));
32780
33113
  }
32781
33114
  sessionParentPathAfterRemember(sessionId) {
32782
33115
  return this.sessionParentPathBySession.get(sessionId);
@@ -32793,7 +33126,7 @@ var SessionWorktreeManager = class {
32793
33126
  const parent = this.sessionParentPathBySession.get(sessionId);
32794
33127
  const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
32795
33128
  if (!parent || !relRoot) return false;
32796
- return path19.resolve(parent) !== path19.resolve(relRoot);
33129
+ return path25.resolve(parent) !== path25.resolve(relRoot);
32797
33130
  }
32798
33131
  /**
32799
33132
  * Session parent path for `worktrees_root`: the per-session directory (new layout) or primary checkout (legacy).
@@ -32802,7 +33135,7 @@ var SessionWorktreeManager = class {
32802
33135
  if (!sessionId) return null;
32803
33136
  const sid = sessionId.trim();
32804
33137
  const cached2 = this.sessionParentPathBySession.get(sid);
32805
- if (cached2) return path19.resolve(cached2);
33138
+ if (cached2) return path25.resolve(cached2);
32806
33139
  const paths = this.ensureRepoCheckoutPathsForSession(sid) ?? this.getRepoCheckoutPathsForSession(sid);
32807
33140
  if (!paths?.length) return null;
32808
33141
  return resolveIsolatedSessionParentPathFromCheckouts(paths);
@@ -32816,7 +33149,7 @@ var SessionWorktreeManager = class {
32816
33149
  const sid = sessionId.trim();
32817
33150
  const parentPathRaw = opts.sessionParentPath?.trim();
32818
33151
  if (parentPathRaw) {
32819
- const resolved = path19.resolve(parentPathRaw);
33152
+ const resolved = path25.resolve(parentPathRaw);
32820
33153
  if (sid && parseSessionParent(opts.sessionParent) === "worktrees_root") {
32821
33154
  const diskFirst = this.tryDiscoverFromDisk(sid);
32822
33155
  if (diskFirst) {
@@ -32835,7 +33168,7 @@ var SessionWorktreeManager = class {
32835
33168
  this.rememberSessionWorktrees(sid, tryRoot);
32836
33169
  return this.sessionParentPathAfterRemember(sid);
32837
33170
  }
32838
- const next = path19.dirname(cur);
33171
+ const next = path25.dirname(cur);
32839
33172
  if (next === cur) break;
32840
33173
  cur = next;
32841
33174
  }
@@ -32988,15 +33321,22 @@ var SessionWorktreeManager = class {
32988
33321
  }
32989
33322
  };
32990
33323
  function defaultWorktreesRootPath() {
32991
- return path19.join(os5.homedir(), ".buildautomaton", "worktrees");
33324
+ return path25.join(os8.homedir(), ".buildautomaton", "worktrees");
32992
33325
  }
32993
33326
 
32994
33327
  // src/files/watch-file-index.ts
32995
33328
  import { watch } from "node:fs";
33329
+ import path30 from "node:path";
33330
+
33331
+ // src/files/index/paths.ts
32996
33332
  import path26 from "node:path";
33333
+ import crypto2 from "node:crypto";
33334
+ function getCwdHashForFileIndex(resolvedCwd) {
33335
+ return crypto2.createHash("sha256").update(path26.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
33336
+ }
32997
33337
 
32998
33338
  // src/files/index/build-file-index.ts
32999
- import path23 from "node:path";
33339
+ import path28 from "node:path";
33000
33340
 
33001
33341
  // src/runtime/yield-to-event-loop.ts
33002
33342
  function yieldToEventLoop() {
@@ -33004,47 +33344,12 @@ function yieldToEventLoop() {
33004
33344
  }
33005
33345
 
33006
33346
  // src/files/index/walk-workspace-tree.ts
33007
- import fs19 from "node:fs";
33008
- import path21 from "node:path";
33009
-
33010
- // src/files/index/constants.ts
33011
- import path20 from "node:path";
33012
- import os6 from "node:os";
33013
- var INDEX_WORK_YIELD_EVERY = 256;
33014
- var INDEX_DIR = path20.join(os6.homedir(), ".buildautomaton");
33015
- var INDEX_HASH_LEN = 16;
33016
- var INDEX_VERSION = 2;
33017
- var INDEX_LOG_PREFIX = "[file-index]";
33018
-
33019
- // src/files/index/walk-workspace-tree.ts
33020
- function walkWorkspaceTreeSync(dir, baseDir, out) {
33021
- let names;
33022
- try {
33023
- names = fs19.readdirSync(dir);
33024
- } catch {
33025
- return;
33026
- }
33027
- for (const name of names) {
33028
- if (name.startsWith(".")) continue;
33029
- const full = path21.join(dir, name);
33030
- let stat2;
33031
- try {
33032
- stat2 = fs19.statSync(full);
33033
- } catch {
33034
- continue;
33035
- }
33036
- const relative5 = path21.relative(baseDir, full).replace(/\\/g, "/");
33037
- if (stat2.isDirectory()) {
33038
- walkWorkspaceTreeSync(full, baseDir, out);
33039
- } else if (stat2.isFile()) {
33040
- out.push(relative5);
33041
- }
33042
- }
33043
- }
33347
+ import fs24 from "node:fs";
33348
+ import path27 from "node:path";
33044
33349
  async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
33045
33350
  let names;
33046
33351
  try {
33047
- names = await fs19.promises.readdir(dir);
33352
+ names = await fs24.promises.readdir(dir);
33048
33353
  } catch {
33049
33354
  return;
33050
33355
  }
@@ -33054,14 +33359,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
33054
33359
  await yieldToEventLoop();
33055
33360
  }
33056
33361
  state.n++;
33057
- const full = path21.join(dir, name);
33362
+ const full = path27.join(dir, name);
33058
33363
  let stat2;
33059
33364
  try {
33060
- stat2 = await fs19.promises.stat(full);
33365
+ stat2 = await fs24.promises.stat(full);
33061
33366
  } catch {
33062
33367
  continue;
33063
33368
  }
33064
- const relative5 = path21.relative(baseDir, full).replace(/\\/g, "/");
33369
+ const relative5 = path27.relative(baseDir, full).replace(/\\/g, "/");
33065
33370
  if (stat2.isDirectory()) {
33066
33371
  await walkWorkspaceTreeAsync(full, baseDir, out, state);
33067
33372
  } else if (stat2.isFile()) {
@@ -33073,205 +33378,124 @@ function createWalkYieldState() {
33073
33378
  return { n: 0 };
33074
33379
  }
33075
33380
 
33076
- // src/files/index/trigram-utils.ts
33077
- function getTrigrams(s) {
33078
- const lower = s.toLowerCase();
33079
- const out = [];
33080
- for (let i = 0; i <= lower.length - 3; i++) {
33081
- out.push(lower.slice(i, i + 3));
33082
- }
33083
- return out;
33084
- }
33085
- function binarySearch(arr, x) {
33086
- let lo = 0;
33087
- let hi = arr.length - 1;
33088
- while (lo <= hi) {
33089
- const mid = lo + hi >>> 1;
33090
- if (arr[mid] < x) lo = mid + 1;
33091
- else if (arr[mid] > x) hi = mid - 1;
33092
- else return mid;
33093
- }
33094
- return -1;
33095
- }
33096
- function intersectSortedTrigramSets(arrays) {
33097
- if (arrays.length === 0) return [];
33098
- if (arrays.length === 1) return arrays[0];
33099
- const byLength = arrays.slice().sort((a, b) => a.length - b.length);
33100
- const smallest = byLength[0];
33101
- const rest = byLength.slice(1);
33102
- const result = [];
33103
- for (const idx of smallest) {
33104
- if (rest.every((arr) => binarySearch(arr, idx) >= 0)) {
33105
- result.push(idx);
33106
- }
33107
- }
33108
- return result;
33109
- }
33110
-
33111
- // src/files/index/build-trigram-map.ts
33112
- function buildTrigramMapForPaths(paths) {
33113
- const trigramIndex = {};
33114
- for (let i = 0; i < paths.length; i++) {
33115
- const trigrams = getTrigrams(paths[i]);
33116
- const seen = /* @__PURE__ */ new Set();
33117
- for (const tri of trigrams) {
33118
- if (seen.has(tri)) continue;
33119
- seen.add(tri);
33120
- if (!trigramIndex[tri]) trigramIndex[tri] = [];
33121
- trigramIndex[tri].push(i);
33122
- }
33123
- }
33124
- return trigramIndex;
33381
+ // src/files/index/file-index-sqlite-lock.ts
33382
+ import fs25 from "node:fs";
33383
+ function isSqliteCorruptError(e) {
33384
+ const msg = e instanceof Error ? e.message : String(e);
33385
+ return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
33125
33386
  }
33126
- async function buildTrigramMapForPathsAsync(paths) {
33127
- const trigramIndex = {};
33128
- for (let i = 0; i < paths.length; i++) {
33129
- if (i > 0 && i % INDEX_WORK_YIELD_EVERY === 0) {
33130
- await yieldToEventLoop();
33131
- }
33132
- const trigrams = getTrigrams(paths[i]);
33133
- const seen = /* @__PURE__ */ new Set();
33134
- for (const tri of trigrams) {
33135
- if (seen.has(tri)) continue;
33136
- seen.add(tri);
33137
- if (!trigramIndex[tri]) trigramIndex[tri] = [];
33138
- trigramIndex[tri].push(i);
33387
+ var chain = Promise.resolve();
33388
+ function withFileIndexSqliteLock(fn) {
33389
+ const run = async () => {
33390
+ try {
33391
+ return await Promise.resolve(fn());
33392
+ } catch (e) {
33393
+ if (!isSqliteCorruptError(e)) throw e;
33394
+ closeAllCliSqliteConnections();
33395
+ try {
33396
+ fs25.unlinkSync(getCliSqlitePath());
33397
+ } catch {
33398
+ }
33399
+ chain = Promise.resolve();
33400
+ return await Promise.resolve(fn());
33139
33401
  }
33140
- }
33141
- return trigramIndex;
33142
- }
33143
-
33144
- // src/files/index/write-index-file.ts
33145
- import fs20 from "node:fs";
33146
-
33147
- // src/files/index/paths.ts
33148
- import path22 from "node:path";
33149
- import crypto2 from "node:crypto";
33150
- function getIndexPathForCwd(resolvedCwd) {
33151
- const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
33152
- return path22.join(INDEX_DIR, `.file-index-${hash}.json`);
33153
- }
33154
-
33155
- // src/files/index/write-index-file.ts
33156
- function writeIndexFileSync(resolvedCwd, data) {
33157
- const indexPath = getIndexPathForCwd(resolvedCwd);
33158
- try {
33159
- if (!fs20.existsSync(INDEX_DIR)) fs20.mkdirSync(INDEX_DIR, { recursive: true });
33160
- fs20.writeFileSync(indexPath, JSON.stringify(data), "utf8");
33161
- } catch (e) {
33162
- console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
33163
- }
33164
- }
33165
- async function writeIndexFileAsync(resolvedCwd, data) {
33166
- const indexPath = getIndexPathForCwd(resolvedCwd);
33167
- try {
33168
- await fs20.promises.mkdir(INDEX_DIR, { recursive: true });
33169
- await fs20.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
33170
- } catch (e) {
33171
- console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
33172
- }
33173
- }
33174
- function makeTrigramIndexData(paths, trigramIndex) {
33175
- return { version: INDEX_VERSION, paths, trigramIndex };
33402
+ };
33403
+ const next = chain.then(run);
33404
+ chain = next.then(
33405
+ () => void 0,
33406
+ () => void 0
33407
+ );
33408
+ return next;
33176
33409
  }
33177
33410
 
33178
33411
  // src/files/index/build-file-index.ts
33179
33412
  function sortPaths(paths) {
33180
33413
  paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
33181
33414
  }
33182
- function buildFileIndex(cwd) {
33183
- const resolved = path23.resolve(cwd);
33184
- const paths = [];
33185
- walkWorkspaceTreeSync(resolved, resolved, paths);
33186
- sortPaths(paths);
33187
- const trigramIndex = buildTrigramMapForPaths(paths);
33188
- const data = makeTrigramIndexData(paths, trigramIndex);
33189
- writeIndexFileSync(resolved, data);
33190
- return data;
33191
- }
33192
- async function buildFileIndexAsync(cwd) {
33193
- const resolved = path23.resolve(cwd);
33194
- const paths = [];
33195
- await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
33196
- await yieldToEventLoop();
33197
- sortPaths(paths);
33198
- const trigramIndex = await buildTrigramMapForPathsAsync(paths);
33199
- const data = makeTrigramIndexData(paths, trigramIndex);
33200
- await writeIndexFileAsync(resolved, data);
33201
- return data;
33202
- }
33203
-
33204
- // src/files/index/load-file-index.ts
33205
- import fs21 from "node:fs";
33206
- import path24 from "node:path";
33207
- function loadFileIndex(cwd) {
33208
- const resolved = path24.resolve(cwd);
33209
- const indexPath = getIndexPathForCwd(resolved);
33415
+ function persistPathsToSqlite(resolved, paths) {
33416
+ const db = getCliDatabase();
33417
+ const h = getCwdHashForFileIndex(resolved);
33418
+ db.run("BEGIN IMMEDIATE");
33210
33419
  try {
33211
- const raw = fs21.readFileSync(indexPath, "utf8");
33212
- const parsed = JSON.parse(raw);
33213
- if (parsed !== null && typeof parsed === "object" && Array.isArray(parsed.paths)) {
33214
- const obj = parsed;
33215
- if (obj.version === INDEX_VERSION && obj.trigramIndex && typeof obj.trigramIndex === "object") {
33216
- return obj;
33420
+ db.run("DELETE FROM file_index_path WHERE cwd_hash = ?", [h]);
33421
+ const ins = db.prepare("INSERT INTO file_index_path (cwd_hash, path) VALUES (?, ?)");
33422
+ try {
33423
+ for (const rel of paths) {
33424
+ ins.run([h, rel]);
33217
33425
  }
33218
- return buildFileIndex(resolved);
33426
+ } finally {
33427
+ ins.finalize();
33219
33428
  }
33220
- if (Array.isArray(parsed) && parsed.every((p) => typeof p === "string")) {
33221
- return buildFileIndex(resolved);
33429
+ db.run("COMMIT");
33430
+ } catch (e) {
33431
+ try {
33432
+ db.run("ROLLBACK");
33433
+ } catch {
33222
33434
  }
33223
- return null;
33224
- } catch {
33225
- return null;
33435
+ throw e;
33226
33436
  }
33227
33437
  }
33438
+ async function buildFileIndexAsync(cwd) {
33439
+ return withFileIndexSqliteLock(async () => {
33440
+ const resolved = path28.resolve(cwd);
33441
+ const paths = [];
33442
+ await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
33443
+ await yieldToEventLoop();
33444
+ sortPaths(paths);
33445
+ persistPathsToSqlite(resolved, paths);
33446
+ return { pathCount: paths.length };
33447
+ });
33448
+ }
33228
33449
 
33229
33450
  // src/files/index/ensure-file-index.ts
33230
- import path25 from "node:path";
33231
- async function ensureFileIndexAsync(cwd) {
33232
- const resolved = path25.resolve(cwd);
33233
- const cached2 = loadFileIndex(resolved);
33234
- if (cached2 !== null) return { data: cached2, fromCache: true };
33235
- const data = await buildFileIndexAsync(resolved);
33236
- return { data, fromCache: false };
33237
- }
33451
+ import path29 from "node:path";
33238
33452
 
33239
33453
  // src/files/index/search-file-index.ts
33240
- function candidatePathIndices(index, q) {
33241
- const { paths, trigramIndex } = index;
33242
- if (q.length < 3) {
33243
- return paths.map((_, i) => i).filter((i) => paths[i].toLowerCase().includes(q));
33244
- }
33245
- const trigrams = getTrigrams(q);
33246
- if (trigrams.length === 0) {
33247
- return paths.map((_, i) => i).filter((i) => paths[i].toLowerCase().includes(q));
33248
- }
33249
- const arrays = trigrams.map((tri) => trigramIndex[tri]).filter((arr) => arr != null && arr.length > 0);
33250
- if (arrays.length === 0) return [];
33251
- return intersectSortedTrigramSets(arrays);
33252
- }
33253
- async function searchFileIndexAsync(index, query, limit = 100) {
33254
- await yieldToEventLoop();
33454
+ function escapeLikePattern(fragment) {
33455
+ return fragment.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
33456
+ }
33457
+ function bridgeFileIndexIsPopulated(resolvedCwd) {
33458
+ const db = getCliDatabase();
33459
+ const h = getCwdHashForFileIndex(resolvedCwd);
33460
+ const row = db.get("SELECT 1 as ok FROM file_index_path WHERE cwd_hash = ? LIMIT 1", [h]);
33461
+ return row != null;
33462
+ }
33463
+ function bridgeFileIndexPathCount(resolvedCwd) {
33464
+ const db = getCliDatabase();
33465
+ const h = getCwdHashForFileIndex(resolvedCwd);
33466
+ const row = db.get("SELECT COUNT(*) as c FROM file_index_path WHERE cwd_hash = ?", [h]);
33467
+ const c = row?.c ?? 0;
33468
+ return Number(c);
33469
+ }
33470
+ function searchBridgeFilePaths(resolvedCwd, query, limit = 100) {
33255
33471
  const q = query.trim().toLowerCase();
33256
33472
  if (!q) return [];
33257
- const { paths } = index;
33258
- const candidateIndices = candidatePathIndices(index, q);
33259
- const out = [];
33260
- let n = 0;
33261
- for (const i of candidateIndices) {
33262
- if (n > 0 && n % INDEX_WORK_YIELD_EVERY === 0) {
33263
- await yieldToEventLoop();
33264
- }
33265
- const p = paths[i];
33266
- if (p.toLowerCase().includes(q)) {
33267
- out.push(p);
33268
- if (out.length >= limit) break;
33269
- }
33270
- n++;
33271
- }
33473
+ const db = getCliDatabase();
33474
+ const h = getCwdHashForFileIndex(resolvedCwd);
33475
+ const pattern = `%${escapeLikePattern(q)}%`;
33476
+ const lim = Math.max(0, Math.min(1e4, Math.floor(limit)));
33477
+ const rows = db.all(
33478
+ `SELECT path FROM file_index_path WHERE cwd_hash = ? AND lower(path) LIKE ? ESCAPE '\\' LIMIT ?`,
33479
+ [h, pattern, lim]
33480
+ );
33481
+ return rows.map((r) => String(r.path));
33482
+ }
33483
+ async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
33484
+ await yieldToEventLoop();
33485
+ const out = searchBridgeFilePaths(resolvedCwd, query, limit);
33486
+ if (out.length >= INDEX_WORK_YIELD_EVERY) await yieldToEventLoop();
33272
33487
  return out;
33273
33488
  }
33274
33489
 
33490
+ // src/files/index/ensure-file-index.ts
33491
+ async function ensureFileIndexAsync(cwd) {
33492
+ const resolved = path29.resolve(cwd);
33493
+ if (bridgeFileIndexIsPopulated(resolved)) {
33494
+ return { fromCache: true, pathCount: bridgeFileIndexPathCount(resolved) };
33495
+ }
33496
+ return { ...await buildFileIndexAsync(resolved), fromCache: false };
33497
+ }
33498
+
33275
33499
  // src/files/watch-file-index.ts
33276
33500
  var DEBOUNCE_MS = 900;
33277
33501
  function shouldIgnoreRelative(rel) {
@@ -33312,7 +33536,7 @@ function createFsWatcher(resolved, schedule) {
33312
33536
  }
33313
33537
  }
33314
33538
  function startFileIndexWatcher(cwd = getBridgeRoot()) {
33315
- const resolved = path26.resolve(cwd);
33539
+ const resolved = path30.resolve(cwd);
33316
33540
  void buildFileIndexAsync(resolved).catch((e) => {
33317
33541
  console.error("[file-index] Initial index build failed:", e);
33318
33542
  });
@@ -33340,7 +33564,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
33340
33564
  }
33341
33565
 
33342
33566
  // src/connection/create-bridge-connection.ts
33343
- import * as path34 from "node:path";
33567
+ import * as path38 from "node:path";
33344
33568
 
33345
33569
  // src/dev-servers/manager/dev-server-manager.ts
33346
33570
  import { rm as rm2 } from "node:fs/promises";
@@ -33384,7 +33608,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
33384
33608
  }
33385
33609
 
33386
33610
  // src/dev-servers/process/wire-dev-server-child-process.ts
33387
- import fs22 from "node:fs";
33611
+ import fs26 from "node:fs";
33388
33612
 
33389
33613
  // src/dev-servers/manager/forward-pipe.ts
33390
33614
  function forwardChildPipe(childReadable, terminal, onData) {
@@ -33420,7 +33644,7 @@ function wireDevServerChildProcess(d) {
33420
33644
  d.setPollInterval(void 0);
33421
33645
  return;
33422
33646
  }
33423
- fs22.readFile(d.mergedLogPath, (err, buf) => {
33647
+ fs26.readFile(d.mergedLogPath, (err, buf) => {
33424
33648
  if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
33425
33649
  if (buf.length <= d.mergedReadPos.value) return;
33426
33650
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
@@ -33458,7 +33682,7 @@ ${errTail}` : ""}`);
33458
33682
  d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
33459
33683
  };
33460
33684
  if (mergedPath) {
33461
- fs22.readFile(mergedPath, (err, buf) => {
33685
+ fs26.readFile(mergedPath, (err, buf) => {
33462
33686
  if (!err && buf.length > d.mergedReadPos.value) {
33463
33687
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
33464
33688
  if (chunk.length > 0) {
@@ -33560,13 +33784,13 @@ function parseDevServerDefs(servers) {
33560
33784
  }
33561
33785
 
33562
33786
  // src/dev-servers/manager/shell-spawn/utils.ts
33563
- import fs23 from "node:fs";
33787
+ import fs27 from "node:fs";
33564
33788
  function isSpawnEbadf(e) {
33565
33789
  return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
33566
33790
  }
33567
33791
  function rmDirQuiet(dir) {
33568
33792
  try {
33569
- fs23.rmSync(dir, { recursive: true, force: true });
33793
+ fs27.rmSync(dir, { recursive: true, force: true });
33570
33794
  } catch {
33571
33795
  }
33572
33796
  }
@@ -33574,7 +33798,7 @@ var cachedDevNullReadFd;
33574
33798
  function devNullReadFd() {
33575
33799
  if (cachedDevNullReadFd === void 0) {
33576
33800
  const devPath = process.platform === "win32" ? "nul" : "/dev/null";
33577
- cachedDevNullReadFd = fs23.openSync(devPath, "r");
33801
+ cachedDevNullReadFd = fs27.openSync(devPath, "r");
33578
33802
  }
33579
33803
  return cachedDevNullReadFd;
33580
33804
  }
@@ -33648,15 +33872,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
33648
33872
 
33649
33873
  // src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
33650
33874
  import { spawn as spawn7 } from "node:child_process";
33651
- import fs24 from "node:fs";
33875
+ import fs28 from "node:fs";
33652
33876
  import { tmpdir } from "node:os";
33653
- import path27 from "node:path";
33877
+ import path31 from "node:path";
33654
33878
  function trySpawnMergedLogFile(command, env, cwd, signal) {
33655
- const tmpRoot = fs24.mkdtempSync(path27.join(tmpdir(), "ba-devsrv-log-"));
33656
- const logPath = path27.join(tmpRoot, "combined.log");
33879
+ const tmpRoot = fs28.mkdtempSync(path31.join(tmpdir(), "ba-devsrv-log-"));
33880
+ const logPath = path31.join(tmpRoot, "combined.log");
33657
33881
  let logFd;
33658
33882
  try {
33659
- logFd = fs24.openSync(logPath, "a");
33883
+ logFd = fs28.openSync(logPath, "a");
33660
33884
  } catch {
33661
33885
  rmDirQuiet(tmpRoot);
33662
33886
  return null;
@@ -33675,7 +33899,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33675
33899
  } else {
33676
33900
  proc = spawn7("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
33677
33901
  }
33678
- fs24.closeSync(logFd);
33902
+ fs28.closeSync(logFd);
33679
33903
  return {
33680
33904
  proc,
33681
33905
  pipedStdoutStderr: true,
@@ -33684,7 +33908,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33684
33908
  };
33685
33909
  } catch (e) {
33686
33910
  try {
33687
- fs24.closeSync(logFd);
33911
+ fs28.closeSync(logFd);
33688
33912
  } catch {
33689
33913
  }
33690
33914
  rmDirQuiet(tmpRoot);
@@ -33695,22 +33919,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33695
33919
 
33696
33920
  // src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
33697
33921
  import { spawn as spawn8 } from "node:child_process";
33698
- import fs25 from "node:fs";
33922
+ import fs29 from "node:fs";
33699
33923
  import { tmpdir as tmpdir2 } from "node:os";
33700
- import path28 from "node:path";
33924
+ import path32 from "node:path";
33701
33925
  function shSingleQuote(s) {
33702
33926
  return `'${s.replace(/'/g, `'\\''`)}'`;
33703
33927
  }
33704
33928
  function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
33705
- const tmpRoot = fs25.mkdtempSync(path28.join(tmpdir2(), "ba-devsrv-sh-"));
33706
- const logPath = path28.join(tmpRoot, "combined.log");
33707
- const innerPath = path28.join(tmpRoot, "_cmd.sh");
33708
- const runnerPath = path28.join(tmpRoot, "_run.sh");
33929
+ const tmpRoot = fs29.mkdtempSync(path32.join(tmpdir2(), "ba-devsrv-sh-"));
33930
+ const logPath = path32.join(tmpRoot, "combined.log");
33931
+ const innerPath = path32.join(tmpRoot, "_cmd.sh");
33932
+ const runnerPath = path32.join(tmpRoot, "_run.sh");
33709
33933
  try {
33710
- fs25.writeFileSync(innerPath, `#!/bin/sh
33934
+ fs29.writeFileSync(innerPath, `#!/bin/sh
33711
33935
  ${command}
33712
33936
  `);
33713
- fs25.writeFileSync(
33937
+ fs29.writeFileSync(
33714
33938
  runnerPath,
33715
33939
  `#!/bin/sh
33716
33940
  cd ${shSingleQuote(cwd)}
@@ -33736,13 +33960,13 @@ cd ${shSingleQuote(cwd)}
33736
33960
  }
33737
33961
  }
33738
33962
  function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
33739
- const tmpRoot = fs25.mkdtempSync(path28.join(tmpdir2(), "ba-devsrv-sh-"));
33740
- const logPath = path28.join(tmpRoot, "combined.log");
33741
- const runnerPath = path28.join(tmpRoot, "_run.bat");
33963
+ const tmpRoot = fs29.mkdtempSync(path32.join(tmpdir2(), "ba-devsrv-sh-"));
33964
+ const logPath = path32.join(tmpRoot, "combined.log");
33965
+ const runnerPath = path32.join(tmpRoot, "_run.bat");
33742
33966
  const q = (p) => `"${p.replace(/"/g, '""')}"`;
33743
33967
  const com = process.env.ComSpec || "cmd.exe";
33744
33968
  try {
33745
- fs25.writeFileSync(
33969
+ fs29.writeFileSync(
33746
33970
  runnerPath,
33747
33971
  `@ECHO OFF\r
33748
33972
  CD /D ${q(cwd)}\r
@@ -34511,30 +34735,30 @@ function createOnBridgeIdentified(opts) {
34511
34735
  }
34512
34736
 
34513
34737
  // src/skills/discover-local-agent-skills.ts
34514
- import fs26 from "node:fs";
34515
- import path29 from "node:path";
34738
+ import fs30 from "node:fs";
34739
+ import path33 from "node:path";
34516
34740
  var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
34517
34741
  function discoverLocalSkills(cwd) {
34518
34742
  const out = [];
34519
34743
  const seenKeys = /* @__PURE__ */ new Set();
34520
34744
  for (const rel of SKILL_DISCOVERY_ROOTS) {
34521
- const base = path29.join(cwd, rel);
34522
- if (!fs26.existsSync(base) || !fs26.statSync(base).isDirectory()) continue;
34745
+ const base = path33.join(cwd, rel);
34746
+ if (!fs30.existsSync(base) || !fs30.statSync(base).isDirectory()) continue;
34523
34747
  let entries = [];
34524
34748
  try {
34525
- entries = fs26.readdirSync(base);
34749
+ entries = fs30.readdirSync(base);
34526
34750
  } catch {
34527
34751
  continue;
34528
34752
  }
34529
34753
  for (const name of entries) {
34530
- const dir = path29.join(base, name);
34754
+ const dir = path33.join(base, name);
34531
34755
  try {
34532
- if (!fs26.statSync(dir).isDirectory()) continue;
34756
+ if (!fs30.statSync(dir).isDirectory()) continue;
34533
34757
  } catch {
34534
34758
  continue;
34535
34759
  }
34536
- const skillMd = path29.join(dir, "SKILL.md");
34537
- if (!fs26.existsSync(skillMd)) continue;
34760
+ const skillMd = path33.join(dir, "SKILL.md");
34761
+ if (!fs30.existsSync(skillMd)) continue;
34538
34762
  const key = `${rel}/${name}`;
34539
34763
  if (seenKeys.has(key)) continue;
34540
34764
  seenKeys.add(key);
@@ -34546,23 +34770,23 @@ function discoverLocalSkills(cwd) {
34546
34770
  function discoverSkillLayoutRoots(cwd) {
34547
34771
  const roots = [];
34548
34772
  for (const rel of SKILL_DISCOVERY_ROOTS) {
34549
- const base = path29.join(cwd, rel);
34550
- if (!fs26.existsSync(base) || !fs26.statSync(base).isDirectory()) continue;
34773
+ const base = path33.join(cwd, rel);
34774
+ if (!fs30.existsSync(base) || !fs30.statSync(base).isDirectory()) continue;
34551
34775
  let entries = [];
34552
34776
  try {
34553
- entries = fs26.readdirSync(base);
34777
+ entries = fs30.readdirSync(base);
34554
34778
  } catch {
34555
34779
  continue;
34556
34780
  }
34557
34781
  const skills2 = [];
34558
34782
  for (const name of entries) {
34559
- const dir = path29.join(base, name);
34783
+ const dir = path33.join(base, name);
34560
34784
  try {
34561
- if (!fs26.statSync(dir).isDirectory()) continue;
34785
+ if (!fs30.statSync(dir).isDirectory()) continue;
34562
34786
  } catch {
34563
34787
  continue;
34564
34788
  }
34565
- if (!fs26.existsSync(path29.join(dir, "SKILL.md"))) continue;
34789
+ if (!fs30.existsSync(path33.join(dir, "SKILL.md"))) continue;
34566
34790
  const relPath = `${rel}/${name}`.replace(/\\/g, "/");
34567
34791
  skills2.push({ name, relPath });
34568
34792
  }
@@ -34756,7 +34980,7 @@ var handleAgentConfigMessage = (msg, deps) => {
34756
34980
  };
34757
34981
 
34758
34982
  // src/prompt-turn-queue/runner.ts
34759
- import fs29 from "node:fs";
34983
+ import fs31 from "node:fs";
34760
34984
 
34761
34985
  // src/prompt-turn-queue/client-report.ts
34762
34986
  function sendPromptQueueClientReport(ws, queues) {
@@ -34765,32 +34989,6 @@ function sendPromptQueueClientReport(ws, queues) {
34765
34989
  return true;
34766
34990
  }
34767
34991
 
34768
- // src/prompt-turn-queue/disk-store.ts
34769
- import fs28 from "node:fs";
34770
-
34771
- // src/prompt-turn-queue/paths.ts
34772
- import crypto3 from "node:crypto";
34773
- import fs27 from "node:fs";
34774
- import path30 from "node:path";
34775
- import os7 from "node:os";
34776
- var QUEUE_KEY_HEX_64 = /^[a-f0-9]{64}$/i;
34777
- function queueStateFileSlug(queueKey) {
34778
- if (QUEUE_KEY_HEX_64.test(queueKey)) return queueKey.toLowerCase();
34779
- return crypto3.createHash("sha256").update(queueKey, "utf8").digest("hex");
34780
- }
34781
- function getPromptQueuesDirectory() {
34782
- const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
34783
- if (override) return path30.resolve(override);
34784
- return path30.join(os7.homedir(), ".buildautomaton", "queues");
34785
- }
34786
- function ensurePromptQueuesDirectory() {
34787
- const dir = getPromptQueuesDirectory();
34788
- if (!fs27.existsSync(dir)) fs27.mkdirSync(dir, { recursive: true });
34789
- }
34790
- function queueStateFilePath(queueKey) {
34791
- return path30.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
34792
- }
34793
-
34794
34992
  // src/prompt-turn-queue/disk-store.ts
34795
34993
  var MERGEABLE_SERVER_STATES = /* @__PURE__ */ new Set([
34796
34994
  "queued",
@@ -34800,28 +34998,27 @@ var MERGEABLE_SERVER_STATES = /* @__PURE__ */ new Set([
34800
34998
  "stopping",
34801
34999
  "discarded"
34802
35000
  ]);
34803
- function parsePersistedQueueFile(raw) {
34804
- try {
34805
- const o = JSON.parse(raw);
34806
- const queueKey = typeof o.queueKey === "string" ? o.queueKey : typeof o.queueKeyHash === "string" ? o.queueKeyHash : null;
34807
- if (!queueKey || typeof o.updatedAt !== "string" || !Array.isArray(o.turns)) return null;
34808
- return { queueKey, updatedAt: o.updatedAt, turns: o.turns };
34809
- } catch {
34810
- return null;
34811
- }
34812
- }
34813
35001
  function readPersistedQueue(queueKey) {
34814
- const p = queueStateFilePath(queueKey);
35002
+ const db = getCliDatabase();
35003
+ const row = db.get("SELECT queue_key, updated_at, turns_json FROM prompt_queue WHERE queue_key = ?", [
35004
+ queueKey
35005
+ ]);
35006
+ if (!row) return null;
34815
35007
  try {
34816
- return parsePersistedQueueFile(fs28.readFileSync(p, "utf8"));
35008
+ const turns = JSON.parse(row.turns_json);
35009
+ if (!Array.isArray(turns)) return null;
35010
+ return { queueKey: row.queue_key, updatedAt: row.updated_at, turns };
34817
35011
  } catch {
34818
35012
  return null;
34819
35013
  }
34820
35014
  }
34821
35015
  function writePersistedQueue(file2) {
34822
- ensurePromptQueuesDirectory();
34823
- const p = queueStateFilePath(file2.queueKey);
34824
- fs28.writeFileSync(p, JSON.stringify(file2, null, 2), "utf8");
35016
+ const db = getCliDatabase();
35017
+ db.run(
35018
+ `INSERT INTO prompt_queue (queue_key, updated_at, turns_json) VALUES (?, ?, ?)
35019
+ ON CONFLICT(queue_key) DO UPDATE SET updated_at = excluded.updated_at, turns_json = excluded.turns_json`,
35020
+ [file2.queueKey, file2.updatedAt, JSON.stringify(file2.turns)]
35021
+ );
34825
35022
  }
34826
35023
  function mergeServerQueueSnapshot(queueKey, serverTurns) {
34827
35024
  const prev = readPersistedQueue(queueKey);
@@ -34879,7 +35076,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
34879
35076
  const tid = typeof pl.snapshotRevertTurnId === "string" && pl.snapshotRevertTurnId.trim() !== "" ? pl.snapshotRevertTurnId.trim() : next.turnId;
34880
35077
  const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
34881
35078
  const file2 = snapshotFilePath(agentBase, tid);
34882
- if (!fs29.existsSync(file2)) {
35079
+ if (!fs31.existsSync(file2)) {
34883
35080
  deps.log(
34884
35081
  `[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
34885
35082
  );
@@ -35103,9 +35300,9 @@ function parseChangeSummarySnapshots(raw) {
35103
35300
  for (const item of raw) {
35104
35301
  if (!item || typeof item !== "object") continue;
35105
35302
  const o = item;
35106
- const path35 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
35107
- if (!path35) continue;
35108
- const row = { path: path35 };
35303
+ const path39 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
35304
+ if (!path39) continue;
35305
+ const row = { path: path39 };
35109
35306
  if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
35110
35307
  if (typeof o.oldText === "string") row.oldText = o.oldText;
35111
35308
  if (typeof o.newText === "string") row.newText = o.newText;
@@ -35326,15 +35523,15 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
35326
35523
  };
35327
35524
 
35328
35525
  // src/files/list-dir.ts
35329
- import fs30 from "node:fs";
35330
- import path32 from "node:path";
35526
+ import fs32 from "node:fs";
35527
+ import path35 from "node:path";
35331
35528
 
35332
35529
  // src/files/ensure-under-cwd.ts
35333
- import path31 from "node:path";
35530
+ import path34 from "node:path";
35334
35531
  function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
35335
- const normalized = path31.normalize(relativePath).replace(/^(\.\/)+/, "");
35336
- const resolved = path31.resolve(cwd, normalized);
35337
- if (!resolved.startsWith(cwd + path31.sep) && resolved !== cwd) {
35532
+ const normalized = path34.normalize(relativePath).replace(/^(\.\/)+/, "");
35533
+ const resolved = path34.resolve(cwd, normalized);
35534
+ if (!resolved.startsWith(cwd + path34.sep) && resolved !== cwd) {
35338
35535
  return null;
35339
35536
  }
35340
35537
  return resolved;
@@ -35348,7 +35545,7 @@ async function listDirAsync(relativePath) {
35348
35545
  return { error: "Path is outside working directory" };
35349
35546
  }
35350
35547
  try {
35351
- const names = await fs30.promises.readdir(resolved, { withFileTypes: true });
35548
+ const names = await fs32.promises.readdir(resolved, { withFileTypes: true });
35352
35549
  const visible = names.filter((d) => !d.name.startsWith("."));
35353
35550
  const entries = [];
35354
35551
  for (let i = 0; i < visible.length; i++) {
@@ -35356,12 +35553,12 @@ async function listDirAsync(relativePath) {
35356
35553
  await yieldToEventLoop();
35357
35554
  }
35358
35555
  const d = visible[i];
35359
- const entryPath = path32.join(relativePath || ".", d.name).replace(/\\/g, "/");
35360
- const fullPath = path32.join(resolved, d.name);
35556
+ const entryPath = path35.join(relativePath || ".", d.name).replace(/\\/g, "/");
35557
+ const fullPath = path35.join(resolved, d.name);
35361
35558
  let isDir = d.isDirectory();
35362
35559
  if (d.isSymbolicLink()) {
35363
35560
  try {
35364
- const targetStat = await fs30.promises.stat(fullPath);
35561
+ const targetStat = await fs32.promises.stat(fullPath);
35365
35562
  isDir = targetStat.isDirectory();
35366
35563
  } catch {
35367
35564
  isDir = false;
@@ -35386,25 +35583,25 @@ async function listDirAsync(relativePath) {
35386
35583
  }
35387
35584
 
35388
35585
  // src/files/read-file.ts
35389
- import fs31 from "node:fs";
35586
+ import fs33 from "node:fs";
35390
35587
  import { StringDecoder } from "node:string_decoder";
35391
35588
  function resolveFilePath(relativePath) {
35392
35589
  const resolved = ensureUnderCwd(relativePath, getBridgeRoot());
35393
35590
  if (!resolved) return { error: "Path is outside working directory" };
35394
35591
  let real;
35395
35592
  try {
35396
- real = fs31.realpathSync(resolved);
35593
+ real = fs33.realpathSync(resolved);
35397
35594
  } catch {
35398
35595
  real = resolved;
35399
35596
  }
35400
- const stat2 = fs31.statSync(real);
35597
+ const stat2 = fs33.statSync(real);
35401
35598
  if (!stat2.isFile()) return { error: "Not a file" };
35402
35599
  return real;
35403
35600
  }
35404
35601
  var LINE_CHUNK_SIZE = 64 * 1024;
35405
35602
  function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
35406
- const fileSize = fs31.statSync(filePath).size;
35407
- const fd = fs31.openSync(filePath, "r");
35603
+ const fileSize = fs33.statSync(filePath).size;
35604
+ const fd = fs33.openSync(filePath, "r");
35408
35605
  const bufSize = 64 * 1024;
35409
35606
  const buf = Buffer.alloc(bufSize);
35410
35607
  const decoder = new StringDecoder("utf8");
@@ -35417,7 +35614,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
35417
35614
  let line0Accum = "";
35418
35615
  try {
35419
35616
  let bytesRead;
35420
- while (!done && (bytesRead = fs31.readSync(fd, buf, 0, bufSize, null)) > 0) {
35617
+ while (!done && (bytesRead = fs33.readSync(fd, buf, 0, bufSize, null)) > 0) {
35421
35618
  const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
35422
35619
  partial2 = "";
35423
35620
  let lineStart = 0;
@@ -35552,7 +35749,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
35552
35749
  }
35553
35750
  return { content: resultLines.join("\n"), size: fileSize };
35554
35751
  } finally {
35555
- fs31.closeSync(fd);
35752
+ fs33.closeSync(fd);
35556
35753
  }
35557
35754
  }
35558
35755
  function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
@@ -35563,8 +35760,8 @@ function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize =
35563
35760
  if (hasRange) {
35564
35761
  return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
35565
35762
  }
35566
- const stat2 = fs31.statSync(result);
35567
- const raw = fs31.readFileSync(result, "utf8");
35763
+ const stat2 = fs33.statSync(result);
35764
+ const raw = fs33.readFileSync(result, "utf8");
35568
35765
  const lines = raw.split(/\r?\n/);
35569
35766
  return { content: raw, totalLines: lines.length, size: stat2.size };
35570
35767
  } catch (err) {
@@ -35577,14 +35774,14 @@ async function readFileAsync(relativePath, startLine, endLine, lineOffset, lineC
35577
35774
  }
35578
35775
 
35579
35776
  // src/files/handle-file-browser-search.ts
35777
+ import path36 from "node:path";
35580
35778
  var SEARCH_LIMIT = 100;
35581
35779
  function handleFileBrowserSearch(msg, socket, e2ee) {
35582
35780
  void (async () => {
35583
35781
  await yieldToEventLoop();
35584
35782
  const q = typeof msg.q === "string" ? msg.q : "";
35585
- const cwd = getBridgeRoot();
35586
- const index = loadFileIndex(cwd);
35587
- if (index === null) {
35783
+ const cwd = path36.resolve(getBridgeRoot());
35784
+ if (!bridgeFileIndexIsPopulated(cwd)) {
35588
35785
  const payload2 = {
35589
35786
  type: "file_browser_search_response",
35590
35787
  id: msg.id,
@@ -35594,7 +35791,7 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
35594
35791
  sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload2, ["paths"]) : payload2);
35595
35792
  return;
35596
35793
  }
35597
- const results = await searchFileIndexAsync(index, q, SEARCH_LIMIT);
35794
+ const results = await searchBridgeFilePathsAsync(cwd, q, SEARCH_LIMIT);
35598
35795
  const payload = {
35599
35796
  type: "file_browser_search_response",
35600
35797
  id: msg.id,
@@ -35682,8 +35879,8 @@ function handleSkillLayoutRequest(msg, deps) {
35682
35879
  }
35683
35880
 
35684
35881
  // src/skills/install-remote-skills.ts
35685
- import fs32 from "node:fs";
35686
- import path33 from "node:path";
35882
+ import fs34 from "node:fs";
35883
+ import path37 from "node:path";
35687
35884
  function installRemoteSkills(cwd, targetDir, items) {
35688
35885
  const installed2 = [];
35689
35886
  if (!Array.isArray(items)) {
@@ -35694,15 +35891,15 @@ function installRemoteSkills(cwd, targetDir, items) {
35694
35891
  if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
35695
35892
  continue;
35696
35893
  }
35697
- const skillDir = path33.join(cwd, targetDir, item.skillName);
35894
+ const skillDir = path37.join(cwd, targetDir, item.skillName);
35698
35895
  for (const f of item.files) {
35699
35896
  if (typeof f.path !== "string" || !f.text && !f.base64) continue;
35700
- const dest = path33.join(skillDir, f.path);
35701
- fs32.mkdirSync(path33.dirname(dest), { recursive: true });
35897
+ const dest = path37.join(skillDir, f.path);
35898
+ fs34.mkdirSync(path37.dirname(dest), { recursive: true });
35702
35899
  if (f.text !== void 0) {
35703
- fs32.writeFileSync(dest, f.text, "utf8");
35900
+ fs34.writeFileSync(dest, f.text, "utf8");
35704
35901
  } else if (f.base64) {
35705
- fs32.writeFileSync(dest, Buffer.from(f.base64, "base64"));
35902
+ fs34.writeFileSync(dest, Buffer.from(f.base64, "base64"));
35706
35903
  }
35707
35904
  }
35708
35905
  installed2.push({
@@ -35852,7 +36049,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
35852
36049
  };
35853
36050
 
35854
36051
  // src/routing/handlers/revert-turn-snapshot.ts
35855
- import * as fs33 from "node:fs";
36052
+ import * as fs35 from "node:fs";
35856
36053
  var handleRevertTurnSnapshotMessage = (msg, deps) => {
35857
36054
  const id = typeof msg.id === "string" ? msg.id : "";
35858
36055
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
@@ -35864,7 +36061,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
35864
36061
  if (!s) return;
35865
36062
  const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
35866
36063
  const file2 = snapshotFilePath(agentBase, turnId);
35867
- if (!fs33.existsSync(file2)) {
36064
+ if (!fs35.existsSync(file2)) {
35868
36065
  sendWsMessage(s, {
35869
36066
  type: "revert_turn_snapshot_result",
35870
36067
  id,
@@ -36359,6 +36556,7 @@ async function createBridgeConnection(options) {
36359
36556
  const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
36360
36557
  const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
36361
36558
  const logFn = options.log ?? log;
36559
+ getCliDatabase({ logLegacyMigration: logFn });
36362
36560
  const tokens = {
36363
36561
  accessToken: options.authToken,
36364
36562
  refreshToken: options.refreshToken
@@ -36424,8 +36622,8 @@ async function createBridgeConnection(options) {
36424
36622
  getCloudAccessToken: () => tokens.accessToken
36425
36623
  };
36426
36624
  const identifyReportedPaths = {
36427
- bridgeRootPath: path34.resolve(getBridgeRoot()),
36428
- worktreesRootPath: path34.resolve(worktreesRootPath)
36625
+ bridgeRootPath: path38.resolve(getBridgeRoot()),
36626
+ worktreesRootPath: path38.resolve(worktreesRootPath)
36429
36627
  };
36430
36628
  const { connect } = createMainBridgeWebSocketLifecycle({
36431
36629
  state,