@askexenow/exe-os 0.8.37 → 0.8.39

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 (93) hide show
  1. package/README.md +17 -8
  2. package/dist/bin/backfill-conversations.js +112 -70
  3. package/dist/bin/backfill-responses.js +53 -18
  4. package/dist/bin/backfill-vectors.js +43 -16
  5. package/dist/bin/cleanup-stale-review-tasks.js +38 -16
  6. package/dist/bin/cli.js +790 -468
  7. package/dist/bin/exe-agent.js +19 -4
  8. package/dist/bin/exe-assign.js +46 -13
  9. package/dist/bin/exe-boot.js +288 -129
  10. package/dist/bin/exe-call.js +20 -10
  11. package/dist/bin/exe-cloud.js +135 -30
  12. package/dist/bin/exe-dispatch.js +1 -1
  13. package/dist/bin/exe-doctor.js +38 -16
  14. package/dist/bin/exe-export-behaviors.js +43 -21
  15. package/dist/bin/exe-forget.js +39 -17
  16. package/dist/bin/exe-gateway.js +159 -50
  17. package/dist/bin/exe-heartbeat.js +53 -31
  18. package/dist/bin/exe-kill.js +40 -18
  19. package/dist/bin/exe-launch-agent.js +109 -36
  20. package/dist/bin/exe-link.js +196 -87
  21. package/dist/bin/exe-new-employee.js +56 -17
  22. package/dist/bin/exe-pending-messages.js +47 -25
  23. package/dist/bin/exe-pending-notifications.js +38 -16
  24. package/dist/bin/exe-pending-reviews.js +51 -29
  25. package/dist/bin/exe-rename.js +21 -7
  26. package/dist/bin/exe-review.js +41 -13
  27. package/dist/bin/exe-search.js +57 -21
  28. package/dist/bin/exe-session-cleanup.js +67 -31
  29. package/dist/bin/exe-settings.js +63 -2
  30. package/dist/bin/exe-status.js +35 -13
  31. package/dist/bin/exe-team.js +35 -13
  32. package/dist/bin/git-sweep.js +45 -17
  33. package/dist/bin/graph-backfill.js +38 -16
  34. package/dist/bin/graph-export.js +38 -16
  35. package/dist/bin/install.js +10 -1
  36. package/dist/bin/scan-tasks.js +47 -19
  37. package/dist/bin/setup.js +444 -259
  38. package/dist/bin/shard-migrate.js +38 -16
  39. package/dist/bin/wiki-sync.js +40 -17
  40. package/dist/gateway/index.js +113 -48
  41. package/dist/hooks/bug-report-worker.js +66 -39
  42. package/dist/hooks/commit-complete.js +45 -17
  43. package/dist/hooks/error-recall.js +60 -20
  44. package/dist/hooks/exe-heartbeat-hook.js +3 -2
  45. package/dist/hooks/ingest-worker.js +174 -45
  46. package/dist/hooks/ingest.js +74 -28
  47. package/dist/hooks/instructions-loaded.js +46 -17
  48. package/dist/hooks/notification.js +44 -15
  49. package/dist/hooks/post-compact.js +44 -15
  50. package/dist/hooks/pre-compact.js +42 -14
  51. package/dist/hooks/pre-tool-use.js +59 -22
  52. package/dist/hooks/prompt-ingest-worker.js +75 -14
  53. package/dist/hooks/prompt-submit.js +75 -32
  54. package/dist/hooks/response-ingest-worker.js +76 -15
  55. package/dist/hooks/session-end.js +54 -22
  56. package/dist/hooks/session-start.js +57 -20
  57. package/dist/hooks/stop.js +44 -15
  58. package/dist/hooks/subagent-stop.js +44 -15
  59. package/dist/hooks/summary-worker.js +339 -106
  60. package/dist/index.js +94 -23
  61. package/dist/lib/cloud-sync.js +191 -80
  62. package/dist/lib/config.js +4 -1
  63. package/dist/lib/consolidation.js +5 -4
  64. package/dist/lib/database.js +1 -0
  65. package/dist/lib/device-registry.js +2 -1
  66. package/dist/lib/embedder.js +9 -1
  67. package/dist/lib/employee-templates.js +5 -0
  68. package/dist/lib/employees.js +11 -6
  69. package/dist/lib/exe-daemon-client.js +6 -1
  70. package/dist/lib/exe-daemon.js +95 -36
  71. package/dist/lib/hybrid-search.js +57 -21
  72. package/dist/lib/identity-templates.js +16 -7
  73. package/dist/lib/identity.js +1 -1
  74. package/dist/lib/keychain.js +2 -1
  75. package/dist/lib/license.js +56 -6
  76. package/dist/lib/messaging.js +1 -1
  77. package/dist/lib/reminders.js +2 -2
  78. package/dist/lib/schedules.js +38 -16
  79. package/dist/lib/skill-learning.js +1 -1
  80. package/dist/lib/store.js +44 -16
  81. package/dist/lib/tasks.js +1 -1
  82. package/dist/lib/tmux-routing.js +1 -1
  83. package/dist/mcp/server.js +280 -155
  84. package/dist/mcp/tools/complete-reminder.js +1 -1
  85. package/dist/mcp/tools/create-task.js +14 -6
  86. package/dist/mcp/tools/deactivate-behavior.js +2 -2
  87. package/dist/mcp/tools/list-reminders.js +1 -1
  88. package/dist/mcp/tools/list-tasks.js +36 -28
  89. package/dist/mcp/tools/send-message.js +1 -1
  90. package/dist/mcp/tools/update-task.js +1 -1
  91. package/dist/runtime/index.js +42 -8
  92. package/dist/tui/App.js +220 -99
  93. package/package.json +5 -3
@@ -1,12 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
- }) : x)(function(x) {
7
- if (typeof require !== "undefined") return require.apply(this, arguments);
8
- throw Error('Dynamic require of "' + x + '" is not supported');
9
- });
10
4
  var __esm = (fn, res) => function __init() {
11
5
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
6
  };
@@ -103,6 +97,7 @@ async function ensureSchema() {
103
97
  const client = getRawClient();
104
98
  await client.execute("PRAGMA journal_mode = WAL");
105
99
  await client.execute("PRAGMA busy_timeout = 30000");
100
+ await client.execute("PRAGMA wal_autocheckpoint = 1000");
106
101
  try {
107
102
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
108
103
  } catch {
@@ -903,15 +898,15 @@ var init_database = __esm({
903
898
  });
904
899
 
905
900
  // src/lib/config.ts
906
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
901
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
907
902
  import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
908
903
  import path2 from "path";
909
- import os from "os";
904
+ import os2 from "os";
910
905
  function resolveDataDir() {
911
906
  if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
912
907
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
913
- const newDir = path2.join(os.homedir(), ".exe-os");
914
- const legacyDir = path2.join(os.homedir(), ".exe-mem");
908
+ const newDir = path2.join(os2.homedir(), ".exe-os");
909
+ const legacyDir = path2.join(os2.homedir(), ".exe-mem");
915
910
  if (!existsSync2(newDir) && existsSync2(legacyDir)) {
916
911
  try {
917
912
  renameSync(legacyDir, newDir);
@@ -998,7 +993,7 @@ async function loadConfig() {
998
993
  normalizeAutoUpdate(migratedCfg);
999
994
  const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
1000
995
  if (config.dbPath.startsWith("~")) {
1001
- config.dbPath = config.dbPath.replace(/^~/, os.homedir());
996
+ config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
1002
997
  }
1003
998
  return config;
1004
999
  } catch {
@@ -1124,7 +1119,7 @@ __export(shard_manager_exports, {
1124
1119
  shardExists: () => shardExists
1125
1120
  });
1126
1121
  import path3 from "path";
1127
- import { existsSync as existsSync3, mkdirSync } from "fs";
1122
+ import { existsSync as existsSync3, mkdirSync, readdirSync } from "fs";
1128
1123
  import { createClient as createClient2 } from "@libsql/client";
1129
1124
  function initShardManager(encryptionKey) {
1130
1125
  _encryptionKey = encryptionKey;
@@ -1163,8 +1158,7 @@ function shardExists(projectName) {
1163
1158
  }
1164
1159
  function listShards() {
1165
1160
  if (!existsSync3(SHARDS_DIR)) return [];
1166
- const { readdirSync: readdirSync3 } = __require("fs");
1167
- return readdirSync3(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1161
+ return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1168
1162
  }
1169
1163
  async function ensureShardSchema(client) {
1170
1164
  await client.execute("PRAGMA journal_mode = WAL");
@@ -1369,10 +1363,10 @@ var init_employees = __esm({
1369
1363
  // src/lib/notifications.ts
1370
1364
  import crypto2 from "crypto";
1371
1365
  import path5 from "path";
1372
- import os2 from "os";
1366
+ import os3 from "os";
1373
1367
  import {
1374
1368
  readFileSync as readFileSync3,
1375
- readdirSync,
1369
+ readdirSync as readdirSync2,
1376
1370
  unlinkSync,
1377
1371
  existsSync as existsSync5,
1378
1372
  rmdirSync
@@ -1399,12 +1393,12 @@ var init_tasks_crud = __esm({
1399
1393
 
1400
1394
  // src/lib/session-registry.ts
1401
1395
  import path7 from "path";
1402
- import os3 from "os";
1396
+ import os4 from "os";
1403
1397
  var REGISTRY_PATH;
1404
1398
  var init_session_registry = __esm({
1405
1399
  "src/lib/session-registry.ts"() {
1406
1400
  "use strict";
1407
- REGISTRY_PATH = path7.join(os3.homedir(), ".exe-os", "session-registry.json");
1401
+ REGISTRY_PATH = path7.join(os4.homedir(), ".exe-os", "session-registry.json");
1408
1402
  }
1409
1403
  });
1410
1404
 
@@ -1455,14 +1449,14 @@ var init_provider_table = __esm({
1455
1449
  // src/lib/intercom-queue.ts
1456
1450
  import { readFileSync as readFileSync5, writeFileSync, renameSync as renameSync2, existsSync as existsSync7, mkdirSync as mkdirSync2 } from "fs";
1457
1451
  import path8 from "path";
1458
- import os4 from "os";
1452
+ import os5 from "os";
1459
1453
  var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
1460
1454
  var init_intercom_queue = __esm({
1461
1455
  "src/lib/intercom-queue.ts"() {
1462
1456
  "use strict";
1463
- QUEUE_PATH = path8.join(os4.homedir(), ".exe-os", "intercom-queue.json");
1457
+ QUEUE_PATH = path8.join(os5.homedir(), ".exe-os", "intercom-queue.json");
1464
1458
  TTL_MS = 60 * 60 * 1e3;
1465
- INTERCOM_LOG = path8.join(os4.homedir(), ".exe-os", "intercom.log");
1459
+ INTERCOM_LOG = path8.join(os5.homedir(), ".exe-os", "intercom.log");
1466
1460
  }
1467
1461
  });
1468
1462
 
@@ -1499,7 +1493,7 @@ var init_plan_limits = __esm({
1499
1493
 
1500
1494
  // src/lib/tmux-routing.ts
1501
1495
  import path11 from "path";
1502
- import os5 from "os";
1496
+ import os6 from "os";
1503
1497
  import { fileURLToPath as fileURLToPath2 } from "url";
1504
1498
  var SPAWN_LOCK_DIR, SESSION_CACHE, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
1505
1499
  var init_tmux_routing = __esm({
@@ -1513,9 +1507,9 @@ var init_tmux_routing = __esm({
1513
1507
  init_provider_table();
1514
1508
  init_intercom_queue();
1515
1509
  init_plan_limits();
1516
- SPAWN_LOCK_DIR = path11.join(os5.homedir(), ".exe-os", "spawn-locks");
1517
- SESSION_CACHE = path11.join(os5.homedir(), ".exe-os", "session-cache");
1518
- INTERCOM_LOG2 = path11.join(os5.homedir(), ".exe-os", "intercom.log");
1510
+ SPAWN_LOCK_DIR = path11.join(os6.homedir(), ".exe-os", "spawn-locks");
1511
+ SESSION_CACHE = path11.join(os6.homedir(), ".exe-os", "session-cache");
1512
+ INTERCOM_LOG2 = path11.join(os6.homedir(), ".exe-os", "intercom.log");
1519
1513
  DEBOUNCE_FILE = path11.join(SESSION_CACHE, "intercom-debounce.json");
1520
1514
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
1521
1515
  }
@@ -1523,7 +1517,7 @@ var init_tmux_routing = __esm({
1523
1517
 
1524
1518
  // src/lib/tasks-review.ts
1525
1519
  import path12 from "path";
1526
- import { existsSync as existsSync10, readdirSync as readdirSync2, unlinkSync as unlinkSync2 } from "fs";
1520
+ import { existsSync as existsSync10, readdirSync as readdirSync3, unlinkSync as unlinkSync2 } from "fs";
1527
1521
  async function listPendingReviews(limit) {
1528
1522
  const client = getClient();
1529
1523
  const result = await client.execute({
@@ -1550,7 +1544,7 @@ var init_tasks_review = __esm({
1550
1544
  // src/bin/exe-heartbeat.ts
1551
1545
  import { createHash } from "crypto";
1552
1546
  import { readFileSync as readFileSync8, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4 } from "fs";
1553
- import os6 from "os";
1547
+ import os7 from "os";
1554
1548
  import path13 from "path";
1555
1549
 
1556
1550
  // src/lib/store.ts
@@ -1560,11 +1554,12 @@ init_database();
1560
1554
  import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
1561
1555
  import { existsSync } from "fs";
1562
1556
  import path from "path";
1557
+ import os from "os";
1563
1558
  import crypto from "crypto";
1564
1559
  var SERVICE = "exe-mem";
1565
1560
  var ACCOUNT = "master-key";
1566
1561
  function getKeyDir() {
1567
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(process.env.HOME ?? "/tmp", ".exe-os");
1562
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
1568
1563
  }
1569
1564
  function getKeyPath() {
1570
1565
  return path.join(getKeyDir(), "master.key");
@@ -1601,6 +1596,30 @@ async function getMasterKey() {
1601
1596
 
1602
1597
  // src/lib/store.ts
1603
1598
  init_config();
1599
+ var INIT_MAX_RETRIES = 3;
1600
+ var INIT_RETRY_DELAY_MS = 1e3;
1601
+ function isBusyError2(err) {
1602
+ if (err instanceof Error) {
1603
+ const msg = err.message.toLowerCase();
1604
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
1605
+ }
1606
+ return false;
1607
+ }
1608
+ async function retryOnBusy2(fn, label) {
1609
+ for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
1610
+ try {
1611
+ return await fn();
1612
+ } catch (err) {
1613
+ if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
1614
+ process.stderr.write(
1615
+ `[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
1616
+ `
1617
+ );
1618
+ await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
1619
+ }
1620
+ }
1621
+ throw new Error("unreachable");
1622
+ }
1604
1623
  var _pendingRecords = [];
1605
1624
  var _batchSize = 20;
1606
1625
  var _flushIntervalMs = 1e4;
@@ -1635,14 +1654,17 @@ async function initStore(options) {
1635
1654
  dbPath,
1636
1655
  encryptionKey: hexKey
1637
1656
  });
1638
- await ensureSchema();
1657
+ await retryOnBusy2(() => ensureSchema(), "ensureSchema");
1639
1658
  try {
1640
1659
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
1641
1660
  initShardManager2(hexKey);
1642
1661
  } catch {
1643
1662
  }
1644
1663
  const client = getClient();
1645
- const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
1664
+ const vResult = await retryOnBusy2(
1665
+ () => client.execute("SELECT MAX(version) as max_v FROM memories"),
1666
+ "version-query"
1667
+ );
1646
1668
  _nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
1647
1669
  }
1648
1670
 
@@ -1677,7 +1699,7 @@ var MESSAGE_PREVIEW_CHARS = 80;
1677
1699
  var MARKER_FILENAME = "exe-heartbeat-marker.json";
1678
1700
  var SESSION_CACHE_SUBDIR = "session-cache";
1679
1701
  function resolveExeOsDir() {
1680
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path13.join(os6.homedir(), ".exe-os");
1702
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path13.join(os7.homedir(), ".exe-os");
1681
1703
  }
1682
1704
  function getMarkerDir() {
1683
1705
  return path13.join(resolveExeOsDir(), SESSION_CACHE_SUBDIR);
@@ -1,12 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
- }) : x)(function(x) {
7
- if (typeof require !== "undefined") return require.apply(this, arguments);
8
- throw Error('Dynamic require of "' + x + '" is not supported');
9
- });
10
4
  var __esm = (fn, res) => function __init() {
11
5
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
6
  };
@@ -16,15 +10,15 @@ var __export = (target, all) => {
16
10
  };
17
11
 
18
12
  // src/lib/config.ts
19
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
13
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
20
14
  import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
21
15
  import path2 from "path";
22
- import os from "os";
16
+ import os2 from "os";
23
17
  function resolveDataDir() {
24
18
  if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
25
19
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
26
- const newDir = path2.join(os.homedir(), ".exe-os");
27
- const legacyDir = path2.join(os.homedir(), ".exe-mem");
20
+ const newDir = path2.join(os2.homedir(), ".exe-os");
21
+ const legacyDir = path2.join(os2.homedir(), ".exe-mem");
28
22
  if (!existsSync2(newDir) && existsSync2(legacyDir)) {
29
23
  try {
30
24
  renameSync(legacyDir, newDir);
@@ -111,7 +105,7 @@ async function loadConfig() {
111
105
  normalizeAutoUpdate(migratedCfg);
112
106
  const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
113
107
  if (config.dbPath.startsWith("~")) {
114
- config.dbPath = config.dbPath.replace(/^~/, os.homedir());
108
+ config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
115
109
  }
116
110
  return config;
117
111
  } catch {
@@ -218,7 +212,7 @@ __export(shard_manager_exports, {
218
212
  shardExists: () => shardExists
219
213
  });
220
214
  import path3 from "path";
221
- import { existsSync as existsSync3, mkdirSync } from "fs";
215
+ import { existsSync as existsSync3, mkdirSync, readdirSync } from "fs";
222
216
  import { createClient as createClient2 } from "@libsql/client";
223
217
  function initShardManager(encryptionKey) {
224
218
  _encryptionKey = encryptionKey;
@@ -257,7 +251,6 @@ function shardExists(projectName) {
257
251
  }
258
252
  function listShards() {
259
253
  if (!existsSync3(SHARDS_DIR)) return [];
260
- const { readdirSync } = __require("fs");
261
254
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
262
255
  }
263
256
  async function ensureShardSchema(client) {
@@ -536,6 +529,7 @@ async function ensureSchema() {
536
529
  const client = getRawClient();
537
530
  await client.execute("PRAGMA journal_mode = WAL");
538
531
  await client.execute("PRAGMA busy_timeout = 30000");
532
+ await client.execute("PRAGMA wal_autocheckpoint = 1000");
539
533
  try {
540
534
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
541
535
  } catch {
@@ -1337,11 +1331,12 @@ async function disposeDatabase() {
1337
1331
  import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
1338
1332
  import { existsSync } from "fs";
1339
1333
  import path from "path";
1334
+ import os from "os";
1340
1335
  import crypto from "crypto";
1341
1336
  var SERVICE = "exe-mem";
1342
1337
  var ACCOUNT = "master-key";
1343
1338
  function getKeyDir() {
1344
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(process.env.HOME ?? "/tmp", ".exe-os");
1339
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
1345
1340
  }
1346
1341
  function getKeyPath() {
1347
1342
  return path.join(getKeyDir(), "master.key");
@@ -1378,6 +1373,30 @@ async function getMasterKey() {
1378
1373
 
1379
1374
  // src/lib/store.ts
1380
1375
  init_config();
1376
+ var INIT_MAX_RETRIES = 3;
1377
+ var INIT_RETRY_DELAY_MS = 1e3;
1378
+ function isBusyError2(err) {
1379
+ if (err instanceof Error) {
1380
+ const msg = err.message.toLowerCase();
1381
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
1382
+ }
1383
+ return false;
1384
+ }
1385
+ async function retryOnBusy2(fn, label) {
1386
+ for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
1387
+ try {
1388
+ return await fn();
1389
+ } catch (err) {
1390
+ if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
1391
+ process.stderr.write(
1392
+ `[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
1393
+ `
1394
+ );
1395
+ await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
1396
+ }
1397
+ }
1398
+ throw new Error("unreachable");
1399
+ }
1381
1400
  var _pendingRecords = [];
1382
1401
  var _batchSize = 20;
1383
1402
  var _flushIntervalMs = 1e4;
@@ -1412,14 +1431,17 @@ async function initStore(options) {
1412
1431
  dbPath,
1413
1432
  encryptionKey: hexKey
1414
1433
  });
1415
- await ensureSchema();
1434
+ await retryOnBusy2(() => ensureSchema(), "ensureSchema");
1416
1435
  try {
1417
1436
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
1418
1437
  initShardManager2(hexKey);
1419
1438
  } catch {
1420
1439
  }
1421
1440
  const client = getClient();
1422
- const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
1441
+ const vResult = await retryOnBusy2(
1442
+ () => client.execute("SELECT MAX(version) as max_v FROM memories"),
1443
+ "version-query"
1444
+ );
1423
1445
  _nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
1424
1446
  }
1425
1447
  async function flushBatch() {
@@ -1601,8 +1623,8 @@ async function recordSessionKill(input) {
1601
1623
  // src/lib/session-registry.ts
1602
1624
  import { readFileSync as readFileSync2, writeFileSync, mkdirSync as mkdirSync2, existsSync as existsSync4 } from "fs";
1603
1625
  import path4 from "path";
1604
- import os2 from "os";
1605
- var REGISTRY_PATH = path4.join(os2.homedir(), ".exe-os", "session-registry.json");
1626
+ import os3 from "os";
1627
+ var REGISTRY_PATH = path4.join(os3.homedir(), ".exe-os", "session-registry.json");
1606
1628
  function listSessions() {
1607
1629
  try {
1608
1630
  const raw = readFileSync2(REGISTRY_PATH, "utf8");