@generacy-ai/orchestrator 0.0.0-preview-20260304013206
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/LICENSE +191 -0
- package/dist/auth/api-key.d.ts +63 -0
- package/dist/auth/api-key.d.ts.map +1 -0
- package/dist/auth/api-key.js +102 -0
- package/dist/auth/api-key.js.map +1 -0
- package/dist/auth/github-oauth.d.ts +29 -0
- package/dist/auth/github-oauth.d.ts.map +1 -0
- package/dist/auth/github-oauth.js +136 -0
- package/dist/auth/github-oauth.js.map +1 -0
- package/dist/auth/index.d.ts +5 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +9 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/jwt.d.ts +34 -0
- package/dist/auth/jwt.d.ts.map +1 -0
- package/dist/auth/jwt.js +74 -0
- package/dist/auth/jwt.js.map +1 -0
- package/dist/auth/middleware.d.ts +43 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +101 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +5 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +21 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +295 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +733 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +174 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +30 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +173 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/index.d.ts +4 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +4 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/rate-limit.d.ts +32 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/middleware/rate-limit.js +92 -0
- package/dist/middleware/rate-limit.js.map +1 -0
- package/dist/middleware/request-logger.d.ts +31 -0
- package/dist/middleware/request-logger.d.ts.map +1 -0
- package/dist/middleware/request-logger.js +89 -0
- package/dist/middleware/request-logger.js.map +1 -0
- package/dist/routes/agents.d.ts +7 -0
- package/dist/routes/agents.d.ts.map +1 -0
- package/dist/routes/agents.js +78 -0
- package/dist/routes/agents.js.map +1 -0
- package/dist/routes/dispatch.d.ts +8 -0
- package/dist/routes/dispatch.d.ts.map +1 -0
- package/dist/routes/dispatch.js +46 -0
- package/dist/routes/dispatch.js.map +1 -0
- package/dist/routes/events.d.ts +14 -0
- package/dist/routes/events.d.ts.map +1 -0
- package/dist/routes/events.js +240 -0
- package/dist/routes/events.js.map +1 -0
- package/dist/routes/health.d.ts +14 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +132 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/index.d.ts +36 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +34 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/integrations.d.ts +34 -0
- package/dist/routes/integrations.d.ts.map +1 -0
- package/dist/routes/integrations.js +81 -0
- package/dist/routes/integrations.js.map +1 -0
- package/dist/routes/metrics.d.ts +31 -0
- package/dist/routes/metrics.d.ts.map +1 -0
- package/dist/routes/metrics.js +157 -0
- package/dist/routes/metrics.js.map +1 -0
- package/dist/routes/pr-webhooks.d.ts +15 -0
- package/dist/routes/pr-webhooks.d.ts.map +1 -0
- package/dist/routes/pr-webhooks.js +114 -0
- package/dist/routes/pr-webhooks.js.map +1 -0
- package/dist/routes/queue.d.ts +7 -0
- package/dist/routes/queue.d.ts.map +1 -0
- package/dist/routes/queue.js +94 -0
- package/dist/routes/queue.js.map +1 -0
- package/dist/routes/webhooks.d.ts +15 -0
- package/dist/routes/webhooks.d.ts.map +1 -0
- package/dist/routes/webhooks.js +117 -0
- package/dist/routes/webhooks.js.map +1 -0
- package/dist/routes/workflows.d.ts +7 -0
- package/dist/routes/workflows.d.ts.map +1 -0
- package/dist/routes/workflows.js +138 -0
- package/dist/routes/workflows.js.map +1 -0
- package/dist/server.d.ts +35 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +264 -0
- package/dist/server.js.map +1 -0
- package/dist/services/agent-registry.d.ts +89 -0
- package/dist/services/agent-registry.d.ts.map +1 -0
- package/dist/services/agent-registry.js +173 -0
- package/dist/services/agent-registry.js.map +1 -0
- package/dist/services/epic-completion-monitor-service.d.ts +69 -0
- package/dist/services/epic-completion-monitor-service.d.ts.map +1 -0
- package/dist/services/epic-completion-monitor-service.js +200 -0
- package/dist/services/epic-completion-monitor-service.js.map +1 -0
- package/dist/services/identity.d.ts +41 -0
- package/dist/services/identity.d.ts.map +1 -0
- package/dist/services/identity.js +91 -0
- package/dist/services/identity.js.map +1 -0
- package/dist/services/index.d.ts +13 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +13 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/label-monitor-service.d.ts +95 -0
- package/dist/services/label-monitor-service.d.ts.map +1 -0
- package/dist/services/label-monitor-service.js +414 -0
- package/dist/services/label-monitor-service.js.map +1 -0
- package/dist/services/label-sync-service.d.ts +76 -0
- package/dist/services/label-sync-service.d.ts.map +1 -0
- package/dist/services/label-sync-service.js +108 -0
- package/dist/services/label-sync-service.js.map +1 -0
- package/dist/services/phase-tracker-service.d.ts +32 -0
- package/dist/services/phase-tracker-service.d.ts.map +1 -0
- package/dist/services/phase-tracker-service.js +82 -0
- package/dist/services/phase-tracker-service.js.map +1 -0
- package/dist/services/pr-feedback-monitor-service.d.ts +86 -0
- package/dist/services/pr-feedback-monitor-service.d.ts.map +1 -0
- package/dist/services/pr-feedback-monitor-service.js +423 -0
- package/dist/services/pr-feedback-monitor-service.js.map +1 -0
- package/dist/services/queue-service.d.ts +62 -0
- package/dist/services/queue-service.d.ts.map +1 -0
- package/dist/services/queue-service.js +147 -0
- package/dist/services/queue-service.js.map +1 -0
- package/dist/services/redis-queue-adapter.d.ts +35 -0
- package/dist/services/redis-queue-adapter.d.ts.map +1 -0
- package/dist/services/redis-queue-adapter.js +218 -0
- package/dist/services/redis-queue-adapter.js.map +1 -0
- package/dist/services/smee-receiver.d.ts +87 -0
- package/dist/services/smee-receiver.d.ts.map +1 -0
- package/dist/services/smee-receiver.js +225 -0
- package/dist/services/smee-receiver.js.map +1 -0
- package/dist/services/webhook-setup-service.d.ts +253 -0
- package/dist/services/webhook-setup-service.d.ts.map +1 -0
- package/dist/services/webhook-setup-service.js +369 -0
- package/dist/services/webhook-setup-service.js.map +1 -0
- package/dist/services/worker-dispatcher.d.ts +57 -0
- package/dist/services/worker-dispatcher.d.ts.map +1 -0
- package/dist/services/worker-dispatcher.js +211 -0
- package/dist/services/worker-dispatcher.js.map +1 -0
- package/dist/services/workflow-service.d.ts +65 -0
- package/dist/services/workflow-service.d.ts.map +1 -0
- package/dist/services/workflow-service.js +164 -0
- package/dist/services/workflow-service.js.map +1 -0
- package/dist/sse/events.d.ts +50 -0
- package/dist/sse/events.d.ts.map +1 -0
- package/dist/sse/events.js +152 -0
- package/dist/sse/events.js.map +1 -0
- package/dist/sse/index.d.ts +4 -0
- package/dist/sse/index.d.ts.map +1 -0
- package/dist/sse/index.js +7 -0
- package/dist/sse/index.js.map +1 -0
- package/dist/sse/stream.d.ts +109 -0
- package/dist/sse/stream.d.ts.map +1 -0
- package/dist/sse/stream.js +239 -0
- package/dist/sse/stream.js.map +1 -0
- package/dist/sse/subscriptions.d.ts +91 -0
- package/dist/sse/subscriptions.d.ts.map +1 -0
- package/dist/sse/subscriptions.js +299 -0
- package/dist/sse/subscriptions.js.map +1 -0
- package/dist/types/api.d.ts +651 -0
- package/dist/types/api.d.ts.map +1 -0
- package/dist/types/api.js +169 -0
- package/dist/types/api.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +27 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/monitor.d.ts +243 -0
- package/dist/types/monitor.d.ts.map +1 -0
- package/dist/types/monitor.js +2 -0
- package/dist/types/monitor.js.map +1 -0
- package/dist/types/problem-details.d.ts +63 -0
- package/dist/types/problem-details.d.ts.map +1 -0
- package/dist/types/problem-details.js +37 -0
- package/dist/types/problem-details.js.map +1 -0
- package/dist/types/sse.d.ts +224 -0
- package/dist/types/sse.d.ts.map +1 -0
- package/dist/types/sse.js +103 -0
- package/dist/types/sse.js.map +1 -0
- package/dist/types/webhook.d.ts +59 -0
- package/dist/types/webhook.d.ts.map +1 -0
- package/dist/types/webhook.js +2 -0
- package/dist/types/webhook.js.map +1 -0
- package/dist/utils/correlation.d.ts +30 -0
- package/dist/utils/correlation.d.ts.map +1 -0
- package/dist/utils/correlation.js +34 -0
- package/dist/utils/correlation.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/shutdown.d.ts +28 -0
- package/dist/utils/shutdown.d.ts.map +1 -0
- package/dist/utils/shutdown.js +86 -0
- package/dist/utils/shutdown.js.map +1 -0
- package/dist/worker/claude-cli-worker.d.ts +61 -0
- package/dist/worker/claude-cli-worker.d.ts.map +1 -0
- package/dist/worker/claude-cli-worker.js +330 -0
- package/dist/worker/claude-cli-worker.js.map +1 -0
- package/dist/worker/cli-spawner.d.ts +42 -0
- package/dist/worker/cli-spawner.d.ts.map +1 -0
- package/dist/worker/cli-spawner.js +183 -0
- package/dist/worker/cli-spawner.js.map +1 -0
- package/dist/worker/config.d.ts +76 -0
- package/dist/worker/config.d.ts.map +1 -0
- package/dist/worker/config.js +39 -0
- package/dist/worker/config.js.map +1 -0
- package/dist/worker/epic-post-tasks.d.ts +73 -0
- package/dist/worker/epic-post-tasks.d.ts.map +1 -0
- package/dist/worker/epic-post-tasks.js +266 -0
- package/dist/worker/epic-post-tasks.js.map +1 -0
- package/dist/worker/gate-checker.d.ts +22 -0
- package/dist/worker/gate-checker.d.ts.map +1 -0
- package/dist/worker/gate-checker.js +41 -0
- package/dist/worker/gate-checker.js.map +1 -0
- package/dist/worker/index.d.ts +13 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +19 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/label-manager.d.ts +89 -0
- package/dist/worker/label-manager.d.ts.map +1 -0
- package/dist/worker/label-manager.js +200 -0
- package/dist/worker/label-manager.js.map +1 -0
- package/dist/worker/output-capture.d.ts +58 -0
- package/dist/worker/output-capture.d.ts.map +1 -0
- package/dist/worker/output-capture.js +153 -0
- package/dist/worker/output-capture.js.map +1 -0
- package/dist/worker/phase-loop.d.ts +64 -0
- package/dist/worker/phase-loop.d.ts.map +1 -0
- package/dist/worker/phase-loop.js +185 -0
- package/dist/worker/phase-loop.js.map +1 -0
- package/dist/worker/phase-resolver.d.ts +62 -0
- package/dist/worker/phase-resolver.d.ts.map +1 -0
- package/dist/worker/phase-resolver.js +144 -0
- package/dist/worker/phase-resolver.js.map +1 -0
- package/dist/worker/pr-feedback-handler.d.ts +105 -0
- package/dist/worker/pr-feedback-handler.d.ts.map +1 -0
- package/dist/worker/pr-feedback-handler.js +391 -0
- package/dist/worker/pr-feedback-handler.js.map +1 -0
- package/dist/worker/pr-linker.d.ts +69 -0
- package/dist/worker/pr-linker.d.ts.map +1 -0
- package/dist/worker/pr-linker.js +108 -0
- package/dist/worker/pr-linker.js.map +1 -0
- package/dist/worker/pr-manager.d.ts +61 -0
- package/dist/worker/pr-manager.d.ts.map +1 -0
- package/dist/worker/pr-manager.js +140 -0
- package/dist/worker/pr-manager.js.map +1 -0
- package/dist/worker/repo-checkout.d.ts +63 -0
- package/dist/worker/repo-checkout.d.ts.map +1 -0
- package/dist/worker/repo-checkout.js +160 -0
- package/dist/worker/repo-checkout.js.map +1 -0
- package/dist/worker/stage-comment-manager.d.ts +34 -0
- package/dist/worker/stage-comment-manager.d.ts.map +1 -0
- package/dist/worker/stage-comment-manager.js +114 -0
- package/dist/worker/stage-comment-manager.js.map +1 -0
- package/dist/worker/types.d.ts +192 -0
- package/dist/worker/types.d.ts.map +1 -0
- package/dist/worker/types.js +53 -0
- package/dist/worker/types.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { PHASE_SEQUENCE, PHASE_TO_COMMAND, PHASE_TO_STAGE } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Iterates through workflow phases from the starting phase to completion.
|
|
4
|
+
*
|
|
5
|
+
* For each phase the loop:
|
|
6
|
+
* 1. Updates labels to reflect the current phase
|
|
7
|
+
* 2. Spawns the Claude CLI (or runs the validate command)
|
|
8
|
+
* 3. Marks the phase as completed
|
|
9
|
+
* 4. Checks for review gates
|
|
10
|
+
* 5. Updates the stage comment with progress
|
|
11
|
+
*
|
|
12
|
+
* The loop stops on:
|
|
13
|
+
* - Gate hit (workflow paused for human review)
|
|
14
|
+
* - Phase failure (error)
|
|
15
|
+
* - Abort signal
|
|
16
|
+
* - All phases completed
|
|
17
|
+
*/
|
|
18
|
+
export class PhaseLoop {
|
|
19
|
+
logger;
|
|
20
|
+
constructor(logger) {
|
|
21
|
+
this.logger = logger;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Execute the phase loop from the starting phase through to completion.
|
|
25
|
+
*
|
|
26
|
+
* @param phaseSequence - Optional workflow-specific phase sequence.
|
|
27
|
+
* Defaults to the global PHASE_SEQUENCE for backward compatibility.
|
|
28
|
+
*/
|
|
29
|
+
async executeLoop(context, config, deps, phaseSequence) {
|
|
30
|
+
const sequence = phaseSequence ?? PHASE_SEQUENCE;
|
|
31
|
+
const { labelManager, stageCommentManager, gateChecker, cliSpawner, outputCapture, prManager } = deps;
|
|
32
|
+
const results = [];
|
|
33
|
+
// Track session ID across phases for conversation resume.
|
|
34
|
+
// When a CLI phase completes, its session ID is passed to the next phase
|
|
35
|
+
// so Claude CLI can reuse the conversation (keeping MCP servers warm and
|
|
36
|
+
// carrying forward accumulated context).
|
|
37
|
+
let currentSessionId;
|
|
38
|
+
// Find the starting index in the phase sequence
|
|
39
|
+
const startIndex = sequence.indexOf(context.startPhase);
|
|
40
|
+
if (startIndex === -1) {
|
|
41
|
+
throw new Error(`Unknown starting phase: ${context.startPhase}`);
|
|
42
|
+
}
|
|
43
|
+
this.logger.info({ startPhase: context.startPhase, startIndex, totalPhases: sequence.length }, 'Starting phase loop');
|
|
44
|
+
for (let i = startIndex; i < sequence.length; i++) {
|
|
45
|
+
const phase = sequence[i];
|
|
46
|
+
// Check abort signal before starting each phase
|
|
47
|
+
if (context.signal.aborted) {
|
|
48
|
+
this.logger.warn({ phase }, 'Abort signal detected, stopping phase loop');
|
|
49
|
+
return { results, completed: false, lastPhase: phase, gateHit: false };
|
|
50
|
+
}
|
|
51
|
+
this.logger.info({ phase, index: i }, 'Starting phase');
|
|
52
|
+
// 1. Update labels: mark this phase as active
|
|
53
|
+
await labelManager.onPhaseStart(phase);
|
|
54
|
+
// 2. Update stage comment to show phase in progress
|
|
55
|
+
const stage = PHASE_TO_STAGE[phase];
|
|
56
|
+
await stageCommentManager.updateStageComment({
|
|
57
|
+
stage,
|
|
58
|
+
status: 'in_progress',
|
|
59
|
+
phases: this.buildPhaseProgress(sequence, startIndex, i),
|
|
60
|
+
startedAt: new Date().toISOString(),
|
|
61
|
+
});
|
|
62
|
+
// 3. Execute the phase
|
|
63
|
+
let result;
|
|
64
|
+
try {
|
|
65
|
+
if (PHASE_TO_COMMAND[phase] === null) {
|
|
66
|
+
// Validate phase — run test command
|
|
67
|
+
result = await cliSpawner.runValidatePhase(context.checkoutPath, config.validateCommand, context.signal);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// CLI phase — spawn Claude CLI (resume previous session if available)
|
|
71
|
+
result = await cliSpawner.spawnPhase(phase, {
|
|
72
|
+
prompt: context.issueUrl,
|
|
73
|
+
cwd: context.checkoutPath,
|
|
74
|
+
env: {},
|
|
75
|
+
maxTurns: config.maxTurns,
|
|
76
|
+
timeoutMs: config.phaseTimeoutMs,
|
|
77
|
+
signal: context.signal,
|
|
78
|
+
resumeSessionId: currentSessionId,
|
|
79
|
+
}, outputCapture);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
// Unexpected error during spawning
|
|
84
|
+
this.logger.error({ phase, error: String(error) }, 'Unexpected error during phase execution');
|
|
85
|
+
await labelManager.onError(phase);
|
|
86
|
+
await stageCommentManager.updateStageComment({
|
|
87
|
+
stage,
|
|
88
|
+
status: 'error',
|
|
89
|
+
phases: this.buildPhaseProgress(sequence, startIndex, i, 'error'),
|
|
90
|
+
startedAt: new Date().toISOString(),
|
|
91
|
+
});
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
results.push(result);
|
|
95
|
+
// 3b. Capture session ID for resume in subsequent phases
|
|
96
|
+
if (result.sessionId) {
|
|
97
|
+
if (!currentSessionId) {
|
|
98
|
+
this.logger.info({ sessionId: result.sessionId, phase }, 'Captured initial session ID for conversation reuse');
|
|
99
|
+
}
|
|
100
|
+
currentSessionId = result.sessionId;
|
|
101
|
+
}
|
|
102
|
+
// 4. Handle phase failure
|
|
103
|
+
if (!result.success) {
|
|
104
|
+
this.logger.error({ phase, exitCode: result.exitCode, error: result.error?.message }, 'Phase failed');
|
|
105
|
+
await labelManager.onError(phase);
|
|
106
|
+
await stageCommentManager.updateStageComment({
|
|
107
|
+
stage,
|
|
108
|
+
status: 'error',
|
|
109
|
+
phases: this.buildPhaseProgress(sequence, startIndex, i, 'error'),
|
|
110
|
+
startedAt: new Date().toISOString(),
|
|
111
|
+
});
|
|
112
|
+
return { results, completed: false, lastPhase: phase, gateHit: false };
|
|
113
|
+
}
|
|
114
|
+
// 5. Mark phase as completed in labels
|
|
115
|
+
await labelManager.onPhaseComplete(phase);
|
|
116
|
+
// 5b. Commit, push, and ensure draft PR exists
|
|
117
|
+
const prUrl = await prManager.commitPushAndEnsurePr(phase);
|
|
118
|
+
if (prUrl) {
|
|
119
|
+
context.prUrl = prUrl;
|
|
120
|
+
}
|
|
121
|
+
// 6. Check for review gates
|
|
122
|
+
const gate = gateChecker.checkGate(phase, context.item.workflowName, config);
|
|
123
|
+
if (gate && gate.condition === 'always') {
|
|
124
|
+
this.logger.info({ phase, gateLabel: gate.gateLabel }, 'Gate hit, pausing workflow');
|
|
125
|
+
await labelManager.onGateHit(phase, gate.gateLabel);
|
|
126
|
+
// Update the result with gate info
|
|
127
|
+
result.gateHit = {
|
|
128
|
+
gateLabel: gate.gateLabel,
|
|
129
|
+
reason: `Review gate "${gate.gateLabel}" activated after phase "${phase}"`,
|
|
130
|
+
};
|
|
131
|
+
// Update stage comment showing gate hit
|
|
132
|
+
await stageCommentManager.updateStageComment({
|
|
133
|
+
stage,
|
|
134
|
+
status: 'in_progress',
|
|
135
|
+
phases: this.buildPhaseProgress(sequence, startIndex, i, 'complete'),
|
|
136
|
+
startedAt: new Date().toISOString(),
|
|
137
|
+
prUrl: context.prUrl,
|
|
138
|
+
});
|
|
139
|
+
return { results, completed: false, lastPhase: phase, gateHit: true };
|
|
140
|
+
}
|
|
141
|
+
// 7. Update stage comment showing phase complete
|
|
142
|
+
const isLastPhaseInStage = i + 1 >= sequence.length || PHASE_TO_STAGE[sequence[i + 1]] !== stage;
|
|
143
|
+
await stageCommentManager.updateStageComment({
|
|
144
|
+
stage,
|
|
145
|
+
status: isLastPhaseInStage ? 'complete' : 'in_progress',
|
|
146
|
+
phases: this.buildPhaseProgress(sequence, startIndex, i, 'complete'),
|
|
147
|
+
startedAt: new Date().toISOString(),
|
|
148
|
+
...(isLastPhaseInStage ? { completedAt: new Date().toISOString() } : {}),
|
|
149
|
+
prUrl: context.prUrl,
|
|
150
|
+
});
|
|
151
|
+
// Clear output buffer for next phase
|
|
152
|
+
outputCapture.clear();
|
|
153
|
+
}
|
|
154
|
+
this.logger.info('Phase loop completed successfully — all phases done');
|
|
155
|
+
return {
|
|
156
|
+
results,
|
|
157
|
+
completed: true,
|
|
158
|
+
lastPhase: sequence[sequence.length - 1],
|
|
159
|
+
gateHit: false,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Build a phase progress array for stage comment updates.
|
|
164
|
+
*/
|
|
165
|
+
buildPhaseProgress(sequence, startIndex, currentIndex, currentStatus = 'in_progress') {
|
|
166
|
+
const now = new Date().toISOString();
|
|
167
|
+
return sequence.map((phase, idx) => {
|
|
168
|
+
if (idx < startIndex) {
|
|
169
|
+
// Before the start — already complete from a prior run
|
|
170
|
+
return { phase, status: 'complete', completedAt: now };
|
|
171
|
+
}
|
|
172
|
+
if (idx < currentIndex) {
|
|
173
|
+
// Earlier in this run — completed
|
|
174
|
+
return { phase, status: 'complete', startedAt: now, completedAt: now };
|
|
175
|
+
}
|
|
176
|
+
if (idx === currentIndex) {
|
|
177
|
+
// Current phase
|
|
178
|
+
return { phase, status: currentStatus, startedAt: now };
|
|
179
|
+
}
|
|
180
|
+
// Future phase
|
|
181
|
+
return { phase, status: 'pending' };
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=phase-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phase-loop.js","sourceRoot":"","sources":["../../src/worker/phase-loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type WorkflowPhase } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Unified mapping from gate names to their owning phase and the phase to resume from.
|
|
4
|
+
*
|
|
5
|
+
* - `phase`: the workflow phase this gate belongs to (used to normalize gate names in resolveFromProcess)
|
|
6
|
+
* - `resumeFrom`: the phase to start from when the gate is satisfied (used in resolveFromContinue)
|
|
7
|
+
*/
|
|
8
|
+
export declare const GATE_MAPPING: Record<string, {
|
|
9
|
+
phase: WorkflowPhase;
|
|
10
|
+
resumeFrom: WorkflowPhase;
|
|
11
|
+
}>;
|
|
12
|
+
/**
|
|
13
|
+
* Workflow-specific gate mappings that override the global GATE_MAPPING.
|
|
14
|
+
*
|
|
15
|
+
* For epic workflows, certain gates have different resume behavior:
|
|
16
|
+
* - `tasks-review`: resumes to 'tasks' (triggers post-tasks/child creation, not implement)
|
|
17
|
+
* - `children-complete`: dedicated handling (routes to epic-complete command)
|
|
18
|
+
* - `epic-approval`: dedicated handling (routes to epic-close)
|
|
19
|
+
*/
|
|
20
|
+
export declare const WORKFLOW_GATE_MAPPING: Record<string, Record<string, {
|
|
21
|
+
phase: WorkflowPhase;
|
|
22
|
+
resumeFrom: WorkflowPhase;
|
|
23
|
+
}>>;
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the starting phase based on issue labels and command type.
|
|
26
|
+
*/
|
|
27
|
+
export declare class PhaseResolver {
|
|
28
|
+
/**
|
|
29
|
+
* Determine the starting phase for a queue item.
|
|
30
|
+
*
|
|
31
|
+
* - 'process' command: inspects completed/phase labels to find the next uncompleted phase.
|
|
32
|
+
* - 'continue' command: matches completed gate labels via GATE_MAPPING to determine resume phase.
|
|
33
|
+
*
|
|
34
|
+
* @param workflowName - Optional workflow name for workflow-specific gate resolution.
|
|
35
|
+
* When provided, uses the workflow's phase sequence and gate mappings.
|
|
36
|
+
*/
|
|
37
|
+
resolveStartPhase(labels: string[], command: 'process' | 'continue', workflowName?: string): WorkflowPhase;
|
|
38
|
+
/**
|
|
39
|
+
* For 'process' command: find the starting phase from labels.
|
|
40
|
+
*
|
|
41
|
+
* Priority:
|
|
42
|
+
* 1. If a `phase:*` label exists, resume from that phase
|
|
43
|
+
* 2. If `completed:*` labels exist, start from next uncompleted phase
|
|
44
|
+
* (gate names like 'clarification' are normalized to phase names via GATE_MAPPING)
|
|
45
|
+
* 3. If no phase labels, start from 'specify'
|
|
46
|
+
*/
|
|
47
|
+
private resolveFromProcess;
|
|
48
|
+
/**
|
|
49
|
+
* For 'continue' command: find which gate was just satisfied and resume from the next phase.
|
|
50
|
+
*
|
|
51
|
+
* Does not depend on `waiting-for:*` labels (those are removed by the worker on resume).
|
|
52
|
+
* Matches `completed:*` labels against the effective gate mapping (workflow-specific first,
|
|
53
|
+
* then global GATE_MAPPING) and returns the most advanced gate's resumeFrom phase.
|
|
54
|
+
*/
|
|
55
|
+
private resolveFromContinue;
|
|
56
|
+
/**
|
|
57
|
+
* Build the effective gate mapping for a workflow.
|
|
58
|
+
* Workflow-specific mappings in WORKFLOW_GATE_MAPPING override entries in the global GATE_MAPPING.
|
|
59
|
+
*/
|
|
60
|
+
private getEffectiveGateMapping;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=phase-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phase-resolver.d.ts","sourceRoot":"","sources":["../../src/worker/phase-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAElF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,aAAa,CAAA;CAAE,CAQ5F,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,aAAa,CAAA;CAAE,CAAC,CAMrH,CAAC;AAEF;;GAEG;AACH,qBAAa,aAAa;IACxB;;;;;;;;OAQG;IACH,iBAAiB,CACf,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,EAAE,SAAS,GAAG,UAAU,EAC/B,YAAY,CAAC,EAAE,MAAM,GACpB,aAAa;IAOhB;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IA2C1B;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;IA8B3B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;CAYhC"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { PHASE_SEQUENCE, getPhaseSequence } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Unified mapping from gate names to their owning phase and the phase to resume from.
|
|
4
|
+
*
|
|
5
|
+
* - `phase`: the workflow phase this gate belongs to (used to normalize gate names in resolveFromProcess)
|
|
6
|
+
* - `resumeFrom`: the phase to start from when the gate is satisfied (used in resolveFromContinue)
|
|
7
|
+
*/
|
|
8
|
+
export const GATE_MAPPING = {
|
|
9
|
+
'clarification': { phase: 'clarify', resumeFrom: 'plan' },
|
|
10
|
+
'spec-review': { phase: 'specify', resumeFrom: 'clarify' },
|
|
11
|
+
'clarification-review': { phase: 'clarify', resumeFrom: 'plan' },
|
|
12
|
+
'plan-review': { phase: 'plan', resumeFrom: 'tasks' },
|
|
13
|
+
'tasks-review': { phase: 'tasks', resumeFrom: 'implement' },
|
|
14
|
+
'implementation-review': { phase: 'implement', resumeFrom: 'validate' },
|
|
15
|
+
'manual-validation': { phase: 'validate', resumeFrom: 'validate' },
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Workflow-specific gate mappings that override the global GATE_MAPPING.
|
|
19
|
+
*
|
|
20
|
+
* For epic workflows, certain gates have different resume behavior:
|
|
21
|
+
* - `tasks-review`: resumes to 'tasks' (triggers post-tasks/child creation, not implement)
|
|
22
|
+
* - `children-complete`: dedicated handling (routes to epic-complete command)
|
|
23
|
+
* - `epic-approval`: dedicated handling (routes to epic-close)
|
|
24
|
+
*/
|
|
25
|
+
export const WORKFLOW_GATE_MAPPING = {
|
|
26
|
+
'speckit-epic': {
|
|
27
|
+
'tasks-review': { phase: 'tasks', resumeFrom: 'tasks' },
|
|
28
|
+
'children-complete': { phase: 'tasks', resumeFrom: 'tasks' },
|
|
29
|
+
'epic-approval': { phase: 'tasks', resumeFrom: 'tasks' },
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the starting phase based on issue labels and command type.
|
|
34
|
+
*/
|
|
35
|
+
export class PhaseResolver {
|
|
36
|
+
/**
|
|
37
|
+
* Determine the starting phase for a queue item.
|
|
38
|
+
*
|
|
39
|
+
* - 'process' command: inspects completed/phase labels to find the next uncompleted phase.
|
|
40
|
+
* - 'continue' command: matches completed gate labels via GATE_MAPPING to determine resume phase.
|
|
41
|
+
*
|
|
42
|
+
* @param workflowName - Optional workflow name for workflow-specific gate resolution.
|
|
43
|
+
* When provided, uses the workflow's phase sequence and gate mappings.
|
|
44
|
+
*/
|
|
45
|
+
resolveStartPhase(labels, command, workflowName) {
|
|
46
|
+
if (command === 'continue') {
|
|
47
|
+
return this.resolveFromContinue(labels, workflowName);
|
|
48
|
+
}
|
|
49
|
+
return this.resolveFromProcess(labels, workflowName);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* For 'process' command: find the starting phase from labels.
|
|
53
|
+
*
|
|
54
|
+
* Priority:
|
|
55
|
+
* 1. If a `phase:*` label exists, resume from that phase
|
|
56
|
+
* 2. If `completed:*` labels exist, start from next uncompleted phase
|
|
57
|
+
* (gate names like 'clarification' are normalized to phase names via GATE_MAPPING)
|
|
58
|
+
* 3. If no phase labels, start from 'specify'
|
|
59
|
+
*/
|
|
60
|
+
resolveFromProcess(labels, workflowName) {
|
|
61
|
+
const sequence = workflowName ? getPhaseSequence(workflowName) : PHASE_SEQUENCE;
|
|
62
|
+
const effectiveGateMapping = this.getEffectiveGateMapping(workflowName);
|
|
63
|
+
// Check for an active phase label
|
|
64
|
+
for (const label of labels) {
|
|
65
|
+
if (label.startsWith('phase:')) {
|
|
66
|
+
const phase = label.slice('phase:'.length);
|
|
67
|
+
if (sequence.includes(phase)) {
|
|
68
|
+
return phase;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Find the last completed phase and return the next one.
|
|
73
|
+
// Normalize gate names (e.g., 'clarification') to phase names (e.g., 'clarify')
|
|
74
|
+
// so phase sequence iteration matches correctly.
|
|
75
|
+
const completedPhases = new Set();
|
|
76
|
+
for (const label of labels) {
|
|
77
|
+
if (label.startsWith('completed:')) {
|
|
78
|
+
const name = label.slice('completed:'.length);
|
|
79
|
+
completedPhases.add(name);
|
|
80
|
+
const gateEntry = effectiveGateMapping[name];
|
|
81
|
+
if (gateEntry) {
|
|
82
|
+
completedPhases.add(gateEntry.phase);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (completedPhases.size > 0) {
|
|
87
|
+
for (const phase of sequence) {
|
|
88
|
+
if (!completedPhases.has(phase)) {
|
|
89
|
+
return phase;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// All phases completed — return the last phase in the sequence as the terminal phase
|
|
93
|
+
return sequence[sequence.length - 1];
|
|
94
|
+
}
|
|
95
|
+
// No phase labels at all — start from beginning
|
|
96
|
+
return 'specify';
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* For 'continue' command: find which gate was just satisfied and resume from the next phase.
|
|
100
|
+
*
|
|
101
|
+
* Does not depend on `waiting-for:*` labels (those are removed by the worker on resume).
|
|
102
|
+
* Matches `completed:*` labels against the effective gate mapping (workflow-specific first,
|
|
103
|
+
* then global GATE_MAPPING) and returns the most advanced gate's resumeFrom phase.
|
|
104
|
+
*/
|
|
105
|
+
resolveFromContinue(labels, workflowName) {
|
|
106
|
+
const sequence = workflowName ? getPhaseSequence(workflowName) : PHASE_SEQUENCE;
|
|
107
|
+
const effectiveGateMapping = this.getEffectiveGateMapping(workflowName);
|
|
108
|
+
const completedGates = new Set();
|
|
109
|
+
for (const label of labels) {
|
|
110
|
+
if (label.startsWith('completed:')) {
|
|
111
|
+
const name = label.slice('completed:'.length);
|
|
112
|
+
if (effectiveGateMapping[name]) {
|
|
113
|
+
completedGates.add(name);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Iterate phases latest-to-earliest — most advanced gate wins
|
|
118
|
+
for (let i = sequence.length - 1; i >= 0; i--) {
|
|
119
|
+
const phase = sequence[i];
|
|
120
|
+
for (const gateName of completedGates) {
|
|
121
|
+
const mapping = effectiveGateMapping[gateName];
|
|
122
|
+
if (mapping && mapping.phase === phase) {
|
|
123
|
+
return mapping.resumeFrom;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Fallback: use the process resolver
|
|
128
|
+
return this.resolveFromProcess(labels, workflowName);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Build the effective gate mapping for a workflow.
|
|
132
|
+
* Workflow-specific mappings in WORKFLOW_GATE_MAPPING override entries in the global GATE_MAPPING.
|
|
133
|
+
*/
|
|
134
|
+
getEffectiveGateMapping(workflowName) {
|
|
135
|
+
if (!workflowName || !WORKFLOW_GATE_MAPPING[workflowName]) {
|
|
136
|
+
return GATE_MAPPING;
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
...GATE_MAPPING,
|
|
140
|
+
...WORKFLOW_GATE_MAPPING[workflowName],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=phase-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phase-resolver.js","sourceRoot":"","sources":["../../src/worker/phase-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { QueueItem } from '../types/index.js';
|
|
2
|
+
import type { Logger, ProcessFactory } from './types.js';
|
|
3
|
+
import type { WorkerConfig } from './config.js';
|
|
4
|
+
import type { SSEEventEmitter } from './output-capture.js';
|
|
5
|
+
/**
|
|
6
|
+
* Handles the `address-pr-feedback` command.
|
|
7
|
+
*
|
|
8
|
+
* Processing flow:
|
|
9
|
+
* 1. Extract PR number from queue item metadata
|
|
10
|
+
* 2. Fetch the PR to get the branch name
|
|
11
|
+
* 3. Switch to the PR branch (not default branch)
|
|
12
|
+
* 4. Fetch fresh unresolved review threads
|
|
13
|
+
* 5. Build a structured prompt with all unresolved comments
|
|
14
|
+
* 6. Spawn Claude CLI to address the feedback
|
|
15
|
+
* 7. Stage, commit, and push changes to the PR branch
|
|
16
|
+
* 8. Reply to each review thread (never resolve)
|
|
17
|
+
* 9. Remove the `waiting-for:address-pr-feedback` label
|
|
18
|
+
*
|
|
19
|
+
* Error handling strategy (T019):
|
|
20
|
+
*
|
|
21
|
+
* **FR-013: Timeout handling**
|
|
22
|
+
* - If CLI times out: push any partial changes that were made
|
|
23
|
+
* - Keep `waiting-for:address-pr-feedback` label (don't remove)
|
|
24
|
+
* - Label retention ensures the task will be retried on next detection cycle
|
|
25
|
+
* - Log timeout warning with structured context
|
|
26
|
+
*
|
|
27
|
+
* **FR-007: Reply failure handling**
|
|
28
|
+
* - If posting replies fails for some threads: still remove label
|
|
29
|
+
* - Log warnings for each failed reply
|
|
30
|
+
* - Partial reply success is acceptable (code changes were pushed successfully)
|
|
31
|
+
* - Handler does not throw on reply failures
|
|
32
|
+
*
|
|
33
|
+
* **SC-006: Thread resolution prevention**
|
|
34
|
+
* - Only use `replyToPRComment()` API — never call any thread-resolve API
|
|
35
|
+
* - Human reviewer will resolve threads after verifying changes
|
|
36
|
+
* - Comments in code explicitly reference SC-006 for clarity
|
|
37
|
+
*
|
|
38
|
+
* **Structured logging**
|
|
39
|
+
* - All operations logged with structured context (prNumber, issueNumber, owner, repo)
|
|
40
|
+
* - Error logs include full error messages and relevant context
|
|
41
|
+
* - Success/failure states clearly logged for observability
|
|
42
|
+
* - All FR/SC references included in log messages for traceability
|
|
43
|
+
*
|
|
44
|
+
* **Critical operation failures**
|
|
45
|
+
* - PR fetch failure: throw (cannot proceed without PR details)
|
|
46
|
+
* - Branch switch failure: throw (wrong branch would cause issues)
|
|
47
|
+
* - Comment fetch failure: throw (cannot address unknown feedback)
|
|
48
|
+
* - Push failure: log error but don't throw (allows retry via label)
|
|
49
|
+
*
|
|
50
|
+
* **Non-critical operation failures**
|
|
51
|
+
* - No unresolved threads: remove label, early return (success case)
|
|
52
|
+
* - Reply posting: log warning, continue (FR-007)
|
|
53
|
+
* - Label removal: log warning, continue (non-fatal)
|
|
54
|
+
*/
|
|
55
|
+
export declare class PrFeedbackHandler {
|
|
56
|
+
private readonly config;
|
|
57
|
+
private readonly logger;
|
|
58
|
+
private readonly processFactory;
|
|
59
|
+
private readonly sseEmitter?;
|
|
60
|
+
private readonly repoCheckout;
|
|
61
|
+
constructor(config: WorkerConfig, logger: Logger, processFactory: ProcessFactory, sseEmitter?: SSEEventEmitter | undefined);
|
|
62
|
+
/**
|
|
63
|
+
* Process a PR feedback addressing task.
|
|
64
|
+
*
|
|
65
|
+
* @param item - Queue item with `command: 'address-pr-feedback'`
|
|
66
|
+
* @param checkoutPath - Path to the already-checked-out repository
|
|
67
|
+
*/
|
|
68
|
+
handle(item: QueueItem, checkoutPath: string): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Build a structured prompt containing all unresolved review comments.
|
|
71
|
+
*
|
|
72
|
+
* The prompt instructs Claude to:
|
|
73
|
+
* - Read each review comment
|
|
74
|
+
* - Make the necessary code changes
|
|
75
|
+
* - Commit the changes
|
|
76
|
+
* - NOT resolve any threads (human reviewer will resolve)
|
|
77
|
+
*/
|
|
78
|
+
private buildFeedbackPrompt;
|
|
79
|
+
/**
|
|
80
|
+
* Spawn Claude CLI to address PR feedback.
|
|
81
|
+
*
|
|
82
|
+
* Returns true if the CLI completed successfully, false on timeout or failure.
|
|
83
|
+
* FR-013: On timeout, partial changes are pushed and label is kept for retry.
|
|
84
|
+
*/
|
|
85
|
+
private spawnClaudeForFeedback;
|
|
86
|
+
/**
|
|
87
|
+
* Stage all changes, commit, and push to the PR branch.
|
|
88
|
+
*
|
|
89
|
+
* Returns true if there were changes to commit, false otherwise.
|
|
90
|
+
*/
|
|
91
|
+
private commitAndPushChanges;
|
|
92
|
+
/**
|
|
93
|
+
* Post a reply to each unresolved review thread.
|
|
94
|
+
*
|
|
95
|
+
* SC-006: Never resolves threads — that's left to the human reviewer.
|
|
96
|
+
* FR-007: Partial failure is acceptable: if some replies fail, log warnings but continue.
|
|
97
|
+
* The handler will still remove the label even if some replies fail.
|
|
98
|
+
*/
|
|
99
|
+
private replyToThreads;
|
|
100
|
+
/**
|
|
101
|
+
* Remove the `waiting-for:address-pr-feedback` label from the linked issue.
|
|
102
|
+
*/
|
|
103
|
+
private removeFeedbackLabel;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=pr-feedback-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-feedback-handler.d.ts","sourceRoot":"","sources":["../../src/worker/pr-feedback-handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAsB,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAI3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,qBAAa,iBAAiB;IAI1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAN9B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;gBAGzB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,cAAc,EAC9B,UAAU,CAAC,EAAE,eAAe,YAAA;IAK/C;;;;;OAKG;IACG,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmKlE;;;;;;;;OAQG;IACH,OAAO,CAAC,mBAAmB;IA6B3B;;;;;OAKG;YACW,sBAAsB;IA0HpC;;;;OAIG;YACW,oBAAoB;IA2ElC;;;;;;OAMG;YACW,cAAc;IAsD5B;;OAEG;YACW,mBAAmB;CAgBlC"}
|