@open-agent-toolkit/cli 0.3.19 → 0.3.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 +2 -1
- package/assets/agents/oat-phase-implementer.md +26 -3
- package/assets/agents/oat-reviewer.md +8 -3
- package/assets/bundle-metadata.json +1 -1
- package/assets/docs/reference/cli-reference.md +12 -7
- package/assets/docs/reference/oat-directory-structure.md +1 -0
- package/assets/docs/reference/project-artifacts.md +56 -1
- package/assets/docs/reference/project-state-machine.md +41 -7
- package/assets/docs/skills/brainstorm.md +3 -2
- package/assets/docs/skills/index.md +13 -10
- package/assets/docs/workflows/advanced/autonomy.md +3 -1
- package/assets/docs/workflows/advanced/dispatch-ceiling.md +2 -2
- package/assets/docs/workflows/advanced/workflow-gates.md +17 -4
- package/assets/docs/workflows/approvals-and-automation.md +21 -10
- package/assets/docs/workflows/choose-workflow.md +17 -9
- package/assets/docs/workflows/ideas/index.md +1 -1
- package/assets/docs/workflows/ideas/lifecycle.md +3 -2
- package/assets/docs/workflows/projects/closeout/closeout-skills.md +80 -7
- package/assets/docs/workflows/projects/closeout/pr-flow.md +7 -1
- package/assets/docs/workflows/projects/execution/execution-skills.md +16 -3
- package/assets/docs/workflows/projects/execution/implementation-execution.md +1 -1
- package/assets/docs/workflows/projects/execution/picking-up-projects.md +11 -1
- package/assets/docs/workflows/projects/lifecycle.md +108 -9
- package/assets/docs/workflows/projects/planning/hill-checkpoints.md +6 -6
- package/assets/docs/workflows/projects/planning/planning-skills.md +9 -7
- package/assets/docs/workflows/projects/planning/starting-projects.md +57 -11
- package/assets/docs/workflows/projects/reviews/index.md +22 -1
- package/assets/docs/workflows/projects/reviews/review-flavors.md +5 -3
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-brainstorm/SKILL.md +34 -9
- package/assets/skills/oat-brainstorm/references/destinations.md +6 -3
- package/assets/skills/oat-docs/SKILL.md +7 -3
- package/assets/skills/oat-pjm-review-backlog/SKILL.md +2 -2
- package/assets/skills/oat-project-autonomous/SKILL.md +9 -3
- package/assets/skills/oat-project-autonomous/references/gate-inventory.md +151 -132
- package/assets/skills/oat-project-brief/SKILL.md +1 -1
- package/assets/skills/oat-project-brief/references/brief-contract.md +458 -9
- package/assets/skills/oat-project-brief/references/docs/autonomy-contract.md +151 -132
- package/assets/skills/oat-project-brief/references/docs/gate-approval-record.md +9 -0
- package/assets/skills/oat-project-capture/SKILL.md +2 -2
- package/assets/skills/oat-project-complete/SKILL.md +14 -5
- package/assets/skills/oat-project-discover/SKILL.md +3 -2
- package/assets/skills/oat-project-document/SKILL.md +12 -6
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +151 -132
- package/assets/skills/oat-project-goal/SKILL.md +697 -0
- package/assets/skills/oat-project-goal/references/docs/autonomy-contract.md +412 -0
- package/assets/skills/oat-project-goal/references/docs/gate-approval-record.md +93 -0
- package/assets/skills/oat-project-implement/SKILL.md +1 -1
- package/assets/skills/oat-project-implement/references/completion-and-closeout.md +67 -0
- package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +151 -132
- package/assets/skills/oat-project-implement/references/docs/gate-approval-record.md +9 -0
- package/assets/skills/oat-project-implement/references/phase-execution.md +10 -3
- package/assets/skills/oat-project-implement/references/plan-and-resume.md +28 -1
- package/assets/skills/oat-project-lite/SKILL.md +1 -1
- package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +151 -132
- package/assets/skills/oat-project-new/SKILL.md +3 -3
- package/assets/skills/oat-project-next/SKILL.md +45 -15
- package/assets/skills/oat-project-next/references/docs/gate-approval-record.md +9 -0
- package/assets/skills/oat-project-plan/SKILL.md +14 -3
- package/assets/skills/oat-project-plan-writing/SKILL.md +6 -4
- package/assets/skills/oat-project-pr-final/SKILL.md +51 -1
- package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +151 -132
- package/assets/skills/oat-project-pr-progress/SKILL.md +97 -3
- package/assets/skills/oat-project-progress/SKILL.md +38 -5
- package/assets/skills/oat-project-progress/references/docs/gate-approval-record.md +9 -0
- package/assets/skills/oat-project-quick-start/SKILL.md +14 -9
- package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +151 -132
- package/assets/skills/oat-project-quick-start/references/docs/gate-approval-record.md +9 -0
- package/assets/skills/oat-project-reconcile/SKILL.md +31 -2
- package/assets/skills/oat-project-review-provide/SKILL.md +79 -13
- package/assets/skills/oat-project-review-receive/SKILL.md +70 -1
- package/assets/skills/oat-project-revise/SKILL.md +25 -1
- package/assets/skills/oat-project-summary/SKILL.md +60 -5
- package/assets/skills/oat-wave-execute/SKILL.md +2 -2
- package/assets/templates/state.md +1 -1
- package/dist/commands/project/closeout-check/closeout-invariant.d.ts +119 -3
- package/dist/commands/project/closeout-check/closeout-invariant.d.ts.map +1 -1
- package/dist/commands/project/closeout-check/closeout-invariant.js +454 -2
- package/dist/commands/project/closeout-check/index.d.ts +21 -3
- package/dist/commands/project/closeout-check/index.d.ts.map +1 -1
- package/dist/commands/project/closeout-check/index.js +190 -4
- package/dist/commands/project/complete-state/index.d.ts +2 -1
- package/dist/commands/project/complete-state/index.d.ts.map +1 -1
- package/dist/commands/project/complete-state/index.js +7 -1
- package/dist/commands/project/delivery/check.d.ts +66 -0
- package/dist/commands/project/delivery/check.d.ts.map +1 -0
- package/dist/commands/project/delivery/check.js +232 -0
- package/dist/commands/project/delivery/evidence.d.ts +171 -0
- package/dist/commands/project/delivery/evidence.d.ts.map +1 -0
- package/dist/commands/project/delivery/evidence.js +902 -0
- package/dist/commands/project/delivery/index.d.ts +7 -0
- package/dist/commands/project/delivery/index.d.ts.map +1 -0
- package/dist/commands/project/delivery/index.js +13 -0
- package/dist/commands/project/delivery/refresh.d.ts +110 -0
- package/dist/commands/project/delivery/refresh.d.ts.map +1 -0
- package/dist/commands/project/delivery/refresh.js +441 -0
- package/dist/commands/project/index.d.ts.map +1 -1
- package/dist/commands/project/index.js +2 -0
- package/dist/commands/project/log/append.d.ts +6 -0
- package/dist/commands/project/log/append.d.ts.map +1 -1
- package/dist/commands/project/log/append.js +6 -1
- package/dist/commands/project/new/scaffold.d.ts.map +1 -1
- package/dist/commands/project/new/scaffold.js +47 -1
- package/dist/commands/project/promote/promote.d.ts +15 -1
- package/dist/commands/project/promote/promote.d.ts.map +1 -1
- package/dist/commands/project/promote/promote.js +99 -15
- package/dist/commands/project/validate-plan/index.d.ts.map +1 -1
- package/dist/commands/project/validate-plan/index.js +10 -0
- package/dist/commands/project/validate-plan/profiles.d.ts +19 -4
- package/dist/commands/project/validate-plan/profiles.d.ts.map +1 -1
- package/dist/commands/project/validate-plan/profiles.js +153 -2
- package/dist/commands/shared/frontmatter.d.ts +1 -1
- package/dist/commands/shared/frontmatter.d.ts.map +1 -1
- package/dist/commands/shared/frontmatter.js +1 -0
- package/dist/commands/state/generate.d.ts.map +1 -1
- package/dist/commands/state/generate.js +35 -4
- package/dist/commands/tools/shared/pack-manifest.d.ts.map +1 -1
- package/dist/commands/tools/shared/pack-manifest.js +1 -0
- package/package.json +2 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parseBriefOutcomes, parsePhaseMarkers, parseTaskProgress, validateGoalOutcomeAudit, } from '@open-agent-toolkit/control-plane';
|
|
1
2
|
import YAML, { isMap } from 'yaml';
|
|
2
3
|
/**
|
|
3
4
|
* The closeout invariant shared by `oat project closeout-check` and
|
|
@@ -12,6 +13,13 @@ import YAML, { isMap } from 'yaml';
|
|
|
12
13
|
* persists. Once a snapshot exists it is authoritative: current configuration
|
|
13
14
|
* is never consulted, so a later config change cannot invalidate a persisted
|
|
14
15
|
* run.
|
|
16
|
+
*
|
|
17
|
+
* A goal project additionally passes the goal terminal boundary before either
|
|
18
|
+
* success return (`complete` or `not_required`): the terminal declaration, an
|
|
19
|
+
* exhaustive outcome audit validated by the control plane's single audit
|
|
20
|
+
* predicate, resolved extraction and delivery coverage over current
|
|
21
|
+
* observations. A complete snapshot cannot waive it, and every refusal names
|
|
22
|
+
* the actual next owner.
|
|
15
23
|
*/
|
|
16
24
|
export const SEQUENCE_FIELD = 'oat_post_implement_sequence';
|
|
17
25
|
export const RECOVERY_SKILL = 'oat-project-implement';
|
|
@@ -37,6 +45,392 @@ export const STEP_SKILLS = {
|
|
|
37
45
|
pr: 'oat-project-pr-final',
|
|
38
46
|
retro: 'oat-project-retro',
|
|
39
47
|
};
|
|
48
|
+
const GOAL_SKILL = 'oat-project-goal';
|
|
49
|
+
const DELIVERY_SKILL = 'oat-project-pr-progress';
|
|
50
|
+
const TERMINAL_DELIVERY_SKILL = 'oat-project-pr-final';
|
|
51
|
+
const REVIEW_SKILL = 'oat-project-review-provide';
|
|
52
|
+
/** The next owner for each refusal reason (A3 diagnostics). */
|
|
53
|
+
const REASON_OWNERS = {
|
|
54
|
+
'plan-unreadable': GOAL_SKILL,
|
|
55
|
+
'journal-unreadable': GOAL_SKILL,
|
|
56
|
+
'registry-unreadable': DELIVERY_SKILL,
|
|
57
|
+
'not-declared': GOAL_SKILL,
|
|
58
|
+
'audit-invalid': GOAL_SKILL,
|
|
59
|
+
'extraction-target-mismatch': GOAL_SKILL,
|
|
60
|
+
'child-missing': GOAL_SKILL,
|
|
61
|
+
'child-backlink-mismatch': GOAL_SKILL,
|
|
62
|
+
'child-incomplete': GOAL_SKILL,
|
|
63
|
+
'child-deferral-under-met': GOAL_SKILL,
|
|
64
|
+
'member-unobserved': DELIVERY_SKILL,
|
|
65
|
+
'delivery-duplicate-id': DELIVERY_SKILL,
|
|
66
|
+
'delivery-self-link': DELIVERY_SKILL,
|
|
67
|
+
'delivery-missing-target': DELIVERY_SKILL,
|
|
68
|
+
'delivery-link-mismatch': DELIVERY_SKILL,
|
|
69
|
+
'delivery-conflicting-predecessor': DELIVERY_SKILL,
|
|
70
|
+
'delivery-source-not-superseded': DELIVERY_SKILL,
|
|
71
|
+
'delivery-missing-link': DELIVERY_SKILL,
|
|
72
|
+
'delivery-cycle': DELIVERY_SKILL,
|
|
73
|
+
'delivery-replaced-after-endpoint': DELIVERY_SKILL,
|
|
74
|
+
'correction-claims-inherited-scope': DELIVERY_SKILL,
|
|
75
|
+
'delivery-registering': DELIVERY_SKILL,
|
|
76
|
+
'terminal-scopes-overlap': DELIVERY_SKILL,
|
|
77
|
+
'endpoint-unmet': DELIVERY_SKILL,
|
|
78
|
+
'evidence-unevaluated': DELIVERY_SKILL,
|
|
79
|
+
'review-not-fresh': REVIEW_SKILL,
|
|
80
|
+
'exit-carrier-not-fresh': RECOVERY_SKILL,
|
|
81
|
+
'scope-claim-unknown': DELIVERY_SKILL,
|
|
82
|
+
'scope-claim-unaccepted': DELIVERY_SKILL,
|
|
83
|
+
'phase-uncovered': TERMINAL_DELIVERY_SKILL,
|
|
84
|
+
};
|
|
85
|
+
function goalReason(code, message, subject) {
|
|
86
|
+
return subject === undefined ? { code, message } : { code, message, subject };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Validate the supersession graph and resolve every replacement chain to its
|
|
90
|
+
* terminal delivery (A4). In v1.5 each replacement has at most one direct
|
|
91
|
+
* predecessor: `covers_scope_of` names it and the predecessor's
|
|
92
|
+
* `superseded_by` points back. Missing targets, self-links, cycles,
|
|
93
|
+
* conflicting predecessors, mismatched links, a non-superseded source and a
|
|
94
|
+
* replacement of a delivery that already reached its endpoint are refused.
|
|
95
|
+
* `corrects_delivery_id` is additive and inherits no coverage, so a
|
|
96
|
+
* correction may not claim its target's scope.
|
|
97
|
+
*/
|
|
98
|
+
export function resolveDeliveryGraph(deliveries, phaseOrder = []) {
|
|
99
|
+
const errors = [];
|
|
100
|
+
const byId = new Map();
|
|
101
|
+
for (const delivery of deliveries) {
|
|
102
|
+
if (byId.has(delivery.delivery_id)) {
|
|
103
|
+
errors.push(goalReason('delivery-duplicate-id', `delivery id ${delivery.delivery_id} is registered more than once`, delivery.delivery_id));
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
byId.set(delivery.delivery_id, delivery);
|
|
107
|
+
}
|
|
108
|
+
const replacedBy = new Map();
|
|
109
|
+
for (const delivery of byId.values()) {
|
|
110
|
+
const id = delivery.delivery_id;
|
|
111
|
+
const predecessorId = delivery.covers_scope_of;
|
|
112
|
+
if (predecessorId !== null) {
|
|
113
|
+
const predecessor = byId.get(predecessorId);
|
|
114
|
+
if (predecessorId === id) {
|
|
115
|
+
errors.push(goalReason('delivery-self-link', `${id} covers its own scope`, id));
|
|
116
|
+
}
|
|
117
|
+
else if (predecessor === undefined) {
|
|
118
|
+
errors.push(goalReason('delivery-missing-target', `${id} covers the scope of ${predecessorId}, which is not registered`, id));
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const existing = replacedBy.get(predecessorId);
|
|
122
|
+
if (existing !== undefined) {
|
|
123
|
+
errors.push(goalReason('delivery-conflicting-predecessor', `${predecessorId} is replaced by both ${existing} and ${id}`, predecessorId));
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
replacedBy.set(predecessorId, id);
|
|
127
|
+
}
|
|
128
|
+
if (predecessor.superseded_by !== id) {
|
|
129
|
+
errors.push(goalReason('delivery-link-mismatch', `${id} covers ${predecessorId}, but ${predecessorId} records superseded_by ${predecessor.superseded_by ?? 'null'}`, id));
|
|
130
|
+
}
|
|
131
|
+
if (predecessor.status !== 'superseded') {
|
|
132
|
+
errors.push(goalReason('delivery-source-not-superseded', `${id} replaces ${predecessorId}, whose status is ${predecessor.status ?? 'unrecorded'}, not superseded`, predecessorId));
|
|
133
|
+
}
|
|
134
|
+
if (predecessor.endpoint_attainment !== null) {
|
|
135
|
+
errors.push(goalReason('delivery-replaced-after-endpoint', `${predecessorId} already reached its agreed endpoint; later corrections are additive and may not replace it`, predecessorId));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const successorId = delivery.superseded_by;
|
|
140
|
+
if (successorId !== null) {
|
|
141
|
+
const successor = byId.get(successorId);
|
|
142
|
+
if (successorId === id) {
|
|
143
|
+
errors.push(goalReason('delivery-self-link', `${id} supersedes itself`, id));
|
|
144
|
+
}
|
|
145
|
+
else if (successor === undefined) {
|
|
146
|
+
errors.push(goalReason('delivery-missing-target', `${id} is superseded by ${successorId}, which is not registered`, id));
|
|
147
|
+
}
|
|
148
|
+
else if (successor.covers_scope_of !== id) {
|
|
149
|
+
errors.push(goalReason('delivery-link-mismatch', `${id} is superseded by ${successorId}, but ${successorId} covers ${successor.covers_scope_of ?? 'nothing'}`, id));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else if (delivery.status === 'superseded') {
|
|
153
|
+
errors.push(goalReason('delivery-missing-link', `${id} is superseded but names no replacement`, id));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Cycles: follow each predecessor chain.
|
|
157
|
+
for (const delivery of byId.values()) {
|
|
158
|
+
const seen = new Set();
|
|
159
|
+
let current = delivery;
|
|
160
|
+
while (current !== undefined && current.covers_scope_of !== null) {
|
|
161
|
+
if (seen.has(current.delivery_id)) {
|
|
162
|
+
errors.push(goalReason('delivery-cycle', `the replacement chain through ${delivery.delivery_id} is a cycle`, delivery.delivery_id));
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
seen.add(current.delivery_id);
|
|
166
|
+
current = byId.get(current.covers_scope_of);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (errors.length > 0) {
|
|
170
|
+
return { terminals: [], errors: dedupe(errors) };
|
|
171
|
+
}
|
|
172
|
+
const order = new Map(phaseOrder.map((phaseId, index) => [phaseId, index]));
|
|
173
|
+
const rank = (phaseId) => order.get(phaseId) ?? order.size;
|
|
174
|
+
const terminals = [];
|
|
175
|
+
for (const delivery of byId.values()) {
|
|
176
|
+
if (delivery.status === 'superseded')
|
|
177
|
+
continue;
|
|
178
|
+
const scope = new Set(delivery.scope);
|
|
179
|
+
const inherits = [];
|
|
180
|
+
let predecessorId = delivery.covers_scope_of;
|
|
181
|
+
while (predecessorId !== null) {
|
|
182
|
+
const predecessor = byId.get(predecessorId);
|
|
183
|
+
inherits.push(predecessorId);
|
|
184
|
+
for (const phaseId of predecessor.scope)
|
|
185
|
+
scope.add(phaseId);
|
|
186
|
+
predecessorId = predecessor.covers_scope_of;
|
|
187
|
+
}
|
|
188
|
+
terminals.push({
|
|
189
|
+
delivery,
|
|
190
|
+
effectiveScope: [...scope].sort((left, right) => rank(left) - rank(right)),
|
|
191
|
+
inherits,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
for (const delivery of byId.values()) {
|
|
195
|
+
const targetId = delivery.corrects_delivery_id;
|
|
196
|
+
if (targetId === null)
|
|
197
|
+
continue;
|
|
198
|
+
const target = byId.get(targetId);
|
|
199
|
+
if (targetId === delivery.delivery_id) {
|
|
200
|
+
errors.push(goalReason('delivery-self-link', `${delivery.delivery_id} corrects itself`, delivery.delivery_id));
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (target === undefined) {
|
|
204
|
+
errors.push(goalReason('delivery-missing-target', `${delivery.delivery_id} corrects ${targetId}, which is not registered`, delivery.delivery_id));
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
const targetScope = new Set(target.scope);
|
|
208
|
+
for (const terminal of terminals) {
|
|
209
|
+
if (terminal.delivery.delivery_id === targetId ||
|
|
210
|
+
terminal.inherits.includes(targetId)) {
|
|
211
|
+
for (const phaseId of terminal.effectiveScope)
|
|
212
|
+
targetScope.add(phaseId);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const claimed = delivery.scope.filter((phaseId) => targetScope.has(phaseId));
|
|
216
|
+
if (claimed.length > 0) {
|
|
217
|
+
errors.push(goalReason('correction-claims-inherited-scope', `${delivery.delivery_id} is an additive correction of ${targetId} but claims its scope (${claimed.join(', ')}); corrections use new phase ids`, delivery.delivery_id));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return { terminals: errors.length > 0 ? [] : terminals, errors };
|
|
221
|
+
}
|
|
222
|
+
function dedupe(reasons) {
|
|
223
|
+
const seen = new Set();
|
|
224
|
+
return reasons.filter((entry) => {
|
|
225
|
+
const key = `${entry.code}:${entry.subject ?? ''}:${entry.message}`;
|
|
226
|
+
if (seen.has(key))
|
|
227
|
+
return false;
|
|
228
|
+
seen.add(key);
|
|
229
|
+
return true;
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
function sameMembers(left, right) {
|
|
233
|
+
return (left.length === right.length &&
|
|
234
|
+
[...left].sort().join(',') === [...right].sort().join(','));
|
|
235
|
+
}
|
|
236
|
+
/** Endpoint satisfaction on observed member state (design "Endpoint satisfaction"). */
|
|
237
|
+
function endpointObserved(delivery) {
|
|
238
|
+
const { endpoint, members } = delivery;
|
|
239
|
+
if (members.length === 0 || endpoint === null)
|
|
240
|
+
return false;
|
|
241
|
+
return endpoint === 'merged'
|
|
242
|
+
? members.every((member) => member.status === 'merged')
|
|
243
|
+
: members.every((member) => member.status === 'open' || member.status === 'merged');
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* The goal delivery coverage predicate (A4), over current observations:
|
|
247
|
+
* no registering entries; a valid supersession graph whose terminal
|
|
248
|
+
* deliveries have disjoint effective scopes; every terminal delivery at its
|
|
249
|
+
* agreed endpoint with a passed, fresh integrated review and an allowed,
|
|
250
|
+
* fresh exit-gate result evaluated against its entire effective scope; and
|
|
251
|
+
* every audited-accepted phase in exactly one terminal effective scope, with
|
|
252
|
+
* no claim of an unknown or unaccepted phase.
|
|
253
|
+
*/
|
|
254
|
+
export function evaluateGoalCoverage(input) {
|
|
255
|
+
const reasons = [];
|
|
256
|
+
for (const delivery of input.deliveries) {
|
|
257
|
+
if (delivery.status === 'registering') {
|
|
258
|
+
reasons.push(goalReason('delivery-registering', `${delivery.delivery_id} is still registering; resume its idempotent registration`, delivery.delivery_id));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const graph = resolveDeliveryGraph(input.deliveries, input.phaseOrder);
|
|
262
|
+
if (graph.errors.length > 0) {
|
|
263
|
+
return [...reasons, ...graph.errors];
|
|
264
|
+
}
|
|
265
|
+
const owners = new Map();
|
|
266
|
+
const known = new Set(input.phaseOrder);
|
|
267
|
+
for (const terminal of graph.terminals) {
|
|
268
|
+
const id = terminal.delivery.delivery_id;
|
|
269
|
+
if (terminal.delivery.status === 'registering')
|
|
270
|
+
continue;
|
|
271
|
+
for (const phaseId of terminal.effectiveScope) {
|
|
272
|
+
const owner = owners.get(phaseId);
|
|
273
|
+
if (owner !== undefined) {
|
|
274
|
+
reasons.push(goalReason('terminal-scopes-overlap', `${phaseId} is in the effective scope of both ${owner} and ${id}`, phaseId));
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
owners.set(phaseId, id);
|
|
278
|
+
}
|
|
279
|
+
if (!known.has(phaseId)) {
|
|
280
|
+
reasons.push(goalReason('scope-claim-unknown', `${id} claims ${phaseId}, which the brief does not declare`, phaseId));
|
|
281
|
+
}
|
|
282
|
+
else if (!input.acceptedPhases.has(phaseId)) {
|
|
283
|
+
reasons.push(goalReason('scope-claim-unaccepted', `${id} claims ${phaseId}, which the audit does not record as accepted`, phaseId));
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (!endpointObserved(terminal.delivery)) {
|
|
287
|
+
reasons.push(goalReason('endpoint-unmet', `${id} is not observed at its agreed endpoint (${terminal.delivery.endpoint ?? 'unrecorded'})`, id));
|
|
288
|
+
}
|
|
289
|
+
const fact = input.evidence[id];
|
|
290
|
+
if (fact === undefined ||
|
|
291
|
+
!sameMembers(fact.scope, terminal.effectiveScope)) {
|
|
292
|
+
reasons.push(goalReason('evidence-unevaluated', `${id}'s evidence was not evaluated against its effective scope (${terminal.effectiveScope.join(', ')})`, id));
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
if (!fact.review.fresh || fact.review.disposition !== 'passed') {
|
|
296
|
+
reasons.push(goalReason('review-not-fresh', `${id} has no passed, fresh integrated review over ${terminal.effectiveScope.join(', ')}: ${fact.review.reason ?? `disposition ${fact.review.disposition ?? 'unrecorded'}`}`, id));
|
|
297
|
+
}
|
|
298
|
+
if (fact.exit.outcome !== 'allowed' || fact.exit.freshness !== 'fresh') {
|
|
299
|
+
reasons.push(goalReason('exit-carrier-not-fresh', `${id}'s exit-gate result is ${fact.exit.outcome}, ${fact.exit.freshness}${fact.exit.reason ? `: ${fact.exit.reason}` : ''}`, id));
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
for (const phaseId of input.phaseOrder) {
|
|
303
|
+
if (input.acceptedPhases.has(phaseId) && !owners.has(phaseId)) {
|
|
304
|
+
reasons.push(goalReason('phase-uncovered', `accepted phase ${phaseId} is in no terminal delivery's effective scope`, phaseId));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return reasons;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* The goal terminal boundary (A3, A4): declaration, an exhaustive audit
|
|
311
|
+
* validated through the single audit predicate, resolved extraction, member
|
|
312
|
+
* observation and delivery coverage, in that order. Returns null when every
|
|
313
|
+
* check holds. Pure: every input arrives as data.
|
|
314
|
+
*/
|
|
315
|
+
export function evaluateGoalBoundary(frontmatter, goal) {
|
|
316
|
+
if (goal === undefined) {
|
|
317
|
+
return {
|
|
318
|
+
invariant: 'goal_inputs_unreadable',
|
|
319
|
+
reasons: [
|
|
320
|
+
goalReason('registry-unreadable', 'the goal boundary inputs were not loaded'),
|
|
321
|
+
],
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
const unreadable = [];
|
|
325
|
+
if (goal.planContent === null) {
|
|
326
|
+
unreadable.push(goalReason('plan-unreadable', 'plan.md could not be read'));
|
|
327
|
+
}
|
|
328
|
+
if (goal.implementationContent === null) {
|
|
329
|
+
unreadable.push(goalReason('journal-unreadable', 'implementation.md could not be read'));
|
|
330
|
+
}
|
|
331
|
+
if (goal.deliveries === null) {
|
|
332
|
+
unreadable.push(goalReason('registry-unreadable', 'the delivery registry could not be read'));
|
|
333
|
+
}
|
|
334
|
+
if (unreadable.length > 0 ||
|
|
335
|
+
goal.planContent === null ||
|
|
336
|
+
goal.implementationContent === null ||
|
|
337
|
+
goal.deliveries === null) {
|
|
338
|
+
return { invariant: 'goal_inputs_unreadable', reasons: unreadable };
|
|
339
|
+
}
|
|
340
|
+
if (frontmatter.oat_goal_status !== 'declared_met') {
|
|
341
|
+
return {
|
|
342
|
+
invariant: 'goal_not_declared',
|
|
343
|
+
reasons: [
|
|
344
|
+
goalReason('not-declared', '`oat_goal_status` is not `declared_met`; only oat-project-goal records the terminal declaration'),
|
|
345
|
+
],
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
const inventory = parseTaskProgress(goal.planContent, goal.implementationContent, { phaseUnits: true, extractedUnits: true }).phases;
|
|
349
|
+
const validation = validateGoalOutcomeAudit(frontmatter.oat_goal_outcome_audit, inventory, parseBriefOutcomes(goal.planContent));
|
|
350
|
+
if (!validation.valid || validation.audit === null) {
|
|
351
|
+
return {
|
|
352
|
+
invariant: 'goal_audit_invalid',
|
|
353
|
+
reasons: validation.errors.map((error) => goalReason('audit-invalid', `${error.code}: ${error.message}`, error.subject)),
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
const extraction = evaluateExtraction(goal, goal.planContent, inventory, validation.audit);
|
|
357
|
+
if (extraction.length > 0) {
|
|
358
|
+
return { invariant: 'goal_extraction_unresolved', reasons: extraction };
|
|
359
|
+
}
|
|
360
|
+
if (goal.observationFailures.length > 0) {
|
|
361
|
+
return {
|
|
362
|
+
invariant: 'goal_observation_failed',
|
|
363
|
+
reasons: goal.observationFailures.map((failure) => goalReason('member-unobserved', `${failure}; failure to observe a member is not endpoint success`)),
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
const acceptedPhases = new Set(Object.entries(validation.audit.phases)
|
|
367
|
+
.filter(([, entry]) => entry.disposition === 'accepted')
|
|
368
|
+
.map(([phaseId]) => phaseId));
|
|
369
|
+
const coverage = evaluateGoalCoverage({
|
|
370
|
+
deliveries: goal.deliveries,
|
|
371
|
+
phaseOrder: inventory.map((phase) => phase.phaseId),
|
|
372
|
+
acceptedPhases,
|
|
373
|
+
evidence: goal.evidence,
|
|
374
|
+
});
|
|
375
|
+
return coverage.length > 0
|
|
376
|
+
? { invariant: 'goal_coverage_incomplete', reasons: coverage }
|
|
377
|
+
: null;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Every extracted phase needs matching plan and journal targets and a child
|
|
381
|
+
* carrying the matching `oat_extracted_from` backlink that is complete, or
|
|
382
|
+
* whose outstanding obligation the audit defers with a reason and scope
|
|
383
|
+
* decision under `met_with_deferrals`.
|
|
384
|
+
*/
|
|
385
|
+
function evaluateExtraction(goal, planContent, inventory, audit) {
|
|
386
|
+
const reasons = [];
|
|
387
|
+
const planMarkers = parsePhaseMarkers(planContent);
|
|
388
|
+
for (const phase of inventory) {
|
|
389
|
+
const planTarget = planMarkers.get(phase.phaseId)?.extractedTo ?? null;
|
|
390
|
+
const journalTarget = phase.extracted?.to ?? null;
|
|
391
|
+
if (planTarget !== journalTarget) {
|
|
392
|
+
reasons.push(goalReason('extraction-target-mismatch', `${phase.phaseId}: the brief names ${planTarget ?? 'no extraction target'} but the journal names ${journalTarget ?? 'none'}`, phase.phaseId));
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
if (journalTarget === null)
|
|
396
|
+
continue;
|
|
397
|
+
const child = goal.children.find((entry) => entry.slug === journalTarget);
|
|
398
|
+
if (child === undefined || child.status !== 'found') {
|
|
399
|
+
reasons.push(goalReason('child-missing', `${phase.phaseId} is extracted to ${journalTarget}, but that child project is ${child?.status ?? 'missing'}`, phase.phaseId));
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
if (child.extractedFrom !== goal.goalSlug) {
|
|
403
|
+
reasons.push(goalReason('child-backlink-mismatch', `${journalTarget} records oat_extracted_from ${child.extractedFrom ?? 'null'}, not ${goal.goalSlug}`, phase.phaseId));
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (child.lifecycle === 'complete')
|
|
407
|
+
continue;
|
|
408
|
+
const entry = audit.phases[phase.phaseId];
|
|
409
|
+
const deferred = entry !== undefined &&
|
|
410
|
+
(entry.reason ?? '').trim() !== '' &&
|
|
411
|
+
(entry.scope_decision_ref ?? '').trim() !== '';
|
|
412
|
+
if (!deferred) {
|
|
413
|
+
reasons.push(goalReason('child-incomplete', `${journalTarget} is ${child.lifecycle ?? 'not complete'} and the audit records no approved deferral (reason and scope_decision_ref) for ${phase.phaseId}`, phase.phaseId));
|
|
414
|
+
}
|
|
415
|
+
else if (audit.disposition === 'met') {
|
|
416
|
+
reasons.push(goalReason('child-deferral-under-met', `${phase.phaseId}'s child obligation is deferred, so the audit must be met_with_deferrals`, phase.phaseId));
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return reasons;
|
|
420
|
+
}
|
|
421
|
+
function goalRefusal(verdict, inputs) {
|
|
422
|
+
const skill = REASON_OWNERS[verdict.reasons[0]?.code ?? 'registry-unreadable'];
|
|
423
|
+
return {
|
|
424
|
+
status: 'incomplete',
|
|
425
|
+
invariant: verdict.invariant,
|
|
426
|
+
detail: `the goal closeout boundary refuses: ${verdict.reasons
|
|
427
|
+
.map((entry) => `${entry.code} (${entry.message})`)
|
|
428
|
+
.join('; ')}`,
|
|
429
|
+
route: skill,
|
|
430
|
+
nextOwner: { kind: 'goal', skill, reasons: verdict.reasons },
|
|
431
|
+
inputs,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
40
434
|
class MalformedSnapshotError extends Error {
|
|
41
435
|
}
|
|
42
436
|
function malformed(detail) {
|
|
@@ -57,6 +451,16 @@ function readFrontmatter(content) {
|
|
|
57
451
|
const value = document.toJS();
|
|
58
452
|
return value;
|
|
59
453
|
}
|
|
454
|
+
/** The state's `oat_workflow_mode`, or null when the frontmatter cannot be read. */
|
|
455
|
+
export function readStateWorkflowMode(stateContent) {
|
|
456
|
+
try {
|
|
457
|
+
const mode = readFrontmatter(stateContent).oat_workflow_mode;
|
|
458
|
+
return typeof mode === 'string' ? mode : null;
|
|
459
|
+
}
|
|
460
|
+
catch {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
60
464
|
function readEnum(record, key, allowed, options = {}) {
|
|
61
465
|
if (!(key in record)) {
|
|
62
466
|
if (options.optional)
|
|
@@ -104,7 +508,40 @@ function assertCompletedPrefix(stored, completed, storedKey, completedKey) {
|
|
|
104
508
|
malformed(`\`${completedKey}\` is not a prefix of the stored \`${storedKey}\` order`);
|
|
105
509
|
}
|
|
106
510
|
}
|
|
107
|
-
|
|
511
|
+
const SATISFIED_BY_VALUES = ['delivery-coverage'];
|
|
512
|
+
/**
|
|
513
|
+
* Goal only: `satisfied_by` records a step completed by delivery coverage.
|
|
514
|
+
* Only the `pr` step may be satisfied that way, and only once execution of
|
|
515
|
+
* the stored order reached it, so the record must name a completed step.
|
|
516
|
+
*/
|
|
517
|
+
function readSatisfiedBy(record, workflowMode, completed) {
|
|
518
|
+
if (!('satisfied_by' in record) || record.satisfied_by === null) {
|
|
519
|
+
return {};
|
|
520
|
+
}
|
|
521
|
+
const value = record.satisfied_by;
|
|
522
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
523
|
+
malformed('`satisfied_by` must be a map of step to `delivery-coverage`');
|
|
524
|
+
}
|
|
525
|
+
if (workflowMode !== 'goal') {
|
|
526
|
+
malformed('`satisfied_by` is recorded only by a goal closeout');
|
|
527
|
+
}
|
|
528
|
+
const satisfiedBy = {};
|
|
529
|
+
for (const [step, source] of Object.entries(value)) {
|
|
530
|
+
if (step !== 'pr') {
|
|
531
|
+
malformed(`\`satisfied_by\` names \`${step}\`; only the \`pr\` step is satisfied by delivery coverage`);
|
|
532
|
+
}
|
|
533
|
+
if (typeof source !== 'string' ||
|
|
534
|
+
!SATISFIED_BY_VALUES.includes(source)) {
|
|
535
|
+
malformed('`satisfied_by.pr` must be `delivery-coverage`');
|
|
536
|
+
}
|
|
537
|
+
if (!completed.includes('pr')) {
|
|
538
|
+
malformed("`satisfied_by.pr` is recorded before the `pr` step's position in the stored order was reached");
|
|
539
|
+
}
|
|
540
|
+
satisfiedBy.pr = 'delivery-coverage';
|
|
541
|
+
}
|
|
542
|
+
return satisfiedBy;
|
|
543
|
+
}
|
|
544
|
+
export function parseCloseoutSnapshot(value, workflowMode = null) {
|
|
108
545
|
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
109
546
|
malformed('the snapshot must be a map');
|
|
110
547
|
}
|
|
@@ -148,6 +585,10 @@ export function parseCloseoutSnapshot(value) {
|
|
|
148
585
|
approval,
|
|
149
586
|
postApproval,
|
|
150
587
|
postApprovalCompleted,
|
|
588
|
+
satisfiedBy: readSatisfiedBy(record, workflowMode, [
|
|
589
|
+
...preApprovalCompleted,
|
|
590
|
+
...postApprovalCompleted,
|
|
591
|
+
]),
|
|
151
592
|
failure: record.failure ?? null,
|
|
152
593
|
};
|
|
153
594
|
if (status === 'complete') {
|
|
@@ -234,10 +675,18 @@ export async function evaluateCloseout(options) {
|
|
|
234
675
|
snapshot: snapshotPresent ? 'present' : 'absent',
|
|
235
676
|
snapshotSource: null,
|
|
236
677
|
};
|
|
678
|
+
// Goal: declaration, an exhaustive audit and delivery coverage are required
|
|
679
|
+
// before either success return; a complete snapshot cannot waive them.
|
|
680
|
+
if (workflowMode === 'goal') {
|
|
681
|
+
const verdict = evaluateGoalBoundary(frontmatter, options.goal);
|
|
682
|
+
if (verdict !== null) {
|
|
683
|
+
return goalRefusal(verdict, inputs);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
237
686
|
if (snapshotPresent) {
|
|
238
687
|
let snapshot;
|
|
239
688
|
try {
|
|
240
|
-
snapshot = parseCloseoutSnapshot(rawSnapshot);
|
|
689
|
+
snapshot = parseCloseoutSnapshot(rawSnapshot, workflowMode);
|
|
241
690
|
}
|
|
242
691
|
catch (error) {
|
|
243
692
|
if (!(error instanceof MalformedSnapshotError))
|
|
@@ -289,6 +738,9 @@ export async function evaluateCloseout(options) {
|
|
|
289
738
|
*/
|
|
290
739
|
export function formatCloseoutRefusal(projectPath, result) {
|
|
291
740
|
const owner = result.nextOwner;
|
|
741
|
+
if (owner.kind === 'goal') {
|
|
742
|
+
return `Closeout invariant not satisfied for ${projectPath} (${result.invariant}): ${result.detail}. Resume with ${owner.skill}.`;
|
|
743
|
+
}
|
|
292
744
|
const next = owner.kind === 'step'
|
|
293
745
|
? ` Next stored step: \`${owner.step}\` (${owner.skill}).`
|
|
294
746
|
: owner.kind === 'approval'
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { readFile as defaultReadFile } from 'node:fs/promises';
|
|
2
2
|
import { buildCommandContext, type CommandContext } from '../../../app/command-context.js';
|
|
3
|
+
import { type GhRunner } from '../../project/links/refresh.js';
|
|
4
|
+
import { type GitRunner } from '../../project/sync/git.js';
|
|
3
5
|
import { resolveEffectiveConfig } from '../../../config/resolve.js';
|
|
4
6
|
import { dirExists, fileExists } from '../../../fs/io.js';
|
|
7
|
+
import { type ProjectState } from '@open-agent-toolkit/control-plane';
|
|
5
8
|
import { Command } from 'commander';
|
|
6
|
-
import { type CloseoutResult } from './closeout-invariant.js';
|
|
7
|
-
export { evaluateCloseout, formatCloseoutRefusal, type CloseoutResult, } from './closeout-invariant.js';
|
|
9
|
+
import { type CloseoutResult, type GoalCloseoutInputs } from './closeout-invariant.js';
|
|
10
|
+
export { evaluateCloseout, evaluateGoalBoundary, evaluateGoalCoverage, formatCloseoutRefusal, resolveDeliveryGraph, type CloseoutResult, type DeliveryEvidenceFact, type ExtractedChildFact, type GoalCloseoutInputs, } from './closeout-invariant.js';
|
|
8
11
|
export interface CloseoutCheckDependencies {
|
|
9
12
|
buildCommandContext: (options: Parameters<typeof buildCommandContext>[0]) => CommandContext;
|
|
10
13
|
resolveProjectRoot: (cwd: string) => Promise<string>;
|
|
@@ -17,8 +20,23 @@ export interface CloseoutCheckDependencies {
|
|
|
17
20
|
* `--autonomous` under `OAT_AUTONOMOUS=1` still cannot fail open.
|
|
18
21
|
*/
|
|
19
22
|
env: NodeJS.ProcessEnv;
|
|
23
|
+
/** Goal only: read-only member observation (`gh pr view`). */
|
|
24
|
+
gh: GhRunner;
|
|
25
|
+
/** Goal only: read-only Git inspection for the shared evidence evaluator. */
|
|
26
|
+
git: GitRunner;
|
|
27
|
+
getProjectState: (projectPath: string) => Promise<ProjectState>;
|
|
28
|
+
listDirectories: (path: string) => Promise<string[]>;
|
|
20
29
|
}
|
|
21
30
|
export declare const DEFAULT_CLOSEOUT_CHECK_DEPENDENCIES: CloseoutCheckDependencies;
|
|
31
|
+
/** The dependencies `checkProjectCloseout` reads through. */
|
|
32
|
+
export type CloseoutInputDependencies = Pick<CloseoutCheckDependencies, 'resolveProjectRoot' | 'resolveEffectiveConfig' | 'readFile' | 'dirExists' | 'fileExists' | 'env' | 'gh' | 'git' | 'getProjectState' | 'listDirectories'>;
|
|
33
|
+
/**
|
|
34
|
+
* Load the goal boundary inputs read-only (A3): the brief, the journal, the
|
|
35
|
+
* registry with fresh member observations merged in (never persisted; that is
|
|
36
|
+
* `delivery refresh`'s job), each extracted child's facts, and the shared
|
|
37
|
+
* evaluator's verdict for every terminal delivery's effective scope.
|
|
38
|
+
*/
|
|
39
|
+
export declare function loadGoalCloseoutInputs(repoRoot: string, targetProjectPath: string, dependencies: CloseoutInputDependencies): Promise<GoalCloseoutInputs>;
|
|
22
40
|
export interface ProjectCloseoutCheck {
|
|
23
41
|
repoRoot: string;
|
|
24
42
|
targetProjectPath: string;
|
|
@@ -33,6 +51,6 @@ export interface ProjectCloseoutCheck {
|
|
|
33
51
|
*/
|
|
34
52
|
export declare function checkProjectCloseout(projectPath: string, options: {
|
|
35
53
|
autonomous: boolean;
|
|
36
|
-
}, context: CommandContext, dependencies:
|
|
54
|
+
}, context: CommandContext, dependencies: CloseoutInputDependencies): Promise<ProjectCloseoutCheck>;
|
|
37
55
|
export declare function createProjectCloseoutCheckCommand(overrides?: Partial<CloseoutCheckDependencies>): Command;
|
|
38
56
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/closeout-check/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,eAAe,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/closeout-check/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAW,MAAM,kBAAkB,CAAC;AAGxE,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAQhF,OAAO,EAEL,KAAK,QAAQ,EACd,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAE9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAE/C,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAKL,KAAK,cAAc,EAGnB,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,yBAAyB;IACxC,mBAAmB,EAAE,CACnB,OAAO,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAC/C,cAAc,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,QAAQ,EAAE,OAAO,eAAe,CAAC;IACjC,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,8DAA8D;IAC9D,EAAE,EAAE,QAAQ,CAAC;IACb,6EAA6E;IAC7E,GAAG,EAAE,SAAS,CAAC;IACf,eAAe,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAChE,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CACtD;AASD,eAAO,MAAM,mCAAmC,EAAE,yBAYjD,CAAC;AAEF,6DAA6D;AAC7D,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAC1C,yBAAyB,EACvB,oBAAoB,GACpB,wBAAwB,GACxB,UAAU,GACV,WAAW,GACX,YAAY,GACZ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,iBAAiB,GACjB,iBAAiB,CACpB,CAAC;AA4EF;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,MAAM,EACzB,YAAY,EAAE,yBAAyB,GACtC,OAAO,CAAC,kBAAkB,CAAC,CAuH7B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,cAAc,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE;IAAE,UAAU,EAAE,OAAO,CAAA;CAAE,EAChC,OAAO,EAAE,cAAc,EACvB,YAAY,EAAE,yBAAyB,GACtC,OAAO,CAAC,oBAAoB,CAAC,CAoC/B;AAmED,wBAAgB,iCAAiC,CAC/C,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CA2BT"}
|