@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,306 @@
1
+ /**
2
+ * findReferences Tool
3
+ *
4
+ * Find all references to a symbol across Python codebases.
5
+ * Uses Tree-sitter for AST analysis.
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, getNodeText } from "../parser/python-parser.js";
11
+ // Supported file extensions
12
+ const SUPPORTED_EXTENSIONS = new Set([".py", ".pyi"]);
13
+ // Tool description
14
+ const TOOL_DESCRIPTION = `Find all references to a symbol across Python files.
15
+ Returns locations grouped by file with context about each reference.
16
+ Useful for refactoring, understanding usage patterns, and impact analysis.`;
17
+ // Tool input schema
18
+ const TOOL_INPUT_SCHEMA = {
19
+ type: "object",
20
+ properties: {
21
+ symbol: {
22
+ type: "string",
23
+ description: "Symbol name to find references for",
24
+ },
25
+ scope: {
26
+ type: "string",
27
+ description: "Scope the search to a specific file or directory",
28
+ },
29
+ limit: {
30
+ type: "number",
31
+ description: "Maximum results to return (default: 50)",
32
+ default: 50,
33
+ },
34
+ includeDefinition: {
35
+ type: "boolean",
36
+ description: "Include the definition itself (default: false)",
37
+ default: false,
38
+ },
39
+ includeVenv: {
40
+ type: "boolean",
41
+ description: "Include virtual environments (default: false)",
42
+ default: false,
43
+ },
44
+ },
45
+ required: ["symbol"],
46
+ };
47
+ /**
48
+ * findReferences tool - Find all references to a symbol
49
+ */
50
+ export const findReferencesTool = defineTool({
51
+ name: "find_references_python",
52
+ description: TOOL_DESCRIPTION,
53
+ inputSchema: TOOL_INPUT_SCHEMA,
54
+ execute: executeFindReferences,
55
+ });
56
+ /**
57
+ * Execute the findReferences tool
58
+ */
59
+ async function executeFindReferences(input) {
60
+ const { symbol, scope, limit = 50, includeDefinition = false, includeVenv = false, } = input;
61
+ if (!symbol || symbol.trim().length === 0) {
62
+ return createErrorResult("Symbol name is required");
63
+ }
64
+ const startTime = Date.now();
65
+ const byFile = [];
66
+ let totalCount = 0;
67
+ let filesSearched = 0;
68
+ try {
69
+ const searchPath = scope || process.cwd();
70
+ try {
71
+ await fs.access(searchPath);
72
+ }
73
+ catch {
74
+ return createErrorResult(`Path not found: ${searchPath}`);
75
+ }
76
+ const stats = await fs.stat(searchPath);
77
+ if (stats.isFile()) {
78
+ if (isPythonFile(searchPath)) {
79
+ filesSearched = 1;
80
+ const refs = await searchFileForReferences(searchPath, symbol, includeDefinition);
81
+ if (refs.length > 0) {
82
+ byFile.push({ path: searchPath, references: refs.slice(0, limit) });
83
+ totalCount = refs.length;
84
+ }
85
+ }
86
+ }
87
+ else if (stats.isDirectory()) {
88
+ const files = await collectFiles(searchPath, includeVenv);
89
+ filesSearched = files.length;
90
+ for (const filePath of files) {
91
+ if (totalCount >= limit)
92
+ break;
93
+ const refs = await searchFileForReferences(filePath, symbol, includeDefinition);
94
+ if (refs.length > 0) {
95
+ const remaining = limit - totalCount;
96
+ byFile.push({
97
+ path: filePath,
98
+ references: refs.slice(0, remaining),
99
+ });
100
+ totalCount += Math.min(refs.length, remaining);
101
+ }
102
+ }
103
+ }
104
+ const endTime = Date.now();
105
+ const result = {
106
+ symbol,
107
+ byFile,
108
+ totalCount,
109
+ truncated: totalCount >= limit,
110
+ stats: {
111
+ filesSearched,
112
+ timeMs: endTime - startTime,
113
+ },
114
+ };
115
+ return createSuccessResult(result);
116
+ }
117
+ catch (error) {
118
+ const message = error instanceof Error ? error.message : String(error);
119
+ return createErrorResult(`Failed to find references: ${message}`);
120
+ }
121
+ }
122
+ /**
123
+ * Check if a file is a Python file
124
+ */
125
+ function isPythonFile(filePath) {
126
+ const ext = path.extname(filePath).toLowerCase();
127
+ return SUPPORTED_EXTENSIONS.has(ext);
128
+ }
129
+ /**
130
+ * Collect all Python files in a directory
131
+ */
132
+ async function collectFiles(dir, includeVenv) {
133
+ const files = [];
134
+ async function walk(currentDir) {
135
+ const entries = await fs.readdir(currentDir, { withFileTypes: true });
136
+ for (const entry of entries) {
137
+ const fullPath = path.join(currentDir, entry.name);
138
+ if (entry.isDirectory()) {
139
+ if (!includeVenv &&
140
+ (entry.name === "venv" ||
141
+ entry.name === ".venv" ||
142
+ entry.name === "env" ||
143
+ entry.name === ".env" ||
144
+ entry.name === "site-packages" ||
145
+ entry.name === "__pycache__")) {
146
+ continue;
147
+ }
148
+ if (entry.name.startsWith(".") ||
149
+ entry.name === "dist" ||
150
+ entry.name === "build") {
151
+ continue;
152
+ }
153
+ await walk(fullPath);
154
+ }
155
+ else if (entry.isFile() && isPythonFile(fullPath)) {
156
+ files.push(fullPath);
157
+ }
158
+ }
159
+ }
160
+ await walk(dir);
161
+ return files;
162
+ }
163
+ /**
164
+ * Search a file for references to a symbol
165
+ */
166
+ async function searchFileForReferences(filePath, symbolName, includeDefinition) {
167
+ const references = [];
168
+ try {
169
+ const parseResult = await parseFile(filePath);
170
+ const { tree, source } = parseResult;
171
+ const lines = source.split("\n");
172
+ // Walk the AST to find all references
173
+ findReferencesInNode(tree.rootNode, source, symbolName, includeDefinition, filePath, lines, references);
174
+ }
175
+ catch {
176
+ // Skip files that can't be parsed
177
+ }
178
+ return references;
179
+ }
180
+ /**
181
+ * Recursively find references in AST nodes
182
+ */
183
+ function findReferencesInNode(node, source, symbolName, includeDefinition, filePath, lines, references) {
184
+ // Check identifier nodes
185
+ if (node.type === "identifier" && getNodeText(node, source) === symbolName) {
186
+ const refType = determineReferenceType(node, includeDefinition);
187
+ if (refType) {
188
+ const lineIndex = node.startPosition.row;
189
+ references.push({
190
+ path: filePath,
191
+ line: lineIndex + 1,
192
+ column: node.startPosition.column + 1,
193
+ context: lines[lineIndex]?.trim() || "",
194
+ type: refType,
195
+ });
196
+ }
197
+ }
198
+ // Check attribute access (e.g., obj.symbolName)
199
+ if (node.type === "attribute") {
200
+ const attrNode = node.childForFieldName("attribute");
201
+ if (attrNode && getNodeText(attrNode, source) === symbolName) {
202
+ const lineIndex = attrNode.startPosition.row;
203
+ references.push({
204
+ path: filePath,
205
+ line: lineIndex + 1,
206
+ column: attrNode.startPosition.column + 1,
207
+ context: lines[lineIndex]?.trim() || "",
208
+ type: "attribute",
209
+ });
210
+ }
211
+ }
212
+ // Check import names
213
+ if (node.type === "import_from_statement" ||
214
+ node.type === "import_statement") {
215
+ for (const child of node.children) {
216
+ if (child.type === "dotted_name" &&
217
+ getNodeText(child, source).includes(symbolName)) {
218
+ const lineIndex = child.startPosition.row;
219
+ references.push({
220
+ path: filePath,
221
+ line: lineIndex + 1,
222
+ column: child.startPosition.column + 1,
223
+ context: lines[lineIndex]?.trim() || "",
224
+ type: "import",
225
+ });
226
+ }
227
+ }
228
+ }
229
+ // Recurse into children
230
+ for (const child of node.children) {
231
+ findReferencesInNode(child, source, symbolName, includeDefinition, filePath, lines, references);
232
+ }
233
+ }
234
+ /**
235
+ * Determine the type of reference based on context
236
+ */
237
+ function determineReferenceType(node, includeDefinition) {
238
+ const parent = node.parent;
239
+ if (!parent)
240
+ return "read";
241
+ // Definition sites
242
+ if (parent.type === "function_definition" ||
243
+ parent.type === "async_function_definition" ||
244
+ parent.type === "class_definition") {
245
+ return includeDefinition ? "definition" : null;
246
+ }
247
+ // Parameter definition
248
+ if (parent.type === "parameters" ||
249
+ parent.type === "typed_parameter" ||
250
+ parent.type === "default_parameter") {
251
+ return includeDefinition ? "definition" : null;
252
+ }
253
+ // Assignment left side
254
+ if (parent.type === "assignment" || parent.type === "annotated_assignment") {
255
+ const leftNode = parent.childForFieldName("left");
256
+ if (leftNode &&
257
+ node.startIndex >= leftNode.startIndex &&
258
+ node.endIndex <= leftNode.endIndex) {
259
+ return "write";
260
+ }
261
+ }
262
+ // Augmented assignment
263
+ if (parent.type === "augmented_assignment") {
264
+ const leftNode = parent.children[0];
265
+ if (leftNode &&
266
+ node.startIndex >= leftNode.startIndex &&
267
+ node.endIndex <= leftNode.endIndex) {
268
+ return "write";
269
+ }
270
+ }
271
+ // Function call
272
+ if (parent.type === "call") {
273
+ const funcNode = parent.childForFieldName("function");
274
+ if (funcNode &&
275
+ node.startIndex >= funcNode.startIndex &&
276
+ node.endIndex <= funcNode.endIndex) {
277
+ return "call";
278
+ }
279
+ }
280
+ // Import
281
+ if (parent.type === "import_statement" ||
282
+ parent.type === "import_from_statement" ||
283
+ parent.type === "aliased_import") {
284
+ return "import";
285
+ }
286
+ // Default to read
287
+ return "read";
288
+ }
289
+ /**
290
+ * Factory function to create a customized findReferences tool
291
+ */
292
+ export function createFindReferencesTool(options) {
293
+ const { defaultLimit = 50, defaultIncludeDefinition = false } = options ?? {};
294
+ return defineTool({
295
+ name: "find_references_python",
296
+ description: TOOL_DESCRIPTION,
297
+ inputSchema: TOOL_INPUT_SCHEMA,
298
+ execute: async (input) => {
299
+ return executeFindReferences({
300
+ ...input,
301
+ limit: input.limit ?? defaultLimit,
302
+ includeDefinition: input.includeDefinition ?? defaultIncludeDefinition,
303
+ });
304
+ },
305
+ });
306
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * findSymbol Tool
3
+ *
4
+ * Find the definition location of a symbol across Python codebases.
5
+ * Uses Tree-sitter for AST analysis.
6
+ */
7
+ import type { Tool } from "@compilr-dev/agents";
8
+ /**
9
+ * Python symbol kinds
10
+ */
11
+ export type PythonSymbolKind = "function" | "class" | "method" | "variable" | "constant" | "parameter";
12
+ export type PythonSymbolKindFilter = PythonSymbolKind | "any";
13
+ /**
14
+ * Input for findSymbol tool
15
+ */
16
+ export interface FindSymbolInput {
17
+ /** Symbol name to find */
18
+ symbol: string;
19
+ /** Scope the search to a specific file or directory */
20
+ scope?: string;
21
+ /** Filter by symbol kind */
22
+ kind?: PythonSymbolKindFilter;
23
+ /** Maximum results to return (default: 10) */
24
+ limit?: number;
25
+ /** Include symbols from virtual environments (default: false) */
26
+ includeVenv?: boolean;
27
+ }
28
+ /**
29
+ * A found symbol definition
30
+ */
31
+ export interface PythonSymbolDefinition {
32
+ /** Symbol name */
33
+ name: string;
34
+ /** File path */
35
+ path: string;
36
+ /** Line number (1-based) */
37
+ line: number;
38
+ /** Column number (1-based) */
39
+ column: number;
40
+ /** Symbol kind */
41
+ kind: PythonSymbolKind;
42
+ /** Containing class/module (if applicable) */
43
+ container?: string;
44
+ /** Is public (doesn't start with _) */
45
+ isPublic: boolean;
46
+ /** Signature (for functions/methods) */
47
+ signature?: string;
48
+ /** Docstring summary */
49
+ docSummary?: string;
50
+ /** Confidence score (0-1) for fuzzy matches */
51
+ confidence: number;
52
+ }
53
+ /**
54
+ * Search statistics
55
+ */
56
+ export interface SearchStats {
57
+ /** Number of files searched */
58
+ filesSearched: number;
59
+ /** Time taken in milliseconds */
60
+ timeMs: number;
61
+ }
62
+ /**
63
+ * Output from findSymbol tool
64
+ */
65
+ export interface FindSymbolResult {
66
+ /** Symbol that was searched */
67
+ query: string;
68
+ /** Found definitions */
69
+ definitions: PythonSymbolDefinition[];
70
+ /** Search statistics */
71
+ stats: SearchStats;
72
+ }
73
+ /**
74
+ * findSymbol tool - Find symbol definitions in Python
75
+ */
76
+ export declare const findSymbolTool: Tool<FindSymbolInput>;
77
+ /**
78
+ * Factory function to create a customized findSymbol tool
79
+ */
80
+ export declare function createFindSymbolTool(options?: {
81
+ /** Default limit */
82
+ defaultLimit?: number;
83
+ /** Default includeVenv */
84
+ defaultIncludeVenv?: boolean;
85
+ }): Tool<FindSymbolInput>;
86
+ //# sourceMappingURL=find-symbol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-symbol.d.ts","sourceRoot":"","sources":["../../src/tools/find-symbol.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,IAAI,EAAuB,MAAM,qBAAqB,CAAC;AAYrE;;GAEG;AACH,MAAM,MAAM,gBAAgB,GACxB,UAAU,GACV,OAAO,GACP,QAAQ,GACR,UAAU,GACV,UAAU,GACV,WAAW,CAAC;AAEhB,MAAM,MAAM,sBAAsB,GAAG,gBAAgB,GAAG,KAAK,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,IAAI,CAAC,EAAE,sBAAsB,CAAC;IAC9B,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,kBAAkB;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB;IAClB,IAAI,EAAE,gBAAgB,CAAC;IACvB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,QAAQ,EAAE,OAAO,CAAC;IAClB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,+BAA+B;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,WAAW,EAAE,sBAAsB,EAAE,CAAC;IACtC,wBAAwB;IACxB,KAAK,EAAE,WAAW,CAAC;CACpB;AAwCD;;GAEG;AACH,eAAO,MAAM,cAAc,uBAKzB,CAAC;AA4aH;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE;IAC7C,oBAAoB;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0BAA0B;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,GAAG,IAAI,CAAC,eAAe,CAAC,CAexB"}