@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
@@ -578,7 +578,7 @@ var init_agent_config = __esm({
578
578
  init_secure_files();
579
579
  AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
580
580
  DEFAULT_MODELS = {
581
- claude: "claude-opus-4",
581
+ claude: "claude-opus-4.6",
582
582
  codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
583
583
  opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
584
584
  };
@@ -648,9 +648,9 @@ var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
648
648
  var init_db_retry = __esm({
649
649
  "src/lib/db-retry.ts"() {
650
650
  "use strict";
651
- MAX_RETRIES = 3;
652
- BASE_DELAY_MS = 200;
653
- MAX_JITTER_MS = 300;
651
+ MAX_RETRIES = 5;
652
+ BASE_DELAY_MS = 250;
653
+ MAX_JITTER_MS = 400;
654
654
  }
655
655
  });
656
656
 
@@ -1238,6 +1238,15 @@ var init_database_adapter = __esm({
1238
1238
  }
1239
1239
  });
1240
1240
 
1241
+ // src/types/memory.ts
1242
+ var EMBEDDING_DIM;
1243
+ var init_memory = __esm({
1244
+ "src/types/memory.ts"() {
1245
+ "use strict";
1246
+ EMBEDDING_DIM = 1024;
1247
+ }
1248
+ });
1249
+
1241
1250
  // src/lib/daemon-auth.ts
1242
1251
  import crypto from "crypto";
1243
1252
  import path8 from "path";
@@ -1660,7 +1669,7 @@ function createDaemonDbClient(fallbackClient) {
1660
1669
  });
1661
1670
  if (response.error) {
1662
1671
  const errMsg = String(response.error);
1663
- if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
1672
+ if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed" || errMsg === "DB not initialized") {
1664
1673
  process.stderr.write(`[db-daemon] Transport error (${errMsg}), falling back to direct
1665
1674
  `);
1666
1675
  return fallbackClient.execute(stmt);
@@ -1685,7 +1694,7 @@ function createDaemonDbClient(fallbackClient) {
1685
1694
  });
1686
1695
  if (response.error) {
1687
1696
  const errMsg = String(response.error);
1688
- if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
1697
+ if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed" || errMsg === "DB not initialized") {
1689
1698
  process.stderr.write(`[db-daemon] Batch transport error (${errMsg}), falling back to direct
1690
1699
  `);
1691
1700
  return fallbackClient.batch(stmts, mode);
@@ -1808,7 +1817,7 @@ async function initDatabase(config) {
1808
1817
  });
1809
1818
  }, 3e4);
1810
1819
  _walCheckpointTimer.unref();
1811
- if (process.env.DATABASE_URL) {
1820
+ if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
1812
1821
  _adapterClient = await createPrismaDbAdapter(_resilientClient);
1813
1822
  }
1814
1823
  }
@@ -1819,7 +1828,7 @@ function getClient() {
1819
1828
  if (!_adapterClient) {
1820
1829
  throw new Error("Database client not initialized. Call initDatabase() first.");
1821
1830
  }
1822
- if (process.env.DATABASE_URL) {
1831
+ if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
1823
1832
  return _adapterClient;
1824
1833
  }
1825
1834
  if (process.env.EXE_IS_DAEMON === "1") {
@@ -1831,9 +1840,11 @@ function getClient() {
1831
1840
  return _resilientClient;
1832
1841
  }
1833
1842
  async function initDaemonClient() {
1834
- if (process.env.DATABASE_URL) return;
1843
+ if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") return;
1835
1844
  if (process.env.EXE_IS_DAEMON === "1") return;
1845
+ if (process.env.VITEST) return;
1836
1846
  if (!_resilientClient) return;
1847
+ if (_daemonClient) return;
1837
1848
  try {
1838
1849
  const { initDaemonDbClient: initDaemonDbClient2 } = await Promise.resolve().then(() => (init_db_daemon_client(), db_daemon_client_exports));
1839
1850
  _daemonClient = await initDaemonDbClient2(_resilientClient);
@@ -1982,6 +1993,13 @@ async function ensureSchema() {
1982
1993
  });
1983
1994
  } catch {
1984
1995
  }
1996
+ try {
1997
+ await client.execute({
1998
+ sql: `ALTER TABLE behaviors ADD COLUMN vector F32_BLOB(${EMBEDDING_DIM})`,
1999
+ args: []
2000
+ });
2001
+ } catch {
2002
+ }
1985
2003
  try {
1986
2004
  await client.execute({
1987
2005
  sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
@@ -2852,6 +2870,7 @@ var init_database = __esm({
2852
2870
  init_db_retry();
2853
2871
  init_employees();
2854
2872
  init_database_adapter();
2873
+ init_memory();
2855
2874
  _client = null;
2856
2875
  _resilientClient = null;
2857
2876
  _walCheckpointTimer = null;
@@ -2987,15 +3006,6 @@ var init_task_scope = __esm({
2987
3006
  }
2988
3007
  });
2989
3008
 
2990
- // src/types/memory.ts
2991
- var EMBEDDING_DIM;
2992
- var init_memory = __esm({
2993
- "src/types/memory.ts"() {
2994
- "use strict";
2995
- EMBEDDING_DIM = 1024;
2996
- }
2997
- });
2998
-
2999
3009
  // src/lib/keychain.ts
3000
3010
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3001
3011
  import { existsSync as existsSync11 } from "fs";
@@ -3538,6 +3548,68 @@ var init_platform_procedures = __esm({
3538
3548
  domain: "architecture",
3539
3549
  priority: "p0",
3540
3550
  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."
3551
+ },
3552
+ // --- MCP is the ONLY data interface ---
3553
+ {
3554
+ title: "MCP disconnect \u2014 ask the user, never work around it",
3555
+ domain: "workflow",
3556
+ priority: "p0",
3557
+ 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."
3558
+ },
3559
+ // --- MCP Tool Catalog (Layer 0 — every agent knows what tools exist) ---
3560
+ {
3561
+ title: "MCP tools \u2014 memory and search",
3562
+ domain: "tool-use",
3563
+ priority: "p1",
3564
+ 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)."
3565
+ },
3566
+ {
3567
+ title: "MCP tools \u2014 task orchestration",
3568
+ domain: "tool-use",
3569
+ priority: "p1",
3570
+ 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."
3571
+ },
3572
+ {
3573
+ title: "MCP tools \u2014 knowledge graph (GraphRAG)",
3574
+ domain: "tool-use",
3575
+ priority: "p1",
3576
+ 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."
3577
+ },
3578
+ {
3579
+ title: "MCP tools \u2014 identity, behavior, and decisions",
3580
+ domain: "tool-use",
3581
+ priority: "p1",
3582
+ 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."
3583
+ },
3584
+ {
3585
+ title: "MCP tools \u2014 communication and messaging",
3586
+ domain: "tool-use",
3587
+ priority: "p1",
3588
+ 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.)."
3589
+ },
3590
+ {
3591
+ title: "MCP tools \u2014 wiki, documents, and content",
3592
+ domain: "tool-use",
3593
+ priority: "p1",
3594
+ 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."
3595
+ },
3596
+ {
3597
+ title: "MCP tools \u2014 system, operations, and admin",
3598
+ domain: "tool-use",
3599
+ priority: "p1",
3600
+ 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."
3601
+ },
3602
+ {
3603
+ title: "MCP tools \u2014 config, licensing, and team",
3604
+ domain: "tool-use",
3605
+ priority: "p1",
3606
+ 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."
3607
+ },
3608
+ {
3609
+ title: "MCP tools \u2014 advanced (triggers, skills, orchestration)",
3610
+ domain: "tool-use",
3611
+ priority: "p1",
3612
+ 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."
3541
3613
  }
3542
3614
  ];
3543
3615
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -3687,6 +3759,11 @@ async function initStore(options) {
3687
3759
  encryptionKey: hexKey
3688
3760
  });
3689
3761
  await retryOnBusy2(() => ensureSchema(), "ensureSchema");
3762
+ try {
3763
+ const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
3764
+ await initDaemonClient2();
3765
+ } catch {
3766
+ }
3690
3767
  if (!options?.lightweight) {
3691
3768
  try {
3692
3769
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
@@ -4200,12 +4277,84 @@ var init_store = __esm({
4200
4277
  }
4201
4278
  });
4202
4279
 
4280
+ // src/lib/memory-queue.ts
4281
+ import { appendFileSync as appendFileSync2, readFileSync as readFileSync11, renameSync as renameSync4, unlinkSync as unlinkSync4, existsSync as existsSync13, statSync as statSync2 } from "fs";
4282
+ import path15 from "path";
4283
+ function enqueueMemory(entry) {
4284
+ appendFileSync2(QUEUE_PATH2, JSON.stringify(entry) + "\n");
4285
+ }
4286
+ var QUEUE_PATH2, PROCESSING_PATH, TTL_MS2;
4287
+ var init_memory_queue = __esm({
4288
+ "src/lib/memory-queue.ts"() {
4289
+ "use strict";
4290
+ init_config();
4291
+ QUEUE_PATH2 = path15.join(EXE_AI_DIR, "memory-queue.jsonl");
4292
+ PROCESSING_PATH = QUEUE_PATH2 + ".processing";
4293
+ TTL_MS2 = 24 * 60 * 60 * 1e3;
4294
+ }
4295
+ });
4296
+
4297
+ // src/lib/memory-queue-client.ts
4298
+ var memory_queue_client_exports = {};
4299
+ __export(memory_queue_client_exports, {
4300
+ batchWriteMemoryViaDaemon: () => batchWriteMemoryViaDaemon,
4301
+ writeMemoryViaDaemon: () => writeMemoryViaDaemon
4302
+ });
4303
+ async function writeMemoryViaDaemon(entry) {
4304
+ if (process.env.EXE_IS_DAEMON === "1") {
4305
+ enqueueMemory(entry);
4306
+ return false;
4307
+ }
4308
+ if (!isClientConnected()) {
4309
+ enqueueMemory(entry);
4310
+ return false;
4311
+ }
4312
+ try {
4313
+ const response = await sendDaemonRequest({
4314
+ type: "write-memory",
4315
+ entry
4316
+ });
4317
+ if (response.ok) return true;
4318
+ enqueueMemory(entry);
4319
+ return false;
4320
+ } catch {
4321
+ enqueueMemory(entry);
4322
+ return false;
4323
+ }
4324
+ }
4325
+ async function batchWriteMemoryViaDaemon(entries) {
4326
+ if (entries.length === 0) return 0;
4327
+ if (process.env.EXE_IS_DAEMON === "1" || !isClientConnected()) {
4328
+ for (const entry of entries) enqueueMemory(entry);
4329
+ return 0;
4330
+ }
4331
+ try {
4332
+ const response = await sendDaemonRequest({
4333
+ type: "batch-write-memory",
4334
+ entries
4335
+ });
4336
+ if (response.ok) return response.count ?? entries.length;
4337
+ for (const entry of entries) enqueueMemory(entry);
4338
+ return 0;
4339
+ } catch {
4340
+ for (const entry of entries) enqueueMemory(entry);
4341
+ return 0;
4342
+ }
4343
+ }
4344
+ var init_memory_queue_client = __esm({
4345
+ "src/lib/memory-queue-client.ts"() {
4346
+ "use strict";
4347
+ init_exe_daemon_client();
4348
+ init_memory_queue();
4349
+ }
4350
+ });
4351
+
4203
4352
  // src/adapters/claude/hooks/stop.ts
4204
4353
  init_config();
4205
4354
  init_config();
4206
4355
  import { spawn as spawn2 } from "child_process";
4207
- import { existsSync as existsSync13, openSync as openSync2, closeSync as closeSync2 } from "fs";
4208
- import path15 from "path";
4356
+ import { existsSync as existsSync14, openSync as openSync2, closeSync as closeSync2 } from "fs";
4357
+ import path16 from "path";
4209
4358
  import { fileURLToPath as fileURLToPath3 } from "url";
4210
4359
 
4211
4360
  // src/lib/active-agent.ts
@@ -4315,7 +4464,7 @@ if (!process.env.AGENT_ID) {
4315
4464
  if (!loadConfigSync().autoIngestion) {
4316
4465
  process.exit(0);
4317
4466
  }
4318
- var WORKER_LOG_PATH = path15.join(EXE_AI_DIR, "workers.log");
4467
+ var WORKER_LOG_PATH = path16.join(EXE_AI_DIR, "workers.log");
4319
4468
  function openWorkerLog() {
4320
4469
  try {
4321
4470
  return openSync2(WORKER_LOG_PATH, "a");
@@ -4324,7 +4473,7 @@ function openWorkerLog() {
4324
4473
  }
4325
4474
  }
4326
4475
  function spawnDetachedWorker(workerPath, env, cwd) {
4327
- if (!existsSync13(workerPath)) {
4476
+ if (!existsSync14(workerPath)) {
4328
4477
  process.stderr.write(`[stop] WARN: worker not found at ${workerPath}
4329
4478
  `);
4330
4479
  return;
@@ -4357,9 +4506,9 @@ process.stdin.on("end", () => {
4357
4506
  try {
4358
4507
  if (process.env.EXE_DEBUG_HOOKS || process.env.EXE_RUNTIME === "codex") {
4359
4508
  try {
4360
- const debugPath = path15.join(EXE_AI_DIR, "logs", "hook-stdin-stop.log");
4509
+ const debugPath = path16.join(EXE_AI_DIR, "logs", "hook-stdin-stop.log");
4361
4510
  const { mkdirSync: mkdirSync7, writeFileSync: writeFileSync8 } = __require("fs");
4362
- mkdirSync7(path15.dirname(debugPath), { recursive: true });
4511
+ mkdirSync7(path16.dirname(debugPath), { recursive: true });
4363
4512
  const ts = (/* @__PURE__ */ new Date()).toISOString();
4364
4513
  const snippet = input.length > 500 ? input.slice(0, 500) + "...[truncated]" : input;
4365
4514
  writeFileSync8(debugPath, `[${ts}] len=${input.length} ${snippet}
@@ -4372,8 +4521,8 @@ process.stdin.on("end", () => {
4372
4521
  const message = data.last_assistant_message ?? "";
4373
4522
  const cwd = data.cwd ?? process.cwd();
4374
4523
  if (process.env.EXE_RUNTIME === "codex" && !canCoordinate(agent.agentId, agent.agentRole)) {
4375
- const codexFinalizerPath = path15.resolve(
4376
- path15.dirname(fileURLToPath3(import.meta.url)),
4524
+ const codexFinalizerPath = path16.resolve(
4525
+ path16.dirname(fileURLToPath3(import.meta.url)),
4377
4526
  "codex-stop-task-finalizer.js"
4378
4527
  );
4379
4528
  spawnDetachedWorker(codexFinalizerPath, {
@@ -4389,10 +4538,7 @@ process.stdin.on("end", () => {
4389
4538
  }
4390
4539
  const CAPACITY_SIGNALS = /context[- ]?full|hit capacity|conversation is too long|maximum context length|context window.*(?:limit|exceed|full)/i;
4391
4540
  if (!canCoordinate(agent.agentId, agent.agentRole) && CAPACITY_SIGNALS.test(message)) {
4392
- Promise.resolve().then(() => (init_store(), store_exports)).then(({ initStore: initStore2 }) => initStore2()).then(() => Promise.all([
4393
- Promise.resolve().then(() => (init_database(), database_exports)),
4394
- Promise.resolve().then(() => (init_store(), store_exports))
4395
- ])).then(async ([{ getClient: getClient2 }, { writeMemory: writeMemory2, flushBatch: flushBatch2 }]) => {
4541
+ Promise.resolve().then(() => (init_store(), store_exports)).then(({ initStore: initStore2 }) => initStore2()).then(() => Promise.resolve().then(() => (init_database(), database_exports))).then(async ({ getClient: getClient2 }) => {
4396
4542
  const client = getClient2();
4397
4543
  const stScope = sessionScopeFilter();
4398
4544
  const tasks = await client.execute({
@@ -4411,21 +4557,16 @@ process.stdin.on("end", () => {
4411
4557
  "",
4412
4558
  `Last response fragment: ${message.slice(0, 500)}`
4413
4559
  ].join("\n");
4414
- const crypto2 = await import("crypto");
4415
- await writeMemory2({
4416
- id: crypto2.randomUUID(),
4560
+ const { writeMemoryViaDaemon: writeMemoryViaDaemon2 } = await Promise.resolve().then(() => (init_memory_queue_client(), memory_queue_client_exports));
4561
+ await writeMemoryViaDaemon2({
4562
+ raw_text: checkpoint,
4417
4563
  agent_id: agent.agentId,
4418
4564
  agent_role: agent.agentRole,
4419
4565
  session_id: data.session_id,
4420
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4421
4566
  tool_name: "auto-checkpoint",
4422
4567
  project_name: process.env.EXE_PROJECT_NAME ?? "unknown",
4423
- has_error: false,
4424
- raw_text: checkpoint,
4425
- vector: null
4426
- // Backfill handles embedding later
4568
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
4427
4569
  });
4428
- await flushBatch2();
4429
4570
  process.stderr.write(`[stop] Context checkpoint stored for ${agent.agentId} (capacity signal detected)
4430
4571
  `);
4431
4572
  }).catch(() => {
@@ -4452,17 +4593,18 @@ process.stdin.on("end", () => {
4452
4593
  }).catch(() => {
4453
4594
  });
4454
4595
  }
4455
- const workerPath = path15.resolve(
4456
- path15.dirname(fileURLToPath3(import.meta.url)),
4457
- "response-ingest-worker.js"
4458
- );
4459
- spawnDetachedWorker(workerPath, {
4460
- ...process.env,
4461
- AGENT_ID: agent.agentId,
4462
- AGENT_ROLE: agent.agentRole,
4463
- EXE_RESPONSE_TEXT: message.slice(0, 5e3),
4464
- EXE_SESSION_ID: data.session_id
4465
- }, cwd);
4596
+ Promise.resolve().then(() => (init_memory_queue_client(), memory_queue_client_exports)).then(
4597
+ ({ writeMemoryViaDaemon: writeMemoryViaDaemon2 }) => writeMemoryViaDaemon2({
4598
+ raw_text: message.slice(0, 5e3),
4599
+ agent_id: agent.agentId,
4600
+ agent_role: agent.agentRole,
4601
+ tool_name: "AssistantResponse",
4602
+ project_name: process.env.EXE_PROJECT_NAME ?? cwd.split("/").pop() ?? "unknown",
4603
+ session_id: data.session_id,
4604
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
4605
+ })
4606
+ ).catch(() => {
4607
+ });
4466
4608
  } catch {
4467
4609
  }
4468
4610
  process.exit(0);
@@ -559,7 +559,7 @@ var init_agent_config = __esm({
559
559
  init_secure_files();
560
560
  AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
561
561
  DEFAULT_MODELS = {
562
- claude: "claude-opus-4",
562
+ claude: "claude-opus-4.6",
563
563
  codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
564
564
  opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
565
565
  };
@@ -629,9 +629,9 @@ var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
629
629
  var init_db_retry = __esm({
630
630
  "src/lib/db-retry.ts"() {
631
631
  "use strict";
632
- MAX_RETRIES = 3;
633
- BASE_DELAY_MS = 200;
634
- MAX_JITTER_MS = 300;
632
+ MAX_RETRIES = 5;
633
+ BASE_DELAY_MS = 250;
634
+ MAX_JITTER_MS = 400;
635
635
  }
636
636
  });
637
637
 
@@ -1219,6 +1219,15 @@ var init_database_adapter = __esm({
1219
1219
  }
1220
1220
  });
1221
1221
 
1222
+ // src/types/memory.ts
1223
+ var EMBEDDING_DIM;
1224
+ var init_memory = __esm({
1225
+ "src/types/memory.ts"() {
1226
+ "use strict";
1227
+ EMBEDDING_DIM = 1024;
1228
+ }
1229
+ });
1230
+
1222
1231
  // src/lib/daemon-auth.ts
1223
1232
  import crypto from "crypto";
1224
1233
  import path8 from "path";
@@ -1641,7 +1650,7 @@ function createDaemonDbClient(fallbackClient) {
1641
1650
  });
1642
1651
  if (response.error) {
1643
1652
  const errMsg = String(response.error);
1644
- if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
1653
+ if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed" || errMsg === "DB not initialized") {
1645
1654
  process.stderr.write(`[db-daemon] Transport error (${errMsg}), falling back to direct
1646
1655
  `);
1647
1656
  return fallbackClient.execute(stmt);
@@ -1666,7 +1675,7 @@ function createDaemonDbClient(fallbackClient) {
1666
1675
  });
1667
1676
  if (response.error) {
1668
1677
  const errMsg = String(response.error);
1669
- if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
1678
+ if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed" || errMsg === "DB not initialized") {
1670
1679
  process.stderr.write(`[db-daemon] Batch transport error (${errMsg}), falling back to direct
1671
1680
  `);
1672
1681
  return fallbackClient.batch(stmts, mode);
@@ -1789,7 +1798,7 @@ async function initDatabase(config) {
1789
1798
  });
1790
1799
  }, 3e4);
1791
1800
  _walCheckpointTimer.unref();
1792
- if (process.env.DATABASE_URL) {
1801
+ if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
1793
1802
  _adapterClient = await createPrismaDbAdapter(_resilientClient);
1794
1803
  }
1795
1804
  }
@@ -1800,7 +1809,7 @@ function getClient() {
1800
1809
  if (!_adapterClient) {
1801
1810
  throw new Error("Database client not initialized. Call initDatabase() first.");
1802
1811
  }
1803
- if (process.env.DATABASE_URL) {
1812
+ if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
1804
1813
  return _adapterClient;
1805
1814
  }
1806
1815
  if (process.env.EXE_IS_DAEMON === "1") {
@@ -1812,9 +1821,11 @@ function getClient() {
1812
1821
  return _resilientClient;
1813
1822
  }
1814
1823
  async function initDaemonClient() {
1815
- if (process.env.DATABASE_URL) return;
1824
+ if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") return;
1816
1825
  if (process.env.EXE_IS_DAEMON === "1") return;
1826
+ if (process.env.VITEST) return;
1817
1827
  if (!_resilientClient) return;
1828
+ if (_daemonClient) return;
1818
1829
  try {
1819
1830
  const { initDaemonDbClient: initDaemonDbClient2 } = await Promise.resolve().then(() => (init_db_daemon_client(), db_daemon_client_exports));
1820
1831
  _daemonClient = await initDaemonDbClient2(_resilientClient);
@@ -1963,6 +1974,13 @@ async function ensureSchema() {
1963
1974
  });
1964
1975
  } catch {
1965
1976
  }
1977
+ try {
1978
+ await client.execute({
1979
+ sql: `ALTER TABLE behaviors ADD COLUMN vector F32_BLOB(${EMBEDDING_DIM})`,
1980
+ args: []
1981
+ });
1982
+ } catch {
1983
+ }
1966
1984
  try {
1967
1985
  await client.execute({
1968
1986
  sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
@@ -2833,6 +2851,7 @@ var init_database = __esm({
2833
2851
  init_db_retry();
2834
2852
  init_employees();
2835
2853
  init_database_adapter();
2854
+ init_memory();
2836
2855
  _client = null;
2837
2856
  _resilientClient = null;
2838
2857
  _walCheckpointTimer = null;
@@ -2968,15 +2987,6 @@ var init_task_scope = __esm({
2968
2987
  }
2969
2988
  });
2970
2989
 
2971
- // src/types/memory.ts
2972
- var EMBEDDING_DIM;
2973
- var init_memory = __esm({
2974
- "src/types/memory.ts"() {
2975
- "use strict";
2976
- EMBEDDING_DIM = 1024;
2977
- }
2978
- });
2979
-
2980
2990
  // src/lib/keychain.ts
2981
2991
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
2982
2992
  import { existsSync as existsSync11 } from "fs";
@@ -3519,6 +3529,68 @@ var init_platform_procedures = __esm({
3519
3529
  domain: "architecture",
3520
3530
  priority: "p0",
3521
3531
  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."
3532
+ },
3533
+ // --- MCP is the ONLY data interface ---
3534
+ {
3535
+ title: "MCP disconnect \u2014 ask the user, never work around it",
3536
+ domain: "workflow",
3537
+ priority: "p0",
3538
+ 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."
3539
+ },
3540
+ // --- MCP Tool Catalog (Layer 0 — every agent knows what tools exist) ---
3541
+ {
3542
+ title: "MCP tools \u2014 memory and search",
3543
+ domain: "tool-use",
3544
+ priority: "p1",
3545
+ 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)."
3546
+ },
3547
+ {
3548
+ title: "MCP tools \u2014 task orchestration",
3549
+ domain: "tool-use",
3550
+ priority: "p1",
3551
+ 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."
3552
+ },
3553
+ {
3554
+ title: "MCP tools \u2014 knowledge graph (GraphRAG)",
3555
+ domain: "tool-use",
3556
+ priority: "p1",
3557
+ 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."
3558
+ },
3559
+ {
3560
+ title: "MCP tools \u2014 identity, behavior, and decisions",
3561
+ domain: "tool-use",
3562
+ priority: "p1",
3563
+ 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."
3564
+ },
3565
+ {
3566
+ title: "MCP tools \u2014 communication and messaging",
3567
+ domain: "tool-use",
3568
+ priority: "p1",
3569
+ 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.)."
3570
+ },
3571
+ {
3572
+ title: "MCP tools \u2014 wiki, documents, and content",
3573
+ domain: "tool-use",
3574
+ priority: "p1",
3575
+ 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."
3576
+ },
3577
+ {
3578
+ title: "MCP tools \u2014 system, operations, and admin",
3579
+ domain: "tool-use",
3580
+ priority: "p1",
3581
+ 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."
3582
+ },
3583
+ {
3584
+ title: "MCP tools \u2014 config, licensing, and team",
3585
+ domain: "tool-use",
3586
+ priority: "p1",
3587
+ 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."
3588
+ },
3589
+ {
3590
+ title: "MCP tools \u2014 advanced (triggers, skills, orchestration)",
3591
+ domain: "tool-use",
3592
+ priority: "p1",
3593
+ 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."
3522
3594
  }
3523
3595
  ];
3524
3596
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -3668,6 +3740,11 @@ async function initStore(options) {
3668
3740
  encryptionKey: hexKey
3669
3741
  });
3670
3742
  await retryOnBusy2(() => ensureSchema(), "ensureSchema");
3743
+ try {
3744
+ const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
3745
+ await initDaemonClient2();
3746
+ } catch {
3747
+ }
3671
3748
  if (!options?.lightweight) {
3672
3749
  try {
3673
3750
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));