@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,49 +4,49 @@
4
4
  * Get detailed signature information for a function, method, class, or type.
5
5
  * Includes parameters, return types, generics, and documentation.
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 = `Get detailed signature information for a function, method, class, interface, or type.
14
14
  Returns parameters with types, return type, generics, and extracted documentation (JSDoc/TSDoc).
15
15
  Useful for understanding API contracts without reading full source code.`;
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 containing the symbol',
21
+ type: "string",
22
+ description: "File containing the symbol",
23
23
  },
24
24
  name: {
25
- type: 'string',
26
- description: 'Symbol name to get signature for',
25
+ type: "string",
26
+ description: "Symbol name to get signature for",
27
27
  },
28
28
  line: {
29
- type: 'number',
30
- description: 'Line number for disambiguation (optional)',
29
+ type: "number",
30
+ description: "Line number for disambiguation (optional)",
31
31
  },
32
32
  includeDoc: {
33
- type: 'boolean',
34
- description: 'Include full documentation (default: true)',
33
+ type: "boolean",
34
+ description: "Include full documentation (default: true)",
35
35
  default: true,
36
36
  },
37
37
  expandTypes: {
38
- type: 'boolean',
39
- description: 'Expand type aliases (default: false)',
38
+ type: "boolean",
39
+ description: "Expand type aliases (default: false)",
40
40
  default: false,
41
41
  },
42
42
  },
43
- required: ['path', 'name'],
43
+ required: ["path", "name"],
44
44
  };
45
45
  /**
46
46
  * getSignature tool
47
47
  */
48
48
  export const getSignatureTool = defineTool({
49
- name: 'get_signature',
49
+ name: "get_signature",
50
50
  description: TOOL_DESCRIPTION,
51
51
  inputSchema: TOOL_INPUT_SCHEMA,
52
52
  execute: executeGetSignature,
@@ -55,7 +55,7 @@ export const getSignatureTool = defineTool({
55
55
  * Execute the getSignature tool
56
56
  */
57
57
  async function executeGetSignature(input) {
58
- const { path: inputPath, name, line, includeDoc = true, expandTypes = false } = input;
58
+ const { path: inputPath, name, line, includeDoc = true, expandTypes = false, } = input;
59
59
  try {
60
60
  const resolvedPath = path.resolve(inputPath);
61
61
  // Check if file exists
@@ -70,8 +70,8 @@ async function executeGetSignature(input) {
70
70
  if (!detection.language || !isLanguageSupported(detection.language)) {
71
71
  return createErrorResult(`Unsupported language for file: ${resolvedPath}`);
72
72
  }
73
- const content = await fs.readFile(resolvedPath, 'utf-8');
74
- const sourceFile = ts.createSourceFile(resolvedPath, content, ts.ScriptTarget.Latest, true, resolvedPath.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
73
+ const content = await fs.readFile(resolvedPath, "utf-8");
74
+ const sourceFile = ts.createSourceFile(resolvedPath, content, ts.ScriptTarget.Latest, true, resolvedPath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
75
75
  // Find the symbol
76
76
  const result = findSymbolSignature(sourceFile, name, line, includeDoc, expandTypes);
77
77
  if (!result) {
@@ -108,48 +108,49 @@ function findSymbolSignature(sourceFile, symbolName, targetLine, includeDoc, _ex
108
108
  // Function declarations
109
109
  if (ts.isFunctionDeclaration(node) && node.name?.text === symbolName) {
110
110
  found.node = node;
111
- found.kind = 'function';
111
+ found.kind = "function";
112
112
  }
113
113
  // Variable declarations (arrow functions, const functions)
114
114
  else if (ts.isVariableDeclaration(node) &&
115
115
  ts.isIdentifier(node.name) &&
116
116
  node.name.text === symbolName) {
117
117
  if (node.initializer &&
118
- (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))) {
118
+ (ts.isArrowFunction(node.initializer) ||
119
+ ts.isFunctionExpression(node.initializer))) {
119
120
  found.node = node;
120
- found.kind = 'function';
121
+ found.kind = "function";
121
122
  }
122
123
  else {
123
124
  found.node = node;
124
- found.kind = 'variable';
125
+ found.kind = "variable";
125
126
  }
126
127
  }
127
128
  // Class declarations
128
129
  else if (ts.isClassDeclaration(node) && node.name?.text === symbolName) {
129
130
  found.node = node;
130
- found.kind = 'class';
131
+ found.kind = "class";
131
132
  }
132
133
  // Interface declarations
133
134
  else if (ts.isInterfaceDeclaration(node) && node.name.text === symbolName) {
134
135
  found.node = node;
135
- found.kind = 'interface';
136
+ found.kind = "interface";
136
137
  }
137
138
  // Type alias declarations
138
139
  else if (ts.isTypeAliasDeclaration(node) && node.name.text === symbolName) {
139
140
  found.node = node;
140
- found.kind = 'type';
141
+ found.kind = "type";
141
142
  }
142
143
  // Enum declarations
143
144
  else if (ts.isEnumDeclaration(node) && node.name.text === symbolName) {
144
145
  found.node = node;
145
- found.kind = 'enum';
146
+ found.kind = "enum";
146
147
  }
147
148
  // Method declarations (inside classes)
148
149
  else if (ts.isMethodDeclaration(node) &&
149
150
  ts.isIdentifier(node.name) &&
150
151
  node.name.text === symbolName) {
151
152
  found.node = node;
152
- found.kind = 'method';
153
+ found.kind = "method";
153
154
  }
154
155
  ts.forEachChild(node, visit);
155
156
  };
@@ -166,21 +167,23 @@ function extractSignature(node, kind, sourceFile, includeDoc) {
166
167
  const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
167
168
  const exported = isExported(node);
168
169
  const name = getNodeName(node);
169
- const documentation = includeDoc ? extractDocumentation(node, sourceFile) : undefined;
170
+ const documentation = includeDoc
171
+ ? extractDocumentation(node, sourceFile)
172
+ : undefined;
170
173
  switch (kind) {
171
- case 'function':
174
+ case "function":
172
175
  return extractFunctionSignature(node, sourceFile, name, line + 1, exported, documentation);
173
- case 'method':
176
+ case "method":
174
177
  return extractMethodSignature(node, sourceFile, name, line + 1, exported, documentation);
175
- case 'class':
178
+ case "class":
176
179
  return extractClassSignature(node, sourceFile, name, line + 1, exported, documentation);
177
- case 'interface':
180
+ case "interface":
178
181
  return extractInterfaceSignature(node, sourceFile, name, line + 1, exported, documentation);
179
- case 'type':
182
+ case "type":
180
183
  return extractTypeSignature(node, sourceFile, name, line + 1, exported, documentation);
181
- case 'enum':
184
+ case "enum":
182
185
  return extractEnumSignature(node, sourceFile, name, line + 1, exported, documentation);
183
- case 'variable':
186
+ case "variable":
184
187
  return extractVariableSignature(node, sourceFile, name, line + 1, exported, documentation);
185
188
  default:
186
189
  return {
@@ -208,7 +211,7 @@ function extractFunctionSignature(node, sourceFile, name, line, exported, docume
208
211
  else {
209
212
  return {
210
213
  name,
211
- kind: 'function',
214
+ kind: "function",
212
215
  line,
213
216
  signature: node.getText(sourceFile),
214
217
  formattedSignature: node.getText(sourceFile),
@@ -219,17 +222,20 @@ function extractFunctionSignature(node, sourceFile, name, line, exported, docume
219
222
  const parameters = extractParameters(funcNode.parameters, sourceFile, documentation);
220
223
  const returnType = extractReturnType(funcNode, sourceFile);
221
224
  const generics = extractGenerics(funcNode.typeParameters, sourceFile);
222
- const isAsync = funcNode.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
225
+ const isAsync = funcNode.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ??
226
+ false;
223
227
  // Build signature string
224
- const asyncPrefix = isAsync ? 'async ' : '';
225
- const genericsStr = generics.length > 0 ? `<${generics.map((g) => formatGeneric(g)).join(', ')}>` : '';
226
- const paramsStr = parameters.map((p) => formatParameter(p)).join(', ');
227
- const returnStr = returnType ? `: ${returnType.type}` : '';
228
+ const asyncPrefix = isAsync ? "async " : "";
229
+ const genericsStr = generics.length > 0
230
+ ? `<${generics.map((g) => formatGeneric(g)).join(", ")}>`
231
+ : "";
232
+ const paramsStr = parameters.map((p) => formatParameter(p)).join(", ");
233
+ const returnStr = returnType ? `: ${returnType.type}` : "";
228
234
  const signature = `${asyncPrefix}function ${name}${genericsStr}(${paramsStr})${returnStr}`;
229
235
  const formattedSignature = formatMultilineSignature(asyncPrefix, name, genericsStr, parameters, returnType);
230
236
  return {
231
237
  name,
232
- kind: 'function',
238
+ kind: "function",
233
239
  line,
234
240
  signature,
235
241
  formattedSignature,
@@ -248,17 +254,20 @@ function extractMethodSignature(node, sourceFile, name, line, exported, document
248
254
  const returnType = extractReturnType(node, sourceFile);
249
255
  const generics = extractGenerics(node.typeParameters, sourceFile);
250
256
  const isAsync = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
251
- const isStatic = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) ?? false;
252
- const asyncPrefix = isAsync ? 'async ' : '';
253
- const staticPrefix = isStatic ? 'static ' : '';
254
- const genericsStr = generics.length > 0 ? `<${generics.map((g) => formatGeneric(g)).join(', ')}>` : '';
255
- const paramsStr = parameters.map((p) => formatParameter(p)).join(', ');
256
- const returnStr = returnType ? `: ${returnType.type}` : '';
257
+ const isStatic = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) ??
258
+ false;
259
+ const asyncPrefix = isAsync ? "async " : "";
260
+ const staticPrefix = isStatic ? "static " : "";
261
+ const genericsStr = generics.length > 0
262
+ ? `<${generics.map((g) => formatGeneric(g)).join(", ")}>`
263
+ : "";
264
+ const paramsStr = parameters.map((p) => formatParameter(p)).join(", ");
265
+ const returnStr = returnType ? `: ${returnType.type}` : "";
257
266
  const signature = `${staticPrefix}${asyncPrefix}${name}${genericsStr}(${paramsStr})${returnStr}`;
258
267
  const formattedSignature = signature;
259
268
  return {
260
269
  name,
261
- kind: 'method',
270
+ kind: "method",
262
271
  line,
263
272
  signature,
264
273
  formattedSignature,
@@ -280,29 +289,32 @@ function extractClassSignature(node, sourceFile, name, line, exported, documenta
280
289
  let constructorSignature;
281
290
  if (constructor) {
282
291
  const params = extractParameters(constructor.parameters, sourceFile, undefined);
283
- constructorSignature = `constructor(${params.map((p) => formatParameter(p)).join(', ')})`;
292
+ constructorSignature = `constructor(${params.map((p) => formatParameter(p)).join(", ")})`;
284
293
  }
285
294
  // Build extends/implements
286
- let heritage = '';
295
+ let heritage = "";
287
296
  if (node.heritageClauses) {
288
297
  for (const clause of node.heritageClauses) {
289
298
  const tokenKind = clause.token;
290
299
  if (tokenKind === ts.SyntaxKind.ExtendsKeyword) {
291
- heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(', ')}`;
300
+ heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(", ")}`;
292
301
  }
293
302
  else if (tokenKind === ts.SyntaxKind.ImplementsKeyword) {
294
- heritage += ` implements ${clause.types.map((t) => t.getText(sourceFile)).join(', ')}`;
303
+ heritage += ` implements ${clause.types.map((t) => t.getText(sourceFile)).join(", ")}`;
295
304
  }
296
305
  }
297
306
  }
298
- const isAbstract = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AbstractKeyword) ?? false;
299
- const abstractPrefix = isAbstract ? 'abstract ' : '';
300
- const genericsStr = generics.length > 0 ? `<${generics.map((g) => formatGeneric(g)).join(', ')}>` : '';
307
+ const isAbstract = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AbstractKeyword) ??
308
+ false;
309
+ const abstractPrefix = isAbstract ? "abstract " : "";
310
+ const genericsStr = generics.length > 0
311
+ ? `<${generics.map((g) => formatGeneric(g)).join(", ")}>`
312
+ : "";
301
313
  const signature = `${abstractPrefix}class ${name}${genericsStr}${heritage}`;
302
314
  const formattedSignature = signature;
303
315
  return {
304
316
  name,
305
- kind: 'class',
317
+ kind: "class",
306
318
  line,
307
319
  signature,
308
320
  formattedSignature,
@@ -320,18 +332,20 @@ function extractInterfaceSignature(node, sourceFile, name, line, exported, docum
320
332
  const generics = extractGenerics(node.typeParameters, sourceFile);
321
333
  const members = extractInterfaceMembers(node, sourceFile);
322
334
  // Build extends
323
- let heritage = '';
335
+ let heritage = "";
324
336
  if (node.heritageClauses) {
325
337
  for (const clause of node.heritageClauses) {
326
- heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(', ')}`;
338
+ heritage += ` extends ${clause.types.map((t) => t.getText(sourceFile)).join(", ")}`;
327
339
  }
328
340
  }
329
- const genericsStr = generics.length > 0 ? `<${generics.map((g) => formatGeneric(g)).join(', ')}>` : '';
341
+ const genericsStr = generics.length > 0
342
+ ? `<${generics.map((g) => formatGeneric(g)).join(", ")}>`
343
+ : "";
330
344
  const signature = `interface ${name}${genericsStr}${heritage}`;
331
345
  const formattedSignature = signature;
332
346
  return {
333
347
  name,
334
- kind: 'interface',
348
+ kind: "interface",
335
349
  line,
336
350
  signature,
337
351
  formattedSignature,
@@ -347,15 +361,17 @@ function extractInterfaceSignature(node, sourceFile, name, line, exported, docum
347
361
  function extractTypeSignature(node, sourceFile, name, line, exported, documentation) {
348
362
  const generics = extractGenerics(node.typeParameters, sourceFile);
349
363
  const typeText = node.type.getText(sourceFile);
350
- const genericsStr = generics.length > 0 ? `<${generics.map((g) => formatGeneric(g)).join(', ')}>` : '';
364
+ const genericsStr = generics.length > 0
365
+ ? `<${generics.map((g) => formatGeneric(g)).join(", ")}>`
366
+ : "";
351
367
  const signature = `type ${name}${genericsStr} = ${typeText}`;
352
368
  // Format multi-line for complex types
353
369
  const formattedSignature = typeText.length > 60
354
- ? `type ${name}${genericsStr} = \n ${typeText.replace(/\n/g, '\n ')}`
370
+ ? `type ${name}${genericsStr} = \n ${typeText.replace(/\n/g, "\n ")}`
355
371
  : signature;
356
372
  return {
357
373
  name,
358
- kind: 'type',
374
+ kind: "type",
359
375
  line,
360
376
  signature,
361
377
  formattedSignature,
@@ -370,7 +386,7 @@ function extractTypeSignature(node, sourceFile, name, line, exported, documentat
370
386
  function extractEnumSignature(node, sourceFile, name, line, exported, documentation) {
371
387
  const members = node.members.map((member) => ({
372
388
  name: member.name.getText(sourceFile),
373
- kind: 'property',
389
+ kind: "property",
374
390
  signature: member.initializer
375
391
  ? `${member.name.getText(sourceFile)} = ${member.initializer.getText(sourceFile)}`
376
392
  : member.name.getText(sourceFile),
@@ -378,11 +394,11 @@ function extractEnumSignature(node, sourceFile, name, line, exported, documentat
378
394
  readonly: true,
379
395
  }));
380
396
  const isConst = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ConstKeyword) ?? false;
381
- const constPrefix = isConst ? 'const ' : '';
397
+ const constPrefix = isConst ? "const " : "";
382
398
  const signature = `${constPrefix}enum ${name}`;
383
399
  return {
384
400
  name,
385
- kind: 'enum',
401
+ kind: "enum",
386
402
  line,
387
403
  signature,
388
404
  formattedSignature: signature,
@@ -399,25 +415,29 @@ function extractVariableSignature(node, sourceFile, name, line, exported, docume
399
415
  const typeText = typeNode ? typeNode.getText(sourceFile) : undefined;
400
416
  // Determine const/let/var
401
417
  const parent = node.parent;
402
- let declKind = 'const';
418
+ let declKind = "const";
403
419
  if (ts.isVariableDeclarationList(parent)) {
404
420
  if (parent.flags & ts.NodeFlags.Let)
405
- declKind = 'let';
421
+ declKind = "let";
406
422
  else if (parent.flags & ts.NodeFlags.Const)
407
- declKind = 'const';
423
+ declKind = "const";
408
424
  else
409
- declKind = 'var';
425
+ declKind = "var";
410
426
  }
411
- const signature = typeText ? `${declKind} ${name}: ${typeText}` : `${declKind} ${name}`;
427
+ const signature = typeText
428
+ ? `${declKind} ${name}: ${typeText}`
429
+ : `${declKind} ${name}`;
412
430
  return {
413
431
  name,
414
- kind: 'variable',
432
+ kind: "variable",
415
433
  line,
416
434
  signature,
417
435
  formattedSignature: signature,
418
436
  exported,
419
437
  documentation,
420
- returnType: typeText ? { type: typeText, isPromise: false, nullable: false } : undefined,
438
+ returnType: typeText
439
+ ? { type: typeText, isPromise: false, nullable: false }
440
+ : undefined,
421
441
  };
422
442
  }
423
443
  /**
@@ -426,10 +446,12 @@ function extractVariableSignature(node, sourceFile, name, line, exported, docume
426
446
  function extractParameters(params, sourceFile, documentation) {
427
447
  return params.map((param) => {
428
448
  const paramName = param.name.getText(sourceFile);
429
- const type = param.type ? param.type.getText(sourceFile) : 'any';
449
+ const type = param.type ? param.type.getText(sourceFile) : "any";
430
450
  const optional = param.questionToken !== undefined || param.initializer !== undefined;
431
451
  const rest = param.dotDotDotToken !== undefined;
432
- const defaultValue = param.initializer ? param.initializer.getText(sourceFile) : undefined;
452
+ const defaultValue = param.initializer
453
+ ? param.initializer.getText(sourceFile)
454
+ : undefined;
433
455
  const description = documentation?.params?.[paramName];
434
456
  return {
435
457
  name: paramName,
@@ -448,8 +470,8 @@ function extractReturnType(node, sourceFile) {
448
470
  if (!node.type)
449
471
  return undefined;
450
472
  const typeText = node.type.getText(sourceFile);
451
- const isPromise = typeText.startsWith('Promise<') || typeText.startsWith('Promise ');
452
- const nullable = typeText.includes('| null') || typeText.includes('| undefined');
473
+ const isPromise = typeText.startsWith("Promise<") || typeText.startsWith("Promise ");
474
+ const nullable = typeText.includes("| null") || typeText.includes("| undefined");
453
475
  return {
454
476
  type: typeText,
455
477
  isPromise,
@@ -464,7 +486,9 @@ function extractGenerics(typeParams, sourceFile) {
464
486
  return [];
465
487
  return typeParams.map((param) => ({
466
488
  name: param.name.getText(sourceFile),
467
- constraint: param.constraint ? param.constraint.getText(sourceFile) : undefined,
489
+ constraint: param.constraint
490
+ ? param.constraint.getText(sourceFile)
491
+ : undefined,
468
492
  default: param.default ? param.default.getText(sourceFile) : undefined,
469
493
  }));
470
494
  }
@@ -479,14 +503,16 @@ function extractClassMembers(node, sourceFile) {
479
503
  // Handle property declarations
480
504
  if (ts.isPropertyDeclaration(member)) {
481
505
  const memberName = member.name.getText(sourceFile);
482
- const mods = ts.canHaveModifiers(member) ? ts.getModifiers(member) : undefined;
506
+ const mods = ts.canHaveModifiers(member)
507
+ ? ts.getModifiers(member)
508
+ : undefined;
483
509
  const isStatic = mods?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) ?? false;
484
510
  const isReadonly = mods?.some((m) => m.kind === ts.SyntaxKind.ReadonlyKeyword) ?? false;
485
511
  const visibility = getVisibility(member);
486
- const type = member.type ? member.type.getText(sourceFile) : 'any';
512
+ const type = member.type ? member.type.getText(sourceFile) : "any";
487
513
  members.push({
488
514
  name: memberName,
489
- kind: 'property',
515
+ kind: "property",
490
516
  signature: `${memberName}: ${type}`,
491
517
  optional: member.questionToken !== undefined,
492
518
  readonly: isReadonly,
@@ -497,14 +523,20 @@ function extractClassMembers(node, sourceFile) {
497
523
  // Handle method declarations
498
524
  else if (ts.isMethodDeclaration(member)) {
499
525
  const memberName = member.name.getText(sourceFile);
500
- const mods = ts.canHaveModifiers(member) ? ts.getModifiers(member) : undefined;
526
+ const mods = ts.canHaveModifiers(member)
527
+ ? ts.getModifiers(member)
528
+ : undefined;
501
529
  const isStatic = mods?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) ?? false;
502
530
  const visibility = getVisibility(member);
503
- const params = member.parameters.map((p) => p.getText(sourceFile)).join(', ');
504
- const returnType = member.type ? `: ${member.type.getText(sourceFile)}` : '';
531
+ const params = member.parameters
532
+ .map((p) => p.getText(sourceFile))
533
+ .join(", ");
534
+ const returnType = member.type
535
+ ? `: ${member.type.getText(sourceFile)}`
536
+ : "";
505
537
  members.push({
506
538
  name: memberName,
507
- kind: 'method',
539
+ kind: "method",
508
540
  signature: `${memberName}(${params})${returnType}`,
509
541
  optional: member.questionToken !== undefined,
510
542
  readonly: false,
@@ -515,13 +547,17 @@ function extractClassMembers(node, sourceFile) {
515
547
  // Handle getter accessors
516
548
  else if (ts.isGetAccessor(member)) {
517
549
  const memberName = member.name.getText(sourceFile);
518
- const mods = ts.canHaveModifiers(member) ? ts.getModifiers(member) : undefined;
550
+ const mods = ts.canHaveModifiers(member)
551
+ ? ts.getModifiers(member)
552
+ : undefined;
519
553
  const isStatic = mods?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) ?? false;
520
554
  const visibility = getVisibility(member);
521
- const returnType = member.type ? `: ${member.type.getText(sourceFile)}` : '';
555
+ const returnType = member.type
556
+ ? `: ${member.type.getText(sourceFile)}`
557
+ : "";
522
558
  members.push({
523
559
  name: memberName,
524
- kind: 'getter',
560
+ kind: "getter",
525
561
  signature: `get ${memberName}()${returnType}`,
526
562
  optional: false,
527
563
  readonly: true,
@@ -532,14 +568,16 @@ function extractClassMembers(node, sourceFile) {
532
568
  // Handle setter accessors
533
569
  else if (ts.isSetAccessor(member)) {
534
570
  const memberName = member.name.getText(sourceFile);
535
- const mods = ts.canHaveModifiers(member) ? ts.getModifiers(member) : undefined;
571
+ const mods = ts.canHaveModifiers(member)
572
+ ? ts.getModifiers(member)
573
+ : undefined;
536
574
  const isStatic = mods?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) ?? false;
537
575
  const visibility = getVisibility(member);
538
576
  const param = member.parameters[0];
539
577
  const paramStr = param.getText(sourceFile);
540
578
  members.push({
541
579
  name: memberName,
542
- kind: 'setter',
580
+ kind: "setter",
543
581
  signature: `set ${memberName}(${paramStr})`,
544
582
  optional: false,
545
583
  readonly: false,
@@ -558,11 +596,11 @@ function extractInterfaceMembers(node, sourceFile) {
558
596
  for (const member of node.members) {
559
597
  if (ts.isPropertySignature(member)) {
560
598
  const memberName = member.name.getText(sourceFile);
561
- const type = member.type ? member.type.getText(sourceFile) : 'any';
599
+ const type = member.type ? member.type.getText(sourceFile) : "any";
562
600
  const isReadonly = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.ReadonlyKeyword) ?? false;
563
601
  members.push({
564
602
  name: memberName,
565
- kind: 'property',
603
+ kind: "property",
566
604
  signature: `${memberName}: ${type}`,
567
605
  optional: member.questionToken !== undefined,
568
606
  readonly: isReadonly,
@@ -570,11 +608,15 @@ function extractInterfaceMembers(node, sourceFile) {
570
608
  }
571
609
  else if (ts.isMethodSignature(member)) {
572
610
  const memberName = member.name.getText(sourceFile);
573
- const params = member.parameters.map((p) => p.getText(sourceFile)).join(', ');
574
- const returnType = member.type ? `: ${member.type.getText(sourceFile)}` : '';
611
+ const params = member.parameters
612
+ .map((p) => p.getText(sourceFile))
613
+ .join(", ");
614
+ const returnType = member.type
615
+ ? `: ${member.type.getText(sourceFile)}`
616
+ : "";
575
617
  members.push({
576
618
  name: memberName,
577
- kind: 'method',
619
+ kind: "method",
578
620
  signature: `${memberName}(${params})${returnType}`,
579
621
  optional: member.questionToken !== undefined,
580
622
  readonly: false,
@@ -592,16 +634,16 @@ function extractDocumentation(node, sourceFile) {
592
634
  if (!jsDocComments?.length && !jsDocTags.length)
593
635
  return undefined;
594
636
  const doc = {
595
- summary: '',
637
+ summary: "",
596
638
  };
597
639
  // Get comment text
598
640
  if (jsDocComments?.length) {
599
641
  const firstDoc = jsDocComments[0];
600
- if (typeof firstDoc.comment === 'string') {
601
- const lines = firstDoc.comment.split('\n');
642
+ if (typeof firstDoc.comment === "string") {
643
+ const lines = firstDoc.comment.split("\n");
602
644
  doc.summary = lines[0].trim();
603
645
  if (lines.length > 1) {
604
- doc.description = lines.slice(1).join('\n').trim();
646
+ doc.description = lines.slice(1).join("\n").trim();
605
647
  }
606
648
  }
607
649
  }
@@ -612,27 +654,27 @@ function extractDocumentation(node, sourceFile) {
612
654
  const see = [];
613
655
  for (const tag of jsDocTags) {
614
656
  const tagName = tag.tagName.text;
615
- const tagComment = typeof tag.comment === 'string' ? tag.comment : '';
616
- if (tagName === 'param' && ts.isJSDocParameterTag(tag)) {
657
+ const tagComment = typeof tag.comment === "string" ? tag.comment : "";
658
+ if (tagName === "param" && ts.isJSDocParameterTag(tag)) {
617
659
  const paramName = tag.name.getText(sourceFile);
618
660
  params[paramName] = tagComment;
619
661
  }
620
- else if (tagName === 'returns' || tagName === 'return') {
662
+ else if (tagName === "returns" || tagName === "return") {
621
663
  doc.returns = tagComment;
622
664
  }
623
- else if (tagName === 'throws' || tagName === 'exception') {
665
+ else if (tagName === "throws" || tagName === "exception") {
624
666
  throws.push(tagComment);
625
667
  }
626
- else if (tagName === 'example') {
668
+ else if (tagName === "example") {
627
669
  examples.push(tagComment);
628
670
  }
629
- else if (tagName === 'see') {
671
+ else if (tagName === "see") {
630
672
  see.push(tagComment);
631
673
  }
632
674
  else if (ts.isJSDocDeprecatedTag(tag)) {
633
- doc.deprecatedMessage = tagComment || 'This API is deprecated';
675
+ doc.deprecatedMessage = tagComment || "This API is deprecated";
634
676
  }
635
- else if (tagName === 'since') {
677
+ else if (tagName === "since") {
636
678
  doc.since = tagComment;
637
679
  }
638
680
  }
@@ -667,7 +709,7 @@ function getNodeName(node) {
667
709
  return node.name.text;
668
710
  if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name))
669
711
  return node.name.text;
670
- return '<anonymous>';
712
+ return "<anonymous>";
671
713
  }
672
714
  /**
673
715
  * Check if node is exported
@@ -680,27 +722,27 @@ function isExported(node) {
680
722
  const varStatement = varDeclList.parent;
681
723
  if (ts.canHaveModifiers(varStatement)) {
682
724
  const modifiers = ts.getModifiers(varStatement);
683
- return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
725
+ return (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false);
684
726
  }
685
727
  return false;
686
728
  }
687
729
  if (!ts.canHaveModifiers(node))
688
730
  return false;
689
731
  const modifiers = ts.getModifiers(node);
690
- return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
732
+ return (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false);
691
733
  }
692
734
  /**
693
735
  * Get visibility modifier
694
736
  */
695
737
  function getVisibility(node) {
696
738
  if (!ts.canHaveModifiers(node))
697
- return 'public';
739
+ return "public";
698
740
  const modifiers = ts.getModifiers(node);
699
741
  if (modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword))
700
- return 'private';
742
+ return "private";
701
743
  if (modifiers?.some((m) => m.kind === ts.SyntaxKind.ProtectedKeyword))
702
- return 'protected';
703
- return 'public';
744
+ return "protected";
745
+ return "public";
704
746
  }
705
747
  /**
706
748
  * Format a generic parameter
@@ -719,7 +761,7 @@ function formatGeneric(g) {
719
761
  function formatParameter(p) {
720
762
  let result = p.rest ? `...${p.name}` : p.name;
721
763
  if (p.optional && !p.defaultValue)
722
- result += '?';
764
+ result += "?";
723
765
  result += `: ${p.type}`;
724
766
  if (p.defaultValue)
725
767
  result += ` = ${p.defaultValue}`;
@@ -730,13 +772,15 @@ function formatParameter(p) {
730
772
  */
731
773
  function formatMultilineSignature(asyncPrefix, name, genericsStr, parameters, returnType) {
732
774
  if (parameters.length <= 2) {
733
- const paramsStr = parameters.map((p) => formatParameter(p)).join(', ');
734
- const returnStr = returnType ? `: ${returnType.type}` : '';
775
+ const paramsStr = parameters.map((p) => formatParameter(p)).join(", ");
776
+ const returnStr = returnType ? `: ${returnType.type}` : "";
735
777
  return `${asyncPrefix}function ${name}${genericsStr}(${paramsStr})${returnStr}`;
736
778
  }
737
779
  // Multi-line for many parameters
738
- const paramsLines = parameters.map((p) => ` ${formatParameter(p)}`).join(',\n');
739
- const returnStr = returnType ? `: ${returnType.type}` : '';
780
+ const paramsLines = parameters
781
+ .map((p) => ` ${formatParameter(p)}`)
782
+ .join(",\n");
783
+ const returnStr = returnType ? `: ${returnType.type}` : "";
740
784
  return `${asyncPrefix}function ${name}${genericsStr}(\n${paramsLines}\n)${returnStr}`;
741
785
  }
742
786
  /**
@@ -744,7 +788,7 @@ function formatMultilineSignature(asyncPrefix, name, genericsStr, parameters, re
744
788
  */
745
789
  export function createGetSignatureTool(options) {
746
790
  return defineTool({
747
- name: options?.name ?? 'get_signature',
791
+ name: options?.name ?? "get_signature",
748
792
  description: options?.description ?? TOOL_DESCRIPTION,
749
793
  inputSchema: TOOL_INPUT_SCHEMA,
750
794
  execute: async (input) => {