@planu/cli 0.48.2 → 0.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/config/license-plans.json +2 -1
  2. package/dist/engine/scan-project/cross-module-analyzer.d.ts +3 -0
  3. package/dist/engine/scan-project/cross-module-analyzer.d.ts.map +1 -0
  4. package/dist/engine/scan-project/cross-module-analyzer.js +302 -0
  5. package/dist/engine/scan-project/cross-module-analyzer.js.map +1 -0
  6. package/dist/engine/scan-project/health-scorer.d.ts +3 -0
  7. package/dist/engine/scan-project/health-scorer.d.ts.map +1 -0
  8. package/dist/engine/scan-project/health-scorer.js +142 -0
  9. package/dist/engine/scan-project/health-scorer.js.map +1 -0
  10. package/dist/engine/scan-project/index.d.ts +7 -0
  11. package/dist/engine/scan-project/index.d.ts.map +1 -0
  12. package/dist/engine/scan-project/index.js +231 -0
  13. package/dist/engine/scan-project/index.js.map +1 -0
  14. package/dist/engine/scan-project/module-discoverer.d.ts +3 -0
  15. package/dist/engine/scan-project/module-discoverer.d.ts.map +1 -0
  16. package/dist/engine/scan-project/module-discoverer.js +388 -0
  17. package/dist/engine/scan-project/module-discoverer.js.map +1 -0
  18. package/dist/engine/scan-project/overview-generator.d.ts +3 -0
  19. package/dist/engine/scan-project/overview-generator.d.ts.map +1 -0
  20. package/dist/engine/scan-project/overview-generator.js +218 -0
  21. package/dist/engine/scan-project/overview-generator.js.map +1 -0
  22. package/dist/index.js +2 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/tools/register-scan-tools.d.ts +3 -0
  25. package/dist/tools/register-scan-tools.d.ts.map +1 -0
  26. package/dist/tools/register-scan-tools.js +38 -0
  27. package/dist/tools/register-scan-tools.js.map +1 -0
  28. package/dist/tools/scan-project.d.ts +3 -0
  29. package/dist/tools/scan-project.d.ts.map +1 -0
  30. package/dist/tools/scan-project.js +22 -0
  31. package/dist/tools/scan-project.js.map +1 -0
  32. package/dist/types/index.d.ts +1 -0
  33. package/dist/types/index.d.ts.map +1 -1
  34. package/dist/types/index.js +1 -0
  35. package/dist/types/index.js.map +1 -1
  36. package/dist/types/scan-project.d.ts +97 -0
  37. package/dist/types/scan-project.d.ts.map +1 -0
  38. package/dist/types/scan-project.js +3 -0
  39. package/dist/types/scan-project.js.map +1 -0
  40. package/package.json +1 -1
  41. package/src/config/license-plans.json +2 -1
@@ -148,7 +148,8 @@
148
148
  "registry_publish",
149
149
  "registry_login",
150
150
  "registry_logout",
151
- "registry_whoami"
151
+ "registry_whoami",
152
+ "scan_project"
152
153
  ],
153
154
  "alwaysAllowed": [
154
155
  "activate_license",
@@ -0,0 +1,3 @@
1
+ import type { ModuleAnalysisResult, CrossModuleAnalysis } from '../../types/index.js';
2
+ export declare function analyzeCrossModuleDependencies(results: ModuleAnalysisResult[]): CrossModuleAnalysis;
3
+ //# sourceMappingURL=cross-module-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-module-analyzer.d.ts","sourceRoot":"","sources":["../../../src/engine/scan-project/cross-module-analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EAGpB,MAAM,sBAAsB,CAAC;AAM9B,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,oBAAoB,EAAE,GAC9B,mBAAmB,CAUrB"}
@@ -0,0 +1,302 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Public API
3
+ // ---------------------------------------------------------------------------
4
+ export function analyzeCrossModuleDependencies(results) {
5
+ const successful = results.filter((r) => r.status === 'success');
6
+ const dependencies = buildDependencyGraph(successful);
7
+ const circularDeps = detectCircularDeps(dependencies);
8
+ const antipatterns = detectAntipatterns(successful, dependencies, circularDeps);
9
+ const orphanModules = findOrphanModules(successful, dependencies);
10
+ const duplications = findDuplications(successful);
11
+ return { dependencies, circularDeps, antipatterns, duplications, orphanModules };
12
+ }
13
+ // ---------------------------------------------------------------------------
14
+ // Step 1: Build cross-module dependency graph
15
+ // ---------------------------------------------------------------------------
16
+ function buildDependencyGraph(results) {
17
+ const modulePathMap = buildModulePathMap(results);
18
+ const deps = [];
19
+ const depIndex = new Map();
20
+ for (const result of results) {
21
+ const fromModule = result.module.name;
22
+ const nodes = result.analysis.dependencyGraph.nodes;
23
+ for (const node of nodes) {
24
+ for (const importPath of node.imports) {
25
+ const toModule = resolveImportToModule(importPath, modulePathMap, fromModule);
26
+ if (toModule === null) {
27
+ continue;
28
+ }
29
+ const key = `${fromModule}→${toModule}`;
30
+ const existing = depIndex.get(key);
31
+ if (existing) {
32
+ if (!existing.files.includes(node.file)) {
33
+ existing.files.push(node.file);
34
+ }
35
+ }
36
+ else {
37
+ const dep = {
38
+ from: fromModule,
39
+ to: toModule,
40
+ type: 'import',
41
+ files: [node.file],
42
+ };
43
+ depIndex.set(key, dep);
44
+ deps.push(dep);
45
+ }
46
+ }
47
+ }
48
+ }
49
+ return deps;
50
+ }
51
+ function buildModulePathMap(results) {
52
+ const map = new Map();
53
+ for (const r of results) {
54
+ map.set(r.module.name, normalizePath(r.module.path));
55
+ }
56
+ return map;
57
+ }
58
+ function normalizePath(p) {
59
+ return p.replace(/\\/g, '/').replace(/\/$/, '');
60
+ }
61
+ function resolveImportToModule(importPath, modulePathMap, fromModule) {
62
+ const normalized = normalizePath(importPath);
63
+ for (const [moduleName, modulePath] of modulePathMap) {
64
+ if (moduleName === fromModule) {
65
+ continue;
66
+ }
67
+ // Check if the import path contains the module's directory path
68
+ if (normalized.includes(modulePath) || normalized.includes(`/${moduleName}/`)) {
69
+ return moduleName;
70
+ }
71
+ }
72
+ return null;
73
+ }
74
+ // ---------------------------------------------------------------------------
75
+ // Step 2: Detect circular dependencies via DFS
76
+ // ---------------------------------------------------------------------------
77
+ function detectCircularDeps(deps) {
78
+ const graph = buildAdjacencyMap(deps);
79
+ const cycles = [];
80
+ const visited = new Set();
81
+ const inStack = new Set();
82
+ for (const node of graph.keys()) {
83
+ if (!visited.has(node)) {
84
+ dfsDetectCycles(node, graph, visited, inStack, [], cycles);
85
+ }
86
+ }
87
+ return deduplicateCycles(cycles);
88
+ }
89
+ function buildAdjacencyMap(deps) {
90
+ const graph = new Map();
91
+ for (const dep of deps) {
92
+ if (!graph.has(dep.from)) {
93
+ graph.set(dep.from, []);
94
+ }
95
+ if (!graph.has(dep.to)) {
96
+ graph.set(dep.to, []);
97
+ }
98
+ const fromEdges = graph.get(dep.from);
99
+ if (fromEdges) {
100
+ fromEdges.push(dep.to);
101
+ }
102
+ }
103
+ return graph;
104
+ }
105
+ function dfsDetectCycles(node, graph, visited, inStack, path, cycles) {
106
+ visited.add(node);
107
+ inStack.add(node);
108
+ path.push(node);
109
+ for (const neighbor of graph.get(node) ?? []) {
110
+ if (!visited.has(neighbor)) {
111
+ dfsDetectCycles(neighbor, graph, visited, inStack, path, cycles);
112
+ }
113
+ else if (inStack.has(neighbor)) {
114
+ const cycleStart = path.indexOf(neighbor);
115
+ cycles.push(path.slice(cycleStart));
116
+ }
117
+ }
118
+ path.pop();
119
+ inStack.delete(node);
120
+ }
121
+ function deduplicateCycles(cycles) {
122
+ const seen = new Set();
123
+ const result = [];
124
+ for (const cycle of cycles) {
125
+ const sorted = [...cycle].sort().join('|');
126
+ if (!seen.has(sorted)) {
127
+ seen.add(sorted);
128
+ result.push(cycle);
129
+ }
130
+ }
131
+ return result;
132
+ }
133
+ // ---------------------------------------------------------------------------
134
+ // Step 3: Detect antipatterns
135
+ // ---------------------------------------------------------------------------
136
+ function detectAntipatterns(results, deps, circularDeps) {
137
+ return [
138
+ ...detectCircularAntipatterns(circularDeps),
139
+ ...detectGodModule(results, deps),
140
+ ...detectOrphanAntipatterns(results, deps),
141
+ ...detectInconsistentTestPatterns(results),
142
+ ...detectDuplicatedLogicAntipatterns(results),
143
+ ];
144
+ }
145
+ function detectCircularAntipatterns(circularDeps) {
146
+ return circularDeps.map((cycle) => ({
147
+ description: `Circular dependency detected: ${cycle.join(' → ')}`,
148
+ severity: 'high',
149
+ modules: cycle,
150
+ suggestion: 'Extract shared interfaces or abstractions into a dedicated module to break the cycle.',
151
+ }));
152
+ }
153
+ function detectGodModule(results, deps) {
154
+ if (results.length === 0 || deps.length === 0) {
155
+ return [];
156
+ }
157
+ const incomingCount = countIncomingDeps(results, deps);
158
+ const threshold = results.length * 0.5;
159
+ const antipatterns = [];
160
+ for (const [moduleName, count] of incomingCount) {
161
+ if (count > threshold) {
162
+ antipatterns.push({
163
+ description: `God module: "${moduleName}" receives ${count} of ${deps.length} cross-module dependencies (${Math.round((count / results.length) * 100)}% of modules depend on it).`,
164
+ severity: 'medium',
165
+ modules: [moduleName],
166
+ suggestion: 'Split this module into smaller, focused modules with well-defined responsibilities.',
167
+ });
168
+ }
169
+ }
170
+ return antipatterns;
171
+ }
172
+ function countIncomingDeps(results, deps) {
173
+ const counts = new Map();
174
+ for (const r of results) {
175
+ counts.set(r.module.name, 0);
176
+ }
177
+ for (const dep of deps) {
178
+ counts.set(dep.to, (counts.get(dep.to) ?? 0) + 1);
179
+ }
180
+ return counts;
181
+ }
182
+ function detectOrphanAntipatterns(results, deps) {
183
+ const connectedModules = new Set();
184
+ for (const dep of deps) {
185
+ connectedModules.add(dep.from);
186
+ connectedModules.add(dep.to);
187
+ }
188
+ const orphans = results.map((r) => r.module.name).filter((name) => !connectedModules.has(name));
189
+ return orphans.map((name) => ({
190
+ description: `Orphan module: "${name}" has no cross-module dependencies (neither imports nor is imported).`,
191
+ severity: 'low',
192
+ modules: [name],
193
+ suggestion: 'Verify this module is intentionally standalone or consider integrating it with the project.',
194
+ }));
195
+ }
196
+ function detectInconsistentTestPatterns(results) {
197
+ const withTests = results.filter((r) => r.analysis.testCoverage.testedModules.length > 0);
198
+ const withoutTests = results.filter((r) => r.analysis.testCoverage.testedModules.length === 0);
199
+ if (withTests.length === 0 || withoutTests.length === 0) {
200
+ return [];
201
+ }
202
+ return [
203
+ {
204
+ description: `Inconsistent test coverage: ${withTests.length} modules have tests but ${withoutTests.length} module(s) have none.`,
205
+ severity: 'medium',
206
+ modules: withoutTests.map((r) => r.module.name),
207
+ suggestion: 'Establish a uniform testing policy and add test coverage to untested modules.',
208
+ },
209
+ ];
210
+ }
211
+ function detectDuplicatedLogicAntipatterns(results) {
212
+ const duplications = findDuplications(results);
213
+ return duplications.map((dup) => ({
214
+ description: `Duplicated logic detected: function signature "${dup.signature}" appears in ${dup.modules.length} modules.`,
215
+ severity: 'low',
216
+ modules: dup.modules,
217
+ suggestion: 'Extract duplicated logic into a shared utility module to avoid divergence over time.',
218
+ }));
219
+ }
220
+ // ---------------------------------------------------------------------------
221
+ // Step 4: Find orphan modules (no cross-module connections)
222
+ // ---------------------------------------------------------------------------
223
+ function findOrphanModules(results, deps) {
224
+ const connected = new Set();
225
+ for (const dep of deps) {
226
+ connected.add(dep.from);
227
+ connected.add(dep.to);
228
+ }
229
+ return results.map((r) => r.module.name).filter((name) => !connected.has(name));
230
+ }
231
+ // ---------------------------------------------------------------------------
232
+ // Step 5: Find duplications via function name similarity
233
+ // ---------------------------------------------------------------------------
234
+ function findDuplications(results) {
235
+ const functionsByModule = extractFunctionNames(results);
236
+ const allNames = Array.from(new Set(functionsByModule.flatMap(({ names }) => names)));
237
+ const duplications = [];
238
+ const reported = new Set();
239
+ for (let i = 0; i < allNames.length; i++) {
240
+ const nameA = allNames[i] ?? '';
241
+ if (nameA === '' || reported.has(nameA)) {
242
+ continue;
243
+ }
244
+ const cluster = [nameA];
245
+ for (let j = i + 1; j < allNames.length; j++) {
246
+ const nameB = allNames[j] ?? '';
247
+ if (!reported.has(nameB) && stringSimilarity(nameA, nameB) >= 0.8) {
248
+ cluster.push(nameB);
249
+ }
250
+ }
251
+ if (cluster.length < 2) {
252
+ continue;
253
+ }
254
+ const modulesWithCluster = functionsByModule
255
+ .filter(({ names }) => cluster.some((c) => names.includes(c)))
256
+ .map(({ module }) => module);
257
+ if (modulesWithCluster.length >= 2) {
258
+ cluster.forEach((n) => reported.add(n));
259
+ duplications.push({ signature: nameA, modules: modulesWithCluster });
260
+ }
261
+ }
262
+ return duplications;
263
+ }
264
+ function extractFunctionNames(results) {
265
+ return results.map((r) => ({
266
+ module: r.module.name,
267
+ names: r.analysis.complexityMetrics.flatMap((m) => m.hotspots.map((h) => h.name)),
268
+ }));
269
+ }
270
+ /**
271
+ * Character overlap ratio similarity (0..1).
272
+ * Counts shared characters relative to the longer string.
273
+ */
274
+ function stringSimilarity(a, b) {
275
+ if (a === b) {
276
+ return 1;
277
+ }
278
+ const longer = a.length >= b.length ? a : b;
279
+ const shorter = a.length < b.length ? a : b;
280
+ if (longer.length === 0) {
281
+ return 1;
282
+ }
283
+ let matches = 0;
284
+ const usedIndices = new Set();
285
+ for (const char of shorter) {
286
+ const idx = findUnusedIndex(longer, char, usedIndices);
287
+ if (idx !== -1) {
288
+ matches++;
289
+ usedIndices.add(idx);
290
+ }
291
+ }
292
+ return matches / longer.length;
293
+ }
294
+ function findUnusedIndex(str, char, usedIndices) {
295
+ for (let i = 0; i < str.length; i++) {
296
+ if (str.charAt(i) === char && !usedIndices.has(i)) {
297
+ return i;
298
+ }
299
+ }
300
+ return -1;
301
+ }
302
+ //# sourceMappingURL=cross-module-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-module-analyzer.js","sourceRoot":"","sources":["../../../src/engine/scan-project/cross-module-analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ModuleAnalysisResult, CrossModuleAnalysis, ScanHealthScore } from '../../types/scan-project.js';
2
+ export declare function calculateProjectHealth(moduleResults: ModuleAnalysisResult[], crossModuleAnalysis: CrossModuleAnalysis): ScanHealthScore;
3
+ //# sourceMappingURL=health-scorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-scorer.d.ts","sourceRoot":"","sources":["../../../src/engine/scan-project/health-scorer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EAGhB,MAAM,6BAA6B,CAAC;AA0JrC,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,oBAAoB,EAAE,EACrC,mBAAmB,EAAE,mBAAmB,GACvC,eAAe,CAoBjB"}
@@ -0,0 +1,142 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Helpers — one per dimension (keeps cyclomatic complexity ≤ 15)
3
+ // ---------------------------------------------------------------------------
4
+ function clamp(value) {
5
+ return Math.max(0, Math.min(100, value));
6
+ }
7
+ function calcTestCoverageScore(modules) {
8
+ const successful = modules.filter((m) => m.status === 'success');
9
+ if (successful.length === 0) {
10
+ return 0;
11
+ }
12
+ const totalRatio = successful.reduce((sum, m) => sum + m.analysis.testCoverage.testToSourceRatio, 0);
13
+ const avgRatio = totalRatio / successful.length;
14
+ return clamp(avgRatio * 100);
15
+ }
16
+ function calcTechDebtScore(modules) {
17
+ const successful = modules.filter((m) => m.status === 'success');
18
+ if (successful.length === 0) {
19
+ return 100;
20
+ }
21
+ let totalHotspots = 0;
22
+ let totalFiles = 0;
23
+ for (const m of successful) {
24
+ for (const metric of m.analysis.complexityMetrics) {
25
+ totalFiles++;
26
+ if (metric.avgComplexity > 10) {
27
+ totalHotspots++;
28
+ }
29
+ }
30
+ }
31
+ if (totalFiles === 0) {
32
+ return 100;
33
+ }
34
+ const density = totalHotspots / totalFiles;
35
+ return clamp(100 - density * 500);
36
+ }
37
+ function calcArchConsistencyScore(modules, cross) {
38
+ const successful = modules.filter((m) => m.status === 'success');
39
+ let score = 100;
40
+ if (successful.length > 1) {
41
+ // Inconsistency 1: test presence varies across modules
42
+ const withTests = successful.filter((m) => m.analysis.testCoverage.testedModules.length > 0);
43
+ const allHaveTests = withTests.length === successful.length;
44
+ const noneHaveTests = withTests.length === 0;
45
+ if (!allHaveTests && !noneHaveTests) {
46
+ score -= 15;
47
+ }
48
+ // Inconsistency 2: config presence varies across modules
49
+ const withConfig = successful.filter((m) => m.analysis.configAnalysis.configFiles.length > 0);
50
+ const allHaveConfig = withConfig.length === successful.length;
51
+ const noneHaveConfig = withConfig.length === 0;
52
+ if (!allHaveConfig && !noneHaveConfig) {
53
+ score -= 15;
54
+ }
55
+ // Inconsistency 3: high std deviation in avg complexity across modules
56
+ const complexities = successful.map((m) => {
57
+ const metrics = m.analysis.complexityMetrics;
58
+ if (metrics.length === 0) {
59
+ return 0;
60
+ }
61
+ return metrics.reduce((s, c) => s + c.avgComplexity, 0) / metrics.length;
62
+ });
63
+ const mean = complexities.reduce((s, v) => s + v, 0) / complexities.length;
64
+ const variance = complexities.reduce((s, v) => s + (v - mean) ** 2, 0) / complexities.length;
65
+ const stdDev = Math.sqrt(variance);
66
+ if (stdDev > 5) {
67
+ score -= 15;
68
+ }
69
+ }
70
+ // Penalise antipatterns from cross-module analysis
71
+ for (const ap of cross.antipatterns) {
72
+ if (ap.severity === 'medium') {
73
+ score -= 10;
74
+ }
75
+ else if (ap.severity === 'high' || ap.severity === 'critical') {
76
+ score -= 20;
77
+ }
78
+ }
79
+ return clamp(score);
80
+ }
81
+ function calcDepHealthScore(modules, cross) {
82
+ let score = 100;
83
+ // Circular dependency cycles
84
+ score -= cross.circularDeps.length * 25;
85
+ // Orphan modules
86
+ score -= cross.orphanModules.length * 5;
87
+ // God module detection: any module where >50% of other modules depend on it
88
+ const totalModules = modules.length;
89
+ if (totalModules > 1) {
90
+ const incomingCount = new Map();
91
+ for (const dep of cross.dependencies) {
92
+ incomingCount.set(dep.to, (incomingCount.get(dep.to) ?? 0) + 1);
93
+ }
94
+ for (const count of incomingCount.values()) {
95
+ if (count / totalModules > 0.5) {
96
+ score -= 10;
97
+ break; // penalise once even if multiple god modules exist
98
+ }
99
+ }
100
+ }
101
+ return clamp(score);
102
+ }
103
+ // ---------------------------------------------------------------------------
104
+ // Grade mapping
105
+ // ---------------------------------------------------------------------------
106
+ function deriveGrade(score) {
107
+ if (score >= 80) {
108
+ return 'A';
109
+ }
110
+ if (score >= 60) {
111
+ return 'B';
112
+ }
113
+ if (score >= 40) {
114
+ return 'C';
115
+ }
116
+ if (score >= 20) {
117
+ return 'D';
118
+ }
119
+ return 'F';
120
+ }
121
+ // ---------------------------------------------------------------------------
122
+ // Public API
123
+ // ---------------------------------------------------------------------------
124
+ export function calculateProjectHealth(moduleResults, crossModuleAnalysis) {
125
+ const testCoverage = calcTestCoverageScore(moduleResults);
126
+ const techDebt = calcTechDebtScore(moduleResults);
127
+ const archConsistency = calcArchConsistencyScore(moduleResults, crossModuleAnalysis);
128
+ const depHealth = calcDepHealthScore(moduleResults, crossModuleAnalysis);
129
+ const breakdown = {
130
+ testCoverage,
131
+ techDebt,
132
+ archConsistency,
133
+ depHealth,
134
+ };
135
+ const score = Math.round((testCoverage + techDebt + archConsistency + depHealth) / 4);
136
+ return {
137
+ score,
138
+ breakdown,
139
+ grade: deriveGrade(score),
140
+ };
141
+ }
142
+ //# sourceMappingURL=health-scorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-scorer.js","sourceRoot":"","sources":["../../../src/engine/scan-project/health-scorer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ScanProjectInput, ScanProjectOutput } from '../../types/index.js';
2
+ export { discoverModules } from './module-discoverer.js';
3
+ export { analyzeCrossModuleDependencies } from './cross-module-analyzer.js';
4
+ export { calculateProjectHealth } from './health-scorer.js';
5
+ export { generateProjectOverview } from './overview-generator.js';
6
+ export declare function scanProject(input: ScanProjectInput): Promise<ScanProjectOutput>;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/scan-project/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAGV,gBAAgB,EAChB,iBAAiB,EAKlB,MAAM,sBAAsB,CAAC;AAS9B,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,8BAA8B,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAwNlE,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA4CrF"}