@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
@@ -1771,9 +1771,79 @@ __export(database_exports, {
1771
1771
  isInitialized: () => isInitialized,
1772
1772
  setExternalClient: () => setExternalClient
1773
1773
  });
1774
- import { chmodSync as chmodSync2 } from "fs";
1774
+ 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";
1775
1775
  import { createClient } from "@libsql/client";
1776
+ import { homedir } from "os";
1777
+ import { join } from "path";
1778
+ function logCatchDebug(context, err) {
1779
+ if (_debugDb) {
1780
+ process.stderr.write(
1781
+ `[database] ${context}: ${err instanceof Error ? err.message : String(err)}
1782
+ `
1783
+ );
1784
+ }
1785
+ }
1786
+ function acquireDbLock() {
1787
+ mkdirSync2(join(homedir(), ".exe-os"), { recursive: true });
1788
+ try {
1789
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
1790
+ } catch (err) {
1791
+ if (err && typeof err === "object" && "code" in err && err.code === "EEXIST") {
1792
+ try {
1793
+ const lockStat = statSync2(DB_LOCK_PATH);
1794
+ if (Date.now() - lockStat.mtimeMs > 6e4) {
1795
+ unlinkSync3(DB_LOCK_PATH);
1796
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
1797
+ return;
1798
+ }
1799
+ } catch (e) {
1800
+ logCatchDebug("stale lock check", e);
1801
+ }
1802
+ process.stderr.write(
1803
+ "[database] WARN: Another process holds db.lock \u2014 waiting briefly then proceeding.\n"
1804
+ );
1805
+ return;
1806
+ }
1807
+ throw err;
1808
+ }
1809
+ }
1810
+ function releaseDbLock() {
1811
+ if (_lockFd !== null) {
1812
+ try {
1813
+ closeSync2(_lockFd);
1814
+ } catch (e) {
1815
+ logCatchDebug("lock close", e);
1816
+ }
1817
+ _lockFd = null;
1818
+ }
1819
+ try {
1820
+ unlinkSync3(DB_LOCK_PATH);
1821
+ } catch (e) {
1822
+ logCatchDebug("lock unlink", e);
1823
+ }
1824
+ }
1776
1825
  async function initDatabase(config) {
1826
+ acquireDbLock();
1827
+ if (existsSync6(config.dbPath)) {
1828
+ const dbStat = statSync2(config.dbPath);
1829
+ if (dbStat.size === 0) {
1830
+ const walPath = config.dbPath + "-wal";
1831
+ if (existsSync6(walPath) && statSync2(walPath).size > 0) {
1832
+ const backupPath = config.dbPath + ".zeroed-" + Date.now();
1833
+ copyFileSync(config.dbPath, backupPath);
1834
+ unlinkSync3(config.dbPath);
1835
+ process.stderr.write(
1836
+ `[database] CRITICAL: DB was 0 bytes. Moved to ${backupPath}, attempting WAL recovery.
1837
+ `
1838
+ );
1839
+ } else {
1840
+ process.stderr.write(
1841
+ `[database] CRITICAL: DB is 0 bytes and no WAL available for recovery. Data may be lost. Check backups at ${config.dbPath}.bak
1842
+ `
1843
+ );
1844
+ }
1845
+ }
1846
+ }
1777
1847
  if (_walCheckpointTimer) {
1778
1848
  clearInterval(_walCheckpointTimer);
1779
1849
  _walCheckpointTimer = null;
@@ -1800,10 +1870,8 @@ async function initDatabase(config) {
1800
1870
  _client = createClient(opts);
1801
1871
  _resilientClient = wrapWithRetry(_client);
1802
1872
  _adapterClient = _resilientClient;
1803
- _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
1804
- });
1805
- _client.execute("PRAGMA journal_mode = WAL").catch(() => {
1806
- });
1873
+ await _client.execute("PRAGMA busy_timeout = 30000");
1874
+ await _client.execute("PRAGMA journal_mode = WAL");
1807
1875
  if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
1808
1876
  _walCheckpointTimer = setInterval(() => {
1809
1877
  _client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
@@ -1818,11 +1886,16 @@ async function initDatabase(config) {
1818
1886
  for (const suffix of ["-wal", "-shm"]) {
1819
1887
  try {
1820
1888
  chmodSync2(config.dbPath + suffix, 384);
1821
- } catch {
1889
+ } catch (chmodErr) {
1890
+ process.stderr.write(`[database] chmod ${suffix} failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
1891
+ `);
1822
1892
  }
1823
1893
  }
1824
- } catch {
1894
+ } catch (chmodErr) {
1895
+ process.stderr.write(`[database] chmod db failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
1896
+ `);
1825
1897
  }
1898
+ releaseDbLock();
1826
1899
  }
1827
1900
  function isInitialized() {
1828
1901
  return _adapterClient !== null || _client !== null;
@@ -1877,7 +1950,8 @@ async function ensureSchema() {
1877
1950
  await client.execute("PRAGMA wal_autocheckpoint = 1000");
1878
1951
  try {
1879
1952
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
1880
- } catch {
1953
+ } catch (e) {
1954
+ logCatchDebug("migration", e);
1881
1955
  }
1882
1956
  await client.executeMultiple(`
1883
1957
  CREATE TABLE IF NOT EXISTS memories (
@@ -1942,6 +2016,23 @@ async function ensureSchema() {
1942
2016
  INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
1943
2017
  END;
1944
2018
  `);
2019
+ try {
2020
+ await client.execute("SELECT COUNT(*) FROM memories_fts LIMIT 1");
2021
+ } catch (ftsErr) {
2022
+ process.stderr.write(
2023
+ `[database] WARN: memories_fts corrupted (${ftsErr instanceof Error ? ftsErr.message : String(ftsErr)}) \u2014 rebuilding FTS index.
2024
+ `
2025
+ );
2026
+ try {
2027
+ await client.execute("INSERT INTO memories_fts(memories_fts) VALUES('rebuild')");
2028
+ process.stderr.write("[database] FTS index rebuilt successfully.\n");
2029
+ } catch (rebuildErr) {
2030
+ process.stderr.write(
2031
+ `[database] ERROR: FTS rebuild failed: ${rebuildErr instanceof Error ? rebuildErr.message : String(rebuildErr)}
2032
+ `
2033
+ );
2034
+ }
2035
+ }
1945
2036
  await client.executeMultiple(`
1946
2037
  CREATE TABLE IF NOT EXISTS sync_meta (
1947
2038
  key TEXT PRIMARY KEY,
@@ -2000,35 +2091,40 @@ async function ensureSchema() {
2000
2091
  });
2001
2092
  }
2002
2093
  }
2003
- } catch {
2094
+ } catch (seedErr) {
2095
+ logCatchDebug("behavior seed", seedErr);
2004
2096
  }
2005
2097
  try {
2006
2098
  await client.execute({
2007
2099
  sql: `ALTER TABLE behaviors ADD COLUMN priority TEXT DEFAULT 'p1'`,
2008
2100
  args: []
2009
2101
  });
2010
- } catch {
2102
+ } catch (e) {
2103
+ logCatchDebug("migration", e);
2011
2104
  }
2012
2105
  try {
2013
2106
  await client.execute({
2014
2107
  sql: `ALTER TABLE behaviors ADD COLUMN vector F32_BLOB(${EMBEDDING_DIM})`,
2015
2108
  args: []
2016
2109
  });
2017
- } catch {
2110
+ } catch (e) {
2111
+ logCatchDebug("migration", e);
2018
2112
  }
2019
2113
  try {
2020
2114
  await client.execute({
2021
2115
  sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
2022
2116
  args: []
2023
2117
  });
2024
- } catch {
2118
+ } catch (e) {
2119
+ logCatchDebug("migration", e);
2025
2120
  }
2026
2121
  try {
2027
2122
  await client.execute({
2028
2123
  sql: `ALTER TABLE tasks ADD COLUMN parent_task_id TEXT`,
2029
2124
  args: []
2030
2125
  });
2031
- } catch {
2126
+ } catch (e) {
2127
+ logCatchDebug("migration", e);
2032
2128
  }
2033
2129
  try {
2034
2130
  await client.execute({
@@ -2037,98 +2133,112 @@ async function ensureSchema() {
2037
2133
  WHERE parent_task_id IS NOT NULL`,
2038
2134
  args: []
2039
2135
  });
2040
- } catch {
2136
+ } catch (e) {
2137
+ logCatchDebug("migration", e);
2041
2138
  }
2042
2139
  try {
2043
2140
  await client.execute({
2044
2141
  sql: `UPDATE tasks SET status = 'done' WHERE status = 'completed'`,
2045
2142
  args: []
2046
2143
  });
2047
- } catch {
2144
+ } catch (e) {
2145
+ logCatchDebug("migration", e);
2048
2146
  }
2049
2147
  try {
2050
2148
  await client.execute({
2051
2149
  sql: `ALTER TABLE tasks ADD COLUMN reviewer TEXT`,
2052
2150
  args: []
2053
2151
  });
2054
- } catch {
2152
+ } catch (e) {
2153
+ logCatchDebug("migration", e);
2055
2154
  }
2056
2155
  try {
2057
2156
  await client.execute({
2058
2157
  sql: `ALTER TABLE tasks ADD COLUMN context TEXT`,
2059
2158
  args: []
2060
2159
  });
2061
- } catch {
2160
+ } catch (e) {
2161
+ logCatchDebug("migration", e);
2062
2162
  }
2063
2163
  try {
2064
2164
  await client.execute({
2065
2165
  sql: `ALTER TABLE tasks ADD COLUMN result TEXT`,
2066
2166
  args: []
2067
2167
  });
2068
- } catch {
2168
+ } catch (e) {
2169
+ logCatchDebug("migration", e);
2069
2170
  }
2070
2171
  try {
2071
2172
  await client.execute({
2072
2173
  sql: `ALTER TABLE tasks ADD COLUMN assigned_tmux TEXT`,
2073
2174
  args: []
2074
2175
  });
2075
- } catch {
2176
+ } catch (e) {
2177
+ logCatchDebug("migration", e);
2076
2178
  }
2077
2179
  try {
2078
2180
  await client.execute({
2079
2181
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint TEXT`,
2080
2182
  args: []
2081
2183
  });
2082
- } catch {
2184
+ } catch (e) {
2185
+ logCatchDebug("migration", e);
2083
2186
  }
2084
2187
  try {
2085
2188
  await client.execute({
2086
2189
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER NOT NULL DEFAULT 0`,
2087
2190
  args: []
2088
2191
  });
2089
- } catch {
2192
+ } catch (e) {
2193
+ logCatchDebug("migration", e);
2090
2194
  }
2091
2195
  try {
2092
2196
  await client.execute({
2093
2197
  sql: `ALTER TABLE tasks ADD COLUMN complexity TEXT NOT NULL DEFAULT 'standard'`,
2094
2198
  args: []
2095
2199
  });
2096
- } catch {
2200
+ } catch (e) {
2201
+ logCatchDebug("migration", e);
2097
2202
  }
2098
2203
  try {
2099
2204
  await client.execute({
2100
2205
  sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
2101
2206
  args: []
2102
2207
  });
2103
- } catch {
2208
+ } catch (e) {
2209
+ logCatchDebug("migration", e);
2104
2210
  }
2105
2211
  try {
2106
2212
  await client.execute({
2107
2213
  sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
2108
2214
  args: []
2109
2215
  });
2110
- } catch {
2216
+ } catch (e) {
2217
+ logCatchDebug("migration", e);
2111
2218
  }
2112
2219
  try {
2113
2220
  await client.execute({
2114
2221
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
2115
2222
  args: []
2116
2223
  });
2117
- } catch {
2224
+ } catch (e) {
2225
+ logCatchDebug("migration", e);
2118
2226
  }
2119
2227
  try {
2120
2228
  await client.execute({
2121
2229
  sql: `ALTER TABLE memories ADD COLUMN author_device_id TEXT`,
2122
2230
  args: []
2123
2231
  });
2124
- } catch {
2232
+ } catch (e) {
2233
+ logCatchDebug("migration", e);
2125
2234
  }
2126
2235
  try {
2127
2236
  await client.execute({
2128
2237
  sql: `ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'`,
2129
2238
  args: []
2130
2239
  });
2131
- } catch {
2240
+ } catch (e) {
2241
+ logCatchDebug("migration", e);
2132
2242
  }
2133
2243
  await client.executeMultiple(`
2134
2244
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2233,14 +2343,16 @@ async function ensureSchema() {
2233
2343
  sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
2234
2344
  args: []
2235
2345
  });
2236
- } catch {
2346
+ } catch (e) {
2347
+ logCatchDebug("migration", e);
2237
2348
  }
2238
2349
  try {
2239
2350
  await client.execute({
2240
2351
  sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
2241
2352
  args: []
2242
2353
  });
2243
- } catch {
2354
+ } catch (e) {
2355
+ logCatchDebug("migration", e);
2244
2356
  }
2245
2357
  await client.executeMultiple(`
2246
2358
  CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
@@ -2266,7 +2378,8 @@ async function ensureSchema() {
2266
2378
  sql: `UPDATE tasks SET project_name = 'exe-os' WHERE project_name = 'worker'`,
2267
2379
  args: []
2268
2380
  });
2269
- } catch {
2381
+ } catch (e) {
2382
+ logCatchDebug("migration", e);
2270
2383
  }
2271
2384
  await client.executeMultiple(`
2272
2385
  CREATE TABLE IF NOT EXISTS trajectories (
@@ -2290,7 +2403,8 @@ async function ensureSchema() {
2290
2403
  `);
2291
2404
  try {
2292
2405
  await client.execute("ALTER TABLE trajectories ADD COLUMN skill_id TEXT");
2293
- } catch {
2406
+ } catch (e) {
2407
+ logCatchDebug("migration", e);
2294
2408
  }
2295
2409
  await client.executeMultiple(`
2296
2410
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2327,63 +2441,72 @@ async function ensureSchema() {
2327
2441
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
2328
2442
  args: []
2329
2443
  });
2330
- } catch {
2444
+ } catch (e) {
2445
+ logCatchDebug("migration", e);
2331
2446
  }
2332
2447
  try {
2333
2448
  await client.execute({
2334
2449
  sql: `ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5`,
2335
2450
  args: []
2336
2451
  });
2337
- } catch {
2452
+ } catch (e) {
2453
+ logCatchDebug("migration", e);
2338
2454
  }
2339
2455
  try {
2340
2456
  await client.execute({
2341
2457
  sql: `ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'`,
2342
2458
  args: []
2343
2459
  });
2344
- } catch {
2460
+ } catch (e) {
2461
+ logCatchDebug("migration", e);
2345
2462
  }
2346
2463
  try {
2347
2464
  await client.execute({
2348
2465
  sql: `ALTER TABLE memories ADD COLUMN deleted_at TEXT`,
2349
2466
  args: []
2350
2467
  });
2351
- } catch {
2468
+ } catch (e) {
2469
+ logCatchDebug("migration", e);
2352
2470
  }
2353
2471
  try {
2354
2472
  await client.execute({
2355
2473
  sql: `ALTER TABLE memories ADD COLUMN confidence REAL DEFAULT 0.7`,
2356
2474
  args: []
2357
2475
  });
2358
- } catch {
2476
+ } catch (e) {
2477
+ logCatchDebug("migration", e);
2359
2478
  }
2360
2479
  try {
2361
2480
  await client.execute({
2362
2481
  sql: `ALTER TABLE memories ADD COLUMN last_accessed TEXT`,
2363
2482
  args: []
2364
2483
  });
2365
- } catch {
2484
+ } catch (e) {
2485
+ logCatchDebug("migration", e);
2366
2486
  }
2367
2487
  try {
2368
2488
  await client.execute({
2369
2489
  sql: `UPDATE memories SET last_accessed = timestamp WHERE last_accessed IS NULL`,
2370
2490
  args: []
2371
2491
  });
2372
- } catch {
2492
+ } catch (e) {
2493
+ logCatchDebug("migration", e);
2373
2494
  }
2374
2495
  try {
2375
2496
  await client.execute({
2376
2497
  sql: `ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0`,
2377
2498
  args: []
2378
2499
  });
2379
- } catch {
2500
+ } catch (e) {
2501
+ logCatchDebug("migration", e);
2380
2502
  }
2381
2503
  try {
2382
2504
  await client.execute({
2383
2505
  sql: `ALTER TABLE memories ADD COLUMN graph_extracted INTEGER DEFAULT 0`,
2384
2506
  args: []
2385
2507
  });
2386
- } catch {
2508
+ } catch (e) {
2509
+ logCatchDebug("migration", e);
2387
2510
  }
2388
2511
  for (const col of [
2389
2512
  "ALTER TABLE memories ADD COLUMN content_hash TEXT",
@@ -2391,14 +2514,16 @@ async function ensureSchema() {
2391
2514
  ]) {
2392
2515
  try {
2393
2516
  await client.execute(col);
2394
- } catch {
2517
+ } catch (e) {
2518
+ logCatchDebug("migration", e);
2395
2519
  }
2396
2520
  }
2397
2521
  try {
2398
2522
  await client.execute(
2399
2523
  `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
2400
2524
  );
2401
- } catch {
2525
+ } catch (e) {
2526
+ logCatchDebug("migration", e);
2402
2527
  }
2403
2528
  try {
2404
2529
  await client.execute(
@@ -2406,7 +2531,8 @@ async function ensureSchema() {
2406
2531
  ON memories(content_hash, agent_id, project_name, memory_type)
2407
2532
  WHERE content_hash IS NOT NULL`
2408
2533
  );
2409
- } catch {
2534
+ } catch (e) {
2535
+ logCatchDebug("migration", e);
2410
2536
  }
2411
2537
  await client.executeMultiple(`
2412
2538
  CREATE TABLE IF NOT EXISTS entities (
@@ -2482,7 +2608,8 @@ async function ensureSchema() {
2482
2608
  `);
2483
2609
  try {
2484
2610
  await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
2485
- } catch {
2611
+ } catch (e) {
2612
+ logCatchDebug("migration", e);
2486
2613
  }
2487
2614
  await client.executeMultiple(`
2488
2615
  CREATE TABLE IF NOT EXISTS entity_aliases (
@@ -2497,14 +2624,16 @@ async function ensureSchema() {
2497
2624
  ]) {
2498
2625
  try {
2499
2626
  await client.execute(col);
2500
- } catch {
2627
+ } catch (e) {
2628
+ logCatchDebug("migration", e);
2501
2629
  }
2502
2630
  }
2503
2631
  try {
2504
2632
  await client.execute(
2505
2633
  `CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)`
2506
2634
  );
2507
- } catch {
2635
+ } catch (e) {
2636
+ logCatchDebug("migration", e);
2508
2637
  }
2509
2638
  await client.executeMultiple(`
2510
2639
  CREATE TABLE IF NOT EXISTS identity (
@@ -2603,7 +2732,8 @@ async function ensureSchema() {
2603
2732
  sql: `ALTER TABLE memories ADD COLUMN ${column}`,
2604
2733
  args: []
2605
2734
  });
2606
- } catch {
2735
+ } catch (e) {
2736
+ logCatchDebug("migration", e);
2607
2737
  }
2608
2738
  }
2609
2739
  for (const col of [
@@ -2612,7 +2742,8 @@ async function ensureSchema() {
2612
2742
  ]) {
2613
2743
  try {
2614
2744
  await client.execute(col);
2615
- } catch {
2745
+ } catch (e) {
2746
+ logCatchDebug("migration", e);
2616
2747
  }
2617
2748
  }
2618
2749
  await client.executeMultiple(`
@@ -2797,56 +2928,64 @@ async function ensureSchema() {
2797
2928
  args: []
2798
2929
  });
2799
2930
  }
2800
- } catch {
2931
+ } catch (e) {
2932
+ logCatchDebug("session_agent_map backfill", e);
2801
2933
  }
2802
2934
  try {
2803
2935
  await client.execute({
2804
2936
  sql: `ALTER TABLE session_agent_map ADD COLUMN cache_cold_count INTEGER NOT NULL DEFAULT 0`,
2805
2937
  args: []
2806
2938
  });
2807
- } catch {
2939
+ } catch (e) {
2940
+ logCatchDebug("migration", e);
2808
2941
  }
2809
2942
  try {
2810
2943
  await client.execute({
2811
2944
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
2812
2945
  args: []
2813
2946
  });
2814
- } catch {
2947
+ } catch (e) {
2948
+ logCatchDebug("migration", e);
2815
2949
  }
2816
2950
  try {
2817
2951
  await client.execute({
2818
2952
  sql: `ALTER TABLE tasks ADD COLUMN budget_fallback_model TEXT`,
2819
2953
  args: []
2820
2954
  });
2821
- } catch {
2955
+ } catch (e) {
2956
+ logCatchDebug("migration", e);
2822
2957
  }
2823
2958
  try {
2824
2959
  await client.execute({
2825
2960
  sql: `ALTER TABLE tasks ADD COLUMN tokens_used INTEGER DEFAULT 0`,
2826
2961
  args: []
2827
2962
  });
2828
- } catch {
2963
+ } catch (e) {
2964
+ logCatchDebug("migration", e);
2829
2965
  }
2830
2966
  try {
2831
2967
  await client.execute({
2832
2968
  sql: `ALTER TABLE tasks ADD COLUMN tokens_warned_at INTEGER`,
2833
2969
  args: []
2834
2970
  });
2835
- } catch {
2971
+ } catch (e) {
2972
+ logCatchDebug("migration", e);
2836
2973
  }
2837
2974
  try {
2838
2975
  await client.execute({
2839
2976
  sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
2840
2977
  args: []
2841
2978
  });
2842
- } catch {
2979
+ } catch (e) {
2980
+ logCatchDebug("migration", e);
2843
2981
  }
2844
2982
  try {
2845
2983
  await client.execute({
2846
2984
  sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
2847
2985
  args: []
2848
2986
  });
2849
- } catch {
2987
+ } catch (e) {
2988
+ logCatchDebug("migration", e);
2850
2989
  }
2851
2990
  await client.executeMultiple(`
2852
2991
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
@@ -3045,13 +3184,15 @@ async function ensureSchema() {
3045
3184
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
3046
3185
  args: []
3047
3186
  });
3048
- } catch {
3187
+ } catch (e) {
3188
+ logCatchDebug("migration", e);
3049
3189
  }
3050
3190
  try {
3051
3191
  await client.execute(
3052
3192
  `CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
3053
3193
  );
3054
- } catch {
3194
+ } catch (e) {
3195
+ logCatchDebug("migration", e);
3055
3196
  }
3056
3197
  try {
3057
3198
  await client.execute({
@@ -3062,20 +3203,23 @@ async function ensureSchema() {
3062
3203
  sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
3063
3204
  args: []
3064
3205
  });
3065
- } catch {
3206
+ } catch (e) {
3207
+ logCatchDebug("migration", e);
3066
3208
  }
3067
3209
  try {
3068
3210
  await client.execute({
3069
3211
  sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
3070
3212
  args: []
3071
3213
  });
3072
- } catch {
3214
+ } catch (e) {
3215
+ logCatchDebug("migration", e);
3073
3216
  }
3074
3217
  try {
3075
3218
  await client.execute(
3076
3219
  `CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
3077
3220
  );
3078
- } catch {
3221
+ } catch (e) {
3222
+ logCatchDebug("migration", e);
3079
3223
  }
3080
3224
  for (const col of [
3081
3225
  "ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
@@ -3083,7 +3227,8 @@ async function ensureSchema() {
3083
3227
  ]) {
3084
3228
  try {
3085
3229
  await client.execute(col);
3086
- } catch {
3230
+ } catch (e) {
3231
+ logCatchDebug("migration", e);
3087
3232
  }
3088
3233
  }
3089
3234
  try {
@@ -3091,13 +3236,15 @@ async function ensureSchema() {
3091
3236
  sql: `ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0`,
3092
3237
  args: []
3093
3238
  });
3094
- } catch {
3239
+ } catch (e) {
3240
+ logCatchDebug("migration", e);
3095
3241
  }
3096
3242
  try {
3097
3243
  await client.execute(
3098
3244
  `CREATE INDEX IF NOT EXISTS idx_memories_draft ON memories(draft) WHERE draft = 1`
3099
3245
  );
3100
- } catch {
3246
+ } catch (e) {
3247
+ logCatchDebug("migration", e);
3101
3248
  }
3102
3249
  for (const col of [
3103
3250
  "ALTER TABLE memories ADD COLUMN valid_from TEXT",
@@ -3105,7 +3252,8 @@ async function ensureSchema() {
3105
3252
  ]) {
3106
3253
  try {
3107
3254
  await client.execute(col);
3108
- } catch {
3255
+ } catch (e) {
3256
+ logCatchDebug("migration", e);
3109
3257
  }
3110
3258
  }
3111
3259
  try {
@@ -3113,27 +3261,31 @@ async function ensureSchema() {
3113
3261
  sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
3114
3262
  args: []
3115
3263
  });
3116
- } catch {
3264
+ } catch (e) {
3265
+ logCatchDebug("migration", e);
3117
3266
  }
3118
3267
  try {
3119
3268
  await client.execute({
3120
3269
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
3121
3270
  args: []
3122
3271
  });
3123
- } catch {
3272
+ } catch (e) {
3273
+ logCatchDebug("migration", e);
3124
3274
  }
3125
3275
  try {
3126
3276
  await client.execute(
3127
3277
  `CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(memory_type)`
3128
3278
  );
3129
- } catch {
3279
+ } catch (e) {
3280
+ logCatchDebug("migration", e);
3130
3281
  }
3131
3282
  try {
3132
3283
  await client.execute({
3133
3284
  sql: `ALTER TABLE memories ADD COLUMN trajectory TEXT`,
3134
3285
  args: []
3135
3286
  });
3136
- } catch {
3287
+ } catch (e) {
3288
+ logCatchDebug("migration", e);
3137
3289
  }
3138
3290
  for (const col of [
3139
3291
  "ALTER TABLE memories ADD COLUMN intent TEXT",
@@ -3154,7 +3306,8 @@ async function ensureSchema() {
3154
3306
  ]) {
3155
3307
  try {
3156
3308
  await client.execute(col);
3157
- } catch {
3309
+ } catch (e) {
3310
+ logCatchDebug("migration", e);
3158
3311
  }
3159
3312
  }
3160
3313
  try {
@@ -3162,14 +3315,16 @@ async function ensureSchema() {
3162
3315
  sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
3163
3316
  args: []
3164
3317
  });
3165
- } catch {
3318
+ } catch (e) {
3319
+ logCatchDebug("migration", e);
3166
3320
  }
3167
3321
  try {
3168
3322
  await client.execute({
3169
3323
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
3170
3324
  args: []
3171
3325
  });
3172
- } catch {
3326
+ } catch (e) {
3327
+ logCatchDebug("migration", e);
3173
3328
  }
3174
3329
  }
3175
3330
  async function disposeDatabase() {
@@ -3180,7 +3335,8 @@ async function disposeDatabase() {
3180
3335
  if (_client) {
3181
3336
  try {
3182
3337
  await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3183
- } catch {
3338
+ } catch (e) {
3339
+ logCatchDebug("WAL checkpoint", e);
3184
3340
  }
3185
3341
  }
3186
3342
  if (_daemonClient) {
@@ -3196,8 +3352,9 @@ async function disposeDatabase() {
3196
3352
  _client = null;
3197
3353
  _resilientClient = null;
3198
3354
  }
3355
+ releaseDbLock();
3199
3356
  }
3200
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
3357
+ var _debugDb, _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, _lockFd, DB_LOCK_PATH, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
3201
3358
  var init_database = __esm({
3202
3359
  "src/lib/database.ts"() {
3203
3360
  "use strict";
@@ -3205,11 +3362,14 @@ var init_database = __esm({
3205
3362
  init_employees();
3206
3363
  init_database_adapter();
3207
3364
  init_memory();
3365
+ _debugDb = process.env.EXE_DEBUG === "1";
3208
3366
  _client = null;
3209
3367
  _resilientClient = null;
3210
3368
  _walCheckpointTimer = null;
3211
3369
  _daemonClient = null;
3212
3370
  _adapterClient = null;
3371
+ _lockFd = null;
3372
+ DB_LOCK_PATH = join(homedir(), ".exe-os", "db.lock");
3213
3373
  initTurso = initDatabase;
3214
3374
  SOFT_DELETE_RETENTION_DAYS = 7;
3215
3375
  disposeTurso = disposeDatabase;
@@ -3218,7 +3378,7 @@ var init_database = __esm({
3218
3378
 
3219
3379
  // src/lib/keychain.ts
3220
3380
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3221
- import { existsSync as existsSync6, statSync as statSync2 } from "fs";
3381
+ import { existsSync as existsSync7, statSync as statSync3 } from "fs";
3222
3382
  import { execSync as execSync3 } from "child_process";
3223
3383
  import path6 from "path";
3224
3384
  import os5 from "os";
@@ -3253,7 +3413,7 @@ function isRootOnlyTrustedServerKeyFile(keyPath) {
3253
3413
  if (process.platform !== "linux") return false;
3254
3414
  try {
3255
3415
  const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
3256
- const st = statSync2(keyPath);
3416
+ const st = statSync3(keyPath);
3257
3417
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
3258
3418
  if (uid === 0) return true;
3259
3419
  const exeOsDir = process.env.EXE_OS_DIR;
@@ -3454,7 +3614,7 @@ async function getMasterKey() {
3454
3614
  }
3455
3615
  }
3456
3616
  const keyPath = getKeyPath();
3457
- if (!existsSync6(keyPath)) {
3617
+ if (!existsSync7(keyPath)) {
3458
3618
  process.stderr.write(
3459
3619
  `[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
3460
3620
  `
@@ -3789,18 +3949,54 @@ __export(shard_manager_exports, {
3789
3949
  shardExists: () => shardExists
3790
3950
  });
3791
3951
  import path7 from "path";
3792
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync3 } from "fs";
3952
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3, readdirSync, renameSync as renameSync3, statSync as statSync4 } from "fs";
3793
3953
  import { createClient as createClient2 } from "@libsql/client";
3794
3954
  function initShardManager(encryptionKey) {
3795
3955
  _encryptionKey = encryptionKey;
3796
- if (!existsSync7(SHARDS_DIR)) {
3797
- mkdirSync2(SHARDS_DIR, { recursive: true });
3956
+ _keyValidated = false;
3957
+ _keyValidationPromise = null;
3958
+ if (!existsSync8(SHARDS_DIR)) {
3959
+ mkdirSync3(SHARDS_DIR, { recursive: true });
3960
+ }
3961
+ const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
3962
+ if (existingShards.length === 0) {
3963
+ _keyValidated = true;
3798
3964
  }
3799
3965
  _shardingEnabled = true;
3800
3966
  if (_evictionTimer) clearInterval(_evictionTimer);
3801
3967
  _evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
3802
3968
  _evictionTimer.unref();
3803
3969
  }
3970
+ async function validateEncryptionKey() {
3971
+ if (_keyValidated) return true;
3972
+ if (!_encryptionKey) return false;
3973
+ const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
3974
+ if (existingShards.length === 0) {
3975
+ _keyValidated = true;
3976
+ return true;
3977
+ }
3978
+ for (const shardFile of existingShards.slice(0, 3)) {
3979
+ const dbPath = path7.join(SHARDS_DIR, shardFile);
3980
+ const testClient = createClient2({ url: `file:${dbPath}`, encryptionKey: _encryptionKey });
3981
+ try {
3982
+ await testClient.execute("SELECT COUNT(*) FROM sqlite_schema");
3983
+ testClient.close();
3984
+ _keyValidated = true;
3985
+ return true;
3986
+ } catch {
3987
+ try {
3988
+ testClient.close();
3989
+ } catch {
3990
+ }
3991
+ }
3992
+ }
3993
+ process.stderr.write(
3994
+ `[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.
3995
+ `
3996
+ );
3997
+ _shardingEnabled = false;
3998
+ return false;
3999
+ }
3804
4000
  function isShardingEnabled() {
3805
4001
  return _shardingEnabled;
3806
4002
  }
@@ -3834,13 +4030,13 @@ function getShardClient(projectName) {
3834
4030
  }
3835
4031
  function shardExists(projectName) {
3836
4032
  const safeName = safeShardName(projectName);
3837
- return existsSync7(path7.join(SHARDS_DIR, `${safeName}.db`));
4033
+ return existsSync8(path7.join(SHARDS_DIR, `${safeName}.db`));
3838
4034
  }
3839
4035
  function safeShardName(projectName) {
3840
4036
  return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3841
4037
  }
3842
4038
  function listShards() {
3843
- if (!existsSync7(SHARDS_DIR)) return [];
4039
+ if (!existsSync8(SHARDS_DIR)) return [];
3844
4040
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
3845
4041
  }
3846
4042
  async function auditShardHealth(options = {}) {
@@ -3853,7 +4049,7 @@ async function auditShardHealth(options = {}) {
3853
4049
  const shards = [];
3854
4050
  for (const name of names) {
3855
4051
  const dbPath = path7.join(SHARDS_DIR, `${name}.db`);
3856
- const stat = statSync3(dbPath);
4052
+ const stat = statSync4(dbPath);
3857
4053
  const item = {
3858
4054
  name,
3859
4055
  path: dbPath,
@@ -4093,6 +4289,17 @@ async function ensureShardSchema(client) {
4093
4289
  }
4094
4290
  }
4095
4291
  async function getReadyShardClient(projectName) {
4292
+ if (!_keyValidated) {
4293
+ if (!_keyValidationPromise) {
4294
+ _keyValidationPromise = validateEncryptionKey();
4295
+ }
4296
+ const valid = await _keyValidationPromise;
4297
+ if (!valid) {
4298
+ throw new Error(
4299
+ `Shard creation blocked: encryption key mismatch with existing shards. Run /exe-doctor to audit.`
4300
+ );
4301
+ }
4302
+ }
4096
4303
  const safeName = safeShardName(projectName);
4097
4304
  let client = getShardClient(projectName);
4098
4305
  try {
@@ -4105,8 +4312,8 @@ async function getReadyShardClient(projectName) {
4105
4312
  _shards.delete(safeName);
4106
4313
  _shardLastAccess.delete(safeName);
4107
4314
  const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
4108
- if (existsSync7(dbPath)) {
4109
- const stat = statSync3(dbPath);
4315
+ if (existsSync8(dbPath)) {
4316
+ const stat = statSync4(dbPath);
4110
4317
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4111
4318
  const archivedPath = path7.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
4112
4319
  renameSync3(dbPath, archivedPath);
@@ -4171,7 +4378,7 @@ function disposeShards() {
4171
4378
  _shardingEnabled = false;
4172
4379
  _encryptionKey = null;
4173
4380
  }
4174
- var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
4381
+ var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled, _keyValidated, _keyValidationPromise;
4175
4382
  var init_shard_manager = __esm({
4176
4383
  "src/lib/shard-manager.ts"() {
4177
4384
  "use strict";
@@ -4185,6 +4392,8 @@ var init_shard_manager = __esm({
4185
4392
  _evictionTimer = null;
4186
4393
  _encryptionKey = null;
4187
4394
  _shardingEnabled = false;
4395
+ _keyValidated = false;
4396
+ _keyValidationPromise = null;
4188
4397
  }
4189
4398
  });
4190
4399
 
@@ -4380,6 +4589,18 @@ var init_platform_procedures = __esm({
4380
4589
  priority: "p0",
4381
4590
  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.'"
4382
4591
  },
4592
+ {
4593
+ title: "Review chain \u2014 managers must actively pull completed work, never wait for nudges",
4594
+ domain: "workflow",
4595
+ priority: "p0",
4596
+ 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."
4597
+ },
4598
+ {
4599
+ title: "Bug fix lifecycle \u2014 triage upstream after every verified fix so customers see the status",
4600
+ domain: "workflow",
4601
+ priority: "p0",
4602
+ 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."
4603
+ },
4383
4604
  {
4384
4605
  title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
4385
4606
  domain: "architecture",
@@ -4977,6 +5198,20 @@ __export(store_exports, {
4977
5198
  vectorToBlob: () => vectorToBlob,
4978
5199
  writeMemory: () => writeMemory
4979
5200
  });
5201
+ function logStoreDebug(context, err) {
5202
+ if (_debugStore) {
5203
+ process.stderr.write(
5204
+ `[store] ${context}: ${err instanceof Error ? err.message : String(err)}
5205
+ `
5206
+ );
5207
+ }
5208
+ }
5209
+ function logStoreWarn(context, err) {
5210
+ process.stderr.write(
5211
+ `[store] WARN ${context}: ${err instanceof Error ? err.message : String(err)}
5212
+ `
5213
+ );
5214
+ }
4980
5215
  function isBusyError2(err) {
4981
5216
  if (err instanceof Error) {
4982
5217
  const msg = err.message.toLowerCase();
@@ -5031,13 +5266,15 @@ async function initStore(options) {
5031
5266
  try {
5032
5267
  const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
5033
5268
  await initDaemonClient2();
5034
- } catch {
5269
+ } catch (e) {
5270
+ logStoreWarn("catch", e);
5035
5271
  }
5036
5272
  if (!options?.lightweight) {
5037
5273
  try {
5038
5274
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
5039
5275
  initShardManager2(hexKey);
5040
- } catch {
5276
+ } catch (e) {
5277
+ logStoreWarn("catch", e);
5041
5278
  }
5042
5279
  const client = getClient();
5043
5280
  const vResult = await retryOnBusy2(
@@ -5048,7 +5285,8 @@ async function initStore(options) {
5048
5285
  try {
5049
5286
  const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
5050
5287
  await loadGlobalProcedures2();
5051
- } catch {
5288
+ } catch (e) {
5289
+ logStoreWarn("catch", e);
5052
5290
  }
5053
5291
  }
5054
5292
  }
@@ -5108,7 +5346,8 @@ async function writeMemory(record) {
5108
5346
  memoryType
5109
5347
  });
5110
5348
  if (existing) return;
5111
- } catch {
5349
+ } catch (e) {
5350
+ logStoreWarn("catch", e);
5112
5351
  }
5113
5352
  const dbRow = {
5114
5353
  id: record.id,
@@ -5309,12 +5548,14 @@ async function flushBatch() {
5309
5548
  try {
5310
5549
  const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
5311
5550
  await insertMemoryCardsForBatch2(batch);
5312
- } catch {
5551
+ } catch (e) {
5552
+ logStoreWarn("catch", e);
5313
5553
  }
5314
5554
  try {
5315
5555
  const { insertOntologyForBatch: insertOntologyForBatch2 } = await Promise.resolve().then(() => (init_agentic_ontology(), agentic_ontology_exports));
5316
5556
  await insertOntologyForBatch2(batch);
5317
- } catch {
5557
+ } catch (e) {
5558
+ logStoreWarn("catch", e);
5318
5559
  }
5319
5560
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
5320
5561
  _pendingRecords.splice(0, batch.length);
@@ -5353,7 +5594,8 @@ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
5353
5594
  }
5354
5595
  }
5355
5596
  }
5356
- } catch {
5597
+ } catch (e) {
5598
+ logStoreWarn("catch", e);
5357
5599
  }
5358
5600
  return batch.length;
5359
5601
  } finally {
@@ -5395,7 +5637,8 @@ async function searchMemories(queryVector, agentId, options) {
5395
5637
  } else {
5396
5638
  client = getClient();
5397
5639
  }
5398
- } catch {
5640
+ } catch (e) {
5641
+ logStoreDebug("shard routing fallback", e);
5399
5642
  client = getClient();
5400
5643
  }
5401
5644
  const limit = options?.limit ?? 10;
@@ -5511,7 +5754,8 @@ async function attachDocumentMetadata(records) {
5511
5754
  if (!record.document_id) continue;
5512
5755
  record.document_metadata = byId.get(record.document_id) ?? null;
5513
5756
  }
5514
- } catch {
5757
+ } catch (e) {
5758
+ logStoreWarn("catch", e);
5515
5759
  }
5516
5760
  return records;
5517
5761
  }
@@ -5572,11 +5816,12 @@ async function getMemoryCardinality(agentId) {
5572
5816
  args: [agentId]
5573
5817
  });
5574
5818
  return Number(result.rows[0]?.cnt) || 0;
5575
- } catch {
5819
+ } catch (e) {
5820
+ logStoreWarn("getMemoryCardinality", e);
5576
5821
  return 0;
5577
5822
  }
5578
5823
  }
5579
- var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
5824
+ var _debugStore, INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
5580
5825
  var init_store = __esm({
5581
5826
  "src/lib/store.ts"() {
5582
5827
  "use strict";
@@ -5586,6 +5831,7 @@ var init_store = __esm({
5586
5831
  init_config();
5587
5832
  init_state_bus();
5588
5833
  init_memory_write_governor();
5834
+ _debugStore = process.env.EXE_DEBUG === "1";
5589
5835
  INIT_MAX_RETRIES = 3;
5590
5836
  INIT_RETRY_DELAY_MS = 1e3;
5591
5837
  _pendingRecords = [];
@@ -5625,10 +5871,10 @@ var init_runtime_table = __esm({
5625
5871
  });
5626
5872
 
5627
5873
  // src/lib/agent-config.ts
5628
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync9 } from "fs";
5874
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync10 } from "fs";
5629
5875
  import path9 from "path";
5630
5876
  function loadAgentConfig() {
5631
- if (!existsSync9(AGENT_CONFIG_PATH)) return {};
5877
+ if (!existsSync10(AGENT_CONFIG_PATH)) return {};
5632
5878
  try {
5633
5879
  return JSON.parse(readFileSync5(AGENT_CONFIG_PATH, "utf-8"));
5634
5880
  } catch {
@@ -5750,7 +5996,7 @@ __export(active_agent_exports, {
5750
5996
  resolveActiveAgentFromTmuxSession: () => resolveActiveAgentFromTmuxSession,
5751
5997
  writeActiveAgent: () => writeActiveAgent
5752
5998
  });
5753
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, unlinkSync as unlinkSync4, readdirSync as readdirSync3 } from "fs";
5999
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, unlinkSync as unlinkSync5, readdirSync as readdirSync3 } from "fs";
5754
6000
  import { execSync as execSync6 } from "child_process";
5755
6001
  import path10 from "path";
5756
6002
  function isNameWithOptionalInstance(candidate, baseName) {
@@ -5800,7 +6046,7 @@ function getMarkerPath() {
5800
6046
  }
5801
6047
  function writeActiveAgent(agentId, agentRole) {
5802
6048
  try {
5803
- mkdirSync4(CACHE_DIR, { recursive: true });
6049
+ mkdirSync5(CACHE_DIR, { recursive: true });
5804
6050
  writeFileSync5(
5805
6051
  getMarkerPath(),
5806
6052
  JSON.stringify({ agentId, agentRole, startedAt: (/* @__PURE__ */ new Date()).toISOString() })
@@ -5810,7 +6056,7 @@ function writeActiveAgent(agentId, agentRole) {
5810
6056
  }
5811
6057
  function clearActiveAgent() {
5812
6058
  try {
5813
- unlinkSync4(getMarkerPath());
6059
+ unlinkSync5(getMarkerPath());
5814
6060
  } catch {
5815
6061
  }
5816
6062
  }
@@ -5826,7 +6072,7 @@ function getActiveAgent() {
5826
6072
  const age = Date.now() - new Date(data.startedAt).getTime();
5827
6073
  if (age > STALE_MS) {
5828
6074
  try {
5829
- unlinkSync4(markerPath);
6075
+ unlinkSync5(markerPath);
5830
6076
  } catch {
5831
6077
  }
5832
6078
  } else {
@@ -5874,7 +6120,7 @@ function getAllActiveAgents() {
5874
6120
  const age = Date.now() - new Date(data.startedAt).getTime();
5875
6121
  if (age > STALE_MS) {
5876
6122
  try {
5877
- unlinkSync4(path10.join(CACHE_DIR, file));
6123
+ unlinkSync5(path10.join(CACHE_DIR, file));
5878
6124
  } catch {
5879
6125
  }
5880
6126
  continue;
@@ -5897,11 +6143,11 @@ function getAllActiveAgents() {
5897
6143
  function cleanupSessionMarkers() {
5898
6144
  const key = getSessionKey();
5899
6145
  try {
5900
- unlinkSync4(path10.join(CACHE_DIR, `active-agent-${key}.json`));
6146
+ unlinkSync5(path10.join(CACHE_DIR, `active-agent-${key}.json`));
5901
6147
  } catch {
5902
6148
  }
5903
6149
  try {
5904
- unlinkSync4(path10.join(CACHE_DIR, "active-agent-undefined.json"));
6150
+ unlinkSync5(path10.join(CACHE_DIR, "active-agent-undefined.json"));
5905
6151
  } catch {
5906
6152
  }
5907
6153
  }
@@ -5922,7 +6168,7 @@ var init_active_agent = __esm({
5922
6168
  init_store();
5923
6169
  import os7 from "os";
5924
6170
  import path11 from "path";
5925
- import { existsSync as existsSync10, readFileSync as readFileSync7, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, readdirSync as readdirSync4 } from "fs";
6171
+ import { existsSync as existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, readdirSync as readdirSync4 } from "fs";
5926
6172
  import { spawnSync } from "child_process";
5927
6173
 
5928
6174
  // src/bin/fast-db-init.ts
@@ -5992,11 +6238,11 @@ async function fastDbInit() {
5992
6238
  import os6 from "os";
5993
6239
  import path8 from "path";
5994
6240
  import {
5995
- existsSync as existsSync8,
5996
- mkdirSync as mkdirSync3,
6241
+ existsSync as existsSync9,
6242
+ mkdirSync as mkdirSync4,
5997
6243
  readdirSync as readdirSync2,
5998
- statSync as statSync4,
5999
- unlinkSync as unlinkSync3,
6244
+ statSync as statSync5,
6245
+ unlinkSync as unlinkSync4,
6000
6246
  writeFileSync as writeFileSync3
6001
6247
  } from "fs";
6002
6248
 
@@ -6057,7 +6303,7 @@ function getBehaviorLimit() {
6057
6303
  }
6058
6304
  }
6059
6305
  function sweepStaleBehaviorExports(now = Date.now()) {
6060
- if (!existsSync8(BEHAVIORS_EXPORT_DIR)) return;
6306
+ if (!existsSync9(BEHAVIORS_EXPORT_DIR)) return;
6061
6307
  let entries;
6062
6308
  try {
6063
6309
  entries = readdirSync2(BEHAVIORS_EXPORT_DIR);
@@ -6067,9 +6313,9 @@ function sweepStaleBehaviorExports(now = Date.now()) {
6067
6313
  for (const entry of entries) {
6068
6314
  const filePath = path8.join(BEHAVIORS_EXPORT_DIR, entry);
6069
6315
  try {
6070
- const stat = statSync4(filePath);
6316
+ const stat = statSync5(filePath);
6071
6317
  if (now - stat.mtimeMs > STALE_EXPORT_AGE_MS) {
6072
- unlinkSync3(filePath);
6318
+ unlinkSync4(filePath);
6073
6319
  }
6074
6320
  } catch {
6075
6321
  }
@@ -6107,7 +6353,7 @@ function exportFilePath(agentId, projectName, sessionKey) {
6107
6353
  );
6108
6354
  }
6109
6355
  async function exportBehaviorsForAgent(agentId, projectName, sessionKey) {
6110
- mkdirSync3(BEHAVIORS_EXPORT_DIR, { recursive: true });
6356
+ mkdirSync4(BEHAVIORS_EXPORT_DIR, { recursive: true });
6111
6357
  sweepStaleBehaviorExports();
6112
6358
  const behaviors = await listBehaviors(agentId, projectName, getBehaviorLimit());
6113
6359
  if (behaviors.length === 0) return null;
@@ -6343,7 +6589,7 @@ async function isKnownAgent(agent) {
6343
6589
  function identityPathFor(agent) {
6344
6590
  const dir = path11.join(os7.homedir(), ".exe-os", "identity");
6345
6591
  const exactPath = path11.join(dir, `${agent}.md`);
6346
- if (existsSync10(exactPath)) return exactPath;
6592
+ if (existsSync11(exactPath)) return exactPath;
6347
6593
  try {
6348
6594
  const files = readdirSync4(dir);
6349
6595
  const match = files.find((f) => f.toLowerCase() === `${agent.toLowerCase()}.md`);
@@ -6374,7 +6620,7 @@ function collectAllMcpServers() {
6374
6620
  ];
6375
6621
  for (const src of sources) {
6376
6622
  try {
6377
- if (!existsSync10(src)) continue;
6623
+ if (!existsSync11(src)) continue;
6378
6624
  const data = JSON.parse(readFileSync7(src, "utf-8"));
6379
6625
  const block = data.mcpServers;
6380
6626
  if (!block) continue;
@@ -6410,7 +6656,7 @@ function generateLeanMcpConfig(agent, role) {
6410
6656
  };
6411
6657
  }
6412
6658
  const configDir = path11.join(os7.homedir(), ".exe-os", "mcp-configs");
6413
- mkdirSync5(configDir, { recursive: true });
6659
+ mkdirSync6(configDir, { recursive: true });
6414
6660
  const configPath = path11.join(configDir, `${agent}-lean.json`);
6415
6661
  writeFileSync6(configPath, JSON.stringify({ mcpServers: leanServers }, null, 2), "utf-8");
6416
6662
  const saved = Object.keys(allServers).length - Object.keys(leanServers).length;
@@ -6432,7 +6678,7 @@ function generateLeanMcpConfig(agent, role) {
6432
6678
  function leanMcpConfigFor(agent) {
6433
6679
  if (!leanMcpEnabled()) return null;
6434
6680
  const p = path11.join(os7.homedir(), ".exe-os", "mcp-configs", `${agent}-lean.json`);
6435
- return existsSync10(p) ? p : null;
6681
+ return existsSync11(p) ? p : null;
6436
6682
  }
6437
6683
  var _ccHelpOutput = null;
6438
6684
  function getCcHelpOutput() {
@@ -6457,7 +6703,7 @@ function buildLaunchPlan(agent, behaviorsPath, passthrough, _hasAgentFlag, _prov
6457
6703
  const idPath = identityPathFor(agent);
6458
6704
  const ccAgentPath = path11.join(os7.homedir(), ".claude", "agents", `${agent}.md`);
6459
6705
  let effectiveCcPath = null;
6460
- if (existsSync10(ccAgentPath)) {
6706
+ if (existsSync11(ccAgentPath)) {
6461
6707
  effectiveCcPath = ccAgentPath;
6462
6708
  } else {
6463
6709
  try {
@@ -6468,9 +6714,9 @@ function buildLaunchPlan(agent, behaviorsPath, passthrough, _hasAgentFlag, _prov
6468
6714
  } catch {
6469
6715
  }
6470
6716
  }
6471
- const effectiveIdPath = existsSync10(idPath) ? idPath : effectiveCcPath;
6717
+ const effectiveIdPath = existsSync11(idPath) ? idPath : effectiveCcPath;
6472
6718
  let identityContent = null;
6473
- if (effectiveIdPath && existsSync10(effectiveIdPath)) {
6719
+ if (effectiveIdPath && existsSync11(effectiveIdPath)) {
6474
6720
  try {
6475
6721
  const content = readFileSync7(effectiveIdPath, "utf-8");
6476
6722
  if (content.trim().length > 0) identityContent = content;
@@ -6480,14 +6726,14 @@ function buildLaunchPlan(agent, behaviorsPath, passthrough, _hasAgentFlag, _prov
6480
6726
  if (!identityContent) {
6481
6727
  try {
6482
6728
  const rosterPath = path11.join(os7.homedir(), ".exe-os", "exe-employees.json");
6483
- if (existsSync10(rosterPath)) {
6729
+ if (existsSync11(rosterPath)) {
6484
6730
  const roster = JSON.parse(readFileSync7(rosterPath, "utf8"));
6485
6731
  const emp = roster.find((e) => e.name.toLowerCase() === agent.toLowerCase());
6486
6732
  if (emp?.systemPrompt && emp.systemPrompt.trim().length > 20) {
6487
6733
  identityContent = emp.systemPrompt;
6488
6734
  try {
6489
6735
  const dir = path11.dirname(idPath);
6490
- if (!existsSync10(dir)) mkdirSync5(dir, { recursive: true });
6736
+ if (!existsSync11(dir)) mkdirSync6(dir, { recursive: true });
6491
6737
  const hasFrontmatter = identityContent.trimStart().startsWith("---");
6492
6738
  const fileContent = hasFrontmatter ? identityContent : `---
6493
6739
  role: ${(emp.role ?? "employee").toLowerCase()}
@@ -6528,14 +6774,14 @@ ${identityContent}`;
6528
6774
  } else {
6529
6775
  try {
6530
6776
  const tmpPath = path11.join(os7.homedir(), ".exe-os", "session-cache", `${agent}-identity.md`);
6531
- mkdirSync5(path11.dirname(tmpPath), { recursive: true });
6777
+ mkdirSync6(path11.dirname(tmpPath), { recursive: true });
6532
6778
  writeFileSync6(tmpPath, identityContent, "utf-8");
6533
6779
  args.push("--append-system-prompt-file", tmpPath);
6534
6780
  } catch {
6535
6781
  }
6536
6782
  }
6537
6783
  }
6538
- if (behaviorsPath && existsSync10(behaviorsPath)) {
6784
+ if (behaviorsPath && existsSync11(behaviorsPath)) {
6539
6785
  args.push("--append-system-prompt-file", behaviorsPath);
6540
6786
  }
6541
6787
  const leanMcp = leanMcpConfigFor(agent);
@@ -6629,10 +6875,10 @@ async function main() {
6629
6875
  if (hasAgentFlag) {
6630
6876
  const ccAgentDir = path11.join(os7.homedir(), ".claude", "agents");
6631
6877
  const ccAgentFile = path11.join(ccAgentDir, `${agent}.md`);
6632
- if (!existsSync10(ccAgentFile)) {
6878
+ if (!existsSync11(ccAgentFile)) {
6633
6879
  const exeIdentity = identityPathFor(agent);
6634
6880
  let sourceFile = null;
6635
- if (existsSync10(exeIdentity)) {
6881
+ if (existsSync11(exeIdentity)) {
6636
6882
  sourceFile = exeIdentity;
6637
6883
  } else {
6638
6884
  try {
@@ -6645,7 +6891,7 @@ async function main() {
6645
6891
  }
6646
6892
  if (sourceFile) {
6647
6893
  try {
6648
- mkdirSync5(ccAgentDir, { recursive: true });
6894
+ mkdirSync6(ccAgentDir, { recursive: true });
6649
6895
  let content = readFileSync7(sourceFile, "utf-8");
6650
6896
  content = content.replace(/\$\{agent_id\}/g, baseAgentName(agent));
6651
6897
  writeFileSync6(ccAgentFile, content, "utf-8");