@compilr-dev/agents-coding-ts 0.1.3 → 0.1.5
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 +95 -8
- package/README.md +4 -1
- 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 +5 -5
- package/dist/skills/code-structure.js +5 -5
- package/dist/skills/dependency-audit.js +5 -5
- package/dist/skills/index.d.ts +7 -7
- package/dist/skills/index.js +11 -11
- package/dist/skills/refactor-impact.js +5 -5
- package/dist/skills/type-analysis.js +5 -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 +8 -8
|
@@ -4,52 +4,52 @@
|
|
|
4
4
|
* Detect duplicate code blocks across the codebase using content hashing.
|
|
5
5
|
* Helps identify opportunities for refactoring and code reuse.
|
|
6
6
|
*/
|
|
7
|
-
import * as fs from
|
|
8
|
-
import * as path from
|
|
9
|
-
import * as crypto from
|
|
10
|
-
import { defineTool, createSuccessResult, createErrorResult } from
|
|
7
|
+
import * as fs from "node:fs/promises";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import * as crypto from "node:crypto";
|
|
10
|
+
import { defineTool, createSuccessResult, createErrorResult, } from "@compilr-dev/agents";
|
|
11
11
|
// Tool description
|
|
12
12
|
const TOOL_DESCRIPTION = `Detect duplicate code blocks across the codebase.
|
|
13
13
|
Uses content hashing to find similar code patterns.
|
|
14
14
|
Useful for identifying refactoring opportunities and reducing code duplication.`;
|
|
15
15
|
// Tool input schema
|
|
16
16
|
const TOOL_INPUT_SCHEMA = {
|
|
17
|
-
type:
|
|
17
|
+
type: "object",
|
|
18
18
|
properties: {
|
|
19
19
|
path: {
|
|
20
|
-
type:
|
|
21
|
-
description:
|
|
20
|
+
type: "string",
|
|
21
|
+
description: "Directory to analyze",
|
|
22
22
|
},
|
|
23
23
|
minLines: {
|
|
24
|
-
type:
|
|
25
|
-
description:
|
|
24
|
+
type: "number",
|
|
25
|
+
description: "Minimum lines for a duplicate (default: 6)",
|
|
26
26
|
default: 6,
|
|
27
27
|
},
|
|
28
28
|
minTokens: {
|
|
29
|
-
type:
|
|
30
|
-
description:
|
|
29
|
+
type: "number",
|
|
30
|
+
description: "Minimum tokens for a duplicate (default: 50)",
|
|
31
31
|
default: 50,
|
|
32
32
|
},
|
|
33
33
|
ignoreIdenticalFiles: {
|
|
34
|
-
type:
|
|
35
|
-
description:
|
|
34
|
+
type: "boolean",
|
|
35
|
+
description: "Ignore identical files (default: true)",
|
|
36
36
|
default: true,
|
|
37
37
|
},
|
|
38
38
|
maxFiles: {
|
|
39
|
-
type:
|
|
40
|
-
description:
|
|
39
|
+
type: "number",
|
|
40
|
+
description: "Maximum files to analyze (default: 100)",
|
|
41
41
|
default: 100,
|
|
42
42
|
},
|
|
43
43
|
},
|
|
44
|
-
required: [
|
|
44
|
+
required: ["path"],
|
|
45
45
|
};
|
|
46
46
|
// Default exclusions
|
|
47
|
-
const DEFAULT_EXCLUDE = [
|
|
47
|
+
const DEFAULT_EXCLUDE = ["node_modules", "dist", "build", ".git", "coverage"];
|
|
48
48
|
/**
|
|
49
49
|
* findDuplicates tool
|
|
50
50
|
*/
|
|
51
51
|
export const findDuplicatesTool = defineTool({
|
|
52
|
-
name:
|
|
52
|
+
name: "find_duplicates",
|
|
53
53
|
description: TOOL_DESCRIPTION,
|
|
54
54
|
inputSchema: TOOL_INPUT_SCHEMA,
|
|
55
55
|
execute: executeFindDuplicates,
|
|
@@ -70,7 +70,7 @@ async function executeFindDuplicates(input) {
|
|
|
70
70
|
}
|
|
71
71
|
const stats = await fs.stat(resolvedPath);
|
|
72
72
|
if (!stats.isDirectory()) {
|
|
73
|
-
return createErrorResult(
|
|
73
|
+
return createErrorResult("findDuplicates requires a directory path");
|
|
74
74
|
}
|
|
75
75
|
// Collect files
|
|
76
76
|
const files = [];
|
|
@@ -79,8 +79,8 @@ async function executeFindDuplicates(input) {
|
|
|
79
79
|
const fileHashes = new Map();
|
|
80
80
|
if (!ignoreIdenticalFiles) {
|
|
81
81
|
for (const file of files) {
|
|
82
|
-
const content = await fs.readFile(file,
|
|
83
|
-
const hash = crypto.createHash(
|
|
82
|
+
const content = await fs.readFile(file, "utf-8");
|
|
83
|
+
const hash = crypto.createHash("md5").update(content).digest("hex");
|
|
84
84
|
const existing = fileHashes.get(hash) ?? [];
|
|
85
85
|
existing.push(file);
|
|
86
86
|
fileHashes.set(hash, existing);
|
|
@@ -93,8 +93,8 @@ async function executeFindDuplicates(input) {
|
|
|
93
93
|
const blocks = await extractCodeBlocks(file, minLines, minTokens);
|
|
94
94
|
allBlocks.push(...blocks);
|
|
95
95
|
// Count total lines
|
|
96
|
-
const content = await fs.readFile(file,
|
|
97
|
-
totalLines += content.split(
|
|
96
|
+
const content = await fs.readFile(file, "utf-8");
|
|
97
|
+
totalLines += content.split("\n").length;
|
|
98
98
|
}
|
|
99
99
|
// Group by hash
|
|
100
100
|
const hashGroups = new Map();
|
|
@@ -133,7 +133,9 @@ async function executeFindDuplicates(input) {
|
|
|
133
133
|
duplicateGroups.sort((a, b) => b.lines - a.lines);
|
|
134
134
|
// Limit results
|
|
135
135
|
const limitedGroups = duplicateGroups.slice(0, 20);
|
|
136
|
-
const percentageDuplicate = totalLines > 0
|
|
136
|
+
const percentageDuplicate = totalLines > 0
|
|
137
|
+
? Math.round((totalDuplicateLines / totalLines) * 10000) / 100
|
|
138
|
+
: 0;
|
|
137
139
|
const result = {
|
|
138
140
|
path: resolvedPath,
|
|
139
141
|
duplicates: limitedGroups,
|
|
@@ -169,7 +171,8 @@ async function collectFiles(dirPath, files, maxFiles, currentDepth = 0) {
|
|
|
169
171
|
}
|
|
170
172
|
else if (entry.isFile()) {
|
|
171
173
|
// Only include TypeScript/JavaScript files
|
|
172
|
-
if (/\.(ts|tsx|js|jsx)$/.test(entry.name) &&
|
|
174
|
+
if (/\.(ts|tsx|js|jsx)$/.test(entry.name) &&
|
|
175
|
+
!entry.name.endsWith(".d.ts")) {
|
|
173
176
|
files.push(fullPath);
|
|
174
177
|
}
|
|
175
178
|
}
|
|
@@ -184,15 +187,15 @@ async function collectFiles(dirPath, files, maxFiles, currentDepth = 0) {
|
|
|
184
187
|
*/
|
|
185
188
|
async function extractCodeBlocks(filePath, minLines, minTokens) {
|
|
186
189
|
try {
|
|
187
|
-
const content = await fs.readFile(filePath,
|
|
188
|
-
const lines = content.split(
|
|
190
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
191
|
+
const lines = content.split("\n");
|
|
189
192
|
const blocks = [];
|
|
190
193
|
// Use sliding window approach
|
|
191
194
|
for (let start = 0; start <= lines.length - minLines; start++) {
|
|
192
195
|
// Try different block sizes
|
|
193
196
|
for (let size = minLines; size <= Math.min(minLines * 3, lines.length - start); size++) {
|
|
194
197
|
const blockLines = lines.slice(start, start + size);
|
|
195
|
-
const blockContent = blockLines.join(
|
|
198
|
+
const blockContent = blockLines.join("\n");
|
|
196
199
|
// Normalize content for comparison
|
|
197
200
|
const normalized = normalizeCode(blockContent);
|
|
198
201
|
// Count tokens (simplified: split on whitespace and punctuation)
|
|
@@ -200,10 +203,10 @@ async function extractCodeBlocks(filePath, minLines, minTokens) {
|
|
|
200
203
|
if (tokens < minTokens)
|
|
201
204
|
continue;
|
|
202
205
|
// Skip if mostly empty/comments
|
|
203
|
-
const significantLines = blockLines.filter((l) => l.trim() && !l.trim().startsWith(
|
|
206
|
+
const significantLines = blockLines.filter((l) => l.trim() && !l.trim().startsWith("//") && !l.trim().startsWith("*"));
|
|
204
207
|
if (significantLines.length < minLines / 2)
|
|
205
208
|
continue;
|
|
206
|
-
const hash = crypto.createHash(
|
|
209
|
+
const hash = crypto.createHash("md5").update(normalized).digest("hex");
|
|
207
210
|
blocks.push({
|
|
208
211
|
hash,
|
|
209
212
|
path: filePath,
|
|
@@ -226,16 +229,16 @@ async function extractCodeBlocks(filePath, minLines, minTokens) {
|
|
|
226
229
|
function normalizeCode(code) {
|
|
227
230
|
return (code
|
|
228
231
|
// Remove comments
|
|
229
|
-
.replace(/\/\/.*$/gm,
|
|
230
|
-
.replace(/\/\*[\s\S]*?\*\//g,
|
|
232
|
+
.replace(/\/\/.*$/gm, "")
|
|
233
|
+
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
231
234
|
// Normalize whitespace
|
|
232
|
-
.replace(/\s+/g,
|
|
235
|
+
.replace(/\s+/g, " ")
|
|
233
236
|
// Remove string literals (replace with placeholder)
|
|
234
237
|
.replace(/"[^"]*"/g, '""')
|
|
235
238
|
.replace(/'[^']*'/g, "''")
|
|
236
|
-
.replace(/`[^`]*`/g,
|
|
239
|
+
.replace(/`[^`]*`/g, "``")
|
|
237
240
|
// Normalize numbers
|
|
238
|
-
.replace(/\b\d+\b/g,
|
|
241
|
+
.replace(/\b\d+\b/g, "0")
|
|
239
242
|
.trim());
|
|
240
243
|
}
|
|
241
244
|
/**
|
|
@@ -249,17 +252,17 @@ function countTokens(code) {
|
|
|
249
252
|
* Truncate sample to first N lines
|
|
250
253
|
*/
|
|
251
254
|
function truncateSample(content, maxLines) {
|
|
252
|
-
const lines = content.split(
|
|
255
|
+
const lines = content.split("\n");
|
|
253
256
|
if (lines.length <= maxLines)
|
|
254
257
|
return content;
|
|
255
|
-
return lines.slice(0, maxLines).join(
|
|
258
|
+
return lines.slice(0, maxLines).join("\n") + "\n...";
|
|
256
259
|
}
|
|
257
260
|
/**
|
|
258
261
|
* Create customizable findDuplicates tool
|
|
259
262
|
*/
|
|
260
263
|
export function createFindDuplicatesTool(options) {
|
|
261
264
|
return defineTool({
|
|
262
|
-
name: options?.name ??
|
|
265
|
+
name: options?.name ?? "find_duplicates",
|
|
263
266
|
description: options?.description ?? TOOL_DESCRIPTION,
|
|
264
267
|
inputSchema: TOOL_INPUT_SCHEMA,
|
|
265
268
|
execute: async (input) => {
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Find classes that implement an interface or extend an abstract class.
|
|
5
5
|
* Useful for understanding interface usage and finding concrete implementations.
|
|
6
6
|
*/
|
|
7
|
-
import type { Tool } from
|
|
8
|
-
import type { FindImplementationsInput } from
|
|
7
|
+
import type { Tool } from "@compilr-dev/agents";
|
|
8
|
+
import type { FindImplementationsInput } from "./types.js";
|
|
9
9
|
/**
|
|
10
10
|
* findImplementations tool - Find implementations of interfaces/abstract classes
|
|
11
11
|
*/
|
|
@@ -4,48 +4,53 @@
|
|
|
4
4
|
* Find classes that implement an interface or extend an abstract class.
|
|
5
5
|
* Useful for understanding interface usage and finding concrete implementations.
|
|
6
6
|
*/
|
|
7
|
-
import * as fs from
|
|
8
|
-
import * as path from
|
|
9
|
-
import * as ts from
|
|
10
|
-
import { defineTool, createSuccessResult, createErrorResult } from
|
|
11
|
-
import { detectLanguage, isLanguageSupported } from
|
|
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
12
|
// Tool description
|
|
13
13
|
const TOOL_DESCRIPTION = `Find classes that implement an interface or extend an abstract class.
|
|
14
14
|
Returns information about each implementation including which methods are implemented.
|
|
15
15
|
Useful for understanding how interfaces are used across the codebase.`;
|
|
16
16
|
// Tool input schema
|
|
17
17
|
const TOOL_INPUT_SCHEMA = {
|
|
18
|
-
type:
|
|
18
|
+
type: "object",
|
|
19
19
|
properties: {
|
|
20
20
|
name: {
|
|
21
|
-
type:
|
|
22
|
-
description:
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "Interface or abstract class name to find implementations of",
|
|
23
23
|
},
|
|
24
24
|
scope: {
|
|
25
|
-
type:
|
|
26
|
-
description:
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "Directory or file to search in (defaults to current directory)",
|
|
27
27
|
},
|
|
28
28
|
includeAbstract: {
|
|
29
|
-
type:
|
|
30
|
-
description:
|
|
29
|
+
type: "boolean",
|
|
30
|
+
description: "Include abstract classes that partially implement (default: false)",
|
|
31
31
|
default: false,
|
|
32
32
|
},
|
|
33
33
|
maxFiles: {
|
|
34
|
-
type:
|
|
35
|
-
description:
|
|
34
|
+
type: "number",
|
|
35
|
+
description: "Maximum files to search (default: 100)",
|
|
36
36
|
default: 100,
|
|
37
37
|
},
|
|
38
38
|
},
|
|
39
|
-
required: [
|
|
39
|
+
required: ["name"],
|
|
40
40
|
};
|
|
41
41
|
// Default file patterns
|
|
42
|
-
const DEFAULT_INCLUDE = [
|
|
43
|
-
const DEFAULT_EXCLUDE = [
|
|
42
|
+
const DEFAULT_INCLUDE = ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"];
|
|
43
|
+
const DEFAULT_EXCLUDE = [
|
|
44
|
+
"**/node_modules/**",
|
|
45
|
+
"**/dist/**",
|
|
46
|
+
"**/build/**",
|
|
47
|
+
"**/.git/**",
|
|
48
|
+
];
|
|
44
49
|
/**
|
|
45
50
|
* findImplementations tool - Find implementations of interfaces/abstract classes
|
|
46
51
|
*/
|
|
47
52
|
export const findImplementationsTool = defineTool({
|
|
48
|
-
name:
|
|
53
|
+
name: "find_implementations",
|
|
49
54
|
description: TOOL_DESCRIPTION,
|
|
50
55
|
inputSchema: TOOL_INPUT_SCHEMA,
|
|
51
56
|
execute: executeFindImplementations,
|
|
@@ -54,11 +59,11 @@ export const findImplementationsTool = defineTool({
|
|
|
54
59
|
* Execute the findImplementations tool
|
|
55
60
|
*/
|
|
56
61
|
async function executeFindImplementations(input) {
|
|
57
|
-
const { name, scope =
|
|
62
|
+
const { name, scope = ".", includeAbstract = false, maxFiles = 100 } = input;
|
|
58
63
|
const startTime = Date.now();
|
|
59
64
|
// Validate input
|
|
60
65
|
if (!name || name.trim().length === 0) {
|
|
61
|
-
return createErrorResult(
|
|
66
|
+
return createErrorResult("Interface or class name is required");
|
|
62
67
|
}
|
|
63
68
|
try {
|
|
64
69
|
// Resolve scope path
|
|
@@ -119,7 +124,7 @@ async function executeFindImplementations(input) {
|
|
|
119
124
|
*/
|
|
120
125
|
async function findTargetDefinition(filePath, targetName) {
|
|
121
126
|
try {
|
|
122
|
-
const content = await fs.readFile(filePath,
|
|
127
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
123
128
|
const detection = detectLanguage(filePath);
|
|
124
129
|
if (!detection.language) {
|
|
125
130
|
return null;
|
|
@@ -127,7 +132,7 @@ async function findTargetDefinition(filePath, targetName) {
|
|
|
127
132
|
if (!isLanguageSupported(detection.language)) {
|
|
128
133
|
return null;
|
|
129
134
|
}
|
|
130
|
-
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, filePath.endsWith(
|
|
135
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
|
|
131
136
|
let result = null;
|
|
132
137
|
const visit = (node) => {
|
|
133
138
|
// Check for interface declaration
|
|
@@ -207,7 +212,7 @@ function extractClassMethods(node, abstractOnly) {
|
|
|
207
212
|
*/
|
|
208
213
|
async function findImplementationsInFile(filePath, targetName, targetMethods, isInterface, isAbstractClass, includeAbstract) {
|
|
209
214
|
try {
|
|
210
|
-
const content = await fs.readFile(filePath,
|
|
215
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
211
216
|
const detection = detectLanguage(filePath);
|
|
212
217
|
if (!detection.language) {
|
|
213
218
|
return [];
|
|
@@ -215,7 +220,7 @@ async function findImplementationsInFile(filePath, targetName, targetMethods, is
|
|
|
215
220
|
if (!isLanguageSupported(detection.language)) {
|
|
216
221
|
return [];
|
|
217
222
|
}
|
|
218
|
-
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, filePath.endsWith(
|
|
223
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
|
|
219
224
|
const implementations = [];
|
|
220
225
|
const visit = (node) => {
|
|
221
226
|
// Check for class declaration
|
|
@@ -248,7 +253,7 @@ async function findImplementationsInFile(filePath, targetName, targetMethods, is
|
|
|
248
253
|
path: filePath,
|
|
249
254
|
line: line + 1,
|
|
250
255
|
column: character + 1,
|
|
251
|
-
kind:
|
|
256
|
+
kind: "object",
|
|
252
257
|
exported: isExported,
|
|
253
258
|
implementedMethods: targetMethods,
|
|
254
259
|
missingMethods: [],
|
|
@@ -277,7 +282,8 @@ function checkClassImplementation(node, sourceFile, filePath, targetName, target
|
|
|
277
282
|
if (className === targetName)
|
|
278
283
|
return null;
|
|
279
284
|
// Check if it's abstract
|
|
280
|
-
const classIsAbstract = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AbstractKeyword) ??
|
|
285
|
+
const classIsAbstract = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AbstractKeyword) ??
|
|
286
|
+
false;
|
|
281
287
|
// Skip abstract classes if not including them
|
|
282
288
|
if (classIsAbstract && !includeAbstract)
|
|
283
289
|
return null;
|
|
@@ -329,13 +335,14 @@ function checkClassImplementation(node, sourceFile, filePath, targetName, target
|
|
|
329
335
|
// Calculate missing methods
|
|
330
336
|
const missingMethods = targetMethods.filter((m) => !implementedMethods.includes(m));
|
|
331
337
|
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
332
|
-
const isExported = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ??
|
|
338
|
+
const isExported = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ??
|
|
339
|
+
false;
|
|
333
340
|
return {
|
|
334
341
|
name: className,
|
|
335
342
|
path: filePath,
|
|
336
343
|
line: line + 1,
|
|
337
344
|
column: character + 1,
|
|
338
|
-
kind:
|
|
345
|
+
kind: "class",
|
|
339
346
|
isAbstract: classIsAbstract,
|
|
340
347
|
exported: isExported,
|
|
341
348
|
implementedMethods,
|
|
@@ -358,13 +365,14 @@ function checkTypeImplementation(node, sourceFile, filePath, targetName) {
|
|
|
358
365
|
if (!extendsTarget)
|
|
359
366
|
return null;
|
|
360
367
|
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
361
|
-
const isExported = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ??
|
|
368
|
+
const isExported = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ??
|
|
369
|
+
false;
|
|
362
370
|
return {
|
|
363
371
|
name: node.name.text,
|
|
364
372
|
path: filePath,
|
|
365
373
|
line: line + 1,
|
|
366
374
|
column: character + 1,
|
|
367
|
-
kind:
|
|
375
|
+
kind: "type",
|
|
368
376
|
exported: isExported,
|
|
369
377
|
};
|
|
370
378
|
}
|
|
@@ -384,9 +392,9 @@ async function collectFiles(dirPath, include, exclude, maxDepth, maxFiles, curre
|
|
|
384
392
|
const relativePath = fullPath;
|
|
385
393
|
// Check exclusions
|
|
386
394
|
const isExcluded = exclude.some((pattern) => {
|
|
387
|
-
if (pattern.includes(
|
|
388
|
-
const simplePattern = pattern.replace(/\*\*/g,
|
|
389
|
-
return relativePath.includes(simplePattern.replace(/\*/g,
|
|
395
|
+
if (pattern.includes("**")) {
|
|
396
|
+
const simplePattern = pattern.replace(/\*\*/g, "");
|
|
397
|
+
return relativePath.includes(simplePattern.replace(/\*/g, ""));
|
|
390
398
|
}
|
|
391
399
|
return entry.name === pattern || relativePath.includes(pattern);
|
|
392
400
|
});
|
|
@@ -399,8 +407,8 @@ async function collectFiles(dirPath, include, exclude, maxDepth, maxFiles, curre
|
|
|
399
407
|
else if (entry.isFile()) {
|
|
400
408
|
// Check if file matches include patterns
|
|
401
409
|
const isIncluded = include.some((pattern) => {
|
|
402
|
-
if (pattern.includes(
|
|
403
|
-
const ext = pattern.replace(
|
|
410
|
+
if (pattern.includes("*")) {
|
|
411
|
+
const ext = pattern.replace("**/", "").replace("*", "");
|
|
404
412
|
return entry.name.endsWith(ext);
|
|
405
413
|
}
|
|
406
414
|
return entry.name === pattern;
|
|
@@ -421,7 +429,7 @@ async function collectFiles(dirPath, include, exclude, maxDepth, maxFiles, curre
|
|
|
421
429
|
*/
|
|
422
430
|
export function createFindImplementationsTool(options) {
|
|
423
431
|
return defineTool({
|
|
424
|
-
name: options?.name ??
|
|
432
|
+
name: options?.name ?? "find_implementations",
|
|
425
433
|
description: options?.description ?? TOOL_DESCRIPTION,
|
|
426
434
|
inputSchema: TOOL_INPUT_SCHEMA,
|
|
427
435
|
execute: async (input) => {
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Find code patterns, anti-patterns, and code smells in the codebase.
|
|
5
5
|
* Uses regex and AST-based pattern matching.
|
|
6
6
|
*/
|
|
7
|
-
import type { Tool } from
|
|
8
|
-
import type { FindPatternsInput, CodePattern } from
|
|
7
|
+
import type { Tool } from "@compilr-dev/agents";
|
|
8
|
+
import type { FindPatternsInput, CodePattern } from "./types.js";
|
|
9
9
|
/**
|
|
10
10
|
* findPatterns tool
|
|
11
11
|
*/
|