@askexenow/exe-os 0.9.64 → 0.9.66

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/deploy/stack-manifests/v0.9.json +4 -4
  2. package/dist/bin/backfill-conversations.js +22 -0
  3. package/dist/bin/backfill-responses.js +22 -0
  4. package/dist/bin/backfill-vectors.js +22 -0
  5. package/dist/bin/cleanup-stale-review-tasks.js +22 -0
  6. package/dist/bin/cli.js +2280 -1199
  7. package/dist/bin/exe-agent-config.js +4 -0
  8. package/dist/bin/exe-agent.js +16 -0
  9. package/dist/bin/exe-assign.js +22 -0
  10. package/dist/bin/exe-boot.js +116 -7
  11. package/dist/bin/exe-call.js +16 -0
  12. package/dist/bin/exe-cloud.js +6671 -464
  13. package/dist/bin/exe-dispatch.js +24 -0
  14. package/dist/bin/exe-doctor.js +2845 -1223
  15. package/dist/bin/exe-export-behaviors.js +24 -0
  16. package/dist/bin/exe-forget.js +22 -0
  17. package/dist/bin/exe-gateway.js +24 -0
  18. package/dist/bin/exe-heartbeat.js +23 -0
  19. package/dist/bin/exe-kill.js +22 -0
  20. package/dist/bin/exe-launch-agent.js +24 -0
  21. package/dist/bin/exe-link.js +310 -178
  22. package/dist/bin/exe-new-employee.js +127 -1
  23. package/dist/bin/exe-pending-messages.js +22 -0
  24. package/dist/bin/exe-pending-notifications.js +22 -0
  25. package/dist/bin/exe-pending-reviews.js +22 -0
  26. package/dist/bin/exe-rename.js +22 -0
  27. package/dist/bin/exe-review.js +22 -0
  28. package/dist/bin/exe-search.js +24 -0
  29. package/dist/bin/exe-session-cleanup.js +24 -0
  30. package/dist/bin/exe-settings.js +10 -0
  31. package/dist/bin/exe-start-codex.js +135 -1
  32. package/dist/bin/exe-start-opencode.js +149 -1
  33. package/dist/bin/exe-status.js +22 -0
  34. package/dist/bin/exe-team.js +22 -0
  35. package/dist/bin/git-sweep.js +24 -0
  36. package/dist/bin/graph-backfill.js +22 -0
  37. package/dist/bin/graph-export.js +22 -0
  38. package/dist/bin/install.js +115 -1
  39. package/dist/bin/intercom-check.js +24 -0
  40. package/dist/bin/scan-tasks.js +24 -0
  41. package/dist/bin/setup.js +412 -157
  42. package/dist/bin/shard-migrate.js +22 -0
  43. package/dist/bin/update.js +4 -0
  44. package/dist/gateway/index.js +24 -0
  45. package/dist/hooks/bug-report-worker.js +135 -42
  46. package/dist/hooks/codex-stop-task-finalizer.js +24 -0
  47. package/dist/hooks/commit-complete.js +24 -0
  48. package/dist/hooks/error-recall.js +24 -0
  49. package/dist/hooks/exe-heartbeat-hook.js +4 -0
  50. package/dist/hooks/ingest-worker.js +4 -0
  51. package/dist/hooks/ingest.js +23 -0
  52. package/dist/hooks/instructions-loaded.js +22 -0
  53. package/dist/hooks/notification.js +22 -0
  54. package/dist/hooks/post-compact.js +22 -0
  55. package/dist/hooks/post-tool-combined.js +24 -0
  56. package/dist/hooks/pre-compact.js +260 -109
  57. package/dist/hooks/pre-tool-use.js +22 -0
  58. package/dist/hooks/prompt-submit.js +24 -0
  59. package/dist/hooks/session-end.js +161 -122
  60. package/dist/hooks/session-start.js +142 -0
  61. package/dist/hooks/stop.js +23 -0
  62. package/dist/hooks/subagent-stop.js +22 -0
  63. package/dist/hooks/summary-worker.js +195 -79
  64. package/dist/index.js +24 -0
  65. package/dist/lib/agent-config.js +4 -0
  66. package/dist/lib/cloud-sync.js +50 -6
  67. package/dist/lib/config.js +12 -0
  68. package/dist/lib/consolidation.js +4 -0
  69. package/dist/lib/database.js +4 -0
  70. package/dist/lib/db-daemon-client.js +4 -0
  71. package/dist/lib/db.js +4 -0
  72. package/dist/lib/device-registry.js +4 -0
  73. package/dist/lib/embedder.js +12 -0
  74. package/dist/lib/employee-templates.js +16 -0
  75. package/dist/lib/employees.js +4 -0
  76. package/dist/lib/exe-daemon-client.js +4 -0
  77. package/dist/lib/exe-daemon.js +1144 -480
  78. package/dist/lib/hybrid-search.js +24 -0
  79. package/dist/lib/identity.js +4 -0
  80. package/dist/lib/license.js +4 -0
  81. package/dist/lib/messaging.js +4 -0
  82. package/dist/lib/reminders.js +4 -0
  83. package/dist/lib/schedules.js +22 -0
  84. package/dist/lib/skill-learning.js +12 -0
  85. package/dist/lib/status-brief.js +39 -0
  86. package/dist/lib/store.js +22 -0
  87. package/dist/lib/task-router.js +4 -0
  88. package/dist/lib/tasks.js +12 -0
  89. package/dist/lib/tmux-routing.js +12 -0
  90. package/dist/lib/token-spend.js +4 -0
  91. package/dist/mcp/server.js +1045 -427
  92. package/dist/mcp/tools/complete-reminder.js +4 -0
  93. package/dist/mcp/tools/create-reminder.js +4 -0
  94. package/dist/mcp/tools/create-task.js +12 -0
  95. package/dist/mcp/tools/deactivate-behavior.js +4 -0
  96. package/dist/mcp/tools/list-reminders.js +4 -0
  97. package/dist/mcp/tools/list-tasks.js +4 -0
  98. package/dist/mcp/tools/send-message.js +4 -0
  99. package/dist/mcp/tools/update-task.js +12 -0
  100. package/dist/runtime/index.js +24 -0
  101. package/dist/tui/App.js +24 -0
  102. package/package.json +3 -2
  103. package/src/commands/exe/cloud.md +15 -8
  104. package/src/commands/exe/link.md +7 -6
  105. package/stack.release.json +2 -2
package/dist/bin/setup.js CHANGED
@@ -139,6 +139,11 @@ function normalizeAutoUpdate(raw) {
139
139
  const userAU = raw.autoUpdate ?? {};
140
140
  raw.autoUpdate = { ...defaultAU, ...userAU };
141
141
  }
142
+ function normalizeOrchestration(raw) {
143
+ const defaultOrg = DEFAULT_CONFIG.orchestration;
144
+ const userOrg = raw.orchestration ?? {};
145
+ raw.orchestration = { ...defaultOrg, ...userOrg };
146
+ }
142
147
  async function loadConfig() {
143
148
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
144
149
  await ensurePrivateDir(dir);
@@ -163,6 +168,7 @@ async function loadConfig() {
163
168
  normalizeScalingRoadmap(migratedCfg);
164
169
  normalizeSessionLifecycle(migratedCfg);
165
170
  normalizeAutoUpdate(migratedCfg);
171
+ normalizeOrchestration(migratedCfg);
166
172
  const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
167
173
  if (config.dbPath.startsWith("~")) {
168
174
  config.dbPath = config.dbPath.replace(/^~/, os.homedir());
@@ -186,6 +192,7 @@ function loadConfigSync() {
186
192
  normalizeScalingRoadmap(migratedCfg);
187
193
  normalizeSessionLifecycle(migratedCfg);
188
194
  normalizeAutoUpdate(migratedCfg);
195
+ normalizeOrchestration(migratedCfg);
189
196
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
190
197
  } catch {
191
198
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
@@ -207,6 +214,7 @@ async function loadConfigFrom(configPath) {
207
214
  normalizeScalingRoadmap(migratedCfg);
208
215
  normalizeSessionLifecycle(migratedCfg);
209
216
  normalizeAutoUpdate(migratedCfg);
217
+ normalizeOrchestration(migratedCfg);
210
218
  return { ...DEFAULT_CONFIG, ...migratedCfg };
211
219
  } catch {
212
220
  return { ...DEFAULT_CONFIG };
@@ -278,6 +286,10 @@ var init_config = __esm({
278
286
  checkOnBoot: true,
279
287
  autoInstall: false,
280
288
  checkIntervalMs: 24 * 60 * 60 * 1e3
289
+ },
290
+ orchestration: {
291
+ phase: "phase_1_coo",
292
+ phaseSetBy: "default"
281
293
  }
282
294
  };
283
295
  CONFIG_MIGRATIONS = [
@@ -415,8 +427,8 @@ function deriveMachineKey() {
415
427
  }
416
428
  function readMachineId() {
417
429
  try {
418
- const { readFileSync: readFileSync13 } = __require("fs");
419
- return readFileSync13("/etc/machine-id", "utf-8").trim();
430
+ const { readFileSync: readFileSync14 } = __require("fs");
431
+ return readFileSync14("/etc/machine-id", "utf-8").trim();
420
432
  } catch {
421
433
  return "";
422
434
  }
@@ -1129,10 +1141,10 @@ async function disposeEmbedder() {
1129
1141
  async function embedDirect(text) {
1130
1142
  const llamaCpp = await import("node-llama-cpp");
1131
1143
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
1132
- const { existsSync: existsSync17 } = await import("fs");
1133
- const path17 = await import("path");
1134
- const modelPath = path17.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
1135
- if (!existsSync17(modelPath)) {
1144
+ const { existsSync: existsSync18 } = await import("fs");
1145
+ const path18 = await import("path");
1146
+ const modelPath = path18.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
1147
+ if (!existsSync18(modelPath)) {
1136
1148
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
1137
1149
  }
1138
1150
  const llama = await llamaCpp.getLlama();
@@ -4503,8 +4515,10 @@ var init_db_backup = __esm({
4503
4515
  // src/lib/cloud-sync.ts
4504
4516
  var cloud_sync_exports = {};
4505
4517
  __export(cloud_sync_exports, {
4518
+ CLOUD_RELINK_REQUIRED_MESSAGE: () => CLOUD_RELINK_REQUIRED_MESSAGE,
4506
4519
  assertSecureEndpoint: () => assertSecureEndpoint,
4507
4520
  buildRosterBlob: () => buildRosterBlob,
4521
+ clearCloudRelinkRequired: () => clearCloudRelinkRequired,
4508
4522
  cloudPull: () => cloudPull,
4509
4523
  cloudPullBehaviors: () => cloudPullBehaviors,
4510
4524
  cloudPullBlob: () => cloudPullBlob,
@@ -4524,6 +4538,7 @@ __export(cloud_sync_exports, {
4524
4538
  cloudPushRoster: () => cloudPushRoster,
4525
4539
  cloudPushTasks: () => cloudPushTasks,
4526
4540
  cloudSync: () => cloudSync,
4541
+ getCloudRelinkRequired: () => getCloudRelinkRequired,
4527
4542
  mergeConfig: () => mergeConfig,
4528
4543
  mergeRosterFromRemote: () => mergeRosterFromRemote,
4529
4544
  pushToPostgres: () => pushToPostgres,
@@ -4544,31 +4559,43 @@ function logError(msg) {
4544
4559
  } catch {
4545
4560
  }
4546
4561
  }
4562
+ function isTruthyEnv(value) {
4563
+ return /^(1|true|yes|on)$/i.test(value ?? "");
4564
+ }
4547
4565
  function loadPgClient() {
4548
4566
  if (_pgFailed) return null;
4549
- const postgresUrl = process.env.DATABASE_URL;
4550
4567
  const configPath = path12.join(EXE_AI_DIR, "config.json");
4551
4568
  let cloudPostgresUrl;
4569
+ let configEnabled = false;
4552
4570
  try {
4553
4571
  if (existsSync12(configPath)) {
4554
4572
  const cfg = JSON.parse(readFileSync8(configPath, "utf8"));
4555
4573
  cloudPostgresUrl = cfg.cloud?.postgresUrl;
4556
- if (cfg.cloud?.syncToPostgres === false) {
4557
- _pgFailed = true;
4558
- return null;
4559
- }
4574
+ configEnabled = cfg.cloud?.syncToPostgres === true;
4560
4575
  }
4561
4576
  } catch {
4562
4577
  }
4563
- const url = postgresUrl || cloudPostgresUrl;
4578
+ const envEnabled = isTruthyEnv(process.env.EXE_CLOUD_SYNC_TO_POSTGRES);
4579
+ if (!envEnabled && !configEnabled) {
4580
+ return null;
4581
+ }
4582
+ const url = process.env.DATABASE_URL || cloudPostgresUrl;
4564
4583
  if (!url) {
4565
4584
  _pgFailed = true;
4566
4585
  return null;
4567
4586
  }
4568
4587
  if (!_pgPromise) {
4569
4588
  _pgPromise = (async () => {
4589
+ if (!process.env.DATABASE_URL) process.env.DATABASE_URL = url;
4570
4590
  const { createRequire: createRequire3 } = await import("module");
4571
4591
  const { pathToFileURL: pathToFileURL3 } = await import("url");
4592
+ const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
4593
+ if (explicitPath) {
4594
+ const mod2 = await import(pathToFileURL3(explicitPath).href);
4595
+ const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
4596
+ if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
4597
+ return new Ctor2();
4598
+ }
4572
4599
  const exeDbRoot = process.env.EXE_DB_ROOT ?? path12.join(homedir2(), "exe-db");
4573
4600
  const req = createRequire3(path12.join(exeDbRoot, "package.json"));
4574
4601
  const entry = req.resolve("@prisma/client");
@@ -4745,6 +4772,24 @@ async function cloudPull(sinceVersion, config) {
4745
4772
  return { records: [], maxVersion: sinceVersion };
4746
4773
  }
4747
4774
  }
4775
+ async function getCloudRelinkRequired(client = getClient()) {
4776
+ try {
4777
+ await client.execute("CREATE TABLE IF NOT EXISTS sync_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)");
4778
+ const relink = await client.execute("SELECT value FROM sync_meta WHERE key = 'cloud_relink_required' LIMIT 1");
4779
+ return String(relink.rows[0]?.value ?? "") === "1";
4780
+ } catch {
4781
+ return false;
4782
+ }
4783
+ }
4784
+ async function clearCloudRelinkRequired(client = getClient()) {
4785
+ await client.execute("CREATE TABLE IF NOT EXISTS sync_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)");
4786
+ await client.execute("INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('cloud_relink_required', '0')");
4787
+ await client.execute({
4788
+ sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('cloud_relinked_at', ?)",
4789
+ args: [(/* @__PURE__ */ new Date()).toISOString()]
4790
+ });
4791
+ await client.execute("DELETE FROM sync_meta WHERE key IN ('last_cloud_pull_version', 'last_cloud_push_version')");
4792
+ }
4748
4793
  async function cloudSync(config) {
4749
4794
  if (!isSyncCryptoInitialized()) {
4750
4795
  try {
@@ -4765,6 +4810,12 @@ async function cloudSync(config) {
4765
4810
  } catch {
4766
4811
  throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
4767
4812
  }
4813
+ try {
4814
+ if (await getCloudRelinkRequired(client)) throw new Error(CLOUD_RELINK_REQUIRED_MESSAGE);
4815
+ } catch (err) {
4816
+ const msg = err instanceof Error ? err.message : String(err);
4817
+ if (msg.includes("Paused after key rotation")) throw err;
4818
+ }
4768
4819
  try {
4769
4820
  const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
4770
4821
  await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
@@ -5692,7 +5743,7 @@ async function cloudPullDocuments(config) {
5692
5743
  }
5693
5744
  return { pulled };
5694
5745
  }
5695
- var LOCALHOST_PATTERNS, FETCH_TIMEOUT_MS, PUSH_BATCH_SIZE, ROSTER_LOCK_PATH, LOCK_STALE_MS, _pgPromise, _pgFailed, ROSTER_DELETIONS_PATH;
5746
+ var LOCALHOST_PATTERNS, FETCH_TIMEOUT_MS, PUSH_BATCH_SIZE, ROSTER_LOCK_PATH, LOCK_STALE_MS, _pgPromise, _pgFailed, CLOUD_RELINK_REQUIRED_MESSAGE, ROSTER_DELETIONS_PATH;
5696
5747
  var init_cloud_sync = __esm({
5697
5748
  "src/lib/cloud-sync.ts"() {
5698
5749
  "use strict";
@@ -5711,43 +5762,194 @@ var init_cloud_sync = __esm({
5711
5762
  LOCK_STALE_MS = 3e4;
5712
5763
  _pgPromise = null;
5713
5764
  _pgFailed = false;
5765
+ CLOUD_RELINK_REQUIRED_MESSAGE = "[cloud-sync] Paused after key rotation. Run `exe-os cloud relink --dry-run` for the safe relink checklist.";
5714
5766
  ROSTER_DELETIONS_PATH = path12.join(EXE_AI_DIR, "roster-deletions.json");
5715
5767
  }
5716
5768
  });
5717
5769
 
5770
+ // src/lib/key-backup-status.ts
5771
+ var key_backup_status_exports = {};
5772
+ __export(key_backup_status_exports, {
5773
+ getKeyBackupStatus: () => getKeyBackupStatus,
5774
+ keyBackupMarkerPath: () => keyBackupMarkerPath,
5775
+ markKeyBackupConfirmed: () => markKeyBackupConfirmed
5776
+ });
5777
+ import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
5778
+ import path13 from "path";
5779
+ function keyBackupMarkerPath() {
5780
+ return path13.join(EXE_AI_DIR, "key-backup-confirmed.json");
5781
+ }
5782
+ function getKeyBackupStatus() {
5783
+ const marker = keyBackupMarkerPath();
5784
+ if (!existsSync13(marker)) return { exists: false };
5785
+ try {
5786
+ const parsed = JSON.parse(readFileSync9(marker, "utf8"));
5787
+ return {
5788
+ exists: true,
5789
+ confirmedAt: parsed.confirmedAt,
5790
+ source: parsed.source
5791
+ };
5792
+ } catch {
5793
+ return { exists: true };
5794
+ }
5795
+ }
5796
+ function markKeyBackupConfirmed(source) {
5797
+ mkdirSync6(EXE_AI_DIR, { recursive: true, mode: 448 });
5798
+ writeFileSync7(
5799
+ keyBackupMarkerPath(),
5800
+ JSON.stringify({ confirmedAt: (/* @__PURE__ */ new Date()).toISOString(), source }, null, 2) + "\n",
5801
+ { mode: 384 }
5802
+ );
5803
+ }
5804
+ var init_key_backup_status = __esm({
5805
+ "src/lib/key-backup-status.ts"() {
5806
+ "use strict";
5807
+ init_config();
5808
+ }
5809
+ });
5810
+
5811
+ // src/lib/orchestration-phase.ts
5812
+ var orchestration_phase_exports = {};
5813
+ __export(orchestration_phase_exports, {
5814
+ ORCHESTRATION_PHASES: () => ORCHESTRATION_PHASES,
5815
+ applyDefaultOrchestrationPhase: () => applyDefaultOrchestrationPhase,
5816
+ getConfigOrchestrationPhase: () => getConfigOrchestrationPhase,
5817
+ getOrchestrationPhaseInfo: () => getOrchestrationPhaseInfo,
5818
+ loadOrchestrationPhase: () => loadOrchestrationPhase,
5819
+ normalizeOrchestrationPhase: () => normalizeOrchestrationPhase,
5820
+ phaseReminderLine: () => phaseReminderLine,
5821
+ setOrchestrationPhase: () => setOrchestrationPhase
5822
+ });
5823
+ function normalizeOrchestrationPhase(input) {
5824
+ if (typeof input !== "string") return "phase_1_coo";
5825
+ const normalized = input.trim().toLowerCase().replace(/\s+/g, "_");
5826
+ if (["1", "phase1", "phase_1", "coo", "coo_mode", "chief_of_staff", "phase_1_coo"].includes(normalized)) {
5827
+ return "phase_1_coo";
5828
+ }
5829
+ if (["2", "phase2", "phase_2", "executives", "executive", "executive_bench", "phase_2_executives"].includes(normalized)) {
5830
+ return "phase_2_executives";
5831
+ }
5832
+ if (["3", "phase3", "phase_3", "parallel", "parallel_org", "parallel_execution", "phase_3_parallel_org"].includes(normalized)) {
5833
+ return "phase_3_parallel_org";
5834
+ }
5835
+ if (ORCHESTRATION_PHASES.includes(normalized)) return normalized;
5836
+ return "phase_1_coo";
5837
+ }
5838
+ function getOrchestrationPhaseInfo(phase) {
5839
+ return PHASE_INFO[normalizeOrchestrationPhase(phase)];
5840
+ }
5841
+ function getConfigOrchestrationPhase(config) {
5842
+ const orchestration = config.orchestration;
5843
+ return normalizeOrchestrationPhase(orchestration?.phase);
5844
+ }
5845
+ function applyDefaultOrchestrationPhase(config) {
5846
+ if (!config.orchestration) {
5847
+ config.orchestration = {
5848
+ phase: "phase_1_coo",
5849
+ phaseSetAt: (/* @__PURE__ */ new Date()).toISOString(),
5850
+ phaseSetBy: "setup-default"
5851
+ };
5852
+ return config;
5853
+ }
5854
+ if (!config.orchestration.phase) {
5855
+ config.orchestration = {
5856
+ ...config.orchestration,
5857
+ phase: "phase_1_coo",
5858
+ phaseSetAt: config.orchestration.phaseSetAt ?? (/* @__PURE__ */ new Date()).toISOString(),
5859
+ phaseSetBy: config.orchestration.phaseSetBy ?? "setup-default"
5860
+ };
5861
+ }
5862
+ return config;
5863
+ }
5864
+ async function loadOrchestrationPhase() {
5865
+ const config = await loadConfig();
5866
+ return getOrchestrationPhaseInfo(config.orchestration?.phase);
5867
+ }
5868
+ async function setOrchestrationPhase(phaseInput, setBy = "user") {
5869
+ const config = await loadConfig();
5870
+ const phase = normalizeOrchestrationPhase(phaseInput);
5871
+ config.orchestration = {
5872
+ ...config.orchestration ?? {},
5873
+ phase,
5874
+ phaseSetAt: (/* @__PURE__ */ new Date()).toISOString(),
5875
+ phaseSetBy: setBy
5876
+ };
5877
+ await saveConfig(config);
5878
+ return getOrchestrationPhaseInfo(phase);
5879
+ }
5880
+ function phaseReminderLine(phase) {
5881
+ const info = getOrchestrationPhaseInfo(phase);
5882
+ return `${info.shortLabel}: ${info.focus}. ${info.nextSuggestion}`;
5883
+ }
5884
+ var ORCHESTRATION_PHASES, PHASE_INFO;
5885
+ var init_orchestration_phase = __esm({
5886
+ "src/lib/orchestration-phase.ts"() {
5887
+ "use strict";
5888
+ init_config();
5889
+ ORCHESTRATION_PHASES = [
5890
+ "phase_1_coo",
5891
+ "phase_2_executives",
5892
+ "phase_3_parallel_org"
5893
+ ];
5894
+ PHASE_INFO = {
5895
+ phase_1_coo: {
5896
+ phase: "phase_1_coo",
5897
+ shortLabel: "Phase 1 \u2014 COO mode",
5898
+ label: "Phase 1 \u2014 COO / Chief of Staff mode",
5899
+ focus: "building company context before delegation",
5900
+ nextSuggestion: "Unlock executives when technical, marketing, ops, legal, or finance work repeats."
5901
+ },
5902
+ phase_2_executives: {
5903
+ phase: "phase_2_executives",
5904
+ shortLabel: "Phase 2 \u2014 Executive bench",
5905
+ label: "Phase 2 \u2014 Executive bench",
5906
+ focus: "COO works with domain executives like CTO/CMO before specialist fan-out",
5907
+ nextSuggestion: "Unlock parallel execution when review gates, permissions, and workflows are ready."
5908
+ },
5909
+ phase_3_parallel_org: {
5910
+ phase: "phase_3_parallel_org",
5911
+ shortLabel: "Phase 3 \u2014 Parallel org",
5912
+ label: "Phase 3 \u2014 Parallel execution org",
5913
+ focus: "executives can delegate to specialists in parallel with review gates",
5914
+ nextSuggestion: "Keep review/CI/permission gates healthy; downgrade anytime if you want simpler COO-only mode."
5915
+ }
5916
+ };
5917
+ }
5918
+ });
5919
+
5718
5920
  // src/lib/preferences.ts
5719
5921
  var preferences_exports = {};
5720
5922
  __export(preferences_exports, {
5721
5923
  loadPreferences: () => loadPreferences,
5722
5924
  savePreferences: () => savePreferences
5723
5925
  });
5724
- import { existsSync as existsSync13, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
5725
- import path13 from "path";
5926
+ import { existsSync as existsSync14, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
5927
+ import path14 from "path";
5726
5928
  import os7 from "os";
5727
5929
  function loadPreferences(homeDir = os7.homedir()) {
5728
- const configPath = path13.join(homeDir, ".exe-os", "config.json");
5729
- if (!existsSync13(configPath)) return {};
5930
+ const configPath = path14.join(homeDir, ".exe-os", "config.json");
5931
+ if (!existsSync14(configPath)) return {};
5730
5932
  try {
5731
- const config = JSON.parse(readFileSync9(configPath, "utf-8"));
5933
+ const config = JSON.parse(readFileSync10(configPath, "utf-8"));
5732
5934
  return config.preferences ?? {};
5733
5935
  } catch {
5734
5936
  return {};
5735
5937
  }
5736
5938
  }
5737
5939
  function savePreferences(prefs, homeDir = os7.homedir()) {
5738
- const configDir = path13.join(homeDir, ".exe-os");
5739
- const configPath = path13.join(configDir, "config.json");
5940
+ const configDir = path14.join(homeDir, ".exe-os");
5941
+ const configPath = path14.join(configDir, "config.json");
5740
5942
  ensurePrivateDirSync(configDir);
5741
5943
  let config = {};
5742
- if (existsSync13(configPath)) {
5944
+ if (existsSync14(configPath)) {
5743
5945
  try {
5744
- config = JSON.parse(readFileSync9(configPath, "utf-8"));
5946
+ config = JSON.parse(readFileSync10(configPath, "utf-8"));
5745
5947
  } catch {
5746
5948
  config = {};
5747
5949
  }
5748
5950
  }
5749
5951
  config.preferences = prefs;
5750
- writeFileSync7(configPath, JSON.stringify(config, null, 2) + "\n");
5952
+ writeFileSync8(configPath, JSON.stringify(config, null, 2) + "\n");
5751
5953
  enforcePrivateFileSync(configPath);
5752
5954
  }
5753
5955
  var init_preferences = __esm({
@@ -5795,6 +5997,12 @@ var init_platform_procedures = __esm({
5795
5997
  priority: "p0",
5796
5998
  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."
5797
5999
  },
6000
+ {
6001
+ title: "Customer orchestration maturity \u2014 recommend, never trap",
6002
+ domain: "workflow",
6003
+ priority: "p1",
6004
+ 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."
6005
+ },
5798
6006
  {
5799
6007
  title: "Single dispatch path \u2014 create_task only",
5800
6008
  domain: "workflow",
@@ -5853,6 +6061,12 @@ var init_platform_procedures = __esm({
5853
6061
  priority: "p0",
5854
6062
  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."
5855
6063
  },
6064
+ {
6065
+ title: "Commit discipline \u2014 never leave verified work floating",
6066
+ domain: "workflow",
6067
+ priority: "p1",
6068
+ 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."
6069
+ },
5856
6070
  {
5857
6071
  title: "Desktop and TUI are the same product",
5858
6072
  domain: "architecture",
@@ -6620,17 +6834,17 @@ __export(identity_exports, {
6620
6834
  listIdentities: () => listIdentities,
6621
6835
  updateIdentity: () => updateIdentity
6622
6836
  });
6623
- import { existsSync as existsSync14, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
6837
+ import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
6624
6838
  import { readdirSync as readdirSync3 } from "fs";
6625
- import path14 from "path";
6839
+ import path15 from "path";
6626
6840
  import { createHash as createHash2 } from "crypto";
6627
6841
  function ensureDir() {
6628
- if (!existsSync14(IDENTITY_DIR2)) {
6629
- mkdirSync6(IDENTITY_DIR2, { recursive: true });
6842
+ if (!existsSync15(IDENTITY_DIR2)) {
6843
+ mkdirSync7(IDENTITY_DIR2, { recursive: true });
6630
6844
  }
6631
6845
  }
6632
6846
  function identityPath(agentId) {
6633
- return path14.join(IDENTITY_DIR2, `${agentId}.md`);
6847
+ return path15.join(IDENTITY_DIR2, `${agentId}.md`);
6634
6848
  }
6635
6849
  function sanitizeIdentityBody(body) {
6636
6850
  return body.replace(/<!--[\s\S]*?-->/g, "").trim();
@@ -6674,8 +6888,8 @@ function contentHash(content) {
6674
6888
  }
6675
6889
  function getIdentity(agentId) {
6676
6890
  const filePath = identityPath(agentId);
6677
- if (!existsSync14(filePath)) return null;
6678
- const raw = readFileSync10(filePath, "utf-8");
6891
+ if (!existsSync15(filePath)) return null;
6892
+ const raw = readFileSync11(filePath, "utf-8");
6679
6893
  const { frontmatter, body } = parseFrontmatter(raw);
6680
6894
  return {
6681
6895
  agentId,
@@ -6689,7 +6903,7 @@ async function updateIdentity(agentId, content, updatedBy) {
6689
6903
  ensureDir();
6690
6904
  const filePath = identityPath(agentId);
6691
6905
  const hash = contentHash(content);
6692
- writeFileSync8(filePath, content, "utf-8");
6906
+ writeFileSync9(filePath, content, "utf-8");
6693
6907
  try {
6694
6908
  const client = getClient();
6695
6909
  await client.execute({
@@ -6747,7 +6961,7 @@ var init_identity = __esm({
6747
6961
  "use strict";
6748
6962
  init_config();
6749
6963
  init_database();
6750
- IDENTITY_DIR2 = path14.join(EXE_AI_DIR, "identity");
6964
+ IDENTITY_DIR2 = path15.join(EXE_AI_DIR, "identity");
6751
6965
  }
6752
6966
  });
6753
6967
 
@@ -7298,36 +7512,36 @@ __export(session_wrappers_exports, {
7298
7512
  generateSessionWrappers: () => generateSessionWrappers
7299
7513
  });
7300
7514
  import {
7301
- existsSync as existsSync15,
7302
- readFileSync as readFileSync11,
7303
- writeFileSync as writeFileSync9,
7304
- mkdirSync as mkdirSync7,
7515
+ existsSync as existsSync16,
7516
+ readFileSync as readFileSync12,
7517
+ writeFileSync as writeFileSync10,
7518
+ mkdirSync as mkdirSync8,
7305
7519
  chmodSync as chmodSync2,
7306
7520
  readdirSync as readdirSync4,
7307
7521
  unlinkSync as unlinkSync7
7308
7522
  } from "fs";
7309
- import path15 from "path";
7523
+ import path16 from "path";
7310
7524
  import { homedir as homedir3 } from "os";
7311
7525
  function generateSessionWrappers(packageRoot, homeDir) {
7312
7526
  const home = homeDir ?? homedir3();
7313
- const binDir = path15.join(home, ".exe-os", "bin");
7314
- const rosterPath = path15.join(home, ".exe-os", "exe-employees.json");
7315
- mkdirSync7(binDir, { recursive: true });
7316
- const exeStartDst = path15.join(binDir, "exe-start");
7527
+ const binDir = path16.join(home, ".exe-os", "bin");
7528
+ const rosterPath = path16.join(home, ".exe-os", "exe-employees.json");
7529
+ mkdirSync8(binDir, { recursive: true });
7530
+ const exeStartDst = path16.join(binDir, "exe-start");
7317
7531
  const candidates = [
7318
- path15.join(packageRoot, "dist", "bin", "exe-start.sh"),
7319
- path15.join(packageRoot, "src", "bin", "exe-start.sh")
7532
+ path16.join(packageRoot, "dist", "bin", "exe-start.sh"),
7533
+ path16.join(packageRoot, "src", "bin", "exe-start.sh")
7320
7534
  ];
7321
7535
  for (const src of candidates) {
7322
- if (existsSync15(src)) {
7323
- writeFileSync9(exeStartDst, readFileSync11(src));
7536
+ if (existsSync16(src)) {
7537
+ writeFileSync10(exeStartDst, readFileSync12(src));
7324
7538
  chmodSync2(exeStartDst, 493);
7325
7539
  break;
7326
7540
  }
7327
7541
  }
7328
7542
  let employees = [];
7329
7543
  try {
7330
- employees = JSON.parse(readFileSync11(rosterPath, "utf8"));
7544
+ employees = JSON.parse(readFileSync12(rosterPath, "utf8"));
7331
7545
  } catch {
7332
7546
  return { created: 0, pathConfigured: false };
7333
7547
  }
@@ -7337,9 +7551,9 @@ function generateSessionWrappers(packageRoot, homeDir) {
7337
7551
  try {
7338
7552
  for (const f of readdirSync4(binDir)) {
7339
7553
  if (f === "exe-start") continue;
7340
- const fPath = path15.join(binDir, f);
7554
+ const fPath = path16.join(binDir, f);
7341
7555
  try {
7342
- const content = readFileSync11(fPath, "utf8");
7556
+ const content = readFileSync12(fPath, "utf8");
7343
7557
  if (content.includes("exe-start")) {
7344
7558
  unlinkSync7(fPath);
7345
7559
  }
@@ -7354,34 +7568,34 @@ exec "${exeStartDst}" "$0" "$@"
7354
7568
  `;
7355
7569
  for (const emp of employees) {
7356
7570
  for (let n = 1; n <= MAX_N; n++) {
7357
- const wrapperPath = path15.join(binDir, `${emp.name}${n}`);
7358
- writeFileSync9(wrapperPath, wrapperContent);
7571
+ const wrapperPath = path16.join(binDir, `${emp.name}${n}`);
7572
+ writeFileSync10(wrapperPath, wrapperContent);
7359
7573
  chmodSync2(wrapperPath, 493);
7360
7574
  created++;
7361
- const codexPath = path15.join(binDir, `${emp.name}${n}-codex`);
7362
- writeFileSync9(codexPath, wrapperContent);
7575
+ const codexPath = path16.join(binDir, `${emp.name}${n}-codex`);
7576
+ writeFileSync10(codexPath, wrapperContent);
7363
7577
  chmodSync2(codexPath, 493);
7364
7578
  created++;
7365
7579
  }
7366
7580
  }
7367
7581
  const codexLauncherCandidates = [
7368
- path15.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
7369
- path15.join(packageRoot, "src", "bin", "exe-start-codex.ts")
7582
+ path16.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
7583
+ path16.join(packageRoot, "src", "bin", "exe-start-codex.ts")
7370
7584
  ];
7371
7585
  let codexLauncher = null;
7372
7586
  for (const c of codexLauncherCandidates) {
7373
- if (existsSync15(c)) {
7587
+ if (existsSync16(c)) {
7374
7588
  codexLauncher = c;
7375
7589
  break;
7376
7590
  }
7377
7591
  }
7378
7592
  if (codexLauncher) {
7379
7593
  for (const emp of employees) {
7380
- const wrapperPath = path15.join(binDir, `${emp.name}-codex`);
7594
+ const wrapperPath = path16.join(binDir, `${emp.name}-codex`);
7381
7595
  const content = `#!/bin/bash
7382
7596
  exec node "${codexLauncher}" --agent ${emp.name} "$@"
7383
7597
  `;
7384
- writeFileSync9(wrapperPath, content);
7598
+ writeFileSync10(wrapperPath, content);
7385
7599
  chmodSync2(wrapperPath, 493);
7386
7600
  created++;
7387
7601
  }
@@ -7400,24 +7614,24 @@ export PATH="${binDir}:$PATH"
7400
7614
  const shell = process.env.SHELL ?? "/bin/bash";
7401
7615
  const profilePaths = [];
7402
7616
  if (shell.includes("zsh")) {
7403
- profilePaths.push(path15.join(home, ".zshrc"));
7617
+ profilePaths.push(path16.join(home, ".zshrc"));
7404
7618
  } else if (shell.includes("bash")) {
7405
- profilePaths.push(path15.join(home, ".bashrc"));
7406
- profilePaths.push(path15.join(home, ".bash_profile"));
7619
+ profilePaths.push(path16.join(home, ".bashrc"));
7620
+ profilePaths.push(path16.join(home, ".bash_profile"));
7407
7621
  } else {
7408
- profilePaths.push(path15.join(home, ".profile"));
7622
+ profilePaths.push(path16.join(home, ".profile"));
7409
7623
  }
7410
7624
  for (const profilePath of profilePaths) {
7411
7625
  try {
7412
7626
  let content = "";
7413
7627
  try {
7414
- content = readFileSync11(profilePath, "utf8");
7628
+ content = readFileSync12(profilePath, "utf8");
7415
7629
  } catch {
7416
7630
  }
7417
7631
  if (content.includes(".exe-os/bin")) {
7418
7632
  return false;
7419
7633
  }
7420
- writeFileSync9(profilePath, content + exportLine);
7634
+ writeFileSync10(profilePath, content + exportLine);
7421
7635
  return true;
7422
7636
  } catch {
7423
7637
  continue;
@@ -7437,9 +7651,9 @@ var init_session_wrappers = __esm({
7437
7651
  init_config();
7438
7652
  init_keychain();
7439
7653
  import crypto4 from "crypto";
7440
- import { existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync10, unlinkSync as unlinkSync8 } from "fs";
7654
+ import { existsSync as existsSync17, mkdirSync as mkdirSync9, readFileSync as readFileSync13, writeFileSync as writeFileSync11, unlinkSync as unlinkSync8 } from "fs";
7441
7655
  import os8 from "os";
7442
- import path16 from "path";
7656
+ import path17 from "path";
7443
7657
  import { createInterface } from "readline";
7444
7658
 
7445
7659
  // src/lib/model-downloader.ts
@@ -7531,32 +7745,32 @@ async function fileHash(filePath) {
7531
7745
 
7532
7746
  // src/lib/setup-wizard.ts
7533
7747
  function findPackageRoot2() {
7534
- let dir = path16.dirname(new URL(import.meta.url).pathname);
7535
- const root = path16.parse(dir).root;
7748
+ let dir = path17.dirname(new URL(import.meta.url).pathname);
7749
+ const root = path17.parse(dir).root;
7536
7750
  while (dir !== root) {
7537
- const pkgPath = path16.join(dir, "package.json");
7538
- if (existsSync16(pkgPath)) {
7751
+ const pkgPath = path17.join(dir, "package.json");
7752
+ if (existsSync17(pkgPath)) {
7539
7753
  try {
7540
- const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
7754
+ const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
7541
7755
  if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
7542
7756
  } catch {
7543
7757
  }
7544
7758
  }
7545
- dir = path16.dirname(dir);
7759
+ dir = path17.dirname(dir);
7546
7760
  }
7547
7761
  return null;
7548
7762
  }
7549
- var SETUP_STATE_PATH = path16.join(os8.homedir(), ".exe-os", "setup-state.json");
7763
+ var SETUP_STATE_PATH = path17.join(os8.homedir(), ".exe-os", "setup-state.json");
7550
7764
  function loadSetupState() {
7551
7765
  try {
7552
- return JSON.parse(readFileSync12(SETUP_STATE_PATH, "utf8"));
7766
+ return JSON.parse(readFileSync13(SETUP_STATE_PATH, "utf8"));
7553
7767
  } catch {
7554
7768
  return { completedSteps: [], startedAt: (/* @__PURE__ */ new Date()).toISOString() };
7555
7769
  }
7556
7770
  }
7557
7771
  function saveSetupState(state) {
7558
- mkdirSync8(path16.dirname(SETUP_STATE_PATH), { recursive: true });
7559
- writeFileSync10(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
7772
+ mkdirSync9(path17.dirname(SETUP_STATE_PATH), { recursive: true });
7773
+ writeFileSync11(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
7560
7774
  }
7561
7775
  function clearSetupState() {
7562
7776
  try {
@@ -7606,8 +7820,8 @@ async function validateModel(log) {
7606
7820
  if (totalGB <= 8 || isLowMemory()) {
7607
7821
  log(`System memory: ${totalGB.toFixed(0)}GB total, ${freeGB.toFixed(1)}GB free`);
7608
7822
  log("Skipping in-memory model validation (low memory \u2014 will validate on first use).");
7609
- const modelPath = path16.join(MODELS_DIR, LOCAL_FILENAME);
7610
- if (existsSync16(modelPath)) {
7823
+ const modelPath = path17.join(MODELS_DIR, LOCAL_FILENAME);
7824
+ if (existsSync17(modelPath)) {
7611
7825
  const { statSync: statSync4 } = await import("fs");
7612
7826
  const size = statSync4(modelPath).size;
7613
7827
  if (size > 300 * 1e6) {
@@ -7638,10 +7852,10 @@ async function runSetupWizard(opts = {}) {
7638
7852
  log("");
7639
7853
  log("=== exe-os Setup ===");
7640
7854
  log("");
7641
- log("Is this a new installation or pairing with an existing device?");
7855
+ log("What are you setting up?");
7642
7856
  log("");
7643
- log(" [1] New installation (first device)");
7644
- log(" [2] Pair with existing device (I have a 24-word phrase)");
7857
+ log(" [1] First device / brand new Exe OS memory");
7858
+ log(" [2] Another device / I already have a 24-word recovery phrase");
7645
7859
  log("");
7646
7860
  const installType = await ask(rl, "Choice (1/2): ");
7647
7861
  let isPairing = false;
@@ -7650,16 +7864,20 @@ async function runSetupWizard(opts = {}) {
7650
7864
  isPairing = true;
7651
7865
  log("");
7652
7866
  const { importMnemonic: importMnemonic2 } = await Promise.resolve().then(() => (init_keychain(), keychain_exports));
7653
- const mnemonic = await ask(rl, "Paste your 24-word recovery phrase: ");
7867
+ log("On your existing device, open Terminal and run:");
7868
+ log(" exe-os cloud link --show-full");
7869
+ log("Then copy the 24-word phrase here.");
7870
+ log("");
7871
+ const mnemonic = await ask(rl, "Paste the 24-word recovery phrase: ");
7654
7872
  try {
7655
7873
  const key = await importMnemonic2(mnemonic);
7656
7874
  await setMasterKey(key);
7657
7875
  log("Master key imported and stored securely.");
7658
7876
  log("");
7659
- log("Enter the API key from your existing device.");
7660
- log("(Find it in ~/.exe-os/config.json under cloud.apiKey, or ask your team lead.)");
7877
+ log("Now paste the Cloud API key from that same `exe-os cloud link --show-full` output.");
7878
+ log("It starts with: exe_sk_");
7661
7879
  log("");
7662
- const apiKey = await ask(rl, "API key (exe_sk_...): ");
7880
+ const apiKey = await ask(rl, "Cloud API key (starts with exe_sk_): ");
7663
7881
  if (apiKey && apiKey.startsWith("exe_sk_")) {
7664
7882
  const cloudEndpoint = "https://askexe.com/cloud";
7665
7883
  const cloudCfg = { apiKey, endpoint: cloudEndpoint };
@@ -7698,7 +7916,7 @@ async function runSetupWizard(opts = {}) {
7698
7916
  if (state.completedSteps.length > 0) {
7699
7917
  log(`Resuming setup from step ${Math.max(...state.completedSteps) + 1}...`);
7700
7918
  }
7701
- if (existsSync16(LEGACY_LANCE_PATH)) {
7919
+ if (existsSync17(LEGACY_LANCE_PATH)) {
7702
7920
  log("\u26A0 Found v1.0 LanceDB at ~/.exe-os/local.lance");
7703
7921
  log(" v1.1 uses libSQL (SQLite). Your existing memories are not automatically migrated.");
7704
7922
  log(" The old directory will not be modified or deleted.");
@@ -7722,14 +7940,22 @@ async function runSetupWizard(opts = {}) {
7722
7940
  log("");
7723
7941
  log(" " + mnemonic);
7724
7942
  log("");
7725
- log(" SAVE THIS NOW. Write it down or store it in your password");
7726
- log(" manager. This phrase is the ONLY way to decrypt your memories");
7727
- log(" if you lose this computer. We cannot recover it for you.");
7943
+ log(" SAVE THIS NOW before continuing.");
7944
+ log(" Best: put it in your password manager, or write it down and keep it safe.");
7945
+ log(" This phrase is the ONLY way to decrypt your memories if you lose this computer.");
7946
+ log(" We cannot recover it for you.");
7728
7947
  log("");
7729
7948
  log(" Like a Bitcoin wallet \u2014 lose the phrase, lose everything.");
7730
7949
  log("=============================================================");
7731
7950
  log("");
7732
- await ask(rl, "Press Enter after you've saved your recovery phrase...");
7951
+ const confirmation = await ask(rl, 'Type "I SAVED MY RECOVERY PHRASE" after you have saved it: ');
7952
+ if (confirmation !== "I SAVED MY RECOVERY PHRASE") {
7953
+ throw new Error(
7954
+ "Setup cancelled: recovery phrase was not confirmed. Save the 24-word phrase before continuing \u2014 it is required to recover encrypted memories."
7955
+ );
7956
+ }
7957
+ const { markKeyBackupConfirmed: markKeyBackupConfirmed2 } = await Promise.resolve().then(() => (init_key_backup_status(), key_backup_status_exports));
7958
+ markKeyBackupConfirmed2("setup-wizard");
7733
7959
  }
7734
7960
  state.completedSteps.push(1);
7735
7961
  saveSetupState(state);
@@ -7876,13 +8102,15 @@ async function runSetupWizard(opts = {}) {
7876
8102
  if (cloudConfig) {
7877
8103
  config.cloud = cloudConfig;
7878
8104
  }
8105
+ const { applyDefaultOrchestrationPhase: applyDefaultOrchestrationPhase2 } = await Promise.resolve().then(() => (init_orchestration_phase(), orchestration_phase_exports));
8106
+ applyDefaultOrchestrationPhase2(config);
7879
8107
  await saveConfig(config);
7880
8108
  log("");
7881
8109
  try {
7882
- const claudeJsonPath = path16.join(os8.homedir(), ".claude.json");
8110
+ const claudeJsonPath = path17.join(os8.homedir(), ".claude.json");
7883
8111
  let claudeJson = {};
7884
8112
  try {
7885
- claudeJson = JSON.parse(readFileSync12(claudeJsonPath, "utf8"));
8113
+ claudeJson = JSON.parse(readFileSync13(claudeJsonPath, "utf8"));
7886
8114
  } catch {
7887
8115
  }
7888
8116
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -7891,7 +8119,7 @@ async function runSetupWizard(opts = {}) {
7891
8119
  if (!projects[dir]) projects[dir] = {};
7892
8120
  projects[dir].hasTrustDialogAccepted = true;
7893
8121
  }
7894
- writeFileSync10(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
8122
+ writeFileSync11(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
7895
8123
  } catch {
7896
8124
  }
7897
8125
  state.completedSteps.push(5);
@@ -7905,7 +8133,7 @@ async function runSetupWizard(opts = {}) {
7905
8133
  const prefs = { ...existingPrefs };
7906
8134
  log("=== Config Defaults ===");
7907
8135
  log("");
7908
- const ghosttyDetected = existsSync16(path16.join(os8.homedir(), ".config", "ghostty")) || existsSync16(path16.join(os8.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
8136
+ const ghosttyDetected = existsSync17(path17.join(os8.homedir(), ".config", "ghostty")) || existsSync17(path17.join(os8.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
7909
8137
  if (ghosttyDetected) {
7910
8138
  const ghosttyAnswer = await ask(rl, "Detected Ghostty terminal. Use exe-os Ghostty defaults? (Y/n) ");
7911
8139
  prefs.ghostty = ghosttyAnswer.toLowerCase() !== "n";
@@ -7952,7 +8180,7 @@ async function runSetupWizard(opts = {}) {
7952
8180
  let missingIdentities = [];
7953
8181
  for (const emp of roster) {
7954
8182
  const idPath = identityPath2(emp.name);
7955
- if (!existsSync16(idPath)) {
8183
+ if (!existsSync17(idPath)) {
7956
8184
  missingIdentities.push(emp.name);
7957
8185
  }
7958
8186
  }
@@ -7984,7 +8212,7 @@ async function runSetupWizard(opts = {}) {
7984
8212
  }
7985
8213
  missingIdentities = [];
7986
8214
  for (const emp of roster) {
7987
- if (!existsSync16(identityPath2(emp.name))) {
8215
+ if (!existsSync17(identityPath2(emp.name))) {
7988
8216
  missingIdentities.push(emp.name);
7989
8217
  }
7990
8218
  }
@@ -8043,9 +8271,9 @@ async function runSetupWizard(opts = {}) {
8043
8271
  const cooIdentityContent = getIdentityTemplate("coo");
8044
8272
  if (cooIdentityContent) {
8045
8273
  const cooIdPath = identityPath2(cooName);
8046
- mkdirSync8(path16.dirname(cooIdPath), { recursive: true });
8274
+ mkdirSync9(path17.dirname(cooIdPath), { recursive: true });
8047
8275
  const replaced = cooIdentityContent.replace(/agent_id:\s*exe/g, `agent_id: ${cooName}`).replace(/\$\{agent_id\}/g, cooName);
8048
- writeFileSync10(cooIdPath, replaced, "utf-8");
8276
+ writeFileSync11(cooIdPath, replaced, "utf-8");
8049
8277
  }
8050
8278
  registerBinSymlinks2(cooName);
8051
8279
  createdEmployees.push({ name: cooName, role: "COO" });
@@ -8096,7 +8324,8 @@ async function runSetupWizard(opts = {}) {
8096
8324
  }
8097
8325
  if (!isLicensed) {
8098
8326
  log("");
8099
- log("You're all set. Your COO handles everything from here.");
8327
+ log("You're all set. You're starting in Phase 1: COO / Chief of Staff mode.");
8328
+ log("Your COO will learn your company context first. You can unlock executives later anytime.");
8100
8329
  log("When you're ready for specialists, add a license key at askexe.com.");
8101
8330
  log("");
8102
8331
  log(`Type your COO's name to start: /${cooName}`);
@@ -8111,67 +8340,89 @@ async function runSetupWizard(opts = {}) {
8111
8340
  }
8112
8341
  if (!state.completedSteps.includes(8)) {
8113
8342
  let employees = await loadEmployees2(EMPLOYEES_PATH2).catch(() => []);
8114
- log("=== Hire Your Team ===");
8343
+ log("=== Orchestration Phase ===");
8115
8344
  log("");
8116
- log("Your COO coordinates specialists. Each one stays focused on");
8117
- log("their domain \u2014 no context switching, no competing priorities.");
8345
+ log("Recommended default: Phase 1 \u2014 COO / Chief of Staff mode.");
8346
+ log("Start with one-on-one conversations so your COO learns your company,");
8347
+ log("vision, priorities, constraints, and operating style before delegating.");
8118
8348
  log("");
8119
- const ctoTemplate = getTemplateByRole2("CTO");
8120
- const ctoDefault = ctoTemplate?.name ?? "cto";
8121
- log(` CTO \u2014 engineering, architecture, code reviews (default: ${ctoDefault})`);
8122
- const cmoTemplate = getTemplateByRole2("CMO");
8123
- const cmoDefault = cmoTemplate?.name ?? "cmo";
8124
- log(` CMO \u2014 design, brand, content, marketing (default: ${cmoDefault})`);
8349
+ log("You can jump ahead now if you want. This is a suggestion, not a blocker.");
8125
8350
  log("");
8126
- const ctoNameInput = await ask(rl, `Name your CTO (default: ${ctoDefault}): `);
8127
- const ctoName = (ctoNameInput || ctoDefault).toLowerCase();
8128
- if (!employees.some((e) => e.name === ctoName)) {
8129
- const ctoEmployee = {
8130
- name: ctoName,
8131
- role: "CTO",
8132
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
8133
- templateName: ctoDefault,
8134
- templateVersion: 1
8135
- };
8136
- employees = addEmployee2(employees, ctoEmployee);
8137
- await saveEmployees2(employees, EMPLOYEES_PATH2);
8138
- }
8139
- const ctoIdentityContent = getIdentityTemplate("cto");
8140
- if (ctoIdentityContent) {
8141
- const ctoIdPath = identityPath2(ctoName);
8142
- mkdirSync8(path16.dirname(ctoIdPath), { recursive: true });
8143
- const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
8144
- writeFileSync10(ctoIdPath, replaced, "utf-8");
8145
- }
8146
- registerBinSymlinks2(ctoName);
8147
- createdEmployees.push({ name: ctoName, role: "CTO" });
8148
- log(`Created ${ctoName} (CTO)`);
8149
- const cmoNameInput = await ask(rl, `Name your CMO (default: ${cmoDefault}): `);
8150
- const cmoName = (cmoNameInput || cmoDefault).toLowerCase();
8151
- if (!employees.some((e) => e.name === cmoName)) {
8152
- const cmoEmployee = {
8153
- name: cmoName,
8154
- role: "CMO",
8155
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
8156
- templateName: cmoDefault,
8157
- templateVersion: 1
8158
- };
8159
- employees = addEmployee2(employees, cmoEmployee);
8160
- await saveEmployees2(employees, EMPLOYEES_PATH2);
8161
- }
8162
- const cmoIdentityContent = getIdentityTemplate("cmo");
8163
- if (cmoIdentityContent) {
8164
- const cmoIdPath = identityPath2(cmoName);
8165
- mkdirSync8(path16.dirname(cmoIdPath), { recursive: true });
8166
- const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
8167
- writeFileSync10(cmoIdPath, replaced, "utf-8");
8168
- }
8169
- registerBinSymlinks2(cmoName);
8170
- createdEmployees.push({ name: cmoName, role: "CMO" });
8171
- log(`Created ${cmoName} (CMO)`);
8351
+ log(" Phase 1: COO only \u2014 build company context first");
8352
+ log(" Phase 2: Executive bench \u2014 add CTO/CMO for repeated domain work");
8353
+ log(" Phase 3: Parallel org \u2014 specialists execute in parallel with reviews");
8172
8354
  log("");
8173
- state.completedSteps.push(8);
8174
- saveSetupState(state);
8355
+ const unlockExecutives = (await ask(rl, "Unlock Phase 2 executives now? (y/N): ")).toLowerCase() === "y";
8356
+ const { setOrchestrationPhase: setOrchestrationPhase2 } = await Promise.resolve().then(() => (init_orchestration_phase(), orchestration_phase_exports));
8357
+ if (!unlockExecutives) {
8358
+ await setOrchestrationPhase2("phase_1_coo", "setup-wizard");
8359
+ log("");
8360
+ log("Starting in Phase 1. Your executive templates are available when you're ready.");
8361
+ log("Later: run `exe-os org unlock executives` to move to Phase 2.");
8362
+ state.completedSteps.push(8);
8363
+ saveSetupState(state);
8364
+ } else {
8365
+ await setOrchestrationPhase2("phase_2_executives", "setup-wizard");
8366
+ log("");
8367
+ log("Phase 2 enabled. Let's name your executive bench.");
8368
+ log("");
8369
+ const ctoTemplate = getTemplateByRole2("CTO");
8370
+ const ctoDefault = ctoTemplate?.name ?? "cto";
8371
+ log(` CTO \u2014 engineering, architecture, code reviews (default: ${ctoDefault})`);
8372
+ const cmoTemplate = getTemplateByRole2("CMO");
8373
+ const cmoDefault = cmoTemplate?.name ?? "cmo";
8374
+ log(` CMO \u2014 design, brand, content, marketing (default: ${cmoDefault})`);
8375
+ log("");
8376
+ const ctoNameInput = await ask(rl, `Name your CTO (default: ${ctoDefault}): `);
8377
+ const ctoName = (ctoNameInput || ctoDefault).toLowerCase();
8378
+ if (!employees.some((e) => e.name === ctoName)) {
8379
+ const ctoEmployee = {
8380
+ name: ctoName,
8381
+ role: "CTO",
8382
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
8383
+ templateName: ctoDefault,
8384
+ templateVersion: 1
8385
+ };
8386
+ employees = addEmployee2(employees, ctoEmployee);
8387
+ await saveEmployees2(employees, EMPLOYEES_PATH2);
8388
+ }
8389
+ const ctoIdentityContent = getIdentityTemplate("cto");
8390
+ if (ctoIdentityContent) {
8391
+ const ctoIdPath = identityPath2(ctoName);
8392
+ mkdirSync9(path17.dirname(ctoIdPath), { recursive: true });
8393
+ const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
8394
+ writeFileSync11(ctoIdPath, replaced, "utf-8");
8395
+ }
8396
+ registerBinSymlinks2(ctoName);
8397
+ createdEmployees.push({ name: ctoName, role: "CTO" });
8398
+ log(`Created ${ctoName} (CTO)`);
8399
+ const cmoNameInput = await ask(rl, `Name your CMO (default: ${cmoDefault}): `);
8400
+ const cmoName = (cmoNameInput || cmoDefault).toLowerCase();
8401
+ if (!employees.some((e) => e.name === cmoName)) {
8402
+ const cmoEmployee = {
8403
+ name: cmoName,
8404
+ role: "CMO",
8405
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
8406
+ templateName: cmoDefault,
8407
+ templateVersion: 1
8408
+ };
8409
+ employees = addEmployee2(employees, cmoEmployee);
8410
+ await saveEmployees2(employees, EMPLOYEES_PATH2);
8411
+ }
8412
+ const cmoIdentityContent = getIdentityTemplate("cmo");
8413
+ if (cmoIdentityContent) {
8414
+ const cmoIdPath = identityPath2(cmoName);
8415
+ mkdirSync9(path17.dirname(cmoIdPath), { recursive: true });
8416
+ const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
8417
+ writeFileSync11(cmoIdPath, replaced, "utf-8");
8418
+ }
8419
+ registerBinSymlinks2(cmoName);
8420
+ createdEmployees.push({ name: cmoName, role: "CMO" });
8421
+ log(`Created ${cmoName} (CMO)`);
8422
+ log("");
8423
+ state.completedSteps.push(8);
8424
+ saveSetupState(state);
8425
+ }
8175
8426
  } else {
8176
8427
  log("Step 8 already complete \u2014 skipping.");
8177
8428
  }
@@ -8186,7 +8437,7 @@ async function runSetupWizard(opts = {}) {
8186
8437
  log(`Session shortcuts generated (${cooName}1, ${cooName}2, ...)`);
8187
8438
  }
8188
8439
  if (wrapResult.pathConfigured) {
8189
- const binDir = path16.join(os8.homedir(), ".exe-os", "bin");
8440
+ const binDir = path17.join(os8.homedir(), ".exe-os", "bin");
8190
8441
  process.env.PATH = `${binDir}:${process.env.PATH ?? ""}`;
8191
8442
  pathJustConfigured = true;
8192
8443
  }
@@ -8229,7 +8480,7 @@ async function runSetupWizard(opts = {}) {
8229
8480
  const pkgRoot2 = findPackageRoot2();
8230
8481
  if (pkgRoot2) {
8231
8482
  try {
8232
- version = JSON.parse(readFileSync12(path16.join(pkgRoot2, "package.json"), "utf-8")).version;
8483
+ version = JSON.parse(readFileSync13(path17.join(pkgRoot2, "package.json"), "utf-8")).version;
8233
8484
  } catch {
8234
8485
  }
8235
8486
  }
@@ -8243,6 +8494,10 @@ async function runSetupWizard(opts = {}) {
8243
8494
  log("");
8244
8495
  log("=== Next Steps ===");
8245
8496
  log("");
8497
+ log(" Recommended start: Phase 1 \u2014 talk to your COO first");
8498
+ log(" Check/change phase: exe-os org phase");
8499
+ log(" Unlock executives later: exe-os org unlock executives");
8500
+ log("");
8246
8501
  log(` cd into a project folder: cd ~/my-project`);
8247
8502
  log(` Launch your COO: ${cooName}1`);
8248
8503
  if (pathJustConfigured) {