@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.
Files changed (49) hide show
  1. package/dist/index.d.ts +8 -5
  2. package/dist/index.js +14 -4
  3. package/dist/parser/index.d.ts +2 -2
  4. package/dist/parser/index.js +1 -1
  5. package/dist/parser/typescript-parser.d.ts +2 -2
  6. package/dist/parser/typescript-parser.js +77 -54
  7. package/dist/skills/code-health.js +18 -5
  8. package/dist/skills/code-structure.js +15 -5
  9. package/dist/skills/dependency-audit.js +16 -5
  10. package/dist/skills/index.d.ts +7 -7
  11. package/dist/skills/index.js +11 -11
  12. package/dist/skills/refactor-impact.js +16 -5
  13. package/dist/skills/type-analysis.js +16 -5
  14. package/dist/tools/find-dead-code.d.ts +2 -2
  15. package/dist/tools/find-dead-code.js +82 -58
  16. package/dist/tools/find-duplicates.d.ts +2 -2
  17. package/dist/tools/find-duplicates.js +41 -38
  18. package/dist/tools/find-implementations.d.ts +2 -2
  19. package/dist/tools/find-implementations.js +44 -36
  20. package/dist/tools/find-patterns.d.ts +2 -2
  21. package/dist/tools/find-patterns.js +154 -148
  22. package/dist/tools/find-references.d.ts +2 -2
  23. package/dist/tools/find-references.js +76 -72
  24. package/dist/tools/find-symbol.d.ts +2 -2
  25. package/dist/tools/find-symbol.js +106 -96
  26. package/dist/tools/get-call-graph.d.ts +2 -2
  27. package/dist/tools/get-call-graph.js +52 -47
  28. package/dist/tools/get-complexity.d.ts +2 -2
  29. package/dist/tools/get-complexity.js +94 -46
  30. package/dist/tools/get-dependency-graph.d.ts +2 -2
  31. package/dist/tools/get-dependency-graph.js +66 -52
  32. package/dist/tools/get-documentation.d.ts +2 -2
  33. package/dist/tools/get-documentation.js +154 -122
  34. package/dist/tools/get-exports.d.ts +2 -2
  35. package/dist/tools/get-exports.js +73 -61
  36. package/dist/tools/get-file-structure.d.ts +2 -2
  37. package/dist/tools/get-file-structure.js +16 -16
  38. package/dist/tools/get-imports.d.ts +2 -2
  39. package/dist/tools/get-imports.js +46 -46
  40. package/dist/tools/get-signature.d.ts +2 -2
  41. package/dist/tools/get-signature.js +168 -124
  42. package/dist/tools/get-type-hierarchy.d.ts +2 -2
  43. package/dist/tools/get-type-hierarchy.js +53 -44
  44. package/dist/tools/index.d.ts +18 -16
  45. package/dist/tools/index.js +17 -15
  46. package/dist/tools/read-symbol.d.ts +62 -0
  47. package/dist/tools/read-symbol.js +464 -0
  48. package/dist/tools/types.d.ts +27 -27
  49. package/package.json +3 -3
@@ -4,53 +4,53 @@
4
4
  * Calculate code complexity metrics including cyclomatic complexity,
5
5
  * cognitive complexity, nesting depth, and identify complexity hotspots.
6
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';
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 = `Calculate code complexity metrics for files or directories.
14
14
  Returns cyclomatic complexity, cognitive complexity, nesting depth, and identifies hotspots.
15
15
  Useful for finding functions that may need refactoring.`;
16
16
  // Tool input schema
17
17
  const TOOL_INPUT_SCHEMA = {
18
- type: 'object',
18
+ type: "object",
19
19
  properties: {
20
20
  path: {
21
- type: 'string',
22
- description: 'File or directory to analyze',
21
+ type: "string",
22
+ description: "File or directory to analyze",
23
23
  },
24
24
  recursive: {
25
- type: 'boolean',
26
- description: 'Recursive analysis for directories (default: false)',
25
+ type: "boolean",
26
+ description: "Recursive analysis for directories (default: false)",
27
27
  default: false,
28
28
  },
29
29
  threshold: {
30
- type: 'number',
31
- description: 'Complexity threshold for warnings (default: 10)',
30
+ type: "number",
31
+ description: "Complexity threshold for warnings (default: 10)",
32
32
  default: 10,
33
33
  },
34
34
  onlyAboveThreshold: {
35
- type: 'boolean',
36
- description: 'Only return items above threshold (default: false)',
35
+ type: "boolean",
36
+ description: "Only return items above threshold (default: false)",
37
37
  default: false,
38
38
  },
39
39
  maxFiles: {
40
- type: 'number',
41
- description: 'Maximum files to analyze (default: 50)',
40
+ type: "number",
41
+ description: "Maximum files to analyze (default: 50)",
42
42
  default: 50,
43
43
  },
44
44
  },
45
- required: ['path'],
45
+ required: ["path"],
46
46
  };
47
47
  // Default exclusions
48
- const DEFAULT_EXCLUDE = ['node_modules', 'dist', 'build', '.git', 'coverage'];
48
+ const DEFAULT_EXCLUDE = ["node_modules", "dist", "build", ".git", "coverage"];
49
49
  /**
50
50
  * getComplexity tool
51
51
  */
52
52
  export const getComplexityTool = defineTool({
53
- name: 'get_complexity',
53
+ name: "get_complexity",
54
54
  description: TOOL_DESCRIPTION,
55
55
  inputSchema: TOOL_INPUT_SCHEMA,
56
56
  execute: executeGetComplexity,
@@ -124,7 +124,9 @@ async function executeGetComplexity(input) {
124
124
  summary: {
125
125
  totalFiles: fileResults.length,
126
126
  totalFunctions,
127
- averageComplexity: totalFunctions > 0 ? Math.round((totalComplexity / totalFunctions) * 100) / 100 : 0,
127
+ averageComplexity: totalFunctions > 0
128
+ ? Math.round((totalComplexity / totalFunctions) * 100) / 100
129
+ : 0,
128
130
  maxComplexity,
129
131
  aboveThreshold: aboveThresholdCount,
130
132
  threshold,
@@ -157,7 +159,8 @@ async function collectFiles(dirPath, files, maxDepth, maxFiles, currentDepth = 0
157
159
  }
158
160
  else if (entry.isFile()) {
159
161
  // Only include TypeScript/JavaScript files
160
- if (/\.(ts|tsx|js|jsx)$/.test(entry.name) && !entry.name.endsWith('.d.ts')) {
162
+ if (/\.(ts|tsx|js|jsx)$/.test(entry.name) &&
163
+ !entry.name.endsWith(".d.ts")) {
161
164
  files.push(fullPath);
162
165
  }
163
166
  }
@@ -172,12 +175,12 @@ async function collectFiles(dirPath, files, maxDepth, maxFiles, currentDepth = 0
172
175
  */
173
176
  async function analyzeFile(filePath, threshold) {
174
177
  try {
175
- const content = await fs.readFile(filePath, 'utf-8');
178
+ const content = await fs.readFile(filePath, "utf-8");
176
179
  const detection = detectLanguage(filePath);
177
180
  if (!detection.language || !isLanguageSupported(detection.language)) {
178
181
  return null;
179
182
  }
180
- const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, filePath.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
183
+ const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
181
184
  const functions = [];
182
185
  let classCount = 0;
183
186
  // Visit all nodes
@@ -200,14 +203,18 @@ async function analyzeFile(filePath, threshold) {
200
203
  };
201
204
  visit(sourceFile);
202
205
  // Calculate file metrics
203
- const lines = content.split('\n');
206
+ const lines = content.split("\n");
204
207
  const totalLines = lines.length;
205
- const blankLines = lines.filter((l) => l.trim() === '').length;
208
+ const blankLines = lines.filter((l) => l.trim() === "").length;
206
209
  const linesOfCode = totalLines - blankLines;
207
210
  const avgComplexity = functions.length > 0
208
- ? Math.round((functions.reduce((sum, f) => sum + f.cyclomatic, 0) / functions.length) * 100) / 100
211
+ ? Math.round((functions.reduce((sum, f) => sum + f.cyclomatic, 0) /
212
+ functions.length) *
213
+ 100) / 100
214
+ : 0;
215
+ const maxComplexity = functions.length > 0
216
+ ? Math.max(...functions.map((f) => f.cyclomatic))
209
217
  : 0;
210
- const maxComplexity = functions.length > 0 ? Math.max(...functions.map((f) => f.cyclomatic)) : 0;
211
218
  return {
212
219
  path: filePath,
213
220
  metrics: {
@@ -230,12 +237,12 @@ async function analyzeFile(filePath, threshold) {
230
237
  */
231
238
  function analyzeFunctionComplexity(node, sourceFile, threshold) {
232
239
  // Get function name
233
- let name = '<anonymous>';
240
+ let name = "<anonymous>";
234
241
  if (ts.isFunctionDeclaration(node) && node.name) {
235
242
  name = node.name.text;
236
243
  }
237
244
  else if (ts.isMethodDeclaration(node)) {
238
- name = ts.isIdentifier(node.name) ? node.name.text : '<computed>';
245
+ name = ts.isIdentifier(node.name) ? node.name.text : "<computed>";
239
246
  }
240
247
  else if (ts.isFunctionExpression(node) && node.name) {
241
248
  name = node.name.text;
@@ -246,19 +253,22 @@ function analyzeFunctionComplexity(node, sourceFile, threshold) {
246
253
  if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) {
247
254
  name = parent.name.text;
248
255
  }
249
- else if (ts.isPropertyAssignment(parent) && ts.isIdentifier(parent.name)) {
256
+ else if (ts.isPropertyAssignment(parent) &&
257
+ ts.isIdentifier(parent.name)) {
250
258
  name = parent.name.text;
251
259
  }
252
260
  }
253
261
  // Skip anonymous functions in certain contexts
254
- if (name === '<anonymous>') {
262
+ if (name === "<anonymous>") {
255
263
  // Only include top-level anonymous functions or named expressions
256
264
  const parent = node.parent;
257
265
  if (!ts.isVariableDeclaration(parent) && !ts.isPropertyAssignment(parent)) {
258
266
  return null;
259
267
  }
260
268
  }
261
- const body = ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node) || ts.isFunctionExpression(node)
269
+ const body = ts.isFunctionDeclaration(node) ||
270
+ ts.isMethodDeclaration(node) ||
271
+ ts.isFunctionExpression(node)
262
272
  ? node.body
263
273
  : node.body;
264
274
  if (!body)
@@ -281,57 +291,95 @@ function analyzeFunctionComplexity(node, sourceFile, threshold) {
281
291
  if (ts.isIfStatement(n)) {
282
292
  cyclomatic++;
283
293
  cognitive += 1 + nestingLevel; // Cognitive adds nesting penalty
284
- contributors.push({ type: 'if', line: line + 1, contribution: 1 + nestingLevel });
294
+ contributors.push({
295
+ type: "if",
296
+ line: line + 1,
297
+ contribution: 1 + nestingLevel,
298
+ });
285
299
  }
286
300
  else if (ts.isConditionalExpression(n)) {
287
301
  cyclomatic++;
288
302
  cognitive += 1 + nestingLevel;
289
- contributors.push({ type: 'ternary', line: line + 1, contribution: 1 + nestingLevel });
303
+ contributors.push({
304
+ type: "ternary",
305
+ line: line + 1,
306
+ contribution: 1 + nestingLevel,
307
+ });
290
308
  }
291
- else if (ts.isForStatement(n) || ts.isForInStatement(n) || ts.isForOfStatement(n)) {
309
+ else if (ts.isForStatement(n) ||
310
+ ts.isForInStatement(n) ||
311
+ ts.isForOfStatement(n)) {
292
312
  cyclomatic++;
293
313
  cognitive += 1 + nestingLevel;
294
- contributors.push({ type: 'for', line: line + 1, contribution: 1 + nestingLevel });
314
+ contributors.push({
315
+ type: "for",
316
+ line: line + 1,
317
+ contribution: 1 + nestingLevel,
318
+ });
295
319
  }
296
320
  else if (ts.isWhileStatement(n)) {
297
321
  cyclomatic++;
298
322
  cognitive += 1 + nestingLevel;
299
- contributors.push({ type: 'while', line: line + 1, contribution: 1 + nestingLevel });
323
+ contributors.push({
324
+ type: "while",
325
+ line: line + 1,
326
+ contribution: 1 + nestingLevel,
327
+ });
300
328
  }
301
329
  else if (ts.isDoStatement(n)) {
302
330
  cyclomatic++;
303
331
  cognitive += 1 + nestingLevel;
304
- contributors.push({ type: 'do', line: line + 1, contribution: 1 + nestingLevel });
332
+ contributors.push({
333
+ type: "do",
334
+ line: line + 1,
335
+ contribution: 1 + nestingLevel,
336
+ });
305
337
  }
306
338
  else if (ts.isSwitchStatement(n)) {
307
339
  cyclomatic++;
308
340
  cognitive += 1 + nestingLevel;
309
- contributors.push({ type: 'switch', line: line + 1, contribution: 1 + nestingLevel });
341
+ contributors.push({
342
+ type: "switch",
343
+ line: line + 1,
344
+ contribution: 1 + nestingLevel,
345
+ });
310
346
  }
311
347
  else if (ts.isCaseClause(n)) {
312
348
  cyclomatic++;
313
- contributors.push({ type: 'case', line: line + 1, contribution: 1 });
349
+ contributors.push({ type: "case", line: line + 1, contribution: 1 });
314
350
  }
315
351
  else if (ts.isCatchClause(n)) {
316
352
  cyclomatic++;
317
353
  cognitive += 1 + nestingLevel;
318
- contributors.push({ type: 'catch', line: line + 1, contribution: 1 + nestingLevel });
354
+ contributors.push({
355
+ type: "catch",
356
+ line: line + 1,
357
+ contribution: 1 + nestingLevel,
358
+ });
319
359
  }
320
360
  else if (ts.isBinaryExpression(n)) {
321
361
  if (n.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) {
322
362
  cyclomatic++;
323
363
  cognitive++;
324
- contributors.push({ type: 'logical_and', line: line + 1, contribution: 1 });
364
+ contributors.push({
365
+ type: "logical_and",
366
+ line: line + 1,
367
+ contribution: 1,
368
+ });
325
369
  }
326
370
  else if (n.operatorToken.kind === ts.SyntaxKind.BarBarToken) {
327
371
  cyclomatic++;
328
372
  cognitive++;
329
- contributors.push({ type: 'logical_or', line: line + 1, contribution: 1 });
373
+ contributors.push({
374
+ type: "logical_or",
375
+ line: line + 1,
376
+ contribution: 1,
377
+ });
330
378
  }
331
379
  else if (n.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
332
380
  cyclomatic++;
333
381
  cognitive++;
334
- contributors.push({ type: 'nullish', line: line + 1, contribution: 1 });
382
+ contributors.push({ type: "nullish", line: line + 1, contribution: 1 });
335
383
  }
336
384
  }
337
385
  // Increase nesting for blocks
@@ -343,7 +391,7 @@ function analyzeFunctionComplexity(node, sourceFile, threshold) {
343
391
  analyzeNode(body, 0);
344
392
  // Calculate LOC
345
393
  const bodyText = body.getText(sourceFile);
346
- const bodyLines = bodyText.split('\n').filter((l) => l.trim() !== '').length;
394
+ const bodyLines = bodyText.split("\n").filter((l) => l.trim() !== "").length;
347
395
  // Parameter count
348
396
  const parameterCount = node.parameters.length;
349
397
  const aboveThreshold = cyclomatic >= threshold;
@@ -379,7 +427,7 @@ function isNestingNode(node) {
379
427
  */
380
428
  export function createGetComplexityTool(options) {
381
429
  return defineTool({
382
- name: options?.name ?? 'get_complexity',
430
+ name: options?.name ?? "get_complexity",
383
431
  description: options?.description ?? TOOL_DESCRIPTION,
384
432
  inputSchema: TOOL_INPUT_SCHEMA,
385
433
  execute: async (input) => {
@@ -4,8 +4,8 @@
4
4
  * Analyze module-level dependencies across a directory.
5
5
  * Builds a dependency graph and detects circular dependencies.
6
6
  */
7
- import type { Tool } from '@compilr-dev/agents';
8
- import type { GetDependencyGraphInput } from './types.js';
7
+ import type { Tool } from "@compilr-dev/agents";
8
+ import type { GetDependencyGraphInput } from "./types.js";
9
9
  /**
10
10
  * getDependencyGraph tool - Analyze module dependencies
11
11
  */
@@ -4,50 +4,62 @@
4
4
  * Analyze module-level dependencies across a directory.
5
5
  * Builds a dependency graph and detects circular dependencies.
6
6
  */
7
- import * as fs from 'node:fs/promises';
8
- import * as fsSync from 'node:fs';
9
- import * as path from 'node:path';
10
- import * as ts from 'typescript';
11
- import { defineTool, createSuccessResult, createErrorResult } from '@compilr-dev/agents';
12
- import { detectLanguage, isLanguageSupported } from '../parser/typescript-parser.js';
7
+ import * as fs from "node:fs/promises";
8
+ import * as fsSync from "node:fs";
9
+ import * as path from "node:path";
10
+ import * as ts from "typescript";
11
+ import { defineTool, createSuccessResult, createErrorResult, } from "@compilr-dev/agents";
12
+ import { detectLanguage, isLanguageSupported, } from "../parser/typescript-parser.js";
13
13
  // Tool description
14
14
  const TOOL_DESCRIPTION = `Analyze module-level dependencies across a directory.
15
15
  Returns a dependency graph showing which modules import which other modules.
16
16
  Detects circular dependencies and provides dependency statistics.`;
17
17
  // Tool input schema
18
18
  const TOOL_INPUT_SCHEMA = {
19
- type: 'object',
19
+ type: "object",
20
20
  properties: {
21
21
  path: {
22
- type: 'string',
23
- description: 'Directory or file to analyze',
22
+ type: "string",
23
+ description: "Directory or file to analyze",
24
24
  },
25
25
  includeExternal: {
26
- type: 'boolean',
27
- description: 'Include external package dependencies (default: true)',
26
+ type: "boolean",
27
+ description: "Include external package dependencies (default: true)",
28
28
  default: true,
29
29
  },
30
30
  includeTypeOnly: {
31
- type: 'boolean',
32
- description: 'Include type-only imports (default: true)',
31
+ type: "boolean",
32
+ description: "Include type-only imports (default: true)",
33
33
  default: true,
34
34
  },
35
35
  maxDepth: {
36
- type: 'number',
37
- description: 'Maximum depth for directory traversal (default: 10)',
36
+ type: "number",
37
+ description: "Maximum depth for directory traversal (default: 10)",
38
38
  default: 10,
39
39
  },
40
40
  },
41
- required: ['path'],
41
+ required: ["path"],
42
42
  };
43
43
  // Default file patterns
44
- const DEFAULT_INCLUDE = ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.mts', '**/*.mjs'];
45
- const DEFAULT_EXCLUDE = ['**/node_modules/**', '**/dist/**', '**/build/**', '**/.git/**'];
44
+ const DEFAULT_INCLUDE = [
45
+ "**/*.ts",
46
+ "**/*.tsx",
47
+ "**/*.js",
48
+ "**/*.jsx",
49
+ "**/*.mts",
50
+ "**/*.mjs",
51
+ ];
52
+ const DEFAULT_EXCLUDE = [
53
+ "**/node_modules/**",
54
+ "**/dist/**",
55
+ "**/build/**",
56
+ "**/.git/**",
57
+ ];
46
58
  /**
47
59
  * getDependencyGraph tool - Analyze module dependencies
48
60
  */
49
61
  export const getDependencyGraphTool = defineTool({
50
- name: 'get_dependency_graph',
62
+ name: "get_dependency_graph",
51
63
  description: TOOL_DESCRIPTION,
52
64
  inputSchema: TOOL_INPUT_SCHEMA,
53
65
  execute: executeGetDependencyGraph,
@@ -59,7 +71,7 @@ async function executeGetDependencyGraph(input) {
59
71
  const { path: inputPath, includeExternal = true, includeTypeOnly = true, maxDepth = 10, include = DEFAULT_INCLUDE, exclude = DEFAULT_EXCLUDE, } = input;
60
72
  // Validate input
61
73
  if (!inputPath || inputPath.trim().length === 0) {
62
- return createErrorResult('Path is required');
74
+ return createErrorResult("Path is required");
63
75
  }
64
76
  try {
65
77
  // Check if path exists
@@ -123,7 +135,8 @@ async function collectFiles(dir, include, exclude, maxDepth, currentDepth = 0) {
123
135
  }
124
136
  else if (entry.isFile()) {
125
137
  // Check if file matches include patterns
126
- if (matchesPattern(relativePath, include) && isSupportedFile(fullPath)) {
138
+ if (matchesPattern(relativePath, include) &&
139
+ isSupportedFile(fullPath)) {
127
140
  files.push(fullPath);
128
141
  }
129
142
  }
@@ -141,14 +154,14 @@ function matchesPattern(filePath, patterns) {
141
154
  const fileName = path.basename(filePath);
142
155
  for (const pattern of patterns) {
143
156
  // Handle simple glob patterns
144
- if (pattern.includes('**')) {
157
+ if (pattern.includes("**")) {
145
158
  // Check if any directory in path matches
146
- const patternDir = pattern.replace('**/', '').replace('/**', '');
147
- if (filePath.includes(patternDir.replace('*', ''))) {
159
+ const patternDir = pattern.replace("**/", "").replace("/**", "");
160
+ if (filePath.includes(patternDir.replace("*", ""))) {
148
161
  return true;
149
162
  }
150
163
  }
151
- else if (pattern.startsWith('*.')) {
164
+ else if (pattern.startsWith("*.")) {
152
165
  // Extension pattern
153
166
  const ext = pattern.substring(1);
154
167
  if (fileName.endsWith(ext)) {
@@ -198,15 +211,15 @@ async function analyzeDependencies(files, rootPath, includeExternal, includeType
198
211
  continue;
199
212
  }
200
213
  // Determine if external
201
- const isExternal = !imp.source.startsWith('.') && !imp.source.startsWith('/');
214
+ const isExternal = !imp.source.startsWith(".") && !imp.source.startsWith("/");
202
215
  if (isExternal) {
203
216
  if (!includeExternal) {
204
217
  continue;
205
218
  }
206
219
  // Extract package name (handle scoped packages)
207
- const packageName = imp.source.startsWith('@')
208
- ? imp.source.split('/').slice(0, 2).join('/')
209
- : imp.source.split('/')[0];
220
+ const packageName = imp.source.startsWith("@")
221
+ ? imp.source.split("/").slice(0, 2).join("/")
222
+ : imp.source.split("/")[0];
210
223
  externalPackages.add(packageName);
211
224
  // Add external module node
212
225
  if (!modules.has(packageName)) {
@@ -300,7 +313,7 @@ async function analyzeDependencies(files, rootPath, includeExternal, includeType
300
313
  async function extractImports(filePath) {
301
314
  const imports = [];
302
315
  try {
303
- const sourceCode = await fs.readFile(filePath, 'utf-8');
316
+ const sourceCode = await fs.readFile(filePath, "utf-8");
304
317
  const scriptKind = getScriptKind(filePath);
305
318
  const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true, scriptKind);
306
319
  ts.forEachChild(sourceFile, (node) => {
@@ -310,24 +323,25 @@ async function extractImports(filePath) {
310
323
  const source = node.moduleSpecifier.text;
311
324
  // Check for type-only import by looking at the import text
312
325
  const importText = node.getText(sourceFile);
313
- const typeOnly = importText.includes('import type');
326
+ const typeOnly = importText.includes("import type");
314
327
  const symbols = [];
315
- let importType = 'side-effect';
328
+ let importType = "side-effect";
316
329
  if (node.importClause) {
317
330
  // Default import
318
331
  if (node.importClause.name) {
319
- importType = 'default';
332
+ importType = "default";
320
333
  symbols.push(node.importClause.name.text);
321
334
  }
322
335
  // Named or namespace imports
323
336
  if (node.importClause.namedBindings) {
324
337
  if (ts.isNamespaceImport(node.importClause.namedBindings)) {
325
- importType = 'namespace';
338
+ importType = "namespace";
326
339
  symbols.push(node.importClause.namedBindings.name.text);
327
340
  }
328
341
  else if (ts.isNamedImports(node.importClause.namedBindings)) {
329
- importType = importType === 'default' ? 'default' : 'named';
330
- for (const element of node.importClause.namedBindings.elements) {
342
+ importType = importType === "default" ? "default" : "named";
343
+ for (const element of node.importClause.namedBindings
344
+ .elements) {
331
345
  symbols.push(element.name.text);
332
346
  }
333
347
  }
@@ -342,9 +356,9 @@ async function extractImports(filePath) {
342
356
  const source = node.moduleSpecifier.text;
343
357
  const typeOnly = node.isTypeOnly;
344
358
  const symbols = [];
345
- let importType = 'namespace';
359
+ let importType = "namespace";
346
360
  if (node.exportClause && ts.isNamedExports(node.exportClause)) {
347
- importType = 'named';
361
+ importType = "named";
348
362
  for (const element of node.exportClause.elements) {
349
363
  symbols.push(element.name.text);
350
364
  }
@@ -366,7 +380,7 @@ function resolveImportPath(fromFile, importSource, _rootPath) {
366
380
  const fromDir = path.dirname(fromFile);
367
381
  const basePath = path.resolve(fromDir, importSource);
368
382
  // Try various extensions
369
- const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mts', '.mjs', ''];
383
+ const extensions = [".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs", ""];
370
384
  for (const ext of extensions) {
371
385
  const candidate = basePath + ext;
372
386
  try {
@@ -377,7 +391,7 @@ function resolveImportPath(fromFile, importSource, _rootPath) {
377
391
  }
378
392
  catch {
379
393
  // Try index file
380
- const indexCandidate = path.join(basePath, `index${ext || '.ts'}`);
394
+ const indexCandidate = path.join(basePath, `index${ext || ".ts"}`);
381
395
  try {
382
396
  fsSync.accessSync(indexCandidate);
383
397
  return indexCandidate;
@@ -404,8 +418,8 @@ function detectCircularDependencies(adjacency) {
404
418
  if (cycleStart !== -1) {
405
419
  const cycle = [...path.slice(cycleStart), node];
406
420
  // Avoid duplicate cycles
407
- const cycleKey = [...cycle].sort().join('->');
408
- if (!cycles.some((c) => [...c.cycle].sort().join('->') === cycleKey)) {
421
+ const cycleKey = [...cycle].sort().join("->");
422
+ if (!cycles.some((c) => [...c.cycle].sort().join("->") === cycleKey)) {
409
423
  cycles.push({
410
424
  cycle,
411
425
  length: cycle.length - 1,
@@ -441,21 +455,21 @@ function detectCircularDependencies(adjacency) {
441
455
  * Get TypeScript script kind from file extension
442
456
  */
443
457
  function getScriptKind(filePath) {
444
- const ext = filePath.toLowerCase().split('.').pop();
458
+ const ext = filePath.toLowerCase().split(".").pop();
445
459
  switch (ext) {
446
- case 'ts':
460
+ case "ts":
447
461
  return ts.ScriptKind.TS;
448
- case 'tsx':
462
+ case "tsx":
449
463
  return ts.ScriptKind.TSX;
450
- case 'js':
464
+ case "js":
451
465
  return ts.ScriptKind.JS;
452
- case 'jsx':
466
+ case "jsx":
453
467
  return ts.ScriptKind.JSX;
454
- case 'mts':
455
- case 'cts':
468
+ case "mts":
469
+ case "cts":
456
470
  return ts.ScriptKind.TS;
457
- case 'mjs':
458
- case 'cjs':
471
+ case "mjs":
472
+ case "cjs":
459
473
  return ts.ScriptKind.JS;
460
474
  default:
461
475
  return ts.ScriptKind.TS;
@@ -467,7 +481,7 @@ function getScriptKind(filePath) {
467
481
  export function createGetDependencyGraphTool(options) {
468
482
  const { defaultIncludeExternal = true, defaultIncludeTypeOnly = true, defaultMaxDepth = 10, } = options ?? {};
469
483
  return defineTool({
470
- name: 'get_dependency_graph',
484
+ name: "get_dependency_graph",
471
485
  description: TOOL_DESCRIPTION,
472
486
  inputSchema: TOOL_INPUT_SCHEMA,
473
487
  execute: async (input) => {
@@ -4,8 +4,8 @@
4
4
  * Extract JSDoc/TSDoc documentation from source files.
5
5
  * Provides documentation coverage metrics and identifies undocumented exports.
6
6
  */
7
- import type { Tool } from '@compilr-dev/agents';
8
- import type { GetDocumentationInput } from './types.js';
7
+ import type { Tool } from "@compilr-dev/agents";
8
+ import type { GetDocumentationInput } from "./types.js";
9
9
  /**
10
10
  * getDocumentation tool
11
11
  */