@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.
- package/CHANGELOG.md +22 -0
- package/README.md +3 -1
- package/dist/agent/agent-loop.d.ts +0 -3
- package/dist/agent/agent-loop.d.ts.map +1 -1
- package/dist/agent/agent-loop.js +49 -34
- package/dist/agent/agent-loop.js.map +1 -1
- package/dist/agent/gateway-tool-executor.d.ts +18 -0
- package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
- package/dist/agent/gateway-tool-executor.js +185 -6
- package/dist/agent/gateway-tool-executor.js.map +1 -1
- package/dist/agent/gateway-tools.md +10 -5
- package/dist/agent/role-manager.d.ts +22 -1
- package/dist/agent/role-manager.d.ts.map +1 -1
- package/dist/agent/role-manager.js +39 -2
- package/dist/agent/role-manager.js.map +1 -1
- package/dist/agent/tool-registry.d.ts.map +1 -1
- package/dist/agent/tool-registry.js +35 -5
- package/dist/agent/tool-registry.js.map +1 -1
- package/dist/agent/types.d.ts +9 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/api/graph-api.d.ts.map +1 -1
- package/dist/api/graph-api.js +43 -33
- package/dist/api/graph-api.js.map +1 -1
- package/dist/api/operator-tasks-handler.d.ts.map +1 -1
- package/dist/api/operator-tasks-handler.js +6 -2
- package/dist/api/operator-tasks-handler.js.map +1 -1
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +185 -2
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/config/config-manager.d.ts +0 -5
- package/dist/cli/config/config-manager.d.ts.map +1 -1
- package/dist/cli/config/config-manager.js +57 -2
- package/dist/cli/config/config-manager.js.map +1 -1
- package/dist/cli/config/types.d.ts.map +1 -1
- package/dist/cli/config/types.js +35 -0
- package/dist/cli/config/types.js.map +1 -1
- package/dist/cli/runtime/agent-loop-init.d.ts.map +1 -1
- package/dist/cli/runtime/agent-loop-init.js +96 -51
- package/dist/cli/runtime/agent-loop-init.js.map +1 -1
- package/dist/cli/runtime/api-routes-init.d.ts +3 -0
- package/dist/cli/runtime/api-routes-init.d.ts.map +1 -1
- package/dist/cli/runtime/api-routes-init.js +293 -196
- package/dist/cli/runtime/api-routes-init.js.map +1 -1
- package/dist/cli/runtime/gateway-init.d.ts.map +1 -1
- package/dist/cli/runtime/gateway-init.js +5 -0
- package/dist/cli/runtime/gateway-init.js.map +1 -1
- package/dist/cli/runtime/gateway-wiring.d.ts.map +1 -1
- package/dist/cli/runtime/gateway-wiring.js +6 -0
- package/dist/cli/runtime/gateway-wiring.js.map +1 -1
- package/dist/envelope/reactive-config.d.ts.map +1 -1
- package/dist/envelope/reactive-config.js +26 -1
- package/dist/envelope/reactive-config.js.map +1 -1
- package/dist/gateways/message-router.d.ts +18 -1
- package/dist/gateways/message-router.d.ts.map +1 -1
- package/dist/gateways/message-router.js +155 -22
- package/dist/gateways/message-router.js.map +1 -1
- package/dist/gateways/telegram.d.ts +1 -0
- package/dist/gateways/telegram.d.ts.map +1 -1
- package/dist/gateways/telegram.js +38 -1
- package/dist/gateways/telegram.js.map +1 -1
- package/dist/gateways/types.d.ts +3 -0
- package/dist/gateways/types.d.ts.map +1 -1
- package/dist/memory/history-extractor.d.ts +0 -24
- package/dist/memory/history-extractor.d.ts.map +1 -1
- package/dist/memory/history-extractor.js +0 -127
- package/dist/memory/history-extractor.js.map +1 -1
- package/dist/memory/save-candidate-extractor.d.ts +3 -0
- package/dist/memory/save-candidate-extractor.d.ts.map +1 -1
- package/dist/memory/save-candidate-extractor.js +12 -1
- package/dist/memory/save-candidate-extractor.js.map +1 -1
- package/dist/memory/secret-filter.d.ts +22 -0
- package/dist/memory/secret-filter.d.ts.map +1 -0
- package/dist/memory/secret-filter.js +77 -0
- package/dist/memory/secret-filter.js.map +1 -0
- package/dist/observability/code-audit.d.ts +87 -0
- package/dist/observability/code-audit.d.ts.map +1 -0
- package/dist/observability/code-audit.js +403 -0
- package/dist/observability/code-audit.js.map +1 -0
- package/dist/operator/briefs.d.ts +26 -0
- package/dist/operator/briefs.d.ts.map +1 -0
- package/dist/operator/briefs.js +128 -0
- package/dist/operator/briefs.js.map +1 -0
- package/dist/operator/operator-trigger-loop.d.ts +24 -0
- package/dist/operator/operator-trigger-loop.d.ts.map +1 -1
- package/dist/operator/operator-trigger-loop.js +71 -12
- package/dist/operator/operator-trigger-loop.js.map +1 -1
- package/dist/operator/report-carry.d.ts +29 -0
- package/dist/operator/report-carry.d.ts.map +1 -0
- package/dist/operator/report-carry.js +81 -0
- package/dist/operator/report-carry.js.map +1 -0
- package/dist/operator/shadow-capture.d.ts +20 -0
- package/dist/operator/shadow-capture.d.ts.map +1 -0
- package/dist/operator/shadow-capture.js +34 -0
- package/dist/operator/shadow-capture.js.map +1 -0
- package/dist/operator/situation-report.d.ts +6 -0
- package/dist/operator/situation-report.d.ts.map +1 -1
- package/dist/operator/situation-report.js +15 -1
- package/dist/operator/situation-report.js.map +1 -1
- package/dist/operator/task-ledger.d.ts +90 -2
- package/dist/operator/task-ledger.d.ts.map +1 -1
- package/dist/operator/task-ledger.js +359 -23
- package/dist/operator/task-ledger.js.map +1 -1
- package/dist/operator/worker-run.d.ts +59 -0
- package/dist/operator/worker-run.d.ts.map +1 -0
- package/dist/operator/worker-run.js +64 -0
- package/dist/operator/worker-run.js.map +1 -0
- package/dist/operator/workorder-consumer.d.ts +118 -0
- package/dist/operator/workorder-consumer.d.ts.map +1 -0
- package/dist/operator/workorder-consumer.js +248 -0
- package/dist/operator/workorder-consumer.js.map +1 -0
- package/dist/operator/workorder-hooks.d.ts +30 -0
- package/dist/operator/workorder-hooks.d.ts.map +1 -0
- package/dist/operator/workorder-hooks.js +70 -0
- package/dist/operator/workorder-hooks.js.map +1 -0
- package/dist/operator/workorder-publishers.d.ts +68 -0
- package/dist/operator/workorder-publishers.d.ts.map +1 -0
- package/dist/operator/workorder-publishers.js +150 -0
- package/dist/operator/workorder-publishers.js.map +1 -0
- package/dist/security/security-monitor.d.ts +19 -0
- package/dist/security/security-monitor.d.ts.map +1 -1
- package/dist/security/security-monitor.js +68 -14
- package/dist/security/security-monitor.js.map +1 -1
- package/dist/utils/untrusted-content.d.ts +31 -0
- package/dist/utils/untrusted-content.d.ts.map +1 -0
- package/dist/utils/untrusted-content.js +77 -0
- package/dist/utils/untrusted-content.js.map +1 -0
- 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"}
|