@aiready/ast-mcp-server 0.8.1 → 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.
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/security.ts
4
+ import path from "path";
5
+ function resolveWorkspaceRoot() {
6
+ return process.env.AST_WORKSPACE_ROOT || process.cwd();
7
+ }
8
+ function validateWorkspacePath(inputPath) {
9
+ const root = resolveWorkspaceRoot();
10
+ const resolved = path.resolve(root, inputPath);
11
+ const normalized = path.normalize(resolved);
12
+ if (!normalized.startsWith(root)) {
13
+ throw new Error(
14
+ `Path traversal detected: ${inputPath} escapes workspace root`
15
+ );
16
+ }
17
+ if (normalized.includes("\0")) {
18
+ throw new Error("Path contains null bytes");
19
+ }
20
+ return normalized;
21
+ }
22
+
23
+ export {
24
+ validateWorkspacePath
25
+ };
26
+ //# sourceMappingURL=chunk-EHE3VUUP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/security.ts"],"sourcesContent":["import path from 'path';\nimport fs from 'fs';\n\nexport function resolveWorkspaceRoot(): string {\n return process.env.AST_WORKSPACE_ROOT || process.cwd();\n}\n\nexport function validateWorkspacePath(inputPath: string): string {\n const root = resolveWorkspaceRoot();\n const resolved = path.resolve(root, inputPath);\n const normalized = path.normalize(resolved);\n\n // Reject path traversal\n if (!normalized.startsWith(root)) {\n throw new Error(\n `Path traversal detected: ${inputPath} escapes workspace root`\n );\n }\n\n // Reject null bytes\n if (normalized.includes('\\0')) {\n throw new Error('Path contains null bytes');\n }\n\n return normalized;\n}\n\nexport function validateFileExists(filePath: string): string {\n const safe = validateWorkspacePath(filePath);\n if (!fs.existsSync(safe)) {\n throw new Error(`File not found: ${filePath}`);\n }\n if (!fs.statSync(safe).isFile()) {\n throw new Error(`Not a file: ${filePath}`);\n }\n return safe;\n}\n"],"mappings":";;;AAAA,OAAO,UAAU;AAGV,SAAS,uBAA+B;AAC7C,SAAO,QAAQ,IAAI,sBAAsB,QAAQ,IAAI;AACvD;AAEO,SAAS,sBAAsB,WAA2B;AAC/D,QAAM,OAAO,qBAAqB;AAClC,QAAM,WAAW,KAAK,QAAQ,MAAM,SAAS;AAC7C,QAAM,aAAa,KAAK,UAAU,QAAQ;AAG1C,MAAI,CAAC,WAAW,WAAW,IAAI,GAAG;AAChC,UAAM,IAAI;AAAA,MACR,4BAA4B,SAAS;AAAA,IACvC;AAAA,EACF;AAGA,MAAI,WAAW,SAAS,IAAI,GAAG;AAC7B,UAAM,IAAI,MAAM,0BAA0B;AAAA,EAC5C;AAEA,SAAO;AACT;","names":[]}
package/dist/index.cjs CHANGED
@@ -162,6 +162,16 @@ var FindImplementationsSchema = import_zod.z.object({
162
162
  var GetFileStructureSchema = import_zod.z.object({
163
163
  file: import_zod.z.string().describe("Absolute path to the file to analyze")
164
164
  });
165
+ var GrepSearchSchema = import_zod.z.object({
166
+ pattern: import_zod.z.string().describe("Search pattern (regex by default)"),
167
+ path: import_zod.z.string().describe("Directory to search in"),
168
+ include: import_zod.z.array(import_zod.z.string()).optional().describe('Include only these glob patterns (e.g., ["*.ts", "src/**"])'),
169
+ exclude: import_zod.z.array(import_zod.z.string()).optional().describe('Exclude these glob patterns (e.g., ["**/*.test.ts"])'),
170
+ limit: import_zod.z.number().optional().default(50).describe("Max matches to return (default 50)"),
171
+ offset: import_zod.z.number().optional().default(0).describe("Pagination offset (default 0)"),
172
+ context: import_zod.z.number().optional().default(2).describe("Number of context lines before and after (default 2)"),
173
+ isRegex: import_zod.z.boolean().optional().default(true).describe("Use regex mode (default true)")
174
+ });
165
175
  var SearchCodeSchema = import_zod.z.object({
166
176
  pattern: import_zod.z.string().describe("Search pattern (regex by default)"),
167
177
  path: import_zod.z.string().describe("Directory to search in"),
@@ -944,7 +954,7 @@ async function getFileStructure(file) {
944
954
  }
945
955
 
946
956
  // src/index.ts
947
- init_search_code();
957
+ var import_core = require("@aiready/core");
948
958
 
949
959
  // src/tools/get-symbol-docs.ts
950
960
  init_cjs_shims();
@@ -1257,9 +1267,35 @@ var ASTExplorerServer = class {
1257
1267
  required: ["file"]
1258
1268
  }
1259
1269
  },
1270
+ {
1271
+ name: "grep_search",
1272
+ description: "Fast, context-aware text search via ripgrep. Supports context lines and result summarization.",
1273
+ inputSchema: {
1274
+ type: "object",
1275
+ properties: {
1276
+ pattern: { type: "string", description: "Search pattern" },
1277
+ path: { type: "string", description: "Directory to search" },
1278
+ include: {
1279
+ type: "array",
1280
+ items: { type: "string" },
1281
+ description: "Glob filter"
1282
+ },
1283
+ exclude: {
1284
+ type: "array",
1285
+ items: { type: "string" },
1286
+ description: "Exclusion filter"
1287
+ },
1288
+ limit: { type: "number", default: 50 },
1289
+ offset: { type: "number", default: 0 },
1290
+ context: { type: "number", default: 2 },
1291
+ isRegex: { type: "boolean", default: true }
1292
+ },
1293
+ required: ["pattern", "path"]
1294
+ }
1295
+ },
1260
1296
  {
1261
1297
  name: "search_code",
1262
- description: "Fast regex search via bundled ripgrep.",
1298
+ description: "Fast regex search via bundled ripgrep (alias for grep_search).",
1263
1299
  inputSchema: {
1264
1300
  type: "object",
1265
1301
  properties: {
@@ -1409,19 +1445,47 @@ var ASTExplorerServer = class {
1409
1445
  ]
1410
1446
  };
1411
1447
  }
1448
+ case "grep_search": {
1449
+ const {
1450
+ pattern,
1451
+ path: path6,
1452
+ include,
1453
+ exclude,
1454
+ limit,
1455
+ offset,
1456
+ context,
1457
+ isRegex
1458
+ } = GrepSearchSchema.parse(args);
1459
+ const result = await (0, import_core.grepSearch)({
1460
+ pattern,
1461
+ path: path6,
1462
+ include,
1463
+ exclude,
1464
+ limit,
1465
+ offset,
1466
+ context,
1467
+ isRegex
1468
+ });
1469
+ return {
1470
+ content: [
1471
+ { type: "text", text: JSON.stringify(result, null, 2) }
1472
+ ]
1473
+ };
1474
+ }
1412
1475
  case "search_code": {
1413
1476
  const { pattern, path: path6, filePattern, limit, offset, regex } = SearchCodeSchema.parse(args);
1414
- const results = await searchCode(
1477
+ const result = await (0, import_core.grepSearch)({
1415
1478
  pattern,
1416
- path6,
1417
- filePattern,
1479
+ path: path6,
1480
+ include: filePattern ? [filePattern] : [],
1418
1481
  limit,
1419
- regex,
1420
- offset
1421
- );
1482
+ offset,
1483
+ isRegex: regex,
1484
+ context: 0
1485
+ });
1422
1486
  return {
1423
1487
  content: [
1424
- { type: "text", text: JSON.stringify(results, null, 2) }
1488
+ { type: "text", text: JSON.stringify(result, null, 2) }
1425
1489
  ]
1426
1490
  };
1427
1491
  }