mstro-app 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +191 -21
- package/PRIVACY.md +286 -62
- package/README.md +81 -58
- package/bin/commands/status.js +1 -1
- package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
- package/dist/server/cli/headless/claude-invoker.js +22 -12
- package/dist/server/cli/headless/claude-invoker.js.map +1 -1
- package/dist/server/cli/headless/headless-logger.d.ts +10 -0
- package/dist/server/cli/headless/headless-logger.d.ts.map +1 -0
- package/dist/server/cli/headless/headless-logger.js +66 -0
- package/dist/server/cli/headless/headless-logger.js.map +1 -0
- package/dist/server/cli/headless/mcp-config.d.ts.map +1 -1
- package/dist/server/cli/headless/mcp-config.js +6 -5
- package/dist/server/cli/headless/mcp-config.js.map +1 -1
- package/dist/server/cli/headless/runner.d.ts.map +1 -1
- package/dist/server/cli/headless/runner.js +4 -0
- package/dist/server/cli/headless/runner.js.map +1 -1
- package/dist/server/cli/headless/stall-assessor.d.ts +21 -0
- package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
- package/dist/server/cli/headless/stall-assessor.js +100 -24
- package/dist/server/cli/headless/stall-assessor.js.map +1 -1
- package/dist/server/cli/headless/tool-watchdog.d.ts +0 -12
- package/dist/server/cli/headless/tool-watchdog.d.ts.map +1 -1
- package/dist/server/cli/headless/tool-watchdog.js +22 -9
- package/dist/server/cli/headless/tool-watchdog.js.map +1 -1
- package/dist/server/cli/headless/types.d.ts +8 -1
- package/dist/server/cli/headless/types.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.d.ts +16 -0
- package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.js +94 -11
- package/dist/server/cli/improvisation-session-manager.js.map +1 -1
- package/dist/server/mcp/bouncer-cli.d.ts +3 -0
- package/dist/server/mcp/bouncer-cli.d.ts.map +1 -0
- package/dist/server/mcp/bouncer-cli.js +54 -0
- package/dist/server/mcp/bouncer-cli.js.map +1 -0
- package/dist/server/services/plan/composer.d.ts +4 -0
- package/dist/server/services/plan/composer.d.ts.map +1 -0
- package/dist/server/services/plan/composer.js +181 -0
- package/dist/server/services/plan/composer.js.map +1 -0
- package/dist/server/services/plan/dependency-resolver.d.ts +28 -0
- package/dist/server/services/plan/dependency-resolver.d.ts.map +1 -0
- package/dist/server/services/plan/dependency-resolver.js +154 -0
- package/dist/server/services/plan/dependency-resolver.js.map +1 -0
- package/dist/server/services/plan/executor.d.ts +110 -0
- package/dist/server/services/plan/executor.d.ts.map +1 -0
- package/dist/server/services/plan/executor.js +641 -0
- package/dist/server/services/plan/executor.js.map +1 -0
- package/dist/server/services/plan/parser.d.ts +11 -0
- package/dist/server/services/plan/parser.d.ts.map +1 -0
- package/dist/server/services/plan/parser.js +445 -0
- package/dist/server/services/plan/parser.js.map +1 -0
- package/dist/server/services/plan/state-reconciler.d.ts +2 -0
- package/dist/server/services/plan/state-reconciler.d.ts.map +1 -0
- package/dist/server/services/plan/state-reconciler.js +145 -0
- package/dist/server/services/plan/state-reconciler.js.map +1 -0
- package/dist/server/services/plan/types.d.ts +121 -0
- package/dist/server/services/plan/types.d.ts.map +1 -0
- package/dist/server/services/plan/types.js +4 -0
- package/dist/server/services/plan/types.js.map +1 -0
- package/dist/server/services/plan/watcher.d.ts +14 -0
- package/dist/server/services/plan/watcher.d.ts.map +1 -0
- package/dist/server/services/plan/watcher.js +69 -0
- package/dist/server/services/plan/watcher.js.map +1 -0
- package/dist/server/services/websocket/file-explorer-handlers.js +20 -0
- package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -1
- package/dist/server/services/websocket/handler.d.ts.map +1 -1
- package/dist/server/services/websocket/handler.js +21 -0
- package/dist/server/services/websocket/handler.js.map +1 -1
- package/dist/server/services/websocket/plan-handlers.d.ts +6 -0
- package/dist/server/services/websocket/plan-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/plan-handlers.js +494 -0
- package/dist/server/services/websocket/plan-handlers.js.map +1 -0
- package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-handlers.js +384 -12
- package/dist/server/services/websocket/quality-handlers.js.map +1 -1
- package/dist/server/services/websocket/quality-persistence.d.ts +45 -0
- package/dist/server/services/websocket/quality-persistence.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-persistence.js +187 -0
- package/dist/server/services/websocket/quality-persistence.js.map +1 -0
- package/dist/server/services/websocket/quality-service.d.ts +12 -2
- package/dist/server/services/websocket/quality-service.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-service.js +162 -18
- package/dist/server/services/websocket/quality-service.js.map +1 -1
- package/dist/server/services/websocket/types.d.ts +2 -2
- package/dist/server/services/websocket/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/server/cli/headless/claude-invoker.ts +25 -12
- package/server/cli/headless/headless-logger.ts +78 -0
- package/server/cli/headless/mcp-config.ts +6 -5
- package/server/cli/headless/runner.ts +4 -0
- package/server/cli/headless/stall-assessor.ts +131 -24
- package/server/cli/headless/tool-watchdog.ts +10 -9
- package/server/cli/headless/types.ts +10 -1
- package/server/cli/improvisation-session-manager.ts +118 -11
- package/server/mcp/bouncer-cli.ts +73 -0
- package/server/services/plan/composer.ts +199 -0
- package/server/services/plan/dependency-resolver.ts +182 -0
- package/server/services/plan/executor.ts +700 -0
- package/server/services/plan/parser.ts +491 -0
- package/server/services/plan/state-reconciler.ts +174 -0
- package/server/services/plan/types.ts +166 -0
- package/server/services/plan/watcher.ts +73 -0
- package/server/services/websocket/file-explorer-handlers.ts +20 -0
- package/server/services/websocket/handler.ts +21 -0
- package/server/services/websocket/plan-handlers.ts +592 -0
- package/server/services/websocket/quality-handlers.ts +450 -12
- package/server/services/websocket/quality-persistence.ts +250 -0
- package/server/services/websocket/quality-service.ts +183 -18
- package/server/services/websocket/types.ts +48 -2
|
@@ -0,0 +1,641 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file for details.
|
|
3
|
+
/**
|
|
4
|
+
* Plan Executor — Wave-based execution with Claude Code Agent Teams.
|
|
5
|
+
*
|
|
6
|
+
* Reads the dependency DAG from .pm/, picks ALL unblocked issues per wave,
|
|
7
|
+
* spawns a coordinator Claude session that uses Agent Teams to execute them
|
|
8
|
+
* in parallel, then reconciles state and repeats for newly-unblocked issues.
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from 'node:events';
|
|
11
|
+
import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
12
|
+
import { join, resolve } from 'node:path';
|
|
13
|
+
import { runWithFileLogger } from '../../cli/headless/headless-logger.js';
|
|
14
|
+
import { HeadlessRunner } from '../../cli/headless/index.js';
|
|
15
|
+
import { generateMcpConfig } from '../../cli/headless/mcp-config.js';
|
|
16
|
+
import { resolveReadyToWork } from './dependency-resolver.js';
|
|
17
|
+
import { parsePlanDirectory, resolvePmDir } from './parser.js';
|
|
18
|
+
import { reconcileState } from './state-reconciler.js';
|
|
19
|
+
export class PlanExecutor extends EventEmitter {
|
|
20
|
+
status = 'idle';
|
|
21
|
+
workingDir;
|
|
22
|
+
shouldStop = false;
|
|
23
|
+
shouldPause = false;
|
|
24
|
+
epicScope = null;
|
|
25
|
+
metrics = {
|
|
26
|
+
issuesCompleted: 0,
|
|
27
|
+
issuesAttempted: 0,
|
|
28
|
+
totalDuration: 0,
|
|
29
|
+
currentIssueId: null,
|
|
30
|
+
currentWaveIds: [],
|
|
31
|
+
};
|
|
32
|
+
constructor(workingDir) {
|
|
33
|
+
super();
|
|
34
|
+
this.workingDir = workingDir;
|
|
35
|
+
}
|
|
36
|
+
getStatus() {
|
|
37
|
+
return this.status;
|
|
38
|
+
}
|
|
39
|
+
getMetrics() {
|
|
40
|
+
return { ...this.metrics };
|
|
41
|
+
}
|
|
42
|
+
async startEpic(epicPath) {
|
|
43
|
+
this.epicScope = epicPath;
|
|
44
|
+
return this.start();
|
|
45
|
+
}
|
|
46
|
+
async start() {
|
|
47
|
+
if (this.status === 'executing' || this.status === 'starting')
|
|
48
|
+
return;
|
|
49
|
+
this.shouldStop = false;
|
|
50
|
+
this.shouldPause = false;
|
|
51
|
+
this.status = 'starting';
|
|
52
|
+
this.emit('statusChanged', this.status);
|
|
53
|
+
const startTime = Date.now();
|
|
54
|
+
try {
|
|
55
|
+
this.status = 'executing';
|
|
56
|
+
this.emit('statusChanged', this.status);
|
|
57
|
+
while (!this.shouldStop && !this.shouldPause) {
|
|
58
|
+
const readyIssues = this.pickReadyIssues();
|
|
59
|
+
if (readyIssues.length === 0)
|
|
60
|
+
break;
|
|
61
|
+
// Always use wave execution with Agent Teams — even for single issues.
|
|
62
|
+
// Each teammate runs as a separate process with its own context window,
|
|
63
|
+
// bouncer coverage via .mcp.json + PreToolUse hook, and disk persistence.
|
|
64
|
+
await this.executeWave(readyIssues);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
this.status = 'error';
|
|
69
|
+
this.emit('error', error instanceof Error ? error.message : String(error));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
this.metrics.totalDuration = Date.now() - startTime;
|
|
73
|
+
if (this.shouldPause) {
|
|
74
|
+
this.status = 'paused';
|
|
75
|
+
}
|
|
76
|
+
else if (this.shouldStop) {
|
|
77
|
+
this.status = 'idle';
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.status = 'complete';
|
|
81
|
+
}
|
|
82
|
+
this.emit('statusChanged', this.status);
|
|
83
|
+
}
|
|
84
|
+
pause() {
|
|
85
|
+
this.shouldPause = true;
|
|
86
|
+
}
|
|
87
|
+
stop() {
|
|
88
|
+
this.shouldStop = true;
|
|
89
|
+
}
|
|
90
|
+
resume() {
|
|
91
|
+
if (this.status !== 'paused')
|
|
92
|
+
return Promise.resolve();
|
|
93
|
+
this.shouldPause = false;
|
|
94
|
+
return this.start();
|
|
95
|
+
}
|
|
96
|
+
// ── Wave execution (Agent Teams) ──────────────────────────────
|
|
97
|
+
async executeWave(issues) {
|
|
98
|
+
const waveStart = Date.now();
|
|
99
|
+
const waveIds = issues.map(i => i.id);
|
|
100
|
+
this.metrics.currentWaveIds = waveIds;
|
|
101
|
+
this.metrics.issuesAttempted += issues.length;
|
|
102
|
+
this.emit('waveStarted', { issueIds: waveIds });
|
|
103
|
+
// Ensure .pm/out/ exists for execution output
|
|
104
|
+
const pmDir = resolvePmDir(this.workingDir);
|
|
105
|
+
if (pmDir) {
|
|
106
|
+
const outDir = join(pmDir, 'out');
|
|
107
|
+
if (!existsSync(outDir))
|
|
108
|
+
mkdirSync(outDir, { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
// Pre-approve tools so teammates don't hit interactive permission prompts
|
|
111
|
+
this.installTeammatePermissions();
|
|
112
|
+
// Install bouncer .mcp.json so Agent Teams teammates discover it
|
|
113
|
+
this.installBouncerForSubagents();
|
|
114
|
+
// Mark all wave issues as in_progress
|
|
115
|
+
for (const issue of issues) {
|
|
116
|
+
this.updateIssueFrontMatter(issue.path, 'in_progress');
|
|
117
|
+
}
|
|
118
|
+
const prompt = this.buildCoordinatorPrompt(issues);
|
|
119
|
+
try {
|
|
120
|
+
const runner = new HeadlessRunner({
|
|
121
|
+
workingDir: this.workingDir,
|
|
122
|
+
directPrompt: prompt,
|
|
123
|
+
stallKillMs: 3_600_000, // 60 min — waves run longer
|
|
124
|
+
stallHardCapMs: 7_200_000, // 2 hr hard cap
|
|
125
|
+
extraEnv: {
|
|
126
|
+
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: '1',
|
|
127
|
+
},
|
|
128
|
+
outputCallback: (text) => {
|
|
129
|
+
this.emit('output', { issueId: `wave[${waveIds.join(',')}]`, text });
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
const result = await runWithFileLogger('pm-execute-wave', () => runner.run());
|
|
133
|
+
if (!result.completed || result.error) {
|
|
134
|
+
this.emit('waveError', {
|
|
135
|
+
issueIds: waveIds,
|
|
136
|
+
error: result.error || 'Wave did not complete successfully',
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// Check which issues the agents actually completed by reading disk
|
|
140
|
+
this.reconcileWaveResults(issues);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
this.emit('waveError', {
|
|
144
|
+
issueIds: waveIds,
|
|
145
|
+
error: error instanceof Error ? error.message : String(error),
|
|
146
|
+
});
|
|
147
|
+
this.revertIncompleteIssues(issues);
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
// Clean up temporary configs — must run even if wave throws
|
|
151
|
+
this.uninstallBouncerForSubagents();
|
|
152
|
+
this.uninstallTeammatePermissions();
|
|
153
|
+
}
|
|
154
|
+
// Reconcile STATE.md and sprint statuses after wave
|
|
155
|
+
reconcileState(this.workingDir);
|
|
156
|
+
this.emit('stateUpdated');
|
|
157
|
+
// Copy confirmed-done outputs to user-specified output_file paths
|
|
158
|
+
this.publishOutputs(issues);
|
|
159
|
+
// Append progress log entry
|
|
160
|
+
this.appendProgressEntry(issues, waveStart);
|
|
161
|
+
this.metrics.currentWaveIds = [];
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* After a wave, check each issue's status on disk.
|
|
165
|
+
* `status: done` in issue front matter is the single completion signal.
|
|
166
|
+
* Output doc existence is NOT used as a proxy — code-focused issues
|
|
167
|
+
* (bug fixes, refactors) don't produce docs but are still valid completions.
|
|
168
|
+
*/
|
|
169
|
+
reconcileWaveResults(issues) {
|
|
170
|
+
const pmDir = resolvePmDir(this.workingDir);
|
|
171
|
+
if (!pmDir)
|
|
172
|
+
return;
|
|
173
|
+
for (const issue of issues) {
|
|
174
|
+
const fullPath = join(pmDir, issue.path);
|
|
175
|
+
try {
|
|
176
|
+
const content = readFileSync(fullPath, 'utf-8');
|
|
177
|
+
const statusMatch = content.match(/^status:\s*(\S+)/m);
|
|
178
|
+
const currentStatus = statusMatch?.[1] ?? 'unknown';
|
|
179
|
+
if (currentStatus === 'done') {
|
|
180
|
+
this.metrics.issuesCompleted++;
|
|
181
|
+
this.emit('issueCompleted', issue);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
// Not done — revert to prior status
|
|
185
|
+
this.updateIssueFrontMatter(issue.path, issue.status);
|
|
186
|
+
this.emit('issueError', {
|
|
187
|
+
issueId: issue.id,
|
|
188
|
+
error: 'Issue did not complete during wave execution',
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
this.emit('issueError', { issueId: issue.id, error: 'Could not read issue file after wave' });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// ── Issue picking ─────────────────────────────────────────────
|
|
198
|
+
pickReadyIssues() {
|
|
199
|
+
const fullState = parsePlanDirectory(this.workingDir);
|
|
200
|
+
if (!fullState) {
|
|
201
|
+
this.emit('error', 'No .pm/ directory found');
|
|
202
|
+
return [];
|
|
203
|
+
}
|
|
204
|
+
if (fullState.state.paused) {
|
|
205
|
+
this.emit('error', 'Project is paused');
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
const readyIssues = resolveReadyToWork(fullState.issues, this.epicScope ?? undefined);
|
|
209
|
+
if (readyIssues.length === 0) {
|
|
210
|
+
this.emit('complete', this.epicScope ? 'All epic issues are done or blocked' : 'All work is done or blocked');
|
|
211
|
+
}
|
|
212
|
+
return readyIssues;
|
|
213
|
+
}
|
|
214
|
+
// ── Prompt building ───────────────────────────────────────────
|
|
215
|
+
/**
|
|
216
|
+
* Build the team lead prompt for a wave of issues.
|
|
217
|
+
* Uses Agent Teams for true parallel execution as separate processes —
|
|
218
|
+
* each teammate gets its own context window and sends idle notifications
|
|
219
|
+
* when done. The team is created implicitly by the first Agent(team_name=...) call.
|
|
220
|
+
*/
|
|
221
|
+
buildCoordinatorPrompt(issues) {
|
|
222
|
+
const pmDir = resolvePmDir(this.workingDir);
|
|
223
|
+
const outDir = pmDir ? join(pmDir, 'out') : join(this.workingDir, '.pm', 'out');
|
|
224
|
+
// Collect existing output docs that issues may need as input
|
|
225
|
+
const existingDocs = this.listExistingDocs();
|
|
226
|
+
const issueBlocks = issues.map(issue => {
|
|
227
|
+
const criteria = issue.acceptanceCriteria
|
|
228
|
+
.map(c => `- [${c.checked ? 'x' : ' '}] ${c.text}`)
|
|
229
|
+
.join('\n');
|
|
230
|
+
const files = issue.filesToModify.length > 0
|
|
231
|
+
? `\nFiles to modify:\n${issue.filesToModify.map(f => `- ${f}`).join('\n')}`
|
|
232
|
+
: '';
|
|
233
|
+
// Find predecessor output docs this issue should read
|
|
234
|
+
const predecessorDocs = issue.blockedBy
|
|
235
|
+
.map(bp => {
|
|
236
|
+
const blockerId = bp.replace(/^backlog\//, '').replace(/\.md$/, '');
|
|
237
|
+
return existingDocs.find(d => d.toLowerCase().includes(blockerId.toLowerCase()));
|
|
238
|
+
})
|
|
239
|
+
.filter(Boolean);
|
|
240
|
+
const predecessorSection = predecessorDocs.length > 0
|
|
241
|
+
? `\nPredecessor outputs to read:\n${predecessorDocs.map(d => `- ${d}`).join('\n')}`
|
|
242
|
+
: '';
|
|
243
|
+
return `### ${issue.id}: ${issue.title}
|
|
244
|
+
|
|
245
|
+
**Type**: ${issue.type} | **Priority**: ${issue.priority} | **Estimate**: ${issue.estimate ?? 'unestimated'}
|
|
246
|
+
|
|
247
|
+
**Description**:
|
|
248
|
+
${issue.description}
|
|
249
|
+
|
|
250
|
+
**Acceptance Criteria**:
|
|
251
|
+
${criteria || 'No specific criteria defined.'}
|
|
252
|
+
|
|
253
|
+
**Technical Notes**:
|
|
254
|
+
${issue.technicalNotes || 'None'}
|
|
255
|
+
${files}${predecessorSection}
|
|
256
|
+
|
|
257
|
+
**Output file**: ${this.resolveOutputPath(issue)}`;
|
|
258
|
+
}).join('\n\n---\n\n');
|
|
259
|
+
const teamName = `pm-wave-${Date.now()}`;
|
|
260
|
+
const teammateSpawns = issues.map(issue => {
|
|
261
|
+
const predecessorDocs = issue.blockedBy
|
|
262
|
+
.map(bp => {
|
|
263
|
+
const blockerId = bp.replace(/^backlog\//, '').replace(/\.md$/, '');
|
|
264
|
+
return existingDocs.find(d => d.toLowerCase().includes(blockerId.toLowerCase()));
|
|
265
|
+
})
|
|
266
|
+
.filter(Boolean);
|
|
267
|
+
const predInstr = predecessorDocs.length > 0
|
|
268
|
+
? `Read these predecessor output docs before starting: ${predecessorDocs.join(', ')}. `
|
|
269
|
+
: '';
|
|
270
|
+
const outputFile = this.resolveOutputPath(issue);
|
|
271
|
+
return `Spawn teammate **${issue.id.toLowerCase()}** using the **Agent** tool with \`team_name: "${teamName}"\` and \`name: "${issue.id.toLowerCase()}"\`:
|
|
272
|
+
> ${predInstr}Work on issue ${issue.id}: ${issue.title}.
|
|
273
|
+
> Read the full spec at ${pmDir ? join(pmDir, issue.path) : issue.path}.
|
|
274
|
+
> Execute all acceptance criteria.
|
|
275
|
+
> CRITICAL: Write ALL output/results to ${outputFile} — this is the handoff artifact for downstream issues.
|
|
276
|
+
> After writing output, update the issue front matter: change \`status: in_progress\` to \`status: done\`.
|
|
277
|
+
> Do not modify STATE.md. Do not work on anything outside this issue's scope.`;
|
|
278
|
+
}).join('\n\n');
|
|
279
|
+
return `You are the team lead coordinating ${issues.length} issue${issues.length > 1 ? 's' : ''} using Agent Teams.
|
|
280
|
+
|
|
281
|
+
## Project Directory
|
|
282
|
+
Working directory: ${this.workingDir}
|
|
283
|
+
Plan directory: ${pmDir || '.pm/'}
|
|
284
|
+
|
|
285
|
+
## Issues to Execute
|
|
286
|
+
|
|
287
|
+
${issueBlocks}
|
|
288
|
+
|
|
289
|
+
## Execution Protocol — Agent Teams
|
|
290
|
+
|
|
291
|
+
### Step 1: Spawn teammates
|
|
292
|
+
|
|
293
|
+
Spawn all ${issues.length} teammates in parallel by sending a single message with ${issues.length} **Agent** tool calls. Each call must include \`team_name: "${teamName}"\` and a unique \`name\`. The team is created automatically when you spawn the first teammate with \`team_name\` — no separate setup step is needed.
|
|
294
|
+
|
|
295
|
+
${teammateSpawns}
|
|
296
|
+
|
|
297
|
+
### Step 2: Wait for ALL teammates to complete
|
|
298
|
+
|
|
299
|
+
CRITICAL: After spawning, you MUST remain active and wait for every single teammate to finish. Each teammate automatically sends you an **idle notification** when they complete their work.
|
|
300
|
+
|
|
301
|
+
Track completion against this checklist — ALL must report idle before you proceed:
|
|
302
|
+
${issues.map(i => `- [ ] ${i.id.toLowerCase()}`).join('\n')}
|
|
303
|
+
|
|
304
|
+
While waiting:
|
|
305
|
+
- As each teammate goes idle, verify their output file exists on disk using the **Read** tool
|
|
306
|
+
- If a teammate has not gone idle after 15 minutes, use **SendMessage** to check on them
|
|
307
|
+
- Do NOT proceed to Step 3 until you have received idle notifications from ALL ${issues.length} teammates
|
|
308
|
+
|
|
309
|
+
WARNING: The #1 failure mode is exiting before all teammates finish. If you exit early, all teammate processes are killed and their work is permanently lost. When in doubt, keep waiting. Err on the side of waiting too long rather than exiting too early.
|
|
310
|
+
|
|
311
|
+
### Step 3: Verify outputs
|
|
312
|
+
|
|
313
|
+
Once every teammate has gone idle:
|
|
314
|
+
1. Verify each output file exists in ${outDir}/ using **Read** or **Glob**
|
|
315
|
+
2. Verify each issue's front matter status is \`done\`
|
|
316
|
+
3. If any teammate failed to write output or update status, do it yourself
|
|
317
|
+
4. Do NOT modify STATE.md — the orchestrator handles that
|
|
318
|
+
|
|
319
|
+
## Critical Rules
|
|
320
|
+
|
|
321
|
+
- The team is created implicitly when you spawn the first teammate with \`team_name\`, and cleaned up automatically when all teammates exit. Your only job is to spawn teammates, wait, and verify.
|
|
322
|
+
- You MUST wait for idle notifications from ALL ${issues.length} teammates before exiting. Exiting early kills all teammate processes and permanently loses their work.
|
|
323
|
+
- Each teammate MUST write its output to disk — research only in conversation is LOST.
|
|
324
|
+
- Each teammate MUST update the issue front matter status to \`done\`.
|
|
325
|
+
- One issue per teammate — no cross-issue work.`;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Revert issues that stayed in_progress after a failed wave.
|
|
329
|
+
*/
|
|
330
|
+
revertIncompleteIssues(issues) {
|
|
331
|
+
const pmDir = resolvePmDir(this.workingDir);
|
|
332
|
+
if (!pmDir)
|
|
333
|
+
return;
|
|
334
|
+
for (const issue of issues) {
|
|
335
|
+
const fullPath = join(pmDir, issue.path);
|
|
336
|
+
try {
|
|
337
|
+
const content = readFileSync(fullPath, 'utf-8');
|
|
338
|
+
if (content.match(/^status:\s*in_progress$/m)) {
|
|
339
|
+
this.updateIssueFrontMatter(issue.path, issue.status);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
catch { /* file may be gone */ }
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// ── Teammate permissions ─────────────────────────────────────
|
|
346
|
+
/** Saved content of any pre-existing .claude/settings.json so we can restore it */
|
|
347
|
+
savedClaudeSettings = null;
|
|
348
|
+
claudeSettingsInstalled = false;
|
|
349
|
+
/**
|
|
350
|
+
* Pre-approve tools in project .claude/settings.json so Agent Teams
|
|
351
|
+
* teammates can work without interactive permission prompts.
|
|
352
|
+
* Teammates are separate processes that inherit the lead's permission
|
|
353
|
+
* settings. Without pre-approved tools, they hit interactive prompts
|
|
354
|
+
* that can't be answered in headless/background mode (known bug #25254).
|
|
355
|
+
*/
|
|
356
|
+
installTeammatePermissions() {
|
|
357
|
+
const claudeDir = join(this.workingDir, '.claude');
|
|
358
|
+
const settingsPath = join(claudeDir, 'settings.json');
|
|
359
|
+
if (!existsSync(claudeDir)) {
|
|
360
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
361
|
+
}
|
|
362
|
+
// Tools that teammates may need during execution
|
|
363
|
+
const requiredPermissions = [
|
|
364
|
+
'Bash',
|
|
365
|
+
'Read',
|
|
366
|
+
'Edit',
|
|
367
|
+
'Write',
|
|
368
|
+
'Glob',
|
|
369
|
+
'Grep',
|
|
370
|
+
'WebFetch',
|
|
371
|
+
'WebSearch',
|
|
372
|
+
'Agent',
|
|
373
|
+
];
|
|
374
|
+
try {
|
|
375
|
+
// Save existing settings
|
|
376
|
+
if (existsSync(settingsPath)) {
|
|
377
|
+
this.savedClaudeSettings = readFileSync(settingsPath, 'utf-8');
|
|
378
|
+
const existing = JSON.parse(this.savedClaudeSettings);
|
|
379
|
+
// Merge permissions into existing settings
|
|
380
|
+
if (!existing.permissions)
|
|
381
|
+
existing.permissions = {};
|
|
382
|
+
if (!existing.permissions.allow)
|
|
383
|
+
existing.permissions.allow = [];
|
|
384
|
+
for (const tool of requiredPermissions) {
|
|
385
|
+
if (!existing.permissions.allow.includes(tool)) {
|
|
386
|
+
existing.permissions.allow.push(tool);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
writeFileSync(settingsPath, JSON.stringify(existing, null, 2));
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
this.savedClaudeSettings = null;
|
|
393
|
+
writeFileSync(settingsPath, JSON.stringify({
|
|
394
|
+
permissions: { allow: requiredPermissions },
|
|
395
|
+
}, null, 2));
|
|
396
|
+
}
|
|
397
|
+
this.claudeSettingsInstalled = true;
|
|
398
|
+
}
|
|
399
|
+
catch {
|
|
400
|
+
// Non-fatal — teammates may hit permission prompts
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Restore original .claude/settings.json after wave execution.
|
|
405
|
+
*/
|
|
406
|
+
uninstallTeammatePermissions() {
|
|
407
|
+
if (!this.claudeSettingsInstalled)
|
|
408
|
+
return;
|
|
409
|
+
const settingsPath = join(this.workingDir, '.claude', 'settings.json');
|
|
410
|
+
try {
|
|
411
|
+
if (this.savedClaudeSettings !== null) {
|
|
412
|
+
writeFileSync(settingsPath, this.savedClaudeSettings);
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
unlinkSync(settingsPath);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
catch {
|
|
419
|
+
// Best effort
|
|
420
|
+
}
|
|
421
|
+
this.savedClaudeSettings = null;
|
|
422
|
+
this.claudeSettingsInstalled = false;
|
|
423
|
+
}
|
|
424
|
+
// ── Bouncer propagation for sub-agents ─────────────────────
|
|
425
|
+
/** Saved content of any pre-existing .mcp.json so we can restore it */
|
|
426
|
+
savedMcpJson = null;
|
|
427
|
+
mcpJsonInstalled = false;
|
|
428
|
+
/**
|
|
429
|
+
* Write .mcp.json in the working directory so Agent Teams teammates
|
|
430
|
+
* (separate processes) auto-discover the bouncer MCP server.
|
|
431
|
+
* This is essential — teammates don't inherit --mcp-config or
|
|
432
|
+
* --permission-prompt-tool from the team lead. .mcp.json project-level
|
|
433
|
+
* discovery + global PreToolUse hooks are the two bouncer paths for teammates.
|
|
434
|
+
*
|
|
435
|
+
* Also generates ~/.mstro/mcp-config.json for the team lead (--mcp-config).
|
|
436
|
+
*/
|
|
437
|
+
installBouncerForSubagents() {
|
|
438
|
+
const mcpJsonPath = join(this.workingDir, '.mcp.json');
|
|
439
|
+
// Generate the standard MCP config (for parent --mcp-config) and reuse for sub-agents
|
|
440
|
+
try {
|
|
441
|
+
const generatedPath = generateMcpConfig(this.workingDir);
|
|
442
|
+
if (!generatedPath)
|
|
443
|
+
return;
|
|
444
|
+
const mcpConfig = readFileSync(generatedPath, 'utf-8');
|
|
445
|
+
// Save any existing .mcp.json
|
|
446
|
+
if (existsSync(mcpJsonPath)) {
|
|
447
|
+
this.savedMcpJson = readFileSync(mcpJsonPath, 'utf-8');
|
|
448
|
+
// Merge: add bouncer to existing config
|
|
449
|
+
const existing = JSON.parse(this.savedMcpJson);
|
|
450
|
+
const generated = JSON.parse(mcpConfig);
|
|
451
|
+
existing.mcpServers = {
|
|
452
|
+
...existing.mcpServers,
|
|
453
|
+
'mstro-bouncer': generated.mcpServers['mstro-bouncer'],
|
|
454
|
+
};
|
|
455
|
+
writeFileSync(mcpJsonPath, JSON.stringify(existing, null, 2));
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
writeFileSync(mcpJsonPath, mcpConfig);
|
|
459
|
+
}
|
|
460
|
+
this.mcpJsonInstalled = true;
|
|
461
|
+
}
|
|
462
|
+
catch {
|
|
463
|
+
// Non-fatal: parent has MCP via --mcp-config, teammates fall back to PreToolUse hooks
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Restore or remove .mcp.json after execution.
|
|
468
|
+
*/
|
|
469
|
+
uninstallBouncerForSubagents() {
|
|
470
|
+
if (!this.mcpJsonInstalled)
|
|
471
|
+
return;
|
|
472
|
+
const mcpJsonPath = join(this.workingDir, '.mcp.json');
|
|
473
|
+
try {
|
|
474
|
+
if (this.savedMcpJson !== null) {
|
|
475
|
+
// Restore the original
|
|
476
|
+
writeFileSync(mcpJsonPath, this.savedMcpJson);
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
// We created it — remove it
|
|
480
|
+
unlinkSync(mcpJsonPath);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
catch {
|
|
484
|
+
// Best effort cleanup
|
|
485
|
+
}
|
|
486
|
+
this.savedMcpJson = null;
|
|
487
|
+
this.mcpJsonInstalled = false;
|
|
488
|
+
}
|
|
489
|
+
// ── Helpers ───────────────────────────────────────────────────
|
|
490
|
+
/**
|
|
491
|
+
* Resolve the canonical output path for an issue in .pm/out/.
|
|
492
|
+
* This is the PM system's internal execution artifact — always under
|
|
493
|
+
* PM control. User-facing delivery to output_file happens via publishOutputs().
|
|
494
|
+
*/
|
|
495
|
+
resolveOutputPath(issue) {
|
|
496
|
+
const pmDir = resolvePmDir(this.workingDir);
|
|
497
|
+
const outDir = pmDir ? join(pmDir, 'out') : join(this.workingDir, '.pm', 'out');
|
|
498
|
+
return join(outDir, `${issue.id}-${this.slugify(issue.title)}.md`);
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* List existing execution output docs in .pm/out/.
|
|
502
|
+
* Single canonical location — no split-brain lookup.
|
|
503
|
+
*/
|
|
504
|
+
listExistingDocs() {
|
|
505
|
+
const pmDir = resolvePmDir(this.workingDir);
|
|
506
|
+
if (!pmDir)
|
|
507
|
+
return [];
|
|
508
|
+
const outDir = join(pmDir, 'out');
|
|
509
|
+
if (!existsSync(outDir))
|
|
510
|
+
return [];
|
|
511
|
+
try {
|
|
512
|
+
return readdirSync(outDir)
|
|
513
|
+
.filter(f => f.endsWith('.md'))
|
|
514
|
+
.map(f => join(outDir, f));
|
|
515
|
+
}
|
|
516
|
+
catch {
|
|
517
|
+
return [];
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Copy confirmed-done outputs from .pm/out/ to user-specified output_file paths.
|
|
522
|
+
* Only copies for issues that completed successfully and have output_file set.
|
|
523
|
+
* Failures are non-fatal — the canonical artifact in .pm/out/ is always safe.
|
|
524
|
+
*/
|
|
525
|
+
publishOutputs(issues) {
|
|
526
|
+
const pmDir = resolvePmDir(this.workingDir);
|
|
527
|
+
if (!pmDir)
|
|
528
|
+
return;
|
|
529
|
+
for (const issue of issues) {
|
|
530
|
+
if (!issue.outputFile)
|
|
531
|
+
continue;
|
|
532
|
+
// Only publish for confirmed-done issues
|
|
533
|
+
try {
|
|
534
|
+
const content = readFileSync(join(pmDir, issue.path), 'utf-8');
|
|
535
|
+
if (!content.match(/^status:\s*done$/m))
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
catch {
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
const srcPath = this.resolveOutputPath(issue);
|
|
542
|
+
if (!existsSync(srcPath))
|
|
543
|
+
continue;
|
|
544
|
+
// Guard against path traversal — output_file must resolve within workingDir
|
|
545
|
+
const destPath = resolve(this.workingDir, issue.outputFile);
|
|
546
|
+
if (!destPath.startsWith(this.workingDir + '/') && destPath !== this.workingDir) {
|
|
547
|
+
this.emit('output', {
|
|
548
|
+
issueId: issue.id,
|
|
549
|
+
text: `Warning: output_file "${issue.outputFile}" escapes project directory — skipping`,
|
|
550
|
+
});
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
try {
|
|
554
|
+
// Ensure destination directory exists
|
|
555
|
+
const destDir = join(destPath, '..');
|
|
556
|
+
if (!existsSync(destDir))
|
|
557
|
+
mkdirSync(destDir, { recursive: true });
|
|
558
|
+
copyFileSync(srcPath, destPath);
|
|
559
|
+
}
|
|
560
|
+
catch {
|
|
561
|
+
// Non-fatal — canonical artifact is safe in .pm/out/
|
|
562
|
+
this.emit('output', {
|
|
563
|
+
issueId: issue.id,
|
|
564
|
+
text: `Warning: could not copy output to ${issue.outputFile}`,
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
slugify(text) {
|
|
570
|
+
return text
|
|
571
|
+
.toLowerCase()
|
|
572
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
573
|
+
.replace(/^-+|-+$/g, '')
|
|
574
|
+
.slice(0, 60);
|
|
575
|
+
}
|
|
576
|
+
updateIssueFrontMatter(issuePath, newStatus) {
|
|
577
|
+
const pmDir = resolvePmDir(this.workingDir);
|
|
578
|
+
if (!pmDir)
|
|
579
|
+
return;
|
|
580
|
+
const fullPath = join(pmDir, issuePath);
|
|
581
|
+
try {
|
|
582
|
+
let content = readFileSync(fullPath, 'utf-8');
|
|
583
|
+
content = content.replace(/^(status:\s*).+$/m, `$1${newStatus}`);
|
|
584
|
+
writeFileSync(fullPath, content, 'utf-8');
|
|
585
|
+
}
|
|
586
|
+
catch {
|
|
587
|
+
// Ignore errors — file may have been moved
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Append a progress log entry after a wave completes.
|
|
592
|
+
* Re-reads issue files from disk to determine which actually completed.
|
|
593
|
+
*/
|
|
594
|
+
appendProgressEntry(issues, waveStart) {
|
|
595
|
+
const pmDir = resolvePmDir(this.workingDir);
|
|
596
|
+
if (!pmDir)
|
|
597
|
+
return;
|
|
598
|
+
const progressPath = join(pmDir, 'progress.md');
|
|
599
|
+
if (!existsSync(progressPath))
|
|
600
|
+
return;
|
|
601
|
+
const durationMin = Math.round((Date.now() - waveStart) / 60_000);
|
|
602
|
+
const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 16);
|
|
603
|
+
// Re-read issue statuses from disk to get accurate completion count
|
|
604
|
+
const completed = [];
|
|
605
|
+
const failed = [];
|
|
606
|
+
for (const issue of issues) {
|
|
607
|
+
try {
|
|
608
|
+
const content = readFileSync(join(pmDir, issue.path), 'utf-8');
|
|
609
|
+
const statusMatch = content.match(/^status:\s*(\S+)/m);
|
|
610
|
+
if (statusMatch?.[1] === 'done') {
|
|
611
|
+
completed.push(issue.id);
|
|
612
|
+
}
|
|
613
|
+
else {
|
|
614
|
+
failed.push(issue.id);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
catch {
|
|
618
|
+
failed.push(issue.id);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
const lines = [
|
|
622
|
+
'',
|
|
623
|
+
`## ${timestamp} — Wave [${issues.map(i => i.id).join(', ')}]`,
|
|
624
|
+
'',
|
|
625
|
+
`- **Duration**: ${durationMin} min`,
|
|
626
|
+
`- **Completed**: ${completed.length}/${issues.length}${completed.length > 0 ? ` (${completed.join(', ')})` : ''}`,
|
|
627
|
+
];
|
|
628
|
+
if (failed.length > 0) {
|
|
629
|
+
lines.push(`- **Failed**: ${failed.join(', ')}`);
|
|
630
|
+
}
|
|
631
|
+
lines.push('');
|
|
632
|
+
try {
|
|
633
|
+
const existing = readFileSync(progressPath, 'utf-8');
|
|
634
|
+
writeFileSync(progressPath, existing.trimEnd() + '\n' + lines.join('\n'), 'utf-8');
|
|
635
|
+
}
|
|
636
|
+
catch {
|
|
637
|
+
// Non-fatal
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../server/services/plan/executor.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,gEAAgE;AAEhE;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACpH,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAcvD,MAAM,OAAO,YAAa,SAAQ,YAAY;IACpC,MAAM,GAAoB,MAAM,CAAC;IACjC,UAAU,CAAS;IACnB,UAAU,GAAG,KAAK,CAAC;IACnB,WAAW,GAAG,KAAK,CAAC;IACpB,SAAS,GAAkB,IAAI,CAAC;IAChC,OAAO,GAAqB;QAClC,eAAe,EAAE,CAAC;QAClB,eAAe,EAAE,CAAC;QAClB,aAAa,EAAE,CAAC;QAChB,cAAc,EAAE,IAAI;QACpB,cAAc,EAAE,EAAE;KACnB,CAAC;IAEF,YAAY,UAAkB;QAC5B,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,UAAU;QACR,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,QAAgB;QAC9B,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU;YAAE,OAAO;QAEtE,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAExC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAExC,OAAO,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC7C,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;gBAC3C,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;oBAAE,MAAM;gBAEpC,uEAAuE;gBACvE,wEAAwE;gBACxE,0EAA0E;gBAC1E,MAAM,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;YACtB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAC3E,OAAO;QACT,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAEpD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC;QACzB,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK;QACH,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED,IAAI;QACF,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;IACzB,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ;YAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QACvD,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,iEAAiE;IAEzD,KAAK,CAAC,WAAW,CAAC,MAAe;QACvC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACtC,IAAI,CAAC,OAAO,CAAC,cAAc,GAAG,OAAO,CAAC;QACtC,IAAI,CAAC,OAAO,CAAC,eAAe,IAAI,MAAM,CAAC,MAAM,CAAC;QAC9C,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QAEhD,8CAA8C;QAC9C,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YAClC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;gBAAE,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC;QAED,0EAA0E;QAC1E,IAAI,CAAC,0BAA0B,EAAE,CAAC;QAElC,iEAAiE;QACjE,IAAI,CAAC,0BAA0B,EAAE,CAAC;QAElC,sCAAsC;QACtC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAEnD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;gBAChC,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,YAAY,EAAE,MAAM;gBACpB,WAAW,EAAE,SAAS,EAAG,4BAA4B;gBACrD,cAAc,EAAE,SAAS,EAAE,gBAAgB;gBAC3C,QAAQ,EAAE;oBACR,oCAAoC,EAAE,GAAG;iBAC1C;gBACD,cAAc,EAAE,CAAC,IAAY,EAAE,EAAE;oBAC/B,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,QAAQ,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;gBACvE,CAAC;aACF,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;YAE9E,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACtC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;oBACrB,QAAQ,EAAE,OAAO;oBACjB,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,oCAAoC;iBAC5D,CAAC,CAAC;YACL,CAAC;YAED,mEAAmE;YACnE,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAEpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;gBACrB,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;aAC9D,CAAC,CAAC;YACH,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC;gBAAS,CAAC;YACT,4DAA4D;YAC5D,IAAI,CAAC,4BAA4B,EAAE,CAAC;YACpC,IAAI,CAAC,4BAA4B,EAAE,CAAC;QACtC,CAAC;QAED,oDAAoD;QACpD,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAE1B,kEAAkE;QAClE,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAE5B,4BAA4B;QAC5B,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAE5C,IAAI,CAAC,OAAO,CAAC,cAAc,GAAG,EAAE,CAAC;IACnC,CAAC;IAED;;;;;OAKG;IACK,oBAAoB,CAAC,MAAe;QAC1C,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAChD,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBACvD,MAAM,aAAa,GAAG,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;gBAEpD,IAAI,aAAa,KAAK,MAAM,EAAE,CAAC;oBAC7B,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;oBAC/B,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;gBACrC,CAAC;qBAAM,CAAC;oBACN,oCAAoC;oBACpC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;oBACtD,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;wBACtB,OAAO,EAAE,KAAK,CAAC,EAAE;wBACjB,KAAK,EAAE,8CAA8C;qBACtD,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,sCAAsC,EAAE,CAAC,CAAC;YAChG,CAAC;QACH,CAAC;IACH,CAAC;IAED,iEAAiE;IAEzD,eAAe;QACrB,MAAM,SAAS,GAAG,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,yBAAyB,CAAC,CAAC;YAC9C,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,IAAI,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;YACxC,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,WAAW,GAAG,kBAAkB,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC;QACtF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,qCAAqC,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC;QAChH,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,iEAAiE;IAEjE;;;;;OAKG;IACK,sBAAsB,CAAC,MAAe;QAC5C,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QAEhF,6DAA6D;QAC7D,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAE7C,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;YACrC,MAAM,QAAQ,GAAG,KAAK,CAAC,kBAAkB;iBACtC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;iBAClD,IAAI,CAAC,IAAI,CAAC,CAAC;YAEd,MAAM,KAAK,GAAG,KAAK,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC;gBAC1C,CAAC,CAAC,uBAAuB,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBAC5E,CAAC,CAAC,EAAE,CAAC;YAEP,sDAAsD;YACtD,MAAM,eAAe,GAAG,KAAK,CAAC,SAAS;iBACpC,GAAG,CAAC,EAAE,CAAC,EAAE;gBACR,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBACpE,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;YACnF,CAAC,CAAC;iBACD,MAAM,CAAC,OAAO,CAAa,CAAC;YAE/B,MAAM,kBAAkB,GAAG,eAAe,CAAC,MAAM,GAAG,CAAC;gBACnD,CAAC,CAAC,mCAAmC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBACpF,CAAC,CAAC,EAAE,CAAC;YAEP,OAAO,OAAO,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,KAAK;;YAEhC,KAAK,CAAC,IAAI,oBAAoB,KAAK,CAAC,QAAQ,oBAAoB,KAAK,CAAC,QAAQ,IAAI,aAAa;;;EAGzG,KAAK,CAAC,WAAW;;;EAGjB,QAAQ,IAAI,+BAA+B;;;EAG3C,KAAK,CAAC,cAAc,IAAI,MAAM;EAC9B,KAAK,GAAG,kBAAkB;;mBAET,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAEvB,MAAM,QAAQ,GAAG,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAEzC,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;YACxC,MAAM,eAAe,GAAG,KAAK,CAAC,SAAS;iBACpC,GAAG,CAAC,EAAE,CAAC,EAAE;gBACR,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBACpE,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;YACnF,CAAC,CAAC;iBACD,MAAM,CAAC,OAAO,CAAa,CAAC;YAE/B,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,GAAG,CAAC;gBAC1C,CAAC,CAAC,uDAAuD,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;gBACvF,CAAC,CAAC,EAAE,CAAC;YAEP,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAEjD,OAAO,oBAAoB,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,kDAAkD,QAAQ,oBAAoB,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE;IACvJ,SAAS,iBAAiB,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,KAAK;0BAC5B,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;;0CAE5B,UAAU;;8EAE0B,CAAC;QAC3E,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEhB,OAAO,sCAAsC,MAAM,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;;;qBAG9E,IAAI,CAAC,UAAU;kBAClB,KAAK,IAAI,MAAM;;;;EAI/B,WAAW;;;;;;YAMD,MAAM,CAAC,MAAM,2DAA2D,MAAM,CAAC,MAAM,+DAA+D,QAAQ;;EAEtK,cAAc;;;;;;;EAOd,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;iFAKsB,MAAM,CAAC,MAAM;;;;;;;uCAOvD,MAAM;;;;;;;;kDAQK,MAAM,CAAC,MAAM;;;gDAGf,CAAC;IAC/C,CAAC;IAED;;OAEG;IACK,sBAAsB,CAAC,MAAe;QAC5C,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAChD,IAAI,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,EAAE,CAAC;oBAC9C,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;gBACxD,CAAC;YACH,CAAC;YAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,gEAAgE;IAEhE,mFAAmF;IAC3E,mBAAmB,GAAkB,IAAI,CAAC;IAC1C,uBAAuB,GAAG,KAAK,CAAC;IAExC;;;;;;OAMG;IACK,0BAA0B;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QACnD,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;QAEtD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,CAAC;QAED,iDAAiD;QACjD,MAAM,mBAAmB,GAAG;YAC1B,MAAM;YACN,MAAM;YACN,MAAM;YACN,OAAO;YACP,MAAM;YACN,MAAM;YACN,UAAU;YACV,WAAW;YACX,OAAO;SACR,CAAC;QAEF,IAAI,CAAC;YACH,yBAAyB;YACzB,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC,mBAAmB,GAAG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;gBAC/D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;gBAEtD,2CAA2C;gBAC3C,IAAI,CAAC,QAAQ,CAAC,WAAW;oBAAE,QAAQ,CAAC,WAAW,GAAG,EAAE,CAAC;gBACrD,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK;oBAAE,QAAQ,CAAC,WAAW,CAAC,KAAK,GAAG,EAAE,CAAC;gBAEjE,KAAK,MAAM,IAAI,IAAI,mBAAmB,EAAE,CAAC;oBACvC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC/C,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACxC,CAAC;gBACH,CAAC;gBAED,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACjE,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;gBAChC,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC;oBACzC,WAAW,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE;iBAC5C,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACf,CAAC;YACD,IAAI,CAAC,uBAAuB,GAAG,IAAI,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,mDAAmD;QACrD,CAAC;IACH,CAAC;IAED;;OAEG;IACK,4BAA4B;QAClC,IAAI,CAAC,IAAI,CAAC,uBAAuB;YAAE,OAAO;QAC1C,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;QAEvE,IAAI,CAAC;YACH,IAAI,IAAI,CAAC,mBAAmB,KAAK,IAAI,EAAE,CAAC;gBACtC,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,mBAAmB,CAAC,CAAC;YACxD,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,YAAY,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;QAED,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;QAChC,IAAI,CAAC,uBAAuB,GAAG,KAAK,CAAC;IACvC,CAAC;IAED,8DAA8D;IAE9D,uEAAuE;IAC/D,YAAY,GAAkB,IAAI,CAAC;IACnC,gBAAgB,GAAG,KAAK,CAAC;IAEjC;;;;;;;;OAQG;IACK,0BAA0B;QAChC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QAEvD,sFAAsF;QACtF,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACzD,IAAI,CAAC,aAAa;gBAAE,OAAO;YAE3B,MAAM,SAAS,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YAEvD,8BAA8B;YAC9B,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC5B,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;gBAEvD,wCAAwC;gBACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBACxC,QAAQ,CAAC,UAAU,GAAG;oBACpB,GAAG,QAAQ,CAAC,UAAU;oBACtB,eAAe,EAAE,SAAS,CAAC,UAAU,CAAC,eAAe,CAAC;iBACvD,CAAC;gBACF,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAChE,CAAC;iBAAM,CAAC;gBACN,aAAa,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;YACxC,CAAC;YAED,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,sFAAsF;QACxF,CAAC;IACH,CAAC;IAED;;OAEG;IACK,4BAA4B;QAClC,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,OAAO;QACnC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QAEvD,IAAI,CAAC;YACH,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;gBAC/B,uBAAuB;gBACvB,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;YAChD,CAAC;iBAAM,CAAC;gBACN,4BAA4B;gBAC5B,UAAU,CAAC,WAAW,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,sBAAsB;QACxB,CAAC;QAED,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;IAChC,CAAC;IAED,iEAAiE;IAEjE;;;;OAIG;IACK,iBAAiB,CAAC,KAAY;QACpC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QAChF,OAAO,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrE,CAAC;IAED;;;OAGG;IACK,gBAAgB;QACtB,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAC;QAEnC,IAAI,CAAC;YACH,OAAO,WAAW,CAAC,MAAM,CAAC;iBACvB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;iBAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,cAAc,CAAC,MAAe;QACpC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC,KAAK,CAAC,UAAU;gBAAE,SAAS;YAEhC,yCAAyC;YACzC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;gBAC/D,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC;oBAAE,SAAS;YACpD,CAAC;YAAC,MAAM,CAAC;gBAAC,SAAS;YAAC,CAAC;YAErB,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC9C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,SAAS;YAEnC,4EAA4E;YAC5E,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;YAC5D,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC,IAAI,QAAQ,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChF,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;oBAClB,OAAO,EAAE,KAAK,CAAC,EAAE;oBACjB,IAAI,EAAE,yBAAyB,KAAK,CAAC,UAAU,wCAAwC;iBACxF,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,sCAAsC;gBACtC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gBACrC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;oBAAE,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAClE,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YAClC,CAAC;YAAC,MAAM,CAAC;gBACP,qDAAqD;gBACrD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;oBAClB,OAAO,EAAE,KAAK,CAAC,EAAE;oBACjB,IAAI,EAAE,qCAAqC,KAAK,CAAC,UAAU,EAAE;iBAC9D,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAEO,OAAO,CAAC,IAAY;QAC1B,OAAO,IAAI;aACR,WAAW,EAAE;aACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;aAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;aACvB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAClB,CAAC;IAEO,sBAAsB,CAAC,SAAiB,EAAE,SAAiB;QACjE,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QACxC,IAAI,CAAC;YACH,IAAI,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC9C,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,mBAAmB,EAAE,KAAK,SAAS,EAAE,CAAC,CAAC;YACjE,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,2CAA2C;QAC7C,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,mBAAmB,CAAC,MAAe,EAAE,SAAiB;QAC5D,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QAChD,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;YAAE,OAAO;QAEtC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,MAAM,CAAC,CAAC;QAClE,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAE1E,oEAAoE;QACpE,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;gBAC/D,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBACvD,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;oBAChC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC3B,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QAED,MAAM,KAAK,GAAG;YACZ,EAAE;YACF,MAAM,SAAS,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;YAC9D,EAAE;YACF,mBAAmB,WAAW,MAAM;YACpC,oBAAoB,SAAS,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;SACnH,CAAC;QACF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,KAAK,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnD,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEf,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACrD,aAAa,CAAC,YAAY,EAAE,QAAQ,CAAC,OAAO,EAAE,GAAG,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;QACrF,CAAC;QAAC,MAAM,CAAC;YACP,YAAY;QACd,CAAC;IACH,CAAC;CACF"}
|