@askexenow/exe-os 0.9.16 → 0.9.18

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 (97) hide show
  1. package/dist/bin/backfill-conversations.js +1242 -909
  2. package/dist/bin/backfill-responses.js +1245 -912
  3. package/dist/bin/backfill-vectors.js +1244 -906
  4. package/dist/bin/cleanup-stale-review-tasks.js +1870 -417
  5. package/dist/bin/cli.js +217 -107
  6. package/dist/bin/exe-agent-config.js +2 -2
  7. package/dist/bin/exe-agent.js +62 -0
  8. package/dist/bin/exe-assign.js +346 -10
  9. package/dist/bin/exe-boot.js +387 -32
  10. package/dist/bin/exe-call.js +72 -2
  11. package/dist/bin/exe-cloud.js +8 -0
  12. package/dist/bin/exe-dispatch.js +1821 -225
  13. package/dist/bin/exe-doctor.js +720 -52
  14. package/dist/bin/exe-export-behaviors.js +1429 -148
  15. package/dist/bin/exe-forget.js +1408 -34
  16. package/dist/bin/exe-gateway.js +1629 -1295
  17. package/dist/bin/exe-heartbeat.js +1899 -448
  18. package/dist/bin/exe-kill.js +1624 -346
  19. package/dist/bin/exe-launch-agent.js +726 -90
  20. package/dist/bin/exe-link.js +27 -8
  21. package/dist/bin/exe-new-employee.js +75 -9
  22. package/dist/bin/exe-pending-messages.js +2769 -1316
  23. package/dist/bin/exe-pending-notifications.js +2829 -1376
  24. package/dist/bin/exe-pending-reviews.js +2847 -1392
  25. package/dist/bin/exe-rename.js +89 -8
  26. package/dist/bin/exe-review.js +1494 -312
  27. package/dist/bin/exe-search.js +1608 -1300
  28. package/dist/bin/exe-session-cleanup.js +194 -91
  29. package/dist/bin/exe-settings.js +10 -2
  30. package/dist/bin/exe-start-codex.js +769 -120
  31. package/dist/bin/exe-start-opencode.js +763 -108
  32. package/dist/bin/exe-status.js +1887 -434
  33. package/dist/bin/exe-team.js +1782 -324
  34. package/dist/bin/git-sweep.js +408 -33
  35. package/dist/bin/graph-backfill.js +681 -27
  36. package/dist/bin/graph-export.js +1419 -141
  37. package/dist/bin/install.js +4 -8
  38. package/dist/bin/intercom-check.js +8641 -0
  39. package/dist/bin/scan-tasks.js +553 -38
  40. package/dist/bin/setup.js +82 -10
  41. package/dist/bin/shard-migrate.js +682 -28
  42. package/dist/gateway/index.js +1629 -1295
  43. package/dist/hooks/bug-report-worker.js +1136 -183
  44. package/dist/hooks/codex-stop-task-finalizer.js +1060 -107
  45. package/dist/hooks/commit-complete.js +408 -33
  46. package/dist/hooks/error-recall.js +1608 -1300
  47. package/dist/hooks/ingest-worker.js +250 -7966
  48. package/dist/hooks/ingest.js +707 -119
  49. package/dist/hooks/instructions-loaded.js +383 -20
  50. package/dist/hooks/notification.js +383 -20
  51. package/dist/hooks/post-compact.js +384 -21
  52. package/dist/hooks/{response-ingest-worker.js → post-tool-combined.js} +4157 -1716
  53. package/dist/hooks/pre-compact.js +486 -45
  54. package/dist/hooks/pre-tool-use.js +385 -22
  55. package/dist/hooks/prompt-submit.js +291 -96
  56. package/dist/hooks/session-end.js +490 -48
  57. package/dist/hooks/session-start.js +236 -22
  58. package/dist/hooks/stop.js +192 -50
  59. package/dist/hooks/subagent-stop.js +95 -18
  60. package/dist/hooks/summary-worker.js +205 -361
  61. package/dist/index.js +221 -105
  62. package/dist/lib/agent-config.js +2 -2
  63. package/dist/lib/cloud-sync.js +27 -8
  64. package/dist/lib/consolidation.js +437 -41
  65. package/dist/lib/database.js +20 -8
  66. package/dist/lib/db-daemon-client.js +2 -2
  67. package/dist/lib/db.js +20 -8
  68. package/dist/lib/device-registry.js +27 -8
  69. package/dist/lib/employee-templates.js +62 -0
  70. package/dist/lib/employees.js +2 -2
  71. package/dist/lib/exe-daemon.js +6703 -6259
  72. package/dist/lib/hybrid-search.js +1608 -1300
  73. package/dist/lib/identity.js +1 -1
  74. package/dist/lib/messaging.js +11 -3
  75. package/dist/lib/reminders.js +1 -1
  76. package/dist/lib/schedules.js +718 -26
  77. package/dist/lib/session-registry.js +11 -0
  78. package/dist/lib/skill-learning.js +639 -9
  79. package/dist/lib/store.js +676 -27
  80. package/dist/lib/tasks.js +665 -27
  81. package/dist/lib/tmux-routing.js +732 -94
  82. package/dist/lib/token-spend.js +1 -1
  83. package/dist/mcp/server.js +856 -383
  84. package/dist/mcp/tools/complete-reminder.js +1 -1
  85. package/dist/mcp/tools/create-reminder.js +1 -1
  86. package/dist/mcp/tools/create-task.js +616 -46
  87. package/dist/mcp/tools/deactivate-behavior.js +9 -1
  88. package/dist/mcp/tools/list-reminders.js +1 -1
  89. package/dist/mcp/tools/list-tasks.js +10 -2
  90. package/dist/mcp/tools/send-message.js +11 -3
  91. package/dist/mcp/tools/update-task.js +677 -39
  92. package/dist/runtime/index.js +425 -37
  93. package/dist/tui/App.js +365 -34
  94. package/package.json +5 -2
  95. package/src/commands/exe/intercom.md +6 -17
  96. package/dist/bin/wiki-sync.js +0 -2991
  97. package/dist/hooks/prompt-ingest-worker.js +0 -3979
@@ -1,6 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
+ }) : x)(function(x) {
7
+ if (typeof require !== "undefined") return require.apply(this, arguments);
8
+ throw Error('Dynamic require of "' + x + '" is not supported');
9
+ });
4
10
  var __esm = (fn, res) => function __init() {
5
11
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
12
  };
@@ -9,6 +15,15 @@ var __export = (target, all) => {
9
15
  __defProp(target, name, { get: all[name], enumerable: true });
10
16
  };
11
17
 
18
+ // src/types/memory.ts
19
+ var EMBEDDING_DIM;
20
+ var init_memory = __esm({
21
+ "src/types/memory.ts"() {
22
+ "use strict";
23
+ EMBEDDING_DIM = 1024;
24
+ }
25
+ });
26
+
12
27
  // src/lib/db-retry.ts
13
28
  function isBusyError(err) {
14
29
  if (err instanceof Error) {
@@ -58,9 +73,9 @@ var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
58
73
  var init_db_retry = __esm({
59
74
  "src/lib/db-retry.ts"() {
60
75
  "use strict";
61
- MAX_RETRIES = 3;
62
- BASE_DELAY_MS = 200;
63
- MAX_JITTER_MS = 300;
76
+ MAX_RETRIES = 5;
77
+ BASE_DELAY_MS = 250;
78
+ MAX_JITTER_MS = 400;
64
79
  }
65
80
  });
66
81
 
@@ -74,12 +89,25 @@ async function ensurePrivateDir(dirPath) {
74
89
  } catch {
75
90
  }
76
91
  }
92
+ function ensurePrivateDirSync(dirPath) {
93
+ mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
94
+ try {
95
+ chmodSync(dirPath, PRIVATE_DIR_MODE);
96
+ } catch {
97
+ }
98
+ }
77
99
  async function enforcePrivateFile(filePath) {
78
100
  try {
79
101
  await chmod(filePath, PRIVATE_FILE_MODE);
80
102
  } catch {
81
103
  }
82
104
  }
105
+ function enforcePrivateFileSync(filePath) {
106
+ try {
107
+ if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
108
+ } catch {
109
+ }
110
+ }
83
111
  var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
84
112
  var init_secure_files = __esm({
85
113
  "src/lib/secure-files.ts"() {
@@ -907,7 +935,538 @@ var init_database_adapter = __esm({
907
935
  }
908
936
  });
909
937
 
938
+ // src/lib/daemon-auth.ts
939
+ import crypto from "crypto";
940
+ import path4 from "path";
941
+ import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
942
+ function normalizeToken(token) {
943
+ if (!token) return null;
944
+ const trimmed = token.trim();
945
+ return trimmed.length > 0 ? trimmed : null;
946
+ }
947
+ function readDaemonToken() {
948
+ try {
949
+ if (!existsSync4(DAEMON_TOKEN_PATH)) return null;
950
+ return normalizeToken(readFileSync3(DAEMON_TOKEN_PATH, "utf8"));
951
+ } catch {
952
+ return null;
953
+ }
954
+ }
955
+ function ensureDaemonToken(seed) {
956
+ const existing = readDaemonToken();
957
+ if (existing) return existing;
958
+ const token = normalizeToken(seed) ?? crypto.randomBytes(32).toString("hex");
959
+ ensurePrivateDirSync(EXE_AI_DIR);
960
+ writeFileSync2(DAEMON_TOKEN_PATH, `${token}
961
+ `, "utf8");
962
+ enforcePrivateFileSync(DAEMON_TOKEN_PATH);
963
+ return token;
964
+ }
965
+ var DAEMON_TOKEN_PATH;
966
+ var init_daemon_auth = __esm({
967
+ "src/lib/daemon-auth.ts"() {
968
+ "use strict";
969
+ init_config();
970
+ init_secure_files();
971
+ DAEMON_TOKEN_PATH = path4.join(EXE_AI_DIR, "exed.token");
972
+ }
973
+ });
974
+
975
+ // src/lib/exe-daemon-client.ts
976
+ import net from "net";
977
+ import os4 from "os";
978
+ import { spawn } from "child_process";
979
+ import { randomUUID } from "crypto";
980
+ import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
981
+ import path5 from "path";
982
+ import { fileURLToPath } from "url";
983
+ function handleData(chunk) {
984
+ _buffer += chunk.toString();
985
+ if (_buffer.length > MAX_BUFFER) {
986
+ _buffer = "";
987
+ return;
988
+ }
989
+ let newlineIdx;
990
+ while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
991
+ const line = _buffer.slice(0, newlineIdx).trim();
992
+ _buffer = _buffer.slice(newlineIdx + 1);
993
+ if (!line) continue;
994
+ try {
995
+ const response = JSON.parse(line);
996
+ const id = response.id;
997
+ if (!id) continue;
998
+ const entry = _pending.get(id);
999
+ if (entry) {
1000
+ clearTimeout(entry.timer);
1001
+ _pending.delete(id);
1002
+ entry.resolve(response);
1003
+ }
1004
+ } catch {
1005
+ }
1006
+ }
1007
+ }
1008
+ function cleanupStaleFiles() {
1009
+ if (existsSync5(PID_PATH)) {
1010
+ try {
1011
+ const pid = parseInt(readFileSync4(PID_PATH, "utf8").trim(), 10);
1012
+ if (pid > 0) {
1013
+ try {
1014
+ process.kill(pid, 0);
1015
+ return;
1016
+ } catch {
1017
+ }
1018
+ }
1019
+ } catch {
1020
+ }
1021
+ try {
1022
+ unlinkSync2(PID_PATH);
1023
+ } catch {
1024
+ }
1025
+ try {
1026
+ unlinkSync2(SOCKET_PATH);
1027
+ } catch {
1028
+ }
1029
+ }
1030
+ }
1031
+ function findPackageRoot() {
1032
+ let dir = path5.dirname(fileURLToPath(import.meta.url));
1033
+ const { root } = path5.parse(dir);
1034
+ while (dir !== root) {
1035
+ if (existsSync5(path5.join(dir, "package.json"))) return dir;
1036
+ dir = path5.dirname(dir);
1037
+ }
1038
+ return null;
1039
+ }
1040
+ function getAvailableMemoryGB() {
1041
+ if (process.platform === "darwin") {
1042
+ try {
1043
+ const { execSync: execSync5 } = __require("child_process");
1044
+ const vmstat = execSync5("vm_stat", { encoding: "utf8" });
1045
+ const pageSize = 16384;
1046
+ const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1047
+ const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
1048
+ const free = vmstat.match(/Pages free:\s+(\d+)/);
1049
+ const inactive = vmstat.match(/Pages inactive:\s+(\d+)/);
1050
+ const speculative = vmstat.match(/Pages speculative:\s+(\d+)/);
1051
+ const freePages = free ? parseInt(free[1], 10) : 0;
1052
+ const inactivePages = inactive ? parseInt(inactive[1], 10) : 0;
1053
+ const speculativePages = speculative ? parseInt(speculative[1], 10) : 0;
1054
+ return (freePages + inactivePages + speculativePages) * actualPageSize / (1024 * 1024 * 1024);
1055
+ } catch {
1056
+ return os4.freemem() / (1024 * 1024 * 1024);
1057
+ }
1058
+ }
1059
+ return os4.freemem() / (1024 * 1024 * 1024);
1060
+ }
1061
+ function spawnDaemon() {
1062
+ const freeGB = getAvailableMemoryGB();
1063
+ const totalGB = os4.totalmem() / (1024 * 1024 * 1024);
1064
+ if (totalGB <= 8) {
1065
+ process.stderr.write(
1066
+ `[exed-client] SKIP: ${totalGB.toFixed(0)}GB system \u2014 embedding daemon disabled. Using keyword search only. Minimum 16GB recommended for vector search.
1067
+ `
1068
+ );
1069
+ return;
1070
+ }
1071
+ if (totalGB <= 16 && freeGB < 2) {
1072
+ process.stderr.write(
1073
+ `[exed-client] SKIP: low memory (${freeGB.toFixed(1)}GB available / ${totalGB.toFixed(0)}GB total). Embedding daemon not started \u2014 using keyword search only.
1074
+ `
1075
+ );
1076
+ return;
1077
+ }
1078
+ const pkgRoot = findPackageRoot();
1079
+ if (!pkgRoot) {
1080
+ process.stderr.write("[exed-client] WARN: cannot find package root\n");
1081
+ return;
1082
+ }
1083
+ const daemonPath = path5.join(pkgRoot, "dist", "lib", "exe-daemon.js");
1084
+ if (!existsSync5(daemonPath)) {
1085
+ process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
1086
+ `);
1087
+ return;
1088
+ }
1089
+ const resolvedPath = daemonPath;
1090
+ const daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV] ?? null);
1091
+ process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
1092
+ `);
1093
+ const logPath = path5.join(path5.dirname(SOCKET_PATH), "exed.log");
1094
+ let stderrFd = "ignore";
1095
+ try {
1096
+ stderrFd = openSync(logPath, "a");
1097
+ } catch {
1098
+ }
1099
+ const heapCapMB = totalGB <= 8 ? 256 : 512;
1100
+ const nodeArgs = [`--max-old-space-size=${heapCapMB}`, resolvedPath];
1101
+ const child = spawn(process.execPath, nodeArgs, {
1102
+ detached: true,
1103
+ stdio: ["ignore", "ignore", stderrFd],
1104
+ env: {
1105
+ ...process.env,
1106
+ TMUX: void 0,
1107
+ // Daemon is global — must not inherit session scope
1108
+ TMUX_PANE: void 0,
1109
+ // Prevents resolveExeSession() from scoping to one session
1110
+ EXE_DAEMON_SOCK: SOCKET_PATH,
1111
+ EXE_DAEMON_PID: PID_PATH,
1112
+ [DAEMON_TOKEN_ENV]: daemonToken
1113
+ }
1114
+ });
1115
+ child.unref();
1116
+ if (typeof stderrFd === "number") {
1117
+ try {
1118
+ closeSync(stderrFd);
1119
+ } catch {
1120
+ }
1121
+ }
1122
+ }
1123
+ function acquireSpawnLock() {
1124
+ try {
1125
+ const fd = openSync(SPAWN_LOCK_PATH, "wx");
1126
+ closeSync(fd);
1127
+ return true;
1128
+ } catch {
1129
+ try {
1130
+ const stat = statSync(SPAWN_LOCK_PATH);
1131
+ if (Date.now() - stat.mtimeMs > SPAWN_LOCK_STALE_MS) {
1132
+ try {
1133
+ unlinkSync2(SPAWN_LOCK_PATH);
1134
+ } catch {
1135
+ }
1136
+ try {
1137
+ const fd = openSync(SPAWN_LOCK_PATH, "wx");
1138
+ closeSync(fd);
1139
+ return true;
1140
+ } catch {
1141
+ }
1142
+ }
1143
+ } catch {
1144
+ }
1145
+ return false;
1146
+ }
1147
+ }
1148
+ function releaseSpawnLock() {
1149
+ try {
1150
+ unlinkSync2(SPAWN_LOCK_PATH);
1151
+ } catch {
1152
+ }
1153
+ }
1154
+ function connectToSocket() {
1155
+ return new Promise((resolve) => {
1156
+ if (_socket && _connected) {
1157
+ resolve(true);
1158
+ return;
1159
+ }
1160
+ const socket = net.createConnection({ path: SOCKET_PATH });
1161
+ const connectTimeout = setTimeout(() => {
1162
+ socket.destroy();
1163
+ resolve(false);
1164
+ }, 2e3);
1165
+ socket.on("connect", () => {
1166
+ clearTimeout(connectTimeout);
1167
+ _socket = socket;
1168
+ _connected = true;
1169
+ _buffer = "";
1170
+ socket.on("data", handleData);
1171
+ socket.on("close", () => {
1172
+ _connected = false;
1173
+ _socket = null;
1174
+ for (const [id, entry] of _pending) {
1175
+ clearTimeout(entry.timer);
1176
+ _pending.delete(id);
1177
+ entry.resolve({ error: "Connection closed" });
1178
+ }
1179
+ });
1180
+ socket.on("error", () => {
1181
+ _connected = false;
1182
+ _socket = null;
1183
+ });
1184
+ resolve(true);
1185
+ });
1186
+ socket.on("error", () => {
1187
+ clearTimeout(connectTimeout);
1188
+ resolve(false);
1189
+ });
1190
+ });
1191
+ }
1192
+ async function connectEmbedDaemon() {
1193
+ if (_socket && _connected) return true;
1194
+ if (await connectToSocket()) return true;
1195
+ if (acquireSpawnLock()) {
1196
+ try {
1197
+ cleanupStaleFiles();
1198
+ spawnDaemon();
1199
+ } finally {
1200
+ releaseSpawnLock();
1201
+ }
1202
+ }
1203
+ const start = Date.now();
1204
+ let delay2 = 100;
1205
+ while (Date.now() - start < CONNECT_TIMEOUT_MS) {
1206
+ await new Promise((r) => setTimeout(r, delay2));
1207
+ if (await connectToSocket()) return true;
1208
+ delay2 = Math.min(delay2 * 2, 3e3);
1209
+ }
1210
+ return false;
1211
+ }
1212
+ function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
1213
+ return new Promise((resolve) => {
1214
+ if (!_socket || !_connected) {
1215
+ resolve({ error: "Not connected" });
1216
+ return;
1217
+ }
1218
+ const id = randomUUID();
1219
+ const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
1220
+ const timer = setTimeout(() => {
1221
+ _pending.delete(id);
1222
+ resolve({ error: "Request timeout" });
1223
+ }, timeoutMs);
1224
+ _pending.set(id, { resolve, timer });
1225
+ try {
1226
+ _socket.write(JSON.stringify({ id, token, ...payload }) + "\n");
1227
+ } catch {
1228
+ clearTimeout(timer);
1229
+ _pending.delete(id);
1230
+ resolve({ error: "Write failed" });
1231
+ }
1232
+ });
1233
+ }
1234
+ function isClientConnected() {
1235
+ return _connected;
1236
+ }
1237
+ var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, DAEMON_TOKEN_ENV, _socket, _connected, _buffer, _pending, MAX_BUFFER;
1238
+ var init_exe_daemon_client = __esm({
1239
+ "src/lib/exe-daemon-client.ts"() {
1240
+ "use strict";
1241
+ init_config();
1242
+ init_daemon_auth();
1243
+ SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path5.join(EXE_AI_DIR, "exed.sock");
1244
+ PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path5.join(EXE_AI_DIR, "exed.pid");
1245
+ SPAWN_LOCK_PATH = path5.join(EXE_AI_DIR, "exed-spawn.lock");
1246
+ SPAWN_LOCK_STALE_MS = 3e4;
1247
+ CONNECT_TIMEOUT_MS = 15e3;
1248
+ REQUEST_TIMEOUT_MS = 3e4;
1249
+ DAEMON_TOKEN_ENV = "EXE_DAEMON_TOKEN";
1250
+ _socket = null;
1251
+ _connected = false;
1252
+ _buffer = "";
1253
+ _pending = /* @__PURE__ */ new Map();
1254
+ MAX_BUFFER = 1e7;
1255
+ }
1256
+ });
1257
+
1258
+ // src/lib/daemon-protocol.ts
1259
+ function serializeValue(v) {
1260
+ if (v === null || v === void 0) return null;
1261
+ if (typeof v === "bigint") return Number(v);
1262
+ if (typeof v === "boolean") return v ? 1 : 0;
1263
+ if (v instanceof Uint8Array) {
1264
+ return { __blob: Buffer.from(v).toString("base64") };
1265
+ }
1266
+ if (ArrayBuffer.isView(v)) {
1267
+ return { __blob: Buffer.from(v.buffer, v.byteOffset, v.byteLength).toString("base64") };
1268
+ }
1269
+ if (v instanceof ArrayBuffer) {
1270
+ return { __blob: Buffer.from(v).toString("base64") };
1271
+ }
1272
+ if (typeof v === "string" || typeof v === "number") return v;
1273
+ return String(v);
1274
+ }
1275
+ function deserializeValue(v) {
1276
+ if (v === null) return null;
1277
+ if (typeof v === "object" && v !== null && "__blob" in v) {
1278
+ const buf = Buffer.from(v.__blob, "base64");
1279
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
1280
+ }
1281
+ return v;
1282
+ }
1283
+ function deserializeResultSet(srs) {
1284
+ const rows = srs.rows.map((obj) => {
1285
+ const values = srs.columns.map(
1286
+ (col) => deserializeValue(obj[col] ?? null)
1287
+ );
1288
+ const row = values;
1289
+ for (let i = 0; i < srs.columns.length; i++) {
1290
+ const col = srs.columns[i];
1291
+ if (col !== void 0) {
1292
+ row[col] = values[i] ?? null;
1293
+ }
1294
+ }
1295
+ Object.defineProperty(row, "length", {
1296
+ value: values.length,
1297
+ enumerable: false
1298
+ });
1299
+ return row;
1300
+ });
1301
+ return {
1302
+ columns: srs.columns,
1303
+ columnTypes: srs.columnTypes ?? [],
1304
+ rows,
1305
+ rowsAffected: srs.rowsAffected,
1306
+ lastInsertRowid: srs.lastInsertRowid != null ? BigInt(srs.lastInsertRowid) : void 0,
1307
+ toJSON: () => ({
1308
+ columns: srs.columns,
1309
+ columnTypes: srs.columnTypes ?? [],
1310
+ rows: srs.rows,
1311
+ rowsAffected: srs.rowsAffected,
1312
+ lastInsertRowid: srs.lastInsertRowid
1313
+ })
1314
+ };
1315
+ }
1316
+ var init_daemon_protocol = __esm({
1317
+ "src/lib/daemon-protocol.ts"() {
1318
+ "use strict";
1319
+ }
1320
+ });
1321
+
1322
+ // src/lib/db-daemon-client.ts
1323
+ var db_daemon_client_exports = {};
1324
+ __export(db_daemon_client_exports, {
1325
+ createDaemonDbClient: () => createDaemonDbClient,
1326
+ initDaemonDbClient: () => initDaemonDbClient
1327
+ });
1328
+ function normalizeStatement2(stmt) {
1329
+ if (typeof stmt === "string") {
1330
+ return { sql: stmt, args: [] };
1331
+ }
1332
+ const sql = stmt.sql;
1333
+ let args = [];
1334
+ if (Array.isArray(stmt.args)) {
1335
+ args = stmt.args.map((v) => serializeValue(v));
1336
+ } else if (stmt.args && typeof stmt.args === "object") {
1337
+ const named = {};
1338
+ for (const [key, val] of Object.entries(stmt.args)) {
1339
+ named[key] = serializeValue(val);
1340
+ }
1341
+ return { sql, args: named };
1342
+ }
1343
+ return { sql, args };
1344
+ }
1345
+ function createDaemonDbClient(fallbackClient) {
1346
+ let _useDaemon = false;
1347
+ const client = {
1348
+ async execute(stmt) {
1349
+ if (!_useDaemon || !isClientConnected()) {
1350
+ return fallbackClient.execute(stmt);
1351
+ }
1352
+ const { sql, args } = normalizeStatement2(stmt);
1353
+ const response = await sendDaemonRequest({
1354
+ type: "db-execute",
1355
+ sql,
1356
+ args
1357
+ });
1358
+ if (response.error) {
1359
+ const errMsg = String(response.error);
1360
+ if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed" || errMsg === "DB not initialized") {
1361
+ process.stderr.write(`[db-daemon] Transport error (${errMsg}), falling back to direct
1362
+ `);
1363
+ return fallbackClient.execute(stmt);
1364
+ }
1365
+ throw new Error(errMsg);
1366
+ }
1367
+ if (response.db) {
1368
+ return deserializeResultSet(response.db);
1369
+ }
1370
+ process.stderr.write("[db-daemon] Unexpected response shape, falling back to direct\n");
1371
+ return fallbackClient.execute(stmt);
1372
+ },
1373
+ async batch(stmts, mode) {
1374
+ if (!_useDaemon || !isClientConnected()) {
1375
+ return fallbackClient.batch(stmts, mode);
1376
+ }
1377
+ const statements = stmts.map(normalizeStatement2);
1378
+ const response = await sendDaemonRequest({
1379
+ type: "db-batch",
1380
+ statements,
1381
+ mode: mode ?? "deferred"
1382
+ });
1383
+ if (response.error) {
1384
+ const errMsg = String(response.error);
1385
+ if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed" || errMsg === "DB not initialized") {
1386
+ process.stderr.write(`[db-daemon] Batch transport error (${errMsg}), falling back to direct
1387
+ `);
1388
+ return fallbackClient.batch(stmts, mode);
1389
+ }
1390
+ throw new Error(errMsg);
1391
+ }
1392
+ const batchResults = response["db-batch"];
1393
+ if (batchResults) {
1394
+ return batchResults.map(deserializeResultSet);
1395
+ }
1396
+ process.stderr.write("[db-daemon] Unexpected batch response shape, falling back to direct\n");
1397
+ return fallbackClient.batch(stmts, mode);
1398
+ },
1399
+ // Transaction support — delegate to fallback (transactions need direct connection)
1400
+ async transaction(mode) {
1401
+ return fallbackClient.transaction(mode);
1402
+ },
1403
+ // executeMultiple — delegate to fallback (used only for schema migrations)
1404
+ async executeMultiple(sql) {
1405
+ return fallbackClient.executeMultiple(sql);
1406
+ },
1407
+ // migrate — delegate to fallback
1408
+ async migrate(stmts) {
1409
+ return fallbackClient.migrate(stmts);
1410
+ },
1411
+ // Sync mode — delegate to fallback
1412
+ sync() {
1413
+ return fallbackClient.sync();
1414
+ },
1415
+ close() {
1416
+ _useDaemon = false;
1417
+ },
1418
+ get closed() {
1419
+ return fallbackClient.closed;
1420
+ },
1421
+ get protocol() {
1422
+ return fallbackClient.protocol;
1423
+ }
1424
+ };
1425
+ return {
1426
+ ...client,
1427
+ /** Enable daemon routing (call after confirming daemon is connected) */
1428
+ _enableDaemon() {
1429
+ _useDaemon = true;
1430
+ },
1431
+ /** Check if daemon routing is active */
1432
+ _isDaemonActive() {
1433
+ return _useDaemon && isClientConnected();
1434
+ }
1435
+ };
1436
+ }
1437
+ async function initDaemonDbClient(fallbackClient) {
1438
+ if (process.env.EXE_IS_DAEMON === "1") return null;
1439
+ const connected = await connectEmbedDaemon();
1440
+ if (!connected) {
1441
+ process.stderr.write("[db-daemon] Daemon unavailable \u2014 using direct SQLite\n");
1442
+ return null;
1443
+ }
1444
+ const client = createDaemonDbClient(fallbackClient);
1445
+ client._enableDaemon();
1446
+ process.stderr.write("[db-daemon] DB routing through daemon (single-writer)\n");
1447
+ return client;
1448
+ }
1449
+ var init_db_daemon_client = __esm({
1450
+ "src/lib/db-daemon-client.ts"() {
1451
+ "use strict";
1452
+ init_exe_daemon_client();
1453
+ init_daemon_protocol();
1454
+ }
1455
+ });
1456
+
910
1457
  // src/lib/database.ts
1458
+ var database_exports = {};
1459
+ __export(database_exports, {
1460
+ disposeDatabase: () => disposeDatabase,
1461
+ disposeTurso: () => disposeTurso,
1462
+ ensureSchema: () => ensureSchema,
1463
+ getClient: () => getClient,
1464
+ getRawClient: () => getRawClient,
1465
+ initDaemonClient: () => initDaemonClient,
1466
+ initDatabase: () => initDatabase,
1467
+ initTurso: () => initTurso,
1468
+ isInitialized: () => isInitialized
1469
+ });
911
1470
  import { createClient } from "@libsql/client";
912
1471
  async function initDatabase(config) {
913
1472
  if (_walCheckpointTimer) {
@@ -946,15 +1505,18 @@ async function initDatabase(config) {
946
1505
  });
947
1506
  }, 3e4);
948
1507
  _walCheckpointTimer.unref();
949
- if (process.env.DATABASE_URL) {
1508
+ if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
950
1509
  _adapterClient = await createPrismaDbAdapter(_resilientClient);
951
1510
  }
952
1511
  }
1512
+ function isInitialized() {
1513
+ return _adapterClient !== null || _client !== null;
1514
+ }
953
1515
  function getClient() {
954
1516
  if (!_adapterClient) {
955
1517
  throw new Error("Database client not initialized. Call initDatabase() first.");
956
1518
  }
957
- if (process.env.DATABASE_URL) {
1519
+ if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
958
1520
  return _adapterClient;
959
1521
  }
960
1522
  if (process.env.EXE_IS_DAEMON === "1") {
@@ -965,6 +1527,22 @@ function getClient() {
965
1527
  }
966
1528
  return _resilientClient;
967
1529
  }
1530
+ async function initDaemonClient() {
1531
+ if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") return;
1532
+ if (process.env.EXE_IS_DAEMON === "1") return;
1533
+ if (process.env.VITEST) return;
1534
+ if (!_resilientClient) return;
1535
+ if (_daemonClient) return;
1536
+ try {
1537
+ const { initDaemonDbClient: initDaemonDbClient2 } = await Promise.resolve().then(() => (init_db_daemon_client(), db_daemon_client_exports));
1538
+ _daemonClient = await initDaemonDbClient2(_resilientClient);
1539
+ } catch (err) {
1540
+ process.stderr.write(
1541
+ `[database] Daemon client init failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
1542
+ `
1543
+ );
1544
+ }
1545
+ }
968
1546
  function getRawClient() {
969
1547
  if (!_client) {
970
1548
  throw new Error("Database client not initialized. Call initDatabase() first.");
@@ -1103,6 +1681,13 @@ async function ensureSchema() {
1103
1681
  });
1104
1682
  } catch {
1105
1683
  }
1684
+ try {
1685
+ await client.execute({
1686
+ sql: `ALTER TABLE behaviors ADD COLUMN vector F32_BLOB(${EMBEDDING_DIM})`,
1687
+ args: []
1688
+ });
1689
+ } catch {
1690
+ }
1106
1691
  try {
1107
1692
  await client.execute({
1108
1693
  sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
@@ -1973,6 +2558,7 @@ var init_database = __esm({
1973
2558
  init_db_retry();
1974
2559
  init_employees();
1975
2560
  init_database_adapter();
2561
+ init_memory();
1976
2562
  _client = null;
1977
2563
  _resilientClient = null;
1978
2564
  _walCheckpointTimer = null;
@@ -1997,12 +2583,12 @@ __export(shard_manager_exports, {
1997
2583
  listShards: () => listShards,
1998
2584
  shardExists: () => shardExists
1999
2585
  });
2000
- import path5 from "path";
2001
- import { existsSync as existsSync5, mkdirSync as mkdirSync2, readdirSync } from "fs";
2586
+ import path7 from "path";
2587
+ import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync } from "fs";
2002
2588
  import { createClient as createClient2 } from "@libsql/client";
2003
2589
  function initShardManager(encryptionKey) {
2004
2590
  _encryptionKey = encryptionKey;
2005
- if (!existsSync5(SHARDS_DIR)) {
2591
+ if (!existsSync7(SHARDS_DIR)) {
2006
2592
  mkdirSync2(SHARDS_DIR, { recursive: true });
2007
2593
  }
2008
2594
  _shardingEnabled = true;
@@ -2032,7 +2618,7 @@ function getShardClient(projectName) {
2032
2618
  while (_shards.size >= MAX_OPEN_SHARDS) {
2033
2619
  evictLRU();
2034
2620
  }
2035
- const dbPath = path5.join(SHARDS_DIR, `${safeName}.db`);
2621
+ const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
2036
2622
  const client = createClient2({
2037
2623
  url: `file:${dbPath}`,
2038
2624
  encryptionKey: _encryptionKey
@@ -2043,10 +2629,10 @@ function getShardClient(projectName) {
2043
2629
  }
2044
2630
  function shardExists(projectName) {
2045
2631
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2046
- return existsSync5(path5.join(SHARDS_DIR, `${safeName}.db`));
2632
+ return existsSync7(path7.join(SHARDS_DIR, `${safeName}.db`));
2047
2633
  }
2048
2634
  function listShards() {
2049
- if (!existsSync5(SHARDS_DIR)) return [];
2635
+ if (!existsSync7(SHARDS_DIR)) return [];
2050
2636
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
2051
2637
  }
2052
2638
  async function ensureShardSchema(client) {
@@ -2293,7 +2879,7 @@ var init_shard_manager = __esm({
2293
2879
  "src/lib/shard-manager.ts"() {
2294
2880
  "use strict";
2295
2881
  init_config();
2296
- SHARDS_DIR = path5.join(EXE_AI_DIR, "shards");
2882
+ SHARDS_DIR = path7.join(EXE_AI_DIR, "shards");
2297
2883
  SHARD_IDLE_MS = 5 * 60 * 1e3;
2298
2884
  MAX_OPEN_SHARDS = 10;
2299
2885
  EVICTION_INTERVAL_MS = 60 * 1e3;
@@ -2413,6 +2999,68 @@ var init_platform_procedures = __esm({
2413
2999
  domain: "architecture",
2414
3000
  priority: "p0",
2415
3001
  content: "Tasks live in the DB. Intercom (tmux send-keys) is fire-and-forget \u2014 it may fail, get garbled, or arrive mid-work. Never rely on intercom for task delivery. The UserPromptSubmit hook checks the DB for new tasks on every prompt. Your operating procedures step 7 says check for next work. The daemon nudges idle agents as a speedup. If you have no tasks, you found them all."
3002
+ },
3003
+ // --- MCP is the ONLY data interface ---
3004
+ {
3005
+ title: "MCP disconnect \u2014 ask the user, never work around it",
3006
+ domain: "workflow",
3007
+ priority: "p0",
3008
+ content: "If MCP tools are unavailable, disconnected, or returning connection errors: STOP. Tell the user clearly: 'MCP server is disconnected. Please run /mcp to reconnect.' Do NOT attempt workarounds \u2014 no raw Node imports, no direct DB access, no CLI hacks, no daemon socket calls. MCP is the ONLY data interface. Working around it wastes time, hits bundling issues, and bypasses the contract boundary. Ask once, wait, proceed when reconnected."
3009
+ },
3010
+ // --- MCP Tool Catalog (Layer 0 — every agent knows what tools exist) ---
3011
+ {
3012
+ title: "MCP tools \u2014 memory and search",
3013
+ domain: "tool-use",
3014
+ priority: "p1",
3015
+ content: "recall_my_memory: search your own memories (semantic + FTS). ask_team_memory: search a colleague's memories by agent name. store_memory: persist a memory (decisions, summaries, context). commit_memory: high-importance memory that survives consolidation. search_everything: unified search across memories, tasks, entities, conversations. get_session_context: temporal window of memories around a timestamp. consolidate_memories: merge duplicate/related memories into insights. get_memory_cardinality: count memories per agent (health check)."
3016
+ },
3017
+ {
3018
+ title: "MCP tools \u2014 task orchestration",
3019
+ domain: "tool-use",
3020
+ priority: "p1",
3021
+ content: "create_task: dispatch work to an employee (auto-spawns session). The ONLY dispatch path. list_tasks: query tasks by status, assignee, project. get_task: fetch full task details by ID. update_task: change status (in_progress, done, blocked, cancelled) + add result summary. close_task: finalize a reviewed task (COO only). checkpoint_task: save progress state for crash recovery. resume_employee: re-spawn an employee session for an existing task."
3022
+ },
3023
+ {
3024
+ title: "MCP tools \u2014 knowledge graph (GraphRAG)",
3025
+ domain: "tool-use",
3026
+ priority: "p1",
3027
+ content: "query_relationships: find connections between entities in the knowledge graph. get_entity_neighbors: explore an entity's direct connections. get_hot_entities: find most-referenced entities (trending topics). get_graph_stats: graph health \u2014 entity/relationship counts, density. export_graph: export graph data for visualization. merge_entities: deduplicate entities (alias resolution). find_similar_trajectories: match tool-call patterns to past task solutions."
3028
+ },
3029
+ {
3030
+ title: "MCP tools \u2014 identity, behavior, and decisions",
3031
+ domain: "tool-use",
3032
+ priority: "p1",
3033
+ content: "get_identity: read an agent's exe.md (Layer 1 identity). update_identity: write an agent's exe.md. Identity > behavior \u2014 use for permanent rules. store_behavior: record a correction or pattern for an agent (Layer 2 expertise). list_behaviors: view an agent's active behaviors. deactivate_behavior: soft-delete a stale or conflicting behavior. store_decision: record an ADR (architectural decision record). get_decision: retrieve a past decision by query."
3034
+ },
3035
+ {
3036
+ title: "MCP tools \u2014 communication and messaging",
3037
+ domain: "tool-use",
3038
+ priority: "p1",
3039
+ content: "send_message: send supplementary context to another agent (NOT for actionable work \u2014 use create_task). acknowledge_messages: mark messages as read. send_whatsapp: send WhatsApp message via gateway (customer-facing alerts). query_conversations: search ingested conversations across all channels (WhatsApp, email, etc.)."
3040
+ },
3041
+ {
3042
+ title: "MCP tools \u2014 wiki, documents, and content",
3043
+ domain: "tool-use",
3044
+ priority: "p1",
3045
+ content: "create_wiki_page: create a wiki page in exe-wiki. list_wiki_pages: browse wiki pages. get_wiki_page: read a wiki page. update_wiki_page: edit a wiki page. ingest_document: import a file (PDF, MD, etc.) into memory as chunks. list_documents: browse ingested documents by workspace. purge_document: remove a document and its memory chunks. set_document_importance: adjust chunk importance scores. rerank_documents: re-score document relevance for a query."
3046
+ },
3047
+ {
3048
+ title: "MCP tools \u2014 system, operations, and admin",
3049
+ domain: "tool-use",
3050
+ priority: "p1",
3051
+ content: "get_agent_spend: token usage per agent/session (cost tracking). list_agent_sessions: view agent session history. get_session_kills: audit log of killed sessions. get_daemon_health: check exed daemon status. get_auto_wake_status: daemon auto-wake configuration. get_worker_gate: check worker deployment gates. run_memory_audit: health check \u2014 duplicates, null vectors, orphaned rows. run_consolidation: trigger sleep-time memory consolidation. cloud_sync: force a cloud sync cycle. backup_vps: trigger VPS backup."
3052
+ },
3053
+ {
3054
+ title: "MCP tools \u2014 config, licensing, and team",
3055
+ domain: "tool-use",
3056
+ priority: "p1",
3057
+ content: "set_agent_config: view/change per-agent runtime and model settings. list_employees: view the employee roster. add_person: add a person to the CRM contacts roster. list_people: browse CRM contacts. get_person: fetch contact details. get_license_status: check license validity. create_license: generate a new license key (admin). list_licenses: view all issued licenses. activate_license: activate a license on a device."
3058
+ },
3059
+ {
3060
+ title: "MCP tools \u2014 advanced (triggers, skills, orchestration)",
3061
+ domain: "tool-use",
3062
+ priority: "p1",
3063
+ content: "create_trigger: set up a scheduled recurring agent job (cron). list_triggers: view active triggers. load_skill: load a slash-command skill dynamically. apply_starter_pack: import a pre-built behavior + identity pack for a role. export_orchestration: export full org state (tasks, behaviors, identities) as portable JSON. import_orchestration: import org state into a new instance. deploy_client: deploy a customer client instance. query_company_brain: unified RAG query across all company knowledge. create_reminder: set a text reminder (shown in boot brief). list_reminders: view pending reminders. complete_reminder: mark a reminder done. global_procedure: manage Layer 0 procedures (actions: store, list, deactivate). Legacy aliases: store_global_procedure, list_global_procedures, deactivate_global_procedure."
2416
3064
  }
2417
3065
  ];
2418
3066
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -2429,7 +3077,7 @@ __export(global_procedures_exports, {
2429
3077
  loadGlobalProcedures: () => loadGlobalProcedures,
2430
3078
  storeGlobalProcedure: () => storeGlobalProcedure
2431
3079
  });
2432
- import { randomUUID } from "crypto";
3080
+ import { randomUUID as randomUUID2 } from "crypto";
2433
3081
  async function loadGlobalProcedures() {
2434
3082
  const client = getClient();
2435
3083
  const result = await client.execute({
@@ -2458,7 +3106,7 @@ ${sections.join("\n\n")}
2458
3106
  `;
2459
3107
  }
2460
3108
  async function storeGlobalProcedure(input) {
2461
- const id = randomUUID();
3109
+ const id = randomUUID2();
2462
3110
  const now = (/* @__PURE__ */ new Date()).toISOString();
2463
3111
  const client = getClient();
2464
3112
  await client.execute({
@@ -2596,9 +3244,9 @@ __export(active_agent_exports, {
2596
3244
  resolveActiveAgentFromTmuxSession: () => resolveActiveAgentFromTmuxSession,
2597
3245
  writeActiveAgent: () => writeActiveAgent
2598
3246
  });
2599
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, unlinkSync as unlinkSync3, readdirSync as readdirSync3 } from "fs";
3247
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, unlinkSync as unlinkSync4, readdirSync as readdirSync3 } from "fs";
2600
3248
  import { execSync as execSync3 } from "child_process";
2601
- import path7 from "path";
3249
+ import path9 from "path";
2602
3250
  function isNameWithOptionalInstance(candidate, baseName) {
2603
3251
  if (candidate === baseName) return true;
2604
3252
  if (!candidate.startsWith(baseName)) return false;
@@ -2642,12 +3290,12 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
2642
3290
  return null;
2643
3291
  }
2644
3292
  function getMarkerPath() {
2645
- return path7.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
3293
+ return path9.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
2646
3294
  }
2647
3295
  function writeActiveAgent(agentId, agentRole) {
2648
3296
  try {
2649
3297
  mkdirSync4(CACHE_DIR, { recursive: true });
2650
- writeFileSync3(
3298
+ writeFileSync4(
2651
3299
  getMarkerPath(),
2652
3300
  JSON.stringify({ agentId, agentRole, startedAt: (/* @__PURE__ */ new Date()).toISOString() })
2653
3301
  );
@@ -2656,21 +3304,21 @@ function writeActiveAgent(agentId, agentRole) {
2656
3304
  }
2657
3305
  function clearActiveAgent() {
2658
3306
  try {
2659
- unlinkSync3(getMarkerPath());
3307
+ unlinkSync4(getMarkerPath());
2660
3308
  } catch {
2661
3309
  }
2662
3310
  }
2663
3311
  function getActiveAgent() {
2664
3312
  try {
2665
3313
  const markerPath = getMarkerPath();
2666
- const raw = readFileSync3(markerPath, "utf8");
3314
+ const raw = readFileSync5(markerPath, "utf8");
2667
3315
  const data = JSON.parse(raw);
2668
3316
  if (data.agentId) {
2669
3317
  if (data.startedAt) {
2670
3318
  const age = Date.now() - new Date(data.startedAt).getTime();
2671
3319
  if (age > STALE_MS) {
2672
3320
  try {
2673
- unlinkSync3(markerPath);
3321
+ unlinkSync4(markerPath);
2674
3322
  } catch {
2675
3323
  }
2676
3324
  } else {
@@ -2711,14 +3359,14 @@ function getAllActiveAgents() {
2711
3359
  const key = file.slice("active-agent-".length, -".json".length);
2712
3360
  if (key === "undefined") continue;
2713
3361
  try {
2714
- const raw = readFileSync3(path7.join(CACHE_DIR, file), "utf8");
3362
+ const raw = readFileSync5(path9.join(CACHE_DIR, file), "utf8");
2715
3363
  const data = JSON.parse(raw);
2716
3364
  if (!data.agentId) continue;
2717
3365
  if (data.startedAt) {
2718
3366
  const age = Date.now() - new Date(data.startedAt).getTime();
2719
3367
  if (age > STALE_MS) {
2720
3368
  try {
2721
- unlinkSync3(path7.join(CACHE_DIR, file));
3369
+ unlinkSync4(path9.join(CACHE_DIR, file));
2722
3370
  } catch {
2723
3371
  }
2724
3372
  continue;
@@ -2741,11 +3389,11 @@ function getAllActiveAgents() {
2741
3389
  function cleanupSessionMarkers() {
2742
3390
  const key = getSessionKey();
2743
3391
  try {
2744
- unlinkSync3(path7.join(CACHE_DIR, `active-agent-${key}.json`));
3392
+ unlinkSync4(path9.join(CACHE_DIR, `active-agent-${key}.json`));
2745
3393
  } catch {
2746
3394
  }
2747
3395
  try {
2748
- unlinkSync3(path7.join(CACHE_DIR, "active-agent-undefined.json"));
3396
+ unlinkSync4(path9.join(CACHE_DIR, "active-agent-undefined.json"));
2749
3397
  } catch {
2750
3398
  }
2751
3399
  }
@@ -2756,16 +3404,16 @@ var init_active_agent = __esm({
2756
3404
  init_config();
2757
3405
  init_session_key();
2758
3406
  init_employees();
2759
- CACHE_DIR = path7.join(EXE_AI_DIR, "session-cache");
3407
+ CACHE_DIR = path9.join(EXE_AI_DIR, "session-cache");
2760
3408
  STALE_MS = 24 * 60 * 60 * 1e3;
2761
3409
  }
2762
3410
  });
2763
3411
 
2764
3412
  // src/lib/agent-symlinks.ts
2765
- import os6 from "os";
2766
- import path8 from "path";
3413
+ import os7 from "os";
3414
+ import path10 from "path";
2767
3415
  import {
2768
- existsSync as existsSync7,
3416
+ existsSync as existsSync9,
2769
3417
  lstatSync,
2770
3418
  mkdirSync as mkdirSync5,
2771
3419
  readlinkSync as readlinkSync2,
@@ -2793,9 +3441,9 @@ var init_mcp_prefix = __esm({
2793
3441
  });
2794
3442
 
2795
3443
  // src/lib/preferences.ts
2796
- import { existsSync as existsSync8, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
2797
- import path9 from "path";
2798
- import os7 from "os";
3444
+ import { existsSync as existsSync10, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
3445
+ import path11 from "path";
3446
+ import os8 from "os";
2799
3447
  var init_preferences = __esm({
2800
3448
  "src/lib/preferences.ts"() {
2801
3449
  "use strict";
@@ -2805,27 +3453,27 @@ var init_preferences = __esm({
2805
3453
 
2806
3454
  // src/adapters/claude/installer.ts
2807
3455
  import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, readdir } from "fs/promises";
2808
- import { existsSync as existsSync9, readFileSync as readFileSync5, writeFileSync as writeFileSync5, copyFileSync, mkdirSync as mkdirSync6 } from "fs";
2809
- import path10 from "path";
2810
- import os8 from "os";
3456
+ import { existsSync as existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync6, copyFileSync, mkdirSync as mkdirSync6 } from "fs";
3457
+ import path12 from "path";
3458
+ import os9 from "os";
2811
3459
  import { execSync as execSync4 } from "child_process";
2812
- import { fileURLToPath } from "url";
3460
+ import { fileURLToPath as fileURLToPath2 } from "url";
2813
3461
  function resolvePackageRoot() {
2814
- const thisFile = fileURLToPath(import.meta.url);
2815
- let dir = path10.dirname(thisFile);
2816
- const root = path10.parse(dir).root;
3462
+ const thisFile = fileURLToPath2(import.meta.url);
3463
+ let dir = path12.dirname(thisFile);
3464
+ const root = path12.parse(dir).root;
2817
3465
  while (dir !== root) {
2818
- const pkgPath = path10.join(dir, "package.json");
2819
- if (existsSync9(pkgPath)) {
3466
+ const pkgPath = path12.join(dir, "package.json");
3467
+ if (existsSync11(pkgPath)) {
2820
3468
  try {
2821
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
3469
+ const pkg = JSON.parse(readFileSync7(pkgPath, "utf-8"));
2822
3470
  if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
2823
3471
  } catch {
2824
3472
  }
2825
3473
  }
2826
- dir = path10.dirname(dir);
3474
+ dir = path12.dirname(dir);
2827
3475
  }
2828
- return path10.resolve(path10.dirname(thisFile), "..", "..", "..");
3476
+ return path12.resolve(path12.dirname(thisFile), "..", "..", "..");
2829
3477
  }
2830
3478
  var EXE_SECTION_START, EXE_SECTION_END, ORCHESTRATION_RULES;
2831
3479
  var init_installer = __esm({
@@ -3043,15 +3691,15 @@ __export(installer_exports, {
3043
3691
  verifyOpenCodeHooks: () => verifyOpenCodeHooks
3044
3692
  });
3045
3693
  import { readFile as readFile5, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
3046
- import { existsSync as existsSync10, readFileSync as readFileSync6 } from "fs";
3047
- import path11 from "path";
3048
- import os9 from "os";
3049
- async function registerOpenCodeMcp(packageRoot, homeDir = os9.homedir()) {
3050
- const configDir = path11.join(homeDir, ".config", "opencode");
3051
- const configPath = path11.join(configDir, "opencode.json");
3694
+ import { existsSync as existsSync12, readFileSync as readFileSync8 } from "fs";
3695
+ import path13 from "path";
3696
+ import os10 from "os";
3697
+ async function registerOpenCodeMcp(packageRoot, homeDir = os10.homedir()) {
3698
+ const configDir = path13.join(homeDir, ".config", "opencode");
3699
+ const configPath = path13.join(configDir, "opencode.json");
3052
3700
  await mkdir5(configDir, { recursive: true });
3053
3701
  let config = {};
3054
- if (existsSync10(configPath)) {
3702
+ if (existsSync12(configPath)) {
3055
3703
  try {
3056
3704
  config = JSON.parse(await readFile5(configPath, "utf-8"));
3057
3705
  } catch {
@@ -3063,7 +3711,7 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os9.homedir()) {
3063
3711
  }
3064
3712
  const newEntry = {
3065
3713
  type: "local",
3066
- command: ["node", path11.join(packageRoot, "dist", "mcp", "server.js")],
3714
+ command: ["node", path13.join(packageRoot, "dist", "mcp", "server.js")],
3067
3715
  enabled: true
3068
3716
  };
3069
3717
  const current = config.mcp["exe-os"];
@@ -3077,15 +3725,15 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os9.homedir()) {
3077
3725
  await writeFile5(configPath, JSON.stringify(config, null, 2) + "\n");
3078
3726
  return true;
3079
3727
  }
3080
- async function installOpenCodePlugin(packageRoot, homeDir = os9.homedir()) {
3081
- const pluginDir = path11.join(homeDir, ".config", "opencode", "plugins");
3082
- const pluginPath = path11.join(pluginDir, "exe-os.mjs");
3728
+ async function installOpenCodePlugin(packageRoot, homeDir = os10.homedir()) {
3729
+ const pluginDir = path13.join(homeDir, ".config", "opencode", "plugins");
3730
+ const pluginPath = path13.join(pluginDir, "exe-os.mjs");
3083
3731
  await mkdir5(pluginDir, { recursive: true });
3084
3732
  const pluginContent = PLUGIN_TEMPLATE.replace(
3085
3733
  /__PACKAGE_ROOT__/g,
3086
3734
  packageRoot.replace(/\\/g, "\\\\")
3087
3735
  );
3088
- if (existsSync10(pluginPath)) {
3736
+ if (existsSync12(pluginPath)) {
3089
3737
  const existing = await readFile5(pluginPath, "utf-8");
3090
3738
  if (existing === pluginContent) {
3091
3739
  return false;
@@ -3094,17 +3742,17 @@ async function installOpenCodePlugin(packageRoot, homeDir = os9.homedir()) {
3094
3742
  await writeFile5(pluginPath, pluginContent);
3095
3743
  return true;
3096
3744
  }
3097
- function verifyOpenCodeHooks(homeDir = os9.homedir()) {
3098
- const configPath = path11.join(homeDir, ".config", "opencode", "opencode.json");
3099
- const pluginPath = path11.join(homeDir, ".config", "opencode", "plugins", "exe-os.mjs");
3100
- if (!existsSync10(configPath)) return false;
3745
+ function verifyOpenCodeHooks(homeDir = os10.homedir()) {
3746
+ const configPath = path13.join(homeDir, ".config", "opencode", "opencode.json");
3747
+ const pluginPath = path13.join(homeDir, ".config", "opencode", "plugins", "exe-os.mjs");
3748
+ if (!existsSync12(configPath)) return false;
3101
3749
  try {
3102
- const config = JSON.parse(readFileSync6(configPath, "utf-8"));
3750
+ const config = JSON.parse(readFileSync8(configPath, "utf-8"));
3103
3751
  if (!config.mcp?.["exe-os"]?.enabled) return false;
3104
3752
  } catch {
3105
3753
  return false;
3106
3754
  }
3107
- if (!existsSync10(pluginPath)) return false;
3755
+ if (!existsSync12(pluginPath)) return false;
3108
3756
  return true;
3109
3757
  }
3110
3758
  async function runOpenCodeInstaller(homeDir) {
@@ -3129,33 +3777,34 @@ var init_installer2 = __esm({
3129
3777
  });
3130
3778
 
3131
3779
  // src/bin/exe-start-opencode.ts
3132
- import os10 from "os";
3133
- import path12 from "path";
3780
+ import os11 from "os";
3781
+ import path14 from "path";
3134
3782
  import {
3135
- existsSync as existsSync11,
3136
- readFileSync as readFileSync7,
3137
- writeFileSync as writeFileSync6,
3783
+ existsSync as existsSync13,
3784
+ readFileSync as readFileSync9,
3785
+ writeFileSync as writeFileSync7,
3138
3786
  mkdirSync as mkdirSync7,
3139
3787
  readdirSync as readdirSync4
3140
3788
  } from "fs";
3141
3789
  import { spawnSync } from "child_process";
3142
3790
 
3143
3791
  // src/lib/store.ts
3144
- import { createHash } from "crypto";
3792
+ init_memory();
3145
3793
  init_database();
3794
+ import { createHash } from "crypto";
3146
3795
 
3147
3796
  // src/lib/keychain.ts
3148
3797
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3149
- import { existsSync as existsSync4 } from "fs";
3150
- import path4 from "path";
3151
- import os4 from "os";
3798
+ import { existsSync as existsSync6 } from "fs";
3799
+ import path6 from "path";
3800
+ import os5 from "os";
3152
3801
  var SERVICE = "exe-mem";
3153
3802
  var ACCOUNT = "master-key";
3154
3803
  function getKeyDir() {
3155
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path4.join(os4.homedir(), ".exe-os");
3804
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path6.join(os5.homedir(), ".exe-os");
3156
3805
  }
3157
3806
  function getKeyPath() {
3158
- return path4.join(getKeyDir(), "master.key");
3807
+ return path6.join(getKeyDir(), "master.key");
3159
3808
  }
3160
3809
  async function tryKeytar() {
3161
3810
  try {
@@ -3176,9 +3825,9 @@ async function getMasterKey() {
3176
3825
  }
3177
3826
  }
3178
3827
  const keyPath = getKeyPath();
3179
- if (!existsSync4(keyPath)) {
3828
+ if (!existsSync6(keyPath)) {
3180
3829
  process.stderr.write(
3181
- `[keychain] Key not found at ${keyPath} (HOME=${os4.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
3830
+ `[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
3182
3831
  `
3183
3832
  );
3184
3833
  return null;
@@ -3307,6 +3956,11 @@ async function initStore(options) {
3307
3956
  encryptionKey: hexKey
3308
3957
  });
3309
3958
  await retryOnBusy2(() => ensureSchema(), "ensureSchema");
3959
+ try {
3960
+ const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
3961
+ await initDaemonClient2();
3962
+ } catch {
3963
+ }
3310
3964
  if (!options?.lightweight) {
3311
3965
  try {
3312
3966
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
@@ -3489,24 +4143,24 @@ function vectorToBlob(vector) {
3489
4143
  }
3490
4144
 
3491
4145
  // src/lib/behaviors-export.ts
3492
- import os5 from "os";
3493
- import path6 from "path";
4146
+ import os6 from "os";
4147
+ import path8 from "path";
3494
4148
  import {
3495
- existsSync as existsSync6,
4149
+ existsSync as existsSync8,
3496
4150
  mkdirSync as mkdirSync3,
3497
4151
  readdirSync as readdirSync2,
3498
- statSync,
3499
- unlinkSync as unlinkSync2,
3500
- writeFileSync as writeFileSync2
4152
+ statSync as statSync2,
4153
+ unlinkSync as unlinkSync3,
4154
+ writeFileSync as writeFileSync3
3501
4155
  } from "fs";
3502
4156
 
3503
4157
  // src/lib/behaviors.ts
3504
4158
  init_database();
3505
- import crypto from "crypto";
4159
+ import crypto2 from "crypto";
3506
4160
  async function listBehaviors(agentId, projectName, limit = 30) {
3507
4161
  const client = getClient();
3508
4162
  const result = await client.execute({
3509
- sql: `SELECT id, agent_id, project_name, domain, priority, content, active, created_at, updated_at
4163
+ sql: `SELECT id, agent_id, project_name, domain, priority, content, active, created_at, updated_at, vector
3510
4164
  FROM behaviors
3511
4165
  WHERE agent_id = ? AND active = 1
3512
4166
  AND (project_name IS NULL OR project_name = ?)
@@ -3527,20 +4181,21 @@ async function listBehaviors(agentId, projectName, limit = 30) {
3527
4181
  content: String(r.content),
3528
4182
  active: Number(r.active),
3529
4183
  created_at: String(r.created_at),
3530
- updated_at: String(r.updated_at)
4184
+ updated_at: String(r.updated_at),
4185
+ vector: r.vector ? Array.from(new Float32Array(r.vector)) : null
3531
4186
  }));
3532
4187
  }
3533
4188
 
3534
4189
  // src/lib/behaviors-export.ts
3535
- var BEHAVIORS_EXPORT_DIR = path6.join(
3536
- os5.homedir(),
4190
+ var BEHAVIORS_EXPORT_DIR = path8.join(
4191
+ os6.homedir(),
3537
4192
  ".exe-os",
3538
4193
  "behaviors-export"
3539
4194
  );
3540
4195
  var STALE_EXPORT_AGE_MS = 60 * 60 * 1e3;
3541
4196
  var EXPORT_BEHAVIOR_LIMIT = 30;
3542
4197
  function sweepStaleBehaviorExports(now = Date.now()) {
3543
- if (!existsSync6(BEHAVIORS_EXPORT_DIR)) return;
4198
+ if (!existsSync8(BEHAVIORS_EXPORT_DIR)) return;
3544
4199
  let entries;
3545
4200
  try {
3546
4201
  entries = readdirSync2(BEHAVIORS_EXPORT_DIR);
@@ -3548,11 +4203,11 @@ function sweepStaleBehaviorExports(now = Date.now()) {
3548
4203
  return;
3549
4204
  }
3550
4205
  for (const entry of entries) {
3551
- const filePath = path6.join(BEHAVIORS_EXPORT_DIR, entry);
4206
+ const filePath = path8.join(BEHAVIORS_EXPORT_DIR, entry);
3552
4207
  try {
3553
- const stat = statSync(filePath);
4208
+ const stat = statSync2(filePath);
3554
4209
  if (now - stat.mtimeMs > STALE_EXPORT_AGE_MS) {
3555
- unlinkSync2(filePath);
4210
+ unlinkSync3(filePath);
3556
4211
  }
3557
4212
  } catch {
3558
4213
  }
@@ -3581,10 +4236,10 @@ function renderBehaviorExport(behaviors) {
3581
4236
  }
3582
4237
  function exportFilePath(agentId, projectName, sessionKey) {
3583
4238
  if (!sessionKey) {
3584
- return path6.join(BEHAVIORS_EXPORT_DIR, `${agentId}.md`);
4239
+ return path8.join(BEHAVIORS_EXPORT_DIR, `${agentId}.md`);
3585
4240
  }
3586
4241
  const safeProject = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3587
- return path6.join(
4242
+ return path8.join(
3588
4243
  BEHAVIORS_EXPORT_DIR,
3589
4244
  `${agentId}-${safeProject}-${sessionKey}.md`
3590
4245
  );
@@ -3596,7 +4251,7 @@ async function exportBehaviorsForAgent(agentId, projectName, sessionKey) {
3596
4251
  if (behaviors.length === 0) return null;
3597
4252
  const body = renderBehaviorExport(behaviors);
3598
4253
  const target = exportFilePath(agentId, projectName, sessionKey);
3599
- writeFileSync2(target, body, "utf-8");
4254
+ writeFileSync3(target, body, "utf-8");
3600
4255
  return target;
3601
4256
  }
3602
4257
 
@@ -3613,7 +4268,7 @@ When done with a task: call update_task with status "done".
3613
4268
  Always call store_memory to persist important findings.
3614
4269
  `;
3615
4270
  function resolveAgent(argv) {
3616
- const invokedAs = path12.basename(argv[1] ?? "");
4271
+ const invokedAs = path14.basename(argv[1] ?? "");
3617
4272
  if (invokedAs && invokedAs !== "exe-start-opencode" && !invokedAs.endsWith(".js")) {
3618
4273
  const agent2 = invokedAs.replace(/-opencode$/, "").toLowerCase();
3619
4274
  return { agent: agent2, passthrough: argv.slice(2) };
@@ -3630,24 +4285,24 @@ function resolveAgent(argv) {
3630
4285
  return { agent, passthrough };
3631
4286
  }
3632
4287
  function loadIdentity(agent) {
3633
- const dir = path12.join(os10.homedir(), ".exe-os", "identity");
3634
- const exact = path12.join(dir, `${agent}.md`);
3635
- if (existsSync11(exact)) {
3636
- const content = readFileSync7(exact, "utf-8").trim();
4288
+ const dir = path14.join(os11.homedir(), ".exe-os", "identity");
4289
+ const exact = path14.join(dir, `${agent}.md`);
4290
+ if (existsSync13(exact)) {
4291
+ const content = readFileSync9(exact, "utf-8").trim();
3637
4292
  if (content) return content;
3638
4293
  }
3639
4294
  try {
3640
4295
  const files = readdirSync4(dir);
3641
4296
  const match = files.find((f) => f.toLowerCase() === `${agent.toLowerCase()}.md`);
3642
4297
  if (match) {
3643
- const content = readFileSync7(path12.join(dir, match), "utf-8").trim();
4298
+ const content = readFileSync9(path14.join(dir, match), "utf-8").trim();
3644
4299
  if (content) return content;
3645
4300
  }
3646
4301
  } catch {
3647
4302
  }
3648
4303
  try {
3649
- const rosterPath = path12.join(os10.homedir(), ".exe-os", "exe-employees.json");
3650
- const roster = JSON.parse(readFileSync7(rosterPath, "utf8"));
4304
+ const rosterPath = path14.join(os11.homedir(), ".exe-os", "exe-employees.json");
4305
+ const roster = JSON.parse(readFileSync9(rosterPath, "utf8"));
3651
4306
  const emp = roster.find((e) => e.name.toLowerCase() === agent.toLowerCase());
3652
4307
  if (emp?.systemPrompt && emp.systemPrompt.trim().length > 20) {
3653
4308
  return emp.systemPrompt;
@@ -3657,18 +4312,18 @@ function loadIdentity(agent) {
3657
4312
  return null;
3658
4313
  }
3659
4314
  function writeAgentFile(agent, identity, behaviorsPath) {
3660
- const agentDir = path12.join(os10.homedir(), ".config", "opencode", "agents");
4315
+ const agentDir = path14.join(os11.homedir(), ".config", "opencode", "agents");
3661
4316
  mkdirSync7(agentDir, { recursive: true });
3662
4317
  let content = identity;
3663
- if (behaviorsPath && existsSync11(behaviorsPath)) {
3664
- const behaviors = readFileSync7(behaviorsPath, "utf-8").trim();
4318
+ if (behaviorsPath && existsSync13(behaviorsPath)) {
4319
+ const behaviors = readFileSync9(behaviorsPath, "utf-8").trim();
3665
4320
  if (behaviors) {
3666
4321
  content += "\n\n" + behaviors;
3667
4322
  }
3668
4323
  }
3669
4324
  content += "\n" + BOOT_INSTRUCTIONS;
3670
- const outPath = path12.join(agentDir, `${agent}.md`);
3671
- writeFileSync6(outPath, content, "utf-8");
4325
+ const outPath = path14.join(agentDir, `${agent}.md`);
4326
+ writeFileSync7(outPath, content, "utf-8");
3672
4327
  return outPath;
3673
4328
  }
3674
4329
  async function main() {
@@ -3729,8 +4384,8 @@ async function main() {
3729
4384
  process.env.EXE_RUNTIME = "opencode";
3730
4385
  const empRole = (() => {
3731
4386
  try {
3732
- const emps = readFileSync7(
3733
- path12.join(os10.homedir(), ".exe-os", "exe-employees.json"),
4387
+ const emps = readFileSync9(
4388
+ path14.join(os11.homedir(), ".exe-os", "exe-employees.json"),
3734
4389
  "utf-8"
3735
4390
  );
3736
4391
  const found = JSON.parse(emps).find(