@askexenow/exe-os 0.9.93 → 0.9.95

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 +121 -13
  10. package/dist/bin/cli.js +1561 -466
  11. package/dist/bin/customer-readiness.js +61 -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 +114 -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 +136 -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 +135 -18
  22. package/dist/bin/exe-heartbeat.js +121 -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 +121 -13
  27. package/dist/bin/exe-pending-notifications.js +121 -13
  28. package/dist/bin/exe-pending-reviews.js +121 -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 +136 -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 +121 -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 +136 -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 +136 -18
  43. package/dist/bin/scan-tasks.js +136 -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 +136 -18
  49. package/dist/hooks/bug-report-worker.js +136 -18
  50. package/dist/hooks/codex-stop-task-finalizer.js +126 -14
  51. package/dist/hooks/commit-complete.js +136 -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 +313 -50
  57. package/dist/hooks/post-tool-combined.js +436 -13
  58. package/dist/hooks/pre-compact.js +136 -18
  59. package/dist/hooks/pre-tool-use.js +121 -13
  60. package/dist/hooks/prompt-submit.js +194 -19
  61. package/dist/hooks/session-end.js +136 -18
  62. package/dist/hooks/session-start.js +146 -13
  63. package/dist/hooks/stop.js +121 -13
  64. package/dist/hooks/subagent-stop.js +121 -13
  65. package/dist/hooks/summary-worker.js +99 -7
  66. package/dist/index.js +136 -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 +916 -42
  74. package/dist/lib/hybrid-search.js +100 -9
  75. package/dist/lib/license.js +1 -1
  76. package/dist/lib/messaging.js +43 -4
  77. package/dist/lib/schedules.js +54 -3
  78. package/dist/lib/store.js +75 -9
  79. package/dist/lib/tasks.js +61 -9
  80. package/dist/lib/tmux-routing.js +61 -9
  81. package/dist/mcp/server.js +878 -42
  82. package/dist/mcp/tools/create-task.js +70 -12
  83. package/dist/mcp/tools/list-tasks.js +49 -5
  84. package/dist/mcp/tools/send-message.js +43 -4
  85. package/dist/mcp/tools/update-task.js +61 -9
  86. package/dist/runtime/index.js +136 -18
  87. package/dist/tui/App.js +135 -18
  88. package/package.json +1 -1
@@ -3269,6 +3269,20 @@ async function ensureSchema() {
3269
3269
  });
3270
3270
  } catch {
3271
3271
  }
3272
+ try {
3273
+ await client.execute({
3274
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
3275
+ args: []
3276
+ });
3277
+ } catch {
3278
+ }
3279
+ try {
3280
+ await client.execute({
3281
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
3282
+ args: []
3283
+ });
3284
+ } catch {
3285
+ }
3272
3286
  await client.executeMultiple(`
3273
3287
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
3274
3288
  content_text,
@@ -3520,6 +3534,22 @@ async function ensureSchema() {
3520
3534
  );
3521
3535
  } catch {
3522
3536
  }
3537
+ for (const col of [
3538
+ "ALTER TABLE memories ADD COLUMN valid_from TEXT",
3539
+ "ALTER TABLE memories ADD COLUMN invalid_at TEXT"
3540
+ ]) {
3541
+ try {
3542
+ await client.execute(col);
3543
+ } catch {
3544
+ }
3545
+ }
3546
+ try {
3547
+ await client.execute({
3548
+ sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
3549
+ args: []
3550
+ });
3551
+ } catch {
3552
+ }
3523
3553
  try {
3524
3554
  await client.execute({
3525
3555
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
@@ -3562,6 +3592,13 @@ async function ensureSchema() {
3562
3592
  } catch {
3563
3593
  }
3564
3594
  }
3595
+ try {
3596
+ await client.execute({
3597
+ sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
3598
+ args: []
3599
+ });
3600
+ } catch {
3601
+ }
3565
3602
  try {
3566
3603
  await client.execute({
3567
3604
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
@@ -4130,7 +4167,7 @@ var init_license = __esm({
4130
4167
  LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
4131
4168
  CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
4132
4169
  DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
4133
- API_BASE = "https://askexe.com/cloud";
4170
+ API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
4134
4171
  RETRY_DELAY_MS = 500;
4135
4172
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
4136
4173
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
@@ -6703,6 +6740,20 @@ var init_platform_procedures = __esm({
6703
6740
  priority: "p1",
6704
6741
  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."
6705
6742
  },
6743
+ // --- Tool guidance ---
6744
+ {
6745
+ title: "How to use company_actions \u2014 execute business actions through gateway connectors",
6746
+ domain: "tools",
6747
+ priority: "p2",
6748
+ 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."
6749
+ },
6750
+ // --- Release awareness ---
6751
+ {
6752
+ title: "What's New check \u2014 surface new features after update",
6753
+ domain: "support",
6754
+ priority: "p1",
6755
+ 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."
6756
+ },
6706
6757
  // --- Platform vs Customer ownership ---
6707
6758
  {
6708
6759
  title: "What the platform provides vs what you customize",
@@ -6791,13 +6842,13 @@ var init_platform_procedures = __esm({
6791
6842
  title: "MCP tools \u2014 memory, decision, and search",
6792
6843
  domain: "tool-use",
6793
6844
  priority: "p1",
6794
- 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.`
6845
+ content: `memory(action="recall") / recall_my_memory: search memories (semantic + FTS). Params: as_of (bi-temporal \u2014 what did I know at time X?), kind (decision|procedure|observation|raw|conversation|behavior), retrieval_mode (all|decisions_only|procedures_only|operational|recent_high_value). memory(action="ask_team") / ask_team_memory: search a colleague's memories. memory(action="store") / store_memory: persist a memory. Params: kind, procedure_for (domain tag for procedures). memory(action="commit") / commit_memory: high-importance, survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal window. Requires session_id + target_timestamp. memory(action="get_by_id"): fetch one memory by UUID with full untruncated text. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. memory(action="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.`
6795
6846
  },
6796
6847
  {
6797
6848
  title: "MCP tools \u2014 task orchestration",
6798
6849
  domain: "tool-use",
6799
6850
  priority: "p1",
6800
- 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.'
6851
+ content: 'task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. Params: blocked_by (task ID for dependency), parent_task_id (subtask hierarchy), reviewer, complexity (routine|standard|complex|critical), budget_tokens (max token cap), budget_fallback_model, spawn_runtime (override runtime: claude|codex|opencode), spawn_model (override model). 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.'
6801
6852
  },
6802
6853
  {
6803
6854
  title: "MCP tools \u2014 knowledge graph (GraphRAG)",
@@ -6827,7 +6878,7 @@ var init_platform_procedures = __esm({
6827
6878
  title: "MCP tools \u2014 admin, config, and operations",
6828
6879
  domain: "tool-use",
6829
6880
  priority: "p1",
6830
- 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.'
6881
+ content: 'config(action="list_employees"): view roster. config(action="set_agent_config"): view or change per-agent runtime + model. Call with no args to show all agents. 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. Supports cloud_action param: status|sync|reupload. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="worker_gate"): check spawn slot availability \u2014 alive/stale/reserved counts vs max. Use before dispatching. config(action="auto_wake_status"): orphaned tasks, blocked tasks, auto-wake retry status. config(action="orchestration_phase"): view/change org phase (phase_1_coo|phase_2_executives|phase_3_parallel_org). 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="pending_work_summary"): pending reviews + messages + notifications in one call. diagnostics(action="rename_employee"): rename an agent across all systems (roster, identity, DB, symlinks). diagnostics(action="tool_search"): semantic tool discovery \u2014 find relevant MCP tools by natural language query. diagnostics(action="drift"): identity drift detection \u2014 score how far an agent has drifted from its role. mcp_ping(): daemon health + license status + tool usage stats.'
6831
6882
  }
6832
6883
  ];
6833
6884
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -7511,6 +7562,8 @@ async function writeMemory(record) {
7511
7562
  source_type: record.source_type ?? null,
7512
7563
  tier: record.tier ?? classifyTier(record),
7513
7564
  supersedes_id: record.supersedes_id ?? null,
7565
+ valid_from: record.valid_from ?? record.timestamp,
7566
+ invalid_at: record.invalid_at ?? null,
7514
7567
  draft: record.draft ? 1 : 0,
7515
7568
  memory_type: memoryType,
7516
7569
  trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
@@ -7529,7 +7582,8 @@ async function writeMemory(record) {
7529
7582
  token_cost: record.token_cost ?? null,
7530
7583
  audience: record.audience ?? null,
7531
7584
  language_type: record.language_type ?? inferLanguageType(record),
7532
- parent_memory_id: record.parent_memory_id ?? null
7585
+ parent_memory_id: record.parent_memory_id ?? null,
7586
+ procedure_for: record.procedure_for ?? null
7533
7587
  };
7534
7588
  _pendingRecords.push(dbRow);
7535
7589
  orgBus.emit({
@@ -7584,6 +7638,8 @@ async function flushBatch() {
7584
7638
  const sourceType = row.source_type ?? null;
7585
7639
  const tier = row.tier ?? 3;
7586
7640
  const supersedesId = row.supersedes_id ?? null;
7641
+ const validFrom = row.valid_from ?? row.timestamp;
7642
+ const invalidAt = row.invalid_at ?? null;
7587
7643
  const draft = row.draft ? 1 : 0;
7588
7644
  const memoryType = row.memory_type ?? "raw";
7589
7645
  const trajectory = row.trajectory ?? null;
@@ -7603,15 +7659,16 @@ async function flushBatch() {
7603
7659
  const audience = row.audience ?? null;
7604
7660
  const languageType = row.language_type ?? null;
7605
7661
  const parentMemoryId = row.parent_memory_id ?? null;
7662
+ const procedureFor = row.procedure_for ?? null;
7606
7663
  const cols = `id, agent_id, agent_role, session_id, timestamp,
7607
7664
  tool_name, project_name,
7608
7665
  has_error, raw_text, vector, version, task_id, importance, status,
7609
7666
  confidence, last_accessed,
7610
7667
  workspace_id, document_id, user_id, char_offset, page_number,
7611
- source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
7668
+ source_path, source_type, tier, supersedes_id, valid_from, invalid_at, draft, memory_type, trajectory, content_hash,
7612
7669
  intent, outcome, domain, referenced_entities, retrieval_count,
7613
7670
  chain_position, review_status, context_window_pct, file_paths, commit_hash,
7614
- duration_ms, token_cost, audience, language_type, parent_memory_id`;
7671
+ duration_ms, token_cost, audience, language_type, parent_memory_id, procedure_for`;
7615
7672
  const metaArgs = [
7616
7673
  intent,
7617
7674
  outcome,
@@ -7627,7 +7684,8 @@ async function flushBatch() {
7627
7684
  tokenCost,
7628
7685
  audience,
7629
7686
  languageType,
7630
- parentMemoryId
7687
+ parentMemoryId,
7688
+ procedureFor
7631
7689
  ];
7632
7690
  const baseArgs = [
7633
7691
  row.id,
@@ -7656,6 +7714,8 @@ async function flushBatch() {
7656
7714
  sourceType,
7657
7715
  tier,
7658
7716
  supersedesId,
7717
+ validFrom,
7718
+ invalidAt,
7659
7719
  draft,
7660
7720
  memoryType,
7661
7721
  trajectory,
@@ -7663,8 +7723,8 @@ async function flushBatch() {
7663
7723
  ];
7664
7724
  return {
7665
7725
  sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
7666
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
7667
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
7726
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
7727
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
7668
7728
  args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
7669
7729
  };
7670
7730
  };
@@ -7780,6 +7840,12 @@ async function searchMemories(queryVector, agentId, options) {
7780
7840
  AND vector IS NOT NULL${statusFilter}${draftFilter}
7781
7841
  AND COALESCE(confidence, 0.7) >= 0.3`;
7782
7842
  const args = [agentId];
7843
+ if (options?.asOf) {
7844
+ sql += ` AND (valid_from IS NULL OR valid_from <= ?) AND (invalid_at IS NULL OR invalid_at > ?)`;
7845
+ args.push(options.asOf, options.asOf);
7846
+ } else {
7847
+ sql += ` AND invalid_at IS NULL`;
7848
+ }
7783
7849
  const scope = buildWikiScopeFilter(options, "");
7784
7850
  sql += scope.clause;
7785
7851
  args.push(...scope.args);
@@ -3354,6 +3354,20 @@ async function ensureSchema() {
3354
3354
  });
3355
3355
  } catch {
3356
3356
  }
3357
+ try {
3358
+ await client.execute({
3359
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
3360
+ args: []
3361
+ });
3362
+ } catch {
3363
+ }
3364
+ try {
3365
+ await client.execute({
3366
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
3367
+ args: []
3368
+ });
3369
+ } catch {
3370
+ }
3357
3371
  await client.executeMultiple(`
3358
3372
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
3359
3373
  content_text,
@@ -3605,6 +3619,22 @@ async function ensureSchema() {
3605
3619
  );
3606
3620
  } catch {
3607
3621
  }
3622
+ for (const col of [
3623
+ "ALTER TABLE memories ADD COLUMN valid_from TEXT",
3624
+ "ALTER TABLE memories ADD COLUMN invalid_at TEXT"
3625
+ ]) {
3626
+ try {
3627
+ await client.execute(col);
3628
+ } catch {
3629
+ }
3630
+ }
3631
+ try {
3632
+ await client.execute({
3633
+ sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
3634
+ args: []
3635
+ });
3636
+ } catch {
3637
+ }
3608
3638
  try {
3609
3639
  await client.execute({
3610
3640
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
@@ -3647,6 +3677,13 @@ async function ensureSchema() {
3647
3677
  } catch {
3648
3678
  }
3649
3679
  }
3680
+ try {
3681
+ await client.execute({
3682
+ sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
3683
+ args: []
3684
+ });
3685
+ } catch {
3686
+ }
3650
3687
  try {
3651
3688
  await client.execute({
3652
3689
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
@@ -3707,7 +3744,7 @@ import { pathToFileURL as pathToFileURL2 } from "url";
3707
3744
  import os7 from "os";
3708
3745
  import path9 from "path";
3709
3746
  import { jwtVerify, importSPKI } from "jose";
3710
- var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
3747
+ var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, PLAN_LIMITS;
3711
3748
  var init_license = __esm({
3712
3749
  "src/lib/license.ts"() {
3713
3750
  "use strict";
@@ -3715,6 +3752,7 @@ var init_license = __esm({
3715
3752
  LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
3716
3753
  CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
3717
3754
  DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
3755
+ API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
3718
3756
  PLAN_LIMITS = {
3719
3757
  free: { devices: 1, employees: 1, memories: 5e3 },
3720
3758
  pro: { devices: 3, employees: 5, memories: 1e5 },
@@ -4365,8 +4403,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
4365
4403
  const complexity = input.complexity ?? "standard";
4366
4404
  const sessionScope = earlySessionScope;
4367
4405
  await client.execute({
4368
- 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)
4369
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
4406
+ 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)
4407
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
4370
4408
  args: [
4371
4409
  id,
4372
4410
  input.title,
@@ -4386,6 +4424,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
4386
4424
  0,
4387
4425
  null,
4388
4426
  sessionScope,
4427
+ input.spawnRuntime ?? null,
4428
+ input.spawnModel ?? null,
4389
4429
  now,
4390
4430
  now
4391
4431
  ]
@@ -4442,7 +4482,9 @@ ${input.context}
4442
4482
  budgetTokens: input.budgetTokens ?? null,
4443
4483
  budgetFallbackModel: input.budgetFallbackModel ?? null,
4444
4484
  tokensUsed: 0,
4445
- tokensWarnedAt: null
4485
+ tokensWarnedAt: null,
4486
+ spawnRuntime: input.spawnRuntime ?? null,
4487
+ spawnModel: input.spawnModel ?? null
4446
4488
  };
4447
4489
  }
4448
4490
  async function listTasks(input) {
@@ -4492,7 +4534,9 @@ async function listTasks(input) {
4492
4534
  budgetTokens: r.budget_tokens !== null ? Number(r.budget_tokens) : null,
4493
4535
  budgetFallbackModel: r.budget_fallback_model !== null ? String(r.budget_fallback_model) : null,
4494
4536
  tokensUsed: Number(r.tokens_used ?? 0),
4495
- tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null
4537
+ tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null,
4538
+ spawnRuntime: r.spawn_runtime !== null && r.spawn_runtime !== void 0 ? String(r.spawn_runtime) : null,
4539
+ spawnModel: r.spawn_model !== null && r.spawn_model !== void 0 ? String(r.spawn_model) : null
4496
4540
  }));
4497
4541
  }
4498
4542
  function isTmuxSessionAlive(identifier) {
@@ -5789,6 +5833,8 @@ async function updateTask(input) {
5789
5833
  budgetFallbackModel: row.budget_fallback_model !== void 0 && row.budget_fallback_model !== null ? String(row.budget_fallback_model) : null,
5790
5834
  tokensUsed: Number(row.tokens_used ?? 0),
5791
5835
  tokensWarnedAt: row.tokens_warned_at !== void 0 && row.tokens_warned_at !== null ? Number(row.tokens_warned_at) : null,
5836
+ spawnRuntime: row.spawn_runtime !== void 0 && row.spawn_runtime !== null ? String(row.spawn_runtime) : null,
5837
+ spawnModel: row.spawn_model !== void 0 && row.spawn_model !== null ? String(row.spawn_model) : null,
5792
5838
  nextTask
5793
5839
  };
5794
5840
  }
@@ -6281,9 +6327,13 @@ function getDispatchedBy(sessionKey) {
6281
6327
  }
6282
6328
  }
6283
6329
  function resolveExeSession() {
6330
+ if (process.env.EXE_SESSION_NAME) {
6331
+ return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
6332
+ }
6284
6333
  const mySession = getMySession();
6285
6334
  if (!mySession) return null;
6286
6335
  const fromSessionName = extractRootExe(mySession);
6336
+ let candidate = null;
6287
6337
  try {
6288
6338
  const key = getSessionKey();
6289
6339
  const parentExe = getParentExe(key);
@@ -6294,13 +6344,47 @@ function resolveExeSession() {
6294
6344
  `[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
6295
6345
  `
6296
6346
  );
6297
- return fromSessionName;
6347
+ candidate = fromSessionName;
6348
+ } else {
6349
+ candidate = fromCache;
6298
6350
  }
6299
- return fromCache;
6300
6351
  }
6301
6352
  } catch {
6302
6353
  }
6303
- return fromSessionName ?? mySession;
6354
+ if (!candidate) {
6355
+ candidate = fromSessionName ?? mySession;
6356
+ }
6357
+ if (candidate && isRootSession(candidate)) {
6358
+ try {
6359
+ const transport = getTransport();
6360
+ const liveSessions = transport.listSessions();
6361
+ if (!liveSessions.includes(candidate)) {
6362
+ const liveRoots = liveSessions.filter((s) => isRootSession(s));
6363
+ if (liveRoots.length === 1) {
6364
+ process.stderr.write(
6365
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead. Using live coordinator "${liveRoots[0]}".
6366
+ `
6367
+ );
6368
+ return liveRoots[0];
6369
+ } else if (liveRoots.length > 1) {
6370
+ const base = candidate.replace(/\d+$/, "");
6371
+ const match = liveRoots.find((s) => s.startsWith(base));
6372
+ const chosen = match ?? liveRoots[0];
6373
+ process.stderr.write(
6374
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead. ${liveRoots.length} live roots found, using "${chosen}".
6375
+ `
6376
+ );
6377
+ return chosen;
6378
+ }
6379
+ process.stderr.write(
6380
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead and no live coordinator found.
6381
+ `
6382
+ );
6383
+ }
6384
+ } catch {
6385
+ }
6386
+ }
6387
+ return candidate;
6304
6388
  }
6305
6389
  function isEmployeeAlive(sessionName) {
6306
6390
  return getTransport().isAlive(sessionName);
@@ -6702,7 +6786,12 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
6702
6786
  }
6703
6787
  const spawnCwd = opts?.cwd ?? projectDir2;
6704
6788
  const useExeAgent = !!(opts?.model && opts?.provider);
6705
- const agentRtConfig = getAgentRuntime(employeeName2);
6789
+ const baseRtConfig = getAgentRuntime(employeeName2);
6790
+ const agentRtConfig = {
6791
+ ...baseRtConfig,
6792
+ ...opts?.runtimeOverride ? { runtime: opts.runtimeOverride } : {},
6793
+ ...opts?.modelOverride ? { model: opts.modelOverride } : {}
6794
+ };
6706
6795
  const useCodex = !useExeAgent && agentRtConfig.runtime === "codex";
6707
6796
  const useOpencode = !useExeAgent && !useCodex && agentRtConfig.runtime === "opencode";
6708
6797
  const ccProvider = useExeAgent || useCodex || useOpencode ? DEFAULT_PROVIDER : detectActiveProvider();
@@ -7962,6 +8051,20 @@ var init_platform_procedures = __esm({
7962
8051
  priority: "p1",
7963
8052
  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."
7964
8053
  },
8054
+ // --- Tool guidance ---
8055
+ {
8056
+ title: "How to use company_actions \u2014 execute business actions through gateway connectors",
8057
+ domain: "tools",
8058
+ priority: "p2",
8059
+ 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."
8060
+ },
8061
+ // --- Release awareness ---
8062
+ {
8063
+ title: "What's New check \u2014 surface new features after update",
8064
+ domain: "support",
8065
+ priority: "p1",
8066
+ 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."
8067
+ },
7965
8068
  // --- Platform vs Customer ownership ---
7966
8069
  {
7967
8070
  title: "What the platform provides vs what you customize",
@@ -8050,13 +8153,13 @@ var init_platform_procedures = __esm({
8050
8153
  title: "MCP tools \u2014 memory, decision, and search",
8051
8154
  domain: "tool-use",
8052
8155
  priority: "p1",
8053
- 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.`
8156
+ content: `memory(action="recall") / recall_my_memory: search memories (semantic + FTS). Params: as_of (bi-temporal \u2014 what did I know at time X?), kind (decision|procedure|observation|raw|conversation|behavior), retrieval_mode (all|decisions_only|procedures_only|operational|recent_high_value). memory(action="ask_team") / ask_team_memory: search a colleague's memories. memory(action="store") / store_memory: persist a memory. Params: kind, procedure_for (domain tag for procedures). memory(action="commit") / commit_memory: high-importance, survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal window. Requires session_id + target_timestamp. memory(action="get_by_id"): fetch one memory by UUID with full untruncated text. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. memory(action="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.`
8054
8157
  },
8055
8158
  {
8056
8159
  title: "MCP tools \u2014 task orchestration",
8057
8160
  domain: "tool-use",
8058
8161
  priority: "p1",
8059
- 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.'
8162
+ content: 'task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. Params: blocked_by (task ID for dependency), parent_task_id (subtask hierarchy), reviewer, complexity (routine|standard|complex|critical), budget_tokens (max token cap), budget_fallback_model, spawn_runtime (override runtime: claude|codex|opencode), spawn_model (override model). 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.'
8060
8163
  },
8061
8164
  {
8062
8165
  title: "MCP tools \u2014 knowledge graph (GraphRAG)",
@@ -8086,7 +8189,7 @@ var init_platform_procedures = __esm({
8086
8189
  title: "MCP tools \u2014 admin, config, and operations",
8087
8190
  domain: "tool-use",
8088
8191
  priority: "p1",
8089
- 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.'
8192
+ content: 'config(action="list_employees"): view roster. config(action="set_agent_config"): view or change per-agent runtime + model. Call with no args to show all agents. 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. Supports cloud_action param: status|sync|reupload. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="worker_gate"): check spawn slot availability \u2014 alive/stale/reserved counts vs max. Use before dispatching. config(action="auto_wake_status"): orphaned tasks, blocked tasks, auto-wake retry status. config(action="orchestration_phase"): view/change org phase (phase_1_coo|phase_2_executives|phase_3_parallel_org). 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="pending_work_summary"): pending reviews + messages + notifications in one call. diagnostics(action="rename_employee"): rename an agent across all systems (roster, identity, DB, symlinks). diagnostics(action="tool_search"): semantic tool discovery \u2014 find relevant MCP tools by natural language query. diagnostics(action="drift"): identity drift detection \u2014 score how far an agent has drifted from its role. mcp_ping(): daemon health + license status + tool usage stats.'
8090
8193
  }
8091
8194
  ];
8092
8195
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -8770,6 +8873,8 @@ async function writeMemory(record) {
8770
8873
  source_type: record.source_type ?? null,
8771
8874
  tier: record.tier ?? classifyTier(record),
8772
8875
  supersedes_id: record.supersedes_id ?? null,
8876
+ valid_from: record.valid_from ?? record.timestamp,
8877
+ invalid_at: record.invalid_at ?? null,
8773
8878
  draft: record.draft ? 1 : 0,
8774
8879
  memory_type: memoryType,
8775
8880
  trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
@@ -8788,7 +8893,8 @@ async function writeMemory(record) {
8788
8893
  token_cost: record.token_cost ?? null,
8789
8894
  audience: record.audience ?? null,
8790
8895
  language_type: record.language_type ?? inferLanguageType(record),
8791
- parent_memory_id: record.parent_memory_id ?? null
8896
+ parent_memory_id: record.parent_memory_id ?? null,
8897
+ procedure_for: record.procedure_for ?? null
8792
8898
  };
8793
8899
  _pendingRecords.push(dbRow);
8794
8900
  orgBus.emit({
@@ -8843,6 +8949,8 @@ async function flushBatch() {
8843
8949
  const sourceType = row.source_type ?? null;
8844
8950
  const tier = row.tier ?? 3;
8845
8951
  const supersedesId = row.supersedes_id ?? null;
8952
+ const validFrom = row.valid_from ?? row.timestamp;
8953
+ const invalidAt = row.invalid_at ?? null;
8846
8954
  const draft = row.draft ? 1 : 0;
8847
8955
  const memoryType = row.memory_type ?? "raw";
8848
8956
  const trajectory = row.trajectory ?? null;
@@ -8862,15 +8970,16 @@ async function flushBatch() {
8862
8970
  const audience = row.audience ?? null;
8863
8971
  const languageType = row.language_type ?? null;
8864
8972
  const parentMemoryId = row.parent_memory_id ?? null;
8973
+ const procedureFor = row.procedure_for ?? null;
8865
8974
  const cols = `id, agent_id, agent_role, session_id, timestamp,
8866
8975
  tool_name, project_name,
8867
8976
  has_error, raw_text, vector, version, task_id, importance, status,
8868
8977
  confidence, last_accessed,
8869
8978
  workspace_id, document_id, user_id, char_offset, page_number,
8870
- source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
8979
+ source_path, source_type, tier, supersedes_id, valid_from, invalid_at, draft, memory_type, trajectory, content_hash,
8871
8980
  intent, outcome, domain, referenced_entities, retrieval_count,
8872
8981
  chain_position, review_status, context_window_pct, file_paths, commit_hash,
8873
- duration_ms, token_cost, audience, language_type, parent_memory_id`;
8982
+ duration_ms, token_cost, audience, language_type, parent_memory_id, procedure_for`;
8874
8983
  const metaArgs = [
8875
8984
  intent,
8876
8985
  outcome,
@@ -8886,7 +8995,8 @@ async function flushBatch() {
8886
8995
  tokenCost,
8887
8996
  audience,
8888
8997
  languageType,
8889
- parentMemoryId
8998
+ parentMemoryId,
8999
+ procedureFor
8890
9000
  ];
8891
9001
  const baseArgs = [
8892
9002
  row.id,
@@ -8915,6 +9025,8 @@ async function flushBatch() {
8915
9025
  sourceType,
8916
9026
  tier,
8917
9027
  supersedesId,
9028
+ validFrom,
9029
+ invalidAt,
8918
9030
  draft,
8919
9031
  memoryType,
8920
9032
  trajectory,
@@ -8922,8 +9034,8 @@ async function flushBatch() {
8922
9034
  ];
8923
9035
  return {
8924
9036
  sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
8925
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
8926
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
9037
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
9038
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
8927
9039
  args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
8928
9040
  };
8929
9041
  };
@@ -9039,6 +9151,12 @@ async function searchMemories(queryVector, agentId, options) {
9039
9151
  AND vector IS NOT NULL${statusFilter}${draftFilter}
9040
9152
  AND COALESCE(confidence, 0.7) >= 0.3`;
9041
9153
  const args = [agentId];
9154
+ if (options?.asOf) {
9155
+ sql += ` AND (valid_from IS NULL OR valid_from <= ?) AND (invalid_at IS NULL OR invalid_at > ?)`;
9156
+ args.push(options.asOf, options.asOf);
9157
+ } else {
9158
+ sql += ` AND invalid_at IS NULL`;
9159
+ }
9042
9160
  const scope = buildWikiScopeFilter(options, "");
9043
9161
  sql += scope.clause;
9044
9162
  args.push(...scope.args);