@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",
@@ -4294,7 +4515,7 @@ __export(active_agent_exports, {
4294
4515
  resolveActiveAgentFromTmuxSession: () => resolveActiveAgentFromTmuxSession,
4295
4516
  writeActiveAgent: () => writeActiveAgent
4296
4517
  });
4297
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, unlinkSync as unlinkSync4, readdirSync as readdirSync3 } from "fs";
4518
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, unlinkSync as unlinkSync5, readdirSync as readdirSync3 } from "fs";
4298
4519
  import { execSync as execSync5 } from "child_process";
4299
4520
  import path9 from "path";
4300
4521
  function isNameWithOptionalInstance(candidate, baseName) {
@@ -4344,7 +4565,7 @@ function getMarkerPath() {
4344
4565
  }
4345
4566
  function writeActiveAgent(agentId, agentRole) {
4346
4567
  try {
4347
- mkdirSync4(CACHE_DIR, { recursive: true });
4568
+ mkdirSync5(CACHE_DIR, { recursive: true });
4348
4569
  writeFileSync4(
4349
4570
  getMarkerPath(),
4350
4571
  JSON.stringify({ agentId, agentRole, startedAt: (/* @__PURE__ */ new Date()).toISOString() })
@@ -4354,7 +4575,7 @@ function writeActiveAgent(agentId, agentRole) {
4354
4575
  }
4355
4576
  function clearActiveAgent() {
4356
4577
  try {
4357
- unlinkSync4(getMarkerPath());
4578
+ unlinkSync5(getMarkerPath());
4358
4579
  } catch {
4359
4580
  }
4360
4581
  }
@@ -4370,7 +4591,7 @@ function getActiveAgent() {
4370
4591
  const age = Date.now() - new Date(data.startedAt).getTime();
4371
4592
  if (age > STALE_MS) {
4372
4593
  try {
4373
- unlinkSync4(markerPath);
4594
+ unlinkSync5(markerPath);
4374
4595
  } catch {
4375
4596
  }
4376
4597
  } else {
@@ -4418,7 +4639,7 @@ function getAllActiveAgents() {
4418
4639
  const age = Date.now() - new Date(data.startedAt).getTime();
4419
4640
  if (age > STALE_MS) {
4420
4641
  try {
4421
- unlinkSync4(path9.join(CACHE_DIR, file));
4642
+ unlinkSync5(path9.join(CACHE_DIR, file));
4422
4643
  } catch {
4423
4644
  }
4424
4645
  continue;
@@ -4441,11 +4662,11 @@ function getAllActiveAgents() {
4441
4662
  function cleanupSessionMarkers() {
4442
4663
  const key = getSessionKey();
4443
4664
  try {
4444
- unlinkSync4(path9.join(CACHE_DIR, `active-agent-${key}.json`));
4665
+ unlinkSync5(path9.join(CACHE_DIR, `active-agent-${key}.json`));
4445
4666
  } catch {
4446
4667
  }
4447
4668
  try {
4448
- unlinkSync4(path9.join(CACHE_DIR, "active-agent-undefined.json"));
4669
+ unlinkSync5(path9.join(CACHE_DIR, "active-agent-undefined.json"));
4449
4670
  } catch {
4450
4671
  }
4451
4672
  }
@@ -4466,9 +4687,9 @@ var init_active_agent = __esm({
4466
4687
  import os7 from "os";
4467
4688
  import path10 from "path";
4468
4689
  import {
4469
- existsSync as existsSync9,
4690
+ existsSync as existsSync10,
4470
4691
  lstatSync,
4471
- mkdirSync as mkdirSync5,
4692
+ mkdirSync as mkdirSync6,
4472
4693
  readlinkSync as readlinkSync2,
4473
4694
  symlinkSync as symlinkSync2
4474
4695
  } from "fs";
@@ -4494,12 +4715,12 @@ var init_mcp_prefix = __esm({
4494
4715
  });
4495
4716
 
4496
4717
  // src/lib/preferences.ts
4497
- import { existsSync as existsSync10, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
4718
+ import { existsSync as existsSync11, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
4498
4719
  import path11 from "path";
4499
4720
  import os8 from "os";
4500
4721
  function loadPreferences(homeDir = os8.homedir()) {
4501
4722
  const configPath = path11.join(homeDir, ".exe-os", "config.json");
4502
- if (!existsSync10(configPath)) return {};
4723
+ if (!existsSync11(configPath)) return {};
4503
4724
  try {
4504
4725
  const config = JSON.parse(readFileSync6(configPath, "utf-8"));
4505
4726
  return config.preferences ?? {};
@@ -4515,7 +4736,7 @@ var init_preferences = __esm({
4515
4736
  });
4516
4737
 
4517
4738
  // src/adapters/mcp-http-config.ts
4518
- import { chmodSync as chmodSync3, existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
4739
+ import { chmodSync as chmodSync3, existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
4519
4740
  import { randomBytes } from "crypto";
4520
4741
  import path12 from "path";
4521
4742
  import os9 from "os";
@@ -4528,7 +4749,7 @@ function mcpHttpUrl() {
4528
4749
  function readOrCreateDaemonToken(homeDir = os9.homedir()) {
4529
4750
  const exeDir = path12.join(homeDir, ".exe-os");
4530
4751
  const tokenPath = path12.join(exeDir, "exed.token");
4531
- if (existsSync11(tokenPath)) {
4752
+ if (existsSync12(tokenPath)) {
4532
4753
  try {
4533
4754
  const token2 = readFileSync7(tokenPath, "utf-8").trim();
4534
4755
  if (/^[a-f0-9]{64}$/i.test(token2)) return token2;
@@ -4536,7 +4757,7 @@ function readOrCreateDaemonToken(homeDir = os9.homedir()) {
4536
4757
  }
4537
4758
  }
4538
4759
  const token = randomBytes(32).toString("hex");
4539
- mkdirSync6(exeDir, { recursive: true });
4760
+ mkdirSync7(exeDir, { recursive: true });
4540
4761
  writeFileSync6(tokenPath, `${token}
4541
4762
  `, "utf-8");
4542
4763
  try {
@@ -4709,7 +4930,7 @@ var init_runtime_hook_manifest = __esm({
4709
4930
 
4710
4931
  // src/adapters/claude/installer.ts
4711
4932
  import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, readdir, rm } from "fs/promises";
4712
- import { existsSync as existsSync12, readFileSync as readFileSync8, writeFileSync as writeFileSync7, copyFileSync, mkdirSync as mkdirSync7 } from "fs";
4933
+ import { existsSync as existsSync13, readFileSync as readFileSync8, writeFileSync as writeFileSync7, copyFileSync as copyFileSync2, mkdirSync as mkdirSync8 } from "fs";
4713
4934
  import { createHash as createHash4 } from "crypto";
4714
4935
  import path13 from "path";
4715
4936
  import os10 from "os";
@@ -4721,7 +4942,7 @@ function resolvePackageRoot() {
4721
4942
  const root = path13.parse(dir).root;
4722
4943
  while (dir !== root) {
4723
4944
  const pkgPath = path13.join(dir, "package.json");
4724
- if (existsSync12(pkgPath)) {
4945
+ if (existsSync13(pkgPath)) {
4725
4946
  try {
4726
4947
  const pkg = JSON.parse(readFileSync8(pkgPath, "utf-8"));
4727
4948
  if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
@@ -4768,7 +4989,7 @@ __export(installer_exports, {
4768
4989
  verifyCodexHooks: () => verifyCodexHooks
4769
4990
  });
4770
4991
  import { readFile as readFile5, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
4771
- import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
4992
+ import { existsSync as existsSync14, readFileSync as readFileSync9 } from "fs";
4772
4993
  import path14 from "path";
4773
4994
  import os11 from "os";
4774
4995
  async function mergeCodexHooks(packageRoot, homeDir = os11.homedir()) {
@@ -4780,7 +5001,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os11.homedir()) {
4780
5001
  await mkdir5(codexDir, { recursive: true });
4781
5002
  await mkdir5(logsDir, { recursive: true });
4782
5003
  let hooksJson = {};
4783
- if (existsSync13(hooksPath)) {
5004
+ if (existsSync14(hooksPath)) {
4784
5005
  try {
4785
5006
  hooksJson = JSON.parse(await readFile5(hooksPath, "utf-8"));
4786
5007
  } catch {
@@ -4889,7 +5110,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os11.homedir()) {
4889
5110
  }
4890
5111
  function verifyCodexHooks(homeDir = os11.homedir()) {
4891
5112
  const hooksPath = path14.join(homeDir, ".codex", "hooks.json");
4892
- if (!existsSync13(hooksPath)) return false;
5113
+ if (!existsSync14(hooksPath)) return false;
4893
5114
  try {
4894
5115
  const hooksJson = JSON.parse(readFileSync9(hooksPath, "utf-8"));
4895
5116
  if (!hooksJson.hooks) return false;
@@ -4927,7 +5148,7 @@ async function installCodexStatusLine(homeDir = os11.homedir()) {
4927
5148
  const configPath = path14.join(codexDir, "config.toml");
4928
5149
  await mkdir5(codexDir, { recursive: true });
4929
5150
  let content = "";
4930
- if (existsSync13(configPath)) {
5151
+ if (existsSync14(configPath)) {
4931
5152
  content = await readFile5(configPath, "utf-8");
4932
5153
  if (/\[tui\][\s\S]*?status_line\s*=/.test(content)) {
4933
5154
  return "already-configured";
@@ -4984,7 +5205,7 @@ async function registerCodexMcpServer(packageRoot, homeDir = os11.homedir()) {
4984
5205
  void packageRoot;
4985
5206
  await mkdir5(codexDir, { recursive: true });
4986
5207
  let content = "";
4987
- if (existsSync13(configPath)) {
5208
+ if (existsSync14(configPath)) {
4988
5209
  content = await readFile5(configPath, "utf-8");
4989
5210
  }
4990
5211
  const sectionHeader = "[mcp_servers.exe-os]";
@@ -5012,7 +5233,7 @@ async function ensureCodexHooksFeature(homeDir = os11.homedir()) {
5012
5233
  const configPath = path14.join(homeDir, ".codex", "config.toml");
5013
5234
  await mkdir5(path14.join(homeDir, ".codex"), { recursive: true });
5014
5235
  let content = "";
5015
- if (existsSync13(configPath)) {
5236
+ if (existsSync14(configPath)) {
5016
5237
  content = await readFile5(configPath, "utf-8");
5017
5238
  }
5018
5239
  if (/\[features\][\s\S]*?codex_hooks\s*=\s*true/.test(content)) {
@@ -5094,10 +5315,10 @@ __export(agent_config_exports, {
5094
5315
  saveAgentConfig: () => saveAgentConfig,
5095
5316
  setAgentRuntime: () => setAgentRuntime
5096
5317
  });
5097
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync8, existsSync as existsSync14 } from "fs";
5318
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync8, existsSync as existsSync15 } from "fs";
5098
5319
  import path15 from "path";
5099
5320
  function loadAgentConfig() {
5100
- if (!existsSync14(AGENT_CONFIG_PATH)) return {};
5321
+ if (!existsSync15(AGENT_CONFIG_PATH)) return {};
5101
5322
  try {
5102
5323
  return JSON.parse(readFileSync10(AGENT_CONFIG_PATH, "utf-8"));
5103
5324
  } catch {
@@ -5174,10 +5395,10 @@ var init_agent_config = __esm({
5174
5395
  import os12 from "os";
5175
5396
  import path16 from "path";
5176
5397
  import {
5177
- existsSync as existsSync15,
5398
+ existsSync as existsSync16,
5178
5399
  readFileSync as readFileSync11,
5179
5400
  writeFileSync as writeFileSync9,
5180
- mkdirSync as mkdirSync8,
5401
+ mkdirSync as mkdirSync9,
5181
5402
  readdirSync as readdirSync4
5182
5403
  } from "fs";
5183
5404
  import { spawnSync } from "child_process";
@@ -5188,7 +5409,7 @@ init_database();
5188
5409
 
5189
5410
  // src/lib/keychain.ts
5190
5411
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
5191
- import { existsSync as existsSync6, statSync as statSync2 } from "fs";
5412
+ import { existsSync as existsSync7, statSync as statSync3 } from "fs";
5192
5413
  import { execSync as execSync3 } from "child_process";
5193
5414
  import path6 from "path";
5194
5415
  import os5 from "os";
@@ -5227,7 +5448,7 @@ function isRootOnlyTrustedServerKeyFile(keyPath) {
5227
5448
  if (process.platform !== "linux") return false;
5228
5449
  try {
5229
5450
  const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
5230
- const st = statSync2(keyPath);
5451
+ const st = statSync3(keyPath);
5231
5452
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
5232
5453
  if (uid === 0) return true;
5233
5454
  const exeOsDir = process.env.EXE_OS_DIR;
@@ -5429,7 +5650,7 @@ async function getMasterKey() {
5429
5650
  }
5430
5651
  }
5431
5652
  const keyPath = getKeyPath();
5432
- if (!existsSync6(keyPath)) {
5653
+ if (!existsSync7(keyPath)) {
5433
5654
  process.stderr.write(
5434
5655
  `[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
5435
5656
  `
@@ -5623,6 +5844,13 @@ function schedulePostWriteMemoryHygiene(memoryIds) {
5623
5844
  }
5624
5845
 
5625
5846
  // src/lib/store.ts
5847
+ var _debugStore = process.env.EXE_DEBUG === "1";
5848
+ function logStoreWarn(context, err) {
5849
+ process.stderr.write(
5850
+ `[store] WARN ${context}: ${err instanceof Error ? err.message : String(err)}
5851
+ `
5852
+ );
5853
+ }
5626
5854
  var INIT_MAX_RETRIES = 3;
5627
5855
  var INIT_RETRY_DELAY_MS = 1e3;
5628
5856
  function isBusyError2(err) {
@@ -5685,13 +5913,15 @@ async function initStore(options) {
5685
5913
  try {
5686
5914
  const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
5687
5915
  await initDaemonClient2();
5688
- } catch {
5916
+ } catch (e) {
5917
+ logStoreWarn("catch", e);
5689
5918
  }
5690
5919
  if (!options?.lightweight) {
5691
5920
  try {
5692
5921
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
5693
5922
  initShardManager2(hexKey);
5694
- } catch {
5923
+ } catch (e) {
5924
+ logStoreWarn("catch", e);
5695
5925
  }
5696
5926
  const client = getClient();
5697
5927
  const vResult = await retryOnBusy2(
@@ -5702,7 +5932,8 @@ async function initStore(options) {
5702
5932
  try {
5703
5933
  const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
5704
5934
  await loadGlobalProcedures2();
5705
- } catch {
5935
+ } catch (e) {
5936
+ logStoreWarn("catch", e);
5706
5937
  }
5707
5938
  }
5708
5939
  }
@@ -5830,12 +6061,14 @@ async function flushBatch() {
5830
6061
  try {
5831
6062
  const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
5832
6063
  await insertMemoryCardsForBatch2(batch);
5833
- } catch {
6064
+ } catch (e) {
6065
+ logStoreWarn("catch", e);
5834
6066
  }
5835
6067
  try {
5836
6068
  const { insertOntologyForBatch: insertOntologyForBatch2 } = await Promise.resolve().then(() => (init_agentic_ontology(), agentic_ontology_exports));
5837
6069
  await insertOntologyForBatch2(batch);
5838
- } catch {
6070
+ } catch (e) {
6071
+ logStoreWarn("catch", e);
5839
6072
  }
5840
6073
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
5841
6074
  _pendingRecords.splice(0, batch.length);
@@ -5874,7 +6107,8 @@ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
5874
6107
  }
5875
6108
  }
5876
6109
  }
5877
- } catch {
6110
+ } catch (e) {
6111
+ logStoreWarn("catch", e);
5878
6112
  }
5879
6113
  return batch.length;
5880
6114
  } finally {
@@ -5902,11 +6136,11 @@ function vectorToBlob(vector) {
5902
6136
  import os6 from "os";
5903
6137
  import path8 from "path";
5904
6138
  import {
5905
- existsSync as existsSync8,
5906
- mkdirSync as mkdirSync3,
6139
+ existsSync as existsSync9,
6140
+ mkdirSync as mkdirSync4,
5907
6141
  readdirSync as readdirSync2,
5908
- statSync as statSync4,
5909
- unlinkSync as unlinkSync3,
6142
+ statSync as statSync5,
6143
+ unlinkSync as unlinkSync4,
5910
6144
  writeFileSync as writeFileSync3
5911
6145
  } from "fs";
5912
6146
 
@@ -5967,7 +6201,7 @@ function getBehaviorLimit() {
5967
6201
  }
5968
6202
  }
5969
6203
  function sweepStaleBehaviorExports(now = Date.now()) {
5970
- if (!existsSync8(BEHAVIORS_EXPORT_DIR)) return;
6204
+ if (!existsSync9(BEHAVIORS_EXPORT_DIR)) return;
5971
6205
  let entries;
5972
6206
  try {
5973
6207
  entries = readdirSync2(BEHAVIORS_EXPORT_DIR);
@@ -5977,9 +6211,9 @@ function sweepStaleBehaviorExports(now = Date.now()) {
5977
6211
  for (const entry of entries) {
5978
6212
  const filePath = path8.join(BEHAVIORS_EXPORT_DIR, entry);
5979
6213
  try {
5980
- const stat = statSync4(filePath);
6214
+ const stat = statSync5(filePath);
5981
6215
  if (now - stat.mtimeMs > STALE_EXPORT_AGE_MS) {
5982
- unlinkSync3(filePath);
6216
+ unlinkSync4(filePath);
5983
6217
  }
5984
6218
  } catch {
5985
6219
  }
@@ -6017,7 +6251,7 @@ function exportFilePath(agentId, projectName, sessionKey) {
6017
6251
  );
6018
6252
  }
6019
6253
  async function exportBehaviorsForAgent(agentId, projectName, sessionKey) {
6020
- mkdirSync3(BEHAVIORS_EXPORT_DIR, { recursive: true });
6254
+ mkdirSync4(BEHAVIORS_EXPORT_DIR, { recursive: true });
6021
6255
  sweepStaleBehaviorExports();
6022
6256
  const behaviors = await listBehaviors(agentId, projectName, getBehaviorLimit());
6023
6257
  if (behaviors.length === 0) return null;
@@ -6083,7 +6317,7 @@ function resolveAgent(argv) {
6083
6317
  function loadIdentity(agent) {
6084
6318
  const dir = path16.join(os12.homedir(), ".exe-os", "identity");
6085
6319
  const exact = path16.join(dir, `${agent}.md`);
6086
- if (existsSync15(exact)) {
6320
+ if (existsSync16(exact)) {
6087
6321
  const content = readFileSync11(exact, "utf-8").trim();
6088
6322
  if (content) return content;
6089
6323
  }
@@ -6109,13 +6343,13 @@ function loadIdentity(agent) {
6109
6343
  }
6110
6344
  function writePromptFile(agent, identity, behaviorsPath, globalProcedures) {
6111
6345
  const promptDir = path16.join(os12.homedir(), ".exe-os", "codex-prompt");
6112
- mkdirSync8(promptDir, { recursive: true });
6346
+ mkdirSync9(promptDir, { recursive: true });
6113
6347
  let prompt = "";
6114
6348
  if (globalProcedures) {
6115
6349
  prompt += globalProcedures + "\n\n";
6116
6350
  }
6117
6351
  prompt += identity;
6118
- if (behaviorsPath && existsSync15(behaviorsPath)) {
6352
+ if (behaviorsPath && existsSync16(behaviorsPath)) {
6119
6353
  const behaviors = readFileSync11(behaviorsPath, "utf-8").trim();
6120
6354
  if (behaviors) {
6121
6355
  prompt += "\n\n" + behaviors;
@@ -6254,12 +6488,12 @@ async function main() {
6254
6488
  const { execSync: es } = await import("child_process");
6255
6489
  const worktreeDir = path16.join(process.cwd(), ".worktrees", worktreeName);
6256
6490
  const branchName = `${worktreeName}/codex-${Date.now()}`;
6257
- if (existsSync15(worktreeDir)) {
6491
+ if (existsSync16(worktreeDir)) {
6258
6492
  worktreePath = worktreeDir;
6259
6493
  process.stderr.write(`[exe-start-codex] Reusing worktree at ${worktreeDir}
6260
6494
  `);
6261
6495
  } else {
6262
- mkdirSync8(path16.dirname(worktreeDir), { recursive: true });
6496
+ mkdirSync9(path16.dirname(worktreeDir), { recursive: true });
6263
6497
  es(`git worktree add "${worktreeDir}" -b "${branchName}" HEAD`, {
6264
6498
  encoding: "utf-8",
6265
6499
  timeout: 3e4