@askexenow/exe-os 0.9.93 → 0.9.94

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 (88) hide show
  1. package/deploy/compose/docker-compose.yml +1 -0
  2. package/dist/bin/agentic-ontology-backfill.js +65 -8
  3. package/dist/bin/agentic-reflection-backfill.js +54 -3
  4. package/dist/bin/agentic-semantic-label.js +54 -3
  5. package/dist/bin/backfill-conversations.js +69 -9
  6. package/dist/bin/backfill-responses.js +69 -9
  7. package/dist/bin/backfill-vectors.js +54 -3
  8. package/dist/bin/bulk-sync-postgres.js +66 -8
  9. package/dist/bin/cleanup-stale-review-tasks.js +118 -13
  10. package/dist/bin/cli.js +1558 -466
  11. package/dist/bin/customer-readiness.js +51 -0
  12. package/dist/bin/exe-agent.js +17 -3
  13. package/dist/bin/exe-assign.js +75 -9
  14. package/dist/bin/exe-boot.js +111 -12
  15. package/dist/bin/exe-call.js +17 -3
  16. package/dist/bin/exe-cloud.js +76 -10
  17. package/dist/bin/exe-dispatch.js +133 -18
  18. package/dist/bin/exe-doctor.js +75 -9
  19. package/dist/bin/exe-export-behaviors.js +75 -9
  20. package/dist/bin/exe-forget.js +94 -9
  21. package/dist/bin/exe-gateway.js +132 -18
  22. package/dist/bin/exe-heartbeat.js +118 -13
  23. package/dist/bin/exe-kill.js +75 -9
  24. package/dist/bin/exe-launch-agent.js +75 -9
  25. package/dist/bin/exe-new-employee.js +18 -4
  26. package/dist/bin/exe-pending-messages.js +118 -13
  27. package/dist/bin/exe-pending-notifications.js +118 -13
  28. package/dist/bin/exe-pending-reviews.js +118 -13
  29. package/dist/bin/exe-rename.js +75 -9
  30. package/dist/bin/exe-review.js +75 -9
  31. package/dist/bin/exe-search.js +100 -9
  32. package/dist/bin/exe-session-cleanup.js +133 -18
  33. package/dist/bin/exe-settings.js +1 -0
  34. package/dist/bin/exe-start-codex.js +65 -8
  35. package/dist/bin/exe-start-opencode.js +65 -8
  36. package/dist/bin/exe-status.js +118 -13
  37. package/dist/bin/exe-support.js +1 -0
  38. package/dist/bin/exe-team.js +75 -9
  39. package/dist/bin/git-sweep.js +133 -18
  40. package/dist/bin/graph-backfill.js +65 -8
  41. package/dist/bin/graph-export.js +75 -9
  42. package/dist/bin/intercom-check.js +133 -18
  43. package/dist/bin/scan-tasks.js +133 -18
  44. package/dist/bin/setup.js +55 -4
  45. package/dist/bin/shard-migrate.js +65 -8
  46. package/dist/bin/stack-update.js +5 -6
  47. package/dist/bin/update.js +1 -1
  48. package/dist/gateway/index.js +133 -18
  49. package/dist/hooks/bug-report-worker.js +133 -18
  50. package/dist/hooks/codex-stop-task-finalizer.js +123 -14
  51. package/dist/hooks/commit-complete.js +133 -18
  52. package/dist/hooks/error-recall.js +100 -9
  53. package/dist/hooks/ingest.js +75 -9
  54. package/dist/hooks/instructions-loaded.js +75 -9
  55. package/dist/hooks/notification.js +75 -9
  56. package/dist/hooks/post-compact.js +310 -50
  57. package/dist/hooks/post-tool-combined.js +433 -13
  58. package/dist/hooks/pre-compact.js +133 -18
  59. package/dist/hooks/pre-tool-use.js +118 -13
  60. package/dist/hooks/prompt-submit.js +191 -19
  61. package/dist/hooks/session-end.js +133 -18
  62. package/dist/hooks/session-start.js +143 -13
  63. package/dist/hooks/stop.js +118 -13
  64. package/dist/hooks/subagent-stop.js +118 -13
  65. package/dist/hooks/summary-worker.js +96 -7
  66. package/dist/index.js +133 -18
  67. package/dist/lib/cloud-sync.js +38 -0
  68. package/dist/lib/consolidation.js +3 -1
  69. package/dist/lib/database.js +37 -0
  70. package/dist/lib/db.js +37 -0
  71. package/dist/lib/device-registry.js +37 -0
  72. package/dist/lib/employee-templates.js +17 -3
  73. package/dist/lib/exe-daemon.js +913 -42
  74. package/dist/lib/hybrid-search.js +100 -9
  75. package/dist/lib/license.js +1 -1
  76. package/dist/lib/messaging.js +40 -4
  77. package/dist/lib/schedules.js +54 -3
  78. package/dist/lib/store.js +75 -9
  79. package/dist/lib/tasks.js +58 -9
  80. package/dist/lib/tmux-routing.js +58 -9
  81. package/dist/mcp/server.js +875 -42
  82. package/dist/mcp/tools/create-task.js +67 -12
  83. package/dist/mcp/tools/list-tasks.js +46 -5
  84. package/dist/mcp/tools/send-message.js +40 -4
  85. package/dist/mcp/tools/update-task.js +58 -9
  86. package/dist/runtime/index.js +133 -18
  87. package/dist/tui/App.js +132 -18
  88. package/package.json +1 -1
package/dist/bin/cli.js CHANGED
@@ -2660,8 +2660,8 @@ function deriveMachineKey() {
2660
2660
  }
2661
2661
  function readMachineId() {
2662
2662
  try {
2663
- const { readFileSync: readFileSync37 } = __require("fs");
2664
- return readFileSync37("/etc/machine-id", "utf-8").trim();
2663
+ const { readFileSync: readFileSync39 } = __require("fs");
2664
+ return readFileSync39("/etc/machine-id", "utf-8").trim();
2665
2665
  } catch {
2666
2666
  return "";
2667
2667
  }
@@ -3751,8 +3751,8 @@ function findPackageRoot() {
3751
3751
  function getAvailableMemoryGB() {
3752
3752
  if (process.platform === "darwin") {
3753
3753
  try {
3754
- const { execSync: execSync19 } = __require("child_process");
3755
- const vmstat = execSync19("vm_stat", { encoding: "utf8" });
3754
+ const { execSync: execSync20 } = __require("child_process");
3755
+ const vmstat = execSync20("vm_stat", { encoding: "utf8" });
3756
3756
  const pageSize = 16384;
3757
3757
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
3758
3758
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -5412,6 +5412,20 @@ async function ensureSchema() {
5412
5412
  });
5413
5413
  } catch {
5414
5414
  }
5415
+ try {
5416
+ await client.execute({
5417
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
5418
+ args: []
5419
+ });
5420
+ } catch {
5421
+ }
5422
+ try {
5423
+ await client.execute({
5424
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
5425
+ args: []
5426
+ });
5427
+ } catch {
5428
+ }
5415
5429
  await client.executeMultiple(`
5416
5430
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
5417
5431
  content_text,
@@ -5663,6 +5677,22 @@ async function ensureSchema() {
5663
5677
  );
5664
5678
  } catch {
5665
5679
  }
5680
+ for (const col of [
5681
+ "ALTER TABLE memories ADD COLUMN valid_from TEXT",
5682
+ "ALTER TABLE memories ADD COLUMN invalid_at TEXT"
5683
+ ]) {
5684
+ try {
5685
+ await client.execute(col);
5686
+ } catch {
5687
+ }
5688
+ }
5689
+ try {
5690
+ await client.execute({
5691
+ sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
5692
+ args: []
5693
+ });
5694
+ } catch {
5695
+ }
5666
5696
  try {
5667
5697
  await client.execute({
5668
5698
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
@@ -5705,6 +5735,13 @@ async function ensureSchema() {
5705
5735
  } catch {
5706
5736
  }
5707
5737
  }
5738
+ try {
5739
+ await client.execute({
5740
+ sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
5741
+ args: []
5742
+ });
5743
+ } catch {
5744
+ }
5708
5745
  try {
5709
5746
  await client.execute({
5710
5747
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
@@ -6146,8 +6183,8 @@ async function validateLicense(apiKey, deviceId) {
6146
6183
  }
6147
6184
  function getCacheAgeMs() {
6148
6185
  try {
6149
- const { statSync: statSync8 } = __require("fs");
6150
- const s = statSync8(CACHE_PATH);
6186
+ const { statSync: statSync9 } = __require("fs");
6187
+ const s = statSync9(CACHE_PATH);
6151
6188
  return Date.now() - s.mtimeMs;
6152
6189
  } catch {
6153
6190
  return Infinity;
@@ -6321,7 +6358,7 @@ var init_license = __esm({
6321
6358
  LICENSE_PATH = path13.join(EXE_AI_DIR, "license.key");
6322
6359
  CACHE_PATH = path13.join(EXE_AI_DIR, "license-cache.json");
6323
6360
  DEVICE_ID_PATH = path13.join(EXE_AI_DIR, "device-id");
6324
- API_BASE = "https://askexe.com/cloud";
6361
+ API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
6325
6362
  RETRY_DELAY_MS = 500;
6326
6363
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
6327
6364
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
@@ -8894,6 +8931,20 @@ var init_platform_procedures = __esm({
8894
8931
  priority: "p1",
8895
8932
  content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
8896
8933
  },
8934
+ // --- Tool guidance ---
8935
+ {
8936
+ title: "How to use company_actions \u2014 execute business actions through gateway connectors",
8937
+ domain: "tools",
8938
+ priority: "p2",
8939
+ content: "The company_actions tool executes business actions through gateway connectors (e.g. send WhatsApp, trigger workflows, update CRM). It routes through the exe-gateway on the VPS. Actions are defined by the customer's gateway configuration \u2014 each connector (WhatsApp, Shopify, email, etc.) exposes specific actions. Use query_company_brain to find available data first, then company_actions to act on it. Requires gateway auth token. Read-only founders should NOT use this \u2014 it mutates external state."
8940
+ },
8941
+ // --- Release awareness ---
8942
+ {
8943
+ title: "What's New check \u2014 surface new features after update",
8944
+ domain: "support",
8945
+ priority: "p1",
8946
+ content: "Once per session (COO boot only, never repeat), check if the installed exe-os version is newer than the last session. If it is, read the bundled release-notes.json (at the package root) and surface a brief summary to the founder: 'Updated to exe-os vX.Y.Z \u2014 N new features, M fixes.' List the top 3 features by name. This helps the founder know what they got from the update. If release-notes.json doesn't exist or the version hasn't changed, skip silently. Never repeat this check in the same session."
8947
+ },
8897
8948
  // --- Platform vs Customer ownership ---
8898
8949
  {
8899
8950
  title: "What the platform provides vs what you customize",
@@ -8982,13 +9033,13 @@ var init_platform_procedures = __esm({
8982
9033
  title: "MCP tools \u2014 memory, decision, and search",
8983
9034
  domain: "tool-use",
8984
9035
  priority: "p1",
8985
- content: `memory(action="recall") / recall_my_memory: search your own memories (semantic + FTS). memory(action="ask_team") / ask_team_memory: search a colleague's memories by agent name. memory(action="store") / store_memory: persist a memory. memory(action="commit") / commit_memory: high-importance memory that survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal memory window. Requires session_id + target_timestamp. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. decision(action="store") / store_decision: record an architectural decision (domain, decision, rationale). decision(action="get") / get_decision: retrieve a past decision by domain or query.`
9036
+ content: `memory(action="recall") / recall_my_memory: search your own memories (semantic + FTS). Supports as_of param for bi-temporal queries (what did I know at time X?), kind param to filter by memory type (decision, procedure, observation, raw, conversation, behavior). memory(action="ask_team") / ask_team_memory: search a colleague's memories by agent name. memory(action="store") / store_memory: persist a memory. Supports kind param and procedure_for domain tag for procedure-type memories. memory(action="commit") / commit_memory: high-importance memory that survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal memory window. Requires session_id + target_timestamp. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. memory(action="supersede") / supersede: replace an old memory with a new version (old_id + new text). decision(action="store") / store_decision: record an architectural decision (domain, decision, rationale). decision(action="get") / get_decision: retrieve a past decision by domain or query.`
8986
9037
  },
8987
9038
  {
8988
9039
  title: "MCP tools \u2014 task orchestration",
8989
9040
  domain: "tool-use",
8990
9041
  priority: "p1",
8991
- content: 'task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. task(action="list") / list_tasks: query tasks by status, assignee, project. task(action="get") / get_task: fetch full task details by task_id. task(action="update") / update_task: change status (in_progress, done, blocked, cancelled) + result summary. task(action="close") / close_task: finalize a reviewed task (COO only). task(action="checkpoint") / checkpoint_task: save progress state for crash recovery. task(action="resume") / resume_employee: re-spawn an employee session for an existing task.'
9042
+ content: `task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. Supports spawn_runtime and spawn_model params to override the agent's default runtime/model for a specific task. task(action="list") / list_tasks: query tasks by status, assignee, project. task(action="get") / get_task: fetch full task details by task_id. task(action="update") / update_task: change status (in_progress, done, blocked, cancelled) + result summary. task(action="close") / close_task: finalize a reviewed task (COO only). task(action="checkpoint") / checkpoint_task: save progress state for crash recovery. task(action="resume") / resume_employee: re-spawn an employee session for an existing task.`
8992
9043
  },
8993
9044
  {
8994
9045
  title: "MCP tools \u2014 knowledge graph (GraphRAG)",
@@ -9018,7 +9069,7 @@ var init_platform_procedures = __esm({
9018
9069
  title: "MCP tools \u2014 admin, config, and operations",
9019
9070
  domain: "tool-use",
9020
9071
  priority: "p1",
9021
- content: 'config(action="list_employees"): view roster. config(action="agent_spend"): token usage per agent. config(action="daemon_health"): check exed status. config(action="license_status"): check license. config(action="cloud_sync"): force sync. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="company_procedure", subaction="store|list|deactivate"): manage company procedures. config(action="global_procedure"): list all procedures (platform + company). config(action="create_trigger|list_triggers"): scheduled agent jobs. config(action="export_orchestration|import_orchestration"): portable org state. diagnostics(action="healthcheck|doctor|status_brief|check_update|cloud_status"): system diagnostics. mcp_ping(): daemon health + license status + tool usage stats.'
9072
+ content: 'config(action="list_employees"): view roster. config(action="agent_spend"): token usage per agent. config(action="daemon_health"): check exed status. config(action="license_status"): check license. config(action="cloud_sync"): force sync. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="company_procedure", subaction="store|list|deactivate"): manage company procedures. config(action="global_procedure"): list all procedures (platform + company). config(action="create_trigger|list_triggers"): scheduled agent jobs. config(action="export_orchestration|import_orchestration"): portable org state. diagnostics(action="healthcheck|doctor|status_brief|check_update|cloud_status"): system diagnostics. diagnostics(action="tool_search"): semantic tool discovery \u2014 find relevant MCP tools by natural language query. Returns top-K tools ranked by relevance. diagnostics(action="drift"): identity drift detection \u2014 score how far an agent has drifted from its role identity. Returns drift score + recommendations. mcp_ping(): daemon health + license status + tool usage stats.'
9022
9073
  }
9023
9074
  ];
9024
9075
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -9702,6 +9753,8 @@ async function writeMemory(record) {
9702
9753
  source_type: record.source_type ?? null,
9703
9754
  tier: record.tier ?? classifyTier(record),
9704
9755
  supersedes_id: record.supersedes_id ?? null,
9756
+ valid_from: record.valid_from ?? record.timestamp,
9757
+ invalid_at: record.invalid_at ?? null,
9705
9758
  draft: record.draft ? 1 : 0,
9706
9759
  memory_type: memoryType,
9707
9760
  trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
@@ -9720,7 +9773,8 @@ async function writeMemory(record) {
9720
9773
  token_cost: record.token_cost ?? null,
9721
9774
  audience: record.audience ?? null,
9722
9775
  language_type: record.language_type ?? inferLanguageType(record),
9723
- parent_memory_id: record.parent_memory_id ?? null
9776
+ parent_memory_id: record.parent_memory_id ?? null,
9777
+ procedure_for: record.procedure_for ?? null
9724
9778
  };
9725
9779
  _pendingRecords.push(dbRow);
9726
9780
  orgBus.emit({
@@ -9775,6 +9829,8 @@ async function flushBatch() {
9775
9829
  const sourceType = row.source_type ?? null;
9776
9830
  const tier = row.tier ?? 3;
9777
9831
  const supersedesId = row.supersedes_id ?? null;
9832
+ const validFrom = row.valid_from ?? row.timestamp;
9833
+ const invalidAt = row.invalid_at ?? null;
9778
9834
  const draft = row.draft ? 1 : 0;
9779
9835
  const memoryType = row.memory_type ?? "raw";
9780
9836
  const trajectory = row.trajectory ?? null;
@@ -9794,15 +9850,16 @@ async function flushBatch() {
9794
9850
  const audience = row.audience ?? null;
9795
9851
  const languageType = row.language_type ?? null;
9796
9852
  const parentMemoryId = row.parent_memory_id ?? null;
9853
+ const procedureFor = row.procedure_for ?? null;
9797
9854
  const cols = `id, agent_id, agent_role, session_id, timestamp,
9798
9855
  tool_name, project_name,
9799
9856
  has_error, raw_text, vector, version, task_id, importance, status,
9800
9857
  confidence, last_accessed,
9801
9858
  workspace_id, document_id, user_id, char_offset, page_number,
9802
- source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
9859
+ source_path, source_type, tier, supersedes_id, valid_from, invalid_at, draft, memory_type, trajectory, content_hash,
9803
9860
  intent, outcome, domain, referenced_entities, retrieval_count,
9804
9861
  chain_position, review_status, context_window_pct, file_paths, commit_hash,
9805
- duration_ms, token_cost, audience, language_type, parent_memory_id`;
9862
+ duration_ms, token_cost, audience, language_type, parent_memory_id, procedure_for`;
9806
9863
  const metaArgs = [
9807
9864
  intent,
9808
9865
  outcome,
@@ -9818,7 +9875,8 @@ async function flushBatch() {
9818
9875
  tokenCost,
9819
9876
  audience,
9820
9877
  languageType,
9821
- parentMemoryId
9878
+ parentMemoryId,
9879
+ procedureFor
9822
9880
  ];
9823
9881
  const baseArgs = [
9824
9882
  row.id,
@@ -9847,6 +9905,8 @@ async function flushBatch() {
9847
9905
  sourceType,
9848
9906
  tier,
9849
9907
  supersedesId,
9908
+ validFrom,
9909
+ invalidAt,
9850
9910
  draft,
9851
9911
  memoryType,
9852
9912
  trajectory,
@@ -9854,8 +9914,8 @@ async function flushBatch() {
9854
9914
  ];
9855
9915
  return {
9856
9916
  sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
9857
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
9858
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
9917
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
9918
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
9859
9919
  args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
9860
9920
  };
9861
9921
  };
@@ -9971,6 +10031,12 @@ async function searchMemories(queryVector, agentId, options) {
9971
10031
  AND vector IS NOT NULL${statusFilter}${draftFilter}
9972
10032
  AND COALESCE(confidence, 0.7) >= 0.3`;
9973
10033
  const args2 = [agentId];
10034
+ if (options?.asOf) {
10035
+ sql += ` AND (valid_from IS NULL OR valid_from <= ?) AND (invalid_at IS NULL OR invalid_at > ?)`;
10036
+ args2.push(options.asOf, options.asOf);
10037
+ } else {
10038
+ sql += ` AND invalid_at IS NULL`;
10039
+ }
9974
10040
  const scope = buildWikiScopeFilter(options, "");
9975
10041
  sql += scope.clause;
9976
10042
  args2.push(...scope.args);
@@ -12351,9 +12417,9 @@ Unclassified: ${unclassified}
12351
12417
  }
12352
12418
  async function exportBatches(options) {
12353
12419
  const fs8 = await import("fs");
12354
- const path56 = await import("path");
12420
+ const path58 = await import("path");
12355
12421
  const client = getClient();
12356
- const outDir = path56.join(process.cwd(), "exe/output/classifications/input");
12422
+ const outDir = path58.join(process.cwd(), "exe/output/classifications/input");
12357
12423
  fs8.mkdirSync(outDir, { recursive: true });
12358
12424
  const countResult = await client.execute({
12359
12425
  sql: "SELECT COUNT(*) as cnt FROM memories WHERE intent IS NULL AND outcome IS NULL AND domain IS NULL",
@@ -12377,7 +12443,7 @@ async function exportBatches(options) {
12377
12443
  const text = String(row.text || "").replace(/\n/g, " ");
12378
12444
  return JSON.stringify({ id: row.id, text });
12379
12445
  });
12380
- const batchFile = path56.join(outDir, `batch-${String(batchNum).padStart(4, "0")}.jsonl`);
12446
+ const batchFile = path58.join(outDir, `batch-${String(batchNum).padStart(4, "0")}.jsonl`);
12381
12447
  fs8.writeFileSync(batchFile, lines.join("\n") + "\n");
12382
12448
  exported += batch.rows.length;
12383
12449
  offset += options.batchSize;
@@ -12393,7 +12459,7 @@ async function exportBatches(options) {
12393
12459
  }
12394
12460
  async function importClassifications(importDir) {
12395
12461
  const fs8 = await import("fs");
12396
- const path56 = await import("path");
12462
+ const path58 = await import("path");
12397
12463
  const client = getClient();
12398
12464
  const files = fs8.readdirSync(importDir).filter((f) => f.endsWith(".jsonl")).sort();
12399
12465
  process.stderr.write(`[backfill-metadata] Found ${files.length} JSONL files to import from ${importDir}
@@ -12401,7 +12467,7 @@ async function importClassifications(importDir) {
12401
12467
  let imported = 0;
12402
12468
  let invalid = 0;
12403
12469
  for (const file of files) {
12404
- const lines = fs8.readFileSync(path56.join(importDir, file), "utf-8").split("\n").filter(Boolean);
12470
+ const lines = fs8.readFileSync(path58.join(importDir, file), "utf-8").split("\n").filter(Boolean);
12405
12471
  for (const line of lines) {
12406
12472
  try {
12407
12473
  const rec = JSON.parse(line);
@@ -13572,8 +13638,8 @@ function logQueue(msg) {
13572
13638
  process.stderr.write(`[intercom-queue] ${msg}
13573
13639
  `);
13574
13640
  try {
13575
- const { appendFileSync: appendFileSync3 } = __require("fs");
13576
- appendFileSync3(INTERCOM_LOG, line);
13641
+ const { appendFileSync: appendFileSync4 } = __require("fs");
13642
+ appendFileSync4(INTERCOM_LOG, line);
13577
13643
  } catch {
13578
13644
  }
13579
13645
  }
@@ -14131,8 +14197,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
14131
14197
  const complexity = input.complexity ?? "standard";
14132
14198
  const sessionScope = earlySessionScope;
14133
14199
  await client.execute({
14134
- sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, created_at, updated_at)
14135
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
14200
+ sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, spawn_runtime, spawn_model, created_at, updated_at)
14201
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
14136
14202
  args: [
14137
14203
  id,
14138
14204
  input.title,
@@ -14152,6 +14218,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
14152
14218
  0,
14153
14219
  null,
14154
14220
  sessionScope,
14221
+ input.spawnRuntime ?? null,
14222
+ input.spawnModel ?? null,
14155
14223
  now2,
14156
14224
  now2
14157
14225
  ]
@@ -14208,7 +14276,9 @@ ${input.context}
14208
14276
  budgetTokens: input.budgetTokens ?? null,
14209
14277
  budgetFallbackModel: input.budgetFallbackModel ?? null,
14210
14278
  tokensUsed: 0,
14211
- tokensWarnedAt: null
14279
+ tokensWarnedAt: null,
14280
+ spawnRuntime: input.spawnRuntime ?? null,
14281
+ spawnModel: input.spawnModel ?? null
14212
14282
  };
14213
14283
  }
14214
14284
  async function listTasks(input) {
@@ -14258,7 +14328,9 @@ async function listTasks(input) {
14258
14328
  budgetTokens: r.budget_tokens !== null ? Number(r.budget_tokens) : null,
14259
14329
  budgetFallbackModel: r.budget_fallback_model !== null ? String(r.budget_fallback_model) : null,
14260
14330
  tokensUsed: Number(r.tokens_used ?? 0),
14261
- tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null
14331
+ tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null,
14332
+ spawnRuntime: r.spawn_runtime !== null && r.spawn_runtime !== void 0 ? String(r.spawn_runtime) : null,
14333
+ spawnModel: r.spawn_model !== null && r.spawn_model !== void 0 ? String(r.spawn_model) : null
14262
14334
  }));
14263
14335
  }
14264
14336
  function isTmuxSessionAlive(identifier) {
@@ -15039,10 +15111,10 @@ async function disposeEmbedder() {
15039
15111
  async function embedDirect(text) {
15040
15112
  const llamaCpp = await import("node-llama-cpp");
15041
15113
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
15042
- const { existsSync: existsSync41 } = await import("fs");
15043
- const path56 = await import("path");
15044
- const modelPath = path56.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
15045
- if (!existsSync41(modelPath)) {
15114
+ const { existsSync: existsSync43 } = await import("fs");
15115
+ const path58 = await import("path");
15116
+ const modelPath = path58.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
15117
+ if (!existsSync43(modelPath)) {
15046
15118
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
15047
15119
  }
15048
15120
  const llama = await llamaCpp.getLlama();
@@ -15555,6 +15627,8 @@ async function updateTask(input) {
15555
15627
  budgetFallbackModel: row.budget_fallback_model !== void 0 && row.budget_fallback_model !== null ? String(row.budget_fallback_model) : null,
15556
15628
  tokensUsed: Number(row.tokens_used ?? 0),
15557
15629
  tokensWarnedAt: row.tokens_warned_at !== void 0 && row.tokens_warned_at !== null ? Number(row.tokens_warned_at) : null,
15630
+ spawnRuntime: row.spawn_runtime !== void 0 && row.spawn_runtime !== null ? String(row.spawn_runtime) : null,
15631
+ spawnModel: row.spawn_model !== void 0 && row.spawn_model !== null ? String(row.spawn_model) : null,
15558
15632
  nextTask
15559
15633
  };
15560
15634
  }
@@ -16050,6 +16124,7 @@ function resolveExeSession() {
16050
16124
  const mySession = getMySession();
16051
16125
  if (!mySession) return null;
16052
16126
  const fromSessionName = extractRootExe(mySession);
16127
+ let candidate = null;
16053
16128
  try {
16054
16129
  const key = getSessionKey();
16055
16130
  const parentExe = getParentExe(key);
@@ -16060,13 +16135,47 @@ function resolveExeSession() {
16060
16135
  `[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
16061
16136
  `
16062
16137
  );
16063
- return fromSessionName;
16138
+ candidate = fromSessionName;
16139
+ } else {
16140
+ candidate = fromCache;
16064
16141
  }
16065
- return fromCache;
16066
16142
  }
16067
16143
  } catch {
16068
16144
  }
16069
- return fromSessionName ?? mySession;
16145
+ if (!candidate) {
16146
+ candidate = fromSessionName ?? mySession;
16147
+ }
16148
+ if (candidate && isRootSession(candidate)) {
16149
+ try {
16150
+ const transport = getTransport();
16151
+ const liveSessions = transport.listSessions();
16152
+ if (!liveSessions.includes(candidate)) {
16153
+ const liveRoots = liveSessions.filter((s) => isRootSession(s));
16154
+ if (liveRoots.length === 1) {
16155
+ process.stderr.write(
16156
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead. Using live coordinator "${liveRoots[0]}".
16157
+ `
16158
+ );
16159
+ return liveRoots[0];
16160
+ } else if (liveRoots.length > 1) {
16161
+ const base = candidate.replace(/\d+$/, "");
16162
+ const match = liveRoots.find((s) => s.startsWith(base));
16163
+ const chosen = match ?? liveRoots[0];
16164
+ process.stderr.write(
16165
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead. ${liveRoots.length} live roots found, using "${chosen}".
16166
+ `
16167
+ );
16168
+ return chosen;
16169
+ }
16170
+ process.stderr.write(
16171
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead and no live coordinator found.
16172
+ `
16173
+ );
16174
+ }
16175
+ } catch {
16176
+ }
16177
+ }
16178
+ return candidate;
16070
16179
  }
16071
16180
  function isEmployeeAlive(sessionName) {
16072
16181
  return getTransport().isAlive(sessionName);
@@ -16468,7 +16577,12 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
16468
16577
  }
16469
16578
  const spawnCwd = opts?.cwd ?? projectDir;
16470
16579
  const useExeAgent = !!(opts?.model && opts?.provider);
16471
- const agentRtConfig = getAgentRuntime(employeeName);
16580
+ const baseRtConfig = getAgentRuntime(employeeName);
16581
+ const agentRtConfig = {
16582
+ ...baseRtConfig,
16583
+ ...opts?.runtimeOverride ? { runtime: opts.runtimeOverride } : {},
16584
+ ...opts?.modelOverride ? { model: opts.modelOverride } : {}
16585
+ };
16472
16586
  const useCodex = !useExeAgent && agentRtConfig.runtime === "codex";
16473
16587
  const useOpencode = !useExeAgent && !useCodex && agentRtConfig.runtime === "opencode";
16474
16588
  const ccProvider = useExeAgent || useCodex || useOpencode ? DEFAULT_PROVIDER : detectActiveProvider();
@@ -18012,17 +18126,980 @@ var init_exe_rename = __esm({
18012
18126
  }
18013
18127
  });
18014
18128
 
18129
+ // src/lib/drift-probes.ts
18130
+ async function getRecentMemories(agentId, limit) {
18131
+ try {
18132
+ const { getClient: getClient2, isInitialized: isInitialized2 } = await Promise.resolve().then(() => (init_database(), database_exports));
18133
+ if (!isInitialized2()) return { count: 0, texts: [] };
18134
+ const client = getClient2();
18135
+ const result = await client.execute({
18136
+ sql: `SELECT text FROM memories WHERE agent_id = ? ORDER BY created_at DESC LIMIT ?`,
18137
+ args: [agentId, limit]
18138
+ });
18139
+ const texts = result.rows.map((r) => String(r.text ?? ""));
18140
+ return { count: texts.length, texts };
18141
+ } catch {
18142
+ return { count: 0, texts: [] };
18143
+ }
18144
+ }
18145
+ async function getDecisionCount(agentId) {
18146
+ try {
18147
+ const { getClient: getClient2, isInitialized: isInitialized2 } = await Promise.resolve().then(() => (init_database(), database_exports));
18148
+ if (!isInitialized2()) return 0;
18149
+ const client = getClient2();
18150
+ const result = await client.execute({
18151
+ sql: `SELECT COUNT(*) as cnt FROM memories WHERE agent_id = ? AND memory_type = 'decision'`,
18152
+ args: [agentId]
18153
+ });
18154
+ return Number(result.rows[0]?.cnt ?? 0);
18155
+ } catch {
18156
+ return 0;
18157
+ }
18158
+ }
18159
+ function probeContinuity(ctx) {
18160
+ const memCount = ctx.recentMemoryCount;
18161
+ let score;
18162
+ let detail;
18163
+ if (memCount >= 20) {
18164
+ score = 95;
18165
+ detail = `${memCount} recent memories \u2014 strong continuity`;
18166
+ } else if (memCount >= 10) {
18167
+ score = 85;
18168
+ detail = `${memCount} recent memories \u2014 adequate continuity`;
18169
+ } else if (memCount >= 3) {
18170
+ score = 70;
18171
+ detail = `${memCount} recent memories \u2014 limited continuity`;
18172
+ } else if (memCount >= 1) {
18173
+ score = 50;
18174
+ detail = `${memCount} recent memories \u2014 weak continuity`;
18175
+ } else {
18176
+ score = 30;
18177
+ detail = "No recent memories \u2014 agent may lack session context";
18178
+ }
18179
+ if (ctx.storedDecisionCount > 0) {
18180
+ score = Math.min(100, score + 5);
18181
+ detail += ` (+${ctx.storedDecisionCount} decisions)`;
18182
+ }
18183
+ return { axis: "continuity", score, detail };
18184
+ }
18185
+ function probeConsistency(ctx) {
18186
+ if (!ctx.identityBody || ctx.recentMemoryTexts.length === 0) {
18187
+ return {
18188
+ axis: "consistency",
18189
+ score: ctx.identityBody ? 80 : 50,
18190
+ detail: ctx.identityBody ? "No memories to check against identity" : "No identity file \u2014 cannot assess consistency"
18191
+ };
18192
+ }
18193
+ const identityTerms = extractKeyTerms(ctx.identityBody);
18194
+ if (identityTerms.length === 0) {
18195
+ return { axis: "consistency", score: 75, detail: "Identity has no extractable key terms" };
18196
+ }
18197
+ const memoryText = ctx.recentMemoryTexts.join(" ").toLowerCase();
18198
+ let matched = 0;
18199
+ for (const term of identityTerms) {
18200
+ if (memoryText.includes(term.toLowerCase())) matched++;
18201
+ }
18202
+ const ratio = matched / identityTerms.length;
18203
+ const score = Math.round(50 + ratio * 50);
18204
+ const detail = `${matched}/${identityTerms.length} identity terms found in recent memories`;
18205
+ return { axis: "consistency", score, detail };
18206
+ }
18207
+ function probeRoleFidelity(ctx) {
18208
+ const flags = [];
18209
+ if (!ctx.identityBody) {
18210
+ return {
18211
+ axis: "role-fidelity",
18212
+ score: 40,
18213
+ detail: `No identity file for ${ctx.agent.name}`
18214
+ };
18215
+ }
18216
+ let score = 100;
18217
+ const identityLower = ctx.identityBody.toLowerCase();
18218
+ const rosterRole = ctx.agent.role.toLowerCase();
18219
+ if (!identityLower.includes(rosterRole)) {
18220
+ score -= 15;
18221
+ flags.push(`Identity does not mention role "${ctx.agent.role}"`);
18222
+ }
18223
+ if (!identityLower.includes(ctx.agent.name.toLowerCase())) {
18224
+ score -= 10;
18225
+ flags.push(`Identity does not mention agent name "${ctx.agent.name}"`);
18226
+ }
18227
+ const hasScopeBoundary = identityLower.includes("do not") || identityLower.includes("don't") || identityLower.includes("not your") || identityLower.includes("outside your") || identityLower.includes("you do not");
18228
+ if (!hasScopeBoundary) {
18229
+ score -= 10;
18230
+ flags.push("Identity lacks explicit scope boundaries (what NOT to do)");
18231
+ }
18232
+ if (ctx.agent.systemPrompt) {
18233
+ const promptTerms = extractKeyTerms(ctx.agent.systemPrompt);
18234
+ const identityText = ctx.identityBody.toLowerCase();
18235
+ let promptMatched = 0;
18236
+ for (const term of promptTerms.slice(0, 20)) {
18237
+ if (identityText.includes(term.toLowerCase())) promptMatched++;
18238
+ }
18239
+ const promptRatio = promptTerms.length > 0 ? promptMatched / Math.min(promptTerms.length, 20) : 1;
18240
+ if (promptRatio < 0.3) {
18241
+ score -= 15;
18242
+ flags.push("Identity content diverges significantly from roster systemPrompt");
18243
+ }
18244
+ }
18245
+ if (ctx.recentMemoryTexts.length > 5) {
18246
+ const roleKeywords = extractRoleKeywords(ctx.agent.role);
18247
+ const memoryText = ctx.recentMemoryTexts.join(" ").toLowerCase();
18248
+ let domainHits = 0;
18249
+ for (const kw of roleKeywords) {
18250
+ if (memoryText.includes(kw)) domainHits++;
18251
+ }
18252
+ const domainRatio = roleKeywords.length > 0 ? domainHits / roleKeywords.length : 1;
18253
+ if (domainRatio < 0.2) {
18254
+ score -= 10;
18255
+ flags.push(`Recent work shows little overlap with ${ctx.agent.role} domain keywords`);
18256
+ }
18257
+ }
18258
+ score = Math.max(0, Math.min(100, score));
18259
+ const detail = flags.length > 0 ? flags.join("; ") : "Identity aligns with roster definition";
18260
+ return { axis: "role-fidelity", score, detail };
18261
+ }
18262
+ function probeWorldModel(ctx) {
18263
+ if (!ctx.identityBody) {
18264
+ return {
18265
+ axis: "world-model",
18266
+ score: 50,
18267
+ detail: "No identity file \u2014 cannot assess org awareness"
18268
+ };
18269
+ }
18270
+ const identityLower = ctx.identityBody.toLowerCase();
18271
+ const flags = [];
18272
+ let score = 100;
18273
+ const otherAgents = ctx.allEmployees.filter((e) => e.name !== ctx.agent.name);
18274
+ let mentionedAgents = 0;
18275
+ for (const other of otherAgents) {
18276
+ if (identityLower.includes(other.name.toLowerCase())) mentionedAgents++;
18277
+ }
18278
+ if (otherAgents.length > 0) {
18279
+ const mentionRatio = mentionedAgents / otherAgents.length;
18280
+ if (mentionRatio < 0.3) {
18281
+ score -= 15;
18282
+ flags.push(`Identity mentions ${mentionedAgents}/${otherAgents.length} team members`);
18283
+ }
18284
+ }
18285
+ const hasReportingChain = identityLower.includes("report") || identityLower.includes("manager") || identityLower.includes("coo") || identityLower.includes("coordinator");
18286
+ if (!hasReportingChain) {
18287
+ score -= 10;
18288
+ flags.push("Identity does not reference reporting chain");
18289
+ }
18290
+ const orgTerms = ["exe-os", "exe-wiki", "exe-crm", "askexe"];
18291
+ let orgMentions = 0;
18292
+ for (const term of orgTerms) {
18293
+ if (identityLower.includes(term)) orgMentions++;
18294
+ }
18295
+ if (orgMentions === 0) {
18296
+ score -= 5;
18297
+ flags.push("Identity does not reference any org products");
18298
+ }
18299
+ score = Math.max(0, Math.min(100, score));
18300
+ const detail = flags.length > 0 ? flags.join("; ") : "Identity reflects org structure";
18301
+ return { axis: "world-model", score, detail };
18302
+ }
18303
+ function extractKeyTerms(text) {
18304
+ const stopwords = /* @__PURE__ */ new Set([
18305
+ "the",
18306
+ "and",
18307
+ "for",
18308
+ "are",
18309
+ "but",
18310
+ "not",
18311
+ "you",
18312
+ "all",
18313
+ "any",
18314
+ "can",
18315
+ "had",
18316
+ "her",
18317
+ "was",
18318
+ "one",
18319
+ "our",
18320
+ "out",
18321
+ "has",
18322
+ "his",
18323
+ "how",
18324
+ "its",
18325
+ "may",
18326
+ "new",
18327
+ "now",
18328
+ "old",
18329
+ "see",
18330
+ "way",
18331
+ "who",
18332
+ "did",
18333
+ "get",
18334
+ "got",
18335
+ "let",
18336
+ "say",
18337
+ "she",
18338
+ "too",
18339
+ "use",
18340
+ "with",
18341
+ "this",
18342
+ "that",
18343
+ "from",
18344
+ "they",
18345
+ "been",
18346
+ "have",
18347
+ "will",
18348
+ "your",
18349
+ "what",
18350
+ "when",
18351
+ "make",
18352
+ "like",
18353
+ "just",
18354
+ "over",
18355
+ "such",
18356
+ "take",
18357
+ "than",
18358
+ "them",
18359
+ "very",
18360
+ "some",
18361
+ "could",
18362
+ "into",
18363
+ "then",
18364
+ "more",
18365
+ "also",
18366
+ "after",
18367
+ "should",
18368
+ "would",
18369
+ "about",
18370
+ "their",
18371
+ "which",
18372
+ "these",
18373
+ "other",
18374
+ "every",
18375
+ "does",
18376
+ "being",
18377
+ "those",
18378
+ "never",
18379
+ "before",
18380
+ "through"
18381
+ ]);
18382
+ const words = text.replace(/[^\w\s-]/g, " ").split(/\s+/).filter((w) => w.length > 3 && !stopwords.has(w.toLowerCase()));
18383
+ return [...new Set(words.map((w) => w.toLowerCase()))].slice(0, 50);
18384
+ }
18385
+ function extractRoleKeywords(role) {
18386
+ const roleKeywordMap = {
18387
+ "coo": ["coordinate", "review", "status", "team", "task", "priority", "dispatch"],
18388
+ "cto": ["architecture", "code", "technical", "system", "design", "review", "security"],
18389
+ "cmo": ["marketing", "brand", "content", "design", "seo", "social", "campaign"],
18390
+ "principal engineer": ["code", "implement", "test", "fix", "feature", "refactor", "build"],
18391
+ "staff code reviewer": ["review", "code", "quality", "issue", "fix", "pattern"],
18392
+ "content production specialist": ["video", "image", "render", "content", "produce", "media"],
18393
+ "ai product lead": ["competitive", "analysis", "feature", "product", "research", "repo"]
18394
+ };
18395
+ const normalized = role.toLowerCase();
18396
+ return roleKeywordMap[normalized] ?? normalized.split(/\s+/).filter((w) => w.length > 2);
18397
+ }
18398
+ async function runDriftProbes(options = {}) {
18399
+ const employees = loadEmployeesSync();
18400
+ const targetAgents = options.agentId ? employees.filter((e) => e.name === options.agentId) : employees;
18401
+ if (targetAgents.length === 0) {
18402
+ return [];
18403
+ }
18404
+ const axes = options.axes ?? ["continuity", "consistency", "role-fidelity", "world-model"];
18405
+ const results = [];
18406
+ for (const agent of targetAgents) {
18407
+ const identity = getIdentity(agent.name);
18408
+ const { count: memCount, texts: memTexts } = await getRecentMemories(agent.name, 50);
18409
+ const decisionCount = await getDecisionCount(agent.name);
18410
+ const ctx = {
18411
+ agent,
18412
+ identityBody: identity?.body ?? null,
18413
+ identityRole: identity?.frontmatter.role ?? null,
18414
+ recentMemoryCount: memCount,
18415
+ recentMemoryTexts: memTexts,
18416
+ storedDecisionCount: decisionCount,
18417
+ allEmployees: employees
18418
+ };
18419
+ const probes = [];
18420
+ const probeFns = {
18421
+ continuity: probeContinuity,
18422
+ consistency: probeConsistency,
18423
+ "role-fidelity": probeRoleFidelity,
18424
+ "world-model": probeWorldModel
18425
+ };
18426
+ for (const axis of axes) {
18427
+ probes.push(probeFns[axis](ctx));
18428
+ }
18429
+ const scores = {
18430
+ continuity: 0,
18431
+ consistency: 0,
18432
+ "role-fidelity": 0,
18433
+ "world-model": 0
18434
+ };
18435
+ for (const probe of probes) {
18436
+ scores[probe.axis] = probe.score;
18437
+ }
18438
+ const weights = {
18439
+ continuity: 0.2,
18440
+ consistency: 0.2,
18441
+ "role-fidelity": 0.35,
18442
+ "world-model": 0.25
18443
+ };
18444
+ let weightedSum = 0;
18445
+ let weightTotal = 0;
18446
+ for (const axis of axes) {
18447
+ weightedSum += scores[axis] * weights[axis];
18448
+ weightTotal += weights[axis];
18449
+ }
18450
+ const overall = Math.round(weightTotal > 0 ? weightedSum / weightTotal : 0);
18451
+ const flags = [];
18452
+ for (const probe of probes) {
18453
+ if (probe.score < DRIFT_THRESHOLD) {
18454
+ flags.push(`${probe.axis} at ${probe.score}% \u2014 ${probe.detail}`);
18455
+ }
18456
+ }
18457
+ results.push({
18458
+ agent: agent.name,
18459
+ scores,
18460
+ overall,
18461
+ drifting: flags.length > 0,
18462
+ flags
18463
+ });
18464
+ }
18465
+ return results;
18466
+ }
18467
+ var DRIFT_THRESHOLD;
18468
+ var init_drift_probes = __esm({
18469
+ "src/lib/drift-probes.ts"() {
18470
+ "use strict";
18471
+ init_identity();
18472
+ init_employees();
18473
+ DRIFT_THRESHOLD = 80;
18474
+ }
18475
+ });
18476
+
18477
+ // src/bin/exe-drift.ts
18478
+ var exe_drift_exports = {};
18479
+ __export(exe_drift_exports, {
18480
+ runDrift: () => runDrift
18481
+ });
18482
+ function statusIcon(overall) {
18483
+ if (overall >= 80) return "\x1B[32m\u{1F7E2} OK\x1B[0m";
18484
+ if (overall >= 60) return "\x1B[33m\u{1F7E0} WARN\x1B[0m";
18485
+ return "\x1B[31m\u{1F534} DRIFTING\x1B[0m";
18486
+ }
18487
+ function padRight(str, len) {
18488
+ return str.length >= len ? str.slice(0, len) : str + " ".repeat(len - str.length);
18489
+ }
18490
+ function padLeft(str, len) {
18491
+ return str.length >= len ? str : " ".repeat(len - str.length) + str;
18492
+ }
18493
+ function formatTable(results) {
18494
+ const lines = [];
18495
+ const header = padRight("Agent", 10) + AXES.map((a) => padLeft(AXIS_HEADERS[a], 9)).join("") + padLeft("Overall", 9) + " Status";
18496
+ lines.push(header);
18497
+ lines.push("-".repeat(header.length + 10));
18498
+ for (const r of results) {
18499
+ const line = padRight(r.agent, 10) + AXES.map((a) => padLeft(String(r.scores[a]), 9)).join("") + padLeft(String(r.overall), 9) + " " + statusIcon(r.overall);
18500
+ lines.push(line);
18501
+ }
18502
+ return lines.join("\n");
18503
+ }
18504
+ async function runDrift(args2) {
18505
+ const agentIdx = args2.indexOf("--agent");
18506
+ const agentId = agentIdx >= 0 ? args2[agentIdx + 1] : void 0;
18507
+ console.log("\nexe-os doctor --drift\n");
18508
+ const results = await runDriftProbes({ agentId });
18509
+ if (results.length === 0) {
18510
+ console.log("No agents found. Run /exe-team to see available employees.");
18511
+ return;
18512
+ }
18513
+ console.log(formatTable(results));
18514
+ console.log();
18515
+ const flagged = results.filter((r) => r.flags.length > 0);
18516
+ if (flagged.length > 0) {
18517
+ for (const r of flagged) {
18518
+ for (const flag of r.flags) {
18519
+ console.log(`\u26A0 ${r.agent}: ${flag}`);
18520
+ }
18521
+ }
18522
+ console.log();
18523
+ } else {
18524
+ console.log("All agents within role-fidelity thresholds.\n");
18525
+ }
18526
+ }
18527
+ var AXES, AXIS_HEADERS;
18528
+ var init_exe_drift = __esm({
18529
+ "src/bin/exe-drift.ts"() {
18530
+ "use strict";
18531
+ init_drift_probes();
18532
+ AXES = ["continuity", "consistency", "role-fidelity", "world-model"];
18533
+ AXIS_HEADERS = {
18534
+ continuity: "Cont.",
18535
+ consistency: "Consist.",
18536
+ "role-fidelity": "Role",
18537
+ "world-model": "World"
18538
+ };
18539
+ }
18540
+ });
18541
+
18542
+ // src/lib/mcp-transport-health.ts
18543
+ import { appendFileSync as appendFileSync3, closeSync as closeSync3, existsSync as existsSync30, mkdirSync as mkdirSync22, openSync as openSync3, readFileSync as readFileSync26, readSync, statSync as statSync7, writeFileSync as writeFileSync23 } from "fs";
18544
+ import path37 from "path";
18545
+ import { fileURLToPath as fileURLToPath5 } from "url";
18546
+ function parsePositiveInt(value, fallback) {
18547
+ if (!value) return fallback;
18548
+ const parsed = Number.parseInt(value, 10);
18549
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
18550
+ }
18551
+ function readTailText(filePath, maxBytes) {
18552
+ const stats = statSync7(filePath);
18553
+ if (stats.size <= maxBytes) return readFileSync26(filePath, "utf8");
18554
+ const fd = openSync3(filePath, "r");
18555
+ try {
18556
+ const buffer = Buffer.allocUnsafe(maxBytes);
18557
+ readSync(fd, buffer, 0, maxBytes, stats.size - maxBytes);
18558
+ const text = buffer.toString("utf8");
18559
+ const firstNewline = text.indexOf("\n");
18560
+ return firstNewline >= 0 ? text.slice(firstNewline + 1) : text;
18561
+ } finally {
18562
+ closeSync3(fd);
18563
+ }
18564
+ }
18565
+ function readPackageVersion2() {
18566
+ let dir = path37.dirname(fileURLToPath5(import.meta.url));
18567
+ const { root } = path37.parse(dir);
18568
+ while (dir !== root) {
18569
+ const pkgPath = path37.join(dir, "package.json");
18570
+ if (existsSync30(pkgPath)) {
18571
+ try {
18572
+ const parsed = JSON.parse(readFileSync26(pkgPath, "utf8"));
18573
+ return parsed.version ?? "unknown";
18574
+ } catch {
18575
+ return "unknown";
18576
+ }
18577
+ }
18578
+ dir = path37.dirname(dir);
18579
+ }
18580
+ return "unknown";
18581
+ }
18582
+ function parseMcpHttpEventLines(raw, limit = 200) {
18583
+ const lines = raw.trim().split("\n").filter(Boolean).slice(-limit);
18584
+ const events = [];
18585
+ for (const line of lines) {
18586
+ try {
18587
+ events.push(JSON.parse(line));
18588
+ } catch {
18589
+ }
18590
+ }
18591
+ return events;
18592
+ }
18593
+ function readMcpHttpEvents(limit = 200) {
18594
+ if (!existsSync30(MCP_HTTP_EVENTS_PATH)) return [];
18595
+ const raw = readTailText(MCP_HTTP_EVENTS_PATH, EVENT_READ_BYTES);
18596
+ return parseMcpHttpEventLines(raw, limit);
18597
+ }
18598
+ function summarizeMcpTransport(events = readMcpHttpEvents()) {
18599
+ const lastServerStartIndex = events.map((event) => event.message).lastIndexOf("server_started");
18600
+ const scopedEvents = lastServerStartIndex >= 0 ? events.slice(lastServerStartIndex) : events;
18601
+ const activeSessionEvent = [...scopedEvents].reverse().find((event) => typeof event.activeSessions === "number");
18602
+ const successfulToolCalls = scopedEvents.filter((event) => event.message === "tool_call_ok");
18603
+ const lastSuccessfulToolCall = successfulToolCalls.at(-1) ?? null;
18604
+ const summary = {
18605
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
18606
+ version: readPackageVersion2(),
18607
+ scope: "local",
18608
+ privacy: "metadata_only",
18609
+ eventLogPath: MCP_HTTP_EVENTS_PATH,
18610
+ activeSessions: activeSessionEvent?.activeSessions ?? null,
18611
+ sessionsCreated: scopedEvents.filter((event) => event.message === "session_initialized").length,
18612
+ sessionsClosed: scopedEvents.filter((event) => event.message === "session_closed").length,
18613
+ missingSessionErrors: scopedEvents.filter((event) => event.message?.includes("missing MCP session")).length,
18614
+ staleSessionErrors: scopedEvents.filter((event) => event.message?.includes("stale or unknown")).length,
18615
+ transportErrors: scopedEvents.filter((event) => event.level === "warn" || event.level === "error").length,
18616
+ lastSuccessfulHandshake: scopedEvents.filter((event) => event.message === "session_initialized").at(-1)?.timestamp ?? null,
18617
+ lastSuccessfulToolCall: lastSuccessfulToolCall?.timestamp ?? null,
18618
+ lastSuccessfulToolCallByRuntime: {},
18619
+ lastSuccessfulToolCallByAgent: {},
18620
+ lastSuccessfulToolCallByFamily: {},
18621
+ activeSessionsByRuntime: {},
18622
+ recentWarnings: scopedEvents.filter((event) => event.level === "warn" || event.level === "error").slice(-10),
18623
+ remediation: [
18624
+ "If MCP tools fail with missing/stale session, reconnect the MCP client (/mcp or restart the runtime).",
18625
+ "Do not access the database directly; MCP is the only data interface.",
18626
+ "Check get_daemon_health or exe-healthcheck for daemon/MCP endpoint status before retrying work."
18627
+ ]
18628
+ };
18629
+ const createdBySession = /* @__PURE__ */ new Map();
18630
+ for (const event of scopedEvents) {
18631
+ if (event.message === "session_initialized" && event.sessionId) createdBySession.set(event.sessionId, event);
18632
+ if ((event.message === "session_closed" || event.message === "session_expired") && event.sessionId) {
18633
+ createdBySession.delete(event.sessionId);
18634
+ }
18635
+ }
18636
+ for (const event of createdBySession.values()) {
18637
+ const runtime = event.runtime ?? "Unknown";
18638
+ summary.activeSessionsByRuntime[runtime] = (summary.activeSessionsByRuntime[runtime] ?? 0) + 1;
18639
+ }
18640
+ for (const event of successfulToolCalls) {
18641
+ if (event.runtime) summary.lastSuccessfulToolCallByRuntime[event.runtime] = event.timestamp ?? "";
18642
+ if (event.agentId) summary.lastSuccessfulToolCallByAgent[event.agentId] = event.timestamp ?? "";
18643
+ if (event.toolFamily) summary.lastSuccessfulToolCallByFamily[event.toolFamily] = event.timestamp ?? "";
18644
+ }
18645
+ return summary;
18646
+ }
18647
+ var MCP_HTTP_EVENTS_PATH, MCP_MONITOR_DIR, MCP_TRANSPORT_SUMMARY_PATH, DEFAULT_EVENT_READ_BYTES, DEFAULT_EVENT_MAX_BYTES, EVENT_READ_BYTES, EVENT_MAX_BYTES;
18648
+ var init_mcp_transport_health = __esm({
18649
+ "src/lib/mcp-transport-health.ts"() {
18650
+ "use strict";
18651
+ init_config();
18652
+ MCP_HTTP_EVENTS_PATH = path37.join(EXE_AI_DIR, "mcp-http-events.jsonl");
18653
+ MCP_MONITOR_DIR = path37.join(EXE_AI_DIR, "monitor");
18654
+ MCP_TRANSPORT_SUMMARY_PATH = path37.join(MCP_MONITOR_DIR, "mcp-transport-summary.json");
18655
+ DEFAULT_EVENT_READ_BYTES = 256 * 1024;
18656
+ DEFAULT_EVENT_MAX_BYTES = 1024 * 1024;
18657
+ EVENT_READ_BYTES = parsePositiveInt(process.env.EXE_MCP_HTTP_EVENT_READ_BYTES, DEFAULT_EVENT_READ_BYTES);
18658
+ EVENT_MAX_BYTES = parsePositiveInt(process.env.EXE_MCP_HTTP_EVENT_MAX_BYTES, DEFAULT_EVENT_MAX_BYTES);
18659
+ }
18660
+ });
18661
+
18662
+ // src/bin/exe-healthcheck.ts
18663
+ import { existsSync as existsSync31, readFileSync as readFileSync27, readdirSync as readdirSync9 } from "fs";
18664
+ import path38 from "path";
18665
+ import { execSync as execSync14 } from "child_process";
18666
+ import { fileURLToPath as fileURLToPath6 } from "url";
18667
+ function findPackageRoot2() {
18668
+ let dir = path38.dirname(fileURLToPath6(import.meta.url));
18669
+ const { root } = path38.parse(dir);
18670
+ while (dir !== root) {
18671
+ if (existsSync31(path38.join(dir, "package.json"))) return dir;
18672
+ dir = path38.dirname(dir);
18673
+ }
18674
+ throw new Error("Cannot find package root");
18675
+ }
18676
+ function checkBuildIntegrity(pkgRoot) {
18677
+ const results = [];
18678
+ const tsupConfig = path38.join(pkgRoot, "tsup.config.ts");
18679
+ if (!existsSync31(tsupConfig)) {
18680
+ return [{ name: "build/tsup-config", pass: false, detail: "tsup.config.ts not found" }];
18681
+ }
18682
+ const configContent = readFileSync27(tsupConfig, "utf-8");
18683
+ const entryMatches = configContent.matchAll(/"([^"]+)":\s*"src\//g);
18684
+ const missing = [];
18685
+ let total = 0;
18686
+ for (const match of entryMatches) {
18687
+ const outputKey = match[1];
18688
+ const expectedPath = path38.join(pkgRoot, "dist", `${outputKey}.js`);
18689
+ total++;
18690
+ if (!existsSync31(expectedPath)) {
18691
+ missing.push(`dist/${outputKey}.js`);
18692
+ }
18693
+ }
18694
+ if (missing.length > 0) {
18695
+ results.push({
18696
+ name: "build/entry-points",
18697
+ pass: false,
18698
+ detail: `${missing.length}/${total} entry points missing:
18699
+ ${missing.join("\n ")}`
18700
+ });
18701
+ } else {
18702
+ results.push({
18703
+ name: "build/entry-points",
18704
+ pass: true,
18705
+ detail: `${total} entry points verified`
18706
+ });
18707
+ }
18708
+ return results;
18709
+ }
18710
+ function checkEmbedPipeline(pkgRoot) {
18711
+ const results = [];
18712
+ const daemonPath = path38.join(pkgRoot, "dist", "lib", "exe-daemon.js");
18713
+ if (!existsSync31(daemonPath)) {
18714
+ results.push({
18715
+ name: "exed/daemon-exists",
18716
+ pass: false,
18717
+ detail: `exe-daemon.js not found at ${daemonPath}`
18718
+ });
18719
+ return results;
18720
+ }
18721
+ results.push({ name: "exed/daemon-exists", pass: true, detail: "dist/lib/exe-daemon.js exists" });
18722
+ const entryDirs = ["dist/hooks", "dist/bin", "dist/mcp"];
18723
+ for (const dir of entryDirs) {
18724
+ const fullDir = path38.join(pkgRoot, dir);
18725
+ if (!existsSync31(fullDir)) continue;
18726
+ let walkDir2 = fullDir;
18727
+ const { root } = path38.parse(walkDir2);
18728
+ let foundRoot = null;
18729
+ while (walkDir2 !== root) {
18730
+ if (existsSync31(path38.join(walkDir2, "package.json"))) {
18731
+ foundRoot = walkDir2;
18732
+ break;
18733
+ }
18734
+ walkDir2 = path38.dirname(walkDir2);
18735
+ }
18736
+ if (!foundRoot) {
18737
+ results.push({
18738
+ name: `exed/reachable-from-${dir}`,
18739
+ pass: false,
18740
+ detail: `Cannot find package root from ${dir}`
18741
+ });
18742
+ continue;
18743
+ }
18744
+ const resolvedDaemon = path38.join(foundRoot, "dist", "lib", "exe-daemon.js");
18745
+ const reachable = existsSync31(resolvedDaemon);
18746
+ results.push({
18747
+ name: `exed/reachable-from-${dir}`,
18748
+ pass: reachable,
18749
+ detail: reachable ? `Resolves to ${resolvedDaemon}` : `NOT FOUND: ${resolvedDaemon}`
18750
+ });
18751
+ }
18752
+ return results;
18753
+ }
18754
+ function checkTaskSystem(pkgRoot) {
18755
+ const results = [];
18756
+ const scannerPath = path38.join(pkgRoot, "dist", "bin", "scan-tasks.js");
18757
+ if (!existsSync31(scannerPath)) {
18758
+ results.push({ name: "tasks/scanner", pass: false, detail: "scan-tasks.js not found" });
18759
+ return results;
18760
+ }
18761
+ try {
18762
+ execSync14(`node "${scannerPath}" /tmp/nonexistent-healthcheck-test --format=json 2>/dev/null`, {
18763
+ timeout: 1e4,
18764
+ encoding: "utf-8"
18765
+ });
18766
+ results.push({ name: "tasks/scanner", pass: true, detail: "scan-tasks.js runs without import errors" });
18767
+ } catch (err) {
18768
+ const msg = err instanceof Error ? err.message : String(err);
18769
+ if (msg.includes("Cannot find module") || msg.includes("ERR_MODULE_NOT_FOUND") || msg.includes("SyntaxError")) {
18770
+ results.push({ name: "tasks/scanner", pass: false, detail: `Import error: ${msg.slice(0, 200)}` });
18771
+ } else {
18772
+ results.push({ name: "tasks/scanner", pass: true, detail: "scan-tasks.js runs (no import errors)" });
18773
+ }
18774
+ }
18775
+ return results;
18776
+ }
18777
+ function checkWorkerSpawning(pkgRoot) {
18778
+ const results = [];
18779
+ const workerPath = path38.join(pkgRoot, "dist", "hooks", "ingest-worker.js");
18780
+ if (!existsSync31(workerPath)) {
18781
+ results.push({ name: "workers/ingest-worker", pass: false, detail: "ingest-worker.js not found" });
18782
+ return results;
18783
+ }
18784
+ try {
18785
+ execSync14(`node --check "${workerPath}" 2>&1`, { timeout: 1e4, encoding: "utf-8" });
18786
+ results.push({ name: "workers/ingest-worker", pass: true, detail: "ingest-worker.js parses OK" });
18787
+ } catch (err) {
18788
+ results.push({
18789
+ name: "workers/ingest-worker",
18790
+ pass: false,
18791
+ detail: `Parse error: ${err instanceof Error ? err.message.slice(0, 200) : String(err)}`
18792
+ });
18793
+ }
18794
+ const hooksDir = path38.join(pkgRoot, "dist", "hooks");
18795
+ if (existsSync31(hooksDir)) {
18796
+ const hookFiles = readdirSync9(hooksDir).filter((f) => f.endsWith(".js") && !f.endsWith(".js.map"));
18797
+ let hooksPassed = 0;
18798
+ const hooksFailed = [];
18799
+ for (const hook of hookFiles) {
18800
+ try {
18801
+ execSync14(`node --check "${path38.join(hooksDir, hook)}" 2>&1`, { timeout: 1e4, encoding: "utf-8" });
18802
+ hooksPassed++;
18803
+ } catch {
18804
+ hooksFailed.push(hook);
18805
+ }
18806
+ }
18807
+ if (hooksFailed.length > 0) {
18808
+ results.push({
18809
+ name: "workers/hooks-parse",
18810
+ pass: false,
18811
+ detail: `${hooksFailed.length}/${hookFiles.length} hooks fail to parse: ${hooksFailed.join(", ")}`
18812
+ });
18813
+ } else {
18814
+ results.push({
18815
+ name: "workers/hooks-parse",
18816
+ pass: true,
18817
+ detail: `${hooksPassed} hook entry points parse OK`
18818
+ });
18819
+ }
18820
+ }
18821
+ return results;
18822
+ }
18823
+ function checkMcpTransport() {
18824
+ const results = [];
18825
+ const pidPath = path38.join(EXE_AI_DIR, "exed.pid");
18826
+ const tokenPath = path38.join(EXE_AI_DIR, "exed.token");
18827
+ let daemonAlive = false;
18828
+ if (existsSync31(pidPath)) {
18829
+ try {
18830
+ const pid = parseInt(readFileSync27(pidPath, "utf8").trim(), 10);
18831
+ process.kill(pid, 0);
18832
+ daemonAlive = true;
18833
+ results.push({ name: "mcp/daemon-process", pass: true, detail: `exed process alive (pid ${pid})` });
18834
+ } catch {
18835
+ results.push({ name: "mcp/daemon-process", pass: false, detail: "exed.pid exists but process is not alive; restart exe-os/exed" });
18836
+ }
18837
+ } else {
18838
+ results.push({ name: "mcp/daemon-process", pass: false, detail: "No exed.pid found; daemon is not running" });
18839
+ }
18840
+ if (daemonAlive && existsSync31(tokenPath)) {
18841
+ try {
18842
+ const token = readFileSync27(tokenPath, "utf8").trim();
18843
+ const response = execSync14(
18844
+ `curl -sS -i -m 2 -H "Authorization: Bearer ${token}" -H 'Accept: application/json, text/event-stream' http://127.0.0.1:48739/mcp`,
18845
+ { encoding: "utf8", timeout: 3e3 }
18846
+ );
18847
+ const jsonRpcError = response.includes("Content-Type: application/json") && response.includes("missing MCP session");
18848
+ results.push({
18849
+ name: "mcp/http-endpoint",
18850
+ pass: jsonRpcError,
18851
+ detail: jsonRpcError ? "MCP HTTP endpoint reachable; missing-session probe returns JSON-RPC (expected)" : "MCP HTTP endpoint reachable but did not return expected JSON-RPC missing-session response"
18852
+ });
18853
+ } catch (err) {
18854
+ results.push({
18855
+ name: "mcp/http-endpoint",
18856
+ pass: false,
18857
+ detail: `MCP HTTP endpoint not reachable: ${err instanceof Error ? err.message.slice(0, 180) : String(err)}`
18858
+ });
18859
+ }
18860
+ } else if (daemonAlive) {
18861
+ results.push({ name: "mcp/http-endpoint", pass: false, detail: "Daemon is alive but exed.token is missing; cannot probe MCP HTTP" });
18862
+ }
18863
+ const events = readMcpHttpEvents(200);
18864
+ const summary = summarizeMcpTransport(events);
18865
+ results.push({
18866
+ name: "mcp/local-event-log",
18867
+ pass: true,
18868
+ detail: `${events.length} recent event(s); activeSessions=${summary.activeSessions ?? "unknown"}; lastHandshake=${summary.lastSuccessfulHandshake ?? "none"}; lastTool=${summary.lastSuccessfulToolCall ?? "none"}`
18869
+ });
18870
+ results.push({
18871
+ name: "mcp/monitor-summary",
18872
+ pass: true,
18873
+ detail: `Privacy-safe local monitor summary: ${path38.join(EXE_AI_DIR, "monitor", "mcp-transport-summary.json")}`
18874
+ });
18875
+ return results;
18876
+ }
18877
+ function checkClaudeCodeInstall() {
18878
+ const results = [];
18879
+ const execPath = process.env.CLAUDE_CODE_EXECPATH ?? "";
18880
+ if (execPath.length > 0 && (execPath.includes("claude/versions/") || execPath.includes("claude.exe") || execPath.includes("claude-native"))) {
18881
+ results.push({
18882
+ name: "cc/execpath-clean",
18883
+ pass: false,
18884
+ detail: `CLAUDE_CODE_EXECPATH points to native binary: "${execPath}" \u2014 20K phantom billing risk. Unset it: unset CLAUDE_CODE_EXECPATH`
18885
+ });
18886
+ } else {
18887
+ results.push({
18888
+ name: "cc/execpath-clean",
18889
+ pass: true,
18890
+ detail: execPath ? `CLAUDE_CODE_EXECPATH=${execPath} (node runtime, OK)` : "CLAUDE_CODE_EXECPATH is unset"
18891
+ });
18892
+ }
18893
+ try {
18894
+ const claudePath = execSync14("which claude 2>/dev/null || true", { encoding: "utf8", timeout: 5e3 }).trim();
18895
+ if (!claudePath) {
18896
+ results.push({
18897
+ name: "cc/cli-binary",
18898
+ pass: false,
18899
+ detail: "claude not found in PATH"
18900
+ });
18901
+ } else {
18902
+ let resolved = claudePath;
18903
+ try {
18904
+ resolved = execSync14(`readlink -f "${claudePath}" 2>/dev/null || readlink "${claudePath}" 2>/dev/null || echo "${claudePath}"`, {
18905
+ encoding: "utf8",
18906
+ timeout: 5e3
18907
+ }).trim();
18908
+ } catch {
18909
+ }
18910
+ if (resolved.includes("bin/claude.exe") || resolved.includes("bin/claude-native")) {
18911
+ results.push({
18912
+ name: "cc/cli-binary",
18913
+ pass: false,
18914
+ detail: `claude resolves to native binary: ${resolved}. Should be cli.js. Run: npm install -g @anthropic-ai/claude-code@2.1.98`
18915
+ });
18916
+ } else {
18917
+ results.push({
18918
+ name: "cc/cli-binary",
18919
+ pass: true,
18920
+ detail: `claude resolves to: ${resolved}`
18921
+ });
18922
+ }
18923
+ }
18924
+ } catch {
18925
+ results.push({
18926
+ name: "cc/cli-binary",
18927
+ pass: false,
18928
+ detail: "Failed to check claude binary path"
18929
+ });
18930
+ }
18931
+ const versionsDir = path38.join(
18932
+ process.env.HOME ?? process.env.USERPROFILE ?? "",
18933
+ ".local",
18934
+ "share",
18935
+ "claude",
18936
+ "versions"
18937
+ );
18938
+ if (existsSync31(versionsDir)) {
18939
+ try {
18940
+ const entries = readdirSync9(versionsDir);
18941
+ if (entries.length > 0) {
18942
+ results.push({
18943
+ name: "cc/native-cache-clean",
18944
+ pass: false,
18945
+ detail: `${entries.length} cached native version(s) found in ${versionsDir}: ${entries.slice(0, 3).join(", ")}${entries.length > 3 ? "..." : ""}. Remove: rm -rf "${versionsDir}"`
18946
+ });
18947
+ } else {
18948
+ results.push({
18949
+ name: "cc/native-cache-clean",
18950
+ pass: true,
18951
+ detail: `${versionsDir} is empty`
18952
+ });
18953
+ }
18954
+ } catch {
18955
+ results.push({
18956
+ name: "cc/native-cache-clean",
18957
+ pass: true,
18958
+ detail: `${versionsDir} not readable (OK)`
18959
+ });
18960
+ }
18961
+ } else {
18962
+ results.push({
18963
+ name: "cc/native-cache-clean",
18964
+ pass: true,
18965
+ detail: `${versionsDir} does not exist`
18966
+ });
18967
+ }
18968
+ const disableOld = process.env.DISABLE_AUTOUPDATER === "1";
18969
+ const disableNew = process.env.CLAUDE_CODE_AUTOUPDATER_DISABLED === "1";
18970
+ if (!disableOld && !disableNew) {
18971
+ results.push({
18972
+ name: "cc/autoupdater-disabled",
18973
+ pass: false,
18974
+ detail: "Neither DISABLE_AUTOUPDATER=1 nor CLAUDE_CODE_AUTOUPDATER_DISABLED=1 is set. Auto-updater may install infected native binary. Export both in your shell profile."
18975
+ });
18976
+ } else {
18977
+ const which = [
18978
+ disableOld ? "DISABLE_AUTOUPDATER=1" : null,
18979
+ disableNew ? "CLAUDE_CODE_AUTOUPDATER_DISABLED=1" : null
18980
+ ].filter(Boolean).join(" + ");
18981
+ results.push({
18982
+ name: "cc/autoupdater-disabled",
18983
+ pass: true,
18984
+ detail: `Auto-updater disabled via ${which}`
18985
+ });
18986
+ }
18987
+ try {
18988
+ const ccVersion = execSync14("claude --version 2>/dev/null || echo unknown", {
18989
+ encoding: "utf8",
18990
+ timeout: 5e3
18991
+ }).trim();
18992
+ const versionMatch = ccVersion.match(/(\d+\.\d+\.\d+)/);
18993
+ if (versionMatch) {
18994
+ const ver = versionMatch[1];
18995
+ const [, minor] = ver.split(".").map(Number);
18996
+ const isRisky = minor !== void 0 && minor >= 1 && parseInt(ver.split(".")[2] ?? "0") >= 119;
18997
+ results.push({
18998
+ name: "cc/version",
18999
+ pass: !isRisky,
19000
+ detail: isRisky ? `CC version ${ver} \u2014 \u22652.1.119 ships native binary only. Pin: npm install -g @anthropic-ai/claude-code@2.1.98` : `CC version ${ver}`
19001
+ });
19002
+ }
19003
+ } catch {
19004
+ }
19005
+ return results;
19006
+ }
19007
+ function runHealthCheck() {
19008
+ const pkgRoot = findPackageRoot2();
19009
+ const results = [
19010
+ ...checkBuildIntegrity(pkgRoot),
19011
+ ...checkEmbedPipeline(pkgRoot),
19012
+ ...checkTaskSystem(pkgRoot),
19013
+ ...checkWorkerSpawning(pkgRoot),
19014
+ ...checkMcpTransport(),
19015
+ ...checkClaudeCodeInstall()
19016
+ ];
19017
+ const passed = results.filter((r) => r.pass).length;
19018
+ const failed = results.filter((r) => !r.pass).length;
19019
+ return { results, passed, failed };
19020
+ }
19021
+ var init_exe_healthcheck = __esm({
19022
+ "src/bin/exe-healthcheck.ts"() {
19023
+ "use strict";
19024
+ init_is_main();
19025
+ init_config();
19026
+ init_mcp_transport_health();
19027
+ if (isMainModule(import.meta.url) && (process.argv[1] ?? "").includes("exe-healthcheck")) {
19028
+ const { results, passed, failed } = runHealthCheck();
19029
+ console.log("\n exe-os Health Check\n");
19030
+ for (const r of results) {
19031
+ const icon = r.pass ? "\x1B[32m\u2713\x1B[0m" : "\x1B[31m\u2717\x1B[0m";
19032
+ console.log(` ${icon} ${r.name}`);
19033
+ console.log(` ${r.detail}`);
19034
+ }
19035
+ console.log(`
19036
+ ${passed} passed, ${failed} failed
19037
+ `);
19038
+ process.exit(failed > 0 ? 1 : 0);
19039
+ }
19040
+ }
19041
+ });
19042
+
19043
+ // src/bin/cc-doctor.ts
19044
+ var cc_doctor_exports = {};
19045
+ __export(cc_doctor_exports, {
19046
+ runCcDoctor: () => runCcDoctor
19047
+ });
19048
+ function formatResult(r) {
19049
+ const icon = r.pass ? "\x1B[32m\u2713\x1B[0m" : "\x1B[31m\u2717\x1B[0m";
19050
+ const label = LABELS[r.name] ?? r.name;
19051
+ return `${icon} ${label}: ${r.detail}`;
19052
+ }
19053
+ function runCcDoctor() {
19054
+ const results = checkClaudeCodeInstall();
19055
+ const passed = results.filter((r) => r.pass).length;
19056
+ const failed = results.filter((r) => !r.pass).length;
19057
+ return { results, passed, failed };
19058
+ }
19059
+ var LABELS;
19060
+ var init_cc_doctor = __esm({
19061
+ "src/bin/cc-doctor.ts"() {
19062
+ "use strict";
19063
+ init_exe_healthcheck();
19064
+ init_is_main();
19065
+ LABELS = {
19066
+ "cc/execpath-clean": "EXECPATH",
19067
+ "cc/cli-binary": "Symlink",
19068
+ "cc/native-cache-clean": "Native cache",
19069
+ "cc/autoupdater-disabled": "Auto-updater",
19070
+ "cc/version": "Version"
19071
+ };
19072
+ if (isMainModule(import.meta.url) && (process.argv[1] ?? "").includes("cc-doctor")) {
19073
+ const { results, passed, failed } = runCcDoctor();
19074
+ console.log("\n CC Install Health Check\n");
19075
+ for (const r of results) {
19076
+ console.log(` ${formatResult(r)}`);
19077
+ }
19078
+ if (failed === 0) {
19079
+ console.log(`
19080
+ \x1B[32mStatus: CLEAN\x1B[0m \u2014 no 20K billing risk (${passed} checks passed)
19081
+ `);
19082
+ } else {
19083
+ console.log(`
19084
+ \x1B[31mStatus: ${failed} ISSUE${failed > 1 ? "S" : ""} FOUND\x1B[0m \u2014 ${passed} passed, ${failed} failed`);
19085
+ console.log(" Fix: npm install -g @anthropic-ai/claude-code@2.1.98\n");
19086
+ }
19087
+ process.exit(failed > 0 ? 1 : 0);
19088
+ }
19089
+ }
19090
+ });
19091
+
18015
19092
  // src/lib/model-downloader.ts
18016
- import { createWriteStream, createReadStream as createReadStream2, existsSync as existsSync30, unlinkSync as unlinkSync14, renameSync as renameSync7 } from "fs";
19093
+ import { createWriteStream, createReadStream as createReadStream2, existsSync as existsSync32, unlinkSync as unlinkSync14, renameSync as renameSync7 } from "fs";
18017
19094
  import { mkdir as mkdir6 } from "fs/promises";
18018
19095
  import { createHash as createHash6 } from "crypto";
18019
- import path37 from "path";
19096
+ import path39 from "path";
18020
19097
  async function downloadModel(opts) {
18021
19098
  const { destDir, onProgress, fetchFn = globalThis.fetch } = opts;
18022
- const destPath = path37.join(destDir, LOCAL_FILENAME);
19099
+ const destPath = path39.join(destDir, LOCAL_FILENAME);
18023
19100
  const tmpPath = destPath + ".tmp";
18024
19101
  await mkdir6(destDir, { recursive: true });
18025
- if (existsSync30(destPath)) {
19102
+ if (existsSync32(destPath)) {
18026
19103
  const hash = await fileHash(destPath);
18027
19104
  if (hash === EXPECTED_SHA256) {
18028
19105
  return destPath;
@@ -18034,7 +19111,7 @@ async function downloadModel(opts) {
18034
19111
  let downloaded = 0;
18035
19112
  for (let attempt = 1; attempt <= MAX_RETRIES4; attempt++) {
18036
19113
  try {
18037
- if (existsSync30(tmpPath)) unlinkSync14(tmpPath);
19114
+ if (existsSync32(tmpPath)) unlinkSync14(tmpPath);
18038
19115
  const response = await fetchFn(GGUF_URL, {
18039
19116
  redirect: "follow",
18040
19117
  signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS)
@@ -18079,7 +19156,7 @@ async function downloadModel(opts) {
18079
19156
  process.stderr.write(`
18080
19157
  Download attempt ${attempt} failed, retrying...
18081
19158
  `);
18082
- if (existsSync30(tmpPath)) unlinkSync14(tmpPath);
19159
+ if (existsSync32(tmpPath)) unlinkSync14(tmpPath);
18083
19160
  }
18084
19161
  }
18085
19162
  }
@@ -18656,38 +19733,38 @@ __export(session_wrappers_exports, {
18656
19733
  generateSessionWrappers: () => generateSessionWrappers
18657
19734
  });
18658
19735
  import {
18659
- existsSync as existsSync31,
18660
- readFileSync as readFileSync26,
18661
- writeFileSync as writeFileSync23,
18662
- mkdirSync as mkdirSync22,
19736
+ existsSync as existsSync33,
19737
+ readFileSync as readFileSync28,
19738
+ writeFileSync as writeFileSync24,
19739
+ mkdirSync as mkdirSync23,
18663
19740
  chmodSync as chmodSync4,
18664
- readdirSync as readdirSync9,
19741
+ readdirSync as readdirSync10,
18665
19742
  unlinkSync as unlinkSync15
18666
19743
  } from "fs";
18667
- import { execSync as execSync14 } from "child_process";
18668
- import path38 from "path";
19744
+ import { execSync as execSync15 } from "child_process";
19745
+ import path40 from "path";
18669
19746
  import { homedir as homedir5 } from "os";
18670
19747
  function generateSessionWrappers(packageRoot, homeDir) {
18671
19748
  const home = homeDir ?? homedir5();
18672
- const binDir = path38.join(home, ".exe-os", "bin");
18673
- const rosterPath = path38.join(home, ".exe-os", "exe-employees.json");
19749
+ const binDir = path40.join(home, ".exe-os", "bin");
19750
+ const rosterPath = path40.join(home, ".exe-os", "exe-employees.json");
18674
19751
  const shouldMirrorToGlobalBin = homeDir === void 0;
18675
- mkdirSync22(binDir, { recursive: true });
18676
- const exeStartDst = path38.join(binDir, "exe-start");
19752
+ mkdirSync23(binDir, { recursive: true });
19753
+ const exeStartDst = path40.join(binDir, "exe-start");
18677
19754
  const candidates = [
18678
- path38.join(packageRoot, "dist", "bin", "exe-start.sh"),
18679
- path38.join(packageRoot, "src", "bin", "exe-start.sh")
19755
+ path40.join(packageRoot, "dist", "bin", "exe-start.sh"),
19756
+ path40.join(packageRoot, "src", "bin", "exe-start.sh")
18680
19757
  ];
18681
19758
  for (const src of candidates) {
18682
- if (existsSync31(src)) {
18683
- writeFileSync23(exeStartDst, readFileSync26(src));
19759
+ if (existsSync33(src)) {
19760
+ writeFileSync24(exeStartDst, readFileSync28(src));
18684
19761
  chmodSync4(exeStartDst, 493);
18685
19762
  break;
18686
19763
  }
18687
19764
  }
18688
19765
  let employees = [];
18689
19766
  try {
18690
- employees = JSON.parse(readFileSync26(rosterPath, "utf8"));
19767
+ employees = JSON.parse(readFileSync28(rosterPath, "utf8"));
18691
19768
  } catch {
18692
19769
  return { created: 0, pathConfigured: false };
18693
19770
  }
@@ -18695,11 +19772,11 @@ function generateSessionWrappers(packageRoot, homeDir) {
18695
19772
  return { created: 0, pathConfigured: false };
18696
19773
  }
18697
19774
  try {
18698
- for (const f of readdirSync9(binDir)) {
19775
+ for (const f of readdirSync10(binDir)) {
18699
19776
  if (f === "exe-start") continue;
18700
- const fPath = path38.join(binDir, f);
19777
+ const fPath = path40.join(binDir, f);
18701
19778
  try {
18702
- const content = readFileSync26(fPath, "utf8");
19779
+ const content = readFileSync28(fPath, "utf8");
18703
19780
  if (content.includes("exe-start")) {
18704
19781
  unlinkSync15(fPath);
18705
19782
  }
@@ -18715,36 +19792,36 @@ exec "${exeStartDst}" "$0" "$@"
18715
19792
  const globalBinDir = shouldMirrorToGlobalBin ? resolveGlobalBinDir() : null;
18716
19793
  for (const emp of employees) {
18717
19794
  for (let n = 1; n <= MAX_N; n++) {
18718
- writeWrapper(path38.join(binDir, `${emp.name}${n}`), wrapperContent);
19795
+ writeWrapper(path40.join(binDir, `${emp.name}${n}`), wrapperContent);
18719
19796
  if (globalBinDir) {
18720
- writeWrapper(path38.join(globalBinDir, `${emp.name}${n}`), wrapperContent);
19797
+ writeWrapper(path40.join(globalBinDir, `${emp.name}${n}`), wrapperContent);
18721
19798
  }
18722
19799
  created++;
18723
- writeWrapper(path38.join(binDir, `${emp.name}${n}-codex`), wrapperContent);
19800
+ writeWrapper(path40.join(binDir, `${emp.name}${n}-codex`), wrapperContent);
18724
19801
  if (globalBinDir) {
18725
- writeWrapper(path38.join(globalBinDir, `${emp.name}${n}-codex`), wrapperContent);
19802
+ writeWrapper(path40.join(globalBinDir, `${emp.name}${n}-codex`), wrapperContent);
18726
19803
  }
18727
19804
  created++;
18728
19805
  }
18729
19806
  }
18730
19807
  const codexLauncherCandidates = [
18731
- path38.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
18732
- path38.join(packageRoot, "src", "bin", "exe-start-codex.ts")
19808
+ path40.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
19809
+ path40.join(packageRoot, "src", "bin", "exe-start-codex.ts")
18733
19810
  ];
18734
19811
  let codexLauncher = null;
18735
19812
  for (const c of codexLauncherCandidates) {
18736
- if (existsSync31(c)) {
19813
+ if (existsSync33(c)) {
18737
19814
  codexLauncher = c;
18738
19815
  break;
18739
19816
  }
18740
19817
  }
18741
19818
  if (codexLauncher) {
18742
19819
  for (const emp of employees) {
18743
- const wrapperPath = path38.join(binDir, `${emp.name}-codex`);
19820
+ const wrapperPath = path40.join(binDir, `${emp.name}-codex`);
18744
19821
  const content = `#!/bin/bash
18745
19822
  exec node "${codexLauncher}" --agent ${emp.name} "$@"
18746
19823
  `;
18747
- writeFileSync23(wrapperPath, content);
19824
+ writeFileSync24(wrapperPath, content);
18748
19825
  chmodSync4(wrapperPath, 493);
18749
19826
  created++;
18750
19827
  }
@@ -18754,20 +19831,20 @@ exec node "${codexLauncher}" --agent ${emp.name} "$@"
18754
19831
  }
18755
19832
  function writeWrapper(wrapperPath, content) {
18756
19833
  try {
18757
- writeFileSync23(wrapperPath, content);
19834
+ writeFileSync24(wrapperPath, content);
18758
19835
  chmodSync4(wrapperPath, 493);
18759
19836
  } catch {
18760
19837
  }
18761
19838
  }
18762
19839
  function resolveGlobalBinDir() {
18763
19840
  try {
18764
- const exeOsPath = execSync14("command -v exe-os", { encoding: "utf8", timeout: 3e3 }).trim().split("\n")[0];
18765
- if (exeOsPath) return path38.dirname(exeOsPath);
19841
+ const exeOsPath = execSync15("command -v exe-os", { encoding: "utf8", timeout: 3e3 }).trim().split("\n")[0];
19842
+ if (exeOsPath) return path40.dirname(exeOsPath);
18766
19843
  } catch {
18767
19844
  }
18768
19845
  try {
18769
- const prefix = execSync14("npm prefix -g", { encoding: "utf8", timeout: 3e3 }).trim();
18770
- if (prefix) return path38.join(prefix, "bin");
19846
+ const prefix = execSync15("npm prefix -g", { encoding: "utf8", timeout: 3e3 }).trim();
19847
+ if (prefix) return path40.join(prefix, "bin");
18771
19848
  } catch {
18772
19849
  }
18773
19850
  return null;
@@ -18783,24 +19860,24 @@ export PATH="${binDir}:$PATH"
18783
19860
  const shell = process.env.SHELL ?? "/bin/bash";
18784
19861
  const profilePaths = [];
18785
19862
  if (shell.includes("zsh")) {
18786
- profilePaths.push(path38.join(home, ".zshrc"));
19863
+ profilePaths.push(path40.join(home, ".zshrc"));
18787
19864
  } else if (shell.includes("bash")) {
18788
- profilePaths.push(path38.join(home, ".bashrc"));
18789
- profilePaths.push(path38.join(home, ".bash_profile"));
19865
+ profilePaths.push(path40.join(home, ".bashrc"));
19866
+ profilePaths.push(path40.join(home, ".bash_profile"));
18790
19867
  } else {
18791
- profilePaths.push(path38.join(home, ".profile"));
19868
+ profilePaths.push(path40.join(home, ".profile"));
18792
19869
  }
18793
19870
  for (const profilePath of profilePaths) {
18794
19871
  try {
18795
19872
  let content = "";
18796
19873
  try {
18797
- content = readFileSync26(profilePath, "utf8");
19874
+ content = readFileSync28(profilePath, "utf8");
18798
19875
  } catch {
18799
19876
  }
18800
19877
  if (content.includes(".exe-os/bin")) {
18801
19878
  return false;
18802
19879
  }
18803
- writeFileSync23(profilePath, content + exportLine);
19880
+ writeFileSync24(profilePath, content + exportLine);
18804
19881
  return true;
18805
19882
  } catch {
18806
19883
  continue;
@@ -18823,36 +19900,36 @@ __export(setup_wizard_exports, {
18823
19900
  validateModel: () => validateModel
18824
19901
  });
18825
19902
  import crypto13 from "crypto";
18826
- import { existsSync as existsSync32, mkdirSync as mkdirSync23, readFileSync as readFileSync27, writeFileSync as writeFileSync24, unlinkSync as unlinkSync16 } from "fs";
19903
+ import { existsSync as existsSync34, mkdirSync as mkdirSync24, readFileSync as readFileSync29, writeFileSync as writeFileSync25, unlinkSync as unlinkSync16 } from "fs";
18827
19904
  import os19 from "os";
18828
- import path39 from "path";
19905
+ import path41 from "path";
18829
19906
  import { createInterface as createInterface4 } from "readline";
18830
- function findPackageRoot2() {
18831
- let dir = path39.dirname(new URL(import.meta.url).pathname);
18832
- const root = path39.parse(dir).root;
19907
+ function findPackageRoot3() {
19908
+ let dir = path41.dirname(new URL(import.meta.url).pathname);
19909
+ const root = path41.parse(dir).root;
18833
19910
  while (dir !== root) {
18834
- const pkgPath = path39.join(dir, "package.json");
18835
- if (existsSync32(pkgPath)) {
19911
+ const pkgPath = path41.join(dir, "package.json");
19912
+ if (existsSync34(pkgPath)) {
18836
19913
  try {
18837
- const pkg = JSON.parse(readFileSync27(pkgPath, "utf-8"));
19914
+ const pkg = JSON.parse(readFileSync29(pkgPath, "utf-8"));
18838
19915
  if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
18839
19916
  } catch {
18840
19917
  }
18841
19918
  }
18842
- dir = path39.dirname(dir);
19919
+ dir = path41.dirname(dir);
18843
19920
  }
18844
19921
  return null;
18845
19922
  }
18846
19923
  function loadSetupState() {
18847
19924
  try {
18848
- return JSON.parse(readFileSync27(SETUP_STATE_PATH, "utf8"));
19925
+ return JSON.parse(readFileSync29(SETUP_STATE_PATH, "utf8"));
18849
19926
  } catch {
18850
19927
  return { completedSteps: [], startedAt: (/* @__PURE__ */ new Date()).toISOString() };
18851
19928
  }
18852
19929
  }
18853
19930
  function saveSetupState(state) {
18854
- mkdirSync23(path39.dirname(SETUP_STATE_PATH), { recursive: true });
18855
- writeFileSync24(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
19931
+ mkdirSync24(path41.dirname(SETUP_STATE_PATH), { recursive: true });
19932
+ writeFileSync25(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
18856
19933
  }
18857
19934
  function clearSetupState() {
18858
19935
  try {
@@ -18873,8 +19950,8 @@ function ask3(rl, prompt) {
18873
19950
  function getAvailableMemoryGB2() {
18874
19951
  if (process.platform === "darwin") {
18875
19952
  try {
18876
- const { execSync: execSync19 } = __require("child_process");
18877
- const vmstat = execSync19("vm_stat", { encoding: "utf8" });
19953
+ const { execSync: execSync20 } = __require("child_process");
19954
+ const vmstat = execSync20("vm_stat", { encoding: "utf8" });
18878
19955
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
18879
19956
  const pageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : 16384;
18880
19957
  const free = vmstat.match(/Pages free:\s+(\d+)/);
@@ -18902,10 +19979,10 @@ async function validateModel(log) {
18902
19979
  if (totalGB <= 8 || isLowMemory()) {
18903
19980
  log(`System memory: ${totalGB.toFixed(0)}GB total, ${freeGB.toFixed(1)}GB free`);
18904
19981
  log("Skipping in-memory model validation (low memory \u2014 will validate on first use).");
18905
- const modelPath = path39.join(MODELS_DIR, LOCAL_FILENAME);
18906
- if (existsSync32(modelPath)) {
18907
- const { statSync: statSync8 } = await import("fs");
18908
- const size = statSync8(modelPath).size;
19982
+ const modelPath = path41.join(MODELS_DIR, LOCAL_FILENAME);
19983
+ if (existsSync34(modelPath)) {
19984
+ const { statSync: statSync9 } = await import("fs");
19985
+ const size = statSync9(modelPath).size;
18909
19986
  if (size > 300 * 1e6) {
18910
19987
  log(`Model file verified (${(size / 1e6).toFixed(0)} MB).`);
18911
19988
  return;
@@ -18998,7 +20075,7 @@ async function runSetupWizard(opts = {}) {
18998
20075
  if (state.completedSteps.length > 0) {
18999
20076
  log(`Resuming setup from step ${Math.max(...state.completedSteps) + 1}...`);
19000
20077
  }
19001
- if (existsSync32(LEGACY_LANCE_PATH)) {
20078
+ if (existsSync34(LEGACY_LANCE_PATH)) {
19002
20079
  log("\u26A0 Found v1.0 LanceDB at ~/.exe-os/local.lance");
19003
20080
  log(" v1.1 uses libSQL (SQLite). Your existing memories are not automatically migrated.");
19004
20081
  log(" The old directory will not be modified or deleted.");
@@ -19189,10 +20266,10 @@ async function runSetupWizard(opts = {}) {
19189
20266
  await saveConfig(config);
19190
20267
  log("");
19191
20268
  try {
19192
- const claudeJsonPath = path39.join(os19.homedir(), ".claude.json");
20269
+ const claudeJsonPath = path41.join(os19.homedir(), ".claude.json");
19193
20270
  let claudeJson = {};
19194
20271
  try {
19195
- claudeJson = JSON.parse(readFileSync27(claudeJsonPath, "utf8"));
20272
+ claudeJson = JSON.parse(readFileSync29(claudeJsonPath, "utf8"));
19196
20273
  } catch {
19197
20274
  }
19198
20275
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -19201,7 +20278,7 @@ async function runSetupWizard(opts = {}) {
19201
20278
  if (!projects[dir]) projects[dir] = {};
19202
20279
  projects[dir].hasTrustDialogAccepted = true;
19203
20280
  }
19204
- writeFileSync24(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
20281
+ writeFileSync25(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
19205
20282
  } catch {
19206
20283
  }
19207
20284
  state.completedSteps.push(5);
@@ -19215,7 +20292,7 @@ async function runSetupWizard(opts = {}) {
19215
20292
  const prefs = { ...existingPrefs };
19216
20293
  log("=== Config Defaults ===");
19217
20294
  log("");
19218
- const ghosttyDetected = existsSync32(path39.join(os19.homedir(), ".config", "ghostty")) || existsSync32(path39.join(os19.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
20295
+ const ghosttyDetected = existsSync34(path41.join(os19.homedir(), ".config", "ghostty")) || existsSync34(path41.join(os19.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
19219
20296
  if (ghosttyDetected) {
19220
20297
  const ghosttyAnswer = await ask3(rl, "Detected Ghostty terminal. Use exe-os Ghostty defaults? (Y/n) ");
19221
20298
  prefs.ghostty = ghosttyAnswer.toLowerCase() !== "n";
@@ -19262,7 +20339,7 @@ async function runSetupWizard(opts = {}) {
19262
20339
  let missingIdentities = [];
19263
20340
  for (const emp of roster) {
19264
20341
  const idPath = identityPath2(emp.name);
19265
- if (!existsSync32(idPath)) {
20342
+ if (!existsSync34(idPath)) {
19266
20343
  missingIdentities.push(emp.name);
19267
20344
  }
19268
20345
  }
@@ -19294,7 +20371,7 @@ async function runSetupWizard(opts = {}) {
19294
20371
  }
19295
20372
  missingIdentities = [];
19296
20373
  for (const emp of roster) {
19297
- if (!existsSync32(identityPath2(emp.name))) {
20374
+ if (!existsSync34(identityPath2(emp.name))) {
19298
20375
  missingIdentities.push(emp.name);
19299
20376
  }
19300
20377
  }
@@ -19312,7 +20389,7 @@ async function runSetupWizard(opts = {}) {
19312
20389
  }
19313
20390
  try {
19314
20391
  const { generateSessionWrappers: generateSessionWrappers2 } = await Promise.resolve().then(() => (init_session_wrappers(), session_wrappers_exports));
19315
- const pkgRoot = findPackageRoot2();
20392
+ const pkgRoot = findPackageRoot3();
19316
20393
  if (pkgRoot) {
19317
20394
  const wrapResult = generateSessionWrappers2(pkgRoot);
19318
20395
  if (wrapResult.created > 0) {
@@ -19353,9 +20430,9 @@ async function runSetupWizard(opts = {}) {
19353
20430
  const cooIdentityContent = getIdentityTemplate("coo");
19354
20431
  if (cooIdentityContent) {
19355
20432
  const cooIdPath = identityPath2(cooName);
19356
- mkdirSync23(path39.dirname(cooIdPath), { recursive: true });
20433
+ mkdirSync24(path41.dirname(cooIdPath), { recursive: true });
19357
20434
  const replaced = cooIdentityContent.replace(/agent_id:\s*exe/g, `agent_id: ${cooName}`).replace(/\$\{agent_id\}/g, cooName);
19358
- writeFileSync24(cooIdPath, replaced, "utf-8");
20435
+ writeFileSync25(cooIdPath, replaced, "utf-8");
19359
20436
  }
19360
20437
  registerBinSymlinks2(cooName);
19361
20438
  createdEmployees.push({ name: cooName, role: "COO" });
@@ -19471,9 +20548,9 @@ async function runSetupWizard(opts = {}) {
19471
20548
  const ctoIdentityContent = getIdentityTemplate("cto");
19472
20549
  if (ctoIdentityContent) {
19473
20550
  const ctoIdPath = identityPath2(ctoName);
19474
- mkdirSync23(path39.dirname(ctoIdPath), { recursive: true });
20551
+ mkdirSync24(path41.dirname(ctoIdPath), { recursive: true });
19475
20552
  const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
19476
- writeFileSync24(ctoIdPath, replaced, "utf-8");
20553
+ writeFileSync25(ctoIdPath, replaced, "utf-8");
19477
20554
  }
19478
20555
  registerBinSymlinks2(ctoName);
19479
20556
  createdEmployees.push({ name: ctoName, role: "CTO" });
@@ -19494,9 +20571,9 @@ async function runSetupWizard(opts = {}) {
19494
20571
  const cmoIdentityContent = getIdentityTemplate("cmo");
19495
20572
  if (cmoIdentityContent) {
19496
20573
  const cmoIdPath = identityPath2(cmoName);
19497
- mkdirSync23(path39.dirname(cmoIdPath), { recursive: true });
20574
+ mkdirSync24(path41.dirname(cmoIdPath), { recursive: true });
19498
20575
  const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
19499
- writeFileSync24(cmoIdPath, replaced, "utf-8");
20576
+ writeFileSync25(cmoIdPath, replaced, "utf-8");
19500
20577
  }
19501
20578
  registerBinSymlinks2(cmoName);
19502
20579
  createdEmployees.push({ name: cmoName, role: "CMO" });
@@ -19512,14 +20589,14 @@ async function runSetupWizard(opts = {}) {
19512
20589
  if (!pairingRosterPulled) {
19513
20590
  try {
19514
20591
  const { generateSessionWrappers: generateSessionWrappers2 } = await Promise.resolve().then(() => (init_session_wrappers(), session_wrappers_exports));
19515
- const pkgRoot = findPackageRoot2();
20592
+ const pkgRoot = findPackageRoot3();
19516
20593
  if (pkgRoot) {
19517
20594
  const wrapResult = generateSessionWrappers2(pkgRoot);
19518
20595
  if (wrapResult.created > 0) {
19519
20596
  log(`Session shortcuts generated (${cooName}1, ${cooName}2, ...)`);
19520
20597
  }
19521
20598
  if (wrapResult.pathConfigured) {
19522
- const binDir = path39.join(os19.homedir(), ".exe-os", "bin");
20599
+ const binDir = path41.join(os19.homedir(), ".exe-os", "bin");
19523
20600
  process.env.PATH = `${binDir}:${process.env.PATH ?? ""}`;
19524
20601
  pathJustConfigured = true;
19525
20602
  }
@@ -19559,10 +20636,10 @@ async function runSetupWizard(opts = {}) {
19559
20636
  log("Team: " + createdEmployees.map((e) => `${e.name} (${e.role})`).join(", "));
19560
20637
  }
19561
20638
  let version = "";
19562
- const pkgRoot2 = findPackageRoot2();
20639
+ const pkgRoot2 = findPackageRoot3();
19563
20640
  if (pkgRoot2) {
19564
20641
  try {
19565
- version = JSON.parse(readFileSync27(path39.join(pkgRoot2, "package.json"), "utf-8")).version;
20642
+ version = JSON.parse(readFileSync29(path41.join(pkgRoot2, "package.json"), "utf-8")).version;
19566
20643
  } catch {
19567
20644
  }
19568
20645
  }
@@ -19601,46 +20678,46 @@ var init_setup_wizard = __esm({
19601
20678
  init_config();
19602
20679
  init_keychain();
19603
20680
  init_model_downloader();
19604
- SETUP_STATE_PATH = path39.join(os19.homedir(), ".exe-os", "setup-state.json");
20681
+ SETUP_STATE_PATH = path41.join(os19.homedir(), ".exe-os", "setup-state.json");
19605
20682
  }
19606
20683
  });
19607
20684
 
19608
20685
  // src/lib/update-backup.ts
19609
20686
  import { copyFile, readFile as readFile6, readdir as readdir3, writeFile as writeFile7, rm as rm2, mkdir as mkdir7, cp } from "fs/promises";
19610
- import { existsSync as existsSync33 } from "fs";
19611
- import path40 from "path";
20687
+ import { existsSync as existsSync35 } from "fs";
20688
+ import path42 from "path";
19612
20689
  import os20 from "os";
19613
20690
  function resolveDataDir2() {
19614
20691
  if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
19615
20692
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
19616
- return path40.join(os20.homedir(), ".exe-os");
20693
+ return path42.join(os20.homedir(), ".exe-os");
19617
20694
  }
19618
20695
  function externalBackupTargets(homeDir) {
19619
20696
  return [
19620
- { name: "claude.json", path: path40.join(homeDir, ".claude.json") },
19621
- { name: "claude-settings.json", path: path40.join(homeDir, ".claude", "settings.json") },
19622
- { name: "claude-CLAUDE.md", path: path40.join(homeDir, ".claude", "CLAUDE.md") },
19623
- { name: "tmux.conf", path: path40.join(homeDir, ".tmux.conf") },
19624
- { name: "zshrc", path: path40.join(homeDir, ".zshrc") },
19625
- { name: "bashrc", path: path40.join(homeDir, ".bashrc") },
19626
- { name: "ghostty-config", path: path40.join(homeDir, ".config", "ghostty", "config") },
19627
- { name: "codex-config.toml", path: path40.join(homeDir, ".codex", "config.toml") },
19628
- { name: "codex-hooks.json", path: path40.join(homeDir, ".codex", "hooks.json") },
19629
- { name: "opencode-config.json", path: path40.join(homeDir, ".config", "opencode", "opencode.json") }
20697
+ { name: "claude.json", path: path42.join(homeDir, ".claude.json") },
20698
+ { name: "claude-settings.json", path: path42.join(homeDir, ".claude", "settings.json") },
20699
+ { name: "claude-CLAUDE.md", path: path42.join(homeDir, ".claude", "CLAUDE.md") },
20700
+ { name: "tmux.conf", path: path42.join(homeDir, ".tmux.conf") },
20701
+ { name: "zshrc", path: path42.join(homeDir, ".zshrc") },
20702
+ { name: "bashrc", path: path42.join(homeDir, ".bashrc") },
20703
+ { name: "ghostty-config", path: path42.join(homeDir, ".config", "ghostty", "config") },
20704
+ { name: "codex-config.toml", path: path42.join(homeDir, ".codex", "config.toml") },
20705
+ { name: "codex-hooks.json", path: path42.join(homeDir, ".codex", "hooks.json") },
20706
+ { name: "opencode-config.json", path: path42.join(homeDir, ".config", "opencode", "opencode.json") }
19630
20707
  ];
19631
20708
  }
19632
20709
  async function createUpdateBackup(currentVersion, dataDir2, homeDir = os20.homedir()) {
19633
20710
  const dir = dataDir2 ?? resolveDataDir2();
19634
- const backupDir = path40.join(dir, BACKUP_DIR_NAME);
19635
- if (existsSync33(backupDir)) {
20711
+ const backupDir = path42.join(dir, BACKUP_DIR_NAME);
20712
+ if (existsSync35(backupDir)) {
19636
20713
  await rm2(backupDir, { recursive: true, force: true });
19637
20714
  }
19638
20715
  await mkdir7(backupDir, { recursive: true });
19639
20716
  const backedUpFiles = [];
19640
20717
  for (const target of BACKUP_TARGETS) {
19641
- const src = path40.join(dir, target.name);
19642
- if (!existsSync33(src)) continue;
19643
- const dest = path40.join(backupDir, target.name);
20718
+ const src = path42.join(dir, target.name);
20719
+ if (!existsSync35(src)) continue;
20720
+ const dest = path42.join(backupDir, target.name);
19644
20721
  if (target.type === "file") {
19645
20722
  await copyFile(src, dest);
19646
20723
  } else {
@@ -19651,18 +20728,18 @@ async function createUpdateBackup(currentVersion, dataDir2, homeDir = os20.homed
19651
20728
  const entries = await readdir3(dir, { withFileTypes: true });
19652
20729
  for (const entry of entries) {
19653
20730
  if (entry.isFile() && entry.name.endsWith(".db") && entry.name !== BACKUP_DIR_NAME) {
19654
- const src = path40.join(dir, entry.name);
19655
- const dest = path40.join(backupDir, entry.name);
20731
+ const src = path42.join(dir, entry.name);
20732
+ const dest = path42.join(backupDir, entry.name);
19656
20733
  await copyFile(src, dest);
19657
20734
  backedUpFiles.push(entry.name);
19658
20735
  }
19659
20736
  }
19660
20737
  const externalFiles = [];
19661
- const externalDir = path40.join(backupDir, "external");
20738
+ const externalDir = path42.join(backupDir, "external");
19662
20739
  for (const target of externalBackupTargets(homeDir)) {
19663
- if (!existsSync33(target.path)) continue;
20740
+ if (!existsSync35(target.path)) continue;
19664
20741
  await mkdir7(externalDir, { recursive: true });
19665
- await copyFile(target.path, path40.join(externalDir, target.name));
20742
+ await copyFile(target.path, path42.join(externalDir, target.name));
19666
20743
  externalFiles.push(target);
19667
20744
  }
19668
20745
  const manifest = {
@@ -19672,16 +20749,16 @@ async function createUpdateBackup(currentVersion, dataDir2, homeDir = os20.homed
19672
20749
  ...externalFiles.length > 0 ? { externalFiles } : {}
19673
20750
  };
19674
20751
  await writeFile7(
19675
- path40.join(backupDir, "manifest.json"),
20752
+ path42.join(backupDir, "manifest.json"),
19676
20753
  JSON.stringify(manifest, null, 2) + "\n"
19677
20754
  );
19678
20755
  return manifest;
19679
20756
  }
19680
20757
  async function restoreFromBackup(dataDir2) {
19681
20758
  const dir = dataDir2 ?? resolveDataDir2();
19682
- const backupDir = path40.join(dir, BACKUP_DIR_NAME);
19683
- const manifestPath = path40.join(backupDir, "manifest.json");
19684
- if (!existsSync33(manifestPath)) {
20759
+ const backupDir = path42.join(dir, BACKUP_DIR_NAME);
20760
+ const manifestPath = path42.join(backupDir, "manifest.json");
20761
+ if (!existsSync35(manifestPath)) {
19685
20762
  throw new Error(
19686
20763
  `No backup found at ${backupDir}. Nothing to restore.`
19687
20764
  );
@@ -19690,9 +20767,9 @@ async function restoreFromBackup(dataDir2) {
19690
20767
  await readFile6(manifestPath, "utf-8")
19691
20768
  );
19692
20769
  for (const fileName of manifest.files) {
19693
- const src = path40.join(backupDir, fileName);
19694
- const dest = path40.join(dir, fileName);
19695
- if (!existsSync33(src)) continue;
20770
+ const src = path42.join(backupDir, fileName);
20771
+ const dest = path42.join(dir, fileName);
20772
+ if (!existsSync35(src)) continue;
19696
20773
  const stat2 = await import("fs/promises").then((m) => m.stat(src));
19697
20774
  if (stat2.isDirectory()) {
19698
20775
  await cp(src, dest, { recursive: true, force: true });
@@ -19701,17 +20778,17 @@ async function restoreFromBackup(dataDir2) {
19701
20778
  }
19702
20779
  }
19703
20780
  for (const external of manifest.externalFiles ?? []) {
19704
- const src = path40.join(backupDir, "external", external.name);
19705
- if (!existsSync33(src)) continue;
19706
- await mkdir7(path40.dirname(external.path), { recursive: true });
20781
+ const src = path42.join(backupDir, "external", external.name);
20782
+ if (!existsSync35(src)) continue;
20783
+ await mkdir7(path42.dirname(external.path), { recursive: true });
19707
20784
  await copyFile(src, external.path);
19708
20785
  }
19709
20786
  return manifest;
19710
20787
  }
19711
20788
  async function deleteBackup(dataDir2) {
19712
20789
  const dir = dataDir2 ?? resolveDataDir2();
19713
- const backupDir = path40.join(dir, BACKUP_DIR_NAME);
19714
- if (existsSync33(backupDir)) {
20790
+ const backupDir = path42.join(dir, BACKUP_DIR_NAME);
20791
+ if (existsSync35(backupDir)) {
19715
20792
  await rm2(backupDir, { recursive: true, force: true });
19716
20793
  }
19717
20794
  }
@@ -19735,17 +20812,17 @@ var init_update_backup = __esm({
19735
20812
  });
19736
20813
 
19737
20814
  // src/lib/update-check.ts
19738
- import { execSync as execSync15 } from "child_process";
19739
- import { readFileSync as readFileSync28 } from "fs";
19740
- import path41 from "path";
20815
+ import { execSync as execSync16 } from "child_process";
20816
+ import { readFileSync as readFileSync30 } from "fs";
20817
+ import path43 from "path";
19741
20818
  function getLocalVersion(packageRoot) {
19742
- const pkgPath = path41.join(packageRoot, "package.json");
19743
- const pkg = JSON.parse(readFileSync28(pkgPath, "utf-8"));
20819
+ const pkgPath = path43.join(packageRoot, "package.json");
20820
+ const pkg = JSON.parse(readFileSync30(pkgPath, "utf-8"));
19744
20821
  return pkg.version;
19745
20822
  }
19746
20823
  function getRemoteVersion() {
19747
20824
  try {
19748
- const output2 = execSync15("npm view @askexenow/exe-os version", {
20825
+ const output2 = execSync16("npm view @askexenow/exe-os version", {
19749
20826
  encoding: "utf-8",
19750
20827
  timeout: 15e3,
19751
20828
  stdio: ["pipe", "pipe", "pipe"]
@@ -19784,7 +20861,7 @@ __export(update_exports, {
19784
20861
  getRemoteVersion: () => getRemoteVersion,
19785
20862
  runUpdate: () => runUpdate
19786
20863
  });
19787
- import { execSync as execSync16 } from "child_process";
20864
+ import { execSync as execSync17 } from "child_process";
19788
20865
  import { createInterface as createInterface5 } from "readline";
19789
20866
  async function runRestore() {
19790
20867
  console.log("\n\u{1F504} Restoring from update backup...");
@@ -19795,7 +20872,7 @@ async function runRestore() {
19795
20872
  console.log(`
19796
20873
  \u{1F4E5} Reinstalling @askexenow/exe-os@${manifest.version}...`);
19797
20874
  try {
19798
- execSync16(`npm install -g @askexenow/exe-os@${manifest.version}`, {
20875
+ execSync17(`npm install -g @askexenow/exe-os@${manifest.version}`, {
19799
20876
  stdio: ["pipe", "pipe", "inherit"],
19800
20877
  timeout: 3e5
19801
20878
  });
@@ -19876,7 +20953,7 @@ async function runUpdate(cliArgs) {
19876
20953
  }
19877
20954
  console.log("\u{1F9F9} Clearing npm cache...");
19878
20955
  try {
19879
- execSync16("npm cache clean --force", { stdio: "pipe" });
20956
+ execSync17("npm cache clean --force", { stdio: "pipe" });
19880
20957
  console.log(" Done");
19881
20958
  } catch {
19882
20959
  console.log(" Skipped (non-critical)");
@@ -19884,7 +20961,7 @@ async function runUpdate(cliArgs) {
19884
20961
  console.log("\u{1F4E5} Installing @askexenow/exe-os@latest...");
19885
20962
  console.log(" This may take a minute...\n");
19886
20963
  try {
19887
- execSync16("npm install -g @askexenow/exe-os@latest", {
20964
+ execSync17("npm install -g @askexenow/exe-os@latest", {
19888
20965
  stdio: ["pipe", "pipe", "inherit"],
19889
20966
  timeout: 3e5
19890
20967
  });
@@ -19902,7 +20979,7 @@ async function runUpdate(cliArgs) {
19902
20979
  newVersion = getLocalVersion(packageRoot);
19903
20980
  } catch {
19904
20981
  try {
19905
- const out = execSync16("npm list -g @askexenow/exe-os --depth=0 2>/dev/null", { encoding: "utf8" });
20982
+ const out = execSync17("npm list -g @askexenow/exe-os --depth=0 2>/dev/null", { encoding: "utf8" });
19906
20983
  const match = out.match(/@askexenow\/exe-os@(\S+)/);
19907
20984
  newVersion = match?.[1] ?? "unknown";
19908
20985
  } catch {
@@ -19931,7 +21008,7 @@ async function runUpdate(cliArgs) {
19931
21008
  }
19932
21009
  console.log("\u{1F527} Re-registering MCP, hooks, wrappers, and daemon...");
19933
21010
  try {
19934
- execSync16("exe-os-install --global", {
21011
+ execSync17("exe-os-install --global", {
19935
21012
  stdio: ["pipe", "inherit", "inherit"],
19936
21013
  timeout: 3e5
19937
21014
  });
@@ -19966,7 +21043,7 @@ async function runUpdate(cliArgs) {
19966
21043
  }
19967
21044
  try {
19968
21045
  console.log("\u{1FA7A} Checking AskExe support intake...");
19969
- execSync16("exe-os support health", {
21046
+ execSync17("exe-os support health", {
19970
21047
  stdio: ["pipe", "inherit", "inherit"],
19971
21048
  timeout: 3e4
19972
21049
  });
@@ -19994,11 +21071,11 @@ var init_update = __esm({
19994
21071
  // src/lib/stack-update.ts
19995
21072
  import { execFileSync as execFileSync4, spawnSync } from "child_process";
19996
21073
  import { createVerify, randomBytes as randomBytes2, verify as verifySignature } from "crypto";
19997
- import { copyFileSync as copyFileSync5, existsSync as existsSync34, mkdirSync as mkdirSync24, readdirSync as readdirSync10, readFileSync as readFileSync29, renameSync as renameSync8, writeFileSync as writeFileSync25 } from "fs";
21074
+ import { copyFileSync as copyFileSync5, existsSync as existsSync36, mkdirSync as mkdirSync25, readdirSync as readdirSync11, readFileSync as readFileSync31, renameSync as renameSync8, writeFileSync as writeFileSync26 } from "fs";
19998
21075
  import http from "http";
19999
21076
  import https from "https";
20000
- import path42 from "path";
20001
- import { fileURLToPath as fileURLToPath5 } from "url";
21077
+ import path44 from "path";
21078
+ import { fileURLToPath as fileURLToPath7 } from "url";
20002
21079
  function isSignedEnvelope(value) {
20003
21080
  return !!value && typeof value === "object" && "manifest" in value && "signature" in value;
20004
21081
  }
@@ -20032,21 +21109,21 @@ function stableJson(value) {
20032
21109
  return `{${Object.keys(obj).sort().map((key) => `${JSON.stringify(key)}:${stableJson(obj[key])}`).join(",")}}`;
20033
21110
  }
20034
21111
  function findLatestBackupEnvFile(envFile) {
20035
- const backupDir = path42.join(path42.dirname(envFile), ".exe-stack-backups");
20036
- if (!existsSync34(backupDir)) return null;
20037
- const backups = readdirSync10(backupDir).filter((name) => name.startsWith("env-") && name.endsWith(".bak")).sort();
21112
+ const backupDir = path44.join(path44.dirname(envFile), ".exe-stack-backups");
21113
+ if (!existsSync36(backupDir)) return null;
21114
+ const backups = readdirSync11(backupDir).filter((name) => name.startsWith("env-") && name.endsWith(".bak")).sort();
20038
21115
  const latest = backups.at(-1);
20039
- return latest ? path42.join(backupDir, latest) : null;
21116
+ return latest ? path44.join(backupDir, latest) : null;
20040
21117
  }
20041
21118
  async function rollbackStackUpdate(options) {
20042
21119
  const exec2 = options.exec ?? defaultExec;
20043
- const backupEnvFile = options.lockFile && existsSync34(options.lockFile) ? JSON.parse(readFileSync29(options.lockFile, "utf8")).backupEnvFile : void 0;
20044
- const rollbackEnv = backupEnvFile && existsSync34(backupEnvFile) ? backupEnvFile : findLatestBackupEnvFile(options.envFile);
21120
+ const backupEnvFile = options.lockFile && existsSync36(options.lockFile) ? JSON.parse(readFileSync31(options.lockFile, "utf8")).backupEnvFile : void 0;
21121
+ const rollbackEnv = backupEnvFile && existsSync36(backupEnvFile) ? backupEnvFile : findLatestBackupEnvFile(options.envFile);
20045
21122
  if (!rollbackEnv) throw new Error(`No stack backup env found beside ${options.envFile}`);
20046
- writeFileSync25(options.envFile, readFileSync29(rollbackEnv), { mode: 384 });
21123
+ writeFileSync26(options.envFile, readFileSync31(rollbackEnv), { mode: 384 });
20047
21124
  const composeArgs = ["compose", "--file", options.composeFile, "--env-file", options.envFile];
20048
21125
  exec2("docker", [...composeArgs, "up", "-d"]);
20049
- return { status: "rolled_back", targetVersion: "previous", changes: [], backupEnvFile: rollbackEnv, lockFile: options.lockFile ?? path42.join(path42.dirname(options.envFile), ".exe-stack-lock.json") };
21126
+ return { status: "rolled_back", targetVersion: "previous", changes: [], backupEnvFile: rollbackEnv, lockFile: options.lockFile ?? path44.join(path44.dirname(options.envFile), ".exe-stack-lock.json") };
20050
21127
  }
20051
21128
  function parseStackManifest(raw, publicKey) {
20052
21129
  const parsedRaw = JSON.parse(raw);
@@ -20071,7 +21148,7 @@ function parseStackManifest(raw, publicKey) {
20071
21148
  }
20072
21149
  async function loadStackManifest(ref, fetchText = defaultFetchText, publicKey, authToken) {
20073
21150
  if (/^https?:\/\//.test(ref)) return parseStackManifest(await fetchTextWithAuth(ref, fetchText, authToken), publicKey);
20074
- return parseStackManifest(readFileSync29(ref, "utf8"), publicKey);
21151
+ return parseStackManifest(readFileSync31(ref, "utf8"), publicKey);
20075
21152
  }
20076
21153
  async function fetchTextWithAuth(ref, fetchText, authToken) {
20077
21154
  if (!authToken || fetchText !== defaultFetchText) return fetchText(ref);
@@ -20200,9 +21277,9 @@ Emergency override requires --break-glass <reason> and writes an audit file.`
20200
21277
  function writeBreakGlassAudit(plan, issues, options) {
20201
21278
  const now2 = options.now ?? (() => /* @__PURE__ */ new Date());
20202
21279
  const stamp = now2().toISOString().replace(/[:.]/g, "-");
20203
- const defaultDir = existsSync34("exe/output") ? "exe/output" : path42.dirname(options.envFile ?? ".");
20204
- const auditFile = options.breakGlassAuditFile ?? path42.join(defaultDir, `stack-update-break-glass-${stamp}.md`);
20205
- mkdirSync24(path42.dirname(auditFile), { recursive: true });
21280
+ const defaultDir = existsSync36("exe/output") ? "exe/output" : path44.dirname(options.envFile ?? ".");
21281
+ const auditFile = options.breakGlassAuditFile ?? path44.join(defaultDir, `stack-update-break-glass-${stamp}.md`);
21282
+ mkdirSync25(path44.dirname(auditFile), { recursive: true });
20206
21283
  const body = [
20207
21284
  `# Stack Update Break-Glass Audit \u2014 ${now2().toISOString()}`,
20208
21285
  "",
@@ -20216,7 +21293,7 @@ function writeBreakGlassAudit(plan, issues, options) {
20216
21293
  "Return this deployment to the standard pinned GHCR image path immediately after the emergency is resolved.",
20217
21294
  ""
20218
21295
  ].join("\n");
20219
- writeFileSync25(auditFile, body, { mode: 384 });
21296
+ writeFileSync26(auditFile, body, { mode: 384 });
20220
21297
  console.warn(`[stack-update] BREAK-GLASS deploy override recorded: ${auditFile}`);
20221
21298
  }
20222
21299
  function assertBreakingChangesAllowed(plan, allowedIds) {
@@ -20242,26 +21319,26 @@ function shellSucceeds(command) {
20242
21319
  return res.status === 0;
20243
21320
  }
20244
21321
  function resolvePackageRoot2() {
20245
- const here = path42.dirname(fileURLToPath5(import.meta.url));
21322
+ const here = path44.dirname(fileURLToPath7(import.meta.url));
20246
21323
  const candidates = [
20247
- path42.resolve(here, "..", ".."),
20248
- path42.resolve(here, ".."),
21324
+ path44.resolve(here, "..", ".."),
21325
+ path44.resolve(here, ".."),
20249
21326
  process.cwd()
20250
21327
  ];
20251
21328
  for (const c of candidates) {
20252
- if (existsSync34(path42.join(c, "package.json")) && existsSync34(path42.join(c, "deploy", "compose", "docker-compose.yml"))) return c;
21329
+ if (existsSync36(path44.join(c, "package.json")) && existsSync36(path44.join(c, "deploy", "compose", "docker-compose.yml"))) return c;
20253
21330
  }
20254
21331
  return process.cwd();
20255
21332
  }
20256
21333
  function copyTemplateIfMissing(srcRel, dest, created) {
20257
- if (existsSync34(dest)) return;
20258
- const src = path42.join(resolvePackageRoot2(), srcRel);
20259
- if (!existsSync34(src)) throw new Error(`Missing packaged stack template: ${srcRel}. Reinstall/update exe-os and retry.`);
21334
+ if (existsSync36(dest)) return;
21335
+ const src = path44.join(resolvePackageRoot2(), srcRel);
21336
+ if (!existsSync36(src)) throw new Error(`Missing packaged stack template: ${srcRel}. Reinstall/update exe-os and retry.`);
20260
21337
  try {
20261
- mkdirSync24(path42.dirname(dest), { recursive: true });
21338
+ mkdirSync25(path44.dirname(dest), { recursive: true });
20262
21339
  } catch (err) {
20263
21340
  if (err.code === "EACCES") {
20264
- const dir = path42.dirname(dest);
21341
+ const dir = path44.dirname(dest);
20265
21342
  throw new Error(
20266
21343
  `Permission denied creating ${dir}. Run this first:
20267
21344
 
@@ -20277,8 +21354,8 @@ Then re-run stack-update.`
20277
21354
  }
20278
21355
  function installDockerUbuntu(exec2) {
20279
21356
  if (process.platform !== "linux") throw new Error("Docker auto-install is only supported on Linux. Install Docker manually, then retry.");
20280
- if (!existsSync34("/etc/os-release")) throw new Error("Cannot detect Linux distro; install Docker manually, then retry.");
20281
- const osRelease = readFileSync29("/etc/os-release", "utf8");
21357
+ if (!existsSync36("/etc/os-release")) throw new Error("Cannot detect Linux distro; install Docker manually, then retry.");
21358
+ const osRelease = readFileSync31("/etc/os-release", "utf8");
20282
21359
  if (!/ID=(ubuntu|debian)|ID_LIKE=.*debian/.test(osRelease)) {
20283
21360
  throw new Error("Docker auto-install currently supports Ubuntu/Debian only. Install Docker manually, then retry.");
20284
21361
  }
@@ -20350,14 +21427,14 @@ async function pairMonitorAgent(hubUrl, licenseKey, domain, envFile) {
20350
21427
  if (!data.token || !data.key) {
20351
21428
  return { paired: false, error: "Monitor hub response missing token or key" };
20352
21429
  }
20353
- if (existsSync34(envFile)) {
20354
- const envRaw = readFileSync29(envFile, "utf8");
21430
+ if (existsSync36(envFile)) {
21431
+ const envRaw = readFileSync31(envFile, "utf8");
20355
21432
  const patched = patchEnv(envRaw, {
20356
21433
  MONITOR_AGENT_TOKEN: data.token,
20357
21434
  MONITOR_AGENT_KEY: data.key
20358
21435
  });
20359
21436
  if (patched !== envRaw) {
20360
- writeFileSync25(envFile, patched, { mode: 384 });
21437
+ writeFileSync26(envFile, patched, { mode: 384 });
20361
21438
  }
20362
21439
  }
20363
21440
  return { paired: true, systemName: data.name ?? domain };
@@ -20380,26 +21457,26 @@ function bootstrapStackHost(options) {
20380
21457
  }
20381
21458
  copyTemplateIfMissing("deploy/compose/docker-compose.yml", options.composeFile, createdFiles);
20382
21459
  copyTemplateIfMissing("deploy/compose/.env.customer.example", options.envFile, createdFiles);
20383
- const brandingDest = path42.join(path42.dirname(options.envFile), "branding.json");
20384
- copyTemplateIfMissing("deploy/compose/gateway.json", path42.join(path42.dirname(options.envFile), "gateway.json"), createdFiles);
20385
- if (!existsSync34(brandingDest)) writeFileSync25(brandingDest, JSON.stringify({ brandName: "Hygo", productName: "Hygo OS" }, null, 2) + "\n", { mode: 384 });
21460
+ const brandingDest = path44.join(path44.dirname(options.envFile), "branding.json");
21461
+ copyTemplateIfMissing("deploy/compose/gateway.json", path44.join(path44.dirname(options.envFile), "gateway.json"), createdFiles);
21462
+ if (!existsSync36(brandingDest)) writeFileSync26(brandingDest, JSON.stringify({ brandName: "Hygo", productName: "Hygo OS" }, null, 2) + "\n", { mode: 384 });
20386
21463
  let envHadPlaceholders = false;
20387
21464
  let envRemainingPlaceholders = [];
20388
- if (existsSync34(options.envFile)) {
20389
- const envRaw = readFileSync29(options.envFile, "utf8");
21465
+ if (existsSync36(options.envFile)) {
21466
+ const envRaw = readFileSync31(options.envFile, "utf8");
20390
21467
  const hydrated = hydrateEnv(envRaw, options);
20391
21468
  envHadPlaceholders = hydrated.hadPlaceholders;
20392
21469
  envRemainingPlaceholders = hydrated.remaining;
20393
21470
  if (hydrated.raw !== envRaw) {
20394
- writeFileSync25(options.envFile, hydrated.raw, { mode: 384 });
21471
+ writeFileSync26(options.envFile, hydrated.raw, { mode: 384 });
20395
21472
  actions.push("hydrate_env_secrets");
20396
21473
  }
20397
21474
  }
20398
21475
  return {
20399
21476
  dockerInstalled,
20400
21477
  dockerComposeInstalled,
20401
- composeFileExists: existsSync34(options.composeFile),
20402
- envFileExists: existsSync34(options.envFile),
21478
+ composeFileExists: existsSync36(options.composeFile),
21479
+ envFileExists: existsSync36(options.envFile),
20403
21480
  envHadPlaceholders,
20404
21481
  envRemainingPlaceholders,
20405
21482
  licensePresent: !!(options.licenseKey || process.env.EXE_LICENSE_KEY || loadLicense()),
@@ -20438,53 +21515,51 @@ async function runStackUpdate(options) {
20438
21515
  const report = bootstrapStackHost({ ...options, installDocker: options.installDocker ?? !!options.yes });
20439
21516
  if (!options.dryRun) assertHostReadyForApply(report);
20440
21517
  }
20441
- const hubUrl = options.monitorHubUrl || parseEnv(readFileSync29(options.envFile, "utf8")).get("MONITOR_HUB_URL") || "";
21518
+ const hubUrl = options.monitorHubUrl || parseEnv(readFileSync31(options.envFile, "utf8")).get("MONITOR_HUB_URL") || "";
20442
21519
  const pairLicense = options.licenseKey || process.env.EXE_LICENSE_KEY || loadLicense() || "";
20443
21520
  const pairDomain = options.domain || process.env.EXE_STACK_DOMAIN || process.env.CUSTOMER_DOMAIN || "";
20444
21521
  if (hubUrl && pairLicense && pairDomain) {
20445
- const envBefore = readFileSync29(options.envFile, "utf8");
21522
+ const envBefore = readFileSync31(options.envFile, "utf8");
20446
21523
  const hasPlaceholder = /CHANGEME/.test(parseEnv(envBefore).get("MONITOR_AGENT_TOKEN") ?? "");
20447
21524
  if (hasPlaceholder) {
20448
21525
  const pair = options.pairMonitor ? options.pairMonitor(hubUrl, pairLicense, pairDomain, options.envFile) : pairMonitorAgent(hubUrl, pairLicense, pairDomain, options.envFile);
20449
21526
  const result = await pair;
20450
- if (typeof result === "object" && result && "paired" in result) {
20451
- if (result.paired) {
20452
- console.log(`[stack-update] Monitor agent paired: ${result.systemName}`);
20453
- } else {
20454
- console.warn(`[stack-update] Monitor pairing skipped: ${result.error}`);
20455
- }
21527
+ if (result.paired) {
21528
+ console.log(`[stack-update] Monitor agent paired: ${result.systemName}`);
21529
+ } else {
21530
+ console.warn(`[stack-update] Monitor pairing skipped: ${result.error}`);
20456
21531
  }
20457
21532
  }
20458
21533
  }
20459
21534
  const manifest = await loadStackManifest(options.manifestRef, options.fetchText, options.manifestPublicKey, options.manifestAuthToken);
20460
- const envRaw = readFileSync29(options.envFile, "utf8");
21535
+ const envRaw = readFileSync31(options.envFile, "utf8");
20461
21536
  const plan = createStackUpdatePlan(manifest, envRaw, options.targetVersion);
20462
21537
  assertBreakingChangesAllowed(plan, options.allowedBreakingChangeIds ?? []);
20463
21538
  assertDeploymentScopeAllowed(plan, options.deploymentPersona ?? "customer");
20464
21539
  const plannedEnvRaw = patchEnv(envRaw, Object.fromEntries(plan.changes.map((c) => [c.key, c.after])));
20465
- const composeRaw = readFileSync29(options.composeFile, "utf8");
21540
+ const composeRaw = readFileSync31(options.composeFile, "utf8");
20466
21541
  assertProductionDeployGate(plan, plannedEnvRaw, composeRaw, {
20467
21542
  breakGlassReason: options.breakGlassReason,
20468
21543
  breakGlassAuditFile: options.breakGlassAuditFile,
20469
21544
  now: now2,
20470
21545
  envFile: options.envFile
20471
21546
  });
20472
- const lockFile = options.lockFile ?? path42.join(path42.dirname(options.envFile), ".exe-stack-lock.json");
21547
+ const lockFile = options.lockFile ?? path44.join(path44.dirname(options.envFile), ".exe-stack-lock.json");
20473
21548
  const previousVersion = readCurrentStackVersion(lockFile);
20474
21549
  const containersRunning = plan.changes.length === 0 ? areStackContainersRunning(options.composeFile, options.envFile) : true;
20475
21550
  if (options.dryRun || plan.changes.length === 0 && containersRunning) {
20476
21551
  return { status: "planned", targetVersion: plan.targetVersion, changes: plan.changes, lockFile };
20477
21552
  }
20478
21553
  await postDeployAudit(options, "started", plan.targetVersion, previousVersion);
20479
- const backupDir = path42.join(path42.dirname(options.envFile), ".exe-stack-backups");
20480
- mkdirSync24(backupDir, { recursive: true });
21554
+ const backupDir = path44.join(path44.dirname(options.envFile), ".exe-stack-backups");
21555
+ mkdirSync25(backupDir, { recursive: true });
20481
21556
  const stamp = now2().toISOString().replace(/[:.]/g, "-");
20482
- const backupEnvFile = path42.join(backupDir, `env-${stamp}.bak`);
20483
- writeFileSync25(backupEnvFile, envRaw, { mode: 384 });
21557
+ const backupEnvFile = path44.join(backupDir, `env-${stamp}.bak`);
21558
+ writeFileSync26(backupEnvFile, envRaw, { mode: 384 });
20484
21559
  const updates = Object.fromEntries(plan.changes.map((c) => [c.key, c.after]));
20485
21560
  const patched = patchEnv(envRaw, updates);
20486
21561
  const tmp = `${options.envFile}.tmp-${process.pid}`;
20487
- writeFileSync25(tmp, patched, { mode: 384 });
21562
+ writeFileSync26(tmp, patched, { mode: 384 });
20488
21563
  renameSync8(tmp, options.envFile);
20489
21564
  const composeArgs = ["compose", "--file", options.composeFile, "--env-file", options.envFile];
20490
21565
  let registryForLogout;
@@ -20497,11 +21572,11 @@ async function runStackUpdate(options) {
20497
21572
  exec2("docker", [...composeArgs, "pull"]);
20498
21573
  exec2("docker", [...composeArgs, "up", "-d"]);
20499
21574
  await verifyReleaseHealth(plan.release, options.healthRetries ?? 12, options.healthDelayMs ?? 5e3);
20500
- writeFileSync25(lockFile, JSON.stringify({ stackVersion: plan.targetVersion, updatedAt: now2().toISOString(), backupEnvFile, services: plan.release.services }, null, 2) + "\n");
21575
+ writeFileSync26(lockFile, JSON.stringify({ stackVersion: plan.targetVersion, updatedAt: now2().toISOString(), backupEnvFile, services: plan.release.services }, null, 2) + "\n");
20501
21576
  await postDeployAudit(options, "success", plan.targetVersion, previousVersion, void 0, { changes: plan.changes.length });
20502
21577
  return { status: "updated", targetVersion: plan.targetVersion, changes: plan.changes, backupEnvFile, lockFile };
20503
21578
  } catch (err) {
20504
- writeFileSync25(options.envFile, envRaw, { mode: 384 });
21579
+ writeFileSync26(options.envFile, envRaw, { mode: 384 });
20505
21580
  try {
20506
21581
  exec2("docker", [...composeArgs, "up", "-d"]);
20507
21582
  } catch {
@@ -20532,9 +21607,9 @@ async function fetchImageCredentials(options) {
20532
21607
  return await res.json();
20533
21608
  }
20534
21609
  function readCurrentStackVersion(lockFile) {
20535
- if (!existsSync34(lockFile)) return void 0;
21610
+ if (!existsSync36(lockFile)) return void 0;
20536
21611
  try {
20537
- const parsed = JSON.parse(readFileSync29(lockFile, "utf8"));
21612
+ const parsed = JSON.parse(readFileSync31(lockFile, "utf8"));
20538
21613
  return parsed.stackVersion;
20539
21614
  } catch {
20540
21615
  return void 0;
@@ -20622,13 +21697,13 @@ async function defaultPostJson(url, body, authToken) {
20622
21697
  if (!res.ok) throw new Error(`Failed to POST ${url}: HTTP ${res.status}`);
20623
21698
  }
20624
21699
  function defaultStackPaths() {
20625
- const cwdCompose = path42.resolve("docker-compose.yml");
20626
- const cwdEnv = path42.resolve(".env");
20627
- const packagedManifest = path42.join(resolvePackageRoot2(), "deploy", "stack-manifests", "v0.9.json");
20628
- const manifestRef = process.env.EXE_STACK_MANIFEST || (existsSync34(packagedManifest) ? packagedManifest : "https://update.askexe.com/stack-manifest.json");
21700
+ const cwdCompose = path44.resolve("docker-compose.yml");
21701
+ const cwdEnv = path44.resolve(".env");
21702
+ const packagedManifest = path44.join(resolvePackageRoot2(), "deploy", "stack-manifests", "v0.9.json");
21703
+ const manifestRef = process.env.EXE_STACK_MANIFEST || (existsSync36(packagedManifest) ? packagedManifest : "https://update.askexe.com/stack-manifest.json");
20629
21704
  return {
20630
- composeFile: process.env.EXE_STACK_COMPOSE_FILE || (existsSync34(cwdCompose) ? cwdCompose : "/opt/exe-stack/docker-compose.yml"),
20631
- envFile: process.env.EXE_STACK_ENV_FILE || (existsSync34(cwdEnv) ? cwdEnv : "/opt/exe-stack/.env"),
21705
+ composeFile: process.env.EXE_STACK_COMPOSE_FILE || (existsSync36(cwdCompose) ? cwdCompose : "/opt/exe-stack/docker-compose.yml"),
21706
+ envFile: process.env.EXE_STACK_ENV_FILE || (existsSync36(cwdEnv) ? cwdEnv : "/opt/exe-stack/.env"),
20632
21707
  manifestRef,
20633
21708
  // Only call update.askexe.com if explicitly configured or if a remote manifest was requested.
20634
21709
  // Packaged manifests keep cold-start installs unblocked even before update-service entitlements are provisioned.
@@ -20642,8 +21717,8 @@ function defaultStackPaths() {
20642
21717
  }
20643
21718
  function loadDefaultPublicKey() {
20644
21719
  if (process.env.EXE_STACK_PUBLIC_KEY) return process.env.EXE_STACK_PUBLIC_KEY;
20645
- if (process.env.EXE_STACK_PUBLIC_KEY_FILE && existsSync34(process.env.EXE_STACK_PUBLIC_KEY_FILE)) {
20646
- return readFileSync29(process.env.EXE_STACK_PUBLIC_KEY_FILE, "utf8");
21720
+ if (process.env.EXE_STACK_PUBLIC_KEY_FILE && existsSync36(process.env.EXE_STACK_PUBLIC_KEY_FILE)) {
21721
+ return readFileSync31(process.env.EXE_STACK_PUBLIC_KEY_FILE, "utf8");
20647
21722
  }
20648
21723
  return void 0;
20649
21724
  }
@@ -20661,7 +21736,7 @@ var stack_update_exports = {};
20661
21736
  __export(stack_update_exports, {
20662
21737
  runStackUpdateCli: () => main7
20663
21738
  });
20664
- import { readFileSync as readFileSync30 } from "fs";
21739
+ import { readFileSync as readFileSync32 } from "fs";
20665
21740
  import { spawnSync as spawnSync2 } from "child_process";
20666
21741
  function parseArgs4(args2) {
20667
21742
  const defaults = defaultStackPaths();
@@ -20695,8 +21770,8 @@ function parseArgs4(args2) {
20695
21770
  else if (arg === "--env-file" || arg === "--stack-env-file") opts.envFile = next();
20696
21771
  else if (arg.startsWith("--env-file=") || arg.startsWith("--stack-env-file=")) opts.envFile = arg.split("=").slice(1).join("=");
20697
21772
  else if (arg === "--lock-file") opts.lockFile = next();
20698
- else if (arg === "--public-key") opts.manifestPublicKey = readFileSync30(next(), "utf8");
20699
- else if (arg.startsWith("--public-key=")) opts.manifestPublicKey = readFileSync30(arg.split("=").slice(1).join("="), "utf8");
21773
+ else if (arg === "--public-key") opts.manifestPublicKey = readFileSync32(next(), "utf8");
21774
+ else if (arg.startsWith("--public-key=")) opts.manifestPublicKey = readFileSync32(arg.split("=").slice(1).join("="), "utf8");
20700
21775
  else if (arg === "--auth-token") opts.manifestAuthToken = next();
20701
21776
  else if (arg.startsWith("--auth-token=")) opts.manifestAuthToken = arg.split("=").slice(1).join("=");
20702
21777
  else if (arg === "--auth-token-env") opts.manifestAuthToken = process.env[next()] ?? "";
@@ -20901,11 +21976,11 @@ async function main7(args2 = process.argv.slice(2)) {
20901
21976
  if (!opts.check && !opts.dryRun) assertHostReadyForApply(hostReport);
20902
21977
  }
20903
21978
  const manifest = await loadStackManifest(opts.manifestRef, void 0, opts.manifestPublicKey, opts.manifestAuthToken);
20904
- const envRaw = readFileSync30(opts.envFile, "utf8");
21979
+ const envRaw = readFileSync32(opts.envFile, "utf8");
20905
21980
  const plan = createStackUpdatePlan(manifest, envRaw, opts.targetVersion);
20906
21981
  assertDeploymentScopeAllowed(plan, opts.deploymentPersona);
20907
21982
  const plannedEnvRaw = patchEnv(envRaw, Object.fromEntries(plan.changes.map((c) => [c.key, c.after])));
20908
- assertProductionDeployGate(plan, plannedEnvRaw, readFileSync30(opts.composeFile, "utf8"), {
21983
+ assertProductionDeployGate(plan, plannedEnvRaw, readFileSync32(opts.composeFile, "utf8"), {
20909
21984
  breakGlassReason: opts.breakGlassReason,
20910
21985
  breakGlassAuditFile: opts.breakGlassAuditFile,
20911
21986
  envFile: opts.envFile
@@ -25507,8 +26582,8 @@ var init_ErrorOverview = __esm({
25507
26582
  "use strict";
25508
26583
  init_Box();
25509
26584
  init_Text();
25510
- cleanupPath = (path56) => {
25511
- return path56?.replace(`file://${cwd()}/`, "");
26585
+ cleanupPath = (path58) => {
26586
+ return path58?.replace(`file://${cwd()}/`, "");
25512
26587
  };
25513
26588
  stackUtils = new StackUtils({
25514
26589
  cwd: cwd(),
@@ -27612,13 +28687,13 @@ __export(tmux_status_exports, {
27612
28687
  parseActivity: () => parseActivity,
27613
28688
  parseContextPercentage: () => parseContextPercentage
27614
28689
  });
27615
- import { execSync as execSync17 } from "child_process";
28690
+ import { execSync as execSync18 } from "child_process";
27616
28691
  function inTmux() {
27617
28692
  if (process.env.TMUX || process.env.TMUX_PANE) return true;
27618
28693
  const term = process.env.TERM ?? "";
27619
28694
  if (term.startsWith("tmux") || term.startsWith("screen")) return true;
27620
28695
  try {
27621
- execSync17("tmux display-message -p '#{session_name}' 2>/dev/null", {
28696
+ execSync18("tmux display-message -p '#{session_name}' 2>/dev/null", {
27622
28697
  encoding: "utf8",
27623
28698
  timeout: 2e3
27624
28699
  });
@@ -27628,12 +28703,12 @@ function inTmux() {
27628
28703
  try {
27629
28704
  let pid = process.ppid;
27630
28705
  for (let depth = 0; depth < 8 && pid > 1; depth++) {
27631
- const comm = execSync17(`ps -p ${pid} -o comm= 2>/dev/null`, {
28706
+ const comm = execSync18(`ps -p ${pid} -o comm= 2>/dev/null`, {
27632
28707
  encoding: "utf8",
27633
28708
  timeout: 1e3
27634
28709
  }).trim();
27635
28710
  if (/tmux/.test(comm)) return true;
27636
- const ppid = execSync17(`ps -p ${pid} -o ppid= 2>/dev/null`, {
28711
+ const ppid = execSync18(`ps -p ${pid} -o ppid= 2>/dev/null`, {
27637
28712
  encoding: "utf8",
27638
28713
  timeout: 1e3
27639
28714
  }).trim();
@@ -27646,7 +28721,7 @@ function inTmux() {
27646
28721
  }
27647
28722
  function listTmuxSessions() {
27648
28723
  try {
27649
- const out = execSync17("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
28724
+ const out = execSync18("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
27650
28725
  encoding: "utf8",
27651
28726
  timeout: 3e3
27652
28727
  });
@@ -27657,7 +28732,7 @@ function listTmuxSessions() {
27657
28732
  }
27658
28733
  function capturePaneLines(windowName, lines = 10) {
27659
28734
  try {
27660
- const out = execSync17(
28735
+ const out = execSync18(
27661
28736
  `tmux capture-pane -t ${JSON.stringify(windowName)} -p 2>/dev/null | tail -${lines}`,
27662
28737
  { encoding: "utf8", timeout: 3e3 }
27663
28738
  );
@@ -27668,7 +28743,7 @@ function capturePaneLines(windowName, lines = 10) {
27668
28743
  }
27669
28744
  function getPaneCwd(windowName) {
27670
28745
  try {
27671
- const out = execSync17(
28746
+ const out = execSync18(
27672
28747
  `tmux display-message -t ${JSON.stringify(windowName)} -p '#{pane_current_path}' 2>/dev/null`,
27673
28748
  { encoding: "utf8", timeout: 3e3 }
27674
28749
  );
@@ -27679,7 +28754,7 @@ function getPaneCwd(windowName) {
27679
28754
  }
27680
28755
  function projectFromPath(dir) {
27681
28756
  try {
27682
- const root = execSync17("git -C " + JSON.stringify(dir) + " rev-parse --show-toplevel 2>/dev/null", {
28757
+ const root = execSync18("git -C " + JSON.stringify(dir) + " rev-parse --show-toplevel 2>/dev/null", {
27683
28758
  encoding: "utf8",
27684
28759
  timeout: 3e3
27685
28760
  }).trim();
@@ -27748,7 +28823,7 @@ function getEmployeeStatuses(employeeNames) {
27748
28823
  }
27749
28824
  let paneAlive = true;
27750
28825
  try {
27751
- const paneStatus = execSync17(
28826
+ const paneStatus = execSync18(
27752
28827
  `tmux list-panes -t ${JSON.stringify(sessionName)} -F '#{pane_dead}' 2>/dev/null`,
27753
28828
  { encoding: "utf8", timeout: 3e3 }
27754
28829
  ).trim();
@@ -27916,11 +28991,11 @@ function Footer() {
27916
28991
  } catch {
27917
28992
  }
27918
28993
  try {
27919
- const { existsSync: existsSync41 } = await import("fs");
28994
+ const { existsSync: existsSync43 } = await import("fs");
27920
28995
  const { join } = await import("path");
27921
28996
  const home = process.env.HOME ?? "";
27922
28997
  const pidPath = join(home, ".exe-os", "exed.pid");
27923
- setDaemon(existsSync41(pidPath) ? "running" : "stopped");
28998
+ setDaemon(existsSync43(pidPath) ? "running" : "stopped");
27924
28999
  } catch {
27925
29000
  setDaemon("unknown");
27926
29001
  }
@@ -27938,8 +29013,8 @@ function Footer() {
27938
29013
  setSessions(allSessions.length);
27939
29014
  if (!currentSession) {
27940
29015
  try {
27941
- const { execSync: execSync19 } = await import("child_process");
27942
- const name = execSync19("tmux display-message -p '#{session_name}' 2>/dev/null", {
29016
+ const { execSync: execSync20 } = await import("child_process");
29017
+ const name = execSync20("tmux display-message -p '#{session_name}' 2>/dev/null", {
27943
29018
  encoding: "utf8",
27944
29019
  timeout: 2e3
27945
29020
  }).trim();
@@ -29971,10 +31046,10 @@ var init_hooks = __esm({
29971
31046
  });
29972
31047
 
29973
31048
  // src/runtime/safety-checks.ts
29974
- import path43 from "path";
31049
+ import path45 from "path";
29975
31050
  import os21 from "os";
29976
31051
  function checkPathSafety(filePath) {
29977
- const resolved = path43.resolve(filePath);
31052
+ const resolved = path45.resolve(filePath);
29978
31053
  for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
29979
31054
  const matches = typeof pattern === "function" ? pattern(resolved) : pattern.test(resolved);
29980
31055
  if (matches) {
@@ -29984,7 +31059,7 @@ function checkPathSafety(filePath) {
29984
31059
  return { safe: true, bypassImmune: true };
29985
31060
  }
29986
31061
  function checkReadPathSafety(filePath) {
29987
- const resolved = path43.resolve(filePath);
31062
+ const resolved = path45.resolve(filePath);
29988
31063
  const credPatterns = BYPASS_IMMUNE_PATTERNS.filter(
29989
31064
  (p) => typeof p.pattern !== "function" && (p.reason.includes("secrets") || p.reason.includes("Private key") || p.reason.includes("Credential"))
29990
31065
  );
@@ -30010,11 +31085,11 @@ var init_safety_checks = __esm({
30010
31085
  reason: "Git config can set hooks and command execution"
30011
31086
  },
30012
31087
  {
30013
- pattern: (p) => p.startsWith(path43.join(HOME, ".claude")),
31088
+ pattern: (p) => p.startsWith(path45.join(HOME, ".claude")),
30014
31089
  reason: "Claude configuration files are protected"
30015
31090
  },
30016
31091
  {
30017
- pattern: (p) => p.startsWith(path43.join(HOME, ".exe-os")),
31092
+ pattern: (p) => p.startsWith(path45.join(HOME, ".exe-os")),
30018
31093
  reason: "exe-os configuration files are protected"
30019
31094
  },
30020
31095
  {
@@ -30031,7 +31106,7 @@ var init_safety_checks = __esm({
30031
31106
  },
30032
31107
  {
30033
31108
  pattern: (p) => {
30034
- const name = path43.basename(p);
31109
+ const name = path45.basename(p);
30035
31110
  return [".bashrc", ".zshrc", ".profile", ".bash_profile", ".zprofile", ".zshenv"].includes(name);
30036
31111
  },
30037
31112
  reason: "Shell configuration files can execute arbitrary code on login"
@@ -30058,7 +31133,7 @@ __export(file_read_exports, {
30058
31133
  FileReadTool: () => FileReadTool
30059
31134
  });
30060
31135
  import fs3 from "fs/promises";
30061
- import path44 from "path";
31136
+ import path46 from "path";
30062
31137
  import { z } from "zod";
30063
31138
  function isBinary(buf) {
30064
31139
  for (let i = 0; i < buf.length; i++) {
@@ -30094,7 +31169,7 @@ var init_file_read = __esm({
30094
31169
  return { behavior: "allow" };
30095
31170
  },
30096
31171
  async call(input, context) {
30097
- const filePath = path44.isAbsolute(input.file_path) ? input.file_path : path44.resolve(context.cwd, input.file_path);
31172
+ const filePath = path46.isAbsolute(input.file_path) ? input.file_path : path46.resolve(context.cwd, input.file_path);
30098
31173
  let stat2;
30099
31174
  try {
30100
31175
  stat2 = await fs3.stat(filePath);
@@ -30134,7 +31209,7 @@ __export(glob_exports, {
30134
31209
  GlobTool: () => GlobTool
30135
31210
  });
30136
31211
  import fs4 from "fs/promises";
30137
- import path45 from "path";
31212
+ import path47 from "path";
30138
31213
  import { z as z2 } from "zod";
30139
31214
  async function walkDir(dir, maxDepth = 10) {
30140
31215
  const results = [];
@@ -30150,7 +31225,7 @@ async function walkDir(dir, maxDepth = 10) {
30150
31225
  if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git")) {
30151
31226
  continue;
30152
31227
  }
30153
- const fullPath = path45.join(current, entry.name);
31228
+ const fullPath = path47.join(current, entry.name);
30154
31229
  if (entry.isDirectory()) {
30155
31230
  await walk(fullPath, depth + 1);
30156
31231
  } else {
@@ -30184,11 +31259,11 @@ var init_glob = __esm({
30184
31259
  inputSchema: inputSchema2,
30185
31260
  isReadOnly: true,
30186
31261
  async call(input, context) {
30187
- const baseDir = input.path ? path45.isAbsolute(input.path) ? input.path : path45.resolve(context.cwd, input.path) : context.cwd;
31262
+ const baseDir = input.path ? path47.isAbsolute(input.path) ? input.path : path47.resolve(context.cwd, input.path) : context.cwd;
30188
31263
  try {
30189
31264
  const entries = await walkDir(baseDir);
30190
31265
  const matched = entries.filter(
30191
- (e) => simpleGlobMatch(path45.relative(baseDir, e.path), input.pattern)
31266
+ (e) => simpleGlobMatch(path47.relative(baseDir, e.path), input.pattern)
30192
31267
  );
30193
31268
  matched.sort((a, b) => b.mtime - a.mtime);
30194
31269
  if (matched.length === 0) {
@@ -30214,7 +31289,7 @@ __export(grep_exports, {
30214
31289
  });
30215
31290
  import { spawn as spawn2 } from "child_process";
30216
31291
  import fs5 from "fs/promises";
30217
- import path46 from "path";
31292
+ import path48 from "path";
30218
31293
  import { z as z3 } from "zod";
30219
31294
  function runRipgrep(input, searchPath, context) {
30220
31295
  return new Promise((resolve, reject) => {
@@ -30268,7 +31343,7 @@ async function nodeGrep(input, searchPath) {
30268
31343
  }
30269
31344
  for (const entry of entries) {
30270
31345
  if (entry.name === "node_modules" || entry.name === ".git") continue;
30271
- const fullPath = path46.join(dir, entry.name);
31346
+ const fullPath = path48.join(dir, entry.name);
30272
31347
  if (entry.isDirectory()) {
30273
31348
  await walk(fullPath);
30274
31349
  } else {
@@ -30314,7 +31389,7 @@ var init_grep = __esm({
30314
31389
  inputSchema: inputSchema3,
30315
31390
  isReadOnly: true,
30316
31391
  async call(input, context) {
30317
- const searchPath = input.path ? path46.isAbsolute(input.path) ? input.path : path46.resolve(context.cwd, input.path) : context.cwd;
31392
+ const searchPath = input.path ? path48.isAbsolute(input.path) ? input.path : path48.resolve(context.cwd, input.path) : context.cwd;
30318
31393
  try {
30319
31394
  const result = await runRipgrep(input, searchPath, context);
30320
31395
  return result;
@@ -30339,7 +31414,7 @@ __export(file_write_exports, {
30339
31414
  FileWriteTool: () => FileWriteTool
30340
31415
  });
30341
31416
  import fs6 from "fs/promises";
30342
- import path47 from "path";
31417
+ import path49 from "path";
30343
31418
  import { z as z4 } from "zod";
30344
31419
  var inputSchema4, FileWriteTool;
30345
31420
  var init_file_write = __esm({
@@ -30367,8 +31442,8 @@ var init_file_write = __esm({
30367
31442
  return { behavior: "allow" };
30368
31443
  },
30369
31444
  async call(input, context) {
30370
- const filePath = path47.isAbsolute(input.file_path) ? input.file_path : path47.resolve(context.cwd, input.file_path);
30371
- const dir = path47.dirname(filePath);
31445
+ const filePath = path49.isAbsolute(input.file_path) ? input.file_path : path49.resolve(context.cwd, input.file_path);
31446
+ const dir = path49.dirname(filePath);
30372
31447
  await fs6.mkdir(dir, { recursive: true });
30373
31448
  await fs6.writeFile(filePath, input.content, "utf-8");
30374
31449
  return {
@@ -30386,7 +31461,7 @@ __export(file_edit_exports, {
30386
31461
  FileEditTool: () => FileEditTool
30387
31462
  });
30388
31463
  import fs7 from "fs/promises";
30389
- import path48 from "path";
31464
+ import path50 from "path";
30390
31465
  import { z as z5 } from "zod";
30391
31466
  function countOccurrences(haystack, needle) {
30392
31467
  let count = 0;
@@ -30427,7 +31502,7 @@ var init_file_edit = __esm({
30427
31502
  return { behavior: "allow" };
30428
31503
  },
30429
31504
  async call(input, context) {
30430
- const filePath = path48.isAbsolute(input.file_path) ? input.file_path : path48.resolve(context.cwd, input.file_path);
31505
+ const filePath = path50.isAbsolute(input.file_path) ? input.file_path : path50.resolve(context.cwd, input.file_path);
30431
31506
  let content;
30432
31507
  try {
30433
31508
  content = await fs7.readFile(filePath, "utf-8");
@@ -30669,7 +31744,7 @@ var init_bash = __esm({
30669
31744
  // src/tui/views/CommandCenter.tsx
30670
31745
  import { useState as useState6, useEffect as useEffect8, useMemo as useMemo4, useCallback as useCallback4, useRef as useRef4 } from "react";
30671
31746
  import TextInput from "ink-text-input";
30672
- import path49 from "path";
31747
+ import path51 from "path";
30673
31748
  import { homedir as homedir6 } from "os";
30674
31749
  import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
30675
31750
  function CommandCenterView({
@@ -30704,15 +31779,15 @@ function CommandCenterView({
30704
31779
  const { createPermissionsFromPreset: createPermissionsFromPreset2, EMPLOYEE_PERMISSIONS: EMPLOYEE_PERMISSIONS2 } = await Promise.resolve().then(() => (init_permissions(), permissions_exports));
30705
31780
  const { getPresetByRole: getPresetByRole2 } = await Promise.resolve().then(() => (init_permission_presets(), permission_presets_exports));
30706
31781
  const { createDefaultHooks: createDefaultHooks2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
30707
- const { readFileSync: readFileSync37, existsSync: existsSync41 } = await import("fs");
31782
+ const { readFileSync: readFileSync39, existsSync: existsSync43 } = await import("fs");
30708
31783
  const { join } = await import("path");
30709
31784
  const { homedir: homedir8 } = await import("os");
30710
31785
  const configPath = join(homedir8(), ".exe-os", "config.json");
30711
31786
  let failoverChain = ["anthropic", "opencode", "gemini", "openai"];
30712
31787
  let providerConfigs = {};
30713
- if (existsSync41(configPath)) {
31788
+ if (existsSync43(configPath)) {
30714
31789
  try {
30715
- const raw = JSON.parse(readFileSync37(configPath, "utf8"));
31790
+ const raw = JSON.parse(readFileSync39(configPath, "utf8"));
30716
31791
  if (Array.isArray(raw.failoverChain)) failoverChain = raw.failoverChain;
30717
31792
  if (raw.providers && typeof raw.providers === "object") {
30718
31793
  providerConfigs = raw.providers;
@@ -30773,7 +31848,7 @@ function CommandCenterView({
30773
31848
  const markerDir = join(homedir8(), ".exe-os", "session-cache");
30774
31849
  const agentFiles = (await import("fs")).readdirSync(markerDir).filter((f) => f.startsWith("active-agent-"));
30775
31850
  for (const f of agentFiles) {
30776
- const data = JSON.parse(readFileSync37(join(markerDir, f), "utf8"));
31851
+ const data = JSON.parse(readFileSync39(join(markerDir, f), "utf8"));
30777
31852
  if (data.agentRole) {
30778
31853
  agentRole = data.agentRole;
30779
31854
  break;
@@ -30918,7 +31993,7 @@ function CommandCenterView({
30918
31993
  const demoEntries = DEMO_PROJECTS.map((p) => ({
30919
31994
  projectName: p.projectName,
30920
31995
  exeSession: p.exeSession,
30921
- projectDir: path49.join(homedir6(), p.projectName),
31996
+ projectDir: path51.join(homedir6(), p.projectName),
30922
31997
  employeeCount: p.employees.length,
30923
31998
  activeCount: p.employees.filter((e) => e.status === "active").length,
30924
31999
  memoryCount: p.employees.length * 4e3,
@@ -30956,7 +32031,7 @@ function CommandCenterView({
30956
32031
  const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
30957
32032
  const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
30958
32033
  const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
30959
- const { existsSync: existsSync41 } = await import("fs");
32034
+ const { existsSync: existsSync43 } = await import("fs");
30960
32035
  const { join } = await import("path");
30961
32036
  const client = getClient2();
30962
32037
  if (!client) {
@@ -31027,7 +32102,7 @@ function CommandCenterView({
31027
32102
  }
31028
32103
  const memoryCount = memoryCounts.get(name) ?? 0;
31029
32104
  const openTaskCount = openTaskCounts.get(name) ?? 0;
31030
- const hasGit = projectDir ? existsSync41(join(projectDir, ".git")) : false;
32105
+ const hasGit = projectDir ? existsSync43(join(projectDir, ".git")) : false;
31031
32106
  const type = hasGit ? "code" : memoryCount > 0 ? "code" : "automation";
31032
32107
  projectList.push({
31033
32108
  projectName: name,
@@ -31052,7 +32127,7 @@ function CommandCenterView({
31052
32127
  setHealth((h) => ({ ...h, memories: Number(totalResult.rows[0]?.cnt ?? 0) }));
31053
32128
  try {
31054
32129
  const pidPath = join(process.env.HOME ?? "", ".exe-os", "exed.pid");
31055
- setHealth((h) => ({ ...h, daemon: existsSync41(pidPath) ? "running" : "stopped" }));
32130
+ setHealth((h) => ({ ...h, daemon: existsSync43(pidPath) ? "running" : "stopped" }));
31056
32131
  } catch {
31057
32132
  }
31058
32133
  const activityResult = await client.execute(
@@ -31293,8 +32368,8 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
31293
32368
  }
31294
32369
  const capture = () => {
31295
32370
  try {
31296
- const { execSync: execSync19 } = __require("child_process");
31297
- const output2 = execSync19(
32371
+ const { execSync: execSync20 } = __require("child_process");
32372
+ const output2 = execSync20(
31298
32373
  `tmux capture-pane -t ${JSON.stringify(sessionName)} -p -e 2>/dev/null | tail -${CAPTURE_LINES}`,
31299
32374
  { encoding: "utf8", timeout: 3e3 }
31300
32375
  );
@@ -31318,8 +32393,8 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
31318
32393
  if (key.return) {
31319
32394
  if (!demo && inputBuffer.trim()) {
31320
32395
  try {
31321
- const { execSync: execSync19 } = __require("child_process");
31322
- execSync19(
32396
+ const { execSync: execSync20 } = __require("child_process");
32397
+ execSync20(
31323
32398
  `tmux send-keys -t ${JSON.stringify(sessionName)} ${JSON.stringify(inputBuffer)} Enter`,
31324
32399
  { timeout: 2e3 }
31325
32400
  );
@@ -31327,8 +32402,8 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
31327
32402
  }
31328
32403
  } else if (!demo) {
31329
32404
  try {
31330
- const { execSync: execSync19 } = __require("child_process");
31331
- execSync19(`tmux send-keys -t ${JSON.stringify(sessionName)} Enter`, { timeout: 2e3 });
32405
+ const { execSync: execSync20 } = __require("child_process");
32406
+ execSync20(`tmux send-keys -t ${JSON.stringify(sessionName)} Enter`, { timeout: 2e3 });
31332
32407
  } catch {
31333
32408
  }
31334
32409
  }
@@ -31808,12 +32883,12 @@ function useOrchestrator(enabled = true) {
31808
32883
  searchFn: async () => [],
31809
32884
  autoApproveP2: true
31810
32885
  });
31811
- await runHealthCheck();
32886
+ await runHealthCheck2();
31812
32887
  } catch {
31813
32888
  setIsLoading(false);
31814
32889
  }
31815
32890
  }
31816
- async function runHealthCheck() {
32891
+ async function runHealthCheck2() {
31817
32892
  if (cancelled || !orchestratorRef.current) return;
31818
32893
  try {
31819
32894
  const health = await orchestratorRef.current.healthCheck();
@@ -31842,7 +32917,7 @@ function useOrchestrator(enabled = true) {
31842
32917
  setIsLoading(false);
31843
32918
  }
31844
32919
  init();
31845
- const timer = setInterval(runHealthCheck, TICK_INTERVAL_MS);
32920
+ const timer = setInterval(runHealthCheck2, TICK_INTERVAL_MS);
31846
32921
  return () => {
31847
32922
  cancelled = true;
31848
32923
  clearInterval(timer);
@@ -31922,7 +32997,7 @@ var init_useOrchestrator = __esm({
31922
32997
 
31923
32998
  // src/tui/views/Sessions.tsx
31924
32999
  import React19, { useState as useState9, useEffect as useEffect11, useCallback as useCallback6 } from "react";
31925
- import path50 from "path";
33000
+ import path52 from "path";
31926
33001
  import { homedir as homedir7 } from "os";
31927
33002
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
31928
33003
  function isCoordinatorEntry(entry) {
@@ -31960,7 +33035,7 @@ function SessionsView({
31960
33035
  if (demo) {
31961
33036
  setProjects(DEMO_PROJECTS.map((p) => ({
31962
33037
  ...p,
31963
- projectDir: path50.join(homedir7(), p.projectName),
33038
+ projectDir: path52.join(homedir7(), p.projectName),
31964
33039
  employees: p.employees.map((e) => ({ ...e, attached: e.status === "active" }))
31965
33040
  })));
31966
33041
  return;
@@ -32015,12 +33090,12 @@ function SessionsView({
32015
33090
  return;
32016
33091
  }
32017
33092
  } else {
32018
- const { execSync: execSync19 } = await import("child_process");
33093
+ const { execSync: execSync20 } = await import("child_process");
32019
33094
  const dir = projectDir || process.cwd();
32020
- execSync19(`tmux new-session -d -s ${JSON.stringify(entry.sessionName)} -c ${JSON.stringify(dir)}`, { timeout: 5e3 });
32021
- execSync19(`tmux send-keys -t ${JSON.stringify(entry.sessionName)} "claude --dangerously-skip-permissions" Enter`, { timeout: 3e3 });
33095
+ execSync20(`tmux new-session -d -s ${JSON.stringify(entry.sessionName)} -c ${JSON.stringify(dir)}`, { timeout: 5e3 });
33096
+ execSync20(`tmux send-keys -t ${JSON.stringify(entry.sessionName)} "claude --dangerously-skip-permissions" Enter`, { timeout: 3e3 });
32022
33097
  await new Promise((r) => setTimeout(r, 3e3));
32023
- execSync19(`tmux send-keys -t ${JSON.stringify(entry.sessionName)} "/exe" Enter`, { timeout: 3e3 });
33098
+ execSync20(`tmux send-keys -t ${JSON.stringify(entry.sessionName)} "/exe" Enter`, { timeout: 3e3 });
32024
33099
  }
32025
33100
  const updated = { ...entry, status: "active", activity: "Starting...", attached: false };
32026
33101
  setViewingEmployee(updated);
@@ -32123,7 +33198,7 @@ function SessionsView({
32123
33198
  const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2, capturePaneLines: capturePaneLines2, parseActivity: parseActivity2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
32124
33199
  const { getCoordinatorName: getCoordinatorName2, isCoordinatorRole: isCoordinatorRole2, loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
32125
33200
  const { isExeSession: isExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
32126
- const { execSync: execSync19 } = await import("child_process");
33201
+ const { execSync: execSync20 } = await import("child_process");
32127
33202
  if (!inTmux2()) {
32128
33203
  setTmuxAvailable(false);
32129
33204
  setProjects([]);
@@ -32132,7 +33207,7 @@ function SessionsView({
32132
33207
  setTmuxAvailable(true);
32133
33208
  const attachedMap = /* @__PURE__ */ new Map();
32134
33209
  try {
32135
- const out = execSync19("tmux list-sessions -F '#{session_name}:#{session_attached}' 2>/dev/null", {
33210
+ const out = execSync20("tmux list-sessions -F '#{session_name}:#{session_attached}' 2>/dev/null", {
32136
33211
  encoding: "utf8",
32137
33212
  timeout: 3e3
32138
33213
  });
@@ -33168,19 +34243,19 @@ function upsertConversation(conversations, platform, senderId, message) {
33168
34243
  async function loadGatewayConfig() {
33169
34244
  const state = { running: false, port: 3100, adapters: [], agents: [], gatewayUrl: "" };
33170
34245
  try {
33171
- const { execSync: execSync19 } = await import("child_process");
33172
- const ps = execSync19("pgrep -f exe-gateway 2>/dev/null", { encoding: "utf8", timeout: 3e3 });
34246
+ const { execSync: execSync20 } = await import("child_process");
34247
+ const ps = execSync20("pgrep -f exe-gateway 2>/dev/null", { encoding: "utf8", timeout: 3e3 });
33173
34248
  state.running = ps.trim().length > 0;
33174
34249
  } catch {
33175
34250
  state.running = false;
33176
34251
  }
33177
34252
  try {
33178
- const { existsSync: existsSync41, readFileSync: readFileSync37 } = await import("fs");
34253
+ const { existsSync: existsSync43, readFileSync: readFileSync39 } = await import("fs");
33179
34254
  const { join } = await import("path");
33180
34255
  const home = process.env.HOME ?? "";
33181
34256
  const configPath = join(home, ".exe-os", "gateway.json");
33182
- if (existsSync41(configPath)) {
33183
- const raw = JSON.parse(readFileSync37(configPath, "utf8"));
34257
+ if (existsSync43(configPath)) {
34258
+ const raw = JSON.parse(readFileSync39(configPath, "utf8"));
33184
34259
  state.port = raw.port ?? 3100;
33185
34260
  state.gatewayUrl = raw.gatewayUrl ?? "";
33186
34261
  if (raw.adapters) {
@@ -33646,10 +34721,10 @@ var init_Gateway = __esm({
33646
34721
  });
33647
34722
 
33648
34723
  // src/tui/utils/agent-status.ts
33649
- import { execSync as execSync18 } from "child_process";
34724
+ import { execSync as execSync19 } from "child_process";
33650
34725
  function getAgentStatus(agentId) {
33651
34726
  try {
33652
- const sessions = execSync18("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
34727
+ const sessions = execSync19("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
33653
34728
  encoding: "utf8",
33654
34729
  timeout: 2e3
33655
34730
  }).trim().split("\n");
@@ -33660,7 +34735,7 @@ function getAgentStatus(agentId) {
33660
34735
  return /^\d?-/.test(suffix) || /^\d+$/.test(suffix);
33661
34736
  });
33662
34737
  if (!agentSession) return { label: "offline", color: "gray" };
33663
- const pane = execSync18(`tmux capture-pane -t "${agentSession}" -p 2>/dev/null | tail -3`, {
34738
+ const pane = execSync19(`tmux capture-pane -t "${agentSession}" -p 2>/dev/null | tail -3`, {
33664
34739
  encoding: "utf8",
33665
34740
  timeout: 2e3
33666
34741
  });
@@ -33778,12 +34853,12 @@ function TeamView({ onBack, onViewSessions }) {
33778
34853
  setMembers(teamData);
33779
34854
  setDbError(null);
33780
34855
  try {
33781
- const { existsSync: existsSync41, readFileSync: readFileSync37 } = await import("fs");
34856
+ const { existsSync: existsSync43, readFileSync: readFileSync39 } = await import("fs");
33782
34857
  const { join } = await import("path");
33783
34858
  const home = process.env.HOME ?? "";
33784
34859
  const gatewayConfig = join(home, ".exe-os", "gateway.json");
33785
- if (existsSync41(gatewayConfig)) {
33786
- const raw = JSON.parse(readFileSync37(gatewayConfig, "utf8"));
34860
+ if (existsSync43(gatewayConfig)) {
34861
+ const raw = JSON.parse(readFileSync39(gatewayConfig, "utf8"));
33787
34862
  if (raw.agents && raw.agents.length > 0) {
33788
34863
  setExternals(raw.agents.map((a) => ({
33789
34864
  name: a.name,
@@ -33963,8 +35038,8 @@ __export(wiki_client_exports, {
33963
35038
  listDocuments: () => listDocuments,
33964
35039
  listWorkspaces: () => listWorkspaces
33965
35040
  });
33966
- async function wikiFetch(config, path56, method = "GET", body) {
33967
- const url = `${config.baseUrl}/api/v1${path56}`;
35041
+ async function wikiFetch(config, path58, method = "GET", body) {
35042
+ const url = `${config.baseUrl}/api/v1${path58}`;
33968
35043
  const headers = {
33969
35044
  Authorization: `Bearer ${config.apiKey}`,
33970
35045
  "Content-Type": "application/json"
@@ -33997,7 +35072,7 @@ async function wikiFetch(config, path56, method = "GET", body) {
33997
35072
  }
33998
35073
  }
33999
35074
  if (!response.ok) {
34000
- throw new Error(`Wiki API ${method} ${path56}: ${response.status} ${response.statusText}`);
35075
+ throw new Error(`Wiki API ${method} ${path58}: ${response.status} ${response.statusText}`);
34001
35076
  }
34002
35077
  return response.json();
34003
35078
  } finally {
@@ -34583,20 +35658,20 @@ function SettingsView({ onBack }) {
34583
35658
  };
34584
35659
  });
34585
35660
  try {
34586
- const { execSync: execSync19 } = await import("child_process");
34587
- execSync19("curl -s --max-time 1 http://localhost:11434/api/tags", { timeout: 2e3 });
35661
+ const { execSync: execSync20 } = await import("child_process");
35662
+ execSync20("curl -s --max-time 1 http://localhost:11434/api/tags", { timeout: 2e3 });
34588
35663
  providerList.push({ name: "Ollama", configured: true, detail: "localhost:11434" });
34589
35664
  } catch {
34590
35665
  providerList.push({ name: "Ollama", configured: false, detail: "not running" });
34591
35666
  }
34592
35667
  setProviders(providerList);
34593
35668
  try {
34594
- const { existsSync: existsSync41 } = await import("fs");
35669
+ const { existsSync: existsSync43 } = await import("fs");
34595
35670
  const { join } = await import("path");
34596
35671
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
34597
35672
  const cfg = await loadConfig2();
34598
35673
  const home = process.env.HOME ?? "";
34599
- const hasKey = existsSync41(join(home, ".exe-os", "master.key"));
35674
+ const hasKey = existsSync43(join(home, ".exe-os", "master.key"));
34600
35675
  if (cfg.cloud) {
34601
35676
  setCloud({
34602
35677
  configured: true,
@@ -34609,22 +35684,22 @@ function SettingsView({ onBack }) {
34609
35684
  const pidPath = join(home, ".exe-os", "exed.pid");
34610
35685
  let daemon = "unknown";
34611
35686
  try {
34612
- daemon = existsSync41(pidPath) ? "running" : "stopped";
35687
+ daemon = existsSync43(pidPath) ? "running" : "stopped";
34613
35688
  } catch {
34614
35689
  }
34615
35690
  let version = "unknown";
34616
35691
  try {
34617
- const { readFileSync: readFileSync37 } = await import("fs");
35692
+ const { readFileSync: readFileSync39 } = await import("fs");
34618
35693
  const { createRequire: createRequire3 } = await import("module");
34619
35694
  const require2 = createRequire3(import.meta.url);
34620
35695
  const pkgPath = require2.resolve("@askexenow/exe-os/package.json");
34621
- const pkg = JSON.parse(readFileSync37(pkgPath, "utf8"));
35696
+ const pkg = JSON.parse(readFileSync39(pkgPath, "utf8"));
34622
35697
  version = pkg.version;
34623
35698
  } catch {
34624
35699
  try {
34625
- const { readFileSync: readFileSync37 } = await import("fs");
35700
+ const { readFileSync: readFileSync39 } = await import("fs");
34626
35701
  const { join: joinPath } = await import("path");
34627
- const pkg = JSON.parse(readFileSync37(joinPath(process.cwd(), "package.json"), "utf8"));
35702
+ const pkg = JSON.parse(readFileSync39(joinPath(process.cwd(), "package.json"), "utf8"));
34628
35703
  version = pkg.version;
34629
35704
  } catch {
34630
35705
  }
@@ -35483,18 +36558,18 @@ __export(code_context_index_exports, {
35483
36558
  traceCodeSymbol: () => traceCodeSymbol
35484
36559
  });
35485
36560
  import crypto14 from "crypto";
35486
- import path51 from "path";
35487
- import { existsSync as existsSync36, mkdirSync as mkdirSync25, readFileSync as readFileSync32, readdirSync as readdirSync11, statSync as statSync7, writeFileSync as writeFileSync26 } from "fs";
36561
+ import path53 from "path";
36562
+ import { existsSync as existsSync38, mkdirSync as mkdirSync26, readFileSync as readFileSync34, readdirSync as readdirSync12, statSync as statSync8, writeFileSync as writeFileSync27 } from "fs";
35488
36563
  import { spawnSync as spawnSync3 } from "child_process";
35489
36564
  function vectorStorePath(projectRoot) {
35490
36565
  const rootHash = hashText(projectRoot).slice(0, 16);
35491
- return path51.join(indexDir(), `${rootHash}.vectors.json`);
36566
+ return path53.join(indexDir(), `${rootHash}.vectors.json`);
35492
36567
  }
35493
36568
  function loadVectorStore(projectRoot) {
35494
36569
  const file = vectorStorePath(projectRoot);
35495
- if (!existsSync36(file)) return null;
36570
+ if (!existsSync38(file)) return null;
35496
36571
  try {
35497
- const parsed = JSON.parse(readFileSync32(file, "utf8"));
36572
+ const parsed = JSON.parse(readFileSync34(file, "utf8"));
35498
36573
  if (parsed.version !== VECTOR_STORE_VERSION) return null;
35499
36574
  return parsed;
35500
36575
  } catch {
@@ -35502,7 +36577,7 @@ function loadVectorStore(projectRoot) {
35502
36577
  }
35503
36578
  }
35504
36579
  function saveVectorStore(projectRoot, store) {
35505
- writeFileSync26(vectorStorePath(projectRoot), JSON.stringify(store));
36580
+ writeFileSync27(vectorStorePath(projectRoot), JSON.stringify(store));
35506
36581
  }
35507
36582
  function cosineSimilarity(a, b) {
35508
36583
  let dot = 0, normA = 0, normB = 0;
@@ -35558,20 +36633,20 @@ async function embedSymbols(index) {
35558
36633
  return store;
35559
36634
  }
35560
36635
  function normalizeProjectRoot(projectRoot) {
35561
- return path51.resolve(projectRoot || process.cwd());
36636
+ return path53.resolve(projectRoot || process.cwd());
35562
36637
  }
35563
36638
  function hashText(text) {
35564
36639
  return crypto14.createHash("sha256").update(text).digest("hex");
35565
36640
  }
35566
36641
  function indexDir() {
35567
- const dir = path51.join(EXE_AI_DIR, "code-context");
35568
- mkdirSync25(dir, { recursive: true });
36642
+ const dir = path53.join(EXE_AI_DIR, "code-context");
36643
+ mkdirSync26(dir, { recursive: true });
35569
36644
  return dir;
35570
36645
  }
35571
36646
  function getCodeContextIndexPath(projectRoot) {
35572
36647
  const root = normalizeProjectRoot(projectRoot);
35573
36648
  const rootHash = hashText(root).slice(0, 16);
35574
- return path51.join(indexDir(), `${rootHash}.json`);
36649
+ return path53.join(indexDir(), `${rootHash}.json`);
35575
36650
  }
35576
36651
  function currentBranch(projectRoot) {
35577
36652
  const result = spawnSync3("git", ["branch", "--show-current"], { cwd: projectRoot, encoding: "utf8", timeout: 2e3 });
@@ -35583,9 +36658,9 @@ function shouldIgnore(relPath) {
35583
36658
  return parts.some((part) => IGNORE_SEGMENTS.has(part));
35584
36659
  }
35585
36660
  function listRecursive(projectRoot, dir = projectRoot, out = []) {
35586
- for (const entry of readdirSync11(dir, { withFileTypes: true })) {
35587
- const abs = path51.join(dir, entry.name);
35588
- const rel = path51.relative(projectRoot, abs).replaceAll(path51.sep, "/");
36661
+ for (const entry of readdirSync12(dir, { withFileTypes: true })) {
36662
+ const abs = path53.join(dir, entry.name);
36663
+ const rel = path53.relative(projectRoot, abs).replaceAll(path53.sep, "/");
35589
36664
  if (shouldIgnore(rel)) continue;
35590
36665
  if (entry.isDirectory()) listRecursive(projectRoot, abs, out);
35591
36666
  else if (entry.isFile()) out.push(rel);
@@ -35601,7 +36676,7 @@ function listCodeFiles(projectRoot, maxFiles) {
35601
36676
  const rg = spawnSync3("rg", ["--files"], { cwd: projectRoot, encoding: "utf8", timeout: 5e3, maxBuffer: 1024 * 1024 * 16 });
35602
36677
  files = rg.status === 0 && rg.stdout.trim() ? rg.stdout.split("\n").map((s) => s.trim()).filter(Boolean) : listRecursive(projectRoot);
35603
36678
  }
35604
- return files.map((file) => file.replaceAll(path51.sep, "/")).filter((file) => isChunkable(file) && !shouldIgnore(file)).slice(0, maxFiles).sort();
36679
+ return files.map((file) => file.replaceAll(path53.sep, "/")).filter((file) => isChunkable(file) && !shouldIgnore(file)).slice(0, maxFiles).sort();
35605
36680
  }
35606
36681
  function parseImportPaths(importText) {
35607
36682
  const paths = [];
@@ -35614,13 +36689,13 @@ function parseImportPaths(importText) {
35614
36689
  }
35615
36690
  function resolveImport(fromFile, importPath, allFiles) {
35616
36691
  if (!importPath.startsWith(".")) return null;
35617
- const base = path51.posix.normalize(path51.posix.join(path51.posix.dirname(fromFile.replaceAll(path51.sep, "/")), importPath));
36692
+ const base = path53.posix.normalize(path53.posix.join(path53.posix.dirname(fromFile.replaceAll(path53.sep, "/")), importPath));
35618
36693
  const withoutKnownExt = base.replace(/\.(?:[a-z0-9]+)$/i, "");
35619
36694
  const candidates = [base];
35620
36695
  for (const ext of ["ts", "tsx", "js", "jsx", "py", "rs", "go", "java", "cs", "cpp", "c", "rb", "php", "swift", "kt", "scala", "sql", "md", "json", "yaml", "yml"]) {
35621
36696
  candidates.push(`${withoutKnownExt}.${ext}`, `${base}.${ext}`);
35622
36697
  }
35623
- for (const indexName of ["index.ts", "index.tsx", "index.js", "mod.rs", "__init__.py"]) candidates.push(path51.posix.join(base, indexName));
36698
+ for (const indexName of ["index.ts", "index.tsx", "index.js", "mod.rs", "__init__.py"]) candidates.push(path53.posix.join(base, indexName));
35624
36699
  return candidates.find((candidate) => allFiles.has(candidate)) ?? null;
35625
36700
  }
35626
36701
  function symbolId(filePath, chunk) {
@@ -35628,9 +36703,9 @@ function symbolId(filePath, chunk) {
35628
36703
  }
35629
36704
  function loadIndex(projectRoot) {
35630
36705
  const file = getCodeContextIndexPath(projectRoot);
35631
- if (!existsSync36(file)) return null;
36706
+ if (!existsSync38(file)) return null;
35632
36707
  try {
35633
- const parsed = JSON.parse(readFileSync32(file, "utf8"));
36708
+ const parsed = JSON.parse(readFileSync34(file, "utf8"));
35634
36709
  if (parsed.version !== INDEX_VERSION || parsed.projectRoot !== projectRoot) return null;
35635
36710
  return parsed;
35636
36711
  } catch {
@@ -35638,20 +36713,20 @@ function loadIndex(projectRoot) {
35638
36713
  }
35639
36714
  }
35640
36715
  function saveIndex(index) {
35641
- writeFileSync26(getCodeContextIndexPath(index.projectRoot), JSON.stringify(index, null, 2));
36716
+ writeFileSync27(getCodeContextIndexPath(index.projectRoot), JSON.stringify(index, null, 2));
35642
36717
  }
35643
36718
  function buildFileRecord(projectRoot, relPath, allFiles, previous) {
35644
- const absPath = path51.join(projectRoot, relPath);
36719
+ const absPath = path53.join(projectRoot, relPath);
35645
36720
  let stat2;
35646
36721
  try {
35647
- stat2 = statSync7(absPath);
36722
+ stat2 = statSync8(absPath);
35648
36723
  } catch {
35649
36724
  return { record: null, reused: false };
35650
36725
  }
35651
36726
  if (!stat2.isFile()) return { record: null, reused: false };
35652
36727
  const language = languageForFile(relPath);
35653
36728
  if (!language || !isChunkable(relPath)) return { record: null, reused: false };
35654
- const source = readFileSync32(absPath, "utf8");
36729
+ const source = readFileSync34(absPath, "utf8");
35655
36730
  const hash = hashText(source);
35656
36731
  if (previous && previous.hash === hash && previous.mtimeMs === stat2.mtimeMs && previous.size === stat2.size && previous.language === language) {
35657
36732
  return { record: previous, reused: true };
@@ -35679,13 +36754,13 @@ function buildCodeContextIndex(options = {}) {
35679
36754
  const branch = currentBranch(projectRoot);
35680
36755
  const previous = options.force ? null : loadIndex(projectRoot);
35681
36756
  const files = listCodeFiles(projectRoot, maxFiles);
35682
- const allFiles = new Set(files.map((file) => file.replaceAll(path51.sep, "/")));
36757
+ const allFiles = new Set(files.map((file) => file.replaceAll(path53.sep, "/")));
35683
36758
  const fileRecords = {};
35684
36759
  let rebuiltFiles = 0;
35685
36760
  let reusedFiles = 0;
35686
36761
  let skippedFiles = 0;
35687
36762
  for (const rel of files) {
35688
- const normalized = rel.replaceAll(path51.sep, "/");
36763
+ const normalized = rel.replaceAll(path53.sep, "/");
35689
36764
  const { record, reused } = buildFileRecord(projectRoot, normalized, allFiles, previous?.files[normalized]);
35690
36765
  if (record) {
35691
36766
  fileRecords[normalized] = record;
@@ -35714,11 +36789,11 @@ function loadOrBuildCodeContextIndex(options = {}) {
35714
36789
  if (loaded) {
35715
36790
  const currentFiles = listCodeFiles(projectRoot, options.maxFiles ?? DEFAULT_MAX_FILES);
35716
36791
  const unchanged = currentFiles.every((rel) => {
35717
- const normalized = rel.replaceAll(path51.sep, "/");
36792
+ const normalized = rel.replaceAll(path53.sep, "/");
35718
36793
  const existing = loaded.files[normalized];
35719
36794
  if (!existing) return false;
35720
36795
  try {
35721
- const stat2 = statSync7(path51.join(projectRoot, normalized));
36796
+ const stat2 = statSync8(path53.join(projectRoot, normalized));
35722
36797
  return stat2.mtimeMs === existing.mtimeMs && stat2.size === existing.size;
35723
36798
  } catch {
35724
36799
  return false;
@@ -35771,9 +36846,9 @@ function globToRegex(pattern) {
35771
36846
  }
35772
36847
  function matchesPath(filePath, patterns) {
35773
36848
  if (!patterns || patterns.length === 0) return true;
35774
- const normalized = filePath.replaceAll(path51.sep, "/");
36849
+ const normalized = filePath.replaceAll(path53.sep, "/");
35775
36850
  return patterns.some((pattern) => {
35776
- const p = pattern.replaceAll(path51.sep, "/").replace(/^\.\//, "");
36851
+ const p = pattern.replaceAll(path53.sep, "/").replace(/^\.\//, "");
35777
36852
  return normalized === p || normalized.startsWith(`${p}/`) || normalized.endsWith(p) || globToRegex(p).test(normalized);
35778
36853
  });
35779
36854
  }
@@ -35966,7 +37041,7 @@ function traceCodeSymbol(symbolName, options = {}) {
35966
37041
  }
35967
37042
  function resolveTargetFile(index, input) {
35968
37043
  if (input.filePath) {
35969
- const normalized = input.filePath.replaceAll(path51.sep, "/").replace(/^\.\//, "");
37044
+ const normalized = input.filePath.replaceAll(path53.sep, "/").replace(/^\.\//, "");
35970
37045
  if (index.files[normalized]) return { filePath: normalized, target: normalized };
35971
37046
  const suffix = Object.keys(index.files).find((file) => file.endsWith(normalized));
35972
37047
  if (suffix) return { filePath: suffix, target: input.filePath };
@@ -35996,7 +37071,7 @@ function analyzeBlastRadius(input) {
35996
37071
  }
35997
37072
  }
35998
37073
  }
35999
- const targetBase = path51.basename(target.filePath).replace(/\.[^.]+$/, "").toLowerCase();
37074
+ const targetBase = path53.basename(target.filePath).replace(/\.[^.]+$/, "").toLowerCase();
36000
37075
  const symbolLower = input.symbol?.toLowerCase();
36001
37076
  const tests = Object.keys(index.files).filter((file) => {
36002
37077
  const lower = file.toLowerCase();
@@ -36233,16 +37308,16 @@ __export(installer_exports2, {
36233
37308
  verifyOpenCodeHooks: () => verifyOpenCodeHooks
36234
37309
  });
36235
37310
  import { readFile as readFile7, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
36236
- import { existsSync as existsSync37, readFileSync as readFileSync33 } from "fs";
36237
- import path52 from "path";
37311
+ import { existsSync as existsSync39, readFileSync as readFileSync35 } from "fs";
37312
+ import path54 from "path";
36238
37313
  import os22 from "os";
36239
37314
  async function registerOpenCodeMcp(packageRoot, homeDir = os22.homedir()) {
36240
37315
  void packageRoot;
36241
- const configDir = path52.join(homeDir, ".config", "opencode");
36242
- const configPath = path52.join(configDir, "opencode.json");
37316
+ const configDir = path54.join(homeDir, ".config", "opencode");
37317
+ const configPath = path54.join(configDir, "opencode.json");
36243
37318
  await mkdir8(configDir, { recursive: true });
36244
37319
  let config = {};
36245
- if (existsSync37(configPath)) {
37320
+ if (existsSync39(configPath)) {
36246
37321
  try {
36247
37322
  config = JSON.parse(await readFile7(configPath, "utf-8"));
36248
37323
  } catch {
@@ -36270,14 +37345,14 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os22.homedir()) {
36270
37345
  return true;
36271
37346
  }
36272
37347
  async function installOpenCodePlugin(packageRoot, homeDir = os22.homedir()) {
36273
- const pluginDir = path52.join(homeDir, ".config", "opencode", "plugins");
36274
- const pluginPath = path52.join(pluginDir, "exe-os.mjs");
37348
+ const pluginDir = path54.join(homeDir, ".config", "opencode", "plugins");
37349
+ const pluginPath = path54.join(pluginDir, "exe-os.mjs");
36275
37350
  await mkdir8(pluginDir, { recursive: true });
36276
37351
  const pluginContent = PLUGIN_TEMPLATE.replace(
36277
37352
  /__PACKAGE_ROOT__/g,
36278
37353
  packageRoot.replace(/\\/g, "\\\\")
36279
37354
  );
36280
- if (existsSync37(pluginPath)) {
37355
+ if (existsSync39(pluginPath)) {
36281
37356
  const existing = await readFile7(pluginPath, "utf-8");
36282
37357
  if (existing === pluginContent) {
36283
37358
  return false;
@@ -36287,18 +37362,18 @@ async function installOpenCodePlugin(packageRoot, homeDir = os22.homedir()) {
36287
37362
  return true;
36288
37363
  }
36289
37364
  function verifyOpenCodeHooks(homeDir = os22.homedir()) {
36290
- const configPath = path52.join(homeDir, ".config", "opencode", "opencode.json");
36291
- const pluginPath = path52.join(homeDir, ".config", "opencode", "plugins", "exe-os.mjs");
36292
- if (!existsSync37(configPath)) return false;
37365
+ const configPath = path54.join(homeDir, ".config", "opencode", "opencode.json");
37366
+ const pluginPath = path54.join(homeDir, ".config", "opencode", "plugins", "exe-os.mjs");
37367
+ if (!existsSync39(configPath)) return false;
36293
37368
  try {
36294
- const config = JSON.parse(readFileSync33(configPath, "utf-8"));
37369
+ const config = JSON.parse(readFileSync35(configPath, "utf-8"));
36295
37370
  if (!config.mcp?.["exe-os"]?.enabled) return false;
36296
37371
  } catch {
36297
37372
  return false;
36298
37373
  }
36299
- if (!existsSync37(pluginPath)) return false;
37374
+ if (!existsSync39(pluginPath)) return false;
36300
37375
  try {
36301
- const plugin = readFileSync33(pluginPath, "utf-8");
37376
+ const plugin = readFileSync35(pluginPath, "utf-8");
36302
37377
  if (!plugin.includes(EXE_HOOK_FILES.postToolCombined)) return false;
36303
37378
  if (textHasLegacySplitPostToolHook(plugin)) return false;
36304
37379
  } catch {
@@ -36340,19 +37415,19 @@ __export(installer_exports3, {
36340
37415
  verifyCodexHooks: () => verifyCodexHooks
36341
37416
  });
36342
37417
  import { readFile as readFile8, writeFile as writeFile9, mkdir as mkdir9 } from "fs/promises";
36343
- import { existsSync as existsSync38, readFileSync as readFileSync34 } from "fs";
36344
- import path53 from "path";
37418
+ import { existsSync as existsSync40, readFileSync as readFileSync36 } from "fs";
37419
+ import path55 from "path";
36345
37420
  import os23 from "os";
36346
37421
  async function mergeCodexHooks(packageRoot, homeDir = os23.homedir()) {
36347
- const codexDir = path53.join(homeDir, ".codex");
36348
- const hooksPath = path53.join(codexDir, "hooks.json");
36349
- const logsDir = path53.join(homeDir, ".exe-os", "logs");
36350
- const hookLogPath = path53.join(logsDir, "hooks.log");
37422
+ const codexDir = path55.join(homeDir, ".codex");
37423
+ const hooksPath = path55.join(codexDir, "hooks.json");
37424
+ const logsDir = path55.join(homeDir, ".exe-os", "logs");
37425
+ const hookLogPath = path55.join(logsDir, "hooks.log");
36351
37426
  const logSuffix = ` 2>> "${hookLogPath}"`;
36352
37427
  await mkdir9(codexDir, { recursive: true });
36353
37428
  await mkdir9(logsDir, { recursive: true });
36354
37429
  let hooksJson = {};
36355
- if (existsSync38(hooksPath)) {
37430
+ if (existsSync40(hooksPath)) {
36356
37431
  try {
36357
37432
  hooksJson = JSON.parse(await readFile8(hooksPath, "utf-8"));
36358
37433
  } catch {
@@ -36372,7 +37447,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os23.homedir()) {
36372
37447
  // Combined hook: runs ingest + error-recall in one Node process.
36373
37448
  // Eliminates a cold-start cycle per tool call (~3-6s savings on Codex).
36374
37449
  type: "command",
36375
- command: `node "${path53.join(packageRoot, "dist", "hooks", "post-tool-combined.js")}"${logSuffix}`
37450
+ command: `node "${path55.join(packageRoot, "dist", "hooks", "post-tool-combined.js")}"${logSuffix}`
36376
37451
  }
36377
37452
  ]
36378
37453
  },
@@ -36386,7 +37461,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os23.homedir()) {
36386
37461
  // Single hook: prompt-submit handles memory retrieval + entity boost.
36387
37462
  // exe-heartbeat-hook is CC-specific (intercom) — omitted on Codex.
36388
37463
  type: "command",
36389
- command: `node "${path53.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
37464
+ command: `node "${path55.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
36390
37465
  }
36391
37466
  ]
36392
37467
  },
@@ -36398,7 +37473,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os23.homedir()) {
36398
37473
  hooks: [
36399
37474
  {
36400
37475
  type: "command",
36401
- command: `node "${path53.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
37476
+ command: `node "${path55.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
36402
37477
  }
36403
37478
  ]
36404
37479
  },
@@ -36411,7 +37486,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os23.homedir()) {
36411
37486
  hooks: [
36412
37487
  {
36413
37488
  type: "command",
36414
- command: `node "${path53.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
37489
+ command: `node "${path55.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
36415
37490
  }
36416
37491
  ]
36417
37492
  },
@@ -36460,10 +37535,10 @@ async function mergeCodexHooks(packageRoot, homeDir = os23.homedir()) {
36460
37535
  return { added, skipped };
36461
37536
  }
36462
37537
  function verifyCodexHooks(homeDir = os23.homedir()) {
36463
- const hooksPath = path53.join(homeDir, ".codex", "hooks.json");
36464
- if (!existsSync38(hooksPath)) return false;
37538
+ const hooksPath = path55.join(homeDir, ".codex", "hooks.json");
37539
+ if (!existsSync40(hooksPath)) return false;
36465
37540
  try {
36466
- const hooksJson = JSON.parse(readFileSync34(hooksPath, "utf-8"));
37541
+ const hooksJson = JSON.parse(readFileSync36(hooksPath, "utf-8"));
36467
37542
  if (!hooksJson.hooks) return false;
36468
37543
  const required = ["PostToolUse", "UserPromptSubmit", "Stop", "PreToolUse"];
36469
37544
  for (const event of required) {
@@ -36495,11 +37570,11 @@ function verifyCodexHooks(homeDir = os23.homedir()) {
36495
37570
  async function installCodexStatusLine(homeDir = os23.homedir()) {
36496
37571
  const prefs = loadPreferences(homeDir);
36497
37572
  if (prefs.codexStatusLine === false) return "opted-out";
36498
- const codexDir = path53.join(homeDir, ".codex");
36499
- const configPath = path53.join(codexDir, "config.toml");
37573
+ const codexDir = path55.join(homeDir, ".codex");
37574
+ const configPath = path55.join(codexDir, "config.toml");
36500
37575
  await mkdir9(codexDir, { recursive: true });
36501
37576
  let content = "";
36502
- if (existsSync38(configPath)) {
37577
+ if (existsSync40(configPath)) {
36503
37578
  content = await readFile8(configPath, "utf-8");
36504
37579
  if (/\[tui\][\s\S]*?status_line\s*=/.test(content)) {
36505
37580
  return "already-configured";
@@ -36551,12 +37626,12 @@ ${line}
36551
37626
  return { content: next, changed: next !== sectionContent };
36552
37627
  }
36553
37628
  async function registerCodexMcpServer(packageRoot, homeDir = os23.homedir()) {
36554
- const codexDir = path53.join(homeDir, ".codex");
36555
- const configPath = path53.join(codexDir, "config.toml");
37629
+ const codexDir = path55.join(homeDir, ".codex");
37630
+ const configPath = path55.join(codexDir, "config.toml");
36556
37631
  void packageRoot;
36557
37632
  await mkdir9(codexDir, { recursive: true });
36558
37633
  let content = "";
36559
- if (existsSync38(configPath)) {
37634
+ if (existsSync40(configPath)) {
36560
37635
  content = await readFile8(configPath, "utf-8");
36561
37636
  }
36562
37637
  const sectionHeader = "[mcp_servers.exe-os]";
@@ -36581,10 +37656,10 @@ async function registerCodexMcpServer(packageRoot, homeDir = os23.homedir()) {
36581
37656
  return "registered";
36582
37657
  }
36583
37658
  async function ensureCodexHooksFeature(homeDir = os23.homedir()) {
36584
- const configPath = path53.join(homeDir, ".codex", "config.toml");
36585
- await mkdir9(path53.join(homeDir, ".codex"), { recursive: true });
37659
+ const configPath = path55.join(homeDir, ".codex", "config.toml");
37660
+ await mkdir9(path55.join(homeDir, ".codex"), { recursive: true });
36586
37661
  let content = "";
36587
- if (existsSync38(configPath)) {
37662
+ if (existsSync40(configPath)) {
36588
37663
  content = await readFile8(configPath, "utf-8");
36589
37664
  }
36590
37665
  if (/\[features\][\s\S]*?codex_hooks\s*=\s*true/.test(content)) {
@@ -36659,32 +37734,32 @@ __export(mcp_diagnostics_exports, {
36659
37734
  diagnoseClaudeMcpConfig: () => diagnoseClaudeMcpConfig,
36660
37735
  formatMcpDiagnosticReport: () => formatMcpDiagnosticReport
36661
37736
  });
36662
- import { existsSync as existsSync39, readFileSync as readFileSync35 } from "fs";
36663
- import path54 from "path";
37737
+ import { existsSync as existsSync41, readFileSync as readFileSync37 } from "fs";
37738
+ import path56 from "path";
36664
37739
  import os24 from "os";
36665
37740
  function readJson(filePath) {
36666
- if (!existsSync39(filePath)) return null;
37741
+ if (!existsSync41(filePath)) return null;
36667
37742
  try {
36668
- return JSON.parse(readFileSync35(filePath, "utf8"));
37743
+ return JSON.parse(readFileSync37(filePath, "utf8"));
36669
37744
  } catch {
36670
37745
  return null;
36671
37746
  }
36672
37747
  }
36673
37748
  function pathApplies2(projectPath, cwd2) {
36674
- const project = path54.resolve(projectPath);
36675
- const current = path54.resolve(cwd2);
36676
- return current === project || current.startsWith(project + path54.sep);
37749
+ const project = path56.resolve(projectPath);
37750
+ const current = path56.resolve(cwd2);
37751
+ return current === project || current.startsWith(project + path56.sep);
36677
37752
  }
36678
37753
  function findAncestorMcpJsons2(cwd2, homeDir) {
36679
37754
  const files = [];
36680
- let dir = path54.resolve(cwd2);
36681
- const root = path54.parse(dir).root;
36682
- const stop = path54.resolve(homeDir);
37755
+ let dir = path56.resolve(cwd2);
37756
+ const root = path56.parse(dir).root;
37757
+ const stop = path56.resolve(homeDir);
36683
37758
  while (dir !== root) {
36684
- const candidate = path54.join(dir, ".mcp.json");
36685
- if (existsSync39(candidate)) files.push(candidate);
37759
+ const candidate = path56.join(dir, ".mcp.json");
37760
+ if (existsSync41(candidate)) files.push(candidate);
36686
37761
  if (dir === stop) break;
36687
- dir = path54.dirname(dir);
37762
+ dir = path56.dirname(dir);
36688
37763
  }
36689
37764
  return files;
36690
37765
  }
@@ -36701,8 +37776,8 @@ function serverAllowedByPermissions(serverName, prefixes) {
36701
37776
  return prefixes.has(serverName) || prefixes.has(serverName.replace(/-/g, "_"));
36702
37777
  }
36703
37778
  function diagnoseClaudeMcpConfig(homeDir = os24.homedir(), cwd2 = process.cwd(), env = process.env) {
36704
- const claudeJsonPath = path54.join(homeDir, ".claude.json");
36705
- const settingsPath = path54.join(homeDir, ".claude", "settings.json");
37779
+ const claudeJsonPath = path56.join(homeDir, ".claude.json");
37780
+ const settingsPath = path56.join(homeDir, ".claude", "settings.json");
36706
37781
  const claudeJson = readJson(claudeJsonPath);
36707
37782
  const settings = readJson(settingsPath);
36708
37783
  const issues = [];
@@ -36822,7 +37897,7 @@ function diagnoseClaudeMcpConfig(homeDir = os24.homedir(), cwd2 = process.cwd(),
36822
37897
  });
36823
37898
  }
36824
37899
  return {
36825
- cwd: path54.resolve(cwd2),
37900
+ cwd: path56.resolve(cwd2),
36826
37901
  globalServers,
36827
37902
  projectServers: projectServers.sort((a, b) => a.name.localeCompare(b.name)),
36828
37903
  mcpJsonServers: mcpJsonServers.sort((a, b) => a.name.localeCompare(b.name)),
@@ -36859,14 +37934,14 @@ var init_mcp_diagnostics = __esm({
36859
37934
  });
36860
37935
 
36861
37936
  // src/bin/cli.ts
36862
- import { existsSync as existsSync40, readFileSync as readFileSync36, writeFileSync as writeFileSync27, readdirSync as readdirSync12, rmSync as rmSync2 } from "fs";
36863
- import path55 from "path";
37937
+ import { existsSync as existsSync42, readFileSync as readFileSync38, writeFileSync as writeFileSync28, readdirSync as readdirSync13, rmSync as rmSync2 } from "fs";
37938
+ import path57 from "path";
36864
37939
  import os25 from "os";
36865
37940
  var args = process.argv.slice(2);
36866
37941
  if (args.includes("--version") || args.includes("-v")) {
36867
37942
  try {
36868
- const pkgPath = path55.join(path55.dirname(new URL(import.meta.url).pathname), "..", "..", "package.json");
36869
- const pkg = JSON.parse(readFileSync36(pkgPath, "utf8"));
37943
+ const pkgPath = path57.join(path57.dirname(new URL(import.meta.url).pathname), "..", "..", "package.json");
37944
+ const pkg = JSON.parse(readFileSync38(pkgPath, "utf8"));
36870
37945
  console.log(pkg.version);
36871
37946
  } catch {
36872
37947
  console.log("unknown");
@@ -37077,6 +38152,23 @@ ID: ${result.id}`);
37077
38152
  await runRename();
37078
38153
  } else if (args[0] === "--activate" || args[0] === "activate") {
37079
38154
  await runActivate(args[1]);
38155
+ } else if (args[0] === "doctor") {
38156
+ if (args.includes("--drift")) {
38157
+ const { runDrift: runDrift2 } = await Promise.resolve().then(() => (init_exe_drift(), exe_drift_exports));
38158
+ await runDrift2(args.slice(1));
38159
+ } else {
38160
+ const { runCcDoctor: runCcDoctor2 } = await Promise.resolve().then(() => (init_cc_doctor(), cc_doctor_exports));
38161
+ const { results, failed } = runCcDoctor2();
38162
+ console.log("\n exe-os doctor\n");
38163
+ for (const r of results) {
38164
+ const icon = r.pass ? "\x1B[32m\u2713\x1B[0m" : "\x1B[31m\u2717\x1B[0m";
38165
+ console.log(` ${icon} ${r.name}: ${r.detail}`);
38166
+ }
38167
+ console.log(failed === 0 ? "\n \x1B[32mAll checks passed\x1B[0m\n" : `
38168
+ \x1B[31m${failed} issue(s) found\x1B[0m
38169
+ `);
38170
+ process.exit(failed > 0 ? 1 : 0);
38171
+ }
37080
38172
  } else if (args[0] === "setup" || args[0] === "-setup" || args[0] === "--setup") {
37081
38173
  const { runSetupWizard: runSetupWizard2 } = await Promise.resolve().then(() => (init_setup_wizard(), setup_wizard_exports));
37082
38174
  await runSetupWizard2({ skipModel: args.includes("--skip-model") });
@@ -37094,11 +38186,11 @@ ID: ${result.id}`);
37094
38186
  });
37095
38187
  await init_App2().then(() => App_exports);
37096
38188
  } else {
37097
- const claudeDir = path55.join(os25.homedir(), ".claude");
37098
- const settingsPath = path55.join(claudeDir, "settings.json");
37099
- const hasClaudeCode = existsSync40(settingsPath) && (() => {
38189
+ const claudeDir = path57.join(os25.homedir(), ".claude");
38190
+ const settingsPath = path57.join(claudeDir, "settings.json");
38191
+ const hasClaudeCode = existsSync42(settingsPath) && (() => {
37100
38192
  try {
37101
- const raw = readFileSync36(settingsPath, "utf8");
38193
+ const raw = readFileSync38(settingsPath, "utf8");
37102
38194
  return raw.includes("exe-os") || raw.includes("exe-mem");
37103
38195
  } catch {
37104
38196
  return false;
@@ -37108,9 +38200,9 @@ ID: ${result.id}`);
37108
38200
  const { DEFAULT_COORDINATOR_TEMPLATE_NAME: DEFAULT_COORDINATOR_TEMPLATE_NAME2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
37109
38201
  let cooName = DEFAULT_COORDINATOR_TEMPLATE_NAME2;
37110
38202
  try {
37111
- const rosterPath = path55.join(os25.homedir(), ".exe-os", "exe-employees.json");
37112
- if (existsSync40(rosterPath)) {
37113
- const roster = JSON.parse(readFileSync36(rosterPath, "utf8"));
38203
+ const rosterPath = path57.join(os25.homedir(), ".exe-os", "exe-employees.json");
38204
+ if (existsSync42(rosterPath)) {
38205
+ const roster = JSON.parse(readFileSync38(rosterPath, "utf8"));
37114
38206
  const coo = roster.find((e) => e.role === "COO");
37115
38207
  if (coo) cooName = coo.name;
37116
38208
  }
@@ -37263,14 +38355,14 @@ async function runCodexInstall() {
37263
38355
  }
37264
38356
  async function runClaudeCheck() {
37265
38357
  const { detectMcpNameCollisions: detectMcpNameCollisions2 } = await Promise.resolve().then(() => (init_installer(), installer_exports));
37266
- const claudeDir = path55.join(os25.homedir(), ".claude");
37267
- const settingsPath = path55.join(claudeDir, "settings.json");
37268
- const claudeJsonPath = path55.join(os25.homedir(), ".claude.json");
38358
+ const claudeDir = path57.join(os25.homedir(), ".claude");
38359
+ const settingsPath = path57.join(claudeDir, "settings.json");
38360
+ const claudeJsonPath = path57.join(os25.homedir(), ".claude.json");
37269
38361
  let ok = true;
37270
- if (existsSync40(settingsPath)) {
38362
+ if (existsSync42(settingsPath)) {
37271
38363
  let settings;
37272
38364
  try {
37273
- settings = JSON.parse(readFileSync36(settingsPath, "utf8"));
38365
+ settings = JSON.parse(readFileSync38(settingsPath, "utf8"));
37274
38366
  } catch {
37275
38367
  console.log("\x1B[31m\u2717\x1B[0m settings.json is malformed (invalid JSON)");
37276
38368
  ok = false;
@@ -37296,10 +38388,10 @@ async function runClaudeCheck() {
37296
38388
  console.log("\x1B[31m\u2717\x1B[0m settings.json not found");
37297
38389
  ok = false;
37298
38390
  }
37299
- if (existsSync40(claudeJsonPath)) {
38391
+ if (existsSync42(claudeJsonPath)) {
37300
38392
  let claudeJson;
37301
38393
  try {
37302
- claudeJson = JSON.parse(readFileSync36(claudeJsonPath, "utf8"));
38394
+ claudeJson = JSON.parse(readFileSync38(claudeJsonPath, "utf8"));
37303
38395
  } catch {
37304
38396
  console.log("\x1B[31m\u2717\x1B[0m claude.json is malformed (invalid JSON)");
37305
38397
  ok = false;
@@ -37332,8 +38424,8 @@ async function runClaudeCheck() {
37332
38424
  } else {
37333
38425
  console.log("\x1B[32m\u2713\x1B[0m No .mcp.json/project MCP name collisions detected");
37334
38426
  }
37335
- const skillsDir = path55.join(claudeDir, "skills");
37336
- if (existsSync40(skillsDir)) {
38427
+ const skillsDir = path57.join(claudeDir, "skills");
38428
+ if (existsSync42(skillsDir)) {
37337
38429
  console.log("\x1B[32m\u2713\x1B[0m Slash skills directory exists");
37338
38430
  } else {
37339
38431
  console.log("\x1B[31m\u2717\x1B[0m Slash skills directory missing");
@@ -37357,16 +38449,16 @@ async function runClaudeUninstall(flags = []) {
37357
38449
  const dryRun = flags.includes("--dry-run");
37358
38450
  const purge = flags.includes("--purge");
37359
38451
  const homeDir = os25.homedir();
37360
- const claudeDir = path55.join(homeDir, ".claude");
37361
- const settingsPath = path55.join(claudeDir, "settings.json");
37362
- const claudeJsonPath = path55.join(homeDir, ".claude.json");
37363
- const exeOsDir = path55.join(homeDir, ".exe-os");
38452
+ const claudeDir = path57.join(homeDir, ".claude");
38453
+ const settingsPath = path57.join(claudeDir, "settings.json");
38454
+ const claudeJsonPath = path57.join(homeDir, ".claude.json");
38455
+ const exeOsDir = path57.join(homeDir, ".exe-os");
37364
38456
  let removed = 0;
37365
38457
  const log = (msg) => console.log(dryRun ? `[dry-run] ${msg}` : msg);
37366
38458
  let settings = {};
37367
- if (existsSync40(settingsPath)) {
38459
+ if (existsSync42(settingsPath)) {
37368
38460
  try {
37369
- settings = JSON.parse(readFileSync36(settingsPath, "utf8"));
38461
+ settings = JSON.parse(readFileSync38(settingsPath, "utf8"));
37370
38462
  } catch {
37371
38463
  console.error("Your ~/.claude/settings.json appears malformed.");
37372
38464
  if (purge) {
@@ -37404,15 +38496,15 @@ async function runClaudeUninstall(flags = []) {
37404
38496
  permCount = before - settings.permissions.allow.length;
37405
38497
  }
37406
38498
  if (!dryRun) {
37407
- writeFileSync27(settingsPath, JSON.stringify(settings, null, 2) + "\n");
38499
+ writeFileSync28(settingsPath, JSON.stringify(settings, null, 2) + "\n");
37408
38500
  }
37409
38501
  log("\u2713 Removed exe-os hooks from settings.json");
37410
38502
  if (permCount > 0) log(`\u2713 Removed ${permCount} MCP permission entries`);
37411
38503
  removed++;
37412
38504
  }
37413
38505
  }
37414
- if (existsSync40(claudeJsonPath)) {
37415
- const raw = readFileSync36(claudeJsonPath, "utf8");
38506
+ if (existsSync42(claudeJsonPath)) {
38507
+ const raw = readFileSync38(claudeJsonPath, "utf8");
37416
38508
  if (raw.length > 1e6) {
37417
38509
  console.error("claude.json exceeds 1 MB \u2014 skipping parse.");
37418
38510
  } else {
@@ -37433,7 +38525,7 @@ async function runClaudeUninstall(flags = []) {
37433
38525
  }
37434
38526
  if (removedMcp) {
37435
38527
  if (!dryRun) {
37436
- writeFileSync27(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
38528
+ writeFileSync28(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
37437
38529
  }
37438
38530
  log("\u2713 Removed exe-os MCP server from claude.json");
37439
38531
  removed++;
@@ -37441,14 +38533,14 @@ async function runClaudeUninstall(flags = []) {
37441
38533
  }
37442
38534
  }
37443
38535
  }
37444
- const skillsDir = path55.join(claudeDir, "skills");
37445
- if (existsSync40(skillsDir)) {
38536
+ const skillsDir = path57.join(claudeDir, "skills");
38537
+ if (existsSync42(skillsDir)) {
37446
38538
  let skillCount = 0;
37447
38539
  try {
37448
- const entries = readdirSync12(skillsDir);
38540
+ const entries = readdirSync13(skillsDir);
37449
38541
  for (const entry of entries) {
37450
38542
  if (entry.startsWith("exe")) {
37451
- const fullPath = path55.join(skillsDir, entry);
38543
+ const fullPath = path57.join(skillsDir, entry);
37452
38544
  if (!dryRun) rmSync2(fullPath, { recursive: true, force: true });
37453
38545
  skillCount++;
37454
38546
  }
@@ -37460,30 +38552,30 @@ async function runClaudeUninstall(flags = []) {
37460
38552
  removed++;
37461
38553
  }
37462
38554
  }
37463
- const claudeMdPath = path55.join(claudeDir, "CLAUDE.md");
37464
- if (existsSync40(claudeMdPath)) {
37465
- const content = readFileSync36(claudeMdPath, "utf8");
38555
+ const claudeMdPath = path57.join(claudeDir, "CLAUDE.md");
38556
+ if (existsSync42(claudeMdPath)) {
38557
+ const content = readFileSync38(claudeMdPath, "utf8");
37466
38558
  const startMarker = "<!-- exe-os:orchestration-start -->";
37467
38559
  const endMarker = "<!-- exe-os:orchestration-end -->";
37468
38560
  const startIdx = content.indexOf(startMarker);
37469
38561
  const endIdx = content.indexOf(endMarker);
37470
38562
  if (startIdx !== -1 && endIdx !== -1) {
37471
38563
  const cleaned = (content.slice(0, startIdx) + content.slice(endIdx + endMarker.length)).replace(/\n{3,}/g, "\n\n").trim() + "\n";
37472
- if (!dryRun) writeFileSync27(claudeMdPath, cleaned);
38564
+ if (!dryRun) writeFileSync28(claudeMdPath, cleaned);
37473
38565
  log("\u2713 Removed orchestration block from CLAUDE.md");
37474
38566
  removed++;
37475
38567
  }
37476
38568
  }
37477
- const agentsDir = path55.join(claudeDir, "agents");
37478
- if (existsSync40(agentsDir)) {
38569
+ const agentsDir = path57.join(claudeDir, "agents");
38570
+ if (existsSync42(agentsDir)) {
37479
38571
  let agentCount = 0;
37480
38572
  try {
37481
- const entries = readdirSync12(agentsDir).filter((f) => f.endsWith(".md"));
38573
+ const entries = readdirSync13(agentsDir).filter((f) => f.endsWith(".md"));
37482
38574
  let knownNames = /* @__PURE__ */ new Set();
37483
- const rosterPath = path55.join(exeOsDir, "exe-employees.json");
37484
- if (existsSync40(rosterPath)) {
38575
+ const rosterPath = path57.join(exeOsDir, "exe-employees.json");
38576
+ if (existsSync42(rosterPath)) {
37485
38577
  try {
37486
- const roster = JSON.parse(readFileSync36(rosterPath, "utf8"));
38578
+ const roster = JSON.parse(readFileSync38(rosterPath, "utf8"));
37487
38579
  knownNames = new Set(roster.map((e) => e.name));
37488
38580
  } catch {
37489
38581
  }
@@ -37491,7 +38583,7 @@ async function runClaudeUninstall(flags = []) {
37491
38583
  for (const entry of entries) {
37492
38584
  const name = entry.replace(/\.md$/, "");
37493
38585
  if (knownNames.has(name)) {
37494
- if (!dryRun) rmSync2(path55.join(agentsDir, entry), { force: true });
38586
+ if (!dryRun) rmSync2(path57.join(agentsDir, entry), { force: true });
37495
38587
  agentCount++;
37496
38588
  }
37497
38589
  }
@@ -37502,16 +38594,16 @@ async function runClaudeUninstall(flags = []) {
37502
38594
  removed++;
37503
38595
  }
37504
38596
  }
37505
- const projectsDir = path55.join(claudeDir, "projects");
37506
- if (existsSync40(projectsDir)) {
38597
+ const projectsDir = path57.join(claudeDir, "projects");
38598
+ if (existsSync42(projectsDir)) {
37507
38599
  let projectCount = 0;
37508
38600
  try {
37509
- const projects = readdirSync12(projectsDir);
38601
+ const projects = readdirSync13(projectsDir);
37510
38602
  for (const proj of projects) {
37511
- const projSettings = path55.join(projectsDir, proj, "settings.json");
37512
- if (!existsSync40(projSettings)) continue;
38603
+ const projSettings = path57.join(projectsDir, proj, "settings.json");
38604
+ if (!existsSync42(projSettings)) continue;
37513
38605
  try {
37514
- const pSettings = JSON.parse(readFileSync36(projSettings, "utf8"));
38606
+ const pSettings = JSON.parse(readFileSync38(projSettings, "utf8"));
37515
38607
  let changed = false;
37516
38608
  if (Array.isArray(pSettings.permissions?.allow)) {
37517
38609
  const before = pSettings.permissions.allow.length;
@@ -37521,7 +38613,7 @@ async function runClaudeUninstall(flags = []) {
37521
38613
  if (pSettings.permissions.allow.length < before) changed = true;
37522
38614
  }
37523
38615
  if (changed && !dryRun) {
37524
- writeFileSync27(projSettings, JSON.stringify(pSettings, null, 2) + "\n");
38616
+ writeFileSync28(projSettings, JSON.stringify(pSettings, null, 2) + "\n");
37525
38617
  }
37526
38618
  if (changed) projectCount++;
37527
38619
  } catch {
@@ -37535,28 +38627,28 @@ async function runClaudeUninstall(flags = []) {
37535
38627
  }
37536
38628
  }
37537
38629
  try {
37538
- const { execSync: execSync19 } = await import("child_process");
38630
+ const { execSync: execSync20 } = await import("child_process");
37539
38631
  const findExeBin3 = () => {
37540
38632
  try {
37541
- return execSync19(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
38633
+ return execSync20(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
37542
38634
  } catch {
37543
38635
  return null;
37544
38636
  }
37545
38637
  };
37546
38638
  const exeBinPath = findExeBin3();
37547
38639
  if (!exeBinPath) throw new Error("exe-os not found in PATH");
37548
- const binDir = path55.dirname(exeBinPath);
38640
+ const binDir = path57.dirname(exeBinPath);
37549
38641
  let symlinkCount = 0;
37550
- const rosterPath = path55.join(exeOsDir, "exe-employees.json");
37551
- if (existsSync40(rosterPath)) {
37552
- const roster = JSON.parse(readFileSync36(rosterPath, "utf8"));
38642
+ const rosterPath = path57.join(exeOsDir, "exe-employees.json");
38643
+ if (existsSync42(rosterPath)) {
38644
+ const roster = JSON.parse(readFileSync38(rosterPath, "utf8"));
37553
38645
  const { DEFAULT_COORDINATOR_TEMPLATE_NAME: DEFAULT_COORDINATOR_TEMPLATE_NAME2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
37554
38646
  const coordinatorName = roster.find((e) => e.role?.toLowerCase() === "coo")?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME2;
37555
38647
  for (const emp of roster) {
37556
38648
  if (emp.name === coordinatorName) continue;
37557
38649
  for (const suffix of ["", "-opencode"]) {
37558
- const linkPath = path55.join(binDir, `${emp.name}${suffix}`);
37559
- if (existsSync40(linkPath)) {
38650
+ const linkPath = path57.join(binDir, `${emp.name}${suffix}`);
38651
+ if (existsSync42(linkPath)) {
37560
38652
  if (!dryRun) rmSync2(linkPath, { force: true });
37561
38653
  symlinkCount++;
37562
38654
  }
@@ -37569,7 +38661,7 @@ async function runClaudeUninstall(flags = []) {
37569
38661
  }
37570
38662
  } catch {
37571
38663
  }
37572
- if (purge && existsSync40(exeOsDir)) {
38664
+ if (purge && existsSync42(exeOsDir)) {
37573
38665
  if (!dryRun) {
37574
38666
  process.stdout.write("\x1B[33m\u26A0 This will delete all memories, identities, and agent data.\x1B[0m\n");
37575
38667
  process.stdout.write(" Removing ~/.exe-os...\n");
@@ -37594,7 +38686,7 @@ async function checkForUpdateOnBoot() {
37594
38686
  const config = await loadConfig2();
37595
38687
  if (!config.autoUpdate.checkOnBoot) return;
37596
38688
  const { checkForUpdate: checkForUpdate2 } = await Promise.resolve().then(() => (init_update(), update_exports));
37597
- const packageRoot = path55.resolve(
38689
+ const packageRoot = path57.resolve(
37598
38690
  new URL("../..", import.meta.url).pathname
37599
38691
  );
37600
38692
  const result = checkForUpdate2(packageRoot);
@@ -37655,7 +38747,7 @@ async function runActivate(key) {
37655
38747
  const idTemplate = getIdentityTemplate(identityKey);
37656
38748
  if (idTemplate) {
37657
38749
  const idPath = identityPath2(name);
37658
- const dir = path55.dirname(idPath);
38750
+ const dir = path57.dirname(idPath);
37659
38751
  if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
37660
38752
  fs8.writeFileSync(idPath, idTemplate.replace(/^agent_id: \w+/m, `agent_id: ${name}`), "utf-8");
37661
38753
  }