@probelabs/probe 0.6.0-rc121 → 0.6.0-rc122
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 +36 -2
- package/build/agent/ProbeAgent.js +50 -14
- package/build/agent/index.js +182 -48
- package/build/agent/mcp/client.js +69 -15
- package/build/agent/mcp/config.js +8 -8
- package/build/agent/mcp/xmlBridge.js +52 -7
- package/build/agent/schemaUtils.js +28 -15
- package/build/grep.js +152 -0
- package/build/index.js +2 -0
- package/build/mcp/index.js +105 -87
- package/build/mcp/index.ts +120 -97
- package/cjs/agent/ProbeAgent.cjs +191 -57
- package/cjs/index.cjs +249 -57
- package/index.d.ts +45 -0
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +50 -14
- package/src/agent/index.js +1 -1
- package/src/agent/mcp/client.js +69 -15
- package/src/agent/mcp/config.js +8 -8
- package/src/agent/mcp/xmlBridge.js +52 -7
- package/src/agent/schemaUtils.js +28 -15
- package/src/grep.js +152 -0
- package/src/index.js +2 -0
- package/src/mcp/index.ts +120 -97
package/src/grep.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grep functionality for the probe package
|
|
3
|
+
* @module grep
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { execFile } from 'child_process';
|
|
7
|
+
import { promisify } from 'util';
|
|
8
|
+
import { getBinaryPath } from './utils.js';
|
|
9
|
+
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Flag mapping for grep options
|
|
14
|
+
* Maps option keys to command-line flags
|
|
15
|
+
*/
|
|
16
|
+
const GREP_FLAG_MAP = {
|
|
17
|
+
ignoreCase: '-i',
|
|
18
|
+
lineNumbers: '-n',
|
|
19
|
+
count: '-c',
|
|
20
|
+
filesWithMatches: '-l',
|
|
21
|
+
filesWithoutMatches: '-L',
|
|
22
|
+
invertMatch: '-v',
|
|
23
|
+
beforeContext: '-B',
|
|
24
|
+
afterContext: '-A',
|
|
25
|
+
context: '-C',
|
|
26
|
+
noGitignore: '--no-gitignore',
|
|
27
|
+
color: '--color',
|
|
28
|
+
maxCount: '-m'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Standard grep-style search across files (works with any file type, not just code)
|
|
33
|
+
*
|
|
34
|
+
* This provides a cross-platform grep interface that works on any OS and file type.
|
|
35
|
+
* Use this for searching non-code files (logs, config files, text files, etc.) that
|
|
36
|
+
* are not supported by probe's semantic search.
|
|
37
|
+
*
|
|
38
|
+
* For code files, prefer using the `search()` function which provides semantic,
|
|
39
|
+
* AST-aware search capabilities.
|
|
40
|
+
*
|
|
41
|
+
* @param {Object} options - Grep options
|
|
42
|
+
* @param {string} options.pattern - Pattern to search for (regex)
|
|
43
|
+
* @param {string|string[]} options.paths - Path(s) to search in
|
|
44
|
+
* @param {boolean} [options.ignoreCase] - Case-insensitive search (-i)
|
|
45
|
+
* @param {boolean} [options.lineNumbers] - Show line numbers (-n)
|
|
46
|
+
* @param {boolean} [options.count] - Only show count of matches (-c)
|
|
47
|
+
* @param {boolean} [options.filesWithMatches] - Only show filenames with matches (-l)
|
|
48
|
+
* @param {boolean} [options.filesWithoutMatches] - Only show filenames without matches (-L)
|
|
49
|
+
* @param {boolean} [options.invertMatch] - Invert match, show non-matching lines (-v)
|
|
50
|
+
* @param {number} [options.beforeContext] - Lines of context before match (-B)
|
|
51
|
+
* @param {number} [options.afterContext] - Lines of context after match (-A)
|
|
52
|
+
* @param {number} [options.context] - Lines of context before and after match (-C)
|
|
53
|
+
* @param {boolean} [options.noGitignore] - Don't respect .gitignore files (--no-gitignore)
|
|
54
|
+
* @param {string} [options.color] - Colorize output: 'always', 'never', 'auto' (--color)
|
|
55
|
+
* @param {number} [options.maxCount] - Stop after N matches per file (-m)
|
|
56
|
+
* @param {Object} [options.binaryOptions] - Options for getting the binary
|
|
57
|
+
* @param {boolean} [options.binaryOptions.forceDownload] - Force download even if binary exists
|
|
58
|
+
* @param {string} [options.binaryOptions.version] - Specific version to download
|
|
59
|
+
* @returns {Promise<string>} - Grep results as string
|
|
60
|
+
* @throws {Error} If the grep operation fails
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* // Search for "error" in log files (case-insensitive)
|
|
64
|
+
* const results = await grep({
|
|
65
|
+
* pattern: 'error',
|
|
66
|
+
* paths: '/var/log',
|
|
67
|
+
* ignoreCase: true,
|
|
68
|
+
* lineNumbers: true
|
|
69
|
+
* });
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* // Count occurrences of "TODO" in project
|
|
73
|
+
* const count = await grep({
|
|
74
|
+
* pattern: 'TODO',
|
|
75
|
+
* paths: '.',
|
|
76
|
+
* count: true
|
|
77
|
+
* });
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* // Find files containing "config" with context
|
|
81
|
+
* const matches = await grep({
|
|
82
|
+
* pattern: 'config',
|
|
83
|
+
* paths: '/etc',
|
|
84
|
+
* context: 2,
|
|
85
|
+
* filesWithMatches: true
|
|
86
|
+
* });
|
|
87
|
+
*/
|
|
88
|
+
export async function grep(options) {
|
|
89
|
+
if (!options || !options.pattern) {
|
|
90
|
+
throw new Error('Pattern is required');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!options.paths) {
|
|
94
|
+
throw new Error('Path(s) are required');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Get the binary path
|
|
98
|
+
const binaryPath = await getBinaryPath(options.binaryOptions || {});
|
|
99
|
+
|
|
100
|
+
// Build CLI arguments array for grep subcommand
|
|
101
|
+
// Using an array prevents command injection vulnerabilities
|
|
102
|
+
const cliArgs = ['grep'];
|
|
103
|
+
|
|
104
|
+
// Add flags from GREP_FLAG_MAP
|
|
105
|
+
for (const [key, flag] of Object.entries(GREP_FLAG_MAP)) {
|
|
106
|
+
const value = options[key];
|
|
107
|
+
if (value === undefined || value === null) continue;
|
|
108
|
+
|
|
109
|
+
if (typeof value === 'boolean' && value) {
|
|
110
|
+
// Boolean flag
|
|
111
|
+
cliArgs.push(flag);
|
|
112
|
+
} else if (typeof value === 'number') {
|
|
113
|
+
// Numeric option
|
|
114
|
+
cliArgs.push(flag, String(value));
|
|
115
|
+
} else if (typeof value === 'string') {
|
|
116
|
+
// String option (like color)
|
|
117
|
+
cliArgs.push(flag, value);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Add pattern (no need to escape - execFile handles it securely)
|
|
122
|
+
cliArgs.push(options.pattern);
|
|
123
|
+
|
|
124
|
+
// Add paths (can be single string or array)
|
|
125
|
+
const paths = Array.isArray(options.paths) ? options.paths : [options.paths];
|
|
126
|
+
cliArgs.push(...paths);
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
// Use execFile instead of exec to prevent command injection
|
|
130
|
+
// execFile does not spawn a shell and passes arguments as an array
|
|
131
|
+
const { stdout, stderr } = await execFileAsync(binaryPath, cliArgs, {
|
|
132
|
+
maxBuffer: 10 * 1024 * 1024, // 10MB buffer
|
|
133
|
+
env: {
|
|
134
|
+
...process.env,
|
|
135
|
+
// Disable colors in stderr for cleaner output
|
|
136
|
+
NO_COLOR: '1'
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Return stdout (grep results)
|
|
141
|
+
return stdout;
|
|
142
|
+
} catch (error) {
|
|
143
|
+
// Grep exit code 1 means "no matches found", which is not an error
|
|
144
|
+
if (error.code === 1 && !error.stderr) {
|
|
145
|
+
return error.stdout || '';
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Other errors are real failures
|
|
149
|
+
const errorMessage = error.stderr || error.message || 'Unknown error';
|
|
150
|
+
throw new Error(`Grep failed: ${errorMessage}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
package/src/index.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { search } from './search.js';
|
|
11
11
|
import { query } from './query.js';
|
|
12
12
|
import { extract } from './extract.js';
|
|
13
|
+
import { grep } from './grep.js';
|
|
13
14
|
import { delegate } from './delegate.js';
|
|
14
15
|
import { getBinaryPath, setBinaryPath } from './utils.js';
|
|
15
16
|
import * as tools from './tools/index.js';
|
|
@@ -40,6 +41,7 @@ export {
|
|
|
40
41
|
search,
|
|
41
42
|
query,
|
|
42
43
|
extract,
|
|
44
|
+
grep,
|
|
43
45
|
delegate,
|
|
44
46
|
getBinaryPath,
|
|
45
47
|
setBinaryPath,
|
package/src/mcp/index.ts
CHANGED
|
@@ -14,7 +14,7 @@ import fs from 'fs-extra';
|
|
|
14
14
|
import { fileURLToPath } from 'url';
|
|
15
15
|
|
|
16
16
|
// Import from parent package
|
|
17
|
-
import { search, query, extract, getBinaryPath, setBinaryPath } from '../index.js';
|
|
17
|
+
import { search, query, extract, grep, getBinaryPath, setBinaryPath } from '../index.js';
|
|
18
18
|
|
|
19
19
|
// Parse command-line arguments
|
|
20
20
|
function parseArgs(): { timeout?: number; format?: string } {
|
|
@@ -44,7 +44,7 @@ Usage:
|
|
|
44
44
|
|
|
45
45
|
Options:
|
|
46
46
|
--timeout, -t <seconds> Set timeout for search operations (default: 30)
|
|
47
|
-
--format <format> Set output format (
|
|
47
|
+
--format <format> Set output format (default: outline)
|
|
48
48
|
--help, -h Show this help message
|
|
49
49
|
`);
|
|
50
50
|
process.exit(0);
|
|
@@ -113,19 +113,19 @@ interface SearchCodeArgs {
|
|
|
113
113
|
path: string;
|
|
114
114
|
query: string | string[];
|
|
115
115
|
exact?: boolean;
|
|
116
|
-
maxResults?: number;
|
|
117
|
-
maxTokens?: number;
|
|
118
|
-
allowTests?: boolean;
|
|
119
|
-
session?: string;
|
|
120
|
-
noGitignore?: boolean;
|
|
121
116
|
}
|
|
122
117
|
|
|
123
|
-
|
|
124
118
|
interface ExtractCodeArgs {
|
|
125
119
|
path: string;
|
|
126
120
|
files: string[];
|
|
127
|
-
|
|
128
|
-
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
interface GrepArgs {
|
|
124
|
+
pattern: string;
|
|
125
|
+
paths: string | string[];
|
|
126
|
+
ignoreCase?: boolean;
|
|
127
|
+
count?: boolean;
|
|
128
|
+
context?: number;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
class ProbeServer {
|
|
@@ -151,7 +151,7 @@ class ProbeServer {
|
|
|
151
151
|
this.setupToolHandlers();
|
|
152
152
|
|
|
153
153
|
// Error handling
|
|
154
|
-
this.server.onerror = (error) => console.error('[MCP
|
|
154
|
+
this.server.onerror = (error) => console.error('[MCP ERROR]', error);
|
|
155
155
|
process.on('SIGINT', async () => {
|
|
156
156
|
await this.server.close();
|
|
157
157
|
process.exit(0);
|
|
@@ -165,35 +165,22 @@ class ProbeServer {
|
|
|
165
165
|
tools: [
|
|
166
166
|
{
|
|
167
167
|
name: 'search_code',
|
|
168
|
-
description: "
|
|
168
|
+
description: "Semantic code search using AST parsing and ElasticSearch-style queries. Use this for finding code, not grep.",
|
|
169
169
|
inputSchema: {
|
|
170
170
|
type: 'object',
|
|
171
171
|
properties: {
|
|
172
172
|
path: {
|
|
173
173
|
type: 'string',
|
|
174
|
-
description: 'Absolute path to the directory to search
|
|
174
|
+
description: 'Absolute path to the directory to search',
|
|
175
175
|
},
|
|
176
176
|
query: {
|
|
177
177
|
type: 'string',
|
|
178
|
-
description: '
|
|
178
|
+
description: 'Search query. Use quotes for exact matches: "functionName". Supports AND, OR, NOT operators.',
|
|
179
179
|
},
|
|
180
180
|
exact: {
|
|
181
181
|
type: 'boolean',
|
|
182
|
-
description: '
|
|
183
|
-
|
|
184
|
-
allowTests: {
|
|
185
|
-
type: 'boolean',
|
|
186
|
-
description: 'Allow test files and test code blocks in results (enabled by default)',
|
|
187
|
-
default: true
|
|
188
|
-
},
|
|
189
|
-
session: {
|
|
190
|
-
type: 'string',
|
|
191
|
-
description: 'Session identifier for caching. Set to "new" if unknown, or want to reset cache. Re-use session ID returned from previous searches',
|
|
192
|
-
default: "new",
|
|
193
|
-
},
|
|
194
|
-
noGitignore: {
|
|
195
|
-
type: 'boolean',
|
|
196
|
-
description: 'Skip .gitignore files (will use PROBE_NO_GITIGNORE environment variable if not set)',
|
|
182
|
+
description: 'Use when searching for exact function/class/variable names',
|
|
183
|
+
default: false
|
|
197
184
|
}
|
|
198
185
|
},
|
|
199
186
|
required: ['path', 'query']
|
|
@@ -201,30 +188,56 @@ class ProbeServer {
|
|
|
201
188
|
},
|
|
202
189
|
{
|
|
203
190
|
name: 'extract_code',
|
|
204
|
-
description: "Extract code
|
|
191
|
+
description: "Extract code from files. Formats: file.js (whole file), file.js:42 (from line), file.js#functionName (symbol).",
|
|
205
192
|
inputSchema: {
|
|
206
193
|
type: 'object',
|
|
207
194
|
properties: {
|
|
208
195
|
path: {
|
|
209
196
|
type: 'string',
|
|
210
|
-
description: 'Absolute path to the directory
|
|
197
|
+
description: 'Absolute path to the project directory',
|
|
211
198
|
},
|
|
212
199
|
files: {
|
|
213
200
|
type: 'array',
|
|
214
201
|
items: { type: 'string' },
|
|
215
|
-
description: '
|
|
202
|
+
description: 'Array of file paths with optional line/symbol: ["file.rs:10", "file.rs#func_name"]',
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
required: ['path', 'files'],
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: 'grep',
|
|
210
|
+
description: "Standard grep-style search for non-code files (logs, config files, text files). Line numbers are shown by default. For code files, use search_code instead.",
|
|
211
|
+
inputSchema: {
|
|
212
|
+
type: 'object',
|
|
213
|
+
properties: {
|
|
214
|
+
pattern: {
|
|
215
|
+
type: 'string',
|
|
216
|
+
description: 'Regular expression pattern to search for',
|
|
217
|
+
},
|
|
218
|
+
paths: {
|
|
219
|
+
oneOf: [
|
|
220
|
+
{ type: 'string' },
|
|
221
|
+
{ type: 'array', items: { type: 'string' } }
|
|
222
|
+
],
|
|
223
|
+
description: 'Path or array of paths to search in',
|
|
216
224
|
},
|
|
217
|
-
|
|
225
|
+
ignoreCase: {
|
|
218
226
|
type: 'boolean',
|
|
219
|
-
description: '
|
|
220
|
-
default:
|
|
227
|
+
description: 'Case-insensitive search',
|
|
228
|
+
default: false
|
|
221
229
|
},
|
|
222
|
-
|
|
230
|
+
count: {
|
|
223
231
|
type: 'boolean',
|
|
224
|
-
description: '
|
|
232
|
+
description: 'Only show count of matches per file instead of the matches',
|
|
233
|
+
default: false
|
|
234
|
+
},
|
|
235
|
+
context: {
|
|
236
|
+
type: 'number',
|
|
237
|
+
description: 'Number of lines of context to show before and after each match',
|
|
225
238
|
}
|
|
226
239
|
},
|
|
227
|
-
required: ['
|
|
240
|
+
required: ['pattern', 'paths'],
|
|
228
241
|
},
|
|
229
242
|
},
|
|
230
243
|
],
|
|
@@ -232,7 +245,7 @@ class ProbeServer {
|
|
|
232
245
|
|
|
233
246
|
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
234
247
|
if (request.params.name !== 'search_code' && request.params.name !== 'extract_code' &&
|
|
235
|
-
request.params.name !== 'probe' && request.params.name !== 'extract') {
|
|
248
|
+
request.params.name !== 'grep' && request.params.name !== 'probe' && request.params.name !== 'extract') {
|
|
236
249
|
throw new McpError(
|
|
237
250
|
ErrorCode.MethodNotFound,
|
|
238
251
|
`Unknown tool: ${request.params.name}`
|
|
@@ -252,9 +265,9 @@ class ProbeServer {
|
|
|
252
265
|
if (!request.params.arguments || typeof request.params.arguments !== 'object') {
|
|
253
266
|
throw new Error("Arguments must be an object");
|
|
254
267
|
}
|
|
255
|
-
|
|
268
|
+
|
|
256
269
|
const args = request.params.arguments as unknown as SearchCodeArgs;
|
|
257
|
-
|
|
270
|
+
|
|
258
271
|
// Validate required fields
|
|
259
272
|
if (!args.path) {
|
|
260
273
|
throw new Error("Path is required in arguments");
|
|
@@ -262,8 +275,11 @@ class ProbeServer {
|
|
|
262
275
|
if (!args.query) {
|
|
263
276
|
throw new Error("Query is required in arguments");
|
|
264
277
|
}
|
|
265
|
-
|
|
278
|
+
|
|
266
279
|
result = await this.executeCodeSearch(args);
|
|
280
|
+
} else if (request.params.name === 'grep') {
|
|
281
|
+
const args = request.params.arguments as unknown as GrepArgs;
|
|
282
|
+
result = await this.executeGrep(args);
|
|
267
283
|
} else { // extract_code or extract
|
|
268
284
|
const args = request.params.arguments as unknown as ExtractCodeArgs;
|
|
269
285
|
result = await this.executeCodeExtract(args);
|
|
@@ -304,53 +320,29 @@ class ProbeServer {
|
|
|
304
320
|
throw new Error("Query is required");
|
|
305
321
|
}
|
|
306
322
|
|
|
307
|
-
//
|
|
308
|
-
console.error(`Received search arguments: path=${args.path}, query=${JSON.stringify(args.query)}`);
|
|
309
|
-
|
|
310
|
-
// Create a clean options object with only the essential properties first
|
|
323
|
+
// Build options with smart defaults
|
|
311
324
|
const options: any = {
|
|
312
|
-
path: args.path.trim(),
|
|
313
|
-
query: args.query
|
|
325
|
+
path: args.path.trim(),
|
|
326
|
+
query: args.query,
|
|
327
|
+
// Smart defaults for MCP usage
|
|
328
|
+
allowTests: true, // Include test files by default
|
|
329
|
+
session: "new", // Fresh session each time
|
|
330
|
+
maxResults: 20, // Reasonable limit for context window
|
|
331
|
+
maxTokens: 8000, // Fits in most AI context windows
|
|
314
332
|
};
|
|
315
|
-
|
|
316
|
-
//
|
|
333
|
+
|
|
334
|
+
// Only override defaults if user explicitly set them
|
|
317
335
|
if (args.exact !== undefined) options.exact = args.exact;
|
|
318
|
-
if (args.maxResults !== undefined) options.maxResults = args.maxResults;
|
|
319
|
-
if (args.maxTokens !== undefined) options.maxTokens = args.maxTokens;
|
|
320
|
-
// Set allowTests to true by default if not specified
|
|
321
|
-
if (args.allowTests !== undefined) {
|
|
322
|
-
options.allowTests = args.allowTests;
|
|
323
|
-
} else {
|
|
324
|
-
options.allowTests = true;
|
|
325
|
-
}
|
|
326
|
-
// Use noGitignore from args, or fall back to PROBE_NO_GITIGNORE environment variable
|
|
327
|
-
if (args.noGitignore !== undefined) {
|
|
328
|
-
options.noGitignore = args.noGitignore;
|
|
329
|
-
} else if (process.env.PROBE_NO_GITIGNORE) {
|
|
330
|
-
options.noGitignore = process.env.PROBE_NO_GITIGNORE === 'true';
|
|
331
|
-
}
|
|
332
|
-
if (args.session !== undefined && args.session.trim() !== '') {
|
|
333
|
-
options.session = args.session;
|
|
334
|
-
} else {
|
|
335
|
-
options.session = "new";
|
|
336
|
-
}
|
|
337
336
|
|
|
338
|
-
// Handle format
|
|
339
|
-
if (this.defaultFormat === 'outline-xml') {
|
|
340
|
-
|
|
341
|
-
options.format = 'outline-xml';
|
|
337
|
+
// Handle format based on server default
|
|
338
|
+
if (this.defaultFormat === 'outline' || this.defaultFormat === 'outline-xml') {
|
|
339
|
+
options.format = this.defaultFormat;
|
|
342
340
|
} else if (this.defaultFormat === 'json') {
|
|
343
341
|
options.json = true;
|
|
344
342
|
}
|
|
345
|
-
|
|
343
|
+
|
|
346
344
|
console.error("Executing search with options:", JSON.stringify(options, null, 2));
|
|
347
345
|
|
|
348
|
-
// Double-check that path is still in the options object
|
|
349
|
-
if (!options.path) {
|
|
350
|
-
console.error("Path is missing from options object after construction");
|
|
351
|
-
throw new Error("Path is missing from options object");
|
|
352
|
-
}
|
|
353
|
-
|
|
354
346
|
try {
|
|
355
347
|
// Call search with the options object
|
|
356
348
|
const result = await search(options);
|
|
@@ -379,27 +371,14 @@ class ProbeServer {
|
|
|
379
371
|
throw new Error("Files array is required and must not be empty");
|
|
380
372
|
}
|
|
381
373
|
|
|
382
|
-
//
|
|
374
|
+
// Build options with smart defaults
|
|
383
375
|
const options: any = {
|
|
384
376
|
files: args.files,
|
|
385
377
|
path: args.path,
|
|
386
|
-
format: 'xml'
|
|
378
|
+
format: 'xml',
|
|
379
|
+
allowTests: true, // Include test files by default
|
|
387
380
|
};
|
|
388
381
|
|
|
389
|
-
// Set allowTests to true by default if not specified
|
|
390
|
-
if (args.allowTests !== undefined) {
|
|
391
|
-
options.allowTests = args.allowTests;
|
|
392
|
-
} else {
|
|
393
|
-
options.allowTests = true;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// Use noGitignore from args, or fall back to PROBE_NO_GITIGNORE environment variable
|
|
397
|
-
if (args.noGitignore !== undefined) {
|
|
398
|
-
options.noGitignore = args.noGitignore;
|
|
399
|
-
} else if (process.env.PROBE_NO_GITIGNORE) {
|
|
400
|
-
options.noGitignore = process.env.PROBE_NO_GITIGNORE === 'true';
|
|
401
|
-
}
|
|
402
|
-
|
|
403
382
|
// Call extract with the complete options object
|
|
404
383
|
try {
|
|
405
384
|
// Track request size for token usage
|
|
@@ -454,6 +433,50 @@ class ProbeServer {
|
|
|
454
433
|
}
|
|
455
434
|
}
|
|
456
435
|
|
|
436
|
+
private async executeGrep(args: GrepArgs): Promise<string> {
|
|
437
|
+
try {
|
|
438
|
+
// Validate required parameters
|
|
439
|
+
if (!args.pattern) {
|
|
440
|
+
throw new Error("Pattern is required");
|
|
441
|
+
}
|
|
442
|
+
if (!args.paths) {
|
|
443
|
+
throw new Error("Paths are required");
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Build options object with good defaults
|
|
447
|
+
const options: any = {
|
|
448
|
+
pattern: args.pattern,
|
|
449
|
+
paths: args.paths,
|
|
450
|
+
// Default: show line numbers (makes output more useful)
|
|
451
|
+
lineNumbers: true,
|
|
452
|
+
// Default: never use color in MCP context (better for parsing)
|
|
453
|
+
color: 'never'
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
// Only add user-specified optional parameters
|
|
457
|
+
if (args.ignoreCase !== undefined) options.ignoreCase = args.ignoreCase;
|
|
458
|
+
if (args.count !== undefined) options.count = args.count;
|
|
459
|
+
if (args.context !== undefined) options.context = args.context;
|
|
460
|
+
|
|
461
|
+
console.error("Executing grep with options:", JSON.stringify(options, null, 2));
|
|
462
|
+
|
|
463
|
+
try {
|
|
464
|
+
// Call grep with the options object
|
|
465
|
+
const result = await grep(options);
|
|
466
|
+
return result || 'No matches found';
|
|
467
|
+
} catch (grepError: any) {
|
|
468
|
+
console.error("Grep function error:", grepError);
|
|
469
|
+
throw new Error(`Grep function error: ${grepError.message || String(grepError)}`);
|
|
470
|
+
}
|
|
471
|
+
} catch (error: any) {
|
|
472
|
+
console.error('Error executing grep:', error);
|
|
473
|
+
throw new McpError(
|
|
474
|
+
'MethodNotFound' as unknown as ErrorCode,
|
|
475
|
+
`Error executing grep: ${error.message || String(error)}`
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
457
480
|
async run() {
|
|
458
481
|
// The @probelabs/probe package now handles binary path management internally
|
|
459
482
|
// We don't need to verify or download the binary in the MCP server anymore
|
|
@@ -465,5 +488,5 @@ class ProbeServer {
|
|
|
465
488
|
}
|
|
466
489
|
}
|
|
467
490
|
|
|
468
|
-
const server = new ProbeServer(cliConfig.timeout, cliConfig.format || 'outline
|
|
491
|
+
const server = new ProbeServer(cliConfig.timeout, cliConfig.format || 'outline');
|
|
469
492
|
server.run().catch(console.error);
|