@jungjaehoon/mama-os 0.36.1 → 0.37.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 (104) hide show
  1. package/dist/agent/agent-loop.d.ts.map +1 -1
  2. package/dist/agent/agent-loop.js +17 -12
  3. package/dist/agent/agent-loop.js.map +1 -1
  4. package/dist/agent/code-act/host-bridge.d.ts.map +1 -1
  5. package/dist/agent/code-act/host-bridge.js +2 -0
  6. package/dist/agent/code-act/host-bridge.js.map +1 -1
  7. package/dist/agent/drive-tools.d.ts +27 -1
  8. package/dist/agent/drive-tools.d.ts.map +1 -1
  9. package/dist/agent/drive-tools.js +68 -2
  10. package/dist/agent/drive-tools.js.map +1 -1
  11. package/dist/agent/gateway-tool-executor.d.ts +6 -2
  12. package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
  13. package/dist/agent/gateway-tool-executor.js +144 -17
  14. package/dist/agent/gateway-tool-executor.js.map +1 -1
  15. package/dist/agent/gateway-tools.md +2 -2
  16. package/dist/agent/tool-registry.js +2 -2
  17. package/dist/agent/tool-registry.js.map +1 -1
  18. package/dist/agent/types.d.ts +15 -0
  19. package/dist/agent/types.d.ts.map +1 -1
  20. package/dist/agent/types.js.map +1 -1
  21. package/dist/cli/commands/start.d.ts +1 -20
  22. package/dist/cli/commands/start.d.ts.map +1 -1
  23. package/dist/cli/commands/start.js +142 -205
  24. package/dist/cli/commands/start.js.map +1 -1
  25. package/dist/cli/config/types.d.ts +0 -21
  26. package/dist/cli/config/types.d.ts.map +1 -1
  27. package/dist/cli/config/types.js +0 -7
  28. package/dist/cli/config/types.js.map +1 -1
  29. package/dist/cli/runtime/agent-loop-init.d.ts +2 -2
  30. package/dist/cli/runtime/agent-loop-init.d.ts.map +1 -1
  31. package/dist/cli/runtime/agent-loop-init.js +3 -3
  32. package/dist/cli/runtime/agent-loop-init.js.map +1 -1
  33. package/dist/cli/runtime/api-routes-init.d.ts.map +1 -1
  34. package/dist/cli/runtime/api-routes-init.js +7 -21
  35. package/dist/cli/runtime/api-routes-init.js.map +1 -1
  36. package/dist/gateways/message-router.js +10 -10
  37. package/dist/gateways/message-router.js.map +1 -1
  38. package/dist/gateways/telegram.d.ts +2 -2
  39. package/dist/gateways/telegram.d.ts.map +1 -1
  40. package/dist/gateways/telegram.js +13 -7
  41. package/dist/gateways/telegram.js.map +1 -1
  42. package/dist/multi-agent/agent-event-bus.d.ts +0 -5
  43. package/dist/multi-agent/agent-event-bus.d.ts.map +1 -1
  44. package/dist/multi-agent/agent-event-bus.js.map +1 -1
  45. package/dist/operator/operator-trigger-loop.d.ts +7 -22
  46. package/dist/operator/operator-trigger-loop.d.ts.map +1 -1
  47. package/dist/operator/operator-trigger-loop.js +33 -34
  48. package/dist/operator/operator-trigger-loop.js.map +1 -1
  49. package/dist/operator/owner-event-effects.d.ts +34 -0
  50. package/dist/operator/owner-event-effects.d.ts.map +1 -0
  51. package/dist/operator/owner-event-effects.js +131 -0
  52. package/dist/operator/owner-event-effects.js.map +1 -0
  53. package/dist/operator/{conductor-inbox.d.ts → owner-event-inbox.d.ts} +23 -12
  54. package/dist/operator/owner-event-inbox.d.ts.map +1 -0
  55. package/dist/operator/{conductor-inbox.js → owner-event-inbox.js} +97 -40
  56. package/dist/operator/owner-event-inbox.js.map +1 -0
  57. package/dist/operator/owner-event-loop.d.ts +59 -0
  58. package/dist/operator/owner-event-loop.d.ts.map +1 -0
  59. package/dist/operator/owner-event-loop.js +141 -0
  60. package/dist/operator/owner-event-loop.js.map +1 -0
  61. package/dist/operator/owner-event-outcome.d.ts +30 -0
  62. package/dist/operator/owner-event-outcome.d.ts.map +1 -0
  63. package/dist/operator/owner-event-outcome.js +108 -0
  64. package/dist/operator/owner-event-outcome.js.map +1 -0
  65. package/dist/operator/owner-event-policy.d.ts +20 -0
  66. package/dist/operator/owner-event-policy.d.ts.map +1 -0
  67. package/dist/operator/owner-event-policy.js +50 -0
  68. package/dist/operator/owner-event-policy.js.map +1 -0
  69. package/dist/operator/owner-event-prompt.d.ts +10 -0
  70. package/dist/operator/owner-event-prompt.d.ts.map +1 -0
  71. package/dist/operator/owner-event-prompt.js +63 -0
  72. package/dist/operator/owner-event-prompt.js.map +1 -0
  73. package/dist/operator/task-ledger.d.ts +2 -0
  74. package/dist/operator/task-ledger.d.ts.map +1 -1
  75. package/dist/operator/task-ledger.js +12 -1
  76. package/dist/operator/task-ledger.js.map +1 -1
  77. package/dist/operator/trigger-matcher.d.ts.map +1 -1
  78. package/dist/operator/trigger-matcher.js +4 -1
  79. package/dist/operator/trigger-matcher.js.map +1 -1
  80. package/dist/operator/trigger-registry.d.ts +1 -1
  81. package/dist/operator/trigger-registry.d.ts.map +1 -1
  82. package/dist/operator/trigger-registry.js +2 -2
  83. package/dist/operator/trigger-registry.js.map +1 -1
  84. package/dist/operator/trigger-types.d.ts +2 -0
  85. package/dist/operator/trigger-types.d.ts.map +1 -1
  86. package/dist/operator/workorder-publishers.d.ts +4 -4
  87. package/dist/operator/workorder-publishers.d.ts.map +1 -1
  88. package/dist/operator/workorder-publishers.js +12 -5
  89. package/dist/operator/workorder-publishers.js.map +1 -1
  90. package/package.json +1 -1
  91. package/dist/operator/board-reground.d.ts +0 -19
  92. package/dist/operator/board-reground.d.ts.map +0 -1
  93. package/dist/operator/board-reground.js +0 -31
  94. package/dist/operator/board-reground.js.map +0 -1
  95. package/dist/operator/conductor-inbox.d.ts.map +0 -1
  96. package/dist/operator/conductor-inbox.js.map +0 -1
  97. package/dist/operator/conductor-session.d.ts +0 -55
  98. package/dist/operator/conductor-session.d.ts.map +0 -1
  99. package/dist/operator/conductor-session.js +0 -110
  100. package/dist/operator/conductor-session.js.map +0 -1
  101. package/dist/operator/conductor.d.ts +0 -69
  102. package/dist/operator/conductor.d.ts.map +0 -1
  103. package/dist/operator/conductor.js +0 -90
  104. package/dist/operator/conductor.js.map +0 -1
@@ -45,11 +45,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
45
45
  return (mod && mod.__esModule) ? mod : { "default": mod };
46
46
  };
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
- exports.CONDUCTOR_TOOL_POLICY = exports.OPERATOR_REPORT_TOOL_POLICY = exports.WORKORDER_TOOL_POLICIES = void 0;
48
+ exports.OPERATOR_REPORT_TOOL_POLICY = exports.WORKORDER_TOOL_POLICIES = void 0;
49
49
  exports.createCorePrincipalRegistry = createCorePrincipalRegistry;
50
50
  exports.createCorePrincipalResolver = createCorePrincipalResolver;
51
51
  exports.requireRuntimeBackend = requireRuntimeBackend;
52
- exports.assertConductorBackendSupported = assertConductorBackendSupported;
53
52
  exports.serializeCodeActExecutionResult = serializeCodeActExecutionResult;
54
53
  exports.deriveCodeActToolPolicy = deriveCodeActToolPolicy;
55
54
  exports.resolveCodeActAgentPolicy = resolveCodeActAgentPolicy;
@@ -58,8 +57,6 @@ exports.buildFullReportGatherLines = buildFullReportGatherLines;
58
57
  exports.causeEventIdsFromPayload = causeEventIdsFromPayload;
59
58
  exports.workOrderEnvelopeScope = workOrderEnvelopeScope;
60
59
  exports.temporalTaskBinding = temporalTaskBinding;
61
- exports.buildConductorAgentPolicy = buildConductorAgentPolicy;
62
- exports.resolveConductorConfig = resolveConductorConfig;
63
60
  exports.buildOperatorReportAgentPolicy = buildOperatorReportAgentPolicy;
64
61
  exports.buildWorkOrderAgentPolicy = buildWorkOrderAgentPolicy;
65
62
  exports.bindCodeActParentModelRun = bindCodeActParentModelRun;
@@ -77,6 +74,7 @@ const gateway_tool_executor_js_1 = require("../../agent/gateway-tool-executor.js
77
74
  const context_compile_service_js_1 = require("../../agent/context-compile-service.js");
78
75
  const read_js_1 = require("../../evidence/read.js");
79
76
  const tool_registry_js_1 = require("../../agent/tool-registry.js");
77
+ const prompt_enhancer_js_1 = require("../../agent/prompt-enhancer.js");
80
78
  const gateway_tool_catalog_js_1 = require("../../agent/gateway-tool-catalog.js");
81
79
  const tool_policy_js_1 = require("../../agent/code-act/tool-policy.js");
82
80
  const run_context_registry_js_1 = require("../../agent/code-act/run-context-registry.js");
@@ -125,12 +123,12 @@ const console_brief_js_1 = require("../../operator/console-brief.js");
125
123
  const task_ledger_js_1 = require("../../operator/task-ledger.js");
126
124
  const board_refresh_gate_js_1 = require("../../operator/board-refresh-gate.js");
127
125
  const workorder_publishers_js_1 = require("../../operator/workorder-publishers.js");
128
- const conductor_inbox_js_1 = require("../../operator/conductor-inbox.js");
129
- const conductor_session_js_1 = require("../../operator/conductor-session.js");
130
- const conductor_js_1 = require("../../operator/conductor.js");
131
- const board_reground_js_1 = require("../../operator/board-reground.js");
126
+ const owner_event_inbox_js_1 = require("../../operator/owner-event-inbox.js");
127
+ const owner_event_effects_js_1 = require("../../operator/owner-event-effects.js");
128
+ const owner_event_loop_js_1 = require("../../operator/owner-event-loop.js");
129
+ const owner_event_prompt_js_1 = require("../../operator/owner-event-prompt.js");
130
+ const owner_event_policy_js_1 = require("../../operator/owner-event-policy.js");
132
131
  const leg_cadence_js_1 = require("../../operator/leg-cadence.js");
133
- const session_pool_js_1 = require("../../agent/session-pool.js");
134
132
  const temporal_worker_js_1 = require("../../operator/temporal-worker.js");
135
133
  const temporal_runtime_js_1 = require("../../operator/temporal-runtime.js");
136
134
  const temporal_init_js_1 = require("../runtime/temporal-init.js");
@@ -161,11 +159,6 @@ function requireRuntimeBackend(value) {
161
159
  }
162
160
  throw new Error(`Unsupported agent backend: ${String(value)}`);
163
161
  }
164
- function assertConductorBackendSupported(enabled, backend) {
165
- if (enabled && backend === 'codex') {
166
- throw new Error('conductor.enabled requires the claude or cline backend - codex session lifecycle lands in S2');
167
- }
168
- }
169
162
  function serializeCodeActExecutionResult(result, toolCalls, hostToolExecutions = []) {
170
163
  const hostToolsInvoked = [
171
164
  ...new Set(hostToolExecutions.filter((execution) => execution.success).map((execution) => execution.name)),
@@ -544,87 +537,6 @@ function buildProjectedLanePrompt(innerTools, surface, privateConnectorPolicy) {
544
537
  privateConnectorPolicy,
545
538
  }).prompt;
546
539
  }
547
- /**
548
- * The conductor's grant (S1). Reads and judgment surfaces plus the ONE write
549
- * family the spec's center names: committing work orders and board cards. No
550
- * sends, no memory writes, no compile - the untrusted-input lane stays the
551
- * most restricted lane, not the least (review F2/security).
552
- */
553
- exports.CONDUCTOR_TOOL_POLICY = {
554
- roleName: 'conductor',
555
- allowedTools: [
556
- 'board_read',
557
- 'changes_read',
558
- 'mama_recall',
559
- 'mama_search',
560
- 'task_create',
561
- 'task_list',
562
- 'task_update',
563
- 'workorder_request',
564
- 'workorder_status',
565
- ],
566
- };
567
- /** Mirrors buildOperatorReportAgentPolicy - same shape, conductor grant. */
568
- function buildConductorAgentPolicy(model, backend, privateConnectorPolicy) {
569
- const blockedTools = [];
570
- const innerTools = uniqueToolList(exports.CONDUCTOR_TOOL_POLICY.allowedTools);
571
- const allowedTools = uniqueToolList([...innerTools]);
572
- const agentContext = {
573
- source: 'conductor',
574
- platform: 'cli',
575
- roleName: exports.CONDUCTOR_TOOL_POLICY.roleName,
576
- role: {
577
- allowedTools,
578
- blockedTools,
579
- allowedPaths: [],
580
- systemControl: false,
581
- sensitiveAccess: false,
582
- model,
583
- },
584
- session: {
585
- sessionId: 'conductor:main',
586
- channelId: 'conductor',
587
- startedAt: new Date(),
588
- },
589
- capabilities: allowedTools,
590
- limitations: blockedTools.map((tool) => `Cannot use ${tool}`),
591
- // Write tier: board cards and work orders only - matches the envelope.
592
- tier: 2,
593
- backend,
594
- };
595
- return {
596
- agentContext,
597
- gatewayToolsPrompt: (0, gateway_tool_catalog_js_1.buildGatewayToolCatalog)({
598
- surface: 'multi-agent-generic',
599
- allowedTools: innerTools,
600
- privateConnectorPolicy,
601
- }).prompt,
602
- briefProjectionPolicy: DISABLED_PRIVATE_CONNECTOR_POLICY,
603
- };
604
- }
605
- /**
606
- * Merge + validate the conductor config at boot. No-fallback: a malformed
607
- * value must crash loudly, not silently clamp (review F10: tickMs 0 spins
608
- * the event loop with a DB write per iteration).
609
- */
610
- function resolveConductorConfig(config) {
611
- const resolved = {
612
- ...types_js_1.DEFAULT_CONFIG.conductor,
613
- ...(config.conductor ?? {}),
614
- };
615
- const positive = [
616
- ['tickMs', resolved.tickMs, 1_000],
617
- ['maxAgeMs', resolved.maxAgeMs, 60_000],
618
- ['maxTurns', resolved.maxTurns, 1],
619
- ['maxTokens', resolved.maxTokens, 1_000],
620
- ];
621
- for (const [name, value, min] of positive) {
622
- if (!Number.isFinite(value) || value < min) {
623
- throw new Error(`conductor.${name} must be a number >= ${min}, got ${String(value)}`);
624
- }
625
- }
626
- return resolved;
627
- }
628
540
  /**
629
541
  * Build the Code-Act role the operator report lane runs under.
630
542
  *
@@ -757,7 +669,7 @@ function buildSystemAgentProcessDefaults(config) {
757
669
  };
758
670
  }
759
671
  const OWNER_BOARD_FULL_REPAIR_CHANNEL = 'host:owner-workorder:board-full';
760
- /** Build the enqueue-and-ack handler shared by direct owner and conductor requests. */
672
+ /** Build the enqueue-and-ack handler shared by owner chat and owner-event turns. */
761
673
  function buildOwnerWorkOrderRequestHandler(deps) {
762
674
  const now = deps.now ?? Date.now;
763
675
  const log = deps.log ?? ((line) => ownerWorkOrderLogger.info(line));
@@ -791,11 +703,20 @@ function buildOwnerWorkOrderRequestHandler(deps) {
791
703
  }
792
704
  }
793
705
  else if (kind === 'wiki') {
794
- idempotencyKey = (0, workorder_publishers_js_1.wikiBatchKey)('manual', requestedAt);
795
- payload = { batchId: `${requestedAt}-manual`, events: ['manual'] };
706
+ if (causeEventIds && causeEventIds.length > 0) {
707
+ idempotencyKey = (0, workorder_publishers_js_1.ownerEventWorkOrderKey)('wiki', causeEventIds);
708
+ payload = { batchId: idempotencyKey, events: [...causeEventIds] };
709
+ }
710
+ else {
711
+ idempotencyKey = (0, workorder_publishers_js_1.wikiBatchKey)('manual', requestedAt);
712
+ payload = { batchId: `${requestedAt}-manual`, events: ['manual'] };
713
+ }
796
714
  }
797
715
  else {
798
- idempotencyKey = (0, workorder_publishers_js_1.promotionManualKey)(requestedAt);
716
+ idempotencyKey =
717
+ causeEventIds && causeEventIds.length > 0
718
+ ? (0, workorder_publishers_js_1.ownerEventWorkOrderKey)('memory-curation', causeEventIds)
719
+ : (0, workorder_publishers_js_1.promotionManualKey)(requestedAt);
799
720
  payload = { scheduledAt: new Date(requestedAt).toISOString() };
800
721
  }
801
722
  (0, workorder_publishers_js_1.validateWorkOrderPayload)(kind, payload);
@@ -1359,12 +1280,6 @@ async function runAgentLoop(config, options = {}) {
1359
1280
  // and point it at the loop once it exists. Null until then -> nudge no-ops (no loop = nothing to
1360
1281
  // wake), which remains safe while the trigger loop is still booting or explicitly disabled.
1361
1282
  const triggerLoopNudge = { current: null };
1362
- // M8: board-reconcile feed. The trigger loop is built BEFORE the event bus
1363
- // exists (initApiServer), so it emits through this mutable sink (same
1364
- // pattern as triggerLoopNudge above).
1365
- const channelDeltaSink = {
1366
- current: null,
1367
- };
1368
1283
  // Operator DB + native task ledger (M8): wired UNCONDITIONALLY -- the task
1369
1284
  // tools are standard gateway tools and must work even when the trigger loop
1370
1285
  // is off (review finding on #142). Single handle, closed once at shutdown.
@@ -1384,11 +1299,12 @@ async function runAgentLoop(config, options = {}) {
1384
1299
  // One host-owned gate spans owner workorder requests, route scheduling,
1385
1300
  // delta ingestion, and completion verification for this boot.
1386
1301
  const boardRefreshGate = process.env.MAMA_BOARD_RECONCILE === '1' ? new board_refresh_gate_js_1.BoardRefreshGate() : null;
1387
- // S1: durable conductor inbox - constructed UNCONDITIONALLY so drained
1388
- // batches persist before the cursor commits even while the conductor is
1389
- // disabled (that accumulation IS the shadow-mode data; retention inside
1390
- // ConductorInbox keeps it bounded).
1391
- const conductorInbox = new conductor_inbox_js_1.ConductorInbox(operatorDb);
1302
+ // Durable MAMA owner-event journal. It uses new tables rather than replaying
1303
+ // the legacy default-off Conductor shadow backlog on cutover.
1304
+ const ownerEventInbox = new owner_event_inbox_js_1.OwnerEventInbox(operatorDb);
1305
+ const ownerEventEffectLedger = new owner_event_effects_js_1.OwnerEventEffectLedger(operatorDb);
1306
+ toolExecutor.setOwnerEventEffectLedger(ownerEventEffectLedger);
1307
+ let stopOwnerEventRuntime = null;
1392
1308
  // S2: leg cadence watchdog - its OWN timer, deliberately outside the
1393
1309
  // trigger loop (a watchdog inside the thing it watches dies with it).
1394
1310
  // Legs declare+beat at their own tick sites via the singleton; pages ride
@@ -1423,14 +1339,6 @@ async function runAgentLoop(config, options = {}) {
1423
1339
  console.error('[leg-watchdog] check failed:', err);
1424
1340
  }
1425
1341
  }, 60_000);
1426
- const conductorConfig = resolveConductorConfig(config);
1427
- try {
1428
- assertConductorBackendSupported(conductorConfig.enabled, runtimeBackend);
1429
- }
1430
- catch (error) {
1431
- operatorDb.close();
1432
- throw error;
1433
- }
1434
1342
  // ── Stage-2 workorder consumer (plan S2-T3): the only system run path.
1435
1343
  // Constructed before production runtime assembly registers per-kind
1436
1344
  // completion hooks, and started only after route registration and recovery
@@ -1446,16 +1354,20 @@ async function runAgentLoop(config, options = {}) {
1446
1354
  gateways.push({
1447
1355
  stop: async () => {
1448
1356
  clearInterval(legWatchdog);
1449
- // Consumer stop BEFORE db close (same gateway = ordered; parallel
1450
- // gateways would race an in-flight tick into "database is not open").
1451
- await (0, temporal_runtime_js_1.closeTemporalRuntimeBeforeDatabase)(temporalRuntime, workOrderConsumer, () => {
1357
+ // All users of the shared operator DB stop inside this one gateway.
1358
+ // Shutdown invokes gateways in parallel, so a separate owner-event
1359
+ // gateway would race its final ACK against this close.
1360
+ await (0, owner_event_loop_js_1.closeOwnerEventBeforeDatabase)(async () => {
1361
+ await stopOwnerEventRuntime?.();
1362
+ stopOwnerEventRuntime = null;
1363
+ }, () => (0, temporal_runtime_js_1.closeTemporalRuntimeBeforeDatabase)(temporalRuntime, workOrderConsumer, () => {
1452
1364
  try {
1453
1365
  operatorDb.close();
1454
1366
  }
1455
1367
  catch {
1456
1368
  /* already closed */
1457
1369
  }
1458
- }).catch(() => { });
1370
+ })).catch(() => { });
1459
1371
  },
1460
1372
  });
1461
1373
  {
@@ -1637,12 +1549,6 @@ async function runAgentLoop(config, options = {}) {
1637
1549
  // MAMA_TRIGGER_LOOP=0 is the explicit opt-out. Placed after initConnectors (which feeds
1638
1550
  // connector_event_index) and after mama-core initDB. Read-only: recall/surface/log.
1639
1551
  const { isOperatorTriggerLoopEnabled, resolveOperatorReportChatId } = await import('../../operator/runtime-config.js');
1640
- if (!isOperatorTriggerLoopEnabled(process.env) && conductorConfig.enabled) {
1641
- // The conductor lives inside the trigger-loop branch (its inbox is fed by
1642
- // the loop's drain). enabled=true with the loop off would otherwise boot
1643
- // silently into a conductor that never runs (review).
1644
- console.error('[conductor] conductor.enabled=true but the trigger loop is disabled - the conductor will NOT run. Enable the trigger loop or disable the conductor.');
1645
- }
1646
1552
  if (isOperatorTriggerLoopEnabled(process.env)) {
1647
1553
  let stopTriggerAgentRuntime;
1648
1554
  // Component isolation (PR #119 review): a trigger-loop bootstrap failure (bad import,
@@ -1725,13 +1631,17 @@ async function runAgentLoop(config, options = {}) {
1725
1631
  dataDir: config.agent.cline_data_dir,
1726
1632
  });
1727
1633
  stopTriggerAgentRuntime = () => triggerAgentRuntime.stop();
1634
+ const ownerEventEnvelopeAuthority = envelopeBootstrap.envelopeAuthority;
1635
+ const ownerEventExecution = (0, owner_event_policy_js_1.resolveOwnerEventExecution)({
1636
+ issuance: envelopeBootstrap.metadata.issuance,
1637
+ hasAuthority: ownerEventEnvelopeAuthority !== undefined,
1638
+ });
1728
1639
  const triggerLoop = new OperatorTriggerLoop({
1729
1640
  backend: runtimeBackend,
1730
1641
  delta: new ConnectorDeltaRepo(getAdapter(), (0, config_manager_js_1.expandPath)('~/.mama/operator/trigger-loop-cursors.json')),
1731
1642
  memory: createMamaMemoryPort(),
1732
1643
  registry: triggerRegistry,
1733
- conductorInbox,
1734
- onChannelDelta: (channelKey, lines, eventIds) => channelDeltaSink.current?.(channelKey, lines, eventIds),
1644
+ ...(ownerEventExecution.enabled ? { ownerEventInbox } : {}),
1735
1645
  askAgent: triggerAgentRuntime.askAuthor,
1736
1646
  // M2.2: reports go through the daemon's persona agent (system prompt, pinned model,
1737
1647
  // session lanes) instead of the bare CLI - report tone comes from generation inputs.
@@ -1872,97 +1782,125 @@ async function runAgentLoop(config, options = {}) {
1872
1782
  (0, leg_cadence_js_1.getLegCadence)()?.declare('full-report', 26 * 60 * 60 * 1000);
1873
1783
  }
1874
1784
  const stopTriggerLoop = triggerLoop.start();
1785
+ stopOwnerEventRuntime = async () => {
1786
+ await Promise.all([stopTriggerLoop(), triggerAgentRuntime.stop()]);
1787
+ };
1875
1788
  // M2.4: point the connector sink's forwarder at this loop now that it exists.
1876
1789
  triggerLoopNudge.current = () => triggerLoop.nudge();
1877
1790
  // S1-T3: owner-intent forwarder - report_request routes to the SAME
1878
1791
  // report machinery (fresh session, delta anchor, consume semantics).
1879
1792
  toolExecutor.setReportRequestHandler(() => triggerLoop.startFullReport());
1880
- // S1: the stateful conductor consumes the durable inbox on its own
1881
- // session:conductor:main lane. Default-off; the inbox records
1882
- // either way (shadow-mode data).
1883
- let conductorTimer = null;
1884
- let conductorTickPromise = null;
1885
- if (conductorConfig.enabled) {
1886
- const conductorSession = new conductor_session_js_1.ConductorSession((0, session_pool_js_1.getSessionPool)(), {
1887
- maxAgeMs: conductorConfig.maxAgeMs,
1888
- maxTurns: conductorConfig.maxTurns,
1889
- maxTokens: conductorConfig.maxTokens,
1793
+ if (ownerEventExecution.enabled && ownerEventEnvelopeAuthority) {
1794
+ // MAMA itself owns connector events. This is the same AgentLoop and
1795
+ // owner operating policy as the owner console, on a durable per-channel
1796
+ // background session. There is no separate Conductor persona.
1797
+ const ownerRole = config.roles?.definitions.owner_console ?? types_js_1.DEFAULT_ROLES.definitions.owner_console;
1798
+ const ownerEventContext = (0, owner_event_policy_js_1.buildOwnerEventAgentContext)({
1799
+ backend: runtimeBackend,
1800
+ model: config.agent.model,
1801
+ ownerRole,
1802
+ privateConnectorPolicy,
1890
1803
  });
1891
- const conductorPolicy = buildConductorAgentPolicy(config.agent.model, runtimeBackend, privateConnectorPolicy);
1892
- // Per-run envelope, mirroring the report lane: without it every
1893
- // model_tool call dies 'envelope_missing' while the run resolves and
1894
- // acks the batch - zero work, green ledger (review F2).
1895
- const conductorIssueEnvelope = envelopeBootstrap.envelopeAuthority && envelopeBootstrap.metadata.issuance !== 'off'
1896
- ? async () => {
1897
- const projectId = (0, reactive_config_js_1.resolveReactiveProjectRoot)(config, process.env);
1898
- const wallSeconds = 300; // one judgment turn, not a gather run
1899
- return envelopeBootstrap.envelopeAuthority.buildAndPersist({
1900
- agent_id: 'conductor',
1901
- instance_id: (0, node_crypto_1.randomUUID)(),
1902
- source: 'watch',
1903
- channel_id: 'conductor',
1904
- trigger_context: { user_text: '<conductor batch judgment>' },
1905
- scope: {
1906
- project_refs: [{ kind: 'project', id: projectId }],
1907
- // The conductor reads channel text from its own durable
1908
- // inbox, never from connectors - no raw read authority.
1909
- raw_connectors: [],
1910
- memory_scopes: uniqueMemoryScopes((0, scope_context_js_1.deriveMemoryScopes)({
1911
- source: 'conductor',
1912
- channelId: 'conductor',
1913
- projectId,
1914
- })),
1915
- allowed_destinations: [], // NO send surface
1916
- },
1917
- tier: 2,
1918
- budget: { wall_seconds: wallSeconds },
1919
- expires_at: new Date(Date.now() + wallSeconds * 1000 + 30_000).toISOString(),
1920
- });
1921
- }
1922
- : undefined;
1923
- const conductor = new conductor_js_1.Conductor({
1924
- inbox: conductorInbox,
1925
- session: conductorSession,
1804
+ const ownerEventPromptEnhancer = new prompt_enhancer_js_1.PromptEnhancer();
1805
+ const ownerEventIssueEnvelope = async (batch) => {
1806
+ const projectId = (0, reactive_config_js_1.resolveReactiveProjectRoot)(config, process.env);
1807
+ const wallSeconds = 300;
1808
+ return ownerEventEnvelopeAuthority.buildAndPersist({
1809
+ agent_id: 'mama-owner',
1810
+ instance_id: (0, node_crypto_1.randomUUID)(),
1811
+ source: 'watch',
1812
+ channel_id: batch.channelKey,
1813
+ trigger_context: { user_text: '<MAMA owner event turn>' },
1814
+ scope: {
1815
+ project_refs: [{ kind: 'project', id: projectId }],
1816
+ raw_connectors: [
1817
+ ...privateConnectorPolicy.projectRawConnectors('owner_console', codeActRawConnectors),
1818
+ ],
1819
+ memory_scopes: uniqueMemoryScopes((0, scope_context_js_1.deriveMemoryScopes)({
1820
+ source: 'owner-event',
1821
+ channelId: batch.channelKey,
1822
+ projectId,
1823
+ })),
1824
+ allowed_destinations: reportChatId
1825
+ ? [{ kind: 'telegram', id: reportChatId }]
1826
+ : [],
1827
+ },
1828
+ tier: 1,
1829
+ budget: { wall_seconds: wallSeconds },
1830
+ expires_at: new Date(Date.now() + wallSeconds * 1000 + 30_000).toISOString(),
1831
+ });
1832
+ };
1833
+ const ownerEventLoop = new owner_event_loop_js_1.OwnerEventLoop({
1834
+ inbox: ownerEventInbox,
1926
1835
  runner: agentLoop,
1927
- reground: () => (0, board_reground_js_1.buildBoardReground)(taskLedger),
1928
- agentContext: conductorPolicy.agentContext,
1929
- issueEnvelope: conductorIssueEnvelope,
1836
+ agentContext: ownerEventContext,
1837
+ buildPrompt: async (batch) => (0, owner_event_prompt_js_1.buildOwnerEventPrompt)({
1838
+ batch,
1839
+ ownerBrief: (0, console_brief_js_1.projectConsoleBriefForPrompt)((0, console_brief_js_1.loadConsoleBrief)(), privateConnectorPolicy),
1840
+ skillContent: await ownerEventPromptEnhancer.detectSkillMatch(batch.lines.join('\n')),
1841
+ ownerTelegramChatId: reportChatId,
1842
+ }),
1843
+ issueEnvelope: ownerEventIssueEnvelope,
1844
+ getNoUpdateMaxId: (scope) => taskLedger.maxNoUpdateId(scope),
1845
+ getTerminalReceipt: (batch) => {
1846
+ const confirmedEffects = ownerEventEffectLedger.confirmedKinds(batch.id);
1847
+ if (confirmedEffects.length > 0) {
1848
+ return { status: 'acted', tools: confirmedEffects };
1849
+ }
1850
+ const acceptedWorkOrder = taskLedger.findWorkOrderByOccurrence('board', (0, workorder_publishers_js_1.boardBatchKey)(batch.eventIds)) ??
1851
+ taskLedger.findWorkOrderByOccurrence('wiki', (0, workorder_publishers_js_1.ownerEventWorkOrderKey)('wiki', batch.eventIds)) ??
1852
+ taskLedger.findWorkOrderByOccurrence('memory-curation', (0, workorder_publishers_js_1.ownerEventWorkOrderKey)('memory-curation', batch.eventIds));
1853
+ if (acceptedWorkOrder) {
1854
+ return { status: 'delegated', tools: ['workorder_request'] };
1855
+ }
1856
+ if (taskLedger.maxNoUpdateId(`owner-event:${batch.id}`) > 0) {
1857
+ return { status: 'no_update', tools: [] };
1858
+ }
1859
+ return null;
1860
+ },
1861
+ recordTriggerOutcome: (triggerId, outcome) => triggerRegistry.recordOutcome(triggerId, outcome),
1862
+ onDead: async (message) => {
1863
+ console.error(message);
1864
+ await (0, leg_cadence_js_1.getLegPageNotifier)()?.(message);
1865
+ },
1930
1866
  log: (line) => console.log(line),
1931
1867
  });
1932
- conductorTimer = setInterval(() => {
1933
- if (conductorTickPromise)
1934
- return; // never overlap ticks
1935
- conductorTickPromise = conductor
1868
+ let ownerEventTickPromise = null;
1869
+ const runOwnerEventTick = () => {
1870
+ if (ownerEventTickPromise)
1871
+ return;
1872
+ ownerEventTickPromise = ownerEventLoop
1936
1873
  .tick()
1937
- .catch((err) => console.error(`[conductor] tick failed: ${err instanceof Error ? err.message : String(err)}`))
1874
+ .catch((err) => console.error(`[owner-event] tick failed: ${err instanceof Error ? err.message : String(err)}`))
1938
1875
  .finally(() => {
1939
- conductorTickPromise = null;
1876
+ ownerEventTickPromise = null;
1940
1877
  });
1941
- }, conductorConfig.tickMs);
1942
- console.log(`✓ Conductor enabled (tick ${conductorConfig.tickMs}ms)`);
1878
+ };
1879
+ const ownerEventTimer = setInterval(runOwnerEventTick, 5_000);
1880
+ ownerEventTimer.unref?.();
1881
+ runOwnerEventTick();
1882
+ console.log('✓ MAMA owner-event agent enabled');
1883
+ stopOwnerEventRuntime = async () => {
1884
+ triggerLoopNudge.current = null;
1885
+ clearInterval(ownerEventTimer);
1886
+ // Let an in-flight effect reach its durable ACK before the shared
1887
+ // operator DB closes.
1888
+ if (ownerEventTickPromise)
1889
+ await ownerEventTickPromise;
1890
+ await Promise.all([stopTriggerLoop(), triggerAgentRuntime.stop()]);
1891
+ };
1943
1892
  }
1944
1893
  else {
1945
- console.log('Conductor inbox recording (conductor disabled)');
1894
+ const reason = ownerEventExecution.enabled
1895
+ ? 'owner-event envelope authority unavailable'
1896
+ : ownerEventExecution.reason;
1897
+ console.error(`[owner-event] disabled: ${reason}`);
1946
1898
  }
1947
- gateways.push({
1948
- stop: async () => {
1949
- triggerLoopNudge.current = null;
1950
- if (conductorTimer)
1951
- clearInterval(conductorTimer);
1952
- // Let an in-flight tick finish BEFORE the operator DB closes: a
1953
- // SIGTERM mid-ack otherwise throws on a closed handle, the row
1954
- // stays 'claimed', and every launchd restart replays the batch
1955
- // (review F7).
1956
- if (conductorTickPromise)
1957
- await conductorTickPromise;
1958
- await Promise.all([stopTriggerLoop(), triggerAgentRuntime.stop()]);
1959
- // The shared operator DB handle is closed by the unconditional stop
1960
- // hook above (single owner); nothing to close here.
1961
- },
1962
- });
1963
- temporalLogger.info('Trigger loop enabled (default-on, read-only surface mode)');
1899
+ temporalLogger.info('Trigger loop enabled (MAMA owner-event intake + report mode)');
1964
1900
  }
1965
1901
  catch (error) {
1902
+ await stopOwnerEventRuntime?.().catch(() => { });
1903
+ stopOwnerEventRuntime = null;
1966
1904
  await stopTriggerAgentRuntime?.().catch(() => { });
1967
1905
  console.error('[trigger-loop] FAILED to start - daemon continues WITHOUT the trigger loop. Fix and restart:', error);
1968
1906
  }
@@ -1984,7 +1922,6 @@ async function runAgentLoop(config, options = {}) {
1984
1922
  connectorConfigLoadResult,
1985
1923
  privateConnectorPolicy,
1986
1924
  });
1987
- channelDeltaSink.current = (channelKey, lines, eventIds) => eventBus.emit({ type: 'operator:channel-delta', channelKey, lines, eventIds });
1988
1925
  const apiRoutesHandle = await (0, api_routes_init_js_1.registerApiRoutes)({
1989
1926
  config,
1990
1927
  apiServer,