@askexenow/exe-os 0.9.7 → 0.9.8
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 +754 -79
- package/dist/bin/backfill-responses.js +752 -77
- package/dist/bin/backfill-vectors.js +752 -77
- package/dist/bin/cleanup-stale-review-tasks.js +657 -35
- package/dist/bin/cli.js +1388 -605
- package/dist/bin/exe-agent-config.js +123 -95
- package/dist/bin/exe-agent.js +41 -25
- package/dist/bin/exe-assign.js +732 -57
- package/dist/bin/exe-boot.js +784 -153
- package/dist/bin/exe-call.js +209 -138
- package/dist/bin/exe-cloud.js +35 -12
- package/dist/bin/exe-dispatch.js +692 -70
- package/dist/bin/exe-doctor.js +648 -26
- package/dist/bin/exe-export-behaviors.js +650 -20
- package/dist/bin/exe-forget.js +635 -13
- package/dist/bin/exe-gateway.js +1053 -271
- package/dist/bin/exe-heartbeat.js +665 -43
- package/dist/bin/exe-kill.js +646 -16
- package/dist/bin/exe-launch-agent.js +887 -97
- package/dist/bin/exe-link.js +658 -43
- package/dist/bin/exe-new-employee.js +378 -177
- package/dist/bin/exe-pending-messages.js +656 -34
- package/dist/bin/exe-pending-notifications.js +635 -13
- package/dist/bin/exe-pending-reviews.js +659 -37
- package/dist/bin/exe-rename.js +645 -30
- package/dist/bin/exe-review.js +635 -13
- package/dist/bin/exe-search.js +771 -88
- package/dist/bin/exe-session-cleanup.js +834 -150
- package/dist/bin/exe-settings.js +127 -91
- package/dist/bin/exe-start-codex.js +729 -94
- package/dist/bin/exe-start-opencode.js +717 -82
- package/dist/bin/exe-status.js +657 -35
- package/dist/bin/exe-team.js +635 -13
- package/dist/bin/git-sweep.js +720 -89
- package/dist/bin/graph-backfill.js +643 -13
- package/dist/bin/graph-export.js +646 -16
- package/dist/bin/install.js +596 -193
- package/dist/bin/scan-tasks.js +724 -93
- package/dist/bin/setup.js +1038 -210
- package/dist/bin/shard-migrate.js +645 -15
- package/dist/bin/wiki-sync.js +646 -16
- package/dist/gateway/index.js +1027 -245
- package/dist/hooks/bug-report-worker.js +891 -170
- package/dist/hooks/commit-complete.js +718 -87
- package/dist/hooks/error-recall.js +776 -93
- package/dist/hooks/exe-heartbeat-hook.js +85 -71
- package/dist/hooks/ingest-worker.js +840 -156
- package/dist/hooks/ingest.js +90 -73
- package/dist/hooks/instructions-loaded.js +669 -38
- package/dist/hooks/notification.js +661 -30
- package/dist/hooks/post-compact.js +674 -43
- package/dist/hooks/pre-compact.js +718 -87
- package/dist/hooks/pre-tool-use.js +872 -125
- package/dist/hooks/prompt-ingest-worker.js +758 -83
- package/dist/hooks/prompt-submit.js +1060 -319
- package/dist/hooks/response-ingest-worker.js +758 -83
- package/dist/hooks/session-end.js +721 -90
- package/dist/hooks/session-start.js +1031 -207
- package/dist/hooks/stop.js +680 -49
- package/dist/hooks/subagent-stop.js +674 -43
- package/dist/hooks/summary-worker.js +816 -132
- package/dist/index.js +1015 -232
- package/dist/lib/cloud-sync.js +663 -48
- package/dist/lib/consolidation.js +26 -3
- package/dist/lib/database.js +626 -18
- package/dist/lib/db.js +2261 -0
- package/dist/lib/device-registry.js +640 -25
- package/dist/lib/embedder.js +96 -43
- package/dist/lib/employee-templates.js +16 -0
- package/dist/lib/employees.js +259 -83
- package/dist/lib/exe-daemon-client.js +101 -63
- package/dist/lib/exe-daemon.js +894 -162
- package/dist/lib/hybrid-search.js +771 -88
- package/dist/lib/identity.js +27 -7
- package/dist/lib/messaging.js +55 -28
- package/dist/lib/reminders.js +21 -1
- package/dist/lib/schedules.js +636 -14
- package/dist/lib/skill-learning.js +21 -1
- package/dist/lib/store.js +643 -13
- package/dist/lib/task-router.js +82 -71
- package/dist/lib/tasks.js +98 -71
- package/dist/lib/tmux-routing.js +87 -60
- package/dist/lib/token-spend.js +26 -6
- package/dist/mcp/server.js +1784 -458
- package/dist/mcp/tools/complete-reminder.js +21 -1
- package/dist/mcp/tools/create-reminder.js +21 -1
- package/dist/mcp/tools/create-task.js +290 -164
- package/dist/mcp/tools/deactivate-behavior.js +24 -4
- package/dist/mcp/tools/list-reminders.js +21 -1
- package/dist/mcp/tools/list-tasks.js +195 -38
- package/dist/mcp/tools/send-message.js +58 -31
- package/dist/mcp/tools/update-task.js +75 -48
- package/dist/runtime/index.js +720 -89
- package/dist/tui/App.js +853 -123
- package/package.json +3 -2
|
@@ -180,7 +180,7 @@ function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
|
180
180
|
return [];
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
|
-
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE;
|
|
183
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, IDENTITY_DIR;
|
|
184
184
|
var init_employees = __esm({
|
|
185
185
|
"src/lib/employees.ts"() {
|
|
186
186
|
"use strict";
|
|
@@ -188,16 +188,601 @@ var init_employees = __esm({
|
|
|
188
188
|
EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
189
189
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
190
190
|
COORDINATOR_ROLE = "COO";
|
|
191
|
+
IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// src/lib/database-adapter.ts
|
|
196
|
+
import os3 from "os";
|
|
197
|
+
import path3 from "path";
|
|
198
|
+
import { createRequire } from "module";
|
|
199
|
+
import { pathToFileURL } from "url";
|
|
200
|
+
function quotedIdentifier(identifier) {
|
|
201
|
+
return `"${identifier.replace(/"/g, '""')}"`;
|
|
202
|
+
}
|
|
203
|
+
function unqualifiedTableName(name) {
|
|
204
|
+
const raw = name.trim().replace(/^"|"$/g, "");
|
|
205
|
+
const parts = raw.split(".");
|
|
206
|
+
return parts[parts.length - 1].replace(/^"|"$/g, "").toLowerCase();
|
|
207
|
+
}
|
|
208
|
+
function stripTrailingSemicolon(sql) {
|
|
209
|
+
return sql.trim().replace(/;+\s*$/u, "");
|
|
210
|
+
}
|
|
211
|
+
function appendClause(sql, clause) {
|
|
212
|
+
const trimmed = stripTrailingSemicolon(sql);
|
|
213
|
+
const returningMatch = /\sRETURNING\b[\s\S]*$/iu.exec(trimmed);
|
|
214
|
+
if (!returningMatch) {
|
|
215
|
+
return `${trimmed}${clause}`;
|
|
216
|
+
}
|
|
217
|
+
const idx = returningMatch.index;
|
|
218
|
+
return `${trimmed.slice(0, idx)}${clause}${trimmed.slice(idx)}`;
|
|
219
|
+
}
|
|
220
|
+
function normalizeStatement(stmt) {
|
|
221
|
+
if (typeof stmt === "string") {
|
|
222
|
+
return { kind: "positional", sql: stmt, args: [] };
|
|
223
|
+
}
|
|
224
|
+
const sql = stmt.sql;
|
|
225
|
+
if (Array.isArray(stmt.args) || stmt.args === void 0) {
|
|
226
|
+
return { kind: "positional", sql, args: stmt.args ?? [] };
|
|
227
|
+
}
|
|
228
|
+
return { kind: "named", sql, args: stmt.args };
|
|
229
|
+
}
|
|
230
|
+
function rewriteBooleanLiterals(sql) {
|
|
231
|
+
let out = sql;
|
|
232
|
+
for (const column of BOOLEAN_COLUMN_NAMES) {
|
|
233
|
+
const scoped = `((?:\\b[a-z_][a-z0-9_]*\\.)?${column})`;
|
|
234
|
+
out = out.replace(new RegExp(`${scoped}\\s*=\\s*0\\b`, "giu"), "$1 = FALSE");
|
|
235
|
+
out = out.replace(new RegExp(`${scoped}\\s*=\\s*1\\b`, "giu"), "$1 = TRUE");
|
|
236
|
+
out = out.replace(new RegExp(`${scoped}\\s*!=\\s*0\\b`, "giu"), "$1 != FALSE");
|
|
237
|
+
out = out.replace(new RegExp(`${scoped}\\s*!=\\s*1\\b`, "giu"), "$1 != TRUE");
|
|
238
|
+
out = out.replace(new RegExp(`${scoped}\\s*<>\\s*0\\b`, "giu"), "$1 <> FALSE");
|
|
239
|
+
out = out.replace(new RegExp(`${scoped}\\s*<>\\s*1\\b`, "giu"), "$1 <> TRUE");
|
|
240
|
+
}
|
|
241
|
+
return out;
|
|
242
|
+
}
|
|
243
|
+
function rewriteInsertOrIgnore(sql) {
|
|
244
|
+
if (!/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu.test(sql)) {
|
|
245
|
+
return sql;
|
|
246
|
+
}
|
|
247
|
+
const replaced = sql.replace(/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu, "INSERT INTO");
|
|
248
|
+
return /\bON\s+CONFLICT\b/iu.test(replaced) ? replaced : appendClause(replaced, " ON CONFLICT DO NOTHING");
|
|
249
|
+
}
|
|
250
|
+
function rewriteInsertOrReplace(sql) {
|
|
251
|
+
const match = /^\s*INSERT\s+OR\s+REPLACE\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)([\s\S]*)$/iu.exec(sql);
|
|
252
|
+
if (!match) {
|
|
253
|
+
return sql;
|
|
254
|
+
}
|
|
255
|
+
const rawTable = match[1];
|
|
256
|
+
const rawColumns = match[2];
|
|
257
|
+
const remainder = match[3];
|
|
258
|
+
const tableName = unqualifiedTableName(rawTable);
|
|
259
|
+
const conflictKeys = UPSERT_KEYS[tableName];
|
|
260
|
+
if (!conflictKeys?.length) {
|
|
261
|
+
return sql;
|
|
262
|
+
}
|
|
263
|
+
const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
|
|
264
|
+
const updateColumns = columns.filter((col) => !conflictKeys.includes(col));
|
|
265
|
+
const conflictTarget = conflictKeys.map(quotedIdentifier).join(", ");
|
|
266
|
+
const updateClause = updateColumns.length === 0 ? " DO NOTHING" : ` DO UPDATE SET ${updateColumns.map((col) => `${quotedIdentifier(col)} = EXCLUDED.${quotedIdentifier(col)}`).join(", ")}`;
|
|
267
|
+
return `INSERT INTO ${rawTable} (${rawColumns})${appendClause(remainder, ` ON CONFLICT (${conflictTarget})${updateClause}`)}`;
|
|
268
|
+
}
|
|
269
|
+
function rewriteSql(sql) {
|
|
270
|
+
let out = sql;
|
|
271
|
+
out = out.replace(/\bdatetime\(\s*['"]now['"]\s*\)/giu, "CURRENT_TIMESTAMP");
|
|
272
|
+
out = out.replace(/\bvector32\s*\(\s*\?\s*\)/giu, "?");
|
|
273
|
+
out = rewriteBooleanLiterals(out);
|
|
274
|
+
out = rewriteInsertOrReplace(out);
|
|
275
|
+
out = rewriteInsertOrIgnore(out);
|
|
276
|
+
return stripTrailingSemicolon(out);
|
|
277
|
+
}
|
|
278
|
+
function toBoolean(value) {
|
|
279
|
+
if (value === null || value === void 0) return value;
|
|
280
|
+
if (typeof value === "boolean") return value;
|
|
281
|
+
if (typeof value === "number") return value !== 0;
|
|
282
|
+
if (typeof value === "bigint") return value !== 0n;
|
|
283
|
+
if (typeof value === "string") {
|
|
284
|
+
const normalized = value.trim().toLowerCase();
|
|
285
|
+
if (normalized === "0" || normalized === "false") return false;
|
|
286
|
+
if (normalized === "1" || normalized === "true") return true;
|
|
287
|
+
}
|
|
288
|
+
return Boolean(value);
|
|
289
|
+
}
|
|
290
|
+
function countQuestionMarks(sql, end) {
|
|
291
|
+
let count = 0;
|
|
292
|
+
let inSingle = false;
|
|
293
|
+
let inDouble = false;
|
|
294
|
+
let inLineComment = false;
|
|
295
|
+
let inBlockComment = false;
|
|
296
|
+
for (let i = 0; i < end; i++) {
|
|
297
|
+
const ch = sql[i];
|
|
298
|
+
const next = sql[i + 1];
|
|
299
|
+
if (inLineComment) {
|
|
300
|
+
if (ch === "\n") inLineComment = false;
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
if (inBlockComment) {
|
|
304
|
+
if (ch === "*" && next === "/") {
|
|
305
|
+
inBlockComment = false;
|
|
306
|
+
i += 1;
|
|
307
|
+
}
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
311
|
+
inLineComment = true;
|
|
312
|
+
i += 1;
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
316
|
+
inBlockComment = true;
|
|
317
|
+
i += 1;
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
321
|
+
inSingle = !inSingle;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
325
|
+
inDouble = !inDouble;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (!inSingle && !inDouble && ch === "?") {
|
|
329
|
+
count += 1;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return count;
|
|
333
|
+
}
|
|
334
|
+
function findBooleanPlaceholderIndexes(sql) {
|
|
335
|
+
const indexes = /* @__PURE__ */ new Set();
|
|
336
|
+
for (const column of BOOLEAN_COLUMN_NAMES) {
|
|
337
|
+
const pattern = new RegExp(`(?:\\b[a-z_][a-z0-9_]*\\.)?${column}\\s*=\\s*\\?`, "giu");
|
|
338
|
+
for (const match of sql.matchAll(pattern)) {
|
|
339
|
+
const matchText = match[0];
|
|
340
|
+
const qIndex = match.index + matchText.lastIndexOf("?");
|
|
341
|
+
indexes.add(countQuestionMarks(sql, qIndex + 1));
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return indexes;
|
|
345
|
+
}
|
|
346
|
+
function coerceInsertBooleanArgs(sql, args) {
|
|
347
|
+
const match = /^\s*INSERT(?:\s+OR\s+(?:IGNORE|REPLACE))?\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)/iu.exec(sql);
|
|
348
|
+
if (!match) return;
|
|
349
|
+
const rawTable = match[1];
|
|
350
|
+
const rawColumns = match[2];
|
|
351
|
+
const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
|
|
352
|
+
if (!boolColumns?.size) return;
|
|
353
|
+
const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
|
|
354
|
+
for (const [index, column] of columns.entries()) {
|
|
355
|
+
if (boolColumns.has(column) && index < args.length) {
|
|
356
|
+
args[index] = toBoolean(args[index]);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
function coerceUpdateBooleanArgs(sql, args) {
|
|
361
|
+
const match = /^\s*UPDATE\s+([A-Za-z0-9_."]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE\b|$)/iu.exec(sql);
|
|
362
|
+
if (!match) return;
|
|
363
|
+
const rawTable = match[1];
|
|
364
|
+
const setClause = match[2];
|
|
365
|
+
const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
|
|
366
|
+
if (!boolColumns?.size) return;
|
|
367
|
+
const assignments = setClause.split(",");
|
|
368
|
+
let placeholderIndex = 0;
|
|
369
|
+
for (const assignment of assignments) {
|
|
370
|
+
if (!assignment.includes("?")) continue;
|
|
371
|
+
placeholderIndex += 1;
|
|
372
|
+
const colMatch = /^\s*(?:[A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\?/iu.exec(assignment);
|
|
373
|
+
if (colMatch && boolColumns.has(colMatch[1])) {
|
|
374
|
+
args[placeholderIndex - 1] = toBoolean(args[placeholderIndex - 1]);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
function coerceBooleanArgs(sql, args) {
|
|
379
|
+
const nextArgs = [...args];
|
|
380
|
+
coerceInsertBooleanArgs(sql, nextArgs);
|
|
381
|
+
coerceUpdateBooleanArgs(sql, nextArgs);
|
|
382
|
+
const placeholderIndexes = findBooleanPlaceholderIndexes(sql);
|
|
383
|
+
for (const index of placeholderIndexes) {
|
|
384
|
+
if (index > 0 && index <= nextArgs.length) {
|
|
385
|
+
nextArgs[index - 1] = toBoolean(nextArgs[index - 1]);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return nextArgs;
|
|
389
|
+
}
|
|
390
|
+
function convertQuestionMarksToDollarParams(sql) {
|
|
391
|
+
let out = "";
|
|
392
|
+
let placeholder = 0;
|
|
393
|
+
let inSingle = false;
|
|
394
|
+
let inDouble = false;
|
|
395
|
+
let inLineComment = false;
|
|
396
|
+
let inBlockComment = false;
|
|
397
|
+
for (let i = 0; i < sql.length; i++) {
|
|
398
|
+
const ch = sql[i];
|
|
399
|
+
const next = sql[i + 1];
|
|
400
|
+
if (inLineComment) {
|
|
401
|
+
out += ch;
|
|
402
|
+
if (ch === "\n") inLineComment = false;
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if (inBlockComment) {
|
|
406
|
+
out += ch;
|
|
407
|
+
if (ch === "*" && next === "/") {
|
|
408
|
+
out += next;
|
|
409
|
+
inBlockComment = false;
|
|
410
|
+
i += 1;
|
|
411
|
+
}
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
415
|
+
out += ch + next;
|
|
416
|
+
inLineComment = true;
|
|
417
|
+
i += 1;
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
421
|
+
out += ch + next;
|
|
422
|
+
inBlockComment = true;
|
|
423
|
+
i += 1;
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
427
|
+
inSingle = !inSingle;
|
|
428
|
+
out += ch;
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
432
|
+
inDouble = !inDouble;
|
|
433
|
+
out += ch;
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
if (!inSingle && !inDouble && ch === "?") {
|
|
437
|
+
placeholder += 1;
|
|
438
|
+
out += `$${placeholder}`;
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
out += ch;
|
|
442
|
+
}
|
|
443
|
+
return out;
|
|
444
|
+
}
|
|
445
|
+
function translateStatementForPostgres(stmt) {
|
|
446
|
+
const normalized = normalizeStatement(stmt);
|
|
447
|
+
if (normalized.kind === "named") {
|
|
448
|
+
throw new Error("Named SQL parameters are not supported by the Prisma adapter.");
|
|
449
|
+
}
|
|
450
|
+
const rewrittenSql = rewriteSql(normalized.sql);
|
|
451
|
+
const coercedArgs = coerceBooleanArgs(rewrittenSql, normalized.args);
|
|
452
|
+
return {
|
|
453
|
+
sql: convertQuestionMarksToDollarParams(rewrittenSql),
|
|
454
|
+
args: coercedArgs
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
function shouldBypassPostgres(stmt) {
|
|
458
|
+
const normalized = normalizeStatement(stmt);
|
|
459
|
+
if (normalized.kind === "named") {
|
|
460
|
+
return true;
|
|
461
|
+
}
|
|
462
|
+
return IMMEDIATE_FALLBACK_PATTERNS.some((pattern) => pattern.test(normalized.sql));
|
|
463
|
+
}
|
|
464
|
+
function shouldFallbackOnError(error) {
|
|
465
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
466
|
+
return /42P01|42883|42601|does not exist|syntax error|not supported|Named SQL parameters are not supported/iu.test(message);
|
|
467
|
+
}
|
|
468
|
+
function isReadQuery(sql) {
|
|
469
|
+
const trimmed = sql.trimStart();
|
|
470
|
+
return /^(SELECT|WITH|SHOW|EXPLAIN|VALUES)\b/iu.test(trimmed) || /\bRETURNING\b/iu.test(trimmed);
|
|
471
|
+
}
|
|
472
|
+
function buildRow(row, columns) {
|
|
473
|
+
const values = columns.map((column) => row[column]);
|
|
474
|
+
return Object.assign(values, row);
|
|
475
|
+
}
|
|
476
|
+
function buildResultSet(rows, rowsAffected = 0) {
|
|
477
|
+
const columns = rows[0] ? Object.keys(rows[0]) : [];
|
|
478
|
+
const resultRows = rows.map((row) => buildRow(row, columns));
|
|
479
|
+
return {
|
|
480
|
+
columns,
|
|
481
|
+
columnTypes: columns.map(() => ""),
|
|
482
|
+
rows: resultRows,
|
|
483
|
+
rowsAffected,
|
|
484
|
+
lastInsertRowid: void 0,
|
|
485
|
+
toJSON() {
|
|
486
|
+
return {
|
|
487
|
+
columns,
|
|
488
|
+
columnTypes: columns.map(() => ""),
|
|
489
|
+
rows,
|
|
490
|
+
rowsAffected,
|
|
491
|
+
lastInsertRowid: void 0
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
async function loadPrismaClient() {
|
|
497
|
+
if (!prismaClientPromise) {
|
|
498
|
+
prismaClientPromise = (async () => {
|
|
499
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
500
|
+
if (explicitPath) {
|
|
501
|
+
const module2 = await import(pathToFileURL(explicitPath).href);
|
|
502
|
+
const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
|
|
503
|
+
if (!PrismaClient2) {
|
|
504
|
+
throw new Error(`No PrismaClient export found at ${explicitPath}`);
|
|
505
|
+
}
|
|
506
|
+
return new PrismaClient2();
|
|
507
|
+
}
|
|
508
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path3.join(os3.homedir(), "exe-db");
|
|
509
|
+
const requireFromExeDb = createRequire(path3.join(exeDbRoot, "package.json"));
|
|
510
|
+
const prismaEntry = requireFromExeDb.resolve("@prisma/client");
|
|
511
|
+
const module = await import(pathToFileURL(prismaEntry).href);
|
|
512
|
+
const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
|
|
513
|
+
if (!PrismaClient) {
|
|
514
|
+
throw new Error(`No PrismaClient export found in ${prismaEntry}`);
|
|
515
|
+
}
|
|
516
|
+
return new PrismaClient();
|
|
517
|
+
})();
|
|
518
|
+
}
|
|
519
|
+
return prismaClientPromise;
|
|
520
|
+
}
|
|
521
|
+
async function ensureCompatibilityViews(prisma) {
|
|
522
|
+
if (!compatibilityBootstrapPromise) {
|
|
523
|
+
compatibilityBootstrapPromise = (async () => {
|
|
524
|
+
for (const mapping of VIEW_MAPPINGS) {
|
|
525
|
+
const relation = mapping.source.replace(/"/g, "");
|
|
526
|
+
const rows = await prisma.$queryRawUnsafe(
|
|
527
|
+
"SELECT to_regclass($1) AS regclass",
|
|
528
|
+
relation
|
|
529
|
+
);
|
|
530
|
+
if (!rows[0]?.regclass) {
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
await prisma.$executeRawUnsafe(
|
|
534
|
+
`CREATE OR REPLACE VIEW public.${quotedIdentifier(mapping.view)} AS SELECT * FROM ${mapping.source}`
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
})();
|
|
538
|
+
}
|
|
539
|
+
return compatibilityBootstrapPromise;
|
|
540
|
+
}
|
|
541
|
+
async function executeOnPrisma(executor, stmt) {
|
|
542
|
+
const translated = translateStatementForPostgres(stmt);
|
|
543
|
+
if (isReadQuery(translated.sql)) {
|
|
544
|
+
const rows = await executor.$queryRawUnsafe(
|
|
545
|
+
translated.sql,
|
|
546
|
+
...translated.args
|
|
547
|
+
);
|
|
548
|
+
return buildResultSet(rows, /\bRETURNING\b/iu.test(translated.sql) ? rows.length : 0);
|
|
549
|
+
}
|
|
550
|
+
const rowsAffected = await executor.$executeRawUnsafe(translated.sql, ...translated.args);
|
|
551
|
+
return buildResultSet([], rowsAffected);
|
|
552
|
+
}
|
|
553
|
+
function splitSqlStatements(sql) {
|
|
554
|
+
const parts = [];
|
|
555
|
+
let current = "";
|
|
556
|
+
let inSingle = false;
|
|
557
|
+
let inDouble = false;
|
|
558
|
+
let inLineComment = false;
|
|
559
|
+
let inBlockComment = false;
|
|
560
|
+
for (let i = 0; i < sql.length; i++) {
|
|
561
|
+
const ch = sql[i];
|
|
562
|
+
const next = sql[i + 1];
|
|
563
|
+
if (inLineComment) {
|
|
564
|
+
current += ch;
|
|
565
|
+
if (ch === "\n") inLineComment = false;
|
|
566
|
+
continue;
|
|
567
|
+
}
|
|
568
|
+
if (inBlockComment) {
|
|
569
|
+
current += ch;
|
|
570
|
+
if (ch === "*" && next === "/") {
|
|
571
|
+
current += next;
|
|
572
|
+
inBlockComment = false;
|
|
573
|
+
i += 1;
|
|
574
|
+
}
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
578
|
+
current += ch + next;
|
|
579
|
+
inLineComment = true;
|
|
580
|
+
i += 1;
|
|
581
|
+
continue;
|
|
582
|
+
}
|
|
583
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
584
|
+
current += ch + next;
|
|
585
|
+
inBlockComment = true;
|
|
586
|
+
i += 1;
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
590
|
+
inSingle = !inSingle;
|
|
591
|
+
current += ch;
|
|
592
|
+
continue;
|
|
593
|
+
}
|
|
594
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
595
|
+
inDouble = !inDouble;
|
|
596
|
+
current += ch;
|
|
597
|
+
continue;
|
|
598
|
+
}
|
|
599
|
+
if (!inSingle && !inDouble && ch === ";") {
|
|
600
|
+
if (current.trim()) {
|
|
601
|
+
parts.push(current.trim());
|
|
602
|
+
}
|
|
603
|
+
current = "";
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
current += ch;
|
|
607
|
+
}
|
|
608
|
+
if (current.trim()) {
|
|
609
|
+
parts.push(current.trim());
|
|
610
|
+
}
|
|
611
|
+
return parts;
|
|
612
|
+
}
|
|
613
|
+
async function createPrismaDbAdapter(fallbackClient) {
|
|
614
|
+
const prisma = await loadPrismaClient();
|
|
615
|
+
await ensureCompatibilityViews(prisma);
|
|
616
|
+
let closed = false;
|
|
617
|
+
let adapter;
|
|
618
|
+
const fallbackExecute = async (stmt, error) => {
|
|
619
|
+
if (!fallbackClient) {
|
|
620
|
+
if (error) throw error;
|
|
621
|
+
throw new Error("No fallback SQLite client is available for this Prisma-routed query.");
|
|
622
|
+
}
|
|
623
|
+
if (error) {
|
|
624
|
+
process.stderr.write(
|
|
625
|
+
`[database-adapter] Falling back to SQLite: ${error instanceof Error ? error.message : String(error)}
|
|
626
|
+
`
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
return fallbackClient.execute(stmt);
|
|
630
|
+
};
|
|
631
|
+
adapter = {
|
|
632
|
+
async execute(stmt) {
|
|
633
|
+
if (shouldBypassPostgres(stmt)) {
|
|
634
|
+
return fallbackExecute(stmt);
|
|
635
|
+
}
|
|
636
|
+
try {
|
|
637
|
+
return await executeOnPrisma(prisma, stmt);
|
|
638
|
+
} catch (error) {
|
|
639
|
+
if (shouldFallbackOnError(error)) {
|
|
640
|
+
return fallbackExecute(stmt, error);
|
|
641
|
+
}
|
|
642
|
+
throw error;
|
|
643
|
+
}
|
|
644
|
+
},
|
|
645
|
+
async batch(stmts, mode) {
|
|
646
|
+
if (stmts.some((stmt) => shouldBypassPostgres(stmt))) {
|
|
647
|
+
if (!fallbackClient) {
|
|
648
|
+
throw new Error("Cannot batch unsupported SQLite-only statements without a fallback client.");
|
|
649
|
+
}
|
|
650
|
+
return fallbackClient.batch(stmts, mode);
|
|
651
|
+
}
|
|
652
|
+
try {
|
|
653
|
+
if (prisma.$transaction) {
|
|
654
|
+
return await prisma.$transaction(async (tx) => {
|
|
655
|
+
const results2 = [];
|
|
656
|
+
for (const stmt of stmts) {
|
|
657
|
+
results2.push(await executeOnPrisma(tx, stmt));
|
|
658
|
+
}
|
|
659
|
+
return results2;
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
const results = [];
|
|
663
|
+
for (const stmt of stmts) {
|
|
664
|
+
results.push(await executeOnPrisma(prisma, stmt));
|
|
665
|
+
}
|
|
666
|
+
return results;
|
|
667
|
+
} catch (error) {
|
|
668
|
+
if (fallbackClient && shouldFallbackOnError(error)) {
|
|
669
|
+
process.stderr.write(
|
|
670
|
+
`[database-adapter] Falling back batch to SQLite: ${error instanceof Error ? error.message : String(error)}
|
|
671
|
+
`
|
|
672
|
+
);
|
|
673
|
+
return fallbackClient.batch(stmts, mode);
|
|
674
|
+
}
|
|
675
|
+
throw error;
|
|
676
|
+
}
|
|
677
|
+
},
|
|
678
|
+
async migrate(stmts) {
|
|
679
|
+
if (fallbackClient) {
|
|
680
|
+
return fallbackClient.migrate(stmts);
|
|
681
|
+
}
|
|
682
|
+
return adapter.batch(stmts, "deferred");
|
|
683
|
+
},
|
|
684
|
+
async transaction(mode) {
|
|
685
|
+
if (!fallbackClient) {
|
|
686
|
+
throw new Error("Interactive transactions are only supported on the SQLite fallback client.");
|
|
687
|
+
}
|
|
688
|
+
return fallbackClient.transaction(mode);
|
|
689
|
+
},
|
|
690
|
+
async executeMultiple(sql) {
|
|
691
|
+
if (fallbackClient && shouldBypassPostgres(sql)) {
|
|
692
|
+
return fallbackClient.executeMultiple(sql);
|
|
693
|
+
}
|
|
694
|
+
for (const statement of splitSqlStatements(sql)) {
|
|
695
|
+
await adapter.execute(statement);
|
|
696
|
+
}
|
|
697
|
+
},
|
|
698
|
+
async sync() {
|
|
699
|
+
if (fallbackClient) {
|
|
700
|
+
return fallbackClient.sync();
|
|
701
|
+
}
|
|
702
|
+
return { frame_no: 0, frames_synced: 0 };
|
|
703
|
+
},
|
|
704
|
+
close() {
|
|
705
|
+
closed = true;
|
|
706
|
+
prismaClientPromise = null;
|
|
707
|
+
compatibilityBootstrapPromise = null;
|
|
708
|
+
void prisma.$disconnect?.();
|
|
709
|
+
},
|
|
710
|
+
get closed() {
|
|
711
|
+
return closed;
|
|
712
|
+
},
|
|
713
|
+
get protocol() {
|
|
714
|
+
return "prisma-postgres";
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
return adapter;
|
|
718
|
+
}
|
|
719
|
+
var VIEW_MAPPINGS, UPSERT_KEYS, BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES, IMMEDIATE_FALLBACK_PATTERNS, prismaClientPromise, compatibilityBootstrapPromise;
|
|
720
|
+
var init_database_adapter = __esm({
|
|
721
|
+
"src/lib/database-adapter.ts"() {
|
|
722
|
+
"use strict";
|
|
723
|
+
VIEW_MAPPINGS = [
|
|
724
|
+
{ view: "memories", source: "memory.memory_records" },
|
|
725
|
+
{ view: "tasks", source: "memory.tasks" },
|
|
726
|
+
{ view: "behaviors", source: "memory.behaviors" },
|
|
727
|
+
{ view: "entities", source: "memory.entities" },
|
|
728
|
+
{ view: "relationships", source: "memory.relationships" },
|
|
729
|
+
{ view: "entity_memories", source: "memory.entity_memories" },
|
|
730
|
+
{ view: "entity_aliases", source: "memory.entity_aliases" },
|
|
731
|
+
{ view: "notifications", source: "memory.notifications" },
|
|
732
|
+
{ view: "messages", source: "memory.messages" },
|
|
733
|
+
{ view: "users", source: "wiki.users" },
|
|
734
|
+
{ view: "workspaces", source: "wiki.workspaces" },
|
|
735
|
+
{ view: "workspace_users", source: "wiki.workspace_users" },
|
|
736
|
+
{ view: "documents", source: "wiki.workspace_documents" },
|
|
737
|
+
{ view: "chats", source: "wiki.workspace_chats" }
|
|
738
|
+
];
|
|
739
|
+
UPSERT_KEYS = {
|
|
740
|
+
memories: ["id"],
|
|
741
|
+
tasks: ["id"],
|
|
742
|
+
behaviors: ["id"],
|
|
743
|
+
entities: ["id"],
|
|
744
|
+
relationships: ["id"],
|
|
745
|
+
entity_aliases: ["alias"],
|
|
746
|
+
notifications: ["id"],
|
|
747
|
+
messages: ["id"],
|
|
748
|
+
users: ["id"],
|
|
749
|
+
workspaces: ["id"],
|
|
750
|
+
workspace_users: ["id"],
|
|
751
|
+
documents: ["id"],
|
|
752
|
+
chats: ["id"]
|
|
753
|
+
};
|
|
754
|
+
BOOLEAN_COLUMNS_BY_TABLE = {
|
|
755
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
756
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
757
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
758
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
759
|
+
};
|
|
760
|
+
BOOLEAN_COLUMN_NAMES = new Set(
|
|
761
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
762
|
+
);
|
|
763
|
+
IMMEDIATE_FALLBACK_PATTERNS = [
|
|
764
|
+
/\bPRAGMA\b/i,
|
|
765
|
+
/\bsqlite_master\b/i,
|
|
766
|
+
/(?:^|[.\s])(?:memories|conversations|entities)_fts\b/i,
|
|
767
|
+
/\bMATCH\b/i,
|
|
768
|
+
/\bvector_distance_cos\s*\(/i,
|
|
769
|
+
/\bjson_extract\s*\(/i,
|
|
770
|
+
/\bjulianday\s*\(/i,
|
|
771
|
+
/\bstrftime\s*\(/i,
|
|
772
|
+
/\blast_insert_rowid\s*\(/i
|
|
773
|
+
];
|
|
774
|
+
prismaClientPromise = null;
|
|
775
|
+
compatibilityBootstrapPromise = null;
|
|
191
776
|
}
|
|
192
777
|
});
|
|
193
778
|
|
|
194
779
|
// src/lib/exe-daemon-client.ts
|
|
195
780
|
import net from "net";
|
|
196
|
-
import
|
|
781
|
+
import os4 from "os";
|
|
197
782
|
import { spawn } from "child_process";
|
|
198
783
|
import { randomUUID } from "crypto";
|
|
199
784
|
import { existsSync as existsSync3, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
|
|
200
|
-
import
|
|
785
|
+
import path4 from "path";
|
|
201
786
|
import { fileURLToPath } from "url";
|
|
202
787
|
function handleData(chunk) {
|
|
203
788
|
_buffer += chunk.toString();
|
|
@@ -248,17 +833,17 @@ function cleanupStaleFiles() {
|
|
|
248
833
|
}
|
|
249
834
|
}
|
|
250
835
|
function findPackageRoot() {
|
|
251
|
-
let dir =
|
|
252
|
-
const { root } =
|
|
836
|
+
let dir = path4.dirname(fileURLToPath(import.meta.url));
|
|
837
|
+
const { root } = path4.parse(dir);
|
|
253
838
|
while (dir !== root) {
|
|
254
|
-
if (existsSync3(
|
|
255
|
-
dir =
|
|
839
|
+
if (existsSync3(path4.join(dir, "package.json"))) return dir;
|
|
840
|
+
dir = path4.dirname(dir);
|
|
256
841
|
}
|
|
257
842
|
return null;
|
|
258
843
|
}
|
|
259
844
|
function spawnDaemon() {
|
|
260
|
-
const freeGB =
|
|
261
|
-
const totalGB =
|
|
845
|
+
const freeGB = os4.freemem() / (1024 * 1024 * 1024);
|
|
846
|
+
const totalGB = os4.totalmem() / (1024 * 1024 * 1024);
|
|
262
847
|
if (totalGB <= 8) {
|
|
263
848
|
process.stderr.write(
|
|
264
849
|
`[exed-client] SKIP: ${totalGB.toFixed(0)}GB system \u2014 embedding daemon disabled. Using keyword search only. Minimum 16GB recommended for vector search.
|
|
@@ -278,7 +863,7 @@ function spawnDaemon() {
|
|
|
278
863
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
279
864
|
return;
|
|
280
865
|
}
|
|
281
|
-
const daemonPath =
|
|
866
|
+
const daemonPath = path4.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
282
867
|
if (!existsSync3(daemonPath)) {
|
|
283
868
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
284
869
|
`);
|
|
@@ -287,7 +872,7 @@ function spawnDaemon() {
|
|
|
287
872
|
const resolvedPath = daemonPath;
|
|
288
873
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
289
874
|
`);
|
|
290
|
-
const logPath =
|
|
875
|
+
const logPath = path4.join(path4.dirname(SOCKET_PATH), "exed.log");
|
|
291
876
|
let stderrFd = "ignore";
|
|
292
877
|
try {
|
|
293
878
|
stderrFd = openSync(logPath, "a");
|
|
@@ -434,9 +1019,9 @@ var init_exe_daemon_client = __esm({
|
|
|
434
1019
|
"src/lib/exe-daemon-client.ts"() {
|
|
435
1020
|
"use strict";
|
|
436
1021
|
init_config();
|
|
437
|
-
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
438
|
-
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
439
|
-
SPAWN_LOCK_PATH =
|
|
1022
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path4.join(EXE_AI_DIR, "exed.sock");
|
|
1023
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path4.join(EXE_AI_DIR, "exed.pid");
|
|
1024
|
+
SPAWN_LOCK_PATH = path4.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
440
1025
|
SPAWN_LOCK_STALE_MS = 3e4;
|
|
441
1026
|
CONNECT_TIMEOUT_MS = 15e3;
|
|
442
1027
|
REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -518,7 +1103,7 @@ __export(db_daemon_client_exports, {
|
|
|
518
1103
|
createDaemonDbClient: () => createDaemonDbClient,
|
|
519
1104
|
initDaemonDbClient: () => initDaemonDbClient
|
|
520
1105
|
});
|
|
521
|
-
function
|
|
1106
|
+
function normalizeStatement2(stmt) {
|
|
522
1107
|
if (typeof stmt === "string") {
|
|
523
1108
|
return { sql: stmt, args: [] };
|
|
524
1109
|
}
|
|
@@ -542,7 +1127,7 @@ function createDaemonDbClient(fallbackClient) {
|
|
|
542
1127
|
if (!_useDaemon || !isClientConnected()) {
|
|
543
1128
|
return fallbackClient.execute(stmt);
|
|
544
1129
|
}
|
|
545
|
-
const { sql, args } =
|
|
1130
|
+
const { sql, args } = normalizeStatement2(stmt);
|
|
546
1131
|
const response = await sendDaemonRequest({
|
|
547
1132
|
type: "db-execute",
|
|
548
1133
|
sql,
|
|
@@ -567,7 +1152,7 @@ function createDaemonDbClient(fallbackClient) {
|
|
|
567
1152
|
if (!_useDaemon || !isClientConnected()) {
|
|
568
1153
|
return fallbackClient.batch(stmts, mode);
|
|
569
1154
|
}
|
|
570
|
-
const statements = stmts.map(
|
|
1155
|
+
const statements = stmts.map(normalizeStatement2);
|
|
571
1156
|
const response = await sendDaemonRequest({
|
|
572
1157
|
type: "db-batch",
|
|
573
1158
|
statements,
|
|
@@ -662,6 +1247,18 @@ __export(database_exports, {
|
|
|
662
1247
|
});
|
|
663
1248
|
import { createClient } from "@libsql/client";
|
|
664
1249
|
async function initDatabase(config) {
|
|
1250
|
+
if (_walCheckpointTimer) {
|
|
1251
|
+
clearInterval(_walCheckpointTimer);
|
|
1252
|
+
_walCheckpointTimer = null;
|
|
1253
|
+
}
|
|
1254
|
+
if (_daemonClient) {
|
|
1255
|
+
_daemonClient.close();
|
|
1256
|
+
_daemonClient = null;
|
|
1257
|
+
}
|
|
1258
|
+
if (_adapterClient && _adapterClient !== _resilientClient) {
|
|
1259
|
+
_adapterClient.close();
|
|
1260
|
+
}
|
|
1261
|
+
_adapterClient = null;
|
|
665
1262
|
if (_client) {
|
|
666
1263
|
_client.close();
|
|
667
1264
|
_client = null;
|
|
@@ -675,6 +1272,7 @@ async function initDatabase(config) {
|
|
|
675
1272
|
}
|
|
676
1273
|
_client = createClient(opts);
|
|
677
1274
|
_resilientClient = wrapWithRetry(_client);
|
|
1275
|
+
_adapterClient = _resilientClient;
|
|
678
1276
|
_client.execute("PRAGMA busy_timeout = 30000").catch(() => {
|
|
679
1277
|
});
|
|
680
1278
|
_client.execute("PRAGMA journal_mode = WAL").catch(() => {
|
|
@@ -685,14 +1283,20 @@ async function initDatabase(config) {
|
|
|
685
1283
|
});
|
|
686
1284
|
}, 3e4);
|
|
687
1285
|
_walCheckpointTimer.unref();
|
|
1286
|
+
if (process.env.DATABASE_URL) {
|
|
1287
|
+
_adapterClient = await createPrismaDbAdapter(_resilientClient);
|
|
1288
|
+
}
|
|
688
1289
|
}
|
|
689
1290
|
function isInitialized() {
|
|
690
|
-
return _client !== null;
|
|
1291
|
+
return _adapterClient !== null || _client !== null;
|
|
691
1292
|
}
|
|
692
1293
|
function getClient() {
|
|
693
|
-
if (!
|
|
1294
|
+
if (!_adapterClient) {
|
|
694
1295
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
695
1296
|
}
|
|
1297
|
+
if (process.env.DATABASE_URL) {
|
|
1298
|
+
return _adapterClient;
|
|
1299
|
+
}
|
|
696
1300
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
697
1301
|
return _resilientClient;
|
|
698
1302
|
}
|
|
@@ -702,6 +1306,7 @@ function getClient() {
|
|
|
702
1306
|
return _resilientClient;
|
|
703
1307
|
}
|
|
704
1308
|
async function initDaemonClient() {
|
|
1309
|
+
if (process.env.DATABASE_URL) return;
|
|
705
1310
|
if (process.env.EXE_IS_DAEMON === "1") return;
|
|
706
1311
|
if (!_resilientClient) return;
|
|
707
1312
|
try {
|
|
@@ -1646,26 +2251,36 @@ async function ensureSchema() {
|
|
|
1646
2251
|
}
|
|
1647
2252
|
}
|
|
1648
2253
|
async function disposeDatabase() {
|
|
2254
|
+
if (_walCheckpointTimer) {
|
|
2255
|
+
clearInterval(_walCheckpointTimer);
|
|
2256
|
+
_walCheckpointTimer = null;
|
|
2257
|
+
}
|
|
1649
2258
|
if (_daemonClient) {
|
|
1650
2259
|
_daemonClient.close();
|
|
1651
2260
|
_daemonClient = null;
|
|
1652
2261
|
}
|
|
2262
|
+
if (_adapterClient && _adapterClient !== _resilientClient) {
|
|
2263
|
+
_adapterClient.close();
|
|
2264
|
+
}
|
|
2265
|
+
_adapterClient = null;
|
|
1653
2266
|
if (_client) {
|
|
1654
2267
|
_client.close();
|
|
1655
2268
|
_client = null;
|
|
1656
2269
|
_resilientClient = null;
|
|
1657
2270
|
}
|
|
1658
2271
|
}
|
|
1659
|
-
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
|
|
2272
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
|
|
1660
2273
|
var init_database = __esm({
|
|
1661
2274
|
"src/lib/database.ts"() {
|
|
1662
2275
|
"use strict";
|
|
1663
2276
|
init_db_retry();
|
|
1664
2277
|
init_employees();
|
|
2278
|
+
init_database_adapter();
|
|
1665
2279
|
_client = null;
|
|
1666
2280
|
_resilientClient = null;
|
|
1667
2281
|
_walCheckpointTimer = null;
|
|
1668
2282
|
_daemonClient = null;
|
|
2283
|
+
_adapterClient = null;
|
|
1669
2284
|
initTurso = initDatabase;
|
|
1670
2285
|
disposeTurso = disposeDatabase;
|
|
1671
2286
|
}
|
|
@@ -1674,10 +2289,10 @@ var init_database = __esm({
|
|
|
1674
2289
|
// src/lib/device-registry.ts
|
|
1675
2290
|
init_config();
|
|
1676
2291
|
import crypto from "crypto";
|
|
1677
|
-
import
|
|
2292
|
+
import os5 from "os";
|
|
1678
2293
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync, existsSync as existsSync4 } from "fs";
|
|
1679
|
-
import
|
|
1680
|
-
var DEVICE_JSON_PATH =
|
|
2294
|
+
import path5 from "path";
|
|
2295
|
+
var DEVICE_JSON_PATH = path5.join(EXE_AI_DIR, "device.json");
|
|
1681
2296
|
function getDeviceInfo() {
|
|
1682
2297
|
if (existsSync4(DEVICE_JSON_PATH)) {
|
|
1683
2298
|
try {
|
|
@@ -1689,13 +2304,13 @@ function getDeviceInfo() {
|
|
|
1689
2304
|
} catch {
|
|
1690
2305
|
}
|
|
1691
2306
|
}
|
|
1692
|
-
const hostname =
|
|
2307
|
+
const hostname = os5.hostname();
|
|
1693
2308
|
const info = {
|
|
1694
2309
|
deviceId: crypto.randomUUID(),
|
|
1695
2310
|
friendlyName: hostname.replace(/\./g, "-").toLowerCase(),
|
|
1696
2311
|
hostname
|
|
1697
2312
|
};
|
|
1698
|
-
mkdirSync(
|
|
2313
|
+
mkdirSync(path5.dirname(DEVICE_JSON_PATH), { recursive: true });
|
|
1699
2314
|
writeFileSync2(DEVICE_JSON_PATH, JSON.stringify(info, null, 2));
|
|
1700
2315
|
return info;
|
|
1701
2316
|
}
|