@compilr-dev/agents-coding-python 0.1.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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +40 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +27 -0
  5. package/dist/parser/index.d.ts +6 -0
  6. package/dist/parser/index.d.ts.map +1 -0
  7. package/dist/parser/index.js +5 -0
  8. package/dist/parser/node-types.d.ts +119 -0
  9. package/dist/parser/node-types.d.ts.map +1 -0
  10. package/dist/parser/node-types.js +4 -0
  11. package/dist/parser/python-parser.d.ts +85 -0
  12. package/dist/parser/python-parser.d.ts.map +1 -0
  13. package/dist/parser/python-parser.js +477 -0
  14. package/dist/skills/index.d.ts +26 -0
  15. package/dist/skills/index.d.ts.map +1 -0
  16. package/dist/skills/index.js +36 -0
  17. package/dist/skills/python-best-practices.d.ts +7 -0
  18. package/dist/skills/python-best-practices.d.ts.map +1 -0
  19. package/dist/skills/python-best-practices.js +78 -0
  20. package/dist/skills/python-code-health.d.ts +7 -0
  21. package/dist/skills/python-code-health.d.ts.map +1 -0
  22. package/dist/skills/python-code-health.js +209 -0
  23. package/dist/skills/python-code-structure.d.ts +7 -0
  24. package/dist/skills/python-code-structure.d.ts.map +1 -0
  25. package/dist/skills/python-code-structure.js +155 -0
  26. package/dist/skills/python-dependency-audit.d.ts +7 -0
  27. package/dist/skills/python-dependency-audit.d.ts.map +1 -0
  28. package/dist/skills/python-dependency-audit.js +246 -0
  29. package/dist/skills/python-refactor-impact.d.ts +7 -0
  30. package/dist/skills/python-refactor-impact.d.ts.map +1 -0
  31. package/dist/skills/python-refactor-impact.js +232 -0
  32. package/dist/tools/extract-docstrings.d.ts +70 -0
  33. package/dist/tools/extract-docstrings.d.ts.map +1 -0
  34. package/dist/tools/extract-docstrings.js +575 -0
  35. package/dist/tools/find-dead-code.d.ts +62 -0
  36. package/dist/tools/find-dead-code.d.ts.map +1 -0
  37. package/dist/tools/find-dead-code.js +422 -0
  38. package/dist/tools/find-duplicates.d.ts +65 -0
  39. package/dist/tools/find-duplicates.d.ts.map +1 -0
  40. package/dist/tools/find-duplicates.js +289 -0
  41. package/dist/tools/find-implementations.d.ts +71 -0
  42. package/dist/tools/find-implementations.d.ts.map +1 -0
  43. package/dist/tools/find-implementations.js +342 -0
  44. package/dist/tools/find-patterns.d.ts +71 -0
  45. package/dist/tools/find-patterns.d.ts.map +1 -0
  46. package/dist/tools/find-patterns.js +477 -0
  47. package/dist/tools/find-references.d.ts +66 -0
  48. package/dist/tools/find-references.d.ts.map +1 -0
  49. package/dist/tools/find-references.js +306 -0
  50. package/dist/tools/find-symbol.d.ts +86 -0
  51. package/dist/tools/find-symbol.d.ts.map +1 -0
  52. package/dist/tools/find-symbol.js +414 -0
  53. package/dist/tools/get-call-graph.d.ts +89 -0
  54. package/dist/tools/get-call-graph.d.ts.map +1 -0
  55. package/dist/tools/get-call-graph.js +431 -0
  56. package/dist/tools/get-class-hierarchy.d.ts +38 -0
  57. package/dist/tools/get-class-hierarchy.d.ts.map +1 -0
  58. package/dist/tools/get-class-hierarchy.js +289 -0
  59. package/dist/tools/get-complexity.d.ts +61 -0
  60. package/dist/tools/get-complexity.d.ts.map +1 -0
  61. package/dist/tools/get-complexity.js +384 -0
  62. package/dist/tools/get-dependency-graph.d.ts +85 -0
  63. package/dist/tools/get-dependency-graph.d.ts.map +1 -0
  64. package/dist/tools/get-dependency-graph.js +387 -0
  65. package/dist/tools/get-exports.d.ts +78 -0
  66. package/dist/tools/get-exports.d.ts.map +1 -0
  67. package/dist/tools/get-exports.js +437 -0
  68. package/dist/tools/get-file-structure.d.ts +28 -0
  69. package/dist/tools/get-file-structure.d.ts.map +1 -0
  70. package/dist/tools/get-file-structure.js +186 -0
  71. package/dist/tools/get-imports.d.ts +34 -0
  72. package/dist/tools/get-imports.d.ts.map +1 -0
  73. package/dist/tools/get-imports.js +455 -0
  74. package/dist/tools/get-signature.d.ts +100 -0
  75. package/dist/tools/get-signature.d.ts.map +1 -0
  76. package/dist/tools/get-signature.js +800 -0
  77. package/dist/tools/index.d.ts +55 -0
  78. package/dist/tools/index.d.ts.map +1 -0
  79. package/dist/tools/index.js +75 -0
  80. package/dist/tools/types.d.ts +378 -0
  81. package/dist/tools/types.d.ts.map +1 -0
  82. package/dist/tools/types.js +4 -0
  83. package/package.json +85 -0
@@ -0,0 +1,387 @@
1
+ /**
2
+ * getDependencyGraph Tool
3
+ *
4
+ * Analyze module-level dependencies in Python code.
5
+ * Builds a dependency graph and detects circular dependencies.
6
+ */
7
+ import * as fs from "node:fs/promises";
8
+ import { accessSync } from "node:fs";
9
+ import * as path from "node:path";
10
+ import { defineTool, createSuccessResult, createErrorResult, } from "@compilr-dev/agents";
11
+ import { parseFile, parseImport } from "../parser/python-parser.js";
12
+ // Tool description
13
+ const TOOL_DESCRIPTION = `Analyze module-level dependencies in Python code.
14
+ Returns a dependency graph showing which modules import which other modules.
15
+ Detects circular dependencies and provides dependency statistics.`;
16
+ // Tool input schema
17
+ const TOOL_INPUT_SCHEMA = {
18
+ type: "object",
19
+ properties: {
20
+ path: {
21
+ type: "string",
22
+ description: "Directory or file to analyze",
23
+ },
24
+ includeExternal: {
25
+ type: "boolean",
26
+ description: "Include external package dependencies (default: true)",
27
+ default: true,
28
+ },
29
+ maxDepth: {
30
+ type: "number",
31
+ description: "Maximum depth for directory traversal (default: 10)",
32
+ default: 10,
33
+ },
34
+ },
35
+ required: ["path"],
36
+ };
37
+ // Default exclusions
38
+ const DEFAULT_EXCLUDE = [
39
+ "node_modules",
40
+ "__pycache__",
41
+ ".git",
42
+ "venv",
43
+ ".venv",
44
+ "env",
45
+ "dist",
46
+ "build",
47
+ ".tox",
48
+ ".eggs",
49
+ ];
50
+ /**
51
+ * getDependencyGraph tool
52
+ */
53
+ export const getDependencyGraphTool = defineTool({
54
+ name: "get_dependency_graph_python",
55
+ description: TOOL_DESCRIPTION,
56
+ inputSchema: TOOL_INPUT_SCHEMA,
57
+ execute: executeGetDependencyGraph,
58
+ });
59
+ /**
60
+ * Execute the getDependencyGraph tool
61
+ */
62
+ async function executeGetDependencyGraph(input) {
63
+ const { path: inputPath, includeExternal = true, maxDepth = 10 } = input;
64
+ // Validate input
65
+ if (!inputPath || inputPath.trim().length === 0) {
66
+ return createErrorResult("Path is required");
67
+ }
68
+ try {
69
+ const resolvedPath = path.resolve(inputPath);
70
+ // Check if path exists
71
+ try {
72
+ await fs.access(resolvedPath);
73
+ }
74
+ catch {
75
+ return createErrorResult(`Path not found: ${resolvedPath}`);
76
+ }
77
+ const stats = await fs.stat(resolvedPath);
78
+ const rootPath = stats.isDirectory()
79
+ ? resolvedPath
80
+ : path.dirname(resolvedPath);
81
+ // Collect files to analyze
82
+ const files = stats.isDirectory()
83
+ ? await collectFiles(resolvedPath, maxDepth)
84
+ : [resolvedPath];
85
+ if (files.length === 0) {
86
+ return createSuccessResult({
87
+ root: rootPath,
88
+ modules: [],
89
+ edges: [],
90
+ circularDependencies: [],
91
+ stats: {
92
+ totalModules: 0,
93
+ internalModules: 0,
94
+ externalPackages: 0,
95
+ totalEdges: 0,
96
+ circularDependencies: 0,
97
+ externalPackageList: [],
98
+ },
99
+ });
100
+ }
101
+ // Analyze dependencies
102
+ const result = await analyzeDependencies(files, rootPath, includeExternal);
103
+ return createSuccessResult(result);
104
+ }
105
+ catch (error) {
106
+ const message = error instanceof Error ? error.message : String(error);
107
+ return createErrorResult(`Failed to analyze dependencies: ${message}`);
108
+ }
109
+ }
110
+ /**
111
+ * Collect Python files
112
+ */
113
+ async function collectFiles(dir, maxDepth, currentDepth = 0) {
114
+ if (currentDepth >= maxDepth)
115
+ return [];
116
+ const files = [];
117
+ try {
118
+ const entries = await fs.readdir(dir, { withFileTypes: true });
119
+ for (const entry of entries) {
120
+ const fullPath = path.join(dir, entry.name);
121
+ if (entry.isDirectory()) {
122
+ if (DEFAULT_EXCLUDE.includes(entry.name))
123
+ continue;
124
+ const subFiles = await collectFiles(fullPath, maxDepth, currentDepth + 1);
125
+ files.push(...subFiles);
126
+ }
127
+ else if (entry.isFile()) {
128
+ if (fullPath.endsWith(".py") && !fullPath.endsWith(".pyi")) {
129
+ files.push(fullPath);
130
+ }
131
+ }
132
+ }
133
+ }
134
+ catch {
135
+ // Silently skip directories we can't read
136
+ }
137
+ return files;
138
+ }
139
+ /**
140
+ * Analyze dependencies across files
141
+ */
142
+ async function analyzeDependencies(files, rootPath, includeExternal) {
143
+ const modules = new Map();
144
+ const edges = [];
145
+ const externalPackages = new Set();
146
+ // Track adjacency for cycle detection
147
+ const adjacency = new Map();
148
+ for (const file of files) {
149
+ const relativePath = path.relative(rootPath, file);
150
+ const imports = await extractImports(file);
151
+ // Add this module
152
+ if (!modules.has(relativePath)) {
153
+ modules.set(relativePath, {
154
+ path: relativePath,
155
+ absolutePath: file,
156
+ isExternal: false,
157
+ });
158
+ }
159
+ const moduleDeps = [];
160
+ for (const imp of imports) {
161
+ // Determine if external
162
+ const isExternal = !imp.isRelative;
163
+ if (isExternal) {
164
+ if (!includeExternal)
165
+ continue;
166
+ // Extract package name
167
+ const packageName = imp.module.split(".")[0];
168
+ externalPackages.add(packageName);
169
+ // Add external module node
170
+ if (!modules.has(packageName)) {
171
+ modules.set(packageName, {
172
+ path: packageName,
173
+ absolutePath: packageName,
174
+ isExternal: true,
175
+ packageName,
176
+ });
177
+ }
178
+ edges.push({
179
+ from: relativePath,
180
+ to: packageName,
181
+ importType: imp.isFromImport ? "from_import" : "import",
182
+ symbols: imp.names.map((n) => n.name),
183
+ isRelative: false,
184
+ });
185
+ moduleDeps.push(packageName);
186
+ }
187
+ else {
188
+ // Internal import - resolve path
189
+ const resolvedPath = resolveImportPath(file, imp.module, rootPath);
190
+ if (resolvedPath) {
191
+ const relativeResolved = path.relative(rootPath, resolvedPath);
192
+ // Add target module if not exists
193
+ if (!modules.has(relativeResolved)) {
194
+ modules.set(relativeResolved, {
195
+ path: relativeResolved,
196
+ absolutePath: resolvedPath,
197
+ isExternal: false,
198
+ });
199
+ }
200
+ edges.push({
201
+ from: relativePath,
202
+ to: relativeResolved,
203
+ importType: imp.isFromImport ? "from_import" : "import",
204
+ symbols: imp.names.map((n) => n.name),
205
+ isRelative: imp.isRelative,
206
+ });
207
+ moduleDeps.push(relativeResolved);
208
+ }
209
+ }
210
+ }
211
+ adjacency.set(relativePath, moduleDeps);
212
+ }
213
+ // Detect circular dependencies
214
+ const circularDependencies = detectCircularDependencies(adjacency);
215
+ // Calculate statistics
216
+ const internalModules = Array.from(modules.values()).filter((m) => !m.isExternal);
217
+ const dependencyCounts = new Map();
218
+ const dependentCounts = new Map();
219
+ for (const edge of edges) {
220
+ dependencyCounts.set(edge.from, (dependencyCounts.get(edge.from) ?? 0) + 1);
221
+ dependentCounts.set(edge.to, (dependentCounts.get(edge.to) ?? 0) + 1);
222
+ }
223
+ let mostDependencies;
224
+ let mostDependents;
225
+ for (const [module, count] of dependencyCounts) {
226
+ if (!mostDependencies || count > mostDependencies.count) {
227
+ mostDependencies = { module, count };
228
+ }
229
+ }
230
+ for (const [module, count] of dependentCounts) {
231
+ if (!mostDependents || count > mostDependents.count) {
232
+ mostDependents = { module, count };
233
+ }
234
+ }
235
+ const stats = {
236
+ totalModules: modules.size,
237
+ internalModules: internalModules.length,
238
+ externalPackages: externalPackages.size,
239
+ totalEdges: edges.length,
240
+ circularDependencies: circularDependencies.length,
241
+ externalPackageList: Array.from(externalPackages).sort(),
242
+ mostDependencies,
243
+ mostDependents,
244
+ };
245
+ return {
246
+ root: rootPath,
247
+ modules: Array.from(modules.values()),
248
+ edges,
249
+ circularDependencies,
250
+ stats,
251
+ };
252
+ }
253
+ /**
254
+ * Extract imports from a Python file
255
+ */
256
+ async function extractImports(filePath) {
257
+ const imports = [];
258
+ try {
259
+ const parseResult = await parseFile(filePath);
260
+ const { tree, source } = parseResult;
261
+ for (const child of tree.rootNode.children) {
262
+ if (child.type === "import_statement" ||
263
+ child.type === "import_from_statement") {
264
+ const importInfo = parseImport(child, source);
265
+ imports.push({
266
+ module: importInfo.module,
267
+ isFromImport: importInfo.isFromImport,
268
+ isRelative: importInfo.isRelative,
269
+ names: importInfo.names,
270
+ });
271
+ }
272
+ }
273
+ }
274
+ catch {
275
+ // Silently skip files that can't be parsed
276
+ }
277
+ return imports;
278
+ }
279
+ /**
280
+ * Resolve import path to absolute file path
281
+ */
282
+ function resolveImportPath(fromFile, importModule, _rootPath) {
283
+ const fromDir = path.dirname(fromFile);
284
+ // Handle relative imports (start with .)
285
+ if (importModule.startsWith(".")) {
286
+ // Count leading dots
287
+ let dots = 0;
288
+ while (importModule[dots] === ".") {
289
+ dots++;
290
+ }
291
+ // Go up (dots - 1) directories
292
+ let baseDir = fromDir;
293
+ for (let i = 1; i < dots; i++) {
294
+ baseDir = path.dirname(baseDir);
295
+ }
296
+ // Get remaining module path
297
+ const modulePath = importModule.slice(dots).replace(/\./g, path.sep);
298
+ const basePath = path.join(baseDir, modulePath);
299
+ return tryResolvePath(basePath);
300
+ }
301
+ // Absolute import within project
302
+ const modulePath = importModule.replace(/\./g, path.sep);
303
+ const basePath = path.join(fromDir, modulePath);
304
+ return tryResolvePath(basePath);
305
+ }
306
+ /**
307
+ * Try to resolve a path with various extensions
308
+ */
309
+ function tryResolvePath(basePath) {
310
+ const candidates = [`${basePath}.py`, path.join(basePath, "__init__.py")];
311
+ for (const candidate of candidates) {
312
+ try {
313
+ accessSync(candidate);
314
+ return candidate;
315
+ }
316
+ catch {
317
+ // Continue to next candidate
318
+ }
319
+ }
320
+ return undefined;
321
+ }
322
+ /**
323
+ * Detect circular dependencies using DFS
324
+ */
325
+ function detectCircularDependencies(adjacency) {
326
+ const cycles = [];
327
+ const visited = new Set();
328
+ const recursionStack = new Set();
329
+ const currentPath = [];
330
+ function dfs(node) {
331
+ if (recursionStack.has(node)) {
332
+ // Found a cycle
333
+ const cycleStart = currentPath.indexOf(node);
334
+ if (cycleStart !== -1) {
335
+ const cycle = [...currentPath.slice(cycleStart), node];
336
+ // Avoid duplicate cycles
337
+ const cycleKey = [...cycle].sort().join("->");
338
+ if (!cycles.some((c) => [...c.cycle].sort().join("->") === cycleKey)) {
339
+ cycles.push({
340
+ cycle,
341
+ length: cycle.length - 1,
342
+ });
343
+ }
344
+ }
345
+ return;
346
+ }
347
+ if (visited.has(node)) {
348
+ return;
349
+ }
350
+ visited.add(node);
351
+ recursionStack.add(node);
352
+ currentPath.push(node);
353
+ const deps = adjacency.get(node) ?? [];
354
+ for (const dep of deps) {
355
+ // Only check internal dependencies
356
+ if (adjacency.has(dep)) {
357
+ dfs(dep);
358
+ }
359
+ }
360
+ currentPath.pop();
361
+ recursionStack.delete(node);
362
+ }
363
+ for (const node of adjacency.keys()) {
364
+ if (!visited.has(node)) {
365
+ dfs(node);
366
+ }
367
+ }
368
+ return cycles;
369
+ }
370
+ /**
371
+ * Factory function to create a customized getDependencyGraph tool
372
+ */
373
+ export function createGetDependencyGraphTool(options) {
374
+ const { defaultIncludeExternal = true, defaultMaxDepth = 10 } = options ?? {};
375
+ return defineTool({
376
+ name: "get_dependency_graph_python",
377
+ description: TOOL_DESCRIPTION,
378
+ inputSchema: TOOL_INPUT_SCHEMA,
379
+ execute: async (input) => {
380
+ return executeGetDependencyGraph({
381
+ ...input,
382
+ includeExternal: input.includeExternal ?? defaultIncludeExternal,
383
+ maxDepth: input.maxDepth ?? defaultMaxDepth,
384
+ });
385
+ },
386
+ });
387
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * getExports Tool
3
+ *
4
+ * Get all exports from a Python module.
5
+ * Analyzes __all__ declarations and identifies public API.
6
+ */
7
+ import type { Tool } from "@compilr-dev/agents";
8
+ /**
9
+ * Export kind
10
+ */
11
+ export type ExportKind = "function" | "async_function" | "class" | "variable" | "constant" | "module" | "unknown";
12
+ /**
13
+ * Exported symbol
14
+ */
15
+ export interface ExportedSymbol {
16
+ name: string;
17
+ kind: ExportKind;
18
+ line: number;
19
+ signature?: string;
20
+ docstring?: string;
21
+ isPrivate?: boolean;
22
+ inAll?: boolean;
23
+ }
24
+ /**
25
+ * Re-export info
26
+ */
27
+ export interface ReExport {
28
+ symbols: string[] | "*";
29
+ from: string;
30
+ line: number;
31
+ isRelative?: boolean;
32
+ }
33
+ /**
34
+ * Export statistics
35
+ */
36
+ export interface ExportStats {
37
+ totalExports: number;
38
+ functions: number;
39
+ classes: number;
40
+ variables: number;
41
+ reExports: number;
42
+ hasAll: boolean;
43
+ allCount?: number;
44
+ }
45
+ /**
46
+ * Input for getExports tool
47
+ */
48
+ export interface GetExportsInput {
49
+ /** File to analyze */
50
+ path: string;
51
+ /** Include re-exports from imports (default: true) */
52
+ includeReExports?: boolean;
53
+ /** Include private symbols with _ prefix (default: false) */
54
+ includePrivate?: boolean;
55
+ }
56
+ /**
57
+ * Result of getExports
58
+ */
59
+ export interface GetExportsResult {
60
+ path: string;
61
+ allDeclaration?: string[];
62
+ publicExports: ExportedSymbol[];
63
+ privateSymbols?: ExportedSymbol[];
64
+ reExports?: ReExport[];
65
+ stats: ExportStats;
66
+ }
67
+ /**
68
+ * getExports tool
69
+ */
70
+ export declare const getExportsTool: Tool<GetExportsInput>;
71
+ /**
72
+ * Factory function to create a customized getExports tool
73
+ */
74
+ export declare function createGetExportsTool(options?: {
75
+ defaultIncludeReExports?: boolean;
76
+ defaultIncludePrivate?: boolean;
77
+ }): Tool<GetExportsInput>;
78
+ //# sourceMappingURL=get-exports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-exports.d.ts","sourceRoot":"","sources":["../../src/tools/get-exports.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,IAAI,EAAuB,MAAM,qBAAqB,CAAC;AAQrE;;GAEG;AACH,MAAM,MAAM,UAAU,GAClB,UAAU,GACV,gBAAgB,GAChB,OAAO,GACP,UAAU,GACV,UAAU,GACV,QAAQ,GACR,SAAS,CAAC;AAEd;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6DAA6D;IAC7D,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,EAAE,cAAc,EAAE,CAAC;IAChC,cAAc,CAAC,EAAE,cAAc,EAAE,CAAC;IAClC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,KAAK,EAAE,WAAW,CAAC;CACpB;AA6BD;;GAEG;AACH,eAAO,MAAM,cAAc,uBAKzB,CAAC;AA2bH;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE;IAC7C,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC,GAAG,IAAI,CAAC,eAAe,CAAC,CAexB"}