@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,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* getTypeHierarchy Tool
|
|
3
|
+
*
|
|
4
|
+
* Analyze the inheritance hierarchy of a class or interface.
|
|
5
|
+
* Shows ancestors (parents) and descendants (children) in the type tree.
|
|
6
|
+
*/
|
|
7
|
+
import type { Tool } from '@compilr-dev/agents';
|
|
8
|
+
import type { GetTypeHierarchyInput, HierarchyDirection } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* getTypeHierarchy tool - Analyze type inheritance
|
|
11
|
+
*/
|
|
12
|
+
export declare const getTypeHierarchyTool: Tool<GetTypeHierarchyInput>;
|
|
13
|
+
/**
|
|
14
|
+
* Create customizable getTypeHierarchy tool
|
|
15
|
+
*/
|
|
16
|
+
export declare function createGetTypeHierarchyTool(options?: {
|
|
17
|
+
name?: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
defaultDirection?: HierarchyDirection;
|
|
20
|
+
defaultMaxDepth?: number;
|
|
21
|
+
defaultScope?: string;
|
|
22
|
+
}): Tool<GetTypeHierarchyInput>;
|
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* getTypeHierarchy Tool
|
|
3
|
+
*
|
|
4
|
+
* Analyze the inheritance hierarchy of a class or interface.
|
|
5
|
+
* Shows ancestors (parents) and descendants (children) in the type tree.
|
|
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 = `Analyze the inheritance hierarchy of a class or interface.
|
|
14
|
+
Returns the type's ancestors (what it extends/implements) and descendants (what extends/implements it).
|
|
15
|
+
Useful for understanding class hierarchies and interface relationships.`;
|
|
16
|
+
// Tool input schema
|
|
17
|
+
const TOOL_INPUT_SCHEMA = {
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
name: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
description: 'Class or interface name to analyze',
|
|
23
|
+
},
|
|
24
|
+
file: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: 'File where the type is defined (improves accuracy)',
|
|
27
|
+
},
|
|
28
|
+
direction: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
enum: ['ancestors', 'descendants', 'both'],
|
|
31
|
+
description: 'Direction: "ancestors" | "descendants" | "both" (default: "both")',
|
|
32
|
+
default: 'both',
|
|
33
|
+
},
|
|
34
|
+
maxDepth: {
|
|
35
|
+
type: 'number',
|
|
36
|
+
description: 'Maximum depth to traverse (default: 5)',
|
|
37
|
+
default: 5,
|
|
38
|
+
},
|
|
39
|
+
scope: {
|
|
40
|
+
type: 'string',
|
|
41
|
+
description: 'Scope directory for searching descendants (default: current directory)',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
required: ['name'],
|
|
45
|
+
};
|
|
46
|
+
// Default file patterns
|
|
47
|
+
const DEFAULT_INCLUDE = ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'];
|
|
48
|
+
const DEFAULT_EXCLUDE = ['**/node_modules/**', '**/dist/**', '**/build/**', '**/.git/**'];
|
|
49
|
+
/**
|
|
50
|
+
* getTypeHierarchy tool - Analyze type inheritance
|
|
51
|
+
*/
|
|
52
|
+
export const getTypeHierarchyTool = defineTool({
|
|
53
|
+
name: 'get_type_hierarchy',
|
|
54
|
+
description: TOOL_DESCRIPTION,
|
|
55
|
+
inputSchema: TOOL_INPUT_SCHEMA,
|
|
56
|
+
execute: executeGetTypeHierarchy,
|
|
57
|
+
});
|
|
58
|
+
/**
|
|
59
|
+
* Execute the getTypeHierarchy tool
|
|
60
|
+
*/
|
|
61
|
+
async function executeGetTypeHierarchy(input) {
|
|
62
|
+
const { name, file, direction = 'both', maxDepth = 5, scope = '.' } = input;
|
|
63
|
+
// Validate input
|
|
64
|
+
if (!name || name.trim().length === 0) {
|
|
65
|
+
return createErrorResult('Type name is required');
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
// Resolve scope path
|
|
69
|
+
const scopePath = path.resolve(scope);
|
|
70
|
+
// Check if scope exists
|
|
71
|
+
try {
|
|
72
|
+
await fs.access(scopePath);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return createErrorResult(`Scope path not found: ${scopePath}`);
|
|
76
|
+
}
|
|
77
|
+
const stats = await fs.stat(scopePath);
|
|
78
|
+
// Collect files to search
|
|
79
|
+
const files = stats.isDirectory()
|
|
80
|
+
? await collectFiles(scopePath, DEFAULT_INCLUDE, DEFAULT_EXCLUDE, 10, 500)
|
|
81
|
+
: [scopePath];
|
|
82
|
+
// Build type information map
|
|
83
|
+
const typeMap = new Map();
|
|
84
|
+
let filesSearched = 0;
|
|
85
|
+
for (const filePath of files) {
|
|
86
|
+
const types = await extractTypeInfo(filePath);
|
|
87
|
+
filesSearched++;
|
|
88
|
+
for (const typeInfo of types) {
|
|
89
|
+
// If there's a specific file, prioritize that definition
|
|
90
|
+
if (typeInfo.name === name && file && filePath === path.resolve(file)) {
|
|
91
|
+
typeMap.set(typeInfo.name, typeInfo);
|
|
92
|
+
}
|
|
93
|
+
else if (!typeMap.has(typeInfo.name)) {
|
|
94
|
+
typeMap.set(typeInfo.name, typeInfo);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Find the target type
|
|
99
|
+
let targetType = typeMap.get(name);
|
|
100
|
+
// If file is specified, try to find in that specific file
|
|
101
|
+
if (file) {
|
|
102
|
+
const resolvedFile = path.resolve(file);
|
|
103
|
+
try {
|
|
104
|
+
await fs.access(resolvedFile);
|
|
105
|
+
const types = await extractTypeInfo(resolvedFile);
|
|
106
|
+
const foundType = types.find((t) => t.name === name);
|
|
107
|
+
if (foundType) {
|
|
108
|
+
targetType = foundType;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Ignore file access error
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (!targetType) {
|
|
116
|
+
// Return empty result if type not found
|
|
117
|
+
const emptyRoot = {
|
|
118
|
+
name,
|
|
119
|
+
path: '',
|
|
120
|
+
line: 0,
|
|
121
|
+
kind: 'class',
|
|
122
|
+
exported: false,
|
|
123
|
+
};
|
|
124
|
+
const result = {
|
|
125
|
+
root: emptyRoot,
|
|
126
|
+
allTypes: [],
|
|
127
|
+
stats: {
|
|
128
|
+
totalTypes: 0,
|
|
129
|
+
maxDepthReached: 0,
|
|
130
|
+
filesSearched,
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
return createSuccessResult(result);
|
|
134
|
+
}
|
|
135
|
+
// Build hierarchy based on direction
|
|
136
|
+
const allTypes = [];
|
|
137
|
+
let maxDepthReached = 0;
|
|
138
|
+
const rootNode = createTypeNode(targetType);
|
|
139
|
+
if (direction === 'ancestors' || direction === 'both') {
|
|
140
|
+
const { ancestors, depth } = buildAncestors(targetType, typeMap, maxDepth, 0);
|
|
141
|
+
rootNode.parents = ancestors;
|
|
142
|
+
if (depth > maxDepthReached)
|
|
143
|
+
maxDepthReached = depth;
|
|
144
|
+
}
|
|
145
|
+
if (direction === 'descendants' || direction === 'both') {
|
|
146
|
+
const { descendants, depth } = buildDescendants(targetType, typeMap, maxDepth, 0);
|
|
147
|
+
rootNode.children = descendants;
|
|
148
|
+
if (depth > maxDepthReached)
|
|
149
|
+
maxDepthReached = depth;
|
|
150
|
+
}
|
|
151
|
+
// Collect all types in the hierarchy
|
|
152
|
+
collectAllTypes(rootNode, allTypes);
|
|
153
|
+
const result = {
|
|
154
|
+
root: rootNode,
|
|
155
|
+
allTypes,
|
|
156
|
+
stats: {
|
|
157
|
+
totalTypes: allTypes.length,
|
|
158
|
+
maxDepthReached,
|
|
159
|
+
filesSearched,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
return createSuccessResult(result);
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
return createErrorResult(`Failed to get type hierarchy: ${error instanceof Error ? error.message : String(error)}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Create a TypeHierarchyNode from TypeInfo
|
|
170
|
+
*/
|
|
171
|
+
function createTypeNode(info) {
|
|
172
|
+
return {
|
|
173
|
+
name: info.name,
|
|
174
|
+
path: info.path,
|
|
175
|
+
line: info.line,
|
|
176
|
+
kind: info.kind,
|
|
177
|
+
isAbstract: info.isAbstract,
|
|
178
|
+
exported: info.exported,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Build ancestor hierarchy (parents, grandparents, etc.)
|
|
183
|
+
*/
|
|
184
|
+
function buildAncestors(type, typeMap, maxDepth, currentDepth) {
|
|
185
|
+
if (currentDepth >= maxDepth) {
|
|
186
|
+
return { ancestors: [], depth: currentDepth };
|
|
187
|
+
}
|
|
188
|
+
const ancestors = [];
|
|
189
|
+
let maxDepthReached = currentDepth;
|
|
190
|
+
// Get parent types from extends and implements
|
|
191
|
+
const parentNames = [];
|
|
192
|
+
if (type.extends) {
|
|
193
|
+
parentNames.push(...type.extends);
|
|
194
|
+
}
|
|
195
|
+
if (type.implements) {
|
|
196
|
+
parentNames.push(...type.implements);
|
|
197
|
+
}
|
|
198
|
+
for (const parentName of parentNames) {
|
|
199
|
+
const parentInfo = typeMap.get(parentName);
|
|
200
|
+
if (parentInfo) {
|
|
201
|
+
const parentNode = createTypeNode(parentInfo);
|
|
202
|
+
// Recursively build ancestors for this parent
|
|
203
|
+
const { ancestors: grandparents, depth } = buildAncestors(parentInfo, typeMap, maxDepth, currentDepth + 1);
|
|
204
|
+
if (grandparents.length > 0) {
|
|
205
|
+
parentNode.parents = grandparents;
|
|
206
|
+
}
|
|
207
|
+
if (depth > maxDepthReached) {
|
|
208
|
+
maxDepthReached = depth;
|
|
209
|
+
}
|
|
210
|
+
ancestors.push(parentNode);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
// External type (not found in codebase)
|
|
214
|
+
ancestors.push({
|
|
215
|
+
name: parentName,
|
|
216
|
+
path: '',
|
|
217
|
+
line: 0,
|
|
218
|
+
kind: 'interface', // Assume interface for unknown types
|
|
219
|
+
exported: true,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return { ancestors, depth: maxDepthReached };
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Build descendant hierarchy (children, grandchildren, etc.)
|
|
227
|
+
*/
|
|
228
|
+
function buildDescendants(type, typeMap, maxDepth, currentDepth) {
|
|
229
|
+
if (currentDepth >= maxDepth) {
|
|
230
|
+
return { descendants: [], depth: currentDepth };
|
|
231
|
+
}
|
|
232
|
+
const descendants = [];
|
|
233
|
+
let maxDepthReached = currentDepth;
|
|
234
|
+
// Find all types that extend or implement this type
|
|
235
|
+
for (const [, info] of typeMap) {
|
|
236
|
+
const isChild = (info.extends && info.extends.includes(type.name)) ||
|
|
237
|
+
(info.implements && info.implements.includes(type.name));
|
|
238
|
+
if (isChild) {
|
|
239
|
+
const childNode = createTypeNode(info);
|
|
240
|
+
// Recursively build descendants for this child
|
|
241
|
+
const { descendants: grandchildren, depth } = buildDescendants(info, typeMap, maxDepth, currentDepth + 1);
|
|
242
|
+
if (grandchildren.length > 0) {
|
|
243
|
+
childNode.children = grandchildren;
|
|
244
|
+
}
|
|
245
|
+
if (depth > maxDepthReached) {
|
|
246
|
+
maxDepthReached = depth;
|
|
247
|
+
}
|
|
248
|
+
descendants.push(childNode);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return { descendants, depth: maxDepthReached };
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Collect all types from the hierarchy tree into a flat list
|
|
255
|
+
*/
|
|
256
|
+
function collectAllTypes(node, allTypes) {
|
|
257
|
+
// Avoid duplicates
|
|
258
|
+
if (!allTypes.find((t) => t.name === node.name && t.path === node.path)) {
|
|
259
|
+
// Create a copy without circular references for the flat list
|
|
260
|
+
const flatNode = {
|
|
261
|
+
name: node.name,
|
|
262
|
+
path: node.path,
|
|
263
|
+
line: node.line,
|
|
264
|
+
kind: node.kind,
|
|
265
|
+
isAbstract: node.isAbstract,
|
|
266
|
+
exported: node.exported,
|
|
267
|
+
};
|
|
268
|
+
allTypes.push(flatNode);
|
|
269
|
+
}
|
|
270
|
+
// Recursively collect from parents
|
|
271
|
+
if (node.parents) {
|
|
272
|
+
for (const parent of node.parents) {
|
|
273
|
+
collectAllTypes(parent, allTypes);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
// Recursively collect from children
|
|
277
|
+
if (node.children) {
|
|
278
|
+
for (const child of node.children) {
|
|
279
|
+
collectAllTypes(child, allTypes);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Extract type information from a file
|
|
285
|
+
*/
|
|
286
|
+
async function extractTypeInfo(filePath) {
|
|
287
|
+
try {
|
|
288
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
289
|
+
const detection = detectLanguage(filePath);
|
|
290
|
+
if (!detection.language) {
|
|
291
|
+
return [];
|
|
292
|
+
}
|
|
293
|
+
if (!isLanguageSupported(detection.language)) {
|
|
294
|
+
return [];
|
|
295
|
+
}
|
|
296
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, filePath.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
|
|
297
|
+
const types = [];
|
|
298
|
+
const visit = (node) => {
|
|
299
|
+
// Class declarations
|
|
300
|
+
if (ts.isClassDeclaration(node) && node.name) {
|
|
301
|
+
const info = extractClassInfo(node, sourceFile, filePath);
|
|
302
|
+
if (info)
|
|
303
|
+
types.push(info);
|
|
304
|
+
}
|
|
305
|
+
// Interface declarations
|
|
306
|
+
if (ts.isInterfaceDeclaration(node)) {
|
|
307
|
+
const info = extractInterfaceInfo(node, sourceFile, filePath);
|
|
308
|
+
if (info)
|
|
309
|
+
types.push(info);
|
|
310
|
+
}
|
|
311
|
+
// Type alias declarations (only if they reference other types)
|
|
312
|
+
if (ts.isTypeAliasDeclaration(node)) {
|
|
313
|
+
const info = extractTypeAliasInfo(node, sourceFile, filePath);
|
|
314
|
+
if (info)
|
|
315
|
+
types.push(info);
|
|
316
|
+
}
|
|
317
|
+
ts.forEachChild(node, visit);
|
|
318
|
+
};
|
|
319
|
+
visit(sourceFile);
|
|
320
|
+
return types;
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
return [];
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Extract class type info
|
|
328
|
+
*/
|
|
329
|
+
function extractClassInfo(node, sourceFile, filePath) {
|
|
330
|
+
if (!node.name)
|
|
331
|
+
return null;
|
|
332
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
333
|
+
const isExported = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
334
|
+
const isAbstract = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AbstractKeyword) ?? false;
|
|
335
|
+
const extendsTypes = [];
|
|
336
|
+
const implementsTypes = [];
|
|
337
|
+
if (node.heritageClauses) {
|
|
338
|
+
for (const clause of node.heritageClauses) {
|
|
339
|
+
if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
|
|
340
|
+
for (const type of clause.types) {
|
|
341
|
+
extendsTypes.push(type.expression.getText());
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (clause.token === ts.SyntaxKind.ImplementsKeyword) {
|
|
345
|
+
for (const type of clause.types) {
|
|
346
|
+
implementsTypes.push(type.expression.getText());
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return {
|
|
352
|
+
name: node.name.text,
|
|
353
|
+
path: filePath,
|
|
354
|
+
line: line + 1,
|
|
355
|
+
kind: 'class',
|
|
356
|
+
isAbstract,
|
|
357
|
+
exported: isExported,
|
|
358
|
+
extends: extendsTypes.length > 0 ? extendsTypes : undefined,
|
|
359
|
+
implements: implementsTypes.length > 0 ? implementsTypes : undefined,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Extract interface type info
|
|
364
|
+
*/
|
|
365
|
+
function extractInterfaceInfo(node, sourceFile, filePath) {
|
|
366
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
367
|
+
const isExported = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
368
|
+
const extendsTypes = [];
|
|
369
|
+
if (node.heritageClauses) {
|
|
370
|
+
for (const clause of node.heritageClauses) {
|
|
371
|
+
if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
|
|
372
|
+
for (const type of clause.types) {
|
|
373
|
+
extendsTypes.push(type.expression.getText());
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
name: node.name.text,
|
|
380
|
+
path: filePath,
|
|
381
|
+
line: line + 1,
|
|
382
|
+
kind: 'interface',
|
|
383
|
+
exported: isExported,
|
|
384
|
+
extends: extendsTypes.length > 0 ? extendsTypes : undefined,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Extract type alias info (for types that extend others via intersection)
|
|
389
|
+
*/
|
|
390
|
+
function extractTypeAliasInfo(node, sourceFile, filePath) {
|
|
391
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
392
|
+
const isExported = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
393
|
+
// Extract types from intersection type
|
|
394
|
+
const extendsTypes = [];
|
|
395
|
+
if (ts.isIntersectionTypeNode(node.type)) {
|
|
396
|
+
for (const type of node.type.types) {
|
|
397
|
+
if (ts.isTypeReferenceNode(type)) {
|
|
398
|
+
extendsTypes.push(type.typeName.getText());
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
else if (ts.isTypeReferenceNode(node.type)) {
|
|
403
|
+
// Direct type reference (type Foo = Bar)
|
|
404
|
+
extendsTypes.push(node.type.typeName.getText());
|
|
405
|
+
}
|
|
406
|
+
// Only include if it references other types
|
|
407
|
+
if (extendsTypes.length === 0) {
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
return {
|
|
411
|
+
name: node.name.text,
|
|
412
|
+
path: filePath,
|
|
413
|
+
line: line + 1,
|
|
414
|
+
kind: 'type',
|
|
415
|
+
exported: isExported,
|
|
416
|
+
extends: extendsTypes,
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Collect files matching patterns
|
|
421
|
+
*/
|
|
422
|
+
async function collectFiles(dirPath, include, exclude, maxDepth, maxFiles, currentDepth = 0) {
|
|
423
|
+
if (currentDepth > maxDepth)
|
|
424
|
+
return [];
|
|
425
|
+
const files = [];
|
|
426
|
+
try {
|
|
427
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
428
|
+
for (const entry of entries) {
|
|
429
|
+
if (files.length >= maxFiles)
|
|
430
|
+
break;
|
|
431
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
432
|
+
const relativePath = fullPath;
|
|
433
|
+
// Check exclusions
|
|
434
|
+
const isExcluded = exclude.some((pattern) => {
|
|
435
|
+
if (pattern.includes('**')) {
|
|
436
|
+
const simplePattern = pattern.replace(/\*\*/g, '');
|
|
437
|
+
return relativePath.includes(simplePattern.replace(/\*/g, ''));
|
|
438
|
+
}
|
|
439
|
+
return entry.name === pattern || relativePath.includes(pattern);
|
|
440
|
+
});
|
|
441
|
+
if (isExcluded)
|
|
442
|
+
continue;
|
|
443
|
+
if (entry.isDirectory()) {
|
|
444
|
+
const subFiles = await collectFiles(fullPath, include, exclude, maxDepth, maxFiles - files.length, currentDepth + 1);
|
|
445
|
+
files.push(...subFiles);
|
|
446
|
+
}
|
|
447
|
+
else if (entry.isFile()) {
|
|
448
|
+
// Check if file matches include patterns
|
|
449
|
+
const isIncluded = include.some((pattern) => {
|
|
450
|
+
if (pattern.includes('*')) {
|
|
451
|
+
const ext = pattern.replace('**/', '').replace('*', '');
|
|
452
|
+
return entry.name.endsWith(ext);
|
|
453
|
+
}
|
|
454
|
+
return entry.name === pattern;
|
|
455
|
+
});
|
|
456
|
+
if (isIncluded) {
|
|
457
|
+
files.push(fullPath);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
catch {
|
|
463
|
+
// Ignore permission errors
|
|
464
|
+
}
|
|
465
|
+
return files;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Create customizable getTypeHierarchy tool
|
|
469
|
+
*/
|
|
470
|
+
export function createGetTypeHierarchyTool(options) {
|
|
471
|
+
return defineTool({
|
|
472
|
+
name: options?.name ?? 'get_type_hierarchy',
|
|
473
|
+
description: options?.description ?? TOOL_DESCRIPTION,
|
|
474
|
+
inputSchema: TOOL_INPUT_SCHEMA,
|
|
475
|
+
execute: async (input) => {
|
|
476
|
+
const modifiedInput = {
|
|
477
|
+
...input,
|
|
478
|
+
direction: input.direction ?? options?.defaultDirection,
|
|
479
|
+
maxDepth: input.maxDepth ?? options?.defaultMaxDepth,
|
|
480
|
+
scope: input.scope ?? options?.defaultScope,
|
|
481
|
+
};
|
|
482
|
+
return executeGetTypeHierarchy(modifiedInput);
|
|
483
|
+
},
|
|
484
|
+
});
|
|
485
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source Code Analysis Tools
|
|
3
|
+
*
|
|
4
|
+
* Tools for analyzing source code structure using TypeScript Compiler API.
|
|
5
|
+
* These tools reduce token usage by returning structured JSON
|
|
6
|
+
* instead of requiring the agent to read and reason through raw code.
|
|
7
|
+
*/
|
|
8
|
+
export { getFileStructureTool, createGetFileStructureTool } from './get-file-structure.js';
|
|
9
|
+
export { findSymbolTool, createFindSymbolTool } from './find-symbol.js';
|
|
10
|
+
export { findReferencesTool, createFindReferencesTool } from './find-references.js';
|
|
11
|
+
export { getImportsTool, createGetImportsTool } from './get-imports.js';
|
|
12
|
+
export { getExportsTool, createGetExportsTool } from './get-exports.js';
|
|
13
|
+
export { getCallGraphTool, createGetCallGraphTool } from './get-call-graph.js';
|
|
14
|
+
export { getDependencyGraphTool, createGetDependencyGraphTool } from './get-dependency-graph.js';
|
|
15
|
+
export { findImplementationsTool, createFindImplementationsTool } from './find-implementations.js';
|
|
16
|
+
export { getTypeHierarchyTool, createGetTypeHierarchyTool } from './get-type-hierarchy.js';
|
|
17
|
+
export { getComplexityTool, createGetComplexityTool } from './get-complexity.js';
|
|
18
|
+
export { findDeadCodeTool, createFindDeadCodeTool } from './find-dead-code.js';
|
|
19
|
+
export { findDuplicatesTool, createFindDuplicatesTool } from './find-duplicates.js';
|
|
20
|
+
export { findPatternsTool, createFindPatternsTool } from './find-patterns.js';
|
|
21
|
+
export { getSignatureTool, createGetSignatureTool } from './get-signature.js';
|
|
22
|
+
export { getDocumentationTool, createGetDocumentationTool } from './get-documentation.js';
|
|
23
|
+
export type { SupportedLanguage, ParameterInfo, GetFileStructureInput, FileStructure, ImportInfo, ExportInfo, ClassInfo, FunctionInfo, MethodInfo, PropertyInfo, VariableInfo, TypeDefinitionInfo, FileStats, SymbolKind, SymbolKindFilter, FindSymbolInput, FindSymbolResult, SymbolDefinition, SearchStats, ReferenceType, FindReferencesInput, FindReferencesResult, Reference, FileReferences, GetImportsInput, GetImportsResult, DetailedImport, ImportedSymbol, TransitiveImport, ImportStats, GetExportsInput, GetExportsResult, ExportedSymbol, ExportKind, ReExport, ExportStats, CallGraphDirection, CallType, GetCallGraphInput, GetCallGraphResult, FunctionNode, CallInfo, CallGraphNode, CallGraphStats, GetDependencyGraphInput, GetDependencyGraphResult, ModuleNode, DependencyEdge, CircularDependency, DependencyGraphStats, FindImplementationsInput, FindImplementationsResult, ImplementationInfo, HierarchyDirection, GetTypeHierarchyInput, GetTypeHierarchyResult, TypeHierarchyNode, GetComplexityInput, GetComplexityResult, FileComplexity, FunctionComplexity, ComplexityContributor, ComplexityContributorType, FindDeadCodeInput, FindDeadCodeResult, DeadCodeItem, FindDuplicatesInput, FindDuplicatesResult, DuplicateGroup, CodeLocation, FindPatternsInput, FindPatternsResult, PatternMatch, CodePattern, GetSignatureInput, GetSignatureResult, ParameterDetail, TypeDetail, GenericDetail, Documentation, MemberSignature, SignatureSymbolKind, GetDocumentationInput, GetDocumentationResult, FileDocumentation, DocumentedSymbol, DocumentationSymbolKind, ExtractorOptions, } from './types.js';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source Code Analysis Tools
|
|
3
|
+
*
|
|
4
|
+
* Tools for analyzing source code structure using TypeScript Compiler API.
|
|
5
|
+
* These tools reduce token usage by returning structured JSON
|
|
6
|
+
* instead of requiring the agent to read and reason through raw code.
|
|
7
|
+
*/
|
|
8
|
+
// Tier 1 & 2 Tools
|
|
9
|
+
export { getFileStructureTool, createGetFileStructureTool } from './get-file-structure.js';
|
|
10
|
+
export { findSymbolTool, createFindSymbolTool } from './find-symbol.js';
|
|
11
|
+
export { findReferencesTool, createFindReferencesTool } from './find-references.js';
|
|
12
|
+
export { getImportsTool, createGetImportsTool } from './get-imports.js';
|
|
13
|
+
export { getExportsTool, createGetExportsTool } from './get-exports.js';
|
|
14
|
+
export { getCallGraphTool, createGetCallGraphTool } from './get-call-graph.js';
|
|
15
|
+
export { getDependencyGraphTool, createGetDependencyGraphTool } from './get-dependency-graph.js';
|
|
16
|
+
export { findImplementationsTool, createFindImplementationsTool } from './find-implementations.js';
|
|
17
|
+
export { getTypeHierarchyTool, createGetTypeHierarchyTool } from './get-type-hierarchy.js';
|
|
18
|
+
// Tier 3 Tools
|
|
19
|
+
export { getComplexityTool, createGetComplexityTool } from './get-complexity.js';
|
|
20
|
+
export { findDeadCodeTool, createFindDeadCodeTool } from './find-dead-code.js';
|
|
21
|
+
export { findDuplicatesTool, createFindDuplicatesTool } from './find-duplicates.js';
|
|
22
|
+
export { findPatternsTool, createFindPatternsTool } from './find-patterns.js';
|
|
23
|
+
// Tier 4 Utility Tools
|
|
24
|
+
export { getSignatureTool, createGetSignatureTool } from './get-signature.js';
|
|
25
|
+
export { getDocumentationTool, createGetDocumentationTool } from './get-documentation.js';
|