@ai-agent-forge/plugin-workflow 0.85.20
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/README.md +29 -0
- package/agent-forge.json +19 -0
- package/dist/engine.d.ts +130 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +925 -0
- package/dist/engine.js.map +1 -0
- package/dist/entry.d.ts +14 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +23 -0
- package/dist/entry.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +456 -0
- package/dist/index.js.map +1 -0
- package/dist/render.d.ts +20 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +128 -0
- package/dist/render.js.map +1 -0
- package/dist/types.d.ts +89 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +60 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +311 -0
- package/dist/validate.js.map +1 -0
- package/package.json +54 -0
- package/plugin.json +12 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow orchestration capability plugin (M1 of
|
|
3
|
+
* `docs/design/工作流编排插件设计.md`): a fourth self-contained state machine
|
|
4
|
+
* orchestrating a stage dependency graph on top of the goal/plan/todo layers.
|
|
5
|
+
*
|
|
6
|
+
* Persistence protocol, structurally identical to the goal/plan/todo plugins:
|
|
7
|
+
* append-only `workflow.state` full snapshots (the single rebuild source) plus
|
|
8
|
+
* one `workflow.transition` audit entry per conversion, announced as
|
|
9
|
+
* `workflow.changed` (version 1, correlationId "workflow.state", data = the
|
|
10
|
+
* complete WorkflowState snapshot).
|
|
11
|
+
*
|
|
12
|
+
* This plugin is the repository's FIRST event subscriber (§7): `plan.changed`
|
|
13
|
+
* is used as a trigger signal only — its in-memory data may be misaligned
|
|
14
|
+
* with the current branch, so every reevaluation reads the plan facts from
|
|
15
|
+
* the current branch entries. The handler is fully isolated (§5 总则 3): any
|
|
16
|
+
* failure lands in diagnostics + a `handler.error` transition and never
|
|
17
|
+
* rethrows at the publisher (an unisolated throw would pierce plan_set's tool
|
|
18
|
+
* return). Soft references (goalId / planId / role) never fail a write (#10):
|
|
19
|
+
* they surface as response warnings; a dangling planId additionally holds the
|
|
20
|
+
* stage's activation until a reevaluation finds the plan.
|
|
21
|
+
*/
|
|
22
|
+
import { Type } from "typebox";
|
|
23
|
+
import { applyAdvance, applyWorkflowSet, inspectWorkflow, reevaluateAll, } from "./engine.js";
|
|
24
|
+
import { renderLog, renderPanorama, renderWhy } from "./render.js";
|
|
25
|
+
import { WORKFLOW_STATE_ENTRY, WORKFLOW_TRANSITION_ENTRY, } from "./types.js";
|
|
26
|
+
import { asObject, asText, parseWorkflowSetInput, planWorkflowSpecUpdate, validateStageGraph } from "./validate.js";
|
|
27
|
+
export { cascadeLimitFor, computeWaitingOn, reevaluateAll } from "./engine.js";
|
|
28
|
+
export { WORKFLOW_STATE_ENTRY, WORKFLOW_TRANSITION_ENTRY } from "./types.js";
|
|
29
|
+
/** Session protocol key of the plan plugin's snapshot entry (plugins/plan). */
|
|
30
|
+
const planStateEntry = "plan.state";
|
|
31
|
+
/** Session protocol key of the goal plugin's snapshot entry (plugins/goal). */
|
|
32
|
+
const goalStateEntry = "goal.state";
|
|
33
|
+
const DIAGNOSTICS_CAP = 50;
|
|
34
|
+
/** §3.1 applicability, verbatim scope (when to use / not to use a workflow). */
|
|
35
|
+
const WORKFLOW_APPLICABILITY_GUIDE = "Workflow applicability — use a workflow only when ALL of these hold: (1) the goal needs at least 3 stages that can be accepted independently (you can write each stage's objective/acceptance); (2) the stages have a real dependency structure (branching or joins), not a plain sequence; (3) independent branches can be pushed in parallel — parallelism is a core payoff, purely linear multi-stage work belongs to goal/plan/todo; (4) the task spans multiple turns/days and is valuable enough to justify process overhead (definition, evidence recording, stage gates). Counterexamples that keep goal/plan/todo or direct execution: single-step tasks; two- or three-step linear tasks; exploratory work with no presettable dependency graph; one-shot questions. A workflow does not exclude the three layers — each stage still uses plan/todo for its execution checklist. Never escalate a small task to a workflow by default.";
|
|
36
|
+
const WORKFLOW_AUTHORING_GUIDE = "Define each stage by a verifiable end state, not by a work list or a role: objective.statement says what must be achieved; acceptance items list the evidence that proves it, referenced from real tool output. Stop splitting at the first verifiable boundary — finer handoffs lose more to interface drift than they gain in drift protection.";
|
|
37
|
+
const WORKFLOW_EXECUTION_GUIDE = "After plan_set marks a stage's plan completed, run workflow_advance inspect to see unlocked stages and acceptance coverage. Record evidence (workflow_advance record-evidence) before completion is evaluated; lower-bound stages (no acceptance declared) need no record-evidence. When multiple stages are active, delegate one subagent per stage following stage.role and push them in parallel.";
|
|
38
|
+
const WORKFLOW_CORRECTION_GUIDE = "On user corrections: run workflow_advance inspect first to confirm the current state, then route by what changed — amend the stage spec (active/awaiting_review stages, amendNote required), append a stage, skip, retreat, or cancel — and report the adjustment and its impact range back to the user.";
|
|
39
|
+
const WORKFLOW_REVIEW_GUIDE = "Stages declared advance: 'review' stop at awaiting_review. Before approve you must present the result and its evidence to the user and get explicit confirmation — never approve on your own (the engine does not authorize; the discipline lives here).";
|
|
40
|
+
const WORKFLOW_CONCURRENCY_GUIDE = "Do not send workflow_set in the same parallel batch as plan_set: amends and completion evaluation race (completed freezes first; if the amend loses, recover via retreat).";
|
|
41
|
+
const acceptanceSchema = Type.Object({
|
|
42
|
+
id: Type.String({ description: "Acceptance item id; evidence references this id" }),
|
|
43
|
+
statement: Type.String({ description: "Verifiable completion criterion for this item" }),
|
|
44
|
+
});
|
|
45
|
+
const stageSchema = Type.Object({
|
|
46
|
+
id: Type.String({ description: "Stable stage id, unique within the workflow" }),
|
|
47
|
+
title: Type.String({ description: "Human-readable stage title" }),
|
|
48
|
+
objective: Type.Object({
|
|
49
|
+
statement: Type.String({
|
|
50
|
+
description: "Verifiable end state this stage must reach (required, non-empty)",
|
|
51
|
+
}),
|
|
52
|
+
acceptance: Type.Optional(Type.Array(acceptanceSchema, {
|
|
53
|
+
description: "Completion criteria items; when empty (or omitted) the lower bound is the referenced plan's completion evidence",
|
|
54
|
+
})),
|
|
55
|
+
}),
|
|
56
|
+
dependsOn: Type.Optional(Type.Array(Type.String(), { description: "Hard prerequisite stage ids; empty array = root stage" })),
|
|
57
|
+
planId: Type.Optional(Type.String({ description: "Soft reference to a plan id; missing = pure checkpoint stage" })),
|
|
58
|
+
kind: Type.Optional(Type.Union([Type.Literal("read"), Type.Literal("write")], {
|
|
59
|
+
description: 'Stage kind; write stages are scope-checked, default "write"',
|
|
60
|
+
})),
|
|
61
|
+
scope: Type.Optional(Type.Array(Type.String(), {
|
|
62
|
+
description: "Write scope tags (modules/dirs); missing = global (intersects every other write stage)",
|
|
63
|
+
})),
|
|
64
|
+
role: Type.Optional(Type.String({ description: "Delegation advice: role id for the subagent recommended to drive this stage" })),
|
|
65
|
+
advance: Type.Optional(Type.Union([Type.Literal("auto"), Type.Literal("review")], {
|
|
66
|
+
description: '"auto" completes on evaluation, "review" stops at awaiting_review (planId stages only), default "auto"',
|
|
67
|
+
})),
|
|
68
|
+
retryLimit: Type.Optional(Type.Integer({ description: "In-place retry limit before onFail/workflow failure, default 2", minimum: 0 })),
|
|
69
|
+
onFail: Type.Optional(Type.String({ description: "Explicit cross-stage retreat target (a topologically earlier stage id)" })),
|
|
70
|
+
amendNote: Type.Optional(Type.String({
|
|
71
|
+
description: "Correction reason; required when an active/awaiting_review stage's spec changes",
|
|
72
|
+
})),
|
|
73
|
+
});
|
|
74
|
+
const workflowSetSchema = Type.Object({
|
|
75
|
+
id: Type.String({ description: "Stable id of the workflow to create or update" }),
|
|
76
|
+
title: Type.String({ description: "Human-readable workflow title" }),
|
|
77
|
+
revision: Type.Integer({
|
|
78
|
+
description: "New revision counter; must be greater than the stored revision of an existing workflow",
|
|
79
|
+
minimum: 0,
|
|
80
|
+
}),
|
|
81
|
+
goalId: Type.Optional(Type.String({
|
|
82
|
+
description: "Soft reference to a goal id; the closure evidence summary is addressed to this goal",
|
|
83
|
+
})),
|
|
84
|
+
maxRetreats: Type.Optional(Type.Integer({ description: "Workflow lifetime retreat budget before failure, default 3", minimum: 0 })),
|
|
85
|
+
maxActiveStages: Type.Optional(Type.Integer({ description: "Parallel activation cap, default 4", minimum: 1 })),
|
|
86
|
+
stages: Type.Array(stageSchema, {
|
|
87
|
+
description: "Full stage list (whole submit, not a patch); the engine aligns runtime by stage id",
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
const workflowAdvanceSchema = Type.Object({
|
|
91
|
+
workflowId: Type.String({ description: "Target workflow id" }),
|
|
92
|
+
action: Type.Union([
|
|
93
|
+
Type.Literal("start"),
|
|
94
|
+
Type.Literal("record-evidence"),
|
|
95
|
+
Type.Literal("inspect"),
|
|
96
|
+
Type.Literal("approve"),
|
|
97
|
+
Type.Literal("reject"),
|
|
98
|
+
Type.Literal("retreat"),
|
|
99
|
+
Type.Literal("complete"),
|
|
100
|
+
Type.Literal("skip"),
|
|
101
|
+
Type.Literal("cancel"),
|
|
102
|
+
], { description: "Explicit action to perform" }),
|
|
103
|
+
stageId: Type.Optional(Type.String({
|
|
104
|
+
description: "Stage id: the evidence/approve/reject/complete/skip target, or the retreat target stage to roll back to",
|
|
105
|
+
})),
|
|
106
|
+
evidence: Type.Optional(Type.Array(Type.Object({
|
|
107
|
+
acceptanceId: Type.Optional(Type.String({ description: "Acceptance item id; required in acceptance mode" })),
|
|
108
|
+
ref: Type.String({ description: "Evidence reference (tool output, file, artifact)" }),
|
|
109
|
+
}), { description: "Evidence items for record-evidence/approve/complete" })),
|
|
110
|
+
note: Type.Optional(Type.String({ description: "Optional note recorded in the transition detail (reject/retreat/skip/cancel)" })),
|
|
111
|
+
});
|
|
112
|
+
const ADVANCE_ACTIONS = [
|
|
113
|
+
"start",
|
|
114
|
+
"record-evidence",
|
|
115
|
+
"inspect",
|
|
116
|
+
"approve",
|
|
117
|
+
"reject",
|
|
118
|
+
"retreat",
|
|
119
|
+
"complete",
|
|
120
|
+
"skip",
|
|
121
|
+
"cancel",
|
|
122
|
+
];
|
|
123
|
+
function objectInput(first, second) {
|
|
124
|
+
const value = second === undefined ? first : second;
|
|
125
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
126
|
+
throw new Error("Workflow input must be an object");
|
|
127
|
+
}
|
|
128
|
+
return value;
|
|
129
|
+
}
|
|
130
|
+
function parseAdvanceInput(value) {
|
|
131
|
+
const workflowId = asText(value.workflowId, "workflowId");
|
|
132
|
+
const action = value.action;
|
|
133
|
+
if (typeof action !== "string" || !ADVANCE_ACTIONS.includes(action)) {
|
|
134
|
+
throw new Error(`action must be one of ${ADVANCE_ACTIONS.join(", ")}`);
|
|
135
|
+
}
|
|
136
|
+
const stageId = value.stageId === undefined ? undefined : asText(value.stageId, "stageId");
|
|
137
|
+
const note = value.note === undefined ? undefined : asText(value.note, "note");
|
|
138
|
+
let evidence;
|
|
139
|
+
if (value.evidence !== undefined) {
|
|
140
|
+
if (!Array.isArray(value.evidence))
|
|
141
|
+
throw new Error("evidence must be an array of {acceptanceId?, ref}");
|
|
142
|
+
evidence = value.evidence.map((item) => {
|
|
143
|
+
const entry = asObject(item, "evidence item");
|
|
144
|
+
const ref = asText(entry.ref, "evidence item ref");
|
|
145
|
+
const acceptanceId = entry.acceptanceId === undefined ? undefined : asText(entry.acceptanceId, "evidence item acceptanceId");
|
|
146
|
+
return acceptanceId === undefined ? { ref } : { acceptanceId, ref };
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
workflowId,
|
|
151
|
+
action: action,
|
|
152
|
+
...(stageId !== undefined ? { stageId } : {}),
|
|
153
|
+
...(evidence !== undefined ? { evidence } : {}),
|
|
154
|
+
...(note !== undefined ? { note } : {}),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function loadState(api) {
|
|
158
|
+
const entries = api.session?.getBranchEntries() ?? [];
|
|
159
|
+
const entry = [...entries].reverse().find((item) => item.customType === WORKFLOW_STATE_ENTRY);
|
|
160
|
+
if (!entry?.data || typeof entry.data !== "object")
|
|
161
|
+
return { workflows: [] };
|
|
162
|
+
const data = entry.data;
|
|
163
|
+
return { workflows: Array.isArray(data.workflows) ? [...data.workflows] : [] };
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Plan facts read from the current branch's LATEST `plan.state` snapshot (the
|
|
167
|
+
* same latest-snapshot semantics as the plan plugin's own loadState). The
|
|
168
|
+
* plan.changed payload is never trusted for state — only as a trigger.
|
|
169
|
+
*/
|
|
170
|
+
function loadPlansSnapshot(api) {
|
|
171
|
+
const entries = api.session?.getBranchEntries() ?? [];
|
|
172
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
173
|
+
const entry = entries[index];
|
|
174
|
+
if (entry.customType !== planStateEntry)
|
|
175
|
+
continue;
|
|
176
|
+
const data = entry.data;
|
|
177
|
+
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
178
|
+
return new Map();
|
|
179
|
+
const plans = data.plans;
|
|
180
|
+
if (!Array.isArray(plans))
|
|
181
|
+
return new Map();
|
|
182
|
+
const facts = new Map();
|
|
183
|
+
for (const plan of plans) {
|
|
184
|
+
if (!plan || typeof plan !== "object")
|
|
185
|
+
continue;
|
|
186
|
+
const record = plan;
|
|
187
|
+
if (typeof record.id !== "string")
|
|
188
|
+
continue;
|
|
189
|
+
const status = record.status === "draft" ||
|
|
190
|
+
record.status === "active" ||
|
|
191
|
+
record.status === "completed" ||
|
|
192
|
+
record.status === "cancelled"
|
|
193
|
+
? record.status
|
|
194
|
+
: "draft";
|
|
195
|
+
const evidence = Array.isArray(record.evidence)
|
|
196
|
+
? record.evidence.filter((item) => typeof item === "string")
|
|
197
|
+
: [];
|
|
198
|
+
facts.set(record.id, { id: record.id, status, evidence });
|
|
199
|
+
}
|
|
200
|
+
return facts;
|
|
201
|
+
}
|
|
202
|
+
return new Map();
|
|
203
|
+
}
|
|
204
|
+
/** Whether the latest `<entryType>` snapshot on the branch knows `id` in its `idsField` array (advisory, #10). */
|
|
205
|
+
function idKnownToSession(api, entryType, idsField, id) {
|
|
206
|
+
const entries = api.session?.getBranchEntries() ?? [];
|
|
207
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
208
|
+
const entry = entries[index];
|
|
209
|
+
if (entry.customType !== entryType)
|
|
210
|
+
continue;
|
|
211
|
+
const data = entry.data;
|
|
212
|
+
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
213
|
+
return false;
|
|
214
|
+
const records = data[idsField];
|
|
215
|
+
if (!Array.isArray(records))
|
|
216
|
+
return false;
|
|
217
|
+
return records.some((record) => record !== null && typeof record === "object" && record.id === id);
|
|
218
|
+
}
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Seeds the held-dedup view (§5 总则 5) from the branch audit stream: the
|
|
223
|
+
* last transition per stage, whatever its code — a repeat held emission is
|
|
224
|
+
* dropped only when it matches that last code and detail.
|
|
225
|
+
*/
|
|
226
|
+
function buildLastStageTransition(api) {
|
|
227
|
+
const map = new Map();
|
|
228
|
+
for (const entry of api.session?.getBranchEntries() ?? []) {
|
|
229
|
+
if (entry.customType !== WORKFLOW_TRANSITION_ENTRY)
|
|
230
|
+
continue;
|
|
231
|
+
const data = entry.data;
|
|
232
|
+
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
233
|
+
continue;
|
|
234
|
+
const record = data;
|
|
235
|
+
if (typeof record.workflowId !== "string" || typeof record.stageId !== "string")
|
|
236
|
+
continue;
|
|
237
|
+
const reason = record.reason;
|
|
238
|
+
if (!reason || typeof reason !== "object" || typeof reason.code !== "string")
|
|
239
|
+
continue;
|
|
240
|
+
map.set(`${record.workflowId}::${record.stageId}`, {
|
|
241
|
+
code: reason.code,
|
|
242
|
+
detail: typeof reason.detail === "string" ? reason.detail : undefined,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return map;
|
|
246
|
+
}
|
|
247
|
+
/** Soft-reference warnings for the tool response only (never the persisted state, #10). */
|
|
248
|
+
function collectSoftReferenceWarnings(api, goalId, planIds, roles) {
|
|
249
|
+
const warnings = [];
|
|
250
|
+
if (goalId !== undefined && !idKnownToSession(api, goalStateEntry, "goals", goalId)) {
|
|
251
|
+
warnings.push(`goalId "${goalId}" does not match any goal in this session's goal state; the workflow keeps the soft reference`);
|
|
252
|
+
}
|
|
253
|
+
for (const item of planIds) {
|
|
254
|
+
if (!idKnownToSession(api, planStateEntry, "plans", item.planId)) {
|
|
255
|
+
warnings.push(`stage ${item.stageId}: planId "${item.planId}" does not match any plan in this session's plan state; ` +
|
|
256
|
+
"the stage stays held until a reevaluation finds the plan");
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
for (const item of roles) {
|
|
260
|
+
// The host's suite role associations are the only verifiable role face;
|
|
261
|
+
// hosts without the listing leave the advice unverified (no warning).
|
|
262
|
+
const associated = api.host?.roleAssociations;
|
|
263
|
+
if (associated !== undefined && !associated.includes(item.role)) {
|
|
264
|
+
warnings.push(`stage ${item.stageId}: role "${item.role}" is not associated with the active suite; delegation advice treated as unspecified`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return warnings;
|
|
268
|
+
}
|
|
269
|
+
export function createCapability(api) {
|
|
270
|
+
let state = loadState(api);
|
|
271
|
+
const deps = {
|
|
272
|
+
getPlan: (planId) => loadPlansSnapshot(api).get(planId),
|
|
273
|
+
lastStageTransition: buildLastStageTransition(api),
|
|
274
|
+
};
|
|
275
|
+
// Persistence boundary (§4): audit entries first, then the full snapshot —
|
|
276
|
+
// a crash mid-batch replays from the older snapshot while the audit stays
|
|
277
|
+
// intact. appendEntry failures propagate unchanged (§5 总则 5: no swallow);
|
|
278
|
+
// publish rejections surface to the tool caller (or are contained on the
|
|
279
|
+
// load/subscriber paths below).
|
|
280
|
+
const persistRun = (run) => {
|
|
281
|
+
for (const transition of run.transitions) {
|
|
282
|
+
api.session?.appendEntry(WORKFLOW_TRANSITION_ENTRY, transition);
|
|
283
|
+
}
|
|
284
|
+
api.session?.appendEntry(WORKFLOW_STATE_ENTRY, run.state);
|
|
285
|
+
};
|
|
286
|
+
const announce = (run) => api.publish({ type: "workflow.changed", version: 1, correlationId: WORKFLOW_STATE_ENTRY, data: run.state });
|
|
287
|
+
/**
|
|
288
|
+
* §5 总则 3 containment: land the failure in diagnostics + a handler.error
|
|
289
|
+
* transition (detail = original error text) and never rethrow. Best-effort
|
|
290
|
+
* — an already-failing boundary must not turn isolation into a second crash.
|
|
291
|
+
*/
|
|
292
|
+
const quarantineEngineError = (error, trigger) => {
|
|
293
|
+
try {
|
|
294
|
+
if (state.workflows.length === 0)
|
|
295
|
+
return;
|
|
296
|
+
const original = error instanceof Error ? error.message : String(error);
|
|
297
|
+
const text = `${trigger} handler failed: ${original}`;
|
|
298
|
+
const workflows = state.workflows.map((workflow) => structuredClone(workflow));
|
|
299
|
+
const transitions = [];
|
|
300
|
+
for (const workflow of workflows) {
|
|
301
|
+
if (workflow.diagnostics.length >= DIAGNOSTICS_CAP)
|
|
302
|
+
workflow.diagnostics.shift();
|
|
303
|
+
workflow.diagnostics.push(text);
|
|
304
|
+
workflow.revision += 1;
|
|
305
|
+
transitions.push({
|
|
306
|
+
workflowId: workflow.id,
|
|
307
|
+
from: workflow.status,
|
|
308
|
+
to: workflow.status,
|
|
309
|
+
trigger,
|
|
310
|
+
reason: { code: "handler.error", message: text, detail: original },
|
|
311
|
+
revision: workflow.revision,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
state = { workflows };
|
|
315
|
+
for (const transition of transitions) {
|
|
316
|
+
api.session?.appendEntry(WORKFLOW_TRANSITION_ENTRY, transition);
|
|
317
|
+
}
|
|
318
|
+
api.session?.appendEntry(WORKFLOW_STATE_ENTRY, state);
|
|
319
|
+
void api
|
|
320
|
+
.publish({ type: "workflow.changed", version: 1, correlationId: WORKFLOW_STATE_ENTRY, data: state })
|
|
321
|
+
.catch(() => undefined);
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
// Containment is best-effort by design.
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
// §5 rule 8 recovery: state replayed from workflow.state, then the
|
|
328
|
+
// load-time reevaluation (总则 1 fallback moment #1). Runs synchronously at
|
|
329
|
+
// factory time; failures are contained, never blocking plugin load.
|
|
330
|
+
try {
|
|
331
|
+
const run = reevaluateAll(state, deps, "load-reeval");
|
|
332
|
+
if (run.transitions.length > 0) {
|
|
333
|
+
state = run.state;
|
|
334
|
+
persistRun(run);
|
|
335
|
+
void announce(run).catch(() => undefined);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
quarantineEngineError(error, "load-reeval");
|
|
340
|
+
}
|
|
341
|
+
const setTool = api.registerTool({
|
|
342
|
+
name: "workflow_set",
|
|
343
|
+
label: "Set workflow",
|
|
344
|
+
promptGuidelines: [
|
|
345
|
+
WORKFLOW_APPLICABILITY_GUIDE,
|
|
346
|
+
WORKFLOW_AUTHORING_GUIDE,
|
|
347
|
+
WORKFLOW_EXECUTION_GUIDE,
|
|
348
|
+
WORKFLOW_CORRECTION_GUIDE,
|
|
349
|
+
WORKFLOW_REVIEW_GUIDE,
|
|
350
|
+
WORKFLOW_CONCURRENCY_GUIDE,
|
|
351
|
+
],
|
|
352
|
+
description: "Create or update a workflow: a stage dependency graph (DAG) with per-stage objectives, acceptance evidence, and soft goal/plan references",
|
|
353
|
+
parameters: workflowSetSchema,
|
|
354
|
+
execute: async (first, second) => {
|
|
355
|
+
const parsed = parseWorkflowSetInput(objectInput(first, second));
|
|
356
|
+
validateStageGraph(parsed.stages);
|
|
357
|
+
const current = state.workflows.find((workflow) => workflow.id === parsed.id);
|
|
358
|
+
if (current !== undefined && parsed.revision <= current.revision) {
|
|
359
|
+
throw new Error(`stale workflow revision: ${parsed.id}`);
|
|
360
|
+
}
|
|
361
|
+
if (current !== undefined &&
|
|
362
|
+
(current.status === "completed" || current.status === "failed" || current.status === "cancelled")) {
|
|
363
|
+
throw new Error(`workflow is terminal and cannot be updated: ${parsed.id}`);
|
|
364
|
+
}
|
|
365
|
+
const diff = planWorkflowSpecUpdate(current, parsed);
|
|
366
|
+
const run = applyWorkflowSet(state, parsed, diff, deps);
|
|
367
|
+
state = run.state;
|
|
368
|
+
if (run.transitions.length > 0 || diff.created)
|
|
369
|
+
persistRun(run);
|
|
370
|
+
if (run.transitions.length > 0 || diff.created)
|
|
371
|
+
await announce(run);
|
|
372
|
+
const response = { ...state };
|
|
373
|
+
if (run.closures.length > 0)
|
|
374
|
+
response.closures = run.closures;
|
|
375
|
+
const warnings = collectSoftReferenceWarnings(api, parsed.goalId, parsed.stages.flatMap((stage) => stage.planId !== undefined ? [{ stageId: stage.id, planId: stage.planId }] : []), parsed.stages.flatMap((stage) => stage.role !== undefined ? [{ stageId: stage.id, role: stage.role }] : []));
|
|
376
|
+
if (warnings.length > 0)
|
|
377
|
+
response.warning = warnings.join("; ");
|
|
378
|
+
return response;
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
const advanceTool = api.registerTool({
|
|
382
|
+
name: "workflow_advance",
|
|
383
|
+
label: "Advance workflow",
|
|
384
|
+
description: "Drive a workflow: start it, record acceptance evidence, inspect waiting conditions and coverage, approve/reject reviews, retreat, complete checkpoints, skip stages, or cancel",
|
|
385
|
+
parameters: workflowAdvanceSchema,
|
|
386
|
+
execute: async (first, second) => {
|
|
387
|
+
const parsed = parseAdvanceInput(objectInput(first, second));
|
|
388
|
+
// Illegal conversions throw structured errors (§5 rule 6) surfaced
|
|
389
|
+
// as tool errors unchanged; legal ones return the full snapshot
|
|
390
|
+
// (the goal_set full-state response pattern).
|
|
391
|
+
const run = applyAdvance(state, parsed, deps);
|
|
392
|
+
state = run.state;
|
|
393
|
+
if (run.transitions.length > 0) {
|
|
394
|
+
persistRun(run);
|
|
395
|
+
await announce(run);
|
|
396
|
+
}
|
|
397
|
+
const response = { ...state };
|
|
398
|
+
if (parsed.action === "inspect") {
|
|
399
|
+
// §5 rule 6 single-workflow semantics: applyAdvance has already
|
|
400
|
+
// rejected unknown ids, so the target always resolves here.
|
|
401
|
+
const target = state.workflows.find((workflow) => workflow.id === parsed.workflowId);
|
|
402
|
+
if (target !== undefined)
|
|
403
|
+
response.inspections = [inspectWorkflow(target, deps)];
|
|
404
|
+
}
|
|
405
|
+
if (run.closures.length > 0)
|
|
406
|
+
response.closures = run.closures;
|
|
407
|
+
return response;
|
|
408
|
+
},
|
|
409
|
+
});
|
|
410
|
+
const workflowCommand = api.registerCommand({
|
|
411
|
+
name: "workflow",
|
|
412
|
+
description: "Workflow overview: dependency tree and status (default), why it is stopped, or the transition log",
|
|
413
|
+
argumentHint: "[view | why | log [N]]",
|
|
414
|
+
execute: async (args) => {
|
|
415
|
+
try {
|
|
416
|
+
const trimmed = args.trim();
|
|
417
|
+
if (trimmed === "" || trimmed === "view") {
|
|
418
|
+
return { status: "success", message: renderPanorama(state, deps) };
|
|
419
|
+
}
|
|
420
|
+
if (trimmed === "why") {
|
|
421
|
+
return { status: "success", message: renderWhy(state, deps) };
|
|
422
|
+
}
|
|
423
|
+
const logMatch = /^log(?:\s+(\d+))?$/.exec(trimmed);
|
|
424
|
+
if (logMatch !== null) {
|
|
425
|
+
const limit = logMatch[1] === undefined ? 20 : Math.max(1, Number.parseInt(logMatch[1], 10));
|
|
426
|
+
return {
|
|
427
|
+
status: "success",
|
|
428
|
+
message: renderLog(api.session?.getBranchEntries() ?? [], limit),
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
return { status: "error", message: "Usage: /workflow [view | why | log [N]]" };
|
|
432
|
+
}
|
|
433
|
+
catch (error) {
|
|
434
|
+
// A slash command must not crash the host (memory /promote precedent).
|
|
435
|
+
return { status: "error", message: error instanceof Error ? error.message : String(error) };
|
|
436
|
+
}
|
|
437
|
+
},
|
|
438
|
+
});
|
|
439
|
+
// The repository's first event subscription (§7). The payload is ignored:
|
|
440
|
+
// reevaluation always reads the current branch entries (§5 总则 1).
|
|
441
|
+
const planChanged = api.subscribe("plan.changed", async () => {
|
|
442
|
+
try {
|
|
443
|
+
const run = reevaluateAll(state, deps, "plan.changed");
|
|
444
|
+
if (run.transitions.length === 0)
|
|
445
|
+
return;
|
|
446
|
+
state = run.state;
|
|
447
|
+
persistRun(run);
|
|
448
|
+
await announce(run);
|
|
449
|
+
}
|
|
450
|
+
catch (error) {
|
|
451
|
+
quarantineEngineError(error, "plan.changed");
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
return [setTool, advanceTool, workflowCommand, planChanged];
|
|
455
|
+
}
|
|
456
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,EAGN,YAAY,EACZ,gBAAgB,EAIhB,eAAe,EAEf,aAAa,GAGb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAEN,oBAAoB,EACpB,yBAAyB,GAIzB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAepH,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAW/E,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE7E,+EAA+E;AAC/E,MAAM,cAAc,GAAG,YAAY,CAAC;AACpC,+EAA+E;AAC/E,MAAM,cAAc,GAAG,YAAY,CAAC;AACpC,MAAM,eAAe,GAAG,EAAE,CAAC;AAE3B,iFAAgF;AAChF,MAAM,4BAA4B,GACjC,w5BAAk5B,CAAC;AAEp5B,MAAM,wBAAwB,GAC7B,qVAAmV,CAAC;AAErV,MAAM,wBAAwB,GAC7B,sYAAsY,CAAC;AAExY,MAAM,yBAAyB,GAC9B,8SAA0S,CAAC;AAE5S,MAAM,qBAAqB,GAC1B,4PAA0P,CAAC;AAE5P,MAAM,0BAA0B,GAC/B,4KAA4K,CAAC;AAE9K,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC;IACpC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,iDAAiD,EAAE,CAAC;IACnF,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,+CAA+C,EAAE,CAAC;CACxF,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC;IAC/B,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,6CAA6C,EAAE,CAAC;IAC/E,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,4BAA4B,EAAE,CAAC;IACjE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;QACtB,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;YACtB,WAAW,EAAE,kEAAkE;SAC/E,CAAC;QACF,UAAU,EAAE,IAAI,CAAC,QAAQ,CACxB,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE;YAC5B,WAAW,EACV,iHAAiH;SAClH,CAAC,CACF;KACD,CAAC;IACF,SAAS,EAAE,IAAI,CAAC,QAAQ,CACvB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,uDAAuD,EAAE,CAAC,CACnG;IACD,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,8DAA8D,EAAE,CAAC,CAAC;IACnH,IAAI,EAAE,IAAI,CAAC,QAAQ,CAClB,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE;QACzD,WAAW,EAAE,6DAA6D;KAC1E,CAAC,CACF;IACD,KAAK,EAAE,IAAI,CAAC,QAAQ,CACnB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE;QACzB,WAAW,EAAE,wFAAwF;KACrG,CAAC,CACF;IACD,IAAI,EAAE,IAAI,CAAC,QAAQ,CAClB,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,6EAA6E,EAAE,CAAC,CAC3G;IACD,OAAO,EAAE,IAAI,CAAC,QAAQ,CACrB,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE;QAC1D,WAAW,EACV,wGAAwG;KACzG,CAAC,CACF;IACD,UAAU,EAAE,IAAI,CAAC,QAAQ,CACxB,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,gEAAgE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAC3G;IACD,MAAM,EAAE,IAAI,CAAC,QAAQ,CACpB,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,wEAAwE,EAAE,CAAC,CACtG;IACD,SAAS,EAAE,IAAI,CAAC,QAAQ,CACvB,IAAI,CAAC,MAAM,CAAC;QACX,WAAW,EAAE,iFAAiF;KAC9F,CAAC,CACF;CACD,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAAG,IAAI,CAAC,MAAM,CAAC;IACrC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,+CAA+C,EAAE,CAAC;IACjF,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,+BAA+B,EAAE,CAAC;IACpE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC;QACtB,WAAW,EAAE,wFAAwF;QACrG,OAAO,EAAE,CAAC;KACV,CAAC;IACF,MAAM,EAAE,IAAI,CAAC,QAAQ,CACpB,IAAI,CAAC,MAAM,CAAC;QACX,WAAW,EAAE,qFAAqF;KAClG,CAAC,CACF;IACD,WAAW,EAAE,IAAI,CAAC,QAAQ,CACzB,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,4DAA4D,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CACvG;IACD,eAAe,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,oCAAoC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/G,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;QAC/B,WAAW,EAAE,oFAAoF;KACjG,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,qBAAqB,GAAG,IAAI,CAAC,MAAM,CAAC;IACzC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAC;IAC9D,MAAM,EAAE,IAAI,CAAC,KAAK,CACjB;QACC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;QACrB,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC;QAC/B,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;QACvB,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;QACvB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;QACvB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QACxB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;QACpB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;KACtB,EACD,EAAE,WAAW,EAAE,4BAA4B,EAAE,CAC7C;IACD,OAAO,EAAE,IAAI,CAAC,QAAQ,CACrB,IAAI,CAAC,MAAM,CAAC;QACX,WAAW,EACV,yGAAyG;KAC1G,CAAC,CACF;IACD,QAAQ,EAAE,IAAI,CAAC,QAAQ,CACtB,IAAI,CAAC,KAAK,CACT,IAAI,CAAC,MAAM,CAAC;QACX,YAAY,EAAE,IAAI,CAAC,QAAQ,CAC1B,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,iDAAiD,EAAE,CAAC,CAC/E;QACD,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,kDAAkD,EAAE,CAAC;KACrF,CAAC,EACF,EAAE,WAAW,EAAE,qDAAqD,EAAE,CACtE,CACD;IACD,IAAI,EAAE,IAAI,CAAC,QAAQ,CAClB,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,8EAA8E,EAAE,CAAC,CAC5G;CACD,CAAC,CAAC;AAEH,MAAM,eAAe,GAAsB;IAC1C,OAAO;IACP,iBAAiB;IACjB,SAAS;IACT,SAAS;IACT,QAAQ;IACR,SAAS;IACT,UAAU;IACV,MAAM;IACN,QAAQ;CACR,CAAC;AAEF,SAAS,WAAW,CAAC,KAAc,EAAE,MAAe,EAA2B;IAC9E,MAAM,KAAK,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IACpD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,KAAgC,CAAC;AAAA,CACxC;AAED,SAAS,iBAAiB,CAAC,KAA8B,EAAgB;IACxE,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC5B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,yBAAyB,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC3F,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC/E,IAAI,QAAoC,CAAC;IACzC,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAClC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACzG,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;YAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;YACnD,MAAM,YAAY,GACjB,KAAK,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,EAAE,4BAA4B,CAAC,CAAC;YACzG,OAAO,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC;QAAA,CACpE,CAAC,CAAC;IACJ,CAAC;IACD,OAAO;QACN,UAAU;QACV,MAAM,EAAE,MAAuB;QAC/B,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7C,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvC,CAAC;AAAA,CACF;AAED,SAAS,SAAS,CAAC,GAAkB,EAAiB;IACrD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;IACtD,MAAM,KAAK,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,KAAK,oBAAoB,CAAC,CAAC;IAC9F,IAAI,CAAC,KAAK,EAAE,IAAI,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC7E,MAAM,IAAI,GAAG,KAAK,CAAC,IAA8B,CAAC;IAClD,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAAA,CAC/E;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,GAAkB,EAA0B;IACtE,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;IACtD,KAAK,IAAI,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC7D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC7B,IAAI,KAAK,CAAC,UAAU,KAAK,cAAc;YAAE,SAAS;QAClD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,GAAG,EAAE,CAAC;QAC/E,MAAM,KAAK,GAAI,IAA4B,CAAC,KAAK,CAAC;QAClD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,GAAG,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;QAC3C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;gBAAE,SAAS;YAChD,MAAM,MAAM,GAAG,IAA8D,CAAC;YAC9E,IAAI,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ;gBAAE,SAAS;YAC5C,MAAM,MAAM,GACX,MAAM,CAAC,MAAM,KAAK,OAAO;gBACzB,MAAM,CAAC,MAAM,KAAK,QAAQ;gBAC1B,MAAM,CAAC,MAAM,KAAK,WAAW;gBAC7B,MAAM,CAAC,MAAM,KAAK,WAAW;gBAC5B,CAAC,CAAC,MAAM,CAAC,MAAM;gBACf,CAAC,CAAC,OAAO,CAAC;YACZ,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;gBAC9C,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC;gBAC5E,CAAC,CAAC,EAAE,CAAC;YACN,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC3D,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,IAAI,GAAG,EAAE,CAAC;AAAA,CACjB;AAED,kHAAkH;AAClH,SAAS,gBAAgB,CAAC,GAAkB,EAAE,SAAiB,EAAE,QAAgB,EAAE,EAAU,EAAW;IACvG,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;IACtD,KAAK,IAAI,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC7D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC7B,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;YAAE,SAAS;QAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QAC3E,MAAM,OAAO,GAAI,IAAgC,CAAC,QAAQ,CAAC,CAAC;QAC5D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;YAAE,OAAO,KAAK,CAAC;QAC1C,OAAO,OAAO,CAAC,IAAI,CAClB,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAK,MAA2B,CAAC,EAAE,KAAK,EAAE,CACnG,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED;;;;GAIG;AACH,SAAS,wBAAwB,CAAC,GAAkB,EAAgE;IACnH,MAAM,GAAG,GAAG,IAAI,GAAG,EAA2D,CAAC;IAC/E,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,EAAE,CAAC;QAC3D,IAAI,KAAK,CAAC,UAAU,KAAK,yBAAyB;YAAE,SAAS;QAC7D,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,SAAS;QACvE,MAAM,MAAM,GAAG,IAAwC,CAAC;QACxD,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ;YAAE,SAAS;QAC1F,MAAM,MAAM,GAAG,MAAM,CAAC,MAA0D,CAAC;QACjF,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;YAAE,SAAS;QACvF,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,OAAO,EAAE,EAAE;YAClD,IAAI,EAAE,MAAM,CAAC,IAA4B;YACzC,MAAM,EAAE,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;SACrE,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AAAA,CACX;AAED,2FAA2F;AAC3F,SAAS,4BAA4B,CACpC,GAAkB,EAClB,MAA0B,EAC1B,OAA8C,EAC9C,KAA0C,EAC/B;IACX,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC;QACrF,QAAQ,CAAC,IAAI,CACZ,WAAW,MAAM,+FAA+F,CAChH,CAAC;IACH,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAClE,QAAQ,CAAC,IAAI,CACZ,SAAS,IAAI,CAAC,OAAO,aAAa,IAAI,CAAC,MAAM,0DAA0D;gBACtG,0DAA0D,CAC3D,CAAC;QACH,CAAC;IACF,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,wEAAwE;QACxE,sEAAsE;QACtE,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,EAAE,gBAAgB,CAAC;QAC9C,IAAI,UAAU,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACjE,QAAQ,CAAC,IAAI,CACZ,SAAS,IAAI,CAAC,OAAO,WAAW,IAAI,CAAC,IAAI,qFAAqF,CAC9H,CAAC;QACH,CAAC;IACF,CAAC;IACD,OAAO,QAAQ,CAAC;AAAA,CAChB;AAQD,MAAM,UAAU,gBAAgB,CAC/B,GAAkB,EAC+D;IACjF,IAAI,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC3B,MAAM,IAAI,GAAe;QACxB,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;QACvD,mBAAmB,EAAE,wBAAwB,CAAC,GAAG,CAAC;KAClD,CAAC;IAEF,8EAA2E;IAC3E,0EAA0E;IAC1E,+EAA0E;IAC1E,yEAAyE;IACzE,gCAAgC;IAChC,MAAM,UAAU,GAAG,CAAC,GAAc,EAAQ,EAAE,CAAC;QAC5C,KAAK,MAAM,UAAU,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YAC1C,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,yBAAyB,EAAE,UAAU,CAAC,CAAC;QACjE,CAAC;QACD,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,oBAAoB,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IAAA,CAC1D,CAAC;IACF,MAAM,QAAQ,GAAG,CAAC,GAAc,EAAoB,EAAE,CACrD,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,CAAC,EAAE,aAAa,EAAE,oBAAoB,EAAE,IAAI,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IAE7G;;;;OAIG;IACH,MAAM,qBAAqB,GAAG,CAAC,KAAc,EAAE,OAAkC,EAAQ,EAAE,CAAC;QAC3F,IAAI,CAAC;YACJ,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YACzC,MAAM,QAAQ,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACxE,MAAM,IAAI,GAAG,GAAG,OAAO,oBAAoB,QAAQ,EAAE,CAAC;YACtD,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC/E,MAAM,WAAW,GAA8B,EAAE,CAAC;YAClD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBAClC,IAAI,QAAQ,CAAC,WAAW,CAAC,MAAM,IAAI,eAAe;oBAAE,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;gBACjF,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAChC,QAAQ,CAAC,QAAQ,IAAI,CAAC,CAAC;gBACvB,WAAW,CAAC,IAAI,CAAC;oBAChB,UAAU,EAAE,QAAQ,CAAC,EAAE;oBACvB,IAAI,EAAE,QAAQ,CAAC,MAAM;oBACrB,EAAE,EAAE,QAAQ,CAAC,MAAM;oBACnB,OAAO;oBACP,MAAM,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE;oBAClE,QAAQ,EAAE,QAAQ,CAAC,QAAQ;iBAC3B,CAAC,CAAC;YACJ,CAAC;YACD,KAAK,GAAG,EAAE,SAAS,EAAE,CAAC;YACtB,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;gBACtC,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,yBAAyB,EAAE,UAAU,CAAC,CAAC;YACjE,CAAC;YACD,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;YACtD,KAAK,GAAG;iBACN,OAAO,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,CAAC,EAAE,aAAa,EAAE,oBAAoB,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;iBACnG,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACR,wCAAwC;QACzC,CAAC;IAAA,CACD,CAAC;IAEF,oEAAmE;IACnE,8EAA0E;IAC1E,oEAAoE;IACpE,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC;QACtD,IAAI,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;YAClB,UAAU,CAAC,GAAG,CAAC,CAAC;YAChB,KAAK,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC3C,CAAC;IACF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,qBAAqB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC;QAChC,IAAI,EAAE,cAAc;QACpB,KAAK,EAAE,cAAc;QACrB,gBAAgB,EAAE;YACjB,4BAA4B;YAC5B,wBAAwB;YACxB,wBAAwB;YACxB,yBAAyB;YACzB,qBAAqB;YACrB,0BAA0B;SAC1B;QACD,WAAW,EACV,2IAA2I;QAC5I,UAAU,EAAE,iBAAiB;QAC7B,OAAO,EAAE,KAAK,EAAE,KAAc,EAAE,MAAgB,EAAE,EAAE,CAAC;YACpD,MAAM,MAAM,GAAG,qBAAqB,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;YACjE,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAClC,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC;YAC9E,IAAI,OAAO,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBAClE,MAAM,IAAI,KAAK,CAAC,4BAA4B,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1D,CAAC;YACD,IACC,OAAO,KAAK,SAAS;gBACrB,CAAC,OAAO,CAAC,MAAM,KAAK,WAAW,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,CAAC,EAChG,CAAC;gBACF,MAAM,IAAI,KAAK,CAAC,+CAA+C,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7E,CAAC;YACD,MAAM,IAAI,GAAG,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACrD,MAAM,GAAG,GAAG,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YACxD,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;YAClB,IAAI,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO;gBAAE,UAAU,CAAC,GAAG,CAAC,CAAC;YAChE,IAAI,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO;gBAAE,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;YACpE,MAAM,QAAQ,GAAyB,EAAE,GAAG,KAAK,EAAE,CAAC;YACpD,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;gBAAE,QAAQ,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;YAC9D,MAAM,QAAQ,GAAG,4BAA4B,CAC5C,GAAG,EACH,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAC/B,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAC/E,EACD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAC/B,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CACzE,CACD,CAAC;YACF,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;gBAAE,QAAQ,CAAC,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChE,OAAO,QAAQ,CAAC;QAAA,CAChB;KACD,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,GAAG,CAAC,YAAY,CAAC;QACpC,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,kBAAkB;QACzB,WAAW,EACV,gLAAgL;QACjL,UAAU,EAAE,qBAAqB;QACjC,OAAO,EAAE,KAAK,EAAE,KAAc,EAAE,MAAgB,EAAE,EAAE,CAAC;YACpD,MAAM,MAAM,GAAG,iBAAiB,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;YAC7D,oEAAmE;YACnE,gEAAgE;YAChE,8CAA8C;YAC9C,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;YAC9C,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;YAClB,IAAI,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChC,UAAU,CAAC,GAAG,CAAC,CAAC;gBAChB,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;YACrB,CAAC;YACD,MAAM,QAAQ,GAAyB,EAAE,GAAG,KAAK,EAAE,CAAC;YACpD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBACjC,iEAAgE;gBAChE,4DAA4D;gBAC5D,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,MAAM,CAAC,UAAU,CAAC,CAAC;gBACrF,IAAI,MAAM,KAAK,SAAS;oBAAE,QAAQ,CAAC,WAAW,GAAG,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;YAClF,CAAC;YACD,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;gBAAE,QAAQ,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;YAC9D,OAAO,QAAQ,CAAC;QAAA,CAChB;KACD,CAAC,CAAC;IAEH,MAAM,eAAe,GAAG,GAAG,CAAC,eAAe,CAAC;QAC3C,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,mGAAmG;QAChH,YAAY,EAAE,wBAAwB;QACtC,OAAO,EAAE,KAAK,EAAE,IAAY,EAAE,EAAE,CAAC;YAChC,IAAI,CAAC;gBACJ,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC5B,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;oBAC1C,OAAO,EAAE,MAAM,EAAE,SAAkB,EAAE,OAAO,EAAE,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;gBAC7E,CAAC;gBACD,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;oBACvB,OAAO,EAAE,MAAM,EAAE,SAAkB,EAAE,OAAO,EAAE,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;gBACxE,CAAC;gBACD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACpD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;oBACvB,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;oBAC7F,OAAO;wBACN,MAAM,EAAE,SAAkB;wBAC1B,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,EAAE,KAAK,CAAC;qBAChE,CAAC;gBACH,CAAC;gBACD,OAAO,EAAE,MAAM,EAAE,OAAgB,EAAE,OAAO,EAAE,yCAAyC,EAAE,CAAC;YACzF,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,uEAAuE;gBACvE,OAAO,EAAE,MAAM,EAAE,OAAgB,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACtG,CAAC;QAAA,CACD;KACD,CAAC,CAAC;IAEH,2EAA0E;IAC1E,uEAAkE;IAClE,MAAM,WAAW,GAAG,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC;QAC7D,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;YACvD,IAAI,GAAG,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YACzC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;YAClB,UAAU,CAAC,GAAG,CAAC,CAAC;YAChB,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,qBAAqB,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;QAC9C,CAAC;IAAA,CACD,CAAC,CAAC;IAEH,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,CAAC,CAAC;AAAA,CAC5D","sourcesContent":["/**\n * Workflow orchestration capability plugin (M1 of\n * `docs/design/工作流编排插件设计.md`): a fourth self-contained state machine\n * orchestrating a stage dependency graph on top of the goal/plan/todo layers.\n *\n * Persistence protocol, structurally identical to the goal/plan/todo plugins:\n * append-only `workflow.state` full snapshots (the single rebuild source) plus\n * one `workflow.transition` audit entry per conversion, announced as\n * `workflow.changed` (version 1, correlationId \"workflow.state\", data = the\n * complete WorkflowState snapshot).\n *\n * This plugin is the repository's FIRST event subscriber (§7): `plan.changed`\n * is used as a trigger signal only — its in-memory data may be misaligned\n * with the current branch, so every reevaluation reads the plan facts from\n * the current branch entries. The handler is fully isolated (§5 总则 3): any\n * failure lands in diagnostics + a `handler.error` transition and never\n * rethrows at the publisher (an unisolated throw would pierce plan_set's tool\n * return). Soft references (goalId / planId / role) never fail a write (#10):\n * they surface as response warnings; a dangling planId additionally holds the\n * stage's activation until a reevaluation finds the plan.\n */\n\nimport type { CapabilityAPI, DisposableRegistration } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport {\n\ttype AdvanceAction,\n\ttype AdvanceInput,\n\tapplyAdvance,\n\tapplyWorkflowSet,\n\ttype EngineDeps,\n\ttype EngineRun,\n\ttype EvidenceItem,\n\tinspectWorkflow,\n\ttype PlanFacts,\n\treevaluateAll,\n\ttype WorkflowClosure,\n\ttype WorkflowInspection,\n} from \"./engine.ts\";\nimport { renderLog, renderPanorama, renderWhy } from \"./render.ts\";\nimport {\n\ttype TransitionReasonCode,\n\tWORKFLOW_STATE_ENTRY,\n\tWORKFLOW_TRANSITION_ENTRY,\n\ttype WorkflowState,\n\ttype WorkflowTransitionEntry,\n\ttype WorkflowTransitionTrigger,\n} from \"./types.ts\";\nimport { asObject, asText, parseWorkflowSetInput, planWorkflowSpecUpdate, validateStageGraph } from \"./validate.ts\";\n\nexport type {\n\tAcceptanceCoverage,\n\tAdvanceAction,\n\tAdvanceInput,\n\tClosureEvidenceItem,\n\tEngineDeps,\n\tEngineRun,\n\tEvidenceItem,\n\tPlanFacts,\n\tStageInspection,\n\tWorkflowClosure,\n\tWorkflowInspection,\n} from \"./engine.ts\";\nexport { cascadeLimitFor, computeWaitingOn, reevaluateAll } from \"./engine.ts\";\nexport type {\n\tStageRuntime,\n\tStageSpec,\n\tTransitionReason,\n\tTransitionReasonCode,\n\tWorkflowRecord,\n\tWorkflowState,\n\tWorkflowTransitionEntry,\n\tWorkflowTransitionTrigger,\n} from \"./types.ts\";\nexport { WORKFLOW_STATE_ENTRY, WORKFLOW_TRANSITION_ENTRY } from \"./types.ts\";\n\n/** Session protocol key of the plan plugin's snapshot entry (plugins/plan). */\nconst planStateEntry = \"plan.state\";\n/** Session protocol key of the goal plugin's snapshot entry (plugins/goal). */\nconst goalStateEntry = \"goal.state\";\nconst DIAGNOSTICS_CAP = 50;\n\n/** §3.1 applicability, verbatim scope (when to use / not to use a workflow). */\nconst WORKFLOW_APPLICABILITY_GUIDE =\n\t\"Workflow applicability — use a workflow only when ALL of these hold: (1) the goal needs at least 3 stages that can be accepted independently (you can write each stage's objective/acceptance); (2) the stages have a real dependency structure (branching or joins), not a plain sequence; (3) independent branches can be pushed in parallel — parallelism is a core payoff, purely linear multi-stage work belongs to goal/plan/todo; (4) the task spans multiple turns/days and is valuable enough to justify process overhead (definition, evidence recording, stage gates). Counterexamples that keep goal/plan/todo or direct execution: single-step tasks; two- or three-step linear tasks; exploratory work with no presettable dependency graph; one-shot questions. A workflow does not exclude the three layers — each stage still uses plan/todo for its execution checklist. Never escalate a small task to a workflow by default.\";\n\nconst WORKFLOW_AUTHORING_GUIDE =\n\t\"Define each stage by a verifiable end state, not by a work list or a role: objective.statement says what must be achieved; acceptance items list the evidence that proves it, referenced from real tool output. Stop splitting at the first verifiable boundary — finer handoffs lose more to interface drift than they gain in drift protection.\";\n\nconst WORKFLOW_EXECUTION_GUIDE =\n\t\"After plan_set marks a stage's plan completed, run workflow_advance inspect to see unlocked stages and acceptance coverage. Record evidence (workflow_advance record-evidence) before completion is evaluated; lower-bound stages (no acceptance declared) need no record-evidence. When multiple stages are active, delegate one subagent per stage following stage.role and push them in parallel.\";\n\nconst WORKFLOW_CORRECTION_GUIDE =\n\t\"On user corrections: run workflow_advance inspect first to confirm the current state, then route by what changed — amend the stage spec (active/awaiting_review stages, amendNote required), append a stage, skip, retreat, or cancel — and report the adjustment and its impact range back to the user.\";\n\nconst WORKFLOW_REVIEW_GUIDE =\n\t\"Stages declared advance: 'review' stop at awaiting_review. Before approve you must present the result and its evidence to the user and get explicit confirmation — never approve on your own (the engine does not authorize; the discipline lives here).\";\n\nconst WORKFLOW_CONCURRENCY_GUIDE =\n\t\"Do not send workflow_set in the same parallel batch as plan_set: amends and completion evaluation race (completed freezes first; if the amend loses, recover via retreat).\";\n\nconst acceptanceSchema = Type.Object({\n\tid: Type.String({ description: \"Acceptance item id; evidence references this id\" }),\n\tstatement: Type.String({ description: \"Verifiable completion criterion for this item\" }),\n});\n\nconst stageSchema = Type.Object({\n\tid: Type.String({ description: \"Stable stage id, unique within the workflow\" }),\n\ttitle: Type.String({ description: \"Human-readable stage title\" }),\n\tobjective: Type.Object({\n\t\tstatement: Type.String({\n\t\t\tdescription: \"Verifiable end state this stage must reach (required, non-empty)\",\n\t\t}),\n\t\tacceptance: Type.Optional(\n\t\t\tType.Array(acceptanceSchema, {\n\t\t\t\tdescription:\n\t\t\t\t\t\"Completion criteria items; when empty (or omitted) the lower bound is the referenced plan's completion evidence\",\n\t\t\t}),\n\t\t),\n\t}),\n\tdependsOn: Type.Optional(\n\t\tType.Array(Type.String(), { description: \"Hard prerequisite stage ids; empty array = root stage\" }),\n\t),\n\tplanId: Type.Optional(Type.String({ description: \"Soft reference to a plan id; missing = pure checkpoint stage\" })),\n\tkind: Type.Optional(\n\t\tType.Union([Type.Literal(\"read\"), Type.Literal(\"write\")], {\n\t\t\tdescription: 'Stage kind; write stages are scope-checked, default \"write\"',\n\t\t}),\n\t),\n\tscope: Type.Optional(\n\t\tType.Array(Type.String(), {\n\t\t\tdescription: \"Write scope tags (modules/dirs); missing = global (intersects every other write stage)\",\n\t\t}),\n\t),\n\trole: Type.Optional(\n\t\tType.String({ description: \"Delegation advice: role id for the subagent recommended to drive this stage\" }),\n\t),\n\tadvance: Type.Optional(\n\t\tType.Union([Type.Literal(\"auto\"), Type.Literal(\"review\")], {\n\t\t\tdescription:\n\t\t\t\t'\"auto\" completes on evaluation, \"review\" stops at awaiting_review (planId stages only), default \"auto\"',\n\t\t}),\n\t),\n\tretryLimit: Type.Optional(\n\t\tType.Integer({ description: \"In-place retry limit before onFail/workflow failure, default 2\", minimum: 0 }),\n\t),\n\tonFail: Type.Optional(\n\t\tType.String({ description: \"Explicit cross-stage retreat target (a topologically earlier stage id)\" }),\n\t),\n\tamendNote: Type.Optional(\n\t\tType.String({\n\t\t\tdescription: \"Correction reason; required when an active/awaiting_review stage's spec changes\",\n\t\t}),\n\t),\n});\n\nconst workflowSetSchema = Type.Object({\n\tid: Type.String({ description: \"Stable id of the workflow to create or update\" }),\n\ttitle: Type.String({ description: \"Human-readable workflow title\" }),\n\trevision: Type.Integer({\n\t\tdescription: \"New revision counter; must be greater than the stored revision of an existing workflow\",\n\t\tminimum: 0,\n\t}),\n\tgoalId: Type.Optional(\n\t\tType.String({\n\t\t\tdescription: \"Soft reference to a goal id; the closure evidence summary is addressed to this goal\",\n\t\t}),\n\t),\n\tmaxRetreats: Type.Optional(\n\t\tType.Integer({ description: \"Workflow lifetime retreat budget before failure, default 3\", minimum: 0 }),\n\t),\n\tmaxActiveStages: Type.Optional(Type.Integer({ description: \"Parallel activation cap, default 4\", minimum: 1 })),\n\tstages: Type.Array(stageSchema, {\n\t\tdescription: \"Full stage list (whole submit, not a patch); the engine aligns runtime by stage id\",\n\t}),\n});\n\nconst workflowAdvanceSchema = Type.Object({\n\tworkflowId: Type.String({ description: \"Target workflow id\" }),\n\taction: Type.Union(\n\t\t[\n\t\t\tType.Literal(\"start\"),\n\t\t\tType.Literal(\"record-evidence\"),\n\t\t\tType.Literal(\"inspect\"),\n\t\t\tType.Literal(\"approve\"),\n\t\t\tType.Literal(\"reject\"),\n\t\t\tType.Literal(\"retreat\"),\n\t\t\tType.Literal(\"complete\"),\n\t\t\tType.Literal(\"skip\"),\n\t\t\tType.Literal(\"cancel\"),\n\t\t],\n\t\t{ description: \"Explicit action to perform\" },\n\t),\n\tstageId: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Stage id: the evidence/approve/reject/complete/skip target, or the retreat target stage to roll back to\",\n\t\t}),\n\t),\n\tevidence: Type.Optional(\n\t\tType.Array(\n\t\t\tType.Object({\n\t\t\t\tacceptanceId: Type.Optional(\n\t\t\t\t\tType.String({ description: \"Acceptance item id; required in acceptance mode\" }),\n\t\t\t\t),\n\t\t\t\tref: Type.String({ description: \"Evidence reference (tool output, file, artifact)\" }),\n\t\t\t}),\n\t\t\t{ description: \"Evidence items for record-evidence/approve/complete\" },\n\t\t),\n\t),\n\tnote: Type.Optional(\n\t\tType.String({ description: \"Optional note recorded in the transition detail (reject/retreat/skip/cancel)\" }),\n\t),\n});\n\nconst ADVANCE_ACTIONS: readonly string[] = [\n\t\"start\",\n\t\"record-evidence\",\n\t\"inspect\",\n\t\"approve\",\n\t\"reject\",\n\t\"retreat\",\n\t\"complete\",\n\t\"skip\",\n\t\"cancel\",\n];\n\nfunction objectInput(first: unknown, second: unknown): Record<string, unknown> {\n\tconst value = second === undefined ? first : second;\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(\"Workflow input must be an object\");\n\t}\n\treturn value as Record<string, unknown>;\n}\n\nfunction parseAdvanceInput(value: Record<string, unknown>): AdvanceInput {\n\tconst workflowId = asText(value.workflowId, \"workflowId\");\n\tconst action = value.action;\n\tif (typeof action !== \"string\" || !ADVANCE_ACTIONS.includes(action)) {\n\t\tthrow new Error(`action must be one of ${ADVANCE_ACTIONS.join(\", \")}`);\n\t}\n\tconst stageId = value.stageId === undefined ? undefined : asText(value.stageId, \"stageId\");\n\tconst note = value.note === undefined ? undefined : asText(value.note, \"note\");\n\tlet evidence: EvidenceItem[] | undefined;\n\tif (value.evidence !== undefined) {\n\t\tif (!Array.isArray(value.evidence)) throw new Error(\"evidence must be an array of {acceptanceId?, ref}\");\n\t\tevidence = value.evidence.map((item) => {\n\t\t\tconst entry = asObject(item, \"evidence item\");\n\t\t\tconst ref = asText(entry.ref, \"evidence item ref\");\n\t\t\tconst acceptanceId =\n\t\t\t\tentry.acceptanceId === undefined ? undefined : asText(entry.acceptanceId, \"evidence item acceptanceId\");\n\t\t\treturn acceptanceId === undefined ? { ref } : { acceptanceId, ref };\n\t\t});\n\t}\n\treturn {\n\t\tworkflowId,\n\t\taction: action as AdvanceAction,\n\t\t...(stageId !== undefined ? { stageId } : {}),\n\t\t...(evidence !== undefined ? { evidence } : {}),\n\t\t...(note !== undefined ? { note } : {}),\n\t};\n}\n\nfunction loadState(api: CapabilityAPI): WorkflowState {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\tconst entry = [...entries].reverse().find((item) => item.customType === WORKFLOW_STATE_ENTRY);\n\tif (!entry?.data || typeof entry.data !== \"object\") return { workflows: [] };\n\tconst data = entry.data as Partial<WorkflowState>;\n\treturn { workflows: Array.isArray(data.workflows) ? [...data.workflows] : [] };\n}\n\n/**\n * Plan facts read from the current branch's LATEST `plan.state` snapshot (the\n * same latest-snapshot semantics as the plan plugin's own loadState). The\n * plan.changed payload is never trusted for state — only as a trigger.\n */\nfunction loadPlansSnapshot(api: CapabilityAPI): Map<string, PlanFacts> {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\tfor (let index = entries.length - 1; index >= 0; index -= 1) {\n\t\tconst entry = entries[index];\n\t\tif (entry.customType !== planStateEntry) continue;\n\t\tconst data = entry.data;\n\t\tif (!data || typeof data !== \"object\" || Array.isArray(data)) return new Map();\n\t\tconst plans = (data as { plans?: unknown }).plans;\n\t\tif (!Array.isArray(plans)) return new Map();\n\t\tconst facts = new Map<string, PlanFacts>();\n\t\tfor (const plan of plans) {\n\t\t\tif (!plan || typeof plan !== \"object\") continue;\n\t\t\tconst record = plan as { id?: unknown; status?: unknown; evidence?: unknown };\n\t\t\tif (typeof record.id !== \"string\") continue;\n\t\t\tconst status =\n\t\t\t\trecord.status === \"draft\" ||\n\t\t\t\trecord.status === \"active\" ||\n\t\t\t\trecord.status === \"completed\" ||\n\t\t\t\trecord.status === \"cancelled\"\n\t\t\t\t\t? record.status\n\t\t\t\t\t: \"draft\";\n\t\t\tconst evidence = Array.isArray(record.evidence)\n\t\t\t\t? record.evidence.filter((item): item is string => typeof item === \"string\")\n\t\t\t\t: [];\n\t\t\tfacts.set(record.id, { id: record.id, status, evidence });\n\t\t}\n\t\treturn facts;\n\t}\n\treturn new Map();\n}\n\n/** Whether the latest `<entryType>` snapshot on the branch knows `id` in its `idsField` array (advisory, #10). */\nfunction idKnownToSession(api: CapabilityAPI, entryType: string, idsField: string, id: string): boolean {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\tfor (let index = entries.length - 1; index >= 0; index -= 1) {\n\t\tconst entry = entries[index];\n\t\tif (entry.customType !== entryType) continue;\n\t\tconst data = entry.data;\n\t\tif (!data || typeof data !== \"object\" || Array.isArray(data)) return false;\n\t\tconst records = (data as Record<string, unknown>)[idsField];\n\t\tif (!Array.isArray(records)) return false;\n\t\treturn records.some(\n\t\t\t(record) => record !== null && typeof record === \"object\" && (record as { id?: unknown }).id === id,\n\t\t);\n\t}\n\treturn false;\n}\n\n/**\n * Seeds the held-dedup view (§5 总则 5) from the branch audit stream: the\n * last transition per stage, whatever its code — a repeat held emission is\n * dropped only when it matches that last code and detail.\n */\nfunction buildLastStageTransition(api: CapabilityAPI): Map<string, { code: TransitionReasonCode; detail?: string }> {\n\tconst map = new Map<string, { code: TransitionReasonCode; detail?: string }>();\n\tfor (const entry of api.session?.getBranchEntries() ?? []) {\n\t\tif (entry.customType !== WORKFLOW_TRANSITION_ENTRY) continue;\n\t\tconst data = entry.data;\n\t\tif (!data || typeof data !== \"object\" || Array.isArray(data)) continue;\n\t\tconst record = data as Partial<WorkflowTransitionEntry>;\n\t\tif (typeof record.workflowId !== \"string\" || typeof record.stageId !== \"string\") continue;\n\t\tconst reason = record.reason as { code?: unknown; detail?: unknown } | undefined;\n\t\tif (!reason || typeof reason !== \"object\" || typeof reason.code !== \"string\") continue;\n\t\tmap.set(`${record.workflowId}::${record.stageId}`, {\n\t\t\tcode: reason.code as TransitionReasonCode,\n\t\t\tdetail: typeof reason.detail === \"string\" ? reason.detail : undefined,\n\t\t});\n\t}\n\treturn map;\n}\n\n/** Soft-reference warnings for the tool response only (never the persisted state, #10). */\nfunction collectSoftReferenceWarnings(\n\tapi: CapabilityAPI,\n\tgoalId: string | undefined,\n\tplanIds: { stageId: string; planId: string }[],\n\troles: { stageId: string; role: string }[],\n): string[] {\n\tconst warnings: string[] = [];\n\tif (goalId !== undefined && !idKnownToSession(api, goalStateEntry, \"goals\", goalId)) {\n\t\twarnings.push(\n\t\t\t`goalId \"${goalId}\" does not match any goal in this session's goal state; the workflow keeps the soft reference`,\n\t\t);\n\t}\n\tfor (const item of planIds) {\n\t\tif (!idKnownToSession(api, planStateEntry, \"plans\", item.planId)) {\n\t\t\twarnings.push(\n\t\t\t\t`stage ${item.stageId}: planId \"${item.planId}\" does not match any plan in this session's plan state; ` +\n\t\t\t\t\t\"the stage stays held until a reevaluation finds the plan\",\n\t\t\t);\n\t\t}\n\t}\n\tfor (const item of roles) {\n\t\t// The host's suite role associations are the only verifiable role face;\n\t\t// hosts without the listing leave the advice unverified (no warning).\n\t\tconst associated = api.host?.roleAssociations;\n\t\tif (associated !== undefined && !associated.includes(item.role)) {\n\t\t\twarnings.push(\n\t\t\t\t`stage ${item.stageId}: role \"${item.role}\" is not associated with the active suite; delegation advice treated as unspecified`,\n\t\t\t);\n\t\t}\n\t}\n\treturn warnings;\n}\n\ninterface WorkflowToolResponse extends WorkflowState {\n\tclosures?: WorkflowClosure[];\n\tinspections?: WorkflowInspection[];\n\twarning?: string;\n}\n\nexport function createCapability(\n\tapi: CapabilityAPI,\n): Promise<readonly DisposableRegistration[]> | readonly DisposableRegistration[] {\n\tlet state = loadState(api);\n\tconst deps: EngineDeps = {\n\t\tgetPlan: (planId) => loadPlansSnapshot(api).get(planId),\n\t\tlastStageTransition: buildLastStageTransition(api),\n\t};\n\n\t// Persistence boundary (§4): audit entries first, then the full snapshot —\n\t// a crash mid-batch replays from the older snapshot while the audit stays\n\t// intact. appendEntry failures propagate unchanged (§5 总则 5: no swallow);\n\t// publish rejections surface to the tool caller (or are contained on the\n\t// load/subscriber paths below).\n\tconst persistRun = (run: EngineRun): void => {\n\t\tfor (const transition of run.transitions) {\n\t\t\tapi.session?.appendEntry(WORKFLOW_TRANSITION_ENTRY, transition);\n\t\t}\n\t\tapi.session?.appendEntry(WORKFLOW_STATE_ENTRY, run.state);\n\t};\n\tconst announce = (run: EngineRun): Promise<unknown> =>\n\t\tapi.publish({ type: \"workflow.changed\", version: 1, correlationId: WORKFLOW_STATE_ENTRY, data: run.state });\n\n\t/**\n\t * §5 总则 3 containment: land the failure in diagnostics + a handler.error\n\t * transition (detail = original error text) and never rethrow. Best-effort\n\t * — an already-failing boundary must not turn isolation into a second crash.\n\t */\n\tconst quarantineEngineError = (error: unknown, trigger: WorkflowTransitionTrigger): void => {\n\t\ttry {\n\t\t\tif (state.workflows.length === 0) return;\n\t\t\tconst original = error instanceof Error ? error.message : String(error);\n\t\t\tconst text = `${trigger} handler failed: ${original}`;\n\t\t\tconst workflows = state.workflows.map((workflow) => structuredClone(workflow));\n\t\t\tconst transitions: WorkflowTransitionEntry[] = [];\n\t\t\tfor (const workflow of workflows) {\n\t\t\t\tif (workflow.diagnostics.length >= DIAGNOSTICS_CAP) workflow.diagnostics.shift();\n\t\t\t\tworkflow.diagnostics.push(text);\n\t\t\t\tworkflow.revision += 1;\n\t\t\t\ttransitions.push({\n\t\t\t\t\tworkflowId: workflow.id,\n\t\t\t\t\tfrom: workflow.status,\n\t\t\t\t\tto: workflow.status,\n\t\t\t\t\ttrigger,\n\t\t\t\t\treason: { code: \"handler.error\", message: text, detail: original },\n\t\t\t\t\trevision: workflow.revision,\n\t\t\t\t});\n\t\t\t}\n\t\t\tstate = { workflows };\n\t\t\tfor (const transition of transitions) {\n\t\t\t\tapi.session?.appendEntry(WORKFLOW_TRANSITION_ENTRY, transition);\n\t\t\t}\n\t\t\tapi.session?.appendEntry(WORKFLOW_STATE_ENTRY, state);\n\t\t\tvoid api\n\t\t\t\t.publish({ type: \"workflow.changed\", version: 1, correlationId: WORKFLOW_STATE_ENTRY, data: state })\n\t\t\t\t.catch(() => undefined);\n\t\t} catch {\n\t\t\t// Containment is best-effort by design.\n\t\t}\n\t};\n\n\t// §5 rule 8 recovery: state replayed from workflow.state, then the\n\t// load-time reevaluation (总则 1 fallback moment #1). Runs synchronously at\n\t// factory time; failures are contained, never blocking plugin load.\n\ttry {\n\t\tconst run = reevaluateAll(state, deps, \"load-reeval\");\n\t\tif (run.transitions.length > 0) {\n\t\t\tstate = run.state;\n\t\t\tpersistRun(run);\n\t\t\tvoid announce(run).catch(() => undefined);\n\t\t}\n\t} catch (error) {\n\t\tquarantineEngineError(error, \"load-reeval\");\n\t}\n\n\tconst setTool = api.registerTool({\n\t\tname: \"workflow_set\",\n\t\tlabel: \"Set workflow\",\n\t\tpromptGuidelines: [\n\t\t\tWORKFLOW_APPLICABILITY_GUIDE,\n\t\t\tWORKFLOW_AUTHORING_GUIDE,\n\t\t\tWORKFLOW_EXECUTION_GUIDE,\n\t\t\tWORKFLOW_CORRECTION_GUIDE,\n\t\t\tWORKFLOW_REVIEW_GUIDE,\n\t\t\tWORKFLOW_CONCURRENCY_GUIDE,\n\t\t],\n\t\tdescription:\n\t\t\t\"Create or update a workflow: a stage dependency graph (DAG) with per-stage objectives, acceptance evidence, and soft goal/plan references\",\n\t\tparameters: workflowSetSchema,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst parsed = parseWorkflowSetInput(objectInput(first, second));\n\t\t\tvalidateStageGraph(parsed.stages);\n\t\t\tconst current = state.workflows.find((workflow) => workflow.id === parsed.id);\n\t\t\tif (current !== undefined && parsed.revision <= current.revision) {\n\t\t\t\tthrow new Error(`stale workflow revision: ${parsed.id}`);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tcurrent !== undefined &&\n\t\t\t\t(current.status === \"completed\" || current.status === \"failed\" || current.status === \"cancelled\")\n\t\t\t) {\n\t\t\t\tthrow new Error(`workflow is terminal and cannot be updated: ${parsed.id}`);\n\t\t\t}\n\t\t\tconst diff = planWorkflowSpecUpdate(current, parsed);\n\t\t\tconst run = applyWorkflowSet(state, parsed, diff, deps);\n\t\t\tstate = run.state;\n\t\t\tif (run.transitions.length > 0 || diff.created) persistRun(run);\n\t\t\tif (run.transitions.length > 0 || diff.created) await announce(run);\n\t\t\tconst response: WorkflowToolResponse = { ...state };\n\t\t\tif (run.closures.length > 0) response.closures = run.closures;\n\t\t\tconst warnings = collectSoftReferenceWarnings(\n\t\t\t\tapi,\n\t\t\t\tparsed.goalId,\n\t\t\t\tparsed.stages.flatMap((stage) =>\n\t\t\t\t\tstage.planId !== undefined ? [{ stageId: stage.id, planId: stage.planId }] : [],\n\t\t\t\t),\n\t\t\t\tparsed.stages.flatMap((stage) =>\n\t\t\t\t\tstage.role !== undefined ? [{ stageId: stage.id, role: stage.role }] : [],\n\t\t\t\t),\n\t\t\t);\n\t\t\tif (warnings.length > 0) response.warning = warnings.join(\"; \");\n\t\t\treturn response;\n\t\t},\n\t});\n\n\tconst advanceTool = api.registerTool({\n\t\tname: \"workflow_advance\",\n\t\tlabel: \"Advance workflow\",\n\t\tdescription:\n\t\t\t\"Drive a workflow: start it, record acceptance evidence, inspect waiting conditions and coverage, approve/reject reviews, retreat, complete checkpoints, skip stages, or cancel\",\n\t\tparameters: workflowAdvanceSchema,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst parsed = parseAdvanceInput(objectInput(first, second));\n\t\t\t// Illegal conversions throw structured errors (§5 rule 6) surfaced\n\t\t\t// as tool errors unchanged; legal ones return the full snapshot\n\t\t\t// (the goal_set full-state response pattern).\n\t\t\tconst run = applyAdvance(state, parsed, deps);\n\t\t\tstate = run.state;\n\t\t\tif (run.transitions.length > 0) {\n\t\t\t\tpersistRun(run);\n\t\t\t\tawait announce(run);\n\t\t\t}\n\t\t\tconst response: WorkflowToolResponse = { ...state };\n\t\t\tif (parsed.action === \"inspect\") {\n\t\t\t\t// §5 rule 6 single-workflow semantics: applyAdvance has already\n\t\t\t\t// rejected unknown ids, so the target always resolves here.\n\t\t\t\tconst target = state.workflows.find((workflow) => workflow.id === parsed.workflowId);\n\t\t\t\tif (target !== undefined) response.inspections = [inspectWorkflow(target, deps)];\n\t\t\t}\n\t\t\tif (run.closures.length > 0) response.closures = run.closures;\n\t\t\treturn response;\n\t\t},\n\t});\n\n\tconst workflowCommand = api.registerCommand({\n\t\tname: \"workflow\",\n\t\tdescription: \"Workflow overview: dependency tree and status (default), why it is stopped, or the transition log\",\n\t\targumentHint: \"[view | why | log [N]]\",\n\t\texecute: async (args: string) => {\n\t\t\ttry {\n\t\t\t\tconst trimmed = args.trim();\n\t\t\t\tif (trimmed === \"\" || trimmed === \"view\") {\n\t\t\t\t\treturn { status: \"success\" as const, message: renderPanorama(state, deps) };\n\t\t\t\t}\n\t\t\t\tif (trimmed === \"why\") {\n\t\t\t\t\treturn { status: \"success\" as const, message: renderWhy(state, deps) };\n\t\t\t\t}\n\t\t\t\tconst logMatch = /^log(?:\\s+(\\d+))?$/.exec(trimmed);\n\t\t\t\tif (logMatch !== null) {\n\t\t\t\t\tconst limit = logMatch[1] === undefined ? 20 : Math.max(1, Number.parseInt(logMatch[1], 10));\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\t\tmessage: renderLog(api.session?.getBranchEntries() ?? [], limit),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn { status: \"error\" as const, message: \"Usage: /workflow [view | why | log [N]]\" };\n\t\t\t} catch (error) {\n\t\t\t\t// A slash command must not crash the host (memory /promote precedent).\n\t\t\t\treturn { status: \"error\" as const, message: error instanceof Error ? error.message : String(error) };\n\t\t\t}\n\t\t},\n\t});\n\n\t// The repository's first event subscription (§7). The payload is ignored:\n\t// reevaluation always reads the current branch entries (§5 总则 1).\n\tconst planChanged = api.subscribe(\"plan.changed\", async () => {\n\t\ttry {\n\t\t\tconst run = reevaluateAll(state, deps, \"plan.changed\");\n\t\t\tif (run.transitions.length === 0) return;\n\t\t\tstate = run.state;\n\t\t\tpersistRun(run);\n\t\t\tawait announce(run);\n\t\t} catch (error) {\n\t\t\tquarantineEngineError(error, \"plan.changed\");\n\t\t}\n\t});\n\n\treturn [setTool, advanceTool, workflowCommand, planChanged];\n}\n"]}
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /workflow command text rendering (§6 text face, §9 L1/L3): panorama
|
|
3
|
+
* (indented dependency tree + per-stage status + waiting conditions +
|
|
4
|
+
* parallel active count + retreat count + active diagnostics), why (one line
|
|
5
|
+
* per waiting stage), and log (transition stream, newest first, reason codes
|
|
6
|
+
* and amend records included). Plain text only — every host shape can render
|
|
7
|
+
* it, no TUI required.
|
|
8
|
+
*/
|
|
9
|
+
import { type EngineDeps } from "./engine.ts";
|
|
10
|
+
import { type WorkflowState } from "./types.ts";
|
|
11
|
+
/** Panorama: one block per workflow. */
|
|
12
|
+
export declare function renderPanorama(state: WorkflowState, deps: EngineDeps): string;
|
|
13
|
+
/** Why it is stopped: every stage with an unmet wait condition, one line each (§6 /workflow why). */
|
|
14
|
+
export declare function renderWhy(state: WorkflowState, deps: EngineDeps): string;
|
|
15
|
+
/** Transition stream, newest first (§8.1 "which conversion went wrong"): revision anchor + trigger + reason code. */
|
|
16
|
+
export declare function renderLog(entries: readonly {
|
|
17
|
+
customType?: string;
|
|
18
|
+
data?: unknown;
|
|
19
|
+
}[], limit: number): string;
|
|
20
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAoB,KAAK,UAAU,EAA8B,MAAM,aAAa,CAAC;AAC5F,OAAO,EAKN,KAAK,aAAa,EAElB,MAAM,YAAY,CAAC;AAmCpB,wCAAwC;AACxC,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CA4B7E;AAED,sGAAqG;AACrG,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAsBxE;AAgBD,sHAAqH;AACrH,wBAAgB,SAAS,CAAC,OAAO,EAAE,SAAS;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAgB5G","sourcesContent":["/**\n * /workflow command text rendering (§6 text face, §9 L1/L3): panorama\n * (indented dependency tree + per-stage status + waiting conditions +\n * parallel active count + retreat count + active diagnostics), why (one line\n * per waiting stage), and log (transition stream, newest first, reason codes\n * and amend records included). Plain text only — every host shape can render\n * it, no TUI required.\n */\n\nimport { computeWaitingOn, type EngineDeps, maxActiveOf, maxRetreatsOf } from \"./engine.ts\";\nimport {\n\ttype StageRuntime,\n\ttype StageSpec,\n\tWORKFLOW_TRANSITION_ENTRY,\n\ttype WorkflowRecord,\n\ttype WorkflowState,\n\ttype WorkflowTransitionEntry,\n} from \"./types.ts\";\n\nconst runtimeOf = (workflow: WorkflowRecord, stageId: string): StageRuntime | undefined =>\n\tworkflow.runtime.find((item) => item.stageId === stageId);\n\nfunction renderStageNode(\n\tworkflow: WorkflowRecord,\n\tspec: StageSpec,\n\tdepth: number,\n\tdeps: EngineDeps,\n\tlines: string[],\n\tvisited: Set<string>,\n): void {\n\tconst pad = \" \".repeat(depth + 1);\n\tif (visited.has(spec.id)) {\n\t\tlines.push(`${pad}-> ${spec.id} (shown above)`);\n\t\treturn;\n\t}\n\tvisited.add(spec.id);\n\tconst runtime = runtimeOf(workflow, spec.id);\n\tconst bits = [`- ${spec.id} [${runtime?.status ?? \"pending\"}] ${spec.title}`];\n\tif (runtime !== undefined) {\n\t\tconst waiting = computeWaitingOn(workflow, spec, runtime, deps);\n\t\tif (waiting !== null) bits.push(`— waiting: ${waiting}`);\n\t\tif (runtime.attempts > 0) bits.push(`· attempts ${runtime.attempts}`);\n\t\tif (runtime.evidence.length > 0) bits.push(`· evidence ${runtime.evidence.length}`);\n\t}\n\tlines.push(`${pad}${bits.join(\" \")}`);\n\t// DAG tree: children are dependents in declaration order; diamond edges\n\t// collapse into a back-reference line instead of duplicating the subtree.\n\tfor (const child of workflow.stages.filter((item) => item.dependsOn.includes(spec.id))) {\n\t\trenderStageNode(workflow, child, depth + 1, deps, lines, visited);\n\t}\n}\n\n/** Panorama: one block per workflow. */\nexport function renderPanorama(state: WorkflowState, deps: EngineDeps): string {\n\tif (state.workflows.length === 0) {\n\t\treturn \"no workflows in this session; create one with workflow_set\";\n\t}\n\treturn state.workflows\n\t\t.map((workflow) => {\n\t\t\tconst lines: string[] = [];\n\t\t\tconst active = workflow.runtime.filter((item) => item.status === \"active\").length;\n\t\t\tlines.push(\n\t\t\t\t`workflow \"${workflow.title}\" (${workflow.id}) — ${workflow.status} · revision ${workflow.revision} · active ${active}/${maxActiveOf(workflow)} · retreats ${workflow.retreatCount}/${maxRetreatsOf(workflow)}`,\n\t\t\t);\n\t\t\tif (workflow.goalId !== undefined) lines.push(` goal: ${workflow.goalId}`);\n\t\t\tconst visited = new Set<string>();\n\t\t\tfor (const spec of workflow.stages.filter((item) => item.dependsOn.length === 0)) {\n\t\t\t\trenderStageNode(workflow, spec, 0, deps, lines, visited);\n\t\t\t}\n\t\t\t// Stages unreachable from a root (defensive: cannot happen on a\n\t\t\t// validated acyclic graph) still render, top-level.\n\t\t\tfor (const spec of workflow.stages) {\n\t\t\t\tif (!visited.has(spec.id)) renderStageNode(workflow, spec, 0, deps, lines, visited);\n\t\t\t}\n\t\t\tif (workflow.diagnostics.length > 0) {\n\t\t\t\tlines.push(\" diagnostics:\");\n\t\t\t\tfor (const diagnostic of workflow.diagnostics) lines.push(` - ${diagnostic}`);\n\t\t\t}\n\t\t\treturn lines.join(\"\\n\");\n\t\t})\n\t\t.join(\"\\n\\n\");\n}\n\n/** Why it is stopped: every stage with an unmet wait condition, one line each (§6 /workflow why). */\nexport function renderWhy(state: WorkflowState, deps: EngineDeps): string {\n\tconst pending = state.workflows.filter(\n\t\t(workflow) => workflow.status !== \"completed\" && workflow.status !== \"cancelled\",\n\t);\n\tif (pending.length === 0) return \"no open workflows; nothing is waiting\";\n\treturn pending\n\t\t.map((workflow) => {\n\t\t\tconst lines = [`workflow ${workflow.id} — ${workflow.status}`];\n\t\t\tlet any = false;\n\t\t\tfor (const spec of workflow.stages) {\n\t\t\t\tconst runtime = runtimeOf(workflow, spec.id);\n\t\t\t\tif (runtime === undefined) continue;\n\t\t\t\tconst waiting = computeWaitingOn(workflow, spec, runtime, deps);\n\t\t\t\tif (waiting === null) continue;\n\t\t\t\tlines.push(` - ${spec.id} [${runtime.status}] waiting: ${waiting}`);\n\t\t\t\tany = true;\n\t\t\t}\n\t\t\tif (!any) lines.push(\" no stage is waiting on an unmet condition\");\n\t\t\tfor (const diagnostic of workflow.diagnostics) lines.push(` ! ${diagnostic}`);\n\t\t\treturn lines.join(\"\\n\");\n\t\t})\n\t\t.join(\"\\n\\n\");\n}\n\nfunction isTransitionEntry(data: unknown): data is WorkflowTransitionEntry {\n\tif (!data || typeof data !== \"object\" || Array.isArray(data)) return false;\n\tconst record = data as Partial<WorkflowTransitionEntry>;\n\treturn (\n\t\ttypeof record.workflowId === \"string\" &&\n\t\ttypeof record.from === \"string\" &&\n\t\ttypeof record.to === \"string\" &&\n\t\ttypeof record.revision === \"number\" &&\n\t\trecord.reason !== undefined &&\n\t\ttypeof record.reason === \"object\" &&\n\t\ttypeof (record.reason as { code?: unknown }).code === \"string\"\n\t);\n}\n\n/** Transition stream, newest first (§8.1 \"which conversion went wrong\"): revision anchor + trigger + reason code. */\nexport function renderLog(entries: readonly { customType?: string; data?: unknown }[], limit: number): string {\n\tconst transitions: WorkflowTransitionEntry[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.customType !== WORKFLOW_TRANSITION_ENTRY) continue;\n\t\tif (isTransitionEntry(entry.data)) transitions.push(entry.data);\n\t}\n\tif (transitions.length === 0) return \"no workflow transitions recorded\";\n\treturn transitions\n\t\t.slice(-limit)\n\t\t.reverse()\n\t\t.map((transition) => {\n\t\t\tconst stage = transition.stageId !== undefined ? `/${transition.stageId}` : \"\";\n\t\t\tconst detail = transition.reason.detail !== undefined ? ` — ${transition.reason.detail}` : \"\";\n\t\t\treturn `#${transition.revision} ${transition.workflowId}${stage} ${transition.from} -> ${transition.to} [${transition.trigger}] ${transition.reason.code}: ${transition.reason.message}${detail}`;\n\t\t})\n\t\t.join(\"\\n\");\n}\n"]}
|