@askexenow/exe-os 0.9.16 → 0.9.18

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 (97) hide show
  1. package/dist/bin/backfill-conversations.js +1242 -909
  2. package/dist/bin/backfill-responses.js +1245 -912
  3. package/dist/bin/backfill-vectors.js +1244 -906
  4. package/dist/bin/cleanup-stale-review-tasks.js +1870 -417
  5. package/dist/bin/cli.js +217 -107
  6. package/dist/bin/exe-agent-config.js +2 -2
  7. package/dist/bin/exe-agent.js +62 -0
  8. package/dist/bin/exe-assign.js +346 -10
  9. package/dist/bin/exe-boot.js +387 -32
  10. package/dist/bin/exe-call.js +72 -2
  11. package/dist/bin/exe-cloud.js +8 -0
  12. package/dist/bin/exe-dispatch.js +1821 -225
  13. package/dist/bin/exe-doctor.js +720 -52
  14. package/dist/bin/exe-export-behaviors.js +1429 -148
  15. package/dist/bin/exe-forget.js +1408 -34
  16. package/dist/bin/exe-gateway.js +1629 -1295
  17. package/dist/bin/exe-heartbeat.js +1899 -448
  18. package/dist/bin/exe-kill.js +1624 -346
  19. package/dist/bin/exe-launch-agent.js +726 -90
  20. package/dist/bin/exe-link.js +27 -8
  21. package/dist/bin/exe-new-employee.js +75 -9
  22. package/dist/bin/exe-pending-messages.js +2769 -1316
  23. package/dist/bin/exe-pending-notifications.js +2829 -1376
  24. package/dist/bin/exe-pending-reviews.js +2847 -1392
  25. package/dist/bin/exe-rename.js +89 -8
  26. package/dist/bin/exe-review.js +1494 -312
  27. package/dist/bin/exe-search.js +1608 -1300
  28. package/dist/bin/exe-session-cleanup.js +194 -91
  29. package/dist/bin/exe-settings.js +10 -2
  30. package/dist/bin/exe-start-codex.js +769 -120
  31. package/dist/bin/exe-start-opencode.js +763 -108
  32. package/dist/bin/exe-status.js +1887 -434
  33. package/dist/bin/exe-team.js +1782 -324
  34. package/dist/bin/git-sweep.js +408 -33
  35. package/dist/bin/graph-backfill.js +681 -27
  36. package/dist/bin/graph-export.js +1419 -141
  37. package/dist/bin/install.js +4 -8
  38. package/dist/bin/intercom-check.js +8641 -0
  39. package/dist/bin/scan-tasks.js +553 -38
  40. package/dist/bin/setup.js +82 -10
  41. package/dist/bin/shard-migrate.js +682 -28
  42. package/dist/gateway/index.js +1629 -1295
  43. package/dist/hooks/bug-report-worker.js +1136 -183
  44. package/dist/hooks/codex-stop-task-finalizer.js +1060 -107
  45. package/dist/hooks/commit-complete.js +408 -33
  46. package/dist/hooks/error-recall.js +1608 -1300
  47. package/dist/hooks/ingest-worker.js +250 -7966
  48. package/dist/hooks/ingest.js +707 -119
  49. package/dist/hooks/instructions-loaded.js +383 -20
  50. package/dist/hooks/notification.js +383 -20
  51. package/dist/hooks/post-compact.js +384 -21
  52. package/dist/hooks/{response-ingest-worker.js → post-tool-combined.js} +4157 -1716
  53. package/dist/hooks/pre-compact.js +486 -45
  54. package/dist/hooks/pre-tool-use.js +385 -22
  55. package/dist/hooks/prompt-submit.js +291 -96
  56. package/dist/hooks/session-end.js +490 -48
  57. package/dist/hooks/session-start.js +236 -22
  58. package/dist/hooks/stop.js +192 -50
  59. package/dist/hooks/subagent-stop.js +95 -18
  60. package/dist/hooks/summary-worker.js +205 -361
  61. package/dist/index.js +221 -105
  62. package/dist/lib/agent-config.js +2 -2
  63. package/dist/lib/cloud-sync.js +27 -8
  64. package/dist/lib/consolidation.js +437 -41
  65. package/dist/lib/database.js +20 -8
  66. package/dist/lib/db-daemon-client.js +2 -2
  67. package/dist/lib/db.js +20 -8
  68. package/dist/lib/device-registry.js +27 -8
  69. package/dist/lib/employee-templates.js +62 -0
  70. package/dist/lib/employees.js +2 -2
  71. package/dist/lib/exe-daemon.js +6703 -6259
  72. package/dist/lib/hybrid-search.js +1608 -1300
  73. package/dist/lib/identity.js +1 -1
  74. package/dist/lib/messaging.js +11 -3
  75. package/dist/lib/reminders.js +1 -1
  76. package/dist/lib/schedules.js +718 -26
  77. package/dist/lib/session-registry.js +11 -0
  78. package/dist/lib/skill-learning.js +639 -9
  79. package/dist/lib/store.js +676 -27
  80. package/dist/lib/tasks.js +665 -27
  81. package/dist/lib/tmux-routing.js +732 -94
  82. package/dist/lib/token-spend.js +1 -1
  83. package/dist/mcp/server.js +856 -383
  84. package/dist/mcp/tools/complete-reminder.js +1 -1
  85. package/dist/mcp/tools/create-reminder.js +1 -1
  86. package/dist/mcp/tools/create-task.js +616 -46
  87. package/dist/mcp/tools/deactivate-behavior.js +9 -1
  88. package/dist/mcp/tools/list-reminders.js +1 -1
  89. package/dist/mcp/tools/list-tasks.js +10 -2
  90. package/dist/mcp/tools/send-message.js +11 -3
  91. package/dist/mcp/tools/update-task.js +677 -39
  92. package/dist/runtime/index.js +425 -37
  93. package/dist/tui/App.js +365 -34
  94. package/package.json +5 -2
  95. package/src/commands/exe/intercom.md +6 -17
  96. package/dist/bin/wiki-sync.js +0 -2991
  97. package/dist/hooks/prompt-ingest-worker.js +0 -3979
package/dist/bin/cli.js CHANGED
@@ -403,7 +403,7 @@ var init_agent_config = __esm({
403
403
  init_secure_files();
404
404
  AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
405
405
  KNOWN_RUNTIMES = {
406
- claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
406
+ claude: ["claude-opus-4.6", "claude-opus-4", "claude-sonnet-4.6", "claude-sonnet-4", "claude-haiku-4.5"],
407
407
  codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
408
408
  opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
409
409
  };
@@ -413,7 +413,7 @@ var init_agent_config = __esm({
413
413
  opencode: "OpenCode (open source)"
414
414
  };
415
415
  DEFAULT_MODELS = {
416
- claude: "claude-opus-4",
416
+ claude: "claude-opus-4.6",
417
417
  codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
418
418
  opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
419
419
  };
@@ -981,15 +981,11 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
981
981
  hooks: [
982
982
  {
983
983
  type: "command",
984
- command: `node "${path6.join(packageRoot, "dist", "hooks", "ingest.js")}"${logSuffix}`
985
- },
986
- {
987
- type: "command",
988
- command: `node "${path6.join(packageRoot, "dist", "hooks", "error-recall.js")}"${logSuffix}`
984
+ command: `node "${path6.join(packageRoot, "dist", "hooks", "post-tool-combined.js")}"${logSuffix}`
989
985
  }
990
986
  ]
991
987
  },
992
- marker: "dist/hooks/ingest.js"
988
+ marker: "dist/hooks/post-tool-combined.js"
993
989
  },
994
990
  {
995
991
  event: "SessionStart",
@@ -1817,9 +1813,9 @@ var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
1817
1813
  var init_db_retry = __esm({
1818
1814
  "src/lib/db-retry.ts"() {
1819
1815
  "use strict";
1820
- MAX_RETRIES = 3;
1821
- BASE_DELAY_MS = 200;
1822
- MAX_JITTER_MS = 300;
1816
+ MAX_RETRIES = 5;
1817
+ BASE_DELAY_MS = 250;
1818
+ MAX_JITTER_MS = 400;
1823
1819
  }
1824
1820
  });
1825
1821
 
@@ -2407,6 +2403,15 @@ var init_database_adapter = __esm({
2407
2403
  }
2408
2404
  });
2409
2405
 
2406
+ // src/types/memory.ts
2407
+ var EMBEDDING_DIM;
2408
+ var init_memory = __esm({
2409
+ "src/types/memory.ts"() {
2410
+ "use strict";
2411
+ EMBEDDING_DIM = 1024;
2412
+ }
2413
+ });
2414
+
2410
2415
  // src/lib/daemon-auth.ts
2411
2416
  import crypto2 from "crypto";
2412
2417
  import path9 from "path";
@@ -2978,7 +2983,7 @@ function createDaemonDbClient(fallbackClient) {
2978
2983
  });
2979
2984
  if (response.error) {
2980
2985
  const errMsg = String(response.error);
2981
- if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
2986
+ if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed" || errMsg === "DB not initialized") {
2982
2987
  process.stderr.write(`[db-daemon] Transport error (${errMsg}), falling back to direct
2983
2988
  `);
2984
2989
  return fallbackClient.execute(stmt);
@@ -3003,7 +3008,7 @@ function createDaemonDbClient(fallbackClient) {
3003
3008
  });
3004
3009
  if (response.error) {
3005
3010
  const errMsg = String(response.error);
3006
- if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
3011
+ if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed" || errMsg === "DB not initialized") {
3007
3012
  process.stderr.write(`[db-daemon] Batch transport error (${errMsg}), falling back to direct
3008
3013
  `);
3009
3014
  return fallbackClient.batch(stmts, mode);
@@ -3126,7 +3131,7 @@ async function initDatabase(config) {
3126
3131
  });
3127
3132
  }, 3e4);
3128
3133
  _walCheckpointTimer.unref();
3129
- if (process.env.DATABASE_URL) {
3134
+ if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
3130
3135
  _adapterClient = await createPrismaDbAdapter(_resilientClient);
3131
3136
  }
3132
3137
  }
@@ -3137,7 +3142,7 @@ function getClient() {
3137
3142
  if (!_adapterClient) {
3138
3143
  throw new Error("Database client not initialized. Call initDatabase() first.");
3139
3144
  }
3140
- if (process.env.DATABASE_URL) {
3145
+ if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
3141
3146
  return _adapterClient;
3142
3147
  }
3143
3148
  if (process.env.EXE_IS_DAEMON === "1") {
@@ -3149,9 +3154,11 @@ function getClient() {
3149
3154
  return _resilientClient;
3150
3155
  }
3151
3156
  async function initDaemonClient() {
3152
- if (process.env.DATABASE_URL) return;
3157
+ if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") return;
3153
3158
  if (process.env.EXE_IS_DAEMON === "1") return;
3159
+ if (process.env.VITEST) return;
3154
3160
  if (!_resilientClient) return;
3161
+ if (_daemonClient) return;
3155
3162
  try {
3156
3163
  const { initDaemonDbClient: initDaemonDbClient2 } = await Promise.resolve().then(() => (init_db_daemon_client(), db_daemon_client_exports));
3157
3164
  _daemonClient = await initDaemonDbClient2(_resilientClient);
@@ -3300,6 +3307,13 @@ async function ensureSchema() {
3300
3307
  });
3301
3308
  } catch {
3302
3309
  }
3310
+ try {
3311
+ await client.execute({
3312
+ sql: `ALTER TABLE behaviors ADD COLUMN vector F32_BLOB(${EMBEDDING_DIM})`,
3313
+ args: []
3314
+ });
3315
+ } catch {
3316
+ }
3303
3317
  try {
3304
3318
  await client.execute({
3305
3319
  sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
@@ -4170,6 +4184,7 @@ var init_database = __esm({
4170
4184
  init_db_retry();
4171
4185
  init_employees();
4172
4186
  init_database_adapter();
4187
+ init_memory();
4173
4188
  _client = null;
4174
4189
  _resilientClient = null;
4175
4190
  _walCheckpointTimer = null;
@@ -6363,15 +6378,6 @@ var init_exe_cloud = __esm({
6363
6378
  }
6364
6379
  });
6365
6380
 
6366
- // src/types/memory.ts
6367
- var EMBEDDING_DIM;
6368
- var init_memory = __esm({
6369
- "src/types/memory.ts"() {
6370
- "use strict";
6371
- EMBEDDING_DIM = 1024;
6372
- }
6373
- });
6374
-
6375
6381
  // src/lib/state-bus.ts
6376
6382
  var StateBus, orgBus;
6377
6383
  var init_state_bus = __esm({
@@ -6857,6 +6863,68 @@ var init_platform_procedures = __esm({
6857
6863
  domain: "architecture",
6858
6864
  priority: "p0",
6859
6865
  content: "Tasks live in the DB. Intercom (tmux send-keys) is fire-and-forget \u2014 it may fail, get garbled, or arrive mid-work. Never rely on intercom for task delivery. The UserPromptSubmit hook checks the DB for new tasks on every prompt. Your operating procedures step 7 says check for next work. The daemon nudges idle agents as a speedup. If you have no tasks, you found them all."
6866
+ },
6867
+ // --- MCP is the ONLY data interface ---
6868
+ {
6869
+ title: "MCP disconnect \u2014 ask the user, never work around it",
6870
+ domain: "workflow",
6871
+ priority: "p0",
6872
+ content: "If MCP tools are unavailable, disconnected, or returning connection errors: STOP. Tell the user clearly: 'MCP server is disconnected. Please run /mcp to reconnect.' Do NOT attempt workarounds \u2014 no raw Node imports, no direct DB access, no CLI hacks, no daemon socket calls. MCP is the ONLY data interface. Working around it wastes time, hits bundling issues, and bypasses the contract boundary. Ask once, wait, proceed when reconnected."
6873
+ },
6874
+ // --- MCP Tool Catalog (Layer 0 — every agent knows what tools exist) ---
6875
+ {
6876
+ title: "MCP tools \u2014 memory and search",
6877
+ domain: "tool-use",
6878
+ priority: "p1",
6879
+ content: "recall_my_memory: search your own memories (semantic + FTS). ask_team_memory: search a colleague's memories by agent name. store_memory: persist a memory (decisions, summaries, context). commit_memory: high-importance memory that survives consolidation. search_everything: unified search across memories, tasks, entities, conversations. get_session_context: temporal window of memories around a timestamp. consolidate_memories: merge duplicate/related memories into insights. get_memory_cardinality: count memories per agent (health check)."
6880
+ },
6881
+ {
6882
+ title: "MCP tools \u2014 task orchestration",
6883
+ domain: "tool-use",
6884
+ priority: "p1",
6885
+ content: "create_task: dispatch work to an employee (auto-spawns session). The ONLY dispatch path. list_tasks: query tasks by status, assignee, project. get_task: fetch full task details by ID. update_task: change status (in_progress, done, blocked, cancelled) + add result summary. close_task: finalize a reviewed task (COO only). checkpoint_task: save progress state for crash recovery. resume_employee: re-spawn an employee session for an existing task."
6886
+ },
6887
+ {
6888
+ title: "MCP tools \u2014 knowledge graph (GraphRAG)",
6889
+ domain: "tool-use",
6890
+ priority: "p1",
6891
+ content: "query_relationships: find connections between entities in the knowledge graph. get_entity_neighbors: explore an entity's direct connections. get_hot_entities: find most-referenced entities (trending topics). get_graph_stats: graph health \u2014 entity/relationship counts, density. export_graph: export graph data for visualization. merge_entities: deduplicate entities (alias resolution). find_similar_trajectories: match tool-call patterns to past task solutions."
6892
+ },
6893
+ {
6894
+ title: "MCP tools \u2014 identity, behavior, and decisions",
6895
+ domain: "tool-use",
6896
+ priority: "p1",
6897
+ content: "get_identity: read an agent's exe.md (Layer 1 identity). update_identity: write an agent's exe.md. Identity > behavior \u2014 use for permanent rules. store_behavior: record a correction or pattern for an agent (Layer 2 expertise). list_behaviors: view an agent's active behaviors. deactivate_behavior: soft-delete a stale or conflicting behavior. store_decision: record an ADR (architectural decision record). get_decision: retrieve a past decision by query."
6898
+ },
6899
+ {
6900
+ title: "MCP tools \u2014 communication and messaging",
6901
+ domain: "tool-use",
6902
+ priority: "p1",
6903
+ content: "send_message: send supplementary context to another agent (NOT for actionable work \u2014 use create_task). acknowledge_messages: mark messages as read. send_whatsapp: send WhatsApp message via gateway (customer-facing alerts). query_conversations: search ingested conversations across all channels (WhatsApp, email, etc.)."
6904
+ },
6905
+ {
6906
+ title: "MCP tools \u2014 wiki, documents, and content",
6907
+ domain: "tool-use",
6908
+ priority: "p1",
6909
+ content: "create_wiki_page: create a wiki page in exe-wiki. list_wiki_pages: browse wiki pages. get_wiki_page: read a wiki page. update_wiki_page: edit a wiki page. ingest_document: import a file (PDF, MD, etc.) into memory as chunks. list_documents: browse ingested documents by workspace. purge_document: remove a document and its memory chunks. set_document_importance: adjust chunk importance scores. rerank_documents: re-score document relevance for a query."
6910
+ },
6911
+ {
6912
+ title: "MCP tools \u2014 system, operations, and admin",
6913
+ domain: "tool-use",
6914
+ priority: "p1",
6915
+ content: "get_agent_spend: token usage per agent/session (cost tracking). list_agent_sessions: view agent session history. get_session_kills: audit log of killed sessions. get_daemon_health: check exed daemon status. get_auto_wake_status: daemon auto-wake configuration. get_worker_gate: check worker deployment gates. run_memory_audit: health check \u2014 duplicates, null vectors, orphaned rows. run_consolidation: trigger sleep-time memory consolidation. cloud_sync: force a cloud sync cycle. backup_vps: trigger VPS backup."
6916
+ },
6917
+ {
6918
+ title: "MCP tools \u2014 config, licensing, and team",
6919
+ domain: "tool-use",
6920
+ priority: "p1",
6921
+ content: "set_agent_config: view/change per-agent runtime and model settings. list_employees: view the employee roster. add_person: add a person to the CRM contacts roster. list_people: browse CRM contacts. get_person: fetch contact details. get_license_status: check license validity. create_license: generate a new license key (admin). list_licenses: view all issued licenses. activate_license: activate a license on a device."
6922
+ },
6923
+ {
6924
+ title: "MCP tools \u2014 advanced (triggers, skills, orchestration)",
6925
+ domain: "tool-use",
6926
+ priority: "p1",
6927
+ content: "create_trigger: set up a scheduled recurring agent job (cron). list_triggers: view active triggers. load_skill: load a slash-command skill dynamically. apply_starter_pack: import a pre-built behavior + identity pack for a role. export_orchestration: export full org state (tasks, behaviors, identities) as portable JSON. import_orchestration: import org state into a new instance. deploy_client: deploy a customer client instance. query_company_brain: unified RAG query across all company knowledge. create_reminder: set a text reminder (shown in boot brief). list_reminders: view pending reminders. complete_reminder: mark a reminder done. global_procedure: manage Layer 0 procedures (actions: store, list, deactivate). Legacy aliases: store_global_procedure, list_global_procedures, deactivate_global_procedure."
6860
6928
  }
6861
6929
  ];
6862
6930
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -7006,6 +7074,11 @@ async function initStore(options) {
7006
7074
  encryptionKey: hexKey
7007
7075
  });
7008
7076
  await retryOnBusy2(() => ensureSchema(), "ensureSchema");
7077
+ try {
7078
+ const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
7079
+ await initDaemonClient2();
7080
+ } catch {
7081
+ }
7009
7082
  if (!options?.lightweight) {
7010
7083
  try {
7011
7084
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
@@ -9105,6 +9178,7 @@ var session_registry_exports = {};
9105
9178
  __export(session_registry_exports, {
9106
9179
  listSessions: () => listSessions,
9107
9180
  pruneStaleSessions: () => pruneStaleSessions,
9181
+ refreshSessionProject: () => refreshSessionProject,
9108
9182
  registerSession: () => registerSession
9109
9183
  });
9110
9184
  import { readFileSync as readFileSync14, writeFileSync as writeFileSync12, mkdirSync as mkdirSync11, existsSync as existsSync17 } from "fs";
@@ -9125,6 +9199,16 @@ function registerSession(entry) {
9125
9199
  }
9126
9200
  writeFileSync12(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
9127
9201
  }
9202
+ function refreshSessionProject(windowName, projectDir) {
9203
+ const sessions = listSessions();
9204
+ const entry = sessions.find((s) => s.windowName === windowName);
9205
+ if (!entry || entry.projectDir === projectDir) return;
9206
+ entry.projectDir = projectDir;
9207
+ try {
9208
+ writeFileSync12(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
9209
+ } catch {
9210
+ }
9211
+ }
9128
9212
  function listSessions() {
9129
9213
  try {
9130
9214
  const raw = readFileSync14(REGISTRY_PATH, "utf8");
@@ -9988,15 +10072,20 @@ async function createTaskCore(input) {
9988
10072
  const { resolveExeSession: resolveExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
9989
10073
  const resolved = resolveExeSession2();
9990
10074
  if (resolved && input.projectName) {
9991
- const { getSessionProject: getSessionProject2 } = await Promise.resolve().then(() => (init_session_scope(), session_scope_exports));
9992
- const sessionProject = getSessionProject2(resolved);
9993
- if (sessionProject && sessionProject !== input.projectName) {
9994
- scopeMismatchWarning = `session/project mismatch: session "${resolved}" owns "${sessionProject}" but task targets "${input.projectName}". Routed to default scope.`;
9995
- process.stderr.write(`[create_task] ${scopeMismatchWarning}
9996
- `);
9997
- earlySessionScope = null;
9998
- } else {
10075
+ const isCoordinatorSession = !resolved.includes("-");
10076
+ if (isCoordinatorSession) {
9999
10077
  earlySessionScope = resolved;
10078
+ } else {
10079
+ const { getSessionProject: getSessionProject2 } = await Promise.resolve().then(() => (init_session_scope(), session_scope_exports));
10080
+ const sessionProject = getSessionProject2(resolved);
10081
+ if (sessionProject && sessionProject !== input.projectName) {
10082
+ scopeMismatchWarning = `session/project mismatch: session "${resolved}" owns "${sessionProject}" but task targets "${input.projectName}". Routed to default scope.`;
10083
+ process.stderr.write(`[create_task] ${scopeMismatchWarning}
10084
+ `);
10085
+ earlySessionScope = null;
10086
+ } else {
10087
+ earlySessionScope = resolved;
10088
+ }
10000
10089
  }
10001
10090
  } else {
10002
10091
  earlySessionScope = resolved;
@@ -10881,6 +10970,10 @@ async function dispatchTaskToEmployee(input) {
10881
10970
  if (transport.isAlive(sessionName)) {
10882
10971
  const result = sendIntercom(sessionName);
10883
10972
  const dispatched = result === "acknowledged" || result === "debounced" || result === "queued" ? "verified" : result === "delivered" ? "sent_unverified" : "session_dead";
10973
+ process.stderr.write(
10974
+ `[dispatch-audit] intercom \u2192 ${sessionName} | task="${input.title}" [${input.priority}] | result=${dispatched} (sendIntercom=${result})
10975
+ `
10976
+ );
10884
10977
  return { dispatched, session: sessionName, crossProject };
10885
10978
  } else {
10886
10979
  const projectDir = input.projectDir ?? process.cwd();
@@ -10889,11 +10982,15 @@ async function dispatchTaskToEmployee(input) {
10889
10982
  });
10890
10983
  if (result.status === "failed") {
10891
10984
  process.stderr.write(
10892
- `[dispatch] Failed to spawn ${input.assignedTo}: ${result.error}
10985
+ `[dispatch-audit] SPAWN FAILED \u2192 ${input.assignedTo} | task="${input.title}" [${input.priority}] | error=${result.error}
10893
10986
  `
10894
10987
  );
10895
10988
  return { dispatched: "session_missing" };
10896
10989
  }
10990
+ process.stderr.write(
10991
+ `[dispatch-audit] SPAWNED \u2192 ${result.sessionName} | task="${input.title}" [${input.priority}]
10992
+ `
10993
+ );
10897
10994
  return { dispatched: "spawned", session: result.sessionName, crossProject };
10898
10995
  }
10899
10996
  } catch {
@@ -10903,7 +11000,13 @@ async function dispatchTaskToEmployee(input) {
10903
11000
  function notifyTaskDone() {
10904
11001
  try {
10905
11002
  const key = getSessionKey();
10906
- if (key && !process.env.VITEST) notifyParentExe(key);
11003
+ if (key && !process.env.VITEST) {
11004
+ notifyParentExe(key);
11005
+ process.stderr.write(
11006
+ `[dispatch-audit] notifyTaskDone \u2192 parent coordinator (session=${key})
11007
+ `
11008
+ );
11009
+ }
10907
11010
  } catch {
10908
11011
  }
10909
11012
  }
@@ -10924,16 +11027,91 @@ var init_tasks_notify = __esm({
10924
11027
  }
10925
11028
  });
10926
11029
 
11030
+ // src/lib/embedder.ts
11031
+ var embedder_exports = {};
11032
+ __export(embedder_exports, {
11033
+ disposeEmbedder: () => disposeEmbedder,
11034
+ embed: () => embed,
11035
+ embedDirect: () => embedDirect,
11036
+ getEmbedder: () => getEmbedder
11037
+ });
11038
+ async function getEmbedder() {
11039
+ const ok = await connectEmbedDaemon();
11040
+ if (!ok) {
11041
+ throw new Error(
11042
+ "Could not connect to embedding daemon. Ensure the model is installed (run /exe-setup)."
11043
+ );
11044
+ }
11045
+ }
11046
+ async function embed(text) {
11047
+ const priority = process.env.EXE_EMBED_PRIORITY === "low" ? "low" : "high";
11048
+ const vector = await embedViaClient(text, priority);
11049
+ if (!vector) {
11050
+ throw new Error(
11051
+ "Embedding failed: daemon unavailable. Run /exe-setup to verify model installation."
11052
+ );
11053
+ }
11054
+ if (vector.length !== EMBEDDING_DIM) {
11055
+ throw new Error(
11056
+ `Embedding dimension mismatch: expected ${EMBEDDING_DIM}, got ${vector.length}. Ensure the correct Jina v5-small Q4_K_M GGUF model is installed.`
11057
+ );
11058
+ }
11059
+ return vector;
11060
+ }
11061
+ async function disposeEmbedder() {
11062
+ disconnectClient();
11063
+ }
11064
+ async function embedDirect(text) {
11065
+ const llamaCpp = await import("node-llama-cpp");
11066
+ const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
11067
+ const { existsSync: existsSync32 } = await import("fs");
11068
+ const path46 = await import("path");
11069
+ const modelPath = path46.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
11070
+ if (!existsSync32(modelPath)) {
11071
+ throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
11072
+ }
11073
+ const llama = await llamaCpp.getLlama();
11074
+ const model = await llama.loadModel({ modelPath });
11075
+ const context = await model.createEmbeddingContext();
11076
+ try {
11077
+ const embedding = await context.getEmbeddingFor(text);
11078
+ const vector = Array.from(embedding.vector);
11079
+ if (vector.length !== EMBEDDING_DIM) {
11080
+ throw new Error(
11081
+ `Embedding dimension mismatch: expected ${EMBEDDING_DIM}, got ${vector.length}.`
11082
+ );
11083
+ }
11084
+ return vector;
11085
+ } finally {
11086
+ await context.dispose();
11087
+ await model.dispose();
11088
+ }
11089
+ }
11090
+ var init_embedder = __esm({
11091
+ "src/lib/embedder.ts"() {
11092
+ "use strict";
11093
+ init_memory();
11094
+ init_exe_daemon_client();
11095
+ }
11096
+ });
11097
+
10927
11098
  // src/lib/behaviors.ts
10928
11099
  import crypto9 from "crypto";
10929
11100
  async function storeBehavior(opts) {
10930
11101
  const client = getClient();
10931
11102
  const id = crypto9.randomUUID();
10932
11103
  const now = (/* @__PURE__ */ new Date()).toISOString();
11104
+ let vector = null;
11105
+ try {
11106
+ const { embed: embed2 } = await Promise.resolve().then(() => (init_embedder(), embedder_exports));
11107
+ const vec = await embed2(opts.content);
11108
+ vector = new Float32Array(vec);
11109
+ } catch {
11110
+ }
10933
11111
  await client.execute({
10934
- sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, priority, content, active, created_at, updated_at)
10935
- VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?)`,
10936
- args: [id, opts.agentId, opts.projectName ?? null, opts.domain ?? null, opts.priority ?? "p1", opts.content, now, now]
11112
+ sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, priority, content, active, created_at, updated_at, vector)
11113
+ VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?)`,
11114
+ args: [id, opts.agentId, opts.projectName ?? null, opts.domain ?? null, opts.priority ?? "p1", opts.content, now, now, vector ? vector.buffer : null]
10937
11115
  });
10938
11116
  return id;
10939
11117
  }
@@ -12036,7 +12214,7 @@ function isSessionBusy(sessionName) {
12036
12214
  function isExeSession(sessionName) {
12037
12215
  const matchesBaseWithInstance = (baseName) => sessionName === baseName || sessionName.startsWith(baseName) && /^\d+$/.test(sessionName.slice(baseName.length));
12038
12216
  const coordinatorName = getCoordinatorName();
12039
- return matchesBaseWithInstance(coordinatorName) || matchesBaseWithInstance("exe");
12217
+ return matchesBaseWithInstance(coordinatorName);
12040
12218
  }
12041
12219
  function sendIntercom(targetSession) {
12042
12220
  const transport = getTransport();
@@ -13898,74 +14076,6 @@ var init_model_downloader = __esm({
13898
14076
  }
13899
14077
  });
13900
14078
 
13901
- // src/lib/embedder.ts
13902
- var embedder_exports = {};
13903
- __export(embedder_exports, {
13904
- disposeEmbedder: () => disposeEmbedder,
13905
- embed: () => embed,
13906
- embedDirect: () => embedDirect,
13907
- getEmbedder: () => getEmbedder
13908
- });
13909
- async function getEmbedder() {
13910
- const ok = await connectEmbedDaemon();
13911
- if (!ok) {
13912
- throw new Error(
13913
- "Could not connect to embedding daemon. Ensure the model is installed (run /exe-setup)."
13914
- );
13915
- }
13916
- }
13917
- async function embed(text) {
13918
- const priority = process.env.EXE_EMBED_PRIORITY === "low" ? "low" : "high";
13919
- const vector = await embedViaClient(text, priority);
13920
- if (!vector) {
13921
- throw new Error(
13922
- "Embedding failed: daemon unavailable. Run /exe-setup to verify model installation."
13923
- );
13924
- }
13925
- if (vector.length !== EMBEDDING_DIM) {
13926
- throw new Error(
13927
- `Embedding dimension mismatch: expected ${EMBEDDING_DIM}, got ${vector.length}. Ensure the correct Jina v5-small Q4_K_M GGUF model is installed.`
13928
- );
13929
- }
13930
- return vector;
13931
- }
13932
- async function disposeEmbedder() {
13933
- disconnectClient();
13934
- }
13935
- async function embedDirect(text) {
13936
- const llamaCpp = await import("node-llama-cpp");
13937
- const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
13938
- const { existsSync: existsSync32 } = await import("fs");
13939
- const path46 = await import("path");
13940
- const modelPath = path46.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
13941
- if (!existsSync32(modelPath)) {
13942
- throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
13943
- }
13944
- const llama = await llamaCpp.getLlama();
13945
- const model = await llama.loadModel({ modelPath });
13946
- const context = await model.createEmbeddingContext();
13947
- try {
13948
- const embedding = await context.getEmbeddingFor(text);
13949
- const vector = Array.from(embedding.vector);
13950
- if (vector.length !== EMBEDDING_DIM) {
13951
- throw new Error(
13952
- `Embedding dimension mismatch: expected ${EMBEDDING_DIM}, got ${vector.length}.`
13953
- );
13954
- }
13955
- return vector;
13956
- } finally {
13957
- await context.dispose();
13958
- await model.dispose();
13959
- }
13960
- }
13961
- var init_embedder = __esm({
13962
- "src/lib/embedder.ts"() {
13963
- "use strict";
13964
- init_memory();
13965
- init_exe_daemon_client();
13966
- }
13967
- });
13968
-
13969
14079
  // src/lib/identity-templates.ts
13970
14080
  var identity_templates_exports = {};
13971
14081
  __export(identity_templates_exports, {
@@ -208,12 +208,12 @@ var init_agent_config = __esm({
208
208
  init_secure_files();
209
209
  AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
210
210
  KNOWN_RUNTIMES = {
211
- claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
211
+ claude: ["claude-opus-4.6", "claude-opus-4", "claude-sonnet-4.6", "claude-sonnet-4", "claude-haiku-4.5"],
212
212
  codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
213
213
  opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
214
214
  };
215
215
  DEFAULT_MODELS = {
216
- claude: "claude-opus-4",
216
+ claude: "claude-opus-4.6",
217
217
  codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
218
218
  opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
219
219
  };
@@ -1395,6 +1395,68 @@ var PLATFORM_PROCEDURES = [
1395
1395
  domain: "architecture",
1396
1396
  priority: "p0",
1397
1397
  content: "Tasks live in the DB. Intercom (tmux send-keys) is fire-and-forget \u2014 it may fail, get garbled, or arrive mid-work. Never rely on intercom for task delivery. The UserPromptSubmit hook checks the DB for new tasks on every prompt. Your operating procedures step 7 says check for next work. The daemon nudges idle agents as a speedup. If you have no tasks, you found them all."
1398
+ },
1399
+ // --- MCP is the ONLY data interface ---
1400
+ {
1401
+ title: "MCP disconnect \u2014 ask the user, never work around it",
1402
+ domain: "workflow",
1403
+ priority: "p0",
1404
+ content: "If MCP tools are unavailable, disconnected, or returning connection errors: STOP. Tell the user clearly: 'MCP server is disconnected. Please run /mcp to reconnect.' Do NOT attempt workarounds \u2014 no raw Node imports, no direct DB access, no CLI hacks, no daemon socket calls. MCP is the ONLY data interface. Working around it wastes time, hits bundling issues, and bypasses the contract boundary. Ask once, wait, proceed when reconnected."
1405
+ },
1406
+ // --- MCP Tool Catalog (Layer 0 — every agent knows what tools exist) ---
1407
+ {
1408
+ title: "MCP tools \u2014 memory and search",
1409
+ domain: "tool-use",
1410
+ priority: "p1",
1411
+ content: "recall_my_memory: search your own memories (semantic + FTS). ask_team_memory: search a colleague's memories by agent name. store_memory: persist a memory (decisions, summaries, context). commit_memory: high-importance memory that survives consolidation. search_everything: unified search across memories, tasks, entities, conversations. get_session_context: temporal window of memories around a timestamp. consolidate_memories: merge duplicate/related memories into insights. get_memory_cardinality: count memories per agent (health check)."
1412
+ },
1413
+ {
1414
+ title: "MCP tools \u2014 task orchestration",
1415
+ domain: "tool-use",
1416
+ priority: "p1",
1417
+ content: "create_task: dispatch work to an employee (auto-spawns session). The ONLY dispatch path. list_tasks: query tasks by status, assignee, project. get_task: fetch full task details by ID. update_task: change status (in_progress, done, blocked, cancelled) + add result summary. close_task: finalize a reviewed task (COO only). checkpoint_task: save progress state for crash recovery. resume_employee: re-spawn an employee session for an existing task."
1418
+ },
1419
+ {
1420
+ title: "MCP tools \u2014 knowledge graph (GraphRAG)",
1421
+ domain: "tool-use",
1422
+ priority: "p1",
1423
+ content: "query_relationships: find connections between entities in the knowledge graph. get_entity_neighbors: explore an entity's direct connections. get_hot_entities: find most-referenced entities (trending topics). get_graph_stats: graph health \u2014 entity/relationship counts, density. export_graph: export graph data for visualization. merge_entities: deduplicate entities (alias resolution). find_similar_trajectories: match tool-call patterns to past task solutions."
1424
+ },
1425
+ {
1426
+ title: "MCP tools \u2014 identity, behavior, and decisions",
1427
+ domain: "tool-use",
1428
+ priority: "p1",
1429
+ content: "get_identity: read an agent's exe.md (Layer 1 identity). update_identity: write an agent's exe.md. Identity > behavior \u2014 use for permanent rules. store_behavior: record a correction or pattern for an agent (Layer 2 expertise). list_behaviors: view an agent's active behaviors. deactivate_behavior: soft-delete a stale or conflicting behavior. store_decision: record an ADR (architectural decision record). get_decision: retrieve a past decision by query."
1430
+ },
1431
+ {
1432
+ title: "MCP tools \u2014 communication and messaging",
1433
+ domain: "tool-use",
1434
+ priority: "p1",
1435
+ content: "send_message: send supplementary context to another agent (NOT for actionable work \u2014 use create_task). acknowledge_messages: mark messages as read. send_whatsapp: send WhatsApp message via gateway (customer-facing alerts). query_conversations: search ingested conversations across all channels (WhatsApp, email, etc.)."
1436
+ },
1437
+ {
1438
+ title: "MCP tools \u2014 wiki, documents, and content",
1439
+ domain: "tool-use",
1440
+ priority: "p1",
1441
+ content: "create_wiki_page: create a wiki page in exe-wiki. list_wiki_pages: browse wiki pages. get_wiki_page: read a wiki page. update_wiki_page: edit a wiki page. ingest_document: import a file (PDF, MD, etc.) into memory as chunks. list_documents: browse ingested documents by workspace. purge_document: remove a document and its memory chunks. set_document_importance: adjust chunk importance scores. rerank_documents: re-score document relevance for a query."
1442
+ },
1443
+ {
1444
+ title: "MCP tools \u2014 system, operations, and admin",
1445
+ domain: "tool-use",
1446
+ priority: "p1",
1447
+ content: "get_agent_spend: token usage per agent/session (cost tracking). list_agent_sessions: view agent session history. get_session_kills: audit log of killed sessions. get_daemon_health: check exed daemon status. get_auto_wake_status: daemon auto-wake configuration. get_worker_gate: check worker deployment gates. run_memory_audit: health check \u2014 duplicates, null vectors, orphaned rows. run_consolidation: trigger sleep-time memory consolidation. cloud_sync: force a cloud sync cycle. backup_vps: trigger VPS backup."
1448
+ },
1449
+ {
1450
+ title: "MCP tools \u2014 config, licensing, and team",
1451
+ domain: "tool-use",
1452
+ priority: "p1",
1453
+ content: "set_agent_config: view/change per-agent runtime and model settings. list_employees: view the employee roster. add_person: add a person to the CRM contacts roster. list_people: browse CRM contacts. get_person: fetch contact details. get_license_status: check license validity. create_license: generate a new license key (admin). list_licenses: view all issued licenses. activate_license: activate a license on a device."
1454
+ },
1455
+ {
1456
+ title: "MCP tools \u2014 advanced (triggers, skills, orchestration)",
1457
+ domain: "tool-use",
1458
+ priority: "p1",
1459
+ content: "create_trigger: set up a scheduled recurring agent job (cron). list_triggers: view active triggers. load_skill: load a slash-command skill dynamically. apply_starter_pack: import a pre-built behavior + identity pack for a role. export_orchestration: export full org state (tasks, behaviors, identities) as portable JSON. import_orchestration: import org state into a new instance. deploy_client: deploy a customer client instance. query_company_brain: unified RAG query across all company knowledge. create_reminder: set a text reminder (shown in boot brief). list_reminders: view pending reminders. complete_reminder: mark a reminder done. global_procedure: manage Layer 0 procedures (actions: store, list, deactivate). Legacy aliases: store_global_procedure, list_global_procedures, deactivate_global_procedure."
1398
1460
  }
1399
1461
  ];
1400
1462
  var PLATFORM_PROCEDURE_TITLES = new Set(