@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.
- package/dist/bin/backfill-conversations.js +746 -595
- package/dist/bin/backfill-responses.js +745 -594
- package/dist/bin/backfill-vectors.js +312 -226
- package/dist/bin/cleanup-stale-review-tasks.js +154 -21
- package/dist/bin/cli.js +14678 -12676
- package/dist/bin/exe-agent-config.js +242 -0
- package/dist/bin/exe-agent.js +100 -91
- package/dist/bin/exe-assign.js +1003 -854
- package/dist/bin/exe-boot.js +1420 -485
- package/dist/bin/exe-call.js +10 -0
- package/dist/bin/exe-cloud.js +29 -6
- package/dist/bin/exe-dispatch.js +572 -271
- package/dist/bin/exe-doctor.js +403 -6
- package/dist/bin/exe-export-behaviors.js +175 -72
- package/dist/bin/exe-forget.js +102 -3
- package/dist/bin/exe-gateway.js +796 -292
- package/dist/bin/exe-healthcheck.js +134 -1
- package/dist/bin/exe-heartbeat.js +172 -36
- package/dist/bin/exe-kill.js +175 -72
- package/dist/bin/exe-launch-agent.js +189 -76
- package/dist/bin/exe-link.js +927 -82
- package/dist/bin/exe-new-employee.js +60 -8
- package/dist/bin/exe-pending-messages.js +151 -19
- package/dist/bin/exe-pending-notifications.js +97 -2
- package/dist/bin/exe-pending-reviews.js +155 -22
- package/dist/bin/exe-rename.js +564 -23
- package/dist/bin/exe-review.js +231 -73
- package/dist/bin/exe-search.js +995 -228
- package/dist/bin/exe-session-cleanup.js +4930 -1664
- package/dist/bin/exe-settings.js +20 -5
- package/dist/bin/exe-start-codex.js +2598 -0
- package/dist/bin/exe-start.sh +15 -3
- package/dist/bin/exe-status.js +154 -21
- package/dist/bin/exe-team.js +97 -2
- package/dist/bin/git-sweep.js +1180 -363
- package/dist/bin/graph-backfill.js +175 -72
- package/dist/bin/graph-export.js +175 -72
- package/dist/bin/install.js +60 -7
- package/dist/bin/list-providers.js +1 -0
- package/dist/bin/scan-tasks.js +1185 -367
- package/dist/bin/setup.js +914 -270
- package/dist/bin/shard-migrate.js +175 -72
- package/dist/bin/update.js +1 -0
- package/dist/bin/wiki-sync.js +175 -72
- package/dist/gateway/index.js +792 -285
- package/dist/hooks/bug-report-worker.js +445 -135
- package/dist/hooks/commit-complete.js +1178 -361
- package/dist/hooks/error-recall.js +994 -228
- package/dist/hooks/ingest-worker.js +1799 -1234
- package/dist/hooks/ingest.js +3 -0
- package/dist/hooks/instructions-loaded.js +707 -97
- package/dist/hooks/notification.js +699 -89
- package/dist/hooks/post-compact.js +757 -109
- package/dist/hooks/pre-compact.js +1061 -244
- package/dist/hooks/pre-tool-use.js +787 -130
- package/dist/hooks/prompt-ingest-worker.js +242 -101
- package/dist/hooks/prompt-submit.js +1121 -299
- package/dist/hooks/response-ingest-worker.js +242 -101
- package/dist/hooks/session-end.js +4063 -397
- package/dist/hooks/session-start.js +1071 -254
- package/dist/hooks/stop.js +768 -120
- package/dist/hooks/subagent-stop.js +757 -109
- package/dist/hooks/summary-worker.js +1706 -1011
- package/dist/index.js +1821 -1098
- package/dist/lib/agent-config.js +167 -0
- package/dist/lib/cloud-sync.js +932 -88
- package/dist/lib/consolidation.js +2 -1
- package/dist/lib/database.js +642 -87
- package/dist/lib/db-daemon-client.js +503 -0
- package/dist/lib/device-registry.js +547 -7
- package/dist/lib/embedder.js +14 -28
- package/dist/lib/employee-templates.js +84 -74
- package/dist/lib/employees.js +9 -0
- package/dist/lib/exe-daemon-client.js +16 -29
- package/dist/lib/exe-daemon.js +2733 -1575
- package/dist/lib/hybrid-search.js +995 -228
- package/dist/lib/identity.js +87 -67
- package/dist/lib/keychain.js +9 -1
- package/dist/lib/messaging.js +103 -40
- package/dist/lib/reminders.js +91 -74
- package/dist/lib/runtime-table.js +16 -0
- package/dist/lib/schedules.js +96 -2
- package/dist/lib/session-wrappers.js +22 -0
- package/dist/lib/skill-learning.js +103 -85
- package/dist/lib/store.js +234 -73
- package/dist/lib/tasks.js +348 -134
- package/dist/lib/tmux-routing.js +422 -208
- package/dist/lib/token-spend.js +273 -0
- package/dist/lib/ws-client.js +11 -0
- package/dist/mcp/server.js +5742 -696
- package/dist/mcp/tools/complete-reminder.js +94 -77
- package/dist/mcp/tools/create-reminder.js +94 -77
- package/dist/mcp/tools/create-task.js +375 -152
- package/dist/mcp/tools/deactivate-behavior.js +95 -77
- package/dist/mcp/tools/list-reminders.js +94 -77
- package/dist/mcp/tools/list-tasks.js +99 -31
- package/dist/mcp/tools/send-message.js +108 -45
- package/dist/mcp/tools/update-task.js +162 -77
- package/dist/runtime/index.js +1075 -258
- package/dist/tui/App.js +1333 -506
- package/package.json +6 -1
- package/src/commands/exe/agent-config.md +27 -0
- package/src/commands/exe/cc-doctor.md +10 -0
package/dist/lib/database.js
CHANGED
|
@@ -1,3 +1,541 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __esm = (fn, res) => function __init() {
|
|
4
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
|
+
};
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// src/lib/config.ts
|
|
12
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
13
|
+
import { readFileSync, existsSync, renameSync } from "fs";
|
|
14
|
+
import path from "path";
|
|
15
|
+
import os from "os";
|
|
16
|
+
function resolveDataDir() {
|
|
17
|
+
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
18
|
+
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
19
|
+
const newDir = path.join(os.homedir(), ".exe-os");
|
|
20
|
+
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
21
|
+
if (!existsSync(newDir) && existsSync(legacyDir)) {
|
|
22
|
+
try {
|
|
23
|
+
renameSync(legacyDir, newDir);
|
|
24
|
+
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
25
|
+
`);
|
|
26
|
+
} catch {
|
|
27
|
+
return legacyDir;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return newDir;
|
|
31
|
+
}
|
|
32
|
+
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG;
|
|
33
|
+
var init_config = __esm({
|
|
34
|
+
"src/lib/config.ts"() {
|
|
35
|
+
"use strict";
|
|
36
|
+
EXE_AI_DIR = resolveDataDir();
|
|
37
|
+
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
38
|
+
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
39
|
+
CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
|
|
40
|
+
LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
|
|
41
|
+
CURRENT_CONFIG_VERSION = 1;
|
|
42
|
+
DEFAULT_CONFIG = {
|
|
43
|
+
config_version: CURRENT_CONFIG_VERSION,
|
|
44
|
+
dbPath: DB_PATH,
|
|
45
|
+
modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
|
|
46
|
+
embeddingDim: 1024,
|
|
47
|
+
batchSize: 20,
|
|
48
|
+
flushIntervalMs: 1e4,
|
|
49
|
+
autoIngestion: true,
|
|
50
|
+
autoRetrieval: true,
|
|
51
|
+
searchMode: "hybrid",
|
|
52
|
+
hookSearchMode: "hybrid",
|
|
53
|
+
fileGrepEnabled: true,
|
|
54
|
+
splashEffect: true,
|
|
55
|
+
consolidationEnabled: true,
|
|
56
|
+
consolidationIntervalMs: 6 * 60 * 60 * 1e3,
|
|
57
|
+
consolidationModel: "claude-haiku-4-5-20251001",
|
|
58
|
+
consolidationMaxCallsPerRun: 20,
|
|
59
|
+
selfQueryRouter: true,
|
|
60
|
+
selfQueryModel: "claude-haiku-4-5-20251001",
|
|
61
|
+
rerankerEnabled: true,
|
|
62
|
+
scalingRoadmap: {
|
|
63
|
+
rerankerAutoTrigger: {
|
|
64
|
+
enabled: true,
|
|
65
|
+
broadQueryMinCardinality: 5e4,
|
|
66
|
+
fetchTopK: 150,
|
|
67
|
+
returnTopK: 5
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
graphRagEnabled: true,
|
|
71
|
+
wikiEnabled: false,
|
|
72
|
+
wikiUrl: "",
|
|
73
|
+
wikiApiKey: "",
|
|
74
|
+
wikiSyncIntervalMs: 30 * 60 * 1e3,
|
|
75
|
+
wikiWorkspaceMapping: {},
|
|
76
|
+
wikiAutoUpdate: true,
|
|
77
|
+
wikiAutoUpdateThreshold: 0.5,
|
|
78
|
+
wikiAutoUpdateCreateNew: true,
|
|
79
|
+
skillLearning: true,
|
|
80
|
+
skillThreshold: 3,
|
|
81
|
+
skillModel: "claude-haiku-4-5-20251001",
|
|
82
|
+
exeHeartbeat: {
|
|
83
|
+
enabled: true,
|
|
84
|
+
intervalSeconds: 60,
|
|
85
|
+
staleInProgressThresholdHours: 2
|
|
86
|
+
},
|
|
87
|
+
sessionLifecycle: {
|
|
88
|
+
idleKillEnabled: true,
|
|
89
|
+
idleKillTicksRequired: 3,
|
|
90
|
+
idleKillIntercomAckWindowMs: 1e4,
|
|
91
|
+
maxAutoInstances: 10
|
|
92
|
+
},
|
|
93
|
+
autoUpdate: {
|
|
94
|
+
checkOnBoot: true,
|
|
95
|
+
autoInstall: false,
|
|
96
|
+
checkIntervalMs: 24 * 60 * 60 * 1e3
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// src/lib/exe-daemon-client.ts
|
|
103
|
+
import net from "net";
|
|
104
|
+
import { spawn } from "child_process";
|
|
105
|
+
import { randomUUID } from "crypto";
|
|
106
|
+
import { existsSync as existsSync3, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
|
|
107
|
+
import path3 from "path";
|
|
108
|
+
import { fileURLToPath } from "url";
|
|
109
|
+
function handleData(chunk) {
|
|
110
|
+
_buffer += chunk.toString();
|
|
111
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
112
|
+
_buffer = "";
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
let newlineIdx;
|
|
116
|
+
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
117
|
+
const line = _buffer.slice(0, newlineIdx).trim();
|
|
118
|
+
_buffer = _buffer.slice(newlineIdx + 1);
|
|
119
|
+
if (!line) continue;
|
|
120
|
+
try {
|
|
121
|
+
const response = JSON.parse(line);
|
|
122
|
+
const id = response.id;
|
|
123
|
+
if (!id) continue;
|
|
124
|
+
const entry = _pending.get(id);
|
|
125
|
+
if (entry) {
|
|
126
|
+
clearTimeout(entry.timer);
|
|
127
|
+
_pending.delete(id);
|
|
128
|
+
entry.resolve(response);
|
|
129
|
+
}
|
|
130
|
+
} catch {
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function cleanupStaleFiles() {
|
|
135
|
+
if (existsSync3(PID_PATH)) {
|
|
136
|
+
try {
|
|
137
|
+
const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
|
|
138
|
+
if (pid > 0) {
|
|
139
|
+
try {
|
|
140
|
+
process.kill(pid, 0);
|
|
141
|
+
return;
|
|
142
|
+
} catch {
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} catch {
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
unlinkSync2(PID_PATH);
|
|
149
|
+
} catch {
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
unlinkSync2(SOCKET_PATH);
|
|
153
|
+
} catch {
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function findPackageRoot() {
|
|
158
|
+
let dir = path3.dirname(fileURLToPath(import.meta.url));
|
|
159
|
+
const { root } = path3.parse(dir);
|
|
160
|
+
while (dir !== root) {
|
|
161
|
+
if (existsSync3(path3.join(dir, "package.json"))) return dir;
|
|
162
|
+
dir = path3.dirname(dir);
|
|
163
|
+
}
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
function spawnDaemon() {
|
|
167
|
+
const pkgRoot = findPackageRoot();
|
|
168
|
+
if (!pkgRoot) {
|
|
169
|
+
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const daemonPath = path3.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
173
|
+
if (!existsSync3(daemonPath)) {
|
|
174
|
+
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
175
|
+
`);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const resolvedPath = daemonPath;
|
|
179
|
+
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
180
|
+
`);
|
|
181
|
+
const logPath = path3.join(path3.dirname(SOCKET_PATH), "exed.log");
|
|
182
|
+
let stderrFd = "ignore";
|
|
183
|
+
try {
|
|
184
|
+
stderrFd = openSync(logPath, "a");
|
|
185
|
+
} catch {
|
|
186
|
+
}
|
|
187
|
+
const child = spawn(process.execPath, [resolvedPath], {
|
|
188
|
+
detached: true,
|
|
189
|
+
stdio: ["ignore", "ignore", stderrFd],
|
|
190
|
+
env: {
|
|
191
|
+
...process.env,
|
|
192
|
+
TMUX: void 0,
|
|
193
|
+
// Daemon is global — must not inherit session scope
|
|
194
|
+
TMUX_PANE: void 0,
|
|
195
|
+
// Prevents resolveExeSession() from scoping to one session
|
|
196
|
+
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
197
|
+
EXE_DAEMON_PID: PID_PATH
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
child.unref();
|
|
201
|
+
if (typeof stderrFd === "number") {
|
|
202
|
+
try {
|
|
203
|
+
closeSync(stderrFd);
|
|
204
|
+
} catch {
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function acquireSpawnLock() {
|
|
209
|
+
try {
|
|
210
|
+
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
211
|
+
closeSync(fd);
|
|
212
|
+
return true;
|
|
213
|
+
} catch {
|
|
214
|
+
try {
|
|
215
|
+
const stat = statSync(SPAWN_LOCK_PATH);
|
|
216
|
+
if (Date.now() - stat.mtimeMs > SPAWN_LOCK_STALE_MS) {
|
|
217
|
+
try {
|
|
218
|
+
unlinkSync2(SPAWN_LOCK_PATH);
|
|
219
|
+
} catch {
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
223
|
+
closeSync(fd);
|
|
224
|
+
return true;
|
|
225
|
+
} catch {
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
} catch {
|
|
229
|
+
}
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
function releaseSpawnLock() {
|
|
234
|
+
try {
|
|
235
|
+
unlinkSync2(SPAWN_LOCK_PATH);
|
|
236
|
+
} catch {
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function connectToSocket() {
|
|
240
|
+
return new Promise((resolve) => {
|
|
241
|
+
if (_socket && _connected) {
|
|
242
|
+
resolve(true);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const socket = net.createConnection({ path: SOCKET_PATH });
|
|
246
|
+
const connectTimeout = setTimeout(() => {
|
|
247
|
+
socket.destroy();
|
|
248
|
+
resolve(false);
|
|
249
|
+
}, 2e3);
|
|
250
|
+
socket.on("connect", () => {
|
|
251
|
+
clearTimeout(connectTimeout);
|
|
252
|
+
_socket = socket;
|
|
253
|
+
_connected = true;
|
|
254
|
+
_buffer = "";
|
|
255
|
+
socket.on("data", handleData);
|
|
256
|
+
socket.on("close", () => {
|
|
257
|
+
_connected = false;
|
|
258
|
+
_socket = null;
|
|
259
|
+
for (const [id, entry] of _pending) {
|
|
260
|
+
clearTimeout(entry.timer);
|
|
261
|
+
_pending.delete(id);
|
|
262
|
+
entry.resolve({ error: "Connection closed" });
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
socket.on("error", () => {
|
|
266
|
+
_connected = false;
|
|
267
|
+
_socket = null;
|
|
268
|
+
});
|
|
269
|
+
resolve(true);
|
|
270
|
+
});
|
|
271
|
+
socket.on("error", () => {
|
|
272
|
+
clearTimeout(connectTimeout);
|
|
273
|
+
resolve(false);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
async function connectEmbedDaemon() {
|
|
278
|
+
if (_socket && _connected) return true;
|
|
279
|
+
if (await connectToSocket()) return true;
|
|
280
|
+
if (acquireSpawnLock()) {
|
|
281
|
+
try {
|
|
282
|
+
cleanupStaleFiles();
|
|
283
|
+
spawnDaemon();
|
|
284
|
+
} finally {
|
|
285
|
+
releaseSpawnLock();
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const start = Date.now();
|
|
289
|
+
let delay2 = 100;
|
|
290
|
+
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
291
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
292
|
+
if (await connectToSocket()) return true;
|
|
293
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
294
|
+
}
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
298
|
+
return new Promise((resolve) => {
|
|
299
|
+
if (!_socket || !_connected) {
|
|
300
|
+
resolve({ error: "Not connected" });
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const id = randomUUID();
|
|
304
|
+
const timer = setTimeout(() => {
|
|
305
|
+
_pending.delete(id);
|
|
306
|
+
resolve({ error: "Request timeout" });
|
|
307
|
+
}, timeoutMs);
|
|
308
|
+
_pending.set(id, { resolve, timer });
|
|
309
|
+
try {
|
|
310
|
+
_socket.write(JSON.stringify({ id, ...payload }) + "\n");
|
|
311
|
+
} catch {
|
|
312
|
+
clearTimeout(timer);
|
|
313
|
+
_pending.delete(id);
|
|
314
|
+
resolve({ error: "Write failed" });
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
function isClientConnected() {
|
|
319
|
+
return _connected;
|
|
320
|
+
}
|
|
321
|
+
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _pending, MAX_BUFFER;
|
|
322
|
+
var init_exe_daemon_client = __esm({
|
|
323
|
+
"src/lib/exe-daemon-client.ts"() {
|
|
324
|
+
"use strict";
|
|
325
|
+
init_config();
|
|
326
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path3.join(EXE_AI_DIR, "exed.sock");
|
|
327
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path3.join(EXE_AI_DIR, "exed.pid");
|
|
328
|
+
SPAWN_LOCK_PATH = path3.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
329
|
+
SPAWN_LOCK_STALE_MS = 3e4;
|
|
330
|
+
CONNECT_TIMEOUT_MS = 15e3;
|
|
331
|
+
REQUEST_TIMEOUT_MS = 3e4;
|
|
332
|
+
_socket = null;
|
|
333
|
+
_connected = false;
|
|
334
|
+
_buffer = "";
|
|
335
|
+
_pending = /* @__PURE__ */ new Map();
|
|
336
|
+
MAX_BUFFER = 1e7;
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// src/lib/daemon-protocol.ts
|
|
341
|
+
function serializeValue(v) {
|
|
342
|
+
if (v === null || v === void 0) return null;
|
|
343
|
+
if (typeof v === "bigint") return Number(v);
|
|
344
|
+
if (typeof v === "boolean") return v ? 1 : 0;
|
|
345
|
+
if (v instanceof Uint8Array) {
|
|
346
|
+
return { __blob: Buffer.from(v).toString("base64") };
|
|
347
|
+
}
|
|
348
|
+
if (ArrayBuffer.isView(v)) {
|
|
349
|
+
return { __blob: Buffer.from(v.buffer, v.byteOffset, v.byteLength).toString("base64") };
|
|
350
|
+
}
|
|
351
|
+
if (v instanceof ArrayBuffer) {
|
|
352
|
+
return { __blob: Buffer.from(v).toString("base64") };
|
|
353
|
+
}
|
|
354
|
+
if (typeof v === "string" || typeof v === "number") return v;
|
|
355
|
+
return String(v);
|
|
356
|
+
}
|
|
357
|
+
function deserializeValue(v) {
|
|
358
|
+
if (v === null) return null;
|
|
359
|
+
if (typeof v === "object" && v !== null && "__blob" in v) {
|
|
360
|
+
const buf = Buffer.from(v.__blob, "base64");
|
|
361
|
+
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
362
|
+
}
|
|
363
|
+
return v;
|
|
364
|
+
}
|
|
365
|
+
function deserializeResultSet(srs) {
|
|
366
|
+
const rows = srs.rows.map((obj) => {
|
|
367
|
+
const values = srs.columns.map(
|
|
368
|
+
(col) => deserializeValue(obj[col] ?? null)
|
|
369
|
+
);
|
|
370
|
+
const row = values;
|
|
371
|
+
for (let i = 0; i < srs.columns.length; i++) {
|
|
372
|
+
const col = srs.columns[i];
|
|
373
|
+
if (col !== void 0) {
|
|
374
|
+
row[col] = values[i] ?? null;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
Object.defineProperty(row, "length", {
|
|
378
|
+
value: values.length,
|
|
379
|
+
enumerable: false
|
|
380
|
+
});
|
|
381
|
+
return row;
|
|
382
|
+
});
|
|
383
|
+
return {
|
|
384
|
+
columns: srs.columns,
|
|
385
|
+
columnTypes: srs.columnTypes ?? [],
|
|
386
|
+
rows,
|
|
387
|
+
rowsAffected: srs.rowsAffected,
|
|
388
|
+
lastInsertRowid: srs.lastInsertRowid != null ? BigInt(srs.lastInsertRowid) : void 0,
|
|
389
|
+
toJSON: () => ({
|
|
390
|
+
columns: srs.columns,
|
|
391
|
+
columnTypes: srs.columnTypes ?? [],
|
|
392
|
+
rows: srs.rows,
|
|
393
|
+
rowsAffected: srs.rowsAffected,
|
|
394
|
+
lastInsertRowid: srs.lastInsertRowid
|
|
395
|
+
})
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
var init_daemon_protocol = __esm({
|
|
399
|
+
"src/lib/daemon-protocol.ts"() {
|
|
400
|
+
"use strict";
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
// src/lib/db-daemon-client.ts
|
|
405
|
+
var db_daemon_client_exports = {};
|
|
406
|
+
__export(db_daemon_client_exports, {
|
|
407
|
+
createDaemonDbClient: () => createDaemonDbClient,
|
|
408
|
+
initDaemonDbClient: () => initDaemonDbClient
|
|
409
|
+
});
|
|
410
|
+
function normalizeStatement(stmt) {
|
|
411
|
+
if (typeof stmt === "string") {
|
|
412
|
+
return { sql: stmt, args: [] };
|
|
413
|
+
}
|
|
414
|
+
const sql = stmt.sql;
|
|
415
|
+
let args = [];
|
|
416
|
+
if (Array.isArray(stmt.args)) {
|
|
417
|
+
args = stmt.args.map((v) => serializeValue(v));
|
|
418
|
+
} else if (stmt.args && typeof stmt.args === "object") {
|
|
419
|
+
const named = {};
|
|
420
|
+
for (const [key, val] of Object.entries(stmt.args)) {
|
|
421
|
+
named[key] = serializeValue(val);
|
|
422
|
+
}
|
|
423
|
+
return { sql, args: named };
|
|
424
|
+
}
|
|
425
|
+
return { sql, args };
|
|
426
|
+
}
|
|
427
|
+
function createDaemonDbClient(fallbackClient) {
|
|
428
|
+
let _useDaemon = false;
|
|
429
|
+
const client = {
|
|
430
|
+
async execute(stmt) {
|
|
431
|
+
if (!_useDaemon || !isClientConnected()) {
|
|
432
|
+
return fallbackClient.execute(stmt);
|
|
433
|
+
}
|
|
434
|
+
const { sql, args } = normalizeStatement(stmt);
|
|
435
|
+
const response = await sendDaemonRequest({
|
|
436
|
+
type: "db-execute",
|
|
437
|
+
sql,
|
|
438
|
+
args
|
|
439
|
+
});
|
|
440
|
+
if (response.error) {
|
|
441
|
+
const errMsg = String(response.error);
|
|
442
|
+
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
|
|
443
|
+
process.stderr.write(`[db-daemon] Transport error (${errMsg}), falling back to direct
|
|
444
|
+
`);
|
|
445
|
+
return fallbackClient.execute(stmt);
|
|
446
|
+
}
|
|
447
|
+
throw new Error(errMsg);
|
|
448
|
+
}
|
|
449
|
+
if (response.db) {
|
|
450
|
+
return deserializeResultSet(response.db);
|
|
451
|
+
}
|
|
452
|
+
process.stderr.write("[db-daemon] Unexpected response shape, falling back to direct\n");
|
|
453
|
+
return fallbackClient.execute(stmt);
|
|
454
|
+
},
|
|
455
|
+
async batch(stmts, mode) {
|
|
456
|
+
if (!_useDaemon || !isClientConnected()) {
|
|
457
|
+
return fallbackClient.batch(stmts, mode);
|
|
458
|
+
}
|
|
459
|
+
const statements = stmts.map(normalizeStatement);
|
|
460
|
+
const response = await sendDaemonRequest({
|
|
461
|
+
type: "db-batch",
|
|
462
|
+
statements,
|
|
463
|
+
mode: mode ?? "deferred"
|
|
464
|
+
});
|
|
465
|
+
if (response.error) {
|
|
466
|
+
const errMsg = String(response.error);
|
|
467
|
+
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
|
|
468
|
+
process.stderr.write(`[db-daemon] Batch transport error (${errMsg}), falling back to direct
|
|
469
|
+
`);
|
|
470
|
+
return fallbackClient.batch(stmts, mode);
|
|
471
|
+
}
|
|
472
|
+
throw new Error(errMsg);
|
|
473
|
+
}
|
|
474
|
+
const batchResults = response["db-batch"];
|
|
475
|
+
if (batchResults) {
|
|
476
|
+
return batchResults.map(deserializeResultSet);
|
|
477
|
+
}
|
|
478
|
+
process.stderr.write("[db-daemon] Unexpected batch response shape, falling back to direct\n");
|
|
479
|
+
return fallbackClient.batch(stmts, mode);
|
|
480
|
+
},
|
|
481
|
+
// Transaction support — delegate to fallback (transactions need direct connection)
|
|
482
|
+
async transaction(mode) {
|
|
483
|
+
return fallbackClient.transaction(mode);
|
|
484
|
+
},
|
|
485
|
+
// executeMultiple — delegate to fallback (used only for schema migrations)
|
|
486
|
+
async executeMultiple(sql) {
|
|
487
|
+
return fallbackClient.executeMultiple(sql);
|
|
488
|
+
},
|
|
489
|
+
// migrate — delegate to fallback
|
|
490
|
+
async migrate(stmts) {
|
|
491
|
+
return fallbackClient.migrate(stmts);
|
|
492
|
+
},
|
|
493
|
+
// Sync mode — delegate to fallback
|
|
494
|
+
sync() {
|
|
495
|
+
return fallbackClient.sync();
|
|
496
|
+
},
|
|
497
|
+
close() {
|
|
498
|
+
_useDaemon = false;
|
|
499
|
+
},
|
|
500
|
+
get closed() {
|
|
501
|
+
return fallbackClient.closed;
|
|
502
|
+
},
|
|
503
|
+
get protocol() {
|
|
504
|
+
return fallbackClient.protocol;
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
return {
|
|
508
|
+
...client,
|
|
509
|
+
/** Enable daemon routing (call after confirming daemon is connected) */
|
|
510
|
+
_enableDaemon() {
|
|
511
|
+
_useDaemon = true;
|
|
512
|
+
},
|
|
513
|
+
/** Check if daemon routing is active */
|
|
514
|
+
_isDaemonActive() {
|
|
515
|
+
return _useDaemon && isClientConnected();
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
async function initDaemonDbClient(fallbackClient) {
|
|
520
|
+
if (process.env.EXE_IS_DAEMON === "1") return null;
|
|
521
|
+
const connected = await connectEmbedDaemon();
|
|
522
|
+
if (!connected) {
|
|
523
|
+
process.stderr.write("[db-daemon] Daemon unavailable \u2014 using direct SQLite\n");
|
|
524
|
+
return null;
|
|
525
|
+
}
|
|
526
|
+
const client = createDaemonDbClient(fallbackClient);
|
|
527
|
+
client._enableDaemon();
|
|
528
|
+
process.stderr.write("[db-daemon] DB routing through daemon (single-writer)\n");
|
|
529
|
+
return client;
|
|
530
|
+
}
|
|
531
|
+
var init_db_daemon_client = __esm({
|
|
532
|
+
"src/lib/db-daemon-client.ts"() {
|
|
533
|
+
"use strict";
|
|
534
|
+
init_exe_daemon_client();
|
|
535
|
+
init_daemon_protocol();
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
|
|
1
539
|
// src/lib/database.ts
|
|
2
540
|
import { createClient } from "@libsql/client";
|
|
3
541
|
|
|
@@ -51,98 +589,12 @@ function wrapWithRetry(client) {
|
|
|
51
589
|
}
|
|
52
590
|
|
|
53
591
|
// src/lib/employees.ts
|
|
592
|
+
init_config();
|
|
54
593
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
55
594
|
import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
56
595
|
import { execSync } from "child_process";
|
|
57
596
|
import path2 from "path";
|
|
58
597
|
import os2 from "os";
|
|
59
|
-
|
|
60
|
-
// src/lib/config.ts
|
|
61
|
-
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
62
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
63
|
-
import path from "path";
|
|
64
|
-
import os from "os";
|
|
65
|
-
function resolveDataDir() {
|
|
66
|
-
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
67
|
-
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
68
|
-
const newDir = path.join(os.homedir(), ".exe-os");
|
|
69
|
-
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
70
|
-
if (!existsSync(newDir) && existsSync(legacyDir)) {
|
|
71
|
-
try {
|
|
72
|
-
renameSync(legacyDir, newDir);
|
|
73
|
-
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
74
|
-
`);
|
|
75
|
-
} catch {
|
|
76
|
-
return legacyDir;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return newDir;
|
|
80
|
-
}
|
|
81
|
-
var EXE_AI_DIR = resolveDataDir();
|
|
82
|
-
var DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
83
|
-
var MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
84
|
-
var CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
|
|
85
|
-
var LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
|
|
86
|
-
var CURRENT_CONFIG_VERSION = 1;
|
|
87
|
-
var DEFAULT_CONFIG = {
|
|
88
|
-
config_version: CURRENT_CONFIG_VERSION,
|
|
89
|
-
dbPath: DB_PATH,
|
|
90
|
-
modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
|
|
91
|
-
embeddingDim: 1024,
|
|
92
|
-
batchSize: 20,
|
|
93
|
-
flushIntervalMs: 1e4,
|
|
94
|
-
autoIngestion: true,
|
|
95
|
-
autoRetrieval: true,
|
|
96
|
-
searchMode: "hybrid",
|
|
97
|
-
hookSearchMode: "hybrid",
|
|
98
|
-
fileGrepEnabled: true,
|
|
99
|
-
splashEffect: true,
|
|
100
|
-
consolidationEnabled: true,
|
|
101
|
-
consolidationIntervalMs: 6 * 60 * 60 * 1e3,
|
|
102
|
-
consolidationModel: "claude-haiku-4-5-20251001",
|
|
103
|
-
consolidationMaxCallsPerRun: 20,
|
|
104
|
-
selfQueryRouter: true,
|
|
105
|
-
selfQueryModel: "claude-haiku-4-5-20251001",
|
|
106
|
-
rerankerEnabled: true,
|
|
107
|
-
scalingRoadmap: {
|
|
108
|
-
rerankerAutoTrigger: {
|
|
109
|
-
enabled: true,
|
|
110
|
-
broadQueryMinCardinality: 5e4,
|
|
111
|
-
fetchTopK: 150,
|
|
112
|
-
returnTopK: 5
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
graphRagEnabled: true,
|
|
116
|
-
wikiEnabled: false,
|
|
117
|
-
wikiUrl: "",
|
|
118
|
-
wikiApiKey: "",
|
|
119
|
-
wikiSyncIntervalMs: 30 * 60 * 1e3,
|
|
120
|
-
wikiWorkspaceMapping: {},
|
|
121
|
-
wikiAutoUpdate: true,
|
|
122
|
-
wikiAutoUpdateThreshold: 0.5,
|
|
123
|
-
wikiAutoUpdateCreateNew: true,
|
|
124
|
-
skillLearning: true,
|
|
125
|
-
skillThreshold: 3,
|
|
126
|
-
skillModel: "claude-haiku-4-5-20251001",
|
|
127
|
-
exeHeartbeat: {
|
|
128
|
-
enabled: true,
|
|
129
|
-
intervalSeconds: 60,
|
|
130
|
-
staleInProgressThresholdHours: 2
|
|
131
|
-
},
|
|
132
|
-
sessionLifecycle: {
|
|
133
|
-
idleKillEnabled: true,
|
|
134
|
-
idleKillTicksRequired: 3,
|
|
135
|
-
idleKillIntercomAckWindowMs: 1e4,
|
|
136
|
-
maxAutoInstances: 10
|
|
137
|
-
},
|
|
138
|
-
autoUpdate: {
|
|
139
|
-
checkOnBoot: true,
|
|
140
|
-
autoInstall: false,
|
|
141
|
-
checkIntervalMs: 24 * 60 * 60 * 1e3
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
// src/lib/employees.ts
|
|
146
598
|
var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
147
599
|
var DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
148
600
|
var COORDINATOR_ROLE = "COO";
|
|
@@ -170,6 +622,7 @@ function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
|
170
622
|
// src/lib/database.ts
|
|
171
623
|
var _client = null;
|
|
172
624
|
var _resilientClient = null;
|
|
625
|
+
var _daemonClient = null;
|
|
173
626
|
var initTurso = initDatabase;
|
|
174
627
|
async function initDatabase(config) {
|
|
175
628
|
if (_client) {
|
|
@@ -193,8 +646,27 @@ function getClient() {
|
|
|
193
646
|
if (!_resilientClient) {
|
|
194
647
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
195
648
|
}
|
|
649
|
+
if (process.env.EXE_IS_DAEMON === "1") {
|
|
650
|
+
return _resilientClient;
|
|
651
|
+
}
|
|
652
|
+
if (_daemonClient && _daemonClient._isDaemonActive()) {
|
|
653
|
+
return _daemonClient;
|
|
654
|
+
}
|
|
196
655
|
return _resilientClient;
|
|
197
656
|
}
|
|
657
|
+
async function initDaemonClient() {
|
|
658
|
+
if (process.env.EXE_IS_DAEMON === "1") return;
|
|
659
|
+
if (!_resilientClient) return;
|
|
660
|
+
try {
|
|
661
|
+
const { initDaemonDbClient: initDaemonDbClient2 } = await Promise.resolve().then(() => (init_db_daemon_client(), db_daemon_client_exports));
|
|
662
|
+
_daemonClient = await initDaemonDbClient2(_resilientClient);
|
|
663
|
+
} catch (err) {
|
|
664
|
+
process.stderr.write(
|
|
665
|
+
`[database] Daemon client init failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
|
|
666
|
+
`
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
198
670
|
function getRawClient() {
|
|
199
671
|
if (!_client) {
|
|
200
672
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
@@ -681,6 +1153,12 @@ async function ensureSchema() {
|
|
|
681
1153
|
} catch {
|
|
682
1154
|
}
|
|
683
1155
|
}
|
|
1156
|
+
try {
|
|
1157
|
+
await client.execute(
|
|
1158
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
|
|
1159
|
+
);
|
|
1160
|
+
} catch {
|
|
1161
|
+
}
|
|
684
1162
|
await client.executeMultiple(`
|
|
685
1163
|
CREATE TABLE IF NOT EXISTS entities (
|
|
686
1164
|
id TEXT PRIMARY KEY,
|
|
@@ -733,7 +1211,30 @@ async function ensureSchema() {
|
|
|
733
1211
|
entity_id TEXT NOT NULL,
|
|
734
1212
|
PRIMARY KEY (hyperedge_id, entity_id)
|
|
735
1213
|
);
|
|
1214
|
+
|
|
1215
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
|
|
1216
|
+
name,
|
|
1217
|
+
content=entities,
|
|
1218
|
+
content_rowid=rowid
|
|
1219
|
+
);
|
|
1220
|
+
|
|
1221
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
|
|
1222
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
1223
|
+
END;
|
|
1224
|
+
|
|
1225
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
|
|
1226
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
1227
|
+
END;
|
|
1228
|
+
|
|
1229
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
|
|
1230
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
1231
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
1232
|
+
END;
|
|
736
1233
|
`);
|
|
1234
|
+
try {
|
|
1235
|
+
await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
|
|
1236
|
+
} catch {
|
|
1237
|
+
}
|
|
737
1238
|
await client.executeMultiple(`
|
|
738
1239
|
CREATE TABLE IF NOT EXISTS entity_aliases (
|
|
739
1240
|
alias TEXT NOT NULL PRIMARY KEY,
|
|
@@ -914,6 +1415,33 @@ async function ensureSchema() {
|
|
|
914
1415
|
CREATE INDEX IF NOT EXISTS idx_conversations_channel
|
|
915
1416
|
ON conversations(channel_id);
|
|
916
1417
|
`);
|
|
1418
|
+
await client.executeMultiple(`
|
|
1419
|
+
CREATE TABLE IF NOT EXISTS session_agent_map (
|
|
1420
|
+
session_uuid TEXT PRIMARY KEY,
|
|
1421
|
+
agent_id TEXT NOT NULL,
|
|
1422
|
+
session_name TEXT,
|
|
1423
|
+
task_id TEXT,
|
|
1424
|
+
project_name TEXT,
|
|
1425
|
+
started_at TEXT NOT NULL
|
|
1426
|
+
);
|
|
1427
|
+
|
|
1428
|
+
CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
|
|
1429
|
+
ON session_agent_map(agent_id);
|
|
1430
|
+
`);
|
|
1431
|
+
try {
|
|
1432
|
+
const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
|
|
1433
|
+
if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
|
|
1434
|
+
await client.execute({
|
|
1435
|
+
sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
|
|
1436
|
+
SELECT session_id, agent_id, '', MIN(timestamp)
|
|
1437
|
+
FROM memories
|
|
1438
|
+
WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
|
|
1439
|
+
GROUP BY session_id, agent_id`,
|
|
1440
|
+
args: []
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
} catch {
|
|
1444
|
+
}
|
|
917
1445
|
try {
|
|
918
1446
|
await client.execute({
|
|
919
1447
|
sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
|
|
@@ -1047,9 +1575,35 @@ async function ensureSchema() {
|
|
|
1047
1575
|
});
|
|
1048
1576
|
} catch {
|
|
1049
1577
|
}
|
|
1578
|
+
for (const col of [
|
|
1579
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
1580
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
1581
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
1582
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
1583
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
1584
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
1585
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
1586
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
1587
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
1588
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
1589
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
1590
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
1591
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
1592
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
1593
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
1594
|
+
]) {
|
|
1595
|
+
try {
|
|
1596
|
+
await client.execute(col);
|
|
1597
|
+
} catch {
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1050
1600
|
}
|
|
1051
1601
|
var disposeTurso = disposeDatabase;
|
|
1052
1602
|
async function disposeDatabase() {
|
|
1603
|
+
if (_daemonClient) {
|
|
1604
|
+
_daemonClient.close();
|
|
1605
|
+
_daemonClient = null;
|
|
1606
|
+
}
|
|
1053
1607
|
if (_client) {
|
|
1054
1608
|
_client.close();
|
|
1055
1609
|
_client = null;
|
|
@@ -1062,6 +1616,7 @@ export {
|
|
|
1062
1616
|
ensureSchema,
|
|
1063
1617
|
getClient,
|
|
1064
1618
|
getRawClient,
|
|
1619
|
+
initDaemonClient,
|
|
1065
1620
|
initDatabase,
|
|
1066
1621
|
initTurso,
|
|
1067
1622
|
isInitialized
|