@askexenow/exe-os 0.8.83 → 0.8.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/backfill-conversations.js +746 -595
- package/dist/bin/backfill-responses.js +745 -594
- package/dist/bin/backfill-vectors.js +312 -226
- package/dist/bin/cleanup-stale-review-tasks.js +97 -2
- package/dist/bin/cli.js +14350 -12518
- package/dist/bin/exe-agent.js +97 -88
- package/dist/bin/exe-assign.js +1003 -854
- package/dist/bin/exe-boot.js +1257 -320
- package/dist/bin/exe-call.js +10 -0
- package/dist/bin/exe-cloud.js +29 -6
- package/dist/bin/exe-dispatch.js +210 -34
- package/dist/bin/exe-doctor.js +403 -6
- package/dist/bin/exe-export-behaviors.js +175 -72
- package/dist/bin/exe-forget.js +97 -2
- package/dist/bin/exe-gateway.js +550 -171
- package/dist/bin/exe-healthcheck.js +1 -0
- package/dist/bin/exe-heartbeat.js +100 -5
- package/dist/bin/exe-kill.js +175 -72
- package/dist/bin/exe-launch-agent.js +189 -76
- package/dist/bin/exe-link.js +902 -80
- package/dist/bin/exe-new-employee.js +38 -8
- package/dist/bin/exe-pending-messages.js +96 -2
- package/dist/bin/exe-pending-notifications.js +97 -2
- package/dist/bin/exe-pending-reviews.js +98 -3
- package/dist/bin/exe-rename.js +564 -23
- package/dist/bin/exe-review.js +231 -73
- package/dist/bin/exe-search.js +989 -226
- package/dist/bin/exe-session-cleanup.js +4806 -1665
- package/dist/bin/exe-settings.js +20 -5
- package/dist/bin/exe-status.js +97 -2
- package/dist/bin/exe-team.js +97 -2
- package/dist/bin/git-sweep.js +899 -207
- package/dist/bin/graph-backfill.js +175 -72
- package/dist/bin/graph-export.js +175 -72
- package/dist/bin/install.js +38 -7
- package/dist/bin/list-providers.js +1 -0
- package/dist/bin/scan-tasks.js +904 -211
- package/dist/bin/setup.js +867 -268
- package/dist/bin/shard-migrate.js +175 -72
- package/dist/bin/update.js +1 -0
- package/dist/bin/wiki-sync.js +175 -72
- package/dist/gateway/index.js +548 -166
- package/dist/hooks/bug-report-worker.js +208 -23
- package/dist/hooks/commit-complete.js +897 -205
- package/dist/hooks/error-recall.js +988 -226
- package/dist/hooks/ingest-worker.js +1638 -1194
- package/dist/hooks/ingest.js +3 -0
- package/dist/hooks/instructions-loaded.js +707 -97
- package/dist/hooks/notification.js +699 -89
- package/dist/hooks/post-compact.js +714 -104
- package/dist/hooks/pre-compact.js +897 -205
- package/dist/hooks/pre-tool-use.js +742 -123
- package/dist/hooks/prompt-ingest-worker.js +242 -101
- package/dist/hooks/prompt-submit.js +995 -233
- package/dist/hooks/response-ingest-worker.js +242 -101
- package/dist/hooks/session-end.js +3941 -400
- package/dist/hooks/session-start.js +1001 -226
- package/dist/hooks/stop.js +725 -115
- package/dist/hooks/subagent-stop.js +714 -104
- package/dist/hooks/summary-worker.js +1964 -1330
- package/dist/index.js +1651 -1053
- package/dist/lib/cloud-sync.js +907 -86
- package/dist/lib/consolidation.js +2 -1
- package/dist/lib/database.js +642 -87
- package/dist/lib/db-daemon-client.js +503 -0
- package/dist/lib/device-registry.js +547 -7
- package/dist/lib/embedder.js +14 -28
- package/dist/lib/employee-templates.js +84 -74
- package/dist/lib/employees.js +9 -0
- package/dist/lib/exe-daemon-client.js +16 -29
- package/dist/lib/exe-daemon.js +1955 -922
- package/dist/lib/hybrid-search.js +988 -226
- package/dist/lib/identity.js +87 -67
- package/dist/lib/keychain.js +9 -1
- package/dist/lib/messaging.js +8 -1
- package/dist/lib/reminders.js +91 -74
- package/dist/lib/schedules.js +96 -2
- package/dist/lib/skill-learning.js +103 -85
- package/dist/lib/store.js +234 -73
- package/dist/lib/tasks.js +111 -22
- package/dist/lib/tmux-routing.js +120 -31
- package/dist/lib/token-spend.js +273 -0
- package/dist/lib/ws-client.js +11 -0
- package/dist/mcp/server.js +5222 -475
- package/dist/mcp/tools/complete-reminder.js +94 -77
- package/dist/mcp/tools/create-reminder.js +94 -77
- package/dist/mcp/tools/create-task.js +120 -22
- package/dist/mcp/tools/deactivate-behavior.js +95 -77
- package/dist/mcp/tools/list-reminders.js +94 -77
- package/dist/mcp/tools/list-tasks.js +31 -1
- package/dist/mcp/tools/send-message.js +8 -1
- package/dist/mcp/tools/update-task.js +39 -10
- package/dist/runtime/index.js +911 -219
- package/dist/tui/App.js +997 -295
- package/package.json +6 -1
package/dist/tui/App.js
CHANGED
|
@@ -673,6 +673,7 @@ __export(employees_exports, {
|
|
|
673
673
|
DEFAULT_COORDINATOR_TEMPLATE_NAME: () => DEFAULT_COORDINATOR_TEMPLATE_NAME,
|
|
674
674
|
EMPLOYEES_PATH: () => EMPLOYEES_PATH,
|
|
675
675
|
addEmployee: () => addEmployee,
|
|
676
|
+
baseAgentName: () => baseAgentName,
|
|
676
677
|
canCoordinate: () => canCoordinate,
|
|
677
678
|
getCoordinatorEmployee: () => getCoordinatorEmployee,
|
|
678
679
|
getCoordinatorName: () => getCoordinatorName,
|
|
@@ -769,6 +770,14 @@ function hasRole(agentName, role) {
|
|
|
769
770
|
const emp = getEmployee(employees, agentName);
|
|
770
771
|
return emp ? emp.role.toLowerCase() === role.toLowerCase() : false;
|
|
771
772
|
}
|
|
773
|
+
function baseAgentName(name, employees) {
|
|
774
|
+
const match = name.match(/^([a-zA-Z]+)\d+$/);
|
|
775
|
+
if (!match) return name;
|
|
776
|
+
const base = match[1];
|
|
777
|
+
const roster = employees ?? loadEmployeesSync();
|
|
778
|
+
if (getEmployee(roster, base)) return base;
|
|
779
|
+
return name;
|
|
780
|
+
}
|
|
772
781
|
function isMultiInstance(agentName, employees) {
|
|
773
782
|
const roster = employees ?? loadEmployeesSync();
|
|
774
783
|
const emp = getEmployee(roster, agentName);
|
|
@@ -864,6 +873,443 @@ var init_employees = __esm({
|
|
|
864
873
|
}
|
|
865
874
|
});
|
|
866
875
|
|
|
876
|
+
// src/lib/exe-daemon-client.ts
|
|
877
|
+
import net from "net";
|
|
878
|
+
import { spawn } from "child_process";
|
|
879
|
+
import { randomUUID } from "crypto";
|
|
880
|
+
import { existsSync as existsSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync6, openSync, closeSync, statSync } from "fs";
|
|
881
|
+
import path5 from "path";
|
|
882
|
+
import { fileURLToPath } from "url";
|
|
883
|
+
function handleData(chunk) {
|
|
884
|
+
_buffer += chunk.toString();
|
|
885
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
886
|
+
_buffer = "";
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
let newlineIdx;
|
|
890
|
+
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
891
|
+
const line = _buffer.slice(0, newlineIdx).trim();
|
|
892
|
+
_buffer = _buffer.slice(newlineIdx + 1);
|
|
893
|
+
if (!line) continue;
|
|
894
|
+
try {
|
|
895
|
+
const response = JSON.parse(line);
|
|
896
|
+
const id = response.id;
|
|
897
|
+
if (!id) continue;
|
|
898
|
+
const entry = _pending.get(id);
|
|
899
|
+
if (entry) {
|
|
900
|
+
clearTimeout(entry.timer);
|
|
901
|
+
_pending.delete(id);
|
|
902
|
+
entry.resolve(response);
|
|
903
|
+
}
|
|
904
|
+
} catch {
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
function cleanupStaleFiles() {
|
|
909
|
+
if (existsSync6(PID_PATH)) {
|
|
910
|
+
try {
|
|
911
|
+
const pid = parseInt(readFileSync6(PID_PATH, "utf8").trim(), 10);
|
|
912
|
+
if (pid > 0) {
|
|
913
|
+
try {
|
|
914
|
+
process.kill(pid, 0);
|
|
915
|
+
return;
|
|
916
|
+
} catch {
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
} catch {
|
|
920
|
+
}
|
|
921
|
+
try {
|
|
922
|
+
unlinkSync2(PID_PATH);
|
|
923
|
+
} catch {
|
|
924
|
+
}
|
|
925
|
+
try {
|
|
926
|
+
unlinkSync2(SOCKET_PATH);
|
|
927
|
+
} catch {
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
function findPackageRoot() {
|
|
932
|
+
let dir = path5.dirname(fileURLToPath(import.meta.url));
|
|
933
|
+
const { root } = path5.parse(dir);
|
|
934
|
+
while (dir !== root) {
|
|
935
|
+
if (existsSync6(path5.join(dir, "package.json"))) return dir;
|
|
936
|
+
dir = path5.dirname(dir);
|
|
937
|
+
}
|
|
938
|
+
return null;
|
|
939
|
+
}
|
|
940
|
+
function spawnDaemon() {
|
|
941
|
+
const pkgRoot = findPackageRoot();
|
|
942
|
+
if (!pkgRoot) {
|
|
943
|
+
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
const daemonPath = path5.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
947
|
+
if (!existsSync6(daemonPath)) {
|
|
948
|
+
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
949
|
+
`);
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
const resolvedPath = daemonPath;
|
|
953
|
+
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
954
|
+
`);
|
|
955
|
+
const logPath = path5.join(path5.dirname(SOCKET_PATH), "exed.log");
|
|
956
|
+
let stderrFd = "ignore";
|
|
957
|
+
try {
|
|
958
|
+
stderrFd = openSync(logPath, "a");
|
|
959
|
+
} catch {
|
|
960
|
+
}
|
|
961
|
+
const child = spawn(process.execPath, [resolvedPath], {
|
|
962
|
+
detached: true,
|
|
963
|
+
stdio: ["ignore", "ignore", stderrFd],
|
|
964
|
+
env: {
|
|
965
|
+
...process.env,
|
|
966
|
+
TMUX: void 0,
|
|
967
|
+
// Daemon is global — must not inherit session scope
|
|
968
|
+
TMUX_PANE: void 0,
|
|
969
|
+
// Prevents resolveExeSession() from scoping to one session
|
|
970
|
+
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
971
|
+
EXE_DAEMON_PID: PID_PATH
|
|
972
|
+
}
|
|
973
|
+
});
|
|
974
|
+
child.unref();
|
|
975
|
+
if (typeof stderrFd === "number") {
|
|
976
|
+
try {
|
|
977
|
+
closeSync(stderrFd);
|
|
978
|
+
} catch {
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
function acquireSpawnLock() {
|
|
983
|
+
try {
|
|
984
|
+
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
985
|
+
closeSync(fd);
|
|
986
|
+
return true;
|
|
987
|
+
} catch {
|
|
988
|
+
try {
|
|
989
|
+
const stat = statSync(SPAWN_LOCK_PATH);
|
|
990
|
+
if (Date.now() - stat.mtimeMs > SPAWN_LOCK_STALE_MS) {
|
|
991
|
+
try {
|
|
992
|
+
unlinkSync2(SPAWN_LOCK_PATH);
|
|
993
|
+
} catch {
|
|
994
|
+
}
|
|
995
|
+
try {
|
|
996
|
+
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
997
|
+
closeSync(fd);
|
|
998
|
+
return true;
|
|
999
|
+
} catch {
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
} catch {
|
|
1003
|
+
}
|
|
1004
|
+
return false;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
function releaseSpawnLock() {
|
|
1008
|
+
try {
|
|
1009
|
+
unlinkSync2(SPAWN_LOCK_PATH);
|
|
1010
|
+
} catch {
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
function connectToSocket() {
|
|
1014
|
+
return new Promise((resolve) => {
|
|
1015
|
+
if (_socket && _connected) {
|
|
1016
|
+
resolve(true);
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
const socket = net.createConnection({ path: SOCKET_PATH });
|
|
1020
|
+
const connectTimeout = setTimeout(() => {
|
|
1021
|
+
socket.destroy();
|
|
1022
|
+
resolve(false);
|
|
1023
|
+
}, 2e3);
|
|
1024
|
+
socket.on("connect", () => {
|
|
1025
|
+
clearTimeout(connectTimeout);
|
|
1026
|
+
_socket = socket;
|
|
1027
|
+
_connected = true;
|
|
1028
|
+
_buffer = "";
|
|
1029
|
+
socket.on("data", handleData);
|
|
1030
|
+
socket.on("close", () => {
|
|
1031
|
+
_connected = false;
|
|
1032
|
+
_socket = null;
|
|
1033
|
+
for (const [id, entry] of _pending) {
|
|
1034
|
+
clearTimeout(entry.timer);
|
|
1035
|
+
_pending.delete(id);
|
|
1036
|
+
entry.resolve({ error: "Connection closed" });
|
|
1037
|
+
}
|
|
1038
|
+
});
|
|
1039
|
+
socket.on("error", () => {
|
|
1040
|
+
_connected = false;
|
|
1041
|
+
_socket = null;
|
|
1042
|
+
});
|
|
1043
|
+
resolve(true);
|
|
1044
|
+
});
|
|
1045
|
+
socket.on("error", () => {
|
|
1046
|
+
clearTimeout(connectTimeout);
|
|
1047
|
+
resolve(false);
|
|
1048
|
+
});
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
async function connectEmbedDaemon() {
|
|
1052
|
+
if (_socket && _connected) return true;
|
|
1053
|
+
if (await connectToSocket()) return true;
|
|
1054
|
+
if (acquireSpawnLock()) {
|
|
1055
|
+
try {
|
|
1056
|
+
cleanupStaleFiles();
|
|
1057
|
+
spawnDaemon();
|
|
1058
|
+
} finally {
|
|
1059
|
+
releaseSpawnLock();
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
const start = Date.now();
|
|
1063
|
+
let delay2 = 100;
|
|
1064
|
+
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1065
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
1066
|
+
if (await connectToSocket()) return true;
|
|
1067
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
1068
|
+
}
|
|
1069
|
+
return false;
|
|
1070
|
+
}
|
|
1071
|
+
function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
1072
|
+
return new Promise((resolve) => {
|
|
1073
|
+
if (!_socket || !_connected) {
|
|
1074
|
+
resolve({ error: "Not connected" });
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
const id = randomUUID();
|
|
1078
|
+
const timer = setTimeout(() => {
|
|
1079
|
+
_pending.delete(id);
|
|
1080
|
+
resolve({ error: "Request timeout" });
|
|
1081
|
+
}, timeoutMs);
|
|
1082
|
+
_pending.set(id, { resolve, timer });
|
|
1083
|
+
try {
|
|
1084
|
+
_socket.write(JSON.stringify({ id, ...payload }) + "\n");
|
|
1085
|
+
} catch {
|
|
1086
|
+
clearTimeout(timer);
|
|
1087
|
+
_pending.delete(id);
|
|
1088
|
+
resolve({ error: "Write failed" });
|
|
1089
|
+
}
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
function isClientConnected() {
|
|
1093
|
+
return _connected;
|
|
1094
|
+
}
|
|
1095
|
+
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _pending, MAX_BUFFER;
|
|
1096
|
+
var init_exe_daemon_client = __esm({
|
|
1097
|
+
"src/lib/exe-daemon-client.ts"() {
|
|
1098
|
+
"use strict";
|
|
1099
|
+
init_config();
|
|
1100
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path5.join(EXE_AI_DIR, "exed.sock");
|
|
1101
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path5.join(EXE_AI_DIR, "exed.pid");
|
|
1102
|
+
SPAWN_LOCK_PATH = path5.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
1103
|
+
SPAWN_LOCK_STALE_MS = 3e4;
|
|
1104
|
+
CONNECT_TIMEOUT_MS = 15e3;
|
|
1105
|
+
REQUEST_TIMEOUT_MS = 3e4;
|
|
1106
|
+
_socket = null;
|
|
1107
|
+
_connected = false;
|
|
1108
|
+
_buffer = "";
|
|
1109
|
+
_pending = /* @__PURE__ */ new Map();
|
|
1110
|
+
MAX_BUFFER = 1e7;
|
|
1111
|
+
}
|
|
1112
|
+
});
|
|
1113
|
+
|
|
1114
|
+
// src/lib/daemon-protocol.ts
|
|
1115
|
+
function serializeValue(v) {
|
|
1116
|
+
if (v === null || v === void 0) return null;
|
|
1117
|
+
if (typeof v === "bigint") return Number(v);
|
|
1118
|
+
if (typeof v === "boolean") return v ? 1 : 0;
|
|
1119
|
+
if (v instanceof Uint8Array) {
|
|
1120
|
+
return { __blob: Buffer.from(v).toString("base64") };
|
|
1121
|
+
}
|
|
1122
|
+
if (ArrayBuffer.isView(v)) {
|
|
1123
|
+
return { __blob: Buffer.from(v.buffer, v.byteOffset, v.byteLength).toString("base64") };
|
|
1124
|
+
}
|
|
1125
|
+
if (v instanceof ArrayBuffer) {
|
|
1126
|
+
return { __blob: Buffer.from(v).toString("base64") };
|
|
1127
|
+
}
|
|
1128
|
+
if (typeof v === "string" || typeof v === "number") return v;
|
|
1129
|
+
return String(v);
|
|
1130
|
+
}
|
|
1131
|
+
function deserializeValue(v) {
|
|
1132
|
+
if (v === null) return null;
|
|
1133
|
+
if (typeof v === "object" && v !== null && "__blob" in v) {
|
|
1134
|
+
const buf = Buffer.from(v.__blob, "base64");
|
|
1135
|
+
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
1136
|
+
}
|
|
1137
|
+
return v;
|
|
1138
|
+
}
|
|
1139
|
+
function deserializeResultSet(srs) {
|
|
1140
|
+
const rows = srs.rows.map((obj) => {
|
|
1141
|
+
const values = srs.columns.map(
|
|
1142
|
+
(col) => deserializeValue(obj[col] ?? null)
|
|
1143
|
+
);
|
|
1144
|
+
const row = values;
|
|
1145
|
+
for (let i = 0; i < srs.columns.length; i++) {
|
|
1146
|
+
const col = srs.columns[i];
|
|
1147
|
+
if (col !== void 0) {
|
|
1148
|
+
row[col] = values[i] ?? null;
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
Object.defineProperty(row, "length", {
|
|
1152
|
+
value: values.length,
|
|
1153
|
+
enumerable: false
|
|
1154
|
+
});
|
|
1155
|
+
return row;
|
|
1156
|
+
});
|
|
1157
|
+
return {
|
|
1158
|
+
columns: srs.columns,
|
|
1159
|
+
columnTypes: srs.columnTypes ?? [],
|
|
1160
|
+
rows,
|
|
1161
|
+
rowsAffected: srs.rowsAffected,
|
|
1162
|
+
lastInsertRowid: srs.lastInsertRowid != null ? BigInt(srs.lastInsertRowid) : void 0,
|
|
1163
|
+
toJSON: () => ({
|
|
1164
|
+
columns: srs.columns,
|
|
1165
|
+
columnTypes: srs.columnTypes ?? [],
|
|
1166
|
+
rows: srs.rows,
|
|
1167
|
+
rowsAffected: srs.rowsAffected,
|
|
1168
|
+
lastInsertRowid: srs.lastInsertRowid
|
|
1169
|
+
})
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
var init_daemon_protocol = __esm({
|
|
1173
|
+
"src/lib/daemon-protocol.ts"() {
|
|
1174
|
+
"use strict";
|
|
1175
|
+
}
|
|
1176
|
+
});
|
|
1177
|
+
|
|
1178
|
+
// src/lib/db-daemon-client.ts
|
|
1179
|
+
var db_daemon_client_exports = {};
|
|
1180
|
+
__export(db_daemon_client_exports, {
|
|
1181
|
+
createDaemonDbClient: () => createDaemonDbClient,
|
|
1182
|
+
initDaemonDbClient: () => initDaemonDbClient
|
|
1183
|
+
});
|
|
1184
|
+
function normalizeStatement(stmt) {
|
|
1185
|
+
if (typeof stmt === "string") {
|
|
1186
|
+
return { sql: stmt, args: [] };
|
|
1187
|
+
}
|
|
1188
|
+
const sql = stmt.sql;
|
|
1189
|
+
let args = [];
|
|
1190
|
+
if (Array.isArray(stmt.args)) {
|
|
1191
|
+
args = stmt.args.map((v) => serializeValue(v));
|
|
1192
|
+
} else if (stmt.args && typeof stmt.args === "object") {
|
|
1193
|
+
const named = {};
|
|
1194
|
+
for (const [key, val] of Object.entries(stmt.args)) {
|
|
1195
|
+
named[key] = serializeValue(val);
|
|
1196
|
+
}
|
|
1197
|
+
return { sql, args: named };
|
|
1198
|
+
}
|
|
1199
|
+
return { sql, args };
|
|
1200
|
+
}
|
|
1201
|
+
function createDaemonDbClient(fallbackClient) {
|
|
1202
|
+
let _useDaemon = false;
|
|
1203
|
+
const client = {
|
|
1204
|
+
async execute(stmt) {
|
|
1205
|
+
if (!_useDaemon || !isClientConnected()) {
|
|
1206
|
+
return fallbackClient.execute(stmt);
|
|
1207
|
+
}
|
|
1208
|
+
const { sql, args } = normalizeStatement(stmt);
|
|
1209
|
+
const response = await sendDaemonRequest({
|
|
1210
|
+
type: "db-execute",
|
|
1211
|
+
sql,
|
|
1212
|
+
args
|
|
1213
|
+
});
|
|
1214
|
+
if (response.error) {
|
|
1215
|
+
const errMsg = String(response.error);
|
|
1216
|
+
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
|
|
1217
|
+
process.stderr.write(`[db-daemon] Transport error (${errMsg}), falling back to direct
|
|
1218
|
+
`);
|
|
1219
|
+
return fallbackClient.execute(stmt);
|
|
1220
|
+
}
|
|
1221
|
+
throw new Error(errMsg);
|
|
1222
|
+
}
|
|
1223
|
+
if (response.db) {
|
|
1224
|
+
return deserializeResultSet(response.db);
|
|
1225
|
+
}
|
|
1226
|
+
process.stderr.write("[db-daemon] Unexpected response shape, falling back to direct\n");
|
|
1227
|
+
return fallbackClient.execute(stmt);
|
|
1228
|
+
},
|
|
1229
|
+
async batch(stmts, mode) {
|
|
1230
|
+
if (!_useDaemon || !isClientConnected()) {
|
|
1231
|
+
return fallbackClient.batch(stmts, mode);
|
|
1232
|
+
}
|
|
1233
|
+
const statements = stmts.map(normalizeStatement);
|
|
1234
|
+
const response = await sendDaemonRequest({
|
|
1235
|
+
type: "db-batch",
|
|
1236
|
+
statements,
|
|
1237
|
+
mode: mode ?? "deferred"
|
|
1238
|
+
});
|
|
1239
|
+
if (response.error) {
|
|
1240
|
+
const errMsg = String(response.error);
|
|
1241
|
+
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
|
|
1242
|
+
process.stderr.write(`[db-daemon] Batch transport error (${errMsg}), falling back to direct
|
|
1243
|
+
`);
|
|
1244
|
+
return fallbackClient.batch(stmts, mode);
|
|
1245
|
+
}
|
|
1246
|
+
throw new Error(errMsg);
|
|
1247
|
+
}
|
|
1248
|
+
const batchResults = response["db-batch"];
|
|
1249
|
+
if (batchResults) {
|
|
1250
|
+
return batchResults.map(deserializeResultSet);
|
|
1251
|
+
}
|
|
1252
|
+
process.stderr.write("[db-daemon] Unexpected batch response shape, falling back to direct\n");
|
|
1253
|
+
return fallbackClient.batch(stmts, mode);
|
|
1254
|
+
},
|
|
1255
|
+
// Transaction support — delegate to fallback (transactions need direct connection)
|
|
1256
|
+
async transaction(mode) {
|
|
1257
|
+
return fallbackClient.transaction(mode);
|
|
1258
|
+
},
|
|
1259
|
+
// executeMultiple — delegate to fallback (used only for schema migrations)
|
|
1260
|
+
async executeMultiple(sql) {
|
|
1261
|
+
return fallbackClient.executeMultiple(sql);
|
|
1262
|
+
},
|
|
1263
|
+
// migrate — delegate to fallback
|
|
1264
|
+
async migrate(stmts) {
|
|
1265
|
+
return fallbackClient.migrate(stmts);
|
|
1266
|
+
},
|
|
1267
|
+
// Sync mode — delegate to fallback
|
|
1268
|
+
sync() {
|
|
1269
|
+
return fallbackClient.sync();
|
|
1270
|
+
},
|
|
1271
|
+
close() {
|
|
1272
|
+
_useDaemon = false;
|
|
1273
|
+
},
|
|
1274
|
+
get closed() {
|
|
1275
|
+
return fallbackClient.closed;
|
|
1276
|
+
},
|
|
1277
|
+
get protocol() {
|
|
1278
|
+
return fallbackClient.protocol;
|
|
1279
|
+
}
|
|
1280
|
+
};
|
|
1281
|
+
return {
|
|
1282
|
+
...client,
|
|
1283
|
+
/** Enable daemon routing (call after confirming daemon is connected) */
|
|
1284
|
+
_enableDaemon() {
|
|
1285
|
+
_useDaemon = true;
|
|
1286
|
+
},
|
|
1287
|
+
/** Check if daemon routing is active */
|
|
1288
|
+
_isDaemonActive() {
|
|
1289
|
+
return _useDaemon && isClientConnected();
|
|
1290
|
+
}
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
async function initDaemonDbClient(fallbackClient) {
|
|
1294
|
+
if (process.env.EXE_IS_DAEMON === "1") return null;
|
|
1295
|
+
const connected = await connectEmbedDaemon();
|
|
1296
|
+
if (!connected) {
|
|
1297
|
+
process.stderr.write("[db-daemon] Daemon unavailable \u2014 using direct SQLite\n");
|
|
1298
|
+
return null;
|
|
1299
|
+
}
|
|
1300
|
+
const client = createDaemonDbClient(fallbackClient);
|
|
1301
|
+
client._enableDaemon();
|
|
1302
|
+
process.stderr.write("[db-daemon] DB routing through daemon (single-writer)\n");
|
|
1303
|
+
return client;
|
|
1304
|
+
}
|
|
1305
|
+
var init_db_daemon_client = __esm({
|
|
1306
|
+
"src/lib/db-daemon-client.ts"() {
|
|
1307
|
+
"use strict";
|
|
1308
|
+
init_exe_daemon_client();
|
|
1309
|
+
init_daemon_protocol();
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
|
|
867
1313
|
// src/lib/database.ts
|
|
868
1314
|
var database_exports = {};
|
|
869
1315
|
__export(database_exports, {
|
|
@@ -872,6 +1318,7 @@ __export(database_exports, {
|
|
|
872
1318
|
ensureSchema: () => ensureSchema,
|
|
873
1319
|
getClient: () => getClient,
|
|
874
1320
|
getRawClient: () => getRawClient,
|
|
1321
|
+
initDaemonClient: () => initDaemonClient,
|
|
875
1322
|
initDatabase: () => initDatabase,
|
|
876
1323
|
initTurso: () => initTurso,
|
|
877
1324
|
isInitialized: () => isInitialized
|
|
@@ -899,8 +1346,27 @@ function getClient() {
|
|
|
899
1346
|
if (!_resilientClient) {
|
|
900
1347
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
901
1348
|
}
|
|
1349
|
+
if (process.env.EXE_IS_DAEMON === "1") {
|
|
1350
|
+
return _resilientClient;
|
|
1351
|
+
}
|
|
1352
|
+
if (_daemonClient && _daemonClient._isDaemonActive()) {
|
|
1353
|
+
return _daemonClient;
|
|
1354
|
+
}
|
|
902
1355
|
return _resilientClient;
|
|
903
1356
|
}
|
|
1357
|
+
async function initDaemonClient() {
|
|
1358
|
+
if (process.env.EXE_IS_DAEMON === "1") return;
|
|
1359
|
+
if (!_resilientClient) return;
|
|
1360
|
+
try {
|
|
1361
|
+
const { initDaemonDbClient: initDaemonDbClient2 } = await Promise.resolve().then(() => (init_db_daemon_client(), db_daemon_client_exports));
|
|
1362
|
+
_daemonClient = await initDaemonDbClient2(_resilientClient);
|
|
1363
|
+
} catch (err) {
|
|
1364
|
+
process.stderr.write(
|
|
1365
|
+
`[database] Daemon client init failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
|
|
1366
|
+
`
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
904
1370
|
function getRawClient() {
|
|
905
1371
|
if (!_client) {
|
|
906
1372
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
@@ -1387,6 +1853,12 @@ async function ensureSchema() {
|
|
|
1387
1853
|
} catch {
|
|
1388
1854
|
}
|
|
1389
1855
|
}
|
|
1856
|
+
try {
|
|
1857
|
+
await client.execute(
|
|
1858
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
|
|
1859
|
+
);
|
|
1860
|
+
} catch {
|
|
1861
|
+
}
|
|
1390
1862
|
await client.executeMultiple(`
|
|
1391
1863
|
CREATE TABLE IF NOT EXISTS entities (
|
|
1392
1864
|
id TEXT PRIMARY KEY,
|
|
@@ -1439,7 +1911,30 @@ async function ensureSchema() {
|
|
|
1439
1911
|
entity_id TEXT NOT NULL,
|
|
1440
1912
|
PRIMARY KEY (hyperedge_id, entity_id)
|
|
1441
1913
|
);
|
|
1914
|
+
|
|
1915
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
|
|
1916
|
+
name,
|
|
1917
|
+
content=entities,
|
|
1918
|
+
content_rowid=rowid
|
|
1919
|
+
);
|
|
1920
|
+
|
|
1921
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
|
|
1922
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
1923
|
+
END;
|
|
1924
|
+
|
|
1925
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
|
|
1926
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
1927
|
+
END;
|
|
1928
|
+
|
|
1929
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
|
|
1930
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
1931
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
1932
|
+
END;
|
|
1442
1933
|
`);
|
|
1934
|
+
try {
|
|
1935
|
+
await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
|
|
1936
|
+
} catch {
|
|
1937
|
+
}
|
|
1443
1938
|
await client.executeMultiple(`
|
|
1444
1939
|
CREATE TABLE IF NOT EXISTS entity_aliases (
|
|
1445
1940
|
alias TEXT NOT NULL PRIMARY KEY,
|
|
@@ -1620,6 +2115,33 @@ async function ensureSchema() {
|
|
|
1620
2115
|
CREATE INDEX IF NOT EXISTS idx_conversations_channel
|
|
1621
2116
|
ON conversations(channel_id);
|
|
1622
2117
|
`);
|
|
2118
|
+
await client.executeMultiple(`
|
|
2119
|
+
CREATE TABLE IF NOT EXISTS session_agent_map (
|
|
2120
|
+
session_uuid TEXT PRIMARY KEY,
|
|
2121
|
+
agent_id TEXT NOT NULL,
|
|
2122
|
+
session_name TEXT,
|
|
2123
|
+
task_id TEXT,
|
|
2124
|
+
project_name TEXT,
|
|
2125
|
+
started_at TEXT NOT NULL
|
|
2126
|
+
);
|
|
2127
|
+
|
|
2128
|
+
CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
|
|
2129
|
+
ON session_agent_map(agent_id);
|
|
2130
|
+
`);
|
|
2131
|
+
try {
|
|
2132
|
+
const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
|
|
2133
|
+
if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
|
|
2134
|
+
await client.execute({
|
|
2135
|
+
sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
|
|
2136
|
+
SELECT session_id, agent_id, '', MIN(timestamp)
|
|
2137
|
+
FROM memories
|
|
2138
|
+
WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
|
|
2139
|
+
GROUP BY session_id, agent_id`,
|
|
2140
|
+
args: []
|
|
2141
|
+
});
|
|
2142
|
+
}
|
|
2143
|
+
} catch {
|
|
2144
|
+
}
|
|
1623
2145
|
try {
|
|
1624
2146
|
await client.execute({
|
|
1625
2147
|
sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
|
|
@@ -1753,15 +2275,41 @@ async function ensureSchema() {
|
|
|
1753
2275
|
});
|
|
1754
2276
|
} catch {
|
|
1755
2277
|
}
|
|
2278
|
+
for (const col of [
|
|
2279
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
2280
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
2281
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
2282
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
2283
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
2284
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
2285
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
2286
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
2287
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
2288
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
2289
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
2290
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
2291
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
2292
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
2293
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
2294
|
+
]) {
|
|
2295
|
+
try {
|
|
2296
|
+
await client.execute(col);
|
|
2297
|
+
} catch {
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
1756
2300
|
}
|
|
1757
2301
|
async function disposeDatabase() {
|
|
2302
|
+
if (_daemonClient) {
|
|
2303
|
+
_daemonClient.close();
|
|
2304
|
+
_daemonClient = null;
|
|
2305
|
+
}
|
|
1758
2306
|
if (_client) {
|
|
1759
2307
|
_client.close();
|
|
1760
2308
|
_client = null;
|
|
1761
2309
|
_resilientClient = null;
|
|
1762
2310
|
}
|
|
1763
2311
|
}
|
|
1764
|
-
var _client, _resilientClient, initTurso, disposeTurso;
|
|
2312
|
+
var _client, _resilientClient, _daemonClient, initTurso, disposeTurso;
|
|
1765
2313
|
var init_database = __esm({
|
|
1766
2314
|
"src/lib/database.ts"() {
|
|
1767
2315
|
"use strict";
|
|
@@ -1769,6 +2317,7 @@ var init_database = __esm({
|
|
|
1769
2317
|
init_employees();
|
|
1770
2318
|
_client = null;
|
|
1771
2319
|
_resilientClient = null;
|
|
2320
|
+
_daemonClient = null;
|
|
1772
2321
|
initTurso = initDatabase;
|
|
1773
2322
|
disposeTurso = disposeDatabase;
|
|
1774
2323
|
}
|
|
@@ -1791,9 +2340,9 @@ __export(license_exports, {
|
|
|
1791
2340
|
stopLicenseRevalidation: () => stopLicenseRevalidation,
|
|
1792
2341
|
validateLicense: () => validateLicense
|
|
1793
2342
|
});
|
|
1794
|
-
import { readFileSync as
|
|
1795
|
-
import { randomUUID } from "crypto";
|
|
1796
|
-
import
|
|
2343
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
|
|
2344
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
2345
|
+
import path6 from "path";
|
|
1797
2346
|
import { jwtVerify, importSPKI } from "jose";
|
|
1798
2347
|
async function fetchRetry(url, init) {
|
|
1799
2348
|
try {
|
|
@@ -1804,30 +2353,30 @@ async function fetchRetry(url, init) {
|
|
|
1804
2353
|
}
|
|
1805
2354
|
}
|
|
1806
2355
|
function loadDeviceId() {
|
|
1807
|
-
const deviceJsonPath =
|
|
2356
|
+
const deviceJsonPath = path6.join(EXE_AI_DIR, "device.json");
|
|
1808
2357
|
try {
|
|
1809
|
-
if (
|
|
1810
|
-
const data = JSON.parse(
|
|
2358
|
+
if (existsSync7(deviceJsonPath)) {
|
|
2359
|
+
const data = JSON.parse(readFileSync7(deviceJsonPath, "utf8"));
|
|
1811
2360
|
if (data.deviceId) return data.deviceId;
|
|
1812
2361
|
}
|
|
1813
2362
|
} catch {
|
|
1814
2363
|
}
|
|
1815
2364
|
try {
|
|
1816
|
-
if (
|
|
1817
|
-
const id2 =
|
|
2365
|
+
if (existsSync7(DEVICE_ID_PATH)) {
|
|
2366
|
+
const id2 = readFileSync7(DEVICE_ID_PATH, "utf8").trim();
|
|
1818
2367
|
if (id2) return id2;
|
|
1819
2368
|
}
|
|
1820
2369
|
} catch {
|
|
1821
2370
|
}
|
|
1822
|
-
const id =
|
|
2371
|
+
const id = randomUUID2();
|
|
1823
2372
|
mkdirSync3(EXE_AI_DIR, { recursive: true });
|
|
1824
2373
|
writeFileSync4(DEVICE_ID_PATH, id, "utf8");
|
|
1825
2374
|
return id;
|
|
1826
2375
|
}
|
|
1827
2376
|
function loadLicense() {
|
|
1828
2377
|
try {
|
|
1829
|
-
if (!
|
|
1830
|
-
return
|
|
2378
|
+
if (!existsSync7(LICENSE_PATH)) return null;
|
|
2379
|
+
return readFileSync7(LICENSE_PATH, "utf8").trim();
|
|
1831
2380
|
} catch {
|
|
1832
2381
|
return null;
|
|
1833
2382
|
}
|
|
@@ -1860,8 +2409,8 @@ async function verifyLicenseJwt(token) {
|
|
|
1860
2409
|
}
|
|
1861
2410
|
async function getCachedLicense() {
|
|
1862
2411
|
try {
|
|
1863
|
-
if (!
|
|
1864
|
-
const raw = JSON.parse(
|
|
2412
|
+
if (!existsSync7(CACHE_PATH)) return null;
|
|
2413
|
+
const raw = JSON.parse(readFileSync7(CACHE_PATH, "utf8"));
|
|
1865
2414
|
if (!raw.token || typeof raw.token !== "string") return null;
|
|
1866
2415
|
return await verifyLicenseJwt(raw.token);
|
|
1867
2416
|
} catch {
|
|
@@ -1870,8 +2419,8 @@ async function getCachedLicense() {
|
|
|
1870
2419
|
}
|
|
1871
2420
|
function readCachedToken() {
|
|
1872
2421
|
try {
|
|
1873
|
-
if (!
|
|
1874
|
-
const raw = JSON.parse(
|
|
2422
|
+
if (!existsSync7(CACHE_PATH)) return null;
|
|
2423
|
+
const raw = JSON.parse(readFileSync7(CACHE_PATH, "utf8"));
|
|
1875
2424
|
return typeof raw.token === "string" ? raw.token : null;
|
|
1876
2425
|
} catch {
|
|
1877
2426
|
return null;
|
|
@@ -1958,8 +2507,8 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
1958
2507
|
}
|
|
1959
2508
|
function getCacheAgeMs() {
|
|
1960
2509
|
try {
|
|
1961
|
-
const { statSync } = __require("fs");
|
|
1962
|
-
const s =
|
|
2510
|
+
const { statSync: statSync2 } = __require("fs");
|
|
2511
|
+
const s = statSync2(CACHE_PATH);
|
|
1963
2512
|
return Date.now() - s.mtimeMs;
|
|
1964
2513
|
} catch {
|
|
1965
2514
|
return Infinity;
|
|
@@ -1969,9 +2518,9 @@ async function checkLicense() {
|
|
|
1969
2518
|
let key = loadLicense();
|
|
1970
2519
|
if (!key) {
|
|
1971
2520
|
try {
|
|
1972
|
-
const configPath =
|
|
1973
|
-
if (
|
|
1974
|
-
const raw = JSON.parse(
|
|
2521
|
+
const configPath = path6.join(EXE_AI_DIR, "config.json");
|
|
2522
|
+
if (existsSync7(configPath)) {
|
|
2523
|
+
const raw = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
1975
2524
|
const cloud = raw.cloud;
|
|
1976
2525
|
if (cloud?.apiKey) {
|
|
1977
2526
|
key = cloud.apiKey;
|
|
@@ -2130,9 +2679,9 @@ var init_license = __esm({
|
|
|
2130
2679
|
"src/lib/license.ts"() {
|
|
2131
2680
|
"use strict";
|
|
2132
2681
|
init_config();
|
|
2133
|
-
LICENSE_PATH =
|
|
2134
|
-
CACHE_PATH =
|
|
2135
|
-
DEVICE_ID_PATH =
|
|
2682
|
+
LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
|
|
2683
|
+
CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
|
|
2684
|
+
DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
|
|
2136
2685
|
API_BASE = "https://askexe.com/cloud";
|
|
2137
2686
|
RETRY_DELAY_MS = 500;
|
|
2138
2687
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
@@ -2162,12 +2711,12 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
2162
2711
|
});
|
|
2163
2712
|
|
|
2164
2713
|
// src/lib/plan-limits.ts
|
|
2165
|
-
import { readFileSync as
|
|
2166
|
-
import
|
|
2714
|
+
import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
|
|
2715
|
+
import path7 from "path";
|
|
2167
2716
|
function getLicenseSync() {
|
|
2168
2717
|
try {
|
|
2169
|
-
if (!
|
|
2170
|
-
const raw = JSON.parse(
|
|
2718
|
+
if (!existsSync8(CACHE_PATH2)) return freeLicense();
|
|
2719
|
+
const raw = JSON.parse(readFileSync8(CACHE_PATH2, "utf8"));
|
|
2171
2720
|
if (!raw.token || typeof raw.token !== "string") return freeLicense();
|
|
2172
2721
|
const parts = raw.token.split(".");
|
|
2173
2722
|
if (parts.length !== 3) return freeLicense();
|
|
@@ -2205,8 +2754,8 @@ function assertEmployeeLimitSync(rosterPath) {
|
|
|
2205
2754
|
const filePath = rosterPath ?? EMPLOYEES_PATH;
|
|
2206
2755
|
let count = 0;
|
|
2207
2756
|
try {
|
|
2208
|
-
if (
|
|
2209
|
-
const raw =
|
|
2757
|
+
if (existsSync8(filePath)) {
|
|
2758
|
+
const raw = readFileSync8(filePath, "utf8");
|
|
2210
2759
|
const employees = JSON.parse(raw);
|
|
2211
2760
|
count = Array.isArray(employees) ? employees.length : 0;
|
|
2212
2761
|
}
|
|
@@ -2235,19 +2784,19 @@ var init_plan_limits = __esm({
|
|
|
2235
2784
|
this.name = "PlanLimitError";
|
|
2236
2785
|
}
|
|
2237
2786
|
};
|
|
2238
|
-
CACHE_PATH2 =
|
|
2787
|
+
CACHE_PATH2 = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
2239
2788
|
}
|
|
2240
2789
|
});
|
|
2241
2790
|
|
|
2242
2791
|
// src/lib/notifications.ts
|
|
2243
2792
|
import crypto from "crypto";
|
|
2244
|
-
import
|
|
2793
|
+
import path8 from "path";
|
|
2245
2794
|
import os5 from "os";
|
|
2246
2795
|
import {
|
|
2247
|
-
readFileSync as
|
|
2796
|
+
readFileSync as readFileSync9,
|
|
2248
2797
|
readdirSync,
|
|
2249
|
-
unlinkSync as
|
|
2250
|
-
existsSync as
|
|
2798
|
+
unlinkSync as unlinkSync3,
|
|
2799
|
+
existsSync as existsSync9,
|
|
2251
2800
|
rmdirSync
|
|
2252
2801
|
} from "fs";
|
|
2253
2802
|
async function writeNotification(notification) {
|
|
@@ -2398,10 +2947,11 @@ __export(tasks_crud_exports, {
|
|
|
2398
2947
|
writeCheckpoint: () => writeCheckpoint
|
|
2399
2948
|
});
|
|
2400
2949
|
import crypto3 from "crypto";
|
|
2401
|
-
import
|
|
2950
|
+
import path9 from "path";
|
|
2951
|
+
import os6 from "os";
|
|
2402
2952
|
import { execSync as execSync5 } from "child_process";
|
|
2403
2953
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
2404
|
-
import { existsSync as
|
|
2954
|
+
import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
|
|
2405
2955
|
async function writeCheckpoint(input) {
|
|
2406
2956
|
const client = getClient();
|
|
2407
2957
|
const row = await resolveTask(client, input.taskId);
|
|
@@ -2442,6 +2992,35 @@ function extractParentFromContext(contextBody) {
|
|
|
2442
2992
|
function slugify(title) {
|
|
2443
2993
|
return title.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
2444
2994
|
}
|
|
2995
|
+
function buildKeywordIndex() {
|
|
2996
|
+
const idx = /* @__PURE__ */ new Map();
|
|
2997
|
+
for (const [role, keywords] of Object.entries(LANE_KEYWORDS)) {
|
|
2998
|
+
for (const kw of keywords) {
|
|
2999
|
+
const existing = idx.get(kw) ?? [];
|
|
3000
|
+
existing.push(role);
|
|
3001
|
+
idx.set(kw, existing);
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
return idx;
|
|
3005
|
+
}
|
|
3006
|
+
function checkLaneAffinity(title, context, assigneeName) {
|
|
3007
|
+
const employees = loadEmployeesSync();
|
|
3008
|
+
const employee = employees.find((e) => e.name === assigneeName);
|
|
3009
|
+
if (!employee) return void 0;
|
|
3010
|
+
const assigneeRole = employee.role;
|
|
3011
|
+
const text = `${title} ${context}`.toLowerCase();
|
|
3012
|
+
const matchedRoles = /* @__PURE__ */ new Set();
|
|
3013
|
+
for (const [keyword, roles] of KEYWORD_INDEX) {
|
|
3014
|
+
if (text.includes(keyword)) {
|
|
3015
|
+
for (const role of roles) matchedRoles.add(role);
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
if (matchedRoles.size === 0) return void 0;
|
|
3019
|
+
if (matchedRoles.has(assigneeRole)) return void 0;
|
|
3020
|
+
if (assigneeRole === "COO") return void 0;
|
|
3021
|
+
const expectedRoles = Array.from(matchedRoles).join(" or ");
|
|
3022
|
+
return `\u26A0\uFE0F Lane mismatch: task content suggests ${expectedRoles}, but assigned to ${assigneeName} (${assigneeRole}).`;
|
|
3023
|
+
}
|
|
2445
3024
|
async function resolveTask(client, identifier, scopeSession) {
|
|
2446
3025
|
const scope = sessionScopeFilter(scopeSession);
|
|
2447
3026
|
let result = await client.execute({
|
|
@@ -2491,7 +3070,14 @@ async function createTaskCore(input) {
|
|
|
2491
3070
|
const id = crypto3.randomUUID();
|
|
2492
3071
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2493
3072
|
const slug = slugify(input.title);
|
|
2494
|
-
|
|
3073
|
+
let earlySessionScope = null;
|
|
3074
|
+
try {
|
|
3075
|
+
const { resolveExeSession: resolveExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
3076
|
+
earlySessionScope = resolveExeSession2();
|
|
3077
|
+
} catch {
|
|
3078
|
+
}
|
|
3079
|
+
const scope = earlySessionScope ?? "default";
|
|
3080
|
+
const taskFile = input.taskFile ?? `tasks/${scope}/${input.assignedTo}/${slug}.md`;
|
|
2495
3081
|
let blockedById = null;
|
|
2496
3082
|
const initialStatus = input.blockedBy ? "blocked" : "open";
|
|
2497
3083
|
if (input.blockedBy) {
|
|
@@ -2531,22 +3117,24 @@ async function createTaskCore(input) {
|
|
|
2531
3117
|
if (dupCheck.rows.length > 0) {
|
|
2532
3118
|
warning = `similar active task already exists (${String(dupCheck.rows[0].id)}). Created new task anyway.`;
|
|
2533
3119
|
}
|
|
3120
|
+
if (!process.env.DISABLE_LANE_AFFINITY) {
|
|
3121
|
+
const laneWarning = checkLaneAffinity(input.title, input.context, input.assignedTo);
|
|
3122
|
+
if (laneWarning) {
|
|
3123
|
+
warning = warning ? `${warning}
|
|
3124
|
+
${laneWarning}` : laneWarning;
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
2534
3127
|
if (input.baseDir) {
|
|
2535
3128
|
try {
|
|
2536
|
-
await mkdir3(
|
|
2537
|
-
await mkdir3(
|
|
3129
|
+
await mkdir3(path9.join(input.baseDir, "exe", "output"), { recursive: true });
|
|
3130
|
+
await mkdir3(path9.join(input.baseDir, "exe", "research"), { recursive: true });
|
|
2538
3131
|
await ensureArchitectureDoc(input.baseDir, input.projectName);
|
|
2539
3132
|
await ensureGitignoreExe(input.baseDir);
|
|
2540
3133
|
} catch {
|
|
2541
3134
|
}
|
|
2542
3135
|
}
|
|
2543
3136
|
const complexity = input.complexity ?? "standard";
|
|
2544
|
-
|
|
2545
|
-
try {
|
|
2546
|
-
const { resolveExeSession: resolveExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
2547
|
-
sessionScope = resolveExeSession2();
|
|
2548
|
-
} catch {
|
|
2549
|
-
}
|
|
3137
|
+
const sessionScope = earlySessionScope;
|
|
2550
3138
|
await client.execute({
|
|
2551
3139
|
sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, created_at, updated_at)
|
|
2552
3140
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
@@ -2573,6 +3161,39 @@ async function createTaskCore(input) {
|
|
|
2573
3161
|
now
|
|
2574
3162
|
]
|
|
2575
3163
|
});
|
|
3164
|
+
if (input.baseDir) {
|
|
3165
|
+
try {
|
|
3166
|
+
const EXE_OS_DIR = path9.join(os6.homedir(), ".exe-os");
|
|
3167
|
+
const mdPath = path9.join(EXE_OS_DIR, taskFile);
|
|
3168
|
+
const mdDir = path9.dirname(mdPath);
|
|
3169
|
+
if (!existsSync10(mdDir)) await mkdir3(mdDir, { recursive: true });
|
|
3170
|
+
const reviewer = input.reviewer ?? input.assignedBy;
|
|
3171
|
+
const mdContent = `# ${input.title}
|
|
3172
|
+
|
|
3173
|
+
**ID:** ${id}
|
|
3174
|
+
**Status:** ${initialStatus}
|
|
3175
|
+
**Priority:** ${input.priority}
|
|
3176
|
+
**Assigned by:** ${input.assignedBy}
|
|
3177
|
+
**Assigned to:** ${input.assignedTo}
|
|
3178
|
+
**Project:** ${input.projectName}
|
|
3179
|
+
**Created:** ${now.split("T")[0]}${parentTaskId ? `
|
|
3180
|
+
**Parent task:** ${parentTaskId}` : ""}
|
|
3181
|
+
**Reviewer:** ${reviewer}
|
|
3182
|
+
|
|
3183
|
+
## Context
|
|
3184
|
+
|
|
3185
|
+
${input.context}
|
|
3186
|
+
|
|
3187
|
+
## MANDATORY: When done
|
|
3188
|
+
|
|
3189
|
+
You MUST call update_task with status "done" and a result summary when finished.
|
|
3190
|
+
If you skip this, your reviewer will not know you're done and your work won't be reviewed.
|
|
3191
|
+
Do NOT let a failed commit or any error prevent you from calling update_task(done).
|
|
3192
|
+
`;
|
|
3193
|
+
await writeFile3(mdPath, mdContent, "utf-8");
|
|
3194
|
+
} catch {
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
2576
3197
|
return {
|
|
2577
3198
|
id,
|
|
2578
3199
|
title: input.title,
|
|
@@ -2765,7 +3386,7 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
|
|
|
2765
3386
|
return { row, taskFile, now, taskId };
|
|
2766
3387
|
}
|
|
2767
3388
|
}
|
|
2768
|
-
if (curStatus === "in_progress" && input.callerAgentId && (input.callerAgentId === assignedBy || input.callerAgentId
|
|
3389
|
+
if (curStatus === "in_progress" && input.callerAgentId && (input.callerAgentId === assignedBy || isCoordinatorName(input.callerAgentId))) {
|
|
2769
3390
|
process.stderr.write(
|
|
2770
3391
|
`[tasks] Assigner override: ${input.callerAgentId} reclaiming ${taskId}
|
|
2771
3392
|
`
|
|
@@ -2830,9 +3451,9 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
2830
3451
|
return { taskFile, assignedTo, assignedBy, taskSlug };
|
|
2831
3452
|
}
|
|
2832
3453
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
2833
|
-
const archPath =
|
|
3454
|
+
const archPath = path9.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
2834
3455
|
try {
|
|
2835
|
-
if (
|
|
3456
|
+
if (existsSync10(archPath)) return;
|
|
2836
3457
|
const template = [
|
|
2837
3458
|
`# ${projectName} \u2014 System Architecture`,
|
|
2838
3459
|
"",
|
|
@@ -2865,10 +3486,10 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
2865
3486
|
}
|
|
2866
3487
|
}
|
|
2867
3488
|
async function ensureGitignoreExe(baseDir) {
|
|
2868
|
-
const gitignorePath =
|
|
3489
|
+
const gitignorePath = path9.join(baseDir, ".gitignore");
|
|
2869
3490
|
try {
|
|
2870
|
-
if (
|
|
2871
|
-
const content =
|
|
3491
|
+
if (existsSync10(gitignorePath)) {
|
|
3492
|
+
const content = readFileSync10(gitignorePath, "utf-8");
|
|
2872
3493
|
if (/^\/?exe\/?$/m.test(content)) return;
|
|
2873
3494
|
await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
|
|
2874
3495
|
} else {
|
|
@@ -2877,20 +3498,30 @@ async function ensureGitignoreExe(baseDir) {
|
|
|
2877
3498
|
} catch {
|
|
2878
3499
|
}
|
|
2879
3500
|
}
|
|
2880
|
-
var DELEGATION_KEYWORDS, TASK_ALREADY_CLAIMED_PREFIX;
|
|
3501
|
+
var LANE_KEYWORDS, KEYWORD_INDEX, DELEGATION_KEYWORDS, TASK_ALREADY_CLAIMED_PREFIX;
|
|
2881
3502
|
var init_tasks_crud = __esm({
|
|
2882
3503
|
"src/lib/tasks-crud.ts"() {
|
|
2883
3504
|
"use strict";
|
|
2884
3505
|
init_database();
|
|
2885
3506
|
init_task_scope();
|
|
3507
|
+
init_employees();
|
|
3508
|
+
LANE_KEYWORDS = {
|
|
3509
|
+
CMO: ["sales", "script", "pitch", "offer", "copy", "objection", "brand", "content", "seo", "marketing", "newsletter", "carousel", "social", "campaign"],
|
|
3510
|
+
CTO: ["spec", "architecture", "migration", "schema", "database", "design doc", "adr", "security audit", "tech stack"],
|
|
3511
|
+
"Principal Engineer": ["implement", "build", "fix", "commit", "refactor", "bug", "feature", "wire", "integration"],
|
|
3512
|
+
"Staff Code Reviewer": ["critique", "verdict", "review", "audit", "code quality"],
|
|
3513
|
+
"Content Production Specialist": ["render", "video", "image", "b-roll", "remotion", "animation", "thumbnail"],
|
|
3514
|
+
"AI Product Lead": ["competitive", "analysis", "benchmark", "compare", "scout", "evaluate", "poc"]
|
|
3515
|
+
};
|
|
3516
|
+
KEYWORD_INDEX = buildKeywordIndex();
|
|
2886
3517
|
DELEGATION_KEYWORDS = /parallel|delegate|wave|worktree|multi-instance/i;
|
|
2887
3518
|
TASK_ALREADY_CLAIMED_PREFIX = "TASK_ALREADY_CLAIMED";
|
|
2888
3519
|
}
|
|
2889
3520
|
});
|
|
2890
3521
|
|
|
2891
3522
|
// src/lib/tasks-review.ts
|
|
2892
|
-
import
|
|
2893
|
-
import { existsSync as
|
|
3523
|
+
import path10 from "path";
|
|
3524
|
+
import { existsSync as existsSync11, readdirSync as readdirSync2, unlinkSync as unlinkSync4 } from "fs";
|
|
2894
3525
|
async function countPendingReviews(sessionScope) {
|
|
2895
3526
|
const client = getClient();
|
|
2896
3527
|
if (sessionScope) {
|
|
@@ -2912,7 +3543,7 @@ async function countNewPendingReviewsSince(sinceIso, sessionScope) {
|
|
|
2912
3543
|
const result2 = await client.execute({
|
|
2913
3544
|
sql: `SELECT COUNT(*) as cnt FROM tasks
|
|
2914
3545
|
WHERE status = 'needs_review' AND updated_at > ?
|
|
2915
|
-
AND
|
|
3546
|
+
AND session_scope = ?`,
|
|
2916
3547
|
args: [sinceIso, sessionScope]
|
|
2917
3548
|
});
|
|
2918
3549
|
return Number(result2.rows[0]?.cnt) || 0;
|
|
@@ -2930,7 +3561,7 @@ async function listPendingReviews(limit, sessionScope) {
|
|
|
2930
3561
|
const result2 = await client.execute({
|
|
2931
3562
|
sql: `SELECT title, assigned_to, project_name FROM tasks
|
|
2932
3563
|
WHERE status = 'needs_review'
|
|
2933
|
-
AND
|
|
3564
|
+
AND session_scope = ?
|
|
2934
3565
|
ORDER BY priority ASC, created_at DESC LIMIT ?`,
|
|
2935
3566
|
args: [sessionScope, limit]
|
|
2936
3567
|
});
|
|
@@ -3051,14 +3682,14 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
3051
3682
|
if (parts.length >= 3 && parts[0] === "review") {
|
|
3052
3683
|
const agent = parts[1];
|
|
3053
3684
|
const slug = parts.slice(2).join("-");
|
|
3054
|
-
const
|
|
3685
|
+
const legacyTaskFile = `exe/${agent}/${slug}.md`;
|
|
3055
3686
|
const result = await client.execute({
|
|
3056
|
-
sql: "UPDATE tasks SET status = 'done', updated_at = ? WHERE task_file = ? AND status = 'needs_review'",
|
|
3057
|
-
args: [now,
|
|
3687
|
+
sql: "UPDATE tasks SET status = 'done', updated_at = ? WHERE (task_file = ? OR task_file LIKE ?) AND status = 'needs_review'",
|
|
3688
|
+
args: [now, legacyTaskFile, `tasks/%/${agent}/${slug}.md`]
|
|
3058
3689
|
});
|
|
3059
3690
|
if (result.rowsAffected > 0) {
|
|
3060
3691
|
process.stderr.write(
|
|
3061
|
-
`[review-cleanup] Cascaded original task to done
|
|
3692
|
+
`[review-cleanup] Cascaded original task to done: ${agent}/${slug}.md
|
|
3062
3693
|
`
|
|
3063
3694
|
);
|
|
3064
3695
|
}
|
|
@@ -3071,11 +3702,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
3071
3702
|
);
|
|
3072
3703
|
}
|
|
3073
3704
|
try {
|
|
3074
|
-
const cacheDir =
|
|
3075
|
-
if (
|
|
3705
|
+
const cacheDir = path10.join(EXE_AI_DIR, "session-cache");
|
|
3706
|
+
if (existsSync11(cacheDir)) {
|
|
3076
3707
|
for (const f of readdirSync2(cacheDir)) {
|
|
3077
3708
|
if (f.startsWith("review-notified-")) {
|
|
3078
|
-
|
|
3709
|
+
unlinkSync4(path10.join(cacheDir, f));
|
|
3079
3710
|
}
|
|
3080
3711
|
}
|
|
3081
3712
|
}
|
|
@@ -3096,7 +3727,7 @@ var init_tasks_review = __esm({
|
|
|
3096
3727
|
});
|
|
3097
3728
|
|
|
3098
3729
|
// src/lib/tasks-chain.ts
|
|
3099
|
-
import
|
|
3730
|
+
import path11 from "path";
|
|
3100
3731
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
3101
3732
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
3102
3733
|
const client = getClient();
|
|
@@ -3113,7 +3744,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
3113
3744
|
});
|
|
3114
3745
|
for (const ur of unblockedRows.rows) {
|
|
3115
3746
|
try {
|
|
3116
|
-
const ubFile =
|
|
3747
|
+
const ubFile = path11.join(baseDir, String(ur.task_file));
|
|
3117
3748
|
let ubContent = await readFile3(ubFile, "utf-8");
|
|
3118
3749
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
3119
3750
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -3182,7 +3813,7 @@ var init_tasks_chain = __esm({
|
|
|
3182
3813
|
|
|
3183
3814
|
// src/lib/project-name.ts
|
|
3184
3815
|
import { execSync as execSync6 } from "child_process";
|
|
3185
|
-
import
|
|
3816
|
+
import path12 from "path";
|
|
3186
3817
|
function getProjectName(cwd2) {
|
|
3187
3818
|
const dir = cwd2 ?? process.cwd();
|
|
3188
3819
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -3195,7 +3826,7 @@ function getProjectName(cwd2) {
|
|
|
3195
3826
|
timeout: 2e3,
|
|
3196
3827
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3197
3828
|
}).trim();
|
|
3198
|
-
repoRoot =
|
|
3829
|
+
repoRoot = path12.dirname(gitCommonDir);
|
|
3199
3830
|
} catch {
|
|
3200
3831
|
repoRoot = execSync6("git rev-parse --show-toplevel", {
|
|
3201
3832
|
cwd: dir,
|
|
@@ -3204,11 +3835,11 @@ function getProjectName(cwd2) {
|
|
|
3204
3835
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3205
3836
|
}).trim();
|
|
3206
3837
|
}
|
|
3207
|
-
_cached2 =
|
|
3838
|
+
_cached2 = path12.basename(repoRoot);
|
|
3208
3839
|
_cachedCwd = dir;
|
|
3209
3840
|
return _cached2;
|
|
3210
3841
|
} catch {
|
|
3211
|
-
_cached2 =
|
|
3842
|
+
_cached2 = path12.basename(dir);
|
|
3212
3843
|
_cachedCwd = dir;
|
|
3213
3844
|
return _cached2;
|
|
3214
3845
|
}
|
|
@@ -3240,7 +3871,7 @@ function findSessionForProject(projectName) {
|
|
|
3240
3871
|
const sessions = listSessions();
|
|
3241
3872
|
for (const s of sessions) {
|
|
3242
3873
|
const proj = s.projectDir.split("/").filter(Boolean).pop();
|
|
3243
|
-
if (proj === projectName &&
|
|
3874
|
+
if (proj === projectName && isCoordinatorName(s.agentId)) return s;
|
|
3244
3875
|
}
|
|
3245
3876
|
return null;
|
|
3246
3877
|
}
|
|
@@ -3286,7 +3917,7 @@ var init_session_scope = __esm({
|
|
|
3286
3917
|
|
|
3287
3918
|
// src/lib/tasks-notify.ts
|
|
3288
3919
|
async function dispatchTaskToEmployee(input) {
|
|
3289
|
-
if (
|
|
3920
|
+
if (isCoordinatorName(input.assignedTo)) return { dispatched: "skipped" };
|
|
3290
3921
|
let crossProject = false;
|
|
3291
3922
|
if (input.projectName) {
|
|
3292
3923
|
try {
|
|
@@ -3681,8 +4312,8 @@ __export(tasks_exports, {
|
|
|
3681
4312
|
updateTaskStatus: () => updateTaskStatus,
|
|
3682
4313
|
writeCheckpoint: () => writeCheckpoint
|
|
3683
4314
|
});
|
|
3684
|
-
import
|
|
3685
|
-
import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, unlinkSync as
|
|
4315
|
+
import path13 from "path";
|
|
4316
|
+
import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, unlinkSync as unlinkSync5 } from "fs";
|
|
3686
4317
|
async function createTask(input) {
|
|
3687
4318
|
const result = await createTaskCore(input);
|
|
3688
4319
|
if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
|
|
@@ -3701,14 +4332,14 @@ async function updateTask(input) {
|
|
|
3701
4332
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input);
|
|
3702
4333
|
try {
|
|
3703
4334
|
const agent = String(row.assigned_to);
|
|
3704
|
-
const cacheDir =
|
|
3705
|
-
const cachePath =
|
|
4335
|
+
const cacheDir = path13.join(EXE_AI_DIR, "session-cache");
|
|
4336
|
+
const cachePath = path13.join(cacheDir, `current-task-${agent}.json`);
|
|
3706
4337
|
if (input.status === "in_progress") {
|
|
3707
4338
|
mkdirSync4(cacheDir, { recursive: true });
|
|
3708
4339
|
writeFileSync5(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
3709
4340
|
} else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
|
|
3710
4341
|
try {
|
|
3711
|
-
|
|
4342
|
+
unlinkSync5(cachePath);
|
|
3712
4343
|
} catch {
|
|
3713
4344
|
}
|
|
3714
4345
|
}
|
|
@@ -3765,7 +4396,7 @@ async function updateTask(input) {
|
|
|
3765
4396
|
}
|
|
3766
4397
|
const isTerminal = input.status === "done" || input.status === "needs_review";
|
|
3767
4398
|
if (isTerminal) {
|
|
3768
|
-
const isCoordinator =
|
|
4399
|
+
const isCoordinator = isCoordinatorName(String(row.assigned_to));
|
|
3769
4400
|
if (!isCoordinator) {
|
|
3770
4401
|
notifyTaskDone();
|
|
3771
4402
|
}
|
|
@@ -3790,7 +4421,7 @@ async function updateTask(input) {
|
|
|
3790
4421
|
}
|
|
3791
4422
|
}
|
|
3792
4423
|
}
|
|
3793
|
-
if (input.status === "done" &&
|
|
4424
|
+
if (input.status === "done" && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
|
|
3794
4425
|
Promise.resolve().then(() => (init_skill_learning(), skill_learning_exports)).then(
|
|
3795
4426
|
({ captureAndLearn: captureAndLearn2 }) => captureAndLearn2({
|
|
3796
4427
|
taskId,
|
|
@@ -3806,7 +4437,7 @@ async function updateTask(input) {
|
|
|
3806
4437
|
});
|
|
3807
4438
|
}
|
|
3808
4439
|
let nextTask;
|
|
3809
|
-
if (isTerminal &&
|
|
4440
|
+
if (isTerminal && !isCoordinatorName(String(row.assigned_to))) {
|
|
3810
4441
|
try {
|
|
3811
4442
|
nextTask = await findNextTask(String(row.assigned_to));
|
|
3812
4443
|
} catch {
|
|
@@ -4150,7 +4781,7 @@ var init_capacity_monitor = __esm({
|
|
|
4150
4781
|
// src/lib/tmux-routing.ts
|
|
4151
4782
|
var tmux_routing_exports = {};
|
|
4152
4783
|
__export(tmux_routing_exports, {
|
|
4153
|
-
acquireSpawnLock: () =>
|
|
4784
|
+
acquireSpawnLock: () => acquireSpawnLock2,
|
|
4154
4785
|
employeeSessionName: () => employeeSessionName,
|
|
4155
4786
|
ensureEmployee: () => ensureEmployee,
|
|
4156
4787
|
extractRootExe: () => extractRootExe,
|
|
@@ -4165,20 +4796,20 @@ __export(tmux_routing_exports, {
|
|
|
4165
4796
|
notifyParentExe: () => notifyParentExe,
|
|
4166
4797
|
parseParentExe: () => parseParentExe,
|
|
4167
4798
|
registerParentExe: () => registerParentExe,
|
|
4168
|
-
releaseSpawnLock: () =>
|
|
4799
|
+
releaseSpawnLock: () => releaseSpawnLock2,
|
|
4169
4800
|
resolveExeSession: () => resolveExeSession,
|
|
4170
4801
|
sendIntercom: () => sendIntercom,
|
|
4171
4802
|
spawnEmployee: () => spawnEmployee,
|
|
4172
4803
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
4173
4804
|
});
|
|
4174
4805
|
import { execFileSync as execFileSync3, execSync as execSync7 } from "child_process";
|
|
4175
|
-
import { readFileSync as
|
|
4176
|
-
import
|
|
4177
|
-
import
|
|
4178
|
-
import { fileURLToPath } from "url";
|
|
4179
|
-
import { unlinkSync as
|
|
4806
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync12, appendFileSync } from "fs";
|
|
4807
|
+
import path14 from "path";
|
|
4808
|
+
import os7 from "os";
|
|
4809
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4810
|
+
import { unlinkSync as unlinkSync6 } from "fs";
|
|
4180
4811
|
function spawnLockPath(sessionName) {
|
|
4181
|
-
return
|
|
4812
|
+
return path14.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
4182
4813
|
}
|
|
4183
4814
|
function isProcessAlive(pid) {
|
|
4184
4815
|
try {
|
|
@@ -4188,14 +4819,14 @@ function isProcessAlive(pid) {
|
|
|
4188
4819
|
return false;
|
|
4189
4820
|
}
|
|
4190
4821
|
}
|
|
4191
|
-
function
|
|
4192
|
-
if (!
|
|
4822
|
+
function acquireSpawnLock2(sessionName) {
|
|
4823
|
+
if (!existsSync12(SPAWN_LOCK_DIR)) {
|
|
4193
4824
|
mkdirSync5(SPAWN_LOCK_DIR, { recursive: true });
|
|
4194
4825
|
}
|
|
4195
4826
|
const lockFile = spawnLockPath(sessionName);
|
|
4196
|
-
if (
|
|
4827
|
+
if (existsSync12(lockFile)) {
|
|
4197
4828
|
try {
|
|
4198
|
-
const lock = JSON.parse(
|
|
4829
|
+
const lock = JSON.parse(readFileSync11(lockFile, "utf8"));
|
|
4199
4830
|
const age = Date.now() - lock.timestamp;
|
|
4200
4831
|
if (isProcessAlive(lock.pid) && age < 6e4) {
|
|
4201
4832
|
return false;
|
|
@@ -4206,22 +4837,22 @@ function acquireSpawnLock(sessionName) {
|
|
|
4206
4837
|
writeFileSync6(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
|
|
4207
4838
|
return true;
|
|
4208
4839
|
}
|
|
4209
|
-
function
|
|
4840
|
+
function releaseSpawnLock2(sessionName) {
|
|
4210
4841
|
try {
|
|
4211
|
-
|
|
4842
|
+
unlinkSync6(spawnLockPath(sessionName));
|
|
4212
4843
|
} catch {
|
|
4213
4844
|
}
|
|
4214
4845
|
}
|
|
4215
4846
|
function resolveBehaviorsExporterScript() {
|
|
4216
4847
|
try {
|
|
4217
|
-
const thisFile =
|
|
4218
|
-
const scriptPath =
|
|
4219
|
-
|
|
4848
|
+
const thisFile = fileURLToPath2(import.meta.url);
|
|
4849
|
+
const scriptPath = path14.join(
|
|
4850
|
+
path14.dirname(thisFile),
|
|
4220
4851
|
"..",
|
|
4221
4852
|
"bin",
|
|
4222
4853
|
"exe-export-behaviors.js"
|
|
4223
4854
|
);
|
|
4224
|
-
return
|
|
4855
|
+
return existsSync12(scriptPath) ? scriptPath : null;
|
|
4225
4856
|
} catch {
|
|
4226
4857
|
return null;
|
|
4227
4858
|
}
|
|
@@ -4287,11 +4918,11 @@ function extractRootExe(name) {
|
|
|
4287
4918
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
4288
4919
|
}
|
|
4289
4920
|
function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
4290
|
-
if (!
|
|
4921
|
+
if (!existsSync12(SESSION_CACHE)) {
|
|
4291
4922
|
mkdirSync5(SESSION_CACHE, { recursive: true });
|
|
4292
4923
|
}
|
|
4293
4924
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
4294
|
-
const filePath =
|
|
4925
|
+
const filePath = path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
4295
4926
|
writeFileSync6(filePath, JSON.stringify({
|
|
4296
4927
|
parentExe: rootExe,
|
|
4297
4928
|
dispatchedBy: dispatchedBy || rootExe,
|
|
@@ -4300,7 +4931,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
4300
4931
|
}
|
|
4301
4932
|
function getParentExe(sessionKey) {
|
|
4302
4933
|
try {
|
|
4303
|
-
const data = JSON.parse(
|
|
4934
|
+
const data = JSON.parse(readFileSync11(path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
4304
4935
|
return data.parentExe || null;
|
|
4305
4936
|
} catch {
|
|
4306
4937
|
return null;
|
|
@@ -4308,8 +4939,8 @@ function getParentExe(sessionKey) {
|
|
|
4308
4939
|
}
|
|
4309
4940
|
function getDispatchedBy(sessionKey) {
|
|
4310
4941
|
try {
|
|
4311
|
-
const data = JSON.parse(
|
|
4312
|
-
|
|
4942
|
+
const data = JSON.parse(readFileSync11(
|
|
4943
|
+
path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
4313
4944
|
"utf8"
|
|
4314
4945
|
));
|
|
4315
4946
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -4335,10 +4966,10 @@ function isEmployeeAlive(sessionName) {
|
|
|
4335
4966
|
}
|
|
4336
4967
|
function findFreeInstance(employeeName, exeSession, maxInstances = 10, isAlive = isEmployeeAlive) {
|
|
4337
4968
|
const base = employeeSessionName(employeeName, exeSession);
|
|
4338
|
-
if (!isAlive(base) &&
|
|
4969
|
+
if (!isAlive(base) && acquireSpawnLock2(base)) return 0;
|
|
4339
4970
|
for (let i = 2; i <= maxInstances; i++) {
|
|
4340
4971
|
const candidate = employeeSessionName(employeeName, exeSession, i);
|
|
4341
|
-
if (!isAlive(candidate) &&
|
|
4972
|
+
if (!isAlive(candidate) && acquireSpawnLock2(candidate)) return i;
|
|
4342
4973
|
}
|
|
4343
4974
|
return null;
|
|
4344
4975
|
}
|
|
@@ -4370,15 +5001,15 @@ async function verifyPaneAtCapacity(sessionName) {
|
|
|
4370
5001
|
}
|
|
4371
5002
|
function readDebounceState() {
|
|
4372
5003
|
try {
|
|
4373
|
-
if (!
|
|
4374
|
-
return JSON.parse(
|
|
5004
|
+
if (!existsSync12(DEBOUNCE_FILE)) return {};
|
|
5005
|
+
return JSON.parse(readFileSync11(DEBOUNCE_FILE, "utf8"));
|
|
4375
5006
|
} catch {
|
|
4376
5007
|
return {};
|
|
4377
5008
|
}
|
|
4378
5009
|
}
|
|
4379
5010
|
function writeDebounceState(state) {
|
|
4380
5011
|
try {
|
|
4381
|
-
if (!
|
|
5012
|
+
if (!existsSync12(SESSION_CACHE)) mkdirSync5(SESSION_CACHE, { recursive: true });
|
|
4382
5013
|
writeFileSync6(DEBOUNCE_FILE, JSON.stringify(state));
|
|
4383
5014
|
} catch {
|
|
4384
5015
|
}
|
|
@@ -4498,7 +5129,7 @@ function notifyParentExe(sessionKey) {
|
|
|
4498
5129
|
return true;
|
|
4499
5130
|
}
|
|
4500
5131
|
function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
4501
|
-
if (
|
|
5132
|
+
if (isCoordinatorName(employeeName)) {
|
|
4502
5133
|
return { status: "failed", sessionName: "", error: "The COO is not a dispatchable employee" };
|
|
4503
5134
|
}
|
|
4504
5135
|
try {
|
|
@@ -4570,26 +5201,26 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4570
5201
|
const transport = getTransport();
|
|
4571
5202
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
4572
5203
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
4573
|
-
const logDir =
|
|
4574
|
-
const logFile =
|
|
4575
|
-
if (!
|
|
5204
|
+
const logDir = path14.join(os7.homedir(), ".exe-os", "session-logs");
|
|
5205
|
+
const logFile = path14.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
5206
|
+
if (!existsSync12(logDir)) {
|
|
4576
5207
|
mkdirSync5(logDir, { recursive: true });
|
|
4577
5208
|
}
|
|
4578
5209
|
transport.kill(sessionName);
|
|
4579
5210
|
let cleanupSuffix = "";
|
|
4580
5211
|
try {
|
|
4581
|
-
const thisFile =
|
|
4582
|
-
const cleanupScript =
|
|
4583
|
-
if (
|
|
5212
|
+
const thisFile = fileURLToPath2(import.meta.url);
|
|
5213
|
+
const cleanupScript = path14.join(path14.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
5214
|
+
if (existsSync12(cleanupScript)) {
|
|
4584
5215
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
4585
5216
|
}
|
|
4586
5217
|
} catch {
|
|
4587
5218
|
}
|
|
4588
5219
|
try {
|
|
4589
|
-
const claudeJsonPath =
|
|
5220
|
+
const claudeJsonPath = path14.join(os7.homedir(), ".claude.json");
|
|
4590
5221
|
let claudeJson = {};
|
|
4591
5222
|
try {
|
|
4592
|
-
claudeJson = JSON.parse(
|
|
5223
|
+
claudeJson = JSON.parse(readFileSync11(claudeJsonPath, "utf8"));
|
|
4593
5224
|
} catch {
|
|
4594
5225
|
}
|
|
4595
5226
|
if (!claudeJson.projects) claudeJson.projects = {};
|
|
@@ -4601,13 +5232,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4601
5232
|
} catch {
|
|
4602
5233
|
}
|
|
4603
5234
|
try {
|
|
4604
|
-
const settingsDir =
|
|
5235
|
+
const settingsDir = path14.join(os7.homedir(), ".claude", "projects");
|
|
4605
5236
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
4606
|
-
const projSettingsDir =
|
|
4607
|
-
const settingsPath =
|
|
5237
|
+
const projSettingsDir = path14.join(settingsDir, normalizedKey);
|
|
5238
|
+
const settingsPath = path14.join(projSettingsDir, "settings.json");
|
|
4608
5239
|
let settings = {};
|
|
4609
5240
|
try {
|
|
4610
|
-
settings = JSON.parse(
|
|
5241
|
+
settings = JSON.parse(readFileSync11(settingsPath, "utf8"));
|
|
4611
5242
|
} catch {
|
|
4612
5243
|
}
|
|
4613
5244
|
const perms = settings.permissions ?? {};
|
|
@@ -4648,8 +5279,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4648
5279
|
let behaviorsFlag = "";
|
|
4649
5280
|
let legacyFallbackWarned = false;
|
|
4650
5281
|
if (!useExeAgent && !useBinSymlink) {
|
|
4651
|
-
const identityPath =
|
|
4652
|
-
|
|
5282
|
+
const identityPath = path14.join(
|
|
5283
|
+
os7.homedir(),
|
|
4653
5284
|
".exe-os",
|
|
4654
5285
|
"identity",
|
|
4655
5286
|
`${employeeName}.md`
|
|
@@ -4658,13 +5289,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4658
5289
|
const hasAgentFlag = claudeSupportsAgentFlag();
|
|
4659
5290
|
if (hasAgentFlag) {
|
|
4660
5291
|
identityFlag = ` --agent ${employeeName}`;
|
|
4661
|
-
} else if (
|
|
5292
|
+
} else if (existsSync12(identityPath)) {
|
|
4662
5293
|
identityFlag = ` --append-system-prompt-file ${identityPath}`;
|
|
4663
5294
|
legacyFallbackWarned = true;
|
|
4664
5295
|
}
|
|
4665
5296
|
const behaviorsFile = exportBehaviorsSync(
|
|
4666
5297
|
employeeName,
|
|
4667
|
-
|
|
5298
|
+
path14.basename(spawnCwd),
|
|
4668
5299
|
sessionName
|
|
4669
5300
|
);
|
|
4670
5301
|
if (behaviorsFile) {
|
|
@@ -4679,9 +5310,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4679
5310
|
}
|
|
4680
5311
|
let sessionContextFlag = "";
|
|
4681
5312
|
try {
|
|
4682
|
-
const ctxDir =
|
|
5313
|
+
const ctxDir = path14.join(os7.homedir(), ".exe-os", "session-cache");
|
|
4683
5314
|
mkdirSync5(ctxDir, { recursive: true });
|
|
4684
|
-
const ctxFile =
|
|
5315
|
+
const ctxFile = path14.join(ctxDir, `session-context-${sessionName}.md`);
|
|
4685
5316
|
const ctxContent = [
|
|
4686
5317
|
`## Session Context`,
|
|
4687
5318
|
`You are running in tmux session: ${sessionName}.`,
|
|
@@ -4720,13 +5351,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4720
5351
|
command: spawnCommand
|
|
4721
5352
|
});
|
|
4722
5353
|
if (spawnResult.error) {
|
|
4723
|
-
|
|
5354
|
+
releaseSpawnLock2(sessionName);
|
|
4724
5355
|
return { sessionName, error: `tmux new-session failed: ${spawnResult.error}` };
|
|
4725
5356
|
}
|
|
4726
5357
|
transport.pipeLog(sessionName, logFile);
|
|
4727
5358
|
try {
|
|
4728
5359
|
const mySession = getMySession();
|
|
4729
|
-
const dispatchInfo =
|
|
5360
|
+
const dispatchInfo = path14.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
4730
5361
|
writeFileSync6(dispatchInfo, JSON.stringify({
|
|
4731
5362
|
dispatchedBy: mySession,
|
|
4732
5363
|
rootExe: exeSession,
|
|
@@ -4758,7 +5389,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4758
5389
|
}
|
|
4759
5390
|
}
|
|
4760
5391
|
if (!booted) {
|
|
4761
|
-
|
|
5392
|
+
releaseSpawnLock2(sessionName);
|
|
4762
5393
|
return { sessionName, error: `${useExeAgent ? "exe-agent" : "claude"} did not boot within 15s` };
|
|
4763
5394
|
}
|
|
4764
5395
|
if (!useExeAgent) {
|
|
@@ -4775,7 +5406,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4775
5406
|
pid: 0,
|
|
4776
5407
|
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4777
5408
|
});
|
|
4778
|
-
|
|
5409
|
+
releaseSpawnLock2(sessionName);
|
|
4779
5410
|
return { sessionName };
|
|
4780
5411
|
}
|
|
4781
5412
|
var SPAWN_LOCK_DIR, SESSION_CACHE, BEHAVIORS_EXPORT_TIMEOUT_MS, VALID_SESSION_NAME, VERIFY_PANE_LINES, INTERCOM_DEBOUNCE_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS, BUSY_PATTERN;
|
|
@@ -4791,14 +5422,14 @@ var init_tmux_routing = __esm({
|
|
|
4791
5422
|
init_intercom_queue();
|
|
4792
5423
|
init_plan_limits();
|
|
4793
5424
|
init_employees();
|
|
4794
|
-
SPAWN_LOCK_DIR =
|
|
4795
|
-
SESSION_CACHE =
|
|
5425
|
+
SPAWN_LOCK_DIR = path14.join(os7.homedir(), ".exe-os", "spawn-locks");
|
|
5426
|
+
SESSION_CACHE = path14.join(os7.homedir(), ".exe-os", "session-cache");
|
|
4796
5427
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
4797
5428
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
4798
5429
|
VERIFY_PANE_LINES = 200;
|
|
4799
5430
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
4800
|
-
INTERCOM_LOG2 =
|
|
4801
|
-
DEBOUNCE_FILE =
|
|
5431
|
+
INTERCOM_LOG2 = path14.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
5432
|
+
DEBOUNCE_FILE = path14.join(SESSION_CACHE, "intercom-debounce.json");
|
|
4802
5433
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
4803
5434
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
4804
5435
|
}
|
|
@@ -6191,7 +6822,7 @@ __export(global_procedures_exports, {
|
|
|
6191
6822
|
loadGlobalProcedures: () => loadGlobalProcedures,
|
|
6192
6823
|
storeGlobalProcedure: () => storeGlobalProcedure
|
|
6193
6824
|
});
|
|
6194
|
-
import { randomUUID as
|
|
6825
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
6195
6826
|
async function loadGlobalProcedures() {
|
|
6196
6827
|
const client = getClient();
|
|
6197
6828
|
const result = await client.execute({
|
|
@@ -6220,7 +6851,7 @@ ${sections.join("\n\n")}
|
|
|
6220
6851
|
`;
|
|
6221
6852
|
}
|
|
6222
6853
|
async function storeGlobalProcedure(input) {
|
|
6223
|
-
const id =
|
|
6854
|
+
const id = randomUUID3();
|
|
6224
6855
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6225
6856
|
const client = getClient();
|
|
6226
6857
|
await client.execute({
|
|
@@ -6358,7 +6989,7 @@ var init_anthropic = __esm({
|
|
|
6358
6989
|
|
|
6359
6990
|
// src/gateway/providers/openai-compat.ts
|
|
6360
6991
|
import OpenAI from "openai";
|
|
6361
|
-
import { randomUUID as
|
|
6992
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
6362
6993
|
var OpenAICompatProvider;
|
|
6363
6994
|
var init_openai_compat = __esm({
|
|
6364
6995
|
"src/gateway/providers/openai-compat.ts"() {
|
|
@@ -6475,7 +7106,7 @@ var init_openai_compat = __esm({
|
|
|
6475
7106
|
}
|
|
6476
7107
|
content.push({
|
|
6477
7108
|
type: "tool_use",
|
|
6478
|
-
id: call.id ??
|
|
7109
|
+
id: call.id ?? randomUUID4(),
|
|
6479
7110
|
name: fn.name,
|
|
6480
7111
|
input
|
|
6481
7112
|
});
|
|
@@ -6667,10 +7298,10 @@ var init_hooks = __esm({
|
|
|
6667
7298
|
});
|
|
6668
7299
|
|
|
6669
7300
|
// src/runtime/safety-checks.ts
|
|
6670
|
-
import
|
|
6671
|
-
import
|
|
7301
|
+
import path15 from "path";
|
|
7302
|
+
import os8 from "os";
|
|
6672
7303
|
function checkPathSafety(filePath) {
|
|
6673
|
-
const resolved =
|
|
7304
|
+
const resolved = path15.resolve(filePath);
|
|
6674
7305
|
for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
|
|
6675
7306
|
const matches = typeof pattern === "function" ? pattern(resolved) : pattern.test(resolved);
|
|
6676
7307
|
if (matches) {
|
|
@@ -6680,7 +7311,7 @@ function checkPathSafety(filePath) {
|
|
|
6680
7311
|
return { safe: true, bypassImmune: true };
|
|
6681
7312
|
}
|
|
6682
7313
|
function checkReadPathSafety(filePath) {
|
|
6683
|
-
const resolved =
|
|
7314
|
+
const resolved = path15.resolve(filePath);
|
|
6684
7315
|
const credPatterns = BYPASS_IMMUNE_PATTERNS.filter(
|
|
6685
7316
|
(p) => typeof p.pattern !== "function" && (p.reason.includes("secrets") || p.reason.includes("Private key") || p.reason.includes("Credential"))
|
|
6686
7317
|
);
|
|
@@ -6695,7 +7326,7 @@ var HOME, BYPASS_IMMUNE_PATTERNS;
|
|
|
6695
7326
|
var init_safety_checks = __esm({
|
|
6696
7327
|
"src/runtime/safety-checks.ts"() {
|
|
6697
7328
|
"use strict";
|
|
6698
|
-
HOME =
|
|
7329
|
+
HOME = os8.homedir();
|
|
6699
7330
|
BYPASS_IMMUNE_PATTERNS = [
|
|
6700
7331
|
{
|
|
6701
7332
|
pattern: /\/\.git\/hooks\//,
|
|
@@ -6706,11 +7337,11 @@ var init_safety_checks = __esm({
|
|
|
6706
7337
|
reason: "Git config can set hooks and command execution"
|
|
6707
7338
|
},
|
|
6708
7339
|
{
|
|
6709
|
-
pattern: (p) => p.startsWith(
|
|
7340
|
+
pattern: (p) => p.startsWith(path15.join(HOME, ".claude")),
|
|
6710
7341
|
reason: "Claude configuration files are protected"
|
|
6711
7342
|
},
|
|
6712
7343
|
{
|
|
6713
|
-
pattern: (p) => p.startsWith(
|
|
7344
|
+
pattern: (p) => p.startsWith(path15.join(HOME, ".exe-os")),
|
|
6714
7345
|
reason: "exe-os configuration files are protected"
|
|
6715
7346
|
},
|
|
6716
7347
|
{
|
|
@@ -6727,7 +7358,7 @@ var init_safety_checks = __esm({
|
|
|
6727
7358
|
},
|
|
6728
7359
|
{
|
|
6729
7360
|
pattern: (p) => {
|
|
6730
|
-
const name =
|
|
7361
|
+
const name = path15.basename(p);
|
|
6731
7362
|
return [".bashrc", ".zshrc", ".profile", ".bash_profile", ".zprofile", ".zshenv"].includes(name);
|
|
6732
7363
|
},
|
|
6733
7364
|
reason: "Shell configuration files can execute arbitrary code on login"
|
|
@@ -6754,7 +7385,7 @@ __export(file_read_exports, {
|
|
|
6754
7385
|
FileReadTool: () => FileReadTool
|
|
6755
7386
|
});
|
|
6756
7387
|
import fs3 from "fs/promises";
|
|
6757
|
-
import
|
|
7388
|
+
import path16 from "path";
|
|
6758
7389
|
import { z } from "zod";
|
|
6759
7390
|
function isBinary(buf) {
|
|
6760
7391
|
for (let i = 0; i < buf.length; i++) {
|
|
@@ -6790,7 +7421,7 @@ var init_file_read = __esm({
|
|
|
6790
7421
|
return { behavior: "allow" };
|
|
6791
7422
|
},
|
|
6792
7423
|
async call(input, context) {
|
|
6793
|
-
const filePath =
|
|
7424
|
+
const filePath = path16.isAbsolute(input.file_path) ? input.file_path : path16.resolve(context.cwd, input.file_path);
|
|
6794
7425
|
let stat;
|
|
6795
7426
|
try {
|
|
6796
7427
|
stat = await fs3.stat(filePath);
|
|
@@ -6830,7 +7461,7 @@ __export(glob_exports, {
|
|
|
6830
7461
|
GlobTool: () => GlobTool
|
|
6831
7462
|
});
|
|
6832
7463
|
import fs4 from "fs/promises";
|
|
6833
|
-
import
|
|
7464
|
+
import path17 from "path";
|
|
6834
7465
|
import { z as z2 } from "zod";
|
|
6835
7466
|
async function walkDir(dir, maxDepth = 10) {
|
|
6836
7467
|
const results = [];
|
|
@@ -6846,7 +7477,7 @@ async function walkDir(dir, maxDepth = 10) {
|
|
|
6846
7477
|
if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git")) {
|
|
6847
7478
|
continue;
|
|
6848
7479
|
}
|
|
6849
|
-
const fullPath =
|
|
7480
|
+
const fullPath = path17.join(current, entry.name);
|
|
6850
7481
|
if (entry.isDirectory()) {
|
|
6851
7482
|
await walk(fullPath, depth + 1);
|
|
6852
7483
|
} else {
|
|
@@ -6880,11 +7511,11 @@ var init_glob = __esm({
|
|
|
6880
7511
|
inputSchema: inputSchema2,
|
|
6881
7512
|
isReadOnly: true,
|
|
6882
7513
|
async call(input, context) {
|
|
6883
|
-
const baseDir = input.path ?
|
|
7514
|
+
const baseDir = input.path ? path17.isAbsolute(input.path) ? input.path : path17.resolve(context.cwd, input.path) : context.cwd;
|
|
6884
7515
|
try {
|
|
6885
7516
|
const entries = await walkDir(baseDir);
|
|
6886
7517
|
const matched = entries.filter(
|
|
6887
|
-
(e) => simpleGlobMatch(
|
|
7518
|
+
(e) => simpleGlobMatch(path17.relative(baseDir, e.path), input.pattern)
|
|
6888
7519
|
);
|
|
6889
7520
|
matched.sort((a, b) => b.mtime - a.mtime);
|
|
6890
7521
|
if (matched.length === 0) {
|
|
@@ -6908,9 +7539,9 @@ var grep_exports = {};
|
|
|
6908
7539
|
__export(grep_exports, {
|
|
6909
7540
|
GrepTool: () => GrepTool
|
|
6910
7541
|
});
|
|
6911
|
-
import { spawn } from "child_process";
|
|
7542
|
+
import { spawn as spawn2 } from "child_process";
|
|
6912
7543
|
import fs5 from "fs/promises";
|
|
6913
|
-
import
|
|
7544
|
+
import path18 from "path";
|
|
6914
7545
|
import { z as z3 } from "zod";
|
|
6915
7546
|
function runRipgrep(input, searchPath, context) {
|
|
6916
7547
|
return new Promise((resolve, reject) => {
|
|
@@ -6922,7 +7553,7 @@ function runRipgrep(input, searchPath, context) {
|
|
|
6922
7553
|
args.push("--glob", input.include);
|
|
6923
7554
|
}
|
|
6924
7555
|
args.push(input.pattern, searchPath);
|
|
6925
|
-
const child =
|
|
7556
|
+
const child = spawn2("rg", args, {
|
|
6926
7557
|
cwd: searchPath,
|
|
6927
7558
|
timeout: 3e4,
|
|
6928
7559
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -6964,7 +7595,7 @@ async function nodeGrep(input, searchPath) {
|
|
|
6964
7595
|
}
|
|
6965
7596
|
for (const entry of entries) {
|
|
6966
7597
|
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
6967
|
-
const fullPath =
|
|
7598
|
+
const fullPath = path18.join(dir, entry.name);
|
|
6968
7599
|
if (entry.isDirectory()) {
|
|
6969
7600
|
await walk(fullPath);
|
|
6970
7601
|
} else {
|
|
@@ -7010,7 +7641,7 @@ var init_grep = __esm({
|
|
|
7010
7641
|
inputSchema: inputSchema3,
|
|
7011
7642
|
isReadOnly: true,
|
|
7012
7643
|
async call(input, context) {
|
|
7013
|
-
const searchPath = input.path ?
|
|
7644
|
+
const searchPath = input.path ? path18.isAbsolute(input.path) ? input.path : path18.resolve(context.cwd, input.path) : context.cwd;
|
|
7014
7645
|
try {
|
|
7015
7646
|
const result = await runRipgrep(input, searchPath, context);
|
|
7016
7647
|
return result;
|
|
@@ -7035,7 +7666,7 @@ __export(file_write_exports, {
|
|
|
7035
7666
|
FileWriteTool: () => FileWriteTool
|
|
7036
7667
|
});
|
|
7037
7668
|
import fs6 from "fs/promises";
|
|
7038
|
-
import
|
|
7669
|
+
import path19 from "path";
|
|
7039
7670
|
import { z as z4 } from "zod";
|
|
7040
7671
|
var inputSchema4, FileWriteTool;
|
|
7041
7672
|
var init_file_write = __esm({
|
|
@@ -7063,8 +7694,8 @@ var init_file_write = __esm({
|
|
|
7063
7694
|
return { behavior: "allow" };
|
|
7064
7695
|
},
|
|
7065
7696
|
async call(input, context) {
|
|
7066
|
-
const filePath =
|
|
7067
|
-
const dir =
|
|
7697
|
+
const filePath = path19.isAbsolute(input.file_path) ? input.file_path : path19.resolve(context.cwd, input.file_path);
|
|
7698
|
+
const dir = path19.dirname(filePath);
|
|
7068
7699
|
await fs6.mkdir(dir, { recursive: true });
|
|
7069
7700
|
await fs6.writeFile(filePath, input.content, "utf-8");
|
|
7070
7701
|
return {
|
|
@@ -7082,7 +7713,7 @@ __export(file_edit_exports, {
|
|
|
7082
7713
|
FileEditTool: () => FileEditTool
|
|
7083
7714
|
});
|
|
7084
7715
|
import fs7 from "fs/promises";
|
|
7085
|
-
import
|
|
7716
|
+
import path20 from "path";
|
|
7086
7717
|
import { z as z5 } from "zod";
|
|
7087
7718
|
function countOccurrences(haystack, needle) {
|
|
7088
7719
|
let count = 0;
|
|
@@ -7123,7 +7754,7 @@ var init_file_edit = __esm({
|
|
|
7123
7754
|
return { behavior: "allow" };
|
|
7124
7755
|
},
|
|
7125
7756
|
async call(input, context) {
|
|
7126
|
-
const filePath =
|
|
7757
|
+
const filePath = path20.isAbsolute(input.file_path) ? input.file_path : path20.resolve(context.cwd, input.file_path);
|
|
7127
7758
|
let content;
|
|
7128
7759
|
try {
|
|
7129
7760
|
content = await fs7.readFile(filePath, "utf-8");
|
|
@@ -7280,7 +7911,7 @@ var bash_exports = {};
|
|
|
7280
7911
|
__export(bash_exports, {
|
|
7281
7912
|
BashTool: () => BashTool
|
|
7282
7913
|
});
|
|
7283
|
-
import { spawn as
|
|
7914
|
+
import { spawn as spawn3 } from "child_process";
|
|
7284
7915
|
import { z as z6 } from "zod";
|
|
7285
7916
|
var DEFAULT_TIMEOUT_MS, inputSchema6, BashTool;
|
|
7286
7917
|
var init_bash = __esm({
|
|
@@ -7311,7 +7942,7 @@ var init_bash = __esm({
|
|
|
7311
7942
|
async call(input, context) {
|
|
7312
7943
|
const timeout = input.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
7313
7944
|
return new Promise((resolve) => {
|
|
7314
|
-
const child =
|
|
7945
|
+
const child = spawn3("bash", ["-c", input.command], {
|
|
7315
7946
|
cwd: context.cwd,
|
|
7316
7947
|
timeout,
|
|
7317
7948
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -7363,7 +7994,7 @@ var init_bash = __esm({
|
|
|
7363
7994
|
});
|
|
7364
7995
|
|
|
7365
7996
|
// src/lib/task-router.ts
|
|
7366
|
-
import { randomUUID as
|
|
7997
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
7367
7998
|
function resolveBloomRouting(complexity, config = DEFAULT_BLOOM_CONFIG) {
|
|
7368
7999
|
const tier = config.complexityToTier[complexity];
|
|
7369
8000
|
const rule = config.tierRules[tier];
|
|
@@ -7788,14 +8419,14 @@ __export(keychain_exports, {
|
|
|
7788
8419
|
setMasterKey: () => setMasterKey
|
|
7789
8420
|
});
|
|
7790
8421
|
import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
|
|
7791
|
-
import { existsSync as
|
|
7792
|
-
import
|
|
7793
|
-
import
|
|
8422
|
+
import { existsSync as existsSync13 } from "fs";
|
|
8423
|
+
import path23 from "path";
|
|
8424
|
+
import os9 from "os";
|
|
7794
8425
|
function getKeyDir() {
|
|
7795
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
8426
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path23.join(os9.homedir(), ".exe-os");
|
|
7796
8427
|
}
|
|
7797
8428
|
function getKeyPath() {
|
|
7798
|
-
return
|
|
8429
|
+
return path23.join(getKeyDir(), "master.key");
|
|
7799
8430
|
}
|
|
7800
8431
|
async function tryKeytar() {
|
|
7801
8432
|
try {
|
|
@@ -7816,13 +8447,21 @@ async function getMasterKey() {
|
|
|
7816
8447
|
}
|
|
7817
8448
|
}
|
|
7818
8449
|
const keyPath = getKeyPath();
|
|
7819
|
-
if (!
|
|
8450
|
+
if (!existsSync13(keyPath)) {
|
|
8451
|
+
process.stderr.write(
|
|
8452
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os9.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
8453
|
+
`
|
|
8454
|
+
);
|
|
7820
8455
|
return null;
|
|
7821
8456
|
}
|
|
7822
8457
|
try {
|
|
7823
8458
|
const content = await readFile4(keyPath, "utf-8");
|
|
7824
8459
|
return Buffer.from(content.trim(), "base64");
|
|
7825
|
-
} catch {
|
|
8460
|
+
} catch (err) {
|
|
8461
|
+
process.stderr.write(
|
|
8462
|
+
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
8463
|
+
`
|
|
8464
|
+
);
|
|
7826
8465
|
return null;
|
|
7827
8466
|
}
|
|
7828
8467
|
}
|
|
@@ -7851,7 +8490,7 @@ async function deleteMasterKey() {
|
|
|
7851
8490
|
}
|
|
7852
8491
|
}
|
|
7853
8492
|
const keyPath = getKeyPath();
|
|
7854
|
-
if (
|
|
8493
|
+
if (existsSync13(keyPath)) {
|
|
7855
8494
|
await unlink(keyPath);
|
|
7856
8495
|
}
|
|
7857
8496
|
}
|
|
@@ -8151,14 +8790,14 @@ __export(wiki_client_exports, {
|
|
|
8151
8790
|
listDocuments: () => listDocuments,
|
|
8152
8791
|
listWorkspaces: () => listWorkspaces
|
|
8153
8792
|
});
|
|
8154
|
-
async function wikiFetch(config,
|
|
8155
|
-
const url = `${config.baseUrl}/api/v1${
|
|
8793
|
+
async function wikiFetch(config, path25, method = "GET", body) {
|
|
8794
|
+
const url = `${config.baseUrl}/api/v1${path25}`;
|
|
8156
8795
|
const headers = {
|
|
8157
8796
|
Authorization: `Bearer ${config.apiKey}`,
|
|
8158
8797
|
"Content-Type": "application/json"
|
|
8159
8798
|
};
|
|
8160
8799
|
const controller = new AbortController();
|
|
8161
|
-
const timeout = setTimeout(() => controller.abort(),
|
|
8800
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
|
|
8162
8801
|
try {
|
|
8163
8802
|
let response;
|
|
8164
8803
|
try {
|
|
@@ -8171,7 +8810,7 @@ async function wikiFetch(config, path24, method = "GET", body) {
|
|
|
8171
8810
|
} catch {
|
|
8172
8811
|
clearTimeout(timeout);
|
|
8173
8812
|
const retryController = new AbortController();
|
|
8174
|
-
const retryTimeout = setTimeout(() => retryController.abort(),
|
|
8813
|
+
const retryTimeout = setTimeout(() => retryController.abort(), REQUEST_TIMEOUT_MS2);
|
|
8175
8814
|
try {
|
|
8176
8815
|
await new Promise((r) => setTimeout(r, 500));
|
|
8177
8816
|
response = await fetch(url, {
|
|
@@ -8185,7 +8824,7 @@ async function wikiFetch(config, path24, method = "GET", body) {
|
|
|
8185
8824
|
}
|
|
8186
8825
|
}
|
|
8187
8826
|
if (!response.ok) {
|
|
8188
|
-
throw new Error(`Wiki API ${method} ${
|
|
8827
|
+
throw new Error(`Wiki API ${method} ${path25}: ${response.status} ${response.statusText}`);
|
|
8189
8828
|
}
|
|
8190
8829
|
return response.json();
|
|
8191
8830
|
} finally {
|
|
@@ -8275,12 +8914,12 @@ async function getChatHistory(client, workspaceSlug, limit = 50) {
|
|
|
8275
8914
|
sentAt: h.sentAt ?? 0
|
|
8276
8915
|
}));
|
|
8277
8916
|
}
|
|
8278
|
-
var LOCAL_WIKI_URL,
|
|
8917
|
+
var LOCAL_WIKI_URL, REQUEST_TIMEOUT_MS2;
|
|
8279
8918
|
var init_wiki_client = __esm({
|
|
8280
8919
|
"src/lib/wiki-client.ts"() {
|
|
8281
8920
|
"use strict";
|
|
8282
|
-
LOCAL_WIKI_URL = "http://localhost:3001";
|
|
8283
|
-
|
|
8921
|
+
LOCAL_WIKI_URL = process.env.EXE_WIKI_URL || "http://localhost:3001";
|
|
8922
|
+
REQUEST_TIMEOUT_MS2 = 8e3;
|
|
8284
8923
|
}
|
|
8285
8924
|
});
|
|
8286
8925
|
|
|
@@ -8306,12 +8945,12 @@ __export(shard_manager_exports, {
|
|
|
8306
8945
|
listShards: () => listShards,
|
|
8307
8946
|
shardExists: () => shardExists
|
|
8308
8947
|
});
|
|
8309
|
-
import
|
|
8310
|
-
import { existsSync as
|
|
8948
|
+
import path24 from "path";
|
|
8949
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync6, readdirSync as readdirSync3 } from "fs";
|
|
8311
8950
|
import { createClient as createClient2 } from "@libsql/client";
|
|
8312
8951
|
function initShardManager(encryptionKey) {
|
|
8313
8952
|
_encryptionKey = encryptionKey;
|
|
8314
|
-
if (!
|
|
8953
|
+
if (!existsSync14(SHARDS_DIR)) {
|
|
8315
8954
|
mkdirSync6(SHARDS_DIR, { recursive: true });
|
|
8316
8955
|
}
|
|
8317
8956
|
_shardingEnabled = true;
|
|
@@ -8332,7 +8971,7 @@ function getShardClient(projectName) {
|
|
|
8332
8971
|
}
|
|
8333
8972
|
const cached = _shards.get(safeName);
|
|
8334
8973
|
if (cached) return cached;
|
|
8335
|
-
const dbPath =
|
|
8974
|
+
const dbPath = path24.join(SHARDS_DIR, `${safeName}.db`);
|
|
8336
8975
|
const client = createClient2({
|
|
8337
8976
|
url: `file:${dbPath}`,
|
|
8338
8977
|
encryptionKey: _encryptionKey
|
|
@@ -8342,10 +8981,10 @@ function getShardClient(projectName) {
|
|
|
8342
8981
|
}
|
|
8343
8982
|
function shardExists(projectName) {
|
|
8344
8983
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8345
|
-
return
|
|
8984
|
+
return existsSync14(path24.join(SHARDS_DIR, `${safeName}.db`));
|
|
8346
8985
|
}
|
|
8347
8986
|
function listShards() {
|
|
8348
|
-
if (!
|
|
8987
|
+
if (!existsSync14(SHARDS_DIR)) return [];
|
|
8349
8988
|
return readdirSync3(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
8350
8989
|
}
|
|
8351
8990
|
async function ensureShardSchema(client) {
|
|
@@ -8531,7 +9170,7 @@ var init_shard_manager = __esm({
|
|
|
8531
9170
|
"src/lib/shard-manager.ts"() {
|
|
8532
9171
|
"use strict";
|
|
8533
9172
|
init_config();
|
|
8534
|
-
SHARDS_DIR =
|
|
9173
|
+
SHARDS_DIR = path24.join(EXE_AI_DIR, "shards");
|
|
8535
9174
|
_shards = /* @__PURE__ */ new Map();
|
|
8536
9175
|
_encryptionKey = null;
|
|
8537
9176
|
_shardingEnabled = false;
|
|
@@ -8555,6 +9194,7 @@ __export(store_exports, {
|
|
|
8555
9194
|
vectorToBlob: () => vectorToBlob,
|
|
8556
9195
|
writeMemory: () => writeMemory
|
|
8557
9196
|
});
|
|
9197
|
+
import { createHash } from "crypto";
|
|
8558
9198
|
function isBusyError2(err) {
|
|
8559
9199
|
if (err instanceof Error) {
|
|
8560
9200
|
const msg = err.message.toLowerCase();
|
|
@@ -8628,12 +9268,52 @@ function classifyTier(record) {
|
|
|
8628
9268
|
if (["store_memory", "manual"].includes(record.tool_name ?? "") && (record.importance ?? 0) >= 5) return 2;
|
|
8629
9269
|
return 3;
|
|
8630
9270
|
}
|
|
9271
|
+
function inferFilePaths(record) {
|
|
9272
|
+
if (!["Read", "Write", "Edit"].includes(record.tool_name)) return null;
|
|
9273
|
+
const firstLine = record.raw_text.split("\n")[0] ?? "";
|
|
9274
|
+
const match = firstLine.match(/(\/[\w./-]+\.\w+)/);
|
|
9275
|
+
return match ? JSON.stringify([match[1]]) : null;
|
|
9276
|
+
}
|
|
9277
|
+
function inferCommitHash(record) {
|
|
9278
|
+
if (record.tool_name !== "Bash") return null;
|
|
9279
|
+
const match = record.raw_text.match(/\b([a-f0-9]{7,40})\b/);
|
|
9280
|
+
return match ? match[1] : null;
|
|
9281
|
+
}
|
|
9282
|
+
function inferLanguageType(record) {
|
|
9283
|
+
const text = record.raw_text;
|
|
9284
|
+
if (!text || text.length < 10) return null;
|
|
9285
|
+
const trimmed = text.trimStart();
|
|
9286
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) return "json";
|
|
9287
|
+
if (/\b(SELECT|INSERT|UPDATE|DELETE|CREATE TABLE|ALTER TABLE)\b/i.test(text)) return "sql";
|
|
9288
|
+
if (/\b(function |const |import |export |class |def |async |=>)\b/.test(text)) return "code";
|
|
9289
|
+
if (trimmed.startsWith("#") || trimmed.startsWith("*")) return "prose";
|
|
9290
|
+
return "mixed";
|
|
9291
|
+
}
|
|
9292
|
+
function inferDomain(record) {
|
|
9293
|
+
const proj = (record.project_name ?? "").toLowerCase();
|
|
9294
|
+
if (proj.includes("marketing") || proj.includes("content")) return "marketing";
|
|
9295
|
+
if (proj.includes("crm") || proj.includes("customer")) return "customer";
|
|
9296
|
+
return null;
|
|
9297
|
+
}
|
|
8631
9298
|
async function writeMemory(record) {
|
|
8632
9299
|
if (record.vector !== null && record.vector.length !== EMBEDDING_DIM) {
|
|
8633
9300
|
throw new Error(
|
|
8634
9301
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
8635
9302
|
);
|
|
8636
9303
|
}
|
|
9304
|
+
const contentHash = createHash("md5").update(record.raw_text).digest("hex");
|
|
9305
|
+
if (_pendingRecords.some((r) => r.content_hash === contentHash && r.agent_id === record.agent_id)) {
|
|
9306
|
+
return;
|
|
9307
|
+
}
|
|
9308
|
+
try {
|
|
9309
|
+
const client = getClient();
|
|
9310
|
+
const existing = await client.execute({
|
|
9311
|
+
sql: "SELECT id FROM memories WHERE content_hash = ? AND agent_id = ? LIMIT 1",
|
|
9312
|
+
args: [contentHash, record.agent_id]
|
|
9313
|
+
});
|
|
9314
|
+
if (existing.rows.length > 0) return;
|
|
9315
|
+
} catch {
|
|
9316
|
+
}
|
|
8637
9317
|
const dbRow = {
|
|
8638
9318
|
id: record.id,
|
|
8639
9319
|
agent_id: record.agent_id,
|
|
@@ -8663,7 +9343,23 @@ async function writeMemory(record) {
|
|
|
8663
9343
|
supersedes_id: record.supersedes_id ?? null,
|
|
8664
9344
|
draft: record.draft ? 1 : 0,
|
|
8665
9345
|
memory_type: record.memory_type ?? "raw",
|
|
8666
|
-
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null
|
|
9346
|
+
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
9347
|
+
content_hash: contentHash,
|
|
9348
|
+
intent: record.intent ?? null,
|
|
9349
|
+
outcome: record.outcome ?? null,
|
|
9350
|
+
domain: record.domain ?? inferDomain(record),
|
|
9351
|
+
referenced_entities: record.referenced_entities ?? null,
|
|
9352
|
+
retrieval_count: record.retrieval_count ?? 0,
|
|
9353
|
+
chain_position: record.chain_position ?? null,
|
|
9354
|
+
review_status: record.review_status ?? null,
|
|
9355
|
+
context_window_pct: record.context_window_pct ?? null,
|
|
9356
|
+
file_paths: record.file_paths ?? inferFilePaths(record),
|
|
9357
|
+
commit_hash: record.commit_hash ?? inferCommitHash(record),
|
|
9358
|
+
duration_ms: record.duration_ms ?? null,
|
|
9359
|
+
token_cost: record.token_cost ?? null,
|
|
9360
|
+
audience: record.audience ?? null,
|
|
9361
|
+
language_type: record.language_type ?? inferLanguageType(record),
|
|
9362
|
+
parent_memory_id: record.parent_memory_id ?? null
|
|
8667
9363
|
};
|
|
8668
9364
|
_pendingRecords.push(dbRow);
|
|
8669
9365
|
orgBus.emit({
|
|
@@ -8721,80 +9417,85 @@ async function flushBatch() {
|
|
|
8721
9417
|
const draft = row.draft ? 1 : 0;
|
|
8722
9418
|
const memoryType = row.memory_type ?? "raw";
|
|
8723
9419
|
const trajectory = row.trajectory ?? null;
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
9420
|
+
const contentHash = row.content_hash ?? null;
|
|
9421
|
+
const intent = row.intent ?? null;
|
|
9422
|
+
const outcome = row.outcome ?? null;
|
|
9423
|
+
const domain = row.domain ?? null;
|
|
9424
|
+
const referencedEntities = row.referenced_entities ?? null;
|
|
9425
|
+
const retrievalCount = row.retrieval_count ?? 0;
|
|
9426
|
+
const chainPosition = row.chain_position ?? null;
|
|
9427
|
+
const reviewStatus = row.review_status ?? null;
|
|
9428
|
+
const contextWindowPct = row.context_window_pct ?? null;
|
|
9429
|
+
const filePaths = row.file_paths ?? null;
|
|
9430
|
+
const commitHash = row.commit_hash ?? null;
|
|
9431
|
+
const durationMs = row.duration_ms ?? null;
|
|
9432
|
+
const tokenCost = row.token_cost ?? null;
|
|
9433
|
+
const audience = row.audience ?? null;
|
|
9434
|
+
const languageType = row.language_type ?? null;
|
|
9435
|
+
const parentMemoryId = row.parent_memory_id ?? null;
|
|
9436
|
+
const cols = `id, agent_id, agent_role, session_id, timestamp,
|
|
8727
9437
|
tool_name, project_name,
|
|
8728
9438
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
8729
9439
|
confidence, last_accessed,
|
|
8730
9440
|
workspace_id, document_id, user_id, char_offset, page_number,
|
|
8731
|
-
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory
|
|
8732
|
-
|
|
8733
|
-
|
|
8734
|
-
|
|
8735
|
-
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
|
|
8740
|
-
|
|
8741
|
-
|
|
8742
|
-
|
|
8743
|
-
|
|
8744
|
-
|
|
8745
|
-
|
|
8746
|
-
|
|
8747
|
-
|
|
8748
|
-
|
|
8749
|
-
|
|
8750
|
-
|
|
8751
|
-
|
|
8752
|
-
|
|
8753
|
-
|
|
8754
|
-
|
|
8755
|
-
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
8766
|
-
|
|
8767
|
-
|
|
8768
|
-
|
|
8769
|
-
|
|
8770
|
-
|
|
8771
|
-
|
|
8772
|
-
|
|
8773
|
-
|
|
8774
|
-
|
|
8775
|
-
|
|
8776
|
-
|
|
8777
|
-
|
|
8778
|
-
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
|
|
8782
|
-
|
|
8783
|
-
|
|
8784
|
-
|
|
8785
|
-
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
pageNumber,
|
|
8790
|
-
sourcePath,
|
|
8791
|
-
sourceType,
|
|
8792
|
-
tier,
|
|
8793
|
-
supersedesId,
|
|
8794
|
-
draft,
|
|
8795
|
-
memoryType,
|
|
8796
|
-
trajectory
|
|
8797
|
-
]
|
|
9441
|
+
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
|
|
9442
|
+
intent, outcome, domain, referenced_entities, retrieval_count,
|
|
9443
|
+
chain_position, review_status, context_window_pct, file_paths, commit_hash,
|
|
9444
|
+
duration_ms, token_cost, audience, language_type, parent_memory_id`;
|
|
9445
|
+
const metaArgs = [
|
|
9446
|
+
intent,
|
|
9447
|
+
outcome,
|
|
9448
|
+
domain,
|
|
9449
|
+
referencedEntities,
|
|
9450
|
+
retrievalCount,
|
|
9451
|
+
chainPosition,
|
|
9452
|
+
reviewStatus,
|
|
9453
|
+
contextWindowPct,
|
|
9454
|
+
filePaths,
|
|
9455
|
+
commitHash,
|
|
9456
|
+
durationMs,
|
|
9457
|
+
tokenCost,
|
|
9458
|
+
audience,
|
|
9459
|
+
languageType,
|
|
9460
|
+
parentMemoryId
|
|
9461
|
+
];
|
|
9462
|
+
const baseArgs = [
|
|
9463
|
+
row.id,
|
|
9464
|
+
row.agent_id,
|
|
9465
|
+
row.agent_role,
|
|
9466
|
+
row.session_id,
|
|
9467
|
+
row.timestamp,
|
|
9468
|
+
row.tool_name,
|
|
9469
|
+
row.project_name,
|
|
9470
|
+
row.has_error,
|
|
9471
|
+
row.raw_text
|
|
9472
|
+
];
|
|
9473
|
+
const sharedArgs = [
|
|
9474
|
+
row.version,
|
|
9475
|
+
taskId,
|
|
9476
|
+
importance,
|
|
9477
|
+
status,
|
|
9478
|
+
confidence,
|
|
9479
|
+
lastAccessed,
|
|
9480
|
+
workspaceId,
|
|
9481
|
+
documentId,
|
|
9482
|
+
userId,
|
|
9483
|
+
charOffset,
|
|
9484
|
+
pageNumber,
|
|
9485
|
+
sourcePath,
|
|
9486
|
+
sourceType,
|
|
9487
|
+
tier,
|
|
9488
|
+
supersedesId,
|
|
9489
|
+
draft,
|
|
9490
|
+
memoryType,
|
|
9491
|
+
trajectory,
|
|
9492
|
+
contentHash
|
|
9493
|
+
];
|
|
9494
|
+
return {
|
|
9495
|
+
sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
|
|
9496
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
|
|
9497
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
9498
|
+
args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
|
|
8798
9499
|
};
|
|
8799
9500
|
};
|
|
8800
9501
|
const globalClient = getClient();
|
|
@@ -13039,8 +13740,8 @@ function Text({ color, backgroundColor, dimColor = false, bold = false, italic =
|
|
|
13039
13740
|
}
|
|
13040
13741
|
|
|
13041
13742
|
// src/tui/ink/components/ErrorOverview.js
|
|
13042
|
-
var cleanupPath = (
|
|
13043
|
-
return
|
|
13743
|
+
var cleanupPath = (path25) => {
|
|
13744
|
+
return path25?.replace(`file://${cwd()}/`, "");
|
|
13044
13745
|
};
|
|
13045
13746
|
var stackUtils = new StackUtils({
|
|
13046
13747
|
cwd: cwd(),
|
|
@@ -14639,7 +15340,7 @@ var useInput = (inputHandler, options = {}) => {
|
|
|
14639
15340
|
if (options.isActive === false) {
|
|
14640
15341
|
return;
|
|
14641
15342
|
}
|
|
14642
|
-
const
|
|
15343
|
+
const handleData2 = (data) => {
|
|
14643
15344
|
const keypress = parse_keypress_default(data);
|
|
14644
15345
|
const key = {
|
|
14645
15346
|
upArrow: keypress.name === "up",
|
|
@@ -14698,9 +15399,9 @@ var useInput = (inputHandler, options = {}) => {
|
|
|
14698
15399
|
});
|
|
14699
15400
|
}
|
|
14700
15401
|
};
|
|
14701
|
-
internal_eventEmitter?.on("input",
|
|
15402
|
+
internal_eventEmitter?.on("input", handleData2);
|
|
14702
15403
|
return () => {
|
|
14703
|
-
internal_eventEmitter?.removeListener("input",
|
|
15404
|
+
internal_eventEmitter?.removeListener("input", handleData2);
|
|
14704
15405
|
};
|
|
14705
15406
|
}, [options.isActive, stdin, internal_exitOnCtrlC, inputHandler]);
|
|
14706
15407
|
};
|
|
@@ -14972,11 +15673,11 @@ function Footer() {
|
|
|
14972
15673
|
} catch {
|
|
14973
15674
|
}
|
|
14974
15675
|
try {
|
|
14975
|
-
const { existsSync:
|
|
15676
|
+
const { existsSync: existsSync15 } = await import("fs");
|
|
14976
15677
|
const { join } = await import("path");
|
|
14977
15678
|
const home = process.env.HOME ?? "";
|
|
14978
15679
|
const pidPath = join(home, ".exe-os", "exed.pid");
|
|
14979
|
-
setDaemon(
|
|
15680
|
+
setDaemon(existsSync15(pidPath) ? "running" : "stopped");
|
|
14980
15681
|
} catch {
|
|
14981
15682
|
setDaemon("unknown");
|
|
14982
15683
|
}
|
|
@@ -15058,7 +15759,7 @@ function Footer() {
|
|
|
15058
15759
|
// src/tui/views/CommandCenter.tsx
|
|
15059
15760
|
import { useState as useState6, useEffect as useEffect8, useMemo as useMemo4, useCallback as useCallback4, useRef as useRef4 } from "react";
|
|
15060
15761
|
import TextInput from "ink-text-input";
|
|
15061
|
-
import
|
|
15762
|
+
import path21 from "path";
|
|
15062
15763
|
import { homedir } from "os";
|
|
15063
15764
|
|
|
15064
15765
|
// src/tui/components/StatusDot.tsx
|
|
@@ -15845,15 +16546,15 @@ function CommandCenterView({
|
|
|
15845
16546
|
const { createPermissionsFromPreset: createPermissionsFromPreset2, EMPLOYEE_PERMISSIONS: EMPLOYEE_PERMISSIONS2 } = await Promise.resolve().then(() => (init_permissions(), permissions_exports));
|
|
15846
16547
|
const { getPresetByRole: getPresetByRole2 } = await Promise.resolve().then(() => (init_permission_presets(), permission_presets_exports));
|
|
15847
16548
|
const { createDefaultHooks: createDefaultHooks2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
|
|
15848
|
-
const { readFileSync:
|
|
16549
|
+
const { readFileSync: readFileSync12, existsSync: existsSync15 } = await import("fs");
|
|
15849
16550
|
const { join } = await import("path");
|
|
15850
16551
|
const { homedir: homedir3 } = await import("os");
|
|
15851
16552
|
const configPath = join(homedir3(), ".exe-os", "config.json");
|
|
15852
16553
|
let failoverChain = ["anthropic", "opencode", "gemini", "openai"];
|
|
15853
16554
|
let providerConfigs = {};
|
|
15854
|
-
if (
|
|
16555
|
+
if (existsSync15(configPath)) {
|
|
15855
16556
|
try {
|
|
15856
|
-
const raw = JSON.parse(
|
|
16557
|
+
const raw = JSON.parse(readFileSync12(configPath, "utf8"));
|
|
15857
16558
|
if (Array.isArray(raw.failoverChain)) failoverChain = raw.failoverChain;
|
|
15858
16559
|
if (raw.providers && typeof raw.providers === "object") {
|
|
15859
16560
|
providerConfigs = raw.providers;
|
|
@@ -15914,7 +16615,7 @@ function CommandCenterView({
|
|
|
15914
16615
|
const markerDir = join(homedir3(), ".exe-os", "session-cache");
|
|
15915
16616
|
const agentFiles = (await import("fs")).readdirSync(markerDir).filter((f) => f.startsWith("active-agent-"));
|
|
15916
16617
|
for (const f of agentFiles) {
|
|
15917
|
-
const data = JSON.parse(
|
|
16618
|
+
const data = JSON.parse(readFileSync12(join(markerDir, f), "utf8"));
|
|
15918
16619
|
if (data.agentRole) {
|
|
15919
16620
|
agentRole = data.agentRole;
|
|
15920
16621
|
break;
|
|
@@ -16059,7 +16760,7 @@ function CommandCenterView({
|
|
|
16059
16760
|
const demoEntries = DEMO_PROJECTS.map((p) => ({
|
|
16060
16761
|
projectName: p.projectName,
|
|
16061
16762
|
exeSession: p.exeSession,
|
|
16062
|
-
projectDir:
|
|
16763
|
+
projectDir: path21.join(homedir(), p.projectName),
|
|
16063
16764
|
employeeCount: p.employees.length,
|
|
16064
16765
|
activeCount: p.employees.filter((e) => e.status === "active").length,
|
|
16065
16766
|
memoryCount: p.employees.length * 4e3,
|
|
@@ -16097,7 +16798,7 @@ function CommandCenterView({
|
|
|
16097
16798
|
const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
|
|
16098
16799
|
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
16099
16800
|
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
16100
|
-
const { existsSync:
|
|
16801
|
+
const { existsSync: existsSync15 } = await import("fs");
|
|
16101
16802
|
const { join } = await import("path");
|
|
16102
16803
|
const client = getClient2();
|
|
16103
16804
|
if (!client) {
|
|
@@ -16142,12 +16843,12 @@ function CommandCenterView({
|
|
|
16142
16843
|
const registry = listSessions2();
|
|
16143
16844
|
const tmuxSessions = inTmux2() ? new Set(listTmuxSessions2()) : /* @__PURE__ */ new Set();
|
|
16144
16845
|
const roster = await loadEmployees2();
|
|
16145
|
-
const { getCoordinatorName: getCoordinatorName2, isCoordinatorRole: isCoordinatorRole2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
16846
|
+
const { getCoordinatorName: getCoordinatorName2, isCoordinatorName: isCoordinatorName2, isCoordinatorRole: isCoordinatorRole2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
16146
16847
|
const coordinatorName = getCoordinatorName2(roster);
|
|
16147
16848
|
const employeeNames = roster.filter((e) => !isCoordinatorRole2(e.role)).map((e) => e.name);
|
|
16148
16849
|
const projectSessions = /* @__PURE__ */ new Map();
|
|
16149
16850
|
for (const entry of registry) {
|
|
16150
|
-
if ((entry.agentId === coordinatorName || entry.agentId
|
|
16851
|
+
if ((entry.agentId === coordinatorName || isCoordinatorName2(entry.agentId)) && tmuxSessions.has(entry.windowName)) {
|
|
16151
16852
|
const projName = entry.projectDir.split("/").filter(Boolean).pop() ?? "";
|
|
16152
16853
|
if (projName) {
|
|
16153
16854
|
projectSessions.set(projName, { exeSession: entry.windowName, projectDir: entry.projectDir });
|
|
@@ -16168,7 +16869,7 @@ function CommandCenterView({
|
|
|
16168
16869
|
}
|
|
16169
16870
|
const memoryCount = memoryCounts.get(name) ?? 0;
|
|
16170
16871
|
const openTaskCount = openTaskCounts.get(name) ?? 0;
|
|
16171
|
-
const hasGit = projectDir ?
|
|
16872
|
+
const hasGit = projectDir ? existsSync15(join(projectDir, ".git")) : false;
|
|
16172
16873
|
const type = hasGit ? "code" : memoryCount > 0 ? "code" : "automation";
|
|
16173
16874
|
projectList.push({
|
|
16174
16875
|
projectName: name,
|
|
@@ -16193,7 +16894,7 @@ function CommandCenterView({
|
|
|
16193
16894
|
setHealth((h) => ({ ...h, memories: Number(totalResult.rows[0]?.cnt ?? 0) }));
|
|
16194
16895
|
try {
|
|
16195
16896
|
const pidPath = join(process.env.HOME ?? "", ".exe-os", "exed.pid");
|
|
16196
|
-
setHealth((h) => ({ ...h, daemon:
|
|
16897
|
+
setHealth((h) => ({ ...h, daemon: existsSync15(pidPath) ? "running" : "stopped" }));
|
|
16197
16898
|
} catch {
|
|
16198
16899
|
}
|
|
16199
16900
|
const activityResult = await client.execute(
|
|
@@ -16408,7 +17109,7 @@ function ChatMessageRow({ msg }) {
|
|
|
16408
17109
|
|
|
16409
17110
|
// src/tui/views/Sessions.tsx
|
|
16410
17111
|
import React19, { useState as useState9, useEffect as useEffect11, useCallback as useCallback6 } from "react";
|
|
16411
|
-
import
|
|
17112
|
+
import path22 from "path";
|
|
16412
17113
|
import { homedir as homedir2 } from "os";
|
|
16413
17114
|
|
|
16414
17115
|
// src/tui/components/TmuxPane.tsx
|
|
@@ -16671,12 +17372,13 @@ function useOrchestrator(enabled = true) {
|
|
|
16671
17372
|
}
|
|
16672
17373
|
|
|
16673
17374
|
// src/tui/views/Sessions.tsx
|
|
17375
|
+
init_employees();
|
|
16674
17376
|
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
16675
17377
|
var SESSION_REFRESH_MS = 5e3;
|
|
16676
17378
|
var ACTIVE_PANE_PATTERN = /█|░|Calculating|tokens|writing|Reading/;
|
|
16677
17379
|
var ACTIVITY_PREVIEW_MAX = 50;
|
|
16678
17380
|
function isCoordinatorEntry(entry) {
|
|
16679
|
-
return entry.role.toLowerCase() === "coo" || entry.name
|
|
17381
|
+
return entry.role.toLowerCase() === "coo" || isCoordinatorName(entry.name);
|
|
16680
17382
|
}
|
|
16681
17383
|
function SessionsView({
|
|
16682
17384
|
initialProject,
|
|
@@ -16710,7 +17412,7 @@ function SessionsView({
|
|
|
16710
17412
|
if (demo) {
|
|
16711
17413
|
setProjects(DEMO_PROJECTS.map((p) => ({
|
|
16712
17414
|
...p,
|
|
16713
|
-
projectDir:
|
|
17415
|
+
projectDir: path22.join(homedir2(), p.projectName),
|
|
16714
17416
|
employees: p.employees.map((e) => ({ ...e, attached: e.status === "active" }))
|
|
16715
17417
|
})));
|
|
16716
17418
|
return;
|
|
@@ -16900,7 +17602,7 @@ function SessionsView({
|
|
|
16900
17602
|
const coordinatorName = getCoordinatorName2(roster);
|
|
16901
17603
|
const exeSessions = /* @__PURE__ */ new Map();
|
|
16902
17604
|
for (const entry of registry) {
|
|
16903
|
-
if ((entry.agentId === coordinatorName || entry.agentId
|
|
17605
|
+
if ((entry.agentId === coordinatorName || isCoordinatorName(entry.agentId)) && tmuxSessions.has(entry.windowName)) {
|
|
16904
17606
|
exeSessions.set(entry.windowName, entry.projectDir);
|
|
16905
17607
|
}
|
|
16906
17608
|
}
|
|
@@ -17607,12 +18309,12 @@ async function loadGatewayConfig() {
|
|
|
17607
18309
|
state.running = false;
|
|
17608
18310
|
}
|
|
17609
18311
|
try {
|
|
17610
|
-
const { existsSync:
|
|
18312
|
+
const { existsSync: existsSync15, readFileSync: readFileSync12 } = await import("fs");
|
|
17611
18313
|
const { join } = await import("path");
|
|
17612
18314
|
const home = process.env.HOME ?? "";
|
|
17613
18315
|
const configPath = join(home, ".exe-os", "gateway.json");
|
|
17614
|
-
if (
|
|
17615
|
-
const raw = JSON.parse(
|
|
18316
|
+
if (existsSync15(configPath)) {
|
|
18317
|
+
const raw = JSON.parse(readFileSync12(configPath, "utf8"));
|
|
17616
18318
|
state.port = raw.port ?? 3100;
|
|
17617
18319
|
state.gatewayUrl = raw.gatewayUrl ?? "";
|
|
17618
18320
|
if (raw.adapters) {
|
|
@@ -18138,12 +18840,12 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
18138
18840
|
setMembers(teamData);
|
|
18139
18841
|
setDbError(null);
|
|
18140
18842
|
try {
|
|
18141
|
-
const { existsSync:
|
|
18843
|
+
const { existsSync: existsSync15, readFileSync: readFileSync12 } = await import("fs");
|
|
18142
18844
|
const { join } = await import("path");
|
|
18143
18845
|
const home = process.env.HOME ?? "";
|
|
18144
18846
|
const gatewayConfig = join(home, ".exe-os", "gateway.json");
|
|
18145
|
-
if (
|
|
18146
|
-
const raw = JSON.parse(
|
|
18847
|
+
if (existsSync15(gatewayConfig)) {
|
|
18848
|
+
const raw = JSON.parse(readFileSync12(gatewayConfig, "utf8"));
|
|
18147
18849
|
if (raw.agents && raw.agents.length > 0) {
|
|
18148
18850
|
setExternals(raw.agents.map((a) => ({
|
|
18149
18851
|
name: a.name,
|
|
@@ -18807,12 +19509,12 @@ function SettingsView({ onBack }) {
|
|
|
18807
19509
|
}
|
|
18808
19510
|
setProviders(providerList);
|
|
18809
19511
|
try {
|
|
18810
|
-
const { existsSync:
|
|
19512
|
+
const { existsSync: existsSync15 } = await import("fs");
|
|
18811
19513
|
const { join } = await import("path");
|
|
18812
19514
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
18813
19515
|
const cfg = await loadConfig2();
|
|
18814
19516
|
const home = process.env.HOME ?? "";
|
|
18815
|
-
const hasKey =
|
|
19517
|
+
const hasKey = existsSync15(join(home, ".exe-os", "master.key"));
|
|
18816
19518
|
if (cfg.cloud) {
|
|
18817
19519
|
setCloud({
|
|
18818
19520
|
configured: true,
|
|
@@ -18825,22 +19527,22 @@ function SettingsView({ onBack }) {
|
|
|
18825
19527
|
const pidPath = join(home, ".exe-os", "exed.pid");
|
|
18826
19528
|
let daemon = "unknown";
|
|
18827
19529
|
try {
|
|
18828
|
-
daemon =
|
|
19530
|
+
daemon = existsSync15(pidPath) ? "running" : "stopped";
|
|
18829
19531
|
} catch {
|
|
18830
19532
|
}
|
|
18831
19533
|
let version = "unknown";
|
|
18832
19534
|
try {
|
|
18833
|
-
const { readFileSync:
|
|
19535
|
+
const { readFileSync: readFileSync12 } = await import("fs");
|
|
18834
19536
|
const { createRequire } = await import("module");
|
|
18835
19537
|
const require2 = createRequire(import.meta.url);
|
|
18836
19538
|
const pkgPath = require2.resolve("@askexenow/exe-os/package.json");
|
|
18837
|
-
const pkg = JSON.parse(
|
|
19539
|
+
const pkg = JSON.parse(readFileSync12(pkgPath, "utf8"));
|
|
18838
19540
|
version = pkg.version;
|
|
18839
19541
|
} catch {
|
|
18840
19542
|
try {
|
|
18841
|
-
const { readFileSync:
|
|
19543
|
+
const { readFileSync: readFileSync12 } = await import("fs");
|
|
18842
19544
|
const { join: joinPath } = await import("path");
|
|
18843
|
-
const pkg = JSON.parse(
|
|
19545
|
+
const pkg = JSON.parse(readFileSync12(joinPath(process.cwd(), "package.json"), "utf8"));
|
|
18844
19546
|
version = pkg.version;
|
|
18845
19547
|
} catch {
|
|
18846
19548
|
}
|