@probelabs/probe 0.6.0-rc102 → 0.6.0-rc104

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.
@@ -207,14 +207,24 @@ export function createWrappedTools(baseTools) {
207
207
  // Simple file listing tool
208
208
  export const listFilesTool = {
209
209
  execute: async (params) => {
210
- const { directory = '.' } = params;
210
+ const { directory = '.', workingDirectory } = params;
211
+
212
+ // Use the provided working directory, or fall back to process.cwd()
213
+ const baseCwd = workingDirectory || process.cwd();
214
+
215
+ // Security: Validate path to prevent traversal attacks
216
+ const secureBaseDir = path.resolve(baseCwd);
217
+ const targetDir = path.resolve(secureBaseDir, directory);
218
+ if (!targetDir.startsWith(secureBaseDir + path.sep) && targetDir !== secureBaseDir) {
219
+ throw new Error('Path traversal attempt detected. Access denied.');
220
+ }
211
221
 
212
222
  try {
213
223
  const files = await listFilesByLevel({
214
- directory,
224
+ directory: targetDir,
215
225
  maxFiles: 100,
216
226
  respectGitignore: !process.env.PROBE_NO_GITIGNORE || process.env.PROBE_NO_GITIGNORE === '',
217
- cwd: process.cwd()
227
+ cwd: secureBaseDir
218
228
  });
219
229
 
220
230
  return files;
@@ -227,15 +237,23 @@ export const listFilesTool = {
227
237
  // Simple file search tool
228
238
  export const searchFilesTool = {
229
239
  execute: async (params) => {
230
- const { pattern, directory = '.', recursive = true } = params;
240
+ const { pattern, directory = '.', recursive = true, workingDirectory } = params;
231
241
 
232
242
  if (!pattern) {
233
243
  throw new Error('Pattern is required for file search');
234
244
  }
235
245
 
246
+ // Security: Validate path to prevent traversal attacks
247
+ const baseCwd = workingDirectory || process.cwd();
248
+ const secureBaseDir = path.resolve(baseCwd);
249
+ const targetDir = path.resolve(secureBaseDir, directory);
250
+ if (!targetDir.startsWith(secureBaseDir + path.sep) && targetDir !== secureBaseDir) {
251
+ throw new Error('Path traversal attempt detected. Access denied.');
252
+ }
253
+
236
254
  try {
237
255
  const options = {
238
- cwd: directory,
256
+ cwd: targetDir,
239
257
  ignore: ['node_modules/**', '.git/**'],
240
258
  absolute: false
241
259
  };
@@ -141,12 +141,45 @@ export function parseXmlToolCallWithThinking(xmlString, validTools) {
141
141
  // Remove thinking tags and their content from the XML string
142
142
  let cleanedXmlString = xmlString.replace(/<thinking>[\s\S]*?<\/thinking>/g, '').trim();
143
143
 
144
- // Check for attempt_complete shorthand (single tag with no closing tag and no parameters)
145
- const attemptCompleteMatch = cleanedXmlString.match(/^<attempt_complete>\s*$/);
146
- if (attemptCompleteMatch) {
147
- // Convert shorthand to full attempt_completion format with special marker
144
+ // Enhanced recovery logic for attempt_complete shorthand
145
+ // Check for various forms of attempt_complete tags:
146
+ // 1. Perfect shorthand: <attempt_complete>
147
+ // 2. Self-closing: <attempt_complete/>
148
+ // 3. Empty with closing tag: <attempt_complete></attempt_complete>
149
+ // 4. Incomplete: <attempt_complete (missing closing bracket)
150
+ // 5. With trailing content that should be ignored
151
+ const attemptCompletePatterns = [
152
+ // Standard shorthand with optional whitespace
153
+ /^<attempt_complete>\s*$/,
154
+ // Empty with proper closing tag (common case from the logs)
155
+ /^<attempt_complete>\s*<\/attempt_complete>\s*$/,
156
+ // Self-closing variant
157
+ /^<attempt_complete\s*\/>\s*$/,
158
+ // Incomplete opening tag (missing closing bracket)
159
+ /^<attempt_complete\s*$/,
160
+ // With trailing content (extract just the tag part) - must come after empty tag pattern
161
+ /^<attempt_complete>(.*)$/s,
162
+ // Self-closing with trailing content
163
+ /^<attempt_complete\s*\/>(.*)$/s
164
+ ];
165
+
166
+ for (const pattern of attemptCompletePatterns) {
167
+ const match = cleanedXmlString.match(pattern);
168
+ if (match) {
169
+ // Convert any form of attempt_complete to the standard format
170
+ return {
171
+ toolName: 'attempt_completion',
172
+ params: { result: '__PREVIOUS_RESPONSE__' }
173
+ };
174
+ }
175
+ }
176
+
177
+ // Additional recovery: check if the string contains attempt_complete anywhere
178
+ // and treat the entire response as a completion signal if no other tool tags are found
179
+ if (cleanedXmlString.includes('<attempt_complete') && !hasOtherToolTags(cleanedXmlString, validTools)) {
180
+ // This handles malformed cases where attempt_complete appears but is broken
148
181
  return {
149
- toolName: 'attempt_completion',
182
+ toolName: 'attempt_completion',
150
183
  params: { result: '__PREVIOUS_RESPONSE__' }
151
184
  };
152
185
  }
@@ -160,4 +193,23 @@ export function parseXmlToolCallWithThinking(xmlString, validTools) {
160
193
  }
161
194
 
162
195
  return parsedTool;
196
+ }
197
+
198
+ /**
199
+ * Helper function to check if the XML string contains other tool tags
200
+ * @param {string} xmlString - The XML string to check
201
+ * @param {string[]} validTools - List of valid tool names
202
+ * @returns {boolean} - True if other tool tags are found
203
+ */
204
+ function hasOtherToolTags(xmlString, validTools = []) {
205
+ const defaultTools = ['search', 'query', 'extract', 'listFiles', 'searchFiles', 'implement', 'attempt_completion'];
206
+ const toolsToCheck = validTools.length > 0 ? validTools : defaultTools;
207
+
208
+ // Check for any tool tags other than attempt_complete variants
209
+ for (const tool of toolsToCheck) {
210
+ if (tool !== 'attempt_completion' && xmlString.includes(`<${tool}`)) {
211
+ return true;
212
+ }
213
+ }
214
+ return false;
163
215
  }
@@ -8,7 +8,7 @@ import path from 'path';
8
8
  import fs from 'fs-extra';
9
9
  import { fileURLToPath } from 'url';
10
10
  // Import from parent package
11
- import { search, query, extract } from '../index.js';
11
+ import { search, extract } from '../index.js';
12
12
  // Parse command-line arguments
13
13
  function parseArgs() {
14
14
  const args = process.argv.slice(2);
@@ -128,38 +128,22 @@ class ProbeServer {
128
128
  },
129
129
  query: {
130
130
  type: 'string',
131
- description: 'Elastic search query. Supports logical operators (AND, OR, NOT), and grouping with parentheses. Examples: "config", "(term1 OR term2) AND term3". Use quotes for exact matches, like function or type names.',
132
- },
133
- filesOnly: {
134
- type: 'boolean',
135
- description: 'Skip AST parsing and just output unique files',
136
- },
137
- ignore: {
138
- type: 'array',
139
- items: { type: 'string' },
140
- description: 'Custom patterns to ignore (in addition to .gitignore and common patterns)'
141
- },
142
- excludeFilenames: {
143
- type: 'boolean',
144
- description: 'Exclude filenames from being used for matching'
131
+ description: 'Elastic search query. Supports logical operators (AND, OR, NOT), and grouping with parentheses. For exact matches of specific identifiers, use quotes: "MyFunction", "SpecificStruct", "exact_variable_name". Examples: "config", "(term1 OR term2) AND term3", "getUserData", "struct Config".',
145
132
  },
146
133
  exact: {
147
134
  type: 'boolean',
148
- description: 'Perform exact search without tokenization (case-insensitive)'
135
+ description: 'When you exactly know what you are looking for, like known function name, struct name, or variable name, set this flag for precise matching'
149
136
  },
150
137
  allowTests: {
151
138
  type: 'boolean',
152
- description: 'Allow test files and test code blocks in results (disabled by default)'
139
+ description: 'Allow test files and test code blocks in results (enabled by default)',
140
+ default: true
153
141
  },
154
142
  session: {
155
143
  type: 'string',
156
144
  description: 'Session identifier for caching. Set to "new" if unknown, or want to reset cache. Re-use session ID returned from previous searches',
157
145
  default: "new",
158
146
  },
159
- timeout: {
160
- type: 'number',
161
- description: 'Timeout for the search operation in seconds (default: 30)',
162
- },
163
147
  noGitignore: {
164
148
  type: 'boolean',
165
149
  description: 'Skip .gitignore files (will use PROBE_NO_GITIGNORE environment variable if not set)',
@@ -168,50 +152,6 @@ class ProbeServer {
168
152
  required: ['path', 'query']
169
153
  },
170
154
  },
171
- {
172
- name: 'query_code',
173
- description: "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.",
174
- inputSchema: {
175
- type: 'object',
176
- properties: {
177
- path: {
178
- type: 'string',
179
- description: 'Absolute path to the directory to search in (e.g., "/Users/username/projects/myproject").',
180
- },
181
- pattern: {
182
- type: 'string',
183
- description: 'The ast-grep pattern to search for. Examples: "fn $NAME($$$PARAMS) $$$BODY" for Rust functions, "def $NAME($$$PARAMS): $$$BODY" for Python functions.',
184
- },
185
- language: {
186
- type: 'string',
187
- description: 'The programming language to search in. If not specified, the tool will try to infer the language from file extensions. Supported languages: rust, javascript, typescript, python, go, c, cpp, java, ruby, php, swift, csharp, yaml.',
188
- },
189
- ignore: {
190
- type: 'array',
191
- items: { type: 'string' },
192
- description: 'Custom patterns to ignore (in addition to common patterns)',
193
- },
194
- maxResults: {
195
- type: 'number',
196
- description: 'Maximum number of results to return'
197
- },
198
- format: {
199
- type: 'string',
200
- enum: ['markdown', 'plain', 'json', 'color'],
201
- description: 'Output format for the query results'
202
- },
203
- timeout: {
204
- type: 'number',
205
- description: 'Timeout for the query operation in seconds (default: 30)',
206
- },
207
- noGitignore: {
208
- type: 'boolean',
209
- description: 'Skip .gitignore files (will use PROBE_NO_GITIGNORE environment variable if not set)',
210
- }
211
- },
212
- required: ['path', 'pattern']
213
- },
214
- },
215
155
  {
216
156
  name: 'extract_code',
217
157
  description: "Extract code blocks from files based on line number, or symbol name. Fetch full file when line number is not provided.",
@@ -229,22 +169,8 @@ class ProbeServer {
229
169
  },
230
170
  allowTests: {
231
171
  type: 'boolean',
232
- description: 'Allow test files and test code blocks in results (disabled by default)',
233
- },
234
- contextLines: {
235
- type: 'number',
236
- description: 'Number of context lines to include before and after the extracted block when AST parsing fails to find a suitable node',
237
- default: 0
238
- },
239
- format: {
240
- type: 'string',
241
- enum: ['markdown', 'plain', 'json'],
242
- description: 'Output format for the extracted code',
243
- default: 'markdown'
244
- },
245
- timeout: {
246
- type: 'number',
247
- description: 'Timeout for the extract operation in seconds (default: 30)',
172
+ description: 'Allow test files and test code blocks in results (enabled by default)',
173
+ default: true
248
174
  },
249
175
  noGitignore: {
250
176
  type: 'boolean',
@@ -257,8 +183,8 @@ class ProbeServer {
257
183
  ],
258
184
  }));
259
185
  this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
260
- if (request.params.name !== 'search_code' && request.params.name !== 'query_code' && request.params.name !== 'extract_code' &&
261
- request.params.name !== 'probe' && request.params.name !== 'query' && request.params.name !== 'extract') {
186
+ if (request.params.name !== 'search_code' && request.params.name !== 'extract_code' &&
187
+ request.params.name !== 'probe' && request.params.name !== 'extract') {
262
188
  throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
263
189
  }
264
190
  try {
@@ -282,10 +208,6 @@ class ProbeServer {
282
208
  }
283
209
  result = await this.executeCodeSearch(args);
284
210
  }
285
- else if (request.params.name === 'query_code' || request.params.name === 'query') {
286
- const args = request.params.arguments;
287
- result = await this.executeCodeQuery(args);
288
- }
289
211
  else { // extract_code or extract
290
212
  const args = request.params.arguments;
291
213
  result = await this.executeCodeExtract(args);
@@ -331,20 +253,19 @@ class ProbeServer {
331
253
  query: args.query
332
254
  };
333
255
  // Add optional parameters only if they exist
334
- if (args.filesOnly !== undefined)
335
- options.filesOnly = args.filesOnly;
336
- if (args.ignore !== undefined)
337
- options.ignore = args.ignore;
338
- if (args.excludeFilenames !== undefined)
339
- options.excludeFilenames = args.excludeFilenames;
340
256
  if (args.exact !== undefined)
341
257
  options.exact = args.exact;
342
258
  if (args.maxResults !== undefined)
343
259
  options.maxResults = args.maxResults;
344
260
  if (args.maxTokens !== undefined)
345
261
  options.maxTokens = args.maxTokens;
346
- if (args.allowTests !== undefined)
262
+ // Set allowTests to true by default if not specified
263
+ if (args.allowTests !== undefined) {
347
264
  options.allowTests = args.allowTests;
265
+ }
266
+ else {
267
+ options.allowTests = true;
268
+ }
348
269
  // Use noGitignore from args, or fall back to PROBE_NO_GITIGNORE environment variable
349
270
  if (args.noGitignore !== undefined) {
350
271
  options.noGitignore = args.noGitignore;
@@ -358,13 +279,6 @@ class ProbeServer {
358
279
  else {
359
280
  options.session = "new";
360
281
  }
361
- // Use timeout from args, or fall back to instance default
362
- if (args.timeout !== undefined) {
363
- options.timeout = args.timeout;
364
- }
365
- else if (this.defaultTimeout !== undefined) {
366
- options.timeout = this.defaultTimeout;
367
- }
368
282
  // Handle format options
369
283
  if (this.defaultFormat === 'outline-xml') {
370
284
  // For outline-xml format, we pass it as a format flag to the search command
@@ -394,45 +308,6 @@ class ProbeServer {
394
308
  throw new McpError('MethodNotFound', `Error executing code search: ${error.message || String(error)}`);
395
309
  }
396
310
  }
397
- async executeCodeQuery(args) {
398
- try {
399
- // Validate required parameters
400
- if (!args.path) {
401
- throw new Error("Path is required");
402
- }
403
- if (!args.pattern) {
404
- throw new Error("Pattern is required");
405
- }
406
- // Create a single options object with both pattern and path
407
- const options = {
408
- path: args.path,
409
- pattern: args.pattern,
410
- language: args.language,
411
- ignore: args.ignore,
412
- allowTests: args.allowTests,
413
- maxResults: args.maxResults,
414
- format: args.format,
415
- timeout: args.timeout || this.defaultTimeout
416
- };
417
- // Use noGitignore from args, or fall back to PROBE_NO_GITIGNORE environment variable
418
- if (args.noGitignore !== undefined) {
419
- options.noGitignore = args.noGitignore;
420
- }
421
- else if (process.env.PROBE_NO_GITIGNORE) {
422
- options.noGitignore = process.env.PROBE_NO_GITIGNORE === 'true';
423
- }
424
- console.log("Executing query with options:", JSON.stringify({
425
- path: options.path,
426
- pattern: options.pattern
427
- }));
428
- const result = await query(options);
429
- return result;
430
- }
431
- catch (error) {
432
- console.error('Error executing code query:', error);
433
- throw new McpError('MethodNotFound', `Error executing code query: ${error.message || String(error)}`);
434
- }
435
- }
436
311
  async executeCodeExtract(args) {
437
312
  try {
438
313
  // Validate required parameters
@@ -446,11 +321,15 @@ class ProbeServer {
446
321
  const options = {
447
322
  files: args.files,
448
323
  path: args.path,
449
- allowTests: args.allowTests,
450
- contextLines: args.contextLines,
451
- format: args.format,
452
- timeout: args.timeout || this.defaultTimeout
324
+ format: 'xml'
453
325
  };
326
+ // Set allowTests to true by default if not specified
327
+ if (args.allowTests !== undefined) {
328
+ options.allowTests = args.allowTests;
329
+ }
330
+ else {
331
+ options.allowTests = true;
332
+ }
454
333
  // Use noGitignore from args, or fall back to PROBE_NO_GITIGNORE environment variable
455
334
  if (args.noGitignore !== undefined) {
456
335
  options.noGitignore = args.noGitignore;
@@ -112,37 +112,19 @@ console.log(`Bin directory: ${binDir}`);
112
112
  interface SearchCodeArgs {
113
113
  path: string;
114
114
  query: string | string[];
115
- filesOnly?: boolean;
116
- ignore?: string[];
117
- excludeFilenames?: boolean;
118
115
  exact?: boolean;
119
116
  maxResults?: number;
120
117
  maxTokens?: number;
121
118
  allowTests?: boolean;
122
119
  session?: string;
123
- timeout?: number;
124
120
  noGitignore?: boolean;
125
121
  }
126
122
 
127
- interface QueryCodeArgs {
128
- path: string;
129
- pattern: string;
130
- language?: string;
131
- ignore?: string[];
132
- allowTests?: boolean;
133
- maxResults?: number;
134
- format?: 'markdown' | 'plain' | 'json' | 'color';
135
- timeout?: number;
136
- noGitignore?: boolean;
137
- }
138
123
 
139
124
  interface ExtractCodeArgs {
140
125
  path: string;
141
126
  files: string[];
142
127
  allowTests?: boolean;
143
- contextLines?: number;
144
- format?: 'markdown' | 'plain' | 'json';
145
- timeout?: number;
146
128
  noGitignore?: boolean;
147
129
  }
148
130
 
@@ -193,38 +175,22 @@ class ProbeServer {
193
175
  },
194
176
  query: {
195
177
  type: 'string',
196
- description: 'Elastic search query. Supports logical operators (AND, OR, NOT), and grouping with parentheses. Examples: "config", "(term1 OR term2) AND term3". Use quotes for exact matches, like function or type names.',
197
- },
198
- filesOnly: {
199
- type: 'boolean',
200
- description: 'Skip AST parsing and just output unique files',
201
- },
202
- ignore: {
203
- type: 'array',
204
- items: { type: 'string' },
205
- description: 'Custom patterns to ignore (in addition to .gitignore and common patterns)'
206
- },
207
- excludeFilenames: {
208
- type: 'boolean',
209
- description: 'Exclude filenames from being used for matching'
178
+ description: 'Elastic search query. Supports logical operators (AND, OR, NOT), and grouping with parentheses. For exact matches of specific identifiers, use quotes: "MyFunction", "SpecificStruct", "exact_variable_name". Examples: "config", "(term1 OR term2) AND term3", "getUserData", "struct Config".',
210
179
  },
211
180
  exact: {
212
181
  type: 'boolean',
213
- description: 'Perform exact search without tokenization (case-insensitive)'
182
+ description: 'When you exactly know what you are looking for, like known function name, struct name, or variable name, set this flag for precise matching'
214
183
  },
215
184
  allowTests: {
216
185
  type: 'boolean',
217
- description: 'Allow test files and test code blocks in results (disabled by default)'
186
+ description: 'Allow test files and test code blocks in results (enabled by default)',
187
+ default: true
218
188
  },
219
189
  session: {
220
190
  type: 'string',
221
191
  description: 'Session identifier for caching. Set to "new" if unknown, or want to reset cache. Re-use session ID returned from previous searches',
222
192
  default: "new",
223
193
  },
224
- timeout: {
225
- type: 'number',
226
- description: 'Timeout for the search operation in seconds (default: 30)',
227
- },
228
194
  noGitignore: {
229
195
  type: 'boolean',
230
196
  description: 'Skip .gitignore files (will use PROBE_NO_GITIGNORE environment variable if not set)',
@@ -233,50 +199,6 @@ class ProbeServer {
233
199
  required: ['path', 'query']
234
200
  },
235
201
  },
236
- {
237
- name: 'query_code',
238
- description: "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.",
239
- inputSchema: {
240
- type: 'object',
241
- properties: {
242
- path: {
243
- type: 'string',
244
- description: 'Absolute path to the directory to search in (e.g., "/Users/username/projects/myproject").',
245
- },
246
- pattern: {
247
- type: 'string',
248
- description: 'The ast-grep pattern to search for. Examples: "fn $NAME($$$PARAMS) $$$BODY" for Rust functions, "def $NAME($$$PARAMS): $$$BODY" for Python functions.',
249
- },
250
- language: {
251
- type: 'string',
252
- description: 'The programming language to search in. If not specified, the tool will try to infer the language from file extensions. Supported languages: rust, javascript, typescript, python, go, c, cpp, java, ruby, php, swift, csharp, yaml.',
253
- },
254
- ignore: {
255
- type: 'array',
256
- items: { type: 'string' },
257
- description: 'Custom patterns to ignore (in addition to common patterns)',
258
- },
259
- maxResults: {
260
- type: 'number',
261
- description: 'Maximum number of results to return'
262
- },
263
- format: {
264
- type: 'string',
265
- enum: ['markdown', 'plain', 'json', 'color'],
266
- description: 'Output format for the query results'
267
- },
268
- timeout: {
269
- type: 'number',
270
- description: 'Timeout for the query operation in seconds (default: 30)',
271
- },
272
- noGitignore: {
273
- type: 'boolean',
274
- description: 'Skip .gitignore files (will use PROBE_NO_GITIGNORE environment variable if not set)',
275
- }
276
- },
277
- required: ['path', 'pattern']
278
- },
279
- },
280
202
  {
281
203
  name: 'extract_code',
282
204
  description: "Extract code blocks from files based on line number, or symbol name. Fetch full file when line number is not provided.",
@@ -294,22 +216,8 @@ class ProbeServer {
294
216
  },
295
217
  allowTests: {
296
218
  type: 'boolean',
297
- description: 'Allow test files and test code blocks in results (disabled by default)',
298
- },
299
- contextLines: {
300
- type: 'number',
301
- description: 'Number of context lines to include before and after the extracted block when AST parsing fails to find a suitable node',
302
- default: 0
303
- },
304
- format: {
305
- type: 'string',
306
- enum: ['markdown', 'plain', 'json'],
307
- description: 'Output format for the extracted code',
308
- default: 'markdown'
309
- },
310
- timeout: {
311
- type: 'number',
312
- description: 'Timeout for the extract operation in seconds (default: 30)',
219
+ description: 'Allow test files and test code blocks in results (enabled by default)',
220
+ default: true
313
221
  },
314
222
  noGitignore: {
315
223
  type: 'boolean',
@@ -323,8 +231,8 @@ class ProbeServer {
323
231
  }));
324
232
 
325
233
  this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
326
- if (request.params.name !== 'search_code' && request.params.name !== 'query_code' && request.params.name !== 'extract_code' &&
327
- request.params.name !== 'probe' && request.params.name !== 'query' && request.params.name !== 'extract') {
234
+ if (request.params.name !== 'search_code' && request.params.name !== 'extract_code' &&
235
+ request.params.name !== 'probe' && request.params.name !== 'extract') {
328
236
  throw new McpError(
329
237
  ErrorCode.MethodNotFound,
330
238
  `Unknown tool: ${request.params.name}`
@@ -356,9 +264,6 @@ class ProbeServer {
356
264
  }
357
265
 
358
266
  result = await this.executeCodeSearch(args);
359
- } else if (request.params.name === 'query_code' || request.params.name === 'query') {
360
- const args = request.params.arguments as unknown as QueryCodeArgs;
361
- result = await this.executeCodeQuery(args);
362
267
  } else { // extract_code or extract
363
268
  const args = request.params.arguments as unknown as ExtractCodeArgs;
364
269
  result = await this.executeCodeExtract(args);
@@ -409,13 +314,15 @@ class ProbeServer {
409
314
  };
410
315
 
411
316
  // Add optional parameters only if they exist
412
- if (args.filesOnly !== undefined) options.filesOnly = args.filesOnly;
413
- if (args.ignore !== undefined) options.ignore = args.ignore;
414
- if (args.excludeFilenames !== undefined) options.excludeFilenames = args.excludeFilenames;
415
317
  if (args.exact !== undefined) options.exact = args.exact;
416
318
  if (args.maxResults !== undefined) options.maxResults = args.maxResults;
417
319
  if (args.maxTokens !== undefined) options.maxTokens = args.maxTokens;
418
- if (args.allowTests !== undefined) options.allowTests = args.allowTests;
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
+ }
419
326
  // Use noGitignore from args, or fall back to PROBE_NO_GITIGNORE environment variable
420
327
  if (args.noGitignore !== undefined) {
421
328
  options.noGitignore = args.noGitignore;
@@ -427,12 +334,6 @@ class ProbeServer {
427
334
  } else {
428
335
  options.session = "new";
429
336
  }
430
- // Use timeout from args, or fall back to instance default
431
- if (args.timeout !== undefined) {
432
- options.timeout = args.timeout;
433
- } else if (this.defaultTimeout !== undefined) {
434
- options.timeout = this.defaultTimeout;
435
- }
436
337
 
437
338
  // Handle format options
438
339
  if (this.defaultFormat === 'outline-xml') {
@@ -467,50 +368,6 @@ class ProbeServer {
467
368
  }
468
369
  }
469
370
 
470
- private async executeCodeQuery(args: QueryCodeArgs): Promise<string> {
471
- try {
472
- // Validate required parameters
473
- if (!args.path) {
474
- throw new Error("Path is required");
475
- }
476
- if (!args.pattern) {
477
- throw new Error("Pattern is required");
478
- }
479
-
480
- // Create a single options object with both pattern and path
481
- const options: any = {
482
- path: args.path,
483
- pattern: args.pattern,
484
- language: args.language,
485
- ignore: args.ignore,
486
- allowTests: args.allowTests,
487
- maxResults: args.maxResults,
488
- format: args.format,
489
- timeout: args.timeout || this.defaultTimeout
490
- };
491
-
492
- // Use noGitignore from args, or fall back to PROBE_NO_GITIGNORE environment variable
493
- if (args.noGitignore !== undefined) {
494
- options.noGitignore = args.noGitignore;
495
- } else if (process.env.PROBE_NO_GITIGNORE) {
496
- options.noGitignore = process.env.PROBE_NO_GITIGNORE === 'true';
497
- }
498
-
499
- console.log("Executing query with options:", JSON.stringify({
500
- path: options.path,
501
- pattern: options.pattern
502
- }));
503
-
504
- const result = await query(options);
505
- return result;
506
- } catch (error: any) {
507
- console.error('Error executing code query:', error);
508
- throw new McpError(
509
- 'MethodNotFound' as unknown as ErrorCode,
510
- `Error executing code query: ${error.message || String(error)}`
511
- );
512
- }
513
- }
514
371
 
515
372
  private async executeCodeExtract(args: ExtractCodeArgs): Promise<string> {
516
373
  try {
@@ -526,12 +383,16 @@ class ProbeServer {
526
383
  const options: any = {
527
384
  files: args.files,
528
385
  path: args.path,
529
- allowTests: args.allowTests,
530
- contextLines: args.contextLines,
531
- format: args.format,
532
- timeout: args.timeout || this.defaultTimeout
386
+ format: 'xml'
533
387
  };
534
388
 
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
+
535
396
  // Use noGitignore from args, or fall back to PROBE_NO_GITIGNORE environment variable
536
397
  if (args.noGitignore !== undefined) {
537
398
  options.noGitignore = args.noGitignore;
package/build/utils.js CHANGED
@@ -43,7 +43,7 @@ export async function getBinaryPath(options = {}) {
43
43
 
44
44
  // Check bin directory
45
45
  const isWindows = process.platform === 'win32';
46
- const binaryName = isWindows ? 'probe.exe' : 'probe';
46
+ const binaryName = isWindows ? 'probe.exe' : 'probe-binary';
47
47
  const binaryPath = path.join(binDir, binaryName);
48
48
 
49
49
  if (fs.existsSync(binaryPath) && !forceDownload) {