@askexenow/exe-os 0.9.65 → 0.9.66
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/deploy/stack-manifests/v0.9.json +4 -4
- package/dist/bin/backfill-conversations.js +22 -0
- package/dist/bin/backfill-responses.js +22 -0
- package/dist/bin/backfill-vectors.js +22 -0
- package/dist/bin/cleanup-stale-review-tasks.js +22 -0
- package/dist/bin/cli.js +2263 -1203
- package/dist/bin/exe-agent-config.js +4 -0
- package/dist/bin/exe-agent.js +16 -0
- package/dist/bin/exe-assign.js +22 -0
- package/dist/bin/exe-boot.js +93 -5
- package/dist/bin/exe-call.js +16 -0
- package/dist/bin/exe-cloud.js +6671 -464
- package/dist/bin/exe-dispatch.js +24 -0
- package/dist/bin/exe-doctor.js +2845 -1223
- package/dist/bin/exe-export-behaviors.js +24 -0
- package/dist/bin/exe-forget.js +22 -0
- package/dist/bin/exe-gateway.js +24 -0
- package/dist/bin/exe-heartbeat.js +23 -0
- package/dist/bin/exe-kill.js +22 -0
- package/dist/bin/exe-launch-agent.js +24 -0
- package/dist/bin/exe-link.js +287 -176
- package/dist/bin/exe-new-employee.js +127 -1
- package/dist/bin/exe-pending-messages.js +22 -0
- package/dist/bin/exe-pending-notifications.js +22 -0
- package/dist/bin/exe-pending-reviews.js +22 -0
- package/dist/bin/exe-rename.js +22 -0
- package/dist/bin/exe-review.js +22 -0
- package/dist/bin/exe-search.js +24 -0
- package/dist/bin/exe-session-cleanup.js +24 -0
- package/dist/bin/exe-settings.js +10 -0
- package/dist/bin/exe-start-codex.js +135 -1
- package/dist/bin/exe-start-opencode.js +149 -1
- package/dist/bin/exe-status.js +22 -0
- package/dist/bin/exe-team.js +22 -0
- package/dist/bin/git-sweep.js +24 -0
- package/dist/bin/graph-backfill.js +22 -0
- package/dist/bin/graph-export.js +22 -0
- package/dist/bin/install.js +115 -1
- package/dist/bin/intercom-check.js +24 -0
- package/dist/bin/scan-tasks.js +24 -0
- package/dist/bin/setup.js +389 -155
- package/dist/bin/shard-migrate.js +22 -0
- package/dist/bin/update.js +4 -0
- package/dist/gateway/index.js +24 -0
- package/dist/hooks/bug-report-worker.js +135 -42
- package/dist/hooks/codex-stop-task-finalizer.js +24 -0
- package/dist/hooks/commit-complete.js +24 -0
- package/dist/hooks/error-recall.js +24 -0
- package/dist/hooks/exe-heartbeat-hook.js +4 -0
- package/dist/hooks/ingest-worker.js +4 -0
- package/dist/hooks/ingest.js +23 -0
- package/dist/hooks/instructions-loaded.js +22 -0
- package/dist/hooks/notification.js +22 -0
- package/dist/hooks/post-compact.js +22 -0
- package/dist/hooks/post-tool-combined.js +24 -0
- package/dist/hooks/pre-compact.js +260 -109
- package/dist/hooks/pre-tool-use.js +22 -0
- package/dist/hooks/prompt-submit.js +24 -0
- package/dist/hooks/session-end.js +161 -122
- package/dist/hooks/session-start.js +142 -0
- package/dist/hooks/stop.js +23 -0
- package/dist/hooks/subagent-stop.js +22 -0
- package/dist/hooks/summary-worker.js +172 -77
- package/dist/index.js +24 -0
- package/dist/lib/agent-config.js +4 -0
- package/dist/lib/cloud-sync.js +27 -4
- package/dist/lib/config.js +12 -0
- package/dist/lib/consolidation.js +4 -0
- package/dist/lib/database.js +4 -0
- package/dist/lib/db-daemon-client.js +4 -0
- package/dist/lib/db.js +4 -0
- package/dist/lib/device-registry.js +4 -0
- package/dist/lib/embedder.js +12 -0
- package/dist/lib/employee-templates.js +16 -0
- package/dist/lib/employees.js +4 -0
- package/dist/lib/exe-daemon-client.js +4 -0
- package/dist/lib/exe-daemon.js +1058 -453
- package/dist/lib/hybrid-search.js +24 -0
- package/dist/lib/identity.js +4 -0
- package/dist/lib/license.js +4 -0
- package/dist/lib/messaging.js +4 -0
- package/dist/lib/reminders.js +4 -0
- package/dist/lib/schedules.js +22 -0
- package/dist/lib/skill-learning.js +12 -0
- package/dist/lib/status-brief.js +39 -0
- package/dist/lib/store.js +22 -0
- package/dist/lib/task-router.js +4 -0
- package/dist/lib/tasks.js +12 -0
- package/dist/lib/tmux-routing.js +12 -0
- package/dist/lib/token-spend.js +4 -0
- package/dist/mcp/server.js +1022 -425
- package/dist/mcp/tools/complete-reminder.js +4 -0
- package/dist/mcp/tools/create-reminder.js +4 -0
- package/dist/mcp/tools/create-task.js +12 -0
- package/dist/mcp/tools/deactivate-behavior.js +4 -0
- package/dist/mcp/tools/list-reminders.js +4 -0
- package/dist/mcp/tools/list-tasks.js +4 -0
- package/dist/mcp/tools/send-message.js +4 -0
- package/dist/mcp/tools/update-task.js +12 -0
- package/dist/runtime/index.js +24 -0
- package/dist/tui/App.js +24 -0
- package/package.json +3 -2
- package/src/commands/exe/cloud.md +15 -8
- package/src/commands/exe/link.md +7 -6
- package/stack.release.json +2 -2
package/dist/mcp/server.js
CHANGED
|
@@ -158,6 +158,11 @@ function normalizeAutoUpdate(raw) {
|
|
|
158
158
|
const userAU = raw.autoUpdate ?? {};
|
|
159
159
|
raw.autoUpdate = { ...defaultAU, ...userAU };
|
|
160
160
|
}
|
|
161
|
+
function normalizeOrchestration(raw) {
|
|
162
|
+
const defaultOrg = DEFAULT_CONFIG.orchestration;
|
|
163
|
+
const userOrg = raw.orchestration ?? {};
|
|
164
|
+
raw.orchestration = { ...defaultOrg, ...userOrg };
|
|
165
|
+
}
|
|
161
166
|
async function loadConfig() {
|
|
162
167
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
163
168
|
await ensurePrivateDir(dir);
|
|
@@ -182,6 +187,7 @@ async function loadConfig() {
|
|
|
182
187
|
normalizeScalingRoadmap(migratedCfg);
|
|
183
188
|
normalizeSessionLifecycle(migratedCfg);
|
|
184
189
|
normalizeAutoUpdate(migratedCfg);
|
|
190
|
+
normalizeOrchestration(migratedCfg);
|
|
185
191
|
const config2 = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
186
192
|
if (config2.dbPath.startsWith("~")) {
|
|
187
193
|
config2.dbPath = config2.dbPath.replace(/^~/, os.homedir());
|
|
@@ -205,6 +211,7 @@ function loadConfigSync() {
|
|
|
205
211
|
normalizeScalingRoadmap(migratedCfg);
|
|
206
212
|
normalizeSessionLifecycle(migratedCfg);
|
|
207
213
|
normalizeAutoUpdate(migratedCfg);
|
|
214
|
+
normalizeOrchestration(migratedCfg);
|
|
208
215
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
209
216
|
} catch {
|
|
210
217
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
@@ -226,6 +233,7 @@ async function loadConfigFrom(configPath) {
|
|
|
226
233
|
normalizeScalingRoadmap(migratedCfg);
|
|
227
234
|
normalizeSessionLifecycle(migratedCfg);
|
|
228
235
|
normalizeAutoUpdate(migratedCfg);
|
|
236
|
+
normalizeOrchestration(migratedCfg);
|
|
229
237
|
return { ...DEFAULT_CONFIG, ...migratedCfg };
|
|
230
238
|
} catch {
|
|
231
239
|
return { ...DEFAULT_CONFIG };
|
|
@@ -297,6 +305,10 @@ var init_config = __esm({
|
|
|
297
305
|
checkOnBoot: true,
|
|
298
306
|
autoInstall: false,
|
|
299
307
|
checkIntervalMs: 24 * 60 * 60 * 1e3
|
|
308
|
+
},
|
|
309
|
+
orchestration: {
|
|
310
|
+
phase: "phase_1_coo",
|
|
311
|
+
phaseSetBy: "default"
|
|
300
312
|
}
|
|
301
313
|
};
|
|
302
314
|
CONFIG_MIGRATIONS = [
|
|
@@ -849,10 +861,10 @@ async function disposeEmbedder() {
|
|
|
849
861
|
async function embedDirect(text3) {
|
|
850
862
|
const llamaCpp = await import("node-llama-cpp");
|
|
851
863
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
852
|
-
const { existsSync:
|
|
853
|
-
const
|
|
854
|
-
const modelPath =
|
|
855
|
-
if (!
|
|
864
|
+
const { existsSync: existsSync38 } = await import("fs");
|
|
865
|
+
const path49 = await import("path");
|
|
866
|
+
const modelPath = path49.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
867
|
+
if (!existsSync38(modelPath)) {
|
|
856
868
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
857
869
|
}
|
|
858
870
|
const llama = await llamaCpp.getLlama();
|
|
@@ -1893,6 +1905,15 @@ var init_database_adapter = __esm({
|
|
|
1893
1905
|
});
|
|
1894
1906
|
|
|
1895
1907
|
// src/lib/daemon-protocol.ts
|
|
1908
|
+
var daemon_protocol_exports = {};
|
|
1909
|
+
__export(daemon_protocol_exports, {
|
|
1910
|
+
deserializeArgs: () => deserializeArgs,
|
|
1911
|
+
deserializeResultSet: () => deserializeResultSet,
|
|
1912
|
+
deserializeValue: () => deserializeValue,
|
|
1913
|
+
serializeArgs: () => serializeArgs,
|
|
1914
|
+
serializeResultSet: () => serializeResultSet,
|
|
1915
|
+
serializeValue: () => serializeValue
|
|
1916
|
+
});
|
|
1896
1917
|
function serializeValue(v) {
|
|
1897
1918
|
if (v === null || v === void 0) return null;
|
|
1898
1919
|
if (typeof v === "bigint") return Number(v);
|
|
@@ -1917,6 +1938,32 @@ function deserializeValue(v) {
|
|
|
1917
1938
|
}
|
|
1918
1939
|
return v;
|
|
1919
1940
|
}
|
|
1941
|
+
function serializeArgs(args) {
|
|
1942
|
+
return args.map(serializeValue);
|
|
1943
|
+
}
|
|
1944
|
+
function deserializeArgs(args) {
|
|
1945
|
+
return args.map(deserializeValue);
|
|
1946
|
+
}
|
|
1947
|
+
function serializeResultSet(rs) {
|
|
1948
|
+
const rows = [];
|
|
1949
|
+
for (const row of rs.rows) {
|
|
1950
|
+
const obj = {};
|
|
1951
|
+
for (let i = 0; i < rs.columns.length; i++) {
|
|
1952
|
+
const col = rs.columns[i];
|
|
1953
|
+
if (col !== void 0) {
|
|
1954
|
+
obj[col] = serializeValue(row[i]);
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
rows.push(obj);
|
|
1958
|
+
}
|
|
1959
|
+
return {
|
|
1960
|
+
columns: [...rs.columns],
|
|
1961
|
+
columnTypes: [...rs.columnTypes ?? []],
|
|
1962
|
+
rows,
|
|
1963
|
+
rowsAffected: typeof rs.rowsAffected === "bigint" ? Number(rs.rowsAffected) : rs.rowsAffected ?? 0,
|
|
1964
|
+
lastInsertRowid: rs.lastInsertRowid != null ? typeof rs.lastInsertRowid === "bigint" ? Number(rs.lastInsertRowid) : rs.lastInsertRowid : null
|
|
1965
|
+
};
|
|
1966
|
+
}
|
|
1920
1967
|
function deserializeResultSet(srs) {
|
|
1921
1968
|
const rows = srs.rows.map((obj) => {
|
|
1922
1969
|
const values = srs.columns.map(
|
|
@@ -3468,8 +3515,8 @@ function deriveMachineKey() {
|
|
|
3468
3515
|
}
|
|
3469
3516
|
function readMachineId() {
|
|
3470
3517
|
try {
|
|
3471
|
-
const { readFileSync:
|
|
3472
|
-
return
|
|
3518
|
+
const { readFileSync: readFileSync31 } = __require("fs");
|
|
3519
|
+
return readFileSync31("/etc/machine-id", "utf-8").trim();
|
|
3473
3520
|
} catch {
|
|
3474
3521
|
return "";
|
|
3475
3522
|
}
|
|
@@ -4369,6 +4416,12 @@ var init_platform_procedures = __esm({
|
|
|
4369
4416
|
priority: "p0",
|
|
4370
4417
|
content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
|
|
4371
4418
|
},
|
|
4419
|
+
{
|
|
4420
|
+
title: "Customer orchestration maturity \u2014 recommend, never trap",
|
|
4421
|
+
domain: "workflow",
|
|
4422
|
+
priority: "p1",
|
|
4423
|
+
content: "New customers start best in Phase 1: founder \u2194 coordinator/Chief of Staff, building company context. Suggest Phase 2 executives when domain work repeats; suggest Phase 3 parallel execution only when review/permission gates are ready. This is guidance, not a blocker: users may jump phases anytime. Never overwrite their phase, role titles, identities, or custom org design."
|
|
4424
|
+
},
|
|
4372
4425
|
{
|
|
4373
4426
|
title: "Single dispatch path \u2014 create_task only",
|
|
4374
4427
|
domain: "workflow",
|
|
@@ -4427,6 +4480,12 @@ var init_platform_procedures = __esm({
|
|
|
4427
4480
|
priority: "p0",
|
|
4428
4481
|
content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
|
|
4429
4482
|
},
|
|
4483
|
+
{
|
|
4484
|
+
title: "Commit discipline \u2014 never leave verified work floating",
|
|
4485
|
+
domain: "workflow",
|
|
4486
|
+
priority: "p1",
|
|
4487
|
+
content: "After any code-change batch passes typecheck/tests/build, run git status, summarize changed files, and commit with a clear message before ending the session. If work must remain uncommitted for review/dogfood, explicitly say so, list the files, and state the blocker. Never imply work is complete while verified changes are still floating locally."
|
|
4488
|
+
},
|
|
4430
4489
|
{
|
|
4431
4490
|
title: "Desktop and TUI are the same product",
|
|
4432
4491
|
domain: "architecture",
|
|
@@ -6643,10 +6702,10 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
6643
6702
|
};
|
|
6644
6703
|
try {
|
|
6645
6704
|
const fs = await import("fs");
|
|
6646
|
-
const
|
|
6705
|
+
const path49 = await import("path");
|
|
6647
6706
|
const os21 = await import("os");
|
|
6648
|
-
const logPath =
|
|
6649
|
-
fs.mkdirSync(
|
|
6707
|
+
const logPath = path49.join(os21.homedir(), ".exe-os", "search-quality.jsonl");
|
|
6708
|
+
fs.mkdirSync(path49.dirname(logPath), { recursive: true });
|
|
6650
6709
|
fs.appendFileSync(logPath, JSON.stringify(logEntry) + "\n");
|
|
6651
6710
|
} catch {
|
|
6652
6711
|
}
|
|
@@ -7938,8 +7997,8 @@ __export(wiki_client_exports, {
|
|
|
7938
7997
|
listDocuments: () => listDocuments,
|
|
7939
7998
|
listWorkspaces: () => listWorkspaces
|
|
7940
7999
|
});
|
|
7941
|
-
async function wikiFetch(config2,
|
|
7942
|
-
const url = `${config2.baseUrl}/api/v1${
|
|
8000
|
+
async function wikiFetch(config2, path49, method = "GET", body) {
|
|
8001
|
+
const url = `${config2.baseUrl}/api/v1${path49}`;
|
|
7943
8002
|
const headers = {
|
|
7944
8003
|
Authorization: `Bearer ${config2.apiKey}`,
|
|
7945
8004
|
"Content-Type": "application/json"
|
|
@@ -7972,7 +8031,7 @@ async function wikiFetch(config2, path48, method = "GET", body) {
|
|
|
7972
8031
|
}
|
|
7973
8032
|
}
|
|
7974
8033
|
if (!response.ok) {
|
|
7975
|
-
throw new Error(`Wiki API ${method} ${
|
|
8034
|
+
throw new Error(`Wiki API ${method} ${path49}: ${response.status} ${response.statusText}`);
|
|
7976
8035
|
}
|
|
7977
8036
|
return response.json();
|
|
7978
8037
|
} finally {
|
|
@@ -12853,6 +12912,119 @@ var init_worker_gate = __esm({
|
|
|
12853
12912
|
}
|
|
12854
12913
|
});
|
|
12855
12914
|
|
|
12915
|
+
// src/lib/key-backup-status.ts
|
|
12916
|
+
var key_backup_status_exports = {};
|
|
12917
|
+
__export(key_backup_status_exports, {
|
|
12918
|
+
getKeyBackupStatus: () => getKeyBackupStatus,
|
|
12919
|
+
keyBackupMarkerPath: () => keyBackupMarkerPath,
|
|
12920
|
+
markKeyBackupConfirmed: () => markKeyBackupConfirmed
|
|
12921
|
+
});
|
|
12922
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync12, readFileSync as readFileSync20, writeFileSync as writeFileSync15 } from "fs";
|
|
12923
|
+
import path31 from "path";
|
|
12924
|
+
function keyBackupMarkerPath() {
|
|
12925
|
+
return path31.join(EXE_AI_DIR, "key-backup-confirmed.json");
|
|
12926
|
+
}
|
|
12927
|
+
function getKeyBackupStatus() {
|
|
12928
|
+
const marker = keyBackupMarkerPath();
|
|
12929
|
+
if (!existsSync26(marker)) return { exists: false };
|
|
12930
|
+
try {
|
|
12931
|
+
const parsed = JSON.parse(readFileSync20(marker, "utf8"));
|
|
12932
|
+
return {
|
|
12933
|
+
exists: true,
|
|
12934
|
+
confirmedAt: parsed.confirmedAt,
|
|
12935
|
+
source: parsed.source
|
|
12936
|
+
};
|
|
12937
|
+
} catch {
|
|
12938
|
+
return { exists: true };
|
|
12939
|
+
}
|
|
12940
|
+
}
|
|
12941
|
+
function markKeyBackupConfirmed(source) {
|
|
12942
|
+
mkdirSync12(EXE_AI_DIR, { recursive: true, mode: 448 });
|
|
12943
|
+
writeFileSync15(
|
|
12944
|
+
keyBackupMarkerPath(),
|
|
12945
|
+
JSON.stringify({ confirmedAt: (/* @__PURE__ */ new Date()).toISOString(), source }, null, 2) + "\n",
|
|
12946
|
+
{ mode: 384 }
|
|
12947
|
+
);
|
|
12948
|
+
}
|
|
12949
|
+
var init_key_backup_status = __esm({
|
|
12950
|
+
"src/lib/key-backup-status.ts"() {
|
|
12951
|
+
"use strict";
|
|
12952
|
+
init_config();
|
|
12953
|
+
}
|
|
12954
|
+
});
|
|
12955
|
+
|
|
12956
|
+
// src/bin/fast-db-init.ts
|
|
12957
|
+
var fast_db_init_exports = {};
|
|
12958
|
+
__export(fast_db_init_exports, {
|
|
12959
|
+
fastDbInit: () => fastDbInit
|
|
12960
|
+
});
|
|
12961
|
+
async function fastDbInit() {
|
|
12962
|
+
const { isInitialized: isInitialized2, getClient: getClient2, setExternalClient: setExternalClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
12963
|
+
if (isInitialized2()) {
|
|
12964
|
+
return getClient2();
|
|
12965
|
+
}
|
|
12966
|
+
try {
|
|
12967
|
+
const { connectEmbedDaemon: connectEmbedDaemon2, sendDaemonRequest: sendDaemonRequest2, isClientConnected: isClientConnected2 } = await Promise.resolve().then(() => (init_exe_daemon_client(), exe_daemon_client_exports));
|
|
12968
|
+
const { deserializeResultSet: deserializeResultSet2 } = await Promise.resolve().then(() => (init_daemon_protocol(), daemon_protocol_exports));
|
|
12969
|
+
await connectEmbedDaemon2();
|
|
12970
|
+
if (isClientConnected2()) {
|
|
12971
|
+
const daemonClient = {
|
|
12972
|
+
async execute(stmt) {
|
|
12973
|
+
const sql = typeof stmt === "string" ? stmt : stmt.sql;
|
|
12974
|
+
const args = typeof stmt === "string" ? [] : Array.isArray(stmt.args) ? stmt.args : [];
|
|
12975
|
+
const resp = await sendDaemonRequest2({ type: "db-execute", sql, args });
|
|
12976
|
+
if (resp.error) throw new Error(String(resp.error));
|
|
12977
|
+
if (resp.db) return deserializeResultSet2(resp.db);
|
|
12978
|
+
throw new Error("Unexpected daemon response");
|
|
12979
|
+
},
|
|
12980
|
+
async batch(stmts, mode) {
|
|
12981
|
+
const statements = stmts.map((s) => {
|
|
12982
|
+
const sql = typeof s === "string" ? s : s.sql;
|
|
12983
|
+
const args = typeof s === "string" ? [] : Array.isArray(s.args) ? s.args : [];
|
|
12984
|
+
return { sql, args };
|
|
12985
|
+
});
|
|
12986
|
+
const resp = await sendDaemonRequest2({ type: "db-batch", statements, mode: mode ?? "deferred" });
|
|
12987
|
+
if (resp.error) throw new Error(String(resp.error));
|
|
12988
|
+
const batchResults = resp["db-batch"];
|
|
12989
|
+
if (batchResults) return batchResults.map(deserializeResultSet2);
|
|
12990
|
+
throw new Error("Unexpected daemon batch response");
|
|
12991
|
+
},
|
|
12992
|
+
async transaction(_mode) {
|
|
12993
|
+
throw new Error("Transactions not supported via daemon socket");
|
|
12994
|
+
},
|
|
12995
|
+
async executeMultiple(_sql) {
|
|
12996
|
+
throw new Error("executeMultiple not supported via daemon socket");
|
|
12997
|
+
},
|
|
12998
|
+
async migrate(_stmts) {
|
|
12999
|
+
throw new Error("migrate not supported via daemon socket");
|
|
13000
|
+
},
|
|
13001
|
+
sync() {
|
|
13002
|
+
return Promise.resolve(void 0);
|
|
13003
|
+
},
|
|
13004
|
+
close() {
|
|
13005
|
+
},
|
|
13006
|
+
get closed() {
|
|
13007
|
+
return false;
|
|
13008
|
+
},
|
|
13009
|
+
get protocol() {
|
|
13010
|
+
return "file";
|
|
13011
|
+
}
|
|
13012
|
+
};
|
|
13013
|
+
setExternalClient2(daemonClient);
|
|
13014
|
+
return daemonClient;
|
|
13015
|
+
}
|
|
13016
|
+
} catch {
|
|
13017
|
+
}
|
|
13018
|
+
const { initStore: initStore2 } = await Promise.resolve().then(() => (init_store(), store_exports));
|
|
13019
|
+
await initStore2({ lightweight: true });
|
|
13020
|
+
return getClient2();
|
|
13021
|
+
}
|
|
13022
|
+
var init_fast_db_init = __esm({
|
|
13023
|
+
"src/bin/fast-db-init.ts"() {
|
|
13024
|
+
"use strict";
|
|
13025
|
+
}
|
|
13026
|
+
});
|
|
13027
|
+
|
|
12856
13028
|
// src/lib/db-backup.ts
|
|
12857
13029
|
var db_backup_exports = {};
|
|
12858
13030
|
__export(db_backup_exports, {
|
|
@@ -12864,33 +13036,33 @@ __export(db_backup_exports, {
|
|
|
12864
13036
|
listBackups: () => listBackups,
|
|
12865
13037
|
rotateBackups: () => rotateBackups
|
|
12866
13038
|
});
|
|
12867
|
-
import { copyFileSync, existsSync as
|
|
12868
|
-
import
|
|
13039
|
+
import { copyFileSync, existsSync as existsSync27, mkdirSync as mkdirSync13, readdirSync as readdirSync10, unlinkSync as unlinkSync9, statSync as statSync4 } from "fs";
|
|
13040
|
+
import path32 from "path";
|
|
12869
13041
|
function findActiveDb() {
|
|
12870
13042
|
for (const name of DB_NAMES) {
|
|
12871
|
-
const p =
|
|
12872
|
-
if (
|
|
13043
|
+
const p = path32.join(EXE_AI_DIR, name);
|
|
13044
|
+
if (existsSync27(p)) return p;
|
|
12873
13045
|
}
|
|
12874
13046
|
return null;
|
|
12875
13047
|
}
|
|
12876
13048
|
function createBackup(reason = "manual") {
|
|
12877
13049
|
const dbPath = findActiveDb();
|
|
12878
13050
|
if (!dbPath) return null;
|
|
12879
|
-
|
|
12880
|
-
const dbName =
|
|
13051
|
+
mkdirSync13(BACKUP_DIR, { recursive: true });
|
|
13052
|
+
const dbName = path32.basename(dbPath, ".db");
|
|
12881
13053
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
12882
13054
|
const backupName = `${dbName}-${reason}-${timestamp}.db`;
|
|
12883
|
-
const backupPath =
|
|
13055
|
+
const backupPath = path32.join(BACKUP_DIR, backupName);
|
|
12884
13056
|
copyFileSync(dbPath, backupPath);
|
|
12885
13057
|
const walPath = dbPath + "-wal";
|
|
12886
|
-
if (
|
|
13058
|
+
if (existsSync27(walPath)) {
|
|
12887
13059
|
try {
|
|
12888
13060
|
copyFileSync(walPath, backupPath + "-wal");
|
|
12889
13061
|
} catch {
|
|
12890
13062
|
}
|
|
12891
13063
|
}
|
|
12892
13064
|
const shmPath = dbPath + "-shm";
|
|
12893
|
-
if (
|
|
13065
|
+
if (existsSync27(shmPath)) {
|
|
12894
13066
|
try {
|
|
12895
13067
|
copyFileSync(shmPath, backupPath + "-shm");
|
|
12896
13068
|
} catch {
|
|
@@ -12899,14 +13071,14 @@ function createBackup(reason = "manual") {
|
|
|
12899
13071
|
return backupPath;
|
|
12900
13072
|
}
|
|
12901
13073
|
function rotateBackups(keepDays = DEFAULT_KEEP_DAYS) {
|
|
12902
|
-
if (!
|
|
13074
|
+
if (!existsSync27(BACKUP_DIR)) return 0;
|
|
12903
13075
|
const cutoff = Date.now() - keepDays * 24 * 60 * 60 * 1e3;
|
|
12904
13076
|
let deleted = 0;
|
|
12905
13077
|
try {
|
|
12906
13078
|
const files = readdirSync10(BACKUP_DIR);
|
|
12907
13079
|
for (const file of files) {
|
|
12908
13080
|
if (!file.endsWith(".db") && !file.endsWith(".db-wal") && !file.endsWith(".db-shm")) continue;
|
|
12909
|
-
const filePath =
|
|
13081
|
+
const filePath = path32.join(BACKUP_DIR, file);
|
|
12910
13082
|
try {
|
|
12911
13083
|
const stat = statSync4(filePath);
|
|
12912
13084
|
if (stat.mtimeMs < cutoff) {
|
|
@@ -12921,11 +13093,11 @@ function rotateBackups(keepDays = DEFAULT_KEEP_DAYS) {
|
|
|
12921
13093
|
return deleted;
|
|
12922
13094
|
}
|
|
12923
13095
|
function listBackups() {
|
|
12924
|
-
if (!
|
|
13096
|
+
if (!existsSync27(BACKUP_DIR)) return [];
|
|
12925
13097
|
try {
|
|
12926
13098
|
const files = readdirSync10(BACKUP_DIR).filter((f) => f.endsWith(".db") && !f.endsWith("-wal") && !f.endsWith("-shm"));
|
|
12927
13099
|
return files.map((name) => {
|
|
12928
|
-
const p =
|
|
13100
|
+
const p = path32.join(BACKUP_DIR, name);
|
|
12929
13101
|
const stat = statSync4(p);
|
|
12930
13102
|
return { path: p, name, size: stat.size, date: stat.mtime };
|
|
12931
13103
|
}).sort((a, b) => b.date.getTime() - a.date.getTime());
|
|
@@ -12950,7 +13122,7 @@ var init_db_backup = __esm({
|
|
|
12950
13122
|
"src/lib/db-backup.ts"() {
|
|
12951
13123
|
"use strict";
|
|
12952
13124
|
init_config();
|
|
12953
|
-
BACKUP_DIR =
|
|
13125
|
+
BACKUP_DIR = path32.join(EXE_AI_DIR, "backups");
|
|
12954
13126
|
DEFAULT_KEEP_DAYS = 3;
|
|
12955
13127
|
DB_NAMES = ["memories.db", "exe-mem.db", "exe-os.db", "exe.db"];
|
|
12956
13128
|
}
|
|
@@ -12975,8 +13147,8 @@ __export(crdt_sync_exports, {
|
|
|
12975
13147
|
rebuildFromDb: () => rebuildFromDb
|
|
12976
13148
|
});
|
|
12977
13149
|
import * as Y from "yjs";
|
|
12978
|
-
import { readFileSync as
|
|
12979
|
-
import
|
|
13150
|
+
import { readFileSync as readFileSync22, writeFileSync as writeFileSync16, existsSync as existsSync29, mkdirSync as mkdirSync14, unlinkSync as unlinkSync10 } from "fs";
|
|
13151
|
+
import path34 from "path";
|
|
12980
13152
|
import { homedir as homedir5 } from "os";
|
|
12981
13153
|
function getStatePath() {
|
|
12982
13154
|
return _statePathOverride ?? DEFAULT_STATE_PATH;
|
|
@@ -12988,9 +13160,9 @@ function initCrdtDoc() {
|
|
|
12988
13160
|
if (doc) return doc;
|
|
12989
13161
|
doc = new Y.Doc();
|
|
12990
13162
|
const sp = getStatePath();
|
|
12991
|
-
if (
|
|
13163
|
+
if (existsSync29(sp)) {
|
|
12992
13164
|
try {
|
|
12993
|
-
const state =
|
|
13165
|
+
const state = readFileSync22(sp);
|
|
12994
13166
|
Y.applyUpdate(doc, new Uint8Array(state));
|
|
12995
13167
|
} catch {
|
|
12996
13168
|
console.warn("[crdt-sync] WARN: corrupted state file, rebuilding from DB");
|
|
@@ -13132,10 +13304,10 @@ function persistState() {
|
|
|
13132
13304
|
if (!doc) return;
|
|
13133
13305
|
try {
|
|
13134
13306
|
const sp = getStatePath();
|
|
13135
|
-
const dir =
|
|
13136
|
-
if (!
|
|
13307
|
+
const dir = path34.dirname(sp);
|
|
13308
|
+
if (!existsSync29(dir)) mkdirSync14(dir, { recursive: true });
|
|
13137
13309
|
const state = Y.encodeStateAsUpdate(doc);
|
|
13138
|
-
|
|
13310
|
+
writeFileSync16(sp, Buffer.from(state));
|
|
13139
13311
|
} catch {
|
|
13140
13312
|
}
|
|
13141
13313
|
}
|
|
@@ -13176,7 +13348,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
|
|
|
13176
13348
|
var init_crdt_sync = __esm({
|
|
13177
13349
|
"src/lib/crdt-sync.ts"() {
|
|
13178
13350
|
"use strict";
|
|
13179
|
-
DEFAULT_STATE_PATH =
|
|
13351
|
+
DEFAULT_STATE_PATH = path34.join(homedir5(), ".exe-os", "crdt-state.bin");
|
|
13180
13352
|
_statePathOverride = null;
|
|
13181
13353
|
doc = null;
|
|
13182
13354
|
}
|
|
@@ -13189,8 +13361,8 @@ init_database();
|
|
|
13189
13361
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
13190
13362
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13191
13363
|
import { spawn as spawn4 } from "child_process";
|
|
13192
|
-
import { existsSync as
|
|
13193
|
-
import
|
|
13364
|
+
import { existsSync as existsSync37, openSync as openSync3, mkdirSync as mkdirSync20, closeSync as closeSync3, readFileSync as readFileSync30 } from "fs";
|
|
13365
|
+
import path48 from "path";
|
|
13194
13366
|
import os20 from "os";
|
|
13195
13367
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
13196
13368
|
|
|
@@ -14576,10 +14748,10 @@ function registerCreateTask(server2) {
|
|
|
14576
14748
|
skipDispatch: true
|
|
14577
14749
|
});
|
|
14578
14750
|
try {
|
|
14579
|
-
const { existsSync:
|
|
14751
|
+
const { existsSync: existsSync38, mkdirSync: mkdirSync21, writeFileSync: writeFileSync22 } = await import("fs");
|
|
14580
14752
|
const { identityPath: identityPath2 } = await Promise.resolve().then(() => (init_identity(), identity_exports));
|
|
14581
14753
|
const idPath = identityPath2(assigned_to);
|
|
14582
|
-
if (!
|
|
14754
|
+
if (!existsSync38(idPath)) {
|
|
14583
14755
|
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
14584
14756
|
const employees = await loadEmployees2();
|
|
14585
14757
|
const emp = employees.find((e) => e.name === assigned_to);
|
|
@@ -14588,8 +14760,8 @@ function registerCreateTask(server2) {
|
|
|
14588
14760
|
const template = getTemplateForTitle2(emp.role);
|
|
14589
14761
|
if (template) {
|
|
14590
14762
|
const dir = (await import("path")).dirname(idPath);
|
|
14591
|
-
if (!
|
|
14592
|
-
|
|
14763
|
+
if (!existsSync38(dir)) mkdirSync21(dir, { recursive: true });
|
|
14764
|
+
writeFileSync22(idPath, template.replace(/^agent_id: \w+/m, `agent_id: ${assigned_to}`), "utf-8");
|
|
14593
14765
|
}
|
|
14594
14766
|
}
|
|
14595
14767
|
}
|
|
@@ -17551,12 +17723,12 @@ function registerExportGraph(server2) {
|
|
|
17551
17723
|
}
|
|
17552
17724
|
const html = await exportGraphHTML(client);
|
|
17553
17725
|
const fs = await import("fs");
|
|
17554
|
-
const
|
|
17726
|
+
const path49 = await import("path");
|
|
17555
17727
|
const os21 = await import("os");
|
|
17556
|
-
const outDir =
|
|
17728
|
+
const outDir = path49.join(os21.homedir(), ".exe-os", "exports");
|
|
17557
17729
|
fs.mkdirSync(outDir, { recursive: true });
|
|
17558
17730
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
17559
|
-
const filePath =
|
|
17731
|
+
const filePath = path49.join(outDir, `graph-${timestamp}.html`);
|
|
17560
17732
|
fs.writeFileSync(filePath, html, "utf-8");
|
|
17561
17733
|
return {
|
|
17562
17734
|
content: [
|
|
@@ -17879,7 +18051,7 @@ function registerGraph(server2) {
|
|
|
17879
18051
|
}
|
|
17880
18052
|
|
|
17881
18053
|
// src/mcp/tools/config.ts
|
|
17882
|
-
import { z as
|
|
18054
|
+
import { z as z73 } from "zod";
|
|
17883
18055
|
|
|
17884
18056
|
// src/mcp/tools/set-agent-config.ts
|
|
17885
18057
|
init_active_agent();
|
|
@@ -18685,8 +18857,6 @@ init_database();
|
|
|
18685
18857
|
import { z as z56 } from "zod";
|
|
18686
18858
|
|
|
18687
18859
|
// src/bin/exe-doctor.ts
|
|
18688
|
-
init_store();
|
|
18689
|
-
init_database();
|
|
18690
18860
|
import os14 from "os";
|
|
18691
18861
|
|
|
18692
18862
|
// src/lib/is-main.ts
|
|
@@ -18705,9 +18875,9 @@ function isMainModule(importMetaUrl) {
|
|
|
18705
18875
|
}
|
|
18706
18876
|
|
|
18707
18877
|
// src/bin/exe-doctor.ts
|
|
18708
|
-
import { existsSync as
|
|
18878
|
+
import { existsSync as existsSync28, readFileSync as readFileSync21 } from "fs";
|
|
18709
18879
|
import { spawn as spawn2 } from "child_process";
|
|
18710
|
-
import
|
|
18880
|
+
import path33 from "path";
|
|
18711
18881
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
18712
18882
|
|
|
18713
18883
|
// src/lib/conflict-detector.ts
|
|
@@ -18970,6 +19140,140 @@ async function detectConflicts(client, projectFilter, agentFilter2) {
|
|
|
18970
19140
|
};
|
|
18971
19141
|
}
|
|
18972
19142
|
|
|
19143
|
+
// src/adapters/runtime-hook-manifest.ts
|
|
19144
|
+
var EXE_HOOKS = {
|
|
19145
|
+
postToolCombined: "dist/hooks/post-tool-combined.js",
|
|
19146
|
+
sessionStart: "dist/hooks/session-start.js",
|
|
19147
|
+
promptSubmit: "dist/hooks/prompt-submit.js",
|
|
19148
|
+
heartbeat: "dist/hooks/exe-heartbeat-hook.js",
|
|
19149
|
+
stop: "dist/hooks/stop.js",
|
|
19150
|
+
preToolUse: "dist/hooks/pre-tool-use.js",
|
|
19151
|
+
subagentStop: "dist/hooks/subagent-stop.js",
|
|
19152
|
+
preCompact: "dist/hooks/pre-compact.js",
|
|
19153
|
+
postCompact: "dist/hooks/post-compact.js",
|
|
19154
|
+
sessionEnd: "dist/hooks/session-end.js",
|
|
19155
|
+
notification: "dist/hooks/notification.js",
|
|
19156
|
+
instructionsLoaded: "dist/hooks/instructions-loaded.js"
|
|
19157
|
+
};
|
|
19158
|
+
var EXE_HOOK_MANIFEST = [
|
|
19159
|
+
{
|
|
19160
|
+
key: "postToolCombined",
|
|
19161
|
+
event: "PostToolUse",
|
|
19162
|
+
commandMarker: EXE_HOOKS.postToolCombined,
|
|
19163
|
+
owner: "exe-os",
|
|
19164
|
+
purpose: "Single PostToolUse entrypoint for ingestion, error recall, summaries, and bug detection.",
|
|
19165
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
19166
|
+
checkpointRole: "none"
|
|
19167
|
+
},
|
|
19168
|
+
{
|
|
19169
|
+
key: "sessionStart",
|
|
19170
|
+
event: "SessionStart",
|
|
19171
|
+
commandMarker: EXE_HOOKS.sessionStart,
|
|
19172
|
+
owner: "exe-os",
|
|
19173
|
+
purpose: "Loads agent identity, procedures, and boot context.",
|
|
19174
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
19175
|
+
checkpointRole: "none"
|
|
19176
|
+
},
|
|
19177
|
+
{
|
|
19178
|
+
key: "promptSubmit",
|
|
19179
|
+
event: "UserPromptSubmit",
|
|
19180
|
+
commandMarker: EXE_HOOKS.promptSubmit,
|
|
19181
|
+
owner: "exe-os",
|
|
19182
|
+
purpose: "Injects current tasks, pending reviews, and local context before each prompt.",
|
|
19183
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
19184
|
+
checkpointRole: "none"
|
|
19185
|
+
},
|
|
19186
|
+
{
|
|
19187
|
+
key: "heartbeat",
|
|
19188
|
+
event: "UserPromptSubmit",
|
|
19189
|
+
commandMarker: EXE_HOOKS.heartbeat,
|
|
19190
|
+
owner: "exe-os",
|
|
19191
|
+
purpose: "Lightweight heartbeat/status sidecar for Claude Code sessions.",
|
|
19192
|
+
runtimes: ["claude"],
|
|
19193
|
+
checkpointRole: "none"
|
|
19194
|
+
},
|
|
19195
|
+
{
|
|
19196
|
+
key: "stop",
|
|
19197
|
+
event: "Stop",
|
|
19198
|
+
commandMarker: EXE_HOOKS.stop,
|
|
19199
|
+
owner: "exe-os",
|
|
19200
|
+
purpose: "Finalizes task state, capacity signals, and emergency checkpointing.",
|
|
19201
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
19202
|
+
checkpointRole: "capacity_checkpoint"
|
|
19203
|
+
},
|
|
19204
|
+
{
|
|
19205
|
+
key: "preToolUse",
|
|
19206
|
+
event: "PreToolUse",
|
|
19207
|
+
commandMarker: EXE_HOOKS.preToolUse,
|
|
19208
|
+
owner: "exe-os",
|
|
19209
|
+
purpose: "Preflight guardrails before shell/tool execution.",
|
|
19210
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
19211
|
+
checkpointRole: "none"
|
|
19212
|
+
},
|
|
19213
|
+
{
|
|
19214
|
+
key: "subagentStop",
|
|
19215
|
+
event: "SubagentStop",
|
|
19216
|
+
commandMarker: EXE_HOOKS.subagentStop,
|
|
19217
|
+
owner: "exe-os",
|
|
19218
|
+
purpose: "Captures subagent completion context.",
|
|
19219
|
+
runtimes: ["claude"],
|
|
19220
|
+
checkpointRole: "none"
|
|
19221
|
+
},
|
|
19222
|
+
{
|
|
19223
|
+
key: "preCompact",
|
|
19224
|
+
event: "PreCompact",
|
|
19225
|
+
commandMarker: EXE_HOOKS.preCompact,
|
|
19226
|
+
owner: "exe-os",
|
|
19227
|
+
purpose: "Writes active-task snapshot and compaction recovery context.",
|
|
19228
|
+
runtimes: ["claude"],
|
|
19229
|
+
checkpointRole: "recovery_context"
|
|
19230
|
+
},
|
|
19231
|
+
{
|
|
19232
|
+
key: "postCompact",
|
|
19233
|
+
event: "PostCompact",
|
|
19234
|
+
commandMarker: EXE_HOOKS.postCompact,
|
|
19235
|
+
owner: "exe-os",
|
|
19236
|
+
purpose: "Rehydrates recovery context after compaction.",
|
|
19237
|
+
runtimes: ["claude"],
|
|
19238
|
+
checkpointRole: "recovery_context"
|
|
19239
|
+
},
|
|
19240
|
+
{
|
|
19241
|
+
key: "sessionEnd",
|
|
19242
|
+
event: "SessionEnd",
|
|
19243
|
+
commandMarker: EXE_HOOKS.sessionEnd,
|
|
19244
|
+
owner: "exe-os",
|
|
19245
|
+
purpose: "Stores session-end checkpoint and triages orphaned in-progress tasks.",
|
|
19246
|
+
runtimes: ["claude"],
|
|
19247
|
+
checkpointRole: "session_summary"
|
|
19248
|
+
},
|
|
19249
|
+
{
|
|
19250
|
+
key: "notification",
|
|
19251
|
+
event: "Notification",
|
|
19252
|
+
commandMarker: EXE_HOOKS.notification,
|
|
19253
|
+
owner: "exe-os",
|
|
19254
|
+
purpose: "Captures runtime notifications and nudges.",
|
|
19255
|
+
runtimes: ["claude"],
|
|
19256
|
+
checkpointRole: "none"
|
|
19257
|
+
},
|
|
19258
|
+
{
|
|
19259
|
+
key: "instructionsLoaded",
|
|
19260
|
+
event: "InstructionsLoaded",
|
|
19261
|
+
commandMarker: EXE_HOOKS.instructionsLoaded,
|
|
19262
|
+
owner: "exe-os",
|
|
19263
|
+
purpose: "Applies runtime instruction post-processing.",
|
|
19264
|
+
runtimes: ["claude"],
|
|
19265
|
+
checkpointRole: "none"
|
|
19266
|
+
}
|
|
19267
|
+
];
|
|
19268
|
+
var LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS = [
|
|
19269
|
+
"dist/hooks/ingest.js",
|
|
19270
|
+
"dist/hooks/error-recall.js",
|
|
19271
|
+
"dist/hooks/ingest-worker.js"
|
|
19272
|
+
];
|
|
19273
|
+
function manifestEntryForCommand(command) {
|
|
19274
|
+
return EXE_HOOK_MANIFEST.find((entry) => command.includes(entry.commandMarker));
|
|
19275
|
+
}
|
|
19276
|
+
|
|
18973
19277
|
// src/bin/exe-doctor.ts
|
|
18974
19278
|
function parseFlags(argv) {
|
|
18975
19279
|
const flags = { fix: false, dryRun: false, verbose: false, conflicts: false };
|
|
@@ -19121,7 +19425,7 @@ async function auditOrphanedProjects(client) {
|
|
|
19121
19425
|
for (const row of result.rows) {
|
|
19122
19426
|
const name = row.project_name;
|
|
19123
19427
|
const count = Number(row.cnt);
|
|
19124
|
-
const exists =
|
|
19428
|
+
const exists = existsSync28(path33.join(home, name)) || existsSync28(path33.join(home, "..", name)) || existsSync28(path33.join(process.cwd(), "..", name));
|
|
19125
19429
|
if (!exists) {
|
|
19126
19430
|
orphans.push({ project_name: name, count });
|
|
19127
19431
|
}
|
|
@@ -19129,18 +19433,18 @@ async function auditOrphanedProjects(client) {
|
|
|
19129
19433
|
return orphans;
|
|
19130
19434
|
}
|
|
19131
19435
|
function auditHookHealth() {
|
|
19132
|
-
const logPath =
|
|
19436
|
+
const logPath = path33.join(
|
|
19133
19437
|
process.env.HOME ?? process.env.USERPROFILE ?? "",
|
|
19134
19438
|
".exe-os",
|
|
19135
19439
|
"logs",
|
|
19136
19440
|
"hooks.log"
|
|
19137
19441
|
);
|
|
19138
|
-
if (!
|
|
19442
|
+
if (!existsSync28(logPath)) {
|
|
19139
19443
|
return { logExists: false, totalLines: 0, errorsLastHour: 0, topPatterns: [] };
|
|
19140
19444
|
}
|
|
19141
19445
|
let content;
|
|
19142
19446
|
try {
|
|
19143
|
-
content =
|
|
19447
|
+
content = readFileSync21(logPath, "utf-8");
|
|
19144
19448
|
} catch {
|
|
19145
19449
|
return { logExists: false, totalLines: 0, errorsLastHour: 0, topPatterns: [] };
|
|
19146
19450
|
}
|
|
@@ -19168,6 +19472,121 @@ function auditHookHealth() {
|
|
|
19168
19472
|
const topPatterns = [...patternCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([pattern, count]) => ({ pattern, count }));
|
|
19169
19473
|
return { logExists: true, totalLines, errorsLastHour, topPatterns };
|
|
19170
19474
|
}
|
|
19475
|
+
function safeReadJson(filePath) {
|
|
19476
|
+
if (!existsSync28(filePath)) return null;
|
|
19477
|
+
try {
|
|
19478
|
+
return JSON.parse(readFileSync21(filePath, "utf-8"));
|
|
19479
|
+
} catch {
|
|
19480
|
+
return null;
|
|
19481
|
+
}
|
|
19482
|
+
}
|
|
19483
|
+
function collectHookCommandsFromClaudeSettings(settings) {
|
|
19484
|
+
const hooks = settings?.hooks;
|
|
19485
|
+
if (!hooks || typeof hooks !== "object") return [];
|
|
19486
|
+
const commands = [];
|
|
19487
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
19488
|
+
if (!Array.isArray(groups)) continue;
|
|
19489
|
+
for (const group of groups) {
|
|
19490
|
+
const hooksForGroup = group?.hooks;
|
|
19491
|
+
if (!Array.isArray(hooksForGroup)) continue;
|
|
19492
|
+
for (const hook of hooksForGroup) {
|
|
19493
|
+
const command = hook?.command;
|
|
19494
|
+
if (typeof command === "string") commands.push({ event, command });
|
|
19495
|
+
}
|
|
19496
|
+
}
|
|
19497
|
+
}
|
|
19498
|
+
return commands;
|
|
19499
|
+
}
|
|
19500
|
+
function collectHookCommandsFromCodexHooks(config2) {
|
|
19501
|
+
const commands = [];
|
|
19502
|
+
if (!config2 || typeof config2 !== "object") return commands;
|
|
19503
|
+
const root = config2;
|
|
19504
|
+
for (const [event, value] of Object.entries(root)) {
|
|
19505
|
+
const entries = Array.isArray(value) ? value : value && typeof value === "object" ? Object.values(value) : [];
|
|
19506
|
+
for (const entry of entries) {
|
|
19507
|
+
if (typeof entry === "string") commands.push({ event, command: entry });
|
|
19508
|
+
const command = entry?.command;
|
|
19509
|
+
if (typeof command === "string") commands.push({ event, command });
|
|
19510
|
+
}
|
|
19511
|
+
}
|
|
19512
|
+
return commands;
|
|
19513
|
+
}
|
|
19514
|
+
function buildHookOwnershipIssues(runtime, commands) {
|
|
19515
|
+
const issues = [];
|
|
19516
|
+
for (const marker of LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS) {
|
|
19517
|
+
const count = commands.filter((cmd) => cmd.command.includes(marker)).length;
|
|
19518
|
+
if (count > 0) {
|
|
19519
|
+
issues.push({
|
|
19520
|
+
runtime,
|
|
19521
|
+
event: "PostToolUse",
|
|
19522
|
+
marker,
|
|
19523
|
+
count,
|
|
19524
|
+
message: `Legacy split PostToolUse hook still installed: ${marker}`
|
|
19525
|
+
});
|
|
19526
|
+
}
|
|
19527
|
+
}
|
|
19528
|
+
for (const entry of EXE_HOOK_MANIFEST.filter((hook) => hook.runtimes.includes(runtime))) {
|
|
19529
|
+
const matching = commands.filter((cmd) => cmd.command.includes(entry.commandMarker));
|
|
19530
|
+
if (matching.length > 1) {
|
|
19531
|
+
issues.push({
|
|
19532
|
+
runtime,
|
|
19533
|
+
event: entry.event,
|
|
19534
|
+
marker: entry.commandMarker,
|
|
19535
|
+
count: matching.length,
|
|
19536
|
+
message: `Duplicate exe-os hook owner for ${entry.event}: ${entry.commandMarker}`
|
|
19537
|
+
});
|
|
19538
|
+
}
|
|
19539
|
+
for (const cmd of matching) {
|
|
19540
|
+
if (cmd.event !== entry.event) {
|
|
19541
|
+
issues.push({
|
|
19542
|
+
runtime,
|
|
19543
|
+
event: cmd.event,
|
|
19544
|
+
marker: entry.commandMarker,
|
|
19545
|
+
count: 1,
|
|
19546
|
+
message: `exe-os hook ${entry.commandMarker} is registered under ${cmd.event}, expected ${entry.event}`
|
|
19547
|
+
});
|
|
19548
|
+
}
|
|
19549
|
+
}
|
|
19550
|
+
}
|
|
19551
|
+
for (const cmd of commands) {
|
|
19552
|
+
if (!cmd.command.includes("dist/hooks/")) continue;
|
|
19553
|
+
if (!cmd.command.includes("exe-os")) continue;
|
|
19554
|
+
const entry = manifestEntryForCommand(cmd.command);
|
|
19555
|
+
const isLegacy = LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS.some((marker) => cmd.command.includes(marker));
|
|
19556
|
+
if (!entry && !isLegacy) {
|
|
19557
|
+
issues.push({
|
|
19558
|
+
runtime,
|
|
19559
|
+
event: cmd.event,
|
|
19560
|
+
marker: "dist/hooks/",
|
|
19561
|
+
count: 1,
|
|
19562
|
+
message: `Unknown exe-os hook command not present in ownership manifest: ${cmd.command.slice(0, 160)}`
|
|
19563
|
+
});
|
|
19564
|
+
}
|
|
19565
|
+
}
|
|
19566
|
+
return issues;
|
|
19567
|
+
}
|
|
19568
|
+
function auditHookOwnership() {
|
|
19569
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
19570
|
+
const checkedFiles = [];
|
|
19571
|
+
const issues = [];
|
|
19572
|
+
const claudeSettingsPath = path33.join(home, ".claude", "settings.json");
|
|
19573
|
+
const claudeSettings = safeReadJson(claudeSettingsPath);
|
|
19574
|
+
if (claudeSettings) {
|
|
19575
|
+
checkedFiles.push(claudeSettingsPath);
|
|
19576
|
+
issues.push(...buildHookOwnershipIssues("claude", collectHookCommandsFromClaudeSettings(claudeSettings)));
|
|
19577
|
+
}
|
|
19578
|
+
const codexHooksPath = path33.join(home, ".codex", "hooks.json");
|
|
19579
|
+
const codexHooks = safeReadJson(codexHooksPath);
|
|
19580
|
+
if (codexHooks) {
|
|
19581
|
+
checkedFiles.push(codexHooksPath);
|
|
19582
|
+
issues.push(...buildHookOwnershipIssues("codex", collectHookCommandsFromCodexHooks(codexHooks)));
|
|
19583
|
+
}
|
|
19584
|
+
return {
|
|
19585
|
+
checkedFiles,
|
|
19586
|
+
issues,
|
|
19587
|
+
staleLegacyHooks: issues.filter((issue) => issue.message.includes("Legacy split"))
|
|
19588
|
+
};
|
|
19589
|
+
}
|
|
19171
19590
|
async function auditShards() {
|
|
19172
19591
|
try {
|
|
19173
19592
|
const { auditShardHealth: auditShardHealth2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -19183,16 +19602,33 @@ async function auditShards() {
|
|
|
19183
19602
|
return { total: 0, ok: 0, unreadable: 0, archived: 0, unreadableNames: [] };
|
|
19184
19603
|
}
|
|
19185
19604
|
}
|
|
19605
|
+
async function auditKeyHealth() {
|
|
19606
|
+
try {
|
|
19607
|
+
const { getMasterKey: getMasterKey2 } = await Promise.resolve().then(() => (init_keychain(), keychain_exports));
|
|
19608
|
+
const { getKeyBackupStatus: getKeyBackupStatus2 } = await Promise.resolve().then(() => (init_key_backup_status(), key_backup_status_exports));
|
|
19609
|
+
const key = await getMasterKey2();
|
|
19610
|
+
const backup = getKeyBackupStatus2();
|
|
19611
|
+
return {
|
|
19612
|
+
masterKeyPresent: Boolean(key),
|
|
19613
|
+
recoveryBackupMarked: backup.exists,
|
|
19614
|
+
recoveryBackupConfirmedAt: backup.confirmedAt,
|
|
19615
|
+
recoveryBackupSource: backup.source
|
|
19616
|
+
};
|
|
19617
|
+
} catch {
|
|
19618
|
+
return { masterKeyPresent: false, recoveryBackupMarked: false };
|
|
19619
|
+
}
|
|
19620
|
+
}
|
|
19186
19621
|
async function runAudit(client, flags) {
|
|
19187
19622
|
const runConflicts = flags.conflicts || process.env.EXE_AUDIT_CONFLICTS === "1";
|
|
19188
|
-
const [stats, nullVectors, duplicates, bloated, fts, orphanedProjects, shards] = await Promise.all([
|
|
19623
|
+
const [stats, nullVectors, duplicates, bloated, fts, orphanedProjects, shards, keyHealth] = await Promise.all([
|
|
19189
19624
|
auditStats(client, flags),
|
|
19190
19625
|
auditNullVectors(client, flags),
|
|
19191
19626
|
auditDuplicates(client, flags),
|
|
19192
19627
|
auditBloated(client, flags),
|
|
19193
19628
|
auditFts(client),
|
|
19194
19629
|
auditOrphanedProjects(client),
|
|
19195
|
-
auditShards()
|
|
19630
|
+
auditShards(),
|
|
19631
|
+
auditKeyHealth()
|
|
19196
19632
|
]);
|
|
19197
19633
|
let conflicts;
|
|
19198
19634
|
if (runConflicts) {
|
|
@@ -19212,7 +19648,8 @@ async function runAudit(client, flags) {
|
|
|
19212
19648
|
}
|
|
19213
19649
|
const duplicateCount = duplicates.reduce((sum, d) => sum + d.delete_ids.length, 0);
|
|
19214
19650
|
const hookHealth = auditHookHealth();
|
|
19215
|
-
|
|
19651
|
+
const hookOwnership = auditHookOwnership();
|
|
19652
|
+
return { stats, nullVectors, duplicates, duplicateCount, bloated, fts, orphanedProjects, conflicts, hookHealth, hookOwnership, shards, keyHealth };
|
|
19216
19653
|
}
|
|
19217
19654
|
function indicator(value, warn) {
|
|
19218
19655
|
if (value === 0) return "\u{1F7E2}";
|
|
@@ -19260,6 +19697,15 @@ function formatReport(report, flags) {
|
|
|
19260
19697
|
lines.push(`${indicator(report.bloated.length, 20)} Bloated (>5KB): ${fmtNum(report.bloated.length)} / ${fmtNum(s.total)} (${pct(report.bloated.length, s.total)})`);
|
|
19261
19698
|
const ftsIndicator = report.fts.inSync ? "\u{1F7E2}" : "\u{1F534}";
|
|
19262
19699
|
lines.push(`${ftsIndicator} FTS index: ${report.fts.inSync ? "in sync" : "OUT OF SYNC"} (${fmtNum(report.fts.memoryCount)} / ${fmtNum(report.fts.ftsCount)})`);
|
|
19700
|
+
const kh = report.keyHealth;
|
|
19701
|
+
if (!kh.masterKeyPresent) {
|
|
19702
|
+
lines.push("\u{1F534} Recovery key: master key missing \u2014 import phrase or run setup before syncing");
|
|
19703
|
+
} else if (!kh.recoveryBackupMarked) {
|
|
19704
|
+
lines.push("\u{1F534} Recovery backup: not confirmed \u2014 run `exe-os link export --local-terminal-only` and save the 24-word phrase");
|
|
19705
|
+
} else {
|
|
19706
|
+
const suffix = kh.recoveryBackupConfirmedAt ? ` (${kh.recoveryBackupConfirmedAt.slice(0, 10)}${kh.recoveryBackupSource ? ` via ${kh.recoveryBackupSource}` : ""})` : "";
|
|
19707
|
+
lines.push(`\u{1F7E2} Recovery backup: confirmed${suffix}`);
|
|
19708
|
+
}
|
|
19263
19709
|
if (report.orphanedProjects.length > 0) {
|
|
19264
19710
|
const orphanList = report.orphanedProjects.map((o) => `${o.project_name} \u2014 ${o.count} memories`).join(", ");
|
|
19265
19711
|
lines.push(`\u2139\uFE0F Orphaned projects: ${report.orphanedProjects.length} (${orphanList})`);
|
|
@@ -19291,6 +19737,15 @@ function formatReport(report, flags) {
|
|
|
19291
19737
|
lines.push(` ${p.count}x: ${p.pattern}`);
|
|
19292
19738
|
}
|
|
19293
19739
|
}
|
|
19740
|
+
const ho = report.hookOwnership;
|
|
19741
|
+
if (ho.issues.length === 0) {
|
|
19742
|
+
lines.push(`\u{1F7E2} Hook ownership: ${ho.checkedFiles.length > 0 ? "manifest clean" : "no local hook config found"}`);
|
|
19743
|
+
} else {
|
|
19744
|
+
lines.push(`\u{1F534} Hook ownership: ${fmtNum(ho.issues.length)} issue(s)`);
|
|
19745
|
+
for (const issue of ho.issues.slice(0, 5)) {
|
|
19746
|
+
lines.push(` [${issue.runtime}/${issue.event}] ${issue.message}`);
|
|
19747
|
+
}
|
|
19748
|
+
}
|
|
19294
19749
|
const sh = report.shards;
|
|
19295
19750
|
if (sh.total > 0) {
|
|
19296
19751
|
if (sh.unreadable === 0) {
|
|
@@ -19360,6 +19815,9 @@ function formatReport(report, flags) {
|
|
|
19360
19815
|
if (report.conflicts.superseded > 0) {
|
|
19361
19816
|
recs.push(`${fmtNum(report.conflicts.superseded)} superseded memories can be deactivated`);
|
|
19362
19817
|
}
|
|
19818
|
+
if (report.hookOwnership.issues.length > 0) {
|
|
19819
|
+
recs.push(`Run exe-os install to refresh hook config; remove stale exe-os hook commands if they remain`);
|
|
19820
|
+
}
|
|
19363
19821
|
if (recs.length > 0) {
|
|
19364
19822
|
lines.push("Recommendations:");
|
|
19365
19823
|
for (const r of recs) {
|
|
@@ -19381,7 +19839,7 @@ async function fixNullVectors() {
|
|
|
19381
19839
|
}
|
|
19382
19840
|
}
|
|
19383
19841
|
const npmRoot = (await import("child_process")).execSync("npm root -g", { encoding: "utf8" }).trim();
|
|
19384
|
-
const backfillPath =
|
|
19842
|
+
const backfillPath = path33.join(npmRoot, "exe-os", "dist", "bin", "backfill-vectors.js");
|
|
19385
19843
|
return new Promise((resolve, reject) => {
|
|
19386
19844
|
const child = spawn2("node", [backfillPath], { stdio: "inherit" });
|
|
19387
19845
|
if (child.pid) registerWorkerPid2(child.pid);
|
|
@@ -19493,8 +19951,8 @@ function splitAtSentences(text3, maxChunkSize) {
|
|
|
19493
19951
|
}
|
|
19494
19952
|
async function main(argv = process.argv.slice(2)) {
|
|
19495
19953
|
const flags = parseFlags(argv);
|
|
19496
|
-
await
|
|
19497
|
-
const client =
|
|
19954
|
+
const { fastDbInit: fastDbInit2 } = await Promise.resolve().then(() => (init_fast_db_init(), fast_db_init_exports));
|
|
19955
|
+
const client = await fastDbInit2();
|
|
19498
19956
|
const report = await runAudit(client, flags);
|
|
19499
19957
|
console.log(formatReport(report, flags));
|
|
19500
19958
|
if (flags.fix || flags.dryRun) {
|
|
@@ -19685,9 +20143,9 @@ import { z as z58 } from "zod";
|
|
|
19685
20143
|
|
|
19686
20144
|
// src/lib/cloud-sync.ts
|
|
19687
20145
|
init_database();
|
|
19688
|
-
import { readFileSync as
|
|
20146
|
+
import { readFileSync as readFileSync23, writeFileSync as writeFileSync17, existsSync as existsSync30, readdirSync as readdirSync11, mkdirSync as mkdirSync15, appendFileSync as appendFileSync2, unlinkSync as unlinkSync11, openSync as openSync2, closeSync as closeSync2, statSync as statSync5 } from "fs";
|
|
19689
20147
|
import crypto15 from "crypto";
|
|
19690
|
-
import
|
|
20148
|
+
import path35 from "path";
|
|
19691
20149
|
import { homedir as homedir6 } from "os";
|
|
19692
20150
|
|
|
19693
20151
|
// src/lib/crypto.ts
|
|
@@ -19762,7 +20220,7 @@ function sqlSafe(v) {
|
|
|
19762
20220
|
}
|
|
19763
20221
|
function logError(msg) {
|
|
19764
20222
|
try {
|
|
19765
|
-
const logPath =
|
|
20223
|
+
const logPath = path35.join(homedir6(), ".exe-os", "workers.log");
|
|
19766
20224
|
appendFileSync2(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
|
|
19767
20225
|
`);
|
|
19768
20226
|
} catch {
|
|
@@ -19771,7 +20229,7 @@ function logError(msg) {
|
|
|
19771
20229
|
var LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
19772
20230
|
var FETCH_TIMEOUT_MS2 = 3e4;
|
|
19773
20231
|
var PUSH_BATCH_SIZE = 5e3;
|
|
19774
|
-
var ROSTER_LOCK_PATH =
|
|
20232
|
+
var ROSTER_LOCK_PATH = path35.join(EXE_AI_DIR, "roster-merge.lock");
|
|
19775
20233
|
var LOCK_STALE_MS = 3e4;
|
|
19776
20234
|
var _pgPromise = null;
|
|
19777
20235
|
var _pgFailed = false;
|
|
@@ -19780,12 +20238,12 @@ function isTruthyEnv(value) {
|
|
|
19780
20238
|
}
|
|
19781
20239
|
function loadPgClient() {
|
|
19782
20240
|
if (_pgFailed) return null;
|
|
19783
|
-
const configPath =
|
|
20241
|
+
const configPath = path35.join(EXE_AI_DIR, "config.json");
|
|
19784
20242
|
let cloudPostgresUrl;
|
|
19785
20243
|
let configEnabled = false;
|
|
19786
20244
|
try {
|
|
19787
|
-
if (
|
|
19788
|
-
const cfg = JSON.parse(
|
|
20245
|
+
if (existsSync30(configPath)) {
|
|
20246
|
+
const cfg = JSON.parse(readFileSync23(configPath, "utf8"));
|
|
19789
20247
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
19790
20248
|
configEnabled = cfg.cloud?.syncToPostgres === true;
|
|
19791
20249
|
}
|
|
@@ -19812,8 +20270,8 @@ function loadPgClient() {
|
|
|
19812
20270
|
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
19813
20271
|
return new Ctor2();
|
|
19814
20272
|
}
|
|
19815
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
19816
|
-
const req = createRequire6(
|
|
20273
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path35.join(homedir6(), "exe-db");
|
|
20274
|
+
const req = createRequire6(path35.join(exeDbRoot, "package.json"));
|
|
19817
20275
|
const entry = req.resolve("@prisma/client");
|
|
19818
20276
|
const mod = await import(pathToFileURL6(entry).href);
|
|
19819
20277
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -19858,18 +20316,18 @@ async function withRosterLock(fn) {
|
|
|
19858
20316
|
try {
|
|
19859
20317
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
19860
20318
|
closeSync2(fd);
|
|
19861
|
-
|
|
20319
|
+
writeFileSync17(ROSTER_LOCK_PATH, String(Date.now()));
|
|
19862
20320
|
} catch (err) {
|
|
19863
20321
|
if (err.code === "EEXIST") {
|
|
19864
20322
|
try {
|
|
19865
|
-
const ts2 = parseInt(
|
|
20323
|
+
const ts2 = parseInt(readFileSync23(ROSTER_LOCK_PATH, "utf-8"), 10);
|
|
19866
20324
|
if (Date.now() - ts2 < LOCK_STALE_MS) {
|
|
19867
20325
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
19868
20326
|
}
|
|
19869
20327
|
unlinkSync11(ROSTER_LOCK_PATH);
|
|
19870
20328
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
19871
20329
|
closeSync2(fd);
|
|
19872
|
-
|
|
20330
|
+
writeFileSync17(ROSTER_LOCK_PATH, String(Date.now()));
|
|
19873
20331
|
} catch (retryErr) {
|
|
19874
20332
|
if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
|
|
19875
20333
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
@@ -19988,6 +20446,16 @@ async function cloudPull(sinceVersion, config2) {
|
|
|
19988
20446
|
return { records: [], maxVersion: sinceVersion };
|
|
19989
20447
|
}
|
|
19990
20448
|
}
|
|
20449
|
+
var CLOUD_RELINK_REQUIRED_MESSAGE = "[cloud-sync] Paused after key rotation. Run `exe-os cloud relink --dry-run` for the safe relink checklist.";
|
|
20450
|
+
async function getCloudRelinkRequired(client = getClient()) {
|
|
20451
|
+
try {
|
|
20452
|
+
await client.execute("CREATE TABLE IF NOT EXISTS sync_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)");
|
|
20453
|
+
const relink = await client.execute("SELECT value FROM sync_meta WHERE key = 'cloud_relink_required' LIMIT 1");
|
|
20454
|
+
return String(relink.rows[0]?.value ?? "") === "1";
|
|
20455
|
+
} catch {
|
|
20456
|
+
return false;
|
|
20457
|
+
}
|
|
20458
|
+
}
|
|
19991
20459
|
async function cloudSync(config2) {
|
|
19992
20460
|
if (!isSyncCryptoInitialized()) {
|
|
19993
20461
|
try {
|
|
@@ -20009,10 +20477,7 @@ async function cloudSync(config2) {
|
|
|
20009
20477
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
20010
20478
|
}
|
|
20011
20479
|
try {
|
|
20012
|
-
|
|
20013
|
-
if (String(relink.rows[0]?.value ?? "") === "1") {
|
|
20014
|
-
throw new Error("[cloud-sync] Paused after key rotation. Re-link/reupload cloud sync with the new recovery phrase before syncing.");
|
|
20015
|
-
}
|
|
20480
|
+
if (await getCloudRelinkRequired(client)) throw new Error(CLOUD_RELINK_REQUIRED_MESSAGE);
|
|
20016
20481
|
} catch (err) {
|
|
20017
20482
|
const msg = err instanceof Error ? err.message : String(err);
|
|
20018
20483
|
if (msg.includes("Paused after key rotation")) throw err;
|
|
@@ -20262,8 +20727,8 @@ async function cloudSync(config2) {
|
|
|
20262
20727
|
try {
|
|
20263
20728
|
const employees = await loadEmployees();
|
|
20264
20729
|
rosterResult.employees = employees.length;
|
|
20265
|
-
const idDir =
|
|
20266
|
-
if (
|
|
20730
|
+
const idDir = path35.join(EXE_AI_DIR, "identity");
|
|
20731
|
+
if (existsSync30(idDir)) {
|
|
20267
20732
|
rosterResult.identities = readdirSync11(idDir).filter((f) => f.endsWith(".md")).length;
|
|
20268
20733
|
}
|
|
20269
20734
|
} catch {
|
|
@@ -20276,7 +20741,7 @@ async function cloudSync(config2) {
|
|
|
20276
20741
|
const backupSize = statSync5(latestBackup).size;
|
|
20277
20742
|
const MAX_CLOUD_BACKUP_BYTES = 50 * 1024 * 1024;
|
|
20278
20743
|
if (backupSize <= MAX_CLOUD_BACKUP_BYTES) {
|
|
20279
|
-
const backupData =
|
|
20744
|
+
const backupData = readFileSync23(latestBackup);
|
|
20280
20745
|
const deviceId = loadDeviceId() ?? "unknown";
|
|
20281
20746
|
const encrypted = encryptSyncBlob(backupData);
|
|
20282
20747
|
const backupRes = await fetchWithRetry(`${config2.endpoint}/sync/push-db-backup`, {
|
|
@@ -20284,7 +20749,7 @@ async function cloudSync(config2) {
|
|
|
20284
20749
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${config2.apiKey}` },
|
|
20285
20750
|
body: JSON.stringify({
|
|
20286
20751
|
device_id: deviceId,
|
|
20287
|
-
filename:
|
|
20752
|
+
filename: path35.basename(latestBackup),
|
|
20288
20753
|
blob: encrypted,
|
|
20289
20754
|
size: backupData.length
|
|
20290
20755
|
})
|
|
@@ -20309,49 +20774,49 @@ async function cloudSync(config2) {
|
|
|
20309
20774
|
roster: rosterResult
|
|
20310
20775
|
};
|
|
20311
20776
|
}
|
|
20312
|
-
var ROSTER_DELETIONS_PATH =
|
|
20777
|
+
var ROSTER_DELETIONS_PATH = path35.join(EXE_AI_DIR, "roster-deletions.json");
|
|
20313
20778
|
function consumeRosterDeletions() {
|
|
20314
20779
|
try {
|
|
20315
|
-
if (!
|
|
20316
|
-
const deletions = JSON.parse(
|
|
20317
|
-
|
|
20780
|
+
if (!existsSync30(ROSTER_DELETIONS_PATH)) return [];
|
|
20781
|
+
const deletions = JSON.parse(readFileSync23(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
20782
|
+
writeFileSync17(ROSTER_DELETIONS_PATH, "[]");
|
|
20318
20783
|
return deletions;
|
|
20319
20784
|
} catch {
|
|
20320
20785
|
return [];
|
|
20321
20786
|
}
|
|
20322
20787
|
}
|
|
20323
20788
|
function buildRosterBlob(paths) {
|
|
20324
|
-
const rosterPath = paths?.rosterPath ??
|
|
20325
|
-
const identityDir = paths?.identityDir ??
|
|
20326
|
-
const configPath = paths?.configPath ??
|
|
20789
|
+
const rosterPath = paths?.rosterPath ?? path35.join(EXE_AI_DIR, "exe-employees.json");
|
|
20790
|
+
const identityDir = paths?.identityDir ?? path35.join(EXE_AI_DIR, "identity");
|
|
20791
|
+
const configPath = paths?.configPath ?? path35.join(EXE_AI_DIR, "config.json");
|
|
20327
20792
|
let roster = [];
|
|
20328
|
-
if (
|
|
20793
|
+
if (existsSync30(rosterPath)) {
|
|
20329
20794
|
try {
|
|
20330
|
-
roster = JSON.parse(
|
|
20795
|
+
roster = JSON.parse(readFileSync23(rosterPath, "utf-8"));
|
|
20331
20796
|
} catch {
|
|
20332
20797
|
}
|
|
20333
20798
|
}
|
|
20334
20799
|
const identities = {};
|
|
20335
|
-
if (
|
|
20800
|
+
if (existsSync30(identityDir)) {
|
|
20336
20801
|
for (const file of readdirSync11(identityDir).filter((f) => f.endsWith(".md"))) {
|
|
20337
20802
|
try {
|
|
20338
|
-
identities[file] =
|
|
20803
|
+
identities[file] = readFileSync23(path35.join(identityDir, file), "utf-8");
|
|
20339
20804
|
} catch {
|
|
20340
20805
|
}
|
|
20341
20806
|
}
|
|
20342
20807
|
}
|
|
20343
20808
|
let config2;
|
|
20344
|
-
if (
|
|
20809
|
+
if (existsSync30(configPath)) {
|
|
20345
20810
|
try {
|
|
20346
|
-
config2 = JSON.parse(
|
|
20811
|
+
config2 = JSON.parse(readFileSync23(configPath, "utf-8"));
|
|
20347
20812
|
} catch {
|
|
20348
20813
|
}
|
|
20349
20814
|
}
|
|
20350
20815
|
let agentConfig;
|
|
20351
|
-
const agentConfigPath =
|
|
20352
|
-
if (
|
|
20816
|
+
const agentConfigPath = path35.join(EXE_AI_DIR, "agent-config.json");
|
|
20817
|
+
if (existsSync30(agentConfigPath)) {
|
|
20353
20818
|
try {
|
|
20354
|
-
agentConfig = JSON.parse(
|
|
20819
|
+
agentConfig = JSON.parse(readFileSync23(agentConfigPath, "utf-8"));
|
|
20355
20820
|
} catch {
|
|
20356
20821
|
}
|
|
20357
20822
|
}
|
|
@@ -20427,24 +20892,24 @@ async function cloudPullRoster(config2) {
|
|
|
20427
20892
|
}
|
|
20428
20893
|
}
|
|
20429
20894
|
function mergeConfig(remoteConfig, configPath) {
|
|
20430
|
-
const cfgPath = configPath ??
|
|
20895
|
+
const cfgPath = configPath ?? path35.join(EXE_AI_DIR, "config.json");
|
|
20431
20896
|
let local = {};
|
|
20432
|
-
if (
|
|
20897
|
+
if (existsSync30(cfgPath)) {
|
|
20433
20898
|
try {
|
|
20434
|
-
local = JSON.parse(
|
|
20899
|
+
local = JSON.parse(readFileSync23(cfgPath, "utf-8"));
|
|
20435
20900
|
} catch {
|
|
20436
20901
|
}
|
|
20437
20902
|
}
|
|
20438
20903
|
const merged = { ...remoteConfig, ...local };
|
|
20439
|
-
const dir =
|
|
20904
|
+
const dir = path35.dirname(cfgPath);
|
|
20440
20905
|
ensurePrivateDirSync(dir);
|
|
20441
|
-
|
|
20906
|
+
writeFileSync17(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
20442
20907
|
enforcePrivateFileSync(cfgPath);
|
|
20443
20908
|
}
|
|
20444
20909
|
async function mergeRosterFromRemote(remote, paths) {
|
|
20445
20910
|
return withRosterLock(async () => {
|
|
20446
20911
|
const rosterPath = paths?.rosterPath ?? void 0;
|
|
20447
|
-
const identityDir = paths?.identityDir ??
|
|
20912
|
+
const identityDir = paths?.identityDir ?? path35.join(EXE_AI_DIR, "identity");
|
|
20448
20913
|
const localEmployees = await loadEmployees(rosterPath);
|
|
20449
20914
|
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
20450
20915
|
let added = 0;
|
|
@@ -20465,15 +20930,15 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
20465
20930
|
) ?? lookupKey;
|
|
20466
20931
|
const remoteIdentity = remote.identities[matchedKey];
|
|
20467
20932
|
if (remoteIdentity) {
|
|
20468
|
-
if (!
|
|
20469
|
-
const idPath =
|
|
20933
|
+
if (!existsSync30(identityDir)) mkdirSync15(identityDir, { recursive: true });
|
|
20934
|
+
const idPath = path35.join(identityDir, `${remoteEmp.name}.md`);
|
|
20470
20935
|
let localIdentity = null;
|
|
20471
20936
|
try {
|
|
20472
|
-
localIdentity =
|
|
20937
|
+
localIdentity = existsSync30(idPath) ? readFileSync23(idPath, "utf-8") : null;
|
|
20473
20938
|
} catch {
|
|
20474
20939
|
}
|
|
20475
20940
|
if (localIdentity !== remoteIdentity) {
|
|
20476
|
-
|
|
20941
|
+
writeFileSync17(idPath, remoteIdentity, "utf-8");
|
|
20477
20942
|
identitiesUpdated++;
|
|
20478
20943
|
}
|
|
20479
20944
|
}
|
|
@@ -20499,17 +20964,17 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
20499
20964
|
}
|
|
20500
20965
|
if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
|
|
20501
20966
|
try {
|
|
20502
|
-
const agentConfigPath =
|
|
20967
|
+
const agentConfigPath = path35.join(EXE_AI_DIR, "agent-config.json");
|
|
20503
20968
|
let local = {};
|
|
20504
|
-
if (
|
|
20969
|
+
if (existsSync30(agentConfigPath)) {
|
|
20505
20970
|
try {
|
|
20506
|
-
local = JSON.parse(
|
|
20971
|
+
local = JSON.parse(readFileSync23(agentConfigPath, "utf-8"));
|
|
20507
20972
|
} catch {
|
|
20508
20973
|
}
|
|
20509
20974
|
}
|
|
20510
20975
|
const merged = { ...remote.agentConfig, ...local };
|
|
20511
|
-
ensurePrivateDirSync(
|
|
20512
|
-
|
|
20976
|
+
ensurePrivateDirSync(path35.dirname(agentConfigPath));
|
|
20977
|
+
writeFileSync17(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
20513
20978
|
enforcePrivateFileSync(agentConfigPath);
|
|
20514
20979
|
} catch {
|
|
20515
20980
|
}
|
|
@@ -20995,9 +21460,136 @@ function registerCloudSync(server2) {
|
|
|
20995
21460
|
);
|
|
20996
21461
|
}
|
|
20997
21462
|
|
|
21463
|
+
// src/mcp/tools/orchestration-phase.ts
|
|
21464
|
+
import { z as z59 } from "zod";
|
|
21465
|
+
|
|
21466
|
+
// src/lib/orchestration-phase.ts
|
|
21467
|
+
init_config();
|
|
21468
|
+
var ORCHESTRATION_PHASES = [
|
|
21469
|
+
"phase_1_coo",
|
|
21470
|
+
"phase_2_executives",
|
|
21471
|
+
"phase_3_parallel_org"
|
|
21472
|
+
];
|
|
21473
|
+
var PHASE_INFO = {
|
|
21474
|
+
phase_1_coo: {
|
|
21475
|
+
phase: "phase_1_coo",
|
|
21476
|
+
shortLabel: "Phase 1 \u2014 COO mode",
|
|
21477
|
+
label: "Phase 1 \u2014 COO / Chief of Staff mode",
|
|
21478
|
+
focus: "building company context before delegation",
|
|
21479
|
+
nextSuggestion: "Unlock executives when technical, marketing, ops, legal, or finance work repeats."
|
|
21480
|
+
},
|
|
21481
|
+
phase_2_executives: {
|
|
21482
|
+
phase: "phase_2_executives",
|
|
21483
|
+
shortLabel: "Phase 2 \u2014 Executive bench",
|
|
21484
|
+
label: "Phase 2 \u2014 Executive bench",
|
|
21485
|
+
focus: "COO works with domain executives like CTO/CMO before specialist fan-out",
|
|
21486
|
+
nextSuggestion: "Unlock parallel execution when review gates, permissions, and workflows are ready."
|
|
21487
|
+
},
|
|
21488
|
+
phase_3_parallel_org: {
|
|
21489
|
+
phase: "phase_3_parallel_org",
|
|
21490
|
+
shortLabel: "Phase 3 \u2014 Parallel org",
|
|
21491
|
+
label: "Phase 3 \u2014 Parallel execution org",
|
|
21492
|
+
focus: "executives can delegate to specialists in parallel with review gates",
|
|
21493
|
+
nextSuggestion: "Keep review/CI/permission gates healthy; downgrade anytime if you want simpler COO-only mode."
|
|
21494
|
+
}
|
|
21495
|
+
};
|
|
21496
|
+
function normalizeOrchestrationPhase(input) {
|
|
21497
|
+
if (typeof input !== "string") return "phase_1_coo";
|
|
21498
|
+
const normalized = input.trim().toLowerCase().replace(/\s+/g, "_");
|
|
21499
|
+
if (["1", "phase1", "phase_1", "coo", "coo_mode", "chief_of_staff", "phase_1_coo"].includes(normalized)) {
|
|
21500
|
+
return "phase_1_coo";
|
|
21501
|
+
}
|
|
21502
|
+
if (["2", "phase2", "phase_2", "executives", "executive", "executive_bench", "phase_2_executives"].includes(normalized)) {
|
|
21503
|
+
return "phase_2_executives";
|
|
21504
|
+
}
|
|
21505
|
+
if (["3", "phase3", "phase_3", "parallel", "parallel_org", "parallel_execution", "phase_3_parallel_org"].includes(normalized)) {
|
|
21506
|
+
return "phase_3_parallel_org";
|
|
21507
|
+
}
|
|
21508
|
+
if (ORCHESTRATION_PHASES.includes(normalized)) return normalized;
|
|
21509
|
+
return "phase_1_coo";
|
|
21510
|
+
}
|
|
21511
|
+
function getOrchestrationPhaseInfo(phase) {
|
|
21512
|
+
return PHASE_INFO[normalizeOrchestrationPhase(phase)];
|
|
21513
|
+
}
|
|
21514
|
+
async function loadOrchestrationPhase() {
|
|
21515
|
+
const config2 = await loadConfig();
|
|
21516
|
+
return getOrchestrationPhaseInfo(config2.orchestration?.phase);
|
|
21517
|
+
}
|
|
21518
|
+
async function setOrchestrationPhase(phaseInput, setBy = "user") {
|
|
21519
|
+
const config2 = await loadConfig();
|
|
21520
|
+
const phase = normalizeOrchestrationPhase(phaseInput);
|
|
21521
|
+
config2.orchestration = {
|
|
21522
|
+
...config2.orchestration ?? {},
|
|
21523
|
+
phase,
|
|
21524
|
+
phaseSetAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21525
|
+
phaseSetBy: setBy
|
|
21526
|
+
};
|
|
21527
|
+
await saveConfig(config2);
|
|
21528
|
+
return getOrchestrationPhaseInfo(phase);
|
|
21529
|
+
}
|
|
21530
|
+
|
|
21531
|
+
// src/mcp/tools/orchestration-phase.ts
|
|
21532
|
+
function render(info, prefix) {
|
|
21533
|
+
return [
|
|
21534
|
+
prefix,
|
|
21535
|
+
`## ${info.label}`,
|
|
21536
|
+
"",
|
|
21537
|
+
`- **Focus:** ${info.focus}`,
|
|
21538
|
+
`- **Suggestion:** ${info.nextSuggestion}`,
|
|
21539
|
+
"",
|
|
21540
|
+
"This is guidance, not a blocker. The user can switch phases anytime. Changing phase never overwrites role titles, identities, memories, tasks, or custom org design."
|
|
21541
|
+
].filter(Boolean).join("\n");
|
|
21542
|
+
}
|
|
21543
|
+
function registerOrchestrationPhase(server2) {
|
|
21544
|
+
server2.registerTool(
|
|
21545
|
+
"orchestration_phase",
|
|
21546
|
+
{
|
|
21547
|
+
title: "Orchestration Phase",
|
|
21548
|
+
description: "View or change the customer-owned orchestration maturity phase. MCP parity for `exe-os org phase`, `exe-os org unlock executives`, and `exe-os org unlock parallel`. This is a recommendation layer, not a blocker; it never exposes recovery phrases or secrets.",
|
|
21549
|
+
inputSchema: {
|
|
21550
|
+
action: z59.enum(["status", "set", "unlock_executives", "unlock_parallel"]).default("status"),
|
|
21551
|
+
phase: z59.enum(["phase_1_coo", "phase_2_executives", "phase_3_parallel_org", "1", "2", "3"]).optional().describe("Phase to set when action='set'.")
|
|
21552
|
+
}
|
|
21553
|
+
},
|
|
21554
|
+
async ({ action = "status", phase }) => {
|
|
21555
|
+
try {
|
|
21556
|
+
if (action === "status") {
|
|
21557
|
+
const info2 = await loadOrchestrationPhase();
|
|
21558
|
+
return { content: [{ type: "text", text: render(info2) }] };
|
|
21559
|
+
}
|
|
21560
|
+
if (action === "unlock_executives") {
|
|
21561
|
+
const info2 = await setOrchestrationPhase("phase_2_executives", "mcp");
|
|
21562
|
+
return {
|
|
21563
|
+
content: [{ type: "text", text: render(info2, "Phase 2 enabled. Your COO can now lean on the executive bench when useful.") }]
|
|
21564
|
+
};
|
|
21565
|
+
}
|
|
21566
|
+
if (action === "unlock_parallel") {
|
|
21567
|
+
const info2 = await setOrchestrationPhase("phase_3_parallel_org", "mcp");
|
|
21568
|
+
return {
|
|
21569
|
+
content: [{ type: "text", text: render(info2, "Phase 3 enabled. Parallel execution is available with review/permission gates.") }]
|
|
21570
|
+
};
|
|
21571
|
+
}
|
|
21572
|
+
if (!phase) {
|
|
21573
|
+
return {
|
|
21574
|
+
content: [{ type: "text", text: "action='set' requires phase: 1, 2, 3, phase_1_coo, phase_2_executives, or phase_3_parallel_org." }],
|
|
21575
|
+
isError: true
|
|
21576
|
+
};
|
|
21577
|
+
}
|
|
21578
|
+
const info = await setOrchestrationPhase(phase, "mcp");
|
|
21579
|
+
return { content: [{ type: "text", text: render(info, "Updated orchestration phase.") }] };
|
|
21580
|
+
} catch (err) {
|
|
21581
|
+
return {
|
|
21582
|
+
content: [{ type: "text", text: `Failed to update orchestration phase: ${err instanceof Error ? err.message : String(err)}` }],
|
|
21583
|
+
isError: true
|
|
21584
|
+
};
|
|
21585
|
+
}
|
|
21586
|
+
}
|
|
21587
|
+
);
|
|
21588
|
+
}
|
|
21589
|
+
|
|
20998
21590
|
// src/mcp/tools/backup-vps.ts
|
|
20999
21591
|
init_keychain();
|
|
21000
|
-
import { z as
|
|
21592
|
+
import { z as z60 } from "zod";
|
|
21001
21593
|
|
|
21002
21594
|
// src/lib/vps-backup.ts
|
|
21003
21595
|
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
@@ -21322,43 +21914,43 @@ function registerBackupVps(server2) {
|
|
|
21322
21914
|
{
|
|
21323
21915
|
title: "VPS Backup",
|
|
21324
21916
|
description: "Run VPS Postgres backup/restore workflows and check status.",
|
|
21325
|
-
inputSchema:
|
|
21326
|
-
|
|
21327
|
-
action:
|
|
21328
|
-
databaseUrl:
|
|
21329
|
-
encryptionKeyB64:
|
|
21917
|
+
inputSchema: z60.discriminatedUnion("action", [
|
|
21918
|
+
z60.object({
|
|
21919
|
+
action: z60.literal("backup"),
|
|
21920
|
+
databaseUrl: z60.string().min(1).describe("Postgres DATABASE_URL to dump from"),
|
|
21921
|
+
encryptionKeyB64: z60.string().min(1).max(4096).optional().describe(
|
|
21330
21922
|
"Base64 AES-256 key (defaults to local master key if omitted)"
|
|
21331
21923
|
),
|
|
21332
|
-
r2Bucket:
|
|
21333
|
-
r2Endpoint:
|
|
21334
|
-
r2AccessKeyId:
|
|
21335
|
-
r2SecretAccessKey:
|
|
21924
|
+
r2Bucket: z60.string().min(1).describe("R2 bucket name"),
|
|
21925
|
+
r2Endpoint: z60.string().min(1).describe("R2 endpoint URL"),
|
|
21926
|
+
r2AccessKeyId: z60.string().min(1).describe("R2 access key ID"),
|
|
21927
|
+
r2SecretAccessKey: z60.string().min(1).describe("R2 secret access key")
|
|
21336
21928
|
}),
|
|
21337
|
-
|
|
21338
|
-
action:
|
|
21339
|
-
databaseUrl:
|
|
21340
|
-
backupKey:
|
|
21341
|
-
encryptionKeyB64:
|
|
21929
|
+
z60.object({
|
|
21930
|
+
action: z60.literal("restore"),
|
|
21931
|
+
databaseUrl: z60.string().min(1).describe("Target Postgres DATABASE_URL for restore"),
|
|
21932
|
+
backupKey: z60.string().min(1).describe("R2 object key to restore from"),
|
|
21933
|
+
encryptionKeyB64: z60.string().min(1).max(4096).optional().describe(
|
|
21342
21934
|
"Base64 AES-256 key (defaults to local master key if omitted)"
|
|
21343
21935
|
),
|
|
21344
|
-
r2Bucket:
|
|
21345
|
-
r2Endpoint:
|
|
21346
|
-
r2AccessKeyId:
|
|
21347
|
-
r2SecretAccessKey:
|
|
21936
|
+
r2Bucket: z60.string().min(1).describe("R2 bucket name"),
|
|
21937
|
+
r2Endpoint: z60.string().min(1).describe("R2 endpoint URL"),
|
|
21938
|
+
r2AccessKeyId: z60.string().min(1).describe("R2 access key ID"),
|
|
21939
|
+
r2SecretAccessKey: z60.string().min(1).describe("R2 secret access key")
|
|
21348
21940
|
}),
|
|
21349
|
-
|
|
21350
|
-
action:
|
|
21351
|
-
r2Bucket:
|
|
21352
|
-
r2Endpoint:
|
|
21353
|
-
r2AccessKeyId:
|
|
21354
|
-
r2SecretAccessKey:
|
|
21941
|
+
z60.object({
|
|
21942
|
+
action: z60.literal("list"),
|
|
21943
|
+
r2Bucket: z60.string().min(1).describe("R2 bucket name"),
|
|
21944
|
+
r2Endpoint: z60.string().min(1).describe("R2 endpoint URL"),
|
|
21945
|
+
r2AccessKeyId: z60.string().min(1).describe("R2 access key ID"),
|
|
21946
|
+
r2SecretAccessKey: z60.string().min(1).describe("R2 secret access key")
|
|
21355
21947
|
}),
|
|
21356
|
-
|
|
21357
|
-
action:
|
|
21358
|
-
r2Bucket:
|
|
21359
|
-
r2Endpoint:
|
|
21360
|
-
r2AccessKeyId:
|
|
21361
|
-
r2SecretAccessKey:
|
|
21948
|
+
z60.object({
|
|
21949
|
+
action: z60.literal("health"),
|
|
21950
|
+
r2Bucket: z60.string().min(1).describe("R2 bucket name"),
|
|
21951
|
+
r2Endpoint: z60.string().min(1).describe("R2 endpoint URL"),
|
|
21952
|
+
r2AccessKeyId: z60.string().min(1).describe("R2 access key ID"),
|
|
21953
|
+
r2SecretAccessKey: z60.string().min(1).describe("R2 secret access key")
|
|
21362
21954
|
})
|
|
21363
21955
|
])
|
|
21364
21956
|
},
|
|
@@ -21496,11 +22088,11 @@ async function resolveEncryptionKey(providedB64) {
|
|
|
21496
22088
|
}
|
|
21497
22089
|
|
|
21498
22090
|
// src/mcp/tools/deploy-client.ts
|
|
21499
|
-
import { z as
|
|
22091
|
+
import { z as z61 } from "zod";
|
|
21500
22092
|
import { execFile } from "child_process";
|
|
21501
22093
|
import { promisify } from "util";
|
|
21502
|
-
import
|
|
21503
|
-
import { existsSync as
|
|
22094
|
+
import path36 from "path";
|
|
22095
|
+
import { existsSync as existsSync31 } from "fs";
|
|
21504
22096
|
|
|
21505
22097
|
// src/lib/hostinger-api.ts
|
|
21506
22098
|
var DEFAULT_BASE_URL = "https://developers.hostinger.com/api/vps/v1";
|
|
@@ -21548,9 +22140,9 @@ var HostingerApiClient = class {
|
|
|
21548
22140
|
}
|
|
21549
22141
|
this.lastRequestTime = Date.now();
|
|
21550
22142
|
}
|
|
21551
|
-
async request(method,
|
|
22143
|
+
async request(method, path49, body) {
|
|
21552
22144
|
await this.rateLimit();
|
|
21553
|
-
const url = `${this.baseUrl}${
|
|
22145
|
+
const url = `${this.baseUrl}${path49}`;
|
|
21554
22146
|
const headers = {
|
|
21555
22147
|
Authorization: `Bearer ${this.apiKey}`,
|
|
21556
22148
|
"Content-Type": "application/json",
|
|
@@ -21623,8 +22215,8 @@ async function requestCloudflare(cfApiToken, zoneId, options) {
|
|
|
21623
22215
|
}
|
|
21624
22216
|
return envelope.result;
|
|
21625
22217
|
}
|
|
21626
|
-
function buildUrl(zoneId,
|
|
21627
|
-
const normalizedPath =
|
|
22218
|
+
function buildUrl(zoneId, path49 = "/dns_records", query) {
|
|
22219
|
+
const normalizedPath = path49.startsWith("/") ? path49 : `/${path49}`;
|
|
21628
22220
|
const url = new URL(
|
|
21629
22221
|
`${CLOUDFLARE_API_BASE_URL}/zones/${zoneId}${normalizedPath}`
|
|
21630
22222
|
);
|
|
@@ -21764,12 +22356,12 @@ function registerDeployClient(server2) {
|
|
|
21764
22356
|
title: "Deploy Client",
|
|
21765
22357
|
description: "Provision a Hostinger VPS and deploy exe-os for a client. Creates VPS, waits for ready state, runs Ansible playbook, verifies health.",
|
|
21766
22358
|
inputSchema: {
|
|
21767
|
-
client_name:
|
|
21768
|
-
domain:
|
|
21769
|
-
region:
|
|
21770
|
-
plan:
|
|
21771
|
-
ssl_email:
|
|
21772
|
-
user_id:
|
|
22359
|
+
client_name: z61.string().min(1).describe("Client name (used for hostname and identification)"),
|
|
22360
|
+
domain: z61.string().min(1).describe("Domain name for the deployment (e.g., client.exe.ai)"),
|
|
22361
|
+
region: z61.string().default("jakarta").describe("VPS region (default: jakarta)"),
|
|
22362
|
+
plan: z61.string().default("kvm-2").describe("Hostinger VPS plan (default: kvm-2)"),
|
|
22363
|
+
ssl_email: z61.string().email().describe("Email for Let's Encrypt SSL certificate"),
|
|
22364
|
+
user_id: z61.string().min(1).describe("User/customer ID for inventory tracking")
|
|
21773
22365
|
}
|
|
21774
22366
|
},
|
|
21775
22367
|
async ({ client_name, domain, region, plan, ssl_email, user_id }) => {
|
|
@@ -21837,12 +22429,12 @@ async function waitForReady(client, vpsId) {
|
|
|
21837
22429
|
}
|
|
21838
22430
|
async function runAnsiblePlaybook(vpsIp, domain, sslEmail, clientName) {
|
|
21839
22431
|
const safeClientName = clientName.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
21840
|
-
const playbookDir =
|
|
21841
|
-
const playbookPath =
|
|
21842
|
-
const inventoryPath =
|
|
21843
|
-
const clientVarsPath =
|
|
21844
|
-
const varsDir =
|
|
21845
|
-
if (!
|
|
22432
|
+
const playbookDir = path36.resolve(process.cwd(), "infrastructure", "ansible");
|
|
22433
|
+
const playbookPath = path36.join(playbookDir, "deploy.yml");
|
|
22434
|
+
const inventoryPath = path36.join(playbookDir, "inventory", "hosts.yml");
|
|
22435
|
+
const clientVarsPath = path36.join(playbookDir, "vars", `${safeClientName}.yml`);
|
|
22436
|
+
const varsDir = path36.join(playbookDir, "vars");
|
|
22437
|
+
if (!path36.resolve(clientVarsPath).startsWith(path36.resolve(varsDir))) {
|
|
21846
22438
|
throw new Error(`Invalid client name for vars path: ${clientName}`);
|
|
21847
22439
|
}
|
|
21848
22440
|
const args = [
|
|
@@ -21858,7 +22450,7 @@ async function runAnsiblePlaybook(vpsIp, domain, sslEmail, clientName) {
|
|
|
21858
22450
|
"-e",
|
|
21859
22451
|
`client_name=${safeClientName}`
|
|
21860
22452
|
];
|
|
21861
|
-
if (
|
|
22453
|
+
if (existsSync31(clientVarsPath)) {
|
|
21862
22454
|
args.push("-e", `@${clientVarsPath}`);
|
|
21863
22455
|
}
|
|
21864
22456
|
try {
|
|
@@ -21931,7 +22523,7 @@ function buildInventoryRecord(params) {
|
|
|
21931
22523
|
|
|
21932
22524
|
// src/mcp/tools/get-license-status.ts
|
|
21933
22525
|
init_license();
|
|
21934
|
-
import { z as
|
|
22526
|
+
import { z as z62 } from "zod";
|
|
21935
22527
|
var FEATURES = [
|
|
21936
22528
|
"cloud_sync",
|
|
21937
22529
|
"external_agents",
|
|
@@ -21945,7 +22537,7 @@ function registerGetLicenseStatus(server2) {
|
|
|
21945
22537
|
title: "Get License Status",
|
|
21946
22538
|
description: "Get current license status: plan, validity, feature gates, limits, and expiry.",
|
|
21947
22539
|
inputSchema: {
|
|
21948
|
-
_dummy:
|
|
22540
|
+
_dummy: z62.string().optional().describe("Unused \u2014 no input required")
|
|
21949
22541
|
}
|
|
21950
22542
|
},
|
|
21951
22543
|
async () => {
|
|
@@ -21999,11 +22591,11 @@ function registerGetLicenseStatus(server2) {
|
|
|
21999
22591
|
// src/mcp/tools/create-license.ts
|
|
22000
22592
|
init_license();
|
|
22001
22593
|
import os15 from "os";
|
|
22002
|
-
import
|
|
22594
|
+
import path37 from "path";
|
|
22003
22595
|
import { randomBytes as randomBytes2, randomUUID as randomUUID6 } from "crypto";
|
|
22004
22596
|
import { createRequire as createRequire3 } from "module";
|
|
22005
22597
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
22006
|
-
import { z as
|
|
22598
|
+
import { z as z63 } from "zod";
|
|
22007
22599
|
var prismaPromise = null;
|
|
22008
22600
|
function loadPrisma() {
|
|
22009
22601
|
if (!prismaPromise) {
|
|
@@ -22015,8 +22607,8 @@ function loadPrisma() {
|
|
|
22015
22607
|
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
22016
22608
|
return new Ctor2();
|
|
22017
22609
|
}
|
|
22018
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
22019
|
-
const req = createRequire3(
|
|
22610
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path37.join(os15.homedir(), "exe-db");
|
|
22611
|
+
const req = createRequire3(path37.join(exeDbRoot, "package.json"));
|
|
22020
22612
|
const entry = req.resolve("@prisma/client");
|
|
22021
22613
|
const mod = await import(pathToFileURL3(entry).href);
|
|
22022
22614
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -22036,10 +22628,10 @@ function registerCreateLicense(server2) {
|
|
|
22036
22628
|
title: "Create License",
|
|
22037
22629
|
description: "Generate an exe_sk_* license key for a user. Stores in billing.licenses. Returns the key to give to the customer.",
|
|
22038
22630
|
inputSchema: {
|
|
22039
|
-
email:
|
|
22040
|
-
name:
|
|
22041
|
-
plan:
|
|
22042
|
-
expires_in_days:
|
|
22631
|
+
email: z63.string().email().describe("Customer email address"),
|
|
22632
|
+
name: z63.string().optional().describe("Customer name"),
|
|
22633
|
+
plan: z63.enum(["free", "pro", "team", "agency", "enterprise"]).default("pro").describe("License plan tier"),
|
|
22634
|
+
expires_in_days: z63.number().int().positive().default(365).describe("Days until expiration (default 365)")
|
|
22043
22635
|
}
|
|
22044
22636
|
},
|
|
22045
22637
|
async ({ email, name, plan, expires_in_days }) => {
|
|
@@ -22091,10 +22683,10 @@ Give this key to the customer. They paste it during \`exe-os setup\`.`);
|
|
|
22091
22683
|
|
|
22092
22684
|
// src/mcp/tools/list-licenses.ts
|
|
22093
22685
|
import os16 from "os";
|
|
22094
|
-
import
|
|
22686
|
+
import path38 from "path";
|
|
22095
22687
|
import { createRequire as createRequire4 } from "module";
|
|
22096
22688
|
import { pathToFileURL as pathToFileURL4 } from "url";
|
|
22097
|
-
import { z as
|
|
22689
|
+
import { z as z64 } from "zod";
|
|
22098
22690
|
var prismaPromise2 = null;
|
|
22099
22691
|
function loadPrisma2() {
|
|
22100
22692
|
if (!prismaPromise2) {
|
|
@@ -22106,8 +22698,8 @@ function loadPrisma2() {
|
|
|
22106
22698
|
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
22107
22699
|
return new Ctor2();
|
|
22108
22700
|
}
|
|
22109
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
22110
|
-
const req = createRequire4(
|
|
22701
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path38.join(os16.homedir(), "exe-db");
|
|
22702
|
+
const req = createRequire4(path38.join(exeDbRoot, "package.json"));
|
|
22111
22703
|
const entry = req.resolve("@prisma/client");
|
|
22112
22704
|
const mod = await import(pathToFileURL4(entry).href);
|
|
22113
22705
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -22124,7 +22716,7 @@ function registerListLicenses(server2) {
|
|
|
22124
22716
|
title: "List Licenses",
|
|
22125
22717
|
description: "List all issued licenses with status (active/expired/revoked). Optionally filter by plan.",
|
|
22126
22718
|
inputSchema: {
|
|
22127
|
-
plan:
|
|
22719
|
+
plan: z64.enum(["free", "pro", "team", "agency", "enterprise"]).optional().describe("Filter by plan tier (omit for all)")
|
|
22128
22720
|
}
|
|
22129
22721
|
},
|
|
22130
22722
|
async ({ plan }) => {
|
|
@@ -22175,7 +22767,7 @@ function registerListLicenses(server2) {
|
|
|
22175
22767
|
|
|
22176
22768
|
// src/mcp/tools/activate-license.ts
|
|
22177
22769
|
init_license();
|
|
22178
|
-
import { z as
|
|
22770
|
+
import { z as z65 } from "zod";
|
|
22179
22771
|
function registerActivateLicense(server2) {
|
|
22180
22772
|
server2.registerTool(
|
|
22181
22773
|
"activate_license",
|
|
@@ -22183,7 +22775,7 @@ function registerActivateLicense(server2) {
|
|
|
22183
22775
|
title: "Activate License",
|
|
22184
22776
|
description: "Activate an exe_sk_* license key on this device. Writes to ~/.exe-os/license.key, validates against Postgres, and caches the result.",
|
|
22185
22777
|
inputSchema: {
|
|
22186
|
-
key:
|
|
22778
|
+
key: z65.string().startsWith("exe_sk_").describe("License key (exe_sk_*)")
|
|
22187
22779
|
}
|
|
22188
22780
|
},
|
|
22189
22781
|
async ({ key }) => {
|
|
@@ -22229,18 +22821,18 @@ Key saved to ~/.exe-os/license.key. Device ID: ${deviceId}`);
|
|
|
22229
22821
|
}
|
|
22230
22822
|
|
|
22231
22823
|
// src/mcp/tools/create-trigger.ts
|
|
22232
|
-
import { z as
|
|
22824
|
+
import { z as z66 } from "zod";
|
|
22233
22825
|
|
|
22234
22826
|
// src/automation/trigger-engine.ts
|
|
22235
|
-
import { readFileSync as
|
|
22827
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync18, existsSync as existsSync32, mkdirSync as mkdirSync16 } from "fs";
|
|
22236
22828
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
22237
|
-
import
|
|
22829
|
+
import path39 from "path";
|
|
22238
22830
|
import os17 from "os";
|
|
22239
|
-
var TRIGGERS_PATH =
|
|
22831
|
+
var TRIGGERS_PATH = path39.join(os17.homedir(), ".exe-os", "triggers.json");
|
|
22240
22832
|
function loadTriggers(project) {
|
|
22241
|
-
if (!
|
|
22833
|
+
if (!existsSync32(TRIGGERS_PATH)) return [];
|
|
22242
22834
|
try {
|
|
22243
|
-
const raw =
|
|
22835
|
+
const raw = readFileSync24(TRIGGERS_PATH, "utf-8");
|
|
22244
22836
|
const all = JSON.parse(raw);
|
|
22245
22837
|
if (!Array.isArray(all)) return [];
|
|
22246
22838
|
if (project) {
|
|
@@ -22252,9 +22844,9 @@ function loadTriggers(project) {
|
|
|
22252
22844
|
}
|
|
22253
22845
|
}
|
|
22254
22846
|
function saveTriggers(triggers) {
|
|
22255
|
-
const dir =
|
|
22256
|
-
if (!
|
|
22257
|
-
|
|
22847
|
+
const dir = path39.dirname(TRIGGERS_PATH);
|
|
22848
|
+
if (!existsSync32(dir)) mkdirSync16(dir, { recursive: true });
|
|
22849
|
+
writeFileSync18(TRIGGERS_PATH, JSON.stringify(triggers, null, 2), "utf-8");
|
|
22258
22850
|
}
|
|
22259
22851
|
function createNewTrigger(input) {
|
|
22260
22852
|
const triggers = loadTriggers();
|
|
@@ -22410,14 +23002,14 @@ function addToCrontab(id, cron, prompt, projectDir) {
|
|
|
22410
23002
|
}
|
|
22411
23003
|
|
|
22412
23004
|
// src/mcp/tools/create-trigger.ts
|
|
22413
|
-
var conditionSchema =
|
|
22414
|
-
field:
|
|
22415
|
-
op:
|
|
22416
|
-
value:
|
|
23005
|
+
var conditionSchema = z66.object({
|
|
23006
|
+
field: z66.string().describe("Dot-path field to evaluate, e.g., 'stage' or 'amount'"),
|
|
23007
|
+
op: z66.enum(["eq", "neq", "gt", "lt", "gte", "lte", "contains", "not_contains"]).describe("Comparison operator"),
|
|
23008
|
+
value: z66.string().or(z66.number()).or(z66.boolean()).describe("Value to compare against")
|
|
22417
23009
|
});
|
|
22418
|
-
var actionSchema =
|
|
22419
|
-
type:
|
|
22420
|
-
params:
|
|
23010
|
+
var actionSchema = z66.object({
|
|
23011
|
+
type: z66.enum(["send_whatsapp", "send_message", "create_task", "mcp_tool"]).describe("Action type to execute"),
|
|
23012
|
+
params: z66.record(z66.string(), z66.string()).describe(
|
|
22421
23013
|
"Action parameters. Supports {{record.field}} templates for dynamic values."
|
|
22422
23014
|
)
|
|
22423
23015
|
});
|
|
@@ -22428,18 +23020,18 @@ function registerCreateTrigger(server2) {
|
|
|
22428
23020
|
title: "Create Trigger",
|
|
22429
23021
|
description: "Create a CRM event trigger or scheduled automation. When matching events occur (e.g., Deal.updated with stage=won), configured actions fire automatically (send_whatsapp, create_task, etc.).",
|
|
22430
23022
|
inputSchema: {
|
|
22431
|
-
name:
|
|
22432
|
-
event:
|
|
23023
|
+
name: z66.string().describe("Human-readable trigger name"),
|
|
23024
|
+
event: z66.string().describe(
|
|
22433
23025
|
'CRM event to match, e.g., "Deal.updated", "Order.created", "*" for all'
|
|
22434
23026
|
),
|
|
22435
|
-
conditions:
|
|
22436
|
-
actions:
|
|
22437
|
-
project:
|
|
22438
|
-
enabled:
|
|
22439
|
-
schedule:
|
|
23027
|
+
conditions: z66.array(conditionSchema).default([]).describe("Conditions that must all match (AND logic)"),
|
|
23028
|
+
actions: z66.array(actionSchema).min(1).describe("Actions to execute when trigger fires"),
|
|
23029
|
+
project: z66.string().optional().describe("Scope trigger to a specific project"),
|
|
23030
|
+
enabled: z66.boolean().default(true).describe("Whether trigger is active"),
|
|
23031
|
+
schedule: z66.string().optional().describe(
|
|
22440
23032
|
'Cron schedule for time-based triggers, e.g., "0 9 * * *" or "Monday 9am"'
|
|
22441
23033
|
),
|
|
22442
|
-
query:
|
|
23034
|
+
query: z66.string().optional().describe(
|
|
22443
23035
|
"CRM GraphQL query to run on schedule (required if schedule is set)"
|
|
22444
23036
|
)
|
|
22445
23037
|
}
|
|
@@ -22512,7 +23104,7 @@ Enabled: ${trigger.enabled}` + scheduleInfo;
|
|
|
22512
23104
|
}
|
|
22513
23105
|
|
|
22514
23106
|
// src/mcp/tools/list-triggers.ts
|
|
22515
|
-
import { z as
|
|
23107
|
+
import { z as z67 } from "zod";
|
|
22516
23108
|
function registerListTriggers(server2) {
|
|
22517
23109
|
server2.registerTool(
|
|
22518
23110
|
"list_triggers",
|
|
@@ -22520,7 +23112,7 @@ function registerListTriggers(server2) {
|
|
|
22520
23112
|
title: "List Triggers",
|
|
22521
23113
|
description: "List configured CRM event triggers and scheduled automations.",
|
|
22522
23114
|
inputSchema: {
|
|
22523
|
-
project:
|
|
23115
|
+
project: z67.string().optional().describe("Filter triggers by project name")
|
|
22524
23116
|
}
|
|
22525
23117
|
},
|
|
22526
23118
|
async ({ project }) => {
|
|
@@ -22555,51 +23147,51 @@ function registerListTriggers(server2) {
|
|
|
22555
23147
|
}
|
|
22556
23148
|
|
|
22557
23149
|
// src/mcp/tools/apply-starter-pack.ts
|
|
22558
|
-
import { z as
|
|
23150
|
+
import { z as z68 } from "zod";
|
|
22559
23151
|
|
|
22560
23152
|
// src/automation/starter-packs/index.ts
|
|
22561
|
-
import { readFileSync as
|
|
22562
|
-
import
|
|
23153
|
+
import { readFileSync as readFileSync25, readdirSync as readdirSync12, existsSync as existsSync33 } from "fs";
|
|
23154
|
+
import path40 from "path";
|
|
22563
23155
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
22564
|
-
var __dirname =
|
|
23156
|
+
var __dirname = path40.dirname(fileURLToPath4(import.meta.url));
|
|
22565
23157
|
function listPacks() {
|
|
22566
|
-
const packsDir =
|
|
22567
|
-
if (!
|
|
23158
|
+
const packsDir = path40.join(__dirname, ".");
|
|
23159
|
+
if (!existsSync33(packsDir)) return [];
|
|
22568
23160
|
return readdirSync12(packsDir, { withFileTypes: true }).filter(
|
|
22569
|
-
(d) => d.isDirectory() &&
|
|
23161
|
+
(d) => d.isDirectory() && existsSync33(path40.join(packsDir, d.name, "custom-objects.json"))
|
|
22570
23162
|
).map((d) => d.name);
|
|
22571
23163
|
}
|
|
22572
23164
|
function loadPack(industry) {
|
|
22573
|
-
const packDir =
|
|
22574
|
-
const objectsPath =
|
|
22575
|
-
const triggersPath =
|
|
22576
|
-
const wikiDir =
|
|
22577
|
-
const manifestPath =
|
|
22578
|
-
const identityContextPath =
|
|
22579
|
-
if (!
|
|
23165
|
+
const packDir = path40.join(__dirname, industry);
|
|
23166
|
+
const objectsPath = path40.join(packDir, "custom-objects.json");
|
|
23167
|
+
const triggersPath = path40.join(packDir, "triggers.json");
|
|
23168
|
+
const wikiDir = path40.join(packDir, "wiki-seeds");
|
|
23169
|
+
const manifestPath = path40.join(packDir, "pack.json");
|
|
23170
|
+
const identityContextPath = path40.join(packDir, "identity-context.md");
|
|
23171
|
+
if (!existsSync33(objectsPath)) return null;
|
|
22580
23172
|
let customObjects = [];
|
|
22581
23173
|
try {
|
|
22582
23174
|
customObjects = JSON.parse(
|
|
22583
|
-
|
|
23175
|
+
readFileSync25(objectsPath, "utf-8")
|
|
22584
23176
|
);
|
|
22585
23177
|
} catch {
|
|
22586
23178
|
customObjects = [];
|
|
22587
23179
|
}
|
|
22588
23180
|
let triggers = [];
|
|
22589
|
-
if (
|
|
23181
|
+
if (existsSync33(triggersPath)) {
|
|
22590
23182
|
try {
|
|
22591
23183
|
triggers = JSON.parse(
|
|
22592
|
-
|
|
23184
|
+
readFileSync25(triggersPath, "utf-8")
|
|
22593
23185
|
);
|
|
22594
23186
|
} catch {
|
|
22595
23187
|
triggers = [];
|
|
22596
23188
|
}
|
|
22597
23189
|
}
|
|
22598
23190
|
const wikiSeeds = [];
|
|
22599
|
-
if (
|
|
23191
|
+
if (existsSync33(wikiDir)) {
|
|
22600
23192
|
const files = readdirSync12(wikiDir).filter((f) => f.endsWith(".md"));
|
|
22601
23193
|
for (const file of files) {
|
|
22602
|
-
const content =
|
|
23194
|
+
const content = readFileSync25(path40.join(wikiDir, file), "utf-8");
|
|
22603
23195
|
const titleMatch = content.match(/^#\s+(.+)/m);
|
|
22604
23196
|
wikiSeeds.push({
|
|
22605
23197
|
filename: file,
|
|
@@ -22609,17 +23201,17 @@ function loadPack(industry) {
|
|
|
22609
23201
|
}
|
|
22610
23202
|
}
|
|
22611
23203
|
let manifest = {};
|
|
22612
|
-
if (
|
|
23204
|
+
if (existsSync33(manifestPath)) {
|
|
22613
23205
|
try {
|
|
22614
|
-
manifest = JSON.parse(
|
|
23206
|
+
manifest = JSON.parse(readFileSync25(manifestPath, "utf-8"));
|
|
22615
23207
|
} catch {
|
|
22616
23208
|
manifest = {};
|
|
22617
23209
|
}
|
|
22618
23210
|
}
|
|
22619
23211
|
let identityContext = null;
|
|
22620
|
-
if (
|
|
23212
|
+
if (existsSync33(identityContextPath)) {
|
|
22621
23213
|
try {
|
|
22622
|
-
identityContext =
|
|
23214
|
+
identityContext = readFileSync25(identityContextPath, "utf-8");
|
|
22623
23215
|
} catch {
|
|
22624
23216
|
identityContext = null;
|
|
22625
23217
|
}
|
|
@@ -22676,8 +23268,8 @@ function applyPack(industry, project) {
|
|
|
22676
23268
|
|
|
22677
23269
|
// src/lib/client-coo.ts
|
|
22678
23270
|
init_config();
|
|
22679
|
-
import { existsSync as
|
|
22680
|
-
import
|
|
23271
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync17, writeFileSync as writeFileSync19 } from "fs";
|
|
23272
|
+
import path41 from "path";
|
|
22681
23273
|
|
|
22682
23274
|
// src/lib/employee-templates.ts
|
|
22683
23275
|
init_global_procedures();
|
|
@@ -22817,18 +23409,18 @@ var ClientCOOClobberError = class extends Error {
|
|
|
22817
23409
|
var COO_ROLE = "Chief Operating Officer";
|
|
22818
23410
|
var FEEDBACK_BEHAVIOR_CONTENT = "Tag exe-os issues with needs_improvement \u2014 this is the feedback loop that surfaces bugs, gaps, and friction to the founder each Monday.";
|
|
22819
23411
|
async function provisionClientCOO(vars, opts = {}) {
|
|
22820
|
-
const identityDir = opts.identityDir ??
|
|
23412
|
+
const identityDir = opts.identityDir ?? path41.join(EXE_AI_DIR, "identity");
|
|
22821
23413
|
const rosterPath = opts.employeesPath ?? EMPLOYEES_PATH;
|
|
22822
23414
|
const storeFeedbackBehavior = opts.storeFeedbackBehavior ?? true;
|
|
22823
|
-
const identityPath2 =
|
|
22824
|
-
if (
|
|
23415
|
+
const identityPath2 = path41.join(identityDir, `${vars.agent_name}.md`);
|
|
23416
|
+
if (existsSync34(identityPath2)) {
|
|
22825
23417
|
throw new ClientCOOClobberError(vars.agent_name, identityPath2);
|
|
22826
23418
|
}
|
|
22827
23419
|
const body = renderClientCOOTemplate(vars);
|
|
22828
|
-
if (!
|
|
22829
|
-
|
|
23420
|
+
if (!existsSync34(identityDir)) {
|
|
23421
|
+
mkdirSync17(identityDir, { recursive: true });
|
|
22830
23422
|
}
|
|
22831
|
-
|
|
23423
|
+
writeFileSync19(identityPath2, body, "utf-8");
|
|
22832
23424
|
const employees = await loadEmployees(rosterPath);
|
|
22833
23425
|
const existing = employees.find((e) => e.name === vars.agent_name);
|
|
22834
23426
|
let addedToRoster = false;
|
|
@@ -22864,17 +23456,17 @@ function registerApplyStarterPack(server2) {
|
|
|
22864
23456
|
title: "Apply Starter Pack",
|
|
22865
23457
|
description: "Apply an industry starter pack to a project. Sets up CRM custom objects, pre-wired automation triggers, and wiki seed content. When the pack creates a Client COO (e.g. distribution) and agent_name, company_name, founder_name are all provided, also provisions the COO identity, roster entry, and feedback-loop behavior. Available packs: distribution. More coming.",
|
|
22866
23458
|
inputSchema: {
|
|
22867
|
-
industry:
|
|
23459
|
+
industry: z68.string().describe(
|
|
22868
23460
|
'Industry pack to apply (e.g., "distribution"). Use without args to list available packs.'
|
|
22869
23461
|
),
|
|
22870
|
-
project:
|
|
22871
|
-
agent_name:
|
|
23462
|
+
project: z68.string().describe("Project name to scope the triggers to"),
|
|
23463
|
+
agent_name: z68.string().optional().describe(
|
|
22872
23464
|
"Optional. Lowercase alphanumeric name for the Client COO agent. Required (alongside company_name and founder_name) to provision a COO."
|
|
22873
23465
|
),
|
|
22874
|
-
company_name:
|
|
23466
|
+
company_name: z68.string().optional().describe(
|
|
22875
23467
|
"Optional. The client company the COO serves. Required to provision a COO."
|
|
22876
23468
|
),
|
|
22877
|
-
founder_name:
|
|
23469
|
+
founder_name: z68.string().optional().describe(
|
|
22878
23470
|
"Optional. The founder the COO reports to. Required to provision a COO."
|
|
22879
23471
|
)
|
|
22880
23472
|
}
|
|
@@ -23019,19 +23611,19 @@ ${err.message}`
|
|
|
23019
23611
|
}
|
|
23020
23612
|
|
|
23021
23613
|
// src/mcp/tools/load-skill.ts
|
|
23022
|
-
import { z as
|
|
23023
|
-
import { readFileSync as
|
|
23024
|
-
import
|
|
23614
|
+
import { z as z69 } from "zod";
|
|
23615
|
+
import { readFileSync as readFileSync26, readdirSync as readdirSync13, statSync as statSync6 } from "fs";
|
|
23616
|
+
import path42 from "path";
|
|
23025
23617
|
import { homedir as homedir7 } from "os";
|
|
23026
|
-
var SKILLS_DIR =
|
|
23618
|
+
var SKILLS_DIR = path42.join(homedir7(), ".claude", "skills");
|
|
23027
23619
|
function listAvailableSkills() {
|
|
23028
23620
|
try {
|
|
23029
23621
|
const entries = readdirSync13(SKILLS_DIR);
|
|
23030
23622
|
return entries.filter((entry) => {
|
|
23031
23623
|
try {
|
|
23032
|
-
const entryPath =
|
|
23624
|
+
const entryPath = path42.join(SKILLS_DIR, entry);
|
|
23033
23625
|
if (!statSync6(entryPath).isDirectory()) return false;
|
|
23034
|
-
const skillFile =
|
|
23626
|
+
const skillFile = path42.join(entryPath, "SKILL.md");
|
|
23035
23627
|
statSync6(skillFile);
|
|
23036
23628
|
return true;
|
|
23037
23629
|
} catch {
|
|
@@ -23049,7 +23641,7 @@ function registerLoadSkill(server2) {
|
|
|
23049
23641
|
title: "Load Skill",
|
|
23050
23642
|
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.",
|
|
23051
23643
|
inputSchema: {
|
|
23052
|
-
skill_name:
|
|
23644
|
+
skill_name: z69.string().describe(
|
|
23053
23645
|
"Skill to load (e.g. 'seo', 'code-reviewer', 'frontend-design'). Pass 'list' to see all available skills."
|
|
23054
23646
|
)
|
|
23055
23647
|
}
|
|
@@ -23074,10 +23666,10 @@ ${skills.map((s) => `- ${s}`).join("\n")}`
|
|
|
23074
23666
|
}]
|
|
23075
23667
|
};
|
|
23076
23668
|
}
|
|
23077
|
-
const sanitized =
|
|
23078
|
-
const skillFile =
|
|
23669
|
+
const sanitized = path42.basename(skill_name);
|
|
23670
|
+
const skillFile = path42.join(SKILLS_DIR, sanitized, "SKILL.md");
|
|
23079
23671
|
try {
|
|
23080
|
-
const content =
|
|
23672
|
+
const content = readFileSync26(skillFile, "utf-8");
|
|
23081
23673
|
return {
|
|
23082
23674
|
content: [{
|
|
23083
23675
|
type: "text",
|
|
@@ -23105,18 +23697,18 @@ ${available.map((s) => `- ${s}`).join("\n")}` : "\n\nNo skills found in ~/.claud
|
|
|
23105
23697
|
|
|
23106
23698
|
// src/mcp/tools/export-orchestration.ts
|
|
23107
23699
|
init_active_agent();
|
|
23108
|
-
import { mkdirSync as
|
|
23109
|
-
import
|
|
23110
|
-
import { z as
|
|
23700
|
+
import { mkdirSync as mkdirSync19, writeFileSync as writeFileSync21 } from "fs";
|
|
23701
|
+
import path44 from "path";
|
|
23702
|
+
import { z as z70 } from "zod";
|
|
23111
23703
|
|
|
23112
23704
|
// src/lib/orchestration-package.ts
|
|
23113
23705
|
init_database();
|
|
23114
23706
|
init_identity();
|
|
23115
23707
|
init_platform_procedures();
|
|
23116
23708
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
23117
|
-
import { copyFileSync as copyFileSync2, existsSync as
|
|
23709
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync35, mkdirSync as mkdirSync18, readFileSync as readFileSync27, writeFileSync as writeFileSync20 } from "fs";
|
|
23118
23710
|
import os18 from "os";
|
|
23119
|
-
import
|
|
23711
|
+
import path43 from "path";
|
|
23120
23712
|
var PACKAGE_VERSION = "1.0";
|
|
23121
23713
|
var ROSTER_FILENAME = "exe-employees.json";
|
|
23122
23714
|
var ROSTER_BACKUP_FILENAME = "exe-employees.json.bak";
|
|
@@ -23182,15 +23774,15 @@ function validateProcedureEntry(value, index) {
|
|
|
23182
23774
|
};
|
|
23183
23775
|
}
|
|
23184
23776
|
function getRosterPath() {
|
|
23185
|
-
return
|
|
23777
|
+
return path43.join(os18.homedir(), EXE_OS_DIRNAME, ROSTER_FILENAME);
|
|
23186
23778
|
}
|
|
23187
23779
|
function getBackupPath() {
|
|
23188
|
-
return
|
|
23780
|
+
return path43.join(os18.homedir(), EXE_OS_DIRNAME, ROSTER_BACKUP_FILENAME);
|
|
23189
23781
|
}
|
|
23190
23782
|
function readRosterFile() {
|
|
23191
23783
|
const rosterPath = getRosterPath();
|
|
23192
|
-
if (!
|
|
23193
|
-
const raw =
|
|
23784
|
+
if (!existsSync35(rosterPath)) return [];
|
|
23785
|
+
const raw = readFileSync27(rosterPath, "utf-8");
|
|
23194
23786
|
const parsed = JSON.parse(raw);
|
|
23195
23787
|
if (!Array.isArray(parsed)) {
|
|
23196
23788
|
throw new Error("Roster file must contain a JSON array");
|
|
@@ -23202,8 +23794,8 @@ function writeRosterFile(roster) {
|
|
|
23202
23794
|
throw new Error("Refusing to write empty roster \u2014 this would delete all employees");
|
|
23203
23795
|
}
|
|
23204
23796
|
const rosterPath = getRosterPath();
|
|
23205
|
-
|
|
23206
|
-
if (
|
|
23797
|
+
mkdirSync18(path43.dirname(rosterPath), { recursive: true });
|
|
23798
|
+
if (existsSync35(rosterPath)) {
|
|
23207
23799
|
const currentRoster = readRosterFile();
|
|
23208
23800
|
if (roster.length < currentRoster.length) {
|
|
23209
23801
|
throw new Error(
|
|
@@ -23212,7 +23804,7 @@ function writeRosterFile(roster) {
|
|
|
23212
23804
|
}
|
|
23213
23805
|
copyFileSync2(rosterPath, getBackupPath());
|
|
23214
23806
|
}
|
|
23215
|
-
|
|
23807
|
+
writeFileSync20(rosterPath, `${JSON.stringify(roster, null, 2)}
|
|
23216
23808
|
`, "utf-8");
|
|
23217
23809
|
}
|
|
23218
23810
|
function buildImportedRosterEntries(roster, timestamp) {
|
|
@@ -23467,15 +24059,15 @@ function registerExportOrchestration(server2) {
|
|
|
23467
24059
|
title: "Export Orchestration",
|
|
23468
24060
|
description: "Export roster, identities, behaviors, and customer procedures to a JSON package.",
|
|
23469
24061
|
inputSchema: {
|
|
23470
|
-
output_path:
|
|
24062
|
+
output_path: z70.string().describe("File path to write the JSON package")
|
|
23471
24063
|
}
|
|
23472
24064
|
},
|
|
23473
24065
|
async ({ output_path }) => {
|
|
23474
24066
|
try {
|
|
23475
24067
|
await initStore();
|
|
23476
24068
|
const pkg = await exportOrchestration(getActiveAgent().agentId);
|
|
23477
|
-
|
|
23478
|
-
|
|
24069
|
+
mkdirSync19(path44.dirname(output_path), { recursive: true });
|
|
24070
|
+
writeFileSync21(output_path, `${JSON.stringify(pkg, null, 2)}
|
|
23479
24071
|
`, "utf-8");
|
|
23480
24072
|
return {
|
|
23481
24073
|
content: [{
|
|
@@ -23497,8 +24089,8 @@ function registerExportOrchestration(server2) {
|
|
|
23497
24089
|
}
|
|
23498
24090
|
|
|
23499
24091
|
// src/mcp/tools/import-orchestration.ts
|
|
23500
|
-
import { readFileSync as
|
|
23501
|
-
import { z as
|
|
24092
|
+
import { readFileSync as readFileSync28 } from "fs";
|
|
24093
|
+
import { z as z71 } from "zod";
|
|
23502
24094
|
init_store();
|
|
23503
24095
|
init_active_agent();
|
|
23504
24096
|
init_employees();
|
|
@@ -23509,8 +24101,8 @@ function registerImportOrchestration(server2) {
|
|
|
23509
24101
|
title: "Import Orchestration",
|
|
23510
24102
|
description: "Import roster, identities, behaviors, and procedures from an orchestration package. Restricted to coordinator/founder.",
|
|
23511
24103
|
inputSchema: {
|
|
23512
|
-
package_path:
|
|
23513
|
-
merge_strategy:
|
|
24104
|
+
package_path: z71.string().describe("Path to the orchestration package JSON file"),
|
|
24105
|
+
merge_strategy: z71.enum(["replace", "merge"]).default("merge").describe("How to apply the package: both strategies are additive-only \u2014 existing data is never deleted or overwritten")
|
|
23514
24106
|
}
|
|
23515
24107
|
},
|
|
23516
24108
|
async ({ package_path, merge_strategy }) => {
|
|
@@ -23527,7 +24119,7 @@ function registerImportOrchestration(server2) {
|
|
|
23527
24119
|
};
|
|
23528
24120
|
}
|
|
23529
24121
|
await initStore();
|
|
23530
|
-
const raw =
|
|
24122
|
+
const raw = readFileSync28(package_path, "utf-8");
|
|
23531
24123
|
const pkg = validatePackage(JSON.parse(raw));
|
|
23532
24124
|
const result = await importOrchestration(pkg, merge_strategy);
|
|
23533
24125
|
return {
|
|
@@ -23555,7 +24147,7 @@ init_platform_procedures();
|
|
|
23555
24147
|
init_active_agent();
|
|
23556
24148
|
init_database();
|
|
23557
24149
|
init_employees();
|
|
23558
|
-
import { z as
|
|
24150
|
+
import { z as z72 } from "zod";
|
|
23559
24151
|
function registerCompanyProcedureTool(server2, toolName) {
|
|
23560
24152
|
server2.registerTool(
|
|
23561
24153
|
toolName,
|
|
@@ -23563,12 +24155,12 @@ function registerCompanyProcedureTool(server2, toolName) {
|
|
|
23563
24155
|
title: "Company Procedure",
|
|
23564
24156
|
description: "Manage company procedures (customer-owned Layer 0 rules) that supersede identity, expertise, and experience. Actions: store (create new, restricted), list (view all, open), deactivate (soft-delete, restricted).",
|
|
23565
24157
|
inputSchema: {
|
|
23566
|
-
action:
|
|
23567
|
-
title:
|
|
23568
|
-
content:
|
|
23569
|
-
priority:
|
|
23570
|
-
domain:
|
|
23571
|
-
procedure_id:
|
|
24158
|
+
action: z72.enum(["store", "list", "deactivate"]).describe("Action to perform"),
|
|
24159
|
+
title: z72.string().optional().describe("Short title for the procedure (store)"),
|
|
24160
|
+
content: z72.string().max(500).optional().describe("The procedure content \u2014 clear, actionable instruction (store)"),
|
|
24161
|
+
priority: z72.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always (default). p1 = standard. p2 = nice-to-have."),
|
|
24162
|
+
domain: z72.string().optional().describe("Category: workflow, code-style, communication, architecture, testing, security"),
|
|
24163
|
+
procedure_id: z72.string().optional().describe("UUID of the company procedure (deactivate)")
|
|
23572
24164
|
}
|
|
23573
24165
|
},
|
|
23574
24166
|
async ({ action, title, content, priority, domain, procedure_id }) => {
|
|
@@ -23701,6 +24293,7 @@ var ACTION_TO_TOOL2 = {
|
|
|
23701
24293
|
memory_audit: "run_memory_audit",
|
|
23702
24294
|
run_consolidation: "run_consolidation",
|
|
23703
24295
|
cloud_sync: "cloud_sync",
|
|
24296
|
+
orchestration_phase: "orchestration_phase",
|
|
23704
24297
|
backup_vps: "backup_vps",
|
|
23705
24298
|
deploy_client: "deploy_client",
|
|
23706
24299
|
license_status: "get_license_status",
|
|
@@ -23737,6 +24330,7 @@ function buildHandlers5() {
|
|
|
23737
24330
|
registerRunMemoryAudit(localServer);
|
|
23738
24331
|
registerRunConsolidation(localServer);
|
|
23739
24332
|
registerCloudSync(localServer);
|
|
24333
|
+
registerOrchestrationPhase(localServer);
|
|
23740
24334
|
registerBackupVps(localServer);
|
|
23741
24335
|
registerDeployClient(localServer);
|
|
23742
24336
|
registerGetLicenseStatus(localServer);
|
|
@@ -23759,41 +24353,42 @@ function registerConfig(server2) {
|
|
|
23759
24353
|
title: "Config",
|
|
23760
24354
|
description: "Consolidated COO/admin tool for runtime config, system health, licensing, triggers, orchestration import/export, and company procedures.",
|
|
23761
24355
|
inputSchema: {
|
|
23762
|
-
action:
|
|
23763
|
-
agent_id:
|
|
23764
|
-
runtime:
|
|
23765
|
-
model:
|
|
23766
|
-
reasoning_effort:
|
|
23767
|
-
dry_run:
|
|
23768
|
-
fix:
|
|
23769
|
-
verbose:
|
|
23770
|
-
project_name:
|
|
23771
|
-
since:
|
|
23772
|
-
limit:
|
|
23773
|
-
output_path:
|
|
23774
|
-
input_path:
|
|
23775
|
-
strategy:
|
|
23776
|
-
license_key:
|
|
23777
|
-
email:
|
|
23778
|
-
plan:
|
|
23779
|
-
name:
|
|
23780
|
-
event:
|
|
23781
|
-
conditions:
|
|
23782
|
-
actions:
|
|
23783
|
-
enabled:
|
|
23784
|
-
schedule:
|
|
23785
|
-
query:
|
|
23786
|
-
skill_name:
|
|
23787
|
-
pack_name:
|
|
23788
|
-
title:
|
|
23789
|
-
content:
|
|
23790
|
-
priority:
|
|
23791
|
-
domain:
|
|
23792
|
-
procedure_id:
|
|
23793
|
-
subaction:
|
|
23794
|
-
max_clusters:
|
|
23795
|
-
force:
|
|
23796
|
-
domain_name:
|
|
24356
|
+
action: z73.enum(Object.keys(ACTION_TO_TOOL2)).describe("Admin/config operation"),
|
|
24357
|
+
agent_id: z73.string().optional().describe("Agent id for set_agent_config/agent_spend/session queries"),
|
|
24358
|
+
runtime: z73.string().optional().describe("Runtime for set_agent_config"),
|
|
24359
|
+
model: z73.string().optional().describe("Model for set_agent_config"),
|
|
24360
|
+
reasoning_effort: z73.string().optional().describe("Reasoning effort for Codex agents"),
|
|
24361
|
+
dry_run: z73.boolean().optional().describe("Preview without applying where supported"),
|
|
24362
|
+
fix: z73.boolean().optional().describe("Apply fixes for memory_audit where supported"),
|
|
24363
|
+
verbose: z73.boolean().optional().describe("Verbose output where supported"),
|
|
24364
|
+
project_name: z73.string().optional().describe("Project filter/name"),
|
|
24365
|
+
since: z73.string().optional().describe("ISO lower-bound timestamp"),
|
|
24366
|
+
limit: z73.coerce.number().optional().describe("Result limit"),
|
|
24367
|
+
output_path: z73.string().optional().describe("Output path for export/backup"),
|
|
24368
|
+
input_path: z73.string().optional().describe("Input path for import_orchestration"),
|
|
24369
|
+
strategy: z73.enum(["merge", "replace"]).optional().describe("Import strategy; replace must still be additive-only per platform rules"),
|
|
24370
|
+
license_key: z73.string().optional().describe("License key for activation/status"),
|
|
24371
|
+
email: z73.string().optional().describe("Customer email for license creation"),
|
|
24372
|
+
plan: z73.string().optional().describe("License plan"),
|
|
24373
|
+
name: z73.string().optional().describe("Trigger/starter pack/procedure/client name"),
|
|
24374
|
+
event: z73.string().optional().describe("Trigger event"),
|
|
24375
|
+
conditions: z73.array(z73.record(z73.string(), z73.unknown())).optional().describe("Trigger conditions"),
|
|
24376
|
+
actions: z73.array(z73.record(z73.string(), z73.unknown())).optional().describe("Trigger actions"),
|
|
24377
|
+
enabled: z73.boolean().optional().describe("Trigger enabled flag"),
|
|
24378
|
+
schedule: z73.string().optional().describe("Trigger schedule"),
|
|
24379
|
+
query: z73.string().optional().describe("Trigger query or filter"),
|
|
24380
|
+
skill_name: z73.string().optional().describe("Skill name for load_skill"),
|
|
24381
|
+
pack_name: z73.string().optional().describe("Starter pack name"),
|
|
24382
|
+
title: z73.string().optional().describe("Procedure title"),
|
|
24383
|
+
content: z73.string().optional().describe("Procedure content"),
|
|
24384
|
+
priority: z73.enum(["p0", "p1", "p2"]).optional().describe("Procedure priority"),
|
|
24385
|
+
domain: z73.string().optional().describe("Procedure domain"),
|
|
24386
|
+
procedure_id: z73.string().optional().describe("Procedure id for deactivate"),
|
|
24387
|
+
subaction: z73.enum(["store", "list", "deactivate"]).optional().describe("Nested action for company_procedure/global_procedure"),
|
|
24388
|
+
max_clusters: z73.coerce.number().optional().describe("Consolidation max clusters"),
|
|
24389
|
+
force: z73.boolean().optional().describe("Force operation where supported"),
|
|
24390
|
+
domain_name: z73.string().optional().describe("Client deployment domain"),
|
|
24391
|
+
phase: z73.enum(["phase_1_coo", "phase_2_executives", "phase_3_parallel_org", "1", "2", "3"]).optional().describe("Orchestration phase for orchestration_phase action")
|
|
23797
24392
|
}
|
|
23798
24393
|
}, async (input, extra) => {
|
|
23799
24394
|
const action = input.action;
|
|
@@ -23814,10 +24409,10 @@ function registerConfig(server2) {
|
|
|
23814
24409
|
}
|
|
23815
24410
|
|
|
23816
24411
|
// src/mcp/tools/wiki.ts
|
|
23817
|
-
import { z as
|
|
24412
|
+
import { z as z76 } from "zod";
|
|
23818
24413
|
|
|
23819
24414
|
// src/mcp/tools/list-wiki-pages.ts
|
|
23820
|
-
import { z as
|
|
24415
|
+
import { z as z74 } from "zod";
|
|
23821
24416
|
var FETCH_TIMEOUT_MS3 = 1e4;
|
|
23822
24417
|
function registerListWikiPages(server2) {
|
|
23823
24418
|
server2.registerTool(
|
|
@@ -23826,8 +24421,8 @@ function registerListWikiPages(server2) {
|
|
|
23826
24421
|
title: "List Wiki Pages",
|
|
23827
24422
|
description: "List documents in an exe-wiki workspace. Optionally filter by folder.",
|
|
23828
24423
|
inputSchema: {
|
|
23829
|
-
workspace:
|
|
23830
|
-
folder:
|
|
24424
|
+
workspace: z74.string().describe('Wiki workspace slug (e.g., "hygo")'),
|
|
24425
|
+
folder: z74.string().optional().describe("Filter by folder path")
|
|
23831
24426
|
}
|
|
23832
24427
|
},
|
|
23833
24428
|
async ({ workspace, folder }) => {
|
|
@@ -23916,7 +24511,7 @@ function registerListWikiPages(server2) {
|
|
|
23916
24511
|
}
|
|
23917
24512
|
|
|
23918
24513
|
// src/mcp/tools/get-wiki-page.ts
|
|
23919
|
-
import { z as
|
|
24514
|
+
import { z as z75 } from "zod";
|
|
23920
24515
|
var FETCH_TIMEOUT_MS4 = 1e4;
|
|
23921
24516
|
function registerGetWikiPage(server2) {
|
|
23922
24517
|
server2.registerTool(
|
|
@@ -23925,9 +24520,9 @@ function registerGetWikiPage(server2) {
|
|
|
23925
24520
|
title: "Get Wiki Page",
|
|
23926
24521
|
description: "Read a wiki page by document ID or title. Returns content, metadata, and folder path. Use title search when you know the page name but not the ID.",
|
|
23927
24522
|
inputSchema: {
|
|
23928
|
-
workspace:
|
|
23929
|
-
document_id:
|
|
23930
|
-
title:
|
|
24523
|
+
workspace: z75.string().describe('Wiki workspace slug (e.g., "hygo")'),
|
|
24524
|
+
document_id: z75.string().optional().describe("Specific document ID (exact lookup)"),
|
|
24525
|
+
title: z75.string().optional().describe("Search by title (fuzzy match)")
|
|
23931
24526
|
}
|
|
23932
24527
|
},
|
|
23933
24528
|
async ({ workspace, document_id, title }) => {
|
|
@@ -24109,14 +24704,14 @@ function registerWiki(server2) {
|
|
|
24109
24704
|
title: "Wiki",
|
|
24110
24705
|
description: "Consolidated wiki domain tool. Actions: list, get. Wiki writes flow through raw data ingestion/projection into the curated wiki store; direct create/update MCP tools have been removed.",
|
|
24111
24706
|
inputSchema: {
|
|
24112
|
-
action:
|
|
24113
|
-
workspace:
|
|
24114
|
-
title:
|
|
24115
|
-
content:
|
|
24116
|
-
folder:
|
|
24117
|
-
document_id:
|
|
24118
|
-
mode:
|
|
24119
|
-
section:
|
|
24707
|
+
action: z76.enum(["list", "get"]).describe("Wiki read operation. Writes use raw-data ingestion/projection, not direct MCP writes."),
|
|
24708
|
+
workspace: z76.string().optional().describe("Wiki workspace slug"),
|
|
24709
|
+
title: z76.string().optional().describe("Fuzzy page title lookup for get"),
|
|
24710
|
+
content: z76.string().optional().describe("Reserved; wiki writes use raw-data ingestion/projection"),
|
|
24711
|
+
folder: z76.string().optional().describe("Optional folder path for list"),
|
|
24712
|
+
document_id: z76.string().optional().describe("Document ID for get"),
|
|
24713
|
+
mode: z76.enum(["replace", "append"]).optional().describe("Reserved; direct wiki updates are removed"),
|
|
24714
|
+
section: z76.string().optional().describe("Reserved; direct wiki updates are removed")
|
|
24120
24715
|
}
|
|
24121
24716
|
},
|
|
24122
24717
|
async (input, extra) => {
|
|
@@ -24144,7 +24739,7 @@ init_active_agent();
|
|
|
24144
24739
|
init_project_name();
|
|
24145
24740
|
init_database();
|
|
24146
24741
|
init_employees();
|
|
24147
|
-
import { z as
|
|
24742
|
+
import { z as z77 } from "zod";
|
|
24148
24743
|
function rowToBehavior2(r) {
|
|
24149
24744
|
return {
|
|
24150
24745
|
id: String(r.id),
|
|
@@ -24166,13 +24761,13 @@ function registerBehavior(server2) {
|
|
|
24166
24761
|
title: "Behavior",
|
|
24167
24762
|
description: "Manage behavioral patterns, corrections, and reusable procedures for employees. Actions: store (create new), list (query existing), deactivate (soft-delete, restricted).",
|
|
24168
24763
|
inputSchema: {
|
|
24169
|
-
action:
|
|
24170
|
-
content:
|
|
24171
|
-
domain:
|
|
24172
|
-
priority:
|
|
24173
|
-
agent_id:
|
|
24174
|
-
project_name:
|
|
24175
|
-
behavior_id:
|
|
24764
|
+
action: z77.enum(["store", "list", "deactivate"]).describe("Action to perform"),
|
|
24765
|
+
content: z77.string().max(500).optional().describe("The behavioral instruction \u2014 one clear sentence (store)"),
|
|
24766
|
+
domain: z77.string().optional().describe("Category: workflow, code-style, tool-use, communication, architecture, testing"),
|
|
24767
|
+
priority: z77.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always included. p1 = standard (default). p2 = nice-to-have."),
|
|
24768
|
+
agent_id: z77.string().optional().describe("Employee name. Defaults to current agent. Pass 'all' to list everyone's (list only)."),
|
|
24769
|
+
project_name: z77.string().optional().describe("Defaults to current project. Pass 'global' for a behavior that applies everywhere (store)."),
|
|
24770
|
+
behavior_id: z77.string().optional().describe("UUID of the behavior (deactivate)")
|
|
24176
24771
|
}
|
|
24177
24772
|
},
|
|
24178
24773
|
async ({ action, content, domain, priority, agent_id, project_name, behavior_id }) => {
|
|
@@ -24343,7 +24938,7 @@ Content: ${row.content}`
|
|
|
24343
24938
|
}
|
|
24344
24939
|
|
|
24345
24940
|
// src/mcp/tools/reminder.ts
|
|
24346
|
-
import { z as
|
|
24941
|
+
import { z as z78 } from "zod";
|
|
24347
24942
|
function registerReminder(server2) {
|
|
24348
24943
|
server2.registerTool(
|
|
24349
24944
|
"reminder",
|
|
@@ -24351,11 +24946,11 @@ function registerReminder(server2) {
|
|
|
24351
24946
|
title: "Reminder",
|
|
24352
24947
|
description: "Manage reminders for the founder. Shown in the boot brief every session. Actions: create (set new), list (view active), complete (mark done).",
|
|
24353
24948
|
inputSchema: {
|
|
24354
|
-
action:
|
|
24355
|
-
text:
|
|
24356
|
-
due_date:
|
|
24357
|
-
reminder_id:
|
|
24358
|
-
include_completed:
|
|
24949
|
+
action: z78.enum(["create", "list", "complete"]).describe("Action to perform"),
|
|
24950
|
+
text: z78.string().optional().describe("What to remind about (create)"),
|
|
24951
|
+
due_date: z78.string().optional().describe("Optional due date \u2014 ISO date (2026-04-01) or null for persistent (create)"),
|
|
24952
|
+
reminder_id: z78.string().optional().describe("Reminder UUID or text substring to match (complete)"),
|
|
24953
|
+
include_completed: z78.boolean().optional().default(false).describe("Include completed reminders (list)")
|
|
24359
24954
|
}
|
|
24360
24955
|
},
|
|
24361
24956
|
async ({ action, text: text3, due_date, reminder_id, include_completed }) => {
|
|
@@ -24411,7 +25006,7 @@ function registerReminder(server2) {
|
|
|
24411
25006
|
init_global_procedures();
|
|
24412
25007
|
init_active_agent();
|
|
24413
25008
|
init_employees();
|
|
24414
|
-
import { z as
|
|
25009
|
+
import { z as z79 } from "zod";
|
|
24415
25010
|
function registerStoreGlobalProcedure(server2) {
|
|
24416
25011
|
server2.registerTool(
|
|
24417
25012
|
"store_global_procedure",
|
|
@@ -24419,10 +25014,10 @@ function registerStoreGlobalProcedure(server2) {
|
|
|
24419
25014
|
title: "Store Company Procedure (use global_procedure instead)",
|
|
24420
25015
|
description: "DEPRECATED \u2014 use global_procedure with action='store'. Create a company procedure (customer-owned Layer 0 rule). RESTRICTED: only coordinator or founder sessions.",
|
|
24421
25016
|
inputSchema: {
|
|
24422
|
-
title:
|
|
24423
|
-
content:
|
|
24424
|
-
priority:
|
|
24425
|
-
domain:
|
|
25017
|
+
title: z79.string().describe("Short title for the procedure"),
|
|
25018
|
+
content: z79.string().max(500).describe("The procedure content \u2014 clear, actionable instruction"),
|
|
25019
|
+
priority: z79.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always (default)."),
|
|
25020
|
+
domain: z79.string().optional().describe("Category: workflow, code-style, communication, architecture, testing, security")
|
|
24426
25021
|
}
|
|
24427
25022
|
},
|
|
24428
25023
|
async ({ title, content, priority, domain }) => {
|
|
@@ -24500,7 +25095,7 @@ init_global_procedures();
|
|
|
24500
25095
|
init_active_agent();
|
|
24501
25096
|
init_database();
|
|
24502
25097
|
init_employees();
|
|
24503
|
-
import { z as
|
|
25098
|
+
import { z as z80 } from "zod";
|
|
24504
25099
|
function registerDeactivateGlobalProcedure(server2) {
|
|
24505
25100
|
server2.registerTool(
|
|
24506
25101
|
"deactivate_global_procedure",
|
|
@@ -24508,7 +25103,7 @@ function registerDeactivateGlobalProcedure(server2) {
|
|
|
24508
25103
|
title: "Deactivate Company Procedure (use global_procedure instead)",
|
|
24509
25104
|
description: "DEPRECATED \u2014 use global_procedure with action='deactivate'. Soft-delete a company procedure. RESTRICTED: only coordinator or founder sessions.",
|
|
24510
25105
|
inputSchema: {
|
|
24511
|
-
procedure_id:
|
|
25106
|
+
procedure_id: z80.string().describe("UUID of the company procedure to deactivate")
|
|
24512
25107
|
}
|
|
24513
25108
|
},
|
|
24514
25109
|
async ({ procedure_id }) => {
|
|
@@ -24568,7 +25163,7 @@ init_store();
|
|
|
24568
25163
|
init_active_agent();
|
|
24569
25164
|
init_database();
|
|
24570
25165
|
init_plan_limits();
|
|
24571
|
-
import { z as
|
|
25166
|
+
import { z as z81 } from "zod";
|
|
24572
25167
|
import crypto17 from "crypto";
|
|
24573
25168
|
function registerStoreDecision(server2) {
|
|
24574
25169
|
server2.registerTool(
|
|
@@ -24577,13 +25172,13 @@ function registerStoreDecision(server2) {
|
|
|
24577
25172
|
title: "Store Decision",
|
|
24578
25173
|
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.",
|
|
24579
25174
|
inputSchema: {
|
|
24580
|
-
domain:
|
|
25175
|
+
domain: z81.string().describe(
|
|
24581
25176
|
"Domain key, e.g. 'auth-strategy', 'db-migration-approach', 'api-versioning'"
|
|
24582
25177
|
),
|
|
24583
|
-
decision:
|
|
24584
|
-
rationale:
|
|
24585
|
-
supersedes:
|
|
24586
|
-
project_name:
|
|
25178
|
+
decision: z81.string().describe("The decision text \u2014 what was decided"),
|
|
25179
|
+
rationale: z81.string().optional().describe("Why this decision was made \u2014 constraints, trade-offs, context"),
|
|
25180
|
+
supersedes: z81.string().optional().describe("UUID of the decision this supersedes (previous decision for this domain)"),
|
|
25181
|
+
project_name: z81.string().optional().describe("Project name")
|
|
24587
25182
|
}
|
|
24588
25183
|
},
|
|
24589
25184
|
async ({ domain, decision, rationale, supersedes, project_name }) => {
|
|
@@ -24651,7 +25246,7 @@ Supersedes: ${supersedes}` : ""}`
|
|
|
24651
25246
|
|
|
24652
25247
|
// src/mcp/tools/get-decision.ts
|
|
24653
25248
|
init_database();
|
|
24654
|
-
import { z as
|
|
25249
|
+
import { z as z82 } from "zod";
|
|
24655
25250
|
function registerGetDecision(server2) {
|
|
24656
25251
|
server2.registerTool(
|
|
24657
25252
|
"get_decision",
|
|
@@ -24659,7 +25254,7 @@ function registerGetDecision(server2) {
|
|
|
24659
25254
|
title: "Get Decision",
|
|
24660
25255
|
description: "Retrieve the latest authoritative decision for a domain. Returns the current active decision and the supersession history.",
|
|
24661
25256
|
inputSchema: {
|
|
24662
|
-
domain:
|
|
25257
|
+
domain: z82.string().describe(
|
|
24663
25258
|
"Domain key to look up, e.g. 'auth-strategy', 'db-migration-approach'"
|
|
24664
25259
|
)
|
|
24665
25260
|
}
|
|
@@ -24722,16 +25317,16 @@ function registerGetDecision(server2) {
|
|
|
24722
25317
|
}
|
|
24723
25318
|
|
|
24724
25319
|
// src/mcp/tools/people-roster.ts
|
|
24725
|
-
import { z as
|
|
25320
|
+
import { z as z83 } from "zod";
|
|
24726
25321
|
|
|
24727
25322
|
// src/lib/people.ts
|
|
24728
25323
|
init_config();
|
|
24729
25324
|
import { readFile as readFile5, writeFile as writeFile6, mkdir as mkdir5 } from "fs/promises";
|
|
24730
|
-
import { existsSync as
|
|
24731
|
-
import
|
|
24732
|
-
var PEOPLE_PATH =
|
|
25325
|
+
import { existsSync as existsSync36, readFileSync as readFileSync29 } from "fs";
|
|
25326
|
+
import path45 from "path";
|
|
25327
|
+
var PEOPLE_PATH = path45.join(EXE_AI_DIR, "people.json");
|
|
24733
25328
|
async function loadPeople() {
|
|
24734
|
-
if (!
|
|
25329
|
+
if (!existsSync36(PEOPLE_PATH)) return [];
|
|
24735
25330
|
try {
|
|
24736
25331
|
const raw = await readFile5(PEOPLE_PATH, "utf-8");
|
|
24737
25332
|
return JSON.parse(raw);
|
|
@@ -24740,7 +25335,7 @@ async function loadPeople() {
|
|
|
24740
25335
|
}
|
|
24741
25336
|
}
|
|
24742
25337
|
async function savePeople(people) {
|
|
24743
|
-
await mkdir5(
|
|
25338
|
+
await mkdir5(path45.dirname(PEOPLE_PATH), { recursive: true });
|
|
24744
25339
|
await writeFile6(PEOPLE_PATH, JSON.stringify(people, null, 2) + "\n", "utf-8");
|
|
24745
25340
|
}
|
|
24746
25341
|
async function addPerson(person) {
|
|
@@ -24770,10 +25365,10 @@ function registerAddPerson(server2) {
|
|
|
24770
25365
|
title: "Add Person",
|
|
24771
25366
|
description: "Add or update a key human in the people roster. Used for co-founders, partners, customers \u2014 anyone agents need to know about.",
|
|
24772
25367
|
inputSchema: {
|
|
24773
|
-
name:
|
|
24774
|
-
role:
|
|
24775
|
-
relationship:
|
|
24776
|
-
notes:
|
|
25368
|
+
name: z83.string().describe("Person's name"),
|
|
25369
|
+
role: z83.string().describe("Their role (e.g. co-founder, customer, partner)"),
|
|
25370
|
+
relationship: z83.string().describe("Relationship to the organization (e.g. co-founder, early adopter, investor)"),
|
|
25371
|
+
notes: z83.string().optional().describe("Additional context about this person")
|
|
24777
25372
|
}
|
|
24778
25373
|
},
|
|
24779
25374
|
async ({ name, role, relationship, notes }) => {
|
|
@@ -24819,7 +25414,7 @@ function registerGetPerson(server2) {
|
|
|
24819
25414
|
title: "Get Person",
|
|
24820
25415
|
description: "Look up a specific person by name from the people roster.",
|
|
24821
25416
|
inputSchema: {
|
|
24822
|
-
name:
|
|
25417
|
+
name: z83.string().describe("Person's name to look up")
|
|
24823
25418
|
}
|
|
24824
25419
|
},
|
|
24825
25420
|
async ({ name }) => {
|
|
@@ -24843,10 +25438,10 @@ Notes: ${person.notes}` : ""}`
|
|
|
24843
25438
|
}
|
|
24844
25439
|
|
|
24845
25440
|
// src/mcp/tools/crm.ts
|
|
24846
|
-
import { z as
|
|
25441
|
+
import { z as z84 } from "zod";
|
|
24847
25442
|
|
|
24848
25443
|
// src/lib/exe-db-read.ts
|
|
24849
|
-
import
|
|
25444
|
+
import path46 from "path";
|
|
24850
25445
|
import os19 from "os";
|
|
24851
25446
|
import { createRequire as createRequire5 } from "module";
|
|
24852
25447
|
import { pathToFileURL as pathToFileURL5 } from "url";
|
|
@@ -24864,8 +25459,8 @@ async function getExeDbReadClient() {
|
|
|
24864
25459
|
if (!Ctor2) throw new Error(`No PrismaClient export found at ${explicitPath}`);
|
|
24865
25460
|
return new Ctor2();
|
|
24866
25461
|
}
|
|
24867
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
24868
|
-
const req = createRequire5(
|
|
25462
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path46.join(os19.homedir(), "exe-db");
|
|
25463
|
+
const req = createRequire5(path46.join(exeDbRoot, "package.json"));
|
|
24869
25464
|
const entry = req.resolve("@prisma/client");
|
|
24870
25465
|
const mod = await import(pathToFileURL5(entry).href);
|
|
24871
25466
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -24898,12 +25493,12 @@ function registerCrm(server2) {
|
|
|
24898
25493
|
title: "CRM",
|
|
24899
25494
|
description: "Read-only CRM access from exe-db crm schema. Actions: list_people, get_person, list_tables, describe_table.",
|
|
24900
25495
|
inputSchema: {
|
|
24901
|
-
action:
|
|
24902
|
-
id:
|
|
24903
|
-
query:
|
|
24904
|
-
table:
|
|
24905
|
-
limit:
|
|
24906
|
-
offset:
|
|
25496
|
+
action: z84.enum(["list_people", "get_person", "list_tables", "describe_table"]).describe("CRM read operation"),
|
|
25497
|
+
id: z84.string().optional().describe("CRM row/person id for get_person"),
|
|
25498
|
+
query: z84.string().optional().describe("Text search for list_people/get_person"),
|
|
25499
|
+
table: z84.string().optional().describe("crm schema table name for describe_table"),
|
|
25500
|
+
limit: z84.coerce.number().int().min(1).max(50).optional().describe("Max rows, capped at 50"),
|
|
25501
|
+
offset: z84.coerce.number().int().min(0).optional().describe("Rows to skip")
|
|
24907
25502
|
}
|
|
24908
25503
|
}, async ({ action, id, query, table, limit, offset }) => {
|
|
24909
25504
|
try {
|
|
@@ -24962,7 +25557,7 @@ function registerCrm(server2) {
|
|
|
24962
25557
|
}
|
|
24963
25558
|
|
|
24964
25559
|
// src/mcp/tools/raw-data.ts
|
|
24965
|
-
import { z as
|
|
25560
|
+
import { z as z85 } from "zod";
|
|
24966
25561
|
function text2(content, isError = false) {
|
|
24967
25562
|
return { content: [{ type: "text", text: content }], ...isError ? { isError: true } : {} };
|
|
24968
25563
|
}
|
|
@@ -24971,15 +25566,15 @@ function registerRawData(server2) {
|
|
|
24971
25566
|
title: "Raw Data",
|
|
24972
25567
|
description: "Read-only access to exe-db raw.raw_events landing pad. Actions: list_sources, query, get. Results are capped because raw payloads can consume many tokens.",
|
|
24973
25568
|
inputSchema: {
|
|
24974
|
-
action:
|
|
24975
|
-
id:
|
|
24976
|
-
source:
|
|
24977
|
-
event_type:
|
|
24978
|
-
query:
|
|
24979
|
-
processed:
|
|
24980
|
-
limit:
|
|
24981
|
-
offset:
|
|
24982
|
-
include_payload:
|
|
25569
|
+
action: z85.enum(["list_sources", "query", "get"]).describe("Raw data read operation"),
|
|
25570
|
+
id: z85.string().optional().describe("raw.raw_events id for action=get"),
|
|
25571
|
+
source: z85.string().optional().describe("Filter by raw source"),
|
|
25572
|
+
event_type: z85.string().optional().describe("Filter by event_type"),
|
|
25573
|
+
query: z85.string().optional().describe("Search payload/metadata text"),
|
|
25574
|
+
processed: z85.boolean().optional().describe("Filter processed_at IS NULL/NOT NULL"),
|
|
25575
|
+
limit: z85.coerce.number().int().min(1).max(50).optional().describe("Max rows, capped at 50"),
|
|
25576
|
+
offset: z85.coerce.number().int().min(0).optional().describe("Rows to skip"),
|
|
25577
|
+
include_payload: z85.boolean().optional().describe("Include full payload JSON. Default false to save tokens.")
|
|
24983
25578
|
}
|
|
24984
25579
|
}, async ({ action, id, source, event_type, query, processed, limit, offset, include_payload }) => {
|
|
24985
25580
|
try {
|
|
@@ -25046,17 +25641,17 @@ init_active_agent();
|
|
|
25046
25641
|
init_config();
|
|
25047
25642
|
init_license();
|
|
25048
25643
|
init_store();
|
|
25049
|
-
import { z as
|
|
25644
|
+
import { z as z86 } from "zod";
|
|
25050
25645
|
import crypto18 from "crypto";
|
|
25051
25646
|
import { mkdir as mkdir6, writeFile as writeFile7 } from "fs/promises";
|
|
25052
|
-
import
|
|
25053
|
-
var CLASSIFICATION =
|
|
25647
|
+
import path47 from "path";
|
|
25648
|
+
var CLASSIFICATION = z86.enum([
|
|
25054
25649
|
"upstream_bug",
|
|
25055
25650
|
"customer_customization",
|
|
25056
25651
|
"emergency_hotfix",
|
|
25057
25652
|
"unclear"
|
|
25058
25653
|
]);
|
|
25059
|
-
var SEVERITY =
|
|
25654
|
+
var SEVERITY = z86.enum(["p0", "p1", "p2", "p3"]);
|
|
25060
25655
|
function slugify2(input) {
|
|
25061
25656
|
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "bug-report";
|
|
25062
25657
|
}
|
|
@@ -25134,22 +25729,22 @@ function registerCreateBugReport(server2) {
|
|
|
25134
25729
|
title: "Create Bug Report",
|
|
25135
25730
|
description: "Classify and file an exe-os issue as upstream_bug, customer_customization, emergency_hotfix, or unclear. Writes a local report, stores memory, and optionally sends to AskExe support when a support endpoint is configured.",
|
|
25136
25731
|
inputSchema: {
|
|
25137
|
-
title:
|
|
25732
|
+
title: z86.string().min(3).describe("Short descriptive title"),
|
|
25138
25733
|
classification: CLASSIFICATION.describe(
|
|
25139
25734
|
"upstream_bug = platform defect; customer_customization = local preference; emergency_hotfix = temporary local patch; unclear = needs maintainer triage"
|
|
25140
25735
|
),
|
|
25141
25736
|
severity: SEVERITY.default("p2").describe("p0 critical \u2192 p3 low"),
|
|
25142
|
-
summary:
|
|
25143
|
-
customer_impact:
|
|
25144
|
-
reproduction_steps:
|
|
25145
|
-
expected:
|
|
25146
|
-
actual:
|
|
25147
|
-
files_changed:
|
|
25148
|
-
workaround:
|
|
25149
|
-
local_patch_diff:
|
|
25150
|
-
package_version:
|
|
25151
|
-
project_name:
|
|
25152
|
-
send_upstream:
|
|
25737
|
+
summary: z86.string().min(10).describe("What happened and why it matters"),
|
|
25738
|
+
customer_impact: z86.string().optional().describe("How this affects the customer/founder"),
|
|
25739
|
+
reproduction_steps: z86.array(z86.string()).optional().describe("Steps to reproduce"),
|
|
25740
|
+
expected: z86.string().optional().describe("Expected behavior"),
|
|
25741
|
+
actual: z86.string().optional().describe("Actual behavior"),
|
|
25742
|
+
files_changed: z86.array(z86.string()).optional().describe("Files changed or suspected"),
|
|
25743
|
+
workaround: z86.string().optional().describe("Temporary local workaround/hotfix, if any"),
|
|
25744
|
+
local_patch_diff: z86.string().optional().describe("Small local diff or patch summary"),
|
|
25745
|
+
package_version: z86.string().optional().describe("Installed @askexenow/exe-os version"),
|
|
25746
|
+
project_name: z86.string().optional().describe("Project/customer context"),
|
|
25747
|
+
send_upstream: z86.boolean().default(true).describe("Attempt to POST to configured AskExe support endpoint")
|
|
25153
25748
|
}
|
|
25154
25749
|
},
|
|
25155
25750
|
async ({
|
|
@@ -25189,9 +25784,9 @@ function registerCreateBugReport(server2) {
|
|
|
25189
25784
|
filesChanged: files_changed,
|
|
25190
25785
|
projectName: project_name
|
|
25191
25786
|
});
|
|
25192
|
-
const outDir =
|
|
25787
|
+
const outDir = path47.join(EXE_AI_DIR, "bug-reports");
|
|
25193
25788
|
await mkdir6(outDir, { recursive: true });
|
|
25194
|
-
const reportPath =
|
|
25789
|
+
const reportPath = path47.join(outDir, `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}-${slugify2(title)}-${id.slice(0, 8)}.md`);
|
|
25195
25790
|
await writeFile7(reportPath, markdown, "utf-8");
|
|
25196
25791
|
let vector = null;
|
|
25197
25792
|
try {
|
|
@@ -25258,9 +25853,9 @@ Upstream status: ${upstreamStatus}`
|
|
|
25258
25853
|
}
|
|
25259
25854
|
|
|
25260
25855
|
// src/mcp/tools/support-inbox.ts
|
|
25261
|
-
import { z as
|
|
25856
|
+
import { z as z87 } from "zod";
|
|
25262
25857
|
var DEFAULT_ENDPOINT = "https://askexe.com/admin/support/bug-reports";
|
|
25263
|
-
var STATUS =
|
|
25858
|
+
var STATUS = z87.enum(["open", "triaged", "fixed", "closed", "wontfix"]);
|
|
25264
25859
|
function adminToken() {
|
|
25265
25860
|
return process.env.ASKEXE_SUPPORT_ADMIN_TOKEN || process.env.EXE_SUPPORT_ADMIN_TOKEN;
|
|
25266
25861
|
}
|
|
@@ -25299,9 +25894,9 @@ function registerListBugReports(server2) {
|
|
|
25299
25894
|
title: "List Bug Reports",
|
|
25300
25895
|
description: "AskExe-internal only: list incoming customer bug reports from the support inbox.",
|
|
25301
25896
|
inputSchema: {
|
|
25302
|
-
status:
|
|
25303
|
-
severity:
|
|
25304
|
-
limit:
|
|
25897
|
+
status: z87.enum(["all", "open", "triaged", "fixed", "closed", "wontfix"]).default("open"),
|
|
25898
|
+
severity: z87.enum(["p0", "p1", "p2", "p3"]).optional(),
|
|
25899
|
+
limit: z87.number().int().min(1).max(100).default(25)
|
|
25305
25900
|
}
|
|
25306
25901
|
},
|
|
25307
25902
|
async ({ status, severity, limit }) => {
|
|
@@ -25320,7 +25915,7 @@ function registerGetBugReport(server2) {
|
|
|
25320
25915
|
{
|
|
25321
25916
|
title: "Get Bug Report",
|
|
25322
25917
|
description: "AskExe-internal only: fetch one customer bug report with full markdown payload.",
|
|
25323
|
-
inputSchema: { id:
|
|
25918
|
+
inputSchema: { id: z87.string().min(8) }
|
|
25324
25919
|
},
|
|
25325
25920
|
async ({ id }) => {
|
|
25326
25921
|
const data = await requestJson(`${endpoint()}/${encodeURIComponent(id)}`);
|
|
@@ -25335,12 +25930,12 @@ function registerTriageBugReport(server2) {
|
|
|
25335
25930
|
title: "Triage Bug Report",
|
|
25336
25931
|
description: "AskExe-internal only: update bug report status and link task/commit/release metadata.",
|
|
25337
25932
|
inputSchema: {
|
|
25338
|
-
id:
|
|
25933
|
+
id: z87.string().min(8),
|
|
25339
25934
|
status: STATUS.optional(),
|
|
25340
|
-
triage_notes:
|
|
25341
|
-
linked_task_id:
|
|
25342
|
-
linked_commit:
|
|
25343
|
-
fixed_version:
|
|
25935
|
+
triage_notes: z87.string().optional(),
|
|
25936
|
+
linked_task_id: z87.string().optional(),
|
|
25937
|
+
linked_commit: z87.string().optional(),
|
|
25938
|
+
fixed_version: z87.string().optional()
|
|
25344
25939
|
}
|
|
25345
25940
|
},
|
|
25346
25941
|
async ({ id, status, triage_notes, linked_task_id, linked_commit, fixed_version }) => {
|
|
@@ -25470,6 +26065,7 @@ var TOOL_CATEGORIES = {
|
|
|
25470
26065
|
registerRunMemoryAudit: "admin",
|
|
25471
26066
|
registerRunConsolidation: "admin",
|
|
25472
26067
|
registerCloudSync: "admin",
|
|
26068
|
+
registerOrchestrationPhase: "admin",
|
|
25473
26069
|
registerSetAgentConfig: "admin",
|
|
25474
26070
|
registerListEmployees: "admin",
|
|
25475
26071
|
registerGetAgentSpend: "admin",
|
|
@@ -25688,6 +26284,7 @@ function registerAllTools(server2) {
|
|
|
25688
26284
|
gate("registerRunMemoryAudit", registerRunMemoryAudit);
|
|
25689
26285
|
gate("registerCloudSync", registerCloudSync);
|
|
25690
26286
|
gate("registerBackupVps", registerBackupVps);
|
|
26287
|
+
gate("registerOrchestrationPhase", registerOrchestrationPhase);
|
|
25691
26288
|
}
|
|
25692
26289
|
if (exposeLegacyMemory) {
|
|
25693
26290
|
gate("registerGetMemoryCardinality", registerGetMemoryCardinality);
|
|
@@ -25832,16 +26429,16 @@ try {
|
|
|
25832
26429
|
}
|
|
25833
26430
|
}, 3e4);
|
|
25834
26431
|
_ppidWatchdog.unref();
|
|
25835
|
-
const MCP_VERSION_PATH =
|
|
26432
|
+
const MCP_VERSION_PATH = path48.join(os20.homedir(), ".exe-os", "mcp-version");
|
|
25836
26433
|
let _currentMcpVersion = null;
|
|
25837
26434
|
try {
|
|
25838
|
-
_currentMcpVersion =
|
|
26435
|
+
_currentMcpVersion = existsSync37(MCP_VERSION_PATH) ? readFileSync30(MCP_VERSION_PATH, "utf8").trim() : null;
|
|
25839
26436
|
} catch {
|
|
25840
26437
|
}
|
|
25841
26438
|
const _versionWatchdog = setInterval(() => {
|
|
25842
26439
|
try {
|
|
25843
|
-
if (!
|
|
25844
|
-
const diskVersion =
|
|
26440
|
+
if (!existsSync37(MCP_VERSION_PATH)) return;
|
|
26441
|
+
const diskVersion = readFileSync30(MCP_VERSION_PATH, "utf8").trim();
|
|
25845
26442
|
if (_currentMcpVersion && diskVersion !== _currentMcpVersion) {
|
|
25846
26443
|
process.stderr.write(
|
|
25847
26444
|
`[exe-os] MCP version changed (${_currentMcpVersion} \u2192 ${diskVersion}). Hot-reloading...
|
|
@@ -25874,14 +26471,14 @@ try {
|
|
|
25874
26471
|
`
|
|
25875
26472
|
);
|
|
25876
26473
|
const thisFile = fileURLToPath5(import.meta.url);
|
|
25877
|
-
const backfillPath =
|
|
25878
|
-
|
|
26474
|
+
const backfillPath = path48.resolve(
|
|
26475
|
+
path48.dirname(thisFile),
|
|
25879
26476
|
"../bin/backfill-vectors.js"
|
|
25880
26477
|
);
|
|
25881
|
-
if (
|
|
26478
|
+
if (existsSync37(backfillPath)) {
|
|
25882
26479
|
const { EXE_AI_DIR: exeDir } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
25883
|
-
const logPath =
|
|
25884
|
-
|
|
26480
|
+
const logPath = path48.join(exeDir, "workers.log");
|
|
26481
|
+
mkdirSync20(path48.dirname(logPath), { recursive: true });
|
|
25885
26482
|
let logFd = "ignore";
|
|
25886
26483
|
try {
|
|
25887
26484
|
logFd = openSync3(logPath, "a");
|