@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
@@ -1782,9 +1782,79 @@ __export(database_exports, {
1782
1782
  isInitialized: () => isInitialized,
1783
1783
  setExternalClient: () => setExternalClient
1784
1784
  });
1785
- import { chmodSync as chmodSync2 } from "fs";
1785
+ 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";
1786
1786
  import { createClient } from "@libsql/client";
1787
+ import { homedir } from "os";
1788
+ import { join } from "path";
1789
+ function logCatchDebug(context, err) {
1790
+ if (_debugDb) {
1791
+ process.stderr.write(
1792
+ `[database] ${context}: ${err instanceof Error ? err.message : String(err)}
1793
+ `
1794
+ );
1795
+ }
1796
+ }
1797
+ function acquireDbLock() {
1798
+ mkdirSync2(join(homedir(), ".exe-os"), { recursive: true });
1799
+ try {
1800
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
1801
+ } catch (err) {
1802
+ if (err && typeof err === "object" && "code" in err && err.code === "EEXIST") {
1803
+ try {
1804
+ const lockStat = statSync2(DB_LOCK_PATH);
1805
+ if (Date.now() - lockStat.mtimeMs > 6e4) {
1806
+ unlinkSync3(DB_LOCK_PATH);
1807
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
1808
+ return;
1809
+ }
1810
+ } catch (e) {
1811
+ logCatchDebug("stale lock check", e);
1812
+ }
1813
+ process.stderr.write(
1814
+ "[database] WARN: Another process holds db.lock \u2014 waiting briefly then proceeding.\n"
1815
+ );
1816
+ return;
1817
+ }
1818
+ throw err;
1819
+ }
1820
+ }
1821
+ function releaseDbLock() {
1822
+ if (_lockFd !== null) {
1823
+ try {
1824
+ closeSync2(_lockFd);
1825
+ } catch (e) {
1826
+ logCatchDebug("lock close", e);
1827
+ }
1828
+ _lockFd = null;
1829
+ }
1830
+ try {
1831
+ unlinkSync3(DB_LOCK_PATH);
1832
+ } catch (e) {
1833
+ logCatchDebug("lock unlink", e);
1834
+ }
1835
+ }
1787
1836
  async function initDatabase(config) {
1837
+ acquireDbLock();
1838
+ if (existsSync6(config.dbPath)) {
1839
+ const dbStat = statSync2(config.dbPath);
1840
+ if (dbStat.size === 0) {
1841
+ const walPath = config.dbPath + "-wal";
1842
+ if (existsSync6(walPath) && statSync2(walPath).size > 0) {
1843
+ const backupPath = config.dbPath + ".zeroed-" + Date.now();
1844
+ copyFileSync(config.dbPath, backupPath);
1845
+ unlinkSync3(config.dbPath);
1846
+ process.stderr.write(
1847
+ `[database] CRITICAL: DB was 0 bytes. Moved to ${backupPath}, attempting WAL recovery.
1848
+ `
1849
+ );
1850
+ } else {
1851
+ process.stderr.write(
1852
+ `[database] CRITICAL: DB is 0 bytes and no WAL available for recovery. Data may be lost. Check backups at ${config.dbPath}.bak
1853
+ `
1854
+ );
1855
+ }
1856
+ }
1857
+ }
1788
1858
  if (_walCheckpointTimer) {
1789
1859
  clearInterval(_walCheckpointTimer);
1790
1860
  _walCheckpointTimer = null;
@@ -1811,10 +1881,8 @@ async function initDatabase(config) {
1811
1881
  _client = createClient(opts);
1812
1882
  _resilientClient = wrapWithRetry(_client);
1813
1883
  _adapterClient = _resilientClient;
1814
- _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
1815
- });
1816
- _client.execute("PRAGMA journal_mode = WAL").catch(() => {
1817
- });
1884
+ await _client.execute("PRAGMA busy_timeout = 30000");
1885
+ await _client.execute("PRAGMA journal_mode = WAL");
1818
1886
  if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
1819
1887
  _walCheckpointTimer = setInterval(() => {
1820
1888
  _client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
@@ -1829,11 +1897,16 @@ async function initDatabase(config) {
1829
1897
  for (const suffix of ["-wal", "-shm"]) {
1830
1898
  try {
1831
1899
  chmodSync2(config.dbPath + suffix, 384);
1832
- } catch {
1900
+ } catch (chmodErr) {
1901
+ process.stderr.write(`[database] chmod ${suffix} failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
1902
+ `);
1833
1903
  }
1834
1904
  }
1835
- } catch {
1905
+ } catch (chmodErr) {
1906
+ process.stderr.write(`[database] chmod db failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
1907
+ `);
1836
1908
  }
1909
+ releaseDbLock();
1837
1910
  }
1838
1911
  function isInitialized() {
1839
1912
  return _adapterClient !== null || _client !== null;
@@ -1888,7 +1961,8 @@ async function ensureSchema() {
1888
1961
  await client.execute("PRAGMA wal_autocheckpoint = 1000");
1889
1962
  try {
1890
1963
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
1891
- } catch {
1964
+ } catch (e) {
1965
+ logCatchDebug("migration", e);
1892
1966
  }
1893
1967
  await client.executeMultiple(`
1894
1968
  CREATE TABLE IF NOT EXISTS memories (
@@ -1953,6 +2027,23 @@ async function ensureSchema() {
1953
2027
  INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
1954
2028
  END;
1955
2029
  `);
2030
+ try {
2031
+ await client.execute("SELECT COUNT(*) FROM memories_fts LIMIT 1");
2032
+ } catch (ftsErr) {
2033
+ process.stderr.write(
2034
+ `[database] WARN: memories_fts corrupted (${ftsErr instanceof Error ? ftsErr.message : String(ftsErr)}) \u2014 rebuilding FTS index.
2035
+ `
2036
+ );
2037
+ try {
2038
+ await client.execute("INSERT INTO memories_fts(memories_fts) VALUES('rebuild')");
2039
+ process.stderr.write("[database] FTS index rebuilt successfully.\n");
2040
+ } catch (rebuildErr) {
2041
+ process.stderr.write(
2042
+ `[database] ERROR: FTS rebuild failed: ${rebuildErr instanceof Error ? rebuildErr.message : String(rebuildErr)}
2043
+ `
2044
+ );
2045
+ }
2046
+ }
1956
2047
  await client.executeMultiple(`
1957
2048
  CREATE TABLE IF NOT EXISTS sync_meta (
1958
2049
  key TEXT PRIMARY KEY,
@@ -2011,35 +2102,40 @@ async function ensureSchema() {
2011
2102
  });
2012
2103
  }
2013
2104
  }
2014
- } catch {
2105
+ } catch (seedErr) {
2106
+ logCatchDebug("behavior seed", seedErr);
2015
2107
  }
2016
2108
  try {
2017
2109
  await client.execute({
2018
2110
  sql: `ALTER TABLE behaviors ADD COLUMN priority TEXT DEFAULT 'p1'`,
2019
2111
  args: []
2020
2112
  });
2021
- } catch {
2113
+ } catch (e) {
2114
+ logCatchDebug("migration", e);
2022
2115
  }
2023
2116
  try {
2024
2117
  await client.execute({
2025
2118
  sql: `ALTER TABLE behaviors ADD COLUMN vector F32_BLOB(${EMBEDDING_DIM})`,
2026
2119
  args: []
2027
2120
  });
2028
- } catch {
2121
+ } catch (e) {
2122
+ logCatchDebug("migration", e);
2029
2123
  }
2030
2124
  try {
2031
2125
  await client.execute({
2032
2126
  sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
2033
2127
  args: []
2034
2128
  });
2035
- } catch {
2129
+ } catch (e) {
2130
+ logCatchDebug("migration", e);
2036
2131
  }
2037
2132
  try {
2038
2133
  await client.execute({
2039
2134
  sql: `ALTER TABLE tasks ADD COLUMN parent_task_id TEXT`,
2040
2135
  args: []
2041
2136
  });
2042
- } catch {
2137
+ } catch (e) {
2138
+ logCatchDebug("migration", e);
2043
2139
  }
2044
2140
  try {
2045
2141
  await client.execute({
@@ -2048,98 +2144,112 @@ async function ensureSchema() {
2048
2144
  WHERE parent_task_id IS NOT NULL`,
2049
2145
  args: []
2050
2146
  });
2051
- } catch {
2147
+ } catch (e) {
2148
+ logCatchDebug("migration", e);
2052
2149
  }
2053
2150
  try {
2054
2151
  await client.execute({
2055
2152
  sql: `UPDATE tasks SET status = 'done' WHERE status = 'completed'`,
2056
2153
  args: []
2057
2154
  });
2058
- } catch {
2155
+ } catch (e) {
2156
+ logCatchDebug("migration", e);
2059
2157
  }
2060
2158
  try {
2061
2159
  await client.execute({
2062
2160
  sql: `ALTER TABLE tasks ADD COLUMN reviewer TEXT`,
2063
2161
  args: []
2064
2162
  });
2065
- } catch {
2163
+ } catch (e) {
2164
+ logCatchDebug("migration", e);
2066
2165
  }
2067
2166
  try {
2068
2167
  await client.execute({
2069
2168
  sql: `ALTER TABLE tasks ADD COLUMN context TEXT`,
2070
2169
  args: []
2071
2170
  });
2072
- } catch {
2171
+ } catch (e) {
2172
+ logCatchDebug("migration", e);
2073
2173
  }
2074
2174
  try {
2075
2175
  await client.execute({
2076
2176
  sql: `ALTER TABLE tasks ADD COLUMN result TEXT`,
2077
2177
  args: []
2078
2178
  });
2079
- } catch {
2179
+ } catch (e) {
2180
+ logCatchDebug("migration", e);
2080
2181
  }
2081
2182
  try {
2082
2183
  await client.execute({
2083
2184
  sql: `ALTER TABLE tasks ADD COLUMN assigned_tmux TEXT`,
2084
2185
  args: []
2085
2186
  });
2086
- } catch {
2187
+ } catch (e) {
2188
+ logCatchDebug("migration", e);
2087
2189
  }
2088
2190
  try {
2089
2191
  await client.execute({
2090
2192
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint TEXT`,
2091
2193
  args: []
2092
2194
  });
2093
- } catch {
2195
+ } catch (e) {
2196
+ logCatchDebug("migration", e);
2094
2197
  }
2095
2198
  try {
2096
2199
  await client.execute({
2097
2200
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER NOT NULL DEFAULT 0`,
2098
2201
  args: []
2099
2202
  });
2100
- } catch {
2203
+ } catch (e) {
2204
+ logCatchDebug("migration", e);
2101
2205
  }
2102
2206
  try {
2103
2207
  await client.execute({
2104
2208
  sql: `ALTER TABLE tasks ADD COLUMN complexity TEXT NOT NULL DEFAULT 'standard'`,
2105
2209
  args: []
2106
2210
  });
2107
- } catch {
2211
+ } catch (e) {
2212
+ logCatchDebug("migration", e);
2108
2213
  }
2109
2214
  try {
2110
2215
  await client.execute({
2111
2216
  sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
2112
2217
  args: []
2113
2218
  });
2114
- } catch {
2219
+ } catch (e) {
2220
+ logCatchDebug("migration", e);
2115
2221
  }
2116
2222
  try {
2117
2223
  await client.execute({
2118
2224
  sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
2119
2225
  args: []
2120
2226
  });
2121
- } catch {
2227
+ } catch (e) {
2228
+ logCatchDebug("migration", e);
2122
2229
  }
2123
2230
  try {
2124
2231
  await client.execute({
2125
2232
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
2126
2233
  args: []
2127
2234
  });
2128
- } catch {
2235
+ } catch (e) {
2236
+ logCatchDebug("migration", e);
2129
2237
  }
2130
2238
  try {
2131
2239
  await client.execute({
2132
2240
  sql: `ALTER TABLE memories ADD COLUMN author_device_id TEXT`,
2133
2241
  args: []
2134
2242
  });
2135
- } catch {
2243
+ } catch (e) {
2244
+ logCatchDebug("migration", e);
2136
2245
  }
2137
2246
  try {
2138
2247
  await client.execute({
2139
2248
  sql: `ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'`,
2140
2249
  args: []
2141
2250
  });
2142
- } catch {
2251
+ } catch (e) {
2252
+ logCatchDebug("migration", e);
2143
2253
  }
2144
2254
  await client.executeMultiple(`
2145
2255
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2244,14 +2354,16 @@ async function ensureSchema() {
2244
2354
  sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
2245
2355
  args: []
2246
2356
  });
2247
- } catch {
2357
+ } catch (e) {
2358
+ logCatchDebug("migration", e);
2248
2359
  }
2249
2360
  try {
2250
2361
  await client.execute({
2251
2362
  sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
2252
2363
  args: []
2253
2364
  });
2254
- } catch {
2365
+ } catch (e) {
2366
+ logCatchDebug("migration", e);
2255
2367
  }
2256
2368
  await client.executeMultiple(`
2257
2369
  CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
@@ -2277,7 +2389,8 @@ async function ensureSchema() {
2277
2389
  sql: `UPDATE tasks SET project_name = 'exe-os' WHERE project_name = 'worker'`,
2278
2390
  args: []
2279
2391
  });
2280
- } catch {
2392
+ } catch (e) {
2393
+ logCatchDebug("migration", e);
2281
2394
  }
2282
2395
  await client.executeMultiple(`
2283
2396
  CREATE TABLE IF NOT EXISTS trajectories (
@@ -2301,7 +2414,8 @@ async function ensureSchema() {
2301
2414
  `);
2302
2415
  try {
2303
2416
  await client.execute("ALTER TABLE trajectories ADD COLUMN skill_id TEXT");
2304
- } catch {
2417
+ } catch (e) {
2418
+ logCatchDebug("migration", e);
2305
2419
  }
2306
2420
  await client.executeMultiple(`
2307
2421
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2338,63 +2452,72 @@ async function ensureSchema() {
2338
2452
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
2339
2453
  args: []
2340
2454
  });
2341
- } catch {
2455
+ } catch (e) {
2456
+ logCatchDebug("migration", e);
2342
2457
  }
2343
2458
  try {
2344
2459
  await client.execute({
2345
2460
  sql: `ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5`,
2346
2461
  args: []
2347
2462
  });
2348
- } catch {
2463
+ } catch (e) {
2464
+ logCatchDebug("migration", e);
2349
2465
  }
2350
2466
  try {
2351
2467
  await client.execute({
2352
2468
  sql: `ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'`,
2353
2469
  args: []
2354
2470
  });
2355
- } catch {
2471
+ } catch (e) {
2472
+ logCatchDebug("migration", e);
2356
2473
  }
2357
2474
  try {
2358
2475
  await client.execute({
2359
2476
  sql: `ALTER TABLE memories ADD COLUMN deleted_at TEXT`,
2360
2477
  args: []
2361
2478
  });
2362
- } catch {
2479
+ } catch (e) {
2480
+ logCatchDebug("migration", e);
2363
2481
  }
2364
2482
  try {
2365
2483
  await client.execute({
2366
2484
  sql: `ALTER TABLE memories ADD COLUMN confidence REAL DEFAULT 0.7`,
2367
2485
  args: []
2368
2486
  });
2369
- } catch {
2487
+ } catch (e) {
2488
+ logCatchDebug("migration", e);
2370
2489
  }
2371
2490
  try {
2372
2491
  await client.execute({
2373
2492
  sql: `ALTER TABLE memories ADD COLUMN last_accessed TEXT`,
2374
2493
  args: []
2375
2494
  });
2376
- } catch {
2495
+ } catch (e) {
2496
+ logCatchDebug("migration", e);
2377
2497
  }
2378
2498
  try {
2379
2499
  await client.execute({
2380
2500
  sql: `UPDATE memories SET last_accessed = timestamp WHERE last_accessed IS NULL`,
2381
2501
  args: []
2382
2502
  });
2383
- } catch {
2503
+ } catch (e) {
2504
+ logCatchDebug("migration", e);
2384
2505
  }
2385
2506
  try {
2386
2507
  await client.execute({
2387
2508
  sql: `ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0`,
2388
2509
  args: []
2389
2510
  });
2390
- } catch {
2511
+ } catch (e) {
2512
+ logCatchDebug("migration", e);
2391
2513
  }
2392
2514
  try {
2393
2515
  await client.execute({
2394
2516
  sql: `ALTER TABLE memories ADD COLUMN graph_extracted INTEGER DEFAULT 0`,
2395
2517
  args: []
2396
2518
  });
2397
- } catch {
2519
+ } catch (e) {
2520
+ logCatchDebug("migration", e);
2398
2521
  }
2399
2522
  for (const col of [
2400
2523
  "ALTER TABLE memories ADD COLUMN content_hash TEXT",
@@ -2402,14 +2525,16 @@ async function ensureSchema() {
2402
2525
  ]) {
2403
2526
  try {
2404
2527
  await client.execute(col);
2405
- } catch {
2528
+ } catch (e) {
2529
+ logCatchDebug("migration", e);
2406
2530
  }
2407
2531
  }
2408
2532
  try {
2409
2533
  await client.execute(
2410
2534
  `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
2411
2535
  );
2412
- } catch {
2536
+ } catch (e) {
2537
+ logCatchDebug("migration", e);
2413
2538
  }
2414
2539
  try {
2415
2540
  await client.execute(
@@ -2417,7 +2542,8 @@ async function ensureSchema() {
2417
2542
  ON memories(content_hash, agent_id, project_name, memory_type)
2418
2543
  WHERE content_hash IS NOT NULL`
2419
2544
  );
2420
- } catch {
2545
+ } catch (e) {
2546
+ logCatchDebug("migration", e);
2421
2547
  }
2422
2548
  await client.executeMultiple(`
2423
2549
  CREATE TABLE IF NOT EXISTS entities (
@@ -2493,7 +2619,8 @@ async function ensureSchema() {
2493
2619
  `);
2494
2620
  try {
2495
2621
  await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
2496
- } catch {
2622
+ } catch (e) {
2623
+ logCatchDebug("migration", e);
2497
2624
  }
2498
2625
  await client.executeMultiple(`
2499
2626
  CREATE TABLE IF NOT EXISTS entity_aliases (
@@ -2508,14 +2635,16 @@ async function ensureSchema() {
2508
2635
  ]) {
2509
2636
  try {
2510
2637
  await client.execute(col);
2511
- } catch {
2638
+ } catch (e) {
2639
+ logCatchDebug("migration", e);
2512
2640
  }
2513
2641
  }
2514
2642
  try {
2515
2643
  await client.execute(
2516
2644
  `CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)`
2517
2645
  );
2518
- } catch {
2646
+ } catch (e) {
2647
+ logCatchDebug("migration", e);
2519
2648
  }
2520
2649
  await client.executeMultiple(`
2521
2650
  CREATE TABLE IF NOT EXISTS identity (
@@ -2614,7 +2743,8 @@ async function ensureSchema() {
2614
2743
  sql: `ALTER TABLE memories ADD COLUMN ${column}`,
2615
2744
  args: []
2616
2745
  });
2617
- } catch {
2746
+ } catch (e) {
2747
+ logCatchDebug("migration", e);
2618
2748
  }
2619
2749
  }
2620
2750
  for (const col of [
@@ -2623,7 +2753,8 @@ async function ensureSchema() {
2623
2753
  ]) {
2624
2754
  try {
2625
2755
  await client.execute(col);
2626
- } catch {
2756
+ } catch (e) {
2757
+ logCatchDebug("migration", e);
2627
2758
  }
2628
2759
  }
2629
2760
  await client.executeMultiple(`
@@ -2808,56 +2939,64 @@ async function ensureSchema() {
2808
2939
  args: []
2809
2940
  });
2810
2941
  }
2811
- } catch {
2942
+ } catch (e) {
2943
+ logCatchDebug("session_agent_map backfill", e);
2812
2944
  }
2813
2945
  try {
2814
2946
  await client.execute({
2815
2947
  sql: `ALTER TABLE session_agent_map ADD COLUMN cache_cold_count INTEGER NOT NULL DEFAULT 0`,
2816
2948
  args: []
2817
2949
  });
2818
- } catch {
2950
+ } catch (e) {
2951
+ logCatchDebug("migration", e);
2819
2952
  }
2820
2953
  try {
2821
2954
  await client.execute({
2822
2955
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
2823
2956
  args: []
2824
2957
  });
2825
- } catch {
2958
+ } catch (e) {
2959
+ logCatchDebug("migration", e);
2826
2960
  }
2827
2961
  try {
2828
2962
  await client.execute({
2829
2963
  sql: `ALTER TABLE tasks ADD COLUMN budget_fallback_model TEXT`,
2830
2964
  args: []
2831
2965
  });
2832
- } catch {
2966
+ } catch (e) {
2967
+ logCatchDebug("migration", e);
2833
2968
  }
2834
2969
  try {
2835
2970
  await client.execute({
2836
2971
  sql: `ALTER TABLE tasks ADD COLUMN tokens_used INTEGER DEFAULT 0`,
2837
2972
  args: []
2838
2973
  });
2839
- } catch {
2974
+ } catch (e) {
2975
+ logCatchDebug("migration", e);
2840
2976
  }
2841
2977
  try {
2842
2978
  await client.execute({
2843
2979
  sql: `ALTER TABLE tasks ADD COLUMN tokens_warned_at INTEGER`,
2844
2980
  args: []
2845
2981
  });
2846
- } catch {
2982
+ } catch (e) {
2983
+ logCatchDebug("migration", e);
2847
2984
  }
2848
2985
  try {
2849
2986
  await client.execute({
2850
2987
  sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
2851
2988
  args: []
2852
2989
  });
2853
- } catch {
2990
+ } catch (e) {
2991
+ logCatchDebug("migration", e);
2854
2992
  }
2855
2993
  try {
2856
2994
  await client.execute({
2857
2995
  sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
2858
2996
  args: []
2859
2997
  });
2860
- } catch {
2998
+ } catch (e) {
2999
+ logCatchDebug("migration", e);
2861
3000
  }
2862
3001
  await client.executeMultiple(`
2863
3002
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
@@ -3056,13 +3195,15 @@ async function ensureSchema() {
3056
3195
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
3057
3196
  args: []
3058
3197
  });
3059
- } catch {
3198
+ } catch (e) {
3199
+ logCatchDebug("migration", e);
3060
3200
  }
3061
3201
  try {
3062
3202
  await client.execute(
3063
3203
  `CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
3064
3204
  );
3065
- } catch {
3205
+ } catch (e) {
3206
+ logCatchDebug("migration", e);
3066
3207
  }
3067
3208
  try {
3068
3209
  await client.execute({
@@ -3073,20 +3214,23 @@ async function ensureSchema() {
3073
3214
  sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
3074
3215
  args: []
3075
3216
  });
3076
- } catch {
3217
+ } catch (e) {
3218
+ logCatchDebug("migration", e);
3077
3219
  }
3078
3220
  try {
3079
3221
  await client.execute({
3080
3222
  sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
3081
3223
  args: []
3082
3224
  });
3083
- } catch {
3225
+ } catch (e) {
3226
+ logCatchDebug("migration", e);
3084
3227
  }
3085
3228
  try {
3086
3229
  await client.execute(
3087
3230
  `CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
3088
3231
  );
3089
- } catch {
3232
+ } catch (e) {
3233
+ logCatchDebug("migration", e);
3090
3234
  }
3091
3235
  for (const col of [
3092
3236
  "ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
@@ -3094,7 +3238,8 @@ async function ensureSchema() {
3094
3238
  ]) {
3095
3239
  try {
3096
3240
  await client.execute(col);
3097
- } catch {
3241
+ } catch (e) {
3242
+ logCatchDebug("migration", e);
3098
3243
  }
3099
3244
  }
3100
3245
  try {
@@ -3102,13 +3247,15 @@ async function ensureSchema() {
3102
3247
  sql: `ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0`,
3103
3248
  args: []
3104
3249
  });
3105
- } catch {
3250
+ } catch (e) {
3251
+ logCatchDebug("migration", e);
3106
3252
  }
3107
3253
  try {
3108
3254
  await client.execute(
3109
3255
  `CREATE INDEX IF NOT EXISTS idx_memories_draft ON memories(draft) WHERE draft = 1`
3110
3256
  );
3111
- } catch {
3257
+ } catch (e) {
3258
+ logCatchDebug("migration", e);
3112
3259
  }
3113
3260
  for (const col of [
3114
3261
  "ALTER TABLE memories ADD COLUMN valid_from TEXT",
@@ -3116,7 +3263,8 @@ async function ensureSchema() {
3116
3263
  ]) {
3117
3264
  try {
3118
3265
  await client.execute(col);
3119
- } catch {
3266
+ } catch (e) {
3267
+ logCatchDebug("migration", e);
3120
3268
  }
3121
3269
  }
3122
3270
  try {
@@ -3124,27 +3272,31 @@ async function ensureSchema() {
3124
3272
  sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
3125
3273
  args: []
3126
3274
  });
3127
- } catch {
3275
+ } catch (e) {
3276
+ logCatchDebug("migration", e);
3128
3277
  }
3129
3278
  try {
3130
3279
  await client.execute({
3131
3280
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
3132
3281
  args: []
3133
3282
  });
3134
- } catch {
3283
+ } catch (e) {
3284
+ logCatchDebug("migration", e);
3135
3285
  }
3136
3286
  try {
3137
3287
  await client.execute(
3138
3288
  `CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(memory_type)`
3139
3289
  );
3140
- } catch {
3290
+ } catch (e) {
3291
+ logCatchDebug("migration", e);
3141
3292
  }
3142
3293
  try {
3143
3294
  await client.execute({
3144
3295
  sql: `ALTER TABLE memories ADD COLUMN trajectory TEXT`,
3145
3296
  args: []
3146
3297
  });
3147
- } catch {
3298
+ } catch (e) {
3299
+ logCatchDebug("migration", e);
3148
3300
  }
3149
3301
  for (const col of [
3150
3302
  "ALTER TABLE memories ADD COLUMN intent TEXT",
@@ -3165,7 +3317,8 @@ async function ensureSchema() {
3165
3317
  ]) {
3166
3318
  try {
3167
3319
  await client.execute(col);
3168
- } catch {
3320
+ } catch (e) {
3321
+ logCatchDebug("migration", e);
3169
3322
  }
3170
3323
  }
3171
3324
  try {
@@ -3173,14 +3326,16 @@ async function ensureSchema() {
3173
3326
  sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
3174
3327
  args: []
3175
3328
  });
3176
- } catch {
3329
+ } catch (e) {
3330
+ logCatchDebug("migration", e);
3177
3331
  }
3178
3332
  try {
3179
3333
  await client.execute({
3180
3334
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
3181
3335
  args: []
3182
3336
  });
3183
- } catch {
3337
+ } catch (e) {
3338
+ logCatchDebug("migration", e);
3184
3339
  }
3185
3340
  }
3186
3341
  async function disposeDatabase() {
@@ -3191,7 +3346,8 @@ async function disposeDatabase() {
3191
3346
  if (_client) {
3192
3347
  try {
3193
3348
  await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3194
- } catch {
3349
+ } catch (e) {
3350
+ logCatchDebug("WAL checkpoint", e);
3195
3351
  }
3196
3352
  }
3197
3353
  if (_daemonClient) {
@@ -3207,8 +3363,9 @@ async function disposeDatabase() {
3207
3363
  _client = null;
3208
3364
  _resilientClient = null;
3209
3365
  }
3366
+ releaseDbLock();
3210
3367
  }
3211
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
3368
+ var _debugDb, _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, _lockFd, DB_LOCK_PATH, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
3212
3369
  var init_database = __esm({
3213
3370
  "src/lib/database.ts"() {
3214
3371
  "use strict";
@@ -3216,11 +3373,14 @@ var init_database = __esm({
3216
3373
  init_employees();
3217
3374
  init_database_adapter();
3218
3375
  init_memory();
3376
+ _debugDb = process.env.EXE_DEBUG === "1";
3219
3377
  _client = null;
3220
3378
  _resilientClient = null;
3221
3379
  _walCheckpointTimer = null;
3222
3380
  _daemonClient = null;
3223
3381
  _adapterClient = null;
3382
+ _lockFd = null;
3383
+ DB_LOCK_PATH = join(homedir(), ".exe-os", "db.lock");
3224
3384
  initTurso = initDatabase;
3225
3385
  SOFT_DELETE_RETENTION_DAYS = 7;
3226
3386
  disposeTurso = disposeDatabase;
@@ -3229,7 +3389,7 @@ var init_database = __esm({
3229
3389
 
3230
3390
  // src/lib/keychain.ts
3231
3391
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3232
- import { existsSync as existsSync6, statSync as statSync2 } from "fs";
3392
+ import { existsSync as existsSync7, statSync as statSync3 } from "fs";
3233
3393
  import { execSync as execSync3 } from "child_process";
3234
3394
  import path6 from "path";
3235
3395
  import os5 from "os";
@@ -3264,7 +3424,7 @@ function isRootOnlyTrustedServerKeyFile(keyPath) {
3264
3424
  if (process.platform !== "linux") return false;
3265
3425
  try {
3266
3426
  const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
3267
- const st = statSync2(keyPath);
3427
+ const st = statSync3(keyPath);
3268
3428
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
3269
3429
  if (uid === 0) return true;
3270
3430
  const exeOsDir = process.env.EXE_OS_DIR;
@@ -3465,7 +3625,7 @@ async function getMasterKey() {
3465
3625
  }
3466
3626
  }
3467
3627
  const keyPath = getKeyPath();
3468
- if (!existsSync6(keyPath)) {
3628
+ if (!existsSync7(keyPath)) {
3469
3629
  process.stderr.write(
3470
3630
  `[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
3471
3631
  `
@@ -3800,18 +3960,54 @@ __export(shard_manager_exports, {
3800
3960
  shardExists: () => shardExists
3801
3961
  });
3802
3962
  import path7 from "path";
3803
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync3 } from "fs";
3963
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3, readdirSync, renameSync as renameSync3, statSync as statSync4 } from "fs";
3804
3964
  import { createClient as createClient2 } from "@libsql/client";
3805
3965
  function initShardManager(encryptionKey) {
3806
3966
  _encryptionKey = encryptionKey;
3807
- if (!existsSync7(SHARDS_DIR)) {
3808
- mkdirSync2(SHARDS_DIR, { recursive: true });
3967
+ _keyValidated = false;
3968
+ _keyValidationPromise = null;
3969
+ if (!existsSync8(SHARDS_DIR)) {
3970
+ mkdirSync3(SHARDS_DIR, { recursive: true });
3971
+ }
3972
+ const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
3973
+ if (existingShards.length === 0) {
3974
+ _keyValidated = true;
3809
3975
  }
3810
3976
  _shardingEnabled = true;
3811
3977
  if (_evictionTimer) clearInterval(_evictionTimer);
3812
3978
  _evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
3813
3979
  _evictionTimer.unref();
3814
3980
  }
3981
+ async function validateEncryptionKey() {
3982
+ if (_keyValidated) return true;
3983
+ if (!_encryptionKey) return false;
3984
+ const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
3985
+ if (existingShards.length === 0) {
3986
+ _keyValidated = true;
3987
+ return true;
3988
+ }
3989
+ for (const shardFile of existingShards.slice(0, 3)) {
3990
+ const dbPath = path7.join(SHARDS_DIR, shardFile);
3991
+ const testClient = createClient2({ url: `file:${dbPath}`, encryptionKey: _encryptionKey });
3992
+ try {
3993
+ await testClient.execute("SELECT COUNT(*) FROM sqlite_schema");
3994
+ testClient.close();
3995
+ _keyValidated = true;
3996
+ return true;
3997
+ } catch {
3998
+ try {
3999
+ testClient.close();
4000
+ } catch {
4001
+ }
4002
+ }
4003
+ }
4004
+ process.stderr.write(
4005
+ `[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.
4006
+ `
4007
+ );
4008
+ _shardingEnabled = false;
4009
+ return false;
4010
+ }
3815
4011
  function isShardingEnabled() {
3816
4012
  return _shardingEnabled;
3817
4013
  }
@@ -3845,13 +4041,13 @@ function getShardClient(projectName) {
3845
4041
  }
3846
4042
  function shardExists(projectName) {
3847
4043
  const safeName = safeShardName(projectName);
3848
- return existsSync7(path7.join(SHARDS_DIR, `${safeName}.db`));
4044
+ return existsSync8(path7.join(SHARDS_DIR, `${safeName}.db`));
3849
4045
  }
3850
4046
  function safeShardName(projectName) {
3851
4047
  return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3852
4048
  }
3853
4049
  function listShards() {
3854
- if (!existsSync7(SHARDS_DIR)) return [];
4050
+ if (!existsSync8(SHARDS_DIR)) return [];
3855
4051
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
3856
4052
  }
3857
4053
  async function auditShardHealth(options = {}) {
@@ -3864,7 +4060,7 @@ async function auditShardHealth(options = {}) {
3864
4060
  const shards = [];
3865
4061
  for (const name of names) {
3866
4062
  const dbPath = path7.join(SHARDS_DIR, `${name}.db`);
3867
- const stat = statSync3(dbPath);
4063
+ const stat = statSync4(dbPath);
3868
4064
  const item = {
3869
4065
  name,
3870
4066
  path: dbPath,
@@ -4104,6 +4300,17 @@ async function ensureShardSchema(client) {
4104
4300
  }
4105
4301
  }
4106
4302
  async function getReadyShardClient(projectName) {
4303
+ if (!_keyValidated) {
4304
+ if (!_keyValidationPromise) {
4305
+ _keyValidationPromise = validateEncryptionKey();
4306
+ }
4307
+ const valid = await _keyValidationPromise;
4308
+ if (!valid) {
4309
+ throw new Error(
4310
+ `Shard creation blocked: encryption key mismatch with existing shards. Run /exe-doctor to audit.`
4311
+ );
4312
+ }
4313
+ }
4107
4314
  const safeName = safeShardName(projectName);
4108
4315
  let client = getShardClient(projectName);
4109
4316
  try {
@@ -4116,8 +4323,8 @@ async function getReadyShardClient(projectName) {
4116
4323
  _shards.delete(safeName);
4117
4324
  _shardLastAccess.delete(safeName);
4118
4325
  const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
4119
- if (existsSync7(dbPath)) {
4120
- const stat = statSync3(dbPath);
4326
+ if (existsSync8(dbPath)) {
4327
+ const stat = statSync4(dbPath);
4121
4328
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4122
4329
  const archivedPath = path7.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
4123
4330
  renameSync3(dbPath, archivedPath);
@@ -4182,7 +4389,7 @@ function disposeShards() {
4182
4389
  _shardingEnabled = false;
4183
4390
  _encryptionKey = null;
4184
4391
  }
4185
- var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
4392
+ var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled, _keyValidated, _keyValidationPromise;
4186
4393
  var init_shard_manager = __esm({
4187
4394
  "src/lib/shard-manager.ts"() {
4188
4395
  "use strict";
@@ -4196,6 +4403,8 @@ var init_shard_manager = __esm({
4196
4403
  _evictionTimer = null;
4197
4404
  _encryptionKey = null;
4198
4405
  _shardingEnabled = false;
4406
+ _keyValidated = false;
4407
+ _keyValidationPromise = null;
4199
4408
  }
4200
4409
  });
4201
4410
 
@@ -4391,6 +4600,18 @@ var init_platform_procedures = __esm({
4391
4600
  priority: "p0",
4392
4601
  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.'"
4393
4602
  },
4603
+ {
4604
+ title: "Review chain \u2014 managers must actively pull completed work, never wait for nudges",
4605
+ domain: "workflow",
4606
+ priority: "p0",
4607
+ 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."
4608
+ },
4609
+ {
4610
+ title: "Bug fix lifecycle \u2014 triage upstream after every verified fix so customers see the status",
4611
+ domain: "workflow",
4612
+ priority: "p0",
4613
+ 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."
4614
+ },
4394
4615
  {
4395
4616
  title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
4396
4617
  domain: "architecture",
@@ -4988,6 +5209,20 @@ __export(store_exports, {
4988
5209
  vectorToBlob: () => vectorToBlob,
4989
5210
  writeMemory: () => writeMemory
4990
5211
  });
5212
+ function logStoreDebug(context, err) {
5213
+ if (_debugStore) {
5214
+ process.stderr.write(
5215
+ `[store] ${context}: ${err instanceof Error ? err.message : String(err)}
5216
+ `
5217
+ );
5218
+ }
5219
+ }
5220
+ function logStoreWarn(context, err) {
5221
+ process.stderr.write(
5222
+ `[store] WARN ${context}: ${err instanceof Error ? err.message : String(err)}
5223
+ `
5224
+ );
5225
+ }
4991
5226
  function isBusyError2(err) {
4992
5227
  if (err instanceof Error) {
4993
5228
  const msg = err.message.toLowerCase();
@@ -5042,13 +5277,15 @@ async function initStore(options) {
5042
5277
  try {
5043
5278
  const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
5044
5279
  await initDaemonClient2();
5045
- } catch {
5280
+ } catch (e) {
5281
+ logStoreWarn("catch", e);
5046
5282
  }
5047
5283
  if (!options?.lightweight) {
5048
5284
  try {
5049
5285
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
5050
5286
  initShardManager2(hexKey);
5051
- } catch {
5287
+ } catch (e) {
5288
+ logStoreWarn("catch", e);
5052
5289
  }
5053
5290
  const client = getClient();
5054
5291
  const vResult = await retryOnBusy2(
@@ -5059,7 +5296,8 @@ async function initStore(options) {
5059
5296
  try {
5060
5297
  const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
5061
5298
  await loadGlobalProcedures2();
5062
- } catch {
5299
+ } catch (e) {
5300
+ logStoreWarn("catch", e);
5063
5301
  }
5064
5302
  }
5065
5303
  }
@@ -5119,7 +5357,8 @@ async function writeMemory(record) {
5119
5357
  memoryType
5120
5358
  });
5121
5359
  if (existing) return;
5122
- } catch {
5360
+ } catch (e) {
5361
+ logStoreWarn("catch", e);
5123
5362
  }
5124
5363
  const dbRow = {
5125
5364
  id: record.id,
@@ -5320,12 +5559,14 @@ async function flushBatch() {
5320
5559
  try {
5321
5560
  const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
5322
5561
  await insertMemoryCardsForBatch2(batch);
5323
- } catch {
5562
+ } catch (e) {
5563
+ logStoreWarn("catch", e);
5324
5564
  }
5325
5565
  try {
5326
5566
  const { insertOntologyForBatch: insertOntologyForBatch2 } = await Promise.resolve().then(() => (init_agentic_ontology(), agentic_ontology_exports));
5327
5567
  await insertOntologyForBatch2(batch);
5328
- } catch {
5568
+ } catch (e) {
5569
+ logStoreWarn("catch", e);
5329
5570
  }
5330
5571
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
5331
5572
  _pendingRecords.splice(0, batch.length);
@@ -5364,7 +5605,8 @@ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
5364
5605
  }
5365
5606
  }
5366
5607
  }
5367
- } catch {
5608
+ } catch (e) {
5609
+ logStoreWarn("catch", e);
5368
5610
  }
5369
5611
  return batch.length;
5370
5612
  } finally {
@@ -5406,7 +5648,8 @@ async function searchMemories(queryVector, agentId, options) {
5406
5648
  } else {
5407
5649
  client = getClient();
5408
5650
  }
5409
- } catch {
5651
+ } catch (e) {
5652
+ logStoreDebug("shard routing fallback", e);
5410
5653
  client = getClient();
5411
5654
  }
5412
5655
  const limit = options?.limit ?? 10;
@@ -5522,7 +5765,8 @@ async function attachDocumentMetadata(records) {
5522
5765
  if (!record.document_id) continue;
5523
5766
  record.document_metadata = byId.get(record.document_id) ?? null;
5524
5767
  }
5525
- } catch {
5768
+ } catch (e) {
5769
+ logStoreWarn("catch", e);
5526
5770
  }
5527
5771
  return records;
5528
5772
  }
@@ -5583,11 +5827,12 @@ async function getMemoryCardinality(agentId) {
5583
5827
  args: [agentId]
5584
5828
  });
5585
5829
  return Number(result.rows[0]?.cnt) || 0;
5586
- } catch {
5830
+ } catch (e) {
5831
+ logStoreWarn("getMemoryCardinality", e);
5587
5832
  return 0;
5588
5833
  }
5589
5834
  }
5590
- var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
5835
+ var _debugStore, INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
5591
5836
  var init_store = __esm({
5592
5837
  "src/lib/store.ts"() {
5593
5838
  "use strict";
@@ -5597,6 +5842,7 @@ var init_store = __esm({
5597
5842
  init_config();
5598
5843
  init_state_bus();
5599
5844
  init_memory_write_governor();
5845
+ _debugStore = process.env.EXE_DEBUG === "1";
5600
5846
  INIT_MAX_RETRIES = 3;
5601
5847
  INIT_RETRY_DELAY_MS = 1e3;
5602
5848
  _pendingRecords = [];
@@ -5681,13 +5927,13 @@ var init_fast_db_init = __esm({
5681
5927
  });
5682
5928
 
5683
5929
  // src/lib/session-registry.ts
5684
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync as existsSync8 } from "fs";
5930
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync9 } from "fs";
5685
5931
  import path8 from "path";
5686
5932
  import os6 from "os";
5687
5933
  function registerSession(entry) {
5688
5934
  const dir = path8.dirname(REGISTRY_PATH);
5689
- if (!existsSync8(dir)) {
5690
- mkdirSync3(dir, { recursive: true });
5935
+ if (!existsSync9(dir)) {
5936
+ mkdirSync4(dir, { recursive: true });
5691
5937
  }
5692
5938
  const sessions = listSessions();
5693
5939
  const idx = sessions.findIndex((s) => s.windowName === entry.windowName);
@@ -6012,10 +6258,10 @@ var init_runtime_table = __esm({
6012
6258
  });
6013
6259
 
6014
6260
  // src/lib/agent-config.ts
6015
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync9 } from "fs";
6261
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync10 } from "fs";
6016
6262
  import path9 from "path";
6017
6263
  function loadAgentConfig() {
6018
- if (!existsSync9(AGENT_CONFIG_PATH)) return {};
6264
+ if (!existsSync10(AGENT_CONFIG_PATH)) return {};
6019
6265
  try {
6020
6266
  return JSON.parse(readFileSync6(AGENT_CONFIG_PATH, "utf-8"));
6021
6267
  } catch {
@@ -6055,16 +6301,16 @@ __export(intercom_queue_exports, {
6055
6301
  queueIntercom: () => queueIntercom,
6056
6302
  readQueue: () => readQueue
6057
6303
  });
6058
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, renameSync as renameSync4, existsSync as existsSync10, mkdirSync as mkdirSync4 } from "fs";
6304
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, renameSync as renameSync4, existsSync as existsSync11, mkdirSync as mkdirSync5 } from "fs";
6059
6305
  import path10 from "path";
6060
6306
  import os7 from "os";
6061
6307
  function ensureDir() {
6062
6308
  const dir = path10.dirname(QUEUE_PATH);
6063
- if (!existsSync10(dir)) mkdirSync4(dir, { recursive: true });
6309
+ if (!existsSync11(dir)) mkdirSync5(dir, { recursive: true });
6064
6310
  }
6065
6311
  function readQueue() {
6066
6312
  try {
6067
- if (!existsSync10(QUEUE_PATH)) return [];
6313
+ if (!existsSync11(QUEUE_PATH)) return [];
6068
6314
  return JSON.parse(readFileSync7(QUEUE_PATH, "utf8"));
6069
6315
  } catch {
6070
6316
  return [];
@@ -6173,7 +6419,7 @@ var init_intercom_queue = __esm({
6173
6419
  });
6174
6420
 
6175
6421
  // src/lib/license.ts
6176
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync11, mkdirSync as mkdirSync5 } from "fs";
6422
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync12, mkdirSync as mkdirSync6 } from "fs";
6177
6423
  import { randomUUID as randomUUID3 } from "crypto";
6178
6424
  import { createRequire as createRequire2 } from "module";
6179
6425
  import { pathToFileURL as pathToFileURL2 } from "url";
@@ -6200,11 +6446,11 @@ var init_license = __esm({
6200
6446
  });
6201
6447
 
6202
6448
  // src/lib/plan-limits.ts
6203
- import { readFileSync as readFileSync9, existsSync as existsSync12 } from "fs";
6449
+ import { readFileSync as readFileSync9, existsSync as existsSync13 } from "fs";
6204
6450
  import path12 from "path";
6205
6451
  function getLicenseSync() {
6206
6452
  try {
6207
- if (!existsSync12(CACHE_PATH2)) return freeLicense();
6453
+ if (!existsSync13(CACHE_PATH2)) return freeLicense();
6208
6454
  const raw = JSON.parse(readFileSync9(CACHE_PATH2, "utf8"));
6209
6455
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
6210
6456
  const parts = raw.token.split(".");
@@ -6243,7 +6489,7 @@ function assertEmployeeLimitSync(rosterPath) {
6243
6489
  const filePath = rosterPath ?? EMPLOYEES_PATH;
6244
6490
  let count = 0;
6245
6491
  try {
6246
- if (existsSync12(filePath)) {
6492
+ if (existsSync13(filePath)) {
6247
6493
  const raw = readFileSync9(filePath, "utf8");
6248
6494
  const employees = JSON.parse(raw);
6249
6495
  count = Array.isArray(employees) ? employees.length : 0;
@@ -6281,9 +6527,9 @@ var init_plan_limits = __esm({
6281
6527
  import os9 from "os";
6282
6528
  import path13 from "path";
6283
6529
  import {
6284
- existsSync as existsSync13,
6530
+ existsSync as existsSync14,
6285
6531
  lstatSync,
6286
- mkdirSync as mkdirSync6,
6532
+ mkdirSync as mkdirSync7,
6287
6533
  readlinkSync as readlinkSync2,
6288
6534
  symlinkSync as symlinkSync2
6289
6535
  } from "fs";
@@ -6299,8 +6545,8 @@ function claudeAgentLinkPath(homeDir, agentId) {
6299
6545
  function ensureAgentSymlink(agentId, homeDir = os9.homedir()) {
6300
6546
  const target = identitySourcePath(homeDir, agentId);
6301
6547
  const link = claudeAgentLinkPath(homeDir, agentId);
6302
- mkdirSync6(claudeAgentsDir(homeDir), { recursive: true });
6303
- if (existsSync13(link)) {
6548
+ mkdirSync7(claudeAgentsDir(homeDir), { recursive: true });
6549
+ if (existsSync14(link)) {
6304
6550
  let stat;
6305
6551
  try {
6306
6552
  stat = lstatSync(link);
@@ -6494,7 +6740,7 @@ import path15 from "path";
6494
6740
  import os10 from "os";
6495
6741
  import { execSync as execSync7 } from "child_process";
6496
6742
  import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
6497
- import { existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
6743
+ import { existsSync as existsSync15, readFileSync as readFileSync10 } from "fs";
6498
6744
  async function writeCheckpoint(input) {
6499
6745
  const client = getClient();
6500
6746
  const row = await resolveTask(client, input.taskId);
@@ -6735,7 +6981,7 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
6735
6981
  const EXE_OS_DIR = path15.join(os10.homedir(), ".exe-os");
6736
6982
  const mdPath = path15.join(EXE_OS_DIR, taskFile);
6737
6983
  const mdDir = path15.dirname(mdPath);
6738
- if (!existsSync14(mdDir)) await mkdir4(mdDir, { recursive: true });
6984
+ if (!existsSync15(mdDir)) await mkdir4(mdDir, { recursive: true });
6739
6985
  const reviewer = input.reviewer ?? input.assignedBy;
6740
6986
  const mdContent = `# ${input.title}
6741
6987
 
@@ -7041,7 +7287,7 @@ async function deleteTaskCore(taskId, _baseDir) {
7041
7287
  async function ensureArchitectureDoc(baseDir, projectName) {
7042
7288
  const archPath = path15.join(baseDir, "exe", "ARCHITECTURE.md");
7043
7289
  try {
7044
- if (existsSync14(archPath)) return;
7290
+ if (existsSync15(archPath)) return;
7045
7291
  const template = [
7046
7292
  `# ${projectName} \u2014 System Architecture`,
7047
7293
  "",
@@ -7076,7 +7322,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
7076
7322
  async function ensureGitignoreExe(baseDir) {
7077
7323
  const gitignorePath = path15.join(baseDir, ".gitignore");
7078
7324
  try {
7079
- if (existsSync14(gitignorePath)) {
7325
+ if (existsSync15(gitignorePath)) {
7080
7326
  const content = readFileSync10(gitignorePath, "utf-8");
7081
7327
  if (/^\/?exe\/?$/m.test(content)) return;
7082
7328
  await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
@@ -7309,10 +7555,10 @@ async function disposeEmbedder() {
7309
7555
  async function embedDirect(text) {
7310
7556
  const llamaCpp = await import("node-llama-cpp");
7311
7557
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
7312
- const { existsSync: existsSync19 } = await import("fs");
7558
+ const { existsSync: existsSync20 } = await import("fs");
7313
7559
  const path22 = await import("path");
7314
7560
  const modelPath = path22.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
7315
- if (!existsSync19(modelPath)) {
7561
+ if (!existsSync20(modelPath)) {
7316
7562
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
7317
7563
  }
7318
7564
  const llama = await llamaCpp.getLlama();
@@ -7679,7 +7925,7 @@ __export(tasks_exports, {
7679
7925
  writeCheckpoint: () => writeCheckpoint
7680
7926
  });
7681
7927
  import path17 from "path";
7682
- import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, unlinkSync as unlinkSync3 } from "fs";
7928
+ import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync8, unlinkSync as unlinkSync4 } from "fs";
7683
7929
  async function createTask(input) {
7684
7930
  const result = await createTaskCore(input);
7685
7931
  if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
@@ -7701,11 +7947,11 @@ async function updateTask(input) {
7701
7947
  const cacheDir = path17.join(EXE_AI_DIR, "session-cache");
7702
7948
  const cachePath = path17.join(cacheDir, `current-task-${agent}.json`);
7703
7949
  if (input.status === "in_progress") {
7704
- mkdirSync7(cacheDir, { recursive: true });
7950
+ mkdirSync8(cacheDir, { recursive: true });
7705
7951
  writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
7706
7952
  } else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled" || input.status === "closed") {
7707
7953
  try {
7708
- unlinkSync3(cachePath);
7954
+ unlinkSync4(cachePath);
7709
7955
  } catch {
7710
7956
  }
7711
7957
  }
@@ -8173,11 +8419,11 @@ __export(tmux_routing_exports, {
8173
8419
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
8174
8420
  });
8175
8421
  import { execFileSync as execFileSync2, execSync as execSync8 } from "child_process";
8176
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, existsSync as existsSync15, appendFileSync, readdirSync as readdirSync2 } from "fs";
8422
+ import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync9, existsSync as existsSync16, appendFileSync, readdirSync as readdirSync2 } from "fs";
8177
8423
  import path18 from "path";
8178
8424
  import os11 from "os";
8179
8425
  import { fileURLToPath as fileURLToPath2 } from "url";
8180
- import { unlinkSync as unlinkSync4 } from "fs";
8426
+ import { unlinkSync as unlinkSync5 } from "fs";
8181
8427
  function spawnLockPath(sessionName) {
8182
8428
  return path18.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
8183
8429
  }
@@ -8190,11 +8436,11 @@ function isProcessAlive(pid) {
8190
8436
  }
8191
8437
  }
8192
8438
  function acquireSpawnLock2(sessionName) {
8193
- if (!existsSync15(SPAWN_LOCK_DIR)) {
8194
- mkdirSync8(SPAWN_LOCK_DIR, { recursive: true });
8439
+ if (!existsSync16(SPAWN_LOCK_DIR)) {
8440
+ mkdirSync9(SPAWN_LOCK_DIR, { recursive: true });
8195
8441
  }
8196
8442
  const lockFile = spawnLockPath(sessionName);
8197
- if (existsSync15(lockFile)) {
8443
+ if (existsSync16(lockFile)) {
8198
8444
  try {
8199
8445
  const lock = JSON.parse(readFileSync11(lockFile, "utf8"));
8200
8446
  const age = Date.now() - lock.timestamp;
@@ -8209,7 +8455,7 @@ function acquireSpawnLock2(sessionName) {
8209
8455
  }
8210
8456
  function releaseSpawnLock2(sessionName) {
8211
8457
  try {
8212
- unlinkSync4(spawnLockPath(sessionName));
8458
+ unlinkSync5(spawnLockPath(sessionName));
8213
8459
  } catch {
8214
8460
  }
8215
8461
  }
@@ -8222,7 +8468,7 @@ function resolveBehaviorsExporterScript() {
8222
8468
  "bin",
8223
8469
  "exe-export-behaviors.js"
8224
8470
  );
8225
- return existsSync15(scriptPath) ? scriptPath : null;
8471
+ return existsSync16(scriptPath) ? scriptPath : null;
8226
8472
  } catch {
8227
8473
  return null;
8228
8474
  }
@@ -8288,8 +8534,8 @@ function extractRootExe(name) {
8288
8534
  return parts.length > 0 ? parts[parts.length - 1] : null;
8289
8535
  }
8290
8536
  function registerParentExe(sessionKey, parentExe, dispatchedBy) {
8291
- if (!existsSync15(SESSION_CACHE)) {
8292
- mkdirSync8(SESSION_CACHE, { recursive: true });
8537
+ if (!existsSync16(SESSION_CACHE)) {
8538
+ mkdirSync9(SESSION_CACHE, { recursive: true });
8293
8539
  }
8294
8540
  const rootExe = extractRootExe(parentExe) ?? parentExe;
8295
8541
  const filePath = path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
@@ -8319,11 +8565,13 @@ function getDispatchedBy(sessionKey) {
8319
8565
  }
8320
8566
  }
8321
8567
  function resolveExeSession() {
8322
- if (process.env.EXE_SESSION_NAME) {
8323
- return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
8324
- }
8325
8568
  const mySession = getMySession();
8326
- if (!mySession) return null;
8569
+ if (!mySession) {
8570
+ if (process.env.EXE_SESSION_NAME) {
8571
+ return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
8572
+ }
8573
+ return null;
8574
+ }
8327
8575
  const fromSessionName = extractRootExe(mySession);
8328
8576
  let candidate = null;
8329
8577
  try {
@@ -8418,7 +8666,7 @@ async function verifyPaneAtCapacity(sessionName) {
8418
8666
  }
8419
8667
  function readDebounceState() {
8420
8668
  try {
8421
- if (!existsSync15(DEBOUNCE_FILE)) return {};
8669
+ if (!existsSync16(DEBOUNCE_FILE)) return {};
8422
8670
  const raw = JSON.parse(readFileSync11(DEBOUNCE_FILE, "utf8"));
8423
8671
  const state = {};
8424
8672
  for (const [key, val] of Object.entries(raw)) {
@@ -8435,7 +8683,7 @@ function readDebounceState() {
8435
8683
  }
8436
8684
  function writeDebounceState(state) {
8437
8685
  try {
8438
- if (!existsSync15(SESSION_CACHE)) mkdirSync8(SESSION_CACHE, { recursive: true });
8686
+ if (!existsSync16(SESSION_CACHE)) mkdirSync9(SESSION_CACHE, { recursive: true });
8439
8687
  writeFileSync8(DEBOUNCE_FILE, JSON.stringify(state));
8440
8688
  } catch {
8441
8689
  }
@@ -8536,7 +8784,7 @@ function sendIntercom(targetSession) {
8536
8784
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
8537
8785
  const agent = baseAgentName(rawAgent);
8538
8786
  const markerPath = path18.join(SESSION_CACHE, `current-task-${agent}.json`);
8539
- if (existsSync15(markerPath)) {
8787
+ if (existsSync16(markerPath)) {
8540
8788
  logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker + not idle \u2014 will auto-chain)`);
8541
8789
  return "debounced";
8542
8790
  }
@@ -8547,7 +8795,7 @@ function sendIntercom(targetSession) {
8547
8795
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
8548
8796
  const agent = baseAgentName(rawAgent);
8549
8797
  const taskDir = path18.join(process.cwd(), "exe", agent);
8550
- if (existsSync15(taskDir)) {
8798
+ if (existsSync16(taskDir)) {
8551
8799
  const files = readdirSync2(taskDir).filter(
8552
8800
  (f) => f.endsWith(".md") && f !== "DONE.txt"
8553
8801
  );
@@ -8708,15 +8956,15 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
8708
8956
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
8709
8957
  const logDir = path18.join(os11.homedir(), ".exe-os", "session-logs");
8710
8958
  const logFile = path18.join(logDir, `${instanceLabel}-${Date.now()}.log`);
8711
- if (!existsSync15(logDir)) {
8712
- mkdirSync8(logDir, { recursive: true });
8959
+ if (!existsSync16(logDir)) {
8960
+ mkdirSync9(logDir, { recursive: true });
8713
8961
  }
8714
8962
  transport.kill(sessionName);
8715
8963
  let cleanupSuffix = "";
8716
8964
  try {
8717
8965
  const thisFile = fileURLToPath2(import.meta.url);
8718
8966
  const cleanupScript = path18.join(path18.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
8719
- if (existsSync15(cleanupScript)) {
8967
+ if (existsSync16(cleanupScript)) {
8720
8968
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
8721
8969
  }
8722
8970
  } catch {
@@ -8771,7 +9019,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
8771
9019
  if (changed) {
8772
9020
  perms.allow = allow;
8773
9021
  settings.permissions = perms;
8774
- mkdirSync8(projSettingsDir, { recursive: true });
9022
+ mkdirSync9(projSettingsDir, { recursive: true });
8775
9023
  writeFileSync8(settingsPath, JSON.stringify(settings, null, 2) + "\n");
8776
9024
  }
8777
9025
  } catch {
@@ -8809,7 +9057,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
8809
9057
  `
8810
9058
  );
8811
9059
  }
8812
- } else if (existsSync15(identityPath)) {
9060
+ } else if (existsSync16(identityPath)) {
8813
9061
  identityFlag = ` --append-system-prompt-file ${identityPath}`;
8814
9062
  legacyFallbackWarned = true;
8815
9063
  }
@@ -8831,7 +9079,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
8831
9079
  let sessionContextFlag = "";
8832
9080
  try {
8833
9081
  const ctxDir = path18.join(os11.homedir(), ".exe-os", "session-cache");
8834
- mkdirSync8(ctxDir, { recursive: true });
9082
+ mkdirSync9(ctxDir, { recursive: true });
8835
9083
  const ctxFile = path18.join(ctxDir, `session-context-${sessionName}.md`);
8836
9084
  const ctxContent = [
8837
9085
  `## Session Context`,
@@ -9063,8 +9311,8 @@ import os12 from "os";
9063
9311
  import {
9064
9312
  readFileSync as readFileSync12,
9065
9313
  readdirSync as readdirSync3,
9066
- unlinkSync as unlinkSync5,
9067
- existsSync as existsSync16,
9314
+ unlinkSync as unlinkSync6,
9315
+ existsSync as existsSync17,
9068
9316
  rmdirSync
9069
9317
  } from "fs";
9070
9318
  async function writeNotification(notification) {
@@ -9212,7 +9460,7 @@ function formatNotifications(notifications) {
9212
9460
  async function migrateJsonNotifications() {
9213
9461
  const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR || path19.join(os12.homedir(), ".exe-os");
9214
9462
  const notifDir = path19.join(base, "notifications");
9215
- if (!existsSync16(notifDir)) return 0;
9463
+ if (!existsSync17(notifDir)) return 0;
9216
9464
  let migrated = 0;
9217
9465
  try {
9218
9466
  const files = readdirSync3(notifDir).filter((f) => f.endsWith(".json"));
@@ -9238,7 +9486,7 @@ async function migrateJsonNotifications() {
9238
9486
  data.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
9239
9487
  ]
9240
9488
  });
9241
- unlinkSync5(filePath);
9489
+ unlinkSync6(filePath);
9242
9490
  migrated++;
9243
9491
  } catch {
9244
9492
  }
@@ -9306,7 +9554,7 @@ __export(tasks_review_exports, {
9306
9554
  listPendingReviews: () => listPendingReviews
9307
9555
  });
9308
9556
  import path20 from "path";
9309
- import { existsSync as existsSync17, readdirSync as readdirSync4, unlinkSync as unlinkSync6 } from "fs";
9557
+ import { existsSync as existsSync18, readdirSync as readdirSync4, unlinkSync as unlinkSync7 } from "fs";
9310
9558
  function formatAge(isoTimestamp) {
9311
9559
  if (!isoTimestamp) return "";
9312
9560
  const ms = Date.now() - new Date(isoTimestamp).getTime();
@@ -9576,10 +9824,10 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
9576
9824
  }
9577
9825
  try {
9578
9826
  const cacheDir = path20.join(EXE_AI_DIR, "session-cache");
9579
- if (existsSync17(cacheDir)) {
9827
+ if (existsSync18(cacheDir)) {
9580
9828
  for (const f of readdirSync4(cacheDir)) {
9581
9829
  if (f.startsWith("review-notified-")) {
9582
- unlinkSync6(path20.join(cacheDir, f));
9830
+ unlinkSync7(path20.join(cacheDir, f));
9583
9831
  }
9584
9832
  }
9585
9833
  }
@@ -9627,7 +9875,7 @@ __export(scan_tasks_exports, {
9627
9875
  getMcpHealthWarning: () => getMcpHealthWarning,
9628
9876
  scanFromDb: () => scanFromDb
9629
9877
  });
9630
- import { existsSync as existsSync18, readFileSync as readFileSync13 } from "fs";
9878
+ import { existsSync as existsSync19, readFileSync as readFileSync13 } from "fs";
9631
9879
  import path21 from "path";
9632
9880
  import os13 from "os";
9633
9881
  function getMcpHealthWarning(runtime = getSessionRuntime(), homeDir = os13.homedir()) {
@@ -9637,7 +9885,7 @@ function getMcpHealthWarning(runtime = getSessionRuntime(), homeDir = os13.homed
9637
9885
  try {
9638
9886
  if (runtime === "opencode") {
9639
9887
  const opencodeJson = path21.join(homeDir, ".config", "opencode", "opencode.json");
9640
- if (!existsSync18(opencodeJson)) {
9888
+ if (!existsSync19(opencodeJson)) {
9641
9889
  return "\u26A0\uFE0F MCP config missing (~/.config/opencode/opencode.json not found) \u2014 exe-os task tools may be unavailable. Run `exe-os opencode`.\n";
9642
9890
  }
9643
9891
  const config2 = JSON.parse(readFileSync13(opencodeJson, "utf8"));
@@ -9647,7 +9895,7 @@ function getMcpHealthWarning(runtime = getSessionRuntime(), homeDir = os13.homed
9647
9895
  return null;
9648
9896
  }
9649
9897
  const claudeJson = path21.join(homeDir, ".claude.json");
9650
- if (!existsSync18(claudeJson)) {
9898
+ if (!existsSync19(claudeJson)) {
9651
9899
  return "\u26A0\uFE0F MCP config missing (~/.claude.json not found) \u2014 close_task won't work. Run /exe-setup\n";
9652
9900
  }
9653
9901
  const config = JSON.parse(readFileSync13(claudeJson, "utf8"));