@compilr-dev/agents-coding-ts 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 +34 -0
- package/dist/index.js +66 -0
- package/dist/parser/index.d.ts +7 -0
- package/dist/parser/index.js +6 -0
- package/dist/parser/typescript-parser.d.ts +22 -0
- package/dist/parser/typescript-parser.js +423 -0
- package/dist/skills/code-health.d.ts +9 -0
- package/dist/skills/code-health.js +167 -0
- package/dist/skills/code-structure.d.ts +9 -0
- package/dist/skills/code-structure.js +97 -0
- package/dist/skills/dependency-audit.d.ts +9 -0
- package/dist/skills/dependency-audit.js +110 -0
- package/dist/skills/index.d.ts +16 -0
- package/dist/skills/index.js +27 -0
- package/dist/skills/refactor-impact.d.ts +9 -0
- package/dist/skills/refactor-impact.js +135 -0
- package/dist/skills/type-analysis.d.ts +9 -0
- package/dist/skills/type-analysis.js +150 -0
- package/dist/tools/find-dead-code.d.ts +20 -0
- package/dist/tools/find-dead-code.js +375 -0
- package/dist/tools/find-duplicates.d.ts +21 -0
- package/dist/tools/find-duplicates.js +274 -0
- package/dist/tools/find-implementations.d.ts +21 -0
- package/dist/tools/find-implementations.js +436 -0
- package/dist/tools/find-patterns.d.ts +21 -0
- package/dist/tools/find-patterns.js +457 -0
- package/dist/tools/find-references.d.ts +23 -0
- package/dist/tools/find-references.js +488 -0
- package/dist/tools/find-symbol.d.ts +21 -0
- package/dist/tools/find-symbol.js +458 -0
- package/dist/tools/get-call-graph.d.ts +23 -0
- package/dist/tools/get-call-graph.js +469 -0
- package/dist/tools/get-complexity.d.ts +21 -0
- package/dist/tools/get-complexity.js +394 -0
- package/dist/tools/get-dependency-graph.d.ts +23 -0
- package/dist/tools/get-dependency-graph.js +482 -0
- package/dist/tools/get-documentation.d.ts +21 -0
- package/dist/tools/get-documentation.js +613 -0
- package/dist/tools/get-exports.d.ts +21 -0
- package/dist/tools/get-exports.js +427 -0
- package/dist/tools/get-file-structure.d.ts +27 -0
- package/dist/tools/get-file-structure.js +120 -0
- package/dist/tools/get-imports.d.ts +23 -0
- package/dist/tools/get-imports.js +350 -0
- package/dist/tools/get-signature.d.ts +20 -0
- package/dist/tools/get-signature.js +758 -0
- package/dist/tools/get-type-hierarchy.d.ts +22 -0
- package/dist/tools/get-type-hierarchy.js +485 -0
- package/dist/tools/index.d.ts +23 -0
- package/dist/tools/index.js +25 -0
- package/dist/tools/types.d.ts +1302 -0
- package/dist/tools/types.js +7 -0
- package/package.json +84 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* getExports Tool
|
|
3
|
+
*
|
|
4
|
+
* Get all exports from a module.
|
|
5
|
+
* Uses TypeScript Compiler API for accurate AST analysis.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'node:fs/promises';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import * as ts from 'typescript';
|
|
10
|
+
import { defineTool, createSuccessResult, createErrorResult } from '@compilr-dev/agents';
|
|
11
|
+
import { detectLanguage, isLanguageSupported } from '../parser/typescript-parser.js';
|
|
12
|
+
// Tool description
|
|
13
|
+
const TOOL_DESCRIPTION = `Get all exports from a module.
|
|
14
|
+
Returns structured JSON with default export, named exports, and re-exports.
|
|
15
|
+
Use this to understand what a module exposes to other modules.`;
|
|
16
|
+
// Tool input schema
|
|
17
|
+
const TOOL_INPUT_SCHEMA = {
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
path: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
description: 'File to analyze',
|
|
23
|
+
},
|
|
24
|
+
includeReExports: {
|
|
25
|
+
type: 'boolean',
|
|
26
|
+
description: 'Include re-exports (default: true)',
|
|
27
|
+
default: true,
|
|
28
|
+
},
|
|
29
|
+
resolveReExports: {
|
|
30
|
+
type: 'boolean',
|
|
31
|
+
description: 'Resolve re-exports to original source (default: false)',
|
|
32
|
+
default: false,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
required: ['path'],
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* getExports tool - Get all exports from a module
|
|
39
|
+
*/
|
|
40
|
+
export const getExportsTool = defineTool({
|
|
41
|
+
name: 'get_exports',
|
|
42
|
+
description: TOOL_DESCRIPTION,
|
|
43
|
+
inputSchema: TOOL_INPUT_SCHEMA,
|
|
44
|
+
execute: executeGetExports,
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* Execute the getExports tool
|
|
48
|
+
*/
|
|
49
|
+
async function executeGetExports(input) {
|
|
50
|
+
const { path: inputPath, includeReExports = true, resolveReExports = false } = input;
|
|
51
|
+
// Validate input
|
|
52
|
+
if (!inputPath || inputPath.trim().length === 0) {
|
|
53
|
+
return createErrorResult('Path is required');
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
// Check if path exists
|
|
57
|
+
try {
|
|
58
|
+
await fs.access(inputPath);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return createErrorResult(`Path not found: ${inputPath}`);
|
|
62
|
+
}
|
|
63
|
+
const stats = await fs.stat(inputPath);
|
|
64
|
+
if (!stats.isFile()) {
|
|
65
|
+
return createErrorResult(`Path must be a file: ${inputPath}`);
|
|
66
|
+
}
|
|
67
|
+
// Check for supported language
|
|
68
|
+
const detection = detectLanguage(inputPath);
|
|
69
|
+
if (!detection.language || !isLanguageSupported(detection.language)) {
|
|
70
|
+
return createErrorResult(`Unsupported file type: ${path.extname(inputPath)}`);
|
|
71
|
+
}
|
|
72
|
+
// Analyze the file
|
|
73
|
+
const { defaultExport, namedExports, reExports } = await analyzeFileExports(inputPath, includeReExports, resolveReExports);
|
|
74
|
+
// Calculate statistics
|
|
75
|
+
const exportStats = {
|
|
76
|
+
totalExports: namedExports.length + (defaultExport ? 1 : 0),
|
|
77
|
+
functions: namedExports.filter((e) => e.kind === 'function').length,
|
|
78
|
+
classes: namedExports.filter((e) => e.kind === 'class').length,
|
|
79
|
+
types: namedExports.filter((e) => e.kind === 'type' || e.kind === 'interface').length,
|
|
80
|
+
variables: namedExports.filter((e) => e.kind === 'variable').length,
|
|
81
|
+
reExports: reExports?.length ?? 0,
|
|
82
|
+
};
|
|
83
|
+
const result = {
|
|
84
|
+
path: inputPath,
|
|
85
|
+
defaultExport,
|
|
86
|
+
namedExports,
|
|
87
|
+
reExports: includeReExports && reExports && reExports.length > 0 ? reExports : undefined,
|
|
88
|
+
stats: exportStats,
|
|
89
|
+
};
|
|
90
|
+
return createSuccessResult(result);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
94
|
+
return createErrorResult(`Failed to analyze exports: ${message}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Analyze exports in a single file
|
|
99
|
+
*/
|
|
100
|
+
async function analyzeFileExports(filePath, includeReExports, resolveReExports) {
|
|
101
|
+
const namedExports = [];
|
|
102
|
+
const reExports = [];
|
|
103
|
+
let defaultExport;
|
|
104
|
+
try {
|
|
105
|
+
const sourceCode = await fs.readFile(filePath, 'utf-8');
|
|
106
|
+
const scriptKind = getScriptKind(filePath);
|
|
107
|
+
const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true, scriptKind);
|
|
108
|
+
const fileDir = path.dirname(filePath);
|
|
109
|
+
ts.forEachChild(sourceFile, (node) => {
|
|
110
|
+
// Handle export declarations
|
|
111
|
+
if (ts.isExportDeclaration(node)) {
|
|
112
|
+
const result = extractExportDeclaration(node, sourceFile, fileDir, resolveReExports);
|
|
113
|
+
if (result.reExport) {
|
|
114
|
+
reExports.push(result.reExport);
|
|
115
|
+
}
|
|
116
|
+
namedExports.push(...result.exports);
|
|
117
|
+
}
|
|
118
|
+
// Handle export assignment (export default ...)
|
|
119
|
+
else if (ts.isExportAssignment(node)) {
|
|
120
|
+
defaultExport = extractExportAssignment(node, sourceFile);
|
|
121
|
+
}
|
|
122
|
+
// Handle exported declarations (export function, export class, etc.)
|
|
123
|
+
else if (hasExportModifier(node)) {
|
|
124
|
+
const exported = extractExportedDeclaration(node, sourceFile);
|
|
125
|
+
if (exported) {
|
|
126
|
+
if (exported.isDefault) {
|
|
127
|
+
defaultExport = exported.symbol;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
namedExports.push(exported.symbol);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// Silently skip files that can't be parsed
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
defaultExport,
|
|
141
|
+
namedExports,
|
|
142
|
+
reExports: includeReExports ? reExports : undefined,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Check if a node has export modifier
|
|
147
|
+
*/
|
|
148
|
+
function hasExportModifier(node) {
|
|
149
|
+
const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
|
|
150
|
+
return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Check if a node has default modifier
|
|
154
|
+
*/
|
|
155
|
+
function hasDefaultModifier(node) {
|
|
156
|
+
const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
|
|
157
|
+
return modifiers?.some((m) => m.kind === ts.SyntaxKind.DefaultKeyword) ?? false;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Extract export declaration (export { ... } or export * from ...)
|
|
161
|
+
*/
|
|
162
|
+
function extractExportDeclaration(node, sourceFile, fileDir, resolveReExports) {
|
|
163
|
+
const exports = [];
|
|
164
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
165
|
+
const lineNum = line + 1;
|
|
166
|
+
// Check for type-only export
|
|
167
|
+
const typeOnly = node.isTypeOnly;
|
|
168
|
+
// Re-export from another module
|
|
169
|
+
if (node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {
|
|
170
|
+
const from = node.moduleSpecifier.text;
|
|
171
|
+
const resolvedFrom = resolveReExports ? resolveLocalImport(from, fileDir) : undefined;
|
|
172
|
+
// export * from '...'
|
|
173
|
+
if (!node.exportClause) {
|
|
174
|
+
return {
|
|
175
|
+
exports: [],
|
|
176
|
+
reExport: {
|
|
177
|
+
symbols: '*',
|
|
178
|
+
from,
|
|
179
|
+
resolvedFrom,
|
|
180
|
+
line: lineNum,
|
|
181
|
+
typeOnly,
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
// export { a, b } from '...'
|
|
186
|
+
if (ts.isNamedExports(node.exportClause)) {
|
|
187
|
+
const symbols = [];
|
|
188
|
+
for (const element of node.exportClause.elements) {
|
|
189
|
+
const name = element.name.text;
|
|
190
|
+
symbols.push(name);
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
exports: [],
|
|
194
|
+
reExport: {
|
|
195
|
+
symbols,
|
|
196
|
+
from,
|
|
197
|
+
resolvedFrom,
|
|
198
|
+
line: lineNum,
|
|
199
|
+
typeOnly,
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
// export * as ns from '...'
|
|
204
|
+
if (ts.isNamespaceExport(node.exportClause)) {
|
|
205
|
+
return {
|
|
206
|
+
exports: [],
|
|
207
|
+
reExport: {
|
|
208
|
+
symbols: '*',
|
|
209
|
+
from,
|
|
210
|
+
resolvedFrom,
|
|
211
|
+
line: lineNum,
|
|
212
|
+
typeOnly,
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Local named exports: export { a, b }
|
|
218
|
+
if (node.exportClause && ts.isNamedExports(node.exportClause)) {
|
|
219
|
+
for (const element of node.exportClause.elements) {
|
|
220
|
+
const name = element.name.text;
|
|
221
|
+
exports.push({
|
|
222
|
+
name,
|
|
223
|
+
kind: 'unknown',
|
|
224
|
+
line: lineNum,
|
|
225
|
+
typeOnly,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return { exports };
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Extract export assignment (export default ...)
|
|
233
|
+
*/
|
|
234
|
+
function extractExportAssignment(node, sourceFile) {
|
|
235
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
236
|
+
const expr = node.expression;
|
|
237
|
+
let name = 'default';
|
|
238
|
+
let kind = 'unknown';
|
|
239
|
+
if (ts.isIdentifier(expr)) {
|
|
240
|
+
name = expr.text;
|
|
241
|
+
}
|
|
242
|
+
else if (ts.isClassExpression(expr)) {
|
|
243
|
+
kind = 'class';
|
|
244
|
+
if (expr.name) {
|
|
245
|
+
name = expr.name.text;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
else if (ts.isFunctionExpression(expr) || ts.isArrowFunction(expr)) {
|
|
249
|
+
kind = 'function';
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
name,
|
|
253
|
+
kind,
|
|
254
|
+
line: line + 1,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Extract exported declaration
|
|
259
|
+
*/
|
|
260
|
+
function extractExportedDeclaration(node, sourceFile) {
|
|
261
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
262
|
+
const lineNum = line + 1;
|
|
263
|
+
const isDefault = hasDefaultModifier(node);
|
|
264
|
+
// Function declaration
|
|
265
|
+
if (ts.isFunctionDeclaration(node)) {
|
|
266
|
+
const name = node.name?.text ?? 'default';
|
|
267
|
+
const signature = extractFunctionSignature(node, sourceFile);
|
|
268
|
+
return {
|
|
269
|
+
symbol: {
|
|
270
|
+
name,
|
|
271
|
+
kind: 'function',
|
|
272
|
+
line: lineNum,
|
|
273
|
+
signature,
|
|
274
|
+
},
|
|
275
|
+
isDefault,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
// Class declaration
|
|
279
|
+
if (ts.isClassDeclaration(node)) {
|
|
280
|
+
const name = node.name?.text ?? 'default';
|
|
281
|
+
return {
|
|
282
|
+
symbol: {
|
|
283
|
+
name,
|
|
284
|
+
kind: 'class',
|
|
285
|
+
line: lineNum,
|
|
286
|
+
},
|
|
287
|
+
isDefault,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
// Interface declaration
|
|
291
|
+
if (ts.isInterfaceDeclaration(node)) {
|
|
292
|
+
return {
|
|
293
|
+
symbol: {
|
|
294
|
+
name: node.name.text,
|
|
295
|
+
kind: 'interface',
|
|
296
|
+
line: lineNum,
|
|
297
|
+
typeOnly: true,
|
|
298
|
+
},
|
|
299
|
+
isDefault: false,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
// Type alias declaration
|
|
303
|
+
if (ts.isTypeAliasDeclaration(node)) {
|
|
304
|
+
return {
|
|
305
|
+
symbol: {
|
|
306
|
+
name: node.name.text,
|
|
307
|
+
kind: 'type',
|
|
308
|
+
line: lineNum,
|
|
309
|
+
typeOnly: true,
|
|
310
|
+
},
|
|
311
|
+
isDefault: false,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
// Enum declaration
|
|
315
|
+
if (ts.isEnumDeclaration(node)) {
|
|
316
|
+
return {
|
|
317
|
+
symbol: {
|
|
318
|
+
name: node.name.text,
|
|
319
|
+
kind: 'enum',
|
|
320
|
+
line: lineNum,
|
|
321
|
+
},
|
|
322
|
+
isDefault: false,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
// Variable statement (export const x = ...)
|
|
326
|
+
if (ts.isVariableStatement(node)) {
|
|
327
|
+
const decls = node.declarationList.declarations;
|
|
328
|
+
if (decls.length > 0) {
|
|
329
|
+
const firstDecl = decls[0];
|
|
330
|
+
if (ts.isIdentifier(firstDecl.name)) {
|
|
331
|
+
const kind = node.declarationList.flags & ts.NodeFlags.Const ? 'variable' : 'variable';
|
|
332
|
+
return {
|
|
333
|
+
symbol: {
|
|
334
|
+
name: firstDecl.name.text,
|
|
335
|
+
kind,
|
|
336
|
+
line: lineNum,
|
|
337
|
+
},
|
|
338
|
+
isDefault: false,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// Module/namespace declaration
|
|
344
|
+
if (ts.isModuleDeclaration(node)) {
|
|
345
|
+
return {
|
|
346
|
+
symbol: {
|
|
347
|
+
name: node.name.getText(sourceFile),
|
|
348
|
+
kind: 'namespace',
|
|
349
|
+
line: lineNum,
|
|
350
|
+
},
|
|
351
|
+
isDefault: false,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Extract function signature
|
|
358
|
+
*/
|
|
359
|
+
function extractFunctionSignature(node, sourceFile) {
|
|
360
|
+
const name = node.name?.text ?? 'anonymous';
|
|
361
|
+
const params = node.parameters.map((p) => {
|
|
362
|
+
const paramName = p.name.getText(sourceFile);
|
|
363
|
+
const paramType = p.type ? p.type.getText(sourceFile) : 'any';
|
|
364
|
+
const optional = p.questionToken ? '?' : '';
|
|
365
|
+
return `${paramName}${optional}: ${paramType}`;
|
|
366
|
+
});
|
|
367
|
+
const returnType = node.type ? node.type.getText(sourceFile) : 'void';
|
|
368
|
+
const async = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ? 'async ' : '';
|
|
369
|
+
return `${async}function ${name}(${params.join(', ')}): ${returnType}`;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Try to resolve a local import path
|
|
373
|
+
*/
|
|
374
|
+
function resolveLocalImport(source, fromDir) {
|
|
375
|
+
if (!source.startsWith('.') && !source.startsWith('/')) {
|
|
376
|
+
return undefined; // External package
|
|
377
|
+
}
|
|
378
|
+
const basePath = path.resolve(fromDir, source);
|
|
379
|
+
// First try exact match for paths that already have extensions
|
|
380
|
+
if (basePath.match(/\.(ts|tsx|js|jsx|mts|mjs|cts|cjs)$/)) {
|
|
381
|
+
return basePath;
|
|
382
|
+
}
|
|
383
|
+
// Try with most likely TypeScript extensions first
|
|
384
|
+
return basePath + '.ts';
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Get TypeScript script kind from file extension
|
|
388
|
+
*/
|
|
389
|
+
function getScriptKind(filePath) {
|
|
390
|
+
const ext = filePath.toLowerCase().split('.').pop();
|
|
391
|
+
switch (ext) {
|
|
392
|
+
case 'ts':
|
|
393
|
+
return ts.ScriptKind.TS;
|
|
394
|
+
case 'tsx':
|
|
395
|
+
return ts.ScriptKind.TSX;
|
|
396
|
+
case 'js':
|
|
397
|
+
return ts.ScriptKind.JS;
|
|
398
|
+
case 'jsx':
|
|
399
|
+
return ts.ScriptKind.JSX;
|
|
400
|
+
case 'mts':
|
|
401
|
+
case 'cts':
|
|
402
|
+
return ts.ScriptKind.TS;
|
|
403
|
+
case 'mjs':
|
|
404
|
+
case 'cjs':
|
|
405
|
+
return ts.ScriptKind.JS;
|
|
406
|
+
default:
|
|
407
|
+
return ts.ScriptKind.TS;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Factory function to create a customized getExports tool
|
|
412
|
+
*/
|
|
413
|
+
export function createGetExportsTool(options) {
|
|
414
|
+
const { defaultIncludeReExports = true, defaultResolveReExports = false } = options ?? {};
|
|
415
|
+
return defineTool({
|
|
416
|
+
name: 'get_exports',
|
|
417
|
+
description: TOOL_DESCRIPTION,
|
|
418
|
+
inputSchema: TOOL_INPUT_SCHEMA,
|
|
419
|
+
execute: async (input) => {
|
|
420
|
+
return executeGetExports({
|
|
421
|
+
...input,
|
|
422
|
+
includeReExports: input.includeReExports ?? defaultIncludeReExports,
|
|
423
|
+
resolveReExports: input.resolveReExports ?? defaultResolveReExports,
|
|
424
|
+
});
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* getFileStructure Tool
|
|
3
|
+
*
|
|
4
|
+
* Analyzes a source file and returns its structural overview:
|
|
5
|
+
* - Imports and exports
|
|
6
|
+
* - Classes with methods and properties
|
|
7
|
+
* - Functions
|
|
8
|
+
* - Variables and constants
|
|
9
|
+
* - Type definitions
|
|
10
|
+
*
|
|
11
|
+
* Uses TypeScript Compiler API for accurate analysis.
|
|
12
|
+
*/
|
|
13
|
+
import type { Tool } from '@compilr-dev/agents';
|
|
14
|
+
import type { GetFileStructureInput } from './types.js';
|
|
15
|
+
/**
|
|
16
|
+
* getFileStructure tool - Analyze source file structure
|
|
17
|
+
*/
|
|
18
|
+
export declare const getFileStructureTool: Tool<GetFileStructureInput>;
|
|
19
|
+
/**
|
|
20
|
+
* Factory function to create a customized getFileStructure tool
|
|
21
|
+
*/
|
|
22
|
+
export declare function createGetFileStructureTool(options?: {
|
|
23
|
+
/** Default maxDepth */
|
|
24
|
+
defaultMaxDepth?: number;
|
|
25
|
+
/** Default includePrivate */
|
|
26
|
+
defaultIncludePrivate?: boolean;
|
|
27
|
+
}): Tool<GetFileStructureInput>;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* getFileStructure Tool
|
|
3
|
+
*
|
|
4
|
+
* Analyzes a source file and returns its structural overview:
|
|
5
|
+
* - Imports and exports
|
|
6
|
+
* - Classes with methods and properties
|
|
7
|
+
* - Functions
|
|
8
|
+
* - Variables and constants
|
|
9
|
+
* - Type definitions
|
|
10
|
+
*
|
|
11
|
+
* Uses TypeScript Compiler API for accurate analysis.
|
|
12
|
+
*/
|
|
13
|
+
import * as fs from 'node:fs/promises';
|
|
14
|
+
import * as path from 'node:path';
|
|
15
|
+
import { defineTool, createSuccessResult, createErrorResult } from '@compilr-dev/agents';
|
|
16
|
+
import { parseTypeScript, detectLanguage, isLanguageSupported } from '../parser/typescript-parser.js';
|
|
17
|
+
// Tool description (shared between tool and factory)
|
|
18
|
+
const TOOL_DESCRIPTION = `Analyze a source file and return its structural overview including imports, exports, classes, functions, and types.
|
|
19
|
+
Use this instead of reading the full file when you need to understand what a file contains.
|
|
20
|
+
Returns structured JSON that's much more compact than raw source code.`;
|
|
21
|
+
// Tool input schema (shared between tool and factory)
|
|
22
|
+
const TOOL_INPUT_SCHEMA = {
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
path: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
description: 'Absolute path to the file to analyze',
|
|
28
|
+
},
|
|
29
|
+
maxDepth: {
|
|
30
|
+
type: 'number',
|
|
31
|
+
description: 'Maximum depth for nested structures (default: 2)',
|
|
32
|
+
default: 2,
|
|
33
|
+
},
|
|
34
|
+
includePrivate: {
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
description: 'Include private/internal symbols (default: true)',
|
|
37
|
+
default: true,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
required: ['path'],
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* getFileStructure tool - Analyze source file structure
|
|
44
|
+
*/
|
|
45
|
+
export const getFileStructureTool = defineTool({
|
|
46
|
+
name: 'get_file_structure',
|
|
47
|
+
description: TOOL_DESCRIPTION,
|
|
48
|
+
inputSchema: TOOL_INPUT_SCHEMA,
|
|
49
|
+
execute: executeGetFileStructure,
|
|
50
|
+
});
|
|
51
|
+
/**
|
|
52
|
+
* Execute the getFileStructure tool
|
|
53
|
+
*/
|
|
54
|
+
async function executeGetFileStructure(input) {
|
|
55
|
+
const { path: filePath, maxDepth = 2, includePrivate = true } = input;
|
|
56
|
+
// Validate input
|
|
57
|
+
if (!filePath || filePath.trim().length === 0) {
|
|
58
|
+
return createErrorResult('File path is required');
|
|
59
|
+
}
|
|
60
|
+
// Check if file exists
|
|
61
|
+
try {
|
|
62
|
+
await fs.access(filePath);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return createErrorResult(`File not found: ${filePath}`);
|
|
66
|
+
}
|
|
67
|
+
// Check if it's a file (not directory)
|
|
68
|
+
const stats = await fs.stat(filePath);
|
|
69
|
+
if (!stats.isFile()) {
|
|
70
|
+
return createErrorResult(`Path is not a file: ${filePath}`);
|
|
71
|
+
}
|
|
72
|
+
// Detect language
|
|
73
|
+
const detection = detectLanguage(filePath);
|
|
74
|
+
if (!detection.language) {
|
|
75
|
+
return createErrorResult(`Unsupported file type: ${path.extname(filePath)}`);
|
|
76
|
+
}
|
|
77
|
+
// Check if language is supported
|
|
78
|
+
if (!isLanguageSupported(detection.language)) {
|
|
79
|
+
return createErrorResult(`No parser available for language: ${detection.language}`);
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
// Read file content
|
|
83
|
+
const sourceCode = await fs.readFile(filePath, 'utf-8');
|
|
84
|
+
// Parse and extract structure
|
|
85
|
+
const structure = parseTypeScript(sourceCode, filePath, {
|
|
86
|
+
maxDepth,
|
|
87
|
+
includePrivate,
|
|
88
|
+
});
|
|
89
|
+
// Build full result
|
|
90
|
+
const result = {
|
|
91
|
+
path: filePath,
|
|
92
|
+
language: detection.language,
|
|
93
|
+
languageConfidence: detection.confidence,
|
|
94
|
+
...structure,
|
|
95
|
+
};
|
|
96
|
+
return createSuccessResult(result);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
100
|
+
return createErrorResult(`Failed to analyze file: ${message}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Factory function to create a customized getFileStructure tool
|
|
105
|
+
*/
|
|
106
|
+
export function createGetFileStructureTool(options) {
|
|
107
|
+
const { defaultMaxDepth = 2, defaultIncludePrivate = true } = options ?? {};
|
|
108
|
+
return defineTool({
|
|
109
|
+
name: 'get_file_structure',
|
|
110
|
+
description: TOOL_DESCRIPTION,
|
|
111
|
+
inputSchema: TOOL_INPUT_SCHEMA,
|
|
112
|
+
execute: async (input) => {
|
|
113
|
+
return executeGetFileStructure({
|
|
114
|
+
...input,
|
|
115
|
+
maxDepth: input.maxDepth ?? defaultMaxDepth,
|
|
116
|
+
includePrivate: input.includePrivate ?? defaultIncludePrivate,
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* getImports Tool
|
|
3
|
+
*
|
|
4
|
+
* Get detailed import information for a file or module.
|
|
5
|
+
* Uses TypeScript Compiler API for accurate AST analysis.
|
|
6
|
+
*/
|
|
7
|
+
import type { Tool } from '@compilr-dev/agents';
|
|
8
|
+
import type { GetImportsInput } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* getImports tool - Get detailed import information
|
|
11
|
+
*/
|
|
12
|
+
export declare const getImportsTool: Tool<GetImportsInput>;
|
|
13
|
+
/**
|
|
14
|
+
* Factory function to create a customized getImports tool
|
|
15
|
+
*/
|
|
16
|
+
export declare function createGetImportsTool(options?: {
|
|
17
|
+
/** Default recursive */
|
|
18
|
+
defaultRecursive?: boolean;
|
|
19
|
+
/** Default transitive */
|
|
20
|
+
defaultTransitive?: boolean;
|
|
21
|
+
/** Default maxDepth */
|
|
22
|
+
defaultMaxDepth?: number;
|
|
23
|
+
}): Tool<GetImportsInput>;
|