@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.
- package/LICENSE +21 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/parser/index.d.ts +6 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +5 -0
- package/dist/parser/node-types.d.ts +119 -0
- package/dist/parser/node-types.d.ts.map +1 -0
- package/dist/parser/node-types.js +4 -0
- package/dist/parser/python-parser.d.ts +85 -0
- package/dist/parser/python-parser.d.ts.map +1 -0
- package/dist/parser/python-parser.js +477 -0
- package/dist/skills/index.d.ts +26 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +36 -0
- package/dist/skills/python-best-practices.d.ts +7 -0
- package/dist/skills/python-best-practices.d.ts.map +1 -0
- package/dist/skills/python-best-practices.js +78 -0
- package/dist/skills/python-code-health.d.ts +7 -0
- package/dist/skills/python-code-health.d.ts.map +1 -0
- package/dist/skills/python-code-health.js +209 -0
- package/dist/skills/python-code-structure.d.ts +7 -0
- package/dist/skills/python-code-structure.d.ts.map +1 -0
- package/dist/skills/python-code-structure.js +155 -0
- package/dist/skills/python-dependency-audit.d.ts +7 -0
- package/dist/skills/python-dependency-audit.d.ts.map +1 -0
- package/dist/skills/python-dependency-audit.js +246 -0
- package/dist/skills/python-refactor-impact.d.ts +7 -0
- package/dist/skills/python-refactor-impact.d.ts.map +1 -0
- package/dist/skills/python-refactor-impact.js +232 -0
- package/dist/tools/extract-docstrings.d.ts +70 -0
- package/dist/tools/extract-docstrings.d.ts.map +1 -0
- package/dist/tools/extract-docstrings.js +575 -0
- package/dist/tools/find-dead-code.d.ts +62 -0
- package/dist/tools/find-dead-code.d.ts.map +1 -0
- package/dist/tools/find-dead-code.js +422 -0
- package/dist/tools/find-duplicates.d.ts +65 -0
- package/dist/tools/find-duplicates.d.ts.map +1 -0
- package/dist/tools/find-duplicates.js +289 -0
- package/dist/tools/find-implementations.d.ts +71 -0
- package/dist/tools/find-implementations.d.ts.map +1 -0
- package/dist/tools/find-implementations.js +342 -0
- package/dist/tools/find-patterns.d.ts +71 -0
- package/dist/tools/find-patterns.d.ts.map +1 -0
- package/dist/tools/find-patterns.js +477 -0
- package/dist/tools/find-references.d.ts +66 -0
- package/dist/tools/find-references.d.ts.map +1 -0
- package/dist/tools/find-references.js +306 -0
- package/dist/tools/find-symbol.d.ts +86 -0
- package/dist/tools/find-symbol.d.ts.map +1 -0
- package/dist/tools/find-symbol.js +414 -0
- package/dist/tools/get-call-graph.d.ts +89 -0
- package/dist/tools/get-call-graph.d.ts.map +1 -0
- package/dist/tools/get-call-graph.js +431 -0
- package/dist/tools/get-class-hierarchy.d.ts +38 -0
- package/dist/tools/get-class-hierarchy.d.ts.map +1 -0
- package/dist/tools/get-class-hierarchy.js +289 -0
- package/dist/tools/get-complexity.d.ts +61 -0
- package/dist/tools/get-complexity.d.ts.map +1 -0
- package/dist/tools/get-complexity.js +384 -0
- package/dist/tools/get-dependency-graph.d.ts +85 -0
- package/dist/tools/get-dependency-graph.d.ts.map +1 -0
- package/dist/tools/get-dependency-graph.js +387 -0
- package/dist/tools/get-exports.d.ts +78 -0
- package/dist/tools/get-exports.d.ts.map +1 -0
- package/dist/tools/get-exports.js +437 -0
- package/dist/tools/get-file-structure.d.ts +28 -0
- package/dist/tools/get-file-structure.d.ts.map +1 -0
- package/dist/tools/get-file-structure.js +186 -0
- package/dist/tools/get-imports.d.ts +34 -0
- package/dist/tools/get-imports.d.ts.map +1 -0
- package/dist/tools/get-imports.js +455 -0
- package/dist/tools/get-signature.d.ts +100 -0
- package/dist/tools/get-signature.d.ts.map +1 -0
- package/dist/tools/get-signature.js +800 -0
- package/dist/tools/index.d.ts +55 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +75 -0
- package/dist/tools/types.d.ts +378 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +4 -0
- package/package.json +85 -0
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* getComplexity Tool
|
|
3
|
+
*
|
|
4
|
+
* Calculate cyclomatic and cognitive complexity for Python functions.
|
|
5
|
+
* Identifies complex code that may need refactoring.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from "node:fs/promises";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import { defineTool, createSuccessResult, createErrorResult, } from "@compilr-dev/agents";
|
|
10
|
+
import { parseFile, parseFunction, parseClass, parseDecorators, } from "../parser/python-parser.js";
|
|
11
|
+
// Tool description
|
|
12
|
+
const TOOL_DESCRIPTION = `Calculate cyclomatic and cognitive complexity for Python functions.
|
|
13
|
+
Identifies code that may be hard to understand or maintain.
|
|
14
|
+
Returns complexity metrics and highlights hotspots that may need refactoring.`;
|
|
15
|
+
// Tool input schema
|
|
16
|
+
const TOOL_INPUT_SCHEMA = {
|
|
17
|
+
type: "object",
|
|
18
|
+
properties: {
|
|
19
|
+
path: {
|
|
20
|
+
type: "string",
|
|
21
|
+
description: "File or directory to analyze",
|
|
22
|
+
},
|
|
23
|
+
recursive: {
|
|
24
|
+
type: "boolean",
|
|
25
|
+
description: "Recursively analyze directory (default: false)",
|
|
26
|
+
default: false,
|
|
27
|
+
},
|
|
28
|
+
threshold: {
|
|
29
|
+
type: "number",
|
|
30
|
+
description: "Complexity threshold for warnings (default: 10)",
|
|
31
|
+
default: 10,
|
|
32
|
+
},
|
|
33
|
+
onlyAboveThreshold: {
|
|
34
|
+
type: "boolean",
|
|
35
|
+
description: "Only return items above threshold (default: false)",
|
|
36
|
+
default: false,
|
|
37
|
+
},
|
|
38
|
+
maxFiles: {
|
|
39
|
+
type: "number",
|
|
40
|
+
description: "Maximum files to analyze (default: 50)",
|
|
41
|
+
default: 50,
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
required: ["path"],
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* getComplexity tool - Calculate code complexity
|
|
48
|
+
*/
|
|
49
|
+
export const getComplexityTool = defineTool({
|
|
50
|
+
name: "get_complexity_python",
|
|
51
|
+
description: TOOL_DESCRIPTION,
|
|
52
|
+
inputSchema: TOOL_INPUT_SCHEMA,
|
|
53
|
+
execute: executeGetComplexity,
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* Execute the getComplexity tool
|
|
57
|
+
*/
|
|
58
|
+
async function executeGetComplexity(input) {
|
|
59
|
+
const { path: targetPath, recursive = false, threshold = 10, onlyAboveThreshold = false, maxFiles = 50, } = input;
|
|
60
|
+
const resolvedPath = path.resolve(targetPath);
|
|
61
|
+
try {
|
|
62
|
+
await fs.access(resolvedPath);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return createErrorResult(`Path not found: ${resolvedPath}`);
|
|
66
|
+
}
|
|
67
|
+
const stats = await fs.stat(resolvedPath);
|
|
68
|
+
try {
|
|
69
|
+
const files = [];
|
|
70
|
+
if (stats.isFile()) {
|
|
71
|
+
if (!resolvedPath.endsWith(".py") && !resolvedPath.endsWith(".pyi")) {
|
|
72
|
+
return createErrorResult(`Not a Python file: ${resolvedPath}`);
|
|
73
|
+
}
|
|
74
|
+
const fileResult = await analyzeFileComplexity(resolvedPath, threshold, onlyAboveThreshold);
|
|
75
|
+
files.push(fileResult);
|
|
76
|
+
}
|
|
77
|
+
else if (stats.isDirectory()) {
|
|
78
|
+
const pythonFiles = await collectPythonFiles(resolvedPath, recursive, maxFiles);
|
|
79
|
+
for (const filePath of pythonFiles) {
|
|
80
|
+
const fileResult = await analyzeFileComplexity(filePath, threshold, onlyAboveThreshold);
|
|
81
|
+
if (fileResult.functions.length > 0 || !onlyAboveThreshold) {
|
|
82
|
+
files.push(fileResult);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Calculate summary
|
|
87
|
+
let totalFunctions = 0;
|
|
88
|
+
let totalComplexity = 0;
|
|
89
|
+
let maxComplexity = 0;
|
|
90
|
+
let aboveThreshold = 0;
|
|
91
|
+
const hotspots = [];
|
|
92
|
+
for (const file of files) {
|
|
93
|
+
totalFunctions += file.functions.length;
|
|
94
|
+
for (const func of file.functions) {
|
|
95
|
+
totalComplexity += func.metrics.cyclomatic;
|
|
96
|
+
if (func.metrics.cyclomatic > maxComplexity) {
|
|
97
|
+
maxComplexity = func.metrics.cyclomatic;
|
|
98
|
+
}
|
|
99
|
+
if (func.isComplex) {
|
|
100
|
+
aboveThreshold++;
|
|
101
|
+
}
|
|
102
|
+
hotspots.push({
|
|
103
|
+
name: func.name,
|
|
104
|
+
path: file.path,
|
|
105
|
+
line: func.line,
|
|
106
|
+
cyclomatic: func.metrics.cyclomatic,
|
|
107
|
+
cognitive: func.metrics.cognitive,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Sort hotspots by complexity and take top 5
|
|
112
|
+
hotspots.sort((a, b) => b.cyclomatic - a.cyclomatic);
|
|
113
|
+
const topHotspots = hotspots.slice(0, 5);
|
|
114
|
+
const result = {
|
|
115
|
+
path: resolvedPath,
|
|
116
|
+
files,
|
|
117
|
+
summary: {
|
|
118
|
+
totalFiles: files.length,
|
|
119
|
+
totalFunctions,
|
|
120
|
+
averageComplexity: totalFunctions > 0 ? totalComplexity / totalFunctions : 0,
|
|
121
|
+
maxComplexity,
|
|
122
|
+
aboveThreshold,
|
|
123
|
+
threshold,
|
|
124
|
+
},
|
|
125
|
+
hotspots: topHotspots,
|
|
126
|
+
};
|
|
127
|
+
return createSuccessResult(result);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
131
|
+
return createErrorResult(`Failed to analyze complexity: ${message}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Analyze complexity for a single file
|
|
136
|
+
*/
|
|
137
|
+
async function analyzeFileComplexity(filePath, threshold, onlyAboveThreshold) {
|
|
138
|
+
const parseResult = await parseFile(filePath);
|
|
139
|
+
const { tree, source } = parseResult;
|
|
140
|
+
const functions = [];
|
|
141
|
+
// Analyze top-level functions
|
|
142
|
+
for (const child of tree.rootNode.children) {
|
|
143
|
+
if (child.type === "function_definition" ||
|
|
144
|
+
child.type === "async_function_definition") {
|
|
145
|
+
const funcInfo = parseFunction(child, source);
|
|
146
|
+
const metrics = calculateComplexity(child, source);
|
|
147
|
+
const isComplex = metrics.cyclomatic >= threshold;
|
|
148
|
+
if (!onlyAboveThreshold || isComplex) {
|
|
149
|
+
functions.push({
|
|
150
|
+
name: funcInfo.name,
|
|
151
|
+
path: filePath,
|
|
152
|
+
line: funcInfo.line,
|
|
153
|
+
metrics,
|
|
154
|
+
isComplex,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Decorated functions
|
|
159
|
+
if (child.type === "decorated_definition") {
|
|
160
|
+
const funcNode = child.children.find((c) => c.type === "function_definition" ||
|
|
161
|
+
c.type === "async_function_definition");
|
|
162
|
+
if (funcNode) {
|
|
163
|
+
const decorators = parseDecorators(child, source);
|
|
164
|
+
const funcInfo = parseFunction(funcNode, source, decorators);
|
|
165
|
+
const metrics = calculateComplexity(funcNode, source);
|
|
166
|
+
const isComplex = metrics.cyclomatic >= threshold;
|
|
167
|
+
if (!onlyAboveThreshold || isComplex) {
|
|
168
|
+
functions.push({
|
|
169
|
+
name: funcInfo.name,
|
|
170
|
+
path: filePath,
|
|
171
|
+
line: funcInfo.line,
|
|
172
|
+
metrics,
|
|
173
|
+
isComplex,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Class methods
|
|
179
|
+
if (child.type === "class_definition") {
|
|
180
|
+
const classInfo = parseClass(child, source);
|
|
181
|
+
const body = child.childForFieldName("body");
|
|
182
|
+
if (body) {
|
|
183
|
+
for (const member of body.children) {
|
|
184
|
+
if (member.type === "function_definition" ||
|
|
185
|
+
member.type === "async_function_definition") {
|
|
186
|
+
const funcInfo = parseFunction(member, source);
|
|
187
|
+
const metrics = calculateComplexity(member, source);
|
|
188
|
+
const isComplex = metrics.cyclomatic >= threshold;
|
|
189
|
+
if (!onlyAboveThreshold || isComplex) {
|
|
190
|
+
functions.push({
|
|
191
|
+
name: `${classInfo.name}.${funcInfo.name}`,
|
|
192
|
+
path: filePath,
|
|
193
|
+
line: funcInfo.line,
|
|
194
|
+
metrics,
|
|
195
|
+
isComplex,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (member.type === "decorated_definition") {
|
|
200
|
+
const funcNode = member.children.find((c) => c.type === "function_definition" ||
|
|
201
|
+
c.type === "async_function_definition");
|
|
202
|
+
if (funcNode) {
|
|
203
|
+
const decorators = parseDecorators(member, source);
|
|
204
|
+
const funcInfo = parseFunction(funcNode, source, decorators);
|
|
205
|
+
const metrics = calculateComplexity(funcNode, source);
|
|
206
|
+
const isComplex = metrics.cyclomatic >= threshold;
|
|
207
|
+
if (!onlyAboveThreshold || isComplex) {
|
|
208
|
+
functions.push({
|
|
209
|
+
name: `${classInfo.name}.${funcInfo.name}`,
|
|
210
|
+
path: filePath,
|
|
211
|
+
line: funcInfo.line,
|
|
212
|
+
metrics,
|
|
213
|
+
isComplex,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// Calculate file-level averages
|
|
223
|
+
const totalCyclomatic = functions.reduce((sum, f) => sum + f.metrics.cyclomatic, 0);
|
|
224
|
+
const maxCyclomatic = Math.max(0, ...functions.map((f) => f.metrics.cyclomatic));
|
|
225
|
+
const complexCount = functions.filter((f) => f.isComplex).length;
|
|
226
|
+
return {
|
|
227
|
+
path: filePath,
|
|
228
|
+
functions,
|
|
229
|
+
averageComplexity: functions.length > 0 ? totalCyclomatic / functions.length : 0,
|
|
230
|
+
maxComplexity: maxCyclomatic,
|
|
231
|
+
stats: {
|
|
232
|
+
totalFunctions: functions.length,
|
|
233
|
+
complexFunctions: complexCount,
|
|
234
|
+
simpleAverage: functions.length > 0 ? totalCyclomatic / functions.length : 0,
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Calculate complexity metrics for a function
|
|
240
|
+
*/
|
|
241
|
+
function calculateComplexity(node, _source) {
|
|
242
|
+
let cyclomatic = 1; // Base complexity
|
|
243
|
+
let cognitive = 0;
|
|
244
|
+
let maxNesting = 0;
|
|
245
|
+
let paramCount = 0;
|
|
246
|
+
// Count parameters
|
|
247
|
+
const paramsNode = node.childForFieldName("parameters");
|
|
248
|
+
if (paramsNode) {
|
|
249
|
+
for (const child of paramsNode.children) {
|
|
250
|
+
if (child.type === "identifier" ||
|
|
251
|
+
child.type === "typed_parameter" ||
|
|
252
|
+
child.type === "default_parameter" ||
|
|
253
|
+
child.type === "typed_default_parameter") {
|
|
254
|
+
paramCount++;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// Walk the AST and count complexity contributors
|
|
259
|
+
function walk(n, depth) {
|
|
260
|
+
// Track nesting
|
|
261
|
+
const isNestingConstruct = n.type === "if_statement" ||
|
|
262
|
+
n.type === "for_statement" ||
|
|
263
|
+
n.type === "while_statement" ||
|
|
264
|
+
n.type === "try_statement" ||
|
|
265
|
+
n.type === "with_statement" ||
|
|
266
|
+
n.type === "match_statement";
|
|
267
|
+
if (isNestingConstruct) {
|
|
268
|
+
if (depth > maxNesting) {
|
|
269
|
+
maxNesting = depth;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// Cyclomatic complexity contributors
|
|
273
|
+
switch (n.type) {
|
|
274
|
+
case "if_statement":
|
|
275
|
+
case "elif_clause":
|
|
276
|
+
cyclomatic++;
|
|
277
|
+
cognitive += 1 + depth; // Cognitive adds nesting penalty
|
|
278
|
+
break;
|
|
279
|
+
case "for_statement":
|
|
280
|
+
case "while_statement":
|
|
281
|
+
cyclomatic++;
|
|
282
|
+
cognitive += 1 + depth;
|
|
283
|
+
break;
|
|
284
|
+
case "except_clause":
|
|
285
|
+
cyclomatic++;
|
|
286
|
+
cognitive++;
|
|
287
|
+
break;
|
|
288
|
+
case "conditional_expression": // Ternary
|
|
289
|
+
cyclomatic++;
|
|
290
|
+
cognitive++;
|
|
291
|
+
break;
|
|
292
|
+
case "boolean_operator":
|
|
293
|
+
// and/or add to cyclomatic
|
|
294
|
+
cyclomatic++;
|
|
295
|
+
break;
|
|
296
|
+
case "match_statement":
|
|
297
|
+
cyclomatic++;
|
|
298
|
+
cognitive += 1 + depth;
|
|
299
|
+
break;
|
|
300
|
+
case "case_clause":
|
|
301
|
+
cyclomatic++;
|
|
302
|
+
break;
|
|
303
|
+
case "lambda":
|
|
304
|
+
cognitive++; // Lambdas add cognitive load
|
|
305
|
+
break;
|
|
306
|
+
case "list_comprehension":
|
|
307
|
+
case "dictionary_comprehension":
|
|
308
|
+
case "set_comprehension":
|
|
309
|
+
case "generator_expression":
|
|
310
|
+
cognitive++; // Comprehensions add cognitive load
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
// Recurse into children
|
|
314
|
+
const newDepth = isNestingConstruct ? depth + 1 : depth;
|
|
315
|
+
for (const child of n.children) {
|
|
316
|
+
walk(child, newDepth);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const body = node.childForFieldName("body");
|
|
320
|
+
if (body) {
|
|
321
|
+
walk(body, 0);
|
|
322
|
+
}
|
|
323
|
+
// Calculate lines of code
|
|
324
|
+
const startLine = node.startPosition.row;
|
|
325
|
+
const endLine = node.endPosition.row;
|
|
326
|
+
const linesOfCode = endLine - startLine + 1;
|
|
327
|
+
return {
|
|
328
|
+
cyclomatic,
|
|
329
|
+
cognitive,
|
|
330
|
+
linesOfCode,
|
|
331
|
+
parameters: paramCount,
|
|
332
|
+
nestingDepth: maxNesting,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Collect Python files in a directory
|
|
337
|
+
*/
|
|
338
|
+
async function collectPythonFiles(dir, recursive, maxFiles) {
|
|
339
|
+
const files = [];
|
|
340
|
+
async function walk(currentDir) {
|
|
341
|
+
if (files.length >= maxFiles)
|
|
342
|
+
return;
|
|
343
|
+
const entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
344
|
+
for (const entry of entries) {
|
|
345
|
+
if (files.length >= maxFiles)
|
|
346
|
+
break;
|
|
347
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
348
|
+
if (entry.isDirectory() && recursive) {
|
|
349
|
+
if (entry.name.startsWith(".") ||
|
|
350
|
+
entry.name === "__pycache__" ||
|
|
351
|
+
entry.name === "venv" ||
|
|
352
|
+
entry.name === ".venv" ||
|
|
353
|
+
entry.name === "node_modules") {
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
await walk(fullPath);
|
|
357
|
+
}
|
|
358
|
+
else if (entry.isFile() &&
|
|
359
|
+
(fullPath.endsWith(".py") || fullPath.endsWith(".pyi"))) {
|
|
360
|
+
files.push(fullPath);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
await walk(dir);
|
|
365
|
+
return files;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Factory function to create a customized getComplexity tool
|
|
369
|
+
*/
|
|
370
|
+
export function createGetComplexityTool(options) {
|
|
371
|
+
const { defaultThreshold = 10, defaultRecursive = false } = options ?? {};
|
|
372
|
+
return defineTool({
|
|
373
|
+
name: "get_complexity_python",
|
|
374
|
+
description: TOOL_DESCRIPTION,
|
|
375
|
+
inputSchema: TOOL_INPUT_SCHEMA,
|
|
376
|
+
execute: async (input) => {
|
|
377
|
+
return executeGetComplexity({
|
|
378
|
+
...input,
|
|
379
|
+
threshold: input.threshold ?? defaultThreshold,
|
|
380
|
+
recursive: input.recursive ?? defaultRecursive,
|
|
381
|
+
});
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
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 type { Tool } from "@compilr-dev/agents";
|
|
8
|
+
/**
|
|
9
|
+
* Module node in the dependency graph
|
|
10
|
+
*/
|
|
11
|
+
export interface ModuleNode {
|
|
12
|
+
path: string;
|
|
13
|
+
absolutePath: string;
|
|
14
|
+
isExternal: boolean;
|
|
15
|
+
packageName?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Dependency edge
|
|
19
|
+
*/
|
|
20
|
+
export interface DependencyEdge {
|
|
21
|
+
from: string;
|
|
22
|
+
to: string;
|
|
23
|
+
importType: "import" | "from_import";
|
|
24
|
+
symbols: string[];
|
|
25
|
+
isRelative: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Circular dependency
|
|
29
|
+
*/
|
|
30
|
+
export interface CircularDependency {
|
|
31
|
+
cycle: string[];
|
|
32
|
+
length: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Dependency graph stats
|
|
36
|
+
*/
|
|
37
|
+
export interface DependencyGraphStats {
|
|
38
|
+
totalModules: number;
|
|
39
|
+
internalModules: number;
|
|
40
|
+
externalPackages: number;
|
|
41
|
+
totalEdges: number;
|
|
42
|
+
circularDependencies: number;
|
|
43
|
+
externalPackageList: string[];
|
|
44
|
+
mostDependencies?: {
|
|
45
|
+
module: string;
|
|
46
|
+
count: number;
|
|
47
|
+
};
|
|
48
|
+
mostDependents?: {
|
|
49
|
+
module: string;
|
|
50
|
+
count: number;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Input for getDependencyGraph tool
|
|
55
|
+
*/
|
|
56
|
+
export interface GetDependencyGraphInput {
|
|
57
|
+
/** Directory or file to analyze */
|
|
58
|
+
path: string;
|
|
59
|
+
/** Include external package dependencies (default: true) */
|
|
60
|
+
includeExternal?: boolean;
|
|
61
|
+
/** Maximum depth for directory traversal (default: 10) */
|
|
62
|
+
maxDepth?: number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Result of getDependencyGraph
|
|
66
|
+
*/
|
|
67
|
+
export interface GetDependencyGraphResult {
|
|
68
|
+
root: string;
|
|
69
|
+
modules: ModuleNode[];
|
|
70
|
+
edges: DependencyEdge[];
|
|
71
|
+
circularDependencies: CircularDependency[];
|
|
72
|
+
stats: DependencyGraphStats;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* getDependencyGraph tool
|
|
76
|
+
*/
|
|
77
|
+
export declare const getDependencyGraphTool: Tool<GetDependencyGraphInput>;
|
|
78
|
+
/**
|
|
79
|
+
* Factory function to create a customized getDependencyGraph tool
|
|
80
|
+
*/
|
|
81
|
+
export declare function createGetDependencyGraphTool(options?: {
|
|
82
|
+
defaultIncludeExternal?: boolean;
|
|
83
|
+
defaultMaxDepth?: number;
|
|
84
|
+
}): Tool<GetDependencyGraphInput>;
|
|
85
|
+
//# sourceMappingURL=get-dependency-graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-dependency-graph.d.ts","sourceRoot":"","sources":["../../src/tools/get-dependency-graph.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,OAAO,KAAK,EAAE,IAAI,EAAuB,MAAM,qBAAqB,CAAC;AAGrE;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,QAAQ,GAAG,aAAa,CAAC;IACrC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,gBAAgB,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,cAAc,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACpD;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,oBAAoB,EAAE,kBAAkB,EAAE,CAAC;IAC3C,KAAK,EAAE,oBAAoB,CAAC;CAC7B;AA2CD;;GAEG;AACH,eAAO,MAAM,sBAAsB,+BAKjC,CAAC;AA8YH;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,CAAC,EAAE;IACrD,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GAAG,IAAI,CAAC,uBAAuB,CAAC,CAiBhC"}
|