@jungjaehoon/mama-os 0.20.1 → 0.21.0

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 (195) hide show
  1. package/dist/agent/code-act/host-bridge.d.ts.map +1 -1
  2. package/dist/agent/code-act/host-bridge.js +14 -3
  3. package/dist/agent/code-act/host-bridge.js.map +1 -1
  4. package/dist/agent/gateway-tool-executor.d.ts +8 -10
  5. package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
  6. package/dist/agent/gateway-tool-executor.js +201 -28
  7. package/dist/agent/gateway-tool-executor.js.map +1 -1
  8. package/dist/agent/gateway-tools.md +1 -1
  9. package/dist/agent/os-agent-capabilities.md +13 -12
  10. package/dist/agent/tool-registry.js +1 -1
  11. package/dist/agent/tool-registry.js.map +1 -1
  12. package/dist/agent/types.d.ts +4 -0
  13. package/dist/agent/types.d.ts.map +1 -1
  14. package/dist/agent/types.js.map +1 -1
  15. package/dist/api/graph-api.d.ts.map +1 -1
  16. package/dist/api/graph-api.js +78 -5
  17. package/dist/api/graph-api.js.map +1 -1
  18. package/dist/api/index.d.ts +7 -0
  19. package/dist/api/index.d.ts.map +1 -1
  20. package/dist/api/index.js +5 -1
  21. package/dist/api/index.js.map +1 -1
  22. package/dist/api/operator-handler.d.ts +17 -0
  23. package/dist/api/operator-handler.d.ts.map +1 -0
  24. package/dist/api/operator-handler.js +88 -0
  25. package/dist/api/operator-handler.js.map +1 -0
  26. package/dist/api/report-handler.d.ts +7 -0
  27. package/dist/api/report-handler.d.ts.map +1 -1
  28. package/dist/api/report-handler.js +30 -0
  29. package/dist/api/report-handler.js.map +1 -1
  30. package/dist/api/report-persistence.d.ts +17 -0
  31. package/dist/api/report-persistence.d.ts.map +1 -0
  32. package/dist/api/report-persistence.js +91 -0
  33. package/dist/api/report-persistence.js.map +1 -0
  34. package/dist/cli/commands/start.d.ts.map +1 -1
  35. package/dist/cli/commands/start.js +351 -249
  36. package/dist/cli/commands/start.js.map +1 -1
  37. package/dist/cli/config/config-manager.d.ts.map +1 -1
  38. package/dist/cli/config/config-manager.js +93 -55
  39. package/dist/cli/config/config-manager.js.map +1 -1
  40. package/dist/cli/config/types.d.ts +17 -2
  41. package/dist/cli/config/types.d.ts.map +1 -1
  42. package/dist/cli/config/types.js +4 -0
  43. package/dist/cli/config/types.js.map +1 -1
  44. package/dist/cli/runtime/agent-loop-init.d.ts +1 -0
  45. package/dist/cli/runtime/agent-loop-init.d.ts.map +1 -1
  46. package/dist/cli/runtime/agent-loop-init.js +1 -0
  47. package/dist/cli/runtime/agent-loop-init.js.map +1 -1
  48. package/dist/cli/runtime/api-routes-init.d.ts.map +1 -1
  49. package/dist/cli/runtime/api-routes-init.js +386 -258
  50. package/dist/cli/runtime/api-routes-init.js.map +1 -1
  51. package/dist/cli/runtime/api-server-init.d.ts.map +1 -1
  52. package/dist/cli/runtime/api-server-init.js +12 -7
  53. package/dist/cli/runtime/api-server-init.js.map +1 -1
  54. package/dist/cli/runtime/connector-init.d.ts +19 -1
  55. package/dist/cli/runtime/connector-init.d.ts.map +1 -1
  56. package/dist/cli/runtime/connector-init.js +32 -2
  57. package/dist/cli/runtime/connector-init.js.map +1 -1
  58. package/dist/cli/runtime/message-router-config.d.ts +4 -0
  59. package/dist/cli/runtime/message-router-config.d.ts.map +1 -0
  60. package/dist/cli/runtime/message-router-config.js +11 -0
  61. package/dist/cli/runtime/message-router-config.js.map +1 -0
  62. package/dist/cli/runtime/scheduler-init.d.ts.map +1 -1
  63. package/dist/cli/runtime/scheduler-init.js +12 -12
  64. package/dist/cli/runtime/scheduler-init.js.map +1 -1
  65. package/dist/connectors/framework/polling-scheduler.d.ts.map +1 -1
  66. package/dist/connectors/framework/polling-scheduler.js +53 -2
  67. package/dist/connectors/framework/polling-scheduler.js.map +1 -1
  68. package/dist/connectors/kagemusha/query-tools.d.ts.map +1 -1
  69. package/dist/connectors/kagemusha/query-tools.js +14 -3
  70. package/dist/connectors/kagemusha/query-tools.js.map +1 -1
  71. package/dist/db/migrations/wiki-artifacts.d.ts +3 -0
  72. package/dist/db/migrations/wiki-artifacts.d.ts.map +1 -0
  73. package/dist/db/migrations/wiki-artifacts.js +24 -0
  74. package/dist/db/migrations/wiki-artifacts.js.map +1 -0
  75. package/dist/gateways/message-router.d.ts.map +1 -1
  76. package/dist/gateways/message-router.js +15 -3
  77. package/dist/gateways/message-router.js.map +1 -1
  78. package/dist/gateways/types.d.ts +4 -0
  79. package/dist/gateways/types.d.ts.map +1 -1
  80. package/dist/multi-agent/agent-event-bus.d.ts +10 -0
  81. package/dist/multi-agent/agent-event-bus.d.ts.map +1 -1
  82. package/dist/multi-agent/agent-event-bus.js +34 -0
  83. package/dist/multi-agent/agent-event-bus.js.map +1 -1
  84. package/dist/multi-agent/conductor-persona.js +2 -2
  85. package/dist/multi-agent/dashboard-agent-persona.d.ts +6 -2
  86. package/dist/multi-agent/dashboard-agent-persona.d.ts.map +1 -1
  87. package/dist/multi-agent/dashboard-agent-persona.js +53 -33
  88. package/dist/multi-agent/dashboard-agent-persona.js.map +1 -1
  89. package/dist/multi-agent/memory-agent-persona.d.ts +1 -1
  90. package/dist/multi-agent/memory-agent-persona.d.ts.map +1 -1
  91. package/dist/multi-agent/memory-agent-persona.js +25 -4
  92. package/dist/multi-agent/memory-agent-persona.js.map +1 -1
  93. package/dist/multi-agent/types.d.ts +1 -1
  94. package/dist/multi-agent/wiki-agent-persona.d.ts +7 -1
  95. package/dist/multi-agent/wiki-agent-persona.d.ts.map +1 -1
  96. package/dist/multi-agent/wiki-agent-persona.js +82 -68
  97. package/dist/multi-agent/wiki-agent-persona.js.map +1 -1
  98. package/dist/operator/board-slot-instructions.d.ts +18 -0
  99. package/dist/operator/board-slot-instructions.d.ts.map +1 -0
  100. package/dist/operator/board-slot-instructions.js +52 -0
  101. package/dist/operator/board-slot-instructions.js.map +1 -0
  102. package/dist/operator/connector-delta-repo.d.ts +33 -0
  103. package/dist/operator/connector-delta-repo.d.ts.map +1 -0
  104. package/dist/operator/connector-delta-repo.js +0 -0
  105. package/dist/operator/connector-delta-repo.js.map +1 -0
  106. package/dist/operator/mama-memory-port.d.ts +13 -0
  107. package/dist/operator/mama-memory-port.d.ts.map +1 -0
  108. package/dist/operator/mama-memory-port.js +35 -0
  109. package/dist/operator/mama-memory-port.js.map +1 -0
  110. package/dist/operator/operator-interfaces.d.ts +136 -0
  111. package/dist/operator/operator-interfaces.d.ts.map +1 -0
  112. package/dist/operator/operator-interfaces.js +15 -0
  113. package/dist/operator/operator-interfaces.js.map +1 -0
  114. package/dist/operator/operator-trigger-loop.d.ts +106 -0
  115. package/dist/operator/operator-trigger-loop.d.ts.map +1 -0
  116. package/dist/operator/operator-trigger-loop.js +228 -0
  117. package/dist/operator/operator-trigger-loop.js.map +1 -0
  118. package/dist/operator/report-run.d.ts +78 -0
  119. package/dist/operator/report-run.d.ts.map +1 -0
  120. package/dist/operator/report-run.js +141 -0
  121. package/dist/operator/report-run.js.map +1 -0
  122. package/dist/operator/report-scheduler.d.ts +43 -0
  123. package/dist/operator/report-scheduler.d.ts.map +1 -0
  124. package/dist/operator/report-scheduler.js +87 -0
  125. package/dist/operator/report-scheduler.js.map +1 -0
  126. package/dist/operator/situation-report.d.ts +86 -0
  127. package/dist/operator/situation-report.d.ts.map +1 -0
  128. package/dist/operator/situation-report.js +211 -0
  129. package/dist/operator/situation-report.js.map +1 -0
  130. package/dist/operator/trigger-author.d.ts +45 -0
  131. package/dist/operator/trigger-author.d.ts.map +1 -0
  132. package/dist/operator/trigger-author.js +217 -0
  133. package/dist/operator/trigger-author.js.map +1 -0
  134. package/dist/operator/trigger-evolve.d.ts +31 -0
  135. package/dist/operator/trigger-evolve.d.ts.map +1 -0
  136. package/dist/operator/trigger-evolve.js +51 -0
  137. package/dist/operator/trigger-evolve.js.map +1 -0
  138. package/dist/operator/trigger-fire.d.ts +29 -0
  139. package/dist/operator/trigger-fire.d.ts.map +1 -0
  140. package/dist/operator/trigger-fire.js +41 -0
  141. package/dist/operator/trigger-fire.js.map +1 -0
  142. package/dist/operator/trigger-matcher.d.ts +19 -0
  143. package/dist/operator/trigger-matcher.d.ts.map +1 -0
  144. package/dist/operator/trigger-matcher.js +61 -0
  145. package/dist/operator/trigger-matcher.js.map +1 -0
  146. package/dist/operator/trigger-registry.d.ts +36 -0
  147. package/dist/operator/trigger-registry.d.ts.map +1 -0
  148. package/dist/operator/trigger-registry.js +135 -0
  149. package/dist/operator/trigger-registry.js.map +1 -0
  150. package/dist/operator/trigger-review.d.ts +23 -0
  151. package/dist/operator/trigger-review.d.ts.map +1 -0
  152. package/dist/operator/trigger-review.js +127 -0
  153. package/dist/operator/trigger-review.js.map +1 -0
  154. package/dist/operator/trigger-types.d.ts +84 -0
  155. package/dist/operator/trigger-types.d.ts.map +1 -0
  156. package/dist/operator/trigger-types.js +14 -0
  157. package/dist/operator/trigger-types.js.map +1 -0
  158. package/dist/scheduler/cron-worker.d.ts.map +1 -1
  159. package/dist/scheduler/cron-worker.js +3 -1
  160. package/dist/scheduler/cron-worker.js.map +1 -1
  161. package/dist/security/security-monitor.d.ts.map +1 -1
  162. package/dist/security/security-monitor.js +1 -0
  163. package/dist/security/security-monitor.js.map +1 -1
  164. package/dist/wiki/obsidian-writer.d.ts +1 -1
  165. package/dist/wiki/obsidian-writer.d.ts.map +1 -1
  166. package/dist/wiki/obsidian-writer.js +67 -27
  167. package/dist/wiki/obsidian-writer.js.map +1 -1
  168. package/dist/wiki/path-safety.d.ts +2 -0
  169. package/dist/wiki/path-safety.d.ts.map +1 -0
  170. package/dist/wiki/path-safety.js +40 -0
  171. package/dist/wiki/path-safety.js.map +1 -0
  172. package/dist/wiki/types.d.ts +4 -2
  173. package/dist/wiki/types.d.ts.map +1 -1
  174. package/dist/wiki/types.js +1 -1
  175. package/dist/wiki/types.js.map +1 -1
  176. package/dist/wiki-artifacts/normalization.d.ts +8 -0
  177. package/dist/wiki-artifacts/normalization.d.ts.map +1 -0
  178. package/dist/wiki-artifacts/normalization.js +41 -0
  179. package/dist/wiki-artifacts/normalization.js.map +1 -0
  180. package/dist/wiki-artifacts/types.d.ts +52 -0
  181. package/dist/wiki-artifacts/types.d.ts.map +1 -0
  182. package/dist/wiki-artifacts/types.js +3 -0
  183. package/dist/wiki-artifacts/types.js.map +1 -0
  184. package/dist/wiki-artifacts/wiki-publish-adapter.d.ts +14 -0
  185. package/dist/wiki-artifacts/wiki-publish-adapter.d.ts.map +1 -0
  186. package/dist/wiki-artifacts/wiki-publish-adapter.js +71 -0
  187. package/dist/wiki-artifacts/wiki-publish-adapter.js.map +1 -0
  188. package/package.json +5 -3
  189. package/public/ui/assets/index-BDsaQNGd.js +62 -0
  190. package/public/ui/assets/index-C4URnm_X.css +1 -0
  191. package/public/ui/index.html +13 -0
  192. package/public/viewer/js/utils/api.js +2 -2
  193. package/public/viewer/src/utils/api.ts +9 -2
  194. package/public/viewer/sw.js +1 -1
  195. package/public/viewer/viewer.html +6 -0
@@ -85,6 +85,7 @@ const api_routes_init_js_1 = require("../runtime/api-routes-init.js");
85
85
  const server_start_js_1 = require("../runtime/server-start.js");
86
86
  const shutdown_js_1 = require("../runtime/shutdown.js");
87
87
  const envelope_bootstrap_js_1 = require("../runtime/envelope-bootstrap.js");
88
+ const message_router_config_js_1 = require("../runtime/message-router-config.js");
88
89
  const reactive_config_js_1 = require("../../envelope/reactive-config.js");
89
90
  const scope_context_js_1 = require("../../memory/scope-context.js");
90
91
  const types_js_1 = require("../config/types.js");
@@ -498,7 +499,10 @@ async function runAgentLoop(config, options = {}) {
498
499
  }
499
500
  const agentLoopBackend = runtimeBackend === 'codex' || runtimeBackend === 'codex-mcp' ? 'codex-mcp' : 'claude';
500
501
  // Initialize main agent loop + client (reasoning state is closure-scoped inside)
501
- const { agentLoop, agentLoopClient } = (0, agent_loop_init_js_1.initMainAgentLoop)(config, oauthManager, db, metricsStore, agentLoopBackend, { ...options, envelopeIssuanceMode: envelopeBootstrap.metadata.issuance });
502
+ const { agentLoop, agentLoopClient } = (0, agent_loop_init_js_1.initMainAgentLoop)(config, oauthManager, db, metricsStore, agentLoopBackend, {
503
+ ...options,
504
+ envelopeIssuanceMode: envelopeBootstrap.metadata.issuance,
505
+ });
502
506
  // ── Phase 3: MAMA Core API ────────────────────────────────────────────────
503
507
  const { mamaApi, mamaApiClient, connectorExtractionFn } = await (0, mama_core_init_js_1.initMamaCore)(config);
504
508
  // getAdapter is still used directly in this file for DB queries after initDB has run
@@ -510,9 +514,7 @@ async function runAgentLoop(config, options = {}) {
510
514
  toolExecutor.setContextCompileService(contextCompileService);
511
515
  agentLoop.setContextCompileService(contextCompileService);
512
516
  // ── Phase 4: Memory Agent + MessageRouter ─────────────────────────────────
513
- const messageRouter = new index_js_2.MessageRouter(sessionStore, agentLoopClient, mamaApiClient, {
514
- backend: runtimeBackend,
515
- }, envelopeBootstrap.envelopeConfig, envelopeBootstrap.envelopeAuthority);
517
+ const messageRouter = new index_js_2.MessageRouter(sessionStore, agentLoopClient, mamaApiClient, (0, message_router_config_js_1.resolveMessageRouterConfig)(config, runtimeBackend), envelopeBootstrap.envelopeConfig, envelopeBootstrap.envelopeAuthority);
516
518
  messageRouter.setSessionsDb(db);
517
519
  // validationService wired after creation (Phase 5 below)
518
520
  const { memoryAgentLoop } = await (0, memory_agent_init_js_1.initMemoryAgent)(oauthManager, config, mamaApi, mamaApiClient, messageRouter, agentLoopBackend);
@@ -537,134 +539,132 @@ async function runAgentLoop(config, options = {}) {
537
539
  agentLoop.setUICommandQueue(uiCommandQueue);
538
540
  // Wire up Code-Act executor for POST /api/code-act endpoint
539
541
  // Always register: Dashboard/Wiki agents use code-act via MCP → HTTP proxy
540
- {
541
- graphHandlerOptions.executeCodeAct = async (code, codeActContext) => {
542
- const { CodeActSandbox, HostBridge } = await import('../../agent/code-act/index.js');
543
- const sandbox = new CodeActSandbox();
544
- const resolvedCodeActPolicy = resolveCodeActAgentPolicy(codeActContext, config.multi_agent?.agents, config.multi_agent?.default_agent || 'conductor');
545
- if (resolvedCodeActPolicy.error) {
546
- return { success: false, error: resolvedCodeActPolicy.error };
547
- }
548
- const codeActAgentId = resolvedCodeActPolicy.agentId;
549
- const codeActPolicy = resolvedCodeActPolicy.policy ?? {};
550
- const codeActRole = buildCodeActRole(codeActPolicy);
551
- const codeActReadOnly = isTruthyEnvValue(process.env.MAMA_CODE_ACT_READ_ONLY);
552
- const codeActTier = codeActReadOnly ? 3 : 2;
553
- const instanceId = (0, node_crypto_1.randomUUID)();
554
- let executionContext = null;
555
- if (envelopeBootstrap.envelopeAuthority && envelopeBootstrap.metadata.issuance !== 'off') {
556
- const projectId = (0, reactive_config_js_1.resolveReactiveProjectRoot)(config, process.env);
557
- const projectRef = { kind: 'project', id: projectId };
558
- const memoryScopes = resolveCodeActMemoryScopes((0, scope_context_js_1.deriveMemoryScopes)({
559
- source: 'watch',
560
- channelId: 'api:code-act',
561
- userId: 'api',
562
- projectId,
563
- }), getAdapter());
564
- const wallSeconds = Math.min(Math.max(Math.floor((config.timeouts?.agent_ms ?? 300_000) / 1000), 1), 300);
565
- const envelope = envelopeBootstrap.envelopeAuthority.buildAndPersist({
566
- agent_id: codeActAgentId,
567
- instance_id: instanceId,
568
- source: 'watch',
569
- channel_id: 'api:code-act',
570
- trigger_context: { user_text: '<api-code-act invocation>' },
571
- scope: {
572
- project_refs: [projectRef],
573
- raw_connectors: codeActRawConnectors,
574
- memory_scopes: memoryScopes,
575
- allowed_destinations: [],
576
- },
577
- tier: codeActTier,
578
- budget: { wall_seconds: wallSeconds },
579
- expires_at: new Date(Date.now() + wallSeconds * 1000 + 30_000).toISOString(),
580
- });
581
- const roleName = `code_act_${codeActAgentId}`;
582
- const role = codeActRole;
583
- const agentContext = {
584
- source: 'watch',
585
- platform: 'cli',
586
- roleName,
587
- role,
588
- session: {
589
- sessionId: `api:code-act:${instanceId}`,
590
- channelId: 'api:code-act',
591
- startedAt: new Date(),
592
- },
593
- capabilities: ['code_act'],
594
- limitations: codeActReadOnly ? ['Code-Act read-only mode: memory writes disabled'] : [],
595
- tier: codeActTier,
596
- backend: 'claude',
597
- };
598
- executionContext = {
599
- agentContext,
600
- agentId: codeActAgentId,
601
- source: 'watch',
602
- channelId: 'api:code-act',
603
- envelope,
604
- executionSurface: 'code_act',
605
- };
606
- }
607
- const parentRun = bindCodeActParentModelRun(getAdapter(), executionContext, {
608
- inputSnapshotRef: `code-act:${instanceId}`,
609
- inputRefs: {
610
- tool: 'code_act',
611
- source: 'api',
612
- channel_id: 'api:code-act',
613
- read_only: codeActReadOnly,
542
+ graphHandlerOptions.executeCodeAct = async (code, codeActContext) => {
543
+ const { CodeActSandbox, HostBridge } = await import('../../agent/code-act/index.js');
544
+ const sandbox = new CodeActSandbox();
545
+ const resolvedCodeActPolicy = resolveCodeActAgentPolicy(codeActContext, config.multi_agent?.agents, config.multi_agent?.default_agent || 'conductor');
546
+ if (resolvedCodeActPolicy.error) {
547
+ return { success: false, error: resolvedCodeActPolicy.error };
548
+ }
549
+ const codeActAgentId = resolvedCodeActPolicy.agentId;
550
+ const codeActPolicy = resolvedCodeActPolicy.policy ?? {};
551
+ const codeActRole = buildCodeActRole(codeActPolicy);
552
+ const codeActReadOnly = isTruthyEnvValue(process.env.MAMA_CODE_ACT_READ_ONLY);
553
+ const codeActTier = codeActReadOnly ? 3 : 2;
554
+ const instanceId = (0, node_crypto_1.randomUUID)();
555
+ let executionContext = null;
556
+ if (envelopeBootstrap.envelopeAuthority && envelopeBootstrap.metadata.issuance !== 'off') {
557
+ const projectId = (0, reactive_config_js_1.resolveReactiveProjectRoot)(config, process.env);
558
+ const projectRef = { kind: 'project', id: projectId };
559
+ const memoryScopes = resolveCodeActMemoryScopes((0, scope_context_js_1.deriveMemoryScopes)({
560
+ source: 'watch',
561
+ channelId: 'api:code-act',
562
+ userId: 'api',
563
+ projectId,
564
+ }), getAdapter());
565
+ const wallSeconds = Math.min(Math.max(Math.floor((config.timeouts?.agent_ms ?? 300_000) / 1000), 1), 300);
566
+ const envelope = envelopeBootstrap.envelopeAuthority.buildAndPersist({
567
+ agent_id: codeActAgentId,
568
+ instance_id: instanceId,
569
+ source: 'watch',
570
+ channel_id: 'api:code-act',
571
+ trigger_context: { user_text: '<api-code-act invocation>' },
572
+ scope: {
573
+ project_refs: [projectRef],
574
+ raw_connectors: codeActRawConnectors,
575
+ memory_scopes: memoryScopes,
576
+ allowed_destinations: [],
614
577
  },
578
+ tier: codeActTier,
579
+ budget: { wall_seconds: wallSeconds },
580
+ expires_at: new Date(Date.now() + wallSeconds * 1000 + 30_000).toISOString(),
615
581
  });
616
- executionContext = parentRun.executionContext;
617
- const bridge = new HostBridge(toolExecutor, new role_manager_js_1.RoleManager({ rolesConfig: config.roles ?? types_js_1.DEFAULT_ROLES }), executionContext);
618
- const toolCalls = [];
619
- bridge.onToolUse = (toolName, input, result) => {
620
- if (result !== undefined) {
621
- toolCalls.push({ name: toolName, input });
622
- if (CODE_ACT_MUTATION_TOOLS.has(toolName)) {
623
- codeActLogger.warn('[CodeAct] mutation tool call', {
624
- toolName,
625
- success: Boolean(result.success),
626
- readOnly: codeActReadOnly,
627
- envelopeHash: executionContext?.envelope?.envelope_hash ?? null,
628
- });
629
- }
630
- }
582
+ const roleName = `code_act_${codeActAgentId}`;
583
+ const role = codeActRole;
584
+ const agentContext = {
585
+ source: 'watch',
586
+ platform: 'cli',
587
+ roleName,
588
+ role,
589
+ session: {
590
+ sessionId: `api:code-act:${instanceId}`,
591
+ channelId: 'api:code-act',
592
+ startedAt: new Date(),
593
+ },
594
+ capabilities: ['code_act'],
595
+ limitations: codeActReadOnly ? ['Code-Act read-only mode: memory writes disabled'] : [],
596
+ tier: codeActTier,
597
+ backend: runtimeBackend,
631
598
  };
632
- const previousRoutingContext = toolExecutor.getCurrentAgentRoutingContext();
633
- try {
634
- // Set default agent context for /api/code-act calls (Conductor, tiered sandbox).
635
- // Per-request executionContext carries envelope data; this routing context is legacy fallback.
636
- toolExecutor.setCurrentAgentContext(codeActAgentId, 'api', 'code-act');
637
- bridge.injectInto(sandbox, codeActTier, codeActRole);
638
- const result = await sandbox.execute(code);
639
- finalizeCodeActParentModelRun(getAdapter(), parentRun.modelRunId, result);
640
- return {
641
- success: result.success,
642
- value: result.value,
643
- logs: result.logs,
644
- error: result.error?.message,
645
- metrics: result.metrics,
646
- toolCalls,
647
- };
648
- }
649
- catch (error) {
650
- failCodeActParentModelRun(getAdapter(), parentRun.modelRunId, error);
651
- throw error;
652
- }
653
- finally {
654
- toolExecutor.restoreCurrentAgentRoutingContext(previousRoutingContext);
599
+ executionContext = {
600
+ agentContext,
601
+ agentId: codeActAgentId,
602
+ source: 'watch',
603
+ channelId: 'api:code-act',
604
+ envelope,
605
+ executionSurface: 'code_act',
606
+ };
607
+ }
608
+ const parentRun = bindCodeActParentModelRun(getAdapter(), executionContext, {
609
+ inputSnapshotRef: `code-act:${instanceId}`,
610
+ inputRefs: {
611
+ tool: 'code_act',
612
+ source: 'api',
613
+ channel_id: 'api:code-act',
614
+ read_only: codeActReadOnly,
615
+ },
616
+ });
617
+ executionContext = parentRun.executionContext;
618
+ const bridge = new HostBridge(toolExecutor, new role_manager_js_1.RoleManager({ rolesConfig: config.roles ?? types_js_1.DEFAULT_ROLES }), executionContext);
619
+ const toolCalls = [];
620
+ bridge.onToolUse = (toolName, input, result) => {
621
+ if (result !== undefined) {
622
+ toolCalls.push({ name: toolName, input });
623
+ if (CODE_ACT_MUTATION_TOOLS.has(toolName)) {
624
+ codeActLogger.warn('[CodeAct] mutation tool call', {
625
+ toolName,
626
+ success: Boolean(result.success),
627
+ readOnly: codeActReadOnly,
628
+ envelopeHash: executionContext?.envelope?.envelope_hash ?? null,
629
+ });
630
+ }
655
631
  }
656
632
  };
657
- // Pre-warm Code-Act WASM module for fast first execution
658
- (async () => {
659
- try {
660
- const { CodeActSandbox } = await import('../../agent/code-act/index.js');
661
- await CodeActSandbox.warmup();
662
- }
663
- catch (err) {
664
- console.warn('[CodeAct] WASM warmup failed (non-fatal):', err);
665
- }
666
- })();
667
- }
633
+ const previousRoutingContext = toolExecutor.getCurrentAgentRoutingContext();
634
+ try {
635
+ // Set default agent context for /api/code-act calls (Conductor, tiered sandbox).
636
+ // Per-request executionContext carries envelope data; this routing context is legacy fallback.
637
+ toolExecutor.setCurrentAgentContext(codeActAgentId, 'api', 'code-act');
638
+ bridge.injectInto(sandbox, codeActTier, codeActRole);
639
+ const result = await sandbox.execute(code);
640
+ finalizeCodeActParentModelRun(getAdapter(), parentRun.modelRunId, result);
641
+ return {
642
+ success: result.success,
643
+ value: result.value,
644
+ logs: result.logs,
645
+ error: result.error?.message,
646
+ metrics: result.metrics,
647
+ toolCalls,
648
+ };
649
+ }
650
+ catch (error) {
651
+ failCodeActParentModelRun(getAdapter(), parentRun.modelRunId, error);
652
+ throw error;
653
+ }
654
+ finally {
655
+ toolExecutor.restoreCurrentAgentRoutingContext(previousRoutingContext);
656
+ }
657
+ };
658
+ // Pre-warm Code-Act WASM module for fast first execution
659
+ (async () => {
660
+ try {
661
+ const { CodeActSandbox } = await import('../../agent/code-act/index.js');
662
+ await CodeActSandbox.warmup();
663
+ }
664
+ catch (err) {
665
+ console.warn('[CodeAct] WASM warmup failed (non-fatal):', err);
666
+ }
667
+ })();
668
668
  const graphHandler = (0, graph_api_js_1.createGraphHandler)(graphHandlerOptions);
669
669
  // Seed initial agent versions from config (version 1 for new agents)
670
670
  // initAgentTables is idempotent (CREATE IF NOT EXISTS) — safe to call before apiServer
@@ -675,134 +675,83 @@ async function runAgentLoop(config, options = {}) {
675
675
  toolExecutor.setValidationService(validationService);
676
676
  messageRouter.setValidationService(validationService);
677
677
  agentLoop.setValidationService(validationService);
678
- {
679
- // Ensure OS system agents exist in config (memory agent may be missing in older configs)
680
- if (!config.multi_agent) {
681
- config.multi_agent = (0, config_manager_js_1.getDefaultMultiAgentConfig)();
682
- }
683
- if (!config.multi_agent.agents) {
684
- config.multi_agent.agents = {};
678
+ // Ensure current primary system agents exist in config. Legacy self-paced
679
+ // dashboard/wiki agents are opt-in and must not be backfilled here.
680
+ if (!config.multi_agent) {
681
+ config.multi_agent = (0, config_manager_js_1.getDefaultMultiAgentConfig)();
682
+ }
683
+ if (!config.multi_agent.agents) {
684
+ config.multi_agent.agents = {};
685
+ }
686
+ const osAgents = {
687
+ 'os-agent': {
688
+ name: 'OS Agent',
689
+ display_name: '🖥️ OS Agent',
690
+ trigger_prefix: '!os',
691
+ persona_file: '~/.mama/personas/os-agent.md',
692
+ tier: 1,
693
+ backend: runtimeBackend,
694
+ model: config.agent.model,
695
+ can_delegate: true,
696
+ enabled: true,
697
+ },
698
+ memory: {
699
+ name: 'Memory Agent',
700
+ display_name: '🧠 Memory',
701
+ trigger_prefix: '!memory',
702
+ persona_file: '~/.mama/personas/memory.md',
703
+ tier: 3,
704
+ backend: runtimeBackend,
705
+ model: config.agent.model,
706
+ can_delegate: false,
707
+ enabled: true,
708
+ },
709
+ };
710
+ let osAgentsAdded = false;
711
+ for (const [id, cfg] of Object.entries(osAgents)) {
712
+ if (!config.multi_agent.agents[id]) {
713
+ config.multi_agent.agents[id] = cfg;
714
+ osAgentsAdded = true;
685
715
  }
686
- const osAgents = {
687
- 'os-agent': {
688
- name: 'OS Agent',
689
- display_name: '🖥️ OS Agent',
690
- trigger_prefix: '!os',
691
- persona_file: '~/.mama/personas/os-agent.md',
692
- tier: 1,
693
- backend: runtimeBackend,
694
- model: config.agent.model,
695
- can_delegate: true,
696
- enabled: true,
697
- },
698
- memory: {
699
- name: 'Memory Agent',
700
- display_name: '🧠 Memory',
701
- trigger_prefix: '!memory',
702
- persona_file: '~/.mama/personas/memory.md',
703
- tier: 3,
704
- backend: runtimeBackend,
705
- model: config.agent.model,
706
- can_delegate: false,
707
- enabled: true,
708
- },
709
- 'dashboard-agent': {
710
- name: 'Dashboard Agent',
711
- display_name: '📊 Dashboard',
712
- trigger_prefix: '!dashboard',
713
- persona_file: '~/.mama/personas/dashboard.md',
714
- tier: 2,
715
- backend: runtimeBackend,
716
- model: config.agent.model,
717
- can_delegate: false,
718
- enabled: true,
719
- useCodeAct: true,
720
- tool_permissions: {
721
- allowed: ['Read', 'Grep', 'Glob', 'code_act'],
722
- blocked: ['Bash', 'Write', 'Edit', 'Agent', 'WebSearch', 'WebFetch'],
723
- },
724
- gateway_tool_permissions: {
725
- allowed: ['mama_search', 'context_compile', 'agent_notices', 'report_publish'],
726
- blocked: [],
727
- },
728
- },
729
- };
730
- const wikiConfig = config.wiki;
731
- if (wikiConfig?.enabled) {
732
- osAgents['wiki-agent'] = {
733
- name: 'Wiki Agent',
734
- display_name: '📚 Wiki',
735
- trigger_prefix: '!wiki',
736
- persona_file: '~/.mama/personas/wiki.md',
737
- tier: 2,
738
- backend: runtimeBackend,
739
- model: config.agent.model,
740
- can_delegate: false,
741
- enabled: true,
742
- useCodeAct: true,
743
- tool_permissions: {
744
- allowed: ['Read', 'Grep', 'Glob', 'code_act'],
745
- blocked: ['Bash', 'Write', 'Edit', 'Agent', 'WebSearch', 'WebFetch'],
746
- },
747
- gateway_tool_permissions: {
748
- allowed: [
749
- 'mama_search',
750
- 'context_compile',
751
- 'agent_notices',
752
- 'case_list',
753
- 'case_assemble',
754
- 'obsidian',
755
- 'wiki_publish',
756
- ],
757
- blocked: [],
758
- },
759
- };
716
+ }
717
+ // Persist to config.yaml so /api/agents sees them too
718
+ if (osAgentsAdded) {
719
+ try {
720
+ const { saveConfig } = await import('../config/config-manager.js');
721
+ await saveConfig(config);
722
+ console.log('✓ OS agents added to config.yaml');
760
723
  }
761
- let osAgentsAdded = false;
762
- for (const [id, cfg] of Object.entries(osAgents)) {
763
- if (!config.multi_agent.agents[id]) {
764
- config.multi_agent.agents[id] = cfg;
765
- osAgentsAdded = true;
766
- }
724
+ catch {
725
+ /* non-fatal runtime config still has them */
767
726
  }
768
- // Persist to config.yaml so /api/agents sees them too
769
- if (osAgentsAdded) {
727
+ }
728
+ const agents = config.multi_agent.agents;
729
+ for (const [id, cfg] of Object.entries(agents)) {
730
+ if (!(0, agent_store_js_1.getLatestVersion)(db, id)) {
731
+ let personaText = null;
770
732
  try {
771
- const { saveConfig } = await import('../config/config-manager.js');
772
- await saveConfig(config);
773
- console.log('✓ OS agents added to config.yaml');
733
+ const pPath = (0, config_manager_js_1.expandPath)(cfg.persona_file);
734
+ if ((0, node_fs_1.existsSync)(pPath))
735
+ personaText = (0, node_fs_1.readFileSync)(pPath, 'utf-8');
774
736
  }
775
737
  catch {
776
- /* non-fatal — runtime config still has them */
777
- }
778
- }
779
- const agents = config.multi_agent.agents;
780
- for (const [id, cfg] of Object.entries(agents)) {
781
- if (!(0, agent_store_js_1.getLatestVersion)(db, id)) {
782
- let personaText = null;
783
- try {
784
- const pPath = (0, config_manager_js_1.expandPath)(cfg.persona_file);
785
- if ((0, node_fs_1.existsSync)(pPath))
786
- personaText = (0, node_fs_1.readFileSync)(pPath, 'utf-8');
787
- }
788
- catch {
789
- /* ignore */
790
- }
791
- (0, agent_store_js_1.createAgentVersion)(db, {
792
- agent_id: id,
793
- snapshot: { model: cfg.model, tier: cfg.tier, backend: cfg.backend },
794
- persona_text: personaText,
795
- change_note: 'Initial version (migrated from config.yaml)',
796
- });
738
+ /* ignore */
797
739
  }
740
+ (0, agent_store_js_1.createAgentVersion)(db, {
741
+ agent_id: id,
742
+ snapshot: { model: cfg.model, tier: cfg.tier, backend: cfg.backend },
743
+ persona_text: personaText,
744
+ change_note: 'Initial version (migrated from config.yaml)',
745
+ });
798
746
  }
799
- console.log(`✓ Agent versions seeded (${Object.keys(agents).length} agents)`);
800
747
  }
748
+ console.log(`✓ Agent versions seeded (${Object.keys(agents).length} agents)`);
801
749
  await (0, utilities_js_1.startEmbeddingServerIfAvailable)(messageRouter, sessionStore, graphHandler);
802
750
  // ── Phase 6: Cron Scheduler ───────────────────────────────────────────────
803
751
  const { scheduler, cronWorker, cronEmitter } = (0, scheduler_init_js_1.initCronScheduler)(config);
804
752
  // ── Phase 7: Gateways ────────────────────────────────────────────────────
805
- const { discordGateway, slackGateway, telegramGateway, gateways } = await (0, gateway_init_js_1.initGateways)(config, messageRouter, toolExecutor, agentLoop, runtimeBackend, db);
753
+ const gatewayInit = await (0, gateway_init_js_1.initGateways)(config, messageRouter, toolExecutor, agentLoop, runtimeBackend, db);
754
+ const { discordGateway, slackGateway, telegramGateway, gateways } = gatewayInit;
806
755
  // ── Phase 8: Gateway Wiring ──────────────────────────────────────────────
807
756
  const { pluginLoader } = await (0, gateway_wiring_js_1.wireGateways)({
808
757
  config,
@@ -829,11 +778,14 @@ async function runAgentLoop(config, options = {}) {
829
778
  // If no Discord/Slack handler wired the delegate tool, create standalone
830
779
  // DelegationManager + AgentProcessManager so delegate() works from any path
831
780
  // (Viewer, Telegram, iMessage, Terminal).
832
- const hasSystemRunAgents = Boolean(config.multi_agent?.agents?.['dashboard-agent'] || config.multi_agent?.agents?.['wiki-agent']);
833
- if (!toolExecutor.getAgentProcessManager() &&
834
- (config.multi_agent?.enabled || hasSystemRunAgents)) {
781
+ const fallbackMultiAgentConfig = config.multi_agent;
782
+ const hasSystemRunAgents = Boolean(fallbackMultiAgentConfig?.agents?.['dashboard-agent'] ||
783
+ fallbackMultiAgentConfig?.agents?.['wiki-agent']);
784
+ if (fallbackMultiAgentConfig &&
785
+ !toolExecutor.getAgentProcessManager() &&
786
+ (fallbackMultiAgentConfig.enabled || hasSystemRunAgents)) {
835
787
  const { AgentProcessManager } = await import('../../multi-agent/agent-process-manager.js');
836
- const pm = new AgentProcessManager(config.multi_agent, buildSystemAgentProcessDefaults(config), {
788
+ const pm = new AgentProcessManager(fallbackMultiAgentConfig, buildSystemAgentProcessDefaults(config), {
837
789
  backend: runtimeBackend,
838
790
  model: config.agent.model,
839
791
  });
@@ -850,9 +802,9 @@ async function runAgentLoop(config, options = {}) {
850
802
  toolExecutor.setRestartMultiAgentAgent(graphHandlerOptions.restartMultiAgentAgent);
851
803
  agentLoop.setApplyMultiAgentConfig(graphHandlerOptions.applyMultiAgentConfig);
852
804
  agentLoop.setRestartMultiAgentAgent(graphHandlerOptions.restartMultiAgentAgent);
853
- if (config.multi_agent?.enabled && !toolExecutor.hasDelegateSupport()) {
805
+ if (fallbackMultiAgentConfig.enabled && !toolExecutor.hasDelegateSupport()) {
854
806
  const { DelegationManager } = await import('../../multi-agent/delegation-manager.js');
855
- const agentConfigs = Object.entries(config.multi_agent.agents || {}).map(([id, cfg]) => ({
807
+ const agentConfigs = Object.entries(fallbackMultiAgentConfig.agents || {}).map(([id, cfg]) => ({
856
808
  id,
857
809
  ...cfg,
858
810
  }));
@@ -875,7 +827,12 @@ async function runAgentLoop(config, options = {}) {
875
827
  }
876
828
  // ── Phase 9: Heartbeat + Connectors ──────────────────────────────────────
877
829
  const { heartbeatScheduler, tokenKeepAlive, healthWarningInterval } = (0, scheduler_init_js_1.initHeartbeat)(config, agentLoop, discordGateway, scheduler, healthCheckService);
878
- const { rawStoreForApi, enabledConnectorNames, connectorSchedulerStop } = await (0, connector_init_js_1.initConnectors)(connectorExtractionFn);
830
+ // M2.4 freshness: the connector sink nudges the trigger loop when a poll indexes new rows. The
831
+ // loop is constructed AFTER initConnectors (below), so hand initConnectors a stable forwarder now
832
+ // and point it at the loop once it exists. Null until then -> nudge no-ops (no loop = nothing to
833
+ // wake), which preserves today's behavior when MAMA_TRIGGER_LOOP is unset.
834
+ const triggerLoopNudge = { current: null };
835
+ const { rawStoreForApi, enabledConnectorNames, connectorSchedulerStop } = await (0, connector_init_js_1.initConnectors)(connectorExtractionFn, { nudge: () => triggerLoopNudge.current?.() });
879
836
  codeActRawConnectors = resolveCodeActRawConnectors(enabledConnectorNames);
880
837
  // Inject rawStore into tool executor for agent_test connector data access
881
838
  if (rawStoreForApi) {
@@ -886,6 +843,151 @@ async function runAgentLoop(config, options = {}) {
886
843
  if (connectorSchedulerStop) {
887
844
  gateways.push({ stop: () => Promise.resolve(connectorSchedulerStop()) });
888
845
  }
846
+ // ── Trigger loop (M1, flag-gated, additive): agent-evolved triggers on the live stream ──
847
+ // Runs ONLY with MAMA_TRIGGER_LOOP=1. Placed after initConnectors (which feeds
848
+ // connector_event_index) and after mama-core initDB. Read-only: recall/surface/log.
849
+ if (process.env.MAMA_TRIGGER_LOOP === '1') {
850
+ // Component isolation (PR #119 review): a trigger-loop bootstrap failure (bad import,
851
+ // DB permission, registry constructor) must not abort the whole daemon before Phase
852
+ // 10/11 - the gateways/viewer/agent serve independently of this optional leg. The
853
+ // failure is still surfaced LOUDLY below (console.error), never swallowed silently.
854
+ try {
855
+ const { OperatorTriggerLoop } = await import('../../operator/operator-trigger-loop.js');
856
+ const { ConnectorDeltaRepo } = await import('../../operator/connector-delta-repo.js');
857
+ const { TriggerRegistry } = await import('../../operator/trigger-registry.js');
858
+ const { createMamaMemoryPort } = await import('../../operator/mama-memory-port.js');
859
+ const { askAgentCLI } = await import('../../operator/trigger-author.js');
860
+ const { reviewTriggerCLI } = await import('../../operator/trigger-review.js');
861
+ const { mkdirSync } = await import('node:fs');
862
+ const { dirname } = await import('node:path');
863
+ const { ReportScheduler, FileReportScheduleStore, parseReportHours } = await import('../../operator/report-scheduler.js');
864
+ const { createPersonaReportAsk, OPERATOR_REPORT_SESSION_KEY } = await import('../../operator/report-run.js');
865
+ const { OPERATOR_FULL_REPORT_TAG } = await import('../../operator/situation-report.js');
866
+ const { buildBoardPublishLines } = await import('../../operator/board-slot-instructions.js');
867
+ const triggerDbPath = (0, config_manager_js_1.expandPath)('~/.mama/operator/triggers.db');
868
+ mkdirSync(dirname(triggerDbPath), { recursive: true });
869
+ const triggerRegistry = new TriggerRegistry(new sqlite_js_1.default(triggerDbPath));
870
+ // Owner-report leg (M1.5): destination chat comes from env (~/.mama/start.sh),
871
+ // never source. No chat configured or no telegram gateway -> loop stays read-only.
872
+ const reportChatId = process.env.MAMA_TRIGGER_LOOP_REPORT_CHAT || '';
873
+ const reportOutput = reportChatId && telegramGateway
874
+ ? { send: (text) => telegramGateway.sendMessage(reportChatId, text) }
875
+ : undefined;
876
+ // Scheduled full-report leg (M2): local hours from env (~/.mama/start.sh), never source.
877
+ // Empty/absent -> [] -> leg off. Requires the same telegram sink as the digest leg.
878
+ const fullReportHours = parseReportHours(process.env.MAMA_TRIGGER_LOOP_FULL_REPORT_HOURS || '');
879
+ const reportScheduler = fullReportHours.length > 0 && reportOutput
880
+ ? new ReportScheduler(fullReportHours, new FileReportScheduleStore((0, config_manager_js_1.expandPath)('~/.mama/operator/report-schedule-state.json')))
881
+ : undefined;
882
+ const triggerLoop = new OperatorTriggerLoop({
883
+ delta: new ConnectorDeltaRepo(getAdapter(), (0, config_manager_js_1.expandPath)('~/.mama/operator/trigger-loop-cursors.json')),
884
+ memory: createMamaMemoryPort(),
885
+ registry: triggerRegistry,
886
+ askAgent: askAgentCLI,
887
+ // M2.2: reports go through the daemon's persona agent (system prompt, pinned model,
888
+ // session lanes) instead of the bare CLI - report tone comes from generation inputs.
889
+ // JSON tasks (authoring/review) stay on the bare CLI for reliable parsing.
890
+ // M3 (GAP1+GAP2): run reports in a dedicated persona session lane so the multi-turn gather
891
+ // loop is isolated from chat and continuous across cadences (runWithContent honors
892
+ // options.sessionKey - agent-loop.ts:879, no agent-loop internal change). Gateway
893
+ // 'model_tool' executions are envelope-gated (gateway-tool-executor.ts:252-256) and
894
+ // issuance defaults to 'enabled' (envelope-bootstrap.ts:28-30), so each report carries a
895
+ // per-run scoped envelope (mirrors the code-act issuance at start.ts:1834-1865); without it
896
+ // every call is denied with code 'envelope_missing'. Then audit the gateway tools the agent
897
+ // actually EXECUTED: a full report that executed NO gateway gather tool is logged loudly
898
+ // (no-fallback), and every write (mama_save) is logged (observability).
899
+ reportAsk: createPersonaReportAsk({
900
+ issueEnvelope: envelopeBootstrap.envelopeAuthority && envelopeBootstrap.metadata.issuance !== 'off'
901
+ ? async () => {
902
+ const projectId = (0, reactive_config_js_1.resolveReactiveProjectRoot)(config, process.env);
903
+ const wallSeconds = Math.min(Math.max(Math.floor((config.timeouts?.agent_ms ?? 300_000) / 1000), 1), 300);
904
+ return envelopeBootstrap.envelopeAuthority.buildAndPersist({
905
+ agent_id: 'operator-report',
906
+ instance_id: (0, node_crypto_1.randomUUID)(),
907
+ // 'operator' is not a member of EnvelopeSource (envelope/types.ts is a closed
908
+ // union); 'watch' is the daemon-internal source used by the mirrored code-act
909
+ // issuance (start.ts:1834-1865). This field is issuing-source metadata only -
910
+ // enforcement authorizes on scope.memory_scopes (which cover the operator:report
911
+ // run below), never on envelope.source (gateway-tool-executor.ts:1421,1511,1590).
912
+ source: 'watch',
913
+ channel_id: 'report',
914
+ trigger_context: { user_text: '<operator scheduled report>' },
915
+ scope: {
916
+ // Reads: the enabled raw connectors (kagemusha_* gathers) + memory scopes
917
+ // covering mama_recall/mama_save. allowed_destinations stays [] - NO new
918
+ // send surface (constraint 2).
919
+ project_refs: [{ kind: 'project', id: projectId }],
920
+ raw_connectors: codeActRawConnectors,
921
+ memory_scopes: resolveCodeActMemoryScopes((0, scope_context_js_1.deriveMemoryScopes)({ source: 'operator', channelId: 'report', projectId }), getAdapter()),
922
+ allowed_destinations: [],
923
+ },
924
+ tier: 2, // write tier: the report may mama_save (matches code-act write tier)
925
+ budget: { wall_seconds: wallSeconds },
926
+ expires_at: new Date(Date.now() + wallSeconds * 1000 + 30_000).toISOString(),
927
+ });
928
+ }
929
+ : undefined,
930
+ run: async (prompt, envelope) => {
931
+ const result = await agentLoop.runWithContent([{ type: 'text', text: prompt }], {
932
+ sessionKey: OPERATOR_REPORT_SESSION_KEY,
933
+ source: 'operator',
934
+ channelId: 'report',
935
+ ...(envelope ? { envelope } : {}),
936
+ });
937
+ return { response: result.response, history: result.history };
938
+ },
939
+ log: (line) => console.log(line),
940
+ fullReportTag: OPERATOR_FULL_REPORT_TAG,
941
+ }),
942
+ review: (trigger, context) => reviewTriggerCLI(trigger, context),
943
+ output: reportOutput,
944
+ reportScheduler,
945
+ // M2.3: the scheduled full report self-gathers via the persona agent's gateway tools
946
+ // (the Kagemusha lesson: a reporter with tools has substance; a window summary alone
947
+ // reports "quiet" whenever polling is between batches).
948
+ fullReportSelfGather: [
949
+ 'kagemusha_overview() for room/task/message counts',
950
+ 'kagemusha_tasks({}) for the open task board, plus kagemusha_tasks({ status: "review" }) for items awaiting review (status values must be real board statuses like pending/in_progress/review - invented labels match nothing)',
951
+ 'kagemusha_entities({ activeOnly: true }) for active channels, then kagemusha_messages({ channelId }) on the busiest 2-3 (since defaults to the last 7 days; pass an ISO-8601 timestamp like since: "2026-07-09T00:00:00Z" to narrow it - never a phrase like "24h ago")',
952
+ 'mama_recall(query) for memory relevant to what you find',
953
+ ],
954
+ // Kagemusha dual output: the same scheduled run updates the /ui operator board
955
+ // slots via report_publish, then writes the plain-text owner report.
956
+ fullReportBoardLines: buildBoardPublishLines(),
957
+ config: {
958
+ tickMs: Number(process.env.MAMA_TRIGGER_LOOP_TICK_MS || 60_000),
959
+ drainLimit: Number(process.env.MAMA_TRIGGER_LOOP_DRAIN_LIMIT || 200),
960
+ authorEveryNTicks: Number(process.env.MAMA_TRIGGER_LOOP_AUTHOR_EVERY || 30),
961
+ reviewEveryNTicks: Number(process.env.MAMA_TRIGGER_LOOP_REVIEW_EVERY || 240),
962
+ authorWindowSize: 50,
963
+ reportEveryNTicks: Number(process.env.MAMA_TRIGGER_LOOP_REPORT_EVERY || 15),
964
+ nudgeDebounceMs: Number(process.env.MAMA_TRIGGER_LOOP_NUDGE_DEBOUNCE_MS || 15_000),
965
+ },
966
+ log: (line) => console.log(line),
967
+ });
968
+ if (reportOutput) {
969
+ console.log('✓ Trigger loop owner-report leg enabled (telegram)');
970
+ }
971
+ if (reportScheduler) {
972
+ console.log(`✓ Trigger loop scheduled full-report leg enabled (local hours: ${fullReportHours.join(', ')})`);
973
+ }
974
+ const stopTriggerLoop = triggerLoop.start();
975
+ // M2.4: point the connector sink's forwarder at this loop now that it exists.
976
+ triggerLoopNudge.current = () => triggerLoop.nudge();
977
+ gateways.push({
978
+ stop: async () => {
979
+ triggerLoopNudge.current = null;
980
+ stopTriggerLoop();
981
+ // Close the operator triggers.db handle (PR #119 review: was leaked on shutdown).
982
+ triggerRegistry.close();
983
+ },
984
+ });
985
+ console.log('✓ Trigger loop enabled (MAMA_TRIGGER_LOOP=1, read-only surface mode)');
986
+ }
987
+ catch (error) {
988
+ console.error('[trigger-loop] FAILED to start - daemon continues WITHOUT the trigger loop. Fix and restart:', error);
989
+ }
990
+ }
889
991
  // ── Phase 10: API Server + Routes ────────────────────────────────────────
890
992
  const { apiServer, eventBus } = await (0, api_server_init_js_1.initApiServer)({
891
993
  config,