@buildautomaton/cli 0.1.30 → 0.1.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -25064,7 +25064,7 @@ var {
25064
25064
  } = import_index.default;
25065
25065
 
25066
25066
  // src/cli-version.ts
25067
- var CLI_VERSION = "0.1.30".length > 0 ? "0.1.30" : "0.0.0-dev";
25067
+ var CLI_VERSION = "0.1.32".length > 0 ? "0.1.32" : "0.0.0-dev";
25068
25068
 
25069
25069
  // src/cli/defaults.ts
25070
25070
  var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
@@ -26699,6 +26699,11 @@ function runPendingAuth(options) {
26699
26699
  // src/sqlite/cli-database.ts
26700
26700
  import sqliteWasm from "node-sqlite3-wasm";
26701
26701
 
26702
+ // src/runtime/yield-to-event-loop.ts
26703
+ function yieldToEventLoop() {
26704
+ return new Promise((resolve20) => setImmediate(resolve20));
26705
+ }
26706
+
26702
26707
  // src/sqlite/cli-sqlite-paths.ts
26703
26708
  import fs8 from "node:fs";
26704
26709
  import path5 from "node:path";
@@ -26991,17 +26996,29 @@ function migrateCliSqlite(db) {
26991
26996
 
26992
26997
  // src/sqlite/cli-database.ts
26993
26998
  var { Database: SqliteDatabase } = sqliteWasm;
26994
- var openDatabases = /* @__PURE__ */ new Map();
26995
- var processExitCloseRegistered = false;
26996
- function registerProcessExitSqliteClose() {
26997
- if (processExitCloseRegistered) return;
26998
- processExitCloseRegistered = true;
26999
- process.once("exit", () => {
27000
- for (const db of openDatabases.values()) {
27001
- safeCloseCliSqliteDatabase(db);
27002
- }
27003
- openDatabases.clear();
27004
- });
26999
+ var CLI_SQLITE_SYNC_RETRY_MAX = 40;
27000
+ var CLI_SQLITE_ASYNC_RETRY_MAX = 60;
27001
+ var CLI_SQLITE_ASYNC_BASE_DELAY_MS = 20;
27002
+ function applyCliSqliteConcurrencyPragmas(db) {
27003
+ try {
27004
+ db.exec("PRAGMA journal_mode = WAL");
27005
+ } catch {
27006
+ }
27007
+ try {
27008
+ db.run("PRAGMA synchronous = NORMAL");
27009
+ } catch {
27010
+ }
27011
+ try {
27012
+ db.run("PRAGMA busy_timeout = 8000");
27013
+ } catch {
27014
+ }
27015
+ }
27016
+ function applyCliSqliteMemoryPragmas(db) {
27017
+ try {
27018
+ db.run("PRAGMA cache_size = -8192");
27019
+ db.run("PRAGMA temp_store = FILE");
27020
+ } catch {
27021
+ }
27005
27022
  }
27006
27023
  function safeCloseCliSqliteDatabase(db) {
27007
27024
  if (db == null) return;
@@ -27011,32 +27028,86 @@ function safeCloseCliSqliteDatabase(db) {
27011
27028
  }
27012
27029
  }
27013
27030
  function closeAllCliSqliteConnections() {
27014
- for (const db of openDatabases.values()) {
27015
- safeCloseCliSqliteDatabase(db);
27031
+ }
27032
+ function isCliSqliteLockError(e) {
27033
+ const msg = e instanceof Error ? e.message : String(e);
27034
+ const lower = msg.toLowerCase();
27035
+ return lower.includes("database is locked") || lower.includes("sqlite_busy") || lower.includes("sqlite3_busy") || lower.includes("database") && lower.includes("locked");
27036
+ }
27037
+ function syncSleepMs(ms) {
27038
+ if (ms <= 0) return;
27039
+ try {
27040
+ const sab = new SharedArrayBuffer(4);
27041
+ const ia = new Int32Array(sab);
27042
+ Atomics.wait(ia, 0, 0, Math.min(ms, 1e4));
27043
+ } catch {
27044
+ const end = Date.now() + ms;
27045
+ while (Date.now() < end) {
27046
+ }
27016
27047
  }
27017
- openDatabases.clear();
27018
27048
  }
27019
- function getCliDatabase(options) {
27049
+ function asyncDelayMs(ms) {
27050
+ return new Promise((resolve20) => setTimeout(resolve20, ms));
27051
+ }
27052
+ function openCliSqliteConnection(options) {
27020
27053
  const sqlitePath = getCliSqlitePath();
27021
- const existing = openDatabases.get(sqlitePath);
27022
- if (existing?.isOpen) return existing;
27023
- if (existing && !existing.isOpen) {
27024
- safeCloseCliSqliteDatabase(existing);
27025
- openDatabases.delete(sqlitePath);
27026
- }
27027
27054
  ensureCliSqliteParentDir(sqlitePath);
27028
27055
  const db = new SqliteDatabase(sqlitePath);
27029
27056
  try {
27057
+ applyCliSqliteConcurrencyPragmas(db);
27058
+ applyCliSqliteMemoryPragmas(db);
27030
27059
  migrateCliSqlite(db);
27031
27060
  importCliSqliteLegacyDiskData(db, options?.logLegacyMigration);
27032
27061
  } catch (e) {
27033
27062
  safeCloseCliSqliteDatabase(db);
27034
27063
  throw e;
27035
27064
  }
27036
- openDatabases.set(sqlitePath, db);
27037
- registerProcessExitSqliteClose();
27038
27065
  return db;
27039
27066
  }
27067
+ function withCliSqliteSync(fn, options) {
27068
+ for (let attempt = 1; attempt <= CLI_SQLITE_SYNC_RETRY_MAX; attempt++) {
27069
+ let db;
27070
+ try {
27071
+ db = openCliSqliteConnection(options);
27072
+ try {
27073
+ return fn(db);
27074
+ } finally {
27075
+ safeCloseCliSqliteDatabase(db);
27076
+ }
27077
+ } catch (e) {
27078
+ safeCloseCliSqliteDatabase(db);
27079
+ if (!isCliSqliteLockError(e) || attempt === CLI_SQLITE_SYNC_RETRY_MAX) throw e;
27080
+ syncSleepMs(Math.min(500, 12 * attempt));
27081
+ }
27082
+ }
27083
+ throw new Error("withCliSqliteSync: exhausted retries");
27084
+ }
27085
+ async function withCliSqlite(fn, options) {
27086
+ let lastError;
27087
+ for (let attempt = 1; attempt <= CLI_SQLITE_ASYNC_RETRY_MAX; attempt++) {
27088
+ let db;
27089
+ try {
27090
+ db = openCliSqliteConnection(options);
27091
+ try {
27092
+ return await Promise.resolve(fn(db));
27093
+ } finally {
27094
+ safeCloseCliSqliteDatabase(db);
27095
+ }
27096
+ } catch (e) {
27097
+ lastError = e;
27098
+ safeCloseCliSqliteDatabase(db);
27099
+ if (!isCliSqliteLockError(e) || attempt === CLI_SQLITE_ASYNC_RETRY_MAX) throw e;
27100
+ const delayMs = Math.min(600, CLI_SQLITE_ASYNC_BASE_DELAY_MS * attempt);
27101
+ await asyncDelayMs(delayMs);
27102
+ await yieldToEventLoop();
27103
+ }
27104
+ }
27105
+ if (lastError instanceof Error) throw lastError;
27106
+ throw new Error(String(lastError));
27107
+ }
27108
+ async function ensureCliSqliteInitialized(options) {
27109
+ await withCliSqlite(() => void 0, options);
27110
+ }
27040
27111
 
27041
27112
  // src/connection/close-bridge-connection.ts
27042
27113
  async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
@@ -34670,6 +34741,28 @@ function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send, sessio
34670
34741
  }
34671
34742
  }
34672
34743
 
34744
+ // src/agents/acp/hooks/bridge-on-session-update/send-session-info-title-update.ts
34745
+ function extractSessionInfoTitle(params) {
34746
+ if (!params || typeof params !== "object") return null;
34747
+ const p = params;
34748
+ const title = typeof p.title === "string" ? p.title.trim() : "";
34749
+ return title ? title : null;
34750
+ }
34751
+ function sendSessionInfoTitleUpdate(params) {
34752
+ const title = extractSessionInfoTitle(params.payload);
34753
+ if (!title || !params.runId || !params.send) return;
34754
+ try {
34755
+ params.send({
34756
+ type: "session_title_update",
34757
+ ...params.sessionId ? { sessionId: params.sessionId } : {},
34758
+ runId: params.runId,
34759
+ title
34760
+ });
34761
+ } catch (err) {
34762
+ params.log(`[Bridge service] Session title update send failed: ${errorMessage(err)}`);
34763
+ }
34764
+ }
34765
+
34673
34766
  // src/agents/acp/hooks/bridge-on-session-update/create-bridge-on-session-update.ts
34674
34767
  function createBridgeOnSessionUpdate(opts) {
34675
34768
  const { routing, getSendSessionUpdate, log: log2, sessionParentPath } = opts;
@@ -34685,6 +34778,10 @@ function createBridgeOnSessionUpdate(opts) {
34685
34778
  if (updateKind === "config_option_update") {
34686
34779
  return;
34687
34780
  }
34781
+ if (updateKind === "session_info_update") {
34782
+ sendSessionInfoTitleUpdate({ payload: params, runId, sessionId, send, log: log2 });
34783
+ return;
34784
+ }
34688
34785
  const isCompletedToolCallUpdate = updateKind === "tool_call_update" && isCompletedToolStatus(p.status);
34689
34786
  const toolName = p.toolCall?.name ?? p.tool_call?.name ?? "";
34690
34787
  const isToolUpdate = updateKind === "tool_call" || updateKind === "tool_call_update" || typeof toolName === "string" && toolName.length > 0;
@@ -34778,56 +34875,80 @@ function sessionKeyForCloudSessionId(cloudSessionId) {
34778
34875
  }
34779
34876
  function readLocalAgentSessionFile(cloudSessionId) {
34780
34877
  try {
34781
- const db = getCliDatabase();
34782
- const key = sessionKeyForCloudSessionId(cloudSessionId);
34783
- const row = db.get(
34784
- "SELECT acp_session_id, backend_agent_type, config_options_json, updated_at FROM agent_session WHERE session_key = ?",
34785
- [key]
34786
- );
34787
- if (!row) return null;
34788
- let configOptions = null;
34789
- if (row.config_options_json != null && row.config_options_json !== "") {
34790
- try {
34791
- const parsed = JSON.parse(row.config_options_json);
34792
- configOptions = Array.isArray(parsed) ? parsed : null;
34793
- } catch {
34794
- configOptions = null;
34878
+ return withCliSqliteSync((db) => {
34879
+ const key = sessionKeyForCloudSessionId(cloudSessionId);
34880
+ const row = db.get(
34881
+ "SELECT acp_session_id, backend_agent_type, config_options_json, updated_at FROM agent_session WHERE session_key = ?",
34882
+ [key]
34883
+ );
34884
+ if (!row) return null;
34885
+ let configOptions = null;
34886
+ if (row.config_options_json != null && row.config_options_json !== "") {
34887
+ try {
34888
+ const parsed = JSON.parse(row.config_options_json);
34889
+ configOptions = Array.isArray(parsed) ? parsed : null;
34890
+ } catch {
34891
+ configOptions = null;
34892
+ }
34795
34893
  }
34796
- }
34797
- return {
34798
- v: 1,
34799
- acpSessionId: row.acp_session_id,
34800
- backendAgentType: row.backend_agent_type,
34801
- configOptions,
34802
- updatedAt: row.updated_at
34803
- };
34894
+ return {
34895
+ v: 1,
34896
+ acpSessionId: row.acp_session_id,
34897
+ backendAgentType: row.backend_agent_type,
34898
+ configOptions,
34899
+ updatedAt: row.updated_at
34900
+ };
34901
+ });
34804
34902
  } catch {
34805
34903
  return null;
34806
34904
  }
34807
34905
  }
34808
34906
  function writeLocalAgentSessionFile(cloudSessionId, patch) {
34809
34907
  try {
34810
- const db = getCliDatabase();
34811
- const key = sessionKeyForCloudSessionId(cloudSessionId);
34812
- const prev = readLocalAgentSessionFile(cloudSessionId);
34813
- const next = {
34814
- v: 1,
34815
- acpSessionId: patch.acpSessionId !== void 0 ? patch.acpSessionId : prev?.acpSessionId ?? null,
34816
- backendAgentType: patch.backendAgentType !== void 0 ? patch.backendAgentType : prev?.backendAgentType ?? null,
34817
- configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
34818
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
34819
- };
34820
- const configJson = next.configOptions != null ? JSON.stringify(next.configOptions) : null;
34821
- db.run(
34822
- `INSERT INTO agent_session (session_key, acp_session_id, backend_agent_type, config_options_json, updated_at)
34823
- VALUES (?, ?, ?, ?, ?)
34824
- ON CONFLICT(session_key) DO UPDATE SET
34825
- acp_session_id = excluded.acp_session_id,
34826
- backend_agent_type = excluded.backend_agent_type,
34827
- config_options_json = excluded.config_options_json,
34828
- updated_at = excluded.updated_at`,
34829
- [key, next.acpSessionId, next.backendAgentType, configJson, next.updatedAt]
34830
- );
34908
+ withCliSqliteSync((db) => {
34909
+ const key = sessionKeyForCloudSessionId(cloudSessionId);
34910
+ const prevRow = db.get(
34911
+ "SELECT acp_session_id, backend_agent_type, config_options_json, updated_at FROM agent_session WHERE session_key = ?",
34912
+ [key]
34913
+ );
34914
+ let prev = null;
34915
+ if (prevRow) {
34916
+ let configOptions = null;
34917
+ if (prevRow.config_options_json != null && prevRow.config_options_json !== "") {
34918
+ try {
34919
+ const parsed = JSON.parse(prevRow.config_options_json);
34920
+ configOptions = Array.isArray(parsed) ? parsed : null;
34921
+ } catch {
34922
+ configOptions = null;
34923
+ }
34924
+ }
34925
+ prev = {
34926
+ v: 1,
34927
+ acpSessionId: prevRow.acp_session_id,
34928
+ backendAgentType: prevRow.backend_agent_type,
34929
+ configOptions,
34930
+ updatedAt: prevRow.updated_at
34931
+ };
34932
+ }
34933
+ const next = {
34934
+ v: 1,
34935
+ acpSessionId: patch.acpSessionId !== void 0 ? patch.acpSessionId : prev?.acpSessionId ?? null,
34936
+ backendAgentType: patch.backendAgentType !== void 0 ? patch.backendAgentType : prev?.backendAgentType ?? null,
34937
+ configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
34938
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
34939
+ };
34940
+ const configJson = next.configOptions != null ? JSON.stringify(next.configOptions) : null;
34941
+ db.run(
34942
+ `INSERT INTO agent_session (session_key, acp_session_id, backend_agent_type, config_options_json, updated_at)
34943
+ VALUES (?, ?, ?, ?, ?)
34944
+ ON CONFLICT(session_key) DO UPDATE SET
34945
+ acp_session_id = excluded.acp_session_id,
34946
+ backend_agent_type = excluded.backend_agent_type,
34947
+ config_options_json = excluded.config_options_json,
34948
+ updated_at = excluded.updated_at`,
34949
+ [key, next.acpSessionId, next.backendAgentType, configJson, next.updatedAt]
34950
+ );
34951
+ });
34831
34952
  } catch {
34832
34953
  }
34833
34954
  }
@@ -36410,45 +36531,36 @@ function getCwdHashForFileIndex(resolvedCwd) {
36410
36531
  // src/files/index/build-file-index.ts
36411
36532
  import path29 from "node:path";
36412
36533
 
36413
- // src/runtime/yield-to-event-loop.ts
36414
- function yieldToEventLoop() {
36415
- return new Promise((resolve20) => setImmediate(resolve20));
36416
- }
36417
-
36418
36534
  // src/files/index/walk-workspace-tree.ts
36419
36535
  import fs25 from "node:fs";
36420
36536
  import path28 from "node:path";
36421
- async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
36537
+ function shouldSkipWorkspaceWalkEntry(name) {
36538
+ return name.startsWith(".");
36539
+ }
36540
+ function walkWorkspaceTreeSync(dir, baseDir, onFile) {
36422
36541
  let names;
36423
36542
  try {
36424
- names = await fs25.promises.readdir(dir);
36543
+ names = fs25.readdirSync(dir);
36425
36544
  } catch {
36426
36545
  return;
36427
36546
  }
36428
36547
  for (const name of names) {
36429
- if (name.startsWith(".")) continue;
36430
- if (state.n > 0 && state.n % INDEX_WORK_YIELD_EVERY === 0) {
36431
- await yieldToEventLoop();
36432
- }
36433
- state.n++;
36548
+ if (shouldSkipWorkspaceWalkEntry(name)) continue;
36434
36549
  const full = path28.join(dir, name);
36435
36550
  let stat3;
36436
36551
  try {
36437
- stat3 = await fs25.promises.stat(full);
36552
+ stat3 = fs25.statSync(full);
36438
36553
  } catch {
36439
36554
  continue;
36440
36555
  }
36441
36556
  const relative5 = path28.relative(baseDir, full).replace(/\\/g, "/");
36442
36557
  if (stat3.isDirectory()) {
36443
- await walkWorkspaceTreeAsync(full, baseDir, out, state);
36558
+ walkWorkspaceTreeSync(full, baseDir, onFile);
36444
36559
  } else if (stat3.isFile()) {
36445
- out.push(relative5);
36560
+ onFile(relative5);
36446
36561
  }
36447
36562
  }
36448
36563
  }
36449
- function createWalkYieldState() {
36450
- return { n: 0 };
36451
- }
36452
36564
 
36453
36565
  // src/files/index/file-index-sqlite-lock.ts
36454
36566
  import fs26 from "node:fs";
@@ -36481,80 +36593,98 @@ function withFileIndexSqliteLock(fn) {
36481
36593
  }
36482
36594
 
36483
36595
  // src/files/index/build-file-index.ts
36484
- function sortPaths(paths) {
36485
- paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
36486
- }
36487
- function persistPathsToSqlite(resolved, paths) {
36488
- const db = getCliDatabase();
36489
- const h = getCwdHashForFileIndex(resolved);
36490
- db.run("BEGIN IMMEDIATE");
36491
- try {
36492
- db.run("DELETE FROM file_index_path WHERE cwd_hash = ?", [h]);
36493
- const ins = db.prepare("INSERT INTO file_index_path (cwd_hash, path) VALUES (?, ?)");
36596
+ var FILE_INDEX_INSERT_BUFFER = 2048;
36597
+ function persistFileIndexForResolvedCwd(resolved) {
36598
+ return withCliSqliteSync((db) => {
36599
+ const h = getCwdHashForFileIndex(resolved);
36600
+ const buf = [];
36601
+ let pathCount = 0;
36602
+ db.run("BEGIN IMMEDIATE");
36494
36603
  try {
36495
- for (const rel of paths) {
36496
- ins.run([h, rel]);
36604
+ db.run("DELETE FROM file_index_path WHERE cwd_hash = ?", [h]);
36605
+ const ins = db.prepare("INSERT INTO file_index_path (cwd_hash, path) VALUES (?, ?)");
36606
+ try {
36607
+ const flushBuf = () => {
36608
+ for (const rel of buf) {
36609
+ ins.run([h, rel]);
36610
+ }
36611
+ pathCount += buf.length;
36612
+ buf.length = 0;
36613
+ };
36614
+ walkWorkspaceTreeSync(resolved, resolved, (rel) => {
36615
+ buf.push(rel);
36616
+ if (buf.length >= FILE_INDEX_INSERT_BUFFER) flushBuf();
36617
+ });
36618
+ flushBuf();
36619
+ } finally {
36620
+ ins.finalize();
36497
36621
  }
36498
- } finally {
36499
- ins.finalize();
36500
- }
36501
- db.run("COMMIT");
36502
- } catch (e) {
36503
- try {
36504
- db.run("ROLLBACK");
36505
- } catch {
36622
+ db.run("COMMIT");
36623
+ } catch (e) {
36624
+ try {
36625
+ db.run("ROLLBACK");
36626
+ } catch {
36627
+ }
36628
+ throw e;
36506
36629
  }
36507
- throw e;
36508
- }
36630
+ return pathCount;
36631
+ });
36509
36632
  }
36510
36633
  async function buildFileIndexAsync(cwd) {
36511
36634
  return withFileIndexSqliteLock(async () => {
36512
36635
  const resolved = path29.resolve(cwd);
36513
- const paths = [];
36514
- await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
36515
36636
  await yieldToEventLoop();
36516
- sortPaths(paths);
36517
- persistPathsToSqlite(resolved, paths);
36518
- return { pathCount: paths.length };
36637
+ const pathCount = persistFileIndexForResolvedCwd(resolved);
36638
+ await yieldToEventLoop();
36639
+ return { pathCount };
36519
36640
  });
36520
36641
  }
36521
36642
 
36522
36643
  // src/files/index/ensure-file-index.ts
36523
36644
  import path30 from "node:path";
36524
36645
 
36646
+ // src/files/index/file-index-dependency-path.ts
36647
+ function sqliteExprBridgeFileIndexDependencyRank() {
36648
+ return `CASE WHEN lower(path) = 'node_modules' OR lower(path) LIKE 'node_modules/%' OR lower(path) LIKE '%/node_modules/%' OR lower(path) = 'bower_components' OR lower(path) LIKE 'bower_components/%' OR lower(path) LIKE '%/bower_components/%' THEN 1 ELSE 0 END`;
36649
+ }
36650
+
36525
36651
  // src/files/index/search-file-index.ts
36526
36652
  function escapeLikePattern(fragment) {
36527
36653
  return fragment.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
36528
36654
  }
36529
- function bridgeFileIndexIsPopulated(resolvedCwd) {
36530
- const db = getCliDatabase();
36655
+ function bridgeFileIndexIsPopulatedWithDb(resolvedCwd, db) {
36531
36656
  const h = getCwdHashForFileIndex(resolvedCwd);
36532
36657
  const row = db.get("SELECT 1 as ok FROM file_index_path WHERE cwd_hash = ? LIMIT 1", [h]);
36533
36658
  return row != null;
36534
36659
  }
36535
- function bridgeFileIndexPathCount(resolvedCwd) {
36536
- const db = getCliDatabase();
36660
+ function bridgeFileIndexPathCountWithDb(resolvedCwd, db) {
36537
36661
  const h = getCwdHashForFileIndex(resolvedCwd);
36538
36662
  const row = db.get("SELECT COUNT(*) as c FROM file_index_path WHERE cwd_hash = ?", [h]);
36539
36663
  const c = row?.c ?? 0;
36540
36664
  return Number(c);
36541
36665
  }
36542
- function searchBridgeFilePaths(resolvedCwd, query, limit = 100) {
36666
+ function searchBridgeFilePathsWithDb(resolvedCwd, query, limit, db) {
36543
36667
  const q = query.trim().toLowerCase();
36544
36668
  if (!q) return [];
36545
- const db = getCliDatabase();
36546
36669
  const h = getCwdHashForFileIndex(resolvedCwd);
36547
36670
  const pattern = `%${escapeLikePattern(q)}%`;
36548
36671
  const lim = Math.max(0, Math.min(1e4, Math.floor(limit)));
36672
+ const depRank = sqliteExprBridgeFileIndexDependencyRank();
36549
36673
  const rows = db.all(
36550
- `SELECT path FROM file_index_path WHERE cwd_hash = ? AND lower(path) LIKE ? ESCAPE '\\' LIMIT ?`,
36674
+ `SELECT path FROM file_index_path WHERE cwd_hash = ? AND lower(path) LIKE ? ESCAPE '\\' ORDER BY ${depRank}, path LIMIT ?`,
36551
36675
  [h, pattern, lim]
36552
36676
  );
36553
36677
  return rows.map((r) => String(r.path));
36554
36678
  }
36679
+ async function bridgeFileIndexIsPopulated(resolvedCwd) {
36680
+ return withCliSqlite((db) => bridgeFileIndexIsPopulatedWithDb(resolvedCwd, db));
36681
+ }
36682
+ async function bridgeFileIndexPathCount(resolvedCwd) {
36683
+ return withCliSqlite((db) => bridgeFileIndexPathCountWithDb(resolvedCwd, db));
36684
+ }
36555
36685
  async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
36556
36686
  await yieldToEventLoop();
36557
- const out = searchBridgeFilePaths(resolvedCwd, query, limit);
36687
+ const out = await withCliSqlite((db) => searchBridgeFilePathsWithDb(resolvedCwd, query, limit, db));
36558
36688
  if (out.length >= INDEX_WORK_YIELD_EVERY) await yieldToEventLoop();
36559
36689
  return out;
36560
36690
  }
@@ -36562,8 +36692,8 @@ async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
36562
36692
  // src/files/index/ensure-file-index.ts
36563
36693
  async function ensureFileIndexAsync(cwd) {
36564
36694
  const resolved = path30.resolve(cwd);
36565
- if (bridgeFileIndexIsPopulated(resolved)) {
36566
- return { fromCache: true, pathCount: bridgeFileIndexPathCount(resolved) };
36695
+ if (await bridgeFileIndexIsPopulated(resolved)) {
36696
+ return { fromCache: true, pathCount: await bridgeFileIndexPathCount(resolved) };
36567
36697
  }
36568
36698
  return { ...await buildFileIndexAsync(resolved), fromCache: false };
36569
36699
  }
@@ -36572,7 +36702,6 @@ async function ensureFileIndexAsync(cwd) {
36572
36702
  var DEBOUNCE_MS = 900;
36573
36703
  function shouldIgnoreRelative(rel) {
36574
36704
  const n = rel.replace(/\\/g, "/");
36575
- if (n.includes("/node_modules/") || n.startsWith("node_modules/")) return true;
36576
36705
  if (n.includes("/.git/") || n === ".git" || n.startsWith(".git/")) return true;
36577
36706
  if (n.includes("/.buildautomaton/") || n.startsWith(".buildautomaton/")) return true;
36578
36707
  return false;
@@ -38245,30 +38374,32 @@ var MERGEABLE_SERVER_STATES = /* @__PURE__ */ new Set([
38245
38374
  "stopping",
38246
38375
  "discarded"
38247
38376
  ]);
38248
- function readPersistedQueue(queueKey) {
38249
- const db = getCliDatabase();
38250
- const row = db.get("SELECT queue_key, updated_at, turns_json FROM prompt_queue WHERE queue_key = ?", [
38251
- queueKey
38252
- ]);
38253
- if (!row) return null;
38254
- try {
38255
- const turns = JSON.parse(row.turns_json);
38256
- if (!Array.isArray(turns)) return null;
38257
- return { queueKey: row.queue_key, updatedAt: row.updated_at, turns };
38258
- } catch {
38259
- return null;
38260
- }
38377
+ async function readPersistedQueue(queueKey) {
38378
+ return withCliSqlite((db) => {
38379
+ const row = db.get("SELECT queue_key, updated_at, turns_json FROM prompt_queue WHERE queue_key = ?", [
38380
+ queueKey
38381
+ ]);
38382
+ if (!row) return null;
38383
+ try {
38384
+ const turns = JSON.parse(row.turns_json);
38385
+ if (!Array.isArray(turns)) return null;
38386
+ return { queueKey: row.queue_key, updatedAt: row.updated_at, turns };
38387
+ } catch {
38388
+ return null;
38389
+ }
38390
+ });
38261
38391
  }
38262
- function writePersistedQueue(file2) {
38263
- const db = getCliDatabase();
38264
- db.run(
38265
- `INSERT INTO prompt_queue (queue_key, updated_at, turns_json) VALUES (?, ?, ?)
38266
- ON CONFLICT(queue_key) DO UPDATE SET updated_at = excluded.updated_at, turns_json = excluded.turns_json`,
38267
- [file2.queueKey, file2.updatedAt, JSON.stringify(file2.turns)]
38268
- );
38392
+ async function writePersistedQueue(file2) {
38393
+ await withCliSqlite((db) => {
38394
+ db.run(
38395
+ `INSERT INTO prompt_queue (queue_key, updated_at, turns_json) VALUES (?, ?, ?)
38396
+ ON CONFLICT(queue_key) DO UPDATE SET updated_at = excluded.updated_at, turns_json = excluded.turns_json`,
38397
+ [file2.queueKey, file2.updatedAt, JSON.stringify(file2.turns)]
38398
+ );
38399
+ });
38269
38400
  }
38270
- function mergeServerQueueSnapshot(queueKey, serverTurns) {
38271
- const prev = readPersistedQueue(queueKey);
38401
+ async function mergeServerQueueSnapshot(queueKey, serverTurns) {
38402
+ const prev = await readPersistedQueue(queueKey);
38272
38403
  const turns = [];
38273
38404
  for (const raw of serverTurns) {
38274
38405
  if (!raw || typeof raw !== "object") continue;
@@ -38365,12 +38496,12 @@ async function applyPromptQueueStateFromServer(msg, deps) {
38365
38496
  const getWs = deps.getWs;
38366
38497
  for (const [queueKey, serverTurns] of Object.entries(raw)) {
38367
38498
  if (!Array.isArray(serverTurns)) continue;
38368
- const file2 = mergeServerQueueSnapshot(queueKey, serverTurns);
38369
- writePersistedQueue(file2);
38499
+ const file2 = await mergeServerQueueSnapshot(queueKey, serverTurns);
38500
+ await writePersistedQueue(file2);
38370
38501
  }
38371
38502
  for (const [queueKey, serverTurns] of Object.entries(raw)) {
38372
38503
  if (!Array.isArray(serverTurns)) continue;
38373
- const file2 = readPersistedQueue(queueKey);
38504
+ const file2 = await readPersistedQueue(queueKey);
38374
38505
  if (!file2) continue;
38375
38506
  for (const running of file2.turns.filter((t) => t.lastClientState === "running")) {
38376
38507
  runIdToQueueKey.set(running.turnId, queueKey);
@@ -38378,7 +38509,7 @@ async function applyPromptQueueStateFromServer(msg, deps) {
38378
38509
  }
38379
38510
  for (const [queueKey, serverTurns] of Object.entries(raw)) {
38380
38511
  if (!Array.isArray(serverTurns)) continue;
38381
- const file2 = readPersistedQueue(queueKey);
38512
+ const file2 = await readPersistedQueue(queueKey);
38382
38513
  if (!file2) continue;
38383
38514
  const cancelRow = file2.turns.find((t) => t.serverState === "cancel_requested" && t.lastClientState === "running");
38384
38515
  if (cancelRow) {
@@ -38387,7 +38518,7 @@ async function applyPromptQueueStateFromServer(msg, deps) {
38387
38518
  deps.log(
38388
38519
  `[Queue] server cancel_requested for ${cancelRow.turnId.slice(0, 8)}\u2026 but no local agent run is active (e.g. after CLI restart); marking cancelled and notifying bridge.`
38389
38520
  );
38390
- finalizePromptTurnOnBridge(deps.getWs, cancelRow.turnId, false, { terminalClientState: "cancelled" });
38521
+ await finalizePromptTurnOnBridge(deps.getWs, cancelRow.turnId, false, { terminalClientState: "cancelled" });
38391
38522
  const ws = deps.getWs();
38392
38523
  if (ws && cancelRow.sessionId) {
38393
38524
  sendWsMessage(ws, {
@@ -38406,19 +38537,19 @@ async function applyPromptQueueStateFromServer(msg, deps) {
38406
38537
  const startedThisTick = /* @__PURE__ */ new Set();
38407
38538
  for (const [queueKey, serverTurns] of Object.entries(raw)) {
38408
38539
  if (!Array.isArray(serverTurns)) continue;
38409
- const file2 = readPersistedQueue(queueKey);
38540
+ const file2 = await readPersistedQueue(queueKey);
38410
38541
  if (!file2) continue;
38411
38542
  if (hasRunningTurn(file2.turns)) continue;
38412
38543
  const next = pickNextRunnableTurn(file2.turns);
38413
38544
  if (!next) continue;
38414
38545
  if (!await runLocalRevertBeforeQueuedPrompt(next, deps)) {
38415
38546
  next.lastClientState = "failed";
38416
- writePersistedQueue(file2);
38547
+ await writePersistedQueue(file2);
38417
38548
  sendPromptQueueClientReport(getWs(), { [queueKey]: [{ turnId: next.turnId, clientState: "failed" }] });
38418
38549
  continue;
38419
38550
  }
38420
38551
  next.lastClientState = "running";
38421
- writePersistedQueue(file2);
38552
+ await writePersistedQueue(file2);
38422
38553
  runIdToQueueKey.set(next.turnId, queueKey);
38423
38554
  startedThisTick.add(next.turnId);
38424
38555
  report[queueKey] = [{ turnId: next.turnId, clientState: "running" }];
@@ -38428,7 +38559,7 @@ async function applyPromptQueueStateFromServer(msg, deps) {
38428
38559
  }
38429
38560
  for (const [queueKey, serverTurns] of Object.entries(raw)) {
38430
38561
  if (!Array.isArray(serverTurns)) continue;
38431
- const file2 = readPersistedQueue(queueKey);
38562
+ const file2 = await readPersistedQueue(queueKey);
38432
38563
  if (!file2) continue;
38433
38564
  const running = file2.turns.find((t) => t.lastClientState === "running");
38434
38565
  if (!running || !startedThisTick.has(running.turnId)) continue;
@@ -38436,17 +38567,17 @@ async function applyPromptQueueStateFromServer(msg, deps) {
38436
38567
  dispatchLocalPrompt(running, deps);
38437
38568
  }
38438
38569
  }
38439
- function finalizePromptTurnOnBridge(getWs, runId, success2, opts) {
38570
+ async function finalizePromptTurnOnBridge(getWs, runId, success2, opts) {
38440
38571
  if (!runId) return false;
38441
38572
  const queueKey = runIdToQueueKey.get(runId);
38442
38573
  runIdToQueueKey.delete(runId);
38443
38574
  if (!queueKey) return false;
38444
- const f = readPersistedQueue(queueKey);
38575
+ const f = await readPersistedQueue(queueKey);
38445
38576
  if (!f) return false;
38446
38577
  const t = f.turns.find((x) => x.turnId === runId);
38447
38578
  if (!t) return false;
38448
38579
  t.lastClientState = opts?.terminalClientState ?? (success2 ? "stopped" : "failed");
38449
- writePersistedQueue(f);
38580
+ await writePersistedQueue(f);
38450
38581
  sendPromptQueueClientReport(getWs(), { [queueKey]: [{ turnId: runId, clientState: t.lastClientState }] });
38451
38582
  return true;
38452
38583
  }
@@ -38467,12 +38598,13 @@ function createBridgePromptSenders(deps, getWs) {
38467
38598
  if (result.type === "prompt_result") {
38468
38599
  const pr = result;
38469
38600
  const cancelled = pr.stopReason === "cancelled";
38470
- finalizePromptTurnOnBridge(
38601
+ void finalizePromptTurnOnBridge(
38471
38602
  getWs,
38472
38603
  typeof pr.runId === "string" ? pr.runId : void 0,
38473
38604
  pr.success === true,
38474
38605
  cancelled ? { terminalClientState: "cancelled" } : void 0
38475
- );
38606
+ ).catch(() => {
38607
+ });
38476
38608
  }
38477
38609
  };
38478
38610
  const sendSessionUpdate = (payload) => {
@@ -39205,7 +39337,7 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
39205
39337
  await yieldToEventLoop();
39206
39338
  const q = typeof msg.q === "string" ? msg.q : "";
39207
39339
  const cwd = path37.resolve(getBridgeRoot());
39208
- if (!bridgeFileIndexIsPopulated(cwd)) {
39340
+ if (!await bridgeFileIndexIsPopulated(cwd)) {
39209
39341
  const payload2 = {
39210
39342
  type: "file_browser_search_response",
39211
39343
  id: msg.id,
@@ -39966,7 +40098,7 @@ import * as path40 from "node:path";
39966
40098
  // src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
39967
40099
  import * as path39 from "node:path";
39968
40100
  async function probeOneAgentTypeForCapabilities(params) {
39969
- const { agentType, cwd, workspaceId, log: log2, getDb, reportAgentCapabilities, bridgeReport = true } = params;
40101
+ const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true } = params;
39970
40102
  const resolved = resolveAgentCommand(agentType);
39971
40103
  if (!resolved) return false;
39972
40104
  let sqliteChanged = false;
@@ -39977,11 +40109,13 @@ async function probeOneAgentTypeForCapabilities(params) {
39977
40109
  reportedRef.done = true;
39978
40110
  let changed = false;
39979
40111
  try {
39980
- changed = upsertCliAgentCapabilityCache(getDb(), {
39981
- workspaceId,
39982
- agentType,
39983
- configOptions: co
39984
- });
40112
+ changed = withCliSqliteSync(
40113
+ (db) => upsertCliAgentCapabilityCache(db, {
40114
+ workspaceId,
40115
+ agentType,
40116
+ configOptions: co
40117
+ })
40118
+ );
39985
40119
  } catch {
39986
40120
  }
39987
40121
  sqliteChanged ||= changed;
@@ -40039,7 +40173,6 @@ async function probeAgentCapabilitiesForDetectedTypes(params) {
40039
40173
  cwd,
40040
40174
  workspaceId,
40041
40175
  log: log2,
40042
- getDb,
40043
40176
  reportAgentCapabilities,
40044
40177
  bridgeReport = true,
40045
40178
  forceAllTypes = false
@@ -40051,7 +40184,7 @@ async function probeAgentCapabilitiesForDetectedTypes(params) {
40051
40184
  if (!agentType.trim()) continue;
40052
40185
  if (!forceAllTypes) {
40053
40186
  try {
40054
- if (process.env.BUILDAUTOMATON_FORCE_PROBE_ACP_CAPABILITIES !== "1" && hasNonEmptyAgentCapabilityCache(getDb(), workspaceId, agentType)) {
40187
+ if (process.env.BUILDAUTOMATON_FORCE_PROBE_ACP_CAPABILITIES !== "1" && await withCliSqlite((db) => hasNonEmptyAgentCapabilityCache(db, workspaceId, agentType))) {
40055
40188
  continue;
40056
40189
  }
40057
40190
  } catch {
@@ -40062,7 +40195,6 @@ async function probeAgentCapabilitiesForDetectedTypes(params) {
40062
40195
  cwd,
40063
40196
  workspaceId,
40064
40197
  log: log2,
40065
- getDb,
40066
40198
  reportAgentCapabilities,
40067
40199
  bridgeReport
40068
40200
  });
@@ -40073,14 +40205,13 @@ async function probeAgentCapabilitiesForDetectedTypes(params) {
40073
40205
 
40074
40206
  // src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
40075
40207
  async function warmupAgentCapabilitiesOnConnect(params) {
40076
- const { workspaceId, log: log2, getDb, getWs } = params;
40208
+ const { workspaceId, log: log2, getWs } = params;
40077
40209
  const cwd = path40.resolve(getBridgeRoot());
40078
- const db = getDb();
40079
- function sendBatchFromCache() {
40210
+ async function sendBatchFromCache() {
40080
40211
  const socket = getWs();
40081
40212
  if (!socket || socket.readyState !== wrapper_default.OPEN) return;
40082
40213
  try {
40083
- const rows = listCliAgentCapabilityCacheForWorkspace(db, workspaceId);
40214
+ const rows = await withCliSqlite((db) => listCliAgentCapabilityCacheForWorkspace(db, workspaceId));
40084
40215
  if (rows.length === 0) return;
40085
40216
  sendWsMessage(socket, {
40086
40217
  type: "agent_capabilities_batch",
@@ -40092,7 +40223,7 @@ async function warmupAgentCapabilitiesOnConnect(params) {
40092
40223
  );
40093
40224
  }
40094
40225
  }
40095
- sendBatchFromCache();
40226
+ await sendBatchFromCache();
40096
40227
  let types = [];
40097
40228
  try {
40098
40229
  types = [...await detectLocalAgentTypes()];
@@ -40105,11 +40236,10 @@ async function warmupAgentCapabilitiesOnConnect(params) {
40105
40236
  cwd,
40106
40237
  workspaceId,
40107
40238
  log: log2,
40108
- getDb,
40109
40239
  bridgeReport: false,
40110
40240
  forceAllTypes: false
40111
40241
  });
40112
- if (n > 0) sendBatchFromCache();
40242
+ if (n > 0) await sendBatchFromCache();
40113
40243
  } catch (e) {
40114
40244
  log2(`[Bridge service] Agent capability probe (missing cache) failed: ${e instanceof Error ? e.message : String(e)}`);
40115
40245
  }
@@ -40121,11 +40251,10 @@ async function warmupAgentCapabilitiesOnConnect(params) {
40121
40251
  cwd,
40122
40252
  workspaceId,
40123
40253
  log: log2,
40124
- getDb,
40125
40254
  bridgeReport: false,
40126
40255
  forceAllTypes: true
40127
40256
  });
40128
- if (n > 0) sendBatchFromCache();
40257
+ if (n > 0) await sendBatchFromCache();
40129
40258
  } catch (e) {
40130
40259
  log2(`[Bridge service] Agent capability lazy refresh failed: ${e instanceof Error ? e.message : String(e)}`);
40131
40260
  }
@@ -40137,7 +40266,7 @@ async function createBridgeConnection(options) {
40137
40266
  const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
40138
40267
  const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
40139
40268
  const logFn = options.log ?? log;
40140
- getCliDatabase({ logLegacyMigration: logFn });
40269
+ await ensureCliSqliteInitialized({ logLegacyMigration: logFn });
40141
40270
  const tokens = {
40142
40271
  accessToken: options.authToken,
40143
40272
  refreshToken: options.refreshToken
@@ -40167,11 +40296,13 @@ async function createBridgeConnection(options) {
40167
40296
  if (!Array.isArray(info.configOptions) || info.configOptions.length === 0) return;
40168
40297
  let changed = false;
40169
40298
  try {
40170
- changed = upsertCliAgentCapabilityCache(getCliDatabase(), {
40171
- workspaceId,
40172
- agentType: info.agentType,
40173
- configOptions: info.configOptions
40174
- });
40299
+ changed = withCliSqliteSync(
40300
+ (db) => upsertCliAgentCapabilityCache(db, {
40301
+ workspaceId,
40302
+ agentType: info.agentType,
40303
+ configOptions: info.configOptions
40304
+ })
40305
+ );
40175
40306
  } catch {
40176
40307
  }
40177
40308
  if (!changed) return;
@@ -40224,7 +40355,6 @@ async function createBridgeConnection(options) {
40224
40355
  await warmupAgentCapabilitiesOnConnect({
40225
40356
  workspaceId,
40226
40357
  log: logFn,
40227
- getDb: getCliDatabase,
40228
40358
  getWs
40229
40359
  });
40230
40360
  },