@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,437 @@
1
+ /**
2
+ * getExports Tool
3
+ *
4
+ * Get all exports from a Python module.
5
+ * Analyzes __all__ declarations and identifies public API.
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 = `Get all exports from a Python module.
13
+ Analyzes __all__ declarations and identifies public API surface.
14
+ Use this to understand what a module exposes to other modules.`;
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
+ includeReExports: {
24
+ type: "boolean",
25
+ description: "Include re-exports from imports (default: true)",
26
+ default: true,
27
+ },
28
+ includePrivate: {
29
+ type: "boolean",
30
+ description: "Include private symbols with _ prefix (default: false)",
31
+ default: false,
32
+ },
33
+ },
34
+ required: ["path"],
35
+ };
36
+ /**
37
+ * getExports tool
38
+ */
39
+ export const getExportsTool = defineTool({
40
+ name: "get_exports_python",
41
+ description: TOOL_DESCRIPTION,
42
+ inputSchema: TOOL_INPUT_SCHEMA,
43
+ execute: executeGetExports,
44
+ });
45
+ /**
46
+ * Execute the getExports tool
47
+ */
48
+ async function executeGetExports(input) {
49
+ const { path: inputPath, includeReExports = true, includePrivate = false, } = input;
50
+ // Validate input
51
+ if (!inputPath || inputPath.trim().length === 0) {
52
+ return createErrorResult("Path is required");
53
+ }
54
+ try {
55
+ const resolvedPath = path.resolve(inputPath);
56
+ // Check if file exists
57
+ try {
58
+ await fs.access(resolvedPath);
59
+ }
60
+ catch {
61
+ return createErrorResult(`File not found: ${resolvedPath}`);
62
+ }
63
+ const stats = await fs.stat(resolvedPath);
64
+ if (!stats.isFile()) {
65
+ return createErrorResult(`Path must be a file: ${resolvedPath}`);
66
+ }
67
+ if (!resolvedPath.endsWith(".py")) {
68
+ return createErrorResult("File must be a Python file (.py)");
69
+ }
70
+ // Analyze the file
71
+ const result = await analyzeExports(resolvedPath, includeReExports, includePrivate);
72
+ return createSuccessResult({
73
+ ...result,
74
+ path: resolvedPath,
75
+ });
76
+ }
77
+ catch (error) {
78
+ const message = error instanceof Error ? error.message : String(error);
79
+ return createErrorResult(`Failed to analyze exports: ${message}`);
80
+ }
81
+ }
82
+ /**
83
+ * Analyze exports in a Python file
84
+ */
85
+ async function analyzeExports(filePath, includeReExports, includePrivate) {
86
+ const parseResult = await parseFile(filePath);
87
+ const { tree, source } = parseResult;
88
+ const allDeclaration = [];
89
+ const publicExports = [];
90
+ const privateSymbols = [];
91
+ const reExports = [];
92
+ // Track names in __all__
93
+ const allNames = new Set();
94
+ // First pass: find __all__ declaration
95
+ for (const child of tree.rootNode.children) {
96
+ if (child.type === "expression_statement") {
97
+ const expr = child.children[0];
98
+ if (expr?.type === "assignment") {
99
+ const left = expr.childForFieldName("left");
100
+ if (left?.text === "__all__") {
101
+ const right = expr.childForFieldName("right");
102
+ if (right) {
103
+ const names = extractAllNames(right);
104
+ names.forEach((n) => {
105
+ allDeclaration.push(n);
106
+ allNames.add(n);
107
+ });
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ // Second pass: extract all module-level definitions
114
+ for (const child of tree.rootNode.children) {
115
+ // Function definitions
116
+ if (child.type === "function_definition") {
117
+ const funcInfo = parseFunction(child, source);
118
+ const isPrivate = funcInfo.name.startsWith("_");
119
+ const inAll = allNames.has(funcInfo.name);
120
+ const symbol = {
121
+ name: funcInfo.name,
122
+ kind: "function",
123
+ line: funcInfo.line,
124
+ signature: buildFunctionSignature(child, source),
125
+ docstring: extractDocstring(child),
126
+ isPrivate,
127
+ inAll,
128
+ };
129
+ if (isPrivate && !inAll) {
130
+ if (includePrivate)
131
+ privateSymbols.push(symbol);
132
+ }
133
+ else {
134
+ publicExports.push(symbol);
135
+ }
136
+ }
137
+ // Async function definitions
138
+ else if (child.type === "async_function_definition") {
139
+ const funcDef = child.children.find((c) => c.type === "function_definition");
140
+ if (funcDef) {
141
+ const funcInfo = parseFunction(funcDef, source);
142
+ const isPrivate = funcInfo.name.startsWith("_");
143
+ const inAll = allNames.has(funcInfo.name);
144
+ const symbol = {
145
+ name: funcInfo.name,
146
+ kind: "async_function",
147
+ line: funcInfo.line,
148
+ signature: `async ${buildFunctionSignature(funcDef, source)}`,
149
+ docstring: extractDocstring(funcDef),
150
+ isPrivate,
151
+ inAll,
152
+ };
153
+ if (isPrivate && !inAll) {
154
+ if (includePrivate)
155
+ privateSymbols.push(symbol);
156
+ }
157
+ else {
158
+ publicExports.push(symbol);
159
+ }
160
+ }
161
+ }
162
+ // Class definitions
163
+ else if (child.type === "class_definition") {
164
+ const classInfo = parseClass(child, source);
165
+ const isPrivate = classInfo.name.startsWith("_");
166
+ const inAll = allNames.has(classInfo.name);
167
+ const symbol = {
168
+ name: classInfo.name,
169
+ kind: "class",
170
+ line: classInfo.line,
171
+ signature: buildClassSignature(child, source),
172
+ docstring: extractDocstring(child),
173
+ isPrivate,
174
+ inAll,
175
+ };
176
+ if (isPrivate && !inAll) {
177
+ if (includePrivate)
178
+ privateSymbols.push(symbol);
179
+ }
180
+ else {
181
+ publicExports.push(symbol);
182
+ }
183
+ }
184
+ // Decorated definitions
185
+ else if (child.type === "decorated_definition") {
186
+ const definition = child.children.find((c) => c.type === "function_definition" ||
187
+ c.type === "async_function_definition" ||
188
+ c.type === "class_definition");
189
+ if (definition) {
190
+ if (definition.type === "class_definition") {
191
+ const classInfo = parseClass(definition, source);
192
+ const isPrivate = classInfo.name.startsWith("_");
193
+ const inAll = allNames.has(classInfo.name);
194
+ const symbol = {
195
+ name: classInfo.name,
196
+ kind: "class",
197
+ line: classInfo.line,
198
+ signature: buildClassSignature(definition, source),
199
+ docstring: extractDocstring(definition),
200
+ isPrivate,
201
+ inAll,
202
+ };
203
+ if (isPrivate && !inAll) {
204
+ if (includePrivate)
205
+ privateSymbols.push(symbol);
206
+ }
207
+ else {
208
+ publicExports.push(symbol);
209
+ }
210
+ }
211
+ else {
212
+ const funcDef = definition.type === "async_function_definition"
213
+ ? definition.children.find((c) => c.type === "function_definition")
214
+ : definition;
215
+ if (funcDef) {
216
+ const funcInfo = parseFunction(funcDef, source);
217
+ const isPrivate = funcInfo.name.startsWith("_");
218
+ const inAll = allNames.has(funcInfo.name);
219
+ const isAsync = definition.type === "async_function_definition";
220
+ const symbol = {
221
+ name: funcInfo.name,
222
+ kind: isAsync ? "async_function" : "function",
223
+ line: funcInfo.line,
224
+ signature: isAsync
225
+ ? `async ${buildFunctionSignature(funcDef, source)}`
226
+ : buildFunctionSignature(funcDef, source),
227
+ docstring: extractDocstring(funcDef),
228
+ isPrivate,
229
+ inAll,
230
+ };
231
+ if (isPrivate && !inAll) {
232
+ if (includePrivate)
233
+ privateSymbols.push(symbol);
234
+ }
235
+ else {
236
+ publicExports.push(symbol);
237
+ }
238
+ }
239
+ }
240
+ }
241
+ }
242
+ // Variable assignments (module-level constants/variables)
243
+ else if (child.type === "expression_statement") {
244
+ const expr = child.children[0];
245
+ if (expr?.type === "assignment") {
246
+ const left = expr.childForFieldName("left");
247
+ if (left?.type === "identifier" && left.text !== "__all__") {
248
+ const name = left.text;
249
+ const isPrivate = name.startsWith("_");
250
+ const inAll = allNames.has(name);
251
+ const isConstant = name === name.toUpperCase();
252
+ const symbol = {
253
+ name,
254
+ kind: isConstant ? "constant" : "variable",
255
+ line: child.startPosition.row + 1,
256
+ isPrivate,
257
+ inAll,
258
+ };
259
+ if (isPrivate && !inAll) {
260
+ if (includePrivate)
261
+ privateSymbols.push(symbol);
262
+ }
263
+ else {
264
+ publicExports.push(symbol);
265
+ }
266
+ }
267
+ }
268
+ }
269
+ // Import statements (for re-exports)
270
+ else if (includeReExports && child.type === "import_from_statement") {
271
+ const reExport = extractReExport(child, source);
272
+ if (reExport) {
273
+ reExports.push(reExport);
274
+ }
275
+ }
276
+ }
277
+ // Calculate statistics
278
+ const exportStats = {
279
+ totalExports: publicExports.length,
280
+ functions: publicExports.filter((e) => e.kind === "function" || e.kind === "async_function").length,
281
+ classes: publicExports.filter((e) => e.kind === "class").length,
282
+ variables: publicExports.filter((e) => e.kind === "variable" || e.kind === "constant").length,
283
+ reExports: reExports.length,
284
+ hasAll: allDeclaration.length > 0,
285
+ allCount: allDeclaration.length > 0 ? allDeclaration.length : undefined,
286
+ };
287
+ return {
288
+ allDeclaration: allDeclaration.length > 0 ? allDeclaration : undefined,
289
+ publicExports,
290
+ privateSymbols: includePrivate && privateSymbols.length > 0 ? privateSymbols : undefined,
291
+ reExports: includeReExports && reExports.length > 0 ? reExports : undefined,
292
+ stats: exportStats,
293
+ };
294
+ }
295
+ /**
296
+ * Extract names from __all__ list
297
+ */
298
+ function extractAllNames(node) {
299
+ const names = [];
300
+ if (node.type === "list") {
301
+ for (const child of node.children) {
302
+ if (child.type === "string") {
303
+ // Remove quotes
304
+ const text = child.text;
305
+ const name = text.slice(1, -1);
306
+ if (name)
307
+ names.push(name);
308
+ }
309
+ }
310
+ }
311
+ else if (node.type === "tuple") {
312
+ for (const child of node.children) {
313
+ if (child.type === "string") {
314
+ const text = child.text;
315
+ const name = text.slice(1, -1);
316
+ if (name)
317
+ names.push(name);
318
+ }
319
+ }
320
+ }
321
+ return names;
322
+ }
323
+ /**
324
+ * Build function signature string
325
+ */
326
+ function buildFunctionSignature(funcNode, _source) {
327
+ const nameNode = funcNode.childForFieldName("name");
328
+ const paramsNode = funcNode.childForFieldName("parameters");
329
+ const returnNode = funcNode.childForFieldName("return_type");
330
+ const name = nameNode?.text ?? "unknown";
331
+ const params = paramsNode?.text ?? "()";
332
+ const returnType = returnNode ? ` -> ${returnNode.text}` : "";
333
+ return `def ${name}${params}${returnType}`;
334
+ }
335
+ /**
336
+ * Build class signature string
337
+ */
338
+ function buildClassSignature(classNode, _source) {
339
+ const nameNode = classNode.childForFieldName("name");
340
+ const superclassNode = classNode.childForFieldName("superclasses");
341
+ const name = nameNode?.text ?? "unknown";
342
+ const bases = superclassNode?.text ?? "";
343
+ return bases ? `class ${name}${bases}` : `class ${name}`;
344
+ }
345
+ /**
346
+ * Extract docstring from a definition
347
+ */
348
+ function extractDocstring(node) {
349
+ const body = node.childForFieldName("body");
350
+ if (!body)
351
+ return undefined;
352
+ for (const child of body.children) {
353
+ if (child.type === "expression_statement") {
354
+ const string = child.children.find((c) => c.type === "string" || c.type === "concatenated_string");
355
+ if (string) {
356
+ // Extract first line of docstring
357
+ let content = string.text;
358
+ if (content.startsWith('"""') || content.startsWith("'''")) {
359
+ content = content.slice(3, -3);
360
+ }
361
+ else if (content.startsWith('"') || content.startsWith("'")) {
362
+ content = content.slice(1, -1);
363
+ }
364
+ const firstLine = content.trim().split("\n")[0];
365
+ return firstLine.length > 100
366
+ ? firstLine.slice(0, 100) + "..."
367
+ : firstLine;
368
+ }
369
+ }
370
+ // Stop after first non-docstring statement
371
+ if (child.type !== "expression_statement" && child.type !== "comment") {
372
+ break;
373
+ }
374
+ }
375
+ return undefined;
376
+ }
377
+ /**
378
+ * Extract re-export info from import statement
379
+ */
380
+ function extractReExport(node, _source) {
381
+ // from module import name, name2
382
+ // from module import *
383
+ const moduleNode = node.childForFieldName("module_name");
384
+ if (!moduleNode)
385
+ return null;
386
+ const moduleName = moduleNode.text;
387
+ const isRelative = moduleName.startsWith(".");
388
+ const line = node.startPosition.row + 1;
389
+ // Check for star import
390
+ const hasWildcard = node.children.some((c) => c.type === "wildcard_import" || c.text === "*");
391
+ if (hasWildcard) {
392
+ return {
393
+ symbols: "*",
394
+ from: moduleName,
395
+ line,
396
+ isRelative,
397
+ };
398
+ }
399
+ // Named imports
400
+ const symbols = [];
401
+ for (const child of node.children) {
402
+ if (child.type === "dotted_name" && child !== moduleNode) {
403
+ symbols.push(child.text);
404
+ }
405
+ else if (child.type === "aliased_import") {
406
+ const nameNode = child.childForFieldName("name");
407
+ if (nameNode) {
408
+ symbols.push(nameNode.text);
409
+ }
410
+ }
411
+ }
412
+ if (symbols.length === 0)
413
+ return null;
414
+ return {
415
+ symbols,
416
+ from: moduleName,
417
+ line,
418
+ isRelative,
419
+ };
420
+ }
421
+ /**
422
+ * Factory function to create a customized getExports tool
423
+ */
424
+ export function createGetExportsTool(options) {
425
+ return defineTool({
426
+ name: "get_exports_python",
427
+ description: TOOL_DESCRIPTION,
428
+ inputSchema: TOOL_INPUT_SCHEMA,
429
+ execute: async (input) => {
430
+ return executeGetExports({
431
+ ...input,
432
+ includeReExports: input.includeReExports ?? options?.defaultIncludeReExports ?? true,
433
+ includePrivate: input.includePrivate ?? options?.defaultIncludePrivate ?? false,
434
+ });
435
+ },
436
+ });
437
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Get File Structure Tool
3
+ *
4
+ * Analyzes a Python file and returns its structural overview including
5
+ * classes, functions, variables, and imports.
6
+ */
7
+ /**
8
+ * Input for getFileStructure tool
9
+ */
10
+ export interface GetFileStructureInput {
11
+ /** Path to Python file */
12
+ path: string;
13
+ /** Include private members (starting with _) */
14
+ includePrivate?: boolean;
15
+ /** Maximum nesting depth */
16
+ maxDepth?: number;
17
+ }
18
+ /**
19
+ * Get file structure tool
20
+ */
21
+ export declare const getFileStructureTool: import("@compilr-dev/agents").Tool<GetFileStructureInput>;
22
+ /**
23
+ * Factory function to create getFileStructure tool with custom options
24
+ */
25
+ export declare function createGetFileStructureTool(options?: {
26
+ baseDir?: string;
27
+ }): import("@compilr-dev/agents").Tool<GetFileStructureInput>;
28
+ //# sourceMappingURL=get-file-structure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-file-structure.d.ts","sourceRoot":"","sources":["../../src/tools/get-file-structure.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqBH;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB,2DAwB/B,CAAC;AAyJH;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,6DAmCxE"}
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Get File Structure Tool
3
+ *
4
+ * Analyzes a Python file and returns its structural overview including
5
+ * classes, functions, variables, and imports.
6
+ */
7
+ import { defineTool, createSuccessResult, createErrorResult, } from "@compilr-dev/agents";
8
+ import { stat } from "node:fs/promises";
9
+ import { resolve } from "node:path";
10
+ import { parseFile, parseClass, parseFunction, parseImport, parseVariable, parseDecorators, extractDocstring, } from "../parser/python-parser.js";
11
+ /**
12
+ * Get file structure tool
13
+ */
14
+ export const getFileStructureTool = defineTool({
15
+ name: "get_file_structure_python",
16
+ description: "Get structural overview of a Python file including classes, functions, variables, and imports. " +
17
+ "Useful for understanding file organization and API surface.",
18
+ inputSchema: {
19
+ type: "object",
20
+ properties: {
21
+ path: {
22
+ type: "string",
23
+ description: "Path to Python file (.py)",
24
+ },
25
+ includePrivate: {
26
+ type: "boolean",
27
+ description: "Include private members (starting with _)",
28
+ },
29
+ maxDepth: {
30
+ type: "number",
31
+ description: "Maximum nesting depth to analyze",
32
+ },
33
+ },
34
+ required: ["path"],
35
+ },
36
+ execute: executeGetFileStructure,
37
+ });
38
+ async function executeGetFileStructure(input) {
39
+ const filePath = resolve(input.path);
40
+ const includePrivate = input.includePrivate ?? false;
41
+ // Validate file exists and is a Python file
42
+ try {
43
+ const stats = await stat(filePath);
44
+ if (!stats.isFile()) {
45
+ return createErrorResult(`Not a file: ${filePath}`);
46
+ }
47
+ if (!filePath.endsWith(".py") && !filePath.endsWith(".pyi")) {
48
+ return createErrorResult(`Not a Python file: ${filePath}`);
49
+ }
50
+ }
51
+ catch {
52
+ return createErrorResult(`File not found: ${filePath}`);
53
+ }
54
+ try {
55
+ const parseResult = await parseFile(filePath);
56
+ const { tree, source } = parseResult;
57
+ const rootNode = tree.rootNode;
58
+ const result = {
59
+ path: filePath,
60
+ classes: [],
61
+ functions: [],
62
+ variables: [],
63
+ imports: [],
64
+ stats: {
65
+ totalClasses: 0,
66
+ totalFunctions: 0,
67
+ totalVariables: 0,
68
+ totalImports: 0,
69
+ totalLines: source.split("\n").length,
70
+ },
71
+ };
72
+ // Extract module docstring
73
+ result.docstring = extractDocstring({ childForFieldName: () => rootNode }, source);
74
+ // Process top-level nodes
75
+ for (const child of rootNode.children) {
76
+ // Imports
77
+ if (child.type === "import_statement" ||
78
+ child.type === "import_from_statement") {
79
+ const importInfo = parseImport(child, source);
80
+ result.imports.push(importInfo);
81
+ result.stats.totalImports++;
82
+ }
83
+ // Class definitions
84
+ if (child.type === "class_definition") {
85
+ const classInfo = parseClass(child, source);
86
+ if (includePrivate || !classInfo.name.startsWith("_")) {
87
+ // Filter private methods if needed
88
+ if (!includePrivate) {
89
+ classInfo.methods = classInfo.methods.filter((m) => !m.name.startsWith("_") || m.name.startsWith("__"));
90
+ classInfo.attributes = classInfo.attributes.filter((a) => !a.name.startsWith("_"));
91
+ }
92
+ result.classes.push(classInfo);
93
+ result.stats.totalClasses++;
94
+ }
95
+ }
96
+ // Decorated class definitions
97
+ if (child.type === "decorated_definition") {
98
+ const decorators = parseDecorators(child, source);
99
+ const classNode = child.children.find((c) => c.type === "class_definition");
100
+ if (classNode) {
101
+ const classInfo = parseClass(classNode, source, decorators);
102
+ if (includePrivate || !classInfo.name.startsWith("_")) {
103
+ if (!includePrivate) {
104
+ classInfo.methods = classInfo.methods.filter((m) => !m.name.startsWith("_") || m.name.startsWith("__"));
105
+ classInfo.attributes = classInfo.attributes.filter((a) => !a.name.startsWith("_"));
106
+ }
107
+ result.classes.push(classInfo);
108
+ result.stats.totalClasses++;
109
+ }
110
+ }
111
+ }
112
+ // Function definitions
113
+ if (child.type === "function_definition" ||
114
+ child.type === "async_function_definition") {
115
+ const funcInfo = parseFunction(child, source);
116
+ if (includePrivate || !funcInfo.name.startsWith("_")) {
117
+ result.functions.push(funcInfo);
118
+ result.stats.totalFunctions++;
119
+ }
120
+ }
121
+ // Decorated function definitions
122
+ if (child.type === "decorated_definition") {
123
+ const decorators = parseDecorators(child, source);
124
+ const funcNode = child.children.find((c) => c.type === "function_definition" ||
125
+ c.type === "async_function_definition");
126
+ if (funcNode) {
127
+ const funcInfo = parseFunction(funcNode, source, decorators);
128
+ if (includePrivate || !funcInfo.name.startsWith("_")) {
129
+ result.functions.push(funcInfo);
130
+ result.stats.totalFunctions++;
131
+ }
132
+ }
133
+ }
134
+ // Variable assignments at module level
135
+ if (child.type === "expression_statement") {
136
+ const expr = child.firstChild;
137
+ if (expr &&
138
+ (expr.type === "assignment" || expr.type === "annotated_assignment")) {
139
+ const varInfo = parseVariable(expr, source);
140
+ if (varInfo && (includePrivate || !varInfo.name.startsWith("_"))) {
141
+ result.variables.push(varInfo);
142
+ result.stats.totalVariables++;
143
+ }
144
+ }
145
+ }
146
+ }
147
+ return createSuccessResult(result);
148
+ }
149
+ catch (error) {
150
+ return createErrorResult(error instanceof Error ? error.message : String(error));
151
+ }
152
+ }
153
+ /**
154
+ * Factory function to create getFileStructure tool with custom options
155
+ */
156
+ export function createGetFileStructureTool(options) {
157
+ return defineTool({
158
+ name: "get_file_structure_python",
159
+ description: "Get structural overview of a Python file including classes, functions, variables, and imports.",
160
+ inputSchema: {
161
+ type: "object",
162
+ properties: {
163
+ path: {
164
+ type: "string",
165
+ description: "Path to Python file (.py)",
166
+ },
167
+ includePrivate: {
168
+ type: "boolean",
169
+ description: "Include private members (starting with _)",
170
+ },
171
+ maxDepth: {
172
+ type: "number",
173
+ description: "Maximum nesting depth to analyze",
174
+ },
175
+ },
176
+ required: ["path"],
177
+ },
178
+ execute: async (input) => {
179
+ let targetPath = input.path;
180
+ if (options?.baseDir && !targetPath.startsWith("/")) {
181
+ targetPath = resolve(options.baseDir, targetPath);
182
+ }
183
+ return executeGetFileStructure({ ...input, path: targetPath });
184
+ },
185
+ });
186
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * getImports Tool
3
+ *
4
+ * Analyzes imports in Python files.
5
+ * Categorizes imports into stdlib, third-party, and local.
6
+ */
7
+ import type { Tool } from "@compilr-dev/agents";
8
+ /**
9
+ * Input for getImports tool
10
+ */
11
+ export interface GetImportsInput {
12
+ /** File or directory to analyze */
13
+ path: string;
14
+ /** Recursively analyze directory (default: false) */
15
+ recursive?: boolean;
16
+ /** Filter to specific import sources */
17
+ filterModule?: string;
18
+ /** Maximum files to analyze (default: 50) */
19
+ maxFiles?: number;
20
+ }
21
+ /**
22
+ * getImports tool - Analyze Python imports
23
+ */
24
+ export declare const getImportsTool: Tool<GetImportsInput>;
25
+ /**
26
+ * Factory function to create a customized getImports tool
27
+ */
28
+ export declare function createGetImportsTool(options?: {
29
+ /** Default recursive */
30
+ defaultRecursive?: boolean;
31
+ /** Default maxFiles */
32
+ defaultMaxFiles?: number;
33
+ }): Tool<GetImportsInput>;
34
+ //# sourceMappingURL=get-imports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-imports.d.ts","sourceRoot":"","sources":["../../src/tools/get-imports.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,IAAI,EAAuB,MAAM,qBAAqB,CAAC;AAwNrE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAiCD;;GAEG;AACH,eAAO,MAAM,cAAc,uBAKzB,CAAC;AAyOH;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE;IAC7C,wBAAwB;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,uBAAuB;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GAAG,IAAI,CAAC,eAAe,CAAC,CAexB"}