@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.
Files changed (103) hide show
  1. package/dist/bin/backfill-conversations.js +746 -595
  2. package/dist/bin/backfill-responses.js +745 -594
  3. package/dist/bin/backfill-vectors.js +312 -226
  4. package/dist/bin/cleanup-stale-review-tasks.js +154 -21
  5. package/dist/bin/cli.js +14678 -12676
  6. package/dist/bin/exe-agent-config.js +242 -0
  7. package/dist/bin/exe-agent.js +100 -91
  8. package/dist/bin/exe-assign.js +1003 -854
  9. package/dist/bin/exe-boot.js +1420 -485
  10. package/dist/bin/exe-call.js +10 -0
  11. package/dist/bin/exe-cloud.js +29 -6
  12. package/dist/bin/exe-dispatch.js +572 -271
  13. package/dist/bin/exe-doctor.js +403 -6
  14. package/dist/bin/exe-export-behaviors.js +175 -72
  15. package/dist/bin/exe-forget.js +102 -3
  16. package/dist/bin/exe-gateway.js +796 -292
  17. package/dist/bin/exe-healthcheck.js +134 -1
  18. package/dist/bin/exe-heartbeat.js +172 -36
  19. package/dist/bin/exe-kill.js +175 -72
  20. package/dist/bin/exe-launch-agent.js +189 -76
  21. package/dist/bin/exe-link.js +927 -82
  22. package/dist/bin/exe-new-employee.js +60 -8
  23. package/dist/bin/exe-pending-messages.js +151 -19
  24. package/dist/bin/exe-pending-notifications.js +97 -2
  25. package/dist/bin/exe-pending-reviews.js +155 -22
  26. package/dist/bin/exe-rename.js +564 -23
  27. package/dist/bin/exe-review.js +231 -73
  28. package/dist/bin/exe-search.js +995 -228
  29. package/dist/bin/exe-session-cleanup.js +4930 -1664
  30. package/dist/bin/exe-settings.js +20 -5
  31. package/dist/bin/exe-start-codex.js +2598 -0
  32. package/dist/bin/exe-start.sh +15 -3
  33. package/dist/bin/exe-status.js +154 -21
  34. package/dist/bin/exe-team.js +97 -2
  35. package/dist/bin/git-sweep.js +1180 -363
  36. package/dist/bin/graph-backfill.js +175 -72
  37. package/dist/bin/graph-export.js +175 -72
  38. package/dist/bin/install.js +60 -7
  39. package/dist/bin/list-providers.js +1 -0
  40. package/dist/bin/scan-tasks.js +1185 -367
  41. package/dist/bin/setup.js +914 -270
  42. package/dist/bin/shard-migrate.js +175 -72
  43. package/dist/bin/update.js +1 -0
  44. package/dist/bin/wiki-sync.js +175 -72
  45. package/dist/gateway/index.js +792 -285
  46. package/dist/hooks/bug-report-worker.js +445 -135
  47. package/dist/hooks/commit-complete.js +1178 -361
  48. package/dist/hooks/error-recall.js +994 -228
  49. package/dist/hooks/ingest-worker.js +1799 -1234
  50. package/dist/hooks/ingest.js +3 -0
  51. package/dist/hooks/instructions-loaded.js +707 -97
  52. package/dist/hooks/notification.js +699 -89
  53. package/dist/hooks/post-compact.js +757 -109
  54. package/dist/hooks/pre-compact.js +1061 -244
  55. package/dist/hooks/pre-tool-use.js +787 -130
  56. package/dist/hooks/prompt-ingest-worker.js +242 -101
  57. package/dist/hooks/prompt-submit.js +1121 -299
  58. package/dist/hooks/response-ingest-worker.js +242 -101
  59. package/dist/hooks/session-end.js +4063 -397
  60. package/dist/hooks/session-start.js +1071 -254
  61. package/dist/hooks/stop.js +768 -120
  62. package/dist/hooks/subagent-stop.js +757 -109
  63. package/dist/hooks/summary-worker.js +1706 -1011
  64. package/dist/index.js +1821 -1098
  65. package/dist/lib/agent-config.js +167 -0
  66. package/dist/lib/cloud-sync.js +932 -88
  67. package/dist/lib/consolidation.js +2 -1
  68. package/dist/lib/database.js +642 -87
  69. package/dist/lib/db-daemon-client.js +503 -0
  70. package/dist/lib/device-registry.js +547 -7
  71. package/dist/lib/embedder.js +14 -28
  72. package/dist/lib/employee-templates.js +84 -74
  73. package/dist/lib/employees.js +9 -0
  74. package/dist/lib/exe-daemon-client.js +16 -29
  75. package/dist/lib/exe-daemon.js +2733 -1575
  76. package/dist/lib/hybrid-search.js +995 -228
  77. package/dist/lib/identity.js +87 -67
  78. package/dist/lib/keychain.js +9 -1
  79. package/dist/lib/messaging.js +103 -40
  80. package/dist/lib/reminders.js +91 -74
  81. package/dist/lib/runtime-table.js +16 -0
  82. package/dist/lib/schedules.js +96 -2
  83. package/dist/lib/session-wrappers.js +22 -0
  84. package/dist/lib/skill-learning.js +103 -85
  85. package/dist/lib/store.js +234 -73
  86. package/dist/lib/tasks.js +348 -134
  87. package/dist/lib/tmux-routing.js +422 -208
  88. package/dist/lib/token-spend.js +273 -0
  89. package/dist/lib/ws-client.js +11 -0
  90. package/dist/mcp/server.js +5742 -696
  91. package/dist/mcp/tools/complete-reminder.js +94 -77
  92. package/dist/mcp/tools/create-reminder.js +94 -77
  93. package/dist/mcp/tools/create-task.js +375 -152
  94. package/dist/mcp/tools/deactivate-behavior.js +95 -77
  95. package/dist/mcp/tools/list-reminders.js +94 -77
  96. package/dist/mcp/tools/list-tasks.js +99 -31
  97. package/dist/mcp/tools/send-message.js +108 -45
  98. package/dist/mcp/tools/update-task.js +162 -77
  99. package/dist/runtime/index.js +1075 -258
  100. package/dist/tui/App.js +1333 -506
  101. package/package.json +6 -1
  102. package/src/commands/exe/agent-config.md +27 -0
  103. package/src/commands/exe/cc-doctor.md +10 -0
@@ -450,17 +450,53 @@ var init_provider_table = __esm({
450
450
  }
451
451
  });
452
452
 
453
- // src/lib/intercom-queue.ts
454
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
453
+ // src/lib/runtime-table.ts
454
+ var RUNTIME_TABLE;
455
+ var init_runtime_table = __esm({
456
+ "src/lib/runtime-table.ts"() {
457
+ "use strict";
458
+ RUNTIME_TABLE = {
459
+ codex: {
460
+ binary: "codex",
461
+ launchMode: "exec",
462
+ autoApproveFlag: "--full-auto",
463
+ inlineFlag: "--no-alt-screen",
464
+ apiKeyEnv: "OPENAI_API_KEY",
465
+ defaultModel: "gpt-5.4"
466
+ }
467
+ };
468
+ }
469
+ });
470
+
471
+ // src/lib/agent-config.ts
472
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
455
473
  import path5 from "path";
474
+ var AGENT_CONFIG_PATH, DEFAULT_MODELS;
475
+ var init_agent_config = __esm({
476
+ "src/lib/agent-config.ts"() {
477
+ "use strict";
478
+ init_config();
479
+ init_runtime_table();
480
+ AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
481
+ DEFAULT_MODELS = {
482
+ claude: "claude-opus-4",
483
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
484
+ opencode: "minimax-m2.7"
485
+ };
486
+ }
487
+ });
488
+
489
+ // src/lib/intercom-queue.ts
490
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
491
+ import path6 from "path";
456
492
  import os4 from "os";
457
493
  var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
458
494
  var init_intercom_queue = __esm({
459
495
  "src/lib/intercom-queue.ts"() {
460
496
  "use strict";
461
- QUEUE_PATH = path5.join(os4.homedir(), ".exe-os", "intercom-queue.json");
497
+ QUEUE_PATH = path6.join(os4.homedir(), ".exe-os", "intercom-queue.json");
462
498
  TTL_MS = 60 * 60 * 1e3;
463
- INTERCOM_LOG = path5.join(os4.homedir(), ".exe-os", "intercom.log");
499
+ INTERCOM_LOG = path6.join(os4.homedir(), ".exe-os", "intercom.log");
464
500
  }
465
501
  });
466
502
 
@@ -519,6 +555,443 @@ var init_db_retry = __esm({
519
555
  }
520
556
  });
521
557
 
558
+ // src/lib/exe-daemon-client.ts
559
+ import net from "net";
560
+ import { spawn } from "child_process";
561
+ import { randomUUID } from "crypto";
562
+ import { existsSync as existsSync5, unlinkSync as unlinkSync3, readFileSync as readFileSync6, openSync, closeSync, statSync } from "fs";
563
+ import path7 from "path";
564
+ import { fileURLToPath } from "url";
565
+ function handleData(chunk) {
566
+ _buffer += chunk.toString();
567
+ if (_buffer.length > MAX_BUFFER) {
568
+ _buffer = "";
569
+ return;
570
+ }
571
+ let newlineIdx;
572
+ while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
573
+ const line = _buffer.slice(0, newlineIdx).trim();
574
+ _buffer = _buffer.slice(newlineIdx + 1);
575
+ if (!line) continue;
576
+ try {
577
+ const response = JSON.parse(line);
578
+ const id = response.id;
579
+ if (!id) continue;
580
+ const entry = _pending.get(id);
581
+ if (entry) {
582
+ clearTimeout(entry.timer);
583
+ _pending.delete(id);
584
+ entry.resolve(response);
585
+ }
586
+ } catch {
587
+ }
588
+ }
589
+ }
590
+ function cleanupStaleFiles() {
591
+ if (existsSync5(PID_PATH)) {
592
+ try {
593
+ const pid = parseInt(readFileSync6(PID_PATH, "utf8").trim(), 10);
594
+ if (pid > 0) {
595
+ try {
596
+ process.kill(pid, 0);
597
+ return;
598
+ } catch {
599
+ }
600
+ }
601
+ } catch {
602
+ }
603
+ try {
604
+ unlinkSync3(PID_PATH);
605
+ } catch {
606
+ }
607
+ try {
608
+ unlinkSync3(SOCKET_PATH);
609
+ } catch {
610
+ }
611
+ }
612
+ }
613
+ function findPackageRoot() {
614
+ let dir = path7.dirname(fileURLToPath(import.meta.url));
615
+ const { root } = path7.parse(dir);
616
+ while (dir !== root) {
617
+ if (existsSync5(path7.join(dir, "package.json"))) return dir;
618
+ dir = path7.dirname(dir);
619
+ }
620
+ return null;
621
+ }
622
+ function spawnDaemon() {
623
+ const pkgRoot = findPackageRoot();
624
+ if (!pkgRoot) {
625
+ process.stderr.write("[exed-client] WARN: cannot find package root\n");
626
+ return;
627
+ }
628
+ const daemonPath = path7.join(pkgRoot, "dist", "lib", "exe-daemon.js");
629
+ if (!existsSync5(daemonPath)) {
630
+ process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
631
+ `);
632
+ return;
633
+ }
634
+ const resolvedPath = daemonPath;
635
+ process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
636
+ `);
637
+ const logPath = path7.join(path7.dirname(SOCKET_PATH), "exed.log");
638
+ let stderrFd = "ignore";
639
+ try {
640
+ stderrFd = openSync(logPath, "a");
641
+ } catch {
642
+ }
643
+ const child = spawn(process.execPath, [resolvedPath], {
644
+ detached: true,
645
+ stdio: ["ignore", "ignore", stderrFd],
646
+ env: {
647
+ ...process.env,
648
+ TMUX: void 0,
649
+ // Daemon is global — must not inherit session scope
650
+ TMUX_PANE: void 0,
651
+ // Prevents resolveExeSession() from scoping to one session
652
+ EXE_DAEMON_SOCK: SOCKET_PATH,
653
+ EXE_DAEMON_PID: PID_PATH
654
+ }
655
+ });
656
+ child.unref();
657
+ if (typeof stderrFd === "number") {
658
+ try {
659
+ closeSync(stderrFd);
660
+ } catch {
661
+ }
662
+ }
663
+ }
664
+ function acquireSpawnLock() {
665
+ try {
666
+ const fd = openSync(SPAWN_LOCK_PATH, "wx");
667
+ closeSync(fd);
668
+ return true;
669
+ } catch {
670
+ try {
671
+ const stat = statSync(SPAWN_LOCK_PATH);
672
+ if (Date.now() - stat.mtimeMs > SPAWN_LOCK_STALE_MS) {
673
+ try {
674
+ unlinkSync3(SPAWN_LOCK_PATH);
675
+ } catch {
676
+ }
677
+ try {
678
+ const fd = openSync(SPAWN_LOCK_PATH, "wx");
679
+ closeSync(fd);
680
+ return true;
681
+ } catch {
682
+ }
683
+ }
684
+ } catch {
685
+ }
686
+ return false;
687
+ }
688
+ }
689
+ function releaseSpawnLock() {
690
+ try {
691
+ unlinkSync3(SPAWN_LOCK_PATH);
692
+ } catch {
693
+ }
694
+ }
695
+ function connectToSocket() {
696
+ return new Promise((resolve) => {
697
+ if (_socket && _connected) {
698
+ resolve(true);
699
+ return;
700
+ }
701
+ const socket = net.createConnection({ path: SOCKET_PATH });
702
+ const connectTimeout = setTimeout(() => {
703
+ socket.destroy();
704
+ resolve(false);
705
+ }, 2e3);
706
+ socket.on("connect", () => {
707
+ clearTimeout(connectTimeout);
708
+ _socket = socket;
709
+ _connected = true;
710
+ _buffer = "";
711
+ socket.on("data", handleData);
712
+ socket.on("close", () => {
713
+ _connected = false;
714
+ _socket = null;
715
+ for (const [id, entry] of _pending) {
716
+ clearTimeout(entry.timer);
717
+ _pending.delete(id);
718
+ entry.resolve({ error: "Connection closed" });
719
+ }
720
+ });
721
+ socket.on("error", () => {
722
+ _connected = false;
723
+ _socket = null;
724
+ });
725
+ resolve(true);
726
+ });
727
+ socket.on("error", () => {
728
+ clearTimeout(connectTimeout);
729
+ resolve(false);
730
+ });
731
+ });
732
+ }
733
+ async function connectEmbedDaemon() {
734
+ if (_socket && _connected) return true;
735
+ if (await connectToSocket()) return true;
736
+ if (acquireSpawnLock()) {
737
+ try {
738
+ cleanupStaleFiles();
739
+ spawnDaemon();
740
+ } finally {
741
+ releaseSpawnLock();
742
+ }
743
+ }
744
+ const start = Date.now();
745
+ let delay2 = 100;
746
+ while (Date.now() - start < CONNECT_TIMEOUT_MS) {
747
+ await new Promise((r) => setTimeout(r, delay2));
748
+ if (await connectToSocket()) return true;
749
+ delay2 = Math.min(delay2 * 2, 3e3);
750
+ }
751
+ return false;
752
+ }
753
+ function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
754
+ return new Promise((resolve) => {
755
+ if (!_socket || !_connected) {
756
+ resolve({ error: "Not connected" });
757
+ return;
758
+ }
759
+ const id = randomUUID();
760
+ const timer = setTimeout(() => {
761
+ _pending.delete(id);
762
+ resolve({ error: "Request timeout" });
763
+ }, timeoutMs);
764
+ _pending.set(id, { resolve, timer });
765
+ try {
766
+ _socket.write(JSON.stringify({ id, ...payload }) + "\n");
767
+ } catch {
768
+ clearTimeout(timer);
769
+ _pending.delete(id);
770
+ resolve({ error: "Write failed" });
771
+ }
772
+ });
773
+ }
774
+ function isClientConnected() {
775
+ return _connected;
776
+ }
777
+ var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _pending, MAX_BUFFER;
778
+ var init_exe_daemon_client = __esm({
779
+ "src/lib/exe-daemon-client.ts"() {
780
+ "use strict";
781
+ init_config();
782
+ SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path7.join(EXE_AI_DIR, "exed.sock");
783
+ PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path7.join(EXE_AI_DIR, "exed.pid");
784
+ SPAWN_LOCK_PATH = path7.join(EXE_AI_DIR, "exed-spawn.lock");
785
+ SPAWN_LOCK_STALE_MS = 3e4;
786
+ CONNECT_TIMEOUT_MS = 15e3;
787
+ REQUEST_TIMEOUT_MS = 3e4;
788
+ _socket = null;
789
+ _connected = false;
790
+ _buffer = "";
791
+ _pending = /* @__PURE__ */ new Map();
792
+ MAX_BUFFER = 1e7;
793
+ }
794
+ });
795
+
796
+ // src/lib/daemon-protocol.ts
797
+ function serializeValue(v) {
798
+ if (v === null || v === void 0) return null;
799
+ if (typeof v === "bigint") return Number(v);
800
+ if (typeof v === "boolean") return v ? 1 : 0;
801
+ if (v instanceof Uint8Array) {
802
+ return { __blob: Buffer.from(v).toString("base64") };
803
+ }
804
+ if (ArrayBuffer.isView(v)) {
805
+ return { __blob: Buffer.from(v.buffer, v.byteOffset, v.byteLength).toString("base64") };
806
+ }
807
+ if (v instanceof ArrayBuffer) {
808
+ return { __blob: Buffer.from(v).toString("base64") };
809
+ }
810
+ if (typeof v === "string" || typeof v === "number") return v;
811
+ return String(v);
812
+ }
813
+ function deserializeValue(v) {
814
+ if (v === null) return null;
815
+ if (typeof v === "object" && v !== null && "__blob" in v) {
816
+ const buf = Buffer.from(v.__blob, "base64");
817
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
818
+ }
819
+ return v;
820
+ }
821
+ function deserializeResultSet(srs) {
822
+ const rows = srs.rows.map((obj) => {
823
+ const values = srs.columns.map(
824
+ (col) => deserializeValue(obj[col] ?? null)
825
+ );
826
+ const row = values;
827
+ for (let i = 0; i < srs.columns.length; i++) {
828
+ const col = srs.columns[i];
829
+ if (col !== void 0) {
830
+ row[col] = values[i] ?? null;
831
+ }
832
+ }
833
+ Object.defineProperty(row, "length", {
834
+ value: values.length,
835
+ enumerable: false
836
+ });
837
+ return row;
838
+ });
839
+ return {
840
+ columns: srs.columns,
841
+ columnTypes: srs.columnTypes ?? [],
842
+ rows,
843
+ rowsAffected: srs.rowsAffected,
844
+ lastInsertRowid: srs.lastInsertRowid != null ? BigInt(srs.lastInsertRowid) : void 0,
845
+ toJSON: () => ({
846
+ columns: srs.columns,
847
+ columnTypes: srs.columnTypes ?? [],
848
+ rows: srs.rows,
849
+ rowsAffected: srs.rowsAffected,
850
+ lastInsertRowid: srs.lastInsertRowid
851
+ })
852
+ };
853
+ }
854
+ var init_daemon_protocol = __esm({
855
+ "src/lib/daemon-protocol.ts"() {
856
+ "use strict";
857
+ }
858
+ });
859
+
860
+ // src/lib/db-daemon-client.ts
861
+ var db_daemon_client_exports = {};
862
+ __export(db_daemon_client_exports, {
863
+ createDaemonDbClient: () => createDaemonDbClient,
864
+ initDaemonDbClient: () => initDaemonDbClient
865
+ });
866
+ function normalizeStatement(stmt) {
867
+ if (typeof stmt === "string") {
868
+ return { sql: stmt, args: [] };
869
+ }
870
+ const sql = stmt.sql;
871
+ let args = [];
872
+ if (Array.isArray(stmt.args)) {
873
+ args = stmt.args.map((v) => serializeValue(v));
874
+ } else if (stmt.args && typeof stmt.args === "object") {
875
+ const named = {};
876
+ for (const [key, val] of Object.entries(stmt.args)) {
877
+ named[key] = serializeValue(val);
878
+ }
879
+ return { sql, args: named };
880
+ }
881
+ return { sql, args };
882
+ }
883
+ function createDaemonDbClient(fallbackClient) {
884
+ let _useDaemon = false;
885
+ const client = {
886
+ async execute(stmt) {
887
+ if (!_useDaemon || !isClientConnected()) {
888
+ return fallbackClient.execute(stmt);
889
+ }
890
+ const { sql, args } = normalizeStatement(stmt);
891
+ const response = await sendDaemonRequest({
892
+ type: "db-execute",
893
+ sql,
894
+ args
895
+ });
896
+ if (response.error) {
897
+ const errMsg = String(response.error);
898
+ if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
899
+ process.stderr.write(`[db-daemon] Transport error (${errMsg}), falling back to direct
900
+ `);
901
+ return fallbackClient.execute(stmt);
902
+ }
903
+ throw new Error(errMsg);
904
+ }
905
+ if (response.db) {
906
+ return deserializeResultSet(response.db);
907
+ }
908
+ process.stderr.write("[db-daemon] Unexpected response shape, falling back to direct\n");
909
+ return fallbackClient.execute(stmt);
910
+ },
911
+ async batch(stmts, mode) {
912
+ if (!_useDaemon || !isClientConnected()) {
913
+ return fallbackClient.batch(stmts, mode);
914
+ }
915
+ const statements = stmts.map(normalizeStatement);
916
+ const response = await sendDaemonRequest({
917
+ type: "db-batch",
918
+ statements,
919
+ mode: mode ?? "deferred"
920
+ });
921
+ if (response.error) {
922
+ const errMsg = String(response.error);
923
+ if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
924
+ process.stderr.write(`[db-daemon] Batch transport error (${errMsg}), falling back to direct
925
+ `);
926
+ return fallbackClient.batch(stmts, mode);
927
+ }
928
+ throw new Error(errMsg);
929
+ }
930
+ const batchResults = response["db-batch"];
931
+ if (batchResults) {
932
+ return batchResults.map(deserializeResultSet);
933
+ }
934
+ process.stderr.write("[db-daemon] Unexpected batch response shape, falling back to direct\n");
935
+ return fallbackClient.batch(stmts, mode);
936
+ },
937
+ // Transaction support — delegate to fallback (transactions need direct connection)
938
+ async transaction(mode) {
939
+ return fallbackClient.transaction(mode);
940
+ },
941
+ // executeMultiple — delegate to fallback (used only for schema migrations)
942
+ async executeMultiple(sql) {
943
+ return fallbackClient.executeMultiple(sql);
944
+ },
945
+ // migrate — delegate to fallback
946
+ async migrate(stmts) {
947
+ return fallbackClient.migrate(stmts);
948
+ },
949
+ // Sync mode — delegate to fallback
950
+ sync() {
951
+ return fallbackClient.sync();
952
+ },
953
+ close() {
954
+ _useDaemon = false;
955
+ },
956
+ get closed() {
957
+ return fallbackClient.closed;
958
+ },
959
+ get protocol() {
960
+ return fallbackClient.protocol;
961
+ }
962
+ };
963
+ return {
964
+ ...client,
965
+ /** Enable daemon routing (call after confirming daemon is connected) */
966
+ _enableDaemon() {
967
+ _useDaemon = true;
968
+ },
969
+ /** Check if daemon routing is active */
970
+ _isDaemonActive() {
971
+ return _useDaemon && isClientConnected();
972
+ }
973
+ };
974
+ }
975
+ async function initDaemonDbClient(fallbackClient) {
976
+ if (process.env.EXE_IS_DAEMON === "1") return null;
977
+ const connected = await connectEmbedDaemon();
978
+ if (!connected) {
979
+ process.stderr.write("[db-daemon] Daemon unavailable \u2014 using direct SQLite\n");
980
+ return null;
981
+ }
982
+ const client = createDaemonDbClient(fallbackClient);
983
+ client._enableDaemon();
984
+ process.stderr.write("[db-daemon] DB routing through daemon (single-writer)\n");
985
+ return client;
986
+ }
987
+ var init_db_daemon_client = __esm({
988
+ "src/lib/db-daemon-client.ts"() {
989
+ "use strict";
990
+ init_exe_daemon_client();
991
+ init_daemon_protocol();
992
+ }
993
+ });
994
+
522
995
  // src/lib/database.ts
523
996
  var database_exports = {};
524
997
  __export(database_exports, {
@@ -527,6 +1000,7 @@ __export(database_exports, {
527
1000
  ensureSchema: () => ensureSchema,
528
1001
  getClient: () => getClient,
529
1002
  getRawClient: () => getRawClient,
1003
+ initDaemonClient: () => initDaemonClient,
530
1004
  initDatabase: () => initDatabase,
531
1005
  initTurso: () => initTurso,
532
1006
  isInitialized: () => isInitialized
@@ -554,8 +1028,27 @@ function getClient() {
554
1028
  if (!_resilientClient) {
555
1029
  throw new Error("Database client not initialized. Call initDatabase() first.");
556
1030
  }
1031
+ if (process.env.EXE_IS_DAEMON === "1") {
1032
+ return _resilientClient;
1033
+ }
1034
+ if (_daemonClient && _daemonClient._isDaemonActive()) {
1035
+ return _daemonClient;
1036
+ }
557
1037
  return _resilientClient;
558
1038
  }
1039
+ async function initDaemonClient() {
1040
+ if (process.env.EXE_IS_DAEMON === "1") return;
1041
+ if (!_resilientClient) return;
1042
+ try {
1043
+ const { initDaemonDbClient: initDaemonDbClient2 } = await Promise.resolve().then(() => (init_db_daemon_client(), db_daemon_client_exports));
1044
+ _daemonClient = await initDaemonDbClient2(_resilientClient);
1045
+ } catch (err) {
1046
+ process.stderr.write(
1047
+ `[database] Daemon client init failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
1048
+ `
1049
+ );
1050
+ }
1051
+ }
559
1052
  function getRawClient() {
560
1053
  if (!_client) {
561
1054
  throw new Error("Database client not initialized. Call initDatabase() first.");
@@ -1042,6 +1535,12 @@ async function ensureSchema() {
1042
1535
  } catch {
1043
1536
  }
1044
1537
  }
1538
+ try {
1539
+ await client.execute(
1540
+ `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
1541
+ );
1542
+ } catch {
1543
+ }
1045
1544
  await client.executeMultiple(`
1046
1545
  CREATE TABLE IF NOT EXISTS entities (
1047
1546
  id TEXT PRIMARY KEY,
@@ -1094,7 +1593,30 @@ async function ensureSchema() {
1094
1593
  entity_id TEXT NOT NULL,
1095
1594
  PRIMARY KEY (hyperedge_id, entity_id)
1096
1595
  );
1596
+
1597
+ CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
1598
+ name,
1599
+ content=entities,
1600
+ content_rowid=rowid
1601
+ );
1602
+
1603
+ CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
1604
+ INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
1605
+ END;
1606
+
1607
+ CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
1608
+ INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
1609
+ END;
1610
+
1611
+ CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
1612
+ INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
1613
+ INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
1614
+ END;
1097
1615
  `);
1616
+ try {
1617
+ await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
1618
+ } catch {
1619
+ }
1098
1620
  await client.executeMultiple(`
1099
1621
  CREATE TABLE IF NOT EXISTS entity_aliases (
1100
1622
  alias TEXT NOT NULL PRIMARY KEY,
@@ -1275,6 +1797,33 @@ async function ensureSchema() {
1275
1797
  CREATE INDEX IF NOT EXISTS idx_conversations_channel
1276
1798
  ON conversations(channel_id);
1277
1799
  `);
1800
+ await client.executeMultiple(`
1801
+ CREATE TABLE IF NOT EXISTS session_agent_map (
1802
+ session_uuid TEXT PRIMARY KEY,
1803
+ agent_id TEXT NOT NULL,
1804
+ session_name TEXT,
1805
+ task_id TEXT,
1806
+ project_name TEXT,
1807
+ started_at TEXT NOT NULL
1808
+ );
1809
+
1810
+ CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
1811
+ ON session_agent_map(agent_id);
1812
+ `);
1813
+ try {
1814
+ const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
1815
+ if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
1816
+ await client.execute({
1817
+ sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
1818
+ SELECT session_id, agent_id, '', MIN(timestamp)
1819
+ FROM memories
1820
+ WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
1821
+ GROUP BY session_id, agent_id`,
1822
+ args: []
1823
+ });
1824
+ }
1825
+ } catch {
1826
+ }
1278
1827
  try {
1279
1828
  await client.execute({
1280
1829
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
@@ -1408,15 +1957,41 @@ async function ensureSchema() {
1408
1957
  });
1409
1958
  } catch {
1410
1959
  }
1960
+ for (const col of [
1961
+ "ALTER TABLE memories ADD COLUMN intent TEXT",
1962
+ "ALTER TABLE memories ADD COLUMN outcome TEXT",
1963
+ "ALTER TABLE memories ADD COLUMN domain TEXT",
1964
+ "ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
1965
+ "ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
1966
+ "ALTER TABLE memories ADD COLUMN chain_position TEXT",
1967
+ "ALTER TABLE memories ADD COLUMN review_status TEXT",
1968
+ "ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
1969
+ "ALTER TABLE memories ADD COLUMN file_paths TEXT",
1970
+ "ALTER TABLE memories ADD COLUMN commit_hash TEXT",
1971
+ "ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
1972
+ "ALTER TABLE memories ADD COLUMN token_cost REAL",
1973
+ "ALTER TABLE memories ADD COLUMN audience TEXT",
1974
+ "ALTER TABLE memories ADD COLUMN language_type TEXT",
1975
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
1976
+ ]) {
1977
+ try {
1978
+ await client.execute(col);
1979
+ } catch {
1980
+ }
1981
+ }
1411
1982
  }
1412
1983
  async function disposeDatabase() {
1984
+ if (_daemonClient) {
1985
+ _daemonClient.close();
1986
+ _daemonClient = null;
1987
+ }
1413
1988
  if (_client) {
1414
1989
  _client.close();
1415
1990
  _client = null;
1416
1991
  _resilientClient = null;
1417
1992
  }
1418
1993
  }
1419
- var _client, _resilientClient, initTurso, disposeTurso;
1994
+ var _client, _resilientClient, _daemonClient, initTurso, disposeTurso;
1420
1995
  var init_database = __esm({
1421
1996
  "src/lib/database.ts"() {
1422
1997
  "use strict";
@@ -1424,30 +1999,31 @@ var init_database = __esm({
1424
1999
  init_employees();
1425
2000
  _client = null;
1426
2001
  _resilientClient = null;
2002
+ _daemonClient = null;
1427
2003
  initTurso = initDatabase;
1428
2004
  disposeTurso = disposeDatabase;
1429
2005
  }
1430
2006
  });
1431
2007
 
1432
2008
  // src/lib/license.ts
1433
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
1434
- import { randomUUID } from "crypto";
1435
- import path6 from "path";
2009
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
2010
+ import { randomUUID as randomUUID2 } from "crypto";
2011
+ import path8 from "path";
1436
2012
  import { jwtVerify, importSPKI } from "jose";
1437
2013
  var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
1438
2014
  var init_license = __esm({
1439
2015
  "src/lib/license.ts"() {
1440
2016
  "use strict";
1441
2017
  init_config();
1442
- LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
1443
- CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
1444
- DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
2018
+ LICENSE_PATH = path8.join(EXE_AI_DIR, "license.key");
2019
+ CACHE_PATH = path8.join(EXE_AI_DIR, "license-cache.json");
2020
+ DEVICE_ID_PATH = path8.join(EXE_AI_DIR, "device-id");
1445
2021
  }
1446
2022
  });
1447
2023
 
1448
2024
  // src/lib/plan-limits.ts
1449
- import { readFileSync as readFileSync6, existsSync as existsSync5 } from "fs";
1450
- import path7 from "path";
2025
+ import { readFileSync as readFileSync8, existsSync as existsSync7 } from "fs";
2026
+ import path9 from "path";
1451
2027
  var CACHE_PATH2;
1452
2028
  var init_plan_limits = __esm({
1453
2029
  "src/lib/plan-limits.ts"() {
@@ -1456,15 +2032,15 @@ var init_plan_limits = __esm({
1456
2032
  init_employees();
1457
2033
  init_license();
1458
2034
  init_config();
1459
- CACHE_PATH2 = path7.join(EXE_AI_DIR, "license-cache.json");
2035
+ CACHE_PATH2 = path9.join(EXE_AI_DIR, "license-cache.json");
1460
2036
  }
1461
2037
  });
1462
2038
 
1463
2039
  // src/lib/tmux-routing.ts
1464
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync6, appendFileSync } from "fs";
1465
- import path8 from "path";
2040
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync8, appendFileSync } from "fs";
2041
+ import path10 from "path";
1466
2042
  import os5 from "os";
1467
- import { fileURLToPath } from "url";
2043
+ import { fileURLToPath as fileURLToPath2 } from "url";
1468
2044
  function getMySession() {
1469
2045
  return getTransport().getMySession();
1470
2046
  }
@@ -1476,7 +2052,7 @@ function extractRootExe(name) {
1476
2052
  }
1477
2053
  function getParentExe(sessionKey) {
1478
2054
  try {
1479
- const data = JSON.parse(readFileSync7(path8.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
2055
+ const data = JSON.parse(readFileSync9(path10.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
1480
2056
  return data.parentExe || null;
1481
2057
  } catch {
1482
2058
  return null;
@@ -1505,13 +2081,15 @@ var init_tmux_routing = __esm({
1505
2081
  init_cc_agent_support();
1506
2082
  init_mcp_prefix();
1507
2083
  init_provider_table();
2084
+ init_agent_config();
2085
+ init_runtime_table();
1508
2086
  init_intercom_queue();
1509
2087
  init_plan_limits();
1510
2088
  init_employees();
1511
- SPAWN_LOCK_DIR = path8.join(os5.homedir(), ".exe-os", "spawn-locks");
1512
- SESSION_CACHE = path8.join(os5.homedir(), ".exe-os", "session-cache");
1513
- INTERCOM_LOG2 = path8.join(os5.homedir(), ".exe-os", "intercom.log");
1514
- DEBOUNCE_FILE = path8.join(SESSION_CACHE, "intercom-debounce.json");
2089
+ SPAWN_LOCK_DIR = path10.join(os5.homedir(), ".exe-os", "spawn-locks");
2090
+ SESSION_CACHE = path10.join(os5.homedir(), ".exe-os", "session-cache");
2091
+ INTERCOM_LOG2 = path10.join(os5.homedir(), ".exe-os", "intercom.log");
2092
+ DEBOUNCE_FILE = path10.join(SESSION_CACHE, "intercom-debounce.json");
1515
2093
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
1516
2094
  }
1517
2095
  });
@@ -1551,14 +2129,14 @@ var init_memory = __esm({
1551
2129
 
1552
2130
  // src/lib/keychain.ts
1553
2131
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
1554
- import { existsSync as existsSync7 } from "fs";
1555
- import path9 from "path";
2132
+ import { existsSync as existsSync9 } from "fs";
2133
+ import path11 from "path";
1556
2134
  import os6 from "os";
1557
2135
  function getKeyDir() {
1558
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path9.join(os6.homedir(), ".exe-os");
2136
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path11.join(os6.homedir(), ".exe-os");
1559
2137
  }
1560
2138
  function getKeyPath() {
1561
- return path9.join(getKeyDir(), "master.key");
2139
+ return path11.join(getKeyDir(), "master.key");
1562
2140
  }
1563
2141
  async function tryKeytar() {
1564
2142
  try {
@@ -1579,13 +2157,21 @@ async function getMasterKey() {
1579
2157
  }
1580
2158
  }
1581
2159
  const keyPath = getKeyPath();
1582
- if (!existsSync7(keyPath)) {
2160
+ if (!existsSync9(keyPath)) {
2161
+ process.stderr.write(
2162
+ `[keychain] Key not found at ${keyPath} (HOME=${os6.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2163
+ `
2164
+ );
1583
2165
  return null;
1584
2166
  }
1585
2167
  try {
1586
2168
  const content = await readFile3(keyPath, "utf-8");
1587
2169
  return Buffer.from(content.trim(), "base64");
1588
- } catch {
2170
+ } catch (err) {
2171
+ process.stderr.write(
2172
+ `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
2173
+ `
2174
+ );
1589
2175
  return null;
1590
2176
  }
1591
2177
  }
@@ -1666,13 +2252,13 @@ __export(shard_manager_exports, {
1666
2252
  listShards: () => listShards,
1667
2253
  shardExists: () => shardExists
1668
2254
  });
1669
- import path10 from "path";
1670
- import { existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as readdirSync2 } from "fs";
2255
+ import path12 from "path";
2256
+ import { existsSync as existsSync10, mkdirSync as mkdirSync6, readdirSync as readdirSync2 } from "fs";
1671
2257
  import { createClient as createClient2 } from "@libsql/client";
1672
2258
  function initShardManager(encryptionKey) {
1673
2259
  _encryptionKey = encryptionKey;
1674
- if (!existsSync8(SHARDS_DIR)) {
1675
- mkdirSync5(SHARDS_DIR, { recursive: true });
2260
+ if (!existsSync10(SHARDS_DIR)) {
2261
+ mkdirSync6(SHARDS_DIR, { recursive: true });
1676
2262
  }
1677
2263
  _shardingEnabled = true;
1678
2264
  }
@@ -1692,7 +2278,7 @@ function getShardClient(projectName) {
1692
2278
  }
1693
2279
  const cached = _shards.get(safeName);
1694
2280
  if (cached) return cached;
1695
- const dbPath = path10.join(SHARDS_DIR, `${safeName}.db`);
2281
+ const dbPath = path12.join(SHARDS_DIR, `${safeName}.db`);
1696
2282
  const client = createClient2({
1697
2283
  url: `file:${dbPath}`,
1698
2284
  encryptionKey: _encryptionKey
@@ -1702,10 +2288,10 @@ function getShardClient(projectName) {
1702
2288
  }
1703
2289
  function shardExists(projectName) {
1704
2290
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
1705
- return existsSync8(path10.join(SHARDS_DIR, `${safeName}.db`));
2291
+ return existsSync10(path12.join(SHARDS_DIR, `${safeName}.db`));
1706
2292
  }
1707
2293
  function listShards() {
1708
- if (!existsSync8(SHARDS_DIR)) return [];
2294
+ if (!existsSync10(SHARDS_DIR)) return [];
1709
2295
  return readdirSync2(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1710
2296
  }
1711
2297
  async function ensureShardSchema(client) {
@@ -1891,7 +2477,7 @@ var init_shard_manager = __esm({
1891
2477
  "src/lib/shard-manager.ts"() {
1892
2478
  "use strict";
1893
2479
  init_config();
1894
- SHARDS_DIR = path10.join(EXE_AI_DIR, "shards");
2480
+ SHARDS_DIR = path12.join(EXE_AI_DIR, "shards");
1895
2481
  _shards = /* @__PURE__ */ new Map();
1896
2482
  _encryptionKey = null;
1897
2483
  _shardingEnabled = false;
@@ -2016,7 +2602,7 @@ __export(global_procedures_exports, {
2016
2602
  loadGlobalProcedures: () => loadGlobalProcedures,
2017
2603
  storeGlobalProcedure: () => storeGlobalProcedure
2018
2604
  });
2019
- import { randomUUID as randomUUID2 } from "crypto";
2605
+ import { randomUUID as randomUUID3 } from "crypto";
2020
2606
  async function loadGlobalProcedures() {
2021
2607
  const client = getClient();
2022
2608
  const result = await client.execute({
@@ -2045,7 +2631,7 @@ ${sections.join("\n\n")}
2045
2631
  `;
2046
2632
  }
2047
2633
  async function storeGlobalProcedure(input2) {
2048
- const id = randomUUID2();
2634
+ const id = randomUUID3();
2049
2635
  const now = (/* @__PURE__ */ new Date()).toISOString();
2050
2636
  const client = getClient();
2051
2637
  await client.execute({
@@ -2096,6 +2682,7 @@ __export(store_exports, {
2096
2682
  vectorToBlob: () => vectorToBlob,
2097
2683
  writeMemory: () => writeMemory
2098
2684
  });
2685
+ import { createHash } from "crypto";
2099
2686
  function isBusyError2(err) {
2100
2687
  if (err instanceof Error) {
2101
2688
  const msg = err.message.toLowerCase();
@@ -2169,12 +2756,52 @@ function classifyTier(record) {
2169
2756
  if (["store_memory", "manual"].includes(record.tool_name ?? "") && (record.importance ?? 0) >= 5) return 2;
2170
2757
  return 3;
2171
2758
  }
2759
+ function inferFilePaths(record) {
2760
+ if (!["Read", "Write", "Edit"].includes(record.tool_name)) return null;
2761
+ const firstLine = record.raw_text.split("\n")[0] ?? "";
2762
+ const match = firstLine.match(/(\/[\w./-]+\.\w+)/);
2763
+ return match ? JSON.stringify([match[1]]) : null;
2764
+ }
2765
+ function inferCommitHash(record) {
2766
+ if (record.tool_name !== "Bash") return null;
2767
+ const match = record.raw_text.match(/\b([a-f0-9]{7,40})\b/);
2768
+ return match ? match[1] : null;
2769
+ }
2770
+ function inferLanguageType(record) {
2771
+ const text = record.raw_text;
2772
+ if (!text || text.length < 10) return null;
2773
+ const trimmed = text.trimStart();
2774
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) return "json";
2775
+ if (/\b(SELECT|INSERT|UPDATE|DELETE|CREATE TABLE|ALTER TABLE)\b/i.test(text)) return "sql";
2776
+ if (/\b(function |const |import |export |class |def |async |=>)\b/.test(text)) return "code";
2777
+ if (trimmed.startsWith("#") || trimmed.startsWith("*")) return "prose";
2778
+ return "mixed";
2779
+ }
2780
+ function inferDomain(record) {
2781
+ const proj = (record.project_name ?? "").toLowerCase();
2782
+ if (proj.includes("marketing") || proj.includes("content")) return "marketing";
2783
+ if (proj.includes("crm") || proj.includes("customer")) return "customer";
2784
+ return null;
2785
+ }
2172
2786
  async function writeMemory(record) {
2173
2787
  if (record.vector !== null && record.vector.length !== EMBEDDING_DIM) {
2174
2788
  throw new Error(
2175
2789
  `Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
2176
2790
  );
2177
2791
  }
2792
+ const contentHash = createHash("md5").update(record.raw_text).digest("hex");
2793
+ if (_pendingRecords.some((r) => r.content_hash === contentHash && r.agent_id === record.agent_id)) {
2794
+ return;
2795
+ }
2796
+ try {
2797
+ const client = getClient();
2798
+ const existing = await client.execute({
2799
+ sql: "SELECT id FROM memories WHERE content_hash = ? AND agent_id = ? LIMIT 1",
2800
+ args: [contentHash, record.agent_id]
2801
+ });
2802
+ if (existing.rows.length > 0) return;
2803
+ } catch {
2804
+ }
2178
2805
  const dbRow = {
2179
2806
  id: record.id,
2180
2807
  agent_id: record.agent_id,
@@ -2204,7 +2831,23 @@ async function writeMemory(record) {
2204
2831
  supersedes_id: record.supersedes_id ?? null,
2205
2832
  draft: record.draft ? 1 : 0,
2206
2833
  memory_type: record.memory_type ?? "raw",
2207
- trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null
2834
+ trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
2835
+ content_hash: contentHash,
2836
+ intent: record.intent ?? null,
2837
+ outcome: record.outcome ?? null,
2838
+ domain: record.domain ?? inferDomain(record),
2839
+ referenced_entities: record.referenced_entities ?? null,
2840
+ retrieval_count: record.retrieval_count ?? 0,
2841
+ chain_position: record.chain_position ?? null,
2842
+ review_status: record.review_status ?? null,
2843
+ context_window_pct: record.context_window_pct ?? null,
2844
+ file_paths: record.file_paths ?? inferFilePaths(record),
2845
+ commit_hash: record.commit_hash ?? inferCommitHash(record),
2846
+ duration_ms: record.duration_ms ?? null,
2847
+ token_cost: record.token_cost ?? null,
2848
+ audience: record.audience ?? null,
2849
+ language_type: record.language_type ?? inferLanguageType(record),
2850
+ parent_memory_id: record.parent_memory_id ?? null
2208
2851
  };
2209
2852
  _pendingRecords.push(dbRow);
2210
2853
  orgBus.emit({
@@ -2262,80 +2905,85 @@ async function flushBatch() {
2262
2905
  const draft = row.draft ? 1 : 0;
2263
2906
  const memoryType = row.memory_type ?? "raw";
2264
2907
  const trajectory = row.trajectory ?? null;
2265
- return {
2266
- sql: hasVector ? `INSERT OR IGNORE INTO memories
2267
- (id, agent_id, agent_role, session_id, timestamp,
2268
- tool_name, project_name,
2269
- has_error, raw_text, vector, version, task_id, importance, status,
2270
- confidence, last_accessed,
2271
- workspace_id, document_id, user_id, char_offset, page_number,
2272
- source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory)
2273
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories
2274
- (id, agent_id, agent_role, session_id, timestamp,
2908
+ const contentHash = row.content_hash ?? null;
2909
+ const intent = row.intent ?? null;
2910
+ const outcome = row.outcome ?? null;
2911
+ const domain = row.domain ?? null;
2912
+ const referencedEntities = row.referenced_entities ?? null;
2913
+ const retrievalCount = row.retrieval_count ?? 0;
2914
+ const chainPosition = row.chain_position ?? null;
2915
+ const reviewStatus = row.review_status ?? null;
2916
+ const contextWindowPct = row.context_window_pct ?? null;
2917
+ const filePaths = row.file_paths ?? null;
2918
+ const commitHash = row.commit_hash ?? null;
2919
+ const durationMs = row.duration_ms ?? null;
2920
+ const tokenCost = row.token_cost ?? null;
2921
+ const audience = row.audience ?? null;
2922
+ const languageType = row.language_type ?? null;
2923
+ const parentMemoryId = row.parent_memory_id ?? null;
2924
+ const cols = `id, agent_id, agent_role, session_id, timestamp,
2275
2925
  tool_name, project_name,
2276
2926
  has_error, raw_text, vector, version, task_id, importance, status,
2277
2927
  confidence, last_accessed,
2278
2928
  workspace_id, document_id, user_id, char_offset, page_number,
2279
- source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory)
2280
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
2281
- args: hasVector ? [
2282
- row.id,
2283
- row.agent_id,
2284
- row.agent_role,
2285
- row.session_id,
2286
- row.timestamp,
2287
- row.tool_name,
2288
- row.project_name,
2289
- row.has_error,
2290
- row.raw_text,
2291
- vectorToBlob(row.vector),
2292
- row.version,
2293
- taskId,
2294
- importance,
2295
- status,
2296
- confidence,
2297
- lastAccessed,
2298
- workspaceId,
2299
- documentId,
2300
- userId,
2301
- charOffset,
2302
- pageNumber,
2303
- sourcePath,
2304
- sourceType,
2305
- tier,
2306
- supersedesId,
2307
- draft,
2308
- memoryType,
2309
- trajectory
2310
- ] : [
2311
- row.id,
2312
- row.agent_id,
2313
- row.agent_role,
2314
- row.session_id,
2315
- row.timestamp,
2316
- row.tool_name,
2317
- row.project_name,
2318
- row.has_error,
2319
- row.raw_text,
2320
- row.version,
2321
- taskId,
2322
- importance,
2323
- status,
2324
- confidence,
2325
- lastAccessed,
2326
- workspaceId,
2327
- documentId,
2328
- userId,
2329
- charOffset,
2330
- pageNumber,
2331
- sourcePath,
2332
- sourceType,
2333
- tier,
2334
- supersedesId,
2335
- draft,
2336
- memoryType,
2337
- trajectory
2338
- ]
2929
+ source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
2930
+ intent, outcome, domain, referenced_entities, retrieval_count,
2931
+ chain_position, review_status, context_window_pct, file_paths, commit_hash,
2932
+ duration_ms, token_cost, audience, language_type, parent_memory_id`;
2933
+ const metaArgs = [
2934
+ intent,
2935
+ outcome,
2936
+ domain,
2937
+ referencedEntities,
2938
+ retrievalCount,
2939
+ chainPosition,
2940
+ reviewStatus,
2941
+ contextWindowPct,
2942
+ filePaths,
2943
+ commitHash,
2944
+ durationMs,
2945
+ tokenCost,
2946
+ audience,
2947
+ languageType,
2948
+ parentMemoryId
2949
+ ];
2950
+ const baseArgs = [
2951
+ row.id,
2952
+ row.agent_id,
2953
+ row.agent_role,
2954
+ row.session_id,
2955
+ row.timestamp,
2956
+ row.tool_name,
2957
+ row.project_name,
2958
+ row.has_error,
2959
+ row.raw_text
2960
+ ];
2961
+ const sharedArgs = [
2962
+ row.version,
2963
+ taskId,
2964
+ importance,
2965
+ status,
2966
+ confidence,
2967
+ lastAccessed,
2968
+ workspaceId,
2969
+ documentId,
2970
+ userId,
2971
+ charOffset,
2972
+ pageNumber,
2973
+ sourcePath,
2974
+ sourceType,
2975
+ tier,
2976
+ supersedesId,
2977
+ draft,
2978
+ memoryType,
2979
+ trajectory,
2980
+ contentHash
2981
+ ];
2982
+ return {
2983
+ sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
2984
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
2985
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
2986
+ args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
2339
2987
  };
2340
2988
  };
2341
2989
  const globalClient = getClient();
@@ -2588,10 +3236,10 @@ var init_store = __esm({
2588
3236
  // src/adapters/claude/hooks/stop.ts
2589
3237
  init_config();
2590
3238
  init_config();
2591
- import { spawn } from "child_process";
2592
- import { existsSync as existsSync9, openSync, closeSync } from "fs";
2593
- import path11 from "path";
2594
- import { fileURLToPath as fileURLToPath2 } from "url";
3239
+ import { spawn as spawn2 } from "child_process";
3240
+ import { existsSync as existsSync11, openSync as openSync2, closeSync as closeSync2 } from "fs";
3241
+ import path13 from "path";
3242
+ import { fileURLToPath as fileURLToPath3 } from "url";
2595
3243
 
2596
3244
  // src/adapters/claude/active-agent.ts
2597
3245
  init_config();
@@ -2704,10 +3352,10 @@ if (!process.env.AGENT_ID) {
2704
3352
  if (!loadConfigSync().autoIngestion) {
2705
3353
  process.exit(0);
2706
3354
  }
2707
- var WORKER_LOG_PATH = path11.join(EXE_AI_DIR, "workers.log");
3355
+ var WORKER_LOG_PATH = path13.join(EXE_AI_DIR, "workers.log");
2708
3356
  function openWorkerLog() {
2709
3357
  try {
2710
- return openSync(WORKER_LOG_PATH, "a");
3358
+ return openSync2(WORKER_LOG_PATH, "a");
2711
3359
  } catch {
2712
3360
  return "ignore";
2713
3361
  }
@@ -2796,17 +3444,17 @@ process.stdin.on("end", () => {
2796
3444
  }).catch(() => {
2797
3445
  });
2798
3446
  }
2799
- const workerPath = path11.resolve(
2800
- path11.dirname(fileURLToPath2(import.meta.url)),
3447
+ const workerPath = path13.resolve(
3448
+ path13.dirname(fileURLToPath3(import.meta.url)),
2801
3449
  "response-ingest-worker.js"
2802
3450
  );
2803
- if (!existsSync9(workerPath)) {
3451
+ if (!existsSync11(workerPath)) {
2804
3452
  process.stderr.write(`[stop] WARN: response-ingest-worker not found at ${workerPath}
2805
3453
  `);
2806
3454
  process.exit(0);
2807
3455
  }
2808
3456
  const stderrFd = openWorkerLog();
2809
- const worker = spawn(process.execPath, [workerPath], {
3457
+ const worker = spawn2(process.execPath, [workerPath], {
2810
3458
  detached: true,
2811
3459
  stdio: ["ignore", "ignore", stderrFd],
2812
3460
  env: {
@@ -2819,7 +3467,7 @@ process.stdin.on("end", () => {
2819
3467
  });
2820
3468
  worker.unref();
2821
3469
  if (typeof stderrFd === "number") try {
2822
- closeSync(stderrFd);
3470
+ closeSync2(stderrFd);
2823
3471
  } catch {
2824
3472
  }
2825
3473
  } catch {