@askexenow/exe-os 0.9.64 → 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 +2280 -1199
- 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 +116 -7
- 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 +310 -178
- 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 +412 -157
- 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 +195 -79
- package/dist/index.js +24 -0
- package/dist/lib/agent-config.js +4 -0
- package/dist/lib/cloud-sync.js +50 -6
- 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 +1144 -480
- 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 +1045 -427
- 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,37 +20229,49 @@ 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;
|
|
20236
|
+
function isTruthyEnv(value) {
|
|
20237
|
+
return /^(1|true|yes|on)$/i.test(value ?? "");
|
|
20238
|
+
}
|
|
19778
20239
|
function loadPgClient() {
|
|
19779
20240
|
if (_pgFailed) return null;
|
|
19780
|
-
const
|
|
19781
|
-
const configPath = path34.join(EXE_AI_DIR, "config.json");
|
|
20241
|
+
const configPath = path35.join(EXE_AI_DIR, "config.json");
|
|
19782
20242
|
let cloudPostgresUrl;
|
|
20243
|
+
let configEnabled = false;
|
|
19783
20244
|
try {
|
|
19784
|
-
if (
|
|
19785
|
-
const cfg = JSON.parse(
|
|
20245
|
+
if (existsSync30(configPath)) {
|
|
20246
|
+
const cfg = JSON.parse(readFileSync23(configPath, "utf8"));
|
|
19786
20247
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
19787
|
-
|
|
19788
|
-
_pgFailed = true;
|
|
19789
|
-
return null;
|
|
19790
|
-
}
|
|
20248
|
+
configEnabled = cfg.cloud?.syncToPostgres === true;
|
|
19791
20249
|
}
|
|
19792
20250
|
} catch {
|
|
19793
20251
|
}
|
|
19794
|
-
const
|
|
20252
|
+
const envEnabled = isTruthyEnv(process.env.EXE_CLOUD_SYNC_TO_POSTGRES);
|
|
20253
|
+
if (!envEnabled && !configEnabled) {
|
|
20254
|
+
return null;
|
|
20255
|
+
}
|
|
20256
|
+
const url = process.env.DATABASE_URL || cloudPostgresUrl;
|
|
19795
20257
|
if (!url) {
|
|
19796
20258
|
_pgFailed = true;
|
|
19797
20259
|
return null;
|
|
19798
20260
|
}
|
|
19799
20261
|
if (!_pgPromise) {
|
|
19800
20262
|
_pgPromise = (async () => {
|
|
20263
|
+
if (!process.env.DATABASE_URL) process.env.DATABASE_URL = url;
|
|
19801
20264
|
const { createRequire: createRequire6 } = await import("module");
|
|
19802
20265
|
const { pathToFileURL: pathToFileURL6 } = await import("url");
|
|
19803
|
-
const
|
|
19804
|
-
|
|
20266
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
20267
|
+
if (explicitPath) {
|
|
20268
|
+
const mod2 = await import(pathToFileURL6(explicitPath).href);
|
|
20269
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
20270
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
20271
|
+
return new Ctor2();
|
|
20272
|
+
}
|
|
20273
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path35.join(homedir6(), "exe-db");
|
|
20274
|
+
const req = createRequire6(path35.join(exeDbRoot, "package.json"));
|
|
19805
20275
|
const entry = req.resolve("@prisma/client");
|
|
19806
20276
|
const mod = await import(pathToFileURL6(entry).href);
|
|
19807
20277
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -19846,18 +20316,18 @@ async function withRosterLock(fn) {
|
|
|
19846
20316
|
try {
|
|
19847
20317
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
19848
20318
|
closeSync2(fd);
|
|
19849
|
-
|
|
20319
|
+
writeFileSync17(ROSTER_LOCK_PATH, String(Date.now()));
|
|
19850
20320
|
} catch (err) {
|
|
19851
20321
|
if (err.code === "EEXIST") {
|
|
19852
20322
|
try {
|
|
19853
|
-
const ts2 = parseInt(
|
|
20323
|
+
const ts2 = parseInt(readFileSync23(ROSTER_LOCK_PATH, "utf-8"), 10);
|
|
19854
20324
|
if (Date.now() - ts2 < LOCK_STALE_MS) {
|
|
19855
20325
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
19856
20326
|
}
|
|
19857
20327
|
unlinkSync11(ROSTER_LOCK_PATH);
|
|
19858
20328
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
19859
20329
|
closeSync2(fd);
|
|
19860
|
-
|
|
20330
|
+
writeFileSync17(ROSTER_LOCK_PATH, String(Date.now()));
|
|
19861
20331
|
} catch (retryErr) {
|
|
19862
20332
|
if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
|
|
19863
20333
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
@@ -19976,6 +20446,16 @@ async function cloudPull(sinceVersion, config2) {
|
|
|
19976
20446
|
return { records: [], maxVersion: sinceVersion };
|
|
19977
20447
|
}
|
|
19978
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
|
+
}
|
|
19979
20459
|
async function cloudSync(config2) {
|
|
19980
20460
|
if (!isSyncCryptoInitialized()) {
|
|
19981
20461
|
try {
|
|
@@ -19996,6 +20476,12 @@ async function cloudSync(config2) {
|
|
|
19996
20476
|
} catch {
|
|
19997
20477
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
19998
20478
|
}
|
|
20479
|
+
try {
|
|
20480
|
+
if (await getCloudRelinkRequired(client)) throw new Error(CLOUD_RELINK_REQUIRED_MESSAGE);
|
|
20481
|
+
} catch (err) {
|
|
20482
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
20483
|
+
if (msg.includes("Paused after key rotation")) throw err;
|
|
20484
|
+
}
|
|
19999
20485
|
try {
|
|
20000
20486
|
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
20001
20487
|
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
@@ -20241,8 +20727,8 @@ async function cloudSync(config2) {
|
|
|
20241
20727
|
try {
|
|
20242
20728
|
const employees = await loadEmployees();
|
|
20243
20729
|
rosterResult.employees = employees.length;
|
|
20244
|
-
const idDir =
|
|
20245
|
-
if (
|
|
20730
|
+
const idDir = path35.join(EXE_AI_DIR, "identity");
|
|
20731
|
+
if (existsSync30(idDir)) {
|
|
20246
20732
|
rosterResult.identities = readdirSync11(idDir).filter((f) => f.endsWith(".md")).length;
|
|
20247
20733
|
}
|
|
20248
20734
|
} catch {
|
|
@@ -20255,7 +20741,7 @@ async function cloudSync(config2) {
|
|
|
20255
20741
|
const backupSize = statSync5(latestBackup).size;
|
|
20256
20742
|
const MAX_CLOUD_BACKUP_BYTES = 50 * 1024 * 1024;
|
|
20257
20743
|
if (backupSize <= MAX_CLOUD_BACKUP_BYTES) {
|
|
20258
|
-
const backupData =
|
|
20744
|
+
const backupData = readFileSync23(latestBackup);
|
|
20259
20745
|
const deviceId = loadDeviceId() ?? "unknown";
|
|
20260
20746
|
const encrypted = encryptSyncBlob(backupData);
|
|
20261
20747
|
const backupRes = await fetchWithRetry(`${config2.endpoint}/sync/push-db-backup`, {
|
|
@@ -20263,7 +20749,7 @@ async function cloudSync(config2) {
|
|
|
20263
20749
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${config2.apiKey}` },
|
|
20264
20750
|
body: JSON.stringify({
|
|
20265
20751
|
device_id: deviceId,
|
|
20266
|
-
filename:
|
|
20752
|
+
filename: path35.basename(latestBackup),
|
|
20267
20753
|
blob: encrypted,
|
|
20268
20754
|
size: backupData.length
|
|
20269
20755
|
})
|
|
@@ -20288,49 +20774,49 @@ async function cloudSync(config2) {
|
|
|
20288
20774
|
roster: rosterResult
|
|
20289
20775
|
};
|
|
20290
20776
|
}
|
|
20291
|
-
var ROSTER_DELETIONS_PATH =
|
|
20777
|
+
var ROSTER_DELETIONS_PATH = path35.join(EXE_AI_DIR, "roster-deletions.json");
|
|
20292
20778
|
function consumeRosterDeletions() {
|
|
20293
20779
|
try {
|
|
20294
|
-
if (!
|
|
20295
|
-
const deletions = JSON.parse(
|
|
20296
|
-
|
|
20780
|
+
if (!existsSync30(ROSTER_DELETIONS_PATH)) return [];
|
|
20781
|
+
const deletions = JSON.parse(readFileSync23(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
20782
|
+
writeFileSync17(ROSTER_DELETIONS_PATH, "[]");
|
|
20297
20783
|
return deletions;
|
|
20298
20784
|
} catch {
|
|
20299
20785
|
return [];
|
|
20300
20786
|
}
|
|
20301
20787
|
}
|
|
20302
20788
|
function buildRosterBlob(paths) {
|
|
20303
|
-
const rosterPath = paths?.rosterPath ??
|
|
20304
|
-
const identityDir = paths?.identityDir ??
|
|
20305
|
-
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");
|
|
20306
20792
|
let roster = [];
|
|
20307
|
-
if (
|
|
20793
|
+
if (existsSync30(rosterPath)) {
|
|
20308
20794
|
try {
|
|
20309
|
-
roster = JSON.parse(
|
|
20795
|
+
roster = JSON.parse(readFileSync23(rosterPath, "utf-8"));
|
|
20310
20796
|
} catch {
|
|
20311
20797
|
}
|
|
20312
20798
|
}
|
|
20313
20799
|
const identities = {};
|
|
20314
|
-
if (
|
|
20800
|
+
if (existsSync30(identityDir)) {
|
|
20315
20801
|
for (const file of readdirSync11(identityDir).filter((f) => f.endsWith(".md"))) {
|
|
20316
20802
|
try {
|
|
20317
|
-
identities[file] =
|
|
20803
|
+
identities[file] = readFileSync23(path35.join(identityDir, file), "utf-8");
|
|
20318
20804
|
} catch {
|
|
20319
20805
|
}
|
|
20320
20806
|
}
|
|
20321
20807
|
}
|
|
20322
20808
|
let config2;
|
|
20323
|
-
if (
|
|
20809
|
+
if (existsSync30(configPath)) {
|
|
20324
20810
|
try {
|
|
20325
|
-
config2 = JSON.parse(
|
|
20811
|
+
config2 = JSON.parse(readFileSync23(configPath, "utf-8"));
|
|
20326
20812
|
} catch {
|
|
20327
20813
|
}
|
|
20328
20814
|
}
|
|
20329
20815
|
let agentConfig;
|
|
20330
|
-
const agentConfigPath =
|
|
20331
|
-
if (
|
|
20816
|
+
const agentConfigPath = path35.join(EXE_AI_DIR, "agent-config.json");
|
|
20817
|
+
if (existsSync30(agentConfigPath)) {
|
|
20332
20818
|
try {
|
|
20333
|
-
agentConfig = JSON.parse(
|
|
20819
|
+
agentConfig = JSON.parse(readFileSync23(agentConfigPath, "utf-8"));
|
|
20334
20820
|
} catch {
|
|
20335
20821
|
}
|
|
20336
20822
|
}
|
|
@@ -20406,24 +20892,24 @@ async function cloudPullRoster(config2) {
|
|
|
20406
20892
|
}
|
|
20407
20893
|
}
|
|
20408
20894
|
function mergeConfig(remoteConfig, configPath) {
|
|
20409
|
-
const cfgPath = configPath ??
|
|
20895
|
+
const cfgPath = configPath ?? path35.join(EXE_AI_DIR, "config.json");
|
|
20410
20896
|
let local = {};
|
|
20411
|
-
if (
|
|
20897
|
+
if (existsSync30(cfgPath)) {
|
|
20412
20898
|
try {
|
|
20413
|
-
local = JSON.parse(
|
|
20899
|
+
local = JSON.parse(readFileSync23(cfgPath, "utf-8"));
|
|
20414
20900
|
} catch {
|
|
20415
20901
|
}
|
|
20416
20902
|
}
|
|
20417
20903
|
const merged = { ...remoteConfig, ...local };
|
|
20418
|
-
const dir =
|
|
20904
|
+
const dir = path35.dirname(cfgPath);
|
|
20419
20905
|
ensurePrivateDirSync(dir);
|
|
20420
|
-
|
|
20906
|
+
writeFileSync17(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
20421
20907
|
enforcePrivateFileSync(cfgPath);
|
|
20422
20908
|
}
|
|
20423
20909
|
async function mergeRosterFromRemote(remote, paths) {
|
|
20424
20910
|
return withRosterLock(async () => {
|
|
20425
20911
|
const rosterPath = paths?.rosterPath ?? void 0;
|
|
20426
|
-
const identityDir = paths?.identityDir ??
|
|
20912
|
+
const identityDir = paths?.identityDir ?? path35.join(EXE_AI_DIR, "identity");
|
|
20427
20913
|
const localEmployees = await loadEmployees(rosterPath);
|
|
20428
20914
|
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
20429
20915
|
let added = 0;
|
|
@@ -20444,15 +20930,15 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
20444
20930
|
) ?? lookupKey;
|
|
20445
20931
|
const remoteIdentity = remote.identities[matchedKey];
|
|
20446
20932
|
if (remoteIdentity) {
|
|
20447
|
-
if (!
|
|
20448
|
-
const idPath =
|
|
20933
|
+
if (!existsSync30(identityDir)) mkdirSync15(identityDir, { recursive: true });
|
|
20934
|
+
const idPath = path35.join(identityDir, `${remoteEmp.name}.md`);
|
|
20449
20935
|
let localIdentity = null;
|
|
20450
20936
|
try {
|
|
20451
|
-
localIdentity =
|
|
20937
|
+
localIdentity = existsSync30(idPath) ? readFileSync23(idPath, "utf-8") : null;
|
|
20452
20938
|
} catch {
|
|
20453
20939
|
}
|
|
20454
20940
|
if (localIdentity !== remoteIdentity) {
|
|
20455
|
-
|
|
20941
|
+
writeFileSync17(idPath, remoteIdentity, "utf-8");
|
|
20456
20942
|
identitiesUpdated++;
|
|
20457
20943
|
}
|
|
20458
20944
|
}
|
|
@@ -20478,17 +20964,17 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
20478
20964
|
}
|
|
20479
20965
|
if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
|
|
20480
20966
|
try {
|
|
20481
|
-
const agentConfigPath =
|
|
20967
|
+
const agentConfigPath = path35.join(EXE_AI_DIR, "agent-config.json");
|
|
20482
20968
|
let local = {};
|
|
20483
|
-
if (
|
|
20969
|
+
if (existsSync30(agentConfigPath)) {
|
|
20484
20970
|
try {
|
|
20485
|
-
local = JSON.parse(
|
|
20971
|
+
local = JSON.parse(readFileSync23(agentConfigPath, "utf-8"));
|
|
20486
20972
|
} catch {
|
|
20487
20973
|
}
|
|
20488
20974
|
}
|
|
20489
20975
|
const merged = { ...remote.agentConfig, ...local };
|
|
20490
|
-
ensurePrivateDirSync(
|
|
20491
|
-
|
|
20976
|
+
ensurePrivateDirSync(path35.dirname(agentConfigPath));
|
|
20977
|
+
writeFileSync17(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
20492
20978
|
enforcePrivateFileSync(agentConfigPath);
|
|
20493
20979
|
} catch {
|
|
20494
20980
|
}
|
|
@@ -20974,9 +21460,136 @@ function registerCloudSync(server2) {
|
|
|
20974
21460
|
);
|
|
20975
21461
|
}
|
|
20976
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
|
+
|
|
20977
21590
|
// src/mcp/tools/backup-vps.ts
|
|
20978
21591
|
init_keychain();
|
|
20979
|
-
import { z as
|
|
21592
|
+
import { z as z60 } from "zod";
|
|
20980
21593
|
|
|
20981
21594
|
// src/lib/vps-backup.ts
|
|
20982
21595
|
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
@@ -21301,43 +21914,43 @@ function registerBackupVps(server2) {
|
|
|
21301
21914
|
{
|
|
21302
21915
|
title: "VPS Backup",
|
|
21303
21916
|
description: "Run VPS Postgres backup/restore workflows and check status.",
|
|
21304
|
-
inputSchema:
|
|
21305
|
-
|
|
21306
|
-
action:
|
|
21307
|
-
databaseUrl:
|
|
21308
|
-
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(
|
|
21309
21922
|
"Base64 AES-256 key (defaults to local master key if omitted)"
|
|
21310
21923
|
),
|
|
21311
|
-
r2Bucket:
|
|
21312
|
-
r2Endpoint:
|
|
21313
|
-
r2AccessKeyId:
|
|
21314
|
-
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")
|
|
21315
21928
|
}),
|
|
21316
|
-
|
|
21317
|
-
action:
|
|
21318
|
-
databaseUrl:
|
|
21319
|
-
backupKey:
|
|
21320
|
-
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(
|
|
21321
21934
|
"Base64 AES-256 key (defaults to local master key if omitted)"
|
|
21322
21935
|
),
|
|
21323
|
-
r2Bucket:
|
|
21324
|
-
r2Endpoint:
|
|
21325
|
-
r2AccessKeyId:
|
|
21326
|
-
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")
|
|
21327
21940
|
}),
|
|
21328
|
-
|
|
21329
|
-
action:
|
|
21330
|
-
r2Bucket:
|
|
21331
|
-
r2Endpoint:
|
|
21332
|
-
r2AccessKeyId:
|
|
21333
|
-
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")
|
|
21334
21947
|
}),
|
|
21335
|
-
|
|
21336
|
-
action:
|
|
21337
|
-
r2Bucket:
|
|
21338
|
-
r2Endpoint:
|
|
21339
|
-
r2AccessKeyId:
|
|
21340
|
-
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")
|
|
21341
21954
|
})
|
|
21342
21955
|
])
|
|
21343
21956
|
},
|
|
@@ -21475,11 +22088,11 @@ async function resolveEncryptionKey(providedB64) {
|
|
|
21475
22088
|
}
|
|
21476
22089
|
|
|
21477
22090
|
// src/mcp/tools/deploy-client.ts
|
|
21478
|
-
import { z as
|
|
22091
|
+
import { z as z61 } from "zod";
|
|
21479
22092
|
import { execFile } from "child_process";
|
|
21480
22093
|
import { promisify } from "util";
|
|
21481
|
-
import
|
|
21482
|
-
import { existsSync as
|
|
22094
|
+
import path36 from "path";
|
|
22095
|
+
import { existsSync as existsSync31 } from "fs";
|
|
21483
22096
|
|
|
21484
22097
|
// src/lib/hostinger-api.ts
|
|
21485
22098
|
var DEFAULT_BASE_URL = "https://developers.hostinger.com/api/vps/v1";
|
|
@@ -21527,9 +22140,9 @@ var HostingerApiClient = class {
|
|
|
21527
22140
|
}
|
|
21528
22141
|
this.lastRequestTime = Date.now();
|
|
21529
22142
|
}
|
|
21530
|
-
async request(method,
|
|
22143
|
+
async request(method, path49, body) {
|
|
21531
22144
|
await this.rateLimit();
|
|
21532
|
-
const url = `${this.baseUrl}${
|
|
22145
|
+
const url = `${this.baseUrl}${path49}`;
|
|
21533
22146
|
const headers = {
|
|
21534
22147
|
Authorization: `Bearer ${this.apiKey}`,
|
|
21535
22148
|
"Content-Type": "application/json",
|
|
@@ -21602,8 +22215,8 @@ async function requestCloudflare(cfApiToken, zoneId, options) {
|
|
|
21602
22215
|
}
|
|
21603
22216
|
return envelope.result;
|
|
21604
22217
|
}
|
|
21605
|
-
function buildUrl(zoneId,
|
|
21606
|
-
const normalizedPath =
|
|
22218
|
+
function buildUrl(zoneId, path49 = "/dns_records", query) {
|
|
22219
|
+
const normalizedPath = path49.startsWith("/") ? path49 : `/${path49}`;
|
|
21607
22220
|
const url = new URL(
|
|
21608
22221
|
`${CLOUDFLARE_API_BASE_URL}/zones/${zoneId}${normalizedPath}`
|
|
21609
22222
|
);
|
|
@@ -21743,12 +22356,12 @@ function registerDeployClient(server2) {
|
|
|
21743
22356
|
title: "Deploy Client",
|
|
21744
22357
|
description: "Provision a Hostinger VPS and deploy exe-os for a client. Creates VPS, waits for ready state, runs Ansible playbook, verifies health.",
|
|
21745
22358
|
inputSchema: {
|
|
21746
|
-
client_name:
|
|
21747
|
-
domain:
|
|
21748
|
-
region:
|
|
21749
|
-
plan:
|
|
21750
|
-
ssl_email:
|
|
21751
|
-
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")
|
|
21752
22365
|
}
|
|
21753
22366
|
},
|
|
21754
22367
|
async ({ client_name, domain, region, plan, ssl_email, user_id }) => {
|
|
@@ -21816,12 +22429,12 @@ async function waitForReady(client, vpsId) {
|
|
|
21816
22429
|
}
|
|
21817
22430
|
async function runAnsiblePlaybook(vpsIp, domain, sslEmail, clientName) {
|
|
21818
22431
|
const safeClientName = clientName.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
21819
|
-
const playbookDir =
|
|
21820
|
-
const playbookPath =
|
|
21821
|
-
const inventoryPath =
|
|
21822
|
-
const clientVarsPath =
|
|
21823
|
-
const varsDir =
|
|
21824
|
-
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))) {
|
|
21825
22438
|
throw new Error(`Invalid client name for vars path: ${clientName}`);
|
|
21826
22439
|
}
|
|
21827
22440
|
const args = [
|
|
@@ -21837,7 +22450,7 @@ async function runAnsiblePlaybook(vpsIp, domain, sslEmail, clientName) {
|
|
|
21837
22450
|
"-e",
|
|
21838
22451
|
`client_name=${safeClientName}`
|
|
21839
22452
|
];
|
|
21840
|
-
if (
|
|
22453
|
+
if (existsSync31(clientVarsPath)) {
|
|
21841
22454
|
args.push("-e", `@${clientVarsPath}`);
|
|
21842
22455
|
}
|
|
21843
22456
|
try {
|
|
@@ -21910,7 +22523,7 @@ function buildInventoryRecord(params) {
|
|
|
21910
22523
|
|
|
21911
22524
|
// src/mcp/tools/get-license-status.ts
|
|
21912
22525
|
init_license();
|
|
21913
|
-
import { z as
|
|
22526
|
+
import { z as z62 } from "zod";
|
|
21914
22527
|
var FEATURES = [
|
|
21915
22528
|
"cloud_sync",
|
|
21916
22529
|
"external_agents",
|
|
@@ -21924,7 +22537,7 @@ function registerGetLicenseStatus(server2) {
|
|
|
21924
22537
|
title: "Get License Status",
|
|
21925
22538
|
description: "Get current license status: plan, validity, feature gates, limits, and expiry.",
|
|
21926
22539
|
inputSchema: {
|
|
21927
|
-
_dummy:
|
|
22540
|
+
_dummy: z62.string().optional().describe("Unused \u2014 no input required")
|
|
21928
22541
|
}
|
|
21929
22542
|
},
|
|
21930
22543
|
async () => {
|
|
@@ -21978,11 +22591,11 @@ function registerGetLicenseStatus(server2) {
|
|
|
21978
22591
|
// src/mcp/tools/create-license.ts
|
|
21979
22592
|
init_license();
|
|
21980
22593
|
import os15 from "os";
|
|
21981
|
-
import
|
|
22594
|
+
import path37 from "path";
|
|
21982
22595
|
import { randomBytes as randomBytes2, randomUUID as randomUUID6 } from "crypto";
|
|
21983
22596
|
import { createRequire as createRequire3 } from "module";
|
|
21984
22597
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
21985
|
-
import { z as
|
|
22598
|
+
import { z as z63 } from "zod";
|
|
21986
22599
|
var prismaPromise = null;
|
|
21987
22600
|
function loadPrisma() {
|
|
21988
22601
|
if (!prismaPromise) {
|
|
@@ -21994,8 +22607,8 @@ function loadPrisma() {
|
|
|
21994
22607
|
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
21995
22608
|
return new Ctor2();
|
|
21996
22609
|
}
|
|
21997
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
21998
|
-
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"));
|
|
21999
22612
|
const entry = req.resolve("@prisma/client");
|
|
22000
22613
|
const mod = await import(pathToFileURL3(entry).href);
|
|
22001
22614
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -22015,10 +22628,10 @@ function registerCreateLicense(server2) {
|
|
|
22015
22628
|
title: "Create License",
|
|
22016
22629
|
description: "Generate an exe_sk_* license key for a user. Stores in billing.licenses. Returns the key to give to the customer.",
|
|
22017
22630
|
inputSchema: {
|
|
22018
|
-
email:
|
|
22019
|
-
name:
|
|
22020
|
-
plan:
|
|
22021
|
-
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)")
|
|
22022
22635
|
}
|
|
22023
22636
|
},
|
|
22024
22637
|
async ({ email, name, plan, expires_in_days }) => {
|
|
@@ -22070,10 +22683,10 @@ Give this key to the customer. They paste it during \`exe-os setup\`.`);
|
|
|
22070
22683
|
|
|
22071
22684
|
// src/mcp/tools/list-licenses.ts
|
|
22072
22685
|
import os16 from "os";
|
|
22073
|
-
import
|
|
22686
|
+
import path38 from "path";
|
|
22074
22687
|
import { createRequire as createRequire4 } from "module";
|
|
22075
22688
|
import { pathToFileURL as pathToFileURL4 } from "url";
|
|
22076
|
-
import { z as
|
|
22689
|
+
import { z as z64 } from "zod";
|
|
22077
22690
|
var prismaPromise2 = null;
|
|
22078
22691
|
function loadPrisma2() {
|
|
22079
22692
|
if (!prismaPromise2) {
|
|
@@ -22085,8 +22698,8 @@ function loadPrisma2() {
|
|
|
22085
22698
|
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
22086
22699
|
return new Ctor2();
|
|
22087
22700
|
}
|
|
22088
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
22089
|
-
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"));
|
|
22090
22703
|
const entry = req.resolve("@prisma/client");
|
|
22091
22704
|
const mod = await import(pathToFileURL4(entry).href);
|
|
22092
22705
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -22103,7 +22716,7 @@ function registerListLicenses(server2) {
|
|
|
22103
22716
|
title: "List Licenses",
|
|
22104
22717
|
description: "List all issued licenses with status (active/expired/revoked). Optionally filter by plan.",
|
|
22105
22718
|
inputSchema: {
|
|
22106
|
-
plan:
|
|
22719
|
+
plan: z64.enum(["free", "pro", "team", "agency", "enterprise"]).optional().describe("Filter by plan tier (omit for all)")
|
|
22107
22720
|
}
|
|
22108
22721
|
},
|
|
22109
22722
|
async ({ plan }) => {
|
|
@@ -22154,7 +22767,7 @@ function registerListLicenses(server2) {
|
|
|
22154
22767
|
|
|
22155
22768
|
// src/mcp/tools/activate-license.ts
|
|
22156
22769
|
init_license();
|
|
22157
|
-
import { z as
|
|
22770
|
+
import { z as z65 } from "zod";
|
|
22158
22771
|
function registerActivateLicense(server2) {
|
|
22159
22772
|
server2.registerTool(
|
|
22160
22773
|
"activate_license",
|
|
@@ -22162,7 +22775,7 @@ function registerActivateLicense(server2) {
|
|
|
22162
22775
|
title: "Activate License",
|
|
22163
22776
|
description: "Activate an exe_sk_* license key on this device. Writes to ~/.exe-os/license.key, validates against Postgres, and caches the result.",
|
|
22164
22777
|
inputSchema: {
|
|
22165
|
-
key:
|
|
22778
|
+
key: z65.string().startsWith("exe_sk_").describe("License key (exe_sk_*)")
|
|
22166
22779
|
}
|
|
22167
22780
|
},
|
|
22168
22781
|
async ({ key }) => {
|
|
@@ -22208,18 +22821,18 @@ Key saved to ~/.exe-os/license.key. Device ID: ${deviceId}`);
|
|
|
22208
22821
|
}
|
|
22209
22822
|
|
|
22210
22823
|
// src/mcp/tools/create-trigger.ts
|
|
22211
|
-
import { z as
|
|
22824
|
+
import { z as z66 } from "zod";
|
|
22212
22825
|
|
|
22213
22826
|
// src/automation/trigger-engine.ts
|
|
22214
|
-
import { readFileSync as
|
|
22827
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync18, existsSync as existsSync32, mkdirSync as mkdirSync16 } from "fs";
|
|
22215
22828
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
22216
|
-
import
|
|
22829
|
+
import path39 from "path";
|
|
22217
22830
|
import os17 from "os";
|
|
22218
|
-
var TRIGGERS_PATH =
|
|
22831
|
+
var TRIGGERS_PATH = path39.join(os17.homedir(), ".exe-os", "triggers.json");
|
|
22219
22832
|
function loadTriggers(project) {
|
|
22220
|
-
if (!
|
|
22833
|
+
if (!existsSync32(TRIGGERS_PATH)) return [];
|
|
22221
22834
|
try {
|
|
22222
|
-
const raw =
|
|
22835
|
+
const raw = readFileSync24(TRIGGERS_PATH, "utf-8");
|
|
22223
22836
|
const all = JSON.parse(raw);
|
|
22224
22837
|
if (!Array.isArray(all)) return [];
|
|
22225
22838
|
if (project) {
|
|
@@ -22231,9 +22844,9 @@ function loadTriggers(project) {
|
|
|
22231
22844
|
}
|
|
22232
22845
|
}
|
|
22233
22846
|
function saveTriggers(triggers) {
|
|
22234
|
-
const dir =
|
|
22235
|
-
if (!
|
|
22236
|
-
|
|
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");
|
|
22237
22850
|
}
|
|
22238
22851
|
function createNewTrigger(input) {
|
|
22239
22852
|
const triggers = loadTriggers();
|
|
@@ -22389,14 +23002,14 @@ function addToCrontab(id, cron, prompt, projectDir) {
|
|
|
22389
23002
|
}
|
|
22390
23003
|
|
|
22391
23004
|
// src/mcp/tools/create-trigger.ts
|
|
22392
|
-
var conditionSchema =
|
|
22393
|
-
field:
|
|
22394
|
-
op:
|
|
22395
|
-
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")
|
|
22396
23009
|
});
|
|
22397
|
-
var actionSchema =
|
|
22398
|
-
type:
|
|
22399
|
-
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(
|
|
22400
23013
|
"Action parameters. Supports {{record.field}} templates for dynamic values."
|
|
22401
23014
|
)
|
|
22402
23015
|
});
|
|
@@ -22407,18 +23020,18 @@ function registerCreateTrigger(server2) {
|
|
|
22407
23020
|
title: "Create Trigger",
|
|
22408
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.).",
|
|
22409
23022
|
inputSchema: {
|
|
22410
|
-
name:
|
|
22411
|
-
event:
|
|
23023
|
+
name: z66.string().describe("Human-readable trigger name"),
|
|
23024
|
+
event: z66.string().describe(
|
|
22412
23025
|
'CRM event to match, e.g., "Deal.updated", "Order.created", "*" for all'
|
|
22413
23026
|
),
|
|
22414
|
-
conditions:
|
|
22415
|
-
actions:
|
|
22416
|
-
project:
|
|
22417
|
-
enabled:
|
|
22418
|
-
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(
|
|
22419
23032
|
'Cron schedule for time-based triggers, e.g., "0 9 * * *" or "Monday 9am"'
|
|
22420
23033
|
),
|
|
22421
|
-
query:
|
|
23034
|
+
query: z66.string().optional().describe(
|
|
22422
23035
|
"CRM GraphQL query to run on schedule (required if schedule is set)"
|
|
22423
23036
|
)
|
|
22424
23037
|
}
|
|
@@ -22491,7 +23104,7 @@ Enabled: ${trigger.enabled}` + scheduleInfo;
|
|
|
22491
23104
|
}
|
|
22492
23105
|
|
|
22493
23106
|
// src/mcp/tools/list-triggers.ts
|
|
22494
|
-
import { z as
|
|
23107
|
+
import { z as z67 } from "zod";
|
|
22495
23108
|
function registerListTriggers(server2) {
|
|
22496
23109
|
server2.registerTool(
|
|
22497
23110
|
"list_triggers",
|
|
@@ -22499,7 +23112,7 @@ function registerListTriggers(server2) {
|
|
|
22499
23112
|
title: "List Triggers",
|
|
22500
23113
|
description: "List configured CRM event triggers and scheduled automations.",
|
|
22501
23114
|
inputSchema: {
|
|
22502
|
-
project:
|
|
23115
|
+
project: z67.string().optional().describe("Filter triggers by project name")
|
|
22503
23116
|
}
|
|
22504
23117
|
},
|
|
22505
23118
|
async ({ project }) => {
|
|
@@ -22534,51 +23147,51 @@ function registerListTriggers(server2) {
|
|
|
22534
23147
|
}
|
|
22535
23148
|
|
|
22536
23149
|
// src/mcp/tools/apply-starter-pack.ts
|
|
22537
|
-
import { z as
|
|
23150
|
+
import { z as z68 } from "zod";
|
|
22538
23151
|
|
|
22539
23152
|
// src/automation/starter-packs/index.ts
|
|
22540
|
-
import { readFileSync as
|
|
22541
|
-
import
|
|
23153
|
+
import { readFileSync as readFileSync25, readdirSync as readdirSync12, existsSync as existsSync33 } from "fs";
|
|
23154
|
+
import path40 from "path";
|
|
22542
23155
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
22543
|
-
var __dirname =
|
|
23156
|
+
var __dirname = path40.dirname(fileURLToPath4(import.meta.url));
|
|
22544
23157
|
function listPacks() {
|
|
22545
|
-
const packsDir =
|
|
22546
|
-
if (!
|
|
23158
|
+
const packsDir = path40.join(__dirname, ".");
|
|
23159
|
+
if (!existsSync33(packsDir)) return [];
|
|
22547
23160
|
return readdirSync12(packsDir, { withFileTypes: true }).filter(
|
|
22548
|
-
(d) => d.isDirectory() &&
|
|
23161
|
+
(d) => d.isDirectory() && existsSync33(path40.join(packsDir, d.name, "custom-objects.json"))
|
|
22549
23162
|
).map((d) => d.name);
|
|
22550
23163
|
}
|
|
22551
23164
|
function loadPack(industry) {
|
|
22552
|
-
const packDir =
|
|
22553
|
-
const objectsPath =
|
|
22554
|
-
const triggersPath =
|
|
22555
|
-
const wikiDir =
|
|
22556
|
-
const manifestPath =
|
|
22557
|
-
const identityContextPath =
|
|
22558
|
-
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;
|
|
22559
23172
|
let customObjects = [];
|
|
22560
23173
|
try {
|
|
22561
23174
|
customObjects = JSON.parse(
|
|
22562
|
-
|
|
23175
|
+
readFileSync25(objectsPath, "utf-8")
|
|
22563
23176
|
);
|
|
22564
23177
|
} catch {
|
|
22565
23178
|
customObjects = [];
|
|
22566
23179
|
}
|
|
22567
23180
|
let triggers = [];
|
|
22568
|
-
if (
|
|
23181
|
+
if (existsSync33(triggersPath)) {
|
|
22569
23182
|
try {
|
|
22570
23183
|
triggers = JSON.parse(
|
|
22571
|
-
|
|
23184
|
+
readFileSync25(triggersPath, "utf-8")
|
|
22572
23185
|
);
|
|
22573
23186
|
} catch {
|
|
22574
23187
|
triggers = [];
|
|
22575
23188
|
}
|
|
22576
23189
|
}
|
|
22577
23190
|
const wikiSeeds = [];
|
|
22578
|
-
if (
|
|
23191
|
+
if (existsSync33(wikiDir)) {
|
|
22579
23192
|
const files = readdirSync12(wikiDir).filter((f) => f.endsWith(".md"));
|
|
22580
23193
|
for (const file of files) {
|
|
22581
|
-
const content =
|
|
23194
|
+
const content = readFileSync25(path40.join(wikiDir, file), "utf-8");
|
|
22582
23195
|
const titleMatch = content.match(/^#\s+(.+)/m);
|
|
22583
23196
|
wikiSeeds.push({
|
|
22584
23197
|
filename: file,
|
|
@@ -22588,17 +23201,17 @@ function loadPack(industry) {
|
|
|
22588
23201
|
}
|
|
22589
23202
|
}
|
|
22590
23203
|
let manifest = {};
|
|
22591
|
-
if (
|
|
23204
|
+
if (existsSync33(manifestPath)) {
|
|
22592
23205
|
try {
|
|
22593
|
-
manifest = JSON.parse(
|
|
23206
|
+
manifest = JSON.parse(readFileSync25(manifestPath, "utf-8"));
|
|
22594
23207
|
} catch {
|
|
22595
23208
|
manifest = {};
|
|
22596
23209
|
}
|
|
22597
23210
|
}
|
|
22598
23211
|
let identityContext = null;
|
|
22599
|
-
if (
|
|
23212
|
+
if (existsSync33(identityContextPath)) {
|
|
22600
23213
|
try {
|
|
22601
|
-
identityContext =
|
|
23214
|
+
identityContext = readFileSync25(identityContextPath, "utf-8");
|
|
22602
23215
|
} catch {
|
|
22603
23216
|
identityContext = null;
|
|
22604
23217
|
}
|
|
@@ -22655,8 +23268,8 @@ function applyPack(industry, project) {
|
|
|
22655
23268
|
|
|
22656
23269
|
// src/lib/client-coo.ts
|
|
22657
23270
|
init_config();
|
|
22658
|
-
import { existsSync as
|
|
22659
|
-
import
|
|
23271
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync17, writeFileSync as writeFileSync19 } from "fs";
|
|
23272
|
+
import path41 from "path";
|
|
22660
23273
|
|
|
22661
23274
|
// src/lib/employee-templates.ts
|
|
22662
23275
|
init_global_procedures();
|
|
@@ -22796,18 +23409,18 @@ var ClientCOOClobberError = class extends Error {
|
|
|
22796
23409
|
var COO_ROLE = "Chief Operating Officer";
|
|
22797
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.";
|
|
22798
23411
|
async function provisionClientCOO(vars, opts = {}) {
|
|
22799
|
-
const identityDir = opts.identityDir ??
|
|
23412
|
+
const identityDir = opts.identityDir ?? path41.join(EXE_AI_DIR, "identity");
|
|
22800
23413
|
const rosterPath = opts.employeesPath ?? EMPLOYEES_PATH;
|
|
22801
23414
|
const storeFeedbackBehavior = opts.storeFeedbackBehavior ?? true;
|
|
22802
|
-
const identityPath2 =
|
|
22803
|
-
if (
|
|
23415
|
+
const identityPath2 = path41.join(identityDir, `${vars.agent_name}.md`);
|
|
23416
|
+
if (existsSync34(identityPath2)) {
|
|
22804
23417
|
throw new ClientCOOClobberError(vars.agent_name, identityPath2);
|
|
22805
23418
|
}
|
|
22806
23419
|
const body = renderClientCOOTemplate(vars);
|
|
22807
|
-
if (!
|
|
22808
|
-
|
|
23420
|
+
if (!existsSync34(identityDir)) {
|
|
23421
|
+
mkdirSync17(identityDir, { recursive: true });
|
|
22809
23422
|
}
|
|
22810
|
-
|
|
23423
|
+
writeFileSync19(identityPath2, body, "utf-8");
|
|
22811
23424
|
const employees = await loadEmployees(rosterPath);
|
|
22812
23425
|
const existing = employees.find((e) => e.name === vars.agent_name);
|
|
22813
23426
|
let addedToRoster = false;
|
|
@@ -22843,17 +23456,17 @@ function registerApplyStarterPack(server2) {
|
|
|
22843
23456
|
title: "Apply Starter Pack",
|
|
22844
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.",
|
|
22845
23458
|
inputSchema: {
|
|
22846
|
-
industry:
|
|
23459
|
+
industry: z68.string().describe(
|
|
22847
23460
|
'Industry pack to apply (e.g., "distribution"). Use without args to list available packs.'
|
|
22848
23461
|
),
|
|
22849
|
-
project:
|
|
22850
|
-
agent_name:
|
|
23462
|
+
project: z68.string().describe("Project name to scope the triggers to"),
|
|
23463
|
+
agent_name: z68.string().optional().describe(
|
|
22851
23464
|
"Optional. Lowercase alphanumeric name for the Client COO agent. Required (alongside company_name and founder_name) to provision a COO."
|
|
22852
23465
|
),
|
|
22853
|
-
company_name:
|
|
23466
|
+
company_name: z68.string().optional().describe(
|
|
22854
23467
|
"Optional. The client company the COO serves. Required to provision a COO."
|
|
22855
23468
|
),
|
|
22856
|
-
founder_name:
|
|
23469
|
+
founder_name: z68.string().optional().describe(
|
|
22857
23470
|
"Optional. The founder the COO reports to. Required to provision a COO."
|
|
22858
23471
|
)
|
|
22859
23472
|
}
|
|
@@ -22998,19 +23611,19 @@ ${err.message}`
|
|
|
22998
23611
|
}
|
|
22999
23612
|
|
|
23000
23613
|
// src/mcp/tools/load-skill.ts
|
|
23001
|
-
import { z as
|
|
23002
|
-
import { readFileSync as
|
|
23003
|
-
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";
|
|
23004
23617
|
import { homedir as homedir7 } from "os";
|
|
23005
|
-
var SKILLS_DIR =
|
|
23618
|
+
var SKILLS_DIR = path42.join(homedir7(), ".claude", "skills");
|
|
23006
23619
|
function listAvailableSkills() {
|
|
23007
23620
|
try {
|
|
23008
23621
|
const entries = readdirSync13(SKILLS_DIR);
|
|
23009
23622
|
return entries.filter((entry) => {
|
|
23010
23623
|
try {
|
|
23011
|
-
const entryPath =
|
|
23624
|
+
const entryPath = path42.join(SKILLS_DIR, entry);
|
|
23012
23625
|
if (!statSync6(entryPath).isDirectory()) return false;
|
|
23013
|
-
const skillFile =
|
|
23626
|
+
const skillFile = path42.join(entryPath, "SKILL.md");
|
|
23014
23627
|
statSync6(skillFile);
|
|
23015
23628
|
return true;
|
|
23016
23629
|
} catch {
|
|
@@ -23028,7 +23641,7 @@ function registerLoadSkill(server2) {
|
|
|
23028
23641
|
title: "Load Skill",
|
|
23029
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.",
|
|
23030
23643
|
inputSchema: {
|
|
23031
|
-
skill_name:
|
|
23644
|
+
skill_name: z69.string().describe(
|
|
23032
23645
|
"Skill to load (e.g. 'seo', 'code-reviewer', 'frontend-design'). Pass 'list' to see all available skills."
|
|
23033
23646
|
)
|
|
23034
23647
|
}
|
|
@@ -23053,10 +23666,10 @@ ${skills.map((s) => `- ${s}`).join("\n")}`
|
|
|
23053
23666
|
}]
|
|
23054
23667
|
};
|
|
23055
23668
|
}
|
|
23056
|
-
const sanitized =
|
|
23057
|
-
const skillFile =
|
|
23669
|
+
const sanitized = path42.basename(skill_name);
|
|
23670
|
+
const skillFile = path42.join(SKILLS_DIR, sanitized, "SKILL.md");
|
|
23058
23671
|
try {
|
|
23059
|
-
const content =
|
|
23672
|
+
const content = readFileSync26(skillFile, "utf-8");
|
|
23060
23673
|
return {
|
|
23061
23674
|
content: [{
|
|
23062
23675
|
type: "text",
|
|
@@ -23084,18 +23697,18 @@ ${available.map((s) => `- ${s}`).join("\n")}` : "\n\nNo skills found in ~/.claud
|
|
|
23084
23697
|
|
|
23085
23698
|
// src/mcp/tools/export-orchestration.ts
|
|
23086
23699
|
init_active_agent();
|
|
23087
|
-
import { mkdirSync as
|
|
23088
|
-
import
|
|
23089
|
-
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";
|
|
23090
23703
|
|
|
23091
23704
|
// src/lib/orchestration-package.ts
|
|
23092
23705
|
init_database();
|
|
23093
23706
|
init_identity();
|
|
23094
23707
|
init_platform_procedures();
|
|
23095
23708
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
23096
|
-
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";
|
|
23097
23710
|
import os18 from "os";
|
|
23098
|
-
import
|
|
23711
|
+
import path43 from "path";
|
|
23099
23712
|
var PACKAGE_VERSION = "1.0";
|
|
23100
23713
|
var ROSTER_FILENAME = "exe-employees.json";
|
|
23101
23714
|
var ROSTER_BACKUP_FILENAME = "exe-employees.json.bak";
|
|
@@ -23161,15 +23774,15 @@ function validateProcedureEntry(value, index) {
|
|
|
23161
23774
|
};
|
|
23162
23775
|
}
|
|
23163
23776
|
function getRosterPath() {
|
|
23164
|
-
return
|
|
23777
|
+
return path43.join(os18.homedir(), EXE_OS_DIRNAME, ROSTER_FILENAME);
|
|
23165
23778
|
}
|
|
23166
23779
|
function getBackupPath() {
|
|
23167
|
-
return
|
|
23780
|
+
return path43.join(os18.homedir(), EXE_OS_DIRNAME, ROSTER_BACKUP_FILENAME);
|
|
23168
23781
|
}
|
|
23169
23782
|
function readRosterFile() {
|
|
23170
23783
|
const rosterPath = getRosterPath();
|
|
23171
|
-
if (!
|
|
23172
|
-
const raw =
|
|
23784
|
+
if (!existsSync35(rosterPath)) return [];
|
|
23785
|
+
const raw = readFileSync27(rosterPath, "utf-8");
|
|
23173
23786
|
const parsed = JSON.parse(raw);
|
|
23174
23787
|
if (!Array.isArray(parsed)) {
|
|
23175
23788
|
throw new Error("Roster file must contain a JSON array");
|
|
@@ -23181,8 +23794,8 @@ function writeRosterFile(roster) {
|
|
|
23181
23794
|
throw new Error("Refusing to write empty roster \u2014 this would delete all employees");
|
|
23182
23795
|
}
|
|
23183
23796
|
const rosterPath = getRosterPath();
|
|
23184
|
-
|
|
23185
|
-
if (
|
|
23797
|
+
mkdirSync18(path43.dirname(rosterPath), { recursive: true });
|
|
23798
|
+
if (existsSync35(rosterPath)) {
|
|
23186
23799
|
const currentRoster = readRosterFile();
|
|
23187
23800
|
if (roster.length < currentRoster.length) {
|
|
23188
23801
|
throw new Error(
|
|
@@ -23191,7 +23804,7 @@ function writeRosterFile(roster) {
|
|
|
23191
23804
|
}
|
|
23192
23805
|
copyFileSync2(rosterPath, getBackupPath());
|
|
23193
23806
|
}
|
|
23194
|
-
|
|
23807
|
+
writeFileSync20(rosterPath, `${JSON.stringify(roster, null, 2)}
|
|
23195
23808
|
`, "utf-8");
|
|
23196
23809
|
}
|
|
23197
23810
|
function buildImportedRosterEntries(roster, timestamp) {
|
|
@@ -23446,15 +24059,15 @@ function registerExportOrchestration(server2) {
|
|
|
23446
24059
|
title: "Export Orchestration",
|
|
23447
24060
|
description: "Export roster, identities, behaviors, and customer procedures to a JSON package.",
|
|
23448
24061
|
inputSchema: {
|
|
23449
|
-
output_path:
|
|
24062
|
+
output_path: z70.string().describe("File path to write the JSON package")
|
|
23450
24063
|
}
|
|
23451
24064
|
},
|
|
23452
24065
|
async ({ output_path }) => {
|
|
23453
24066
|
try {
|
|
23454
24067
|
await initStore();
|
|
23455
24068
|
const pkg = await exportOrchestration(getActiveAgent().agentId);
|
|
23456
|
-
|
|
23457
|
-
|
|
24069
|
+
mkdirSync19(path44.dirname(output_path), { recursive: true });
|
|
24070
|
+
writeFileSync21(output_path, `${JSON.stringify(pkg, null, 2)}
|
|
23458
24071
|
`, "utf-8");
|
|
23459
24072
|
return {
|
|
23460
24073
|
content: [{
|
|
@@ -23476,8 +24089,8 @@ function registerExportOrchestration(server2) {
|
|
|
23476
24089
|
}
|
|
23477
24090
|
|
|
23478
24091
|
// src/mcp/tools/import-orchestration.ts
|
|
23479
|
-
import { readFileSync as
|
|
23480
|
-
import { z as
|
|
24092
|
+
import { readFileSync as readFileSync28 } from "fs";
|
|
24093
|
+
import { z as z71 } from "zod";
|
|
23481
24094
|
init_store();
|
|
23482
24095
|
init_active_agent();
|
|
23483
24096
|
init_employees();
|
|
@@ -23488,8 +24101,8 @@ function registerImportOrchestration(server2) {
|
|
|
23488
24101
|
title: "Import Orchestration",
|
|
23489
24102
|
description: "Import roster, identities, behaviors, and procedures from an orchestration package. Restricted to coordinator/founder.",
|
|
23490
24103
|
inputSchema: {
|
|
23491
|
-
package_path:
|
|
23492
|
-
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")
|
|
23493
24106
|
}
|
|
23494
24107
|
},
|
|
23495
24108
|
async ({ package_path, merge_strategy }) => {
|
|
@@ -23506,7 +24119,7 @@ function registerImportOrchestration(server2) {
|
|
|
23506
24119
|
};
|
|
23507
24120
|
}
|
|
23508
24121
|
await initStore();
|
|
23509
|
-
const raw =
|
|
24122
|
+
const raw = readFileSync28(package_path, "utf-8");
|
|
23510
24123
|
const pkg = validatePackage(JSON.parse(raw));
|
|
23511
24124
|
const result = await importOrchestration(pkg, merge_strategy);
|
|
23512
24125
|
return {
|
|
@@ -23534,7 +24147,7 @@ init_platform_procedures();
|
|
|
23534
24147
|
init_active_agent();
|
|
23535
24148
|
init_database();
|
|
23536
24149
|
init_employees();
|
|
23537
|
-
import { z as
|
|
24150
|
+
import { z as z72 } from "zod";
|
|
23538
24151
|
function registerCompanyProcedureTool(server2, toolName) {
|
|
23539
24152
|
server2.registerTool(
|
|
23540
24153
|
toolName,
|
|
@@ -23542,12 +24155,12 @@ function registerCompanyProcedureTool(server2, toolName) {
|
|
|
23542
24155
|
title: "Company Procedure",
|
|
23543
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).",
|
|
23544
24157
|
inputSchema: {
|
|
23545
|
-
action:
|
|
23546
|
-
title:
|
|
23547
|
-
content:
|
|
23548
|
-
priority:
|
|
23549
|
-
domain:
|
|
23550
|
-
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)")
|
|
23551
24164
|
}
|
|
23552
24165
|
},
|
|
23553
24166
|
async ({ action, title, content, priority, domain, procedure_id }) => {
|
|
@@ -23680,6 +24293,7 @@ var ACTION_TO_TOOL2 = {
|
|
|
23680
24293
|
memory_audit: "run_memory_audit",
|
|
23681
24294
|
run_consolidation: "run_consolidation",
|
|
23682
24295
|
cloud_sync: "cloud_sync",
|
|
24296
|
+
orchestration_phase: "orchestration_phase",
|
|
23683
24297
|
backup_vps: "backup_vps",
|
|
23684
24298
|
deploy_client: "deploy_client",
|
|
23685
24299
|
license_status: "get_license_status",
|
|
@@ -23716,6 +24330,7 @@ function buildHandlers5() {
|
|
|
23716
24330
|
registerRunMemoryAudit(localServer);
|
|
23717
24331
|
registerRunConsolidation(localServer);
|
|
23718
24332
|
registerCloudSync(localServer);
|
|
24333
|
+
registerOrchestrationPhase(localServer);
|
|
23719
24334
|
registerBackupVps(localServer);
|
|
23720
24335
|
registerDeployClient(localServer);
|
|
23721
24336
|
registerGetLicenseStatus(localServer);
|
|
@@ -23738,41 +24353,42 @@ function registerConfig(server2) {
|
|
|
23738
24353
|
title: "Config",
|
|
23739
24354
|
description: "Consolidated COO/admin tool for runtime config, system health, licensing, triggers, orchestration import/export, and company procedures.",
|
|
23740
24355
|
inputSchema: {
|
|
23741
|
-
action:
|
|
23742
|
-
agent_id:
|
|
23743
|
-
runtime:
|
|
23744
|
-
model:
|
|
23745
|
-
reasoning_effort:
|
|
23746
|
-
dry_run:
|
|
23747
|
-
fix:
|
|
23748
|
-
verbose:
|
|
23749
|
-
project_name:
|
|
23750
|
-
since:
|
|
23751
|
-
limit:
|
|
23752
|
-
output_path:
|
|
23753
|
-
input_path:
|
|
23754
|
-
strategy:
|
|
23755
|
-
license_key:
|
|
23756
|
-
email:
|
|
23757
|
-
plan:
|
|
23758
|
-
name:
|
|
23759
|
-
event:
|
|
23760
|
-
conditions:
|
|
23761
|
-
actions:
|
|
23762
|
-
enabled:
|
|
23763
|
-
schedule:
|
|
23764
|
-
query:
|
|
23765
|
-
skill_name:
|
|
23766
|
-
pack_name:
|
|
23767
|
-
title:
|
|
23768
|
-
content:
|
|
23769
|
-
priority:
|
|
23770
|
-
domain:
|
|
23771
|
-
procedure_id:
|
|
23772
|
-
subaction:
|
|
23773
|
-
max_clusters:
|
|
23774
|
-
force:
|
|
23775
|
-
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")
|
|
23776
24392
|
}
|
|
23777
24393
|
}, async (input, extra) => {
|
|
23778
24394
|
const action = input.action;
|
|
@@ -23793,10 +24409,10 @@ function registerConfig(server2) {
|
|
|
23793
24409
|
}
|
|
23794
24410
|
|
|
23795
24411
|
// src/mcp/tools/wiki.ts
|
|
23796
|
-
import { z as
|
|
24412
|
+
import { z as z76 } from "zod";
|
|
23797
24413
|
|
|
23798
24414
|
// src/mcp/tools/list-wiki-pages.ts
|
|
23799
|
-
import { z as
|
|
24415
|
+
import { z as z74 } from "zod";
|
|
23800
24416
|
var FETCH_TIMEOUT_MS3 = 1e4;
|
|
23801
24417
|
function registerListWikiPages(server2) {
|
|
23802
24418
|
server2.registerTool(
|
|
@@ -23805,8 +24421,8 @@ function registerListWikiPages(server2) {
|
|
|
23805
24421
|
title: "List Wiki Pages",
|
|
23806
24422
|
description: "List documents in an exe-wiki workspace. Optionally filter by folder.",
|
|
23807
24423
|
inputSchema: {
|
|
23808
|
-
workspace:
|
|
23809
|
-
folder:
|
|
24424
|
+
workspace: z74.string().describe('Wiki workspace slug (e.g., "hygo")'),
|
|
24425
|
+
folder: z74.string().optional().describe("Filter by folder path")
|
|
23810
24426
|
}
|
|
23811
24427
|
},
|
|
23812
24428
|
async ({ workspace, folder }) => {
|
|
@@ -23895,7 +24511,7 @@ function registerListWikiPages(server2) {
|
|
|
23895
24511
|
}
|
|
23896
24512
|
|
|
23897
24513
|
// src/mcp/tools/get-wiki-page.ts
|
|
23898
|
-
import { z as
|
|
24514
|
+
import { z as z75 } from "zod";
|
|
23899
24515
|
var FETCH_TIMEOUT_MS4 = 1e4;
|
|
23900
24516
|
function registerGetWikiPage(server2) {
|
|
23901
24517
|
server2.registerTool(
|
|
@@ -23904,9 +24520,9 @@ function registerGetWikiPage(server2) {
|
|
|
23904
24520
|
title: "Get Wiki Page",
|
|
23905
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.",
|
|
23906
24522
|
inputSchema: {
|
|
23907
|
-
workspace:
|
|
23908
|
-
document_id:
|
|
23909
|
-
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)")
|
|
23910
24526
|
}
|
|
23911
24527
|
},
|
|
23912
24528
|
async ({ workspace, document_id, title }) => {
|
|
@@ -24088,14 +24704,14 @@ function registerWiki(server2) {
|
|
|
24088
24704
|
title: "Wiki",
|
|
24089
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.",
|
|
24090
24706
|
inputSchema: {
|
|
24091
|
-
action:
|
|
24092
|
-
workspace:
|
|
24093
|
-
title:
|
|
24094
|
-
content:
|
|
24095
|
-
folder:
|
|
24096
|
-
document_id:
|
|
24097
|
-
mode:
|
|
24098
|
-
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")
|
|
24099
24715
|
}
|
|
24100
24716
|
},
|
|
24101
24717
|
async (input, extra) => {
|
|
@@ -24123,7 +24739,7 @@ init_active_agent();
|
|
|
24123
24739
|
init_project_name();
|
|
24124
24740
|
init_database();
|
|
24125
24741
|
init_employees();
|
|
24126
|
-
import { z as
|
|
24742
|
+
import { z as z77 } from "zod";
|
|
24127
24743
|
function rowToBehavior2(r) {
|
|
24128
24744
|
return {
|
|
24129
24745
|
id: String(r.id),
|
|
@@ -24145,13 +24761,13 @@ function registerBehavior(server2) {
|
|
|
24145
24761
|
title: "Behavior",
|
|
24146
24762
|
description: "Manage behavioral patterns, corrections, and reusable procedures for employees. Actions: store (create new), list (query existing), deactivate (soft-delete, restricted).",
|
|
24147
24763
|
inputSchema: {
|
|
24148
|
-
action:
|
|
24149
|
-
content:
|
|
24150
|
-
domain:
|
|
24151
|
-
priority:
|
|
24152
|
-
agent_id:
|
|
24153
|
-
project_name:
|
|
24154
|
-
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)")
|
|
24155
24771
|
}
|
|
24156
24772
|
},
|
|
24157
24773
|
async ({ action, content, domain, priority, agent_id, project_name, behavior_id }) => {
|
|
@@ -24322,7 +24938,7 @@ Content: ${row.content}`
|
|
|
24322
24938
|
}
|
|
24323
24939
|
|
|
24324
24940
|
// src/mcp/tools/reminder.ts
|
|
24325
|
-
import { z as
|
|
24941
|
+
import { z as z78 } from "zod";
|
|
24326
24942
|
function registerReminder(server2) {
|
|
24327
24943
|
server2.registerTool(
|
|
24328
24944
|
"reminder",
|
|
@@ -24330,11 +24946,11 @@ function registerReminder(server2) {
|
|
|
24330
24946
|
title: "Reminder",
|
|
24331
24947
|
description: "Manage reminders for the founder. Shown in the boot brief every session. Actions: create (set new), list (view active), complete (mark done).",
|
|
24332
24948
|
inputSchema: {
|
|
24333
|
-
action:
|
|
24334
|
-
text:
|
|
24335
|
-
due_date:
|
|
24336
|
-
reminder_id:
|
|
24337
|
-
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)")
|
|
24338
24954
|
}
|
|
24339
24955
|
},
|
|
24340
24956
|
async ({ action, text: text3, due_date, reminder_id, include_completed }) => {
|
|
@@ -24390,7 +25006,7 @@ function registerReminder(server2) {
|
|
|
24390
25006
|
init_global_procedures();
|
|
24391
25007
|
init_active_agent();
|
|
24392
25008
|
init_employees();
|
|
24393
|
-
import { z as
|
|
25009
|
+
import { z as z79 } from "zod";
|
|
24394
25010
|
function registerStoreGlobalProcedure(server2) {
|
|
24395
25011
|
server2.registerTool(
|
|
24396
25012
|
"store_global_procedure",
|
|
@@ -24398,10 +25014,10 @@ function registerStoreGlobalProcedure(server2) {
|
|
|
24398
25014
|
title: "Store Company Procedure (use global_procedure instead)",
|
|
24399
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.",
|
|
24400
25016
|
inputSchema: {
|
|
24401
|
-
title:
|
|
24402
|
-
content:
|
|
24403
|
-
priority:
|
|
24404
|
-
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")
|
|
24405
25021
|
}
|
|
24406
25022
|
},
|
|
24407
25023
|
async ({ title, content, priority, domain }) => {
|
|
@@ -24479,7 +25095,7 @@ init_global_procedures();
|
|
|
24479
25095
|
init_active_agent();
|
|
24480
25096
|
init_database();
|
|
24481
25097
|
init_employees();
|
|
24482
|
-
import { z as
|
|
25098
|
+
import { z as z80 } from "zod";
|
|
24483
25099
|
function registerDeactivateGlobalProcedure(server2) {
|
|
24484
25100
|
server2.registerTool(
|
|
24485
25101
|
"deactivate_global_procedure",
|
|
@@ -24487,7 +25103,7 @@ function registerDeactivateGlobalProcedure(server2) {
|
|
|
24487
25103
|
title: "Deactivate Company Procedure (use global_procedure instead)",
|
|
24488
25104
|
description: "DEPRECATED \u2014 use global_procedure with action='deactivate'. Soft-delete a company procedure. RESTRICTED: only coordinator or founder sessions.",
|
|
24489
25105
|
inputSchema: {
|
|
24490
|
-
procedure_id:
|
|
25106
|
+
procedure_id: z80.string().describe("UUID of the company procedure to deactivate")
|
|
24491
25107
|
}
|
|
24492
25108
|
},
|
|
24493
25109
|
async ({ procedure_id }) => {
|
|
@@ -24547,7 +25163,7 @@ init_store();
|
|
|
24547
25163
|
init_active_agent();
|
|
24548
25164
|
init_database();
|
|
24549
25165
|
init_plan_limits();
|
|
24550
|
-
import { z as
|
|
25166
|
+
import { z as z81 } from "zod";
|
|
24551
25167
|
import crypto17 from "crypto";
|
|
24552
25168
|
function registerStoreDecision(server2) {
|
|
24553
25169
|
server2.registerTool(
|
|
@@ -24556,13 +25172,13 @@ function registerStoreDecision(server2) {
|
|
|
24556
25172
|
title: "Store Decision",
|
|
24557
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.",
|
|
24558
25174
|
inputSchema: {
|
|
24559
|
-
domain:
|
|
25175
|
+
domain: z81.string().describe(
|
|
24560
25176
|
"Domain key, e.g. 'auth-strategy', 'db-migration-approach', 'api-versioning'"
|
|
24561
25177
|
),
|
|
24562
|
-
decision:
|
|
24563
|
-
rationale:
|
|
24564
|
-
supersedes:
|
|
24565
|
-
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")
|
|
24566
25182
|
}
|
|
24567
25183
|
},
|
|
24568
25184
|
async ({ domain, decision, rationale, supersedes, project_name }) => {
|
|
@@ -24630,7 +25246,7 @@ Supersedes: ${supersedes}` : ""}`
|
|
|
24630
25246
|
|
|
24631
25247
|
// src/mcp/tools/get-decision.ts
|
|
24632
25248
|
init_database();
|
|
24633
|
-
import { z as
|
|
25249
|
+
import { z as z82 } from "zod";
|
|
24634
25250
|
function registerGetDecision(server2) {
|
|
24635
25251
|
server2.registerTool(
|
|
24636
25252
|
"get_decision",
|
|
@@ -24638,7 +25254,7 @@ function registerGetDecision(server2) {
|
|
|
24638
25254
|
title: "Get Decision",
|
|
24639
25255
|
description: "Retrieve the latest authoritative decision for a domain. Returns the current active decision and the supersession history.",
|
|
24640
25256
|
inputSchema: {
|
|
24641
|
-
domain:
|
|
25257
|
+
domain: z82.string().describe(
|
|
24642
25258
|
"Domain key to look up, e.g. 'auth-strategy', 'db-migration-approach'"
|
|
24643
25259
|
)
|
|
24644
25260
|
}
|
|
@@ -24701,16 +25317,16 @@ function registerGetDecision(server2) {
|
|
|
24701
25317
|
}
|
|
24702
25318
|
|
|
24703
25319
|
// src/mcp/tools/people-roster.ts
|
|
24704
|
-
import { z as
|
|
25320
|
+
import { z as z83 } from "zod";
|
|
24705
25321
|
|
|
24706
25322
|
// src/lib/people.ts
|
|
24707
25323
|
init_config();
|
|
24708
25324
|
import { readFile as readFile5, writeFile as writeFile6, mkdir as mkdir5 } from "fs/promises";
|
|
24709
|
-
import { existsSync as
|
|
24710
|
-
import
|
|
24711
|
-
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");
|
|
24712
25328
|
async function loadPeople() {
|
|
24713
|
-
if (!
|
|
25329
|
+
if (!existsSync36(PEOPLE_PATH)) return [];
|
|
24714
25330
|
try {
|
|
24715
25331
|
const raw = await readFile5(PEOPLE_PATH, "utf-8");
|
|
24716
25332
|
return JSON.parse(raw);
|
|
@@ -24719,7 +25335,7 @@ async function loadPeople() {
|
|
|
24719
25335
|
}
|
|
24720
25336
|
}
|
|
24721
25337
|
async function savePeople(people) {
|
|
24722
|
-
await mkdir5(
|
|
25338
|
+
await mkdir5(path45.dirname(PEOPLE_PATH), { recursive: true });
|
|
24723
25339
|
await writeFile6(PEOPLE_PATH, JSON.stringify(people, null, 2) + "\n", "utf-8");
|
|
24724
25340
|
}
|
|
24725
25341
|
async function addPerson(person) {
|
|
@@ -24749,10 +25365,10 @@ function registerAddPerson(server2) {
|
|
|
24749
25365
|
title: "Add Person",
|
|
24750
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.",
|
|
24751
25367
|
inputSchema: {
|
|
24752
|
-
name:
|
|
24753
|
-
role:
|
|
24754
|
-
relationship:
|
|
24755
|
-
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")
|
|
24756
25372
|
}
|
|
24757
25373
|
},
|
|
24758
25374
|
async ({ name, role, relationship, notes }) => {
|
|
@@ -24798,7 +25414,7 @@ function registerGetPerson(server2) {
|
|
|
24798
25414
|
title: "Get Person",
|
|
24799
25415
|
description: "Look up a specific person by name from the people roster.",
|
|
24800
25416
|
inputSchema: {
|
|
24801
|
-
name:
|
|
25417
|
+
name: z83.string().describe("Person's name to look up")
|
|
24802
25418
|
}
|
|
24803
25419
|
},
|
|
24804
25420
|
async ({ name }) => {
|
|
@@ -24822,10 +25438,10 @@ Notes: ${person.notes}` : ""}`
|
|
|
24822
25438
|
}
|
|
24823
25439
|
|
|
24824
25440
|
// src/mcp/tools/crm.ts
|
|
24825
|
-
import { z as
|
|
25441
|
+
import { z as z84 } from "zod";
|
|
24826
25442
|
|
|
24827
25443
|
// src/lib/exe-db-read.ts
|
|
24828
|
-
import
|
|
25444
|
+
import path46 from "path";
|
|
24829
25445
|
import os19 from "os";
|
|
24830
25446
|
import { createRequire as createRequire5 } from "module";
|
|
24831
25447
|
import { pathToFileURL as pathToFileURL5 } from "url";
|
|
@@ -24843,8 +25459,8 @@ async function getExeDbReadClient() {
|
|
|
24843
25459
|
if (!Ctor2) throw new Error(`No PrismaClient export found at ${explicitPath}`);
|
|
24844
25460
|
return new Ctor2();
|
|
24845
25461
|
}
|
|
24846
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
24847
|
-
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"));
|
|
24848
25464
|
const entry = req.resolve("@prisma/client");
|
|
24849
25465
|
const mod = await import(pathToFileURL5(entry).href);
|
|
24850
25466
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -24877,12 +25493,12 @@ function registerCrm(server2) {
|
|
|
24877
25493
|
title: "CRM",
|
|
24878
25494
|
description: "Read-only CRM access from exe-db crm schema. Actions: list_people, get_person, list_tables, describe_table.",
|
|
24879
25495
|
inputSchema: {
|
|
24880
|
-
action:
|
|
24881
|
-
id:
|
|
24882
|
-
query:
|
|
24883
|
-
table:
|
|
24884
|
-
limit:
|
|
24885
|
-
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")
|
|
24886
25502
|
}
|
|
24887
25503
|
}, async ({ action, id, query, table, limit, offset }) => {
|
|
24888
25504
|
try {
|
|
@@ -24941,7 +25557,7 @@ function registerCrm(server2) {
|
|
|
24941
25557
|
}
|
|
24942
25558
|
|
|
24943
25559
|
// src/mcp/tools/raw-data.ts
|
|
24944
|
-
import { z as
|
|
25560
|
+
import { z as z85 } from "zod";
|
|
24945
25561
|
function text2(content, isError = false) {
|
|
24946
25562
|
return { content: [{ type: "text", text: content }], ...isError ? { isError: true } : {} };
|
|
24947
25563
|
}
|
|
@@ -24950,15 +25566,15 @@ function registerRawData(server2) {
|
|
|
24950
25566
|
title: "Raw Data",
|
|
24951
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.",
|
|
24952
25568
|
inputSchema: {
|
|
24953
|
-
action:
|
|
24954
|
-
id:
|
|
24955
|
-
source:
|
|
24956
|
-
event_type:
|
|
24957
|
-
query:
|
|
24958
|
-
processed:
|
|
24959
|
-
limit:
|
|
24960
|
-
offset:
|
|
24961
|
-
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.")
|
|
24962
25578
|
}
|
|
24963
25579
|
}, async ({ action, id, source, event_type, query, processed, limit, offset, include_payload }) => {
|
|
24964
25580
|
try {
|
|
@@ -25025,17 +25641,17 @@ init_active_agent();
|
|
|
25025
25641
|
init_config();
|
|
25026
25642
|
init_license();
|
|
25027
25643
|
init_store();
|
|
25028
|
-
import { z as
|
|
25644
|
+
import { z as z86 } from "zod";
|
|
25029
25645
|
import crypto18 from "crypto";
|
|
25030
25646
|
import { mkdir as mkdir6, writeFile as writeFile7 } from "fs/promises";
|
|
25031
|
-
import
|
|
25032
|
-
var CLASSIFICATION =
|
|
25647
|
+
import path47 from "path";
|
|
25648
|
+
var CLASSIFICATION = z86.enum([
|
|
25033
25649
|
"upstream_bug",
|
|
25034
25650
|
"customer_customization",
|
|
25035
25651
|
"emergency_hotfix",
|
|
25036
25652
|
"unclear"
|
|
25037
25653
|
]);
|
|
25038
|
-
var SEVERITY =
|
|
25654
|
+
var SEVERITY = z86.enum(["p0", "p1", "p2", "p3"]);
|
|
25039
25655
|
function slugify2(input) {
|
|
25040
25656
|
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "bug-report";
|
|
25041
25657
|
}
|
|
@@ -25113,22 +25729,22 @@ function registerCreateBugReport(server2) {
|
|
|
25113
25729
|
title: "Create Bug Report",
|
|
25114
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.",
|
|
25115
25731
|
inputSchema: {
|
|
25116
|
-
title:
|
|
25732
|
+
title: z86.string().min(3).describe("Short descriptive title"),
|
|
25117
25733
|
classification: CLASSIFICATION.describe(
|
|
25118
25734
|
"upstream_bug = platform defect; customer_customization = local preference; emergency_hotfix = temporary local patch; unclear = needs maintainer triage"
|
|
25119
25735
|
),
|
|
25120
25736
|
severity: SEVERITY.default("p2").describe("p0 critical \u2192 p3 low"),
|
|
25121
|
-
summary:
|
|
25122
|
-
customer_impact:
|
|
25123
|
-
reproduction_steps:
|
|
25124
|
-
expected:
|
|
25125
|
-
actual:
|
|
25126
|
-
files_changed:
|
|
25127
|
-
workaround:
|
|
25128
|
-
local_patch_diff:
|
|
25129
|
-
package_version:
|
|
25130
|
-
project_name:
|
|
25131
|
-
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")
|
|
25132
25748
|
}
|
|
25133
25749
|
},
|
|
25134
25750
|
async ({
|
|
@@ -25168,9 +25784,9 @@ function registerCreateBugReport(server2) {
|
|
|
25168
25784
|
filesChanged: files_changed,
|
|
25169
25785
|
projectName: project_name
|
|
25170
25786
|
});
|
|
25171
|
-
const outDir =
|
|
25787
|
+
const outDir = path47.join(EXE_AI_DIR, "bug-reports");
|
|
25172
25788
|
await mkdir6(outDir, { recursive: true });
|
|
25173
|
-
const reportPath =
|
|
25789
|
+
const reportPath = path47.join(outDir, `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}-${slugify2(title)}-${id.slice(0, 8)}.md`);
|
|
25174
25790
|
await writeFile7(reportPath, markdown, "utf-8");
|
|
25175
25791
|
let vector = null;
|
|
25176
25792
|
try {
|
|
@@ -25237,9 +25853,9 @@ Upstream status: ${upstreamStatus}`
|
|
|
25237
25853
|
}
|
|
25238
25854
|
|
|
25239
25855
|
// src/mcp/tools/support-inbox.ts
|
|
25240
|
-
import { z as
|
|
25856
|
+
import { z as z87 } from "zod";
|
|
25241
25857
|
var DEFAULT_ENDPOINT = "https://askexe.com/admin/support/bug-reports";
|
|
25242
|
-
var STATUS =
|
|
25858
|
+
var STATUS = z87.enum(["open", "triaged", "fixed", "closed", "wontfix"]);
|
|
25243
25859
|
function adminToken() {
|
|
25244
25860
|
return process.env.ASKEXE_SUPPORT_ADMIN_TOKEN || process.env.EXE_SUPPORT_ADMIN_TOKEN;
|
|
25245
25861
|
}
|
|
@@ -25278,9 +25894,9 @@ function registerListBugReports(server2) {
|
|
|
25278
25894
|
title: "List Bug Reports",
|
|
25279
25895
|
description: "AskExe-internal only: list incoming customer bug reports from the support inbox.",
|
|
25280
25896
|
inputSchema: {
|
|
25281
|
-
status:
|
|
25282
|
-
severity:
|
|
25283
|
-
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)
|
|
25284
25900
|
}
|
|
25285
25901
|
},
|
|
25286
25902
|
async ({ status, severity, limit }) => {
|
|
@@ -25299,7 +25915,7 @@ function registerGetBugReport(server2) {
|
|
|
25299
25915
|
{
|
|
25300
25916
|
title: "Get Bug Report",
|
|
25301
25917
|
description: "AskExe-internal only: fetch one customer bug report with full markdown payload.",
|
|
25302
|
-
inputSchema: { id:
|
|
25918
|
+
inputSchema: { id: z87.string().min(8) }
|
|
25303
25919
|
},
|
|
25304
25920
|
async ({ id }) => {
|
|
25305
25921
|
const data = await requestJson(`${endpoint()}/${encodeURIComponent(id)}`);
|
|
@@ -25314,12 +25930,12 @@ function registerTriageBugReport(server2) {
|
|
|
25314
25930
|
title: "Triage Bug Report",
|
|
25315
25931
|
description: "AskExe-internal only: update bug report status and link task/commit/release metadata.",
|
|
25316
25932
|
inputSchema: {
|
|
25317
|
-
id:
|
|
25933
|
+
id: z87.string().min(8),
|
|
25318
25934
|
status: STATUS.optional(),
|
|
25319
|
-
triage_notes:
|
|
25320
|
-
linked_task_id:
|
|
25321
|
-
linked_commit:
|
|
25322
|
-
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()
|
|
25323
25939
|
}
|
|
25324
25940
|
},
|
|
25325
25941
|
async ({ id, status, triage_notes, linked_task_id, linked_commit, fixed_version }) => {
|
|
@@ -25449,6 +26065,7 @@ var TOOL_CATEGORIES = {
|
|
|
25449
26065
|
registerRunMemoryAudit: "admin",
|
|
25450
26066
|
registerRunConsolidation: "admin",
|
|
25451
26067
|
registerCloudSync: "admin",
|
|
26068
|
+
registerOrchestrationPhase: "admin",
|
|
25452
26069
|
registerSetAgentConfig: "admin",
|
|
25453
26070
|
registerListEmployees: "admin",
|
|
25454
26071
|
registerGetAgentSpend: "admin",
|
|
@@ -25667,6 +26284,7 @@ function registerAllTools(server2) {
|
|
|
25667
26284
|
gate("registerRunMemoryAudit", registerRunMemoryAudit);
|
|
25668
26285
|
gate("registerCloudSync", registerCloudSync);
|
|
25669
26286
|
gate("registerBackupVps", registerBackupVps);
|
|
26287
|
+
gate("registerOrchestrationPhase", registerOrchestrationPhase);
|
|
25670
26288
|
}
|
|
25671
26289
|
if (exposeLegacyMemory) {
|
|
25672
26290
|
gate("registerGetMemoryCardinality", registerGetMemoryCardinality);
|
|
@@ -25811,16 +26429,16 @@ try {
|
|
|
25811
26429
|
}
|
|
25812
26430
|
}, 3e4);
|
|
25813
26431
|
_ppidWatchdog.unref();
|
|
25814
|
-
const MCP_VERSION_PATH =
|
|
26432
|
+
const MCP_VERSION_PATH = path48.join(os20.homedir(), ".exe-os", "mcp-version");
|
|
25815
26433
|
let _currentMcpVersion = null;
|
|
25816
26434
|
try {
|
|
25817
|
-
_currentMcpVersion =
|
|
26435
|
+
_currentMcpVersion = existsSync37(MCP_VERSION_PATH) ? readFileSync30(MCP_VERSION_PATH, "utf8").trim() : null;
|
|
25818
26436
|
} catch {
|
|
25819
26437
|
}
|
|
25820
26438
|
const _versionWatchdog = setInterval(() => {
|
|
25821
26439
|
try {
|
|
25822
|
-
if (!
|
|
25823
|
-
const diskVersion =
|
|
26440
|
+
if (!existsSync37(MCP_VERSION_PATH)) return;
|
|
26441
|
+
const diskVersion = readFileSync30(MCP_VERSION_PATH, "utf8").trim();
|
|
25824
26442
|
if (_currentMcpVersion && diskVersion !== _currentMcpVersion) {
|
|
25825
26443
|
process.stderr.write(
|
|
25826
26444
|
`[exe-os] MCP version changed (${_currentMcpVersion} \u2192 ${diskVersion}). Hot-reloading...
|
|
@@ -25853,14 +26471,14 @@ try {
|
|
|
25853
26471
|
`
|
|
25854
26472
|
);
|
|
25855
26473
|
const thisFile = fileURLToPath5(import.meta.url);
|
|
25856
|
-
const backfillPath =
|
|
25857
|
-
|
|
26474
|
+
const backfillPath = path48.resolve(
|
|
26475
|
+
path48.dirname(thisFile),
|
|
25858
26476
|
"../bin/backfill-vectors.js"
|
|
25859
26477
|
);
|
|
25860
|
-
if (
|
|
26478
|
+
if (existsSync37(backfillPath)) {
|
|
25861
26479
|
const { EXE_AI_DIR: exeDir } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
25862
|
-
const logPath =
|
|
25863
|
-
|
|
26480
|
+
const logPath = path48.join(exeDir, "workers.log");
|
|
26481
|
+
mkdirSync20(path48.dirname(logPath), { recursive: true });
|
|
25864
26482
|
let logFd = "ignore";
|
|
25865
26483
|
try {
|
|
25866
26484
|
logFd = openSync3(logPath, "a");
|