@askexenow/exe-os 0.9.65 → 0.9.66

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/deploy/stack-manifests/v0.9.json +4 -4
  2. package/dist/bin/backfill-conversations.js +22 -0
  3. package/dist/bin/backfill-responses.js +22 -0
  4. package/dist/bin/backfill-vectors.js +22 -0
  5. package/dist/bin/cleanup-stale-review-tasks.js +22 -0
  6. package/dist/bin/cli.js +2263 -1203
  7. package/dist/bin/exe-agent-config.js +4 -0
  8. package/dist/bin/exe-agent.js +16 -0
  9. package/dist/bin/exe-assign.js +22 -0
  10. package/dist/bin/exe-boot.js +93 -5
  11. package/dist/bin/exe-call.js +16 -0
  12. package/dist/bin/exe-cloud.js +6671 -464
  13. package/dist/bin/exe-dispatch.js +24 -0
  14. package/dist/bin/exe-doctor.js +2845 -1223
  15. package/dist/bin/exe-export-behaviors.js +24 -0
  16. package/dist/bin/exe-forget.js +22 -0
  17. package/dist/bin/exe-gateway.js +24 -0
  18. package/dist/bin/exe-heartbeat.js +23 -0
  19. package/dist/bin/exe-kill.js +22 -0
  20. package/dist/bin/exe-launch-agent.js +24 -0
  21. package/dist/bin/exe-link.js +287 -176
  22. package/dist/bin/exe-new-employee.js +127 -1
  23. package/dist/bin/exe-pending-messages.js +22 -0
  24. package/dist/bin/exe-pending-notifications.js +22 -0
  25. package/dist/bin/exe-pending-reviews.js +22 -0
  26. package/dist/bin/exe-rename.js +22 -0
  27. package/dist/bin/exe-review.js +22 -0
  28. package/dist/bin/exe-search.js +24 -0
  29. package/dist/bin/exe-session-cleanup.js +24 -0
  30. package/dist/bin/exe-settings.js +10 -0
  31. package/dist/bin/exe-start-codex.js +135 -1
  32. package/dist/bin/exe-start-opencode.js +149 -1
  33. package/dist/bin/exe-status.js +22 -0
  34. package/dist/bin/exe-team.js +22 -0
  35. package/dist/bin/git-sweep.js +24 -0
  36. package/dist/bin/graph-backfill.js +22 -0
  37. package/dist/bin/graph-export.js +22 -0
  38. package/dist/bin/install.js +115 -1
  39. package/dist/bin/intercom-check.js +24 -0
  40. package/dist/bin/scan-tasks.js +24 -0
  41. package/dist/bin/setup.js +389 -155
  42. package/dist/bin/shard-migrate.js +22 -0
  43. package/dist/bin/update.js +4 -0
  44. package/dist/gateway/index.js +24 -0
  45. package/dist/hooks/bug-report-worker.js +135 -42
  46. package/dist/hooks/codex-stop-task-finalizer.js +24 -0
  47. package/dist/hooks/commit-complete.js +24 -0
  48. package/dist/hooks/error-recall.js +24 -0
  49. package/dist/hooks/exe-heartbeat-hook.js +4 -0
  50. package/dist/hooks/ingest-worker.js +4 -0
  51. package/dist/hooks/ingest.js +23 -0
  52. package/dist/hooks/instructions-loaded.js +22 -0
  53. package/dist/hooks/notification.js +22 -0
  54. package/dist/hooks/post-compact.js +22 -0
  55. package/dist/hooks/post-tool-combined.js +24 -0
  56. package/dist/hooks/pre-compact.js +260 -109
  57. package/dist/hooks/pre-tool-use.js +22 -0
  58. package/dist/hooks/prompt-submit.js +24 -0
  59. package/dist/hooks/session-end.js +161 -122
  60. package/dist/hooks/session-start.js +142 -0
  61. package/dist/hooks/stop.js +23 -0
  62. package/dist/hooks/subagent-stop.js +22 -0
  63. package/dist/hooks/summary-worker.js +172 -77
  64. package/dist/index.js +24 -0
  65. package/dist/lib/agent-config.js +4 -0
  66. package/dist/lib/cloud-sync.js +27 -4
  67. package/dist/lib/config.js +12 -0
  68. package/dist/lib/consolidation.js +4 -0
  69. package/dist/lib/database.js +4 -0
  70. package/dist/lib/db-daemon-client.js +4 -0
  71. package/dist/lib/db.js +4 -0
  72. package/dist/lib/device-registry.js +4 -0
  73. package/dist/lib/embedder.js +12 -0
  74. package/dist/lib/employee-templates.js +16 -0
  75. package/dist/lib/employees.js +4 -0
  76. package/dist/lib/exe-daemon-client.js +4 -0
  77. package/dist/lib/exe-daemon.js +1058 -453
  78. package/dist/lib/hybrid-search.js +24 -0
  79. package/dist/lib/identity.js +4 -0
  80. package/dist/lib/license.js +4 -0
  81. package/dist/lib/messaging.js +4 -0
  82. package/dist/lib/reminders.js +4 -0
  83. package/dist/lib/schedules.js +22 -0
  84. package/dist/lib/skill-learning.js +12 -0
  85. package/dist/lib/status-brief.js +39 -0
  86. package/dist/lib/store.js +22 -0
  87. package/dist/lib/task-router.js +4 -0
  88. package/dist/lib/tasks.js +12 -0
  89. package/dist/lib/tmux-routing.js +12 -0
  90. package/dist/lib/token-spend.js +4 -0
  91. package/dist/mcp/server.js +1022 -425
  92. package/dist/mcp/tools/complete-reminder.js +4 -0
  93. package/dist/mcp/tools/create-reminder.js +4 -0
  94. package/dist/mcp/tools/create-task.js +12 -0
  95. package/dist/mcp/tools/deactivate-behavior.js +4 -0
  96. package/dist/mcp/tools/list-reminders.js +4 -0
  97. package/dist/mcp/tools/list-tasks.js +4 -0
  98. package/dist/mcp/tools/send-message.js +4 -0
  99. package/dist/mcp/tools/update-task.js +12 -0
  100. package/dist/runtime/index.js +24 -0
  101. package/dist/tui/App.js +24 -0
  102. package/package.json +3 -2
  103. package/src/commands/exe/cloud.md +15 -8
  104. package/src/commands/exe/link.md +7 -6
  105. package/stack.release.json +2 -2
@@ -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,7 +20229,7 @@ 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;
@@ -19780,12 +20238,12 @@ function isTruthyEnv(value) {
19780
20238
  }
19781
20239
  function loadPgClient() {
19782
20240
  if (_pgFailed) return null;
19783
- const configPath = path34.join(EXE_AI_DIR, "config.json");
20241
+ const configPath = path35.join(EXE_AI_DIR, "config.json");
19784
20242
  let cloudPostgresUrl;
19785
20243
  let configEnabled = false;
19786
20244
  try {
19787
- if (existsSync29(configPath)) {
19788
- const cfg = JSON.parse(readFileSync22(configPath, "utf8"));
20245
+ if (existsSync30(configPath)) {
20246
+ const cfg = JSON.parse(readFileSync23(configPath, "utf8"));
19789
20247
  cloudPostgresUrl = cfg.cloud?.postgresUrl;
19790
20248
  configEnabled = cfg.cloud?.syncToPostgres === true;
19791
20249
  }
@@ -19812,8 +20270,8 @@ function loadPgClient() {
19812
20270
  if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
19813
20271
  return new Ctor2();
19814
20272
  }
19815
- const exeDbRoot = process.env.EXE_DB_ROOT ?? path34.join(homedir6(), "exe-db");
19816
- const req = createRequire6(path34.join(exeDbRoot, "package.json"));
20273
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path35.join(homedir6(), "exe-db");
20274
+ const req = createRequire6(path35.join(exeDbRoot, "package.json"));
19817
20275
  const entry = req.resolve("@prisma/client");
19818
20276
  const mod = await import(pathToFileURL6(entry).href);
19819
20277
  const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
@@ -19858,18 +20316,18 @@ async function withRosterLock(fn) {
19858
20316
  try {
19859
20317
  const fd = openSync2(ROSTER_LOCK_PATH, "wx");
19860
20318
  closeSync2(fd);
19861
- writeFileSync16(ROSTER_LOCK_PATH, String(Date.now()));
20319
+ writeFileSync17(ROSTER_LOCK_PATH, String(Date.now()));
19862
20320
  } catch (err) {
19863
20321
  if (err.code === "EEXIST") {
19864
20322
  try {
19865
- const ts2 = parseInt(readFileSync22(ROSTER_LOCK_PATH, "utf-8"), 10);
20323
+ const ts2 = parseInt(readFileSync23(ROSTER_LOCK_PATH, "utf-8"), 10);
19866
20324
  if (Date.now() - ts2 < LOCK_STALE_MS) {
19867
20325
  throw new Error("Roster merge already in progress \u2014 another sync is running");
19868
20326
  }
19869
20327
  unlinkSync11(ROSTER_LOCK_PATH);
19870
20328
  const fd = openSync2(ROSTER_LOCK_PATH, "wx");
19871
20329
  closeSync2(fd);
19872
- writeFileSync16(ROSTER_LOCK_PATH, String(Date.now()));
20330
+ writeFileSync17(ROSTER_LOCK_PATH, String(Date.now()));
19873
20331
  } catch (retryErr) {
19874
20332
  if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
19875
20333
  throw new Error("Roster merge already in progress \u2014 another sync is running");
@@ -19988,6 +20446,16 @@ async function cloudPull(sinceVersion, config2) {
19988
20446
  return { records: [], maxVersion: sinceVersion };
19989
20447
  }
19990
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
+ }
19991
20459
  async function cloudSync(config2) {
19992
20460
  if (!isSyncCryptoInitialized()) {
19993
20461
  try {
@@ -20009,10 +20477,7 @@ async function cloudSync(config2) {
20009
20477
  throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
20010
20478
  }
20011
20479
  try {
20012
- const relink = await client.execute("SELECT value FROM sync_meta WHERE key = 'cloud_relink_required' LIMIT 1");
20013
- if (String(relink.rows[0]?.value ?? "") === "1") {
20014
- throw new Error("[cloud-sync] Paused after key rotation. Re-link/reupload cloud sync with the new recovery phrase before syncing.");
20015
- }
20480
+ if (await getCloudRelinkRequired(client)) throw new Error(CLOUD_RELINK_REQUIRED_MESSAGE);
20016
20481
  } catch (err) {
20017
20482
  const msg = err instanceof Error ? err.message : String(err);
20018
20483
  if (msg.includes("Paused after key rotation")) throw err;
@@ -20262,8 +20727,8 @@ async function cloudSync(config2) {
20262
20727
  try {
20263
20728
  const employees = await loadEmployees();
20264
20729
  rosterResult.employees = employees.length;
20265
- const idDir = path34.join(EXE_AI_DIR, "identity");
20266
- if (existsSync29(idDir)) {
20730
+ const idDir = path35.join(EXE_AI_DIR, "identity");
20731
+ if (existsSync30(idDir)) {
20267
20732
  rosterResult.identities = readdirSync11(idDir).filter((f) => f.endsWith(".md")).length;
20268
20733
  }
20269
20734
  } catch {
@@ -20276,7 +20741,7 @@ async function cloudSync(config2) {
20276
20741
  const backupSize = statSync5(latestBackup).size;
20277
20742
  const MAX_CLOUD_BACKUP_BYTES = 50 * 1024 * 1024;
20278
20743
  if (backupSize <= MAX_CLOUD_BACKUP_BYTES) {
20279
- const backupData = readFileSync22(latestBackup);
20744
+ const backupData = readFileSync23(latestBackup);
20280
20745
  const deviceId = loadDeviceId() ?? "unknown";
20281
20746
  const encrypted = encryptSyncBlob(backupData);
20282
20747
  const backupRes = await fetchWithRetry(`${config2.endpoint}/sync/push-db-backup`, {
@@ -20284,7 +20749,7 @@ async function cloudSync(config2) {
20284
20749
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${config2.apiKey}` },
20285
20750
  body: JSON.stringify({
20286
20751
  device_id: deviceId,
20287
- filename: path34.basename(latestBackup),
20752
+ filename: path35.basename(latestBackup),
20288
20753
  blob: encrypted,
20289
20754
  size: backupData.length
20290
20755
  })
@@ -20309,49 +20774,49 @@ async function cloudSync(config2) {
20309
20774
  roster: rosterResult
20310
20775
  };
20311
20776
  }
20312
- 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");
20313
20778
  function consumeRosterDeletions() {
20314
20779
  try {
20315
- if (!existsSync29(ROSTER_DELETIONS_PATH)) return [];
20316
- const deletions = JSON.parse(readFileSync22(ROSTER_DELETIONS_PATH, "utf-8"));
20317
- 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, "[]");
20318
20783
  return deletions;
20319
20784
  } catch {
20320
20785
  return [];
20321
20786
  }
20322
20787
  }
20323
20788
  function buildRosterBlob(paths) {
20324
- const rosterPath = paths?.rosterPath ?? path34.join(EXE_AI_DIR, "exe-employees.json");
20325
- const identityDir = paths?.identityDir ?? path34.join(EXE_AI_DIR, "identity");
20326
- 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");
20327
20792
  let roster = [];
20328
- if (existsSync29(rosterPath)) {
20793
+ if (existsSync30(rosterPath)) {
20329
20794
  try {
20330
- roster = JSON.parse(readFileSync22(rosterPath, "utf-8"));
20795
+ roster = JSON.parse(readFileSync23(rosterPath, "utf-8"));
20331
20796
  } catch {
20332
20797
  }
20333
20798
  }
20334
20799
  const identities = {};
20335
- if (existsSync29(identityDir)) {
20800
+ if (existsSync30(identityDir)) {
20336
20801
  for (const file of readdirSync11(identityDir).filter((f) => f.endsWith(".md"))) {
20337
20802
  try {
20338
- identities[file] = readFileSync22(path34.join(identityDir, file), "utf-8");
20803
+ identities[file] = readFileSync23(path35.join(identityDir, file), "utf-8");
20339
20804
  } catch {
20340
20805
  }
20341
20806
  }
20342
20807
  }
20343
20808
  let config2;
20344
- if (existsSync29(configPath)) {
20809
+ if (existsSync30(configPath)) {
20345
20810
  try {
20346
- config2 = JSON.parse(readFileSync22(configPath, "utf-8"));
20811
+ config2 = JSON.parse(readFileSync23(configPath, "utf-8"));
20347
20812
  } catch {
20348
20813
  }
20349
20814
  }
20350
20815
  let agentConfig;
20351
- const agentConfigPath = path34.join(EXE_AI_DIR, "agent-config.json");
20352
- if (existsSync29(agentConfigPath)) {
20816
+ const agentConfigPath = path35.join(EXE_AI_DIR, "agent-config.json");
20817
+ if (existsSync30(agentConfigPath)) {
20353
20818
  try {
20354
- agentConfig = JSON.parse(readFileSync22(agentConfigPath, "utf-8"));
20819
+ agentConfig = JSON.parse(readFileSync23(agentConfigPath, "utf-8"));
20355
20820
  } catch {
20356
20821
  }
20357
20822
  }
@@ -20427,24 +20892,24 @@ async function cloudPullRoster(config2) {
20427
20892
  }
20428
20893
  }
20429
20894
  function mergeConfig(remoteConfig, configPath) {
20430
- const cfgPath = configPath ?? path34.join(EXE_AI_DIR, "config.json");
20895
+ const cfgPath = configPath ?? path35.join(EXE_AI_DIR, "config.json");
20431
20896
  let local = {};
20432
- if (existsSync29(cfgPath)) {
20897
+ if (existsSync30(cfgPath)) {
20433
20898
  try {
20434
- local = JSON.parse(readFileSync22(cfgPath, "utf-8"));
20899
+ local = JSON.parse(readFileSync23(cfgPath, "utf-8"));
20435
20900
  } catch {
20436
20901
  }
20437
20902
  }
20438
20903
  const merged = { ...remoteConfig, ...local };
20439
- const dir = path34.dirname(cfgPath);
20904
+ const dir = path35.dirname(cfgPath);
20440
20905
  ensurePrivateDirSync(dir);
20441
- writeFileSync16(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
20906
+ writeFileSync17(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
20442
20907
  enforcePrivateFileSync(cfgPath);
20443
20908
  }
20444
20909
  async function mergeRosterFromRemote(remote, paths) {
20445
20910
  return withRosterLock(async () => {
20446
20911
  const rosterPath = paths?.rosterPath ?? void 0;
20447
- const identityDir = paths?.identityDir ?? path34.join(EXE_AI_DIR, "identity");
20912
+ const identityDir = paths?.identityDir ?? path35.join(EXE_AI_DIR, "identity");
20448
20913
  const localEmployees = await loadEmployees(rosterPath);
20449
20914
  const localNames = new Set(localEmployees.map((e) => e.name));
20450
20915
  let added = 0;
@@ -20465,15 +20930,15 @@ async function mergeRosterFromRemote(remote, paths) {
20465
20930
  ) ?? lookupKey;
20466
20931
  const remoteIdentity = remote.identities[matchedKey];
20467
20932
  if (remoteIdentity) {
20468
- if (!existsSync29(identityDir)) mkdirSync14(identityDir, { recursive: true });
20469
- 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`);
20470
20935
  let localIdentity = null;
20471
20936
  try {
20472
- localIdentity = existsSync29(idPath) ? readFileSync22(idPath, "utf-8") : null;
20937
+ localIdentity = existsSync30(idPath) ? readFileSync23(idPath, "utf-8") : null;
20473
20938
  } catch {
20474
20939
  }
20475
20940
  if (localIdentity !== remoteIdentity) {
20476
- writeFileSync16(idPath, remoteIdentity, "utf-8");
20941
+ writeFileSync17(idPath, remoteIdentity, "utf-8");
20477
20942
  identitiesUpdated++;
20478
20943
  }
20479
20944
  }
@@ -20499,17 +20964,17 @@ async function mergeRosterFromRemote(remote, paths) {
20499
20964
  }
20500
20965
  if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
20501
20966
  try {
20502
- const agentConfigPath = path34.join(EXE_AI_DIR, "agent-config.json");
20967
+ const agentConfigPath = path35.join(EXE_AI_DIR, "agent-config.json");
20503
20968
  let local = {};
20504
- if (existsSync29(agentConfigPath)) {
20969
+ if (existsSync30(agentConfigPath)) {
20505
20970
  try {
20506
- local = JSON.parse(readFileSync22(agentConfigPath, "utf-8"));
20971
+ local = JSON.parse(readFileSync23(agentConfigPath, "utf-8"));
20507
20972
  } catch {
20508
20973
  }
20509
20974
  }
20510
20975
  const merged = { ...remote.agentConfig, ...local };
20511
- ensurePrivateDirSync(path34.dirname(agentConfigPath));
20512
- 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");
20513
20978
  enforcePrivateFileSync(agentConfigPath);
20514
20979
  } catch {
20515
20980
  }
@@ -20995,9 +21460,136 @@ function registerCloudSync(server2) {
20995
21460
  );
20996
21461
  }
20997
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
+
20998
21590
  // src/mcp/tools/backup-vps.ts
20999
21591
  init_keychain();
21000
- import { z as z59 } from "zod";
21592
+ import { z as z60 } from "zod";
21001
21593
 
21002
21594
  // src/lib/vps-backup.ts
21003
21595
  import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
@@ -21322,43 +21914,43 @@ function registerBackupVps(server2) {
21322
21914
  {
21323
21915
  title: "VPS Backup",
21324
21916
  description: "Run VPS Postgres backup/restore workflows and check status.",
21325
- inputSchema: z59.discriminatedUnion("action", [
21326
- z59.object({
21327
- action: z59.literal("backup"),
21328
- databaseUrl: z59.string().min(1).describe("Postgres DATABASE_URL to dump from"),
21329
- 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(
21330
21922
  "Base64 AES-256 key (defaults to local master key if omitted)"
21331
21923
  ),
21332
- r2Bucket: z59.string().min(1).describe("R2 bucket name"),
21333
- r2Endpoint: z59.string().min(1).describe("R2 endpoint URL"),
21334
- r2AccessKeyId: z59.string().min(1).describe("R2 access key ID"),
21335
- 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")
21336
21928
  }),
21337
- z59.object({
21338
- action: z59.literal("restore"),
21339
- databaseUrl: z59.string().min(1).describe("Target Postgres DATABASE_URL for restore"),
21340
- backupKey: z59.string().min(1).describe("R2 object key to restore from"),
21341
- 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(
21342
21934
  "Base64 AES-256 key (defaults to local master key if omitted)"
21343
21935
  ),
21344
- r2Bucket: z59.string().min(1).describe("R2 bucket name"),
21345
- r2Endpoint: z59.string().min(1).describe("R2 endpoint URL"),
21346
- r2AccessKeyId: z59.string().min(1).describe("R2 access key ID"),
21347
- 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")
21348
21940
  }),
21349
- z59.object({
21350
- action: z59.literal("list"),
21351
- r2Bucket: z59.string().min(1).describe("R2 bucket name"),
21352
- r2Endpoint: z59.string().min(1).describe("R2 endpoint URL"),
21353
- r2AccessKeyId: z59.string().min(1).describe("R2 access key ID"),
21354
- 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")
21355
21947
  }),
21356
- z59.object({
21357
- action: z59.literal("health"),
21358
- r2Bucket: z59.string().min(1).describe("R2 bucket name"),
21359
- r2Endpoint: z59.string().min(1).describe("R2 endpoint URL"),
21360
- r2AccessKeyId: z59.string().min(1).describe("R2 access key ID"),
21361
- 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")
21362
21954
  })
21363
21955
  ])
21364
21956
  },
@@ -21496,11 +22088,11 @@ async function resolveEncryptionKey(providedB64) {
21496
22088
  }
21497
22089
 
21498
22090
  // src/mcp/tools/deploy-client.ts
21499
- import { z as z60 } from "zod";
22091
+ import { z as z61 } from "zod";
21500
22092
  import { execFile } from "child_process";
21501
22093
  import { promisify } from "util";
21502
- import path35 from "path";
21503
- import { existsSync as existsSync30 } from "fs";
22094
+ import path36 from "path";
22095
+ import { existsSync as existsSync31 } from "fs";
21504
22096
 
21505
22097
  // src/lib/hostinger-api.ts
21506
22098
  var DEFAULT_BASE_URL = "https://developers.hostinger.com/api/vps/v1";
@@ -21548,9 +22140,9 @@ var HostingerApiClient = class {
21548
22140
  }
21549
22141
  this.lastRequestTime = Date.now();
21550
22142
  }
21551
- async request(method, path48, body) {
22143
+ async request(method, path49, body) {
21552
22144
  await this.rateLimit();
21553
- const url = `${this.baseUrl}${path48}`;
22145
+ const url = `${this.baseUrl}${path49}`;
21554
22146
  const headers = {
21555
22147
  Authorization: `Bearer ${this.apiKey}`,
21556
22148
  "Content-Type": "application/json",
@@ -21623,8 +22215,8 @@ async function requestCloudflare(cfApiToken, zoneId, options) {
21623
22215
  }
21624
22216
  return envelope.result;
21625
22217
  }
21626
- function buildUrl(zoneId, path48 = "/dns_records", query) {
21627
- const normalizedPath = path48.startsWith("/") ? path48 : `/${path48}`;
22218
+ function buildUrl(zoneId, path49 = "/dns_records", query) {
22219
+ const normalizedPath = path49.startsWith("/") ? path49 : `/${path49}`;
21628
22220
  const url = new URL(
21629
22221
  `${CLOUDFLARE_API_BASE_URL}/zones/${zoneId}${normalizedPath}`
21630
22222
  );
@@ -21764,12 +22356,12 @@ function registerDeployClient(server2) {
21764
22356
  title: "Deploy Client",
21765
22357
  description: "Provision a Hostinger VPS and deploy exe-os for a client. Creates VPS, waits for ready state, runs Ansible playbook, verifies health.",
21766
22358
  inputSchema: {
21767
- client_name: z60.string().min(1).describe("Client name (used for hostname and identification)"),
21768
- domain: z60.string().min(1).describe("Domain name for the deployment (e.g., client.exe.ai)"),
21769
- region: z60.string().default("jakarta").describe("VPS region (default: jakarta)"),
21770
- plan: z60.string().default("kvm-2").describe("Hostinger VPS plan (default: kvm-2)"),
21771
- ssl_email: z60.string().email().describe("Email for Let's Encrypt SSL certificate"),
21772
- 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")
21773
22365
  }
21774
22366
  },
21775
22367
  async ({ client_name, domain, region, plan, ssl_email, user_id }) => {
@@ -21837,12 +22429,12 @@ async function waitForReady(client, vpsId) {
21837
22429
  }
21838
22430
  async function runAnsiblePlaybook(vpsIp, domain, sslEmail, clientName) {
21839
22431
  const safeClientName = clientName.replace(/[^a-zA-Z0-9_-]/g, "-");
21840
- const playbookDir = path35.resolve(process.cwd(), "infrastructure", "ansible");
21841
- const playbookPath = path35.join(playbookDir, "deploy.yml");
21842
- const inventoryPath = path35.join(playbookDir, "inventory", "hosts.yml");
21843
- const clientVarsPath = path35.join(playbookDir, "vars", `${safeClientName}.yml`);
21844
- const varsDir = path35.join(playbookDir, "vars");
21845
- 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))) {
21846
22438
  throw new Error(`Invalid client name for vars path: ${clientName}`);
21847
22439
  }
21848
22440
  const args = [
@@ -21858,7 +22450,7 @@ async function runAnsiblePlaybook(vpsIp, domain, sslEmail, clientName) {
21858
22450
  "-e",
21859
22451
  `client_name=${safeClientName}`
21860
22452
  ];
21861
- if (existsSync30(clientVarsPath)) {
22453
+ if (existsSync31(clientVarsPath)) {
21862
22454
  args.push("-e", `@${clientVarsPath}`);
21863
22455
  }
21864
22456
  try {
@@ -21931,7 +22523,7 @@ function buildInventoryRecord(params) {
21931
22523
 
21932
22524
  // src/mcp/tools/get-license-status.ts
21933
22525
  init_license();
21934
- import { z as z61 } from "zod";
22526
+ import { z as z62 } from "zod";
21935
22527
  var FEATURES = [
21936
22528
  "cloud_sync",
21937
22529
  "external_agents",
@@ -21945,7 +22537,7 @@ function registerGetLicenseStatus(server2) {
21945
22537
  title: "Get License Status",
21946
22538
  description: "Get current license status: plan, validity, feature gates, limits, and expiry.",
21947
22539
  inputSchema: {
21948
- _dummy: z61.string().optional().describe("Unused \u2014 no input required")
22540
+ _dummy: z62.string().optional().describe("Unused \u2014 no input required")
21949
22541
  }
21950
22542
  },
21951
22543
  async () => {
@@ -21999,11 +22591,11 @@ function registerGetLicenseStatus(server2) {
21999
22591
  // src/mcp/tools/create-license.ts
22000
22592
  init_license();
22001
22593
  import os15 from "os";
22002
- import path36 from "path";
22594
+ import path37 from "path";
22003
22595
  import { randomBytes as randomBytes2, randomUUID as randomUUID6 } from "crypto";
22004
22596
  import { createRequire as createRequire3 } from "module";
22005
22597
  import { pathToFileURL as pathToFileURL3 } from "url";
22006
- import { z as z62 } from "zod";
22598
+ import { z as z63 } from "zod";
22007
22599
  var prismaPromise = null;
22008
22600
  function loadPrisma() {
22009
22601
  if (!prismaPromise) {
@@ -22015,8 +22607,8 @@ function loadPrisma() {
22015
22607
  if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
22016
22608
  return new Ctor2();
22017
22609
  }
22018
- const exeDbRoot = process.env.EXE_DB_ROOT ?? path36.join(os15.homedir(), "exe-db");
22019
- 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"));
22020
22612
  const entry = req.resolve("@prisma/client");
22021
22613
  const mod = await import(pathToFileURL3(entry).href);
22022
22614
  const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
@@ -22036,10 +22628,10 @@ function registerCreateLicense(server2) {
22036
22628
  title: "Create License",
22037
22629
  description: "Generate an exe_sk_* license key for a user. Stores in billing.licenses. Returns the key to give to the customer.",
22038
22630
  inputSchema: {
22039
- email: z62.string().email().describe("Customer email address"),
22040
- name: z62.string().optional().describe("Customer name"),
22041
- plan: z62.enum(["free", "pro", "team", "agency", "enterprise"]).default("pro").describe("License plan tier"),
22042
- 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)")
22043
22635
  }
22044
22636
  },
22045
22637
  async ({ email, name, plan, expires_in_days }) => {
@@ -22091,10 +22683,10 @@ Give this key to the customer. They paste it during \`exe-os setup\`.`);
22091
22683
 
22092
22684
  // src/mcp/tools/list-licenses.ts
22093
22685
  import os16 from "os";
22094
- import path37 from "path";
22686
+ import path38 from "path";
22095
22687
  import { createRequire as createRequire4 } from "module";
22096
22688
  import { pathToFileURL as pathToFileURL4 } from "url";
22097
- import { z as z63 } from "zod";
22689
+ import { z as z64 } from "zod";
22098
22690
  var prismaPromise2 = null;
22099
22691
  function loadPrisma2() {
22100
22692
  if (!prismaPromise2) {
@@ -22106,8 +22698,8 @@ function loadPrisma2() {
22106
22698
  if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
22107
22699
  return new Ctor2();
22108
22700
  }
22109
- const exeDbRoot = process.env.EXE_DB_ROOT ?? path37.join(os16.homedir(), "exe-db");
22110
- 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"));
22111
22703
  const entry = req.resolve("@prisma/client");
22112
22704
  const mod = await import(pathToFileURL4(entry).href);
22113
22705
  const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
@@ -22124,7 +22716,7 @@ function registerListLicenses(server2) {
22124
22716
  title: "List Licenses",
22125
22717
  description: "List all issued licenses with status (active/expired/revoked). Optionally filter by plan.",
22126
22718
  inputSchema: {
22127
- 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)")
22128
22720
  }
22129
22721
  },
22130
22722
  async ({ plan }) => {
@@ -22175,7 +22767,7 @@ function registerListLicenses(server2) {
22175
22767
 
22176
22768
  // src/mcp/tools/activate-license.ts
22177
22769
  init_license();
22178
- import { z as z64 } from "zod";
22770
+ import { z as z65 } from "zod";
22179
22771
  function registerActivateLicense(server2) {
22180
22772
  server2.registerTool(
22181
22773
  "activate_license",
@@ -22183,7 +22775,7 @@ function registerActivateLicense(server2) {
22183
22775
  title: "Activate License",
22184
22776
  description: "Activate an exe_sk_* license key on this device. Writes to ~/.exe-os/license.key, validates against Postgres, and caches the result.",
22185
22777
  inputSchema: {
22186
- key: z64.string().startsWith("exe_sk_").describe("License key (exe_sk_*)")
22778
+ key: z65.string().startsWith("exe_sk_").describe("License key (exe_sk_*)")
22187
22779
  }
22188
22780
  },
22189
22781
  async ({ key }) => {
@@ -22229,18 +22821,18 @@ Key saved to ~/.exe-os/license.key. Device ID: ${deviceId}`);
22229
22821
  }
22230
22822
 
22231
22823
  // src/mcp/tools/create-trigger.ts
22232
- import { z as z65 } from "zod";
22824
+ import { z as z66 } from "zod";
22233
22825
 
22234
22826
  // src/automation/trigger-engine.ts
22235
- 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";
22236
22828
  import { randomUUID as randomUUID7 } from "crypto";
22237
- import path38 from "path";
22829
+ import path39 from "path";
22238
22830
  import os17 from "os";
22239
- var TRIGGERS_PATH = path38.join(os17.homedir(), ".exe-os", "triggers.json");
22831
+ var TRIGGERS_PATH = path39.join(os17.homedir(), ".exe-os", "triggers.json");
22240
22832
  function loadTriggers(project) {
22241
- if (!existsSync31(TRIGGERS_PATH)) return [];
22833
+ if (!existsSync32(TRIGGERS_PATH)) return [];
22242
22834
  try {
22243
- const raw = readFileSync23(TRIGGERS_PATH, "utf-8");
22835
+ const raw = readFileSync24(TRIGGERS_PATH, "utf-8");
22244
22836
  const all = JSON.parse(raw);
22245
22837
  if (!Array.isArray(all)) return [];
22246
22838
  if (project) {
@@ -22252,9 +22844,9 @@ function loadTriggers(project) {
22252
22844
  }
22253
22845
  }
22254
22846
  function saveTriggers(triggers) {
22255
- const dir = path38.dirname(TRIGGERS_PATH);
22256
- if (!existsSync31(dir)) mkdirSync15(dir, { recursive: true });
22257
- 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");
22258
22850
  }
22259
22851
  function createNewTrigger(input) {
22260
22852
  const triggers = loadTriggers();
@@ -22410,14 +23002,14 @@ function addToCrontab(id, cron, prompt, projectDir) {
22410
23002
  }
22411
23003
 
22412
23004
  // src/mcp/tools/create-trigger.ts
22413
- var conditionSchema = z65.object({
22414
- field: z65.string().describe("Dot-path field to evaluate, e.g., 'stage' or 'amount'"),
22415
- op: z65.enum(["eq", "neq", "gt", "lt", "gte", "lte", "contains", "not_contains"]).describe("Comparison operator"),
22416
- 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")
22417
23009
  });
22418
- var actionSchema = z65.object({
22419
- type: z65.enum(["send_whatsapp", "send_message", "create_task", "mcp_tool"]).describe("Action type to execute"),
22420
- 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(
22421
23013
  "Action parameters. Supports {{record.field}} templates for dynamic values."
22422
23014
  )
22423
23015
  });
@@ -22428,18 +23020,18 @@ function registerCreateTrigger(server2) {
22428
23020
  title: "Create Trigger",
22429
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.).",
22430
23022
  inputSchema: {
22431
- name: z65.string().describe("Human-readable trigger name"),
22432
- event: z65.string().describe(
23023
+ name: z66.string().describe("Human-readable trigger name"),
23024
+ event: z66.string().describe(
22433
23025
  'CRM event to match, e.g., "Deal.updated", "Order.created", "*" for all'
22434
23026
  ),
22435
- conditions: z65.array(conditionSchema).default([]).describe("Conditions that must all match (AND logic)"),
22436
- actions: z65.array(actionSchema).min(1).describe("Actions to execute when trigger fires"),
22437
- project: z65.string().optional().describe("Scope trigger to a specific project"),
22438
- enabled: z65.boolean().default(true).describe("Whether trigger is active"),
22439
- 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(
22440
23032
  'Cron schedule for time-based triggers, e.g., "0 9 * * *" or "Monday 9am"'
22441
23033
  ),
22442
- query: z65.string().optional().describe(
23034
+ query: z66.string().optional().describe(
22443
23035
  "CRM GraphQL query to run on schedule (required if schedule is set)"
22444
23036
  )
22445
23037
  }
@@ -22512,7 +23104,7 @@ Enabled: ${trigger.enabled}` + scheduleInfo;
22512
23104
  }
22513
23105
 
22514
23106
  // src/mcp/tools/list-triggers.ts
22515
- import { z as z66 } from "zod";
23107
+ import { z as z67 } from "zod";
22516
23108
  function registerListTriggers(server2) {
22517
23109
  server2.registerTool(
22518
23110
  "list_triggers",
@@ -22520,7 +23112,7 @@ function registerListTriggers(server2) {
22520
23112
  title: "List Triggers",
22521
23113
  description: "List configured CRM event triggers and scheduled automations.",
22522
23114
  inputSchema: {
22523
- project: z66.string().optional().describe("Filter triggers by project name")
23115
+ project: z67.string().optional().describe("Filter triggers by project name")
22524
23116
  }
22525
23117
  },
22526
23118
  async ({ project }) => {
@@ -22555,51 +23147,51 @@ function registerListTriggers(server2) {
22555
23147
  }
22556
23148
 
22557
23149
  // src/mcp/tools/apply-starter-pack.ts
22558
- import { z as z67 } from "zod";
23150
+ import { z as z68 } from "zod";
22559
23151
 
22560
23152
  // src/automation/starter-packs/index.ts
22561
- import { readFileSync as readFileSync24, readdirSync as readdirSync12, existsSync as existsSync32 } from "fs";
22562
- import path39 from "path";
23153
+ import { readFileSync as readFileSync25, readdirSync as readdirSync12, existsSync as existsSync33 } from "fs";
23154
+ import path40 from "path";
22563
23155
  import { fileURLToPath as fileURLToPath4 } from "url";
22564
- var __dirname = path39.dirname(fileURLToPath4(import.meta.url));
23156
+ var __dirname = path40.dirname(fileURLToPath4(import.meta.url));
22565
23157
  function listPacks() {
22566
- const packsDir = path39.join(__dirname, ".");
22567
- if (!existsSync32(packsDir)) return [];
23158
+ const packsDir = path40.join(__dirname, ".");
23159
+ if (!existsSync33(packsDir)) return [];
22568
23160
  return readdirSync12(packsDir, { withFileTypes: true }).filter(
22569
- (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"))
22570
23162
  ).map((d) => d.name);
22571
23163
  }
22572
23164
  function loadPack(industry) {
22573
- const packDir = path39.join(__dirname, industry);
22574
- const objectsPath = path39.join(packDir, "custom-objects.json");
22575
- const triggersPath = path39.join(packDir, "triggers.json");
22576
- const wikiDir = path39.join(packDir, "wiki-seeds");
22577
- const manifestPath = path39.join(packDir, "pack.json");
22578
- const identityContextPath = path39.join(packDir, "identity-context.md");
22579
- 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;
22580
23172
  let customObjects = [];
22581
23173
  try {
22582
23174
  customObjects = JSON.parse(
22583
- readFileSync24(objectsPath, "utf-8")
23175
+ readFileSync25(objectsPath, "utf-8")
22584
23176
  );
22585
23177
  } catch {
22586
23178
  customObjects = [];
22587
23179
  }
22588
23180
  let triggers = [];
22589
- if (existsSync32(triggersPath)) {
23181
+ if (existsSync33(triggersPath)) {
22590
23182
  try {
22591
23183
  triggers = JSON.parse(
22592
- readFileSync24(triggersPath, "utf-8")
23184
+ readFileSync25(triggersPath, "utf-8")
22593
23185
  );
22594
23186
  } catch {
22595
23187
  triggers = [];
22596
23188
  }
22597
23189
  }
22598
23190
  const wikiSeeds = [];
22599
- if (existsSync32(wikiDir)) {
23191
+ if (existsSync33(wikiDir)) {
22600
23192
  const files = readdirSync12(wikiDir).filter((f) => f.endsWith(".md"));
22601
23193
  for (const file of files) {
22602
- const content = readFileSync24(path39.join(wikiDir, file), "utf-8");
23194
+ const content = readFileSync25(path40.join(wikiDir, file), "utf-8");
22603
23195
  const titleMatch = content.match(/^#\s+(.+)/m);
22604
23196
  wikiSeeds.push({
22605
23197
  filename: file,
@@ -22609,17 +23201,17 @@ function loadPack(industry) {
22609
23201
  }
22610
23202
  }
22611
23203
  let manifest = {};
22612
- if (existsSync32(manifestPath)) {
23204
+ if (existsSync33(manifestPath)) {
22613
23205
  try {
22614
- manifest = JSON.parse(readFileSync24(manifestPath, "utf-8"));
23206
+ manifest = JSON.parse(readFileSync25(manifestPath, "utf-8"));
22615
23207
  } catch {
22616
23208
  manifest = {};
22617
23209
  }
22618
23210
  }
22619
23211
  let identityContext = null;
22620
- if (existsSync32(identityContextPath)) {
23212
+ if (existsSync33(identityContextPath)) {
22621
23213
  try {
22622
- identityContext = readFileSync24(identityContextPath, "utf-8");
23214
+ identityContext = readFileSync25(identityContextPath, "utf-8");
22623
23215
  } catch {
22624
23216
  identityContext = null;
22625
23217
  }
@@ -22676,8 +23268,8 @@ function applyPack(industry, project) {
22676
23268
 
22677
23269
  // src/lib/client-coo.ts
22678
23270
  init_config();
22679
- import { existsSync as existsSync33, mkdirSync as mkdirSync16, writeFileSync as writeFileSync18 } from "fs";
22680
- import path40 from "path";
23271
+ import { existsSync as existsSync34, mkdirSync as mkdirSync17, writeFileSync as writeFileSync19 } from "fs";
23272
+ import path41 from "path";
22681
23273
 
22682
23274
  // src/lib/employee-templates.ts
22683
23275
  init_global_procedures();
@@ -22817,18 +23409,18 @@ var ClientCOOClobberError = class extends Error {
22817
23409
  var COO_ROLE = "Chief Operating Officer";
22818
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.";
22819
23411
  async function provisionClientCOO(vars, opts = {}) {
22820
- const identityDir = opts.identityDir ?? path40.join(EXE_AI_DIR, "identity");
23412
+ const identityDir = opts.identityDir ?? path41.join(EXE_AI_DIR, "identity");
22821
23413
  const rosterPath = opts.employeesPath ?? EMPLOYEES_PATH;
22822
23414
  const storeFeedbackBehavior = opts.storeFeedbackBehavior ?? true;
22823
- const identityPath2 = path40.join(identityDir, `${vars.agent_name}.md`);
22824
- if (existsSync33(identityPath2)) {
23415
+ const identityPath2 = path41.join(identityDir, `${vars.agent_name}.md`);
23416
+ if (existsSync34(identityPath2)) {
22825
23417
  throw new ClientCOOClobberError(vars.agent_name, identityPath2);
22826
23418
  }
22827
23419
  const body = renderClientCOOTemplate(vars);
22828
- if (!existsSync33(identityDir)) {
22829
- mkdirSync16(identityDir, { recursive: true });
23420
+ if (!existsSync34(identityDir)) {
23421
+ mkdirSync17(identityDir, { recursive: true });
22830
23422
  }
22831
- writeFileSync18(identityPath2, body, "utf-8");
23423
+ writeFileSync19(identityPath2, body, "utf-8");
22832
23424
  const employees = await loadEmployees(rosterPath);
22833
23425
  const existing = employees.find((e) => e.name === vars.agent_name);
22834
23426
  let addedToRoster = false;
@@ -22864,17 +23456,17 @@ function registerApplyStarterPack(server2) {
22864
23456
  title: "Apply Starter Pack",
22865
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.",
22866
23458
  inputSchema: {
22867
- industry: z67.string().describe(
23459
+ industry: z68.string().describe(
22868
23460
  'Industry pack to apply (e.g., "distribution"). Use without args to list available packs.'
22869
23461
  ),
22870
- project: z67.string().describe("Project name to scope the triggers to"),
22871
- 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(
22872
23464
  "Optional. Lowercase alphanumeric name for the Client COO agent. Required (alongside company_name and founder_name) to provision a COO."
22873
23465
  ),
22874
- company_name: z67.string().optional().describe(
23466
+ company_name: z68.string().optional().describe(
22875
23467
  "Optional. The client company the COO serves. Required to provision a COO."
22876
23468
  ),
22877
- founder_name: z67.string().optional().describe(
23469
+ founder_name: z68.string().optional().describe(
22878
23470
  "Optional. The founder the COO reports to. Required to provision a COO."
22879
23471
  )
22880
23472
  }
@@ -23019,19 +23611,19 @@ ${err.message}`
23019
23611
  }
23020
23612
 
23021
23613
  // src/mcp/tools/load-skill.ts
23022
- import { z as z68 } from "zod";
23023
- import { readFileSync as readFileSync25, readdirSync as readdirSync13, statSync as statSync6 } from "fs";
23024
- 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";
23025
23617
  import { homedir as homedir7 } from "os";
23026
- var SKILLS_DIR = path41.join(homedir7(), ".claude", "skills");
23618
+ var SKILLS_DIR = path42.join(homedir7(), ".claude", "skills");
23027
23619
  function listAvailableSkills() {
23028
23620
  try {
23029
23621
  const entries = readdirSync13(SKILLS_DIR);
23030
23622
  return entries.filter((entry) => {
23031
23623
  try {
23032
- const entryPath = path41.join(SKILLS_DIR, entry);
23624
+ const entryPath = path42.join(SKILLS_DIR, entry);
23033
23625
  if (!statSync6(entryPath).isDirectory()) return false;
23034
- const skillFile = path41.join(entryPath, "SKILL.md");
23626
+ const skillFile = path42.join(entryPath, "SKILL.md");
23035
23627
  statSync6(skillFile);
23036
23628
  return true;
23037
23629
  } catch {
@@ -23049,7 +23641,7 @@ function registerLoadSkill(server2) {
23049
23641
  title: "Load Skill",
23050
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.",
23051
23643
  inputSchema: {
23052
- skill_name: z68.string().describe(
23644
+ skill_name: z69.string().describe(
23053
23645
  "Skill to load (e.g. 'seo', 'code-reviewer', 'frontend-design'). Pass 'list' to see all available skills."
23054
23646
  )
23055
23647
  }
@@ -23074,10 +23666,10 @@ ${skills.map((s) => `- ${s}`).join("\n")}`
23074
23666
  }]
23075
23667
  };
23076
23668
  }
23077
- const sanitized = path41.basename(skill_name);
23078
- 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");
23079
23671
  try {
23080
- const content = readFileSync25(skillFile, "utf-8");
23672
+ const content = readFileSync26(skillFile, "utf-8");
23081
23673
  return {
23082
23674
  content: [{
23083
23675
  type: "text",
@@ -23105,18 +23697,18 @@ ${available.map((s) => `- ${s}`).join("\n")}` : "\n\nNo skills found in ~/.claud
23105
23697
 
23106
23698
  // src/mcp/tools/export-orchestration.ts
23107
23699
  init_active_agent();
23108
- import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync20 } from "fs";
23109
- import path43 from "path";
23110
- 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";
23111
23703
 
23112
23704
  // src/lib/orchestration-package.ts
23113
23705
  init_database();
23114
23706
  init_identity();
23115
23707
  init_platform_procedures();
23116
23708
  import { randomUUID as randomUUID8 } from "crypto";
23117
- 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";
23118
23710
  import os18 from "os";
23119
- import path42 from "path";
23711
+ import path43 from "path";
23120
23712
  var PACKAGE_VERSION = "1.0";
23121
23713
  var ROSTER_FILENAME = "exe-employees.json";
23122
23714
  var ROSTER_BACKUP_FILENAME = "exe-employees.json.bak";
@@ -23182,15 +23774,15 @@ function validateProcedureEntry(value, index) {
23182
23774
  };
23183
23775
  }
23184
23776
  function getRosterPath() {
23185
- return path42.join(os18.homedir(), EXE_OS_DIRNAME, ROSTER_FILENAME);
23777
+ return path43.join(os18.homedir(), EXE_OS_DIRNAME, ROSTER_FILENAME);
23186
23778
  }
23187
23779
  function getBackupPath() {
23188
- return path42.join(os18.homedir(), EXE_OS_DIRNAME, ROSTER_BACKUP_FILENAME);
23780
+ return path43.join(os18.homedir(), EXE_OS_DIRNAME, ROSTER_BACKUP_FILENAME);
23189
23781
  }
23190
23782
  function readRosterFile() {
23191
23783
  const rosterPath = getRosterPath();
23192
- if (!existsSync34(rosterPath)) return [];
23193
- const raw = readFileSync26(rosterPath, "utf-8");
23784
+ if (!existsSync35(rosterPath)) return [];
23785
+ const raw = readFileSync27(rosterPath, "utf-8");
23194
23786
  const parsed = JSON.parse(raw);
23195
23787
  if (!Array.isArray(parsed)) {
23196
23788
  throw new Error("Roster file must contain a JSON array");
@@ -23202,8 +23794,8 @@ function writeRosterFile(roster) {
23202
23794
  throw new Error("Refusing to write empty roster \u2014 this would delete all employees");
23203
23795
  }
23204
23796
  const rosterPath = getRosterPath();
23205
- mkdirSync17(path42.dirname(rosterPath), { recursive: true });
23206
- if (existsSync34(rosterPath)) {
23797
+ mkdirSync18(path43.dirname(rosterPath), { recursive: true });
23798
+ if (existsSync35(rosterPath)) {
23207
23799
  const currentRoster = readRosterFile();
23208
23800
  if (roster.length < currentRoster.length) {
23209
23801
  throw new Error(
@@ -23212,7 +23804,7 @@ function writeRosterFile(roster) {
23212
23804
  }
23213
23805
  copyFileSync2(rosterPath, getBackupPath());
23214
23806
  }
23215
- writeFileSync19(rosterPath, `${JSON.stringify(roster, null, 2)}
23807
+ writeFileSync20(rosterPath, `${JSON.stringify(roster, null, 2)}
23216
23808
  `, "utf-8");
23217
23809
  }
23218
23810
  function buildImportedRosterEntries(roster, timestamp) {
@@ -23467,15 +24059,15 @@ function registerExportOrchestration(server2) {
23467
24059
  title: "Export Orchestration",
23468
24060
  description: "Export roster, identities, behaviors, and customer procedures to a JSON package.",
23469
24061
  inputSchema: {
23470
- 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")
23471
24063
  }
23472
24064
  },
23473
24065
  async ({ output_path }) => {
23474
24066
  try {
23475
24067
  await initStore();
23476
24068
  const pkg = await exportOrchestration(getActiveAgent().agentId);
23477
- mkdirSync18(path43.dirname(output_path), { recursive: true });
23478
- 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)}
23479
24071
  `, "utf-8");
23480
24072
  return {
23481
24073
  content: [{
@@ -23497,8 +24089,8 @@ function registerExportOrchestration(server2) {
23497
24089
  }
23498
24090
 
23499
24091
  // src/mcp/tools/import-orchestration.ts
23500
- import { readFileSync as readFileSync27 } from "fs";
23501
- import { z as z70 } from "zod";
24092
+ import { readFileSync as readFileSync28 } from "fs";
24093
+ import { z as z71 } from "zod";
23502
24094
  init_store();
23503
24095
  init_active_agent();
23504
24096
  init_employees();
@@ -23509,8 +24101,8 @@ function registerImportOrchestration(server2) {
23509
24101
  title: "Import Orchestration",
23510
24102
  description: "Import roster, identities, behaviors, and procedures from an orchestration package. Restricted to coordinator/founder.",
23511
24103
  inputSchema: {
23512
- package_path: z70.string().describe("Path to the orchestration package JSON file"),
23513
- 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")
23514
24106
  }
23515
24107
  },
23516
24108
  async ({ package_path, merge_strategy }) => {
@@ -23527,7 +24119,7 @@ function registerImportOrchestration(server2) {
23527
24119
  };
23528
24120
  }
23529
24121
  await initStore();
23530
- const raw = readFileSync27(package_path, "utf-8");
24122
+ const raw = readFileSync28(package_path, "utf-8");
23531
24123
  const pkg = validatePackage(JSON.parse(raw));
23532
24124
  const result = await importOrchestration(pkg, merge_strategy);
23533
24125
  return {
@@ -23555,7 +24147,7 @@ init_platform_procedures();
23555
24147
  init_active_agent();
23556
24148
  init_database();
23557
24149
  init_employees();
23558
- import { z as z71 } from "zod";
24150
+ import { z as z72 } from "zod";
23559
24151
  function registerCompanyProcedureTool(server2, toolName) {
23560
24152
  server2.registerTool(
23561
24153
  toolName,
@@ -23563,12 +24155,12 @@ function registerCompanyProcedureTool(server2, toolName) {
23563
24155
  title: "Company Procedure",
23564
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).",
23565
24157
  inputSchema: {
23566
- action: z71.enum(["store", "list", "deactivate"]).describe("Action to perform"),
23567
- title: z71.string().optional().describe("Short title for the procedure (store)"),
23568
- content: z71.string().max(500).optional().describe("The procedure content \u2014 clear, actionable instruction (store)"),
23569
- priority: z71.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always (default). p1 = standard. p2 = nice-to-have."),
23570
- domain: z71.string().optional().describe("Category: workflow, code-style, communication, architecture, testing, security"),
23571
- 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)")
23572
24164
  }
23573
24165
  },
23574
24166
  async ({ action, title, content, priority, domain, procedure_id }) => {
@@ -23701,6 +24293,7 @@ var ACTION_TO_TOOL2 = {
23701
24293
  memory_audit: "run_memory_audit",
23702
24294
  run_consolidation: "run_consolidation",
23703
24295
  cloud_sync: "cloud_sync",
24296
+ orchestration_phase: "orchestration_phase",
23704
24297
  backup_vps: "backup_vps",
23705
24298
  deploy_client: "deploy_client",
23706
24299
  license_status: "get_license_status",
@@ -23737,6 +24330,7 @@ function buildHandlers5() {
23737
24330
  registerRunMemoryAudit(localServer);
23738
24331
  registerRunConsolidation(localServer);
23739
24332
  registerCloudSync(localServer);
24333
+ registerOrchestrationPhase(localServer);
23740
24334
  registerBackupVps(localServer);
23741
24335
  registerDeployClient(localServer);
23742
24336
  registerGetLicenseStatus(localServer);
@@ -23759,41 +24353,42 @@ function registerConfig(server2) {
23759
24353
  title: "Config",
23760
24354
  description: "Consolidated COO/admin tool for runtime config, system health, licensing, triggers, orchestration import/export, and company procedures.",
23761
24355
  inputSchema: {
23762
- action: z72.enum(Object.keys(ACTION_TO_TOOL2)).describe("Admin/config operation"),
23763
- agent_id: z72.string().optional().describe("Agent id for set_agent_config/agent_spend/session queries"),
23764
- runtime: z72.string().optional().describe("Runtime for set_agent_config"),
23765
- model: z72.string().optional().describe("Model for set_agent_config"),
23766
- reasoning_effort: z72.string().optional().describe("Reasoning effort for Codex agents"),
23767
- dry_run: z72.boolean().optional().describe("Preview without applying where supported"),
23768
- fix: z72.boolean().optional().describe("Apply fixes for memory_audit where supported"),
23769
- verbose: z72.boolean().optional().describe("Verbose output where supported"),
23770
- project_name: z72.string().optional().describe("Project filter/name"),
23771
- since: z72.string().optional().describe("ISO lower-bound timestamp"),
23772
- limit: z72.coerce.number().optional().describe("Result limit"),
23773
- output_path: z72.string().optional().describe("Output path for export/backup"),
23774
- input_path: z72.string().optional().describe("Input path for import_orchestration"),
23775
- strategy: z72.enum(["merge", "replace"]).optional().describe("Import strategy; replace must still be additive-only per platform rules"),
23776
- license_key: z72.string().optional().describe("License key for activation/status"),
23777
- email: z72.string().optional().describe("Customer email for license creation"),
23778
- plan: z72.string().optional().describe("License plan"),
23779
- name: z72.string().optional().describe("Trigger/starter pack/procedure/client name"),
23780
- event: z72.string().optional().describe("Trigger event"),
23781
- conditions: z72.array(z72.record(z72.string(), z72.unknown())).optional().describe("Trigger conditions"),
23782
- actions: z72.array(z72.record(z72.string(), z72.unknown())).optional().describe("Trigger actions"),
23783
- enabled: z72.boolean().optional().describe("Trigger enabled flag"),
23784
- schedule: z72.string().optional().describe("Trigger schedule"),
23785
- query: z72.string().optional().describe("Trigger query or filter"),
23786
- skill_name: z72.string().optional().describe("Skill name for load_skill"),
23787
- pack_name: z72.string().optional().describe("Starter pack name"),
23788
- title: z72.string().optional().describe("Procedure title"),
23789
- content: z72.string().optional().describe("Procedure content"),
23790
- priority: z72.enum(["p0", "p1", "p2"]).optional().describe("Procedure priority"),
23791
- domain: z72.string().optional().describe("Procedure domain"),
23792
- procedure_id: z72.string().optional().describe("Procedure id for deactivate"),
23793
- subaction: z72.enum(["store", "list", "deactivate"]).optional().describe("Nested action for company_procedure/global_procedure"),
23794
- max_clusters: z72.coerce.number().optional().describe("Consolidation max clusters"),
23795
- force: z72.boolean().optional().describe("Force operation where supported"),
23796
- 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")
23797
24392
  }
23798
24393
  }, async (input, extra) => {
23799
24394
  const action = input.action;
@@ -23814,10 +24409,10 @@ function registerConfig(server2) {
23814
24409
  }
23815
24410
 
23816
24411
  // src/mcp/tools/wiki.ts
23817
- import { z as z75 } from "zod";
24412
+ import { z as z76 } from "zod";
23818
24413
 
23819
24414
  // src/mcp/tools/list-wiki-pages.ts
23820
- import { z as z73 } from "zod";
24415
+ import { z as z74 } from "zod";
23821
24416
  var FETCH_TIMEOUT_MS3 = 1e4;
23822
24417
  function registerListWikiPages(server2) {
23823
24418
  server2.registerTool(
@@ -23826,8 +24421,8 @@ function registerListWikiPages(server2) {
23826
24421
  title: "List Wiki Pages",
23827
24422
  description: "List documents in an exe-wiki workspace. Optionally filter by folder.",
23828
24423
  inputSchema: {
23829
- workspace: z73.string().describe('Wiki workspace slug (e.g., "hygo")'),
23830
- 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")
23831
24426
  }
23832
24427
  },
23833
24428
  async ({ workspace, folder }) => {
@@ -23916,7 +24511,7 @@ function registerListWikiPages(server2) {
23916
24511
  }
23917
24512
 
23918
24513
  // src/mcp/tools/get-wiki-page.ts
23919
- import { z as z74 } from "zod";
24514
+ import { z as z75 } from "zod";
23920
24515
  var FETCH_TIMEOUT_MS4 = 1e4;
23921
24516
  function registerGetWikiPage(server2) {
23922
24517
  server2.registerTool(
@@ -23925,9 +24520,9 @@ function registerGetWikiPage(server2) {
23925
24520
  title: "Get Wiki Page",
23926
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.",
23927
24522
  inputSchema: {
23928
- workspace: z74.string().describe('Wiki workspace slug (e.g., "hygo")'),
23929
- document_id: z74.string().optional().describe("Specific document ID (exact lookup)"),
23930
- 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)")
23931
24526
  }
23932
24527
  },
23933
24528
  async ({ workspace, document_id, title }) => {
@@ -24109,14 +24704,14 @@ function registerWiki(server2) {
24109
24704
  title: "Wiki",
24110
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.",
24111
24706
  inputSchema: {
24112
- action: z75.enum(["list", "get"]).describe("Wiki read operation. Writes use raw-data ingestion/projection, not direct MCP writes."),
24113
- workspace: z75.string().optional().describe("Wiki workspace slug"),
24114
- title: z75.string().optional().describe("Fuzzy page title lookup for get"),
24115
- content: z75.string().optional().describe("Reserved; wiki writes use raw-data ingestion/projection"),
24116
- folder: z75.string().optional().describe("Optional folder path for list"),
24117
- document_id: z75.string().optional().describe("Document ID for get"),
24118
- mode: z75.enum(["replace", "append"]).optional().describe("Reserved; direct wiki updates are removed"),
24119
- 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")
24120
24715
  }
24121
24716
  },
24122
24717
  async (input, extra) => {
@@ -24144,7 +24739,7 @@ init_active_agent();
24144
24739
  init_project_name();
24145
24740
  init_database();
24146
24741
  init_employees();
24147
- import { z as z76 } from "zod";
24742
+ import { z as z77 } from "zod";
24148
24743
  function rowToBehavior2(r) {
24149
24744
  return {
24150
24745
  id: String(r.id),
@@ -24166,13 +24761,13 @@ function registerBehavior(server2) {
24166
24761
  title: "Behavior",
24167
24762
  description: "Manage behavioral patterns, corrections, and reusable procedures for employees. Actions: store (create new), list (query existing), deactivate (soft-delete, restricted).",
24168
24763
  inputSchema: {
24169
- action: z76.enum(["store", "list", "deactivate"]).describe("Action to perform"),
24170
- content: z76.string().max(500).optional().describe("The behavioral instruction \u2014 one clear sentence (store)"),
24171
- domain: z76.string().optional().describe("Category: workflow, code-style, tool-use, communication, architecture, testing"),
24172
- priority: z76.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always included. p1 = standard (default). p2 = nice-to-have."),
24173
- agent_id: z76.string().optional().describe("Employee name. Defaults to current agent. Pass 'all' to list everyone's (list only)."),
24174
- project_name: z76.string().optional().describe("Defaults to current project. Pass 'global' for a behavior that applies everywhere (store)."),
24175
- 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)")
24176
24771
  }
24177
24772
  },
24178
24773
  async ({ action, content, domain, priority, agent_id, project_name, behavior_id }) => {
@@ -24343,7 +24938,7 @@ Content: ${row.content}`
24343
24938
  }
24344
24939
 
24345
24940
  // src/mcp/tools/reminder.ts
24346
- import { z as z77 } from "zod";
24941
+ import { z as z78 } from "zod";
24347
24942
  function registerReminder(server2) {
24348
24943
  server2.registerTool(
24349
24944
  "reminder",
@@ -24351,11 +24946,11 @@ function registerReminder(server2) {
24351
24946
  title: "Reminder",
24352
24947
  description: "Manage reminders for the founder. Shown in the boot brief every session. Actions: create (set new), list (view active), complete (mark done).",
24353
24948
  inputSchema: {
24354
- action: z77.enum(["create", "list", "complete"]).describe("Action to perform"),
24355
- text: z77.string().optional().describe("What to remind about (create)"),
24356
- due_date: z77.string().optional().describe("Optional due date \u2014 ISO date (2026-04-01) or null for persistent (create)"),
24357
- reminder_id: z77.string().optional().describe("Reminder UUID or text substring to match (complete)"),
24358
- 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)")
24359
24954
  }
24360
24955
  },
24361
24956
  async ({ action, text: text3, due_date, reminder_id, include_completed }) => {
@@ -24411,7 +25006,7 @@ function registerReminder(server2) {
24411
25006
  init_global_procedures();
24412
25007
  init_active_agent();
24413
25008
  init_employees();
24414
- import { z as z78 } from "zod";
25009
+ import { z as z79 } from "zod";
24415
25010
  function registerStoreGlobalProcedure(server2) {
24416
25011
  server2.registerTool(
24417
25012
  "store_global_procedure",
@@ -24419,10 +25014,10 @@ function registerStoreGlobalProcedure(server2) {
24419
25014
  title: "Store Company Procedure (use global_procedure instead)",
24420
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.",
24421
25016
  inputSchema: {
24422
- title: z78.string().describe("Short title for the procedure"),
24423
- content: z78.string().max(500).describe("The procedure content \u2014 clear, actionable instruction"),
24424
- priority: z78.enum(["p0", "p1", "p2"]).optional().describe("Priority tier. p0 = always (default)."),
24425
- 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")
24426
25021
  }
24427
25022
  },
24428
25023
  async ({ title, content, priority, domain }) => {
@@ -24500,7 +25095,7 @@ init_global_procedures();
24500
25095
  init_active_agent();
24501
25096
  init_database();
24502
25097
  init_employees();
24503
- import { z as z79 } from "zod";
25098
+ import { z as z80 } from "zod";
24504
25099
  function registerDeactivateGlobalProcedure(server2) {
24505
25100
  server2.registerTool(
24506
25101
  "deactivate_global_procedure",
@@ -24508,7 +25103,7 @@ function registerDeactivateGlobalProcedure(server2) {
24508
25103
  title: "Deactivate Company Procedure (use global_procedure instead)",
24509
25104
  description: "DEPRECATED \u2014 use global_procedure with action='deactivate'. Soft-delete a company procedure. RESTRICTED: only coordinator or founder sessions.",
24510
25105
  inputSchema: {
24511
- 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")
24512
25107
  }
24513
25108
  },
24514
25109
  async ({ procedure_id }) => {
@@ -24568,7 +25163,7 @@ init_store();
24568
25163
  init_active_agent();
24569
25164
  init_database();
24570
25165
  init_plan_limits();
24571
- import { z as z80 } from "zod";
25166
+ import { z as z81 } from "zod";
24572
25167
  import crypto17 from "crypto";
24573
25168
  function registerStoreDecision(server2) {
24574
25169
  server2.registerTool(
@@ -24577,13 +25172,13 @@ function registerStoreDecision(server2) {
24577
25172
  title: "Store Decision",
24578
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.",
24579
25174
  inputSchema: {
24580
- domain: z80.string().describe(
25175
+ domain: z81.string().describe(
24581
25176
  "Domain key, e.g. 'auth-strategy', 'db-migration-approach', 'api-versioning'"
24582
25177
  ),
24583
- decision: z80.string().describe("The decision text \u2014 what was decided"),
24584
- rationale: z80.string().optional().describe("Why this decision was made \u2014 constraints, trade-offs, context"),
24585
- supersedes: z80.string().optional().describe("UUID of the decision this supersedes (previous decision for this domain)"),
24586
- 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")
24587
25182
  }
24588
25183
  },
24589
25184
  async ({ domain, decision, rationale, supersedes, project_name }) => {
@@ -24651,7 +25246,7 @@ Supersedes: ${supersedes}` : ""}`
24651
25246
 
24652
25247
  // src/mcp/tools/get-decision.ts
24653
25248
  init_database();
24654
- import { z as z81 } from "zod";
25249
+ import { z as z82 } from "zod";
24655
25250
  function registerGetDecision(server2) {
24656
25251
  server2.registerTool(
24657
25252
  "get_decision",
@@ -24659,7 +25254,7 @@ function registerGetDecision(server2) {
24659
25254
  title: "Get Decision",
24660
25255
  description: "Retrieve the latest authoritative decision for a domain. Returns the current active decision and the supersession history.",
24661
25256
  inputSchema: {
24662
- domain: z81.string().describe(
25257
+ domain: z82.string().describe(
24663
25258
  "Domain key to look up, e.g. 'auth-strategy', 'db-migration-approach'"
24664
25259
  )
24665
25260
  }
@@ -24722,16 +25317,16 @@ function registerGetDecision(server2) {
24722
25317
  }
24723
25318
 
24724
25319
  // src/mcp/tools/people-roster.ts
24725
- import { z as z82 } from "zod";
25320
+ import { z as z83 } from "zod";
24726
25321
 
24727
25322
  // src/lib/people.ts
24728
25323
  init_config();
24729
25324
  import { readFile as readFile5, writeFile as writeFile6, mkdir as mkdir5 } from "fs/promises";
24730
- import { existsSync as existsSync35, readFileSync as readFileSync28 } from "fs";
24731
- import path44 from "path";
24732
- 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");
24733
25328
  async function loadPeople() {
24734
- if (!existsSync35(PEOPLE_PATH)) return [];
25329
+ if (!existsSync36(PEOPLE_PATH)) return [];
24735
25330
  try {
24736
25331
  const raw = await readFile5(PEOPLE_PATH, "utf-8");
24737
25332
  return JSON.parse(raw);
@@ -24740,7 +25335,7 @@ async function loadPeople() {
24740
25335
  }
24741
25336
  }
24742
25337
  async function savePeople(people) {
24743
- await mkdir5(path44.dirname(PEOPLE_PATH), { recursive: true });
25338
+ await mkdir5(path45.dirname(PEOPLE_PATH), { recursive: true });
24744
25339
  await writeFile6(PEOPLE_PATH, JSON.stringify(people, null, 2) + "\n", "utf-8");
24745
25340
  }
24746
25341
  async function addPerson(person) {
@@ -24770,10 +25365,10 @@ function registerAddPerson(server2) {
24770
25365
  title: "Add Person",
24771
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.",
24772
25367
  inputSchema: {
24773
- name: z82.string().describe("Person's name"),
24774
- role: z82.string().describe("Their role (e.g. co-founder, customer, partner)"),
24775
- relationship: z82.string().describe("Relationship to the organization (e.g. co-founder, early adopter, investor)"),
24776
- 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")
24777
25372
  }
24778
25373
  },
24779
25374
  async ({ name, role, relationship, notes }) => {
@@ -24819,7 +25414,7 @@ function registerGetPerson(server2) {
24819
25414
  title: "Get Person",
24820
25415
  description: "Look up a specific person by name from the people roster.",
24821
25416
  inputSchema: {
24822
- name: z82.string().describe("Person's name to look up")
25417
+ name: z83.string().describe("Person's name to look up")
24823
25418
  }
24824
25419
  },
24825
25420
  async ({ name }) => {
@@ -24843,10 +25438,10 @@ Notes: ${person.notes}` : ""}`
24843
25438
  }
24844
25439
 
24845
25440
  // src/mcp/tools/crm.ts
24846
- import { z as z83 } from "zod";
25441
+ import { z as z84 } from "zod";
24847
25442
 
24848
25443
  // src/lib/exe-db-read.ts
24849
- import path45 from "path";
25444
+ import path46 from "path";
24850
25445
  import os19 from "os";
24851
25446
  import { createRequire as createRequire5 } from "module";
24852
25447
  import { pathToFileURL as pathToFileURL5 } from "url";
@@ -24864,8 +25459,8 @@ async function getExeDbReadClient() {
24864
25459
  if (!Ctor2) throw new Error(`No PrismaClient export found at ${explicitPath}`);
24865
25460
  return new Ctor2();
24866
25461
  }
24867
- const exeDbRoot = process.env.EXE_DB_ROOT ?? path45.join(os19.homedir(), "exe-db");
24868
- 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"));
24869
25464
  const entry = req.resolve("@prisma/client");
24870
25465
  const mod = await import(pathToFileURL5(entry).href);
24871
25466
  const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
@@ -24898,12 +25493,12 @@ function registerCrm(server2) {
24898
25493
  title: "CRM",
24899
25494
  description: "Read-only CRM access from exe-db crm schema. Actions: list_people, get_person, list_tables, describe_table.",
24900
25495
  inputSchema: {
24901
- action: z83.enum(["list_people", "get_person", "list_tables", "describe_table"]).describe("CRM read operation"),
24902
- id: z83.string().optional().describe("CRM row/person id for get_person"),
24903
- query: z83.string().optional().describe("Text search for list_people/get_person"),
24904
- table: z83.string().optional().describe("crm schema table name for describe_table"),
24905
- limit: z83.coerce.number().int().min(1).max(50).optional().describe("Max rows, capped at 50"),
24906
- 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")
24907
25502
  }
24908
25503
  }, async ({ action, id, query, table, limit, offset }) => {
24909
25504
  try {
@@ -24962,7 +25557,7 @@ function registerCrm(server2) {
24962
25557
  }
24963
25558
 
24964
25559
  // src/mcp/tools/raw-data.ts
24965
- import { z as z84 } from "zod";
25560
+ import { z as z85 } from "zod";
24966
25561
  function text2(content, isError = false) {
24967
25562
  return { content: [{ type: "text", text: content }], ...isError ? { isError: true } : {} };
24968
25563
  }
@@ -24971,15 +25566,15 @@ function registerRawData(server2) {
24971
25566
  title: "Raw Data",
24972
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.",
24973
25568
  inputSchema: {
24974
- action: z84.enum(["list_sources", "query", "get"]).describe("Raw data read operation"),
24975
- id: z84.string().optional().describe("raw.raw_events id for action=get"),
24976
- source: z84.string().optional().describe("Filter by raw source"),
24977
- event_type: z84.string().optional().describe("Filter by event_type"),
24978
- query: z84.string().optional().describe("Search payload/metadata text"),
24979
- processed: z84.boolean().optional().describe("Filter processed_at IS NULL/NOT NULL"),
24980
- limit: z84.coerce.number().int().min(1).max(50).optional().describe("Max rows, capped at 50"),
24981
- offset: z84.coerce.number().int().min(0).optional().describe("Rows to skip"),
24982
- 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.")
24983
25578
  }
24984
25579
  }, async ({ action, id, source, event_type, query, processed, limit, offset, include_payload }) => {
24985
25580
  try {
@@ -25046,17 +25641,17 @@ init_active_agent();
25046
25641
  init_config();
25047
25642
  init_license();
25048
25643
  init_store();
25049
- import { z as z85 } from "zod";
25644
+ import { z as z86 } from "zod";
25050
25645
  import crypto18 from "crypto";
25051
25646
  import { mkdir as mkdir6, writeFile as writeFile7 } from "fs/promises";
25052
- import path46 from "path";
25053
- var CLASSIFICATION = z85.enum([
25647
+ import path47 from "path";
25648
+ var CLASSIFICATION = z86.enum([
25054
25649
  "upstream_bug",
25055
25650
  "customer_customization",
25056
25651
  "emergency_hotfix",
25057
25652
  "unclear"
25058
25653
  ]);
25059
- var SEVERITY = z85.enum(["p0", "p1", "p2", "p3"]);
25654
+ var SEVERITY = z86.enum(["p0", "p1", "p2", "p3"]);
25060
25655
  function slugify2(input) {
25061
25656
  return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "bug-report";
25062
25657
  }
@@ -25134,22 +25729,22 @@ function registerCreateBugReport(server2) {
25134
25729
  title: "Create Bug Report",
25135
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.",
25136
25731
  inputSchema: {
25137
- title: z85.string().min(3).describe("Short descriptive title"),
25732
+ title: z86.string().min(3).describe("Short descriptive title"),
25138
25733
  classification: CLASSIFICATION.describe(
25139
25734
  "upstream_bug = platform defect; customer_customization = local preference; emergency_hotfix = temporary local patch; unclear = needs maintainer triage"
25140
25735
  ),
25141
25736
  severity: SEVERITY.default("p2").describe("p0 critical \u2192 p3 low"),
25142
- summary: z85.string().min(10).describe("What happened and why it matters"),
25143
- customer_impact: z85.string().optional().describe("How this affects the customer/founder"),
25144
- reproduction_steps: z85.array(z85.string()).optional().describe("Steps to reproduce"),
25145
- expected: z85.string().optional().describe("Expected behavior"),
25146
- actual: z85.string().optional().describe("Actual behavior"),
25147
- files_changed: z85.array(z85.string()).optional().describe("Files changed or suspected"),
25148
- workaround: z85.string().optional().describe("Temporary local workaround/hotfix, if any"),
25149
- local_patch_diff: z85.string().optional().describe("Small local diff or patch summary"),
25150
- package_version: z85.string().optional().describe("Installed @askexenow/exe-os version"),
25151
- project_name: z85.string().optional().describe("Project/customer context"),
25152
- 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")
25153
25748
  }
25154
25749
  },
25155
25750
  async ({
@@ -25189,9 +25784,9 @@ function registerCreateBugReport(server2) {
25189
25784
  filesChanged: files_changed,
25190
25785
  projectName: project_name
25191
25786
  });
25192
- const outDir = path46.join(EXE_AI_DIR, "bug-reports");
25787
+ const outDir = path47.join(EXE_AI_DIR, "bug-reports");
25193
25788
  await mkdir6(outDir, { recursive: true });
25194
- 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`);
25195
25790
  await writeFile7(reportPath, markdown, "utf-8");
25196
25791
  let vector = null;
25197
25792
  try {
@@ -25258,9 +25853,9 @@ Upstream status: ${upstreamStatus}`
25258
25853
  }
25259
25854
 
25260
25855
  // src/mcp/tools/support-inbox.ts
25261
- import { z as z86 } from "zod";
25856
+ import { z as z87 } from "zod";
25262
25857
  var DEFAULT_ENDPOINT = "https://askexe.com/admin/support/bug-reports";
25263
- var STATUS = z86.enum(["open", "triaged", "fixed", "closed", "wontfix"]);
25858
+ var STATUS = z87.enum(["open", "triaged", "fixed", "closed", "wontfix"]);
25264
25859
  function adminToken() {
25265
25860
  return process.env.ASKEXE_SUPPORT_ADMIN_TOKEN || process.env.EXE_SUPPORT_ADMIN_TOKEN;
25266
25861
  }
@@ -25299,9 +25894,9 @@ function registerListBugReports(server2) {
25299
25894
  title: "List Bug Reports",
25300
25895
  description: "AskExe-internal only: list incoming customer bug reports from the support inbox.",
25301
25896
  inputSchema: {
25302
- status: z86.enum(["all", "open", "triaged", "fixed", "closed", "wontfix"]).default("open"),
25303
- severity: z86.enum(["p0", "p1", "p2", "p3"]).optional(),
25304
- 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)
25305
25900
  }
25306
25901
  },
25307
25902
  async ({ status, severity, limit }) => {
@@ -25320,7 +25915,7 @@ function registerGetBugReport(server2) {
25320
25915
  {
25321
25916
  title: "Get Bug Report",
25322
25917
  description: "AskExe-internal only: fetch one customer bug report with full markdown payload.",
25323
- inputSchema: { id: z86.string().min(8) }
25918
+ inputSchema: { id: z87.string().min(8) }
25324
25919
  },
25325
25920
  async ({ id }) => {
25326
25921
  const data = await requestJson(`${endpoint()}/${encodeURIComponent(id)}`);
@@ -25335,12 +25930,12 @@ function registerTriageBugReport(server2) {
25335
25930
  title: "Triage Bug Report",
25336
25931
  description: "AskExe-internal only: update bug report status and link task/commit/release metadata.",
25337
25932
  inputSchema: {
25338
- id: z86.string().min(8),
25933
+ id: z87.string().min(8),
25339
25934
  status: STATUS.optional(),
25340
- triage_notes: z86.string().optional(),
25341
- linked_task_id: z86.string().optional(),
25342
- linked_commit: z86.string().optional(),
25343
- 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()
25344
25939
  }
25345
25940
  },
25346
25941
  async ({ id, status, triage_notes, linked_task_id, linked_commit, fixed_version }) => {
@@ -25470,6 +26065,7 @@ var TOOL_CATEGORIES = {
25470
26065
  registerRunMemoryAudit: "admin",
25471
26066
  registerRunConsolidation: "admin",
25472
26067
  registerCloudSync: "admin",
26068
+ registerOrchestrationPhase: "admin",
25473
26069
  registerSetAgentConfig: "admin",
25474
26070
  registerListEmployees: "admin",
25475
26071
  registerGetAgentSpend: "admin",
@@ -25688,6 +26284,7 @@ function registerAllTools(server2) {
25688
26284
  gate("registerRunMemoryAudit", registerRunMemoryAudit);
25689
26285
  gate("registerCloudSync", registerCloudSync);
25690
26286
  gate("registerBackupVps", registerBackupVps);
26287
+ gate("registerOrchestrationPhase", registerOrchestrationPhase);
25691
26288
  }
25692
26289
  if (exposeLegacyMemory) {
25693
26290
  gate("registerGetMemoryCardinality", registerGetMemoryCardinality);
@@ -25832,16 +26429,16 @@ try {
25832
26429
  }
25833
26430
  }, 3e4);
25834
26431
  _ppidWatchdog.unref();
25835
- 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");
25836
26433
  let _currentMcpVersion = null;
25837
26434
  try {
25838
- _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;
25839
26436
  } catch {
25840
26437
  }
25841
26438
  const _versionWatchdog = setInterval(() => {
25842
26439
  try {
25843
- if (!existsSync36(MCP_VERSION_PATH)) return;
25844
- const diskVersion = readFileSync29(MCP_VERSION_PATH, "utf8").trim();
26440
+ if (!existsSync37(MCP_VERSION_PATH)) return;
26441
+ const diskVersion = readFileSync30(MCP_VERSION_PATH, "utf8").trim();
25845
26442
  if (_currentMcpVersion && diskVersion !== _currentMcpVersion) {
25846
26443
  process.stderr.write(
25847
26444
  `[exe-os] MCP version changed (${_currentMcpVersion} \u2192 ${diskVersion}). Hot-reloading...
@@ -25874,14 +26471,14 @@ try {
25874
26471
  `
25875
26472
  );
25876
26473
  const thisFile = fileURLToPath5(import.meta.url);
25877
- const backfillPath = path47.resolve(
25878
- path47.dirname(thisFile),
26474
+ const backfillPath = path48.resolve(
26475
+ path48.dirname(thisFile),
25879
26476
  "../bin/backfill-vectors.js"
25880
26477
  );
25881
- if (existsSync36(backfillPath)) {
26478
+ if (existsSync37(backfillPath)) {
25882
26479
  const { EXE_AI_DIR: exeDir } = await Promise.resolve().then(() => (init_config(), config_exports));
25883
- const logPath = path47.join(exeDir, "workers.log");
25884
- mkdirSync19(path47.dirname(logPath), { recursive: true });
26480
+ const logPath = path48.join(exeDir, "workers.log");
26481
+ mkdirSync20(path48.dirname(logPath), { recursive: true });
25885
26482
  let logFd = "ignore";
25886
26483
  try {
25887
26484
  logFd = openSync3(logPath, "a");