@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.
- package/dist/bin/backfill-conversations.js +1242 -909
- package/dist/bin/backfill-responses.js +1245 -912
- package/dist/bin/backfill-vectors.js +1244 -906
- package/dist/bin/cleanup-stale-review-tasks.js +1870 -417
- package/dist/bin/cli.js +217 -107
- package/dist/bin/exe-agent-config.js +2 -2
- package/dist/bin/exe-agent.js +62 -0
- package/dist/bin/exe-assign.js +346 -10
- package/dist/bin/exe-boot.js +387 -32
- package/dist/bin/exe-call.js +72 -2
- package/dist/bin/exe-cloud.js +8 -0
- package/dist/bin/exe-dispatch.js +1821 -225
- package/dist/bin/exe-doctor.js +720 -52
- package/dist/bin/exe-export-behaviors.js +1429 -148
- package/dist/bin/exe-forget.js +1408 -34
- package/dist/bin/exe-gateway.js +1629 -1295
- package/dist/bin/exe-heartbeat.js +1899 -448
- package/dist/bin/exe-kill.js +1624 -346
- package/dist/bin/exe-launch-agent.js +726 -90
- package/dist/bin/exe-link.js +27 -8
- package/dist/bin/exe-new-employee.js +75 -9
- package/dist/bin/exe-pending-messages.js +2769 -1316
- package/dist/bin/exe-pending-notifications.js +2829 -1376
- package/dist/bin/exe-pending-reviews.js +2847 -1392
- package/dist/bin/exe-rename.js +89 -8
- package/dist/bin/exe-review.js +1494 -312
- package/dist/bin/exe-search.js +1608 -1300
- package/dist/bin/exe-session-cleanup.js +194 -91
- package/dist/bin/exe-settings.js +10 -2
- package/dist/bin/exe-start-codex.js +769 -120
- package/dist/bin/exe-start-opencode.js +763 -108
- package/dist/bin/exe-status.js +1887 -434
- package/dist/bin/exe-team.js +1782 -324
- package/dist/bin/git-sweep.js +408 -33
- package/dist/bin/graph-backfill.js +681 -27
- package/dist/bin/graph-export.js +1419 -141
- package/dist/bin/install.js +4 -8
- package/dist/bin/intercom-check.js +8641 -0
- package/dist/bin/scan-tasks.js +553 -38
- package/dist/bin/setup.js +82 -10
- package/dist/bin/shard-migrate.js +682 -28
- package/dist/gateway/index.js +1629 -1295
- package/dist/hooks/bug-report-worker.js +1136 -183
- package/dist/hooks/codex-stop-task-finalizer.js +1060 -107
- package/dist/hooks/commit-complete.js +408 -33
- package/dist/hooks/error-recall.js +1608 -1300
- package/dist/hooks/ingest-worker.js +250 -7966
- package/dist/hooks/ingest.js +707 -119
- package/dist/hooks/instructions-loaded.js +383 -20
- package/dist/hooks/notification.js +383 -20
- package/dist/hooks/post-compact.js +384 -21
- package/dist/hooks/{response-ingest-worker.js → post-tool-combined.js} +4157 -1716
- package/dist/hooks/pre-compact.js +486 -45
- package/dist/hooks/pre-tool-use.js +385 -22
- package/dist/hooks/prompt-submit.js +291 -96
- package/dist/hooks/session-end.js +490 -48
- package/dist/hooks/session-start.js +236 -22
- package/dist/hooks/stop.js +192 -50
- package/dist/hooks/subagent-stop.js +95 -18
- package/dist/hooks/summary-worker.js +205 -361
- package/dist/index.js +221 -105
- package/dist/lib/agent-config.js +2 -2
- package/dist/lib/cloud-sync.js +27 -8
- package/dist/lib/consolidation.js +437 -41
- package/dist/lib/database.js +20 -8
- package/dist/lib/db-daemon-client.js +2 -2
- package/dist/lib/db.js +20 -8
- package/dist/lib/device-registry.js +27 -8
- package/dist/lib/employee-templates.js +62 -0
- package/dist/lib/employees.js +2 -2
- package/dist/lib/exe-daemon.js +6703 -6259
- package/dist/lib/hybrid-search.js +1608 -1300
- package/dist/lib/identity.js +1 -1
- package/dist/lib/messaging.js +11 -3
- package/dist/lib/reminders.js +1 -1
- package/dist/lib/schedules.js +718 -26
- package/dist/lib/session-registry.js +11 -0
- package/dist/lib/skill-learning.js +639 -9
- package/dist/lib/store.js +676 -27
- package/dist/lib/tasks.js +665 -27
- package/dist/lib/tmux-routing.js +732 -94
- package/dist/lib/token-spend.js +1 -1
- package/dist/mcp/server.js +856 -383
- package/dist/mcp/tools/complete-reminder.js +1 -1
- package/dist/mcp/tools/create-reminder.js +1 -1
- package/dist/mcp/tools/create-task.js +616 -46
- package/dist/mcp/tools/deactivate-behavior.js +9 -1
- package/dist/mcp/tools/list-reminders.js +1 -1
- package/dist/mcp/tools/list-tasks.js +10 -2
- package/dist/mcp/tools/send-message.js +11 -3
- package/dist/mcp/tools/update-task.js +677 -39
- package/dist/runtime/index.js +425 -37
- package/dist/tui/App.js +365 -34
- package/package.json +5 -2
- package/src/commands/exe/intercom.md +6 -17
- package/dist/bin/wiki-sync.js +0 -2991
- package/dist/hooks/prompt-ingest-worker.js +0 -3979
|
@@ -15,6 +15,15 @@ var __export = (target, all) => {
|
|
|
15
15
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
16
|
};
|
|
17
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
|
+
|
|
18
27
|
// src/lib/db-retry.ts
|
|
19
28
|
function isBusyError(err) {
|
|
20
29
|
if (err instanceof Error) {
|
|
@@ -64,9 +73,9 @@ var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
|
|
|
64
73
|
var init_db_retry = __esm({
|
|
65
74
|
"src/lib/db-retry.ts"() {
|
|
66
75
|
"use strict";
|
|
67
|
-
MAX_RETRIES =
|
|
68
|
-
BASE_DELAY_MS =
|
|
69
|
-
MAX_JITTER_MS =
|
|
76
|
+
MAX_RETRIES = 5;
|
|
77
|
+
BASE_DELAY_MS = 250;
|
|
78
|
+
MAX_JITTER_MS = 400;
|
|
70
79
|
}
|
|
71
80
|
});
|
|
72
81
|
|
|
@@ -80,12 +89,25 @@ async function ensurePrivateDir(dirPath) {
|
|
|
80
89
|
} catch {
|
|
81
90
|
}
|
|
82
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
|
+
}
|
|
83
99
|
async function enforcePrivateFile(filePath) {
|
|
84
100
|
try {
|
|
85
101
|
await chmod(filePath, PRIVATE_FILE_MODE);
|
|
86
102
|
} catch {
|
|
87
103
|
}
|
|
88
104
|
}
|
|
105
|
+
function enforcePrivateFileSync(filePath) {
|
|
106
|
+
try {
|
|
107
|
+
if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
|
|
108
|
+
} catch {
|
|
109
|
+
}
|
|
110
|
+
}
|
|
89
111
|
var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
|
|
90
112
|
var init_secure_files = __esm({
|
|
91
113
|
"src/lib/secure-files.ts"() {
|
|
@@ -913,7 +935,538 @@ var init_database_adapter = __esm({
|
|
|
913
935
|
}
|
|
914
936
|
});
|
|
915
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
|
+
|
|
916
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
|
+
});
|
|
917
1470
|
import { createClient } from "@libsql/client";
|
|
918
1471
|
async function initDatabase(config) {
|
|
919
1472
|
if (_walCheckpointTimer) {
|
|
@@ -952,15 +1505,18 @@ async function initDatabase(config) {
|
|
|
952
1505
|
});
|
|
953
1506
|
}, 3e4);
|
|
954
1507
|
_walCheckpointTimer.unref();
|
|
955
|
-
if (process.env.DATABASE_URL) {
|
|
1508
|
+
if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
|
|
956
1509
|
_adapterClient = await createPrismaDbAdapter(_resilientClient);
|
|
957
1510
|
}
|
|
958
1511
|
}
|
|
1512
|
+
function isInitialized() {
|
|
1513
|
+
return _adapterClient !== null || _client !== null;
|
|
1514
|
+
}
|
|
959
1515
|
function getClient() {
|
|
960
1516
|
if (!_adapterClient) {
|
|
961
1517
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
962
1518
|
}
|
|
963
|
-
if (process.env.DATABASE_URL) {
|
|
1519
|
+
if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
|
|
964
1520
|
return _adapterClient;
|
|
965
1521
|
}
|
|
966
1522
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
@@ -971,6 +1527,22 @@ function getClient() {
|
|
|
971
1527
|
}
|
|
972
1528
|
return _resilientClient;
|
|
973
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
|
+
}
|
|
974
1546
|
function getRawClient() {
|
|
975
1547
|
if (!_client) {
|
|
976
1548
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
@@ -1109,6 +1681,13 @@ async function ensureSchema() {
|
|
|
1109
1681
|
});
|
|
1110
1682
|
} catch {
|
|
1111
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
|
+
}
|
|
1112
1691
|
try {
|
|
1113
1692
|
await client.execute({
|
|
1114
1693
|
sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
|
|
@@ -1979,6 +2558,7 @@ var init_database = __esm({
|
|
|
1979
2558
|
init_db_retry();
|
|
1980
2559
|
init_employees();
|
|
1981
2560
|
init_database_adapter();
|
|
2561
|
+
init_memory();
|
|
1982
2562
|
_client = null;
|
|
1983
2563
|
_resilientClient = null;
|
|
1984
2564
|
_walCheckpointTimer = null;
|
|
@@ -2003,12 +2583,12 @@ __export(shard_manager_exports, {
|
|
|
2003
2583
|
listShards: () => listShards,
|
|
2004
2584
|
shardExists: () => shardExists
|
|
2005
2585
|
});
|
|
2006
|
-
import
|
|
2007
|
-
import { existsSync as
|
|
2586
|
+
import path7 from "path";
|
|
2587
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync } from "fs";
|
|
2008
2588
|
import { createClient as createClient2 } from "@libsql/client";
|
|
2009
2589
|
function initShardManager(encryptionKey) {
|
|
2010
2590
|
_encryptionKey = encryptionKey;
|
|
2011
|
-
if (!
|
|
2591
|
+
if (!existsSync7(SHARDS_DIR)) {
|
|
2012
2592
|
mkdirSync2(SHARDS_DIR, { recursive: true });
|
|
2013
2593
|
}
|
|
2014
2594
|
_shardingEnabled = true;
|
|
@@ -2038,7 +2618,7 @@ function getShardClient(projectName) {
|
|
|
2038
2618
|
while (_shards.size >= MAX_OPEN_SHARDS) {
|
|
2039
2619
|
evictLRU();
|
|
2040
2620
|
}
|
|
2041
|
-
const dbPath =
|
|
2621
|
+
const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
|
|
2042
2622
|
const client = createClient2({
|
|
2043
2623
|
url: `file:${dbPath}`,
|
|
2044
2624
|
encryptionKey: _encryptionKey
|
|
@@ -2049,10 +2629,10 @@ function getShardClient(projectName) {
|
|
|
2049
2629
|
}
|
|
2050
2630
|
function shardExists(projectName) {
|
|
2051
2631
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2052
|
-
return
|
|
2632
|
+
return existsSync7(path7.join(SHARDS_DIR, `${safeName}.db`));
|
|
2053
2633
|
}
|
|
2054
2634
|
function listShards() {
|
|
2055
|
-
if (!
|
|
2635
|
+
if (!existsSync7(SHARDS_DIR)) return [];
|
|
2056
2636
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
2057
2637
|
}
|
|
2058
2638
|
async function ensureShardSchema(client) {
|
|
@@ -2299,7 +2879,7 @@ var init_shard_manager = __esm({
|
|
|
2299
2879
|
"src/lib/shard-manager.ts"() {
|
|
2300
2880
|
"use strict";
|
|
2301
2881
|
init_config();
|
|
2302
|
-
SHARDS_DIR =
|
|
2882
|
+
SHARDS_DIR = path7.join(EXE_AI_DIR, "shards");
|
|
2303
2883
|
SHARD_IDLE_MS = 5 * 60 * 1e3;
|
|
2304
2884
|
MAX_OPEN_SHARDS = 10;
|
|
2305
2885
|
EVICTION_INTERVAL_MS = 60 * 1e3;
|
|
@@ -2419,6 +2999,68 @@ var init_platform_procedures = __esm({
|
|
|
2419
2999
|
domain: "architecture",
|
|
2420
3000
|
priority: "p0",
|
|
2421
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."
|
|
2422
3064
|
}
|
|
2423
3065
|
];
|
|
2424
3066
|
PLATFORM_PROCEDURE_TITLES = new Set(
|
|
@@ -2435,7 +3077,7 @@ __export(global_procedures_exports, {
|
|
|
2435
3077
|
loadGlobalProcedures: () => loadGlobalProcedures,
|
|
2436
3078
|
storeGlobalProcedure: () => storeGlobalProcedure
|
|
2437
3079
|
});
|
|
2438
|
-
import { randomUUID } from "crypto";
|
|
3080
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
2439
3081
|
async function loadGlobalProcedures() {
|
|
2440
3082
|
const client = getClient();
|
|
2441
3083
|
const result = await client.execute({
|
|
@@ -2464,7 +3106,7 @@ ${sections.join("\n\n")}
|
|
|
2464
3106
|
`;
|
|
2465
3107
|
}
|
|
2466
3108
|
async function storeGlobalProcedure(input) {
|
|
2467
|
-
const id =
|
|
3109
|
+
const id = randomUUID2();
|
|
2468
3110
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2469
3111
|
const client = getClient();
|
|
2470
3112
|
await client.execute({
|
|
@@ -2602,9 +3244,9 @@ __export(active_agent_exports, {
|
|
|
2602
3244
|
resolveActiveAgentFromTmuxSession: () => resolveActiveAgentFromTmuxSession,
|
|
2603
3245
|
writeActiveAgent: () => writeActiveAgent
|
|
2604
3246
|
});
|
|
2605
|
-
import { readFileSync as
|
|
3247
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, unlinkSync as unlinkSync4, readdirSync as readdirSync3 } from "fs";
|
|
2606
3248
|
import { execSync as execSync3 } from "child_process";
|
|
2607
|
-
import
|
|
3249
|
+
import path9 from "path";
|
|
2608
3250
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
2609
3251
|
if (candidate === baseName) return true;
|
|
2610
3252
|
if (!candidate.startsWith(baseName)) return false;
|
|
@@ -2648,12 +3290,12 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
|
|
|
2648
3290
|
return null;
|
|
2649
3291
|
}
|
|
2650
3292
|
function getMarkerPath() {
|
|
2651
|
-
return
|
|
3293
|
+
return path9.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
|
|
2652
3294
|
}
|
|
2653
3295
|
function writeActiveAgent(agentId, agentRole) {
|
|
2654
3296
|
try {
|
|
2655
3297
|
mkdirSync4(CACHE_DIR, { recursive: true });
|
|
2656
|
-
|
|
3298
|
+
writeFileSync4(
|
|
2657
3299
|
getMarkerPath(),
|
|
2658
3300
|
JSON.stringify({ agentId, agentRole, startedAt: (/* @__PURE__ */ new Date()).toISOString() })
|
|
2659
3301
|
);
|
|
@@ -2662,21 +3304,21 @@ function writeActiveAgent(agentId, agentRole) {
|
|
|
2662
3304
|
}
|
|
2663
3305
|
function clearActiveAgent() {
|
|
2664
3306
|
try {
|
|
2665
|
-
|
|
3307
|
+
unlinkSync4(getMarkerPath());
|
|
2666
3308
|
} catch {
|
|
2667
3309
|
}
|
|
2668
3310
|
}
|
|
2669
3311
|
function getActiveAgent() {
|
|
2670
3312
|
try {
|
|
2671
3313
|
const markerPath = getMarkerPath();
|
|
2672
|
-
const raw =
|
|
3314
|
+
const raw = readFileSync5(markerPath, "utf8");
|
|
2673
3315
|
const data = JSON.parse(raw);
|
|
2674
3316
|
if (data.agentId) {
|
|
2675
3317
|
if (data.startedAt) {
|
|
2676
3318
|
const age = Date.now() - new Date(data.startedAt).getTime();
|
|
2677
3319
|
if (age > STALE_MS) {
|
|
2678
3320
|
try {
|
|
2679
|
-
|
|
3321
|
+
unlinkSync4(markerPath);
|
|
2680
3322
|
} catch {
|
|
2681
3323
|
}
|
|
2682
3324
|
} else {
|
|
@@ -2717,14 +3359,14 @@ function getAllActiveAgents() {
|
|
|
2717
3359
|
const key = file.slice("active-agent-".length, -".json".length);
|
|
2718
3360
|
if (key === "undefined") continue;
|
|
2719
3361
|
try {
|
|
2720
|
-
const raw =
|
|
3362
|
+
const raw = readFileSync5(path9.join(CACHE_DIR, file), "utf8");
|
|
2721
3363
|
const data = JSON.parse(raw);
|
|
2722
3364
|
if (!data.agentId) continue;
|
|
2723
3365
|
if (data.startedAt) {
|
|
2724
3366
|
const age = Date.now() - new Date(data.startedAt).getTime();
|
|
2725
3367
|
if (age > STALE_MS) {
|
|
2726
3368
|
try {
|
|
2727
|
-
|
|
3369
|
+
unlinkSync4(path9.join(CACHE_DIR, file));
|
|
2728
3370
|
} catch {
|
|
2729
3371
|
}
|
|
2730
3372
|
continue;
|
|
@@ -2747,11 +3389,11 @@ function getAllActiveAgents() {
|
|
|
2747
3389
|
function cleanupSessionMarkers() {
|
|
2748
3390
|
const key = getSessionKey();
|
|
2749
3391
|
try {
|
|
2750
|
-
|
|
3392
|
+
unlinkSync4(path9.join(CACHE_DIR, `active-agent-${key}.json`));
|
|
2751
3393
|
} catch {
|
|
2752
3394
|
}
|
|
2753
3395
|
try {
|
|
2754
|
-
|
|
3396
|
+
unlinkSync4(path9.join(CACHE_DIR, "active-agent-undefined.json"));
|
|
2755
3397
|
} catch {
|
|
2756
3398
|
}
|
|
2757
3399
|
}
|
|
@@ -2762,16 +3404,16 @@ var init_active_agent = __esm({
|
|
|
2762
3404
|
init_config();
|
|
2763
3405
|
init_session_key();
|
|
2764
3406
|
init_employees();
|
|
2765
|
-
CACHE_DIR =
|
|
3407
|
+
CACHE_DIR = path9.join(EXE_AI_DIR, "session-cache");
|
|
2766
3408
|
STALE_MS = 24 * 60 * 60 * 1e3;
|
|
2767
3409
|
}
|
|
2768
3410
|
});
|
|
2769
3411
|
|
|
2770
3412
|
// src/lib/agent-symlinks.ts
|
|
2771
|
-
import
|
|
2772
|
-
import
|
|
3413
|
+
import os7 from "os";
|
|
3414
|
+
import path10 from "path";
|
|
2773
3415
|
import {
|
|
2774
|
-
existsSync as
|
|
3416
|
+
existsSync as existsSync9,
|
|
2775
3417
|
lstatSync,
|
|
2776
3418
|
mkdirSync as mkdirSync5,
|
|
2777
3419
|
readlinkSync as readlinkSync2,
|
|
@@ -2799,14 +3441,14 @@ var init_mcp_prefix = __esm({
|
|
|
2799
3441
|
});
|
|
2800
3442
|
|
|
2801
3443
|
// src/lib/preferences.ts
|
|
2802
|
-
import { existsSync as
|
|
2803
|
-
import
|
|
2804
|
-
import
|
|
2805
|
-
function loadPreferences(homeDir =
|
|
2806
|
-
const configPath =
|
|
2807
|
-
if (!
|
|
3444
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
3445
|
+
import path11 from "path";
|
|
3446
|
+
import os8 from "os";
|
|
3447
|
+
function loadPreferences(homeDir = os8.homedir()) {
|
|
3448
|
+
const configPath = path11.join(homeDir, ".exe-os", "config.json");
|
|
3449
|
+
if (!existsSync10(configPath)) return {};
|
|
2808
3450
|
try {
|
|
2809
|
-
const config = JSON.parse(
|
|
3451
|
+
const config = JSON.parse(readFileSync6(configPath, "utf-8"));
|
|
2810
3452
|
return config.preferences ?? {};
|
|
2811
3453
|
} catch {
|
|
2812
3454
|
return {};
|
|
@@ -2821,27 +3463,27 @@ var init_preferences = __esm({
|
|
|
2821
3463
|
|
|
2822
3464
|
// src/adapters/claude/installer.ts
|
|
2823
3465
|
import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, readdir } from "fs/promises";
|
|
2824
|
-
import { existsSync as
|
|
2825
|
-
import
|
|
2826
|
-
import
|
|
3466
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync6, copyFileSync, mkdirSync as mkdirSync6 } from "fs";
|
|
3467
|
+
import path12 from "path";
|
|
3468
|
+
import os9 from "os";
|
|
2827
3469
|
import { execSync as execSync4 } from "child_process";
|
|
2828
|
-
import { fileURLToPath } from "url";
|
|
3470
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2829
3471
|
function resolvePackageRoot() {
|
|
2830
|
-
const thisFile =
|
|
2831
|
-
let dir =
|
|
2832
|
-
const root =
|
|
3472
|
+
const thisFile = fileURLToPath2(import.meta.url);
|
|
3473
|
+
let dir = path12.dirname(thisFile);
|
|
3474
|
+
const root = path12.parse(dir).root;
|
|
2833
3475
|
while (dir !== root) {
|
|
2834
|
-
const pkgPath =
|
|
2835
|
-
if (
|
|
3476
|
+
const pkgPath = path12.join(dir, "package.json");
|
|
3477
|
+
if (existsSync11(pkgPath)) {
|
|
2836
3478
|
try {
|
|
2837
|
-
const pkg = JSON.parse(
|
|
3479
|
+
const pkg = JSON.parse(readFileSync7(pkgPath, "utf-8"));
|
|
2838
3480
|
if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
|
|
2839
3481
|
} catch {
|
|
2840
3482
|
}
|
|
2841
3483
|
}
|
|
2842
|
-
dir =
|
|
3484
|
+
dir = path12.dirname(dir);
|
|
2843
3485
|
}
|
|
2844
|
-
return
|
|
3486
|
+
return path12.resolve(path12.dirname(thisFile), "..", "..", "..");
|
|
2845
3487
|
}
|
|
2846
3488
|
var EXE_SECTION_START, EXE_SECTION_END, ORCHESTRATION_RULES;
|
|
2847
3489
|
var init_installer = __esm({
|
|
@@ -2875,19 +3517,19 @@ __export(installer_exports, {
|
|
|
2875
3517
|
verifyCodexHooks: () => verifyCodexHooks
|
|
2876
3518
|
});
|
|
2877
3519
|
import { readFile as readFile5, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
|
|
2878
|
-
import { existsSync as
|
|
2879
|
-
import
|
|
2880
|
-
import
|
|
2881
|
-
async function mergeCodexHooks(packageRoot, homeDir =
|
|
2882
|
-
const codexDir =
|
|
2883
|
-
const hooksPath =
|
|
2884
|
-
const logsDir =
|
|
2885
|
-
const hookLogPath =
|
|
3520
|
+
import { existsSync as existsSync12 } from "fs";
|
|
3521
|
+
import path13 from "path";
|
|
3522
|
+
import os10 from "os";
|
|
3523
|
+
async function mergeCodexHooks(packageRoot, homeDir = os10.homedir()) {
|
|
3524
|
+
const codexDir = path13.join(homeDir, ".codex");
|
|
3525
|
+
const hooksPath = path13.join(codexDir, "hooks.json");
|
|
3526
|
+
const logsDir = path13.join(homeDir, ".exe-os", "logs");
|
|
3527
|
+
const hookLogPath = path13.join(logsDir, "hooks.log");
|
|
2886
3528
|
const logSuffix = ` 2>> "${hookLogPath}"`;
|
|
2887
3529
|
await mkdir5(codexDir, { recursive: true });
|
|
2888
3530
|
await mkdir5(logsDir, { recursive: true });
|
|
2889
3531
|
let hooksJson = {};
|
|
2890
|
-
if (
|
|
3532
|
+
if (existsSync12(hooksPath)) {
|
|
2891
3533
|
try {
|
|
2892
3534
|
hooksJson = JSON.parse(await readFile5(hooksPath, "utf-8"));
|
|
2893
3535
|
} catch {
|
|
@@ -2904,7 +3546,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os9.homedir()) {
|
|
|
2904
3546
|
hooks: [
|
|
2905
3547
|
{
|
|
2906
3548
|
type: "command",
|
|
2907
|
-
command: `node "${
|
|
3549
|
+
command: `node "${path13.join(packageRoot, "dist", "hooks", "session-start.js")}"${logSuffix}`,
|
|
2908
3550
|
timeout: 30,
|
|
2909
3551
|
statusMessage: "exe-os: loading memory brief"
|
|
2910
3552
|
}
|
|
@@ -2919,11 +3561,11 @@ async function mergeCodexHooks(packageRoot, homeDir = os9.homedir()) {
|
|
|
2919
3561
|
hooks: [
|
|
2920
3562
|
{
|
|
2921
3563
|
type: "command",
|
|
2922
|
-
command: `node "${
|
|
3564
|
+
command: `node "${path13.join(packageRoot, "dist", "hooks", "ingest.js")}"${logSuffix}`
|
|
2923
3565
|
},
|
|
2924
3566
|
{
|
|
2925
3567
|
type: "command",
|
|
2926
|
-
command: `node "${
|
|
3568
|
+
command: `node "${path13.join(packageRoot, "dist", "hooks", "error-recall.js")}"${logSuffix}`
|
|
2927
3569
|
}
|
|
2928
3570
|
]
|
|
2929
3571
|
},
|
|
@@ -2935,11 +3577,11 @@ async function mergeCodexHooks(packageRoot, homeDir = os9.homedir()) {
|
|
|
2935
3577
|
hooks: [
|
|
2936
3578
|
{
|
|
2937
3579
|
type: "command",
|
|
2938
|
-
command: `node "${
|
|
3580
|
+
command: `node "${path13.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
|
|
2939
3581
|
},
|
|
2940
3582
|
{
|
|
2941
3583
|
type: "command",
|
|
2942
|
-
command: `node "${
|
|
3584
|
+
command: `node "${path13.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"${logSuffix}`,
|
|
2943
3585
|
timeout: 5
|
|
2944
3586
|
}
|
|
2945
3587
|
]
|
|
@@ -2952,7 +3594,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os9.homedir()) {
|
|
|
2952
3594
|
hooks: [
|
|
2953
3595
|
{
|
|
2954
3596
|
type: "command",
|
|
2955
|
-
command: `node "${
|
|
3597
|
+
command: `node "${path13.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
|
|
2956
3598
|
}
|
|
2957
3599
|
]
|
|
2958
3600
|
},
|
|
@@ -2965,7 +3607,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os9.homedir()) {
|
|
|
2965
3607
|
hooks: [
|
|
2966
3608
|
{
|
|
2967
3609
|
type: "command",
|
|
2968
|
-
command: `node "${
|
|
3610
|
+
command: `node "${path13.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
|
|
2969
3611
|
}
|
|
2970
3612
|
]
|
|
2971
3613
|
},
|
|
@@ -2996,9 +3638,9 @@ async function mergeCodexHooks(packageRoot, homeDir = os9.homedir()) {
|
|
|
2996
3638
|
await writeFile5(hooksPath, JSON.stringify(hooksJson, null, 2) + "\n");
|
|
2997
3639
|
return { added, skipped };
|
|
2998
3640
|
}
|
|
2999
|
-
function verifyCodexHooks(homeDir =
|
|
3000
|
-
const hooksPath =
|
|
3001
|
-
if (!
|
|
3641
|
+
function verifyCodexHooks(homeDir = os10.homedir()) {
|
|
3642
|
+
const hooksPath = path13.join(homeDir, ".codex", "hooks.json");
|
|
3643
|
+
if (!existsSync12(hooksPath)) return false;
|
|
3002
3644
|
try {
|
|
3003
3645
|
const hooksJson = JSON.parse(
|
|
3004
3646
|
__require("fs").readFileSync(hooksPath, "utf-8")
|
|
@@ -3018,14 +3660,14 @@ function verifyCodexHooks(homeDir = os9.homedir()) {
|
|
|
3018
3660
|
return false;
|
|
3019
3661
|
}
|
|
3020
3662
|
}
|
|
3021
|
-
async function installCodexStatusLine(homeDir =
|
|
3663
|
+
async function installCodexStatusLine(homeDir = os10.homedir()) {
|
|
3022
3664
|
const prefs = loadPreferences(homeDir);
|
|
3023
3665
|
if (prefs.codexStatusLine === false) return "opted-out";
|
|
3024
|
-
const codexDir =
|
|
3025
|
-
const configPath =
|
|
3666
|
+
const codexDir = path13.join(homeDir, ".codex");
|
|
3667
|
+
const configPath = path13.join(codexDir, "config.toml");
|
|
3026
3668
|
await mkdir5(codexDir, { recursive: true });
|
|
3027
3669
|
let content = "";
|
|
3028
|
-
if (
|
|
3670
|
+
if (existsSync12(configPath)) {
|
|
3029
3671
|
content = await readFile5(configPath, "utf-8");
|
|
3030
3672
|
if (/\[tui\][\s\S]*?status_line\s*=/.test(content)) {
|
|
3031
3673
|
return "already-configured";
|
|
@@ -3073,33 +3715,34 @@ var init_installer2 = __esm({
|
|
|
3073
3715
|
});
|
|
3074
3716
|
|
|
3075
3717
|
// src/bin/exe-start-codex.ts
|
|
3076
|
-
import
|
|
3077
|
-
import
|
|
3718
|
+
import os11 from "os";
|
|
3719
|
+
import path14 from "path";
|
|
3078
3720
|
import {
|
|
3079
|
-
existsSync as
|
|
3080
|
-
readFileSync as
|
|
3081
|
-
writeFileSync as
|
|
3721
|
+
existsSync as existsSync13,
|
|
3722
|
+
readFileSync as readFileSync8,
|
|
3723
|
+
writeFileSync as writeFileSync7,
|
|
3082
3724
|
mkdirSync as mkdirSync7,
|
|
3083
3725
|
readdirSync as readdirSync4
|
|
3084
3726
|
} from "fs";
|
|
3085
3727
|
import { spawnSync } from "child_process";
|
|
3086
3728
|
|
|
3087
3729
|
// src/lib/store.ts
|
|
3088
|
-
|
|
3730
|
+
init_memory();
|
|
3089
3731
|
init_database();
|
|
3732
|
+
import { createHash } from "crypto";
|
|
3090
3733
|
|
|
3091
3734
|
// src/lib/keychain.ts
|
|
3092
3735
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3093
|
-
import { existsSync as
|
|
3094
|
-
import
|
|
3095
|
-
import
|
|
3736
|
+
import { existsSync as existsSync6 } from "fs";
|
|
3737
|
+
import path6 from "path";
|
|
3738
|
+
import os5 from "os";
|
|
3096
3739
|
var SERVICE = "exe-mem";
|
|
3097
3740
|
var ACCOUNT = "master-key";
|
|
3098
3741
|
function getKeyDir() {
|
|
3099
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
3742
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path6.join(os5.homedir(), ".exe-os");
|
|
3100
3743
|
}
|
|
3101
3744
|
function getKeyPath() {
|
|
3102
|
-
return
|
|
3745
|
+
return path6.join(getKeyDir(), "master.key");
|
|
3103
3746
|
}
|
|
3104
3747
|
async function tryKeytar() {
|
|
3105
3748
|
try {
|
|
@@ -3120,9 +3763,9 @@ async function getMasterKey() {
|
|
|
3120
3763
|
}
|
|
3121
3764
|
}
|
|
3122
3765
|
const keyPath = getKeyPath();
|
|
3123
|
-
if (!
|
|
3766
|
+
if (!existsSync6(keyPath)) {
|
|
3124
3767
|
process.stderr.write(
|
|
3125
|
-
`[keychain] Key not found at ${keyPath} (HOME=${
|
|
3768
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
3126
3769
|
`
|
|
3127
3770
|
);
|
|
3128
3771
|
return null;
|
|
@@ -3251,6 +3894,11 @@ async function initStore(options) {
|
|
|
3251
3894
|
encryptionKey: hexKey
|
|
3252
3895
|
});
|
|
3253
3896
|
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
3897
|
+
try {
|
|
3898
|
+
const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3899
|
+
await initDaemonClient2();
|
|
3900
|
+
} catch {
|
|
3901
|
+
}
|
|
3254
3902
|
if (!options?.lightweight) {
|
|
3255
3903
|
try {
|
|
3256
3904
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -3433,24 +4081,24 @@ function vectorToBlob(vector) {
|
|
|
3433
4081
|
}
|
|
3434
4082
|
|
|
3435
4083
|
// src/lib/behaviors-export.ts
|
|
3436
|
-
import
|
|
3437
|
-
import
|
|
4084
|
+
import os6 from "os";
|
|
4085
|
+
import path8 from "path";
|
|
3438
4086
|
import {
|
|
3439
|
-
existsSync as
|
|
4087
|
+
existsSync as existsSync8,
|
|
3440
4088
|
mkdirSync as mkdirSync3,
|
|
3441
4089
|
readdirSync as readdirSync2,
|
|
3442
|
-
statSync,
|
|
3443
|
-
unlinkSync as
|
|
3444
|
-
writeFileSync as
|
|
4090
|
+
statSync as statSync2,
|
|
4091
|
+
unlinkSync as unlinkSync3,
|
|
4092
|
+
writeFileSync as writeFileSync3
|
|
3445
4093
|
} from "fs";
|
|
3446
4094
|
|
|
3447
4095
|
// src/lib/behaviors.ts
|
|
3448
4096
|
init_database();
|
|
3449
|
-
import
|
|
4097
|
+
import crypto2 from "crypto";
|
|
3450
4098
|
async function listBehaviors(agentId, projectName, limit = 30) {
|
|
3451
4099
|
const client = getClient();
|
|
3452
4100
|
const result = await client.execute({
|
|
3453
|
-
sql: `SELECT id, agent_id, project_name, domain, priority, content, active, created_at, updated_at
|
|
4101
|
+
sql: `SELECT id, agent_id, project_name, domain, priority, content, active, created_at, updated_at, vector
|
|
3454
4102
|
FROM behaviors
|
|
3455
4103
|
WHERE agent_id = ? AND active = 1
|
|
3456
4104
|
AND (project_name IS NULL OR project_name = ?)
|
|
@@ -3471,20 +4119,21 @@ async function listBehaviors(agentId, projectName, limit = 30) {
|
|
|
3471
4119
|
content: String(r.content),
|
|
3472
4120
|
active: Number(r.active),
|
|
3473
4121
|
created_at: String(r.created_at),
|
|
3474
|
-
updated_at: String(r.updated_at)
|
|
4122
|
+
updated_at: String(r.updated_at),
|
|
4123
|
+
vector: r.vector ? Array.from(new Float32Array(r.vector)) : null
|
|
3475
4124
|
}));
|
|
3476
4125
|
}
|
|
3477
4126
|
|
|
3478
4127
|
// src/lib/behaviors-export.ts
|
|
3479
|
-
var BEHAVIORS_EXPORT_DIR =
|
|
3480
|
-
|
|
4128
|
+
var BEHAVIORS_EXPORT_DIR = path8.join(
|
|
4129
|
+
os6.homedir(),
|
|
3481
4130
|
".exe-os",
|
|
3482
4131
|
"behaviors-export"
|
|
3483
4132
|
);
|
|
3484
4133
|
var STALE_EXPORT_AGE_MS = 60 * 60 * 1e3;
|
|
3485
4134
|
var EXPORT_BEHAVIOR_LIMIT = 30;
|
|
3486
4135
|
function sweepStaleBehaviorExports(now = Date.now()) {
|
|
3487
|
-
if (!
|
|
4136
|
+
if (!existsSync8(BEHAVIORS_EXPORT_DIR)) return;
|
|
3488
4137
|
let entries;
|
|
3489
4138
|
try {
|
|
3490
4139
|
entries = readdirSync2(BEHAVIORS_EXPORT_DIR);
|
|
@@ -3492,11 +4141,11 @@ function sweepStaleBehaviorExports(now = Date.now()) {
|
|
|
3492
4141
|
return;
|
|
3493
4142
|
}
|
|
3494
4143
|
for (const entry of entries) {
|
|
3495
|
-
const filePath =
|
|
4144
|
+
const filePath = path8.join(BEHAVIORS_EXPORT_DIR, entry);
|
|
3496
4145
|
try {
|
|
3497
|
-
const stat =
|
|
4146
|
+
const stat = statSync2(filePath);
|
|
3498
4147
|
if (now - stat.mtimeMs > STALE_EXPORT_AGE_MS) {
|
|
3499
|
-
|
|
4148
|
+
unlinkSync3(filePath);
|
|
3500
4149
|
}
|
|
3501
4150
|
} catch {
|
|
3502
4151
|
}
|
|
@@ -3525,10 +4174,10 @@ function renderBehaviorExport(behaviors) {
|
|
|
3525
4174
|
}
|
|
3526
4175
|
function exportFilePath(agentId, projectName, sessionKey) {
|
|
3527
4176
|
if (!sessionKey) {
|
|
3528
|
-
return
|
|
4177
|
+
return path8.join(BEHAVIORS_EXPORT_DIR, `${agentId}.md`);
|
|
3529
4178
|
}
|
|
3530
4179
|
const safeProject = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
3531
|
-
return
|
|
4180
|
+
return path8.join(
|
|
3532
4181
|
BEHAVIORS_EXPORT_DIR,
|
|
3533
4182
|
`${agentId}-${safeProject}-${sessionKey}.md`
|
|
3534
4183
|
);
|
|
@@ -3540,7 +4189,7 @@ async function exportBehaviorsForAgent(agentId, projectName, sessionKey) {
|
|
|
3540
4189
|
if (behaviors.length === 0) return null;
|
|
3541
4190
|
const body = renderBehaviorExport(behaviors);
|
|
3542
4191
|
const target = exportFilePath(agentId, projectName, sessionKey);
|
|
3543
|
-
|
|
4192
|
+
writeFileSync3(target, body, "utf-8");
|
|
3544
4193
|
return target;
|
|
3545
4194
|
}
|
|
3546
4195
|
|
|
@@ -3557,7 +4206,7 @@ When done with a task: call update_task with status "done".
|
|
|
3557
4206
|
Always call store_memory to persist important findings.
|
|
3558
4207
|
`;
|
|
3559
4208
|
function resolveAgent(argv) {
|
|
3560
|
-
const invokedAs =
|
|
4209
|
+
const invokedAs = path14.basename(argv[1] ?? "");
|
|
3561
4210
|
if (invokedAs && invokedAs !== "exe-start-codex" && !invokedAs.endsWith(".js")) {
|
|
3562
4211
|
const agent2 = invokedAs.replace(/-codex$/, "").toLowerCase();
|
|
3563
4212
|
return { agent: agent2, passthrough: argv.slice(2) };
|
|
@@ -3583,24 +4232,24 @@ function resolveAgent(argv) {
|
|
|
3583
4232
|
return { agent, passthrough, sessionName };
|
|
3584
4233
|
}
|
|
3585
4234
|
function loadIdentity(agent) {
|
|
3586
|
-
const dir =
|
|
3587
|
-
const exact =
|
|
3588
|
-
if (
|
|
3589
|
-
const content =
|
|
4235
|
+
const dir = path14.join(os11.homedir(), ".exe-os", "identity");
|
|
4236
|
+
const exact = path14.join(dir, `${agent}.md`);
|
|
4237
|
+
if (existsSync13(exact)) {
|
|
4238
|
+
const content = readFileSync8(exact, "utf-8").trim();
|
|
3590
4239
|
if (content) return content;
|
|
3591
4240
|
}
|
|
3592
4241
|
try {
|
|
3593
4242
|
const files = readdirSync4(dir);
|
|
3594
4243
|
const match = files.find((f) => f.toLowerCase() === `${agent.toLowerCase()}.md`);
|
|
3595
4244
|
if (match) {
|
|
3596
|
-
const content =
|
|
4245
|
+
const content = readFileSync8(path14.join(dir, match), "utf-8").trim();
|
|
3597
4246
|
if (content) return content;
|
|
3598
4247
|
}
|
|
3599
4248
|
} catch {
|
|
3600
4249
|
}
|
|
3601
4250
|
try {
|
|
3602
|
-
const rosterPath =
|
|
3603
|
-
const roster = JSON.parse(
|
|
4251
|
+
const rosterPath = path14.join(os11.homedir(), ".exe-os", "exe-employees.json");
|
|
4252
|
+
const roster = JSON.parse(readFileSync8(rosterPath, "utf8"));
|
|
3604
4253
|
const emp = roster.find((e) => e.name.toLowerCase() === agent.toLowerCase());
|
|
3605
4254
|
if (emp?.systemPrompt && emp.systemPrompt.trim().length > 20) {
|
|
3606
4255
|
return emp.systemPrompt;
|
|
@@ -3610,18 +4259,18 @@ function loadIdentity(agent) {
|
|
|
3610
4259
|
return null;
|
|
3611
4260
|
}
|
|
3612
4261
|
function writePromptFile(agent, identity, behaviorsPath) {
|
|
3613
|
-
const promptDir =
|
|
4262
|
+
const promptDir = path14.join(os11.homedir(), ".exe-os", "codex-prompt");
|
|
3614
4263
|
mkdirSync7(promptDir, { recursive: true });
|
|
3615
4264
|
let prompt = identity;
|
|
3616
|
-
if (behaviorsPath &&
|
|
3617
|
-
const behaviors =
|
|
4265
|
+
if (behaviorsPath && existsSync13(behaviorsPath)) {
|
|
4266
|
+
const behaviors = readFileSync8(behaviorsPath, "utf-8").trim();
|
|
3618
4267
|
if (behaviors) {
|
|
3619
4268
|
prompt += "\n\n" + behaviors;
|
|
3620
4269
|
}
|
|
3621
4270
|
}
|
|
3622
4271
|
prompt += "\n" + BOOT_INSTRUCTIONS;
|
|
3623
|
-
const outPath =
|
|
3624
|
-
|
|
4272
|
+
const outPath = path14.join(promptDir, `${agent}.md`);
|
|
4273
|
+
writeFileSync7(outPath, prompt, "utf-8");
|
|
3625
4274
|
return outPath;
|
|
3626
4275
|
}
|
|
3627
4276
|
async function main() {
|
|
@@ -3700,8 +4349,8 @@ async function main() {
|
|
|
3700
4349
|
process.env.EXE_RUNTIME = "codex";
|
|
3701
4350
|
const empRole = (() => {
|
|
3702
4351
|
try {
|
|
3703
|
-
const emps =
|
|
3704
|
-
|
|
4352
|
+
const emps = readFileSync8(
|
|
4353
|
+
path14.join(os11.homedir(), ".exe-os", "exe-employees.json"),
|
|
3705
4354
|
"utf-8"
|
|
3706
4355
|
);
|
|
3707
4356
|
const found = JSON.parse(emps).find(
|
|
@@ -3738,14 +4387,14 @@ async function main() {
|
|
|
3738
4387
|
if (WORKTREE_ROLES.has(empRole)) {
|
|
3739
4388
|
try {
|
|
3740
4389
|
const { execSync: es } = await import("child_process");
|
|
3741
|
-
const worktreeDir =
|
|
4390
|
+
const worktreeDir = path14.join(process.cwd(), ".worktrees", worktreeName);
|
|
3742
4391
|
const branchName = `${worktreeName}/codex-${Date.now()}`;
|
|
3743
|
-
if (
|
|
4392
|
+
if (existsSync13(worktreeDir)) {
|
|
3744
4393
|
worktreePath = worktreeDir;
|
|
3745
4394
|
process.stderr.write(`[exe-start-codex] Reusing worktree at ${worktreeDir}
|
|
3746
4395
|
`);
|
|
3747
4396
|
} else {
|
|
3748
|
-
mkdirSync7(
|
|
4397
|
+
mkdirSync7(path14.dirname(worktreeDir), { recursive: true });
|
|
3749
4398
|
es(`git worktree add "${worktreeDir}" -b "${branchName}" HEAD`, {
|
|
3750
4399
|
encoding: "utf-8",
|
|
3751
4400
|
timeout: 3e4
|