@aiready/ast-mcp-server 0.1.2 → 0.1.3
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/dist/index.cjs +193 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +187 -82
- package/dist/index.js.map +1 -1
- package/dist/worker/ast-worker.cjs +158 -0
- package/dist/worker/ast-worker.cjs.map +1 -0
- package/dist/worker/ast-worker.d.cts +2 -0
- package/dist/worker/ast-worker.d.ts +2 -0
- package/dist/worker/ast-worker.js +156 -0
- package/dist/worker/ast-worker.js.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -329,22 +329,101 @@ var SymbolIndex = class {
|
|
|
329
329
|
};
|
|
330
330
|
var symbolIndex = new SymbolIndex();
|
|
331
331
|
|
|
332
|
+
// src/worker/pool.ts
|
|
333
|
+
import { Worker } from "worker_threads";
|
|
334
|
+
import path3 from "path";
|
|
335
|
+
import { fileURLToPath } from "url";
|
|
336
|
+
var WorkerPool = class {
|
|
337
|
+
constructor(poolSize) {
|
|
338
|
+
this.poolSize = poolSize;
|
|
339
|
+
}
|
|
340
|
+
workers = [];
|
|
341
|
+
available = [];
|
|
342
|
+
queue = [];
|
|
343
|
+
activeJobs = /* @__PURE__ */ new Map();
|
|
344
|
+
taskId = 0;
|
|
345
|
+
async init() {
|
|
346
|
+
const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
|
|
347
|
+
const workerPath = path3.join(__dirname2, "ast-worker.js");
|
|
348
|
+
for (let i = 0; i < this.poolSize; i++) {
|
|
349
|
+
const worker = new Worker(workerPath);
|
|
350
|
+
worker.on("message", (msg) => this.handleResult(msg));
|
|
351
|
+
worker.on("error", (err) => this.handleWorkerError(worker, err));
|
|
352
|
+
this.workers.push(worker);
|
|
353
|
+
this.available.push(worker);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
async execute(type, payload) {
|
|
357
|
+
return new Promise((resolve, reject) => {
|
|
358
|
+
const id = String(++this.taskId);
|
|
359
|
+
const task = { id, type, payload, resolve, reject };
|
|
360
|
+
const worker = this.available.pop();
|
|
361
|
+
if (worker) {
|
|
362
|
+
this.dispatch(worker, task);
|
|
363
|
+
} else {
|
|
364
|
+
this.queue.push(task);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
dispatch(worker, task) {
|
|
369
|
+
this.activeJobs.set(task.id, task);
|
|
370
|
+
worker.postMessage({ id: task.id, type: task.type, payload: task.payload });
|
|
371
|
+
}
|
|
372
|
+
handleResult(msg) {
|
|
373
|
+
const task = this.activeJobs.get(msg.id);
|
|
374
|
+
if (!task) return;
|
|
375
|
+
this.activeJobs.delete(msg.id);
|
|
376
|
+
if (msg.error) {
|
|
377
|
+
task.reject(new Error(msg.error));
|
|
378
|
+
} else {
|
|
379
|
+
task.resolve(msg.result);
|
|
380
|
+
}
|
|
381
|
+
const worker = this.workers.find(
|
|
382
|
+
(w) => !this.available.includes(w) && ![...this.activeJobs.values()].some((t) => t.id === msg.id)
|
|
383
|
+
// simplistic
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
handleWorkerError(worker, err) {
|
|
387
|
+
const idx = this.workers.indexOf(worker);
|
|
388
|
+
if (idx !== -1) {
|
|
389
|
+
worker.terminate();
|
|
390
|
+
const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
|
|
391
|
+
const workerPath = path3.join(__dirname2, "ast-worker.js");
|
|
392
|
+
const newWorker = new Worker(workerPath);
|
|
393
|
+
newWorker.on("message", (msg) => this.handleResult(msg));
|
|
394
|
+
newWorker.on("error", (e) => this.handleWorkerError(newWorker, e));
|
|
395
|
+
this.workers[idx] = newWorker;
|
|
396
|
+
this.available.push(newWorker);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
async terminate() {
|
|
400
|
+
await Promise.all(this.workers.map((w) => w.terminate()));
|
|
401
|
+
this.workers = [];
|
|
402
|
+
this.available = [];
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
|
|
332
406
|
// src/adapters/typescript-adapter.ts
|
|
333
407
|
var TypeScriptAdapter = class {
|
|
334
|
-
|
|
335
|
-
|
|
408
|
+
pool;
|
|
409
|
+
constructor() {
|
|
410
|
+
const poolSize = parseInt(process.env.AST_WORKER_POOL_SIZE || "2");
|
|
411
|
+
this.pool = new WorkerPool(poolSize);
|
|
412
|
+
}
|
|
413
|
+
async resolveDefinition(symbolName, path4) {
|
|
414
|
+
validateWorkspacePath(path4);
|
|
336
415
|
const indexHits = symbolIndex.lookup(symbolName);
|
|
337
416
|
if (indexHits.length > 0) {
|
|
338
417
|
const results = [];
|
|
339
418
|
for (const hit of indexHits) {
|
|
340
419
|
const tsconfig2 = await projectManager.findNearestTsConfig(hit.file);
|
|
341
420
|
if (tsconfig2) {
|
|
342
|
-
const
|
|
343
|
-
const
|
|
344
|
-
if (
|
|
345
|
-
const
|
|
346
|
-
if (
|
|
347
|
-
results.push(this.mapToDefinitionLocation(
|
|
421
|
+
const project = projectManager.ensureProject(tsconfig2);
|
|
422
|
+
const sourceFile = project.addSourceFileAtPathIfExists(hit.file);
|
|
423
|
+
if (sourceFile) {
|
|
424
|
+
const exported = sourceFile.getExportedDeclarations().get(symbolName);
|
|
425
|
+
if (exported && exported.length > 0) {
|
|
426
|
+
results.push(this.mapToDefinitionLocation(exported[0]));
|
|
348
427
|
continue;
|
|
349
428
|
}
|
|
350
429
|
}
|
|
@@ -360,20 +439,32 @@ var TypeScriptAdapter = class {
|
|
|
360
439
|
}
|
|
361
440
|
return results;
|
|
362
441
|
}
|
|
363
|
-
if (fs3.statSync(
|
|
442
|
+
if (fs3.statSync(path4).isDirectory()) {
|
|
364
443
|
return [];
|
|
365
444
|
}
|
|
366
|
-
const tsconfig = await projectManager.findNearestTsConfig(
|
|
445
|
+
const tsconfig = await projectManager.findNearestTsConfig(path4);
|
|
367
446
|
if (!tsconfig) return [];
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
447
|
+
try {
|
|
448
|
+
const result = await this.pool.execute(
|
|
449
|
+
"resolve_definition",
|
|
450
|
+
{
|
|
451
|
+
tsconfig,
|
|
452
|
+
file: path4,
|
|
453
|
+
symbol: symbolName
|
|
454
|
+
}
|
|
455
|
+
);
|
|
456
|
+
return result;
|
|
457
|
+
} catch {
|
|
458
|
+
const project = projectManager.ensureProject(tsconfig);
|
|
459
|
+
const sourceFile = project.addSourceFileAtPathIfExists(path4);
|
|
460
|
+
if (!sourceFile) return [];
|
|
461
|
+
const exported = sourceFile.getExportedDeclarations().get(symbolName);
|
|
462
|
+
if (!exported) return [];
|
|
463
|
+
return exported.map((decl) => this.mapToDefinitionLocation(decl));
|
|
464
|
+
}
|
|
374
465
|
}
|
|
375
|
-
async findReferences(symbolName,
|
|
376
|
-
validateWorkspacePath(
|
|
466
|
+
async findReferences(symbolName, path4, limit = 50, offset = 0) {
|
|
467
|
+
validateWorkspacePath(path4);
|
|
377
468
|
const hits = symbolIndex.lookup(symbolName);
|
|
378
469
|
if (hits.length === 0) return { references: [], total_count: 0 };
|
|
379
470
|
const hit = hits[0];
|
|
@@ -390,13 +481,12 @@ var TypeScriptAdapter = class {
|
|
|
390
481
|
const { searchCode: searchCode2 } = await import("./search-code-V3LACKQ6.js");
|
|
391
482
|
const searchResults = await searchCode2(
|
|
392
483
|
symbolName,
|
|
393
|
-
|
|
484
|
+
path4,
|
|
394
485
|
"*.{ts,tsx,js,jsx}",
|
|
395
486
|
1e3,
|
|
396
487
|
false
|
|
397
488
|
);
|
|
398
489
|
const filesToLoad = [...new Set(searchResults.map((r) => r.file))];
|
|
399
|
-
console.log("Search code files to load:", filesToLoad);
|
|
400
490
|
for (const file of filesToLoad) {
|
|
401
491
|
project.addSourceFileAtPathIfExists(file);
|
|
402
492
|
}
|
|
@@ -423,57 +513,69 @@ var TypeScriptAdapter = class {
|
|
|
423
513
|
total_count: unique.length
|
|
424
514
|
};
|
|
425
515
|
}
|
|
426
|
-
async findImplementations(symbolName,
|
|
427
|
-
validateWorkspacePath(
|
|
516
|
+
async findImplementations(symbolName, path4, limit = 50, offset = 0) {
|
|
517
|
+
validateWorkspacePath(path4);
|
|
428
518
|
const hits = symbolIndex.lookup(symbolName);
|
|
429
519
|
if (hits.length === 0) return { implementations: [], total_count: 0 };
|
|
430
520
|
const hit = hits[0];
|
|
431
521
|
const tsconfig = await projectManager.findNearestTsConfig(hit.file);
|
|
432
522
|
if (!tsconfig) return { implementations: [], total_count: 0 };
|
|
433
|
-
const project = projectManager.ensureProject(tsconfig);
|
|
434
|
-
const sourceFile = project.addSourceFileAtPathIfExists(hit.file);
|
|
435
|
-
if (!sourceFile) return { implementations: [], total_count: 0 };
|
|
436
|
-
const exported = sourceFile.getExportedDeclarations().get(symbolName);
|
|
437
|
-
if (!exported || exported.length === 0)
|
|
438
|
-
return { implementations: [], total_count: 0 };
|
|
439
|
-
const targetNode = exported[0];
|
|
440
|
-
if (!Node2.isClassDeclaration(targetNode) && !Node2.isInterfaceDeclaration(targetNode)) {
|
|
441
|
-
return { implementations: [], total_count: 0 };
|
|
442
|
-
}
|
|
443
523
|
try {
|
|
444
|
-
const
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
524
|
+
const result = await this.pool.execute("find_implementations", {
|
|
525
|
+
tsconfig,
|
|
526
|
+
file: hit.file,
|
|
527
|
+
symbol: symbolName
|
|
528
|
+
});
|
|
529
|
+
return {
|
|
530
|
+
implementations: result.implementations.slice(offset, offset + limit),
|
|
531
|
+
total_count: result.total_count
|
|
532
|
+
};
|
|
533
|
+
} catch {
|
|
534
|
+
const project = projectManager.ensureProject(tsconfig);
|
|
535
|
+
const sourceFile = project.addSourceFileAtPathIfExists(hit.file);
|
|
536
|
+
if (!sourceFile) return { implementations: [], total_count: 0 };
|
|
537
|
+
const exported = sourceFile.getExportedDeclarations().get(symbolName);
|
|
538
|
+
if (!exported || exported.length === 0)
|
|
539
|
+
return { implementations: [], total_count: 0 };
|
|
540
|
+
const targetNode = exported[0];
|
|
541
|
+
if (!Node2.isClassDeclaration(targetNode) && !Node2.isInterfaceDeclaration(targetNode)) {
|
|
542
|
+
return { implementations: [], total_count: 0 };
|
|
455
543
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
544
|
+
try {
|
|
545
|
+
const { searchCode: searchCode2 } = await import("./search-code-V3LACKQ6.js");
|
|
546
|
+
const searchResults = await searchCode2(
|
|
547
|
+
symbolName,
|
|
548
|
+
path4,
|
|
549
|
+
"*.{ts,tsx,js,jsx}",
|
|
550
|
+
1e3,
|
|
551
|
+
false
|
|
552
|
+
);
|
|
553
|
+
const filesToLoad = [...new Set(searchResults.map((r) => r.file))];
|
|
554
|
+
for (const file of filesToLoad) {
|
|
555
|
+
project.addSourceFileAtPathIfExists(file);
|
|
556
|
+
}
|
|
557
|
+
} catch (_e) {
|
|
558
|
+
}
|
|
559
|
+
const results = [];
|
|
560
|
+
const implementations = targetNode.getImplementations?.();
|
|
561
|
+
if (implementations) {
|
|
562
|
+
for (const impl of implementations) {
|
|
563
|
+
const sf = impl.getSourceFile();
|
|
564
|
+
const lc = sf.getLineAndColumnAtPos(impl.getTextSpan().getStart());
|
|
565
|
+
results.push({
|
|
566
|
+
file: sf.getFilePath(),
|
|
567
|
+
line: lc.line,
|
|
568
|
+
column: lc.column,
|
|
569
|
+
text: impl.getNode().getParent()?.getText() || impl.getNode().getText()
|
|
570
|
+
});
|
|
571
|
+
}
|
|
470
572
|
}
|
|
573
|
+
const unique = this.deduplicateLocations(results);
|
|
574
|
+
return {
|
|
575
|
+
implementations: unique.slice(offset, offset + limit),
|
|
576
|
+
total_count: unique.length
|
|
577
|
+
};
|
|
471
578
|
}
|
|
472
|
-
const unique = this.deduplicateLocations(results);
|
|
473
|
-
return {
|
|
474
|
-
implementations: unique.slice(offset, offset + limit),
|
|
475
|
-
total_count: unique.length
|
|
476
|
-
};
|
|
477
579
|
}
|
|
478
580
|
async getFileStructure(filePath) {
|
|
479
581
|
const safePath = validateWorkspacePath(filePath);
|
|
@@ -500,6 +602,9 @@ var TypeScriptAdapter = class {
|
|
|
500
602
|
};
|
|
501
603
|
return structure;
|
|
502
604
|
}
|
|
605
|
+
async shutdown() {
|
|
606
|
+
await this.pool.terminate();
|
|
607
|
+
}
|
|
503
608
|
mapToDefinitionLocation(node) {
|
|
504
609
|
const sourceFile = node.getSourceFile();
|
|
505
610
|
const lineAndColumn = sourceFile.getLineAndColumnAtPos(node.getStart());
|
|
@@ -615,20 +720,20 @@ var TypeScriptAdapter = class {
|
|
|
615
720
|
var typescriptAdapter = new TypeScriptAdapter();
|
|
616
721
|
|
|
617
722
|
// src/tools/resolve-definition.ts
|
|
618
|
-
async function resolveDefinition(symbol,
|
|
619
|
-
return await typescriptAdapter.resolveDefinition(symbol,
|
|
723
|
+
async function resolveDefinition(symbol, path4) {
|
|
724
|
+
return await typescriptAdapter.resolveDefinition(symbol, path4);
|
|
620
725
|
}
|
|
621
726
|
|
|
622
727
|
// src/tools/find-references.ts
|
|
623
|
-
async function findReferences(symbol,
|
|
624
|
-
return await typescriptAdapter.findReferences(symbol,
|
|
728
|
+
async function findReferences(symbol, path4, limit = 50, offset = 0) {
|
|
729
|
+
return await typescriptAdapter.findReferences(symbol, path4, limit, offset);
|
|
625
730
|
}
|
|
626
731
|
|
|
627
732
|
// src/tools/find-implementations.ts
|
|
628
|
-
async function findImplementations(symbol,
|
|
733
|
+
async function findImplementations(symbol, path4, limit = 50, offset = 0) {
|
|
629
734
|
return await typescriptAdapter.findImplementations(
|
|
630
735
|
symbol,
|
|
631
|
-
|
|
736
|
+
path4,
|
|
632
737
|
limit,
|
|
633
738
|
offset
|
|
634
739
|
);
|
|
@@ -668,8 +773,8 @@ async function getSymbolDocs(symbol, filePath) {
|
|
|
668
773
|
}
|
|
669
774
|
|
|
670
775
|
// src/tools/build-symbol-index.ts
|
|
671
|
-
async function buildSymbolIndex(
|
|
672
|
-
return await symbolIndex.buildIndex(
|
|
776
|
+
async function buildSymbolIndex(path4) {
|
|
777
|
+
return await symbolIndex.buildIndex(path4);
|
|
673
778
|
}
|
|
674
779
|
|
|
675
780
|
// src/index.ts
|
|
@@ -800,8 +905,8 @@ var ASTExplorerServer = class {
|
|
|
800
905
|
try {
|
|
801
906
|
switch (name) {
|
|
802
907
|
case "resolve_definition": {
|
|
803
|
-
const { symbol, path:
|
|
804
|
-
const results = await resolveDefinition(symbol,
|
|
908
|
+
const { symbol, path: path4 } = ResolveDefinitionSchema.parse(args);
|
|
909
|
+
const results = await resolveDefinition(symbol, path4);
|
|
805
910
|
return {
|
|
806
911
|
content: [
|
|
807
912
|
{ type: "text", text: JSON.stringify(results, null, 2) }
|
|
@@ -809,8 +914,8 @@ var ASTExplorerServer = class {
|
|
|
809
914
|
};
|
|
810
915
|
}
|
|
811
916
|
case "find_references": {
|
|
812
|
-
const { symbol, path:
|
|
813
|
-
const results = await findReferences(symbol,
|
|
917
|
+
const { symbol, path: path4, limit, offset } = FindReferencesSchema.parse(args);
|
|
918
|
+
const results = await findReferences(symbol, path4, limit, offset);
|
|
814
919
|
return {
|
|
815
920
|
content: [
|
|
816
921
|
{ type: "text", text: JSON.stringify(results, null, 2) }
|
|
@@ -818,10 +923,10 @@ var ASTExplorerServer = class {
|
|
|
818
923
|
};
|
|
819
924
|
}
|
|
820
925
|
case "find_implementations": {
|
|
821
|
-
const { symbol, path:
|
|
926
|
+
const { symbol, path: path4, limit, offset } = FindImplementationsSchema.parse(args);
|
|
822
927
|
const results = await findImplementations(
|
|
823
928
|
symbol,
|
|
824
|
-
|
|
929
|
+
path4,
|
|
825
930
|
limit,
|
|
826
931
|
offset
|
|
827
932
|
);
|
|
@@ -841,10 +946,10 @@ var ASTExplorerServer = class {
|
|
|
841
946
|
};
|
|
842
947
|
}
|
|
843
948
|
case "search_code": {
|
|
844
|
-
const { pattern, path:
|
|
949
|
+
const { pattern, path: path4, filePattern, limit, regex } = SearchCodeSchema.parse(args);
|
|
845
950
|
const results = await searchCode(
|
|
846
951
|
pattern,
|
|
847
|
-
|
|
952
|
+
path4,
|
|
848
953
|
filePattern,
|
|
849
954
|
limit,
|
|
850
955
|
regex
|
|
@@ -856,15 +961,15 @@ var ASTExplorerServer = class {
|
|
|
856
961
|
};
|
|
857
962
|
}
|
|
858
963
|
case "get_symbol_docs": {
|
|
859
|
-
const { symbol, path:
|
|
860
|
-
const docs = await getSymbolDocs(symbol,
|
|
964
|
+
const { symbol, path: path4 } = GetSymbolDocsSchema.parse(args);
|
|
965
|
+
const docs = await getSymbolDocs(symbol, path4);
|
|
861
966
|
return {
|
|
862
967
|
content: [{ type: "text", text: JSON.stringify(docs, null, 2) }]
|
|
863
968
|
};
|
|
864
969
|
}
|
|
865
970
|
case "build_symbol_index": {
|
|
866
|
-
const { path:
|
|
867
|
-
const stats = await buildSymbolIndex(
|
|
971
|
+
const { path: path4 } = BuildSymbolIndexSchema.parse(args);
|
|
972
|
+
const stats = await buildSymbolIndex(path4);
|
|
868
973
|
return {
|
|
869
974
|
content: [{ type: "text", text: JSON.stringify(stats, null, 2) }]
|
|
870
975
|
};
|