@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
package/dist/hooks/stop.js
CHANGED
|
@@ -519,6 +519,443 @@ var init_db_retry = __esm({
|
|
|
519
519
|
}
|
|
520
520
|
});
|
|
521
521
|
|
|
522
|
+
// src/lib/exe-daemon-client.ts
|
|
523
|
+
import net from "net";
|
|
524
|
+
import { spawn } from "child_process";
|
|
525
|
+
import { randomUUID } from "crypto";
|
|
526
|
+
import { existsSync as existsSync4, unlinkSync as unlinkSync3, readFileSync as readFileSync5, openSync, closeSync, statSync } from "fs";
|
|
527
|
+
import path6 from "path";
|
|
528
|
+
import { fileURLToPath } from "url";
|
|
529
|
+
function handleData(chunk) {
|
|
530
|
+
_buffer += chunk.toString();
|
|
531
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
532
|
+
_buffer = "";
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
let newlineIdx;
|
|
536
|
+
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
537
|
+
const line = _buffer.slice(0, newlineIdx).trim();
|
|
538
|
+
_buffer = _buffer.slice(newlineIdx + 1);
|
|
539
|
+
if (!line) continue;
|
|
540
|
+
try {
|
|
541
|
+
const response = JSON.parse(line);
|
|
542
|
+
const id = response.id;
|
|
543
|
+
if (!id) continue;
|
|
544
|
+
const entry = _pending.get(id);
|
|
545
|
+
if (entry) {
|
|
546
|
+
clearTimeout(entry.timer);
|
|
547
|
+
_pending.delete(id);
|
|
548
|
+
entry.resolve(response);
|
|
549
|
+
}
|
|
550
|
+
} catch {
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
function cleanupStaleFiles() {
|
|
555
|
+
if (existsSync4(PID_PATH)) {
|
|
556
|
+
try {
|
|
557
|
+
const pid = parseInt(readFileSync5(PID_PATH, "utf8").trim(), 10);
|
|
558
|
+
if (pid > 0) {
|
|
559
|
+
try {
|
|
560
|
+
process.kill(pid, 0);
|
|
561
|
+
return;
|
|
562
|
+
} catch {
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
} catch {
|
|
566
|
+
}
|
|
567
|
+
try {
|
|
568
|
+
unlinkSync3(PID_PATH);
|
|
569
|
+
} catch {
|
|
570
|
+
}
|
|
571
|
+
try {
|
|
572
|
+
unlinkSync3(SOCKET_PATH);
|
|
573
|
+
} catch {
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
function findPackageRoot() {
|
|
578
|
+
let dir = path6.dirname(fileURLToPath(import.meta.url));
|
|
579
|
+
const { root } = path6.parse(dir);
|
|
580
|
+
while (dir !== root) {
|
|
581
|
+
if (existsSync4(path6.join(dir, "package.json"))) return dir;
|
|
582
|
+
dir = path6.dirname(dir);
|
|
583
|
+
}
|
|
584
|
+
return null;
|
|
585
|
+
}
|
|
586
|
+
function spawnDaemon() {
|
|
587
|
+
const pkgRoot = findPackageRoot();
|
|
588
|
+
if (!pkgRoot) {
|
|
589
|
+
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
const daemonPath = path6.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
593
|
+
if (!existsSync4(daemonPath)) {
|
|
594
|
+
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
595
|
+
`);
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
const resolvedPath = daemonPath;
|
|
599
|
+
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
600
|
+
`);
|
|
601
|
+
const logPath = path6.join(path6.dirname(SOCKET_PATH), "exed.log");
|
|
602
|
+
let stderrFd = "ignore";
|
|
603
|
+
try {
|
|
604
|
+
stderrFd = openSync(logPath, "a");
|
|
605
|
+
} catch {
|
|
606
|
+
}
|
|
607
|
+
const child = spawn(process.execPath, [resolvedPath], {
|
|
608
|
+
detached: true,
|
|
609
|
+
stdio: ["ignore", "ignore", stderrFd],
|
|
610
|
+
env: {
|
|
611
|
+
...process.env,
|
|
612
|
+
TMUX: void 0,
|
|
613
|
+
// Daemon is global — must not inherit session scope
|
|
614
|
+
TMUX_PANE: void 0,
|
|
615
|
+
// Prevents resolveExeSession() from scoping to one session
|
|
616
|
+
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
617
|
+
EXE_DAEMON_PID: PID_PATH
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
child.unref();
|
|
621
|
+
if (typeof stderrFd === "number") {
|
|
622
|
+
try {
|
|
623
|
+
closeSync(stderrFd);
|
|
624
|
+
} catch {
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
function acquireSpawnLock() {
|
|
629
|
+
try {
|
|
630
|
+
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
631
|
+
closeSync(fd);
|
|
632
|
+
return true;
|
|
633
|
+
} catch {
|
|
634
|
+
try {
|
|
635
|
+
const stat = statSync(SPAWN_LOCK_PATH);
|
|
636
|
+
if (Date.now() - stat.mtimeMs > SPAWN_LOCK_STALE_MS) {
|
|
637
|
+
try {
|
|
638
|
+
unlinkSync3(SPAWN_LOCK_PATH);
|
|
639
|
+
} catch {
|
|
640
|
+
}
|
|
641
|
+
try {
|
|
642
|
+
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
643
|
+
closeSync(fd);
|
|
644
|
+
return true;
|
|
645
|
+
} catch {
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
} catch {
|
|
649
|
+
}
|
|
650
|
+
return false;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
function releaseSpawnLock() {
|
|
654
|
+
try {
|
|
655
|
+
unlinkSync3(SPAWN_LOCK_PATH);
|
|
656
|
+
} catch {
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
function connectToSocket() {
|
|
660
|
+
return new Promise((resolve) => {
|
|
661
|
+
if (_socket && _connected) {
|
|
662
|
+
resolve(true);
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
const socket = net.createConnection({ path: SOCKET_PATH });
|
|
666
|
+
const connectTimeout = setTimeout(() => {
|
|
667
|
+
socket.destroy();
|
|
668
|
+
resolve(false);
|
|
669
|
+
}, 2e3);
|
|
670
|
+
socket.on("connect", () => {
|
|
671
|
+
clearTimeout(connectTimeout);
|
|
672
|
+
_socket = socket;
|
|
673
|
+
_connected = true;
|
|
674
|
+
_buffer = "";
|
|
675
|
+
socket.on("data", handleData);
|
|
676
|
+
socket.on("close", () => {
|
|
677
|
+
_connected = false;
|
|
678
|
+
_socket = null;
|
|
679
|
+
for (const [id, entry] of _pending) {
|
|
680
|
+
clearTimeout(entry.timer);
|
|
681
|
+
_pending.delete(id);
|
|
682
|
+
entry.resolve({ error: "Connection closed" });
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
socket.on("error", () => {
|
|
686
|
+
_connected = false;
|
|
687
|
+
_socket = null;
|
|
688
|
+
});
|
|
689
|
+
resolve(true);
|
|
690
|
+
});
|
|
691
|
+
socket.on("error", () => {
|
|
692
|
+
clearTimeout(connectTimeout);
|
|
693
|
+
resolve(false);
|
|
694
|
+
});
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
async function connectEmbedDaemon() {
|
|
698
|
+
if (_socket && _connected) return true;
|
|
699
|
+
if (await connectToSocket()) return true;
|
|
700
|
+
if (acquireSpawnLock()) {
|
|
701
|
+
try {
|
|
702
|
+
cleanupStaleFiles();
|
|
703
|
+
spawnDaemon();
|
|
704
|
+
} finally {
|
|
705
|
+
releaseSpawnLock();
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
const start = Date.now();
|
|
709
|
+
let delay2 = 100;
|
|
710
|
+
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
711
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
712
|
+
if (await connectToSocket()) return true;
|
|
713
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
714
|
+
}
|
|
715
|
+
return false;
|
|
716
|
+
}
|
|
717
|
+
function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
718
|
+
return new Promise((resolve) => {
|
|
719
|
+
if (!_socket || !_connected) {
|
|
720
|
+
resolve({ error: "Not connected" });
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
const id = randomUUID();
|
|
724
|
+
const timer = setTimeout(() => {
|
|
725
|
+
_pending.delete(id);
|
|
726
|
+
resolve({ error: "Request timeout" });
|
|
727
|
+
}, timeoutMs);
|
|
728
|
+
_pending.set(id, { resolve, timer });
|
|
729
|
+
try {
|
|
730
|
+
_socket.write(JSON.stringify({ id, ...payload }) + "\n");
|
|
731
|
+
} catch {
|
|
732
|
+
clearTimeout(timer);
|
|
733
|
+
_pending.delete(id);
|
|
734
|
+
resolve({ error: "Write failed" });
|
|
735
|
+
}
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
function isClientConnected() {
|
|
739
|
+
return _connected;
|
|
740
|
+
}
|
|
741
|
+
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _pending, MAX_BUFFER;
|
|
742
|
+
var init_exe_daemon_client = __esm({
|
|
743
|
+
"src/lib/exe-daemon-client.ts"() {
|
|
744
|
+
"use strict";
|
|
745
|
+
init_config();
|
|
746
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path6.join(EXE_AI_DIR, "exed.sock");
|
|
747
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path6.join(EXE_AI_DIR, "exed.pid");
|
|
748
|
+
SPAWN_LOCK_PATH = path6.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
749
|
+
SPAWN_LOCK_STALE_MS = 3e4;
|
|
750
|
+
CONNECT_TIMEOUT_MS = 15e3;
|
|
751
|
+
REQUEST_TIMEOUT_MS = 3e4;
|
|
752
|
+
_socket = null;
|
|
753
|
+
_connected = false;
|
|
754
|
+
_buffer = "";
|
|
755
|
+
_pending = /* @__PURE__ */ new Map();
|
|
756
|
+
MAX_BUFFER = 1e7;
|
|
757
|
+
}
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
// src/lib/daemon-protocol.ts
|
|
761
|
+
function serializeValue(v) {
|
|
762
|
+
if (v === null || v === void 0) return null;
|
|
763
|
+
if (typeof v === "bigint") return Number(v);
|
|
764
|
+
if (typeof v === "boolean") return v ? 1 : 0;
|
|
765
|
+
if (v instanceof Uint8Array) {
|
|
766
|
+
return { __blob: Buffer.from(v).toString("base64") };
|
|
767
|
+
}
|
|
768
|
+
if (ArrayBuffer.isView(v)) {
|
|
769
|
+
return { __blob: Buffer.from(v.buffer, v.byteOffset, v.byteLength).toString("base64") };
|
|
770
|
+
}
|
|
771
|
+
if (v instanceof ArrayBuffer) {
|
|
772
|
+
return { __blob: Buffer.from(v).toString("base64") };
|
|
773
|
+
}
|
|
774
|
+
if (typeof v === "string" || typeof v === "number") return v;
|
|
775
|
+
return String(v);
|
|
776
|
+
}
|
|
777
|
+
function deserializeValue(v) {
|
|
778
|
+
if (v === null) return null;
|
|
779
|
+
if (typeof v === "object" && v !== null && "__blob" in v) {
|
|
780
|
+
const buf = Buffer.from(v.__blob, "base64");
|
|
781
|
+
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
782
|
+
}
|
|
783
|
+
return v;
|
|
784
|
+
}
|
|
785
|
+
function deserializeResultSet(srs) {
|
|
786
|
+
const rows = srs.rows.map((obj) => {
|
|
787
|
+
const values = srs.columns.map(
|
|
788
|
+
(col) => deserializeValue(obj[col] ?? null)
|
|
789
|
+
);
|
|
790
|
+
const row = values;
|
|
791
|
+
for (let i = 0; i < srs.columns.length; i++) {
|
|
792
|
+
const col = srs.columns[i];
|
|
793
|
+
if (col !== void 0) {
|
|
794
|
+
row[col] = values[i] ?? null;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
Object.defineProperty(row, "length", {
|
|
798
|
+
value: values.length,
|
|
799
|
+
enumerable: false
|
|
800
|
+
});
|
|
801
|
+
return row;
|
|
802
|
+
});
|
|
803
|
+
return {
|
|
804
|
+
columns: srs.columns,
|
|
805
|
+
columnTypes: srs.columnTypes ?? [],
|
|
806
|
+
rows,
|
|
807
|
+
rowsAffected: srs.rowsAffected,
|
|
808
|
+
lastInsertRowid: srs.lastInsertRowid != null ? BigInt(srs.lastInsertRowid) : void 0,
|
|
809
|
+
toJSON: () => ({
|
|
810
|
+
columns: srs.columns,
|
|
811
|
+
columnTypes: srs.columnTypes ?? [],
|
|
812
|
+
rows: srs.rows,
|
|
813
|
+
rowsAffected: srs.rowsAffected,
|
|
814
|
+
lastInsertRowid: srs.lastInsertRowid
|
|
815
|
+
})
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
var init_daemon_protocol = __esm({
|
|
819
|
+
"src/lib/daemon-protocol.ts"() {
|
|
820
|
+
"use strict";
|
|
821
|
+
}
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
// src/lib/db-daemon-client.ts
|
|
825
|
+
var db_daemon_client_exports = {};
|
|
826
|
+
__export(db_daemon_client_exports, {
|
|
827
|
+
createDaemonDbClient: () => createDaemonDbClient,
|
|
828
|
+
initDaemonDbClient: () => initDaemonDbClient
|
|
829
|
+
});
|
|
830
|
+
function normalizeStatement(stmt) {
|
|
831
|
+
if (typeof stmt === "string") {
|
|
832
|
+
return { sql: stmt, args: [] };
|
|
833
|
+
}
|
|
834
|
+
const sql = stmt.sql;
|
|
835
|
+
let args = [];
|
|
836
|
+
if (Array.isArray(stmt.args)) {
|
|
837
|
+
args = stmt.args.map((v) => serializeValue(v));
|
|
838
|
+
} else if (stmt.args && typeof stmt.args === "object") {
|
|
839
|
+
const named = {};
|
|
840
|
+
for (const [key, val] of Object.entries(stmt.args)) {
|
|
841
|
+
named[key] = serializeValue(val);
|
|
842
|
+
}
|
|
843
|
+
return { sql, args: named };
|
|
844
|
+
}
|
|
845
|
+
return { sql, args };
|
|
846
|
+
}
|
|
847
|
+
function createDaemonDbClient(fallbackClient) {
|
|
848
|
+
let _useDaemon = false;
|
|
849
|
+
const client = {
|
|
850
|
+
async execute(stmt) {
|
|
851
|
+
if (!_useDaemon || !isClientConnected()) {
|
|
852
|
+
return fallbackClient.execute(stmt);
|
|
853
|
+
}
|
|
854
|
+
const { sql, args } = normalizeStatement(stmt);
|
|
855
|
+
const response = await sendDaemonRequest({
|
|
856
|
+
type: "db-execute",
|
|
857
|
+
sql,
|
|
858
|
+
args
|
|
859
|
+
});
|
|
860
|
+
if (response.error) {
|
|
861
|
+
const errMsg = String(response.error);
|
|
862
|
+
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
|
|
863
|
+
process.stderr.write(`[db-daemon] Transport error (${errMsg}), falling back to direct
|
|
864
|
+
`);
|
|
865
|
+
return fallbackClient.execute(stmt);
|
|
866
|
+
}
|
|
867
|
+
throw new Error(errMsg);
|
|
868
|
+
}
|
|
869
|
+
if (response.db) {
|
|
870
|
+
return deserializeResultSet(response.db);
|
|
871
|
+
}
|
|
872
|
+
process.stderr.write("[db-daemon] Unexpected response shape, falling back to direct\n");
|
|
873
|
+
return fallbackClient.execute(stmt);
|
|
874
|
+
},
|
|
875
|
+
async batch(stmts, mode) {
|
|
876
|
+
if (!_useDaemon || !isClientConnected()) {
|
|
877
|
+
return fallbackClient.batch(stmts, mode);
|
|
878
|
+
}
|
|
879
|
+
const statements = stmts.map(normalizeStatement);
|
|
880
|
+
const response = await sendDaemonRequest({
|
|
881
|
+
type: "db-batch",
|
|
882
|
+
statements,
|
|
883
|
+
mode: mode ?? "deferred"
|
|
884
|
+
});
|
|
885
|
+
if (response.error) {
|
|
886
|
+
const errMsg = String(response.error);
|
|
887
|
+
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
|
|
888
|
+
process.stderr.write(`[db-daemon] Batch transport error (${errMsg}), falling back to direct
|
|
889
|
+
`);
|
|
890
|
+
return fallbackClient.batch(stmts, mode);
|
|
891
|
+
}
|
|
892
|
+
throw new Error(errMsg);
|
|
893
|
+
}
|
|
894
|
+
const batchResults = response["db-batch"];
|
|
895
|
+
if (batchResults) {
|
|
896
|
+
return batchResults.map(deserializeResultSet);
|
|
897
|
+
}
|
|
898
|
+
process.stderr.write("[db-daemon] Unexpected batch response shape, falling back to direct\n");
|
|
899
|
+
return fallbackClient.batch(stmts, mode);
|
|
900
|
+
},
|
|
901
|
+
// Transaction support — delegate to fallback (transactions need direct connection)
|
|
902
|
+
async transaction(mode) {
|
|
903
|
+
return fallbackClient.transaction(mode);
|
|
904
|
+
},
|
|
905
|
+
// executeMultiple — delegate to fallback (used only for schema migrations)
|
|
906
|
+
async executeMultiple(sql) {
|
|
907
|
+
return fallbackClient.executeMultiple(sql);
|
|
908
|
+
},
|
|
909
|
+
// migrate — delegate to fallback
|
|
910
|
+
async migrate(stmts) {
|
|
911
|
+
return fallbackClient.migrate(stmts);
|
|
912
|
+
},
|
|
913
|
+
// Sync mode — delegate to fallback
|
|
914
|
+
sync() {
|
|
915
|
+
return fallbackClient.sync();
|
|
916
|
+
},
|
|
917
|
+
close() {
|
|
918
|
+
_useDaemon = false;
|
|
919
|
+
},
|
|
920
|
+
get closed() {
|
|
921
|
+
return fallbackClient.closed;
|
|
922
|
+
},
|
|
923
|
+
get protocol() {
|
|
924
|
+
return fallbackClient.protocol;
|
|
925
|
+
}
|
|
926
|
+
};
|
|
927
|
+
return {
|
|
928
|
+
...client,
|
|
929
|
+
/** Enable daemon routing (call after confirming daemon is connected) */
|
|
930
|
+
_enableDaemon() {
|
|
931
|
+
_useDaemon = true;
|
|
932
|
+
},
|
|
933
|
+
/** Check if daemon routing is active */
|
|
934
|
+
_isDaemonActive() {
|
|
935
|
+
return _useDaemon && isClientConnected();
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
async function initDaemonDbClient(fallbackClient) {
|
|
940
|
+
if (process.env.EXE_IS_DAEMON === "1") return null;
|
|
941
|
+
const connected = await connectEmbedDaemon();
|
|
942
|
+
if (!connected) {
|
|
943
|
+
process.stderr.write("[db-daemon] Daemon unavailable \u2014 using direct SQLite\n");
|
|
944
|
+
return null;
|
|
945
|
+
}
|
|
946
|
+
const client = createDaemonDbClient(fallbackClient);
|
|
947
|
+
client._enableDaemon();
|
|
948
|
+
process.stderr.write("[db-daemon] DB routing through daemon (single-writer)\n");
|
|
949
|
+
return client;
|
|
950
|
+
}
|
|
951
|
+
var init_db_daemon_client = __esm({
|
|
952
|
+
"src/lib/db-daemon-client.ts"() {
|
|
953
|
+
"use strict";
|
|
954
|
+
init_exe_daemon_client();
|
|
955
|
+
init_daemon_protocol();
|
|
956
|
+
}
|
|
957
|
+
});
|
|
958
|
+
|
|
522
959
|
// src/lib/database.ts
|
|
523
960
|
var database_exports = {};
|
|
524
961
|
__export(database_exports, {
|
|
@@ -527,6 +964,7 @@ __export(database_exports, {
|
|
|
527
964
|
ensureSchema: () => ensureSchema,
|
|
528
965
|
getClient: () => getClient,
|
|
529
966
|
getRawClient: () => getRawClient,
|
|
967
|
+
initDaemonClient: () => initDaemonClient,
|
|
530
968
|
initDatabase: () => initDatabase,
|
|
531
969
|
initTurso: () => initTurso,
|
|
532
970
|
isInitialized: () => isInitialized
|
|
@@ -554,8 +992,27 @@ function getClient() {
|
|
|
554
992
|
if (!_resilientClient) {
|
|
555
993
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
556
994
|
}
|
|
995
|
+
if (process.env.EXE_IS_DAEMON === "1") {
|
|
996
|
+
return _resilientClient;
|
|
997
|
+
}
|
|
998
|
+
if (_daemonClient && _daemonClient._isDaemonActive()) {
|
|
999
|
+
return _daemonClient;
|
|
1000
|
+
}
|
|
557
1001
|
return _resilientClient;
|
|
558
1002
|
}
|
|
1003
|
+
async function initDaemonClient() {
|
|
1004
|
+
if (process.env.EXE_IS_DAEMON === "1") return;
|
|
1005
|
+
if (!_resilientClient) return;
|
|
1006
|
+
try {
|
|
1007
|
+
const { initDaemonDbClient: initDaemonDbClient2 } = await Promise.resolve().then(() => (init_db_daemon_client(), db_daemon_client_exports));
|
|
1008
|
+
_daemonClient = await initDaemonDbClient2(_resilientClient);
|
|
1009
|
+
} catch (err) {
|
|
1010
|
+
process.stderr.write(
|
|
1011
|
+
`[database] Daemon client init failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
|
|
1012
|
+
`
|
|
1013
|
+
);
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
559
1016
|
function getRawClient() {
|
|
560
1017
|
if (!_client) {
|
|
561
1018
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
@@ -1042,6 +1499,12 @@ async function ensureSchema() {
|
|
|
1042
1499
|
} catch {
|
|
1043
1500
|
}
|
|
1044
1501
|
}
|
|
1502
|
+
try {
|
|
1503
|
+
await client.execute(
|
|
1504
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
|
|
1505
|
+
);
|
|
1506
|
+
} catch {
|
|
1507
|
+
}
|
|
1045
1508
|
await client.executeMultiple(`
|
|
1046
1509
|
CREATE TABLE IF NOT EXISTS entities (
|
|
1047
1510
|
id TEXT PRIMARY KEY,
|
|
@@ -1094,7 +1557,30 @@ async function ensureSchema() {
|
|
|
1094
1557
|
entity_id TEXT NOT NULL,
|
|
1095
1558
|
PRIMARY KEY (hyperedge_id, entity_id)
|
|
1096
1559
|
);
|
|
1560
|
+
|
|
1561
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
|
|
1562
|
+
name,
|
|
1563
|
+
content=entities,
|
|
1564
|
+
content_rowid=rowid
|
|
1565
|
+
);
|
|
1566
|
+
|
|
1567
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
|
|
1568
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
1569
|
+
END;
|
|
1570
|
+
|
|
1571
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
|
|
1572
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
1573
|
+
END;
|
|
1574
|
+
|
|
1575
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
|
|
1576
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
1577
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
1578
|
+
END;
|
|
1097
1579
|
`);
|
|
1580
|
+
try {
|
|
1581
|
+
await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
|
|
1582
|
+
} catch {
|
|
1583
|
+
}
|
|
1098
1584
|
await client.executeMultiple(`
|
|
1099
1585
|
CREATE TABLE IF NOT EXISTS entity_aliases (
|
|
1100
1586
|
alias TEXT NOT NULL PRIMARY KEY,
|
|
@@ -1275,6 +1761,33 @@ async function ensureSchema() {
|
|
|
1275
1761
|
CREATE INDEX IF NOT EXISTS idx_conversations_channel
|
|
1276
1762
|
ON conversations(channel_id);
|
|
1277
1763
|
`);
|
|
1764
|
+
await client.executeMultiple(`
|
|
1765
|
+
CREATE TABLE IF NOT EXISTS session_agent_map (
|
|
1766
|
+
session_uuid TEXT PRIMARY KEY,
|
|
1767
|
+
agent_id TEXT NOT NULL,
|
|
1768
|
+
session_name TEXT,
|
|
1769
|
+
task_id TEXT,
|
|
1770
|
+
project_name TEXT,
|
|
1771
|
+
started_at TEXT NOT NULL
|
|
1772
|
+
);
|
|
1773
|
+
|
|
1774
|
+
CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
|
|
1775
|
+
ON session_agent_map(agent_id);
|
|
1776
|
+
`);
|
|
1777
|
+
try {
|
|
1778
|
+
const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
|
|
1779
|
+
if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
|
|
1780
|
+
await client.execute({
|
|
1781
|
+
sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
|
|
1782
|
+
SELECT session_id, agent_id, '', MIN(timestamp)
|
|
1783
|
+
FROM memories
|
|
1784
|
+
WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
|
|
1785
|
+
GROUP BY session_id, agent_id`,
|
|
1786
|
+
args: []
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
} catch {
|
|
1790
|
+
}
|
|
1278
1791
|
try {
|
|
1279
1792
|
await client.execute({
|
|
1280
1793
|
sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
|
|
@@ -1408,15 +1921,41 @@ async function ensureSchema() {
|
|
|
1408
1921
|
});
|
|
1409
1922
|
} catch {
|
|
1410
1923
|
}
|
|
1924
|
+
for (const col of [
|
|
1925
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
1926
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
1927
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
1928
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
1929
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
1930
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
1931
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
1932
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
1933
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
1934
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
1935
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
1936
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
1937
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
1938
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
1939
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
1940
|
+
]) {
|
|
1941
|
+
try {
|
|
1942
|
+
await client.execute(col);
|
|
1943
|
+
} catch {
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1411
1946
|
}
|
|
1412
1947
|
async function disposeDatabase() {
|
|
1948
|
+
if (_daemonClient) {
|
|
1949
|
+
_daemonClient.close();
|
|
1950
|
+
_daemonClient = null;
|
|
1951
|
+
}
|
|
1413
1952
|
if (_client) {
|
|
1414
1953
|
_client.close();
|
|
1415
1954
|
_client = null;
|
|
1416
1955
|
_resilientClient = null;
|
|
1417
1956
|
}
|
|
1418
1957
|
}
|
|
1419
|
-
var _client, _resilientClient, initTurso, disposeTurso;
|
|
1958
|
+
var _client, _resilientClient, _daemonClient, initTurso, disposeTurso;
|
|
1420
1959
|
var init_database = __esm({
|
|
1421
1960
|
"src/lib/database.ts"() {
|
|
1422
1961
|
"use strict";
|
|
@@ -1424,30 +1963,31 @@ var init_database = __esm({
|
|
|
1424
1963
|
init_employees();
|
|
1425
1964
|
_client = null;
|
|
1426
1965
|
_resilientClient = null;
|
|
1966
|
+
_daemonClient = null;
|
|
1427
1967
|
initTurso = initDatabase;
|
|
1428
1968
|
disposeTurso = disposeDatabase;
|
|
1429
1969
|
}
|
|
1430
1970
|
});
|
|
1431
1971
|
|
|
1432
1972
|
// src/lib/license.ts
|
|
1433
|
-
import { readFileSync as
|
|
1434
|
-
import { randomUUID } from "crypto";
|
|
1435
|
-
import
|
|
1973
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
1974
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
1975
|
+
import path7 from "path";
|
|
1436
1976
|
import { jwtVerify, importSPKI } from "jose";
|
|
1437
1977
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
1438
1978
|
var init_license = __esm({
|
|
1439
1979
|
"src/lib/license.ts"() {
|
|
1440
1980
|
"use strict";
|
|
1441
1981
|
init_config();
|
|
1442
|
-
LICENSE_PATH =
|
|
1443
|
-
CACHE_PATH =
|
|
1444
|
-
DEVICE_ID_PATH =
|
|
1982
|
+
LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
|
|
1983
|
+
CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
1984
|
+
DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
|
|
1445
1985
|
}
|
|
1446
1986
|
});
|
|
1447
1987
|
|
|
1448
1988
|
// src/lib/plan-limits.ts
|
|
1449
|
-
import { readFileSync as
|
|
1450
|
-
import
|
|
1989
|
+
import { readFileSync as readFileSync7, existsSync as existsSync6 } from "fs";
|
|
1990
|
+
import path8 from "path";
|
|
1451
1991
|
var CACHE_PATH2;
|
|
1452
1992
|
var init_plan_limits = __esm({
|
|
1453
1993
|
"src/lib/plan-limits.ts"() {
|
|
@@ -1456,15 +1996,15 @@ var init_plan_limits = __esm({
|
|
|
1456
1996
|
init_employees();
|
|
1457
1997
|
init_license();
|
|
1458
1998
|
init_config();
|
|
1459
|
-
CACHE_PATH2 =
|
|
1999
|
+
CACHE_PATH2 = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
1460
2000
|
}
|
|
1461
2001
|
});
|
|
1462
2002
|
|
|
1463
2003
|
// src/lib/tmux-routing.ts
|
|
1464
|
-
import { readFileSync as
|
|
1465
|
-
import
|
|
2004
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync7, appendFileSync } from "fs";
|
|
2005
|
+
import path9 from "path";
|
|
1466
2006
|
import os5 from "os";
|
|
1467
|
-
import { fileURLToPath } from "url";
|
|
2007
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1468
2008
|
function getMySession() {
|
|
1469
2009
|
return getTransport().getMySession();
|
|
1470
2010
|
}
|
|
@@ -1476,7 +2016,7 @@ function extractRootExe(name) {
|
|
|
1476
2016
|
}
|
|
1477
2017
|
function getParentExe(sessionKey) {
|
|
1478
2018
|
try {
|
|
1479
|
-
const data = JSON.parse(
|
|
2019
|
+
const data = JSON.parse(readFileSync8(path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
1480
2020
|
return data.parentExe || null;
|
|
1481
2021
|
} catch {
|
|
1482
2022
|
return null;
|
|
@@ -1508,10 +2048,10 @@ var init_tmux_routing = __esm({
|
|
|
1508
2048
|
init_intercom_queue();
|
|
1509
2049
|
init_plan_limits();
|
|
1510
2050
|
init_employees();
|
|
1511
|
-
SPAWN_LOCK_DIR =
|
|
1512
|
-
SESSION_CACHE =
|
|
1513
|
-
INTERCOM_LOG2 =
|
|
1514
|
-
DEBOUNCE_FILE =
|
|
2051
|
+
SPAWN_LOCK_DIR = path9.join(os5.homedir(), ".exe-os", "spawn-locks");
|
|
2052
|
+
SESSION_CACHE = path9.join(os5.homedir(), ".exe-os", "session-cache");
|
|
2053
|
+
INTERCOM_LOG2 = path9.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
2054
|
+
DEBOUNCE_FILE = path9.join(SESSION_CACHE, "intercom-debounce.json");
|
|
1515
2055
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
1516
2056
|
}
|
|
1517
2057
|
});
|
|
@@ -1551,14 +2091,14 @@ var init_memory = __esm({
|
|
|
1551
2091
|
|
|
1552
2092
|
// src/lib/keychain.ts
|
|
1553
2093
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
1554
|
-
import { existsSync as
|
|
1555
|
-
import
|
|
2094
|
+
import { existsSync as existsSync8 } from "fs";
|
|
2095
|
+
import path10 from "path";
|
|
1556
2096
|
import os6 from "os";
|
|
1557
2097
|
function getKeyDir() {
|
|
1558
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
2098
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path10.join(os6.homedir(), ".exe-os");
|
|
1559
2099
|
}
|
|
1560
2100
|
function getKeyPath() {
|
|
1561
|
-
return
|
|
2101
|
+
return path10.join(getKeyDir(), "master.key");
|
|
1562
2102
|
}
|
|
1563
2103
|
async function tryKeytar() {
|
|
1564
2104
|
try {
|
|
@@ -1579,13 +2119,21 @@ async function getMasterKey() {
|
|
|
1579
2119
|
}
|
|
1580
2120
|
}
|
|
1581
2121
|
const keyPath = getKeyPath();
|
|
1582
|
-
if (!
|
|
2122
|
+
if (!existsSync8(keyPath)) {
|
|
2123
|
+
process.stderr.write(
|
|
2124
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os6.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
2125
|
+
`
|
|
2126
|
+
);
|
|
1583
2127
|
return null;
|
|
1584
2128
|
}
|
|
1585
2129
|
try {
|
|
1586
2130
|
const content = await readFile3(keyPath, "utf-8");
|
|
1587
2131
|
return Buffer.from(content.trim(), "base64");
|
|
1588
|
-
} catch {
|
|
2132
|
+
} catch (err) {
|
|
2133
|
+
process.stderr.write(
|
|
2134
|
+
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
2135
|
+
`
|
|
2136
|
+
);
|
|
1589
2137
|
return null;
|
|
1590
2138
|
}
|
|
1591
2139
|
}
|
|
@@ -1666,12 +2214,12 @@ __export(shard_manager_exports, {
|
|
|
1666
2214
|
listShards: () => listShards,
|
|
1667
2215
|
shardExists: () => shardExists
|
|
1668
2216
|
});
|
|
1669
|
-
import
|
|
1670
|
-
import { existsSync as
|
|
2217
|
+
import path11 from "path";
|
|
2218
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync as readdirSync2 } from "fs";
|
|
1671
2219
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1672
2220
|
function initShardManager(encryptionKey) {
|
|
1673
2221
|
_encryptionKey = encryptionKey;
|
|
1674
|
-
if (!
|
|
2222
|
+
if (!existsSync9(SHARDS_DIR)) {
|
|
1675
2223
|
mkdirSync5(SHARDS_DIR, { recursive: true });
|
|
1676
2224
|
}
|
|
1677
2225
|
_shardingEnabled = true;
|
|
@@ -1692,7 +2240,7 @@ function getShardClient(projectName) {
|
|
|
1692
2240
|
}
|
|
1693
2241
|
const cached = _shards.get(safeName);
|
|
1694
2242
|
if (cached) return cached;
|
|
1695
|
-
const dbPath =
|
|
2243
|
+
const dbPath = path11.join(SHARDS_DIR, `${safeName}.db`);
|
|
1696
2244
|
const client = createClient2({
|
|
1697
2245
|
url: `file:${dbPath}`,
|
|
1698
2246
|
encryptionKey: _encryptionKey
|
|
@@ -1702,10 +2250,10 @@ function getShardClient(projectName) {
|
|
|
1702
2250
|
}
|
|
1703
2251
|
function shardExists(projectName) {
|
|
1704
2252
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1705
|
-
return
|
|
2253
|
+
return existsSync9(path11.join(SHARDS_DIR, `${safeName}.db`));
|
|
1706
2254
|
}
|
|
1707
2255
|
function listShards() {
|
|
1708
|
-
if (!
|
|
2256
|
+
if (!existsSync9(SHARDS_DIR)) return [];
|
|
1709
2257
|
return readdirSync2(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1710
2258
|
}
|
|
1711
2259
|
async function ensureShardSchema(client) {
|
|
@@ -1891,7 +2439,7 @@ var init_shard_manager = __esm({
|
|
|
1891
2439
|
"src/lib/shard-manager.ts"() {
|
|
1892
2440
|
"use strict";
|
|
1893
2441
|
init_config();
|
|
1894
|
-
SHARDS_DIR =
|
|
2442
|
+
SHARDS_DIR = path11.join(EXE_AI_DIR, "shards");
|
|
1895
2443
|
_shards = /* @__PURE__ */ new Map();
|
|
1896
2444
|
_encryptionKey = null;
|
|
1897
2445
|
_shardingEnabled = false;
|
|
@@ -2016,7 +2564,7 @@ __export(global_procedures_exports, {
|
|
|
2016
2564
|
loadGlobalProcedures: () => loadGlobalProcedures,
|
|
2017
2565
|
storeGlobalProcedure: () => storeGlobalProcedure
|
|
2018
2566
|
});
|
|
2019
|
-
import { randomUUID as
|
|
2567
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
2020
2568
|
async function loadGlobalProcedures() {
|
|
2021
2569
|
const client = getClient();
|
|
2022
2570
|
const result = await client.execute({
|
|
@@ -2045,7 +2593,7 @@ ${sections.join("\n\n")}
|
|
|
2045
2593
|
`;
|
|
2046
2594
|
}
|
|
2047
2595
|
async function storeGlobalProcedure(input2) {
|
|
2048
|
-
const id =
|
|
2596
|
+
const id = randomUUID3();
|
|
2049
2597
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2050
2598
|
const client = getClient();
|
|
2051
2599
|
await client.execute({
|
|
@@ -2096,6 +2644,7 @@ __export(store_exports, {
|
|
|
2096
2644
|
vectorToBlob: () => vectorToBlob,
|
|
2097
2645
|
writeMemory: () => writeMemory
|
|
2098
2646
|
});
|
|
2647
|
+
import { createHash } from "crypto";
|
|
2099
2648
|
function isBusyError2(err) {
|
|
2100
2649
|
if (err instanceof Error) {
|
|
2101
2650
|
const msg = err.message.toLowerCase();
|
|
@@ -2169,12 +2718,52 @@ function classifyTier(record) {
|
|
|
2169
2718
|
if (["store_memory", "manual"].includes(record.tool_name ?? "") && (record.importance ?? 0) >= 5) return 2;
|
|
2170
2719
|
return 3;
|
|
2171
2720
|
}
|
|
2721
|
+
function inferFilePaths(record) {
|
|
2722
|
+
if (!["Read", "Write", "Edit"].includes(record.tool_name)) return null;
|
|
2723
|
+
const firstLine = record.raw_text.split("\n")[0] ?? "";
|
|
2724
|
+
const match = firstLine.match(/(\/[\w./-]+\.\w+)/);
|
|
2725
|
+
return match ? JSON.stringify([match[1]]) : null;
|
|
2726
|
+
}
|
|
2727
|
+
function inferCommitHash(record) {
|
|
2728
|
+
if (record.tool_name !== "Bash") return null;
|
|
2729
|
+
const match = record.raw_text.match(/\b([a-f0-9]{7,40})\b/);
|
|
2730
|
+
return match ? match[1] : null;
|
|
2731
|
+
}
|
|
2732
|
+
function inferLanguageType(record) {
|
|
2733
|
+
const text = record.raw_text;
|
|
2734
|
+
if (!text || text.length < 10) return null;
|
|
2735
|
+
const trimmed = text.trimStart();
|
|
2736
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) return "json";
|
|
2737
|
+
if (/\b(SELECT|INSERT|UPDATE|DELETE|CREATE TABLE|ALTER TABLE)\b/i.test(text)) return "sql";
|
|
2738
|
+
if (/\b(function |const |import |export |class |def |async |=>)\b/.test(text)) return "code";
|
|
2739
|
+
if (trimmed.startsWith("#") || trimmed.startsWith("*")) return "prose";
|
|
2740
|
+
return "mixed";
|
|
2741
|
+
}
|
|
2742
|
+
function inferDomain(record) {
|
|
2743
|
+
const proj = (record.project_name ?? "").toLowerCase();
|
|
2744
|
+
if (proj.includes("marketing") || proj.includes("content")) return "marketing";
|
|
2745
|
+
if (proj.includes("crm") || proj.includes("customer")) return "customer";
|
|
2746
|
+
return null;
|
|
2747
|
+
}
|
|
2172
2748
|
async function writeMemory(record) {
|
|
2173
2749
|
if (record.vector !== null && record.vector.length !== EMBEDDING_DIM) {
|
|
2174
2750
|
throw new Error(
|
|
2175
2751
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
2176
2752
|
);
|
|
2177
2753
|
}
|
|
2754
|
+
const contentHash = createHash("md5").update(record.raw_text).digest("hex");
|
|
2755
|
+
if (_pendingRecords.some((r) => r.content_hash === contentHash && r.agent_id === record.agent_id)) {
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2758
|
+
try {
|
|
2759
|
+
const client = getClient();
|
|
2760
|
+
const existing = await client.execute({
|
|
2761
|
+
sql: "SELECT id FROM memories WHERE content_hash = ? AND agent_id = ? LIMIT 1",
|
|
2762
|
+
args: [contentHash, record.agent_id]
|
|
2763
|
+
});
|
|
2764
|
+
if (existing.rows.length > 0) return;
|
|
2765
|
+
} catch {
|
|
2766
|
+
}
|
|
2178
2767
|
const dbRow = {
|
|
2179
2768
|
id: record.id,
|
|
2180
2769
|
agent_id: record.agent_id,
|
|
@@ -2204,7 +2793,23 @@ async function writeMemory(record) {
|
|
|
2204
2793
|
supersedes_id: record.supersedes_id ?? null,
|
|
2205
2794
|
draft: record.draft ? 1 : 0,
|
|
2206
2795
|
memory_type: record.memory_type ?? "raw",
|
|
2207
|
-
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null
|
|
2796
|
+
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
2797
|
+
content_hash: contentHash,
|
|
2798
|
+
intent: record.intent ?? null,
|
|
2799
|
+
outcome: record.outcome ?? null,
|
|
2800
|
+
domain: record.domain ?? inferDomain(record),
|
|
2801
|
+
referenced_entities: record.referenced_entities ?? null,
|
|
2802
|
+
retrieval_count: record.retrieval_count ?? 0,
|
|
2803
|
+
chain_position: record.chain_position ?? null,
|
|
2804
|
+
review_status: record.review_status ?? null,
|
|
2805
|
+
context_window_pct: record.context_window_pct ?? null,
|
|
2806
|
+
file_paths: record.file_paths ?? inferFilePaths(record),
|
|
2807
|
+
commit_hash: record.commit_hash ?? inferCommitHash(record),
|
|
2808
|
+
duration_ms: record.duration_ms ?? null,
|
|
2809
|
+
token_cost: record.token_cost ?? null,
|
|
2810
|
+
audience: record.audience ?? null,
|
|
2811
|
+
language_type: record.language_type ?? inferLanguageType(record),
|
|
2812
|
+
parent_memory_id: record.parent_memory_id ?? null
|
|
2208
2813
|
};
|
|
2209
2814
|
_pendingRecords.push(dbRow);
|
|
2210
2815
|
orgBus.emit({
|
|
@@ -2262,80 +2867,85 @@ async function flushBatch() {
|
|
|
2262
2867
|
const draft = row.draft ? 1 : 0;
|
|
2263
2868
|
const memoryType = row.memory_type ?? "raw";
|
|
2264
2869
|
const trajectory = row.trajectory ?? null;
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2870
|
+
const contentHash = row.content_hash ?? null;
|
|
2871
|
+
const intent = row.intent ?? null;
|
|
2872
|
+
const outcome = row.outcome ?? null;
|
|
2873
|
+
const domain = row.domain ?? null;
|
|
2874
|
+
const referencedEntities = row.referenced_entities ?? null;
|
|
2875
|
+
const retrievalCount = row.retrieval_count ?? 0;
|
|
2876
|
+
const chainPosition = row.chain_position ?? null;
|
|
2877
|
+
const reviewStatus = row.review_status ?? null;
|
|
2878
|
+
const contextWindowPct = row.context_window_pct ?? null;
|
|
2879
|
+
const filePaths = row.file_paths ?? null;
|
|
2880
|
+
const commitHash = row.commit_hash ?? null;
|
|
2881
|
+
const durationMs = row.duration_ms ?? null;
|
|
2882
|
+
const tokenCost = row.token_cost ?? null;
|
|
2883
|
+
const audience = row.audience ?? null;
|
|
2884
|
+
const languageType = row.language_type ?? null;
|
|
2885
|
+
const parentMemoryId = row.parent_memory_id ?? null;
|
|
2886
|
+
const cols = `id, agent_id, agent_role, session_id, timestamp,
|
|
2268
2887
|
tool_name, project_name,
|
|
2269
2888
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
2270
2889
|
confidence, last_accessed,
|
|
2271
2890
|
workspace_id, document_id, user_id, char_offset, page_number,
|
|
2272
|
-
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory
|
|
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
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
pageNumber,
|
|
2331
|
-
sourcePath,
|
|
2332
|
-
sourceType,
|
|
2333
|
-
tier,
|
|
2334
|
-
supersedesId,
|
|
2335
|
-
draft,
|
|
2336
|
-
memoryType,
|
|
2337
|
-
trajectory
|
|
2338
|
-
]
|
|
2891
|
+
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
|
|
2892
|
+
intent, outcome, domain, referenced_entities, retrieval_count,
|
|
2893
|
+
chain_position, review_status, context_window_pct, file_paths, commit_hash,
|
|
2894
|
+
duration_ms, token_cost, audience, language_type, parent_memory_id`;
|
|
2895
|
+
const metaArgs = [
|
|
2896
|
+
intent,
|
|
2897
|
+
outcome,
|
|
2898
|
+
domain,
|
|
2899
|
+
referencedEntities,
|
|
2900
|
+
retrievalCount,
|
|
2901
|
+
chainPosition,
|
|
2902
|
+
reviewStatus,
|
|
2903
|
+
contextWindowPct,
|
|
2904
|
+
filePaths,
|
|
2905
|
+
commitHash,
|
|
2906
|
+
durationMs,
|
|
2907
|
+
tokenCost,
|
|
2908
|
+
audience,
|
|
2909
|
+
languageType,
|
|
2910
|
+
parentMemoryId
|
|
2911
|
+
];
|
|
2912
|
+
const baseArgs = [
|
|
2913
|
+
row.id,
|
|
2914
|
+
row.agent_id,
|
|
2915
|
+
row.agent_role,
|
|
2916
|
+
row.session_id,
|
|
2917
|
+
row.timestamp,
|
|
2918
|
+
row.tool_name,
|
|
2919
|
+
row.project_name,
|
|
2920
|
+
row.has_error,
|
|
2921
|
+
row.raw_text
|
|
2922
|
+
];
|
|
2923
|
+
const sharedArgs = [
|
|
2924
|
+
row.version,
|
|
2925
|
+
taskId,
|
|
2926
|
+
importance,
|
|
2927
|
+
status,
|
|
2928
|
+
confidence,
|
|
2929
|
+
lastAccessed,
|
|
2930
|
+
workspaceId,
|
|
2931
|
+
documentId,
|
|
2932
|
+
userId,
|
|
2933
|
+
charOffset,
|
|
2934
|
+
pageNumber,
|
|
2935
|
+
sourcePath,
|
|
2936
|
+
sourceType,
|
|
2937
|
+
tier,
|
|
2938
|
+
supersedesId,
|
|
2939
|
+
draft,
|
|
2940
|
+
memoryType,
|
|
2941
|
+
trajectory,
|
|
2942
|
+
contentHash
|
|
2943
|
+
];
|
|
2944
|
+
return {
|
|
2945
|
+
sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
|
|
2946
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
|
|
2947
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
2948
|
+
args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
|
|
2339
2949
|
};
|
|
2340
2950
|
};
|
|
2341
2951
|
const globalClient = getClient();
|
|
@@ -2588,10 +3198,10 @@ var init_store = __esm({
|
|
|
2588
3198
|
// src/adapters/claude/hooks/stop.ts
|
|
2589
3199
|
init_config();
|
|
2590
3200
|
init_config();
|
|
2591
|
-
import { spawn } from "child_process";
|
|
2592
|
-
import { existsSync as
|
|
2593
|
-
import
|
|
2594
|
-
import { fileURLToPath as
|
|
3201
|
+
import { spawn as spawn2 } from "child_process";
|
|
3202
|
+
import { existsSync as existsSync10, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
3203
|
+
import path12 from "path";
|
|
3204
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2595
3205
|
|
|
2596
3206
|
// src/adapters/claude/active-agent.ts
|
|
2597
3207
|
init_config();
|
|
@@ -2704,10 +3314,10 @@ if (!process.env.AGENT_ID) {
|
|
|
2704
3314
|
if (!loadConfigSync().autoIngestion) {
|
|
2705
3315
|
process.exit(0);
|
|
2706
3316
|
}
|
|
2707
|
-
var WORKER_LOG_PATH =
|
|
3317
|
+
var WORKER_LOG_PATH = path12.join(EXE_AI_DIR, "workers.log");
|
|
2708
3318
|
function openWorkerLog() {
|
|
2709
3319
|
try {
|
|
2710
|
-
return
|
|
3320
|
+
return openSync2(WORKER_LOG_PATH, "a");
|
|
2711
3321
|
} catch {
|
|
2712
3322
|
return "ignore";
|
|
2713
3323
|
}
|
|
@@ -2796,17 +3406,17 @@ process.stdin.on("end", () => {
|
|
|
2796
3406
|
}).catch(() => {
|
|
2797
3407
|
});
|
|
2798
3408
|
}
|
|
2799
|
-
const workerPath =
|
|
2800
|
-
|
|
3409
|
+
const workerPath = path12.resolve(
|
|
3410
|
+
path12.dirname(fileURLToPath3(import.meta.url)),
|
|
2801
3411
|
"response-ingest-worker.js"
|
|
2802
3412
|
);
|
|
2803
|
-
if (!
|
|
3413
|
+
if (!existsSync10(workerPath)) {
|
|
2804
3414
|
process.stderr.write(`[stop] WARN: response-ingest-worker not found at ${workerPath}
|
|
2805
3415
|
`);
|
|
2806
3416
|
process.exit(0);
|
|
2807
3417
|
}
|
|
2808
3418
|
const stderrFd = openWorkerLog();
|
|
2809
|
-
const worker =
|
|
3419
|
+
const worker = spawn2(process.execPath, [workerPath], {
|
|
2810
3420
|
detached: true,
|
|
2811
3421
|
stdio: ["ignore", "ignore", stderrFd],
|
|
2812
3422
|
env: {
|
|
@@ -2819,7 +3429,7 @@ process.stdin.on("end", () => {
|
|
|
2819
3429
|
});
|
|
2820
3430
|
worker.unref();
|
|
2821
3431
|
if (typeof stderrFd === "number") try {
|
|
2822
|
-
|
|
3432
|
+
closeSync2(stderrFd);
|
|
2823
3433
|
} catch {
|
|
2824
3434
|
}
|
|
2825
3435
|
} catch {
|