popeye-cli 1.8.0 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +47 -3
  2. package/cheatsheet.md +33 -0
  3. package/dist/cli/commands/index.d.ts +1 -0
  4. package/dist/cli/commands/index.d.ts.map +1 -1
  5. package/dist/cli/commands/index.js +1 -0
  6. package/dist/cli/commands/index.js.map +1 -1
  7. package/dist/cli/commands/review.d.ts +31 -0
  8. package/dist/cli/commands/review.d.ts.map +1 -0
  9. package/dist/cli/commands/review.js +156 -0
  10. package/dist/cli/commands/review.js.map +1 -0
  11. package/dist/cli/index.d.ts.map +1 -1
  12. package/dist/cli/index.js +2 -1
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/cli/interactive.d.ts.map +1 -1
  15. package/dist/cli/interactive.js +122 -61
  16. package/dist/cli/interactive.js.map +1 -1
  17. package/dist/types/audit.d.ts +623 -0
  18. package/dist/types/audit.d.ts.map +1 -0
  19. package/dist/types/audit.js +240 -0
  20. package/dist/types/audit.js.map +1 -0
  21. package/dist/types/workflow.d.ts +15 -0
  22. package/dist/types/workflow.d.ts.map +1 -1
  23. package/dist/types/workflow.js +5 -0
  24. package/dist/types/workflow.js.map +1 -1
  25. package/dist/workflow/audit-analyzer.d.ts +58 -0
  26. package/dist/workflow/audit-analyzer.d.ts.map +1 -0
  27. package/dist/workflow/audit-analyzer.js +438 -0
  28. package/dist/workflow/audit-analyzer.js.map +1 -0
  29. package/dist/workflow/audit-mode.d.ts +28 -0
  30. package/dist/workflow/audit-mode.d.ts.map +1 -0
  31. package/dist/workflow/audit-mode.js +169 -0
  32. package/dist/workflow/audit-mode.js.map +1 -0
  33. package/dist/workflow/audit-recovery.d.ts +61 -0
  34. package/dist/workflow/audit-recovery.d.ts.map +1 -0
  35. package/dist/workflow/audit-recovery.js +242 -0
  36. package/dist/workflow/audit-recovery.js.map +1 -0
  37. package/dist/workflow/audit-reporter.d.ts +65 -0
  38. package/dist/workflow/audit-reporter.d.ts.map +1 -0
  39. package/dist/workflow/audit-reporter.js +301 -0
  40. package/dist/workflow/audit-reporter.js.map +1 -0
  41. package/dist/workflow/audit-scanner.d.ts +87 -0
  42. package/dist/workflow/audit-scanner.d.ts.map +1 -0
  43. package/dist/workflow/audit-scanner.js +768 -0
  44. package/dist/workflow/audit-scanner.js.map +1 -0
  45. package/dist/workflow/index.d.ts +5 -0
  46. package/dist/workflow/index.d.ts.map +1 -1
  47. package/dist/workflow/index.js +5 -0
  48. package/dist/workflow/index.js.map +1 -1
  49. package/package.json +1 -1
  50. package/src/cli/commands/index.ts +1 -0
  51. package/src/cli/commands/review.ts +187 -0
  52. package/src/cli/index.ts +2 -0
  53. package/src/cli/interactive.ts +72 -4
  54. package/src/types/audit.ts +294 -0
  55. package/src/types/workflow.ts +15 -0
  56. package/src/workflow/audit-analyzer.ts +510 -0
  57. package/src/workflow/audit-mode.ts +240 -0
  58. package/src/workflow/audit-recovery.ts +284 -0
  59. package/src/workflow/audit-reporter.ts +370 -0
  60. package/src/workflow/audit-scanner.ts +873 -0
  61. package/src/workflow/index.ts +5 -0
  62. package/tests/cli/commands/review.test.ts +52 -0
  63. package/tests/types/audit.test.ts +250 -0
  64. package/tests/workflow/audit-analyzer.test.ts +281 -0
  65. package/tests/workflow/audit-mode.test.ts +114 -0
  66. package/tests/workflow/audit-recovery.test.ts +237 -0
  67. package/tests/workflow/audit-reporter.test.ts +254 -0
  68. package/tests/workflow/audit-scanner.test.ts +270 -0
@@ -0,0 +1,301 @@
1
+ /**
2
+ * Report generation for the audit system.
3
+ *
4
+ * Builds summary + full reports, writes markdown and JSON artifacts
5
+ * to the project's .popeye/ directory.
6
+ */
7
+ import { promises as fs } from 'node:fs';
8
+ import path from 'node:path';
9
+ // ---------------------------------------------------------------------------
10
+ // Summary report
11
+ // ---------------------------------------------------------------------------
12
+ /**
13
+ * Build a summary report from the scan result and project state.
14
+ *
15
+ * @param scan - The project scan result.
16
+ * @param state - Current project state.
17
+ * @param aiOverview - Optional AI-generated overview text.
18
+ * @returns A structured summary report.
19
+ */
20
+ export function buildSummaryReport(scan, state, aiOverview) {
21
+ const depCount = scan.dependencies.reduce((sum, d) => {
22
+ const deps = d.dependencies ? Object.keys(d.dependencies).length : 0;
23
+ const devDeps = d.devDependencies ? Object.keys(d.devDependencies).length : 0;
24
+ return sum + deps + devDeps;
25
+ }, 0);
26
+ return {
27
+ projectName: state.name,
28
+ language: scan.language,
29
+ totalSourceFiles: scan.totalSourceFiles,
30
+ totalTestFiles: scan.totalTestFiles,
31
+ totalLinesOfCode: scan.totalLinesOfCode,
32
+ totalLinesOfTests: scan.totalLinesOfTests,
33
+ componentCount: scan.components.length,
34
+ detectedComposition: [...scan.detectedComposition],
35
+ entryPointCount: scan.entryPoints.length,
36
+ routeCount: scan.routeFiles.length,
37
+ dependencyCount: depCount,
38
+ hasDocker: scan.configFiles.includes('docker-compose.yml')
39
+ || scan.configFiles.includes('docker-compose.yaml')
40
+ || scan.configFiles.includes('Dockerfile'),
41
+ hasEnvExample: !!scan.envExampleContent,
42
+ hasCiConfig: scan.configFiles.some((f) => f.includes('.github') || f.includes('Jenkinsfile') || f.includes('.gitlab-ci')),
43
+ aiOverview,
44
+ };
45
+ }
46
+ // ---------------------------------------------------------------------------
47
+ // Audit report
48
+ // ---------------------------------------------------------------------------
49
+ /**
50
+ * Derive the overall recommendation from finding counts and score.
51
+ *
52
+ * @param criticalCount - Number of critical findings.
53
+ * @param majorCount - Number of major findings.
54
+ * @param overallScore - The overall audit score (0-100).
55
+ * @param strict - Whether strict mode is enabled.
56
+ * @returns The recommendation string.
57
+ */
58
+ function deriveRecommendation(criticalCount, majorCount, overallScore, strict) {
59
+ if (criticalCount >= 3 || overallScore < 50)
60
+ return 'major-rework';
61
+ if (criticalCount === 0 && (strict ? majorCount === 0 : majorCount <= 2))
62
+ return 'pass';
63
+ return 'fix-and-recheck';
64
+ }
65
+ /**
66
+ * Build the full audit report from all analysis results.
67
+ *
68
+ * @param summary - The summary report.
69
+ * @param findings - All audit findings.
70
+ * @param scores - Overall and category scores.
71
+ * @param searchMeta - Serena search tracking metadata.
72
+ * @param options - Audit options (for strict mode, etc.).
73
+ * @param auditRunId - Unique run identifier.
74
+ * @returns The complete audit report.
75
+ */
76
+ export function buildAuditReport(summary, findings, scores, searchMeta, options, auditRunId) {
77
+ const criticalCount = findings.filter((f) => f.severity === 'critical').length;
78
+ const majorCount = findings.filter((f) => f.severity === 'major').length;
79
+ const minorCount = findings.filter((f) => f.severity === 'minor').length;
80
+ const infoCount = findings.filter((f) => f.severity === 'info').length;
81
+ // Determine passed checks — categories with no findings
82
+ const categoriesWithFindings = new Set(findings.map((f) => f.category));
83
+ const allCategories = [
84
+ 'feature-completeness', 'integration-wiring', 'test-coverage',
85
+ 'config-deployment', 'dependency-sanity', 'consistency', 'security', 'documentation',
86
+ ];
87
+ const passedChecks = allCategories
88
+ .filter((c) => !categoriesWithFindings.has(c))
89
+ .map((c) => `${c}: no issues found`);
90
+ return {
91
+ projectName: summary.projectName,
92
+ language: summary.language,
93
+ auditedAt: new Date().toISOString(),
94
+ auditRunId,
95
+ summary,
96
+ findings,
97
+ overallScore: scores.overallScore,
98
+ categoryScores: scores.categoryScores,
99
+ criticalCount,
100
+ majorCount,
101
+ minorCount,
102
+ infoCount,
103
+ passedChecks,
104
+ searchMetadata: searchMeta,
105
+ recommendation: deriveRecommendation(criticalCount, majorCount, scores.overallScore, options.strict),
106
+ };
107
+ }
108
+ // ---------------------------------------------------------------------------
109
+ // Markdown rendering
110
+ // ---------------------------------------------------------------------------
111
+ /**
112
+ * Render the audit report as a markdown string.
113
+ *
114
+ * @param report - The audit report.
115
+ * @returns Markdown string.
116
+ */
117
+ function renderAuditMarkdown(report) {
118
+ const lines = [];
119
+ lines.push(`# Audit Report: ${report.projectName}`);
120
+ lines.push('');
121
+ lines.push(`**Language:** ${report.language}`);
122
+ lines.push(`**Audited:** ${report.auditedAt}`);
123
+ lines.push(`**Run ID:** ${report.auditRunId}`);
124
+ lines.push(`**Overall Score:** ${report.overallScore}/100`);
125
+ lines.push(`**Recommendation:** ${report.recommendation}`);
126
+ lines.push('');
127
+ // Summary
128
+ lines.push('## Summary');
129
+ lines.push('');
130
+ lines.push(`| Metric | Value |`);
131
+ lines.push(`| --- | --- |`);
132
+ lines.push(`| Source files | ${report.summary.totalSourceFiles} |`);
133
+ lines.push(`| Test files | ${report.summary.totalTestFiles} |`);
134
+ lines.push(`| Lines of code | ${report.summary.totalLinesOfCode} |`);
135
+ lines.push(`| Lines of tests | ${report.summary.totalLinesOfTests} |`);
136
+ lines.push(`| Components | ${report.summary.componentCount} |`);
137
+ lines.push(`| Entry points | ${report.summary.entryPointCount} |`);
138
+ lines.push(`| Routes | ${report.summary.routeCount} |`);
139
+ lines.push(`| Dependencies | ${report.summary.dependencyCount} |`);
140
+ lines.push('');
141
+ // Category scores
142
+ lines.push('## Category Scores');
143
+ lines.push('');
144
+ for (const [cat, score] of Object.entries(report.categoryScores)) {
145
+ lines.push(`- **${cat}:** ${score}/100`);
146
+ }
147
+ lines.push('');
148
+ // Findings
149
+ lines.push(`## Findings (${report.findings.length} total)`);
150
+ lines.push('');
151
+ lines.push(`- Critical: ${report.criticalCount}`);
152
+ lines.push(`- Major: ${report.majorCount}`);
153
+ lines.push(`- Minor: ${report.minorCount}`);
154
+ lines.push(`- Info: ${report.infoCount}`);
155
+ lines.push('');
156
+ // Group findings by severity
157
+ const severityOrder = ['critical', 'major', 'minor', 'info'];
158
+ for (const sev of severityOrder) {
159
+ const sevFindings = report.findings.filter((f) => f.severity === sev);
160
+ if (sevFindings.length === 0)
161
+ continue;
162
+ lines.push(`### ${sev.charAt(0).toUpperCase() + sev.slice(1)}`);
163
+ lines.push('');
164
+ for (const f of sevFindings) {
165
+ lines.push(`#### ${f.id}: ${f.title}`);
166
+ lines.push('');
167
+ lines.push(f.description);
168
+ if (f.evidence.length > 0) {
169
+ lines.push('');
170
+ lines.push('**Evidence:**');
171
+ for (const e of f.evidence) {
172
+ const loc = e.line ? `${e.file}:${e.line}` : e.file;
173
+ lines.push(`- \`${loc}\`${e.description ? ` - ${e.description}` : ''}`);
174
+ }
175
+ }
176
+ lines.push('');
177
+ lines.push(`**Recommendation:** ${f.recommendation}`);
178
+ lines.push(`**Auto-fixable:** ${f.autoFixable ? 'Yes' : 'No'}`);
179
+ lines.push('');
180
+ }
181
+ }
182
+ // Passed checks
183
+ if (report.passedChecks.length > 0) {
184
+ lines.push('## Passed Checks');
185
+ lines.push('');
186
+ for (const check of report.passedChecks) {
187
+ lines.push(`- ${check}`);
188
+ }
189
+ lines.push('');
190
+ }
191
+ return lines.join('\n');
192
+ }
193
+ /**
194
+ * Render the recovery plan as a markdown string.
195
+ *
196
+ * @param recovery - The recovery plan.
197
+ * @returns Markdown string.
198
+ */
199
+ function renderRecoveryMarkdown(recovery) {
200
+ const lines = [];
201
+ lines.push('# Recovery Plan');
202
+ lines.push('');
203
+ lines.push(`**Generated:** ${recovery.generatedAt}`);
204
+ lines.push(`**Audit Score:** ${recovery.auditScore}/100`);
205
+ lines.push(`**Run ID:** ${recovery.auditRunId}`);
206
+ lines.push(`**Total Findings:** ${recovery.totalFindings}`);
207
+ lines.push(`**Critical Findings:** ${recovery.criticalFindings}`);
208
+ lines.push(`**Estimated Effort:** ${recovery.estimatedEffort}`);
209
+ lines.push('');
210
+ for (const milestone of recovery.milestones) {
211
+ lines.push(`## ${milestone.name}`);
212
+ lines.push('');
213
+ lines.push(milestone.description);
214
+ lines.push('');
215
+ for (const task of milestone.tasks) {
216
+ lines.push(`### ${task.name} (target: ${task.appTarget})`);
217
+ lines.push('');
218
+ lines.push(task.description);
219
+ lines.push('');
220
+ lines.push('**Finding IDs:** ' + task.findingIds.join(', '));
221
+ lines.push('');
222
+ lines.push('**Acceptance Criteria:**');
223
+ for (const ac of task.acceptanceCriteria) {
224
+ lines.push(`- [ ] ${ac}`);
225
+ }
226
+ if (task.testPlan) {
227
+ lines.push('');
228
+ lines.push(`**Test Plan:** ${task.testPlan}`);
229
+ }
230
+ lines.push('');
231
+ }
232
+ }
233
+ return lines.join('\n');
234
+ }
235
+ // ---------------------------------------------------------------------------
236
+ // File writers
237
+ // ---------------------------------------------------------------------------
238
+ /**
239
+ * Ensure .popeye directory exists.
240
+ *
241
+ * @param projectDir - Project root directory.
242
+ * @returns Path to .popeye directory.
243
+ */
244
+ async function ensurePopeyeDir(projectDir) {
245
+ const dir = path.join(projectDir, '.popeye');
246
+ await fs.mkdir(dir, { recursive: true });
247
+ return dir;
248
+ }
249
+ /**
250
+ * Write the audit report as markdown.
251
+ *
252
+ * @param projectDir - Project root directory.
253
+ * @param report - The audit report.
254
+ * @returns Path to the written file.
255
+ */
256
+ export async function writeAuditMarkdown(projectDir, report) {
257
+ const dir = await ensurePopeyeDir(projectDir);
258
+ const filePath = path.join(dir, 'popeye.audit.md');
259
+ await fs.writeFile(filePath, renderAuditMarkdown(report), 'utf-8');
260
+ return filePath;
261
+ }
262
+ /**
263
+ * Write the audit report as JSON.
264
+ *
265
+ * @param projectDir - Project root directory.
266
+ * @param report - The audit report.
267
+ * @returns Path to the written file.
268
+ */
269
+ export async function writeAuditJson(projectDir, report) {
270
+ const dir = await ensurePopeyeDir(projectDir);
271
+ const filePath = path.join(dir, 'popeye.audit.json');
272
+ await fs.writeFile(filePath, JSON.stringify(report, null, 2), 'utf-8');
273
+ return filePath;
274
+ }
275
+ /**
276
+ * Write the recovery plan as markdown.
277
+ *
278
+ * @param projectDir - Project root directory.
279
+ * @param recovery - The recovery plan.
280
+ * @returns Path to the written file.
281
+ */
282
+ export async function writeRecoveryMarkdown(projectDir, recovery) {
283
+ const dir = await ensurePopeyeDir(projectDir);
284
+ const filePath = path.join(dir, 'popeye.recovery.md');
285
+ await fs.writeFile(filePath, renderRecoveryMarkdown(recovery), 'utf-8');
286
+ return filePath;
287
+ }
288
+ /**
289
+ * Write the recovery plan as JSON.
290
+ *
291
+ * @param projectDir - Project root directory.
292
+ * @param recovery - The recovery plan.
293
+ * @returns Path to the written file.
294
+ */
295
+ export async function writeRecoveryJson(projectDir, recovery) {
296
+ const dir = await ensurePopeyeDir(projectDir);
297
+ const filePath = path.join(dir, 'popeye.recovery.json');
298
+ await fs.writeFile(filePath, JSON.stringify(recovery, null, 2), 'utf-8');
299
+ return filePath;
300
+ }
301
+ //# sourceMappingURL=audit-reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-reporter.js","sourceRoot":"","sources":["../../src/workflow/audit-reporter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Deterministic project scanner for the audit system.
3
+ *
4
+ * Scans the filesystem to detect workspace composition, per-component structure,
5
+ * dependency manifests, route files, LOC, and FE<->BE wiring mismatches.
6
+ * Reads docs in priority order: CLAUDE.md -> README.md -> other docs.
7
+ */
8
+ import type { ComponentKind, ComponentScan, DependencyManifest, FileEntry, FileExcerpt, ProjectScanResult, WiringMatrix } from '../types/audit.js';
9
+ /**
10
+ * Detect workspace composition from the filesystem.
11
+ *
12
+ * Examines directory structure for signals of frontend, backend, website,
13
+ * shared, and infra components. Does NOT trust state.language — derives
14
+ * composition purely from filesystem evidence.
15
+ *
16
+ * @param projectDir - Project root directory.
17
+ * @returns Array of detected ComponentKind values.
18
+ */
19
+ export declare function detectWorkspaceComposition(projectDir: string): Promise<ComponentKind[]>;
20
+ /**
21
+ * Scan a single component directory for files, routes, entry points, and deps.
22
+ *
23
+ * @param componentDir - Absolute path to component root.
24
+ * @param kind - Component kind.
25
+ * @param language - Language hint (e.g., 'typescript', 'python').
26
+ * @returns ComponentScan result.
27
+ */
28
+ export declare function scanComponent(componentDir: string, kind: ComponentKind, language: 'typescript' | 'python' | 'mixed', projectDir?: string): Promise<ComponentScan>;
29
+ /**
30
+ * Parse all dependency manifests found in the project.
31
+ *
32
+ * @param projectDir - Project root directory.
33
+ * @param language - Project language.
34
+ * @returns Array of dependency manifests.
35
+ */
36
+ export declare function parseDependencies(projectDir: string, _language: string): Promise<DependencyManifest[]>;
37
+ /**
38
+ * Find all route-like files in the project.
39
+ *
40
+ * @param projectDir - Project root directory.
41
+ * @param language - Project language.
42
+ * @returns Array of relative paths to route files.
43
+ */
44
+ export declare function findRouteFiles(projectDir: string, _language: string): Promise<string[]>;
45
+ /**
46
+ * Read project documentation in priority order: CLAUDE.md -> README.md -> docs.
47
+ *
48
+ * @param projectDir - Project root directory.
49
+ * @returns Priority doc contents and docs index.
50
+ */
51
+ export declare function readPriorityDocs(projectDir: string): Promise<{
52
+ claudeMd?: string;
53
+ readme?: string;
54
+ docsIndex: string[];
55
+ keyFiles: FileExcerpt[];
56
+ }>;
57
+ /**
58
+ * Build a wiring matrix from the project, checking FE<->BE env keys,
59
+ * CORS origins, and API prefixes for mismatches.
60
+ *
61
+ * @param projectDir - Project root directory.
62
+ * @param components - Already-scanned component list.
63
+ * @returns WiringMatrix with detected mismatches.
64
+ */
65
+ export declare function buildWiringMatrix(projectDir: string, components: ComponentScan[]): Promise<WiringMatrix>;
66
+ /**
67
+ * Count lines of code and test code in the given file lists.
68
+ *
69
+ * @param sourceFiles - Array of source file entries.
70
+ * @param testFiles - Array of test file entries.
71
+ * @param projectDir - Project root for resolving paths.
72
+ * @returns Total lines of code and test code.
73
+ */
74
+ export declare function countLines(sourceFiles: FileEntry[], testFiles: FileEntry[], projectDir: string): Promise<{
75
+ code: number;
76
+ tests: number;
77
+ }>;
78
+ /**
79
+ * Scan the entire project and produce a structured ProjectScanResult.
80
+ *
81
+ * @param projectDir - Project root directory.
82
+ * @param language - Language from state.json.
83
+ * @param onProgress - Optional progress callback.
84
+ * @returns ProjectScanResult with all scan data.
85
+ */
86
+ export declare function scanProject(projectDir: string, language: string, onProgress?: (message: string) => void): Promise<ProjectScanResult>;
87
+ //# sourceMappingURL=audit-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-scanner.d.ts","sourceRoot":"","sources":["../../src/workflow/audit-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,YAAY,EAEb,MAAM,mBAAmB,CAAC;AAyJ3B;;;;;;;;;GASG;AACH,wBAAsB,0BAA0B,CAC9C,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,EAAE,CAAC,CAoE1B;AA6CD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,aAAa,EACnB,QAAQ,EAAE,YAAY,GAAG,QAAQ,GAAG,OAAO,EAC3C,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,CAAC,CAqExB;AAgDD;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAgB/B;AAMD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,EAAE,CAAC,CAoBnB;AAMD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB,CAAC,CAkDD;AAMD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,aAAa,EAAE,GAC1B,OAAO,CAAC,YAAY,CAAC,CAuFvB;AAMD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,SAAS,EAAE,EACxB,SAAS,EAAE,SAAS,EAAE,EACtB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAe1C;AAkCD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GACrC,OAAO,CAAC,iBAAiB,CAAC,CAoI5B"}