@askexenow/exe-os 0.8.32 → 0.8.36

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.
Files changed (87) hide show
  1. package/dist/bin/backfill-conversations.js +332 -348
  2. package/dist/bin/backfill-responses.js +72 -12
  3. package/dist/bin/backfill-vectors.js +72 -12
  4. package/dist/bin/cleanup-stale-review-tasks.js +63 -3
  5. package/dist/bin/cli.js +1518 -1122
  6. package/dist/bin/exe-agent.js +4 -4
  7. package/dist/bin/exe-assign.js +80 -18
  8. package/dist/bin/exe-boot.js +408 -89
  9. package/dist/bin/exe-call.js +83 -24
  10. package/dist/bin/exe-dispatch.js +18 -10
  11. package/dist/bin/exe-doctor.js +63 -3
  12. package/dist/bin/exe-export-behaviors.js +64 -3
  13. package/dist/bin/exe-forget.js +69 -4
  14. package/dist/bin/exe-gateway.js +121 -36
  15. package/dist/bin/exe-heartbeat.js +77 -13
  16. package/dist/bin/exe-kill.js +64 -3
  17. package/dist/bin/exe-launch-agent.js +162 -35
  18. package/dist/bin/exe-link.js +946 -0
  19. package/dist/bin/exe-new-employee.js +121 -36
  20. package/dist/bin/exe-pending-messages.js +72 -7
  21. package/dist/bin/exe-pending-notifications.js +63 -3
  22. package/dist/bin/exe-pending-reviews.js +75 -10
  23. package/dist/bin/exe-rename.js +1287 -0
  24. package/dist/bin/exe-review.js +64 -4
  25. package/dist/bin/exe-search.js +79 -13
  26. package/dist/bin/exe-session-cleanup.js +91 -26
  27. package/dist/bin/exe-status.js +64 -4
  28. package/dist/bin/exe-team.js +64 -4
  29. package/dist/bin/git-sweep.js +71 -4
  30. package/dist/bin/graph-backfill.js +64 -3
  31. package/dist/bin/graph-export.js +64 -3
  32. package/dist/bin/install.js +3 -3
  33. package/dist/bin/scan-tasks.js +71 -4
  34. package/dist/bin/setup.js +156 -38
  35. package/dist/bin/shard-migrate.js +64 -3
  36. package/dist/bin/wiki-sync.js +64 -3
  37. package/dist/gateway/index.js +122 -37
  38. package/dist/hooks/bug-report-worker.js +209 -23
  39. package/dist/hooks/commit-complete.js +71 -4
  40. package/dist/hooks/error-recall.js +79 -13
  41. package/dist/hooks/ingest-worker.js +129 -43
  42. package/dist/hooks/instructions-loaded.js +71 -4
  43. package/dist/hooks/notification.js +71 -4
  44. package/dist/hooks/post-compact.js +71 -4
  45. package/dist/hooks/pre-compact.js +71 -4
  46. package/dist/hooks/pre-tool-use.js +413 -194
  47. package/dist/hooks/prompt-ingest-worker.js +82 -22
  48. package/dist/hooks/prompt-submit.js +103 -37
  49. package/dist/hooks/response-ingest-worker.js +87 -22
  50. package/dist/hooks/session-end.js +71 -4
  51. package/dist/hooks/session-start.js +79 -13
  52. package/dist/hooks/stop.js +71 -4
  53. package/dist/hooks/subagent-stop.js +71 -4
  54. package/dist/hooks/summary-worker.js +303 -50
  55. package/dist/index.js +134 -46
  56. package/dist/lib/cloud-sync.js +209 -15
  57. package/dist/lib/consolidation.js +4 -4
  58. package/dist/lib/database.js +64 -2
  59. package/dist/lib/device-registry.js +70 -3
  60. package/dist/lib/employee-templates.js +48 -22
  61. package/dist/lib/employees.js +34 -1
  62. package/dist/lib/exe-daemon.js +136 -53
  63. package/dist/lib/hybrid-search.js +79 -13
  64. package/dist/lib/identity-templates.js +57 -6
  65. package/dist/lib/identity.js +3 -3
  66. package/dist/lib/messaging.js +22 -14
  67. package/dist/lib/reminders.js +3 -3
  68. package/dist/lib/schedules.js +63 -3
  69. package/dist/lib/skill-learning.js +3 -3
  70. package/dist/lib/status-brief.js +63 -5
  71. package/dist/lib/store.js +64 -3
  72. package/dist/lib/task-router.js +4 -2
  73. package/dist/lib/tasks.js +48 -21
  74. package/dist/lib/tmux-routing.js +47 -20
  75. package/dist/mcp/server.js +727 -58
  76. package/dist/mcp/tools/complete-reminder.js +3 -3
  77. package/dist/mcp/tools/create-reminder.js +3 -3
  78. package/dist/mcp/tools/create-task.js +151 -24
  79. package/dist/mcp/tools/deactivate-behavior.js +3 -3
  80. package/dist/mcp/tools/list-reminders.js +3 -3
  81. package/dist/mcp/tools/list-tasks.js +17 -8
  82. package/dist/mcp/tools/send-message.js +24 -16
  83. package/dist/mcp/tools/update-task.js +25 -16
  84. package/dist/runtime/index.js +112 -24
  85. package/dist/tui/App.js +139 -36
  86. package/package.json +6 -2
  87. package/src/commands/exe/rename.md +12 -0
@@ -23,12 +23,68 @@ var init_memory = __esm({
23
23
  }
24
24
  });
25
25
 
26
+ // src/lib/db-retry.ts
27
+ function isBusyError(err) {
28
+ if (err instanceof Error) {
29
+ const msg = err.message.toLowerCase();
30
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
31
+ }
32
+ return false;
33
+ }
34
+ function delay(ms) {
35
+ return new Promise((resolve) => setTimeout(resolve, ms));
36
+ }
37
+ async function retryOnBusy(fn, label) {
38
+ let lastError;
39
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
40
+ try {
41
+ return await fn();
42
+ } catch (err) {
43
+ lastError = err;
44
+ if (!isBusyError(err) || attempt === MAX_RETRIES) {
45
+ throw err;
46
+ }
47
+ const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
48
+ const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
49
+ process.stderr.write(
50
+ `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
51
+ `
52
+ );
53
+ await delay(backoff + jitter);
54
+ }
55
+ }
56
+ throw lastError;
57
+ }
58
+ function wrapWithRetry(client) {
59
+ return new Proxy(client, {
60
+ get(target, prop, receiver) {
61
+ if (prop === "execute") {
62
+ return (sql) => retryOnBusy(() => target.execute(sql), "execute");
63
+ }
64
+ if (prop === "batch") {
65
+ return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
66
+ }
67
+ return Reflect.get(target, prop, receiver);
68
+ }
69
+ });
70
+ }
71
+ var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
72
+ var init_db_retry = __esm({
73
+ "src/lib/db-retry.ts"() {
74
+ "use strict";
75
+ MAX_RETRIES = 3;
76
+ BASE_DELAY_MS = 200;
77
+ MAX_JITTER_MS = 300;
78
+ }
79
+ });
80
+
26
81
  // src/lib/database.ts
27
82
  import { createClient } from "@libsql/client";
28
83
  async function initDatabase(config) {
29
84
  if (_client) {
30
85
  _client.close();
31
86
  _client = null;
87
+ _resilientClient = null;
32
88
  }
33
89
  const opts = {
34
90
  url: `file:${config.dbPath}`
@@ -37,20 +93,27 @@ async function initDatabase(config) {
37
93
  opts.encryptionKey = config.encryptionKey;
38
94
  }
39
95
  _client = createClient(opts);
96
+ _resilientClient = wrapWithRetry(_client);
40
97
  }
41
98
  function isInitialized() {
42
99
  return _client !== null;
43
100
  }
44
101
  function getClient() {
102
+ if (!_resilientClient) {
103
+ throw new Error("Database client not initialized. Call initDatabase() first.");
104
+ }
105
+ return _resilientClient;
106
+ }
107
+ function getRawClient() {
45
108
  if (!_client) {
46
109
  throw new Error("Database client not initialized. Call initDatabase() first.");
47
110
  }
48
111
  return _client;
49
112
  }
50
113
  async function ensureSchema() {
51
- const client = getClient();
114
+ const client = getRawClient();
52
115
  await client.execute("PRAGMA journal_mode = WAL");
53
- await client.execute("PRAGMA busy_timeout = 5000");
116
+ await client.execute("PRAGMA busy_timeout = 30000");
54
117
  try {
55
118
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
56
119
  } catch {
@@ -839,11 +902,13 @@ async function ensureSchema() {
839
902
  }
840
903
  }
841
904
  }
842
- var _client, initTurso;
905
+ var _client, _resilientClient, initTurso;
843
906
  var init_database = __esm({
844
907
  "src/lib/database.ts"() {
845
908
  "use strict";
909
+ init_db_retry();
846
910
  _client = null;
911
+ _resilientClient = null;
847
912
  initTurso = initDatabase;
848
913
  }
849
914
  });
@@ -1149,7 +1214,7 @@ function listShards() {
1149
1214
  }
1150
1215
  async function ensureShardSchema(client) {
1151
1216
  await client.execute("PRAGMA journal_mode = WAL");
1152
- await client.execute("PRAGMA busy_timeout = 5000");
1217
+ await client.execute("PRAGMA busy_timeout = 30000");
1153
1218
  try {
1154
1219
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
1155
1220
  } catch {
@@ -1510,11 +1575,11 @@ async function connectEmbedDaemon() {
1510
1575
  }
1511
1576
  }
1512
1577
  const start = Date.now();
1513
- let delay = 100;
1578
+ let delay2 = 100;
1514
1579
  while (Date.now() - start < CONNECT_TIMEOUT_MS) {
1515
- await new Promise((r) => setTimeout(r, delay));
1580
+ await new Promise((r) => setTimeout(r, delay2));
1516
1581
  if (await connectToSocket()) return true;
1517
- delay = Math.min(delay * 2, 3e3);
1582
+ delay2 = Math.min(delay2 * 2, 3e3);
1518
1583
  }
1519
1584
  return false;
1520
1585
  }
@@ -1606,11 +1671,11 @@ async function embedViaClient(text, priority = "high") {
1606
1671
  `);
1607
1672
  killAndRespawnDaemon();
1608
1673
  const start = Date.now();
1609
- let delay = 200;
1674
+ let delay2 = 200;
1610
1675
  while (Date.now() - start < CONNECT_TIMEOUT_MS) {
1611
- await new Promise((r) => setTimeout(r, delay));
1676
+ await new Promise((r) => setTimeout(r, delay2));
1612
1677
  if (await connectToSocket()) break;
1613
- delay = Math.min(delay * 2, 3e3);
1678
+ delay2 = Math.min(delay2 * 2, 3e3);
1614
1679
  }
1615
1680
  if (!_connected) return null;
1616
1681
  }
@@ -1622,11 +1687,11 @@ async function embedViaClient(text, priority = "high") {
1622
1687
  `);
1623
1688
  killAndRespawnDaemon();
1624
1689
  const start = Date.now();
1625
- let delay = 200;
1690
+ let delay2 = 200;
1626
1691
  while (Date.now() - start < CONNECT_TIMEOUT_MS) {
1627
- await new Promise((r) => setTimeout(r, delay));
1692
+ await new Promise((r) => setTimeout(r, delay2));
1628
1693
  if (await connectToSocket()) break;
1629
- delay = Math.min(delay * 2, 3e3);
1694
+ delay2 = Math.min(delay2 * 2, 3e3);
1630
1695
  }
1631
1696
  if (!_connected) return null;
1632
1697
  const retry = await sendRequest([text], priority);
@@ -1739,7 +1804,7 @@ var init_embedder = __esm({
1739
1804
 
1740
1805
  // src/lib/employees.ts
1741
1806
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
1742
- import { existsSync as existsSync5, symlinkSync, readlinkSync } from "fs";
1807
+ import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync3 } from "fs";
1743
1808
  import { execSync as execSync2 } from "child_process";
1744
1809
  import path6 from "path";
1745
1810
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
@@ -1763,7 +1828,7 @@ var init_employees = __esm({
1763
1828
  });
1764
1829
 
1765
1830
  // src/lib/license.ts
1766
- import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
1831
+ import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
1767
1832
  import { randomUUID as randomUUID2 } from "crypto";
1768
1833
  import path7 from "path";
1769
1834
  import { jwtVerify, importSPKI } from "jose";
@@ -1771,14 +1836,14 @@ function loadDeviceId() {
1771
1836
  const deviceJsonPath = path7.join(EXE_AI_DIR, "device.json");
1772
1837
  try {
1773
1838
  if (existsSync6(deviceJsonPath)) {
1774
- const data = JSON.parse(readFileSync3(deviceJsonPath, "utf8"));
1839
+ const data = JSON.parse(readFileSync4(deviceJsonPath, "utf8"));
1775
1840
  if (data.deviceId) return data.deviceId;
1776
1841
  }
1777
1842
  } catch {
1778
1843
  }
1779
1844
  try {
1780
1845
  if (existsSync6(DEVICE_ID_PATH)) {
1781
- const id2 = readFileSync3(DEVICE_ID_PATH, "utf8").trim();
1846
+ const id2 = readFileSync4(DEVICE_ID_PATH, "utf8").trim();
1782
1847
  if (id2) return id2;
1783
1848
  }
1784
1849
  } catch {
@@ -1791,7 +1856,7 @@ function loadDeviceId() {
1791
1856
  function loadLicense() {
1792
1857
  try {
1793
1858
  if (!existsSync6(LICENSE_PATH)) return null;
1794
- return readFileSync3(LICENSE_PATH, "utf8").trim();
1859
+ return readFileSync4(LICENSE_PATH, "utf8").trim();
1795
1860
  } catch {
1796
1861
  return null;
1797
1862
  }
@@ -1821,7 +1886,7 @@ async function verifyLicenseJwt(token) {
1821
1886
  async function getCachedLicense() {
1822
1887
  try {
1823
1888
  if (!existsSync6(CACHE_PATH)) return null;
1824
- const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
1889
+ const raw = JSON.parse(readFileSync4(CACHE_PATH, "utf8"));
1825
1890
  if (!raw.token || typeof raw.token !== "string") return null;
1826
1891
  return await verifyLicenseJwt(raw.token);
1827
1892
  } catch {
@@ -1937,12 +2002,12 @@ __export(plan_limits_exports, {
1937
2002
  countActiveMemories: () => countActiveMemories,
1938
2003
  getLicenseSync: () => getLicenseSync
1939
2004
  });
1940
- import { readFileSync as readFileSync4, existsSync as existsSync7 } from "fs";
2005
+ import { readFileSync as readFileSync5, existsSync as existsSync7 } from "fs";
1941
2006
  import path8 from "path";
1942
2007
  function getLicenseSync() {
1943
2008
  try {
1944
2009
  if (!existsSync7(CACHE_PATH2)) return freeLicense();
1945
- const raw = JSON.parse(readFileSync4(CACHE_PATH2, "utf8"));
2010
+ const raw = JSON.parse(readFileSync5(CACHE_PATH2, "utf8"));
1946
2011
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
1947
2012
  const parts = raw.token.split(".");
1948
2013
  if (parts.length !== 3) return freeLicense();
@@ -2010,7 +2075,7 @@ function assertEmployeeLimitSync(rosterPath) {
2010
2075
  let count = 0;
2011
2076
  try {
2012
2077
  if (existsSync7(filePath)) {
2013
- const raw = readFileSync4(filePath, "utf8");
2078
+ const raw = readFileSync5(filePath, "utf8");
2014
2079
  const employees = JSON.parse(raw);
2015
2080
  count = Array.isArray(employees) ? employees.length : 0;
2016
2081
  }
@@ -212,6 +212,61 @@ var init_memory = __esm({
212
212
  }
213
213
  });
214
214
 
215
+ // src/lib/db-retry.ts
216
+ function isBusyError(err) {
217
+ if (err instanceof Error) {
218
+ const msg = err.message.toLowerCase();
219
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
220
+ }
221
+ return false;
222
+ }
223
+ function delay(ms) {
224
+ return new Promise((resolve) => setTimeout(resolve, ms));
225
+ }
226
+ async function retryOnBusy(fn, label) {
227
+ let lastError;
228
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
229
+ try {
230
+ return await fn();
231
+ } catch (err) {
232
+ lastError = err;
233
+ if (!isBusyError(err) || attempt === MAX_RETRIES) {
234
+ throw err;
235
+ }
236
+ const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
237
+ const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
238
+ process.stderr.write(
239
+ `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
240
+ `
241
+ );
242
+ await delay(backoff + jitter);
243
+ }
244
+ }
245
+ throw lastError;
246
+ }
247
+ function wrapWithRetry(client) {
248
+ return new Proxy(client, {
249
+ get(target, prop, receiver) {
250
+ if (prop === "execute") {
251
+ return (sql) => retryOnBusy(() => target.execute(sql), "execute");
252
+ }
253
+ if (prop === "batch") {
254
+ return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
255
+ }
256
+ return Reflect.get(target, prop, receiver);
257
+ }
258
+ });
259
+ }
260
+ var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
261
+ var init_db_retry = __esm({
262
+ "src/lib/db-retry.ts"() {
263
+ "use strict";
264
+ MAX_RETRIES = 3;
265
+ BASE_DELAY_MS = 200;
266
+ MAX_JITTER_MS = 300;
267
+ }
268
+ });
269
+
215
270
  // src/lib/database.ts
216
271
  var database_exports = {};
217
272
  __export(database_exports, {
@@ -219,6 +274,7 @@ __export(database_exports, {
219
274
  disposeTurso: () => disposeTurso,
220
275
  ensureSchema: () => ensureSchema,
221
276
  getClient: () => getClient,
277
+ getRawClient: () => getRawClient,
222
278
  initDatabase: () => initDatabase,
223
279
  initTurso: () => initTurso,
224
280
  isInitialized: () => isInitialized
@@ -228,6 +284,7 @@ async function initDatabase(config) {
228
284
  if (_client) {
229
285
  _client.close();
230
286
  _client = null;
287
+ _resilientClient = null;
231
288
  }
232
289
  const opts = {
233
290
  url: `file:${config.dbPath}`
@@ -236,20 +293,27 @@ async function initDatabase(config) {
236
293
  opts.encryptionKey = config.encryptionKey;
237
294
  }
238
295
  _client = createClient(opts);
296
+ _resilientClient = wrapWithRetry(_client);
239
297
  }
240
298
  function isInitialized() {
241
299
  return _client !== null;
242
300
  }
243
301
  function getClient() {
302
+ if (!_resilientClient) {
303
+ throw new Error("Database client not initialized. Call initDatabase() first.");
304
+ }
305
+ return _resilientClient;
306
+ }
307
+ function getRawClient() {
244
308
  if (!_client) {
245
309
  throw new Error("Database client not initialized. Call initDatabase() first.");
246
310
  }
247
311
  return _client;
248
312
  }
249
313
  async function ensureSchema() {
250
- const client = getClient();
314
+ const client = getRawClient();
251
315
  await client.execute("PRAGMA journal_mode = WAL");
252
- await client.execute("PRAGMA busy_timeout = 5000");
316
+ await client.execute("PRAGMA busy_timeout = 30000");
253
317
  try {
254
318
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
255
319
  } catch {
@@ -1042,13 +1106,16 @@ async function disposeDatabase() {
1042
1106
  if (_client) {
1043
1107
  _client.close();
1044
1108
  _client = null;
1109
+ _resilientClient = null;
1045
1110
  }
1046
1111
  }
1047
- var _client, initTurso, disposeTurso;
1112
+ var _client, _resilientClient, initTurso, disposeTurso;
1048
1113
  var init_database = __esm({
1049
1114
  "src/lib/database.ts"() {
1050
1115
  "use strict";
1116
+ init_db_retry();
1051
1117
  _client = null;
1118
+ _resilientClient = null;
1052
1119
  initTurso = initDatabase;
1053
1120
  disposeTurso = disposeDatabase;
1054
1121
  }
@@ -1161,7 +1228,7 @@ function listShards() {
1161
1228
  }
1162
1229
  async function ensureShardSchema(client) {
1163
1230
  await client.execute("PRAGMA journal_mode = WAL");
1164
- await client.execute("PRAGMA busy_timeout = 5000");
1231
+ await client.execute("PRAGMA busy_timeout = 30000");
1165
1232
  try {
1166
1233
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
1167
1234
  } catch {
@@ -266,12 +266,68 @@ var init_memory = __esm({
266
266
  }
267
267
  });
268
268
 
269
+ // src/lib/db-retry.ts
270
+ function isBusyError(err) {
271
+ if (err instanceof Error) {
272
+ const msg = err.message.toLowerCase();
273
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
274
+ }
275
+ return false;
276
+ }
277
+ function delay(ms) {
278
+ return new Promise((resolve) => setTimeout(resolve, ms));
279
+ }
280
+ async function retryOnBusy(fn, label) {
281
+ let lastError;
282
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
283
+ try {
284
+ return await fn();
285
+ } catch (err) {
286
+ lastError = err;
287
+ if (!isBusyError(err) || attempt === MAX_RETRIES) {
288
+ throw err;
289
+ }
290
+ const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
291
+ const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
292
+ process.stderr.write(
293
+ `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
294
+ `
295
+ );
296
+ await delay(backoff + jitter);
297
+ }
298
+ }
299
+ throw lastError;
300
+ }
301
+ function wrapWithRetry(client) {
302
+ return new Proxy(client, {
303
+ get(target, prop, receiver) {
304
+ if (prop === "execute") {
305
+ return (sql) => retryOnBusy(() => target.execute(sql), "execute");
306
+ }
307
+ if (prop === "batch") {
308
+ return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
309
+ }
310
+ return Reflect.get(target, prop, receiver);
311
+ }
312
+ });
313
+ }
314
+ var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
315
+ var init_db_retry = __esm({
316
+ "src/lib/db-retry.ts"() {
317
+ "use strict";
318
+ MAX_RETRIES = 3;
319
+ BASE_DELAY_MS = 200;
320
+ MAX_JITTER_MS = 300;
321
+ }
322
+ });
323
+
269
324
  // src/lib/database.ts
270
325
  import { createClient } from "@libsql/client";
271
326
  async function initDatabase(config) {
272
327
  if (_client) {
273
328
  _client.close();
274
329
  _client = null;
330
+ _resilientClient = null;
275
331
  }
276
332
  const opts = {
277
333
  url: `file:${config.dbPath}`
@@ -280,17 +336,24 @@ async function initDatabase(config) {
280
336
  opts.encryptionKey = config.encryptionKey;
281
337
  }
282
338
  _client = createClient(opts);
339
+ _resilientClient = wrapWithRetry(_client);
283
340
  }
284
341
  function getClient() {
342
+ if (!_resilientClient) {
343
+ throw new Error("Database client not initialized. Call initDatabase() first.");
344
+ }
345
+ return _resilientClient;
346
+ }
347
+ function getRawClient() {
285
348
  if (!_client) {
286
349
  throw new Error("Database client not initialized. Call initDatabase() first.");
287
350
  }
288
351
  return _client;
289
352
  }
290
353
  async function ensureSchema() {
291
- const client = getClient();
354
+ const client = getRawClient();
292
355
  await client.execute("PRAGMA journal_mode = WAL");
293
- await client.execute("PRAGMA busy_timeout = 5000");
356
+ await client.execute("PRAGMA busy_timeout = 30000");
294
357
  try {
295
358
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
296
359
  } catch {
@@ -1083,13 +1146,16 @@ async function disposeDatabase() {
1083
1146
  if (_client) {
1084
1147
  _client.close();
1085
1148
  _client = null;
1149
+ _resilientClient = null;
1086
1150
  }
1087
1151
  }
1088
- var _client, initTurso, disposeTurso;
1152
+ var _client, _resilientClient, initTurso, disposeTurso;
1089
1153
  var init_database = __esm({
1090
1154
  "src/lib/database.ts"() {
1091
1155
  "use strict";
1156
+ init_db_retry();
1092
1157
  _client = null;
1158
+ _resilientClient = null;
1093
1159
  initTurso = initDatabase;
1094
1160
  disposeTurso = disposeDatabase;
1095
1161
  }
@@ -1202,7 +1268,7 @@ function listShards() {
1202
1268
  }
1203
1269
  async function ensureShardSchema(client) {
1204
1270
  await client.execute("PRAGMA journal_mode = WAL");
1205
- await client.execute("PRAGMA busy_timeout = 5000");
1271
+ await client.execute("PRAGMA busy_timeout = 30000");
1206
1272
  try {
1207
1273
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
1208
1274
  } catch {
@@ -2087,11 +2153,11 @@ async function connectEmbedDaemon() {
2087
2153
  }
2088
2154
  }
2089
2155
  const start = Date.now();
2090
- let delay = 100;
2156
+ let delay2 = 100;
2091
2157
  while (Date.now() - start < CONNECT_TIMEOUT_MS) {
2092
- await new Promise((r) => setTimeout(r, delay));
2158
+ await new Promise((r) => setTimeout(r, delay2));
2093
2159
  if (await connectToSocket()) return true;
2094
- delay = Math.min(delay * 2, 3e3);
2160
+ delay2 = Math.min(delay2 * 2, 3e3);
2095
2161
  }
2096
2162
  return false;
2097
2163
  }
@@ -2183,11 +2249,11 @@ async function embedViaClient(text, priority = "high") {
2183
2249
  `);
2184
2250
  killAndRespawnDaemon();
2185
2251
  const start = Date.now();
2186
- let delay = 200;
2252
+ let delay2 = 200;
2187
2253
  while (Date.now() - start < CONNECT_TIMEOUT_MS) {
2188
- await new Promise((r) => setTimeout(r, delay));
2254
+ await new Promise((r) => setTimeout(r, delay2));
2189
2255
  if (await connectToSocket()) break;
2190
- delay = Math.min(delay * 2, 3e3);
2256
+ delay2 = Math.min(delay2 * 2, 3e3);
2191
2257
  }
2192
2258
  if (!_connected) return null;
2193
2259
  }
@@ -2199,11 +2265,11 @@ async function embedViaClient(text, priority = "high") {
2199
2265
  `);
2200
2266
  killAndRespawnDaemon();
2201
2267
  const start = Date.now();
2202
- let delay = 200;
2268
+ let delay2 = 200;
2203
2269
  while (Date.now() - start < CONNECT_TIMEOUT_MS) {
2204
- await new Promise((r) => setTimeout(r, delay));
2270
+ await new Promise((r) => setTimeout(r, delay2));
2205
2271
  if (await connectToSocket()) break;
2206
- delay = Math.min(delay * 2, 3e3);
2272
+ delay2 = Math.min(delay2 * 2, 3e3);
2207
2273
  }
2208
2274
  if (!_connected) return null;
2209
2275
  const retry = await sendRequest([text], priority);
@@ -231,6 +231,61 @@ var init_memory = __esm({
231
231
  }
232
232
  });
233
233
 
234
+ // src/lib/db-retry.ts
235
+ function isBusyError(err) {
236
+ if (err instanceof Error) {
237
+ const msg = err.message.toLowerCase();
238
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
239
+ }
240
+ return false;
241
+ }
242
+ function delay(ms) {
243
+ return new Promise((resolve) => setTimeout(resolve, ms));
244
+ }
245
+ async function retryOnBusy(fn, label) {
246
+ let lastError;
247
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
248
+ try {
249
+ return await fn();
250
+ } catch (err) {
251
+ lastError = err;
252
+ if (!isBusyError(err) || attempt === MAX_RETRIES) {
253
+ throw err;
254
+ }
255
+ const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
256
+ const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
257
+ process.stderr.write(
258
+ `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
259
+ `
260
+ );
261
+ await delay(backoff + jitter);
262
+ }
263
+ }
264
+ throw lastError;
265
+ }
266
+ function wrapWithRetry(client) {
267
+ return new Proxy(client, {
268
+ get(target, prop, receiver) {
269
+ if (prop === "execute") {
270
+ return (sql) => retryOnBusy(() => target.execute(sql), "execute");
271
+ }
272
+ if (prop === "batch") {
273
+ return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
274
+ }
275
+ return Reflect.get(target, prop, receiver);
276
+ }
277
+ });
278
+ }
279
+ var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
280
+ var init_db_retry = __esm({
281
+ "src/lib/db-retry.ts"() {
282
+ "use strict";
283
+ MAX_RETRIES = 3;
284
+ BASE_DELAY_MS = 200;
285
+ MAX_JITTER_MS = 300;
286
+ }
287
+ });
288
+
234
289
  // src/lib/database.ts
235
290
  var database_exports = {};
236
291
  __export(database_exports, {
@@ -238,6 +293,7 @@ __export(database_exports, {
238
293
  disposeTurso: () => disposeTurso,
239
294
  ensureSchema: () => ensureSchema,
240
295
  getClient: () => getClient,
296
+ getRawClient: () => getRawClient,
241
297
  initDatabase: () => initDatabase,
242
298
  initTurso: () => initTurso,
243
299
  isInitialized: () => isInitialized
@@ -247,6 +303,7 @@ async function initDatabase(config) {
247
303
  if (_client) {
248
304
  _client.close();
249
305
  _client = null;
306
+ _resilientClient = null;
250
307
  }
251
308
  const opts = {
252
309
  url: `file:${config.dbPath}`
@@ -255,20 +312,27 @@ async function initDatabase(config) {
255
312
  opts.encryptionKey = config.encryptionKey;
256
313
  }
257
314
  _client = createClient(opts);
315
+ _resilientClient = wrapWithRetry(_client);
258
316
  }
259
317
  function isInitialized() {
260
318
  return _client !== null;
261
319
  }
262
320
  function getClient() {
321
+ if (!_resilientClient) {
322
+ throw new Error("Database client not initialized. Call initDatabase() first.");
323
+ }
324
+ return _resilientClient;
325
+ }
326
+ function getRawClient() {
263
327
  if (!_client) {
264
328
  throw new Error("Database client not initialized. Call initDatabase() first.");
265
329
  }
266
330
  return _client;
267
331
  }
268
332
  async function ensureSchema() {
269
- const client = getClient();
333
+ const client = getRawClient();
270
334
  await client.execute("PRAGMA journal_mode = WAL");
271
- await client.execute("PRAGMA busy_timeout = 5000");
335
+ await client.execute("PRAGMA busy_timeout = 30000");
272
336
  try {
273
337
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
274
338
  } catch {
@@ -1061,13 +1125,16 @@ async function disposeDatabase() {
1061
1125
  if (_client) {
1062
1126
  _client.close();
1063
1127
  _client = null;
1128
+ _resilientClient = null;
1064
1129
  }
1065
1130
  }
1066
- var _client, initTurso, disposeTurso;
1131
+ var _client, _resilientClient, initTurso, disposeTurso;
1067
1132
  var init_database = __esm({
1068
1133
  "src/lib/database.ts"() {
1069
1134
  "use strict";
1135
+ init_db_retry();
1070
1136
  _client = null;
1137
+ _resilientClient = null;
1071
1138
  initTurso = initDatabase;
1072
1139
  disposeTurso = disposeDatabase;
1073
1140
  }
@@ -1180,7 +1247,7 @@ function listShards() {
1180
1247
  }
1181
1248
  async function ensureShardSchema(client) {
1182
1249
  await client.execute("PRAGMA journal_mode = WAL");
1183
- await client.execute("PRAGMA busy_timeout = 5000");
1250
+ await client.execute("PRAGMA busy_timeout = 30000");
1184
1251
  try {
1185
1252
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
1186
1253
  } catch {