@askexenow/exe-os 0.8.83 → 0.8.86
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 +154 -21
- package/dist/bin/cli.js +14678 -12676
- package/dist/bin/exe-agent-config.js +242 -0
- package/dist/bin/exe-agent.js +100 -91
- package/dist/bin/exe-assign.js +1003 -854
- package/dist/bin/exe-boot.js +1420 -485
- package/dist/bin/exe-call.js +10 -0
- package/dist/bin/exe-cloud.js +29 -6
- package/dist/bin/exe-dispatch.js +572 -271
- package/dist/bin/exe-doctor.js +403 -6
- package/dist/bin/exe-export-behaviors.js +175 -72
- package/dist/bin/exe-forget.js +102 -3
- package/dist/bin/exe-gateway.js +796 -292
- package/dist/bin/exe-healthcheck.js +134 -1
- package/dist/bin/exe-heartbeat.js +172 -36
- package/dist/bin/exe-kill.js +175 -72
- package/dist/bin/exe-launch-agent.js +189 -76
- package/dist/bin/exe-link.js +927 -82
- package/dist/bin/exe-new-employee.js +60 -8
- package/dist/bin/exe-pending-messages.js +151 -19
- package/dist/bin/exe-pending-notifications.js +97 -2
- package/dist/bin/exe-pending-reviews.js +155 -22
- package/dist/bin/exe-rename.js +564 -23
- package/dist/bin/exe-review.js +231 -73
- package/dist/bin/exe-search.js +995 -228
- package/dist/bin/exe-session-cleanup.js +4930 -1664
- package/dist/bin/exe-settings.js +20 -5
- package/dist/bin/exe-start-codex.js +2598 -0
- package/dist/bin/exe-start.sh +15 -3
- package/dist/bin/exe-status.js +154 -21
- package/dist/bin/exe-team.js +97 -2
- package/dist/bin/git-sweep.js +1180 -363
- package/dist/bin/graph-backfill.js +175 -72
- package/dist/bin/graph-export.js +175 -72
- package/dist/bin/install.js +60 -7
- package/dist/bin/list-providers.js +1 -0
- package/dist/bin/scan-tasks.js +1185 -367
- package/dist/bin/setup.js +914 -270
- 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 +792 -285
- package/dist/hooks/bug-report-worker.js +445 -135
- package/dist/hooks/commit-complete.js +1178 -361
- package/dist/hooks/error-recall.js +994 -228
- package/dist/hooks/ingest-worker.js +1799 -1234
- 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 +757 -109
- package/dist/hooks/pre-compact.js +1061 -244
- package/dist/hooks/pre-tool-use.js +787 -130
- package/dist/hooks/prompt-ingest-worker.js +242 -101
- package/dist/hooks/prompt-submit.js +1121 -299
- package/dist/hooks/response-ingest-worker.js +242 -101
- package/dist/hooks/session-end.js +4063 -397
- package/dist/hooks/session-start.js +1071 -254
- package/dist/hooks/stop.js +768 -120
- package/dist/hooks/subagent-stop.js +757 -109
- package/dist/hooks/summary-worker.js +1706 -1011
- package/dist/index.js +1821 -1098
- package/dist/lib/agent-config.js +167 -0
- package/dist/lib/cloud-sync.js +932 -88
- 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 +2733 -1575
- package/dist/lib/hybrid-search.js +995 -228
- package/dist/lib/identity.js +87 -67
- package/dist/lib/keychain.js +9 -1
- package/dist/lib/messaging.js +103 -40
- package/dist/lib/reminders.js +91 -74
- package/dist/lib/runtime-table.js +16 -0
- package/dist/lib/schedules.js +96 -2
- package/dist/lib/session-wrappers.js +22 -0
- package/dist/lib/skill-learning.js +103 -85
- package/dist/lib/store.js +234 -73
- package/dist/lib/tasks.js +348 -134
- package/dist/lib/tmux-routing.js +422 -208
- package/dist/lib/token-spend.js +273 -0
- package/dist/lib/ws-client.js +11 -0
- package/dist/mcp/server.js +5742 -696
- 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 +375 -152
- 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 +99 -31
- package/dist/mcp/tools/send-message.js +108 -45
- package/dist/mcp/tools/update-task.js +162 -77
- package/dist/runtime/index.js +1075 -258
- package/dist/tui/App.js +1333 -506
- package/package.json +6 -1
- package/src/commands/exe/agent-config.md +27 -0
- package/src/commands/exe/cc-doctor.md +10 -0
|
@@ -424,17 +424,53 @@ var init_provider_table = __esm({
|
|
|
424
424
|
}
|
|
425
425
|
});
|
|
426
426
|
|
|
427
|
-
// src/lib/
|
|
428
|
-
|
|
427
|
+
// src/lib/runtime-table.ts
|
|
428
|
+
var RUNTIME_TABLE;
|
|
429
|
+
var init_runtime_table = __esm({
|
|
430
|
+
"src/lib/runtime-table.ts"() {
|
|
431
|
+
"use strict";
|
|
432
|
+
RUNTIME_TABLE = {
|
|
433
|
+
codex: {
|
|
434
|
+
binary: "codex",
|
|
435
|
+
launchMode: "exec",
|
|
436
|
+
autoApproveFlag: "--full-auto",
|
|
437
|
+
inlineFlag: "--no-alt-screen",
|
|
438
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
439
|
+
defaultModel: "gpt-5.4"
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
// src/lib/agent-config.ts
|
|
446
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
429
447
|
import path5 from "path";
|
|
448
|
+
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
449
|
+
var init_agent_config = __esm({
|
|
450
|
+
"src/lib/agent-config.ts"() {
|
|
451
|
+
"use strict";
|
|
452
|
+
init_config();
|
|
453
|
+
init_runtime_table();
|
|
454
|
+
AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
|
|
455
|
+
DEFAULT_MODELS = {
|
|
456
|
+
claude: "claude-opus-4",
|
|
457
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
458
|
+
opencode: "minimax-m2.7"
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
// src/lib/intercom-queue.ts
|
|
464
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
465
|
+
import path6 from "path";
|
|
430
466
|
import os4 from "os";
|
|
431
467
|
var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
432
468
|
var init_intercom_queue = __esm({
|
|
433
469
|
"src/lib/intercom-queue.ts"() {
|
|
434
470
|
"use strict";
|
|
435
|
-
QUEUE_PATH =
|
|
471
|
+
QUEUE_PATH = path6.join(os4.homedir(), ".exe-os", "intercom-queue.json");
|
|
436
472
|
TTL_MS = 60 * 60 * 1e3;
|
|
437
|
-
INTERCOM_LOG =
|
|
473
|
+
INTERCOM_LOG = path6.join(os4.homedir(), ".exe-os", "intercom.log");
|
|
438
474
|
}
|
|
439
475
|
});
|
|
440
476
|
|
|
@@ -493,6 +529,443 @@ var init_db_retry = __esm({
|
|
|
493
529
|
}
|
|
494
530
|
});
|
|
495
531
|
|
|
532
|
+
// src/lib/exe-daemon-client.ts
|
|
533
|
+
import net from "net";
|
|
534
|
+
import { spawn } from "child_process";
|
|
535
|
+
import { randomUUID } from "crypto";
|
|
536
|
+
import { existsSync as existsSync5, unlinkSync as unlinkSync3, readFileSync as readFileSync6, openSync, closeSync, statSync } from "fs";
|
|
537
|
+
import path7 from "path";
|
|
538
|
+
import { fileURLToPath } from "url";
|
|
539
|
+
function handleData(chunk) {
|
|
540
|
+
_buffer += chunk.toString();
|
|
541
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
542
|
+
_buffer = "";
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
let newlineIdx;
|
|
546
|
+
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
547
|
+
const line = _buffer.slice(0, newlineIdx).trim();
|
|
548
|
+
_buffer = _buffer.slice(newlineIdx + 1);
|
|
549
|
+
if (!line) continue;
|
|
550
|
+
try {
|
|
551
|
+
const response = JSON.parse(line);
|
|
552
|
+
const id = response.id;
|
|
553
|
+
if (!id) continue;
|
|
554
|
+
const entry = _pending.get(id);
|
|
555
|
+
if (entry) {
|
|
556
|
+
clearTimeout(entry.timer);
|
|
557
|
+
_pending.delete(id);
|
|
558
|
+
entry.resolve(response);
|
|
559
|
+
}
|
|
560
|
+
} catch {
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
function cleanupStaleFiles() {
|
|
565
|
+
if (existsSync5(PID_PATH)) {
|
|
566
|
+
try {
|
|
567
|
+
const pid = parseInt(readFileSync6(PID_PATH, "utf8").trim(), 10);
|
|
568
|
+
if (pid > 0) {
|
|
569
|
+
try {
|
|
570
|
+
process.kill(pid, 0);
|
|
571
|
+
return;
|
|
572
|
+
} catch {
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
} catch {
|
|
576
|
+
}
|
|
577
|
+
try {
|
|
578
|
+
unlinkSync3(PID_PATH);
|
|
579
|
+
} catch {
|
|
580
|
+
}
|
|
581
|
+
try {
|
|
582
|
+
unlinkSync3(SOCKET_PATH);
|
|
583
|
+
} catch {
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
function findPackageRoot() {
|
|
588
|
+
let dir = path7.dirname(fileURLToPath(import.meta.url));
|
|
589
|
+
const { root } = path7.parse(dir);
|
|
590
|
+
while (dir !== root) {
|
|
591
|
+
if (existsSync5(path7.join(dir, "package.json"))) return dir;
|
|
592
|
+
dir = path7.dirname(dir);
|
|
593
|
+
}
|
|
594
|
+
return null;
|
|
595
|
+
}
|
|
596
|
+
function spawnDaemon() {
|
|
597
|
+
const pkgRoot = findPackageRoot();
|
|
598
|
+
if (!pkgRoot) {
|
|
599
|
+
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
const daemonPath = path7.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
603
|
+
if (!existsSync5(daemonPath)) {
|
|
604
|
+
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
605
|
+
`);
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
const resolvedPath = daemonPath;
|
|
609
|
+
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
610
|
+
`);
|
|
611
|
+
const logPath = path7.join(path7.dirname(SOCKET_PATH), "exed.log");
|
|
612
|
+
let stderrFd = "ignore";
|
|
613
|
+
try {
|
|
614
|
+
stderrFd = openSync(logPath, "a");
|
|
615
|
+
} catch {
|
|
616
|
+
}
|
|
617
|
+
const child = spawn(process.execPath, [resolvedPath], {
|
|
618
|
+
detached: true,
|
|
619
|
+
stdio: ["ignore", "ignore", stderrFd],
|
|
620
|
+
env: {
|
|
621
|
+
...process.env,
|
|
622
|
+
TMUX: void 0,
|
|
623
|
+
// Daemon is global — must not inherit session scope
|
|
624
|
+
TMUX_PANE: void 0,
|
|
625
|
+
// Prevents resolveExeSession() from scoping to one session
|
|
626
|
+
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
627
|
+
EXE_DAEMON_PID: PID_PATH
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
child.unref();
|
|
631
|
+
if (typeof stderrFd === "number") {
|
|
632
|
+
try {
|
|
633
|
+
closeSync(stderrFd);
|
|
634
|
+
} catch {
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
function acquireSpawnLock() {
|
|
639
|
+
try {
|
|
640
|
+
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
641
|
+
closeSync(fd);
|
|
642
|
+
return true;
|
|
643
|
+
} catch {
|
|
644
|
+
try {
|
|
645
|
+
const stat = statSync(SPAWN_LOCK_PATH);
|
|
646
|
+
if (Date.now() - stat.mtimeMs > SPAWN_LOCK_STALE_MS) {
|
|
647
|
+
try {
|
|
648
|
+
unlinkSync3(SPAWN_LOCK_PATH);
|
|
649
|
+
} catch {
|
|
650
|
+
}
|
|
651
|
+
try {
|
|
652
|
+
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
653
|
+
closeSync(fd);
|
|
654
|
+
return true;
|
|
655
|
+
} catch {
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
} catch {
|
|
659
|
+
}
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
function releaseSpawnLock() {
|
|
664
|
+
try {
|
|
665
|
+
unlinkSync3(SPAWN_LOCK_PATH);
|
|
666
|
+
} catch {
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
function connectToSocket() {
|
|
670
|
+
return new Promise((resolve) => {
|
|
671
|
+
if (_socket && _connected) {
|
|
672
|
+
resolve(true);
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
const socket = net.createConnection({ path: SOCKET_PATH });
|
|
676
|
+
const connectTimeout = setTimeout(() => {
|
|
677
|
+
socket.destroy();
|
|
678
|
+
resolve(false);
|
|
679
|
+
}, 2e3);
|
|
680
|
+
socket.on("connect", () => {
|
|
681
|
+
clearTimeout(connectTimeout);
|
|
682
|
+
_socket = socket;
|
|
683
|
+
_connected = true;
|
|
684
|
+
_buffer = "";
|
|
685
|
+
socket.on("data", handleData);
|
|
686
|
+
socket.on("close", () => {
|
|
687
|
+
_connected = false;
|
|
688
|
+
_socket = null;
|
|
689
|
+
for (const [id, entry] of _pending) {
|
|
690
|
+
clearTimeout(entry.timer);
|
|
691
|
+
_pending.delete(id);
|
|
692
|
+
entry.resolve({ error: "Connection closed" });
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
socket.on("error", () => {
|
|
696
|
+
_connected = false;
|
|
697
|
+
_socket = null;
|
|
698
|
+
});
|
|
699
|
+
resolve(true);
|
|
700
|
+
});
|
|
701
|
+
socket.on("error", () => {
|
|
702
|
+
clearTimeout(connectTimeout);
|
|
703
|
+
resolve(false);
|
|
704
|
+
});
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
async function connectEmbedDaemon() {
|
|
708
|
+
if (_socket && _connected) return true;
|
|
709
|
+
if (await connectToSocket()) return true;
|
|
710
|
+
if (acquireSpawnLock()) {
|
|
711
|
+
try {
|
|
712
|
+
cleanupStaleFiles();
|
|
713
|
+
spawnDaemon();
|
|
714
|
+
} finally {
|
|
715
|
+
releaseSpawnLock();
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
const start = Date.now();
|
|
719
|
+
let delay2 = 100;
|
|
720
|
+
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
721
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
722
|
+
if (await connectToSocket()) return true;
|
|
723
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
724
|
+
}
|
|
725
|
+
return false;
|
|
726
|
+
}
|
|
727
|
+
function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
728
|
+
return new Promise((resolve) => {
|
|
729
|
+
if (!_socket || !_connected) {
|
|
730
|
+
resolve({ error: "Not connected" });
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
const id = randomUUID();
|
|
734
|
+
const timer = setTimeout(() => {
|
|
735
|
+
_pending.delete(id);
|
|
736
|
+
resolve({ error: "Request timeout" });
|
|
737
|
+
}, timeoutMs);
|
|
738
|
+
_pending.set(id, { resolve, timer });
|
|
739
|
+
try {
|
|
740
|
+
_socket.write(JSON.stringify({ id, ...payload }) + "\n");
|
|
741
|
+
} catch {
|
|
742
|
+
clearTimeout(timer);
|
|
743
|
+
_pending.delete(id);
|
|
744
|
+
resolve({ error: "Write failed" });
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
function isClientConnected() {
|
|
749
|
+
return _connected;
|
|
750
|
+
}
|
|
751
|
+
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _pending, MAX_BUFFER;
|
|
752
|
+
var init_exe_daemon_client = __esm({
|
|
753
|
+
"src/lib/exe-daemon-client.ts"() {
|
|
754
|
+
"use strict";
|
|
755
|
+
init_config();
|
|
756
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path7.join(EXE_AI_DIR, "exed.sock");
|
|
757
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path7.join(EXE_AI_DIR, "exed.pid");
|
|
758
|
+
SPAWN_LOCK_PATH = path7.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
759
|
+
SPAWN_LOCK_STALE_MS = 3e4;
|
|
760
|
+
CONNECT_TIMEOUT_MS = 15e3;
|
|
761
|
+
REQUEST_TIMEOUT_MS = 3e4;
|
|
762
|
+
_socket = null;
|
|
763
|
+
_connected = false;
|
|
764
|
+
_buffer = "";
|
|
765
|
+
_pending = /* @__PURE__ */ new Map();
|
|
766
|
+
MAX_BUFFER = 1e7;
|
|
767
|
+
}
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
// src/lib/daemon-protocol.ts
|
|
771
|
+
function serializeValue(v) {
|
|
772
|
+
if (v === null || v === void 0) return null;
|
|
773
|
+
if (typeof v === "bigint") return Number(v);
|
|
774
|
+
if (typeof v === "boolean") return v ? 1 : 0;
|
|
775
|
+
if (v instanceof Uint8Array) {
|
|
776
|
+
return { __blob: Buffer.from(v).toString("base64") };
|
|
777
|
+
}
|
|
778
|
+
if (ArrayBuffer.isView(v)) {
|
|
779
|
+
return { __blob: Buffer.from(v.buffer, v.byteOffset, v.byteLength).toString("base64") };
|
|
780
|
+
}
|
|
781
|
+
if (v instanceof ArrayBuffer) {
|
|
782
|
+
return { __blob: Buffer.from(v).toString("base64") };
|
|
783
|
+
}
|
|
784
|
+
if (typeof v === "string" || typeof v === "number") return v;
|
|
785
|
+
return String(v);
|
|
786
|
+
}
|
|
787
|
+
function deserializeValue(v) {
|
|
788
|
+
if (v === null) return null;
|
|
789
|
+
if (typeof v === "object" && v !== null && "__blob" in v) {
|
|
790
|
+
const buf = Buffer.from(v.__blob, "base64");
|
|
791
|
+
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
792
|
+
}
|
|
793
|
+
return v;
|
|
794
|
+
}
|
|
795
|
+
function deserializeResultSet(srs) {
|
|
796
|
+
const rows = srs.rows.map((obj) => {
|
|
797
|
+
const values = srs.columns.map(
|
|
798
|
+
(col) => deserializeValue(obj[col] ?? null)
|
|
799
|
+
);
|
|
800
|
+
const row = values;
|
|
801
|
+
for (let i = 0; i < srs.columns.length; i++) {
|
|
802
|
+
const col = srs.columns[i];
|
|
803
|
+
if (col !== void 0) {
|
|
804
|
+
row[col] = values[i] ?? null;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
Object.defineProperty(row, "length", {
|
|
808
|
+
value: values.length,
|
|
809
|
+
enumerable: false
|
|
810
|
+
});
|
|
811
|
+
return row;
|
|
812
|
+
});
|
|
813
|
+
return {
|
|
814
|
+
columns: srs.columns,
|
|
815
|
+
columnTypes: srs.columnTypes ?? [],
|
|
816
|
+
rows,
|
|
817
|
+
rowsAffected: srs.rowsAffected,
|
|
818
|
+
lastInsertRowid: srs.lastInsertRowid != null ? BigInt(srs.lastInsertRowid) : void 0,
|
|
819
|
+
toJSON: () => ({
|
|
820
|
+
columns: srs.columns,
|
|
821
|
+
columnTypes: srs.columnTypes ?? [],
|
|
822
|
+
rows: srs.rows,
|
|
823
|
+
rowsAffected: srs.rowsAffected,
|
|
824
|
+
lastInsertRowid: srs.lastInsertRowid
|
|
825
|
+
})
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
var init_daemon_protocol = __esm({
|
|
829
|
+
"src/lib/daemon-protocol.ts"() {
|
|
830
|
+
"use strict";
|
|
831
|
+
}
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
// src/lib/db-daemon-client.ts
|
|
835
|
+
var db_daemon_client_exports = {};
|
|
836
|
+
__export(db_daemon_client_exports, {
|
|
837
|
+
createDaemonDbClient: () => createDaemonDbClient,
|
|
838
|
+
initDaemonDbClient: () => initDaemonDbClient
|
|
839
|
+
});
|
|
840
|
+
function normalizeStatement(stmt) {
|
|
841
|
+
if (typeof stmt === "string") {
|
|
842
|
+
return { sql: stmt, args: [] };
|
|
843
|
+
}
|
|
844
|
+
const sql = stmt.sql;
|
|
845
|
+
let args = [];
|
|
846
|
+
if (Array.isArray(stmt.args)) {
|
|
847
|
+
args = stmt.args.map((v) => serializeValue(v));
|
|
848
|
+
} else if (stmt.args && typeof stmt.args === "object") {
|
|
849
|
+
const named = {};
|
|
850
|
+
for (const [key, val] of Object.entries(stmt.args)) {
|
|
851
|
+
named[key] = serializeValue(val);
|
|
852
|
+
}
|
|
853
|
+
return { sql, args: named };
|
|
854
|
+
}
|
|
855
|
+
return { sql, args };
|
|
856
|
+
}
|
|
857
|
+
function createDaemonDbClient(fallbackClient) {
|
|
858
|
+
let _useDaemon = false;
|
|
859
|
+
const client = {
|
|
860
|
+
async execute(stmt) {
|
|
861
|
+
if (!_useDaemon || !isClientConnected()) {
|
|
862
|
+
return fallbackClient.execute(stmt);
|
|
863
|
+
}
|
|
864
|
+
const { sql, args } = normalizeStatement(stmt);
|
|
865
|
+
const response = await sendDaemonRequest({
|
|
866
|
+
type: "db-execute",
|
|
867
|
+
sql,
|
|
868
|
+
args
|
|
869
|
+
});
|
|
870
|
+
if (response.error) {
|
|
871
|
+
const errMsg = String(response.error);
|
|
872
|
+
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
|
|
873
|
+
process.stderr.write(`[db-daemon] Transport error (${errMsg}), falling back to direct
|
|
874
|
+
`);
|
|
875
|
+
return fallbackClient.execute(stmt);
|
|
876
|
+
}
|
|
877
|
+
throw new Error(errMsg);
|
|
878
|
+
}
|
|
879
|
+
if (response.db) {
|
|
880
|
+
return deserializeResultSet(response.db);
|
|
881
|
+
}
|
|
882
|
+
process.stderr.write("[db-daemon] Unexpected response shape, falling back to direct\n");
|
|
883
|
+
return fallbackClient.execute(stmt);
|
|
884
|
+
},
|
|
885
|
+
async batch(stmts, mode) {
|
|
886
|
+
if (!_useDaemon || !isClientConnected()) {
|
|
887
|
+
return fallbackClient.batch(stmts, mode);
|
|
888
|
+
}
|
|
889
|
+
const statements = stmts.map(normalizeStatement);
|
|
890
|
+
const response = await sendDaemonRequest({
|
|
891
|
+
type: "db-batch",
|
|
892
|
+
statements,
|
|
893
|
+
mode: mode ?? "deferred"
|
|
894
|
+
});
|
|
895
|
+
if (response.error) {
|
|
896
|
+
const errMsg = String(response.error);
|
|
897
|
+
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
|
|
898
|
+
process.stderr.write(`[db-daemon] Batch transport error (${errMsg}), falling back to direct
|
|
899
|
+
`);
|
|
900
|
+
return fallbackClient.batch(stmts, mode);
|
|
901
|
+
}
|
|
902
|
+
throw new Error(errMsg);
|
|
903
|
+
}
|
|
904
|
+
const batchResults = response["db-batch"];
|
|
905
|
+
if (batchResults) {
|
|
906
|
+
return batchResults.map(deserializeResultSet);
|
|
907
|
+
}
|
|
908
|
+
process.stderr.write("[db-daemon] Unexpected batch response shape, falling back to direct\n");
|
|
909
|
+
return fallbackClient.batch(stmts, mode);
|
|
910
|
+
},
|
|
911
|
+
// Transaction support — delegate to fallback (transactions need direct connection)
|
|
912
|
+
async transaction(mode) {
|
|
913
|
+
return fallbackClient.transaction(mode);
|
|
914
|
+
},
|
|
915
|
+
// executeMultiple — delegate to fallback (used only for schema migrations)
|
|
916
|
+
async executeMultiple(sql) {
|
|
917
|
+
return fallbackClient.executeMultiple(sql);
|
|
918
|
+
},
|
|
919
|
+
// migrate — delegate to fallback
|
|
920
|
+
async migrate(stmts) {
|
|
921
|
+
return fallbackClient.migrate(stmts);
|
|
922
|
+
},
|
|
923
|
+
// Sync mode — delegate to fallback
|
|
924
|
+
sync() {
|
|
925
|
+
return fallbackClient.sync();
|
|
926
|
+
},
|
|
927
|
+
close() {
|
|
928
|
+
_useDaemon = false;
|
|
929
|
+
},
|
|
930
|
+
get closed() {
|
|
931
|
+
return fallbackClient.closed;
|
|
932
|
+
},
|
|
933
|
+
get protocol() {
|
|
934
|
+
return fallbackClient.protocol;
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
return {
|
|
938
|
+
...client,
|
|
939
|
+
/** Enable daemon routing (call after confirming daemon is connected) */
|
|
940
|
+
_enableDaemon() {
|
|
941
|
+
_useDaemon = true;
|
|
942
|
+
},
|
|
943
|
+
/** Check if daemon routing is active */
|
|
944
|
+
_isDaemonActive() {
|
|
945
|
+
return _useDaemon && isClientConnected();
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
async function initDaemonDbClient(fallbackClient) {
|
|
950
|
+
if (process.env.EXE_IS_DAEMON === "1") return null;
|
|
951
|
+
const connected = await connectEmbedDaemon();
|
|
952
|
+
if (!connected) {
|
|
953
|
+
process.stderr.write("[db-daemon] Daemon unavailable \u2014 using direct SQLite\n");
|
|
954
|
+
return null;
|
|
955
|
+
}
|
|
956
|
+
const client = createDaemonDbClient(fallbackClient);
|
|
957
|
+
client._enableDaemon();
|
|
958
|
+
process.stderr.write("[db-daemon] DB routing through daemon (single-writer)\n");
|
|
959
|
+
return client;
|
|
960
|
+
}
|
|
961
|
+
var init_db_daemon_client = __esm({
|
|
962
|
+
"src/lib/db-daemon-client.ts"() {
|
|
963
|
+
"use strict";
|
|
964
|
+
init_exe_daemon_client();
|
|
965
|
+
init_daemon_protocol();
|
|
966
|
+
}
|
|
967
|
+
});
|
|
968
|
+
|
|
496
969
|
// src/lib/database.ts
|
|
497
970
|
var database_exports = {};
|
|
498
971
|
__export(database_exports, {
|
|
@@ -501,6 +974,7 @@ __export(database_exports, {
|
|
|
501
974
|
ensureSchema: () => ensureSchema,
|
|
502
975
|
getClient: () => getClient,
|
|
503
976
|
getRawClient: () => getRawClient,
|
|
977
|
+
initDaemonClient: () => initDaemonClient,
|
|
504
978
|
initDatabase: () => initDatabase,
|
|
505
979
|
initTurso: () => initTurso,
|
|
506
980
|
isInitialized: () => isInitialized
|
|
@@ -528,8 +1002,27 @@ function getClient() {
|
|
|
528
1002
|
if (!_resilientClient) {
|
|
529
1003
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
530
1004
|
}
|
|
1005
|
+
if (process.env.EXE_IS_DAEMON === "1") {
|
|
1006
|
+
return _resilientClient;
|
|
1007
|
+
}
|
|
1008
|
+
if (_daemonClient && _daemonClient._isDaemonActive()) {
|
|
1009
|
+
return _daemonClient;
|
|
1010
|
+
}
|
|
531
1011
|
return _resilientClient;
|
|
532
1012
|
}
|
|
1013
|
+
async function initDaemonClient() {
|
|
1014
|
+
if (process.env.EXE_IS_DAEMON === "1") return;
|
|
1015
|
+
if (!_resilientClient) return;
|
|
1016
|
+
try {
|
|
1017
|
+
const { initDaemonDbClient: initDaemonDbClient2 } = await Promise.resolve().then(() => (init_db_daemon_client(), db_daemon_client_exports));
|
|
1018
|
+
_daemonClient = await initDaemonDbClient2(_resilientClient);
|
|
1019
|
+
} catch (err) {
|
|
1020
|
+
process.stderr.write(
|
|
1021
|
+
`[database] Daemon client init failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
|
|
1022
|
+
`
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
533
1026
|
function getRawClient() {
|
|
534
1027
|
if (!_client) {
|
|
535
1028
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
@@ -1016,6 +1509,12 @@ async function ensureSchema() {
|
|
|
1016
1509
|
} catch {
|
|
1017
1510
|
}
|
|
1018
1511
|
}
|
|
1512
|
+
try {
|
|
1513
|
+
await client.execute(
|
|
1514
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
|
|
1515
|
+
);
|
|
1516
|
+
} catch {
|
|
1517
|
+
}
|
|
1019
1518
|
await client.executeMultiple(`
|
|
1020
1519
|
CREATE TABLE IF NOT EXISTS entities (
|
|
1021
1520
|
id TEXT PRIMARY KEY,
|
|
@@ -1068,7 +1567,30 @@ async function ensureSchema() {
|
|
|
1068
1567
|
entity_id TEXT NOT NULL,
|
|
1069
1568
|
PRIMARY KEY (hyperedge_id, entity_id)
|
|
1070
1569
|
);
|
|
1570
|
+
|
|
1571
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
|
|
1572
|
+
name,
|
|
1573
|
+
content=entities,
|
|
1574
|
+
content_rowid=rowid
|
|
1575
|
+
);
|
|
1576
|
+
|
|
1577
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
|
|
1578
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
1579
|
+
END;
|
|
1580
|
+
|
|
1581
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
|
|
1582
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
1583
|
+
END;
|
|
1584
|
+
|
|
1585
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
|
|
1586
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
1587
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
1588
|
+
END;
|
|
1071
1589
|
`);
|
|
1590
|
+
try {
|
|
1591
|
+
await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
|
|
1592
|
+
} catch {
|
|
1593
|
+
}
|
|
1072
1594
|
await client.executeMultiple(`
|
|
1073
1595
|
CREATE TABLE IF NOT EXISTS entity_aliases (
|
|
1074
1596
|
alias TEXT NOT NULL PRIMARY KEY,
|
|
@@ -1249,6 +1771,33 @@ async function ensureSchema() {
|
|
|
1249
1771
|
CREATE INDEX IF NOT EXISTS idx_conversations_channel
|
|
1250
1772
|
ON conversations(channel_id);
|
|
1251
1773
|
`);
|
|
1774
|
+
await client.executeMultiple(`
|
|
1775
|
+
CREATE TABLE IF NOT EXISTS session_agent_map (
|
|
1776
|
+
session_uuid TEXT PRIMARY KEY,
|
|
1777
|
+
agent_id TEXT NOT NULL,
|
|
1778
|
+
session_name TEXT,
|
|
1779
|
+
task_id TEXT,
|
|
1780
|
+
project_name TEXT,
|
|
1781
|
+
started_at TEXT NOT NULL
|
|
1782
|
+
);
|
|
1783
|
+
|
|
1784
|
+
CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
|
|
1785
|
+
ON session_agent_map(agent_id);
|
|
1786
|
+
`);
|
|
1787
|
+
try {
|
|
1788
|
+
const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
|
|
1789
|
+
if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
|
|
1790
|
+
await client.execute({
|
|
1791
|
+
sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
|
|
1792
|
+
SELECT session_id, agent_id, '', MIN(timestamp)
|
|
1793
|
+
FROM memories
|
|
1794
|
+
WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
|
|
1795
|
+
GROUP BY session_id, agent_id`,
|
|
1796
|
+
args: []
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
} catch {
|
|
1800
|
+
}
|
|
1252
1801
|
try {
|
|
1253
1802
|
await client.execute({
|
|
1254
1803
|
sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
|
|
@@ -1382,15 +1931,41 @@ async function ensureSchema() {
|
|
|
1382
1931
|
});
|
|
1383
1932
|
} catch {
|
|
1384
1933
|
}
|
|
1934
|
+
for (const col of [
|
|
1935
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
1936
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
1937
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
1938
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
1939
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
1940
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
1941
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
1942
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
1943
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
1944
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
1945
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
1946
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
1947
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
1948
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
1949
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
1950
|
+
]) {
|
|
1951
|
+
try {
|
|
1952
|
+
await client.execute(col);
|
|
1953
|
+
} catch {
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1385
1956
|
}
|
|
1386
1957
|
async function disposeDatabase() {
|
|
1958
|
+
if (_daemonClient) {
|
|
1959
|
+
_daemonClient.close();
|
|
1960
|
+
_daemonClient = null;
|
|
1961
|
+
}
|
|
1387
1962
|
if (_client) {
|
|
1388
1963
|
_client.close();
|
|
1389
1964
|
_client = null;
|
|
1390
1965
|
_resilientClient = null;
|
|
1391
1966
|
}
|
|
1392
1967
|
}
|
|
1393
|
-
var _client, _resilientClient, initTurso, disposeTurso;
|
|
1968
|
+
var _client, _resilientClient, _daemonClient, initTurso, disposeTurso;
|
|
1394
1969
|
var init_database = __esm({
|
|
1395
1970
|
"src/lib/database.ts"() {
|
|
1396
1971
|
"use strict";
|
|
@@ -1398,30 +1973,31 @@ var init_database = __esm({
|
|
|
1398
1973
|
init_employees();
|
|
1399
1974
|
_client = null;
|
|
1400
1975
|
_resilientClient = null;
|
|
1976
|
+
_daemonClient = null;
|
|
1401
1977
|
initTurso = initDatabase;
|
|
1402
1978
|
disposeTurso = disposeDatabase;
|
|
1403
1979
|
}
|
|
1404
1980
|
});
|
|
1405
1981
|
|
|
1406
1982
|
// src/lib/license.ts
|
|
1407
|
-
import { readFileSync as
|
|
1408
|
-
import { randomUUID } from "crypto";
|
|
1409
|
-
import
|
|
1983
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
|
|
1984
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
1985
|
+
import path8 from "path";
|
|
1410
1986
|
import { jwtVerify, importSPKI } from "jose";
|
|
1411
1987
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
1412
1988
|
var init_license = __esm({
|
|
1413
1989
|
"src/lib/license.ts"() {
|
|
1414
1990
|
"use strict";
|
|
1415
1991
|
init_config();
|
|
1416
|
-
LICENSE_PATH =
|
|
1417
|
-
CACHE_PATH =
|
|
1418
|
-
DEVICE_ID_PATH =
|
|
1992
|
+
LICENSE_PATH = path8.join(EXE_AI_DIR, "license.key");
|
|
1993
|
+
CACHE_PATH = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
1994
|
+
DEVICE_ID_PATH = path8.join(EXE_AI_DIR, "device-id");
|
|
1419
1995
|
}
|
|
1420
1996
|
});
|
|
1421
1997
|
|
|
1422
1998
|
// src/lib/plan-limits.ts
|
|
1423
|
-
import { readFileSync as
|
|
1424
|
-
import
|
|
1999
|
+
import { readFileSync as readFileSync8, existsSync as existsSync7 } from "fs";
|
|
2000
|
+
import path9 from "path";
|
|
1425
2001
|
var CACHE_PATH2;
|
|
1426
2002
|
var init_plan_limits = __esm({
|
|
1427
2003
|
"src/lib/plan-limits.ts"() {
|
|
@@ -1430,15 +2006,15 @@ var init_plan_limits = __esm({
|
|
|
1430
2006
|
init_employees();
|
|
1431
2007
|
init_license();
|
|
1432
2008
|
init_config();
|
|
1433
|
-
CACHE_PATH2 =
|
|
2009
|
+
CACHE_PATH2 = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
1434
2010
|
}
|
|
1435
2011
|
});
|
|
1436
2012
|
|
|
1437
2013
|
// src/lib/tmux-routing.ts
|
|
1438
|
-
import { readFileSync as
|
|
1439
|
-
import
|
|
2014
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync8, appendFileSync } from "fs";
|
|
2015
|
+
import path10 from "path";
|
|
1440
2016
|
import os5 from "os";
|
|
1441
|
-
import { fileURLToPath } from "url";
|
|
2017
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1442
2018
|
function getMySession() {
|
|
1443
2019
|
return getTransport().getMySession();
|
|
1444
2020
|
}
|
|
@@ -1450,7 +2026,7 @@ function extractRootExe(name) {
|
|
|
1450
2026
|
}
|
|
1451
2027
|
function getParentExe(sessionKey) {
|
|
1452
2028
|
try {
|
|
1453
|
-
const data = JSON.parse(
|
|
2029
|
+
const data = JSON.parse(readFileSync9(path10.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
1454
2030
|
return data.parentExe || null;
|
|
1455
2031
|
} catch {
|
|
1456
2032
|
return null;
|
|
@@ -1479,13 +2055,15 @@ var init_tmux_routing = __esm({
|
|
|
1479
2055
|
init_cc_agent_support();
|
|
1480
2056
|
init_mcp_prefix();
|
|
1481
2057
|
init_provider_table();
|
|
2058
|
+
init_agent_config();
|
|
2059
|
+
init_runtime_table();
|
|
1482
2060
|
init_intercom_queue();
|
|
1483
2061
|
init_plan_limits();
|
|
1484
2062
|
init_employees();
|
|
1485
|
-
SPAWN_LOCK_DIR =
|
|
1486
|
-
SESSION_CACHE =
|
|
1487
|
-
INTERCOM_LOG2 =
|
|
1488
|
-
DEBOUNCE_FILE =
|
|
2063
|
+
SPAWN_LOCK_DIR = path10.join(os5.homedir(), ".exe-os", "spawn-locks");
|
|
2064
|
+
SESSION_CACHE = path10.join(os5.homedir(), ".exe-os", "session-cache");
|
|
2065
|
+
INTERCOM_LOG2 = path10.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
2066
|
+
DEBOUNCE_FILE = path10.join(SESSION_CACHE, "intercom-debounce.json");
|
|
1489
2067
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
1490
2068
|
}
|
|
1491
2069
|
});
|
|
@@ -1525,14 +2103,14 @@ var init_memory = __esm({
|
|
|
1525
2103
|
|
|
1526
2104
|
// src/lib/keychain.ts
|
|
1527
2105
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
1528
|
-
import { existsSync as
|
|
1529
|
-
import
|
|
2106
|
+
import { existsSync as existsSync9 } from "fs";
|
|
2107
|
+
import path11 from "path";
|
|
1530
2108
|
import os6 from "os";
|
|
1531
2109
|
function getKeyDir() {
|
|
1532
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
2110
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path11.join(os6.homedir(), ".exe-os");
|
|
1533
2111
|
}
|
|
1534
2112
|
function getKeyPath() {
|
|
1535
|
-
return
|
|
2113
|
+
return path11.join(getKeyDir(), "master.key");
|
|
1536
2114
|
}
|
|
1537
2115
|
async function tryKeytar() {
|
|
1538
2116
|
try {
|
|
@@ -1553,13 +2131,21 @@ async function getMasterKey() {
|
|
|
1553
2131
|
}
|
|
1554
2132
|
}
|
|
1555
2133
|
const keyPath = getKeyPath();
|
|
1556
|
-
if (!
|
|
2134
|
+
if (!existsSync9(keyPath)) {
|
|
2135
|
+
process.stderr.write(
|
|
2136
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os6.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
2137
|
+
`
|
|
2138
|
+
);
|
|
1557
2139
|
return null;
|
|
1558
2140
|
}
|
|
1559
2141
|
try {
|
|
1560
2142
|
const content = await readFile3(keyPath, "utf-8");
|
|
1561
2143
|
return Buffer.from(content.trim(), "base64");
|
|
1562
|
-
} catch {
|
|
2144
|
+
} catch (err) {
|
|
2145
|
+
process.stderr.write(
|
|
2146
|
+
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
2147
|
+
`
|
|
2148
|
+
);
|
|
1563
2149
|
return null;
|
|
1564
2150
|
}
|
|
1565
2151
|
}
|
|
@@ -1640,13 +2226,13 @@ __export(shard_manager_exports, {
|
|
|
1640
2226
|
listShards: () => listShards,
|
|
1641
2227
|
shardExists: () => shardExists
|
|
1642
2228
|
});
|
|
1643
|
-
import
|
|
1644
|
-
import { existsSync as
|
|
2229
|
+
import path12 from "path";
|
|
2230
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync6, readdirSync as readdirSync2 } from "fs";
|
|
1645
2231
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1646
2232
|
function initShardManager(encryptionKey) {
|
|
1647
2233
|
_encryptionKey = encryptionKey;
|
|
1648
|
-
if (!
|
|
1649
|
-
|
|
2234
|
+
if (!existsSync10(SHARDS_DIR)) {
|
|
2235
|
+
mkdirSync6(SHARDS_DIR, { recursive: true });
|
|
1650
2236
|
}
|
|
1651
2237
|
_shardingEnabled = true;
|
|
1652
2238
|
}
|
|
@@ -1666,7 +2252,7 @@ function getShardClient(projectName) {
|
|
|
1666
2252
|
}
|
|
1667
2253
|
const cached = _shards.get(safeName);
|
|
1668
2254
|
if (cached) return cached;
|
|
1669
|
-
const dbPath =
|
|
2255
|
+
const dbPath = path12.join(SHARDS_DIR, `${safeName}.db`);
|
|
1670
2256
|
const client = createClient2({
|
|
1671
2257
|
url: `file:${dbPath}`,
|
|
1672
2258
|
encryptionKey: _encryptionKey
|
|
@@ -1676,10 +2262,10 @@ function getShardClient(projectName) {
|
|
|
1676
2262
|
}
|
|
1677
2263
|
function shardExists(projectName) {
|
|
1678
2264
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1679
|
-
return
|
|
2265
|
+
return existsSync10(path12.join(SHARDS_DIR, `${safeName}.db`));
|
|
1680
2266
|
}
|
|
1681
2267
|
function listShards() {
|
|
1682
|
-
if (!
|
|
2268
|
+
if (!existsSync10(SHARDS_DIR)) return [];
|
|
1683
2269
|
return readdirSync2(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1684
2270
|
}
|
|
1685
2271
|
async function ensureShardSchema(client) {
|
|
@@ -1865,7 +2451,7 @@ var init_shard_manager = __esm({
|
|
|
1865
2451
|
"src/lib/shard-manager.ts"() {
|
|
1866
2452
|
"use strict";
|
|
1867
2453
|
init_config();
|
|
1868
|
-
SHARDS_DIR =
|
|
2454
|
+
SHARDS_DIR = path12.join(EXE_AI_DIR, "shards");
|
|
1869
2455
|
_shards = /* @__PURE__ */ new Map();
|
|
1870
2456
|
_encryptionKey = null;
|
|
1871
2457
|
_shardingEnabled = false;
|
|
@@ -1990,7 +2576,7 @@ __export(global_procedures_exports, {
|
|
|
1990
2576
|
loadGlobalProcedures: () => loadGlobalProcedures,
|
|
1991
2577
|
storeGlobalProcedure: () => storeGlobalProcedure
|
|
1992
2578
|
});
|
|
1993
|
-
import { randomUUID as
|
|
2579
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
1994
2580
|
async function loadGlobalProcedures() {
|
|
1995
2581
|
const client = getClient();
|
|
1996
2582
|
const result = await client.execute({
|
|
@@ -2019,7 +2605,7 @@ ${sections.join("\n\n")}
|
|
|
2019
2605
|
`;
|
|
2020
2606
|
}
|
|
2021
2607
|
async function storeGlobalProcedure(input2) {
|
|
2022
|
-
const id =
|
|
2608
|
+
const id = randomUUID3();
|
|
2023
2609
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2024
2610
|
const client = getClient();
|
|
2025
2611
|
await client.execute({
|
|
@@ -2070,6 +2656,7 @@ __export(store_exports, {
|
|
|
2070
2656
|
vectorToBlob: () => vectorToBlob,
|
|
2071
2657
|
writeMemory: () => writeMemory
|
|
2072
2658
|
});
|
|
2659
|
+
import { createHash } from "crypto";
|
|
2073
2660
|
function isBusyError2(err) {
|
|
2074
2661
|
if (err instanceof Error) {
|
|
2075
2662
|
const msg = err.message.toLowerCase();
|
|
@@ -2143,12 +2730,52 @@ function classifyTier(record) {
|
|
|
2143
2730
|
if (["store_memory", "manual"].includes(record.tool_name ?? "") && (record.importance ?? 0) >= 5) return 2;
|
|
2144
2731
|
return 3;
|
|
2145
2732
|
}
|
|
2733
|
+
function inferFilePaths(record) {
|
|
2734
|
+
if (!["Read", "Write", "Edit"].includes(record.tool_name)) return null;
|
|
2735
|
+
const firstLine = record.raw_text.split("\n")[0] ?? "";
|
|
2736
|
+
const match = firstLine.match(/(\/[\w./-]+\.\w+)/);
|
|
2737
|
+
return match ? JSON.stringify([match[1]]) : null;
|
|
2738
|
+
}
|
|
2739
|
+
function inferCommitHash(record) {
|
|
2740
|
+
if (record.tool_name !== "Bash") return null;
|
|
2741
|
+
const match = record.raw_text.match(/\b([a-f0-9]{7,40})\b/);
|
|
2742
|
+
return match ? match[1] : null;
|
|
2743
|
+
}
|
|
2744
|
+
function inferLanguageType(record) {
|
|
2745
|
+
const text = record.raw_text;
|
|
2746
|
+
if (!text || text.length < 10) return null;
|
|
2747
|
+
const trimmed = text.trimStart();
|
|
2748
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) return "json";
|
|
2749
|
+
if (/\b(SELECT|INSERT|UPDATE|DELETE|CREATE TABLE|ALTER TABLE)\b/i.test(text)) return "sql";
|
|
2750
|
+
if (/\b(function |const |import |export |class |def |async |=>)\b/.test(text)) return "code";
|
|
2751
|
+
if (trimmed.startsWith("#") || trimmed.startsWith("*")) return "prose";
|
|
2752
|
+
return "mixed";
|
|
2753
|
+
}
|
|
2754
|
+
function inferDomain(record) {
|
|
2755
|
+
const proj = (record.project_name ?? "").toLowerCase();
|
|
2756
|
+
if (proj.includes("marketing") || proj.includes("content")) return "marketing";
|
|
2757
|
+
if (proj.includes("crm") || proj.includes("customer")) return "customer";
|
|
2758
|
+
return null;
|
|
2759
|
+
}
|
|
2146
2760
|
async function writeMemory(record) {
|
|
2147
2761
|
if (record.vector !== null && record.vector.length !== EMBEDDING_DIM) {
|
|
2148
2762
|
throw new Error(
|
|
2149
2763
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
2150
2764
|
);
|
|
2151
2765
|
}
|
|
2766
|
+
const contentHash = createHash("md5").update(record.raw_text).digest("hex");
|
|
2767
|
+
if (_pendingRecords.some((r) => r.content_hash === contentHash && r.agent_id === record.agent_id)) {
|
|
2768
|
+
return;
|
|
2769
|
+
}
|
|
2770
|
+
try {
|
|
2771
|
+
const client = getClient();
|
|
2772
|
+
const existing = await client.execute({
|
|
2773
|
+
sql: "SELECT id FROM memories WHERE content_hash = ? AND agent_id = ? LIMIT 1",
|
|
2774
|
+
args: [contentHash, record.agent_id]
|
|
2775
|
+
});
|
|
2776
|
+
if (existing.rows.length > 0) return;
|
|
2777
|
+
} catch {
|
|
2778
|
+
}
|
|
2152
2779
|
const dbRow = {
|
|
2153
2780
|
id: record.id,
|
|
2154
2781
|
agent_id: record.agent_id,
|
|
@@ -2178,7 +2805,23 @@ async function writeMemory(record) {
|
|
|
2178
2805
|
supersedes_id: record.supersedes_id ?? null,
|
|
2179
2806
|
draft: record.draft ? 1 : 0,
|
|
2180
2807
|
memory_type: record.memory_type ?? "raw",
|
|
2181
|
-
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null
|
|
2808
|
+
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
2809
|
+
content_hash: contentHash,
|
|
2810
|
+
intent: record.intent ?? null,
|
|
2811
|
+
outcome: record.outcome ?? null,
|
|
2812
|
+
domain: record.domain ?? inferDomain(record),
|
|
2813
|
+
referenced_entities: record.referenced_entities ?? null,
|
|
2814
|
+
retrieval_count: record.retrieval_count ?? 0,
|
|
2815
|
+
chain_position: record.chain_position ?? null,
|
|
2816
|
+
review_status: record.review_status ?? null,
|
|
2817
|
+
context_window_pct: record.context_window_pct ?? null,
|
|
2818
|
+
file_paths: record.file_paths ?? inferFilePaths(record),
|
|
2819
|
+
commit_hash: record.commit_hash ?? inferCommitHash(record),
|
|
2820
|
+
duration_ms: record.duration_ms ?? null,
|
|
2821
|
+
token_cost: record.token_cost ?? null,
|
|
2822
|
+
audience: record.audience ?? null,
|
|
2823
|
+
language_type: record.language_type ?? inferLanguageType(record),
|
|
2824
|
+
parent_memory_id: record.parent_memory_id ?? null
|
|
2182
2825
|
};
|
|
2183
2826
|
_pendingRecords.push(dbRow);
|
|
2184
2827
|
orgBus.emit({
|
|
@@ -2236,80 +2879,85 @@ async function flushBatch() {
|
|
|
2236
2879
|
const draft = row.draft ? 1 : 0;
|
|
2237
2880
|
const memoryType = row.memory_type ?? "raw";
|
|
2238
2881
|
const trajectory = row.trajectory ?? null;
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2882
|
+
const contentHash = row.content_hash ?? null;
|
|
2883
|
+
const intent = row.intent ?? null;
|
|
2884
|
+
const outcome = row.outcome ?? null;
|
|
2885
|
+
const domain = row.domain ?? null;
|
|
2886
|
+
const referencedEntities = row.referenced_entities ?? null;
|
|
2887
|
+
const retrievalCount = row.retrieval_count ?? 0;
|
|
2888
|
+
const chainPosition = row.chain_position ?? null;
|
|
2889
|
+
const reviewStatus = row.review_status ?? null;
|
|
2890
|
+
const contextWindowPct = row.context_window_pct ?? null;
|
|
2891
|
+
const filePaths = row.file_paths ?? null;
|
|
2892
|
+
const commitHash = row.commit_hash ?? null;
|
|
2893
|
+
const durationMs = row.duration_ms ?? null;
|
|
2894
|
+
const tokenCost = row.token_cost ?? null;
|
|
2895
|
+
const audience = row.audience ?? null;
|
|
2896
|
+
const languageType = row.language_type ?? null;
|
|
2897
|
+
const parentMemoryId = row.parent_memory_id ?? null;
|
|
2898
|
+
const cols = `id, agent_id, agent_role, session_id, timestamp,
|
|
2242
2899
|
tool_name, project_name,
|
|
2243
2900
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
2244
2901
|
confidence, last_accessed,
|
|
2245
2902
|
workspace_id, document_id, user_id, char_offset, page_number,
|
|
2246
|
-
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
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
|
-
pageNumber,
|
|
2305
|
-
sourcePath,
|
|
2306
|
-
sourceType,
|
|
2307
|
-
tier,
|
|
2308
|
-
supersedesId,
|
|
2309
|
-
draft,
|
|
2310
|
-
memoryType,
|
|
2311
|
-
trajectory
|
|
2312
|
-
]
|
|
2903
|
+
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
|
|
2904
|
+
intent, outcome, domain, referenced_entities, retrieval_count,
|
|
2905
|
+
chain_position, review_status, context_window_pct, file_paths, commit_hash,
|
|
2906
|
+
duration_ms, token_cost, audience, language_type, parent_memory_id`;
|
|
2907
|
+
const metaArgs = [
|
|
2908
|
+
intent,
|
|
2909
|
+
outcome,
|
|
2910
|
+
domain,
|
|
2911
|
+
referencedEntities,
|
|
2912
|
+
retrievalCount,
|
|
2913
|
+
chainPosition,
|
|
2914
|
+
reviewStatus,
|
|
2915
|
+
contextWindowPct,
|
|
2916
|
+
filePaths,
|
|
2917
|
+
commitHash,
|
|
2918
|
+
durationMs,
|
|
2919
|
+
tokenCost,
|
|
2920
|
+
audience,
|
|
2921
|
+
languageType,
|
|
2922
|
+
parentMemoryId
|
|
2923
|
+
];
|
|
2924
|
+
const baseArgs = [
|
|
2925
|
+
row.id,
|
|
2926
|
+
row.agent_id,
|
|
2927
|
+
row.agent_role,
|
|
2928
|
+
row.session_id,
|
|
2929
|
+
row.timestamp,
|
|
2930
|
+
row.tool_name,
|
|
2931
|
+
row.project_name,
|
|
2932
|
+
row.has_error,
|
|
2933
|
+
row.raw_text
|
|
2934
|
+
];
|
|
2935
|
+
const sharedArgs = [
|
|
2936
|
+
row.version,
|
|
2937
|
+
taskId,
|
|
2938
|
+
importance,
|
|
2939
|
+
status,
|
|
2940
|
+
confidence,
|
|
2941
|
+
lastAccessed,
|
|
2942
|
+
workspaceId,
|
|
2943
|
+
documentId,
|
|
2944
|
+
userId,
|
|
2945
|
+
charOffset,
|
|
2946
|
+
pageNumber,
|
|
2947
|
+
sourcePath,
|
|
2948
|
+
sourceType,
|
|
2949
|
+
tier,
|
|
2950
|
+
supersedesId,
|
|
2951
|
+
draft,
|
|
2952
|
+
memoryType,
|
|
2953
|
+
trajectory,
|
|
2954
|
+
contentHash
|
|
2955
|
+
];
|
|
2956
|
+
return {
|
|
2957
|
+
sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
|
|
2958
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
|
|
2959
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
2960
|
+
args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
|
|
2313
2961
|
};
|
|
2314
2962
|
};
|
|
2315
2963
|
const globalClient = getClient();
|