@cat-factory/orchestration 0.30.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/container.d.ts +6 -1
  2. package/dist/container.d.ts.map +1 -1
  3. package/dist/container.js.map +1 -1
  4. package/dist/index.d.ts +2 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/modules/artifacts/artifactRetention.d.ts +17 -0
  9. package/dist/modules/artifacts/artifactRetention.d.ts.map +1 -0
  10. package/dist/modules/artifacts/artifactRetention.js +25 -0
  11. package/dist/modules/artifacts/artifactRetention.js.map +1 -0
  12. package/dist/modules/execution/ExecutionService.d.ts +16 -2
  13. package/dist/modules/execution/ExecutionService.d.ts.map +1 -1
  14. package/dist/modules/execution/ExecutionService.js +69 -7
  15. package/dist/modules/execution/ExecutionService.js.map +1 -1
  16. package/dist/modules/execution/VisualConfirmationController.d.ts +102 -0
  17. package/dist/modules/execution/VisualConfirmationController.d.ts.map +1 -0
  18. package/dist/modules/execution/VisualConfirmationController.js +352 -0
  19. package/dist/modules/execution/VisualConfirmationController.js.map +1 -0
  20. package/dist/modules/execution/ci.logic.d.ts +28 -5
  21. package/dist/modules/execution/ci.logic.d.ts.map +1 -1
  22. package/dist/modules/execution/ci.logic.js +30 -5
  23. package/dist/modules/execution/ci.logic.js.map +1 -1
  24. package/dist/modules/observability/observability.logic.d.ts +6 -0
  25. package/dist/modules/observability/observability.logic.d.ts.map +1 -1
  26. package/dist/modules/observability/observability.logic.js +15 -0
  27. package/dist/modules/observability/observability.logic.js.map +1 -1
  28. package/dist/modules/settings/WorkspaceSettingsService.d.ts.map +1 -1
  29. package/dist/modules/settings/WorkspaceSettingsService.js +1 -0
  30. package/dist/modules/settings/WorkspaceSettingsService.js.map +1 -1
  31. package/package.json +9 -9
@@ -0,0 +1,102 @@
1
+ import type { AgentExecutor, BinaryArtifactStore, Block, BlockRepository, ExecutionInstance, ExecutionRepository, PipelineStep, WorkRunner } from '@cat-factory/kernel';
2
+ import type { NotificationService } from '../notifications/NotificationService.js';
3
+ import type { AdvanceResult } from './advance.js';
4
+ import type { AgentContextBuilder } from './AgentContextBuilder.js';
5
+ /**
6
+ * The engine collaborators the visual-confirmation gate drives (kept on the engine, injected
7
+ * here). The binary-artifact store + notification channel are optional — absent ones put the
8
+ * gate into a degraded "manual" mode rather than failing.
9
+ */
10
+ export interface VisualConfirmationControllerDeps {
11
+ blockRepository: BlockRepository;
12
+ executionRepository: ExecutionRepository;
13
+ workRunner: WorkRunner;
14
+ agentExecutor: AgentExecutor;
15
+ contextBuilder: AgentContextBuilder;
16
+ notificationService?: NotificationService;
17
+ /** The binary-artifact store the gate reads screenshots + reference designs from. */
18
+ binaryArtifactStore?: BinaryArtifactStore;
19
+ /** The task's helper attempt budget (from the resolved merge preset). */
20
+ resolveMergePreset: (workspaceId: string, block: Block) => Promise<{
21
+ ciMaxAttempts: number;
22
+ }>;
23
+ parkStepOnDecision: (workspaceId: string, instance: ExecutionInstance, step: PipelineStep, proposal?: string) => Promise<AdvanceResult>;
24
+ finishStep: (step: PipelineStep) => void;
25
+ startStep: (step: PipelineStep) => void;
26
+ updateBlockProgress: (workspaceId: string, instance: ExecutionInstance, status: 'in_progress' | 'blocked') => Promise<void>;
27
+ finalizeBlock: (workspaceId: string, instance: ExecutionInstance, confidence: number | undefined) => Promise<void>;
28
+ stopRunContainer: (workspaceId: string, instance: ExecutionInstance) => Promise<void>;
29
+ persistInstance: (workspaceId: string, instance: ExecutionInstance) => Promise<void>;
30
+ emitInstance: (workspaceId: string, instance: ExecutionInstance) => Promise<void>;
31
+ clockNow: () => number;
32
+ }
33
+ /** The settle outcome of a helper (fixer) job, as seen by the gate. */
34
+ type HelperUpdate = {
35
+ state: 'done';
36
+ } | {
37
+ state: 'failed';
38
+ };
39
+ /**
40
+ * Drives the `visual-confirmation` gate: a non-LLM engine step where a HUMAN is the verdict.
41
+ * When reached it gathers the UI tester's captured screenshots + the human-uploaded reference
42
+ * designs (paired by view) and PARKS; a person reviews actual-vs-reference and drives one of:
43
+ * approve (advance), request a fix from findings (dispatch the Tester's `fixer`, then re-park),
44
+ * or recapture (refresh the pairs from the latest UI-tester report). Modelled like the
45
+ * `human-test` gate (the slow/awaiting work runs in the durable driver; the human actions just
46
+ * record intent + signal). Passes through (auto-advances) when no binary-artifact store is wired.
47
+ */
48
+ export declare class VisualConfirmationController {
49
+ private readonly deps;
50
+ constructor(deps: VisualConfirmationControllerDeps);
51
+ /**
52
+ * Run the gate from `step`. FRESH entry gathers screenshots and parks (or passes through
53
+ * when no store is wired). RE-ENTRY after a human action consumes the pending action.
54
+ */
55
+ evaluate(workspaceId: string, instance: ExecutionInstance, step: PipelineStep, block: Block, isFinalStep: boolean): Promise<AdvanceResult>;
56
+ /**
57
+ * A fixer job the gate dispatched has settled (delegated from `pollAgentJob`). Record the
58
+ * round's outcome, refresh the pairs from the latest UI-tester report, and re-park the human.
59
+ * We never fail the run here — the human is in control.
60
+ */
61
+ onHelperComplete(workspaceId: string, instance: ExecutionInstance, step: PipelineStep, update: HelperUpdate): Promise<AdvanceResult>;
62
+ /** The human approved the screenshots: advance the run. */
63
+ approve(workspaceId: string, blockId: string): Promise<ExecutionInstance>;
64
+ /** The human wrote findings and asked for a fix: dispatch the Tester's `fixer`. */
65
+ requestFix(workspaceId: string, blockId: string, findings: string): Promise<ExecutionInstance>;
66
+ /**
67
+ * Re-pair actual-vs-reference from the current store state: the latest UI-tester report's
68
+ * screenshots PLUS any reference design images uploaded since the gate parked. This is the
69
+ * action a human takes after uploading (or replacing) reference images mid-review, or after an
70
+ * out-of-band UI-tester re-run. NOTE: it does not itself re-run the UI tester — auto re-capture
71
+ * after a fix is a deferred enhancement (see the visual-confirmation handover doc) — so with no
72
+ * new references/run it is a harmless refresh that re-reads the same pairs.
73
+ */
74
+ recapture(workspaceId: string, blockId: string): Promise<ExecutionInstance>;
75
+ /** Fresh entry: gather screenshots and park (or pass through when no store is wired). */
76
+ private begin;
77
+ /** Consume a human-requested action on re-entry. */
78
+ private handleAction;
79
+ /** Dispatch the Tester's `fixer` from the human's findings and park on its job. */
80
+ private dispatchFixer;
81
+ /** Gather actual-vs-reference pairs: the latest UI-tester report's screenshots + block references. */
82
+ private gatherPairs;
83
+ /** Flip to awaiting-human, summon the human (idempotent notification), and park. */
84
+ private toAwaitingHuman;
85
+ /** Finish the gate step and advance to the next step (or finish the run). */
86
+ private completeStep;
87
+ /**
88
+ * Record the human's action on the parked gate step and wake the durable driver, which
89
+ * re-enters {@link evaluate} and acts on it. Re-arms the run to `running` first.
90
+ */
91
+ private signalAction;
92
+ /** Locate the run + gate step a block's visual-confirmation gate is parked on (or null). */
93
+ private findParked;
94
+ private requireParked;
95
+ private proposal;
96
+ /** Summon the human to review (idempotent per block+type). Best-effort. */
97
+ private raiseReadyNotification;
98
+ /** Dismiss the "ready for review" card once the gate passes. Best-effort. */
99
+ private clearReadyNotification;
100
+ }
101
+ export {};
102
+ //# sourceMappingURL=VisualConfirmationController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VisualConfirmationController.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/VisualConfirmationController.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,352 @@
1
+ import { ConflictError, isAsyncAgentExecutor } from '@cat-factory/kernel';
2
+ import { FIXER_AGENT_KIND, UI_TESTER_AGENT_KIND, VISUAL_CONFIRM_AGENT_KIND } from './ci.logic.js';
3
+ /** Render the human's findings as the resolved-context block handed to the fixer. */
4
+ function renderFindingsForFixer(findings) {
5
+ return [
6
+ 'A human reviewed the UI screenshots against the reference designs and asked for the',
7
+ 'changes below. Fix them and push to the PR branch; the UI will be reviewed again.',
8
+ '',
9
+ findings.trim(),
10
+ ]
11
+ .join('\n')
12
+ .trim();
13
+ }
14
+ /**
15
+ * Drives the `visual-confirmation` gate: a non-LLM engine step where a HUMAN is the verdict.
16
+ * When reached it gathers the UI tester's captured screenshots + the human-uploaded reference
17
+ * designs (paired by view) and PARKS; a person reviews actual-vs-reference and drives one of:
18
+ * approve (advance), request a fix from findings (dispatch the Tester's `fixer`, then re-park),
19
+ * or recapture (refresh the pairs from the latest UI-tester report). Modelled like the
20
+ * `human-test` gate (the slow/awaiting work runs in the durable driver; the human actions just
21
+ * record intent + signal). Passes through (auto-advances) when no binary-artifact store is wired.
22
+ */
23
+ export class VisualConfirmationController {
24
+ deps;
25
+ constructor(deps) {
26
+ this.deps = deps;
27
+ }
28
+ // ---- driver-entry paths --------------------------------------------------
29
+ /**
30
+ * Run the gate from `step`. FRESH entry gathers screenshots and parks (or passes through
31
+ * when no store is wired). RE-ENTRY after a human action consumes the pending action.
32
+ */
33
+ async evaluate(workspaceId, instance, step, block, isFinalStep) {
34
+ const vc = step.visualConfirm;
35
+ if (vc?.pendingAction) {
36
+ const action = vc.pendingAction;
37
+ vc.pendingAction = null;
38
+ // Checkpoint the consumed action BEFORE any slow/side-effecting work (a fixer dispatch
39
+ // is a real container), so a retry can't re-consume it and dispatch a second helper.
40
+ await this.deps.persistInstance(workspaceId, instance);
41
+ return this.handleAction(workspaceId, instance, step, block, isFinalStep, action);
42
+ }
43
+ if (!vc)
44
+ return this.begin(workspaceId, instance, step, block, isFinalStep);
45
+ // A fixer is in flight: re-attach to its job rather than re-parking.
46
+ if (vc.phase === 'fixing' && step.jobId) {
47
+ return { kind: 'awaiting_job', jobId: step.jobId, stepIndex: instance.currentStep };
48
+ }
49
+ return this.deps.parkStepOnDecision(workspaceId, instance, step, this.proposal(vc));
50
+ }
51
+ /**
52
+ * A fixer job the gate dispatched has settled (delegated from `pollAgentJob`). Record the
53
+ * round's outcome, refresh the pairs from the latest UI-tester report, and re-park the human.
54
+ * We never fail the run here — the human is in control.
55
+ */
56
+ async onHelperComplete(workspaceId, instance, step, update) {
57
+ const vc = step.visualConfirm;
58
+ if (!vc)
59
+ return { kind: 'continue' };
60
+ const rounds = vc.rounds ?? [];
61
+ const last = rounds[rounds.length - 1];
62
+ if (last && !last.outcome)
63
+ last.outcome = update.state === 'failed' ? 'failed' : 'completed';
64
+ step.jobId = undefined;
65
+ step.subtasks = undefined;
66
+ // Reclaim the finished helper container before re-parking.
67
+ await this.deps.stopRunContainer(workspaceId, instance);
68
+ const block = await this.deps.blockRepository.get(workspaceId, instance.blockId);
69
+ if (!block)
70
+ return { kind: 'noop' };
71
+ vc.pairs = await this.gatherPairs(workspaceId, instance, block);
72
+ // The pairs come from the LAST UI-tester report, which predates this fix — the gate does
73
+ // not auto re-run the UI tester yet (see the handover doc). Flag the staleness so the human
74
+ // knows to recapture (or re-run the UI tester) before judging the screenshots as final,
75
+ // unless the fix itself failed (then the existing pre-fix shots are still the right ones).
76
+ vc.degradedReason =
77
+ update.state === 'failed'
78
+ ? 'The requested fix did not complete — review the change manually, then approve or retry.'
79
+ : 'A fix was applied. These screenshots were captured BEFORE it — recapture (or re-run the UI tester) to refresh them before approving.';
80
+ return this.toAwaitingHuman(workspaceId, instance, step, block);
81
+ }
82
+ // ---- human actions (called from ExecutionService, driven server-side) ----
83
+ /** The human approved the screenshots: advance the run. */
84
+ async approve(workspaceId, blockId) {
85
+ return this.signalAction(workspaceId, blockId, { type: 'approve' });
86
+ }
87
+ /** The human wrote findings and asked for a fix: dispatch the Tester's `fixer`. */
88
+ async requestFix(workspaceId, blockId, findings) {
89
+ return this.signalAction(workspaceId, blockId, { type: 'request-fix', findings });
90
+ }
91
+ /**
92
+ * Re-pair actual-vs-reference from the current store state: the latest UI-tester report's
93
+ * screenshots PLUS any reference design images uploaded since the gate parked. This is the
94
+ * action a human takes after uploading (or replacing) reference images mid-review, or after an
95
+ * out-of-band UI-tester re-run. NOTE: it does not itself re-run the UI tester — auto re-capture
96
+ * after a fix is a deferred enhancement (see the visual-confirmation handover doc) — so with no
97
+ * new references/run it is a harmless refresh that re-reads the same pairs.
98
+ */
99
+ async recapture(workspaceId, blockId) {
100
+ return this.signalAction(workspaceId, blockId, { type: 'recapture' });
101
+ }
102
+ // ---- internals -----------------------------------------------------------
103
+ /** Fresh entry: gather screenshots and park (or pass through when no store is wired). */
104
+ async begin(workspaceId, instance, step, block, isFinalStep) {
105
+ // No store ⇒ nowhere to read screenshots from: pass through so a pipeline that includes
106
+ // the gate still completes (tests / a deployment without blob storage).
107
+ if (!this.deps.binaryArtifactStore) {
108
+ return this.completeStep(workspaceId, instance, step, isFinalStep);
109
+ }
110
+ const maxAttempts = (await this.deps.resolveMergePreset(workspaceId, block)).ciMaxAttempts;
111
+ const pairs = await this.gatherPairs(workspaceId, instance, block);
112
+ step.visualConfirm = {
113
+ phase: 'awaiting_human',
114
+ pairs,
115
+ attempts: 0,
116
+ maxAttempts,
117
+ rounds: [],
118
+ ...(pairs.length === 0
119
+ ? {
120
+ degradedReason: 'No UI screenshots were captured for this task — review the change manually, then approve or request a fix.',
121
+ }
122
+ : {}),
123
+ };
124
+ return this.toAwaitingHuman(workspaceId, instance, step, block);
125
+ }
126
+ /** Consume a human-requested action on re-entry. */
127
+ async handleAction(workspaceId, instance, step, block, isFinalStep, action) {
128
+ switch (action.type) {
129
+ case 'approve': {
130
+ const vc = step.visualConfirm;
131
+ if (vc)
132
+ vc.phase = 'approved';
133
+ await this.clearReadyNotification(workspaceId, instance.blockId);
134
+ return this.completeStep(workspaceId, instance, step, isFinalStep);
135
+ }
136
+ case 'request-fix':
137
+ return this.dispatchFixer(workspaceId, instance, step, block, action.findings ?? '');
138
+ case 'recapture': {
139
+ const vc = step.visualConfirm;
140
+ if (vc)
141
+ vc.pairs = await this.gatherPairs(workspaceId, instance, block);
142
+ return this.toAwaitingHuman(workspaceId, instance, step, block);
143
+ }
144
+ }
145
+ }
146
+ /** Dispatch the Tester's `fixer` from the human's findings and park on its job. */
147
+ async dispatchFixer(workspaceId, instance, step, block, findings) {
148
+ const vc = step.visualConfirm;
149
+ const executor = this.deps.agentExecutor;
150
+ // The fixer pushes onto the PR branch, so it needs one to exist + an async executor. If
151
+ // it can't run, DON'T silently swallow the human's findings: surface why on the gate (a
152
+ // degraded reason + a recorded failed round) and re-park, so the human sees the request
153
+ // didn't dispatch rather than the window quietly resetting.
154
+ if (!isAsyncAgentExecutor(executor) || !block.pullRequest?.branch) {
155
+ vc.degradedReason = !block.pullRequest?.branch
156
+ ? 'Could not request a fix: this task has no open pull-request branch for the fixer to push to. Review the change manually, then approve.'
157
+ : 'Could not request a fix: no async agent executor is wired in this runtime. Review the change manually, then approve.';
158
+ vc.rounds = [
159
+ ...(vc.rounds ?? []),
160
+ {
161
+ findings,
162
+ helperKind: FIXER_AGENT_KIND,
163
+ jobId: null,
164
+ outcome: 'failed',
165
+ at: this.deps.clockNow(),
166
+ },
167
+ ];
168
+ return this.toAwaitingHuman(workspaceId, instance, step, block);
169
+ }
170
+ const isFinalStep = instance.currentStep === instance.steps.length - 1;
171
+ const base = await this.deps.contextBuilder.buildContext(workspaceId, instance, step, isFinalStep, block);
172
+ const context = {
173
+ ...base,
174
+ agentKind: FIXER_AGENT_KIND,
175
+ priorOutputs: [
176
+ ...base.priorOutputs,
177
+ { agentKind: VISUAL_CONFIRM_AGENT_KIND, output: renderFindingsForFixer(findings) },
178
+ ],
179
+ };
180
+ const handle = await executor.startJob(context);
181
+ step.jobId = handle.jobId;
182
+ if (handle.model)
183
+ step.model = handle.model;
184
+ step.startingContainer = true;
185
+ step.subtasks = undefined;
186
+ // Leave the parked decision state: while the helper runs the step is `working` with a
187
+ // live job, NOT parked on a stale approval (a re-drive would otherwise abandon the job).
188
+ this.deps.startStep(step);
189
+ step.approval = null;
190
+ vc.phase = 'fixing';
191
+ // A fix is now in flight: clear any prior degraded note (e.g. a previous failed dispatch).
192
+ vc.degradedReason = null;
193
+ vc.attempts += 1;
194
+ vc.rounds = [
195
+ ...(vc.rounds ?? []),
196
+ {
197
+ findings,
198
+ helperKind: FIXER_AGENT_KIND,
199
+ jobId: handle.jobId,
200
+ outcome: null,
201
+ at: this.deps.clockNow(),
202
+ },
203
+ ];
204
+ await this.deps.persistInstance(workspaceId, instance);
205
+ await this.deps.emitInstance(workspaceId, instance);
206
+ return { kind: 'awaiting_job', jobId: step.jobId, stepIndex: instance.currentStep };
207
+ }
208
+ /** Gather actual-vs-reference pairs: the latest UI-tester report's screenshots + block references. */
209
+ async gatherPairs(workspaceId, instance, block) {
210
+ const byView = new Map();
211
+ // The artifact ids the run ACTUALLY uploaded — so a screenshot id the agent reported but
212
+ // that was never stored (a fabricated/typo'd id), or one since removed by the retention
213
+ // sweep, is treated as "not captured" rather than rendered as a dangling/404 gallery image.
214
+ const validActualIds = this.deps.binaryArtifactStore
215
+ ? new Set((await this.deps.binaryArtifactStore.listByExecution(workspaceId, instance.id))
216
+ .filter((r) => r.kind === 'screenshot')
217
+ .map((r) => r.id))
218
+ : null;
219
+ // Actual: the most recent `tester-ui` step's captured screenshots.
220
+ const uiStep = [...instance.steps]
221
+ .reverse()
222
+ .find((s) => s.agentKind === UI_TESTER_AGENT_KIND && s.test?.lastReport);
223
+ for (const shot of uiStep?.test?.lastReport?.screenshots ?? []) {
224
+ const actualArtifactId = validActualIds === null || validActualIds.has(shot.artifactId) ? shot.artifactId : null;
225
+ byView.set(shot.view, {
226
+ view: shot.view,
227
+ actualArtifactId,
228
+ referenceArtifactId: shot.referenceArtifactId ?? null,
229
+ });
230
+ }
231
+ // Reference: the block's uploaded reference design images (carry no executionId).
232
+ if (this.deps.binaryArtifactStore) {
233
+ const refs = (await this.deps.binaryArtifactStore.listByBlock(workspaceId, block.id)).filter((r) => r.kind === 'reference');
234
+ // `listByBlock` returns references oldest-first, so assign unconditionally: the LAST
235
+ // (newest) reference uploaded for a view wins. A human re-uploading a corrected reference
236
+ // for a view they already populated must override the stale one, not be discarded.
237
+ for (const ref of refs) {
238
+ const view = ref.view ?? '(reference)';
239
+ const existing = byView.get(view);
240
+ if (existing)
241
+ existing.referenceArtifactId = ref.id;
242
+ else
243
+ byView.set(view, { view, actualArtifactId: null, referenceArtifactId: ref.id });
244
+ }
245
+ }
246
+ return [...byView.values()];
247
+ }
248
+ /** Flip to awaiting-human, summon the human (idempotent notification), and park. */
249
+ async toAwaitingHuman(workspaceId, instance, step, block) {
250
+ const vc = step.visualConfirm;
251
+ vc.phase = 'awaiting_human';
252
+ await this.raiseReadyNotification(workspaceId, instance, block, vc);
253
+ return this.deps.parkStepOnDecision(workspaceId, instance, step, this.proposal(vc));
254
+ }
255
+ /** Finish the gate step and advance to the next step (or finish the run). */
256
+ async completeStep(workspaceId, instance, step, isFinalStep) {
257
+ this.deps.finishStep(step);
258
+ step.progress = 1;
259
+ step.subtasks = undefined;
260
+ step.approval = null;
261
+ if (isFinalStep) {
262
+ instance.status = 'done';
263
+ await this.deps.finalizeBlock(workspaceId, instance, undefined);
264
+ await this.deps.persistInstance(workspaceId, instance);
265
+ await this.deps.emitInstance(workspaceId, instance);
266
+ await this.deps.stopRunContainer(workspaceId, instance);
267
+ return { kind: 'done' };
268
+ }
269
+ instance.currentStep += 1;
270
+ const next = instance.steps[instance.currentStep];
271
+ if (next)
272
+ this.deps.startStep(next);
273
+ await this.deps.updateBlockProgress(workspaceId, instance, 'in_progress');
274
+ await this.deps.persistInstance(workspaceId, instance);
275
+ await this.deps.emitInstance(workspaceId, instance);
276
+ return { kind: 'continue' };
277
+ }
278
+ /**
279
+ * Record the human's action on the parked gate step and wake the durable driver, which
280
+ * re-enters {@link evaluate} and acts on it. Re-arms the run to `running` first.
281
+ */
282
+ async signalAction(workspaceId, blockId, action) {
283
+ const { instance, step } = this.requireParked(await this.findParked(workspaceId, blockId));
284
+ const vc = step.visualConfirm;
285
+ if (action.type === 'request-fix' && vc.attempts >= vc.maxAttempts) {
286
+ throw new ConflictError(`This task has reached its fix-attempt limit (${vc.maxAttempts}); approve the change or review it manually.`);
287
+ }
288
+ vc.pendingAction = action;
289
+ if (instance.status === 'blocked')
290
+ instance.status = 'running';
291
+ await this.deps.persistInstance(workspaceId, instance);
292
+ await this.deps.emitInstance(workspaceId, instance);
293
+ await this.deps.workRunner.signalDecision(workspaceId, instance.id, step.approval.id, 'visual-confirmation');
294
+ return instance;
295
+ }
296
+ /** Locate the run + gate step a block's visual-confirmation gate is parked on (or null). */
297
+ async findParked(workspaceId, blockId) {
298
+ const block = await this.deps.blockRepository.get(workspaceId, blockId);
299
+ if (!block?.executionId)
300
+ return null;
301
+ const instance = await this.deps.executionRepository.get(workspaceId, block.executionId);
302
+ if (!instance)
303
+ return null;
304
+ const step = instance.steps.find((s) => s.agentKind === VISUAL_CONFIRM_AGENT_KIND &&
305
+ s.state === 'waiting_decision' &&
306
+ s.approval?.status === 'pending');
307
+ return step ? { instance, step } : null;
308
+ }
309
+ requireParked(found) {
310
+ if (!found)
311
+ throw new ConflictError('No visual-confirmation gate is currently awaiting input');
312
+ return found;
313
+ }
314
+ proposal(vc) {
315
+ const n = vc.pairs?.length ?? 0;
316
+ return n > 0
317
+ ? `Review ${n} screenshot${n === 1 ? '' : 's'} against the reference designs, then approve or request a fix.`
318
+ : 'Review the UI change, then approve or request a fix.';
319
+ }
320
+ /** Summon the human to review (idempotent per block+type). Best-effort. */
321
+ async raiseReadyNotification(workspaceId, instance, block, vc) {
322
+ if (!this.deps.notificationService)
323
+ return;
324
+ const n = vc.pairs?.length ?? 0;
325
+ await this.deps.notificationService.raise(workspaceId, {
326
+ type: 'visual_confirmation_ready',
327
+ blockId: block.id,
328
+ executionId: instance.id,
329
+ title: `"${block.title}" is ready for visual confirmation`,
330
+ body: n > 0
331
+ ? `Review ${n} captured screenshot${n === 1 ? '' : 's'} against the reference designs, then approve or request a fix.`
332
+ : 'Review the UI change, then approve or request a fix.',
333
+ payload: {
334
+ ...(block.pullRequest?.url ? { prUrl: block.pullRequest.url } : {}),
335
+ pipelineName: instance.pipelineName,
336
+ },
337
+ });
338
+ }
339
+ /** Dismiss the "ready for review" card once the gate passes. Best-effort. */
340
+ async clearReadyNotification(workspaceId, blockId) {
341
+ const svc = this.deps.notificationService;
342
+ if (!svc)
343
+ return;
344
+ const open = await svc.listOpen(workspaceId);
345
+ for (const card of open) {
346
+ if (card.type === 'visual_confirmation_ready' && card.blockId === blockId) {
347
+ await svc.resolve(workspaceId, card.id, 'act');
348
+ }
349
+ }
350
+ }
351
+ }
352
+ //# sourceMappingURL=VisualConfirmationController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VisualConfirmationController.js","sourceRoot":"","sources":["../../../src/modules/execution/VisualConfirmationController.ts"],"names":[],"mappings":"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"}
@@ -54,12 +54,26 @@ export declare const BLUEPRINTS_AGENT_KIND = "blueprints";
54
54
  /** The agent kind of the container agent that scores a PR for the merge decision. */
55
55
  export declare const MERGER_AGENT_KIND = "merger";
56
56
  /**
57
- * The agent kind of the special `tester` gate step: a container agent that runs the
58
- * project's tests (local docker-compose infra or an ephemeral env) and returns a
59
- * structured report. On a withheld greenlight the engine loops the `fixer` agent
60
- * with the report and re-tests — mirroring the CI gate / ci-fixer loop.
57
+ * The agent kind of the API/general tester gate step (formerly `tester`): a container
58
+ * agent that runs the project's tests (local docker-compose infra or an ephemeral env)
59
+ * and returns a structured report. On a withheld greenlight the engine loops the `fixer`
60
+ * agent with the report and re-tests — mirroring the CI gate / ci-fixer loop. The UI
61
+ * tester ({@link UI_TESTER_AGENT_KIND}) is its browser-driven, screenshot-capturing sibling.
61
62
  */
62
- export declare const TESTER_AGENT_KIND = "tester";
63
+ export declare const TESTER_AGENT_KIND = "tester-api";
64
+ /**
65
+ * The agent kind of the UI tester gate step: like {@link TESTER_AGENT_KIND} but it drives
66
+ * a real browser (Playwright/Chromium — supplied by a dedicated UI-tester container image)
67
+ * against the running app, captures a non-redundant screenshot of each distinct view, and
68
+ * uploads them to the binary-artifact store. Its report carries `screenshots[]`, which the
69
+ * visual-confirmation gate reviews against the supplied reference designs. Shares the
70
+ * Tester→Fixer loop and the `tester.environment` infra choice; always needs a running app.
71
+ */
72
+ export declare const UI_TESTER_AGENT_KIND = "tester-ui";
73
+ /** Both tester gate kinds (API + UI). They share the Tester→Fixer loop + infra choice. */
74
+ export declare const TESTER_KINDS: readonly string[];
75
+ /** Whether an agent kind is one of the tester gate kinds (API or UI). */
76
+ export declare function isTesterKind(kind: string): boolean;
63
77
  /**
64
78
  * The agent kind of the read-only code-analysis agent that opens the tech-debt
65
79
  * recurring pipeline: it inspects the repo and emits a prioritized markdown report
@@ -82,4 +96,13 @@ export declare const TRACKER_AGENT_KIND = "tracker";
82
96
  * (no-env) mode when no ephemeral-environment provider is wired.
83
97
  */
84
98
  export declare const HUMAN_TEST_AGENT_KIND = "human-test";
99
+ /**
100
+ * The agent kind of the special `visual-confirmation` gate: a non-LLM engine step that
101
+ * PARKS for a human to review the UI tester's screenshots against the uploaded reference
102
+ * designs, then on demand dispatches the Tester's `fixer` (from the human's findings) and
103
+ * re-captures via the UI tester. Approving advances the run. Handled by the
104
+ * {@link VisualConfirmationController}; passes through (auto-advances) when no binary-artifact
105
+ * store is wired (nowhere to read screenshots from).
106
+ */
107
+ export declare const VISUAL_CONFIRM_AGENT_KIND = "visual-confirmation";
85
108
  //# sourceMappingURL=ci.logic.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ci.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/ci.logic.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,4BAA4B,EAC5B,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,SAAS,EACd,WAAW,EACX,SAAS,EACT,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,qBAAqB,CAAA;AAE5B;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B,wBAAwB,CAAA;AAEnE;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,mBAAmB,CAAA;AAEzD;;;;;;;;;GASG;AACH,eAAO,MAAM,kCAAkC,4BAA4B,CAAA;AAC3E,eAAO,MAAM,kCAAkC,4BAA4B,CAAA;AAE3E;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,qBAAqB,CAAA;AAE7D;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAA;AAEnD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,eAAe,CAAA;AAEjD,qFAAqF;AACrF,eAAO,MAAM,iBAAiB,WAAW,CAAA;AAEzC;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,WAAW,CAAA;AAEzC;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,aAAa,CAAA;AAE7C;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,YAAY,CAAA;AAE3C;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,eAAe,CAAA"}
1
+ {"version":3,"file":"ci.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/ci.logic.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,4BAA4B,EAC5B,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,SAAS,EACd,WAAW,EACX,SAAS,EACT,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,qBAAqB,CAAA;AAE5B;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B,wBAAwB,CAAA;AAEnE;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,mBAAmB,CAAA;AAEzD;;;;;;;;;GASG;AACH,eAAO,MAAM,kCAAkC,4BAA4B,CAAA;AAC3E,eAAO,MAAM,kCAAkC,4BAA4B,CAAA;AAE3E;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,qBAAqB,CAAA;AAE7D;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAA;AAEnD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,eAAe,CAAA;AAEjD,qFAAqF;AACrF,eAAO,MAAM,iBAAiB,WAAW,CAAA;AAEzC;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,eAAe,CAAA;AAE7C;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,cAAc,CAAA;AAE/C,0FAA0F;AAC1F,eAAO,MAAM,YAAY,EAAE,SAAS,MAAM,EAA8C,CAAA;AAExF,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,aAAa,CAAA;AAE7C;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,YAAY,CAAA;AAE3C;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,eAAe,CAAA;AAEjD;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,wBAAwB,CAAA"}
@@ -58,12 +58,28 @@ export const BLUEPRINTS_AGENT_KIND = 'blueprints';
58
58
  /** The agent kind of the container agent that scores a PR for the merge decision. */
59
59
  export const MERGER_AGENT_KIND = 'merger';
60
60
  /**
61
- * The agent kind of the special `tester` gate step: a container agent that runs the
62
- * project's tests (local docker-compose infra or an ephemeral env) and returns a
63
- * structured report. On a withheld greenlight the engine loops the `fixer` agent
64
- * with the report and re-tests — mirroring the CI gate / ci-fixer loop.
61
+ * The agent kind of the API/general tester gate step (formerly `tester`): a container
62
+ * agent that runs the project's tests (local docker-compose infra or an ephemeral env)
63
+ * and returns a structured report. On a withheld greenlight the engine loops the `fixer`
64
+ * agent with the report and re-tests — mirroring the CI gate / ci-fixer loop. The UI
65
+ * tester ({@link UI_TESTER_AGENT_KIND}) is its browser-driven, screenshot-capturing sibling.
65
66
  */
66
- export const TESTER_AGENT_KIND = 'tester';
67
+ export const TESTER_AGENT_KIND = 'tester-api';
68
+ /**
69
+ * The agent kind of the UI tester gate step: like {@link TESTER_AGENT_KIND} but it drives
70
+ * a real browser (Playwright/Chromium — supplied by a dedicated UI-tester container image)
71
+ * against the running app, captures a non-redundant screenshot of each distinct view, and
72
+ * uploads them to the binary-artifact store. Its report carries `screenshots[]`, which the
73
+ * visual-confirmation gate reviews against the supplied reference designs. Shares the
74
+ * Tester→Fixer loop and the `tester.environment` infra choice; always needs a running app.
75
+ */
76
+ export const UI_TESTER_AGENT_KIND = 'tester-ui';
77
+ /** Both tester gate kinds (API + UI). They share the Tester→Fixer loop + infra choice. */
78
+ export const TESTER_KINDS = [TESTER_AGENT_KIND, UI_TESTER_AGENT_KIND];
79
+ /** Whether an agent kind is one of the tester gate kinds (API or UI). */
80
+ export function isTesterKind(kind) {
81
+ return kind === TESTER_AGENT_KIND || kind === UI_TESTER_AGENT_KIND;
82
+ }
67
83
  /**
68
84
  * The agent kind of the read-only code-analysis agent that opens the tech-debt
69
85
  * recurring pipeline: it inspects the repo and emits a prioritized markdown report
@@ -86,4 +102,13 @@ export const TRACKER_AGENT_KIND = 'tracker';
86
102
  * (no-env) mode when no ephemeral-environment provider is wired.
87
103
  */
88
104
  export const HUMAN_TEST_AGENT_KIND = 'human-test';
105
+ /**
106
+ * The agent kind of the special `visual-confirmation` gate: a non-LLM engine step that
107
+ * PARKS for a human to review the UI tester's screenshots against the uploaded reference
108
+ * designs, then on demand dispatches the Tester's `fixer` (from the human's findings) and
109
+ * re-captures via the UI tester. Approving advances the run. Handled by the
110
+ * {@link VisualConfirmationController}; passes through (auto-advances) when no binary-artifact
111
+ * store is wired (nowhere to read screenshots from).
112
+ */
113
+ export const VISUAL_CONFIRM_AGENT_KIND = 'visual-confirmation';
89
114
  //# sourceMappingURL=ci.logic.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ci.logic.js","sourceRoot":"","sources":["../../../src/modules/execution/ci.logic.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,oFAAoF;AACpF,yFAAyF;AACzF,iDAAiD;AACjD,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,4BAA4B,EAC5B,gBAAgB,EAChB,uBAAuB,EAEvB,WAAW,EACX,SAAS,EACT,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,qBAAqB,CAAA;AAE5B;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,qBAAqB,CAAA;AAEnE;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,gBAAgB,CAAA;AAEzD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,kCAAkC,GAAG,yBAAyB,CAAA;AAC3E,MAAM,CAAC,MAAM,kCAAkC,GAAG,yBAAyB,CAAA;AAE3E;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,kBAAkB,CAAA;AAE7D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,aAAa,CAAA;AAEnD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAAA;AAEjD,qFAAqF;AACrF,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAA;AAEzC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAA;AAEzC;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAA;AAE7C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,SAAS,CAAA;AAE3C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAAA"}
1
+ {"version":3,"file":"ci.logic.js","sourceRoot":"","sources":["../../../src/modules/execution/ci.logic.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,oFAAoF;AACpF,yFAAyF;AACzF,iDAAiD;AACjD,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,4BAA4B,EAC5B,gBAAgB,EAChB,uBAAuB,EAEvB,WAAW,EACX,SAAS,EACT,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,qBAAqB,CAAA;AAE5B;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,qBAAqB,CAAA;AAEnE;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,gBAAgB,CAAA;AAEzD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,kCAAkC,GAAG,yBAAyB,CAAA;AAC3E,MAAM,CAAC,MAAM,kCAAkC,GAAG,yBAAyB,CAAA;AAE3E;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,kBAAkB,CAAA;AAE7D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,aAAa,CAAA;AAEnD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAAA;AAEjD,qFAAqF;AACrF,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAA;AAEzC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAA;AAE7C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,WAAW,CAAA;AAE/C,0FAA0F;AAC1F,MAAM,CAAC,MAAM,YAAY,GAAsB,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,CAAA;AAExF,yEAAyE;AACzE,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI,KAAK,iBAAiB,IAAI,IAAI,KAAK,oBAAoB,CAAA;AACpE,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAA;AAE7C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,SAAS,CAAA;AAE3C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAAA;AAEjD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,qBAAqB,CAAA"}
@@ -16,6 +16,12 @@ export declare function classifyCall(metric: Pick<LlmCallMetric, 'ok' | 'finishR
16
16
  export declare function outputHeadroomRatio(peakCompletionTokens: number, maxOutputTokens: number | null): number | null;
17
17
  /** Share of total latency spent in transport/proxy overhead (0..1), or null when no timing. */
18
18
  export declare function transportOverheadRatio(upstreamMs: number, overheadMs: number): number | null;
19
+ /**
20
+ * Share of prompt tokens served from the provider's prefix cache (0..1), or null when
21
+ * there were no prompt tokens. A low rate on a multi-turn run flags a cache-less hot
22
+ * path (e.g. a Workers-AI flavour) re-billing the whole prompt every turn.
23
+ */
24
+ export declare function cacheHitRate(cachedPromptTokens: number, promptTokens: number): number | null;
19
25
  /** The previous call's chain tip: enough to decide if the next call extends it. */
20
26
  export interface PromptChainTip {
21
27
  /** The previous call's full message count (its `messageCount`). */
@@ -1 +1 @@
1
- {"version":3,"file":"observability.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/observability/observability.logic.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACpF,OAAO,KAAK,EAAoB,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAMhF,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAA;AAEvD,uFAAuF;AACvF,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAI1E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,cAAc,CAAC,GAAG,cAAc,CAI/F;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,oBAAoB,EAAE,MAAM,EAC5B,eAAe,EAAE,MAAM,GAAG,IAAI,GAC7B,MAAM,GAAG,IAAI,CAGf;AAED,+FAA+F;AAC/F,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG5F;AAkBD,mFAAmF;AACnF,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAA;IACpB,qFAAqF;IACrF,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,iEAAiE;AACjE,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAA;IAClB,iBAAiB,EAAE,MAAM,CAAA;IACzB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,uFAAuF;AACvF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAS/C;AAWD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,cAAc,GAAG,IAAI,GAC1B,YAAY,CAkBd;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE,CAgC1E;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,aAAa,EAAE,EAC5B,WAAW,EAAE,MAAM,GAClB,gBAAgB,CAwDlB"}
1
+ {"version":3,"file":"observability.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/observability/observability.logic.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACpF,OAAO,KAAK,EAAoB,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAMhF,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAA;AAEvD,uFAAuF;AACvF,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAI1E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,cAAc,CAAC,GAAG,cAAc,CAI/F;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,oBAAoB,EAAE,MAAM,EAC5B,eAAe,EAAE,MAAM,GAAG,IAAI,GAC7B,MAAM,GAAG,IAAI,CAGf;AAED,+FAA+F;AAC/F,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG5F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,kBAAkB,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG5F;AAkBD,mFAAmF;AACnF,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAA;IACpB,qFAAqF;IACrF,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,iEAAiE;AACjE,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAA;IAClB,iBAAiB,EAAE,MAAM,CAAA;IACzB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,uFAAuF;AACvF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAS/C;AAWD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,cAAc,GAAG,IAAI,GAC1B,YAAY,CAkBd;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE,CAgC1E;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,aAAa,EAAE,EAC5B,WAAW,EAAE,MAAM,GAClB,gBAAgB,CAgElB"}