@askexenow/exe-os 0.9.7 → 0.9.9
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 +953 -105
- package/dist/bin/backfill-responses.js +952 -104
- package/dist/bin/backfill-vectors.js +956 -108
- package/dist/bin/cleanup-stale-review-tasks.js +802 -58
- package/dist/bin/cli.js +2292 -1070
- package/dist/bin/exe-agent-config.js +157 -101
- package/dist/bin/exe-agent.js +55 -29
- package/dist/bin/exe-assign.js +940 -92
- package/dist/bin/exe-boot.js +1424 -442
- package/dist/bin/exe-call.js +240 -141
- package/dist/bin/exe-cloud.js +198 -70
- package/dist/bin/exe-dispatch.js +951 -192
- package/dist/bin/exe-doctor.js +791 -51
- package/dist/bin/exe-export-behaviors.js +790 -42
- package/dist/bin/exe-forget.js +771 -31
- package/dist/bin/exe-gateway.js +1592 -521
- package/dist/bin/exe-heartbeat.js +850 -109
- package/dist/bin/exe-kill.js +783 -35
- package/dist/bin/exe-launch-agent.js +1030 -107
- package/dist/bin/exe-link.js +916 -110
- package/dist/bin/exe-new-employee.js +526 -217
- package/dist/bin/exe-pending-messages.js +1046 -62
- package/dist/bin/exe-pending-notifications.js +1318 -111
- package/dist/bin/exe-pending-reviews.js +1040 -72
- package/dist/bin/exe-rename.js +772 -59
- package/dist/bin/exe-review.js +772 -32
- package/dist/bin/exe-search.js +982 -128
- package/dist/bin/exe-session-cleanup.js +1180 -306
- package/dist/bin/exe-settings.js +185 -105
- package/dist/bin/exe-start-codex.js +886 -132
- package/dist/bin/exe-start-opencode.js +873 -119
- package/dist/bin/exe-status.js +803 -59
- package/dist/bin/exe-team.js +772 -32
- package/dist/bin/git-sweep.js +1046 -223
- package/dist/bin/graph-backfill.js +779 -31
- package/dist/bin/graph-export.js +785 -37
- package/dist/bin/install.js +632 -200
- package/dist/bin/scan-tasks.js +1055 -232
- package/dist/bin/setup.js +1419 -320
- package/dist/bin/shard-migrate.js +783 -35
- package/dist/bin/update.js +138 -49
- package/dist/bin/wiki-sync.js +782 -34
- package/dist/gateway/index.js +1444 -449
- package/dist/hooks/bug-report-worker.js +1141 -269
- package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
- package/dist/hooks/commit-complete.js +1044 -221
- package/dist/hooks/error-recall.js +989 -135
- package/dist/hooks/exe-heartbeat-hook.js +99 -75
- package/dist/hooks/ingest-worker.js +4176 -3226
- package/dist/hooks/ingest.js +920 -168
- package/dist/hooks/instructions-loaded.js +874 -70
- package/dist/hooks/notification.js +860 -56
- package/dist/hooks/post-compact.js +881 -73
- package/dist/hooks/pre-compact.js +1050 -227
- package/dist/hooks/pre-tool-use.js +1084 -159
- package/dist/hooks/prompt-ingest-worker.js +1089 -164
- package/dist/hooks/prompt-submit.js +1469 -515
- package/dist/hooks/response-ingest-worker.js +1104 -179
- package/dist/hooks/session-end.js +1085 -251
- package/dist/hooks/session-start.js +1241 -231
- package/dist/hooks/stop.js +935 -109
- package/dist/hooks/subagent-stop.js +881 -73
- package/dist/hooks/summary-worker.js +1323 -307
- package/dist/index.js +1449 -452
- package/dist/lib/agent-config.js +28 -6
- package/dist/lib/cloud-sync.js +909 -115
- package/dist/lib/config.js +30 -10
- package/dist/lib/consolidation.js +42 -9
- package/dist/lib/database.js +739 -33
- package/dist/lib/db-daemon-client.js +73 -19
- package/dist/lib/db.js +2359 -0
- package/dist/lib/device-registry.js +760 -47
- package/dist/lib/embedder.js +201 -73
- package/dist/lib/employee-templates.js +30 -4
- package/dist/lib/employees.js +290 -86
- package/dist/lib/exe-daemon-client.js +187 -83
- package/dist/lib/exe-daemon.js +1696 -616
- package/dist/lib/hybrid-search.js +982 -128
- package/dist/lib/identity.js +43 -13
- package/dist/lib/license.js +133 -48
- package/dist/lib/messaging.js +167 -80
- package/dist/lib/reminders.js +35 -5
- package/dist/lib/schedules.js +772 -32
- package/dist/lib/skill-learning.js +54 -7
- package/dist/lib/store.js +779 -31
- package/dist/lib/task-router.js +94 -73
- package/dist/lib/tasks.js +298 -225
- package/dist/lib/tmux-routing.js +246 -172
- package/dist/lib/token-spend.js +52 -14
- package/dist/mcp/server.js +2893 -850
- package/dist/mcp/tools/complete-reminder.js +35 -5
- package/dist/mcp/tools/create-reminder.js +35 -5
- package/dist/mcp/tools/create-task.js +507 -323
- package/dist/mcp/tools/deactivate-behavior.js +40 -10
- package/dist/mcp/tools/list-reminders.js +35 -5
- package/dist/mcp/tools/list-tasks.js +277 -104
- package/dist/mcp/tools/send-message.js +129 -56
- package/dist/mcp/tools/update-task.js +1864 -188
- package/dist/runtime/index.js +1083 -259
- package/dist/tui/App.js +1501 -434
- package/package.json +3 -2
package/dist/hooks/stop.js
CHANGED
|
@@ -25,9 +25,47 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
25
25
|
};
|
|
26
26
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
27
|
|
|
28
|
+
// src/lib/secure-files.ts
|
|
29
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
30
|
+
import { chmod, mkdir } from "fs/promises";
|
|
31
|
+
async function ensurePrivateDir(dirPath) {
|
|
32
|
+
await mkdir(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
33
|
+
try {
|
|
34
|
+
await chmod(dirPath, PRIVATE_DIR_MODE);
|
|
35
|
+
} catch {
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function ensurePrivateDirSync(dirPath) {
|
|
39
|
+
mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
40
|
+
try {
|
|
41
|
+
chmodSync(dirPath, PRIVATE_DIR_MODE);
|
|
42
|
+
} catch {
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function enforcePrivateFile(filePath) {
|
|
46
|
+
try {
|
|
47
|
+
await chmod(filePath, PRIVATE_FILE_MODE);
|
|
48
|
+
} catch {
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function enforcePrivateFileSync(filePath) {
|
|
52
|
+
try {
|
|
53
|
+
if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
|
|
58
|
+
var init_secure_files = __esm({
|
|
59
|
+
"src/lib/secure-files.ts"() {
|
|
60
|
+
"use strict";
|
|
61
|
+
PRIVATE_DIR_MODE = 448;
|
|
62
|
+
PRIVATE_FILE_MODE = 384;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
28
66
|
// src/lib/config.ts
|
|
29
|
-
import { readFile, writeFile
|
|
30
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
67
|
+
import { readFile, writeFile } from "fs/promises";
|
|
68
|
+
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
31
69
|
import path from "path";
|
|
32
70
|
import os from "os";
|
|
33
71
|
function resolveDataDir() {
|
|
@@ -35,7 +73,7 @@ function resolveDataDir() {
|
|
|
35
73
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
36
74
|
const newDir = path.join(os.homedir(), ".exe-os");
|
|
37
75
|
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
38
|
-
if (!
|
|
76
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
39
77
|
try {
|
|
40
78
|
renameSync(legacyDir, newDir);
|
|
41
79
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -98,9 +136,9 @@ function normalizeAutoUpdate(raw) {
|
|
|
98
136
|
}
|
|
99
137
|
async function loadConfig() {
|
|
100
138
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
101
|
-
await
|
|
139
|
+
await ensurePrivateDir(dir);
|
|
102
140
|
const configPath = path.join(dir, "config.json");
|
|
103
|
-
if (!
|
|
141
|
+
if (!existsSync2(configPath)) {
|
|
104
142
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
105
143
|
}
|
|
106
144
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -113,6 +151,7 @@ async function loadConfig() {
|
|
|
113
151
|
`);
|
|
114
152
|
try {
|
|
115
153
|
await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
|
|
154
|
+
await enforcePrivateFile(configPath);
|
|
116
155
|
} catch {
|
|
117
156
|
}
|
|
118
157
|
}
|
|
@@ -131,7 +170,7 @@ async function loadConfig() {
|
|
|
131
170
|
function loadConfigSync() {
|
|
132
171
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
133
172
|
const configPath = path.join(dir, "config.json");
|
|
134
|
-
if (!
|
|
173
|
+
if (!existsSync2(configPath)) {
|
|
135
174
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
136
175
|
}
|
|
137
176
|
try {
|
|
@@ -151,6 +190,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
|
|
|
151
190
|
var init_config = __esm({
|
|
152
191
|
"src/lib/config.ts"() {
|
|
153
192
|
"use strict";
|
|
193
|
+
init_secure_files();
|
|
154
194
|
EXE_AI_DIR = resolveDataDir();
|
|
155
195
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
156
196
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
@@ -297,7 +337,7 @@ var init_session_key = __esm({
|
|
|
297
337
|
|
|
298
338
|
// src/lib/employees.ts
|
|
299
339
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
300
|
-
import { existsSync as
|
|
340
|
+
import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
301
341
|
import { execSync as execSync2 } from "child_process";
|
|
302
342
|
import path2 from "path";
|
|
303
343
|
import os2 from "os";
|
|
@@ -321,7 +361,7 @@ function canCoordinate(agentName, agentRole, employees = loadEmployeesSync()) {
|
|
|
321
361
|
return agentName === "default" || isCoordinatorRole(agentRole) || isCoordinatorName(agentName, employees);
|
|
322
362
|
}
|
|
323
363
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
324
|
-
if (!
|
|
364
|
+
if (!existsSync3(employeesPath)) return [];
|
|
325
365
|
try {
|
|
326
366
|
return JSON.parse(readFileSync2(employeesPath, "utf-8"));
|
|
327
367
|
} catch {
|
|
@@ -331,7 +371,7 @@ function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
|
331
371
|
function getEmployee(employees, name) {
|
|
332
372
|
return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
|
|
333
373
|
}
|
|
334
|
-
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE;
|
|
374
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, IDENTITY_DIR;
|
|
335
375
|
var init_employees = __esm({
|
|
336
376
|
"src/lib/employees.ts"() {
|
|
337
377
|
"use strict";
|
|
@@ -339,6 +379,7 @@ var init_employees = __esm({
|
|
|
339
379
|
EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
340
380
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
341
381
|
COORDINATOR_ROLE = "COO";
|
|
382
|
+
IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
|
|
342
383
|
}
|
|
343
384
|
});
|
|
344
385
|
|
|
@@ -516,7 +557,7 @@ var init_runtime_table = __esm({
|
|
|
516
557
|
});
|
|
517
558
|
|
|
518
559
|
// src/lib/agent-config.ts
|
|
519
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as
|
|
560
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4 } from "fs";
|
|
520
561
|
import path5 from "path";
|
|
521
562
|
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
522
563
|
var init_agent_config = __esm({
|
|
@@ -524,6 +565,7 @@ var init_agent_config = __esm({
|
|
|
524
565
|
"use strict";
|
|
525
566
|
init_config();
|
|
526
567
|
init_runtime_table();
|
|
568
|
+
init_secure_files();
|
|
527
569
|
AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
|
|
528
570
|
DEFAULT_MODELS = {
|
|
529
571
|
claude: "claude-opus-4",
|
|
@@ -534,7 +576,7 @@ var init_agent_config = __esm({
|
|
|
534
576
|
});
|
|
535
577
|
|
|
536
578
|
// src/lib/intercom-queue.ts
|
|
537
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as
|
|
579
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
538
580
|
import path6 from "path";
|
|
539
581
|
import os4 from "os";
|
|
540
582
|
var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
@@ -602,13 +644,634 @@ var init_db_retry = __esm({
|
|
|
602
644
|
}
|
|
603
645
|
});
|
|
604
646
|
|
|
647
|
+
// src/lib/database-adapter.ts
|
|
648
|
+
import os5 from "os";
|
|
649
|
+
import path7 from "path";
|
|
650
|
+
import { createRequire } from "module";
|
|
651
|
+
import { pathToFileURL } from "url";
|
|
652
|
+
function quotedIdentifier(identifier) {
|
|
653
|
+
return `"${identifier.replace(/"/g, '""')}"`;
|
|
654
|
+
}
|
|
655
|
+
function unqualifiedTableName(name) {
|
|
656
|
+
const raw = name.trim().replace(/^"|"$/g, "");
|
|
657
|
+
const parts = raw.split(".");
|
|
658
|
+
return parts[parts.length - 1].replace(/^"|"$/g, "").toLowerCase();
|
|
659
|
+
}
|
|
660
|
+
function stripTrailingSemicolon(sql) {
|
|
661
|
+
return sql.trim().replace(/;+\s*$/u, "");
|
|
662
|
+
}
|
|
663
|
+
function appendClause(sql, clause) {
|
|
664
|
+
const trimmed = stripTrailingSemicolon(sql);
|
|
665
|
+
const returningMatch = /\sRETURNING\b[\s\S]*$/iu.exec(trimmed);
|
|
666
|
+
if (!returningMatch) {
|
|
667
|
+
return `${trimmed}${clause}`;
|
|
668
|
+
}
|
|
669
|
+
const idx = returningMatch.index;
|
|
670
|
+
return `${trimmed.slice(0, idx)}${clause}${trimmed.slice(idx)}`;
|
|
671
|
+
}
|
|
672
|
+
function normalizeStatement(stmt) {
|
|
673
|
+
if (typeof stmt === "string") {
|
|
674
|
+
return { kind: "positional", sql: stmt, args: [] };
|
|
675
|
+
}
|
|
676
|
+
const sql = stmt.sql;
|
|
677
|
+
if (Array.isArray(stmt.args) || stmt.args === void 0) {
|
|
678
|
+
return { kind: "positional", sql, args: stmt.args ?? [] };
|
|
679
|
+
}
|
|
680
|
+
return { kind: "named", sql, args: stmt.args };
|
|
681
|
+
}
|
|
682
|
+
function rewriteBooleanLiterals(sql) {
|
|
683
|
+
let out = sql;
|
|
684
|
+
for (const column of BOOLEAN_COLUMN_NAMES) {
|
|
685
|
+
const scoped = `((?:\\b[a-z_][a-z0-9_]*\\.)?${column})`;
|
|
686
|
+
out = out.replace(new RegExp(`${scoped}\\s*=\\s*0\\b`, "giu"), "$1 = FALSE");
|
|
687
|
+
out = out.replace(new RegExp(`${scoped}\\s*=\\s*1\\b`, "giu"), "$1 = TRUE");
|
|
688
|
+
out = out.replace(new RegExp(`${scoped}\\s*!=\\s*0\\b`, "giu"), "$1 != FALSE");
|
|
689
|
+
out = out.replace(new RegExp(`${scoped}\\s*!=\\s*1\\b`, "giu"), "$1 != TRUE");
|
|
690
|
+
out = out.replace(new RegExp(`${scoped}\\s*<>\\s*0\\b`, "giu"), "$1 <> FALSE");
|
|
691
|
+
out = out.replace(new RegExp(`${scoped}\\s*<>\\s*1\\b`, "giu"), "$1 <> TRUE");
|
|
692
|
+
}
|
|
693
|
+
return out;
|
|
694
|
+
}
|
|
695
|
+
function rewriteInsertOrIgnore(sql) {
|
|
696
|
+
if (!/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu.test(sql)) {
|
|
697
|
+
return sql;
|
|
698
|
+
}
|
|
699
|
+
const replaced = sql.replace(/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu, "INSERT INTO");
|
|
700
|
+
return /\bON\s+CONFLICT\b/iu.test(replaced) ? replaced : appendClause(replaced, " ON CONFLICT DO NOTHING");
|
|
701
|
+
}
|
|
702
|
+
function rewriteInsertOrReplace(sql) {
|
|
703
|
+
const match = /^\s*INSERT\s+OR\s+REPLACE\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)([\s\S]*)$/iu.exec(sql);
|
|
704
|
+
if (!match) {
|
|
705
|
+
return sql;
|
|
706
|
+
}
|
|
707
|
+
const rawTable = match[1];
|
|
708
|
+
const rawColumns = match[2];
|
|
709
|
+
const remainder = match[3];
|
|
710
|
+
const tableName = unqualifiedTableName(rawTable);
|
|
711
|
+
const conflictKeys = UPSERT_KEYS[tableName];
|
|
712
|
+
if (!conflictKeys?.length) {
|
|
713
|
+
return sql;
|
|
714
|
+
}
|
|
715
|
+
const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
|
|
716
|
+
const updateColumns = columns.filter((col) => !conflictKeys.includes(col));
|
|
717
|
+
const conflictTarget = conflictKeys.map(quotedIdentifier).join(", ");
|
|
718
|
+
const updateClause = updateColumns.length === 0 ? " DO NOTHING" : ` DO UPDATE SET ${updateColumns.map((col) => `${quotedIdentifier(col)} = EXCLUDED.${quotedIdentifier(col)}`).join(", ")}`;
|
|
719
|
+
return `INSERT INTO ${rawTable} (${rawColumns})${appendClause(remainder, ` ON CONFLICT (${conflictTarget})${updateClause}`)}`;
|
|
720
|
+
}
|
|
721
|
+
function rewriteSql(sql) {
|
|
722
|
+
let out = sql;
|
|
723
|
+
out = out.replace(/\bdatetime\(\s*['"]now['"]\s*\)/giu, "CURRENT_TIMESTAMP");
|
|
724
|
+
out = out.replace(/\bvector32\s*\(\s*\?\s*\)/giu, "?");
|
|
725
|
+
out = rewriteBooleanLiterals(out);
|
|
726
|
+
out = rewriteInsertOrReplace(out);
|
|
727
|
+
out = rewriteInsertOrIgnore(out);
|
|
728
|
+
return stripTrailingSemicolon(out);
|
|
729
|
+
}
|
|
730
|
+
function toBoolean(value) {
|
|
731
|
+
if (value === null || value === void 0) return value;
|
|
732
|
+
if (typeof value === "boolean") return value;
|
|
733
|
+
if (typeof value === "number") return value !== 0;
|
|
734
|
+
if (typeof value === "bigint") return value !== 0n;
|
|
735
|
+
if (typeof value === "string") {
|
|
736
|
+
const normalized = value.trim().toLowerCase();
|
|
737
|
+
if (normalized === "0" || normalized === "false") return false;
|
|
738
|
+
if (normalized === "1" || normalized === "true") return true;
|
|
739
|
+
}
|
|
740
|
+
return Boolean(value);
|
|
741
|
+
}
|
|
742
|
+
function countQuestionMarks(sql, end) {
|
|
743
|
+
let count = 0;
|
|
744
|
+
let inSingle = false;
|
|
745
|
+
let inDouble = false;
|
|
746
|
+
let inLineComment = false;
|
|
747
|
+
let inBlockComment = false;
|
|
748
|
+
for (let i = 0; i < end; i++) {
|
|
749
|
+
const ch = sql[i];
|
|
750
|
+
const next = sql[i + 1];
|
|
751
|
+
if (inLineComment) {
|
|
752
|
+
if (ch === "\n") inLineComment = false;
|
|
753
|
+
continue;
|
|
754
|
+
}
|
|
755
|
+
if (inBlockComment) {
|
|
756
|
+
if (ch === "*" && next === "/") {
|
|
757
|
+
inBlockComment = false;
|
|
758
|
+
i += 1;
|
|
759
|
+
}
|
|
760
|
+
continue;
|
|
761
|
+
}
|
|
762
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
763
|
+
inLineComment = true;
|
|
764
|
+
i += 1;
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
768
|
+
inBlockComment = true;
|
|
769
|
+
i += 1;
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
773
|
+
inSingle = !inSingle;
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
776
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
777
|
+
inDouble = !inDouble;
|
|
778
|
+
continue;
|
|
779
|
+
}
|
|
780
|
+
if (!inSingle && !inDouble && ch === "?") {
|
|
781
|
+
count += 1;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
return count;
|
|
785
|
+
}
|
|
786
|
+
function findBooleanPlaceholderIndexes(sql) {
|
|
787
|
+
const indexes = /* @__PURE__ */ new Set();
|
|
788
|
+
for (const column of BOOLEAN_COLUMN_NAMES) {
|
|
789
|
+
const pattern = new RegExp(`(?:\\b[a-z_][a-z0-9_]*\\.)?${column}\\s*=\\s*\\?`, "giu");
|
|
790
|
+
for (const match of sql.matchAll(pattern)) {
|
|
791
|
+
const matchText = match[0];
|
|
792
|
+
const qIndex = match.index + matchText.lastIndexOf("?");
|
|
793
|
+
indexes.add(countQuestionMarks(sql, qIndex + 1));
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
return indexes;
|
|
797
|
+
}
|
|
798
|
+
function coerceInsertBooleanArgs(sql, args) {
|
|
799
|
+
const match = /^\s*INSERT(?:\s+OR\s+(?:IGNORE|REPLACE))?\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)/iu.exec(sql);
|
|
800
|
+
if (!match) return;
|
|
801
|
+
const rawTable = match[1];
|
|
802
|
+
const rawColumns = match[2];
|
|
803
|
+
const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
|
|
804
|
+
if (!boolColumns?.size) return;
|
|
805
|
+
const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
|
|
806
|
+
for (const [index, column] of columns.entries()) {
|
|
807
|
+
if (boolColumns.has(column) && index < args.length) {
|
|
808
|
+
args[index] = toBoolean(args[index]);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
function coerceUpdateBooleanArgs(sql, args) {
|
|
813
|
+
const match = /^\s*UPDATE\s+([A-Za-z0-9_."]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE\b|$)/iu.exec(sql);
|
|
814
|
+
if (!match) return;
|
|
815
|
+
const rawTable = match[1];
|
|
816
|
+
const setClause = match[2];
|
|
817
|
+
const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
|
|
818
|
+
if (!boolColumns?.size) return;
|
|
819
|
+
const assignments = setClause.split(",");
|
|
820
|
+
let placeholderIndex = 0;
|
|
821
|
+
for (const assignment of assignments) {
|
|
822
|
+
if (!assignment.includes("?")) continue;
|
|
823
|
+
placeholderIndex += 1;
|
|
824
|
+
const colMatch = /^\s*(?:[A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\?/iu.exec(assignment);
|
|
825
|
+
if (colMatch && boolColumns.has(colMatch[1])) {
|
|
826
|
+
args[placeholderIndex - 1] = toBoolean(args[placeholderIndex - 1]);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
function coerceBooleanArgs(sql, args) {
|
|
831
|
+
const nextArgs = [...args];
|
|
832
|
+
coerceInsertBooleanArgs(sql, nextArgs);
|
|
833
|
+
coerceUpdateBooleanArgs(sql, nextArgs);
|
|
834
|
+
const placeholderIndexes = findBooleanPlaceholderIndexes(sql);
|
|
835
|
+
for (const index of placeholderIndexes) {
|
|
836
|
+
if (index > 0 && index <= nextArgs.length) {
|
|
837
|
+
nextArgs[index - 1] = toBoolean(nextArgs[index - 1]);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
return nextArgs;
|
|
841
|
+
}
|
|
842
|
+
function convertQuestionMarksToDollarParams(sql) {
|
|
843
|
+
let out = "";
|
|
844
|
+
let placeholder = 0;
|
|
845
|
+
let inSingle = false;
|
|
846
|
+
let inDouble = false;
|
|
847
|
+
let inLineComment = false;
|
|
848
|
+
let inBlockComment = false;
|
|
849
|
+
for (let i = 0; i < sql.length; i++) {
|
|
850
|
+
const ch = sql[i];
|
|
851
|
+
const next = sql[i + 1];
|
|
852
|
+
if (inLineComment) {
|
|
853
|
+
out += ch;
|
|
854
|
+
if (ch === "\n") inLineComment = false;
|
|
855
|
+
continue;
|
|
856
|
+
}
|
|
857
|
+
if (inBlockComment) {
|
|
858
|
+
out += ch;
|
|
859
|
+
if (ch === "*" && next === "/") {
|
|
860
|
+
out += next;
|
|
861
|
+
inBlockComment = false;
|
|
862
|
+
i += 1;
|
|
863
|
+
}
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
866
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
867
|
+
out += ch + next;
|
|
868
|
+
inLineComment = true;
|
|
869
|
+
i += 1;
|
|
870
|
+
continue;
|
|
871
|
+
}
|
|
872
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
873
|
+
out += ch + next;
|
|
874
|
+
inBlockComment = true;
|
|
875
|
+
i += 1;
|
|
876
|
+
continue;
|
|
877
|
+
}
|
|
878
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
879
|
+
inSingle = !inSingle;
|
|
880
|
+
out += ch;
|
|
881
|
+
continue;
|
|
882
|
+
}
|
|
883
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
884
|
+
inDouble = !inDouble;
|
|
885
|
+
out += ch;
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
if (!inSingle && !inDouble && ch === "?") {
|
|
889
|
+
placeholder += 1;
|
|
890
|
+
out += `$${placeholder}`;
|
|
891
|
+
continue;
|
|
892
|
+
}
|
|
893
|
+
out += ch;
|
|
894
|
+
}
|
|
895
|
+
return out;
|
|
896
|
+
}
|
|
897
|
+
function translateStatementForPostgres(stmt) {
|
|
898
|
+
const normalized = normalizeStatement(stmt);
|
|
899
|
+
if (normalized.kind === "named") {
|
|
900
|
+
throw new Error("Named SQL parameters are not supported by the Prisma adapter.");
|
|
901
|
+
}
|
|
902
|
+
const rewrittenSql = rewriteSql(normalized.sql);
|
|
903
|
+
const coercedArgs = coerceBooleanArgs(rewrittenSql, normalized.args);
|
|
904
|
+
return {
|
|
905
|
+
sql: convertQuestionMarksToDollarParams(rewrittenSql),
|
|
906
|
+
args: coercedArgs
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
function shouldBypassPostgres(stmt) {
|
|
910
|
+
const normalized = normalizeStatement(stmt);
|
|
911
|
+
if (normalized.kind === "named") {
|
|
912
|
+
return true;
|
|
913
|
+
}
|
|
914
|
+
return IMMEDIATE_FALLBACK_PATTERNS.some((pattern) => pattern.test(normalized.sql));
|
|
915
|
+
}
|
|
916
|
+
function shouldFallbackOnError(error) {
|
|
917
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
918
|
+
return /42P01|42883|42601|does not exist|syntax error|not supported|Named SQL parameters are not supported/iu.test(message);
|
|
919
|
+
}
|
|
920
|
+
function isReadQuery(sql) {
|
|
921
|
+
const trimmed = sql.trimStart();
|
|
922
|
+
return /^(SELECT|WITH|SHOW|EXPLAIN|VALUES)\b/iu.test(trimmed) || /\bRETURNING\b/iu.test(trimmed);
|
|
923
|
+
}
|
|
924
|
+
function buildRow(row, columns) {
|
|
925
|
+
const values = columns.map((column) => row[column]);
|
|
926
|
+
return Object.assign(values, row);
|
|
927
|
+
}
|
|
928
|
+
function buildResultSet(rows, rowsAffected = 0) {
|
|
929
|
+
const columns = rows[0] ? Object.keys(rows[0]) : [];
|
|
930
|
+
const resultRows = rows.map((row) => buildRow(row, columns));
|
|
931
|
+
return {
|
|
932
|
+
columns,
|
|
933
|
+
columnTypes: columns.map(() => ""),
|
|
934
|
+
rows: resultRows,
|
|
935
|
+
rowsAffected,
|
|
936
|
+
lastInsertRowid: void 0,
|
|
937
|
+
toJSON() {
|
|
938
|
+
return {
|
|
939
|
+
columns,
|
|
940
|
+
columnTypes: columns.map(() => ""),
|
|
941
|
+
rows,
|
|
942
|
+
rowsAffected,
|
|
943
|
+
lastInsertRowid: void 0
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
async function loadPrismaClient() {
|
|
949
|
+
if (!prismaClientPromise) {
|
|
950
|
+
prismaClientPromise = (async () => {
|
|
951
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
952
|
+
if (explicitPath) {
|
|
953
|
+
const module2 = await import(pathToFileURL(explicitPath).href);
|
|
954
|
+
const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
|
|
955
|
+
if (!PrismaClient2) {
|
|
956
|
+
throw new Error(`No PrismaClient export found at ${explicitPath}`);
|
|
957
|
+
}
|
|
958
|
+
return new PrismaClient2();
|
|
959
|
+
}
|
|
960
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path7.join(os5.homedir(), "exe-db");
|
|
961
|
+
const requireFromExeDb = createRequire(path7.join(exeDbRoot, "package.json"));
|
|
962
|
+
const prismaEntry = requireFromExeDb.resolve("@prisma/client");
|
|
963
|
+
const module = await import(pathToFileURL(prismaEntry).href);
|
|
964
|
+
const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
|
|
965
|
+
if (!PrismaClient) {
|
|
966
|
+
throw new Error(`No PrismaClient export found in ${prismaEntry}`);
|
|
967
|
+
}
|
|
968
|
+
return new PrismaClient();
|
|
969
|
+
})();
|
|
970
|
+
}
|
|
971
|
+
return prismaClientPromise;
|
|
972
|
+
}
|
|
973
|
+
async function ensureCompatibilityViews(prisma) {
|
|
974
|
+
if (!compatibilityBootstrapPromise) {
|
|
975
|
+
compatibilityBootstrapPromise = (async () => {
|
|
976
|
+
for (const mapping of VIEW_MAPPINGS) {
|
|
977
|
+
const relation = mapping.source.replace(/"/g, "");
|
|
978
|
+
const rows = await prisma.$queryRawUnsafe(
|
|
979
|
+
"SELECT to_regclass($1) AS regclass",
|
|
980
|
+
relation
|
|
981
|
+
);
|
|
982
|
+
if (!rows[0]?.regclass) {
|
|
983
|
+
continue;
|
|
984
|
+
}
|
|
985
|
+
await prisma.$executeRawUnsafe(
|
|
986
|
+
`CREATE OR REPLACE VIEW public.${quotedIdentifier(mapping.view)} AS SELECT * FROM ${mapping.source}`
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
})();
|
|
990
|
+
}
|
|
991
|
+
return compatibilityBootstrapPromise;
|
|
992
|
+
}
|
|
993
|
+
async function executeOnPrisma(executor, stmt) {
|
|
994
|
+
const translated = translateStatementForPostgres(stmt);
|
|
995
|
+
if (isReadQuery(translated.sql)) {
|
|
996
|
+
const rows = await executor.$queryRawUnsafe(
|
|
997
|
+
translated.sql,
|
|
998
|
+
...translated.args
|
|
999
|
+
);
|
|
1000
|
+
return buildResultSet(rows, /\bRETURNING\b/iu.test(translated.sql) ? rows.length : 0);
|
|
1001
|
+
}
|
|
1002
|
+
const rowsAffected = await executor.$executeRawUnsafe(translated.sql, ...translated.args);
|
|
1003
|
+
return buildResultSet([], rowsAffected);
|
|
1004
|
+
}
|
|
1005
|
+
function splitSqlStatements(sql) {
|
|
1006
|
+
const parts = [];
|
|
1007
|
+
let current = "";
|
|
1008
|
+
let inSingle = false;
|
|
1009
|
+
let inDouble = false;
|
|
1010
|
+
let inLineComment = false;
|
|
1011
|
+
let inBlockComment = false;
|
|
1012
|
+
for (let i = 0; i < sql.length; i++) {
|
|
1013
|
+
const ch = sql[i];
|
|
1014
|
+
const next = sql[i + 1];
|
|
1015
|
+
if (inLineComment) {
|
|
1016
|
+
current += ch;
|
|
1017
|
+
if (ch === "\n") inLineComment = false;
|
|
1018
|
+
continue;
|
|
1019
|
+
}
|
|
1020
|
+
if (inBlockComment) {
|
|
1021
|
+
current += ch;
|
|
1022
|
+
if (ch === "*" && next === "/") {
|
|
1023
|
+
current += next;
|
|
1024
|
+
inBlockComment = false;
|
|
1025
|
+
i += 1;
|
|
1026
|
+
}
|
|
1027
|
+
continue;
|
|
1028
|
+
}
|
|
1029
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
1030
|
+
current += ch + next;
|
|
1031
|
+
inLineComment = true;
|
|
1032
|
+
i += 1;
|
|
1033
|
+
continue;
|
|
1034
|
+
}
|
|
1035
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
1036
|
+
current += ch + next;
|
|
1037
|
+
inBlockComment = true;
|
|
1038
|
+
i += 1;
|
|
1039
|
+
continue;
|
|
1040
|
+
}
|
|
1041
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
1042
|
+
inSingle = !inSingle;
|
|
1043
|
+
current += ch;
|
|
1044
|
+
continue;
|
|
1045
|
+
}
|
|
1046
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
1047
|
+
inDouble = !inDouble;
|
|
1048
|
+
current += ch;
|
|
1049
|
+
continue;
|
|
1050
|
+
}
|
|
1051
|
+
if (!inSingle && !inDouble && ch === ";") {
|
|
1052
|
+
if (current.trim()) {
|
|
1053
|
+
parts.push(current.trim());
|
|
1054
|
+
}
|
|
1055
|
+
current = "";
|
|
1056
|
+
continue;
|
|
1057
|
+
}
|
|
1058
|
+
current += ch;
|
|
1059
|
+
}
|
|
1060
|
+
if (current.trim()) {
|
|
1061
|
+
parts.push(current.trim());
|
|
1062
|
+
}
|
|
1063
|
+
return parts;
|
|
1064
|
+
}
|
|
1065
|
+
async function createPrismaDbAdapter(fallbackClient) {
|
|
1066
|
+
const prisma = await loadPrismaClient();
|
|
1067
|
+
await ensureCompatibilityViews(prisma);
|
|
1068
|
+
let closed = false;
|
|
1069
|
+
let adapter;
|
|
1070
|
+
const fallbackExecute = async (stmt, error) => {
|
|
1071
|
+
if (!fallbackClient) {
|
|
1072
|
+
if (error) throw error;
|
|
1073
|
+
throw new Error("No fallback SQLite client is available for this Prisma-routed query.");
|
|
1074
|
+
}
|
|
1075
|
+
if (error) {
|
|
1076
|
+
process.stderr.write(
|
|
1077
|
+
`[database-adapter] Falling back to SQLite: ${error instanceof Error ? error.message : String(error)}
|
|
1078
|
+
`
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
return fallbackClient.execute(stmt);
|
|
1082
|
+
};
|
|
1083
|
+
adapter = {
|
|
1084
|
+
async execute(stmt) {
|
|
1085
|
+
if (shouldBypassPostgres(stmt)) {
|
|
1086
|
+
return fallbackExecute(stmt);
|
|
1087
|
+
}
|
|
1088
|
+
try {
|
|
1089
|
+
return await executeOnPrisma(prisma, stmt);
|
|
1090
|
+
} catch (error) {
|
|
1091
|
+
if (shouldFallbackOnError(error)) {
|
|
1092
|
+
return fallbackExecute(stmt, error);
|
|
1093
|
+
}
|
|
1094
|
+
throw error;
|
|
1095
|
+
}
|
|
1096
|
+
},
|
|
1097
|
+
async batch(stmts, mode) {
|
|
1098
|
+
if (stmts.some((stmt) => shouldBypassPostgres(stmt))) {
|
|
1099
|
+
if (!fallbackClient) {
|
|
1100
|
+
throw new Error("Cannot batch unsupported SQLite-only statements without a fallback client.");
|
|
1101
|
+
}
|
|
1102
|
+
return fallbackClient.batch(stmts, mode);
|
|
1103
|
+
}
|
|
1104
|
+
try {
|
|
1105
|
+
if (prisma.$transaction) {
|
|
1106
|
+
return await prisma.$transaction(async (tx) => {
|
|
1107
|
+
const results2 = [];
|
|
1108
|
+
for (const stmt of stmts) {
|
|
1109
|
+
results2.push(await executeOnPrisma(tx, stmt));
|
|
1110
|
+
}
|
|
1111
|
+
return results2;
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
const results = [];
|
|
1115
|
+
for (const stmt of stmts) {
|
|
1116
|
+
results.push(await executeOnPrisma(prisma, stmt));
|
|
1117
|
+
}
|
|
1118
|
+
return results;
|
|
1119
|
+
} catch (error) {
|
|
1120
|
+
if (fallbackClient && shouldFallbackOnError(error)) {
|
|
1121
|
+
process.stderr.write(
|
|
1122
|
+
`[database-adapter] Falling back batch to SQLite: ${error instanceof Error ? error.message : String(error)}
|
|
1123
|
+
`
|
|
1124
|
+
);
|
|
1125
|
+
return fallbackClient.batch(stmts, mode);
|
|
1126
|
+
}
|
|
1127
|
+
throw error;
|
|
1128
|
+
}
|
|
1129
|
+
},
|
|
1130
|
+
async migrate(stmts) {
|
|
1131
|
+
if (fallbackClient) {
|
|
1132
|
+
return fallbackClient.migrate(stmts);
|
|
1133
|
+
}
|
|
1134
|
+
return adapter.batch(stmts, "deferred");
|
|
1135
|
+
},
|
|
1136
|
+
async transaction(mode) {
|
|
1137
|
+
if (!fallbackClient) {
|
|
1138
|
+
throw new Error("Interactive transactions are only supported on the SQLite fallback client.");
|
|
1139
|
+
}
|
|
1140
|
+
return fallbackClient.transaction(mode);
|
|
1141
|
+
},
|
|
1142
|
+
async executeMultiple(sql) {
|
|
1143
|
+
if (fallbackClient && shouldBypassPostgres(sql)) {
|
|
1144
|
+
return fallbackClient.executeMultiple(sql);
|
|
1145
|
+
}
|
|
1146
|
+
for (const statement of splitSqlStatements(sql)) {
|
|
1147
|
+
await adapter.execute(statement);
|
|
1148
|
+
}
|
|
1149
|
+
},
|
|
1150
|
+
async sync() {
|
|
1151
|
+
if (fallbackClient) {
|
|
1152
|
+
return fallbackClient.sync();
|
|
1153
|
+
}
|
|
1154
|
+
return { frame_no: 0, frames_synced: 0 };
|
|
1155
|
+
},
|
|
1156
|
+
close() {
|
|
1157
|
+
closed = true;
|
|
1158
|
+
prismaClientPromise = null;
|
|
1159
|
+
compatibilityBootstrapPromise = null;
|
|
1160
|
+
void prisma.$disconnect?.();
|
|
1161
|
+
},
|
|
1162
|
+
get closed() {
|
|
1163
|
+
return closed;
|
|
1164
|
+
},
|
|
1165
|
+
get protocol() {
|
|
1166
|
+
return "prisma-postgres";
|
|
1167
|
+
}
|
|
1168
|
+
};
|
|
1169
|
+
return adapter;
|
|
1170
|
+
}
|
|
1171
|
+
var VIEW_MAPPINGS, UPSERT_KEYS, BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES, IMMEDIATE_FALLBACK_PATTERNS, prismaClientPromise, compatibilityBootstrapPromise;
|
|
1172
|
+
var init_database_adapter = __esm({
|
|
1173
|
+
"src/lib/database-adapter.ts"() {
|
|
1174
|
+
"use strict";
|
|
1175
|
+
VIEW_MAPPINGS = [
|
|
1176
|
+
{ view: "memories", source: "memory.memory_records" },
|
|
1177
|
+
{ view: "tasks", source: "memory.tasks" },
|
|
1178
|
+
{ view: "behaviors", source: "memory.behaviors" },
|
|
1179
|
+
{ view: "entities", source: "memory.entities" },
|
|
1180
|
+
{ view: "relationships", source: "memory.relationships" },
|
|
1181
|
+
{ view: "entity_memories", source: "memory.entity_memories" },
|
|
1182
|
+
{ view: "entity_aliases", source: "memory.entity_aliases" },
|
|
1183
|
+
{ view: "notifications", source: "memory.notifications" },
|
|
1184
|
+
{ view: "messages", source: "memory.messages" },
|
|
1185
|
+
{ view: "users", source: "wiki.users" },
|
|
1186
|
+
{ view: "workspaces", source: "wiki.workspaces" },
|
|
1187
|
+
{ view: "workspace_users", source: "wiki.workspace_users" },
|
|
1188
|
+
{ view: "documents", source: "wiki.workspace_documents" },
|
|
1189
|
+
{ view: "chats", source: "wiki.workspace_chats" }
|
|
1190
|
+
];
|
|
1191
|
+
UPSERT_KEYS = {
|
|
1192
|
+
memories: ["id"],
|
|
1193
|
+
tasks: ["id"],
|
|
1194
|
+
behaviors: ["id"],
|
|
1195
|
+
entities: ["id"],
|
|
1196
|
+
relationships: ["id"],
|
|
1197
|
+
entity_aliases: ["alias"],
|
|
1198
|
+
notifications: ["id"],
|
|
1199
|
+
messages: ["id"],
|
|
1200
|
+
users: ["id"],
|
|
1201
|
+
workspaces: ["id"],
|
|
1202
|
+
workspace_users: ["id"],
|
|
1203
|
+
documents: ["id"],
|
|
1204
|
+
chats: ["id"]
|
|
1205
|
+
};
|
|
1206
|
+
BOOLEAN_COLUMNS_BY_TABLE = {
|
|
1207
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
1208
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
1209
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
1210
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
1211
|
+
};
|
|
1212
|
+
BOOLEAN_COLUMN_NAMES = new Set(
|
|
1213
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
1214
|
+
);
|
|
1215
|
+
IMMEDIATE_FALLBACK_PATTERNS = [
|
|
1216
|
+
/\bPRAGMA\b/i,
|
|
1217
|
+
/\bsqlite_master\b/i,
|
|
1218
|
+
/(?:^|[.\s])(?:memories|conversations|entities)_fts\b/i,
|
|
1219
|
+
/\bMATCH\b/i,
|
|
1220
|
+
/\bvector_distance_cos\s*\(/i,
|
|
1221
|
+
/\bjson_extract\s*\(/i,
|
|
1222
|
+
/\bjulianday\s*\(/i,
|
|
1223
|
+
/\bstrftime\s*\(/i,
|
|
1224
|
+
/\blast_insert_rowid\s*\(/i
|
|
1225
|
+
];
|
|
1226
|
+
prismaClientPromise = null;
|
|
1227
|
+
compatibilityBootstrapPromise = null;
|
|
1228
|
+
}
|
|
1229
|
+
});
|
|
1230
|
+
|
|
1231
|
+
// src/lib/daemon-auth.ts
|
|
1232
|
+
import crypto from "crypto";
|
|
1233
|
+
import path8 from "path";
|
|
1234
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
1235
|
+
function normalizeToken(token) {
|
|
1236
|
+
if (!token) return null;
|
|
1237
|
+
const trimmed = token.trim();
|
|
1238
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1239
|
+
}
|
|
1240
|
+
function readDaemonToken() {
|
|
1241
|
+
try {
|
|
1242
|
+
if (!existsSync6(DAEMON_TOKEN_PATH)) return null;
|
|
1243
|
+
return normalizeToken(readFileSync6(DAEMON_TOKEN_PATH, "utf8"));
|
|
1244
|
+
} catch {
|
|
1245
|
+
return null;
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
function ensureDaemonToken(seed) {
|
|
1249
|
+
const existing = readDaemonToken();
|
|
1250
|
+
if (existing) return existing;
|
|
1251
|
+
const token = normalizeToken(seed) ?? crypto.randomBytes(32).toString("hex");
|
|
1252
|
+
ensurePrivateDirSync(EXE_AI_DIR);
|
|
1253
|
+
writeFileSync5(DAEMON_TOKEN_PATH, `${token}
|
|
1254
|
+
`, "utf8");
|
|
1255
|
+
enforcePrivateFileSync(DAEMON_TOKEN_PATH);
|
|
1256
|
+
return token;
|
|
1257
|
+
}
|
|
1258
|
+
var DAEMON_TOKEN_PATH;
|
|
1259
|
+
var init_daemon_auth = __esm({
|
|
1260
|
+
"src/lib/daemon-auth.ts"() {
|
|
1261
|
+
"use strict";
|
|
1262
|
+
init_config();
|
|
1263
|
+
init_secure_files();
|
|
1264
|
+
DAEMON_TOKEN_PATH = path8.join(EXE_AI_DIR, "exed.token");
|
|
1265
|
+
}
|
|
1266
|
+
});
|
|
1267
|
+
|
|
605
1268
|
// src/lib/exe-daemon-client.ts
|
|
606
1269
|
import net from "net";
|
|
607
|
-
import
|
|
1270
|
+
import os6 from "os";
|
|
608
1271
|
import { spawn } from "child_process";
|
|
609
1272
|
import { randomUUID } from "crypto";
|
|
610
|
-
import { existsSync as
|
|
611
|
-
import
|
|
1273
|
+
import { existsSync as existsSync7, unlinkSync as unlinkSync3, readFileSync as readFileSync7, openSync, closeSync, statSync } from "fs";
|
|
1274
|
+
import path9 from "path";
|
|
612
1275
|
import { fileURLToPath } from "url";
|
|
613
1276
|
function handleData(chunk) {
|
|
614
1277
|
_buffer += chunk.toString();
|
|
@@ -636,9 +1299,9 @@ function handleData(chunk) {
|
|
|
636
1299
|
}
|
|
637
1300
|
}
|
|
638
1301
|
function cleanupStaleFiles() {
|
|
639
|
-
if (
|
|
1302
|
+
if (existsSync7(PID_PATH)) {
|
|
640
1303
|
try {
|
|
641
|
-
const pid = parseInt(
|
|
1304
|
+
const pid = parseInt(readFileSync7(PID_PATH, "utf8").trim(), 10);
|
|
642
1305
|
if (pid > 0) {
|
|
643
1306
|
try {
|
|
644
1307
|
process.kill(pid, 0);
|
|
@@ -659,17 +1322,17 @@ function cleanupStaleFiles() {
|
|
|
659
1322
|
}
|
|
660
1323
|
}
|
|
661
1324
|
function findPackageRoot() {
|
|
662
|
-
let dir =
|
|
663
|
-
const { root } =
|
|
1325
|
+
let dir = path9.dirname(fileURLToPath(import.meta.url));
|
|
1326
|
+
const { root } = path9.parse(dir);
|
|
664
1327
|
while (dir !== root) {
|
|
665
|
-
if (
|
|
666
|
-
dir =
|
|
1328
|
+
if (existsSync7(path9.join(dir, "package.json"))) return dir;
|
|
1329
|
+
dir = path9.dirname(dir);
|
|
667
1330
|
}
|
|
668
1331
|
return null;
|
|
669
1332
|
}
|
|
670
1333
|
function spawnDaemon() {
|
|
671
|
-
const freeGB =
|
|
672
|
-
const totalGB =
|
|
1334
|
+
const freeGB = os6.freemem() / (1024 * 1024 * 1024);
|
|
1335
|
+
const totalGB = os6.totalmem() / (1024 * 1024 * 1024);
|
|
673
1336
|
if (totalGB <= 8) {
|
|
674
1337
|
process.stderr.write(
|
|
675
1338
|
`[exed-client] SKIP: ${totalGB.toFixed(0)}GB system \u2014 embedding daemon disabled. Using keyword search only. Minimum 16GB recommended for vector search.
|
|
@@ -689,16 +1352,17 @@ function spawnDaemon() {
|
|
|
689
1352
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
690
1353
|
return;
|
|
691
1354
|
}
|
|
692
|
-
const daemonPath =
|
|
693
|
-
if (!
|
|
1355
|
+
const daemonPath = path9.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
1356
|
+
if (!existsSync7(daemonPath)) {
|
|
694
1357
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
695
1358
|
`);
|
|
696
1359
|
return;
|
|
697
1360
|
}
|
|
698
1361
|
const resolvedPath = daemonPath;
|
|
1362
|
+
const daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV] ?? null);
|
|
699
1363
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
700
1364
|
`);
|
|
701
|
-
const logPath =
|
|
1365
|
+
const logPath = path9.join(path9.dirname(SOCKET_PATH), "exed.log");
|
|
702
1366
|
let stderrFd = "ignore";
|
|
703
1367
|
try {
|
|
704
1368
|
stderrFd = openSync(logPath, "a");
|
|
@@ -716,7 +1380,8 @@ function spawnDaemon() {
|
|
|
716
1380
|
TMUX_PANE: void 0,
|
|
717
1381
|
// Prevents resolveExeSession() from scoping to one session
|
|
718
1382
|
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
719
|
-
EXE_DAEMON_PID: PID_PATH
|
|
1383
|
+
EXE_DAEMON_PID: PID_PATH,
|
|
1384
|
+
[DAEMON_TOKEN_ENV]: daemonToken
|
|
720
1385
|
}
|
|
721
1386
|
});
|
|
722
1387
|
child.unref();
|
|
@@ -823,13 +1488,14 @@ function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
|
823
1488
|
return;
|
|
824
1489
|
}
|
|
825
1490
|
const id = randomUUID();
|
|
1491
|
+
const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
|
|
826
1492
|
const timer = setTimeout(() => {
|
|
827
1493
|
_pending.delete(id);
|
|
828
1494
|
resolve({ error: "Request timeout" });
|
|
829
1495
|
}, timeoutMs);
|
|
830
1496
|
_pending.set(id, { resolve, timer });
|
|
831
1497
|
try {
|
|
832
|
-
_socket.write(JSON.stringify({ id, ...payload }) + "\n");
|
|
1498
|
+
_socket.write(JSON.stringify({ id, token, ...payload }) + "\n");
|
|
833
1499
|
} catch {
|
|
834
1500
|
clearTimeout(timer);
|
|
835
1501
|
_pending.delete(id);
|
|
@@ -840,17 +1506,19 @@ function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
|
840
1506
|
function isClientConnected() {
|
|
841
1507
|
return _connected;
|
|
842
1508
|
}
|
|
843
|
-
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _pending, MAX_BUFFER;
|
|
1509
|
+
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, DAEMON_TOKEN_ENV, _socket, _connected, _buffer, _pending, MAX_BUFFER;
|
|
844
1510
|
var init_exe_daemon_client = __esm({
|
|
845
1511
|
"src/lib/exe-daemon-client.ts"() {
|
|
846
1512
|
"use strict";
|
|
847
1513
|
init_config();
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
1514
|
+
init_daemon_auth();
|
|
1515
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path9.join(EXE_AI_DIR, "exed.sock");
|
|
1516
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path9.join(EXE_AI_DIR, "exed.pid");
|
|
1517
|
+
SPAWN_LOCK_PATH = path9.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
851
1518
|
SPAWN_LOCK_STALE_MS = 3e4;
|
|
852
1519
|
CONNECT_TIMEOUT_MS = 15e3;
|
|
853
1520
|
REQUEST_TIMEOUT_MS = 3e4;
|
|
1521
|
+
DAEMON_TOKEN_ENV = "EXE_DAEMON_TOKEN";
|
|
854
1522
|
_socket = null;
|
|
855
1523
|
_connected = false;
|
|
856
1524
|
_buffer = "";
|
|
@@ -929,7 +1597,7 @@ __export(db_daemon_client_exports, {
|
|
|
929
1597
|
createDaemonDbClient: () => createDaemonDbClient,
|
|
930
1598
|
initDaemonDbClient: () => initDaemonDbClient
|
|
931
1599
|
});
|
|
932
|
-
function
|
|
1600
|
+
function normalizeStatement2(stmt) {
|
|
933
1601
|
if (typeof stmt === "string") {
|
|
934
1602
|
return { sql: stmt, args: [] };
|
|
935
1603
|
}
|
|
@@ -953,7 +1621,7 @@ function createDaemonDbClient(fallbackClient) {
|
|
|
953
1621
|
if (!_useDaemon || !isClientConnected()) {
|
|
954
1622
|
return fallbackClient.execute(stmt);
|
|
955
1623
|
}
|
|
956
|
-
const { sql, args } =
|
|
1624
|
+
const { sql, args } = normalizeStatement2(stmt);
|
|
957
1625
|
const response = await sendDaemonRequest({
|
|
958
1626
|
type: "db-execute",
|
|
959
1627
|
sql,
|
|
@@ -978,7 +1646,7 @@ function createDaemonDbClient(fallbackClient) {
|
|
|
978
1646
|
if (!_useDaemon || !isClientConnected()) {
|
|
979
1647
|
return fallbackClient.batch(stmts, mode);
|
|
980
1648
|
}
|
|
981
|
-
const statements = stmts.map(
|
|
1649
|
+
const statements = stmts.map(normalizeStatement2);
|
|
982
1650
|
const response = await sendDaemonRequest({
|
|
983
1651
|
type: "db-batch",
|
|
984
1652
|
statements,
|
|
@@ -1073,6 +1741,18 @@ __export(database_exports, {
|
|
|
1073
1741
|
});
|
|
1074
1742
|
import { createClient } from "@libsql/client";
|
|
1075
1743
|
async function initDatabase(config) {
|
|
1744
|
+
if (_walCheckpointTimer) {
|
|
1745
|
+
clearInterval(_walCheckpointTimer);
|
|
1746
|
+
_walCheckpointTimer = null;
|
|
1747
|
+
}
|
|
1748
|
+
if (_daemonClient) {
|
|
1749
|
+
_daemonClient.close();
|
|
1750
|
+
_daemonClient = null;
|
|
1751
|
+
}
|
|
1752
|
+
if (_adapterClient && _adapterClient !== _resilientClient) {
|
|
1753
|
+
_adapterClient.close();
|
|
1754
|
+
}
|
|
1755
|
+
_adapterClient = null;
|
|
1076
1756
|
if (_client) {
|
|
1077
1757
|
_client.close();
|
|
1078
1758
|
_client = null;
|
|
@@ -1086,6 +1766,7 @@ async function initDatabase(config) {
|
|
|
1086
1766
|
}
|
|
1087
1767
|
_client = createClient(opts);
|
|
1088
1768
|
_resilientClient = wrapWithRetry(_client);
|
|
1769
|
+
_adapterClient = _resilientClient;
|
|
1089
1770
|
_client.execute("PRAGMA busy_timeout = 30000").catch(() => {
|
|
1090
1771
|
});
|
|
1091
1772
|
_client.execute("PRAGMA journal_mode = WAL").catch(() => {
|
|
@@ -1096,14 +1777,20 @@ async function initDatabase(config) {
|
|
|
1096
1777
|
});
|
|
1097
1778
|
}, 3e4);
|
|
1098
1779
|
_walCheckpointTimer.unref();
|
|
1780
|
+
if (process.env.DATABASE_URL) {
|
|
1781
|
+
_adapterClient = await createPrismaDbAdapter(_resilientClient);
|
|
1782
|
+
}
|
|
1099
1783
|
}
|
|
1100
1784
|
function isInitialized() {
|
|
1101
|
-
return _client !== null;
|
|
1785
|
+
return _adapterClient !== null || _client !== null;
|
|
1102
1786
|
}
|
|
1103
1787
|
function getClient() {
|
|
1104
|
-
if (!
|
|
1788
|
+
if (!_adapterClient) {
|
|
1105
1789
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
1106
1790
|
}
|
|
1791
|
+
if (process.env.DATABASE_URL) {
|
|
1792
|
+
return _adapterClient;
|
|
1793
|
+
}
|
|
1107
1794
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
1108
1795
|
return _resilientClient;
|
|
1109
1796
|
}
|
|
@@ -1113,6 +1800,7 @@ function getClient() {
|
|
|
1113
1800
|
return _resilientClient;
|
|
1114
1801
|
}
|
|
1115
1802
|
async function initDaemonClient() {
|
|
1803
|
+
if (process.env.DATABASE_URL) return;
|
|
1116
1804
|
if (process.env.EXE_IS_DAEMON === "1") return;
|
|
1117
1805
|
if (!_resilientClient) return;
|
|
1118
1806
|
try {
|
|
@@ -1409,6 +2097,7 @@ async function ensureSchema() {
|
|
|
1409
2097
|
project TEXT NOT NULL,
|
|
1410
2098
|
summary TEXT NOT NULL,
|
|
1411
2099
|
task_file TEXT,
|
|
2100
|
+
session_scope TEXT,
|
|
1412
2101
|
read INTEGER NOT NULL DEFAULT 0,
|
|
1413
2102
|
created_at TEXT NOT NULL
|
|
1414
2103
|
);
|
|
@@ -1417,7 +2106,7 @@ async function ensureSchema() {
|
|
|
1417
2106
|
ON notifications(read);
|
|
1418
2107
|
|
|
1419
2108
|
CREATE INDEX IF NOT EXISTS idx_notifications_agent
|
|
1420
|
-
ON notifications(agent_id);
|
|
2109
|
+
ON notifications(agent_id, session_scope);
|
|
1421
2110
|
|
|
1422
2111
|
CREATE INDEX IF NOT EXISTS idx_notifications_task_file
|
|
1423
2112
|
ON notifications(task_file);
|
|
@@ -1455,6 +2144,7 @@ async function ensureSchema() {
|
|
|
1455
2144
|
target_agent TEXT NOT NULL,
|
|
1456
2145
|
target_project TEXT,
|
|
1457
2146
|
target_device TEXT NOT NULL DEFAULT 'local',
|
|
2147
|
+
session_scope TEXT,
|
|
1458
2148
|
content TEXT NOT NULL,
|
|
1459
2149
|
priority TEXT DEFAULT 'normal',
|
|
1460
2150
|
status TEXT DEFAULT 'pending',
|
|
@@ -1468,10 +2158,31 @@ async function ensureSchema() {
|
|
|
1468
2158
|
);
|
|
1469
2159
|
|
|
1470
2160
|
CREATE INDEX IF NOT EXISTS idx_messages_target
|
|
1471
|
-
ON messages(target_agent, status);
|
|
2161
|
+
ON messages(target_agent, session_scope, status);
|
|
1472
2162
|
|
|
1473
2163
|
CREATE INDEX IF NOT EXISTS idx_messages_conversation_order
|
|
1474
|
-
ON messages(target_agent, from_agent, server_seq);
|
|
2164
|
+
ON messages(target_agent, session_scope, from_agent, server_seq);
|
|
2165
|
+
`);
|
|
2166
|
+
try {
|
|
2167
|
+
await client.execute({
|
|
2168
|
+
sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
|
|
2169
|
+
args: []
|
|
2170
|
+
});
|
|
2171
|
+
} catch {
|
|
2172
|
+
}
|
|
2173
|
+
try {
|
|
2174
|
+
await client.execute({
|
|
2175
|
+
sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
|
|
2176
|
+
args: []
|
|
2177
|
+
});
|
|
2178
|
+
} catch {
|
|
2179
|
+
}
|
|
2180
|
+
await client.executeMultiple(`
|
|
2181
|
+
CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
|
|
2182
|
+
ON notifications(agent_id, session_scope, read, created_at);
|
|
2183
|
+
|
|
2184
|
+
CREATE INDEX IF NOT EXISTS idx_messages_target_scope_status
|
|
2185
|
+
ON messages(target_agent, session_scope, status, created_at);
|
|
1475
2186
|
`);
|
|
1476
2187
|
try {
|
|
1477
2188
|
await client.execute({
|
|
@@ -2055,52 +2766,72 @@ async function ensureSchema() {
|
|
|
2055
2766
|
} catch {
|
|
2056
2767
|
}
|
|
2057
2768
|
}
|
|
2769
|
+
try {
|
|
2770
|
+
await client.execute({
|
|
2771
|
+
sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
|
|
2772
|
+
args: []
|
|
2773
|
+
});
|
|
2774
|
+
} catch {
|
|
2775
|
+
}
|
|
2058
2776
|
}
|
|
2059
2777
|
async function disposeDatabase() {
|
|
2778
|
+
if (_walCheckpointTimer) {
|
|
2779
|
+
clearInterval(_walCheckpointTimer);
|
|
2780
|
+
_walCheckpointTimer = null;
|
|
2781
|
+
}
|
|
2060
2782
|
if (_daemonClient) {
|
|
2061
2783
|
_daemonClient.close();
|
|
2062
2784
|
_daemonClient = null;
|
|
2063
2785
|
}
|
|
2786
|
+
if (_adapterClient && _adapterClient !== _resilientClient) {
|
|
2787
|
+
_adapterClient.close();
|
|
2788
|
+
}
|
|
2789
|
+
_adapterClient = null;
|
|
2064
2790
|
if (_client) {
|
|
2065
2791
|
_client.close();
|
|
2066
2792
|
_client = null;
|
|
2067
2793
|
_resilientClient = null;
|
|
2068
2794
|
}
|
|
2069
2795
|
}
|
|
2070
|
-
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
|
|
2796
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
|
|
2071
2797
|
var init_database = __esm({
|
|
2072
2798
|
"src/lib/database.ts"() {
|
|
2073
2799
|
"use strict";
|
|
2074
2800
|
init_db_retry();
|
|
2075
2801
|
init_employees();
|
|
2802
|
+
init_database_adapter();
|
|
2076
2803
|
_client = null;
|
|
2077
2804
|
_resilientClient = null;
|
|
2078
2805
|
_walCheckpointTimer = null;
|
|
2079
2806
|
_daemonClient = null;
|
|
2807
|
+
_adapterClient = null;
|
|
2080
2808
|
initTurso = initDatabase;
|
|
2081
2809
|
disposeTurso = disposeDatabase;
|
|
2082
2810
|
}
|
|
2083
2811
|
});
|
|
2084
2812
|
|
|
2085
2813
|
// src/lib/license.ts
|
|
2086
|
-
import { readFileSync as
|
|
2814
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
|
|
2087
2815
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2088
|
-
import
|
|
2816
|
+
import { createRequire as createRequire2 } from "module";
|
|
2817
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
2818
|
+
import os7 from "os";
|
|
2819
|
+
import path10 from "path";
|
|
2089
2820
|
import { jwtVerify, importSPKI } from "jose";
|
|
2090
2821
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
2091
2822
|
var init_license = __esm({
|
|
2092
2823
|
"src/lib/license.ts"() {
|
|
2093
2824
|
"use strict";
|
|
2094
2825
|
init_config();
|
|
2095
|
-
LICENSE_PATH =
|
|
2096
|
-
CACHE_PATH =
|
|
2097
|
-
DEVICE_ID_PATH =
|
|
2826
|
+
LICENSE_PATH = path10.join(EXE_AI_DIR, "license.key");
|
|
2827
|
+
CACHE_PATH = path10.join(EXE_AI_DIR, "license-cache.json");
|
|
2828
|
+
DEVICE_ID_PATH = path10.join(EXE_AI_DIR, "device-id");
|
|
2098
2829
|
}
|
|
2099
2830
|
});
|
|
2100
2831
|
|
|
2101
2832
|
// src/lib/plan-limits.ts
|
|
2102
|
-
import { readFileSync as
|
|
2103
|
-
import
|
|
2833
|
+
import { readFileSync as readFileSync9, existsSync as existsSync9 } from "fs";
|
|
2834
|
+
import path11 from "path";
|
|
2104
2835
|
var CACHE_PATH2;
|
|
2105
2836
|
var init_plan_limits = __esm({
|
|
2106
2837
|
"src/lib/plan-limits.ts"() {
|
|
@@ -2109,14 +2840,14 @@ var init_plan_limits = __esm({
|
|
|
2109
2840
|
init_employees();
|
|
2110
2841
|
init_license();
|
|
2111
2842
|
init_config();
|
|
2112
|
-
CACHE_PATH2 =
|
|
2843
|
+
CACHE_PATH2 = path11.join(EXE_AI_DIR, "license-cache.json");
|
|
2113
2844
|
}
|
|
2114
2845
|
});
|
|
2115
2846
|
|
|
2116
2847
|
// src/lib/tmux-routing.ts
|
|
2117
|
-
import { readFileSync as
|
|
2118
|
-
import
|
|
2119
|
-
import
|
|
2848
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync5, existsSync as existsSync10, appendFileSync, readdirSync as readdirSync2 } from "fs";
|
|
2849
|
+
import path12 from "path";
|
|
2850
|
+
import os8 from "os";
|
|
2120
2851
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2121
2852
|
function getMySession() {
|
|
2122
2853
|
return getTransport().getMySession();
|
|
@@ -2129,7 +2860,7 @@ function extractRootExe(name) {
|
|
|
2129
2860
|
}
|
|
2130
2861
|
function getParentExe(sessionKey) {
|
|
2131
2862
|
try {
|
|
2132
|
-
const data = JSON.parse(
|
|
2863
|
+
const data = JSON.parse(readFileSync10(path12.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
2133
2864
|
return data.parentExe || null;
|
|
2134
2865
|
} catch {
|
|
2135
2866
|
return null;
|
|
@@ -2172,10 +2903,10 @@ var init_tmux_routing = __esm({
|
|
|
2172
2903
|
init_intercom_queue();
|
|
2173
2904
|
init_plan_limits();
|
|
2174
2905
|
init_employees();
|
|
2175
|
-
SPAWN_LOCK_DIR =
|
|
2176
|
-
SESSION_CACHE =
|
|
2177
|
-
INTERCOM_LOG2 =
|
|
2178
|
-
DEBOUNCE_FILE =
|
|
2906
|
+
SPAWN_LOCK_DIR = path12.join(os8.homedir(), ".exe-os", "spawn-locks");
|
|
2907
|
+
SESSION_CACHE = path12.join(os8.homedir(), ".exe-os", "session-cache");
|
|
2908
|
+
INTERCOM_LOG2 = path12.join(os8.homedir(), ".exe-os", "intercom.log");
|
|
2909
|
+
DEBOUNCE_FILE = path12.join(SESSION_CACHE, "intercom-debounce.json");
|
|
2179
2910
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
2180
2911
|
}
|
|
2181
2912
|
});
|
|
@@ -2215,14 +2946,14 @@ var init_memory = __esm({
|
|
|
2215
2946
|
|
|
2216
2947
|
// src/lib/keychain.ts
|
|
2217
2948
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
2218
|
-
import { existsSync as
|
|
2219
|
-
import
|
|
2220
|
-
import
|
|
2949
|
+
import { existsSync as existsSync11 } from "fs";
|
|
2950
|
+
import path13 from "path";
|
|
2951
|
+
import os9 from "os";
|
|
2221
2952
|
function getKeyDir() {
|
|
2222
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
2953
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path13.join(os9.homedir(), ".exe-os");
|
|
2223
2954
|
}
|
|
2224
2955
|
function getKeyPath() {
|
|
2225
|
-
return
|
|
2956
|
+
return path13.join(getKeyDir(), "master.key");
|
|
2226
2957
|
}
|
|
2227
2958
|
async function tryKeytar() {
|
|
2228
2959
|
try {
|
|
@@ -2243,9 +2974,9 @@ async function getMasterKey() {
|
|
|
2243
2974
|
}
|
|
2244
2975
|
}
|
|
2245
2976
|
const keyPath = getKeyPath();
|
|
2246
|
-
if (!
|
|
2977
|
+
if (!existsSync11(keyPath)) {
|
|
2247
2978
|
process.stderr.write(
|
|
2248
|
-
`[keychain] Key not found at ${keyPath} (HOME=${
|
|
2979
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os9.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
2249
2980
|
`
|
|
2250
2981
|
);
|
|
2251
2982
|
return null;
|
|
@@ -2330,6 +3061,7 @@ var shard_manager_exports = {};
|
|
|
2330
3061
|
__export(shard_manager_exports, {
|
|
2331
3062
|
disposeShards: () => disposeShards,
|
|
2332
3063
|
ensureShardSchema: () => ensureShardSchema,
|
|
3064
|
+
getOpenShardCount: () => getOpenShardCount,
|
|
2333
3065
|
getReadyShardClient: () => getReadyShardClient,
|
|
2334
3066
|
getShardClient: () => getShardClient,
|
|
2335
3067
|
getShardsDir: () => getShardsDir,
|
|
@@ -2338,15 +3070,18 @@ __export(shard_manager_exports, {
|
|
|
2338
3070
|
listShards: () => listShards,
|
|
2339
3071
|
shardExists: () => shardExists
|
|
2340
3072
|
});
|
|
2341
|
-
import
|
|
2342
|
-
import { existsSync as
|
|
3073
|
+
import path14 from "path";
|
|
3074
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readdirSync as readdirSync3 } from "fs";
|
|
2343
3075
|
import { createClient as createClient2 } from "@libsql/client";
|
|
2344
3076
|
function initShardManager(encryptionKey) {
|
|
2345
3077
|
_encryptionKey = encryptionKey;
|
|
2346
|
-
if (!
|
|
3078
|
+
if (!existsSync12(SHARDS_DIR)) {
|
|
2347
3079
|
mkdirSync6(SHARDS_DIR, { recursive: true });
|
|
2348
3080
|
}
|
|
2349
3081
|
_shardingEnabled = true;
|
|
3082
|
+
if (_evictionTimer) clearInterval(_evictionTimer);
|
|
3083
|
+
_evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
|
|
3084
|
+
_evictionTimer.unref();
|
|
2350
3085
|
}
|
|
2351
3086
|
function isShardingEnabled() {
|
|
2352
3087
|
return _shardingEnabled;
|
|
@@ -2363,21 +3098,28 @@ function getShardClient(projectName) {
|
|
|
2363
3098
|
throw new Error(`Invalid project name for shard: "${projectName}"`);
|
|
2364
3099
|
}
|
|
2365
3100
|
const cached = _shards.get(safeName);
|
|
2366
|
-
if (cached)
|
|
2367
|
-
|
|
3101
|
+
if (cached) {
|
|
3102
|
+
_shardLastAccess.set(safeName, Date.now());
|
|
3103
|
+
return cached;
|
|
3104
|
+
}
|
|
3105
|
+
while (_shards.size >= MAX_OPEN_SHARDS) {
|
|
3106
|
+
evictLRU();
|
|
3107
|
+
}
|
|
3108
|
+
const dbPath = path14.join(SHARDS_DIR, `${safeName}.db`);
|
|
2368
3109
|
const client = createClient2({
|
|
2369
3110
|
url: `file:${dbPath}`,
|
|
2370
3111
|
encryptionKey: _encryptionKey
|
|
2371
3112
|
});
|
|
2372
3113
|
_shards.set(safeName, client);
|
|
3114
|
+
_shardLastAccess.set(safeName, Date.now());
|
|
2373
3115
|
return client;
|
|
2374
3116
|
}
|
|
2375
3117
|
function shardExists(projectName) {
|
|
2376
3118
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2377
|
-
return
|
|
3119
|
+
return existsSync12(path14.join(SHARDS_DIR, `${safeName}.db`));
|
|
2378
3120
|
}
|
|
2379
3121
|
function listShards() {
|
|
2380
|
-
if (!
|
|
3122
|
+
if (!existsSync12(SHARDS_DIR)) return [];
|
|
2381
3123
|
return readdirSync3(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
2382
3124
|
}
|
|
2383
3125
|
async function ensureShardSchema(client) {
|
|
@@ -2429,6 +3171,8 @@ async function ensureShardSchema(client) {
|
|
|
2429
3171
|
for (const col of [
|
|
2430
3172
|
"ALTER TABLE memories ADD COLUMN task_id TEXT",
|
|
2431
3173
|
"ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0",
|
|
3174
|
+
"ALTER TABLE memories ADD COLUMN author_device_id TEXT",
|
|
3175
|
+
"ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'",
|
|
2432
3176
|
"ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5",
|
|
2433
3177
|
"ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'",
|
|
2434
3178
|
"ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0",
|
|
@@ -2451,7 +3195,23 @@ async function ensureShardSchema(client) {
|
|
|
2451
3195
|
// MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
|
|
2452
3196
|
"ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
|
|
2453
3197
|
"ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
|
|
2454
|
-
"ALTER TABLE memories ADD COLUMN trajectory TEXT"
|
|
3198
|
+
"ALTER TABLE memories ADD COLUMN trajectory TEXT",
|
|
3199
|
+
// Metadata enrichment columns (must match database.ts)
|
|
3200
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
3201
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
3202
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
3203
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
3204
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
3205
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
3206
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
3207
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
3208
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
3209
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
3210
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
3211
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
3212
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
3213
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
3214
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
2455
3215
|
]) {
|
|
2456
3216
|
try {
|
|
2457
3217
|
await client.execute(col);
|
|
@@ -2550,21 +3310,69 @@ async function getReadyShardClient(projectName) {
|
|
|
2550
3310
|
await ensureShardSchema(client);
|
|
2551
3311
|
return client;
|
|
2552
3312
|
}
|
|
3313
|
+
function evictLRU() {
|
|
3314
|
+
let oldest = null;
|
|
3315
|
+
let oldestTime = Infinity;
|
|
3316
|
+
for (const [name, time] of _shardLastAccess) {
|
|
3317
|
+
if (time < oldestTime) {
|
|
3318
|
+
oldestTime = time;
|
|
3319
|
+
oldest = name;
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
if (oldest) {
|
|
3323
|
+
const client = _shards.get(oldest);
|
|
3324
|
+
if (client) {
|
|
3325
|
+
client.close();
|
|
3326
|
+
}
|
|
3327
|
+
_shards.delete(oldest);
|
|
3328
|
+
_shardLastAccess.delete(oldest);
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
function evictIdleShards() {
|
|
3332
|
+
const now = Date.now();
|
|
3333
|
+
const toEvict = [];
|
|
3334
|
+
for (const [name, lastAccess] of _shardLastAccess) {
|
|
3335
|
+
if (now - lastAccess > SHARD_IDLE_MS) {
|
|
3336
|
+
toEvict.push(name);
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3339
|
+
for (const name of toEvict) {
|
|
3340
|
+
const client = _shards.get(name);
|
|
3341
|
+
if (client) {
|
|
3342
|
+
client.close();
|
|
3343
|
+
}
|
|
3344
|
+
_shards.delete(name);
|
|
3345
|
+
_shardLastAccess.delete(name);
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3348
|
+
function getOpenShardCount() {
|
|
3349
|
+
return _shards.size;
|
|
3350
|
+
}
|
|
2553
3351
|
function disposeShards() {
|
|
3352
|
+
if (_evictionTimer) {
|
|
3353
|
+
clearInterval(_evictionTimer);
|
|
3354
|
+
_evictionTimer = null;
|
|
3355
|
+
}
|
|
2554
3356
|
for (const [, client] of _shards) {
|
|
2555
3357
|
client.close();
|
|
2556
3358
|
}
|
|
2557
3359
|
_shards.clear();
|
|
3360
|
+
_shardLastAccess.clear();
|
|
2558
3361
|
_shardingEnabled = false;
|
|
2559
3362
|
_encryptionKey = null;
|
|
2560
3363
|
}
|
|
2561
|
-
var SHARDS_DIR, _shards, _encryptionKey, _shardingEnabled;
|
|
3364
|
+
var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
|
|
2562
3365
|
var init_shard_manager = __esm({
|
|
2563
3366
|
"src/lib/shard-manager.ts"() {
|
|
2564
3367
|
"use strict";
|
|
2565
3368
|
init_config();
|
|
2566
|
-
SHARDS_DIR =
|
|
3369
|
+
SHARDS_DIR = path14.join(EXE_AI_DIR, "shards");
|
|
3370
|
+
SHARD_IDLE_MS = 5 * 60 * 1e3;
|
|
3371
|
+
MAX_OPEN_SHARDS = 10;
|
|
3372
|
+
EVICTION_INTERVAL_MS = 60 * 1e3;
|
|
2567
3373
|
_shards = /* @__PURE__ */ new Map();
|
|
3374
|
+
_shardLastAccess = /* @__PURE__ */ new Map();
|
|
3375
|
+
_evictionTimer = null;
|
|
2568
3376
|
_encryptionKey = null;
|
|
2569
3377
|
_shardingEnabled = false;
|
|
2570
3378
|
}
|
|
@@ -3331,15 +4139,15 @@ var init_store = __esm({
|
|
|
3331
4139
|
init_config();
|
|
3332
4140
|
init_config();
|
|
3333
4141
|
import { spawn as spawn2 } from "child_process";
|
|
3334
|
-
import { existsSync as
|
|
3335
|
-
import
|
|
4142
|
+
import { existsSync as existsSync13, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
4143
|
+
import path15 from "path";
|
|
3336
4144
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3337
4145
|
|
|
3338
4146
|
// src/lib/active-agent.ts
|
|
3339
4147
|
init_config();
|
|
3340
4148
|
init_session_key();
|
|
3341
4149
|
init_employees();
|
|
3342
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync, unlinkSync as unlinkSync2, readdirSync } from "fs";
|
|
4150
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2, readdirSync } from "fs";
|
|
3343
4151
|
import { execSync as execSync3 } from "child_process";
|
|
3344
4152
|
import path3 from "path";
|
|
3345
4153
|
var CACHE_DIR = path3.join(EXE_AI_DIR, "session-cache");
|
|
@@ -3442,7 +4250,7 @@ if (!process.env.AGENT_ID) {
|
|
|
3442
4250
|
if (!loadConfigSync().autoIngestion) {
|
|
3443
4251
|
process.exit(0);
|
|
3444
4252
|
}
|
|
3445
|
-
var WORKER_LOG_PATH =
|
|
4253
|
+
var WORKER_LOG_PATH = path15.join(EXE_AI_DIR, "workers.log");
|
|
3446
4254
|
function openWorkerLog() {
|
|
3447
4255
|
try {
|
|
3448
4256
|
return openSync2(WORKER_LOG_PATH, "a");
|
|
@@ -3450,6 +4258,25 @@ function openWorkerLog() {
|
|
|
3450
4258
|
return "ignore";
|
|
3451
4259
|
}
|
|
3452
4260
|
}
|
|
4261
|
+
function spawnDetachedWorker(workerPath, env, cwd) {
|
|
4262
|
+
if (!existsSync13(workerPath)) {
|
|
4263
|
+
process.stderr.write(`[stop] WARN: worker not found at ${workerPath}
|
|
4264
|
+
`);
|
|
4265
|
+
return;
|
|
4266
|
+
}
|
|
4267
|
+
const stderrFd = openWorkerLog();
|
|
4268
|
+
const worker = spawn2(process.execPath, [workerPath], {
|
|
4269
|
+
cwd,
|
|
4270
|
+
detached: true,
|
|
4271
|
+
stdio: ["ignore", "ignore", stderrFd],
|
|
4272
|
+
env
|
|
4273
|
+
});
|
|
4274
|
+
worker.unref();
|
|
4275
|
+
if (typeof stderrFd === "number") try {
|
|
4276
|
+
closeSync2(stderrFd);
|
|
4277
|
+
} catch {
|
|
4278
|
+
}
|
|
4279
|
+
}
|
|
3453
4280
|
var MIN_LENGTH = 100;
|
|
3454
4281
|
var timeout = setTimeout(() => {
|
|
3455
4282
|
process.exit(0);
|
|
@@ -3465,22 +4292,36 @@ process.stdin.on("end", () => {
|
|
|
3465
4292
|
try {
|
|
3466
4293
|
if (process.env.EXE_DEBUG_HOOKS || process.env.EXE_RUNTIME === "codex") {
|
|
3467
4294
|
try {
|
|
3468
|
-
const debugPath =
|
|
3469
|
-
const { mkdirSync: mkdirSync7, writeFileSync:
|
|
3470
|
-
mkdirSync7(
|
|
4295
|
+
const debugPath = path15.join(EXE_AI_DIR, "logs", "hook-stdin-stop.log");
|
|
4296
|
+
const { mkdirSync: mkdirSync7, writeFileSync: writeFileSync8 } = __require("fs");
|
|
4297
|
+
mkdirSync7(path15.dirname(debugPath), { recursive: true });
|
|
3471
4298
|
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
3472
4299
|
const snippet = input.length > 500 ? input.slice(0, 500) + "...[truncated]" : input;
|
|
3473
|
-
|
|
4300
|
+
writeFileSync8(debugPath, `[${ts}] len=${input.length} ${snippet}
|
|
3474
4301
|
`, { flag: "a" });
|
|
3475
4302
|
} catch {
|
|
3476
4303
|
}
|
|
3477
4304
|
}
|
|
3478
4305
|
const data = JSON.parse(input);
|
|
3479
|
-
const
|
|
4306
|
+
const agent = getActiveAgent();
|
|
4307
|
+
const message = data.last_assistant_message ?? "";
|
|
4308
|
+
const cwd = data.cwd ?? process.cwd();
|
|
4309
|
+
if (process.env.EXE_RUNTIME === "codex" && !canCoordinate(agent.agentId, agent.agentRole)) {
|
|
4310
|
+
const codexFinalizerPath = path15.resolve(
|
|
4311
|
+
path15.dirname(fileURLToPath3(import.meta.url)),
|
|
4312
|
+
"codex-stop-task-finalizer.js"
|
|
4313
|
+
);
|
|
4314
|
+
spawnDetachedWorker(codexFinalizerPath, {
|
|
4315
|
+
...process.env,
|
|
4316
|
+
AGENT_ID: agent.agentId,
|
|
4317
|
+
AGENT_ROLE: agent.agentRole,
|
|
4318
|
+
EXE_RESPONSE_TEXT: message.slice(0, 5e3),
|
|
4319
|
+
EXE_SESSION_ID: data.session_id
|
|
4320
|
+
}, cwd);
|
|
4321
|
+
}
|
|
3480
4322
|
if (!message || message.length < MIN_LENGTH) {
|
|
3481
4323
|
process.exit(0);
|
|
3482
4324
|
}
|
|
3483
|
-
const agent = getActiveAgent();
|
|
3484
4325
|
const CAPACITY_SIGNALS = /context[- ]?full|hit capacity|conversation is too long|maximum context length|context window.*(?:limit|exceed|full)/i;
|
|
3485
4326
|
if (!canCoordinate(agent.agentId, agent.agentRole) && CAPACITY_SIGNALS.test(message)) {
|
|
3486
4327
|
Promise.resolve().then(() => (init_store(), store_exports)).then(({ initStore: initStore2 }) => initStore2()).then(() => Promise.all([
|
|
@@ -3505,9 +4346,9 @@ process.stdin.on("end", () => {
|
|
|
3505
4346
|
"",
|
|
3506
4347
|
`Last response fragment: ${message.slice(0, 500)}`
|
|
3507
4348
|
].join("\n");
|
|
3508
|
-
const
|
|
4349
|
+
const crypto2 = await import("crypto");
|
|
3509
4350
|
await writeMemory2({
|
|
3510
|
-
id:
|
|
4351
|
+
id: crypto2.randomUUID(),
|
|
3511
4352
|
agent_id: agent.agentId,
|
|
3512
4353
|
agent_role: agent.agentRole,
|
|
3513
4354
|
session_id: data.session_id,
|
|
@@ -3546,32 +4387,17 @@ process.stdin.on("end", () => {
|
|
|
3546
4387
|
}).catch(() => {
|
|
3547
4388
|
});
|
|
3548
4389
|
}
|
|
3549
|
-
const workerPath =
|
|
3550
|
-
|
|
4390
|
+
const workerPath = path15.resolve(
|
|
4391
|
+
path15.dirname(fileURLToPath3(import.meta.url)),
|
|
3551
4392
|
"response-ingest-worker.js"
|
|
3552
4393
|
);
|
|
3553
|
-
|
|
3554
|
-
process.
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
detached: true,
|
|
3561
|
-
stdio: ["ignore", "ignore", stderrFd],
|
|
3562
|
-
env: {
|
|
3563
|
-
...process.env,
|
|
3564
|
-
AGENT_ID: agent.agentId,
|
|
3565
|
-
AGENT_ROLE: agent.agentRole,
|
|
3566
|
-
EXE_RESPONSE_TEXT: message.slice(0, 5e3),
|
|
3567
|
-
EXE_SESSION_ID: data.session_id
|
|
3568
|
-
}
|
|
3569
|
-
});
|
|
3570
|
-
worker.unref();
|
|
3571
|
-
if (typeof stderrFd === "number") try {
|
|
3572
|
-
closeSync2(stderrFd);
|
|
3573
|
-
} catch {
|
|
3574
|
-
}
|
|
4394
|
+
spawnDetachedWorker(workerPath, {
|
|
4395
|
+
...process.env,
|
|
4396
|
+
AGENT_ID: agent.agentId,
|
|
4397
|
+
AGENT_ROLE: agent.agentRole,
|
|
4398
|
+
EXE_RESPONSE_TEXT: message.slice(0, 5e3),
|
|
4399
|
+
EXE_SESSION_ID: data.session_id
|
|
4400
|
+
}, cwd);
|
|
3575
4401
|
} catch {
|
|
3576
4402
|
}
|
|
3577
4403
|
process.exit(0);
|