@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
@@ -1545,9 +1545,79 @@ __export(database_exports, {
1545
1545
  isInitialized: () => isInitialized,
1546
1546
  setExternalClient: () => setExternalClient
1547
1547
  });
1548
- import { chmodSync as chmodSync2 } from "fs";
1548
+ 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";
1549
1549
  import { createClient } from "@libsql/client";
1550
+ import { homedir } from "os";
1551
+ import { join } from "path";
1552
+ function logCatchDebug(context, err) {
1553
+ if (_debugDb) {
1554
+ process.stderr.write(
1555
+ `[database] ${context}: ${err instanceof Error ? err.message : String(err)}
1556
+ `
1557
+ );
1558
+ }
1559
+ }
1560
+ function acquireDbLock() {
1561
+ mkdirSync2(join(homedir(), ".exe-os"), { recursive: true });
1562
+ try {
1563
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
1564
+ } catch (err) {
1565
+ if (err && typeof err === "object" && "code" in err && err.code === "EEXIST") {
1566
+ try {
1567
+ const lockStat = statSync2(DB_LOCK_PATH);
1568
+ if (Date.now() - lockStat.mtimeMs > 6e4) {
1569
+ unlinkSync3(DB_LOCK_PATH);
1570
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
1571
+ return;
1572
+ }
1573
+ } catch (e) {
1574
+ logCatchDebug("stale lock check", e);
1575
+ }
1576
+ process.stderr.write(
1577
+ "[database] WARN: Another process holds db.lock \u2014 waiting briefly then proceeding.\n"
1578
+ );
1579
+ return;
1580
+ }
1581
+ throw err;
1582
+ }
1583
+ }
1584
+ function releaseDbLock() {
1585
+ if (_lockFd !== null) {
1586
+ try {
1587
+ closeSync2(_lockFd);
1588
+ } catch (e) {
1589
+ logCatchDebug("lock close", e);
1590
+ }
1591
+ _lockFd = null;
1592
+ }
1593
+ try {
1594
+ unlinkSync3(DB_LOCK_PATH);
1595
+ } catch (e) {
1596
+ logCatchDebug("lock unlink", e);
1597
+ }
1598
+ }
1550
1599
  async function initDatabase(config) {
1600
+ acquireDbLock();
1601
+ if (existsSync6(config.dbPath)) {
1602
+ const dbStat = statSync2(config.dbPath);
1603
+ if (dbStat.size === 0) {
1604
+ const walPath = config.dbPath + "-wal";
1605
+ if (existsSync6(walPath) && statSync2(walPath).size > 0) {
1606
+ const backupPath = config.dbPath + ".zeroed-" + Date.now();
1607
+ copyFileSync(config.dbPath, backupPath);
1608
+ unlinkSync3(config.dbPath);
1609
+ process.stderr.write(
1610
+ `[database] CRITICAL: DB was 0 bytes. Moved to ${backupPath}, attempting WAL recovery.
1611
+ `
1612
+ );
1613
+ } else {
1614
+ process.stderr.write(
1615
+ `[database] CRITICAL: DB is 0 bytes and no WAL available for recovery. Data may be lost. Check backups at ${config.dbPath}.bak
1616
+ `
1617
+ );
1618
+ }
1619
+ }
1620
+ }
1551
1621
  if (_walCheckpointTimer) {
1552
1622
  clearInterval(_walCheckpointTimer);
1553
1623
  _walCheckpointTimer = null;
@@ -1574,10 +1644,8 @@ async function initDatabase(config) {
1574
1644
  _client = createClient(opts);
1575
1645
  _resilientClient = wrapWithRetry(_client);
1576
1646
  _adapterClient = _resilientClient;
1577
- _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
1578
- });
1579
- _client.execute("PRAGMA journal_mode = WAL").catch(() => {
1580
- });
1647
+ await _client.execute("PRAGMA busy_timeout = 30000");
1648
+ await _client.execute("PRAGMA journal_mode = WAL");
1581
1649
  if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
1582
1650
  _walCheckpointTimer = setInterval(() => {
1583
1651
  _client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
@@ -1592,11 +1660,16 @@ async function initDatabase(config) {
1592
1660
  for (const suffix of ["-wal", "-shm"]) {
1593
1661
  try {
1594
1662
  chmodSync2(config.dbPath + suffix, 384);
1595
- } catch {
1663
+ } catch (chmodErr) {
1664
+ process.stderr.write(`[database] chmod ${suffix} failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
1665
+ `);
1596
1666
  }
1597
1667
  }
1598
- } catch {
1668
+ } catch (chmodErr) {
1669
+ process.stderr.write(`[database] chmod db failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
1670
+ `);
1599
1671
  }
1672
+ releaseDbLock();
1600
1673
  }
1601
1674
  function isInitialized() {
1602
1675
  return _adapterClient !== null || _client !== null;
@@ -1651,7 +1724,8 @@ async function ensureSchema() {
1651
1724
  await client.execute("PRAGMA wal_autocheckpoint = 1000");
1652
1725
  try {
1653
1726
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
1654
- } catch {
1727
+ } catch (e) {
1728
+ logCatchDebug("migration", e);
1655
1729
  }
1656
1730
  await client.executeMultiple(`
1657
1731
  CREATE TABLE IF NOT EXISTS memories (
@@ -1716,6 +1790,23 @@ async function ensureSchema() {
1716
1790
  INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
1717
1791
  END;
1718
1792
  `);
1793
+ try {
1794
+ await client.execute("SELECT COUNT(*) FROM memories_fts LIMIT 1");
1795
+ } catch (ftsErr) {
1796
+ process.stderr.write(
1797
+ `[database] WARN: memories_fts corrupted (${ftsErr instanceof Error ? ftsErr.message : String(ftsErr)}) \u2014 rebuilding FTS index.
1798
+ `
1799
+ );
1800
+ try {
1801
+ await client.execute("INSERT INTO memories_fts(memories_fts) VALUES('rebuild')");
1802
+ process.stderr.write("[database] FTS index rebuilt successfully.\n");
1803
+ } catch (rebuildErr) {
1804
+ process.stderr.write(
1805
+ `[database] ERROR: FTS rebuild failed: ${rebuildErr instanceof Error ? rebuildErr.message : String(rebuildErr)}
1806
+ `
1807
+ );
1808
+ }
1809
+ }
1719
1810
  await client.executeMultiple(`
1720
1811
  CREATE TABLE IF NOT EXISTS sync_meta (
1721
1812
  key TEXT PRIMARY KEY,
@@ -1774,35 +1865,40 @@ async function ensureSchema() {
1774
1865
  });
1775
1866
  }
1776
1867
  }
1777
- } catch {
1868
+ } catch (seedErr) {
1869
+ logCatchDebug("behavior seed", seedErr);
1778
1870
  }
1779
1871
  try {
1780
1872
  await client.execute({
1781
1873
  sql: `ALTER TABLE behaviors ADD COLUMN priority TEXT DEFAULT 'p1'`,
1782
1874
  args: []
1783
1875
  });
1784
- } catch {
1876
+ } catch (e) {
1877
+ logCatchDebug("migration", e);
1785
1878
  }
1786
1879
  try {
1787
1880
  await client.execute({
1788
1881
  sql: `ALTER TABLE behaviors ADD COLUMN vector F32_BLOB(${EMBEDDING_DIM})`,
1789
1882
  args: []
1790
1883
  });
1791
- } catch {
1884
+ } catch (e) {
1885
+ logCatchDebug("migration", e);
1792
1886
  }
1793
1887
  try {
1794
1888
  await client.execute({
1795
1889
  sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
1796
1890
  args: []
1797
1891
  });
1798
- } catch {
1892
+ } catch (e) {
1893
+ logCatchDebug("migration", e);
1799
1894
  }
1800
1895
  try {
1801
1896
  await client.execute({
1802
1897
  sql: `ALTER TABLE tasks ADD COLUMN parent_task_id TEXT`,
1803
1898
  args: []
1804
1899
  });
1805
- } catch {
1900
+ } catch (e) {
1901
+ logCatchDebug("migration", e);
1806
1902
  }
1807
1903
  try {
1808
1904
  await client.execute({
@@ -1811,98 +1907,112 @@ async function ensureSchema() {
1811
1907
  WHERE parent_task_id IS NOT NULL`,
1812
1908
  args: []
1813
1909
  });
1814
- } catch {
1910
+ } catch (e) {
1911
+ logCatchDebug("migration", e);
1815
1912
  }
1816
1913
  try {
1817
1914
  await client.execute({
1818
1915
  sql: `UPDATE tasks SET status = 'done' WHERE status = 'completed'`,
1819
1916
  args: []
1820
1917
  });
1821
- } catch {
1918
+ } catch (e) {
1919
+ logCatchDebug("migration", e);
1822
1920
  }
1823
1921
  try {
1824
1922
  await client.execute({
1825
1923
  sql: `ALTER TABLE tasks ADD COLUMN reviewer TEXT`,
1826
1924
  args: []
1827
1925
  });
1828
- } catch {
1926
+ } catch (e) {
1927
+ logCatchDebug("migration", e);
1829
1928
  }
1830
1929
  try {
1831
1930
  await client.execute({
1832
1931
  sql: `ALTER TABLE tasks ADD COLUMN context TEXT`,
1833
1932
  args: []
1834
1933
  });
1835
- } catch {
1934
+ } catch (e) {
1935
+ logCatchDebug("migration", e);
1836
1936
  }
1837
1937
  try {
1838
1938
  await client.execute({
1839
1939
  sql: `ALTER TABLE tasks ADD COLUMN result TEXT`,
1840
1940
  args: []
1841
1941
  });
1842
- } catch {
1942
+ } catch (e) {
1943
+ logCatchDebug("migration", e);
1843
1944
  }
1844
1945
  try {
1845
1946
  await client.execute({
1846
1947
  sql: `ALTER TABLE tasks ADD COLUMN assigned_tmux TEXT`,
1847
1948
  args: []
1848
1949
  });
1849
- } catch {
1950
+ } catch (e) {
1951
+ logCatchDebug("migration", e);
1850
1952
  }
1851
1953
  try {
1852
1954
  await client.execute({
1853
1955
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint TEXT`,
1854
1956
  args: []
1855
1957
  });
1856
- } catch {
1958
+ } catch (e) {
1959
+ logCatchDebug("migration", e);
1857
1960
  }
1858
1961
  try {
1859
1962
  await client.execute({
1860
1963
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER NOT NULL DEFAULT 0`,
1861
1964
  args: []
1862
1965
  });
1863
- } catch {
1966
+ } catch (e) {
1967
+ logCatchDebug("migration", e);
1864
1968
  }
1865
1969
  try {
1866
1970
  await client.execute({
1867
1971
  sql: `ALTER TABLE tasks ADD COLUMN complexity TEXT NOT NULL DEFAULT 'standard'`,
1868
1972
  args: []
1869
1973
  });
1870
- } catch {
1974
+ } catch (e) {
1975
+ logCatchDebug("migration", e);
1871
1976
  }
1872
1977
  try {
1873
1978
  await client.execute({
1874
1979
  sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
1875
1980
  args: []
1876
1981
  });
1877
- } catch {
1982
+ } catch (e) {
1983
+ logCatchDebug("migration", e);
1878
1984
  }
1879
1985
  try {
1880
1986
  await client.execute({
1881
1987
  sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
1882
1988
  args: []
1883
1989
  });
1884
- } catch {
1990
+ } catch (e) {
1991
+ logCatchDebug("migration", e);
1885
1992
  }
1886
1993
  try {
1887
1994
  await client.execute({
1888
1995
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
1889
1996
  args: []
1890
1997
  });
1891
- } catch {
1998
+ } catch (e) {
1999
+ logCatchDebug("migration", e);
1892
2000
  }
1893
2001
  try {
1894
2002
  await client.execute({
1895
2003
  sql: `ALTER TABLE memories ADD COLUMN author_device_id TEXT`,
1896
2004
  args: []
1897
2005
  });
1898
- } catch {
2006
+ } catch (e) {
2007
+ logCatchDebug("migration", e);
1899
2008
  }
1900
2009
  try {
1901
2010
  await client.execute({
1902
2011
  sql: `ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'`,
1903
2012
  args: []
1904
2013
  });
1905
- } catch {
2014
+ } catch (e) {
2015
+ logCatchDebug("migration", e);
1906
2016
  }
1907
2017
  await client.executeMultiple(`
1908
2018
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2007,14 +2117,16 @@ async function ensureSchema() {
2007
2117
  sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
2008
2118
  args: []
2009
2119
  });
2010
- } catch {
2120
+ } catch (e) {
2121
+ logCatchDebug("migration", e);
2011
2122
  }
2012
2123
  try {
2013
2124
  await client.execute({
2014
2125
  sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
2015
2126
  args: []
2016
2127
  });
2017
- } catch {
2128
+ } catch (e) {
2129
+ logCatchDebug("migration", e);
2018
2130
  }
2019
2131
  await client.executeMultiple(`
2020
2132
  CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
@@ -2040,7 +2152,8 @@ async function ensureSchema() {
2040
2152
  sql: `UPDATE tasks SET project_name = 'exe-os' WHERE project_name = 'worker'`,
2041
2153
  args: []
2042
2154
  });
2043
- } catch {
2155
+ } catch (e) {
2156
+ logCatchDebug("migration", e);
2044
2157
  }
2045
2158
  await client.executeMultiple(`
2046
2159
  CREATE TABLE IF NOT EXISTS trajectories (
@@ -2064,7 +2177,8 @@ async function ensureSchema() {
2064
2177
  `);
2065
2178
  try {
2066
2179
  await client.execute("ALTER TABLE trajectories ADD COLUMN skill_id TEXT");
2067
- } catch {
2180
+ } catch (e) {
2181
+ logCatchDebug("migration", e);
2068
2182
  }
2069
2183
  await client.executeMultiple(`
2070
2184
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2101,63 +2215,72 @@ async function ensureSchema() {
2101
2215
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
2102
2216
  args: []
2103
2217
  });
2104
- } catch {
2218
+ } catch (e) {
2219
+ logCatchDebug("migration", e);
2105
2220
  }
2106
2221
  try {
2107
2222
  await client.execute({
2108
2223
  sql: `ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5`,
2109
2224
  args: []
2110
2225
  });
2111
- } catch {
2226
+ } catch (e) {
2227
+ logCatchDebug("migration", e);
2112
2228
  }
2113
2229
  try {
2114
2230
  await client.execute({
2115
2231
  sql: `ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'`,
2116
2232
  args: []
2117
2233
  });
2118
- } catch {
2234
+ } catch (e) {
2235
+ logCatchDebug("migration", e);
2119
2236
  }
2120
2237
  try {
2121
2238
  await client.execute({
2122
2239
  sql: `ALTER TABLE memories ADD COLUMN deleted_at TEXT`,
2123
2240
  args: []
2124
2241
  });
2125
- } catch {
2242
+ } catch (e) {
2243
+ logCatchDebug("migration", e);
2126
2244
  }
2127
2245
  try {
2128
2246
  await client.execute({
2129
2247
  sql: `ALTER TABLE memories ADD COLUMN confidence REAL DEFAULT 0.7`,
2130
2248
  args: []
2131
2249
  });
2132
- } catch {
2250
+ } catch (e) {
2251
+ logCatchDebug("migration", e);
2133
2252
  }
2134
2253
  try {
2135
2254
  await client.execute({
2136
2255
  sql: `ALTER TABLE memories ADD COLUMN last_accessed TEXT`,
2137
2256
  args: []
2138
2257
  });
2139
- } catch {
2258
+ } catch (e) {
2259
+ logCatchDebug("migration", e);
2140
2260
  }
2141
2261
  try {
2142
2262
  await client.execute({
2143
2263
  sql: `UPDATE memories SET last_accessed = timestamp WHERE last_accessed IS NULL`,
2144
2264
  args: []
2145
2265
  });
2146
- } catch {
2266
+ } catch (e) {
2267
+ logCatchDebug("migration", e);
2147
2268
  }
2148
2269
  try {
2149
2270
  await client.execute({
2150
2271
  sql: `ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0`,
2151
2272
  args: []
2152
2273
  });
2153
- } catch {
2274
+ } catch (e) {
2275
+ logCatchDebug("migration", e);
2154
2276
  }
2155
2277
  try {
2156
2278
  await client.execute({
2157
2279
  sql: `ALTER TABLE memories ADD COLUMN graph_extracted INTEGER DEFAULT 0`,
2158
2280
  args: []
2159
2281
  });
2160
- } catch {
2282
+ } catch (e) {
2283
+ logCatchDebug("migration", e);
2161
2284
  }
2162
2285
  for (const col of [
2163
2286
  "ALTER TABLE memories ADD COLUMN content_hash TEXT",
@@ -2165,14 +2288,16 @@ async function ensureSchema() {
2165
2288
  ]) {
2166
2289
  try {
2167
2290
  await client.execute(col);
2168
- } catch {
2291
+ } catch (e) {
2292
+ logCatchDebug("migration", e);
2169
2293
  }
2170
2294
  }
2171
2295
  try {
2172
2296
  await client.execute(
2173
2297
  `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
2174
2298
  );
2175
- } catch {
2299
+ } catch (e) {
2300
+ logCatchDebug("migration", e);
2176
2301
  }
2177
2302
  try {
2178
2303
  await client.execute(
@@ -2180,7 +2305,8 @@ async function ensureSchema() {
2180
2305
  ON memories(content_hash, agent_id, project_name, memory_type)
2181
2306
  WHERE content_hash IS NOT NULL`
2182
2307
  );
2183
- } catch {
2308
+ } catch (e) {
2309
+ logCatchDebug("migration", e);
2184
2310
  }
2185
2311
  await client.executeMultiple(`
2186
2312
  CREATE TABLE IF NOT EXISTS entities (
@@ -2256,7 +2382,8 @@ async function ensureSchema() {
2256
2382
  `);
2257
2383
  try {
2258
2384
  await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
2259
- } catch {
2385
+ } catch (e) {
2386
+ logCatchDebug("migration", e);
2260
2387
  }
2261
2388
  await client.executeMultiple(`
2262
2389
  CREATE TABLE IF NOT EXISTS entity_aliases (
@@ -2271,14 +2398,16 @@ async function ensureSchema() {
2271
2398
  ]) {
2272
2399
  try {
2273
2400
  await client.execute(col);
2274
- } catch {
2401
+ } catch (e) {
2402
+ logCatchDebug("migration", e);
2275
2403
  }
2276
2404
  }
2277
2405
  try {
2278
2406
  await client.execute(
2279
2407
  `CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)`
2280
2408
  );
2281
- } catch {
2409
+ } catch (e) {
2410
+ logCatchDebug("migration", e);
2282
2411
  }
2283
2412
  await client.executeMultiple(`
2284
2413
  CREATE TABLE IF NOT EXISTS identity (
@@ -2377,7 +2506,8 @@ async function ensureSchema() {
2377
2506
  sql: `ALTER TABLE memories ADD COLUMN ${column}`,
2378
2507
  args: []
2379
2508
  });
2380
- } catch {
2509
+ } catch (e) {
2510
+ logCatchDebug("migration", e);
2381
2511
  }
2382
2512
  }
2383
2513
  for (const col of [
@@ -2386,7 +2516,8 @@ async function ensureSchema() {
2386
2516
  ]) {
2387
2517
  try {
2388
2518
  await client.execute(col);
2389
- } catch {
2519
+ } catch (e) {
2520
+ logCatchDebug("migration", e);
2390
2521
  }
2391
2522
  }
2392
2523
  await client.executeMultiple(`
@@ -2571,56 +2702,64 @@ async function ensureSchema() {
2571
2702
  args: []
2572
2703
  });
2573
2704
  }
2574
- } catch {
2705
+ } catch (e) {
2706
+ logCatchDebug("session_agent_map backfill", e);
2575
2707
  }
2576
2708
  try {
2577
2709
  await client.execute({
2578
2710
  sql: `ALTER TABLE session_agent_map ADD COLUMN cache_cold_count INTEGER NOT NULL DEFAULT 0`,
2579
2711
  args: []
2580
2712
  });
2581
- } catch {
2713
+ } catch (e) {
2714
+ logCatchDebug("migration", e);
2582
2715
  }
2583
2716
  try {
2584
2717
  await client.execute({
2585
2718
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
2586
2719
  args: []
2587
2720
  });
2588
- } catch {
2721
+ } catch (e) {
2722
+ logCatchDebug("migration", e);
2589
2723
  }
2590
2724
  try {
2591
2725
  await client.execute({
2592
2726
  sql: `ALTER TABLE tasks ADD COLUMN budget_fallback_model TEXT`,
2593
2727
  args: []
2594
2728
  });
2595
- } catch {
2729
+ } catch (e) {
2730
+ logCatchDebug("migration", e);
2596
2731
  }
2597
2732
  try {
2598
2733
  await client.execute({
2599
2734
  sql: `ALTER TABLE tasks ADD COLUMN tokens_used INTEGER DEFAULT 0`,
2600
2735
  args: []
2601
2736
  });
2602
- } catch {
2737
+ } catch (e) {
2738
+ logCatchDebug("migration", e);
2603
2739
  }
2604
2740
  try {
2605
2741
  await client.execute({
2606
2742
  sql: `ALTER TABLE tasks ADD COLUMN tokens_warned_at INTEGER`,
2607
2743
  args: []
2608
2744
  });
2609
- } catch {
2745
+ } catch (e) {
2746
+ logCatchDebug("migration", e);
2610
2747
  }
2611
2748
  try {
2612
2749
  await client.execute({
2613
2750
  sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
2614
2751
  args: []
2615
2752
  });
2616
- } catch {
2753
+ } catch (e) {
2754
+ logCatchDebug("migration", e);
2617
2755
  }
2618
2756
  try {
2619
2757
  await client.execute({
2620
2758
  sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
2621
2759
  args: []
2622
2760
  });
2623
- } catch {
2761
+ } catch (e) {
2762
+ logCatchDebug("migration", e);
2624
2763
  }
2625
2764
  await client.executeMultiple(`
2626
2765
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
@@ -2819,13 +2958,15 @@ async function ensureSchema() {
2819
2958
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
2820
2959
  args: []
2821
2960
  });
2822
- } catch {
2961
+ } catch (e) {
2962
+ logCatchDebug("migration", e);
2823
2963
  }
2824
2964
  try {
2825
2965
  await client.execute(
2826
2966
  `CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
2827
2967
  );
2828
- } catch {
2968
+ } catch (e) {
2969
+ logCatchDebug("migration", e);
2829
2970
  }
2830
2971
  try {
2831
2972
  await client.execute({
@@ -2836,20 +2977,23 @@ async function ensureSchema() {
2836
2977
  sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
2837
2978
  args: []
2838
2979
  });
2839
- } catch {
2980
+ } catch (e) {
2981
+ logCatchDebug("migration", e);
2840
2982
  }
2841
2983
  try {
2842
2984
  await client.execute({
2843
2985
  sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
2844
2986
  args: []
2845
2987
  });
2846
- } catch {
2988
+ } catch (e) {
2989
+ logCatchDebug("migration", e);
2847
2990
  }
2848
2991
  try {
2849
2992
  await client.execute(
2850
2993
  `CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
2851
2994
  );
2852
- } catch {
2995
+ } catch (e) {
2996
+ logCatchDebug("migration", e);
2853
2997
  }
2854
2998
  for (const col of [
2855
2999
  "ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
@@ -2857,7 +3001,8 @@ async function ensureSchema() {
2857
3001
  ]) {
2858
3002
  try {
2859
3003
  await client.execute(col);
2860
- } catch {
3004
+ } catch (e) {
3005
+ logCatchDebug("migration", e);
2861
3006
  }
2862
3007
  }
2863
3008
  try {
@@ -2865,13 +3010,15 @@ async function ensureSchema() {
2865
3010
  sql: `ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0`,
2866
3011
  args: []
2867
3012
  });
2868
- } catch {
3013
+ } catch (e) {
3014
+ logCatchDebug("migration", e);
2869
3015
  }
2870
3016
  try {
2871
3017
  await client.execute(
2872
3018
  `CREATE INDEX IF NOT EXISTS idx_memories_draft ON memories(draft) WHERE draft = 1`
2873
3019
  );
2874
- } catch {
3020
+ } catch (e) {
3021
+ logCatchDebug("migration", e);
2875
3022
  }
2876
3023
  for (const col of [
2877
3024
  "ALTER TABLE memories ADD COLUMN valid_from TEXT",
@@ -2879,7 +3026,8 @@ async function ensureSchema() {
2879
3026
  ]) {
2880
3027
  try {
2881
3028
  await client.execute(col);
2882
- } catch {
3029
+ } catch (e) {
3030
+ logCatchDebug("migration", e);
2883
3031
  }
2884
3032
  }
2885
3033
  try {
@@ -2887,27 +3035,31 @@ async function ensureSchema() {
2887
3035
  sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
2888
3036
  args: []
2889
3037
  });
2890
- } catch {
3038
+ } catch (e) {
3039
+ logCatchDebug("migration", e);
2891
3040
  }
2892
3041
  try {
2893
3042
  await client.execute({
2894
3043
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
2895
3044
  args: []
2896
3045
  });
2897
- } catch {
3046
+ } catch (e) {
3047
+ logCatchDebug("migration", e);
2898
3048
  }
2899
3049
  try {
2900
3050
  await client.execute(
2901
3051
  `CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(memory_type)`
2902
3052
  );
2903
- } catch {
3053
+ } catch (e) {
3054
+ logCatchDebug("migration", e);
2904
3055
  }
2905
3056
  try {
2906
3057
  await client.execute({
2907
3058
  sql: `ALTER TABLE memories ADD COLUMN trajectory TEXT`,
2908
3059
  args: []
2909
3060
  });
2910
- } catch {
3061
+ } catch (e) {
3062
+ logCatchDebug("migration", e);
2911
3063
  }
2912
3064
  for (const col of [
2913
3065
  "ALTER TABLE memories ADD COLUMN intent TEXT",
@@ -2928,7 +3080,8 @@ async function ensureSchema() {
2928
3080
  ]) {
2929
3081
  try {
2930
3082
  await client.execute(col);
2931
- } catch {
3083
+ } catch (e) {
3084
+ logCatchDebug("migration", e);
2932
3085
  }
2933
3086
  }
2934
3087
  try {
@@ -2936,14 +3089,16 @@ async function ensureSchema() {
2936
3089
  sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
2937
3090
  args: []
2938
3091
  });
2939
- } catch {
3092
+ } catch (e) {
3093
+ logCatchDebug("migration", e);
2940
3094
  }
2941
3095
  try {
2942
3096
  await client.execute({
2943
3097
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
2944
3098
  args: []
2945
3099
  });
2946
- } catch {
3100
+ } catch (e) {
3101
+ logCatchDebug("migration", e);
2947
3102
  }
2948
3103
  }
2949
3104
  async function disposeDatabase() {
@@ -2954,7 +3109,8 @@ async function disposeDatabase() {
2954
3109
  if (_client) {
2955
3110
  try {
2956
3111
  await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
2957
- } catch {
3112
+ } catch (e) {
3113
+ logCatchDebug("WAL checkpoint", e);
2958
3114
  }
2959
3115
  }
2960
3116
  if (_daemonClient) {
@@ -2970,8 +3126,9 @@ async function disposeDatabase() {
2970
3126
  _client = null;
2971
3127
  _resilientClient = null;
2972
3128
  }
3129
+ releaseDbLock();
2973
3130
  }
2974
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
3131
+ var _debugDb, _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, _lockFd, DB_LOCK_PATH, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
2975
3132
  var init_database = __esm({
2976
3133
  "src/lib/database.ts"() {
2977
3134
  "use strict";
@@ -2979,11 +3136,14 @@ var init_database = __esm({
2979
3136
  init_employees();
2980
3137
  init_database_adapter();
2981
3138
  init_memory();
3139
+ _debugDb = process.env.EXE_DEBUG === "1";
2982
3140
  _client = null;
2983
3141
  _resilientClient = null;
2984
3142
  _walCheckpointTimer = null;
2985
3143
  _daemonClient = null;
2986
3144
  _adapterClient = null;
3145
+ _lockFd = null;
3146
+ DB_LOCK_PATH = join(homedir(), ".exe-os", "db.lock");
2987
3147
  initTurso = initDatabase;
2988
3148
  SOFT_DELETE_RETENTION_DAYS = 7;
2989
3149
  disposeTurso = disposeDatabase;
@@ -3006,18 +3166,54 @@ __export(shard_manager_exports, {
3006
3166
  shardExists: () => shardExists
3007
3167
  });
3008
3168
  import path7 from "path";
3009
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync3 } from "fs";
3169
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3, readdirSync, renameSync as renameSync3, statSync as statSync4 } from "fs";
3010
3170
  import { createClient as createClient2 } from "@libsql/client";
3011
3171
  function initShardManager(encryptionKey) {
3012
3172
  _encryptionKey = encryptionKey;
3013
- if (!existsSync7(SHARDS_DIR)) {
3014
- mkdirSync2(SHARDS_DIR, { recursive: true });
3173
+ _keyValidated = false;
3174
+ _keyValidationPromise = null;
3175
+ if (!existsSync8(SHARDS_DIR)) {
3176
+ mkdirSync3(SHARDS_DIR, { recursive: true });
3177
+ }
3178
+ const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
3179
+ if (existingShards.length === 0) {
3180
+ _keyValidated = true;
3015
3181
  }
3016
3182
  _shardingEnabled = true;
3017
3183
  if (_evictionTimer) clearInterval(_evictionTimer);
3018
3184
  _evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
3019
3185
  _evictionTimer.unref();
3020
3186
  }
3187
+ async function validateEncryptionKey() {
3188
+ if (_keyValidated) return true;
3189
+ if (!_encryptionKey) return false;
3190
+ const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
3191
+ if (existingShards.length === 0) {
3192
+ _keyValidated = true;
3193
+ return true;
3194
+ }
3195
+ for (const shardFile of existingShards.slice(0, 3)) {
3196
+ const dbPath = path7.join(SHARDS_DIR, shardFile);
3197
+ const testClient = createClient2({ url: `file:${dbPath}`, encryptionKey: _encryptionKey });
3198
+ try {
3199
+ await testClient.execute("SELECT COUNT(*) FROM sqlite_schema");
3200
+ testClient.close();
3201
+ _keyValidated = true;
3202
+ return true;
3203
+ } catch {
3204
+ try {
3205
+ testClient.close();
3206
+ } catch {
3207
+ }
3208
+ }
3209
+ }
3210
+ process.stderr.write(
3211
+ `[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.
3212
+ `
3213
+ );
3214
+ _shardingEnabled = false;
3215
+ return false;
3216
+ }
3021
3217
  function isShardingEnabled() {
3022
3218
  return _shardingEnabled;
3023
3219
  }
@@ -3051,13 +3247,13 @@ function getShardClient(projectName) {
3051
3247
  }
3052
3248
  function shardExists(projectName) {
3053
3249
  const safeName = safeShardName(projectName);
3054
- return existsSync7(path7.join(SHARDS_DIR, `${safeName}.db`));
3250
+ return existsSync8(path7.join(SHARDS_DIR, `${safeName}.db`));
3055
3251
  }
3056
3252
  function safeShardName(projectName) {
3057
3253
  return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3058
3254
  }
3059
3255
  function listShards() {
3060
- if (!existsSync7(SHARDS_DIR)) return [];
3256
+ if (!existsSync8(SHARDS_DIR)) return [];
3061
3257
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
3062
3258
  }
3063
3259
  async function auditShardHealth(options = {}) {
@@ -3070,7 +3266,7 @@ async function auditShardHealth(options = {}) {
3070
3266
  const shards = [];
3071
3267
  for (const name of names) {
3072
3268
  const dbPath = path7.join(SHARDS_DIR, `${name}.db`);
3073
- const stat = statSync3(dbPath);
3269
+ const stat = statSync4(dbPath);
3074
3270
  const item = {
3075
3271
  name,
3076
3272
  path: dbPath,
@@ -3310,6 +3506,17 @@ async function ensureShardSchema(client) {
3310
3506
  }
3311
3507
  }
3312
3508
  async function getReadyShardClient(projectName) {
3509
+ if (!_keyValidated) {
3510
+ if (!_keyValidationPromise) {
3511
+ _keyValidationPromise = validateEncryptionKey();
3512
+ }
3513
+ const valid = await _keyValidationPromise;
3514
+ if (!valid) {
3515
+ throw new Error(
3516
+ `Shard creation blocked: encryption key mismatch with existing shards. Run /exe-doctor to audit.`
3517
+ );
3518
+ }
3519
+ }
3313
3520
  const safeName = safeShardName(projectName);
3314
3521
  let client = getShardClient(projectName);
3315
3522
  try {
@@ -3322,8 +3529,8 @@ async function getReadyShardClient(projectName) {
3322
3529
  _shards.delete(safeName);
3323
3530
  _shardLastAccess.delete(safeName);
3324
3531
  const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
3325
- if (existsSync7(dbPath)) {
3326
- const stat = statSync3(dbPath);
3532
+ if (existsSync8(dbPath)) {
3533
+ const stat = statSync4(dbPath);
3327
3534
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3328
3535
  const archivedPath = path7.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
3329
3536
  renameSync3(dbPath, archivedPath);
@@ -3388,7 +3595,7 @@ function disposeShards() {
3388
3595
  _shardingEnabled = false;
3389
3596
  _encryptionKey = null;
3390
3597
  }
3391
- var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
3598
+ var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled, _keyValidated, _keyValidationPromise;
3392
3599
  var init_shard_manager = __esm({
3393
3600
  "src/lib/shard-manager.ts"() {
3394
3601
  "use strict";
@@ -3402,6 +3609,8 @@ var init_shard_manager = __esm({
3402
3609
  _evictionTimer = null;
3403
3610
  _encryptionKey = null;
3404
3611
  _shardingEnabled = false;
3612
+ _keyValidated = false;
3613
+ _keyValidationPromise = null;
3405
3614
  }
3406
3615
  });
3407
3616
 
@@ -3597,6 +3806,18 @@ var init_platform_procedures = __esm({
3597
3806
  priority: "p0",
3598
3807
  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.'"
3599
3808
  },
3809
+ {
3810
+ title: "Review chain \u2014 managers must actively pull completed work, never wait for nudges",
3811
+ domain: "workflow",
3812
+ priority: "p0",
3813
+ 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."
3814
+ },
3815
+ {
3816
+ title: "Bug fix lifecycle \u2014 triage upstream after every verified fix so customers see the status",
3817
+ domain: "workflow",
3818
+ priority: "p0",
3819
+ 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."
3820
+ },
3600
3821
  {
3601
3822
  title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
3602
3823
  domain: "architecture",
@@ -4293,7 +4514,7 @@ __export(active_agent_exports, {
4293
4514
  resolveActiveAgentFromTmuxSession: () => resolveActiveAgentFromTmuxSession,
4294
4515
  writeActiveAgent: () => writeActiveAgent
4295
4516
  });
4296
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, unlinkSync as unlinkSync4, readdirSync as readdirSync3 } from "fs";
4517
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, unlinkSync as unlinkSync5, readdirSync as readdirSync3 } from "fs";
4297
4518
  import { execSync as execSync5 } from "child_process";
4298
4519
  import path9 from "path";
4299
4520
  function isNameWithOptionalInstance(candidate, baseName) {
@@ -4343,7 +4564,7 @@ function getMarkerPath() {
4343
4564
  }
4344
4565
  function writeActiveAgent(agentId, agentRole) {
4345
4566
  try {
4346
- mkdirSync4(CACHE_DIR, { recursive: true });
4567
+ mkdirSync5(CACHE_DIR, { recursive: true });
4347
4568
  writeFileSync4(
4348
4569
  getMarkerPath(),
4349
4570
  JSON.stringify({ agentId, agentRole, startedAt: (/* @__PURE__ */ new Date()).toISOString() })
@@ -4353,7 +4574,7 @@ function writeActiveAgent(agentId, agentRole) {
4353
4574
  }
4354
4575
  function clearActiveAgent() {
4355
4576
  try {
4356
- unlinkSync4(getMarkerPath());
4577
+ unlinkSync5(getMarkerPath());
4357
4578
  } catch {
4358
4579
  }
4359
4580
  }
@@ -4369,7 +4590,7 @@ function getActiveAgent() {
4369
4590
  const age = Date.now() - new Date(data.startedAt).getTime();
4370
4591
  if (age > STALE_MS) {
4371
4592
  try {
4372
- unlinkSync4(markerPath);
4593
+ unlinkSync5(markerPath);
4373
4594
  } catch {
4374
4595
  }
4375
4596
  } else {
@@ -4417,7 +4638,7 @@ function getAllActiveAgents() {
4417
4638
  const age = Date.now() - new Date(data.startedAt).getTime();
4418
4639
  if (age > STALE_MS) {
4419
4640
  try {
4420
- unlinkSync4(path9.join(CACHE_DIR, file));
4641
+ unlinkSync5(path9.join(CACHE_DIR, file));
4421
4642
  } catch {
4422
4643
  }
4423
4644
  continue;
@@ -4440,11 +4661,11 @@ function getAllActiveAgents() {
4440
4661
  function cleanupSessionMarkers() {
4441
4662
  const key = getSessionKey();
4442
4663
  try {
4443
- unlinkSync4(path9.join(CACHE_DIR, `active-agent-${key}.json`));
4664
+ unlinkSync5(path9.join(CACHE_DIR, `active-agent-${key}.json`));
4444
4665
  } catch {
4445
4666
  }
4446
4667
  try {
4447
- unlinkSync4(path9.join(CACHE_DIR, "active-agent-undefined.json"));
4668
+ unlinkSync5(path9.join(CACHE_DIR, "active-agent-undefined.json"));
4448
4669
  } catch {
4449
4670
  }
4450
4671
  }
@@ -4465,9 +4686,9 @@ var init_active_agent = __esm({
4465
4686
  import os7 from "os";
4466
4687
  import path10 from "path";
4467
4688
  import {
4468
- existsSync as existsSync9,
4689
+ existsSync as existsSync10,
4469
4690
  lstatSync,
4470
- mkdirSync as mkdirSync5,
4691
+ mkdirSync as mkdirSync6,
4471
4692
  readlinkSync as readlinkSync2,
4472
4693
  symlinkSync as symlinkSync2
4473
4694
  } from "fs";
@@ -4493,7 +4714,7 @@ var init_mcp_prefix = __esm({
4493
4714
  });
4494
4715
 
4495
4716
  // src/lib/preferences.ts
4496
- import { existsSync as existsSync10, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
4717
+ import { existsSync as existsSync11, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
4497
4718
  import path11 from "path";
4498
4719
  import os8 from "os";
4499
4720
  var init_preferences = __esm({
@@ -4504,7 +4725,7 @@ var init_preferences = __esm({
4504
4725
  });
4505
4726
 
4506
4727
  // src/adapters/mcp-http-config.ts
4507
- import { chmodSync as chmodSync3, existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
4728
+ import { chmodSync as chmodSync3, existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
4508
4729
  import { randomBytes } from "crypto";
4509
4730
  import path12 from "path";
4510
4731
  import os9 from "os";
@@ -4517,7 +4738,7 @@ function mcpHttpUrl() {
4517
4738
  function readOrCreateDaemonToken(homeDir = os9.homedir()) {
4518
4739
  const exeDir = path12.join(homeDir, ".exe-os");
4519
4740
  const tokenPath = path12.join(exeDir, "exed.token");
4520
- if (existsSync11(tokenPath)) {
4741
+ if (existsSync12(tokenPath)) {
4521
4742
  try {
4522
4743
  const token2 = readFileSync7(tokenPath, "utf-8").trim();
4523
4744
  if (/^[a-f0-9]{64}$/i.test(token2)) return token2;
@@ -4525,7 +4746,7 @@ function readOrCreateDaemonToken(homeDir = os9.homedir()) {
4525
4746
  }
4526
4747
  }
4527
4748
  const token = randomBytes(32).toString("hex");
4528
- mkdirSync6(exeDir, { recursive: true });
4749
+ mkdirSync7(exeDir, { recursive: true });
4529
4750
  writeFileSync6(tokenPath, `${token}
4530
4751
  `, "utf-8");
4531
4752
  try {
@@ -4696,7 +4917,7 @@ var init_runtime_hook_manifest = __esm({
4696
4917
 
4697
4918
  // src/adapters/claude/installer.ts
4698
4919
  import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, readdir, rm } from "fs/promises";
4699
- import { existsSync as existsSync12, readFileSync as readFileSync8, writeFileSync as writeFileSync7, copyFileSync, mkdirSync as mkdirSync7 } from "fs";
4920
+ import { existsSync as existsSync13, readFileSync as readFileSync8, writeFileSync as writeFileSync7, copyFileSync as copyFileSync2, mkdirSync as mkdirSync8 } from "fs";
4700
4921
  import { createHash as createHash4 } from "crypto";
4701
4922
  import path13 from "path";
4702
4923
  import os10 from "os";
@@ -4708,7 +4929,7 @@ function resolvePackageRoot() {
4708
4929
  const root = path13.parse(dir).root;
4709
4930
  while (dir !== root) {
4710
4931
  const pkgPath = path13.join(dir, "package.json");
4711
- if (existsSync12(pkgPath)) {
4932
+ if (existsSync13(pkgPath)) {
4712
4933
  try {
4713
4934
  const pkg = JSON.parse(readFileSync8(pkgPath, "utf-8"));
4714
4935
  if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
@@ -4937,7 +5158,7 @@ __export(installer_exports, {
4937
5158
  verifyOpenCodeHooks: () => verifyOpenCodeHooks
4938
5159
  });
4939
5160
  import { readFile as readFile5, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
4940
- import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
5161
+ import { existsSync as existsSync14, readFileSync as readFileSync9 } from "fs";
4941
5162
  import path14 from "path";
4942
5163
  import os11 from "os";
4943
5164
  async function registerOpenCodeMcp(packageRoot, homeDir = os11.homedir()) {
@@ -4946,7 +5167,7 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os11.homedir()) {
4946
5167
  const configPath = path14.join(configDir, "opencode.json");
4947
5168
  await mkdir5(configDir, { recursive: true });
4948
5169
  let config = {};
4949
- if (existsSync13(configPath)) {
5170
+ if (existsSync14(configPath)) {
4950
5171
  try {
4951
5172
  config = JSON.parse(await readFile5(configPath, "utf-8"));
4952
5173
  } catch {
@@ -4981,7 +5202,7 @@ async function installOpenCodePlugin(packageRoot, homeDir = os11.homedir()) {
4981
5202
  /__PACKAGE_ROOT__/g,
4982
5203
  packageRoot.replace(/\\/g, "\\\\")
4983
5204
  );
4984
- if (existsSync13(pluginPath)) {
5205
+ if (existsSync14(pluginPath)) {
4985
5206
  const existing = await readFile5(pluginPath, "utf-8");
4986
5207
  if (existing === pluginContent) {
4987
5208
  return false;
@@ -4993,14 +5214,14 @@ async function installOpenCodePlugin(packageRoot, homeDir = os11.homedir()) {
4993
5214
  function verifyOpenCodeHooks(homeDir = os11.homedir()) {
4994
5215
  const configPath = path14.join(homeDir, ".config", "opencode", "opencode.json");
4995
5216
  const pluginPath = path14.join(homeDir, ".config", "opencode", "plugins", "exe-os.mjs");
4996
- if (!existsSync13(configPath)) return false;
5217
+ if (!existsSync14(configPath)) return false;
4997
5218
  try {
4998
5219
  const config = JSON.parse(readFileSync9(configPath, "utf-8"));
4999
5220
  if (!config.mcp?.["exe-os"]?.enabled) return false;
5000
5221
  } catch {
5001
5222
  return false;
5002
5223
  }
5003
- if (!existsSync13(pluginPath)) return false;
5224
+ if (!existsSync14(pluginPath)) return false;
5004
5225
  try {
5005
5226
  const plugin = readFileSync9(pluginPath, "utf-8");
5006
5227
  if (!plugin.includes(EXE_HOOK_FILES.postToolCombined)) return false;
@@ -5037,10 +5258,10 @@ var init_installer2 = __esm({
5037
5258
  import os12 from "os";
5038
5259
  import path15 from "path";
5039
5260
  import {
5040
- existsSync as existsSync14,
5261
+ existsSync as existsSync15,
5041
5262
  readFileSync as readFileSync10,
5042
5263
  writeFileSync as writeFileSync8,
5043
- mkdirSync as mkdirSync8,
5264
+ mkdirSync as mkdirSync9,
5044
5265
  readdirSync as readdirSync4
5045
5266
  } from "fs";
5046
5267
  import { spawnSync } from "child_process";
@@ -5051,7 +5272,7 @@ init_database();
5051
5272
 
5052
5273
  // src/lib/keychain.ts
5053
5274
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
5054
- import { existsSync as existsSync6, statSync as statSync2 } from "fs";
5275
+ import { existsSync as existsSync7, statSync as statSync3 } from "fs";
5055
5276
  import { execSync as execSync3 } from "child_process";
5056
5277
  import path6 from "path";
5057
5278
  import os5 from "os";
@@ -5090,7 +5311,7 @@ function isRootOnlyTrustedServerKeyFile(keyPath) {
5090
5311
  if (process.platform !== "linux") return false;
5091
5312
  try {
5092
5313
  const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
5093
- const st = statSync2(keyPath);
5314
+ const st = statSync3(keyPath);
5094
5315
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
5095
5316
  if (uid === 0) return true;
5096
5317
  const exeOsDir = process.env.EXE_OS_DIR;
@@ -5292,7 +5513,7 @@ async function getMasterKey() {
5292
5513
  }
5293
5514
  }
5294
5515
  const keyPath = getKeyPath();
5295
- if (!existsSync6(keyPath)) {
5516
+ if (!existsSync7(keyPath)) {
5296
5517
  process.stderr.write(
5297
5518
  `[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
5298
5519
  `
@@ -5486,6 +5707,13 @@ function schedulePostWriteMemoryHygiene(memoryIds) {
5486
5707
  }
5487
5708
 
5488
5709
  // src/lib/store.ts
5710
+ var _debugStore = process.env.EXE_DEBUG === "1";
5711
+ function logStoreWarn(context, err) {
5712
+ process.stderr.write(
5713
+ `[store] WARN ${context}: ${err instanceof Error ? err.message : String(err)}
5714
+ `
5715
+ );
5716
+ }
5489
5717
  var INIT_MAX_RETRIES = 3;
5490
5718
  var INIT_RETRY_DELAY_MS = 1e3;
5491
5719
  function isBusyError2(err) {
@@ -5548,13 +5776,15 @@ async function initStore(options) {
5548
5776
  try {
5549
5777
  const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
5550
5778
  await initDaemonClient2();
5551
- } catch {
5779
+ } catch (e) {
5780
+ logStoreWarn("catch", e);
5552
5781
  }
5553
5782
  if (!options?.lightweight) {
5554
5783
  try {
5555
5784
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
5556
5785
  initShardManager2(hexKey);
5557
- } catch {
5786
+ } catch (e) {
5787
+ logStoreWarn("catch", e);
5558
5788
  }
5559
5789
  const client = getClient();
5560
5790
  const vResult = await retryOnBusy2(
@@ -5565,7 +5795,8 @@ async function initStore(options) {
5565
5795
  try {
5566
5796
  const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
5567
5797
  await loadGlobalProcedures2();
5568
- } catch {
5798
+ } catch (e) {
5799
+ logStoreWarn("catch", e);
5569
5800
  }
5570
5801
  }
5571
5802
  }
@@ -5693,12 +5924,14 @@ async function flushBatch() {
5693
5924
  try {
5694
5925
  const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
5695
5926
  await insertMemoryCardsForBatch2(batch);
5696
- } catch {
5927
+ } catch (e) {
5928
+ logStoreWarn("catch", e);
5697
5929
  }
5698
5930
  try {
5699
5931
  const { insertOntologyForBatch: insertOntologyForBatch2 } = await Promise.resolve().then(() => (init_agentic_ontology(), agentic_ontology_exports));
5700
5932
  await insertOntologyForBatch2(batch);
5701
- } catch {
5933
+ } catch (e) {
5934
+ logStoreWarn("catch", e);
5702
5935
  }
5703
5936
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
5704
5937
  _pendingRecords.splice(0, batch.length);
@@ -5737,7 +5970,8 @@ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
5737
5970
  }
5738
5971
  }
5739
5972
  }
5740
- } catch {
5973
+ } catch (e) {
5974
+ logStoreWarn("catch", e);
5741
5975
  }
5742
5976
  return batch.length;
5743
5977
  } finally {
@@ -5765,11 +5999,11 @@ function vectorToBlob(vector) {
5765
5999
  import os6 from "os";
5766
6000
  import path8 from "path";
5767
6001
  import {
5768
- existsSync as existsSync8,
5769
- mkdirSync as mkdirSync3,
6002
+ existsSync as existsSync9,
6003
+ mkdirSync as mkdirSync4,
5770
6004
  readdirSync as readdirSync2,
5771
- statSync as statSync4,
5772
- unlinkSync as unlinkSync3,
6005
+ statSync as statSync5,
6006
+ unlinkSync as unlinkSync4,
5773
6007
  writeFileSync as writeFileSync3
5774
6008
  } from "fs";
5775
6009
 
@@ -5830,7 +6064,7 @@ function getBehaviorLimit() {
5830
6064
  }
5831
6065
  }
5832
6066
  function sweepStaleBehaviorExports(now = Date.now()) {
5833
- if (!existsSync8(BEHAVIORS_EXPORT_DIR)) return;
6067
+ if (!existsSync9(BEHAVIORS_EXPORT_DIR)) return;
5834
6068
  let entries;
5835
6069
  try {
5836
6070
  entries = readdirSync2(BEHAVIORS_EXPORT_DIR);
@@ -5840,9 +6074,9 @@ function sweepStaleBehaviorExports(now = Date.now()) {
5840
6074
  for (const entry of entries) {
5841
6075
  const filePath = path8.join(BEHAVIORS_EXPORT_DIR, entry);
5842
6076
  try {
5843
- const stat = statSync4(filePath);
6077
+ const stat = statSync5(filePath);
5844
6078
  if (now - stat.mtimeMs > STALE_EXPORT_AGE_MS) {
5845
- unlinkSync3(filePath);
6079
+ unlinkSync4(filePath);
5846
6080
  }
5847
6081
  } catch {
5848
6082
  }
@@ -5880,7 +6114,7 @@ function exportFilePath(agentId, projectName, sessionKey) {
5880
6114
  );
5881
6115
  }
5882
6116
  async function exportBehaviorsForAgent(agentId, projectName, sessionKey) {
5883
- mkdirSync3(BEHAVIORS_EXPORT_DIR, { recursive: true });
6117
+ mkdirSync4(BEHAVIORS_EXPORT_DIR, { recursive: true });
5884
6118
  sweepStaleBehaviorExports();
5885
6119
  const behaviors = await listBehaviors(agentId, projectName, getBehaviorLimit());
5886
6120
  if (behaviors.length === 0) return null;
@@ -5922,7 +6156,7 @@ function resolveAgent(argv) {
5922
6156
  function loadIdentity(agent) {
5923
6157
  const dir = path15.join(os12.homedir(), ".exe-os", "identity");
5924
6158
  const exact = path15.join(dir, `${agent}.md`);
5925
- if (existsSync14(exact)) {
6159
+ if (existsSync15(exact)) {
5926
6160
  const content = readFileSync10(exact, "utf-8").trim();
5927
6161
  if (content) return content;
5928
6162
  }
@@ -5948,9 +6182,9 @@ function loadIdentity(agent) {
5948
6182
  }
5949
6183
  function writeAgentFile(agent, identity, behaviorsPath) {
5950
6184
  const agentDir = path15.join(os12.homedir(), ".config", "opencode", "agents");
5951
- mkdirSync8(agentDir, { recursive: true });
6185
+ mkdirSync9(agentDir, { recursive: true });
5952
6186
  let content = identity;
5953
- if (behaviorsPath && existsSync14(behaviorsPath)) {
6187
+ if (behaviorsPath && existsSync15(behaviorsPath)) {
5954
6188
  const behaviors = readFileSync10(behaviorsPath, "utf-8").trim();
5955
6189
  if (behaviors) {
5956
6190
  content += "\n\n" + behaviors;