@askexenow/exe-os 0.8.83 → 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 (95) 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 +14350 -12518
  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 +1257 -320
  9. package/dist/bin/exe-call.js +10 -0
  10. package/dist/bin/exe-cloud.js +29 -6
  11. package/dist/bin/exe-dispatch.js +210 -34
  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 +550 -171
  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 +38 -8
  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 +564 -23
  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 +899 -207
  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 +904 -211
  38. package/dist/bin/setup.js +867 -268
  39. package/dist/bin/shard-migrate.js +175 -72
  40. package/dist/bin/update.js +1 -0
  41. package/dist/bin/wiki-sync.js +175 -72
  42. package/dist/gateway/index.js +548 -166
  43. package/dist/hooks/bug-report-worker.js +208 -23
  44. package/dist/hooks/commit-complete.js +897 -205
  45. package/dist/hooks/error-recall.js +988 -226
  46. package/dist/hooks/ingest-worker.js +1638 -1194
  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 +897 -205
  52. package/dist/hooks/pre-tool-use.js +742 -123
  53. package/dist/hooks/prompt-ingest-worker.js +242 -101
  54. package/dist/hooks/prompt-submit.js +995 -233
  55. package/dist/hooks/response-ingest-worker.js +242 -101
  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 +1964 -1330
  61. package/dist/index.js +1651 -1053
  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 +1955 -922
  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/messaging.js +8 -1
  76. package/dist/lib/reminders.js +91 -74
  77. package/dist/lib/schedules.js +96 -2
  78. package/dist/lib/skill-learning.js +103 -85
  79. package/dist/lib/store.js +234 -73
  80. package/dist/lib/tasks.js +111 -22
  81. package/dist/lib/tmux-routing.js +120 -31
  82. package/dist/lib/token-spend.js +273 -0
  83. package/dist/lib/ws-client.js +11 -0
  84. package/dist/mcp/server.js +5222 -475
  85. package/dist/mcp/tools/complete-reminder.js +94 -77
  86. package/dist/mcp/tools/create-reminder.js +94 -77
  87. package/dist/mcp/tools/create-task.js +120 -22
  88. package/dist/mcp/tools/deactivate-behavior.js +95 -77
  89. package/dist/mcp/tools/list-reminders.js +94 -77
  90. package/dist/mcp/tools/list-tasks.js +31 -1
  91. package/dist/mcp/tools/send-message.js +8 -1
  92. package/dist/mcp/tools/update-task.js +39 -10
  93. package/dist/runtime/index.js +911 -219
  94. package/dist/tui/App.js +997 -295
  95. package/package.json +6 -1
@@ -1,8 +1,7 @@
1
- // src/lib/identity.ts
2
- import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
3
- import { readdirSync } from "fs";
4
- import path3 from "path";
5
- import { createHash } from "crypto";
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __esm = (fn, res) => function __init() {
3
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ };
6
5
 
7
6
  // src/lib/config.ts
8
7
  import { readFile, writeFile, mkdir, chmod } from "fs/promises";
@@ -25,74 +24,88 @@ function resolveDataDir() {
25
24
  }
26
25
  return newDir;
27
26
  }
28
- var EXE_AI_DIR = resolveDataDir();
29
- var DB_PATH = path.join(EXE_AI_DIR, "memories.db");
30
- var MODELS_DIR = path.join(EXE_AI_DIR, "models");
31
- var CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
32
- var LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
33
- var CURRENT_CONFIG_VERSION = 1;
34
- var DEFAULT_CONFIG = {
35
- config_version: CURRENT_CONFIG_VERSION,
36
- dbPath: DB_PATH,
37
- modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
38
- embeddingDim: 1024,
39
- batchSize: 20,
40
- flushIntervalMs: 1e4,
41
- autoIngestion: true,
42
- autoRetrieval: true,
43
- searchMode: "hybrid",
44
- hookSearchMode: "hybrid",
45
- fileGrepEnabled: true,
46
- splashEffect: true,
47
- consolidationEnabled: true,
48
- consolidationIntervalMs: 6 * 60 * 60 * 1e3,
49
- consolidationModel: "claude-haiku-4-5-20251001",
50
- consolidationMaxCallsPerRun: 20,
51
- selfQueryRouter: true,
52
- selfQueryModel: "claude-haiku-4-5-20251001",
53
- rerankerEnabled: true,
54
- scalingRoadmap: {
55
- rerankerAutoTrigger: {
56
- enabled: true,
57
- broadQueryMinCardinality: 5e4,
58
- fetchTopK: 150,
59
- returnTopK: 5
60
- }
61
- },
62
- graphRagEnabled: true,
63
- wikiEnabled: false,
64
- wikiUrl: "",
65
- wikiApiKey: "",
66
- wikiSyncIntervalMs: 30 * 60 * 1e3,
67
- wikiWorkspaceMapping: {},
68
- wikiAutoUpdate: true,
69
- wikiAutoUpdateThreshold: 0.5,
70
- wikiAutoUpdateCreateNew: true,
71
- skillLearning: true,
72
- skillThreshold: 3,
73
- skillModel: "claude-haiku-4-5-20251001",
74
- exeHeartbeat: {
75
- enabled: true,
76
- intervalSeconds: 60,
77
- staleInProgressThresholdHours: 2
78
- },
79
- sessionLifecycle: {
80
- idleKillEnabled: true,
81
- idleKillTicksRequired: 3,
82
- idleKillIntercomAckWindowMs: 1e4,
83
- maxAutoInstances: 10
84
- },
85
- autoUpdate: {
86
- checkOnBoot: true,
87
- autoInstall: false,
88
- checkIntervalMs: 24 * 60 * 60 * 1e3
27
+ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG;
28
+ var init_config = __esm({
29
+ "src/lib/config.ts"() {
30
+ "use strict";
31
+ EXE_AI_DIR = resolveDataDir();
32
+ DB_PATH = path.join(EXE_AI_DIR, "memories.db");
33
+ MODELS_DIR = path.join(EXE_AI_DIR, "models");
34
+ CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
35
+ LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
36
+ CURRENT_CONFIG_VERSION = 1;
37
+ DEFAULT_CONFIG = {
38
+ config_version: CURRENT_CONFIG_VERSION,
39
+ dbPath: DB_PATH,
40
+ modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
41
+ embeddingDim: 1024,
42
+ batchSize: 20,
43
+ flushIntervalMs: 1e4,
44
+ autoIngestion: true,
45
+ autoRetrieval: true,
46
+ searchMode: "hybrid",
47
+ hookSearchMode: "hybrid",
48
+ fileGrepEnabled: true,
49
+ splashEffect: true,
50
+ consolidationEnabled: true,
51
+ consolidationIntervalMs: 6 * 60 * 60 * 1e3,
52
+ consolidationModel: "claude-haiku-4-5-20251001",
53
+ consolidationMaxCallsPerRun: 20,
54
+ selfQueryRouter: true,
55
+ selfQueryModel: "claude-haiku-4-5-20251001",
56
+ rerankerEnabled: true,
57
+ scalingRoadmap: {
58
+ rerankerAutoTrigger: {
59
+ enabled: true,
60
+ broadQueryMinCardinality: 5e4,
61
+ fetchTopK: 150,
62
+ returnTopK: 5
63
+ }
64
+ },
65
+ graphRagEnabled: true,
66
+ wikiEnabled: false,
67
+ wikiUrl: "",
68
+ wikiApiKey: "",
69
+ wikiSyncIntervalMs: 30 * 60 * 1e3,
70
+ wikiWorkspaceMapping: {},
71
+ wikiAutoUpdate: true,
72
+ wikiAutoUpdateThreshold: 0.5,
73
+ wikiAutoUpdateCreateNew: true,
74
+ skillLearning: true,
75
+ skillThreshold: 3,
76
+ skillModel: "claude-haiku-4-5-20251001",
77
+ exeHeartbeat: {
78
+ enabled: true,
79
+ intervalSeconds: 60,
80
+ staleInProgressThresholdHours: 2
81
+ },
82
+ sessionLifecycle: {
83
+ idleKillEnabled: true,
84
+ idleKillTicksRequired: 3,
85
+ idleKillIntercomAckWindowMs: 1e4,
86
+ maxAutoInstances: 10
87
+ },
88
+ autoUpdate: {
89
+ checkOnBoot: true,
90
+ autoInstall: false,
91
+ checkIntervalMs: 24 * 60 * 60 * 1e3
92
+ }
93
+ };
89
94
  }
90
- };
95
+ });
96
+
97
+ // src/lib/identity.ts
98
+ init_config();
99
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
100
+ import { readdirSync } from "fs";
101
+ import path3 from "path";
102
+ import { createHash } from "crypto";
91
103
 
92
104
  // src/lib/database.ts
93
105
  import { createClient } from "@libsql/client";
94
106
 
95
107
  // src/lib/employees.ts
108
+ init_config();
96
109
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
97
110
  import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
98
111
  import { execSync } from "child_process";
@@ -102,10 +115,17 @@ var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
102
115
 
103
116
  // src/lib/database.ts
104
117
  var _resilientClient = null;
118
+ var _daemonClient = null;
105
119
  function getClient() {
106
120
  if (!_resilientClient) {
107
121
  throw new Error("Database client not initialized. Call initDatabase() first.");
108
122
  }
123
+ if (process.env.EXE_IS_DAEMON === "1") {
124
+ return _resilientClient;
125
+ }
126
+ if (_daemonClient && _daemonClient._isDaemonActive()) {
127
+ return _daemonClient;
128
+ }
109
129
  return _resilientClient;
110
130
  }
111
131
 
@@ -31,12 +31,20 @@ async function getMasterKey() {
31
31
  }
32
32
  const keyPath = getKeyPath();
33
33
  if (!existsSync(keyPath)) {
34
+ process.stderr.write(
35
+ `[keychain] Key not found at ${keyPath} (HOME=${os.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
36
+ `
37
+ );
34
38
  return null;
35
39
  }
36
40
  try {
37
41
  const content = await readFile(keyPath, "utf-8");
38
42
  return Buffer.from(content.trim(), "base64");
39
- } catch {
43
+ } catch (err) {
44
+ process.stderr.write(
45
+ `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
46
+ `
47
+ );
40
48
  return null;
41
49
  }
42
50
  }
@@ -160,15 +160,22 @@ function getClient() {
160
160
  if (!_resilientClient) {
161
161
  throw new Error("Database client not initialized. Call initDatabase() first.");
162
162
  }
163
+ if (process.env.EXE_IS_DAEMON === "1") {
164
+ return _resilientClient;
165
+ }
166
+ if (_daemonClient && _daemonClient._isDaemonActive()) {
167
+ return _daemonClient;
168
+ }
163
169
  return _resilientClient;
164
170
  }
165
- var _resilientClient;
171
+ var _resilientClient, _daemonClient;
166
172
  var init_database = __esm({
167
173
  "src/lib/database.ts"() {
168
174
  "use strict";
169
175
  init_db_retry();
170
176
  init_employees();
171
177
  _resilientClient = null;
178
+ _daemonClient = null;
172
179
  }
173
180
  });
174
181
 
@@ -1,15 +1,7 @@
1
- // src/lib/reminders.ts
2
- import crypto from "crypto";
3
-
4
- // src/lib/database.ts
5
- import { createClient } from "@libsql/client";
6
-
7
- // src/lib/employees.ts
8
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
9
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
10
- import { execSync } from "child_process";
11
- import path2 from "path";
12
- import os2 from "os";
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __esm = (fn, res) => function __init() {
3
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ };
13
5
 
14
6
  // src/lib/config.ts
15
7
  import { readFile, writeFile, mkdir, chmod } from "fs/promises";
@@ -32,79 +24,104 @@ function resolveDataDir() {
32
24
  }
33
25
  return newDir;
34
26
  }
35
- var EXE_AI_DIR = resolveDataDir();
36
- var DB_PATH = path.join(EXE_AI_DIR, "memories.db");
37
- var MODELS_DIR = path.join(EXE_AI_DIR, "models");
38
- var CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
39
- var LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
40
- var CURRENT_CONFIG_VERSION = 1;
41
- var DEFAULT_CONFIG = {
42
- config_version: CURRENT_CONFIG_VERSION,
43
- dbPath: DB_PATH,
44
- modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
45
- embeddingDim: 1024,
46
- batchSize: 20,
47
- flushIntervalMs: 1e4,
48
- autoIngestion: true,
49
- autoRetrieval: true,
50
- searchMode: "hybrid",
51
- hookSearchMode: "hybrid",
52
- fileGrepEnabled: true,
53
- splashEffect: true,
54
- consolidationEnabled: true,
55
- consolidationIntervalMs: 6 * 60 * 60 * 1e3,
56
- consolidationModel: "claude-haiku-4-5-20251001",
57
- consolidationMaxCallsPerRun: 20,
58
- selfQueryRouter: true,
59
- selfQueryModel: "claude-haiku-4-5-20251001",
60
- rerankerEnabled: true,
61
- scalingRoadmap: {
62
- rerankerAutoTrigger: {
63
- enabled: true,
64
- broadQueryMinCardinality: 5e4,
65
- fetchTopK: 150,
66
- returnTopK: 5
67
- }
68
- },
69
- graphRagEnabled: true,
70
- wikiEnabled: false,
71
- wikiUrl: "",
72
- wikiApiKey: "",
73
- wikiSyncIntervalMs: 30 * 60 * 1e3,
74
- wikiWorkspaceMapping: {},
75
- wikiAutoUpdate: true,
76
- wikiAutoUpdateThreshold: 0.5,
77
- wikiAutoUpdateCreateNew: true,
78
- skillLearning: true,
79
- skillThreshold: 3,
80
- skillModel: "claude-haiku-4-5-20251001",
81
- exeHeartbeat: {
82
- enabled: true,
83
- intervalSeconds: 60,
84
- staleInProgressThresholdHours: 2
85
- },
86
- sessionLifecycle: {
87
- idleKillEnabled: true,
88
- idleKillTicksRequired: 3,
89
- idleKillIntercomAckWindowMs: 1e4,
90
- maxAutoInstances: 10
91
- },
92
- autoUpdate: {
93
- checkOnBoot: true,
94
- autoInstall: false,
95
- checkIntervalMs: 24 * 60 * 60 * 1e3
27
+ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG;
28
+ var init_config = __esm({
29
+ "src/lib/config.ts"() {
30
+ "use strict";
31
+ EXE_AI_DIR = resolveDataDir();
32
+ DB_PATH = path.join(EXE_AI_DIR, "memories.db");
33
+ MODELS_DIR = path.join(EXE_AI_DIR, "models");
34
+ CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
35
+ LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
36
+ CURRENT_CONFIG_VERSION = 1;
37
+ DEFAULT_CONFIG = {
38
+ config_version: CURRENT_CONFIG_VERSION,
39
+ dbPath: DB_PATH,
40
+ modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
41
+ embeddingDim: 1024,
42
+ batchSize: 20,
43
+ flushIntervalMs: 1e4,
44
+ autoIngestion: true,
45
+ autoRetrieval: true,
46
+ searchMode: "hybrid",
47
+ hookSearchMode: "hybrid",
48
+ fileGrepEnabled: true,
49
+ splashEffect: true,
50
+ consolidationEnabled: true,
51
+ consolidationIntervalMs: 6 * 60 * 60 * 1e3,
52
+ consolidationModel: "claude-haiku-4-5-20251001",
53
+ consolidationMaxCallsPerRun: 20,
54
+ selfQueryRouter: true,
55
+ selfQueryModel: "claude-haiku-4-5-20251001",
56
+ rerankerEnabled: true,
57
+ scalingRoadmap: {
58
+ rerankerAutoTrigger: {
59
+ enabled: true,
60
+ broadQueryMinCardinality: 5e4,
61
+ fetchTopK: 150,
62
+ returnTopK: 5
63
+ }
64
+ },
65
+ graphRagEnabled: true,
66
+ wikiEnabled: false,
67
+ wikiUrl: "",
68
+ wikiApiKey: "",
69
+ wikiSyncIntervalMs: 30 * 60 * 1e3,
70
+ wikiWorkspaceMapping: {},
71
+ wikiAutoUpdate: true,
72
+ wikiAutoUpdateThreshold: 0.5,
73
+ wikiAutoUpdateCreateNew: true,
74
+ skillLearning: true,
75
+ skillThreshold: 3,
76
+ skillModel: "claude-haiku-4-5-20251001",
77
+ exeHeartbeat: {
78
+ enabled: true,
79
+ intervalSeconds: 60,
80
+ staleInProgressThresholdHours: 2
81
+ },
82
+ sessionLifecycle: {
83
+ idleKillEnabled: true,
84
+ idleKillTicksRequired: 3,
85
+ idleKillIntercomAckWindowMs: 1e4,
86
+ maxAutoInstances: 10
87
+ },
88
+ autoUpdate: {
89
+ checkOnBoot: true,
90
+ autoInstall: false,
91
+ checkIntervalMs: 24 * 60 * 60 * 1e3
92
+ }
93
+ };
96
94
  }
97
- };
95
+ });
96
+
97
+ // src/lib/reminders.ts
98
+ import crypto from "crypto";
99
+
100
+ // src/lib/database.ts
101
+ import { createClient } from "@libsql/client";
98
102
 
99
103
  // src/lib/employees.ts
104
+ init_config();
105
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
106
+ import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
107
+ import { execSync } from "child_process";
108
+ import path2 from "path";
109
+ import os2 from "os";
100
110
  var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
101
111
 
102
112
  // src/lib/database.ts
103
113
  var _resilientClient = null;
114
+ var _daemonClient = null;
104
115
  function getClient() {
105
116
  if (!_resilientClient) {
106
117
  throw new Error("Database client not initialized. Call initDatabase() first.");
107
118
  }
119
+ if (process.env.EXE_IS_DAEMON === "1") {
120
+ return _resilientClient;
121
+ }
122
+ if (_daemonClient && _daemonClient._isDaemonActive()) {
123
+ return _daemonClient;
124
+ }
108
125
  return _resilientClient;
109
126
  }
110
127
 
@@ -307,6 +307,12 @@ function getClient() {
307
307
  if (!_resilientClient) {
308
308
  throw new Error("Database client not initialized. Call initDatabase() first.");
309
309
  }
310
+ if (process.env.EXE_IS_DAEMON === "1") {
311
+ return _resilientClient;
312
+ }
313
+ if (_daemonClient && _daemonClient._isDaemonActive()) {
314
+ return _daemonClient;
315
+ }
310
316
  return _resilientClient;
311
317
  }
312
318
  function getRawClient() {
@@ -795,6 +801,12 @@ async function ensureSchema() {
795
801
  } catch {
796
802
  }
797
803
  }
804
+ try {
805
+ await client.execute(
806
+ `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
807
+ );
808
+ } catch {
809
+ }
798
810
  await client.executeMultiple(`
799
811
  CREATE TABLE IF NOT EXISTS entities (
800
812
  id TEXT PRIMARY KEY,
@@ -847,7 +859,30 @@ async function ensureSchema() {
847
859
  entity_id TEXT NOT NULL,
848
860
  PRIMARY KEY (hyperedge_id, entity_id)
849
861
  );
862
+
863
+ CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
864
+ name,
865
+ content=entities,
866
+ content_rowid=rowid
867
+ );
868
+
869
+ CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
870
+ INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
871
+ END;
872
+
873
+ CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
874
+ INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
875
+ END;
876
+
877
+ CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
878
+ INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
879
+ INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
880
+ END;
850
881
  `);
882
+ try {
883
+ await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
884
+ } catch {
885
+ }
851
886
  await client.executeMultiple(`
852
887
  CREATE TABLE IF NOT EXISTS entity_aliases (
853
888
  alias TEXT NOT NULL PRIMARY KEY,
@@ -1028,6 +1063,33 @@ async function ensureSchema() {
1028
1063
  CREATE INDEX IF NOT EXISTS idx_conversations_channel
1029
1064
  ON conversations(channel_id);
1030
1065
  `);
1066
+ await client.executeMultiple(`
1067
+ CREATE TABLE IF NOT EXISTS session_agent_map (
1068
+ session_uuid TEXT PRIMARY KEY,
1069
+ agent_id TEXT NOT NULL,
1070
+ session_name TEXT,
1071
+ task_id TEXT,
1072
+ project_name TEXT,
1073
+ started_at TEXT NOT NULL
1074
+ );
1075
+
1076
+ CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
1077
+ ON session_agent_map(agent_id);
1078
+ `);
1079
+ try {
1080
+ const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
1081
+ if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
1082
+ await client.execute({
1083
+ sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
1084
+ SELECT session_id, agent_id, '', MIN(timestamp)
1085
+ FROM memories
1086
+ WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
1087
+ GROUP BY session_id, agent_id`,
1088
+ args: []
1089
+ });
1090
+ }
1091
+ } catch {
1092
+ }
1031
1093
  try {
1032
1094
  await client.execute({
1033
1095
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
@@ -1161,8 +1223,30 @@ async function ensureSchema() {
1161
1223
  });
1162
1224
  } catch {
1163
1225
  }
1226
+ for (const col of [
1227
+ "ALTER TABLE memories ADD COLUMN intent TEXT",
1228
+ "ALTER TABLE memories ADD COLUMN outcome TEXT",
1229
+ "ALTER TABLE memories ADD COLUMN domain TEXT",
1230
+ "ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
1231
+ "ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
1232
+ "ALTER TABLE memories ADD COLUMN chain_position TEXT",
1233
+ "ALTER TABLE memories ADD COLUMN review_status TEXT",
1234
+ "ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
1235
+ "ALTER TABLE memories ADD COLUMN file_paths TEXT",
1236
+ "ALTER TABLE memories ADD COLUMN commit_hash TEXT",
1237
+ "ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
1238
+ "ALTER TABLE memories ADD COLUMN token_cost REAL",
1239
+ "ALTER TABLE memories ADD COLUMN audience TEXT",
1240
+ "ALTER TABLE memories ADD COLUMN language_type TEXT",
1241
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
1242
+ ]) {
1243
+ try {
1244
+ await client.execute(col);
1245
+ } catch {
1246
+ }
1247
+ }
1164
1248
  }
1165
- var _client, _resilientClient, initTurso;
1249
+ var _client, _resilientClient, _daemonClient, initTurso;
1166
1250
  var init_database = __esm({
1167
1251
  "src/lib/database.ts"() {
1168
1252
  "use strict";
@@ -1170,6 +1254,7 @@ var init_database = __esm({
1170
1254
  init_employees();
1171
1255
  _client = null;
1172
1256
  _resilientClient = null;
1257
+ _daemonClient = null;
1173
1258
  initTurso = initDatabase;
1174
1259
  }
1175
1260
  });
@@ -1606,6 +1691,7 @@ import crypto from "crypto";
1606
1691
  import { execSync as execSync2 } from "child_process";
1607
1692
 
1608
1693
  // src/lib/store.ts
1694
+ import { createHash } from "crypto";
1609
1695
  init_database();
1610
1696
 
1611
1697
  // src/lib/keychain.ts
@@ -1641,12 +1727,20 @@ async function getMasterKey() {
1641
1727
  }
1642
1728
  const keyPath = getKeyPath();
1643
1729
  if (!existsSync3(keyPath)) {
1730
+ process.stderr.write(
1731
+ `[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
1732
+ `
1733
+ );
1644
1734
  return null;
1645
1735
  }
1646
1736
  try {
1647
1737
  const content = await readFile3(keyPath, "utf-8");
1648
1738
  return Buffer.from(content.trim(), "base64");
1649
- } catch {
1739
+ } catch (err) {
1740
+ process.stderr.write(
1741
+ `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
1742
+ `
1743
+ );
1650
1744
  return null;
1651
1745
  }
1652
1746
  }