@askexenow/exe-os 0.8.82 → 0.8.85

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 (97) hide show
  1. package/dist/bin/backfill-conversations.js +746 -595
  2. package/dist/bin/backfill-responses.js +745 -594
  3. package/dist/bin/backfill-vectors.js +312 -226
  4. package/dist/bin/cleanup-stale-review-tasks.js +97 -2
  5. package/dist/bin/cli.js +14360 -12525
  6. package/dist/bin/exe-agent.js +97 -88
  7. package/dist/bin/exe-assign.js +1003 -854
  8. package/dist/bin/exe-boot.js +1260 -323
  9. package/dist/bin/exe-call.js +10 -0
  10. package/dist/bin/exe-cloud.js +32 -9
  11. package/dist/bin/exe-dispatch.js +212 -36
  12. package/dist/bin/exe-doctor.js +403 -6
  13. package/dist/bin/exe-export-behaviors.js +175 -72
  14. package/dist/bin/exe-forget.js +97 -2
  15. package/dist/bin/exe-gateway.js +553 -174
  16. package/dist/bin/exe-healthcheck.js +1 -0
  17. package/dist/bin/exe-heartbeat.js +100 -5
  18. package/dist/bin/exe-kill.js +175 -72
  19. package/dist/bin/exe-launch-agent.js +189 -76
  20. package/dist/bin/exe-link.js +902 -80
  21. package/dist/bin/exe-new-employee.js +41 -11
  22. package/dist/bin/exe-pending-messages.js +96 -2
  23. package/dist/bin/exe-pending-notifications.js +97 -2
  24. package/dist/bin/exe-pending-reviews.js +98 -3
  25. package/dist/bin/exe-rename.js +577 -33
  26. package/dist/bin/exe-review.js +231 -73
  27. package/dist/bin/exe-search.js +989 -226
  28. package/dist/bin/exe-session-cleanup.js +4806 -1665
  29. package/dist/bin/exe-settings.js +20 -5
  30. package/dist/bin/exe-status.js +97 -2
  31. package/dist/bin/exe-team.js +97 -2
  32. package/dist/bin/git-sweep.js +901 -209
  33. package/dist/bin/graph-backfill.js +175 -72
  34. package/dist/bin/graph-export.js +175 -72
  35. package/dist/bin/install.js +38 -7
  36. package/dist/bin/list-providers.js +1 -0
  37. package/dist/bin/scan-tasks.js +906 -213
  38. package/dist/bin/setup.js +870 -271
  39. package/dist/bin/shard-migrate.js +175 -72
  40. package/dist/bin/update.js +4 -3
  41. package/dist/bin/wiki-sync.js +175 -72
  42. package/dist/gateway/index.js +550 -168
  43. package/dist/hooks/bug-report-worker.js +210 -25
  44. package/dist/hooks/commit-complete.js +899 -207
  45. package/dist/hooks/error-recall.js +988 -226
  46. package/dist/hooks/ingest-worker.js +1639 -1195
  47. package/dist/hooks/ingest.js +3 -0
  48. package/dist/hooks/instructions-loaded.js +707 -97
  49. package/dist/hooks/notification.js +699 -89
  50. package/dist/hooks/post-compact.js +714 -104
  51. package/dist/hooks/pre-compact.js +899 -207
  52. package/dist/hooks/pre-tool-use.js +742 -123
  53. package/dist/hooks/prompt-ingest-worker.js +245 -104
  54. package/dist/hooks/prompt-submit.js +995 -233
  55. package/dist/hooks/response-ingest-worker.js +245 -104
  56. package/dist/hooks/session-end.js +3941 -400
  57. package/dist/hooks/session-start.js +1001 -226
  58. package/dist/hooks/stop.js +725 -115
  59. package/dist/hooks/subagent-stop.js +714 -104
  60. package/dist/hooks/summary-worker.js +1970 -1336
  61. package/dist/index.js +1653 -1055
  62. package/dist/lib/cloud-sync.js +907 -86
  63. package/dist/lib/consolidation.js +2 -1
  64. package/dist/lib/database.js +642 -87
  65. package/dist/lib/db-daemon-client.js +503 -0
  66. package/dist/lib/device-registry.js +547 -7
  67. package/dist/lib/embedder.js +14 -28
  68. package/dist/lib/employee-templates.js +84 -74
  69. package/dist/lib/employees.js +9 -0
  70. package/dist/lib/exe-daemon-client.js +16 -29
  71. package/dist/lib/exe-daemon.js +1957 -924
  72. package/dist/lib/hybrid-search.js +988 -226
  73. package/dist/lib/identity.js +87 -67
  74. package/dist/lib/keychain.js +9 -1
  75. package/dist/lib/license.js +3 -3
  76. package/dist/lib/messaging.js +8 -1
  77. package/dist/lib/reminders.js +91 -74
  78. package/dist/lib/schedules.js +96 -2
  79. package/dist/lib/skill-learning.js +103 -85
  80. package/dist/lib/store.js +234 -73
  81. package/dist/lib/tasks.js +113 -24
  82. package/dist/lib/tmux-routing.js +122 -33
  83. package/dist/lib/token-spend.js +273 -0
  84. package/dist/lib/ws-client.js +11 -0
  85. package/dist/mcp/server.js +10874 -5546
  86. package/dist/mcp/tools/complete-reminder.js +94 -77
  87. package/dist/mcp/tools/create-reminder.js +94 -77
  88. package/dist/mcp/tools/create-task.js +810 -27
  89. package/dist/mcp/tools/deactivate-behavior.js +95 -77
  90. package/dist/mcp/tools/list-reminders.js +94 -77
  91. package/dist/mcp/tools/list-tasks.js +31 -1
  92. package/dist/mcp/tools/send-message.js +8 -1
  93. package/dist/mcp/tools/update-task.js +39 -10
  94. package/dist/runtime/index.js +913 -221
  95. package/dist/tui/App.js +1000 -298
  96. package/package.json +6 -1
  97. package/src/commands/exe/build-adv.md +2 -2
@@ -211,15 +211,22 @@ function getClient() {
211
211
  if (!_resilientClient) {
212
212
  throw new Error("Database client not initialized. Call initDatabase() first.");
213
213
  }
214
+ if (process.env.EXE_IS_DAEMON === "1") {
215
+ return _resilientClient;
216
+ }
217
+ if (_daemonClient && _daemonClient._isDaemonActive()) {
218
+ return _daemonClient;
219
+ }
214
220
  return _resilientClient;
215
221
  }
216
- var _resilientClient;
222
+ var _resilientClient, _daemonClient;
217
223
  var init_database = __esm({
218
224
  "src/lib/database.ts"() {
219
225
  "use strict";
220
226
  init_db_retry();
221
227
  init_employees();
222
228
  _resilientClient = null;
229
+ _daemonClient = null;
223
230
  }
224
231
  });
225
232
 
@@ -1084,19 +1091,41 @@ async function registerMcpServer(packageRoot, homeDir = os4.homedir()) {
1084
1091
  args: [path8.join(packageRoot, "dist", "mcp", "server.js")],
1085
1092
  env: {}
1086
1093
  };
1087
- const legacy = claudeJson.mcpServers[MCP_LEGACY_KEY];
1088
- const current = claudeJson.mcpServers[MCP_PRIMARY_KEY];
1089
- const currentMatches = current && JSON.stringify(current) === JSON.stringify(newEntry);
1090
- if (currentMatches && !legacy) {
1094
+ const currentMem = claudeJson.mcpServers[MCP_LEGACY_KEY];
1095
+ const currentOs = claudeJson.mcpServers[MCP_PRIMARY_KEY];
1096
+ const memMatches = currentMem && JSON.stringify(currentMem) === JSON.stringify(newEntry);
1097
+ const osMatches = currentOs && JSON.stringify(currentOs) === JSON.stringify(newEntry);
1098
+ if (memMatches && osMatches) {
1099
+ await cleanSettingsJsonMcp(path8.join(homeDir, ".claude", "settings.json"));
1091
1100
  return false;
1092
1101
  }
1102
+ claudeJson.mcpServers[MCP_LEGACY_KEY] = newEntry;
1093
1103
  claudeJson.mcpServers[MCP_PRIMARY_KEY] = newEntry;
1094
- if (legacy) {
1095
- delete claudeJson.mcpServers[MCP_LEGACY_KEY];
1096
- }
1097
1104
  await writeFile3(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
1105
+ await cleanSettingsJsonMcp(path8.join(homeDir, ".claude", "settings.json"));
1098
1106
  return true;
1099
1107
  }
1108
+ async function cleanSettingsJsonMcp(settingsPath) {
1109
+ if (!existsSync8(settingsPath)) return;
1110
+ try {
1111
+ const settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
1112
+ const servers = settings.mcpServers;
1113
+ if (!servers) return;
1114
+ let changed = false;
1115
+ if (servers[MCP_PRIMARY_KEY]) {
1116
+ delete servers[MCP_PRIMARY_KEY];
1117
+ changed = true;
1118
+ }
1119
+ if (servers[MCP_LEGACY_KEY]) {
1120
+ delete servers[MCP_LEGACY_KEY];
1121
+ changed = true;
1122
+ }
1123
+ if (changed) {
1124
+ await writeFile3(settingsPath, JSON.stringify(settings, null, 2) + "\n");
1125
+ }
1126
+ } catch {
1127
+ }
1128
+ }
1100
1129
  async function mergeHooks(packageRoot, homeDir = os4.homedir()) {
1101
1130
  const settingsPath = path8.join(homeDir, ".claude", "settings.json");
1102
1131
  let settings = {};
@@ -2065,6 +2094,7 @@ import { realpathSync } from "fs";
2065
2094
  import { fileURLToPath } from "url";
2066
2095
  function isMainModule(importMetaUrl) {
2067
2096
  if (process.argv[1] == null) return false;
2097
+ if (process.argv[1].includes("mcp/server")) return false;
2068
2098
  try {
2069
2099
  const scriptPath = realpathSync(process.argv[1]);
2070
2100
  const modulePath = realpathSync(fileURLToPath(importMetaUrl));
@@ -2105,8 +2135,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
2105
2135
  -----END PUBLIC KEY-----`;
2106
2136
  var LICENSE_JWT_ALG = "ES256";
2107
2137
  var PLAN_LIMITS = {
2108
- free: { devices: 1, employees: 1, memories: 5e4 },
2109
- pro: { devices: 2, employees: 5, memories: 25e4 },
2138
+ free: { devices: 1, employees: 1, memories: 5e3 },
2139
+ pro: { devices: 3, employees: 5, memories: 1e5 },
2110
2140
  team: { devices: 10, employees: 20, memories: 1e6 },
2111
2141
  agency: { devices: 50, employees: 100, memories: 1e7 },
2112
2142
  enterprise: { devices: -1, employees: -1, memories: -1 }
@@ -2118,7 +2148,7 @@ var FREE_LICENSE = {
2118
2148
  expiresAt: null,
2119
2149
  deviceLimit: 1,
2120
2150
  employeeLimit: 1,
2121
- memoryLimit: 5e4
2151
+ memoryLimit: 5e3
2122
2152
  };
2123
2153
  function loadDeviceId() {
2124
2154
  const deviceJsonPath = path4.join(EXE_AI_DIR, "device.json");
@@ -304,6 +304,12 @@ function getClient() {
304
304
  if (!_resilientClient) {
305
305
  throw new Error("Database client not initialized. Call initDatabase() first.");
306
306
  }
307
+ if (process.env.EXE_IS_DAEMON === "1") {
308
+ return _resilientClient;
309
+ }
310
+ if (_daemonClient && _daemonClient._isDaemonActive()) {
311
+ return _daemonClient;
312
+ }
307
313
  return _resilientClient;
308
314
  }
309
315
  function getRawClient() {
@@ -792,6 +798,12 @@ async function ensureSchema() {
792
798
  } catch {
793
799
  }
794
800
  }
801
+ try {
802
+ await client.execute(
803
+ `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
804
+ );
805
+ } catch {
806
+ }
795
807
  await client.executeMultiple(`
796
808
  CREATE TABLE IF NOT EXISTS entities (
797
809
  id TEXT PRIMARY KEY,
@@ -844,7 +856,30 @@ async function ensureSchema() {
844
856
  entity_id TEXT NOT NULL,
845
857
  PRIMARY KEY (hyperedge_id, entity_id)
846
858
  );
859
+
860
+ CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
861
+ name,
862
+ content=entities,
863
+ content_rowid=rowid
864
+ );
865
+
866
+ CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
867
+ INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
868
+ END;
869
+
870
+ CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
871
+ INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
872
+ END;
873
+
874
+ CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
875
+ INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
876
+ INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
877
+ END;
847
878
  `);
879
+ try {
880
+ await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
881
+ } catch {
882
+ }
848
883
  await client.executeMultiple(`
849
884
  CREATE TABLE IF NOT EXISTS entity_aliases (
850
885
  alias TEXT NOT NULL PRIMARY KEY,
@@ -1025,6 +1060,33 @@ async function ensureSchema() {
1025
1060
  CREATE INDEX IF NOT EXISTS idx_conversations_channel
1026
1061
  ON conversations(channel_id);
1027
1062
  `);
1063
+ await client.executeMultiple(`
1064
+ CREATE TABLE IF NOT EXISTS session_agent_map (
1065
+ session_uuid TEXT PRIMARY KEY,
1066
+ agent_id TEXT NOT NULL,
1067
+ session_name TEXT,
1068
+ task_id TEXT,
1069
+ project_name TEXT,
1070
+ started_at TEXT NOT NULL
1071
+ );
1072
+
1073
+ CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
1074
+ ON session_agent_map(agent_id);
1075
+ `);
1076
+ try {
1077
+ const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
1078
+ if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
1079
+ await client.execute({
1080
+ sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
1081
+ SELECT session_id, agent_id, '', MIN(timestamp)
1082
+ FROM memories
1083
+ WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
1084
+ GROUP BY session_id, agent_id`,
1085
+ args: []
1086
+ });
1087
+ }
1088
+ } catch {
1089
+ }
1028
1090
  try {
1029
1091
  await client.execute({
1030
1092
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
@@ -1158,8 +1220,30 @@ async function ensureSchema() {
1158
1220
  });
1159
1221
  } catch {
1160
1222
  }
1223
+ for (const col of [
1224
+ "ALTER TABLE memories ADD COLUMN intent TEXT",
1225
+ "ALTER TABLE memories ADD COLUMN outcome TEXT",
1226
+ "ALTER TABLE memories ADD COLUMN domain TEXT",
1227
+ "ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
1228
+ "ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
1229
+ "ALTER TABLE memories ADD COLUMN chain_position TEXT",
1230
+ "ALTER TABLE memories ADD COLUMN review_status TEXT",
1231
+ "ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
1232
+ "ALTER TABLE memories ADD COLUMN file_paths TEXT",
1233
+ "ALTER TABLE memories ADD COLUMN commit_hash TEXT",
1234
+ "ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
1235
+ "ALTER TABLE memories ADD COLUMN token_cost REAL",
1236
+ "ALTER TABLE memories ADD COLUMN audience TEXT",
1237
+ "ALTER TABLE memories ADD COLUMN language_type TEXT",
1238
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
1239
+ ]) {
1240
+ try {
1241
+ await client.execute(col);
1242
+ } catch {
1243
+ }
1244
+ }
1161
1245
  }
1162
- var _client, _resilientClient, initTurso;
1246
+ var _client, _resilientClient, _daemonClient, initTurso;
1163
1247
  var init_database = __esm({
1164
1248
  "src/lib/database.ts"() {
1165
1249
  "use strict";
@@ -1167,6 +1251,7 @@ var init_database = __esm({
1167
1251
  init_employees();
1168
1252
  _client = null;
1169
1253
  _resilientClient = null;
1254
+ _daemonClient = null;
1170
1255
  initTurso = initDatabase;
1171
1256
  }
1172
1257
  });
@@ -1778,6 +1863,7 @@ var init_tmux_routing = __esm({
1778
1863
  });
1779
1864
 
1780
1865
  // src/lib/store.ts
1866
+ import { createHash } from "crypto";
1781
1867
  init_database();
1782
1868
 
1783
1869
  // src/lib/keychain.ts
@@ -1813,12 +1899,20 @@ async function getMasterKey() {
1813
1899
  }
1814
1900
  const keyPath = getKeyPath();
1815
1901
  if (!existsSync3(keyPath)) {
1902
+ process.stderr.write(
1903
+ `[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
1904
+ `
1905
+ );
1816
1906
  return null;
1817
1907
  }
1818
1908
  try {
1819
1909
  const content = await readFile3(keyPath, "utf-8");
1820
1910
  return Buffer.from(content.trim(), "base64");
1821
- } catch {
1911
+ } catch (err) {
1912
+ process.stderr.write(
1913
+ `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
1914
+ `
1915
+ );
1822
1916
  return null;
1823
1917
  }
1824
1918
  }
@@ -305,6 +305,12 @@ function getClient() {
305
305
  if (!_resilientClient) {
306
306
  throw new Error("Database client not initialized. Call initDatabase() first.");
307
307
  }
308
+ if (process.env.EXE_IS_DAEMON === "1") {
309
+ return _resilientClient;
310
+ }
311
+ if (_daemonClient && _daemonClient._isDaemonActive()) {
312
+ return _daemonClient;
313
+ }
308
314
  return _resilientClient;
309
315
  }
310
316
  function getRawClient() {
@@ -793,6 +799,12 @@ async function ensureSchema() {
793
799
  } catch {
794
800
  }
795
801
  }
802
+ try {
803
+ await client.execute(
804
+ `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
805
+ );
806
+ } catch {
807
+ }
796
808
  await client.executeMultiple(`
797
809
  CREATE TABLE IF NOT EXISTS entities (
798
810
  id TEXT PRIMARY KEY,
@@ -845,7 +857,30 @@ async function ensureSchema() {
845
857
  entity_id TEXT NOT NULL,
846
858
  PRIMARY KEY (hyperedge_id, entity_id)
847
859
  );
860
+
861
+ CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
862
+ name,
863
+ content=entities,
864
+ content_rowid=rowid
865
+ );
866
+
867
+ CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
868
+ INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
869
+ END;
870
+
871
+ CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
872
+ INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
873
+ END;
874
+
875
+ CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
876
+ INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
877
+ INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
878
+ END;
848
879
  `);
880
+ try {
881
+ await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
882
+ } catch {
883
+ }
849
884
  await client.executeMultiple(`
850
885
  CREATE TABLE IF NOT EXISTS entity_aliases (
851
886
  alias TEXT NOT NULL PRIMARY KEY,
@@ -1026,6 +1061,33 @@ async function ensureSchema() {
1026
1061
  CREATE INDEX IF NOT EXISTS idx_conversations_channel
1027
1062
  ON conversations(channel_id);
1028
1063
  `);
1064
+ await client.executeMultiple(`
1065
+ CREATE TABLE IF NOT EXISTS session_agent_map (
1066
+ session_uuid TEXT PRIMARY KEY,
1067
+ agent_id TEXT NOT NULL,
1068
+ session_name TEXT,
1069
+ task_id TEXT,
1070
+ project_name TEXT,
1071
+ started_at TEXT NOT NULL
1072
+ );
1073
+
1074
+ CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
1075
+ ON session_agent_map(agent_id);
1076
+ `);
1077
+ try {
1078
+ const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
1079
+ if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
1080
+ await client.execute({
1081
+ sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
1082
+ SELECT session_id, agent_id, '', MIN(timestamp)
1083
+ FROM memories
1084
+ WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
1085
+ GROUP BY session_id, agent_id`,
1086
+ args: []
1087
+ });
1088
+ }
1089
+ } catch {
1090
+ }
1029
1091
  try {
1030
1092
  await client.execute({
1031
1093
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
@@ -1159,8 +1221,30 @@ async function ensureSchema() {
1159
1221
  });
1160
1222
  } catch {
1161
1223
  }
1224
+ for (const col of [
1225
+ "ALTER TABLE memories ADD COLUMN intent TEXT",
1226
+ "ALTER TABLE memories ADD COLUMN outcome TEXT",
1227
+ "ALTER TABLE memories ADD COLUMN domain TEXT",
1228
+ "ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
1229
+ "ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
1230
+ "ALTER TABLE memories ADD COLUMN chain_position TEXT",
1231
+ "ALTER TABLE memories ADD COLUMN review_status TEXT",
1232
+ "ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
1233
+ "ALTER TABLE memories ADD COLUMN file_paths TEXT",
1234
+ "ALTER TABLE memories ADD COLUMN commit_hash TEXT",
1235
+ "ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
1236
+ "ALTER TABLE memories ADD COLUMN token_cost REAL",
1237
+ "ALTER TABLE memories ADD COLUMN audience TEXT",
1238
+ "ALTER TABLE memories ADD COLUMN language_type TEXT",
1239
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
1240
+ ]) {
1241
+ try {
1242
+ await client.execute(col);
1243
+ } catch {
1244
+ }
1245
+ }
1162
1246
  }
1163
- var _client, _resilientClient, initTurso;
1247
+ var _client, _resilientClient, _daemonClient, initTurso;
1164
1248
  var init_database = __esm({
1165
1249
  "src/lib/database.ts"() {
1166
1250
  "use strict";
@@ -1168,6 +1252,7 @@ var init_database = __esm({
1168
1252
  init_employees();
1169
1253
  _client = null;
1170
1254
  _resilientClient = null;
1255
+ _daemonClient = null;
1171
1256
  initTurso = initDatabase;
1172
1257
  }
1173
1258
  });
@@ -1599,6 +1684,7 @@ ${p.content}`).join("\n\n");
1599
1684
  });
1600
1685
 
1601
1686
  // src/lib/store.ts
1687
+ import { createHash } from "crypto";
1602
1688
  init_database();
1603
1689
 
1604
1690
  // src/lib/keychain.ts
@@ -1634,12 +1720,20 @@ async function getMasterKey() {
1634
1720
  }
1635
1721
  const keyPath = getKeyPath();
1636
1722
  if (!existsSync3(keyPath)) {
1723
+ process.stderr.write(
1724
+ `[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
1725
+ `
1726
+ );
1637
1727
  return null;
1638
1728
  }
1639
1729
  try {
1640
1730
  const content = await readFile3(keyPath, "utf-8");
1641
1731
  return Buffer.from(content.trim(), "base64");
1642
- } catch {
1732
+ } catch (err) {
1733
+ process.stderr.write(
1734
+ `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
1735
+ `
1736
+ );
1643
1737
  return null;
1644
1738
  }
1645
1739
  }
@@ -1782,6 +1876,7 @@ import { realpathSync } from "fs";
1782
1876
  import { fileURLToPath } from "url";
1783
1877
  function isMainModule(importMetaUrl) {
1784
1878
  if (process.argv[1] == null) return false;
1879
+ if (process.argv[1].includes("mcp/server")) return false;
1785
1880
  try {
1786
1881
  const scriptPath = realpathSync(process.argv[1]);
1787
1882
  const modulePath = realpathSync(fileURLToPath(importMetaUrl));
@@ -305,6 +305,12 @@ function getClient() {
305
305
  if (!_resilientClient) {
306
306
  throw new Error("Database client not initialized. Call initDatabase() first.");
307
307
  }
308
+ if (process.env.EXE_IS_DAEMON === "1") {
309
+ return _resilientClient;
310
+ }
311
+ if (_daemonClient && _daemonClient._isDaemonActive()) {
312
+ return _daemonClient;
313
+ }
308
314
  return _resilientClient;
309
315
  }
310
316
  function getRawClient() {
@@ -793,6 +799,12 @@ async function ensureSchema() {
793
799
  } catch {
794
800
  }
795
801
  }
802
+ try {
803
+ await client.execute(
804
+ `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
805
+ );
806
+ } catch {
807
+ }
796
808
  await client.executeMultiple(`
797
809
  CREATE TABLE IF NOT EXISTS entities (
798
810
  id TEXT PRIMARY KEY,
@@ -845,7 +857,30 @@ async function ensureSchema() {
845
857
  entity_id TEXT NOT NULL,
846
858
  PRIMARY KEY (hyperedge_id, entity_id)
847
859
  );
860
+
861
+ CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
862
+ name,
863
+ content=entities,
864
+ content_rowid=rowid
865
+ );
866
+
867
+ CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
868
+ INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
869
+ END;
870
+
871
+ CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
872
+ INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
873
+ END;
874
+
875
+ CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
876
+ INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
877
+ INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
878
+ END;
848
879
  `);
880
+ try {
881
+ await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
882
+ } catch {
883
+ }
849
884
  await client.executeMultiple(`
850
885
  CREATE TABLE IF NOT EXISTS entity_aliases (
851
886
  alias TEXT NOT NULL PRIMARY KEY,
@@ -1026,6 +1061,33 @@ async function ensureSchema() {
1026
1061
  CREATE INDEX IF NOT EXISTS idx_conversations_channel
1027
1062
  ON conversations(channel_id);
1028
1063
  `);
1064
+ await client.executeMultiple(`
1065
+ CREATE TABLE IF NOT EXISTS session_agent_map (
1066
+ session_uuid TEXT PRIMARY KEY,
1067
+ agent_id TEXT NOT NULL,
1068
+ session_name TEXT,
1069
+ task_id TEXT,
1070
+ project_name TEXT,
1071
+ started_at TEXT NOT NULL
1072
+ );
1073
+
1074
+ CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
1075
+ ON session_agent_map(agent_id);
1076
+ `);
1077
+ try {
1078
+ const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
1079
+ if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
1080
+ await client.execute({
1081
+ sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
1082
+ SELECT session_id, agent_id, '', MIN(timestamp)
1083
+ FROM memories
1084
+ WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
1085
+ GROUP BY session_id, agent_id`,
1086
+ args: []
1087
+ });
1088
+ }
1089
+ } catch {
1090
+ }
1029
1091
  try {
1030
1092
  await client.execute({
1031
1093
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
@@ -1159,8 +1221,30 @@ async function ensureSchema() {
1159
1221
  });
1160
1222
  } catch {
1161
1223
  }
1224
+ for (const col of [
1225
+ "ALTER TABLE memories ADD COLUMN intent TEXT",
1226
+ "ALTER TABLE memories ADD COLUMN outcome TEXT",
1227
+ "ALTER TABLE memories ADD COLUMN domain TEXT",
1228
+ "ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
1229
+ "ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
1230
+ "ALTER TABLE memories ADD COLUMN chain_position TEXT",
1231
+ "ALTER TABLE memories ADD COLUMN review_status TEXT",
1232
+ "ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
1233
+ "ALTER TABLE memories ADD COLUMN file_paths TEXT",
1234
+ "ALTER TABLE memories ADD COLUMN commit_hash TEXT",
1235
+ "ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
1236
+ "ALTER TABLE memories ADD COLUMN token_cost REAL",
1237
+ "ALTER TABLE memories ADD COLUMN audience TEXT",
1238
+ "ALTER TABLE memories ADD COLUMN language_type TEXT",
1239
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
1240
+ ]) {
1241
+ try {
1242
+ await client.execute(col);
1243
+ } catch {
1244
+ }
1245
+ }
1162
1246
  }
1163
- var _client, _resilientClient, initTurso;
1247
+ var _client, _resilientClient, _daemonClient, initTurso;
1164
1248
  var init_database = __esm({
1165
1249
  "src/lib/database.ts"() {
1166
1250
  "use strict";
@@ -1168,6 +1252,7 @@ var init_database = __esm({
1168
1252
  init_employees();
1169
1253
  _client = null;
1170
1254
  _resilientClient = null;
1255
+ _daemonClient = null;
1171
1256
  initTurso = initDatabase;
1172
1257
  }
1173
1258
  });
@@ -1816,7 +1901,7 @@ async function listPendingReviews(limit, sessionScope) {
1816
1901
  const result2 = await client.execute({
1817
1902
  sql: `SELECT title, assigned_to, project_name FROM tasks
1818
1903
  WHERE status = 'needs_review'
1819
- AND (session_scope = ? OR session_scope IS NULL)
1904
+ AND session_scope = ?
1820
1905
  ORDER BY priority ASC, created_at DESC LIMIT ?`,
1821
1906
  args: [sessionScope, limit]
1822
1907
  });
@@ -1879,6 +1964,7 @@ var init_tasks_review = __esm({
1879
1964
  });
1880
1965
 
1881
1966
  // src/lib/store.ts
1967
+ import { createHash } from "crypto";
1882
1968
  init_database();
1883
1969
 
1884
1970
  // src/lib/keychain.ts
@@ -1914,12 +2000,20 @@ async function getMasterKey() {
1914
2000
  }
1915
2001
  const keyPath = getKeyPath();
1916
2002
  if (!existsSync3(keyPath)) {
2003
+ process.stderr.write(
2004
+ `[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2005
+ `
2006
+ );
1917
2007
  return null;
1918
2008
  }
1919
2009
  try {
1920
2010
  const content = await readFile3(keyPath, "utf-8");
1921
2011
  return Buffer.from(content.trim(), "base64");
1922
- } catch {
2012
+ } catch (err) {
2013
+ process.stderr.write(
2014
+ `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
2015
+ `
2016
+ );
1923
2017
  return null;
1924
2018
  }
1925
2019
  }
@@ -2009,6 +2103,7 @@ import { realpathSync } from "fs";
2009
2103
  import { fileURLToPath } from "url";
2010
2104
  function isMainModule(importMetaUrl) {
2011
2105
  if (process.argv[1] == null) return false;
2106
+ if (process.argv[1].includes("mcp/server")) return false;
2012
2107
  try {
2013
2108
  const scriptPath = realpathSync(process.argv[1]);
2014
2109
  const modulePath = realpathSync(fileURLToPath(importMetaUrl));