@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
@@ -3366,6 +3366,20 @@ async function ensureSchema() {
3366
3366
  });
3367
3367
  } catch {
3368
3368
  }
3369
+ try {
3370
+ await client.execute({
3371
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
3372
+ args: []
3373
+ });
3374
+ } catch {
3375
+ }
3376
+ try {
3377
+ await client.execute({
3378
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
3379
+ args: []
3380
+ });
3381
+ } catch {
3382
+ }
3369
3383
  await client.executeMultiple(`
3370
3384
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
3371
3385
  content_text,
@@ -3617,6 +3631,22 @@ async function ensureSchema() {
3617
3631
  );
3618
3632
  } catch {
3619
3633
  }
3634
+ for (const col of [
3635
+ "ALTER TABLE memories ADD COLUMN valid_from TEXT",
3636
+ "ALTER TABLE memories ADD COLUMN invalid_at TEXT"
3637
+ ]) {
3638
+ try {
3639
+ await client.execute(col);
3640
+ } catch {
3641
+ }
3642
+ }
3643
+ try {
3644
+ await client.execute({
3645
+ sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
3646
+ args: []
3647
+ });
3648
+ } catch {
3649
+ }
3620
3650
  try {
3621
3651
  await client.execute({
3622
3652
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
@@ -3659,6 +3689,13 @@ async function ensureSchema() {
3659
3689
  } catch {
3660
3690
  }
3661
3691
  }
3692
+ try {
3693
+ await client.execute({
3694
+ sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
3695
+ args: []
3696
+ });
3697
+ } catch {
3698
+ }
3662
3699
  try {
3663
3700
  await client.execute({
3664
3701
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
@@ -3719,7 +3756,7 @@ import { pathToFileURL as pathToFileURL2 } from "url";
3719
3756
  import os7 from "os";
3720
3757
  import path9 from "path";
3721
3758
  import { jwtVerify, importSPKI } from "jose";
3722
- var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
3759
+ var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, PLAN_LIMITS;
3723
3760
  var init_license = __esm({
3724
3761
  "src/lib/license.ts"() {
3725
3762
  "use strict";
@@ -3727,6 +3764,7 @@ var init_license = __esm({
3727
3764
  LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
3728
3765
  CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
3729
3766
  DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
3767
+ API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
3730
3768
  PLAN_LIMITS = {
3731
3769
  free: { devices: 1, employees: 1, memories: 5e3 },
3732
3770
  pro: { devices: 3, employees: 5, memories: 1e5 },
@@ -4353,8 +4391,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
4353
4391
  const complexity = input.complexity ?? "standard";
4354
4392
  const sessionScope = earlySessionScope;
4355
4393
  await client.execute({
4356
- 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)
4357
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
4394
+ 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)
4395
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
4358
4396
  args: [
4359
4397
  id,
4360
4398
  input.title,
@@ -4374,6 +4412,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
4374
4412
  0,
4375
4413
  null,
4376
4414
  sessionScope,
4415
+ input.spawnRuntime ?? null,
4416
+ input.spawnModel ?? null,
4377
4417
  now,
4378
4418
  now
4379
4419
  ]
@@ -4430,7 +4470,9 @@ ${input.context}
4430
4470
  budgetTokens: input.budgetTokens ?? null,
4431
4471
  budgetFallbackModel: input.budgetFallbackModel ?? null,
4432
4472
  tokensUsed: 0,
4433
- tokensWarnedAt: null
4473
+ tokensWarnedAt: null,
4474
+ spawnRuntime: input.spawnRuntime ?? null,
4475
+ spawnModel: input.spawnModel ?? null
4434
4476
  };
4435
4477
  }
4436
4478
  async function listTasks(input) {
@@ -4480,7 +4522,9 @@ async function listTasks(input) {
4480
4522
  budgetTokens: r.budget_tokens !== null ? Number(r.budget_tokens) : null,
4481
4523
  budgetFallbackModel: r.budget_fallback_model !== null ? String(r.budget_fallback_model) : null,
4482
4524
  tokensUsed: Number(r.tokens_used ?? 0),
4483
- tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null
4525
+ tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null,
4526
+ spawnRuntime: r.spawn_runtime !== null && r.spawn_runtime !== void 0 ? String(r.spawn_runtime) : null,
4527
+ spawnModel: r.spawn_model !== null && r.spawn_model !== void 0 ? String(r.spawn_model) : null
4484
4528
  }));
4485
4529
  }
4486
4530
  function isTmuxSessionAlive(identifier) {
@@ -5777,6 +5821,8 @@ async function updateTask(input) {
5777
5821
  budgetFallbackModel: row.budget_fallback_model !== void 0 && row.budget_fallback_model !== null ? String(row.budget_fallback_model) : null,
5778
5822
  tokensUsed: Number(row.tokens_used ?? 0),
5779
5823
  tokensWarnedAt: row.tokens_warned_at !== void 0 && row.tokens_warned_at !== null ? Number(row.tokens_warned_at) : null,
5824
+ spawnRuntime: row.spawn_runtime !== void 0 && row.spawn_runtime !== null ? String(row.spawn_runtime) : null,
5825
+ spawnModel: row.spawn_model !== void 0 && row.spawn_model !== null ? String(row.spawn_model) : null,
5780
5826
  nextTask
5781
5827
  };
5782
5828
  }
@@ -6272,6 +6318,7 @@ function resolveExeSession() {
6272
6318
  const mySession = getMySession();
6273
6319
  if (!mySession) return null;
6274
6320
  const fromSessionName = extractRootExe(mySession);
6321
+ let candidate = null;
6275
6322
  try {
6276
6323
  const key = getSessionKey();
6277
6324
  const parentExe = getParentExe(key);
@@ -6282,13 +6329,47 @@ function resolveExeSession() {
6282
6329
  `[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
6283
6330
  `
6284
6331
  );
6285
- return fromSessionName;
6332
+ candidate = fromSessionName;
6333
+ } else {
6334
+ candidate = fromCache;
6286
6335
  }
6287
- return fromCache;
6288
6336
  }
6289
6337
  } catch {
6290
6338
  }
6291
- return fromSessionName ?? mySession;
6339
+ if (!candidate) {
6340
+ candidate = fromSessionName ?? mySession;
6341
+ }
6342
+ if (candidate && isRootSession(candidate)) {
6343
+ try {
6344
+ const transport = getTransport();
6345
+ const liveSessions = transport.listSessions();
6346
+ if (!liveSessions.includes(candidate)) {
6347
+ const liveRoots = liveSessions.filter((s) => isRootSession(s));
6348
+ if (liveRoots.length === 1) {
6349
+ process.stderr.write(
6350
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead. Using live coordinator "${liveRoots[0]}".
6351
+ `
6352
+ );
6353
+ return liveRoots[0];
6354
+ } else if (liveRoots.length > 1) {
6355
+ const base = candidate.replace(/\d+$/, "");
6356
+ const match = liveRoots.find((s) => s.startsWith(base));
6357
+ const chosen = match ?? liveRoots[0];
6358
+ process.stderr.write(
6359
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead. ${liveRoots.length} live roots found, using "${chosen}".
6360
+ `
6361
+ );
6362
+ return chosen;
6363
+ }
6364
+ process.stderr.write(
6365
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead and no live coordinator found.
6366
+ `
6367
+ );
6368
+ }
6369
+ } catch {
6370
+ }
6371
+ }
6372
+ return candidate;
6292
6373
  }
6293
6374
  function isEmployeeAlive(sessionName) {
6294
6375
  return getTransport().isAlive(sessionName);
@@ -6690,7 +6771,12 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6690
6771
  }
6691
6772
  const spawnCwd = opts?.cwd ?? projectDir;
6692
6773
  const useExeAgent = !!(opts?.model && opts?.provider);
6693
- const agentRtConfig = getAgentRuntime(employeeName);
6774
+ const baseRtConfig = getAgentRuntime(employeeName);
6775
+ const agentRtConfig = {
6776
+ ...baseRtConfig,
6777
+ ...opts?.runtimeOverride ? { runtime: opts.runtimeOverride } : {},
6778
+ ...opts?.modelOverride ? { model: opts.modelOverride } : {}
6779
+ };
6694
6780
  const useCodex = !useExeAgent && agentRtConfig.runtime === "codex";
6695
6781
  const useOpencode = !useExeAgent && !useCodex && agentRtConfig.runtime === "opencode";
6696
6782
  const ccProvider = useExeAgent || useCodex || useOpencode ? DEFAULT_PROVIDER : detectActiveProvider();
@@ -7983,6 +8069,20 @@ var init_platform_procedures = __esm({
7983
8069
  priority: "p1",
7984
8070
  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."
7985
8071
  },
8072
+ // --- Tool guidance ---
8073
+ {
8074
+ title: "How to use company_actions \u2014 execute business actions through gateway connectors",
8075
+ domain: "tools",
8076
+ priority: "p2",
8077
+ 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."
8078
+ },
8079
+ // --- Release awareness ---
8080
+ {
8081
+ title: "What's New check \u2014 surface new features after update",
8082
+ domain: "support",
8083
+ priority: "p1",
8084
+ 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."
8085
+ },
7986
8086
  // --- Platform vs Customer ownership ---
7987
8087
  {
7988
8088
  title: "What the platform provides vs what you customize",
@@ -8071,13 +8171,13 @@ var init_platform_procedures = __esm({
8071
8171
  title: "MCP tools \u2014 memory, decision, and search",
8072
8172
  domain: "tool-use",
8073
8173
  priority: "p1",
8074
- 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.`
8174
+ 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.`
8075
8175
  },
8076
8176
  {
8077
8177
  title: "MCP tools \u2014 task orchestration",
8078
8178
  domain: "tool-use",
8079
8179
  priority: "p1",
8080
- 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.'
8180
+ 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.`
8081
8181
  },
8082
8182
  {
8083
8183
  title: "MCP tools \u2014 knowledge graph (GraphRAG)",
@@ -8107,7 +8207,7 @@ var init_platform_procedures = __esm({
8107
8207
  title: "MCP tools \u2014 admin, config, and operations",
8108
8208
  domain: "tool-use",
8109
8209
  priority: "p1",
8110
- 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.'
8210
+ 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.'
8111
8211
  }
8112
8212
  ];
8113
8213
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -8791,6 +8891,8 @@ async function writeMemory(record) {
8791
8891
  source_type: record.source_type ?? null,
8792
8892
  tier: record.tier ?? classifyTier(record),
8793
8893
  supersedes_id: record.supersedes_id ?? null,
8894
+ valid_from: record.valid_from ?? record.timestamp,
8895
+ invalid_at: record.invalid_at ?? null,
8794
8896
  draft: record.draft ? 1 : 0,
8795
8897
  memory_type: memoryType,
8796
8898
  trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
@@ -8809,7 +8911,8 @@ async function writeMemory(record) {
8809
8911
  token_cost: record.token_cost ?? null,
8810
8912
  audience: record.audience ?? null,
8811
8913
  language_type: record.language_type ?? inferLanguageType(record),
8812
- parent_memory_id: record.parent_memory_id ?? null
8914
+ parent_memory_id: record.parent_memory_id ?? null,
8915
+ procedure_for: record.procedure_for ?? null
8813
8916
  };
8814
8917
  _pendingRecords.push(dbRow);
8815
8918
  orgBus.emit({
@@ -8864,6 +8967,8 @@ async function flushBatch() {
8864
8967
  const sourceType = row.source_type ?? null;
8865
8968
  const tier = row.tier ?? 3;
8866
8969
  const supersedesId = row.supersedes_id ?? null;
8970
+ const validFrom = row.valid_from ?? row.timestamp;
8971
+ const invalidAt = row.invalid_at ?? null;
8867
8972
  const draft = row.draft ? 1 : 0;
8868
8973
  const memoryType = row.memory_type ?? "raw";
8869
8974
  const trajectory = row.trajectory ?? null;
@@ -8883,15 +8988,16 @@ async function flushBatch() {
8883
8988
  const audience = row.audience ?? null;
8884
8989
  const languageType = row.language_type ?? null;
8885
8990
  const parentMemoryId = row.parent_memory_id ?? null;
8991
+ const procedureFor = row.procedure_for ?? null;
8886
8992
  const cols = `id, agent_id, agent_role, session_id, timestamp,
8887
8993
  tool_name, project_name,
8888
8994
  has_error, raw_text, vector, version, task_id, importance, status,
8889
8995
  confidence, last_accessed,
8890
8996
  workspace_id, document_id, user_id, char_offset, page_number,
8891
- source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
8997
+ source_path, source_type, tier, supersedes_id, valid_from, invalid_at, draft, memory_type, trajectory, content_hash,
8892
8998
  intent, outcome, domain, referenced_entities, retrieval_count,
8893
8999
  chain_position, review_status, context_window_pct, file_paths, commit_hash,
8894
- duration_ms, token_cost, audience, language_type, parent_memory_id`;
9000
+ duration_ms, token_cost, audience, language_type, parent_memory_id, procedure_for`;
8895
9001
  const metaArgs = [
8896
9002
  intent,
8897
9003
  outcome,
@@ -8907,7 +9013,8 @@ async function flushBatch() {
8907
9013
  tokenCost,
8908
9014
  audience,
8909
9015
  languageType,
8910
- parentMemoryId
9016
+ parentMemoryId,
9017
+ procedureFor
8911
9018
  ];
8912
9019
  const baseArgs = [
8913
9020
  row.id,
@@ -8936,6 +9043,8 @@ async function flushBatch() {
8936
9043
  sourceType,
8937
9044
  tier,
8938
9045
  supersedesId,
9046
+ validFrom,
9047
+ invalidAt,
8939
9048
  draft,
8940
9049
  memoryType,
8941
9050
  trajectory,
@@ -8943,8 +9052,8 @@ async function flushBatch() {
8943
9052
  ];
8944
9053
  return {
8945
9054
  sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
8946
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
8947
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
9055
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
9056
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
8948
9057
  args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
8949
9058
  };
8950
9059
  };
@@ -9060,6 +9169,12 @@ async function searchMemories(queryVector, agentId, options) {
9060
9169
  AND vector IS NOT NULL${statusFilter}${draftFilter}
9061
9170
  AND COALESCE(confidence, 0.7) >= 0.3`;
9062
9171
  const args = [agentId];
9172
+ if (options?.asOf) {
9173
+ sql += ` AND (valid_from IS NULL OR valid_from <= ?) AND (invalid_at IS NULL OR invalid_at > ?)`;
9174
+ args.push(options.asOf, options.asOf);
9175
+ } else {
9176
+ sql += ` AND invalid_at IS NULL`;
9177
+ }
9063
9178
  const scope = buildWikiScopeFilter(options, "");
9064
9179
  sql += scope.clause;
9065
9180
  args.push(...scope.args);
package/dist/bin/setup.js CHANGED
@@ -1792,7 +1792,7 @@ var init_license = __esm({
1792
1792
  LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
1793
1793
  CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
1794
1794
  DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
1795
- API_BASE = "https://askexe.com/cloud";
1795
+ API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
1796
1796
  RETRY_DELAY_MS = 500;
1797
1797
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
1798
1798
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
@@ -4170,6 +4170,20 @@ async function ensureSchema() {
4170
4170
  });
4171
4171
  } catch {
4172
4172
  }
4173
+ try {
4174
+ await client.execute({
4175
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
4176
+ args: []
4177
+ });
4178
+ } catch {
4179
+ }
4180
+ try {
4181
+ await client.execute({
4182
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
4183
+ args: []
4184
+ });
4185
+ } catch {
4186
+ }
4173
4187
  await client.executeMultiple(`
4174
4188
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
4175
4189
  content_text,
@@ -4421,6 +4435,22 @@ async function ensureSchema() {
4421
4435
  );
4422
4436
  } catch {
4423
4437
  }
4438
+ for (const col of [
4439
+ "ALTER TABLE memories ADD COLUMN valid_from TEXT",
4440
+ "ALTER TABLE memories ADD COLUMN invalid_at TEXT"
4441
+ ]) {
4442
+ try {
4443
+ await client.execute(col);
4444
+ } catch {
4445
+ }
4446
+ }
4447
+ try {
4448
+ await client.execute({
4449
+ sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
4450
+ args: []
4451
+ });
4452
+ } catch {
4453
+ }
4424
4454
  try {
4425
4455
  await client.execute({
4426
4456
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
@@ -4463,6 +4493,13 @@ async function ensureSchema() {
4463
4493
  } catch {
4464
4494
  }
4465
4495
  }
4496
+ try {
4497
+ await client.execute({
4498
+ sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
4499
+ args: []
4500
+ });
4501
+ } catch {
4502
+ }
4466
4503
  try {
4467
4504
  await client.execute({
4468
4505
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
@@ -6606,6 +6643,20 @@ var init_platform_procedures = __esm({
6606
6643
  priority: "p1",
6607
6644
  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."
6608
6645
  },
6646
+ // --- Tool guidance ---
6647
+ {
6648
+ title: "How to use company_actions \u2014 execute business actions through gateway connectors",
6649
+ domain: "tools",
6650
+ priority: "p2",
6651
+ 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."
6652
+ },
6653
+ // --- Release awareness ---
6654
+ {
6655
+ title: "What's New check \u2014 surface new features after update",
6656
+ domain: "support",
6657
+ priority: "p1",
6658
+ 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."
6659
+ },
6609
6660
  // --- Platform vs Customer ownership ---
6610
6661
  {
6611
6662
  title: "What the platform provides vs what you customize",
@@ -6694,13 +6745,13 @@ var init_platform_procedures = __esm({
6694
6745
  title: "MCP tools \u2014 memory, decision, and search",
6695
6746
  domain: "tool-use",
6696
6747
  priority: "p1",
6697
- 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.`
6748
+ 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.`
6698
6749
  },
6699
6750
  {
6700
6751
  title: "MCP tools \u2014 task orchestration",
6701
6752
  domain: "tool-use",
6702
6753
  priority: "p1",
6703
- 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.'
6754
+ 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.`
6704
6755
  },
6705
6756
  {
6706
6757
  title: "MCP tools \u2014 knowledge graph (GraphRAG)",
@@ -6730,7 +6781,7 @@ var init_platform_procedures = __esm({
6730
6781
  title: "MCP tools \u2014 admin, config, and operations",
6731
6782
  domain: "tool-use",
6732
6783
  priority: "p1",
6733
- 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.'
6784
+ 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.'
6734
6785
  }
6735
6786
  ];
6736
6787
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -2550,6 +2550,20 @@ async function ensureSchema() {
2550
2550
  });
2551
2551
  } catch {
2552
2552
  }
2553
+ try {
2554
+ await client.execute({
2555
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
2556
+ args: []
2557
+ });
2558
+ } catch {
2559
+ }
2560
+ try {
2561
+ await client.execute({
2562
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
2563
+ args: []
2564
+ });
2565
+ } catch {
2566
+ }
2553
2567
  await client.executeMultiple(`
2554
2568
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
2555
2569
  content_text,
@@ -2801,6 +2815,22 @@ async function ensureSchema() {
2801
2815
  );
2802
2816
  } catch {
2803
2817
  }
2818
+ for (const col of [
2819
+ "ALTER TABLE memories ADD COLUMN valid_from TEXT",
2820
+ "ALTER TABLE memories ADD COLUMN invalid_at TEXT"
2821
+ ]) {
2822
+ try {
2823
+ await client.execute(col);
2824
+ } catch {
2825
+ }
2826
+ }
2827
+ try {
2828
+ await client.execute({
2829
+ sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
2830
+ args: []
2831
+ });
2832
+ } catch {
2833
+ }
2804
2834
  try {
2805
2835
  await client.execute({
2806
2836
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
@@ -2843,6 +2873,13 @@ async function ensureSchema() {
2843
2873
  } catch {
2844
2874
  }
2845
2875
  }
2876
+ try {
2877
+ await client.execute({
2878
+ sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
2879
+ args: []
2880
+ });
2881
+ } catch {
2882
+ }
2846
2883
  try {
2847
2884
  await client.execute({
2848
2885
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
@@ -3424,6 +3461,20 @@ var init_platform_procedures = __esm({
3424
3461
  priority: "p1",
3425
3462
  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."
3426
3463
  },
3464
+ // --- Tool guidance ---
3465
+ {
3466
+ title: "How to use company_actions \u2014 execute business actions through gateway connectors",
3467
+ domain: "tools",
3468
+ priority: "p2",
3469
+ 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."
3470
+ },
3471
+ // --- Release awareness ---
3472
+ {
3473
+ title: "What's New check \u2014 surface new features after update",
3474
+ domain: "support",
3475
+ priority: "p1",
3476
+ 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."
3477
+ },
3427
3478
  // --- Platform vs Customer ownership ---
3428
3479
  {
3429
3480
  title: "What the platform provides vs what you customize",
@@ -3512,13 +3563,13 @@ var init_platform_procedures = __esm({
3512
3563
  title: "MCP tools \u2014 memory, decision, and search",
3513
3564
  domain: "tool-use",
3514
3565
  priority: "p1",
3515
- 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.`
3566
+ 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.`
3516
3567
  },
3517
3568
  {
3518
3569
  title: "MCP tools \u2014 task orchestration",
3519
3570
  domain: "tool-use",
3520
3571
  priority: "p1",
3521
- 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.'
3572
+ 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.`
3522
3573
  },
3523
3574
  {
3524
3575
  title: "MCP tools \u2014 knowledge graph (GraphRAG)",
@@ -3548,7 +3599,7 @@ var init_platform_procedures = __esm({
3548
3599
  title: "MCP tools \u2014 admin, config, and operations",
3549
3600
  domain: "tool-use",
3550
3601
  priority: "p1",
3551
- 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.'
3602
+ 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.'
3552
3603
  }
3553
3604
  ];
3554
3605
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -4606,6 +4657,8 @@ async function flushBatch() {
4606
4657
  const sourceType = row.source_type ?? null;
4607
4658
  const tier = row.tier ?? 3;
4608
4659
  const supersedesId = row.supersedes_id ?? null;
4660
+ const validFrom = row.valid_from ?? row.timestamp;
4661
+ const invalidAt = row.invalid_at ?? null;
4609
4662
  const draft = row.draft ? 1 : 0;
4610
4663
  const memoryType = row.memory_type ?? "raw";
4611
4664
  const trajectory = row.trajectory ?? null;
@@ -4625,15 +4678,16 @@ async function flushBatch() {
4625
4678
  const audience = row.audience ?? null;
4626
4679
  const languageType = row.language_type ?? null;
4627
4680
  const parentMemoryId = row.parent_memory_id ?? null;
4681
+ const procedureFor = row.procedure_for ?? null;
4628
4682
  const cols = `id, agent_id, agent_role, session_id, timestamp,
4629
4683
  tool_name, project_name,
4630
4684
  has_error, raw_text, vector, version, task_id, importance, status,
4631
4685
  confidence, last_accessed,
4632
4686
  workspace_id, document_id, user_id, char_offset, page_number,
4633
- source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
4687
+ source_path, source_type, tier, supersedes_id, valid_from, invalid_at, draft, memory_type, trajectory, content_hash,
4634
4688
  intent, outcome, domain, referenced_entities, retrieval_count,
4635
4689
  chain_position, review_status, context_window_pct, file_paths, commit_hash,
4636
- duration_ms, token_cost, audience, language_type, parent_memory_id`;
4690
+ duration_ms, token_cost, audience, language_type, parent_memory_id, procedure_for`;
4637
4691
  const metaArgs = [
4638
4692
  intent,
4639
4693
  outcome,
@@ -4649,7 +4703,8 @@ async function flushBatch() {
4649
4703
  tokenCost,
4650
4704
  audience,
4651
4705
  languageType,
4652
- parentMemoryId
4706
+ parentMemoryId,
4707
+ procedureFor
4653
4708
  ];
4654
4709
  const baseArgs = [
4655
4710
  row.id,
@@ -4678,6 +4733,8 @@ async function flushBatch() {
4678
4733
  sourceType,
4679
4734
  tier,
4680
4735
  supersedesId,
4736
+ validFrom,
4737
+ invalidAt,
4681
4738
  draft,
4682
4739
  memoryType,
4683
4740
  trajectory,
@@ -4685,8 +4742,8 @@ async function flushBatch() {
4685
4742
  ];
4686
4743
  return {
4687
4744
  sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
4688
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
4689
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
4745
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
4746
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
4690
4747
  args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
4691
4748
  };
4692
4749
  };
@@ -140,6 +140,7 @@ var DEFAULT_CONFIG = {
140
140
  var LICENSE_PATH = path2.join(EXE_AI_DIR, "license.key");
141
141
  var CACHE_PATH = path2.join(EXE_AI_DIR, "license-cache.json");
142
142
  var DEVICE_ID_PATH = path2.join(EXE_AI_DIR, "device-id");
143
+ var API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
143
144
  function loadLicense() {
144
145
  try {
145
146
  if (!existsSync3(LICENSE_PATH)) return null;
@@ -599,12 +600,10 @@ async function runStackUpdate(options) {
599
600
  if (hasPlaceholder) {
600
601
  const pair = options.pairMonitor ? options.pairMonitor(hubUrl, pairLicense, pairDomain, options.envFile) : pairMonitorAgent(hubUrl, pairLicense, pairDomain, options.envFile);
601
602
  const result = await pair;
602
- if (typeof result === "object" && result && "paired" in result) {
603
- if (result.paired) {
604
- console.log(`[stack-update] Monitor agent paired: ${result.systemName}`);
605
- } else {
606
- console.warn(`[stack-update] Monitor pairing skipped: ${result.error}`);
607
- }
603
+ if (result.paired) {
604
+ console.log(`[stack-update] Monitor agent paired: ${result.systemName}`);
605
+ } else {
606
+ console.warn(`[stack-update] Monitor pairing skipped: ${result.error}`);
608
607
  }
609
608
  }
610
609
  }