@buildautomaton/cli 0.1.31 → 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.31".length > 0 ? "0.1.31" : "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,6 +26996,23 @@ function migrateCliSqlite(db) {
26991
26996
 
26992
26997
  // src/sqlite/cli-database.ts
26993
26998
  var { Database: SqliteDatabase } = sqliteWasm;
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
+ }
26994
27016
  function applyCliSqliteMemoryPragmas(db) {
26995
27017
  try {
26996
27018
  db.run("PRAGMA cache_size = -8192");
@@ -26998,18 +27020,6 @@ function applyCliSqliteMemoryPragmas(db) {
26998
27020
  } catch {
26999
27021
  }
27000
27022
  }
27001
- var openDatabases = /* @__PURE__ */ new Map();
27002
- var processExitCloseRegistered = false;
27003
- function registerProcessExitSqliteClose() {
27004
- if (processExitCloseRegistered) return;
27005
- processExitCloseRegistered = true;
27006
- process.once("exit", () => {
27007
- for (const db of openDatabases.values()) {
27008
- safeCloseCliSqliteDatabase(db);
27009
- }
27010
- openDatabases.clear();
27011
- });
27012
- }
27013
27023
  function safeCloseCliSqliteDatabase(db) {
27014
27024
  if (db == null) return;
27015
27025
  try {
@@ -27018,22 +27028,33 @@ function safeCloseCliSqliteDatabase(db) {
27018
27028
  }
27019
27029
  }
27020
27030
  function closeAllCliSqliteConnections() {
27021
- for (const db of openDatabases.values()) {
27022
- 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
+ }
27023
27047
  }
27024
- openDatabases.clear();
27025
27048
  }
27026
- function getCliDatabase(options) {
27049
+ function asyncDelayMs(ms) {
27050
+ return new Promise((resolve20) => setTimeout(resolve20, ms));
27051
+ }
27052
+ function openCliSqliteConnection(options) {
27027
27053
  const sqlitePath = getCliSqlitePath();
27028
- const existing = openDatabases.get(sqlitePath);
27029
- if (existing?.isOpen) return existing;
27030
- if (existing && !existing.isOpen) {
27031
- safeCloseCliSqliteDatabase(existing);
27032
- openDatabases.delete(sqlitePath);
27033
- }
27034
27054
  ensureCliSqliteParentDir(sqlitePath);
27035
27055
  const db = new SqliteDatabase(sqlitePath);
27036
27056
  try {
27057
+ applyCliSqliteConcurrencyPragmas(db);
27037
27058
  applyCliSqliteMemoryPragmas(db);
27038
27059
  migrateCliSqlite(db);
27039
27060
  importCliSqliteLegacyDiskData(db, options?.logLegacyMigration);
@@ -27041,10 +27062,52 @@ function getCliDatabase(options) {
27041
27062
  safeCloseCliSqliteDatabase(db);
27042
27063
  throw e;
27043
27064
  }
27044
- openDatabases.set(sqlitePath, db);
27045
- registerProcessExitSqliteClose();
27046
27065
  return db;
27047
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
+ }
27048
27111
 
27049
27112
  // src/connection/close-bridge-connection.ts
27050
27113
  async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
@@ -34812,56 +34875,80 @@ function sessionKeyForCloudSessionId(cloudSessionId) {
34812
34875
  }
34813
34876
  function readLocalAgentSessionFile(cloudSessionId) {
34814
34877
  try {
34815
- const db = getCliDatabase();
34816
- const key = sessionKeyForCloudSessionId(cloudSessionId);
34817
- const row = db.get(
34818
- "SELECT acp_session_id, backend_agent_type, config_options_json, updated_at FROM agent_session WHERE session_key = ?",
34819
- [key]
34820
- );
34821
- if (!row) return null;
34822
- let configOptions = null;
34823
- if (row.config_options_json != null && row.config_options_json !== "") {
34824
- try {
34825
- const parsed = JSON.parse(row.config_options_json);
34826
- configOptions = Array.isArray(parsed) ? parsed : null;
34827
- } catch {
34828
- 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
+ }
34829
34893
  }
34830
- }
34831
- return {
34832
- v: 1,
34833
- acpSessionId: row.acp_session_id,
34834
- backendAgentType: row.backend_agent_type,
34835
- configOptions,
34836
- updatedAt: row.updated_at
34837
- };
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
+ });
34838
34902
  } catch {
34839
34903
  return null;
34840
34904
  }
34841
34905
  }
34842
34906
  function writeLocalAgentSessionFile(cloudSessionId, patch) {
34843
34907
  try {
34844
- const db = getCliDatabase();
34845
- const key = sessionKeyForCloudSessionId(cloudSessionId);
34846
- const prev = readLocalAgentSessionFile(cloudSessionId);
34847
- const next = {
34848
- v: 1,
34849
- acpSessionId: patch.acpSessionId !== void 0 ? patch.acpSessionId : prev?.acpSessionId ?? null,
34850
- backendAgentType: patch.backendAgentType !== void 0 ? patch.backendAgentType : prev?.backendAgentType ?? null,
34851
- configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
34852
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
34853
- };
34854
- const configJson = next.configOptions != null ? JSON.stringify(next.configOptions) : null;
34855
- db.run(
34856
- `INSERT INTO agent_session (session_key, acp_session_id, backend_agent_type, config_options_json, updated_at)
34857
- VALUES (?, ?, ?, ?, ?)
34858
- ON CONFLICT(session_key) DO UPDATE SET
34859
- acp_session_id = excluded.acp_session_id,
34860
- backend_agent_type = excluded.backend_agent_type,
34861
- config_options_json = excluded.config_options_json,
34862
- updated_at = excluded.updated_at`,
34863
- [key, next.acpSessionId, next.backendAgentType, configJson, next.updatedAt]
34864
- );
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
+ });
34865
34952
  } catch {
34866
34953
  }
34867
34954
  }
@@ -36444,11 +36531,6 @@ function getCwdHashForFileIndex(resolvedCwd) {
36444
36531
  // src/files/index/build-file-index.ts
36445
36532
  import path29 from "node:path";
36446
36533
 
36447
- // src/runtime/yield-to-event-loop.ts
36448
- function yieldToEventLoop() {
36449
- return new Promise((resolve20) => setImmediate(resolve20));
36450
- }
36451
-
36452
36534
  // src/files/index/walk-workspace-tree.ts
36453
36535
  import fs25 from "node:fs";
36454
36536
  import path28 from "node:path";
@@ -36513,39 +36595,40 @@ function withFileIndexSqliteLock(fn) {
36513
36595
  // src/files/index/build-file-index.ts
36514
36596
  var FILE_INDEX_INSERT_BUFFER = 2048;
36515
36597
  function persistFileIndexForResolvedCwd(resolved) {
36516
- const db = getCliDatabase();
36517
- const h = getCwdHashForFileIndex(resolved);
36518
- const buf = [];
36519
- let pathCount = 0;
36520
- db.run("BEGIN IMMEDIATE");
36521
- try {
36522
- db.run("DELETE FROM file_index_path WHERE cwd_hash = ?", [h]);
36523
- const ins = db.prepare("INSERT INTO file_index_path (cwd_hash, path) VALUES (?, ?)");
36598
+ return withCliSqliteSync((db) => {
36599
+ const h = getCwdHashForFileIndex(resolved);
36600
+ const buf = [];
36601
+ let pathCount = 0;
36602
+ db.run("BEGIN IMMEDIATE");
36524
36603
  try {
36525
- const flushBuf = () => {
36526
- for (const rel of buf) {
36527
- ins.run([h, rel]);
36528
- }
36529
- pathCount += buf.length;
36530
- buf.length = 0;
36531
- };
36532
- walkWorkspaceTreeSync(resolved, resolved, (rel) => {
36533
- buf.push(rel);
36534
- if (buf.length >= FILE_INDEX_INSERT_BUFFER) flushBuf();
36535
- });
36536
- flushBuf();
36537
- } finally {
36538
- ins.finalize();
36539
- }
36540
- db.run("COMMIT");
36541
- } catch (e) {
36542
- try {
36543
- db.run("ROLLBACK");
36544
- } catch {
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();
36621
+ }
36622
+ db.run("COMMIT");
36623
+ } catch (e) {
36624
+ try {
36625
+ db.run("ROLLBACK");
36626
+ } catch {
36627
+ }
36628
+ throw e;
36545
36629
  }
36546
- throw e;
36547
- }
36548
- return pathCount;
36630
+ return pathCount;
36631
+ });
36549
36632
  }
36550
36633
  async function buildFileIndexAsync(cwd) {
36551
36634
  return withFileIndexSqliteLock(async () => {
@@ -36569,23 +36652,20 @@ function sqliteExprBridgeFileIndexDependencyRank() {
36569
36652
  function escapeLikePattern(fragment) {
36570
36653
  return fragment.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
36571
36654
  }
36572
- function bridgeFileIndexIsPopulated(resolvedCwd) {
36573
- const db = getCliDatabase();
36655
+ function bridgeFileIndexIsPopulatedWithDb(resolvedCwd, db) {
36574
36656
  const h = getCwdHashForFileIndex(resolvedCwd);
36575
36657
  const row = db.get("SELECT 1 as ok FROM file_index_path WHERE cwd_hash = ? LIMIT 1", [h]);
36576
36658
  return row != null;
36577
36659
  }
36578
- function bridgeFileIndexPathCount(resolvedCwd) {
36579
- const db = getCliDatabase();
36660
+ function bridgeFileIndexPathCountWithDb(resolvedCwd, db) {
36580
36661
  const h = getCwdHashForFileIndex(resolvedCwd);
36581
36662
  const row = db.get("SELECT COUNT(*) as c FROM file_index_path WHERE cwd_hash = ?", [h]);
36582
36663
  const c = row?.c ?? 0;
36583
36664
  return Number(c);
36584
36665
  }
36585
- function searchBridgeFilePaths(resolvedCwd, query, limit = 100) {
36666
+ function searchBridgeFilePathsWithDb(resolvedCwd, query, limit, db) {
36586
36667
  const q = query.trim().toLowerCase();
36587
36668
  if (!q) return [];
36588
- const db = getCliDatabase();
36589
36669
  const h = getCwdHashForFileIndex(resolvedCwd);
36590
36670
  const pattern = `%${escapeLikePattern(q)}%`;
36591
36671
  const lim = Math.max(0, Math.min(1e4, Math.floor(limit)));
@@ -36596,9 +36676,15 @@ function searchBridgeFilePaths(resolvedCwd, query, limit = 100) {
36596
36676
  );
36597
36677
  return rows.map((r) => String(r.path));
36598
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
+ }
36599
36685
  async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
36600
36686
  await yieldToEventLoop();
36601
- const out = searchBridgeFilePaths(resolvedCwd, query, limit);
36687
+ const out = await withCliSqlite((db) => searchBridgeFilePathsWithDb(resolvedCwd, query, limit, db));
36602
36688
  if (out.length >= INDEX_WORK_YIELD_EVERY) await yieldToEventLoop();
36603
36689
  return out;
36604
36690
  }
@@ -36606,8 +36692,8 @@ async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
36606
36692
  // src/files/index/ensure-file-index.ts
36607
36693
  async function ensureFileIndexAsync(cwd) {
36608
36694
  const resolved = path30.resolve(cwd);
36609
- if (bridgeFileIndexIsPopulated(resolved)) {
36610
- return { fromCache: true, pathCount: bridgeFileIndexPathCount(resolved) };
36695
+ if (await bridgeFileIndexIsPopulated(resolved)) {
36696
+ return { fromCache: true, pathCount: await bridgeFileIndexPathCount(resolved) };
36611
36697
  }
36612
36698
  return { ...await buildFileIndexAsync(resolved), fromCache: false };
36613
36699
  }
@@ -38288,30 +38374,32 @@ var MERGEABLE_SERVER_STATES = /* @__PURE__ */ new Set([
38288
38374
  "stopping",
38289
38375
  "discarded"
38290
38376
  ]);
38291
- function readPersistedQueue(queueKey) {
38292
- const db = getCliDatabase();
38293
- const row = db.get("SELECT queue_key, updated_at, turns_json FROM prompt_queue WHERE queue_key = ?", [
38294
- queueKey
38295
- ]);
38296
- if (!row) return null;
38297
- try {
38298
- const turns = JSON.parse(row.turns_json);
38299
- if (!Array.isArray(turns)) return null;
38300
- return { queueKey: row.queue_key, updatedAt: row.updated_at, turns };
38301
- } catch {
38302
- return null;
38303
- }
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
+ });
38304
38391
  }
38305
- function writePersistedQueue(file2) {
38306
- const db = getCliDatabase();
38307
- db.run(
38308
- `INSERT INTO prompt_queue (queue_key, updated_at, turns_json) VALUES (?, ?, ?)
38309
- ON CONFLICT(queue_key) DO UPDATE SET updated_at = excluded.updated_at, turns_json = excluded.turns_json`,
38310
- [file2.queueKey, file2.updatedAt, JSON.stringify(file2.turns)]
38311
- );
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
+ });
38312
38400
  }
38313
- function mergeServerQueueSnapshot(queueKey, serverTurns) {
38314
- const prev = readPersistedQueue(queueKey);
38401
+ async function mergeServerQueueSnapshot(queueKey, serverTurns) {
38402
+ const prev = await readPersistedQueue(queueKey);
38315
38403
  const turns = [];
38316
38404
  for (const raw of serverTurns) {
38317
38405
  if (!raw || typeof raw !== "object") continue;
@@ -38408,12 +38496,12 @@ async function applyPromptQueueStateFromServer(msg, deps) {
38408
38496
  const getWs = deps.getWs;
38409
38497
  for (const [queueKey, serverTurns] of Object.entries(raw)) {
38410
38498
  if (!Array.isArray(serverTurns)) continue;
38411
- const file2 = mergeServerQueueSnapshot(queueKey, serverTurns);
38412
- writePersistedQueue(file2);
38499
+ const file2 = await mergeServerQueueSnapshot(queueKey, serverTurns);
38500
+ await writePersistedQueue(file2);
38413
38501
  }
38414
38502
  for (const [queueKey, serverTurns] of Object.entries(raw)) {
38415
38503
  if (!Array.isArray(serverTurns)) continue;
38416
- const file2 = readPersistedQueue(queueKey);
38504
+ const file2 = await readPersistedQueue(queueKey);
38417
38505
  if (!file2) continue;
38418
38506
  for (const running of file2.turns.filter((t) => t.lastClientState === "running")) {
38419
38507
  runIdToQueueKey.set(running.turnId, queueKey);
@@ -38421,7 +38509,7 @@ async function applyPromptQueueStateFromServer(msg, deps) {
38421
38509
  }
38422
38510
  for (const [queueKey, serverTurns] of Object.entries(raw)) {
38423
38511
  if (!Array.isArray(serverTurns)) continue;
38424
- const file2 = readPersistedQueue(queueKey);
38512
+ const file2 = await readPersistedQueue(queueKey);
38425
38513
  if (!file2) continue;
38426
38514
  const cancelRow = file2.turns.find((t) => t.serverState === "cancel_requested" && t.lastClientState === "running");
38427
38515
  if (cancelRow) {
@@ -38430,7 +38518,7 @@ async function applyPromptQueueStateFromServer(msg, deps) {
38430
38518
  deps.log(
38431
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.`
38432
38520
  );
38433
- finalizePromptTurnOnBridge(deps.getWs, cancelRow.turnId, false, { terminalClientState: "cancelled" });
38521
+ await finalizePromptTurnOnBridge(deps.getWs, cancelRow.turnId, false, { terminalClientState: "cancelled" });
38434
38522
  const ws = deps.getWs();
38435
38523
  if (ws && cancelRow.sessionId) {
38436
38524
  sendWsMessage(ws, {
@@ -38449,19 +38537,19 @@ async function applyPromptQueueStateFromServer(msg, deps) {
38449
38537
  const startedThisTick = /* @__PURE__ */ new Set();
38450
38538
  for (const [queueKey, serverTurns] of Object.entries(raw)) {
38451
38539
  if (!Array.isArray(serverTurns)) continue;
38452
- const file2 = readPersistedQueue(queueKey);
38540
+ const file2 = await readPersistedQueue(queueKey);
38453
38541
  if (!file2) continue;
38454
38542
  if (hasRunningTurn(file2.turns)) continue;
38455
38543
  const next = pickNextRunnableTurn(file2.turns);
38456
38544
  if (!next) continue;
38457
38545
  if (!await runLocalRevertBeforeQueuedPrompt(next, deps)) {
38458
38546
  next.lastClientState = "failed";
38459
- writePersistedQueue(file2);
38547
+ await writePersistedQueue(file2);
38460
38548
  sendPromptQueueClientReport(getWs(), { [queueKey]: [{ turnId: next.turnId, clientState: "failed" }] });
38461
38549
  continue;
38462
38550
  }
38463
38551
  next.lastClientState = "running";
38464
- writePersistedQueue(file2);
38552
+ await writePersistedQueue(file2);
38465
38553
  runIdToQueueKey.set(next.turnId, queueKey);
38466
38554
  startedThisTick.add(next.turnId);
38467
38555
  report[queueKey] = [{ turnId: next.turnId, clientState: "running" }];
@@ -38471,7 +38559,7 @@ async function applyPromptQueueStateFromServer(msg, deps) {
38471
38559
  }
38472
38560
  for (const [queueKey, serverTurns] of Object.entries(raw)) {
38473
38561
  if (!Array.isArray(serverTurns)) continue;
38474
- const file2 = readPersistedQueue(queueKey);
38562
+ const file2 = await readPersistedQueue(queueKey);
38475
38563
  if (!file2) continue;
38476
38564
  const running = file2.turns.find((t) => t.lastClientState === "running");
38477
38565
  if (!running || !startedThisTick.has(running.turnId)) continue;
@@ -38479,17 +38567,17 @@ async function applyPromptQueueStateFromServer(msg, deps) {
38479
38567
  dispatchLocalPrompt(running, deps);
38480
38568
  }
38481
38569
  }
38482
- function finalizePromptTurnOnBridge(getWs, runId, success2, opts) {
38570
+ async function finalizePromptTurnOnBridge(getWs, runId, success2, opts) {
38483
38571
  if (!runId) return false;
38484
38572
  const queueKey = runIdToQueueKey.get(runId);
38485
38573
  runIdToQueueKey.delete(runId);
38486
38574
  if (!queueKey) return false;
38487
- const f = readPersistedQueue(queueKey);
38575
+ const f = await readPersistedQueue(queueKey);
38488
38576
  if (!f) return false;
38489
38577
  const t = f.turns.find((x) => x.turnId === runId);
38490
38578
  if (!t) return false;
38491
38579
  t.lastClientState = opts?.terminalClientState ?? (success2 ? "stopped" : "failed");
38492
- writePersistedQueue(f);
38580
+ await writePersistedQueue(f);
38493
38581
  sendPromptQueueClientReport(getWs(), { [queueKey]: [{ turnId: runId, clientState: t.lastClientState }] });
38494
38582
  return true;
38495
38583
  }
@@ -38510,12 +38598,13 @@ function createBridgePromptSenders(deps, getWs) {
38510
38598
  if (result.type === "prompt_result") {
38511
38599
  const pr = result;
38512
38600
  const cancelled = pr.stopReason === "cancelled";
38513
- finalizePromptTurnOnBridge(
38601
+ void finalizePromptTurnOnBridge(
38514
38602
  getWs,
38515
38603
  typeof pr.runId === "string" ? pr.runId : void 0,
38516
38604
  pr.success === true,
38517
38605
  cancelled ? { terminalClientState: "cancelled" } : void 0
38518
- );
38606
+ ).catch(() => {
38607
+ });
38519
38608
  }
38520
38609
  };
38521
38610
  const sendSessionUpdate = (payload) => {
@@ -39248,7 +39337,7 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
39248
39337
  await yieldToEventLoop();
39249
39338
  const q = typeof msg.q === "string" ? msg.q : "";
39250
39339
  const cwd = path37.resolve(getBridgeRoot());
39251
- if (!bridgeFileIndexIsPopulated(cwd)) {
39340
+ if (!await bridgeFileIndexIsPopulated(cwd)) {
39252
39341
  const payload2 = {
39253
39342
  type: "file_browser_search_response",
39254
39343
  id: msg.id,
@@ -40009,7 +40098,7 @@ import * as path40 from "node:path";
40009
40098
  // src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
40010
40099
  import * as path39 from "node:path";
40011
40100
  async function probeOneAgentTypeForCapabilities(params) {
40012
- const { agentType, cwd, workspaceId, log: log2, getDb, reportAgentCapabilities, bridgeReport = true } = params;
40101
+ const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true } = params;
40013
40102
  const resolved = resolveAgentCommand(agentType);
40014
40103
  if (!resolved) return false;
40015
40104
  let sqliteChanged = false;
@@ -40020,11 +40109,13 @@ async function probeOneAgentTypeForCapabilities(params) {
40020
40109
  reportedRef.done = true;
40021
40110
  let changed = false;
40022
40111
  try {
40023
- changed = upsertCliAgentCapabilityCache(getDb(), {
40024
- workspaceId,
40025
- agentType,
40026
- configOptions: co
40027
- });
40112
+ changed = withCliSqliteSync(
40113
+ (db) => upsertCliAgentCapabilityCache(db, {
40114
+ workspaceId,
40115
+ agentType,
40116
+ configOptions: co
40117
+ })
40118
+ );
40028
40119
  } catch {
40029
40120
  }
40030
40121
  sqliteChanged ||= changed;
@@ -40082,7 +40173,6 @@ async function probeAgentCapabilitiesForDetectedTypes(params) {
40082
40173
  cwd,
40083
40174
  workspaceId,
40084
40175
  log: log2,
40085
- getDb,
40086
40176
  reportAgentCapabilities,
40087
40177
  bridgeReport = true,
40088
40178
  forceAllTypes = false
@@ -40094,7 +40184,7 @@ async function probeAgentCapabilitiesForDetectedTypes(params) {
40094
40184
  if (!agentType.trim()) continue;
40095
40185
  if (!forceAllTypes) {
40096
40186
  try {
40097
- 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))) {
40098
40188
  continue;
40099
40189
  }
40100
40190
  } catch {
@@ -40105,7 +40195,6 @@ async function probeAgentCapabilitiesForDetectedTypes(params) {
40105
40195
  cwd,
40106
40196
  workspaceId,
40107
40197
  log: log2,
40108
- getDb,
40109
40198
  reportAgentCapabilities,
40110
40199
  bridgeReport
40111
40200
  });
@@ -40116,14 +40205,13 @@ async function probeAgentCapabilitiesForDetectedTypes(params) {
40116
40205
 
40117
40206
  // src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
40118
40207
  async function warmupAgentCapabilitiesOnConnect(params) {
40119
- const { workspaceId, log: log2, getDb, getWs } = params;
40208
+ const { workspaceId, log: log2, getWs } = params;
40120
40209
  const cwd = path40.resolve(getBridgeRoot());
40121
- const db = getDb();
40122
- function sendBatchFromCache() {
40210
+ async function sendBatchFromCache() {
40123
40211
  const socket = getWs();
40124
40212
  if (!socket || socket.readyState !== wrapper_default.OPEN) return;
40125
40213
  try {
40126
- const rows = listCliAgentCapabilityCacheForWorkspace(db, workspaceId);
40214
+ const rows = await withCliSqlite((db) => listCliAgentCapabilityCacheForWorkspace(db, workspaceId));
40127
40215
  if (rows.length === 0) return;
40128
40216
  sendWsMessage(socket, {
40129
40217
  type: "agent_capabilities_batch",
@@ -40135,7 +40223,7 @@ async function warmupAgentCapabilitiesOnConnect(params) {
40135
40223
  );
40136
40224
  }
40137
40225
  }
40138
- sendBatchFromCache();
40226
+ await sendBatchFromCache();
40139
40227
  let types = [];
40140
40228
  try {
40141
40229
  types = [...await detectLocalAgentTypes()];
@@ -40148,11 +40236,10 @@ async function warmupAgentCapabilitiesOnConnect(params) {
40148
40236
  cwd,
40149
40237
  workspaceId,
40150
40238
  log: log2,
40151
- getDb,
40152
40239
  bridgeReport: false,
40153
40240
  forceAllTypes: false
40154
40241
  });
40155
- if (n > 0) sendBatchFromCache();
40242
+ if (n > 0) await sendBatchFromCache();
40156
40243
  } catch (e) {
40157
40244
  log2(`[Bridge service] Agent capability probe (missing cache) failed: ${e instanceof Error ? e.message : String(e)}`);
40158
40245
  }
@@ -40164,11 +40251,10 @@ async function warmupAgentCapabilitiesOnConnect(params) {
40164
40251
  cwd,
40165
40252
  workspaceId,
40166
40253
  log: log2,
40167
- getDb,
40168
40254
  bridgeReport: false,
40169
40255
  forceAllTypes: true
40170
40256
  });
40171
- if (n > 0) sendBatchFromCache();
40257
+ if (n > 0) await sendBatchFromCache();
40172
40258
  } catch (e) {
40173
40259
  log2(`[Bridge service] Agent capability lazy refresh failed: ${e instanceof Error ? e.message : String(e)}`);
40174
40260
  }
@@ -40180,7 +40266,7 @@ async function createBridgeConnection(options) {
40180
40266
  const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
40181
40267
  const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
40182
40268
  const logFn = options.log ?? log;
40183
- getCliDatabase({ logLegacyMigration: logFn });
40269
+ await ensureCliSqliteInitialized({ logLegacyMigration: logFn });
40184
40270
  const tokens = {
40185
40271
  accessToken: options.authToken,
40186
40272
  refreshToken: options.refreshToken
@@ -40210,11 +40296,13 @@ async function createBridgeConnection(options) {
40210
40296
  if (!Array.isArray(info.configOptions) || info.configOptions.length === 0) return;
40211
40297
  let changed = false;
40212
40298
  try {
40213
- changed = upsertCliAgentCapabilityCache(getCliDatabase(), {
40214
- workspaceId,
40215
- agentType: info.agentType,
40216
- configOptions: info.configOptions
40217
- });
40299
+ changed = withCliSqliteSync(
40300
+ (db) => upsertCliAgentCapabilityCache(db, {
40301
+ workspaceId,
40302
+ agentType: info.agentType,
40303
+ configOptions: info.configOptions
40304
+ })
40305
+ );
40218
40306
  } catch {
40219
40307
  }
40220
40308
  if (!changed) return;
@@ -40267,7 +40355,6 @@ async function createBridgeConnection(options) {
40267
40355
  await warmupAgentCapabilitiesOnConnect({
40268
40356
  workspaceId,
40269
40357
  log: logFn,
40270
- getDb: getCliDatabase,
40271
40358
  getWs
40272
40359
  });
40273
40360
  },