@aiready/ast-mcp-server 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.cjs +147 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +140 -18
- package/dist/index.js.map +1 -1
- package/package.json +12 -9
package/dist/index.js
CHANGED
|
@@ -55,6 +55,10 @@ var GetCallHierarchySchema = z.object({
|
|
|
55
55
|
path: z.string().describe("Project root directory"),
|
|
56
56
|
direction: z.enum(["incoming", "outgoing", "both"]).optional().default("both").describe("Direction of calls (default: both)")
|
|
57
57
|
});
|
|
58
|
+
var CheckSymbolGroundingSchema = z.object({
|
|
59
|
+
symbol: z.string().describe("Symbol name to assess grounding for"),
|
|
60
|
+
path: z.string().describe("Project root directory")
|
|
61
|
+
});
|
|
58
62
|
|
|
59
63
|
// src/adapters/typescript-adapter.ts
|
|
60
64
|
import { Node as Node2 } from "ts-morph";
|
|
@@ -238,7 +242,7 @@ var SymbolIndex = class {
|
|
|
238
242
|
const startTime = Date.now();
|
|
239
243
|
const safeRoot = validateWorkspacePath(rootDir);
|
|
240
244
|
const cachePath = this.getCachePath(safeRoot);
|
|
241
|
-
if (fs2.existsSync(cachePath)) {
|
|
245
|
+
if (fs2.existsSync(cachePath) && process.env.AST_DISABLE_CACHE !== "true") {
|
|
242
246
|
try {
|
|
243
247
|
const cached = JSON.parse(
|
|
244
248
|
fs2.readFileSync(cachePath, "utf-8")
|
|
@@ -348,6 +352,7 @@ var WorkerPool = class {
|
|
|
348
352
|
constructor(poolSize) {
|
|
349
353
|
this.poolSize = poolSize;
|
|
350
354
|
}
|
|
355
|
+
poolSize;
|
|
351
356
|
workers = [];
|
|
352
357
|
available = [];
|
|
353
358
|
queue = [];
|
|
@@ -358,8 +363,8 @@ var WorkerPool = class {
|
|
|
358
363
|
const workerPath = path3.join(__dirname2, "ast-worker.js");
|
|
359
364
|
for (let i = 0; i < this.poolSize; i++) {
|
|
360
365
|
const worker = new Worker(workerPath);
|
|
361
|
-
worker.on("message", (msg) => this.handleResult(msg));
|
|
362
|
-
worker.on("error", (
|
|
366
|
+
worker.on("message", (msg) => this.handleResult(worker, msg));
|
|
367
|
+
worker.on("error", (_err) => this.handleWorkerError(worker, _err));
|
|
363
368
|
this.workers.push(worker);
|
|
364
369
|
this.available.push(worker);
|
|
365
370
|
}
|
|
@@ -380,7 +385,7 @@ var WorkerPool = class {
|
|
|
380
385
|
this.activeJobs.set(task.id, task);
|
|
381
386
|
worker.postMessage({ id: task.id, type: task.type, payload: task.payload });
|
|
382
387
|
}
|
|
383
|
-
handleResult(msg) {
|
|
388
|
+
handleResult(worker, msg) {
|
|
384
389
|
const task = this.activeJobs.get(msg.id);
|
|
385
390
|
if (!task) return;
|
|
386
391
|
this.activeJobs.delete(msg.id);
|
|
@@ -389,6 +394,12 @@ var WorkerPool = class {
|
|
|
389
394
|
} else {
|
|
390
395
|
task.resolve(msg.result);
|
|
391
396
|
}
|
|
397
|
+
const nextTask = this.queue.shift();
|
|
398
|
+
if (nextTask) {
|
|
399
|
+
this.dispatch(worker, nextTask);
|
|
400
|
+
} else {
|
|
401
|
+
this.available.push(worker);
|
|
402
|
+
}
|
|
392
403
|
}
|
|
393
404
|
handleWorkerError(worker, err) {
|
|
394
405
|
const idx = this.workers.indexOf(worker);
|
|
@@ -397,7 +408,7 @@ var WorkerPool = class {
|
|
|
397
408
|
const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
|
|
398
409
|
const workerPath = path3.join(__dirname2, "ast-worker.js");
|
|
399
410
|
const newWorker = new Worker(workerPath);
|
|
400
|
-
newWorker.on("message", (msg) => this.handleResult(msg));
|
|
411
|
+
newWorker.on("message", (msg) => this.handleResult(newWorker, msg));
|
|
401
412
|
newWorker.on("error", (_e) => this.handleWorkerError(newWorker, _e));
|
|
402
413
|
this.workers[idx] = newWorker;
|
|
403
414
|
this.available.push(newWorker);
|
|
@@ -496,16 +507,12 @@ var TypeScriptAdapter = class {
|
|
|
496
507
|
const project = projectManager.ensureProject(tsconfig);
|
|
497
508
|
const sourceFile = project.addSourceFileAtPathIfExists(hit.file);
|
|
498
509
|
if (!sourceFile) return { references: [], total_count: 0 };
|
|
499
|
-
const exported = sourceFile.getExportedDeclarations().get(symbolName);
|
|
500
|
-
if (!exported || exported.length === 0)
|
|
501
|
-
return { references: [], total_count: 0 };
|
|
502
|
-
const targetNode = exported[0];
|
|
503
510
|
try {
|
|
504
511
|
const { searchCode: searchCode2 } = await import("./search-code-63QOEFQN.js");
|
|
505
512
|
const searchResults = await searchCode2(
|
|
506
513
|
symbolName,
|
|
507
514
|
path5,
|
|
508
|
-
"
|
|
515
|
+
"**/*.{ts,tsx,js,jsx}",
|
|
509
516
|
1e3,
|
|
510
517
|
false
|
|
511
518
|
);
|
|
@@ -513,8 +520,13 @@ var TypeScriptAdapter = class {
|
|
|
513
520
|
for (const file of filesToLoad) {
|
|
514
521
|
project.addSourceFileAtPathIfExists(file);
|
|
515
522
|
}
|
|
523
|
+
project.resolveSourceFileDependencies();
|
|
516
524
|
} catch (_e) {
|
|
517
525
|
}
|
|
526
|
+
const exported = sourceFile.getExportedDeclarations().get(symbolName);
|
|
527
|
+
if (!exported || exported.length === 0)
|
|
528
|
+
return { references: [], total_count: 0 };
|
|
529
|
+
const targetNode = exported[0];
|
|
518
530
|
const refSymbols = "findReferences" in targetNode && typeof targetNode.findReferences === "function" ? targetNode.findReferences() : void 0;
|
|
519
531
|
if (!refSymbols) return { references: [], total_count: 0 };
|
|
520
532
|
const results = [];
|
|
@@ -570,7 +582,7 @@ var TypeScriptAdapter = class {
|
|
|
570
582
|
const searchResults = await searchCode2(
|
|
571
583
|
symbolName,
|
|
572
584
|
path5,
|
|
573
|
-
"
|
|
585
|
+
"**/*.{ts,tsx,js,jsx}",
|
|
574
586
|
1e3,
|
|
575
587
|
false
|
|
576
588
|
);
|
|
@@ -747,19 +759,30 @@ var TypeScriptAdapter = class {
|
|
|
747
759
|
};
|
|
748
760
|
var typescriptAdapter = new TypeScriptAdapter();
|
|
749
761
|
|
|
762
|
+
// src/utils/tool-utils.ts
|
|
763
|
+
async function wrapAdapterCall(methodName, symbol, path5, ...args) {
|
|
764
|
+
const method = typescriptAdapter[methodName];
|
|
765
|
+
return await method.apply(typescriptAdapter, [symbol, path5, ...args]);
|
|
766
|
+
}
|
|
767
|
+
|
|
750
768
|
// src/tools/resolve-definition.ts
|
|
751
769
|
async function resolveDefinition(symbol, path5) {
|
|
752
|
-
return await
|
|
770
|
+
return await wrapAdapterCall(
|
|
771
|
+
"resolveDefinition",
|
|
772
|
+
symbol,
|
|
773
|
+
path5
|
|
774
|
+
);
|
|
753
775
|
}
|
|
754
776
|
|
|
755
777
|
// src/tools/find-references.ts
|
|
756
778
|
async function findReferences(symbol, path5, limit = 50, offset = 0) {
|
|
757
|
-
return await
|
|
779
|
+
return await wrapAdapterCall("findReferences", symbol, path5, limit, offset);
|
|
758
780
|
}
|
|
759
781
|
|
|
760
782
|
// src/tools/find-implementations.ts
|
|
761
783
|
async function findImplementations(symbol, path5, limit = 50, offset = 0) {
|
|
762
|
-
return await
|
|
784
|
+
return await wrapAdapterCall(
|
|
785
|
+
"findImplementations",
|
|
763
786
|
symbol,
|
|
764
787
|
path5,
|
|
765
788
|
limit,
|
|
@@ -880,6 +903,84 @@ async function getCallHierarchy(symbolName, rootDir, direction = "both") {
|
|
|
880
903
|
return results;
|
|
881
904
|
}
|
|
882
905
|
|
|
906
|
+
// src/tools/check-symbol-grounding.ts
|
|
907
|
+
import { SyntaxKind as SyntaxKind3 } from "ts-morph";
|
|
908
|
+
async function checkSymbolGrounding(symbol, filePath) {
|
|
909
|
+
const safePath = validateWorkspacePath(filePath);
|
|
910
|
+
const tsconfig = await projectManager.findNearestTsConfig(safePath);
|
|
911
|
+
if (!tsconfig) return void 0;
|
|
912
|
+
const project = projectManager.ensureProject(tsconfig);
|
|
913
|
+
const sourceFile = project.addSourceFileAtPathIfExists(safePath);
|
|
914
|
+
if (!sourceFile) return void 0;
|
|
915
|
+
const node = sourceFile.getDescendantsOfKind(SyntaxKind3.Identifier).find((id) => id.getText() === symbol);
|
|
916
|
+
if (!node) return void 0;
|
|
917
|
+
const decl = node.getSymbol()?.getDeclarations()?.[0];
|
|
918
|
+
if (!decl) return void 0;
|
|
919
|
+
let docScore = 0;
|
|
920
|
+
let typeScore = 0;
|
|
921
|
+
let depthScore = 30;
|
|
922
|
+
const recommendations = [];
|
|
923
|
+
const docs = typescriptAdapter.getSymbolDocs(decl);
|
|
924
|
+
if (docs) {
|
|
925
|
+
docScore += 10;
|
|
926
|
+
if (docs.documentation && docs.documentation.length > 20) docScore += 10;
|
|
927
|
+
const hasParams = docs.tags.some((t) => t.name === "param");
|
|
928
|
+
const hasReturns = docs.tags.some(
|
|
929
|
+
(t) => t.name === "returns" || t.name === "return"
|
|
930
|
+
);
|
|
931
|
+
if (hasParams) docScore += 10;
|
|
932
|
+
else
|
|
933
|
+
recommendations.push(
|
|
934
|
+
"Add @param tags to document implementation details for the agent."
|
|
935
|
+
);
|
|
936
|
+
if (hasReturns) docScore += 10;
|
|
937
|
+
else
|
|
938
|
+
recommendations.push("Add @returns tag to clarify output expectations.");
|
|
939
|
+
} else {
|
|
940
|
+
recommendations.push(
|
|
941
|
+
"Missing JSDoc. Agents need explicit documentation to understand intent without reading the source."
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
const typeText = decl.getType?.()?.getText?.() || "";
|
|
945
|
+
if (typeText) {
|
|
946
|
+
if (!typeText.includes("any")) typeScore += 15;
|
|
947
|
+
else
|
|
948
|
+
recommendations.push(
|
|
949
|
+
'Avoid "any" types. They break agentic reasoning and cause hallucinations.'
|
|
950
|
+
);
|
|
951
|
+
if (!typeText.includes("unknown")) typeScore += 15;
|
|
952
|
+
else
|
|
953
|
+
recommendations.push(
|
|
954
|
+
'Use specific interfaces instead of "unknown" to minimize agent probe requirements.'
|
|
955
|
+
);
|
|
956
|
+
}
|
|
957
|
+
const importCount = sourceFile.getImportDeclarations().length;
|
|
958
|
+
if (importCount > 10) {
|
|
959
|
+
const penalty = Math.min(20, (importCount - 10) * 2);
|
|
960
|
+
depthScore -= penalty;
|
|
961
|
+
recommendations.push(
|
|
962
|
+
`High dependency depth (${importCount} imports). Agents must load more files to understand this symbol's context.`
|
|
963
|
+
);
|
|
964
|
+
}
|
|
965
|
+
const totalScore = docScore + typeScore + depthScore;
|
|
966
|
+
let grade = "F";
|
|
967
|
+
if (totalScore >= 90) grade = "S (Agent-Native)";
|
|
968
|
+
else if (totalScore >= 80) grade = "A (Highly Grounded)";
|
|
969
|
+
else if (totalScore >= 70) grade = "B (Good)";
|
|
970
|
+
else if (totalScore >= 60) grade = "C (Acceptable)";
|
|
971
|
+
else if (totalScore >= 40) grade = "D (Poor)";
|
|
972
|
+
return {
|
|
973
|
+
score: totalScore,
|
|
974
|
+
grade,
|
|
975
|
+
breakdown: {
|
|
976
|
+
documentation: docScore,
|
|
977
|
+
typeClarity: typeScore,
|
|
978
|
+
depthImpact: depthScore
|
|
979
|
+
},
|
|
980
|
+
recommendations
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
|
|
883
984
|
// src/index.ts
|
|
884
985
|
import {
|
|
885
986
|
ListResourcesRequestSchema,
|
|
@@ -1046,16 +1147,28 @@ var ASTExplorerServer = class {
|
|
|
1046
1147
|
inputSchema: {
|
|
1047
1148
|
type: "object",
|
|
1048
1149
|
properties: {
|
|
1049
|
-
symbol: { type: "string"
|
|
1050
|
-
path: { type: "string"
|
|
1150
|
+
symbol: { type: "string" },
|
|
1151
|
+
path: { type: "string" },
|
|
1051
1152
|
direction: {
|
|
1052
1153
|
type: "string",
|
|
1053
|
-
enum: ["incoming", "outgoing"
|
|
1054
|
-
default: "
|
|
1154
|
+
enum: ["incoming", "outgoing"],
|
|
1155
|
+
default: "outgoing"
|
|
1055
1156
|
}
|
|
1056
1157
|
},
|
|
1057
1158
|
required: ["symbol", "path"]
|
|
1058
1159
|
}
|
|
1160
|
+
},
|
|
1161
|
+
{
|
|
1162
|
+
name: "check_symbol_grounding",
|
|
1163
|
+
description: "Assess a symbol's AI grounding quality (docs, type clarity, depth).",
|
|
1164
|
+
inputSchema: {
|
|
1165
|
+
type: "object",
|
|
1166
|
+
properties: {
|
|
1167
|
+
symbol: { type: "string" },
|
|
1168
|
+
path: { type: "string" }
|
|
1169
|
+
},
|
|
1170
|
+
required: ["symbol", "path"]
|
|
1171
|
+
}
|
|
1059
1172
|
}
|
|
1060
1173
|
]
|
|
1061
1174
|
};
|
|
@@ -1144,6 +1257,15 @@ var ASTExplorerServer = class {
|
|
|
1144
1257
|
]
|
|
1145
1258
|
};
|
|
1146
1259
|
}
|
|
1260
|
+
case "check_symbol_grounding": {
|
|
1261
|
+
const { symbol, path: path5 } = CheckSymbolGroundingSchema.parse(args);
|
|
1262
|
+
const result = await checkSymbolGrounding(symbol, path5);
|
|
1263
|
+
return {
|
|
1264
|
+
content: [
|
|
1265
|
+
{ type: "text", text: JSON.stringify(result, null, 2) }
|
|
1266
|
+
]
|
|
1267
|
+
};
|
|
1268
|
+
}
|
|
1147
1269
|
default:
|
|
1148
1270
|
throw new Error(`Unknown tool: ${name}`);
|
|
1149
1271
|
}
|