@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,11 +4,11 @@
4
4
  * Extract JSDoc/TSDoc documentation from source files.
5
5
  * Provides documentation coverage metrics and identifies undocumented exports.
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 = `Extract JSDoc/TSDoc documentation from source files.
14
14
  Returns documented symbols with their signatures and documentation content.
@@ -16,52 +16,52 @@ Calculates documentation coverage metrics and identifies undocumented exports.
16
16
  Useful for generating API documentation and measuring doc coverage.`;
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: 'File or directory to analyze',
22
+ type: "string",
23
+ description: "File or directory to analyze",
24
24
  },
25
25
  recursive: {
26
- type: 'boolean',
27
- description: 'Recursive analysis for directories (default: false)',
26
+ type: "boolean",
27
+ description: "Recursive analysis for directories (default: false)",
28
28
  default: false,
29
29
  },
30
30
  kinds: {
31
- type: 'array',
32
- items: { type: 'string' },
33
- description: 'Filter by symbol kinds: function, class, interface, type, enum, variable, method, property',
31
+ type: "array",
32
+ items: { type: "string" },
33
+ description: "Filter by symbol kinds: function, class, interface, type, enum, variable, method, property",
34
34
  },
35
35
  exportedOnly: {
36
- type: 'boolean',
37
- description: 'Only include exported symbols (default: false)',
36
+ type: "boolean",
37
+ description: "Only include exported symbols (default: false)",
38
38
  default: false,
39
39
  },
40
40
  documentedOnly: {
41
- type: 'boolean',
42
- description: 'Only include symbols with documentation (default: true)',
41
+ type: "boolean",
42
+ description: "Only include symbols with documentation (default: true)",
43
43
  default: true,
44
44
  },
45
45
  maxFiles: {
46
- type: 'number',
47
- description: 'Maximum files to analyze (default: 50)',
46
+ type: "number",
47
+ description: "Maximum files to analyze (default: 50)",
48
48
  default: 50,
49
49
  },
50
50
  includePrivate: {
51
- type: 'boolean',
52
- description: 'Include private class members (default: false)',
51
+ type: "boolean",
52
+ description: "Include private class members (default: false)",
53
53
  default: false,
54
54
  },
55
55
  },
56
- required: ['path'],
56
+ required: ["path"],
57
57
  };
58
58
  // Default exclusions
59
- const DEFAULT_EXCLUDE = ['node_modules', 'dist', 'build', '.git', 'coverage'];
59
+ const DEFAULT_EXCLUDE = ["node_modules", "dist", "build", ".git", "coverage"];
60
60
  /**
61
61
  * getDocumentation tool
62
62
  */
63
63
  export const getDocumentationTool = defineTool({
64
- name: 'get_documentation',
64
+ name: "get_documentation",
65
65
  description: TOOL_DESCRIPTION,
66
66
  inputSchema: TOOL_INPUT_SCHEMA,
67
67
  execute: executeGetDocumentation,
@@ -120,7 +120,9 @@ async function executeGetDocumentation(input) {
120
120
  }
121
121
  }
122
122
  }
123
- const coveragePercent = totalSymbols > 0 ? Math.round((documentedSymbols / totalSymbols) * 100) : 100;
123
+ const coveragePercent = totalSymbols > 0
124
+ ? Math.round((documentedSymbols / totalSymbols) * 100)
125
+ : 100;
124
126
  const result = {
125
127
  path: resolvedPath,
126
128
  files: fileResults,
@@ -170,7 +172,8 @@ async function collectFiles(dirPath, files, maxDepth, maxFiles, currentDepth = 0
170
172
  }
171
173
  else if (entry.isFile()) {
172
174
  // Only include TypeScript/JavaScript files
173
- if (/\.(ts|tsx|js|jsx)$/.test(entry.name) && !entry.name.endsWith('.d.ts')) {
175
+ if (/\.(ts|tsx|js|jsx)$/.test(entry.name) &&
176
+ !entry.name.endsWith(".d.ts")) {
174
177
  files.push(fullPath);
175
178
  }
176
179
  }
@@ -185,12 +188,12 @@ async function collectFiles(dirPath, files, maxDepth, maxFiles, currentDepth = 0
185
188
  */
186
189
  async function analyzeFile(filePath, options) {
187
190
  try {
188
- const content = await fs.readFile(filePath, 'utf-8');
191
+ const content = await fs.readFile(filePath, "utf-8");
189
192
  const detection = detectLanguage(filePath);
190
193
  if (!detection.language || !isLanguageSupported(detection.language)) {
191
194
  return null;
192
195
  }
193
- const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, filePath.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
196
+ const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
194
197
  // Extract file-level documentation
195
198
  const fileDoc = extractFileDocumentation(sourceFile);
196
199
  // Extract symbol documentation
@@ -212,7 +215,9 @@ async function analyzeFile(filePath, options) {
212
215
  const totalSymbols = allSymbols.length;
213
216
  const documentedCount = allSymbols.filter((s) => hasDocumentation(s.documentation)).length;
214
217
  const undocumentedCount = totalSymbols - documentedCount;
215
- const coveragePercent = totalSymbols > 0 ? Math.round((documentedCount / totalSymbols) * 100) : 100;
218
+ const coveragePercent = totalSymbols > 0
219
+ ? Math.round((documentedCount / totalSymbols) * 100)
220
+ : 100;
216
221
  return {
217
222
  path: filePath,
218
223
  fileDoc: fileDoc && hasDocumentation(fileDoc) ? fileDoc : undefined,
@@ -239,25 +244,27 @@ function extractFileDocumentation(sourceFile) {
239
244
  if (!match)
240
245
  return undefined;
241
246
  const commentText = match[1];
242
- const lines = commentText.split('\n').map((l) => l.replace(/^\s*\*\s?/, '').trim());
247
+ const lines = commentText
248
+ .split("\n")
249
+ .map((l) => l.replace(/^\s*\*\s?/, "").trim());
243
250
  // Filter out @module and similar file-level tags, and empty lines
244
251
  const descLines = [];
245
252
  let isFileLevel = false;
246
253
  for (const line of lines) {
247
- if (line.startsWith('@module') ||
248
- line.startsWith('@fileoverview') ||
249
- line.startsWith('@file')) {
254
+ if (line.startsWith("@module") ||
255
+ line.startsWith("@fileoverview") ||
256
+ line.startsWith("@file")) {
250
257
  isFileLevel = true;
251
258
  }
252
- else if (!line.startsWith('@') && line.length > 0) {
259
+ else if (!line.startsWith("@") && line.length > 0) {
253
260
  descLines.push(line);
254
261
  }
255
262
  }
256
263
  // Only return if this looks like a file-level comment
257
264
  if (!isFileLevel && descLines.length === 0)
258
265
  return undefined;
259
- const summary = descLines[0] || '';
260
- const description = descLines.length > 1 ? descLines.slice(1).join('\n').trim() : undefined;
266
+ const summary = descLines[0] || "";
267
+ const description = descLines.length > 1 ? descLines.slice(1).join("\n").trim() : undefined;
261
268
  return {
262
269
  summary,
263
270
  description,
@@ -269,56 +276,58 @@ function extractFileDocumentation(sourceFile) {
269
276
  function extractSymbols(node, sourceFile, symbols, options, _containerName) {
270
277
  // Function declarations
271
278
  if (ts.isFunctionDeclaration(node) && node.name) {
272
- symbols.push(extractSymbolInfo(node, sourceFile, 'function', node.name.text));
279
+ symbols.push(extractSymbolInfo(node, sourceFile, "function", node.name.text));
273
280
  }
274
281
  // Variable declarations (arrow functions, const values)
275
282
  else if (ts.isVariableStatement(node)) {
276
283
  for (const decl of node.declarationList.declarations) {
277
284
  if (ts.isIdentifier(decl.name)) {
278
285
  const kind = decl.initializer &&
279
- (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))
280
- ? 'function'
281
- : 'variable';
286
+ (ts.isArrowFunction(decl.initializer) ||
287
+ ts.isFunctionExpression(decl.initializer))
288
+ ? "function"
289
+ : "variable";
282
290
  symbols.push(extractSymbolInfo(node, sourceFile, kind, decl.name.text));
283
291
  }
284
292
  }
285
293
  }
286
294
  // Class declarations
287
295
  else if (ts.isClassDeclaration(node) && node.name) {
288
- symbols.push(extractSymbolInfo(node, sourceFile, 'class', node.name.text));
296
+ symbols.push(extractSymbolInfo(node, sourceFile, "class", node.name.text));
289
297
  // Extract class members
290
298
  for (const member of node.members) {
291
299
  // Skip private members if not included
292
300
  if (!options.includePrivate && isPrivateMember(member))
293
301
  continue;
294
302
  if (ts.isMethodDeclaration(member) && ts.isIdentifier(member.name)) {
295
- symbols.push(extractSymbolInfo(member, sourceFile, 'method', member.name.text, node.name.text));
303
+ symbols.push(extractSymbolInfo(member, sourceFile, "method", member.name.text, node.name.text));
296
304
  }
297
- else if (ts.isPropertyDeclaration(member) && ts.isIdentifier(member.name)) {
298
- symbols.push(extractSymbolInfo(member, sourceFile, 'property', member.name.text, node.name.text));
305
+ else if (ts.isPropertyDeclaration(member) &&
306
+ ts.isIdentifier(member.name)) {
307
+ symbols.push(extractSymbolInfo(member, sourceFile, "property", member.name.text, node.name.text));
299
308
  }
300
309
  }
301
310
  }
302
311
  // Interface declarations
303
312
  else if (ts.isInterfaceDeclaration(node)) {
304
- symbols.push(extractSymbolInfo(node, sourceFile, 'interface', node.name.text));
313
+ symbols.push(extractSymbolInfo(node, sourceFile, "interface", node.name.text));
305
314
  // Extract interface members
306
315
  for (const member of node.members) {
307
316
  if (ts.isPropertySignature(member) && ts.isIdentifier(member.name)) {
308
- symbols.push(extractSymbolInfo(member, sourceFile, 'property', member.name.text, node.name.text));
317
+ symbols.push(extractSymbolInfo(member, sourceFile, "property", member.name.text, node.name.text));
309
318
  }
310
319
  else if (ts.isMethodSignature(member) && ts.isIdentifier(member.name)) {
311
- symbols.push(extractSymbolInfo(member, sourceFile, 'method', member.name.text, node.name.text));
320
+ symbols.push(extractSymbolInfo(member, sourceFile, "method", member.name.text, node.name.text));
312
321
  }
313
322
  }
314
323
  }
315
324
  // Type alias declarations
316
325
  else if (ts.isTypeAliasDeclaration(node)) {
317
- symbols.push(extractSymbolInfo(node, sourceFile, 'type', node.name.text));
326
+ symbols.push(extractSymbolInfo(node, sourceFile, "type", node.name.text));
318
327
  }
319
328
  // Enum declarations
320
329
  else if (ts.isEnumDeclaration(node)) {
321
- symbols.push(extractSymbolInfo(node, sourceFile, 'enum', node.name.text));
330
+ symbols.push(extractSymbolInfo(node, sourceFile, "enum", node.name.text));
322
331
  }
323
332
  // Continue traversing (but skip into class/interface bodies as they're handled above)
324
333
  if (!ts.isClassDeclaration(node) && !ts.isInterfaceDeclaration(node)) {
@@ -334,7 +343,7 @@ function isPrivateMember(node) {
334
343
  if (!ts.canHaveModifiers(node))
335
344
  return false;
336
345
  const modifiers = ts.getModifiers(node);
337
- return modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword) ?? false;
346
+ return (modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword) ?? false);
338
347
  }
339
348
  /**
340
349
  * Extract symbol information
@@ -364,7 +373,7 @@ function isExported(node) {
364
373
  const varStatement = varDeclList.parent;
365
374
  if (ts.canHaveModifiers(varStatement)) {
366
375
  const modifiers = ts.getModifiers(varStatement);
367
- return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
376
+ return (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false);
368
377
  }
369
378
  return false;
370
379
  }
@@ -382,131 +391,154 @@ function isExported(node) {
382
391
  if (!ts.canHaveModifiers(node))
383
392
  return false;
384
393
  const modifiers = ts.getModifiers(node);
385
- return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
394
+ return (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false);
386
395
  }
387
396
  /**
388
397
  * Extract signature from node
389
398
  */
390
399
  function extractSignature(node, sourceFile, kind) {
391
400
  switch (kind) {
392
- case 'function': {
401
+ case "function": {
393
402
  if (ts.isFunctionDeclaration(node) && node.name) {
394
- const params = node.parameters.map((p) => p.getText(sourceFile)).join(', ');
395
- const returnType = node.type ? `: ${node.type.getText(sourceFile)}` : '';
403
+ const params = node.parameters
404
+ .map((p) => p.getText(sourceFile))
405
+ .join(", ");
406
+ const returnType = node.type
407
+ ? `: ${node.type.getText(sourceFile)}`
408
+ : "";
396
409
  const generics = node.typeParameters
397
- ? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(', ')}>`
398
- : '';
410
+ ? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(", ")}>`
411
+ : "";
399
412
  return `function ${node.name.text}${generics}(${params})${returnType}`;
400
413
  }
401
414
  if (ts.isVariableStatement(node)) {
402
415
  const decl = node.declarationList.declarations[0];
403
416
  if (ts.isIdentifier(decl.name)) {
404
417
  if (decl.initializer &&
405
- (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))) {
418
+ (ts.isArrowFunction(decl.initializer) ||
419
+ ts.isFunctionExpression(decl.initializer))) {
406
420
  const func = decl.initializer;
407
- const params = func.parameters.map((p) => p.getText(sourceFile)).join(', ');
408
- const returnType = func.type ? `: ${func.type.getText(sourceFile)}` : '';
421
+ const params = func.parameters
422
+ .map((p) => p.getText(sourceFile))
423
+ .join(", ");
424
+ const returnType = func.type
425
+ ? `: ${func.type.getText(sourceFile)}`
426
+ : "";
409
427
  return `const ${decl.name.text} = (${params})${returnType} => ...`;
410
428
  }
411
429
  }
412
430
  }
413
- return node.getText(sourceFile).split('\n')[0];
431
+ return node.getText(sourceFile).split("\n")[0];
414
432
  }
415
- case 'class': {
433
+ case "class": {
416
434
  if (ts.isClassDeclaration(node) && node.name) {
417
435
  const generics = node.typeParameters
418
- ? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(', ')}>`
419
- : '';
420
- let heritage = '';
436
+ ? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(", ")}>`
437
+ : "";
438
+ let heritage = "";
421
439
  if (node.heritageClauses) {
422
440
  for (const clause of node.heritageClauses) {
423
441
  const tokenKind = clause.token;
424
442
  if (tokenKind === ts.SyntaxKind.ExtendsKeyword) {
425
- heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(', ')}`;
443
+ heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(", ")}`;
426
444
  }
427
445
  else if (tokenKind === ts.SyntaxKind.ImplementsKeyword) {
428
- heritage += ` implements ${clause.types.map((t) => t.getText(sourceFile)).join(', ')}`;
446
+ heritage += ` implements ${clause.types.map((t) => t.getText(sourceFile)).join(", ")}`;
429
447
  }
430
448
  }
431
449
  }
432
450
  return `class ${node.name.text}${generics}${heritage}`;
433
451
  }
434
- return node.getText(sourceFile).split('\n')[0];
452
+ return node.getText(sourceFile).split("\n")[0];
435
453
  }
436
- case 'interface': {
454
+ case "interface": {
437
455
  if (ts.isInterfaceDeclaration(node)) {
438
456
  const generics = node.typeParameters
439
- ? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(', ')}>`
440
- : '';
441
- let heritage = '';
457
+ ? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(", ")}>`
458
+ : "";
459
+ let heritage = "";
442
460
  if (node.heritageClauses) {
443
461
  for (const clause of node.heritageClauses) {
444
- heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(', ')}`;
462
+ heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(", ")}`;
445
463
  }
446
464
  }
447
465
  return `interface ${node.name.text}${generics}${heritage}`;
448
466
  }
449
- return node.getText(sourceFile).split('\n')[0];
467
+ return node.getText(sourceFile).split("\n")[0];
450
468
  }
451
- case 'type': {
469
+ case "type": {
452
470
  if (ts.isTypeAliasDeclaration(node)) {
453
471
  const generics = node.typeParameters
454
- ? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(', ')}>`
455
- : '';
472
+ ? `<${node.typeParameters.map((t) => t.getText(sourceFile)).join(", ")}>`
473
+ : "";
456
474
  const typeText = node.type.getText(sourceFile);
457
475
  // Truncate long types
458
476
  const maxLen = 80;
459
- const truncatedType = typeText.length > maxLen ? typeText.slice(0, maxLen) + '...' : typeText;
477
+ const truncatedType = typeText.length > maxLen
478
+ ? typeText.slice(0, maxLen) + "..."
479
+ : typeText;
460
480
  return `type ${node.name.text}${generics} = ${truncatedType}`;
461
481
  }
462
- return node.getText(sourceFile).split('\n')[0];
482
+ return node.getText(sourceFile).split("\n")[0];
463
483
  }
464
- case 'enum': {
484
+ case "enum": {
465
485
  if (ts.isEnumDeclaration(node)) {
466
- const members = node.members.map((m) => m.name.getText(sourceFile)).slice(0, 5);
467
- const suffix = node.members.length > 5 ? ', ...' : '';
468
- return `enum ${node.name.text} { ${members.join(', ')}${suffix} }`;
486
+ const members = node.members
487
+ .map((m) => m.name.getText(sourceFile))
488
+ .slice(0, 5);
489
+ const suffix = node.members.length > 5 ? ", ..." : "";
490
+ return `enum ${node.name.text} { ${members.join(", ")}${suffix} }`;
469
491
  }
470
- return node.getText(sourceFile).split('\n')[0];
492
+ return node.getText(sourceFile).split("\n")[0];
471
493
  }
472
- case 'variable': {
494
+ case "variable": {
473
495
  if (ts.isVariableStatement(node)) {
474
496
  const decl = node.declarationList.declarations[0];
475
497
  if (ts.isIdentifier(decl.name)) {
476
- const typeText = decl.type ? `: ${decl.type.getText(sourceFile)}` : '';
498
+ const typeText = decl.type
499
+ ? `: ${decl.type.getText(sourceFile)}`
500
+ : "";
477
501
  return `const ${decl.name.text}${typeText}`;
478
502
  }
479
503
  }
480
- return node.getText(sourceFile).split('\n')[0];
504
+ return node.getText(sourceFile).split("\n")[0];
481
505
  }
482
- case 'method': {
506
+ case "method": {
483
507
  if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) {
484
- const params = node.parameters.map((p) => p.getText(sourceFile)).join(', ');
485
- const returnType = node.type ? `: ${node.type.getText(sourceFile)}` : '';
508
+ const params = node.parameters
509
+ .map((p) => p.getText(sourceFile))
510
+ .join(", ");
511
+ const returnType = node.type
512
+ ? `: ${node.type.getText(sourceFile)}`
513
+ : "";
486
514
  return `${node.name.text}(${params})${returnType}`;
487
515
  }
488
516
  if (ts.isMethodSignature(node) && ts.isIdentifier(node.name)) {
489
- const params = node.parameters.map((p) => p.getText(sourceFile)).join(', ');
490
- const returnType = node.type ? `: ${node.type.getText(sourceFile)}` : '';
517
+ const params = node.parameters
518
+ .map((p) => p.getText(sourceFile))
519
+ .join(", ");
520
+ const returnType = node.type
521
+ ? `: ${node.type.getText(sourceFile)}`
522
+ : "";
491
523
  return `${node.name.text}(${params})${returnType}`;
492
524
  }
493
- return node.getText(sourceFile).split('\n')[0];
525
+ return node.getText(sourceFile).split("\n")[0];
494
526
  }
495
- case 'property': {
527
+ case "property": {
496
528
  if (ts.isPropertyDeclaration(node) && ts.isIdentifier(node.name)) {
497
- const typeText = node.type ? `: ${node.type.getText(sourceFile)}` : '';
498
- const optional = node.questionToken ? '?' : '';
529
+ const typeText = node.type ? `: ${node.type.getText(sourceFile)}` : "";
530
+ const optional = node.questionToken ? "?" : "";
499
531
  return `${node.name.text}${optional}${typeText}`;
500
532
  }
501
533
  if (ts.isPropertySignature(node) && ts.isIdentifier(node.name)) {
502
- const typeText = node.type ? `: ${node.type.getText(sourceFile)}` : '';
503
- const optional = node.questionToken ? '?' : '';
534
+ const typeText = node.type ? `: ${node.type.getText(sourceFile)}` : "";
535
+ const optional = node.questionToken ? "?" : "";
504
536
  return `${node.name.text}${optional}${typeText}`;
505
537
  }
506
- return node.getText(sourceFile).split('\n')[0];
538
+ return node.getText(sourceFile).split("\n")[0];
507
539
  }
508
540
  default:
509
- return node.getText(sourceFile).split('\n')[0];
541
+ return node.getText(sourceFile).split("\n")[0];
510
542
  }
511
543
  }
512
544
  /**
@@ -516,29 +548,29 @@ function extractDocumentation(node, sourceFile) {
516
548
  const jsDocTags = ts.getJSDocTags(node);
517
549
  const jsDocComments = node.jsDoc;
518
550
  const doc = {
519
- summary: '',
551
+ summary: "",
520
552
  };
521
553
  // Get comment text
522
554
  if (jsDocComments?.length) {
523
555
  const firstDoc = jsDocComments[0];
524
- if (typeof firstDoc.comment === 'string') {
525
- const lines = firstDoc.comment.split('\n');
556
+ if (typeof firstDoc.comment === "string") {
557
+ const lines = firstDoc.comment.split("\n");
526
558
  doc.summary = lines[0].trim();
527
559
  if (lines.length > 1) {
528
- doc.description = lines.slice(1).join('\n').trim();
560
+ doc.description = lines.slice(1).join("\n").trim();
529
561
  }
530
562
  }
531
- else if (firstDoc.comment && typeof firstDoc.comment !== 'string') {
563
+ else if (firstDoc.comment && typeof firstDoc.comment !== "string") {
532
564
  // JSDocComment can be an array of JSDocText | JSDocLink
533
565
  const commentParts = firstDoc.comment;
534
566
  const text = commentParts
535
- .map((c) => (c.kind === ts.SyntaxKind.JSDocText ? c.text : ''))
536
- .join('')
567
+ .map((c) => (c.kind === ts.SyntaxKind.JSDocText ? c.text : ""))
568
+ .join("")
537
569
  .trim();
538
- const lines = text.split('\n');
570
+ const lines = text.split("\n");
539
571
  doc.summary = lines[0].trim();
540
572
  if (lines.length > 1) {
541
- doc.description = lines.slice(1).join('\n').trim();
573
+ doc.description = lines.slice(1).join("\n").trim();
542
574
  }
543
575
  }
544
576
  }
@@ -549,37 +581,37 @@ function extractDocumentation(node, sourceFile) {
549
581
  const see = [];
550
582
  for (const tag of jsDocTags) {
551
583
  const tagName = tag.tagName.text;
552
- let tagComment = '';
553
- if (typeof tag.comment === 'string') {
584
+ let tagComment = "";
585
+ if (typeof tag.comment === "string") {
554
586
  tagComment = tag.comment;
555
587
  }
556
- else if (tag.comment && typeof tag.comment !== 'string') {
588
+ else if (tag.comment && typeof tag.comment !== "string") {
557
589
  const commentParts = tag.comment;
558
590
  tagComment = commentParts
559
- .map((c) => (c.kind === ts.SyntaxKind.JSDocText ? c.text : ''))
560
- .join('')
591
+ .map((c) => (c.kind === ts.SyntaxKind.JSDocText ? c.text : ""))
592
+ .join("")
561
593
  .trim();
562
594
  }
563
- if (tagName === 'param' && ts.isJSDocParameterTag(tag)) {
595
+ if (tagName === "param" && ts.isJSDocParameterTag(tag)) {
564
596
  const paramName = tag.name.getText(sourceFile);
565
597
  params[paramName] = tagComment;
566
598
  }
567
- else if (tagName === 'returns' || tagName === 'return') {
599
+ else if (tagName === "returns" || tagName === "return") {
568
600
  doc.returns = tagComment;
569
601
  }
570
- else if (tagName === 'throws' || tagName === 'exception') {
602
+ else if (tagName === "throws" || tagName === "exception") {
571
603
  throws.push(tagComment);
572
604
  }
573
- else if (tagName === 'example') {
605
+ else if (tagName === "example") {
574
606
  examples.push(tagComment);
575
607
  }
576
- else if (tagName === 'see') {
608
+ else if (tagName === "see") {
577
609
  see.push(tagComment);
578
610
  }
579
611
  else if (ts.isJSDocDeprecatedTag(tag)) {
580
- doc.deprecatedMessage = tagComment || 'This API is deprecated';
612
+ doc.deprecatedMessage = tagComment || "This API is deprecated";
581
613
  }
582
- else if (tagName === 'since') {
614
+ else if (tagName === "since") {
583
615
  doc.since = tagComment;
584
616
  }
585
617
  }
@@ -598,7 +630,7 @@ function extractDocumentation(node, sourceFile) {
598
630
  */
599
631
  export function createGetDocumentationTool(options) {
600
632
  return defineTool({
601
- name: options?.name ?? 'get_documentation',
633
+ name: options?.name ?? "get_documentation",
602
634
  description: options?.description ?? TOOL_DESCRIPTION,
603
635
  inputSchema: TOOL_INPUT_SCHEMA,
604
636
  execute: async (input) => {
@@ -4,8 +4,8 @@
4
4
  * Get all exports from a module.
5
5
  * Uses TypeScript Compiler API for accurate AST analysis.
6
6
  */
7
- import type { Tool } from '@compilr-dev/agents';
8
- import type { GetExportsInput } from './types.js';
7
+ import type { Tool } from "@compilr-dev/agents";
8
+ import type { GetExportsInput } from "./types.js";
9
9
  /**
10
10
  * getExports tool - Get all exports from a module
11
11
  */