@askexenow/exe-os 0.9.65 → 0.9.66

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