@askexenow/exe-os 0.9.64 → 0.9.66

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +2280 -1199
  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 +116 -7
  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 +310 -178
  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 +412 -157
  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 +195 -79
  64. package/dist/index.js +24 -0
  65. package/dist/lib/agent-config.js +4 -0
  66. package/dist/lib/cloud-sync.js +50 -6
  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 +1144 -480
  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 +1045 -427
  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
@@ -158,6 +158,11 @@ function normalizeAutoUpdate(raw) {
158
158
  const userAU = raw.autoUpdate ?? {};
159
159
  raw.autoUpdate = { ...defaultAU, ...userAU };
160
160
  }
161
+ function normalizeOrchestration(raw) {
162
+ const defaultOrg = DEFAULT_CONFIG.orchestration;
163
+ const userOrg = raw.orchestration ?? {};
164
+ raw.orchestration = { ...defaultOrg, ...userOrg };
165
+ }
161
166
  async function loadConfig() {
162
167
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
163
168
  await ensurePrivateDir(dir);
@@ -182,6 +187,7 @@ async function loadConfig() {
182
187
  normalizeScalingRoadmap(migratedCfg);
183
188
  normalizeSessionLifecycle(migratedCfg);
184
189
  normalizeAutoUpdate(migratedCfg);
190
+ normalizeOrchestration(migratedCfg);
185
191
  const config2 = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
186
192
  if (config2.dbPath.startsWith("~")) {
187
193
  config2.dbPath = config2.dbPath.replace(/^~/, os.homedir());
@@ -205,6 +211,7 @@ function loadConfigSync() {
205
211
  normalizeScalingRoadmap(migratedCfg);
206
212
  normalizeSessionLifecycle(migratedCfg);
207
213
  normalizeAutoUpdate(migratedCfg);
214
+ normalizeOrchestration(migratedCfg);
208
215
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
209
216
  } catch {
210
217
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
@@ -226,6 +233,7 @@ async function loadConfigFrom(configPath) {
226
233
  normalizeScalingRoadmap(migratedCfg);
227
234
  normalizeSessionLifecycle(migratedCfg);
228
235
  normalizeAutoUpdate(migratedCfg);
236
+ normalizeOrchestration(migratedCfg);
229
237
  return { ...DEFAULT_CONFIG, ...migratedCfg };
230
238
  } catch {
231
239
  return { ...DEFAULT_CONFIG };
@@ -297,6 +305,10 @@ var init_config = __esm({
297
305
  checkOnBoot: true,
298
306
  autoInstall: false,
299
307
  checkIntervalMs: 24 * 60 * 60 * 1e3
308
+ },
309
+ orchestration: {
310
+ phase: "phase_1_coo",
311
+ phaseSetBy: "default"
300
312
  }
301
313
  };
302
314
  CONFIG_MIGRATIONS = [
@@ -849,10 +861,10 @@ async function disposeEmbedder() {
849
861
  async function embedDirect(text3) {
850
862
  const llamaCpp = await import("node-llama-cpp");
851
863
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
852
- const { existsSync: existsSync37 } = await import("fs");
853
- const path48 = await import("path");
854
- const modelPath = path48.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
855
- if (!existsSync37(modelPath)) {
864
+ const { existsSync: existsSync38 } = await import("fs");
865
+ const path49 = await import("path");
866
+ const modelPath = path49.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
867
+ if (!existsSync38(modelPath)) {
856
868
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
857
869
  }
858
870
  const llama = await llamaCpp.getLlama();
@@ -1893,6 +1905,15 @@ var init_database_adapter = __esm({
1893
1905
  });
1894
1906
 
1895
1907
  // src/lib/daemon-protocol.ts
1908
+ var daemon_protocol_exports = {};
1909
+ __export(daemon_protocol_exports, {
1910
+ deserializeArgs: () => deserializeArgs,
1911
+ deserializeResultSet: () => deserializeResultSet,
1912
+ deserializeValue: () => deserializeValue,
1913
+ serializeArgs: () => serializeArgs,
1914
+ serializeResultSet: () => serializeResultSet,
1915
+ serializeValue: () => serializeValue
1916
+ });
1896
1917
  function serializeValue(v) {
1897
1918
  if (v === null || v === void 0) return null;
1898
1919
  if (typeof v === "bigint") return Number(v);
@@ -1917,6 +1938,32 @@ function deserializeValue(v) {
1917
1938
  }
1918
1939
  return v;
1919
1940
  }
1941
+ function serializeArgs(args) {
1942
+ return args.map(serializeValue);
1943
+ }
1944
+ function deserializeArgs(args) {
1945
+ return args.map(deserializeValue);
1946
+ }
1947
+ function serializeResultSet(rs) {
1948
+ const rows = [];
1949
+ for (const row of rs.rows) {
1950
+ const obj = {};
1951
+ for (let i = 0; i < rs.columns.length; i++) {
1952
+ const col = rs.columns[i];
1953
+ if (col !== void 0) {
1954
+ obj[col] = serializeValue(row[i]);
1955
+ }
1956
+ }
1957
+ rows.push(obj);
1958
+ }
1959
+ return {
1960
+ columns: [...rs.columns],
1961
+ columnTypes: [...rs.columnTypes ?? []],
1962
+ rows,
1963
+ rowsAffected: typeof rs.rowsAffected === "bigint" ? Number(rs.rowsAffected) : rs.rowsAffected ?? 0,
1964
+ lastInsertRowid: rs.lastInsertRowid != null ? typeof rs.lastInsertRowid === "bigint" ? Number(rs.lastInsertRowid) : rs.lastInsertRowid : null
1965
+ };
1966
+ }
1920
1967
  function deserializeResultSet(srs) {
1921
1968
  const rows = srs.rows.map((obj) => {
1922
1969
  const values = srs.columns.map(
@@ -3468,8 +3515,8 @@ function deriveMachineKey() {
3468
3515
  }
3469
3516
  function readMachineId() {
3470
3517
  try {
3471
- const { readFileSync: readFileSync30 } = __require("fs");
3472
- return readFileSync30("/etc/machine-id", "utf-8").trim();
3518
+ const { readFileSync: readFileSync31 } = __require("fs");
3519
+ return readFileSync31("/etc/machine-id", "utf-8").trim();
3473
3520
  } catch {
3474
3521
  return "";
3475
3522
  }
@@ -4369,6 +4416,12 @@ var init_platform_procedures = __esm({
4369
4416
  priority: "p0",
4370
4417
  content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
4371
4418
  },
4419
+ {
4420
+ title: "Customer orchestration maturity \u2014 recommend, never trap",
4421
+ domain: "workflow",
4422
+ priority: "p1",
4423
+ content: "New customers start best in Phase 1: founder \u2194 coordinator/Chief of Staff, building company context. Suggest Phase 2 executives when domain work repeats; suggest Phase 3 parallel execution only when review/permission gates are ready. This is guidance, not a blocker: users may jump phases anytime. Never overwrite their phase, role titles, identities, or custom org design."
4424
+ },
4372
4425
  {
4373
4426
  title: "Single dispatch path \u2014 create_task only",
4374
4427
  domain: "workflow",
@@ -4427,6 +4480,12 @@ var init_platform_procedures = __esm({
4427
4480
  priority: "p0",
4428
4481
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
4429
4482
  },
4483
+ {
4484
+ title: "Commit discipline \u2014 never leave verified work floating",
4485
+ domain: "workflow",
4486
+ priority: "p1",
4487
+ content: "After any code-change batch passes typecheck/tests/build, run git status, summarize changed files, and commit with a clear message before ending the session. If work must remain uncommitted for review/dogfood, explicitly say so, list the files, and state the blocker. Never imply work is complete while verified changes are still floating locally."
4488
+ },
4430
4489
  {
4431
4490
  title: "Desktop and TUI are the same product",
4432
4491
  domain: "architecture",
@@ -6643,10 +6702,10 @@ async function hybridSearch(queryText, agentId, options) {
6643
6702
  };
6644
6703
  try {
6645
6704
  const fs = await import("fs");
6646
- const path48 = await import("path");
6705
+ const path49 = await import("path");
6647
6706
  const os21 = await import("os");
6648
- const logPath = path48.join(os21.homedir(), ".exe-os", "search-quality.jsonl");
6649
- fs.mkdirSync(path48.dirname(logPath), { recursive: true });
6707
+ const logPath = path49.join(os21.homedir(), ".exe-os", "search-quality.jsonl");
6708
+ fs.mkdirSync(path49.dirname(logPath), { recursive: true });
6650
6709
  fs.appendFileSync(logPath, JSON.stringify(logEntry) + "\n");
6651
6710
  } catch {
6652
6711
  }
@@ -7938,8 +7997,8 @@ __export(wiki_client_exports, {
7938
7997
  listDocuments: () => listDocuments,
7939
7998
  listWorkspaces: () => listWorkspaces
7940
7999
  });
7941
- async function wikiFetch(config2, path48, method = "GET", body) {
7942
- const url = `${config2.baseUrl}/api/v1${path48}`;
8000
+ async function wikiFetch(config2, path49, method = "GET", body) {
8001
+ const url = `${config2.baseUrl}/api/v1${path49}`;
7943
8002
  const headers = {
7944
8003
  Authorization: `Bearer ${config2.apiKey}`,
7945
8004
  "Content-Type": "application/json"
@@ -7972,7 +8031,7 @@ async function wikiFetch(config2, path48, method = "GET", body) {
7972
8031
  }
7973
8032
  }
7974
8033
  if (!response.ok) {
7975
- throw new Error(`Wiki API ${method} ${path48}: ${response.status} ${response.statusText}`);
8034
+ throw new Error(`Wiki API ${method} ${path49}: ${response.status} ${response.statusText}`);
7976
8035
  }
7977
8036
  return response.json();
7978
8037
  } finally {
@@ -12853,6 +12912,119 @@ var init_worker_gate = __esm({
12853
12912
  }
12854
12913
  });
12855
12914
 
12915
+ // src/lib/key-backup-status.ts
12916
+ var key_backup_status_exports = {};
12917
+ __export(key_backup_status_exports, {
12918
+ getKeyBackupStatus: () => getKeyBackupStatus,
12919
+ keyBackupMarkerPath: () => keyBackupMarkerPath,
12920
+ markKeyBackupConfirmed: () => markKeyBackupConfirmed
12921
+ });
12922
+ import { existsSync as existsSync26, mkdirSync as mkdirSync12, readFileSync as readFileSync20, writeFileSync as writeFileSync15 } from "fs";
12923
+ import path31 from "path";
12924
+ function keyBackupMarkerPath() {
12925
+ return path31.join(EXE_AI_DIR, "key-backup-confirmed.json");
12926
+ }
12927
+ function getKeyBackupStatus() {
12928
+ const marker = keyBackupMarkerPath();
12929
+ if (!existsSync26(marker)) return { exists: false };
12930
+ try {
12931
+ const parsed = JSON.parse(readFileSync20(marker, "utf8"));
12932
+ return {
12933
+ exists: true,
12934
+ confirmedAt: parsed.confirmedAt,
12935
+ source: parsed.source
12936
+ };
12937
+ } catch {
12938
+ return { exists: true };
12939
+ }
12940
+ }
12941
+ function markKeyBackupConfirmed(source) {
12942
+ mkdirSync12(EXE_AI_DIR, { recursive: true, mode: 448 });
12943
+ writeFileSync15(
12944
+ keyBackupMarkerPath(),
12945
+ JSON.stringify({ confirmedAt: (/* @__PURE__ */ new Date()).toISOString(), source }, null, 2) + "\n",
12946
+ { mode: 384 }
12947
+ );
12948
+ }
12949
+ var init_key_backup_status = __esm({
12950
+ "src/lib/key-backup-status.ts"() {
12951
+ "use strict";
12952
+ init_config();
12953
+ }
12954
+ });
12955
+
12956
+ // src/bin/fast-db-init.ts
12957
+ var fast_db_init_exports = {};
12958
+ __export(fast_db_init_exports, {
12959
+ fastDbInit: () => fastDbInit
12960
+ });
12961
+ async function fastDbInit() {
12962
+ const { isInitialized: isInitialized2, getClient: getClient2, setExternalClient: setExternalClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
12963
+ if (isInitialized2()) {
12964
+ return getClient2();
12965
+ }
12966
+ try {
12967
+ const { connectEmbedDaemon: connectEmbedDaemon2, sendDaemonRequest: sendDaemonRequest2, isClientConnected: isClientConnected2 } = await Promise.resolve().then(() => (init_exe_daemon_client(), exe_daemon_client_exports));
12968
+ const { deserializeResultSet: deserializeResultSet2 } = await Promise.resolve().then(() => (init_daemon_protocol(), daemon_protocol_exports));
12969
+ await connectEmbedDaemon2();
12970
+ if (isClientConnected2()) {
12971
+ const daemonClient = {
12972
+ async execute(stmt) {
12973
+ const sql = typeof stmt === "string" ? stmt : stmt.sql;
12974
+ const args = typeof stmt === "string" ? [] : Array.isArray(stmt.args) ? stmt.args : [];
12975
+ const resp = await sendDaemonRequest2({ type: "db-execute", sql, args });
12976
+ if (resp.error) throw new Error(String(resp.error));
12977
+ if (resp.db) return deserializeResultSet2(resp.db);
12978
+ throw new Error("Unexpected daemon response");
12979
+ },
12980
+ async batch(stmts, mode) {
12981
+ const statements = stmts.map((s) => {
12982
+ const sql = typeof s === "string" ? s : s.sql;
12983
+ const args = typeof s === "string" ? [] : Array.isArray(s.args) ? s.args : [];
12984
+ return { sql, args };
12985
+ });
12986
+ const resp = await sendDaemonRequest2({ type: "db-batch", statements, mode: mode ?? "deferred" });
12987
+ if (resp.error) throw new Error(String(resp.error));
12988
+ const batchResults = resp["db-batch"];
12989
+ if (batchResults) return batchResults.map(deserializeResultSet2);
12990
+ throw new Error("Unexpected daemon batch response");
12991
+ },
12992
+ async transaction(_mode) {
12993
+ throw new Error("Transactions not supported via daemon socket");
12994
+ },
12995
+ async executeMultiple(_sql) {
12996
+ throw new Error("executeMultiple not supported via daemon socket");
12997
+ },
12998
+ async migrate(_stmts) {
12999
+ throw new Error("migrate not supported via daemon socket");
13000
+ },
13001
+ sync() {
13002
+ return Promise.resolve(void 0);
13003
+ },
13004
+ close() {
13005
+ },
13006
+ get closed() {
13007
+ return false;
13008
+ },
13009
+ get protocol() {
13010
+ return "file";
13011
+ }
13012
+ };
13013
+ setExternalClient2(daemonClient);
13014
+ return daemonClient;
13015
+ }
13016
+ } catch {
13017
+ }
13018
+ const { initStore: initStore2 } = await Promise.resolve().then(() => (init_store(), store_exports));
13019
+ await initStore2({ lightweight: true });
13020
+ return getClient2();
13021
+ }
13022
+ var init_fast_db_init = __esm({
13023
+ "src/bin/fast-db-init.ts"() {
13024
+ "use strict";
13025
+ }
13026
+ });
13027
+
12856
13028
  // src/lib/db-backup.ts
12857
13029
  var db_backup_exports = {};
12858
13030
  __export(db_backup_exports, {
@@ -12864,33 +13036,33 @@ __export(db_backup_exports, {
12864
13036
  listBackups: () => listBackups,
12865
13037
  rotateBackups: () => rotateBackups
12866
13038
  });
12867
- import { copyFileSync, existsSync as existsSync26, mkdirSync as mkdirSync12, readdirSync as readdirSync10, unlinkSync as unlinkSync9, statSync as statSync4 } from "fs";
12868
- import path31 from "path";
13039
+ import { copyFileSync, existsSync as existsSync27, mkdirSync as mkdirSync13, readdirSync as readdirSync10, unlinkSync as unlinkSync9, statSync as statSync4 } from "fs";
13040
+ import path32 from "path";
12869
13041
  function findActiveDb() {
12870
13042
  for (const name of DB_NAMES) {
12871
- const p = path31.join(EXE_AI_DIR, name);
12872
- if (existsSync26(p)) return p;
13043
+ const p = path32.join(EXE_AI_DIR, name);
13044
+ if (existsSync27(p)) return p;
12873
13045
  }
12874
13046
  return null;
12875
13047
  }
12876
13048
  function createBackup(reason = "manual") {
12877
13049
  const dbPath = findActiveDb();
12878
13050
  if (!dbPath) return null;
12879
- mkdirSync12(BACKUP_DIR, { recursive: true });
12880
- const dbName = path31.basename(dbPath, ".db");
13051
+ mkdirSync13(BACKUP_DIR, { recursive: true });
13052
+ const dbName = path32.basename(dbPath, ".db");
12881
13053
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
12882
13054
  const backupName = `${dbName}-${reason}-${timestamp}.db`;
12883
- const backupPath = path31.join(BACKUP_DIR, backupName);
13055
+ const backupPath = path32.join(BACKUP_DIR, backupName);
12884
13056
  copyFileSync(dbPath, backupPath);
12885
13057
  const walPath = dbPath + "-wal";
12886
- if (existsSync26(walPath)) {
13058
+ if (existsSync27(walPath)) {
12887
13059
  try {
12888
13060
  copyFileSync(walPath, backupPath + "-wal");
12889
13061
  } catch {
12890
13062
  }
12891
13063
  }
12892
13064
  const shmPath = dbPath + "-shm";
12893
- if (existsSync26(shmPath)) {
13065
+ if (existsSync27(shmPath)) {
12894
13066
  try {
12895
13067
  copyFileSync(shmPath, backupPath + "-shm");
12896
13068
  } catch {
@@ -12899,14 +13071,14 @@ function createBackup(reason = "manual") {
12899
13071
  return backupPath;
12900
13072
  }
12901
13073
  function rotateBackups(keepDays = DEFAULT_KEEP_DAYS) {
12902
- if (!existsSync26(BACKUP_DIR)) return 0;
13074
+ if (!existsSync27(BACKUP_DIR)) return 0;
12903
13075
  const cutoff = Date.now() - keepDays * 24 * 60 * 60 * 1e3;
12904
13076
  let deleted = 0;
12905
13077
  try {
12906
13078
  const files = readdirSync10(BACKUP_DIR);
12907
13079
  for (const file of files) {
12908
13080
  if (!file.endsWith(".db") && !file.endsWith(".db-wal") && !file.endsWith(".db-shm")) continue;
12909
- const filePath = path31.join(BACKUP_DIR, file);
13081
+ const filePath = path32.join(BACKUP_DIR, file);
12910
13082
  try {
12911
13083
  const stat = statSync4(filePath);
12912
13084
  if (stat.mtimeMs < cutoff) {
@@ -12921,11 +13093,11 @@ function rotateBackups(keepDays = DEFAULT_KEEP_DAYS) {
12921
13093
  return deleted;
12922
13094
  }
12923
13095
  function listBackups() {
12924
- if (!existsSync26(BACKUP_DIR)) return [];
13096
+ if (!existsSync27(BACKUP_DIR)) return [];
12925
13097
  try {
12926
13098
  const files = readdirSync10(BACKUP_DIR).filter((f) => f.endsWith(".db") && !f.endsWith("-wal") && !f.endsWith("-shm"));
12927
13099
  return files.map((name) => {
12928
- const p = path31.join(BACKUP_DIR, name);
13100
+ const p = path32.join(BACKUP_DIR, name);
12929
13101
  const stat = statSync4(p);
12930
13102
  return { path: p, name, size: stat.size, date: stat.mtime };
12931
13103
  }).sort((a, b) => b.date.getTime() - a.date.getTime());
@@ -12950,7 +13122,7 @@ var init_db_backup = __esm({
12950
13122
  "src/lib/db-backup.ts"() {
12951
13123
  "use strict";
12952
13124
  init_config();
12953
- BACKUP_DIR = path31.join(EXE_AI_DIR, "backups");
13125
+ BACKUP_DIR = path32.join(EXE_AI_DIR, "backups");
12954
13126
  DEFAULT_KEEP_DAYS = 3;
12955
13127
  DB_NAMES = ["memories.db", "exe-mem.db", "exe-os.db", "exe.db"];
12956
13128
  }
@@ -12975,8 +13147,8 @@ __export(crdt_sync_exports, {
12975
13147
  rebuildFromDb: () => rebuildFromDb
12976
13148
  });
12977
13149
  import * as Y from "yjs";
12978
- import { readFileSync as readFileSync21, writeFileSync as writeFileSync15, existsSync as existsSync28, mkdirSync as mkdirSync13, unlinkSync as unlinkSync10 } from "fs";
12979
- import path33 from "path";
13150
+ import { readFileSync as readFileSync22, writeFileSync as writeFileSync16, existsSync as existsSync29, mkdirSync as mkdirSync14, unlinkSync as unlinkSync10 } from "fs";
13151
+ import path34 from "path";
12980
13152
  import { homedir as homedir5 } from "os";
12981
13153
  function getStatePath() {
12982
13154
  return _statePathOverride ?? DEFAULT_STATE_PATH;
@@ -12988,9 +13160,9 @@ function initCrdtDoc() {
12988
13160
  if (doc) return doc;
12989
13161
  doc = new Y.Doc();
12990
13162
  const sp = getStatePath();
12991
- if (existsSync28(sp)) {
13163
+ if (existsSync29(sp)) {
12992
13164
  try {
12993
- const state = readFileSync21(sp);
13165
+ const state = readFileSync22(sp);
12994
13166
  Y.applyUpdate(doc, new Uint8Array(state));
12995
13167
  } catch {
12996
13168
  console.warn("[crdt-sync] WARN: corrupted state file, rebuilding from DB");
@@ -13132,10 +13304,10 @@ function persistState() {
13132
13304
  if (!doc) return;
13133
13305
  try {
13134
13306
  const sp = getStatePath();
13135
- const dir = path33.dirname(sp);
13136
- if (!existsSync28(dir)) mkdirSync13(dir, { recursive: true });
13307
+ const dir = path34.dirname(sp);
13308
+ if (!existsSync29(dir)) mkdirSync14(dir, { recursive: true });
13137
13309
  const state = Y.encodeStateAsUpdate(doc);
13138
- writeFileSync15(sp, Buffer.from(state));
13310
+ writeFileSync16(sp, Buffer.from(state));
13139
13311
  } catch {
13140
13312
  }
13141
13313
  }
@@ -13176,7 +13348,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
13176
13348
  var init_crdt_sync = __esm({
13177
13349
  "src/lib/crdt-sync.ts"() {
13178
13350
  "use strict";
13179
- DEFAULT_STATE_PATH = path33.join(homedir5(), ".exe-os", "crdt-state.bin");
13351
+ DEFAULT_STATE_PATH = path34.join(homedir5(), ".exe-os", "crdt-state.bin");
13180
13352
  _statePathOverride = null;
13181
13353
  doc = null;
13182
13354
  }
@@ -13189,8 +13361,8 @@ init_database();
13189
13361
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
13190
13362
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
13191
13363
  import { spawn as spawn4 } from "child_process";
13192
- import { existsSync as existsSync36, openSync as openSync3, mkdirSync as mkdirSync19, closeSync as closeSync3, readFileSync as readFileSync29 } from "fs";
13193
- import path47 from "path";
13364
+ import { existsSync as existsSync37, openSync as openSync3, mkdirSync as mkdirSync20, closeSync as closeSync3, readFileSync as readFileSync30 } from "fs";
13365
+ import path48 from "path";
13194
13366
  import os20 from "os";
13195
13367
  import { fileURLToPath as fileURLToPath5 } from "url";
13196
13368
 
@@ -14576,10 +14748,10 @@ function registerCreateTask(server2) {
14576
14748
  skipDispatch: true
14577
14749
  });
14578
14750
  try {
14579
- const { existsSync: existsSync37, mkdirSync: mkdirSync20, writeFileSync: writeFileSync21 } = await import("fs");
14751
+ const { existsSync: existsSync38, mkdirSync: mkdirSync21, writeFileSync: writeFileSync22 } = await import("fs");
14580
14752
  const { identityPath: identityPath2 } = await Promise.resolve().then(() => (init_identity(), identity_exports));
14581
14753
  const idPath = identityPath2(assigned_to);
14582
- if (!existsSync37(idPath)) {
14754
+ if (!existsSync38(idPath)) {
14583
14755
  const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
14584
14756
  const employees = await loadEmployees2();
14585
14757
  const emp = employees.find((e) => e.name === assigned_to);
@@ -14588,8 +14760,8 @@ function registerCreateTask(server2) {
14588
14760
  const template = getTemplateForTitle2(emp.role);
14589
14761
  if (template) {
14590
14762
  const dir = (await import("path")).dirname(idPath);
14591
- if (!existsSync37(dir)) mkdirSync20(dir, { recursive: true });
14592
- writeFileSync21(idPath, template.replace(/^agent_id: \w+/m, `agent_id: ${assigned_to}`), "utf-8");
14763
+ if (!existsSync38(dir)) mkdirSync21(dir, { recursive: true });
14764
+ writeFileSync22(idPath, template.replace(/^agent_id: \w+/m, `agent_id: ${assigned_to}`), "utf-8");
14593
14765
  }
14594
14766
  }
14595
14767
  }
@@ -17551,12 +17723,12 @@ function registerExportGraph(server2) {
17551
17723
  }
17552
17724
  const html = await exportGraphHTML(client);
17553
17725
  const fs = await import("fs");
17554
- const path48 = await import("path");
17726
+ const path49 = await import("path");
17555
17727
  const os21 = await import("os");
17556
- const outDir = path48.join(os21.homedir(), ".exe-os", "exports");
17728
+ const outDir = path49.join(os21.homedir(), ".exe-os", "exports");
17557
17729
  fs.mkdirSync(outDir, { recursive: true });
17558
17730
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
17559
- const filePath = path48.join(outDir, `graph-${timestamp}.html`);
17731
+ const filePath = path49.join(outDir, `graph-${timestamp}.html`);
17560
17732
  fs.writeFileSync(filePath, html, "utf-8");
17561
17733
  return {
17562
17734
  content: [
@@ -17879,7 +18051,7 @@ function registerGraph(server2) {
17879
18051
  }
17880
18052
 
17881
18053
  // src/mcp/tools/config.ts
17882
- import { z as z72 } from "zod";
18054
+ import { z as z73 } from "zod";
17883
18055
 
17884
18056
  // src/mcp/tools/set-agent-config.ts
17885
18057
  init_active_agent();
@@ -18685,8 +18857,6 @@ init_database();
18685
18857
  import { z as z56 } from "zod";
18686
18858
 
18687
18859
  // src/bin/exe-doctor.ts
18688
- init_store();
18689
- init_database();
18690
18860
  import os14 from "os";
18691
18861
 
18692
18862
  // src/lib/is-main.ts
@@ -18705,9 +18875,9 @@ function isMainModule(importMetaUrl) {
18705
18875
  }
18706
18876
 
18707
18877
  // src/bin/exe-doctor.ts
18708
- import { existsSync as existsSync27, readFileSync as readFileSync20 } from "fs";
18878
+ import { existsSync as existsSync28, readFileSync as readFileSync21 } from "fs";
18709
18879
  import { spawn as spawn2 } from "child_process";
18710
- import path32 from "path";
18880
+ import path33 from "path";
18711
18881
  import { randomUUID as randomUUID5 } from "crypto";
18712
18882
 
18713
18883
  // src/lib/conflict-detector.ts
@@ -18970,6 +19140,140 @@ async function detectConflicts(client, projectFilter, agentFilter2) {
18970
19140
  };
18971
19141
  }
18972
19142
 
19143
+ // src/adapters/runtime-hook-manifest.ts
19144
+ var EXE_HOOKS = {
19145
+ postToolCombined: "dist/hooks/post-tool-combined.js",
19146
+ sessionStart: "dist/hooks/session-start.js",
19147
+ promptSubmit: "dist/hooks/prompt-submit.js",
19148
+ heartbeat: "dist/hooks/exe-heartbeat-hook.js",
19149
+ stop: "dist/hooks/stop.js",
19150
+ preToolUse: "dist/hooks/pre-tool-use.js",
19151
+ subagentStop: "dist/hooks/subagent-stop.js",
19152
+ preCompact: "dist/hooks/pre-compact.js",
19153
+ postCompact: "dist/hooks/post-compact.js",
19154
+ sessionEnd: "dist/hooks/session-end.js",
19155
+ notification: "dist/hooks/notification.js",
19156
+ instructionsLoaded: "dist/hooks/instructions-loaded.js"
19157
+ };
19158
+ var EXE_HOOK_MANIFEST = [
19159
+ {
19160
+ key: "postToolCombined",
19161
+ event: "PostToolUse",
19162
+ commandMarker: EXE_HOOKS.postToolCombined,
19163
+ owner: "exe-os",
19164
+ purpose: "Single PostToolUse entrypoint for ingestion, error recall, summaries, and bug detection.",
19165
+ runtimes: ["claude", "codex", "opencode"],
19166
+ checkpointRole: "none"
19167
+ },
19168
+ {
19169
+ key: "sessionStart",
19170
+ event: "SessionStart",
19171
+ commandMarker: EXE_HOOKS.sessionStart,
19172
+ owner: "exe-os",
19173
+ purpose: "Loads agent identity, procedures, and boot context.",
19174
+ runtimes: ["claude", "codex", "opencode"],
19175
+ checkpointRole: "none"
19176
+ },
19177
+ {
19178
+ key: "promptSubmit",
19179
+ event: "UserPromptSubmit",
19180
+ commandMarker: EXE_HOOKS.promptSubmit,
19181
+ owner: "exe-os",
19182
+ purpose: "Injects current tasks, pending reviews, and local context before each prompt.",
19183
+ runtimes: ["claude", "codex", "opencode"],
19184
+ checkpointRole: "none"
19185
+ },
19186
+ {
19187
+ key: "heartbeat",
19188
+ event: "UserPromptSubmit",
19189
+ commandMarker: EXE_HOOKS.heartbeat,
19190
+ owner: "exe-os",
19191
+ purpose: "Lightweight heartbeat/status sidecar for Claude Code sessions.",
19192
+ runtimes: ["claude"],
19193
+ checkpointRole: "none"
19194
+ },
19195
+ {
19196
+ key: "stop",
19197
+ event: "Stop",
19198
+ commandMarker: EXE_HOOKS.stop,
19199
+ owner: "exe-os",
19200
+ purpose: "Finalizes task state, capacity signals, and emergency checkpointing.",
19201
+ runtimes: ["claude", "codex", "opencode"],
19202
+ checkpointRole: "capacity_checkpoint"
19203
+ },
19204
+ {
19205
+ key: "preToolUse",
19206
+ event: "PreToolUse",
19207
+ commandMarker: EXE_HOOKS.preToolUse,
19208
+ owner: "exe-os",
19209
+ purpose: "Preflight guardrails before shell/tool execution.",
19210
+ runtimes: ["claude", "codex", "opencode"],
19211
+ checkpointRole: "none"
19212
+ },
19213
+ {
19214
+ key: "subagentStop",
19215
+ event: "SubagentStop",
19216
+ commandMarker: EXE_HOOKS.subagentStop,
19217
+ owner: "exe-os",
19218
+ purpose: "Captures subagent completion context.",
19219
+ runtimes: ["claude"],
19220
+ checkpointRole: "none"
19221
+ },
19222
+ {
19223
+ key: "preCompact",
19224
+ event: "PreCompact",
19225
+ commandMarker: EXE_HOOKS.preCompact,
19226
+ owner: "exe-os",
19227
+ purpose: "Writes active-task snapshot and compaction recovery context.",
19228
+ runtimes: ["claude"],
19229
+ checkpointRole: "recovery_context"
19230
+ },
19231
+ {
19232
+ key: "postCompact",
19233
+ event: "PostCompact",
19234
+ commandMarker: EXE_HOOKS.postCompact,
19235
+ owner: "exe-os",
19236
+ purpose: "Rehydrates recovery context after compaction.",
19237
+ runtimes: ["claude"],
19238
+ checkpointRole: "recovery_context"
19239
+ },
19240
+ {
19241
+ key: "sessionEnd",
19242
+ event: "SessionEnd",
19243
+ commandMarker: EXE_HOOKS.sessionEnd,
19244
+ owner: "exe-os",
19245
+ purpose: "Stores session-end checkpoint and triages orphaned in-progress tasks.",
19246
+ runtimes: ["claude"],
19247
+ checkpointRole: "session_summary"
19248
+ },
19249
+ {
19250
+ key: "notification",
19251
+ event: "Notification",
19252
+ commandMarker: EXE_HOOKS.notification,
19253
+ owner: "exe-os",
19254
+ purpose: "Captures runtime notifications and nudges.",
19255
+ runtimes: ["claude"],
19256
+ checkpointRole: "none"
19257
+ },
19258
+ {
19259
+ key: "instructionsLoaded",
19260
+ event: "InstructionsLoaded",
19261
+ commandMarker: EXE_HOOKS.instructionsLoaded,
19262
+ owner: "exe-os",
19263
+ purpose: "Applies runtime instruction post-processing.",
19264
+ runtimes: ["claude"],
19265
+ checkpointRole: "none"
19266
+ }
19267
+ ];
19268
+ var LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS = [
19269
+ "dist/hooks/ingest.js",
19270
+ "dist/hooks/error-recall.js",
19271
+ "dist/hooks/ingest-worker.js"
19272
+ ];
19273
+ function manifestEntryForCommand(command) {
19274
+ return EXE_HOOK_MANIFEST.find((entry) => command.includes(entry.commandMarker));
19275
+ }
19276
+
18973
19277
  // src/bin/exe-doctor.ts
18974
19278
  function parseFlags(argv) {
18975
19279
  const flags = { fix: false, dryRun: false, verbose: false, conflicts: false };
@@ -19121,7 +19425,7 @@ async function auditOrphanedProjects(client) {
19121
19425
  for (const row of result.rows) {
19122
19426
  const name = row.project_name;
19123
19427
  const count = Number(row.cnt);
19124
- const exists = existsSync27(path32.join(home, name)) || existsSync27(path32.join(home, "..", name)) || existsSync27(path32.join(process.cwd(), "..", name));
19428
+ const exists = existsSync28(path33.join(home, name)) || existsSync28(path33.join(home, "..", name)) || existsSync28(path33.join(process.cwd(), "..", name));
19125
19429
  if (!exists) {
19126
19430
  orphans.push({ project_name: name, count });
19127
19431
  }
@@ -19129,18 +19433,18 @@ async function auditOrphanedProjects(client) {
19129
19433
  return orphans;
19130
19434
  }
19131
19435
  function auditHookHealth() {
19132
- const logPath = path32.join(
19436
+ const logPath = path33.join(
19133
19437
  process.env.HOME ?? process.env.USERPROFILE ?? "",
19134
19438
  ".exe-os",
19135
19439
  "logs",
19136
19440
  "hooks.log"
19137
19441
  );
19138
- if (!existsSync27(logPath)) {
19442
+ if (!existsSync28(logPath)) {
19139
19443
  return { logExists: false, totalLines: 0, errorsLastHour: 0, topPatterns: [] };
19140
19444
  }
19141
19445
  let content;
19142
19446
  try {
19143
- content = readFileSync20(logPath, "utf-8");
19447
+ content = readFileSync21(logPath, "utf-8");
19144
19448
  } catch {
19145
19449
  return { logExists: false, totalLines: 0, errorsLastHour: 0, topPatterns: [] };
19146
19450
  }
@@ -19168,6 +19472,121 @@ function auditHookHealth() {
19168
19472
  const topPatterns = [...patternCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([pattern, count]) => ({ pattern, count }));
19169
19473
  return { logExists: true, totalLines, errorsLastHour, topPatterns };
19170
19474
  }
19475
+ function safeReadJson(filePath) {
19476
+ if (!existsSync28(filePath)) return null;
19477
+ try {
19478
+ return JSON.parse(readFileSync21(filePath, "utf-8"));
19479
+ } catch {
19480
+ return null;
19481
+ }
19482
+ }
19483
+ function collectHookCommandsFromClaudeSettings(settings) {
19484
+ const hooks = settings?.hooks;
19485
+ if (!hooks || typeof hooks !== "object") return [];
19486
+ const commands = [];
19487
+ for (const [event, groups] of Object.entries(hooks)) {
19488
+ if (!Array.isArray(groups)) continue;
19489
+ for (const group of groups) {
19490
+ const hooksForGroup = group?.hooks;
19491
+ if (!Array.isArray(hooksForGroup)) continue;
19492
+ for (const hook of hooksForGroup) {
19493
+ const command = hook?.command;
19494
+ if (typeof command === "string") commands.push({ event, command });
19495
+ }
19496
+ }
19497
+ }
19498
+ return commands;
19499
+ }
19500
+ function collectHookCommandsFromCodexHooks(config2) {
19501
+ const commands = [];
19502
+ if (!config2 || typeof config2 !== "object") return commands;
19503
+ const root = config2;
19504
+ for (const [event, value] of Object.entries(root)) {
19505
+ const entries = Array.isArray(value) ? value : value && typeof value === "object" ? Object.values(value) : [];
19506
+ for (const entry of entries) {
19507
+ if (typeof entry === "string") commands.push({ event, command: entry });
19508
+ const command = entry?.command;
19509
+ if (typeof command === "string") commands.push({ event, command });
19510
+ }
19511
+ }
19512
+ return commands;
19513
+ }
19514
+ function buildHookOwnershipIssues(runtime, commands) {
19515
+ const issues = [];
19516
+ for (const marker of LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS) {
19517
+ const count = commands.filter((cmd) => cmd.command.includes(marker)).length;
19518
+ if (count > 0) {
19519
+ issues.push({
19520
+ runtime,
19521
+ event: "PostToolUse",
19522
+ marker,
19523
+ count,
19524
+ message: `Legacy split PostToolUse hook still installed: ${marker}`
19525
+ });
19526
+ }
19527
+ }
19528
+ for (const entry of EXE_HOOK_MANIFEST.filter((hook) => hook.runtimes.includes(runtime))) {
19529
+ const matching = commands.filter((cmd) => cmd.command.includes(entry.commandMarker));
19530
+ if (matching.length > 1) {
19531
+ issues.push({
19532
+ runtime,
19533
+ event: entry.event,
19534
+ marker: entry.commandMarker,
19535
+ count: matching.length,
19536
+ message: `Duplicate exe-os hook owner for ${entry.event}: ${entry.commandMarker}`
19537
+ });
19538
+ }
19539
+ for (const cmd of matching) {
19540
+ if (cmd.event !== entry.event) {
19541
+ issues.push({
19542
+ runtime,
19543
+ event: cmd.event,
19544
+ marker: entry.commandMarker,
19545
+ count: 1,
19546
+ message: `exe-os hook ${entry.commandMarker} is registered under ${cmd.event}, expected ${entry.event}`
19547
+ });
19548
+ }
19549
+ }
19550
+ }
19551
+ for (const cmd of commands) {
19552
+ if (!cmd.command.includes("dist/hooks/")) continue;
19553
+ if (!cmd.command.includes("exe-os")) continue;
19554
+ const entry = manifestEntryForCommand(cmd.command);
19555
+ const isLegacy = LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS.some((marker) => cmd.command.includes(marker));
19556
+ if (!entry && !isLegacy) {
19557
+ issues.push({
19558
+ runtime,
19559
+ event: cmd.event,
19560
+ marker: "dist/hooks/",
19561
+ count: 1,
19562
+ message: `Unknown exe-os hook command not present in ownership manifest: ${cmd.command.slice(0, 160)}`
19563
+ });
19564
+ }
19565
+ }
19566
+ return issues;
19567
+ }
19568
+ function auditHookOwnership() {
19569
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
19570
+ const checkedFiles = [];
19571
+ const issues = [];
19572
+ const claudeSettingsPath = path33.join(home, ".claude", "settings.json");
19573
+ const claudeSettings = safeReadJson(claudeSettingsPath);
19574
+ if (claudeSettings) {
19575
+ checkedFiles.push(claudeSettingsPath);
19576
+ issues.push(...buildHookOwnershipIssues("claude", collectHookCommandsFromClaudeSettings(claudeSettings)));
19577
+ }
19578
+ const codexHooksPath = path33.join(home, ".codex", "hooks.json");
19579
+ const codexHooks = safeReadJson(codexHooksPath);
19580
+ if (codexHooks) {
19581
+ checkedFiles.push(codexHooksPath);
19582
+ issues.push(...buildHookOwnershipIssues("codex", collectHookCommandsFromCodexHooks(codexHooks)));
19583
+ }
19584
+ return {
19585
+ checkedFiles,
19586
+ issues,
19587
+ staleLegacyHooks: issues.filter((issue) => issue.message.includes("Legacy split"))
19588
+ };
19589
+ }
19171
19590
  async function auditShards() {
19172
19591
  try {
19173
19592
  const { auditShardHealth: auditShardHealth2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
@@ -19183,16 +19602,33 @@ async function auditShards() {
19183
19602
  return { total: 0, ok: 0, unreadable: 0, archived: 0, unreadableNames: [] };
19184
19603
  }
19185
19604
  }
19605
+ async function auditKeyHealth() {
19606
+ try {
19607
+ const { getMasterKey: getMasterKey2 } = await Promise.resolve().then(() => (init_keychain(), keychain_exports));
19608
+ const { getKeyBackupStatus: getKeyBackupStatus2 } = await Promise.resolve().then(() => (init_key_backup_status(), key_backup_status_exports));
19609
+ const key = await getMasterKey2();
19610
+ const backup = getKeyBackupStatus2();
19611
+ return {
19612
+ masterKeyPresent: Boolean(key),
19613
+ recoveryBackupMarked: backup.exists,
19614
+ recoveryBackupConfirmedAt: backup.confirmedAt,
19615
+ recoveryBackupSource: backup.source
19616
+ };
19617
+ } catch {
19618
+ return { masterKeyPresent: false, recoveryBackupMarked: false };
19619
+ }
19620
+ }
19186
19621
  async function runAudit(client, flags) {
19187
19622
  const runConflicts = flags.conflicts || process.env.EXE_AUDIT_CONFLICTS === "1";
19188
- const [stats, nullVectors, duplicates, bloated, fts, orphanedProjects, shards] = await Promise.all([
19623
+ const [stats, nullVectors, duplicates, bloated, fts, orphanedProjects, shards, keyHealth] = await Promise.all([
19189
19624
  auditStats(client, flags),
19190
19625
  auditNullVectors(client, flags),
19191
19626
  auditDuplicates(client, flags),
19192
19627
  auditBloated(client, flags),
19193
19628
  auditFts(client),
19194
19629
  auditOrphanedProjects(client),
19195
- auditShards()
19630
+ auditShards(),
19631
+ auditKeyHealth()
19196
19632
  ]);
19197
19633
  let conflicts;
19198
19634
  if (runConflicts) {
@@ -19212,7 +19648,8 @@ async function runAudit(client, flags) {
19212
19648
  }
19213
19649
  const duplicateCount = duplicates.reduce((sum, d) => sum + d.delete_ids.length, 0);
19214
19650
  const hookHealth = auditHookHealth();
19215
- return { stats, nullVectors, duplicates, duplicateCount, bloated, fts, orphanedProjects, conflicts, hookHealth, shards };
19651
+ const hookOwnership = auditHookOwnership();
19652
+ return { stats, nullVectors, duplicates, duplicateCount, bloated, fts, orphanedProjects, conflicts, hookHealth, hookOwnership, shards, keyHealth };
19216
19653
  }
19217
19654
  function indicator(value, warn) {
19218
19655
  if (value === 0) return "\u{1F7E2}";
@@ -19260,6 +19697,15 @@ function formatReport(report, flags) {
19260
19697
  lines.push(`${indicator(report.bloated.length, 20)} Bloated (>5KB): ${fmtNum(report.bloated.length)} / ${fmtNum(s.total)} (${pct(report.bloated.length, s.total)})`);
19261
19698
  const ftsIndicator = report.fts.inSync ? "\u{1F7E2}" : "\u{1F534}";
19262
19699
  lines.push(`${ftsIndicator} FTS index: ${report.fts.inSync ? "in sync" : "OUT OF SYNC"} (${fmtNum(report.fts.memoryCount)} / ${fmtNum(report.fts.ftsCount)})`);
19700
+ const kh = report.keyHealth;
19701
+ if (!kh.masterKeyPresent) {
19702
+ lines.push("\u{1F534} Recovery key: master key missing \u2014 import phrase or run setup before syncing");
19703
+ } else if (!kh.recoveryBackupMarked) {
19704
+ lines.push("\u{1F534} Recovery backup: not confirmed \u2014 run `exe-os link export --local-terminal-only` and save the 24-word phrase");
19705
+ } else {
19706
+ const suffix = kh.recoveryBackupConfirmedAt ? ` (${kh.recoveryBackupConfirmedAt.slice(0, 10)}${kh.recoveryBackupSource ? ` via ${kh.recoveryBackupSource}` : ""})` : "";
19707
+ lines.push(`\u{1F7E2} Recovery backup: confirmed${suffix}`);
19708
+ }
19263
19709
  if (report.orphanedProjects.length > 0) {
19264
19710
  const orphanList = report.orphanedProjects.map((o) => `${o.project_name} \u2014 ${o.count} memories`).join(", ");
19265
19711
  lines.push(`\u2139\uFE0F Orphaned projects: ${report.orphanedProjects.length} (${orphanList})`);
@@ -19291,6 +19737,15 @@ function formatReport(report, flags) {
19291
19737
  lines.push(` ${p.count}x: ${p.pattern}`);
19292
19738
  }
19293
19739
  }
19740
+ const ho = report.hookOwnership;
19741
+ if (ho.issues.length === 0) {
19742
+ lines.push(`\u{1F7E2} Hook ownership: ${ho.checkedFiles.length > 0 ? "manifest clean" : "no local hook config found"}`);
19743
+ } else {
19744
+ lines.push(`\u{1F534} Hook ownership: ${fmtNum(ho.issues.length)} issue(s)`);
19745
+ for (const issue of ho.issues.slice(0, 5)) {
19746
+ lines.push(` [${issue.runtime}/${issue.event}] ${issue.message}`);
19747
+ }
19748
+ }
19294
19749
  const sh = report.shards;
19295
19750
  if (sh.total > 0) {
19296
19751
  if (sh.unreadable === 0) {
@@ -19360,6 +19815,9 @@ function formatReport(report, flags) {
19360
19815
  if (report.conflicts.superseded > 0) {
19361
19816
  recs.push(`${fmtNum(report.conflicts.superseded)} superseded memories can be deactivated`);
19362
19817
  }
19818
+ if (report.hookOwnership.issues.length > 0) {
19819
+ recs.push(`Run exe-os install to refresh hook config; remove stale exe-os hook commands if they remain`);
19820
+ }
19363
19821
  if (recs.length > 0) {
19364
19822
  lines.push("Recommendations:");
19365
19823
  for (const r of recs) {
@@ -19381,7 +19839,7 @@ async function fixNullVectors() {
19381
19839
  }
19382
19840
  }
19383
19841
  const npmRoot = (await import("child_process")).execSync("npm root -g", { encoding: "utf8" }).trim();
19384
- const backfillPath = path32.join(npmRoot, "exe-os", "dist", "bin", "backfill-vectors.js");
19842
+ const backfillPath = path33.join(npmRoot, "exe-os", "dist", "bin", "backfill-vectors.js");
19385
19843
  return new Promise((resolve, reject) => {
19386
19844
  const child = spawn2("node", [backfillPath], { stdio: "inherit" });
19387
19845
  if (child.pid) registerWorkerPid2(child.pid);
@@ -19493,8 +19951,8 @@ function splitAtSentences(text3, maxChunkSize) {
19493
19951
  }
19494
19952
  async function main(argv = process.argv.slice(2)) {
19495
19953
  const flags = parseFlags(argv);
19496
- await initStore();
19497
- const client = getClient();
19954
+ const { fastDbInit: fastDbInit2 } = await Promise.resolve().then(() => (init_fast_db_init(), fast_db_init_exports));
19955
+ const client = await fastDbInit2();
19498
19956
  const report = await runAudit(client, flags);
19499
19957
  console.log(formatReport(report, flags));
19500
19958
  if (flags.fix || flags.dryRun) {
@@ -19685,9 +20143,9 @@ import { z as z58 } from "zod";
19685
20143
 
19686
20144
  // src/lib/cloud-sync.ts
19687
20145
  init_database();
19688
- import { readFileSync as readFileSync22, writeFileSync as writeFileSync16, existsSync as existsSync29, readdirSync as readdirSync11, mkdirSync as mkdirSync14, appendFileSync as appendFileSync2, unlinkSync as unlinkSync11, openSync as openSync2, closeSync as closeSync2, statSync as statSync5 } from "fs";
20146
+ import { readFileSync as readFileSync23, writeFileSync as writeFileSync17, existsSync as existsSync30, readdirSync as readdirSync11, mkdirSync as mkdirSync15, appendFileSync as appendFileSync2, unlinkSync as unlinkSync11, openSync as openSync2, closeSync as closeSync2, statSync as statSync5 } from "fs";
19689
20147
  import crypto15 from "crypto";
19690
- import path34 from "path";
20148
+ import path35 from "path";
19691
20149
  import { homedir as homedir6 } from "os";
19692
20150
 
19693
20151
  // src/lib/crypto.ts
@@ -19762,7 +20220,7 @@ function sqlSafe(v) {
19762
20220
  }
19763
20221
  function logError(msg) {
19764
20222
  try {
19765
- const logPath = path34.join(homedir6(), ".exe-os", "workers.log");
20223
+ const logPath = path35.join(homedir6(), ".exe-os", "workers.log");
19766
20224
  appendFileSync2(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
19767
20225
  `);
19768
20226
  } catch {
@@ -19771,37 +20229,49 @@ function logError(msg) {
19771
20229
  var LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
19772
20230
  var FETCH_TIMEOUT_MS2 = 3e4;
19773
20231
  var PUSH_BATCH_SIZE = 5e3;
19774
- var ROSTER_LOCK_PATH = path34.join(EXE_AI_DIR, "roster-merge.lock");
20232
+ var ROSTER_LOCK_PATH = path35.join(EXE_AI_DIR, "roster-merge.lock");
19775
20233
  var LOCK_STALE_MS = 3e4;
19776
20234
  var _pgPromise = null;
19777
20235
  var _pgFailed = false;
20236
+ function isTruthyEnv(value) {
20237
+ return /^(1|true|yes|on)$/i.test(value ?? "");
20238
+ }
19778
20239
  function loadPgClient() {
19779
20240
  if (_pgFailed) return null;
19780
- const postgresUrl = process.env.DATABASE_URL;
19781
- const configPath = path34.join(EXE_AI_DIR, "config.json");
20241
+ const configPath = path35.join(EXE_AI_DIR, "config.json");
19782
20242
  let cloudPostgresUrl;
20243
+ let configEnabled = false;
19783
20244
  try {
19784
- if (existsSync29(configPath)) {
19785
- const cfg = JSON.parse(readFileSync22(configPath, "utf8"));
20245
+ if (existsSync30(configPath)) {
20246
+ const cfg = JSON.parse(readFileSync23(configPath, "utf8"));
19786
20247
  cloudPostgresUrl = cfg.cloud?.postgresUrl;
19787
- if (cfg.cloud?.syncToPostgres === false) {
19788
- _pgFailed = true;
19789
- return null;
19790
- }
20248
+ configEnabled = cfg.cloud?.syncToPostgres === true;
19791
20249
  }
19792
20250
  } catch {
19793
20251
  }
19794
- const url = postgresUrl || cloudPostgresUrl;
20252
+ const envEnabled = isTruthyEnv(process.env.EXE_CLOUD_SYNC_TO_POSTGRES);
20253
+ if (!envEnabled && !configEnabled) {
20254
+ return null;
20255
+ }
20256
+ const url = process.env.DATABASE_URL || cloudPostgresUrl;
19795
20257
  if (!url) {
19796
20258
  _pgFailed = true;
19797
20259
  return null;
19798
20260
  }
19799
20261
  if (!_pgPromise) {
19800
20262
  _pgPromise = (async () => {
20263
+ if (!process.env.DATABASE_URL) process.env.DATABASE_URL = url;
19801
20264
  const { createRequire: createRequire6 } = await import("module");
19802
20265
  const { pathToFileURL: pathToFileURL6 } = await import("url");
19803
- const exeDbRoot = process.env.EXE_DB_ROOT ?? path34.join(homedir6(), "exe-db");
19804
- const req = createRequire6(path34.join(exeDbRoot, "package.json"));
20266
+ const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
20267
+ if (explicitPath) {
20268
+ const mod2 = await import(pathToFileURL6(explicitPath).href);
20269
+ const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
20270
+ if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
20271
+ return new Ctor2();
20272
+ }
20273
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path35.join(homedir6(), "exe-db");
20274
+ const req = createRequire6(path35.join(exeDbRoot, "package.json"));
19805
20275
  const entry = req.resolve("@prisma/client");
19806
20276
  const mod = await import(pathToFileURL6(entry).href);
19807
20277
  const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
@@ -19846,18 +20316,18 @@ async function withRosterLock(fn) {
19846
20316
  try {
19847
20317
  const fd = openSync2(ROSTER_LOCK_PATH, "wx");
19848
20318
  closeSync2(fd);
19849
- writeFileSync16(ROSTER_LOCK_PATH, String(Date.now()));
20319
+ writeFileSync17(ROSTER_LOCK_PATH, String(Date.now()));
19850
20320
  } catch (err) {
19851
20321
  if (err.code === "EEXIST") {
19852
20322
  try {
19853
- const ts2 = parseInt(readFileSync22(ROSTER_LOCK_PATH, "utf-8"), 10);
20323
+ const ts2 = parseInt(readFileSync23(ROSTER_LOCK_PATH, "utf-8"), 10);
19854
20324
  if (Date.now() - ts2 < LOCK_STALE_MS) {
19855
20325
  throw new Error("Roster merge already in progress \u2014 another sync is running");
19856
20326
  }
19857
20327
  unlinkSync11(ROSTER_LOCK_PATH);
19858
20328
  const fd = openSync2(ROSTER_LOCK_PATH, "wx");
19859
20329
  closeSync2(fd);
19860
- writeFileSync16(ROSTER_LOCK_PATH, String(Date.now()));
20330
+ writeFileSync17(ROSTER_LOCK_PATH, String(Date.now()));
19861
20331
  } catch (retryErr) {
19862
20332
  if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
19863
20333
  throw new Error("Roster merge already in progress \u2014 another sync is running");
@@ -19976,6 +20446,16 @@ async function cloudPull(sinceVersion, config2) {
19976
20446
  return { records: [], maxVersion: sinceVersion };
19977
20447
  }
19978
20448
  }
20449
+ var CLOUD_RELINK_REQUIRED_MESSAGE = "[cloud-sync] Paused after key rotation. Run `exe-os cloud relink --dry-run` for the safe relink checklist.";
20450
+ async function getCloudRelinkRequired(client = getClient()) {
20451
+ try {
20452
+ await client.execute("CREATE TABLE IF NOT EXISTS sync_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)");
20453
+ const relink = await client.execute("SELECT value FROM sync_meta WHERE key = 'cloud_relink_required' LIMIT 1");
20454
+ return String(relink.rows[0]?.value ?? "") === "1";
20455
+ } catch {
20456
+ return false;
20457
+ }
20458
+ }
19979
20459
  async function cloudSync(config2) {
19980
20460
  if (!isSyncCryptoInitialized()) {
19981
20461
  try {
@@ -19996,6 +20476,12 @@ async function cloudSync(config2) {
19996
20476
  } catch {
19997
20477
  throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
19998
20478
  }
20479
+ try {
20480
+ if (await getCloudRelinkRequired(client)) throw new Error(CLOUD_RELINK_REQUIRED_MESSAGE);
20481
+ } catch (err) {
20482
+ const msg = err instanceof Error ? err.message : String(err);
20483
+ if (msg.includes("Paused after key rotation")) throw err;
20484
+ }
19999
20485
  try {
20000
20486
  const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
20001
20487
  await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
@@ -20241,8 +20727,8 @@ async function cloudSync(config2) {
20241
20727
  try {
20242
20728
  const employees = await loadEmployees();
20243
20729
  rosterResult.employees = employees.length;
20244
- const idDir = path34.join(EXE_AI_DIR, "identity");
20245
- if (existsSync29(idDir)) {
20730
+ const idDir = path35.join(EXE_AI_DIR, "identity");
20731
+ if (existsSync30(idDir)) {
20246
20732
  rosterResult.identities = readdirSync11(idDir).filter((f) => f.endsWith(".md")).length;
20247
20733
  }
20248
20734
  } catch {
@@ -20255,7 +20741,7 @@ async function cloudSync(config2) {
20255
20741
  const backupSize = statSync5(latestBackup).size;
20256
20742
  const MAX_CLOUD_BACKUP_BYTES = 50 * 1024 * 1024;
20257
20743
  if (backupSize <= MAX_CLOUD_BACKUP_BYTES) {
20258
- const backupData = readFileSync22(latestBackup);
20744
+ const backupData = readFileSync23(latestBackup);
20259
20745
  const deviceId = loadDeviceId() ?? "unknown";
20260
20746
  const encrypted = encryptSyncBlob(backupData);
20261
20747
  const backupRes = await fetchWithRetry(`${config2.endpoint}/sync/push-db-backup`, {
@@ -20263,7 +20749,7 @@ async function cloudSync(config2) {
20263
20749
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${config2.apiKey}` },
20264
20750
  body: JSON.stringify({
20265
20751
  device_id: deviceId,
20266
- filename: path34.basename(latestBackup),
20752
+ filename: path35.basename(latestBackup),
20267
20753
  blob: encrypted,
20268
20754
  size: backupData.length
20269
20755
  })
@@ -20288,49 +20774,49 @@ async function cloudSync(config2) {
20288
20774
  roster: rosterResult
20289
20775
  };
20290
20776
  }
20291
- var ROSTER_DELETIONS_PATH = path34.join(EXE_AI_DIR, "roster-deletions.json");
20777
+ var ROSTER_DELETIONS_PATH = path35.join(EXE_AI_DIR, "roster-deletions.json");
20292
20778
  function consumeRosterDeletions() {
20293
20779
  try {
20294
- if (!existsSync29(ROSTER_DELETIONS_PATH)) return [];
20295
- const deletions = JSON.parse(readFileSync22(ROSTER_DELETIONS_PATH, "utf-8"));
20296
- writeFileSync16(ROSTER_DELETIONS_PATH, "[]");
20780
+ if (!existsSync30(ROSTER_DELETIONS_PATH)) return [];
20781
+ const deletions = JSON.parse(readFileSync23(ROSTER_DELETIONS_PATH, "utf-8"));
20782
+ writeFileSync17(ROSTER_DELETIONS_PATH, "[]");
20297
20783
  return deletions;
20298
20784
  } catch {
20299
20785
  return [];
20300
20786
  }
20301
20787
  }
20302
20788
  function buildRosterBlob(paths) {
20303
- const rosterPath = paths?.rosterPath ?? path34.join(EXE_AI_DIR, "exe-employees.json");
20304
- const identityDir = paths?.identityDir ?? path34.join(EXE_AI_DIR, "identity");
20305
- const configPath = paths?.configPath ?? path34.join(EXE_AI_DIR, "config.json");
20789
+ const rosterPath = paths?.rosterPath ?? path35.join(EXE_AI_DIR, "exe-employees.json");
20790
+ const identityDir = paths?.identityDir ?? path35.join(EXE_AI_DIR, "identity");
20791
+ const configPath = paths?.configPath ?? path35.join(EXE_AI_DIR, "config.json");
20306
20792
  let roster = [];
20307
- if (existsSync29(rosterPath)) {
20793
+ if (existsSync30(rosterPath)) {
20308
20794
  try {
20309
- roster = JSON.parse(readFileSync22(rosterPath, "utf-8"));
20795
+ roster = JSON.parse(readFileSync23(rosterPath, "utf-8"));
20310
20796
  } catch {
20311
20797
  }
20312
20798
  }
20313
20799
  const identities = {};
20314
- if (existsSync29(identityDir)) {
20800
+ if (existsSync30(identityDir)) {
20315
20801
  for (const file of readdirSync11(identityDir).filter((f) => f.endsWith(".md"))) {
20316
20802
  try {
20317
- identities[file] = readFileSync22(path34.join(identityDir, file), "utf-8");
20803
+ identities[file] = readFileSync23(path35.join(identityDir, file), "utf-8");
20318
20804
  } catch {
20319
20805
  }
20320
20806
  }
20321
20807
  }
20322
20808
  let config2;
20323
- if (existsSync29(configPath)) {
20809
+ if (existsSync30(configPath)) {
20324
20810
  try {
20325
- config2 = JSON.parse(readFileSync22(configPath, "utf-8"));
20811
+ config2 = JSON.parse(readFileSync23(configPath, "utf-8"));
20326
20812
  } catch {
20327
20813
  }
20328
20814
  }
20329
20815
  let agentConfig;
20330
- const agentConfigPath = path34.join(EXE_AI_DIR, "agent-config.json");
20331
- if (existsSync29(agentConfigPath)) {
20816
+ const agentConfigPath = path35.join(EXE_AI_DIR, "agent-config.json");
20817
+ if (existsSync30(agentConfigPath)) {
20332
20818
  try {
20333
- agentConfig = JSON.parse(readFileSync22(agentConfigPath, "utf-8"));
20819
+ agentConfig = JSON.parse(readFileSync23(agentConfigPath, "utf-8"));
20334
20820
  } catch {
20335
20821
  }
20336
20822
  }
@@ -20406,24 +20892,24 @@ async function cloudPullRoster(config2) {
20406
20892
  }
20407
20893
  }
20408
20894
  function mergeConfig(remoteConfig, configPath) {
20409
- const cfgPath = configPath ?? path34.join(EXE_AI_DIR, "config.json");
20895
+ const cfgPath = configPath ?? path35.join(EXE_AI_DIR, "config.json");
20410
20896
  let local = {};
20411
- if (existsSync29(cfgPath)) {
20897
+ if (existsSync30(cfgPath)) {
20412
20898
  try {
20413
- local = JSON.parse(readFileSync22(cfgPath, "utf-8"));
20899
+ local = JSON.parse(readFileSync23(cfgPath, "utf-8"));
20414
20900
  } catch {
20415
20901
  }
20416
20902
  }
20417
20903
  const merged = { ...remoteConfig, ...local };
20418
- const dir = path34.dirname(cfgPath);
20904
+ const dir = path35.dirname(cfgPath);
20419
20905
  ensurePrivateDirSync(dir);
20420
- writeFileSync16(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
20906
+ writeFileSync17(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
20421
20907
  enforcePrivateFileSync(cfgPath);
20422
20908
  }
20423
20909
  async function mergeRosterFromRemote(remote, paths) {
20424
20910
  return withRosterLock(async () => {
20425
20911
  const rosterPath = paths?.rosterPath ?? void 0;
20426
- const identityDir = paths?.identityDir ?? path34.join(EXE_AI_DIR, "identity");
20912
+ const identityDir = paths?.identityDir ?? path35.join(EXE_AI_DIR, "identity");
20427
20913
  const localEmployees = await loadEmployees(rosterPath);
20428
20914
  const localNames = new Set(localEmployees.map((e) => e.name));
20429
20915
  let added = 0;
@@ -20444,15 +20930,15 @@ async function mergeRosterFromRemote(remote, paths) {
20444
20930
  ) ?? lookupKey;
20445
20931
  const remoteIdentity = remote.identities[matchedKey];
20446
20932
  if (remoteIdentity) {
20447
- if (!existsSync29(identityDir)) mkdirSync14(identityDir, { recursive: true });
20448
- const idPath = path34.join(identityDir, `${remoteEmp.name}.md`);
20933
+ if (!existsSync30(identityDir)) mkdirSync15(identityDir, { recursive: true });
20934
+ const idPath = path35.join(identityDir, `${remoteEmp.name}.md`);
20449
20935
  let localIdentity = null;
20450
20936
  try {
20451
- localIdentity = existsSync29(idPath) ? readFileSync22(idPath, "utf-8") : null;
20937
+ localIdentity = existsSync30(idPath) ? readFileSync23(idPath, "utf-8") : null;
20452
20938
  } catch {
20453
20939
  }
20454
20940
  if (localIdentity !== remoteIdentity) {
20455
- writeFileSync16(idPath, remoteIdentity, "utf-8");
20941
+ writeFileSync17(idPath, remoteIdentity, "utf-8");
20456
20942
  identitiesUpdated++;
20457
20943
  }
20458
20944
  }
@@ -20478,17 +20964,17 @@ async function mergeRosterFromRemote(remote, paths) {
20478
20964
  }
20479
20965
  if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
20480
20966
  try {
20481
- const agentConfigPath = path34.join(EXE_AI_DIR, "agent-config.json");
20967
+ const agentConfigPath = path35.join(EXE_AI_DIR, "agent-config.json");
20482
20968
  let local = {};
20483
- if (existsSync29(agentConfigPath)) {
20969
+ if (existsSync30(agentConfigPath)) {
20484
20970
  try {
20485
- local = JSON.parse(readFileSync22(agentConfigPath, "utf-8"));
20971
+ local = JSON.parse(readFileSync23(agentConfigPath, "utf-8"));
20486
20972
  } catch {
20487
20973
  }
20488
20974
  }
20489
20975
  const merged = { ...remote.agentConfig, ...local };
20490
- ensurePrivateDirSync(path34.dirname(agentConfigPath));
20491
- writeFileSync16(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
20976
+ ensurePrivateDirSync(path35.dirname(agentConfigPath));
20977
+ writeFileSync17(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
20492
20978
  enforcePrivateFileSync(agentConfigPath);
20493
20979
  } catch {
20494
20980
  }
@@ -20974,9 +21460,136 @@ function registerCloudSync(server2) {
20974
21460
  );
20975
21461
  }
20976
21462
 
21463
+ // src/mcp/tools/orchestration-phase.ts
21464
+ import { z as z59 } from "zod";
21465
+
21466
+ // src/lib/orchestration-phase.ts
21467
+ init_config();
21468
+ var ORCHESTRATION_PHASES = [
21469
+ "phase_1_coo",
21470
+ "phase_2_executives",
21471
+ "phase_3_parallel_org"
21472
+ ];
21473
+ var PHASE_INFO = {
21474
+ phase_1_coo: {
21475
+ phase: "phase_1_coo",
21476
+ shortLabel: "Phase 1 \u2014 COO mode",
21477
+ label: "Phase 1 \u2014 COO / Chief of Staff mode",
21478
+ focus: "building company context before delegation",
21479
+ nextSuggestion: "Unlock executives when technical, marketing, ops, legal, or finance work repeats."
21480
+ },
21481
+ phase_2_executives: {
21482
+ phase: "phase_2_executives",
21483
+ shortLabel: "Phase 2 \u2014 Executive bench",
21484
+ label: "Phase 2 \u2014 Executive bench",
21485
+ focus: "COO works with domain executives like CTO/CMO before specialist fan-out",
21486
+ nextSuggestion: "Unlock parallel execution when review gates, permissions, and workflows are ready."
21487
+ },
21488
+ phase_3_parallel_org: {
21489
+ phase: "phase_3_parallel_org",
21490
+ shortLabel: "Phase 3 \u2014 Parallel org",
21491
+ label: "Phase 3 \u2014 Parallel execution org",
21492
+ focus: "executives can delegate to specialists in parallel with review gates",
21493
+ nextSuggestion: "Keep review/CI/permission gates healthy; downgrade anytime if you want simpler COO-only mode."
21494
+ }
21495
+ };
21496
+ function normalizeOrchestrationPhase(input) {
21497
+ if (typeof input !== "string") return "phase_1_coo";
21498
+ const normalized = input.trim().toLowerCase().replace(/\s+/g, "_");
21499
+ if (["1", "phase1", "phase_1", "coo", "coo_mode", "chief_of_staff", "phase_1_coo"].includes(normalized)) {
21500
+ return "phase_1_coo";
21501
+ }
21502
+ if (["2", "phase2", "phase_2", "executives", "executive", "executive_bench", "phase_2_executives"].includes(normalized)) {
21503
+ return "phase_2_executives";
21504
+ }
21505
+ if (["3", "phase3", "phase_3", "parallel", "parallel_org", "parallel_execution", "phase_3_parallel_org"].includes(normalized)) {
21506
+ return "phase_3_parallel_org";
21507
+ }
21508
+ if (ORCHESTRATION_PHASES.includes(normalized)) return normalized;
21509
+ return "phase_1_coo";
21510
+ }
21511
+ function getOrchestrationPhaseInfo(phase) {
21512
+ return PHASE_INFO[normalizeOrchestrationPhase(phase)];
21513
+ }
21514
+ async function loadOrchestrationPhase() {
21515
+ const config2 = await loadConfig();
21516
+ return getOrchestrationPhaseInfo(config2.orchestration?.phase);
21517
+ }
21518
+ async function setOrchestrationPhase(phaseInput, setBy = "user") {
21519
+ const config2 = await loadConfig();
21520
+ const phase = normalizeOrchestrationPhase(phaseInput);
21521
+ config2.orchestration = {
21522
+ ...config2.orchestration ?? {},
21523
+ phase,
21524
+ phaseSetAt: (/* @__PURE__ */ new Date()).toISOString(),
21525
+ phaseSetBy: setBy
21526
+ };
21527
+ await saveConfig(config2);
21528
+ return getOrchestrationPhaseInfo(phase);
21529
+ }
21530
+
21531
+ // src/mcp/tools/orchestration-phase.ts
21532
+ function render(info, prefix) {
21533
+ return [
21534
+ prefix,
21535
+ `## ${info.label}`,
21536
+ "",
21537
+ `- **Focus:** ${info.focus}`,
21538
+ `- **Suggestion:** ${info.nextSuggestion}`,
21539
+ "",
21540
+ "This is guidance, not a blocker. The user can switch phases anytime. Changing phase never overwrites role titles, identities, memories, tasks, or custom org design."
21541
+ ].filter(Boolean).join("\n");
21542
+ }
21543
+ function registerOrchestrationPhase(server2) {
21544
+ server2.registerTool(
21545
+ "orchestration_phase",
21546
+ {
21547
+ title: "Orchestration Phase",
21548
+ description: "View or change the customer-owned orchestration maturity phase. MCP parity for `exe-os org phase`, `exe-os org unlock executives`, and `exe-os org unlock parallel`. This is a recommendation layer, not a blocker; it never exposes recovery phrases or secrets.",
21549
+ inputSchema: {
21550
+ action: z59.enum(["status", "set", "unlock_executives", "unlock_parallel"]).default("status"),
21551
+ phase: z59.enum(["phase_1_coo", "phase_2_executives", "phase_3_parallel_org", "1", "2", "3"]).optional().describe("Phase to set when action='set'.")
21552
+ }
21553
+ },
21554
+ async ({ action = "status", phase }) => {
21555
+ try {
21556
+ if (action === "status") {
21557
+ const info2 = await loadOrchestrationPhase();
21558
+ return { content: [{ type: "text", text: render(info2) }] };
21559
+ }
21560
+ if (action === "unlock_executives") {
21561
+ const info2 = await setOrchestrationPhase("phase_2_executives", "mcp");
21562
+ return {
21563
+ content: [{ type: "text", text: render(info2, "Phase 2 enabled. Your COO can now lean on the executive bench when useful.") }]
21564
+ };
21565
+ }
21566
+ if (action === "unlock_parallel") {
21567
+ const info2 = await setOrchestrationPhase("phase_3_parallel_org", "mcp");
21568
+ return {
21569
+ content: [{ type: "text", text: render(info2, "Phase 3 enabled. Parallel execution is available with review/permission gates.") }]
21570
+ };
21571
+ }
21572
+ if (!phase) {
21573
+ return {
21574
+ content: [{ type: "text", text: "action='set' requires phase: 1, 2, 3, phase_1_coo, phase_2_executives, or phase_3_parallel_org." }],
21575
+ isError: true
21576
+ };
21577
+ }
21578
+ const info = await setOrchestrationPhase(phase, "mcp");
21579
+ return { content: [{ type: "text", text: render(info, "Updated orchestration phase.") }] };
21580
+ } catch (err) {
21581
+ return {
21582
+ content: [{ type: "text", text: `Failed to update orchestration phase: ${err instanceof Error ? err.message : String(err)}` }],
21583
+ isError: true
21584
+ };
21585
+ }
21586
+ }
21587
+ );
21588
+ }
21589
+
20977
21590
  // src/mcp/tools/backup-vps.ts
20978
21591
  init_keychain();
20979
- import { z as z59 } from "zod";
21592
+ import { z as z60 } from "zod";
20980
21593
 
20981
21594
  // src/lib/vps-backup.ts
20982
21595
  import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
@@ -21301,43 +21914,43 @@ function registerBackupVps(server2) {
21301
21914
  {
21302
21915
  title: "VPS Backup",
21303
21916
  description: "Run VPS Postgres backup/restore workflows and check status.",
21304
- inputSchema: z59.discriminatedUnion("action", [
21305
- z59.object({
21306
- action: z59.literal("backup"),
21307
- databaseUrl: z59.string().min(1).describe("Postgres DATABASE_URL to dump from"),
21308
- encryptionKeyB64: z59.string().min(1).max(4096).optional().describe(
21917
+ inputSchema: z60.discriminatedUnion("action", [
21918
+ z60.object({
21919
+ action: z60.literal("backup"),
21920
+ databaseUrl: z60.string().min(1).describe("Postgres DATABASE_URL to dump from"),
21921
+ encryptionKeyB64: z60.string().min(1).max(4096).optional().describe(
21309
21922
  "Base64 AES-256 key (defaults to local master key if omitted)"
21310
21923
  ),
21311
- r2Bucket: z59.string().min(1).describe("R2 bucket name"),
21312
- r2Endpoint: z59.string().min(1).describe("R2 endpoint URL"),
21313
- r2AccessKeyId: z59.string().min(1).describe("R2 access key ID"),
21314
- r2SecretAccessKey: z59.string().min(1).describe("R2 secret access key")
21924
+ r2Bucket: z60.string().min(1).describe("R2 bucket name"),
21925
+ r2Endpoint: z60.string().min(1).describe("R2 endpoint URL"),
21926
+ r2AccessKeyId: z60.string().min(1).describe("R2 access key ID"),
21927
+ r2SecretAccessKey: z60.string().min(1).describe("R2 secret access key")
21315
21928
  }),
21316
- z59.object({
21317
- action: z59.literal("restore"),
21318
- databaseUrl: z59.string().min(1).describe("Target Postgres DATABASE_URL for restore"),
21319
- backupKey: z59.string().min(1).describe("R2 object key to restore from"),
21320
- encryptionKeyB64: z59.string().min(1).max(4096).optional().describe(
21929
+ z60.object({
21930
+ action: z60.literal("restore"),
21931
+ databaseUrl: z60.string().min(1).describe("Target Postgres DATABASE_URL for restore"),
21932
+ backupKey: z60.string().min(1).describe("R2 object key to restore from"),
21933
+ encryptionKeyB64: z60.string().min(1).max(4096).optional().describe(
21321
21934
  "Base64 AES-256 key (defaults to local master key if omitted)"
21322
21935
  ),
21323
- r2Bucket: z59.string().min(1).describe("R2 bucket name"),
21324
- r2Endpoint: z59.string().min(1).describe("R2 endpoint URL"),
21325
- r2AccessKeyId: z59.string().min(1).describe("R2 access key ID"),
21326
- r2SecretAccessKey: z59.string().min(1).describe("R2 secret access key")
21936
+ r2Bucket: z60.string().min(1).describe("R2 bucket name"),
21937
+ r2Endpoint: z60.string().min(1).describe("R2 endpoint URL"),
21938
+ r2AccessKeyId: z60.string().min(1).describe("R2 access key ID"),
21939
+ r2SecretAccessKey: z60.string().min(1).describe("R2 secret access key")
21327
21940
  }),
21328
- z59.object({
21329
- action: z59.literal("list"),
21330
- r2Bucket: z59.string().min(1).describe("R2 bucket name"),
21331
- r2Endpoint: z59.string().min(1).describe("R2 endpoint URL"),
21332
- r2AccessKeyId: z59.string().min(1).describe("R2 access key ID"),
21333
- r2SecretAccessKey: z59.string().min(1).describe("R2 secret access key")
21941
+ z60.object({
21942
+ action: z60.literal("list"),
21943
+ r2Bucket: z60.string().min(1).describe("R2 bucket name"),
21944
+ r2Endpoint: z60.string().min(1).describe("R2 endpoint URL"),
21945
+ r2AccessKeyId: z60.string().min(1).describe("R2 access key ID"),
21946
+ r2SecretAccessKey: z60.string().min(1).describe("R2 secret access key")
21334
21947
  }),
21335
- z59.object({
21336
- action: z59.literal("health"),
21337
- r2Bucket: z59.string().min(1).describe("R2 bucket name"),
21338
- r2Endpoint: z59.string().min(1).describe("R2 endpoint URL"),
21339
- r2AccessKeyId: z59.string().min(1).describe("R2 access key ID"),
21340
- r2SecretAccessKey: z59.string().min(1).describe("R2 secret access key")
21948
+ z60.object({
21949
+ action: z60.literal("health"),
21950
+ r2Bucket: z60.string().min(1).describe("R2 bucket name"),
21951
+ r2Endpoint: z60.string().min(1).describe("R2 endpoint URL"),
21952
+ r2AccessKeyId: z60.string().min(1).describe("R2 access key ID"),
21953
+ r2SecretAccessKey: z60.string().min(1).describe("R2 secret access key")
21341
21954
  })
21342
21955
  ])
21343
21956
  },
@@ -21475,11 +22088,11 @@ async function resolveEncryptionKey(providedB64) {
21475
22088
  }
21476
22089
 
21477
22090
  // src/mcp/tools/deploy-client.ts
21478
- import { z as z60 } from "zod";
22091
+ import { z as z61 } from "zod";
21479
22092
  import { execFile } from "child_process";
21480
22093
  import { promisify } from "util";
21481
- import path35 from "path";
21482
- import { existsSync as existsSync30 } from "fs";
22094
+ import path36 from "path";
22095
+ import { existsSync as existsSync31 } from "fs";
21483
22096
 
21484
22097
  // src/lib/hostinger-api.ts
21485
22098
  var DEFAULT_BASE_URL = "https://developers.hostinger.com/api/vps/v1";
@@ -21527,9 +22140,9 @@ var HostingerApiClient = class {
21527
22140
  }
21528
22141
  this.lastRequestTime = Date.now();
21529
22142
  }
21530
- async request(method, path48, body) {
22143
+ async request(method, path49, body) {
21531
22144
  await this.rateLimit();
21532
- const url = `${this.baseUrl}${path48}`;
22145
+ const url = `${this.baseUrl}${path49}`;
21533
22146
  const headers = {
21534
22147
  Authorization: `Bearer ${this.apiKey}`,
21535
22148
  "Content-Type": "application/json",
@@ -21602,8 +22215,8 @@ async function requestCloudflare(cfApiToken, zoneId, options) {
21602
22215
  }
21603
22216
  return envelope.result;
21604
22217
  }
21605
- function buildUrl(zoneId, path48 = "/dns_records", query) {
21606
- const normalizedPath = path48.startsWith("/") ? path48 : `/${path48}`;
22218
+ function buildUrl(zoneId, path49 = "/dns_records", query) {
22219
+ const normalizedPath = path49.startsWith("/") ? path49 : `/${path49}`;
21607
22220
  const url = new URL(
21608
22221
  `${CLOUDFLARE_API_BASE_URL}/zones/${zoneId}${normalizedPath}`
21609
22222
  );
@@ -21743,12 +22356,12 @@ function registerDeployClient(server2) {
21743
22356
  title: "Deploy Client",
21744
22357
  description: "Provision a Hostinger VPS and deploy exe-os for a client. Creates VPS, waits for ready state, runs Ansible playbook, verifies health.",
21745
22358
  inputSchema: {
21746
- client_name: z60.string().min(1).describe("Client name (used for hostname and identification)"),
21747
- domain: z60.string().min(1).describe("Domain name for the deployment (e.g., client.exe.ai)"),
21748
- region: z60.string().default("jakarta").describe("VPS region (default: jakarta)"),
21749
- plan: z60.string().default("kvm-2").describe("Hostinger VPS plan (default: kvm-2)"),
21750
- ssl_email: z60.string().email().describe("Email for Let's Encrypt SSL certificate"),
21751
- user_id: z60.string().min(1).describe("User/customer ID for inventory tracking")
22359
+ client_name: z61.string().min(1).describe("Client name (used for hostname and identification)"),
22360
+ domain: z61.string().min(1).describe("Domain name for the deployment (e.g., client.exe.ai)"),
22361
+ region: z61.string().default("jakarta").describe("VPS region (default: jakarta)"),
22362
+ plan: z61.string().default("kvm-2").describe("Hostinger VPS plan (default: kvm-2)"),
22363
+ ssl_email: z61.string().email().describe("Email for Let's Encrypt SSL certificate"),
22364
+ user_id: z61.string().min(1).describe("User/customer ID for inventory tracking")
21752
22365
  }
21753
22366
  },
21754
22367
  async ({ client_name, domain, region, plan, ssl_email, user_id }) => {
@@ -21816,12 +22429,12 @@ async function waitForReady(client, vpsId) {
21816
22429
  }
21817
22430
  async function runAnsiblePlaybook(vpsIp, domain, sslEmail, clientName) {
21818
22431
  const safeClientName = clientName.replace(/[^a-zA-Z0-9_-]/g, "-");
21819
- const playbookDir = path35.resolve(process.cwd(), "infrastructure", "ansible");
21820
- const playbookPath = path35.join(playbookDir, "deploy.yml");
21821
- const inventoryPath = path35.join(playbookDir, "inventory", "hosts.yml");
21822
- const clientVarsPath = path35.join(playbookDir, "vars", `${safeClientName}.yml`);
21823
- const varsDir = path35.join(playbookDir, "vars");
21824
- if (!path35.resolve(clientVarsPath).startsWith(path35.resolve(varsDir))) {
22432
+ const playbookDir = path36.resolve(process.cwd(), "infrastructure", "ansible");
22433
+ const playbookPath = path36.join(playbookDir, "deploy.yml");
22434
+ const inventoryPath = path36.join(playbookDir, "inventory", "hosts.yml");
22435
+ const clientVarsPath = path36.join(playbookDir, "vars", `${safeClientName}.yml`);
22436
+ const varsDir = path36.join(playbookDir, "vars");
22437
+ if (!path36.resolve(clientVarsPath).startsWith(path36.resolve(varsDir))) {
21825
22438
  throw new Error(`Invalid client name for vars path: ${clientName}`);
21826
22439
  }
21827
22440
  const args = [
@@ -21837,7 +22450,7 @@ async function runAnsiblePlaybook(vpsIp, domain, sslEmail, clientName) {
21837
22450
  "-e",
21838
22451
  `client_name=${safeClientName}`
21839
22452
  ];
21840
- if (existsSync30(clientVarsPath)) {
22453
+ if (existsSync31(clientVarsPath)) {
21841
22454
  args.push("-e", `@${clientVarsPath}`);
21842
22455
  }
21843
22456
  try {
@@ -21910,7 +22523,7 @@ function buildInventoryRecord(params) {
21910
22523
 
21911
22524
  // src/mcp/tools/get-license-status.ts
21912
22525
  init_license();
21913
- import { z as z61 } from "zod";
22526
+ import { z as z62 } from "zod";
21914
22527
  var FEATURES = [
21915
22528
  "cloud_sync",
21916
22529
  "external_agents",
@@ -21924,7 +22537,7 @@ function registerGetLicenseStatus(server2) {
21924
22537
  title: "Get License Status",
21925
22538
  description: "Get current license status: plan, validity, feature gates, limits, and expiry.",
21926
22539
  inputSchema: {
21927
- _dummy: z61.string().optional().describe("Unused \u2014 no input required")
22540
+ _dummy: z62.string().optional().describe("Unused \u2014 no input required")
21928
22541
  }
21929
22542
  },
21930
22543
  async () => {
@@ -21978,11 +22591,11 @@ function registerGetLicenseStatus(server2) {
21978
22591
  // src/mcp/tools/create-license.ts
21979
22592
  init_license();
21980
22593
  import os15 from "os";
21981
- import path36 from "path";
22594
+ import path37 from "path";
21982
22595
  import { randomBytes as randomBytes2, randomUUID as randomUUID6 } from "crypto";
21983
22596
  import { createRequire as createRequire3 } from "module";
21984
22597
  import { pathToFileURL as pathToFileURL3 } from "url";
21985
- import { z as z62 } from "zod";
22598
+ import { z as z63 } from "zod";
21986
22599
  var prismaPromise = null;
21987
22600
  function loadPrisma() {
21988
22601
  if (!prismaPromise) {
@@ -21994,8 +22607,8 @@ function loadPrisma() {
21994
22607
  if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
21995
22608
  return new Ctor2();
21996
22609
  }
21997
- const exeDbRoot = process.env.EXE_DB_ROOT ?? path36.join(os15.homedir(), "exe-db");
21998
- const req = createRequire3(path36.join(exeDbRoot, "package.json"));
22610
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path37.join(os15.homedir(), "exe-db");
22611
+ const req = createRequire3(path37.join(exeDbRoot, "package.json"));
21999
22612
  const entry = req.resolve("@prisma/client");
22000
22613
  const mod = await import(pathToFileURL3(entry).href);
22001
22614
  const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
@@ -22015,10 +22628,10 @@ function registerCreateLicense(server2) {
22015
22628
  title: "Create License",
22016
22629
  description: "Generate an exe_sk_* license key for a user. Stores in billing.licenses. Returns the key to give to the customer.",
22017
22630
  inputSchema: {
22018
- email: z62.string().email().describe("Customer email address"),
22019
- name: z62.string().optional().describe("Customer name"),
22020
- plan: z62.enum(["free", "pro", "team", "agency", "enterprise"]).default("pro").describe("License plan tier"),
22021
- expires_in_days: z62.number().int().positive().default(365).describe("Days until expiration (default 365)")
22631
+ email: z63.string().email().describe("Customer email address"),
22632
+ name: z63.string().optional().describe("Customer name"),
22633
+ plan: z63.enum(["free", "pro", "team", "agency", "enterprise"]).default("pro").describe("License plan tier"),
22634
+ expires_in_days: z63.number().int().positive().default(365).describe("Days until expiration (default 365)")
22022
22635
  }
22023
22636
  },
22024
22637
  async ({ email, name, plan, expires_in_days }) => {
@@ -22070,10 +22683,10 @@ Give this key to the customer. They paste it during \`exe-os setup\`.`);
22070
22683
 
22071
22684
  // src/mcp/tools/list-licenses.ts
22072
22685
  import os16 from "os";
22073
- import path37 from "path";
22686
+ import path38 from "path";
22074
22687
  import { createRequire as createRequire4 } from "module";
22075
22688
  import { pathToFileURL as pathToFileURL4 } from "url";
22076
- import { z as z63 } from "zod";
22689
+ import { z as z64 } from "zod";
22077
22690
  var prismaPromise2 = null;
22078
22691
  function loadPrisma2() {
22079
22692
  if (!prismaPromise2) {
@@ -22085,8 +22698,8 @@ function loadPrisma2() {
22085
22698
  if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
22086
22699
  return new Ctor2();
22087
22700
  }
22088
- const exeDbRoot = process.env.EXE_DB_ROOT ?? path37.join(os16.homedir(), "exe-db");
22089
- const req = createRequire4(path37.join(exeDbRoot, "package.json"));
22701
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path38.join(os16.homedir(), "exe-db");
22702
+ const req = createRequire4(path38.join(exeDbRoot, "package.json"));
22090
22703
  const entry = req.resolve("@prisma/client");
22091
22704
  const mod = await import(pathToFileURL4(entry).href);
22092
22705
  const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
@@ -22103,7 +22716,7 @@ function registerListLicenses(server2) {
22103
22716
  title: "List Licenses",
22104
22717
  description: "List all issued licenses with status (active/expired/revoked). Optionally filter by plan.",
22105
22718
  inputSchema: {
22106
- plan: z63.enum(["free", "pro", "team", "agency", "enterprise"]).optional().describe("Filter by plan tier (omit for all)")
22719
+ plan: z64.enum(["free", "pro", "team", "agency", "enterprise"]).optional().describe("Filter by plan tier (omit for all)")
22107
22720
  }
22108
22721
  },
22109
22722
  async ({ plan }) => {
@@ -22154,7 +22767,7 @@ function registerListLicenses(server2) {
22154
22767
 
22155
22768
  // src/mcp/tools/activate-license.ts
22156
22769
  init_license();
22157
- import { z as z64 } from "zod";
22770
+ import { z as z65 } from "zod";
22158
22771
  function registerActivateLicense(server2) {
22159
22772
  server2.registerTool(
22160
22773
  "activate_license",
@@ -22162,7 +22775,7 @@ function registerActivateLicense(server2) {
22162
22775
  title: "Activate License",
22163
22776
  description: "Activate an exe_sk_* license key on this device. Writes to ~/.exe-os/license.key, validates against Postgres, and caches the result.",
22164
22777
  inputSchema: {
22165
- key: z64.string().startsWith("exe_sk_").describe("License key (exe_sk_*)")
22778
+ key: z65.string().startsWith("exe_sk_").describe("License key (exe_sk_*)")
22166
22779
  }
22167
22780
  },
22168
22781
  async ({ key }) => {
@@ -22208,18 +22821,18 @@ Key saved to ~/.exe-os/license.key. Device ID: ${deviceId}`);
22208
22821
  }
22209
22822
 
22210
22823
  // src/mcp/tools/create-trigger.ts
22211
- import { z as z65 } from "zod";
22824
+ import { z as z66 } from "zod";
22212
22825
 
22213
22826
  // src/automation/trigger-engine.ts
22214
- import { readFileSync as readFileSync23, writeFileSync as writeFileSync17, existsSync as existsSync31, mkdirSync as mkdirSync15 } from "fs";
22827
+ import { readFileSync as readFileSync24, writeFileSync as writeFileSync18, existsSync as existsSync32, mkdirSync as mkdirSync16 } from "fs";
22215
22828
  import { randomUUID as randomUUID7 } from "crypto";
22216
- import path38 from "path";
22829
+ import path39 from "path";
22217
22830
  import os17 from "os";
22218
- var TRIGGERS_PATH = path38.join(os17.homedir(), ".exe-os", "triggers.json");
22831
+ var TRIGGERS_PATH = path39.join(os17.homedir(), ".exe-os", "triggers.json");
22219
22832
  function loadTriggers(project) {
22220
- if (!existsSync31(TRIGGERS_PATH)) return [];
22833
+ if (!existsSync32(TRIGGERS_PATH)) return [];
22221
22834
  try {
22222
- const raw = readFileSync23(TRIGGERS_PATH, "utf-8");
22835
+ const raw = readFileSync24(TRIGGERS_PATH, "utf-8");
22223
22836
  const all = JSON.parse(raw);
22224
22837
  if (!Array.isArray(all)) return [];
22225
22838
  if (project) {
@@ -22231,9 +22844,9 @@ function loadTriggers(project) {
22231
22844
  }
22232
22845
  }
22233
22846
  function saveTriggers(triggers) {
22234
- const dir = path38.dirname(TRIGGERS_PATH);
22235
- if (!existsSync31(dir)) mkdirSync15(dir, { recursive: true });
22236
- writeFileSync17(TRIGGERS_PATH, JSON.stringify(triggers, null, 2), "utf-8");
22847
+ const dir = path39.dirname(TRIGGERS_PATH);
22848
+ if (!existsSync32(dir)) mkdirSync16(dir, { recursive: true });
22849
+ writeFileSync18(TRIGGERS_PATH, JSON.stringify(triggers, null, 2), "utf-8");
22237
22850
  }
22238
22851
  function createNewTrigger(input) {
22239
22852
  const triggers = loadTriggers();
@@ -22389,14 +23002,14 @@ function addToCrontab(id, cron, prompt, projectDir) {
22389
23002
  }
22390
23003
 
22391
23004
  // src/mcp/tools/create-trigger.ts
22392
- var conditionSchema = z65.object({
22393
- field: z65.string().describe("Dot-path field to evaluate, e.g., 'stage' or 'amount'"),
22394
- op: z65.enum(["eq", "neq", "gt", "lt", "gte", "lte", "contains", "not_contains"]).describe("Comparison operator"),
22395
- value: z65.string().or(z65.number()).or(z65.boolean()).describe("Value to compare against")
23005
+ var conditionSchema = z66.object({
23006
+ field: z66.string().describe("Dot-path field to evaluate, e.g., 'stage' or 'amount'"),
23007
+ op: z66.enum(["eq", "neq", "gt", "lt", "gte", "lte", "contains", "not_contains"]).describe("Comparison operator"),
23008
+ value: z66.string().or(z66.number()).or(z66.boolean()).describe("Value to compare against")
22396
23009
  });
22397
- var actionSchema = z65.object({
22398
- type: z65.enum(["send_whatsapp", "send_message", "create_task", "mcp_tool"]).describe("Action type to execute"),
22399
- params: z65.record(z65.string(), z65.string()).describe(
23010
+ var actionSchema = z66.object({
23011
+ type: z66.enum(["send_whatsapp", "send_message", "create_task", "mcp_tool"]).describe("Action type to execute"),
23012
+ params: z66.record(z66.string(), z66.string()).describe(
22400
23013
  "Action parameters. Supports {{record.field}} templates for dynamic values."
22401
23014
  )
22402
23015
  });
@@ -22407,18 +23020,18 @@ function registerCreateTrigger(server2) {
22407
23020
  title: "Create Trigger",
22408
23021
  description: "Create a CRM event trigger or scheduled automation. When matching events occur (e.g., Deal.updated with stage=won), configured actions fire automatically (send_whatsapp, create_task, etc.).",
22409
23022
  inputSchema: {
22410
- name: z65.string().describe("Human-readable trigger name"),
22411
- event: z65.string().describe(
23023
+ name: z66.string().describe("Human-readable trigger name"),
23024
+ event: z66.string().describe(
22412
23025
  'CRM event to match, e.g., "Deal.updated", "Order.created", "*" for all'
22413
23026
  ),
22414
- conditions: z65.array(conditionSchema).default([]).describe("Conditions that must all match (AND logic)"),
22415
- actions: z65.array(actionSchema).min(1).describe("Actions to execute when trigger fires"),
22416
- project: z65.string().optional().describe("Scope trigger to a specific project"),
22417
- enabled: z65.boolean().default(true).describe("Whether trigger is active"),
22418
- schedule: z65.string().optional().describe(
23027
+ conditions: z66.array(conditionSchema).default([]).describe("Conditions that must all match (AND logic)"),
23028
+ actions: z66.array(actionSchema).min(1).describe("Actions to execute when trigger fires"),
23029
+ project: z66.string().optional().describe("Scope trigger to a specific project"),
23030
+ enabled: z66.boolean().default(true).describe("Whether trigger is active"),
23031
+ schedule: z66.string().optional().describe(
22419
23032
  'Cron schedule for time-based triggers, e.g., "0 9 * * *" or "Monday 9am"'
22420
23033
  ),
22421
- query: z65.string().optional().describe(
23034
+ query: z66.string().optional().describe(
22422
23035
  "CRM GraphQL query to run on schedule (required if schedule is set)"
22423
23036
  )
22424
23037
  }
@@ -22491,7 +23104,7 @@ Enabled: ${trigger.enabled}` + scheduleInfo;
22491
23104
  }
22492
23105
 
22493
23106
  // src/mcp/tools/list-triggers.ts
22494
- import { z as z66 } from "zod";
23107
+ import { z as z67 } from "zod";
22495
23108
  function registerListTriggers(server2) {
22496
23109
  server2.registerTool(
22497
23110
  "list_triggers",
@@ -22499,7 +23112,7 @@ function registerListTriggers(server2) {
22499
23112
  title: "List Triggers",
22500
23113
  description: "List configured CRM event triggers and scheduled automations.",
22501
23114
  inputSchema: {
22502
- project: z66.string().optional().describe("Filter triggers by project name")
23115
+ project: z67.string().optional().describe("Filter triggers by project name")
22503
23116
  }
22504
23117
  },
22505
23118
  async ({ project }) => {
@@ -22534,51 +23147,51 @@ function registerListTriggers(server2) {
22534
23147
  }
22535
23148
 
22536
23149
  // src/mcp/tools/apply-starter-pack.ts
22537
- import { z as z67 } from "zod";
23150
+ import { z as z68 } from "zod";
22538
23151
 
22539
23152
  // src/automation/starter-packs/index.ts
22540
- import { readFileSync as readFileSync24, readdirSync as readdirSync12, existsSync as existsSync32 } from "fs";
22541
- import path39 from "path";
23153
+ import { readFileSync as readFileSync25, readdirSync as readdirSync12, existsSync as existsSync33 } from "fs";
23154
+ import path40 from "path";
22542
23155
  import { fileURLToPath as fileURLToPath4 } from "url";
22543
- var __dirname = path39.dirname(fileURLToPath4(import.meta.url));
23156
+ var __dirname = path40.dirname(fileURLToPath4(import.meta.url));
22544
23157
  function listPacks() {
22545
- const packsDir = path39.join(__dirname, ".");
22546
- if (!existsSync32(packsDir)) return [];
23158
+ const packsDir = path40.join(__dirname, ".");
23159
+ if (!existsSync33(packsDir)) return [];
22547
23160
  return readdirSync12(packsDir, { withFileTypes: true }).filter(
22548
- (d) => d.isDirectory() && existsSync32(path39.join(packsDir, d.name, "custom-objects.json"))
23161
+ (d) => d.isDirectory() && existsSync33(path40.join(packsDir, d.name, "custom-objects.json"))
22549
23162
  ).map((d) => d.name);
22550
23163
  }
22551
23164
  function loadPack(industry) {
22552
- const packDir = path39.join(__dirname, industry);
22553
- const objectsPath = path39.join(packDir, "custom-objects.json");
22554
- const triggersPath = path39.join(packDir, "triggers.json");
22555
- const wikiDir = path39.join(packDir, "wiki-seeds");
22556
- const manifestPath = path39.join(packDir, "pack.json");
22557
- const identityContextPath = path39.join(packDir, "identity-context.md");
22558
- if (!existsSync32(objectsPath)) return null;
23165
+ const packDir = path40.join(__dirname, industry);
23166
+ const objectsPath = path40.join(packDir, "custom-objects.json");
23167
+ const triggersPath = path40.join(packDir, "triggers.json");
23168
+ const wikiDir = path40.join(packDir, "wiki-seeds");
23169
+ const manifestPath = path40.join(packDir, "pack.json");
23170
+ const identityContextPath = path40.join(packDir, "identity-context.md");
23171
+ if (!existsSync33(objectsPath)) return null;
22559
23172
  let customObjects = [];
22560
23173
  try {
22561
23174
  customObjects = JSON.parse(
22562
- readFileSync24(objectsPath, "utf-8")
23175
+ readFileSync25(objectsPath, "utf-8")
22563
23176
  );
22564
23177
  } catch {
22565
23178
  customObjects = [];
22566
23179
  }
22567
23180
  let triggers = [];
22568
- if (existsSync32(triggersPath)) {
23181
+ if (existsSync33(triggersPath)) {
22569
23182
  try {
22570
23183
  triggers = JSON.parse(
22571
- readFileSync24(triggersPath, "utf-8")
23184
+ readFileSync25(triggersPath, "utf-8")
22572
23185
  );
22573
23186
  } catch {
22574
23187
  triggers = [];
22575
23188
  }
22576
23189
  }
22577
23190
  const wikiSeeds = [];
22578
- if (existsSync32(wikiDir)) {
23191
+ if (existsSync33(wikiDir)) {
22579
23192
  const files = readdirSync12(wikiDir).filter((f) => f.endsWith(".md"));
22580
23193
  for (const file of files) {
22581
- const content = readFileSync24(path39.join(wikiDir, file), "utf-8");
23194
+ const content = readFileSync25(path40.join(wikiDir, file), "utf-8");
22582
23195
  const titleMatch = content.match(/^#\s+(.+)/m);
22583
23196
  wikiSeeds.push({
22584
23197
  filename: file,
@@ -22588,17 +23201,17 @@ function loadPack(industry) {
22588
23201
  }
22589
23202
  }
22590
23203
  let manifest = {};
22591
- if (existsSync32(manifestPath)) {
23204
+ if (existsSync33(manifestPath)) {
22592
23205
  try {
22593
- manifest = JSON.parse(readFileSync24(manifestPath, "utf-8"));
23206
+ manifest = JSON.parse(readFileSync25(manifestPath, "utf-8"));
22594
23207
  } catch {
22595
23208
  manifest = {};
22596
23209
  }
22597
23210
  }
22598
23211
  let identityContext = null;
22599
- if (existsSync32(identityContextPath)) {
23212
+ if (existsSync33(identityContextPath)) {
22600
23213
  try {
22601
- identityContext = readFileSync24(identityContextPath, "utf-8");
23214
+ identityContext = readFileSync25(identityContextPath, "utf-8");
22602
23215
  } catch {
22603
23216
  identityContext = null;
22604
23217
  }
@@ -22655,8 +23268,8 @@ function applyPack(industry, project) {
22655
23268
 
22656
23269
  // src/lib/client-coo.ts
22657
23270
  init_config();
22658
- import { existsSync as existsSync33, mkdirSync as mkdirSync16, writeFileSync as writeFileSync18 } from "fs";
22659
- import path40 from "path";
23271
+ import { existsSync as existsSync34, mkdirSync as mkdirSync17, writeFileSync as writeFileSync19 } from "fs";
23272
+ import path41 from "path";
22660
23273
 
22661
23274
  // src/lib/employee-templates.ts
22662
23275
  init_global_procedures();
@@ -22796,18 +23409,18 @@ var ClientCOOClobberError = class extends Error {
22796
23409
  var COO_ROLE = "Chief Operating Officer";
22797
23410
  var FEEDBACK_BEHAVIOR_CONTENT = "Tag exe-os issues with needs_improvement \u2014 this is the feedback loop that surfaces bugs, gaps, and friction to the founder each Monday.";
22798
23411
  async function provisionClientCOO(vars, opts = {}) {
22799
- const identityDir = opts.identityDir ?? path40.join(EXE_AI_DIR, "identity");
23412
+ const identityDir = opts.identityDir ?? path41.join(EXE_AI_DIR, "identity");
22800
23413
  const rosterPath = opts.employeesPath ?? EMPLOYEES_PATH;
22801
23414
  const storeFeedbackBehavior = opts.storeFeedbackBehavior ?? true;
22802
- const identityPath2 = path40.join(identityDir, `${vars.agent_name}.md`);
22803
- if (existsSync33(identityPath2)) {
23415
+ const identityPath2 = path41.join(identityDir, `${vars.agent_name}.md`);
23416
+ if (existsSync34(identityPath2)) {
22804
23417
  throw new ClientCOOClobberError(vars.agent_name, identityPath2);
22805
23418
  }
22806
23419
  const body = renderClientCOOTemplate(vars);
22807
- if (!existsSync33(identityDir)) {
22808
- mkdirSync16(identityDir, { recursive: true });
23420
+ if (!existsSync34(identityDir)) {
23421
+ mkdirSync17(identityDir, { recursive: true });
22809
23422
  }
22810
- writeFileSync18(identityPath2, body, "utf-8");
23423
+ writeFileSync19(identityPath2, body, "utf-8");
22811
23424
  const employees = await loadEmployees(rosterPath);
22812
23425
  const existing = employees.find((e) => e.name === vars.agent_name);
22813
23426
  let addedToRoster = false;
@@ -22843,17 +23456,17 @@ function registerApplyStarterPack(server2) {
22843
23456
  title: "Apply Starter Pack",
22844
23457
  description: "Apply an industry starter pack to a project. Sets up CRM custom objects, pre-wired automation triggers, and wiki seed content. When the pack creates a Client COO (e.g. distribution) and agent_name, company_name, founder_name are all provided, also provisions the COO identity, roster entry, and feedback-loop behavior. Available packs: distribution. More coming.",
22845
23458
  inputSchema: {
22846
- industry: z67.string().describe(
23459
+ industry: z68.string().describe(
22847
23460
  'Industry pack to apply (e.g., "distribution"). Use without args to list available packs.'
22848
23461
  ),
22849
- project: z67.string().describe("Project name to scope the triggers to"),
22850
- agent_name: z67.string().optional().describe(
23462
+ project: z68.string().describe("Project name to scope the triggers to"),
23463
+ agent_name: z68.string().optional().describe(
22851
23464
  "Optional. Lowercase alphanumeric name for the Client COO agent. Required (alongside company_name and founder_name) to provision a COO."
22852
23465
  ),
22853
- company_name: z67.string().optional().describe(
23466
+ company_name: z68.string().optional().describe(
22854
23467
  "Optional. The client company the COO serves. Required to provision a COO."
22855
23468
  ),
22856
- founder_name: z67.string().optional().describe(
23469
+ founder_name: z68.string().optional().describe(
22857
23470
  "Optional. The founder the COO reports to. Required to provision a COO."
22858
23471
  )
22859
23472
  }
@@ -22998,19 +23611,19 @@ ${err.message}`
22998
23611
  }
22999
23612
 
23000
23613
  // src/mcp/tools/load-skill.ts
23001
- import { z as z68 } from "zod";
23002
- import { readFileSync as readFileSync25, readdirSync as readdirSync13, statSync as statSync6 } from "fs";
23003
- import path41 from "path";
23614
+ import { z as z69 } from "zod";
23615
+ import { readFileSync as readFileSync26, readdirSync as readdirSync13, statSync as statSync6 } from "fs";
23616
+ import path42 from "path";
23004
23617
  import { homedir as homedir7 } from "os";
23005
- var SKILLS_DIR = path41.join(homedir7(), ".claude", "skills");
23618
+ var SKILLS_DIR = path42.join(homedir7(), ".claude", "skills");
23006
23619
  function listAvailableSkills() {
23007
23620
  try {
23008
23621
  const entries = readdirSync13(SKILLS_DIR);
23009
23622
  return entries.filter((entry) => {
23010
23623
  try {
23011
- const entryPath = path41.join(SKILLS_DIR, entry);
23624
+ const entryPath = path42.join(SKILLS_DIR, entry);
23012
23625
  if (!statSync6(entryPath).isDirectory()) return false;
23013
- const skillFile = path41.join(entryPath, "SKILL.md");
23626
+ const skillFile = path42.join(entryPath, "SKILL.md");
23014
23627
  statSync6(skillFile);
23015
23628
  return true;
23016
23629
  } catch {
@@ -23028,7 +23641,7 @@ function registerLoadSkill(server2) {
23028
23641
  title: "Load Skill",
23029
23642
  description: "Load domain-specific guidance into your context. Use when you need specialized knowledge for a task (e.g., load_skill('seo') before doing SEO work, load_skill('code-reviewer') before reviewing code). Pass skill_name='list' to see all available skills.",
23030
23643
  inputSchema: {
23031
- skill_name: z68.string().describe(
23644
+ skill_name: z69.string().describe(
23032
23645
  "Skill to load (e.g. 'seo', 'code-reviewer', 'frontend-design'). Pass 'list' to see all available skills."
23033
23646
  )
23034
23647
  }
@@ -23053,10 +23666,10 @@ ${skills.map((s) => `- ${s}`).join("\n")}`
23053
23666
  }]
23054
23667
  };
23055
23668
  }
23056
- const sanitized = path41.basename(skill_name);
23057
- const skillFile = path41.join(SKILLS_DIR, sanitized, "SKILL.md");
23669
+ const sanitized = path42.basename(skill_name);
23670
+ const skillFile = path42.join(SKILLS_DIR, sanitized, "SKILL.md");
23058
23671
  try {
23059
- const content = readFileSync25(skillFile, "utf-8");
23672
+ const content = readFileSync26(skillFile, "utf-8");
23060
23673
  return {
23061
23674
  content: [{
23062
23675
  type: "text",
@@ -23084,18 +23697,18 @@ ${available.map((s) => `- ${s}`).join("\n")}` : "\n\nNo skills found in ~/.claud
23084
23697
 
23085
23698
  // src/mcp/tools/export-orchestration.ts
23086
23699
  init_active_agent();
23087
- import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync20 } from "fs";
23088
- import path43 from "path";
23089
- import { z as z69 } from "zod";
23700
+ import { mkdirSync as mkdirSync19, writeFileSync as writeFileSync21 } from "fs";
23701
+ import path44 from "path";
23702
+ import { z as z70 } from "zod";
23090
23703
 
23091
23704
  // src/lib/orchestration-package.ts
23092
23705
  init_database();
23093
23706
  init_identity();
23094
23707
  init_platform_procedures();
23095
23708
  import { randomUUID as randomUUID8 } from "crypto";
23096
- import { copyFileSync as copyFileSync2, existsSync as existsSync34, mkdirSync as mkdirSync17, readFileSync as readFileSync26, writeFileSync as writeFileSync19 } from "fs";
23709
+ import { copyFileSync as copyFileSync2, existsSync as existsSync35, mkdirSync as mkdirSync18, readFileSync as readFileSync27, writeFileSync as writeFileSync20 } from "fs";
23097
23710
  import os18 from "os";
23098
- import path42 from "path";
23711
+ import path43 from "path";
23099
23712
  var PACKAGE_VERSION = "1.0";
23100
23713
  var ROSTER_FILENAME = "exe-employees.json";
23101
23714
  var ROSTER_BACKUP_FILENAME = "exe-employees.json.bak";
@@ -23161,15 +23774,15 @@ function validateProcedureEntry(value, index) {
23161
23774
  };
23162
23775
  }
23163
23776
  function getRosterPath() {
23164
- return path42.join(os18.homedir(), EXE_OS_DIRNAME, ROSTER_FILENAME);
23777
+ return path43.join(os18.homedir(), EXE_OS_DIRNAME, ROSTER_FILENAME);
23165
23778
  }
23166
23779
  function getBackupPath() {
23167
- return path42.join(os18.homedir(), EXE_OS_DIRNAME, ROSTER_BACKUP_FILENAME);
23780
+ return path43.join(os18.homedir(), EXE_OS_DIRNAME, ROSTER_BACKUP_FILENAME);
23168
23781
  }
23169
23782
  function readRosterFile() {
23170
23783
  const rosterPath = getRosterPath();
23171
- if (!existsSync34(rosterPath)) return [];
23172
- const raw = readFileSync26(rosterPath, "utf-8");
23784
+ if (!existsSync35(rosterPath)) return [];
23785
+ const raw = readFileSync27(rosterPath, "utf-8");
23173
23786
  const parsed = JSON.parse(raw);
23174
23787
  if (!Array.isArray(parsed)) {
23175
23788
  throw new Error("Roster file must contain a JSON array");
@@ -23181,8 +23794,8 @@ function writeRosterFile(roster) {
23181
23794
  throw new Error("Refusing to write empty roster \u2014 this would delete all employees");
23182
23795
  }
23183
23796
  const rosterPath = getRosterPath();
23184
- mkdirSync17(path42.dirname(rosterPath), { recursive: true });
23185
- if (existsSync34(rosterPath)) {
23797
+ mkdirSync18(path43.dirname(rosterPath), { recursive: true });
23798
+ if (existsSync35(rosterPath)) {
23186
23799
  const currentRoster = readRosterFile();
23187
23800
  if (roster.length < currentRoster.length) {
23188
23801
  throw new Error(
@@ -23191,7 +23804,7 @@ function writeRosterFile(roster) {
23191
23804
  }
23192
23805
  copyFileSync2(rosterPath, getBackupPath());
23193
23806
  }
23194
- writeFileSync19(rosterPath, `${JSON.stringify(roster, null, 2)}
23807
+ writeFileSync20(rosterPath, `${JSON.stringify(roster, null, 2)}
23195
23808
  `, "utf-8");
23196
23809
  }
23197
23810
  function buildImportedRosterEntries(roster, timestamp) {
@@ -23446,15 +24059,15 @@ function registerExportOrchestration(server2) {
23446
24059
  title: "Export Orchestration",
23447
24060
  description: "Export roster, identities, behaviors, and customer procedures to a JSON package.",
23448
24061
  inputSchema: {
23449
- output_path: z69.string().describe("File path to write the JSON package")
24062
+ output_path: z70.string().describe("File path to write the JSON package")
23450
24063
  }
23451
24064
  },
23452
24065
  async ({ output_path }) => {
23453
24066
  try {
23454
24067
  await initStore();
23455
24068
  const pkg = await exportOrchestration(getActiveAgent().agentId);
23456
- mkdirSync18(path43.dirname(output_path), { recursive: true });
23457
- writeFileSync20(output_path, `${JSON.stringify(pkg, null, 2)}
24069
+ mkdirSync19(path44.dirname(output_path), { recursive: true });
24070
+ writeFileSync21(output_path, `${JSON.stringify(pkg, null, 2)}
23458
24071
  `, "utf-8");
23459
24072
  return {
23460
24073
  content: [{
@@ -23476,8 +24089,8 @@ function registerExportOrchestration(server2) {
23476
24089
  }
23477
24090
 
23478
24091
  // src/mcp/tools/import-orchestration.ts
23479
- import { readFileSync as readFileSync27 } from "fs";
23480
- import { z as z70 } from "zod";
24092
+ import { readFileSync as readFileSync28 } from "fs";
24093
+ import { z as z71 } from "zod";
23481
24094
  init_store();
23482
24095
  init_active_agent();
23483
24096
  init_employees();
@@ -23488,8 +24101,8 @@ function registerImportOrchestration(server2) {
23488
24101
  title: "Import Orchestration",
23489
24102
  description: "Import roster, identities, behaviors, and procedures from an orchestration package. Restricted to coordinator/founder.",
23490
24103
  inputSchema: {
23491
- package_path: z70.string().describe("Path to the orchestration package JSON file"),
23492
- 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")
24104
+ package_path: z71.string().describe("Path to the orchestration package JSON file"),
24105
+ merge_strategy: z71.enum(["replace", "merge"]).default("merge").describe("How to apply the package: both strategies are additive-only \u2014 existing data is never deleted or overwritten")
23493
24106
  }
23494
24107
  },
23495
24108
  async ({ package_path, merge_strategy }) => {
@@ -23506,7 +24119,7 @@ function registerImportOrchestration(server2) {
23506
24119
  };
23507
24120
  }
23508
24121
  await initStore();
23509
- const raw = readFileSync27(package_path, "utf-8");
24122
+ const raw = readFileSync28(package_path, "utf-8");
23510
24123
  const pkg = validatePackage(JSON.parse(raw));
23511
24124
  const result = await importOrchestration(pkg, merge_strategy);
23512
24125
  return {
@@ -23534,7 +24147,7 @@ init_platform_procedures();
23534
24147
  init_active_agent();
23535
24148
  init_database();
23536
24149
  init_employees();
23537
- import { z as z71 } from "zod";
24150
+ import { z as z72 } from "zod";
23538
24151
  function registerCompanyProcedureTool(server2, toolName) {
23539
24152
  server2.registerTool(
23540
24153
  toolName,
@@ -23542,12 +24155,12 @@ function registerCompanyProcedureTool(server2, toolName) {
23542
24155
  title: "Company Procedure",
23543
24156
  description: "Manage company procedures (customer-owned Layer 0 rules) that supersede identity, expertise, and experience. Actions: store (create new, restricted), list (view all, open), deactivate (soft-delete, restricted).",
23544
24157
  inputSchema: {
23545
- action: z71.enum(["store", "list", "deactivate"]).describe("Action to perform"),
23546
- title: z71.string().optional().describe("Short title for the procedure (store)"),
23547
- content: z71.string().max(500).optional().describe("The procedure content \u2014 clear, actionable instruction (store)"),
23548
- priority: z71.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always (default). p1 = standard. p2 = nice-to-have."),
23549
- domain: z71.string().optional().describe("Category: workflow, code-style, communication, architecture, testing, security"),
23550
- procedure_id: z71.string().optional().describe("UUID of the company procedure (deactivate)")
24158
+ action: z72.enum(["store", "list", "deactivate"]).describe("Action to perform"),
24159
+ title: z72.string().optional().describe("Short title for the procedure (store)"),
24160
+ content: z72.string().max(500).optional().describe("The procedure content \u2014 clear, actionable instruction (store)"),
24161
+ priority: z72.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always (default). p1 = standard. p2 = nice-to-have."),
24162
+ domain: z72.string().optional().describe("Category: workflow, code-style, communication, architecture, testing, security"),
24163
+ procedure_id: z72.string().optional().describe("UUID of the company procedure (deactivate)")
23551
24164
  }
23552
24165
  },
23553
24166
  async ({ action, title, content, priority, domain, procedure_id }) => {
@@ -23680,6 +24293,7 @@ var ACTION_TO_TOOL2 = {
23680
24293
  memory_audit: "run_memory_audit",
23681
24294
  run_consolidation: "run_consolidation",
23682
24295
  cloud_sync: "cloud_sync",
24296
+ orchestration_phase: "orchestration_phase",
23683
24297
  backup_vps: "backup_vps",
23684
24298
  deploy_client: "deploy_client",
23685
24299
  license_status: "get_license_status",
@@ -23716,6 +24330,7 @@ function buildHandlers5() {
23716
24330
  registerRunMemoryAudit(localServer);
23717
24331
  registerRunConsolidation(localServer);
23718
24332
  registerCloudSync(localServer);
24333
+ registerOrchestrationPhase(localServer);
23719
24334
  registerBackupVps(localServer);
23720
24335
  registerDeployClient(localServer);
23721
24336
  registerGetLicenseStatus(localServer);
@@ -23738,41 +24353,42 @@ function registerConfig(server2) {
23738
24353
  title: "Config",
23739
24354
  description: "Consolidated COO/admin tool for runtime config, system health, licensing, triggers, orchestration import/export, and company procedures.",
23740
24355
  inputSchema: {
23741
- action: z72.enum(Object.keys(ACTION_TO_TOOL2)).describe("Admin/config operation"),
23742
- agent_id: z72.string().optional().describe("Agent id for set_agent_config/agent_spend/session queries"),
23743
- runtime: z72.string().optional().describe("Runtime for set_agent_config"),
23744
- model: z72.string().optional().describe("Model for set_agent_config"),
23745
- reasoning_effort: z72.string().optional().describe("Reasoning effort for Codex agents"),
23746
- dry_run: z72.boolean().optional().describe("Preview without applying where supported"),
23747
- fix: z72.boolean().optional().describe("Apply fixes for memory_audit where supported"),
23748
- verbose: z72.boolean().optional().describe("Verbose output where supported"),
23749
- project_name: z72.string().optional().describe("Project filter/name"),
23750
- since: z72.string().optional().describe("ISO lower-bound timestamp"),
23751
- limit: z72.coerce.number().optional().describe("Result limit"),
23752
- output_path: z72.string().optional().describe("Output path for export/backup"),
23753
- input_path: z72.string().optional().describe("Input path for import_orchestration"),
23754
- strategy: z72.enum(["merge", "replace"]).optional().describe("Import strategy; replace must still be additive-only per platform rules"),
23755
- license_key: z72.string().optional().describe("License key for activation/status"),
23756
- email: z72.string().optional().describe("Customer email for license creation"),
23757
- plan: z72.string().optional().describe("License plan"),
23758
- name: z72.string().optional().describe("Trigger/starter pack/procedure/client name"),
23759
- event: z72.string().optional().describe("Trigger event"),
23760
- conditions: z72.array(z72.record(z72.string(), z72.unknown())).optional().describe("Trigger conditions"),
23761
- actions: z72.array(z72.record(z72.string(), z72.unknown())).optional().describe("Trigger actions"),
23762
- enabled: z72.boolean().optional().describe("Trigger enabled flag"),
23763
- schedule: z72.string().optional().describe("Trigger schedule"),
23764
- query: z72.string().optional().describe("Trigger query or filter"),
23765
- skill_name: z72.string().optional().describe("Skill name for load_skill"),
23766
- pack_name: z72.string().optional().describe("Starter pack name"),
23767
- title: z72.string().optional().describe("Procedure title"),
23768
- content: z72.string().optional().describe("Procedure content"),
23769
- priority: z72.enum(["p0", "p1", "p2"]).optional().describe("Procedure priority"),
23770
- domain: z72.string().optional().describe("Procedure domain"),
23771
- procedure_id: z72.string().optional().describe("Procedure id for deactivate"),
23772
- subaction: z72.enum(["store", "list", "deactivate"]).optional().describe("Nested action for company_procedure/global_procedure"),
23773
- max_clusters: z72.coerce.number().optional().describe("Consolidation max clusters"),
23774
- force: z72.boolean().optional().describe("Force operation where supported"),
23775
- domain_name: z72.string().optional().describe("Client deployment domain")
24356
+ action: z73.enum(Object.keys(ACTION_TO_TOOL2)).describe("Admin/config operation"),
24357
+ agent_id: z73.string().optional().describe("Agent id for set_agent_config/agent_spend/session queries"),
24358
+ runtime: z73.string().optional().describe("Runtime for set_agent_config"),
24359
+ model: z73.string().optional().describe("Model for set_agent_config"),
24360
+ reasoning_effort: z73.string().optional().describe("Reasoning effort for Codex agents"),
24361
+ dry_run: z73.boolean().optional().describe("Preview without applying where supported"),
24362
+ fix: z73.boolean().optional().describe("Apply fixes for memory_audit where supported"),
24363
+ verbose: z73.boolean().optional().describe("Verbose output where supported"),
24364
+ project_name: z73.string().optional().describe("Project filter/name"),
24365
+ since: z73.string().optional().describe("ISO lower-bound timestamp"),
24366
+ limit: z73.coerce.number().optional().describe("Result limit"),
24367
+ output_path: z73.string().optional().describe("Output path for export/backup"),
24368
+ input_path: z73.string().optional().describe("Input path for import_orchestration"),
24369
+ strategy: z73.enum(["merge", "replace"]).optional().describe("Import strategy; replace must still be additive-only per platform rules"),
24370
+ license_key: z73.string().optional().describe("License key for activation/status"),
24371
+ email: z73.string().optional().describe("Customer email for license creation"),
24372
+ plan: z73.string().optional().describe("License plan"),
24373
+ name: z73.string().optional().describe("Trigger/starter pack/procedure/client name"),
24374
+ event: z73.string().optional().describe("Trigger event"),
24375
+ conditions: z73.array(z73.record(z73.string(), z73.unknown())).optional().describe("Trigger conditions"),
24376
+ actions: z73.array(z73.record(z73.string(), z73.unknown())).optional().describe("Trigger actions"),
24377
+ enabled: z73.boolean().optional().describe("Trigger enabled flag"),
24378
+ schedule: z73.string().optional().describe("Trigger schedule"),
24379
+ query: z73.string().optional().describe("Trigger query or filter"),
24380
+ skill_name: z73.string().optional().describe("Skill name for load_skill"),
24381
+ pack_name: z73.string().optional().describe("Starter pack name"),
24382
+ title: z73.string().optional().describe("Procedure title"),
24383
+ content: z73.string().optional().describe("Procedure content"),
24384
+ priority: z73.enum(["p0", "p1", "p2"]).optional().describe("Procedure priority"),
24385
+ domain: z73.string().optional().describe("Procedure domain"),
24386
+ procedure_id: z73.string().optional().describe("Procedure id for deactivate"),
24387
+ subaction: z73.enum(["store", "list", "deactivate"]).optional().describe("Nested action for company_procedure/global_procedure"),
24388
+ max_clusters: z73.coerce.number().optional().describe("Consolidation max clusters"),
24389
+ force: z73.boolean().optional().describe("Force operation where supported"),
24390
+ domain_name: z73.string().optional().describe("Client deployment domain"),
24391
+ phase: z73.enum(["phase_1_coo", "phase_2_executives", "phase_3_parallel_org", "1", "2", "3"]).optional().describe("Orchestration phase for orchestration_phase action")
23776
24392
  }
23777
24393
  }, async (input, extra) => {
23778
24394
  const action = input.action;
@@ -23793,10 +24409,10 @@ function registerConfig(server2) {
23793
24409
  }
23794
24410
 
23795
24411
  // src/mcp/tools/wiki.ts
23796
- import { z as z75 } from "zod";
24412
+ import { z as z76 } from "zod";
23797
24413
 
23798
24414
  // src/mcp/tools/list-wiki-pages.ts
23799
- import { z as z73 } from "zod";
24415
+ import { z as z74 } from "zod";
23800
24416
  var FETCH_TIMEOUT_MS3 = 1e4;
23801
24417
  function registerListWikiPages(server2) {
23802
24418
  server2.registerTool(
@@ -23805,8 +24421,8 @@ function registerListWikiPages(server2) {
23805
24421
  title: "List Wiki Pages",
23806
24422
  description: "List documents in an exe-wiki workspace. Optionally filter by folder.",
23807
24423
  inputSchema: {
23808
- workspace: z73.string().describe('Wiki workspace slug (e.g., "hygo")'),
23809
- folder: z73.string().optional().describe("Filter by folder path")
24424
+ workspace: z74.string().describe('Wiki workspace slug (e.g., "hygo")'),
24425
+ folder: z74.string().optional().describe("Filter by folder path")
23810
24426
  }
23811
24427
  },
23812
24428
  async ({ workspace, folder }) => {
@@ -23895,7 +24511,7 @@ function registerListWikiPages(server2) {
23895
24511
  }
23896
24512
 
23897
24513
  // src/mcp/tools/get-wiki-page.ts
23898
- import { z as z74 } from "zod";
24514
+ import { z as z75 } from "zod";
23899
24515
  var FETCH_TIMEOUT_MS4 = 1e4;
23900
24516
  function registerGetWikiPage(server2) {
23901
24517
  server2.registerTool(
@@ -23904,9 +24520,9 @@ function registerGetWikiPage(server2) {
23904
24520
  title: "Get Wiki Page",
23905
24521
  description: "Read a wiki page by document ID or title. Returns content, metadata, and folder path. Use title search when you know the page name but not the ID.",
23906
24522
  inputSchema: {
23907
- workspace: z74.string().describe('Wiki workspace slug (e.g., "hygo")'),
23908
- document_id: z74.string().optional().describe("Specific document ID (exact lookup)"),
23909
- title: z74.string().optional().describe("Search by title (fuzzy match)")
24523
+ workspace: z75.string().describe('Wiki workspace slug (e.g., "hygo")'),
24524
+ document_id: z75.string().optional().describe("Specific document ID (exact lookup)"),
24525
+ title: z75.string().optional().describe("Search by title (fuzzy match)")
23910
24526
  }
23911
24527
  },
23912
24528
  async ({ workspace, document_id, title }) => {
@@ -24088,14 +24704,14 @@ function registerWiki(server2) {
24088
24704
  title: "Wiki",
24089
24705
  description: "Consolidated wiki domain tool. Actions: list, get. Wiki writes flow through raw data ingestion/projection into the curated wiki store; direct create/update MCP tools have been removed.",
24090
24706
  inputSchema: {
24091
- action: z75.enum(["list", "get"]).describe("Wiki read operation. Writes use raw-data ingestion/projection, not direct MCP writes."),
24092
- workspace: z75.string().optional().describe("Wiki workspace slug"),
24093
- title: z75.string().optional().describe("Fuzzy page title lookup for get"),
24094
- content: z75.string().optional().describe("Reserved; wiki writes use raw-data ingestion/projection"),
24095
- folder: z75.string().optional().describe("Optional folder path for list"),
24096
- document_id: z75.string().optional().describe("Document ID for get"),
24097
- mode: z75.enum(["replace", "append"]).optional().describe("Reserved; direct wiki updates are removed"),
24098
- section: z75.string().optional().describe("Reserved; direct wiki updates are removed")
24707
+ action: z76.enum(["list", "get"]).describe("Wiki read operation. Writes use raw-data ingestion/projection, not direct MCP writes."),
24708
+ workspace: z76.string().optional().describe("Wiki workspace slug"),
24709
+ title: z76.string().optional().describe("Fuzzy page title lookup for get"),
24710
+ content: z76.string().optional().describe("Reserved; wiki writes use raw-data ingestion/projection"),
24711
+ folder: z76.string().optional().describe("Optional folder path for list"),
24712
+ document_id: z76.string().optional().describe("Document ID for get"),
24713
+ mode: z76.enum(["replace", "append"]).optional().describe("Reserved; direct wiki updates are removed"),
24714
+ section: z76.string().optional().describe("Reserved; direct wiki updates are removed")
24099
24715
  }
24100
24716
  },
24101
24717
  async (input, extra) => {
@@ -24123,7 +24739,7 @@ init_active_agent();
24123
24739
  init_project_name();
24124
24740
  init_database();
24125
24741
  init_employees();
24126
- import { z as z76 } from "zod";
24742
+ import { z as z77 } from "zod";
24127
24743
  function rowToBehavior2(r) {
24128
24744
  return {
24129
24745
  id: String(r.id),
@@ -24145,13 +24761,13 @@ function registerBehavior(server2) {
24145
24761
  title: "Behavior",
24146
24762
  description: "Manage behavioral patterns, corrections, and reusable procedures for employees. Actions: store (create new), list (query existing), deactivate (soft-delete, restricted).",
24147
24763
  inputSchema: {
24148
- action: z76.enum(["store", "list", "deactivate"]).describe("Action to perform"),
24149
- content: z76.string().max(500).optional().describe("The behavioral instruction \u2014 one clear sentence (store)"),
24150
- domain: z76.string().optional().describe("Category: workflow, code-style, tool-use, communication, architecture, testing"),
24151
- priority: z76.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always included. p1 = standard (default). p2 = nice-to-have."),
24152
- agent_id: z76.string().optional().describe("Employee name. Defaults to current agent. Pass 'all' to list everyone's (list only)."),
24153
- project_name: z76.string().optional().describe("Defaults to current project. Pass 'global' for a behavior that applies everywhere (store)."),
24154
- behavior_id: z76.string().optional().describe("UUID of the behavior (deactivate)")
24764
+ action: z77.enum(["store", "list", "deactivate"]).describe("Action to perform"),
24765
+ content: z77.string().max(500).optional().describe("The behavioral instruction \u2014 one clear sentence (store)"),
24766
+ domain: z77.string().optional().describe("Category: workflow, code-style, tool-use, communication, architecture, testing"),
24767
+ priority: z77.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always included. p1 = standard (default). p2 = nice-to-have."),
24768
+ agent_id: z77.string().optional().describe("Employee name. Defaults to current agent. Pass 'all' to list everyone's (list only)."),
24769
+ project_name: z77.string().optional().describe("Defaults to current project. Pass 'global' for a behavior that applies everywhere (store)."),
24770
+ behavior_id: z77.string().optional().describe("UUID of the behavior (deactivate)")
24155
24771
  }
24156
24772
  },
24157
24773
  async ({ action, content, domain, priority, agent_id, project_name, behavior_id }) => {
@@ -24322,7 +24938,7 @@ Content: ${row.content}`
24322
24938
  }
24323
24939
 
24324
24940
  // src/mcp/tools/reminder.ts
24325
- import { z as z77 } from "zod";
24941
+ import { z as z78 } from "zod";
24326
24942
  function registerReminder(server2) {
24327
24943
  server2.registerTool(
24328
24944
  "reminder",
@@ -24330,11 +24946,11 @@ function registerReminder(server2) {
24330
24946
  title: "Reminder",
24331
24947
  description: "Manage reminders for the founder. Shown in the boot brief every session. Actions: create (set new), list (view active), complete (mark done).",
24332
24948
  inputSchema: {
24333
- action: z77.enum(["create", "list", "complete"]).describe("Action to perform"),
24334
- text: z77.string().optional().describe("What to remind about (create)"),
24335
- due_date: z77.string().optional().describe("Optional due date \u2014 ISO date (2026-04-01) or null for persistent (create)"),
24336
- reminder_id: z77.string().optional().describe("Reminder UUID or text substring to match (complete)"),
24337
- include_completed: z77.boolean().optional().default(false).describe("Include completed reminders (list)")
24949
+ action: z78.enum(["create", "list", "complete"]).describe("Action to perform"),
24950
+ text: z78.string().optional().describe("What to remind about (create)"),
24951
+ due_date: z78.string().optional().describe("Optional due date \u2014 ISO date (2026-04-01) or null for persistent (create)"),
24952
+ reminder_id: z78.string().optional().describe("Reminder UUID or text substring to match (complete)"),
24953
+ include_completed: z78.boolean().optional().default(false).describe("Include completed reminders (list)")
24338
24954
  }
24339
24955
  },
24340
24956
  async ({ action, text: text3, due_date, reminder_id, include_completed }) => {
@@ -24390,7 +25006,7 @@ function registerReminder(server2) {
24390
25006
  init_global_procedures();
24391
25007
  init_active_agent();
24392
25008
  init_employees();
24393
- import { z as z78 } from "zod";
25009
+ import { z as z79 } from "zod";
24394
25010
  function registerStoreGlobalProcedure(server2) {
24395
25011
  server2.registerTool(
24396
25012
  "store_global_procedure",
@@ -24398,10 +25014,10 @@ function registerStoreGlobalProcedure(server2) {
24398
25014
  title: "Store Company Procedure (use global_procedure instead)",
24399
25015
  description: "DEPRECATED \u2014 use global_procedure with action='store'. Create a company procedure (customer-owned Layer 0 rule). RESTRICTED: only coordinator or founder sessions.",
24400
25016
  inputSchema: {
24401
- title: z78.string().describe("Short title for the procedure"),
24402
- content: z78.string().max(500).describe("The procedure content \u2014 clear, actionable instruction"),
24403
- priority: z78.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always (default)."),
24404
- domain: z78.string().optional().describe("Category: workflow, code-style, communication, architecture, testing, security")
25017
+ title: z79.string().describe("Short title for the procedure"),
25018
+ content: z79.string().max(500).describe("The procedure content \u2014 clear, actionable instruction"),
25019
+ priority: z79.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always (default)."),
25020
+ domain: z79.string().optional().describe("Category: workflow, code-style, communication, architecture, testing, security")
24405
25021
  }
24406
25022
  },
24407
25023
  async ({ title, content, priority, domain }) => {
@@ -24479,7 +25095,7 @@ init_global_procedures();
24479
25095
  init_active_agent();
24480
25096
  init_database();
24481
25097
  init_employees();
24482
- import { z as z79 } from "zod";
25098
+ import { z as z80 } from "zod";
24483
25099
  function registerDeactivateGlobalProcedure(server2) {
24484
25100
  server2.registerTool(
24485
25101
  "deactivate_global_procedure",
@@ -24487,7 +25103,7 @@ function registerDeactivateGlobalProcedure(server2) {
24487
25103
  title: "Deactivate Company Procedure (use global_procedure instead)",
24488
25104
  description: "DEPRECATED \u2014 use global_procedure with action='deactivate'. Soft-delete a company procedure. RESTRICTED: only coordinator or founder sessions.",
24489
25105
  inputSchema: {
24490
- procedure_id: z79.string().describe("UUID of the company procedure to deactivate")
25106
+ procedure_id: z80.string().describe("UUID of the company procedure to deactivate")
24491
25107
  }
24492
25108
  },
24493
25109
  async ({ procedure_id }) => {
@@ -24547,7 +25163,7 @@ init_store();
24547
25163
  init_active_agent();
24548
25164
  init_database();
24549
25165
  init_plan_limits();
24550
- import { z as z80 } from "zod";
25166
+ import { z as z81 } from "zod";
24551
25167
  import crypto17 from "crypto";
24552
25168
  function registerStoreDecision(server2) {
24553
25169
  server2.registerTool(
@@ -24556,13 +25172,13 @@ function registerStoreDecision(server2) {
24556
25172
  title: "Store Decision",
24557
25173
  description: "Store an authoritative decision keyed by domain. Use this when a decision is made that should be canonical \u2014 future lookups via get_decision return the latest decision for that domain. Supports supersession chains.",
24558
25174
  inputSchema: {
24559
- domain: z80.string().describe(
25175
+ domain: z81.string().describe(
24560
25176
  "Domain key, e.g. 'auth-strategy', 'db-migration-approach', 'api-versioning'"
24561
25177
  ),
24562
- decision: z80.string().describe("The decision text \u2014 what was decided"),
24563
- rationale: z80.string().optional().describe("Why this decision was made \u2014 constraints, trade-offs, context"),
24564
- supersedes: z80.string().optional().describe("UUID of the decision this supersedes (previous decision for this domain)"),
24565
- project_name: z80.string().optional().describe("Project name")
25178
+ decision: z81.string().describe("The decision text \u2014 what was decided"),
25179
+ rationale: z81.string().optional().describe("Why this decision was made \u2014 constraints, trade-offs, context"),
25180
+ supersedes: z81.string().optional().describe("UUID of the decision this supersedes (previous decision for this domain)"),
25181
+ project_name: z81.string().optional().describe("Project name")
24566
25182
  }
24567
25183
  },
24568
25184
  async ({ domain, decision, rationale, supersedes, project_name }) => {
@@ -24630,7 +25246,7 @@ Supersedes: ${supersedes}` : ""}`
24630
25246
 
24631
25247
  // src/mcp/tools/get-decision.ts
24632
25248
  init_database();
24633
- import { z as z81 } from "zod";
25249
+ import { z as z82 } from "zod";
24634
25250
  function registerGetDecision(server2) {
24635
25251
  server2.registerTool(
24636
25252
  "get_decision",
@@ -24638,7 +25254,7 @@ function registerGetDecision(server2) {
24638
25254
  title: "Get Decision",
24639
25255
  description: "Retrieve the latest authoritative decision for a domain. Returns the current active decision and the supersession history.",
24640
25256
  inputSchema: {
24641
- domain: z81.string().describe(
25257
+ domain: z82.string().describe(
24642
25258
  "Domain key to look up, e.g. 'auth-strategy', 'db-migration-approach'"
24643
25259
  )
24644
25260
  }
@@ -24701,16 +25317,16 @@ function registerGetDecision(server2) {
24701
25317
  }
24702
25318
 
24703
25319
  // src/mcp/tools/people-roster.ts
24704
- import { z as z82 } from "zod";
25320
+ import { z as z83 } from "zod";
24705
25321
 
24706
25322
  // src/lib/people.ts
24707
25323
  init_config();
24708
25324
  import { readFile as readFile5, writeFile as writeFile6, mkdir as mkdir5 } from "fs/promises";
24709
- import { existsSync as existsSync35, readFileSync as readFileSync28 } from "fs";
24710
- import path44 from "path";
24711
- var PEOPLE_PATH = path44.join(EXE_AI_DIR, "people.json");
25325
+ import { existsSync as existsSync36, readFileSync as readFileSync29 } from "fs";
25326
+ import path45 from "path";
25327
+ var PEOPLE_PATH = path45.join(EXE_AI_DIR, "people.json");
24712
25328
  async function loadPeople() {
24713
- if (!existsSync35(PEOPLE_PATH)) return [];
25329
+ if (!existsSync36(PEOPLE_PATH)) return [];
24714
25330
  try {
24715
25331
  const raw = await readFile5(PEOPLE_PATH, "utf-8");
24716
25332
  return JSON.parse(raw);
@@ -24719,7 +25335,7 @@ async function loadPeople() {
24719
25335
  }
24720
25336
  }
24721
25337
  async function savePeople(people) {
24722
- await mkdir5(path44.dirname(PEOPLE_PATH), { recursive: true });
25338
+ await mkdir5(path45.dirname(PEOPLE_PATH), { recursive: true });
24723
25339
  await writeFile6(PEOPLE_PATH, JSON.stringify(people, null, 2) + "\n", "utf-8");
24724
25340
  }
24725
25341
  async function addPerson(person) {
@@ -24749,10 +25365,10 @@ function registerAddPerson(server2) {
24749
25365
  title: "Add Person",
24750
25366
  description: "Add or update a key human in the people roster. Used for co-founders, partners, customers \u2014 anyone agents need to know about.",
24751
25367
  inputSchema: {
24752
- name: z82.string().describe("Person's name"),
24753
- role: z82.string().describe("Their role (e.g. co-founder, customer, partner)"),
24754
- relationship: z82.string().describe("Relationship to the organization (e.g. co-founder, early adopter, investor)"),
24755
- notes: z82.string().optional().describe("Additional context about this person")
25368
+ name: z83.string().describe("Person's name"),
25369
+ role: z83.string().describe("Their role (e.g. co-founder, customer, partner)"),
25370
+ relationship: z83.string().describe("Relationship to the organization (e.g. co-founder, early adopter, investor)"),
25371
+ notes: z83.string().optional().describe("Additional context about this person")
24756
25372
  }
24757
25373
  },
24758
25374
  async ({ name, role, relationship, notes }) => {
@@ -24798,7 +25414,7 @@ function registerGetPerson(server2) {
24798
25414
  title: "Get Person",
24799
25415
  description: "Look up a specific person by name from the people roster.",
24800
25416
  inputSchema: {
24801
- name: z82.string().describe("Person's name to look up")
25417
+ name: z83.string().describe("Person's name to look up")
24802
25418
  }
24803
25419
  },
24804
25420
  async ({ name }) => {
@@ -24822,10 +25438,10 @@ Notes: ${person.notes}` : ""}`
24822
25438
  }
24823
25439
 
24824
25440
  // src/mcp/tools/crm.ts
24825
- import { z as z83 } from "zod";
25441
+ import { z as z84 } from "zod";
24826
25442
 
24827
25443
  // src/lib/exe-db-read.ts
24828
- import path45 from "path";
25444
+ import path46 from "path";
24829
25445
  import os19 from "os";
24830
25446
  import { createRequire as createRequire5 } from "module";
24831
25447
  import { pathToFileURL as pathToFileURL5 } from "url";
@@ -24843,8 +25459,8 @@ async function getExeDbReadClient() {
24843
25459
  if (!Ctor2) throw new Error(`No PrismaClient export found at ${explicitPath}`);
24844
25460
  return new Ctor2();
24845
25461
  }
24846
- const exeDbRoot = process.env.EXE_DB_ROOT ?? path45.join(os19.homedir(), "exe-db");
24847
- const req = createRequire5(path45.join(exeDbRoot, "package.json"));
25462
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path46.join(os19.homedir(), "exe-db");
25463
+ const req = createRequire5(path46.join(exeDbRoot, "package.json"));
24848
25464
  const entry = req.resolve("@prisma/client");
24849
25465
  const mod = await import(pathToFileURL5(entry).href);
24850
25466
  const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
@@ -24877,12 +25493,12 @@ function registerCrm(server2) {
24877
25493
  title: "CRM",
24878
25494
  description: "Read-only CRM access from exe-db crm schema. Actions: list_people, get_person, list_tables, describe_table.",
24879
25495
  inputSchema: {
24880
- action: z83.enum(["list_people", "get_person", "list_tables", "describe_table"]).describe("CRM read operation"),
24881
- id: z83.string().optional().describe("CRM row/person id for get_person"),
24882
- query: z83.string().optional().describe("Text search for list_people/get_person"),
24883
- table: z83.string().optional().describe("crm schema table name for describe_table"),
24884
- limit: z83.coerce.number().int().min(1).max(50).optional().describe("Max rows, capped at 50"),
24885
- offset: z83.coerce.number().int().min(0).optional().describe("Rows to skip")
25496
+ action: z84.enum(["list_people", "get_person", "list_tables", "describe_table"]).describe("CRM read operation"),
25497
+ id: z84.string().optional().describe("CRM row/person id for get_person"),
25498
+ query: z84.string().optional().describe("Text search for list_people/get_person"),
25499
+ table: z84.string().optional().describe("crm schema table name for describe_table"),
25500
+ limit: z84.coerce.number().int().min(1).max(50).optional().describe("Max rows, capped at 50"),
25501
+ offset: z84.coerce.number().int().min(0).optional().describe("Rows to skip")
24886
25502
  }
24887
25503
  }, async ({ action, id, query, table, limit, offset }) => {
24888
25504
  try {
@@ -24941,7 +25557,7 @@ function registerCrm(server2) {
24941
25557
  }
24942
25558
 
24943
25559
  // src/mcp/tools/raw-data.ts
24944
- import { z as z84 } from "zod";
25560
+ import { z as z85 } from "zod";
24945
25561
  function text2(content, isError = false) {
24946
25562
  return { content: [{ type: "text", text: content }], ...isError ? { isError: true } : {} };
24947
25563
  }
@@ -24950,15 +25566,15 @@ function registerRawData(server2) {
24950
25566
  title: "Raw Data",
24951
25567
  description: "Read-only access to exe-db raw.raw_events landing pad. Actions: list_sources, query, get. Results are capped because raw payloads can consume many tokens.",
24952
25568
  inputSchema: {
24953
- action: z84.enum(["list_sources", "query", "get"]).describe("Raw data read operation"),
24954
- id: z84.string().optional().describe("raw.raw_events id for action=get"),
24955
- source: z84.string().optional().describe("Filter by raw source"),
24956
- event_type: z84.string().optional().describe("Filter by event_type"),
24957
- query: z84.string().optional().describe("Search payload/metadata text"),
24958
- processed: z84.boolean().optional().describe("Filter processed_at IS NULL/NOT NULL"),
24959
- limit: z84.coerce.number().int().min(1).max(50).optional().describe("Max rows, capped at 50"),
24960
- offset: z84.coerce.number().int().min(0).optional().describe("Rows to skip"),
24961
- include_payload: z84.boolean().optional().describe("Include full payload JSON. Default false to save tokens.")
25569
+ action: z85.enum(["list_sources", "query", "get"]).describe("Raw data read operation"),
25570
+ id: z85.string().optional().describe("raw.raw_events id for action=get"),
25571
+ source: z85.string().optional().describe("Filter by raw source"),
25572
+ event_type: z85.string().optional().describe("Filter by event_type"),
25573
+ query: z85.string().optional().describe("Search payload/metadata text"),
25574
+ processed: z85.boolean().optional().describe("Filter processed_at IS NULL/NOT NULL"),
25575
+ limit: z85.coerce.number().int().min(1).max(50).optional().describe("Max rows, capped at 50"),
25576
+ offset: z85.coerce.number().int().min(0).optional().describe("Rows to skip"),
25577
+ include_payload: z85.boolean().optional().describe("Include full payload JSON. Default false to save tokens.")
24962
25578
  }
24963
25579
  }, async ({ action, id, source, event_type, query, processed, limit, offset, include_payload }) => {
24964
25580
  try {
@@ -25025,17 +25641,17 @@ init_active_agent();
25025
25641
  init_config();
25026
25642
  init_license();
25027
25643
  init_store();
25028
- import { z as z85 } from "zod";
25644
+ import { z as z86 } from "zod";
25029
25645
  import crypto18 from "crypto";
25030
25646
  import { mkdir as mkdir6, writeFile as writeFile7 } from "fs/promises";
25031
- import path46 from "path";
25032
- var CLASSIFICATION = z85.enum([
25647
+ import path47 from "path";
25648
+ var CLASSIFICATION = z86.enum([
25033
25649
  "upstream_bug",
25034
25650
  "customer_customization",
25035
25651
  "emergency_hotfix",
25036
25652
  "unclear"
25037
25653
  ]);
25038
- var SEVERITY = z85.enum(["p0", "p1", "p2", "p3"]);
25654
+ var SEVERITY = z86.enum(["p0", "p1", "p2", "p3"]);
25039
25655
  function slugify2(input) {
25040
25656
  return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "bug-report";
25041
25657
  }
@@ -25113,22 +25729,22 @@ function registerCreateBugReport(server2) {
25113
25729
  title: "Create Bug Report",
25114
25730
  description: "Classify and file an exe-os issue as upstream_bug, customer_customization, emergency_hotfix, or unclear. Writes a local report, stores memory, and optionally sends to AskExe support when a support endpoint is configured.",
25115
25731
  inputSchema: {
25116
- title: z85.string().min(3).describe("Short descriptive title"),
25732
+ title: z86.string().min(3).describe("Short descriptive title"),
25117
25733
  classification: CLASSIFICATION.describe(
25118
25734
  "upstream_bug = platform defect; customer_customization = local preference; emergency_hotfix = temporary local patch; unclear = needs maintainer triage"
25119
25735
  ),
25120
25736
  severity: SEVERITY.default("p2").describe("p0 critical \u2192 p3 low"),
25121
- summary: z85.string().min(10).describe("What happened and why it matters"),
25122
- customer_impact: z85.string().optional().describe("How this affects the customer/founder"),
25123
- reproduction_steps: z85.array(z85.string()).optional().describe("Steps to reproduce"),
25124
- expected: z85.string().optional().describe("Expected behavior"),
25125
- actual: z85.string().optional().describe("Actual behavior"),
25126
- files_changed: z85.array(z85.string()).optional().describe("Files changed or suspected"),
25127
- workaround: z85.string().optional().describe("Temporary local workaround/hotfix, if any"),
25128
- local_patch_diff: z85.string().optional().describe("Small local diff or patch summary"),
25129
- package_version: z85.string().optional().describe("Installed @askexenow/exe-os version"),
25130
- project_name: z85.string().optional().describe("Project/customer context"),
25131
- send_upstream: z85.boolean().default(true).describe("Attempt to POST to configured AskExe support endpoint")
25737
+ summary: z86.string().min(10).describe("What happened and why it matters"),
25738
+ customer_impact: z86.string().optional().describe("How this affects the customer/founder"),
25739
+ reproduction_steps: z86.array(z86.string()).optional().describe("Steps to reproduce"),
25740
+ expected: z86.string().optional().describe("Expected behavior"),
25741
+ actual: z86.string().optional().describe("Actual behavior"),
25742
+ files_changed: z86.array(z86.string()).optional().describe("Files changed or suspected"),
25743
+ workaround: z86.string().optional().describe("Temporary local workaround/hotfix, if any"),
25744
+ local_patch_diff: z86.string().optional().describe("Small local diff or patch summary"),
25745
+ package_version: z86.string().optional().describe("Installed @askexenow/exe-os version"),
25746
+ project_name: z86.string().optional().describe("Project/customer context"),
25747
+ send_upstream: z86.boolean().default(true).describe("Attempt to POST to configured AskExe support endpoint")
25132
25748
  }
25133
25749
  },
25134
25750
  async ({
@@ -25168,9 +25784,9 @@ function registerCreateBugReport(server2) {
25168
25784
  filesChanged: files_changed,
25169
25785
  projectName: project_name
25170
25786
  });
25171
- const outDir = path46.join(EXE_AI_DIR, "bug-reports");
25787
+ const outDir = path47.join(EXE_AI_DIR, "bug-reports");
25172
25788
  await mkdir6(outDir, { recursive: true });
25173
- const reportPath = path46.join(outDir, `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}-${slugify2(title)}-${id.slice(0, 8)}.md`);
25789
+ const reportPath = path47.join(outDir, `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}-${slugify2(title)}-${id.slice(0, 8)}.md`);
25174
25790
  await writeFile7(reportPath, markdown, "utf-8");
25175
25791
  let vector = null;
25176
25792
  try {
@@ -25237,9 +25853,9 @@ Upstream status: ${upstreamStatus}`
25237
25853
  }
25238
25854
 
25239
25855
  // src/mcp/tools/support-inbox.ts
25240
- import { z as z86 } from "zod";
25856
+ import { z as z87 } from "zod";
25241
25857
  var DEFAULT_ENDPOINT = "https://askexe.com/admin/support/bug-reports";
25242
- var STATUS = z86.enum(["open", "triaged", "fixed", "closed", "wontfix"]);
25858
+ var STATUS = z87.enum(["open", "triaged", "fixed", "closed", "wontfix"]);
25243
25859
  function adminToken() {
25244
25860
  return process.env.ASKEXE_SUPPORT_ADMIN_TOKEN || process.env.EXE_SUPPORT_ADMIN_TOKEN;
25245
25861
  }
@@ -25278,9 +25894,9 @@ function registerListBugReports(server2) {
25278
25894
  title: "List Bug Reports",
25279
25895
  description: "AskExe-internal only: list incoming customer bug reports from the support inbox.",
25280
25896
  inputSchema: {
25281
- status: z86.enum(["all", "open", "triaged", "fixed", "closed", "wontfix"]).default("open"),
25282
- severity: z86.enum(["p0", "p1", "p2", "p3"]).optional(),
25283
- limit: z86.number().int().min(1).max(100).default(25)
25897
+ status: z87.enum(["all", "open", "triaged", "fixed", "closed", "wontfix"]).default("open"),
25898
+ severity: z87.enum(["p0", "p1", "p2", "p3"]).optional(),
25899
+ limit: z87.number().int().min(1).max(100).default(25)
25284
25900
  }
25285
25901
  },
25286
25902
  async ({ status, severity, limit }) => {
@@ -25299,7 +25915,7 @@ function registerGetBugReport(server2) {
25299
25915
  {
25300
25916
  title: "Get Bug Report",
25301
25917
  description: "AskExe-internal only: fetch one customer bug report with full markdown payload.",
25302
- inputSchema: { id: z86.string().min(8) }
25918
+ inputSchema: { id: z87.string().min(8) }
25303
25919
  },
25304
25920
  async ({ id }) => {
25305
25921
  const data = await requestJson(`${endpoint()}/${encodeURIComponent(id)}`);
@@ -25314,12 +25930,12 @@ function registerTriageBugReport(server2) {
25314
25930
  title: "Triage Bug Report",
25315
25931
  description: "AskExe-internal only: update bug report status and link task/commit/release metadata.",
25316
25932
  inputSchema: {
25317
- id: z86.string().min(8),
25933
+ id: z87.string().min(8),
25318
25934
  status: STATUS.optional(),
25319
- triage_notes: z86.string().optional(),
25320
- linked_task_id: z86.string().optional(),
25321
- linked_commit: z86.string().optional(),
25322
- fixed_version: z86.string().optional()
25935
+ triage_notes: z87.string().optional(),
25936
+ linked_task_id: z87.string().optional(),
25937
+ linked_commit: z87.string().optional(),
25938
+ fixed_version: z87.string().optional()
25323
25939
  }
25324
25940
  },
25325
25941
  async ({ id, status, triage_notes, linked_task_id, linked_commit, fixed_version }) => {
@@ -25449,6 +26065,7 @@ var TOOL_CATEGORIES = {
25449
26065
  registerRunMemoryAudit: "admin",
25450
26066
  registerRunConsolidation: "admin",
25451
26067
  registerCloudSync: "admin",
26068
+ registerOrchestrationPhase: "admin",
25452
26069
  registerSetAgentConfig: "admin",
25453
26070
  registerListEmployees: "admin",
25454
26071
  registerGetAgentSpend: "admin",
@@ -25667,6 +26284,7 @@ function registerAllTools(server2) {
25667
26284
  gate("registerRunMemoryAudit", registerRunMemoryAudit);
25668
26285
  gate("registerCloudSync", registerCloudSync);
25669
26286
  gate("registerBackupVps", registerBackupVps);
26287
+ gate("registerOrchestrationPhase", registerOrchestrationPhase);
25670
26288
  }
25671
26289
  if (exposeLegacyMemory) {
25672
26290
  gate("registerGetMemoryCardinality", registerGetMemoryCardinality);
@@ -25811,16 +26429,16 @@ try {
25811
26429
  }
25812
26430
  }, 3e4);
25813
26431
  _ppidWatchdog.unref();
25814
- const MCP_VERSION_PATH = path47.join(os20.homedir(), ".exe-os", "mcp-version");
26432
+ const MCP_VERSION_PATH = path48.join(os20.homedir(), ".exe-os", "mcp-version");
25815
26433
  let _currentMcpVersion = null;
25816
26434
  try {
25817
- _currentMcpVersion = existsSync36(MCP_VERSION_PATH) ? readFileSync29(MCP_VERSION_PATH, "utf8").trim() : null;
26435
+ _currentMcpVersion = existsSync37(MCP_VERSION_PATH) ? readFileSync30(MCP_VERSION_PATH, "utf8").trim() : null;
25818
26436
  } catch {
25819
26437
  }
25820
26438
  const _versionWatchdog = setInterval(() => {
25821
26439
  try {
25822
- if (!existsSync36(MCP_VERSION_PATH)) return;
25823
- const diskVersion = readFileSync29(MCP_VERSION_PATH, "utf8").trim();
26440
+ if (!existsSync37(MCP_VERSION_PATH)) return;
26441
+ const diskVersion = readFileSync30(MCP_VERSION_PATH, "utf8").trim();
25824
26442
  if (_currentMcpVersion && diskVersion !== _currentMcpVersion) {
25825
26443
  process.stderr.write(
25826
26444
  `[exe-os] MCP version changed (${_currentMcpVersion} \u2192 ${diskVersion}). Hot-reloading...
@@ -25853,14 +26471,14 @@ try {
25853
26471
  `
25854
26472
  );
25855
26473
  const thisFile = fileURLToPath5(import.meta.url);
25856
- const backfillPath = path47.resolve(
25857
- path47.dirname(thisFile),
26474
+ const backfillPath = path48.resolve(
26475
+ path48.dirname(thisFile),
25858
26476
  "../bin/backfill-vectors.js"
25859
26477
  );
25860
- if (existsSync36(backfillPath)) {
26478
+ if (existsSync37(backfillPath)) {
25861
26479
  const { EXE_AI_DIR: exeDir } = await Promise.resolve().then(() => (init_config(), config_exports));
25862
- const logPath = path47.join(exeDir, "workers.log");
25863
- mkdirSync19(path47.dirname(logPath), { recursive: true });
26480
+ const logPath = path48.join(exeDir, "workers.log");
26481
+ mkdirSync20(path48.dirname(logPath), { recursive: true });
25864
26482
  let logFd = "ignore";
25865
26483
  try {
25866
26484
  logFd = openSync3(logPath, "a");