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