@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
@@ -1687,9 +1687,79 @@ __export(database_exports, {
1687
1687
  isInitialized: () => isInitialized,
1688
1688
  setExternalClient: () => setExternalClient
1689
1689
  });
1690
- import { chmodSync as chmodSync2 } from "fs";
1690
+ 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";
1691
1691
  import { createClient } from "@libsql/client";
1692
+ import { homedir } from "os";
1693
+ import { join } from "path";
1694
+ function logCatchDebug(context, err) {
1695
+ if (_debugDb) {
1696
+ process.stderr.write(
1697
+ `[database] ${context}: ${err instanceof Error ? err.message : String(err)}
1698
+ `
1699
+ );
1700
+ }
1701
+ }
1702
+ function acquireDbLock() {
1703
+ mkdirSync2(join(homedir(), ".exe-os"), { recursive: true });
1704
+ try {
1705
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
1706
+ } catch (err) {
1707
+ if (err && typeof err === "object" && "code" in err && err.code === "EEXIST") {
1708
+ try {
1709
+ const lockStat = statSync2(DB_LOCK_PATH);
1710
+ if (Date.now() - lockStat.mtimeMs > 6e4) {
1711
+ unlinkSync3(DB_LOCK_PATH);
1712
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
1713
+ return;
1714
+ }
1715
+ } catch (e) {
1716
+ logCatchDebug("stale lock check", e);
1717
+ }
1718
+ process.stderr.write(
1719
+ "[database] WARN: Another process holds db.lock \u2014 waiting briefly then proceeding.\n"
1720
+ );
1721
+ return;
1722
+ }
1723
+ throw err;
1724
+ }
1725
+ }
1726
+ function releaseDbLock() {
1727
+ if (_lockFd !== null) {
1728
+ try {
1729
+ closeSync2(_lockFd);
1730
+ } catch (e) {
1731
+ logCatchDebug("lock close", e);
1732
+ }
1733
+ _lockFd = null;
1734
+ }
1735
+ try {
1736
+ unlinkSync3(DB_LOCK_PATH);
1737
+ } catch (e) {
1738
+ logCatchDebug("lock unlink", e);
1739
+ }
1740
+ }
1692
1741
  async function initDatabase(config) {
1742
+ acquireDbLock();
1743
+ if (existsSync6(config.dbPath)) {
1744
+ const dbStat = statSync2(config.dbPath);
1745
+ if (dbStat.size === 0) {
1746
+ const walPath = config.dbPath + "-wal";
1747
+ if (existsSync6(walPath) && statSync2(walPath).size > 0) {
1748
+ const backupPath = config.dbPath + ".zeroed-" + Date.now();
1749
+ copyFileSync(config.dbPath, backupPath);
1750
+ unlinkSync3(config.dbPath);
1751
+ process.stderr.write(
1752
+ `[database] CRITICAL: DB was 0 bytes. Moved to ${backupPath}, attempting WAL recovery.
1753
+ `
1754
+ );
1755
+ } else {
1756
+ process.stderr.write(
1757
+ `[database] CRITICAL: DB is 0 bytes and no WAL available for recovery. Data may be lost. Check backups at ${config.dbPath}.bak
1758
+ `
1759
+ );
1760
+ }
1761
+ }
1762
+ }
1693
1763
  if (_walCheckpointTimer) {
1694
1764
  clearInterval(_walCheckpointTimer);
1695
1765
  _walCheckpointTimer = null;
@@ -1716,10 +1786,8 @@ async function initDatabase(config) {
1716
1786
  _client = createClient(opts);
1717
1787
  _resilientClient = wrapWithRetry(_client);
1718
1788
  _adapterClient = _resilientClient;
1719
- _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
1720
- });
1721
- _client.execute("PRAGMA journal_mode = WAL").catch(() => {
1722
- });
1789
+ await _client.execute("PRAGMA busy_timeout = 30000");
1790
+ await _client.execute("PRAGMA journal_mode = WAL");
1723
1791
  if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
1724
1792
  _walCheckpointTimer = setInterval(() => {
1725
1793
  _client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
@@ -1734,11 +1802,16 @@ async function initDatabase(config) {
1734
1802
  for (const suffix of ["-wal", "-shm"]) {
1735
1803
  try {
1736
1804
  chmodSync2(config.dbPath + suffix, 384);
1737
- } catch {
1805
+ } catch (chmodErr) {
1806
+ process.stderr.write(`[database] chmod ${suffix} failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
1807
+ `);
1738
1808
  }
1739
1809
  }
1740
- } catch {
1810
+ } catch (chmodErr) {
1811
+ process.stderr.write(`[database] chmod db failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
1812
+ `);
1741
1813
  }
1814
+ releaseDbLock();
1742
1815
  }
1743
1816
  function isInitialized() {
1744
1817
  return _adapterClient !== null || _client !== null;
@@ -1793,7 +1866,8 @@ async function ensureSchema() {
1793
1866
  await client.execute("PRAGMA wal_autocheckpoint = 1000");
1794
1867
  try {
1795
1868
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
1796
- } catch {
1869
+ } catch (e) {
1870
+ logCatchDebug("migration", e);
1797
1871
  }
1798
1872
  await client.executeMultiple(`
1799
1873
  CREATE TABLE IF NOT EXISTS memories (
@@ -1858,6 +1932,23 @@ async function ensureSchema() {
1858
1932
  INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
1859
1933
  END;
1860
1934
  `);
1935
+ try {
1936
+ await client.execute("SELECT COUNT(*) FROM memories_fts LIMIT 1");
1937
+ } catch (ftsErr) {
1938
+ process.stderr.write(
1939
+ `[database] WARN: memories_fts corrupted (${ftsErr instanceof Error ? ftsErr.message : String(ftsErr)}) \u2014 rebuilding FTS index.
1940
+ `
1941
+ );
1942
+ try {
1943
+ await client.execute("INSERT INTO memories_fts(memories_fts) VALUES('rebuild')");
1944
+ process.stderr.write("[database] FTS index rebuilt successfully.\n");
1945
+ } catch (rebuildErr) {
1946
+ process.stderr.write(
1947
+ `[database] ERROR: FTS rebuild failed: ${rebuildErr instanceof Error ? rebuildErr.message : String(rebuildErr)}
1948
+ `
1949
+ );
1950
+ }
1951
+ }
1861
1952
  await client.executeMultiple(`
1862
1953
  CREATE TABLE IF NOT EXISTS sync_meta (
1863
1954
  key TEXT PRIMARY KEY,
@@ -1916,35 +2007,40 @@ async function ensureSchema() {
1916
2007
  });
1917
2008
  }
1918
2009
  }
1919
- } catch {
2010
+ } catch (seedErr) {
2011
+ logCatchDebug("behavior seed", seedErr);
1920
2012
  }
1921
2013
  try {
1922
2014
  await client.execute({
1923
2015
  sql: `ALTER TABLE behaviors ADD COLUMN priority TEXT DEFAULT 'p1'`,
1924
2016
  args: []
1925
2017
  });
1926
- } catch {
2018
+ } catch (e) {
2019
+ logCatchDebug("migration", e);
1927
2020
  }
1928
2021
  try {
1929
2022
  await client.execute({
1930
2023
  sql: `ALTER TABLE behaviors ADD COLUMN vector F32_BLOB(${EMBEDDING_DIM})`,
1931
2024
  args: []
1932
2025
  });
1933
- } catch {
2026
+ } catch (e) {
2027
+ logCatchDebug("migration", e);
1934
2028
  }
1935
2029
  try {
1936
2030
  await client.execute({
1937
2031
  sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
1938
2032
  args: []
1939
2033
  });
1940
- } catch {
2034
+ } catch (e) {
2035
+ logCatchDebug("migration", e);
1941
2036
  }
1942
2037
  try {
1943
2038
  await client.execute({
1944
2039
  sql: `ALTER TABLE tasks ADD COLUMN parent_task_id TEXT`,
1945
2040
  args: []
1946
2041
  });
1947
- } catch {
2042
+ } catch (e) {
2043
+ logCatchDebug("migration", e);
1948
2044
  }
1949
2045
  try {
1950
2046
  await client.execute({
@@ -1953,98 +2049,112 @@ async function ensureSchema() {
1953
2049
  WHERE parent_task_id IS NOT NULL`,
1954
2050
  args: []
1955
2051
  });
1956
- } catch {
2052
+ } catch (e) {
2053
+ logCatchDebug("migration", e);
1957
2054
  }
1958
2055
  try {
1959
2056
  await client.execute({
1960
2057
  sql: `UPDATE tasks SET status = 'done' WHERE status = 'completed'`,
1961
2058
  args: []
1962
2059
  });
1963
- } catch {
2060
+ } catch (e) {
2061
+ logCatchDebug("migration", e);
1964
2062
  }
1965
2063
  try {
1966
2064
  await client.execute({
1967
2065
  sql: `ALTER TABLE tasks ADD COLUMN reviewer TEXT`,
1968
2066
  args: []
1969
2067
  });
1970
- } catch {
2068
+ } catch (e) {
2069
+ logCatchDebug("migration", e);
1971
2070
  }
1972
2071
  try {
1973
2072
  await client.execute({
1974
2073
  sql: `ALTER TABLE tasks ADD COLUMN context TEXT`,
1975
2074
  args: []
1976
2075
  });
1977
- } catch {
2076
+ } catch (e) {
2077
+ logCatchDebug("migration", e);
1978
2078
  }
1979
2079
  try {
1980
2080
  await client.execute({
1981
2081
  sql: `ALTER TABLE tasks ADD COLUMN result TEXT`,
1982
2082
  args: []
1983
2083
  });
1984
- } catch {
2084
+ } catch (e) {
2085
+ logCatchDebug("migration", e);
1985
2086
  }
1986
2087
  try {
1987
2088
  await client.execute({
1988
2089
  sql: `ALTER TABLE tasks ADD COLUMN assigned_tmux TEXT`,
1989
2090
  args: []
1990
2091
  });
1991
- } catch {
2092
+ } catch (e) {
2093
+ logCatchDebug("migration", e);
1992
2094
  }
1993
2095
  try {
1994
2096
  await client.execute({
1995
2097
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint TEXT`,
1996
2098
  args: []
1997
2099
  });
1998
- } catch {
2100
+ } catch (e) {
2101
+ logCatchDebug("migration", e);
1999
2102
  }
2000
2103
  try {
2001
2104
  await client.execute({
2002
2105
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER NOT NULL DEFAULT 0`,
2003
2106
  args: []
2004
2107
  });
2005
- } catch {
2108
+ } catch (e) {
2109
+ logCatchDebug("migration", e);
2006
2110
  }
2007
2111
  try {
2008
2112
  await client.execute({
2009
2113
  sql: `ALTER TABLE tasks ADD COLUMN complexity TEXT NOT NULL DEFAULT 'standard'`,
2010
2114
  args: []
2011
2115
  });
2012
- } catch {
2116
+ } catch (e) {
2117
+ logCatchDebug("migration", e);
2013
2118
  }
2014
2119
  try {
2015
2120
  await client.execute({
2016
2121
  sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
2017
2122
  args: []
2018
2123
  });
2019
- } catch {
2124
+ } catch (e) {
2125
+ logCatchDebug("migration", e);
2020
2126
  }
2021
2127
  try {
2022
2128
  await client.execute({
2023
2129
  sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
2024
2130
  args: []
2025
2131
  });
2026
- } catch {
2132
+ } catch (e) {
2133
+ logCatchDebug("migration", e);
2027
2134
  }
2028
2135
  try {
2029
2136
  await client.execute({
2030
2137
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
2031
2138
  args: []
2032
2139
  });
2033
- } catch {
2140
+ } catch (e) {
2141
+ logCatchDebug("migration", e);
2034
2142
  }
2035
2143
  try {
2036
2144
  await client.execute({
2037
2145
  sql: `ALTER TABLE memories ADD COLUMN author_device_id TEXT`,
2038
2146
  args: []
2039
2147
  });
2040
- } catch {
2148
+ } catch (e) {
2149
+ logCatchDebug("migration", e);
2041
2150
  }
2042
2151
  try {
2043
2152
  await client.execute({
2044
2153
  sql: `ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'`,
2045
2154
  args: []
2046
2155
  });
2047
- } catch {
2156
+ } catch (e) {
2157
+ logCatchDebug("migration", e);
2048
2158
  }
2049
2159
  await client.executeMultiple(`
2050
2160
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2149,14 +2259,16 @@ async function ensureSchema() {
2149
2259
  sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
2150
2260
  args: []
2151
2261
  });
2152
- } catch {
2262
+ } catch (e) {
2263
+ logCatchDebug("migration", e);
2153
2264
  }
2154
2265
  try {
2155
2266
  await client.execute({
2156
2267
  sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
2157
2268
  args: []
2158
2269
  });
2159
- } catch {
2270
+ } catch (e) {
2271
+ logCatchDebug("migration", e);
2160
2272
  }
2161
2273
  await client.executeMultiple(`
2162
2274
  CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
@@ -2182,7 +2294,8 @@ async function ensureSchema() {
2182
2294
  sql: `UPDATE tasks SET project_name = 'exe-os' WHERE project_name = 'worker'`,
2183
2295
  args: []
2184
2296
  });
2185
- } catch {
2297
+ } catch (e) {
2298
+ logCatchDebug("migration", e);
2186
2299
  }
2187
2300
  await client.executeMultiple(`
2188
2301
  CREATE TABLE IF NOT EXISTS trajectories (
@@ -2206,7 +2319,8 @@ async function ensureSchema() {
2206
2319
  `);
2207
2320
  try {
2208
2321
  await client.execute("ALTER TABLE trajectories ADD COLUMN skill_id TEXT");
2209
- } catch {
2322
+ } catch (e) {
2323
+ logCatchDebug("migration", e);
2210
2324
  }
2211
2325
  await client.executeMultiple(`
2212
2326
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2243,63 +2357,72 @@ async function ensureSchema() {
2243
2357
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
2244
2358
  args: []
2245
2359
  });
2246
- } catch {
2360
+ } catch (e) {
2361
+ logCatchDebug("migration", e);
2247
2362
  }
2248
2363
  try {
2249
2364
  await client.execute({
2250
2365
  sql: `ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5`,
2251
2366
  args: []
2252
2367
  });
2253
- } catch {
2368
+ } catch (e) {
2369
+ logCatchDebug("migration", e);
2254
2370
  }
2255
2371
  try {
2256
2372
  await client.execute({
2257
2373
  sql: `ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'`,
2258
2374
  args: []
2259
2375
  });
2260
- } catch {
2376
+ } catch (e) {
2377
+ logCatchDebug("migration", e);
2261
2378
  }
2262
2379
  try {
2263
2380
  await client.execute({
2264
2381
  sql: `ALTER TABLE memories ADD COLUMN deleted_at TEXT`,
2265
2382
  args: []
2266
2383
  });
2267
- } catch {
2384
+ } catch (e) {
2385
+ logCatchDebug("migration", e);
2268
2386
  }
2269
2387
  try {
2270
2388
  await client.execute({
2271
2389
  sql: `ALTER TABLE memories ADD COLUMN confidence REAL DEFAULT 0.7`,
2272
2390
  args: []
2273
2391
  });
2274
- } catch {
2392
+ } catch (e) {
2393
+ logCatchDebug("migration", e);
2275
2394
  }
2276
2395
  try {
2277
2396
  await client.execute({
2278
2397
  sql: `ALTER TABLE memories ADD COLUMN last_accessed TEXT`,
2279
2398
  args: []
2280
2399
  });
2281
- } catch {
2400
+ } catch (e) {
2401
+ logCatchDebug("migration", e);
2282
2402
  }
2283
2403
  try {
2284
2404
  await client.execute({
2285
2405
  sql: `UPDATE memories SET last_accessed = timestamp WHERE last_accessed IS NULL`,
2286
2406
  args: []
2287
2407
  });
2288
- } catch {
2408
+ } catch (e) {
2409
+ logCatchDebug("migration", e);
2289
2410
  }
2290
2411
  try {
2291
2412
  await client.execute({
2292
2413
  sql: `ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0`,
2293
2414
  args: []
2294
2415
  });
2295
- } catch {
2416
+ } catch (e) {
2417
+ logCatchDebug("migration", e);
2296
2418
  }
2297
2419
  try {
2298
2420
  await client.execute({
2299
2421
  sql: `ALTER TABLE memories ADD COLUMN graph_extracted INTEGER DEFAULT 0`,
2300
2422
  args: []
2301
2423
  });
2302
- } catch {
2424
+ } catch (e) {
2425
+ logCatchDebug("migration", e);
2303
2426
  }
2304
2427
  for (const col of [
2305
2428
  "ALTER TABLE memories ADD COLUMN content_hash TEXT",
@@ -2307,14 +2430,16 @@ async function ensureSchema() {
2307
2430
  ]) {
2308
2431
  try {
2309
2432
  await client.execute(col);
2310
- } catch {
2433
+ } catch (e) {
2434
+ logCatchDebug("migration", e);
2311
2435
  }
2312
2436
  }
2313
2437
  try {
2314
2438
  await client.execute(
2315
2439
  `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
2316
2440
  );
2317
- } catch {
2441
+ } catch (e) {
2442
+ logCatchDebug("migration", e);
2318
2443
  }
2319
2444
  try {
2320
2445
  await client.execute(
@@ -2322,7 +2447,8 @@ async function ensureSchema() {
2322
2447
  ON memories(content_hash, agent_id, project_name, memory_type)
2323
2448
  WHERE content_hash IS NOT NULL`
2324
2449
  );
2325
- } catch {
2450
+ } catch (e) {
2451
+ logCatchDebug("migration", e);
2326
2452
  }
2327
2453
  await client.executeMultiple(`
2328
2454
  CREATE TABLE IF NOT EXISTS entities (
@@ -2398,7 +2524,8 @@ async function ensureSchema() {
2398
2524
  `);
2399
2525
  try {
2400
2526
  await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
2401
- } catch {
2527
+ } catch (e) {
2528
+ logCatchDebug("migration", e);
2402
2529
  }
2403
2530
  await client.executeMultiple(`
2404
2531
  CREATE TABLE IF NOT EXISTS entity_aliases (
@@ -2413,14 +2540,16 @@ async function ensureSchema() {
2413
2540
  ]) {
2414
2541
  try {
2415
2542
  await client.execute(col);
2416
- } catch {
2543
+ } catch (e) {
2544
+ logCatchDebug("migration", e);
2417
2545
  }
2418
2546
  }
2419
2547
  try {
2420
2548
  await client.execute(
2421
2549
  `CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)`
2422
2550
  );
2423
- } catch {
2551
+ } catch (e) {
2552
+ logCatchDebug("migration", e);
2424
2553
  }
2425
2554
  await client.executeMultiple(`
2426
2555
  CREATE TABLE IF NOT EXISTS identity (
@@ -2519,7 +2648,8 @@ async function ensureSchema() {
2519
2648
  sql: `ALTER TABLE memories ADD COLUMN ${column}`,
2520
2649
  args: []
2521
2650
  });
2522
- } catch {
2651
+ } catch (e) {
2652
+ logCatchDebug("migration", e);
2523
2653
  }
2524
2654
  }
2525
2655
  for (const col of [
@@ -2528,7 +2658,8 @@ async function ensureSchema() {
2528
2658
  ]) {
2529
2659
  try {
2530
2660
  await client.execute(col);
2531
- } catch {
2661
+ } catch (e) {
2662
+ logCatchDebug("migration", e);
2532
2663
  }
2533
2664
  }
2534
2665
  await client.executeMultiple(`
@@ -2713,56 +2844,64 @@ async function ensureSchema() {
2713
2844
  args: []
2714
2845
  });
2715
2846
  }
2716
- } catch {
2847
+ } catch (e) {
2848
+ logCatchDebug("session_agent_map backfill", e);
2717
2849
  }
2718
2850
  try {
2719
2851
  await client.execute({
2720
2852
  sql: `ALTER TABLE session_agent_map ADD COLUMN cache_cold_count INTEGER NOT NULL DEFAULT 0`,
2721
2853
  args: []
2722
2854
  });
2723
- } catch {
2855
+ } catch (e) {
2856
+ logCatchDebug("migration", e);
2724
2857
  }
2725
2858
  try {
2726
2859
  await client.execute({
2727
2860
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
2728
2861
  args: []
2729
2862
  });
2730
- } catch {
2863
+ } catch (e) {
2864
+ logCatchDebug("migration", e);
2731
2865
  }
2732
2866
  try {
2733
2867
  await client.execute({
2734
2868
  sql: `ALTER TABLE tasks ADD COLUMN budget_fallback_model TEXT`,
2735
2869
  args: []
2736
2870
  });
2737
- } catch {
2871
+ } catch (e) {
2872
+ logCatchDebug("migration", e);
2738
2873
  }
2739
2874
  try {
2740
2875
  await client.execute({
2741
2876
  sql: `ALTER TABLE tasks ADD COLUMN tokens_used INTEGER DEFAULT 0`,
2742
2877
  args: []
2743
2878
  });
2744
- } catch {
2879
+ } catch (e) {
2880
+ logCatchDebug("migration", e);
2745
2881
  }
2746
2882
  try {
2747
2883
  await client.execute({
2748
2884
  sql: `ALTER TABLE tasks ADD COLUMN tokens_warned_at INTEGER`,
2749
2885
  args: []
2750
2886
  });
2751
- } catch {
2887
+ } catch (e) {
2888
+ logCatchDebug("migration", e);
2752
2889
  }
2753
2890
  try {
2754
2891
  await client.execute({
2755
2892
  sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
2756
2893
  args: []
2757
2894
  });
2758
- } catch {
2895
+ } catch (e) {
2896
+ logCatchDebug("migration", e);
2759
2897
  }
2760
2898
  try {
2761
2899
  await client.execute({
2762
2900
  sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
2763
2901
  args: []
2764
2902
  });
2765
- } catch {
2903
+ } catch (e) {
2904
+ logCatchDebug("migration", e);
2766
2905
  }
2767
2906
  await client.executeMultiple(`
2768
2907
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
@@ -2961,13 +3100,15 @@ async function ensureSchema() {
2961
3100
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
2962
3101
  args: []
2963
3102
  });
2964
- } catch {
3103
+ } catch (e) {
3104
+ logCatchDebug("migration", e);
2965
3105
  }
2966
3106
  try {
2967
3107
  await client.execute(
2968
3108
  `CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
2969
3109
  );
2970
- } catch {
3110
+ } catch (e) {
3111
+ logCatchDebug("migration", e);
2971
3112
  }
2972
3113
  try {
2973
3114
  await client.execute({
@@ -2978,20 +3119,23 @@ async function ensureSchema() {
2978
3119
  sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
2979
3120
  args: []
2980
3121
  });
2981
- } catch {
3122
+ } catch (e) {
3123
+ logCatchDebug("migration", e);
2982
3124
  }
2983
3125
  try {
2984
3126
  await client.execute({
2985
3127
  sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
2986
3128
  args: []
2987
3129
  });
2988
- } catch {
3130
+ } catch (e) {
3131
+ logCatchDebug("migration", e);
2989
3132
  }
2990
3133
  try {
2991
3134
  await client.execute(
2992
3135
  `CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
2993
3136
  );
2994
- } catch {
3137
+ } catch (e) {
3138
+ logCatchDebug("migration", e);
2995
3139
  }
2996
3140
  for (const col of [
2997
3141
  "ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
@@ -2999,7 +3143,8 @@ async function ensureSchema() {
2999
3143
  ]) {
3000
3144
  try {
3001
3145
  await client.execute(col);
3002
- } catch {
3146
+ } catch (e) {
3147
+ logCatchDebug("migration", e);
3003
3148
  }
3004
3149
  }
3005
3150
  try {
@@ -3007,13 +3152,15 @@ async function ensureSchema() {
3007
3152
  sql: `ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0`,
3008
3153
  args: []
3009
3154
  });
3010
- } catch {
3155
+ } catch (e) {
3156
+ logCatchDebug("migration", e);
3011
3157
  }
3012
3158
  try {
3013
3159
  await client.execute(
3014
3160
  `CREATE INDEX IF NOT EXISTS idx_memories_draft ON memories(draft) WHERE draft = 1`
3015
3161
  );
3016
- } catch {
3162
+ } catch (e) {
3163
+ logCatchDebug("migration", e);
3017
3164
  }
3018
3165
  for (const col of [
3019
3166
  "ALTER TABLE memories ADD COLUMN valid_from TEXT",
@@ -3021,7 +3168,8 @@ async function ensureSchema() {
3021
3168
  ]) {
3022
3169
  try {
3023
3170
  await client.execute(col);
3024
- } catch {
3171
+ } catch (e) {
3172
+ logCatchDebug("migration", e);
3025
3173
  }
3026
3174
  }
3027
3175
  try {
@@ -3029,27 +3177,31 @@ async function ensureSchema() {
3029
3177
  sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
3030
3178
  args: []
3031
3179
  });
3032
- } catch {
3180
+ } catch (e) {
3181
+ logCatchDebug("migration", e);
3033
3182
  }
3034
3183
  try {
3035
3184
  await client.execute({
3036
3185
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
3037
3186
  args: []
3038
3187
  });
3039
- } catch {
3188
+ } catch (e) {
3189
+ logCatchDebug("migration", e);
3040
3190
  }
3041
3191
  try {
3042
3192
  await client.execute(
3043
3193
  `CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(memory_type)`
3044
3194
  );
3045
- } catch {
3195
+ } catch (e) {
3196
+ logCatchDebug("migration", e);
3046
3197
  }
3047
3198
  try {
3048
3199
  await client.execute({
3049
3200
  sql: `ALTER TABLE memories ADD COLUMN trajectory TEXT`,
3050
3201
  args: []
3051
3202
  });
3052
- } catch {
3203
+ } catch (e) {
3204
+ logCatchDebug("migration", e);
3053
3205
  }
3054
3206
  for (const col of [
3055
3207
  "ALTER TABLE memories ADD COLUMN intent TEXT",
@@ -3070,7 +3222,8 @@ async function ensureSchema() {
3070
3222
  ]) {
3071
3223
  try {
3072
3224
  await client.execute(col);
3073
- } catch {
3225
+ } catch (e) {
3226
+ logCatchDebug("migration", e);
3074
3227
  }
3075
3228
  }
3076
3229
  try {
@@ -3078,14 +3231,16 @@ async function ensureSchema() {
3078
3231
  sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
3079
3232
  args: []
3080
3233
  });
3081
- } catch {
3234
+ } catch (e) {
3235
+ logCatchDebug("migration", e);
3082
3236
  }
3083
3237
  try {
3084
3238
  await client.execute({
3085
3239
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
3086
3240
  args: []
3087
3241
  });
3088
- } catch {
3242
+ } catch (e) {
3243
+ logCatchDebug("migration", e);
3089
3244
  }
3090
3245
  }
3091
3246
  async function disposeDatabase() {
@@ -3096,7 +3251,8 @@ async function disposeDatabase() {
3096
3251
  if (_client) {
3097
3252
  try {
3098
3253
  await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3099
- } catch {
3254
+ } catch (e) {
3255
+ logCatchDebug("WAL checkpoint", e);
3100
3256
  }
3101
3257
  }
3102
3258
  if (_daemonClient) {
@@ -3112,8 +3268,9 @@ async function disposeDatabase() {
3112
3268
  _client = null;
3113
3269
  _resilientClient = null;
3114
3270
  }
3271
+ releaseDbLock();
3115
3272
  }
3116
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
3273
+ var _debugDb, _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, _lockFd, DB_LOCK_PATH, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
3117
3274
  var init_database = __esm({
3118
3275
  "src/lib/database.ts"() {
3119
3276
  "use strict";
@@ -3121,11 +3278,14 @@ var init_database = __esm({
3121
3278
  init_employees();
3122
3279
  init_database_adapter();
3123
3280
  init_memory();
3281
+ _debugDb = process.env.EXE_DEBUG === "1";
3124
3282
  _client = null;
3125
3283
  _resilientClient = null;
3126
3284
  _walCheckpointTimer = null;
3127
3285
  _daemonClient = null;
3128
3286
  _adapterClient = null;
3287
+ _lockFd = null;
3288
+ DB_LOCK_PATH = join(homedir(), ".exe-os", "db.lock");
3129
3289
  initTurso = initDatabase;
3130
3290
  SOFT_DELETE_RETENTION_DAYS = 7;
3131
3291
  disposeTurso = disposeDatabase;
@@ -3134,7 +3294,7 @@ var init_database = __esm({
3134
3294
 
3135
3295
  // src/lib/keychain.ts
3136
3296
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3137
- import { existsSync as existsSync6, statSync as statSync2 } from "fs";
3297
+ import { existsSync as existsSync7, statSync as statSync3 } from "fs";
3138
3298
  import { execSync as execSync3 } from "child_process";
3139
3299
  import path6 from "path";
3140
3300
  import os5 from "os";
@@ -3169,7 +3329,7 @@ function isRootOnlyTrustedServerKeyFile(keyPath) {
3169
3329
  if (process.platform !== "linux") return false;
3170
3330
  try {
3171
3331
  const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
3172
- const st = statSync2(keyPath);
3332
+ const st = statSync3(keyPath);
3173
3333
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
3174
3334
  if (uid === 0) return true;
3175
3335
  const exeOsDir = process.env.EXE_OS_DIR;
@@ -3370,7 +3530,7 @@ async function getMasterKey() {
3370
3530
  }
3371
3531
  }
3372
3532
  const keyPath = getKeyPath();
3373
- if (!existsSync6(keyPath)) {
3533
+ if (!existsSync7(keyPath)) {
3374
3534
  process.stderr.write(
3375
3535
  `[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
3376
3536
  `
@@ -3705,18 +3865,54 @@ __export(shard_manager_exports, {
3705
3865
  shardExists: () => shardExists
3706
3866
  });
3707
3867
  import path7 from "path";
3708
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync3 } from "fs";
3868
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3, readdirSync, renameSync as renameSync3, statSync as statSync4 } from "fs";
3709
3869
  import { createClient as createClient2 } from "@libsql/client";
3710
3870
  function initShardManager(encryptionKey) {
3711
3871
  _encryptionKey = encryptionKey;
3712
- if (!existsSync7(SHARDS_DIR)) {
3713
- mkdirSync2(SHARDS_DIR, { recursive: true });
3872
+ _keyValidated = false;
3873
+ _keyValidationPromise = null;
3874
+ if (!existsSync8(SHARDS_DIR)) {
3875
+ mkdirSync3(SHARDS_DIR, { recursive: true });
3876
+ }
3877
+ const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
3878
+ if (existingShards.length === 0) {
3879
+ _keyValidated = true;
3714
3880
  }
3715
3881
  _shardingEnabled = true;
3716
3882
  if (_evictionTimer) clearInterval(_evictionTimer);
3717
3883
  _evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
3718
3884
  _evictionTimer.unref();
3719
3885
  }
3886
+ async function validateEncryptionKey() {
3887
+ if (_keyValidated) return true;
3888
+ if (!_encryptionKey) return false;
3889
+ const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
3890
+ if (existingShards.length === 0) {
3891
+ _keyValidated = true;
3892
+ return true;
3893
+ }
3894
+ for (const shardFile of existingShards.slice(0, 3)) {
3895
+ const dbPath = path7.join(SHARDS_DIR, shardFile);
3896
+ const testClient = createClient2({ url: `file:${dbPath}`, encryptionKey: _encryptionKey });
3897
+ try {
3898
+ await testClient.execute("SELECT COUNT(*) FROM sqlite_schema");
3899
+ testClient.close();
3900
+ _keyValidated = true;
3901
+ return true;
3902
+ } catch {
3903
+ try {
3904
+ testClient.close();
3905
+ } catch {
3906
+ }
3907
+ }
3908
+ }
3909
+ process.stderr.write(
3910
+ `[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.
3911
+ `
3912
+ );
3913
+ _shardingEnabled = false;
3914
+ return false;
3915
+ }
3720
3916
  function isShardingEnabled() {
3721
3917
  return _shardingEnabled;
3722
3918
  }
@@ -3750,13 +3946,13 @@ function getShardClient(projectName) {
3750
3946
  }
3751
3947
  function shardExists(projectName) {
3752
3948
  const safeName = safeShardName(projectName);
3753
- return existsSync7(path7.join(SHARDS_DIR, `${safeName}.db`));
3949
+ return existsSync8(path7.join(SHARDS_DIR, `${safeName}.db`));
3754
3950
  }
3755
3951
  function safeShardName(projectName) {
3756
3952
  return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3757
3953
  }
3758
3954
  function listShards() {
3759
- if (!existsSync7(SHARDS_DIR)) return [];
3955
+ if (!existsSync8(SHARDS_DIR)) return [];
3760
3956
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
3761
3957
  }
3762
3958
  async function auditShardHealth(options = {}) {
@@ -3769,7 +3965,7 @@ async function auditShardHealth(options = {}) {
3769
3965
  const shards = [];
3770
3966
  for (const name of names) {
3771
3967
  const dbPath = path7.join(SHARDS_DIR, `${name}.db`);
3772
- const stat = statSync3(dbPath);
3968
+ const stat = statSync4(dbPath);
3773
3969
  const item = {
3774
3970
  name,
3775
3971
  path: dbPath,
@@ -4009,6 +4205,17 @@ async function ensureShardSchema(client) {
4009
4205
  }
4010
4206
  }
4011
4207
  async function getReadyShardClient(projectName) {
4208
+ if (!_keyValidated) {
4209
+ if (!_keyValidationPromise) {
4210
+ _keyValidationPromise = validateEncryptionKey();
4211
+ }
4212
+ const valid = await _keyValidationPromise;
4213
+ if (!valid) {
4214
+ throw new Error(
4215
+ `Shard creation blocked: encryption key mismatch with existing shards. Run /exe-doctor to audit.`
4216
+ );
4217
+ }
4218
+ }
4012
4219
  const safeName = safeShardName(projectName);
4013
4220
  let client = getShardClient(projectName);
4014
4221
  try {
@@ -4021,8 +4228,8 @@ async function getReadyShardClient(projectName) {
4021
4228
  _shards.delete(safeName);
4022
4229
  _shardLastAccess.delete(safeName);
4023
4230
  const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
4024
- if (existsSync7(dbPath)) {
4025
- const stat = statSync3(dbPath);
4231
+ if (existsSync8(dbPath)) {
4232
+ const stat = statSync4(dbPath);
4026
4233
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4027
4234
  const archivedPath = path7.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
4028
4235
  renameSync3(dbPath, archivedPath);
@@ -4087,7 +4294,7 @@ function disposeShards() {
4087
4294
  _shardingEnabled = false;
4088
4295
  _encryptionKey = null;
4089
4296
  }
4090
- var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
4297
+ var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled, _keyValidated, _keyValidationPromise;
4091
4298
  var init_shard_manager = __esm({
4092
4299
  "src/lib/shard-manager.ts"() {
4093
4300
  "use strict";
@@ -4101,6 +4308,8 @@ var init_shard_manager = __esm({
4101
4308
  _evictionTimer = null;
4102
4309
  _encryptionKey = null;
4103
4310
  _shardingEnabled = false;
4311
+ _keyValidated = false;
4312
+ _keyValidationPromise = null;
4104
4313
  }
4105
4314
  });
4106
4315
 
@@ -4296,6 +4505,18 @@ var init_platform_procedures = __esm({
4296
4505
  priority: "p0",
4297
4506
  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.'"
4298
4507
  },
4508
+ {
4509
+ title: "Review chain \u2014 managers must actively pull completed work, never wait for nudges",
4510
+ domain: "workflow",
4511
+ priority: "p0",
4512
+ 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."
4513
+ },
4514
+ {
4515
+ title: "Bug fix lifecycle \u2014 triage upstream after every verified fix so customers see the status",
4516
+ domain: "workflow",
4517
+ priority: "p0",
4518
+ 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."
4519
+ },
4299
4520
  {
4300
4521
  title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
4301
4522
  domain: "architecture",
@@ -4893,6 +5114,20 @@ __export(store_exports, {
4893
5114
  vectorToBlob: () => vectorToBlob,
4894
5115
  writeMemory: () => writeMemory
4895
5116
  });
5117
+ function logStoreDebug(context, err) {
5118
+ if (_debugStore) {
5119
+ process.stderr.write(
5120
+ `[store] ${context}: ${err instanceof Error ? err.message : String(err)}
5121
+ `
5122
+ );
5123
+ }
5124
+ }
5125
+ function logStoreWarn(context, err) {
5126
+ process.stderr.write(
5127
+ `[store] WARN ${context}: ${err instanceof Error ? err.message : String(err)}
5128
+ `
5129
+ );
5130
+ }
4896
5131
  function isBusyError2(err) {
4897
5132
  if (err instanceof Error) {
4898
5133
  const msg = err.message.toLowerCase();
@@ -4947,13 +5182,15 @@ async function initStore(options) {
4947
5182
  try {
4948
5183
  const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
4949
5184
  await initDaemonClient2();
4950
- } catch {
5185
+ } catch (e) {
5186
+ logStoreWarn("catch", e);
4951
5187
  }
4952
5188
  if (!options?.lightweight) {
4953
5189
  try {
4954
5190
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
4955
5191
  initShardManager2(hexKey);
4956
- } catch {
5192
+ } catch (e) {
5193
+ logStoreWarn("catch", e);
4957
5194
  }
4958
5195
  const client = getClient();
4959
5196
  const vResult = await retryOnBusy2(
@@ -4964,7 +5201,8 @@ async function initStore(options) {
4964
5201
  try {
4965
5202
  const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
4966
5203
  await loadGlobalProcedures2();
4967
- } catch {
5204
+ } catch (e) {
5205
+ logStoreWarn("catch", e);
4968
5206
  }
4969
5207
  }
4970
5208
  }
@@ -5024,7 +5262,8 @@ async function writeMemory(record) {
5024
5262
  memoryType
5025
5263
  });
5026
5264
  if (existing) return;
5027
- } catch {
5265
+ } catch (e) {
5266
+ logStoreWarn("catch", e);
5028
5267
  }
5029
5268
  const dbRow = {
5030
5269
  id: record.id,
@@ -5225,12 +5464,14 @@ async function flushBatch() {
5225
5464
  try {
5226
5465
  const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
5227
5466
  await insertMemoryCardsForBatch2(batch);
5228
- } catch {
5467
+ } catch (e) {
5468
+ logStoreWarn("catch", e);
5229
5469
  }
5230
5470
  try {
5231
5471
  const { insertOntologyForBatch: insertOntologyForBatch2 } = await Promise.resolve().then(() => (init_agentic_ontology(), agentic_ontology_exports));
5232
5472
  await insertOntologyForBatch2(batch);
5233
- } catch {
5473
+ } catch (e) {
5474
+ logStoreWarn("catch", e);
5234
5475
  }
5235
5476
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
5236
5477
  _pendingRecords.splice(0, batch.length);
@@ -5269,7 +5510,8 @@ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
5269
5510
  }
5270
5511
  }
5271
5512
  }
5272
- } catch {
5513
+ } catch (e) {
5514
+ logStoreWarn("catch", e);
5273
5515
  }
5274
5516
  return batch.length;
5275
5517
  } finally {
@@ -5311,7 +5553,8 @@ async function searchMemories(queryVector, agentId, options) {
5311
5553
  } else {
5312
5554
  client = getClient();
5313
5555
  }
5314
- } catch {
5556
+ } catch (e) {
5557
+ logStoreDebug("shard routing fallback", e);
5315
5558
  client = getClient();
5316
5559
  }
5317
5560
  const limit = options?.limit ?? 10;
@@ -5427,7 +5670,8 @@ async function attachDocumentMetadata(records) {
5427
5670
  if (!record.document_id) continue;
5428
5671
  record.document_metadata = byId.get(record.document_id) ?? null;
5429
5672
  }
5430
- } catch {
5673
+ } catch (e) {
5674
+ logStoreWarn("catch", e);
5431
5675
  }
5432
5676
  return records;
5433
5677
  }
@@ -5488,11 +5732,12 @@ async function getMemoryCardinality(agentId) {
5488
5732
  args: [agentId]
5489
5733
  });
5490
5734
  return Number(result.rows[0]?.cnt) || 0;
5491
- } catch {
5735
+ } catch (e) {
5736
+ logStoreWarn("getMemoryCardinality", e);
5492
5737
  return 0;
5493
5738
  }
5494
5739
  }
5495
- var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
5740
+ var _debugStore, INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
5496
5741
  var init_store = __esm({
5497
5742
  "src/lib/store.ts"() {
5498
5743
  "use strict";
@@ -5502,6 +5747,7 @@ var init_store = __esm({
5502
5747
  init_config();
5503
5748
  init_state_bus();
5504
5749
  init_memory_write_governor();
5750
+ _debugStore = process.env.EXE_DEBUG === "1";
5505
5751
  INIT_MAX_RETRIES = 3;
5506
5752
  INIT_RETRY_DELAY_MS = 1e3;
5507
5753
  _pendingRecords = [];