@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,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* getCallGraph Tool
|
|
3
|
+
*
|
|
4
|
+
* Analyze function call relationships in Python code.
|
|
5
|
+
* Returns a call graph showing what functions call what.
|
|
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, } from "../parser/python-parser.js";
|
|
11
|
+
// Tool description
|
|
12
|
+
const TOOL_DESCRIPTION = `Analyze function call relationships in Python code.
|
|
13
|
+
Returns a call graph showing which functions call which other functions.
|
|
14
|
+
Use this to understand code flow, dependencies, and refactoring impact.`;
|
|
15
|
+
// Tool input schema
|
|
16
|
+
const TOOL_INPUT_SCHEMA = {
|
|
17
|
+
type: "object",
|
|
18
|
+
properties: {
|
|
19
|
+
path: {
|
|
20
|
+
type: "string",
|
|
21
|
+
description: "File to analyze",
|
|
22
|
+
},
|
|
23
|
+
functionName: {
|
|
24
|
+
type: "string",
|
|
25
|
+
description: "Specific function to analyze (optional)",
|
|
26
|
+
},
|
|
27
|
+
direction: {
|
|
28
|
+
type: "string",
|
|
29
|
+
enum: ["callers", "callees", "both"],
|
|
30
|
+
description: "Direction: 'callers' | 'callees' | 'both' (default: 'both')",
|
|
31
|
+
},
|
|
32
|
+
maxDepth: {
|
|
33
|
+
type: "number",
|
|
34
|
+
description: "Maximum depth to traverse (default: 2)",
|
|
35
|
+
default: 2,
|
|
36
|
+
},
|
|
37
|
+
includeExternal: {
|
|
38
|
+
type: "boolean",
|
|
39
|
+
description: "Include external package calls (default: false)",
|
|
40
|
+
default: false,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
required: ["path"],
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* getCallGraph tool
|
|
47
|
+
*/
|
|
48
|
+
export const getCallGraphTool = defineTool({
|
|
49
|
+
name: "get_call_graph_python",
|
|
50
|
+
description: TOOL_DESCRIPTION,
|
|
51
|
+
inputSchema: TOOL_INPUT_SCHEMA,
|
|
52
|
+
execute: executeGetCallGraph,
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* Execute the getCallGraph tool
|
|
56
|
+
*/
|
|
57
|
+
async function executeGetCallGraph(input) {
|
|
58
|
+
const { path: inputPath, functionName, direction = "both", maxDepth = 2, includeExternal = false, } = input;
|
|
59
|
+
// Validate input
|
|
60
|
+
if (!inputPath || inputPath.trim().length === 0) {
|
|
61
|
+
return createErrorResult("Path is required");
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const resolvedPath = path.resolve(inputPath);
|
|
65
|
+
// Check if path exists
|
|
66
|
+
try {
|
|
67
|
+
await fs.access(resolvedPath);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return createErrorResult(`Path not found: ${resolvedPath}`);
|
|
71
|
+
}
|
|
72
|
+
const stats = await fs.stat(resolvedPath);
|
|
73
|
+
if (!stats.isFile()) {
|
|
74
|
+
return createErrorResult(`Path must be a file: ${resolvedPath}`);
|
|
75
|
+
}
|
|
76
|
+
if (!resolvedPath.endsWith(".py")) {
|
|
77
|
+
return createErrorResult("File must be a Python file (.py)");
|
|
78
|
+
}
|
|
79
|
+
// Analyze the file
|
|
80
|
+
const result = await analyzeCallGraph(resolvedPath, functionName, direction, maxDepth, includeExternal);
|
|
81
|
+
return createSuccessResult(result);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
85
|
+
return createErrorResult(`Failed to analyze call graph: ${message}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Analyze call graph for a file
|
|
90
|
+
*/
|
|
91
|
+
async function analyzeCallGraph(filePath, functionName, direction, maxDepth, includeExternal) {
|
|
92
|
+
const parseResult = await parseFile(filePath);
|
|
93
|
+
const { tree, source } = parseResult;
|
|
94
|
+
// Find all functions in the file
|
|
95
|
+
const functions = extractFunctions(tree.rootNode, source, filePath);
|
|
96
|
+
// Build the call graph
|
|
97
|
+
const graphNodes = new Map();
|
|
98
|
+
let rootNode;
|
|
99
|
+
let externalCallCount = 0;
|
|
100
|
+
// If functionName is specified, find it
|
|
101
|
+
if (functionName) {
|
|
102
|
+
const targetFunc = functions.find((f) => f.node.name === functionName);
|
|
103
|
+
if (!targetFunc) {
|
|
104
|
+
return {
|
|
105
|
+
graph: [],
|
|
106
|
+
stats: {
|
|
107
|
+
totalFunctions: 0,
|
|
108
|
+
totalCalls: 0,
|
|
109
|
+
maxDepthReached: 0,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
rootNode = targetFunc.node;
|
|
114
|
+
}
|
|
115
|
+
// Analyze callees (what each function calls)
|
|
116
|
+
if (direction === "callees" || direction === "both") {
|
|
117
|
+
const functionsToAnalyze = functionName
|
|
118
|
+
? functions.filter((f) => f.node.name === functionName)
|
|
119
|
+
: functions;
|
|
120
|
+
for (const func of functionsToAnalyze) {
|
|
121
|
+
const callees = extractCallees(func, functions, source, includeExternal);
|
|
122
|
+
let graphNode = graphNodes.get(func.node.name);
|
|
123
|
+
if (!graphNode) {
|
|
124
|
+
graphNode = {
|
|
125
|
+
function: func.node,
|
|
126
|
+
calls: [],
|
|
127
|
+
calledBy: [],
|
|
128
|
+
};
|
|
129
|
+
graphNodes.set(func.node.name, graphNode);
|
|
130
|
+
}
|
|
131
|
+
graphNode.calls = callees;
|
|
132
|
+
if (includeExternal) {
|
|
133
|
+
externalCallCount += callees.filter((c) => c.function.path === "external").length;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Analyze callers (what calls each function)
|
|
138
|
+
if (direction === "callers" || direction === "both") {
|
|
139
|
+
const functionsToAnalyze = functionName
|
|
140
|
+
? functions.filter((f) => f.node.name === functionName)
|
|
141
|
+
: functions;
|
|
142
|
+
for (const func of functionsToAnalyze) {
|
|
143
|
+
const callers = findCallersInFile(func.node.name, functions, source, filePath);
|
|
144
|
+
let graphNode = graphNodes.get(func.node.name);
|
|
145
|
+
if (!graphNode) {
|
|
146
|
+
graphNode = {
|
|
147
|
+
function: func.node,
|
|
148
|
+
calls: [],
|
|
149
|
+
calledBy: [],
|
|
150
|
+
};
|
|
151
|
+
graphNodes.set(func.node.name, graphNode);
|
|
152
|
+
}
|
|
153
|
+
graphNode.calledBy = callers;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Calculate statistics
|
|
157
|
+
const graph = Array.from(graphNodes.values());
|
|
158
|
+
const totalCalls = graph.reduce((sum, node) => sum + node.calls.length, 0);
|
|
159
|
+
const callGraphStats = {
|
|
160
|
+
totalFunctions: graph.length,
|
|
161
|
+
totalCalls,
|
|
162
|
+
maxDepthReached: Math.min(maxDepth, 1),
|
|
163
|
+
externalCalls: includeExternal ? externalCallCount : undefined,
|
|
164
|
+
};
|
|
165
|
+
return {
|
|
166
|
+
root: rootNode,
|
|
167
|
+
graph,
|
|
168
|
+
stats: callGraphStats,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Extract all functions from an AST
|
|
173
|
+
*/
|
|
174
|
+
function extractFunctions(rootNode, source, filePath) {
|
|
175
|
+
const functions = [];
|
|
176
|
+
function visit(node, className) {
|
|
177
|
+
// Function definitions
|
|
178
|
+
if (node.type === "function_definition" ||
|
|
179
|
+
node.type === "async_function_definition") {
|
|
180
|
+
const funcInfo = parseFunction(node, source);
|
|
181
|
+
const isAsync = node.type === "async_function_definition";
|
|
182
|
+
functions.push({
|
|
183
|
+
node: {
|
|
184
|
+
name: funcInfo.name,
|
|
185
|
+
path: filePath,
|
|
186
|
+
line: funcInfo.line,
|
|
187
|
+
column: node.startPosition.column + 1,
|
|
188
|
+
className,
|
|
189
|
+
async: isAsync,
|
|
190
|
+
},
|
|
191
|
+
astNode: node,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
// Class definitions - extract methods
|
|
195
|
+
if (node.type === "class_definition") {
|
|
196
|
+
const classInfo = parseClass(node, source);
|
|
197
|
+
const body = node.childForFieldName("body");
|
|
198
|
+
if (body) {
|
|
199
|
+
for (const member of body.children) {
|
|
200
|
+
if (member.type === "function_definition" ||
|
|
201
|
+
member.type === "async_function_definition") {
|
|
202
|
+
const methodInfo = parseFunction(member, source);
|
|
203
|
+
const isAsync = member.type === "async_function_definition";
|
|
204
|
+
functions.push({
|
|
205
|
+
node: {
|
|
206
|
+
name: methodInfo.name,
|
|
207
|
+
path: filePath,
|
|
208
|
+
line: methodInfo.line,
|
|
209
|
+
column: member.startPosition.column + 1,
|
|
210
|
+
className: classInfo.name,
|
|
211
|
+
async: isAsync,
|
|
212
|
+
},
|
|
213
|
+
astNode: member,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
// Decorated methods
|
|
217
|
+
if (member.type === "decorated_definition") {
|
|
218
|
+
const funcNode = member.children.find((c) => c.type === "function_definition" ||
|
|
219
|
+
c.type === "async_function_definition");
|
|
220
|
+
if (funcNode) {
|
|
221
|
+
const methodInfo = parseFunction(funcNode, source);
|
|
222
|
+
const isAsync = funcNode.type === "async_function_definition";
|
|
223
|
+
functions.push({
|
|
224
|
+
node: {
|
|
225
|
+
name: methodInfo.name,
|
|
226
|
+
path: filePath,
|
|
227
|
+
line: methodInfo.line,
|
|
228
|
+
column: funcNode.startPosition.column + 1,
|
|
229
|
+
className: classInfo.name,
|
|
230
|
+
async: isAsync,
|
|
231
|
+
},
|
|
232
|
+
astNode: funcNode,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Decorated function definitions
|
|
240
|
+
if (node.type === "decorated_definition") {
|
|
241
|
+
const funcNode = node.children.find((c) => c.type === "function_definition" ||
|
|
242
|
+
c.type === "async_function_definition");
|
|
243
|
+
if (funcNode) {
|
|
244
|
+
const funcInfo = parseFunction(funcNode, source);
|
|
245
|
+
const isAsync = funcNode.type === "async_function_definition";
|
|
246
|
+
functions.push({
|
|
247
|
+
node: {
|
|
248
|
+
name: funcInfo.name,
|
|
249
|
+
path: filePath,
|
|
250
|
+
line: funcInfo.line,
|
|
251
|
+
column: funcNode.startPosition.column + 1,
|
|
252
|
+
className,
|
|
253
|
+
async: isAsync,
|
|
254
|
+
},
|
|
255
|
+
astNode: funcNode,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// Recurse for nested functions (but not into class methods which are handled separately)
|
|
260
|
+
if (node.type !== "class_definition") {
|
|
261
|
+
for (const child of node.children) {
|
|
262
|
+
visit(child, className);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
visit(rootNode);
|
|
267
|
+
return functions;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Extract callees (functions called by a function)
|
|
271
|
+
*/
|
|
272
|
+
function extractCallees(func, allFunctions, source, includeExternal) {
|
|
273
|
+
const callCounts = new Map();
|
|
274
|
+
const bodyNode = func.astNode.childForFieldName("body");
|
|
275
|
+
if (!bodyNode)
|
|
276
|
+
return [];
|
|
277
|
+
function visit(node) {
|
|
278
|
+
if (node.type === "call") {
|
|
279
|
+
const callInfo = extractCallInfo(node, allFunctions, source, includeExternal);
|
|
280
|
+
if (callInfo) {
|
|
281
|
+
const key = `${callInfo.function.name}:${callInfo.function.path}`;
|
|
282
|
+
const existing = callCounts.get(key);
|
|
283
|
+
if (existing) {
|
|
284
|
+
existing.count++;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
callCounts.set(key, callInfo);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
for (const child of node.children) {
|
|
292
|
+
visit(child);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
visit(bodyNode);
|
|
296
|
+
return Array.from(callCounts.values());
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Extract call info from a call expression
|
|
300
|
+
*/
|
|
301
|
+
function extractCallInfo(node, allFunctions, _source, includeExternal) {
|
|
302
|
+
const functionNode = node.childForFieldName("function");
|
|
303
|
+
if (!functionNode)
|
|
304
|
+
return null;
|
|
305
|
+
let funcName;
|
|
306
|
+
let callType = "direct";
|
|
307
|
+
let className;
|
|
308
|
+
// Simple function call: func_name()
|
|
309
|
+
if (functionNode.type === "identifier") {
|
|
310
|
+
funcName = functionNode.text;
|
|
311
|
+
}
|
|
312
|
+
// Method call: obj.method() or self.method()
|
|
313
|
+
else if (functionNode.type === "attribute") {
|
|
314
|
+
const attr = functionNode.childForFieldName("attribute");
|
|
315
|
+
const obj = functionNode.childForFieldName("object");
|
|
316
|
+
if (attr) {
|
|
317
|
+
funcName = attr.text;
|
|
318
|
+
callType = "method";
|
|
319
|
+
if (obj?.type === "identifier") {
|
|
320
|
+
const objName = obj.text;
|
|
321
|
+
if (objName !== "self" && objName !== "cls") {
|
|
322
|
+
className = objName;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (!funcName)
|
|
328
|
+
return null;
|
|
329
|
+
// Check if it's a known function in the file
|
|
330
|
+
const knownFunc = allFunctions.find((f) => f.node.name === funcName);
|
|
331
|
+
if (knownFunc) {
|
|
332
|
+
return {
|
|
333
|
+
function: knownFunc.node,
|
|
334
|
+
callLine: node.startPosition.row + 1,
|
|
335
|
+
callColumn: node.startPosition.column + 1,
|
|
336
|
+
type: callType,
|
|
337
|
+
count: 1,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
// External call (not in this file)
|
|
341
|
+
if (includeExternal) {
|
|
342
|
+
return {
|
|
343
|
+
function: {
|
|
344
|
+
name: funcName,
|
|
345
|
+
path: "external",
|
|
346
|
+
line: 0,
|
|
347
|
+
className,
|
|
348
|
+
},
|
|
349
|
+
callLine: node.startPosition.row + 1,
|
|
350
|
+
callColumn: node.startPosition.column + 1,
|
|
351
|
+
type: callType,
|
|
352
|
+
count: 1,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Find callers of a function within the same file
|
|
359
|
+
*/
|
|
360
|
+
function findCallersInFile(targetFuncName, allFunctions, _source, _filePath) {
|
|
361
|
+
const callerCounts = new Map();
|
|
362
|
+
for (const func of allFunctions) {
|
|
363
|
+
// Skip the function itself
|
|
364
|
+
if (func.node.name === targetFuncName)
|
|
365
|
+
continue;
|
|
366
|
+
const bodyNode = func.astNode.childForFieldName("body");
|
|
367
|
+
if (!bodyNode)
|
|
368
|
+
continue;
|
|
369
|
+
let callsTarget = false;
|
|
370
|
+
let callLine = 0;
|
|
371
|
+
let callColumn = 0;
|
|
372
|
+
let callCount = 0;
|
|
373
|
+
function visit(node) {
|
|
374
|
+
if (node.type === "call") {
|
|
375
|
+
const functionNode = node.childForFieldName("function");
|
|
376
|
+
let calledName;
|
|
377
|
+
if (functionNode?.type === "identifier") {
|
|
378
|
+
calledName = functionNode.text;
|
|
379
|
+
}
|
|
380
|
+
else if (functionNode?.type === "attribute") {
|
|
381
|
+
const attr = functionNode.childForFieldName("attribute");
|
|
382
|
+
if (attr) {
|
|
383
|
+
calledName = attr.text;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
if (calledName === targetFuncName) {
|
|
387
|
+
callsTarget = true;
|
|
388
|
+
callCount++;
|
|
389
|
+
if (callLine === 0) {
|
|
390
|
+
callLine = node.startPosition.row + 1;
|
|
391
|
+
callColumn = node.startPosition.column + 1;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
for (const child of node.children) {
|
|
396
|
+
visit(child);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
visit(bodyNode);
|
|
400
|
+
if (callsTarget) {
|
|
401
|
+
const key = func.node.name;
|
|
402
|
+
callerCounts.set(key, {
|
|
403
|
+
function: func.node,
|
|
404
|
+
callLine,
|
|
405
|
+
callColumn,
|
|
406
|
+
type: "direct",
|
|
407
|
+
count: callCount,
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return Array.from(callerCounts.values());
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Factory function to create a customized getCallGraph tool
|
|
415
|
+
*/
|
|
416
|
+
export function createGetCallGraphTool(options) {
|
|
417
|
+
const { defaultDirection = "both", defaultMaxDepth = 2, defaultIncludeExternal = false, } = options ?? {};
|
|
418
|
+
return defineTool({
|
|
419
|
+
name: "get_call_graph_python",
|
|
420
|
+
description: TOOL_DESCRIPTION,
|
|
421
|
+
inputSchema: TOOL_INPUT_SCHEMA,
|
|
422
|
+
execute: async (input) => {
|
|
423
|
+
return executeGetCallGraph({
|
|
424
|
+
...input,
|
|
425
|
+
direction: input.direction ?? defaultDirection,
|
|
426
|
+
maxDepth: input.maxDepth ?? defaultMaxDepth,
|
|
427
|
+
includeExternal: input.includeExternal ?? defaultIncludeExternal,
|
|
428
|
+
});
|
|
429
|
+
},
|
|
430
|
+
});
|
|
431
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* getClassHierarchy Tool
|
|
3
|
+
*
|
|
4
|
+
* Analyze class inheritance hierarchy in Python codebases.
|
|
5
|
+
* Finds parent classes (ancestors) and child classes (descendants).
|
|
6
|
+
*/
|
|
7
|
+
import type { Tool } from "@compilr-dev/agents";
|
|
8
|
+
/**
|
|
9
|
+
* Direction for hierarchy traversal
|
|
10
|
+
*/
|
|
11
|
+
export type HierarchyDirection = "ancestors" | "descendants" | "both";
|
|
12
|
+
/**
|
|
13
|
+
* Input for getClassHierarchy tool
|
|
14
|
+
*/
|
|
15
|
+
export interface GetClassHierarchyInput {
|
|
16
|
+
/** Class name to analyze */
|
|
17
|
+
name: string;
|
|
18
|
+
/** File where the class is defined (improves accuracy) */
|
|
19
|
+
file?: string;
|
|
20
|
+
/** Direction: 'ancestors' | 'descendants' | 'both' (default: 'both') */
|
|
21
|
+
direction?: HierarchyDirection;
|
|
22
|
+
/** Maximum depth to traverse (default: 5) */
|
|
23
|
+
maxDepth?: number;
|
|
24
|
+
/** Scope for searching descendants */
|
|
25
|
+
scope?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* getClassHierarchy tool - Analyze class inheritance
|
|
29
|
+
*/
|
|
30
|
+
export declare const getClassHierarchyTool: Tool<GetClassHierarchyInput>;
|
|
31
|
+
/**
|
|
32
|
+
* Factory function to create a customized getClassHierarchy tool
|
|
33
|
+
*/
|
|
34
|
+
export declare function createGetClassHierarchyTool(options?: {
|
|
35
|
+
defaultDirection?: HierarchyDirection;
|
|
36
|
+
defaultMaxDepth?: number;
|
|
37
|
+
}): Tool<GetClassHierarchyInput>;
|
|
38
|
+
//# sourceMappingURL=get-class-hierarchy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-class-hierarchy.d.ts","sourceRoot":"","sources":["../../src/tools/get-class-hierarchy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,IAAI,EAAuB,MAAM,qBAAqB,CAAC;AAQrE;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,aAAa,GAAG,MAAM,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAsCD;;GAEG;AACH,eAAO,MAAM,qBAAqB,8BAKhC,CAAC;AA+QH;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,CAAC,EAAE;IACpD,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAiB/B"}
|