@askexenow/exe-os 0.9.102 → 0.9.104

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 (92) hide show
  1. package/dist/bin/agentic-ontology-backfill.js +334 -100
  2. package/dist/bin/agentic-reflection-backfill.js +328 -97
  3. package/dist/bin/agentic-semantic-label.js +328 -97
  4. package/dist/bin/backfill-conversations.js +332 -97
  5. package/dist/bin/backfill-responses.js +332 -97
  6. package/dist/bin/backfill-vectors.js +337 -106
  7. package/dist/bin/bulk-sync-postgres.js +335 -101
  8. package/dist/bin/cleanup-stale-review-tasks.js +356 -108
  9. package/dist/bin/cli.js +653 -405
  10. package/dist/bin/exe-agent.js +21 -3
  11. package/dist/bin/exe-assign.js +338 -94
  12. package/dist/bin/exe-boot.js +472 -239
  13. package/dist/bin/exe-call.js +22 -5
  14. package/dist/bin/exe-cloud.js +404 -158
  15. package/dist/bin/exe-dispatch.js +390 -142
  16. package/dist/bin/exe-doctor.js +349 -103
  17. package/dist/bin/exe-export-behaviors.js +351 -105
  18. package/dist/bin/exe-forget.js +352 -103
  19. package/dist/bin/exe-gateway.js +420 -172
  20. package/dist/bin/exe-heartbeat.js +361 -113
  21. package/dist/bin/exe-kill.js +344 -98
  22. package/dist/bin/exe-launch-agent.js +375 -129
  23. package/dist/bin/exe-new-employee.js +83 -67
  24. package/dist/bin/exe-pending-messages.js +356 -108
  25. package/dist/bin/exe-pending-notifications.js +358 -110
  26. package/dist/bin/exe-pending-reviews.js +359 -111
  27. package/dist/bin/exe-rename.js +354 -108
  28. package/dist/bin/exe-review.js +343 -97
  29. package/dist/bin/exe-search.js +363 -113
  30. package/dist/bin/exe-session-cleanup.js +403 -155
  31. package/dist/bin/exe-settings.js +14 -9
  32. package/dist/bin/exe-start-codex.js +365 -131
  33. package/dist/bin/exe-start-opencode.js +359 -125
  34. package/dist/bin/exe-status.js +356 -108
  35. package/dist/bin/exe-team.js +343 -97
  36. package/dist/bin/git-sweep.js +390 -142
  37. package/dist/bin/graph-backfill.js +334 -100
  38. package/dist/bin/graph-export.js +346 -100
  39. package/dist/bin/install.js +1 -0
  40. package/dist/bin/intercom-check.js +403 -155
  41. package/dist/bin/pre-publish.js +12 -0
  42. package/dist/bin/scan-tasks.js +393 -145
  43. package/dist/bin/setup.js +331 -159
  44. package/dist/bin/shard-migrate.js +328 -94
  45. package/dist/gateway/index.js +406 -158
  46. package/dist/hooks/bug-report-worker.js +396 -148
  47. package/dist/hooks/codex-stop-task-finalizer.js +374 -126
  48. package/dist/hooks/commit-complete.js +390 -142
  49. package/dist/hooks/error-recall.js +365 -115
  50. package/dist/hooks/ingest.js +357 -111
  51. package/dist/hooks/instructions-loaded.js +351 -105
  52. package/dist/hooks/notification.js +343 -97
  53. package/dist/hooks/post-compact.js +358 -110
  54. package/dist/hooks/post-tool-combined.js +384 -132
  55. package/dist/hooks/pre-compact.js +391 -143
  56. package/dist/hooks/pre-tool-use.js +362 -114
  57. package/dist/hooks/prompt-submit.js +422 -170
  58. package/dist/hooks/session-end.js +393 -145
  59. package/dist/hooks/session-start.js +390 -138
  60. package/dist/hooks/stop.js +361 -113
  61. package/dist/hooks/subagent-stop.js +354 -106
  62. package/dist/hooks/summary-worker.js +418 -185
  63. package/dist/index.js +400 -152
  64. package/dist/lib/cloud-sync.js +291 -131
  65. package/dist/lib/consolidation.js +8 -2
  66. package/dist/lib/database.js +233 -73
  67. package/dist/lib/db.js +233 -73
  68. package/dist/lib/device-registry.js +237 -77
  69. package/dist/lib/employee-templates.js +19 -1
  70. package/dist/lib/exe-daemon.js +705 -409
  71. package/dist/lib/hybrid-search.js +363 -113
  72. package/dist/lib/identity.js +9 -5
  73. package/dist/lib/messaging.js +26 -20
  74. package/dist/lib/reminders.js +5 -1
  75. package/dist/lib/schedules.js +320 -89
  76. package/dist/lib/skill-learning.js +28 -24
  77. package/dist/lib/store.js +342 -96
  78. package/dist/lib/tasks.js +82 -76
  79. package/dist/lib/tmux-routing.js +74 -68
  80. package/dist/lib/token-spend.js +5 -1
  81. package/dist/mcp/server.js +628 -355
  82. package/dist/mcp/tools/complete-reminder.js +5 -1
  83. package/dist/mcp/tools/create-reminder.js +5 -1
  84. package/dist/mcp/tools/create-task.js +89 -83
  85. package/dist/mcp/tools/deactivate-behavior.js +7 -3
  86. package/dist/mcp/tools/list-reminders.js +5 -1
  87. package/dist/mcp/tools/list-tasks.js +28 -21
  88. package/dist/mcp/tools/send-message.js +28 -22
  89. package/dist/mcp/tools/update-task.js +89 -83
  90. package/dist/runtime/index.js +390 -142
  91. package/dist/tui/App.js +437 -189
  92. package/package.json +1 -1
@@ -1594,9 +1594,79 @@ __export(database_exports, {
1594
1594
  isInitialized: () => isInitialized,
1595
1595
  setExternalClient: () => setExternalClient
1596
1596
  });
1597
- import { chmodSync as chmodSync2 } from "fs";
1597
+ import { chmodSync as chmodSync2, existsSync as existsSync6, statSync as statSync2, copyFileSync, unlinkSync as unlinkSync3, openSync as openSync2, closeSync as closeSync2, mkdirSync as mkdirSync2 } from "fs";
1598
1598
  import { createClient } from "@libsql/client";
1599
+ import { homedir } from "os";
1600
+ import { join } from "path";
1601
+ function logCatchDebug(context, err) {
1602
+ if (_debugDb) {
1603
+ process.stderr.write(
1604
+ `[database] ${context}: ${err instanceof Error ? err.message : String(err)}
1605
+ `
1606
+ );
1607
+ }
1608
+ }
1609
+ function acquireDbLock() {
1610
+ mkdirSync2(join(homedir(), ".exe-os"), { recursive: true });
1611
+ try {
1612
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
1613
+ } catch (err) {
1614
+ if (err && typeof err === "object" && "code" in err && err.code === "EEXIST") {
1615
+ try {
1616
+ const lockStat = statSync2(DB_LOCK_PATH);
1617
+ if (Date.now() - lockStat.mtimeMs > 6e4) {
1618
+ unlinkSync3(DB_LOCK_PATH);
1619
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
1620
+ return;
1621
+ }
1622
+ } catch (e) {
1623
+ logCatchDebug("stale lock check", e);
1624
+ }
1625
+ process.stderr.write(
1626
+ "[database] WARN: Another process holds db.lock \u2014 waiting briefly then proceeding.\n"
1627
+ );
1628
+ return;
1629
+ }
1630
+ throw err;
1631
+ }
1632
+ }
1633
+ function releaseDbLock() {
1634
+ if (_lockFd !== null) {
1635
+ try {
1636
+ closeSync2(_lockFd);
1637
+ } catch (e) {
1638
+ logCatchDebug("lock close", e);
1639
+ }
1640
+ _lockFd = null;
1641
+ }
1642
+ try {
1643
+ unlinkSync3(DB_LOCK_PATH);
1644
+ } catch (e) {
1645
+ logCatchDebug("lock unlink", e);
1646
+ }
1647
+ }
1599
1648
  async function initDatabase(config) {
1649
+ acquireDbLock();
1650
+ if (existsSync6(config.dbPath)) {
1651
+ const dbStat = statSync2(config.dbPath);
1652
+ if (dbStat.size === 0) {
1653
+ const walPath = config.dbPath + "-wal";
1654
+ if (existsSync6(walPath) && statSync2(walPath).size > 0) {
1655
+ const backupPath = config.dbPath + ".zeroed-" + Date.now();
1656
+ copyFileSync(config.dbPath, backupPath);
1657
+ unlinkSync3(config.dbPath);
1658
+ process.stderr.write(
1659
+ `[database] CRITICAL: DB was 0 bytes. Moved to ${backupPath}, attempting WAL recovery.
1660
+ `
1661
+ );
1662
+ } else {
1663
+ process.stderr.write(
1664
+ `[database] CRITICAL: DB is 0 bytes and no WAL available for recovery. Data may be lost. Check backups at ${config.dbPath}.bak
1665
+ `
1666
+ );
1667
+ }
1668
+ }
1669
+ }
1600
1670
  if (_walCheckpointTimer) {
1601
1671
  clearInterval(_walCheckpointTimer);
1602
1672
  _walCheckpointTimer = null;
@@ -1623,10 +1693,8 @@ async function initDatabase(config) {
1623
1693
  _client = createClient(opts);
1624
1694
  _resilientClient = wrapWithRetry(_client);
1625
1695
  _adapterClient = _resilientClient;
1626
- _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
1627
- });
1628
- _client.execute("PRAGMA journal_mode = WAL").catch(() => {
1629
- });
1696
+ await _client.execute("PRAGMA busy_timeout = 30000");
1697
+ await _client.execute("PRAGMA journal_mode = WAL");
1630
1698
  if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
1631
1699
  _walCheckpointTimer = setInterval(() => {
1632
1700
  _client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
@@ -1641,11 +1709,16 @@ async function initDatabase(config) {
1641
1709
  for (const suffix of ["-wal", "-shm"]) {
1642
1710
  try {
1643
1711
  chmodSync2(config.dbPath + suffix, 384);
1644
- } catch {
1712
+ } catch (chmodErr) {
1713
+ process.stderr.write(`[database] chmod ${suffix} failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
1714
+ `);
1645
1715
  }
1646
1716
  }
1647
- } catch {
1717
+ } catch (chmodErr) {
1718
+ process.stderr.write(`[database] chmod db failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
1719
+ `);
1648
1720
  }
1721
+ releaseDbLock();
1649
1722
  }
1650
1723
  function isInitialized() {
1651
1724
  return _adapterClient !== null || _client !== null;
@@ -1700,7 +1773,8 @@ async function ensureSchema() {
1700
1773
  await client.execute("PRAGMA wal_autocheckpoint = 1000");
1701
1774
  try {
1702
1775
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
1703
- } catch {
1776
+ } catch (e) {
1777
+ logCatchDebug("migration", e);
1704
1778
  }
1705
1779
  await client.executeMultiple(`
1706
1780
  CREATE TABLE IF NOT EXISTS memories (
@@ -1765,6 +1839,23 @@ async function ensureSchema() {
1765
1839
  INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
1766
1840
  END;
1767
1841
  `);
1842
+ try {
1843
+ await client.execute("SELECT COUNT(*) FROM memories_fts LIMIT 1");
1844
+ } catch (ftsErr) {
1845
+ process.stderr.write(
1846
+ `[database] WARN: memories_fts corrupted (${ftsErr instanceof Error ? ftsErr.message : String(ftsErr)}) \u2014 rebuilding FTS index.
1847
+ `
1848
+ );
1849
+ try {
1850
+ await client.execute("INSERT INTO memories_fts(memories_fts) VALUES('rebuild')");
1851
+ process.stderr.write("[database] FTS index rebuilt successfully.\n");
1852
+ } catch (rebuildErr) {
1853
+ process.stderr.write(
1854
+ `[database] ERROR: FTS rebuild failed: ${rebuildErr instanceof Error ? rebuildErr.message : String(rebuildErr)}
1855
+ `
1856
+ );
1857
+ }
1858
+ }
1768
1859
  await client.executeMultiple(`
1769
1860
  CREATE TABLE IF NOT EXISTS sync_meta (
1770
1861
  key TEXT PRIMARY KEY,
@@ -1823,35 +1914,40 @@ async function ensureSchema() {
1823
1914
  });
1824
1915
  }
1825
1916
  }
1826
- } catch {
1917
+ } catch (seedErr) {
1918
+ logCatchDebug("behavior seed", seedErr);
1827
1919
  }
1828
1920
  try {
1829
1921
  await client.execute({
1830
1922
  sql: `ALTER TABLE behaviors ADD COLUMN priority TEXT DEFAULT 'p1'`,
1831
1923
  args: []
1832
1924
  });
1833
- } catch {
1925
+ } catch (e) {
1926
+ logCatchDebug("migration", e);
1834
1927
  }
1835
1928
  try {
1836
1929
  await client.execute({
1837
1930
  sql: `ALTER TABLE behaviors ADD COLUMN vector F32_BLOB(${EMBEDDING_DIM})`,
1838
1931
  args: []
1839
1932
  });
1840
- } catch {
1933
+ } catch (e) {
1934
+ logCatchDebug("migration", e);
1841
1935
  }
1842
1936
  try {
1843
1937
  await client.execute({
1844
1938
  sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
1845
1939
  args: []
1846
1940
  });
1847
- } catch {
1941
+ } catch (e) {
1942
+ logCatchDebug("migration", e);
1848
1943
  }
1849
1944
  try {
1850
1945
  await client.execute({
1851
1946
  sql: `ALTER TABLE tasks ADD COLUMN parent_task_id TEXT`,
1852
1947
  args: []
1853
1948
  });
1854
- } catch {
1949
+ } catch (e) {
1950
+ logCatchDebug("migration", e);
1855
1951
  }
1856
1952
  try {
1857
1953
  await client.execute({
@@ -1860,98 +1956,112 @@ async function ensureSchema() {
1860
1956
  WHERE parent_task_id IS NOT NULL`,
1861
1957
  args: []
1862
1958
  });
1863
- } catch {
1959
+ } catch (e) {
1960
+ logCatchDebug("migration", e);
1864
1961
  }
1865
1962
  try {
1866
1963
  await client.execute({
1867
1964
  sql: `UPDATE tasks SET status = 'done' WHERE status = 'completed'`,
1868
1965
  args: []
1869
1966
  });
1870
- } catch {
1967
+ } catch (e) {
1968
+ logCatchDebug("migration", e);
1871
1969
  }
1872
1970
  try {
1873
1971
  await client.execute({
1874
1972
  sql: `ALTER TABLE tasks ADD COLUMN reviewer TEXT`,
1875
1973
  args: []
1876
1974
  });
1877
- } catch {
1975
+ } catch (e) {
1976
+ logCatchDebug("migration", e);
1878
1977
  }
1879
1978
  try {
1880
1979
  await client.execute({
1881
1980
  sql: `ALTER TABLE tasks ADD COLUMN context TEXT`,
1882
1981
  args: []
1883
1982
  });
1884
- } catch {
1983
+ } catch (e) {
1984
+ logCatchDebug("migration", e);
1885
1985
  }
1886
1986
  try {
1887
1987
  await client.execute({
1888
1988
  sql: `ALTER TABLE tasks ADD COLUMN result TEXT`,
1889
1989
  args: []
1890
1990
  });
1891
- } catch {
1991
+ } catch (e) {
1992
+ logCatchDebug("migration", e);
1892
1993
  }
1893
1994
  try {
1894
1995
  await client.execute({
1895
1996
  sql: `ALTER TABLE tasks ADD COLUMN assigned_tmux TEXT`,
1896
1997
  args: []
1897
1998
  });
1898
- } catch {
1999
+ } catch (e) {
2000
+ logCatchDebug("migration", e);
1899
2001
  }
1900
2002
  try {
1901
2003
  await client.execute({
1902
2004
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint TEXT`,
1903
2005
  args: []
1904
2006
  });
1905
- } catch {
2007
+ } catch (e) {
2008
+ logCatchDebug("migration", e);
1906
2009
  }
1907
2010
  try {
1908
2011
  await client.execute({
1909
2012
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER NOT NULL DEFAULT 0`,
1910
2013
  args: []
1911
2014
  });
1912
- } catch {
2015
+ } catch (e) {
2016
+ logCatchDebug("migration", e);
1913
2017
  }
1914
2018
  try {
1915
2019
  await client.execute({
1916
2020
  sql: `ALTER TABLE tasks ADD COLUMN complexity TEXT NOT NULL DEFAULT 'standard'`,
1917
2021
  args: []
1918
2022
  });
1919
- } catch {
2023
+ } catch (e) {
2024
+ logCatchDebug("migration", e);
1920
2025
  }
1921
2026
  try {
1922
2027
  await client.execute({
1923
2028
  sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
1924
2029
  args: []
1925
2030
  });
1926
- } catch {
2031
+ } catch (e) {
2032
+ logCatchDebug("migration", e);
1927
2033
  }
1928
2034
  try {
1929
2035
  await client.execute({
1930
2036
  sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
1931
2037
  args: []
1932
2038
  });
1933
- } catch {
2039
+ } catch (e) {
2040
+ logCatchDebug("migration", e);
1934
2041
  }
1935
2042
  try {
1936
2043
  await client.execute({
1937
2044
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
1938
2045
  args: []
1939
2046
  });
1940
- } catch {
2047
+ } catch (e) {
2048
+ logCatchDebug("migration", e);
1941
2049
  }
1942
2050
  try {
1943
2051
  await client.execute({
1944
2052
  sql: `ALTER TABLE memories ADD COLUMN author_device_id TEXT`,
1945
2053
  args: []
1946
2054
  });
1947
- } catch {
2055
+ } catch (e) {
2056
+ logCatchDebug("migration", e);
1948
2057
  }
1949
2058
  try {
1950
2059
  await client.execute({
1951
2060
  sql: `ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'`,
1952
2061
  args: []
1953
2062
  });
1954
- } catch {
2063
+ } catch (e) {
2064
+ logCatchDebug("migration", e);
1955
2065
  }
1956
2066
  await client.executeMultiple(`
1957
2067
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2056,14 +2166,16 @@ async function ensureSchema() {
2056
2166
  sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
2057
2167
  args: []
2058
2168
  });
2059
- } catch {
2169
+ } catch (e) {
2170
+ logCatchDebug("migration", e);
2060
2171
  }
2061
2172
  try {
2062
2173
  await client.execute({
2063
2174
  sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
2064
2175
  args: []
2065
2176
  });
2066
- } catch {
2177
+ } catch (e) {
2178
+ logCatchDebug("migration", e);
2067
2179
  }
2068
2180
  await client.executeMultiple(`
2069
2181
  CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
@@ -2089,7 +2201,8 @@ async function ensureSchema() {
2089
2201
  sql: `UPDATE tasks SET project_name = 'exe-os' WHERE project_name = 'worker'`,
2090
2202
  args: []
2091
2203
  });
2092
- } catch {
2204
+ } catch (e) {
2205
+ logCatchDebug("migration", e);
2093
2206
  }
2094
2207
  await client.executeMultiple(`
2095
2208
  CREATE TABLE IF NOT EXISTS trajectories (
@@ -2113,7 +2226,8 @@ async function ensureSchema() {
2113
2226
  `);
2114
2227
  try {
2115
2228
  await client.execute("ALTER TABLE trajectories ADD COLUMN skill_id TEXT");
2116
- } catch {
2229
+ } catch (e) {
2230
+ logCatchDebug("migration", e);
2117
2231
  }
2118
2232
  await client.executeMultiple(`
2119
2233
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2150,63 +2264,72 @@ async function ensureSchema() {
2150
2264
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
2151
2265
  args: []
2152
2266
  });
2153
- } catch {
2267
+ } catch (e) {
2268
+ logCatchDebug("migration", e);
2154
2269
  }
2155
2270
  try {
2156
2271
  await client.execute({
2157
2272
  sql: `ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5`,
2158
2273
  args: []
2159
2274
  });
2160
- } catch {
2275
+ } catch (e) {
2276
+ logCatchDebug("migration", e);
2161
2277
  }
2162
2278
  try {
2163
2279
  await client.execute({
2164
2280
  sql: `ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'`,
2165
2281
  args: []
2166
2282
  });
2167
- } catch {
2283
+ } catch (e) {
2284
+ logCatchDebug("migration", e);
2168
2285
  }
2169
2286
  try {
2170
2287
  await client.execute({
2171
2288
  sql: `ALTER TABLE memories ADD COLUMN deleted_at TEXT`,
2172
2289
  args: []
2173
2290
  });
2174
- } catch {
2291
+ } catch (e) {
2292
+ logCatchDebug("migration", e);
2175
2293
  }
2176
2294
  try {
2177
2295
  await client.execute({
2178
2296
  sql: `ALTER TABLE memories ADD COLUMN confidence REAL DEFAULT 0.7`,
2179
2297
  args: []
2180
2298
  });
2181
- } catch {
2299
+ } catch (e) {
2300
+ logCatchDebug("migration", e);
2182
2301
  }
2183
2302
  try {
2184
2303
  await client.execute({
2185
2304
  sql: `ALTER TABLE memories ADD COLUMN last_accessed TEXT`,
2186
2305
  args: []
2187
2306
  });
2188
- } catch {
2307
+ } catch (e) {
2308
+ logCatchDebug("migration", e);
2189
2309
  }
2190
2310
  try {
2191
2311
  await client.execute({
2192
2312
  sql: `UPDATE memories SET last_accessed = timestamp WHERE last_accessed IS NULL`,
2193
2313
  args: []
2194
2314
  });
2195
- } catch {
2315
+ } catch (e) {
2316
+ logCatchDebug("migration", e);
2196
2317
  }
2197
2318
  try {
2198
2319
  await client.execute({
2199
2320
  sql: `ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0`,
2200
2321
  args: []
2201
2322
  });
2202
- } catch {
2323
+ } catch (e) {
2324
+ logCatchDebug("migration", e);
2203
2325
  }
2204
2326
  try {
2205
2327
  await client.execute({
2206
2328
  sql: `ALTER TABLE memories ADD COLUMN graph_extracted INTEGER DEFAULT 0`,
2207
2329
  args: []
2208
2330
  });
2209
- } catch {
2331
+ } catch (e) {
2332
+ logCatchDebug("migration", e);
2210
2333
  }
2211
2334
  for (const col of [
2212
2335
  "ALTER TABLE memories ADD COLUMN content_hash TEXT",
@@ -2214,14 +2337,16 @@ async function ensureSchema() {
2214
2337
  ]) {
2215
2338
  try {
2216
2339
  await client.execute(col);
2217
- } catch {
2340
+ } catch (e) {
2341
+ logCatchDebug("migration", e);
2218
2342
  }
2219
2343
  }
2220
2344
  try {
2221
2345
  await client.execute(
2222
2346
  `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
2223
2347
  );
2224
- } catch {
2348
+ } catch (e) {
2349
+ logCatchDebug("migration", e);
2225
2350
  }
2226
2351
  try {
2227
2352
  await client.execute(
@@ -2229,7 +2354,8 @@ async function ensureSchema() {
2229
2354
  ON memories(content_hash, agent_id, project_name, memory_type)
2230
2355
  WHERE content_hash IS NOT NULL`
2231
2356
  );
2232
- } catch {
2357
+ } catch (e) {
2358
+ logCatchDebug("migration", e);
2233
2359
  }
2234
2360
  await client.executeMultiple(`
2235
2361
  CREATE TABLE IF NOT EXISTS entities (
@@ -2305,7 +2431,8 @@ async function ensureSchema() {
2305
2431
  `);
2306
2432
  try {
2307
2433
  await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
2308
- } catch {
2434
+ } catch (e) {
2435
+ logCatchDebug("migration", e);
2309
2436
  }
2310
2437
  await client.executeMultiple(`
2311
2438
  CREATE TABLE IF NOT EXISTS entity_aliases (
@@ -2320,14 +2447,16 @@ async function ensureSchema() {
2320
2447
  ]) {
2321
2448
  try {
2322
2449
  await client.execute(col);
2323
- } catch {
2450
+ } catch (e) {
2451
+ logCatchDebug("migration", e);
2324
2452
  }
2325
2453
  }
2326
2454
  try {
2327
2455
  await client.execute(
2328
2456
  `CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)`
2329
2457
  );
2330
- } catch {
2458
+ } catch (e) {
2459
+ logCatchDebug("migration", e);
2331
2460
  }
2332
2461
  await client.executeMultiple(`
2333
2462
  CREATE TABLE IF NOT EXISTS identity (
@@ -2426,7 +2555,8 @@ async function ensureSchema() {
2426
2555
  sql: `ALTER TABLE memories ADD COLUMN ${column}`,
2427
2556
  args: []
2428
2557
  });
2429
- } catch {
2558
+ } catch (e) {
2559
+ logCatchDebug("migration", e);
2430
2560
  }
2431
2561
  }
2432
2562
  for (const col of [
@@ -2435,7 +2565,8 @@ async function ensureSchema() {
2435
2565
  ]) {
2436
2566
  try {
2437
2567
  await client.execute(col);
2438
- } catch {
2568
+ } catch (e) {
2569
+ logCatchDebug("migration", e);
2439
2570
  }
2440
2571
  }
2441
2572
  await client.executeMultiple(`
@@ -2620,56 +2751,64 @@ async function ensureSchema() {
2620
2751
  args: []
2621
2752
  });
2622
2753
  }
2623
- } catch {
2754
+ } catch (e) {
2755
+ logCatchDebug("session_agent_map backfill", e);
2624
2756
  }
2625
2757
  try {
2626
2758
  await client.execute({
2627
2759
  sql: `ALTER TABLE session_agent_map ADD COLUMN cache_cold_count INTEGER NOT NULL DEFAULT 0`,
2628
2760
  args: []
2629
2761
  });
2630
- } catch {
2762
+ } catch (e) {
2763
+ logCatchDebug("migration", e);
2631
2764
  }
2632
2765
  try {
2633
2766
  await client.execute({
2634
2767
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
2635
2768
  args: []
2636
2769
  });
2637
- } catch {
2770
+ } catch (e) {
2771
+ logCatchDebug("migration", e);
2638
2772
  }
2639
2773
  try {
2640
2774
  await client.execute({
2641
2775
  sql: `ALTER TABLE tasks ADD COLUMN budget_fallback_model TEXT`,
2642
2776
  args: []
2643
2777
  });
2644
- } catch {
2778
+ } catch (e) {
2779
+ logCatchDebug("migration", e);
2645
2780
  }
2646
2781
  try {
2647
2782
  await client.execute({
2648
2783
  sql: `ALTER TABLE tasks ADD COLUMN tokens_used INTEGER DEFAULT 0`,
2649
2784
  args: []
2650
2785
  });
2651
- } catch {
2786
+ } catch (e) {
2787
+ logCatchDebug("migration", e);
2652
2788
  }
2653
2789
  try {
2654
2790
  await client.execute({
2655
2791
  sql: `ALTER TABLE tasks ADD COLUMN tokens_warned_at INTEGER`,
2656
2792
  args: []
2657
2793
  });
2658
- } catch {
2794
+ } catch (e) {
2795
+ logCatchDebug("migration", e);
2659
2796
  }
2660
2797
  try {
2661
2798
  await client.execute({
2662
2799
  sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
2663
2800
  args: []
2664
2801
  });
2665
- } catch {
2802
+ } catch (e) {
2803
+ logCatchDebug("migration", e);
2666
2804
  }
2667
2805
  try {
2668
2806
  await client.execute({
2669
2807
  sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
2670
2808
  args: []
2671
2809
  });
2672
- } catch {
2810
+ } catch (e) {
2811
+ logCatchDebug("migration", e);
2673
2812
  }
2674
2813
  await client.executeMultiple(`
2675
2814
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
@@ -2868,13 +3007,15 @@ async function ensureSchema() {
2868
3007
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
2869
3008
  args: []
2870
3009
  });
2871
- } catch {
3010
+ } catch (e) {
3011
+ logCatchDebug("migration", e);
2872
3012
  }
2873
3013
  try {
2874
3014
  await client.execute(
2875
3015
  `CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
2876
3016
  );
2877
- } catch {
3017
+ } catch (e) {
3018
+ logCatchDebug("migration", e);
2878
3019
  }
2879
3020
  try {
2880
3021
  await client.execute({
@@ -2885,20 +3026,23 @@ async function ensureSchema() {
2885
3026
  sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
2886
3027
  args: []
2887
3028
  });
2888
- } catch {
3029
+ } catch (e) {
3030
+ logCatchDebug("migration", e);
2889
3031
  }
2890
3032
  try {
2891
3033
  await client.execute({
2892
3034
  sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
2893
3035
  args: []
2894
3036
  });
2895
- } catch {
3037
+ } catch (e) {
3038
+ logCatchDebug("migration", e);
2896
3039
  }
2897
3040
  try {
2898
3041
  await client.execute(
2899
3042
  `CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
2900
3043
  );
2901
- } catch {
3044
+ } catch (e) {
3045
+ logCatchDebug("migration", e);
2902
3046
  }
2903
3047
  for (const col of [
2904
3048
  "ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
@@ -2906,7 +3050,8 @@ async function ensureSchema() {
2906
3050
  ]) {
2907
3051
  try {
2908
3052
  await client.execute(col);
2909
- } catch {
3053
+ } catch (e) {
3054
+ logCatchDebug("migration", e);
2910
3055
  }
2911
3056
  }
2912
3057
  try {
@@ -2914,13 +3059,15 @@ async function ensureSchema() {
2914
3059
  sql: `ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0`,
2915
3060
  args: []
2916
3061
  });
2917
- } catch {
3062
+ } catch (e) {
3063
+ logCatchDebug("migration", e);
2918
3064
  }
2919
3065
  try {
2920
3066
  await client.execute(
2921
3067
  `CREATE INDEX IF NOT EXISTS idx_memories_draft ON memories(draft) WHERE draft = 1`
2922
3068
  );
2923
- } catch {
3069
+ } catch (e) {
3070
+ logCatchDebug("migration", e);
2924
3071
  }
2925
3072
  for (const col of [
2926
3073
  "ALTER TABLE memories ADD COLUMN valid_from TEXT",
@@ -2928,7 +3075,8 @@ async function ensureSchema() {
2928
3075
  ]) {
2929
3076
  try {
2930
3077
  await client.execute(col);
2931
- } catch {
3078
+ } catch (e) {
3079
+ logCatchDebug("migration", e);
2932
3080
  }
2933
3081
  }
2934
3082
  try {
@@ -2936,27 +3084,31 @@ async function ensureSchema() {
2936
3084
  sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
2937
3085
  args: []
2938
3086
  });
2939
- } catch {
3087
+ } catch (e) {
3088
+ logCatchDebug("migration", e);
2940
3089
  }
2941
3090
  try {
2942
3091
  await client.execute({
2943
3092
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
2944
3093
  args: []
2945
3094
  });
2946
- } catch {
3095
+ } catch (e) {
3096
+ logCatchDebug("migration", e);
2947
3097
  }
2948
3098
  try {
2949
3099
  await client.execute(
2950
3100
  `CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(memory_type)`
2951
3101
  );
2952
- } catch {
3102
+ } catch (e) {
3103
+ logCatchDebug("migration", e);
2953
3104
  }
2954
3105
  try {
2955
3106
  await client.execute({
2956
3107
  sql: `ALTER TABLE memories ADD COLUMN trajectory TEXT`,
2957
3108
  args: []
2958
3109
  });
2959
- } catch {
3110
+ } catch (e) {
3111
+ logCatchDebug("migration", e);
2960
3112
  }
2961
3113
  for (const col of [
2962
3114
  "ALTER TABLE memories ADD COLUMN intent TEXT",
@@ -2977,7 +3129,8 @@ async function ensureSchema() {
2977
3129
  ]) {
2978
3130
  try {
2979
3131
  await client.execute(col);
2980
- } catch {
3132
+ } catch (e) {
3133
+ logCatchDebug("migration", e);
2981
3134
  }
2982
3135
  }
2983
3136
  try {
@@ -2985,14 +3138,16 @@ async function ensureSchema() {
2985
3138
  sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
2986
3139
  args: []
2987
3140
  });
2988
- } catch {
3141
+ } catch (e) {
3142
+ logCatchDebug("migration", e);
2989
3143
  }
2990
3144
  try {
2991
3145
  await client.execute({
2992
3146
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
2993
3147
  args: []
2994
3148
  });
2995
- } catch {
3149
+ } catch (e) {
3150
+ logCatchDebug("migration", e);
2996
3151
  }
2997
3152
  }
2998
3153
  async function disposeDatabase() {
@@ -3003,7 +3158,8 @@ async function disposeDatabase() {
3003
3158
  if (_client) {
3004
3159
  try {
3005
3160
  await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3006
- } catch {
3161
+ } catch (e) {
3162
+ logCatchDebug("WAL checkpoint", e);
3007
3163
  }
3008
3164
  }
3009
3165
  if (_daemonClient) {
@@ -3019,8 +3175,9 @@ async function disposeDatabase() {
3019
3175
  _client = null;
3020
3176
  _resilientClient = null;
3021
3177
  }
3178
+ releaseDbLock();
3022
3179
  }
3023
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
3180
+ var _debugDb, _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, _lockFd, DB_LOCK_PATH, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
3024
3181
  var init_database = __esm({
3025
3182
  "src/lib/database.ts"() {
3026
3183
  "use strict";
@@ -3028,11 +3185,14 @@ var init_database = __esm({
3028
3185
  init_employees();
3029
3186
  init_database_adapter();
3030
3187
  init_memory();
3188
+ _debugDb = process.env.EXE_DEBUG === "1";
3031
3189
  _client = null;
3032
3190
  _resilientClient = null;
3033
3191
  _walCheckpointTimer = null;
3034
3192
  _daemonClient = null;
3035
3193
  _adapterClient = null;
3194
+ _lockFd = null;
3195
+ DB_LOCK_PATH = join(homedir(), ".exe-os", "db.lock");
3036
3196
  initTurso = initDatabase;
3037
3197
  SOFT_DELETE_RETENTION_DAYS = 7;
3038
3198
  disposeTurso = disposeDatabase;
@@ -3055,18 +3215,54 @@ __export(shard_manager_exports, {
3055
3215
  shardExists: () => shardExists
3056
3216
  });
3057
3217
  import path7 from "path";
3058
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync3 } from "fs";
3218
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3, readdirSync, renameSync as renameSync3, statSync as statSync4 } from "fs";
3059
3219
  import { createClient as createClient2 } from "@libsql/client";
3060
3220
  function initShardManager(encryptionKey) {
3061
3221
  _encryptionKey = encryptionKey;
3062
- if (!existsSync7(SHARDS_DIR)) {
3063
- mkdirSync2(SHARDS_DIR, { recursive: true });
3222
+ _keyValidated = false;
3223
+ _keyValidationPromise = null;
3224
+ if (!existsSync8(SHARDS_DIR)) {
3225
+ mkdirSync3(SHARDS_DIR, { recursive: true });
3226
+ }
3227
+ const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
3228
+ if (existingShards.length === 0) {
3229
+ _keyValidated = true;
3064
3230
  }
3065
3231
  _shardingEnabled = true;
3066
3232
  if (_evictionTimer) clearInterval(_evictionTimer);
3067
3233
  _evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
3068
3234
  _evictionTimer.unref();
3069
3235
  }
3236
+ async function validateEncryptionKey() {
3237
+ if (_keyValidated) return true;
3238
+ if (!_encryptionKey) return false;
3239
+ const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
3240
+ if (existingShards.length === 0) {
3241
+ _keyValidated = true;
3242
+ return true;
3243
+ }
3244
+ for (const shardFile of existingShards.slice(0, 3)) {
3245
+ const dbPath = path7.join(SHARDS_DIR, shardFile);
3246
+ const testClient = createClient2({ url: `file:${dbPath}`, encryptionKey: _encryptionKey });
3247
+ try {
3248
+ await testClient.execute("SELECT COUNT(*) FROM sqlite_schema");
3249
+ testClient.close();
3250
+ _keyValidated = true;
3251
+ return true;
3252
+ } catch {
3253
+ try {
3254
+ testClient.close();
3255
+ } catch {
3256
+ }
3257
+ }
3258
+ }
3259
+ process.stderr.write(
3260
+ `[shard-manager] WARNING: encryption key cannot read any existing shards (${existingShards.length} found). New shard creation disabled to prevent stranded files. Run /exe-doctor to audit.
3261
+ `
3262
+ );
3263
+ _shardingEnabled = false;
3264
+ return false;
3265
+ }
3070
3266
  function isShardingEnabled() {
3071
3267
  return _shardingEnabled;
3072
3268
  }
@@ -3100,13 +3296,13 @@ function getShardClient(projectName) {
3100
3296
  }
3101
3297
  function shardExists(projectName) {
3102
3298
  const safeName = safeShardName(projectName);
3103
- return existsSync7(path7.join(SHARDS_DIR, `${safeName}.db`));
3299
+ return existsSync8(path7.join(SHARDS_DIR, `${safeName}.db`));
3104
3300
  }
3105
3301
  function safeShardName(projectName) {
3106
3302
  return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3107
3303
  }
3108
3304
  function listShards() {
3109
- if (!existsSync7(SHARDS_DIR)) return [];
3305
+ if (!existsSync8(SHARDS_DIR)) return [];
3110
3306
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
3111
3307
  }
3112
3308
  async function auditShardHealth(options = {}) {
@@ -3119,7 +3315,7 @@ async function auditShardHealth(options = {}) {
3119
3315
  const shards = [];
3120
3316
  for (const name of names) {
3121
3317
  const dbPath = path7.join(SHARDS_DIR, `${name}.db`);
3122
- const stat = statSync3(dbPath);
3318
+ const stat = statSync4(dbPath);
3123
3319
  const item = {
3124
3320
  name,
3125
3321
  path: dbPath,
@@ -3359,6 +3555,17 @@ async function ensureShardSchema(client) {
3359
3555
  }
3360
3556
  }
3361
3557
  async function getReadyShardClient(projectName) {
3558
+ if (!_keyValidated) {
3559
+ if (!_keyValidationPromise) {
3560
+ _keyValidationPromise = validateEncryptionKey();
3561
+ }
3562
+ const valid = await _keyValidationPromise;
3563
+ if (!valid) {
3564
+ throw new Error(
3565
+ `Shard creation blocked: encryption key mismatch with existing shards. Run /exe-doctor to audit.`
3566
+ );
3567
+ }
3568
+ }
3362
3569
  const safeName = safeShardName(projectName);
3363
3570
  let client = getShardClient(projectName);
3364
3571
  try {
@@ -3371,8 +3578,8 @@ async function getReadyShardClient(projectName) {
3371
3578
  _shards.delete(safeName);
3372
3579
  _shardLastAccess.delete(safeName);
3373
3580
  const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
3374
- if (existsSync7(dbPath)) {
3375
- const stat = statSync3(dbPath);
3581
+ if (existsSync8(dbPath)) {
3582
+ const stat = statSync4(dbPath);
3376
3583
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3377
3584
  const archivedPath = path7.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
3378
3585
  renameSync3(dbPath, archivedPath);
@@ -3437,7 +3644,7 @@ function disposeShards() {
3437
3644
  _shardingEnabled = false;
3438
3645
  _encryptionKey = null;
3439
3646
  }
3440
- var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
3647
+ var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled, _keyValidated, _keyValidationPromise;
3441
3648
  var init_shard_manager = __esm({
3442
3649
  "src/lib/shard-manager.ts"() {
3443
3650
  "use strict";
@@ -3451,6 +3658,8 @@ var init_shard_manager = __esm({
3451
3658
  _evictionTimer = null;
3452
3659
  _encryptionKey = null;
3453
3660
  _shardingEnabled = false;
3661
+ _keyValidated = false;
3662
+ _keyValidationPromise = null;
3454
3663
  }
3455
3664
  });
3456
3665
 
@@ -3646,6 +3855,18 @@ var init_platform_procedures = __esm({
3646
3855
  priority: "p0",
3647
3856
  content: "create_task is dispatch + delivery. Task lifecycle: open \u2192 in_progress (you start) \u2192 done (update_task when finished) \u2192 needs_review (reviewer nudged) \u2192 closed (COO only via close_task). DB is the reliable delivery \u2014 intercom is just a speedup nudge. If you finish a task, self-chain: check for next task immediately (step 7). Never wait for a nudge. Never say 'standing by.'"
3648
3857
  },
3858
+ {
3859
+ title: "Review chain \u2014 managers must actively pull completed work, never wait for nudges",
3860
+ domain: "workflow",
3861
+ priority: "p0",
3862
+ content: "When you dispatch work, you OWN the review. Check list_tasks(status='needs_review') on EVERY prompt \u2014 don't wait for intercom nudges (they're unreliable). When a task shows needs_review: (1) read the deliverable (git diff in worktree, exe/output/ files, or task result summary), (2) verify it works (tsc, build, run), (3) close_task if good or create a fix task if not. Reviews sitting >30 minutes is a pipeline stall. The whole chain: worker calls update_task(done) \u2192 system flags needs_review \u2192 manager pulls and verifies \u2192 close_task \u2192 COO reviews manager's work \u2192 merge to main. Every level actively pulls \u2014 nobody waits."
3863
+ },
3864
+ {
3865
+ title: "Bug fix lifecycle \u2014 triage upstream after every verified fix so customers see the status",
3866
+ domain: "workflow",
3867
+ priority: "p0",
3868
+ content: "When a bug from support(action='list_bugs') is fixed and verified, the reviewer MUST triage it upstream: support(action='triage_bug', id='<bug-id>', notes='<what was fixed>', fixed_version='<version>', linked_commit='<hash>'). This closes the bug in the customer's view \u2014 their COO checks list_my_bugs and sees status change from open \u2192 closed with the fix version. Without triage, customers see 'open' forever even after the fix ships. Same for feature requests: support(action='triage_feature', ..., shipped_version='<version>'). Triage is part of the review gate \u2014 a fix is not done until the upstream report is closed."
3869
+ },
3649
3870
  {
3650
3871
  title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
3651
3872
  domain: "architecture",
@@ -3805,7 +4026,7 @@ init_database();
3805
4026
 
3806
4027
  // src/lib/keychain.ts
3807
4028
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3808
- import { existsSync as existsSync6, statSync as statSync2 } from "fs";
4029
+ import { existsSync as existsSync7, statSync as statSync3 } from "fs";
3809
4030
  import { execSync as execSync3 } from "child_process";
3810
4031
  import path6 from "path";
3811
4032
  import os5 from "os";
@@ -3844,7 +4065,7 @@ function isRootOnlyTrustedServerKeyFile(keyPath) {
3844
4065
  if (process.platform !== "linux") return false;
3845
4066
  try {
3846
4067
  const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
3847
- const st = statSync2(keyPath);
4068
+ const st = statSync3(keyPath);
3848
4069
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
3849
4070
  if (uid === 0) return true;
3850
4071
  const exeOsDir = process.env.EXE_OS_DIR;
@@ -4046,7 +4267,7 @@ async function getMasterKey() {
4046
4267
  }
4047
4268
  }
4048
4269
  const keyPath = getKeyPath();
4049
- if (!existsSync6(keyPath)) {
4270
+ if (!existsSync7(keyPath)) {
4050
4271
  process.stderr.write(
4051
4272
  `[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
4052
4273
  `
@@ -4161,6 +4382,13 @@ var orgBus = new StateBus();
4161
4382
  import { createHash } from "crypto";
4162
4383
 
4163
4384
  // src/lib/store.ts
4385
+ var _debugStore = process.env.EXE_DEBUG === "1";
4386
+ function logStoreWarn(context, err) {
4387
+ process.stderr.write(
4388
+ `[store] WARN ${context}: ${err instanceof Error ? err.message : String(err)}
4389
+ `
4390
+ );
4391
+ }
4164
4392
  var INIT_MAX_RETRIES = 3;
4165
4393
  var INIT_RETRY_DELAY_MS = 1e3;
4166
4394
  function isBusyError2(err) {
@@ -4223,13 +4451,15 @@ async function initStore(options) {
4223
4451
  try {
4224
4452
  const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
4225
4453
  await initDaemonClient2();
4226
- } catch {
4454
+ } catch (e) {
4455
+ logStoreWarn("catch", e);
4227
4456
  }
4228
4457
  if (!options?.lightweight) {
4229
4458
  try {
4230
4459
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
4231
4460
  initShardManager2(hexKey);
4232
- } catch {
4461
+ } catch (e) {
4462
+ logStoreWarn("catch", e);
4233
4463
  }
4234
4464
  const client = getClient();
4235
4465
  const vResult = await retryOnBusy2(
@@ -4240,7 +4470,8 @@ async function initStore(options) {
4240
4470
  try {
4241
4471
  const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
4242
4472
  await loadGlobalProcedures2();
4243
- } catch {
4473
+ } catch (e) {
4474
+ logStoreWarn("catch", e);
4244
4475
  }
4245
4476
  }
4246
4477
  }
@@ -4271,32 +4502,32 @@ function isMainModule(importMetaUrl) {
4271
4502
  }
4272
4503
 
4273
4504
  // src/bin/backfill-vectors.ts
4274
- import { existsSync as existsSync10, unlinkSync as unlinkSync5 } from "fs";
4505
+ import { existsSync as existsSync11, unlinkSync as unlinkSync6 } from "fs";
4275
4506
  import path10 from "path";
4276
4507
 
4277
4508
  // src/lib/worker-gate.ts
4278
4509
  init_config();
4279
- import { readdirSync as readdirSync2, writeFileSync as writeFileSync3, unlinkSync as unlinkSync3, mkdirSync as mkdirSync3, existsSync as existsSync8 } from "fs";
4510
+ import { readdirSync as readdirSync2, writeFileSync as writeFileSync3, unlinkSync as unlinkSync4, mkdirSync as mkdirSync4, existsSync as existsSync9 } from "fs";
4280
4511
  import path8 from "path";
4281
4512
  var WORKER_PID_DIR = path8.join(EXE_AI_DIR, "worker-pids");
4282
4513
  function registerWorkerPid(pid) {
4283
4514
  try {
4284
- mkdirSync3(WORKER_PID_DIR, { recursive: true });
4515
+ mkdirSync4(WORKER_PID_DIR, { recursive: true });
4285
4516
  writeFileSync3(path8.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
4286
4517
  } catch {
4287
4518
  }
4288
4519
  }
4289
4520
  function cleanupWorkerPid() {
4290
4521
  try {
4291
- unlinkSync3(path8.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
4522
+ unlinkSync4(path8.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
4292
4523
  } catch {
4293
4524
  }
4294
4525
  }
4295
4526
  var BACKFILL_LOCK = path8.join(WORKER_PID_DIR, "backfill.lock");
4296
4527
  function tryAcquireBackfillLock() {
4297
4528
  try {
4298
- mkdirSync3(WORKER_PID_DIR, { recursive: true });
4299
- if (existsSync8(BACKFILL_LOCK)) {
4529
+ mkdirSync4(WORKER_PID_DIR, { recursive: true });
4530
+ if (existsSync9(BACKFILL_LOCK)) {
4300
4531
  try {
4301
4532
  const pid = parseInt(
4302
4533
  __require("fs").readFileSync(BACKFILL_LOCK, "utf8").trim(),
@@ -4320,14 +4551,14 @@ function tryAcquireBackfillLock() {
4320
4551
  }
4321
4552
  function releaseBackfillLock() {
4322
4553
  try {
4323
- unlinkSync3(BACKFILL_LOCK);
4554
+ unlinkSync4(BACKFILL_LOCK);
4324
4555
  } catch {
4325
4556
  }
4326
4557
  }
4327
4558
 
4328
4559
  // src/lib/background-jobs.ts
4329
4560
  init_config();
4330
- import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4, unlinkSync as unlinkSync4 } from "fs";
4561
+ import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4, unlinkSync as unlinkSync5 } from "fs";
4331
4562
  import { execFileSync } from "child_process";
4332
4563
  import os6 from "os";
4333
4564
  import path9 from "path";
@@ -4337,7 +4568,7 @@ var LOCK_DIR = path9.join(JOB_DIR, "locks");
4337
4568
  var DEFAULT_LOCK_TTL_MS = 6 * 60 * 60 * 1e3;
4338
4569
  var MAX_HISTORY = 200;
4339
4570
  function ensureDirs() {
4340
- mkdirSync4(LOCK_DIR, { recursive: true });
4571
+ mkdirSync5(LOCK_DIR, { recursive: true });
4341
4572
  }
4342
4573
  function now() {
4343
4574
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -4353,7 +4584,7 @@ function isAlive(pid) {
4353
4584
  }
4354
4585
  function readJobsRaw() {
4355
4586
  ensureDirs();
4356
- if (!existsSync9(JOBS_FILE)) return [];
4587
+ if (!existsSync10(JOBS_FILE)) return [];
4357
4588
  try {
4358
4589
  const parsed = JSON.parse(readFileSync5(JOBS_FILE, "utf8"));
4359
4590
  return Array.isArray(parsed) ? parsed : [];
@@ -4373,7 +4604,7 @@ function lockPath(type) {
4373
4604
  function acquireJobLock(type, ttlMs = DEFAULT_LOCK_TTL_MS) {
4374
4605
  ensureDirs();
4375
4606
  const file = lockPath(type);
4376
- if (existsSync9(file)) {
4607
+ if (existsSync10(file)) {
4377
4608
  try {
4378
4609
  const lock = JSON.parse(readFileSync5(file, "utf8"));
4379
4610
  const age = Date.now() - Date.parse(lock.updatedAt ?? "");
@@ -4381,7 +4612,7 @@ function acquireJobLock(type, ttlMs = DEFAULT_LOCK_TTL_MS) {
4381
4612
  } catch {
4382
4613
  }
4383
4614
  try {
4384
- unlinkSync4(file);
4615
+ unlinkSync5(file);
4385
4616
  } catch {
4386
4617
  }
4387
4618
  }
@@ -4395,12 +4626,12 @@ function acquireJobLock(type, ttlMs = DEFAULT_LOCK_TTL_MS) {
4395
4626
  function releaseJobLock(type) {
4396
4627
  const file = lockPath(type);
4397
4628
  try {
4398
- if (!existsSync9(file)) return;
4629
+ if (!existsSync10(file)) return;
4399
4630
  const lock = JSON.parse(readFileSync5(file, "utf8"));
4400
- if (lock.pid === process.pid || !lock.pid || !isAlive(lock.pid)) unlinkSync4(file);
4631
+ if (lock.pid === process.pid || !lock.pid || !isAlive(lock.pid)) unlinkSync5(file);
4401
4632
  } catch {
4402
4633
  try {
4403
- unlinkSync4(file);
4634
+ unlinkSync5(file);
4404
4635
  } catch {
4405
4636
  }
4406
4637
  }
@@ -4557,7 +4788,7 @@ async function backfillVectors() {
4557
4788
  const remainingCount = Number(remaining.rows[0]?.cnt) || 0;
4558
4789
  if (remainingCount === 0) {
4559
4790
  try {
4560
- unlinkSync5(BACKFILL_FLAG);
4791
+ unlinkSync6(BACKFILL_FLAG);
4561
4792
  } catch {
4562
4793
  }
4563
4794
  }
@@ -4568,7 +4799,7 @@ async function backfillVectors() {
4568
4799
  return { processed: totalProcessed, failed: totalFailed, remaining: remainingCount };
4569
4800
  }
4570
4801
  function isBackfillNeeded() {
4571
- return existsSync10(BACKFILL_FLAG);
4802
+ return existsSync11(BACKFILL_FLAG);
4572
4803
  }
4573
4804
  if (isMainModule(import.meta.url)) {
4574
4805
  backfillVectors().then((result) => {