@askexenow/exe-os 0.9.65 → 0.9.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deploy/stack-manifests/v0.9.json +4 -4
- package/dist/bin/backfill-conversations.js +22 -0
- package/dist/bin/backfill-responses.js +22 -0
- package/dist/bin/backfill-vectors.js +22 -0
- package/dist/bin/cleanup-stale-review-tasks.js +22 -0
- package/dist/bin/cli.js +2263 -1203
- package/dist/bin/exe-agent-config.js +4 -0
- package/dist/bin/exe-agent.js +16 -0
- package/dist/bin/exe-assign.js +22 -0
- package/dist/bin/exe-boot.js +93 -5
- package/dist/bin/exe-call.js +16 -0
- package/dist/bin/exe-cloud.js +6671 -464
- package/dist/bin/exe-dispatch.js +24 -0
- package/dist/bin/exe-doctor.js +2845 -1223
- package/dist/bin/exe-export-behaviors.js +24 -0
- package/dist/bin/exe-forget.js +22 -0
- package/dist/bin/exe-gateway.js +24 -0
- package/dist/bin/exe-heartbeat.js +23 -0
- package/dist/bin/exe-kill.js +22 -0
- package/dist/bin/exe-launch-agent.js +24 -0
- package/dist/bin/exe-link.js +287 -176
- package/dist/bin/exe-new-employee.js +127 -1
- package/dist/bin/exe-pending-messages.js +22 -0
- package/dist/bin/exe-pending-notifications.js +22 -0
- package/dist/bin/exe-pending-reviews.js +22 -0
- package/dist/bin/exe-rename.js +22 -0
- package/dist/bin/exe-review.js +22 -0
- package/dist/bin/exe-search.js +24 -0
- package/dist/bin/exe-session-cleanup.js +24 -0
- package/dist/bin/exe-settings.js +10 -0
- package/dist/bin/exe-start-codex.js +135 -1
- package/dist/bin/exe-start-opencode.js +149 -1
- package/dist/bin/exe-status.js +22 -0
- package/dist/bin/exe-team.js +22 -0
- package/dist/bin/git-sweep.js +24 -0
- package/dist/bin/graph-backfill.js +22 -0
- package/dist/bin/graph-export.js +22 -0
- package/dist/bin/install.js +115 -1
- package/dist/bin/intercom-check.js +24 -0
- package/dist/bin/scan-tasks.js +24 -0
- package/dist/bin/setup.js +389 -155
- package/dist/bin/shard-migrate.js +22 -0
- package/dist/bin/update.js +4 -0
- package/dist/gateway/index.js +24 -0
- package/dist/hooks/bug-report-worker.js +135 -42
- package/dist/hooks/codex-stop-task-finalizer.js +24 -0
- package/dist/hooks/commit-complete.js +24 -0
- package/dist/hooks/error-recall.js +24 -0
- package/dist/hooks/exe-heartbeat-hook.js +4 -0
- package/dist/hooks/ingest-worker.js +4 -0
- package/dist/hooks/ingest.js +23 -0
- package/dist/hooks/instructions-loaded.js +22 -0
- package/dist/hooks/notification.js +22 -0
- package/dist/hooks/post-compact.js +22 -0
- package/dist/hooks/post-tool-combined.js +24 -0
- package/dist/hooks/pre-compact.js +260 -109
- package/dist/hooks/pre-tool-use.js +22 -0
- package/dist/hooks/prompt-submit.js +24 -0
- package/dist/hooks/session-end.js +161 -122
- package/dist/hooks/session-start.js +142 -0
- package/dist/hooks/stop.js +23 -0
- package/dist/hooks/subagent-stop.js +22 -0
- package/dist/hooks/summary-worker.js +172 -77
- package/dist/index.js +24 -0
- package/dist/lib/agent-config.js +4 -0
- package/dist/lib/cloud-sync.js +27 -4
- package/dist/lib/config.js +12 -0
- package/dist/lib/consolidation.js +4 -0
- package/dist/lib/database.js +4 -0
- package/dist/lib/db-daemon-client.js +4 -0
- package/dist/lib/db.js +4 -0
- package/dist/lib/device-registry.js +4 -0
- package/dist/lib/embedder.js +12 -0
- package/dist/lib/employee-templates.js +16 -0
- package/dist/lib/employees.js +4 -0
- package/dist/lib/exe-daemon-client.js +4 -0
- package/dist/lib/exe-daemon.js +1058 -453
- package/dist/lib/hybrid-search.js +24 -0
- package/dist/lib/identity.js +4 -0
- package/dist/lib/license.js +4 -0
- package/dist/lib/messaging.js +4 -0
- package/dist/lib/reminders.js +4 -0
- package/dist/lib/schedules.js +22 -0
- package/dist/lib/skill-learning.js +12 -0
- package/dist/lib/status-brief.js +39 -0
- package/dist/lib/store.js +22 -0
- package/dist/lib/task-router.js +4 -0
- package/dist/lib/tasks.js +12 -0
- package/dist/lib/tmux-routing.js +12 -0
- package/dist/lib/token-spend.js +4 -0
- package/dist/mcp/server.js +1022 -425
- package/dist/mcp/tools/complete-reminder.js +4 -0
- package/dist/mcp/tools/create-reminder.js +4 -0
- package/dist/mcp/tools/create-task.js +12 -0
- package/dist/mcp/tools/deactivate-behavior.js +4 -0
- package/dist/mcp/tools/list-reminders.js +4 -0
- package/dist/mcp/tools/list-tasks.js +4 -0
- package/dist/mcp/tools/send-message.js +4 -0
- package/dist/mcp/tools/update-task.js +12 -0
- package/dist/runtime/index.js +24 -0
- package/dist/tui/App.js +24 -0
- package/package.json +3 -2
- package/src/commands/exe/cloud.md +15 -8
- package/src/commands/exe/link.md +7 -6
- package/stack.release.json +2 -2
package/dist/lib/exe-daemon.js
CHANGED
|
@@ -149,6 +149,11 @@ function normalizeAutoUpdate(raw) {
|
|
|
149
149
|
const userAU = raw.autoUpdate ?? {};
|
|
150
150
|
raw.autoUpdate = { ...defaultAU, ...userAU };
|
|
151
151
|
}
|
|
152
|
+
function normalizeOrchestration(raw) {
|
|
153
|
+
const defaultOrg = DEFAULT_CONFIG.orchestration;
|
|
154
|
+
const userOrg = raw.orchestration ?? {};
|
|
155
|
+
raw.orchestration = { ...defaultOrg, ...userOrg };
|
|
156
|
+
}
|
|
152
157
|
async function loadConfig() {
|
|
153
158
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
154
159
|
await ensurePrivateDir(dir);
|
|
@@ -173,6 +178,7 @@ async function loadConfig() {
|
|
|
173
178
|
normalizeScalingRoadmap(migratedCfg);
|
|
174
179
|
normalizeSessionLifecycle(migratedCfg);
|
|
175
180
|
normalizeAutoUpdate(migratedCfg);
|
|
181
|
+
normalizeOrchestration(migratedCfg);
|
|
176
182
|
const config2 = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
177
183
|
if (config2.dbPath.startsWith("~")) {
|
|
178
184
|
config2.dbPath = config2.dbPath.replace(/^~/, os.homedir());
|
|
@@ -196,6 +202,7 @@ function loadConfigSync() {
|
|
|
196
202
|
normalizeScalingRoadmap(migratedCfg);
|
|
197
203
|
normalizeSessionLifecycle(migratedCfg);
|
|
198
204
|
normalizeAutoUpdate(migratedCfg);
|
|
205
|
+
normalizeOrchestration(migratedCfg);
|
|
199
206
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
200
207
|
} catch {
|
|
201
208
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
@@ -217,6 +224,7 @@ async function loadConfigFrom(configPath) {
|
|
|
217
224
|
normalizeScalingRoadmap(migratedCfg);
|
|
218
225
|
normalizeSessionLifecycle(migratedCfg);
|
|
219
226
|
normalizeAutoUpdate(migratedCfg);
|
|
227
|
+
normalizeOrchestration(migratedCfg);
|
|
220
228
|
return { ...DEFAULT_CONFIG, ...migratedCfg };
|
|
221
229
|
} catch {
|
|
222
230
|
return { ...DEFAULT_CONFIG };
|
|
@@ -288,6 +296,10 @@ var init_config = __esm({
|
|
|
288
296
|
checkOnBoot: true,
|
|
289
297
|
autoInstall: false,
|
|
290
298
|
checkIntervalMs: 24 * 60 * 60 * 1e3
|
|
299
|
+
},
|
|
300
|
+
orchestration: {
|
|
301
|
+
phase: "phase_1_coo",
|
|
302
|
+
phaseSetBy: "default"
|
|
291
303
|
}
|
|
292
304
|
};
|
|
293
305
|
CONFIG_MIGRATIONS = [
|
|
@@ -313,6 +325,15 @@ var init_memory = __esm({
|
|
|
313
325
|
});
|
|
314
326
|
|
|
315
327
|
// src/lib/daemon-protocol.ts
|
|
328
|
+
var daemon_protocol_exports = {};
|
|
329
|
+
__export(daemon_protocol_exports, {
|
|
330
|
+
deserializeArgs: () => deserializeArgs,
|
|
331
|
+
deserializeResultSet: () => deserializeResultSet,
|
|
332
|
+
deserializeValue: () => deserializeValue,
|
|
333
|
+
serializeArgs: () => serializeArgs,
|
|
334
|
+
serializeResultSet: () => serializeResultSet,
|
|
335
|
+
serializeValue: () => serializeValue
|
|
336
|
+
});
|
|
316
337
|
function serializeValue(v) {
|
|
317
338
|
if (v === null || v === void 0) return null;
|
|
318
339
|
if (typeof v === "bigint") return Number(v);
|
|
@@ -337,6 +358,9 @@ function deserializeValue(v) {
|
|
|
337
358
|
}
|
|
338
359
|
return v;
|
|
339
360
|
}
|
|
361
|
+
function serializeArgs(args) {
|
|
362
|
+
return args.map(serializeValue);
|
|
363
|
+
}
|
|
340
364
|
function deserializeArgs(args) {
|
|
341
365
|
return args.map(deserializeValue);
|
|
342
366
|
}
|
|
@@ -4319,8 +4343,8 @@ function deriveMachineKey() {
|
|
|
4319
4343
|
}
|
|
4320
4344
|
function readMachineId() {
|
|
4321
4345
|
try {
|
|
4322
|
-
const { readFileSync:
|
|
4323
|
-
return
|
|
4346
|
+
const { readFileSync: readFileSync36 } = __require("fs");
|
|
4347
|
+
return readFileSync36("/etc/machine-id", "utf-8").trim();
|
|
4324
4348
|
} catch {
|
|
4325
4349
|
return "";
|
|
4326
4350
|
}
|
|
@@ -4611,6 +4635,12 @@ var init_platform_procedures = __esm({
|
|
|
4611
4635
|
priority: "p0",
|
|
4612
4636
|
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."
|
|
4613
4637
|
},
|
|
4638
|
+
{
|
|
4639
|
+
title: "Customer orchestration maturity \u2014 recommend, never trap",
|
|
4640
|
+
domain: "workflow",
|
|
4641
|
+
priority: "p1",
|
|
4642
|
+
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."
|
|
4643
|
+
},
|
|
4614
4644
|
{
|
|
4615
4645
|
title: "Single dispatch path \u2014 create_task only",
|
|
4616
4646
|
domain: "workflow",
|
|
@@ -4669,6 +4699,12 @@ var init_platform_procedures = __esm({
|
|
|
4669
4699
|
priority: "p0",
|
|
4670
4700
|
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."
|
|
4671
4701
|
},
|
|
4702
|
+
{
|
|
4703
|
+
title: "Commit discipline \u2014 never leave verified work floating",
|
|
4704
|
+
domain: "workflow",
|
|
4705
|
+
priority: "p1",
|
|
4706
|
+
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."
|
|
4707
|
+
},
|
|
4672
4708
|
{
|
|
4673
4709
|
title: "Desktop and TUI are the same product",
|
|
4674
4710
|
domain: "architecture",
|
|
@@ -6006,10 +6042,10 @@ async function disposeEmbedder() {
|
|
|
6006
6042
|
async function embedDirect(text3) {
|
|
6007
6043
|
const llamaCpp = await import("node-llama-cpp");
|
|
6008
6044
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
6009
|
-
const { existsSync:
|
|
6010
|
-
const
|
|
6011
|
-
const modelPath =
|
|
6012
|
-
if (!
|
|
6045
|
+
const { existsSync: existsSync43 } = await import("fs");
|
|
6046
|
+
const path56 = await import("path");
|
|
6047
|
+
const modelPath = path56.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
6048
|
+
if (!existsSync43(modelPath)) {
|
|
6013
6049
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
6014
6050
|
}
|
|
6015
6051
|
const llama = await llamaCpp.getLlama();
|
|
@@ -7100,10 +7136,10 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
7100
7136
|
};
|
|
7101
7137
|
try {
|
|
7102
7138
|
const fs = await import("fs");
|
|
7103
|
-
const
|
|
7139
|
+
const path56 = await import("path");
|
|
7104
7140
|
const os24 = await import("os");
|
|
7105
|
-
const logPath =
|
|
7106
|
-
fs.mkdirSync(
|
|
7141
|
+
const logPath = path56.join(os24.homedir(), ".exe-os", "search-quality.jsonl");
|
|
7142
|
+
fs.mkdirSync(path56.dirname(logPath), { recursive: true });
|
|
7107
7143
|
fs.appendFileSync(logPath, JSON.stringify(logEntry) + "\n");
|
|
7108
7144
|
} catch {
|
|
7109
7145
|
}
|
|
@@ -8736,8 +8772,8 @@ __export(wiki_client_exports, {
|
|
|
8736
8772
|
listDocuments: () => listDocuments,
|
|
8737
8773
|
listWorkspaces: () => listWorkspaces
|
|
8738
8774
|
});
|
|
8739
|
-
async function wikiFetch(config2,
|
|
8740
|
-
const url = `${config2.baseUrl}/api/v1${
|
|
8775
|
+
async function wikiFetch(config2, path56, method = "GET", body) {
|
|
8776
|
+
const url = `${config2.baseUrl}/api/v1${path56}`;
|
|
8741
8777
|
const headers = {
|
|
8742
8778
|
Authorization: `Bearer ${config2.apiKey}`,
|
|
8743
8779
|
"Content-Type": "application/json"
|
|
@@ -8770,7 +8806,7 @@ async function wikiFetch(config2, path55, method = "GET", body) {
|
|
|
8770
8806
|
}
|
|
8771
8807
|
}
|
|
8772
8808
|
if (!response.ok) {
|
|
8773
|
-
throw new Error(`Wiki API ${method} ${
|
|
8809
|
+
throw new Error(`Wiki API ${method} ${path56}: ${response.status} ${response.statusText}`);
|
|
8774
8810
|
}
|
|
8775
8811
|
return response.json();
|
|
8776
8812
|
} finally {
|
|
@@ -14348,10 +14384,10 @@ function registerCreateTask(server) {
|
|
|
14348
14384
|
skipDispatch: true
|
|
14349
14385
|
});
|
|
14350
14386
|
try {
|
|
14351
|
-
const { existsSync:
|
|
14387
|
+
const { existsSync: existsSync43, mkdirSync: mkdirSync22, writeFileSync: writeFileSync26 } = await import("fs");
|
|
14352
14388
|
const { identityPath: identityPath2 } = await Promise.resolve().then(() => (init_identity(), identity_exports));
|
|
14353
14389
|
const idPath = identityPath2(assigned_to);
|
|
14354
|
-
if (!
|
|
14390
|
+
if (!existsSync43(idPath)) {
|
|
14355
14391
|
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
14356
14392
|
const employees = await loadEmployees2();
|
|
14357
14393
|
const emp = employees.find((e) => e.name === assigned_to);
|
|
@@ -14360,8 +14396,8 @@ function registerCreateTask(server) {
|
|
|
14360
14396
|
const template = getTemplateForTitle2(emp.role);
|
|
14361
14397
|
if (template) {
|
|
14362
14398
|
const dir = (await import("path")).dirname(idPath);
|
|
14363
|
-
if (!
|
|
14364
|
-
|
|
14399
|
+
if (!existsSync43(dir)) mkdirSync22(dir, { recursive: true });
|
|
14400
|
+
writeFileSync26(idPath, template.replace(/^agent_id: \w+/m, `agent_id: ${assigned_to}`), "utf-8");
|
|
14365
14401
|
}
|
|
14366
14402
|
}
|
|
14367
14403
|
}
|
|
@@ -17845,12 +17881,12 @@ function registerExportGraph(server) {
|
|
|
17845
17881
|
}
|
|
17846
17882
|
const html = await exportGraphHTML(client);
|
|
17847
17883
|
const fs = await import("fs");
|
|
17848
|
-
const
|
|
17884
|
+
const path56 = await import("path");
|
|
17849
17885
|
const os24 = await import("os");
|
|
17850
|
-
const outDir =
|
|
17886
|
+
const outDir = path56.join(os24.homedir(), ".exe-os", "exports");
|
|
17851
17887
|
fs.mkdirSync(outDir, { recursive: true });
|
|
17852
17888
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
17853
|
-
const filePath =
|
|
17889
|
+
const filePath = path56.join(outDir, `graph-${timestamp}.html`);
|
|
17854
17890
|
fs.writeFileSync(filePath, html, "utf-8");
|
|
17855
17891
|
return {
|
|
17856
17892
|
content: [
|
|
@@ -21029,6 +21065,259 @@ var init_conflict_detector = __esm({
|
|
|
21029
21065
|
}
|
|
21030
21066
|
});
|
|
21031
21067
|
|
|
21068
|
+
// src/adapters/runtime-hook-manifest.ts
|
|
21069
|
+
function manifestEntryForCommand(command) {
|
|
21070
|
+
return EXE_HOOK_MANIFEST.find((entry) => command.includes(entry.commandMarker));
|
|
21071
|
+
}
|
|
21072
|
+
var EXE_HOOKS, EXE_HOOK_MANIFEST, LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS;
|
|
21073
|
+
var init_runtime_hook_manifest = __esm({
|
|
21074
|
+
"src/adapters/runtime-hook-manifest.ts"() {
|
|
21075
|
+
"use strict";
|
|
21076
|
+
EXE_HOOKS = {
|
|
21077
|
+
postToolCombined: "dist/hooks/post-tool-combined.js",
|
|
21078
|
+
sessionStart: "dist/hooks/session-start.js",
|
|
21079
|
+
promptSubmit: "dist/hooks/prompt-submit.js",
|
|
21080
|
+
heartbeat: "dist/hooks/exe-heartbeat-hook.js",
|
|
21081
|
+
stop: "dist/hooks/stop.js",
|
|
21082
|
+
preToolUse: "dist/hooks/pre-tool-use.js",
|
|
21083
|
+
subagentStop: "dist/hooks/subagent-stop.js",
|
|
21084
|
+
preCompact: "dist/hooks/pre-compact.js",
|
|
21085
|
+
postCompact: "dist/hooks/post-compact.js",
|
|
21086
|
+
sessionEnd: "dist/hooks/session-end.js",
|
|
21087
|
+
notification: "dist/hooks/notification.js",
|
|
21088
|
+
instructionsLoaded: "dist/hooks/instructions-loaded.js"
|
|
21089
|
+
};
|
|
21090
|
+
EXE_HOOK_MANIFEST = [
|
|
21091
|
+
{
|
|
21092
|
+
key: "postToolCombined",
|
|
21093
|
+
event: "PostToolUse",
|
|
21094
|
+
commandMarker: EXE_HOOKS.postToolCombined,
|
|
21095
|
+
owner: "exe-os",
|
|
21096
|
+
purpose: "Single PostToolUse entrypoint for ingestion, error recall, summaries, and bug detection.",
|
|
21097
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
21098
|
+
checkpointRole: "none"
|
|
21099
|
+
},
|
|
21100
|
+
{
|
|
21101
|
+
key: "sessionStart",
|
|
21102
|
+
event: "SessionStart",
|
|
21103
|
+
commandMarker: EXE_HOOKS.sessionStart,
|
|
21104
|
+
owner: "exe-os",
|
|
21105
|
+
purpose: "Loads agent identity, procedures, and boot context.",
|
|
21106
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
21107
|
+
checkpointRole: "none"
|
|
21108
|
+
},
|
|
21109
|
+
{
|
|
21110
|
+
key: "promptSubmit",
|
|
21111
|
+
event: "UserPromptSubmit",
|
|
21112
|
+
commandMarker: EXE_HOOKS.promptSubmit,
|
|
21113
|
+
owner: "exe-os",
|
|
21114
|
+
purpose: "Injects current tasks, pending reviews, and local context before each prompt.",
|
|
21115
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
21116
|
+
checkpointRole: "none"
|
|
21117
|
+
},
|
|
21118
|
+
{
|
|
21119
|
+
key: "heartbeat",
|
|
21120
|
+
event: "UserPromptSubmit",
|
|
21121
|
+
commandMarker: EXE_HOOKS.heartbeat,
|
|
21122
|
+
owner: "exe-os",
|
|
21123
|
+
purpose: "Lightweight heartbeat/status sidecar for Claude Code sessions.",
|
|
21124
|
+
runtimes: ["claude"],
|
|
21125
|
+
checkpointRole: "none"
|
|
21126
|
+
},
|
|
21127
|
+
{
|
|
21128
|
+
key: "stop",
|
|
21129
|
+
event: "Stop",
|
|
21130
|
+
commandMarker: EXE_HOOKS.stop,
|
|
21131
|
+
owner: "exe-os",
|
|
21132
|
+
purpose: "Finalizes task state, capacity signals, and emergency checkpointing.",
|
|
21133
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
21134
|
+
checkpointRole: "capacity_checkpoint"
|
|
21135
|
+
},
|
|
21136
|
+
{
|
|
21137
|
+
key: "preToolUse",
|
|
21138
|
+
event: "PreToolUse",
|
|
21139
|
+
commandMarker: EXE_HOOKS.preToolUse,
|
|
21140
|
+
owner: "exe-os",
|
|
21141
|
+
purpose: "Preflight guardrails before shell/tool execution.",
|
|
21142
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
21143
|
+
checkpointRole: "none"
|
|
21144
|
+
},
|
|
21145
|
+
{
|
|
21146
|
+
key: "subagentStop",
|
|
21147
|
+
event: "SubagentStop",
|
|
21148
|
+
commandMarker: EXE_HOOKS.subagentStop,
|
|
21149
|
+
owner: "exe-os",
|
|
21150
|
+
purpose: "Captures subagent completion context.",
|
|
21151
|
+
runtimes: ["claude"],
|
|
21152
|
+
checkpointRole: "none"
|
|
21153
|
+
},
|
|
21154
|
+
{
|
|
21155
|
+
key: "preCompact",
|
|
21156
|
+
event: "PreCompact",
|
|
21157
|
+
commandMarker: EXE_HOOKS.preCompact,
|
|
21158
|
+
owner: "exe-os",
|
|
21159
|
+
purpose: "Writes active-task snapshot and compaction recovery context.",
|
|
21160
|
+
runtimes: ["claude"],
|
|
21161
|
+
checkpointRole: "recovery_context"
|
|
21162
|
+
},
|
|
21163
|
+
{
|
|
21164
|
+
key: "postCompact",
|
|
21165
|
+
event: "PostCompact",
|
|
21166
|
+
commandMarker: EXE_HOOKS.postCompact,
|
|
21167
|
+
owner: "exe-os",
|
|
21168
|
+
purpose: "Rehydrates recovery context after compaction.",
|
|
21169
|
+
runtimes: ["claude"],
|
|
21170
|
+
checkpointRole: "recovery_context"
|
|
21171
|
+
},
|
|
21172
|
+
{
|
|
21173
|
+
key: "sessionEnd",
|
|
21174
|
+
event: "SessionEnd",
|
|
21175
|
+
commandMarker: EXE_HOOKS.sessionEnd,
|
|
21176
|
+
owner: "exe-os",
|
|
21177
|
+
purpose: "Stores session-end checkpoint and triages orphaned in-progress tasks.",
|
|
21178
|
+
runtimes: ["claude"],
|
|
21179
|
+
checkpointRole: "session_summary"
|
|
21180
|
+
},
|
|
21181
|
+
{
|
|
21182
|
+
key: "notification",
|
|
21183
|
+
event: "Notification",
|
|
21184
|
+
commandMarker: EXE_HOOKS.notification,
|
|
21185
|
+
owner: "exe-os",
|
|
21186
|
+
purpose: "Captures runtime notifications and nudges.",
|
|
21187
|
+
runtimes: ["claude"],
|
|
21188
|
+
checkpointRole: "none"
|
|
21189
|
+
},
|
|
21190
|
+
{
|
|
21191
|
+
key: "instructionsLoaded",
|
|
21192
|
+
event: "InstructionsLoaded",
|
|
21193
|
+
commandMarker: EXE_HOOKS.instructionsLoaded,
|
|
21194
|
+
owner: "exe-os",
|
|
21195
|
+
purpose: "Applies runtime instruction post-processing.",
|
|
21196
|
+
runtimes: ["claude"],
|
|
21197
|
+
checkpointRole: "none"
|
|
21198
|
+
}
|
|
21199
|
+
];
|
|
21200
|
+
LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS = [
|
|
21201
|
+
"dist/hooks/ingest.js",
|
|
21202
|
+
"dist/hooks/error-recall.js",
|
|
21203
|
+
"dist/hooks/ingest-worker.js"
|
|
21204
|
+
];
|
|
21205
|
+
}
|
|
21206
|
+
});
|
|
21207
|
+
|
|
21208
|
+
// src/lib/key-backup-status.ts
|
|
21209
|
+
var key_backup_status_exports = {};
|
|
21210
|
+
__export(key_backup_status_exports, {
|
|
21211
|
+
getKeyBackupStatus: () => getKeyBackupStatus,
|
|
21212
|
+
keyBackupMarkerPath: () => keyBackupMarkerPath,
|
|
21213
|
+
markKeyBackupConfirmed: () => markKeyBackupConfirmed
|
|
21214
|
+
});
|
|
21215
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync12, readFileSync as readFileSync23, writeFileSync as writeFileSync16 } from "fs";
|
|
21216
|
+
import path35 from "path";
|
|
21217
|
+
function keyBackupMarkerPath() {
|
|
21218
|
+
return path35.join(EXE_AI_DIR, "key-backup-confirmed.json");
|
|
21219
|
+
}
|
|
21220
|
+
function getKeyBackupStatus() {
|
|
21221
|
+
const marker = keyBackupMarkerPath();
|
|
21222
|
+
if (!existsSync30(marker)) return { exists: false };
|
|
21223
|
+
try {
|
|
21224
|
+
const parsed = JSON.parse(readFileSync23(marker, "utf8"));
|
|
21225
|
+
return {
|
|
21226
|
+
exists: true,
|
|
21227
|
+
confirmedAt: parsed.confirmedAt,
|
|
21228
|
+
source: parsed.source
|
|
21229
|
+
};
|
|
21230
|
+
} catch {
|
|
21231
|
+
return { exists: true };
|
|
21232
|
+
}
|
|
21233
|
+
}
|
|
21234
|
+
function markKeyBackupConfirmed(source) {
|
|
21235
|
+
mkdirSync12(EXE_AI_DIR, { recursive: true, mode: 448 });
|
|
21236
|
+
writeFileSync16(
|
|
21237
|
+
keyBackupMarkerPath(),
|
|
21238
|
+
JSON.stringify({ confirmedAt: (/* @__PURE__ */ new Date()).toISOString(), source }, null, 2) + "\n",
|
|
21239
|
+
{ mode: 384 }
|
|
21240
|
+
);
|
|
21241
|
+
}
|
|
21242
|
+
var init_key_backup_status = __esm({
|
|
21243
|
+
"src/lib/key-backup-status.ts"() {
|
|
21244
|
+
"use strict";
|
|
21245
|
+
init_config();
|
|
21246
|
+
}
|
|
21247
|
+
});
|
|
21248
|
+
|
|
21249
|
+
// src/bin/fast-db-init.ts
|
|
21250
|
+
var fast_db_init_exports = {};
|
|
21251
|
+
__export(fast_db_init_exports, {
|
|
21252
|
+
fastDbInit: () => fastDbInit
|
|
21253
|
+
});
|
|
21254
|
+
async function fastDbInit() {
|
|
21255
|
+
const { isInitialized: isInitialized2, getClient: getClient2, setExternalClient: setExternalClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
21256
|
+
if (isInitialized2()) {
|
|
21257
|
+
return getClient2();
|
|
21258
|
+
}
|
|
21259
|
+
try {
|
|
21260
|
+
const { connectEmbedDaemon: connectEmbedDaemon2, sendDaemonRequest: sendDaemonRequest2, isClientConnected: isClientConnected2 } = await Promise.resolve().then(() => (init_exe_daemon_client(), exe_daemon_client_exports));
|
|
21261
|
+
const { deserializeResultSet: deserializeResultSet2 } = await Promise.resolve().then(() => (init_daemon_protocol(), daemon_protocol_exports));
|
|
21262
|
+
await connectEmbedDaemon2();
|
|
21263
|
+
if (isClientConnected2()) {
|
|
21264
|
+
const daemonClient = {
|
|
21265
|
+
async execute(stmt) {
|
|
21266
|
+
const sql = typeof stmt === "string" ? stmt : stmt.sql;
|
|
21267
|
+
const args = typeof stmt === "string" ? [] : Array.isArray(stmt.args) ? stmt.args : [];
|
|
21268
|
+
const resp = await sendDaemonRequest2({ type: "db-execute", sql, args });
|
|
21269
|
+
if (resp.error) throw new Error(String(resp.error));
|
|
21270
|
+
if (resp.db) return deserializeResultSet2(resp.db);
|
|
21271
|
+
throw new Error("Unexpected daemon response");
|
|
21272
|
+
},
|
|
21273
|
+
async batch(stmts, mode) {
|
|
21274
|
+
const statements = stmts.map((s) => {
|
|
21275
|
+
const sql = typeof s === "string" ? s : s.sql;
|
|
21276
|
+
const args = typeof s === "string" ? [] : Array.isArray(s.args) ? s.args : [];
|
|
21277
|
+
return { sql, args };
|
|
21278
|
+
});
|
|
21279
|
+
const resp = await sendDaemonRequest2({ type: "db-batch", statements, mode: mode ?? "deferred" });
|
|
21280
|
+
if (resp.error) throw new Error(String(resp.error));
|
|
21281
|
+
const batchResults = resp["db-batch"];
|
|
21282
|
+
if (batchResults) return batchResults.map(deserializeResultSet2);
|
|
21283
|
+
throw new Error("Unexpected daemon batch response");
|
|
21284
|
+
},
|
|
21285
|
+
async transaction(_mode) {
|
|
21286
|
+
throw new Error("Transactions not supported via daemon socket");
|
|
21287
|
+
},
|
|
21288
|
+
async executeMultiple(_sql) {
|
|
21289
|
+
throw new Error("executeMultiple not supported via daemon socket");
|
|
21290
|
+
},
|
|
21291
|
+
async migrate(_stmts) {
|
|
21292
|
+
throw new Error("migrate not supported via daemon socket");
|
|
21293
|
+
},
|
|
21294
|
+
sync() {
|
|
21295
|
+
return Promise.resolve(void 0);
|
|
21296
|
+
},
|
|
21297
|
+
close() {
|
|
21298
|
+
},
|
|
21299
|
+
get closed() {
|
|
21300
|
+
return false;
|
|
21301
|
+
},
|
|
21302
|
+
get protocol() {
|
|
21303
|
+
return "file";
|
|
21304
|
+
}
|
|
21305
|
+
};
|
|
21306
|
+
setExternalClient2(daemonClient);
|
|
21307
|
+
return daemonClient;
|
|
21308
|
+
}
|
|
21309
|
+
} catch {
|
|
21310
|
+
}
|
|
21311
|
+
const { initStore: initStore2 } = await Promise.resolve().then(() => (init_store(), store_exports));
|
|
21312
|
+
await initStore2({ lightweight: true });
|
|
21313
|
+
return getClient2();
|
|
21314
|
+
}
|
|
21315
|
+
var init_fast_db_init = __esm({
|
|
21316
|
+
"src/bin/fast-db-init.ts"() {
|
|
21317
|
+
"use strict";
|
|
21318
|
+
}
|
|
21319
|
+
});
|
|
21320
|
+
|
|
21032
21321
|
// src/lib/db-backup.ts
|
|
21033
21322
|
var db_backup_exports = {};
|
|
21034
21323
|
__export(db_backup_exports, {
|
|
@@ -21040,33 +21329,33 @@ __export(db_backup_exports, {
|
|
|
21040
21329
|
listBackups: () => listBackups,
|
|
21041
21330
|
rotateBackups: () => rotateBackups
|
|
21042
21331
|
});
|
|
21043
|
-
import { copyFileSync, existsSync as
|
|
21044
|
-
import
|
|
21332
|
+
import { copyFileSync, existsSync as existsSync31, mkdirSync as mkdirSync13, readdirSync as readdirSync10, unlinkSync as unlinkSync10, statSync as statSync5 } from "fs";
|
|
21333
|
+
import path36 from "path";
|
|
21045
21334
|
function findActiveDb() {
|
|
21046
21335
|
for (const name of DB_NAMES) {
|
|
21047
|
-
const p =
|
|
21048
|
-
if (
|
|
21336
|
+
const p = path36.join(EXE_AI_DIR, name);
|
|
21337
|
+
if (existsSync31(p)) return p;
|
|
21049
21338
|
}
|
|
21050
21339
|
return null;
|
|
21051
21340
|
}
|
|
21052
21341
|
function createBackup(reason = "manual") {
|
|
21053
21342
|
const dbPath = findActiveDb();
|
|
21054
21343
|
if (!dbPath) return null;
|
|
21055
|
-
|
|
21056
|
-
const dbName =
|
|
21344
|
+
mkdirSync13(BACKUP_DIR, { recursive: true });
|
|
21345
|
+
const dbName = path36.basename(dbPath, ".db");
|
|
21057
21346
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
21058
21347
|
const backupName = `${dbName}-${reason}-${timestamp}.db`;
|
|
21059
|
-
const backupPath =
|
|
21348
|
+
const backupPath = path36.join(BACKUP_DIR, backupName);
|
|
21060
21349
|
copyFileSync(dbPath, backupPath);
|
|
21061
21350
|
const walPath = dbPath + "-wal";
|
|
21062
|
-
if (
|
|
21351
|
+
if (existsSync31(walPath)) {
|
|
21063
21352
|
try {
|
|
21064
21353
|
copyFileSync(walPath, backupPath + "-wal");
|
|
21065
21354
|
} catch {
|
|
21066
21355
|
}
|
|
21067
21356
|
}
|
|
21068
21357
|
const shmPath = dbPath + "-shm";
|
|
21069
|
-
if (
|
|
21358
|
+
if (existsSync31(shmPath)) {
|
|
21070
21359
|
try {
|
|
21071
21360
|
copyFileSync(shmPath, backupPath + "-shm");
|
|
21072
21361
|
} catch {
|
|
@@ -21075,14 +21364,14 @@ function createBackup(reason = "manual") {
|
|
|
21075
21364
|
return backupPath;
|
|
21076
21365
|
}
|
|
21077
21366
|
function rotateBackups(keepDays = DEFAULT_KEEP_DAYS) {
|
|
21078
|
-
if (!
|
|
21367
|
+
if (!existsSync31(BACKUP_DIR)) return 0;
|
|
21079
21368
|
const cutoff = Date.now() - keepDays * 24 * 60 * 60 * 1e3;
|
|
21080
21369
|
let deleted = 0;
|
|
21081
21370
|
try {
|
|
21082
21371
|
const files = readdirSync10(BACKUP_DIR);
|
|
21083
21372
|
for (const file of files) {
|
|
21084
21373
|
if (!file.endsWith(".db") && !file.endsWith(".db-wal") && !file.endsWith(".db-shm")) continue;
|
|
21085
|
-
const filePath =
|
|
21374
|
+
const filePath = path36.join(BACKUP_DIR, file);
|
|
21086
21375
|
try {
|
|
21087
21376
|
const stat = statSync5(filePath);
|
|
21088
21377
|
if (stat.mtimeMs < cutoff) {
|
|
@@ -21097,11 +21386,11 @@ function rotateBackups(keepDays = DEFAULT_KEEP_DAYS) {
|
|
|
21097
21386
|
return deleted;
|
|
21098
21387
|
}
|
|
21099
21388
|
function listBackups() {
|
|
21100
|
-
if (!
|
|
21389
|
+
if (!existsSync31(BACKUP_DIR)) return [];
|
|
21101
21390
|
try {
|
|
21102
21391
|
const files = readdirSync10(BACKUP_DIR).filter((f) => f.endsWith(".db") && !f.endsWith("-wal") && !f.endsWith("-shm"));
|
|
21103
21392
|
return files.map((name) => {
|
|
21104
|
-
const p =
|
|
21393
|
+
const p = path36.join(BACKUP_DIR, name);
|
|
21105
21394
|
const stat = statSync5(p);
|
|
21106
21395
|
return { path: p, name, size: stat.size, date: stat.mtime };
|
|
21107
21396
|
}).sort((a, b) => b.date.getTime() - a.date.getTime());
|
|
@@ -21126,7 +21415,7 @@ var init_db_backup = __esm({
|
|
|
21126
21415
|
"src/lib/db-backup.ts"() {
|
|
21127
21416
|
"use strict";
|
|
21128
21417
|
init_config();
|
|
21129
|
-
BACKUP_DIR =
|
|
21418
|
+
BACKUP_DIR = path36.join(EXE_AI_DIR, "backups");
|
|
21130
21419
|
DEFAULT_KEEP_DAYS = 3;
|
|
21131
21420
|
DB_NAMES = ["memories.db", "exe-mem.db", "exe-os.db", "exe.db"];
|
|
21132
21421
|
}
|
|
@@ -21134,9 +21423,9 @@ var init_db_backup = __esm({
|
|
|
21134
21423
|
|
|
21135
21424
|
// src/bin/exe-doctor.ts
|
|
21136
21425
|
import os16 from "os";
|
|
21137
|
-
import { existsSync as
|
|
21426
|
+
import { existsSync as existsSync32, readFileSync as readFileSync24 } from "fs";
|
|
21138
21427
|
import { spawn as spawn2 } from "child_process";
|
|
21139
|
-
import
|
|
21428
|
+
import path37 from "path";
|
|
21140
21429
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
21141
21430
|
function parseFlags(argv) {
|
|
21142
21431
|
const flags = { fix: false, dryRun: false, verbose: false, conflicts: false };
|
|
@@ -21288,7 +21577,7 @@ async function auditOrphanedProjects(client) {
|
|
|
21288
21577
|
for (const row of result.rows) {
|
|
21289
21578
|
const name = row.project_name;
|
|
21290
21579
|
const count = Number(row.cnt);
|
|
21291
|
-
const exists =
|
|
21580
|
+
const exists = existsSync32(path37.join(home, name)) || existsSync32(path37.join(home, "..", name)) || existsSync32(path37.join(process.cwd(), "..", name));
|
|
21292
21581
|
if (!exists) {
|
|
21293
21582
|
orphans.push({ project_name: name, count });
|
|
21294
21583
|
}
|
|
@@ -21296,18 +21585,18 @@ async function auditOrphanedProjects(client) {
|
|
|
21296
21585
|
return orphans;
|
|
21297
21586
|
}
|
|
21298
21587
|
function auditHookHealth() {
|
|
21299
|
-
const logPath =
|
|
21588
|
+
const logPath = path37.join(
|
|
21300
21589
|
process.env.HOME ?? process.env.USERPROFILE ?? "",
|
|
21301
21590
|
".exe-os",
|
|
21302
21591
|
"logs",
|
|
21303
21592
|
"hooks.log"
|
|
21304
21593
|
);
|
|
21305
|
-
if (!
|
|
21594
|
+
if (!existsSync32(logPath)) {
|
|
21306
21595
|
return { logExists: false, totalLines: 0, errorsLastHour: 0, topPatterns: [] };
|
|
21307
21596
|
}
|
|
21308
21597
|
let content;
|
|
21309
21598
|
try {
|
|
21310
|
-
content =
|
|
21599
|
+
content = readFileSync24(logPath, "utf-8");
|
|
21311
21600
|
} catch {
|
|
21312
21601
|
return { logExists: false, totalLines: 0, errorsLastHour: 0, topPatterns: [] };
|
|
21313
21602
|
}
|
|
@@ -21335,6 +21624,121 @@ function auditHookHealth() {
|
|
|
21335
21624
|
const topPatterns = [...patternCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([pattern, count]) => ({ pattern, count }));
|
|
21336
21625
|
return { logExists: true, totalLines, errorsLastHour, topPatterns };
|
|
21337
21626
|
}
|
|
21627
|
+
function safeReadJson(filePath) {
|
|
21628
|
+
if (!existsSync32(filePath)) return null;
|
|
21629
|
+
try {
|
|
21630
|
+
return JSON.parse(readFileSync24(filePath, "utf-8"));
|
|
21631
|
+
} catch {
|
|
21632
|
+
return null;
|
|
21633
|
+
}
|
|
21634
|
+
}
|
|
21635
|
+
function collectHookCommandsFromClaudeSettings(settings) {
|
|
21636
|
+
const hooks = settings?.hooks;
|
|
21637
|
+
if (!hooks || typeof hooks !== "object") return [];
|
|
21638
|
+
const commands = [];
|
|
21639
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
21640
|
+
if (!Array.isArray(groups)) continue;
|
|
21641
|
+
for (const group of groups) {
|
|
21642
|
+
const hooksForGroup = group?.hooks;
|
|
21643
|
+
if (!Array.isArray(hooksForGroup)) continue;
|
|
21644
|
+
for (const hook of hooksForGroup) {
|
|
21645
|
+
const command = hook?.command;
|
|
21646
|
+
if (typeof command === "string") commands.push({ event, command });
|
|
21647
|
+
}
|
|
21648
|
+
}
|
|
21649
|
+
}
|
|
21650
|
+
return commands;
|
|
21651
|
+
}
|
|
21652
|
+
function collectHookCommandsFromCodexHooks(config2) {
|
|
21653
|
+
const commands = [];
|
|
21654
|
+
if (!config2 || typeof config2 !== "object") return commands;
|
|
21655
|
+
const root = config2;
|
|
21656
|
+
for (const [event, value] of Object.entries(root)) {
|
|
21657
|
+
const entries = Array.isArray(value) ? value : value && typeof value === "object" ? Object.values(value) : [];
|
|
21658
|
+
for (const entry of entries) {
|
|
21659
|
+
if (typeof entry === "string") commands.push({ event, command: entry });
|
|
21660
|
+
const command = entry?.command;
|
|
21661
|
+
if (typeof command === "string") commands.push({ event, command });
|
|
21662
|
+
}
|
|
21663
|
+
}
|
|
21664
|
+
return commands;
|
|
21665
|
+
}
|
|
21666
|
+
function buildHookOwnershipIssues(runtime, commands) {
|
|
21667
|
+
const issues = [];
|
|
21668
|
+
for (const marker of LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS) {
|
|
21669
|
+
const count = commands.filter((cmd) => cmd.command.includes(marker)).length;
|
|
21670
|
+
if (count > 0) {
|
|
21671
|
+
issues.push({
|
|
21672
|
+
runtime,
|
|
21673
|
+
event: "PostToolUse",
|
|
21674
|
+
marker,
|
|
21675
|
+
count,
|
|
21676
|
+
message: `Legacy split PostToolUse hook still installed: ${marker}`
|
|
21677
|
+
});
|
|
21678
|
+
}
|
|
21679
|
+
}
|
|
21680
|
+
for (const entry of EXE_HOOK_MANIFEST.filter((hook) => hook.runtimes.includes(runtime))) {
|
|
21681
|
+
const matching = commands.filter((cmd) => cmd.command.includes(entry.commandMarker));
|
|
21682
|
+
if (matching.length > 1) {
|
|
21683
|
+
issues.push({
|
|
21684
|
+
runtime,
|
|
21685
|
+
event: entry.event,
|
|
21686
|
+
marker: entry.commandMarker,
|
|
21687
|
+
count: matching.length,
|
|
21688
|
+
message: `Duplicate exe-os hook owner for ${entry.event}: ${entry.commandMarker}`
|
|
21689
|
+
});
|
|
21690
|
+
}
|
|
21691
|
+
for (const cmd of matching) {
|
|
21692
|
+
if (cmd.event !== entry.event) {
|
|
21693
|
+
issues.push({
|
|
21694
|
+
runtime,
|
|
21695
|
+
event: cmd.event,
|
|
21696
|
+
marker: entry.commandMarker,
|
|
21697
|
+
count: 1,
|
|
21698
|
+
message: `exe-os hook ${entry.commandMarker} is registered under ${cmd.event}, expected ${entry.event}`
|
|
21699
|
+
});
|
|
21700
|
+
}
|
|
21701
|
+
}
|
|
21702
|
+
}
|
|
21703
|
+
for (const cmd of commands) {
|
|
21704
|
+
if (!cmd.command.includes("dist/hooks/")) continue;
|
|
21705
|
+
if (!cmd.command.includes("exe-os")) continue;
|
|
21706
|
+
const entry = manifestEntryForCommand(cmd.command);
|
|
21707
|
+
const isLegacy = LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS.some((marker) => cmd.command.includes(marker));
|
|
21708
|
+
if (!entry && !isLegacy) {
|
|
21709
|
+
issues.push({
|
|
21710
|
+
runtime,
|
|
21711
|
+
event: cmd.event,
|
|
21712
|
+
marker: "dist/hooks/",
|
|
21713
|
+
count: 1,
|
|
21714
|
+
message: `Unknown exe-os hook command not present in ownership manifest: ${cmd.command.slice(0, 160)}`
|
|
21715
|
+
});
|
|
21716
|
+
}
|
|
21717
|
+
}
|
|
21718
|
+
return issues;
|
|
21719
|
+
}
|
|
21720
|
+
function auditHookOwnership() {
|
|
21721
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
21722
|
+
const checkedFiles = [];
|
|
21723
|
+
const issues = [];
|
|
21724
|
+
const claudeSettingsPath = path37.join(home, ".claude", "settings.json");
|
|
21725
|
+
const claudeSettings = safeReadJson(claudeSettingsPath);
|
|
21726
|
+
if (claudeSettings) {
|
|
21727
|
+
checkedFiles.push(claudeSettingsPath);
|
|
21728
|
+
issues.push(...buildHookOwnershipIssues("claude", collectHookCommandsFromClaudeSettings(claudeSettings)));
|
|
21729
|
+
}
|
|
21730
|
+
const codexHooksPath = path37.join(home, ".codex", "hooks.json");
|
|
21731
|
+
const codexHooks = safeReadJson(codexHooksPath);
|
|
21732
|
+
if (codexHooks) {
|
|
21733
|
+
checkedFiles.push(codexHooksPath);
|
|
21734
|
+
issues.push(...buildHookOwnershipIssues("codex", collectHookCommandsFromCodexHooks(codexHooks)));
|
|
21735
|
+
}
|
|
21736
|
+
return {
|
|
21737
|
+
checkedFiles,
|
|
21738
|
+
issues,
|
|
21739
|
+
staleLegacyHooks: issues.filter((issue) => issue.message.includes("Legacy split"))
|
|
21740
|
+
};
|
|
21741
|
+
}
|
|
21338
21742
|
async function auditShards() {
|
|
21339
21743
|
try {
|
|
21340
21744
|
const { auditShardHealth: auditShardHealth2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -21350,16 +21754,33 @@ async function auditShards() {
|
|
|
21350
21754
|
return { total: 0, ok: 0, unreadable: 0, archived: 0, unreadableNames: [] };
|
|
21351
21755
|
}
|
|
21352
21756
|
}
|
|
21757
|
+
async function auditKeyHealth() {
|
|
21758
|
+
try {
|
|
21759
|
+
const { getMasterKey: getMasterKey2 } = await Promise.resolve().then(() => (init_keychain(), keychain_exports));
|
|
21760
|
+
const { getKeyBackupStatus: getKeyBackupStatus2 } = await Promise.resolve().then(() => (init_key_backup_status(), key_backup_status_exports));
|
|
21761
|
+
const key = await getMasterKey2();
|
|
21762
|
+
const backup = getKeyBackupStatus2();
|
|
21763
|
+
return {
|
|
21764
|
+
masterKeyPresent: Boolean(key),
|
|
21765
|
+
recoveryBackupMarked: backup.exists,
|
|
21766
|
+
recoveryBackupConfirmedAt: backup.confirmedAt,
|
|
21767
|
+
recoveryBackupSource: backup.source
|
|
21768
|
+
};
|
|
21769
|
+
} catch {
|
|
21770
|
+
return { masterKeyPresent: false, recoveryBackupMarked: false };
|
|
21771
|
+
}
|
|
21772
|
+
}
|
|
21353
21773
|
async function runAudit(client, flags) {
|
|
21354
21774
|
const runConflicts = flags.conflicts || process.env.EXE_AUDIT_CONFLICTS === "1";
|
|
21355
|
-
const [stats, nullVectors, duplicates, bloated, fts, orphanedProjects, shards] = await Promise.all([
|
|
21775
|
+
const [stats, nullVectors, duplicates, bloated, fts, orphanedProjects, shards, keyHealth] = await Promise.all([
|
|
21356
21776
|
auditStats(client, flags),
|
|
21357
21777
|
auditNullVectors(client, flags),
|
|
21358
21778
|
auditDuplicates(client, flags),
|
|
21359
21779
|
auditBloated(client, flags),
|
|
21360
21780
|
auditFts(client),
|
|
21361
21781
|
auditOrphanedProjects(client),
|
|
21362
|
-
auditShards()
|
|
21782
|
+
auditShards(),
|
|
21783
|
+
auditKeyHealth()
|
|
21363
21784
|
]);
|
|
21364
21785
|
let conflicts;
|
|
21365
21786
|
if (runConflicts) {
|
|
@@ -21379,7 +21800,8 @@ async function runAudit(client, flags) {
|
|
|
21379
21800
|
}
|
|
21380
21801
|
const duplicateCount = duplicates.reduce((sum, d) => sum + d.delete_ids.length, 0);
|
|
21381
21802
|
const hookHealth = auditHookHealth();
|
|
21382
|
-
|
|
21803
|
+
const hookOwnership = auditHookOwnership();
|
|
21804
|
+
return { stats, nullVectors, duplicates, duplicateCount, bloated, fts, orphanedProjects, conflicts, hookHealth, hookOwnership, shards, keyHealth };
|
|
21383
21805
|
}
|
|
21384
21806
|
function indicator(value, warn) {
|
|
21385
21807
|
if (value === 0) return "\u{1F7E2}";
|
|
@@ -21427,6 +21849,15 @@ function formatReport(report, flags) {
|
|
|
21427
21849
|
lines.push(`${indicator(report.bloated.length, 20)} Bloated (>5KB): ${fmtNum(report.bloated.length)} / ${fmtNum(s.total)} (${pct(report.bloated.length, s.total)})`);
|
|
21428
21850
|
const ftsIndicator = report.fts.inSync ? "\u{1F7E2}" : "\u{1F534}";
|
|
21429
21851
|
lines.push(`${ftsIndicator} FTS index: ${report.fts.inSync ? "in sync" : "OUT OF SYNC"} (${fmtNum(report.fts.memoryCount)} / ${fmtNum(report.fts.ftsCount)})`);
|
|
21852
|
+
const kh = report.keyHealth;
|
|
21853
|
+
if (!kh.masterKeyPresent) {
|
|
21854
|
+
lines.push("\u{1F534} Recovery key: master key missing \u2014 import phrase or run setup before syncing");
|
|
21855
|
+
} else if (!kh.recoveryBackupMarked) {
|
|
21856
|
+
lines.push("\u{1F534} Recovery backup: not confirmed \u2014 run `exe-os link export --local-terminal-only` and save the 24-word phrase");
|
|
21857
|
+
} else {
|
|
21858
|
+
const suffix = kh.recoveryBackupConfirmedAt ? ` (${kh.recoveryBackupConfirmedAt.slice(0, 10)}${kh.recoveryBackupSource ? ` via ${kh.recoveryBackupSource}` : ""})` : "";
|
|
21859
|
+
lines.push(`\u{1F7E2} Recovery backup: confirmed${suffix}`);
|
|
21860
|
+
}
|
|
21430
21861
|
if (report.orphanedProjects.length > 0) {
|
|
21431
21862
|
const orphanList = report.orphanedProjects.map((o) => `${o.project_name} \u2014 ${o.count} memories`).join(", ");
|
|
21432
21863
|
lines.push(`\u2139\uFE0F Orphaned projects: ${report.orphanedProjects.length} (${orphanList})`);
|
|
@@ -21458,6 +21889,15 @@ function formatReport(report, flags) {
|
|
|
21458
21889
|
lines.push(` ${p.count}x: ${p.pattern}`);
|
|
21459
21890
|
}
|
|
21460
21891
|
}
|
|
21892
|
+
const ho = report.hookOwnership;
|
|
21893
|
+
if (ho.issues.length === 0) {
|
|
21894
|
+
lines.push(`\u{1F7E2} Hook ownership: ${ho.checkedFiles.length > 0 ? "manifest clean" : "no local hook config found"}`);
|
|
21895
|
+
} else {
|
|
21896
|
+
lines.push(`\u{1F534} Hook ownership: ${fmtNum(ho.issues.length)} issue(s)`);
|
|
21897
|
+
for (const issue of ho.issues.slice(0, 5)) {
|
|
21898
|
+
lines.push(` [${issue.runtime}/${issue.event}] ${issue.message}`);
|
|
21899
|
+
}
|
|
21900
|
+
}
|
|
21461
21901
|
const sh = report.shards;
|
|
21462
21902
|
if (sh.total > 0) {
|
|
21463
21903
|
if (sh.unreadable === 0) {
|
|
@@ -21527,6 +21967,9 @@ function formatReport(report, flags) {
|
|
|
21527
21967
|
if (report.conflicts.superseded > 0) {
|
|
21528
21968
|
recs.push(`${fmtNum(report.conflicts.superseded)} superseded memories can be deactivated`);
|
|
21529
21969
|
}
|
|
21970
|
+
if (report.hookOwnership.issues.length > 0) {
|
|
21971
|
+
recs.push(`Run exe-os install to refresh hook config; remove stale exe-os hook commands if they remain`);
|
|
21972
|
+
}
|
|
21530
21973
|
if (recs.length > 0) {
|
|
21531
21974
|
lines.push("Recommendations:");
|
|
21532
21975
|
for (const r of recs) {
|
|
@@ -21548,7 +21991,7 @@ async function fixNullVectors() {
|
|
|
21548
21991
|
}
|
|
21549
21992
|
}
|
|
21550
21993
|
const npmRoot = (await import("child_process")).execSync("npm root -g", { encoding: "utf8" }).trim();
|
|
21551
|
-
const backfillPath =
|
|
21994
|
+
const backfillPath = path37.join(npmRoot, "exe-os", "dist", "bin", "backfill-vectors.js");
|
|
21552
21995
|
return new Promise((resolve, reject) => {
|
|
21553
21996
|
const child = spawn2("node", [backfillPath], { stdio: "inherit" });
|
|
21554
21997
|
if (child.pid) registerWorkerPid2(child.pid);
|
|
@@ -21660,8 +22103,8 @@ function splitAtSentences(text3, maxChunkSize) {
|
|
|
21660
22103
|
}
|
|
21661
22104
|
async function main(argv = process.argv.slice(2)) {
|
|
21662
22105
|
const flags = parseFlags(argv);
|
|
21663
|
-
await
|
|
21664
|
-
const client =
|
|
22106
|
+
const { fastDbInit: fastDbInit2 } = await Promise.resolve().then(() => (init_fast_db_init(), fast_db_init_exports));
|
|
22107
|
+
const client = await fastDbInit2();
|
|
21665
22108
|
const report = await runAudit(client, flags);
|
|
21666
22109
|
console.log(formatReport(report, flags));
|
|
21667
22110
|
if (flags.fix || flags.dryRun) {
|
|
@@ -21721,10 +22164,9 @@ ${mode} Complete.`);
|
|
|
21721
22164
|
var init_exe_doctor = __esm({
|
|
21722
22165
|
"src/bin/exe-doctor.ts"() {
|
|
21723
22166
|
"use strict";
|
|
21724
|
-
init_store();
|
|
21725
|
-
init_database();
|
|
21726
22167
|
init_is_main();
|
|
21727
22168
|
init_conflict_detector();
|
|
22169
|
+
init_runtime_hook_manifest();
|
|
21728
22170
|
if (isMainModule(import.meta.url) && (process.argv[1] ?? "").includes("exe-doctor")) {
|
|
21729
22171
|
main().catch((err) => {
|
|
21730
22172
|
console.error(err instanceof Error ? err.message : String(err));
|
|
@@ -21960,8 +22402,8 @@ __export(crdt_sync_exports, {
|
|
|
21960
22402
|
rebuildFromDb: () => rebuildFromDb
|
|
21961
22403
|
});
|
|
21962
22404
|
import * as Y from "yjs";
|
|
21963
|
-
import { readFileSync as
|
|
21964
|
-
import
|
|
22405
|
+
import { readFileSync as readFileSync25, writeFileSync as writeFileSync17, existsSync as existsSync33, mkdirSync as mkdirSync14, unlinkSync as unlinkSync11 } from "fs";
|
|
22406
|
+
import path38 from "path";
|
|
21965
22407
|
import { homedir as homedir5 } from "os";
|
|
21966
22408
|
function getStatePath() {
|
|
21967
22409
|
return _statePathOverride ?? DEFAULT_STATE_PATH;
|
|
@@ -21973,9 +22415,9 @@ function initCrdtDoc() {
|
|
|
21973
22415
|
if (doc) return doc;
|
|
21974
22416
|
doc = new Y.Doc();
|
|
21975
22417
|
const sp = getStatePath();
|
|
21976
|
-
if (
|
|
22418
|
+
if (existsSync33(sp)) {
|
|
21977
22419
|
try {
|
|
21978
|
-
const state =
|
|
22420
|
+
const state = readFileSync25(sp);
|
|
21979
22421
|
Y.applyUpdate(doc, new Uint8Array(state));
|
|
21980
22422
|
} catch {
|
|
21981
22423
|
console.warn("[crdt-sync] WARN: corrupted state file, rebuilding from DB");
|
|
@@ -22117,10 +22559,10 @@ function persistState() {
|
|
|
22117
22559
|
if (!doc) return;
|
|
22118
22560
|
try {
|
|
22119
22561
|
const sp = getStatePath();
|
|
22120
|
-
const dir =
|
|
22121
|
-
if (!
|
|
22562
|
+
const dir = path38.dirname(sp);
|
|
22563
|
+
if (!existsSync33(dir)) mkdirSync14(dir, { recursive: true });
|
|
22122
22564
|
const state = Y.encodeStateAsUpdate(doc);
|
|
22123
|
-
|
|
22565
|
+
writeFileSync17(sp, Buffer.from(state));
|
|
22124
22566
|
} catch {
|
|
22125
22567
|
}
|
|
22126
22568
|
}
|
|
@@ -22161,7 +22603,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
|
|
|
22161
22603
|
var init_crdt_sync = __esm({
|
|
22162
22604
|
"src/lib/crdt-sync.ts"() {
|
|
22163
22605
|
"use strict";
|
|
22164
|
-
DEFAULT_STATE_PATH =
|
|
22606
|
+
DEFAULT_STATE_PATH = path38.join(homedir5(), ".exe-os", "crdt-state.bin");
|
|
22165
22607
|
_statePathOverride = null;
|
|
22166
22608
|
doc = null;
|
|
22167
22609
|
}
|
|
@@ -22170,8 +22612,10 @@ var init_crdt_sync = __esm({
|
|
|
22170
22612
|
// src/lib/cloud-sync.ts
|
|
22171
22613
|
var cloud_sync_exports = {};
|
|
22172
22614
|
__export(cloud_sync_exports, {
|
|
22615
|
+
CLOUD_RELINK_REQUIRED_MESSAGE: () => CLOUD_RELINK_REQUIRED_MESSAGE,
|
|
22173
22616
|
assertSecureEndpoint: () => assertSecureEndpoint,
|
|
22174
22617
|
buildRosterBlob: () => buildRosterBlob,
|
|
22618
|
+
clearCloudRelinkRequired: () => clearCloudRelinkRequired,
|
|
22175
22619
|
cloudPull: () => cloudPull,
|
|
22176
22620
|
cloudPullBehaviors: () => cloudPullBehaviors,
|
|
22177
22621
|
cloudPullBlob: () => cloudPullBlob,
|
|
@@ -22191,21 +22635,22 @@ __export(cloud_sync_exports, {
|
|
|
22191
22635
|
cloudPushRoster: () => cloudPushRoster,
|
|
22192
22636
|
cloudPushTasks: () => cloudPushTasks,
|
|
22193
22637
|
cloudSync: () => cloudSync,
|
|
22638
|
+
getCloudRelinkRequired: () => getCloudRelinkRequired,
|
|
22194
22639
|
mergeConfig: () => mergeConfig,
|
|
22195
22640
|
mergeRosterFromRemote: () => mergeRosterFromRemote,
|
|
22196
22641
|
pushToPostgres: () => pushToPostgres,
|
|
22197
22642
|
recordRosterDeletion: () => recordRosterDeletion
|
|
22198
22643
|
});
|
|
22199
|
-
import { readFileSync as
|
|
22644
|
+
import { readFileSync as readFileSync26, writeFileSync as writeFileSync18, existsSync as existsSync34, readdirSync as readdirSync11, mkdirSync as mkdirSync15, appendFileSync as appendFileSync3, unlinkSync as unlinkSync12, openSync as openSync2, closeSync as closeSync2, statSync as statSync6 } from "fs";
|
|
22200
22645
|
import crypto16 from "crypto";
|
|
22201
|
-
import
|
|
22646
|
+
import path39 from "path";
|
|
22202
22647
|
import { homedir as homedir6 } from "os";
|
|
22203
22648
|
function sqlSafe(v) {
|
|
22204
22649
|
return v === void 0 ? null : v;
|
|
22205
22650
|
}
|
|
22206
22651
|
function logError(msg) {
|
|
22207
22652
|
try {
|
|
22208
|
-
const logPath =
|
|
22653
|
+
const logPath = path39.join(homedir6(), ".exe-os", "workers.log");
|
|
22209
22654
|
appendFileSync3(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
|
|
22210
22655
|
`);
|
|
22211
22656
|
} catch {
|
|
@@ -22216,12 +22661,12 @@ function isTruthyEnv2(value) {
|
|
|
22216
22661
|
}
|
|
22217
22662
|
function loadPgClient() {
|
|
22218
22663
|
if (_pgFailed) return null;
|
|
22219
|
-
const configPath =
|
|
22664
|
+
const configPath = path39.join(EXE_AI_DIR, "config.json");
|
|
22220
22665
|
let cloudPostgresUrl;
|
|
22221
22666
|
let configEnabled = false;
|
|
22222
22667
|
try {
|
|
22223
|
-
if (
|
|
22224
|
-
const cfg = JSON.parse(
|
|
22668
|
+
if (existsSync34(configPath)) {
|
|
22669
|
+
const cfg = JSON.parse(readFileSync26(configPath, "utf8"));
|
|
22225
22670
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
22226
22671
|
configEnabled = cfg.cloud?.syncToPostgres === true;
|
|
22227
22672
|
}
|
|
@@ -22248,8 +22693,8 @@ function loadPgClient() {
|
|
|
22248
22693
|
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
22249
22694
|
return new Ctor2();
|
|
22250
22695
|
}
|
|
22251
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
22252
|
-
const req = createRequire7(
|
|
22696
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path39.join(homedir6(), "exe-db");
|
|
22697
|
+
const req = createRequire7(path39.join(exeDbRoot, "package.json"));
|
|
22253
22698
|
const entry = req.resolve("@prisma/client");
|
|
22254
22699
|
const mod = await import(pathToFileURL7(entry).href);
|
|
22255
22700
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -22294,18 +22739,18 @@ async function withRosterLock(fn) {
|
|
|
22294
22739
|
try {
|
|
22295
22740
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
22296
22741
|
closeSync2(fd);
|
|
22297
|
-
|
|
22742
|
+
writeFileSync18(ROSTER_LOCK_PATH, String(Date.now()));
|
|
22298
22743
|
} catch (err) {
|
|
22299
22744
|
if (err.code === "EEXIST") {
|
|
22300
22745
|
try {
|
|
22301
|
-
const ts2 = parseInt(
|
|
22746
|
+
const ts2 = parseInt(readFileSync26(ROSTER_LOCK_PATH, "utf-8"), 10);
|
|
22302
22747
|
if (Date.now() - ts2 < LOCK_STALE_MS) {
|
|
22303
22748
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
22304
22749
|
}
|
|
22305
22750
|
unlinkSync12(ROSTER_LOCK_PATH);
|
|
22306
22751
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
22307
22752
|
closeSync2(fd);
|
|
22308
|
-
|
|
22753
|
+
writeFileSync18(ROSTER_LOCK_PATH, String(Date.now()));
|
|
22309
22754
|
} catch (retryErr) {
|
|
22310
22755
|
if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
|
|
22311
22756
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
@@ -22424,6 +22869,24 @@ async function cloudPull(sinceVersion, config2) {
|
|
|
22424
22869
|
return { records: [], maxVersion: sinceVersion };
|
|
22425
22870
|
}
|
|
22426
22871
|
}
|
|
22872
|
+
async function getCloudRelinkRequired(client = getClient()) {
|
|
22873
|
+
try {
|
|
22874
|
+
await client.execute("CREATE TABLE IF NOT EXISTS sync_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)");
|
|
22875
|
+
const relink = await client.execute("SELECT value FROM sync_meta WHERE key = 'cloud_relink_required' LIMIT 1");
|
|
22876
|
+
return String(relink.rows[0]?.value ?? "") === "1";
|
|
22877
|
+
} catch {
|
|
22878
|
+
return false;
|
|
22879
|
+
}
|
|
22880
|
+
}
|
|
22881
|
+
async function clearCloudRelinkRequired(client = getClient()) {
|
|
22882
|
+
await client.execute("CREATE TABLE IF NOT EXISTS sync_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)");
|
|
22883
|
+
await client.execute("INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('cloud_relink_required', '0')");
|
|
22884
|
+
await client.execute({
|
|
22885
|
+
sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('cloud_relinked_at', ?)",
|
|
22886
|
+
args: [(/* @__PURE__ */ new Date()).toISOString()]
|
|
22887
|
+
});
|
|
22888
|
+
await client.execute("DELETE FROM sync_meta WHERE key IN ('last_cloud_pull_version', 'last_cloud_push_version')");
|
|
22889
|
+
}
|
|
22427
22890
|
async function cloudSync(config2) {
|
|
22428
22891
|
if (!isSyncCryptoInitialized()) {
|
|
22429
22892
|
try {
|
|
@@ -22445,10 +22908,7 @@ async function cloudSync(config2) {
|
|
|
22445
22908
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
22446
22909
|
}
|
|
22447
22910
|
try {
|
|
22448
|
-
|
|
22449
|
-
if (String(relink.rows[0]?.value ?? "") === "1") {
|
|
22450
|
-
throw new Error("[cloud-sync] Paused after key rotation. Re-link/reupload cloud sync with the new recovery phrase before syncing.");
|
|
22451
|
-
}
|
|
22911
|
+
if (await getCloudRelinkRequired(client)) throw new Error(CLOUD_RELINK_REQUIRED_MESSAGE);
|
|
22452
22912
|
} catch (err) {
|
|
22453
22913
|
const msg = err instanceof Error ? err.message : String(err);
|
|
22454
22914
|
if (msg.includes("Paused after key rotation")) throw err;
|
|
@@ -22698,8 +23158,8 @@ async function cloudSync(config2) {
|
|
|
22698
23158
|
try {
|
|
22699
23159
|
const employees = await loadEmployees();
|
|
22700
23160
|
rosterResult.employees = employees.length;
|
|
22701
|
-
const idDir =
|
|
22702
|
-
if (
|
|
23161
|
+
const idDir = path39.join(EXE_AI_DIR, "identity");
|
|
23162
|
+
if (existsSync34(idDir)) {
|
|
22703
23163
|
rosterResult.identities = readdirSync11(idDir).filter((f) => f.endsWith(".md")).length;
|
|
22704
23164
|
}
|
|
22705
23165
|
} catch {
|
|
@@ -22712,7 +23172,7 @@ async function cloudSync(config2) {
|
|
|
22712
23172
|
const backupSize = statSync6(latestBackup).size;
|
|
22713
23173
|
const MAX_CLOUD_BACKUP_BYTES = 50 * 1024 * 1024;
|
|
22714
23174
|
if (backupSize <= MAX_CLOUD_BACKUP_BYTES) {
|
|
22715
|
-
const backupData =
|
|
23175
|
+
const backupData = readFileSync26(latestBackup);
|
|
22716
23176
|
const deviceId = loadDeviceId() ?? "unknown";
|
|
22717
23177
|
const encrypted = encryptSyncBlob(backupData);
|
|
22718
23178
|
const backupRes = await fetchWithRetry(`${config2.endpoint}/sync/push-db-backup`, {
|
|
@@ -22720,7 +23180,7 @@ async function cloudSync(config2) {
|
|
|
22720
23180
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${config2.apiKey}` },
|
|
22721
23181
|
body: JSON.stringify({
|
|
22722
23182
|
device_id: deviceId,
|
|
22723
|
-
filename:
|
|
23183
|
+
filename: path39.basename(latestBackup),
|
|
22724
23184
|
blob: encrypted,
|
|
22725
23185
|
size: backupData.length
|
|
22726
23186
|
})
|
|
@@ -22748,56 +23208,56 @@ async function cloudSync(config2) {
|
|
|
22748
23208
|
function recordRosterDeletion(name) {
|
|
22749
23209
|
let deletions = [];
|
|
22750
23210
|
try {
|
|
22751
|
-
if (
|
|
22752
|
-
deletions = JSON.parse(
|
|
23211
|
+
if (existsSync34(ROSTER_DELETIONS_PATH)) {
|
|
23212
|
+
deletions = JSON.parse(readFileSync26(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
22753
23213
|
}
|
|
22754
23214
|
} catch {
|
|
22755
23215
|
}
|
|
22756
23216
|
if (!deletions.includes(name)) deletions.push(name);
|
|
22757
|
-
|
|
23217
|
+
writeFileSync18(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
|
|
22758
23218
|
}
|
|
22759
23219
|
function consumeRosterDeletions() {
|
|
22760
23220
|
try {
|
|
22761
|
-
if (!
|
|
22762
|
-
const deletions = JSON.parse(
|
|
22763
|
-
|
|
23221
|
+
if (!existsSync34(ROSTER_DELETIONS_PATH)) return [];
|
|
23222
|
+
const deletions = JSON.parse(readFileSync26(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
23223
|
+
writeFileSync18(ROSTER_DELETIONS_PATH, "[]");
|
|
22764
23224
|
return deletions;
|
|
22765
23225
|
} catch {
|
|
22766
23226
|
return [];
|
|
22767
23227
|
}
|
|
22768
23228
|
}
|
|
22769
23229
|
function buildRosterBlob(paths) {
|
|
22770
|
-
const rosterPath = paths?.rosterPath ??
|
|
22771
|
-
const identityDir = paths?.identityDir ??
|
|
22772
|
-
const configPath = paths?.configPath ??
|
|
23230
|
+
const rosterPath = paths?.rosterPath ?? path39.join(EXE_AI_DIR, "exe-employees.json");
|
|
23231
|
+
const identityDir = paths?.identityDir ?? path39.join(EXE_AI_DIR, "identity");
|
|
23232
|
+
const configPath = paths?.configPath ?? path39.join(EXE_AI_DIR, "config.json");
|
|
22773
23233
|
let roster = [];
|
|
22774
|
-
if (
|
|
23234
|
+
if (existsSync34(rosterPath)) {
|
|
22775
23235
|
try {
|
|
22776
|
-
roster = JSON.parse(
|
|
23236
|
+
roster = JSON.parse(readFileSync26(rosterPath, "utf-8"));
|
|
22777
23237
|
} catch {
|
|
22778
23238
|
}
|
|
22779
23239
|
}
|
|
22780
23240
|
const identities = {};
|
|
22781
|
-
if (
|
|
23241
|
+
if (existsSync34(identityDir)) {
|
|
22782
23242
|
for (const file of readdirSync11(identityDir).filter((f) => f.endsWith(".md"))) {
|
|
22783
23243
|
try {
|
|
22784
|
-
identities[file] =
|
|
23244
|
+
identities[file] = readFileSync26(path39.join(identityDir, file), "utf-8");
|
|
22785
23245
|
} catch {
|
|
22786
23246
|
}
|
|
22787
23247
|
}
|
|
22788
23248
|
}
|
|
22789
23249
|
let config2;
|
|
22790
|
-
if (
|
|
23250
|
+
if (existsSync34(configPath)) {
|
|
22791
23251
|
try {
|
|
22792
|
-
config2 = JSON.parse(
|
|
23252
|
+
config2 = JSON.parse(readFileSync26(configPath, "utf-8"));
|
|
22793
23253
|
} catch {
|
|
22794
23254
|
}
|
|
22795
23255
|
}
|
|
22796
23256
|
let agentConfig;
|
|
22797
|
-
const agentConfigPath =
|
|
22798
|
-
if (
|
|
23257
|
+
const agentConfigPath = path39.join(EXE_AI_DIR, "agent-config.json");
|
|
23258
|
+
if (existsSync34(agentConfigPath)) {
|
|
22799
23259
|
try {
|
|
22800
|
-
agentConfig = JSON.parse(
|
|
23260
|
+
agentConfig = JSON.parse(readFileSync26(agentConfigPath, "utf-8"));
|
|
22801
23261
|
} catch {
|
|
22802
23262
|
}
|
|
22803
23263
|
}
|
|
@@ -22873,24 +23333,24 @@ async function cloudPullRoster(config2) {
|
|
|
22873
23333
|
}
|
|
22874
23334
|
}
|
|
22875
23335
|
function mergeConfig(remoteConfig, configPath) {
|
|
22876
|
-
const cfgPath = configPath ??
|
|
23336
|
+
const cfgPath = configPath ?? path39.join(EXE_AI_DIR, "config.json");
|
|
22877
23337
|
let local = {};
|
|
22878
|
-
if (
|
|
23338
|
+
if (existsSync34(cfgPath)) {
|
|
22879
23339
|
try {
|
|
22880
|
-
local = JSON.parse(
|
|
23340
|
+
local = JSON.parse(readFileSync26(cfgPath, "utf-8"));
|
|
22881
23341
|
} catch {
|
|
22882
23342
|
}
|
|
22883
23343
|
}
|
|
22884
23344
|
const merged = { ...remoteConfig, ...local };
|
|
22885
|
-
const dir =
|
|
23345
|
+
const dir = path39.dirname(cfgPath);
|
|
22886
23346
|
ensurePrivateDirSync(dir);
|
|
22887
|
-
|
|
23347
|
+
writeFileSync18(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
22888
23348
|
enforcePrivateFileSync(cfgPath);
|
|
22889
23349
|
}
|
|
22890
23350
|
async function mergeRosterFromRemote(remote, paths) {
|
|
22891
23351
|
return withRosterLock(async () => {
|
|
22892
23352
|
const rosterPath = paths?.rosterPath ?? void 0;
|
|
22893
|
-
const identityDir = paths?.identityDir ??
|
|
23353
|
+
const identityDir = paths?.identityDir ?? path39.join(EXE_AI_DIR, "identity");
|
|
22894
23354
|
const localEmployees = await loadEmployees(rosterPath);
|
|
22895
23355
|
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
22896
23356
|
let added = 0;
|
|
@@ -22911,15 +23371,15 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
22911
23371
|
) ?? lookupKey;
|
|
22912
23372
|
const remoteIdentity = remote.identities[matchedKey];
|
|
22913
23373
|
if (remoteIdentity) {
|
|
22914
|
-
if (!
|
|
22915
|
-
const idPath =
|
|
23374
|
+
if (!existsSync34(identityDir)) mkdirSync15(identityDir, { recursive: true });
|
|
23375
|
+
const idPath = path39.join(identityDir, `${remoteEmp.name}.md`);
|
|
22916
23376
|
let localIdentity = null;
|
|
22917
23377
|
try {
|
|
22918
|
-
localIdentity =
|
|
23378
|
+
localIdentity = existsSync34(idPath) ? readFileSync26(idPath, "utf-8") : null;
|
|
22919
23379
|
} catch {
|
|
22920
23380
|
}
|
|
22921
23381
|
if (localIdentity !== remoteIdentity) {
|
|
22922
|
-
|
|
23382
|
+
writeFileSync18(idPath, remoteIdentity, "utf-8");
|
|
22923
23383
|
identitiesUpdated++;
|
|
22924
23384
|
}
|
|
22925
23385
|
}
|
|
@@ -22945,17 +23405,17 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
22945
23405
|
}
|
|
22946
23406
|
if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
|
|
22947
23407
|
try {
|
|
22948
|
-
const agentConfigPath =
|
|
23408
|
+
const agentConfigPath = path39.join(EXE_AI_DIR, "agent-config.json");
|
|
22949
23409
|
let local = {};
|
|
22950
|
-
if (
|
|
23410
|
+
if (existsSync34(agentConfigPath)) {
|
|
22951
23411
|
try {
|
|
22952
|
-
local = JSON.parse(
|
|
23412
|
+
local = JSON.parse(readFileSync26(agentConfigPath, "utf-8"));
|
|
22953
23413
|
} catch {
|
|
22954
23414
|
}
|
|
22955
23415
|
}
|
|
22956
23416
|
const merged = { ...remote.agentConfig, ...local };
|
|
22957
|
-
ensurePrivateDirSync(
|
|
22958
|
-
|
|
23417
|
+
ensurePrivateDirSync(path39.dirname(agentConfigPath));
|
|
23418
|
+
writeFileSync18(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
22959
23419
|
enforcePrivateFileSync(agentConfigPath);
|
|
22960
23420
|
} catch {
|
|
22961
23421
|
}
|
|
@@ -23380,7 +23840,7 @@ async function cloudPullDocuments(config2) {
|
|
|
23380
23840
|
}
|
|
23381
23841
|
return { pulled };
|
|
23382
23842
|
}
|
|
23383
|
-
var LOCALHOST_PATTERNS, FETCH_TIMEOUT_MS2, PUSH_BATCH_SIZE, ROSTER_LOCK_PATH, LOCK_STALE_MS, _pgPromise, _pgFailed, ROSTER_DELETIONS_PATH;
|
|
23843
|
+
var LOCALHOST_PATTERNS, FETCH_TIMEOUT_MS2, PUSH_BATCH_SIZE, ROSTER_LOCK_PATH, LOCK_STALE_MS, _pgPromise, _pgFailed, CLOUD_RELINK_REQUIRED_MESSAGE, ROSTER_DELETIONS_PATH;
|
|
23384
23844
|
var init_cloud_sync = __esm({
|
|
23385
23845
|
"src/lib/cloud-sync.ts"() {
|
|
23386
23846
|
"use strict";
|
|
@@ -23395,11 +23855,12 @@ var init_cloud_sync = __esm({
|
|
|
23395
23855
|
LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
23396
23856
|
FETCH_TIMEOUT_MS2 = 3e4;
|
|
23397
23857
|
PUSH_BATCH_SIZE = 5e3;
|
|
23398
|
-
ROSTER_LOCK_PATH =
|
|
23858
|
+
ROSTER_LOCK_PATH = path39.join(EXE_AI_DIR, "roster-merge.lock");
|
|
23399
23859
|
LOCK_STALE_MS = 3e4;
|
|
23400
23860
|
_pgPromise = null;
|
|
23401
23861
|
_pgFailed = false;
|
|
23402
|
-
|
|
23862
|
+
CLOUD_RELINK_REQUIRED_MESSAGE = "[cloud-sync] Paused after key rotation. Run `exe-os cloud relink --dry-run` for the safe relink checklist.";
|
|
23863
|
+
ROSTER_DELETIONS_PATH = path39.join(EXE_AI_DIR, "roster-deletions.json");
|
|
23403
23864
|
}
|
|
23404
23865
|
});
|
|
23405
23866
|
|
|
@@ -23470,6 +23931,143 @@ var init_cloud_sync2 = __esm({
|
|
|
23470
23931
|
}
|
|
23471
23932
|
});
|
|
23472
23933
|
|
|
23934
|
+
// src/lib/orchestration-phase.ts
|
|
23935
|
+
function normalizeOrchestrationPhase(input) {
|
|
23936
|
+
if (typeof input !== "string") return "phase_1_coo";
|
|
23937
|
+
const normalized = input.trim().toLowerCase().replace(/\s+/g, "_");
|
|
23938
|
+
if (["1", "phase1", "phase_1", "coo", "coo_mode", "chief_of_staff", "phase_1_coo"].includes(normalized)) {
|
|
23939
|
+
return "phase_1_coo";
|
|
23940
|
+
}
|
|
23941
|
+
if (["2", "phase2", "phase_2", "executives", "executive", "executive_bench", "phase_2_executives"].includes(normalized)) {
|
|
23942
|
+
return "phase_2_executives";
|
|
23943
|
+
}
|
|
23944
|
+
if (["3", "phase3", "phase_3", "parallel", "parallel_org", "parallel_execution", "phase_3_parallel_org"].includes(normalized)) {
|
|
23945
|
+
return "phase_3_parallel_org";
|
|
23946
|
+
}
|
|
23947
|
+
if (ORCHESTRATION_PHASES.includes(normalized)) return normalized;
|
|
23948
|
+
return "phase_1_coo";
|
|
23949
|
+
}
|
|
23950
|
+
function getOrchestrationPhaseInfo(phase) {
|
|
23951
|
+
return PHASE_INFO[normalizeOrchestrationPhase(phase)];
|
|
23952
|
+
}
|
|
23953
|
+
async function loadOrchestrationPhase() {
|
|
23954
|
+
const config2 = await loadConfig();
|
|
23955
|
+
return getOrchestrationPhaseInfo(config2.orchestration?.phase);
|
|
23956
|
+
}
|
|
23957
|
+
async function setOrchestrationPhase(phaseInput, setBy = "user") {
|
|
23958
|
+
const config2 = await loadConfig();
|
|
23959
|
+
const phase = normalizeOrchestrationPhase(phaseInput);
|
|
23960
|
+
config2.orchestration = {
|
|
23961
|
+
...config2.orchestration ?? {},
|
|
23962
|
+
phase,
|
|
23963
|
+
phaseSetAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
23964
|
+
phaseSetBy: setBy
|
|
23965
|
+
};
|
|
23966
|
+
await saveConfig(config2);
|
|
23967
|
+
return getOrchestrationPhaseInfo(phase);
|
|
23968
|
+
}
|
|
23969
|
+
var ORCHESTRATION_PHASES, PHASE_INFO;
|
|
23970
|
+
var init_orchestration_phase = __esm({
|
|
23971
|
+
"src/lib/orchestration-phase.ts"() {
|
|
23972
|
+
"use strict";
|
|
23973
|
+
init_config();
|
|
23974
|
+
ORCHESTRATION_PHASES = [
|
|
23975
|
+
"phase_1_coo",
|
|
23976
|
+
"phase_2_executives",
|
|
23977
|
+
"phase_3_parallel_org"
|
|
23978
|
+
];
|
|
23979
|
+
PHASE_INFO = {
|
|
23980
|
+
phase_1_coo: {
|
|
23981
|
+
phase: "phase_1_coo",
|
|
23982
|
+
shortLabel: "Phase 1 \u2014 COO mode",
|
|
23983
|
+
label: "Phase 1 \u2014 COO / Chief of Staff mode",
|
|
23984
|
+
focus: "building company context before delegation",
|
|
23985
|
+
nextSuggestion: "Unlock executives when technical, marketing, ops, legal, or finance work repeats."
|
|
23986
|
+
},
|
|
23987
|
+
phase_2_executives: {
|
|
23988
|
+
phase: "phase_2_executives",
|
|
23989
|
+
shortLabel: "Phase 2 \u2014 Executive bench",
|
|
23990
|
+
label: "Phase 2 \u2014 Executive bench",
|
|
23991
|
+
focus: "COO works with domain executives like CTO/CMO before specialist fan-out",
|
|
23992
|
+
nextSuggestion: "Unlock parallel execution when review gates, permissions, and workflows are ready."
|
|
23993
|
+
},
|
|
23994
|
+
phase_3_parallel_org: {
|
|
23995
|
+
phase: "phase_3_parallel_org",
|
|
23996
|
+
shortLabel: "Phase 3 \u2014 Parallel org",
|
|
23997
|
+
label: "Phase 3 \u2014 Parallel execution org",
|
|
23998
|
+
focus: "executives can delegate to specialists in parallel with review gates",
|
|
23999
|
+
nextSuggestion: "Keep review/CI/permission gates healthy; downgrade anytime if you want simpler COO-only mode."
|
|
24000
|
+
}
|
|
24001
|
+
};
|
|
24002
|
+
}
|
|
24003
|
+
});
|
|
24004
|
+
|
|
24005
|
+
// src/mcp/tools/orchestration-phase.ts
|
|
24006
|
+
import { z as z59 } from "zod";
|
|
24007
|
+
function render(info, prefix) {
|
|
24008
|
+
return [
|
|
24009
|
+
prefix,
|
|
24010
|
+
`## ${info.label}`,
|
|
24011
|
+
"",
|
|
24012
|
+
`- **Focus:** ${info.focus}`,
|
|
24013
|
+
`- **Suggestion:** ${info.nextSuggestion}`,
|
|
24014
|
+
"",
|
|
24015
|
+
"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."
|
|
24016
|
+
].filter(Boolean).join("\n");
|
|
24017
|
+
}
|
|
24018
|
+
function registerOrchestrationPhase(server) {
|
|
24019
|
+
server.registerTool(
|
|
24020
|
+
"orchestration_phase",
|
|
24021
|
+
{
|
|
24022
|
+
title: "Orchestration Phase",
|
|
24023
|
+
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.",
|
|
24024
|
+
inputSchema: {
|
|
24025
|
+
action: z59.enum(["status", "set", "unlock_executives", "unlock_parallel"]).default("status"),
|
|
24026
|
+
phase: z59.enum(["phase_1_coo", "phase_2_executives", "phase_3_parallel_org", "1", "2", "3"]).optional().describe("Phase to set when action='set'.")
|
|
24027
|
+
}
|
|
24028
|
+
},
|
|
24029
|
+
async ({ action = "status", phase }) => {
|
|
24030
|
+
try {
|
|
24031
|
+
if (action === "status") {
|
|
24032
|
+
const info2 = await loadOrchestrationPhase();
|
|
24033
|
+
return { content: [{ type: "text", text: render(info2) }] };
|
|
24034
|
+
}
|
|
24035
|
+
if (action === "unlock_executives") {
|
|
24036
|
+
const info2 = await setOrchestrationPhase("phase_2_executives", "mcp");
|
|
24037
|
+
return {
|
|
24038
|
+
content: [{ type: "text", text: render(info2, "Phase 2 enabled. Your COO can now lean on the executive bench when useful.") }]
|
|
24039
|
+
};
|
|
24040
|
+
}
|
|
24041
|
+
if (action === "unlock_parallel") {
|
|
24042
|
+
const info2 = await setOrchestrationPhase("phase_3_parallel_org", "mcp");
|
|
24043
|
+
return {
|
|
24044
|
+
content: [{ type: "text", text: render(info2, "Phase 3 enabled. Parallel execution is available with review/permission gates.") }]
|
|
24045
|
+
};
|
|
24046
|
+
}
|
|
24047
|
+
if (!phase) {
|
|
24048
|
+
return {
|
|
24049
|
+
content: [{ type: "text", text: "action='set' requires phase: 1, 2, 3, phase_1_coo, phase_2_executives, or phase_3_parallel_org." }],
|
|
24050
|
+
isError: true
|
|
24051
|
+
};
|
|
24052
|
+
}
|
|
24053
|
+
const info = await setOrchestrationPhase(phase, "mcp");
|
|
24054
|
+
return { content: [{ type: "text", text: render(info, "Updated orchestration phase.") }] };
|
|
24055
|
+
} catch (err) {
|
|
24056
|
+
return {
|
|
24057
|
+
content: [{ type: "text", text: `Failed to update orchestration phase: ${err instanceof Error ? err.message : String(err)}` }],
|
|
24058
|
+
isError: true
|
|
24059
|
+
};
|
|
24060
|
+
}
|
|
24061
|
+
}
|
|
24062
|
+
);
|
|
24063
|
+
}
|
|
24064
|
+
var init_orchestration_phase2 = __esm({
|
|
24065
|
+
"src/mcp/tools/orchestration-phase.ts"() {
|
|
24066
|
+
"use strict";
|
|
24067
|
+
init_orchestration_phase();
|
|
24068
|
+
}
|
|
24069
|
+
});
|
|
24070
|
+
|
|
23473
24071
|
// src/lib/vps-backup.ts
|
|
23474
24072
|
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
23475
24073
|
import { Readable } from "stream";
|
|
@@ -23793,50 +24391,50 @@ var init_vps_backup = __esm({
|
|
|
23793
24391
|
});
|
|
23794
24392
|
|
|
23795
24393
|
// src/mcp/tools/backup-vps.ts
|
|
23796
|
-
import { z as
|
|
24394
|
+
import { z as z60 } from "zod";
|
|
23797
24395
|
function registerBackupVps(server) {
|
|
23798
24396
|
server.registerTool(
|
|
23799
24397
|
"backup_vps",
|
|
23800
24398
|
{
|
|
23801
24399
|
title: "VPS Backup",
|
|
23802
24400
|
description: "Run VPS Postgres backup/restore workflows and check status.",
|
|
23803
|
-
inputSchema:
|
|
23804
|
-
|
|
23805
|
-
action:
|
|
23806
|
-
databaseUrl:
|
|
23807
|
-
encryptionKeyB64:
|
|
24401
|
+
inputSchema: z60.discriminatedUnion("action", [
|
|
24402
|
+
z60.object({
|
|
24403
|
+
action: z60.literal("backup"),
|
|
24404
|
+
databaseUrl: z60.string().min(1).describe("Postgres DATABASE_URL to dump from"),
|
|
24405
|
+
encryptionKeyB64: z60.string().min(1).max(4096).optional().describe(
|
|
23808
24406
|
"Base64 AES-256 key (defaults to local master key if omitted)"
|
|
23809
24407
|
),
|
|
23810
|
-
r2Bucket:
|
|
23811
|
-
r2Endpoint:
|
|
23812
|
-
r2AccessKeyId:
|
|
23813
|
-
r2SecretAccessKey:
|
|
24408
|
+
r2Bucket: z60.string().min(1).describe("R2 bucket name"),
|
|
24409
|
+
r2Endpoint: z60.string().min(1).describe("R2 endpoint URL"),
|
|
24410
|
+
r2AccessKeyId: z60.string().min(1).describe("R2 access key ID"),
|
|
24411
|
+
r2SecretAccessKey: z60.string().min(1).describe("R2 secret access key")
|
|
23814
24412
|
}),
|
|
23815
|
-
|
|
23816
|
-
action:
|
|
23817
|
-
databaseUrl:
|
|
23818
|
-
backupKey:
|
|
23819
|
-
encryptionKeyB64:
|
|
24413
|
+
z60.object({
|
|
24414
|
+
action: z60.literal("restore"),
|
|
24415
|
+
databaseUrl: z60.string().min(1).describe("Target Postgres DATABASE_URL for restore"),
|
|
24416
|
+
backupKey: z60.string().min(1).describe("R2 object key to restore from"),
|
|
24417
|
+
encryptionKeyB64: z60.string().min(1).max(4096).optional().describe(
|
|
23820
24418
|
"Base64 AES-256 key (defaults to local master key if omitted)"
|
|
23821
24419
|
),
|
|
23822
|
-
r2Bucket:
|
|
23823
|
-
r2Endpoint:
|
|
23824
|
-
r2AccessKeyId:
|
|
23825
|
-
r2SecretAccessKey:
|
|
24420
|
+
r2Bucket: z60.string().min(1).describe("R2 bucket name"),
|
|
24421
|
+
r2Endpoint: z60.string().min(1).describe("R2 endpoint URL"),
|
|
24422
|
+
r2AccessKeyId: z60.string().min(1).describe("R2 access key ID"),
|
|
24423
|
+
r2SecretAccessKey: z60.string().min(1).describe("R2 secret access key")
|
|
23826
24424
|
}),
|
|
23827
|
-
|
|
23828
|
-
action:
|
|
23829
|
-
r2Bucket:
|
|
23830
|
-
r2Endpoint:
|
|
23831
|
-
r2AccessKeyId:
|
|
23832
|
-
r2SecretAccessKey:
|
|
24425
|
+
z60.object({
|
|
24426
|
+
action: z60.literal("list"),
|
|
24427
|
+
r2Bucket: z60.string().min(1).describe("R2 bucket name"),
|
|
24428
|
+
r2Endpoint: z60.string().min(1).describe("R2 endpoint URL"),
|
|
24429
|
+
r2AccessKeyId: z60.string().min(1).describe("R2 access key ID"),
|
|
24430
|
+
r2SecretAccessKey: z60.string().min(1).describe("R2 secret access key")
|
|
23833
24431
|
}),
|
|
23834
|
-
|
|
23835
|
-
action:
|
|
23836
|
-
r2Bucket:
|
|
23837
|
-
r2Endpoint:
|
|
23838
|
-
r2AccessKeyId:
|
|
23839
|
-
r2SecretAccessKey:
|
|
24432
|
+
z60.object({
|
|
24433
|
+
action: z60.literal("health"),
|
|
24434
|
+
r2Bucket: z60.string().min(1).describe("R2 bucket name"),
|
|
24435
|
+
r2Endpoint: z60.string().min(1).describe("R2 endpoint URL"),
|
|
24436
|
+
r2AccessKeyId: z60.string().min(1).describe("R2 access key ID"),
|
|
24437
|
+
r2SecretAccessKey: z60.string().min(1).describe("R2 secret access key")
|
|
23840
24438
|
})
|
|
23841
24439
|
])
|
|
23842
24440
|
},
|
|
@@ -24030,9 +24628,9 @@ var init_hostinger_api = __esm({
|
|
|
24030
24628
|
}
|
|
24031
24629
|
this.lastRequestTime = Date.now();
|
|
24032
24630
|
}
|
|
24033
|
-
async request(method,
|
|
24631
|
+
async request(method, path56, body) {
|
|
24034
24632
|
await this.rateLimit();
|
|
24035
|
-
const url = `${this.baseUrl}${
|
|
24633
|
+
const url = `${this.baseUrl}${path56}`;
|
|
24036
24634
|
const headers = {
|
|
24037
24635
|
Authorization: `Bearer ${this.apiKey}`,
|
|
24038
24636
|
"Content-Type": "application/json",
|
|
@@ -24101,8 +24699,8 @@ async function requestCloudflare(cfApiToken, zoneId, options) {
|
|
|
24101
24699
|
}
|
|
24102
24700
|
return envelope.result;
|
|
24103
24701
|
}
|
|
24104
|
-
function buildUrl(zoneId,
|
|
24105
|
-
const normalizedPath =
|
|
24702
|
+
function buildUrl(zoneId, path56 = "/dns_records", query) {
|
|
24703
|
+
const normalizedPath = path56.startsWith("/") ? path56 : `/${path56}`;
|
|
24106
24704
|
const url = new URL(
|
|
24107
24705
|
`${CLOUDFLARE_API_BASE_URL}/zones/${zoneId}${normalizedPath}`
|
|
24108
24706
|
);
|
|
@@ -24173,11 +24771,11 @@ var init_cloudflare_dns = __esm({
|
|
|
24173
24771
|
});
|
|
24174
24772
|
|
|
24175
24773
|
// src/mcp/tools/deploy-client.ts
|
|
24176
|
-
import { z as
|
|
24774
|
+
import { z as z61 } from "zod";
|
|
24177
24775
|
import { execFile } from "child_process";
|
|
24178
24776
|
import { promisify } from "util";
|
|
24179
|
-
import
|
|
24180
|
-
import { existsSync as
|
|
24777
|
+
import path40 from "path";
|
|
24778
|
+
import { existsSync as existsSync35 } from "fs";
|
|
24181
24779
|
async function executeDeployment(params, client) {
|
|
24182
24780
|
const {
|
|
24183
24781
|
client_name,
|
|
@@ -24249,12 +24847,12 @@ function registerDeployClient(server) {
|
|
|
24249
24847
|
title: "Deploy Client",
|
|
24250
24848
|
description: "Provision a Hostinger VPS and deploy exe-os for a client. Creates VPS, waits for ready state, runs Ansible playbook, verifies health.",
|
|
24251
24849
|
inputSchema: {
|
|
24252
|
-
client_name:
|
|
24253
|
-
domain:
|
|
24254
|
-
region:
|
|
24255
|
-
plan:
|
|
24256
|
-
ssl_email:
|
|
24257
|
-
user_id:
|
|
24850
|
+
client_name: z61.string().min(1).describe("Client name (used for hostname and identification)"),
|
|
24851
|
+
domain: z61.string().min(1).describe("Domain name for the deployment (e.g., client.exe.ai)"),
|
|
24852
|
+
region: z61.string().default("jakarta").describe("VPS region (default: jakarta)"),
|
|
24853
|
+
plan: z61.string().default("kvm-2").describe("Hostinger VPS plan (default: kvm-2)"),
|
|
24854
|
+
ssl_email: z61.string().email().describe("Email for Let's Encrypt SSL certificate"),
|
|
24855
|
+
user_id: z61.string().min(1).describe("User/customer ID for inventory tracking")
|
|
24258
24856
|
}
|
|
24259
24857
|
},
|
|
24260
24858
|
async ({ client_name, domain, region, plan, ssl_email, user_id }) => {
|
|
@@ -24322,12 +24920,12 @@ async function waitForReady(client, vpsId) {
|
|
|
24322
24920
|
}
|
|
24323
24921
|
async function runAnsiblePlaybook(vpsIp, domain, sslEmail, clientName) {
|
|
24324
24922
|
const safeClientName = clientName.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
24325
|
-
const playbookDir =
|
|
24326
|
-
const playbookPath =
|
|
24327
|
-
const inventoryPath =
|
|
24328
|
-
const clientVarsPath =
|
|
24329
|
-
const varsDir =
|
|
24330
|
-
if (!
|
|
24923
|
+
const playbookDir = path40.resolve(process.cwd(), "infrastructure", "ansible");
|
|
24924
|
+
const playbookPath = path40.join(playbookDir, "deploy.yml");
|
|
24925
|
+
const inventoryPath = path40.join(playbookDir, "inventory", "hosts.yml");
|
|
24926
|
+
const clientVarsPath = path40.join(playbookDir, "vars", `${safeClientName}.yml`);
|
|
24927
|
+
const varsDir = path40.join(playbookDir, "vars");
|
|
24928
|
+
if (!path40.resolve(clientVarsPath).startsWith(path40.resolve(varsDir))) {
|
|
24331
24929
|
throw new Error(`Invalid client name for vars path: ${clientName}`);
|
|
24332
24930
|
}
|
|
24333
24931
|
const args = [
|
|
@@ -24343,7 +24941,7 @@ async function runAnsiblePlaybook(vpsIp, domain, sslEmail, clientName) {
|
|
|
24343
24941
|
"-e",
|
|
24344
24942
|
`client_name=${safeClientName}`
|
|
24345
24943
|
];
|
|
24346
|
-
if (
|
|
24944
|
+
if (existsSync35(clientVarsPath)) {
|
|
24347
24945
|
args.push("-e", `@${clientVarsPath}`);
|
|
24348
24946
|
}
|
|
24349
24947
|
try {
|
|
@@ -24433,7 +25031,7 @@ var init_deploy_client = __esm({
|
|
|
24433
25031
|
});
|
|
24434
25032
|
|
|
24435
25033
|
// src/mcp/tools/get-license-status.ts
|
|
24436
|
-
import { z as
|
|
25034
|
+
import { z as z62 } from "zod";
|
|
24437
25035
|
function registerGetLicenseStatus(server) {
|
|
24438
25036
|
server.registerTool(
|
|
24439
25037
|
"get_license_status",
|
|
@@ -24441,7 +25039,7 @@ function registerGetLicenseStatus(server) {
|
|
|
24441
25039
|
title: "Get License Status",
|
|
24442
25040
|
description: "Get current license status: plan, validity, feature gates, limits, and expiry.",
|
|
24443
25041
|
inputSchema: {
|
|
24444
|
-
_dummy:
|
|
25042
|
+
_dummy: z62.string().optional().describe("Unused \u2014 no input required")
|
|
24445
25043
|
}
|
|
24446
25044
|
},
|
|
24447
25045
|
async () => {
|
|
@@ -24507,11 +25105,11 @@ var init_get_license_status = __esm({
|
|
|
24507
25105
|
|
|
24508
25106
|
// src/mcp/tools/create-license.ts
|
|
24509
25107
|
import os17 from "os";
|
|
24510
|
-
import
|
|
25108
|
+
import path41 from "path";
|
|
24511
25109
|
import { randomBytes as randomBytes2, randomUUID as randomUUID6 } from "crypto";
|
|
24512
25110
|
import { createRequire as createRequire4 } from "module";
|
|
24513
25111
|
import { pathToFileURL as pathToFileURL4 } from "url";
|
|
24514
|
-
import { z as
|
|
25112
|
+
import { z as z63 } from "zod";
|
|
24515
25113
|
function loadPrisma2() {
|
|
24516
25114
|
if (!prismaPromise2) {
|
|
24517
25115
|
prismaPromise2 = (async () => {
|
|
@@ -24522,8 +25120,8 @@ function loadPrisma2() {
|
|
|
24522
25120
|
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
24523
25121
|
return new Ctor2();
|
|
24524
25122
|
}
|
|
24525
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
24526
|
-
const req = createRequire4(
|
|
25123
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path41.join(os17.homedir(), "exe-db");
|
|
25124
|
+
const req = createRequire4(path41.join(exeDbRoot, "package.json"));
|
|
24527
25125
|
const entry = req.resolve("@prisma/client");
|
|
24528
25126
|
const mod = await import(pathToFileURL4(entry).href);
|
|
24529
25127
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -24543,10 +25141,10 @@ function registerCreateLicense(server) {
|
|
|
24543
25141
|
title: "Create License",
|
|
24544
25142
|
description: "Generate an exe_sk_* license key for a user. Stores in billing.licenses. Returns the key to give to the customer.",
|
|
24545
25143
|
inputSchema: {
|
|
24546
|
-
email:
|
|
24547
|
-
name:
|
|
24548
|
-
plan:
|
|
24549
|
-
expires_in_days:
|
|
25144
|
+
email: z63.string().email().describe("Customer email address"),
|
|
25145
|
+
name: z63.string().optional().describe("Customer name"),
|
|
25146
|
+
plan: z63.enum(["free", "pro", "team", "agency", "enterprise"]).default("pro").describe("License plan tier"),
|
|
25147
|
+
expires_in_days: z63.number().int().positive().default(365).describe("Days until expiration (default 365)")
|
|
24550
25148
|
}
|
|
24551
25149
|
},
|
|
24552
25150
|
async ({ email, name, plan, expires_in_days }) => {
|
|
@@ -24606,10 +25204,10 @@ var init_create_license = __esm({
|
|
|
24606
25204
|
|
|
24607
25205
|
// src/mcp/tools/list-licenses.ts
|
|
24608
25206
|
import os18 from "os";
|
|
24609
|
-
import
|
|
25207
|
+
import path42 from "path";
|
|
24610
25208
|
import { createRequire as createRequire5 } from "module";
|
|
24611
25209
|
import { pathToFileURL as pathToFileURL5 } from "url";
|
|
24612
|
-
import { z as
|
|
25210
|
+
import { z as z64 } from "zod";
|
|
24613
25211
|
function loadPrisma3() {
|
|
24614
25212
|
if (!prismaPromise3) {
|
|
24615
25213
|
prismaPromise3 = (async () => {
|
|
@@ -24620,8 +25218,8 @@ function loadPrisma3() {
|
|
|
24620
25218
|
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
24621
25219
|
return new Ctor2();
|
|
24622
25220
|
}
|
|
24623
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
24624
|
-
const req = createRequire5(
|
|
25221
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path42.join(os18.homedir(), "exe-db");
|
|
25222
|
+
const req = createRequire5(path42.join(exeDbRoot, "package.json"));
|
|
24625
25223
|
const entry = req.resolve("@prisma/client");
|
|
24626
25224
|
const mod = await import(pathToFileURL5(entry).href);
|
|
24627
25225
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -24638,7 +25236,7 @@ function registerListLicenses(server) {
|
|
|
24638
25236
|
title: "List Licenses",
|
|
24639
25237
|
description: "List all issued licenses with status (active/expired/revoked). Optionally filter by plan.",
|
|
24640
25238
|
inputSchema: {
|
|
24641
|
-
plan:
|
|
25239
|
+
plan: z64.enum(["free", "pro", "team", "agency", "enterprise"]).optional().describe("Filter by plan tier (omit for all)")
|
|
24642
25240
|
}
|
|
24643
25241
|
},
|
|
24644
25242
|
async ({ plan }) => {
|
|
@@ -24695,7 +25293,7 @@ var init_list_licenses = __esm({
|
|
|
24695
25293
|
});
|
|
24696
25294
|
|
|
24697
25295
|
// src/mcp/tools/activate-license.ts
|
|
24698
|
-
import { z as
|
|
25296
|
+
import { z as z65 } from "zod";
|
|
24699
25297
|
function registerActivateLicense(server) {
|
|
24700
25298
|
server.registerTool(
|
|
24701
25299
|
"activate_license",
|
|
@@ -24703,7 +25301,7 @@ function registerActivateLicense(server) {
|
|
|
24703
25301
|
title: "Activate License",
|
|
24704
25302
|
description: "Activate an exe_sk_* license key on this device. Writes to ~/.exe-os/license.key, validates against Postgres, and caches the result.",
|
|
24705
25303
|
inputSchema: {
|
|
24706
|
-
key:
|
|
25304
|
+
key: z65.string().startsWith("exe_sk_").describe("License key (exe_sk_*)")
|
|
24707
25305
|
}
|
|
24708
25306
|
},
|
|
24709
25307
|
async ({ key }) => {
|
|
@@ -24755,14 +25353,14 @@ var init_activate_license = __esm({
|
|
|
24755
25353
|
});
|
|
24756
25354
|
|
|
24757
25355
|
// src/automation/trigger-engine.ts
|
|
24758
|
-
import { readFileSync as
|
|
25356
|
+
import { readFileSync as readFileSync27, writeFileSync as writeFileSync19, existsSync as existsSync36, mkdirSync as mkdirSync16 } from "fs";
|
|
24759
25357
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
24760
|
-
import
|
|
25358
|
+
import path43 from "path";
|
|
24761
25359
|
import os19 from "os";
|
|
24762
25360
|
function loadTriggers(project) {
|
|
24763
|
-
if (!
|
|
25361
|
+
if (!existsSync36(TRIGGERS_PATH)) return [];
|
|
24764
25362
|
try {
|
|
24765
|
-
const raw =
|
|
25363
|
+
const raw = readFileSync27(TRIGGERS_PATH, "utf-8");
|
|
24766
25364
|
const all = JSON.parse(raw);
|
|
24767
25365
|
if (!Array.isArray(all)) return [];
|
|
24768
25366
|
if (project) {
|
|
@@ -24774,9 +25372,9 @@ function loadTriggers(project) {
|
|
|
24774
25372
|
}
|
|
24775
25373
|
}
|
|
24776
25374
|
function saveTriggers(triggers) {
|
|
24777
|
-
const dir =
|
|
24778
|
-
if (!
|
|
24779
|
-
|
|
25375
|
+
const dir = path43.dirname(TRIGGERS_PATH);
|
|
25376
|
+
if (!existsSync36(dir)) mkdirSync16(dir, { recursive: true });
|
|
25377
|
+
writeFileSync19(TRIGGERS_PATH, JSON.stringify(triggers, null, 2), "utf-8");
|
|
24780
25378
|
}
|
|
24781
25379
|
function createNewTrigger(input) {
|
|
24782
25380
|
const triggers = loadTriggers();
|
|
@@ -24795,7 +25393,7 @@ var TRIGGERS_PATH;
|
|
|
24795
25393
|
var init_trigger_engine = __esm({
|
|
24796
25394
|
"src/automation/trigger-engine.ts"() {
|
|
24797
25395
|
"use strict";
|
|
24798
|
-
TRIGGERS_PATH =
|
|
25396
|
+
TRIGGERS_PATH = path43.join(os19.homedir(), ".exe-os", "triggers.json");
|
|
24799
25397
|
}
|
|
24800
25398
|
});
|
|
24801
25399
|
|
|
@@ -24945,7 +25543,7 @@ var init_schedules = __esm({
|
|
|
24945
25543
|
});
|
|
24946
25544
|
|
|
24947
25545
|
// src/mcp/tools/create-trigger.ts
|
|
24948
|
-
import { z as
|
|
25546
|
+
import { z as z66 } from "zod";
|
|
24949
25547
|
function registerCreateTrigger(server) {
|
|
24950
25548
|
server.registerTool(
|
|
24951
25549
|
"create_trigger",
|
|
@@ -24953,18 +25551,18 @@ function registerCreateTrigger(server) {
|
|
|
24953
25551
|
title: "Create Trigger",
|
|
24954
25552
|
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.).",
|
|
24955
25553
|
inputSchema: {
|
|
24956
|
-
name:
|
|
24957
|
-
event:
|
|
25554
|
+
name: z66.string().describe("Human-readable trigger name"),
|
|
25555
|
+
event: z66.string().describe(
|
|
24958
25556
|
'CRM event to match, e.g., "Deal.updated", "Order.created", "*" for all'
|
|
24959
25557
|
),
|
|
24960
|
-
conditions:
|
|
24961
|
-
actions:
|
|
24962
|
-
project:
|
|
24963
|
-
enabled:
|
|
24964
|
-
schedule:
|
|
25558
|
+
conditions: z66.array(conditionSchema).default([]).describe("Conditions that must all match (AND logic)"),
|
|
25559
|
+
actions: z66.array(actionSchema).min(1).describe("Actions to execute when trigger fires"),
|
|
25560
|
+
project: z66.string().optional().describe("Scope trigger to a specific project"),
|
|
25561
|
+
enabled: z66.boolean().default(true).describe("Whether trigger is active"),
|
|
25562
|
+
schedule: z66.string().optional().describe(
|
|
24965
25563
|
'Cron schedule for time-based triggers, e.g., "0 9 * * *" or "Monday 9am"'
|
|
24966
25564
|
),
|
|
24967
|
-
query:
|
|
25565
|
+
query: z66.string().optional().describe(
|
|
24968
25566
|
"CRM GraphQL query to run on schedule (required if schedule is set)"
|
|
24969
25567
|
)
|
|
24970
25568
|
}
|
|
@@ -25041,14 +25639,14 @@ var init_create_trigger = __esm({
|
|
|
25041
25639
|
"use strict";
|
|
25042
25640
|
init_trigger_engine();
|
|
25043
25641
|
init_schedules();
|
|
25044
|
-
conditionSchema =
|
|
25045
|
-
field:
|
|
25046
|
-
op:
|
|
25047
|
-
value:
|
|
25642
|
+
conditionSchema = z66.object({
|
|
25643
|
+
field: z66.string().describe("Dot-path field to evaluate, e.g., 'stage' or 'amount'"),
|
|
25644
|
+
op: z66.enum(["eq", "neq", "gt", "lt", "gte", "lte", "contains", "not_contains"]).describe("Comparison operator"),
|
|
25645
|
+
value: z66.string().or(z66.number()).or(z66.boolean()).describe("Value to compare against")
|
|
25048
25646
|
});
|
|
25049
|
-
actionSchema =
|
|
25050
|
-
type:
|
|
25051
|
-
params:
|
|
25647
|
+
actionSchema = z66.object({
|
|
25648
|
+
type: z66.enum(["send_whatsapp", "send_message", "create_task", "mcp_tool"]).describe("Action type to execute"),
|
|
25649
|
+
params: z66.record(z66.string(), z66.string()).describe(
|
|
25052
25650
|
"Action parameters. Supports {{record.field}} templates for dynamic values."
|
|
25053
25651
|
)
|
|
25054
25652
|
});
|
|
@@ -25056,7 +25654,7 @@ var init_create_trigger = __esm({
|
|
|
25056
25654
|
});
|
|
25057
25655
|
|
|
25058
25656
|
// src/mcp/tools/list-triggers.ts
|
|
25059
|
-
import { z as
|
|
25657
|
+
import { z as z67 } from "zod";
|
|
25060
25658
|
function registerListTriggers(server) {
|
|
25061
25659
|
server.registerTool(
|
|
25062
25660
|
"list_triggers",
|
|
@@ -25064,7 +25662,7 @@ function registerListTriggers(server) {
|
|
|
25064
25662
|
title: "List Triggers",
|
|
25065
25663
|
description: "List configured CRM event triggers and scheduled automations.",
|
|
25066
25664
|
inputSchema: {
|
|
25067
|
-
project:
|
|
25665
|
+
project: z67.string().optional().describe("Filter triggers by project name")
|
|
25068
25666
|
}
|
|
25069
25667
|
},
|
|
25070
25668
|
async ({ project }) => {
|
|
@@ -25105,47 +25703,47 @@ var init_list_triggers = __esm({
|
|
|
25105
25703
|
});
|
|
25106
25704
|
|
|
25107
25705
|
// src/automation/starter-packs/index.ts
|
|
25108
|
-
import { readFileSync as
|
|
25109
|
-
import
|
|
25706
|
+
import { readFileSync as readFileSync28, readdirSync as readdirSync12, existsSync as existsSync37 } from "fs";
|
|
25707
|
+
import path44 from "path";
|
|
25110
25708
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
25111
25709
|
function listPacks() {
|
|
25112
|
-
const packsDir =
|
|
25113
|
-
if (!
|
|
25710
|
+
const packsDir = path44.join(__dirname, ".");
|
|
25711
|
+
if (!existsSync37(packsDir)) return [];
|
|
25114
25712
|
return readdirSync12(packsDir, { withFileTypes: true }).filter(
|
|
25115
|
-
(d) => d.isDirectory() &&
|
|
25713
|
+
(d) => d.isDirectory() && existsSync37(path44.join(packsDir, d.name, "custom-objects.json"))
|
|
25116
25714
|
).map((d) => d.name);
|
|
25117
25715
|
}
|
|
25118
25716
|
function loadPack(industry) {
|
|
25119
|
-
const packDir =
|
|
25120
|
-
const objectsPath =
|
|
25121
|
-
const triggersPath =
|
|
25122
|
-
const wikiDir =
|
|
25123
|
-
const manifestPath =
|
|
25124
|
-
const identityContextPath =
|
|
25125
|
-
if (!
|
|
25717
|
+
const packDir = path44.join(__dirname, industry);
|
|
25718
|
+
const objectsPath = path44.join(packDir, "custom-objects.json");
|
|
25719
|
+
const triggersPath = path44.join(packDir, "triggers.json");
|
|
25720
|
+
const wikiDir = path44.join(packDir, "wiki-seeds");
|
|
25721
|
+
const manifestPath = path44.join(packDir, "pack.json");
|
|
25722
|
+
const identityContextPath = path44.join(packDir, "identity-context.md");
|
|
25723
|
+
if (!existsSync37(objectsPath)) return null;
|
|
25126
25724
|
let customObjects = [];
|
|
25127
25725
|
try {
|
|
25128
25726
|
customObjects = JSON.parse(
|
|
25129
|
-
|
|
25727
|
+
readFileSync28(objectsPath, "utf-8")
|
|
25130
25728
|
);
|
|
25131
25729
|
} catch {
|
|
25132
25730
|
customObjects = [];
|
|
25133
25731
|
}
|
|
25134
25732
|
let triggers = [];
|
|
25135
|
-
if (
|
|
25733
|
+
if (existsSync37(triggersPath)) {
|
|
25136
25734
|
try {
|
|
25137
25735
|
triggers = JSON.parse(
|
|
25138
|
-
|
|
25736
|
+
readFileSync28(triggersPath, "utf-8")
|
|
25139
25737
|
);
|
|
25140
25738
|
} catch {
|
|
25141
25739
|
triggers = [];
|
|
25142
25740
|
}
|
|
25143
25741
|
}
|
|
25144
25742
|
const wikiSeeds = [];
|
|
25145
|
-
if (
|
|
25743
|
+
if (existsSync37(wikiDir)) {
|
|
25146
25744
|
const files = readdirSync12(wikiDir).filter((f) => f.endsWith(".md"));
|
|
25147
25745
|
for (const file of files) {
|
|
25148
|
-
const content =
|
|
25746
|
+
const content = readFileSync28(path44.join(wikiDir, file), "utf-8");
|
|
25149
25747
|
const titleMatch = content.match(/^#\s+(.+)/m);
|
|
25150
25748
|
wikiSeeds.push({
|
|
25151
25749
|
filename: file,
|
|
@@ -25155,17 +25753,17 @@ function loadPack(industry) {
|
|
|
25155
25753
|
}
|
|
25156
25754
|
}
|
|
25157
25755
|
let manifest = {};
|
|
25158
|
-
if (
|
|
25756
|
+
if (existsSync37(manifestPath)) {
|
|
25159
25757
|
try {
|
|
25160
|
-
manifest = JSON.parse(
|
|
25758
|
+
manifest = JSON.parse(readFileSync28(manifestPath, "utf-8"));
|
|
25161
25759
|
} catch {
|
|
25162
25760
|
manifest = {};
|
|
25163
25761
|
}
|
|
25164
25762
|
}
|
|
25165
25763
|
let identityContext = null;
|
|
25166
|
-
if (
|
|
25764
|
+
if (existsSync37(identityContextPath)) {
|
|
25167
25765
|
try {
|
|
25168
|
-
identityContext =
|
|
25766
|
+
identityContext = readFileSync28(identityContextPath, "utf-8");
|
|
25169
25767
|
} catch {
|
|
25170
25768
|
identityContext = null;
|
|
25171
25769
|
}
|
|
@@ -25224,7 +25822,7 @@ var init_starter_packs = __esm({
|
|
|
25224
25822
|
"src/automation/starter-packs/index.ts"() {
|
|
25225
25823
|
"use strict";
|
|
25226
25824
|
init_trigger_engine();
|
|
25227
|
-
__dirname =
|
|
25825
|
+
__dirname = path44.dirname(fileURLToPath4(import.meta.url));
|
|
25228
25826
|
}
|
|
25229
25827
|
});
|
|
25230
25828
|
|
|
@@ -25356,21 +25954,21 @@ All memory, tasks, behaviors, documents, and wiki content belonging to {{company
|
|
|
25356
25954
|
});
|
|
25357
25955
|
|
|
25358
25956
|
// src/lib/client-coo.ts
|
|
25359
|
-
import { existsSync as
|
|
25360
|
-
import
|
|
25957
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync17, writeFileSync as writeFileSync20 } from "fs";
|
|
25958
|
+
import path45 from "path";
|
|
25361
25959
|
async function provisionClientCOO(vars, opts = {}) {
|
|
25362
|
-
const identityDir = opts.identityDir ??
|
|
25960
|
+
const identityDir = opts.identityDir ?? path45.join(EXE_AI_DIR, "identity");
|
|
25363
25961
|
const rosterPath = opts.employeesPath ?? EMPLOYEES_PATH;
|
|
25364
25962
|
const storeFeedbackBehavior = opts.storeFeedbackBehavior ?? true;
|
|
25365
|
-
const identityPath2 =
|
|
25366
|
-
if (
|
|
25963
|
+
const identityPath2 = path45.join(identityDir, `${vars.agent_name}.md`);
|
|
25964
|
+
if (existsSync38(identityPath2)) {
|
|
25367
25965
|
throw new ClientCOOClobberError(vars.agent_name, identityPath2);
|
|
25368
25966
|
}
|
|
25369
25967
|
const body = renderClientCOOTemplate(vars);
|
|
25370
|
-
if (!
|
|
25371
|
-
|
|
25968
|
+
if (!existsSync38(identityDir)) {
|
|
25969
|
+
mkdirSync17(identityDir, { recursive: true });
|
|
25372
25970
|
}
|
|
25373
|
-
|
|
25971
|
+
writeFileSync20(identityPath2, body, "utf-8");
|
|
25374
25972
|
const employees = await loadEmployees(rosterPath);
|
|
25375
25973
|
const existing = employees.find((e) => e.name === vars.agent_name);
|
|
25376
25974
|
let addedToRoster = false;
|
|
@@ -25422,7 +26020,7 @@ var init_client_coo = __esm({
|
|
|
25422
26020
|
});
|
|
25423
26021
|
|
|
25424
26022
|
// src/mcp/tools/apply-starter-pack.ts
|
|
25425
|
-
import { z as
|
|
26023
|
+
import { z as z68 } from "zod";
|
|
25426
26024
|
function registerApplyStarterPack(server) {
|
|
25427
26025
|
server.registerTool(
|
|
25428
26026
|
"apply_starter_pack",
|
|
@@ -25430,17 +26028,17 @@ function registerApplyStarterPack(server) {
|
|
|
25430
26028
|
title: "Apply Starter Pack",
|
|
25431
26029
|
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.",
|
|
25432
26030
|
inputSchema: {
|
|
25433
|
-
industry:
|
|
26031
|
+
industry: z68.string().describe(
|
|
25434
26032
|
'Industry pack to apply (e.g., "distribution"). Use without args to list available packs.'
|
|
25435
26033
|
),
|
|
25436
|
-
project:
|
|
25437
|
-
agent_name:
|
|
26034
|
+
project: z68.string().describe("Project name to scope the triggers to"),
|
|
26035
|
+
agent_name: z68.string().optional().describe(
|
|
25438
26036
|
"Optional. Lowercase alphanumeric name for the Client COO agent. Required (alongside company_name and founder_name) to provision a COO."
|
|
25439
26037
|
),
|
|
25440
|
-
company_name:
|
|
26038
|
+
company_name: z68.string().optional().describe(
|
|
25441
26039
|
"Optional. The client company the COO serves. Required to provision a COO."
|
|
25442
26040
|
),
|
|
25443
|
-
founder_name:
|
|
26041
|
+
founder_name: z68.string().optional().describe(
|
|
25444
26042
|
"Optional. The founder the COO reports to. Required to provision a COO."
|
|
25445
26043
|
)
|
|
25446
26044
|
}
|
|
@@ -25592,18 +26190,18 @@ var init_apply_starter_pack = __esm({
|
|
|
25592
26190
|
});
|
|
25593
26191
|
|
|
25594
26192
|
// src/mcp/tools/load-skill.ts
|
|
25595
|
-
import { z as
|
|
25596
|
-
import { readFileSync as
|
|
25597
|
-
import
|
|
26193
|
+
import { z as z69 } from "zod";
|
|
26194
|
+
import { readFileSync as readFileSync29, readdirSync as readdirSync13, statSync as statSync7 } from "fs";
|
|
26195
|
+
import path46 from "path";
|
|
25598
26196
|
import { homedir as homedir7 } from "os";
|
|
25599
26197
|
function listAvailableSkills() {
|
|
25600
26198
|
try {
|
|
25601
26199
|
const entries = readdirSync13(SKILLS_DIR);
|
|
25602
26200
|
return entries.filter((entry) => {
|
|
25603
26201
|
try {
|
|
25604
|
-
const entryPath =
|
|
26202
|
+
const entryPath = path46.join(SKILLS_DIR, entry);
|
|
25605
26203
|
if (!statSync7(entryPath).isDirectory()) return false;
|
|
25606
|
-
const skillFile =
|
|
26204
|
+
const skillFile = path46.join(entryPath, "SKILL.md");
|
|
25607
26205
|
statSync7(skillFile);
|
|
25608
26206
|
return true;
|
|
25609
26207
|
} catch {
|
|
@@ -25621,7 +26219,7 @@ function registerLoadSkill(server) {
|
|
|
25621
26219
|
title: "Load Skill",
|
|
25622
26220
|
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.",
|
|
25623
26221
|
inputSchema: {
|
|
25624
|
-
skill_name:
|
|
26222
|
+
skill_name: z69.string().describe(
|
|
25625
26223
|
"Skill to load (e.g. 'seo', 'code-reviewer', 'frontend-design'). Pass 'list' to see all available skills."
|
|
25626
26224
|
)
|
|
25627
26225
|
}
|
|
@@ -25646,10 +26244,10 @@ ${skills.map((s) => `- ${s}`).join("\n")}`
|
|
|
25646
26244
|
}]
|
|
25647
26245
|
};
|
|
25648
26246
|
}
|
|
25649
|
-
const sanitized =
|
|
25650
|
-
const skillFile =
|
|
26247
|
+
const sanitized = path46.basename(skill_name);
|
|
26248
|
+
const skillFile = path46.join(SKILLS_DIR, sanitized, "SKILL.md");
|
|
25651
26249
|
try {
|
|
25652
|
-
const content =
|
|
26250
|
+
const content = readFileSync29(skillFile, "utf-8");
|
|
25653
26251
|
return {
|
|
25654
26252
|
content: [{
|
|
25655
26253
|
type: "text",
|
|
@@ -25678,15 +26276,15 @@ var SKILLS_DIR;
|
|
|
25678
26276
|
var init_load_skill = __esm({
|
|
25679
26277
|
"src/mcp/tools/load-skill.ts"() {
|
|
25680
26278
|
"use strict";
|
|
25681
|
-
SKILLS_DIR =
|
|
26279
|
+
SKILLS_DIR = path46.join(homedir7(), ".claude", "skills");
|
|
25682
26280
|
}
|
|
25683
26281
|
});
|
|
25684
26282
|
|
|
25685
26283
|
// src/lib/orchestration-package.ts
|
|
25686
26284
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
25687
|
-
import { copyFileSync as copyFileSync2, existsSync as
|
|
26285
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync39, mkdirSync as mkdirSync18, readFileSync as readFileSync30, writeFileSync as writeFileSync21 } from "fs";
|
|
25688
26286
|
import os20 from "os";
|
|
25689
|
-
import
|
|
26287
|
+
import path47 from "path";
|
|
25690
26288
|
function ensureObject(value, label) {
|
|
25691
26289
|
if (value == null || Array.isArray(value) || typeof value !== "object") {
|
|
25692
26290
|
throw new Error(`${label} must be an object`);
|
|
@@ -25745,15 +26343,15 @@ function validateProcedureEntry(value, index) {
|
|
|
25745
26343
|
};
|
|
25746
26344
|
}
|
|
25747
26345
|
function getRosterPath() {
|
|
25748
|
-
return
|
|
26346
|
+
return path47.join(os20.homedir(), EXE_OS_DIRNAME, ROSTER_FILENAME);
|
|
25749
26347
|
}
|
|
25750
26348
|
function getBackupPath() {
|
|
25751
|
-
return
|
|
26349
|
+
return path47.join(os20.homedir(), EXE_OS_DIRNAME, ROSTER_BACKUP_FILENAME);
|
|
25752
26350
|
}
|
|
25753
26351
|
function readRosterFile() {
|
|
25754
26352
|
const rosterPath = getRosterPath();
|
|
25755
|
-
if (!
|
|
25756
|
-
const raw =
|
|
26353
|
+
if (!existsSync39(rosterPath)) return [];
|
|
26354
|
+
const raw = readFileSync30(rosterPath, "utf-8");
|
|
25757
26355
|
const parsed = JSON.parse(raw);
|
|
25758
26356
|
if (!Array.isArray(parsed)) {
|
|
25759
26357
|
throw new Error("Roster file must contain a JSON array");
|
|
@@ -25765,8 +26363,8 @@ function writeRosterFile(roster) {
|
|
|
25765
26363
|
throw new Error("Refusing to write empty roster \u2014 this would delete all employees");
|
|
25766
26364
|
}
|
|
25767
26365
|
const rosterPath = getRosterPath();
|
|
25768
|
-
|
|
25769
|
-
if (
|
|
26366
|
+
mkdirSync18(path47.dirname(rosterPath), { recursive: true });
|
|
26367
|
+
if (existsSync39(rosterPath)) {
|
|
25770
26368
|
const currentRoster = readRosterFile();
|
|
25771
26369
|
if (roster.length < currentRoster.length) {
|
|
25772
26370
|
throw new Error(
|
|
@@ -25775,7 +26373,7 @@ function writeRosterFile(roster) {
|
|
|
25775
26373
|
}
|
|
25776
26374
|
copyFileSync2(rosterPath, getBackupPath());
|
|
25777
26375
|
}
|
|
25778
|
-
|
|
26376
|
+
writeFileSync21(rosterPath, `${JSON.stringify(roster, null, 2)}
|
|
25779
26377
|
`, "utf-8");
|
|
25780
26378
|
}
|
|
25781
26379
|
function buildImportedRosterEntries(roster, timestamp) {
|
|
@@ -26038,9 +26636,9 @@ var init_orchestration_package = __esm({
|
|
|
26038
26636
|
});
|
|
26039
26637
|
|
|
26040
26638
|
// src/mcp/tools/export-orchestration.ts
|
|
26041
|
-
import { mkdirSync as
|
|
26042
|
-
import
|
|
26043
|
-
import { z as
|
|
26639
|
+
import { mkdirSync as mkdirSync19, writeFileSync as writeFileSync22 } from "fs";
|
|
26640
|
+
import path48 from "path";
|
|
26641
|
+
import { z as z70 } from "zod";
|
|
26044
26642
|
function registerExportOrchestration(server) {
|
|
26045
26643
|
server.registerTool(
|
|
26046
26644
|
"export_orchestration",
|
|
@@ -26048,15 +26646,15 @@ function registerExportOrchestration(server) {
|
|
|
26048
26646
|
title: "Export Orchestration",
|
|
26049
26647
|
description: "Export roster, identities, behaviors, and customer procedures to a JSON package.",
|
|
26050
26648
|
inputSchema: {
|
|
26051
|
-
output_path:
|
|
26649
|
+
output_path: z70.string().describe("File path to write the JSON package")
|
|
26052
26650
|
}
|
|
26053
26651
|
},
|
|
26054
26652
|
async ({ output_path }) => {
|
|
26055
26653
|
try {
|
|
26056
26654
|
await initStore();
|
|
26057
26655
|
const pkg = await exportOrchestration(getActiveAgent().agentId);
|
|
26058
|
-
|
|
26059
|
-
|
|
26656
|
+
mkdirSync19(path48.dirname(output_path), { recursive: true });
|
|
26657
|
+
writeFileSync22(output_path, `${JSON.stringify(pkg, null, 2)}
|
|
26060
26658
|
`, "utf-8");
|
|
26061
26659
|
return {
|
|
26062
26660
|
content: [{
|
|
@@ -26086,8 +26684,8 @@ var init_export_orchestration = __esm({
|
|
|
26086
26684
|
});
|
|
26087
26685
|
|
|
26088
26686
|
// src/mcp/tools/import-orchestration.ts
|
|
26089
|
-
import { readFileSync as
|
|
26090
|
-
import { z as
|
|
26687
|
+
import { readFileSync as readFileSync31 } from "fs";
|
|
26688
|
+
import { z as z71 } from "zod";
|
|
26091
26689
|
function registerImportOrchestration(server) {
|
|
26092
26690
|
server.registerTool(
|
|
26093
26691
|
"import_orchestration",
|
|
@@ -26095,8 +26693,8 @@ function registerImportOrchestration(server) {
|
|
|
26095
26693
|
title: "Import Orchestration",
|
|
26096
26694
|
description: "Import roster, identities, behaviors, and procedures from an orchestration package. Restricted to coordinator/founder.",
|
|
26097
26695
|
inputSchema: {
|
|
26098
|
-
package_path:
|
|
26099
|
-
merge_strategy:
|
|
26696
|
+
package_path: z71.string().describe("Path to the orchestration package JSON file"),
|
|
26697
|
+
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")
|
|
26100
26698
|
}
|
|
26101
26699
|
},
|
|
26102
26700
|
async ({ package_path, merge_strategy }) => {
|
|
@@ -26113,7 +26711,7 @@ function registerImportOrchestration(server) {
|
|
|
26113
26711
|
};
|
|
26114
26712
|
}
|
|
26115
26713
|
await initStore();
|
|
26116
|
-
const raw =
|
|
26714
|
+
const raw = readFileSync31(package_path, "utf-8");
|
|
26117
26715
|
const pkg = validatePackage(JSON.parse(raw));
|
|
26118
26716
|
const result = await importOrchestration(pkg, merge_strategy);
|
|
26119
26717
|
return {
|
|
@@ -26145,7 +26743,7 @@ var init_import_orchestration = __esm({
|
|
|
26145
26743
|
});
|
|
26146
26744
|
|
|
26147
26745
|
// src/mcp/tools/global-procedure.ts
|
|
26148
|
-
import { z as
|
|
26746
|
+
import { z as z72 } from "zod";
|
|
26149
26747
|
function registerCompanyProcedureTool(server, toolName) {
|
|
26150
26748
|
server.registerTool(
|
|
26151
26749
|
toolName,
|
|
@@ -26153,12 +26751,12 @@ function registerCompanyProcedureTool(server, toolName) {
|
|
|
26153
26751
|
title: "Company Procedure",
|
|
26154
26752
|
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).",
|
|
26155
26753
|
inputSchema: {
|
|
26156
|
-
action:
|
|
26157
|
-
title:
|
|
26158
|
-
content:
|
|
26159
|
-
priority:
|
|
26160
|
-
domain:
|
|
26161
|
-
procedure_id:
|
|
26754
|
+
action: z72.enum(["store", "list", "deactivate"]).describe("Action to perform"),
|
|
26755
|
+
title: z72.string().optional().describe("Short title for the procedure (store)"),
|
|
26756
|
+
content: z72.string().max(500).optional().describe("The procedure content \u2014 clear, actionable instruction (store)"),
|
|
26757
|
+
priority: z72.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always (default). p1 = standard. p2 = nice-to-have."),
|
|
26758
|
+
domain: z72.string().optional().describe("Category: workflow, code-style, communication, architecture, testing, security"),
|
|
26759
|
+
procedure_id: z72.string().optional().describe("UUID of the company procedure (deactivate)")
|
|
26162
26760
|
}
|
|
26163
26761
|
},
|
|
26164
26762
|
async ({ action, title, content, priority, domain, procedure_id }) => {
|
|
@@ -26289,7 +26887,7 @@ var init_global_procedure = __esm({
|
|
|
26289
26887
|
});
|
|
26290
26888
|
|
|
26291
26889
|
// src/mcp/tools/config.ts
|
|
26292
|
-
import { z as
|
|
26890
|
+
import { z as z73 } from "zod";
|
|
26293
26891
|
function errorResult8(text3) {
|
|
26294
26892
|
return { content: [{ type: "text", text: text3 }], isError: true };
|
|
26295
26893
|
}
|
|
@@ -26311,6 +26909,7 @@ function buildHandlers5() {
|
|
|
26311
26909
|
registerRunMemoryAudit(localServer);
|
|
26312
26910
|
registerRunConsolidation(localServer);
|
|
26313
26911
|
registerCloudSync(localServer);
|
|
26912
|
+
registerOrchestrationPhase(localServer);
|
|
26314
26913
|
registerBackupVps(localServer);
|
|
26315
26914
|
registerDeployClient(localServer);
|
|
26316
26915
|
registerGetLicenseStatus(localServer);
|
|
@@ -26333,41 +26932,42 @@ function registerConfig(server) {
|
|
|
26333
26932
|
title: "Config",
|
|
26334
26933
|
description: "Consolidated COO/admin tool for runtime config, system health, licensing, triggers, orchestration import/export, and company procedures.",
|
|
26335
26934
|
inputSchema: {
|
|
26336
|
-
action:
|
|
26337
|
-
agent_id:
|
|
26338
|
-
runtime:
|
|
26339
|
-
model:
|
|
26340
|
-
reasoning_effort:
|
|
26341
|
-
dry_run:
|
|
26342
|
-
fix:
|
|
26343
|
-
verbose:
|
|
26344
|
-
project_name:
|
|
26345
|
-
since:
|
|
26346
|
-
limit:
|
|
26347
|
-
output_path:
|
|
26348
|
-
input_path:
|
|
26349
|
-
strategy:
|
|
26350
|
-
license_key:
|
|
26351
|
-
email:
|
|
26352
|
-
plan:
|
|
26353
|
-
name:
|
|
26354
|
-
event:
|
|
26355
|
-
conditions:
|
|
26356
|
-
actions:
|
|
26357
|
-
enabled:
|
|
26358
|
-
schedule:
|
|
26359
|
-
query:
|
|
26360
|
-
skill_name:
|
|
26361
|
-
pack_name:
|
|
26362
|
-
title:
|
|
26363
|
-
content:
|
|
26364
|
-
priority:
|
|
26365
|
-
domain:
|
|
26366
|
-
procedure_id:
|
|
26367
|
-
subaction:
|
|
26368
|
-
max_clusters:
|
|
26369
|
-
force:
|
|
26370
|
-
domain_name:
|
|
26935
|
+
action: z73.enum(Object.keys(ACTION_TO_TOOL2)).describe("Admin/config operation"),
|
|
26936
|
+
agent_id: z73.string().optional().describe("Agent id for set_agent_config/agent_spend/session queries"),
|
|
26937
|
+
runtime: z73.string().optional().describe("Runtime for set_agent_config"),
|
|
26938
|
+
model: z73.string().optional().describe("Model for set_agent_config"),
|
|
26939
|
+
reasoning_effort: z73.string().optional().describe("Reasoning effort for Codex agents"),
|
|
26940
|
+
dry_run: z73.boolean().optional().describe("Preview without applying where supported"),
|
|
26941
|
+
fix: z73.boolean().optional().describe("Apply fixes for memory_audit where supported"),
|
|
26942
|
+
verbose: z73.boolean().optional().describe("Verbose output where supported"),
|
|
26943
|
+
project_name: z73.string().optional().describe("Project filter/name"),
|
|
26944
|
+
since: z73.string().optional().describe("ISO lower-bound timestamp"),
|
|
26945
|
+
limit: z73.coerce.number().optional().describe("Result limit"),
|
|
26946
|
+
output_path: z73.string().optional().describe("Output path for export/backup"),
|
|
26947
|
+
input_path: z73.string().optional().describe("Input path for import_orchestration"),
|
|
26948
|
+
strategy: z73.enum(["merge", "replace"]).optional().describe("Import strategy; replace must still be additive-only per platform rules"),
|
|
26949
|
+
license_key: z73.string().optional().describe("License key for activation/status"),
|
|
26950
|
+
email: z73.string().optional().describe("Customer email for license creation"),
|
|
26951
|
+
plan: z73.string().optional().describe("License plan"),
|
|
26952
|
+
name: z73.string().optional().describe("Trigger/starter pack/procedure/client name"),
|
|
26953
|
+
event: z73.string().optional().describe("Trigger event"),
|
|
26954
|
+
conditions: z73.array(z73.record(z73.string(), z73.unknown())).optional().describe("Trigger conditions"),
|
|
26955
|
+
actions: z73.array(z73.record(z73.string(), z73.unknown())).optional().describe("Trigger actions"),
|
|
26956
|
+
enabled: z73.boolean().optional().describe("Trigger enabled flag"),
|
|
26957
|
+
schedule: z73.string().optional().describe("Trigger schedule"),
|
|
26958
|
+
query: z73.string().optional().describe("Trigger query or filter"),
|
|
26959
|
+
skill_name: z73.string().optional().describe("Skill name for load_skill"),
|
|
26960
|
+
pack_name: z73.string().optional().describe("Starter pack name"),
|
|
26961
|
+
title: z73.string().optional().describe("Procedure title"),
|
|
26962
|
+
content: z73.string().optional().describe("Procedure content"),
|
|
26963
|
+
priority: z73.enum(["p0", "p1", "p2"]).optional().describe("Procedure priority"),
|
|
26964
|
+
domain: z73.string().optional().describe("Procedure domain"),
|
|
26965
|
+
procedure_id: z73.string().optional().describe("Procedure id for deactivate"),
|
|
26966
|
+
subaction: z73.enum(["store", "list", "deactivate"]).optional().describe("Nested action for company_procedure/global_procedure"),
|
|
26967
|
+
max_clusters: z73.coerce.number().optional().describe("Consolidation max clusters"),
|
|
26968
|
+
force: z73.boolean().optional().describe("Force operation where supported"),
|
|
26969
|
+
domain_name: z73.string().optional().describe("Client deployment domain"),
|
|
26970
|
+
phase: z73.enum(["phase_1_coo", "phase_2_executives", "phase_3_parallel_org", "1", "2", "3"]).optional().describe("Orchestration phase for orchestration_phase action")
|
|
26371
26971
|
}
|
|
26372
26972
|
}, async (input, extra) => {
|
|
26373
26973
|
const action = input.action;
|
|
@@ -26401,6 +27001,7 @@ var init_config2 = __esm({
|
|
|
26401
27001
|
init_run_memory_audit();
|
|
26402
27002
|
init_run_consolidation();
|
|
26403
27003
|
init_cloud_sync2();
|
|
27004
|
+
init_orchestration_phase2();
|
|
26404
27005
|
init_backup_vps();
|
|
26405
27006
|
init_deploy_client();
|
|
26406
27007
|
init_get_license_status();
|
|
@@ -26426,6 +27027,7 @@ var init_config2 = __esm({
|
|
|
26426
27027
|
memory_audit: "run_memory_audit",
|
|
26427
27028
|
run_consolidation: "run_consolidation",
|
|
26428
27029
|
cloud_sync: "cloud_sync",
|
|
27030
|
+
orchestration_phase: "orchestration_phase",
|
|
26429
27031
|
backup_vps: "backup_vps",
|
|
26430
27032
|
deploy_client: "deploy_client",
|
|
26431
27033
|
license_status: "get_license_status",
|
|
@@ -26445,7 +27047,7 @@ var init_config2 = __esm({
|
|
|
26445
27047
|
});
|
|
26446
27048
|
|
|
26447
27049
|
// src/mcp/tools/list-wiki-pages.ts
|
|
26448
|
-
import { z as
|
|
27050
|
+
import { z as z74 } from "zod";
|
|
26449
27051
|
function registerListWikiPages(server) {
|
|
26450
27052
|
server.registerTool(
|
|
26451
27053
|
"list_wiki_pages",
|
|
@@ -26453,8 +27055,8 @@ function registerListWikiPages(server) {
|
|
|
26453
27055
|
title: "List Wiki Pages",
|
|
26454
27056
|
description: "List documents in an exe-wiki workspace. Optionally filter by folder.",
|
|
26455
27057
|
inputSchema: {
|
|
26456
|
-
workspace:
|
|
26457
|
-
folder:
|
|
27058
|
+
workspace: z74.string().describe('Wiki workspace slug (e.g., "hygo")'),
|
|
27059
|
+
folder: z74.string().optional().describe("Filter by folder path")
|
|
26458
27060
|
}
|
|
26459
27061
|
},
|
|
26460
27062
|
async ({ workspace, folder }) => {
|
|
@@ -26550,7 +27152,7 @@ var init_list_wiki_pages = __esm({
|
|
|
26550
27152
|
});
|
|
26551
27153
|
|
|
26552
27154
|
// src/mcp/tools/get-wiki-page.ts
|
|
26553
|
-
import { z as
|
|
27155
|
+
import { z as z75 } from "zod";
|
|
26554
27156
|
function registerGetWikiPage(server) {
|
|
26555
27157
|
server.registerTool(
|
|
26556
27158
|
"get_wiki_page",
|
|
@@ -26558,9 +27160,9 @@ function registerGetWikiPage(server) {
|
|
|
26558
27160
|
title: "Get Wiki Page",
|
|
26559
27161
|
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.",
|
|
26560
27162
|
inputSchema: {
|
|
26561
|
-
workspace:
|
|
26562
|
-
document_id:
|
|
26563
|
-
title:
|
|
27163
|
+
workspace: z75.string().describe('Wiki workspace slug (e.g., "hygo")'),
|
|
27164
|
+
document_id: z75.string().optional().describe("Specific document ID (exact lookup)"),
|
|
27165
|
+
title: z75.string().optional().describe("Search by title (fuzzy match)")
|
|
26564
27166
|
}
|
|
26565
27167
|
},
|
|
26566
27168
|
async ({ workspace, document_id, title }) => {
|
|
@@ -26716,7 +27318,7 @@ var init_get_wiki_page = __esm({
|
|
|
26716
27318
|
});
|
|
26717
27319
|
|
|
26718
27320
|
// src/mcp/tools/wiki.ts
|
|
26719
|
-
import { z as
|
|
27321
|
+
import { z as z76 } from "zod";
|
|
26720
27322
|
function errorResult9(text3) {
|
|
26721
27323
|
return { content: [{ type: "text", text: text3 }], isError: true };
|
|
26722
27324
|
}
|
|
@@ -26742,14 +27344,14 @@ function registerWiki(server) {
|
|
|
26742
27344
|
title: "Wiki",
|
|
26743
27345
|
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.",
|
|
26744
27346
|
inputSchema: {
|
|
26745
|
-
action:
|
|
26746
|
-
workspace:
|
|
26747
|
-
title:
|
|
26748
|
-
content:
|
|
26749
|
-
folder:
|
|
26750
|
-
document_id:
|
|
26751
|
-
mode:
|
|
26752
|
-
section:
|
|
27347
|
+
action: z76.enum(["list", "get"]).describe("Wiki read operation. Writes use raw-data ingestion/projection, not direct MCP writes."),
|
|
27348
|
+
workspace: z76.string().optional().describe("Wiki workspace slug"),
|
|
27349
|
+
title: z76.string().optional().describe("Fuzzy page title lookup for get"),
|
|
27350
|
+
content: z76.string().optional().describe("Reserved; wiki writes use raw-data ingestion/projection"),
|
|
27351
|
+
folder: z76.string().optional().describe("Optional folder path for list"),
|
|
27352
|
+
document_id: z76.string().optional().describe("Document ID for get"),
|
|
27353
|
+
mode: z76.enum(["replace", "append"]).optional().describe("Reserved; direct wiki updates are removed"),
|
|
27354
|
+
section: z76.string().optional().describe("Reserved; direct wiki updates are removed")
|
|
26753
27355
|
}
|
|
26754
27356
|
},
|
|
26755
27357
|
async (input, extra) => {
|
|
@@ -26788,7 +27390,7 @@ var init_wiki = __esm({
|
|
|
26788
27390
|
});
|
|
26789
27391
|
|
|
26790
27392
|
// src/mcp/tools/behavior.ts
|
|
26791
|
-
import { z as
|
|
27393
|
+
import { z as z77 } from "zod";
|
|
26792
27394
|
function rowToBehavior2(r) {
|
|
26793
27395
|
return {
|
|
26794
27396
|
id: String(r.id),
|
|
@@ -26810,13 +27412,13 @@ function registerBehavior(server) {
|
|
|
26810
27412
|
title: "Behavior",
|
|
26811
27413
|
description: "Manage behavioral patterns, corrections, and reusable procedures for employees. Actions: store (create new), list (query existing), deactivate (soft-delete, restricted).",
|
|
26812
27414
|
inputSchema: {
|
|
26813
|
-
action:
|
|
26814
|
-
content:
|
|
26815
|
-
domain:
|
|
26816
|
-
priority:
|
|
26817
|
-
agent_id:
|
|
26818
|
-
project_name:
|
|
26819
|
-
behavior_id:
|
|
27415
|
+
action: z77.enum(["store", "list", "deactivate"]).describe("Action to perform"),
|
|
27416
|
+
content: z77.string().max(500).optional().describe("The behavioral instruction \u2014 one clear sentence (store)"),
|
|
27417
|
+
domain: z77.string().optional().describe("Category: workflow, code-style, tool-use, communication, architecture, testing"),
|
|
27418
|
+
priority: z77.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always included. p1 = standard (default). p2 = nice-to-have."),
|
|
27419
|
+
agent_id: z77.string().optional().describe("Employee name. Defaults to current agent. Pass 'all' to list everyone's (list only)."),
|
|
27420
|
+
project_name: z77.string().optional().describe("Defaults to current project. Pass 'global' for a behavior that applies everywhere (store)."),
|
|
27421
|
+
behavior_id: z77.string().optional().describe("UUID of the behavior (deactivate)")
|
|
26820
27422
|
}
|
|
26821
27423
|
},
|
|
26822
27424
|
async ({ action, content, domain, priority, agent_id, project_name, behavior_id }) => {
|
|
@@ -26997,7 +27599,7 @@ var init_behavior = __esm({
|
|
|
26997
27599
|
});
|
|
26998
27600
|
|
|
26999
27601
|
// src/mcp/tools/reminder.ts
|
|
27000
|
-
import { z as
|
|
27602
|
+
import { z as z78 } from "zod";
|
|
27001
27603
|
function registerReminder(server) {
|
|
27002
27604
|
server.registerTool(
|
|
27003
27605
|
"reminder",
|
|
@@ -27005,11 +27607,11 @@ function registerReminder(server) {
|
|
|
27005
27607
|
title: "Reminder",
|
|
27006
27608
|
description: "Manage reminders for the founder. Shown in the boot brief every session. Actions: create (set new), list (view active), complete (mark done).",
|
|
27007
27609
|
inputSchema: {
|
|
27008
|
-
action:
|
|
27009
|
-
text:
|
|
27010
|
-
due_date:
|
|
27011
|
-
reminder_id:
|
|
27012
|
-
include_completed:
|
|
27610
|
+
action: z78.enum(["create", "list", "complete"]).describe("Action to perform"),
|
|
27611
|
+
text: z78.string().optional().describe("What to remind about (create)"),
|
|
27612
|
+
due_date: z78.string().optional().describe("Optional due date \u2014 ISO date (2026-04-01) or null for persistent (create)"),
|
|
27613
|
+
reminder_id: z78.string().optional().describe("Reminder UUID or text substring to match (complete)"),
|
|
27614
|
+
include_completed: z78.boolean().optional().default(false).describe("Include completed reminders (list)")
|
|
27013
27615
|
}
|
|
27014
27616
|
},
|
|
27015
27617
|
async ({ action, text: text3, due_date, reminder_id, include_completed }) => {
|
|
@@ -27068,7 +27670,7 @@ var init_reminder = __esm({
|
|
|
27068
27670
|
});
|
|
27069
27671
|
|
|
27070
27672
|
// src/mcp/tools/store-global-procedure.ts
|
|
27071
|
-
import { z as
|
|
27673
|
+
import { z as z79 } from "zod";
|
|
27072
27674
|
function registerStoreGlobalProcedure(server) {
|
|
27073
27675
|
server.registerTool(
|
|
27074
27676
|
"store_global_procedure",
|
|
@@ -27076,10 +27678,10 @@ function registerStoreGlobalProcedure(server) {
|
|
|
27076
27678
|
title: "Store Company Procedure (use global_procedure instead)",
|
|
27077
27679
|
description: "DEPRECATED \u2014 use global_procedure with action='store'. Create a company procedure (customer-owned Layer 0 rule). RESTRICTED: only coordinator or founder sessions.",
|
|
27078
27680
|
inputSchema: {
|
|
27079
|
-
title:
|
|
27080
|
-
content:
|
|
27081
|
-
priority:
|
|
27082
|
-
domain:
|
|
27681
|
+
title: z79.string().describe("Short title for the procedure"),
|
|
27682
|
+
content: z79.string().max(500).describe("The procedure content \u2014 clear, actionable instruction"),
|
|
27683
|
+
priority: z79.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always (default)."),
|
|
27684
|
+
domain: z79.string().optional().describe("Category: workflow, code-style, communication, architecture, testing, security")
|
|
27083
27685
|
}
|
|
27084
27686
|
},
|
|
27085
27687
|
async ({ title, content, priority, domain }) => {
|
|
@@ -27166,7 +27768,7 @@ var init_list_global_procedures = __esm({
|
|
|
27166
27768
|
});
|
|
27167
27769
|
|
|
27168
27770
|
// src/mcp/tools/deactivate-global-procedure.ts
|
|
27169
|
-
import { z as
|
|
27771
|
+
import { z as z80 } from "zod";
|
|
27170
27772
|
function registerDeactivateGlobalProcedure(server) {
|
|
27171
27773
|
server.registerTool(
|
|
27172
27774
|
"deactivate_global_procedure",
|
|
@@ -27174,7 +27776,7 @@ function registerDeactivateGlobalProcedure(server) {
|
|
|
27174
27776
|
title: "Deactivate Company Procedure (use global_procedure instead)",
|
|
27175
27777
|
description: "DEPRECATED \u2014 use global_procedure with action='deactivate'. Soft-delete a company procedure. RESTRICTED: only coordinator or founder sessions.",
|
|
27176
27778
|
inputSchema: {
|
|
27177
|
-
procedure_id:
|
|
27779
|
+
procedure_id: z80.string().describe("UUID of the company procedure to deactivate")
|
|
27178
27780
|
}
|
|
27179
27781
|
},
|
|
27180
27782
|
async ({ procedure_id }) => {
|
|
@@ -27238,7 +27840,7 @@ var init_deactivate_global_procedure = __esm({
|
|
|
27238
27840
|
});
|
|
27239
27841
|
|
|
27240
27842
|
// src/mcp/tools/store-decision.ts
|
|
27241
|
-
import { z as
|
|
27843
|
+
import { z as z81 } from "zod";
|
|
27242
27844
|
import crypto18 from "crypto";
|
|
27243
27845
|
function registerStoreDecision(server) {
|
|
27244
27846
|
server.registerTool(
|
|
@@ -27247,13 +27849,13 @@ function registerStoreDecision(server) {
|
|
|
27247
27849
|
title: "Store Decision",
|
|
27248
27850
|
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.",
|
|
27249
27851
|
inputSchema: {
|
|
27250
|
-
domain:
|
|
27852
|
+
domain: z81.string().describe(
|
|
27251
27853
|
"Domain key, e.g. 'auth-strategy', 'db-migration-approach', 'api-versioning'"
|
|
27252
27854
|
),
|
|
27253
|
-
decision:
|
|
27254
|
-
rationale:
|
|
27255
|
-
supersedes:
|
|
27256
|
-
project_name:
|
|
27855
|
+
decision: z81.string().describe("The decision text \u2014 what was decided"),
|
|
27856
|
+
rationale: z81.string().optional().describe("Why this decision was made \u2014 constraints, trade-offs, context"),
|
|
27857
|
+
supersedes: z81.string().optional().describe("UUID of the decision this supersedes (previous decision for this domain)"),
|
|
27858
|
+
project_name: z81.string().optional().describe("Project name")
|
|
27257
27859
|
}
|
|
27258
27860
|
},
|
|
27259
27861
|
async ({ domain, decision, rationale, supersedes, project_name }) => {
|
|
@@ -27330,7 +27932,7 @@ var init_store_decision = __esm({
|
|
|
27330
27932
|
});
|
|
27331
27933
|
|
|
27332
27934
|
// src/mcp/tools/get-decision.ts
|
|
27333
|
-
import { z as
|
|
27935
|
+
import { z as z82 } from "zod";
|
|
27334
27936
|
function registerGetDecision(server) {
|
|
27335
27937
|
server.registerTool(
|
|
27336
27938
|
"get_decision",
|
|
@@ -27338,7 +27940,7 @@ function registerGetDecision(server) {
|
|
|
27338
27940
|
title: "Get Decision",
|
|
27339
27941
|
description: "Retrieve the latest authoritative decision for a domain. Returns the current active decision and the supersession history.",
|
|
27340
27942
|
inputSchema: {
|
|
27341
|
-
domain:
|
|
27943
|
+
domain: z82.string().describe(
|
|
27342
27944
|
"Domain key to look up, e.g. 'auth-strategy', 'db-migration-approach'"
|
|
27343
27945
|
)
|
|
27344
27946
|
}
|
|
@@ -27408,10 +28010,10 @@ var init_get_decision = __esm({
|
|
|
27408
28010
|
|
|
27409
28011
|
// src/lib/people.ts
|
|
27410
28012
|
import { readFile as readFile5, writeFile as writeFile6, mkdir as mkdir5 } from "fs/promises";
|
|
27411
|
-
import { existsSync as
|
|
27412
|
-
import
|
|
28013
|
+
import { existsSync as existsSync40, readFileSync as readFileSync32 } from "fs";
|
|
28014
|
+
import path49 from "path";
|
|
27413
28015
|
async function loadPeople() {
|
|
27414
|
-
if (!
|
|
28016
|
+
if (!existsSync40(PEOPLE_PATH)) return [];
|
|
27415
28017
|
try {
|
|
27416
28018
|
const raw = await readFile5(PEOPLE_PATH, "utf-8");
|
|
27417
28019
|
return JSON.parse(raw);
|
|
@@ -27420,7 +28022,7 @@ async function loadPeople() {
|
|
|
27420
28022
|
}
|
|
27421
28023
|
}
|
|
27422
28024
|
async function savePeople(people) {
|
|
27423
|
-
await mkdir5(
|
|
28025
|
+
await mkdir5(path49.dirname(PEOPLE_PATH), { recursive: true });
|
|
27424
28026
|
await writeFile6(PEOPLE_PATH, JSON.stringify(people, null, 2) + "\n", "utf-8");
|
|
27425
28027
|
}
|
|
27426
28028
|
async function addPerson(person) {
|
|
@@ -27446,12 +28048,12 @@ var init_people = __esm({
|
|
|
27446
28048
|
"src/lib/people.ts"() {
|
|
27447
28049
|
"use strict";
|
|
27448
28050
|
init_config();
|
|
27449
|
-
PEOPLE_PATH =
|
|
28051
|
+
PEOPLE_PATH = path49.join(EXE_AI_DIR, "people.json");
|
|
27450
28052
|
}
|
|
27451
28053
|
});
|
|
27452
28054
|
|
|
27453
28055
|
// src/mcp/tools/people-roster.ts
|
|
27454
|
-
import { z as
|
|
28056
|
+
import { z as z83 } from "zod";
|
|
27455
28057
|
function registerAddPerson(server) {
|
|
27456
28058
|
server.registerTool(
|
|
27457
28059
|
"add_person",
|
|
@@ -27459,10 +28061,10 @@ function registerAddPerson(server) {
|
|
|
27459
28061
|
title: "Add Person",
|
|
27460
28062
|
description: "Add or update a key human in the people roster. Used for co-founders, partners, customers \u2014 anyone agents need to know about.",
|
|
27461
28063
|
inputSchema: {
|
|
27462
|
-
name:
|
|
27463
|
-
role:
|
|
27464
|
-
relationship:
|
|
27465
|
-
notes:
|
|
28064
|
+
name: z83.string().describe("Person's name"),
|
|
28065
|
+
role: z83.string().describe("Their role (e.g. co-founder, customer, partner)"),
|
|
28066
|
+
relationship: z83.string().describe("Relationship to the organization (e.g. co-founder, early adopter, investor)"),
|
|
28067
|
+
notes: z83.string().optional().describe("Additional context about this person")
|
|
27466
28068
|
}
|
|
27467
28069
|
},
|
|
27468
28070
|
async ({ name, role, relationship, notes }) => {
|
|
@@ -27508,7 +28110,7 @@ function registerGetPerson(server) {
|
|
|
27508
28110
|
title: "Get Person",
|
|
27509
28111
|
description: "Look up a specific person by name from the people roster.",
|
|
27510
28112
|
inputSchema: {
|
|
27511
|
-
name:
|
|
28113
|
+
name: z83.string().describe("Person's name to look up")
|
|
27512
28114
|
}
|
|
27513
28115
|
},
|
|
27514
28116
|
async ({ name }) => {
|
|
@@ -27538,7 +28140,7 @@ var init_people_roster = __esm({
|
|
|
27538
28140
|
});
|
|
27539
28141
|
|
|
27540
28142
|
// src/lib/exe-db-read.ts
|
|
27541
|
-
import
|
|
28143
|
+
import path50 from "path";
|
|
27542
28144
|
import os21 from "os";
|
|
27543
28145
|
import { createRequire as createRequire6 } from "module";
|
|
27544
28146
|
import { pathToFileURL as pathToFileURL6 } from "url";
|
|
@@ -27555,8 +28157,8 @@ async function getExeDbReadClient() {
|
|
|
27555
28157
|
if (!Ctor2) throw new Error(`No PrismaClient export found at ${explicitPath}`);
|
|
27556
28158
|
return new Ctor2();
|
|
27557
28159
|
}
|
|
27558
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
27559
|
-
const req = createRequire6(
|
|
28160
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path50.join(os21.homedir(), "exe-db");
|
|
28161
|
+
const req = createRequire6(path50.join(exeDbRoot, "package.json"));
|
|
27560
28162
|
const entry = req.resolve("@prisma/client");
|
|
27561
28163
|
const mod = await import(pathToFileURL6(entry).href);
|
|
27562
28164
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -27583,7 +28185,7 @@ var init_exe_db_read = __esm({
|
|
|
27583
28185
|
});
|
|
27584
28186
|
|
|
27585
28187
|
// src/mcp/tools/crm.ts
|
|
27586
|
-
import { z as
|
|
28188
|
+
import { z as z84 } from "zod";
|
|
27587
28189
|
function text(content, isError = false) {
|
|
27588
28190
|
return { content: [{ type: "text", text: content }], ...isError ? { isError: true } : {} };
|
|
27589
28191
|
}
|
|
@@ -27597,12 +28199,12 @@ function registerCrm(server) {
|
|
|
27597
28199
|
title: "CRM",
|
|
27598
28200
|
description: "Read-only CRM access from exe-db crm schema. Actions: list_people, get_person, list_tables, describe_table.",
|
|
27599
28201
|
inputSchema: {
|
|
27600
|
-
action:
|
|
27601
|
-
id:
|
|
27602
|
-
query:
|
|
27603
|
-
table:
|
|
27604
|
-
limit:
|
|
27605
|
-
offset:
|
|
28202
|
+
action: z84.enum(["list_people", "get_person", "list_tables", "describe_table"]).describe("CRM read operation"),
|
|
28203
|
+
id: z84.string().optional().describe("CRM row/person id for get_person"),
|
|
28204
|
+
query: z84.string().optional().describe("Text search for list_people/get_person"),
|
|
28205
|
+
table: z84.string().optional().describe("crm schema table name for describe_table"),
|
|
28206
|
+
limit: z84.coerce.number().int().min(1).max(50).optional().describe("Max rows, capped at 50"),
|
|
28207
|
+
offset: z84.coerce.number().int().min(0).optional().describe("Rows to skip")
|
|
27606
28208
|
}
|
|
27607
28209
|
}, async ({ action, id, query, table, limit, offset }) => {
|
|
27608
28210
|
try {
|
|
@@ -27667,7 +28269,7 @@ var init_crm = __esm({
|
|
|
27667
28269
|
});
|
|
27668
28270
|
|
|
27669
28271
|
// src/mcp/tools/raw-data.ts
|
|
27670
|
-
import { z as
|
|
28272
|
+
import { z as z85 } from "zod";
|
|
27671
28273
|
function text2(content, isError = false) {
|
|
27672
28274
|
return { content: [{ type: "text", text: content }], ...isError ? { isError: true } : {} };
|
|
27673
28275
|
}
|
|
@@ -27676,15 +28278,15 @@ function registerRawData(server) {
|
|
|
27676
28278
|
title: "Raw Data",
|
|
27677
28279
|
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.",
|
|
27678
28280
|
inputSchema: {
|
|
27679
|
-
action:
|
|
27680
|
-
id:
|
|
27681
|
-
source:
|
|
27682
|
-
event_type:
|
|
27683
|
-
query:
|
|
27684
|
-
processed:
|
|
27685
|
-
limit:
|
|
27686
|
-
offset:
|
|
27687
|
-
include_payload:
|
|
28281
|
+
action: z85.enum(["list_sources", "query", "get"]).describe("Raw data read operation"),
|
|
28282
|
+
id: z85.string().optional().describe("raw.raw_events id for action=get"),
|
|
28283
|
+
source: z85.string().optional().describe("Filter by raw source"),
|
|
28284
|
+
event_type: z85.string().optional().describe("Filter by event_type"),
|
|
28285
|
+
query: z85.string().optional().describe("Search payload/metadata text"),
|
|
28286
|
+
processed: z85.boolean().optional().describe("Filter processed_at IS NULL/NOT NULL"),
|
|
28287
|
+
limit: z85.coerce.number().int().min(1).max(50).optional().describe("Max rows, capped at 50"),
|
|
28288
|
+
offset: z85.coerce.number().int().min(0).optional().describe("Rows to skip"),
|
|
28289
|
+
include_payload: z85.boolean().optional().describe("Include full payload JSON. Default false to save tokens.")
|
|
27688
28290
|
}
|
|
27689
28291
|
}, async ({ action, id, source, event_type, query, processed, limit, offset, include_payload }) => {
|
|
27690
28292
|
try {
|
|
@@ -27752,10 +28354,10 @@ var init_raw_data = __esm({
|
|
|
27752
28354
|
});
|
|
27753
28355
|
|
|
27754
28356
|
// src/mcp/tools/create-bug-report.ts
|
|
27755
|
-
import { z as
|
|
28357
|
+
import { z as z86 } from "zod";
|
|
27756
28358
|
import crypto19 from "crypto";
|
|
27757
28359
|
import { mkdir as mkdir6, writeFile as writeFile7 } from "fs/promises";
|
|
27758
|
-
import
|
|
28360
|
+
import path51 from "path";
|
|
27759
28361
|
function slugify2(input) {
|
|
27760
28362
|
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "bug-report";
|
|
27761
28363
|
}
|
|
@@ -27833,22 +28435,22 @@ function registerCreateBugReport(server) {
|
|
|
27833
28435
|
title: "Create Bug Report",
|
|
27834
28436
|
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.",
|
|
27835
28437
|
inputSchema: {
|
|
27836
|
-
title:
|
|
28438
|
+
title: z86.string().min(3).describe("Short descriptive title"),
|
|
27837
28439
|
classification: CLASSIFICATION.describe(
|
|
27838
28440
|
"upstream_bug = platform defect; customer_customization = local preference; emergency_hotfix = temporary local patch; unclear = needs maintainer triage"
|
|
27839
28441
|
),
|
|
27840
28442
|
severity: SEVERITY.default("p2").describe("p0 critical \u2192 p3 low"),
|
|
27841
|
-
summary:
|
|
27842
|
-
customer_impact:
|
|
27843
|
-
reproduction_steps:
|
|
27844
|
-
expected:
|
|
27845
|
-
actual:
|
|
27846
|
-
files_changed:
|
|
27847
|
-
workaround:
|
|
27848
|
-
local_patch_diff:
|
|
27849
|
-
package_version:
|
|
27850
|
-
project_name:
|
|
27851
|
-
send_upstream:
|
|
28443
|
+
summary: z86.string().min(10).describe("What happened and why it matters"),
|
|
28444
|
+
customer_impact: z86.string().optional().describe("How this affects the customer/founder"),
|
|
28445
|
+
reproduction_steps: z86.array(z86.string()).optional().describe("Steps to reproduce"),
|
|
28446
|
+
expected: z86.string().optional().describe("Expected behavior"),
|
|
28447
|
+
actual: z86.string().optional().describe("Actual behavior"),
|
|
28448
|
+
files_changed: z86.array(z86.string()).optional().describe("Files changed or suspected"),
|
|
28449
|
+
workaround: z86.string().optional().describe("Temporary local workaround/hotfix, if any"),
|
|
28450
|
+
local_patch_diff: z86.string().optional().describe("Small local diff or patch summary"),
|
|
28451
|
+
package_version: z86.string().optional().describe("Installed @askexenow/exe-os version"),
|
|
28452
|
+
project_name: z86.string().optional().describe("Project/customer context"),
|
|
28453
|
+
send_upstream: z86.boolean().default(true).describe("Attempt to POST to configured AskExe support endpoint")
|
|
27852
28454
|
}
|
|
27853
28455
|
},
|
|
27854
28456
|
async ({
|
|
@@ -27888,9 +28490,9 @@ function registerCreateBugReport(server) {
|
|
|
27888
28490
|
filesChanged: files_changed,
|
|
27889
28491
|
projectName: project_name
|
|
27890
28492
|
});
|
|
27891
|
-
const outDir =
|
|
28493
|
+
const outDir = path51.join(EXE_AI_DIR, "bug-reports");
|
|
27892
28494
|
await mkdir6(outDir, { recursive: true });
|
|
27893
|
-
const reportPath =
|
|
28495
|
+
const reportPath = path51.join(outDir, `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}-${slugify2(title)}-${id.slice(0, 8)}.md`);
|
|
27894
28496
|
await writeFile7(reportPath, markdown, "utf-8");
|
|
27895
28497
|
let vector = null;
|
|
27896
28498
|
try {
|
|
@@ -27964,18 +28566,18 @@ var init_create_bug_report = __esm({
|
|
|
27964
28566
|
init_config();
|
|
27965
28567
|
init_license();
|
|
27966
28568
|
init_store();
|
|
27967
|
-
CLASSIFICATION =
|
|
28569
|
+
CLASSIFICATION = z86.enum([
|
|
27968
28570
|
"upstream_bug",
|
|
27969
28571
|
"customer_customization",
|
|
27970
28572
|
"emergency_hotfix",
|
|
27971
28573
|
"unclear"
|
|
27972
28574
|
]);
|
|
27973
|
-
SEVERITY =
|
|
28575
|
+
SEVERITY = z86.enum(["p0", "p1", "p2", "p3"]);
|
|
27974
28576
|
}
|
|
27975
28577
|
});
|
|
27976
28578
|
|
|
27977
28579
|
// src/mcp/tools/support-inbox.ts
|
|
27978
|
-
import { z as
|
|
28580
|
+
import { z as z87 } from "zod";
|
|
27979
28581
|
function adminToken() {
|
|
27980
28582
|
return process.env.ASKEXE_SUPPORT_ADMIN_TOKEN || process.env.EXE_SUPPORT_ADMIN_TOKEN;
|
|
27981
28583
|
}
|
|
@@ -28014,9 +28616,9 @@ function registerListBugReports(server) {
|
|
|
28014
28616
|
title: "List Bug Reports",
|
|
28015
28617
|
description: "AskExe-internal only: list incoming customer bug reports from the support inbox.",
|
|
28016
28618
|
inputSchema: {
|
|
28017
|
-
status:
|
|
28018
|
-
severity:
|
|
28019
|
-
limit:
|
|
28619
|
+
status: z87.enum(["all", "open", "triaged", "fixed", "closed", "wontfix"]).default("open"),
|
|
28620
|
+
severity: z87.enum(["p0", "p1", "p2", "p3"]).optional(),
|
|
28621
|
+
limit: z87.number().int().min(1).max(100).default(25)
|
|
28020
28622
|
}
|
|
28021
28623
|
},
|
|
28022
28624
|
async ({ status, severity, limit }) => {
|
|
@@ -28035,7 +28637,7 @@ function registerGetBugReport(server) {
|
|
|
28035
28637
|
{
|
|
28036
28638
|
title: "Get Bug Report",
|
|
28037
28639
|
description: "AskExe-internal only: fetch one customer bug report with full markdown payload.",
|
|
28038
|
-
inputSchema: { id:
|
|
28640
|
+
inputSchema: { id: z87.string().min(8) }
|
|
28039
28641
|
},
|
|
28040
28642
|
async ({ id }) => {
|
|
28041
28643
|
const data = await requestJson(`${endpoint()}/${encodeURIComponent(id)}`);
|
|
@@ -28050,12 +28652,12 @@ function registerTriageBugReport(server) {
|
|
|
28050
28652
|
title: "Triage Bug Report",
|
|
28051
28653
|
description: "AskExe-internal only: update bug report status and link task/commit/release metadata.",
|
|
28052
28654
|
inputSchema: {
|
|
28053
|
-
id:
|
|
28655
|
+
id: z87.string().min(8),
|
|
28054
28656
|
status: STATUS.optional(),
|
|
28055
|
-
triage_notes:
|
|
28056
|
-
linked_task_id:
|
|
28057
|
-
linked_commit:
|
|
28058
|
-
fixed_version:
|
|
28657
|
+
triage_notes: z87.string().optional(),
|
|
28658
|
+
linked_task_id: z87.string().optional(),
|
|
28659
|
+
linked_commit: z87.string().optional(),
|
|
28660
|
+
fixed_version: z87.string().optional()
|
|
28059
28661
|
}
|
|
28060
28662
|
},
|
|
28061
28663
|
async ({ id, status, triage_notes, linked_task_id, linked_commit, fixed_version }) => {
|
|
@@ -28072,7 +28674,7 @@ var init_support_inbox = __esm({
|
|
|
28072
28674
|
"src/mcp/tools/support-inbox.ts"() {
|
|
28073
28675
|
"use strict";
|
|
28074
28676
|
DEFAULT_ENDPOINT = "https://askexe.com/admin/support/bug-reports";
|
|
28075
|
-
STATUS =
|
|
28677
|
+
STATUS = z87.enum(["open", "triaged", "fixed", "closed", "wontfix"]);
|
|
28076
28678
|
}
|
|
28077
28679
|
});
|
|
28078
28680
|
|
|
@@ -28213,6 +28815,7 @@ var init_tool_gates = __esm({
|
|
|
28213
28815
|
registerRunMemoryAudit: "admin",
|
|
28214
28816
|
registerRunConsolidation: "admin",
|
|
28215
28817
|
registerCloudSync: "admin",
|
|
28818
|
+
registerOrchestrationPhase: "admin",
|
|
28216
28819
|
registerSetAgentConfig: "admin",
|
|
28217
28820
|
registerListEmployees: "admin",
|
|
28218
28821
|
registerGetAgentSpend: "admin",
|
|
@@ -28421,6 +29024,7 @@ function registerAllTools(server) {
|
|
|
28421
29024
|
gate("registerRunMemoryAudit", registerRunMemoryAudit);
|
|
28422
29025
|
gate("registerCloudSync", registerCloudSync);
|
|
28423
29026
|
gate("registerBackupVps", registerBackupVps);
|
|
29027
|
+
gate("registerOrchestrationPhase", registerOrchestrationPhase);
|
|
28424
29028
|
}
|
|
28425
29029
|
if (exposeLegacyMemory) {
|
|
28426
29030
|
gate("registerGetMemoryCardinality", registerGetMemoryCardinality);
|
|
@@ -28532,6 +29136,7 @@ var init_register_tools = __esm({
|
|
|
28532
29136
|
init_raw_data();
|
|
28533
29137
|
init_set_agent_config();
|
|
28534
29138
|
init_list_employees();
|
|
29139
|
+
init_orchestration_phase2();
|
|
28535
29140
|
init_create_license();
|
|
28536
29141
|
init_list_licenses();
|
|
28537
29142
|
init_activate_license();
|
|
@@ -28762,12 +29367,12 @@ __export(task_enforcement_exports, {
|
|
|
28762
29367
|
runTaskEnforcementTick: () => runTaskEnforcementTick,
|
|
28763
29368
|
sendNudge: () => sendNudge
|
|
28764
29369
|
});
|
|
28765
|
-
import { writeFileSync as
|
|
28766
|
-
import
|
|
29370
|
+
import { writeFileSync as writeFileSync23 } from "fs";
|
|
29371
|
+
import path52 from "path";
|
|
28767
29372
|
function writeAuditEntry(entry) {
|
|
28768
29373
|
try {
|
|
28769
29374
|
const line = JSON.stringify(entry) + "\n";
|
|
28770
|
-
|
|
29375
|
+
writeFileSync23(AUDIT_LOG_PATH, line, { flag: "a" });
|
|
28771
29376
|
} catch {
|
|
28772
29377
|
}
|
|
28773
29378
|
}
|
|
@@ -28938,7 +29543,7 @@ var init_task_enforcement = __esm({
|
|
|
28938
29543
|
"What do you need?"
|
|
28939
29544
|
];
|
|
28940
29545
|
MANAGER_ROLES = ["COO", "CTO"];
|
|
28941
|
-
AUDIT_LOG_PATH =
|
|
29546
|
+
AUDIT_LOG_PATH = path52.join(
|
|
28942
29547
|
process.env.HOME ?? process.env.USERPROFILE ?? "/tmp",
|
|
28943
29548
|
".exe-os",
|
|
28944
29549
|
"enforcement-audit.jsonl"
|
|
@@ -28955,11 +29560,11 @@ __export(update_check_exports, {
|
|
|
28955
29560
|
getRemoteVersion: () => getRemoteVersion
|
|
28956
29561
|
});
|
|
28957
29562
|
import { execSync as execSync15 } from "child_process";
|
|
28958
|
-
import { readFileSync as
|
|
28959
|
-
import
|
|
29563
|
+
import { readFileSync as readFileSync33 } from "fs";
|
|
29564
|
+
import path53 from "path";
|
|
28960
29565
|
function getLocalVersion(packageRoot) {
|
|
28961
|
-
const pkgPath =
|
|
28962
|
-
const pkg = JSON.parse(
|
|
29566
|
+
const pkgPath = path53.join(packageRoot, "package.json");
|
|
29567
|
+
const pkg = JSON.parse(readFileSync33(pkgPath, "utf-8"));
|
|
28963
29568
|
return pkg.version;
|
|
28964
29569
|
}
|
|
28965
29570
|
function getRemoteVersion() {
|
|
@@ -29031,12 +29636,12 @@ __export(device_registry_exports, {
|
|
|
29031
29636
|
});
|
|
29032
29637
|
import crypto21 from "crypto";
|
|
29033
29638
|
import os22 from "os";
|
|
29034
|
-
import { readFileSync as
|
|
29035
|
-
import
|
|
29639
|
+
import { readFileSync as readFileSync34, writeFileSync as writeFileSync24, mkdirSync as mkdirSync20, existsSync as existsSync41 } from "fs";
|
|
29640
|
+
import path54 from "path";
|
|
29036
29641
|
function getDeviceInfo() {
|
|
29037
|
-
if (
|
|
29642
|
+
if (existsSync41(DEVICE_JSON_PATH)) {
|
|
29038
29643
|
try {
|
|
29039
|
-
const raw =
|
|
29644
|
+
const raw = readFileSync34(DEVICE_JSON_PATH, "utf8");
|
|
29040
29645
|
const data = JSON.parse(raw);
|
|
29041
29646
|
if (data.deviceId && data.friendlyName && data.hostname) {
|
|
29042
29647
|
return data;
|
|
@@ -29050,14 +29655,14 @@ function getDeviceInfo() {
|
|
|
29050
29655
|
friendlyName: hostname.replace(/\./g, "-").toLowerCase(),
|
|
29051
29656
|
hostname
|
|
29052
29657
|
};
|
|
29053
|
-
|
|
29054
|
-
|
|
29658
|
+
mkdirSync20(path54.dirname(DEVICE_JSON_PATH), { recursive: true });
|
|
29659
|
+
writeFileSync24(DEVICE_JSON_PATH, JSON.stringify(info, null, 2));
|
|
29055
29660
|
return info;
|
|
29056
29661
|
}
|
|
29057
29662
|
function setFriendlyName(name) {
|
|
29058
29663
|
const info = getDeviceInfo();
|
|
29059
29664
|
info.friendlyName = name;
|
|
29060
|
-
|
|
29665
|
+
writeFileSync24(DEVICE_JSON_PATH, JSON.stringify(info, null, 2));
|
|
29061
29666
|
}
|
|
29062
29667
|
async function resolveTargetDevice(targetAgent, targetProject) {
|
|
29063
29668
|
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
@@ -29091,7 +29696,7 @@ var init_device_registry = __esm({
|
|
|
29091
29696
|
"src/lib/device-registry.ts"() {
|
|
29092
29697
|
"use strict";
|
|
29093
29698
|
init_config();
|
|
29094
|
-
DEVICE_JSON_PATH =
|
|
29699
|
+
DEVICE_JSON_PATH = path54.join(EXE_AI_DIR, "device.json");
|
|
29095
29700
|
}
|
|
29096
29701
|
});
|
|
29097
29702
|
|
|
@@ -29307,8 +29912,8 @@ import os23 from "os";
|
|
|
29307
29912
|
import net2 from "net";
|
|
29308
29913
|
import { createServer as createHttpServer } from "http";
|
|
29309
29914
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
29310
|
-
import { writeFileSync as
|
|
29311
|
-
import
|
|
29915
|
+
import { writeFileSync as writeFileSync25, unlinkSync as unlinkSync13, mkdirSync as mkdirSync21, existsSync as existsSync42, readFileSync as readFileSync35, chmodSync as chmodSync2 } from "fs";
|
|
29916
|
+
import path55 from "path";
|
|
29312
29917
|
|
|
29313
29918
|
// src/lib/orchestration-metrics.ts
|
|
29314
29919
|
init_config();
|
|
@@ -29380,8 +29985,8 @@ function initMetrics() {
|
|
|
29380
29985
|
|
|
29381
29986
|
// src/lib/exe-daemon.ts
|
|
29382
29987
|
init_memory_write_governor();
|
|
29383
|
-
var SOCKET_PATH2 = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
29384
|
-
var PID_PATH3 = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
29988
|
+
var SOCKET_PATH2 = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path55.join(EXE_AI_DIR, "exed.sock");
|
|
29989
|
+
var PID_PATH3 = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path55.join(EXE_AI_DIR, "exed.pid");
|
|
29385
29990
|
var MODEL_FILE = "jina-embeddings-v5-small-q4_k_m.gguf";
|
|
29386
29991
|
var IDLE_TIMEOUT_MS2 = 15 * 60 * 1e3;
|
|
29387
29992
|
var REVIEW_POLL_INTERVAL_MS = 60 * 1e3;
|
|
@@ -29409,8 +30014,8 @@ function enqueue(queue, entry) {
|
|
|
29409
30014
|
queue.push(entry);
|
|
29410
30015
|
}
|
|
29411
30016
|
async function loadModel() {
|
|
29412
|
-
const modelPath =
|
|
29413
|
-
if (!
|
|
30017
|
+
const modelPath = path55.join(MODELS_DIR, MODEL_FILE);
|
|
30018
|
+
if (!existsSync42(modelPath)) {
|
|
29414
30019
|
process.stderr.write(`[exed] No model at ${modelPath} \u2014 running without embeddings (VPS mode).
|
|
29415
30020
|
`);
|
|
29416
30021
|
return;
|
|
@@ -29808,17 +30413,17 @@ function startMemoryQueueDrain() {
|
|
|
29808
30413
|
`);
|
|
29809
30414
|
}
|
|
29810
30415
|
function startServer() {
|
|
29811
|
-
|
|
30416
|
+
mkdirSync21(path55.dirname(SOCKET_PATH2), { recursive: true });
|
|
29812
30417
|
try {
|
|
29813
|
-
chmodSync2(
|
|
30418
|
+
chmodSync2(path55.dirname(SOCKET_PATH2), 448);
|
|
29814
30419
|
} catch {
|
|
29815
30420
|
}
|
|
29816
30421
|
_daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV2] ?? null);
|
|
29817
30422
|
for (const oldFile of ["embed.sock", "embed.pid"]) {
|
|
29818
|
-
const oldPath =
|
|
30423
|
+
const oldPath = path55.join(path55.dirname(SOCKET_PATH2), oldFile);
|
|
29819
30424
|
try {
|
|
29820
30425
|
if (oldFile.endsWith(".pid")) {
|
|
29821
|
-
const pid = parseInt(
|
|
30426
|
+
const pid = parseInt(readFileSync35(oldPath, "utf8").trim(), 10);
|
|
29822
30427
|
if (pid > 0) try {
|
|
29823
30428
|
process.kill(pid, "SIGKILL");
|
|
29824
30429
|
} catch {
|
|
@@ -30291,7 +30896,7 @@ function startGraphExtraction() {
|
|
|
30291
30896
|
`);
|
|
30292
30897
|
}
|
|
30293
30898
|
var AGENT_STATS_INTERVAL_MS = 60 * 1e3;
|
|
30294
|
-
var AGENT_STATS_PATH =
|
|
30899
|
+
var AGENT_STATS_PATH = path55.join(EXE_AI_DIR, "agent-stats.json");
|
|
30295
30900
|
async function writeAgentStats() {
|
|
30296
30901
|
fired("agent_stats");
|
|
30297
30902
|
if (!await ensureStoreForPolling()) return;
|
|
@@ -30351,7 +30956,7 @@ async function writeAgentStats() {
|
|
|
30351
30956
|
pid: process.pid
|
|
30352
30957
|
}
|
|
30353
30958
|
};
|
|
30354
|
-
|
|
30959
|
+
writeFileSync25(AGENT_STATS_PATH, JSON.stringify(stats, null, 2), "utf8");
|
|
30355
30960
|
} catch (err) {
|
|
30356
30961
|
process.stderr.write(`[exed] Agent stats error: ${err instanceof Error ? err.message : String(err)}
|
|
30357
30962
|
`);
|
|
@@ -30468,12 +31073,12 @@ function startIntercomQueueDrain() {
|
|
|
30468
31073
|
const hasInProgressTask = (session) => {
|
|
30469
31074
|
try {
|
|
30470
31075
|
const { baseAgentName: ban } = (init_employees(), __toCommonJS(employees_exports));
|
|
30471
|
-
const
|
|
30472
|
-
const { existsSync:
|
|
31076
|
+
const path56 = __require("path");
|
|
31077
|
+
const { existsSync: existsSync43 } = __require("fs");
|
|
30473
31078
|
const os24 = __require("os");
|
|
30474
31079
|
const agent = ban(session.split("-")[0] ?? session);
|
|
30475
|
-
const markerPath =
|
|
30476
|
-
return
|
|
31080
|
+
const markerPath = path56.join(os24.homedir(), ".exe-os", "session-cache", `current-task-${agent}.json`);
|
|
31081
|
+
return existsSync43(markerPath);
|
|
30477
31082
|
} catch {
|
|
30478
31083
|
return false;
|
|
30479
31084
|
}
|
|
@@ -30637,8 +31242,8 @@ process.on("SIGINT", () => void shutdown());
|
|
|
30637
31242
|
process.on("SIGTERM", () => void shutdown());
|
|
30638
31243
|
function checkExistingDaemon() {
|
|
30639
31244
|
try {
|
|
30640
|
-
if (!
|
|
30641
|
-
const pid = parseInt(
|
|
31245
|
+
if (!existsSync42(PID_PATH3)) return false;
|
|
31246
|
+
const pid = parseInt(readFileSync35(PID_PATH3, "utf8").trim(), 10);
|
|
30642
31247
|
if (!pid || isNaN(pid)) return false;
|
|
30643
31248
|
process.kill(pid, 0);
|
|
30644
31249
|
process.stderr.write(`[exed] Another daemon is already running (PID ${pid}). Exiting.
|
|
@@ -30708,7 +31313,7 @@ function startAutoUpdateCheck() {
|
|
|
30708
31313
|
if (checkExistingDaemon()) {
|
|
30709
31314
|
process.exit(0);
|
|
30710
31315
|
}
|
|
30711
|
-
|
|
31316
|
+
writeFileSync25(PID_PATH3, String(process.pid));
|
|
30712
31317
|
try {
|
|
30713
31318
|
chmodSync2(PID_PATH3, 384);
|
|
30714
31319
|
} catch {
|