@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,21 +4,21 @@
4
4
  * Find the definition location of a symbol across the codebase.
5
5
  * Uses TypeScript Compiler API for accurate AST analysis.
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
  // Supported file extensions for searching
13
13
  const SUPPORTED_EXTENSIONS = new Set([
14
- '.ts',
15
- '.tsx',
16
- '.js',
17
- '.jsx',
18
- '.mts',
19
- '.mjs',
20
- '.cts',
21
- '.cjs',
14
+ ".ts",
15
+ ".tsx",
16
+ ".js",
17
+ ".jsx",
18
+ ".mts",
19
+ ".mjs",
20
+ ".cts",
21
+ ".cjs",
22
22
  ]);
23
23
  // Helper to check for a specific modifier kind
24
24
  function hasModifierKind(modifiers, kind) {
@@ -30,50 +30,50 @@ Returns structured JSON with file path, line number, symbol kind, and other meta
30
30
  Use this to locate where functions, classes, variables, types, etc. are defined.`;
31
31
  // Tool input schema
32
32
  const TOOL_INPUT_SCHEMA = {
33
- type: 'object',
33
+ type: "object",
34
34
  properties: {
35
35
  symbol: {
36
- type: 'string',
37
- description: 'Symbol name to find',
36
+ type: "string",
37
+ description: "Symbol name to find",
38
38
  },
39
39
  scope: {
40
- type: 'string',
41
- description: 'Scope the search to a specific file or directory',
40
+ type: "string",
41
+ description: "Scope the search to a specific file or directory",
42
42
  },
43
43
  kind: {
44
- type: 'string',
44
+ type: "string",
45
45
  enum: [
46
- 'function',
47
- 'class',
48
- 'variable',
49
- 'type',
50
- 'interface',
51
- 'enum',
52
- 'method',
53
- 'property',
54
- 'any',
46
+ "function",
47
+ "class",
48
+ "variable",
49
+ "type",
50
+ "interface",
51
+ "enum",
52
+ "method",
53
+ "property",
54
+ "any",
55
55
  ],
56
- description: 'Filter by symbol kind (default: any)',
57
- default: 'any',
56
+ description: "Filter by symbol kind (default: any)",
57
+ default: "any",
58
58
  },
59
59
  limit: {
60
- type: 'number',
61
- description: 'Maximum results to return (default: 10)',
60
+ type: "number",
61
+ description: "Maximum results to return (default: 10)",
62
62
  default: 10,
63
63
  },
64
64
  includeNodeModules: {
65
- type: 'boolean',
66
- description: 'Include symbols from node_modules (default: false)',
65
+ type: "boolean",
66
+ description: "Include symbols from node_modules (default: false)",
67
67
  default: false,
68
68
  },
69
69
  },
70
- required: ['symbol'],
70
+ required: ["symbol"],
71
71
  };
72
72
  /**
73
73
  * findSymbol tool - Find symbol definitions
74
74
  */
75
75
  export const findSymbolTool = defineTool({
76
- name: 'find_symbol',
76
+ name: "find_symbol",
77
77
  description: TOOL_DESCRIPTION,
78
78
  inputSchema: TOOL_INPUT_SCHEMA,
79
79
  execute: executeFindSymbol,
@@ -82,10 +82,10 @@ export const findSymbolTool = defineTool({
82
82
  * Execute the findSymbol tool
83
83
  */
84
84
  async function executeFindSymbol(input) {
85
- const { symbol, scope, kind = 'any', limit = 10, includeNodeModules = false } = input;
85
+ const { symbol, scope, kind = "any", limit = 10, includeNodeModules = false, } = input;
86
86
  // Validate input
87
87
  if (!symbol || symbol.trim().length === 0) {
88
- return createErrorResult('Symbol name is required');
88
+ return createErrorResult("Symbol name is required");
89
89
  }
90
90
  const startTime = Date.now();
91
91
  const definitions = [];
@@ -152,14 +152,14 @@ async function collectFiles(dir, includeNodeModules) {
152
152
  const fullPath = path.join(currentDir, entry.name);
153
153
  if (entry.isDirectory()) {
154
154
  // Skip node_modules unless explicitly included
155
- if (entry.name === 'node_modules' && !includeNodeModules) {
155
+ if (entry.name === "node_modules" && !includeNodeModules) {
156
156
  continue;
157
157
  }
158
158
  // Skip common non-source directories
159
- if (entry.name.startsWith('.') ||
160
- entry.name === 'dist' ||
161
- entry.name === 'build' ||
162
- entry.name === 'coverage') {
159
+ if (entry.name.startsWith(".") ||
160
+ entry.name === "dist" ||
161
+ entry.name === "build" ||
162
+ entry.name === "coverage") {
163
163
  continue;
164
164
  }
165
165
  await walk(fullPath);
@@ -181,7 +181,7 @@ async function collectFiles(dir, includeNodeModules) {
181
181
  async function searchFileForSymbol(filePath, symbolName, kindFilter) {
182
182
  const definitions = [];
183
183
  try {
184
- const sourceCode = await fs.readFile(filePath, 'utf-8');
184
+ const sourceCode = await fs.readFile(filePath, "utf-8");
185
185
  const scriptKind = getScriptKind(filePath);
186
186
  const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true, scriptKind);
187
187
  // Search for symbols
@@ -196,21 +196,21 @@ async function searchFileForSymbol(filePath, symbolName, kindFilter) {
196
196
  * Get TypeScript script kind from file extension
197
197
  */
198
198
  function getScriptKind(filePath) {
199
- const ext = filePath.toLowerCase().split('.').pop();
199
+ const ext = filePath.toLowerCase().split(".").pop();
200
200
  switch (ext) {
201
- case 'ts':
201
+ case "ts":
202
202
  return ts.ScriptKind.TS;
203
- case 'tsx':
203
+ case "tsx":
204
204
  return ts.ScriptKind.TSX;
205
- case 'js':
205
+ case "js":
206
206
  return ts.ScriptKind.JS;
207
- case 'jsx':
207
+ case "jsx":
208
208
  return ts.ScriptKind.JSX;
209
- case 'mts':
210
- case 'cts':
209
+ case "mts":
210
+ case "cts":
211
211
  return ts.ScriptKind.TS;
212
- case 'mjs':
213
- case 'cjs':
212
+ case "mjs":
213
+ case "cjs":
214
214
  return ts.ScriptKind.JS;
215
215
  default:
216
216
  return ts.ScriptKind.TS;
@@ -244,40 +244,42 @@ function extractSymbolDefinition(node, sourceFile, symbolName, kindFilter, fileP
244
244
  let exported = false;
245
245
  let signature;
246
246
  let docSummary;
247
- const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
247
+ const modifiers = ts.canHaveModifiers(node)
248
+ ? ts.getModifiers(node)
249
+ : undefined;
248
250
  exported = hasModifierKind(modifiers, ts.SyntaxKind.ExportKeyword);
249
251
  // Function declarations
250
252
  if (ts.isFunctionDeclaration(node) && node.name) {
251
253
  name = node.name.text;
252
- kind = 'function';
254
+ kind = "function";
253
255
  signature = buildFunctionSignature(node);
254
256
  docSummary = getJsDocSummary(node, sourceFile);
255
257
  }
256
258
  // Class declarations
257
259
  else if (ts.isClassDeclaration(node) && node.name) {
258
260
  name = node.name.text;
259
- kind = 'class';
261
+ kind = "class";
260
262
  signature = `class ${name}`;
261
263
  docSummary = getJsDocSummary(node, sourceFile);
262
264
  }
263
265
  // Interface declarations
264
266
  else if (ts.isInterfaceDeclaration(node)) {
265
267
  name = node.name.text;
266
- kind = 'interface';
268
+ kind = "interface";
267
269
  signature = `interface ${name}`;
268
270
  docSummary = getJsDocSummary(node, sourceFile);
269
271
  }
270
272
  // Type alias declarations
271
273
  else if (ts.isTypeAliasDeclaration(node)) {
272
274
  name = node.name.text;
273
- kind = 'type';
275
+ kind = "type";
274
276
  signature = `type ${name}`;
275
277
  docSummary = getJsDocSummary(node, sourceFile);
276
278
  }
277
279
  // Enum declarations
278
280
  else if (ts.isEnumDeclaration(node)) {
279
281
  name = node.name.text;
280
- kind = 'enum';
282
+ kind = "enum";
281
283
  signature = `enum ${name}`;
282
284
  docSummary = getJsDocSummary(node, sourceFile);
283
285
  }
@@ -285,39 +287,42 @@ function extractSymbolDefinition(node, sourceFile, symbolName, kindFilter, fileP
285
287
  else if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
286
288
  // Skip if this is a function (arrow function or function expression)
287
289
  if (node.initializer &&
288
- (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))) {
290
+ (ts.isArrowFunction(node.initializer) ||
291
+ ts.isFunctionExpression(node.initializer))) {
289
292
  name = node.name.text;
290
- kind = 'function';
293
+ kind = "function";
291
294
  signature = buildArrowFunctionSignature(node);
292
295
  }
293
296
  else {
294
297
  name = node.name.text;
295
- kind = 'variable';
298
+ kind = "variable";
296
299
  signature = `${getVariableKind(node)} ${name}`;
297
300
  }
298
301
  // Check parent for export status
299
302
  const parent = node.parent.parent;
300
303
  if (ts.isVariableStatement(parent)) {
301
- const parentMods = ts.canHaveModifiers(parent) ? ts.getModifiers(parent) : undefined;
304
+ const parentMods = ts.canHaveModifiers(parent)
305
+ ? ts.getModifiers(parent)
306
+ : undefined;
302
307
  exported = hasModifierKind(parentMods, ts.SyntaxKind.ExportKeyword);
303
308
  docSummary = getJsDocSummary(parent, sourceFile);
304
309
  }
305
310
  }
306
311
  // Method declarations (inside classes)
307
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- node.name can be undefined for computed properties
308
- else if (ts.isMethodDeclaration(node) && node.name && ts.isIdentifier(node.name)) {
312
+ else if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) {
309
313
  name = node.name.text;
310
- kind = 'method';
314
+ kind = "method";
311
315
  signature = buildMethodSignature(node);
312
316
  docSummary = getJsDocSummary(node, sourceFile);
313
317
  // Methods are exported if their containing class is exported
314
318
  }
315
319
  // Property declarations (inside classes)
316
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- node.name can be undefined for computed properties
317
- else if (ts.isPropertyDeclaration(node) && node.name && ts.isIdentifier(node.name)) {
320
+ else if (ts.isPropertyDeclaration(node) && ts.isIdentifier(node.name)) {
318
321
  name = node.name.text;
319
- kind = 'property';
320
- const typeAnnotation = node.type ? `: ${node.type.getText(sourceFile)}` : '';
322
+ kind = "property";
323
+ const typeAnnotation = node.type
324
+ ? `: ${node.type.getText(sourceFile)}`
325
+ : "";
321
326
  signature = `${name}${typeAnnotation}`;
322
327
  docSummary = getJsDocSummary(node, sourceFile);
323
328
  }
@@ -329,9 +334,9 @@ function extractSymbolDefinition(node, sourceFile, symbolName, kindFilter, fileP
329
334
  return null;
330
335
  }
331
336
  // Apply kind filter
332
- if (kindFilter !== 'any' && kind !== kindFilter) {
337
+ if (kindFilter !== "any" && kind !== kindFilter) {
333
338
  // Handle type filter matching both 'type' and 'interface'
334
- if (kindFilter === 'type' && kind === 'interface') {
339
+ if (kindFilter === "type" && kind === "interface") {
335
340
  // Allow interface to match type filter
336
341
  }
337
342
  else {
@@ -360,64 +365,69 @@ function getVariableKind(node) {
360
365
  const parent = node.parent;
361
366
  if (ts.isVariableDeclarationList(parent)) {
362
367
  if (parent.flags & ts.NodeFlags.Const)
363
- return 'const';
368
+ return "const";
364
369
  if (parent.flags & ts.NodeFlags.Let)
365
- return 'let';
370
+ return "let";
366
371
  }
367
- return 'var';
372
+ return "var";
368
373
  }
369
374
  /**
370
375
  * Build a function signature string
371
376
  */
372
377
  function buildFunctionSignature(node) {
373
- const name = node.name?.text ?? 'anonymous';
378
+ const name = node.name?.text ?? "anonymous";
374
379
  const params = node.parameters
375
380
  .map((p) => {
376
- const paramName = ts.isIdentifier(p.name) ? p.name.text : 'param';
377
- const paramType = p.type ? p.type.getText() : '';
381
+ const paramName = ts.isIdentifier(p.name) ? p.name.text : "param";
382
+ const paramType = p.type ? p.type.getText() : "";
378
383
  return paramType ? `${paramName}: ${paramType}` : paramName;
379
384
  })
380
- .join(', ');
381
- const returnType = node.type ? `: ${node.type.getText()}` : '';
385
+ .join(", ");
386
+ const returnType = node.type ? `: ${node.type.getText()}` : "";
382
387
  const asyncPrefix = hasModifierKind(ts.getModifiers(node), ts.SyntaxKind.AsyncKeyword)
383
- ? 'async '
384
- : '';
388
+ ? "async "
389
+ : "";
385
390
  return `${asyncPrefix}function ${name}(${params})${returnType}`;
386
391
  }
387
392
  /**
388
393
  * Build a method signature string
389
394
  */
390
395
  function buildMethodSignature(node) {
391
- const name = ts.isIdentifier(node.name) ? node.name.text : 'method';
396
+ const name = ts.isIdentifier(node.name) ? node.name.text : "method";
392
397
  const params = node.parameters
393
398
  .map((p) => {
394
- const paramName = ts.isIdentifier(p.name) ? p.name.text : 'param';
395
- const paramType = p.type ? p.type.getText() : '';
399
+ const paramName = ts.isIdentifier(p.name) ? p.name.text : "param";
400
+ const paramType = p.type ? p.type.getText() : "";
396
401
  return paramType ? `${paramName}: ${paramType}` : paramName;
397
402
  })
398
- .join(', ');
399
- const returnType = node.type ? `: ${node.type.getText()}` : '';
403
+ .join(", ");
404
+ const returnType = node.type ? `: ${node.type.getText()}` : "";
400
405
  const modifiers = ts.getModifiers(node);
401
- const asyncPrefix = hasModifierKind(modifiers, ts.SyntaxKind.AsyncKeyword) ? 'async ' : '';
402
- const staticPrefix = hasModifierKind(modifiers, ts.SyntaxKind.StaticKeyword) ? 'static ' : '';
406
+ const asyncPrefix = hasModifierKind(modifiers, ts.SyntaxKind.AsyncKeyword)
407
+ ? "async "
408
+ : "";
409
+ const staticPrefix = hasModifierKind(modifiers, ts.SyntaxKind.StaticKeyword)
410
+ ? "static "
411
+ : "";
403
412
  return `${staticPrefix}${asyncPrefix}${name}(${params})${returnType}`;
404
413
  }
405
414
  /**
406
415
  * Build an arrow function signature string from variable declaration
407
416
  */
408
417
  function buildArrowFunctionSignature(node) {
409
- const name = ts.isIdentifier(node.name) ? node.name.text : 'anonymous';
418
+ const name = ts.isIdentifier(node.name) ? node.name.text : "anonymous";
410
419
  if (node.initializer &&
411
- (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))) {
420
+ (ts.isArrowFunction(node.initializer) ||
421
+ ts.isFunctionExpression(node.initializer))) {
412
422
  const func = node.initializer;
413
423
  const params = func.parameters
414
424
  .map((p) => {
415
- const paramName = ts.isIdentifier(p.name) ? p.name.text : 'param';
416
- const paramType = p.type ? p.type.getText() : '';
425
+ const paramName = ts.isIdentifier(p.name) ? p.name.text : "param";
426
+ const paramType = p.type ? p.type.getText() : "";
417
427
  return paramType ? `${paramName}: ${paramType}` : paramName;
418
428
  })
419
- .join(', ');
420
- const returnType = func.type ? `: ${func.type.getText()}` : '';
429
+ .join(", ");
430
+ const returnType = func.type ? `: ${func.type.getText()}` : "";
421
431
  return `const ${name} = (${params})${returnType}`;
422
432
  }
423
433
  return `const ${name}`;
@@ -444,7 +454,7 @@ function getJsDocSummary(node, sourceFile) {
444
454
  export function createFindSymbolTool(options) {
445
455
  const { defaultLimit = 10, defaultIncludeNodeModules = false } = options ?? {};
446
456
  return defineTool({
447
- name: 'find_symbol',
457
+ name: "find_symbol",
448
458
  description: TOOL_DESCRIPTION,
449
459
  inputSchema: TOOL_INPUT_SCHEMA,
450
460
  execute: async (input) => {
@@ -4,8 +4,8 @@
4
4
  * Analyze function call relationships using TypeScript Compiler API.
5
5
  * Returns a call graph showing what functions call what.
6
6
  */
7
- import type { Tool } from '@compilr-dev/agents';
8
- import type { GetCallGraphInput, CallGraphDirection } from './types.js';
7
+ import type { Tool } from "@compilr-dev/agents";
8
+ import type { GetCallGraphInput, CallGraphDirection } from "./types.js";
9
9
  /**
10
10
  * getCallGraph tool - Analyze function call relationships
11
11
  */
@@ -4,54 +4,54 @@
4
4
  * Analyze function call relationships using TypeScript Compiler API.
5
5
  * Returns a call graph showing what functions call what.
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 = `Analyze function call relationships in source code.
14
14
  Returns a call graph showing which functions call which other functions.
15
15
  Use this to understand code flow, dependencies, and refactoring impact.`;
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 to analyze',
21
+ type: "string",
22
+ description: "File to analyze",
23
23
  },
24
24
  functionName: {
25
- type: 'string',
26
- description: 'Specific function to analyze (optional)',
25
+ type: "string",
26
+ description: "Specific function to analyze (optional)",
27
27
  },
28
28
  direction: {
29
- type: 'string',
30
- enum: ['callers', 'callees', 'both'],
29
+ type: "string",
30
+ enum: ["callers", "callees", "both"],
31
31
  description: "Direction: 'callers' | 'callees' | 'both' (default: 'both')",
32
32
  },
33
33
  maxDepth: {
34
- type: 'number',
35
- description: 'Maximum depth to traverse (default: 2)',
34
+ type: "number",
35
+ description: "Maximum depth to traverse (default: 2)",
36
36
  default: 2,
37
37
  },
38
38
  includeExternal: {
39
- type: 'boolean',
40
- description: 'Include external package calls (default: false)',
39
+ type: "boolean",
40
+ description: "Include external package calls (default: false)",
41
41
  default: false,
42
42
  },
43
43
  scope: {
44
- type: 'string',
44
+ type: "string",
45
45
  description: "Scope directory for finding callers (default: file's directory)",
46
46
  },
47
47
  },
48
- required: ['path'],
48
+ required: ["path"],
49
49
  };
50
50
  /**
51
51
  * getCallGraph tool - Analyze function call relationships
52
52
  */
53
53
  export const getCallGraphTool = defineTool({
54
- name: 'get_call_graph',
54
+ name: "get_call_graph",
55
55
  description: TOOL_DESCRIPTION,
56
56
  inputSchema: TOOL_INPUT_SCHEMA,
57
57
  execute: executeGetCallGraph,
@@ -60,10 +60,10 @@ export const getCallGraphTool = defineTool({
60
60
  * Execute the getCallGraph tool
61
61
  */
62
62
  async function executeGetCallGraph(input) {
63
- const { path: inputPath, functionName, direction = 'both', maxDepth = 2, includeExternal = false, scope, } = input;
63
+ const { path: inputPath, functionName, direction = "both", maxDepth = 2, includeExternal = false, scope, } = input;
64
64
  // Validate input
65
65
  if (!inputPath || inputPath.trim().length === 0) {
66
- return createErrorResult('Path is required');
66
+ return createErrorResult("Path is required");
67
67
  }
68
68
  try {
69
69
  // Check if path exists
@@ -96,7 +96,7 @@ async function executeGetCallGraph(input) {
96
96
  * Analyze call graph for a file
97
97
  */
98
98
  async function analyzeCallGraph(filePath, functionName, direction, maxDepth, includeExternal, _scopeDir) {
99
- const sourceCode = await fs.readFile(filePath, 'utf-8');
99
+ const sourceCode = await fs.readFile(filePath, "utf-8");
100
100
  const scriptKind = getScriptKind(filePath);
101
101
  const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true, scriptKind);
102
102
  // Find all functions in the file
@@ -122,7 +122,7 @@ async function analyzeCallGraph(filePath, functionName, direction, maxDepth, inc
122
122
  rootNode = targetFunc.node;
123
123
  }
124
124
  // Analyze callees (what each function calls)
125
- if (direction === 'callees' || direction === 'both') {
125
+ if (direction === "callees" || direction === "both") {
126
126
  const functionsToAnalyze = functionName
127
127
  ? functions.filter((f) => f.node.name === functionName)
128
128
  : functions;
@@ -140,12 +140,12 @@ async function analyzeCallGraph(filePath, functionName, direction, maxDepth, inc
140
140
  graphNode.calls = callees;
141
141
  // Count external calls
142
142
  if (includeExternal) {
143
- externalCallCount += callees.filter((c) => c.function.path === 'external').length;
143
+ externalCallCount += callees.filter((c) => c.function.path === "external").length;
144
144
  }
145
145
  }
146
146
  }
147
147
  // Analyze callers (what calls each function)
148
- if (direction === 'callers' || direction === 'both') {
148
+ if (direction === "callers" || direction === "both") {
149
149
  const functionsToAnalyze = functionName
150
150
  ? functions.filter((f) => f.node.name === functionName)
151
151
  : functions;
@@ -208,7 +208,8 @@ function extractFunctions(sourceFile, filePath) {
208
208
  const decls = node.declarationList.declarations;
209
209
  for (const decl of decls) {
210
210
  if (ts.isIdentifier(decl.name) && decl.initializer) {
211
- if (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer)) {
211
+ if (ts.isArrowFunction(decl.initializer) ||
212
+ ts.isFunctionExpression(decl.initializer)) {
212
213
  const { line, character } = sourceFile.getLineAndCharacterOfPosition(decl.getStart(sourceFile));
213
214
  const isExported = hasExportModifier(node);
214
215
  const isAsync = hasAsyncModifier(decl.initializer);
@@ -295,7 +296,7 @@ function extractCallees(sourceFile, func, allFunctions, includeExternal) {
295
296
  function extractCallInfo(node, sourceFile, allFunctions, includeExternal) {
296
297
  const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
297
298
  let funcName;
298
- let callType = 'direct';
299
+ let callType = "direct";
299
300
  let className;
300
301
  // Simple function call: funcName()
301
302
  if (ts.isIdentifier(node.expression)) {
@@ -306,14 +307,14 @@ function extractCallInfo(node, sourceFile, allFunctions, includeExternal) {
306
307
  funcName = node.expression.name.text;
307
308
  const propName = node.expression.name.text;
308
309
  // Check for promise chain
309
- if (propName === 'then' || propName === 'catch' || propName === 'finally') {
310
- callType = 'promise';
310
+ if (propName === "then" || propName === "catch" || propName === "finally") {
311
+ callType = "promise";
311
312
  }
312
313
  else {
313
- callType = 'method';
314
+ callType = "method";
314
315
  if (ts.isIdentifier(node.expression.expression)) {
315
316
  const objName = node.expression.expression.text;
316
- if (objName !== 'this') {
317
+ if (objName !== "this") {
317
318
  // Could be instance.method or ClassName.staticMethod
318
319
  className = objName;
319
320
  }
@@ -339,7 +340,7 @@ function extractCallInfo(node, sourceFile, allFunctions, includeExternal) {
339
340
  return {
340
341
  function: {
341
342
  name: funcName,
342
- path: 'external',
343
+ path: "external",
343
344
  line: 0,
344
345
  column: 0,
345
346
  className,
@@ -403,7 +404,7 @@ function findCallersInFile(sourceFile, targetFuncName, allFunctions, _filePath)
403
404
  function: func.node,
404
405
  callLine,
405
406
  callColumn,
406
- type: 'direct',
407
+ type: "direct",
407
408
  count: callCount,
408
409
  });
409
410
  }
@@ -414,35 +415,39 @@ function findCallersInFile(sourceFile, targetFuncName, allFunctions, _filePath)
414
415
  * Check if a node has export modifier
415
416
  */
416
417
  function hasExportModifier(node) {
417
- const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
418
- return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
418
+ const modifiers = ts.canHaveModifiers(node)
419
+ ? ts.getModifiers(node)
420
+ : undefined;
421
+ return (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false);
419
422
  }
420
423
  /**
421
424
  * Check if a node has async modifier
422
425
  */
423
426
  function hasAsyncModifier(node) {
424
- const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
427
+ const modifiers = ts.canHaveModifiers(node)
428
+ ? ts.getModifiers(node)
429
+ : undefined;
425
430
  return modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
426
431
  }
427
432
  /**
428
433
  * Get TypeScript script kind from file extension
429
434
  */
430
435
  function getScriptKind(filePath) {
431
- const ext = filePath.toLowerCase().split('.').pop();
436
+ const ext = filePath.toLowerCase().split(".").pop();
432
437
  switch (ext) {
433
- case 'ts':
438
+ case "ts":
434
439
  return ts.ScriptKind.TS;
435
- case 'tsx':
440
+ case "tsx":
436
441
  return ts.ScriptKind.TSX;
437
- case 'js':
442
+ case "js":
438
443
  return ts.ScriptKind.JS;
439
- case 'jsx':
444
+ case "jsx":
440
445
  return ts.ScriptKind.JSX;
441
- case 'mts':
442
- case 'cts':
446
+ case "mts":
447
+ case "cts":
443
448
  return ts.ScriptKind.TS;
444
- case 'mjs':
445
- case 'cjs':
449
+ case "mjs":
450
+ case "cjs":
446
451
  return ts.ScriptKind.JS;
447
452
  default:
448
453
  return ts.ScriptKind.TS;
@@ -452,9 +457,9 @@ function getScriptKind(filePath) {
452
457
  * Factory function to create a customized getCallGraph tool
453
458
  */
454
459
  export function createGetCallGraphTool(options) {
455
- const { defaultDirection = 'both', defaultMaxDepth = 2, defaultIncludeExternal = false, } = options ?? {};
460
+ const { defaultDirection = "both", defaultMaxDepth = 2, defaultIncludeExternal = false, } = options ?? {};
456
461
  return defineTool({
457
- name: 'get_call_graph',
462
+ name: "get_call_graph",
458
463
  description: TOOL_DESCRIPTION,
459
464
  inputSchema: TOOL_INPUT_SCHEMA,
460
465
  execute: async (input) => {
@@ -4,8 +4,8 @@
4
4
  * Calculate code complexity metrics including cyclomatic complexity,
5
5
  * cognitive complexity, nesting depth, and identify complexity hotspots.
6
6
  */
7
- import type { Tool } from '@compilr-dev/agents';
8
- import type { GetComplexityInput } from './types.js';
7
+ import type { Tool } from "@compilr-dev/agents";
8
+ import type { GetComplexityInput } from "./types.js";
9
9
  /**
10
10
  * getComplexity tool
11
11
  */