@jungjaehoon/mama-os 0.22.0 → 0.23.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 (128) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +3 -1
  3. package/dist/agent/agent-loop.d.ts +0 -3
  4. package/dist/agent/agent-loop.d.ts.map +1 -1
  5. package/dist/agent/agent-loop.js +49 -34
  6. package/dist/agent/agent-loop.js.map +1 -1
  7. package/dist/agent/gateway-tool-executor.d.ts +18 -0
  8. package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
  9. package/dist/agent/gateway-tool-executor.js +185 -6
  10. package/dist/agent/gateway-tool-executor.js.map +1 -1
  11. package/dist/agent/gateway-tools.md +10 -5
  12. package/dist/agent/role-manager.d.ts +22 -1
  13. package/dist/agent/role-manager.d.ts.map +1 -1
  14. package/dist/agent/role-manager.js +39 -2
  15. package/dist/agent/role-manager.js.map +1 -1
  16. package/dist/agent/tool-registry.d.ts.map +1 -1
  17. package/dist/agent/tool-registry.js +35 -5
  18. package/dist/agent/tool-registry.js.map +1 -1
  19. package/dist/agent/types.d.ts +9 -1
  20. package/dist/agent/types.d.ts.map +1 -1
  21. package/dist/agent/types.js.map +1 -1
  22. package/dist/api/graph-api.d.ts.map +1 -1
  23. package/dist/api/graph-api.js +43 -33
  24. package/dist/api/graph-api.js.map +1 -1
  25. package/dist/api/operator-tasks-handler.d.ts.map +1 -1
  26. package/dist/api/operator-tasks-handler.js +6 -2
  27. package/dist/api/operator-tasks-handler.js.map +1 -1
  28. package/dist/cli/commands/start.d.ts.map +1 -1
  29. package/dist/cli/commands/start.js +185 -2
  30. package/dist/cli/commands/start.js.map +1 -1
  31. package/dist/cli/config/config-manager.d.ts +0 -5
  32. package/dist/cli/config/config-manager.d.ts.map +1 -1
  33. package/dist/cli/config/config-manager.js +57 -2
  34. package/dist/cli/config/config-manager.js.map +1 -1
  35. package/dist/cli/config/types.d.ts.map +1 -1
  36. package/dist/cli/config/types.js +35 -0
  37. package/dist/cli/config/types.js.map +1 -1
  38. package/dist/cli/runtime/agent-loop-init.d.ts.map +1 -1
  39. package/dist/cli/runtime/agent-loop-init.js +96 -51
  40. package/dist/cli/runtime/agent-loop-init.js.map +1 -1
  41. package/dist/cli/runtime/api-routes-init.d.ts +3 -0
  42. package/dist/cli/runtime/api-routes-init.d.ts.map +1 -1
  43. package/dist/cli/runtime/api-routes-init.js +293 -196
  44. package/dist/cli/runtime/api-routes-init.js.map +1 -1
  45. package/dist/cli/runtime/gateway-init.d.ts.map +1 -1
  46. package/dist/cli/runtime/gateway-init.js +5 -0
  47. package/dist/cli/runtime/gateway-init.js.map +1 -1
  48. package/dist/cli/runtime/gateway-wiring.d.ts.map +1 -1
  49. package/dist/cli/runtime/gateway-wiring.js +6 -0
  50. package/dist/cli/runtime/gateway-wiring.js.map +1 -1
  51. package/dist/envelope/reactive-config.d.ts.map +1 -1
  52. package/dist/envelope/reactive-config.js +26 -1
  53. package/dist/envelope/reactive-config.js.map +1 -1
  54. package/dist/gateways/message-router.d.ts +18 -1
  55. package/dist/gateways/message-router.d.ts.map +1 -1
  56. package/dist/gateways/message-router.js +155 -22
  57. package/dist/gateways/message-router.js.map +1 -1
  58. package/dist/gateways/telegram.d.ts +1 -0
  59. package/dist/gateways/telegram.d.ts.map +1 -1
  60. package/dist/gateways/telegram.js +38 -1
  61. package/dist/gateways/telegram.js.map +1 -1
  62. package/dist/gateways/types.d.ts +3 -0
  63. package/dist/gateways/types.d.ts.map +1 -1
  64. package/dist/memory/history-extractor.d.ts +0 -24
  65. package/dist/memory/history-extractor.d.ts.map +1 -1
  66. package/dist/memory/history-extractor.js +0 -127
  67. package/dist/memory/history-extractor.js.map +1 -1
  68. package/dist/memory/save-candidate-extractor.d.ts +3 -0
  69. package/dist/memory/save-candidate-extractor.d.ts.map +1 -1
  70. package/dist/memory/save-candidate-extractor.js +12 -1
  71. package/dist/memory/save-candidate-extractor.js.map +1 -1
  72. package/dist/memory/secret-filter.d.ts +22 -0
  73. package/dist/memory/secret-filter.d.ts.map +1 -0
  74. package/dist/memory/secret-filter.js +77 -0
  75. package/dist/memory/secret-filter.js.map +1 -0
  76. package/dist/observability/code-audit.d.ts +87 -0
  77. package/dist/observability/code-audit.d.ts.map +1 -0
  78. package/dist/observability/code-audit.js +403 -0
  79. package/dist/observability/code-audit.js.map +1 -0
  80. package/dist/operator/briefs.d.ts +26 -0
  81. package/dist/operator/briefs.d.ts.map +1 -0
  82. package/dist/operator/briefs.js +128 -0
  83. package/dist/operator/briefs.js.map +1 -0
  84. package/dist/operator/operator-trigger-loop.d.ts +24 -0
  85. package/dist/operator/operator-trigger-loop.d.ts.map +1 -1
  86. package/dist/operator/operator-trigger-loop.js +71 -12
  87. package/dist/operator/operator-trigger-loop.js.map +1 -1
  88. package/dist/operator/report-carry.d.ts +29 -0
  89. package/dist/operator/report-carry.d.ts.map +1 -0
  90. package/dist/operator/report-carry.js +81 -0
  91. package/dist/operator/report-carry.js.map +1 -0
  92. package/dist/operator/shadow-capture.d.ts +20 -0
  93. package/dist/operator/shadow-capture.d.ts.map +1 -0
  94. package/dist/operator/shadow-capture.js +34 -0
  95. package/dist/operator/shadow-capture.js.map +1 -0
  96. package/dist/operator/situation-report.d.ts +6 -0
  97. package/dist/operator/situation-report.d.ts.map +1 -1
  98. package/dist/operator/situation-report.js +15 -1
  99. package/dist/operator/situation-report.js.map +1 -1
  100. package/dist/operator/task-ledger.d.ts +90 -2
  101. package/dist/operator/task-ledger.d.ts.map +1 -1
  102. package/dist/operator/task-ledger.js +359 -23
  103. package/dist/operator/task-ledger.js.map +1 -1
  104. package/dist/operator/worker-run.d.ts +59 -0
  105. package/dist/operator/worker-run.d.ts.map +1 -0
  106. package/dist/operator/worker-run.js +64 -0
  107. package/dist/operator/worker-run.js.map +1 -0
  108. package/dist/operator/workorder-consumer.d.ts +118 -0
  109. package/dist/operator/workorder-consumer.d.ts.map +1 -0
  110. package/dist/operator/workorder-consumer.js +248 -0
  111. package/dist/operator/workorder-consumer.js.map +1 -0
  112. package/dist/operator/workorder-hooks.d.ts +30 -0
  113. package/dist/operator/workorder-hooks.d.ts.map +1 -0
  114. package/dist/operator/workorder-hooks.js +70 -0
  115. package/dist/operator/workorder-hooks.js.map +1 -0
  116. package/dist/operator/workorder-publishers.d.ts +68 -0
  117. package/dist/operator/workorder-publishers.d.ts.map +1 -0
  118. package/dist/operator/workorder-publishers.js +150 -0
  119. package/dist/operator/workorder-publishers.js.map +1 -0
  120. package/dist/security/security-monitor.d.ts +19 -0
  121. package/dist/security/security-monitor.d.ts.map +1 -1
  122. package/dist/security/security-monitor.js +68 -14
  123. package/dist/security/security-monitor.js.map +1 -1
  124. package/dist/utils/untrusted-content.d.ts +31 -0
  125. package/dist/utils/untrusted-content.d.ts.map +1 -0
  126. package/dist/utils/untrusted-content.js +77 -0
  127. package/dist/utils/untrusted-content.js.map +1 -0
  128. package/package.json +2 -2
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ /**
3
+ * workerRun - the operator's worker primitive (plan: owner-console v6 S0-T1).
4
+ *
5
+ * A worker is NOT a standing agent identity and NOT a delegate/native-Task
6
+ * subagent: it is a briefed, FRESH-session lane run - the same substrate the
7
+ * report lane already uses (LaneManager serialization, loud failure, result
8
+ * returned to the caller, gateway calls audited).
9
+ *
10
+ * CALLER CONTRACT (deadlock seal):
11
+ * - Callers must be HOST CODE running OUTSIDE any lane (scheduler ticks,
12
+ * work-order consumers, forwarder hooks).
13
+ * - NEVER call workerRun from inside an active lane run (an LLM run's tool
14
+ * handler, a report run, another worker): the parent holds its global lane
15
+ * slot for its whole duration, so a nested awaited lane run can queue
16
+ * behind its own parent forever.
17
+ *
18
+ * Concurrency: same-kind runs serialize on the `operator:worker:<kind>`
19
+ * session lane; ALL operator work (reports + workers) serializes on the
20
+ * 'operator' global lane, which is separate from chat 'main' so long worker
21
+ * runs never block owner replies.
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.buildWorkerSessionKey = buildWorkerSessionKey;
25
+ exports.workerRun = workerRun;
26
+ const KIND_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
27
+ function buildWorkerSessionKey(kind) {
28
+ return `operator:worker:${kind}`;
29
+ }
30
+ /**
31
+ * Run a briefed worker on its own operator lane and return its output.
32
+ * Throws loudly on invalid input, runner failure, or an empty response -
33
+ * a worker never ends silently.
34
+ */
35
+ async function workerRun(runner, { kind, brief, input, runOptions }) {
36
+ if (!KIND_PATTERN.test(kind)) {
37
+ throw new Error(`[worker-run] invalid worker kind "${kind}" (expected kebab-case)`);
38
+ }
39
+ if (!brief.trim()) {
40
+ throw new Error(`[worker-run] empty brief for worker kind "${kind}"`);
41
+ }
42
+ if (!input.trim()) {
43
+ throw new Error(`[worker-run] empty input for worker kind "${kind}"`);
44
+ }
45
+ const prompt = `${brief.trim()}\n\n---\n\nWork order:\n${input.trim()}`;
46
+ const result = await runner.runWithContent([{ type: 'text', text: prompt }], {
47
+ // runOptions FIRST: identity fields below always win (plan E7/G3).
48
+ ...(runOptions ?? {}),
49
+ sessionKey: buildWorkerSessionKey(kind),
50
+ // freshSession pool reset keys on source+channelId (agent-loop.ts) -
51
+ // both MUST be explicit per call or another lane's pool entry gets reset.
52
+ source: 'operator',
53
+ channelId: `worker:${kind}`,
54
+ // Workers are stateless: continuity lives in the brief + artifacts,
55
+ // never in session accumulation (owner principle: session = cache).
56
+ freshSession: true,
57
+ });
58
+ const response = result.response?.trim();
59
+ if (!response) {
60
+ throw new Error(`[worker-run] worker "${kind}" returned an empty response`);
61
+ }
62
+ return response;
63
+ }
64
+ //# sourceMappingURL=worker-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-run.js","sourceRoot":"","sources":["../../src/operator/worker-run.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;AAwCH,sDAEC;AAOD,8BAkCC;AA7CD,MAAM,YAAY,GAAG,iCAAiC,CAAC;AAEvD,SAAgB,qBAAqB,CAAC,IAAY;IAChD,OAAO,mBAAmB,IAAI,EAAE,CAAC;AACnC,CAAC;AAED;;;;GAIG;AACI,KAAK,UAAU,SAAS,CAC7B,MAAoB,EACpB,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAkB;IAElD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,qCAAqC,IAAI,yBAAyB,CAAC,CAAC;IACtF,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,6CAA6C,IAAI,GAAG,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,6CAA6C,IAAI,GAAG,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,2BAA2B,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;IAExE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE;QAC3E,mEAAmE;QACnE,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC;QACrB,UAAU,EAAE,qBAAqB,CAAC,IAAI,CAAC;QACvC,qEAAqE;QACrE,0EAA0E;QAC1E,MAAM,EAAE,UAAU;QAClB,SAAS,EAAE,UAAU,IAAI,EAAE;QAC3B,oEAAoE;QACpE,oEAAoE;QACpE,YAAY,EAAE,IAAI;KACnB,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;IACzC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,8BAA8B,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * WorkOrderConsumer - the single host-code consumer of system workorders
3
+ * (Stage 2, plan S2-T3).
4
+ *
5
+ * A dedicated interval timer (60s default) claims pending workorders from the
6
+ * TaskLedger and runs each through workerRun on the operator lane. It runs
7
+ * UNCONDITIONALLY of MAMA_TRIGGER_LOOP (the publishers are unconditional, so
8
+ * coupling consumption to an opt-in loop would strand every workorder - plan
9
+ * A1 BLOCKER), gated only by MAMA_STAGE2_WORKORDERS=shadow|on.
10
+ *
11
+ * Serial consumption: one claim at a time, awaited to completion, with a tick
12
+ * re-entrancy guard (a 260s board run spans 4+ ticks - overlapping ticks skip,
13
+ * plan G4). Blocking bound = the runner's per-request timeout x maxTurns; no
14
+ * consumer-level watchdog (plan N2).
15
+ *
16
+ * Failure policy (plan G5/M4): failWorkOrder marks the row, then per-kind
17
+ * maxAttempts decides requeue (fresh row, attempts+1, same occurrence key)
18
+ * vs retries-exhausted (owner alarm, deduped per kind). Boot recovery routes
19
+ * stale in_progress claims (crash artifacts) through the SAME policy, with a
20
+ * separate stale-claim alarm.
21
+ *
22
+ * Completion hooks (plan E3/E4): per-kind before/after seams re-home the
23
+ * post-run host effects the legacy closures owned (board bracket
24
+ * verification, promotion event re-emission, wiki noUpdate reading). Hook
25
+ * errors are LOUD but never fail a completed run (observe, never block).
26
+ */
27
+ import type { WorkOrderKind, WorkOrderRecord, EnqueueWorkOrderInput } from './task-ledger.js';
28
+ import { type WorkerRunner } from './worker-run.js';
29
+ export interface WorkOrderLedgerPort {
30
+ claimNextWorkOrder(): WorkOrderRecord | null;
31
+ completeWorkOrder(id: number): void;
32
+ failWorkOrder(id: number, reason: string): void;
33
+ /** Atomic fail+replacement (retry) - one transaction (PR bot round). */
34
+ requeueWorkOrder(wo: WorkOrderRecord, reason: string): WorkOrderRecord;
35
+ enqueueWorkOrder(order: EnqueueWorkOrderInput): WorkOrderRecord;
36
+ listStaleClaims(): WorkOrderRecord[];
37
+ countPendingWorkOrders(): number;
38
+ }
39
+ /** Active owner alarm channel (telegram via the ops sink; may be unconfigured). */
40
+ export interface OpsAlarmSink {
41
+ configured: boolean;
42
+ send(line: string): Promise<void>;
43
+ }
44
+ export interface WorkOrderHook {
45
+ /** Bracket 'before' state (e.g. verifier snapshot at claim time). */
46
+ before?: (wo: WorkOrderRecord) => unknown;
47
+ /** Post-run effects (verification, event re-emission, outcome reading). */
48
+ after?: (wo: WorkOrderRecord, response: string, beforeState: unknown) => void;
49
+ }
50
+ export interface WorkOrderConsumerEvent {
51
+ type: 'complete' | 'failed' | 'requeued' | 'exhausted' | 'stale-claim';
52
+ workKind: WorkOrderKind;
53
+ workOrderId: number;
54
+ reason?: string;
55
+ }
56
+ export interface WorkOrderConsumerDeps {
57
+ ledger: WorkOrderLedgerPort;
58
+ runner: WorkerRunner;
59
+ /** null = brief missing -> the workorder fails loudly (never a silent skip). */
60
+ loadBrief: (kind: WorkOrderKind) => string | null;
61
+ /** Passive owner surface (AgentNoticeQueue via MessageRouter accessor). */
62
+ noticeOwner: (summary: string) => void;
63
+ opsAlarm: OpsAlarmSink;
64
+ /** Telemetry seam (agent_activity / eventBus) - optional. */
65
+ onEvent?: (event: WorkOrderConsumerEvent) => void;
66
+ /**
67
+ * Per-order extra run options (Stage-2 shadow: the board capture-publisher
68
+ * override). A THROW here fails the order loudly - at shadow, a missing
69
+ * capture publisher must never fall through to a live publish (plan T4 AC).
70
+ */
71
+ runOptionsFor?: (wo: WorkOrderRecord) => Record<string, unknown> | undefined;
72
+ log?: (line: string) => void;
73
+ tickMs?: number;
74
+ now?: () => number;
75
+ }
76
+ /** Per-kind retry budget: attempts start at 1; board/promotion self-heal on
77
+ * the next publish cycle, wiki events do not re-fire so it retries once. */
78
+ export declare const WORKORDER_MAX_ATTEMPTS: Record<WorkOrderKind, number>;
79
+ export declare class WorkOrderConsumer {
80
+ private readonly deps;
81
+ private readonly hooks;
82
+ private readonly lastAlarmAt;
83
+ private timer;
84
+ private consuming;
85
+ private activeTick;
86
+ constructor(deps: WorkOrderConsumerDeps);
87
+ registerHook(kind: WorkOrderKind, hook: WorkOrderHook): void;
88
+ /**
89
+ * Boot recovery (plan C4/M4): in_progress system rows are crash artifacts
90
+ * (single serial consumer). Each routes through the SAME failure policy
91
+ * (a crashed wiki batch requeues once; board/promotion do not), plus a
92
+ * separate stale-claim alarm.
93
+ */
94
+ bootRecover(): void;
95
+ start(): void;
96
+ isStarted(): boolean;
97
+ /** Graceful: awaits an in-flight tick so shutdown does not race the
98
+ * operator-DB close into "database is not open" noise (review m4). */
99
+ stop(): Promise<void>;
100
+ /**
101
+ * Drain pending workorders serially: claim -> await -> next claim. Returns
102
+ * 'skipped' when a previous tick is still consuming (re-entrancy guard,
103
+ * plan G4) - long runs span multiple tick firings.
104
+ */
105
+ tick(): Promise<'drained' | 'skipped'>;
106
+ private runOne;
107
+ /**
108
+ * Failure policy layer (plan G5): mark failed, then requeue (attempts+1,
109
+ * fresh row, same occurrence key - the terminal row freed it) or declare
110
+ * retries-exhausted with an owner alarm.
111
+ */
112
+ private handleFailure;
113
+ /** Owner alarm: passive notice + active telegram, deduped per kind (6h). */
114
+ private alarm;
115
+ private emitEvent;
116
+ private log;
117
+ }
118
+ //# sourceMappingURL=workorder-consumer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workorder-consumer.d.ts","sourceRoot":"","sources":["../../src/operator/workorder-consumer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,248 @@
1
+ "use strict";
2
+ /**
3
+ * WorkOrderConsumer - the single host-code consumer of system workorders
4
+ * (Stage 2, plan S2-T3).
5
+ *
6
+ * A dedicated interval timer (60s default) claims pending workorders from the
7
+ * TaskLedger and runs each through workerRun on the operator lane. It runs
8
+ * UNCONDITIONALLY of MAMA_TRIGGER_LOOP (the publishers are unconditional, so
9
+ * coupling consumption to an opt-in loop would strand every workorder - plan
10
+ * A1 BLOCKER), gated only by MAMA_STAGE2_WORKORDERS=shadow|on.
11
+ *
12
+ * Serial consumption: one claim at a time, awaited to completion, with a tick
13
+ * re-entrancy guard (a 260s board run spans 4+ ticks - overlapping ticks skip,
14
+ * plan G4). Blocking bound = the runner's per-request timeout x maxTurns; no
15
+ * consumer-level watchdog (plan N2).
16
+ *
17
+ * Failure policy (plan G5/M4): failWorkOrder marks the row, then per-kind
18
+ * maxAttempts decides requeue (fresh row, attempts+1, same occurrence key)
19
+ * vs retries-exhausted (owner alarm, deduped per kind). Boot recovery routes
20
+ * stale in_progress claims (crash artifacts) through the SAME policy, with a
21
+ * separate stale-claim alarm.
22
+ *
23
+ * Completion hooks (plan E3/E4): per-kind before/after seams re-home the
24
+ * post-run host effects the legacy closures owned (board bracket
25
+ * verification, promotion event re-emission, wiki noUpdate reading). Hook
26
+ * errors are LOUD but never fail a completed run (observe, never block).
27
+ */
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.WorkOrderConsumer = exports.WORKORDER_MAX_ATTEMPTS = void 0;
30
+ const worker_run_js_1 = require("./worker-run.js");
31
+ /** Per-kind retry budget: attempts start at 1; board/promotion self-heal on
32
+ * the next publish cycle, wiki events do not re-fire so it retries once. */
33
+ exports.WORKORDER_MAX_ATTEMPTS = {
34
+ board: 1,
35
+ wiki: 2,
36
+ 'memory-curation': 1,
37
+ };
38
+ const DEFAULT_TICK_MS = 60_000;
39
+ const ALARM_DEDUP_MS = 6 * 60 * 60 * 1000;
40
+ class WorkOrderConsumer {
41
+ deps;
42
+ hooks = new Map();
43
+ lastAlarmAt = new Map();
44
+ timer = null;
45
+ consuming = false;
46
+ activeTick = null;
47
+ constructor(deps) {
48
+ this.deps = deps;
49
+ }
50
+ registerHook(kind, hook) {
51
+ if (this.hooks.has(kind)) {
52
+ throw new Error(`[workorder-consumer] hook for '${kind}' already registered`);
53
+ }
54
+ this.hooks.set(kind, hook);
55
+ }
56
+ /**
57
+ * Boot recovery (plan C4/M4): in_progress system rows are crash artifacts
58
+ * (single serial consumer). Each routes through the SAME failure policy
59
+ * (a crashed wiki batch requeues once; board/promotion do not), plus a
60
+ * separate stale-claim alarm.
61
+ */
62
+ bootRecover() {
63
+ for (const wo of this.deps.ledger.listStaleClaims()) {
64
+ this.log(`[workorder-consumer] stale claim recovered: ${wo.workKind}#${wo.id}`);
65
+ this.emitEvent({ type: 'stale-claim', workKind: wo.workKind, workOrderId: wo.id });
66
+ this.alarm(wo.workKind, `workorder ${wo.workKind}#${wo.id} stale claim (daemon crash?)`);
67
+ this.handleFailure(wo, 'stale-claim');
68
+ }
69
+ }
70
+ start() {
71
+ if (this.timer) {
72
+ throw new Error('[workorder-consumer] already started');
73
+ }
74
+ const tickMs = this.deps.tickMs ?? DEFAULT_TICK_MS;
75
+ this.timer = setInterval(() => {
76
+ // Only track a REAL tick: during a long run subsequent firings resolve
77
+ // 'skipped' instantly and would OVERWRITE activeTick - stop() would
78
+ // then await the skipped promise while the true tick still runs and
79
+ // the DB closes under it (round-2 review N1).
80
+ if (!this.consuming) {
81
+ this.activeTick = this.tick();
82
+ }
83
+ }, tickMs);
84
+ this.timer.unref?.();
85
+ this.log(`[workorder-consumer] started (tick every ${tickMs}ms)`);
86
+ }
87
+ isStarted() {
88
+ return this.timer !== null;
89
+ }
90
+ /** Graceful: awaits an in-flight tick so shutdown does not race the
91
+ * operator-DB close into "database is not open" noise (review m4). */
92
+ async stop() {
93
+ if (this.timer) {
94
+ clearInterval(this.timer);
95
+ this.timer = null;
96
+ }
97
+ if (this.activeTick) {
98
+ await this.activeTick.catch(() => { });
99
+ this.activeTick = null;
100
+ }
101
+ }
102
+ /**
103
+ * Drain pending workorders serially: claim -> await -> next claim. Returns
104
+ * 'skipped' when a previous tick is still consuming (re-entrancy guard,
105
+ * plan G4) - long runs span multiple tick firings.
106
+ */
107
+ async tick() {
108
+ if (this.consuming)
109
+ return 'skipped';
110
+ this.consuming = true;
111
+ try {
112
+ // Drain is BOUNDED by the pending count at tick start: a row requeued
113
+ // by this tick's failure policy waits for the NEXT tick (natural
114
+ // backoff - otherwise a failing order retries in a tight loop).
115
+ let remaining = this.deps.ledger.countPendingWorkOrders();
116
+ while (remaining > 0) {
117
+ const wo = this.deps.ledger.claimNextWorkOrder();
118
+ if (!wo)
119
+ break;
120
+ await this.runOne(wo);
121
+ remaining--;
122
+ }
123
+ return 'drained';
124
+ }
125
+ finally {
126
+ this.consuming = false;
127
+ }
128
+ }
129
+ async runOne(wo) {
130
+ let brief;
131
+ try {
132
+ brief = this.deps.loadBrief(wo.workKind);
133
+ }
134
+ catch (err) {
135
+ // I/O errors (permissions etc.) must fail THIS order, not abort the
136
+ // whole tick with a stranded claim (PR bot round).
137
+ this.handleFailure(wo, `brief-load-failed: ${errMessage(err)}`);
138
+ return;
139
+ }
140
+ if (!brief || !brief.trim()) {
141
+ this.log(`[workorder-consumer] brief missing for '${wo.workKind}' - failing #${wo.id}`);
142
+ this.handleFailure(wo, 'brief-missing');
143
+ return;
144
+ }
145
+ const hook = this.hooks.get(wo.workKind);
146
+ let beforeState;
147
+ if (hook?.before) {
148
+ try {
149
+ beforeState = hook.before(wo);
150
+ }
151
+ catch (err) {
152
+ // A broken before-hook must not strand the claim: fail the order loudly.
153
+ this.handleFailure(wo, `before-hook: ${errMessage(err)}`);
154
+ return;
155
+ }
156
+ }
157
+ let response;
158
+ try {
159
+ response = await (0, worker_run_js_1.workerRun)(this.deps.runner, {
160
+ kind: wo.workKind,
161
+ brief,
162
+ input: JSON.stringify(wo.payload),
163
+ // Inside the try: a runOptionsFor throw (e.g. shadow capture publisher
164
+ // missing) fails the order instead of running with the live publisher.
165
+ runOptions: this.deps.runOptionsFor?.(wo),
166
+ });
167
+ }
168
+ catch (err) {
169
+ this.handleFailure(wo, errMessage(err));
170
+ return;
171
+ }
172
+ if (hook?.after) {
173
+ try {
174
+ hook.after(wo, response, beforeState);
175
+ }
176
+ catch (err) {
177
+ // Observe, never block: a verification/emission failure is loud but
178
+ // does not fail a run that completed.
179
+ this.log(`[workorder-consumer] after-hook error (${wo.workKind}#${wo.id}): ${errMessage(err)}`);
180
+ }
181
+ }
182
+ this.deps.ledger.completeWorkOrder(wo.id);
183
+ this.emitEvent({ type: 'complete', workKind: wo.workKind, workOrderId: wo.id });
184
+ this.log(`[workorder-consumer] completed ${wo.workKind}#${wo.id}`);
185
+ }
186
+ /**
187
+ * Failure policy layer (plan G5): mark failed, then requeue (attempts+1,
188
+ * fresh row, same occurrence key - the terminal row freed it) or declare
189
+ * retries-exhausted with an owner alarm.
190
+ */
191
+ handleFailure(wo, reason) {
192
+ const maxAttempts = exports.WORKORDER_MAX_ATTEMPTS[wo.workKind];
193
+ if (wo.payload.attempts < maxAttempts) {
194
+ // Atomic fail+requeue (PR bot round): a crash between separate fail and
195
+ // enqueue calls would silently lose the retry.
196
+ const requeued = this.deps.ledger.requeueWorkOrder(wo, reason);
197
+ this.emitEvent({ type: 'failed', workKind: wo.workKind, workOrderId: wo.id, reason });
198
+ this.emitEvent({ type: 'requeued', workKind: wo.workKind, workOrderId: requeued.id });
199
+ this.log(`[workorder-consumer] failed ${wo.workKind}#${wo.id} (${reason}) -> requeued #${requeued.id} (attempt ${wo.payload.attempts + 1}/${maxAttempts})`);
200
+ return;
201
+ }
202
+ this.deps.ledger.failWorkOrder(wo.id, reason);
203
+ this.emitEvent({ type: 'failed', workKind: wo.workKind, workOrderId: wo.id, reason });
204
+ this.log(`[workorder-consumer] failed ${wo.workKind}#${wo.id}: ${reason}`);
205
+ this.emitEvent({ type: 'exhausted', workKind: wo.workKind, workOrderId: wo.id, reason });
206
+ this.alarm(wo.workKind, `workorder ${wo.workKind}#${wo.id} retries exhausted (${wo.payload.attempts}/${maxAttempts}): ${reason}`);
207
+ }
208
+ /** Owner alarm: passive notice + active telegram, deduped per kind (6h). */
209
+ alarm(kind, message) {
210
+ const now = this.deps.now?.() ?? Date.now();
211
+ const last = this.lastAlarmAt.get(kind);
212
+ if (last !== undefined && now - last < ALARM_DEDUP_MS) {
213
+ this.log(`[workorder-consumer] alarm deduped (${kind}): ${message}`);
214
+ return;
215
+ }
216
+ this.lastAlarmAt.set(kind, now);
217
+ try {
218
+ this.deps.noticeOwner(message);
219
+ }
220
+ catch (err) {
221
+ this.log(`[workorder-consumer] notice enqueue failed: ${errMessage(err)}`);
222
+ }
223
+ if (this.deps.opsAlarm.configured) {
224
+ void this.deps.opsAlarm.send(`⚠️ ${message}`).catch((err) => {
225
+ this.log(`[workorder-consumer] active alarm send failed: ${errMessage(err)}`);
226
+ });
227
+ }
228
+ else {
229
+ this.log(`[workorder-consumer] active alarm unconfigured - log-only: ${message}`);
230
+ }
231
+ }
232
+ emitEvent(event) {
233
+ try {
234
+ this.deps.onEvent?.(event);
235
+ }
236
+ catch {
237
+ /* telemetry only */
238
+ }
239
+ }
240
+ log(line) {
241
+ (this.deps.log ?? console.log)(line);
242
+ }
243
+ }
244
+ exports.WorkOrderConsumer = WorkOrderConsumer;
245
+ function errMessage(err) {
246
+ return err instanceof Error ? err.message : String(err);
247
+ }
248
+ //# sourceMappingURL=workorder-consumer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workorder-consumer.js","sourceRoot":"","sources":["../../src/operator/workorder-consumer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Extracted, testable pieces of the Stage-2 per-kind completion hooks
3
+ * (plan S2-T3; extraction demanded by implementation review round 1 - the
4
+ * hook bodies lived in registerApiRoutes closures where nothing could prove
5
+ * them, which is the green-test-trap class the plan bans).
6
+ *
7
+ * - buildWorkerTraceQueries: the G1 re-keyed verifier trace queries. Worker
8
+ * runs log gateway_tool_call rows with the worker's identity, NOT
9
+ * agent_id='dashboard-agent'; the ONLY schema-supported key is the details
10
+ * JSON (agent_activity has no channel_id column) - hence json_extract.
11
+ * - buildPromotionAfterHook: the PROMOTED <n> parse + event re-emission that
12
+ * keeps the memory:promoted -> wiki ingress chain alive (plan E4/R7).
13
+ * - buildWikiAfterHook: outcome reading only.
14
+ */
15
+ import type { SQLiteDatabase } from '../sqlite.js';
16
+ import type { WorkOrderRecord } from './task-ledger.js';
17
+ export interface WorkerTraceQueries {
18
+ getTraceMaxId: () => number;
19
+ countObligatedTraceRowsSince: (maxId: number) => number;
20
+ }
21
+ export declare function buildWorkerTraceQueries(sessionsDb: SQLiteDatabase | undefined, workerChannelId: string): WorkerTraceQueries;
22
+ export interface PromotionHookEvents {
23
+ emitAgentAction: (action: 'promoted' | 'no_update', target: string) => void;
24
+ emitMemoryPromoted: (saved: number) => void;
25
+ log?: (line: string) => void;
26
+ }
27
+ /** The wiki ingress chain's second link: losing this parse severs memory:promoted. */
28
+ export declare function buildPromotionAfterHook(events: PromotionHookEvents): (wo: WorkOrderRecord, response: string) => void;
29
+ export declare function buildWikiAfterHook(log: (line: string) => void): (wo: WorkOrderRecord, response: string) => void;
30
+ //# sourceMappingURL=workorder-hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workorder-hooks.d.ts","sourceRoot":"","sources":["../../src/operator/workorder-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAIxD,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,MAAM,CAAC;IAC5B,4BAA4B,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CACzD;AAED,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,cAAc,GAAG,SAAS,EACtC,eAAe,EAAE,MAAM,GACtB,kBAAkB,CA0BpB;AAED,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5E,kBAAkB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,sFAAsF;AACtF,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,mBAAmB,GAC1B,CAAC,EAAE,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAcjD;AAED,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC1B,CAAC,EAAE,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAQjD"}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ /**
3
+ * Extracted, testable pieces of the Stage-2 per-kind completion hooks
4
+ * (plan S2-T3; extraction demanded by implementation review round 1 - the
5
+ * hook bodies lived in registerApiRoutes closures where nothing could prove
6
+ * them, which is the green-test-trap class the plan bans).
7
+ *
8
+ * - buildWorkerTraceQueries: the G1 re-keyed verifier trace queries. Worker
9
+ * runs log gateway_tool_call rows with the worker's identity, NOT
10
+ * agent_id='dashboard-agent'; the ONLY schema-supported key is the details
11
+ * JSON (agent_activity has no channel_id column) - hence json_extract.
12
+ * - buildPromotionAfterHook: the PROMOTED <n> parse + event re-emission that
13
+ * keeps the memory:promoted -> wiki ingress chain alive (plan E4/R7).
14
+ * - buildWikiAfterHook: outcome reading only.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.buildWorkerTraceQueries = buildWorkerTraceQueries;
18
+ exports.buildPromotionAfterHook = buildPromotionAfterHook;
19
+ exports.buildWikiAfterHook = buildWikiAfterHook;
20
+ const action_verifier_js_1 = require("./action-verifier.js");
21
+ const TRACE_TOOL_LIST = action_verifier_js_1.OBLIGATED_TOOLS.map((t) => `'${t}'`).join(',');
22
+ function buildWorkerTraceQueries(sessionsDb, workerChannelId) {
23
+ return {
24
+ getTraceMaxId: () => {
25
+ if (!sessionsDb)
26
+ return 0;
27
+ const row = sessionsDb
28
+ .prepare(`SELECT MAX(id) AS max_id FROM agent_activity
29
+ WHERE type = 'gateway_tool_call'
30
+ AND json_extract(details, '$.channel_id') = ?`)
31
+ .get(workerChannelId);
32
+ return row.max_id ?? 0;
33
+ },
34
+ countObligatedTraceRowsSince: (maxId) => {
35
+ if (!sessionsDb)
36
+ return 0;
37
+ const row = sessionsDb
38
+ .prepare(`SELECT COUNT(*) AS n FROM agent_activity
39
+ WHERE type = 'gateway_tool_call'
40
+ AND json_extract(details, '$.channel_id') = ?
41
+ AND id > ? AND (normalized_tool_name IN (${TRACE_TOOL_LIST}) OR input_summary IN (${TRACE_TOOL_LIST}))`)
42
+ .get(workerChannelId, maxId);
43
+ return row.n;
44
+ },
45
+ };
46
+ }
47
+ /** The wiki ingress chain's second link: losing this parse severs memory:promoted. */
48
+ function buildPromotionAfterHook(events) {
49
+ return (_wo, response) => {
50
+ const promotedMatch = response.match(/PROMOTED\s+(\d+)/);
51
+ const saved = promotedMatch ? Number(promotedMatch[1]) : 0;
52
+ const noUpdate = response.includes('NO_UPDATE');
53
+ events.emitAgentAction(noUpdate || saved === 0 ? 'no_update' : 'promoted', `promotion run: ${saved} saved`);
54
+ if (saved > 0) {
55
+ events.emitMemoryPromoted(saved);
56
+ events.log?.(`[stage2] promotion worker: promoted ${saved} durable judgments`);
57
+ }
58
+ };
59
+ }
60
+ function buildWikiAfterHook(log) {
61
+ return (_wo, response) => {
62
+ if (response.includes('NO_UPDATE')) {
63
+ log('[stage2] wiki worker: no changes detected');
64
+ }
65
+ else {
66
+ log('[stage2] wiki worker: compilation complete');
67
+ }
68
+ };
69
+ }
70
+ //# sourceMappingURL=workorder-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workorder-hooks.js","sourceRoot":"","sources":["../../src/operator/workorder-hooks.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;AAaH,0DA6BC;AASD,0DAgBC;AAED,gDAUC;AA5ED,6DAAuD;AAGvD,MAAM,eAAe,GAAG,oCAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAOvE,SAAgB,uBAAuB,CACrC,UAAsC,EACtC,eAAuB;IAEvB,OAAO;QACL,aAAa,EAAE,GAAG,EAAE;YAClB,IAAI,CAAC,UAAU;gBAAE,OAAO,CAAC,CAAC;YAC1B,MAAM,GAAG,GAAG,UAAU;iBACnB,OAAO,CACN;;2DAEiD,CAClD;iBACA,GAAG,CAAC,eAAe,CAA8B,CAAC;YACrD,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;QACzB,CAAC;QACD,4BAA4B,EAAE,CAAC,KAAa,EAAE,EAAE;YAC9C,IAAI,CAAC,UAAU;gBAAE,OAAO,CAAC,CAAC;YAC1B,MAAM,GAAG,GAAG,UAAU;iBACnB,OAAO,CACN;;;wDAG8C,eAAe,0BAA0B,eAAe,IAAI,CAC3G;iBACA,GAAG,CAAC,eAAe,EAAE,KAAK,CAAkB,CAAC;YAChD,OAAO,GAAG,CAAC,CAAC,CAAC;QACf,CAAC;KACF,CAAC;AACJ,CAAC;AAQD,sFAAsF;AACtF,SAAgB,uBAAuB,CACrC,MAA2B;IAE3B,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE;QACvB,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAChD,MAAM,CAAC,eAAe,CACpB,QAAQ,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,EAClD,kBAAkB,KAAK,QAAQ,CAChC,CAAC;QACF,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACd,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YACjC,MAAM,CAAC,GAAG,EAAE,CAAC,uCAAuC,KAAK,oBAAoB,CAAC,CAAC;QACjF,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,kBAAkB,CAChC,GAA2B;IAE3B,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE;QACvB,IAAI,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YACnC,GAAG,CAAC,2CAA2C,CAAC,CAAC;QACnD,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,4CAA4C,CAAC,CAAC;QACpD,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Stage-2 publisher gate: pure decision + key/payload contracts for converting
3
+ * the three system-agent run paths (dashboard/wiki/promotion) and the
4
+ * reconcile leg into workorder enqueues.
5
+ *
6
+ * The gate decision is a PURE function (plan E5) so every flag x kind combo is
7
+ * unit-testable outside the api-routes-init closures. The wiring sites call
8
+ * resolvePublishAction and act on 'legacy' | 'enqueue' | 'both'.
9
+ *
10
+ * Flag: MAMA_STAGE2_WORKORDERS=off|shadow|on (tri-state; deliberate deviation
11
+ * from the repo's `=== '1'` convention - documented in configuration-options).
12
+ * off - legacy direct runs (current behavior)
13
+ * shadow - board ONLY dual-runs: legacy keeps publishing live AND the same
14
+ * occurrence is enqueued for the capture consumer. wiki/promotion
15
+ * stay pure legacy - their side effects (Obsidian writes, mama_save)
16
+ * have no capture seam and must never double-execute (plan B1/C2).
17
+ * on - all three kinds (and the reconcile leg) enqueue; legacy stops.
18
+ *
19
+ * Plan: docs/superpowers/plans/2026-07-18-stage2-workorder-ownership.md S2-T2
20
+ */
21
+ import type { WorkOrderKind } from './task-ledger.js';
22
+ export declare const STAGE2_FLAG_ENV = "MAMA_STAGE2_WORKORDERS";
23
+ export declare const STAGE2_FLAGS: readonly ["off", "shadow", "on"];
24
+ export type Stage2Flag = (typeof STAGE2_FLAGS)[number];
25
+ export type PublishAction = 'legacy' | 'enqueue' | 'both';
26
+ /**
27
+ * Parse the tri-state flag. Absent/empty -> 'off'. Any other value is a
28
+ * misconfiguration and throws at boot (no-fallback: a typo silently reverting
29
+ * to legacy would mask a believed-active migration).
30
+ */
31
+ export declare function readStage2Flag(env?: NodeJS.ProcessEnv): Stage2Flag;
32
+ /** Pure gate decision for the three scheduled/boot/manual run paths. */
33
+ export declare function resolvePublishAction(flag: Stage2Flag, kind: WorkOrderKind): PublishAction;
34
+ /**
35
+ * The reconcile leg converts at 'on' ONLY (plan: shadow/off keep the legacy
36
+ * bracket-verified path; its verification moves to the consumer hook at 'on').
37
+ */
38
+ export declare function resolveReconcileAction(flag: Stage2Flag): 'legacy' | 'enqueue';
39
+ export declare function boardFullKey(now: number): string;
40
+ /** Manual/forced orders get their own key (plan M2): a forced refresh must
41
+ * never dedup against a pending scheduled FULL that lacks force. */
42
+ export declare function boardManualKey(now: number): string;
43
+ export declare function boardReconcileKey(channelKey: string, now: number): string;
44
+ export declare function wikiBatchKey(trigger: string, now: number): string;
45
+ export declare function promotionKey(now: number): string;
46
+ export declare function promotionManualKey(now: number): string;
47
+ export interface BoardPayload {
48
+ mode: 'full' | 'reconcile';
49
+ /** Owner-forced refresh: brief must publish even on NO_UPDATE. */
50
+ force?: boolean;
51
+ channelKey?: string;
52
+ deltaLines?: string[];
53
+ }
54
+ export interface WikiPayload {
55
+ batchId: string;
56
+ /** Trigger provenance; the run does its own novelty check, events carry no content. */
57
+ events: string[];
58
+ }
59
+ export interface PromotionPayload {
60
+ scheduledAt: string;
61
+ }
62
+ /**
63
+ * Validate a payload at enqueue time. Unknown fields are rejected LOUDLY -
64
+ * a misspelled field silently dropped would surface as a wrong run later.
65
+ * (`attempts` is ledger-managed and allowed everywhere.)
66
+ */
67
+ export declare function validateWorkOrderPayload(kind: WorkOrderKind, payload: Record<string, unknown>): void;
68
+ //# sourceMappingURL=workorder-publishers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workorder-publishers.d.ts","sourceRoot":"","sources":["../../src/operator/workorder-publishers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,eAAO,MAAM,eAAe,2BAA2B,CAAC;AAExD,eAAO,MAAM,YAAY,kCAAmC,CAAC;AAC7D,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAE1D;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,UAAU,CAS/E;AAED,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,GAAG,aAAa,CAKzF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,SAAS,CAE7E;AAUD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;qEACqE;AACrE,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAOzE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAID,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,kEAAkE;IAClE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;CACrB;AAQD;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,IAAI,CA2CN"}