@askexenow/exe-os 0.9.0 → 0.9.2
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/cli.js +127 -34
- package/dist/bin/exe-agent-config.js +1 -1
- package/dist/bin/exe-boot.js +89 -5
- package/dist/bin/exe-call.js +1 -1
- package/dist/bin/exe-dispatch.js +96 -6
- package/dist/bin/exe-doctor.js +55 -2
- package/dist/bin/exe-gateway.js +89 -5
- package/dist/bin/exe-new-employee.js +17 -13
- package/dist/bin/exe-session-cleanup.js +91 -1
- package/dist/bin/exe-settings.js +1 -1
- package/dist/bin/exe-start-codex.js +12 -8
- package/dist/bin/git-sweep.js +96 -6
- package/dist/bin/install.js +17 -13
- package/dist/bin/scan-tasks.js +96 -6
- package/dist/bin/update.js +3 -2
- package/dist/gateway/index.js +95 -5
- package/dist/hooks/bug-report-worker.js +91 -1
- package/dist/hooks/commit-complete.js +96 -6
- package/dist/hooks/error-recall.js +14 -0
- package/dist/hooks/ingest-worker.js +85 -1
- package/dist/hooks/ingest.js +11 -0
- package/dist/hooks/pre-compact.js +96 -6
- package/dist/hooks/prompt-submit.js +18 -1
- package/dist/hooks/session-end.js +96 -6
- package/dist/hooks/stop.js +18 -0
- package/dist/index.js +94 -10
- package/dist/lib/agent-config.js +1 -1
- package/dist/lib/exe-daemon.js +18 -1
- package/dist/lib/tasks.js +91 -1
- package/dist/lib/tmux-routing.js +91 -1
- package/dist/mcp/server.js +955 -224
- package/dist/mcp/tools/create-task.js +91 -1
- package/dist/mcp/tools/update-task.js +91 -1
- package/dist/runtime/index.js +90 -6
- package/dist/tui/App.js +90 -6
- package/package.json +1 -1
package/dist/mcp/server.js
CHANGED
|
@@ -698,10 +698,10 @@ async function disposeEmbedder() {
|
|
|
698
698
|
async function embedDirect(text) {
|
|
699
699
|
const llamaCpp = await import("node-llama-cpp");
|
|
700
700
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
701
|
-
const { existsSync:
|
|
702
|
-
const
|
|
703
|
-
const modelPath =
|
|
704
|
-
if (!
|
|
701
|
+
const { existsSync: existsSync32 } = await import("fs");
|
|
702
|
+
const path40 = await import("path");
|
|
703
|
+
const modelPath = path40.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
704
|
+
if (!existsSync32(modelPath)) {
|
|
705
705
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
706
706
|
}
|
|
707
707
|
const llama = await llamaCpp.getLlama();
|
|
@@ -6108,7 +6108,7 @@ var init_agent_config = __esm({
|
|
|
6108
6108
|
AGENT_CONFIG_PATH = path16.join(EXE_AI_DIR, "agent-config.json");
|
|
6109
6109
|
KNOWN_RUNTIMES = {
|
|
6110
6110
|
claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
6111
|
-
codex: ["gpt-5.4", "gpt-5.5", "o3", "o4-mini"],
|
|
6111
|
+
codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
|
|
6112
6112
|
opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
|
|
6113
6113
|
};
|
|
6114
6114
|
RUNTIME_LABELS = {
|
|
@@ -6125,6 +6125,14 @@ var init_agent_config = __esm({
|
|
|
6125
6125
|
});
|
|
6126
6126
|
|
|
6127
6127
|
// src/lib/intercom-queue.ts
|
|
6128
|
+
var intercom_queue_exports = {};
|
|
6129
|
+
__export(intercom_queue_exports, {
|
|
6130
|
+
clearQueueForAgent: () => clearQueueForAgent,
|
|
6131
|
+
drainForSession: () => drainForSession,
|
|
6132
|
+
drainQueue: () => drainQueue,
|
|
6133
|
+
queueIntercom: () => queueIntercom,
|
|
6134
|
+
readQueue: () => readQueue
|
|
6135
|
+
});
|
|
6128
6136
|
import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, renameSync as renameSync3, existsSync as existsSync13, mkdirSync as mkdirSync6 } from "fs";
|
|
6129
6137
|
import path17 from "path";
|
|
6130
6138
|
import os7 from "os";
|
|
@@ -6163,11 +6171,80 @@ function queueIntercom(targetSession, reason) {
|
|
|
6163
6171
|
}
|
|
6164
6172
|
writeQueue(queue);
|
|
6165
6173
|
}
|
|
6166
|
-
|
|
6174
|
+
function drainQueue(isSessionBusy2, sendKeys) {
|
|
6175
|
+
const queue = readQueue();
|
|
6176
|
+
if (queue.length === 0) return { drained: 0, failed: 0 };
|
|
6177
|
+
const remaining = [];
|
|
6178
|
+
let drained = 0;
|
|
6179
|
+
let failed = 0;
|
|
6180
|
+
for (const item of queue) {
|
|
6181
|
+
const age = Date.now() - new Date(item.queuedAt).getTime();
|
|
6182
|
+
if (age > TTL_MS) {
|
|
6183
|
+
logQueue(`EXPIRED \u2192 ${item.targetSession} (${Math.round(age / 6e4)}min old, reason: ${item.reason})`);
|
|
6184
|
+
failed++;
|
|
6185
|
+
continue;
|
|
6186
|
+
}
|
|
6187
|
+
try {
|
|
6188
|
+
if (!isSessionBusy2(item.targetSession)) {
|
|
6189
|
+
const success = sendKeys(item.targetSession);
|
|
6190
|
+
if (success) {
|
|
6191
|
+
logQueue(`DRAINED \u2192 ${item.targetSession} (after ${item.attempts} retries)`);
|
|
6192
|
+
drained++;
|
|
6193
|
+
continue;
|
|
6194
|
+
}
|
|
6195
|
+
}
|
|
6196
|
+
} catch {
|
|
6197
|
+
}
|
|
6198
|
+
item.attempts++;
|
|
6199
|
+
if (item.attempts >= MAX_RETRIES2) {
|
|
6200
|
+
logQueue(`FAILED \u2192 ${item.targetSession} (${MAX_RETRIES2} retries exhausted, reason: ${item.reason})`);
|
|
6201
|
+
failed++;
|
|
6202
|
+
continue;
|
|
6203
|
+
}
|
|
6204
|
+
remaining.push(item);
|
|
6205
|
+
}
|
|
6206
|
+
writeQueue(remaining);
|
|
6207
|
+
return { drained, failed };
|
|
6208
|
+
}
|
|
6209
|
+
function drainForSession(targetSession, sendKeys) {
|
|
6210
|
+
const queue = readQueue();
|
|
6211
|
+
const match = queue.findIndex((q) => q.targetSession === targetSession);
|
|
6212
|
+
if (match < 0) return false;
|
|
6213
|
+
const success = sendKeys(targetSession);
|
|
6214
|
+
if (success) {
|
|
6215
|
+
queue.splice(match, 1);
|
|
6216
|
+
writeQueue(queue);
|
|
6217
|
+
logQueue(`DRAINED \u2192 ${targetSession} (prompt-submit trigger)`);
|
|
6218
|
+
return true;
|
|
6219
|
+
}
|
|
6220
|
+
return false;
|
|
6221
|
+
}
|
|
6222
|
+
function clearQueueForAgent(agentName) {
|
|
6223
|
+
const queue = readQueue();
|
|
6224
|
+
const before = queue.length;
|
|
6225
|
+
const filtered = queue.filter((q) => !q.targetSession.startsWith(`${agentName}-`));
|
|
6226
|
+
if (filtered.length < before) {
|
|
6227
|
+
writeQueue(filtered);
|
|
6228
|
+
logQueue(`CLEARED ${before - filtered.length} stale item(s) for ${agentName}`);
|
|
6229
|
+
}
|
|
6230
|
+
}
|
|
6231
|
+
function logQueue(msg) {
|
|
6232
|
+
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [queue] ${msg}
|
|
6233
|
+
`;
|
|
6234
|
+
process.stderr.write(`[intercom-queue] ${msg}
|
|
6235
|
+
`);
|
|
6236
|
+
try {
|
|
6237
|
+
const { appendFileSync: appendFileSync3 } = __require("fs");
|
|
6238
|
+
appendFileSync3(INTERCOM_LOG, line);
|
|
6239
|
+
} catch {
|
|
6240
|
+
}
|
|
6241
|
+
}
|
|
6242
|
+
var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
|
|
6167
6243
|
var init_intercom_queue = __esm({
|
|
6168
6244
|
"src/lib/intercom-queue.ts"() {
|
|
6169
6245
|
"use strict";
|
|
6170
6246
|
QUEUE_PATH = path17.join(os7.homedir(), ".exe-os", "intercom-queue.json");
|
|
6247
|
+
MAX_RETRIES2 = 5;
|
|
6171
6248
|
TTL_MS = 60 * 60 * 1e3;
|
|
6172
6249
|
INTERCOM_LOG = path17.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
6173
6250
|
}
|
|
@@ -7806,6 +7883,13 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
|
|
|
7806
7883
|
await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
7807
7884
|
} catch {
|
|
7808
7885
|
}
|
|
7886
|
+
if (input.status === "done" || input.status === "cancelled") {
|
|
7887
|
+
try {
|
|
7888
|
+
const { clearQueueForAgent: clearQueueForAgent2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
|
|
7889
|
+
clearQueueForAgent2(String(row.assigned_to));
|
|
7890
|
+
} catch {
|
|
7891
|
+
}
|
|
7892
|
+
}
|
|
7809
7893
|
try {
|
|
7810
7894
|
await writeCheckpoint({
|
|
7811
7895
|
taskId,
|
|
@@ -9651,7 +9735,7 @@ async function deliverLocalMessage(messageId) {
|
|
|
9651
9735
|
return true;
|
|
9652
9736
|
} catch {
|
|
9653
9737
|
const newRetryCount = msg.retryCount + 1;
|
|
9654
|
-
if (newRetryCount >=
|
|
9738
|
+
if (newRetryCount >= MAX_RETRIES3) {
|
|
9655
9739
|
await markFailed(messageId, "session unavailable after 10 retries");
|
|
9656
9740
|
} else {
|
|
9657
9741
|
await client.execute({
|
|
@@ -9669,13 +9753,13 @@ async function markFailed(messageId, reason) {
|
|
|
9669
9753
|
args: [(/* @__PURE__ */ new Date()).toISOString(), reason, messageId]
|
|
9670
9754
|
});
|
|
9671
9755
|
}
|
|
9672
|
-
var
|
|
9756
|
+
var MAX_RETRIES3, _wsClientSend;
|
|
9673
9757
|
var init_messaging = __esm({
|
|
9674
9758
|
"src/lib/messaging.ts"() {
|
|
9675
9759
|
"use strict";
|
|
9676
9760
|
init_database();
|
|
9677
9761
|
init_tmux_routing();
|
|
9678
|
-
|
|
9762
|
+
MAX_RETRIES3 = 10;
|
|
9679
9763
|
_wsClientSend = null;
|
|
9680
9764
|
}
|
|
9681
9765
|
});
|
|
@@ -9733,7 +9817,7 @@ __export(consolidation_exports, {
|
|
|
9733
9817
|
selectUnconsolidated: () => selectUnconsolidated,
|
|
9734
9818
|
storeConsolidation: () => storeConsolidation
|
|
9735
9819
|
});
|
|
9736
|
-
import { randomUUID as
|
|
9820
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
9737
9821
|
async function selectUnconsolidated(client, limit = 200) {
|
|
9738
9822
|
const result = await client.execute({
|
|
9739
9823
|
sql: `SELECT id, agent_id, project_name, tool_name, raw_text, timestamp
|
|
@@ -9829,7 +9913,7 @@ async function consolidateCluster(cluster, model) {
|
|
|
9829
9913
|
return textBlock?.text ?? "";
|
|
9830
9914
|
}
|
|
9831
9915
|
async function storeConsolidation(client, cluster, synthesisText, embedFn) {
|
|
9832
|
-
const consolidatedId =
|
|
9916
|
+
const consolidatedId = randomUUID6();
|
|
9833
9917
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
9834
9918
|
const rawText = `CONSOLIDATION [${cluster.dateRange}, ${cluster.projectName}]:
|
|
9835
9919
|
|
|
@@ -9854,7 +9938,7 @@ ${synthesisText}`;
|
|
|
9854
9938
|
const linkStmts = sourceIds.map((sourceId) => ({
|
|
9855
9939
|
sql: `INSERT INTO consolidations (id, consolidated_memory_id, source_memory_id, created_at)
|
|
9856
9940
|
VALUES (?, ?, ?, ?)`,
|
|
9857
|
-
args: [
|
|
9941
|
+
args: [randomUUID6(), consolidatedId, sourceId, now]
|
|
9858
9942
|
}));
|
|
9859
9943
|
const placeholders = sourceIds.map(() => "?").join(",");
|
|
9860
9944
|
const markStmt = {
|
|
@@ -10100,14 +10184,14 @@ __export(wiki_client_exports, {
|
|
|
10100
10184
|
listDocuments: () => listDocuments,
|
|
10101
10185
|
listWorkspaces: () => listWorkspaces
|
|
10102
10186
|
});
|
|
10103
|
-
async function wikiFetch(config2,
|
|
10104
|
-
const url = `${config2.baseUrl}/api/v1${
|
|
10187
|
+
async function wikiFetch(config2, path40, method = "GET", body) {
|
|
10188
|
+
const url = `${config2.baseUrl}/api/v1${path40}`;
|
|
10105
10189
|
const headers = {
|
|
10106
10190
|
Authorization: `Bearer ${config2.apiKey}`,
|
|
10107
10191
|
"Content-Type": "application/json"
|
|
10108
10192
|
};
|
|
10109
10193
|
const controller = new AbortController();
|
|
10110
|
-
const timeout = setTimeout(() => controller.abort(),
|
|
10194
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS3);
|
|
10111
10195
|
try {
|
|
10112
10196
|
let response;
|
|
10113
10197
|
try {
|
|
@@ -10120,7 +10204,7 @@ async function wikiFetch(config2, path38, method = "GET", body) {
|
|
|
10120
10204
|
} catch {
|
|
10121
10205
|
clearTimeout(timeout);
|
|
10122
10206
|
const retryController = new AbortController();
|
|
10123
|
-
const retryTimeout = setTimeout(() => retryController.abort(),
|
|
10207
|
+
const retryTimeout = setTimeout(() => retryController.abort(), REQUEST_TIMEOUT_MS3);
|
|
10124
10208
|
try {
|
|
10125
10209
|
await new Promise((r) => setTimeout(r, 500));
|
|
10126
10210
|
response = await fetch(url, {
|
|
@@ -10134,7 +10218,7 @@ async function wikiFetch(config2, path38, method = "GET", body) {
|
|
|
10134
10218
|
}
|
|
10135
10219
|
}
|
|
10136
10220
|
if (!response.ok) {
|
|
10137
|
-
throw new Error(`Wiki API ${method} ${
|
|
10221
|
+
throw new Error(`Wiki API ${method} ${path40}: ${response.status} ${response.statusText}`);
|
|
10138
10222
|
}
|
|
10139
10223
|
return response.json();
|
|
10140
10224
|
} finally {
|
|
@@ -10224,12 +10308,12 @@ async function getChatHistory(client, workspaceSlug, limit = 50) {
|
|
|
10224
10308
|
sentAt: h.sentAt ?? 0
|
|
10225
10309
|
}));
|
|
10226
10310
|
}
|
|
10227
|
-
var LOCAL_WIKI_URL,
|
|
10311
|
+
var LOCAL_WIKI_URL, REQUEST_TIMEOUT_MS3;
|
|
10228
10312
|
var init_wiki_client = __esm({
|
|
10229
10313
|
"src/lib/wiki-client.ts"() {
|
|
10230
10314
|
"use strict";
|
|
10231
10315
|
LOCAL_WIKI_URL = process.env.EXE_WIKI_URL || "http://localhost:3001";
|
|
10232
|
-
|
|
10316
|
+
REQUEST_TIMEOUT_MS3 = 8e3;
|
|
10233
10317
|
}
|
|
10234
10318
|
});
|
|
10235
10319
|
|
|
@@ -10243,14 +10327,14 @@ __export(worker_gate_exports, {
|
|
|
10243
10327
|
tryAcquireBackfillLock: () => tryAcquireBackfillLock,
|
|
10244
10328
|
tryAcquireWorkerSlot: () => tryAcquireWorkerSlot
|
|
10245
10329
|
});
|
|
10246
|
-
import { readdirSync as readdirSync9, writeFileSync as
|
|
10247
|
-
import
|
|
10330
|
+
import { readdirSync as readdirSync9, writeFileSync as writeFileSync17, unlinkSync as unlinkSync8, mkdirSync as mkdirSync14, existsSync as existsSync25 } from "fs";
|
|
10331
|
+
import path33 from "path";
|
|
10248
10332
|
function tryAcquireWorkerSlot() {
|
|
10249
10333
|
try {
|
|
10250
|
-
|
|
10334
|
+
mkdirSync14(WORKER_PID_DIR, { recursive: true });
|
|
10251
10335
|
const reservationId = `res-${process.pid}-${Date.now()}`;
|
|
10252
|
-
const reservationPath =
|
|
10253
|
-
|
|
10336
|
+
const reservationPath = path33.join(WORKER_PID_DIR, `${reservationId}.pid`);
|
|
10337
|
+
writeFileSync17(reservationPath, String(process.pid));
|
|
10254
10338
|
const files = readdirSync9(WORKER_PID_DIR);
|
|
10255
10339
|
let alive = 0;
|
|
10256
10340
|
for (const f of files) {
|
|
@@ -10267,7 +10351,7 @@ function tryAcquireWorkerSlot() {
|
|
|
10267
10351
|
alive++;
|
|
10268
10352
|
} catch {
|
|
10269
10353
|
try {
|
|
10270
|
-
unlinkSync8(
|
|
10354
|
+
unlinkSync8(path33.join(WORKER_PID_DIR, f));
|
|
10271
10355
|
} catch {
|
|
10272
10356
|
}
|
|
10273
10357
|
}
|
|
@@ -10290,21 +10374,21 @@ function tryAcquireWorkerSlot() {
|
|
|
10290
10374
|
}
|
|
10291
10375
|
function registerWorkerPid(pid) {
|
|
10292
10376
|
try {
|
|
10293
|
-
|
|
10294
|
-
|
|
10377
|
+
mkdirSync14(WORKER_PID_DIR, { recursive: true });
|
|
10378
|
+
writeFileSync17(path33.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
|
|
10295
10379
|
} catch {
|
|
10296
10380
|
}
|
|
10297
10381
|
}
|
|
10298
10382
|
function cleanupWorkerPid() {
|
|
10299
10383
|
try {
|
|
10300
|
-
unlinkSync8(
|
|
10384
|
+
unlinkSync8(path33.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
|
|
10301
10385
|
} catch {
|
|
10302
10386
|
}
|
|
10303
10387
|
}
|
|
10304
10388
|
function tryAcquireBackfillLock() {
|
|
10305
10389
|
try {
|
|
10306
|
-
|
|
10307
|
-
if (
|
|
10390
|
+
mkdirSync14(WORKER_PID_DIR, { recursive: true });
|
|
10391
|
+
if (existsSync25(BACKFILL_LOCK)) {
|
|
10308
10392
|
try {
|
|
10309
10393
|
const pid = parseInt(
|
|
10310
10394
|
__require("fs").readFileSync(BACKFILL_LOCK, "utf8").trim(),
|
|
@@ -10320,7 +10404,7 @@ function tryAcquireBackfillLock() {
|
|
|
10320
10404
|
} catch {
|
|
10321
10405
|
}
|
|
10322
10406
|
}
|
|
10323
|
-
|
|
10407
|
+
writeFileSync17(BACKFILL_LOCK, String(process.pid));
|
|
10324
10408
|
return true;
|
|
10325
10409
|
} catch {
|
|
10326
10410
|
return true;
|
|
@@ -10337,9 +10421,9 @@ var init_worker_gate = __esm({
|
|
|
10337
10421
|
"src/lib/worker-gate.ts"() {
|
|
10338
10422
|
"use strict";
|
|
10339
10423
|
init_config();
|
|
10340
|
-
WORKER_PID_DIR =
|
|
10424
|
+
WORKER_PID_DIR = path33.join(EXE_AI_DIR, "worker-pids");
|
|
10341
10425
|
MAX_CONCURRENT_WORKERS = 3;
|
|
10342
|
-
BACKFILL_LOCK =
|
|
10426
|
+
BACKFILL_LOCK = path33.join(WORKER_PID_DIR, "backfill.lock");
|
|
10343
10427
|
}
|
|
10344
10428
|
});
|
|
10345
10429
|
|
|
@@ -10362,8 +10446,8 @@ __export(crdt_sync_exports, {
|
|
|
10362
10446
|
rebuildFromDb: () => rebuildFromDb
|
|
10363
10447
|
});
|
|
10364
10448
|
import * as Y from "yjs";
|
|
10365
|
-
import { readFileSync as
|
|
10366
|
-
import
|
|
10449
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync18, existsSync as existsSync28, mkdirSync as mkdirSync15, unlinkSync as unlinkSync9 } from "fs";
|
|
10450
|
+
import path36 from "path";
|
|
10367
10451
|
import { homedir as homedir5 } from "os";
|
|
10368
10452
|
function getStatePath() {
|
|
10369
10453
|
return _statePathOverride ?? DEFAULT_STATE_PATH;
|
|
@@ -10375,9 +10459,9 @@ function initCrdtDoc() {
|
|
|
10375
10459
|
if (doc) return doc;
|
|
10376
10460
|
doc = new Y.Doc();
|
|
10377
10461
|
const sp = getStatePath();
|
|
10378
|
-
if (
|
|
10462
|
+
if (existsSync28(sp)) {
|
|
10379
10463
|
try {
|
|
10380
|
-
const state =
|
|
10464
|
+
const state = readFileSync24(sp);
|
|
10381
10465
|
Y.applyUpdate(doc, new Uint8Array(state));
|
|
10382
10466
|
} catch {
|
|
10383
10467
|
console.warn("[crdt-sync] WARN: corrupted state file, rebuilding from DB");
|
|
@@ -10519,10 +10603,10 @@ function persistState() {
|
|
|
10519
10603
|
if (!doc) return;
|
|
10520
10604
|
try {
|
|
10521
10605
|
const sp = getStatePath();
|
|
10522
|
-
const dir =
|
|
10523
|
-
if (!
|
|
10606
|
+
const dir = path36.dirname(sp);
|
|
10607
|
+
if (!existsSync28(dir)) mkdirSync15(dir, { recursive: true });
|
|
10524
10608
|
const state = Y.encodeStateAsUpdate(doc);
|
|
10525
|
-
|
|
10609
|
+
writeFileSync18(sp, Buffer.from(state));
|
|
10526
10610
|
} catch {
|
|
10527
10611
|
}
|
|
10528
10612
|
}
|
|
@@ -10563,7 +10647,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
|
|
|
10563
10647
|
var init_crdt_sync = __esm({
|
|
10564
10648
|
"src/lib/crdt-sync.ts"() {
|
|
10565
10649
|
"use strict";
|
|
10566
|
-
DEFAULT_STATE_PATH =
|
|
10650
|
+
DEFAULT_STATE_PATH = path36.join(homedir5(), ".exe-os", "crdt-state.bin");
|
|
10567
10651
|
_statePathOverride = null;
|
|
10568
10652
|
doc = null;
|
|
10569
10653
|
}
|
|
@@ -10576,8 +10660,8 @@ init_database();
|
|
|
10576
10660
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10577
10661
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10578
10662
|
import { spawn as spawn3 } from "child_process";
|
|
10579
|
-
import { existsSync as
|
|
10580
|
-
import
|
|
10663
|
+
import { existsSync as existsSync31, openSync as openSync3, mkdirSync as mkdirSync17, closeSync as closeSync3 } from "fs";
|
|
10664
|
+
import path39 from "path";
|
|
10581
10665
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
10582
10666
|
|
|
10583
10667
|
// src/mcp/tools/recall-my-memory.ts
|
|
@@ -11247,10 +11331,10 @@ function registerCreateTask(server2) {
|
|
|
11247
11331
|
skipDispatch: true
|
|
11248
11332
|
});
|
|
11249
11333
|
try {
|
|
11250
|
-
const { existsSync:
|
|
11334
|
+
const { existsSync: existsSync32, mkdirSync: mkdirSync18, writeFileSync: writeFileSync20 } = await import("fs");
|
|
11251
11335
|
const { identityPath: identityPath2 } = await Promise.resolve().then(() => (init_identity(), identity_exports));
|
|
11252
11336
|
const idPath = identityPath2(assigned_to);
|
|
11253
|
-
if (!
|
|
11337
|
+
if (!existsSync32(idPath)) {
|
|
11254
11338
|
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
11255
11339
|
const employees = await loadEmployees2();
|
|
11256
11340
|
const emp = employees.find((e) => e.name === assigned_to);
|
|
@@ -11259,8 +11343,8 @@ function registerCreateTask(server2) {
|
|
|
11259
11343
|
const template = getTemplateForTitle2(emp.role);
|
|
11260
11344
|
if (template) {
|
|
11261
11345
|
const dir = (await import("path")).dirname(idPath);
|
|
11262
|
-
if (!
|
|
11263
|
-
|
|
11346
|
+
if (!existsSync32(dir)) mkdirSync18(dir, { recursive: true });
|
|
11347
|
+
writeFileSync20(idPath, template.replace(/^agent_id: \w+/m, `agent_id: ${assigned_to}`), "utf-8");
|
|
11264
11348
|
}
|
|
11265
11349
|
}
|
|
11266
11350
|
}
|
|
@@ -14605,9 +14689,9 @@ var HostingerApiClient = class {
|
|
|
14605
14689
|
}
|
|
14606
14690
|
this.lastRequestTime = Date.now();
|
|
14607
14691
|
}
|
|
14608
|
-
async request(method,
|
|
14692
|
+
async request(method, path40, body) {
|
|
14609
14693
|
await this.rateLimit();
|
|
14610
|
-
const url = `${this.baseUrl}${
|
|
14694
|
+
const url = `${this.baseUrl}${path40}`;
|
|
14611
14695
|
const headers = {
|
|
14612
14696
|
Authorization: `Bearer ${this.apiKey}`,
|
|
14613
14697
|
"Content-Type": "application/json",
|
|
@@ -14645,13 +14729,123 @@ var HostingerError = class extends Error {
|
|
|
14645
14729
|
}
|
|
14646
14730
|
};
|
|
14647
14731
|
|
|
14732
|
+
// src/lib/cloudflare-dns.ts
|
|
14733
|
+
var CLOUDFLARE_API_BASE_URL = "https://api.cloudflare.com/client/v4";
|
|
14734
|
+
var DNS_RECORD_TYPE_A = "A";
|
|
14735
|
+
var DEFAULT_PROXIED = true;
|
|
14736
|
+
var DEFAULT_TTL = 1;
|
|
14737
|
+
var REQUEST_TIMEOUT_MS2 = 3e4;
|
|
14738
|
+
var UNKNOWN_ERROR_CODE = "unknown";
|
|
14739
|
+
async function createARecord(cfApiToken, zoneId, domain, ip, opts) {
|
|
14740
|
+
const proxied = opts?.proxied ?? DEFAULT_PROXIED;
|
|
14741
|
+
const ttl = opts?.ttl ?? DEFAULT_TTL;
|
|
14742
|
+
const response = await requestCloudflare(cfApiToken, zoneId, {
|
|
14743
|
+
method: "POST",
|
|
14744
|
+
body: {
|
|
14745
|
+
type: DNS_RECORD_TYPE_A,
|
|
14746
|
+
name: domain,
|
|
14747
|
+
content: ip,
|
|
14748
|
+
proxied,
|
|
14749
|
+
ttl
|
|
14750
|
+
}
|
|
14751
|
+
});
|
|
14752
|
+
return mapDnsRecord(response);
|
|
14753
|
+
}
|
|
14754
|
+
async function requestCloudflare(cfApiToken, zoneId, options) {
|
|
14755
|
+
const response = await fetch(buildUrl(zoneId, options.path, options.query), {
|
|
14756
|
+
method: options.method,
|
|
14757
|
+
headers: buildHeaders(cfApiToken),
|
|
14758
|
+
body: options.body ? JSON.stringify(options.body) : void 0,
|
|
14759
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
|
|
14760
|
+
});
|
|
14761
|
+
const envelope = await parseEnvelope(response);
|
|
14762
|
+
if (!response.ok || !envelope.success) {
|
|
14763
|
+
throw toCloudflareError(response, envelope);
|
|
14764
|
+
}
|
|
14765
|
+
return envelope.result;
|
|
14766
|
+
}
|
|
14767
|
+
function buildUrl(zoneId, path40 = "/dns_records", query) {
|
|
14768
|
+
const normalizedPath = path40.startsWith("/") ? path40 : `/${path40}`;
|
|
14769
|
+
const url = new URL(
|
|
14770
|
+
`${CLOUDFLARE_API_BASE_URL}/zones/${zoneId}${normalizedPath}`
|
|
14771
|
+
);
|
|
14772
|
+
if (query) {
|
|
14773
|
+
url.search = query.toString();
|
|
14774
|
+
}
|
|
14775
|
+
return url.toString();
|
|
14776
|
+
}
|
|
14777
|
+
function buildHeaders(cfApiToken) {
|
|
14778
|
+
return {
|
|
14779
|
+
Authorization: `Bearer ${cfApiToken}`,
|
|
14780
|
+
"Content-Type": "application/json",
|
|
14781
|
+
Accept: "application/json"
|
|
14782
|
+
};
|
|
14783
|
+
}
|
|
14784
|
+
async function parseEnvelope(response) {
|
|
14785
|
+
try {
|
|
14786
|
+
return await response.json();
|
|
14787
|
+
} catch {
|
|
14788
|
+
return {
|
|
14789
|
+
success: false,
|
|
14790
|
+
errors: [
|
|
14791
|
+
{
|
|
14792
|
+
code: UNKNOWN_ERROR_CODE,
|
|
14793
|
+
message: `HTTP ${response.status}: ${response.statusText}`
|
|
14794
|
+
}
|
|
14795
|
+
],
|
|
14796
|
+
messages: [],
|
|
14797
|
+
result: null
|
|
14798
|
+
};
|
|
14799
|
+
}
|
|
14800
|
+
}
|
|
14801
|
+
function toCloudflareError(response, envelope) {
|
|
14802
|
+
const firstError = envelope.errors[0];
|
|
14803
|
+
const errorCode = String(firstError?.code ?? UNKNOWN_ERROR_CODE);
|
|
14804
|
+
const message = firstError?.message ?? `HTTP ${response.status}: ${response.statusText}`;
|
|
14805
|
+
return new CloudflareError(response.status, errorCode, message);
|
|
14806
|
+
}
|
|
14807
|
+
function mapDnsRecord(record) {
|
|
14808
|
+
return {
|
|
14809
|
+
recordId: record.id,
|
|
14810
|
+
name: record.name,
|
|
14811
|
+
ip: record.content,
|
|
14812
|
+
proxied: record.proxied
|
|
14813
|
+
};
|
|
14814
|
+
}
|
|
14815
|
+
var CloudflareError = class extends Error {
|
|
14816
|
+
status;
|
|
14817
|
+
errorCode;
|
|
14818
|
+
constructor(status, errorCode, message) {
|
|
14819
|
+
super(message);
|
|
14820
|
+
this.name = "CloudflareError";
|
|
14821
|
+
this.status = status;
|
|
14822
|
+
this.errorCode = errorCode;
|
|
14823
|
+
}
|
|
14824
|
+
};
|
|
14825
|
+
|
|
14648
14826
|
// src/mcp/tools/deploy-client.ts
|
|
14649
14827
|
init_config();
|
|
14650
14828
|
var execFileAsync = promisify(execFile);
|
|
14651
14829
|
var POLL_INTERVAL_MS = 1e4;
|
|
14652
14830
|
var POLL_MAX_ATTEMPTS = 60;
|
|
14831
|
+
var DEFAULT_VPS_TEMPLATE = "ubuntu-24.04";
|
|
14832
|
+
var DNS_PROXIED_OPTIONS = { proxied: true };
|
|
14833
|
+
var DEPLOYED_STATUS = "deployed";
|
|
14834
|
+
var PLAYBOOK_COMPLETE_HEALTH_PENDING_STATUS = "playbook_complete_health_pending";
|
|
14835
|
+
var ACTIVE_INVENTORY_STATUS = "active";
|
|
14836
|
+
var PROVISIONING_INVENTORY_STATUS = "provisioning";
|
|
14653
14837
|
async function executeDeployment(params, client) {
|
|
14654
|
-
const {
|
|
14838
|
+
const {
|
|
14839
|
+
client_name,
|
|
14840
|
+
domain,
|
|
14841
|
+
region,
|
|
14842
|
+
plan,
|
|
14843
|
+
ssl_email,
|
|
14844
|
+
user_id,
|
|
14845
|
+
apiKey,
|
|
14846
|
+
cfApiToken,
|
|
14847
|
+
cfZoneId
|
|
14848
|
+
} = params;
|
|
14655
14849
|
const hostinger = client ?? new HostingerApiClient(apiKey);
|
|
14656
14850
|
const hostname = `exe-${client_name.toLowerCase().replace(/[^a-z0-9-]/g, "-")}`;
|
|
14657
14851
|
process.stderr.write(`[deploy_client] Provisioning VPS: ${hostname} (${plan}, ${region})...
|
|
@@ -14660,7 +14854,7 @@ async function executeDeployment(params, client) {
|
|
|
14660
14854
|
hostname,
|
|
14661
14855
|
plan,
|
|
14662
14856
|
region,
|
|
14663
|
-
os_template:
|
|
14857
|
+
os_template: DEFAULT_VPS_TEMPLATE
|
|
14664
14858
|
});
|
|
14665
14859
|
process.stderr.write(`[deploy_client] VPS created (ID: ${created.id}). Waiting for ready state...
|
|
14666
14860
|
`);
|
|
@@ -14668,9 +14862,27 @@ async function executeDeployment(params, client) {
|
|
|
14668
14862
|
process.stderr.write(`[deploy_client] VPS ready at ${vps.ip_address}. Running Ansible playbook...
|
|
14669
14863
|
`);
|
|
14670
14864
|
const playbookResult = await runAnsiblePlaybook(vps.ip_address, domain, ssl_email, client_name);
|
|
14865
|
+
const dnsRecordId = await createDnsRecordIfConfigured({
|
|
14866
|
+
domain,
|
|
14867
|
+
ipAddress: vps.ip_address,
|
|
14868
|
+
cfApiToken,
|
|
14869
|
+
cfZoneId
|
|
14870
|
+
});
|
|
14671
14871
|
process.stderr.write(`[deploy_client] Playbook complete. Verifying health...
|
|
14672
14872
|
`);
|
|
14673
14873
|
const healthy = await verifyHealth(domain);
|
|
14874
|
+
const status = healthy ? DEPLOYED_STATUS : PLAYBOOK_COMPLETE_HEALTH_PENDING_STATUS;
|
|
14875
|
+
process.stderr.write("[deploy_client] Recording VPS inventory...\n");
|
|
14876
|
+
const inventory = buildInventoryRecord({
|
|
14877
|
+
userId: user_id,
|
|
14878
|
+
clientName: client_name,
|
|
14879
|
+
vpsId: vps.id,
|
|
14880
|
+
ipAddress: vps.ip_address,
|
|
14881
|
+
domain,
|
|
14882
|
+
region: vps.region,
|
|
14883
|
+
plan: vps.plan,
|
|
14884
|
+
healthy
|
|
14885
|
+
});
|
|
14674
14886
|
return {
|
|
14675
14887
|
vps_id: vps.id,
|
|
14676
14888
|
hostname: vps.hostname,
|
|
@@ -14680,8 +14892,10 @@ async function executeDeployment(params, client) {
|
|
|
14680
14892
|
plan: vps.plan,
|
|
14681
14893
|
ssh_port: vps.ssh_port,
|
|
14682
14894
|
ssh_access: `ssh exeai@${vps.ip_address}`,
|
|
14683
|
-
status
|
|
14684
|
-
ansible_output: playbookResult
|
|
14895
|
+
status,
|
|
14896
|
+
ansible_output: playbookResult,
|
|
14897
|
+
dns_record_id: dnsRecordId,
|
|
14898
|
+
inventory
|
|
14685
14899
|
};
|
|
14686
14900
|
}
|
|
14687
14901
|
function registerDeployClient(server2) {
|
|
@@ -14695,12 +14909,15 @@ function registerDeployClient(server2) {
|
|
|
14695
14909
|
domain: z37.string().min(1).describe("Domain name for the deployment (e.g., client.exe.ai)"),
|
|
14696
14910
|
region: z37.string().default("jakarta").describe("VPS region (default: jakarta)"),
|
|
14697
14911
|
plan: z37.string().default("kvm-2").describe("Hostinger VPS plan (default: kvm-2)"),
|
|
14698
|
-
ssl_email: z37.string().email().describe("Email for Let's Encrypt SSL certificate")
|
|
14912
|
+
ssl_email: z37.string().email().describe("Email for Let's Encrypt SSL certificate"),
|
|
14913
|
+
user_id: z37.string().min(1).describe("User/customer ID for inventory tracking")
|
|
14699
14914
|
}
|
|
14700
14915
|
},
|
|
14701
|
-
async ({ client_name, domain, region, plan, ssl_email }) => {
|
|
14916
|
+
async ({ client_name, domain, region, plan, ssl_email, user_id }) => {
|
|
14702
14917
|
const config2 = await loadConfig();
|
|
14703
14918
|
const apiKey = config2.hostinger?.apiKey;
|
|
14919
|
+
const cfApiToken = config2.cloudflare?.apiToken;
|
|
14920
|
+
const cfZoneId = config2.cloudflare?.zoneId;
|
|
14704
14921
|
if (!apiKey) {
|
|
14705
14922
|
return {
|
|
14706
14923
|
content: [
|
|
@@ -14718,7 +14935,10 @@ function registerDeployClient(server2) {
|
|
|
14718
14935
|
region,
|
|
14719
14936
|
plan,
|
|
14720
14937
|
ssl_email,
|
|
14721
|
-
|
|
14938
|
+
user_id,
|
|
14939
|
+
apiKey,
|
|
14940
|
+
cfApiToken,
|
|
14941
|
+
cfZoneId
|
|
14722
14942
|
});
|
|
14723
14943
|
return {
|
|
14724
14944
|
content: [
|
|
@@ -14816,10 +15036,467 @@ async function verifyHealth(domain) {
|
|
|
14816
15036
|
return false;
|
|
14817
15037
|
}
|
|
14818
15038
|
}
|
|
15039
|
+
async function createDnsRecordIfConfigured(params) {
|
|
15040
|
+
const { domain, ipAddress, cfApiToken, cfZoneId } = params;
|
|
15041
|
+
if (!cfApiToken || !cfZoneId) {
|
|
15042
|
+
process.stderr.write(
|
|
15043
|
+
`[deploy_client] Warning: Cloudflare config missing. Skipping DNS setup for ${domain}; configure cloudflare.apiToken and cloudflare.zoneId to automate this step.
|
|
15044
|
+
`
|
|
15045
|
+
);
|
|
15046
|
+
return void 0;
|
|
15047
|
+
}
|
|
15048
|
+
process.stderr.write(`[deploy_client] Setting up DNS: ${domain} \u2192 ${ipAddress}...
|
|
15049
|
+
`);
|
|
15050
|
+
const dnsResult = await createARecord(
|
|
15051
|
+
cfApiToken,
|
|
15052
|
+
cfZoneId,
|
|
15053
|
+
domain,
|
|
15054
|
+
ipAddress,
|
|
15055
|
+
DNS_PROXIED_OPTIONS
|
|
15056
|
+
);
|
|
15057
|
+
return dnsResult.recordId;
|
|
15058
|
+
}
|
|
15059
|
+
function buildInventoryRecord(params) {
|
|
15060
|
+
const { userId, clientName, vpsId, ipAddress, domain, region, plan, healthy } = params;
|
|
15061
|
+
return {
|
|
15062
|
+
user_id: userId,
|
|
15063
|
+
client_name: clientName,
|
|
15064
|
+
hostinger_vps_id: vpsId,
|
|
15065
|
+
ip_address: ipAddress,
|
|
15066
|
+
domain,
|
|
15067
|
+
region,
|
|
15068
|
+
plan,
|
|
15069
|
+
status: healthy ? ACTIVE_INVENTORY_STATUS : PROVISIONING_INVENTORY_STATUS
|
|
15070
|
+
};
|
|
15071
|
+
}
|
|
15072
|
+
|
|
15073
|
+
// src/mcp/tools/export-orchestration.ts
|
|
15074
|
+
init_active_agent();
|
|
15075
|
+
import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync15 } from "fs";
|
|
15076
|
+
import path29 from "path";
|
|
15077
|
+
import { z as z38 } from "zod";
|
|
15078
|
+
|
|
15079
|
+
// src/lib/orchestration-package.ts
|
|
15080
|
+
init_database();
|
|
15081
|
+
init_identity();
|
|
15082
|
+
init_platform_procedures();
|
|
15083
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
15084
|
+
import { copyFileSync, existsSync as existsSync22, mkdirSync as mkdirSync12, readFileSync as readFileSync18, writeFileSync as writeFileSync14 } from "fs";
|
|
15085
|
+
import os11 from "os";
|
|
15086
|
+
import path28 from "path";
|
|
15087
|
+
var PACKAGE_VERSION = "1.0";
|
|
15088
|
+
var ROSTER_FILENAME = "exe-employees.json";
|
|
15089
|
+
var ROSTER_BACKUP_FILENAME = "exe-employees.json.bak";
|
|
15090
|
+
var EXE_OS_DIRNAME = ".exe-os";
|
|
15091
|
+
var DEFAULT_BEHAVIOR_PRIORITY = "p1";
|
|
15092
|
+
var DEFAULT_PROCEDURE_PRIORITY = "p0";
|
|
15093
|
+
var DEFAULT_IDENTITY_UPDATED_BY = "orchestration-import";
|
|
15094
|
+
function ensureObject(value, label) {
|
|
15095
|
+
if (value == null || Array.isArray(value) || typeof value !== "object") {
|
|
15096
|
+
throw new Error(`${label} must be an object`);
|
|
15097
|
+
}
|
|
15098
|
+
return value;
|
|
15099
|
+
}
|
|
15100
|
+
function ensureString(value, label) {
|
|
15101
|
+
if (typeof value !== "string") {
|
|
15102
|
+
throw new Error(`${label} must be a string`);
|
|
15103
|
+
}
|
|
15104
|
+
return value;
|
|
15105
|
+
}
|
|
15106
|
+
function ensureOptionalString(value, label) {
|
|
15107
|
+
if (value == null) return void 0;
|
|
15108
|
+
return ensureString(value, label);
|
|
15109
|
+
}
|
|
15110
|
+
function ensureNullableString(value, label) {
|
|
15111
|
+
if (value == null) return null;
|
|
15112
|
+
return ensureString(value, label);
|
|
15113
|
+
}
|
|
15114
|
+
function ensurePriority(value, label, fallback) {
|
|
15115
|
+
if (value == null) return fallback;
|
|
15116
|
+
if (value === "p0" || value === "p1" || value === "p2") {
|
|
15117
|
+
return value;
|
|
15118
|
+
}
|
|
15119
|
+
throw new Error(`${label} must be one of: p0, p1, p2`);
|
|
15120
|
+
}
|
|
15121
|
+
function validateRosterEntry(value, index) {
|
|
15122
|
+
const record = ensureObject(value, `roster[${index}]`);
|
|
15123
|
+
return {
|
|
15124
|
+
name: ensureString(record.name, `roster[${index}].name`),
|
|
15125
|
+
role: ensureString(record.role, `roster[${index}].role`),
|
|
15126
|
+
systemPrompt: ensureString(record.systemPrompt, `roster[${index}].systemPrompt`),
|
|
15127
|
+
createdAt: typeof record.createdAt === "string" ? record.createdAt : "",
|
|
15128
|
+
templateName: ensureOptionalString(record.templateName, `roster[${index}].templateName`),
|
|
15129
|
+
templateVersion: typeof record.templateVersion === "number" ? record.templateVersion : void 0
|
|
15130
|
+
};
|
|
15131
|
+
}
|
|
15132
|
+
function validateBehaviorEntry(value, index) {
|
|
15133
|
+
const record = ensureObject(value, `behaviors[${index}]`);
|
|
15134
|
+
return {
|
|
15135
|
+
agent_id: ensureString(record.agent_id, `behaviors[${index}].agent_id`),
|
|
15136
|
+
project_name: ensureNullableString(record.project_name, `behaviors[${index}].project_name`),
|
|
15137
|
+
domain: ensureNullableString(record.domain, `behaviors[${index}].domain`),
|
|
15138
|
+
content: ensureString(record.content, `behaviors[${index}].content`),
|
|
15139
|
+
priority: ensurePriority(record.priority, `behaviors[${index}].priority`, DEFAULT_BEHAVIOR_PRIORITY)
|
|
15140
|
+
};
|
|
15141
|
+
}
|
|
15142
|
+
function validateProcedureEntry(value, index) {
|
|
15143
|
+
const record = ensureObject(value, `procedures[${index}]`);
|
|
15144
|
+
return {
|
|
15145
|
+
title: ensureString(record.title, `procedures[${index}].title`),
|
|
15146
|
+
content: ensureString(record.content, `procedures[${index}].content`),
|
|
15147
|
+
priority: ensurePriority(record.priority, `procedures[${index}].priority`, DEFAULT_PROCEDURE_PRIORITY),
|
|
15148
|
+
domain: ensureNullableString(record.domain, `procedures[${index}].domain`)
|
|
15149
|
+
};
|
|
15150
|
+
}
|
|
15151
|
+
function getRosterPath() {
|
|
15152
|
+
return path28.join(os11.homedir(), EXE_OS_DIRNAME, ROSTER_FILENAME);
|
|
15153
|
+
}
|
|
15154
|
+
function getBackupPath() {
|
|
15155
|
+
return path28.join(os11.homedir(), EXE_OS_DIRNAME, ROSTER_BACKUP_FILENAME);
|
|
15156
|
+
}
|
|
15157
|
+
function readRosterFile() {
|
|
15158
|
+
const rosterPath = getRosterPath();
|
|
15159
|
+
if (!existsSync22(rosterPath)) return [];
|
|
15160
|
+
const raw = readFileSync18(rosterPath, "utf-8");
|
|
15161
|
+
const parsed = JSON.parse(raw);
|
|
15162
|
+
if (!Array.isArray(parsed)) {
|
|
15163
|
+
throw new Error("Roster file must contain a JSON array");
|
|
15164
|
+
}
|
|
15165
|
+
return parsed.map((entry, index) => validateRosterEntry(entry, index));
|
|
15166
|
+
}
|
|
15167
|
+
function writeRosterFile(roster) {
|
|
15168
|
+
if (roster.length === 0) {
|
|
15169
|
+
throw new Error("Refusing to write empty roster \u2014 this would delete all employees");
|
|
15170
|
+
}
|
|
15171
|
+
const rosterPath = getRosterPath();
|
|
15172
|
+
mkdirSync12(path28.dirname(rosterPath), { recursive: true });
|
|
15173
|
+
if (existsSync22(rosterPath)) {
|
|
15174
|
+
const currentRoster = readRosterFile();
|
|
15175
|
+
if (roster.length < currentRoster.length) {
|
|
15176
|
+
throw new Error(
|
|
15177
|
+
`Refusing to write roster with ${roster.length} entries \u2014 current roster has ${currentRoster.length}. Import would delete ${currentRoster.length - roster.length} employee(s). Use merge strategy instead, or add the missing entries to the package.`
|
|
15178
|
+
);
|
|
15179
|
+
}
|
|
15180
|
+
copyFileSync(rosterPath, getBackupPath());
|
|
15181
|
+
}
|
|
15182
|
+
writeFileSync14(rosterPath, `${JSON.stringify(roster, null, 2)}
|
|
15183
|
+
`, "utf-8");
|
|
15184
|
+
}
|
|
15185
|
+
function buildImportedRosterEntries(roster, timestamp) {
|
|
15186
|
+
return roster.map((entry) => ({
|
|
15187
|
+
name: entry.name,
|
|
15188
|
+
role: entry.role,
|
|
15189
|
+
systemPrompt: entry.systemPrompt,
|
|
15190
|
+
createdAt: timestamp,
|
|
15191
|
+
...entry.templateName != null ? { templateName: entry.templateName } : {},
|
|
15192
|
+
...entry.templateVersion != null ? { templateVersion: entry.templateVersion } : {}
|
|
15193
|
+
}));
|
|
15194
|
+
}
|
|
15195
|
+
async function insertBehaviors(behaviors, timestamp) {
|
|
15196
|
+
const client = getClient();
|
|
15197
|
+
for (const behavior of behaviors) {
|
|
15198
|
+
await client.execute({
|
|
15199
|
+
sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, priority, content, active, created_at, updated_at)
|
|
15200
|
+
VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?)`,
|
|
15201
|
+
args: [
|
|
15202
|
+
randomUUID5(),
|
|
15203
|
+
behavior.agent_id,
|
|
15204
|
+
behavior.project_name,
|
|
15205
|
+
behavior.domain,
|
|
15206
|
+
behavior.priority,
|
|
15207
|
+
behavior.content,
|
|
15208
|
+
timestamp,
|
|
15209
|
+
timestamp
|
|
15210
|
+
]
|
|
15211
|
+
});
|
|
15212
|
+
}
|
|
15213
|
+
return behaviors.length;
|
|
15214
|
+
}
|
|
15215
|
+
async function insertProcedures(procedures, timestamp, options) {
|
|
15216
|
+
const client = getClient();
|
|
15217
|
+
const skipTitles = options?.skipTitles ?? /* @__PURE__ */ new Set();
|
|
15218
|
+
let inserted = 0;
|
|
15219
|
+
for (const procedure of procedures) {
|
|
15220
|
+
if (skipTitles.has(procedure.title) || PLATFORM_PROCEDURE_TITLES.has(procedure.title)) {
|
|
15221
|
+
continue;
|
|
15222
|
+
}
|
|
15223
|
+
await client.execute({
|
|
15224
|
+
sql: `INSERT INTO global_procedures (id, title, content, priority, domain, active, created_at, updated_at)
|
|
15225
|
+
VALUES (?, ?, ?, ?, ?, 1, ?, ?)`,
|
|
15226
|
+
args: [
|
|
15227
|
+
randomUUID5(),
|
|
15228
|
+
procedure.title,
|
|
15229
|
+
procedure.content,
|
|
15230
|
+
procedure.priority,
|
|
15231
|
+
procedure.domain,
|
|
15232
|
+
timestamp,
|
|
15233
|
+
timestamp
|
|
15234
|
+
]
|
|
15235
|
+
});
|
|
15236
|
+
skipTitles.add(procedure.title);
|
|
15237
|
+
inserted += 1;
|
|
15238
|
+
}
|
|
15239
|
+
return inserted;
|
|
15240
|
+
}
|
|
15241
|
+
async function replaceBehaviorsAndProcedures(behaviors, procedures, timestamp) {
|
|
15242
|
+
const client = getClient();
|
|
15243
|
+
await client.execute({
|
|
15244
|
+
sql: "UPDATE behaviors SET active = 0, updated_at = ? WHERE active = 1",
|
|
15245
|
+
args: [timestamp]
|
|
15246
|
+
});
|
|
15247
|
+
await client.execute({
|
|
15248
|
+
sql: "UPDATE global_procedures SET active = 0, updated_at = ? WHERE active = 1",
|
|
15249
|
+
args: [timestamp]
|
|
15250
|
+
});
|
|
15251
|
+
return {
|
|
15252
|
+
behaviors: await insertBehaviors(behaviors, timestamp),
|
|
15253
|
+
procedures: await insertProcedures(procedures, timestamp)
|
|
15254
|
+
};
|
|
15255
|
+
}
|
|
15256
|
+
async function mergeRosterEntries(importedRoster, timestamp) {
|
|
15257
|
+
const currentRoster = readRosterFile();
|
|
15258
|
+
const existingNames = new Set(currentRoster.map((entry) => entry.name.toLowerCase()));
|
|
15259
|
+
const additions = buildImportedRosterEntries(
|
|
15260
|
+
importedRoster.filter((entry) => !existingNames.has(entry.name.toLowerCase())),
|
|
15261
|
+
timestamp
|
|
15262
|
+
);
|
|
15263
|
+
if (additions.length > 0) {
|
|
15264
|
+
writeRosterFile([...currentRoster, ...additions]);
|
|
15265
|
+
}
|
|
15266
|
+
return additions.length;
|
|
15267
|
+
}
|
|
15268
|
+
async function replaceRosterEntries(importedRoster, timestamp) {
|
|
15269
|
+
const currentRoster = readRosterFile();
|
|
15270
|
+
const importedByName = new Map(
|
|
15271
|
+
buildImportedRosterEntries(importedRoster, timestamp).map((entry) => [entry.name.toLowerCase(), entry])
|
|
15272
|
+
);
|
|
15273
|
+
const merged = currentRoster.map((existing) => {
|
|
15274
|
+
const imported = importedByName.get(existing.name.toLowerCase());
|
|
15275
|
+
if (imported) {
|
|
15276
|
+
importedByName.delete(existing.name.toLowerCase());
|
|
15277
|
+
return imported;
|
|
15278
|
+
}
|
|
15279
|
+
return existing;
|
|
15280
|
+
});
|
|
15281
|
+
for (const newEntry of importedByName.values()) {
|
|
15282
|
+
merged.push(newEntry);
|
|
15283
|
+
}
|
|
15284
|
+
writeRosterFile(merged);
|
|
15285
|
+
return importedRoster.length;
|
|
15286
|
+
}
|
|
15287
|
+
async function importIdentities(identities, updatedBy) {
|
|
15288
|
+
const entries = Object.entries(identities);
|
|
15289
|
+
for (const [agentId, content] of entries) {
|
|
15290
|
+
await updateIdentity(agentId, content, updatedBy);
|
|
15291
|
+
}
|
|
15292
|
+
return entries.length;
|
|
15293
|
+
}
|
|
15294
|
+
async function getActiveProcedureTitles() {
|
|
15295
|
+
const client = getClient();
|
|
15296
|
+
const result = await client.execute({
|
|
15297
|
+
sql: "SELECT title FROM global_procedures WHERE active = 1",
|
|
15298
|
+
args: []
|
|
15299
|
+
});
|
|
15300
|
+
return new Set(result.rows.map((row) => String(row.title)));
|
|
15301
|
+
}
|
|
15302
|
+
async function exportOrchestration(createdBy) {
|
|
15303
|
+
const client = getClient();
|
|
15304
|
+
const roster = readRosterFile().map((entry) => ({
|
|
15305
|
+
...entry,
|
|
15306
|
+
createdAt: ""
|
|
15307
|
+
}));
|
|
15308
|
+
const identities = {};
|
|
15309
|
+
for (const identitySummary of listIdentities()) {
|
|
15310
|
+
const identity = getIdentity(identitySummary.agentId);
|
|
15311
|
+
if (identity?.raw) {
|
|
15312
|
+
identities[identitySummary.agentId] = identity.raw;
|
|
15313
|
+
}
|
|
15314
|
+
}
|
|
15315
|
+
const behaviorResult = await client.execute({
|
|
15316
|
+
sql: "SELECT agent_id, project_name, domain, content, priority FROM behaviors WHERE active = 1",
|
|
15317
|
+
args: []
|
|
15318
|
+
});
|
|
15319
|
+
const procedureResult = await client.execute({
|
|
15320
|
+
sql: "SELECT title, content, priority, domain FROM global_procedures WHERE active = 1",
|
|
15321
|
+
args: []
|
|
15322
|
+
});
|
|
15323
|
+
const behaviors = behaviorResult.rows.map((row) => ({
|
|
15324
|
+
agent_id: String(row.agent_id),
|
|
15325
|
+
project_name: row.project_name == null ? null : String(row.project_name),
|
|
15326
|
+
domain: row.domain == null ? null : String(row.domain),
|
|
15327
|
+
content: String(row.content),
|
|
15328
|
+
priority: ensurePriority(row.priority, "behaviors.priority", DEFAULT_BEHAVIOR_PRIORITY)
|
|
15329
|
+
}));
|
|
15330
|
+
const procedures = procedureResult.rows.map((row) => ({
|
|
15331
|
+
title: String(row.title),
|
|
15332
|
+
content: String(row.content),
|
|
15333
|
+
priority: ensurePriority(row.priority, "procedures.priority", DEFAULT_PROCEDURE_PRIORITY),
|
|
15334
|
+
domain: row.domain == null ? null : String(row.domain)
|
|
15335
|
+
})).filter((procedure) => !PLATFORM_PROCEDURE_TITLES.has(procedure.title));
|
|
15336
|
+
return {
|
|
15337
|
+
version: PACKAGE_VERSION,
|
|
15338
|
+
created_by: createdBy,
|
|
15339
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15340
|
+
roster,
|
|
15341
|
+
identities,
|
|
15342
|
+
behaviors,
|
|
15343
|
+
procedures
|
|
15344
|
+
};
|
|
15345
|
+
}
|
|
15346
|
+
async function importOrchestration(pkg, strategy) {
|
|
15347
|
+
const validated = validatePackage(pkg);
|
|
15348
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
15349
|
+
const updatedBy = validated.created_by || DEFAULT_IDENTITY_UPDATED_BY;
|
|
15350
|
+
const rosterCount = strategy === "replace" ? await replaceRosterEntries(validated.roster, timestamp) : await mergeRosterEntries(validated.roster, timestamp);
|
|
15351
|
+
const identityCount = await importIdentities(validated.identities, updatedBy);
|
|
15352
|
+
if (strategy === "replace") {
|
|
15353
|
+
const replaced = await replaceBehaviorsAndProcedures(
|
|
15354
|
+
validated.behaviors,
|
|
15355
|
+
validated.procedures,
|
|
15356
|
+
timestamp
|
|
15357
|
+
);
|
|
15358
|
+
return {
|
|
15359
|
+
imported: {
|
|
15360
|
+
roster: rosterCount,
|
|
15361
|
+
identities: identityCount,
|
|
15362
|
+
behaviors: replaced.behaviors,
|
|
15363
|
+
procedures: replaced.procedures
|
|
15364
|
+
}
|
|
15365
|
+
};
|
|
15366
|
+
}
|
|
15367
|
+
const existingProcedureTitles = await getActiveProcedureTitles();
|
|
15368
|
+
const behaviorCount = await insertBehaviors(validated.behaviors, timestamp);
|
|
15369
|
+
const procedureCount = await insertProcedures(
|
|
15370
|
+
validated.procedures,
|
|
15371
|
+
timestamp,
|
|
15372
|
+
{ skipTitles: existingProcedureTitles }
|
|
15373
|
+
);
|
|
15374
|
+
return {
|
|
15375
|
+
imported: {
|
|
15376
|
+
roster: rosterCount,
|
|
15377
|
+
identities: identityCount,
|
|
15378
|
+
behaviors: behaviorCount,
|
|
15379
|
+
procedures: procedureCount
|
|
15380
|
+
}
|
|
15381
|
+
};
|
|
15382
|
+
}
|
|
15383
|
+
function validatePackage(data) {
|
|
15384
|
+
const record = ensureObject(data, "package");
|
|
15385
|
+
const version = ensureString(record.version, "version");
|
|
15386
|
+
if (version !== PACKAGE_VERSION) {
|
|
15387
|
+
throw new Error(`Unsupported orchestration package version: ${version}`);
|
|
15388
|
+
}
|
|
15389
|
+
if (!Array.isArray(record.roster)) {
|
|
15390
|
+
throw new Error("roster is required and must be an array");
|
|
15391
|
+
}
|
|
15392
|
+
if (record.identities == null || Array.isArray(record.identities) || typeof record.identities !== "object") {
|
|
15393
|
+
throw new Error("identities is required and must be an object");
|
|
15394
|
+
}
|
|
15395
|
+
if (!Array.isArray(record.behaviors)) {
|
|
15396
|
+
throw new Error("behaviors is required and must be an array");
|
|
15397
|
+
}
|
|
15398
|
+
if (!Array.isArray(record.procedures)) {
|
|
15399
|
+
throw new Error("procedures is required and must be an array");
|
|
15400
|
+
}
|
|
15401
|
+
const identities = Object.entries(record.identities).reduce(
|
|
15402
|
+
(acc, [agentId, content]) => {
|
|
15403
|
+
acc[agentId] = ensureString(content, `identities.${agentId}`);
|
|
15404
|
+
return acc;
|
|
15405
|
+
},
|
|
15406
|
+
{}
|
|
15407
|
+
);
|
|
15408
|
+
return {
|
|
15409
|
+
version: PACKAGE_VERSION,
|
|
15410
|
+
created_by: ensureString(record.created_by, "created_by"),
|
|
15411
|
+
created_at: ensureString(record.created_at, "created_at"),
|
|
15412
|
+
roster: record.roster.map((entry, index) => validateRosterEntry(entry, index)),
|
|
15413
|
+
identities,
|
|
15414
|
+
behaviors: record.behaviors.map((entry, index) => validateBehaviorEntry(entry, index)),
|
|
15415
|
+
procedures: record.procedures.map((entry, index) => validateProcedureEntry(entry, index))
|
|
15416
|
+
};
|
|
15417
|
+
}
|
|
15418
|
+
|
|
15419
|
+
// src/mcp/tools/export-orchestration.ts
|
|
15420
|
+
init_store();
|
|
15421
|
+
function registerExportOrchestration(server2) {
|
|
15422
|
+
server2.registerTool(
|
|
15423
|
+
"export_orchestration",
|
|
15424
|
+
{
|
|
15425
|
+
title: "Export Orchestration",
|
|
15426
|
+
description: "Export roster, identities, behaviors, and customer procedures to a JSON package.",
|
|
15427
|
+
inputSchema: {
|
|
15428
|
+
output_path: z38.string().describe("File path to write the JSON package")
|
|
15429
|
+
}
|
|
15430
|
+
},
|
|
15431
|
+
async ({ output_path }) => {
|
|
15432
|
+
try {
|
|
15433
|
+
await initStore();
|
|
15434
|
+
const pkg = await exportOrchestration(getActiveAgent().agentId);
|
|
15435
|
+
mkdirSync13(path29.dirname(output_path), { recursive: true });
|
|
15436
|
+
writeFileSync15(output_path, `${JSON.stringify(pkg, null, 2)}
|
|
15437
|
+
`, "utf-8");
|
|
15438
|
+
return {
|
|
15439
|
+
content: [{
|
|
15440
|
+
type: "text",
|
|
15441
|
+
text: `Exported ${pkg.roster.length} roster entries, ${Object.keys(pkg.identities).length} identities, ${pkg.behaviors.length} behaviors, ${pkg.procedures.length} procedures to ${output_path}`
|
|
15442
|
+
}]
|
|
15443
|
+
};
|
|
15444
|
+
} catch (err) {
|
|
15445
|
+
return {
|
|
15446
|
+
content: [{
|
|
15447
|
+
type: "text",
|
|
15448
|
+
text: `Failed to export orchestration: ${err instanceof Error ? err.message : String(err)}`
|
|
15449
|
+
}],
|
|
15450
|
+
isError: true
|
|
15451
|
+
};
|
|
15452
|
+
}
|
|
15453
|
+
}
|
|
15454
|
+
);
|
|
15455
|
+
}
|
|
15456
|
+
|
|
15457
|
+
// src/mcp/tools/import-orchestration.ts
|
|
15458
|
+
import { readFileSync as readFileSync19 } from "fs";
|
|
15459
|
+
import { z as z39 } from "zod";
|
|
15460
|
+
init_store();
|
|
15461
|
+
function registerImportOrchestration(server2) {
|
|
15462
|
+
server2.registerTool(
|
|
15463
|
+
"import_orchestration",
|
|
15464
|
+
{
|
|
15465
|
+
title: "Import Orchestration",
|
|
15466
|
+
description: "Import roster, identities, behaviors, and procedures from an orchestration package.",
|
|
15467
|
+
inputSchema: {
|
|
15468
|
+
package_path: z39.string().describe("Path to the orchestration package JSON file"),
|
|
15469
|
+
merge_strategy: z39.enum(["replace", "merge"]).default("merge").describe("How to apply the package: replace existing data or merge additively")
|
|
15470
|
+
}
|
|
15471
|
+
},
|
|
15472
|
+
async ({ package_path, merge_strategy }) => {
|
|
15473
|
+
try {
|
|
15474
|
+
await initStore();
|
|
15475
|
+
const raw = readFileSync19(package_path, "utf-8");
|
|
15476
|
+
const pkg = validatePackage(JSON.parse(raw));
|
|
15477
|
+
const result = await importOrchestration(pkg, merge_strategy);
|
|
15478
|
+
return {
|
|
15479
|
+
content: [{
|
|
15480
|
+
type: "text",
|
|
15481
|
+
text: `Imported ${result.imported.roster} roster entries, ${result.imported.identities} identities, ${result.imported.behaviors} behaviors, ${result.imported.procedures} procedures using ${merge_strategy} strategy`
|
|
15482
|
+
}]
|
|
15483
|
+
};
|
|
15484
|
+
} catch (err) {
|
|
15485
|
+
return {
|
|
15486
|
+
content: [{
|
|
15487
|
+
type: "text",
|
|
15488
|
+
text: `Failed to import orchestration: ${err instanceof Error ? err.message : String(err)}`
|
|
15489
|
+
}],
|
|
15490
|
+
isError: true
|
|
15491
|
+
};
|
|
15492
|
+
}
|
|
15493
|
+
}
|
|
15494
|
+
);
|
|
15495
|
+
}
|
|
14819
15496
|
|
|
14820
15497
|
// src/mcp/tools/query-conversations.ts
|
|
14821
15498
|
init_database();
|
|
14822
|
-
import { z as
|
|
15499
|
+
import { z as z40 } from "zod";
|
|
14823
15500
|
function registerQueryConversations(server2) {
|
|
14824
15501
|
server2.registerTool(
|
|
14825
15502
|
"query_conversations",
|
|
@@ -14827,14 +15504,14 @@ function registerQueryConversations(server2) {
|
|
|
14827
15504
|
title: "Query Conversations",
|
|
14828
15505
|
description: "Search across all adapter messages by content, sender, date range, or platform. Returns messages with source attribution (platform, sender, timestamp).",
|
|
14829
15506
|
inputSchema: {
|
|
14830
|
-
query:
|
|
14831
|
-
sender:
|
|
14832
|
-
platform:
|
|
14833
|
-
after:
|
|
14834
|
-
before:
|
|
14835
|
-
channel_id:
|
|
14836
|
-
thread_id:
|
|
14837
|
-
limit:
|
|
15507
|
+
query: z40.string().optional().describe("Full-text search query across message content and responses"),
|
|
15508
|
+
sender: z40.string().optional().describe("Filter by sender ID or name (partial match)"),
|
|
15509
|
+
platform: z40.string().optional().describe("Filter by platform: whatsapp, signal, telegram, discord, imessage, slack, email, webchat"),
|
|
15510
|
+
after: z40.string().optional().describe("Filter messages after this ISO 8601 date (e.g. 2026-04-01)"),
|
|
15511
|
+
before: z40.string().optional().describe("Filter messages before this ISO 8601 date (e.g. 2026-04-15)"),
|
|
15512
|
+
channel_id: z40.string().optional().describe("Filter by channel/chat ID"),
|
|
15513
|
+
thread_id: z40.string().optional().describe("Filter by conversation thread ID"),
|
|
15514
|
+
limit: z40.number().int().min(1).max(100).optional().default(25).describe("Max results to return (default 25, max 100)")
|
|
14838
15515
|
}
|
|
14839
15516
|
},
|
|
14840
15517
|
async (params) => {
|
|
@@ -14941,19 +15618,19 @@ function registerQueryConversations(server2) {
|
|
|
14941
15618
|
}
|
|
14942
15619
|
|
|
14943
15620
|
// src/mcp/tools/load-skill.ts
|
|
14944
|
-
import { z as
|
|
14945
|
-
import { readFileSync as
|
|
14946
|
-
import
|
|
15621
|
+
import { z as z41 } from "zod";
|
|
15622
|
+
import { readFileSync as readFileSync20, readdirSync as readdirSync8, statSync as statSync3 } from "fs";
|
|
15623
|
+
import path30 from "path";
|
|
14947
15624
|
import { homedir as homedir2 } from "os";
|
|
14948
|
-
var SKILLS_DIR =
|
|
15625
|
+
var SKILLS_DIR = path30.join(homedir2(), ".claude", "skills");
|
|
14949
15626
|
function listAvailableSkills() {
|
|
14950
15627
|
try {
|
|
14951
15628
|
const entries = readdirSync8(SKILLS_DIR);
|
|
14952
15629
|
return entries.filter((entry) => {
|
|
14953
15630
|
try {
|
|
14954
|
-
const entryPath =
|
|
15631
|
+
const entryPath = path30.join(SKILLS_DIR, entry);
|
|
14955
15632
|
if (!statSync3(entryPath).isDirectory()) return false;
|
|
14956
|
-
const skillFile =
|
|
15633
|
+
const skillFile = path30.join(entryPath, "SKILL.md");
|
|
14957
15634
|
statSync3(skillFile);
|
|
14958
15635
|
return true;
|
|
14959
15636
|
} catch {
|
|
@@ -14971,7 +15648,7 @@ function registerLoadSkill(server2) {
|
|
|
14971
15648
|
title: "Load Skill",
|
|
14972
15649
|
description: "Load domain-specific guidance into your context. Use when you need specialized knowledge for a task (e.g., load_skill('seo') before doing SEO work, load_skill('code-reviewer') before reviewing code). Pass skill_name='list' to see all available skills.",
|
|
14973
15650
|
inputSchema: {
|
|
14974
|
-
skill_name:
|
|
15651
|
+
skill_name: z41.string().describe(
|
|
14975
15652
|
"Skill to load (e.g. 'seo', 'code-reviewer', 'frontend-design'). Pass 'list' to see all available skills."
|
|
14976
15653
|
)
|
|
14977
15654
|
}
|
|
@@ -14996,10 +15673,10 @@ ${skills.map((s) => `- ${s}`).join("\n")}`
|
|
|
14996
15673
|
}]
|
|
14997
15674
|
};
|
|
14998
15675
|
}
|
|
14999
|
-
const sanitized =
|
|
15000
|
-
const skillFile =
|
|
15676
|
+
const sanitized = path30.basename(skill_name);
|
|
15677
|
+
const skillFile = path30.join(SKILLS_DIR, sanitized, "SKILL.md");
|
|
15001
15678
|
try {
|
|
15002
|
-
const content =
|
|
15679
|
+
const content = readFileSync20(skillFile, "utf-8");
|
|
15003
15680
|
return {
|
|
15004
15681
|
content: [{
|
|
15005
15682
|
type: "text",
|
|
@@ -15028,7 +15705,7 @@ ${available.map((s) => `- ${s}`).join("\n")}` : "\n\nNo skills found in ~/.claud
|
|
|
15028
15705
|
// src/mcp/tools/consolidate-memories.ts
|
|
15029
15706
|
init_database();
|
|
15030
15707
|
init_active_agent();
|
|
15031
|
-
import { z as
|
|
15708
|
+
import { z as z42 } from "zod";
|
|
15032
15709
|
function registerConsolidateMemories(server2) {
|
|
15033
15710
|
server2.registerTool(
|
|
15034
15711
|
"consolidate_memories",
|
|
@@ -15036,8 +15713,8 @@ function registerConsolidateMemories(server2) {
|
|
|
15036
15713
|
title: "Consolidate Memories",
|
|
15037
15714
|
description: "Trigger content-aware memory consolidation. Groups recent memories by project, uses LLM to extract key facts, decisions, and patterns, then stores a high-importance summary and archives the originals. Runs automatically during idle time, but can be triggered manually when you want to compress your working memory.",
|
|
15038
15715
|
inputSchema: {
|
|
15039
|
-
max_clusters:
|
|
15040
|
-
model:
|
|
15716
|
+
max_clusters: z42.coerce.number().optional().default(5).describe("Maximum number of clusters to consolidate (default 5)"),
|
|
15717
|
+
model: z42.string().optional().describe("LLM model for summarization (defaults to config value)")
|
|
15041
15718
|
}
|
|
15042
15719
|
},
|
|
15043
15720
|
async ({ max_clusters, model }) => {
|
|
@@ -15093,7 +15770,7 @@ Consolidated summaries stored as tier-1 (importance=9) memories.`
|
|
|
15093
15770
|
init_global_procedures();
|
|
15094
15771
|
init_active_agent();
|
|
15095
15772
|
init_employees();
|
|
15096
|
-
import { z as
|
|
15773
|
+
import { z as z43 } from "zod";
|
|
15097
15774
|
function registerStoreGlobalProcedure(server2) {
|
|
15098
15775
|
server2.registerTool(
|
|
15099
15776
|
"store_global_procedure",
|
|
@@ -15101,10 +15778,10 @@ function registerStoreGlobalProcedure(server2) {
|
|
|
15101
15778
|
title: "Store Global Procedure",
|
|
15102
15779
|
description: "Create an organization-wide procedure (Layer 0) that supersedes identity, expertise, and experience. Use for hard rules that every employee must follow. RESTRICTED: only coordinator or founder sessions.",
|
|
15103
15780
|
inputSchema: {
|
|
15104
|
-
title:
|
|
15105
|
-
content:
|
|
15106
|
-
priority:
|
|
15107
|
-
domain:
|
|
15781
|
+
title: z43.string().describe("Short title for the procedure"),
|
|
15782
|
+
content: z43.string().max(500).describe("The procedure content \u2014 clear, actionable instruction"),
|
|
15783
|
+
priority: z43.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always (default). p1 = standard. p2 = nice-to-have."),
|
|
15784
|
+
domain: z43.string().optional().describe("Category: workflow, code-style, communication, architecture, testing, security")
|
|
15108
15785
|
}
|
|
15109
15786
|
},
|
|
15110
15787
|
async ({ title, content, priority, domain }) => {
|
|
@@ -15182,7 +15859,7 @@ init_global_procedures();
|
|
|
15182
15859
|
init_active_agent();
|
|
15183
15860
|
init_database();
|
|
15184
15861
|
init_employees();
|
|
15185
|
-
import { z as
|
|
15862
|
+
import { z as z44 } from "zod";
|
|
15186
15863
|
function registerDeactivateGlobalProcedure(server2) {
|
|
15187
15864
|
server2.registerTool(
|
|
15188
15865
|
"deactivate_global_procedure",
|
|
@@ -15190,7 +15867,7 @@ function registerDeactivateGlobalProcedure(server2) {
|
|
|
15190
15867
|
title: "Deactivate Global Procedure",
|
|
15191
15868
|
description: "Soft-delete a global procedure by setting active = 0. RESTRICTED: only coordinator or founder sessions. Use list_global_procedures to find the procedure ID first.",
|
|
15192
15869
|
inputSchema: {
|
|
15193
|
-
procedure_id:
|
|
15870
|
+
procedure_id: z44.string().describe("UUID of the global procedure to deactivate")
|
|
15194
15871
|
}
|
|
15195
15872
|
},
|
|
15196
15873
|
async ({ procedure_id }) => {
|
|
@@ -15245,7 +15922,7 @@ Content: ${row.content}`
|
|
|
15245
15922
|
}
|
|
15246
15923
|
|
|
15247
15924
|
// src/mcp/tools/search-everything.ts
|
|
15248
|
-
import { z as
|
|
15925
|
+
import { z as z45 } from "zod";
|
|
15249
15926
|
|
|
15250
15927
|
// src/lib/unified-search.ts
|
|
15251
15928
|
var DEFAULT_LIMIT = 10;
|
|
@@ -15412,11 +16089,11 @@ function registerSearchEverything(server2) {
|
|
|
15412
16089
|
title: "Search Everything",
|
|
15413
16090
|
description: "Search across all data stores \u2014 memories, conversations, and wiki \u2014 in one query. Returns merged results sorted by relevance with entity links.",
|
|
15414
16091
|
inputSchema: {
|
|
15415
|
-
query:
|
|
15416
|
-
sources:
|
|
16092
|
+
query: z45.string().describe("What to search for across all data stores"),
|
|
16093
|
+
sources: z45.array(z45.enum(["memory", "conversations", "wiki"])).optional().describe(
|
|
15417
16094
|
"Which sources to search (default: all). Options: memory, conversations, wiki"
|
|
15418
16095
|
),
|
|
15419
|
-
limit:
|
|
16096
|
+
limit: z45.coerce.number().int().min(1).max(50).optional().default(10).describe("Max results to return (default 10, max 50)")
|
|
15420
16097
|
}
|
|
15421
16098
|
},
|
|
15422
16099
|
async (params) => {
|
|
@@ -15477,7 +16154,7 @@ init_store();
|
|
|
15477
16154
|
init_active_agent();
|
|
15478
16155
|
init_database();
|
|
15479
16156
|
init_plan_limits();
|
|
15480
|
-
import { z as
|
|
16157
|
+
import { z as z46 } from "zod";
|
|
15481
16158
|
import crypto14 from "crypto";
|
|
15482
16159
|
function registerStoreDecision(server2) {
|
|
15483
16160
|
server2.registerTool(
|
|
@@ -15486,13 +16163,13 @@ function registerStoreDecision(server2) {
|
|
|
15486
16163
|
title: "Store Decision",
|
|
15487
16164
|
description: "Store an authoritative decision keyed by domain. Use this when a decision is made that should be canonical \u2014 future lookups via get_decision return the latest decision for that domain. Supports supersession chains.",
|
|
15488
16165
|
inputSchema: {
|
|
15489
|
-
domain:
|
|
16166
|
+
domain: z46.string().describe(
|
|
15490
16167
|
"Domain key, e.g. 'auth-strategy', 'db-migration-approach', 'api-versioning'"
|
|
15491
16168
|
),
|
|
15492
|
-
decision:
|
|
15493
|
-
rationale:
|
|
15494
|
-
supersedes:
|
|
15495
|
-
project_name:
|
|
16169
|
+
decision: z46.string().describe("The decision text \u2014 what was decided"),
|
|
16170
|
+
rationale: z46.string().optional().describe("Why this decision was made \u2014 constraints, trade-offs, context"),
|
|
16171
|
+
supersedes: z46.string().optional().describe("UUID of the decision this supersedes (previous decision for this domain)"),
|
|
16172
|
+
project_name: z46.string().optional().describe("Project name")
|
|
15496
16173
|
}
|
|
15497
16174
|
},
|
|
15498
16175
|
async ({ domain, decision, rationale, supersedes, project_name }) => {
|
|
@@ -15560,7 +16237,7 @@ Supersedes: ${supersedes}` : ""}`
|
|
|
15560
16237
|
|
|
15561
16238
|
// src/mcp/tools/get-decision.ts
|
|
15562
16239
|
init_database();
|
|
15563
|
-
import { z as
|
|
16240
|
+
import { z as z47 } from "zod";
|
|
15564
16241
|
function registerGetDecision(server2) {
|
|
15565
16242
|
server2.registerTool(
|
|
15566
16243
|
"get_decision",
|
|
@@ -15568,7 +16245,7 @@ function registerGetDecision(server2) {
|
|
|
15568
16245
|
title: "Get Decision",
|
|
15569
16246
|
description: "Retrieve the latest authoritative decision for a domain. Returns the current active decision and the supersession history.",
|
|
15570
16247
|
inputSchema: {
|
|
15571
|
-
domain:
|
|
16248
|
+
domain: z47.string().describe(
|
|
15572
16249
|
"Domain key to look up, e.g. 'auth-strategy', 'db-migration-approach'"
|
|
15573
16250
|
)
|
|
15574
16251
|
}
|
|
@@ -15631,15 +16308,15 @@ function registerGetDecision(server2) {
|
|
|
15631
16308
|
}
|
|
15632
16309
|
|
|
15633
16310
|
// src/mcp/tools/get-agent-spend.ts
|
|
15634
|
-
import { z as
|
|
16311
|
+
import { z as z48 } from "zod";
|
|
15635
16312
|
|
|
15636
16313
|
// src/lib/token-spend.ts
|
|
15637
16314
|
init_database();
|
|
15638
16315
|
import { readdir } from "fs/promises";
|
|
15639
16316
|
import { createReadStream } from "fs";
|
|
15640
16317
|
import { createInterface } from "readline";
|
|
15641
|
-
import
|
|
15642
|
-
import
|
|
16318
|
+
import path31 from "path";
|
|
16319
|
+
import os12 from "os";
|
|
15643
16320
|
var MODEL_PRICING = {
|
|
15644
16321
|
// Opus 4.5+ ($5/$25 — Anthropic price drop from original Opus 4)
|
|
15645
16322
|
"claude-opus-4-7": { input: 5 / 1e6, output: 25 / 1e6, cacheRead: 0.5 / 1e6, cacheWrite: 6.25 / 1e6 },
|
|
@@ -15687,18 +16364,18 @@ async function getAgentSpend(period = "7d") {
|
|
|
15687
16364
|
for (const row of result.rows) {
|
|
15688
16365
|
sessionAgent.set(row.session_uuid, row.agent_id);
|
|
15689
16366
|
}
|
|
15690
|
-
const claudeDir =
|
|
16367
|
+
const claudeDir = path31.join(os12.homedir(), ".claude", "projects");
|
|
15691
16368
|
let projectDirs = [];
|
|
15692
16369
|
try {
|
|
15693
16370
|
const entries = await readdir(claudeDir);
|
|
15694
|
-
projectDirs = entries.map((e) =>
|
|
16371
|
+
projectDirs = entries.map((e) => path31.join(claudeDir, e));
|
|
15695
16372
|
} catch {
|
|
15696
16373
|
return [];
|
|
15697
16374
|
}
|
|
15698
16375
|
const agentTotals = /* @__PURE__ */ new Map();
|
|
15699
16376
|
for (const [sessionUuid, agentId] of sessionAgent) {
|
|
15700
16377
|
for (const dir of projectDirs) {
|
|
15701
|
-
const jsonlPath =
|
|
16378
|
+
const jsonlPath = path31.join(dir, `${sessionUuid}.jsonl`);
|
|
15702
16379
|
try {
|
|
15703
16380
|
const usage = await extractSessionUsage(jsonlPath);
|
|
15704
16381
|
if (usage.input === 0 && usage.output === 0) continue;
|
|
@@ -15793,8 +16470,8 @@ function registerGetAgentSpend(server2) {
|
|
|
15793
16470
|
title: "Get Agent Spend",
|
|
15794
16471
|
description: "Get per-agent token spend attribution. Shows input, output, and cache tokens consumed by each agent over a time period, with estimated cost.",
|
|
15795
16472
|
inputSchema: {
|
|
15796
|
-
period:
|
|
15797
|
-
agent_id:
|
|
16473
|
+
period: z48.enum(["24h", "7d", "30d"]).default("7d").describe("Time period to query"),
|
|
16474
|
+
agent_id: z48.string().optional().describe("Filter to a specific agent (e.g. 'tom', 'yoshi')")
|
|
15798
16475
|
}
|
|
15799
16476
|
},
|
|
15800
16477
|
async ({ period, agent_id }) => {
|
|
@@ -15860,7 +16537,7 @@ function registerGetAgentSpend(server2) {
|
|
|
15860
16537
|
// src/mcp/tools/get-graph-stats.ts
|
|
15861
16538
|
init_database();
|
|
15862
16539
|
init_graph_query();
|
|
15863
|
-
import { z as
|
|
16540
|
+
import { z as z49 } from "zod";
|
|
15864
16541
|
function registerGetGraphStats(server2) {
|
|
15865
16542
|
server2.registerTool(
|
|
15866
16543
|
"get_graph_stats",
|
|
@@ -15868,7 +16545,7 @@ function registerGetGraphStats(server2) {
|
|
|
15868
16545
|
title: "Get Graph Stats",
|
|
15869
16546
|
description: "Get knowledge graph summary statistics: entity count, relationship count, and entity type breakdown.",
|
|
15870
16547
|
inputSchema: {
|
|
15871
|
-
_dummy:
|
|
16548
|
+
_dummy: z49.string().optional().describe("Unused \u2014 no input required")
|
|
15872
16549
|
}
|
|
15873
16550
|
},
|
|
15874
16551
|
async () => {
|
|
@@ -15910,7 +16587,7 @@ function registerGetGraphStats(server2) {
|
|
|
15910
16587
|
// src/mcp/tools/get-entity-neighbors.ts
|
|
15911
16588
|
init_database();
|
|
15912
16589
|
init_graph_query();
|
|
15913
|
-
import { z as
|
|
16590
|
+
import { z as z50 } from "zod";
|
|
15914
16591
|
function registerGetEntityNeighbors(server2) {
|
|
15915
16592
|
server2.registerTool(
|
|
15916
16593
|
"get_entity_neighbors",
|
|
@@ -15918,7 +16595,7 @@ function registerGetEntityNeighbors(server2) {
|
|
|
15918
16595
|
title: "Get Entity Neighbors",
|
|
15919
16596
|
description: "Get connected entities for a given entity name. Returns neighbors with relationship types, directions, and weights.",
|
|
15920
16597
|
inputSchema: {
|
|
15921
|
-
entity_name:
|
|
16598
|
+
entity_name: z50.string().describe("Name of the entity to find neighbors for")
|
|
15922
16599
|
}
|
|
15923
16600
|
},
|
|
15924
16601
|
async ({ entity_name }) => {
|
|
@@ -15987,7 +16664,7 @@ function registerGetEntityNeighbors(server2) {
|
|
|
15987
16664
|
// src/mcp/tools/get-hot-entities.ts
|
|
15988
16665
|
init_database();
|
|
15989
16666
|
init_graph_query();
|
|
15990
|
-
import { z as
|
|
16667
|
+
import { z as z51 } from "zod";
|
|
15991
16668
|
var PERIOD_MS = {
|
|
15992
16669
|
"24h": 24 * 60 * 60 * 1e3,
|
|
15993
16670
|
"7d": 7 * 24 * 60 * 60 * 1e3,
|
|
@@ -16000,8 +16677,8 @@ function registerGetHotEntities(server2) {
|
|
|
16000
16677
|
title: "Get Hot Entities",
|
|
16001
16678
|
description: "Get trending entities \u2014 those with the most new relationships in a time period. Surfaces what's most active in the knowledge graph.",
|
|
16002
16679
|
inputSchema: {
|
|
16003
|
-
period:
|
|
16004
|
-
limit:
|
|
16680
|
+
period: z51.enum(["24h", "7d", "30d"]).default("7d").describe("Time period to look back"),
|
|
16681
|
+
limit: z51.number().int().min(1).max(50).default(10).describe("Max entities to return")
|
|
16005
16682
|
}
|
|
16006
16683
|
},
|
|
16007
16684
|
async ({ period, limit }) => {
|
|
@@ -16049,7 +16726,7 @@ function registerGetHotEntities(server2) {
|
|
|
16049
16726
|
|
|
16050
16727
|
// src/mcp/tools/export-graph.ts
|
|
16051
16728
|
init_database();
|
|
16052
|
-
import { z as
|
|
16729
|
+
import { z as z52 } from "zod";
|
|
16053
16730
|
|
|
16054
16731
|
// src/lib/graph-export.ts
|
|
16055
16732
|
async function loadGraphData(client) {
|
|
@@ -16262,7 +16939,7 @@ function registerExportGraph(server2) {
|
|
|
16262
16939
|
title: "Export Graph",
|
|
16263
16940
|
description: "Export the knowledge graph as a markdown report (inline) or an interactive HTML visualization (writes file, returns path).",
|
|
16264
16941
|
inputSchema: {
|
|
16265
|
-
format:
|
|
16942
|
+
format: z52.enum(["html", "markdown"]).default("markdown").describe("Export format: markdown (inline) or html (file)")
|
|
16266
16943
|
}
|
|
16267
16944
|
},
|
|
16268
16945
|
async ({ format }) => {
|
|
@@ -16276,12 +16953,12 @@ function registerExportGraph(server2) {
|
|
|
16276
16953
|
}
|
|
16277
16954
|
const html = await exportGraphHTML(client);
|
|
16278
16955
|
const fs = await import("fs");
|
|
16279
|
-
const
|
|
16280
|
-
const
|
|
16281
|
-
const outDir =
|
|
16956
|
+
const path40 = await import("path");
|
|
16957
|
+
const os14 = await import("os");
|
|
16958
|
+
const outDir = path40.join(os14.homedir(), ".exe-os", "exports");
|
|
16282
16959
|
fs.mkdirSync(outDir, { recursive: true });
|
|
16283
16960
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
16284
|
-
const filePath =
|
|
16961
|
+
const filePath = path40.join(outDir, `graph-${timestamp}.html`);
|
|
16285
16962
|
fs.writeFileSync(filePath, html, "utf-8");
|
|
16286
16963
|
return {
|
|
16287
16964
|
content: [
|
|
@@ -16312,7 +16989,7 @@ Open in a browser to explore interactively.`
|
|
|
16312
16989
|
|
|
16313
16990
|
// src/mcp/tools/find-similar-trajectories.ts
|
|
16314
16991
|
init_skill_learning();
|
|
16315
|
-
import { z as
|
|
16992
|
+
import { z as z53 } from "zod";
|
|
16316
16993
|
function registerFindSimilarTrajectories(server2) {
|
|
16317
16994
|
server2.registerTool(
|
|
16318
16995
|
"find_similar_trajectories",
|
|
@@ -16320,7 +16997,7 @@ function registerFindSimilarTrajectories(server2) {
|
|
|
16320
16997
|
title: "Find Similar Trajectories",
|
|
16321
16998
|
description: 'Find past task trajectories that match a described tool sequence. Input a comma-separated tool sequence (e.g. "Read, Edit, Bash, Read") to find similar past workflows.',
|
|
16322
16999
|
inputSchema: {
|
|
16323
|
-
description:
|
|
17000
|
+
description: z53.string().describe(
|
|
16324
17001
|
'Tool sequence to match \u2014 comma-separated tool names (e.g. "Read, Grep, Edit, Bash:npm, Bash:git")'
|
|
16325
17002
|
)
|
|
16326
17003
|
}
|
|
@@ -16391,7 +17068,7 @@ ${withSkill.length} trajectory(s) already extracted into skill(s).`
|
|
|
16391
17068
|
|
|
16392
17069
|
// src/mcp/tools/get-session-kills.ts
|
|
16393
17070
|
init_session_kill_telemetry();
|
|
16394
|
-
import { z as
|
|
17071
|
+
import { z as z54 } from "zod";
|
|
16395
17072
|
var PERIOD_MS2 = {
|
|
16396
17073
|
"24h": 24 * 60 * 60 * 1e3,
|
|
16397
17074
|
"7d": 7 * 24 * 60 * 60 * 1e3,
|
|
@@ -16407,7 +17084,7 @@ function registerGetSessionKills(server2) {
|
|
|
16407
17084
|
title: "Get Session Kills",
|
|
16408
17085
|
description: "Get session kill telemetry: how many idle/TTL sessions were killed, tokens saved, and estimated cost savings over a time period.",
|
|
16409
17086
|
inputSchema: {
|
|
16410
|
-
period:
|
|
17087
|
+
period: z54.enum(["24h", "7d", "30d"]).default("7d").describe("Time period to query")
|
|
16411
17088
|
}
|
|
16412
17089
|
},
|
|
16413
17090
|
async ({ period }) => {
|
|
@@ -16447,7 +17124,7 @@ function registerGetSessionKills(server2) {
|
|
|
16447
17124
|
|
|
16448
17125
|
// src/mcp/tools/list-agent-sessions.ts
|
|
16449
17126
|
init_session_registry();
|
|
16450
|
-
import { z as
|
|
17127
|
+
import { z as z55 } from "zod";
|
|
16451
17128
|
function registerListAgentSessions(server2) {
|
|
16452
17129
|
server2.registerTool(
|
|
16453
17130
|
"list_agent_sessions",
|
|
@@ -16455,7 +17132,7 @@ function registerListAgentSessions(server2) {
|
|
|
16455
17132
|
title: "List Agent Sessions",
|
|
16456
17133
|
description: "List all registered agent sessions with their agent ID, project, PID, and registration time.",
|
|
16457
17134
|
inputSchema: {
|
|
16458
|
-
_placeholder:
|
|
17135
|
+
_placeholder: z55.string().optional().describe("No input required")
|
|
16459
17136
|
}
|
|
16460
17137
|
},
|
|
16461
17138
|
async () => {
|
|
@@ -16501,11 +17178,11 @@ function registerListAgentSessions(server2) {
|
|
|
16501
17178
|
}
|
|
16502
17179
|
|
|
16503
17180
|
// src/mcp/tools/get-daemon-health.ts
|
|
16504
|
-
import { z as
|
|
16505
|
-
import { existsSync as
|
|
16506
|
-
import
|
|
17181
|
+
import { z as z56 } from "zod";
|
|
17182
|
+
import { existsSync as existsSync23, readFileSync as readFileSync21 } from "fs";
|
|
17183
|
+
import path32 from "path";
|
|
16507
17184
|
import { homedir as homedir3 } from "os";
|
|
16508
|
-
var PID_PATH2 =
|
|
17185
|
+
var PID_PATH2 = path32.join(homedir3(), ".exe-os", "exed.pid");
|
|
16509
17186
|
function formatUptime(seconds) {
|
|
16510
17187
|
const h = Math.floor(seconds / 3600);
|
|
16511
17188
|
const m = Math.floor(seconds % 3600 / 60);
|
|
@@ -16516,8 +17193,8 @@ function formatUptime(seconds) {
|
|
|
16516
17193
|
}
|
|
16517
17194
|
function isDaemonAlive() {
|
|
16518
17195
|
try {
|
|
16519
|
-
if (!
|
|
16520
|
-
const pid = parseInt(
|
|
17196
|
+
if (!existsSync23(PID_PATH2)) return { alive: false, pid: null };
|
|
17197
|
+
const pid = parseInt(readFileSync21(PID_PATH2, "utf8").trim(), 10);
|
|
16521
17198
|
if (isNaN(pid) || pid <= 0) return { alive: false, pid: null };
|
|
16522
17199
|
process.kill(pid, 0);
|
|
16523
17200
|
return { alive: true, pid };
|
|
@@ -16532,7 +17209,7 @@ function registerGetDaemonHealth(server2) {
|
|
|
16532
17209
|
title: "Get Daemon Health",
|
|
16533
17210
|
description: "Check the embedding daemon (exed) health: whether it's running, its PID, uptime, and requests served.",
|
|
16534
17211
|
inputSchema: {
|
|
16535
|
-
_placeholder:
|
|
17212
|
+
_placeholder: z56.string().optional().describe("No input required")
|
|
16536
17213
|
}
|
|
16537
17214
|
},
|
|
16538
17215
|
async () => {
|
|
@@ -16584,14 +17261,14 @@ function registerGetDaemonHealth(server2) {
|
|
|
16584
17261
|
// src/mcp/tools/get-auto-wake-status.ts
|
|
16585
17262
|
init_database();
|
|
16586
17263
|
init_session_registry();
|
|
16587
|
-
import { z as
|
|
17264
|
+
import { z as z57 } from "zod";
|
|
16588
17265
|
|
|
16589
17266
|
// src/lib/daemon-orchestration.ts
|
|
16590
17267
|
init_tmux_routing();
|
|
16591
17268
|
init_task_scope();
|
|
16592
17269
|
init_employees();
|
|
16593
17270
|
import { execSync as execSync10 } from "child_process";
|
|
16594
|
-
import { existsSync as
|
|
17271
|
+
import { existsSync as existsSync24, readFileSync as readFileSync22, writeFileSync as writeFileSync16 } from "fs";
|
|
16595
17272
|
import { homedir as homedir4 } from "os";
|
|
16596
17273
|
import { join as join2 } from "path";
|
|
16597
17274
|
var IDLE_NUDGE_DEDUP_MS = Number(process.env.EXE_NUDGE_INTERVAL_MS) || 6e4;
|
|
@@ -16612,7 +17289,7 @@ function registerGetAutoWakeStatus(server2) {
|
|
|
16612
17289
|
title: "Get Auto-Wake Status",
|
|
16613
17290
|
description: "Check auto-wake status: orphaned tasks (assigned agent has no running session), tasks blocked by auto-wake retry limit, and session activity.",
|
|
16614
17291
|
inputSchema: {
|
|
16615
|
-
_placeholder:
|
|
17292
|
+
_placeholder: z57.string().optional().describe("No input required")
|
|
16616
17293
|
}
|
|
16617
17294
|
},
|
|
16618
17295
|
async () => {
|
|
@@ -16693,16 +17370,16 @@ function registerGetAutoWakeStatus(server2) {
|
|
|
16693
17370
|
// src/mcp/tools/get-worker-gate.ts
|
|
16694
17371
|
init_worker_gate();
|
|
16695
17372
|
init_config();
|
|
16696
|
-
import { z as
|
|
16697
|
-
import { readdirSync as readdirSync10, existsSync as
|
|
16698
|
-
import
|
|
16699
|
-
var WORKER_PID_DIR2 =
|
|
17373
|
+
import { z as z58 } from "zod";
|
|
17374
|
+
import { readdirSync as readdirSync10, existsSync as existsSync26 } from "fs";
|
|
17375
|
+
import path34 from "path";
|
|
17376
|
+
var WORKER_PID_DIR2 = path34.join(EXE_AI_DIR, "worker-pids");
|
|
16700
17377
|
function countAliveWorkers() {
|
|
16701
17378
|
let alive = 0;
|
|
16702
17379
|
let stale = 0;
|
|
16703
17380
|
let reservations = 0;
|
|
16704
17381
|
try {
|
|
16705
|
-
if (!
|
|
17382
|
+
if (!existsSync26(WORKER_PID_DIR2)) return { alive: 0, stale: 0, reservations: 0 };
|
|
16706
17383
|
const files = readdirSync10(WORKER_PID_DIR2);
|
|
16707
17384
|
for (const f of files) {
|
|
16708
17385
|
if (!f.endsWith(".pid")) continue;
|
|
@@ -16731,7 +17408,7 @@ function registerGetWorkerGate(server2) {
|
|
|
16731
17408
|
title: "Get Worker Gate",
|
|
16732
17409
|
description: "Check worker concurrency gate status: how many worker slots are in use, the maximum allowed, and whether new workers can spawn.",
|
|
16733
17410
|
inputSchema: {
|
|
16734
|
-
_placeholder:
|
|
17411
|
+
_placeholder: z58.string().optional().describe("No input required")
|
|
16735
17412
|
}
|
|
16736
17413
|
},
|
|
16737
17414
|
async () => {
|
|
@@ -16767,12 +17444,12 @@ function registerGetWorkerGate(server2) {
|
|
|
16767
17444
|
|
|
16768
17445
|
// src/mcp/tools/run-memory-audit.ts
|
|
16769
17446
|
init_database();
|
|
16770
|
-
import { z as
|
|
17447
|
+
import { z as z59 } from "zod";
|
|
16771
17448
|
|
|
16772
17449
|
// src/bin/exe-doctor.ts
|
|
16773
17450
|
init_store();
|
|
16774
17451
|
init_database();
|
|
16775
|
-
import
|
|
17452
|
+
import os13 from "os";
|
|
16776
17453
|
|
|
16777
17454
|
// src/lib/is-main.ts
|
|
16778
17455
|
import { realpathSync } from "fs";
|
|
@@ -16790,10 +17467,10 @@ function isMainModule(importMetaUrl) {
|
|
|
16790
17467
|
}
|
|
16791
17468
|
|
|
16792
17469
|
// src/bin/exe-doctor.ts
|
|
16793
|
-
import { existsSync as
|
|
17470
|
+
import { existsSync as existsSync27, readFileSync as readFileSync23 } from "fs";
|
|
16794
17471
|
import { spawn as spawn2 } from "child_process";
|
|
16795
|
-
import
|
|
16796
|
-
import { randomUUID as
|
|
17472
|
+
import path35 from "path";
|
|
17473
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
16797
17474
|
|
|
16798
17475
|
// src/lib/conflict-detector.ts
|
|
16799
17476
|
var DEFAULT_MAX_PAIRS = 100;
|
|
@@ -17195,13 +17872,53 @@ async function auditOrphanedProjects(client) {
|
|
|
17195
17872
|
for (const row of result.rows) {
|
|
17196
17873
|
const name = row.project_name;
|
|
17197
17874
|
const count = Number(row.cnt);
|
|
17198
|
-
const exists =
|
|
17875
|
+
const exists = existsSync27(path35.join(home, name)) || existsSync27(path35.join(home, "..", name)) || existsSync27(path35.join(process.cwd(), "..", name));
|
|
17199
17876
|
if (!exists) {
|
|
17200
17877
|
orphans.push({ project_name: name, count });
|
|
17201
17878
|
}
|
|
17202
17879
|
}
|
|
17203
17880
|
return orphans;
|
|
17204
17881
|
}
|
|
17882
|
+
function auditHookHealth() {
|
|
17883
|
+
const logPath = path35.join(
|
|
17884
|
+
process.env.HOME ?? process.env.USERPROFILE ?? "",
|
|
17885
|
+
".exe-os",
|
|
17886
|
+
"logs",
|
|
17887
|
+
"hooks.log"
|
|
17888
|
+
);
|
|
17889
|
+
if (!existsSync27(logPath)) {
|
|
17890
|
+
return { logExists: false, totalLines: 0, errorsLastHour: 0, topPatterns: [] };
|
|
17891
|
+
}
|
|
17892
|
+
let content;
|
|
17893
|
+
try {
|
|
17894
|
+
content = readFileSync23(logPath, "utf-8");
|
|
17895
|
+
} catch {
|
|
17896
|
+
return { logExists: false, totalLines: 0, errorsLastHour: 0, topPatterns: [] };
|
|
17897
|
+
}
|
|
17898
|
+
const lines = content.split("\n").filter(Boolean);
|
|
17899
|
+
const totalLines = lines.length;
|
|
17900
|
+
const recent = lines.slice(-200);
|
|
17901
|
+
const oneHourAgo = new Date(Date.now() - 36e5).toISOString();
|
|
17902
|
+
let errorsLastHour = 0;
|
|
17903
|
+
const patternCounts = /* @__PURE__ */ new Map();
|
|
17904
|
+
for (const line of recent) {
|
|
17905
|
+
const isError = /error|Error|ERR|FAIL|throw|exception|TypeError|ReferenceError|SyntaxError/i.test(line);
|
|
17906
|
+
if (!isError) continue;
|
|
17907
|
+
const tsMatch = line.match(/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/);
|
|
17908
|
+
if (tsMatch && tsMatch[1] >= oneHourAgo) {
|
|
17909
|
+
errorsLastHour++;
|
|
17910
|
+
} else if (!tsMatch) {
|
|
17911
|
+
errorsLastHour++;
|
|
17912
|
+
}
|
|
17913
|
+
const patternMatch = line.match(/((?:TypeError|ReferenceError|SyntaxError|Error):[^\n]{0,80})/);
|
|
17914
|
+
if (patternMatch) {
|
|
17915
|
+
const p = patternMatch[1];
|
|
17916
|
+
patternCounts.set(p, (patternCounts.get(p) ?? 0) + 1);
|
|
17917
|
+
}
|
|
17918
|
+
}
|
|
17919
|
+
const topPatterns = [...patternCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([pattern, count]) => ({ pattern, count }));
|
|
17920
|
+
return { logExists: true, totalLines, errorsLastHour, topPatterns };
|
|
17921
|
+
}
|
|
17205
17922
|
async function runAudit(client, flags) {
|
|
17206
17923
|
const [stats, nullVectors, duplicates, bloated, fts, orphanedProjects, conflicts] = await Promise.all([
|
|
17207
17924
|
auditStats(client, flags),
|
|
@@ -17213,7 +17930,8 @@ async function runAudit(client, flags) {
|
|
|
17213
17930
|
detectConflicts(client, flags.project, flags.agent)
|
|
17214
17931
|
]);
|
|
17215
17932
|
const duplicateCount = duplicates.reduce((sum, d) => sum + d.delete_ids.length, 0);
|
|
17216
|
-
|
|
17933
|
+
const hookHealth = auditHookHealth();
|
|
17934
|
+
return { stats, nullVectors, duplicates, duplicateCount, bloated, fts, orphanedProjects, conflicts, hookHealth };
|
|
17217
17935
|
}
|
|
17218
17936
|
function indicator(value, warn) {
|
|
17219
17937
|
if (value === 0) return "\u{1F7E2}";
|
|
@@ -17248,7 +17966,7 @@ function formatReport(report, flags) {
|
|
|
17248
17966
|
}
|
|
17249
17967
|
lines.push("");
|
|
17250
17968
|
}
|
|
17251
|
-
const totalMemGB =
|
|
17969
|
+
const totalMemGB = os13.totalmem() / (1024 * 1024 * 1024);
|
|
17252
17970
|
const isLowMemSystem = totalMemGB <= 8;
|
|
17253
17971
|
if (isLowMemSystem && report.nullVectors > 0) {
|
|
17254
17972
|
lines.push(`\u{1F7E2} Null vectors: ${fmtNum(report.nullVectors)} / ${fmtNum(s.total)} (expected \u2014 8GB system, keyword search mode)`);
|
|
@@ -17281,6 +17999,17 @@ function formatReport(report, flags) {
|
|
|
17281
17999
|
} else {
|
|
17282
18000
|
lines.push("\u{1F7E2} Conflicts: none detected");
|
|
17283
18001
|
}
|
|
18002
|
+
const hh = report.hookHealth;
|
|
18003
|
+
if (!hh.logExists) {
|
|
18004
|
+
lines.push("\u{1F7E0} Hook logs: no log file (run installer to enable stderr capture)");
|
|
18005
|
+
} else if (hh.errorsLastHour === 0) {
|
|
18006
|
+
lines.push(`\u{1F7E2} Hook logs: ${fmtNum(hh.totalLines)} lines, 0 errors in last hour`);
|
|
18007
|
+
} else {
|
|
18008
|
+
lines.push(`\u{1F534} Hook logs: ${fmtNum(hh.errorsLastHour)} errors in last hour (${fmtNum(hh.totalLines)} total lines)`);
|
|
18009
|
+
for (const p of hh.topPatterns) {
|
|
18010
|
+
lines.push(` ${p.count}x: ${p.pattern}`);
|
|
18011
|
+
}
|
|
18012
|
+
}
|
|
17284
18013
|
lines.push("");
|
|
17285
18014
|
if (flags.verbose) {
|
|
17286
18015
|
if (report.duplicates.length > 0) {
|
|
@@ -17359,7 +18088,7 @@ async function fixNullVectors() {
|
|
|
17359
18088
|
}
|
|
17360
18089
|
}
|
|
17361
18090
|
const npmRoot = (await import("child_process")).execSync("npm root -g", { encoding: "utf8" }).trim();
|
|
17362
|
-
const backfillPath =
|
|
18091
|
+
const backfillPath = path35.join(npmRoot, "exe-os", "dist", "bin", "backfill-vectors.js");
|
|
17363
18092
|
return new Promise((resolve, reject) => {
|
|
17364
18093
|
const child = spawn2("node", [backfillPath], { stdio: "inherit" });
|
|
17365
18094
|
if (child.pid) registerWorkerPid2(child.pid);
|
|
@@ -17415,7 +18144,7 @@ async function fixBloated(client, bloated, dryRun) {
|
|
|
17415
18144
|
tool_name, project_name, has_error, raw_text, vector, version, consolidated)
|
|
17416
18145
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, 0, 0)`,
|
|
17417
18146
|
args: [
|
|
17418
|
-
|
|
18147
|
+
randomUUID7(),
|
|
17419
18148
|
row.agent_id,
|
|
17420
18149
|
row.agent_role,
|
|
17421
18150
|
row.session_id,
|
|
@@ -17519,8 +18248,8 @@ function registerRunMemoryAudit(server2) {
|
|
|
17519
18248
|
title: "Run Memory Audit",
|
|
17520
18249
|
description: "Run a memory health audit: total counts, per-agent breakdown, null vectors, duplicates, FTS sync status, bloated records, and conflict detection (contradictory/superseded memories).",
|
|
17521
18250
|
inputSchema: {
|
|
17522
|
-
agent_id:
|
|
17523
|
-
project_name:
|
|
18251
|
+
agent_id: z59.string().optional().describe("Filter audit to a specific agent"),
|
|
18252
|
+
project_name: z59.string().optional().describe("Filter audit to a specific project")
|
|
17524
18253
|
}
|
|
17525
18254
|
},
|
|
17526
18255
|
async ({ agent_id, project_name }) => {
|
|
@@ -17553,13 +18282,13 @@ function registerRunMemoryAudit(server2) {
|
|
|
17553
18282
|
}
|
|
17554
18283
|
|
|
17555
18284
|
// src/mcp/tools/cloud-sync.ts
|
|
17556
|
-
import { z as
|
|
18285
|
+
import { z as z60 } from "zod";
|
|
17557
18286
|
|
|
17558
18287
|
// src/lib/cloud-sync.ts
|
|
17559
18288
|
init_database();
|
|
17560
|
-
import { readFileSync as
|
|
18289
|
+
import { readFileSync as readFileSync25, writeFileSync as writeFileSync19, existsSync as existsSync29, readdirSync as readdirSync11, mkdirSync as mkdirSync16, appendFileSync as appendFileSync2, unlinkSync as unlinkSync10, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
17561
18290
|
import crypto16 from "crypto";
|
|
17562
|
-
import
|
|
18291
|
+
import path37 from "path";
|
|
17563
18292
|
import { homedir as homedir6 } from "os";
|
|
17564
18293
|
|
|
17565
18294
|
// src/lib/crypto.ts
|
|
@@ -17633,7 +18362,7 @@ function sqlSafe(v) {
|
|
|
17633
18362
|
}
|
|
17634
18363
|
function logError(msg) {
|
|
17635
18364
|
try {
|
|
17636
|
-
const logPath =
|
|
18365
|
+
const logPath = path37.join(homedir6(), ".exe-os", "workers.log");
|
|
17637
18366
|
appendFileSync2(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
|
|
17638
18367
|
`);
|
|
17639
18368
|
} catch {
|
|
@@ -17642,24 +18371,24 @@ function logError(msg) {
|
|
|
17642
18371
|
var LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
17643
18372
|
var FETCH_TIMEOUT_MS4 = 3e4;
|
|
17644
18373
|
var PUSH_BATCH_SIZE = 5e3;
|
|
17645
|
-
var ROSTER_LOCK_PATH =
|
|
18374
|
+
var ROSTER_LOCK_PATH = path37.join(EXE_AI_DIR, "roster-merge.lock");
|
|
17646
18375
|
var LOCK_STALE_MS = 3e4;
|
|
17647
18376
|
async function withRosterLock(fn) {
|
|
17648
18377
|
try {
|
|
17649
18378
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
17650
18379
|
closeSync2(fd);
|
|
17651
|
-
|
|
18380
|
+
writeFileSync19(ROSTER_LOCK_PATH, String(Date.now()));
|
|
17652
18381
|
} catch (err) {
|
|
17653
18382
|
if (err.code === "EEXIST") {
|
|
17654
18383
|
try {
|
|
17655
|
-
const ts2 = parseInt(
|
|
18384
|
+
const ts2 = parseInt(readFileSync25(ROSTER_LOCK_PATH, "utf-8"), 10);
|
|
17656
18385
|
if (Date.now() - ts2 < LOCK_STALE_MS) {
|
|
17657
18386
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
17658
18387
|
}
|
|
17659
18388
|
unlinkSync10(ROSTER_LOCK_PATH);
|
|
17660
18389
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
17661
18390
|
closeSync2(fd);
|
|
17662
|
-
|
|
18391
|
+
writeFileSync19(ROSTER_LOCK_PATH, String(Date.now()));
|
|
17663
18392
|
} catch (retryErr) {
|
|
17664
18393
|
if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
|
|
17665
18394
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
@@ -17678,21 +18407,21 @@ async function withRosterLock(fn) {
|
|
|
17678
18407
|
}
|
|
17679
18408
|
}
|
|
17680
18409
|
async function fetchWithRetry(url, init) {
|
|
17681
|
-
const
|
|
18410
|
+
const MAX_RETRIES4 = 3;
|
|
17682
18411
|
const BASE_DELAY_MS2 = 200;
|
|
17683
18412
|
let lastError;
|
|
17684
|
-
for (let attempt = 0; attempt <=
|
|
18413
|
+
for (let attempt = 0; attempt <= MAX_RETRIES4; attempt++) {
|
|
17685
18414
|
try {
|
|
17686
18415
|
const signal = AbortSignal.timeout(FETCH_TIMEOUT_MS4);
|
|
17687
18416
|
const resp = await fetch(url, { ...init, signal });
|
|
17688
|
-
if (resp && resp.status >= 500 && attempt <
|
|
18417
|
+
if (resp && resp.status >= 500 && attempt < MAX_RETRIES4) {
|
|
17689
18418
|
await new Promise((r) => setTimeout(r, BASE_DELAY_MS2 * Math.pow(2, attempt)));
|
|
17690
18419
|
continue;
|
|
17691
18420
|
}
|
|
17692
18421
|
return resp;
|
|
17693
18422
|
} catch (err) {
|
|
17694
18423
|
lastError = err;
|
|
17695
|
-
if (attempt ===
|
|
18424
|
+
if (attempt === MAX_RETRIES4) throw err;
|
|
17696
18425
|
await new Promise((r) => setTimeout(r, BASE_DELAY_MS2 * Math.pow(2, attempt)));
|
|
17697
18426
|
}
|
|
17698
18427
|
}
|
|
@@ -18033,8 +18762,8 @@ async function cloudSync(config2) {
|
|
|
18033
18762
|
try {
|
|
18034
18763
|
const employees = await loadEmployees();
|
|
18035
18764
|
rosterResult.employees = employees.length;
|
|
18036
|
-
const idDir =
|
|
18037
|
-
if (
|
|
18765
|
+
const idDir = path37.join(EXE_AI_DIR, "identity");
|
|
18766
|
+
if (existsSync29(idDir)) {
|
|
18038
18767
|
rosterResult.identities = readdirSync11(idDir).filter((f) => f.endsWith(".md")).length;
|
|
18039
18768
|
}
|
|
18040
18769
|
} catch {
|
|
@@ -18052,49 +18781,49 @@ async function cloudSync(config2) {
|
|
|
18052
18781
|
roster: rosterResult
|
|
18053
18782
|
};
|
|
18054
18783
|
}
|
|
18055
|
-
var ROSTER_DELETIONS_PATH =
|
|
18784
|
+
var ROSTER_DELETIONS_PATH = path37.join(EXE_AI_DIR, "roster-deletions.json");
|
|
18056
18785
|
function consumeRosterDeletions() {
|
|
18057
18786
|
try {
|
|
18058
|
-
if (!
|
|
18059
|
-
const deletions = JSON.parse(
|
|
18060
|
-
|
|
18787
|
+
if (!existsSync29(ROSTER_DELETIONS_PATH)) return [];
|
|
18788
|
+
const deletions = JSON.parse(readFileSync25(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
18789
|
+
writeFileSync19(ROSTER_DELETIONS_PATH, "[]");
|
|
18061
18790
|
return deletions;
|
|
18062
18791
|
} catch {
|
|
18063
18792
|
return [];
|
|
18064
18793
|
}
|
|
18065
18794
|
}
|
|
18066
18795
|
function buildRosterBlob(paths) {
|
|
18067
|
-
const rosterPath = paths?.rosterPath ??
|
|
18068
|
-
const identityDir = paths?.identityDir ??
|
|
18069
|
-
const configPath = paths?.configPath ??
|
|
18796
|
+
const rosterPath = paths?.rosterPath ?? path37.join(EXE_AI_DIR, "exe-employees.json");
|
|
18797
|
+
const identityDir = paths?.identityDir ?? path37.join(EXE_AI_DIR, "identity");
|
|
18798
|
+
const configPath = paths?.configPath ?? path37.join(EXE_AI_DIR, "config.json");
|
|
18070
18799
|
let roster = [];
|
|
18071
|
-
if (
|
|
18800
|
+
if (existsSync29(rosterPath)) {
|
|
18072
18801
|
try {
|
|
18073
|
-
roster = JSON.parse(
|
|
18802
|
+
roster = JSON.parse(readFileSync25(rosterPath, "utf-8"));
|
|
18074
18803
|
} catch {
|
|
18075
18804
|
}
|
|
18076
18805
|
}
|
|
18077
18806
|
const identities = {};
|
|
18078
|
-
if (
|
|
18807
|
+
if (existsSync29(identityDir)) {
|
|
18079
18808
|
for (const file of readdirSync11(identityDir).filter((f) => f.endsWith(".md"))) {
|
|
18080
18809
|
try {
|
|
18081
|
-
identities[file] =
|
|
18810
|
+
identities[file] = readFileSync25(path37.join(identityDir, file), "utf-8");
|
|
18082
18811
|
} catch {
|
|
18083
18812
|
}
|
|
18084
18813
|
}
|
|
18085
18814
|
}
|
|
18086
18815
|
let config2;
|
|
18087
|
-
if (
|
|
18816
|
+
if (existsSync29(configPath)) {
|
|
18088
18817
|
try {
|
|
18089
|
-
config2 = JSON.parse(
|
|
18818
|
+
config2 = JSON.parse(readFileSync25(configPath, "utf-8"));
|
|
18090
18819
|
} catch {
|
|
18091
18820
|
}
|
|
18092
18821
|
}
|
|
18093
18822
|
let agentConfig;
|
|
18094
|
-
const agentConfigPath =
|
|
18095
|
-
if (
|
|
18823
|
+
const agentConfigPath = path37.join(EXE_AI_DIR, "agent-config.json");
|
|
18824
|
+
if (existsSync29(agentConfigPath)) {
|
|
18096
18825
|
try {
|
|
18097
|
-
agentConfig = JSON.parse(
|
|
18826
|
+
agentConfig = JSON.parse(readFileSync25(agentConfigPath, "utf-8"));
|
|
18098
18827
|
} catch {
|
|
18099
18828
|
}
|
|
18100
18829
|
}
|
|
@@ -18170,23 +18899,23 @@ async function cloudPullRoster(config2) {
|
|
|
18170
18899
|
}
|
|
18171
18900
|
}
|
|
18172
18901
|
function mergeConfig(remoteConfig, configPath) {
|
|
18173
|
-
const cfgPath = configPath ??
|
|
18902
|
+
const cfgPath = configPath ?? path37.join(EXE_AI_DIR, "config.json");
|
|
18174
18903
|
let local = {};
|
|
18175
|
-
if (
|
|
18904
|
+
if (existsSync29(cfgPath)) {
|
|
18176
18905
|
try {
|
|
18177
|
-
local = JSON.parse(
|
|
18906
|
+
local = JSON.parse(readFileSync25(cfgPath, "utf-8"));
|
|
18178
18907
|
} catch {
|
|
18179
18908
|
}
|
|
18180
18909
|
}
|
|
18181
18910
|
const merged = { ...remoteConfig, ...local };
|
|
18182
|
-
const dir =
|
|
18183
|
-
if (!
|
|
18184
|
-
|
|
18911
|
+
const dir = path37.dirname(cfgPath);
|
|
18912
|
+
if (!existsSync29(dir)) mkdirSync16(dir, { recursive: true });
|
|
18913
|
+
writeFileSync19(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
18185
18914
|
}
|
|
18186
18915
|
async function mergeRosterFromRemote(remote, paths) {
|
|
18187
18916
|
return withRosterLock(async () => {
|
|
18188
18917
|
const rosterPath = paths?.rosterPath ?? void 0;
|
|
18189
|
-
const identityDir = paths?.identityDir ??
|
|
18918
|
+
const identityDir = paths?.identityDir ?? path37.join(EXE_AI_DIR, "identity");
|
|
18190
18919
|
const localEmployees = await loadEmployees(rosterPath);
|
|
18191
18920
|
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
18192
18921
|
let added = 0;
|
|
@@ -18207,15 +18936,15 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
18207
18936
|
) ?? lookupKey;
|
|
18208
18937
|
const remoteIdentity = remote.identities[matchedKey];
|
|
18209
18938
|
if (remoteIdentity) {
|
|
18210
|
-
if (!
|
|
18211
|
-
const idPath =
|
|
18939
|
+
if (!existsSync29(identityDir)) mkdirSync16(identityDir, { recursive: true });
|
|
18940
|
+
const idPath = path37.join(identityDir, `${remoteEmp.name}.md`);
|
|
18212
18941
|
let localIdentity = null;
|
|
18213
18942
|
try {
|
|
18214
|
-
localIdentity =
|
|
18943
|
+
localIdentity = existsSync29(idPath) ? readFileSync25(idPath, "utf-8") : null;
|
|
18215
18944
|
} catch {
|
|
18216
18945
|
}
|
|
18217
18946
|
if (localIdentity !== remoteIdentity) {
|
|
18218
|
-
|
|
18947
|
+
writeFileSync19(idPath, remoteIdentity, "utf-8");
|
|
18219
18948
|
identitiesUpdated++;
|
|
18220
18949
|
}
|
|
18221
18950
|
}
|
|
@@ -18241,16 +18970,16 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
18241
18970
|
}
|
|
18242
18971
|
if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
|
|
18243
18972
|
try {
|
|
18244
|
-
const agentConfigPath =
|
|
18973
|
+
const agentConfigPath = path37.join(EXE_AI_DIR, "agent-config.json");
|
|
18245
18974
|
let local = {};
|
|
18246
|
-
if (
|
|
18975
|
+
if (existsSync29(agentConfigPath)) {
|
|
18247
18976
|
try {
|
|
18248
|
-
local = JSON.parse(
|
|
18977
|
+
local = JSON.parse(readFileSync25(agentConfigPath, "utf-8"));
|
|
18249
18978
|
} catch {
|
|
18250
18979
|
}
|
|
18251
18980
|
}
|
|
18252
18981
|
const merged = { ...remote.agentConfig, ...local };
|
|
18253
|
-
|
|
18982
|
+
writeFileSync19(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
18254
18983
|
} catch {
|
|
18255
18984
|
}
|
|
18256
18985
|
}
|
|
@@ -18684,7 +19413,7 @@ function registerCloudSync(server2) {
|
|
|
18684
19413
|
title: "Cloud Sync",
|
|
18685
19414
|
description: "Trigger a cloud sync cycle \u2014 pulls remote changes then pushes local. Reports pushed/pulled counts for memories, behaviors, graph, tasks, and more.",
|
|
18686
19415
|
inputSchema: {
|
|
18687
|
-
force:
|
|
19416
|
+
force: z60.boolean().default(false).describe("Force sync even if recently synced")
|
|
18688
19417
|
}
|
|
18689
19418
|
},
|
|
18690
19419
|
async () => {
|
|
@@ -18737,7 +19466,7 @@ function registerCloudSync(server2) {
|
|
|
18737
19466
|
|
|
18738
19467
|
// src/mcp/tools/get-memory-cardinality.ts
|
|
18739
19468
|
init_database();
|
|
18740
|
-
import { z as
|
|
19469
|
+
import { z as z61 } from "zod";
|
|
18741
19470
|
function registerGetMemoryCardinality(server2) {
|
|
18742
19471
|
server2.registerTool(
|
|
18743
19472
|
"get_memory_cardinality",
|
|
@@ -18745,7 +19474,7 @@ function registerGetMemoryCardinality(server2) {
|
|
|
18745
19474
|
title: "Get Memory Cardinality",
|
|
18746
19475
|
description: "Get memory counts: total active memories and per-project breakdown. Optionally filter by agent.",
|
|
18747
19476
|
inputSchema: {
|
|
18748
|
-
agent_id:
|
|
19477
|
+
agent_id: z61.string().optional().describe("Filter to a specific agent (e.g. 'tom', 'exe')")
|
|
18749
19478
|
}
|
|
18750
19479
|
},
|
|
18751
19480
|
async ({ agent_id }) => {
|
|
@@ -18828,7 +19557,7 @@ function registerGetMemoryCardinality(server2) {
|
|
|
18828
19557
|
init_database();
|
|
18829
19558
|
init_consolidation();
|
|
18830
19559
|
init_config();
|
|
18831
|
-
import { z as
|
|
19560
|
+
import { z as z62 } from "zod";
|
|
18832
19561
|
function registerRunConsolidation(server2) {
|
|
18833
19562
|
server2.registerTool(
|
|
18834
19563
|
"run_consolidation",
|
|
@@ -18836,7 +19565,7 @@ function registerRunConsolidation(server2) {
|
|
|
18836
19565
|
title: "Run Consolidation",
|
|
18837
19566
|
description: "Run memory consolidation \u2014 synthesizes unconsolidated memories into meta-insights. Use dry_run=true (default) to preview without executing.",
|
|
18838
19567
|
inputSchema: {
|
|
18839
|
-
dry_run:
|
|
19568
|
+
dry_run: z62.boolean().default(true).describe("Preview mode \u2014 show what would be consolidated without doing it")
|
|
18840
19569
|
}
|
|
18841
19570
|
},
|
|
18842
19571
|
async ({ dry_run }) => {
|
|
@@ -18905,7 +19634,7 @@ function registerRunConsolidation(server2) {
|
|
|
18905
19634
|
|
|
18906
19635
|
// src/mcp/tools/get-license-status.ts
|
|
18907
19636
|
init_license();
|
|
18908
|
-
import { z as
|
|
19637
|
+
import { z as z63 } from "zod";
|
|
18909
19638
|
var FEATURES = [
|
|
18910
19639
|
"cloud_sync",
|
|
18911
19640
|
"external_agents",
|
|
@@ -18919,7 +19648,7 @@ function registerGetLicenseStatus(server2) {
|
|
|
18919
19648
|
title: "Get License Status",
|
|
18920
19649
|
description: "Get current license status: plan, validity, feature gates, limits, and expiry.",
|
|
18921
19650
|
inputSchema: {
|
|
18922
|
-
_dummy:
|
|
19651
|
+
_dummy: z63.string().optional().describe("Unused \u2014 no input required")
|
|
18923
19652
|
}
|
|
18924
19653
|
},
|
|
18925
19654
|
async () => {
|
|
@@ -18971,16 +19700,16 @@ function registerGetLicenseStatus(server2) {
|
|
|
18971
19700
|
}
|
|
18972
19701
|
|
|
18973
19702
|
// src/mcp/tools/people-roster.ts
|
|
18974
|
-
import { z as
|
|
19703
|
+
import { z as z64 } from "zod";
|
|
18975
19704
|
|
|
18976
19705
|
// src/lib/people.ts
|
|
18977
19706
|
init_config();
|
|
18978
19707
|
import { readFile as readFile5, writeFile as writeFile6, mkdir as mkdir5 } from "fs/promises";
|
|
18979
|
-
import { existsSync as
|
|
18980
|
-
import
|
|
18981
|
-
var PEOPLE_PATH =
|
|
19708
|
+
import { existsSync as existsSync30, readFileSync as readFileSync26 } from "fs";
|
|
19709
|
+
import path38 from "path";
|
|
19710
|
+
var PEOPLE_PATH = path38.join(EXE_AI_DIR, "people.json");
|
|
18982
19711
|
async function loadPeople() {
|
|
18983
|
-
if (!
|
|
19712
|
+
if (!existsSync30(PEOPLE_PATH)) return [];
|
|
18984
19713
|
try {
|
|
18985
19714
|
const raw = await readFile5(PEOPLE_PATH, "utf-8");
|
|
18986
19715
|
return JSON.parse(raw);
|
|
@@ -18989,7 +19718,7 @@ async function loadPeople() {
|
|
|
18989
19718
|
}
|
|
18990
19719
|
}
|
|
18991
19720
|
async function savePeople(people) {
|
|
18992
|
-
await mkdir5(
|
|
19721
|
+
await mkdir5(path38.dirname(PEOPLE_PATH), { recursive: true });
|
|
18993
19722
|
await writeFile6(PEOPLE_PATH, JSON.stringify(people, null, 2) + "\n", "utf-8");
|
|
18994
19723
|
}
|
|
18995
19724
|
async function addPerson(person) {
|
|
@@ -19019,10 +19748,10 @@ function registerAddPerson(server2) {
|
|
|
19019
19748
|
title: "Add Person",
|
|
19020
19749
|
description: "Add or update a key human in the people roster. Used for co-founders, partners, customers \u2014 anyone agents need to know about.",
|
|
19021
19750
|
inputSchema: {
|
|
19022
|
-
name:
|
|
19023
|
-
role:
|
|
19024
|
-
relationship:
|
|
19025
|
-
notes:
|
|
19751
|
+
name: z64.string().describe("Person's name"),
|
|
19752
|
+
role: z64.string().describe("Their role (e.g. co-founder, customer, partner)"),
|
|
19753
|
+
relationship: z64.string().describe("Relationship to the organization (e.g. co-founder, early adopter, investor)"),
|
|
19754
|
+
notes: z64.string().optional().describe("Additional context about this person")
|
|
19026
19755
|
}
|
|
19027
19756
|
},
|
|
19028
19757
|
async ({ name, role, relationship, notes }) => {
|
|
@@ -19068,7 +19797,7 @@ function registerGetPerson(server2) {
|
|
|
19068
19797
|
title: "Get Person",
|
|
19069
19798
|
description: "Look up a specific person by name from the people roster.",
|
|
19070
19799
|
inputSchema: {
|
|
19071
|
-
name:
|
|
19800
|
+
name: z64.string().describe("Person's name to look up")
|
|
19072
19801
|
}
|
|
19073
19802
|
},
|
|
19074
19803
|
async ({ name }) => {
|
|
@@ -19096,7 +19825,7 @@ init_active_agent();
|
|
|
19096
19825
|
init_agent_config();
|
|
19097
19826
|
init_runtime_table();
|
|
19098
19827
|
init_employees();
|
|
19099
|
-
import { z as
|
|
19828
|
+
import { z as z65 } from "zod";
|
|
19100
19829
|
function registerSetAgentConfig(server2) {
|
|
19101
19830
|
server2.registerTool(
|
|
19102
19831
|
"set_agent_config",
|
|
@@ -19104,9 +19833,9 @@ function registerSetAgentConfig(server2) {
|
|
|
19104
19833
|
title: "Set Agent Config",
|
|
19105
19834
|
description: "Set or view per-agent runtime + model configuration. Controls which runtime (claude, codex, opencode) and model each agent uses when dispatched. COO-only. Omit runtime/model to view current config for an agent or all agents.",
|
|
19106
19835
|
inputSchema: {
|
|
19107
|
-
agent_id:
|
|
19108
|
-
runtime:
|
|
19109
|
-
model:
|
|
19836
|
+
agent_id: z65.string().optional().describe("Agent name, or 'default' for org-wide default. Omit to view all agents."),
|
|
19837
|
+
runtime: z65.string().optional().describe(`Runtime: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`),
|
|
19838
|
+
model: z65.string().optional().describe("Model name (e.g. claude-opus-4, gpt-5.4, anthropic/claude-sonnet-4-6)")
|
|
19110
19839
|
}
|
|
19111
19840
|
},
|
|
19112
19841
|
async ({ agent_id, runtime, model }) => {
|
|
@@ -19299,6 +20028,8 @@ registerListWikiPages(server);
|
|
|
19299
20028
|
registerGetWikiPage(server);
|
|
19300
20029
|
registerUpdateWikiPage(server);
|
|
19301
20030
|
registerDeployClient(server);
|
|
20031
|
+
registerExportOrchestration(server);
|
|
20032
|
+
registerImportOrchestration(server);
|
|
19302
20033
|
registerQueryConversations(server);
|
|
19303
20034
|
registerLoadSkill(server);
|
|
19304
20035
|
registerConsolidateMemories(server);
|
|
@@ -19390,14 +20121,14 @@ try {
|
|
|
19390
20121
|
`
|
|
19391
20122
|
);
|
|
19392
20123
|
const thisFile = fileURLToPath5(import.meta.url);
|
|
19393
|
-
const backfillPath =
|
|
19394
|
-
|
|
20124
|
+
const backfillPath = path39.resolve(
|
|
20125
|
+
path39.dirname(thisFile),
|
|
19395
20126
|
"../bin/backfill-vectors.js"
|
|
19396
20127
|
);
|
|
19397
|
-
if (
|
|
20128
|
+
if (existsSync31(backfillPath)) {
|
|
19398
20129
|
const { EXE_AI_DIR: exeDir } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
19399
|
-
const logPath =
|
|
19400
|
-
|
|
20130
|
+
const logPath = path39.join(exeDir, "workers.log");
|
|
20131
|
+
mkdirSync17(path39.dirname(logPath), { recursive: true });
|
|
19401
20132
|
let logFd = "ignore";
|
|
19402
20133
|
try {
|
|
19403
20134
|
logFd = openSync3(logPath, "a");
|