@askexenow/exe-os 0.9.64 → 0.9.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deploy/stack-manifests/v0.9.json +4 -4
- package/dist/bin/backfill-conversations.js +22 -0
- package/dist/bin/backfill-responses.js +22 -0
- package/dist/bin/backfill-vectors.js +22 -0
- package/dist/bin/cleanup-stale-review-tasks.js +22 -0
- package/dist/bin/cli.js +2280 -1199
- package/dist/bin/exe-agent-config.js +4 -0
- package/dist/bin/exe-agent.js +16 -0
- package/dist/bin/exe-assign.js +22 -0
- package/dist/bin/exe-boot.js +116 -7
- package/dist/bin/exe-call.js +16 -0
- package/dist/bin/exe-cloud.js +6671 -464
- package/dist/bin/exe-dispatch.js +24 -0
- package/dist/bin/exe-doctor.js +2845 -1223
- package/dist/bin/exe-export-behaviors.js +24 -0
- package/dist/bin/exe-forget.js +22 -0
- package/dist/bin/exe-gateway.js +24 -0
- package/dist/bin/exe-heartbeat.js +23 -0
- package/dist/bin/exe-kill.js +22 -0
- package/dist/bin/exe-launch-agent.js +24 -0
- package/dist/bin/exe-link.js +310 -178
- package/dist/bin/exe-new-employee.js +127 -1
- package/dist/bin/exe-pending-messages.js +22 -0
- package/dist/bin/exe-pending-notifications.js +22 -0
- package/dist/bin/exe-pending-reviews.js +22 -0
- package/dist/bin/exe-rename.js +22 -0
- package/dist/bin/exe-review.js +22 -0
- package/dist/bin/exe-search.js +24 -0
- package/dist/bin/exe-session-cleanup.js +24 -0
- package/dist/bin/exe-settings.js +10 -0
- package/dist/bin/exe-start-codex.js +135 -1
- package/dist/bin/exe-start-opencode.js +149 -1
- package/dist/bin/exe-status.js +22 -0
- package/dist/bin/exe-team.js +22 -0
- package/dist/bin/git-sweep.js +24 -0
- package/dist/bin/graph-backfill.js +22 -0
- package/dist/bin/graph-export.js +22 -0
- package/dist/bin/install.js +115 -1
- package/dist/bin/intercom-check.js +24 -0
- package/dist/bin/scan-tasks.js +24 -0
- package/dist/bin/setup.js +412 -157
- package/dist/bin/shard-migrate.js +22 -0
- package/dist/bin/update.js +4 -0
- package/dist/gateway/index.js +24 -0
- package/dist/hooks/bug-report-worker.js +135 -42
- package/dist/hooks/codex-stop-task-finalizer.js +24 -0
- package/dist/hooks/commit-complete.js +24 -0
- package/dist/hooks/error-recall.js +24 -0
- package/dist/hooks/exe-heartbeat-hook.js +4 -0
- package/dist/hooks/ingest-worker.js +4 -0
- package/dist/hooks/ingest.js +23 -0
- package/dist/hooks/instructions-loaded.js +22 -0
- package/dist/hooks/notification.js +22 -0
- package/dist/hooks/post-compact.js +22 -0
- package/dist/hooks/post-tool-combined.js +24 -0
- package/dist/hooks/pre-compact.js +260 -109
- package/dist/hooks/pre-tool-use.js +22 -0
- package/dist/hooks/prompt-submit.js +24 -0
- package/dist/hooks/session-end.js +161 -122
- package/dist/hooks/session-start.js +142 -0
- package/dist/hooks/stop.js +23 -0
- package/dist/hooks/subagent-stop.js +22 -0
- package/dist/hooks/summary-worker.js +195 -79
- package/dist/index.js +24 -0
- package/dist/lib/agent-config.js +4 -0
- package/dist/lib/cloud-sync.js +50 -6
- package/dist/lib/config.js +12 -0
- package/dist/lib/consolidation.js +4 -0
- package/dist/lib/database.js +4 -0
- package/dist/lib/db-daemon-client.js +4 -0
- package/dist/lib/db.js +4 -0
- package/dist/lib/device-registry.js +4 -0
- package/dist/lib/embedder.js +12 -0
- package/dist/lib/employee-templates.js +16 -0
- package/dist/lib/employees.js +4 -0
- package/dist/lib/exe-daemon-client.js +4 -0
- package/dist/lib/exe-daemon.js +1144 -480
- package/dist/lib/hybrid-search.js +24 -0
- package/dist/lib/identity.js +4 -0
- package/dist/lib/license.js +4 -0
- package/dist/lib/messaging.js +4 -0
- package/dist/lib/reminders.js +4 -0
- package/dist/lib/schedules.js +22 -0
- package/dist/lib/skill-learning.js +12 -0
- package/dist/lib/status-brief.js +39 -0
- package/dist/lib/store.js +22 -0
- package/dist/lib/task-router.js +4 -0
- package/dist/lib/tasks.js +12 -0
- package/dist/lib/tmux-routing.js +12 -0
- package/dist/lib/token-spend.js +4 -0
- package/dist/mcp/server.js +1045 -427
- package/dist/mcp/tools/complete-reminder.js +4 -0
- package/dist/mcp/tools/create-reminder.js +4 -0
- package/dist/mcp/tools/create-task.js +12 -0
- package/dist/mcp/tools/deactivate-behavior.js +4 -0
- package/dist/mcp/tools/list-reminders.js +4 -0
- package/dist/mcp/tools/list-tasks.js +4 -0
- package/dist/mcp/tools/send-message.js +4 -0
- package/dist/mcp/tools/update-task.js +12 -0
- package/dist/runtime/index.js +24 -0
- package/dist/tui/App.js +24 -0
- package/package.json +3 -2
- package/src/commands/exe/cloud.md +15 -8
- package/src/commands/exe/link.md +7 -6
- package/stack.release.json +2 -2
package/dist/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
|
}
|
|
@@ -3498,10 +3522,12 @@ var init_memory_write_governor = __esm({
|
|
|
3498
3522
|
// src/lib/projection-worker.ts
|
|
3499
3523
|
var projection_worker_exports = {};
|
|
3500
3524
|
__export(projection_worker_exports, {
|
|
3525
|
+
computeProjectionBackoffMs: () => computeProjectionBackoffMs,
|
|
3501
3526
|
processProjectionBatch: () => processProjectionBatch,
|
|
3502
3527
|
projectionHandlersForTests: () => projectionHandlersForTests,
|
|
3503
3528
|
resetProjectionWorkerForTests: () => resetProjectionWorkerForTests,
|
|
3504
3529
|
setProjectionWorkerPrismaClientForTests: () => setProjectionWorkerPrismaClientForTests,
|
|
3530
|
+
shouldStartProjectionWorker: () => shouldStartProjectionWorker,
|
|
3505
3531
|
startProjectionWorker: () => startProjectionWorker,
|
|
3506
3532
|
stopProjectionWorker: () => stopProjectionWorker
|
|
3507
3533
|
});
|
|
@@ -3540,8 +3566,12 @@ function resetProjectionWorkerForTests() {
|
|
|
3540
3566
|
clearTimeout(pollTimer);
|
|
3541
3567
|
pollTimer = null;
|
|
3542
3568
|
}
|
|
3569
|
+
consecutivePollErrors = 0;
|
|
3543
3570
|
prismaPromise = null;
|
|
3544
3571
|
}
|
|
3572
|
+
function isTruthyEnv(value) {
|
|
3573
|
+
return /^(1|true|yes|on)$/i.test(value ?? "");
|
|
3574
|
+
}
|
|
3545
3575
|
async function processBatch() {
|
|
3546
3576
|
const prisma = await loadPrisma();
|
|
3547
3577
|
const events = await prisma.$queryRawUnsafe(
|
|
@@ -3583,36 +3613,65 @@ async function processBatch() {
|
|
|
3583
3613
|
}
|
|
3584
3614
|
return processed;
|
|
3585
3615
|
}
|
|
3616
|
+
async function shouldStartProjectionWorker() {
|
|
3617
|
+
try {
|
|
3618
|
+
const config2 = await loadConfig();
|
|
3619
|
+
const envEnabled = isTruthyEnv(process.env.EXE_CLOUD_SYNC_TO_POSTGRES);
|
|
3620
|
+
if (!envEnabled && config2.cloud?.syncToPostgres !== true) {
|
|
3621
|
+
return { start: false, reason: "cloud.syncToPostgres is not enabled" };
|
|
3622
|
+
}
|
|
3623
|
+
} catch (err) {
|
|
3624
|
+
return { start: false, reason: `config unavailable: ${err instanceof Error ? err.message : String(err)}` };
|
|
3625
|
+
}
|
|
3626
|
+
if (!process.env.DATABASE_URL) {
|
|
3627
|
+
return { start: false, reason: "DATABASE_URL is not set" };
|
|
3628
|
+
}
|
|
3629
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path8.join(os5.homedir(), "exe-db");
|
|
3630
|
+
if (!existsSync8(path8.join(exeDbRoot, "package.json")) && !process.env.EXE_OS_PRISMA_CLIENT_PATH) {
|
|
3631
|
+
return { start: false, reason: "exe-db Prisma client not found" };
|
|
3632
|
+
}
|
|
3633
|
+
return { start: true };
|
|
3634
|
+
}
|
|
3635
|
+
function computeProjectionBackoffMs(errorCount) {
|
|
3636
|
+
if (errorCount <= 0) return POLL_INTERVAL_MS;
|
|
3637
|
+
return Math.min(POLL_INTERVAL_MS * 2 ** Math.min(errorCount, 5), MAX_POLL_BACKOFF_MS);
|
|
3638
|
+
}
|
|
3586
3639
|
function startProjectionWorker() {
|
|
3587
3640
|
if (running) return;
|
|
3588
|
-
|
|
3589
|
-
const
|
|
3590
|
-
if (!
|
|
3591
|
-
process.stderr.write(
|
|
3641
|
+
void (async () => {
|
|
3642
|
+
const decision = await shouldStartProjectionWorker();
|
|
3643
|
+
if (!decision.start) {
|
|
3644
|
+
process.stderr.write(`[projection-worker] Skipped \u2014 ${decision.reason}.
|
|
3645
|
+
`);
|
|
3592
3646
|
return;
|
|
3593
3647
|
}
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3648
|
+
running = true;
|
|
3649
|
+
consecutivePollErrors = 0;
|
|
3650
|
+
process.stderr.write("[projection-worker] Starting...\n");
|
|
3651
|
+
const tick = async () => {
|
|
3652
|
+
if (!running) return;
|
|
3653
|
+
let nextDelay = POLL_INTERVAL_MS;
|
|
3654
|
+
try {
|
|
3655
|
+
const count = await processBatch();
|
|
3656
|
+
consecutivePollErrors = 0;
|
|
3657
|
+
if (count > 0) {
|
|
3658
|
+
process.stderr.write(`[projection-worker] Processed ${count} events.
|
|
3603
3659
|
`);
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3660
|
+
}
|
|
3661
|
+
} catch (err) {
|
|
3662
|
+
consecutivePollErrors++;
|
|
3663
|
+
nextDelay = computeProjectionBackoffMs(consecutivePollErrors);
|
|
3664
|
+
process.stderr.write(
|
|
3665
|
+
`[projection-worker] Poll error (${consecutivePollErrors}; next retry ${Math.round(nextDelay / 1e3)}s): ${err instanceof Error ? err.message : String(err)}
|
|
3608
3666
|
`
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3667
|
+
);
|
|
3668
|
+
}
|
|
3669
|
+
if (running) {
|
|
3670
|
+
pollTimer = setTimeout(tick, nextDelay);
|
|
3671
|
+
}
|
|
3672
|
+
};
|
|
3673
|
+
void tick();
|
|
3674
|
+
})();
|
|
3616
3675
|
}
|
|
3617
3676
|
function stopProjectionWorker() {
|
|
3618
3677
|
running = false;
|
|
@@ -3625,10 +3684,11 @@ function stopProjectionWorker() {
|
|
|
3625
3684
|
async function processProjectionBatch() {
|
|
3626
3685
|
return processBatch();
|
|
3627
3686
|
}
|
|
3628
|
-
var prismaPromise, projectionHandlers, projectionHandlersForTests, defaultHandler, BATCH_SIZE, POLL_INTERVAL_MS, running, pollTimer;
|
|
3687
|
+
var prismaPromise, projectionHandlers, projectionHandlersForTests, defaultHandler, BATCH_SIZE, POLL_INTERVAL_MS, MAX_POLL_BACKOFF_MS, running, pollTimer, consecutivePollErrors;
|
|
3629
3688
|
var init_projection_worker = __esm({
|
|
3630
3689
|
"src/lib/projection-worker.ts"() {
|
|
3631
3690
|
"use strict";
|
|
3691
|
+
init_config();
|
|
3632
3692
|
prismaPromise = null;
|
|
3633
3693
|
projectionHandlers = {
|
|
3634
3694
|
async whatsapp(event, prisma) {
|
|
@@ -3739,8 +3799,10 @@ var init_projection_worker = __esm({
|
|
|
3739
3799
|
};
|
|
3740
3800
|
BATCH_SIZE = 50;
|
|
3741
3801
|
POLL_INTERVAL_MS = 1e4;
|
|
3802
|
+
MAX_POLL_BACKOFF_MS = 5 * 6e4;
|
|
3742
3803
|
running = false;
|
|
3743
3804
|
pollTimer = null;
|
|
3805
|
+
consecutivePollErrors = 0;
|
|
3744
3806
|
}
|
|
3745
3807
|
});
|
|
3746
3808
|
|
|
@@ -4281,8 +4343,8 @@ function deriveMachineKey() {
|
|
|
4281
4343
|
}
|
|
4282
4344
|
function readMachineId() {
|
|
4283
4345
|
try {
|
|
4284
|
-
const { readFileSync:
|
|
4285
|
-
return
|
|
4346
|
+
const { readFileSync: readFileSync36 } = __require("fs");
|
|
4347
|
+
return readFileSync36("/etc/machine-id", "utf-8").trim();
|
|
4286
4348
|
} catch {
|
|
4287
4349
|
return "";
|
|
4288
4350
|
}
|
|
@@ -4573,6 +4635,12 @@ var init_platform_procedures = __esm({
|
|
|
4573
4635
|
priority: "p0",
|
|
4574
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."
|
|
4575
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
|
+
},
|
|
4576
4644
|
{
|
|
4577
4645
|
title: "Single dispatch path \u2014 create_task only",
|
|
4578
4646
|
domain: "workflow",
|
|
@@ -4631,6 +4699,12 @@ var init_platform_procedures = __esm({
|
|
|
4631
4699
|
priority: "p0",
|
|
4632
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."
|
|
4633
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
|
+
},
|
|
4634
4708
|
{
|
|
4635
4709
|
title: "Desktop and TUI are the same product",
|
|
4636
4710
|
domain: "architecture",
|
|
@@ -5968,10 +6042,10 @@ async function disposeEmbedder() {
|
|
|
5968
6042
|
async function embedDirect(text3) {
|
|
5969
6043
|
const llamaCpp = await import("node-llama-cpp");
|
|
5970
6044
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
5971
|
-
const { existsSync:
|
|
5972
|
-
const
|
|
5973
|
-
const modelPath =
|
|
5974
|
-
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)) {
|
|
5975
6049
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
5976
6050
|
}
|
|
5977
6051
|
const llama = await llamaCpp.getLlama();
|
|
@@ -7062,10 +7136,10 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
7062
7136
|
};
|
|
7063
7137
|
try {
|
|
7064
7138
|
const fs = await import("fs");
|
|
7065
|
-
const
|
|
7139
|
+
const path56 = await import("path");
|
|
7066
7140
|
const os24 = await import("os");
|
|
7067
|
-
const logPath =
|
|
7068
|
-
fs.mkdirSync(
|
|
7141
|
+
const logPath = path56.join(os24.homedir(), ".exe-os", "search-quality.jsonl");
|
|
7142
|
+
fs.mkdirSync(path56.dirname(logPath), { recursive: true });
|
|
7069
7143
|
fs.appendFileSync(logPath, JSON.stringify(logEntry) + "\n");
|
|
7070
7144
|
} catch {
|
|
7071
7145
|
}
|
|
@@ -8698,8 +8772,8 @@ __export(wiki_client_exports, {
|
|
|
8698
8772
|
listDocuments: () => listDocuments,
|
|
8699
8773
|
listWorkspaces: () => listWorkspaces
|
|
8700
8774
|
});
|
|
8701
|
-
async function wikiFetch(config2,
|
|
8702
|
-
const url = `${config2.baseUrl}/api/v1${
|
|
8775
|
+
async function wikiFetch(config2, path56, method = "GET", body) {
|
|
8776
|
+
const url = `${config2.baseUrl}/api/v1${path56}`;
|
|
8703
8777
|
const headers = {
|
|
8704
8778
|
Authorization: `Bearer ${config2.apiKey}`,
|
|
8705
8779
|
"Content-Type": "application/json"
|
|
@@ -8732,7 +8806,7 @@ async function wikiFetch(config2, path55, method = "GET", body) {
|
|
|
8732
8806
|
}
|
|
8733
8807
|
}
|
|
8734
8808
|
if (!response.ok) {
|
|
8735
|
-
throw new Error(`Wiki API ${method} ${
|
|
8809
|
+
throw new Error(`Wiki API ${method} ${path56}: ${response.status} ${response.statusText}`);
|
|
8736
8810
|
}
|
|
8737
8811
|
return response.json();
|
|
8738
8812
|
} finally {
|
|
@@ -14310,10 +14384,10 @@ function registerCreateTask(server) {
|
|
|
14310
14384
|
skipDispatch: true
|
|
14311
14385
|
});
|
|
14312
14386
|
try {
|
|
14313
|
-
const { existsSync:
|
|
14387
|
+
const { existsSync: existsSync43, mkdirSync: mkdirSync22, writeFileSync: writeFileSync26 } = await import("fs");
|
|
14314
14388
|
const { identityPath: identityPath2 } = await Promise.resolve().then(() => (init_identity(), identity_exports));
|
|
14315
14389
|
const idPath = identityPath2(assigned_to);
|
|
14316
|
-
if (!
|
|
14390
|
+
if (!existsSync43(idPath)) {
|
|
14317
14391
|
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
14318
14392
|
const employees = await loadEmployees2();
|
|
14319
14393
|
const emp = employees.find((e) => e.name === assigned_to);
|
|
@@ -14322,8 +14396,8 @@ function registerCreateTask(server) {
|
|
|
14322
14396
|
const template = getTemplateForTitle2(emp.role);
|
|
14323
14397
|
if (template) {
|
|
14324
14398
|
const dir = (await import("path")).dirname(idPath);
|
|
14325
|
-
if (!
|
|
14326
|
-
|
|
14399
|
+
if (!existsSync43(dir)) mkdirSync22(dir, { recursive: true });
|
|
14400
|
+
writeFileSync26(idPath, template.replace(/^agent_id: \w+/m, `agent_id: ${assigned_to}`), "utf-8");
|
|
14327
14401
|
}
|
|
14328
14402
|
}
|
|
14329
14403
|
}
|
|
@@ -17807,12 +17881,12 @@ function registerExportGraph(server) {
|
|
|
17807
17881
|
}
|
|
17808
17882
|
const html = await exportGraphHTML(client);
|
|
17809
17883
|
const fs = await import("fs");
|
|
17810
|
-
const
|
|
17884
|
+
const path56 = await import("path");
|
|
17811
17885
|
const os24 = await import("os");
|
|
17812
|
-
const outDir =
|
|
17886
|
+
const outDir = path56.join(os24.homedir(), ".exe-os", "exports");
|
|
17813
17887
|
fs.mkdirSync(outDir, { recursive: true });
|
|
17814
17888
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
17815
|
-
const filePath =
|
|
17889
|
+
const filePath = path56.join(outDir, `graph-${timestamp}.html`);
|
|
17816
17890
|
fs.writeFileSync(filePath, html, "utf-8");
|
|
17817
17891
|
return {
|
|
17818
17892
|
content: [
|
|
@@ -20991,6 +21065,259 @@ var init_conflict_detector = __esm({
|
|
|
20991
21065
|
}
|
|
20992
21066
|
});
|
|
20993
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
|
+
|
|
20994
21321
|
// src/lib/db-backup.ts
|
|
20995
21322
|
var db_backup_exports = {};
|
|
20996
21323
|
__export(db_backup_exports, {
|
|
@@ -21002,33 +21329,33 @@ __export(db_backup_exports, {
|
|
|
21002
21329
|
listBackups: () => listBackups,
|
|
21003
21330
|
rotateBackups: () => rotateBackups
|
|
21004
21331
|
});
|
|
21005
|
-
import { copyFileSync, existsSync as
|
|
21006
|
-
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";
|
|
21007
21334
|
function findActiveDb() {
|
|
21008
21335
|
for (const name of DB_NAMES) {
|
|
21009
|
-
const p =
|
|
21010
|
-
if (
|
|
21336
|
+
const p = path36.join(EXE_AI_DIR, name);
|
|
21337
|
+
if (existsSync31(p)) return p;
|
|
21011
21338
|
}
|
|
21012
21339
|
return null;
|
|
21013
21340
|
}
|
|
21014
21341
|
function createBackup(reason = "manual") {
|
|
21015
21342
|
const dbPath = findActiveDb();
|
|
21016
21343
|
if (!dbPath) return null;
|
|
21017
|
-
|
|
21018
|
-
const dbName =
|
|
21344
|
+
mkdirSync13(BACKUP_DIR, { recursive: true });
|
|
21345
|
+
const dbName = path36.basename(dbPath, ".db");
|
|
21019
21346
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
21020
21347
|
const backupName = `${dbName}-${reason}-${timestamp}.db`;
|
|
21021
|
-
const backupPath =
|
|
21348
|
+
const backupPath = path36.join(BACKUP_DIR, backupName);
|
|
21022
21349
|
copyFileSync(dbPath, backupPath);
|
|
21023
21350
|
const walPath = dbPath + "-wal";
|
|
21024
|
-
if (
|
|
21351
|
+
if (existsSync31(walPath)) {
|
|
21025
21352
|
try {
|
|
21026
21353
|
copyFileSync(walPath, backupPath + "-wal");
|
|
21027
21354
|
} catch {
|
|
21028
21355
|
}
|
|
21029
21356
|
}
|
|
21030
21357
|
const shmPath = dbPath + "-shm";
|
|
21031
|
-
if (
|
|
21358
|
+
if (existsSync31(shmPath)) {
|
|
21032
21359
|
try {
|
|
21033
21360
|
copyFileSync(shmPath, backupPath + "-shm");
|
|
21034
21361
|
} catch {
|
|
@@ -21037,14 +21364,14 @@ function createBackup(reason = "manual") {
|
|
|
21037
21364
|
return backupPath;
|
|
21038
21365
|
}
|
|
21039
21366
|
function rotateBackups(keepDays = DEFAULT_KEEP_DAYS) {
|
|
21040
|
-
if (!
|
|
21367
|
+
if (!existsSync31(BACKUP_DIR)) return 0;
|
|
21041
21368
|
const cutoff = Date.now() - keepDays * 24 * 60 * 60 * 1e3;
|
|
21042
21369
|
let deleted = 0;
|
|
21043
21370
|
try {
|
|
21044
21371
|
const files = readdirSync10(BACKUP_DIR);
|
|
21045
21372
|
for (const file of files) {
|
|
21046
21373
|
if (!file.endsWith(".db") && !file.endsWith(".db-wal") && !file.endsWith(".db-shm")) continue;
|
|
21047
|
-
const filePath =
|
|
21374
|
+
const filePath = path36.join(BACKUP_DIR, file);
|
|
21048
21375
|
try {
|
|
21049
21376
|
const stat = statSync5(filePath);
|
|
21050
21377
|
if (stat.mtimeMs < cutoff) {
|
|
@@ -21059,11 +21386,11 @@ function rotateBackups(keepDays = DEFAULT_KEEP_DAYS) {
|
|
|
21059
21386
|
return deleted;
|
|
21060
21387
|
}
|
|
21061
21388
|
function listBackups() {
|
|
21062
|
-
if (!
|
|
21389
|
+
if (!existsSync31(BACKUP_DIR)) return [];
|
|
21063
21390
|
try {
|
|
21064
21391
|
const files = readdirSync10(BACKUP_DIR).filter((f) => f.endsWith(".db") && !f.endsWith("-wal") && !f.endsWith("-shm"));
|
|
21065
21392
|
return files.map((name) => {
|
|
21066
|
-
const p =
|
|
21393
|
+
const p = path36.join(BACKUP_DIR, name);
|
|
21067
21394
|
const stat = statSync5(p);
|
|
21068
21395
|
return { path: p, name, size: stat.size, date: stat.mtime };
|
|
21069
21396
|
}).sort((a, b) => b.date.getTime() - a.date.getTime());
|
|
@@ -21088,7 +21415,7 @@ var init_db_backup = __esm({
|
|
|
21088
21415
|
"src/lib/db-backup.ts"() {
|
|
21089
21416
|
"use strict";
|
|
21090
21417
|
init_config();
|
|
21091
|
-
BACKUP_DIR =
|
|
21418
|
+
BACKUP_DIR = path36.join(EXE_AI_DIR, "backups");
|
|
21092
21419
|
DEFAULT_KEEP_DAYS = 3;
|
|
21093
21420
|
DB_NAMES = ["memories.db", "exe-mem.db", "exe-os.db", "exe.db"];
|
|
21094
21421
|
}
|
|
@@ -21096,9 +21423,9 @@ var init_db_backup = __esm({
|
|
|
21096
21423
|
|
|
21097
21424
|
// src/bin/exe-doctor.ts
|
|
21098
21425
|
import os16 from "os";
|
|
21099
|
-
import { existsSync as
|
|
21426
|
+
import { existsSync as existsSync32, readFileSync as readFileSync24 } from "fs";
|
|
21100
21427
|
import { spawn as spawn2 } from "child_process";
|
|
21101
|
-
import
|
|
21428
|
+
import path37 from "path";
|
|
21102
21429
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
21103
21430
|
function parseFlags(argv) {
|
|
21104
21431
|
const flags = { fix: false, dryRun: false, verbose: false, conflicts: false };
|
|
@@ -21250,7 +21577,7 @@ async function auditOrphanedProjects(client) {
|
|
|
21250
21577
|
for (const row of result.rows) {
|
|
21251
21578
|
const name = row.project_name;
|
|
21252
21579
|
const count = Number(row.cnt);
|
|
21253
|
-
const exists =
|
|
21580
|
+
const exists = existsSync32(path37.join(home, name)) || existsSync32(path37.join(home, "..", name)) || existsSync32(path37.join(process.cwd(), "..", name));
|
|
21254
21581
|
if (!exists) {
|
|
21255
21582
|
orphans.push({ project_name: name, count });
|
|
21256
21583
|
}
|
|
@@ -21258,18 +21585,18 @@ async function auditOrphanedProjects(client) {
|
|
|
21258
21585
|
return orphans;
|
|
21259
21586
|
}
|
|
21260
21587
|
function auditHookHealth() {
|
|
21261
|
-
const logPath =
|
|
21588
|
+
const logPath = path37.join(
|
|
21262
21589
|
process.env.HOME ?? process.env.USERPROFILE ?? "",
|
|
21263
21590
|
".exe-os",
|
|
21264
21591
|
"logs",
|
|
21265
21592
|
"hooks.log"
|
|
21266
21593
|
);
|
|
21267
|
-
if (!
|
|
21594
|
+
if (!existsSync32(logPath)) {
|
|
21268
21595
|
return { logExists: false, totalLines: 0, errorsLastHour: 0, topPatterns: [] };
|
|
21269
21596
|
}
|
|
21270
21597
|
let content;
|
|
21271
21598
|
try {
|
|
21272
|
-
content =
|
|
21599
|
+
content = readFileSync24(logPath, "utf-8");
|
|
21273
21600
|
} catch {
|
|
21274
21601
|
return { logExists: false, totalLines: 0, errorsLastHour: 0, topPatterns: [] };
|
|
21275
21602
|
}
|
|
@@ -21297,6 +21624,121 @@ function auditHookHealth() {
|
|
|
21297
21624
|
const topPatterns = [...patternCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([pattern, count]) => ({ pattern, count }));
|
|
21298
21625
|
return { logExists: true, totalLines, errorsLastHour, topPatterns };
|
|
21299
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
|
+
}
|
|
21300
21742
|
async function auditShards() {
|
|
21301
21743
|
try {
|
|
21302
21744
|
const { auditShardHealth: auditShardHealth2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -21312,16 +21754,33 @@ async function auditShards() {
|
|
|
21312
21754
|
return { total: 0, ok: 0, unreadable: 0, archived: 0, unreadableNames: [] };
|
|
21313
21755
|
}
|
|
21314
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
|
+
}
|
|
21315
21773
|
async function runAudit(client, flags) {
|
|
21316
21774
|
const runConflicts = flags.conflicts || process.env.EXE_AUDIT_CONFLICTS === "1";
|
|
21317
|
-
const [stats, nullVectors, duplicates, bloated, fts, orphanedProjects, shards] = await Promise.all([
|
|
21775
|
+
const [stats, nullVectors, duplicates, bloated, fts, orphanedProjects, shards, keyHealth] = await Promise.all([
|
|
21318
21776
|
auditStats(client, flags),
|
|
21319
21777
|
auditNullVectors(client, flags),
|
|
21320
21778
|
auditDuplicates(client, flags),
|
|
21321
21779
|
auditBloated(client, flags),
|
|
21322
21780
|
auditFts(client),
|
|
21323
21781
|
auditOrphanedProjects(client),
|
|
21324
|
-
auditShards()
|
|
21782
|
+
auditShards(),
|
|
21783
|
+
auditKeyHealth()
|
|
21325
21784
|
]);
|
|
21326
21785
|
let conflicts;
|
|
21327
21786
|
if (runConflicts) {
|
|
@@ -21341,7 +21800,8 @@ async function runAudit(client, flags) {
|
|
|
21341
21800
|
}
|
|
21342
21801
|
const duplicateCount = duplicates.reduce((sum, d) => sum + d.delete_ids.length, 0);
|
|
21343
21802
|
const hookHealth = auditHookHealth();
|
|
21344
|
-
|
|
21803
|
+
const hookOwnership = auditHookOwnership();
|
|
21804
|
+
return { stats, nullVectors, duplicates, duplicateCount, bloated, fts, orphanedProjects, conflicts, hookHealth, hookOwnership, shards, keyHealth };
|
|
21345
21805
|
}
|
|
21346
21806
|
function indicator(value, warn) {
|
|
21347
21807
|
if (value === 0) return "\u{1F7E2}";
|
|
@@ -21389,6 +21849,15 @@ function formatReport(report, flags) {
|
|
|
21389
21849
|
lines.push(`${indicator(report.bloated.length, 20)} Bloated (>5KB): ${fmtNum(report.bloated.length)} / ${fmtNum(s.total)} (${pct(report.bloated.length, s.total)})`);
|
|
21390
21850
|
const ftsIndicator = report.fts.inSync ? "\u{1F7E2}" : "\u{1F534}";
|
|
21391
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
|
+
}
|
|
21392
21861
|
if (report.orphanedProjects.length > 0) {
|
|
21393
21862
|
const orphanList = report.orphanedProjects.map((o) => `${o.project_name} \u2014 ${o.count} memories`).join(", ");
|
|
21394
21863
|
lines.push(`\u2139\uFE0F Orphaned projects: ${report.orphanedProjects.length} (${orphanList})`);
|
|
@@ -21420,6 +21889,15 @@ function formatReport(report, flags) {
|
|
|
21420
21889
|
lines.push(` ${p.count}x: ${p.pattern}`);
|
|
21421
21890
|
}
|
|
21422
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
|
+
}
|
|
21423
21901
|
const sh = report.shards;
|
|
21424
21902
|
if (sh.total > 0) {
|
|
21425
21903
|
if (sh.unreadable === 0) {
|
|
@@ -21489,6 +21967,9 @@ function formatReport(report, flags) {
|
|
|
21489
21967
|
if (report.conflicts.superseded > 0) {
|
|
21490
21968
|
recs.push(`${fmtNum(report.conflicts.superseded)} superseded memories can be deactivated`);
|
|
21491
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
|
+
}
|
|
21492
21973
|
if (recs.length > 0) {
|
|
21493
21974
|
lines.push("Recommendations:");
|
|
21494
21975
|
for (const r of recs) {
|
|
@@ -21510,7 +21991,7 @@ async function fixNullVectors() {
|
|
|
21510
21991
|
}
|
|
21511
21992
|
}
|
|
21512
21993
|
const npmRoot = (await import("child_process")).execSync("npm root -g", { encoding: "utf8" }).trim();
|
|
21513
|
-
const backfillPath =
|
|
21994
|
+
const backfillPath = path37.join(npmRoot, "exe-os", "dist", "bin", "backfill-vectors.js");
|
|
21514
21995
|
return new Promise((resolve, reject) => {
|
|
21515
21996
|
const child = spawn2("node", [backfillPath], { stdio: "inherit" });
|
|
21516
21997
|
if (child.pid) registerWorkerPid2(child.pid);
|
|
@@ -21622,8 +22103,8 @@ function splitAtSentences(text3, maxChunkSize) {
|
|
|
21622
22103
|
}
|
|
21623
22104
|
async function main(argv = process.argv.slice(2)) {
|
|
21624
22105
|
const flags = parseFlags(argv);
|
|
21625
|
-
await
|
|
21626
|
-
const client =
|
|
22106
|
+
const { fastDbInit: fastDbInit2 } = await Promise.resolve().then(() => (init_fast_db_init(), fast_db_init_exports));
|
|
22107
|
+
const client = await fastDbInit2();
|
|
21627
22108
|
const report = await runAudit(client, flags);
|
|
21628
22109
|
console.log(formatReport(report, flags));
|
|
21629
22110
|
if (flags.fix || flags.dryRun) {
|
|
@@ -21683,10 +22164,9 @@ ${mode} Complete.`);
|
|
|
21683
22164
|
var init_exe_doctor = __esm({
|
|
21684
22165
|
"src/bin/exe-doctor.ts"() {
|
|
21685
22166
|
"use strict";
|
|
21686
|
-
init_store();
|
|
21687
|
-
init_database();
|
|
21688
22167
|
init_is_main();
|
|
21689
22168
|
init_conflict_detector();
|
|
22169
|
+
init_runtime_hook_manifest();
|
|
21690
22170
|
if (isMainModule(import.meta.url) && (process.argv[1] ?? "").includes("exe-doctor")) {
|
|
21691
22171
|
main().catch((err) => {
|
|
21692
22172
|
console.error(err instanceof Error ? err.message : String(err));
|
|
@@ -21922,8 +22402,8 @@ __export(crdt_sync_exports, {
|
|
|
21922
22402
|
rebuildFromDb: () => rebuildFromDb
|
|
21923
22403
|
});
|
|
21924
22404
|
import * as Y from "yjs";
|
|
21925
|
-
import { readFileSync as
|
|
21926
|
-
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";
|
|
21927
22407
|
import { homedir as homedir5 } from "os";
|
|
21928
22408
|
function getStatePath() {
|
|
21929
22409
|
return _statePathOverride ?? DEFAULT_STATE_PATH;
|
|
@@ -21935,9 +22415,9 @@ function initCrdtDoc() {
|
|
|
21935
22415
|
if (doc) return doc;
|
|
21936
22416
|
doc = new Y.Doc();
|
|
21937
22417
|
const sp = getStatePath();
|
|
21938
|
-
if (
|
|
22418
|
+
if (existsSync33(sp)) {
|
|
21939
22419
|
try {
|
|
21940
|
-
const state =
|
|
22420
|
+
const state = readFileSync25(sp);
|
|
21941
22421
|
Y.applyUpdate(doc, new Uint8Array(state));
|
|
21942
22422
|
} catch {
|
|
21943
22423
|
console.warn("[crdt-sync] WARN: corrupted state file, rebuilding from DB");
|
|
@@ -22079,10 +22559,10 @@ function persistState() {
|
|
|
22079
22559
|
if (!doc) return;
|
|
22080
22560
|
try {
|
|
22081
22561
|
const sp = getStatePath();
|
|
22082
|
-
const dir =
|
|
22083
|
-
if (!
|
|
22562
|
+
const dir = path38.dirname(sp);
|
|
22563
|
+
if (!existsSync33(dir)) mkdirSync14(dir, { recursive: true });
|
|
22084
22564
|
const state = Y.encodeStateAsUpdate(doc);
|
|
22085
|
-
|
|
22565
|
+
writeFileSync17(sp, Buffer.from(state));
|
|
22086
22566
|
} catch {
|
|
22087
22567
|
}
|
|
22088
22568
|
}
|
|
@@ -22123,7 +22603,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
|
|
|
22123
22603
|
var init_crdt_sync = __esm({
|
|
22124
22604
|
"src/lib/crdt-sync.ts"() {
|
|
22125
22605
|
"use strict";
|
|
22126
|
-
DEFAULT_STATE_PATH =
|
|
22606
|
+
DEFAULT_STATE_PATH = path38.join(homedir5(), ".exe-os", "crdt-state.bin");
|
|
22127
22607
|
_statePathOverride = null;
|
|
22128
22608
|
doc = null;
|
|
22129
22609
|
}
|
|
@@ -22132,8 +22612,10 @@ var init_crdt_sync = __esm({
|
|
|
22132
22612
|
// src/lib/cloud-sync.ts
|
|
22133
22613
|
var cloud_sync_exports = {};
|
|
22134
22614
|
__export(cloud_sync_exports, {
|
|
22615
|
+
CLOUD_RELINK_REQUIRED_MESSAGE: () => CLOUD_RELINK_REQUIRED_MESSAGE,
|
|
22135
22616
|
assertSecureEndpoint: () => assertSecureEndpoint,
|
|
22136
22617
|
buildRosterBlob: () => buildRosterBlob,
|
|
22618
|
+
clearCloudRelinkRequired: () => clearCloudRelinkRequired,
|
|
22137
22619
|
cloudPull: () => cloudPull,
|
|
22138
22620
|
cloudPullBehaviors: () => cloudPullBehaviors,
|
|
22139
22621
|
cloudPullBlob: () => cloudPullBlob,
|
|
@@ -22153,53 +22635,66 @@ __export(cloud_sync_exports, {
|
|
|
22153
22635
|
cloudPushRoster: () => cloudPushRoster,
|
|
22154
22636
|
cloudPushTasks: () => cloudPushTasks,
|
|
22155
22637
|
cloudSync: () => cloudSync,
|
|
22638
|
+
getCloudRelinkRequired: () => getCloudRelinkRequired,
|
|
22156
22639
|
mergeConfig: () => mergeConfig,
|
|
22157
22640
|
mergeRosterFromRemote: () => mergeRosterFromRemote,
|
|
22158
22641
|
pushToPostgres: () => pushToPostgres,
|
|
22159
22642
|
recordRosterDeletion: () => recordRosterDeletion
|
|
22160
22643
|
});
|
|
22161
|
-
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";
|
|
22162
22645
|
import crypto16 from "crypto";
|
|
22163
|
-
import
|
|
22646
|
+
import path39 from "path";
|
|
22164
22647
|
import { homedir as homedir6 } from "os";
|
|
22165
22648
|
function sqlSafe(v) {
|
|
22166
22649
|
return v === void 0 ? null : v;
|
|
22167
22650
|
}
|
|
22168
22651
|
function logError(msg) {
|
|
22169
22652
|
try {
|
|
22170
|
-
const logPath =
|
|
22653
|
+
const logPath = path39.join(homedir6(), ".exe-os", "workers.log");
|
|
22171
22654
|
appendFileSync3(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
|
|
22172
22655
|
`);
|
|
22173
22656
|
} catch {
|
|
22174
22657
|
}
|
|
22175
22658
|
}
|
|
22659
|
+
function isTruthyEnv2(value) {
|
|
22660
|
+
return /^(1|true|yes|on)$/i.test(value ?? "");
|
|
22661
|
+
}
|
|
22176
22662
|
function loadPgClient() {
|
|
22177
22663
|
if (_pgFailed) return null;
|
|
22178
|
-
const
|
|
22179
|
-
const configPath = path38.join(EXE_AI_DIR, "config.json");
|
|
22664
|
+
const configPath = path39.join(EXE_AI_DIR, "config.json");
|
|
22180
22665
|
let cloudPostgresUrl;
|
|
22666
|
+
let configEnabled = false;
|
|
22181
22667
|
try {
|
|
22182
|
-
if (
|
|
22183
|
-
const cfg = JSON.parse(
|
|
22668
|
+
if (existsSync34(configPath)) {
|
|
22669
|
+
const cfg = JSON.parse(readFileSync26(configPath, "utf8"));
|
|
22184
22670
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
22185
|
-
|
|
22186
|
-
_pgFailed = true;
|
|
22187
|
-
return null;
|
|
22188
|
-
}
|
|
22671
|
+
configEnabled = cfg.cloud?.syncToPostgres === true;
|
|
22189
22672
|
}
|
|
22190
22673
|
} catch {
|
|
22191
22674
|
}
|
|
22192
|
-
const
|
|
22675
|
+
const envEnabled = isTruthyEnv2(process.env.EXE_CLOUD_SYNC_TO_POSTGRES);
|
|
22676
|
+
if (!envEnabled && !configEnabled) {
|
|
22677
|
+
return null;
|
|
22678
|
+
}
|
|
22679
|
+
const url = process.env.DATABASE_URL || cloudPostgresUrl;
|
|
22193
22680
|
if (!url) {
|
|
22194
22681
|
_pgFailed = true;
|
|
22195
22682
|
return null;
|
|
22196
22683
|
}
|
|
22197
22684
|
if (!_pgPromise) {
|
|
22198
22685
|
_pgPromise = (async () => {
|
|
22686
|
+
if (!process.env.DATABASE_URL) process.env.DATABASE_URL = url;
|
|
22199
22687
|
const { createRequire: createRequire7 } = await import("module");
|
|
22200
22688
|
const { pathToFileURL: pathToFileURL7 } = await import("url");
|
|
22201
|
-
const
|
|
22202
|
-
|
|
22689
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
22690
|
+
if (explicitPath) {
|
|
22691
|
+
const mod2 = await import(pathToFileURL7(explicitPath).href);
|
|
22692
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
22693
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
22694
|
+
return new Ctor2();
|
|
22695
|
+
}
|
|
22696
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path39.join(homedir6(), "exe-db");
|
|
22697
|
+
const req = createRequire7(path39.join(exeDbRoot, "package.json"));
|
|
22203
22698
|
const entry = req.resolve("@prisma/client");
|
|
22204
22699
|
const mod = await import(pathToFileURL7(entry).href);
|
|
22205
22700
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -22244,18 +22739,18 @@ async function withRosterLock(fn) {
|
|
|
22244
22739
|
try {
|
|
22245
22740
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
22246
22741
|
closeSync2(fd);
|
|
22247
|
-
|
|
22742
|
+
writeFileSync18(ROSTER_LOCK_PATH, String(Date.now()));
|
|
22248
22743
|
} catch (err) {
|
|
22249
22744
|
if (err.code === "EEXIST") {
|
|
22250
22745
|
try {
|
|
22251
|
-
const ts2 = parseInt(
|
|
22746
|
+
const ts2 = parseInt(readFileSync26(ROSTER_LOCK_PATH, "utf-8"), 10);
|
|
22252
22747
|
if (Date.now() - ts2 < LOCK_STALE_MS) {
|
|
22253
22748
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
22254
22749
|
}
|
|
22255
22750
|
unlinkSync12(ROSTER_LOCK_PATH);
|
|
22256
22751
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
22257
22752
|
closeSync2(fd);
|
|
22258
|
-
|
|
22753
|
+
writeFileSync18(ROSTER_LOCK_PATH, String(Date.now()));
|
|
22259
22754
|
} catch (retryErr) {
|
|
22260
22755
|
if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
|
|
22261
22756
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
@@ -22374,6 +22869,24 @@ async function cloudPull(sinceVersion, config2) {
|
|
|
22374
22869
|
return { records: [], maxVersion: sinceVersion };
|
|
22375
22870
|
}
|
|
22376
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
|
+
}
|
|
22377
22890
|
async function cloudSync(config2) {
|
|
22378
22891
|
if (!isSyncCryptoInitialized()) {
|
|
22379
22892
|
try {
|
|
@@ -22394,6 +22907,12 @@ async function cloudSync(config2) {
|
|
|
22394
22907
|
} catch {
|
|
22395
22908
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
22396
22909
|
}
|
|
22910
|
+
try {
|
|
22911
|
+
if (await getCloudRelinkRequired(client)) throw new Error(CLOUD_RELINK_REQUIRED_MESSAGE);
|
|
22912
|
+
} catch (err) {
|
|
22913
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
22914
|
+
if (msg.includes("Paused after key rotation")) throw err;
|
|
22915
|
+
}
|
|
22397
22916
|
try {
|
|
22398
22917
|
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
22399
22918
|
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
@@ -22639,8 +23158,8 @@ async function cloudSync(config2) {
|
|
|
22639
23158
|
try {
|
|
22640
23159
|
const employees = await loadEmployees();
|
|
22641
23160
|
rosterResult.employees = employees.length;
|
|
22642
|
-
const idDir =
|
|
22643
|
-
if (
|
|
23161
|
+
const idDir = path39.join(EXE_AI_DIR, "identity");
|
|
23162
|
+
if (existsSync34(idDir)) {
|
|
22644
23163
|
rosterResult.identities = readdirSync11(idDir).filter((f) => f.endsWith(".md")).length;
|
|
22645
23164
|
}
|
|
22646
23165
|
} catch {
|
|
@@ -22653,7 +23172,7 @@ async function cloudSync(config2) {
|
|
|
22653
23172
|
const backupSize = statSync6(latestBackup).size;
|
|
22654
23173
|
const MAX_CLOUD_BACKUP_BYTES = 50 * 1024 * 1024;
|
|
22655
23174
|
if (backupSize <= MAX_CLOUD_BACKUP_BYTES) {
|
|
22656
|
-
const backupData =
|
|
23175
|
+
const backupData = readFileSync26(latestBackup);
|
|
22657
23176
|
const deviceId = loadDeviceId() ?? "unknown";
|
|
22658
23177
|
const encrypted = encryptSyncBlob(backupData);
|
|
22659
23178
|
const backupRes = await fetchWithRetry(`${config2.endpoint}/sync/push-db-backup`, {
|
|
@@ -22661,7 +23180,7 @@ async function cloudSync(config2) {
|
|
|
22661
23180
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${config2.apiKey}` },
|
|
22662
23181
|
body: JSON.stringify({
|
|
22663
23182
|
device_id: deviceId,
|
|
22664
|
-
filename:
|
|
23183
|
+
filename: path39.basename(latestBackup),
|
|
22665
23184
|
blob: encrypted,
|
|
22666
23185
|
size: backupData.length
|
|
22667
23186
|
})
|
|
@@ -22689,56 +23208,56 @@ async function cloudSync(config2) {
|
|
|
22689
23208
|
function recordRosterDeletion(name) {
|
|
22690
23209
|
let deletions = [];
|
|
22691
23210
|
try {
|
|
22692
|
-
if (
|
|
22693
|
-
deletions = JSON.parse(
|
|
23211
|
+
if (existsSync34(ROSTER_DELETIONS_PATH)) {
|
|
23212
|
+
deletions = JSON.parse(readFileSync26(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
22694
23213
|
}
|
|
22695
23214
|
} catch {
|
|
22696
23215
|
}
|
|
22697
23216
|
if (!deletions.includes(name)) deletions.push(name);
|
|
22698
|
-
|
|
23217
|
+
writeFileSync18(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
|
|
22699
23218
|
}
|
|
22700
23219
|
function consumeRosterDeletions() {
|
|
22701
23220
|
try {
|
|
22702
|
-
if (!
|
|
22703
|
-
const deletions = JSON.parse(
|
|
22704
|
-
|
|
23221
|
+
if (!existsSync34(ROSTER_DELETIONS_PATH)) return [];
|
|
23222
|
+
const deletions = JSON.parse(readFileSync26(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
23223
|
+
writeFileSync18(ROSTER_DELETIONS_PATH, "[]");
|
|
22705
23224
|
return deletions;
|
|
22706
23225
|
} catch {
|
|
22707
23226
|
return [];
|
|
22708
23227
|
}
|
|
22709
23228
|
}
|
|
22710
23229
|
function buildRosterBlob(paths) {
|
|
22711
|
-
const rosterPath = paths?.rosterPath ??
|
|
22712
|
-
const identityDir = paths?.identityDir ??
|
|
22713
|
-
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");
|
|
22714
23233
|
let roster = [];
|
|
22715
|
-
if (
|
|
23234
|
+
if (existsSync34(rosterPath)) {
|
|
22716
23235
|
try {
|
|
22717
|
-
roster = JSON.parse(
|
|
23236
|
+
roster = JSON.parse(readFileSync26(rosterPath, "utf-8"));
|
|
22718
23237
|
} catch {
|
|
22719
23238
|
}
|
|
22720
23239
|
}
|
|
22721
23240
|
const identities = {};
|
|
22722
|
-
if (
|
|
23241
|
+
if (existsSync34(identityDir)) {
|
|
22723
23242
|
for (const file of readdirSync11(identityDir).filter((f) => f.endsWith(".md"))) {
|
|
22724
23243
|
try {
|
|
22725
|
-
identities[file] =
|
|
23244
|
+
identities[file] = readFileSync26(path39.join(identityDir, file), "utf-8");
|
|
22726
23245
|
} catch {
|
|
22727
23246
|
}
|
|
22728
23247
|
}
|
|
22729
23248
|
}
|
|
22730
23249
|
let config2;
|
|
22731
|
-
if (
|
|
23250
|
+
if (existsSync34(configPath)) {
|
|
22732
23251
|
try {
|
|
22733
|
-
config2 = JSON.parse(
|
|
23252
|
+
config2 = JSON.parse(readFileSync26(configPath, "utf-8"));
|
|
22734
23253
|
} catch {
|
|
22735
23254
|
}
|
|
22736
23255
|
}
|
|
22737
23256
|
let agentConfig;
|
|
22738
|
-
const agentConfigPath =
|
|
22739
|
-
if (
|
|
23257
|
+
const agentConfigPath = path39.join(EXE_AI_DIR, "agent-config.json");
|
|
23258
|
+
if (existsSync34(agentConfigPath)) {
|
|
22740
23259
|
try {
|
|
22741
|
-
agentConfig = JSON.parse(
|
|
23260
|
+
agentConfig = JSON.parse(readFileSync26(agentConfigPath, "utf-8"));
|
|
22742
23261
|
} catch {
|
|
22743
23262
|
}
|
|
22744
23263
|
}
|
|
@@ -22814,24 +23333,24 @@ async function cloudPullRoster(config2) {
|
|
|
22814
23333
|
}
|
|
22815
23334
|
}
|
|
22816
23335
|
function mergeConfig(remoteConfig, configPath) {
|
|
22817
|
-
const cfgPath = configPath ??
|
|
23336
|
+
const cfgPath = configPath ?? path39.join(EXE_AI_DIR, "config.json");
|
|
22818
23337
|
let local = {};
|
|
22819
|
-
if (
|
|
23338
|
+
if (existsSync34(cfgPath)) {
|
|
22820
23339
|
try {
|
|
22821
|
-
local = JSON.parse(
|
|
23340
|
+
local = JSON.parse(readFileSync26(cfgPath, "utf-8"));
|
|
22822
23341
|
} catch {
|
|
22823
23342
|
}
|
|
22824
23343
|
}
|
|
22825
23344
|
const merged = { ...remoteConfig, ...local };
|
|
22826
|
-
const dir =
|
|
23345
|
+
const dir = path39.dirname(cfgPath);
|
|
22827
23346
|
ensurePrivateDirSync(dir);
|
|
22828
|
-
|
|
23347
|
+
writeFileSync18(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
22829
23348
|
enforcePrivateFileSync(cfgPath);
|
|
22830
23349
|
}
|
|
22831
23350
|
async function mergeRosterFromRemote(remote, paths) {
|
|
22832
23351
|
return withRosterLock(async () => {
|
|
22833
23352
|
const rosterPath = paths?.rosterPath ?? void 0;
|
|
22834
|
-
const identityDir = paths?.identityDir ??
|
|
23353
|
+
const identityDir = paths?.identityDir ?? path39.join(EXE_AI_DIR, "identity");
|
|
22835
23354
|
const localEmployees = await loadEmployees(rosterPath);
|
|
22836
23355
|
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
22837
23356
|
let added = 0;
|
|
@@ -22852,15 +23371,15 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
22852
23371
|
) ?? lookupKey;
|
|
22853
23372
|
const remoteIdentity = remote.identities[matchedKey];
|
|
22854
23373
|
if (remoteIdentity) {
|
|
22855
|
-
if (!
|
|
22856
|
-
const idPath =
|
|
23374
|
+
if (!existsSync34(identityDir)) mkdirSync15(identityDir, { recursive: true });
|
|
23375
|
+
const idPath = path39.join(identityDir, `${remoteEmp.name}.md`);
|
|
22857
23376
|
let localIdentity = null;
|
|
22858
23377
|
try {
|
|
22859
|
-
localIdentity =
|
|
23378
|
+
localIdentity = existsSync34(idPath) ? readFileSync26(idPath, "utf-8") : null;
|
|
22860
23379
|
} catch {
|
|
22861
23380
|
}
|
|
22862
23381
|
if (localIdentity !== remoteIdentity) {
|
|
22863
|
-
|
|
23382
|
+
writeFileSync18(idPath, remoteIdentity, "utf-8");
|
|
22864
23383
|
identitiesUpdated++;
|
|
22865
23384
|
}
|
|
22866
23385
|
}
|
|
@@ -22886,17 +23405,17 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
22886
23405
|
}
|
|
22887
23406
|
if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
|
|
22888
23407
|
try {
|
|
22889
|
-
const agentConfigPath =
|
|
23408
|
+
const agentConfigPath = path39.join(EXE_AI_DIR, "agent-config.json");
|
|
22890
23409
|
let local = {};
|
|
22891
|
-
if (
|
|
23410
|
+
if (existsSync34(agentConfigPath)) {
|
|
22892
23411
|
try {
|
|
22893
|
-
local = JSON.parse(
|
|
23412
|
+
local = JSON.parse(readFileSync26(agentConfigPath, "utf-8"));
|
|
22894
23413
|
} catch {
|
|
22895
23414
|
}
|
|
22896
23415
|
}
|
|
22897
23416
|
const merged = { ...remote.agentConfig, ...local };
|
|
22898
|
-
ensurePrivateDirSync(
|
|
22899
|
-
|
|
23417
|
+
ensurePrivateDirSync(path39.dirname(agentConfigPath));
|
|
23418
|
+
writeFileSync18(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
22900
23419
|
enforcePrivateFileSync(agentConfigPath);
|
|
22901
23420
|
} catch {
|
|
22902
23421
|
}
|
|
@@ -23321,7 +23840,7 @@ async function cloudPullDocuments(config2) {
|
|
|
23321
23840
|
}
|
|
23322
23841
|
return { pulled };
|
|
23323
23842
|
}
|
|
23324
|
-
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;
|
|
23325
23844
|
var init_cloud_sync = __esm({
|
|
23326
23845
|
"src/lib/cloud-sync.ts"() {
|
|
23327
23846
|
"use strict";
|
|
@@ -23336,11 +23855,12 @@ var init_cloud_sync = __esm({
|
|
|
23336
23855
|
LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
23337
23856
|
FETCH_TIMEOUT_MS2 = 3e4;
|
|
23338
23857
|
PUSH_BATCH_SIZE = 5e3;
|
|
23339
|
-
ROSTER_LOCK_PATH =
|
|
23858
|
+
ROSTER_LOCK_PATH = path39.join(EXE_AI_DIR, "roster-merge.lock");
|
|
23340
23859
|
LOCK_STALE_MS = 3e4;
|
|
23341
23860
|
_pgPromise = null;
|
|
23342
23861
|
_pgFailed = false;
|
|
23343
|
-
|
|
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");
|
|
23344
23864
|
}
|
|
23345
23865
|
});
|
|
23346
23866
|
|
|
@@ -23411,6 +23931,143 @@ var init_cloud_sync2 = __esm({
|
|
|
23411
23931
|
}
|
|
23412
23932
|
});
|
|
23413
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
|
+
|
|
23414
24071
|
// src/lib/vps-backup.ts
|
|
23415
24072
|
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
23416
24073
|
import { Readable } from "stream";
|
|
@@ -23734,50 +24391,50 @@ var init_vps_backup = __esm({
|
|
|
23734
24391
|
});
|
|
23735
24392
|
|
|
23736
24393
|
// src/mcp/tools/backup-vps.ts
|
|
23737
|
-
import { z as
|
|
24394
|
+
import { z as z60 } from "zod";
|
|
23738
24395
|
function registerBackupVps(server) {
|
|
23739
24396
|
server.registerTool(
|
|
23740
24397
|
"backup_vps",
|
|
23741
24398
|
{
|
|
23742
24399
|
title: "VPS Backup",
|
|
23743
24400
|
description: "Run VPS Postgres backup/restore workflows and check status.",
|
|
23744
|
-
inputSchema:
|
|
23745
|
-
|
|
23746
|
-
action:
|
|
23747
|
-
databaseUrl:
|
|
23748
|
-
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(
|
|
23749
24406
|
"Base64 AES-256 key (defaults to local master key if omitted)"
|
|
23750
24407
|
),
|
|
23751
|
-
r2Bucket:
|
|
23752
|
-
r2Endpoint:
|
|
23753
|
-
r2AccessKeyId:
|
|
23754
|
-
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")
|
|
23755
24412
|
}),
|
|
23756
|
-
|
|
23757
|
-
action:
|
|
23758
|
-
databaseUrl:
|
|
23759
|
-
backupKey:
|
|
23760
|
-
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(
|
|
23761
24418
|
"Base64 AES-256 key (defaults to local master key if omitted)"
|
|
23762
24419
|
),
|
|
23763
|
-
r2Bucket:
|
|
23764
|
-
r2Endpoint:
|
|
23765
|
-
r2AccessKeyId:
|
|
23766
|
-
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")
|
|
23767
24424
|
}),
|
|
23768
|
-
|
|
23769
|
-
action:
|
|
23770
|
-
r2Bucket:
|
|
23771
|
-
r2Endpoint:
|
|
23772
|
-
r2AccessKeyId:
|
|
23773
|
-
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")
|
|
23774
24431
|
}),
|
|
23775
|
-
|
|
23776
|
-
action:
|
|
23777
|
-
r2Bucket:
|
|
23778
|
-
r2Endpoint:
|
|
23779
|
-
r2AccessKeyId:
|
|
23780
|
-
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")
|
|
23781
24438
|
})
|
|
23782
24439
|
])
|
|
23783
24440
|
},
|
|
@@ -23971,9 +24628,9 @@ var init_hostinger_api = __esm({
|
|
|
23971
24628
|
}
|
|
23972
24629
|
this.lastRequestTime = Date.now();
|
|
23973
24630
|
}
|
|
23974
|
-
async request(method,
|
|
24631
|
+
async request(method, path56, body) {
|
|
23975
24632
|
await this.rateLimit();
|
|
23976
|
-
const url = `${this.baseUrl}${
|
|
24633
|
+
const url = `${this.baseUrl}${path56}`;
|
|
23977
24634
|
const headers = {
|
|
23978
24635
|
Authorization: `Bearer ${this.apiKey}`,
|
|
23979
24636
|
"Content-Type": "application/json",
|
|
@@ -24042,8 +24699,8 @@ async function requestCloudflare(cfApiToken, zoneId, options) {
|
|
|
24042
24699
|
}
|
|
24043
24700
|
return envelope.result;
|
|
24044
24701
|
}
|
|
24045
|
-
function buildUrl(zoneId,
|
|
24046
|
-
const normalizedPath =
|
|
24702
|
+
function buildUrl(zoneId, path56 = "/dns_records", query) {
|
|
24703
|
+
const normalizedPath = path56.startsWith("/") ? path56 : `/${path56}`;
|
|
24047
24704
|
const url = new URL(
|
|
24048
24705
|
`${CLOUDFLARE_API_BASE_URL}/zones/${zoneId}${normalizedPath}`
|
|
24049
24706
|
);
|
|
@@ -24114,11 +24771,11 @@ var init_cloudflare_dns = __esm({
|
|
|
24114
24771
|
});
|
|
24115
24772
|
|
|
24116
24773
|
// src/mcp/tools/deploy-client.ts
|
|
24117
|
-
import { z as
|
|
24774
|
+
import { z as z61 } from "zod";
|
|
24118
24775
|
import { execFile } from "child_process";
|
|
24119
24776
|
import { promisify } from "util";
|
|
24120
|
-
import
|
|
24121
|
-
import { existsSync as
|
|
24777
|
+
import path40 from "path";
|
|
24778
|
+
import { existsSync as existsSync35 } from "fs";
|
|
24122
24779
|
async function executeDeployment(params, client) {
|
|
24123
24780
|
const {
|
|
24124
24781
|
client_name,
|
|
@@ -24190,12 +24847,12 @@ function registerDeployClient(server) {
|
|
|
24190
24847
|
title: "Deploy Client",
|
|
24191
24848
|
description: "Provision a Hostinger VPS and deploy exe-os for a client. Creates VPS, waits for ready state, runs Ansible playbook, verifies health.",
|
|
24192
24849
|
inputSchema: {
|
|
24193
|
-
client_name:
|
|
24194
|
-
domain:
|
|
24195
|
-
region:
|
|
24196
|
-
plan:
|
|
24197
|
-
ssl_email:
|
|
24198
|
-
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")
|
|
24199
24856
|
}
|
|
24200
24857
|
},
|
|
24201
24858
|
async ({ client_name, domain, region, plan, ssl_email, user_id }) => {
|
|
@@ -24263,12 +24920,12 @@ async function waitForReady(client, vpsId) {
|
|
|
24263
24920
|
}
|
|
24264
24921
|
async function runAnsiblePlaybook(vpsIp, domain, sslEmail, clientName) {
|
|
24265
24922
|
const safeClientName = clientName.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
24266
|
-
const playbookDir =
|
|
24267
|
-
const playbookPath =
|
|
24268
|
-
const inventoryPath =
|
|
24269
|
-
const clientVarsPath =
|
|
24270
|
-
const varsDir =
|
|
24271
|
-
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))) {
|
|
24272
24929
|
throw new Error(`Invalid client name for vars path: ${clientName}`);
|
|
24273
24930
|
}
|
|
24274
24931
|
const args = [
|
|
@@ -24284,7 +24941,7 @@ async function runAnsiblePlaybook(vpsIp, domain, sslEmail, clientName) {
|
|
|
24284
24941
|
"-e",
|
|
24285
24942
|
`client_name=${safeClientName}`
|
|
24286
24943
|
];
|
|
24287
|
-
if (
|
|
24944
|
+
if (existsSync35(clientVarsPath)) {
|
|
24288
24945
|
args.push("-e", `@${clientVarsPath}`);
|
|
24289
24946
|
}
|
|
24290
24947
|
try {
|
|
@@ -24374,7 +25031,7 @@ var init_deploy_client = __esm({
|
|
|
24374
25031
|
});
|
|
24375
25032
|
|
|
24376
25033
|
// src/mcp/tools/get-license-status.ts
|
|
24377
|
-
import { z as
|
|
25034
|
+
import { z as z62 } from "zod";
|
|
24378
25035
|
function registerGetLicenseStatus(server) {
|
|
24379
25036
|
server.registerTool(
|
|
24380
25037
|
"get_license_status",
|
|
@@ -24382,7 +25039,7 @@ function registerGetLicenseStatus(server) {
|
|
|
24382
25039
|
title: "Get License Status",
|
|
24383
25040
|
description: "Get current license status: plan, validity, feature gates, limits, and expiry.",
|
|
24384
25041
|
inputSchema: {
|
|
24385
|
-
_dummy:
|
|
25042
|
+
_dummy: z62.string().optional().describe("Unused \u2014 no input required")
|
|
24386
25043
|
}
|
|
24387
25044
|
},
|
|
24388
25045
|
async () => {
|
|
@@ -24448,11 +25105,11 @@ var init_get_license_status = __esm({
|
|
|
24448
25105
|
|
|
24449
25106
|
// src/mcp/tools/create-license.ts
|
|
24450
25107
|
import os17 from "os";
|
|
24451
|
-
import
|
|
25108
|
+
import path41 from "path";
|
|
24452
25109
|
import { randomBytes as randomBytes2, randomUUID as randomUUID6 } from "crypto";
|
|
24453
25110
|
import { createRequire as createRequire4 } from "module";
|
|
24454
25111
|
import { pathToFileURL as pathToFileURL4 } from "url";
|
|
24455
|
-
import { z as
|
|
25112
|
+
import { z as z63 } from "zod";
|
|
24456
25113
|
function loadPrisma2() {
|
|
24457
25114
|
if (!prismaPromise2) {
|
|
24458
25115
|
prismaPromise2 = (async () => {
|
|
@@ -24463,8 +25120,8 @@ function loadPrisma2() {
|
|
|
24463
25120
|
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
24464
25121
|
return new Ctor2();
|
|
24465
25122
|
}
|
|
24466
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
24467
|
-
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"));
|
|
24468
25125
|
const entry = req.resolve("@prisma/client");
|
|
24469
25126
|
const mod = await import(pathToFileURL4(entry).href);
|
|
24470
25127
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -24484,10 +25141,10 @@ function registerCreateLicense(server) {
|
|
|
24484
25141
|
title: "Create License",
|
|
24485
25142
|
description: "Generate an exe_sk_* license key for a user. Stores in billing.licenses. Returns the key to give to the customer.",
|
|
24486
25143
|
inputSchema: {
|
|
24487
|
-
email:
|
|
24488
|
-
name:
|
|
24489
|
-
plan:
|
|
24490
|
-
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)")
|
|
24491
25148
|
}
|
|
24492
25149
|
},
|
|
24493
25150
|
async ({ email, name, plan, expires_in_days }) => {
|
|
@@ -24547,10 +25204,10 @@ var init_create_license = __esm({
|
|
|
24547
25204
|
|
|
24548
25205
|
// src/mcp/tools/list-licenses.ts
|
|
24549
25206
|
import os18 from "os";
|
|
24550
|
-
import
|
|
25207
|
+
import path42 from "path";
|
|
24551
25208
|
import { createRequire as createRequire5 } from "module";
|
|
24552
25209
|
import { pathToFileURL as pathToFileURL5 } from "url";
|
|
24553
|
-
import { z as
|
|
25210
|
+
import { z as z64 } from "zod";
|
|
24554
25211
|
function loadPrisma3() {
|
|
24555
25212
|
if (!prismaPromise3) {
|
|
24556
25213
|
prismaPromise3 = (async () => {
|
|
@@ -24561,8 +25218,8 @@ function loadPrisma3() {
|
|
|
24561
25218
|
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
24562
25219
|
return new Ctor2();
|
|
24563
25220
|
}
|
|
24564
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
24565
|
-
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"));
|
|
24566
25223
|
const entry = req.resolve("@prisma/client");
|
|
24567
25224
|
const mod = await import(pathToFileURL5(entry).href);
|
|
24568
25225
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -24579,7 +25236,7 @@ function registerListLicenses(server) {
|
|
|
24579
25236
|
title: "List Licenses",
|
|
24580
25237
|
description: "List all issued licenses with status (active/expired/revoked). Optionally filter by plan.",
|
|
24581
25238
|
inputSchema: {
|
|
24582
|
-
plan:
|
|
25239
|
+
plan: z64.enum(["free", "pro", "team", "agency", "enterprise"]).optional().describe("Filter by plan tier (omit for all)")
|
|
24583
25240
|
}
|
|
24584
25241
|
},
|
|
24585
25242
|
async ({ plan }) => {
|
|
@@ -24636,7 +25293,7 @@ var init_list_licenses = __esm({
|
|
|
24636
25293
|
});
|
|
24637
25294
|
|
|
24638
25295
|
// src/mcp/tools/activate-license.ts
|
|
24639
|
-
import { z as
|
|
25296
|
+
import { z as z65 } from "zod";
|
|
24640
25297
|
function registerActivateLicense(server) {
|
|
24641
25298
|
server.registerTool(
|
|
24642
25299
|
"activate_license",
|
|
@@ -24644,7 +25301,7 @@ function registerActivateLicense(server) {
|
|
|
24644
25301
|
title: "Activate License",
|
|
24645
25302
|
description: "Activate an exe_sk_* license key on this device. Writes to ~/.exe-os/license.key, validates against Postgres, and caches the result.",
|
|
24646
25303
|
inputSchema: {
|
|
24647
|
-
key:
|
|
25304
|
+
key: z65.string().startsWith("exe_sk_").describe("License key (exe_sk_*)")
|
|
24648
25305
|
}
|
|
24649
25306
|
},
|
|
24650
25307
|
async ({ key }) => {
|
|
@@ -24696,14 +25353,14 @@ var init_activate_license = __esm({
|
|
|
24696
25353
|
});
|
|
24697
25354
|
|
|
24698
25355
|
// src/automation/trigger-engine.ts
|
|
24699
|
-
import { readFileSync as
|
|
25356
|
+
import { readFileSync as readFileSync27, writeFileSync as writeFileSync19, existsSync as existsSync36, mkdirSync as mkdirSync16 } from "fs";
|
|
24700
25357
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
24701
|
-
import
|
|
25358
|
+
import path43 from "path";
|
|
24702
25359
|
import os19 from "os";
|
|
24703
25360
|
function loadTriggers(project) {
|
|
24704
|
-
if (!
|
|
25361
|
+
if (!existsSync36(TRIGGERS_PATH)) return [];
|
|
24705
25362
|
try {
|
|
24706
|
-
const raw =
|
|
25363
|
+
const raw = readFileSync27(TRIGGERS_PATH, "utf-8");
|
|
24707
25364
|
const all = JSON.parse(raw);
|
|
24708
25365
|
if (!Array.isArray(all)) return [];
|
|
24709
25366
|
if (project) {
|
|
@@ -24715,9 +25372,9 @@ function loadTriggers(project) {
|
|
|
24715
25372
|
}
|
|
24716
25373
|
}
|
|
24717
25374
|
function saveTriggers(triggers) {
|
|
24718
|
-
const dir =
|
|
24719
|
-
if (!
|
|
24720
|
-
|
|
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");
|
|
24721
25378
|
}
|
|
24722
25379
|
function createNewTrigger(input) {
|
|
24723
25380
|
const triggers = loadTriggers();
|
|
@@ -24736,7 +25393,7 @@ var TRIGGERS_PATH;
|
|
|
24736
25393
|
var init_trigger_engine = __esm({
|
|
24737
25394
|
"src/automation/trigger-engine.ts"() {
|
|
24738
25395
|
"use strict";
|
|
24739
|
-
TRIGGERS_PATH =
|
|
25396
|
+
TRIGGERS_PATH = path43.join(os19.homedir(), ".exe-os", "triggers.json");
|
|
24740
25397
|
}
|
|
24741
25398
|
});
|
|
24742
25399
|
|
|
@@ -24886,7 +25543,7 @@ var init_schedules = __esm({
|
|
|
24886
25543
|
});
|
|
24887
25544
|
|
|
24888
25545
|
// src/mcp/tools/create-trigger.ts
|
|
24889
|
-
import { z as
|
|
25546
|
+
import { z as z66 } from "zod";
|
|
24890
25547
|
function registerCreateTrigger(server) {
|
|
24891
25548
|
server.registerTool(
|
|
24892
25549
|
"create_trigger",
|
|
@@ -24894,18 +25551,18 @@ function registerCreateTrigger(server) {
|
|
|
24894
25551
|
title: "Create Trigger",
|
|
24895
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.).",
|
|
24896
25553
|
inputSchema: {
|
|
24897
|
-
name:
|
|
24898
|
-
event:
|
|
25554
|
+
name: z66.string().describe("Human-readable trigger name"),
|
|
25555
|
+
event: z66.string().describe(
|
|
24899
25556
|
'CRM event to match, e.g., "Deal.updated", "Order.created", "*" for all'
|
|
24900
25557
|
),
|
|
24901
|
-
conditions:
|
|
24902
|
-
actions:
|
|
24903
|
-
project:
|
|
24904
|
-
enabled:
|
|
24905
|
-
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(
|
|
24906
25563
|
'Cron schedule for time-based triggers, e.g., "0 9 * * *" or "Monday 9am"'
|
|
24907
25564
|
),
|
|
24908
|
-
query:
|
|
25565
|
+
query: z66.string().optional().describe(
|
|
24909
25566
|
"CRM GraphQL query to run on schedule (required if schedule is set)"
|
|
24910
25567
|
)
|
|
24911
25568
|
}
|
|
@@ -24982,14 +25639,14 @@ var init_create_trigger = __esm({
|
|
|
24982
25639
|
"use strict";
|
|
24983
25640
|
init_trigger_engine();
|
|
24984
25641
|
init_schedules();
|
|
24985
|
-
conditionSchema =
|
|
24986
|
-
field:
|
|
24987
|
-
op:
|
|
24988
|
-
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")
|
|
24989
25646
|
});
|
|
24990
|
-
actionSchema =
|
|
24991
|
-
type:
|
|
24992
|
-
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(
|
|
24993
25650
|
"Action parameters. Supports {{record.field}} templates for dynamic values."
|
|
24994
25651
|
)
|
|
24995
25652
|
});
|
|
@@ -24997,7 +25654,7 @@ var init_create_trigger = __esm({
|
|
|
24997
25654
|
});
|
|
24998
25655
|
|
|
24999
25656
|
// src/mcp/tools/list-triggers.ts
|
|
25000
|
-
import { z as
|
|
25657
|
+
import { z as z67 } from "zod";
|
|
25001
25658
|
function registerListTriggers(server) {
|
|
25002
25659
|
server.registerTool(
|
|
25003
25660
|
"list_triggers",
|
|
@@ -25005,7 +25662,7 @@ function registerListTriggers(server) {
|
|
|
25005
25662
|
title: "List Triggers",
|
|
25006
25663
|
description: "List configured CRM event triggers and scheduled automations.",
|
|
25007
25664
|
inputSchema: {
|
|
25008
|
-
project:
|
|
25665
|
+
project: z67.string().optional().describe("Filter triggers by project name")
|
|
25009
25666
|
}
|
|
25010
25667
|
},
|
|
25011
25668
|
async ({ project }) => {
|
|
@@ -25046,47 +25703,47 @@ var init_list_triggers = __esm({
|
|
|
25046
25703
|
});
|
|
25047
25704
|
|
|
25048
25705
|
// src/automation/starter-packs/index.ts
|
|
25049
|
-
import { readFileSync as
|
|
25050
|
-
import
|
|
25706
|
+
import { readFileSync as readFileSync28, readdirSync as readdirSync12, existsSync as existsSync37 } from "fs";
|
|
25707
|
+
import path44 from "path";
|
|
25051
25708
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
25052
25709
|
function listPacks() {
|
|
25053
|
-
const packsDir =
|
|
25054
|
-
if (!
|
|
25710
|
+
const packsDir = path44.join(__dirname, ".");
|
|
25711
|
+
if (!existsSync37(packsDir)) return [];
|
|
25055
25712
|
return readdirSync12(packsDir, { withFileTypes: true }).filter(
|
|
25056
|
-
(d) => d.isDirectory() &&
|
|
25713
|
+
(d) => d.isDirectory() && existsSync37(path44.join(packsDir, d.name, "custom-objects.json"))
|
|
25057
25714
|
).map((d) => d.name);
|
|
25058
25715
|
}
|
|
25059
25716
|
function loadPack(industry) {
|
|
25060
|
-
const packDir =
|
|
25061
|
-
const objectsPath =
|
|
25062
|
-
const triggersPath =
|
|
25063
|
-
const wikiDir =
|
|
25064
|
-
const manifestPath =
|
|
25065
|
-
const identityContextPath =
|
|
25066
|
-
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;
|
|
25067
25724
|
let customObjects = [];
|
|
25068
25725
|
try {
|
|
25069
25726
|
customObjects = JSON.parse(
|
|
25070
|
-
|
|
25727
|
+
readFileSync28(objectsPath, "utf-8")
|
|
25071
25728
|
);
|
|
25072
25729
|
} catch {
|
|
25073
25730
|
customObjects = [];
|
|
25074
25731
|
}
|
|
25075
25732
|
let triggers = [];
|
|
25076
|
-
if (
|
|
25733
|
+
if (existsSync37(triggersPath)) {
|
|
25077
25734
|
try {
|
|
25078
25735
|
triggers = JSON.parse(
|
|
25079
|
-
|
|
25736
|
+
readFileSync28(triggersPath, "utf-8")
|
|
25080
25737
|
);
|
|
25081
25738
|
} catch {
|
|
25082
25739
|
triggers = [];
|
|
25083
25740
|
}
|
|
25084
25741
|
}
|
|
25085
25742
|
const wikiSeeds = [];
|
|
25086
|
-
if (
|
|
25743
|
+
if (existsSync37(wikiDir)) {
|
|
25087
25744
|
const files = readdirSync12(wikiDir).filter((f) => f.endsWith(".md"));
|
|
25088
25745
|
for (const file of files) {
|
|
25089
|
-
const content =
|
|
25746
|
+
const content = readFileSync28(path44.join(wikiDir, file), "utf-8");
|
|
25090
25747
|
const titleMatch = content.match(/^#\s+(.+)/m);
|
|
25091
25748
|
wikiSeeds.push({
|
|
25092
25749
|
filename: file,
|
|
@@ -25096,17 +25753,17 @@ function loadPack(industry) {
|
|
|
25096
25753
|
}
|
|
25097
25754
|
}
|
|
25098
25755
|
let manifest = {};
|
|
25099
|
-
if (
|
|
25756
|
+
if (existsSync37(manifestPath)) {
|
|
25100
25757
|
try {
|
|
25101
|
-
manifest = JSON.parse(
|
|
25758
|
+
manifest = JSON.parse(readFileSync28(manifestPath, "utf-8"));
|
|
25102
25759
|
} catch {
|
|
25103
25760
|
manifest = {};
|
|
25104
25761
|
}
|
|
25105
25762
|
}
|
|
25106
25763
|
let identityContext = null;
|
|
25107
|
-
if (
|
|
25764
|
+
if (existsSync37(identityContextPath)) {
|
|
25108
25765
|
try {
|
|
25109
|
-
identityContext =
|
|
25766
|
+
identityContext = readFileSync28(identityContextPath, "utf-8");
|
|
25110
25767
|
} catch {
|
|
25111
25768
|
identityContext = null;
|
|
25112
25769
|
}
|
|
@@ -25165,7 +25822,7 @@ var init_starter_packs = __esm({
|
|
|
25165
25822
|
"src/automation/starter-packs/index.ts"() {
|
|
25166
25823
|
"use strict";
|
|
25167
25824
|
init_trigger_engine();
|
|
25168
|
-
__dirname =
|
|
25825
|
+
__dirname = path44.dirname(fileURLToPath4(import.meta.url));
|
|
25169
25826
|
}
|
|
25170
25827
|
});
|
|
25171
25828
|
|
|
@@ -25297,21 +25954,21 @@ All memory, tasks, behaviors, documents, and wiki content belonging to {{company
|
|
|
25297
25954
|
});
|
|
25298
25955
|
|
|
25299
25956
|
// src/lib/client-coo.ts
|
|
25300
|
-
import { existsSync as
|
|
25301
|
-
import
|
|
25957
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync17, writeFileSync as writeFileSync20 } from "fs";
|
|
25958
|
+
import path45 from "path";
|
|
25302
25959
|
async function provisionClientCOO(vars, opts = {}) {
|
|
25303
|
-
const identityDir = opts.identityDir ??
|
|
25960
|
+
const identityDir = opts.identityDir ?? path45.join(EXE_AI_DIR, "identity");
|
|
25304
25961
|
const rosterPath = opts.employeesPath ?? EMPLOYEES_PATH;
|
|
25305
25962
|
const storeFeedbackBehavior = opts.storeFeedbackBehavior ?? true;
|
|
25306
|
-
const identityPath2 =
|
|
25307
|
-
if (
|
|
25963
|
+
const identityPath2 = path45.join(identityDir, `${vars.agent_name}.md`);
|
|
25964
|
+
if (existsSync38(identityPath2)) {
|
|
25308
25965
|
throw new ClientCOOClobberError(vars.agent_name, identityPath2);
|
|
25309
25966
|
}
|
|
25310
25967
|
const body = renderClientCOOTemplate(vars);
|
|
25311
|
-
if (!
|
|
25312
|
-
|
|
25968
|
+
if (!existsSync38(identityDir)) {
|
|
25969
|
+
mkdirSync17(identityDir, { recursive: true });
|
|
25313
25970
|
}
|
|
25314
|
-
|
|
25971
|
+
writeFileSync20(identityPath2, body, "utf-8");
|
|
25315
25972
|
const employees = await loadEmployees(rosterPath);
|
|
25316
25973
|
const existing = employees.find((e) => e.name === vars.agent_name);
|
|
25317
25974
|
let addedToRoster = false;
|
|
@@ -25363,7 +26020,7 @@ var init_client_coo = __esm({
|
|
|
25363
26020
|
});
|
|
25364
26021
|
|
|
25365
26022
|
// src/mcp/tools/apply-starter-pack.ts
|
|
25366
|
-
import { z as
|
|
26023
|
+
import { z as z68 } from "zod";
|
|
25367
26024
|
function registerApplyStarterPack(server) {
|
|
25368
26025
|
server.registerTool(
|
|
25369
26026
|
"apply_starter_pack",
|
|
@@ -25371,17 +26028,17 @@ function registerApplyStarterPack(server) {
|
|
|
25371
26028
|
title: "Apply Starter Pack",
|
|
25372
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.",
|
|
25373
26030
|
inputSchema: {
|
|
25374
|
-
industry:
|
|
26031
|
+
industry: z68.string().describe(
|
|
25375
26032
|
'Industry pack to apply (e.g., "distribution"). Use without args to list available packs.'
|
|
25376
26033
|
),
|
|
25377
|
-
project:
|
|
25378
|
-
agent_name:
|
|
26034
|
+
project: z68.string().describe("Project name to scope the triggers to"),
|
|
26035
|
+
agent_name: z68.string().optional().describe(
|
|
25379
26036
|
"Optional. Lowercase alphanumeric name for the Client COO agent. Required (alongside company_name and founder_name) to provision a COO."
|
|
25380
26037
|
),
|
|
25381
|
-
company_name:
|
|
26038
|
+
company_name: z68.string().optional().describe(
|
|
25382
26039
|
"Optional. The client company the COO serves. Required to provision a COO."
|
|
25383
26040
|
),
|
|
25384
|
-
founder_name:
|
|
26041
|
+
founder_name: z68.string().optional().describe(
|
|
25385
26042
|
"Optional. The founder the COO reports to. Required to provision a COO."
|
|
25386
26043
|
)
|
|
25387
26044
|
}
|
|
@@ -25533,18 +26190,18 @@ var init_apply_starter_pack = __esm({
|
|
|
25533
26190
|
});
|
|
25534
26191
|
|
|
25535
26192
|
// src/mcp/tools/load-skill.ts
|
|
25536
|
-
import { z as
|
|
25537
|
-
import { readFileSync as
|
|
25538
|
-
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";
|
|
25539
26196
|
import { homedir as homedir7 } from "os";
|
|
25540
26197
|
function listAvailableSkills() {
|
|
25541
26198
|
try {
|
|
25542
26199
|
const entries = readdirSync13(SKILLS_DIR);
|
|
25543
26200
|
return entries.filter((entry) => {
|
|
25544
26201
|
try {
|
|
25545
|
-
const entryPath =
|
|
26202
|
+
const entryPath = path46.join(SKILLS_DIR, entry);
|
|
25546
26203
|
if (!statSync7(entryPath).isDirectory()) return false;
|
|
25547
|
-
const skillFile =
|
|
26204
|
+
const skillFile = path46.join(entryPath, "SKILL.md");
|
|
25548
26205
|
statSync7(skillFile);
|
|
25549
26206
|
return true;
|
|
25550
26207
|
} catch {
|
|
@@ -25562,7 +26219,7 @@ function registerLoadSkill(server) {
|
|
|
25562
26219
|
title: "Load Skill",
|
|
25563
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.",
|
|
25564
26221
|
inputSchema: {
|
|
25565
|
-
skill_name:
|
|
26222
|
+
skill_name: z69.string().describe(
|
|
25566
26223
|
"Skill to load (e.g. 'seo', 'code-reviewer', 'frontend-design'). Pass 'list' to see all available skills."
|
|
25567
26224
|
)
|
|
25568
26225
|
}
|
|
@@ -25587,10 +26244,10 @@ ${skills.map((s) => `- ${s}`).join("\n")}`
|
|
|
25587
26244
|
}]
|
|
25588
26245
|
};
|
|
25589
26246
|
}
|
|
25590
|
-
const sanitized =
|
|
25591
|
-
const skillFile =
|
|
26247
|
+
const sanitized = path46.basename(skill_name);
|
|
26248
|
+
const skillFile = path46.join(SKILLS_DIR, sanitized, "SKILL.md");
|
|
25592
26249
|
try {
|
|
25593
|
-
const content =
|
|
26250
|
+
const content = readFileSync29(skillFile, "utf-8");
|
|
25594
26251
|
return {
|
|
25595
26252
|
content: [{
|
|
25596
26253
|
type: "text",
|
|
@@ -25619,15 +26276,15 @@ var SKILLS_DIR;
|
|
|
25619
26276
|
var init_load_skill = __esm({
|
|
25620
26277
|
"src/mcp/tools/load-skill.ts"() {
|
|
25621
26278
|
"use strict";
|
|
25622
|
-
SKILLS_DIR =
|
|
26279
|
+
SKILLS_DIR = path46.join(homedir7(), ".claude", "skills");
|
|
25623
26280
|
}
|
|
25624
26281
|
});
|
|
25625
26282
|
|
|
25626
26283
|
// src/lib/orchestration-package.ts
|
|
25627
26284
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
25628
|
-
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";
|
|
25629
26286
|
import os20 from "os";
|
|
25630
|
-
import
|
|
26287
|
+
import path47 from "path";
|
|
25631
26288
|
function ensureObject(value, label) {
|
|
25632
26289
|
if (value == null || Array.isArray(value) || typeof value !== "object") {
|
|
25633
26290
|
throw new Error(`${label} must be an object`);
|
|
@@ -25686,15 +26343,15 @@ function validateProcedureEntry(value, index) {
|
|
|
25686
26343
|
};
|
|
25687
26344
|
}
|
|
25688
26345
|
function getRosterPath() {
|
|
25689
|
-
return
|
|
26346
|
+
return path47.join(os20.homedir(), EXE_OS_DIRNAME, ROSTER_FILENAME);
|
|
25690
26347
|
}
|
|
25691
26348
|
function getBackupPath() {
|
|
25692
|
-
return
|
|
26349
|
+
return path47.join(os20.homedir(), EXE_OS_DIRNAME, ROSTER_BACKUP_FILENAME);
|
|
25693
26350
|
}
|
|
25694
26351
|
function readRosterFile() {
|
|
25695
26352
|
const rosterPath = getRosterPath();
|
|
25696
|
-
if (!
|
|
25697
|
-
const raw =
|
|
26353
|
+
if (!existsSync39(rosterPath)) return [];
|
|
26354
|
+
const raw = readFileSync30(rosterPath, "utf-8");
|
|
25698
26355
|
const parsed = JSON.parse(raw);
|
|
25699
26356
|
if (!Array.isArray(parsed)) {
|
|
25700
26357
|
throw new Error("Roster file must contain a JSON array");
|
|
@@ -25706,8 +26363,8 @@ function writeRosterFile(roster) {
|
|
|
25706
26363
|
throw new Error("Refusing to write empty roster \u2014 this would delete all employees");
|
|
25707
26364
|
}
|
|
25708
26365
|
const rosterPath = getRosterPath();
|
|
25709
|
-
|
|
25710
|
-
if (
|
|
26366
|
+
mkdirSync18(path47.dirname(rosterPath), { recursive: true });
|
|
26367
|
+
if (existsSync39(rosterPath)) {
|
|
25711
26368
|
const currentRoster = readRosterFile();
|
|
25712
26369
|
if (roster.length < currentRoster.length) {
|
|
25713
26370
|
throw new Error(
|
|
@@ -25716,7 +26373,7 @@ function writeRosterFile(roster) {
|
|
|
25716
26373
|
}
|
|
25717
26374
|
copyFileSync2(rosterPath, getBackupPath());
|
|
25718
26375
|
}
|
|
25719
|
-
|
|
26376
|
+
writeFileSync21(rosterPath, `${JSON.stringify(roster, null, 2)}
|
|
25720
26377
|
`, "utf-8");
|
|
25721
26378
|
}
|
|
25722
26379
|
function buildImportedRosterEntries(roster, timestamp) {
|
|
@@ -25979,9 +26636,9 @@ var init_orchestration_package = __esm({
|
|
|
25979
26636
|
});
|
|
25980
26637
|
|
|
25981
26638
|
// src/mcp/tools/export-orchestration.ts
|
|
25982
|
-
import { mkdirSync as
|
|
25983
|
-
import
|
|
25984
|
-
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";
|
|
25985
26642
|
function registerExportOrchestration(server) {
|
|
25986
26643
|
server.registerTool(
|
|
25987
26644
|
"export_orchestration",
|
|
@@ -25989,15 +26646,15 @@ function registerExportOrchestration(server) {
|
|
|
25989
26646
|
title: "Export Orchestration",
|
|
25990
26647
|
description: "Export roster, identities, behaviors, and customer procedures to a JSON package.",
|
|
25991
26648
|
inputSchema: {
|
|
25992
|
-
output_path:
|
|
26649
|
+
output_path: z70.string().describe("File path to write the JSON package")
|
|
25993
26650
|
}
|
|
25994
26651
|
},
|
|
25995
26652
|
async ({ output_path }) => {
|
|
25996
26653
|
try {
|
|
25997
26654
|
await initStore();
|
|
25998
26655
|
const pkg = await exportOrchestration(getActiveAgent().agentId);
|
|
25999
|
-
|
|
26000
|
-
|
|
26656
|
+
mkdirSync19(path48.dirname(output_path), { recursive: true });
|
|
26657
|
+
writeFileSync22(output_path, `${JSON.stringify(pkg, null, 2)}
|
|
26001
26658
|
`, "utf-8");
|
|
26002
26659
|
return {
|
|
26003
26660
|
content: [{
|
|
@@ -26027,8 +26684,8 @@ var init_export_orchestration = __esm({
|
|
|
26027
26684
|
});
|
|
26028
26685
|
|
|
26029
26686
|
// src/mcp/tools/import-orchestration.ts
|
|
26030
|
-
import { readFileSync as
|
|
26031
|
-
import { z as
|
|
26687
|
+
import { readFileSync as readFileSync31 } from "fs";
|
|
26688
|
+
import { z as z71 } from "zod";
|
|
26032
26689
|
function registerImportOrchestration(server) {
|
|
26033
26690
|
server.registerTool(
|
|
26034
26691
|
"import_orchestration",
|
|
@@ -26036,8 +26693,8 @@ function registerImportOrchestration(server) {
|
|
|
26036
26693
|
title: "Import Orchestration",
|
|
26037
26694
|
description: "Import roster, identities, behaviors, and procedures from an orchestration package. Restricted to coordinator/founder.",
|
|
26038
26695
|
inputSchema: {
|
|
26039
|
-
package_path:
|
|
26040
|
-
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")
|
|
26041
26698
|
}
|
|
26042
26699
|
},
|
|
26043
26700
|
async ({ package_path, merge_strategy }) => {
|
|
@@ -26054,7 +26711,7 @@ function registerImportOrchestration(server) {
|
|
|
26054
26711
|
};
|
|
26055
26712
|
}
|
|
26056
26713
|
await initStore();
|
|
26057
|
-
const raw =
|
|
26714
|
+
const raw = readFileSync31(package_path, "utf-8");
|
|
26058
26715
|
const pkg = validatePackage(JSON.parse(raw));
|
|
26059
26716
|
const result = await importOrchestration(pkg, merge_strategy);
|
|
26060
26717
|
return {
|
|
@@ -26086,7 +26743,7 @@ var init_import_orchestration = __esm({
|
|
|
26086
26743
|
});
|
|
26087
26744
|
|
|
26088
26745
|
// src/mcp/tools/global-procedure.ts
|
|
26089
|
-
import { z as
|
|
26746
|
+
import { z as z72 } from "zod";
|
|
26090
26747
|
function registerCompanyProcedureTool(server, toolName) {
|
|
26091
26748
|
server.registerTool(
|
|
26092
26749
|
toolName,
|
|
@@ -26094,12 +26751,12 @@ function registerCompanyProcedureTool(server, toolName) {
|
|
|
26094
26751
|
title: "Company Procedure",
|
|
26095
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).",
|
|
26096
26753
|
inputSchema: {
|
|
26097
|
-
action:
|
|
26098
|
-
title:
|
|
26099
|
-
content:
|
|
26100
|
-
priority:
|
|
26101
|
-
domain:
|
|
26102
|
-
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)")
|
|
26103
26760
|
}
|
|
26104
26761
|
},
|
|
26105
26762
|
async ({ action, title, content, priority, domain, procedure_id }) => {
|
|
@@ -26230,7 +26887,7 @@ var init_global_procedure = __esm({
|
|
|
26230
26887
|
});
|
|
26231
26888
|
|
|
26232
26889
|
// src/mcp/tools/config.ts
|
|
26233
|
-
import { z as
|
|
26890
|
+
import { z as z73 } from "zod";
|
|
26234
26891
|
function errorResult8(text3) {
|
|
26235
26892
|
return { content: [{ type: "text", text: text3 }], isError: true };
|
|
26236
26893
|
}
|
|
@@ -26252,6 +26909,7 @@ function buildHandlers5() {
|
|
|
26252
26909
|
registerRunMemoryAudit(localServer);
|
|
26253
26910
|
registerRunConsolidation(localServer);
|
|
26254
26911
|
registerCloudSync(localServer);
|
|
26912
|
+
registerOrchestrationPhase(localServer);
|
|
26255
26913
|
registerBackupVps(localServer);
|
|
26256
26914
|
registerDeployClient(localServer);
|
|
26257
26915
|
registerGetLicenseStatus(localServer);
|
|
@@ -26274,41 +26932,42 @@ function registerConfig(server) {
|
|
|
26274
26932
|
title: "Config",
|
|
26275
26933
|
description: "Consolidated COO/admin tool for runtime config, system health, licensing, triggers, orchestration import/export, and company procedures.",
|
|
26276
26934
|
inputSchema: {
|
|
26277
|
-
action:
|
|
26278
|
-
agent_id:
|
|
26279
|
-
runtime:
|
|
26280
|
-
model:
|
|
26281
|
-
reasoning_effort:
|
|
26282
|
-
dry_run:
|
|
26283
|
-
fix:
|
|
26284
|
-
verbose:
|
|
26285
|
-
project_name:
|
|
26286
|
-
since:
|
|
26287
|
-
limit:
|
|
26288
|
-
output_path:
|
|
26289
|
-
input_path:
|
|
26290
|
-
strategy:
|
|
26291
|
-
license_key:
|
|
26292
|
-
email:
|
|
26293
|
-
plan:
|
|
26294
|
-
name:
|
|
26295
|
-
event:
|
|
26296
|
-
conditions:
|
|
26297
|
-
actions:
|
|
26298
|
-
enabled:
|
|
26299
|
-
schedule:
|
|
26300
|
-
query:
|
|
26301
|
-
skill_name:
|
|
26302
|
-
pack_name:
|
|
26303
|
-
title:
|
|
26304
|
-
content:
|
|
26305
|
-
priority:
|
|
26306
|
-
domain:
|
|
26307
|
-
procedure_id:
|
|
26308
|
-
subaction:
|
|
26309
|
-
max_clusters:
|
|
26310
|
-
force:
|
|
26311
|
-
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")
|
|
26312
26971
|
}
|
|
26313
26972
|
}, async (input, extra) => {
|
|
26314
26973
|
const action = input.action;
|
|
@@ -26342,6 +27001,7 @@ var init_config2 = __esm({
|
|
|
26342
27001
|
init_run_memory_audit();
|
|
26343
27002
|
init_run_consolidation();
|
|
26344
27003
|
init_cloud_sync2();
|
|
27004
|
+
init_orchestration_phase2();
|
|
26345
27005
|
init_backup_vps();
|
|
26346
27006
|
init_deploy_client();
|
|
26347
27007
|
init_get_license_status();
|
|
@@ -26367,6 +27027,7 @@ var init_config2 = __esm({
|
|
|
26367
27027
|
memory_audit: "run_memory_audit",
|
|
26368
27028
|
run_consolidation: "run_consolidation",
|
|
26369
27029
|
cloud_sync: "cloud_sync",
|
|
27030
|
+
orchestration_phase: "orchestration_phase",
|
|
26370
27031
|
backup_vps: "backup_vps",
|
|
26371
27032
|
deploy_client: "deploy_client",
|
|
26372
27033
|
license_status: "get_license_status",
|
|
@@ -26386,7 +27047,7 @@ var init_config2 = __esm({
|
|
|
26386
27047
|
});
|
|
26387
27048
|
|
|
26388
27049
|
// src/mcp/tools/list-wiki-pages.ts
|
|
26389
|
-
import { z as
|
|
27050
|
+
import { z as z74 } from "zod";
|
|
26390
27051
|
function registerListWikiPages(server) {
|
|
26391
27052
|
server.registerTool(
|
|
26392
27053
|
"list_wiki_pages",
|
|
@@ -26394,8 +27055,8 @@ function registerListWikiPages(server) {
|
|
|
26394
27055
|
title: "List Wiki Pages",
|
|
26395
27056
|
description: "List documents in an exe-wiki workspace. Optionally filter by folder.",
|
|
26396
27057
|
inputSchema: {
|
|
26397
|
-
workspace:
|
|
26398
|
-
folder:
|
|
27058
|
+
workspace: z74.string().describe('Wiki workspace slug (e.g., "hygo")'),
|
|
27059
|
+
folder: z74.string().optional().describe("Filter by folder path")
|
|
26399
27060
|
}
|
|
26400
27061
|
},
|
|
26401
27062
|
async ({ workspace, folder }) => {
|
|
@@ -26491,7 +27152,7 @@ var init_list_wiki_pages = __esm({
|
|
|
26491
27152
|
});
|
|
26492
27153
|
|
|
26493
27154
|
// src/mcp/tools/get-wiki-page.ts
|
|
26494
|
-
import { z as
|
|
27155
|
+
import { z as z75 } from "zod";
|
|
26495
27156
|
function registerGetWikiPage(server) {
|
|
26496
27157
|
server.registerTool(
|
|
26497
27158
|
"get_wiki_page",
|
|
@@ -26499,9 +27160,9 @@ function registerGetWikiPage(server) {
|
|
|
26499
27160
|
title: "Get Wiki Page",
|
|
26500
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.",
|
|
26501
27162
|
inputSchema: {
|
|
26502
|
-
workspace:
|
|
26503
|
-
document_id:
|
|
26504
|
-
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)")
|
|
26505
27166
|
}
|
|
26506
27167
|
},
|
|
26507
27168
|
async ({ workspace, document_id, title }) => {
|
|
@@ -26657,7 +27318,7 @@ var init_get_wiki_page = __esm({
|
|
|
26657
27318
|
});
|
|
26658
27319
|
|
|
26659
27320
|
// src/mcp/tools/wiki.ts
|
|
26660
|
-
import { z as
|
|
27321
|
+
import { z as z76 } from "zod";
|
|
26661
27322
|
function errorResult9(text3) {
|
|
26662
27323
|
return { content: [{ type: "text", text: text3 }], isError: true };
|
|
26663
27324
|
}
|
|
@@ -26683,14 +27344,14 @@ function registerWiki(server) {
|
|
|
26683
27344
|
title: "Wiki",
|
|
26684
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.",
|
|
26685
27346
|
inputSchema: {
|
|
26686
|
-
action:
|
|
26687
|
-
workspace:
|
|
26688
|
-
title:
|
|
26689
|
-
content:
|
|
26690
|
-
folder:
|
|
26691
|
-
document_id:
|
|
26692
|
-
mode:
|
|
26693
|
-
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")
|
|
26694
27355
|
}
|
|
26695
27356
|
},
|
|
26696
27357
|
async (input, extra) => {
|
|
@@ -26729,7 +27390,7 @@ var init_wiki = __esm({
|
|
|
26729
27390
|
});
|
|
26730
27391
|
|
|
26731
27392
|
// src/mcp/tools/behavior.ts
|
|
26732
|
-
import { z as
|
|
27393
|
+
import { z as z77 } from "zod";
|
|
26733
27394
|
function rowToBehavior2(r) {
|
|
26734
27395
|
return {
|
|
26735
27396
|
id: String(r.id),
|
|
@@ -26751,13 +27412,13 @@ function registerBehavior(server) {
|
|
|
26751
27412
|
title: "Behavior",
|
|
26752
27413
|
description: "Manage behavioral patterns, corrections, and reusable procedures for employees. Actions: store (create new), list (query existing), deactivate (soft-delete, restricted).",
|
|
26753
27414
|
inputSchema: {
|
|
26754
|
-
action:
|
|
26755
|
-
content:
|
|
26756
|
-
domain:
|
|
26757
|
-
priority:
|
|
26758
|
-
agent_id:
|
|
26759
|
-
project_name:
|
|
26760
|
-
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)")
|
|
26761
27422
|
}
|
|
26762
27423
|
},
|
|
26763
27424
|
async ({ action, content, domain, priority, agent_id, project_name, behavior_id }) => {
|
|
@@ -26938,7 +27599,7 @@ var init_behavior = __esm({
|
|
|
26938
27599
|
});
|
|
26939
27600
|
|
|
26940
27601
|
// src/mcp/tools/reminder.ts
|
|
26941
|
-
import { z as
|
|
27602
|
+
import { z as z78 } from "zod";
|
|
26942
27603
|
function registerReminder(server) {
|
|
26943
27604
|
server.registerTool(
|
|
26944
27605
|
"reminder",
|
|
@@ -26946,11 +27607,11 @@ function registerReminder(server) {
|
|
|
26946
27607
|
title: "Reminder",
|
|
26947
27608
|
description: "Manage reminders for the founder. Shown in the boot brief every session. Actions: create (set new), list (view active), complete (mark done).",
|
|
26948
27609
|
inputSchema: {
|
|
26949
|
-
action:
|
|
26950
|
-
text:
|
|
26951
|
-
due_date:
|
|
26952
|
-
reminder_id:
|
|
26953
|
-
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)")
|
|
26954
27615
|
}
|
|
26955
27616
|
},
|
|
26956
27617
|
async ({ action, text: text3, due_date, reminder_id, include_completed }) => {
|
|
@@ -27009,7 +27670,7 @@ var init_reminder = __esm({
|
|
|
27009
27670
|
});
|
|
27010
27671
|
|
|
27011
27672
|
// src/mcp/tools/store-global-procedure.ts
|
|
27012
|
-
import { z as
|
|
27673
|
+
import { z as z79 } from "zod";
|
|
27013
27674
|
function registerStoreGlobalProcedure(server) {
|
|
27014
27675
|
server.registerTool(
|
|
27015
27676
|
"store_global_procedure",
|
|
@@ -27017,10 +27678,10 @@ function registerStoreGlobalProcedure(server) {
|
|
|
27017
27678
|
title: "Store Company Procedure (use global_procedure instead)",
|
|
27018
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.",
|
|
27019
27680
|
inputSchema: {
|
|
27020
|
-
title:
|
|
27021
|
-
content:
|
|
27022
|
-
priority:
|
|
27023
|
-
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")
|
|
27024
27685
|
}
|
|
27025
27686
|
},
|
|
27026
27687
|
async ({ title, content, priority, domain }) => {
|
|
@@ -27107,7 +27768,7 @@ var init_list_global_procedures = __esm({
|
|
|
27107
27768
|
});
|
|
27108
27769
|
|
|
27109
27770
|
// src/mcp/tools/deactivate-global-procedure.ts
|
|
27110
|
-
import { z as
|
|
27771
|
+
import { z as z80 } from "zod";
|
|
27111
27772
|
function registerDeactivateGlobalProcedure(server) {
|
|
27112
27773
|
server.registerTool(
|
|
27113
27774
|
"deactivate_global_procedure",
|
|
@@ -27115,7 +27776,7 @@ function registerDeactivateGlobalProcedure(server) {
|
|
|
27115
27776
|
title: "Deactivate Company Procedure (use global_procedure instead)",
|
|
27116
27777
|
description: "DEPRECATED \u2014 use global_procedure with action='deactivate'. Soft-delete a company procedure. RESTRICTED: only coordinator or founder sessions.",
|
|
27117
27778
|
inputSchema: {
|
|
27118
|
-
procedure_id:
|
|
27779
|
+
procedure_id: z80.string().describe("UUID of the company procedure to deactivate")
|
|
27119
27780
|
}
|
|
27120
27781
|
},
|
|
27121
27782
|
async ({ procedure_id }) => {
|
|
@@ -27179,7 +27840,7 @@ var init_deactivate_global_procedure = __esm({
|
|
|
27179
27840
|
});
|
|
27180
27841
|
|
|
27181
27842
|
// src/mcp/tools/store-decision.ts
|
|
27182
|
-
import { z as
|
|
27843
|
+
import { z as z81 } from "zod";
|
|
27183
27844
|
import crypto18 from "crypto";
|
|
27184
27845
|
function registerStoreDecision(server) {
|
|
27185
27846
|
server.registerTool(
|
|
@@ -27188,13 +27849,13 @@ function registerStoreDecision(server) {
|
|
|
27188
27849
|
title: "Store Decision",
|
|
27189
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.",
|
|
27190
27851
|
inputSchema: {
|
|
27191
|
-
domain:
|
|
27852
|
+
domain: z81.string().describe(
|
|
27192
27853
|
"Domain key, e.g. 'auth-strategy', 'db-migration-approach', 'api-versioning'"
|
|
27193
27854
|
),
|
|
27194
|
-
decision:
|
|
27195
|
-
rationale:
|
|
27196
|
-
supersedes:
|
|
27197
|
-
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")
|
|
27198
27859
|
}
|
|
27199
27860
|
},
|
|
27200
27861
|
async ({ domain, decision, rationale, supersedes, project_name }) => {
|
|
@@ -27271,7 +27932,7 @@ var init_store_decision = __esm({
|
|
|
27271
27932
|
});
|
|
27272
27933
|
|
|
27273
27934
|
// src/mcp/tools/get-decision.ts
|
|
27274
|
-
import { z as
|
|
27935
|
+
import { z as z82 } from "zod";
|
|
27275
27936
|
function registerGetDecision(server) {
|
|
27276
27937
|
server.registerTool(
|
|
27277
27938
|
"get_decision",
|
|
@@ -27279,7 +27940,7 @@ function registerGetDecision(server) {
|
|
|
27279
27940
|
title: "Get Decision",
|
|
27280
27941
|
description: "Retrieve the latest authoritative decision for a domain. Returns the current active decision and the supersession history.",
|
|
27281
27942
|
inputSchema: {
|
|
27282
|
-
domain:
|
|
27943
|
+
domain: z82.string().describe(
|
|
27283
27944
|
"Domain key to look up, e.g. 'auth-strategy', 'db-migration-approach'"
|
|
27284
27945
|
)
|
|
27285
27946
|
}
|
|
@@ -27349,10 +28010,10 @@ var init_get_decision = __esm({
|
|
|
27349
28010
|
|
|
27350
28011
|
// src/lib/people.ts
|
|
27351
28012
|
import { readFile as readFile5, writeFile as writeFile6, mkdir as mkdir5 } from "fs/promises";
|
|
27352
|
-
import { existsSync as
|
|
27353
|
-
import
|
|
28013
|
+
import { existsSync as existsSync40, readFileSync as readFileSync32 } from "fs";
|
|
28014
|
+
import path49 from "path";
|
|
27354
28015
|
async function loadPeople() {
|
|
27355
|
-
if (!
|
|
28016
|
+
if (!existsSync40(PEOPLE_PATH)) return [];
|
|
27356
28017
|
try {
|
|
27357
28018
|
const raw = await readFile5(PEOPLE_PATH, "utf-8");
|
|
27358
28019
|
return JSON.parse(raw);
|
|
@@ -27361,7 +28022,7 @@ async function loadPeople() {
|
|
|
27361
28022
|
}
|
|
27362
28023
|
}
|
|
27363
28024
|
async function savePeople(people) {
|
|
27364
|
-
await mkdir5(
|
|
28025
|
+
await mkdir5(path49.dirname(PEOPLE_PATH), { recursive: true });
|
|
27365
28026
|
await writeFile6(PEOPLE_PATH, JSON.stringify(people, null, 2) + "\n", "utf-8");
|
|
27366
28027
|
}
|
|
27367
28028
|
async function addPerson(person) {
|
|
@@ -27387,12 +28048,12 @@ var init_people = __esm({
|
|
|
27387
28048
|
"src/lib/people.ts"() {
|
|
27388
28049
|
"use strict";
|
|
27389
28050
|
init_config();
|
|
27390
|
-
PEOPLE_PATH =
|
|
28051
|
+
PEOPLE_PATH = path49.join(EXE_AI_DIR, "people.json");
|
|
27391
28052
|
}
|
|
27392
28053
|
});
|
|
27393
28054
|
|
|
27394
28055
|
// src/mcp/tools/people-roster.ts
|
|
27395
|
-
import { z as
|
|
28056
|
+
import { z as z83 } from "zod";
|
|
27396
28057
|
function registerAddPerson(server) {
|
|
27397
28058
|
server.registerTool(
|
|
27398
28059
|
"add_person",
|
|
@@ -27400,10 +28061,10 @@ function registerAddPerson(server) {
|
|
|
27400
28061
|
title: "Add Person",
|
|
27401
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.",
|
|
27402
28063
|
inputSchema: {
|
|
27403
|
-
name:
|
|
27404
|
-
role:
|
|
27405
|
-
relationship:
|
|
27406
|
-
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")
|
|
27407
28068
|
}
|
|
27408
28069
|
},
|
|
27409
28070
|
async ({ name, role, relationship, notes }) => {
|
|
@@ -27449,7 +28110,7 @@ function registerGetPerson(server) {
|
|
|
27449
28110
|
title: "Get Person",
|
|
27450
28111
|
description: "Look up a specific person by name from the people roster.",
|
|
27451
28112
|
inputSchema: {
|
|
27452
|
-
name:
|
|
28113
|
+
name: z83.string().describe("Person's name to look up")
|
|
27453
28114
|
}
|
|
27454
28115
|
},
|
|
27455
28116
|
async ({ name }) => {
|
|
@@ -27479,7 +28140,7 @@ var init_people_roster = __esm({
|
|
|
27479
28140
|
});
|
|
27480
28141
|
|
|
27481
28142
|
// src/lib/exe-db-read.ts
|
|
27482
|
-
import
|
|
28143
|
+
import path50 from "path";
|
|
27483
28144
|
import os21 from "os";
|
|
27484
28145
|
import { createRequire as createRequire6 } from "module";
|
|
27485
28146
|
import { pathToFileURL as pathToFileURL6 } from "url";
|
|
@@ -27496,8 +28157,8 @@ async function getExeDbReadClient() {
|
|
|
27496
28157
|
if (!Ctor2) throw new Error(`No PrismaClient export found at ${explicitPath}`);
|
|
27497
28158
|
return new Ctor2();
|
|
27498
28159
|
}
|
|
27499
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
27500
|
-
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"));
|
|
27501
28162
|
const entry = req.resolve("@prisma/client");
|
|
27502
28163
|
const mod = await import(pathToFileURL6(entry).href);
|
|
27503
28164
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -27524,7 +28185,7 @@ var init_exe_db_read = __esm({
|
|
|
27524
28185
|
});
|
|
27525
28186
|
|
|
27526
28187
|
// src/mcp/tools/crm.ts
|
|
27527
|
-
import { z as
|
|
28188
|
+
import { z as z84 } from "zod";
|
|
27528
28189
|
function text(content, isError = false) {
|
|
27529
28190
|
return { content: [{ type: "text", text: content }], ...isError ? { isError: true } : {} };
|
|
27530
28191
|
}
|
|
@@ -27538,12 +28199,12 @@ function registerCrm(server) {
|
|
|
27538
28199
|
title: "CRM",
|
|
27539
28200
|
description: "Read-only CRM access from exe-db crm schema. Actions: list_people, get_person, list_tables, describe_table.",
|
|
27540
28201
|
inputSchema: {
|
|
27541
|
-
action:
|
|
27542
|
-
id:
|
|
27543
|
-
query:
|
|
27544
|
-
table:
|
|
27545
|
-
limit:
|
|
27546
|
-
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")
|
|
27547
28208
|
}
|
|
27548
28209
|
}, async ({ action, id, query, table, limit, offset }) => {
|
|
27549
28210
|
try {
|
|
@@ -27608,7 +28269,7 @@ var init_crm = __esm({
|
|
|
27608
28269
|
});
|
|
27609
28270
|
|
|
27610
28271
|
// src/mcp/tools/raw-data.ts
|
|
27611
|
-
import { z as
|
|
28272
|
+
import { z as z85 } from "zod";
|
|
27612
28273
|
function text2(content, isError = false) {
|
|
27613
28274
|
return { content: [{ type: "text", text: content }], ...isError ? { isError: true } : {} };
|
|
27614
28275
|
}
|
|
@@ -27617,15 +28278,15 @@ function registerRawData(server) {
|
|
|
27617
28278
|
title: "Raw Data",
|
|
27618
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.",
|
|
27619
28280
|
inputSchema: {
|
|
27620
|
-
action:
|
|
27621
|
-
id:
|
|
27622
|
-
source:
|
|
27623
|
-
event_type:
|
|
27624
|
-
query:
|
|
27625
|
-
processed:
|
|
27626
|
-
limit:
|
|
27627
|
-
offset:
|
|
27628
|
-
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.")
|
|
27629
28290
|
}
|
|
27630
28291
|
}, async ({ action, id, source, event_type, query, processed, limit, offset, include_payload }) => {
|
|
27631
28292
|
try {
|
|
@@ -27693,10 +28354,10 @@ var init_raw_data = __esm({
|
|
|
27693
28354
|
});
|
|
27694
28355
|
|
|
27695
28356
|
// src/mcp/tools/create-bug-report.ts
|
|
27696
|
-
import { z as
|
|
28357
|
+
import { z as z86 } from "zod";
|
|
27697
28358
|
import crypto19 from "crypto";
|
|
27698
28359
|
import { mkdir as mkdir6, writeFile as writeFile7 } from "fs/promises";
|
|
27699
|
-
import
|
|
28360
|
+
import path51 from "path";
|
|
27700
28361
|
function slugify2(input) {
|
|
27701
28362
|
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "bug-report";
|
|
27702
28363
|
}
|
|
@@ -27774,22 +28435,22 @@ function registerCreateBugReport(server) {
|
|
|
27774
28435
|
title: "Create Bug Report",
|
|
27775
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.",
|
|
27776
28437
|
inputSchema: {
|
|
27777
|
-
title:
|
|
28438
|
+
title: z86.string().min(3).describe("Short descriptive title"),
|
|
27778
28439
|
classification: CLASSIFICATION.describe(
|
|
27779
28440
|
"upstream_bug = platform defect; customer_customization = local preference; emergency_hotfix = temporary local patch; unclear = needs maintainer triage"
|
|
27780
28441
|
),
|
|
27781
28442
|
severity: SEVERITY.default("p2").describe("p0 critical \u2192 p3 low"),
|
|
27782
|
-
summary:
|
|
27783
|
-
customer_impact:
|
|
27784
|
-
reproduction_steps:
|
|
27785
|
-
expected:
|
|
27786
|
-
actual:
|
|
27787
|
-
files_changed:
|
|
27788
|
-
workaround:
|
|
27789
|
-
local_patch_diff:
|
|
27790
|
-
package_version:
|
|
27791
|
-
project_name:
|
|
27792
|
-
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")
|
|
27793
28454
|
}
|
|
27794
28455
|
},
|
|
27795
28456
|
async ({
|
|
@@ -27829,9 +28490,9 @@ function registerCreateBugReport(server) {
|
|
|
27829
28490
|
filesChanged: files_changed,
|
|
27830
28491
|
projectName: project_name
|
|
27831
28492
|
});
|
|
27832
|
-
const outDir =
|
|
28493
|
+
const outDir = path51.join(EXE_AI_DIR, "bug-reports");
|
|
27833
28494
|
await mkdir6(outDir, { recursive: true });
|
|
27834
|
-
const reportPath =
|
|
28495
|
+
const reportPath = path51.join(outDir, `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}-${slugify2(title)}-${id.slice(0, 8)}.md`);
|
|
27835
28496
|
await writeFile7(reportPath, markdown, "utf-8");
|
|
27836
28497
|
let vector = null;
|
|
27837
28498
|
try {
|
|
@@ -27905,18 +28566,18 @@ var init_create_bug_report = __esm({
|
|
|
27905
28566
|
init_config();
|
|
27906
28567
|
init_license();
|
|
27907
28568
|
init_store();
|
|
27908
|
-
CLASSIFICATION =
|
|
28569
|
+
CLASSIFICATION = z86.enum([
|
|
27909
28570
|
"upstream_bug",
|
|
27910
28571
|
"customer_customization",
|
|
27911
28572
|
"emergency_hotfix",
|
|
27912
28573
|
"unclear"
|
|
27913
28574
|
]);
|
|
27914
|
-
SEVERITY =
|
|
28575
|
+
SEVERITY = z86.enum(["p0", "p1", "p2", "p3"]);
|
|
27915
28576
|
}
|
|
27916
28577
|
});
|
|
27917
28578
|
|
|
27918
28579
|
// src/mcp/tools/support-inbox.ts
|
|
27919
|
-
import { z as
|
|
28580
|
+
import { z as z87 } from "zod";
|
|
27920
28581
|
function adminToken() {
|
|
27921
28582
|
return process.env.ASKEXE_SUPPORT_ADMIN_TOKEN || process.env.EXE_SUPPORT_ADMIN_TOKEN;
|
|
27922
28583
|
}
|
|
@@ -27955,9 +28616,9 @@ function registerListBugReports(server) {
|
|
|
27955
28616
|
title: "List Bug Reports",
|
|
27956
28617
|
description: "AskExe-internal only: list incoming customer bug reports from the support inbox.",
|
|
27957
28618
|
inputSchema: {
|
|
27958
|
-
status:
|
|
27959
|
-
severity:
|
|
27960
|
-
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)
|
|
27961
28622
|
}
|
|
27962
28623
|
},
|
|
27963
28624
|
async ({ status, severity, limit }) => {
|
|
@@ -27976,7 +28637,7 @@ function registerGetBugReport(server) {
|
|
|
27976
28637
|
{
|
|
27977
28638
|
title: "Get Bug Report",
|
|
27978
28639
|
description: "AskExe-internal only: fetch one customer bug report with full markdown payload.",
|
|
27979
|
-
inputSchema: { id:
|
|
28640
|
+
inputSchema: { id: z87.string().min(8) }
|
|
27980
28641
|
},
|
|
27981
28642
|
async ({ id }) => {
|
|
27982
28643
|
const data = await requestJson(`${endpoint()}/${encodeURIComponent(id)}`);
|
|
@@ -27991,12 +28652,12 @@ function registerTriageBugReport(server) {
|
|
|
27991
28652
|
title: "Triage Bug Report",
|
|
27992
28653
|
description: "AskExe-internal only: update bug report status and link task/commit/release metadata.",
|
|
27993
28654
|
inputSchema: {
|
|
27994
|
-
id:
|
|
28655
|
+
id: z87.string().min(8),
|
|
27995
28656
|
status: STATUS.optional(),
|
|
27996
|
-
triage_notes:
|
|
27997
|
-
linked_task_id:
|
|
27998
|
-
linked_commit:
|
|
27999
|
-
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()
|
|
28000
28661
|
}
|
|
28001
28662
|
},
|
|
28002
28663
|
async ({ id, status, triage_notes, linked_task_id, linked_commit, fixed_version }) => {
|
|
@@ -28013,7 +28674,7 @@ var init_support_inbox = __esm({
|
|
|
28013
28674
|
"src/mcp/tools/support-inbox.ts"() {
|
|
28014
28675
|
"use strict";
|
|
28015
28676
|
DEFAULT_ENDPOINT = "https://askexe.com/admin/support/bug-reports";
|
|
28016
|
-
STATUS =
|
|
28677
|
+
STATUS = z87.enum(["open", "triaged", "fixed", "closed", "wontfix"]);
|
|
28017
28678
|
}
|
|
28018
28679
|
});
|
|
28019
28680
|
|
|
@@ -28154,6 +28815,7 @@ var init_tool_gates = __esm({
|
|
|
28154
28815
|
registerRunMemoryAudit: "admin",
|
|
28155
28816
|
registerRunConsolidation: "admin",
|
|
28156
28817
|
registerCloudSync: "admin",
|
|
28818
|
+
registerOrchestrationPhase: "admin",
|
|
28157
28819
|
registerSetAgentConfig: "admin",
|
|
28158
28820
|
registerListEmployees: "admin",
|
|
28159
28821
|
registerGetAgentSpend: "admin",
|
|
@@ -28362,6 +29024,7 @@ function registerAllTools(server) {
|
|
|
28362
29024
|
gate("registerRunMemoryAudit", registerRunMemoryAudit);
|
|
28363
29025
|
gate("registerCloudSync", registerCloudSync);
|
|
28364
29026
|
gate("registerBackupVps", registerBackupVps);
|
|
29027
|
+
gate("registerOrchestrationPhase", registerOrchestrationPhase);
|
|
28365
29028
|
}
|
|
28366
29029
|
if (exposeLegacyMemory) {
|
|
28367
29030
|
gate("registerGetMemoryCardinality", registerGetMemoryCardinality);
|
|
@@ -28473,6 +29136,7 @@ var init_register_tools = __esm({
|
|
|
28473
29136
|
init_raw_data();
|
|
28474
29137
|
init_set_agent_config();
|
|
28475
29138
|
init_list_employees();
|
|
29139
|
+
init_orchestration_phase2();
|
|
28476
29140
|
init_create_license();
|
|
28477
29141
|
init_list_licenses();
|
|
28478
29142
|
init_activate_license();
|
|
@@ -28703,12 +29367,12 @@ __export(task_enforcement_exports, {
|
|
|
28703
29367
|
runTaskEnforcementTick: () => runTaskEnforcementTick,
|
|
28704
29368
|
sendNudge: () => sendNudge
|
|
28705
29369
|
});
|
|
28706
|
-
import { writeFileSync as
|
|
28707
|
-
import
|
|
29370
|
+
import { writeFileSync as writeFileSync23 } from "fs";
|
|
29371
|
+
import path52 from "path";
|
|
28708
29372
|
function writeAuditEntry(entry) {
|
|
28709
29373
|
try {
|
|
28710
29374
|
const line = JSON.stringify(entry) + "\n";
|
|
28711
|
-
|
|
29375
|
+
writeFileSync23(AUDIT_LOG_PATH, line, { flag: "a" });
|
|
28712
29376
|
} catch {
|
|
28713
29377
|
}
|
|
28714
29378
|
}
|
|
@@ -28879,7 +29543,7 @@ var init_task_enforcement = __esm({
|
|
|
28879
29543
|
"What do you need?"
|
|
28880
29544
|
];
|
|
28881
29545
|
MANAGER_ROLES = ["COO", "CTO"];
|
|
28882
|
-
AUDIT_LOG_PATH =
|
|
29546
|
+
AUDIT_LOG_PATH = path52.join(
|
|
28883
29547
|
process.env.HOME ?? process.env.USERPROFILE ?? "/tmp",
|
|
28884
29548
|
".exe-os",
|
|
28885
29549
|
"enforcement-audit.jsonl"
|
|
@@ -28896,11 +29560,11 @@ __export(update_check_exports, {
|
|
|
28896
29560
|
getRemoteVersion: () => getRemoteVersion
|
|
28897
29561
|
});
|
|
28898
29562
|
import { execSync as execSync15 } from "child_process";
|
|
28899
|
-
import { readFileSync as
|
|
28900
|
-
import
|
|
29563
|
+
import { readFileSync as readFileSync33 } from "fs";
|
|
29564
|
+
import path53 from "path";
|
|
28901
29565
|
function getLocalVersion(packageRoot) {
|
|
28902
|
-
const pkgPath =
|
|
28903
|
-
const pkg = JSON.parse(
|
|
29566
|
+
const pkgPath = path53.join(packageRoot, "package.json");
|
|
29567
|
+
const pkg = JSON.parse(readFileSync33(pkgPath, "utf-8"));
|
|
28904
29568
|
return pkg.version;
|
|
28905
29569
|
}
|
|
28906
29570
|
function getRemoteVersion() {
|
|
@@ -28972,12 +29636,12 @@ __export(device_registry_exports, {
|
|
|
28972
29636
|
});
|
|
28973
29637
|
import crypto21 from "crypto";
|
|
28974
29638
|
import os22 from "os";
|
|
28975
|
-
import { readFileSync as
|
|
28976
|
-
import
|
|
29639
|
+
import { readFileSync as readFileSync34, writeFileSync as writeFileSync24, mkdirSync as mkdirSync20, existsSync as existsSync41 } from "fs";
|
|
29640
|
+
import path54 from "path";
|
|
28977
29641
|
function getDeviceInfo() {
|
|
28978
|
-
if (
|
|
29642
|
+
if (existsSync41(DEVICE_JSON_PATH)) {
|
|
28979
29643
|
try {
|
|
28980
|
-
const raw =
|
|
29644
|
+
const raw = readFileSync34(DEVICE_JSON_PATH, "utf8");
|
|
28981
29645
|
const data = JSON.parse(raw);
|
|
28982
29646
|
if (data.deviceId && data.friendlyName && data.hostname) {
|
|
28983
29647
|
return data;
|
|
@@ -28991,14 +29655,14 @@ function getDeviceInfo() {
|
|
|
28991
29655
|
friendlyName: hostname.replace(/\./g, "-").toLowerCase(),
|
|
28992
29656
|
hostname
|
|
28993
29657
|
};
|
|
28994
|
-
|
|
28995
|
-
|
|
29658
|
+
mkdirSync20(path54.dirname(DEVICE_JSON_PATH), { recursive: true });
|
|
29659
|
+
writeFileSync24(DEVICE_JSON_PATH, JSON.stringify(info, null, 2));
|
|
28996
29660
|
return info;
|
|
28997
29661
|
}
|
|
28998
29662
|
function setFriendlyName(name) {
|
|
28999
29663
|
const info = getDeviceInfo();
|
|
29000
29664
|
info.friendlyName = name;
|
|
29001
|
-
|
|
29665
|
+
writeFileSync24(DEVICE_JSON_PATH, JSON.stringify(info, null, 2));
|
|
29002
29666
|
}
|
|
29003
29667
|
async function resolveTargetDevice(targetAgent, targetProject) {
|
|
29004
29668
|
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
@@ -29032,7 +29696,7 @@ var init_device_registry = __esm({
|
|
|
29032
29696
|
"src/lib/device-registry.ts"() {
|
|
29033
29697
|
"use strict";
|
|
29034
29698
|
init_config();
|
|
29035
|
-
DEVICE_JSON_PATH =
|
|
29699
|
+
DEVICE_JSON_PATH = path54.join(EXE_AI_DIR, "device.json");
|
|
29036
29700
|
}
|
|
29037
29701
|
});
|
|
29038
29702
|
|
|
@@ -29248,8 +29912,8 @@ import os23 from "os";
|
|
|
29248
29912
|
import net2 from "net";
|
|
29249
29913
|
import { createServer as createHttpServer } from "http";
|
|
29250
29914
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
29251
|
-
import { writeFileSync as
|
|
29252
|
-
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";
|
|
29253
29917
|
|
|
29254
29918
|
// src/lib/orchestration-metrics.ts
|
|
29255
29919
|
init_config();
|
|
@@ -29321,8 +29985,8 @@ function initMetrics() {
|
|
|
29321
29985
|
|
|
29322
29986
|
// src/lib/exe-daemon.ts
|
|
29323
29987
|
init_memory_write_governor();
|
|
29324
|
-
var SOCKET_PATH2 = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
29325
|
-
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");
|
|
29326
29990
|
var MODEL_FILE = "jina-embeddings-v5-small-q4_k_m.gguf";
|
|
29327
29991
|
var IDLE_TIMEOUT_MS2 = 15 * 60 * 1e3;
|
|
29328
29992
|
var REVIEW_POLL_INTERVAL_MS = 60 * 1e3;
|
|
@@ -29350,8 +30014,8 @@ function enqueue(queue, entry) {
|
|
|
29350
30014
|
queue.push(entry);
|
|
29351
30015
|
}
|
|
29352
30016
|
async function loadModel() {
|
|
29353
|
-
const modelPath =
|
|
29354
|
-
if (!
|
|
30017
|
+
const modelPath = path55.join(MODELS_DIR, MODEL_FILE);
|
|
30018
|
+
if (!existsSync42(modelPath)) {
|
|
29355
30019
|
process.stderr.write(`[exed] No model at ${modelPath} \u2014 running without embeddings (VPS mode).
|
|
29356
30020
|
`);
|
|
29357
30021
|
return;
|
|
@@ -29749,17 +30413,17 @@ function startMemoryQueueDrain() {
|
|
|
29749
30413
|
`);
|
|
29750
30414
|
}
|
|
29751
30415
|
function startServer() {
|
|
29752
|
-
|
|
30416
|
+
mkdirSync21(path55.dirname(SOCKET_PATH2), { recursive: true });
|
|
29753
30417
|
try {
|
|
29754
|
-
chmodSync2(
|
|
30418
|
+
chmodSync2(path55.dirname(SOCKET_PATH2), 448);
|
|
29755
30419
|
} catch {
|
|
29756
30420
|
}
|
|
29757
30421
|
_daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV2] ?? null);
|
|
29758
30422
|
for (const oldFile of ["embed.sock", "embed.pid"]) {
|
|
29759
|
-
const oldPath =
|
|
30423
|
+
const oldPath = path55.join(path55.dirname(SOCKET_PATH2), oldFile);
|
|
29760
30424
|
try {
|
|
29761
30425
|
if (oldFile.endsWith(".pid")) {
|
|
29762
|
-
const pid = parseInt(
|
|
30426
|
+
const pid = parseInt(readFileSync35(oldPath, "utf8").trim(), 10);
|
|
29763
30427
|
if (pid > 0) try {
|
|
29764
30428
|
process.kill(pid, "SIGKILL");
|
|
29765
30429
|
} catch {
|
|
@@ -30232,7 +30896,7 @@ function startGraphExtraction() {
|
|
|
30232
30896
|
`);
|
|
30233
30897
|
}
|
|
30234
30898
|
var AGENT_STATS_INTERVAL_MS = 60 * 1e3;
|
|
30235
|
-
var AGENT_STATS_PATH =
|
|
30899
|
+
var AGENT_STATS_PATH = path55.join(EXE_AI_DIR, "agent-stats.json");
|
|
30236
30900
|
async function writeAgentStats() {
|
|
30237
30901
|
fired("agent_stats");
|
|
30238
30902
|
if (!await ensureStoreForPolling()) return;
|
|
@@ -30292,7 +30956,7 @@ async function writeAgentStats() {
|
|
|
30292
30956
|
pid: process.pid
|
|
30293
30957
|
}
|
|
30294
30958
|
};
|
|
30295
|
-
|
|
30959
|
+
writeFileSync25(AGENT_STATS_PATH, JSON.stringify(stats, null, 2), "utf8");
|
|
30296
30960
|
} catch (err) {
|
|
30297
30961
|
process.stderr.write(`[exed] Agent stats error: ${err instanceof Error ? err.message : String(err)}
|
|
30298
30962
|
`);
|
|
@@ -30409,12 +31073,12 @@ function startIntercomQueueDrain() {
|
|
|
30409
31073
|
const hasInProgressTask = (session) => {
|
|
30410
31074
|
try {
|
|
30411
31075
|
const { baseAgentName: ban } = (init_employees(), __toCommonJS(employees_exports));
|
|
30412
|
-
const
|
|
30413
|
-
const { existsSync:
|
|
31076
|
+
const path56 = __require("path");
|
|
31077
|
+
const { existsSync: existsSync43 } = __require("fs");
|
|
30414
31078
|
const os24 = __require("os");
|
|
30415
31079
|
const agent = ban(session.split("-")[0] ?? session);
|
|
30416
|
-
const markerPath =
|
|
30417
|
-
return
|
|
31080
|
+
const markerPath = path56.join(os24.homedir(), ".exe-os", "session-cache", `current-task-${agent}.json`);
|
|
31081
|
+
return existsSync43(markerPath);
|
|
30418
31082
|
} catch {
|
|
30419
31083
|
return false;
|
|
30420
31084
|
}
|
|
@@ -30578,8 +31242,8 @@ process.on("SIGINT", () => void shutdown());
|
|
|
30578
31242
|
process.on("SIGTERM", () => void shutdown());
|
|
30579
31243
|
function checkExistingDaemon() {
|
|
30580
31244
|
try {
|
|
30581
|
-
if (!
|
|
30582
|
-
const pid = parseInt(
|
|
31245
|
+
if (!existsSync42(PID_PATH3)) return false;
|
|
31246
|
+
const pid = parseInt(readFileSync35(PID_PATH3, "utf8").trim(), 10);
|
|
30583
31247
|
if (!pid || isNaN(pid)) return false;
|
|
30584
31248
|
process.kill(pid, 0);
|
|
30585
31249
|
process.stderr.write(`[exed] Another daemon is already running (PID ${pid}). Exiting.
|
|
@@ -30649,7 +31313,7 @@ function startAutoUpdateCheck() {
|
|
|
30649
31313
|
if (checkExistingDaemon()) {
|
|
30650
31314
|
process.exit(0);
|
|
30651
31315
|
}
|
|
30652
|
-
|
|
31316
|
+
writeFileSync25(PID_PATH3, String(process.pid));
|
|
30653
31317
|
try {
|
|
30654
31318
|
chmodSync2(PID_PATH3, 384);
|
|
30655
31319
|
} catch {
|