@askexenow/exe-os 0.8.83 → 0.8.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/backfill-conversations.js +746 -595
- package/dist/bin/backfill-responses.js +745 -594
- package/dist/bin/backfill-vectors.js +312 -226
- package/dist/bin/cleanup-stale-review-tasks.js +97 -2
- package/dist/bin/cli.js +14350 -12518
- package/dist/bin/exe-agent.js +97 -88
- package/dist/bin/exe-assign.js +1003 -854
- package/dist/bin/exe-boot.js +1257 -320
- package/dist/bin/exe-call.js +10 -0
- package/dist/bin/exe-cloud.js +29 -6
- package/dist/bin/exe-dispatch.js +210 -34
- package/dist/bin/exe-doctor.js +403 -6
- package/dist/bin/exe-export-behaviors.js +175 -72
- package/dist/bin/exe-forget.js +97 -2
- package/dist/bin/exe-gateway.js +550 -171
- package/dist/bin/exe-healthcheck.js +1 -0
- package/dist/bin/exe-heartbeat.js +100 -5
- package/dist/bin/exe-kill.js +175 -72
- package/dist/bin/exe-launch-agent.js +189 -76
- package/dist/bin/exe-link.js +902 -80
- package/dist/bin/exe-new-employee.js +38 -8
- package/dist/bin/exe-pending-messages.js +96 -2
- package/dist/bin/exe-pending-notifications.js +97 -2
- package/dist/bin/exe-pending-reviews.js +98 -3
- package/dist/bin/exe-rename.js +564 -23
- package/dist/bin/exe-review.js +231 -73
- package/dist/bin/exe-search.js +989 -226
- package/dist/bin/exe-session-cleanup.js +4806 -1665
- package/dist/bin/exe-settings.js +20 -5
- package/dist/bin/exe-status.js +97 -2
- package/dist/bin/exe-team.js +97 -2
- package/dist/bin/git-sweep.js +899 -207
- package/dist/bin/graph-backfill.js +175 -72
- package/dist/bin/graph-export.js +175 -72
- package/dist/bin/install.js +38 -7
- package/dist/bin/list-providers.js +1 -0
- package/dist/bin/scan-tasks.js +904 -211
- package/dist/bin/setup.js +867 -268
- package/dist/bin/shard-migrate.js +175 -72
- package/dist/bin/update.js +1 -0
- package/dist/bin/wiki-sync.js +175 -72
- package/dist/gateway/index.js +548 -166
- package/dist/hooks/bug-report-worker.js +208 -23
- package/dist/hooks/commit-complete.js +897 -205
- package/dist/hooks/error-recall.js +988 -226
- package/dist/hooks/ingest-worker.js +1638 -1194
- package/dist/hooks/ingest.js +3 -0
- package/dist/hooks/instructions-loaded.js +707 -97
- package/dist/hooks/notification.js +699 -89
- package/dist/hooks/post-compact.js +714 -104
- package/dist/hooks/pre-compact.js +897 -205
- package/dist/hooks/pre-tool-use.js +742 -123
- package/dist/hooks/prompt-ingest-worker.js +242 -101
- package/dist/hooks/prompt-submit.js +995 -233
- package/dist/hooks/response-ingest-worker.js +242 -101
- package/dist/hooks/session-end.js +3941 -400
- package/dist/hooks/session-start.js +1001 -226
- package/dist/hooks/stop.js +725 -115
- package/dist/hooks/subagent-stop.js +714 -104
- package/dist/hooks/summary-worker.js +1964 -1330
- package/dist/index.js +1651 -1053
- package/dist/lib/cloud-sync.js +907 -86
- package/dist/lib/consolidation.js +2 -1
- package/dist/lib/database.js +642 -87
- package/dist/lib/db-daemon-client.js +503 -0
- package/dist/lib/device-registry.js +547 -7
- package/dist/lib/embedder.js +14 -28
- package/dist/lib/employee-templates.js +84 -74
- package/dist/lib/employees.js +9 -0
- package/dist/lib/exe-daemon-client.js +16 -29
- package/dist/lib/exe-daemon.js +1955 -922
- package/dist/lib/hybrid-search.js +988 -226
- package/dist/lib/identity.js +87 -67
- package/dist/lib/keychain.js +9 -1
- package/dist/lib/messaging.js +8 -1
- package/dist/lib/reminders.js +91 -74
- package/dist/lib/schedules.js +96 -2
- package/dist/lib/skill-learning.js +103 -85
- package/dist/lib/store.js +234 -73
- package/dist/lib/tasks.js +111 -22
- package/dist/lib/tmux-routing.js +120 -31
- package/dist/lib/token-spend.js +273 -0
- package/dist/lib/ws-client.js +11 -0
- package/dist/mcp/server.js +5222 -475
- package/dist/mcp/tools/complete-reminder.js +94 -77
- package/dist/mcp/tools/create-reminder.js +94 -77
- package/dist/mcp/tools/create-task.js +120 -22
- package/dist/mcp/tools/deactivate-behavior.js +95 -77
- package/dist/mcp/tools/list-reminders.js +94 -77
- package/dist/mcp/tools/list-tasks.js +31 -1
- package/dist/mcp/tools/send-message.js +8 -1
- package/dist/mcp/tools/update-task.js +39 -10
- package/dist/runtime/index.js +911 -219
- package/dist/tui/App.js +997 -295
- package/package.json +6 -1
|
@@ -500,6 +500,443 @@ var init_db_retry = __esm({
|
|
|
500
500
|
}
|
|
501
501
|
});
|
|
502
502
|
|
|
503
|
+
// src/lib/exe-daemon-client.ts
|
|
504
|
+
import net from "net";
|
|
505
|
+
import { spawn } from "child_process";
|
|
506
|
+
import { randomUUID } from "crypto";
|
|
507
|
+
import { existsSync as existsSync4, unlinkSync as unlinkSync3, readFileSync as readFileSync5, openSync, closeSync, statSync } from "fs";
|
|
508
|
+
import path6 from "path";
|
|
509
|
+
import { fileURLToPath } from "url";
|
|
510
|
+
function handleData(chunk) {
|
|
511
|
+
_buffer += chunk.toString();
|
|
512
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
513
|
+
_buffer = "";
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
let newlineIdx;
|
|
517
|
+
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
518
|
+
const line = _buffer.slice(0, newlineIdx).trim();
|
|
519
|
+
_buffer = _buffer.slice(newlineIdx + 1);
|
|
520
|
+
if (!line) continue;
|
|
521
|
+
try {
|
|
522
|
+
const response = JSON.parse(line);
|
|
523
|
+
const id = response.id;
|
|
524
|
+
if (!id) continue;
|
|
525
|
+
const entry = _pending.get(id);
|
|
526
|
+
if (entry) {
|
|
527
|
+
clearTimeout(entry.timer);
|
|
528
|
+
_pending.delete(id);
|
|
529
|
+
entry.resolve(response);
|
|
530
|
+
}
|
|
531
|
+
} catch {
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
function cleanupStaleFiles() {
|
|
536
|
+
if (existsSync4(PID_PATH)) {
|
|
537
|
+
try {
|
|
538
|
+
const pid = parseInt(readFileSync5(PID_PATH, "utf8").trim(), 10);
|
|
539
|
+
if (pid > 0) {
|
|
540
|
+
try {
|
|
541
|
+
process.kill(pid, 0);
|
|
542
|
+
return;
|
|
543
|
+
} catch {
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
} catch {
|
|
547
|
+
}
|
|
548
|
+
try {
|
|
549
|
+
unlinkSync3(PID_PATH);
|
|
550
|
+
} catch {
|
|
551
|
+
}
|
|
552
|
+
try {
|
|
553
|
+
unlinkSync3(SOCKET_PATH);
|
|
554
|
+
} catch {
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
function findPackageRoot() {
|
|
559
|
+
let dir = path6.dirname(fileURLToPath(import.meta.url));
|
|
560
|
+
const { root } = path6.parse(dir);
|
|
561
|
+
while (dir !== root) {
|
|
562
|
+
if (existsSync4(path6.join(dir, "package.json"))) return dir;
|
|
563
|
+
dir = path6.dirname(dir);
|
|
564
|
+
}
|
|
565
|
+
return null;
|
|
566
|
+
}
|
|
567
|
+
function spawnDaemon() {
|
|
568
|
+
const pkgRoot = findPackageRoot();
|
|
569
|
+
if (!pkgRoot) {
|
|
570
|
+
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
const daemonPath = path6.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
574
|
+
if (!existsSync4(daemonPath)) {
|
|
575
|
+
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
576
|
+
`);
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
const resolvedPath = daemonPath;
|
|
580
|
+
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
581
|
+
`);
|
|
582
|
+
const logPath = path6.join(path6.dirname(SOCKET_PATH), "exed.log");
|
|
583
|
+
let stderrFd = "ignore";
|
|
584
|
+
try {
|
|
585
|
+
stderrFd = openSync(logPath, "a");
|
|
586
|
+
} catch {
|
|
587
|
+
}
|
|
588
|
+
const child = spawn(process.execPath, [resolvedPath], {
|
|
589
|
+
detached: true,
|
|
590
|
+
stdio: ["ignore", "ignore", stderrFd],
|
|
591
|
+
env: {
|
|
592
|
+
...process.env,
|
|
593
|
+
TMUX: void 0,
|
|
594
|
+
// Daemon is global — must not inherit session scope
|
|
595
|
+
TMUX_PANE: void 0,
|
|
596
|
+
// Prevents resolveExeSession() from scoping to one session
|
|
597
|
+
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
598
|
+
EXE_DAEMON_PID: PID_PATH
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
child.unref();
|
|
602
|
+
if (typeof stderrFd === "number") {
|
|
603
|
+
try {
|
|
604
|
+
closeSync(stderrFd);
|
|
605
|
+
} catch {
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
function acquireSpawnLock() {
|
|
610
|
+
try {
|
|
611
|
+
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
612
|
+
closeSync(fd);
|
|
613
|
+
return true;
|
|
614
|
+
} catch {
|
|
615
|
+
try {
|
|
616
|
+
const stat = statSync(SPAWN_LOCK_PATH);
|
|
617
|
+
if (Date.now() - stat.mtimeMs > SPAWN_LOCK_STALE_MS) {
|
|
618
|
+
try {
|
|
619
|
+
unlinkSync3(SPAWN_LOCK_PATH);
|
|
620
|
+
} catch {
|
|
621
|
+
}
|
|
622
|
+
try {
|
|
623
|
+
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
624
|
+
closeSync(fd);
|
|
625
|
+
return true;
|
|
626
|
+
} catch {
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
} catch {
|
|
630
|
+
}
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
function releaseSpawnLock() {
|
|
635
|
+
try {
|
|
636
|
+
unlinkSync3(SPAWN_LOCK_PATH);
|
|
637
|
+
} catch {
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
function connectToSocket() {
|
|
641
|
+
return new Promise((resolve) => {
|
|
642
|
+
if (_socket && _connected) {
|
|
643
|
+
resolve(true);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
const socket = net.createConnection({ path: SOCKET_PATH });
|
|
647
|
+
const connectTimeout = setTimeout(() => {
|
|
648
|
+
socket.destroy();
|
|
649
|
+
resolve(false);
|
|
650
|
+
}, 2e3);
|
|
651
|
+
socket.on("connect", () => {
|
|
652
|
+
clearTimeout(connectTimeout);
|
|
653
|
+
_socket = socket;
|
|
654
|
+
_connected = true;
|
|
655
|
+
_buffer = "";
|
|
656
|
+
socket.on("data", handleData);
|
|
657
|
+
socket.on("close", () => {
|
|
658
|
+
_connected = false;
|
|
659
|
+
_socket = null;
|
|
660
|
+
for (const [id, entry] of _pending) {
|
|
661
|
+
clearTimeout(entry.timer);
|
|
662
|
+
_pending.delete(id);
|
|
663
|
+
entry.resolve({ error: "Connection closed" });
|
|
664
|
+
}
|
|
665
|
+
});
|
|
666
|
+
socket.on("error", () => {
|
|
667
|
+
_connected = false;
|
|
668
|
+
_socket = null;
|
|
669
|
+
});
|
|
670
|
+
resolve(true);
|
|
671
|
+
});
|
|
672
|
+
socket.on("error", () => {
|
|
673
|
+
clearTimeout(connectTimeout);
|
|
674
|
+
resolve(false);
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
async function connectEmbedDaemon() {
|
|
679
|
+
if (_socket && _connected) return true;
|
|
680
|
+
if (await connectToSocket()) return true;
|
|
681
|
+
if (acquireSpawnLock()) {
|
|
682
|
+
try {
|
|
683
|
+
cleanupStaleFiles();
|
|
684
|
+
spawnDaemon();
|
|
685
|
+
} finally {
|
|
686
|
+
releaseSpawnLock();
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
const start = Date.now();
|
|
690
|
+
let delay2 = 100;
|
|
691
|
+
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
692
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
693
|
+
if (await connectToSocket()) return true;
|
|
694
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
695
|
+
}
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
699
|
+
return new Promise((resolve) => {
|
|
700
|
+
if (!_socket || !_connected) {
|
|
701
|
+
resolve({ error: "Not connected" });
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
const id = randomUUID();
|
|
705
|
+
const timer = setTimeout(() => {
|
|
706
|
+
_pending.delete(id);
|
|
707
|
+
resolve({ error: "Request timeout" });
|
|
708
|
+
}, timeoutMs);
|
|
709
|
+
_pending.set(id, { resolve, timer });
|
|
710
|
+
try {
|
|
711
|
+
_socket.write(JSON.stringify({ id, ...payload }) + "\n");
|
|
712
|
+
} catch {
|
|
713
|
+
clearTimeout(timer);
|
|
714
|
+
_pending.delete(id);
|
|
715
|
+
resolve({ error: "Write failed" });
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
function isClientConnected() {
|
|
720
|
+
return _connected;
|
|
721
|
+
}
|
|
722
|
+
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _pending, MAX_BUFFER;
|
|
723
|
+
var init_exe_daemon_client = __esm({
|
|
724
|
+
"src/lib/exe-daemon-client.ts"() {
|
|
725
|
+
"use strict";
|
|
726
|
+
init_config();
|
|
727
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path6.join(EXE_AI_DIR, "exed.sock");
|
|
728
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path6.join(EXE_AI_DIR, "exed.pid");
|
|
729
|
+
SPAWN_LOCK_PATH = path6.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
730
|
+
SPAWN_LOCK_STALE_MS = 3e4;
|
|
731
|
+
CONNECT_TIMEOUT_MS = 15e3;
|
|
732
|
+
REQUEST_TIMEOUT_MS = 3e4;
|
|
733
|
+
_socket = null;
|
|
734
|
+
_connected = false;
|
|
735
|
+
_buffer = "";
|
|
736
|
+
_pending = /* @__PURE__ */ new Map();
|
|
737
|
+
MAX_BUFFER = 1e7;
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
// src/lib/daemon-protocol.ts
|
|
742
|
+
function serializeValue(v) {
|
|
743
|
+
if (v === null || v === void 0) return null;
|
|
744
|
+
if (typeof v === "bigint") return Number(v);
|
|
745
|
+
if (typeof v === "boolean") return v ? 1 : 0;
|
|
746
|
+
if (v instanceof Uint8Array) {
|
|
747
|
+
return { __blob: Buffer.from(v).toString("base64") };
|
|
748
|
+
}
|
|
749
|
+
if (ArrayBuffer.isView(v)) {
|
|
750
|
+
return { __blob: Buffer.from(v.buffer, v.byteOffset, v.byteLength).toString("base64") };
|
|
751
|
+
}
|
|
752
|
+
if (v instanceof ArrayBuffer) {
|
|
753
|
+
return { __blob: Buffer.from(v).toString("base64") };
|
|
754
|
+
}
|
|
755
|
+
if (typeof v === "string" || typeof v === "number") return v;
|
|
756
|
+
return String(v);
|
|
757
|
+
}
|
|
758
|
+
function deserializeValue(v) {
|
|
759
|
+
if (v === null) return null;
|
|
760
|
+
if (typeof v === "object" && v !== null && "__blob" in v) {
|
|
761
|
+
const buf = Buffer.from(v.__blob, "base64");
|
|
762
|
+
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
763
|
+
}
|
|
764
|
+
return v;
|
|
765
|
+
}
|
|
766
|
+
function deserializeResultSet(srs) {
|
|
767
|
+
const rows = srs.rows.map((obj) => {
|
|
768
|
+
const values = srs.columns.map(
|
|
769
|
+
(col) => deserializeValue(obj[col] ?? null)
|
|
770
|
+
);
|
|
771
|
+
const row = values;
|
|
772
|
+
for (let i = 0; i < srs.columns.length; i++) {
|
|
773
|
+
const col = srs.columns[i];
|
|
774
|
+
if (col !== void 0) {
|
|
775
|
+
row[col] = values[i] ?? null;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
Object.defineProperty(row, "length", {
|
|
779
|
+
value: values.length,
|
|
780
|
+
enumerable: false
|
|
781
|
+
});
|
|
782
|
+
return row;
|
|
783
|
+
});
|
|
784
|
+
return {
|
|
785
|
+
columns: srs.columns,
|
|
786
|
+
columnTypes: srs.columnTypes ?? [],
|
|
787
|
+
rows,
|
|
788
|
+
rowsAffected: srs.rowsAffected,
|
|
789
|
+
lastInsertRowid: srs.lastInsertRowid != null ? BigInt(srs.lastInsertRowid) : void 0,
|
|
790
|
+
toJSON: () => ({
|
|
791
|
+
columns: srs.columns,
|
|
792
|
+
columnTypes: srs.columnTypes ?? [],
|
|
793
|
+
rows: srs.rows,
|
|
794
|
+
rowsAffected: srs.rowsAffected,
|
|
795
|
+
lastInsertRowid: srs.lastInsertRowid
|
|
796
|
+
})
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
var init_daemon_protocol = __esm({
|
|
800
|
+
"src/lib/daemon-protocol.ts"() {
|
|
801
|
+
"use strict";
|
|
802
|
+
}
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
// src/lib/db-daemon-client.ts
|
|
806
|
+
var db_daemon_client_exports = {};
|
|
807
|
+
__export(db_daemon_client_exports, {
|
|
808
|
+
createDaemonDbClient: () => createDaemonDbClient,
|
|
809
|
+
initDaemonDbClient: () => initDaemonDbClient
|
|
810
|
+
});
|
|
811
|
+
function normalizeStatement(stmt) {
|
|
812
|
+
if (typeof stmt === "string") {
|
|
813
|
+
return { sql: stmt, args: [] };
|
|
814
|
+
}
|
|
815
|
+
const sql = stmt.sql;
|
|
816
|
+
let args = [];
|
|
817
|
+
if (Array.isArray(stmt.args)) {
|
|
818
|
+
args = stmt.args.map((v) => serializeValue(v));
|
|
819
|
+
} else if (stmt.args && typeof stmt.args === "object") {
|
|
820
|
+
const named = {};
|
|
821
|
+
for (const [key, val] of Object.entries(stmt.args)) {
|
|
822
|
+
named[key] = serializeValue(val);
|
|
823
|
+
}
|
|
824
|
+
return { sql, args: named };
|
|
825
|
+
}
|
|
826
|
+
return { sql, args };
|
|
827
|
+
}
|
|
828
|
+
function createDaemonDbClient(fallbackClient) {
|
|
829
|
+
let _useDaemon = false;
|
|
830
|
+
const client = {
|
|
831
|
+
async execute(stmt) {
|
|
832
|
+
if (!_useDaemon || !isClientConnected()) {
|
|
833
|
+
return fallbackClient.execute(stmt);
|
|
834
|
+
}
|
|
835
|
+
const { sql, args } = normalizeStatement(stmt);
|
|
836
|
+
const response = await sendDaemonRequest({
|
|
837
|
+
type: "db-execute",
|
|
838
|
+
sql,
|
|
839
|
+
args
|
|
840
|
+
});
|
|
841
|
+
if (response.error) {
|
|
842
|
+
const errMsg = String(response.error);
|
|
843
|
+
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
|
|
844
|
+
process.stderr.write(`[db-daemon] Transport error (${errMsg}), falling back to direct
|
|
845
|
+
`);
|
|
846
|
+
return fallbackClient.execute(stmt);
|
|
847
|
+
}
|
|
848
|
+
throw new Error(errMsg);
|
|
849
|
+
}
|
|
850
|
+
if (response.db) {
|
|
851
|
+
return deserializeResultSet(response.db);
|
|
852
|
+
}
|
|
853
|
+
process.stderr.write("[db-daemon] Unexpected response shape, falling back to direct\n");
|
|
854
|
+
return fallbackClient.execute(stmt);
|
|
855
|
+
},
|
|
856
|
+
async batch(stmts, mode) {
|
|
857
|
+
if (!_useDaemon || !isClientConnected()) {
|
|
858
|
+
return fallbackClient.batch(stmts, mode);
|
|
859
|
+
}
|
|
860
|
+
const statements = stmts.map(normalizeStatement);
|
|
861
|
+
const response = await sendDaemonRequest({
|
|
862
|
+
type: "db-batch",
|
|
863
|
+
statements,
|
|
864
|
+
mode: mode ?? "deferred"
|
|
865
|
+
});
|
|
866
|
+
if (response.error) {
|
|
867
|
+
const errMsg = String(response.error);
|
|
868
|
+
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
|
|
869
|
+
process.stderr.write(`[db-daemon] Batch transport error (${errMsg}), falling back to direct
|
|
870
|
+
`);
|
|
871
|
+
return fallbackClient.batch(stmts, mode);
|
|
872
|
+
}
|
|
873
|
+
throw new Error(errMsg);
|
|
874
|
+
}
|
|
875
|
+
const batchResults = response["db-batch"];
|
|
876
|
+
if (batchResults) {
|
|
877
|
+
return batchResults.map(deserializeResultSet);
|
|
878
|
+
}
|
|
879
|
+
process.stderr.write("[db-daemon] Unexpected batch response shape, falling back to direct\n");
|
|
880
|
+
return fallbackClient.batch(stmts, mode);
|
|
881
|
+
},
|
|
882
|
+
// Transaction support — delegate to fallback (transactions need direct connection)
|
|
883
|
+
async transaction(mode) {
|
|
884
|
+
return fallbackClient.transaction(mode);
|
|
885
|
+
},
|
|
886
|
+
// executeMultiple — delegate to fallback (used only for schema migrations)
|
|
887
|
+
async executeMultiple(sql) {
|
|
888
|
+
return fallbackClient.executeMultiple(sql);
|
|
889
|
+
},
|
|
890
|
+
// migrate — delegate to fallback
|
|
891
|
+
async migrate(stmts) {
|
|
892
|
+
return fallbackClient.migrate(stmts);
|
|
893
|
+
},
|
|
894
|
+
// Sync mode — delegate to fallback
|
|
895
|
+
sync() {
|
|
896
|
+
return fallbackClient.sync();
|
|
897
|
+
},
|
|
898
|
+
close() {
|
|
899
|
+
_useDaemon = false;
|
|
900
|
+
},
|
|
901
|
+
get closed() {
|
|
902
|
+
return fallbackClient.closed;
|
|
903
|
+
},
|
|
904
|
+
get protocol() {
|
|
905
|
+
return fallbackClient.protocol;
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
return {
|
|
909
|
+
...client,
|
|
910
|
+
/** Enable daemon routing (call after confirming daemon is connected) */
|
|
911
|
+
_enableDaemon() {
|
|
912
|
+
_useDaemon = true;
|
|
913
|
+
},
|
|
914
|
+
/** Check if daemon routing is active */
|
|
915
|
+
_isDaemonActive() {
|
|
916
|
+
return _useDaemon && isClientConnected();
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
async function initDaemonDbClient(fallbackClient) {
|
|
921
|
+
if (process.env.EXE_IS_DAEMON === "1") return null;
|
|
922
|
+
const connected = await connectEmbedDaemon();
|
|
923
|
+
if (!connected) {
|
|
924
|
+
process.stderr.write("[db-daemon] Daemon unavailable \u2014 using direct SQLite\n");
|
|
925
|
+
return null;
|
|
926
|
+
}
|
|
927
|
+
const client = createDaemonDbClient(fallbackClient);
|
|
928
|
+
client._enableDaemon();
|
|
929
|
+
process.stderr.write("[db-daemon] DB routing through daemon (single-writer)\n");
|
|
930
|
+
return client;
|
|
931
|
+
}
|
|
932
|
+
var init_db_daemon_client = __esm({
|
|
933
|
+
"src/lib/db-daemon-client.ts"() {
|
|
934
|
+
"use strict";
|
|
935
|
+
init_exe_daemon_client();
|
|
936
|
+
init_daemon_protocol();
|
|
937
|
+
}
|
|
938
|
+
});
|
|
939
|
+
|
|
503
940
|
// src/lib/database.ts
|
|
504
941
|
var database_exports = {};
|
|
505
942
|
__export(database_exports, {
|
|
@@ -508,6 +945,7 @@ __export(database_exports, {
|
|
|
508
945
|
ensureSchema: () => ensureSchema,
|
|
509
946
|
getClient: () => getClient,
|
|
510
947
|
getRawClient: () => getRawClient,
|
|
948
|
+
initDaemonClient: () => initDaemonClient,
|
|
511
949
|
initDatabase: () => initDatabase,
|
|
512
950
|
initTurso: () => initTurso,
|
|
513
951
|
isInitialized: () => isInitialized
|
|
@@ -535,8 +973,27 @@ function getClient() {
|
|
|
535
973
|
if (!_resilientClient) {
|
|
536
974
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
537
975
|
}
|
|
976
|
+
if (process.env.EXE_IS_DAEMON === "1") {
|
|
977
|
+
return _resilientClient;
|
|
978
|
+
}
|
|
979
|
+
if (_daemonClient && _daemonClient._isDaemonActive()) {
|
|
980
|
+
return _daemonClient;
|
|
981
|
+
}
|
|
538
982
|
return _resilientClient;
|
|
539
983
|
}
|
|
984
|
+
async function initDaemonClient() {
|
|
985
|
+
if (process.env.EXE_IS_DAEMON === "1") return;
|
|
986
|
+
if (!_resilientClient) return;
|
|
987
|
+
try {
|
|
988
|
+
const { initDaemonDbClient: initDaemonDbClient2 } = await Promise.resolve().then(() => (init_db_daemon_client(), db_daemon_client_exports));
|
|
989
|
+
_daemonClient = await initDaemonDbClient2(_resilientClient);
|
|
990
|
+
} catch (err) {
|
|
991
|
+
process.stderr.write(
|
|
992
|
+
`[database] Daemon client init failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
|
|
993
|
+
`
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
540
997
|
function getRawClient() {
|
|
541
998
|
if (!_client) {
|
|
542
999
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
@@ -1023,6 +1480,12 @@ async function ensureSchema() {
|
|
|
1023
1480
|
} catch {
|
|
1024
1481
|
}
|
|
1025
1482
|
}
|
|
1483
|
+
try {
|
|
1484
|
+
await client.execute(
|
|
1485
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
|
|
1486
|
+
);
|
|
1487
|
+
} catch {
|
|
1488
|
+
}
|
|
1026
1489
|
await client.executeMultiple(`
|
|
1027
1490
|
CREATE TABLE IF NOT EXISTS entities (
|
|
1028
1491
|
id TEXT PRIMARY KEY,
|
|
@@ -1075,7 +1538,30 @@ async function ensureSchema() {
|
|
|
1075
1538
|
entity_id TEXT NOT NULL,
|
|
1076
1539
|
PRIMARY KEY (hyperedge_id, entity_id)
|
|
1077
1540
|
);
|
|
1541
|
+
|
|
1542
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
|
|
1543
|
+
name,
|
|
1544
|
+
content=entities,
|
|
1545
|
+
content_rowid=rowid
|
|
1546
|
+
);
|
|
1547
|
+
|
|
1548
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
|
|
1549
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
1550
|
+
END;
|
|
1551
|
+
|
|
1552
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
|
|
1553
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
1554
|
+
END;
|
|
1555
|
+
|
|
1556
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
|
|
1557
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
1558
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
1559
|
+
END;
|
|
1078
1560
|
`);
|
|
1561
|
+
try {
|
|
1562
|
+
await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
|
|
1563
|
+
} catch {
|
|
1564
|
+
}
|
|
1079
1565
|
await client.executeMultiple(`
|
|
1080
1566
|
CREATE TABLE IF NOT EXISTS entity_aliases (
|
|
1081
1567
|
alias TEXT NOT NULL PRIMARY KEY,
|
|
@@ -1256,6 +1742,33 @@ async function ensureSchema() {
|
|
|
1256
1742
|
CREATE INDEX IF NOT EXISTS idx_conversations_channel
|
|
1257
1743
|
ON conversations(channel_id);
|
|
1258
1744
|
`);
|
|
1745
|
+
await client.executeMultiple(`
|
|
1746
|
+
CREATE TABLE IF NOT EXISTS session_agent_map (
|
|
1747
|
+
session_uuid TEXT PRIMARY KEY,
|
|
1748
|
+
agent_id TEXT NOT NULL,
|
|
1749
|
+
session_name TEXT,
|
|
1750
|
+
task_id TEXT,
|
|
1751
|
+
project_name TEXT,
|
|
1752
|
+
started_at TEXT NOT NULL
|
|
1753
|
+
);
|
|
1754
|
+
|
|
1755
|
+
CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
|
|
1756
|
+
ON session_agent_map(agent_id);
|
|
1757
|
+
`);
|
|
1758
|
+
try {
|
|
1759
|
+
const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
|
|
1760
|
+
if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
|
|
1761
|
+
await client.execute({
|
|
1762
|
+
sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
|
|
1763
|
+
SELECT session_id, agent_id, '', MIN(timestamp)
|
|
1764
|
+
FROM memories
|
|
1765
|
+
WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
|
|
1766
|
+
GROUP BY session_id, agent_id`,
|
|
1767
|
+
args: []
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
} catch {
|
|
1771
|
+
}
|
|
1259
1772
|
try {
|
|
1260
1773
|
await client.execute({
|
|
1261
1774
|
sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
|
|
@@ -1389,15 +1902,41 @@ async function ensureSchema() {
|
|
|
1389
1902
|
});
|
|
1390
1903
|
} catch {
|
|
1391
1904
|
}
|
|
1905
|
+
for (const col of [
|
|
1906
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
1907
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
1908
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
1909
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
1910
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
1911
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
1912
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
1913
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
1914
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
1915
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
1916
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
1917
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
1918
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
1919
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
1920
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
1921
|
+
]) {
|
|
1922
|
+
try {
|
|
1923
|
+
await client.execute(col);
|
|
1924
|
+
} catch {
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1392
1927
|
}
|
|
1393
1928
|
async function disposeDatabase() {
|
|
1929
|
+
if (_daemonClient) {
|
|
1930
|
+
_daemonClient.close();
|
|
1931
|
+
_daemonClient = null;
|
|
1932
|
+
}
|
|
1394
1933
|
if (_client) {
|
|
1395
1934
|
_client.close();
|
|
1396
1935
|
_client = null;
|
|
1397
1936
|
_resilientClient = null;
|
|
1398
1937
|
}
|
|
1399
1938
|
}
|
|
1400
|
-
var _client, _resilientClient, initTurso, disposeTurso;
|
|
1939
|
+
var _client, _resilientClient, _daemonClient, initTurso, disposeTurso;
|
|
1401
1940
|
var init_database = __esm({
|
|
1402
1941
|
"src/lib/database.ts"() {
|
|
1403
1942
|
"use strict";
|
|
@@ -1405,30 +1944,31 @@ var init_database = __esm({
|
|
|
1405
1944
|
init_employees();
|
|
1406
1945
|
_client = null;
|
|
1407
1946
|
_resilientClient = null;
|
|
1947
|
+
_daemonClient = null;
|
|
1408
1948
|
initTurso = initDatabase;
|
|
1409
1949
|
disposeTurso = disposeDatabase;
|
|
1410
1950
|
}
|
|
1411
1951
|
});
|
|
1412
1952
|
|
|
1413
1953
|
// src/lib/license.ts
|
|
1414
|
-
import { readFileSync as
|
|
1415
|
-
import { randomUUID } from "crypto";
|
|
1416
|
-
import
|
|
1954
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
1955
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
1956
|
+
import path7 from "path";
|
|
1417
1957
|
import { jwtVerify, importSPKI } from "jose";
|
|
1418
1958
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
1419
1959
|
var init_license = __esm({
|
|
1420
1960
|
"src/lib/license.ts"() {
|
|
1421
1961
|
"use strict";
|
|
1422
1962
|
init_config();
|
|
1423
|
-
LICENSE_PATH =
|
|
1424
|
-
CACHE_PATH =
|
|
1425
|
-
DEVICE_ID_PATH =
|
|
1963
|
+
LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
|
|
1964
|
+
CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
1965
|
+
DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
|
|
1426
1966
|
}
|
|
1427
1967
|
});
|
|
1428
1968
|
|
|
1429
1969
|
// src/lib/plan-limits.ts
|
|
1430
|
-
import { readFileSync as
|
|
1431
|
-
import
|
|
1970
|
+
import { readFileSync as readFileSync7, existsSync as existsSync6 } from "fs";
|
|
1971
|
+
import path8 from "path";
|
|
1432
1972
|
var CACHE_PATH2;
|
|
1433
1973
|
var init_plan_limits = __esm({
|
|
1434
1974
|
"src/lib/plan-limits.ts"() {
|
|
@@ -1437,15 +1977,15 @@ var init_plan_limits = __esm({
|
|
|
1437
1977
|
init_employees();
|
|
1438
1978
|
init_license();
|
|
1439
1979
|
init_config();
|
|
1440
|
-
CACHE_PATH2 =
|
|
1980
|
+
CACHE_PATH2 = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
1441
1981
|
}
|
|
1442
1982
|
});
|
|
1443
1983
|
|
|
1444
1984
|
// src/lib/tmux-routing.ts
|
|
1445
|
-
import { readFileSync as
|
|
1446
|
-
import
|
|
1985
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync7, appendFileSync } from "fs";
|
|
1986
|
+
import path9 from "path";
|
|
1447
1987
|
import os5 from "os";
|
|
1448
|
-
import { fileURLToPath } from "url";
|
|
1988
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1449
1989
|
function getMySession() {
|
|
1450
1990
|
return getTransport().getMySession();
|
|
1451
1991
|
}
|
|
@@ -1457,7 +1997,7 @@ function extractRootExe(name) {
|
|
|
1457
1997
|
}
|
|
1458
1998
|
function getParentExe(sessionKey) {
|
|
1459
1999
|
try {
|
|
1460
|
-
const data = JSON.parse(
|
|
2000
|
+
const data = JSON.parse(readFileSync8(path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
1461
2001
|
return data.parentExe || null;
|
|
1462
2002
|
} catch {
|
|
1463
2003
|
return null;
|
|
@@ -1489,10 +2029,10 @@ var init_tmux_routing = __esm({
|
|
|
1489
2029
|
init_intercom_queue();
|
|
1490
2030
|
init_plan_limits();
|
|
1491
2031
|
init_employees();
|
|
1492
|
-
SPAWN_LOCK_DIR =
|
|
1493
|
-
SESSION_CACHE =
|
|
1494
|
-
INTERCOM_LOG2 =
|
|
1495
|
-
DEBOUNCE_FILE =
|
|
2032
|
+
SPAWN_LOCK_DIR = path9.join(os5.homedir(), ".exe-os", "spawn-locks");
|
|
2033
|
+
SESSION_CACHE = path9.join(os5.homedir(), ".exe-os", "session-cache");
|
|
2034
|
+
INTERCOM_LOG2 = path9.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
2035
|
+
DEBOUNCE_FILE = path9.join(SESSION_CACHE, "intercom-debounce.json");
|
|
1496
2036
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
1497
2037
|
}
|
|
1498
2038
|
});
|
|
@@ -1532,14 +2072,14 @@ var init_memory = __esm({
|
|
|
1532
2072
|
|
|
1533
2073
|
// src/lib/keychain.ts
|
|
1534
2074
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
1535
|
-
import { existsSync as
|
|
1536
|
-
import
|
|
2075
|
+
import { existsSync as existsSync8 } from "fs";
|
|
2076
|
+
import path10 from "path";
|
|
1537
2077
|
import os6 from "os";
|
|
1538
2078
|
function getKeyDir() {
|
|
1539
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
2079
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path10.join(os6.homedir(), ".exe-os");
|
|
1540
2080
|
}
|
|
1541
2081
|
function getKeyPath() {
|
|
1542
|
-
return
|
|
2082
|
+
return path10.join(getKeyDir(), "master.key");
|
|
1543
2083
|
}
|
|
1544
2084
|
async function tryKeytar() {
|
|
1545
2085
|
try {
|
|
@@ -1560,13 +2100,21 @@ async function getMasterKey() {
|
|
|
1560
2100
|
}
|
|
1561
2101
|
}
|
|
1562
2102
|
const keyPath = getKeyPath();
|
|
1563
|
-
if (!
|
|
2103
|
+
if (!existsSync8(keyPath)) {
|
|
2104
|
+
process.stderr.write(
|
|
2105
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os6.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
2106
|
+
`
|
|
2107
|
+
);
|
|
1564
2108
|
return null;
|
|
1565
2109
|
}
|
|
1566
2110
|
try {
|
|
1567
2111
|
const content = await readFile3(keyPath, "utf-8");
|
|
1568
2112
|
return Buffer.from(content.trim(), "base64");
|
|
1569
|
-
} catch {
|
|
2113
|
+
} catch (err) {
|
|
2114
|
+
process.stderr.write(
|
|
2115
|
+
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
2116
|
+
`
|
|
2117
|
+
);
|
|
1570
2118
|
return null;
|
|
1571
2119
|
}
|
|
1572
2120
|
}
|
|
@@ -1647,12 +2195,12 @@ __export(shard_manager_exports, {
|
|
|
1647
2195
|
listShards: () => listShards,
|
|
1648
2196
|
shardExists: () => shardExists
|
|
1649
2197
|
});
|
|
1650
|
-
import
|
|
1651
|
-
import { existsSync as
|
|
2198
|
+
import path11 from "path";
|
|
2199
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync as readdirSync2 } from "fs";
|
|
1652
2200
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1653
2201
|
function initShardManager(encryptionKey) {
|
|
1654
2202
|
_encryptionKey = encryptionKey;
|
|
1655
|
-
if (!
|
|
2203
|
+
if (!existsSync9(SHARDS_DIR)) {
|
|
1656
2204
|
mkdirSync5(SHARDS_DIR, { recursive: true });
|
|
1657
2205
|
}
|
|
1658
2206
|
_shardingEnabled = true;
|
|
@@ -1673,7 +2221,7 @@ function getShardClient(projectName) {
|
|
|
1673
2221
|
}
|
|
1674
2222
|
const cached = _shards.get(safeName);
|
|
1675
2223
|
if (cached) return cached;
|
|
1676
|
-
const dbPath =
|
|
2224
|
+
const dbPath = path11.join(SHARDS_DIR, `${safeName}.db`);
|
|
1677
2225
|
const client = createClient2({
|
|
1678
2226
|
url: `file:${dbPath}`,
|
|
1679
2227
|
encryptionKey: _encryptionKey
|
|
@@ -1683,10 +2231,10 @@ function getShardClient(projectName) {
|
|
|
1683
2231
|
}
|
|
1684
2232
|
function shardExists(projectName) {
|
|
1685
2233
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1686
|
-
return
|
|
2234
|
+
return existsSync9(path11.join(SHARDS_DIR, `${safeName}.db`));
|
|
1687
2235
|
}
|
|
1688
2236
|
function listShards() {
|
|
1689
|
-
if (!
|
|
2237
|
+
if (!existsSync9(SHARDS_DIR)) return [];
|
|
1690
2238
|
return readdirSync2(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1691
2239
|
}
|
|
1692
2240
|
async function ensureShardSchema(client) {
|
|
@@ -1872,7 +2420,7 @@ var init_shard_manager = __esm({
|
|
|
1872
2420
|
"src/lib/shard-manager.ts"() {
|
|
1873
2421
|
"use strict";
|
|
1874
2422
|
init_config();
|
|
1875
|
-
SHARDS_DIR =
|
|
2423
|
+
SHARDS_DIR = path11.join(EXE_AI_DIR, "shards");
|
|
1876
2424
|
_shards = /* @__PURE__ */ new Map();
|
|
1877
2425
|
_encryptionKey = null;
|
|
1878
2426
|
_shardingEnabled = false;
|
|
@@ -1997,7 +2545,7 @@ __export(global_procedures_exports, {
|
|
|
1997
2545
|
loadGlobalProcedures: () => loadGlobalProcedures,
|
|
1998
2546
|
storeGlobalProcedure: () => storeGlobalProcedure
|
|
1999
2547
|
});
|
|
2000
|
-
import { randomUUID as
|
|
2548
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
2001
2549
|
async function loadGlobalProcedures() {
|
|
2002
2550
|
const client = getClient();
|
|
2003
2551
|
const result = await client.execute({
|
|
@@ -2026,7 +2574,7 @@ ${sections.join("\n\n")}
|
|
|
2026
2574
|
`;
|
|
2027
2575
|
}
|
|
2028
2576
|
async function storeGlobalProcedure(input2) {
|
|
2029
|
-
const id =
|
|
2577
|
+
const id = randomUUID3();
|
|
2030
2578
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2031
2579
|
const client = getClient();
|
|
2032
2580
|
await client.execute({
|
|
@@ -2077,6 +2625,7 @@ __export(store_exports, {
|
|
|
2077
2625
|
vectorToBlob: () => vectorToBlob,
|
|
2078
2626
|
writeMemory: () => writeMemory
|
|
2079
2627
|
});
|
|
2628
|
+
import { createHash } from "crypto";
|
|
2080
2629
|
function isBusyError2(err) {
|
|
2081
2630
|
if (err instanceof Error) {
|
|
2082
2631
|
const msg = err.message.toLowerCase();
|
|
@@ -2150,12 +2699,52 @@ function classifyTier(record) {
|
|
|
2150
2699
|
if (["store_memory", "manual"].includes(record.tool_name ?? "") && (record.importance ?? 0) >= 5) return 2;
|
|
2151
2700
|
return 3;
|
|
2152
2701
|
}
|
|
2702
|
+
function inferFilePaths(record) {
|
|
2703
|
+
if (!["Read", "Write", "Edit"].includes(record.tool_name)) return null;
|
|
2704
|
+
const firstLine = record.raw_text.split("\n")[0] ?? "";
|
|
2705
|
+
const match = firstLine.match(/(\/[\w./-]+\.\w+)/);
|
|
2706
|
+
return match ? JSON.stringify([match[1]]) : null;
|
|
2707
|
+
}
|
|
2708
|
+
function inferCommitHash(record) {
|
|
2709
|
+
if (record.tool_name !== "Bash") return null;
|
|
2710
|
+
const match = record.raw_text.match(/\b([a-f0-9]{7,40})\b/);
|
|
2711
|
+
return match ? match[1] : null;
|
|
2712
|
+
}
|
|
2713
|
+
function inferLanguageType(record) {
|
|
2714
|
+
const text = record.raw_text;
|
|
2715
|
+
if (!text || text.length < 10) return null;
|
|
2716
|
+
const trimmed = text.trimStart();
|
|
2717
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) return "json";
|
|
2718
|
+
if (/\b(SELECT|INSERT|UPDATE|DELETE|CREATE TABLE|ALTER TABLE)\b/i.test(text)) return "sql";
|
|
2719
|
+
if (/\b(function |const |import |export |class |def |async |=>)\b/.test(text)) return "code";
|
|
2720
|
+
if (trimmed.startsWith("#") || trimmed.startsWith("*")) return "prose";
|
|
2721
|
+
return "mixed";
|
|
2722
|
+
}
|
|
2723
|
+
function inferDomain(record) {
|
|
2724
|
+
const proj = (record.project_name ?? "").toLowerCase();
|
|
2725
|
+
if (proj.includes("marketing") || proj.includes("content")) return "marketing";
|
|
2726
|
+
if (proj.includes("crm") || proj.includes("customer")) return "customer";
|
|
2727
|
+
return null;
|
|
2728
|
+
}
|
|
2153
2729
|
async function writeMemory(record) {
|
|
2154
2730
|
if (record.vector !== null && record.vector.length !== EMBEDDING_DIM) {
|
|
2155
2731
|
throw new Error(
|
|
2156
2732
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
2157
2733
|
);
|
|
2158
2734
|
}
|
|
2735
|
+
const contentHash = createHash("md5").update(record.raw_text).digest("hex");
|
|
2736
|
+
if (_pendingRecords.some((r) => r.content_hash === contentHash && r.agent_id === record.agent_id)) {
|
|
2737
|
+
return;
|
|
2738
|
+
}
|
|
2739
|
+
try {
|
|
2740
|
+
const client = getClient();
|
|
2741
|
+
const existing = await client.execute({
|
|
2742
|
+
sql: "SELECT id FROM memories WHERE content_hash = ? AND agent_id = ? LIMIT 1",
|
|
2743
|
+
args: [contentHash, record.agent_id]
|
|
2744
|
+
});
|
|
2745
|
+
if (existing.rows.length > 0) return;
|
|
2746
|
+
} catch {
|
|
2747
|
+
}
|
|
2159
2748
|
const dbRow = {
|
|
2160
2749
|
id: record.id,
|
|
2161
2750
|
agent_id: record.agent_id,
|
|
@@ -2185,7 +2774,23 @@ async function writeMemory(record) {
|
|
|
2185
2774
|
supersedes_id: record.supersedes_id ?? null,
|
|
2186
2775
|
draft: record.draft ? 1 : 0,
|
|
2187
2776
|
memory_type: record.memory_type ?? "raw",
|
|
2188
|
-
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null
|
|
2777
|
+
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
2778
|
+
content_hash: contentHash,
|
|
2779
|
+
intent: record.intent ?? null,
|
|
2780
|
+
outcome: record.outcome ?? null,
|
|
2781
|
+
domain: record.domain ?? inferDomain(record),
|
|
2782
|
+
referenced_entities: record.referenced_entities ?? null,
|
|
2783
|
+
retrieval_count: record.retrieval_count ?? 0,
|
|
2784
|
+
chain_position: record.chain_position ?? null,
|
|
2785
|
+
review_status: record.review_status ?? null,
|
|
2786
|
+
context_window_pct: record.context_window_pct ?? null,
|
|
2787
|
+
file_paths: record.file_paths ?? inferFilePaths(record),
|
|
2788
|
+
commit_hash: record.commit_hash ?? inferCommitHash(record),
|
|
2789
|
+
duration_ms: record.duration_ms ?? null,
|
|
2790
|
+
token_cost: record.token_cost ?? null,
|
|
2791
|
+
audience: record.audience ?? null,
|
|
2792
|
+
language_type: record.language_type ?? inferLanguageType(record),
|
|
2793
|
+
parent_memory_id: record.parent_memory_id ?? null
|
|
2189
2794
|
};
|
|
2190
2795
|
_pendingRecords.push(dbRow);
|
|
2191
2796
|
orgBus.emit({
|
|
@@ -2243,80 +2848,85 @@ async function flushBatch() {
|
|
|
2243
2848
|
const draft = row.draft ? 1 : 0;
|
|
2244
2849
|
const memoryType = row.memory_type ?? "raw";
|
|
2245
2850
|
const trajectory = row.trajectory ?? null;
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2851
|
+
const contentHash = row.content_hash ?? null;
|
|
2852
|
+
const intent = row.intent ?? null;
|
|
2853
|
+
const outcome = row.outcome ?? null;
|
|
2854
|
+
const domain = row.domain ?? null;
|
|
2855
|
+
const referencedEntities = row.referenced_entities ?? null;
|
|
2856
|
+
const retrievalCount = row.retrieval_count ?? 0;
|
|
2857
|
+
const chainPosition = row.chain_position ?? null;
|
|
2858
|
+
const reviewStatus = row.review_status ?? null;
|
|
2859
|
+
const contextWindowPct = row.context_window_pct ?? null;
|
|
2860
|
+
const filePaths = row.file_paths ?? null;
|
|
2861
|
+
const commitHash = row.commit_hash ?? null;
|
|
2862
|
+
const durationMs = row.duration_ms ?? null;
|
|
2863
|
+
const tokenCost = row.token_cost ?? null;
|
|
2864
|
+
const audience = row.audience ?? null;
|
|
2865
|
+
const languageType = row.language_type ?? null;
|
|
2866
|
+
const parentMemoryId = row.parent_memory_id ?? null;
|
|
2867
|
+
const cols = `id, agent_id, agent_role, session_id, timestamp,
|
|
2256
2868
|
tool_name, project_name,
|
|
2257
2869
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
2258
2870
|
confidence, last_accessed,
|
|
2259
2871
|
workspace_id, document_id, user_id, char_offset, page_number,
|
|
2260
|
-
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
trajectory
|
|
2319
|
-
]
|
|
2872
|
+
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
|
|
2873
|
+
intent, outcome, domain, referenced_entities, retrieval_count,
|
|
2874
|
+
chain_position, review_status, context_window_pct, file_paths, commit_hash,
|
|
2875
|
+
duration_ms, token_cost, audience, language_type, parent_memory_id`;
|
|
2876
|
+
const metaArgs = [
|
|
2877
|
+
intent,
|
|
2878
|
+
outcome,
|
|
2879
|
+
domain,
|
|
2880
|
+
referencedEntities,
|
|
2881
|
+
retrievalCount,
|
|
2882
|
+
chainPosition,
|
|
2883
|
+
reviewStatus,
|
|
2884
|
+
contextWindowPct,
|
|
2885
|
+
filePaths,
|
|
2886
|
+
commitHash,
|
|
2887
|
+
durationMs,
|
|
2888
|
+
tokenCost,
|
|
2889
|
+
audience,
|
|
2890
|
+
languageType,
|
|
2891
|
+
parentMemoryId
|
|
2892
|
+
];
|
|
2893
|
+
const baseArgs = [
|
|
2894
|
+
row.id,
|
|
2895
|
+
row.agent_id,
|
|
2896
|
+
row.agent_role,
|
|
2897
|
+
row.session_id,
|
|
2898
|
+
row.timestamp,
|
|
2899
|
+
row.tool_name,
|
|
2900
|
+
row.project_name,
|
|
2901
|
+
row.has_error,
|
|
2902
|
+
row.raw_text
|
|
2903
|
+
];
|
|
2904
|
+
const sharedArgs = [
|
|
2905
|
+
row.version,
|
|
2906
|
+
taskId,
|
|
2907
|
+
importance,
|
|
2908
|
+
status,
|
|
2909
|
+
confidence,
|
|
2910
|
+
lastAccessed,
|
|
2911
|
+
workspaceId,
|
|
2912
|
+
documentId,
|
|
2913
|
+
userId,
|
|
2914
|
+
charOffset,
|
|
2915
|
+
pageNumber,
|
|
2916
|
+
sourcePath,
|
|
2917
|
+
sourceType,
|
|
2918
|
+
tier,
|
|
2919
|
+
supersedesId,
|
|
2920
|
+
draft,
|
|
2921
|
+
memoryType,
|
|
2922
|
+
trajectory,
|
|
2923
|
+
contentHash
|
|
2924
|
+
];
|
|
2925
|
+
return {
|
|
2926
|
+
sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
|
|
2927
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
|
|
2928
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
2929
|
+
args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
|
|
2320
2930
|
};
|
|
2321
2931
|
};
|
|
2322
2932
|
const globalClient = getClient();
|