@askexenow/exe-os 0.8.83 → 0.8.86

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 (103) 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 +154 -21
  5. package/dist/bin/cli.js +14678 -12676
  6. package/dist/bin/exe-agent-config.js +242 -0
  7. package/dist/bin/exe-agent.js +100 -91
  8. package/dist/bin/exe-assign.js +1003 -854
  9. package/dist/bin/exe-boot.js +1420 -485
  10. package/dist/bin/exe-call.js +10 -0
  11. package/dist/bin/exe-cloud.js +29 -6
  12. package/dist/bin/exe-dispatch.js +572 -271
  13. package/dist/bin/exe-doctor.js +403 -6
  14. package/dist/bin/exe-export-behaviors.js +175 -72
  15. package/dist/bin/exe-forget.js +102 -3
  16. package/dist/bin/exe-gateway.js +796 -292
  17. package/dist/bin/exe-healthcheck.js +134 -1
  18. package/dist/bin/exe-heartbeat.js +172 -36
  19. package/dist/bin/exe-kill.js +175 -72
  20. package/dist/bin/exe-launch-agent.js +189 -76
  21. package/dist/bin/exe-link.js +927 -82
  22. package/dist/bin/exe-new-employee.js +60 -8
  23. package/dist/bin/exe-pending-messages.js +151 -19
  24. package/dist/bin/exe-pending-notifications.js +97 -2
  25. package/dist/bin/exe-pending-reviews.js +155 -22
  26. package/dist/bin/exe-rename.js +564 -23
  27. package/dist/bin/exe-review.js +231 -73
  28. package/dist/bin/exe-search.js +995 -228
  29. package/dist/bin/exe-session-cleanup.js +4930 -1664
  30. package/dist/bin/exe-settings.js +20 -5
  31. package/dist/bin/exe-start-codex.js +2598 -0
  32. package/dist/bin/exe-start.sh +15 -3
  33. package/dist/bin/exe-status.js +154 -21
  34. package/dist/bin/exe-team.js +97 -2
  35. package/dist/bin/git-sweep.js +1180 -363
  36. package/dist/bin/graph-backfill.js +175 -72
  37. package/dist/bin/graph-export.js +175 -72
  38. package/dist/bin/install.js +60 -7
  39. package/dist/bin/list-providers.js +1 -0
  40. package/dist/bin/scan-tasks.js +1185 -367
  41. package/dist/bin/setup.js +914 -270
  42. package/dist/bin/shard-migrate.js +175 -72
  43. package/dist/bin/update.js +1 -0
  44. package/dist/bin/wiki-sync.js +175 -72
  45. package/dist/gateway/index.js +792 -285
  46. package/dist/hooks/bug-report-worker.js +445 -135
  47. package/dist/hooks/commit-complete.js +1178 -361
  48. package/dist/hooks/error-recall.js +994 -228
  49. package/dist/hooks/ingest-worker.js +1799 -1234
  50. package/dist/hooks/ingest.js +3 -0
  51. package/dist/hooks/instructions-loaded.js +707 -97
  52. package/dist/hooks/notification.js +699 -89
  53. package/dist/hooks/post-compact.js +757 -109
  54. package/dist/hooks/pre-compact.js +1061 -244
  55. package/dist/hooks/pre-tool-use.js +787 -130
  56. package/dist/hooks/prompt-ingest-worker.js +242 -101
  57. package/dist/hooks/prompt-submit.js +1121 -299
  58. package/dist/hooks/response-ingest-worker.js +242 -101
  59. package/dist/hooks/session-end.js +4063 -397
  60. package/dist/hooks/session-start.js +1071 -254
  61. package/dist/hooks/stop.js +768 -120
  62. package/dist/hooks/subagent-stop.js +757 -109
  63. package/dist/hooks/summary-worker.js +1706 -1011
  64. package/dist/index.js +1821 -1098
  65. package/dist/lib/agent-config.js +167 -0
  66. package/dist/lib/cloud-sync.js +932 -88
  67. package/dist/lib/consolidation.js +2 -1
  68. package/dist/lib/database.js +642 -87
  69. package/dist/lib/db-daemon-client.js +503 -0
  70. package/dist/lib/device-registry.js +547 -7
  71. package/dist/lib/embedder.js +14 -28
  72. package/dist/lib/employee-templates.js +84 -74
  73. package/dist/lib/employees.js +9 -0
  74. package/dist/lib/exe-daemon-client.js +16 -29
  75. package/dist/lib/exe-daemon.js +2733 -1575
  76. package/dist/lib/hybrid-search.js +995 -228
  77. package/dist/lib/identity.js +87 -67
  78. package/dist/lib/keychain.js +9 -1
  79. package/dist/lib/messaging.js +103 -40
  80. package/dist/lib/reminders.js +91 -74
  81. package/dist/lib/runtime-table.js +16 -0
  82. package/dist/lib/schedules.js +96 -2
  83. package/dist/lib/session-wrappers.js +22 -0
  84. package/dist/lib/skill-learning.js +103 -85
  85. package/dist/lib/store.js +234 -73
  86. package/dist/lib/tasks.js +348 -134
  87. package/dist/lib/tmux-routing.js +422 -208
  88. package/dist/lib/token-spend.js +273 -0
  89. package/dist/lib/ws-client.js +11 -0
  90. package/dist/mcp/server.js +5742 -696
  91. package/dist/mcp/tools/complete-reminder.js +94 -77
  92. package/dist/mcp/tools/create-reminder.js +94 -77
  93. package/dist/mcp/tools/create-task.js +375 -152
  94. package/dist/mcp/tools/deactivate-behavior.js +95 -77
  95. package/dist/mcp/tools/list-reminders.js +94 -77
  96. package/dist/mcp/tools/list-tasks.js +99 -31
  97. package/dist/mcp/tools/send-message.js +108 -45
  98. package/dist/mcp/tools/update-task.js +162 -77
  99. package/dist/runtime/index.js +1075 -258
  100. package/dist/tui/App.js +1333 -506
  101. package/package.json +6 -1
  102. package/src/commands/exe/agent-config.md +27 -0
  103. package/src/commands/exe/cc-doctor.md +10 -0
@@ -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,15 +1221,41 @@ 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
1247
  async function disposeDatabase() {
1248
+ if (_daemonClient) {
1249
+ _daemonClient.close();
1250
+ _daemonClient = null;
1251
+ }
1164
1252
  if (_client) {
1165
1253
  _client.close();
1166
1254
  _client = null;
1167
1255
  _resilientClient = null;
1168
1256
  }
1169
1257
  }
1170
- var _client, _resilientClient, initTurso, disposeTurso;
1258
+ var _client, _resilientClient, _daemonClient, initTurso, disposeTurso;
1171
1259
  var init_database = __esm({
1172
1260
  "src/lib/database.ts"() {
1173
1261
  "use strict";
@@ -1175,6 +1263,7 @@ var init_database = __esm({
1175
1263
  init_employees();
1176
1264
  _client = null;
1177
1265
  _resilientClient = null;
1266
+ _daemonClient = null;
1178
1267
  initTurso = initDatabase;
1179
1268
  disposeTurso = disposeDatabase;
1180
1269
  }
@@ -1607,6 +1696,7 @@ ${p.content}`).join("\n\n");
1607
1696
  });
1608
1697
 
1609
1698
  // src/lib/store.ts
1699
+ import { createHash } from "crypto";
1610
1700
  init_database();
1611
1701
 
1612
1702
  // src/lib/keychain.ts
@@ -1642,12 +1732,20 @@ async function getMasterKey() {
1642
1732
  }
1643
1733
  const keyPath = getKeyPath();
1644
1734
  if (!existsSync3(keyPath)) {
1735
+ process.stderr.write(
1736
+ `[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
1737
+ `
1738
+ );
1645
1739
  return null;
1646
1740
  }
1647
1741
  try {
1648
1742
  const content = await readFile3(keyPath, "utf-8");
1649
1743
  return Buffer.from(content.trim(), "base64");
1650
- } catch {
1744
+ } catch (err) {
1745
+ process.stderr.write(
1746
+ `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
1747
+ `
1748
+ );
1651
1749
  return null;
1652
1750
  }
1653
1751
  }
@@ -1812,80 +1910,85 @@ async function flushBatch() {
1812
1910
  const draft = row.draft ? 1 : 0;
1813
1911
  const memoryType = row.memory_type ?? "raw";
1814
1912
  const trajectory = row.trajectory ?? null;
1815
- return {
1816
- sql: hasVector ? `INSERT OR IGNORE INTO memories
1817
- (id, agent_id, agent_role, session_id, timestamp,
1913
+ const contentHash = row.content_hash ?? null;
1914
+ const intent = row.intent ?? null;
1915
+ const outcome = row.outcome ?? null;
1916
+ const domain = row.domain ?? null;
1917
+ const referencedEntities = row.referenced_entities ?? null;
1918
+ const retrievalCount = row.retrieval_count ?? 0;
1919
+ const chainPosition = row.chain_position ?? null;
1920
+ const reviewStatus = row.review_status ?? null;
1921
+ const contextWindowPct = row.context_window_pct ?? null;
1922
+ const filePaths = row.file_paths ?? null;
1923
+ const commitHash = row.commit_hash ?? null;
1924
+ const durationMs = row.duration_ms ?? null;
1925
+ const tokenCost = row.token_cost ?? null;
1926
+ const audience = row.audience ?? null;
1927
+ const languageType = row.language_type ?? null;
1928
+ const parentMemoryId = row.parent_memory_id ?? null;
1929
+ const cols = `id, agent_id, agent_role, session_id, timestamp,
1818
1930
  tool_name, project_name,
1819
1931
  has_error, raw_text, vector, version, task_id, importance, status,
1820
1932
  confidence, last_accessed,
1821
1933
  workspace_id, document_id, user_id, char_offset, page_number,
1822
- source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory)
1823
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories
1824
- (id, agent_id, agent_role, session_id, timestamp,
1825
- tool_name, project_name,
1826
- has_error, raw_text, vector, version, task_id, importance, status,
1827
- confidence, last_accessed,
1828
- workspace_id, document_id, user_id, char_offset, page_number,
1829
- source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory)
1830
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
1831
- args: hasVector ? [
1832
- row.id,
1833
- row.agent_id,
1834
- row.agent_role,
1835
- row.session_id,
1836
- row.timestamp,
1837
- row.tool_name,
1838
- row.project_name,
1839
- row.has_error,
1840
- row.raw_text,
1841
- vectorToBlob(row.vector),
1842
- row.version,
1843
- taskId,
1844
- importance,
1845
- status,
1846
- confidence,
1847
- lastAccessed,
1848
- workspaceId,
1849
- documentId,
1850
- userId,
1851
- charOffset,
1852
- pageNumber,
1853
- sourcePath,
1854
- sourceType,
1855
- tier,
1856
- supersedesId,
1857
- draft,
1858
- memoryType,
1859
- trajectory
1860
- ] : [
1861
- row.id,
1862
- row.agent_id,
1863
- row.agent_role,
1864
- row.session_id,
1865
- row.timestamp,
1866
- row.tool_name,
1867
- row.project_name,
1868
- row.has_error,
1869
- row.raw_text,
1870
- row.version,
1871
- taskId,
1872
- importance,
1873
- status,
1874
- confidence,
1875
- lastAccessed,
1876
- workspaceId,
1877
- documentId,
1878
- userId,
1879
- charOffset,
1880
- pageNumber,
1881
- sourcePath,
1882
- sourceType,
1883
- tier,
1884
- supersedesId,
1885
- draft,
1886
- memoryType,
1887
- trajectory
1888
- ]
1934
+ source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
1935
+ intent, outcome, domain, referenced_entities, retrieval_count,
1936
+ chain_position, review_status, context_window_pct, file_paths, commit_hash,
1937
+ duration_ms, token_cost, audience, language_type, parent_memory_id`;
1938
+ const metaArgs = [
1939
+ intent,
1940
+ outcome,
1941
+ domain,
1942
+ referencedEntities,
1943
+ retrievalCount,
1944
+ chainPosition,
1945
+ reviewStatus,
1946
+ contextWindowPct,
1947
+ filePaths,
1948
+ commitHash,
1949
+ durationMs,
1950
+ tokenCost,
1951
+ audience,
1952
+ languageType,
1953
+ parentMemoryId
1954
+ ];
1955
+ const baseArgs = [
1956
+ row.id,
1957
+ row.agent_id,
1958
+ row.agent_role,
1959
+ row.session_id,
1960
+ row.timestamp,
1961
+ row.tool_name,
1962
+ row.project_name,
1963
+ row.has_error,
1964
+ row.raw_text
1965
+ ];
1966
+ const sharedArgs = [
1967
+ row.version,
1968
+ taskId,
1969
+ importance,
1970
+ status,
1971
+ confidence,
1972
+ lastAccessed,
1973
+ workspaceId,
1974
+ documentId,
1975
+ userId,
1976
+ charOffset,
1977
+ pageNumber,
1978
+ sourcePath,
1979
+ sourceType,
1980
+ tier,
1981
+ supersedesId,
1982
+ draft,
1983
+ memoryType,
1984
+ trajectory,
1985
+ contentHash
1986
+ ];
1987
+ return {
1988
+ sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
1989
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
1990
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
1991
+ args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
1889
1992
  };
1890
1993
  };
1891
1994
  const globalClient = getClient();
@@ -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,15 +1221,41 @@ 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
1247
  async function disposeDatabase() {
1248
+ if (_daemonClient) {
1249
+ _daemonClient.close();
1250
+ _daemonClient = null;
1251
+ }
1164
1252
  if (_client) {
1165
1253
  _client.close();
1166
1254
  _client = null;
1167
1255
  _resilientClient = null;
1168
1256
  }
1169
1257
  }
1170
- var _client, _resilientClient, initTurso, disposeTurso;
1258
+ var _client, _resilientClient, _daemonClient, initTurso, disposeTurso;
1171
1259
  var init_database = __esm({
1172
1260
  "src/lib/database.ts"() {
1173
1261
  "use strict";
@@ -1175,6 +1263,7 @@ var init_database = __esm({
1175
1263
  init_employees();
1176
1264
  _client = null;
1177
1265
  _resilientClient = null;
1266
+ _daemonClient = null;
1178
1267
  initTurso = initDatabase;
1179
1268
  disposeTurso = disposeDatabase;
1180
1269
  }
@@ -1611,6 +1700,7 @@ import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as
1611
1700
  import path5 from "path";
1612
1701
 
1613
1702
  // src/lib/store.ts
1703
+ import { createHash } from "crypto";
1614
1704
  init_database();
1615
1705
 
1616
1706
  // src/lib/keychain.ts
@@ -1646,12 +1736,20 @@ async function getMasterKey() {
1646
1736
  }
1647
1737
  const keyPath = getKeyPath();
1648
1738
  if (!existsSync3(keyPath)) {
1739
+ process.stderr.write(
1740
+ `[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
1741
+ `
1742
+ );
1649
1743
  return null;
1650
1744
  }
1651
1745
  try {
1652
1746
  const content = await readFile3(keyPath, "utf-8");
1653
1747
  return Buffer.from(content.trim(), "base64");
1654
- } catch {
1748
+ } catch (err) {
1749
+ process.stderr.write(
1750
+ `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
1751
+ `
1752
+ );
1655
1753
  return null;
1656
1754
  }
1657
1755
  }
@@ -1816,80 +1914,85 @@ async function flushBatch() {
1816
1914
  const draft = row.draft ? 1 : 0;
1817
1915
  const memoryType = row.memory_type ?? "raw";
1818
1916
  const trajectory = row.trajectory ?? null;
1819
- return {
1820
- sql: hasVector ? `INSERT OR IGNORE INTO memories
1821
- (id, agent_id, agent_role, session_id, timestamp,
1822
- tool_name, project_name,
1823
- has_error, raw_text, vector, version, task_id, importance, status,
1824
- confidence, last_accessed,
1825
- workspace_id, document_id, user_id, char_offset, page_number,
1826
- source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory)
1827
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories
1828
- (id, agent_id, agent_role, session_id, timestamp,
1917
+ const contentHash = row.content_hash ?? null;
1918
+ const intent = row.intent ?? null;
1919
+ const outcome = row.outcome ?? null;
1920
+ const domain = row.domain ?? null;
1921
+ const referencedEntities = row.referenced_entities ?? null;
1922
+ const retrievalCount = row.retrieval_count ?? 0;
1923
+ const chainPosition = row.chain_position ?? null;
1924
+ const reviewStatus = row.review_status ?? null;
1925
+ const contextWindowPct = row.context_window_pct ?? null;
1926
+ const filePaths = row.file_paths ?? null;
1927
+ const commitHash = row.commit_hash ?? null;
1928
+ const durationMs = row.duration_ms ?? null;
1929
+ const tokenCost = row.token_cost ?? null;
1930
+ const audience = row.audience ?? null;
1931
+ const languageType = row.language_type ?? null;
1932
+ const parentMemoryId = row.parent_memory_id ?? null;
1933
+ const cols = `id, agent_id, agent_role, session_id, timestamp,
1829
1934
  tool_name, project_name,
1830
1935
  has_error, raw_text, vector, version, task_id, importance, status,
1831
1936
  confidence, last_accessed,
1832
1937
  workspace_id, document_id, user_id, char_offset, page_number,
1833
- source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory)
1834
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
1835
- args: hasVector ? [
1836
- row.id,
1837
- row.agent_id,
1838
- row.agent_role,
1839
- row.session_id,
1840
- row.timestamp,
1841
- row.tool_name,
1842
- row.project_name,
1843
- row.has_error,
1844
- row.raw_text,
1845
- vectorToBlob(row.vector),
1846
- row.version,
1847
- taskId,
1848
- importance,
1849
- status,
1850
- confidence,
1851
- lastAccessed,
1852
- workspaceId,
1853
- documentId,
1854
- userId,
1855
- charOffset,
1856
- pageNumber,
1857
- sourcePath,
1858
- sourceType,
1859
- tier,
1860
- supersedesId,
1861
- draft,
1862
- memoryType,
1863
- trajectory
1864
- ] : [
1865
- row.id,
1866
- row.agent_id,
1867
- row.agent_role,
1868
- row.session_id,
1869
- row.timestamp,
1870
- row.tool_name,
1871
- row.project_name,
1872
- row.has_error,
1873
- row.raw_text,
1874
- row.version,
1875
- taskId,
1876
- importance,
1877
- status,
1878
- confidence,
1879
- lastAccessed,
1880
- workspaceId,
1881
- documentId,
1882
- userId,
1883
- charOffset,
1884
- pageNumber,
1885
- sourcePath,
1886
- sourceType,
1887
- tier,
1888
- supersedesId,
1889
- draft,
1890
- memoryType,
1891
- trajectory
1892
- ]
1938
+ source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
1939
+ intent, outcome, domain, referenced_entities, retrieval_count,
1940
+ chain_position, review_status, context_window_pct, file_paths, commit_hash,
1941
+ duration_ms, token_cost, audience, language_type, parent_memory_id`;
1942
+ const metaArgs = [
1943
+ intent,
1944
+ outcome,
1945
+ domain,
1946
+ referencedEntities,
1947
+ retrievalCount,
1948
+ chainPosition,
1949
+ reviewStatus,
1950
+ contextWindowPct,
1951
+ filePaths,
1952
+ commitHash,
1953
+ durationMs,
1954
+ tokenCost,
1955
+ audience,
1956
+ languageType,
1957
+ parentMemoryId
1958
+ ];
1959
+ const baseArgs = [
1960
+ row.id,
1961
+ row.agent_id,
1962
+ row.agent_role,
1963
+ row.session_id,
1964
+ row.timestamp,
1965
+ row.tool_name,
1966
+ row.project_name,
1967
+ row.has_error,
1968
+ row.raw_text
1969
+ ];
1970
+ const sharedArgs = [
1971
+ row.version,
1972
+ taskId,
1973
+ importance,
1974
+ status,
1975
+ confidence,
1976
+ lastAccessed,
1977
+ workspaceId,
1978
+ documentId,
1979
+ userId,
1980
+ charOffset,
1981
+ pageNumber,
1982
+ sourcePath,
1983
+ sourceType,
1984
+ tier,
1985
+ supersedesId,
1986
+ draft,
1987
+ memoryType,
1988
+ trajectory,
1989
+ contentHash
1990
+ ];
1991
+ return {
1992
+ sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
1993
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
1994
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
1995
+ args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
1893
1996
  };
1894
1997
  };
1895
1998
  const globalClient = getClient();