@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
@@ -1675,9 +1675,79 @@ __export(database_exports, {
1675
1675
  isInitialized: () => isInitialized,
1676
1676
  setExternalClient: () => setExternalClient
1677
1677
  });
1678
- import { chmodSync as chmodSync2 } from "fs";
1678
+ import { chmodSync as chmodSync2, existsSync as existsSync6, statSync as statSync2, copyFileSync, unlinkSync as unlinkSync4, openSync as openSync2, closeSync as closeSync2, mkdirSync as mkdirSync3 } from "fs";
1679
1679
  import { createClient } from "@libsql/client";
1680
+ import { homedir } from "os";
1681
+ import { join } from "path";
1682
+ function logCatchDebug(context, err) {
1683
+ if (_debugDb) {
1684
+ process.stderr.write(
1685
+ `[database] ${context}: ${err instanceof Error ? err.message : String(err)}
1686
+ `
1687
+ );
1688
+ }
1689
+ }
1690
+ function acquireDbLock() {
1691
+ mkdirSync3(join(homedir(), ".exe-os"), { recursive: true });
1692
+ try {
1693
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
1694
+ } catch (err) {
1695
+ if (err && typeof err === "object" && "code" in err && err.code === "EEXIST") {
1696
+ try {
1697
+ const lockStat = statSync2(DB_LOCK_PATH);
1698
+ if (Date.now() - lockStat.mtimeMs > 6e4) {
1699
+ unlinkSync4(DB_LOCK_PATH);
1700
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
1701
+ return;
1702
+ }
1703
+ } catch (e) {
1704
+ logCatchDebug("stale lock check", e);
1705
+ }
1706
+ process.stderr.write(
1707
+ "[database] WARN: Another process holds db.lock \u2014 waiting briefly then proceeding.\n"
1708
+ );
1709
+ return;
1710
+ }
1711
+ throw err;
1712
+ }
1713
+ }
1714
+ function releaseDbLock() {
1715
+ if (_lockFd !== null) {
1716
+ try {
1717
+ closeSync2(_lockFd);
1718
+ } catch (e) {
1719
+ logCatchDebug("lock close", e);
1720
+ }
1721
+ _lockFd = null;
1722
+ }
1723
+ try {
1724
+ unlinkSync4(DB_LOCK_PATH);
1725
+ } catch (e) {
1726
+ logCatchDebug("lock unlink", e);
1727
+ }
1728
+ }
1680
1729
  async function initDatabase(config) {
1730
+ acquireDbLock();
1731
+ if (existsSync6(config.dbPath)) {
1732
+ const dbStat = statSync2(config.dbPath);
1733
+ if (dbStat.size === 0) {
1734
+ const walPath = config.dbPath + "-wal";
1735
+ if (existsSync6(walPath) && statSync2(walPath).size > 0) {
1736
+ const backupPath = config.dbPath + ".zeroed-" + Date.now();
1737
+ copyFileSync(config.dbPath, backupPath);
1738
+ unlinkSync4(config.dbPath);
1739
+ process.stderr.write(
1740
+ `[database] CRITICAL: DB was 0 bytes. Moved to ${backupPath}, attempting WAL recovery.
1741
+ `
1742
+ );
1743
+ } else {
1744
+ process.stderr.write(
1745
+ `[database] CRITICAL: DB is 0 bytes and no WAL available for recovery. Data may be lost. Check backups at ${config.dbPath}.bak
1746
+ `
1747
+ );
1748
+ }
1749
+ }
1750
+ }
1681
1751
  if (_walCheckpointTimer) {
1682
1752
  clearInterval(_walCheckpointTimer);
1683
1753
  _walCheckpointTimer = null;
@@ -1704,10 +1774,8 @@ async function initDatabase(config) {
1704
1774
  _client = createClient(opts);
1705
1775
  _resilientClient = wrapWithRetry(_client);
1706
1776
  _adapterClient = _resilientClient;
1707
- _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
1708
- });
1709
- _client.execute("PRAGMA journal_mode = WAL").catch(() => {
1710
- });
1777
+ await _client.execute("PRAGMA busy_timeout = 30000");
1778
+ await _client.execute("PRAGMA journal_mode = WAL");
1711
1779
  if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
1712
1780
  _walCheckpointTimer = setInterval(() => {
1713
1781
  _client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
@@ -1722,11 +1790,16 @@ async function initDatabase(config) {
1722
1790
  for (const suffix of ["-wal", "-shm"]) {
1723
1791
  try {
1724
1792
  chmodSync2(config.dbPath + suffix, 384);
1725
- } catch {
1793
+ } catch (chmodErr) {
1794
+ process.stderr.write(`[database] chmod ${suffix} failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
1795
+ `);
1726
1796
  }
1727
1797
  }
1728
- } catch {
1798
+ } catch (chmodErr) {
1799
+ process.stderr.write(`[database] chmod db failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
1800
+ `);
1729
1801
  }
1802
+ releaseDbLock();
1730
1803
  }
1731
1804
  function isInitialized() {
1732
1805
  return _adapterClient !== null || _client !== null;
@@ -1781,7 +1854,8 @@ async function ensureSchema() {
1781
1854
  await client.execute("PRAGMA wal_autocheckpoint = 1000");
1782
1855
  try {
1783
1856
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
1784
- } catch {
1857
+ } catch (e) {
1858
+ logCatchDebug("migration", e);
1785
1859
  }
1786
1860
  await client.executeMultiple(`
1787
1861
  CREATE TABLE IF NOT EXISTS memories (
@@ -1846,6 +1920,23 @@ async function ensureSchema() {
1846
1920
  INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
1847
1921
  END;
1848
1922
  `);
1923
+ try {
1924
+ await client.execute("SELECT COUNT(*) FROM memories_fts LIMIT 1");
1925
+ } catch (ftsErr) {
1926
+ process.stderr.write(
1927
+ `[database] WARN: memories_fts corrupted (${ftsErr instanceof Error ? ftsErr.message : String(ftsErr)}) \u2014 rebuilding FTS index.
1928
+ `
1929
+ );
1930
+ try {
1931
+ await client.execute("INSERT INTO memories_fts(memories_fts) VALUES('rebuild')");
1932
+ process.stderr.write("[database] FTS index rebuilt successfully.\n");
1933
+ } catch (rebuildErr) {
1934
+ process.stderr.write(
1935
+ `[database] ERROR: FTS rebuild failed: ${rebuildErr instanceof Error ? rebuildErr.message : String(rebuildErr)}
1936
+ `
1937
+ );
1938
+ }
1939
+ }
1849
1940
  await client.executeMultiple(`
1850
1941
  CREATE TABLE IF NOT EXISTS sync_meta (
1851
1942
  key TEXT PRIMARY KEY,
@@ -1904,35 +1995,40 @@ async function ensureSchema() {
1904
1995
  });
1905
1996
  }
1906
1997
  }
1907
- } catch {
1998
+ } catch (seedErr) {
1999
+ logCatchDebug("behavior seed", seedErr);
1908
2000
  }
1909
2001
  try {
1910
2002
  await client.execute({
1911
2003
  sql: `ALTER TABLE behaviors ADD COLUMN priority TEXT DEFAULT 'p1'`,
1912
2004
  args: []
1913
2005
  });
1914
- } catch {
2006
+ } catch (e) {
2007
+ logCatchDebug("migration", e);
1915
2008
  }
1916
2009
  try {
1917
2010
  await client.execute({
1918
2011
  sql: `ALTER TABLE behaviors ADD COLUMN vector F32_BLOB(${EMBEDDING_DIM})`,
1919
2012
  args: []
1920
2013
  });
1921
- } catch {
2014
+ } catch (e) {
2015
+ logCatchDebug("migration", e);
1922
2016
  }
1923
2017
  try {
1924
2018
  await client.execute({
1925
2019
  sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
1926
2020
  args: []
1927
2021
  });
1928
- } catch {
2022
+ } catch (e) {
2023
+ logCatchDebug("migration", e);
1929
2024
  }
1930
2025
  try {
1931
2026
  await client.execute({
1932
2027
  sql: `ALTER TABLE tasks ADD COLUMN parent_task_id TEXT`,
1933
2028
  args: []
1934
2029
  });
1935
- } catch {
2030
+ } catch (e) {
2031
+ logCatchDebug("migration", e);
1936
2032
  }
1937
2033
  try {
1938
2034
  await client.execute({
@@ -1941,98 +2037,112 @@ async function ensureSchema() {
1941
2037
  WHERE parent_task_id IS NOT NULL`,
1942
2038
  args: []
1943
2039
  });
1944
- } catch {
2040
+ } catch (e) {
2041
+ logCatchDebug("migration", e);
1945
2042
  }
1946
2043
  try {
1947
2044
  await client.execute({
1948
2045
  sql: `UPDATE tasks SET status = 'done' WHERE status = 'completed'`,
1949
2046
  args: []
1950
2047
  });
1951
- } catch {
2048
+ } catch (e) {
2049
+ logCatchDebug("migration", e);
1952
2050
  }
1953
2051
  try {
1954
2052
  await client.execute({
1955
2053
  sql: `ALTER TABLE tasks ADD COLUMN reviewer TEXT`,
1956
2054
  args: []
1957
2055
  });
1958
- } catch {
2056
+ } catch (e) {
2057
+ logCatchDebug("migration", e);
1959
2058
  }
1960
2059
  try {
1961
2060
  await client.execute({
1962
2061
  sql: `ALTER TABLE tasks ADD COLUMN context TEXT`,
1963
2062
  args: []
1964
2063
  });
1965
- } catch {
2064
+ } catch (e) {
2065
+ logCatchDebug("migration", e);
1966
2066
  }
1967
2067
  try {
1968
2068
  await client.execute({
1969
2069
  sql: `ALTER TABLE tasks ADD COLUMN result TEXT`,
1970
2070
  args: []
1971
2071
  });
1972
- } catch {
2072
+ } catch (e) {
2073
+ logCatchDebug("migration", e);
1973
2074
  }
1974
2075
  try {
1975
2076
  await client.execute({
1976
2077
  sql: `ALTER TABLE tasks ADD COLUMN assigned_tmux TEXT`,
1977
2078
  args: []
1978
2079
  });
1979
- } catch {
2080
+ } catch (e) {
2081
+ logCatchDebug("migration", e);
1980
2082
  }
1981
2083
  try {
1982
2084
  await client.execute({
1983
2085
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint TEXT`,
1984
2086
  args: []
1985
2087
  });
1986
- } catch {
2088
+ } catch (e) {
2089
+ logCatchDebug("migration", e);
1987
2090
  }
1988
2091
  try {
1989
2092
  await client.execute({
1990
2093
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER NOT NULL DEFAULT 0`,
1991
2094
  args: []
1992
2095
  });
1993
- } catch {
2096
+ } catch (e) {
2097
+ logCatchDebug("migration", e);
1994
2098
  }
1995
2099
  try {
1996
2100
  await client.execute({
1997
2101
  sql: `ALTER TABLE tasks ADD COLUMN complexity TEXT NOT NULL DEFAULT 'standard'`,
1998
2102
  args: []
1999
2103
  });
2000
- } catch {
2104
+ } catch (e) {
2105
+ logCatchDebug("migration", e);
2001
2106
  }
2002
2107
  try {
2003
2108
  await client.execute({
2004
2109
  sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
2005
2110
  args: []
2006
2111
  });
2007
- } catch {
2112
+ } catch (e) {
2113
+ logCatchDebug("migration", e);
2008
2114
  }
2009
2115
  try {
2010
2116
  await client.execute({
2011
2117
  sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
2012
2118
  args: []
2013
2119
  });
2014
- } catch {
2120
+ } catch (e) {
2121
+ logCatchDebug("migration", e);
2015
2122
  }
2016
2123
  try {
2017
2124
  await client.execute({
2018
2125
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
2019
2126
  args: []
2020
2127
  });
2021
- } catch {
2128
+ } catch (e) {
2129
+ logCatchDebug("migration", e);
2022
2130
  }
2023
2131
  try {
2024
2132
  await client.execute({
2025
2133
  sql: `ALTER TABLE memories ADD COLUMN author_device_id TEXT`,
2026
2134
  args: []
2027
2135
  });
2028
- } catch {
2136
+ } catch (e) {
2137
+ logCatchDebug("migration", e);
2029
2138
  }
2030
2139
  try {
2031
2140
  await client.execute({
2032
2141
  sql: `ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'`,
2033
2142
  args: []
2034
2143
  });
2035
- } catch {
2144
+ } catch (e) {
2145
+ logCatchDebug("migration", e);
2036
2146
  }
2037
2147
  await client.executeMultiple(`
2038
2148
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2137,14 +2247,16 @@ async function ensureSchema() {
2137
2247
  sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
2138
2248
  args: []
2139
2249
  });
2140
- } catch {
2250
+ } catch (e) {
2251
+ logCatchDebug("migration", e);
2141
2252
  }
2142
2253
  try {
2143
2254
  await client.execute({
2144
2255
  sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
2145
2256
  args: []
2146
2257
  });
2147
- } catch {
2258
+ } catch (e) {
2259
+ logCatchDebug("migration", e);
2148
2260
  }
2149
2261
  await client.executeMultiple(`
2150
2262
  CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
@@ -2170,7 +2282,8 @@ async function ensureSchema() {
2170
2282
  sql: `UPDATE tasks SET project_name = 'exe-os' WHERE project_name = 'worker'`,
2171
2283
  args: []
2172
2284
  });
2173
- } catch {
2285
+ } catch (e) {
2286
+ logCatchDebug("migration", e);
2174
2287
  }
2175
2288
  await client.executeMultiple(`
2176
2289
  CREATE TABLE IF NOT EXISTS trajectories (
@@ -2194,7 +2307,8 @@ async function ensureSchema() {
2194
2307
  `);
2195
2308
  try {
2196
2309
  await client.execute("ALTER TABLE trajectories ADD COLUMN skill_id TEXT");
2197
- } catch {
2310
+ } catch (e) {
2311
+ logCatchDebug("migration", e);
2198
2312
  }
2199
2313
  await client.executeMultiple(`
2200
2314
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2231,63 +2345,72 @@ async function ensureSchema() {
2231
2345
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
2232
2346
  args: []
2233
2347
  });
2234
- } catch {
2348
+ } catch (e) {
2349
+ logCatchDebug("migration", e);
2235
2350
  }
2236
2351
  try {
2237
2352
  await client.execute({
2238
2353
  sql: `ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5`,
2239
2354
  args: []
2240
2355
  });
2241
- } catch {
2356
+ } catch (e) {
2357
+ logCatchDebug("migration", e);
2242
2358
  }
2243
2359
  try {
2244
2360
  await client.execute({
2245
2361
  sql: `ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'`,
2246
2362
  args: []
2247
2363
  });
2248
- } catch {
2364
+ } catch (e) {
2365
+ logCatchDebug("migration", e);
2249
2366
  }
2250
2367
  try {
2251
2368
  await client.execute({
2252
2369
  sql: `ALTER TABLE memories ADD COLUMN deleted_at TEXT`,
2253
2370
  args: []
2254
2371
  });
2255
- } catch {
2372
+ } catch (e) {
2373
+ logCatchDebug("migration", e);
2256
2374
  }
2257
2375
  try {
2258
2376
  await client.execute({
2259
2377
  sql: `ALTER TABLE memories ADD COLUMN confidence REAL DEFAULT 0.7`,
2260
2378
  args: []
2261
2379
  });
2262
- } catch {
2380
+ } catch (e) {
2381
+ logCatchDebug("migration", e);
2263
2382
  }
2264
2383
  try {
2265
2384
  await client.execute({
2266
2385
  sql: `ALTER TABLE memories ADD COLUMN last_accessed TEXT`,
2267
2386
  args: []
2268
2387
  });
2269
- } catch {
2388
+ } catch (e) {
2389
+ logCatchDebug("migration", e);
2270
2390
  }
2271
2391
  try {
2272
2392
  await client.execute({
2273
2393
  sql: `UPDATE memories SET last_accessed = timestamp WHERE last_accessed IS NULL`,
2274
2394
  args: []
2275
2395
  });
2276
- } catch {
2396
+ } catch (e) {
2397
+ logCatchDebug("migration", e);
2277
2398
  }
2278
2399
  try {
2279
2400
  await client.execute({
2280
2401
  sql: `ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0`,
2281
2402
  args: []
2282
2403
  });
2283
- } catch {
2404
+ } catch (e) {
2405
+ logCatchDebug("migration", e);
2284
2406
  }
2285
2407
  try {
2286
2408
  await client.execute({
2287
2409
  sql: `ALTER TABLE memories ADD COLUMN graph_extracted INTEGER DEFAULT 0`,
2288
2410
  args: []
2289
2411
  });
2290
- } catch {
2412
+ } catch (e) {
2413
+ logCatchDebug("migration", e);
2291
2414
  }
2292
2415
  for (const col of [
2293
2416
  "ALTER TABLE memories ADD COLUMN content_hash TEXT",
@@ -2295,14 +2418,16 @@ async function ensureSchema() {
2295
2418
  ]) {
2296
2419
  try {
2297
2420
  await client.execute(col);
2298
- } catch {
2421
+ } catch (e) {
2422
+ logCatchDebug("migration", e);
2299
2423
  }
2300
2424
  }
2301
2425
  try {
2302
2426
  await client.execute(
2303
2427
  `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
2304
2428
  );
2305
- } catch {
2429
+ } catch (e) {
2430
+ logCatchDebug("migration", e);
2306
2431
  }
2307
2432
  try {
2308
2433
  await client.execute(
@@ -2310,7 +2435,8 @@ async function ensureSchema() {
2310
2435
  ON memories(content_hash, agent_id, project_name, memory_type)
2311
2436
  WHERE content_hash IS NOT NULL`
2312
2437
  );
2313
- } catch {
2438
+ } catch (e) {
2439
+ logCatchDebug("migration", e);
2314
2440
  }
2315
2441
  await client.executeMultiple(`
2316
2442
  CREATE TABLE IF NOT EXISTS entities (
@@ -2386,7 +2512,8 @@ async function ensureSchema() {
2386
2512
  `);
2387
2513
  try {
2388
2514
  await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
2389
- } catch {
2515
+ } catch (e) {
2516
+ logCatchDebug("migration", e);
2390
2517
  }
2391
2518
  await client.executeMultiple(`
2392
2519
  CREATE TABLE IF NOT EXISTS entity_aliases (
@@ -2401,14 +2528,16 @@ async function ensureSchema() {
2401
2528
  ]) {
2402
2529
  try {
2403
2530
  await client.execute(col);
2404
- } catch {
2531
+ } catch (e) {
2532
+ logCatchDebug("migration", e);
2405
2533
  }
2406
2534
  }
2407
2535
  try {
2408
2536
  await client.execute(
2409
2537
  `CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)`
2410
2538
  );
2411
- } catch {
2539
+ } catch (e) {
2540
+ logCatchDebug("migration", e);
2412
2541
  }
2413
2542
  await client.executeMultiple(`
2414
2543
  CREATE TABLE IF NOT EXISTS identity (
@@ -2507,7 +2636,8 @@ async function ensureSchema() {
2507
2636
  sql: `ALTER TABLE memories ADD COLUMN ${column}`,
2508
2637
  args: []
2509
2638
  });
2510
- } catch {
2639
+ } catch (e) {
2640
+ logCatchDebug("migration", e);
2511
2641
  }
2512
2642
  }
2513
2643
  for (const col of [
@@ -2516,7 +2646,8 @@ async function ensureSchema() {
2516
2646
  ]) {
2517
2647
  try {
2518
2648
  await client.execute(col);
2519
- } catch {
2649
+ } catch (e) {
2650
+ logCatchDebug("migration", e);
2520
2651
  }
2521
2652
  }
2522
2653
  await client.executeMultiple(`
@@ -2701,56 +2832,64 @@ async function ensureSchema() {
2701
2832
  args: []
2702
2833
  });
2703
2834
  }
2704
- } catch {
2835
+ } catch (e) {
2836
+ logCatchDebug("session_agent_map backfill", e);
2705
2837
  }
2706
2838
  try {
2707
2839
  await client.execute({
2708
2840
  sql: `ALTER TABLE session_agent_map ADD COLUMN cache_cold_count INTEGER NOT NULL DEFAULT 0`,
2709
2841
  args: []
2710
2842
  });
2711
- } catch {
2843
+ } catch (e) {
2844
+ logCatchDebug("migration", e);
2712
2845
  }
2713
2846
  try {
2714
2847
  await client.execute({
2715
2848
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
2716
2849
  args: []
2717
2850
  });
2718
- } catch {
2851
+ } catch (e) {
2852
+ logCatchDebug("migration", e);
2719
2853
  }
2720
2854
  try {
2721
2855
  await client.execute({
2722
2856
  sql: `ALTER TABLE tasks ADD COLUMN budget_fallback_model TEXT`,
2723
2857
  args: []
2724
2858
  });
2725
- } catch {
2859
+ } catch (e) {
2860
+ logCatchDebug("migration", e);
2726
2861
  }
2727
2862
  try {
2728
2863
  await client.execute({
2729
2864
  sql: `ALTER TABLE tasks ADD COLUMN tokens_used INTEGER DEFAULT 0`,
2730
2865
  args: []
2731
2866
  });
2732
- } catch {
2867
+ } catch (e) {
2868
+ logCatchDebug("migration", e);
2733
2869
  }
2734
2870
  try {
2735
2871
  await client.execute({
2736
2872
  sql: `ALTER TABLE tasks ADD COLUMN tokens_warned_at INTEGER`,
2737
2873
  args: []
2738
2874
  });
2739
- } catch {
2875
+ } catch (e) {
2876
+ logCatchDebug("migration", e);
2740
2877
  }
2741
2878
  try {
2742
2879
  await client.execute({
2743
2880
  sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
2744
2881
  args: []
2745
2882
  });
2746
- } catch {
2883
+ } catch (e) {
2884
+ logCatchDebug("migration", e);
2747
2885
  }
2748
2886
  try {
2749
2887
  await client.execute({
2750
2888
  sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
2751
2889
  args: []
2752
2890
  });
2753
- } catch {
2891
+ } catch (e) {
2892
+ logCatchDebug("migration", e);
2754
2893
  }
2755
2894
  await client.executeMultiple(`
2756
2895
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
@@ -2949,13 +3088,15 @@ async function ensureSchema() {
2949
3088
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
2950
3089
  args: []
2951
3090
  });
2952
- } catch {
3091
+ } catch (e) {
3092
+ logCatchDebug("migration", e);
2953
3093
  }
2954
3094
  try {
2955
3095
  await client.execute(
2956
3096
  `CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
2957
3097
  );
2958
- } catch {
3098
+ } catch (e) {
3099
+ logCatchDebug("migration", e);
2959
3100
  }
2960
3101
  try {
2961
3102
  await client.execute({
@@ -2966,20 +3107,23 @@ async function ensureSchema() {
2966
3107
  sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
2967
3108
  args: []
2968
3109
  });
2969
- } catch {
3110
+ } catch (e) {
3111
+ logCatchDebug("migration", e);
2970
3112
  }
2971
3113
  try {
2972
3114
  await client.execute({
2973
3115
  sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
2974
3116
  args: []
2975
3117
  });
2976
- } catch {
3118
+ } catch (e) {
3119
+ logCatchDebug("migration", e);
2977
3120
  }
2978
3121
  try {
2979
3122
  await client.execute(
2980
3123
  `CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
2981
3124
  );
2982
- } catch {
3125
+ } catch (e) {
3126
+ logCatchDebug("migration", e);
2983
3127
  }
2984
3128
  for (const col of [
2985
3129
  "ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
@@ -2987,7 +3131,8 @@ async function ensureSchema() {
2987
3131
  ]) {
2988
3132
  try {
2989
3133
  await client.execute(col);
2990
- } catch {
3134
+ } catch (e) {
3135
+ logCatchDebug("migration", e);
2991
3136
  }
2992
3137
  }
2993
3138
  try {
@@ -2995,13 +3140,15 @@ async function ensureSchema() {
2995
3140
  sql: `ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0`,
2996
3141
  args: []
2997
3142
  });
2998
- } catch {
3143
+ } catch (e) {
3144
+ logCatchDebug("migration", e);
2999
3145
  }
3000
3146
  try {
3001
3147
  await client.execute(
3002
3148
  `CREATE INDEX IF NOT EXISTS idx_memories_draft ON memories(draft) WHERE draft = 1`
3003
3149
  );
3004
- } catch {
3150
+ } catch (e) {
3151
+ logCatchDebug("migration", e);
3005
3152
  }
3006
3153
  for (const col of [
3007
3154
  "ALTER TABLE memories ADD COLUMN valid_from TEXT",
@@ -3009,7 +3156,8 @@ async function ensureSchema() {
3009
3156
  ]) {
3010
3157
  try {
3011
3158
  await client.execute(col);
3012
- } catch {
3159
+ } catch (e) {
3160
+ logCatchDebug("migration", e);
3013
3161
  }
3014
3162
  }
3015
3163
  try {
@@ -3017,27 +3165,31 @@ async function ensureSchema() {
3017
3165
  sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
3018
3166
  args: []
3019
3167
  });
3020
- } catch {
3168
+ } catch (e) {
3169
+ logCatchDebug("migration", e);
3021
3170
  }
3022
3171
  try {
3023
3172
  await client.execute({
3024
3173
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
3025
3174
  args: []
3026
3175
  });
3027
- } catch {
3176
+ } catch (e) {
3177
+ logCatchDebug("migration", e);
3028
3178
  }
3029
3179
  try {
3030
3180
  await client.execute(
3031
3181
  `CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(memory_type)`
3032
3182
  );
3033
- } catch {
3183
+ } catch (e) {
3184
+ logCatchDebug("migration", e);
3034
3185
  }
3035
3186
  try {
3036
3187
  await client.execute({
3037
3188
  sql: `ALTER TABLE memories ADD COLUMN trajectory TEXT`,
3038
3189
  args: []
3039
3190
  });
3040
- } catch {
3191
+ } catch (e) {
3192
+ logCatchDebug("migration", e);
3041
3193
  }
3042
3194
  for (const col of [
3043
3195
  "ALTER TABLE memories ADD COLUMN intent TEXT",
@@ -3058,7 +3210,8 @@ async function ensureSchema() {
3058
3210
  ]) {
3059
3211
  try {
3060
3212
  await client.execute(col);
3061
- } catch {
3213
+ } catch (e) {
3214
+ logCatchDebug("migration", e);
3062
3215
  }
3063
3216
  }
3064
3217
  try {
@@ -3066,14 +3219,16 @@ async function ensureSchema() {
3066
3219
  sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
3067
3220
  args: []
3068
3221
  });
3069
- } catch {
3222
+ } catch (e) {
3223
+ logCatchDebug("migration", e);
3070
3224
  }
3071
3225
  try {
3072
3226
  await client.execute({
3073
3227
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
3074
3228
  args: []
3075
3229
  });
3076
- } catch {
3230
+ } catch (e) {
3231
+ logCatchDebug("migration", e);
3077
3232
  }
3078
3233
  }
3079
3234
  async function disposeDatabase() {
@@ -3084,7 +3239,8 @@ async function disposeDatabase() {
3084
3239
  if (_client) {
3085
3240
  try {
3086
3241
  await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3087
- } catch {
3242
+ } catch (e) {
3243
+ logCatchDebug("WAL checkpoint", e);
3088
3244
  }
3089
3245
  }
3090
3246
  if (_daemonClient) {
@@ -3100,8 +3256,9 @@ async function disposeDatabase() {
3100
3256
  _client = null;
3101
3257
  _resilientClient = null;
3102
3258
  }
3259
+ releaseDbLock();
3103
3260
  }
3104
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
3261
+ var _debugDb, _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, _lockFd, DB_LOCK_PATH, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
3105
3262
  var init_database = __esm({
3106
3263
  "src/lib/database.ts"() {
3107
3264
  "use strict";
@@ -3109,11 +3266,14 @@ var init_database = __esm({
3109
3266
  init_employees();
3110
3267
  init_database_adapter();
3111
3268
  init_memory();
3269
+ _debugDb = process.env.EXE_DEBUG === "1";
3112
3270
  _client = null;
3113
3271
  _resilientClient = null;
3114
3272
  _walCheckpointTimer = null;
3115
3273
  _daemonClient = null;
3116
3274
  _adapterClient = null;
3275
+ _lockFd = null;
3276
+ DB_LOCK_PATH = join(homedir(), ".exe-os", "db.lock");
3117
3277
  initTurso = initDatabase;
3118
3278
  SOFT_DELETE_RETENTION_DAYS = 7;
3119
3279
  disposeTurso = disposeDatabase;
@@ -3122,7 +3282,7 @@ var init_database = __esm({
3122
3282
 
3123
3283
  // src/lib/keychain.ts
3124
3284
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3125
- import { existsSync as existsSync6, statSync as statSync2 } from "fs";
3285
+ import { existsSync as existsSync7, statSync as statSync3 } from "fs";
3126
3286
  import { execSync as execSync5 } from "child_process";
3127
3287
  import path7 from "path";
3128
3288
  import os5 from "os";
@@ -3157,7 +3317,7 @@ function isRootOnlyTrustedServerKeyFile(keyPath) {
3157
3317
  if (process.platform !== "linux") return false;
3158
3318
  try {
3159
3319
  const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
3160
- const st = statSync2(keyPath);
3320
+ const st = statSync3(keyPath);
3161
3321
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
3162
3322
  if (uid === 0) return true;
3163
3323
  const exeOsDir = process.env.EXE_OS_DIR;
@@ -3358,7 +3518,7 @@ async function getMasterKey() {
3358
3518
  }
3359
3519
  }
3360
3520
  const keyPath = getKeyPath();
3361
- if (!existsSync6(keyPath)) {
3521
+ if (!existsSync7(keyPath)) {
3362
3522
  process.stderr.write(
3363
3523
  `[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
3364
3524
  `
@@ -3693,18 +3853,54 @@ __export(shard_manager_exports, {
3693
3853
  shardExists: () => shardExists
3694
3854
  });
3695
3855
  import path8 from "path";
3696
- import { existsSync as existsSync7, mkdirSync as mkdirSync3, readdirSync as readdirSync2, renameSync as renameSync3, statSync as statSync3 } from "fs";
3856
+ import { existsSync as existsSync8, mkdirSync as mkdirSync4, readdirSync as readdirSync2, renameSync as renameSync3, statSync as statSync4 } from "fs";
3697
3857
  import { createClient as createClient2 } from "@libsql/client";
3698
3858
  function initShardManager(encryptionKey) {
3699
3859
  _encryptionKey = encryptionKey;
3700
- if (!existsSync7(SHARDS_DIR)) {
3701
- mkdirSync3(SHARDS_DIR, { recursive: true });
3860
+ _keyValidated = false;
3861
+ _keyValidationPromise = null;
3862
+ if (!existsSync8(SHARDS_DIR)) {
3863
+ mkdirSync4(SHARDS_DIR, { recursive: true });
3864
+ }
3865
+ const existingShards = readdirSync2(SHARDS_DIR).filter((f) => f.endsWith(".db"));
3866
+ if (existingShards.length === 0) {
3867
+ _keyValidated = true;
3702
3868
  }
3703
3869
  _shardingEnabled = true;
3704
3870
  if (_evictionTimer) clearInterval(_evictionTimer);
3705
3871
  _evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
3706
3872
  _evictionTimer.unref();
3707
3873
  }
3874
+ async function validateEncryptionKey() {
3875
+ if (_keyValidated) return true;
3876
+ if (!_encryptionKey) return false;
3877
+ const existingShards = readdirSync2(SHARDS_DIR).filter((f) => f.endsWith(".db"));
3878
+ if (existingShards.length === 0) {
3879
+ _keyValidated = true;
3880
+ return true;
3881
+ }
3882
+ for (const shardFile of existingShards.slice(0, 3)) {
3883
+ const dbPath = path8.join(SHARDS_DIR, shardFile);
3884
+ const testClient = createClient2({ url: `file:${dbPath}`, encryptionKey: _encryptionKey });
3885
+ try {
3886
+ await testClient.execute("SELECT COUNT(*) FROM sqlite_schema");
3887
+ testClient.close();
3888
+ _keyValidated = true;
3889
+ return true;
3890
+ } catch {
3891
+ try {
3892
+ testClient.close();
3893
+ } catch {
3894
+ }
3895
+ }
3896
+ }
3897
+ process.stderr.write(
3898
+ `[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.
3899
+ `
3900
+ );
3901
+ _shardingEnabled = false;
3902
+ return false;
3903
+ }
3708
3904
  function isShardingEnabled() {
3709
3905
  return _shardingEnabled;
3710
3906
  }
@@ -3738,13 +3934,13 @@ function getShardClient(projectName) {
3738
3934
  }
3739
3935
  function shardExists(projectName) {
3740
3936
  const safeName = safeShardName(projectName);
3741
- return existsSync7(path8.join(SHARDS_DIR, `${safeName}.db`));
3937
+ return existsSync8(path8.join(SHARDS_DIR, `${safeName}.db`));
3742
3938
  }
3743
3939
  function safeShardName(projectName) {
3744
3940
  return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3745
3941
  }
3746
3942
  function listShards() {
3747
- if (!existsSync7(SHARDS_DIR)) return [];
3943
+ if (!existsSync8(SHARDS_DIR)) return [];
3748
3944
  return readdirSync2(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
3749
3945
  }
3750
3946
  async function auditShardHealth(options = {}) {
@@ -3757,7 +3953,7 @@ async function auditShardHealth(options = {}) {
3757
3953
  const shards = [];
3758
3954
  for (const name of names) {
3759
3955
  const dbPath = path8.join(SHARDS_DIR, `${name}.db`);
3760
- const stat = statSync3(dbPath);
3956
+ const stat = statSync4(dbPath);
3761
3957
  const item = {
3762
3958
  name,
3763
3959
  path: dbPath,
@@ -3997,6 +4193,17 @@ async function ensureShardSchema(client) {
3997
4193
  }
3998
4194
  }
3999
4195
  async function getReadyShardClient(projectName) {
4196
+ if (!_keyValidated) {
4197
+ if (!_keyValidationPromise) {
4198
+ _keyValidationPromise = validateEncryptionKey();
4199
+ }
4200
+ const valid = await _keyValidationPromise;
4201
+ if (!valid) {
4202
+ throw new Error(
4203
+ `Shard creation blocked: encryption key mismatch with existing shards. Run /exe-doctor to audit.`
4204
+ );
4205
+ }
4206
+ }
4000
4207
  const safeName = safeShardName(projectName);
4001
4208
  let client = getShardClient(projectName);
4002
4209
  try {
@@ -4009,8 +4216,8 @@ async function getReadyShardClient(projectName) {
4009
4216
  _shards.delete(safeName);
4010
4217
  _shardLastAccess.delete(safeName);
4011
4218
  const dbPath = path8.join(SHARDS_DIR, `${safeName}.db`);
4012
- if (existsSync7(dbPath)) {
4013
- const stat = statSync3(dbPath);
4219
+ if (existsSync8(dbPath)) {
4220
+ const stat = statSync4(dbPath);
4014
4221
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4015
4222
  const archivedPath = path8.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
4016
4223
  renameSync3(dbPath, archivedPath);
@@ -4075,7 +4282,7 @@ function disposeShards() {
4075
4282
  _shardingEnabled = false;
4076
4283
  _encryptionKey = null;
4077
4284
  }
4078
- var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
4285
+ var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled, _keyValidated, _keyValidationPromise;
4079
4286
  var init_shard_manager = __esm({
4080
4287
  "src/lib/shard-manager.ts"() {
4081
4288
  "use strict";
@@ -4089,6 +4296,8 @@ var init_shard_manager = __esm({
4089
4296
  _evictionTimer = null;
4090
4297
  _encryptionKey = null;
4091
4298
  _shardingEnabled = false;
4299
+ _keyValidated = false;
4300
+ _keyValidationPromise = null;
4092
4301
  }
4093
4302
  });
4094
4303
 
@@ -4284,6 +4493,18 @@ var init_platform_procedures = __esm({
4284
4493
  priority: "p0",
4285
4494
  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.'"
4286
4495
  },
4496
+ {
4497
+ title: "Review chain \u2014 managers must actively pull completed work, never wait for nudges",
4498
+ domain: "workflow",
4499
+ priority: "p0",
4500
+ 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."
4501
+ },
4502
+ {
4503
+ title: "Bug fix lifecycle \u2014 triage upstream after every verified fix so customers see the status",
4504
+ domain: "workflow",
4505
+ priority: "p0",
4506
+ 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."
4507
+ },
4287
4508
  {
4288
4509
  title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
4289
4510
  domain: "architecture",
@@ -4881,6 +5102,20 @@ __export(store_exports, {
4881
5102
  vectorToBlob: () => vectorToBlob,
4882
5103
  writeMemory: () => writeMemory
4883
5104
  });
5105
+ function logStoreDebug(context, err) {
5106
+ if (_debugStore) {
5107
+ process.stderr.write(
5108
+ `[store] ${context}: ${err instanceof Error ? err.message : String(err)}
5109
+ `
5110
+ );
5111
+ }
5112
+ }
5113
+ function logStoreWarn(context, err) {
5114
+ process.stderr.write(
5115
+ `[store] WARN ${context}: ${err instanceof Error ? err.message : String(err)}
5116
+ `
5117
+ );
5118
+ }
4884
5119
  function isBusyError2(err) {
4885
5120
  if (err instanceof Error) {
4886
5121
  const msg = err.message.toLowerCase();
@@ -4935,13 +5170,15 @@ async function initStore(options) {
4935
5170
  try {
4936
5171
  const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
4937
5172
  await initDaemonClient2();
4938
- } catch {
5173
+ } catch (e) {
5174
+ logStoreWarn("catch", e);
4939
5175
  }
4940
5176
  if (!options?.lightweight) {
4941
5177
  try {
4942
5178
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
4943
5179
  initShardManager2(hexKey);
4944
- } catch {
5180
+ } catch (e) {
5181
+ logStoreWarn("catch", e);
4945
5182
  }
4946
5183
  const client = getClient();
4947
5184
  const vResult = await retryOnBusy2(
@@ -4952,7 +5189,8 @@ async function initStore(options) {
4952
5189
  try {
4953
5190
  const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
4954
5191
  await loadGlobalProcedures2();
4955
- } catch {
5192
+ } catch (e) {
5193
+ logStoreWarn("catch", e);
4956
5194
  }
4957
5195
  }
4958
5196
  }
@@ -5012,7 +5250,8 @@ async function writeMemory(record) {
5012
5250
  memoryType
5013
5251
  });
5014
5252
  if (existing) return;
5015
- } catch {
5253
+ } catch (e) {
5254
+ logStoreWarn("catch", e);
5016
5255
  }
5017
5256
  const dbRow = {
5018
5257
  id: record.id,
@@ -5213,12 +5452,14 @@ async function flushBatch() {
5213
5452
  try {
5214
5453
  const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
5215
5454
  await insertMemoryCardsForBatch2(batch);
5216
- } catch {
5455
+ } catch (e) {
5456
+ logStoreWarn("catch", e);
5217
5457
  }
5218
5458
  try {
5219
5459
  const { insertOntologyForBatch: insertOntologyForBatch2 } = await Promise.resolve().then(() => (init_agentic_ontology(), agentic_ontology_exports));
5220
5460
  await insertOntologyForBatch2(batch);
5221
- } catch {
5461
+ } catch (e) {
5462
+ logStoreWarn("catch", e);
5222
5463
  }
5223
5464
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
5224
5465
  _pendingRecords.splice(0, batch.length);
@@ -5257,7 +5498,8 @@ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
5257
5498
  }
5258
5499
  }
5259
5500
  }
5260
- } catch {
5501
+ } catch (e) {
5502
+ logStoreWarn("catch", e);
5261
5503
  }
5262
5504
  return batch.length;
5263
5505
  } finally {
@@ -5299,7 +5541,8 @@ async function searchMemories(queryVector, agentId, options) {
5299
5541
  } else {
5300
5542
  client = getClient();
5301
5543
  }
5302
- } catch {
5544
+ } catch (e) {
5545
+ logStoreDebug("shard routing fallback", e);
5303
5546
  client = getClient();
5304
5547
  }
5305
5548
  const limit = options?.limit ?? 10;
@@ -5415,7 +5658,8 @@ async function attachDocumentMetadata(records) {
5415
5658
  if (!record.document_id) continue;
5416
5659
  record.document_metadata = byId.get(record.document_id) ?? null;
5417
5660
  }
5418
- } catch {
5661
+ } catch (e) {
5662
+ logStoreWarn("catch", e);
5419
5663
  }
5420
5664
  return records;
5421
5665
  }
@@ -5476,11 +5720,12 @@ async function getMemoryCardinality(agentId) {
5476
5720
  args: [agentId]
5477
5721
  });
5478
5722
  return Number(result.rows[0]?.cnt) || 0;
5479
- } catch {
5723
+ } catch (e) {
5724
+ logStoreWarn("getMemoryCardinality", e);
5480
5725
  return 0;
5481
5726
  }
5482
5727
  }
5483
- var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
5728
+ var _debugStore, INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
5484
5729
  var init_store = __esm({
5485
5730
  "src/lib/store.ts"() {
5486
5731
  "use strict";
@@ -5490,6 +5735,7 @@ var init_store = __esm({
5490
5735
  init_config();
5491
5736
  init_state_bus();
5492
5737
  init_memory_write_governor();
5738
+ _debugStore = process.env.EXE_DEBUG === "1";
5493
5739
  INIT_MAX_RETRIES = 3;
5494
5740
  INIT_RETRY_DELAY_MS = 1e3;
5495
5741
  _pendingRecords = [];