@compilr-dev/agents-coding-ts 0.1.2 → 0.1.4
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/dist/index.d.ts +8 -5
- package/dist/index.js +14 -4
- package/dist/parser/index.d.ts +2 -2
- package/dist/parser/index.js +1 -1
- package/dist/parser/typescript-parser.d.ts +2 -2
- package/dist/parser/typescript-parser.js +77 -54
- package/dist/skills/code-health.js +18 -5
- package/dist/skills/code-structure.js +15 -5
- package/dist/skills/dependency-audit.js +16 -5
- package/dist/skills/index.d.ts +7 -7
- package/dist/skills/index.js +11 -11
- package/dist/skills/refactor-impact.js +16 -5
- package/dist/skills/type-analysis.js +16 -5
- package/dist/tools/find-dead-code.d.ts +2 -2
- package/dist/tools/find-dead-code.js +82 -58
- package/dist/tools/find-duplicates.d.ts +2 -2
- package/dist/tools/find-duplicates.js +41 -38
- package/dist/tools/find-implementations.d.ts +2 -2
- package/dist/tools/find-implementations.js +44 -36
- package/dist/tools/find-patterns.d.ts +2 -2
- package/dist/tools/find-patterns.js +154 -148
- package/dist/tools/find-references.d.ts +2 -2
- package/dist/tools/find-references.js +76 -72
- package/dist/tools/find-symbol.d.ts +2 -2
- package/dist/tools/find-symbol.js +106 -96
- package/dist/tools/get-call-graph.d.ts +2 -2
- package/dist/tools/get-call-graph.js +52 -47
- package/dist/tools/get-complexity.d.ts +2 -2
- package/dist/tools/get-complexity.js +94 -46
- package/dist/tools/get-dependency-graph.d.ts +2 -2
- package/dist/tools/get-dependency-graph.js +66 -52
- package/dist/tools/get-documentation.d.ts +2 -2
- package/dist/tools/get-documentation.js +154 -122
- package/dist/tools/get-exports.d.ts +2 -2
- package/dist/tools/get-exports.js +73 -61
- package/dist/tools/get-file-structure.d.ts +2 -2
- package/dist/tools/get-file-structure.js +16 -16
- package/dist/tools/get-imports.d.ts +2 -2
- package/dist/tools/get-imports.js +46 -46
- package/dist/tools/get-signature.d.ts +2 -2
- package/dist/tools/get-signature.js +168 -124
- package/dist/tools/get-type-hierarchy.d.ts +2 -2
- package/dist/tools/get-type-hierarchy.js +53 -44
- package/dist/tools/index.d.ts +18 -16
- package/dist/tools/index.js +17 -15
- package/dist/tools/read-symbol.d.ts +62 -0
- package/dist/tools/read-symbol.js +464 -0
- package/dist/tools/types.d.ts +27 -27
- package/package.json +3 -3
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart File Reading Tools
|
|
3
|
+
*
|
|
4
|
+
* AST-aware tools that extract specific code elements by name,
|
|
5
|
+
* returning exact source code without guessing line numbers.
|
|
6
|
+
*
|
|
7
|
+
* Tools:
|
|
8
|
+
* - read_function: Read a function/method by name
|
|
9
|
+
* - read_class: Read a class by name
|
|
10
|
+
* - read_type: Read a type/interface by name
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from "node:fs/promises";
|
|
13
|
+
import * as ts from "typescript";
|
|
14
|
+
import { defineTool, createSuccessResult, createErrorResult, } from "@compilr-dev/agents";
|
|
15
|
+
import { detectLanguage, isLanguageSupported, } from "../parser/typescript-parser.js";
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Helper Functions
|
|
18
|
+
// =============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Get script kind from file extension
|
|
21
|
+
*/
|
|
22
|
+
function getScriptKind(filePath) {
|
|
23
|
+
const ext = filePath.toLowerCase().split(".").pop();
|
|
24
|
+
switch (ext) {
|
|
25
|
+
case "ts":
|
|
26
|
+
case "mts":
|
|
27
|
+
case "cts":
|
|
28
|
+
return ts.ScriptKind.TS;
|
|
29
|
+
case "tsx":
|
|
30
|
+
return ts.ScriptKind.TSX;
|
|
31
|
+
case "js":
|
|
32
|
+
case "mjs":
|
|
33
|
+
case "cjs":
|
|
34
|
+
return ts.ScriptKind.JS;
|
|
35
|
+
case "jsx":
|
|
36
|
+
return ts.ScriptKind.JSX;
|
|
37
|
+
default:
|
|
38
|
+
return ts.ScriptKind.TS;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get the JSDoc comment for a node
|
|
43
|
+
*/
|
|
44
|
+
function getJsDoc(node, sourceFile) {
|
|
45
|
+
const jsDocNodes = ts.getJSDocCommentsAndTags(node);
|
|
46
|
+
if (jsDocNodes.length === 0)
|
|
47
|
+
return undefined;
|
|
48
|
+
// Get the full text range including JSDoc
|
|
49
|
+
const firstJsDoc = jsDocNodes[0];
|
|
50
|
+
const jsDocStart = firstJsDoc.getStart(sourceFile);
|
|
51
|
+
const nodeStart = node.getStart(sourceFile);
|
|
52
|
+
if (jsDocStart < nodeStart) {
|
|
53
|
+
return sourceFile.text.slice(jsDocStart, nodeStart).trim();
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get line number from character position
|
|
59
|
+
*/
|
|
60
|
+
function getLineNumber(sourceFile, pos) {
|
|
61
|
+
return sourceFile.getLineAndCharacterOfPosition(pos).line + 1;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Extract function signature (first line until opening brace or arrow)
|
|
65
|
+
*/
|
|
66
|
+
function extractSignature(content) {
|
|
67
|
+
// Find the first { or => and take everything before it
|
|
68
|
+
const braceIndex = content.indexOf("{");
|
|
69
|
+
const arrowIndex = content.indexOf("=>");
|
|
70
|
+
let endIndex = content.length;
|
|
71
|
+
if (braceIndex !== -1)
|
|
72
|
+
endIndex = Math.min(endIndex, braceIndex);
|
|
73
|
+
if (arrowIndex !== -1)
|
|
74
|
+
endIndex = Math.min(endIndex, arrowIndex + 2);
|
|
75
|
+
return content.slice(0, endIndex).trim();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Extract class signature (class declaration without body)
|
|
79
|
+
*/
|
|
80
|
+
function extractClassSignature(node, sourceFile) {
|
|
81
|
+
const start = node.getStart(sourceFile);
|
|
82
|
+
const bodyStart = node.members.length > 0
|
|
83
|
+
? node.members[0].getStart(sourceFile)
|
|
84
|
+
: node.getEnd();
|
|
85
|
+
// Find the opening brace
|
|
86
|
+
let text = sourceFile.text.slice(start, bodyStart);
|
|
87
|
+
const braceIndex = text.indexOf("{");
|
|
88
|
+
if (braceIndex !== -1) {
|
|
89
|
+
text = text.slice(0, braceIndex).trim() + " { ... }";
|
|
90
|
+
}
|
|
91
|
+
return text;
|
|
92
|
+
}
|
|
93
|
+
// =============================================================================
|
|
94
|
+
// read_function Tool
|
|
95
|
+
// =============================================================================
|
|
96
|
+
async function executeReadFunction(input) {
|
|
97
|
+
const { path: filePath, name, className, includeJsDoc = true } = input;
|
|
98
|
+
if (!filePath || !name) {
|
|
99
|
+
return createErrorResult("Both path and name are required");
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
await fs.access(filePath);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return createErrorResult(`File not found: ${filePath}`);
|
|
106
|
+
}
|
|
107
|
+
const detection = detectLanguage(filePath);
|
|
108
|
+
if (!detection.language || !isLanguageSupported(detection.language)) {
|
|
109
|
+
return createErrorResult(`Unsupported file type: ${filePath}`);
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const sourceCode = await fs.readFile(filePath, "utf-8");
|
|
113
|
+
const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true, getScriptKind(filePath));
|
|
114
|
+
// Find the function
|
|
115
|
+
let foundNode;
|
|
116
|
+
let containerName;
|
|
117
|
+
let arrowFunctionStatement;
|
|
118
|
+
function visit(node) {
|
|
119
|
+
if (foundNode)
|
|
120
|
+
return;
|
|
121
|
+
// Function declaration
|
|
122
|
+
if (ts.isFunctionDeclaration(node) &&
|
|
123
|
+
node.name?.getText(sourceFile) === name &&
|
|
124
|
+
!className) {
|
|
125
|
+
foundNode = node;
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
// Method in class
|
|
129
|
+
if (ts.isClassDeclaration(node) && node.name) {
|
|
130
|
+
const classNameText = node.name.getText(sourceFile);
|
|
131
|
+
if (!className || classNameText === className) {
|
|
132
|
+
for (const member of node.members) {
|
|
133
|
+
if (ts.isMethodDeclaration(member) &&
|
|
134
|
+
member.name.getText(sourceFile) === name) {
|
|
135
|
+
foundNode = member;
|
|
136
|
+
containerName = classNameText;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// Arrow function assigned to variable
|
|
143
|
+
if (ts.isVariableStatement(node) && !className) {
|
|
144
|
+
for (const decl of node.declarationList.declarations) {
|
|
145
|
+
if (decl.name.getText(sourceFile) === name &&
|
|
146
|
+
decl.initializer &&
|
|
147
|
+
ts.isArrowFunction(decl.initializer)) {
|
|
148
|
+
foundNode = decl.initializer;
|
|
149
|
+
arrowFunctionStatement = node;
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
ts.forEachChild(node, visit);
|
|
155
|
+
}
|
|
156
|
+
visit(sourceFile);
|
|
157
|
+
if (!foundNode) {
|
|
158
|
+
const searchDesc = className
|
|
159
|
+
? `method ${name} in class ${className}`
|
|
160
|
+
: `function ${name}`;
|
|
161
|
+
return createErrorResult(`Function not found: ${searchDesc}`);
|
|
162
|
+
}
|
|
163
|
+
// For arrow functions, use the full variable statement for content
|
|
164
|
+
const nodeForContent = arrowFunctionStatement ?? foundNode;
|
|
165
|
+
// Extract the source code
|
|
166
|
+
let start = nodeForContent.getStart(sourceFile);
|
|
167
|
+
const end = nodeForContent.getEnd();
|
|
168
|
+
// Include JSDoc if requested
|
|
169
|
+
if (includeJsDoc) {
|
|
170
|
+
const jsDoc = getJsDoc(nodeForContent, sourceFile);
|
|
171
|
+
if (jsDoc) {
|
|
172
|
+
// Find where the JSDoc starts
|
|
173
|
+
const jsDocStart = sourceFile.text.lastIndexOf("/**", start);
|
|
174
|
+
if (jsDocStart !== -1 && jsDocStart < start) {
|
|
175
|
+
start = jsDocStart;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const content = sourceFile.text.slice(start, end);
|
|
180
|
+
const startLine = getLineNumber(sourceFile, start);
|
|
181
|
+
const endLine = getLineNumber(sourceFile, end);
|
|
182
|
+
const result = {
|
|
183
|
+
name,
|
|
184
|
+
kind: containerName ? "method" : "function",
|
|
185
|
+
startLine,
|
|
186
|
+
endLine,
|
|
187
|
+
content,
|
|
188
|
+
signature: extractSignature(content),
|
|
189
|
+
container: containerName,
|
|
190
|
+
};
|
|
191
|
+
return createSuccessResult(result);
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
return createErrorResult(`Failed to read function: ${error instanceof Error ? error.message : String(error)}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
export const readFunctionTool = defineTool({
|
|
198
|
+
name: "read_function",
|
|
199
|
+
description: "Read a specific function or method by name. Returns the exact source code without guessing line numbers. " +
|
|
200
|
+
"Use this instead of read_file when you need to see a specific function. " +
|
|
201
|
+
"For methods, specify the className parameter.",
|
|
202
|
+
inputSchema: {
|
|
203
|
+
type: "object",
|
|
204
|
+
properties: {
|
|
205
|
+
path: {
|
|
206
|
+
type: "string",
|
|
207
|
+
description: "Absolute path to the file",
|
|
208
|
+
},
|
|
209
|
+
name: {
|
|
210
|
+
type: "string",
|
|
211
|
+
description: "Function or method name to read",
|
|
212
|
+
},
|
|
213
|
+
className: {
|
|
214
|
+
type: "string",
|
|
215
|
+
description: "Class name if reading a method (optional)",
|
|
216
|
+
},
|
|
217
|
+
includeJsDoc: {
|
|
218
|
+
type: "boolean",
|
|
219
|
+
description: "Include JSDoc comment (default: true)",
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
required: ["path", "name"],
|
|
223
|
+
},
|
|
224
|
+
execute: executeReadFunction,
|
|
225
|
+
});
|
|
226
|
+
// =============================================================================
|
|
227
|
+
// read_class Tool
|
|
228
|
+
// =============================================================================
|
|
229
|
+
async function executeReadClass(input) {
|
|
230
|
+
const { path: filePath, name, include = "full", includeJsDoc = true } = input;
|
|
231
|
+
if (!filePath || !name) {
|
|
232
|
+
return createErrorResult("Both path and name are required");
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
await fs.access(filePath);
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
return createErrorResult(`File not found: ${filePath}`);
|
|
239
|
+
}
|
|
240
|
+
const detection = detectLanguage(filePath);
|
|
241
|
+
if (!detection.language || !isLanguageSupported(detection.language)) {
|
|
242
|
+
return createErrorResult(`Unsupported file type: ${filePath}`);
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
const sourceCode = await fs.readFile(filePath, "utf-8");
|
|
246
|
+
const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true, getScriptKind(filePath));
|
|
247
|
+
// Find the class
|
|
248
|
+
let foundNode;
|
|
249
|
+
function visit(node) {
|
|
250
|
+
if (foundNode)
|
|
251
|
+
return;
|
|
252
|
+
if (ts.isClassDeclaration(node) &&
|
|
253
|
+
node.name?.getText(sourceFile) === name) {
|
|
254
|
+
foundNode = node;
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
ts.forEachChild(node, visit);
|
|
258
|
+
}
|
|
259
|
+
visit(sourceFile);
|
|
260
|
+
if (!foundNode) {
|
|
261
|
+
return createErrorResult(`Class not found: ${name}`);
|
|
262
|
+
}
|
|
263
|
+
let start = foundNode.getStart(sourceFile);
|
|
264
|
+
const end = foundNode.getEnd();
|
|
265
|
+
// Include JSDoc if requested
|
|
266
|
+
if (includeJsDoc) {
|
|
267
|
+
const jsDoc = getJsDoc(foundNode, sourceFile);
|
|
268
|
+
if (jsDoc) {
|
|
269
|
+
const jsDocStart = sourceFile.text.lastIndexOf("/**", start);
|
|
270
|
+
if (jsDocStart !== -1 && jsDocStart < start) {
|
|
271
|
+
start = jsDocStart;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
let content;
|
|
276
|
+
if (include === "full") {
|
|
277
|
+
content = sourceCode.slice(start, end);
|
|
278
|
+
}
|
|
279
|
+
else if (include === "signature") {
|
|
280
|
+
content = extractClassSignature(foundNode, sourceFile);
|
|
281
|
+
}
|
|
282
|
+
else if (include === "methods-only") {
|
|
283
|
+
const methods = [];
|
|
284
|
+
for (const member of foundNode.members) {
|
|
285
|
+
if (ts.isMethodDeclaration(member)) {
|
|
286
|
+
const memberStart = member.getStart(sourceFile);
|
|
287
|
+
const memberEnd = member.getEnd();
|
|
288
|
+
methods.push(sourceCode.slice(memberStart, memberEnd));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
content = methods.join("\n\n");
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
// include === 'properties-only'
|
|
295
|
+
const props = [];
|
|
296
|
+
for (const member of foundNode.members) {
|
|
297
|
+
if (ts.isPropertyDeclaration(member)) {
|
|
298
|
+
const memberStart = member.getStart(sourceFile);
|
|
299
|
+
const memberEnd = member.getEnd();
|
|
300
|
+
props.push(sourceCode.slice(memberStart, memberEnd));
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
content = props.join("\n");
|
|
304
|
+
}
|
|
305
|
+
const startLine = getLineNumber(sourceFile, start);
|
|
306
|
+
const endLine = getLineNumber(sourceFile, end);
|
|
307
|
+
const result = {
|
|
308
|
+
name,
|
|
309
|
+
kind: "class",
|
|
310
|
+
startLine,
|
|
311
|
+
endLine,
|
|
312
|
+
content,
|
|
313
|
+
signature: extractClassSignature(foundNode, sourceFile),
|
|
314
|
+
};
|
|
315
|
+
return createSuccessResult(result);
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
return createErrorResult(`Failed to read class: ${error instanceof Error ? error.message : String(error)}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
export const readClassTool = defineTool({
|
|
322
|
+
name: "read_class",
|
|
323
|
+
description: "Read a specific class by name. Returns the exact source code without guessing line numbers. " +
|
|
324
|
+
"Use the include parameter to get: full class, signature only, methods only, or properties only.",
|
|
325
|
+
inputSchema: {
|
|
326
|
+
type: "object",
|
|
327
|
+
properties: {
|
|
328
|
+
path: {
|
|
329
|
+
type: "string",
|
|
330
|
+
description: "Absolute path to the file",
|
|
331
|
+
},
|
|
332
|
+
name: {
|
|
333
|
+
type: "string",
|
|
334
|
+
description: "Class name to read",
|
|
335
|
+
},
|
|
336
|
+
include: {
|
|
337
|
+
type: "string",
|
|
338
|
+
enum: ["full", "signature", "methods-only", "properties-only"],
|
|
339
|
+
description: "What to include (default: full)",
|
|
340
|
+
},
|
|
341
|
+
includeJsDoc: {
|
|
342
|
+
type: "boolean",
|
|
343
|
+
description: "Include JSDoc comment (default: true)",
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
required: ["path", "name"],
|
|
347
|
+
},
|
|
348
|
+
execute: executeReadClass,
|
|
349
|
+
});
|
|
350
|
+
// =============================================================================
|
|
351
|
+
// read_type Tool
|
|
352
|
+
// =============================================================================
|
|
353
|
+
async function executeReadType(input) {
|
|
354
|
+
const { path: filePath, name, includeJsDoc = true } = input;
|
|
355
|
+
if (!filePath || !name) {
|
|
356
|
+
return createErrorResult("Both path and name are required");
|
|
357
|
+
}
|
|
358
|
+
try {
|
|
359
|
+
await fs.access(filePath);
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
return createErrorResult(`File not found: ${filePath}`);
|
|
363
|
+
}
|
|
364
|
+
const detection = detectLanguage(filePath);
|
|
365
|
+
if (!detection.language || !isLanguageSupported(detection.language)) {
|
|
366
|
+
return createErrorResult(`Unsupported file type: ${filePath}`);
|
|
367
|
+
}
|
|
368
|
+
try {
|
|
369
|
+
const sourceCode = await fs.readFile(filePath, "utf-8");
|
|
370
|
+
const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true, getScriptKind(filePath));
|
|
371
|
+
// Find the type/interface/enum
|
|
372
|
+
let foundNode;
|
|
373
|
+
let kind = "type";
|
|
374
|
+
function visit(node) {
|
|
375
|
+
if (foundNode)
|
|
376
|
+
return;
|
|
377
|
+
if (ts.isInterfaceDeclaration(node) &&
|
|
378
|
+
node.name.getText(sourceFile) === name) {
|
|
379
|
+
foundNode = node;
|
|
380
|
+
kind = "interface";
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
if (ts.isTypeAliasDeclaration(node) &&
|
|
384
|
+
node.name.getText(sourceFile) === name) {
|
|
385
|
+
foundNode = node;
|
|
386
|
+
kind = "type";
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
if (ts.isEnumDeclaration(node) &&
|
|
390
|
+
node.name.getText(sourceFile) === name) {
|
|
391
|
+
foundNode = node;
|
|
392
|
+
kind = "enum";
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
ts.forEachChild(node, visit);
|
|
396
|
+
}
|
|
397
|
+
visit(sourceFile);
|
|
398
|
+
if (!foundNode) {
|
|
399
|
+
return createErrorResult(`Type/interface/enum not found: ${name}`);
|
|
400
|
+
}
|
|
401
|
+
let start = foundNode.getStart(sourceFile);
|
|
402
|
+
const end = foundNode.getEnd();
|
|
403
|
+
// Include JSDoc if requested
|
|
404
|
+
if (includeJsDoc) {
|
|
405
|
+
const jsDoc = getJsDoc(foundNode, sourceFile);
|
|
406
|
+
if (jsDoc) {
|
|
407
|
+
const jsDocStart = sourceFile.text.lastIndexOf("/**", start);
|
|
408
|
+
if (jsDocStart !== -1 && jsDocStart < start) {
|
|
409
|
+
start = jsDocStart;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
const content = sourceCode.slice(start, end);
|
|
414
|
+
const startLine = getLineNumber(sourceFile, start);
|
|
415
|
+
const endLine = getLineNumber(sourceFile, end);
|
|
416
|
+
const result = {
|
|
417
|
+
name,
|
|
418
|
+
kind,
|
|
419
|
+
startLine,
|
|
420
|
+
endLine,
|
|
421
|
+
content,
|
|
422
|
+
};
|
|
423
|
+
return createSuccessResult(result);
|
|
424
|
+
}
|
|
425
|
+
catch (error) {
|
|
426
|
+
return createErrorResult(`Failed to read type: ${error instanceof Error ? error.message : String(error)}`);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
export const readTypeTool = defineTool({
|
|
430
|
+
name: "read_type",
|
|
431
|
+
description: "Read a specific type, interface, or enum by name. Returns the exact source code without guessing line numbers. " +
|
|
432
|
+
"Works for TypeScript interfaces, type aliases, and enums.",
|
|
433
|
+
inputSchema: {
|
|
434
|
+
type: "object",
|
|
435
|
+
properties: {
|
|
436
|
+
path: {
|
|
437
|
+
type: "string",
|
|
438
|
+
description: "Absolute path to the file",
|
|
439
|
+
},
|
|
440
|
+
name: {
|
|
441
|
+
type: "string",
|
|
442
|
+
description: "Type, interface, or enum name to read",
|
|
443
|
+
},
|
|
444
|
+
includeJsDoc: {
|
|
445
|
+
type: "boolean",
|
|
446
|
+
description: "Include JSDoc comment (default: true)",
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
required: ["path", "name"],
|
|
450
|
+
},
|
|
451
|
+
execute: executeReadType,
|
|
452
|
+
});
|
|
453
|
+
// =============================================================================
|
|
454
|
+
// Factory Functions
|
|
455
|
+
// =============================================================================
|
|
456
|
+
export function createReadFunctionTool() {
|
|
457
|
+
return readFunctionTool;
|
|
458
|
+
}
|
|
459
|
+
export function createReadClassTool() {
|
|
460
|
+
return readClassTool;
|
|
461
|
+
}
|
|
462
|
+
export function createReadTypeTool() {
|
|
463
|
+
return readTypeTool;
|
|
464
|
+
}
|
package/dist/tools/types.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
/**
|
|
8
8
|
* Supported languages for analysis
|
|
9
9
|
*/
|
|
10
|
-
export type SupportedLanguage =
|
|
10
|
+
export type SupportedLanguage = "typescript" | "javascript";
|
|
11
11
|
/**
|
|
12
12
|
* Parameter information for functions/methods
|
|
13
13
|
*/
|
|
@@ -116,7 +116,7 @@ export interface MethodInfo {
|
|
|
116
116
|
/** Method name */
|
|
117
117
|
name: string;
|
|
118
118
|
/** Visibility */
|
|
119
|
-
visibility:
|
|
119
|
+
visibility: "public" | "private" | "protected";
|
|
120
120
|
/** Is async */
|
|
121
121
|
async: boolean;
|
|
122
122
|
/** Is static */
|
|
@@ -135,7 +135,7 @@ export interface PropertyInfo {
|
|
|
135
135
|
/** Type annotation */
|
|
136
136
|
type?: string;
|
|
137
137
|
/** Visibility */
|
|
138
|
-
visibility:
|
|
138
|
+
visibility: "public" | "private" | "protected";
|
|
139
139
|
/** Is static */
|
|
140
140
|
static: boolean;
|
|
141
141
|
/** Is readonly */
|
|
@@ -148,7 +148,7 @@ export interface VariableInfo {
|
|
|
148
148
|
/** Variable name */
|
|
149
149
|
name: string;
|
|
150
150
|
/** Declaration kind */
|
|
151
|
-
kind:
|
|
151
|
+
kind: "const" | "let" | "var";
|
|
152
152
|
/** Type annotation */
|
|
153
153
|
type?: string;
|
|
154
154
|
/** Is exported */
|
|
@@ -161,7 +161,7 @@ export interface TypeDefinitionInfo {
|
|
|
161
161
|
/** Type name */
|
|
162
162
|
name: string;
|
|
163
163
|
/** Kind of type definition */
|
|
164
|
-
kind:
|
|
164
|
+
kind: "interface" | "type" | "enum";
|
|
165
165
|
/** Is exported */
|
|
166
166
|
exported: boolean;
|
|
167
167
|
}
|
|
@@ -194,11 +194,11 @@ export interface ExtractorOptions {
|
|
|
194
194
|
/**
|
|
195
195
|
* Symbol kind for filtering
|
|
196
196
|
*/
|
|
197
|
-
export type SymbolKind =
|
|
197
|
+
export type SymbolKind = "function" | "class" | "variable" | "type" | "interface" | "enum" | "method" | "property";
|
|
198
198
|
/**
|
|
199
199
|
* Symbol kind filter (includes 'any' for no filtering)
|
|
200
200
|
*/
|
|
201
|
-
export type SymbolKindFilter = SymbolKind |
|
|
201
|
+
export type SymbolKindFilter = SymbolKind | "any";
|
|
202
202
|
/**
|
|
203
203
|
* Input for findSymbol tool
|
|
204
204
|
*/
|
|
@@ -262,7 +262,7 @@ export interface FindSymbolResult {
|
|
|
262
262
|
/**
|
|
263
263
|
* Reference type - how the symbol is used
|
|
264
264
|
*/
|
|
265
|
-
export type ReferenceType =
|
|
265
|
+
export type ReferenceType = "read" | "write" | "call" | "import" | "export" | "type" | "extend" | "implement";
|
|
266
266
|
/**
|
|
267
267
|
* Input for findReferences tool
|
|
268
268
|
*/
|
|
@@ -427,7 +427,7 @@ export interface GetExportsInput {
|
|
|
427
427
|
/**
|
|
428
428
|
* Kind of exported symbol
|
|
429
429
|
*/
|
|
430
|
-
export type ExportKind =
|
|
430
|
+
export type ExportKind = "function" | "class" | "variable" | "type" | "interface" | "enum" | "namespace" | "unknown";
|
|
431
431
|
/**
|
|
432
432
|
* An exported symbol
|
|
433
433
|
*/
|
|
@@ -450,7 +450,7 @@ export interface ExportedSymbol {
|
|
|
450
450
|
*/
|
|
451
451
|
export interface ReExport {
|
|
452
452
|
/** What is being re-exported ('*' for all) */
|
|
453
|
-
symbols: string[] |
|
|
453
|
+
symbols: string[] | "*";
|
|
454
454
|
/** Source module */
|
|
455
455
|
from: string;
|
|
456
456
|
/** Resolved absolute path (for local modules) */
|
|
@@ -495,11 +495,11 @@ export interface GetExportsResult {
|
|
|
495
495
|
/**
|
|
496
496
|
* Direction for call graph traversal
|
|
497
497
|
*/
|
|
498
|
-
export type CallGraphDirection =
|
|
498
|
+
export type CallGraphDirection = "callers" | "callees" | "both";
|
|
499
499
|
/**
|
|
500
500
|
* Type of function call
|
|
501
501
|
*/
|
|
502
|
-
export type CallType =
|
|
502
|
+
export type CallType = "direct" | "callback" | "promise" | "event" | "method";
|
|
503
503
|
/**
|
|
504
504
|
* Input for getCallGraph tool
|
|
505
505
|
*/
|
|
@@ -627,7 +627,7 @@ export interface DependencyEdge {
|
|
|
627
627
|
/** Target module */
|
|
628
628
|
to: string;
|
|
629
629
|
/** Import type */
|
|
630
|
-
importType:
|
|
630
|
+
importType: "named" | "default" | "namespace" | "side-effect";
|
|
631
631
|
/** Is type-only import */
|
|
632
632
|
typeOnly: boolean;
|
|
633
633
|
/** Number of symbols imported */
|
|
@@ -712,7 +712,7 @@ export interface ImplementationInfo {
|
|
|
712
712
|
/** Column number (1-based) */
|
|
713
713
|
column: number;
|
|
714
714
|
/** Kind of implementation */
|
|
715
|
-
kind:
|
|
715
|
+
kind: "class" | "type" | "object";
|
|
716
716
|
/** Is abstract (partial implementation) */
|
|
717
717
|
isAbstract?: boolean;
|
|
718
718
|
/** Is exported */
|
|
@@ -745,7 +745,7 @@ export interface FindImplementationsResult {
|
|
|
745
745
|
/**
|
|
746
746
|
* Direction for type hierarchy traversal
|
|
747
747
|
*/
|
|
748
|
-
export type HierarchyDirection =
|
|
748
|
+
export type HierarchyDirection = "ancestors" | "descendants" | "both";
|
|
749
749
|
/**
|
|
750
750
|
* Input for getTypeHierarchy tool
|
|
751
751
|
*/
|
|
@@ -772,7 +772,7 @@ export interface TypeHierarchyNode {
|
|
|
772
772
|
/** Line number (1-based) */
|
|
773
773
|
line: number;
|
|
774
774
|
/** Kind of type */
|
|
775
|
-
kind:
|
|
775
|
+
kind: "class" | "interface" | "type";
|
|
776
776
|
/** Is abstract */
|
|
777
777
|
isAbstract?: boolean;
|
|
778
778
|
/** Is exported */
|
|
@@ -815,7 +815,7 @@ export interface GetComplexityInput {
|
|
|
815
815
|
/**
|
|
816
816
|
* Complexity contributor type
|
|
817
817
|
*/
|
|
818
|
-
export type ComplexityContributorType =
|
|
818
|
+
export type ComplexityContributorType = "if" | "else" | "switch" | "case" | "for" | "while" | "do" | "catch" | "ternary" | "logical_and" | "logical_or" | "nullish" | "nesting";
|
|
819
819
|
/**
|
|
820
820
|
* A contributor to complexity score
|
|
821
821
|
*/
|
|
@@ -930,11 +930,11 @@ export interface DeadCodeItem {
|
|
|
930
930
|
/** Line number */
|
|
931
931
|
line: number;
|
|
932
932
|
/** Kind of symbol */
|
|
933
|
-
kind:
|
|
933
|
+
kind: "function" | "class" | "variable" | "type" | "interface" | "enum" | "export";
|
|
934
934
|
/** Is exported */
|
|
935
935
|
exported: boolean;
|
|
936
936
|
/** Confidence level */
|
|
937
|
-
confidence:
|
|
937
|
+
confidence: "high" | "medium" | "low";
|
|
938
938
|
/** Reason for flagging */
|
|
939
939
|
reason: string;
|
|
940
940
|
}
|
|
@@ -1023,11 +1023,11 @@ export interface CodePattern {
|
|
|
1023
1023
|
/** Description */
|
|
1024
1024
|
description: string;
|
|
1025
1025
|
/** Pattern type */
|
|
1026
|
-
type:
|
|
1026
|
+
type: "anti-pattern" | "pattern" | "smell";
|
|
1027
1027
|
/** AST pattern or regex */
|
|
1028
1028
|
matcher: string;
|
|
1029
1029
|
/** Severity */
|
|
1030
|
-
severity:
|
|
1030
|
+
severity: "error" | "warning" | "info";
|
|
1031
1031
|
}
|
|
1032
1032
|
/**
|
|
1033
1033
|
* Input for findPatterns tool
|
|
@@ -1038,7 +1038,7 @@ export interface FindPatternsInput {
|
|
|
1038
1038
|
/** Patterns to search for (uses built-in if not specified) */
|
|
1039
1039
|
patterns?: CodePattern[];
|
|
1040
1040
|
/** Pattern categories to include */
|
|
1041
|
-
categories?: Array<
|
|
1041
|
+
categories?: Array<"security" | "performance" | "maintainability" | "all">;
|
|
1042
1042
|
/** Maximum files to analyze (default: 100) */
|
|
1043
1043
|
maxFiles?: number;
|
|
1044
1044
|
}
|
|
@@ -1051,7 +1051,7 @@ export interface PatternMatch {
|
|
|
1051
1051
|
/** Pattern description */
|
|
1052
1052
|
description: string;
|
|
1053
1053
|
/** Severity */
|
|
1054
|
-
severity:
|
|
1054
|
+
severity: "error" | "warning" | "info";
|
|
1055
1055
|
/** File path */
|
|
1056
1056
|
path: string;
|
|
1057
1057
|
/** Line number */
|
|
@@ -1169,7 +1169,7 @@ export interface MemberSignature {
|
|
|
1169
1169
|
/** Member name */
|
|
1170
1170
|
name: string;
|
|
1171
1171
|
/** Member kind */
|
|
1172
|
-
kind:
|
|
1172
|
+
kind: "property" | "method" | "getter" | "setter";
|
|
1173
1173
|
/** Signature string */
|
|
1174
1174
|
signature: string;
|
|
1175
1175
|
/** Is optional */
|
|
@@ -1177,14 +1177,14 @@ export interface MemberSignature {
|
|
|
1177
1177
|
/** Is readonly */
|
|
1178
1178
|
readonly: boolean;
|
|
1179
1179
|
/** Visibility */
|
|
1180
|
-
visibility?:
|
|
1180
|
+
visibility?: "public" | "private" | "protected";
|
|
1181
1181
|
/** Is static */
|
|
1182
1182
|
static?: boolean;
|
|
1183
1183
|
}
|
|
1184
1184
|
/**
|
|
1185
1185
|
* Symbol kind for signature
|
|
1186
1186
|
*/
|
|
1187
|
-
export type SignatureSymbolKind =
|
|
1187
|
+
export type SignatureSymbolKind = "function" | "method" | "class" | "interface" | "type" | "enum" | "variable";
|
|
1188
1188
|
/**
|
|
1189
1189
|
* Output from getSignature tool
|
|
1190
1190
|
*/
|
|
@@ -1219,7 +1219,7 @@ export interface GetSignatureResult {
|
|
|
1219
1219
|
/**
|
|
1220
1220
|
* Symbol kind for documentation extraction
|
|
1221
1221
|
*/
|
|
1222
|
-
export type DocumentationSymbolKind =
|
|
1222
|
+
export type DocumentationSymbolKind = "function" | "class" | "interface" | "type" | "enum" | "variable" | "method" | "property";
|
|
1223
1223
|
/**
|
|
1224
1224
|
* Input for getDocumentation tool
|
|
1225
1225
|
*/
|