@askexenow/exe-os 0.8.37 → 0.8.39
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/README.md +17 -8
- package/dist/bin/backfill-conversations.js +112 -70
- package/dist/bin/backfill-responses.js +53 -18
- package/dist/bin/backfill-vectors.js +43 -16
- package/dist/bin/cleanup-stale-review-tasks.js +38 -16
- package/dist/bin/cli.js +790 -468
- package/dist/bin/exe-agent.js +19 -4
- package/dist/bin/exe-assign.js +46 -13
- package/dist/bin/exe-boot.js +288 -129
- package/dist/bin/exe-call.js +20 -10
- package/dist/bin/exe-cloud.js +135 -30
- package/dist/bin/exe-dispatch.js +1 -1
- package/dist/bin/exe-doctor.js +38 -16
- package/dist/bin/exe-export-behaviors.js +43 -21
- package/dist/bin/exe-forget.js +39 -17
- package/dist/bin/exe-gateway.js +159 -50
- package/dist/bin/exe-heartbeat.js +53 -31
- package/dist/bin/exe-kill.js +40 -18
- package/dist/bin/exe-launch-agent.js +109 -36
- package/dist/bin/exe-link.js +196 -87
- package/dist/bin/exe-new-employee.js +56 -17
- package/dist/bin/exe-pending-messages.js +47 -25
- package/dist/bin/exe-pending-notifications.js +38 -16
- package/dist/bin/exe-pending-reviews.js +51 -29
- package/dist/bin/exe-rename.js +21 -7
- package/dist/bin/exe-review.js +41 -13
- package/dist/bin/exe-search.js +57 -21
- package/dist/bin/exe-session-cleanup.js +67 -31
- package/dist/bin/exe-settings.js +63 -2
- package/dist/bin/exe-status.js +35 -13
- package/dist/bin/exe-team.js +35 -13
- package/dist/bin/git-sweep.js +45 -17
- package/dist/bin/graph-backfill.js +38 -16
- package/dist/bin/graph-export.js +38 -16
- package/dist/bin/install.js +10 -1
- package/dist/bin/scan-tasks.js +47 -19
- package/dist/bin/setup.js +444 -259
- package/dist/bin/shard-migrate.js +38 -16
- package/dist/bin/wiki-sync.js +40 -17
- package/dist/gateway/index.js +113 -48
- package/dist/hooks/bug-report-worker.js +66 -39
- package/dist/hooks/commit-complete.js +45 -17
- package/dist/hooks/error-recall.js +60 -20
- package/dist/hooks/exe-heartbeat-hook.js +3 -2
- package/dist/hooks/ingest-worker.js +174 -45
- package/dist/hooks/ingest.js +74 -28
- package/dist/hooks/instructions-loaded.js +46 -17
- package/dist/hooks/notification.js +44 -15
- package/dist/hooks/post-compact.js +44 -15
- package/dist/hooks/pre-compact.js +42 -14
- package/dist/hooks/pre-tool-use.js +59 -22
- package/dist/hooks/prompt-ingest-worker.js +75 -14
- package/dist/hooks/prompt-submit.js +75 -32
- package/dist/hooks/response-ingest-worker.js +76 -15
- package/dist/hooks/session-end.js +54 -22
- package/dist/hooks/session-start.js +57 -20
- package/dist/hooks/stop.js +44 -15
- package/dist/hooks/subagent-stop.js +44 -15
- package/dist/hooks/summary-worker.js +339 -106
- package/dist/index.js +94 -23
- package/dist/lib/cloud-sync.js +191 -80
- package/dist/lib/config.js +4 -1
- package/dist/lib/consolidation.js +5 -4
- package/dist/lib/database.js +1 -0
- package/dist/lib/device-registry.js +2 -1
- package/dist/lib/embedder.js +9 -1
- package/dist/lib/employee-templates.js +5 -0
- package/dist/lib/employees.js +11 -6
- package/dist/lib/exe-daemon-client.js +6 -1
- package/dist/lib/exe-daemon.js +95 -36
- package/dist/lib/hybrid-search.js +57 -21
- package/dist/lib/identity-templates.js +16 -7
- package/dist/lib/identity.js +1 -1
- package/dist/lib/keychain.js +2 -1
- package/dist/lib/license.js +56 -6
- package/dist/lib/messaging.js +1 -1
- package/dist/lib/reminders.js +2 -2
- package/dist/lib/schedules.js +38 -16
- package/dist/lib/skill-learning.js +1 -1
- package/dist/lib/store.js +44 -16
- package/dist/lib/tasks.js +1 -1
- package/dist/lib/tmux-routing.js +1 -1
- package/dist/mcp/server.js +280 -155
- package/dist/mcp/tools/complete-reminder.js +1 -1
- package/dist/mcp/tools/create-task.js +14 -6
- package/dist/mcp/tools/deactivate-behavior.js +2 -2
- package/dist/mcp/tools/list-reminders.js +1 -1
- package/dist/mcp/tools/list-tasks.js +36 -28
- package/dist/mcp/tools/send-message.js +1 -1
- package/dist/mcp/tools/update-task.js +1 -1
- package/dist/runtime/index.js +42 -8
- package/dist/tui/App.js +220 -99
- package/package.json +5 -3
package/dist/hooks/ingest.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/lib/config.ts
|
|
2
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
2
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
3
3
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import os from "os";
|
|
@@ -170,8 +170,8 @@ function loadConfigSync() {
|
|
|
170
170
|
|
|
171
171
|
// src/adapters/claude/hooks/ingest.ts
|
|
172
172
|
import { spawn } from "child_process";
|
|
173
|
-
import { readFileSync as readFileSync3, writeFileSync as
|
|
174
|
-
import
|
|
173
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync as existsSync2, openSync, closeSync } from "fs";
|
|
174
|
+
import path4 from "path";
|
|
175
175
|
import { fileURLToPath } from "url";
|
|
176
176
|
|
|
177
177
|
// src/adapters/claude/active-agent.ts
|
|
@@ -412,6 +412,44 @@ function errorFingerprint(toolName, errorText) {
|
|
|
412
412
|
return crypto.createHash("sha256").update(`${toolName}:${normalized}`).digest("hex").slice(0, 16);
|
|
413
413
|
}
|
|
414
414
|
|
|
415
|
+
// src/lib/worker-gate.ts
|
|
416
|
+
import { readdirSync as readdirSync2, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
417
|
+
import path3 from "path";
|
|
418
|
+
var WORKER_PID_DIR = path3.join(EXE_AI_DIR, "worker-pids");
|
|
419
|
+
var MAX_CONCURRENT_WORKERS = 3;
|
|
420
|
+
function tryAcquireWorkerSlot() {
|
|
421
|
+
try {
|
|
422
|
+
mkdirSync2(WORKER_PID_DIR, { recursive: true });
|
|
423
|
+
const files = readdirSync2(WORKER_PID_DIR);
|
|
424
|
+
let alive = 0;
|
|
425
|
+
for (const f of files) {
|
|
426
|
+
if (!f.endsWith(".pid")) continue;
|
|
427
|
+
const dashIdx = f.lastIndexOf("-");
|
|
428
|
+
const pid = parseInt(f.slice(dashIdx + 1).replace(".pid", ""), 10);
|
|
429
|
+
if (isNaN(pid)) continue;
|
|
430
|
+
try {
|
|
431
|
+
process.kill(pid, 0);
|
|
432
|
+
alive++;
|
|
433
|
+
} catch {
|
|
434
|
+
try {
|
|
435
|
+
unlinkSync2(path3.join(WORKER_PID_DIR, f));
|
|
436
|
+
} catch {
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return alive < MAX_CONCURRENT_WORKERS;
|
|
441
|
+
} catch {
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
function registerWorkerPid(pid) {
|
|
446
|
+
try {
|
|
447
|
+
mkdirSync2(WORKER_PID_DIR, { recursive: true });
|
|
448
|
+
writeFileSync2(path3.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
|
|
449
|
+
} catch {
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
415
453
|
// src/adapters/claude/hooks/ingest.ts
|
|
416
454
|
if (!process.env.AGENT_ID) {
|
|
417
455
|
process.env.AGENT_ID = "default";
|
|
@@ -420,7 +458,7 @@ if (!process.env.AGENT_ID) {
|
|
|
420
458
|
if (!loadConfigSync().autoIngestion) {
|
|
421
459
|
process.exit(0);
|
|
422
460
|
}
|
|
423
|
-
var WORKER_LOG_PATH =
|
|
461
|
+
var WORKER_LOG_PATH = path4.join(EXE_AI_DIR, "workers.log");
|
|
424
462
|
function openWorkerLog() {
|
|
425
463
|
try {
|
|
426
464
|
return openSync(WORKER_LOG_PATH, "a");
|
|
@@ -432,9 +470,9 @@ var ALLOWED_TOOL_RE = /^(Bash|Edit|Write|Read|Glob|Grep|Agent|mcp__.*)$/;
|
|
|
432
470
|
var WRITE_TOOL_RE = /^(Bash|Edit|Write)$/;
|
|
433
471
|
var SUMMARY_INTERVAL = 25;
|
|
434
472
|
var MIN_WRITES_FOR_SUMMARY = 3;
|
|
435
|
-
var COUNTER_DIR =
|
|
473
|
+
var COUNTER_DIR = path4.join(EXE_AI_DIR, "session-cache");
|
|
436
474
|
function getCounterPath(sessionId) {
|
|
437
|
-
return
|
|
475
|
+
return path4.join(COUNTER_DIR, `counter-${sessionId}.json`);
|
|
438
476
|
}
|
|
439
477
|
function loadCounter(sessionId) {
|
|
440
478
|
try {
|
|
@@ -446,8 +484,8 @@ function loadCounter(sessionId) {
|
|
|
446
484
|
}
|
|
447
485
|
function saveCounter(sessionId, counter) {
|
|
448
486
|
try {
|
|
449
|
-
|
|
450
|
-
|
|
487
|
+
mkdirSync3(COUNTER_DIR, { recursive: true });
|
|
488
|
+
writeFileSync3(getCounterPath(sessionId), JSON.stringify(counter));
|
|
451
489
|
} catch {
|
|
452
490
|
}
|
|
453
491
|
}
|
|
@@ -466,7 +504,7 @@ process.stdin.on("end", () => {
|
|
|
466
504
|
process.exit(0);
|
|
467
505
|
}
|
|
468
506
|
const agent = getActiveAgent();
|
|
469
|
-
if (/^(Read|Write|Edit)$/.test(data.tool_name) && agent.
|
|
507
|
+
if (/^(Read|Write|Edit)$/.test(data.tool_name) && agent.agentRole !== "COO" && agent.agentId !== "default") {
|
|
470
508
|
const filePath = data.tool_input?.file_path ?? "";
|
|
471
509
|
const exeMatch = filePath.match(/exe\/([^/]+)\//);
|
|
472
510
|
if (exeMatch && exeMatch[1] !== agent.agentId) {
|
|
@@ -483,7 +521,7 @@ Do NOT read, write, or modify files in another employee's folder.`
|
|
|
483
521
|
process.stdout.write(warning);
|
|
484
522
|
}
|
|
485
523
|
}
|
|
486
|
-
if (/^(Read|Glob|Grep|Bash)$/.test(data.tool_name) && agent.
|
|
524
|
+
if (/^(Read|Glob|Grep|Bash)$/.test(data.tool_name) && agent.agentRole === "COO") {
|
|
487
525
|
const target = data.tool_input?.file_path ?? data.tool_input?.path ?? data.tool_input?.pattern ?? String(data.tool_input?.command ?? "");
|
|
488
526
|
if (/exe\/exe\//.test(target)) {
|
|
489
527
|
const warning = JSON.stringify({
|
|
@@ -498,7 +536,7 @@ Open reviews are tracked in the tasks table: SELECT COUNT(*) FROM tasks WHERE as
|
|
|
498
536
|
process.stdout.write(warning);
|
|
499
537
|
}
|
|
500
538
|
}
|
|
501
|
-
if (/^(Write|Bash)$/.test(data.tool_name) && agent.
|
|
539
|
+
if (/^(Write|Bash)$/.test(data.tool_name) && agent.agentRole !== "COO" && agent.agentId !== "default") {
|
|
502
540
|
const filePath = data.tool_input?.file_path ?? String(data.tool_input?.command ?? "");
|
|
503
541
|
const outputMatch = filePath.match(/exe\/output\/([^/\-]+)-([^/]+)/);
|
|
504
542
|
if (outputMatch) {
|
|
@@ -522,7 +560,7 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
522
560
|
const classification = classifyError(errorText);
|
|
523
561
|
if (classification === "system" && data.session_id) {
|
|
524
562
|
const fp = errorFingerprint(data.tool_name, errorText);
|
|
525
|
-
const fpFilePath =
|
|
563
|
+
const fpFilePath = path4.join(COUNTER_DIR, `bug-fingerprints-${data.session_id}.json`);
|
|
526
564
|
let fpData = {
|
|
527
565
|
seen: {},
|
|
528
566
|
taskCount: 0,
|
|
@@ -547,13 +585,13 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
547
585
|
fpData.seen[fp] = { count: 1, firstAt: now, lastAt: now };
|
|
548
586
|
fpData.taskCount++;
|
|
549
587
|
fpData.lastTaskAt = now;
|
|
550
|
-
const bugWorkerPath =
|
|
551
|
-
|
|
588
|
+
const bugWorkerPath = path4.resolve(
|
|
589
|
+
path4.dirname(fileURLToPath(import.meta.url)),
|
|
552
590
|
"bug-report-worker.js"
|
|
553
591
|
);
|
|
554
|
-
if (existsSync2(bugWorkerPath)) {
|
|
592
|
+
if (existsSync2(bugWorkerPath) && tryAcquireWorkerSlot()) {
|
|
555
593
|
const stderrFd2 = openWorkerLog();
|
|
556
|
-
const projectName = process.cwd().split(
|
|
594
|
+
const projectName = process.cwd().split(path4.sep).pop() ?? "unknown";
|
|
557
595
|
const bugToolInput = data.tool_input ?? {};
|
|
558
596
|
const bugWorker = spawn(process.execPath, [bugWorkerPath], {
|
|
559
597
|
detached: true,
|
|
@@ -569,6 +607,7 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
569
607
|
BUG_PROJECT_NAME: projectName
|
|
570
608
|
}
|
|
571
609
|
});
|
|
610
|
+
if (bugWorker.pid) registerWorkerPid(bugWorker.pid);
|
|
572
611
|
bugWorker.unref();
|
|
573
612
|
if (typeof stderrFd2 === "number") try {
|
|
574
613
|
closeSync(stderrFd2);
|
|
@@ -580,13 +619,13 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
580
619
|
}
|
|
581
620
|
}
|
|
582
621
|
try {
|
|
583
|
-
|
|
584
|
-
|
|
622
|
+
mkdirSync3(COUNTER_DIR, { recursive: true });
|
|
623
|
+
writeFileSync3(fpFilePath, JSON.stringify(fpData));
|
|
585
624
|
} catch {
|
|
586
625
|
}
|
|
587
626
|
}
|
|
588
627
|
}
|
|
589
|
-
if (data.session_id && agent.
|
|
628
|
+
if (data.session_id && agent.agentRole !== "COO" && agent.agentId !== "default") {
|
|
590
629
|
const counter = loadCounter(data.session_id);
|
|
591
630
|
counter.total++;
|
|
592
631
|
if (WRITE_TOOL_RE.test(data.tool_name)) {
|
|
@@ -598,11 +637,11 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
598
637
|
}
|
|
599
638
|
const callsSinceLastSummary = counter.total - counter.lastSummaryAt;
|
|
600
639
|
if (callsSinceLastSummary >= SUMMARY_INTERVAL && counter.writes >= MIN_WRITES_FOR_SUMMARY) {
|
|
601
|
-
const summaryWorkerPath =
|
|
602
|
-
|
|
640
|
+
const summaryWorkerPath = path4.resolve(
|
|
641
|
+
path4.dirname(fileURLToPath(import.meta.url)),
|
|
603
642
|
"summary-worker.js"
|
|
604
643
|
);
|
|
605
|
-
if (existsSync2(summaryWorkerPath)) {
|
|
644
|
+
if (existsSync2(summaryWorkerPath) && tryAcquireWorkerSlot()) {
|
|
606
645
|
const stderrFd2 = openWorkerLog();
|
|
607
646
|
const summaryWorker = spawn(process.execPath, [summaryWorkerPath], {
|
|
608
647
|
detached: true,
|
|
@@ -616,6 +655,7 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
616
655
|
EXE_SUMMARY_WRITES: String(counter.writes)
|
|
617
656
|
}
|
|
618
657
|
});
|
|
658
|
+
if (summaryWorker.pid) registerWorkerPid(summaryWorker.pid);
|
|
619
659
|
summaryWorker.unref();
|
|
620
660
|
if (typeof stderrFd2 === "number") try {
|
|
621
661
|
closeSync(stderrFd2);
|
|
@@ -643,13 +683,13 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
643
683
|
const bashOutput = typeof data.tool_response === "string" ? data.tool_response : JSON.stringify(data.tool_response ?? "");
|
|
644
684
|
const commitMatch = bashOutput.match(/\[(\S+)\s+([a-f0-9]{7,40})\]\s+(.+)/);
|
|
645
685
|
if (commitMatch) {
|
|
646
|
-
const commitWorkerPath =
|
|
647
|
-
|
|
686
|
+
const commitWorkerPath = path4.resolve(
|
|
687
|
+
path4.dirname(fileURLToPath(import.meta.url)),
|
|
648
688
|
"commit-complete.js"
|
|
649
689
|
);
|
|
650
|
-
if (existsSync2(commitWorkerPath)) {
|
|
690
|
+
if (existsSync2(commitWorkerPath) && tryAcquireWorkerSlot()) {
|
|
651
691
|
const stderrFd2 = openWorkerLog();
|
|
652
|
-
const projectName = process.cwd().split(
|
|
692
|
+
const projectName = process.cwd().split(path4.sep).pop() ?? "unknown";
|
|
653
693
|
const commitWorker = spawn(process.execPath, [commitWorkerPath], {
|
|
654
694
|
detached: true,
|
|
655
695
|
stdio: ["ignore", "ignore", stderrFd2],
|
|
@@ -661,6 +701,7 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
661
701
|
PROJECT_NAME: projectName
|
|
662
702
|
}
|
|
663
703
|
});
|
|
704
|
+
if (commitWorker.pid) registerWorkerPid(commitWorker.pid);
|
|
664
705
|
commitWorker.unref();
|
|
665
706
|
if (typeof stderrFd2 === "number") try {
|
|
666
707
|
closeSync(stderrFd2);
|
|
@@ -672,16 +713,21 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
672
713
|
if (!ALLOWED_TOOL_RE.test(data.tool_name)) {
|
|
673
714
|
process.exit(0);
|
|
674
715
|
}
|
|
675
|
-
const workerPath =
|
|
676
|
-
|
|
716
|
+
const workerPath = path4.resolve(
|
|
717
|
+
path4.dirname(fileURLToPath(import.meta.url)),
|
|
677
718
|
"ingest-worker.js"
|
|
678
719
|
);
|
|
720
|
+
if (!tryAcquireWorkerSlot()) {
|
|
721
|
+
process.stderr.write("[ingest] Worker concurrency limit reached, skipping ingestion\n");
|
|
722
|
+
process.exit(0);
|
|
723
|
+
}
|
|
679
724
|
const stderrFd = openWorkerLog();
|
|
680
725
|
const worker = spawn(process.execPath, [workerPath], {
|
|
681
726
|
detached: true,
|
|
682
727
|
stdio: ["pipe", "ignore", stderrFd],
|
|
683
728
|
env: { ...process.env, AGENT_ID: agent.agentId, AGENT_ROLE: agent.agentRole }
|
|
684
729
|
});
|
|
730
|
+
if (worker.pid) registerWorkerPid(worker.pid);
|
|
685
731
|
worker.stdin.write(input);
|
|
686
732
|
worker.stdin.end();
|
|
687
733
|
worker.unref();
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
-
}) : x)(function(x) {
|
|
6
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
-
});
|
|
9
3
|
var __esm = (fn, res) => function __init() {
|
|
10
4
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
5
|
};
|
|
@@ -15,7 +9,7 @@ var __export = (target, all) => {
|
|
|
15
9
|
};
|
|
16
10
|
|
|
17
11
|
// src/lib/config.ts
|
|
18
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
12
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
19
13
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
20
14
|
import path from "path";
|
|
21
15
|
import os from "os";
|
|
@@ -305,6 +299,7 @@ async function ensureSchema() {
|
|
|
305
299
|
const client = getRawClient();
|
|
306
300
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
307
301
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
302
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
308
303
|
try {
|
|
309
304
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
310
305
|
} catch {
|
|
@@ -1122,12 +1117,13 @@ var init_memory = __esm({
|
|
|
1122
1117
|
});
|
|
1123
1118
|
|
|
1124
1119
|
// src/lib/keychain.ts
|
|
1125
|
-
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod } from "fs/promises";
|
|
1120
|
+
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
1126
1121
|
import { existsSync as existsSync3 } from "fs";
|
|
1127
1122
|
import path4 from "path";
|
|
1123
|
+
import os2 from "os";
|
|
1128
1124
|
import crypto from "crypto";
|
|
1129
1125
|
function getKeyDir() {
|
|
1130
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path4.join(
|
|
1126
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path4.join(os2.homedir(), ".exe-os");
|
|
1131
1127
|
}
|
|
1132
1128
|
function getKeyPath() {
|
|
1133
1129
|
return path4.join(getKeyDir(), "master.key");
|
|
@@ -1184,7 +1180,7 @@ __export(shard_manager_exports, {
|
|
|
1184
1180
|
shardExists: () => shardExists
|
|
1185
1181
|
});
|
|
1186
1182
|
import path5 from "path";
|
|
1187
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
1183
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync3 } from "fs";
|
|
1188
1184
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1189
1185
|
function initShardManager(encryptionKey) {
|
|
1190
1186
|
_encryptionKey = encryptionKey;
|
|
@@ -1223,7 +1219,6 @@ function shardExists(projectName) {
|
|
|
1223
1219
|
}
|
|
1224
1220
|
function listShards() {
|
|
1225
1221
|
if (!existsSync4(SHARDS_DIR)) return [];
|
|
1226
|
-
const { readdirSync: readdirSync3 } = __require("fs");
|
|
1227
1222
|
return readdirSync3(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1228
1223
|
}
|
|
1229
1224
|
async function ensureShardSchema(client) {
|
|
@@ -1429,6 +1424,28 @@ __export(store_exports, {
|
|
|
1429
1424
|
vectorToBlob: () => vectorToBlob,
|
|
1430
1425
|
writeMemory: () => writeMemory
|
|
1431
1426
|
});
|
|
1427
|
+
function isBusyError2(err) {
|
|
1428
|
+
if (err instanceof Error) {
|
|
1429
|
+
const msg = err.message.toLowerCase();
|
|
1430
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1431
|
+
}
|
|
1432
|
+
return false;
|
|
1433
|
+
}
|
|
1434
|
+
async function retryOnBusy2(fn, label) {
|
|
1435
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1436
|
+
try {
|
|
1437
|
+
return await fn();
|
|
1438
|
+
} catch (err) {
|
|
1439
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1440
|
+
process.stderr.write(
|
|
1441
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1442
|
+
`
|
|
1443
|
+
);
|
|
1444
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
throw new Error("unreachable");
|
|
1448
|
+
}
|
|
1432
1449
|
async function initStore(options) {
|
|
1433
1450
|
if (_flushTimer !== null) {
|
|
1434
1451
|
clearInterval(_flushTimer);
|
|
@@ -1457,14 +1474,17 @@ async function initStore(options) {
|
|
|
1457
1474
|
dbPath,
|
|
1458
1475
|
encryptionKey: hexKey
|
|
1459
1476
|
});
|
|
1460
|
-
await ensureSchema();
|
|
1477
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1461
1478
|
try {
|
|
1462
1479
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1463
1480
|
initShardManager2(hexKey);
|
|
1464
1481
|
} catch {
|
|
1465
1482
|
}
|
|
1466
1483
|
const client = getClient();
|
|
1467
|
-
const vResult = await
|
|
1484
|
+
const vResult = await retryOnBusy2(
|
|
1485
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1486
|
+
"version-query"
|
|
1487
|
+
);
|
|
1468
1488
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1469
1489
|
}
|
|
1470
1490
|
function classifyTier(record) {
|
|
@@ -1507,6 +1527,12 @@ async function writeMemory(record) {
|
|
|
1507
1527
|
supersedes_id: record.supersedes_id ?? null
|
|
1508
1528
|
};
|
|
1509
1529
|
_pendingRecords.push(dbRow);
|
|
1530
|
+
const MAX_PENDING = 1e3;
|
|
1531
|
+
if (_pendingRecords.length > MAX_PENDING) {
|
|
1532
|
+
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
1533
|
+
_pendingRecords = _pendingRecords.slice(-MAX_PENDING);
|
|
1534
|
+
console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
|
|
1535
|
+
}
|
|
1510
1536
|
if (_flushTimer === null) {
|
|
1511
1537
|
_flushTimer = setInterval(() => {
|
|
1512
1538
|
void flushBatch();
|
|
@@ -1838,7 +1864,7 @@ async function getMemoryCardinality(agentId) {
|
|
|
1838
1864
|
return 0;
|
|
1839
1865
|
}
|
|
1840
1866
|
}
|
|
1841
|
-
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1867
|
+
var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1842
1868
|
var init_store = __esm({
|
|
1843
1869
|
"src/lib/store.ts"() {
|
|
1844
1870
|
"use strict";
|
|
@@ -1846,6 +1872,8 @@ var init_store = __esm({
|
|
|
1846
1872
|
init_database();
|
|
1847
1873
|
init_keychain();
|
|
1848
1874
|
init_config();
|
|
1875
|
+
INIT_MAX_RETRIES = 3;
|
|
1876
|
+
INIT_RETRY_DELAY_MS = 1e3;
|
|
1849
1877
|
_pendingRecords = [];
|
|
1850
1878
|
_batchSize = 20;
|
|
1851
1879
|
_flushIntervalMs = 1e4;
|
|
@@ -2055,10 +2083,11 @@ var timeout = setTimeout(() => {
|
|
|
2055
2083
|
process.exit(0);
|
|
2056
2084
|
}, 5e3);
|
|
2057
2085
|
timeout.unref();
|
|
2086
|
+
var MAX_INPUT_SIZE = 1e6;
|
|
2058
2087
|
var input = "";
|
|
2059
2088
|
process.stdin.setEncoding("utf8");
|
|
2060
2089
|
process.stdin.on("data", (chunk) => {
|
|
2061
|
-
input += chunk;
|
|
2090
|
+
if (input.length < MAX_INPUT_SIZE) input += chunk;
|
|
2062
2091
|
});
|
|
2063
2092
|
process.stdin.on("end", async () => {
|
|
2064
2093
|
try {
|
|
@@ -2101,8 +2130,8 @@ process.stdin.on("end", async () => {
|
|
|
2101
2130
|
try {
|
|
2102
2131
|
const { readFileSync: readFileSync4, existsSync: existsSync5 } = await import("fs");
|
|
2103
2132
|
const { join } = await import("path");
|
|
2104
|
-
const
|
|
2105
|
-
const claudeMd = join(
|
|
2133
|
+
const os3 = await import("os");
|
|
2134
|
+
const claudeMd = join(os3.homedir(), ".claude", "CLAUDE.md");
|
|
2106
2135
|
if (existsSync5(claudeMd)) {
|
|
2107
2136
|
const content = readFileSync4(claudeMd, "utf8");
|
|
2108
2137
|
const hasOrchRules = content.includes("exe-os:orchestration-start");
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
-
}) : x)(function(x) {
|
|
6
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
-
});
|
|
9
3
|
var __esm = (fn, res) => function __init() {
|
|
10
4
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
5
|
};
|
|
@@ -15,7 +9,7 @@ var __export = (target, all) => {
|
|
|
15
9
|
};
|
|
16
10
|
|
|
17
11
|
// src/lib/config.ts
|
|
18
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
12
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
19
13
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
20
14
|
import path from "path";
|
|
21
15
|
import os from "os";
|
|
@@ -314,6 +308,7 @@ async function ensureSchema() {
|
|
|
314
308
|
const client = getRawClient();
|
|
315
309
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
316
310
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
311
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
317
312
|
try {
|
|
318
313
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
319
314
|
} catch {
|
|
@@ -1122,12 +1117,13 @@ var init_database = __esm({
|
|
|
1122
1117
|
});
|
|
1123
1118
|
|
|
1124
1119
|
// src/lib/keychain.ts
|
|
1125
|
-
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod } from "fs/promises";
|
|
1120
|
+
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
1126
1121
|
import { existsSync as existsSync2 } from "fs";
|
|
1127
1122
|
import path3 from "path";
|
|
1123
|
+
import os2 from "os";
|
|
1128
1124
|
import crypto from "crypto";
|
|
1129
1125
|
function getKeyDir() {
|
|
1130
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(
|
|
1126
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
|
|
1131
1127
|
}
|
|
1132
1128
|
function getKeyPath() {
|
|
1133
1129
|
return path3.join(getKeyDir(), "master.key");
|
|
@@ -1184,7 +1180,7 @@ __export(shard_manager_exports, {
|
|
|
1184
1180
|
shardExists: () => shardExists
|
|
1185
1181
|
});
|
|
1186
1182
|
import path4 from "path";
|
|
1187
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
1183
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync2 } from "fs";
|
|
1188
1184
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1189
1185
|
function initShardManager(encryptionKey) {
|
|
1190
1186
|
_encryptionKey = encryptionKey;
|
|
@@ -1223,7 +1219,6 @@ function shardExists(projectName) {
|
|
|
1223
1219
|
}
|
|
1224
1220
|
function listShards() {
|
|
1225
1221
|
if (!existsSync3(SHARDS_DIR)) return [];
|
|
1226
|
-
const { readdirSync: readdirSync2 } = __require("fs");
|
|
1227
1222
|
return readdirSync2(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1228
1223
|
}
|
|
1229
1224
|
async function ensureShardSchema(client) {
|
|
@@ -1429,6 +1424,28 @@ __export(store_exports, {
|
|
|
1429
1424
|
vectorToBlob: () => vectorToBlob,
|
|
1430
1425
|
writeMemory: () => writeMemory
|
|
1431
1426
|
});
|
|
1427
|
+
function isBusyError2(err) {
|
|
1428
|
+
if (err instanceof Error) {
|
|
1429
|
+
const msg = err.message.toLowerCase();
|
|
1430
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1431
|
+
}
|
|
1432
|
+
return false;
|
|
1433
|
+
}
|
|
1434
|
+
async function retryOnBusy2(fn, label) {
|
|
1435
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1436
|
+
try {
|
|
1437
|
+
return await fn();
|
|
1438
|
+
} catch (err) {
|
|
1439
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1440
|
+
process.stderr.write(
|
|
1441
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1442
|
+
`
|
|
1443
|
+
);
|
|
1444
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
throw new Error("unreachable");
|
|
1448
|
+
}
|
|
1432
1449
|
async function initStore(options) {
|
|
1433
1450
|
if (_flushTimer !== null) {
|
|
1434
1451
|
clearInterval(_flushTimer);
|
|
@@ -1457,14 +1474,17 @@ async function initStore(options) {
|
|
|
1457
1474
|
dbPath,
|
|
1458
1475
|
encryptionKey: hexKey
|
|
1459
1476
|
});
|
|
1460
|
-
await ensureSchema();
|
|
1477
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1461
1478
|
try {
|
|
1462
1479
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1463
1480
|
initShardManager2(hexKey);
|
|
1464
1481
|
} catch {
|
|
1465
1482
|
}
|
|
1466
1483
|
const client = getClient();
|
|
1467
|
-
const vResult = await
|
|
1484
|
+
const vResult = await retryOnBusy2(
|
|
1485
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1486
|
+
"version-query"
|
|
1487
|
+
);
|
|
1468
1488
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1469
1489
|
}
|
|
1470
1490
|
function classifyTier(record) {
|
|
@@ -1507,6 +1527,12 @@ async function writeMemory(record) {
|
|
|
1507
1527
|
supersedes_id: record.supersedes_id ?? null
|
|
1508
1528
|
};
|
|
1509
1529
|
_pendingRecords.push(dbRow);
|
|
1530
|
+
const MAX_PENDING = 1e3;
|
|
1531
|
+
if (_pendingRecords.length > MAX_PENDING) {
|
|
1532
|
+
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
1533
|
+
_pendingRecords = _pendingRecords.slice(-MAX_PENDING);
|
|
1534
|
+
console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
|
|
1535
|
+
}
|
|
1510
1536
|
if (_flushTimer === null) {
|
|
1511
1537
|
_flushTimer = setInterval(() => {
|
|
1512
1538
|
void flushBatch();
|
|
@@ -1838,7 +1864,7 @@ async function getMemoryCardinality(agentId) {
|
|
|
1838
1864
|
return 0;
|
|
1839
1865
|
}
|
|
1840
1866
|
}
|
|
1841
|
-
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1867
|
+
var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1842
1868
|
var init_store = __esm({
|
|
1843
1869
|
"src/lib/store.ts"() {
|
|
1844
1870
|
"use strict";
|
|
@@ -1846,6 +1872,8 @@ var init_store = __esm({
|
|
|
1846
1872
|
init_database();
|
|
1847
1873
|
init_keychain();
|
|
1848
1874
|
init_config();
|
|
1875
|
+
INIT_MAX_RETRIES = 3;
|
|
1876
|
+
INIT_RETRY_DELAY_MS = 1e3;
|
|
1849
1877
|
_pendingRecords = [];
|
|
1850
1878
|
_batchSize = 20;
|
|
1851
1879
|
_flushIntervalMs = 1e4;
|
|
@@ -1953,10 +1981,11 @@ var timeout = setTimeout(() => {
|
|
|
1953
1981
|
process.exit(0);
|
|
1954
1982
|
}, 5e3);
|
|
1955
1983
|
timeout.unref();
|
|
1984
|
+
var MAX_INPUT_SIZE = 1e6;
|
|
1956
1985
|
var input = "";
|
|
1957
1986
|
process.stdin.setEncoding("utf8");
|
|
1958
1987
|
process.stdin.on("data", (chunk) => {
|
|
1959
|
-
input += chunk;
|
|
1988
|
+
if (input.length < MAX_INPUT_SIZE) input += chunk;
|
|
1960
1989
|
});
|
|
1961
1990
|
process.stdin.on("end", async () => {
|
|
1962
1991
|
try {
|