@jungjaehoon/mama-os 0.36.0 → 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 (158) hide show
  1. package/dist/agent/agent-loop.d.ts +2 -1
  2. package/dist/agent/agent-loop.d.ts.map +1 -1
  3. package/dist/agent/agent-loop.js +17 -12
  4. package/dist/agent/agent-loop.js.map +1 -1
  5. package/dist/agent/code-act/host-bridge.d.ts.map +1 -1
  6. package/dist/agent/code-act/host-bridge.js +27 -2
  7. package/dist/agent/code-act/host-bridge.js.map +1 -1
  8. package/dist/agent/code-act/type-definition-generator.d.ts.map +1 -1
  9. package/dist/agent/code-act/type-definition-generator.js +3 -1
  10. package/dist/agent/code-act/type-definition-generator.js.map +1 -1
  11. package/dist/agent/context-compile-service.d.ts +2 -0
  12. package/dist/agent/context-compile-service.d.ts.map +1 -1
  13. package/dist/agent/context-compile-service.js +1 -1
  14. package/dist/agent/context-compile-service.js.map +1 -1
  15. package/dist/agent/drive-tools.d.ts +27 -1
  16. package/dist/agent/drive-tools.d.ts.map +1 -1
  17. package/dist/agent/drive-tools.js +68 -2
  18. package/dist/agent/drive-tools.js.map +1 -1
  19. package/dist/agent/gateway-tool-executor.d.ts +11 -6
  20. package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
  21. package/dist/agent/gateway-tool-executor.js +210 -37
  22. package/dist/agent/gateway-tool-executor.js.map +1 -1
  23. package/dist/agent/gateway-tools.md +2 -2
  24. package/dist/agent/tool-registry.js +2 -2
  25. package/dist/agent/tool-registry.js.map +1 -1
  26. package/dist/agent/types.d.ts +15 -0
  27. package/dist/agent/types.d.ts.map +1 -1
  28. package/dist/agent/types.js.map +1 -1
  29. package/dist/api/report-handler.d.ts +9 -5
  30. package/dist/api/report-handler.d.ts.map +1 -1
  31. package/dist/api/report-handler.js +26 -13
  32. package/dist/api/report-handler.js.map +1 -1
  33. package/dist/api/report-persistence.d.ts.map +1 -1
  34. package/dist/api/report-persistence.js +6 -3
  35. package/dist/api/report-persistence.js.map +1 -1
  36. package/dist/api/runtime-status-handler.d.ts +1 -0
  37. package/dist/api/runtime-status-handler.d.ts.map +1 -1
  38. package/dist/api/runtime-status-handler.js +1 -0
  39. package/dist/api/runtime-status-handler.js.map +1 -1
  40. package/dist/cli/commands/start.d.ts +14 -20
  41. package/dist/cli/commands/start.d.ts.map +1 -1
  42. package/dist/cli/commands/start.js +207 -248
  43. package/dist/cli/commands/start.js.map +1 -1
  44. package/dist/cli/commands/status.d.ts +6 -0
  45. package/dist/cli/commands/status.d.ts.map +1 -1
  46. package/dist/cli/commands/status.js +89 -0
  47. package/dist/cli/commands/status.js.map +1 -1
  48. package/dist/cli/config/types.d.ts +0 -21
  49. package/dist/cli/config/types.d.ts.map +1 -1
  50. package/dist/cli/config/types.js +0 -7
  51. package/dist/cli/config/types.js.map +1 -1
  52. package/dist/cli/index.js +2 -15
  53. package/dist/cli/index.js.map +1 -1
  54. package/dist/cli/runtime/agent-loop-init.d.ts +2 -2
  55. package/dist/cli/runtime/agent-loop-init.d.ts.map +1 -1
  56. package/dist/cli/runtime/agent-loop-init.js +3 -3
  57. package/dist/cli/runtime/agent-loop-init.js.map +1 -1
  58. package/dist/cli/runtime/api-routes-init.d.ts +7 -1
  59. package/dist/cli/runtime/api-routes-init.d.ts.map +1 -1
  60. package/dist/cli/runtime/api-routes-init.js +99 -38
  61. package/dist/cli/runtime/api-routes-init.js.map +1 -1
  62. package/dist/cli/runtime/api-server-init.d.ts.map +1 -1
  63. package/dist/cli/runtime/api-server-init.js +3 -0
  64. package/dist/cli/runtime/api-server-init.js.map +1 -1
  65. package/dist/gateways/message-router.js +10 -10
  66. package/dist/gateways/message-router.js.map +1 -1
  67. package/dist/gateways/telegram.d.ts +2 -2
  68. package/dist/gateways/telegram.d.ts.map +1 -1
  69. package/dist/gateways/telegram.js +13 -7
  70. package/dist/gateways/telegram.js.map +1 -1
  71. package/dist/multi-agent/agent-event-bus.d.ts +0 -5
  72. package/dist/multi-agent/agent-event-bus.d.ts.map +1 -1
  73. package/dist/multi-agent/agent-event-bus.js.map +1 -1
  74. package/dist/operator/action-verifier.d.ts +2 -0
  75. package/dist/operator/action-verifier.d.ts.map +1 -1
  76. package/dist/operator/action-verifier.js +3 -2
  77. package/dist/operator/action-verifier.js.map +1 -1
  78. package/dist/operator/board-reconcile.d.ts +2 -2
  79. package/dist/operator/board-reconcile.d.ts.map +1 -1
  80. package/dist/operator/board-reconcile.js +10 -2
  81. package/dist/operator/board-reconcile.js.map +1 -1
  82. package/dist/operator/board-refresh-gate.d.ts +34 -0
  83. package/dist/operator/board-refresh-gate.d.ts.map +1 -0
  84. package/dist/operator/board-refresh-gate.js +82 -0
  85. package/dist/operator/board-refresh-gate.js.map +1 -0
  86. package/dist/operator/briefs.d.ts.map +1 -1
  87. package/dist/operator/briefs.js +92 -4
  88. package/dist/operator/briefs.js.map +1 -1
  89. package/dist/operator/operator-trigger-loop.d.ts +7 -22
  90. package/dist/operator/operator-trigger-loop.d.ts.map +1 -1
  91. package/dist/operator/operator-trigger-loop.js +33 -34
  92. package/dist/operator/operator-trigger-loop.js.map +1 -1
  93. package/dist/operator/owner-event-effects.d.ts +34 -0
  94. package/dist/operator/owner-event-effects.d.ts.map +1 -0
  95. package/dist/operator/owner-event-effects.js +131 -0
  96. package/dist/operator/owner-event-effects.js.map +1 -0
  97. package/dist/operator/{conductor-inbox.d.ts → owner-event-inbox.d.ts} +23 -12
  98. package/dist/operator/owner-event-inbox.d.ts.map +1 -0
  99. package/dist/operator/{conductor-inbox.js → owner-event-inbox.js} +97 -40
  100. package/dist/operator/owner-event-inbox.js.map +1 -0
  101. package/dist/operator/owner-event-loop.d.ts +59 -0
  102. package/dist/operator/owner-event-loop.d.ts.map +1 -0
  103. package/dist/operator/owner-event-loop.js +141 -0
  104. package/dist/operator/owner-event-loop.js.map +1 -0
  105. package/dist/operator/owner-event-outcome.d.ts +30 -0
  106. package/dist/operator/owner-event-outcome.d.ts.map +1 -0
  107. package/dist/operator/owner-event-outcome.js +108 -0
  108. package/dist/operator/owner-event-outcome.js.map +1 -0
  109. package/dist/operator/owner-event-policy.d.ts +20 -0
  110. package/dist/operator/owner-event-policy.d.ts.map +1 -0
  111. package/dist/operator/owner-event-policy.js +50 -0
  112. package/dist/operator/owner-event-policy.js.map +1 -0
  113. package/dist/operator/owner-event-prompt.d.ts +10 -0
  114. package/dist/operator/owner-event-prompt.d.ts.map +1 -0
  115. package/dist/operator/owner-event-prompt.js +63 -0
  116. package/dist/operator/owner-event-prompt.js.map +1 -0
  117. package/dist/operator/task-ledger.d.ts +2 -0
  118. package/dist/operator/task-ledger.d.ts.map +1 -1
  119. package/dist/operator/task-ledger.js +12 -1
  120. package/dist/operator/task-ledger.js.map +1 -1
  121. package/dist/operator/trigger-matcher.d.ts.map +1 -1
  122. package/dist/operator/trigger-matcher.js +4 -1
  123. package/dist/operator/trigger-matcher.js.map +1 -1
  124. package/dist/operator/trigger-registry.d.ts +1 -1
  125. package/dist/operator/trigger-registry.d.ts.map +1 -1
  126. package/dist/operator/trigger-registry.js +2 -2
  127. package/dist/operator/trigger-registry.js.map +1 -1
  128. package/dist/operator/trigger-types.d.ts +2 -0
  129. package/dist/operator/trigger-types.d.ts.map +1 -1
  130. package/dist/operator/workorder-hooks.d.ts +14 -0
  131. package/dist/operator/workorder-hooks.d.ts.map +1 -1
  132. package/dist/operator/workorder-hooks.js +64 -0
  133. package/dist/operator/workorder-hooks.js.map +1 -1
  134. package/dist/operator/workorder-publishers.d.ts +14 -4
  135. package/dist/operator/workorder-publishers.d.ts.map +1 -1
  136. package/dist/operator/workorder-publishers.js +51 -13
  137. package/dist/operator/workorder-publishers.js.map +1 -1
  138. package/dist/package-version.d.ts +3 -0
  139. package/dist/package-version.d.ts.map +1 -0
  140. package/dist/package-version.js +18 -0
  141. package/dist/package-version.js.map +1 -0
  142. package/package.json +2 -2
  143. package/public/viewer/js/modules/system.js +1 -0
  144. package/public/viewer/src/modules/system.ts +2 -0
  145. package/dist/operator/board-reground.d.ts +0 -19
  146. package/dist/operator/board-reground.d.ts.map +0 -1
  147. package/dist/operator/board-reground.js +0 -31
  148. package/dist/operator/board-reground.js.map +0 -1
  149. package/dist/operator/conductor-inbox.d.ts.map +0 -1
  150. package/dist/operator/conductor-inbox.js.map +0 -1
  151. package/dist/operator/conductor-session.d.ts +0 -55
  152. package/dist/operator/conductor-session.d.ts.map +0 -1
  153. package/dist/operator/conductor-session.js +0 -110
  154. package/dist/operator/conductor-session.js.map +0 -1
  155. package/dist/operator/conductor.d.ts +0 -69
  156. package/dist/operator/conductor.d.ts.map +0 -1
  157. package/dist/operator/conductor.js +0 -90
  158. 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,14 +57,13 @@ 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;
66
63
  exports.finalizeCodeActParentModelRun = finalizeCodeActParentModelRun;
67
64
  exports.failCodeActParentModelRun = failCodeActParentModelRun;
68
65
  exports.buildSystemAgentProcessDefaults = buildSystemAgentProcessDefaults;
66
+ exports.buildOwnerWorkOrderRequestHandler = buildOwnerWorkOrderRequestHandler;
69
67
  exports.startCommand = startCommand;
70
68
  exports.runAgentLoop = runAgentLoop;
71
69
  const config_manager_js_1 = require("../config/config-manager.js");
@@ -76,6 +74,7 @@ const gateway_tool_executor_js_1 = require("../../agent/gateway-tool-executor.js
76
74
  const context_compile_service_js_1 = require("../../agent/context-compile-service.js");
77
75
  const read_js_1 = require("../../evidence/read.js");
78
76
  const tool_registry_js_1 = require("../../agent/tool-registry.js");
77
+ const prompt_enhancer_js_1 = require("../../agent/prompt-enhancer.js");
79
78
  const gateway_tool_catalog_js_1 = require("../../agent/gateway-tool-catalog.js");
80
79
  const tool_policy_js_1 = require("../../agent/code-act/tool-policy.js");
81
80
  const run_context_registry_js_1 = require("../../agent/code-act/run-context-registry.js");
@@ -122,12 +121,14 @@ const mamaCore = __importStar(require("@jungjaehoon/mama-core"));
122
121
  const report_run_js_1 = require("../../operator/report-run.js");
123
122
  const console_brief_js_1 = require("../../operator/console-brief.js");
124
123
  const task_ledger_js_1 = require("../../operator/task-ledger.js");
125
- const conductor_inbox_js_1 = require("../../operator/conductor-inbox.js");
126
- const conductor_session_js_1 = require("../../operator/conductor-session.js");
127
- const conductor_js_1 = require("../../operator/conductor.js");
128
- const board_reground_js_1 = require("../../operator/board-reground.js");
124
+ const board_refresh_gate_js_1 = require("../../operator/board-refresh-gate.js");
125
+ const workorder_publishers_js_1 = require("../../operator/workorder-publishers.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");
129
131
  const leg_cadence_js_1 = require("../../operator/leg-cadence.js");
130
- const session_pool_js_1 = require("../../agent/session-pool.js");
131
132
  const temporal_worker_js_1 = require("../../operator/temporal-worker.js");
132
133
  const temporal_runtime_js_1 = require("../../operator/temporal-runtime.js");
133
134
  const temporal_init_js_1 = require("../runtime/temporal-init.js");
@@ -138,6 +139,7 @@ const { DebugLogger } = debugLogger;
138
139
  const codeActLogger = new DebugLogger('CodeAct');
139
140
  const temporalLogger = new DebugLogger('TemporalReconcile');
140
141
  const principalRegistryLogger = new DebugLogger('PrincipalRegistry');
142
+ const ownerWorkOrderLogger = new DebugLogger('OwnerWorkOrder');
141
143
  const DISABLED_PRIVATE_CONNECTOR_POLICY = (0, private_connector_policy_js_1.resolvePrivateConnectorPolicy)({
142
144
  ok: true,
143
145
  config: {},
@@ -157,11 +159,6 @@ function requireRuntimeBackend(value) {
157
159
  }
158
160
  throw new Error(`Unsupported agent backend: ${String(value)}`);
159
161
  }
160
- function assertConductorBackendSupported(enabled, backend) {
161
- if (enabled && backend === 'codex') {
162
- throw new Error('conductor.enabled requires the claude or cline backend - codex session lifecycle lands in S2');
163
- }
164
- }
165
162
  function serializeCodeActExecutionResult(result, toolCalls, hostToolExecutions = []) {
166
163
  const hostToolsInvoked = [
167
164
  ...new Set(hostToolExecutions.filter((execution) => execution.success).map((execution) => execution.name)),
@@ -540,87 +537,6 @@ function buildProjectedLanePrompt(innerTools, surface, privateConnectorPolicy) {
540
537
  privateConnectorPolicy,
541
538
  }).prompt;
542
539
  }
543
- /**
544
- * The conductor's grant (S1). Reads and judgment surfaces plus the ONE write
545
- * family the spec's center names: committing work orders and board cards. No
546
- * sends, no memory writes, no compile - the untrusted-input lane stays the
547
- * most restricted lane, not the least (review F2/security).
548
- */
549
- exports.CONDUCTOR_TOOL_POLICY = {
550
- roleName: 'conductor',
551
- allowedTools: [
552
- 'board_read',
553
- 'changes_read',
554
- 'mama_recall',
555
- 'mama_search',
556
- 'task_create',
557
- 'task_list',
558
- 'task_update',
559
- 'workorder_request',
560
- 'workorder_status',
561
- ],
562
- };
563
- /** Mirrors buildOperatorReportAgentPolicy - same shape, conductor grant. */
564
- function buildConductorAgentPolicy(model, backend, privateConnectorPolicy) {
565
- const blockedTools = [];
566
- const innerTools = uniqueToolList(exports.CONDUCTOR_TOOL_POLICY.allowedTools);
567
- const allowedTools = uniqueToolList([...innerTools]);
568
- const agentContext = {
569
- source: 'conductor',
570
- platform: 'cli',
571
- roleName: exports.CONDUCTOR_TOOL_POLICY.roleName,
572
- role: {
573
- allowedTools,
574
- blockedTools,
575
- allowedPaths: [],
576
- systemControl: false,
577
- sensitiveAccess: false,
578
- model,
579
- },
580
- session: {
581
- sessionId: 'conductor:main',
582
- channelId: 'conductor',
583
- startedAt: new Date(),
584
- },
585
- capabilities: allowedTools,
586
- limitations: blockedTools.map((tool) => `Cannot use ${tool}`),
587
- // Write tier: board cards and work orders only - matches the envelope.
588
- tier: 2,
589
- backend,
590
- };
591
- return {
592
- agentContext,
593
- gatewayToolsPrompt: (0, gateway_tool_catalog_js_1.buildGatewayToolCatalog)({
594
- surface: 'multi-agent-generic',
595
- allowedTools: innerTools,
596
- privateConnectorPolicy,
597
- }).prompt,
598
- briefProjectionPolicy: DISABLED_PRIVATE_CONNECTOR_POLICY,
599
- };
600
- }
601
- /**
602
- * Merge + validate the conductor config at boot. No-fallback: a malformed
603
- * value must crash loudly, not silently clamp (review F10: tickMs 0 spins
604
- * the event loop with a DB write per iteration).
605
- */
606
- function resolveConductorConfig(config) {
607
- const resolved = {
608
- ...types_js_1.DEFAULT_CONFIG.conductor,
609
- ...(config.conductor ?? {}),
610
- };
611
- const positive = [
612
- ['tickMs', resolved.tickMs, 1_000],
613
- ['maxAgeMs', resolved.maxAgeMs, 60_000],
614
- ['maxTurns', resolved.maxTurns, 1],
615
- ['maxTokens', resolved.maxTokens, 1_000],
616
- ];
617
- for (const [name, value, min] of positive) {
618
- if (!Number.isFinite(value) || value < min) {
619
- throw new Error(`conductor.${name} must be a number >= ${min}, got ${String(value)}`);
620
- }
621
- }
622
- return resolved;
623
- }
624
540
  /**
625
541
  * Build the Code-Act role the operator report lane runs under.
626
542
  *
@@ -752,6 +668,73 @@ function buildSystemAgentProcessDefaults(config) {
752
668
  dangerouslySkipPermissions: config.multi_agent?.dangerouslySkipPermissions ?? true,
753
669
  };
754
670
  }
671
+ const OWNER_BOARD_FULL_REPAIR_CHANNEL = 'host:owner-workorder:board-full';
672
+ /** Build the enqueue-and-ack handler shared by owner chat and owner-event turns. */
673
+ function buildOwnerWorkOrderRequestHandler(deps) {
674
+ const now = deps.now ?? Date.now;
675
+ const log = deps.log ?? ((line) => ownerWorkOrderLogger.info(line));
676
+ const logError = deps.logError ?? ((line, detail) => ownerWorkOrderLogger.error(line, detail));
677
+ return (kind, causeEventIds) => {
678
+ try {
679
+ const requestedAt = now();
680
+ let idempotencyKey;
681
+ let payload;
682
+ if (kind === 'board') {
683
+ // TG-06: host dirt is recorded before validation or enqueue can fail.
684
+ // The fixed synthetic channel never trusts model/event identifiers.
685
+ const repair = deps.boardRefreshGate
686
+ ? (() => {
687
+ deps.boardRefreshGate.markChannelDirty(OWNER_BOARD_FULL_REPAIR_CHANNEL);
688
+ return deps.boardRefreshGate.captureFullRepair();
689
+ })()
690
+ : null;
691
+ if (causeEventIds && causeEventIds.length > 0) {
692
+ idempotencyKey = (0, workorder_publishers_js_1.boardBatchKey)(causeEventIds);
693
+ payload = {
694
+ mode: 'full',
695
+ force: true,
696
+ eventIds: [...causeEventIds],
697
+ ...(repair ?? {}),
698
+ };
699
+ }
700
+ else {
701
+ idempotencyKey = (0, workorder_publishers_js_1.boardManualKey)(requestedAt);
702
+ payload = { mode: 'full', force: true, ...(repair ?? {}) };
703
+ }
704
+ }
705
+ else if (kind === 'wiki') {
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
+ }
714
+ }
715
+ else {
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);
720
+ payload = { scheduledAt: new Date(requestedAt).toISOString() };
721
+ }
722
+ (0, workorder_publishers_js_1.validateWorkOrderPayload)(kind, payload);
723
+ const wo = deps.taskLedger.enqueueWorkOrder({
724
+ workKind: kind,
725
+ idempotencyKey,
726
+ input: payload,
727
+ priority: 'high',
728
+ });
729
+ log(`[stage2] owner workorder enqueued: ${kind}#${wo.id}`);
730
+ return { accepted: true };
731
+ }
732
+ catch (err) {
733
+ logError(`[stage2] owner workorder enqueue failed (${kind}):`, err instanceof Error ? err.message : err);
734
+ return { accepted: false, reason: 'enqueue-failed' };
735
+ }
736
+ };
737
+ }
755
738
  /**
756
739
  * Execute start command
757
740
  */
@@ -1297,12 +1280,6 @@ async function runAgentLoop(config, options = {}) {
1297
1280
  // and point it at the loop once it exists. Null until then -> nudge no-ops (no loop = nothing to
1298
1281
  // wake), which remains safe while the trigger loop is still booting or explicitly disabled.
1299
1282
  const triggerLoopNudge = { current: null };
1300
- // M8: board-reconcile feed. The trigger loop is built BEFORE the event bus
1301
- // exists (initApiServer), so it emits through this mutable sink (same
1302
- // pattern as triggerLoopNudge above).
1303
- const channelDeltaSink = {
1304
- current: null,
1305
- };
1306
1283
  // Operator DB + native task ledger (M8): wired UNCONDITIONALLY -- the task
1307
1284
  // tools are standard gateway tools and must work even when the trigger loop
1308
1285
  // is off (review finding on #142). Single handle, closed once at shutdown.
@@ -1319,11 +1296,15 @@ async function runAgentLoop(config, options = {}) {
1319
1296
  operatorDb.close();
1320
1297
  throw err;
1321
1298
  }
1322
- // S1: durable conductor inbox - constructed UNCONDITIONALLY so drained
1323
- // batches persist before the cursor commits even while the conductor is
1324
- // disabled (that accumulation IS the shadow-mode data; retention inside
1325
- // ConductorInbox keeps it bounded).
1326
- const conductorInbox = new conductor_inbox_js_1.ConductorInbox(operatorDb);
1299
+ // One host-owned gate spans owner workorder requests, route scheduling,
1300
+ // delta ingestion, and completion verification for this boot.
1301
+ const boardRefreshGate = process.env.MAMA_BOARD_RECONCILE === '1' ? new board_refresh_gate_js_1.BoardRefreshGate() : null;
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;
1327
1308
  // S2: leg cadence watchdog - its OWN timer, deliberately outside the
1328
1309
  // trigger loop (a watchdog inside the thing it watches dies with it).
1329
1310
  // Legs declare+beat at their own tick sites via the singleton; pages ride
@@ -1358,14 +1339,6 @@ async function runAgentLoop(config, options = {}) {
1358
1339
  console.error('[leg-watchdog] check failed:', err);
1359
1340
  }
1360
1341
  }, 60_000);
1361
- const conductorConfig = resolveConductorConfig(config);
1362
- try {
1363
- assertConductorBackendSupported(conductorConfig.enabled, runtimeBackend);
1364
- }
1365
- catch (error) {
1366
- operatorDb.close();
1367
- throw error;
1368
- }
1369
1342
  // ── Stage-2 workorder consumer (plan S2-T3): the only system run path.
1370
1343
  // Constructed before production runtime assembly registers per-kind
1371
1344
  // completion hooks, and started only after route registration and recovery
@@ -1381,16 +1354,20 @@ async function runAgentLoop(config, options = {}) {
1381
1354
  gateways.push({
1382
1355
  stop: async () => {
1383
1356
  clearInterval(legWatchdog);
1384
- // Consumer stop BEFORE db close (same gateway = ordered; parallel
1385
- // gateways would race an in-flight tick into "database is not open").
1386
- 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, () => {
1387
1364
  try {
1388
1365
  operatorDb.close();
1389
1366
  }
1390
1367
  catch {
1391
1368
  /* already closed */
1392
1369
  }
1393
- }).catch(() => { });
1370
+ })).catch(() => { });
1394
1371
  },
1395
1372
  });
1396
1373
  {
@@ -1401,7 +1378,6 @@ async function runAgentLoop(config, options = {}) {
1401
1378
  ensureBriefs();
1402
1379
  (0, console_brief_js_1.ensureConsoleBrief)();
1403
1380
  const { logActivity: logWorkOrderActivity } = await import('../../db/agent-store.js');
1404
- const { validateWorkOrderPayload, boardManualKey, boardBatchKey, wikiBatchKey, promotionManualKey, } = await import('../../operator/workorder-publishers.js');
1405
1381
  // Ops alarm sink (plan D4/E1/G8): constructed OUTSIDE any trigger-loop
1406
1382
  // block - the consumer runs with the loop off, so its terminal alarms
1407
1383
  // must too. Chat id: MAMA_OPS_ALERT_CHAT, falling back to the loop's
@@ -1540,51 +1516,7 @@ async function runAgentLoop(config, options = {}) {
1540
1516
  // (Consumer stop is folded into the operator-DB gateway above - ordering.)
1541
1517
  // Owner-issued workorders (workorder_request tool): enqueue+ack only.
1542
1518
  // Wired here - NOT inside any trigger-loop block (plan C11 class).
1543
- toolExecutor.setWorkOrderRequestHandler((kind, causeEventIds) => {
1544
- try {
1545
- const now = Date.now();
1546
- let idempotencyKey;
1547
- let payload;
1548
- if (kind === 'board') {
1549
- if (causeEventIds && causeEventIds.length > 0) {
1550
- // Batch-carrying delegation: FULL mode (reconcile requires
1551
- // channelKey+deltaLines the requester does not have - proven by
1552
- // review running the validator) with the batch riding as
1553
- // eventIds, which the validator allows on full and
1554
- // causeEventIdsFromPayload lifts as the worker's cause. The
1555
- // batch-deterministic key dedups a redelivered judgment while
1556
- // the first order is still open.
1557
- idempotencyKey = boardBatchKey(causeEventIds);
1558
- payload = { mode: 'full', force: true, eventIds: [...causeEventIds] };
1559
- }
1560
- else {
1561
- idempotencyKey = boardManualKey(now);
1562
- payload = { mode: 'full', force: true };
1563
- }
1564
- }
1565
- else if (kind === 'wiki') {
1566
- idempotencyKey = wikiBatchKey('manual', now);
1567
- payload = { batchId: `${now}-manual`, events: ['manual'] };
1568
- }
1569
- else {
1570
- idempotencyKey = promotionManualKey(now);
1571
- payload = { scheduledAt: new Date(now).toISOString() };
1572
- }
1573
- validateWorkOrderPayload(kind, payload);
1574
- const wo = taskLedger.enqueueWorkOrder({
1575
- workKind: kind,
1576
- idempotencyKey,
1577
- input: payload,
1578
- priority: 'high',
1579
- });
1580
- console.log(`[stage2] owner workorder enqueued: ${kind}#${wo.id}`);
1581
- return { accepted: true };
1582
- }
1583
- catch (err) {
1584
- console.error(`[stage2] owner workorder enqueue failed (${kind}):`, err instanceof Error ? err.message : err);
1585
- return { accepted: false, reason: 'enqueue-failed' };
1586
- }
1587
- });
1519
+ toolExecutor.setWorkOrderRequestHandler(buildOwnerWorkOrderRequestHandler({ taskLedger, boardRefreshGate }));
1588
1520
  }
1589
1521
  const temporalTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
1590
1522
  const temporalAssembly = (0, temporal_init_js_1.assembleDaemonTemporalRuntime)({
@@ -1617,12 +1549,6 @@ async function runAgentLoop(config, options = {}) {
1617
1549
  // MAMA_TRIGGER_LOOP=0 is the explicit opt-out. Placed after initConnectors (which feeds
1618
1550
  // connector_event_index) and after mama-core initDB. Read-only: recall/surface/log.
1619
1551
  const { isOperatorTriggerLoopEnabled, resolveOperatorReportChatId } = await import('../../operator/runtime-config.js');
1620
- if (!isOperatorTriggerLoopEnabled(process.env) && conductorConfig.enabled) {
1621
- // The conductor lives inside the trigger-loop branch (its inbox is fed by
1622
- // the loop's drain). enabled=true with the loop off would otherwise boot
1623
- // silently into a conductor that never runs (review).
1624
- 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.');
1625
- }
1626
1552
  if (isOperatorTriggerLoopEnabled(process.env)) {
1627
1553
  let stopTriggerAgentRuntime;
1628
1554
  // Component isolation (PR #119 review): a trigger-loop bootstrap failure (bad import,
@@ -1705,13 +1631,17 @@ async function runAgentLoop(config, options = {}) {
1705
1631
  dataDir: config.agent.cline_data_dir,
1706
1632
  });
1707
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
+ });
1708
1639
  const triggerLoop = new OperatorTriggerLoop({
1709
1640
  backend: runtimeBackend,
1710
1641
  delta: new ConnectorDeltaRepo(getAdapter(), (0, config_manager_js_1.expandPath)('~/.mama/operator/trigger-loop-cursors.json')),
1711
1642
  memory: createMamaMemoryPort(),
1712
1643
  registry: triggerRegistry,
1713
- conductorInbox,
1714
- onChannelDelta: (channelKey, lines, eventIds) => channelDeltaSink.current?.(channelKey, lines, eventIds),
1644
+ ...(ownerEventExecution.enabled ? { ownerEventInbox } : {}),
1715
1645
  askAgent: triggerAgentRuntime.askAuthor,
1716
1646
  // M2.2: reports go through the daemon's persona agent (system prompt, pinned model,
1717
1647
  // session lanes) instead of the bare CLI - report tone comes from generation inputs.
@@ -1852,97 +1782,125 @@ async function runAgentLoop(config, options = {}) {
1852
1782
  (0, leg_cadence_js_1.getLegCadence)()?.declare('full-report', 26 * 60 * 60 * 1000);
1853
1783
  }
1854
1784
  const stopTriggerLoop = triggerLoop.start();
1785
+ stopOwnerEventRuntime = async () => {
1786
+ await Promise.all([stopTriggerLoop(), triggerAgentRuntime.stop()]);
1787
+ };
1855
1788
  // M2.4: point the connector sink's forwarder at this loop now that it exists.
1856
1789
  triggerLoopNudge.current = () => triggerLoop.nudge();
1857
1790
  // S1-T3: owner-intent forwarder - report_request routes to the SAME
1858
1791
  // report machinery (fresh session, delta anchor, consume semantics).
1859
1792
  toolExecutor.setReportRequestHandler(() => triggerLoop.startFullReport());
1860
- // S1: the stateful conductor consumes the durable inbox on its own
1861
- // session:conductor:main lane. Default-off; the inbox records
1862
- // either way (shadow-mode data).
1863
- let conductorTimer = null;
1864
- let conductorTickPromise = null;
1865
- if (conductorConfig.enabled) {
1866
- const conductorSession = new conductor_session_js_1.ConductorSession((0, session_pool_js_1.getSessionPool)(), {
1867
- maxAgeMs: conductorConfig.maxAgeMs,
1868
- maxTurns: conductorConfig.maxTurns,
1869
- 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,
1870
1803
  });
1871
- const conductorPolicy = buildConductorAgentPolicy(config.agent.model, runtimeBackend, privateConnectorPolicy);
1872
- // Per-run envelope, mirroring the report lane: without it every
1873
- // model_tool call dies 'envelope_missing' while the run resolves and
1874
- // acks the batch - zero work, green ledger (review F2).
1875
- const conductorIssueEnvelope = envelopeBootstrap.envelopeAuthority && envelopeBootstrap.metadata.issuance !== 'off'
1876
- ? async () => {
1877
- const projectId = (0, reactive_config_js_1.resolveReactiveProjectRoot)(config, process.env);
1878
- const wallSeconds = 300; // one judgment turn, not a gather run
1879
- return envelopeBootstrap.envelopeAuthority.buildAndPersist({
1880
- agent_id: 'conductor',
1881
- instance_id: (0, node_crypto_1.randomUUID)(),
1882
- source: 'watch',
1883
- channel_id: 'conductor',
1884
- trigger_context: { user_text: '<conductor batch judgment>' },
1885
- scope: {
1886
- project_refs: [{ kind: 'project', id: projectId }],
1887
- // The conductor reads channel text from its own durable
1888
- // inbox, never from connectors - no raw read authority.
1889
- raw_connectors: [],
1890
- memory_scopes: uniqueMemoryScopes((0, scope_context_js_1.deriveMemoryScopes)({
1891
- source: 'conductor',
1892
- channelId: 'conductor',
1893
- projectId,
1894
- })),
1895
- allowed_destinations: [], // NO send surface
1896
- },
1897
- tier: 2,
1898
- budget: { wall_seconds: wallSeconds },
1899
- expires_at: new Date(Date.now() + wallSeconds * 1000 + 30_000).toISOString(),
1900
- });
1901
- }
1902
- : undefined;
1903
- const conductor = new conductor_js_1.Conductor({
1904
- inbox: conductorInbox,
1905
- 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,
1906
1835
  runner: agentLoop,
1907
- reground: () => (0, board_reground_js_1.buildBoardReground)(taskLedger),
1908
- agentContext: conductorPolicy.agentContext,
1909
- 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
+ },
1910
1866
  log: (line) => console.log(line),
1911
1867
  });
1912
- conductorTimer = setInterval(() => {
1913
- if (conductorTickPromise)
1914
- return; // never overlap ticks
1915
- conductorTickPromise = conductor
1868
+ let ownerEventTickPromise = null;
1869
+ const runOwnerEventTick = () => {
1870
+ if (ownerEventTickPromise)
1871
+ return;
1872
+ ownerEventTickPromise = ownerEventLoop
1916
1873
  .tick()
1917
- .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)}`))
1918
1875
  .finally(() => {
1919
- conductorTickPromise = null;
1876
+ ownerEventTickPromise = null;
1920
1877
  });
1921
- }, conductorConfig.tickMs);
1922
- 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
+ };
1923
1892
  }
1924
1893
  else {
1925
- 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}`);
1926
1898
  }
1927
- gateways.push({
1928
- stop: async () => {
1929
- triggerLoopNudge.current = null;
1930
- if (conductorTimer)
1931
- clearInterval(conductorTimer);
1932
- // Let an in-flight tick finish BEFORE the operator DB closes: a
1933
- // SIGTERM mid-ack otherwise throws on a closed handle, the row
1934
- // stays 'claimed', and every launchd restart replays the batch
1935
- // (review F7).
1936
- if (conductorTickPromise)
1937
- await conductorTickPromise;
1938
- await Promise.all([stopTriggerLoop(), triggerAgentRuntime.stop()]);
1939
- // The shared operator DB handle is closed by the unconditional stop
1940
- // hook above (single owner); nothing to close here.
1941
- },
1942
- });
1943
- temporalLogger.info('Trigger loop enabled (default-on, read-only surface mode)');
1899
+ temporalLogger.info('Trigger loop enabled (MAMA owner-event intake + report mode)');
1944
1900
  }
1945
1901
  catch (error) {
1902
+ await stopOwnerEventRuntime?.().catch(() => { });
1903
+ stopOwnerEventRuntime = null;
1946
1904
  await stopTriggerAgentRuntime?.().catch(() => { });
1947
1905
  console.error('[trigger-loop] FAILED to start - daemon continues WITHOUT the trigger loop. Fix and restart:', error);
1948
1906
  }
@@ -1964,8 +1922,7 @@ async function runAgentLoop(config, options = {}) {
1964
1922
  connectorConfigLoadResult,
1965
1923
  privateConnectorPolicy,
1966
1924
  });
1967
- channelDeltaSink.current = (channelKey, lines, eventIds) => eventBus.emit({ type: 'operator:channel-delta', channelKey, lines, eventIds });
1968
- await (0, api_routes_init_js_1.registerApiRoutes)({
1925
+ const apiRoutesHandle = await (0, api_routes_init_js_1.registerApiRoutes)({
1969
1926
  config,
1970
1927
  apiServer,
1971
1928
  eventBus,
@@ -1985,7 +1942,9 @@ async function runAgentLoop(config, options = {}) {
1985
1942
  ],
1986
1943
  sessionsDb: db,
1987
1944
  workOrderConsumer: workOrderConsumer ?? undefined,
1945
+ boardRefreshGate,
1988
1946
  });
1947
+ gateways.push({ stop: async () => apiRoutesHandle.stop() });
1989
1948
  // ── Stage-2 boot pass (plan S2-T3): runtime assembly registered hooks;
1990
1949
  // recovery/cleanup run after routes are ready, then the consumer starts.
1991
1950
  const temporalBoot = temporalAssembly.bootAfterRoutes();