@buildautomaton/cli 0.1.56 → 0.1.57

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
@@ -4175,8 +4175,8 @@ var init_parseUtil = __esm({
4175
4175
  init_errors();
4176
4176
  init_en();
4177
4177
  makeIssue = (params) => {
4178
- const { data, path: path71, errorMaps, issueData } = params;
4179
- const fullPath = [...path71, ...issueData.path || []];
4178
+ const { data, path: path73, errorMaps, issueData } = params;
4179
+ const fullPath = [...path73, ...issueData.path || []];
4180
4180
  const fullIssue = {
4181
4181
  ...issueData,
4182
4182
  path: fullPath
@@ -4484,11 +4484,11 @@ var init_types = __esm({
4484
4484
  init_parseUtil();
4485
4485
  init_util();
4486
4486
  ParseInputLazyPath = class {
4487
- constructor(parent, value, path71, key) {
4487
+ constructor(parent, value, path73, key) {
4488
4488
  this._cachedPath = [];
4489
4489
  this.parent = parent;
4490
4490
  this.data = value;
4491
- this._path = path71;
4491
+ this._path = path73;
4492
4492
  this._key = key;
4493
4493
  }
4494
4494
  get path() {
@@ -8103,10 +8103,10 @@ function assignProp(target, prop, value) {
8103
8103
  configurable: true
8104
8104
  });
8105
8105
  }
8106
- function getElementAtPath(obj, path71) {
8107
- if (!path71)
8106
+ function getElementAtPath(obj, path73) {
8107
+ if (!path73)
8108
8108
  return obj;
8109
- return path71.reduce((acc, key) => acc?.[key], obj);
8109
+ return path73.reduce((acc, key) => acc?.[key], obj);
8110
8110
  }
8111
8111
  function promiseAllObject(promisesObj) {
8112
8112
  const keys = Object.keys(promisesObj);
@@ -8355,11 +8355,11 @@ function aborted(x, startIndex = 0) {
8355
8355
  }
8356
8356
  return false;
8357
8357
  }
8358
- function prefixIssues(path71, issues) {
8358
+ function prefixIssues(path73, issues) {
8359
8359
  return issues.map((iss) => {
8360
8360
  var _a2;
8361
8361
  (_a2 = iss).path ?? (_a2.path = []);
8362
- iss.path.unshift(path71);
8362
+ iss.path.unshift(path73);
8363
8363
  return iss;
8364
8364
  });
8365
8365
  }
@@ -8548,7 +8548,7 @@ function treeifyError(error40, _mapper) {
8548
8548
  return issue2.message;
8549
8549
  };
8550
8550
  const result = { errors: [] };
8551
- const processError = (error41, path71 = []) => {
8551
+ const processError = (error41, path73 = []) => {
8552
8552
  var _a2, _b;
8553
8553
  for (const issue2 of error41.issues) {
8554
8554
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -8558,7 +8558,7 @@ function treeifyError(error40, _mapper) {
8558
8558
  } else if (issue2.code === "invalid_element") {
8559
8559
  processError({ issues: issue2.issues }, issue2.path);
8560
8560
  } else {
8561
- const fullpath = [...path71, ...issue2.path];
8561
+ const fullpath = [...path73, ...issue2.path];
8562
8562
  if (fullpath.length === 0) {
8563
8563
  result.errors.push(mapper(issue2));
8564
8564
  continue;
@@ -8588,9 +8588,9 @@ function treeifyError(error40, _mapper) {
8588
8588
  processError(error40);
8589
8589
  return result;
8590
8590
  }
8591
- function toDotPath(path71) {
8591
+ function toDotPath(path73) {
8592
8592
  const segs = [];
8593
- for (const seg of path71) {
8593
+ for (const seg of path73) {
8594
8594
  if (typeof seg === "number")
8595
8595
  segs.push(`[${seg}]`);
8596
8596
  else if (typeof seg === "symbol")
@@ -21596,7 +21596,7 @@ var require_ignore = __commonJS({
21596
21596
  // path matching.
21597
21597
  // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
21598
21598
  // @returns {TestResult} true if a file is ignored
21599
- test(path71, checkUnignored, mode) {
21599
+ test(path73, checkUnignored, mode) {
21600
21600
  let ignored = false;
21601
21601
  let unignored = false;
21602
21602
  let matchedRule;
@@ -21605,7 +21605,7 @@ var require_ignore = __commonJS({
21605
21605
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
21606
21606
  return;
21607
21607
  }
21608
- const matched = rule[mode].test(path71);
21608
+ const matched = rule[mode].test(path73);
21609
21609
  if (!matched) {
21610
21610
  return;
21611
21611
  }
@@ -21626,17 +21626,17 @@ var require_ignore = __commonJS({
21626
21626
  var throwError = (message, Ctor) => {
21627
21627
  throw new Ctor(message);
21628
21628
  };
21629
- var checkPath = (path71, originalPath, doThrow) => {
21630
- if (!isString(path71)) {
21629
+ var checkPath = (path73, originalPath, doThrow) => {
21630
+ if (!isString(path73)) {
21631
21631
  return doThrow(
21632
21632
  `path must be a string, but got \`${originalPath}\``,
21633
21633
  TypeError
21634
21634
  );
21635
21635
  }
21636
- if (!path71) {
21636
+ if (!path73) {
21637
21637
  return doThrow(`path must not be empty`, TypeError);
21638
21638
  }
21639
- if (checkPath.isNotRelative(path71)) {
21639
+ if (checkPath.isNotRelative(path73)) {
21640
21640
  const r = "`path.relative()`d";
21641
21641
  return doThrow(
21642
21642
  `path should be a ${r} string, but got "${originalPath}"`,
@@ -21645,7 +21645,7 @@ var require_ignore = __commonJS({
21645
21645
  }
21646
21646
  return true;
21647
21647
  };
21648
- var isNotRelative = (path71) => REGEX_TEST_INVALID_PATH.test(path71);
21648
+ var isNotRelative = (path73) => REGEX_TEST_INVALID_PATH.test(path73);
21649
21649
  checkPath.isNotRelative = isNotRelative;
21650
21650
  checkPath.convert = (p) => p;
21651
21651
  var Ignore = class {
@@ -21675,19 +21675,19 @@ var require_ignore = __commonJS({
21675
21675
  }
21676
21676
  // @returns {TestResult}
21677
21677
  _test(originalPath, cache2, checkUnignored, slices) {
21678
- const path71 = originalPath && checkPath.convert(originalPath);
21678
+ const path73 = originalPath && checkPath.convert(originalPath);
21679
21679
  checkPath(
21680
- path71,
21680
+ path73,
21681
21681
  originalPath,
21682
21682
  this._strictPathCheck ? throwError : RETURN_FALSE
21683
21683
  );
21684
- return this._t(path71, cache2, checkUnignored, slices);
21684
+ return this._t(path73, cache2, checkUnignored, slices);
21685
21685
  }
21686
- checkIgnore(path71) {
21687
- if (!REGEX_TEST_TRAILING_SLASH.test(path71)) {
21688
- return this.test(path71);
21686
+ checkIgnore(path73) {
21687
+ if (!REGEX_TEST_TRAILING_SLASH.test(path73)) {
21688
+ return this.test(path73);
21689
21689
  }
21690
- const slices = path71.split(SLASH).filter(Boolean);
21690
+ const slices = path73.split(SLASH).filter(Boolean);
21691
21691
  slices.pop();
21692
21692
  if (slices.length) {
21693
21693
  const parent = this._t(
@@ -21700,18 +21700,18 @@ var require_ignore = __commonJS({
21700
21700
  return parent;
21701
21701
  }
21702
21702
  }
21703
- return this._rules.test(path71, false, MODE_CHECK_IGNORE);
21703
+ return this._rules.test(path73, false, MODE_CHECK_IGNORE);
21704
21704
  }
21705
- _t(path71, cache2, checkUnignored, slices) {
21706
- if (path71 in cache2) {
21707
- return cache2[path71];
21705
+ _t(path73, cache2, checkUnignored, slices) {
21706
+ if (path73 in cache2) {
21707
+ return cache2[path73];
21708
21708
  }
21709
21709
  if (!slices) {
21710
- slices = path71.split(SLASH).filter(Boolean);
21710
+ slices = path73.split(SLASH).filter(Boolean);
21711
21711
  }
21712
21712
  slices.pop();
21713
21713
  if (!slices.length) {
21714
- return cache2[path71] = this._rules.test(path71, checkUnignored, MODE_IGNORE);
21714
+ return cache2[path73] = this._rules.test(path73, checkUnignored, MODE_IGNORE);
21715
21715
  }
21716
21716
  const parent = this._t(
21717
21717
  slices.join(SLASH) + SLASH,
@@ -21719,29 +21719,29 @@ var require_ignore = __commonJS({
21719
21719
  checkUnignored,
21720
21720
  slices
21721
21721
  );
21722
- return cache2[path71] = parent.ignored ? parent : this._rules.test(path71, checkUnignored, MODE_IGNORE);
21722
+ return cache2[path73] = parent.ignored ? parent : this._rules.test(path73, checkUnignored, MODE_IGNORE);
21723
21723
  }
21724
- ignores(path71) {
21725
- return this._test(path71, this._ignoreCache, false).ignored;
21724
+ ignores(path73) {
21725
+ return this._test(path73, this._ignoreCache, false).ignored;
21726
21726
  }
21727
21727
  createFilter() {
21728
- return (path71) => !this.ignores(path71);
21728
+ return (path73) => !this.ignores(path73);
21729
21729
  }
21730
21730
  filter(paths) {
21731
21731
  return makeArray(paths).filter(this.createFilter());
21732
21732
  }
21733
21733
  // @returns {TestResult}
21734
- test(path71) {
21735
- return this._test(path71, this._testCache, true);
21734
+ test(path73) {
21735
+ return this._test(path73, this._testCache, true);
21736
21736
  }
21737
21737
  };
21738
21738
  var factory = (options) => new Ignore(options);
21739
- var isPathValid = (path71) => checkPath(path71 && checkPath.convert(path71), path71, RETURN_FALSE);
21739
+ var isPathValid = (path73) => checkPath(path73 && checkPath.convert(path73), path73, RETURN_FALSE);
21740
21740
  var setupWindows = () => {
21741
21741
  const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
21742
21742
  checkPath.convert = makePosix;
21743
21743
  const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
21744
- checkPath.isNotRelative = (path71) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path71) || isNotRelative(path71);
21744
+ checkPath.isNotRelative = (path73) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path73) || isNotRelative(path73);
21745
21745
  };
21746
21746
  if (
21747
21747
  // Detect `process` so that it can run in browsers.
@@ -22530,10 +22530,10 @@ var require_src2 = __commonJS({
22530
22530
  var fs_1 = __require("fs");
22531
22531
  var debug_1 = __importDefault(require_src());
22532
22532
  var log2 = debug_1.default("@kwsites/file-exists");
22533
- function check2(path71, isFile, isDirectory) {
22534
- log2(`checking %s`, path71);
22533
+ function check2(path73, isFile, isDirectory) {
22534
+ log2(`checking %s`, path73);
22535
22535
  try {
22536
- const stat2 = fs_1.statSync(path71);
22536
+ const stat2 = fs_1.statSync(path73);
22537
22537
  if (stat2.isFile() && isFile) {
22538
22538
  log2(`[OK] path represents a file`);
22539
22539
  return true;
@@ -22553,8 +22553,8 @@ var require_src2 = __commonJS({
22553
22553
  throw e;
22554
22554
  }
22555
22555
  }
22556
- function exists2(path71, type = exports.READABLE) {
22557
- return check2(path71, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
22556
+ function exists2(path73, type = exports.READABLE) {
22557
+ return check2(path73, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
22558
22558
  }
22559
22559
  exports.exists = exists2;
22560
22560
  exports.FILE = 1;
@@ -23640,9 +23640,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
23640
23640
  const rawPath = typeof o.path === "string" ? o.path.trim() : "";
23641
23641
  const summary = typeof o.summary === "string" ? o.summary.trim() : "";
23642
23642
  if (!rawPath || !summary) continue;
23643
- const path71 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
23644
- if (!path71) continue;
23645
- rows.push({ path: path71, summary: clampSummaryToAtMostTwoLines(summary) });
23643
+ const path73 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
23644
+ if (!path73) continue;
23645
+ rows.push({ path: path73, summary: clampSummaryToAtMostTwoLines(summary) });
23646
23646
  }
23647
23647
  return rows;
23648
23648
  }
@@ -24956,8 +24956,8 @@ function randomSecret() {
24956
24956
  }
24957
24957
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
24958
24958
  }
24959
- async function requestPreviewApi(port, secret, method, path71, body) {
24960
- const url2 = `http://127.0.0.1:${port}${path71}`;
24959
+ async function requestPreviewApi(port, secret, method, path73, body) {
24960
+ const url2 = `http://127.0.0.1:${port}${path73}`;
24961
24961
  const headers = {
24962
24962
  [PREVIEW_SECRET_HEADER]: secret,
24963
24963
  "Content-Type": "application/json"
@@ -24969,7 +24969,7 @@ async function requestPreviewApi(port, secret, method, path71, body) {
24969
24969
  });
24970
24970
  const data = await res.json().catch(() => ({}));
24971
24971
  if (!res.ok) {
24972
- throw new Error(data?.error ?? `Preview API ${method} ${path71}: ${res.status}`);
24972
+ throw new Error(data?.error ?? `Preview API ${method} ${path73}: ${res.status}`);
24973
24973
  }
24974
24974
  return data;
24975
24975
  }
@@ -25184,7 +25184,7 @@ function installBridgeProcessResilience() {
25184
25184
  }
25185
25185
 
25186
25186
  // src/cli-version.ts
25187
- var CLI_VERSION = "0.1.56".length > 0 ? "0.1.56" : "0.0.0-dev";
25187
+ var CLI_VERSION = "0.1.57".length > 0 ? "0.1.57" : "0.0.0-dev";
25188
25188
 
25189
25189
  // src/connection/heartbeat/constants.ts
25190
25190
  var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
@@ -26043,7 +26043,7 @@ function clearMainBridgeReconnectQuietOnOpen(state, log2) {
26043
26043
  function scheduleMainBridgeReconnect(state, connect, log2, closeMeta) {
26044
26044
  if (state.closedByUser || state.currentWs != null) return;
26045
26045
  const meta = closeMeta ?? state.lastReconnectCloseMeta ?? void 0;
26046
- const delay2 = applyTieredReconnectPlanAndLog(
26046
+ const delay3 = applyTieredReconnectPlanAndLog(
26047
26047
  state.mainOutage,
26048
26048
  log2,
26049
26049
  BRIDGE_SERVICE_LABEL,
@@ -26052,7 +26052,7 @@ function scheduleMainBridgeReconnect(state, connect, log2, closeMeta) {
26052
26052
  meta?.reason
26053
26053
  );
26054
26054
  armReconnectDelayTimer({
26055
- delayMs: delay2,
26055
+ delayMs: delay3,
26056
26056
  bumpAttempt: () => {
26057
26057
  state.reconnectAttempt += 1;
26058
26058
  },
@@ -26254,10 +26254,10 @@ function runPendingAuth(options) {
26254
26254
  }
26255
26255
  if (resolved) return;
26256
26256
  beginDeferredPendingCloseLog(code, reason);
26257
- const delay2 = pendingAuthReconnectDelayMs(reconnectAttempt);
26257
+ const delay3 = pendingAuthReconnectDelayMs(reconnectAttempt);
26258
26258
  reconnectAttempt += 1;
26259
26259
  if (signInQuiet.verboseLogs) {
26260
- const delayLabel = formatReconnectDelayForLog(delay2);
26260
+ const delayLabel = formatReconnectDelayForLog(delay3);
26261
26261
  logFn(
26262
26262
  `[Bridge service] Next sign-in connection attempt in ${delayLabel} (attempt ${reconnectAttempt}).`
26263
26263
  );
@@ -26265,7 +26265,7 @@ function runPendingAuth(options) {
26265
26265
  reconnectTimeout = setTimeout(() => {
26266
26266
  reconnectTimeout = null;
26267
26267
  connect();
26268
- }, delay2);
26268
+ }, delay3);
26269
26269
  },
26270
26270
  onError: (err) => logCliWebSocketError(logFn, "[Bridge service]", err, "while waiting for sign-in"),
26271
26271
  onMessage: (data) => {
@@ -26359,11 +26359,7 @@ function isCliSqliteLockError(e) {
26359
26359
  return lower.includes("database is locked") || lower.includes("sqlite_busy") || lower.includes("sqlite3_busy") || lower.includes("database") && lower.includes("locked");
26360
26360
  }
26361
26361
 
26362
- // src/sqlite/create-sqlite-database-access.ts
26363
- var { Database: SqliteDatabase } = sqliteWasm;
26364
- var SYNC_RETRY_MAX = 40;
26365
- var ASYNC_RETRY_MAX = 60;
26366
- var ASYNC_BASE_DELAY_MS = 20;
26362
+ // src/sqlite/sqlite-pragmas.ts
26367
26363
  function applySqliteConcurrencyPragmas(db) {
26368
26364
  try {
26369
26365
  db.run("PRAGMA foreign_keys = ON");
@@ -26389,12 +26385,17 @@ function applySqliteMemoryPragmas(db) {
26389
26385
  } catch {
26390
26386
  }
26391
26387
  }
26388
+
26389
+ // src/sqlite/sqlite-lock-retry.ts
26390
+ var SYNC_RETRY_MAX = 40;
26391
+ var ASYNC_RETRY_MAX = 60;
26392
+ var ASYNC_BASE_DELAY_MS = 20;
26392
26393
  function syncSleepMs(ms) {
26393
26394
  if (ms <= 0) return;
26394
26395
  const deadline = Date.now() + ms;
26395
26396
  while (Date.now() < deadline) {
26396
26397
  if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
26397
- const chunk = Math.min(80, deadline - Date.now());
26398
+ const chunk = Math.min(10, deadline - Date.now());
26398
26399
  if (chunk <= 0) break;
26399
26400
  try {
26400
26401
  const sab = new SharedArrayBuffer(4);
@@ -26418,7 +26419,22 @@ async function asyncDelayMsInterruptible(ms) {
26418
26419
  await yieldToEventLoop();
26419
26420
  }
26420
26421
  }
26422
+
26423
+ // src/sqlite/create-sqlite-database-access.ts
26424
+ var { Database: SqliteDatabase } = sqliteWasm;
26421
26425
  function createSqliteDatabaseAccess(config2) {
26426
+ let migrateDoneForPath = null;
26427
+ function shouldSkipMigrate(sqlitePath, db) {
26428
+ if (migrateDoneForPath !== sqlitePath) return false;
26429
+ try {
26430
+ const row = db.get(
26431
+ "SELECT 1 as ok FROM sqlite_master WHERE type='table' AND name='__migrations' LIMIT 1"
26432
+ );
26433
+ return row != null;
26434
+ } catch {
26435
+ return false;
26436
+ }
26437
+ }
26422
26438
  function safeClose(db) {
26423
26439
  if (db == null) return;
26424
26440
  try {
@@ -26434,7 +26450,11 @@ function createSqliteDatabaseAccess(config2) {
26434
26450
  try {
26435
26451
  applySqliteConcurrencyPragmas(db);
26436
26452
  applySqliteMemoryPragmas(db);
26437
- config2.migrate(db);
26453
+ const sqlitePath2 = config2.getPath();
26454
+ if (!shouldSkipMigrate(sqlitePath2, db)) {
26455
+ config2.migrate(db);
26456
+ migrateDoneForPath = sqlitePath2;
26457
+ }
26438
26458
  config2.afterOpen?.(db, options);
26439
26459
  } catch (e) {
26440
26460
  safeClose(db);
@@ -26490,14 +26510,16 @@ function createSqliteDatabaseAccess(config2) {
26490
26510
  async function ensureInitialized(options) {
26491
26511
  await withAsync(() => void 0, options);
26492
26512
  }
26513
+ function closeAllConnections() {
26514
+ migrateDoneForPath = null;
26515
+ }
26493
26516
  return {
26494
26517
  safeClose,
26495
26518
  openConnection,
26496
26519
  withSync,
26497
26520
  withAsync,
26498
26521
  ensureInitialized,
26499
- closeAllConnections: () => {
26500
- }
26522
+ closeAllConnections
26501
26523
  };
26502
26524
  }
26503
26525
 
@@ -26697,7 +26719,7 @@ function readMigrationSql(filename, ...searchSubdirs) {
26697
26719
  join(moduleDir, "..", sub, filename),
26698
26720
  join(moduleDir, "..", "..", "dist", sub, filename)
26699
26721
  ]);
26700
- const resolved = candidates.find((path71) => existsSync(path71));
26722
+ const resolved = candidates.find((path73) => existsSync(path73));
26701
26723
  if (!resolved) {
26702
26724
  throw new Error(`Missing SQLite migration SQL: ${filename} (searched ${searchSubdirs.join(", ")})`);
26703
26725
  }
@@ -26829,6 +26851,161 @@ var withCliSqliteSync = cliSqlite.withSync;
26829
26851
  var withCliSqlite = cliSqlite.withAsync;
26830
26852
  var ensureCliSqliteInitialized = cliSqlite.ensureInitialized;
26831
26853
 
26854
+ // src/sqlite/code-nav-cache/code-nav-cache-paths.ts
26855
+ import fs14 from "node:fs";
26856
+ import path12 from "node:path";
26857
+ import os7 from "node:os";
26858
+ function getCodeNavCacheSqlitePath() {
26859
+ const override = process.env.BUILDAMATON_CODE_NAV_CACHE_SQLITE_PATH?.trim();
26860
+ if (override) return path12.resolve(override);
26861
+ return path12.join(os7.homedir(), ".buildautomaton", "code-nav-cache.sqlite");
26862
+ }
26863
+ function ensureCodeNavCacheSqliteParentDir(sqlitePath) {
26864
+ const dir = path12.dirname(sqlitePath);
26865
+ if (!fs14.existsSync(dir)) fs14.mkdirSync(dir, { recursive: true });
26866
+ }
26867
+
26868
+ // src/sqlite/code-nav-cache/migrate-code-nav-cache-sqlite.ts
26869
+ var CHECKPOINT_V12 = "001_code_nav_cache_checkpoint_v1";
26870
+ var CHECKPOINT_V1_SQL2 = readCodeNavCacheMigrationSql("001_code_nav_cache_checkpoint_v1.sql");
26871
+ var MIGRATION_002 = "002_content_hash_symbol_index";
26872
+ var MIGRATION_002_SQL = readCodeNavCacheMigrationSql("002_content_hash_symbol_index.sql");
26873
+ var MIGRATION_003 = "003_content_hash_tag_rows";
26874
+ var MIGRATION_003_SQL = readCodeNavCacheMigrationSql("003_content_hash_tag_rows.sql");
26875
+ var CODE_NAV_CACHE_SQLITE_MIGRATIONS = [
26876
+ {
26877
+ name: CHECKPOINT_V12,
26878
+ checkpoint: true,
26879
+ migrate: (db) => {
26880
+ db.exec(CHECKPOINT_V1_SQL2);
26881
+ },
26882
+ alreadyApplied: (db) => {
26883
+ const row = db.get(
26884
+ `SELECT 1 as ok FROM sqlite_master WHERE type='table' AND name='file_index_parent_path' LIMIT 1`
26885
+ );
26886
+ return row != null;
26887
+ }
26888
+ },
26889
+ {
26890
+ name: MIGRATION_002,
26891
+ migrate: (db) => {
26892
+ db.exec(MIGRATION_002_SQL);
26893
+ },
26894
+ alreadyApplied: (db) => {
26895
+ const row = db.get(
26896
+ `SELECT 1 as ok FROM sqlite_master WHERE type='table' AND name='symbol_file_blob' LIMIT 1`
26897
+ );
26898
+ return row != null;
26899
+ }
26900
+ },
26901
+ {
26902
+ name: MIGRATION_003,
26903
+ migrate: (db) => {
26904
+ db.exec(MIGRATION_003_SQL);
26905
+ },
26906
+ alreadyApplied: (db) => {
26907
+ const row = db.get(
26908
+ `SELECT 1 as ok FROM sqlite_master WHERE type='table' AND name='symbol_index_tag' LIMIT 1`
26909
+ );
26910
+ if (row == null) return false;
26911
+ const blob = db.get(
26912
+ `SELECT 1 as ok FROM sqlite_master WHERE type='table' AND name='symbol_file_blob' LIMIT 1`
26913
+ );
26914
+ return blob == null;
26915
+ }
26916
+ }
26917
+ ];
26918
+ function migrateCodeNavCacheSqlite(db) {
26919
+ runSqliteMigrations(
26920
+ db,
26921
+ CODE_NAV_CACHE_SQLITE_MIGRATIONS,
26922
+ readCodeNavCacheMigrationSql("000_bootstrap_migrations_table.sql"),
26923
+ "code-nav-cache"
26924
+ );
26925
+ }
26926
+
26927
+ // src/sqlite/code-nav-cache/code-nav-cache-sqlite-work-lock.ts
26928
+ import fs15 from "node:fs";
26929
+ function isSqliteCorruptError(e) {
26930
+ const msg = e instanceof Error ? e.message : String(e);
26931
+ return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
26932
+ }
26933
+ var chain = Promise.resolve();
26934
+ var workLockDepth = 0;
26935
+ function resetCodeNavCacheSqliteWorkLock() {
26936
+ chain = Promise.resolve();
26937
+ workLockDepth = 0;
26938
+ }
26939
+ function withCodeNavCacheSqliteWorkLock(fn) {
26940
+ if (workLockDepth > 0) {
26941
+ return Promise.resolve(fn());
26942
+ }
26943
+ const run = async () => {
26944
+ workLockDepth += 1;
26945
+ try {
26946
+ return await Promise.resolve(fn());
26947
+ } finally {
26948
+ workLockDepth = Math.max(0, workLockDepth - 1);
26949
+ }
26950
+ };
26951
+ const runWithCorruptRecovery = async () => {
26952
+ try {
26953
+ return await run();
26954
+ } catch (e) {
26955
+ if (!isSqliteCorruptError(e)) throw e;
26956
+ try {
26957
+ fs15.unlinkSync(getCodeNavCacheSqlitePath());
26958
+ } catch {
26959
+ }
26960
+ chain = Promise.resolve();
26961
+ return await run();
26962
+ }
26963
+ };
26964
+ const next = chain.then(runWithCorruptRecovery);
26965
+ chain = next.then(
26966
+ () => void 0,
26967
+ () => void 0
26968
+ );
26969
+ return next;
26970
+ }
26971
+
26972
+ // src/sqlite/code-nav-cache/code-nav-cache-database.ts
26973
+ var codeNavCacheSqlite = createSqliteDatabaseAccess({
26974
+ getPath: getCodeNavCacheSqlitePath,
26975
+ ensureParentDir: ensureCodeNavCacheSqliteParentDir,
26976
+ migrate: migrateCodeNavCacheSqlite
26977
+ });
26978
+ var codeNavCacheAccessDepth = 0;
26979
+ async function waitForOuterCodeNavCacheAccessAsync() {
26980
+ while (codeNavCacheAccessDepth > 0) {
26981
+ if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
26982
+ await new Promise((resolve32) => setTimeout(resolve32, 5));
26983
+ await yieldToEventLoop();
26984
+ }
26985
+ }
26986
+ var safeCloseCodeNavCacheSqliteDatabase = codeNavCacheSqlite.safeClose;
26987
+ function closeAllCodeNavCacheSqliteConnections() {
26988
+ codeNavCacheSqlite.closeAllConnections();
26989
+ resetCodeNavCacheSqliteWorkLock();
26990
+ codeNavCacheAccessDepth = 0;
26991
+ }
26992
+ var openCodeNavCacheSqliteConnection = codeNavCacheSqlite.openConnection;
26993
+ async function withCodeNavCacheSqlite(fn) {
26994
+ return withCodeNavCacheSqliteWorkLock(async () => {
26995
+ const nested = codeNavCacheAccessDepth > 0;
26996
+ if (!nested) await waitForOuterCodeNavCacheAccessAsync();
26997
+ codeNavCacheAccessDepth += 1;
26998
+ try {
26999
+ return await codeNavCacheSqlite.withAsync(fn);
27000
+ } finally {
27001
+ codeNavCacheAccessDepth = Math.max(0, codeNavCacheAccessDepth - 1);
27002
+ }
27003
+ });
27004
+ }
27005
+ async function ensureCodeNavCacheSqliteInitialized() {
27006
+ await withCodeNavCacheSqlite(() => void 0);
27007
+ }
27008
+
26832
27009
  // src/connection/close-bridge-connection.ts
26833
27010
  async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
26834
27011
  requestCliImmediateShutdown();
@@ -26874,6 +27051,7 @@ async function closeBridgeConnection(state, acpManager, devServerManager, log2)
26874
27051
  }
26875
27052
  try {
26876
27053
  closeAllCliSqliteConnections();
27054
+ closeAllCodeNavCacheSqliteConnections();
26877
27055
  } catch {
26878
27056
  }
26879
27057
  say("Shutdown complete.");
@@ -26960,16 +27138,16 @@ import * as fs20 from "node:fs";
26960
27138
  import * as path24 from "node:path";
26961
27139
 
26962
27140
  // src/paths/session-layout-paths.ts
26963
- import * as path12 from "node:path";
27141
+ import * as path13 from "node:path";
26964
27142
  function resolveIsolatedSessionParentPathFromCheckouts(worktreePaths) {
26965
- const resolved = worktreePaths.map((p) => path12.resolve(p)).filter(Boolean);
27143
+ const resolved = worktreePaths.map((p) => path13.resolve(p)).filter(Boolean);
26966
27144
  if (resolved.length === 0) return null;
26967
27145
  resolved.sort();
26968
27146
  return resolved[0];
26969
27147
  }
26970
27148
  function resolveSessionParentPathForAgentProcess(resolvedSessionParentPath) {
26971
27149
  if (resolvedSessionParentPath != null && String(resolvedSessionParentPath).trim() !== "") {
26972
- return path12.resolve(String(resolvedSessionParentPath).trim());
27150
+ return path13.resolve(String(resolvedSessionParentPath).trim());
26973
27151
  }
26974
27152
  return getBridgeRoot();
26975
27153
  }
@@ -27710,16 +27888,16 @@ import { existsSync as existsSync2, statSync } from "node:fs";
27710
27888
 
27711
27889
  // src/git/get-git-repo-root-sync.ts
27712
27890
  import { execFileSync as execFileSync2 } from "node:child_process";
27713
- import * as path13 from "node:path";
27891
+ import * as path14 from "node:path";
27714
27892
  function getGitRepoRootSync(startDir) {
27715
27893
  try {
27716
27894
  const out = execFileSync2("git", ["rev-parse", "--show-toplevel"], {
27717
- cwd: path13.resolve(startDir),
27895
+ cwd: path14.resolve(startDir),
27718
27896
  encoding: "utf8",
27719
27897
  stdio: ["ignore", "pipe", "ignore"],
27720
27898
  maxBuffer: 1024 * 1024
27721
27899
  }).trim();
27722
- return out ? path13.resolve(out) : null;
27900
+ return out ? path14.resolve(out) : null;
27723
27901
  } catch {
27724
27902
  return null;
27725
27903
  }
@@ -27728,25 +27906,25 @@ function getGitRepoRootSync(startDir) {
27728
27906
  // src/agents/acp/workspace-files.ts
27729
27907
  import { execFileSync as execFileSync3 } from "node:child_process";
27730
27908
  import { readFileSync as readFileSync3 } from "node:fs";
27731
- import * as path14 from "node:path";
27909
+ import * as path15 from "node:path";
27732
27910
  function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
27733
27911
  const trimmed2 = rawPath.trim();
27734
27912
  if (!trimmed2) return null;
27735
- const normalizedSessionParent = path14.resolve(sessionParentPath);
27913
+ const normalizedSessionParent = path15.resolve(sessionParentPath);
27736
27914
  let resolvedPath = resolveSafePathUnderCwd(sessionParentPath, trimmed2);
27737
27915
  if (!resolvedPath) {
27738
- const candidate = path14.isAbsolute(trimmed2) ? path14.normalize(trimmed2) : path14.normalize(path14.resolve(normalizedSessionParent, trimmed2));
27916
+ const candidate = path15.isAbsolute(trimmed2) ? path15.normalize(trimmed2) : path15.normalize(path15.resolve(normalizedSessionParent, trimmed2));
27739
27917
  const gitRoot2 = getGitRepoRootSync(sessionParentPath);
27740
27918
  if (!gitRoot2) return null;
27741
- const rel = path14.relative(gitRoot2, candidate);
27742
- if (rel.startsWith("..") || path14.isAbsolute(rel)) return null;
27919
+ const rel = path15.relative(gitRoot2, candidate);
27920
+ if (rel.startsWith("..") || path15.isAbsolute(rel)) return null;
27743
27921
  resolvedPath = candidate;
27744
27922
  }
27745
27923
  const gitRoot = getGitRepoRootSync(sessionParentPath);
27746
27924
  if (gitRoot) {
27747
- const relFromRoot = path14.relative(gitRoot, resolvedPath);
27748
- if (!relFromRoot.startsWith("..") && !path14.isAbsolute(relFromRoot)) {
27749
- return { resolvedPath, display: relFromRoot.split(path14.sep).join("/") };
27925
+ const relFromRoot = path15.relative(gitRoot, resolvedPath);
27926
+ if (!relFromRoot.startsWith("..") && !path15.isAbsolute(relFromRoot)) {
27927
+ return { resolvedPath, display: relFromRoot.split(path15.sep).join("/") };
27750
27928
  }
27751
27929
  }
27752
27930
  return { resolvedPath, display: toDisplayPathRelativeToCwd(sessionParentPath, resolvedPath) };
@@ -27755,9 +27933,9 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
27755
27933
  if (!displayPath || displayPath.includes("..")) return "";
27756
27934
  const gitRoot = getGitRepoRootSync(sessionParentPath);
27757
27935
  if (gitRoot) {
27758
- const resolvedPath2 = path14.resolve(gitRoot, displayPath);
27759
- const rel = path14.relative(gitRoot, resolvedPath2);
27760
- if (!rel.startsWith("..") && !path14.isAbsolute(rel)) {
27936
+ const resolvedPath2 = path15.resolve(gitRoot, displayPath);
27937
+ const rel = path15.relative(gitRoot, resolvedPath2);
27938
+ if (!rel.startsWith("..") && !path15.isAbsolute(rel)) {
27761
27939
  try {
27762
27940
  return readFileSync3(resolvedPath2, "utf8");
27763
27941
  } catch {
@@ -27776,9 +27954,9 @@ function tryWorkspaceDisplayToPath(sessionParentPath, displayPath) {
27776
27954
  if (!displayPath || displayPath.includes("..")) return null;
27777
27955
  const gitRoot = getGitRepoRootSync(sessionParentPath);
27778
27956
  if (gitRoot) {
27779
- const resolvedPath = path14.resolve(gitRoot, displayPath);
27780
- const rel = path14.relative(gitRoot, resolvedPath);
27781
- if (!rel.startsWith("..") && !path14.isAbsolute(rel)) return resolvedPath;
27957
+ const resolvedPath = path15.resolve(gitRoot, displayPath);
27958
+ const rel = path15.relative(gitRoot, resolvedPath);
27959
+ if (!rel.startsWith("..") && !path15.isAbsolute(rel)) return resolvedPath;
27782
27960
  }
27783
27961
  return resolveSafePathUnderCwd(sessionParentPath, displayPath);
27784
27962
  }
@@ -27829,92 +28007,22 @@ function getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath) {
27829
28007
  return { isDirectory: false, directoryRemoved: false };
27830
28008
  }
27831
28009
 
27832
- // src/sqlite/code-nav-cache/code-nav-cache-paths.ts
27833
- import fs14 from "node:fs";
27834
- import path15 from "node:path";
27835
- import os7 from "node:os";
27836
- function getCodeNavCacheSqlitePath() {
27837
- const override = process.env.BUILDAMATON_CODE_NAV_CACHE_SQLITE_PATH?.trim();
27838
- if (override) return path15.resolve(override);
27839
- return path15.join(os7.homedir(), ".buildautomaton", "code-nav-cache.sqlite");
27840
- }
27841
- function ensureCodeNavCacheSqliteParentDir(sqlitePath) {
27842
- const dir = path15.dirname(sqlitePath);
27843
- if (!fs14.existsSync(dir)) fs14.mkdirSync(dir, { recursive: true });
27844
- }
27845
-
27846
- // src/sqlite/code-nav-cache/migrate-code-nav-cache-sqlite.ts
27847
- var CHECKPOINT_V12 = "001_code_nav_cache_checkpoint_v1";
27848
- var CHECKPOINT_V1_SQL2 = readCodeNavCacheMigrationSql("001_code_nav_cache_checkpoint_v1.sql");
27849
- var MIGRATION_002 = "002_content_hash_symbol_index";
27850
- var MIGRATION_002_SQL = readCodeNavCacheMigrationSql("002_content_hash_symbol_index.sql");
27851
- var MIGRATION_003 = "003_content_hash_tag_rows";
27852
- var MIGRATION_003_SQL = readCodeNavCacheMigrationSql("003_content_hash_tag_rows.sql");
27853
- var CODE_NAV_CACHE_SQLITE_MIGRATIONS = [
27854
- {
27855
- name: CHECKPOINT_V12,
27856
- checkpoint: true,
27857
- migrate: (db) => {
27858
- db.exec(CHECKPOINT_V1_SQL2);
27859
- },
27860
- alreadyApplied: (db) => {
27861
- const row = db.get(
27862
- `SELECT 1 as ok FROM sqlite_master WHERE type='table' AND name='file_index_parent_path' LIMIT 1`
27863
- );
27864
- return row != null;
27865
- }
27866
- },
27867
- {
27868
- name: MIGRATION_002,
27869
- migrate: (db) => {
27870
- db.exec(MIGRATION_002_SQL);
27871
- },
27872
- alreadyApplied: (db) => {
27873
- const row = db.get(
27874
- `SELECT 1 as ok FROM sqlite_master WHERE type='table' AND name='symbol_file_blob' LIMIT 1`
27875
- );
27876
- return row != null;
27877
- }
27878
- },
27879
- {
27880
- name: MIGRATION_003,
27881
- migrate: (db) => {
27882
- db.exec(MIGRATION_003_SQL);
27883
- },
27884
- alreadyApplied: (db) => {
27885
- const row = db.get(
27886
- `SELECT 1 as ok FROM sqlite_master WHERE type='table' AND name='symbol_index_tag' LIMIT 1`
27887
- );
27888
- if (row == null) return false;
27889
- const blob = db.get(
27890
- `SELECT 1 as ok FROM sqlite_master WHERE type='table' AND name='symbol_file_blob' LIMIT 1`
27891
- );
27892
- return blob == null;
28010
+ // src/sqlite/code-nav-cache/code-nav-cache-sqlite-transaction.ts
28011
+ function runCodeNavCacheWriteTransaction(db, fn) {
28012
+ db.run("BEGIN IMMEDIATE");
28013
+ try {
28014
+ const result = fn();
28015
+ db.run("COMMIT");
28016
+ return result;
28017
+ } catch (e) {
28018
+ try {
28019
+ db.run("ROLLBACK");
28020
+ } catch {
27893
28021
  }
28022
+ throw e;
27894
28023
  }
27895
- ];
27896
- function migrateCodeNavCacheSqlite(db) {
27897
- runSqliteMigrations(
27898
- db,
27899
- CODE_NAV_CACHE_SQLITE_MIGRATIONS,
27900
- readCodeNavCacheMigrationSql("000_bootstrap_migrations_table.sql"),
27901
- "code-nav-cache"
27902
- );
27903
28024
  }
27904
28025
 
27905
- // src/sqlite/code-nav-cache/code-nav-cache-database.ts
27906
- var codeNavCacheSqlite = createSqliteDatabaseAccess({
27907
- getPath: getCodeNavCacheSqlitePath,
27908
- ensureParentDir: ensureCodeNavCacheSqliteParentDir,
27909
- migrate: migrateCodeNavCacheSqlite
27910
- });
27911
- var safeCloseCodeNavCacheSqliteDatabase = codeNavCacheSqlite.safeClose;
27912
- var closeAllCodeNavCacheSqliteConnections = codeNavCacheSqlite.closeAllConnections;
27913
- var openCodeNavCacheSqliteConnection = codeNavCacheSqlite.openConnection;
27914
- var withCodeNavCacheSqliteSync = codeNavCacheSqlite.withSync;
27915
- var withCodeNavCacheSqlite = codeNavCacheSqlite.withAsync;
27916
- var ensureCodeNavCacheSqliteInitialized = codeNavCacheSqlite.ensureInitialized;
27917
-
27918
28026
  // src/code-nav/yield-during-work.ts
27919
28027
  var CODE_NAV_YIELD_EVERY = INDEX_WORK_YIELD_EVERY;
27920
28028
  function createCodeNavYieldState() {
@@ -27929,11 +28037,11 @@ async function yieldDuringCodeNavWork(state) {
27929
28037
  }
27930
28038
 
27931
28039
  // src/code-nav/walk-code-nav-files.ts
27932
- import fs17 from "node:fs";
28040
+ import fs18 from "node:fs";
27933
28041
  import path19 from "node:path";
27934
28042
 
27935
28043
  // src/files/index/walk-workspace-tree.ts
27936
- import fs15 from "node:fs";
28044
+ import fs16 from "node:fs";
27937
28045
  import path16 from "node:path";
27938
28046
  var DEPENDENCY_INSTALL_DIR_NAMES = /* @__PURE__ */ new Set([
27939
28047
  "node_modules",
@@ -27951,7 +28059,7 @@ function shouldSkipWorkspaceWalkEntry(name) {
27951
28059
  async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
27952
28060
  let names;
27953
28061
  try {
27954
- names = await fs15.promises.readdir(dir);
28062
+ names = await fs16.promises.readdir(dir);
27955
28063
  } catch {
27956
28064
  return;
27957
28065
  }
@@ -27966,7 +28074,7 @@ async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
27966
28074
  const full = path16.join(dir, name);
27967
28075
  let stat2;
27968
28076
  try {
27969
- stat2 = await fs15.promises.stat(full);
28077
+ stat2 = await fs16.promises.stat(full);
27970
28078
  } catch {
27971
28079
  continue;
27972
28080
  }
@@ -27984,7 +28092,7 @@ function createWalkYieldState() {
27984
28092
 
27985
28093
  // src/code-nav/gitignore-filter.ts
27986
28094
  var import_ignore = __toESM(require_ignore(), 1);
27987
- import fs16 from "node:fs";
28095
+ import fs17 from "node:fs";
27988
28096
  import path17 from "node:path";
27989
28097
  var DEFAULT_IGNORED = [".git", ".git/**"];
27990
28098
  function normalizeRelPath(relPath) {
@@ -27995,7 +28103,7 @@ var GitignoreFilter = class {
27995
28103
  /** Load `.gitignore` in `absDir` and push a layer when the file exists. */
27996
28104
  async enterDirectory(absDir, dirRel) {
27997
28105
  try {
27998
- const content = await fs16.promises.readFile(path17.join(absDir, ".gitignore"), "utf8");
28106
+ const content = await fs17.promises.readFile(path17.join(absDir, ".gitignore"), "utf8");
27999
28107
  this.layers.push({ dirRel, ig: (0, import_ignore.default)().add(content) });
28000
28108
  } catch {
28001
28109
  }
@@ -28098,7 +28206,7 @@ async function walkCodeNavFilesInDirectory(dir, baseDir, relDir, filter, onFile,
28098
28206
  await filter.enterDirectory(dir, relDir);
28099
28207
  let names;
28100
28208
  try {
28101
- names = await fs17.promises.readdir(dir);
28209
+ names = await fs18.promises.readdir(dir);
28102
28210
  } catch {
28103
28211
  filter.leaveDirectory(relDir);
28104
28212
  return;
@@ -28115,7 +28223,7 @@ async function walkCodeNavFilesInDirectory(dir, baseDir, relDir, filter, onFile,
28115
28223
  const full = path19.join(dir, name);
28116
28224
  let stat2;
28117
28225
  try {
28118
- stat2 = await fs17.promises.stat(full);
28226
+ stat2 = await fs18.promises.stat(full);
28119
28227
  } catch {
28120
28228
  continue;
28121
28229
  }
@@ -28322,12 +28430,27 @@ function removeParentFileMapEntry(db, parentId, filePath) {
28322
28430
  db.run("DELETE FROM symbol_parent_file_map WHERE parent_id = ? AND file_path = ?", [parentId, filePath]);
28323
28431
  return previous === void 0 ? null : previous;
28324
28432
  }
28325
- function clearParentFileMap(db, parentId) {
28326
- const rows = db.all("SELECT content_hash FROM symbol_parent_file_map WHERE parent_id = ? AND content_hash IS NOT NULL", [
28327
- parentId
28328
- ]);
28329
- db.run("DELETE FROM symbol_parent_file_map WHERE parent_id = ?", [parentId]);
28330
- return rows.map((row) => row.content_hash);
28433
+ function clearParentFileMapBatch(db, parentId, limit) {
28434
+ const rows = db.all(
28435
+ `SELECT file_path, content_hash
28436
+ FROM symbol_parent_file_map
28437
+ WHERE parent_id = ?
28438
+ LIMIT ?`,
28439
+ [parentId, limit]
28440
+ );
28441
+ if (rows.length === 0) return { released: [], remaining: false };
28442
+ const del = db.prepare("DELETE FROM symbol_parent_file_map WHERE parent_id = ? AND file_path = ?");
28443
+ try {
28444
+ for (const row of rows) {
28445
+ del.run([parentId, row.file_path]);
28446
+ }
28447
+ } finally {
28448
+ del.finalize();
28449
+ }
28450
+ return {
28451
+ released: rows.flatMap((row) => row.content_hash == null ? [] : [row.content_hash]),
28452
+ remaining: rows.length >= limit
28453
+ };
28331
28454
  }
28332
28455
 
28333
28456
  // src/code-nav/symbol-index/storage/symbol-content-index.ts
@@ -28416,139 +28539,15 @@ function removeSymbolIndexFileData(db, ctx, filePath) {
28416
28539
  const released = removeParentFileMapEntry(db, ctx.parentId, filePath);
28417
28540
  gcReleasedHashes(db, [released]);
28418
28541
  }
28419
- function clearSymbolIndexParentData(db, ctx) {
28420
- const released = clearParentFileMap(db, ctx.parentId);
28542
+ function clearSymbolIndexParentDataBatch(db, ctx, limit) {
28543
+ const { released, remaining } = clearParentFileMapBatch(db, ctx.parentId, limit);
28421
28544
  gcReleasedHashes(db, released);
28422
- }
28423
-
28424
- // src/code-nav/symbol-index/query/tag-query-shared.ts
28425
- var TAG_SELECT = `file_path, name, role, kind, start_line, start_column, end_line, end_column,
28426
- scope_start_line, scope_start_column, parent_scope_start_line, parent_scope_start_column, nav_target_path, scope_chain`;
28427
- function rowToLocation(row) {
28428
- return {
28429
- path: row.file_path,
28430
- line: row.start_line + 1,
28431
- column: row.start_column,
28432
- kind: row.kind,
28433
- role: row.role === "def" ? "definition" : "reference"
28434
- };
28435
- }
28436
- function modulePathLocation(row) {
28437
- return {
28438
- path: row.nav_target_path,
28439
- line: 1,
28440
- column: 0,
28441
- kind: "module",
28442
- role: "reference"
28443
- };
28444
- }
28445
- function emptyRefRow(filePath) {
28446
- return {
28447
- file_path: filePath,
28448
- name: "",
28449
- role: "ref",
28450
- kind: "",
28451
- start_line: 0,
28452
- start_column: 0,
28453
- end_line: 0,
28454
- end_column: 0,
28455
- scope_start_line: null,
28456
- scope_start_column: null,
28457
- parent_scope_start_line: null,
28458
- parent_scope_start_column: null,
28459
- nav_target_path: null,
28460
- scope_chain: null
28461
- };
28462
- }
28463
-
28464
- // src/code-nav/symbol-index/storage/file-content-load.ts
28465
- function loadFileTags(db, ctx, filePath) {
28466
- const contentHash = getEffectiveContentHash(db, ctx, filePath);
28467
- if (contentHash == null) return [];
28468
- return db.all(
28469
- `SELECT ${TAG_SELECT}
28470
- FROM symbol_index_tag
28471
- WHERE content_hash = ? AND file_path = ?
28472
- ORDER BY start_line, start_column`,
28473
- [contentHash, filePath]
28474
- );
28475
- }
28476
- function loadFileImports(db, ctx, filePath) {
28477
- const contentHash = getEffectiveContentHash(db, ctx, filePath);
28478
- if (contentHash == null) return [];
28479
- return db.all(
28480
- `SELECT file_path, local_name, source_name, module_specifier, source_file_path, import_kind, start_line, start_column
28481
- FROM symbol_index_import
28482
- WHERE content_hash = ? AND file_path = ?
28483
- ORDER BY start_line, start_column`,
28484
- [contentHash, filePath]
28485
- );
28486
- }
28487
- function findTagsByName(db, ctx, name) {
28488
- const filePaths = listEffectiveIndexedFilePaths(db, ctx);
28489
- const rows = [];
28490
- for (const filePath of filePaths) {
28491
- const contentHash = getEffectiveContentHash(db, ctx, filePath);
28492
- if (contentHash == null) continue;
28493
- const matches = db.all(
28494
- `SELECT ${TAG_SELECT}
28495
- FROM symbol_index_tag
28496
- WHERE content_hash = ? AND file_path = ? AND name = ?
28497
- ORDER BY start_line, start_column`,
28498
- [contentHash, filePath, name]
28499
- );
28500
- rows.push(...matches);
28501
- }
28502
- rows.sort(
28503
- (a, b) => a.file_path.localeCompare(b.file_path) || a.start_line - b.start_line || a.start_column - b.start_column
28504
- );
28505
- return rows;
28506
- }
28507
-
28508
- // src/code-nav/symbol-index/lifecycle/symbol-index-file-ready.ts
28509
- function symbolIndexFileIsReady(parentPath, filePath) {
28510
- const normalizedParent = normalizeResolvedPath(parentPath);
28511
- const normalizedFile = filePath.replace(/\\/g, "/").replace(/^\/+/, "");
28512
- if (!normalizedFile) return false;
28513
- return withCodeNavCacheSqliteSync((db) => {
28514
- const ctx = getSymbolIndexParentContext(db, normalizedParent);
28515
- if (ctx == null) return false;
28516
- const versionRow = db.get("SELECT index_version FROM symbol_index_parent_path WHERE id = ?", [
28517
- ctx.parentId
28518
- ]);
28519
- if (versionRow == null || versionRow.index_version < SYMBOL_INDEX_VERSION) return false;
28520
- return getEffectiveContentHash(db, ctx, normalizedFile) != null;
28521
- });
28545
+ return remaining;
28522
28546
  }
28523
28547
 
28524
28548
  // src/code-nav/symbol-index/sqlite/symbol-index-sqlite-lock.ts
28525
- import fs18 from "node:fs";
28526
- function isSqliteCorruptError(e) {
28527
- const msg = e instanceof Error ? e.message : String(e);
28528
- return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
28529
- }
28530
- var chain = Promise.resolve();
28531
28549
  function withSymbolIndexSqliteLock(fn) {
28532
- const run = async () => {
28533
- try {
28534
- return await Promise.resolve(fn());
28535
- } catch (e) {
28536
- if (!isSqliteCorruptError(e)) throw e;
28537
- closeAllCodeNavCacheSqliteConnections();
28538
- try {
28539
- fs18.unlinkSync(getCodeNavCacheSqlitePath());
28540
- } catch {
28541
- }
28542
- chain = Promise.resolve();
28543
- return await Promise.resolve(fn());
28544
- }
28545
- };
28546
- const next = chain.then(run);
28547
- chain = next.then(
28548
- () => void 0,
28549
- () => void 0
28550
- );
28551
- return next;
28550
+ return withCodeNavCacheSqliteWorkLock(fn);
28552
28551
  }
28553
28552
 
28554
28553
  // src/code-nav/symbol-index/imports/star-reexport-names.ts
@@ -28653,43 +28652,111 @@ function expandStarReexportBindings(collected) {
28653
28652
  }
28654
28653
 
28655
28654
  // src/code-nav/symbol-index/persistence/persist-single-file.ts
28656
- function persistSymbolIndexFile(resolved, relPath, source, tags, imports) {
28657
- withCodeNavCacheSqliteSync((db) => {
28658
- db.run("BEGIN IMMEDIATE");
28659
- try {
28655
+ async function persistSymbolIndexFileAsync(resolved, relPath, source, tags, imports) {
28656
+ await withCodeNavCacheSqlite(async (db) => {
28657
+ runCodeNavCacheWriteTransaction(db, () => {
28660
28658
  upsertSymbolIndexParentPath(db, resolved);
28661
28659
  const ctx = getSymbolIndexParentContext(db, resolved);
28662
28660
  if (ctx == null) throw new Error(`Failed to resolve symbol index parent: ${resolved}`);
28663
28661
  persistSymbolIndexFileData(db, ctx, relPath, source, tags, imports);
28664
- db.run("COMMIT");
28665
- } catch (e) {
28666
- try {
28667
- db.run("ROLLBACK");
28668
- } catch {
28669
- }
28670
- throw e;
28671
- }
28662
+ });
28672
28663
  });
28673
28664
  }
28674
- function removeSymbolIndexFile(resolved, relPath) {
28675
- withCodeNavCacheSqliteSync((db) => {
28676
- db.run("BEGIN IMMEDIATE");
28677
- try {
28665
+ async function removeSymbolIndexFileAsync(resolved, relPath) {
28666
+ await withCodeNavCacheSqlite(async (db) => {
28667
+ runCodeNavCacheWriteTransaction(db, () => {
28678
28668
  upsertSymbolIndexParentPath(db, resolved);
28679
28669
  const ctx = getSymbolIndexParentContext(db, resolved);
28680
28670
  if (ctx == null) throw new Error(`Failed to resolve symbol index parent: ${resolved}`);
28681
28671
  removeSymbolIndexFileData(db, ctx, relPath);
28682
- db.run("COMMIT");
28683
- } catch (e) {
28684
- try {
28685
- db.run("ROLLBACK");
28686
- } catch {
28687
- }
28688
- throw e;
28689
- }
28672
+ });
28690
28673
  });
28691
28674
  }
28692
28675
 
28676
+ // src/code-nav/symbol-index/query/tag-query-shared.ts
28677
+ var TAG_SELECT = `file_path, name, role, kind, start_line, start_column, end_line, end_column,
28678
+ scope_start_line, scope_start_column, parent_scope_start_line, parent_scope_start_column, nav_target_path, scope_chain`;
28679
+ function rowToLocation(row) {
28680
+ return {
28681
+ path: row.file_path,
28682
+ line: row.start_line + 1,
28683
+ column: row.start_column,
28684
+ kind: row.kind,
28685
+ role: row.role === "def" ? "definition" : "reference"
28686
+ };
28687
+ }
28688
+ function modulePathLocation(row) {
28689
+ return {
28690
+ path: row.nav_target_path,
28691
+ line: 1,
28692
+ column: 0,
28693
+ kind: "module",
28694
+ role: "reference"
28695
+ };
28696
+ }
28697
+ function emptyRefRow(filePath) {
28698
+ return {
28699
+ file_path: filePath,
28700
+ name: "",
28701
+ role: "ref",
28702
+ kind: "",
28703
+ start_line: 0,
28704
+ start_column: 0,
28705
+ end_line: 0,
28706
+ end_column: 0,
28707
+ scope_start_line: null,
28708
+ scope_start_column: null,
28709
+ parent_scope_start_line: null,
28710
+ parent_scope_start_column: null,
28711
+ nav_target_path: null,
28712
+ scope_chain: null
28713
+ };
28714
+ }
28715
+
28716
+ // src/code-nav/symbol-index/storage/file-content-load.ts
28717
+ function loadFileTags(db, ctx, filePath) {
28718
+ const contentHash = getEffectiveContentHash(db, ctx, filePath);
28719
+ if (contentHash == null) return [];
28720
+ return db.all(
28721
+ `SELECT ${TAG_SELECT}
28722
+ FROM symbol_index_tag
28723
+ WHERE content_hash = ? AND file_path = ?
28724
+ ORDER BY start_line, start_column`,
28725
+ [contentHash, filePath]
28726
+ );
28727
+ }
28728
+ function loadFileImports(db, ctx, filePath) {
28729
+ const contentHash = getEffectiveContentHash(db, ctx, filePath);
28730
+ if (contentHash == null) return [];
28731
+ return db.all(
28732
+ `SELECT file_path, local_name, source_name, module_specifier, source_file_path, import_kind, start_line, start_column
28733
+ FROM symbol_index_import
28734
+ WHERE content_hash = ? AND file_path = ?
28735
+ ORDER BY start_line, start_column`,
28736
+ [contentHash, filePath]
28737
+ );
28738
+ }
28739
+ function findTagsByName(db, ctx, name) {
28740
+ const filePaths = listEffectiveIndexedFilePaths(db, ctx);
28741
+ const rows = [];
28742
+ for (const filePath of filePaths) {
28743
+ const contentHash = getEffectiveContentHash(db, ctx, filePath);
28744
+ if (contentHash == null) continue;
28745
+ const matches = db.all(
28746
+ `SELECT ${TAG_SELECT}
28747
+ FROM symbol_index_tag
28748
+ WHERE content_hash = ? AND file_path = ? AND name = ?
28749
+ ORDER BY start_line, start_column`,
28750
+ [contentHash, filePath, name]
28751
+ );
28752
+ rows.push(...matches);
28753
+ }
28754
+ rows.sort(
28755
+ (a, b) => a.file_path.localeCompare(b.file_path) || a.start_line - b.start_line || a.start_column - b.start_column
28756
+ );
28757
+ return rows;
28758
+ }
28759
+
28693
28760
  // src/code-nav/symbol-index/build/load-indexed-file-entry.ts
28694
28761
  function dbTagToSymbolTag(row) {
28695
28762
  return {
@@ -28735,21 +28802,52 @@ function loadIndexedFileEntry(db, ctx, relPath) {
28735
28802
  function normalizeRelPath2(filePath) {
28736
28803
  return filePath.replace(/\\/g, "/").replace(/^\/+/, "");
28737
28804
  }
28738
- function listDirectImportTargetsForFile(parentPath, filePath) {
28805
+ function listDirectImportTargetsWithDb(db, resolved, relPath) {
28806
+ const ctx = getSymbolIndexParentContext(db, resolved);
28807
+ if (ctx == null) return [];
28808
+ const entry = loadIndexedFileEntry(db, ctx, relPath);
28809
+ if (entry == null) return [];
28810
+ const paths = /* @__PURE__ */ new Set();
28811
+ for (const binding of entry.imports) {
28812
+ if (binding.sourceFilePath) paths.add(binding.sourceFilePath);
28813
+ }
28814
+ return Array.from(paths);
28815
+ }
28816
+ async function listDirectImportTargetsForFileAsync(parentPath, filePath) {
28739
28817
  const resolved = normalizeResolvedPath(parentPath);
28740
28818
  const relPath = normalizeRelPath2(filePath);
28741
28819
  if (!relPath) return [];
28742
- return withCodeNavCacheSqliteSync((db) => {
28743
- const ctx = getSymbolIndexParentContext(db, resolved);
28820
+ return withCodeNavCacheSqlite((db) => listDirectImportTargetsWithDb(db, resolved, relPath));
28821
+ }
28822
+
28823
+ // src/code-nav/symbol-index/lifecycle/symbol-index-file-ready.ts
28824
+ function symbolIndexFileIsReadyWithDb(db, parentPath, filePath) {
28825
+ const normalizedParent = normalizeResolvedPath(parentPath);
28826
+ const normalizedFile = filePath.replace(/\\/g, "/").replace(/^\/+/, "");
28827
+ if (!normalizedFile) return false;
28828
+ const ctx = getSymbolIndexParentContext(db, normalizedParent);
28829
+ if (ctx == null) return false;
28830
+ const versionRow = db.get("SELECT index_version FROM symbol_index_parent_path WHERE id = ?", [
28831
+ ctx.parentId
28832
+ ]);
28833
+ if (versionRow == null || versionRow.index_version < SYMBOL_INDEX_VERSION) return false;
28834
+ return getEffectiveContentHash(db, ctx, normalizedFile) != null;
28835
+ }
28836
+ async function symbolIndexFileIsReadyAsync(parentPath, filePath) {
28837
+ return withCodeNavCacheSqlite((db) => symbolIndexFileIsReadyWithDb(db, parentPath, filePath));
28838
+ }
28839
+ async function loadSymbolIndexReadyFileSet(parentPath) {
28840
+ const normalizedParent = normalizeResolvedPath(parentPath);
28841
+ const paths = await withCodeNavCacheSqlite((db) => {
28842
+ const ctx = getSymbolIndexParentContext(db, normalizedParent);
28744
28843
  if (ctx == null) return [];
28745
- const entry = loadIndexedFileEntry(db, ctx, relPath);
28746
- if (entry == null) return [];
28747
- const paths = /* @__PURE__ */ new Set();
28748
- for (const binding of entry.imports) {
28749
- if (binding.sourceFilePath) paths.add(binding.sourceFilePath);
28750
- }
28751
- return [...paths];
28844
+ const versionRow = db.get("SELECT index_version FROM symbol_index_parent_path WHERE id = ?", [
28845
+ ctx.parentId
28846
+ ]);
28847
+ if (versionRow == null || versionRow.index_version < SYMBOL_INDEX_VERSION) return [];
28848
+ return listEffectiveIndexedFilePaths(db, ctx);
28752
28849
  });
28850
+ return new Set(paths);
28753
28851
  }
28754
28852
 
28755
28853
  // src/code-nav/symbol-index/build/extract-file-symbol-data.ts
@@ -29059,9 +29157,9 @@ async function augmentTypeReferenceTags(tags, nameNodes, root) {
29059
29157
  }
29060
29158
 
29061
29159
  // src/code-nav/scope-chain.ts
29062
- function serializeScopeChain(chain3) {
29063
- if (chain3.length === 0) return null;
29064
- return chain3.map((anchor) => `${anchor.startLine}:${anchor.startColumn}`).join(",");
29160
+ function serializeScopeChain(chain2) {
29161
+ if (chain2.length === 0) return null;
29162
+ return chain2.map((anchor) => `${anchor.startLine}:${anchor.startColumn}`).join(",");
29065
29163
  }
29066
29164
  function parseScopeChain(raw) {
29067
29165
  if (!raw) return [];
@@ -29077,9 +29175,9 @@ function parseScopeChain(raw) {
29077
29175
  }
29078
29176
  return out;
29079
29177
  }
29080
- function anchorInScopeChain(line, column, chain3) {
29081
- if (line == null || column == null) return chain3.length === 0;
29082
- return chain3.some((anchor) => anchor.startLine === line && anchor.startColumn === column);
29178
+ function anchorInScopeChain(line, column, chain2) {
29179
+ if (line == null || column == null) return chain2.length === 0;
29180
+ return chain2.some((anchor) => anchor.startLine === line && anchor.startColumn === column);
29083
29181
  }
29084
29182
 
29085
29183
  // src/code-nav/enrich-tag-scope.ts
@@ -29116,15 +29214,15 @@ function scopeAnchorFromNode(node) {
29116
29214
  };
29117
29215
  }
29118
29216
  function findEnclosingScopeChain(nameNode) {
29119
- const chain3 = [];
29217
+ const chain2 = [];
29120
29218
  let current = nameNode.parent;
29121
29219
  while (current) {
29122
29220
  if (SCOPE_CONTAINER_TYPES.has(current.type)) {
29123
- chain3.push(scopeAnchorFromNode(current));
29221
+ chain2.push(scopeAnchorFromNode(current));
29124
29222
  }
29125
29223
  current = current.parent;
29126
29224
  }
29127
- return chain3;
29225
+ return chain2;
29128
29226
  }
29129
29227
  function findEnclosingScopes(nameNode) {
29130
29228
  const scopeChain = findEnclosingScopeChain(nameNode);
@@ -29981,7 +30079,7 @@ async function extractFileSymbolData(resolved, relPath, workspaceFilesOverride)
29981
30079
  }
29982
30080
  }
29983
30081
  await yieldToEventLoop();
29984
- const workspaceFiles = workspaceFilesOverride ?? withCodeNavCacheSqliteSync((db) => listWorkspaceFiles(db, resolved, relPath));
30082
+ const workspaceFiles = workspaceFilesOverride ?? await withCodeNavCacheSqlite((db) => listWorkspaceFiles(db, resolved, relPath));
29985
30083
  const imports = source != null ? await extractImportBindingsFromSource(relPath, source, workspaceFiles) : [];
29986
30084
  const yieldState = createCodeNavYieldState();
29987
30085
  return {
@@ -30006,7 +30104,7 @@ async function indexOneSymbolFileForBuild(resolved, relPath, workspaceFiles) {
30006
30104
  };
30007
30105
  if (data.imports.some((binding) => binding.importKind === "star")) {
30008
30106
  await yieldToEventLoop();
30009
- entry = withCodeNavCacheSqliteSync((db) => {
30107
+ entry = await withCodeNavCacheSqlite((db) => {
30010
30108
  const ctx = getSymbolIndexParentContext(db, resolved);
30011
30109
  if (ctx == null) return entry;
30012
30110
  const resolveEntry = (filePath) => loadIndexedFileEntry(db, ctx, filePath);
@@ -30016,7 +30114,7 @@ async function indexOneSymbolFileForBuild(resolved, relPath, workspaceFiles) {
30016
30114
  }
30017
30115
  await withSymbolIndexSqliteLock(async () => {
30018
30116
  await yieldToEventLoop();
30019
- persistSymbolIndexFile(resolved, relPath, entry.source, entry.tags, entry.imports);
30117
+ await persistSymbolIndexFileAsync(resolved, relPath, entry.source, entry.tags, entry.imports);
30020
30118
  });
30021
30119
  }
30022
30120
  async function ensureSymbolIndexFileAsync(parentPath, filePath, opts) {
@@ -30024,41 +30122,51 @@ async function ensureSymbolIndexFileAsync(parentPath, filePath, opts) {
30024
30122
  const relPath = normalizeRelPath3(filePath);
30025
30123
  if (!relPath) return false;
30026
30124
  const importDepth = opts?.importDepth ?? 0;
30027
- withCodeNavCacheSqliteSync((db) => {
30125
+ await withCodeNavCacheSqlite((db) => {
30028
30126
  upsertSymbolIndexParentPath(db, resolved);
30029
30127
  });
30030
- if (!symbolIndexFileIsReady(resolved, relPath)) {
30128
+ if (!await symbolIndexFileIsReadyAsync(resolved, relPath)) {
30031
30129
  await indexOneSymbolFileForBuild(resolved, relPath, void 0);
30032
30130
  }
30033
- if (importDepth > 0 && symbolIndexFileIsReady(resolved, relPath)) {
30034
- const targets = listDirectImportTargetsForFile(resolved, relPath).slice(0, MAX_IMPORT_PREFETCH_COUNT);
30131
+ if (importDepth > 0 && await symbolIndexFileIsReadyAsync(resolved, relPath)) {
30132
+ const targets = (await listDirectImportTargetsForFileAsync(resolved, relPath)).slice(
30133
+ 0,
30134
+ MAX_IMPORT_PREFETCH_COUNT
30135
+ );
30035
30136
  for (const target of targets) {
30036
30137
  await yieldToEventLoop();
30037
- if (!symbolIndexFileIsReady(resolved, target)) {
30138
+ if (!await symbolIndexFileIsReadyAsync(resolved, target)) {
30038
30139
  await ensureSymbolIndexFileAsync(resolved, target, { importDepth: importDepth - 1 });
30039
30140
  }
30040
30141
  }
30041
30142
  }
30042
- return symbolIndexFileIsReady(resolved, relPath);
30143
+ return await symbolIndexFileIsReadyAsync(resolved, relPath);
30043
30144
  }
30044
- function registerSymbolIndexParent(parentPath) {
30145
+ async function registerSymbolIndexParentAsync(parentPath) {
30045
30146
  const resolved = normalizeResolvedPath(parentPath);
30046
- withCodeNavCacheSqliteSync((db) => {
30147
+ await withCodeNavCacheSqlite((db) => {
30047
30148
  upsertSymbolIndexParentPath(db, resolved);
30048
30149
  });
30049
30150
  }
30050
30151
 
30051
30152
  // src/code-nav/symbol-index/build/build-symbol-index.ts
30153
+ var SYMBOL_PARENT_CLEAR_BATCH_SIZE = 256;
30052
30154
  async function buildSymbolIndexAsync(parentPath) {
30053
30155
  const resolved = normalizeResolvedPath(parentPath);
30054
30156
  await yieldToEventLoop();
30055
- await withSymbolIndexSqliteLock(() => {
30056
- withCodeNavCacheSqliteSync((db) => {
30057
- upsertSymbolIndexParentPath(db, resolved);
30058
- const ctx = getSymbolIndexParentContext(db, resolved);
30059
- if (ctx != null) clearSymbolIndexParentData(db, ctx);
30157
+ let clearRemaining = true;
30158
+ while (clearRemaining) {
30159
+ await withSymbolIndexSqliteLock(async () => {
30160
+ clearRemaining = await withCodeNavCacheSqlite(
30161
+ (db) => runCodeNavCacheWriteTransaction(db, () => {
30162
+ upsertSymbolIndexParentPath(db, resolved);
30163
+ const ctx = getSymbolIndexParentContext(db, resolved);
30164
+ return ctx == null ? false : clearSymbolIndexParentDataBatch(db, ctx, SYMBOL_PARENT_CLEAR_BATCH_SIZE);
30165
+ })
30166
+ );
30060
30167
  });
30061
- });
30168
+ if (clearRemaining) await yieldToEventLoop();
30169
+ }
30062
30170
  const workspaceFiles = /* @__PURE__ */ new Set();
30063
30171
  const walkState = createWalkYieldState();
30064
30172
  const yieldState = createCodeNavYieldState();
@@ -30075,9 +30183,7 @@ async function buildSymbolIndexAsync(parentPath) {
30075
30183
  resolved,
30076
30184
  async (relPath) => {
30077
30185
  await yieldDuringCodeNavWork(yieldState);
30078
- if (!symbolIndexFileIsReady(resolved, relPath)) {
30079
- await indexOneSymbolFileForBuild(resolved, relPath, workspaceFiles);
30080
- }
30186
+ await indexOneSymbolFileForBuild(resolved, relPath, workspaceFiles);
30081
30187
  fileCount += 1;
30082
30188
  },
30083
30189
  walkState
@@ -30086,18 +30192,79 @@ async function buildSymbolIndexAsync(parentPath) {
30086
30192
  return { fileCount, tagCount: 0 };
30087
30193
  }
30088
30194
 
30195
+ // src/code-nav/symbol-index/scheduler/task-priority-heap.ts
30196
+ function higherPriority(a, b) {
30197
+ return a.priority > b.priority;
30198
+ }
30199
+ var SymbolIndexTaskPriorityHeap = class {
30200
+ heap = [];
30201
+ clear() {
30202
+ this.heap.length = 0;
30203
+ }
30204
+ push(task) {
30205
+ this.heap.push(task);
30206
+ let i = this.heap.length - 1;
30207
+ while (i > 0) {
30208
+ const parent = Math.floor((i - 1) / 2);
30209
+ if (!higherPriority(this.heap[i], this.heap[parent])) break;
30210
+ this.swap(i, parent);
30211
+ i = parent;
30212
+ }
30213
+ }
30214
+ pop() {
30215
+ if (this.heap.length === 0) return void 0;
30216
+ const top = this.heap[0];
30217
+ const last2 = this.heap.pop();
30218
+ if (this.heap.length > 0) {
30219
+ this.heap[0] = last2;
30220
+ this.sink(0);
30221
+ }
30222
+ return top;
30223
+ }
30224
+ get size() {
30225
+ return this.heap.length;
30226
+ }
30227
+ sink(start) {
30228
+ let i = start;
30229
+ while (true) {
30230
+ const left = i * 2 + 1;
30231
+ const right = left + 1;
30232
+ let best = i;
30233
+ if (left < this.heap.length && higherPriority(this.heap[left], this.heap[best])) best = left;
30234
+ if (right < this.heap.length && higherPriority(this.heap[right], this.heap[best])) best = right;
30235
+ if (best === i) break;
30236
+ this.swap(i, best);
30237
+ i = best;
30238
+ }
30239
+ }
30240
+ swap(i, j) {
30241
+ const tmp = this.heap[i];
30242
+ this.heap[i] = this.heap[j];
30243
+ this.heap[j] = tmp;
30244
+ }
30245
+ };
30246
+
30247
+ // src/code-nav/symbol-index/scheduler/task-queue-types.ts
30248
+ function symbolIndexTaskKey(parentPath, filePath) {
30249
+ return `${parentPath}\0${filePath}`;
30250
+ }
30251
+
30089
30252
  // src/code-nav/symbol-index/scheduler/task-queue.ts
30090
30253
  var pending = /* @__PURE__ */ new Map();
30254
+ var heap = new SymbolIndexTaskPriorityHeap();
30255
+ var latestActiveSequenceByParent = /* @__PURE__ */ new Map();
30091
30256
  var workerRunning = false;
30092
- function taskKey(parentPath, filePath) {
30093
- return `${parentPath}\0${filePath}`;
30257
+ function taskMatchesCurrentPending(task) {
30258
+ const current = pending.get(symbolIndexTaskKey(task.parentPath, task.filePath));
30259
+ return current === task;
30094
30260
  }
30095
30261
  function pickNextTask() {
30096
- let best;
30097
- for (const task of pending.values()) {
30098
- if (best == null || task.priority > best.priority) best = task;
30262
+ while (heap.size > 0) {
30263
+ const task = heap.pop();
30264
+ if (task == null || !taskMatchesCurrentPending(task)) continue;
30265
+ return task;
30099
30266
  }
30100
- return best;
30267
+ return void 0;
30101
30268
  }
30102
30269
  async function runWorker() {
30103
30270
  if (workerRunning) return;
@@ -30107,74 +30274,93 @@ async function runWorker() {
30107
30274
  while (pending.size > 0) {
30108
30275
  const task = pickNextTask();
30109
30276
  if (task == null) break;
30110
- pending.delete(taskKey(task.parentPath, task.filePath));
30277
+ pending.delete(symbolIndexTaskKey(task.parentPath, task.filePath));
30111
30278
  await yieldDuringCodeNavWork(yieldState);
30112
- if (!symbolIndexFileIsReady(task.parentPath, task.filePath)) {
30279
+ const latestActiveSequence = latestActiveSequenceByParent.get(task.parentPath);
30280
+ if (latestActiveSequence != null && task.sequence != null && task.sequence < latestActiveSequence) {
30281
+ continue;
30282
+ }
30283
+ if (!await symbolIndexFileIsReadyAsync(task.parentPath, task.filePath)) {
30113
30284
  await ensureSymbolIndexFileAsync(task.parentPath, task.filePath);
30114
30285
  }
30115
30286
  await yieldToEventLoop();
30116
30287
  }
30117
30288
  } finally {
30289
+ if (pending.size === 0) heap.clear();
30118
30290
  workerRunning = false;
30119
30291
  if (pending.size > 0) void runWorker();
30120
30292
  }
30121
30293
  }
30122
- function enqueueSymbolIndexTask(parentPath, filePath, priority) {
30294
+ function enqueueSymbolIndexTask(parentPath, filePath, priority, sequence) {
30123
30295
  const normalizedParent = normalizeResolvedPath(parentPath);
30124
30296
  const normalizedFile = filePath.replace(/\\/g, "/").replace(/^\/+/, "");
30125
30297
  if (!normalizedFile) return;
30126
- if (symbolIndexFileIsReady(normalizedParent, normalizedFile)) return;
30127
- const key = taskKey(normalizedParent, normalizedFile);
30298
+ const key = symbolIndexTaskKey(normalizedParent, normalizedFile);
30128
30299
  const existing = pending.get(key);
30129
30300
  if (existing != null && existing.priority >= priority) return;
30130
- pending.set(key, { parentPath: normalizedParent, filePath: normalizedFile, priority });
30301
+ const task = { parentPath: normalizedParent, filePath: normalizedFile, priority, sequence };
30302
+ pending.set(key, task);
30303
+ heap.push(task);
30131
30304
  void runWorker();
30132
30305
  }
30306
+ function markLatestActiveSymbolIndexTask(parentPath, sequence) {
30307
+ const normalizedParent = normalizeResolvedPath(parentPath);
30308
+ const existing = latestActiveSequenceByParent.get(normalizedParent);
30309
+ if (existing != null && existing >= sequence) return;
30310
+ latestActiveSequenceByParent.set(normalizedParent, sequence);
30311
+ for (const [key, task] of pending) {
30312
+ if (task.parentPath === normalizedParent && task.sequence != null && task.sequence < sequence) {
30313
+ pending.delete(key);
30314
+ }
30315
+ }
30316
+ if (pending.size === 0) heap.clear();
30317
+ }
30133
30318
 
30134
30319
  // src/code-nav/symbol-index/scheduler/symbol-index-scheduler.ts
30135
30320
  var requestSeq = 0;
30136
30321
  var warmupSeq = 0;
30137
30322
  var warmupScheduled = /* @__PURE__ */ new Set();
30323
+ var warmupCompleted = /* @__PURE__ */ new Set();
30138
30324
  function scheduleSymbolIndexFile(parentPath, filePath) {
30139
- enqueueSymbolIndexTask(parentPath, filePath, 1e6 + ++requestSeq);
30325
+ const sequence = ++requestSeq;
30326
+ markLatestActiveSymbolIndexTask(parentPath, sequence);
30327
+ enqueueSymbolIndexTask(parentPath, filePath, 1e6 + sequence, sequence);
30140
30328
  }
30141
30329
  function scheduleSymbolIndexImportNeighbors(parentPath, filePaths) {
30142
30330
  let priority = 5e5 + requestSeq;
30143
30331
  for (const filePath of filePaths) {
30144
- enqueueSymbolIndexTask(parentPath, filePath, priority);
30332
+ enqueueSymbolIndexTask(parentPath, filePath, priority, requestSeq);
30145
30333
  priority -= 1;
30146
30334
  }
30147
30335
  }
30148
30336
  function scheduleSymbolIndexWarmup(parentPath) {
30149
30337
  const resolved = normalizeResolvedPath(parentPath);
30338
+ if (warmupCompleted.has(resolved)) return;
30150
30339
  if (warmupScheduled.has(resolved)) return;
30151
30340
  warmupScheduled.add(resolved);
30152
30341
  setImmediate(() => {
30153
30342
  void (async () => {
30154
30343
  try {
30344
+ const readyFiles = await loadSymbolIndexReadyFileSet(resolved);
30155
30345
  const walkState = createWalkYieldState();
30156
30346
  const yieldState = createCodeNavYieldState();
30157
30347
  await walkCodeNavFilesAsync(
30158
30348
  resolved,
30159
30349
  async (relPath) => {
30160
30350
  await yieldDuringCodeNavWork(yieldState);
30161
- if (!symbolIndexFileIsReady(resolved, relPath)) {
30162
- enqueueSymbolIndexTask(resolved, relPath, ++warmupSeq);
30351
+ if (!readyFiles.has(relPath)) {
30352
+ enqueueSymbolIndexTask(resolved, relPath, ++warmupSeq, requestSeq);
30163
30353
  }
30164
30354
  },
30165
30355
  walkState
30166
30356
  );
30357
+ warmupCompleted.add(resolved);
30167
30358
  } finally {
30168
30359
  warmupScheduled.delete(resolved);
30169
30360
  }
30170
30361
  })();
30171
30362
  });
30172
30363
  }
30173
- function scheduleSymbolIndexForRequest(parentPath, reqPath, importTargets) {
30174
- scheduleSymbolIndexFile(parentPath, reqPath);
30175
- scheduleSymbolIndexImportNeighbors(parentPath, importTargets);
30176
- scheduleSymbolIndexWarmup(parentPath);
30177
- }
30178
30364
 
30179
30365
  // src/code-nav/symbol-index/lifecycle/normalize-symbol-index-path.ts
30180
30366
  import path23 from "node:path";
@@ -30190,27 +30376,23 @@ function normalizeSymbolIndexRelPath(parentPath, changedPath) {
30190
30376
  async function updateSymbolIndexForFile(parentPath, changedPath) {
30191
30377
  const relPath = normalizeSymbolIndexRelPath(parentPath, changedPath);
30192
30378
  if (relPath == null) return;
30379
+ const resolved = normalizeResolvedPath(parentPath);
30380
+ const { source, tags, imports } = await extractFileSymbolData(resolved, relPath);
30381
+ await yieldToEventLoop();
30193
30382
  await withSymbolIndexSqliteLock(async () => {
30194
- const resolved = normalizeResolvedPath(parentPath);
30195
- const { source, tags, imports } = await extractFileSymbolData(resolved, relPath);
30196
- await yieldToEventLoop();
30197
- persistSymbolIndexFile(resolved, relPath, source, tags, imports);
30383
+ await persistSymbolIndexFileAsync(resolved, relPath, source, tags, imports);
30198
30384
  });
30199
30385
  }
30200
30386
  async function removeSymbolIndexForFile(parentPath, changedPath) {
30201
30387
  const relPath = normalizeSymbolIndexRelPath(parentPath, changedPath);
30202
30388
  if (relPath == null) return;
30389
+ const resolved = normalizeResolvedPath(parentPath);
30203
30390
  await withSymbolIndexSqliteLock(async () => {
30204
- removeSymbolIndexFile(normalizeResolvedPath(parentPath), relPath);
30391
+ await removeSymbolIndexFileAsync(resolved, relPath);
30205
30392
  });
30206
30393
  }
30207
30394
 
30208
30395
  // src/code-nav/symbol-index/sqlite/symbol-index-import-sqlite.ts
30209
- function listImportsForFile(db, parentId, filePath) {
30210
- const ctx = getSymbolIndexParentContextById(db, parentId);
30211
- if (ctx == null) return [];
30212
- return loadFileImports(db, ctx, filePath);
30213
- }
30214
30396
  function prefersTypeImport(refKind) {
30215
30397
  return refKind === "type";
30216
30398
  }
@@ -30236,7 +30418,7 @@ function findImportBindingForLocalName(imports, localName, ref) {
30236
30418
  function defsByFileNameKey(filePath, name) {
30237
30419
  return `${filePath}\0${name}`;
30238
30420
  }
30239
- function createNavigationLookups(db, parentId) {
30421
+ function createSnapshotNavigationLookups(db, parentId) {
30240
30422
  const ctx = getSymbolIndexParentContextById(db, parentId);
30241
30423
  if (ctx == null) {
30242
30424
  return {
@@ -30248,29 +30430,24 @@ function createNavigationLookups(db, parentId) {
30248
30430
  const fileDefsCache = /* @__PURE__ */ new Map();
30249
30431
  const defsByFileNameCache = /* @__PURE__ */ new Map();
30250
30432
  const importsCache = /* @__PURE__ */ new Map();
30251
- return {
30252
- loadFileDefs(filePath) {
30253
- let cached2 = fileDefsCache.get(filePath);
30254
- if (cached2) return cached2;
30255
- cached2 = loadFileTags(db, ctx, filePath).filter((row) => row.role === "def");
30256
- fileDefsCache.set(filePath, cached2);
30257
- return cached2;
30258
- },
30259
- lookupDefsInFileNamed(filePath, name) {
30260
- const key = defsByFileNameKey(filePath, name);
30261
- let cached2 = defsByFileNameCache.get(key);
30262
- if (cached2) return cached2;
30263
- cached2 = loadFileTags(db, ctx, filePath).filter((row) => row.role === "def" && row.name === name);
30264
- defsByFileNameCache.set(key, cached2);
30265
- return cached2;
30266
- },
30267
- lookupImportsForFile(filePath) {
30268
- let cached2 = importsCache.get(filePath);
30269
- if (cached2) return cached2;
30270
- cached2 = listImportsForFile(db, parentId, filePath);
30271
- importsCache.set(filePath, cached2);
30272
- return cached2;
30433
+ for (const filePath of listEffectiveIndexedFilePaths(db, ctx)) {
30434
+ const defs = loadFileTags(db, ctx, filePath).filter((row) => row.role === "def");
30435
+ fileDefsCache.set(filePath, defs);
30436
+ for (const def of defs) {
30437
+ const key = defsByFileNameKey(filePath, def.name);
30438
+ const existing = defsByFileNameCache.get(key);
30439
+ if (existing) {
30440
+ existing.push(def);
30441
+ } else {
30442
+ defsByFileNameCache.set(key, [def]);
30443
+ }
30273
30444
  }
30445
+ importsCache.set(filePath, loadFileImports(db, ctx, filePath));
30446
+ }
30447
+ return {
30448
+ loadFileDefs: (filePath) => fileDefsCache.get(filePath) ?? [],
30449
+ lookupDefsInFileNamed: (filePath, name) => defsByFileNameCache.get(defsByFileNameKey(filePath, name)) ?? [],
30450
+ lookupImportsForFile: (filePath) => importsCache.get(filePath) ?? []
30274
30451
  };
30275
30452
  }
30276
30453
 
@@ -30279,11 +30456,11 @@ function refScopeChain(ref) {
30279
30456
  const parsed = parseScopeChain(ref.scope_chain);
30280
30457
  if (parsed.length > 0) return parsed;
30281
30458
  if (ref.scope_start_line != null && ref.scope_start_column != null) {
30282
- const chain3 = [{ startLine: ref.scope_start_line, startColumn: ref.scope_start_column }];
30459
+ const chain2 = [{ startLine: ref.scope_start_line, startColumn: ref.scope_start_column }];
30283
30460
  if (ref.parent_scope_start_line != null && ref.parent_scope_start_column != null) {
30284
- chain3.push({ startLine: ref.parent_scope_start_line, startColumn: ref.parent_scope_start_column });
30461
+ chain2.push({ startLine: ref.parent_scope_start_line, startColumn: ref.parent_scope_start_column });
30285
30462
  }
30286
- return chain3;
30463
+ return chain2;
30287
30464
  }
30288
30465
  return [];
30289
30466
  }
@@ -30294,17 +30471,17 @@ function defAtScopeAnchor(def, anchor) {
30294
30471
  return scopesMatch(def.scope_start_line, def.scope_start_column, anchor.startLine, anchor.startColumn) || scopesMatch(def.start_line, def.start_column, anchor.startLine, anchor.startColumn);
30295
30472
  }
30296
30473
  function defVisibleInRefScopeChain(def, ref) {
30297
- const chain3 = refScopeChain(ref);
30298
- if (chain3.length === 0) return isModuleLevelDef2(def);
30299
- return anchorInScopeChain(def.scope_start_line, def.scope_start_column, chain3) || anchorInScopeChain(def.start_line, def.start_column, chain3.slice(1));
30474
+ const chain2 = refScopeChain(ref);
30475
+ if (chain2.length === 0) return isModuleLevelDef2(def);
30476
+ return anchorInScopeChain(def.scope_start_line, def.scope_start_column, chain2) || anchorInScopeChain(def.start_line, def.start_column, chain2.slice(1));
30300
30477
  }
30301
30478
  function scopeDepthInChain(def, ref) {
30302
- const chain3 = refScopeChain(ref);
30303
- for (let index = 0; index < chain3.length; index++) {
30304
- const anchor = chain3[index];
30479
+ const chain2 = refScopeChain(ref);
30480
+ for (let index = 0; index < chain2.length; index++) {
30481
+ const anchor = chain2[index];
30305
30482
  if (defAtScopeAnchor(def, anchor)) return index;
30306
30483
  }
30307
- return chain3.length;
30484
+ return chain2.length;
30308
30485
  }
30309
30486
 
30310
30487
  // src/code-nav/resolution/navigation/confidence.ts
@@ -30470,9 +30647,9 @@ function resolveScopeLevelCandidates(defs) {
30470
30647
  function resolveLocalDefinitions(ref, fileDefs) {
30471
30648
  const named = fileDefs.filter((def) => def.name === ref.name && declaredBeforeRef(def, ref));
30472
30649
  if (named.length === 0) return [];
30473
- const chain3 = refScopeChain(ref);
30474
- if (chain3.length > 0) {
30475
- for (const anchor of chain3) {
30650
+ const chain2 = refScopeChain(ref);
30651
+ if (chain2.length > 0) {
30652
+ for (const anchor of chain2) {
30476
30653
  const atLevel = named.filter((def) => defAtScopeAnchor(def, anchor));
30477
30654
  if (atLevel.length > 0) return resolveScopeLevelCandidates(atLevel);
30478
30655
  }
@@ -30487,10 +30664,10 @@ function resolveLocalDefinitions(ref, fileDefs) {
30487
30664
  function resolveLocalDefinitionCandidates(ref, fileDefs) {
30488
30665
  const named = fileDefs.filter((def) => def.name === ref.name && declaredBeforeRef(def, ref));
30489
30666
  if (named.length === 0) return [];
30490
- const chain3 = refScopeChain(ref);
30491
- if (chain3.length === 0) return resolveScopeLevelCandidates(named.filter((def) => isModuleLevelDef2(def)));
30667
+ const chain2 = refScopeChain(ref);
30668
+ if (chain2.length === 0) return resolveScopeLevelCandidates(named.filter((def) => isModuleLevelDef2(def)));
30492
30669
  const visible = named.filter((def) => {
30493
- if (chain3.some((anchor) => defAtScopeAnchor(def, anchor))) return true;
30670
+ if (chain2.some((anchor) => defAtScopeAnchor(def, anchor))) return true;
30494
30671
  if (defVisibleInRefScopeChain(def, ref)) return true;
30495
30672
  return isModuleLevelDef2(def);
30496
30673
  });
@@ -30671,32 +30848,41 @@ function pickPrimaryTagAtPosition(rows, filePath, line, column) {
30671
30848
  async function queryDefinitionsNavigation(parentPath, filePath, line, column) {
30672
30849
  await yieldToEventLoop();
30673
30850
  const resolved = normalizeResolvedPath(parentPath);
30674
- const result = withCodeNavCacheSqliteSync((db) => {
30851
+ const snapshot = await withCodeNavCacheSqlite((db) => {
30675
30852
  const ctx = getSymbolIndexParentContext(db, resolved);
30676
30853
  if (ctx == null) return null;
30677
30854
  const fileRows = loadFileTags(db, ctx, filePath);
30678
30855
  const primary = pickPrimaryTagAtPosition(fileRows, filePath, line, column);
30679
30856
  if (!primary) return null;
30680
30857
  const atPos = findTagsAtPosition(fileRows, filePath, line, column);
30681
- if (primary.kind === "module" && primary.nav_target_path) {
30682
- return { definitions: [modulePathLocation(primary)], confidentTarget: true };
30683
- }
30684
- const onDefinition = atPos.some((row) => row.role === "def");
30685
- if (onDefinition) {
30686
- const defs = atPos.filter((row) => row.role === "def").map(rowToLocation);
30687
- return { definitions: defs, confidentTarget: defs.length === 1 };
30688
- }
30689
- const lookups = createNavigationLookups(db, ctx.parentId);
30858
+ const lookups = createSnapshotNavigationLookups(db, ctx.parentId);
30690
30859
  const workspaceFiles = listWorkspaceFiles(db, resolved, filePath);
30691
- const navCtx = buildNavigationContext(filePath, primary, lookups, workspaceFiles);
30692
- const navigation = resolveNavigation(navCtx);
30693
- return {
30694
- definitions: navigation.definitions.map(rowToLocation),
30695
- confidentTarget: navigation.confidentTarget
30696
- };
30860
+ return { primary, atPos, lookups, workspaceFiles };
30697
30861
  });
30862
+ if (snapshot == null) {
30863
+ await yieldToEventLoop();
30864
+ return { definitions: [], confidentTarget: false };
30865
+ }
30866
+ const result = resolveDefinitionsFromSnapshot(filePath, snapshot);
30698
30867
  await yieldToEventLoop();
30699
- return result ?? { definitions: [], confidentTarget: false };
30868
+ return result;
30869
+ }
30870
+ function resolveDefinitionsFromSnapshot(filePath, snapshot) {
30871
+ const { primary, atPos, lookups, workspaceFiles } = snapshot;
30872
+ if (primary.kind === "module" && primary.nav_target_path) {
30873
+ return { definitions: [modulePathLocation(primary)], confidentTarget: true };
30874
+ }
30875
+ const onDefinition = atPos.some((row) => row.role === "def");
30876
+ if (onDefinition) {
30877
+ const defs = atPos.filter((row) => row.role === "def").map(rowToLocation);
30878
+ return { definitions: defs, confidentTarget: defs.length === 1 };
30879
+ }
30880
+ const navCtx = buildNavigationContext(filePath, primary, lookups, workspaceFiles);
30881
+ const navigation = resolveNavigation(navCtx);
30882
+ return {
30883
+ definitions: navigation.definitions.map(rowToLocation),
30884
+ confidentTarget: navigation.confidentTarget
30885
+ };
30700
30886
  }
30701
30887
  async function queryDefinitionsAt(parentPath, filePath, line, column) {
30702
30888
  return (await queryDefinitionsNavigation(parentPath, filePath, line, column)).definitions;
@@ -30709,7 +30895,7 @@ async function queryDefinitionAt(parentPath, filePath, line, column) {
30709
30895
  async function queryReferencesAt(parentPath, filePath, line, column) {
30710
30896
  await yieldToEventLoop();
30711
30897
  const resolved = normalizeResolvedPath(parentPath);
30712
- const rows = withCodeNavCacheSqliteSync((db) => {
30898
+ const rows = await withCodeNavCacheSqlite((db) => {
30713
30899
  const ctx = getSymbolIndexParentContext(db, resolved);
30714
30900
  if (ctx == null) return null;
30715
30901
  const fileRows = loadFileTags(db, ctx, filePath);
@@ -30744,23 +30930,28 @@ function rowToSymbolSpan(row, clickable) {
30744
30930
  async function querySymbolsInFile(parentPath, filePath) {
30745
30931
  await yieldToEventLoop();
30746
30932
  const resolved = normalizeResolvedPath(parentPath);
30747
- const spans = withCodeNavCacheSqliteSync((db) => {
30933
+ const snapshot = await withCodeNavCacheSqlite((db) => {
30748
30934
  const ctx = getSymbolIndexParentContext(db, resolved);
30749
- if (ctx == null) return [];
30935
+ if (ctx == null) return null;
30750
30936
  const rows = loadFileTags(db, ctx, filePath);
30751
- if (rows.length === 0) return [];
30752
- const lookups = createNavigationLookups(db, ctx.parentId);
30937
+ if (rows.length === 0) return null;
30938
+ const lookups = createSnapshotNavigationLookups(db, ctx.parentId);
30753
30939
  const workspaceFiles = listWorkspaceFiles(db, resolved, filePath);
30754
- const baseCtx = buildNavigationContext(
30755
- filePath,
30756
- rows[0] ?? emptyRefRow(filePath),
30757
- lookups,
30758
- workspaceFiles
30759
- );
30760
- return rows.map((row) => {
30761
- const navCtx = { ...baseCtx, ref: row };
30762
- return rowToSymbolSpan(row, refHasResolvableDefinitions(navCtx));
30763
- });
30940
+ return { rows, lookups, workspaceFiles };
30941
+ });
30942
+ if (snapshot == null) {
30943
+ await yieldToEventLoop();
30944
+ return [];
30945
+ }
30946
+ const baseCtx = buildNavigationContext(
30947
+ filePath,
30948
+ snapshot.rows[0] ?? emptyRefRow(filePath),
30949
+ snapshot.lookups,
30950
+ snapshot.workspaceFiles
30951
+ );
30952
+ const spans = snapshot.rows.map((row) => {
30953
+ const navCtx = { ...baseCtx, ref: row };
30954
+ return rowToSymbolSpan(row, refHasResolvableDefinitions(navCtx));
30764
30955
  });
30765
30956
  await yieldToEventLoop();
30766
30957
  return spans;
@@ -31763,8 +31954,8 @@ async function execGitFile(args, options) {
31763
31954
  }
31764
31955
 
31765
31956
  // src/git/changes/parse/normalize-git-diff-path.ts
31766
- function normalizeGitDiffPath(path71) {
31767
- return path71.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
31957
+ function normalizeGitDiffPath(path73) {
31958
+ return path73.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
31768
31959
  }
31769
31960
 
31770
31961
  // src/git/changes/parse/parse-name-status-entries.ts
@@ -32051,9 +32242,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
32051
32242
  // src/agents/acp/put-summarize-change-summaries.ts
32052
32243
  async function putEncryptedChangeSummaryRows(params) {
32053
32244
  const base = params.apiBaseUrl.replace(/\/+$/, "");
32054
- const entries = params.rows.map(({ path: path71, summary }) => {
32245
+ const entries = params.rows.map(({ path: path73, summary }) => {
32055
32246
  const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
32056
- return { path: path71, summary: JSON.stringify(enc) };
32247
+ return { path: path73, summary: JSON.stringify(enc) };
32057
32248
  });
32058
32249
  const res = await fetch(
32059
32250
  `${base}/internal/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
@@ -32980,8 +33171,8 @@ function pathspec(...paths) {
32980
33171
  cache.set(key, paths);
32981
33172
  return key;
32982
33173
  }
32983
- function isPathSpec(path71) {
32984
- return path71 instanceof String && cache.has(path71);
33174
+ function isPathSpec(path73) {
33175
+ return path73 instanceof String && cache.has(path73);
32985
33176
  }
32986
33177
  function toPaths(pathSpec) {
32987
33178
  return cache.get(pathSpec) || [];
@@ -33070,8 +33261,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
33070
33261
  function forEachLineWithContent(input, callback) {
33071
33262
  return toLinesWithContent(input, true).map((line) => callback(line));
33072
33263
  }
33073
- function folderExists(path71) {
33074
- return (0, import_file_exists.exists)(path71, import_file_exists.FOLDER);
33264
+ function folderExists(path73) {
33265
+ return (0, import_file_exists.exists)(path73, import_file_exists.FOLDER);
33075
33266
  }
33076
33267
  function append(target, item) {
33077
33268
  if (Array.isArray(target)) {
@@ -33475,8 +33666,8 @@ function checkIsRepoRootTask() {
33475
33666
  commands,
33476
33667
  format: "utf-8",
33477
33668
  onError,
33478
- parser(path71) {
33479
- return /^\.(git)?$/.test(path71.trim());
33669
+ parser(path73) {
33670
+ return /^\.(git)?$/.test(path73.trim());
33480
33671
  }
33481
33672
  };
33482
33673
  }
@@ -33910,11 +34101,11 @@ function parseGrep(grep) {
33910
34101
  const paths = /* @__PURE__ */ new Set();
33911
34102
  const results = {};
33912
34103
  forEachLineWithContent(grep, (input) => {
33913
- const [path71, line, preview] = input.split(NULL);
33914
- paths.add(path71);
33915
- (results[path71] = results[path71] || []).push({
34104
+ const [path73, line, preview] = input.split(NULL);
34105
+ paths.add(path73);
34106
+ (results[path73] = results[path73] || []).push({
33916
34107
  line: asNumber(line),
33917
- path: path71,
34108
+ path: path73,
33918
34109
  preview
33919
34110
  });
33920
34111
  });
@@ -34679,14 +34870,14 @@ var init_hash_object = __esm2({
34679
34870
  init_task();
34680
34871
  }
34681
34872
  });
34682
- function parseInit(bare, path71, text) {
34873
+ function parseInit(bare, path73, text) {
34683
34874
  const response = String(text).trim();
34684
34875
  let result;
34685
34876
  if (result = initResponseRegex.exec(response)) {
34686
- return new InitSummary(bare, path71, false, result[1]);
34877
+ return new InitSummary(bare, path73, false, result[1]);
34687
34878
  }
34688
34879
  if (result = reInitResponseRegex.exec(response)) {
34689
- return new InitSummary(bare, path71, true, result[1]);
34880
+ return new InitSummary(bare, path73, true, result[1]);
34690
34881
  }
34691
34882
  let gitDir = "";
34692
34883
  const tokens = response.split(" ");
@@ -34697,7 +34888,7 @@ function parseInit(bare, path71, text) {
34697
34888
  break;
34698
34889
  }
34699
34890
  }
34700
- return new InitSummary(bare, path71, /^re/i.test(response), gitDir);
34891
+ return new InitSummary(bare, path73, /^re/i.test(response), gitDir);
34701
34892
  }
34702
34893
  var InitSummary;
34703
34894
  var initResponseRegex;
@@ -34706,9 +34897,9 @@ var init_InitSummary = __esm2({
34706
34897
  "src/lib/responses/InitSummary.ts"() {
34707
34898
  "use strict";
34708
34899
  InitSummary = class {
34709
- constructor(bare, path71, existing, gitDir) {
34900
+ constructor(bare, path73, existing, gitDir) {
34710
34901
  this.bare = bare;
34711
- this.path = path71;
34902
+ this.path = path73;
34712
34903
  this.existing = existing;
34713
34904
  this.gitDir = gitDir;
34714
34905
  }
@@ -34720,7 +34911,7 @@ var init_InitSummary = __esm2({
34720
34911
  function hasBareCommand(command) {
34721
34912
  return command.includes(bareCommand);
34722
34913
  }
34723
- function initTask(bare = false, path71, customArgs) {
34914
+ function initTask(bare = false, path73, customArgs) {
34724
34915
  const commands = ["init", ...customArgs];
34725
34916
  if (bare && !hasBareCommand(commands)) {
34726
34917
  commands.splice(1, 0, bareCommand);
@@ -34729,7 +34920,7 @@ function initTask(bare = false, path71, customArgs) {
34729
34920
  commands,
34730
34921
  format: "utf-8",
34731
34922
  parser(text) {
34732
- return parseInit(commands.includes("--bare"), path71, text);
34923
+ return parseInit(commands.includes("--bare"), path73, text);
34733
34924
  }
34734
34925
  };
34735
34926
  }
@@ -35545,12 +35736,12 @@ var init_FileStatusSummary = __esm2({
35545
35736
  "use strict";
35546
35737
  fromPathRegex = /^(.+)\0(.+)$/;
35547
35738
  FileStatusSummary = class {
35548
- constructor(path71, index, working_dir) {
35549
- this.path = path71;
35739
+ constructor(path73, index, working_dir) {
35740
+ this.path = path73;
35550
35741
  this.index = index;
35551
35742
  this.working_dir = working_dir;
35552
35743
  if (index === "R" || working_dir === "R") {
35553
- const detail = fromPathRegex.exec(path71) || [null, path71, path71];
35744
+ const detail = fromPathRegex.exec(path73) || [null, path73, path73];
35554
35745
  this.from = detail[2] || "";
35555
35746
  this.path = detail[1] || "";
35556
35747
  }
@@ -35581,14 +35772,14 @@ function splitLine(result, lineStr) {
35581
35772
  default:
35582
35773
  return;
35583
35774
  }
35584
- function data(index, workingDir, path71) {
35775
+ function data(index, workingDir, path73) {
35585
35776
  const raw = `${index}${workingDir}`;
35586
35777
  const handler = parsers6.get(raw);
35587
35778
  if (handler) {
35588
- handler(result, path71);
35779
+ handler(result, path73);
35589
35780
  }
35590
35781
  if (raw !== "##" && raw !== "!!") {
35591
- result.files.push(new FileStatusSummary(path71, index, workingDir));
35782
+ result.files.push(new FileStatusSummary(path73, index, workingDir));
35592
35783
  }
35593
35784
  }
35594
35785
  }
@@ -35861,15 +36052,15 @@ var init_simple_git_api = __esm2({
35861
36052
  this._executor = _executor;
35862
36053
  }
35863
36054
  _runTask(task, then) {
35864
- const chain3 = this._executor.chain();
35865
- const promise2 = chain3.push(task);
36055
+ const chain2 = this._executor.chain();
36056
+ const promise2 = chain2.push(task);
35866
36057
  if (then) {
35867
36058
  taskCallback(task, promise2, then);
35868
36059
  }
35869
36060
  return Object.create(this, {
35870
36061
  then: { value: promise2.then.bind(promise2) },
35871
36062
  catch: { value: promise2.catch.bind(promise2) },
35872
- _executor: { value: chain3 }
36063
+ _executor: { value: chain2 }
35873
36064
  });
35874
36065
  }
35875
36066
  add(files) {
@@ -35897,9 +36088,9 @@ var init_simple_git_api = __esm2({
35897
36088
  next
35898
36089
  );
35899
36090
  }
35900
- hashObject(path71, write) {
36091
+ hashObject(path73, write) {
35901
36092
  return this._runTask(
35902
- hashObjectTask(path71, write === true),
36093
+ hashObjectTask(path73, write === true),
35903
36094
  trailingFunctionArgument(arguments)
35904
36095
  );
35905
36096
  }
@@ -36252,8 +36443,8 @@ var init_branch = __esm2({
36252
36443
  }
36253
36444
  });
36254
36445
  function toPath(input) {
36255
- const path71 = input.trim().replace(/^["']|["']$/g, "");
36256
- return path71 && normalize3(path71);
36446
+ const path73 = input.trim().replace(/^["']|["']$/g, "");
36447
+ return path73 && normalize3(path73);
36257
36448
  }
36258
36449
  var parseCheckIgnore;
36259
36450
  var init_CheckIgnore = __esm2({
@@ -36567,8 +36758,8 @@ __export2(sub_module_exports, {
36567
36758
  subModuleTask: () => subModuleTask,
36568
36759
  updateSubModuleTask: () => updateSubModuleTask
36569
36760
  });
36570
- function addSubModuleTask(repo, path71) {
36571
- return subModuleTask(["add", repo, path71]);
36761
+ function addSubModuleTask(repo, path73) {
36762
+ return subModuleTask(["add", repo, path73]);
36572
36763
  }
36573
36764
  function initSubModuleTask(customArgs) {
36574
36765
  return subModuleTask(["init", ...customArgs]);
@@ -36901,8 +37092,8 @@ var require_git = __commonJS2({
36901
37092
  }
36902
37093
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
36903
37094
  };
36904
- Git2.prototype.submoduleAdd = function(repo, path71, then) {
36905
- return this._runTask(addSubModuleTask2(repo, path71), trailingFunctionArgument2(arguments));
37095
+ Git2.prototype.submoduleAdd = function(repo, path73, then) {
37096
+ return this._runTask(addSubModuleTask2(repo, path73), trailingFunctionArgument2(arguments));
36906
37097
  };
36907
37098
  Git2.prototype.submoduleUpdate = function(args, then) {
36908
37099
  return this._runTask(
@@ -37638,8 +37829,8 @@ function parseNumstatEntries(lines) {
37638
37829
  }
37639
37830
  function parseNumstat(lines) {
37640
37831
  const m = /* @__PURE__ */ new Map();
37641
- for (const [path71, entry] of parseNumstatEntries(lines)) {
37642
- m.set(path71, { additions: entry.additions, deletions: entry.deletions });
37832
+ for (const [path73, entry] of parseNumstatEntries(lines)) {
37833
+ m.set(path73, { additions: entry.additions, deletions: entry.deletions });
37643
37834
  }
37644
37835
  return m;
37645
37836
  }
@@ -39683,37 +39874,16 @@ function defaultWorktreesRootPath() {
39683
39874
  }
39684
39875
 
39685
39876
  // src/files/watch-file-index.ts
39686
- import fs36 from "node:fs";
39687
- import { watch } from "node:fs";
39688
- import path56 from "node:path";
39877
+ import path58 from "node:path";
39689
39878
 
39690
39879
  // src/files/index/build-file-index.ts
39691
39880
  import path54 from "node:path";
39692
39881
 
39693
39882
  // src/files/index/file-index-sqlite-lock.ts
39694
- import fs35 from "node:fs";
39695
- function isSqliteCorruptError2(e) {
39696
- const msg = e instanceof Error ? e.message : String(e);
39697
- return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
39698
- }
39699
- var chain2 = Promise.resolve();
39883
+ var fileIndexChain = Promise.resolve();
39700
39884
  function withFileIndexSqliteLock(fn) {
39701
- const run = async () => {
39702
- try {
39703
- return await Promise.resolve(fn());
39704
- } catch (e) {
39705
- if (!isSqliteCorruptError2(e)) throw e;
39706
- closeAllCodeNavCacheSqliteConnections();
39707
- try {
39708
- fs35.unlinkSync(getCodeNavCacheSqlitePath());
39709
- } catch {
39710
- }
39711
- chain2 = Promise.resolve();
39712
- return await Promise.resolve(fn());
39713
- }
39714
- };
39715
- const next = chain2.then(run);
39716
- chain2 = next.then(
39885
+ const next = fileIndexChain.then(() => Promise.resolve(fn()));
39886
+ fileIndexChain = next.then(
39717
39887
  () => void 0,
39718
39888
  () => void 0
39719
39889
  );
@@ -39734,6 +39904,14 @@ async function collectWorkspacePathsAsync(resolved) {
39734
39904
  return paths;
39735
39905
  }
39736
39906
 
39907
+ // src/files/index/file-index-persist-constants.ts
39908
+ var FILE_INDEX_INSERT_BUFFER = 2048;
39909
+
39910
+ // src/files/index/file-index-persist-shutdown.ts
39911
+ function assertFileIndexPersistNotShutdown() {
39912
+ if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
39913
+ }
39914
+
39737
39915
  // src/files/index/file-index-parent-path.ts
39738
39916
  function upsertFileIndexParentPath(db, resolved) {
39739
39917
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -39748,57 +39926,56 @@ function upsertFileIndexParentPath(db, resolved) {
39748
39926
  return Number(row.id);
39749
39927
  }
39750
39928
 
39751
- // src/files/index/persist-file-index.ts
39752
- var FILE_INDEX_INTERRUPT_CHECK_EVERY = 256;
39753
- function assertNotShutdown2() {
39754
- if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
39929
+ // src/files/index/file-index-persist-transaction.ts
39930
+ function clearFileIndexChildPaths(db, resolved) {
39931
+ runCodeNavCacheWriteTransaction(db, () => {
39932
+ const parentId = upsertFileIndexParentPath(db, resolved);
39933
+ db.run("DELETE FROM file_index_child_path WHERE parent_id = ?", [parentId]);
39934
+ });
39755
39935
  }
39756
- function persistFileIndexPaths(resolved, paths) {
39757
- return withCodeNavCacheSqliteSync((db) => {
39758
- let pathCount = 0;
39759
- db.run("BEGIN IMMEDIATE");
39936
+ function insertFileIndexChildPathBatch(db, resolved, paths) {
39937
+ return runCodeNavCacheWriteTransaction(db, () => {
39938
+ const parentId = upsertFileIndexParentPath(db, resolved);
39939
+ const ins = db.prepare(
39940
+ "INSERT INTO file_index_child_path (parent_id, path) VALUES (?, ?)"
39941
+ );
39760
39942
  try {
39761
- const parentId = upsertFileIndexParentPath(db, resolved);
39762
- db.run("DELETE FROM file_index_child_path WHERE parent_id = ?", [parentId]);
39763
- const ins = db.prepare("INSERT INTO file_index_child_path (parent_id, path) VALUES (?, ?)");
39764
- try {
39765
- let batch = 0;
39766
- for (const rel of paths) {
39767
- if (++batch >= FILE_INDEX_INTERRUPT_CHECK_EVERY) {
39768
- batch = 0;
39769
- assertNotShutdown2();
39770
- }
39771
- ins.run([parentId, rel]);
39772
- pathCount += 1;
39773
- }
39774
- } finally {
39775
- ins.finalize();
39943
+ for (const rel of paths) {
39944
+ ins.run([parentId, rel]);
39776
39945
  }
39777
- db.run("COMMIT");
39778
- } catch (e) {
39779
- try {
39780
- db.run("ROLLBACK");
39781
- } catch {
39782
- }
39783
- throw e;
39946
+ return paths.length;
39947
+ } finally {
39948
+ ins.finalize();
39784
39949
  }
39785
- return pathCount;
39786
39950
  });
39787
39951
  }
39788
39952
 
39953
+ // src/files/index/persist-file-index-paths.ts
39954
+ async function persistFileIndexPathsAsync(resolved, paths) {
39955
+ await withCodeNavCacheSqlite((db) => clearFileIndexChildPaths(db, resolved));
39956
+ let pathCount = 0;
39957
+ for (let offset = 0; offset < paths.length; offset += FILE_INDEX_INSERT_BUFFER) {
39958
+ assertFileIndexPersistNotShutdown();
39959
+ const batch = paths.slice(offset, offset + FILE_INDEX_INSERT_BUFFER);
39960
+ pathCount += await withCodeNavCacheSqlite((db) => insertFileIndexChildPathBatch(db, resolved, batch));
39961
+ await yieldToEventLoop();
39962
+ }
39963
+ return pathCount;
39964
+ }
39965
+
39789
39966
  // src/files/index/build-file-index.ts
39790
- function assertNotShutdown3() {
39967
+ function assertNotShutdown2() {
39791
39968
  if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
39792
39969
  }
39793
39970
  async function buildFileIndexAsync(cwd) {
39794
- return withFileIndexSqliteLock(async () => {
39795
- const resolved = path54.resolve(cwd);
39796
- await yieldToEventLoop();
39797
- assertNotShutdown3();
39798
- const paths = await collectWorkspacePathsAsync(resolved);
39799
- await yieldToEventLoop();
39800
- assertNotShutdown3();
39801
- const pathCount = persistFileIndexPaths(resolved, paths);
39971
+ const resolved = path54.resolve(cwd);
39972
+ await yieldToEventLoop();
39973
+ assertNotShutdown2();
39974
+ const paths = await collectWorkspacePathsAsync(resolved);
39975
+ await yieldToEventLoop();
39976
+ assertNotShutdown2();
39977
+ return await withFileIndexSqliteLock(async () => {
39978
+ const pathCount = await persistFileIndexPathsAsync(resolved, paths);
39802
39979
  return { pathCount };
39803
39980
  });
39804
39981
  }
@@ -39863,8 +40040,9 @@ async function ensureFileIndexAsync(cwd) {
39863
40040
  return { ...await buildFileIndexAsync(resolved), fromCache: false };
39864
40041
  }
39865
40042
 
39866
- // src/files/watch-file-index.ts
39867
- var DEBOUNCE_MS = 900;
40043
+ // src/files/index/file-index-fs-watcher.ts
40044
+ import { watch } from "node:fs";
40045
+ var FILE_INDEX_WATCH_DEBOUNCE_MS = 900;
39868
40046
  function shouldIgnoreRelative(rel) {
39869
40047
  const n = rel.replace(/\\/g, "/");
39870
40048
  return n.split("/").some((segment) => shouldSkipWorkspaceWalkEntry(segment));
@@ -39874,7 +40052,7 @@ function attachWatchErrorLog(w) {
39874
40052
  console.error("[file-index] File watcher error:", err);
39875
40053
  });
39876
40054
  }
39877
- function createFsWatcher(resolved, schedule) {
40055
+ function createFileIndexFsWatcher(resolved, schedule) {
39878
40056
  const onEvent = (_event, filename) => {
39879
40057
  if (filename != null) {
39880
40058
  const rel = typeof filename === "string" ? filename.replace(/\\/g, "/") : filename.toString("utf8").replace(/\\/g, "/");
@@ -39901,11 +40079,15 @@ function createFsWatcher(resolved, schedule) {
39901
40079
  throw e;
39902
40080
  }
39903
40081
  }
40082
+
40083
+ // src/files/index/file-index-incremental-symbol-updates.ts
40084
+ import fs35 from "node:fs";
40085
+ import path56 from "node:path";
39904
40086
  async function applyIncrementalSymbolIndexUpdates(resolved, relPaths) {
39905
40087
  for (const rel of relPaths) {
39906
40088
  const absPath = path56.join(resolved, rel);
39907
40089
  try {
39908
- const stat2 = await fs36.promises.stat(absPath);
40090
+ const stat2 = await fs35.promises.stat(absPath);
39909
40091
  if (stat2.isFile()) {
39910
40092
  await updateSymbolIndexForFile(resolved, absPath);
39911
40093
  } else {
@@ -39921,54 +40103,80 @@ async function applyIncrementalSymbolIndexUpdates(resolved, relPaths) {
39921
40103
  await yieldToEventLoop();
39922
40104
  }
39923
40105
  }
39924
- function startFileIndexWatcher(cwd = getBridgeRoot()) {
39925
- const resolved = path56.resolve(cwd);
39926
- void buildFileIndexAsync(resolved).catch((e) => {
40106
+
40107
+ // src/files/index/file-index-initial-builds.ts
40108
+ import path57 from "node:path";
40109
+ async function runInitialIndexBuilds(cwd = getBridgeRoot()) {
40110
+ const resolved = path57.resolve(cwd);
40111
+ try {
40112
+ await buildFileIndexAsync(resolved);
40113
+ await buildSymbolIndexAsync(resolved);
40114
+ } catch (e) {
39927
40115
  if (e instanceof CliSqliteInterrupted) return;
39928
40116
  console.error("[file-index] Initial index build failed:", e);
40117
+ }
40118
+ }
40119
+ function scheduleInitialIndexBuilds(cwd = getBridgeRoot()) {
40120
+ setImmediate(() => {
40121
+ void runInitialIndexBuilds(cwd);
39929
40122
  });
39930
- void buildSymbolIndexAsync(resolved).catch((e) => {
39931
- if (e instanceof CliSqliteInterrupted) return;
39932
- console.error("[code-nav] Initial symbol index build failed:", e);
39933
- });
40123
+ }
40124
+
40125
+ // src/files/watch-file-index.ts
40126
+ var MAX_INCREMENTAL_SYMBOL_UPDATES = 512;
40127
+ function startFileIndexWatcher(cwd = getBridgeRoot()) {
40128
+ const resolved = path58.resolve(cwd);
39934
40129
  let timer = null;
39935
40130
  const pendingSymbolUpdates = /* @__PURE__ */ new Set();
39936
40131
  let needsFullSymbolRebuild = false;
40132
+ let rebuildRunning = false;
40133
+ let rebuildQueued = false;
39937
40134
  const runRebuild = () => {
39938
- void buildFileIndexAsync(resolved).catch((e) => {
39939
- if (e instanceof CliSqliteInterrupted) return;
39940
- console.error("[file-index] Watch rebuild failed:", e);
39941
- });
39942
- if (needsFullSymbolRebuild) {
39943
- needsFullSymbolRebuild = false;
39944
- pendingSymbolUpdates.clear();
39945
- void buildSymbolIndexAsync(resolved).catch((e) => {
39946
- if (e instanceof CliSqliteInterrupted) return;
39947
- console.error("[code-nav] Watch rebuild failed:", e);
39948
- });
40135
+ if (rebuildRunning) {
40136
+ rebuildQueued = true;
39949
40137
  return;
39950
40138
  }
39951
- const relPaths = [...pendingSymbolUpdates];
40139
+ rebuildRunning = true;
40140
+ const fullSymbol = needsFullSymbolRebuild;
40141
+ needsFullSymbolRebuild = false;
40142
+ const relPaths = fullSymbol ? [] : [...pendingSymbolUpdates];
39952
40143
  pendingSymbolUpdates.clear();
39953
- if (relPaths.length === 0) return;
39954
- void applyIncrementalSymbolIndexUpdates(resolved, relPaths).catch((e) => {
40144
+ void buildFileIndexAsync(resolved).then(async () => {
40145
+ if (fullSymbol) {
40146
+ await buildSymbolIndexAsync(resolved);
40147
+ return;
40148
+ }
40149
+ if (relPaths.length === 0) return;
40150
+ await applyIncrementalSymbolIndexUpdates(resolved, relPaths);
40151
+ }).catch((e) => {
39955
40152
  if (e instanceof CliSqliteInterrupted) return;
39956
- console.error("[code-nav] Incremental watch update failed:", e);
40153
+ console.error("[file-index] Watch rebuild failed:", e);
40154
+ }).finally(() => {
40155
+ rebuildRunning = false;
40156
+ if (rebuildQueued || needsFullSymbolRebuild || pendingSymbolUpdates.size > 0) {
40157
+ rebuildQueued = false;
40158
+ setImmediate(runRebuild);
40159
+ }
39957
40160
  });
39958
40161
  };
39959
40162
  const schedule = (relPath) => {
39960
- if (relPath != null) {
40163
+ if (relPath != null && !needsFullSymbolRebuild) {
39961
40164
  pendingSymbolUpdates.add(relPath);
40165
+ if (pendingSymbolUpdates.size > MAX_INCREMENTAL_SYMBOL_UPDATES) {
40166
+ pendingSymbolUpdates.clear();
40167
+ needsFullSymbolRebuild = true;
40168
+ }
39962
40169
  } else {
40170
+ pendingSymbolUpdates.clear();
39963
40171
  needsFullSymbolRebuild = true;
39964
40172
  }
39965
40173
  if (timer) clearTimeout(timer);
39966
40174
  timer = setTimeout(() => {
39967
40175
  timer = null;
39968
40176
  runRebuild();
39969
- }, DEBOUNCE_MS);
40177
+ }, FILE_INDEX_WATCH_DEBOUNCE_MS);
39970
40178
  };
39971
- const watcher = createFsWatcher(resolved, schedule);
40179
+ const watcher = createFileIndexFsWatcher(resolved, schedule);
39972
40180
  return () => {
39973
40181
  if (timer) {
39974
40182
  clearTimeout(timer);
@@ -39979,7 +40187,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
39979
40187
  }
39980
40188
 
39981
40189
  // src/connection/create-bridge-connection.ts
39982
- import * as path70 from "node:path";
40190
+ import * as path72 from "node:path";
39983
40191
 
39984
40192
  // src/dev-servers/manager/dev-server-manager.ts
39985
40193
  import { rm as rm2 } from "node:fs/promises";
@@ -40023,7 +40231,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
40023
40231
  }
40024
40232
 
40025
40233
  // src/dev-servers/process/wire-dev-server-child-process.ts
40026
- import fs37 from "node:fs";
40234
+ import fs36 from "node:fs";
40027
40235
 
40028
40236
  // src/dev-servers/manager/forward-pipe.ts
40029
40237
  function forwardChildPipe(childReadable, terminal, onData) {
@@ -40059,7 +40267,7 @@ function wireDevServerChildProcess(d) {
40059
40267
  d.setPollInterval(void 0);
40060
40268
  return;
40061
40269
  }
40062
- fs37.readFile(d.mergedLogPath, (err, buf) => {
40270
+ fs36.readFile(d.mergedLogPath, (err, buf) => {
40063
40271
  if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
40064
40272
  if (buf.length <= d.mergedReadPos.value) return;
40065
40273
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
@@ -40097,7 +40305,7 @@ ${errTail}` : ""}`);
40097
40305
  d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
40098
40306
  };
40099
40307
  if (mergedPath) {
40100
- fs37.readFile(mergedPath, (err, buf) => {
40308
+ fs36.readFile(mergedPath, (err, buf) => {
40101
40309
  if (!err && buf.length > d.mergedReadPos.value) {
40102
40310
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
40103
40311
  if (chunk.length > 0) {
@@ -40199,13 +40407,13 @@ function parseDevServerDefs(servers) {
40199
40407
  }
40200
40408
 
40201
40409
  // src/dev-servers/manager/shell-spawn/utils.ts
40202
- import fs38 from "node:fs";
40410
+ import fs37 from "node:fs";
40203
40411
  function isSpawnEbadf(e) {
40204
40412
  return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
40205
40413
  }
40206
40414
  function rmDirQuiet(dir) {
40207
40415
  try {
40208
- fs38.rmSync(dir, { recursive: true, force: true });
40416
+ fs37.rmSync(dir, { recursive: true, force: true });
40209
40417
  } catch {
40210
40418
  }
40211
40419
  }
@@ -40213,7 +40421,7 @@ var cachedDevNullReadFd;
40213
40421
  function devNullReadFd() {
40214
40422
  if (cachedDevNullReadFd === void 0) {
40215
40423
  const devPath = process.platform === "win32" ? "nul" : "/dev/null";
40216
- cachedDevNullReadFd = fs38.openSync(devPath, "r");
40424
+ cachedDevNullReadFd = fs37.openSync(devPath, "r");
40217
40425
  }
40218
40426
  return cachedDevNullReadFd;
40219
40427
  }
@@ -40287,15 +40495,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
40287
40495
 
40288
40496
  // src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
40289
40497
  import { spawn as spawn8 } from "node:child_process";
40290
- import fs39 from "node:fs";
40498
+ import fs38 from "node:fs";
40291
40499
  import { tmpdir } from "node:os";
40292
- import path57 from "node:path";
40500
+ import path59 from "node:path";
40293
40501
  function trySpawnMergedLogFile(command, env, cwd, signal) {
40294
- const tmpRoot = fs39.mkdtempSync(path57.join(tmpdir(), "ba-devsrv-log-"));
40295
- const logPath = path57.join(tmpRoot, "combined.log");
40502
+ const tmpRoot = fs38.mkdtempSync(path59.join(tmpdir(), "ba-devsrv-log-"));
40503
+ const logPath = path59.join(tmpRoot, "combined.log");
40296
40504
  let logFd;
40297
40505
  try {
40298
- logFd = fs39.openSync(logPath, "a");
40506
+ logFd = fs38.openSync(logPath, "a");
40299
40507
  } catch {
40300
40508
  rmDirQuiet(tmpRoot);
40301
40509
  return null;
@@ -40314,7 +40522,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
40314
40522
  } else {
40315
40523
  proc = spawn8("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
40316
40524
  }
40317
- fs39.closeSync(logFd);
40525
+ fs38.closeSync(logFd);
40318
40526
  return {
40319
40527
  proc,
40320
40528
  pipedStdoutStderr: true,
@@ -40323,7 +40531,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
40323
40531
  };
40324
40532
  } catch (e) {
40325
40533
  try {
40326
- fs39.closeSync(logFd);
40534
+ fs38.closeSync(logFd);
40327
40535
  } catch {
40328
40536
  }
40329
40537
  rmDirQuiet(tmpRoot);
@@ -40334,22 +40542,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
40334
40542
 
40335
40543
  // src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
40336
40544
  import { spawn as spawn9 } from "node:child_process";
40337
- import fs40 from "node:fs";
40545
+ import fs39 from "node:fs";
40338
40546
  import { tmpdir as tmpdir2 } from "node:os";
40339
- import path58 from "node:path";
40547
+ import path60 from "node:path";
40340
40548
  function shSingleQuote(s) {
40341
40549
  return `'${s.replace(/'/g, `'\\''`)}'`;
40342
40550
  }
40343
40551
  function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
40344
- const tmpRoot = fs40.mkdtempSync(path58.join(tmpdir2(), "ba-devsrv-sh-"));
40345
- const logPath = path58.join(tmpRoot, "combined.log");
40346
- const innerPath = path58.join(tmpRoot, "_cmd.sh");
40347
- const runnerPath = path58.join(tmpRoot, "_run.sh");
40552
+ const tmpRoot = fs39.mkdtempSync(path60.join(tmpdir2(), "ba-devsrv-sh-"));
40553
+ const logPath = path60.join(tmpRoot, "combined.log");
40554
+ const innerPath = path60.join(tmpRoot, "_cmd.sh");
40555
+ const runnerPath = path60.join(tmpRoot, "_run.sh");
40348
40556
  try {
40349
- fs40.writeFileSync(innerPath, `#!/bin/sh
40557
+ fs39.writeFileSync(innerPath, `#!/bin/sh
40350
40558
  ${command}
40351
40559
  `);
40352
- fs40.writeFileSync(
40560
+ fs39.writeFileSync(
40353
40561
  runnerPath,
40354
40562
  `#!/bin/sh
40355
40563
  cd ${shSingleQuote(cwd)}
@@ -40375,13 +40583,13 @@ cd ${shSingleQuote(cwd)}
40375
40583
  }
40376
40584
  }
40377
40585
  function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
40378
- const tmpRoot = fs40.mkdtempSync(path58.join(tmpdir2(), "ba-devsrv-sh-"));
40379
- const logPath = path58.join(tmpRoot, "combined.log");
40380
- const runnerPath = path58.join(tmpRoot, "_run.bat");
40586
+ const tmpRoot = fs39.mkdtempSync(path60.join(tmpdir2(), "ba-devsrv-sh-"));
40587
+ const logPath = path60.join(tmpRoot, "combined.log");
40588
+ const runnerPath = path60.join(tmpRoot, "_run.bat");
40381
40589
  const q = (p) => `"${p.replace(/"/g, '""')}"`;
40382
40590
  const com = process.env.ComSpec || "cmd.exe";
40383
40591
  try {
40384
- fs40.writeFileSync(
40592
+ fs39.writeFileSync(
40385
40593
  runnerPath,
40386
40594
  `@ECHO OFF\r
40387
40595
  CD /D ${q(cwd)}\r
@@ -41038,7 +41246,7 @@ function attachFirehoseAfterIdentified(ctx, params) {
41038
41246
  function scheduleFirehoseRetryAfterDrop(closeMeta) {
41039
41247
  if (state.closedByUser) return;
41040
41248
  const meta = closeMeta ?? state.lastFirehoseReconnectCloseMeta ?? void 0;
41041
- const delay2 = applyTieredReconnectPlanAndLog(
41249
+ const delay3 = applyTieredReconnectPlanAndLog(
41042
41250
  state.firehoseOutage,
41043
41251
  logFn,
41044
41252
  PREVIEW_TUNNEL_SERVICE_LABEL,
@@ -41047,7 +41255,7 @@ function attachFirehoseAfterIdentified(ctx, params) {
41047
41255
  meta?.reason
41048
41256
  );
41049
41257
  armReconnectDelayTimer({
41050
- delayMs: delay2,
41258
+ delayMs: delay3,
41051
41259
  bumpAttempt: () => {
41052
41260
  state.firehoseReconnectAttempt += 1;
41053
41261
  },
@@ -41158,17 +41366,17 @@ async function yieldSkillDiscoveryWork(entryCount) {
41158
41366
  }
41159
41367
 
41160
41368
  // src/skills/discovery/discover-local-skills.ts
41161
- import fs41 from "node:fs";
41162
- import path59 from "node:path";
41369
+ import fs40 from "node:fs";
41370
+ import path61 from "node:path";
41163
41371
  function collectSkillFromDir(rel, base, name, seenKeys, out) {
41164
- const dir = path59.join(base, name);
41372
+ const dir = path61.join(base, name);
41165
41373
  try {
41166
- if (!fs41.statSync(dir).isDirectory()) return;
41374
+ if (!fs40.statSync(dir).isDirectory()) return;
41167
41375
  } catch {
41168
41376
  return;
41169
41377
  }
41170
- const skillMd = path59.join(dir, "SKILL.md");
41171
- if (!fs41.existsSync(skillMd)) return;
41378
+ const skillMd = path61.join(dir, "SKILL.md");
41379
+ if (!fs40.existsSync(skillMd)) return;
41172
41380
  const key = `${rel}/${name}`;
41173
41381
  if (seenKeys.has(key)) return;
41174
41382
  seenKeys.add(key);
@@ -41180,11 +41388,11 @@ async function discoverLocalSkillsAsync(cwd) {
41180
41388
  let work = 0;
41181
41389
  for (const rel of SKILL_DISCOVERY_ROOTS) {
41182
41390
  await yieldSkillDiscoveryWork(++work);
41183
- const base = path59.join(cwd, rel);
41184
- if (!fs41.existsSync(base) || !fs41.statSync(base).isDirectory()) continue;
41391
+ const base = path61.join(cwd, rel);
41392
+ if (!fs40.existsSync(base) || !fs40.statSync(base).isDirectory()) continue;
41185
41393
  let entries = [];
41186
41394
  try {
41187
- entries = fs41.readdirSync(base);
41395
+ entries = fs40.readdirSync(base);
41188
41396
  } catch {
41189
41397
  continue;
41190
41398
  }
@@ -41197,16 +41405,16 @@ async function discoverLocalSkillsAsync(cwd) {
41197
41405
  }
41198
41406
 
41199
41407
  // src/skills/discovery/discover-skill-layout-roots.ts
41200
- import fs42 from "node:fs";
41201
- import path60 from "node:path";
41408
+ import fs41 from "node:fs";
41409
+ import path62 from "node:path";
41202
41410
  function collectLayoutSkill(rel, base, name, skills2) {
41203
- const dir = path60.join(base, name);
41411
+ const dir = path62.join(base, name);
41204
41412
  try {
41205
- if (!fs42.statSync(dir).isDirectory()) return;
41413
+ if (!fs41.statSync(dir).isDirectory()) return;
41206
41414
  } catch {
41207
41415
  return;
41208
41416
  }
41209
- if (!fs42.existsSync(path60.join(dir, "SKILL.md"))) return;
41417
+ if (!fs41.existsSync(path62.join(dir, "SKILL.md"))) return;
41210
41418
  const relPath = `${rel}/${name}`.replace(/\\/g, "/");
41211
41419
  skills2.push({ name, relPath });
41212
41420
  }
@@ -41215,11 +41423,11 @@ async function discoverSkillLayoutRootsAsync(cwd) {
41215
41423
  let work = 0;
41216
41424
  for (const rel of SKILL_DISCOVERY_ROOTS) {
41217
41425
  await yieldSkillDiscoveryWork(++work);
41218
- const base = path60.join(cwd, rel);
41219
- if (!fs42.existsSync(base) || !fs42.statSync(base).isDirectory()) continue;
41426
+ const base = path62.join(cwd, rel);
41427
+ if (!fs41.existsSync(base) || !fs41.statSync(base).isDirectory()) continue;
41220
41428
  let entries = [];
41221
41429
  try {
41222
- entries = fs42.readdirSync(base);
41430
+ entries = fs41.readdirSync(base);
41223
41431
  } catch {
41224
41432
  continue;
41225
41433
  }
@@ -41307,27 +41515,6 @@ function buildBridgeUrl(apiUrl, workspaceId, authToken) {
41307
41515
  return `${base}/ws/bridge?${params.toString()}`;
41308
41516
  }
41309
41517
 
41310
- // src/connection/report-git-repos.ts
41311
- function reportGitRepos(getWs, log2) {
41312
- setImmediate(() => {
41313
- discoverGitRepos().then((repos) => {
41314
- if (repos.length > 0) {
41315
- const socket = getWs();
41316
- if (socket) {
41317
- sendWsMessage(socket, {
41318
- type: "git_repos",
41319
- repos: repos.map((r) => ({ absolutePath: r.absolutePath, remoteUrl: r.remoteUrl }))
41320
- });
41321
- }
41322
- }
41323
- }).catch((err) => {
41324
- log2(
41325
- `[Bridge service] Git repository discovery failed: ${err instanceof Error ? err.message : String(err)}`
41326
- );
41327
- });
41328
- });
41329
- }
41330
-
41331
41518
  // src/types/api-to-bridge-messages.ts
41332
41519
  var API_TO_BRIDGE_MESSAGE_TYPES = [
41333
41520
  "auth_token",
@@ -41584,11 +41771,11 @@ function syncRunningTurnQueueKeys(turns, queueKey) {
41584
41771
  }
41585
41772
 
41586
41773
  // src/prompt-turn-queue/runner/run-local-revert-before-queued-prompt.ts
41587
- import fs44 from "node:fs";
41774
+ import fs43 from "node:fs";
41588
41775
 
41589
41776
  // src/git/snapshot/capture.ts
41590
- import * as fs43 from "node:fs";
41591
- import * as path61 from "node:path";
41777
+ import * as fs42 from "node:fs";
41778
+ import * as path63 from "node:path";
41592
41779
 
41593
41780
  // src/git/snapshot/git.ts
41594
41781
  async function gitStashCreate(repoRoot, log2) {
@@ -41628,7 +41815,7 @@ async function gitRun(repoRoot, args, log2, label) {
41628
41815
  async function resolveSnapshotRepoRoots(options) {
41629
41816
  const { worktreePaths, fallbackCwd, sessionId, log: log2 } = options;
41630
41817
  if (worktreePaths?.length) {
41631
- const uniq = [...new Set(worktreePaths.map((p) => path61.resolve(p)))];
41818
+ const uniq = [...new Set(worktreePaths.map((p) => path63.resolve(p)))];
41632
41819
  return uniq;
41633
41820
  }
41634
41821
  try {
@@ -41636,7 +41823,7 @@ async function resolveSnapshotRepoRoots(options) {
41636
41823
  const mapped = repos.map((r) => r.absolutePath);
41637
41824
  const sid = sessionId?.trim();
41638
41825
  if (sid) {
41639
- const filtered = mapped.filter((root) => path61.basename(root) === sid);
41826
+ const filtered = mapped.filter((root) => path63.basename(root) === sid);
41640
41827
  if (filtered.length > 0) return filtered;
41641
41828
  }
41642
41829
  return mapped;
@@ -41658,7 +41845,7 @@ async function capturePreTurnSnapshot(options) {
41658
41845
  });
41659
41846
  const dir = snapshotsDirForCwd(agentCwd);
41660
41847
  try {
41661
- fs43.mkdirSync(dir, { recursive: true });
41848
+ fs42.mkdirSync(dir, { recursive: true });
41662
41849
  } catch (e) {
41663
41850
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
41664
41851
  }
@@ -41667,9 +41854,9 @@ async function capturePreTurnSnapshot(options) {
41667
41854
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
41668
41855
  repos
41669
41856
  };
41670
- const filePath = path61.join(dir, `${runId}.json`);
41857
+ const filePath = path63.join(dir, `${runId}.json`);
41671
41858
  try {
41672
- fs43.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
41859
+ fs42.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
41673
41860
  } catch (e) {
41674
41861
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
41675
41862
  }
@@ -41682,7 +41869,7 @@ async function capturePreTurnSnapshot(options) {
41682
41869
  async function applyPreTurnSnapshot(filePath, log2) {
41683
41870
  let data;
41684
41871
  try {
41685
- const raw = fs43.readFileSync(filePath, "utf8");
41872
+ const raw = fs42.readFileSync(filePath, "utf8");
41686
41873
  data = JSON.parse(raw);
41687
41874
  } catch (e) {
41688
41875
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
@@ -41722,7 +41909,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
41722
41909
  const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
41723
41910
  const file2 = snapshotFilePath(agentBase, tid);
41724
41911
  try {
41725
- await fs44.promises.access(file2, fs44.constants.F_OK);
41912
+ await fs43.promises.access(file2, fs43.constants.F_OK);
41726
41913
  } catch {
41727
41914
  deps.log(
41728
41915
  `[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
@@ -42010,9 +42197,9 @@ function parseChangeSummarySnapshots(raw) {
42010
42197
  for (const item of raw) {
42011
42198
  if (!item || typeof item !== "object") continue;
42012
42199
  const o = item;
42013
- const path71 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
42014
- if (!path71) continue;
42015
- const row = { path: path71 };
42200
+ const path73 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
42201
+ if (!path73) continue;
42202
+ const row = { path: path73 };
42016
42203
  if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
42017
42204
  if (typeof o.oldText === "string") row.oldText = o.oldText;
42018
42205
  if (typeof o.newText === "string") row.newText = o.newText;
@@ -42237,14 +42424,14 @@ async function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId
42237
42424
  }
42238
42425
 
42239
42426
  // src/files/list-dir/index.ts
42240
- import fs46 from "node:fs";
42427
+ import fs45 from "node:fs";
42241
42428
 
42242
42429
  // src/files/ensure-under-cwd.ts
42243
- import path62 from "node:path";
42430
+ import path64 from "node:path";
42244
42431
  function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
42245
- const normalized = path62.normalize(relativePath).replace(/^(\.\/)+/, "");
42246
- const resolved = path62.resolve(cwd, normalized);
42247
- if (!resolved.startsWith(cwd + path62.sep) && resolved !== cwd) {
42432
+ const normalized = path64.normalize(relativePath).replace(/^(\.\/)+/, "");
42433
+ const resolved = path64.resolve(cwd, normalized);
42434
+ if (!resolved.startsWith(cwd + path64.sep) && resolved !== cwd) {
42248
42435
  return null;
42249
42436
  }
42250
42437
  return resolved;
@@ -42254,15 +42441,15 @@ function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
42254
42441
  var LIST_DIR_YIELD_EVERY = 256;
42255
42442
 
42256
42443
  // src/files/list-dir/map-dir-entry.ts
42257
- import path63 from "node:path";
42258
- import fs45 from "node:fs";
42444
+ import path65 from "node:path";
42445
+ import fs44 from "node:fs";
42259
42446
  async function mapDirEntry(d, relativePath, resolved) {
42260
- const entryPath = path63.join(relativePath || ".", d.name).replace(/\\/g, "/");
42261
- const fullPath = path63.join(resolved, d.name);
42447
+ const entryPath = path65.join(relativePath || ".", d.name).replace(/\\/g, "/");
42448
+ const fullPath = path65.join(resolved, d.name);
42262
42449
  let isDir = d.isDirectory();
42263
42450
  if (d.isSymbolicLink()) {
42264
42451
  try {
42265
- const targetStat = await fs45.promises.stat(fullPath);
42452
+ const targetStat = await fs44.promises.stat(fullPath);
42266
42453
  isDir = targetStat.isDirectory();
42267
42454
  } catch {
42268
42455
  isDir = false;
@@ -42292,7 +42479,7 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
42292
42479
  return { error: "Path is outside working directory" };
42293
42480
  }
42294
42481
  try {
42295
- const names = await fs46.promises.readdir(resolved, { withFileTypes: true });
42482
+ const names = await fs45.promises.readdir(resolved, { withFileTypes: true });
42296
42483
  const entries = [];
42297
42484
  for (let i = 0; i < names.length; i++) {
42298
42485
  if (i > 0 && i % LIST_DIR_YIELD_EVERY === 0) {
@@ -42308,13 +42495,13 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
42308
42495
  }
42309
42496
 
42310
42497
  // src/files/handle-file-browser-search.ts
42311
- import path64 from "node:path";
42498
+ import path66 from "node:path";
42312
42499
  var SEARCH_LIMIT = 100;
42313
42500
  function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
42314
42501
  void (async () => {
42315
42502
  await yieldToEventLoop();
42316
42503
  const q = typeof msg.q === "string" ? msg.q : "";
42317
- const sessionParentPath = path64.resolve(
42504
+ const sessionParentPath = path66.resolve(
42318
42505
  sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
42319
42506
  );
42320
42507
  if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
@@ -42418,6 +42605,19 @@ async function resolveCodeNavParentPath(sessionWorktreeManager, sessionId) {
42418
42605
  }
42419
42606
 
42420
42607
  // src/code-nav/handlers/prepare-code-nav-request.ts
42608
+ var CODE_NAV_INDEX_READY_WAIT_MS = 75;
42609
+ var CODE_NAV_INDEX_READY_POLL_MS = 15;
42610
+ function delay2(ms) {
42611
+ return new Promise((resolve32) => setTimeout(resolve32, ms));
42612
+ }
42613
+ async function waitForSymbolIndexReady(sessionParentPath, reqPath) {
42614
+ const deadline = Date.now() + CODE_NAV_INDEX_READY_WAIT_MS;
42615
+ do {
42616
+ if (await symbolIndexFileIsReadyAsync(sessionParentPath, reqPath)) return true;
42617
+ await delay2(CODE_NAV_INDEX_READY_POLL_MS);
42618
+ } while (Date.now() < deadline);
42619
+ return await symbolIndexFileIsReadyAsync(sessionParentPath, reqPath);
42620
+ }
42421
42621
  async function prepareCodeNavRequest(msg, socket, e2ee, sessionWorktreeManager) {
42422
42622
  await yieldToEventLoop();
42423
42623
  const reqPath = msg.path.replace(/^\/+/, "") || "";
@@ -42430,12 +42630,15 @@ async function prepareCodeNavRequest(msg, socket, e2ee, sessionWorktreeManager)
42430
42630
  return null;
42431
42631
  }
42432
42632
  const sessionParentPath = await resolveCodeNavParentPath(sessionWorktreeManager, msg.sessionId);
42433
- registerSymbolIndexParent(sessionParentPath);
42434
- await ensureSymbolIndexFileAsync(sessionParentPath, reqPath, { importDepth: 1 });
42633
+ await registerSymbolIndexParentAsync(sessionParentPath);
42634
+ scheduleSymbolIndexFile(sessionParentPath, reqPath);
42635
+ const indexReady = await waitForSymbolIndexReady(sessionParentPath, reqPath);
42636
+ if (indexReady) {
42637
+ const importTargets = await listDirectImportTargetsForFileAsync(sessionParentPath, reqPath);
42638
+ scheduleSymbolIndexImportNeighbors(sessionParentPath, importTargets);
42639
+ }
42640
+ scheduleSymbolIndexWarmup(sessionParentPath);
42435
42641
  await yieldToEventLoop();
42436
- const importTargets = listDirectImportTargetsForFile(sessionParentPath, reqPath);
42437
- scheduleSymbolIndexForRequest(sessionParentPath, reqPath, importTargets);
42438
- const indexReady = symbolIndexFileIsReady(sessionParentPath, reqPath);
42439
42642
  return {
42440
42643
  socket,
42441
42644
  e2ee,
@@ -42499,20 +42702,22 @@ function handleCodeNavRequest(msg, socket, e2ee, sessionWorktreeManager) {
42499
42702
  // src/code-nav/handlers/trigger-symbol-index-build.ts
42500
42703
  function triggerSymbolIndexBuild(parentPath) {
42501
42704
  setImmediate(() => {
42502
- const resolved = normalizeResolvedPath(parentPath);
42503
- registerSymbolIndexParent(resolved);
42504
- scheduleSymbolIndexWarmup(resolved);
42705
+ void (async () => {
42706
+ const resolved = normalizeResolvedPath(parentPath);
42707
+ await registerSymbolIndexParentAsync(resolved);
42708
+ scheduleSymbolIndexWarmup(resolved);
42709
+ })();
42505
42710
  });
42506
42711
  }
42507
42712
 
42508
42713
  // src/git/tree/resolve-repo-abs-path.ts
42509
- import * as path65 from "node:path";
42714
+ import * as path67 from "node:path";
42510
42715
  function resolveRepoAbsPathFromBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
42511
- const bridgeResolved = path65.resolve(bridgeRoot);
42716
+ const bridgeResolved = path67.resolve(bridgeRoot);
42512
42717
  const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
42513
- const repoPath = rel === "" ? bridgeResolved : path65.join(bridgeResolved, rel);
42514
- const resolved = path65.resolve(repoPath);
42515
- if (!resolved.startsWith(bridgeResolved + path65.sep) && resolved !== bridgeResolved) {
42718
+ const repoPath = rel === "" ? bridgeResolved : path67.join(bridgeResolved, rel);
42719
+ const resolved = path67.resolve(repoPath);
42720
+ if (!resolved.startsWith(bridgeResolved + path67.sep) && resolved !== bridgeResolved) {
42516
42721
  return null;
42517
42722
  }
42518
42723
  return resolved;
@@ -42910,18 +43115,18 @@ async function handleFileBrowserList(socket, e2ee, id, reqPath, sessionParentPat
42910
43115
  }
42911
43116
 
42912
43117
  // src/files/read-file/resolve-file-path.ts
42913
- import fs47 from "node:fs";
43118
+ import fs46 from "node:fs";
42914
43119
  async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeRoot()) {
42915
43120
  const resolved = ensureUnderCwd(relativePath, sessionParentPath);
42916
43121
  if (!resolved) return { error: "Path is outside working directory" };
42917
43122
  let real;
42918
43123
  try {
42919
- real = await fs47.promises.realpath(resolved);
43124
+ real = await fs46.promises.realpath(resolved);
42920
43125
  } catch {
42921
43126
  real = resolved;
42922
43127
  }
42923
43128
  try {
42924
- const stat2 = await fs47.promises.stat(real);
43129
+ const stat2 = await fs46.promises.stat(real);
42925
43130
  if (!stat2.isFile()) return { error: "Not a file" };
42926
43131
  return real;
42927
43132
  } catch (err) {
@@ -42930,11 +43135,11 @@ async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeR
42930
43135
  }
42931
43136
 
42932
43137
  // src/files/read-file/read-file-range-async.ts
42933
- import fs48 from "node:fs";
43138
+ import fs47 from "node:fs";
42934
43139
  import { StringDecoder as StringDecoder2 } from "node:string_decoder";
42935
43140
  async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
42936
- const fileSize = (await fs48.promises.stat(filePath)).size;
42937
- const fd = await fs48.promises.open(filePath, "r");
43141
+ const fileSize = (await fs47.promises.stat(filePath)).size;
43142
+ const fd = await fs47.promises.open(filePath, "r");
42938
43143
  const bufSize = 64 * 1024;
42939
43144
  const buf = Buffer.alloc(bufSize);
42940
43145
  const decoder = new StringDecoder2("utf8");
@@ -43096,11 +43301,11 @@ async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, li
43096
43301
  }
43097
43302
 
43098
43303
  // src/files/read-file/read-file-buffer-full-async.ts
43099
- import fs49 from "node:fs";
43304
+ import fs48 from "node:fs";
43100
43305
  var READ_CHUNK_BYTES = 256 * 1024;
43101
43306
  async function readFileBufferFullAsync(filePath) {
43102
- const stat2 = await fs49.promises.stat(filePath);
43103
- const fd = await fs49.promises.open(filePath, "r");
43307
+ const stat2 = await fs48.promises.stat(filePath);
43308
+ const fd = await fs48.promises.open(filePath, "r");
43104
43309
  const chunks = [];
43105
43310
  let position = 0;
43106
43311
  let bytesSinceYield = 0;
@@ -43294,8 +43499,8 @@ function isValidRemoteSkillInstallItem(item) {
43294
43499
  }
43295
43500
 
43296
43501
  // src/skills/install/install-remote-skills-async.ts
43297
- import fs50 from "node:fs";
43298
- import path66 from "node:path";
43502
+ import fs49 from "node:fs";
43503
+ import path68 from "node:path";
43299
43504
 
43300
43505
  // src/skills/install/constants.ts
43301
43506
  var INSTALL_SKILLS_YIELD_EVERY = 16;
@@ -43306,12 +43511,12 @@ async function writeInstallFileAsync(skillDir, f, filesWritten) {
43306
43511
  if (++filesWritten.count % INSTALL_SKILLS_YIELD_EVERY === 0) {
43307
43512
  await yieldToEventLoop();
43308
43513
  }
43309
- const dest = path66.join(skillDir, f.path);
43310
- await fs50.promises.mkdir(path66.dirname(dest), { recursive: true });
43514
+ const dest = path68.join(skillDir, f.path);
43515
+ await fs49.promises.mkdir(path68.dirname(dest), { recursive: true });
43311
43516
  if (f.text !== void 0) {
43312
- await fs50.promises.writeFile(dest, f.text, "utf8");
43517
+ await fs49.promises.writeFile(dest, f.text, "utf8");
43313
43518
  } else if (f.base64) {
43314
- await fs50.promises.writeFile(dest, Buffer.from(f.base64, "base64"));
43519
+ await fs49.promises.writeFile(dest, Buffer.from(f.base64, "base64"));
43315
43520
  }
43316
43521
  }
43317
43522
  async function installRemoteSkillsAsync(cwd, targetDir, items) {
@@ -43323,7 +43528,7 @@ async function installRemoteSkillsAsync(cwd, targetDir, items) {
43323
43528
  try {
43324
43529
  for (const item of items) {
43325
43530
  if (!isValidRemoteSkillInstallItem(item)) continue;
43326
- const skillDir = path66.join(cwd, targetDir, item.skillName);
43531
+ const skillDir = path68.join(cwd, targetDir, item.skillName);
43327
43532
  for (const f of item.files) {
43328
43533
  await writeInstallFileAsync(skillDir, f, filesWritten);
43329
43534
  }
@@ -43605,7 +43810,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
43605
43810
  };
43606
43811
 
43607
43812
  // src/routing/handlers/revert-turn-snapshot.ts
43608
- import * as fs51 from "node:fs";
43813
+ import * as fs50 from "node:fs";
43609
43814
  var handleRevertTurnSnapshotMessage = (msg, deps) => {
43610
43815
  const id = typeof msg.id === "string" ? msg.id : "";
43611
43816
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
@@ -43618,7 +43823,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
43618
43823
  const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
43619
43824
  const file2 = snapshotFilePath(agentBase, turnId);
43620
43825
  try {
43621
- await fs51.promises.access(file2, fs51.constants.F_OK);
43826
+ await fs50.promises.access(file2, fs50.constants.F_OK);
43622
43827
  } catch {
43623
43828
  sendWsMessage(s, {
43624
43829
  type: "revert_turn_snapshot_result",
@@ -43662,7 +43867,7 @@ var handleDevServersConfig = (msg, deps) => {
43662
43867
  };
43663
43868
 
43664
43869
  // src/git/bridge-git-context.ts
43665
- import * as path67 from "node:path";
43870
+ import * as path69 from "node:path";
43666
43871
 
43667
43872
  // src/git/branches/get-current-branch.ts
43668
43873
  async function getCurrentBranch(repoPath) {
@@ -43712,12 +43917,12 @@ async function listRepoBranchRefs(repoPath) {
43712
43917
  // src/git/bridge-git-context.ts
43713
43918
  function folderNameForRelPath(relPath, bridgeRoot) {
43714
43919
  if (relPath === "." || relPath === "") {
43715
- return path67.basename(path67.resolve(bridgeRoot)) || "repo";
43920
+ return path69.basename(path69.resolve(bridgeRoot)) || "repo";
43716
43921
  }
43717
- return path67.basename(relPath) || relPath;
43922
+ return path69.basename(relPath) || relPath;
43718
43923
  }
43719
43924
  async function discoverGitReposForBridgeContext(bridgeRoot) {
43720
- const root = path67.resolve(bridgeRoot);
43925
+ const root = path69.resolve(bridgeRoot);
43721
43926
  if (await isGitRepoDirectory(root)) {
43722
43927
  const remoteUrl = await getRemoteOriginUrl(root);
43723
43928
  return [{ absolutePath: root, remoteUrl }];
@@ -43725,19 +43930,19 @@ async function discoverGitReposForBridgeContext(bridgeRoot) {
43725
43930
  const [deep, shallow] = await Promise.all([discoverGitReposUnderRoot(root), discoverGitRepos(root)]);
43726
43931
  const byPath = /* @__PURE__ */ new Map();
43727
43932
  for (const repo of [...deep, ...shallow]) {
43728
- byPath.set(path67.resolve(repo.absolutePath), repo);
43933
+ byPath.set(path69.resolve(repo.absolutePath), repo);
43729
43934
  }
43730
43935
  return [...byPath.values()];
43731
43936
  }
43732
43937
  async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
43733
- const bridgeResolved = path67.resolve(bridgeRoot);
43938
+ const bridgeResolved = path69.resolve(bridgeRoot);
43734
43939
  const repos = await discoverGitReposForBridgeContext(bridgeResolved);
43735
43940
  const rows = [];
43736
43941
  for (let i = 0; i < repos.length; i++) {
43737
43942
  if (i > 0) await yieldToEventLoop();
43738
43943
  const repo = repos[i];
43739
- let rel = path67.relative(bridgeResolved, repo.absolutePath);
43740
- if (rel.startsWith("..") || path67.isAbsolute(rel)) continue;
43944
+ let rel = path69.relative(bridgeResolved, repo.absolutePath);
43945
+ if (rel.startsWith("..") || path69.isAbsolute(rel)) continue;
43741
43946
  const relPath = rel === "" ? "." : rel.replace(/\\/g, "/");
43742
43947
  const currentBranch = await getCurrentBranch(repo.absolutePath);
43743
43948
  const remoteUrl = repo.remoteUrl.trim() || null;
@@ -43752,11 +43957,11 @@ async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
43752
43957
  return rows;
43753
43958
  }
43754
43959
  async function listRepoBranchesForBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
43755
- const bridgeResolved = path67.resolve(bridgeRoot);
43960
+ const bridgeResolved = path69.resolve(bridgeRoot);
43756
43961
  const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
43757
- const repoPath = rel === "" ? bridgeResolved : path67.join(bridgeResolved, rel);
43758
- const resolved = path67.resolve(repoPath);
43759
- if (!resolved.startsWith(bridgeResolved + path67.sep) && resolved !== bridgeResolved) {
43962
+ const repoPath = rel === "" ? bridgeResolved : path69.join(bridgeResolved, rel);
43963
+ const resolved = path69.resolve(repoPath);
43964
+ if (!resolved.startsWith(bridgeResolved + path69.sep) && resolved !== bridgeResolved) {
43760
43965
  return [];
43761
43966
  }
43762
43967
  return listRepoBranchRefs(resolved);
@@ -43925,25 +44130,127 @@ async function refreshBridgeTokens(params) {
43925
44130
  }
43926
44131
  }
43927
44132
 
43928
- // src/connection/main-bridge-ws-lifecycle.ts
43929
- function createMainBridgeWebSocketLifecycle(params) {
44133
+ // src/connection/main-bridge-auth-refresh-handler.ts
44134
+ function resetAfterAuthInvalid(params) {
44135
+ const { state } = params;
44136
+ state.reconnectAttempt = 0;
44137
+ resetReconnectOutageTracker(state.mainOutage);
44138
+ state.lastReconnectCloseMeta = null;
44139
+ }
44140
+ function createMainBridgeAuthRefreshHandler(params, connect) {
44141
+ const { apiUrl, workspaceId, logFn, tokens, persistTokens, onAuthInvalid } = params;
44142
+ let authRefreshInFlight = false;
44143
+ return () => {
44144
+ if (authRefreshInFlight) return;
44145
+ void (async () => {
44146
+ authRefreshInFlight = true;
44147
+ try {
44148
+ if (tokens.refreshToken) {
44149
+ const next = await refreshBridgeTokens({
44150
+ apiUrl,
44151
+ workspaceId,
44152
+ refreshToken: tokens.refreshToken
44153
+ });
44154
+ if (next?.token && next.refreshToken) {
44155
+ tokens.accessToken = next.token;
44156
+ tokens.refreshToken = next.refreshToken;
44157
+ persistTokens?.({ token: tokens.accessToken, refreshToken: tokens.refreshToken });
44158
+ try {
44159
+ logFn("[Bridge service] Access token refreshed; reconnecting\u2026");
44160
+ } catch {
44161
+ }
44162
+ resetAfterAuthInvalid(params);
44163
+ params.state.logBridgeOpenAsReconnect = true;
44164
+ authRefreshInFlight = false;
44165
+ connect();
44166
+ return;
44167
+ }
44168
+ }
44169
+ authRefreshInFlight = false;
44170
+ resetAfterAuthInvalid(params);
44171
+ onAuthInvalid();
44172
+ } catch {
44173
+ authRefreshInFlight = false;
44174
+ resetAfterAuthInvalid(params);
44175
+ onAuthInvalid();
44176
+ }
44177
+ })();
44178
+ };
44179
+ }
44180
+
44181
+ // src/connection/main-bridge-ws-close-handler.ts
44182
+ function createMainBridgeCloseHandler(params, connect) {
44183
+ const { state, logFn, bridgeHeartbeat } = params;
44184
+ return (code, reason) => {
44185
+ bridgeHeartbeat?.stop();
44186
+ try {
44187
+ const was = state.currentWs;
44188
+ state.currentWs = null;
44189
+ if (was) was.removeAllListeners();
44190
+ const willReconnect = !state.closedByUser;
44191
+ if (willReconnect) {
44192
+ const duplicateResult = evaluateDuplicateBridgeDisconnect(
44193
+ state.duplicateBridgeFlap,
44194
+ Date.now(),
44195
+ code,
44196
+ reason
44197
+ );
44198
+ logDuplicateBridgeWarning(logFn, duplicateResult);
44199
+ }
44200
+ beginMainBridgeDeferredDisconnect(state, code, reason, logFn, willReconnect);
44201
+ if (willReconnect) {
44202
+ state.lastReconnectCloseMeta = { code, reason };
44203
+ try {
44204
+ scheduleMainBridgeReconnect(state, connect, logFn, { code, reason });
44205
+ } catch {
44206
+ }
44207
+ }
44208
+ } catch {
44209
+ if (!state.closedByUser) {
44210
+ try {
44211
+ scheduleMainBridgeReconnect(state, connect, logFn);
44212
+ } catch {
44213
+ }
44214
+ }
44215
+ }
44216
+ };
44217
+ }
44218
+
44219
+ // src/connection/report-git-repos.ts
44220
+ function reportGitRepos(getWs, log2) {
44221
+ setImmediate(() => {
44222
+ discoverGitRepos().then((repos) => {
44223
+ if (repos.length > 0) {
44224
+ const socket = getWs();
44225
+ if (socket) {
44226
+ sendWsMessage(socket, {
44227
+ type: "git_repos",
44228
+ repos: repos.map((r) => ({ absolutePath: r.absolutePath, remoteUrl: r.remoteUrl }))
44229
+ });
44230
+ }
44231
+ }
44232
+ }).catch((err) => {
44233
+ log2(
44234
+ `[Bridge service] Git repository discovery failed: ${err instanceof Error ? err.message : String(err)}`
44235
+ );
44236
+ });
44237
+ });
44238
+ }
44239
+
44240
+ // src/connection/main-bridge-ws-open-handler.ts
44241
+ function createMainBridgeOpenHandler(params) {
43930
44242
  const {
43931
44243
  state,
43932
44244
  getWs,
43933
- apiUrl,
43934
44245
  workspaceId,
43935
44246
  justAuthenticated,
43936
44247
  logFn,
43937
- messageDeps,
43938
44248
  tokens,
43939
- persistTokens,
43940
- onAuthInvalid,
43941
44249
  e2ee,
43942
44250
  identifyReportedPaths,
43943
- bridgeHeartbeat
44251
+ onBridgeSocketOpen
43944
44252
  } = params;
43945
- let authRefreshInFlight = false;
43946
- function handleOpen() {
44253
+ return () => {
43947
44254
  recordBridgeSessionOpened(state.duplicateBridgeFlap, Date.now());
43948
44255
  const logOpenAsPostRefreshReconnect = state.logBridgeOpenAsReconnect;
43949
44256
  clearMainBridgeReconnectQuietOnOpen(state, logFn);
@@ -43963,6 +44270,10 @@ function createMainBridgeWebSocketLifecycle(params) {
43963
44270
  ...e2ee ? { e: e2ee.handshake } : {}
43964
44271
  });
43965
44272
  reportGitRepos(getWs, logFn);
44273
+ try {
44274
+ onBridgeSocketOpen?.();
44275
+ } catch {
44276
+ }
43966
44277
  }
43967
44278
  if (justAuthenticated && socket) {
43968
44279
  logFn(
@@ -43971,41 +44282,25 @@ function createMainBridgeWebSocketLifecycle(params) {
43971
44282
  logFn(` export BUILDAUTOMATON_AUTH_TOKEN="${tokens.accessToken}"`);
43972
44283
  logFn(` export BUILDAUTOMATON_WORKSPACE_ID="${workspaceId}"`);
43973
44284
  }
43974
- }
43975
- function handleClose(code, reason) {
43976
- bridgeHeartbeat?.stop();
43977
- try {
43978
- const was = state.currentWs;
43979
- state.currentWs = null;
43980
- if (was) was.removeAllListeners();
43981
- const willReconnect = !state.closedByUser;
43982
- if (willReconnect) {
43983
- const duplicateResult = evaluateDuplicateBridgeDisconnect(
43984
- state.duplicateBridgeFlap,
43985
- Date.now(),
43986
- code,
43987
- reason
43988
- );
43989
- logDuplicateBridgeWarning(logFn, duplicateResult);
43990
- }
43991
- beginMainBridgeDeferredDisconnect(state, code, reason, logFn, willReconnect);
43992
- if (willReconnect) {
43993
- state.lastReconnectCloseMeta = { code, reason };
43994
- try {
43995
- scheduleMainBridgeReconnect(state, connect, logFn, { code, reason });
43996
- } catch {
43997
- }
43998
- }
43999
- } catch {
44000
- if (!state.closedByUser) {
44001
- try {
44002
- scheduleMainBridgeReconnect(state, connect, logFn);
44003
- } catch {
44004
- }
44005
- }
44006
- }
44007
- }
44008
- function connect() {
44285
+ };
44286
+ }
44287
+
44288
+ // src/connection/main-bridge-ws-lifecycle.ts
44289
+ function createMainBridgeWebSocketLifecycle(params) {
44290
+ const {
44291
+ state,
44292
+ apiUrl,
44293
+ workspaceId,
44294
+ logFn,
44295
+ messageDeps,
44296
+ tokens,
44297
+ bridgeHeartbeat
44298
+ } = params;
44299
+ let connect;
44300
+ const handleOpen = createMainBridgeOpenHandler(params);
44301
+ const handleClose = createMainBridgeCloseHandler(params, () => connect());
44302
+ const handleAuthInvalid = createMainBridgeAuthRefreshHandler(params, () => connect());
44303
+ connect = () => {
44009
44304
  if (state.closedByUser) return;
44010
44305
  if (state.reconnectTimeout != null) {
44011
44306
  clearTimeout(state.reconnectTimeout);
@@ -44041,48 +44336,7 @@ function createMainBridgeWebSocketLifecycle(params) {
44041
44336
  onCompactHeartbeatAck: (seq) => {
44042
44337
  messageDeps.onBridgeHeartbeatAck?.(seq);
44043
44338
  },
44044
- onAuthInvalid: () => {
44045
- if (authRefreshInFlight) return;
44046
- void (async () => {
44047
- authRefreshInFlight = true;
44048
- try {
44049
- if (tokens.refreshToken) {
44050
- const next = await refreshBridgeTokens({
44051
- apiUrl,
44052
- workspaceId,
44053
- refreshToken: tokens.refreshToken
44054
- });
44055
- if (next?.token && next.refreshToken) {
44056
- tokens.accessToken = next.token;
44057
- tokens.refreshToken = next.refreshToken;
44058
- persistTokens?.({ token: tokens.accessToken, refreshToken: tokens.refreshToken });
44059
- try {
44060
- logFn("[Bridge service] Access token refreshed; reconnecting\u2026");
44061
- } catch {
44062
- }
44063
- state.reconnectAttempt = 0;
44064
- resetReconnectOutageTracker(state.mainOutage);
44065
- state.lastReconnectCloseMeta = null;
44066
- state.logBridgeOpenAsReconnect = true;
44067
- authRefreshInFlight = false;
44068
- connect();
44069
- return;
44070
- }
44071
- }
44072
- authRefreshInFlight = false;
44073
- state.reconnectAttempt = 0;
44074
- resetReconnectOutageTracker(state.mainOutage);
44075
- state.lastReconnectCloseMeta = null;
44076
- onAuthInvalid();
44077
- } catch {
44078
- authRefreshInFlight = false;
44079
- state.reconnectAttempt = 0;
44080
- resetReconnectOutageTracker(state.mainOutage);
44081
- state.lastReconnectCloseMeta = null;
44082
- onAuthInvalid();
44083
- }
44084
- })();
44085
- },
44339
+ onAuthInvalid: handleAuthInvalid,
44086
44340
  onOpen: handleOpen,
44087
44341
  onClose: handleClose,
44088
44342
  onError: (err) => {
@@ -44109,7 +44363,7 @@ function createMainBridgeWebSocketLifecycle(params) {
44109
44363
  }
44110
44364
  }
44111
44365
  }
44112
- }
44366
+ };
44113
44367
  return { connect };
44114
44368
  }
44115
44369
 
@@ -44278,256 +44532,6 @@ function createBridgeHeartbeatController(params) {
44278
44532
  };
44279
44533
  }
44280
44534
 
44281
- // src/sqlite/hash-json-sha256.ts
44282
- import { createHash } from "node:crypto";
44283
- function hashJsonUtf8Sha256(value) {
44284
- return createHash("sha256").update(JSON.stringify(value), "utf8").digest("hex");
44285
- }
44286
-
44287
- // src/sqlite/agent-capability-cache.ts
44288
- function hasNonEmptyAgentCapabilityCache(db, workspaceId, agentType) {
44289
- const t = agentType.trim();
44290
- if (!t) return false;
44291
- try {
44292
- const row = db.get(
44293
- `SELECT config_options_json FROM agent_capabilities WHERE workspace_id = ? AND agent_type = ?`,
44294
- [workspaceId, t]
44295
- );
44296
- if (row?.config_options_json == null || row.config_options_json === "") return false;
44297
- const parsed = JSON.parse(row.config_options_json);
44298
- return Array.isArray(parsed) && parsed.length > 0;
44299
- } catch {
44300
- return false;
44301
- }
44302
- }
44303
- function upsertCliAgentCapabilityCache(db, row) {
44304
- const t = row.agentType.trim();
44305
- if (!t) return false;
44306
- const hash = hashJsonUtf8Sha256(row.configOptions);
44307
- try {
44308
- const prev = db.get(
44309
- `SELECT content_hash FROM agent_capabilities WHERE workspace_id = ? AND agent_type = ?`,
44310
- [row.workspaceId, t]
44311
- );
44312
- if (prev?.content_hash === hash) return false;
44313
- } catch {
44314
- }
44315
- const json2 = JSON.stringify(row.configOptions);
44316
- const now = (/* @__PURE__ */ new Date()).toISOString();
44317
- db.run(
44318
- `INSERT INTO agent_capabilities (workspace_id, agent_type, config_options_json, content_hash, updated_at)
44319
- VALUES (?, ?, ?, ?, ?)
44320
- ON CONFLICT(workspace_id, agent_type) DO UPDATE SET
44321
- config_options_json = excluded.config_options_json,
44322
- content_hash = excluded.content_hash,
44323
- updated_at = excluded.updated_at`,
44324
- [row.workspaceId, t, json2, hash, now]
44325
- );
44326
- return true;
44327
- }
44328
- function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
44329
- const rows = db.all(
44330
- `SELECT agent_type, config_options_json FROM agent_capabilities WHERE workspace_id = ?`,
44331
- [workspaceId]
44332
- );
44333
- const out = [];
44334
- for (const r of rows) {
44335
- try {
44336
- const parsed = JSON.parse(r.config_options_json);
44337
- if (!Array.isArray(parsed) || parsed.length === 0) continue;
44338
- out.push({ agentType: r.agent_type, configOptions: parsed });
44339
- } catch {
44340
- }
44341
- }
44342
- return out;
44343
- }
44344
-
44345
- // src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
44346
- import * as path69 from "node:path";
44347
-
44348
- // src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
44349
- import * as path68 from "node:path";
44350
- async function probeOneAgentTypeForCapabilities(params) {
44351
- const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true, shouldContinue } = params;
44352
- const canContinue = () => shouldContinue?.() !== false;
44353
- if (!canContinue()) return false;
44354
- const resolved = resolveAgentCommand(agentType);
44355
- if (!resolved) return false;
44356
- let sqliteChanged = false;
44357
- const reportedRef = { done: false };
44358
- const tryReport = (co) => {
44359
- if (reportedRef.done) return;
44360
- if (!Array.isArray(co) || co.length === 0) return;
44361
- reportedRef.done = true;
44362
- let changed = false;
44363
- try {
44364
- changed = withCliSqliteSync(
44365
- (db) => upsertCliAgentCapabilityCache(db, {
44366
- workspaceId,
44367
- agentType,
44368
- configOptions: co
44369
- })
44370
- );
44371
- } catch {
44372
- }
44373
- sqliteChanged ||= changed;
44374
- if (bridgeReport && changed) {
44375
- reportAgentCapabilities?.({ agentType, configOptions: co });
44376
- }
44377
- };
44378
- let handle = null;
44379
- const killTimer = setTimeout(() => {
44380
- void handle?.disconnectGracefully();
44381
- }, 28e3);
44382
- killTimer.unref?.();
44383
- try {
44384
- if (!canContinue()) return false;
44385
- handle = await resolved.createClient({
44386
- command: resolved.command,
44387
- cwd: path68.resolve(cwd),
44388
- backendAgentType: agentType,
44389
- sessionMode: "agent",
44390
- persistedAcpSessionId: null,
44391
- agentConfig: null,
44392
- getActiveConfigOptions: () => null,
44393
- onAcpSessionEstablished: (info) => {
44394
- tryReport(info.configOptions ?? null);
44395
- },
44396
- onAcpConfigOptionsUpdated: (co) => {
44397
- tryReport(co);
44398
- },
44399
- onAgentSubprocessExit: () => {
44400
- },
44401
- onSessionUpdate: () => {
44402
- }
44403
- });
44404
- if (!await delayMsUnlessShutdownRequested(1200) || !canContinue()) return false;
44405
- } catch (e) {
44406
- log2(
44407
- `[Bridge service] Agent capability probe (${agentType}): ${e instanceof Error ? e.message : String(e)}`
44408
- );
44409
- } finally {
44410
- clearTimeout(killTimer);
44411
- try {
44412
- await handle?.disconnectGracefully();
44413
- } catch {
44414
- }
44415
- }
44416
- return sqliteChanged;
44417
- }
44418
-
44419
- // src/agents/capabilities/probe-agent-capabilities-for-types.ts
44420
- async function probeAgentCapabilitiesForDetectedTypes(params) {
44421
- const {
44422
- agentTypes,
44423
- cwd,
44424
- workspaceId,
44425
- log: log2,
44426
- reportAgentCapabilities,
44427
- bridgeReport = true,
44428
- forceAllTypes = false,
44429
- shouldContinue
44430
- } = params;
44431
- const canContinue = () => !isCliImmediateShutdownRequested() && shouldContinue?.() !== false;
44432
- let changedCount = 0;
44433
- for (let i = 0; i < agentTypes.length; i++) {
44434
- if (!canContinue()) return changedCount;
44435
- if (i > 0) await yieldToEventLoop();
44436
- const agentType = agentTypes[i];
44437
- if (!agentType.trim()) continue;
44438
- if (!forceAllTypes) {
44439
- try {
44440
- if (process.env.BUILDAUTOMATON_FORCE_PROBE_ACP_CAPABILITIES !== "1" && await withCliSqlite((db) => hasNonEmptyAgentCapabilityCache(db, workspaceId, agentType))) {
44441
- continue;
44442
- }
44443
- } catch {
44444
- }
44445
- }
44446
- const changed = await probeOneAgentTypeForCapabilities({
44447
- agentType,
44448
- cwd,
44449
- workspaceId,
44450
- log: log2,
44451
- reportAgentCapabilities,
44452
- bridgeReport,
44453
- shouldContinue: canContinue
44454
- });
44455
- if (changed) changedCount += 1;
44456
- }
44457
- return changedCount;
44458
- }
44459
-
44460
- // src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
44461
- async function warmupAgentCapabilitiesOnConnect(params) {
44462
- const { workspaceId, log: log2, getWs } = params;
44463
- const isCurrent = beginAgentCapabilityWarmupRun();
44464
- if (!isCurrent()) return;
44465
- const cwd = path69.resolve(getBridgeRoot());
44466
- async function sendBatchFromCache() {
44467
- if (!isCurrent()) return;
44468
- const socket = getWs();
44469
- if (!socket || socket.readyState !== wrapper_default.OPEN) return;
44470
- try {
44471
- const rows = await withCliSqlite((db) => listCliAgentCapabilityCacheForWorkspace(db, workspaceId));
44472
- if (!isCurrent()) return;
44473
- if (rows.length === 0) return;
44474
- sendWsMessage(socket, {
44475
- type: "agent_capabilities_batch",
44476
- items: rows.map((r) => ({ agentType: r.agentType, configOptions: r.configOptions }))
44477
- });
44478
- } catch (e) {
44479
- if (e instanceof CliSqliteInterrupted) return;
44480
- log2(
44481
- `[Bridge service] Agent capability batch to bridge failed: ${e instanceof Error ? e.message : String(e)}`
44482
- );
44483
- }
44484
- }
44485
- await sendBatchFromCache();
44486
- if (!isCurrent()) return;
44487
- let types = [];
44488
- try {
44489
- types = [...await detectLocalAgentTypes()];
44490
- } catch (e) {
44491
- log2(`[Bridge service] detectLocalAgentTypes failed: ${e instanceof Error ? e.message : String(e)}`);
44492
- }
44493
- if (!isCurrent()) return;
44494
- try {
44495
- const n = await probeAgentCapabilitiesForDetectedTypes({
44496
- agentTypes: types,
44497
- cwd,
44498
- workspaceId,
44499
- log: log2,
44500
- bridgeReport: false,
44501
- forceAllTypes: false,
44502
- shouldContinue: isCurrent
44503
- });
44504
- if (n > 0) await sendBatchFromCache();
44505
- } catch (e) {
44506
- if (e instanceof CliSqliteInterrupted) return;
44507
- log2(`[Bridge service] Agent capability probe (missing cache) failed: ${e instanceof Error ? e.message : String(e)}`);
44508
- }
44509
- if (!isCurrent()) return;
44510
- void (async () => {
44511
- try {
44512
- await yieldToEventLoop();
44513
- if (!isCurrent()) return;
44514
- const n = await probeAgentCapabilitiesForDetectedTypes({
44515
- agentTypes: types,
44516
- cwd,
44517
- workspaceId,
44518
- log: log2,
44519
- bridgeReport: false,
44520
- forceAllTypes: true,
44521
- shouldContinue: isCurrent
44522
- });
44523
- if (n > 0) await sendBatchFromCache();
44524
- } catch (e) {
44525
- if (e instanceof CliSqliteInterrupted) return;
44526
- log2(`[Bridge service] Agent capability lazy refresh failed: ${e instanceof Error ? e.message : String(e)}`);
44527
- }
44528
- })();
44529
- }
44530
-
44531
44535
  // src/mcp/tools/session-history/fork/mcp-text-result.ts
44532
44536
  function mcpTextResult(text, isError = false) {
44533
44537
  return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
@@ -44912,6 +44916,327 @@ async function createBridgeAccessState(options = {}) {
44912
44916
  };
44913
44917
  }
44914
44918
 
44919
+ // src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
44920
+ import * as path71 from "node:path";
44921
+
44922
+ // src/sqlite/hash-json-sha256.ts
44923
+ import { createHash } from "node:crypto";
44924
+ function hashJsonUtf8Sha256(value) {
44925
+ return createHash("sha256").update(JSON.stringify(value), "utf8").digest("hex");
44926
+ }
44927
+
44928
+ // src/sqlite/agent-capability-cache.ts
44929
+ function hasNonEmptyAgentCapabilityCache(db, workspaceId, agentType) {
44930
+ const t = agentType.trim();
44931
+ if (!t) return false;
44932
+ try {
44933
+ const row = db.get(
44934
+ `SELECT config_options_json FROM agent_capabilities WHERE workspace_id = ? AND agent_type = ?`,
44935
+ [workspaceId, t]
44936
+ );
44937
+ if (row?.config_options_json == null || row.config_options_json === "") return false;
44938
+ const parsed = JSON.parse(row.config_options_json);
44939
+ return Array.isArray(parsed) && parsed.length > 0;
44940
+ } catch {
44941
+ return false;
44942
+ }
44943
+ }
44944
+ function upsertCliAgentCapabilityCache(db, row) {
44945
+ const t = row.agentType.trim();
44946
+ if (!t) return false;
44947
+ const hash = hashJsonUtf8Sha256(row.configOptions);
44948
+ try {
44949
+ const prev = db.get(
44950
+ `SELECT content_hash FROM agent_capabilities WHERE workspace_id = ? AND agent_type = ?`,
44951
+ [row.workspaceId, t]
44952
+ );
44953
+ if (prev?.content_hash === hash) return false;
44954
+ } catch {
44955
+ }
44956
+ const json2 = JSON.stringify(row.configOptions);
44957
+ const now = (/* @__PURE__ */ new Date()).toISOString();
44958
+ db.run(
44959
+ `INSERT INTO agent_capabilities (workspace_id, agent_type, config_options_json, content_hash, updated_at)
44960
+ VALUES (?, ?, ?, ?, ?)
44961
+ ON CONFLICT(workspace_id, agent_type) DO UPDATE SET
44962
+ config_options_json = excluded.config_options_json,
44963
+ content_hash = excluded.content_hash,
44964
+ updated_at = excluded.updated_at`,
44965
+ [row.workspaceId, t, json2, hash, now]
44966
+ );
44967
+ return true;
44968
+ }
44969
+ function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
44970
+ const rows = db.all(
44971
+ `SELECT agent_type, config_options_json FROM agent_capabilities WHERE workspace_id = ?`,
44972
+ [workspaceId]
44973
+ );
44974
+ const out = [];
44975
+ for (const r of rows) {
44976
+ try {
44977
+ const parsed = JSON.parse(r.config_options_json);
44978
+ if (!Array.isArray(parsed) || parsed.length === 0) continue;
44979
+ out.push({ agentType: r.agent_type, configOptions: parsed });
44980
+ } catch {
44981
+ }
44982
+ }
44983
+ return out;
44984
+ }
44985
+
44986
+ // src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
44987
+ import * as path70 from "node:path";
44988
+ async function probeOneAgentTypeForCapabilities(params) {
44989
+ const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true, shouldContinue } = params;
44990
+ const canContinue = () => shouldContinue?.() !== false;
44991
+ if (!canContinue()) return false;
44992
+ const resolved = resolveAgentCommand(agentType);
44993
+ if (!resolved) return false;
44994
+ let sqliteChanged = false;
44995
+ const reportedRef = { done: false };
44996
+ const tryReport = (co) => {
44997
+ if (reportedRef.done) return;
44998
+ if (!Array.isArray(co) || co.length === 0) return;
44999
+ reportedRef.done = true;
45000
+ let changed = false;
45001
+ try {
45002
+ changed = withCliSqliteSync(
45003
+ (db) => upsertCliAgentCapabilityCache(db, {
45004
+ workspaceId,
45005
+ agentType,
45006
+ configOptions: co
45007
+ })
45008
+ );
45009
+ } catch {
45010
+ }
45011
+ sqliteChanged ||= changed;
45012
+ if (bridgeReport && changed) {
45013
+ reportAgentCapabilities?.({ agentType, configOptions: co });
45014
+ }
45015
+ };
45016
+ let handle = null;
45017
+ const killTimer = setTimeout(() => {
45018
+ void handle?.disconnectGracefully();
45019
+ }, 28e3);
45020
+ killTimer.unref?.();
45021
+ try {
45022
+ if (!canContinue()) return false;
45023
+ handle = await resolved.createClient({
45024
+ command: resolved.command,
45025
+ cwd: path70.resolve(cwd),
45026
+ backendAgentType: agentType,
45027
+ sessionMode: "agent",
45028
+ persistedAcpSessionId: null,
45029
+ agentConfig: null,
45030
+ getActiveConfigOptions: () => null,
45031
+ onAcpSessionEstablished: (info) => {
45032
+ tryReport(info.configOptions ?? null);
45033
+ },
45034
+ onAcpConfigOptionsUpdated: (co) => {
45035
+ tryReport(co);
45036
+ },
45037
+ onAgentSubprocessExit: () => {
45038
+ },
45039
+ onSessionUpdate: () => {
45040
+ }
45041
+ });
45042
+ if (!await delayMsUnlessShutdownRequested(1200) || !canContinue()) return false;
45043
+ } catch (e) {
45044
+ log2(
45045
+ `[Bridge service] Agent capability probe (${agentType}): ${e instanceof Error ? e.message : String(e)}`
45046
+ );
45047
+ } finally {
45048
+ clearTimeout(killTimer);
45049
+ try {
45050
+ await handle?.disconnectGracefully();
45051
+ } catch {
45052
+ }
45053
+ }
45054
+ return sqliteChanged;
45055
+ }
45056
+
45057
+ // src/agents/capabilities/probe-agent-capabilities-for-types.ts
45058
+ async function probeAgentCapabilitiesForDetectedTypes(params) {
45059
+ const {
45060
+ agentTypes,
45061
+ cwd,
45062
+ workspaceId,
45063
+ log: log2,
45064
+ reportAgentCapabilities,
45065
+ bridgeReport = true,
45066
+ forceAllTypes = false,
45067
+ shouldContinue
45068
+ } = params;
45069
+ const canContinue = () => !isCliImmediateShutdownRequested() && shouldContinue?.() !== false;
45070
+ let changedCount = 0;
45071
+ for (let i = 0; i < agentTypes.length; i++) {
45072
+ if (!canContinue()) return changedCount;
45073
+ if (i > 0) await yieldToEventLoop();
45074
+ const agentType = agentTypes[i];
45075
+ if (!agentType.trim()) continue;
45076
+ if (!forceAllTypes) {
45077
+ try {
45078
+ if (process.env.BUILDAUTOMATON_FORCE_PROBE_ACP_CAPABILITIES !== "1" && await withCliSqlite((db) => hasNonEmptyAgentCapabilityCache(db, workspaceId, agentType))) {
45079
+ continue;
45080
+ }
45081
+ } catch {
45082
+ }
45083
+ }
45084
+ const changed = await probeOneAgentTypeForCapabilities({
45085
+ agentType,
45086
+ cwd,
45087
+ workspaceId,
45088
+ log: log2,
45089
+ reportAgentCapabilities,
45090
+ bridgeReport,
45091
+ shouldContinue: canContinue
45092
+ });
45093
+ if (changed) changedCount += 1;
45094
+ }
45095
+ return changedCount;
45096
+ }
45097
+
45098
+ // src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
45099
+ async function warmupAgentCapabilitiesOnConnect(params) {
45100
+ const { workspaceId, log: log2, getWs } = params;
45101
+ const isCurrent = beginAgentCapabilityWarmupRun();
45102
+ if (!isCurrent()) return;
45103
+ const cwd = path71.resolve(getBridgeRoot());
45104
+ async function sendBatchFromCache() {
45105
+ if (!isCurrent()) return;
45106
+ const socket = getWs();
45107
+ if (!socket || socket.readyState !== wrapper_default.OPEN) return;
45108
+ try {
45109
+ const rows = await withCliSqlite((db) => listCliAgentCapabilityCacheForWorkspace(db, workspaceId));
45110
+ if (!isCurrent()) return;
45111
+ if (rows.length === 0) return;
45112
+ sendWsMessage(socket, {
45113
+ type: "agent_capabilities_batch",
45114
+ items: rows.map((r) => ({ agentType: r.agentType, configOptions: r.configOptions }))
45115
+ });
45116
+ } catch (e) {
45117
+ if (e instanceof CliSqliteInterrupted) return;
45118
+ log2(
45119
+ `[Bridge service] Agent capability batch to bridge failed: ${e instanceof Error ? e.message : String(e)}`
45120
+ );
45121
+ }
45122
+ }
45123
+ await sendBatchFromCache();
45124
+ if (!isCurrent()) return;
45125
+ let types = [];
45126
+ try {
45127
+ types = [...await detectLocalAgentTypes()];
45128
+ } catch (e) {
45129
+ log2(`[Bridge service] detectLocalAgentTypes failed: ${e instanceof Error ? e.message : String(e)}`);
45130
+ }
45131
+ if (!isCurrent()) return;
45132
+ try {
45133
+ const n = await probeAgentCapabilitiesForDetectedTypes({
45134
+ agentTypes: types,
45135
+ cwd,
45136
+ workspaceId,
45137
+ log: log2,
45138
+ bridgeReport: false,
45139
+ forceAllTypes: false,
45140
+ shouldContinue: isCurrent
45141
+ });
45142
+ if (n > 0) await sendBatchFromCache();
45143
+ } catch (e) {
45144
+ if (e instanceof CliSqliteInterrupted) return;
45145
+ log2(`[Bridge service] Agent capability probe (missing cache) failed: ${e instanceof Error ? e.message : String(e)}`);
45146
+ }
45147
+ if (!isCurrent()) return;
45148
+ void (async () => {
45149
+ try {
45150
+ await yieldToEventLoop();
45151
+ if (!isCurrent()) return;
45152
+ const n = await probeAgentCapabilitiesForDetectedTypes({
45153
+ agentTypes: types,
45154
+ cwd,
45155
+ workspaceId,
45156
+ log: log2,
45157
+ bridgeReport: false,
45158
+ forceAllTypes: true,
45159
+ shouldContinue: isCurrent
45160
+ });
45161
+ if (n > 0) await sendBatchFromCache();
45162
+ } catch (e) {
45163
+ if (e instanceof CliSqliteInterrupted) return;
45164
+ log2(`[Bridge service] Agent capability lazy refresh failed: ${e instanceof Error ? e.message : String(e)}`);
45165
+ }
45166
+ })();
45167
+ }
45168
+
45169
+ // src/connection/create-bridge-agent-capabilities-reporter.ts
45170
+ function createAgentCapabilitiesReporter(params) {
45171
+ const { workspaceId, getWs } = params;
45172
+ return (info) => {
45173
+ if (!Array.isArray(info.configOptions) || info.configOptions.length === 0) return;
45174
+ setImmediate(() => {
45175
+ let changed = false;
45176
+ try {
45177
+ changed = withCliSqliteSync(
45178
+ (db) => upsertCliAgentCapabilityCache(db, {
45179
+ workspaceId,
45180
+ agentType: info.agentType,
45181
+ configOptions: info.configOptions
45182
+ })
45183
+ );
45184
+ } catch (e) {
45185
+ if (e instanceof CliSqliteInterrupted) return;
45186
+ }
45187
+ if (!changed) return;
45188
+ const socket = getWs();
45189
+ if (!socket || socket.readyState !== wrapper_default.OPEN) return;
45190
+ sendWsMessage(socket, {
45191
+ type: "agent_capabilities",
45192
+ agentType: info.agentType,
45193
+ configOptions: info.configOptions
45194
+ });
45195
+ });
45196
+ };
45197
+ }
45198
+ function createWarmupAgentCapabilitiesOnConnect(params) {
45199
+ return async () => {
45200
+ await warmupAgentCapabilitiesOnConnect(params);
45201
+ };
45202
+ }
45203
+
45204
+ // src/connection/create-bridge-message-deps.ts
45205
+ function createBridgeMessageDeps(params) {
45206
+ const {
45207
+ getWs,
45208
+ log: log2,
45209
+ acpManager,
45210
+ sessionWorktreeManager,
45211
+ onBridgeIdentified,
45212
+ bridgeHeartbeat,
45213
+ sendLocalSkillsReport,
45214
+ reportAutoDetectedAgents,
45215
+ warmupAgentCapabilitiesOnConnect: warmupAgentCapabilitiesOnConnect2,
45216
+ devServerManager,
45217
+ e2ee,
45218
+ cloudApiBaseUrl,
45219
+ getCloudAccessToken
45220
+ } = params;
45221
+ return {
45222
+ getWs,
45223
+ log: log2,
45224
+ acpManager,
45225
+ sessionWorktreeManager,
45226
+ onBridgeIdentified,
45227
+ onBridgeHeartbeatAck: (seq) => {
45228
+ bridgeHeartbeat.onAck(seq);
45229
+ },
45230
+ sendLocalSkillsReport,
45231
+ reportAutoDetectedAgents,
45232
+ warmupAgentCapabilitiesOnConnect: warmupAgentCapabilitiesOnConnect2,
45233
+ devServerManager,
45234
+ e2ee,
45235
+ cloudApiBaseUrl,
45236
+ getCloudAccessToken
45237
+ };
45238
+ }
45239
+
44915
45240
  // src/connection/create-bridge-connection.ts
44916
45241
  async function createBridgeConnection(options) {
44917
45242
  const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
@@ -44945,48 +45270,36 @@ async function createBridgeConnection(options) {
44945
45270
  function getWs() {
44946
45271
  return state.currentWs;
44947
45272
  }
44948
- function sendAgentCapabilitiesToBridge(info) {
44949
- if (!Array.isArray(info.configOptions) || info.configOptions.length === 0) return;
44950
- setImmediate(() => {
44951
- let changed = false;
44952
- try {
44953
- changed = withCliSqliteSync(
44954
- (db) => upsertCliAgentCapabilityCache(db, {
44955
- workspaceId,
44956
- agentType: info.agentType,
44957
- configOptions: info.configOptions
44958
- })
44959
- );
44960
- } catch (e) {
44961
- if (e instanceof CliSqliteInterrupted) return;
44962
- }
44963
- if (!changed) return;
44964
- const socket = getWs();
44965
- if (!socket || socket.readyState !== wrapper_default.OPEN) return;
44966
- sendWsMessage(socket, {
44967
- type: "agent_capabilities",
44968
- agentType: info.agentType,
44969
- configOptions: info.configOptions
44970
- });
44971
- });
44972
- }
45273
+ const sendAgentCapabilitiesToBridge = createAgentCapabilitiesReporter({ workspaceId, getWs });
44973
45274
  const worktreesRootPath = options.worktreesRootPath ?? defaultWorktreesRootPath();
44974
45275
  const sessionWorktreeManager = new SessionWorktreeManager({
44975
45276
  worktreesRootPath,
44976
45277
  log: logFn
44977
45278
  });
44978
45279
  const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
44979
- const bridgeAccess = await createBridgeAccessState({
45280
+ const bridgeAccessRef = {
45281
+ current: null
45282
+ };
45283
+ const bridgeAccessPromise = createBridgeAccessState({
44980
45284
  cloudApiBaseUrl: apiUrl,
44981
45285
  getCloudAccessToken: () => tokens.accessToken,
44982
45286
  e2ee
45287
+ }).then((bridgeAccess2) => {
45288
+ bridgeAccessRef.current = bridgeAccess2;
45289
+ return bridgeAccess2;
44983
45290
  });
44984
45291
  const acpManager = await createAcpManager({
44985
45292
  log: logFn,
44986
- getBridgeAccessPort: () => bridgeAccess.getPort(),
45293
+ getBridgeAccessPort: () => bridgeAccessRef.current?.getPort() ?? 0,
44987
45294
  reportAgentCapabilities: sendAgentCapabilitiesToBridge
44988
45295
  });
44989
45296
  logFn("CLI running. Press Ctrl+C to exit.");
45297
+ let initialIndexBuildsScheduled = false;
45298
+ const scheduleInitialIndexBuildsOnce = () => {
45299
+ if (initialIndexBuildsScheduled) return;
45300
+ initialIndexBuildsScheduled = true;
45301
+ scheduleInitialIndexBuilds(getBridgeRoot());
45302
+ };
44990
45303
  const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeRoot, e2ee });
44991
45304
  const bridgeHeartbeat = createBridgeHeartbeatController({ getWs, log: logFn });
44992
45305
  const baseOnBridgeIdentified = createOnBridgeIdentified({
@@ -45002,32 +45315,28 @@ async function createBridgeConnection(options) {
45002
45315
  };
45003
45316
  const sendLocalSkillsReport = createSendLocalSkillsReport(getWs, logFn);
45004
45317
  const reportAutoDetectedAgents = createReportAutoDetectedAgents(getWs, logFn);
45005
- const messageDeps = {
45318
+ const messageDeps = createBridgeMessageDeps({
45006
45319
  getWs,
45007
45320
  log: logFn,
45008
45321
  acpManager,
45009
45322
  sessionWorktreeManager,
45010
45323
  onBridgeIdentified,
45011
- onBridgeHeartbeatAck: (seq) => {
45012
- bridgeHeartbeat.onAck(seq);
45013
- },
45324
+ bridgeHeartbeat,
45014
45325
  sendLocalSkillsReport,
45015
45326
  reportAutoDetectedAgents,
45016
- warmupAgentCapabilitiesOnConnect: async () => {
45017
- await warmupAgentCapabilitiesOnConnect({
45018
- workspaceId,
45019
- log: logFn,
45020
- getWs
45021
- });
45022
- },
45327
+ warmupAgentCapabilitiesOnConnect: createWarmupAgentCapabilitiesOnConnect({
45328
+ workspaceId,
45329
+ log: logFn,
45330
+ getWs
45331
+ }),
45023
45332
  devServerManager,
45024
45333
  e2ee,
45025
45334
  cloudApiBaseUrl: apiUrl,
45026
45335
  getCloudAccessToken: () => tokens.accessToken
45027
- };
45336
+ });
45028
45337
  const identifyReportedPaths = {
45029
- bridgeRootPath: path70.resolve(getBridgeRoot()),
45030
- worktreesRootPath: path70.resolve(worktreesRootPath)
45338
+ bridgeRootPath: path72.resolve(getBridgeRoot()),
45339
+ worktreesRootPath: path72.resolve(worktreesRootPath)
45031
45340
  };
45032
45341
  const { connect } = createMainBridgeWebSocketLifecycle({
45033
45342
  state,
@@ -45042,10 +45351,12 @@ async function createBridgeConnection(options) {
45042
45351
  onAuthInvalid,
45043
45352
  e2ee,
45044
45353
  identifyReportedPaths,
45045
- bridgeHeartbeat
45354
+ bridgeHeartbeat,
45355
+ onBridgeSocketOpen: scheduleInitialIndexBuildsOnce
45046
45356
  });
45047
45357
  connect();
45048
45358
  const stopFileIndexWatcher = startFileIndexWatcher(getBridgeRoot());
45359
+ const bridgeAccess = await bridgeAccessPromise;
45049
45360
  return {
45050
45361
  close: async () => {
45051
45362
  requestCliImmediateShutdown();