@aiready/ast-mcp-server 0.8.0 → 0.8.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/dist/index.js CHANGED
@@ -1,8 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- searchCode,
4
3
  validateWorkspacePath
5
- } from "./chunk-FQP7SHLM.js";
4
+ } from "./chunk-EHE3VUUP.js";
6
5
 
7
6
  // src/index.ts
8
7
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -35,6 +34,16 @@ var FindImplementationsSchema = z.object({
35
34
  var GetFileStructureSchema = z.object({
36
35
  file: z.string().describe("Absolute path to the file to analyze")
37
36
  });
37
+ var GrepSearchSchema = z.object({
38
+ pattern: z.string().describe("Search pattern (regex by default)"),
39
+ path: z.string().describe("Directory to search in"),
40
+ include: z.array(z.string()).optional().describe('Include only these glob patterns (e.g., ["*.ts", "src/**"])'),
41
+ exclude: z.array(z.string()).optional().describe('Exclude these glob patterns (e.g., ["**/*.test.ts"])'),
42
+ limit: z.number().optional().default(50).describe("Max matches to return (default 50)"),
43
+ offset: z.number().optional().default(0).describe("Pagination offset (default 0)"),
44
+ context: z.number().optional().default(2).describe("Number of context lines before and after (default 2)"),
45
+ isRegex: z.boolean().optional().default(true).describe("Use regex mode (default true)")
46
+ });
38
47
  var SearchCodeSchema = z.object({
39
48
  pattern: z.string().describe("Search pattern (regex by default)"),
40
49
  path: z.string().describe("Directory to search in"),
@@ -445,9 +454,9 @@ var TypeScriptAdapter = class {
445
454
  await symbolIndex.buildIndex(searchPath);
446
455
  }
447
456
  }
448
- async resolveDefinition(symbolName, path6) {
449
- validateWorkspacePath(path6);
450
- await this.ensureIndex(path6);
457
+ async resolveDefinition(symbolName, path5) {
458
+ validateWorkspacePath(path5);
459
+ await this.ensureIndex(path5);
451
460
  const indexHits = symbolIndex.lookup(symbolName);
452
461
  if (indexHits.length > 0) {
453
462
  const results = [];
@@ -475,33 +484,33 @@ var TypeScriptAdapter = class {
475
484
  }
476
485
  return results;
477
486
  }
478
- if (fs3.statSync(path6).isDirectory()) {
487
+ if (fs3.statSync(path5).isDirectory()) {
479
488
  return [];
480
489
  }
481
- const tsconfig = await projectManager.findNearestTsConfig(path6);
490
+ const tsconfig = await projectManager.findNearestTsConfig(path5);
482
491
  if (!tsconfig) return [];
483
492
  try {
484
493
  const result = await this.pool.execute(
485
494
  "resolve_definition",
486
495
  {
487
496
  tsconfig,
488
- file: path6,
497
+ file: path5,
489
498
  symbol: symbolName
490
499
  }
491
500
  );
492
501
  return result;
493
502
  } catch {
494
503
  const project = projectManager.ensureProject(tsconfig);
495
- const sourceFile = project.addSourceFileAtPathIfExists(path6);
504
+ const sourceFile = project.addSourceFileAtPathIfExists(path5);
496
505
  if (!sourceFile) return [];
497
506
  const exported = sourceFile.getExportedDeclarations().get(symbolName);
498
507
  if (!exported) return [];
499
508
  return exported.map((decl) => this.mapToDefinitionLocation(decl));
500
509
  }
501
510
  }
502
- async findReferences(symbolName, path6, limit = 50, offset = 0) {
503
- validateWorkspacePath(path6);
504
- await this.ensureIndex(path6);
511
+ async findReferences(symbolName, path5, limit = 50, offset = 0) {
512
+ validateWorkspacePath(path5);
513
+ await this.ensureIndex(path5);
505
514
  const hits = symbolIndex.lookup(symbolName);
506
515
  if (hits.length === 0) return { references: [], total_count: 0 };
507
516
  const hit = hits[0];
@@ -511,10 +520,10 @@ var TypeScriptAdapter = class {
511
520
  const sourceFile = project.addSourceFileAtPathIfExists(hit.file);
512
521
  if (!sourceFile) return { references: [], total_count: 0 };
513
522
  try {
514
- const { searchCode: searchCode2 } = await import("./search-code-63QOEFQN.js");
515
- const searchResults = await searchCode2(
523
+ const { searchCode } = await import("./search-code-SYD75SEK.js");
524
+ const searchResults = await searchCode(
516
525
  symbolName,
517
- path6,
526
+ path5,
518
527
  "**/*.{ts,tsx,js,jsx}",
519
528
  1e3,
520
529
  false
@@ -551,9 +560,9 @@ var TypeScriptAdapter = class {
551
560
  total_count: unique.length
552
561
  };
553
562
  }
554
- async findImplementations(symbolName, path6, limit = 50, offset = 0) {
555
- validateWorkspacePath(path6);
556
- await this.ensureIndex(path6);
563
+ async findImplementations(symbolName, path5, limit = 50, offset = 0) {
564
+ validateWorkspacePath(path5);
565
+ await this.ensureIndex(path5);
557
566
  const hits = symbolIndex.lookup(symbolName);
558
567
  if (hits.length === 0) return { implementations: [], total_count: 0 };
559
568
  const hit = hits[0];
@@ -581,10 +590,10 @@ var TypeScriptAdapter = class {
581
590
  return { implementations: [], total_count: 0 };
582
591
  }
583
592
  try {
584
- const { searchCode: searchCode2 } = await import("./search-code-63QOEFQN.js");
585
- const searchResults = await searchCode2(
593
+ const { searchCode } = await import("./search-code-SYD75SEK.js");
594
+ const searchResults = await searchCode(
586
595
  symbolName,
587
- path6,
596
+ path5,
588
597
  "**/*.{ts,tsx,js,jsx}",
589
598
  1e3,
590
599
  false
@@ -763,31 +772,31 @@ var TypeScriptAdapter = class {
763
772
  var typescriptAdapter = new TypeScriptAdapter();
764
773
 
765
774
  // src/utils/tool-utils.ts
766
- async function wrapAdapterCall(methodName, symbol, path6, ...args) {
775
+ async function wrapAdapterCall(methodName, symbol, path5, ...args) {
767
776
  const method = typescriptAdapter[methodName];
768
- return await method.apply(typescriptAdapter, [symbol, path6, ...args]);
777
+ return await method.apply(typescriptAdapter, [symbol, path5, ...args]);
769
778
  }
770
779
 
771
780
  // src/tools/resolve-definition.ts
772
- async function resolveDefinition(symbol, path6) {
781
+ async function resolveDefinition(symbol, path5) {
773
782
  return await wrapAdapterCall(
774
783
  "resolveDefinition",
775
784
  symbol,
776
- path6
785
+ path5
777
786
  );
778
787
  }
779
788
 
780
789
  // src/tools/find-references.ts
781
- async function findReferences(symbol, path6, limit = 50, offset = 0) {
782
- return await wrapAdapterCall("findReferences", symbol, path6, limit, offset);
790
+ async function findReferences(symbol, path5, limit = 50, offset = 0) {
791
+ return await wrapAdapterCall("findReferences", symbol, path5, limit, offset);
783
792
  }
784
793
 
785
794
  // src/tools/find-implementations.ts
786
- async function findImplementations(symbol, path6, limit = 50, offset = 0) {
795
+ async function findImplementations(symbol, path5, limit = 50, offset = 0) {
787
796
  return await wrapAdapterCall(
788
797
  "findImplementations",
789
798
  symbol,
790
- path6,
799
+ path5,
791
800
  limit,
792
801
  offset
793
802
  );
@@ -798,6 +807,9 @@ async function getFileStructure(file) {
798
807
  return await typescriptAdapter.getFileStructure(file);
799
808
  }
800
809
 
810
+ // src/index.ts
811
+ import { grepSearch } from "@aiready/core";
812
+
801
813
  // src/tools/get-symbol-docs.ts
802
814
  import { SyntaxKind } from "ts-morph";
803
815
  async function getSymbolDocs(symbol, filePath) {
@@ -827,8 +839,8 @@ async function getSymbolDocs(symbol, filePath) {
827
839
  }
828
840
 
829
841
  // src/tools/build-symbol-index.ts
830
- async function buildSymbolIndex(path6) {
831
- return await symbolIndex.buildIndex(path6);
842
+ async function buildSymbolIndex(path5) {
843
+ return await symbolIndex.buildIndex(path5);
832
844
  }
833
845
 
834
846
  // src/tools/call-hierarchy.ts
@@ -984,115 +996,6 @@ async function checkSymbolGrounding(symbol, filePath) {
984
996
  };
985
997
  }
986
998
 
987
- // src/tools/codebase-audit.ts
988
- import { execFile } from "child_process";
989
- import { promisify } from "util";
990
- import { rgPath } from "@vscode/ripgrep";
991
- import * as fs4 from "fs";
992
- import * as path5 from "path";
993
- var execFileAsync = promisify(execFile);
994
- async function codebaseAudit(rootDir) {
995
- const safePath = validateWorkspacePath(rootDir);
996
- let debtMarkers = 0;
997
- try {
998
- const { stdout } = await execFileAsync(rgPath, [
999
- "--count-matches",
1000
- "--fixed-strings",
1001
- "-e",
1002
- "TODO",
1003
- "-e",
1004
- "FIXME",
1005
- "--glob",
1006
- "!**/node_modules/**",
1007
- "--glob",
1008
- "!**/.git/**",
1009
- "--glob",
1010
- "!**/dist/**",
1011
- safePath
1012
- ]);
1013
- const lines = stdout.split("\n").filter(Boolean);
1014
- for (const line of lines) {
1015
- const match = line.match(/:(\d+)$/);
1016
- if (match) {
1017
- debtMarkers += parseInt(match[1], 10);
1018
- }
1019
- }
1020
- } catch (error) {
1021
- if (error.code !== 1) {
1022
- console.error("[Audit] Error counting debt markers:", error);
1023
- }
1024
- }
1025
- const emptyDirs = [];
1026
- const scanEmpty = (dir) => {
1027
- const files = fs4.readdirSync(dir);
1028
- if (files.length === 0) {
1029
- emptyDirs.push(path5.relative(safePath, dir));
1030
- return;
1031
- }
1032
- for (const file of files) {
1033
- const fullPath = path5.join(dir, file);
1034
- if (fs4.statSync(fullPath).isDirectory()) {
1035
- if (["node_modules", ".git", "dist", ".sst", ".turbo", ".next"].includes(
1036
- file
1037
- ))
1038
- continue;
1039
- scanEmpty(fullPath);
1040
- }
1041
- }
1042
- };
1043
- scanEmpty(safePath);
1044
- const orphanedFiles = [];
1045
- const allFiles = [];
1046
- const collectFiles = (dir) => {
1047
- const files = fs4.readdirSync(dir);
1048
- for (const file of files) {
1049
- const fullPath = path5.join(dir, file);
1050
- if (fs4.statSync(fullPath).isDirectory()) {
1051
- if (["node_modules", ".git", "dist", ".sst", ".turbo", ".next"].includes(
1052
- file
1053
- ))
1054
- continue;
1055
- collectFiles(fullPath);
1056
- } else if (file.endsWith(".ts") || file.endsWith(".js") || file.endsWith(".tsx") || file.endsWith(".jsx")) {
1057
- allFiles.push(fullPath);
1058
- }
1059
- }
1060
- };
1061
- collectFiles(safePath);
1062
- for (const file of allFiles) {
1063
- const base = path5.basename(file, path5.extname(file));
1064
- if (base === "index" || base.endsWith(".test") || base.endsWith(".spec") || base === "sst.config")
1065
- continue;
1066
- let referenced = false;
1067
- try {
1068
- const { status } = await execFileAsync(rgPath, [
1069
- "--quiet",
1070
- "--fixed-strings",
1071
- "--word-regexp",
1072
- "--glob",
1073
- `!${path5.relative(safePath, file)}`,
1074
- "--glob",
1075
- "!**/node_modules/**",
1076
- "--glob",
1077
- "!**/.git/**",
1078
- base,
1079
- safePath
1080
- ]);
1081
- if (status === 0) referenced = true;
1082
- } catch (e) {
1083
- if (e.code === 0) referenced = true;
1084
- }
1085
- if (!referenced) {
1086
- orphanedFiles.push(path5.relative(safePath, file));
1087
- }
1088
- }
1089
- return {
1090
- debtMarkers,
1091
- emptyDirs,
1092
- orphanedFiles
1093
- };
1094
- }
1095
-
1096
999
  // src/index.ts
1097
1000
  import {
1098
1001
  ListResourcesRequestSchema,
@@ -1214,9 +1117,35 @@ var ASTExplorerServer = class {
1214
1117
  required: ["file"]
1215
1118
  }
1216
1119
  },
1120
+ {
1121
+ name: "grep_search",
1122
+ description: "Fast, context-aware text search via ripgrep. Supports context lines and result summarization.",
1123
+ inputSchema: {
1124
+ type: "object",
1125
+ properties: {
1126
+ pattern: { type: "string", description: "Search pattern" },
1127
+ path: { type: "string", description: "Directory to search" },
1128
+ include: {
1129
+ type: "array",
1130
+ items: { type: "string" },
1131
+ description: "Glob filter"
1132
+ },
1133
+ exclude: {
1134
+ type: "array",
1135
+ items: { type: "string" },
1136
+ description: "Exclusion filter"
1137
+ },
1138
+ limit: { type: "number", default: 50 },
1139
+ offset: { type: "number", default: 0 },
1140
+ context: { type: "number", default: 2 },
1141
+ isRegex: { type: "boolean", default: true }
1142
+ },
1143
+ required: ["pattern", "path"]
1144
+ }
1145
+ },
1217
1146
  {
1218
1147
  name: "search_code",
1219
- description: "Fast regex search via bundled ripgrep.",
1148
+ description: "Fast regex search via bundled ripgrep (alias for grep_search).",
1220
1149
  inputSchema: {
1221
1150
  type: "object",
1222
1151
  properties: {
@@ -1283,8 +1212,8 @@ var ASTExplorerServer = class {
1283
1212
  }
1284
1213
  },
1285
1214
  {
1286
- name: "codebase_audit",
1287
- description: "Performs a codebase-level audit for technical debt (TODOs) and bloat (empty dirs, orphans).",
1215
+ name: "hygiene_audit",
1216
+ description: "Performs a codebase-level hygiene check for technical debt (TODOs) and waste (empty dirs, orphans).",
1288
1217
  inputSchema: {
1289
1218
  type: "object",
1290
1219
  properties: {
@@ -1295,6 +1224,28 @@ var ASTExplorerServer = class {
1295
1224
  },
1296
1225
  required: ["path"]
1297
1226
  }
1227
+ },
1228
+ {
1229
+ name: "metabolism_audit",
1230
+ description: "Alias for hygiene_audit (Serverless Claw compat).",
1231
+ inputSchema: {
1232
+ type: "object",
1233
+ properties: {
1234
+ path: { type: "string" }
1235
+ },
1236
+ required: ["path"]
1237
+ }
1238
+ },
1239
+ {
1240
+ name: "codebase_audit",
1241
+ description: "Alias for hygiene_audit.",
1242
+ inputSchema: {
1243
+ type: "object",
1244
+ properties: {
1245
+ path: { type: "string" }
1246
+ },
1247
+ required: ["path"]
1248
+ }
1298
1249
  }
1299
1250
  ]
1300
1251
  };
@@ -1304,8 +1255,8 @@ var ASTExplorerServer = class {
1304
1255
  try {
1305
1256
  switch (name) {
1306
1257
  case "resolve_definition": {
1307
- const { symbol, path: path6 } = ResolveDefinitionSchema.parse(args);
1308
- const results = await resolveDefinition(symbol, path6);
1258
+ const { symbol, path: path5 } = ResolveDefinitionSchema.parse(args);
1259
+ const results = await resolveDefinition(symbol, path5);
1309
1260
  return {
1310
1261
  content: [
1311
1262
  { type: "text", text: JSON.stringify(results, null, 2) }
@@ -1313,8 +1264,8 @@ var ASTExplorerServer = class {
1313
1264
  };
1314
1265
  }
1315
1266
  case "find_references": {
1316
- const { symbol, path: path6, limit, offset } = FindReferencesSchema.parse(args);
1317
- const results = await findReferences(symbol, path6, limit, offset);
1267
+ const { symbol, path: path5, limit, offset } = FindReferencesSchema.parse(args);
1268
+ const results = await findReferences(symbol, path5, limit, offset);
1318
1269
  return {
1319
1270
  content: [
1320
1271
  { type: "text", text: JSON.stringify(results, null, 2) }
@@ -1322,10 +1273,10 @@ var ASTExplorerServer = class {
1322
1273
  };
1323
1274
  }
1324
1275
  case "find_implementations": {
1325
- const { symbol, path: path6, limit, offset } = FindImplementationsSchema.parse(args);
1276
+ const { symbol, path: path5, limit, offset } = FindImplementationsSchema.parse(args);
1326
1277
  const results = await findImplementations(
1327
1278
  symbol,
1328
- path6,
1279
+ path5,
1329
1280
  limit,
1330
1281
  offset
1331
1282
  );
@@ -1344,39 +1295,67 @@ var ASTExplorerServer = class {
1344
1295
  ]
1345
1296
  };
1346
1297
  }
1298
+ case "grep_search": {
1299
+ const {
1300
+ pattern,
1301
+ path: path5,
1302
+ include,
1303
+ exclude,
1304
+ limit,
1305
+ offset,
1306
+ context,
1307
+ isRegex
1308
+ } = GrepSearchSchema.parse(args);
1309
+ const result = await grepSearch({
1310
+ pattern,
1311
+ path: path5,
1312
+ include,
1313
+ exclude,
1314
+ limit,
1315
+ offset,
1316
+ context,
1317
+ isRegex
1318
+ });
1319
+ return {
1320
+ content: [
1321
+ { type: "text", text: JSON.stringify(result, null, 2) }
1322
+ ]
1323
+ };
1324
+ }
1347
1325
  case "search_code": {
1348
- const { pattern, path: path6, filePattern, limit, offset, regex } = SearchCodeSchema.parse(args);
1349
- const results = await searchCode(
1326
+ const { pattern, path: path5, filePattern, limit, offset, regex } = SearchCodeSchema.parse(args);
1327
+ const result = await grepSearch({
1350
1328
  pattern,
1351
- path6,
1352
- filePattern,
1329
+ path: path5,
1330
+ include: filePattern ? [filePattern] : [],
1353
1331
  limit,
1354
- regex,
1355
- offset
1356
- );
1332
+ offset,
1333
+ isRegex: regex,
1334
+ context: 0
1335
+ });
1357
1336
  return {
1358
1337
  content: [
1359
- { type: "text", text: JSON.stringify(results, null, 2) }
1338
+ { type: "text", text: JSON.stringify(result, null, 2) }
1360
1339
  ]
1361
1340
  };
1362
1341
  }
1363
1342
  case "get_symbol_docs": {
1364
- const { symbol, path: path6 } = GetSymbolDocsSchema.parse(args);
1365
- const docs = await getSymbolDocs(symbol, path6);
1343
+ const { symbol, path: path5 } = GetSymbolDocsSchema.parse(args);
1344
+ const docs = await getSymbolDocs(symbol, path5);
1366
1345
  return {
1367
1346
  content: [{ type: "text", text: JSON.stringify(docs, null, 2) }]
1368
1347
  };
1369
1348
  }
1370
1349
  case "build_symbol_index": {
1371
- const { path: path6 } = BuildSymbolIndexSchema.parse(args);
1372
- const stats = await buildSymbolIndex(path6);
1350
+ const { path: path5 } = BuildSymbolIndexSchema.parse(args);
1351
+ const stats = await buildSymbolIndex(path5);
1373
1352
  return {
1374
1353
  content: [{ type: "text", text: JSON.stringify(stats, null, 2) }]
1375
1354
  };
1376
1355
  }
1377
1356
  case "get_call_hierarchy": {
1378
- const { symbol, path: path6, direction } = GetCallHierarchySchema.parse(args);
1379
- const hierarchy = await getCallHierarchy(symbol, path6, direction);
1357
+ const { symbol, path: path5, direction } = GetCallHierarchySchema.parse(args);
1358
+ const hierarchy = await getCallHierarchy(symbol, path5, direction);
1380
1359
  return {
1381
1360
  content: [
1382
1361
  { type: "text", text: JSON.stringify(hierarchy, null, 2) }
@@ -1384,21 +1363,38 @@ var ASTExplorerServer = class {
1384
1363
  };
1385
1364
  }
1386
1365
  case "check_symbol_grounding": {
1387
- const { symbol, path: path6 } = CheckSymbolGroundingSchema.parse(args);
1388
- const result = await checkSymbolGrounding(symbol, path6);
1366
+ const { symbol, path: path5 } = CheckSymbolGroundingSchema.parse(args);
1367
+ const result = await checkSymbolGrounding(symbol, path5);
1389
1368
  return {
1390
1369
  content: [
1391
1370
  { type: "text", text: JSON.stringify(result, null, 2) }
1392
1371
  ]
1393
1372
  };
1394
1373
  }
1374
+ case "hygiene_audit":
1375
+ case "metabolism_audit":
1395
1376
  case "codebase_audit": {
1396
- const { path: path6 } = CodebaseAuditSchema.parse(args);
1397
- const result = await codebaseAudit(path6);
1377
+ const { path: rootDir } = CodebaseAuditSchema.parse(args);
1378
+ const { HygieneAuditProvider } = await import("@aiready/hygiene-audit");
1379
+ const provider = new HygieneAuditProvider();
1380
+ const result = await provider.analyze({ rootDir });
1381
+ const allIssues = result.results.flatMap((r) => r.issues);
1382
+ const metadata = {
1383
+ debtMarkers: result.metadata?.debtMarkers || 0,
1384
+ emptyDirs: result.metadata?.emptyDirs || [],
1385
+ orphanedFiles: result.metadata?.orphanedFiles || [],
1386
+ findings: allIssues.map((i) => ({
1387
+ expected: i.recommendation || i.suggestion || "",
1388
+ actual: i.message,
1389
+ severity: i.severity === "critical" ? "P0" : i.severity === "major" ? "P1" : "P2",
1390
+ recommendation: i.recommendation || i.suggestion || ""
1391
+ }))
1392
+ };
1398
1393
  return {
1399
1394
  content: [
1400
1395
  { type: "text", text: JSON.stringify(result, null, 2) }
1401
- ]
1396
+ ],
1397
+ metadata
1402
1398
  };
1403
1399
  }
1404
1400
  default: