@probelabs/probe 0.6.0-rc141 → 0.6.0-rc142
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/build/agent/index.js +34 -28
- package/build/mcp/index.js +3 -2
- package/build/mcp/index.ts +3 -2
- package/build/search.js +20 -29
- package/cjs/agent/ProbeAgent.cjs +28 -22
- package/cjs/index.cjs +29 -23
- package/package.json +1 -1
- package/src/mcp/index.ts +3 -2
- package/src/search.js +20 -29
package/build/agent/index.js
CHANGED
|
@@ -2471,7 +2471,7 @@ var init_utils = __esm({
|
|
|
2471
2471
|
});
|
|
2472
2472
|
|
|
2473
2473
|
// src/search.js
|
|
2474
|
-
import {
|
|
2474
|
+
import { execFile } from "child_process";
|
|
2475
2475
|
import { promisify as promisify2 } from "util";
|
|
2476
2476
|
async function search(options) {
|
|
2477
2477
|
if (!options || !options.path) {
|
|
@@ -2523,17 +2523,20 @@ Search: query="${queries[0]}" path="${options.path}"`;
|
|
|
2523
2523
|
if (options.session) logMessage += ` session=${options.session}`;
|
|
2524
2524
|
console.error(logMessage);
|
|
2525
2525
|
}
|
|
2526
|
-
const
|
|
2526
|
+
const args = ["search", ...cliArgs];
|
|
2527
2527
|
if (queries.length > 0) {
|
|
2528
|
-
|
|
2528
|
+
args.push(queries[0]);
|
|
2529
|
+
}
|
|
2530
|
+
args.push(options.path);
|
|
2531
|
+
if (process.env.DEBUG === "1") {
|
|
2532
|
+
console.error(`Executing: ${binaryPath} ${args.join(" ")}`);
|
|
2529
2533
|
}
|
|
2530
|
-
positionalArgs.push(escapeString(options.path));
|
|
2531
|
-
const command = `${binaryPath} search ${cliArgs.join(" ")} ${positionalArgs.join(" ")}`;
|
|
2532
2534
|
try {
|
|
2533
|
-
const { stdout, stderr } = await
|
|
2534
|
-
|
|
2535
|
-
timeout: options.timeout * 1e3
|
|
2535
|
+
const { stdout, stderr } = await execFileAsync(binaryPath, args, {
|
|
2536
|
+
timeout: options.timeout * 1e3,
|
|
2536
2537
|
// Convert seconds to milliseconds
|
|
2538
|
+
maxBuffer: 50 * 1024 * 1024
|
|
2539
|
+
// 50MB buffer for large outputs
|
|
2537
2540
|
});
|
|
2538
2541
|
if (stderr && process.env.DEBUG) {
|
|
2539
2542
|
console.error(`stderr: ${stderr}`);
|
|
@@ -2582,21 +2585,23 @@ Search results: ${resultCount} matches, ${tokenCount} tokens`;
|
|
|
2582
2585
|
} catch (error) {
|
|
2583
2586
|
if (error.code === "ETIMEDOUT" || error.killed) {
|
|
2584
2587
|
const timeoutMessage = `Search operation timed out after ${options.timeout} seconds.
|
|
2585
|
-
|
|
2588
|
+
Binary: ${binaryPath}
|
|
2589
|
+
Args: ${args.join(" ")}`;
|
|
2586
2590
|
console.error(timeoutMessage);
|
|
2587
2591
|
throw new Error(timeoutMessage);
|
|
2588
2592
|
}
|
|
2589
2593
|
const errorMessage = `Error executing search command: ${error.message}
|
|
2590
|
-
|
|
2594
|
+
Binary: ${binaryPath}
|
|
2595
|
+
Args: ${args.join(" ")}`;
|
|
2591
2596
|
throw new Error(errorMessage);
|
|
2592
2597
|
}
|
|
2593
2598
|
}
|
|
2594
|
-
var
|
|
2599
|
+
var execFileAsync, SEARCH_FLAG_MAP;
|
|
2595
2600
|
var init_search = __esm({
|
|
2596
2601
|
"src/search.js"() {
|
|
2597
2602
|
"use strict";
|
|
2598
2603
|
init_utils();
|
|
2599
|
-
|
|
2604
|
+
execFileAsync = promisify2(execFile);
|
|
2600
2605
|
SEARCH_FLAG_MAP = {
|
|
2601
2606
|
filesOnly: "--files-only",
|
|
2602
2607
|
ignore: "--ignore",
|
|
@@ -2604,6 +2609,7 @@ var init_search = __esm({
|
|
|
2604
2609
|
reranker: "--reranker",
|
|
2605
2610
|
frequencySearch: "--frequency",
|
|
2606
2611
|
exact: "--exact",
|
|
2612
|
+
strictElasticSyntax: "--strict-elastic-syntax",
|
|
2607
2613
|
maxResults: "--max-results",
|
|
2608
2614
|
maxBytes: "--max-bytes",
|
|
2609
2615
|
maxTokens: "--max-tokens",
|
|
@@ -2619,7 +2625,7 @@ var init_search = __esm({
|
|
|
2619
2625
|
});
|
|
2620
2626
|
|
|
2621
2627
|
// src/query.js
|
|
2622
|
-
import { exec as
|
|
2628
|
+
import { exec as exec2 } from "child_process";
|
|
2623
2629
|
import { promisify as promisify3 } from "util";
|
|
2624
2630
|
async function query(options) {
|
|
2625
2631
|
if (!options || !options.path) {
|
|
@@ -2643,7 +2649,7 @@ async function query(options) {
|
|
|
2643
2649
|
}
|
|
2644
2650
|
const command = `${binaryPath} query ${cliArgs.join(" ")}`;
|
|
2645
2651
|
try {
|
|
2646
|
-
const { stdout, stderr } = await
|
|
2652
|
+
const { stdout, stderr } = await execAsync(command);
|
|
2647
2653
|
if (stderr) {
|
|
2648
2654
|
console.error(`stderr: ${stderr}`);
|
|
2649
2655
|
}
|
|
@@ -2672,12 +2678,12 @@ Command: ${command}`;
|
|
|
2672
2678
|
throw new Error(errorMessage);
|
|
2673
2679
|
}
|
|
2674
2680
|
}
|
|
2675
|
-
var
|
|
2681
|
+
var execAsync, QUERY_FLAG_MAP;
|
|
2676
2682
|
var init_query = __esm({
|
|
2677
2683
|
"src/query.js"() {
|
|
2678
2684
|
"use strict";
|
|
2679
2685
|
init_utils();
|
|
2680
|
-
|
|
2686
|
+
execAsync = promisify3(exec2);
|
|
2681
2687
|
QUERY_FLAG_MAP = {
|
|
2682
2688
|
language: "--language",
|
|
2683
2689
|
ignore: "--ignore",
|
|
@@ -2689,7 +2695,7 @@ var init_query = __esm({
|
|
|
2689
2695
|
});
|
|
2690
2696
|
|
|
2691
2697
|
// src/extract.js
|
|
2692
|
-
import { exec as
|
|
2698
|
+
import { exec as exec3, spawn } from "child_process";
|
|
2693
2699
|
import { promisify as promisify4 } from "util";
|
|
2694
2700
|
async function extract(options) {
|
|
2695
2701
|
if (!options) {
|
|
@@ -2732,7 +2738,7 @@ Extract:`;
|
|
|
2732
2738
|
}
|
|
2733
2739
|
const command = `${binaryPath} extract ${cliArgs.join(" ")}`;
|
|
2734
2740
|
try {
|
|
2735
|
-
const { stdout, stderr } = await
|
|
2741
|
+
const { stdout, stderr } = await execAsync2(command);
|
|
2736
2742
|
if (stderr) {
|
|
2737
2743
|
console.error(`stderr: ${stderr}`);
|
|
2738
2744
|
}
|
|
@@ -2830,12 +2836,12 @@ Token Usage:
|
|
|
2830
2836
|
}
|
|
2831
2837
|
return output;
|
|
2832
2838
|
}
|
|
2833
|
-
var
|
|
2839
|
+
var execAsync2, EXTRACT_FLAG_MAP;
|
|
2834
2840
|
var init_extract = __esm({
|
|
2835
2841
|
"src/extract.js"() {
|
|
2836
2842
|
"use strict";
|
|
2837
2843
|
init_utils();
|
|
2838
|
-
|
|
2844
|
+
execAsync2 = promisify4(exec3);
|
|
2839
2845
|
EXTRACT_FLAG_MAP = {
|
|
2840
2846
|
allowTests: "--allow-tests",
|
|
2841
2847
|
contextLines: "--context",
|
|
@@ -2846,14 +2852,14 @@ var init_extract = __esm({
|
|
|
2846
2852
|
});
|
|
2847
2853
|
|
|
2848
2854
|
// src/grep.js
|
|
2849
|
-
import { execFile } from "child_process";
|
|
2855
|
+
import { execFile as execFile2 } from "child_process";
|
|
2850
2856
|
import { promisify as promisify5 } from "util";
|
|
2851
|
-
var
|
|
2857
|
+
var execFileAsync2;
|
|
2852
2858
|
var init_grep = __esm({
|
|
2853
2859
|
"src/grep.js"() {
|
|
2854
2860
|
"use strict";
|
|
2855
2861
|
init_utils();
|
|
2856
|
-
|
|
2862
|
+
execFileAsync2 = promisify5(execFile2);
|
|
2857
2863
|
}
|
|
2858
2864
|
});
|
|
2859
2865
|
|
|
@@ -9119,7 +9125,7 @@ var init_tools = __esm({
|
|
|
9119
9125
|
import fs4 from "fs";
|
|
9120
9126
|
import path4 from "path";
|
|
9121
9127
|
import { promisify as promisify6 } from "util";
|
|
9122
|
-
import { exec as
|
|
9128
|
+
import { exec as exec4 } from "child_process";
|
|
9123
9129
|
async function listFilesByLevel(options) {
|
|
9124
9130
|
const {
|
|
9125
9131
|
directory,
|
|
@@ -9141,7 +9147,7 @@ async function listFilesByLevel(options) {
|
|
|
9141
9147
|
return await listFilesByLevelManually(directory, maxFiles, respectGitignore);
|
|
9142
9148
|
}
|
|
9143
9149
|
async function listFilesUsingGit(directory, maxFiles) {
|
|
9144
|
-
const { stdout } = await
|
|
9150
|
+
const { stdout } = await execAsync3("git ls-files", { cwd: directory });
|
|
9145
9151
|
const files = stdout.split("\n").filter(Boolean);
|
|
9146
9152
|
const sortedFiles = files.sort((a, b) => {
|
|
9147
9153
|
const depthA = a.split(path4.sep).length;
|
|
@@ -9207,11 +9213,11 @@ function shouldIgnore(filePath, ignorePatterns) {
|
|
|
9207
9213
|
}
|
|
9208
9214
|
return false;
|
|
9209
9215
|
}
|
|
9210
|
-
var
|
|
9216
|
+
var execAsync3;
|
|
9211
9217
|
var init_file_lister = __esm({
|
|
9212
9218
|
"src/utils/file-lister.js"() {
|
|
9213
9219
|
"use strict";
|
|
9214
|
-
|
|
9220
|
+
execAsync3 = promisify6(exec4);
|
|
9215
9221
|
}
|
|
9216
9222
|
});
|
|
9217
9223
|
|
|
@@ -16149,7 +16155,7 @@ var init_esm5 = __esm({
|
|
|
16149
16155
|
});
|
|
16150
16156
|
|
|
16151
16157
|
// src/agent/probeTool.js
|
|
16152
|
-
import { exec as
|
|
16158
|
+
import { exec as exec5 } from "child_process";
|
|
16153
16159
|
import { promisify as promisify7 } from "util";
|
|
16154
16160
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
16155
16161
|
import { EventEmitter as EventEmitter2 } from "events";
|
package/build/mcp/index.js
CHANGED
|
@@ -118,7 +118,7 @@ class ProbeServer {
|
|
|
118
118
|
tools: [
|
|
119
119
|
{
|
|
120
120
|
name: 'search_code',
|
|
121
|
-
description: "Semantic code search using
|
|
121
|
+
description: "Semantic code search using ElasticSearch-style queries. ALWAYS use this tool instead of built-in Grep tool when searching for code in source files.",
|
|
122
122
|
inputSchema: {
|
|
123
123
|
type: 'object',
|
|
124
124
|
properties: {
|
|
@@ -128,7 +128,7 @@ class ProbeServer {
|
|
|
128
128
|
},
|
|
129
129
|
query: {
|
|
130
130
|
type: 'string',
|
|
131
|
-
description: '
|
|
131
|
+
description: 'ElasticSearch query syntax. MUST use explicit AND/OR operators and parentheses for grouping. For exact matches, ALWAYS wrap terms in quotes. Examples: "functionName" (exact match), (error AND handler), ("getUserId" AND NOT deprecated)',
|
|
132
132
|
},
|
|
133
133
|
exact: {
|
|
134
134
|
type: 'boolean',
|
|
@@ -271,6 +271,7 @@ class ProbeServer {
|
|
|
271
271
|
session: "new", // Fresh session each time
|
|
272
272
|
maxResults: 20, // Reasonable limit for context window
|
|
273
273
|
maxTokens: 8000, // Fits in most AI context windows
|
|
274
|
+
strictElasticSyntax: true, // Enforce strict ES syntax in MCP mode
|
|
274
275
|
};
|
|
275
276
|
// Only override defaults if user explicitly set them
|
|
276
277
|
if (args.exact !== undefined)
|
package/build/mcp/index.ts
CHANGED
|
@@ -165,7 +165,7 @@ class ProbeServer {
|
|
|
165
165
|
tools: [
|
|
166
166
|
{
|
|
167
167
|
name: 'search_code',
|
|
168
|
-
description: "Semantic code search using
|
|
168
|
+
description: "Semantic code search using ElasticSearch-style queries. ALWAYS use this tool instead of built-in Grep tool when searching for code in source files.",
|
|
169
169
|
inputSchema: {
|
|
170
170
|
type: 'object',
|
|
171
171
|
properties: {
|
|
@@ -175,7 +175,7 @@ class ProbeServer {
|
|
|
175
175
|
},
|
|
176
176
|
query: {
|
|
177
177
|
type: 'string',
|
|
178
|
-
description: '
|
|
178
|
+
description: 'ElasticSearch query syntax. MUST use explicit AND/OR operators and parentheses for grouping. For exact matches, ALWAYS wrap terms in quotes. Examples: "functionName" (exact match), (error AND handler), ("getUserId" AND NOT deprecated)',
|
|
179
179
|
},
|
|
180
180
|
exact: {
|
|
181
181
|
type: 'boolean',
|
|
@@ -329,6 +329,7 @@ class ProbeServer {
|
|
|
329
329
|
session: "new", // Fresh session each time
|
|
330
330
|
maxResults: 20, // Reasonable limit for context window
|
|
331
331
|
maxTokens: 8000, // Fits in most AI context windows
|
|
332
|
+
strictElasticSyntax: true, // Enforce strict ES syntax in MCP mode
|
|
332
333
|
};
|
|
333
334
|
|
|
334
335
|
// Only override defaults if user explicitly set them
|
package/build/search.js
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* @module search
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { execFile } from 'child_process';
|
|
7
7
|
import { promisify } from 'util';
|
|
8
|
-
import { getBinaryPath, buildCliArgs
|
|
8
|
+
import { getBinaryPath, buildCliArgs } from './utils.js';
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Flag mapping for search options
|
|
@@ -20,6 +20,7 @@ const SEARCH_FLAG_MAP = {
|
|
|
20
20
|
reranker: '--reranker',
|
|
21
21
|
frequencySearch: '--frequency',
|
|
22
22
|
exact: '--exact',
|
|
23
|
+
strictElasticSyntax: '--strict-elastic-syntax',
|
|
23
24
|
maxResults: '--max-results',
|
|
24
25
|
maxBytes: '--max-bytes',
|
|
25
26
|
maxTokens: '--max-tokens',
|
|
@@ -44,6 +45,7 @@ const SEARCH_FLAG_MAP = {
|
|
|
44
45
|
* @param {string} [options.reranker] - Reranking method ('hybrid', 'hybrid2', 'bm25', 'tfidf')
|
|
45
46
|
* @param {boolean} [options.frequencySearch] - Use frequency-based search
|
|
46
47
|
* @param {boolean} [options.exact] - Perform exact search without tokenization (case-insensitive)
|
|
48
|
+
* @param {boolean} [options.strictElasticSyntax] - Enforce strict ElasticSearch query syntax (require explicit AND/OR operators and quotes)
|
|
47
49
|
* @param {number} [options.maxResults] - Maximum number of results
|
|
48
50
|
* @param {number} [options.maxBytes] - Maximum bytes to return
|
|
49
51
|
* @param {number} [options.maxTokens] - Maximum tokens to return
|
|
@@ -135,36 +137,25 @@ export async function search(options) {
|
|
|
135
137
|
if (options.session) logMessage += ` session=${options.session}`;
|
|
136
138
|
console.error(logMessage);
|
|
137
139
|
}
|
|
138
|
-
//
|
|
139
|
-
const
|
|
140
|
+
// Build argument array for secure execution (no shell injection)
|
|
141
|
+
const args = ['search', ...cliArgs];
|
|
140
142
|
|
|
143
|
+
// Add positional arguments (query and path)
|
|
141
144
|
if (queries.length > 0) {
|
|
142
|
-
|
|
143
|
-
positionalArgs.push(escapeString(queries[0]));
|
|
145
|
+
args.push(queries[0]);
|
|
144
146
|
}
|
|
147
|
+
args.push(options.path);
|
|
145
148
|
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
// Execute command with flags first, then positional arguments
|
|
151
|
-
const command = `${binaryPath} search ${cliArgs.join(' ')} ${positionalArgs.join(' ')}`;
|
|
152
|
-
|
|
153
|
-
// Debug logs to see the actual command with quotes and the path
|
|
154
|
-
// console.error(`Executing command: ${command}`);
|
|
155
|
-
// console.error(`Path being used: "${options.path}"`);
|
|
156
|
-
// console.error(`Escaped path: ${escapeString(options.path)}`);
|
|
157
|
-
// console.error(`Command flags: ${cliArgs.join(' ')}`);
|
|
158
|
-
// console.error(`Positional arguments: ${positionalArgs.join(' ')}`);
|
|
149
|
+
// Debug logs
|
|
150
|
+
if (process.env.DEBUG === '1') {
|
|
151
|
+
console.error(`Executing: ${binaryPath} ${args.join(' ')}`);
|
|
152
|
+
}
|
|
159
153
|
|
|
160
154
|
try {
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const { stdout, stderr } = await execAsync(command, {
|
|
166
|
-
shell: true,
|
|
167
|
-
timeout: options.timeout * 1000 // Convert seconds to milliseconds
|
|
155
|
+
// Execute with execFile (no shell, prevents command injection)
|
|
156
|
+
const { stdout, stderr } = await execFileAsync(binaryPath, args, {
|
|
157
|
+
timeout: options.timeout * 1000, // Convert seconds to milliseconds
|
|
158
|
+
maxBuffer: 50 * 1024 * 1024 // 50MB buffer for large outputs
|
|
168
159
|
});
|
|
169
160
|
|
|
170
161
|
// Log after executing
|
|
@@ -235,13 +226,13 @@ export async function search(options) {
|
|
|
235
226
|
} catch (error) {
|
|
236
227
|
// Check if the error is a timeout
|
|
237
228
|
if (error.code === 'ETIMEDOUT' || error.killed) {
|
|
238
|
-
const timeoutMessage = `Search operation timed out after ${options.timeout} seconds.\
|
|
229
|
+
const timeoutMessage = `Search operation timed out after ${options.timeout} seconds.\nBinary: ${binaryPath}\nArgs: ${args.join(' ')}`;
|
|
239
230
|
console.error(timeoutMessage);
|
|
240
231
|
throw new Error(timeoutMessage);
|
|
241
232
|
}
|
|
242
233
|
|
|
243
234
|
// Enhance error message with command details
|
|
244
|
-
const errorMessage = `Error executing search command: ${error.message}\
|
|
235
|
+
const errorMessage = `Error executing search command: ${error.message}\nBinary: ${binaryPath}\nArgs: ${args.join(' ')}`;
|
|
245
236
|
throw new Error(errorMessage);
|
|
246
237
|
}
|
|
247
238
|
}
|
package/cjs/agent/ProbeAgent.cjs
CHANGED
|
@@ -27922,17 +27922,20 @@ Search: query="${queries[0]}" path="${options.path}"`;
|
|
|
27922
27922
|
if (options.session) logMessage += ` session=${options.session}`;
|
|
27923
27923
|
console.error(logMessage);
|
|
27924
27924
|
}
|
|
27925
|
-
const
|
|
27925
|
+
const args = ["search", ...cliArgs];
|
|
27926
27926
|
if (queries.length > 0) {
|
|
27927
|
-
|
|
27927
|
+
args.push(queries[0]);
|
|
27928
|
+
}
|
|
27929
|
+
args.push(options.path);
|
|
27930
|
+
if (process.env.DEBUG === "1") {
|
|
27931
|
+
console.error(`Executing: ${binaryPath} ${args.join(" ")}`);
|
|
27928
27932
|
}
|
|
27929
|
-
positionalArgs.push(escapeString(options.path));
|
|
27930
|
-
const command = `${binaryPath} search ${cliArgs.join(" ")} ${positionalArgs.join(" ")}`;
|
|
27931
27933
|
try {
|
|
27932
|
-
const { stdout, stderr } = await
|
|
27933
|
-
|
|
27934
|
-
timeout: options.timeout * 1e3
|
|
27934
|
+
const { stdout, stderr } = await execFileAsync(binaryPath, args, {
|
|
27935
|
+
timeout: options.timeout * 1e3,
|
|
27935
27936
|
// Convert seconds to milliseconds
|
|
27937
|
+
maxBuffer: 50 * 1024 * 1024
|
|
27938
|
+
// 50MB buffer for large outputs
|
|
27936
27939
|
});
|
|
27937
27940
|
if (stderr && process.env.DEBUG) {
|
|
27938
27941
|
console.error(`stderr: ${stderr}`);
|
|
@@ -27981,23 +27984,25 @@ Search results: ${resultCount} matches, ${tokenCount} tokens`;
|
|
|
27981
27984
|
} catch (error2) {
|
|
27982
27985
|
if (error2.code === "ETIMEDOUT" || error2.killed) {
|
|
27983
27986
|
const timeoutMessage = `Search operation timed out after ${options.timeout} seconds.
|
|
27984
|
-
|
|
27987
|
+
Binary: ${binaryPath}
|
|
27988
|
+
Args: ${args.join(" ")}`;
|
|
27985
27989
|
console.error(timeoutMessage);
|
|
27986
27990
|
throw new Error(timeoutMessage);
|
|
27987
27991
|
}
|
|
27988
27992
|
const errorMessage = `Error executing search command: ${error2.message}
|
|
27989
|
-
|
|
27993
|
+
Binary: ${binaryPath}
|
|
27994
|
+
Args: ${args.join(" ")}`;
|
|
27990
27995
|
throw new Error(errorMessage);
|
|
27991
27996
|
}
|
|
27992
27997
|
}
|
|
27993
|
-
var import_child_process2, import_util4,
|
|
27998
|
+
var import_child_process2, import_util4, execFileAsync, SEARCH_FLAG_MAP;
|
|
27994
27999
|
var init_search = __esm({
|
|
27995
28000
|
"src/search.js"() {
|
|
27996
28001
|
"use strict";
|
|
27997
28002
|
import_child_process2 = require("child_process");
|
|
27998
28003
|
import_util4 = require("util");
|
|
27999
28004
|
init_utils2();
|
|
28000
|
-
|
|
28005
|
+
execFileAsync = (0, import_util4.promisify)(import_child_process2.execFile);
|
|
28001
28006
|
SEARCH_FLAG_MAP = {
|
|
28002
28007
|
filesOnly: "--files-only",
|
|
28003
28008
|
ignore: "--ignore",
|
|
@@ -28005,6 +28010,7 @@ var init_search = __esm({
|
|
|
28005
28010
|
reranker: "--reranker",
|
|
28006
28011
|
frequencySearch: "--frequency",
|
|
28007
28012
|
exact: "--exact",
|
|
28013
|
+
strictElasticSyntax: "--strict-elastic-syntax",
|
|
28008
28014
|
maxResults: "--max-results",
|
|
28009
28015
|
maxBytes: "--max-bytes",
|
|
28010
28016
|
maxTokens: "--max-tokens",
|
|
@@ -28042,7 +28048,7 @@ async function query(options) {
|
|
|
28042
28048
|
}
|
|
28043
28049
|
const command = `${binaryPath} query ${cliArgs.join(" ")}`;
|
|
28044
28050
|
try {
|
|
28045
|
-
const { stdout, stderr } = await
|
|
28051
|
+
const { stdout, stderr } = await execAsync(command);
|
|
28046
28052
|
if (stderr) {
|
|
28047
28053
|
console.error(`stderr: ${stderr}`);
|
|
28048
28054
|
}
|
|
@@ -28071,14 +28077,14 @@ Command: ${command}`;
|
|
|
28071
28077
|
throw new Error(errorMessage);
|
|
28072
28078
|
}
|
|
28073
28079
|
}
|
|
28074
|
-
var import_child_process3, import_util5,
|
|
28080
|
+
var import_child_process3, import_util5, execAsync, QUERY_FLAG_MAP;
|
|
28075
28081
|
var init_query = __esm({
|
|
28076
28082
|
"src/query.js"() {
|
|
28077
28083
|
"use strict";
|
|
28078
28084
|
import_child_process3 = require("child_process");
|
|
28079
28085
|
import_util5 = require("util");
|
|
28080
28086
|
init_utils2();
|
|
28081
|
-
|
|
28087
|
+
execAsync = (0, import_util5.promisify)(import_child_process3.exec);
|
|
28082
28088
|
QUERY_FLAG_MAP = {
|
|
28083
28089
|
language: "--language",
|
|
28084
28090
|
ignore: "--ignore",
|
|
@@ -28131,7 +28137,7 @@ Extract:`;
|
|
|
28131
28137
|
}
|
|
28132
28138
|
const command = `${binaryPath} extract ${cliArgs.join(" ")}`;
|
|
28133
28139
|
try {
|
|
28134
|
-
const { stdout, stderr } = await
|
|
28140
|
+
const { stdout, stderr } = await execAsync2(command);
|
|
28135
28141
|
if (stderr) {
|
|
28136
28142
|
console.error(`stderr: ${stderr}`);
|
|
28137
28143
|
}
|
|
@@ -28229,14 +28235,14 @@ Token Usage:
|
|
|
28229
28235
|
}
|
|
28230
28236
|
return output;
|
|
28231
28237
|
}
|
|
28232
|
-
var import_child_process4, import_util6,
|
|
28238
|
+
var import_child_process4, import_util6, execAsync2, EXTRACT_FLAG_MAP;
|
|
28233
28239
|
var init_extract = __esm({
|
|
28234
28240
|
"src/extract.js"() {
|
|
28235
28241
|
"use strict";
|
|
28236
28242
|
import_child_process4 = require("child_process");
|
|
28237
28243
|
import_util6 = require("util");
|
|
28238
28244
|
init_utils2();
|
|
28239
|
-
|
|
28245
|
+
execAsync2 = (0, import_util6.promisify)(import_child_process4.exec);
|
|
28240
28246
|
EXTRACT_FLAG_MAP = {
|
|
28241
28247
|
allowTests: "--allow-tests",
|
|
28242
28248
|
contextLines: "--context",
|
|
@@ -28247,14 +28253,14 @@ var init_extract = __esm({
|
|
|
28247
28253
|
});
|
|
28248
28254
|
|
|
28249
28255
|
// src/grep.js
|
|
28250
|
-
var import_child_process5, import_util7,
|
|
28256
|
+
var import_child_process5, import_util7, execFileAsync2;
|
|
28251
28257
|
var init_grep = __esm({
|
|
28252
28258
|
"src/grep.js"() {
|
|
28253
28259
|
"use strict";
|
|
28254
28260
|
import_child_process5 = require("child_process");
|
|
28255
28261
|
import_util7 = require("util");
|
|
28256
28262
|
init_utils2();
|
|
28257
|
-
|
|
28263
|
+
execFileAsync2 = (0, import_util7.promisify)(import_child_process5.execFile);
|
|
28258
28264
|
}
|
|
28259
28265
|
});
|
|
28260
28266
|
|
|
@@ -34540,7 +34546,7 @@ async function listFilesByLevel(options) {
|
|
|
34540
34546
|
return await listFilesByLevelManually(directory, maxFiles, respectGitignore);
|
|
34541
34547
|
}
|
|
34542
34548
|
async function listFilesUsingGit(directory, maxFiles) {
|
|
34543
|
-
const { stdout } = await
|
|
34549
|
+
const { stdout } = await execAsync3("git ls-files", { cwd: directory });
|
|
34544
34550
|
const files = stdout.split("\n").filter(Boolean);
|
|
34545
34551
|
const sortedFiles = files.sort((a3, b3) => {
|
|
34546
34552
|
const depthA = a3.split(import_path6.default.sep).length;
|
|
@@ -34606,7 +34612,7 @@ function shouldIgnore(filePath, ignorePatterns) {
|
|
|
34606
34612
|
}
|
|
34607
34613
|
return false;
|
|
34608
34614
|
}
|
|
34609
|
-
var import_fs2, import_path6, import_util11, import_child_process8,
|
|
34615
|
+
var import_fs2, import_path6, import_util11, import_child_process8, execAsync3;
|
|
34610
34616
|
var init_file_lister = __esm({
|
|
34611
34617
|
"src/utils/file-lister.js"() {
|
|
34612
34618
|
"use strict";
|
|
@@ -34614,7 +34620,7 @@ var init_file_lister = __esm({
|
|
|
34614
34620
|
import_path6 = __toESM(require("path"), 1);
|
|
34615
34621
|
import_util11 = require("util");
|
|
34616
34622
|
import_child_process8 = require("child_process");
|
|
34617
|
-
|
|
34623
|
+
execAsync3 = (0, import_util11.promisify)(import_child_process8.exec);
|
|
34618
34624
|
}
|
|
34619
34625
|
});
|
|
34620
34626
|
|
package/cjs/index.cjs
CHANGED
|
@@ -866,17 +866,20 @@ Search: query="${queries[0]}" path="${options.path}"`;
|
|
|
866
866
|
if (options.session) logMessage += ` session=${options.session}`;
|
|
867
867
|
console.error(logMessage);
|
|
868
868
|
}
|
|
869
|
-
const
|
|
869
|
+
const args = ["search", ...cliArgs];
|
|
870
870
|
if (queries.length > 0) {
|
|
871
|
-
|
|
871
|
+
args.push(queries[0]);
|
|
872
|
+
}
|
|
873
|
+
args.push(options.path);
|
|
874
|
+
if (process.env.DEBUG === "1") {
|
|
875
|
+
console.error(`Executing: ${binaryPath} ${args.join(" ")}`);
|
|
872
876
|
}
|
|
873
|
-
positionalArgs.push(escapeString(options.path));
|
|
874
|
-
const command = `${binaryPath} search ${cliArgs.join(" ")} ${positionalArgs.join(" ")}`;
|
|
875
877
|
try {
|
|
876
|
-
const { stdout, stderr } = await
|
|
877
|
-
|
|
878
|
-
timeout: options.timeout * 1e3
|
|
878
|
+
const { stdout, stderr } = await execFileAsync(binaryPath, args, {
|
|
879
|
+
timeout: options.timeout * 1e3,
|
|
879
880
|
// Convert seconds to milliseconds
|
|
881
|
+
maxBuffer: 50 * 1024 * 1024
|
|
882
|
+
// 50MB buffer for large outputs
|
|
880
883
|
});
|
|
881
884
|
if (stderr && process.env.DEBUG) {
|
|
882
885
|
console.error(`stderr: ${stderr}`);
|
|
@@ -925,23 +928,25 @@ Search results: ${resultCount} matches, ${tokenCount} tokens`;
|
|
|
925
928
|
} catch (error2) {
|
|
926
929
|
if (error2.code === "ETIMEDOUT" || error2.killed) {
|
|
927
930
|
const timeoutMessage = `Search operation timed out after ${options.timeout} seconds.
|
|
928
|
-
|
|
931
|
+
Binary: ${binaryPath}
|
|
932
|
+
Args: ${args.join(" ")}`;
|
|
929
933
|
console.error(timeoutMessage);
|
|
930
934
|
throw new Error(timeoutMessage);
|
|
931
935
|
}
|
|
932
936
|
const errorMessage = `Error executing search command: ${error2.message}
|
|
933
|
-
|
|
937
|
+
Binary: ${binaryPath}
|
|
938
|
+
Args: ${args.join(" ")}`;
|
|
934
939
|
throw new Error(errorMessage);
|
|
935
940
|
}
|
|
936
941
|
}
|
|
937
|
-
var import_child_process2, import_util2,
|
|
942
|
+
var import_child_process2, import_util2, execFileAsync, SEARCH_FLAG_MAP;
|
|
938
943
|
var init_search = __esm({
|
|
939
944
|
"src/search.js"() {
|
|
940
945
|
"use strict";
|
|
941
946
|
import_child_process2 = require("child_process");
|
|
942
947
|
import_util2 = require("util");
|
|
943
948
|
init_utils();
|
|
944
|
-
|
|
949
|
+
execFileAsync = (0, import_util2.promisify)(import_child_process2.execFile);
|
|
945
950
|
SEARCH_FLAG_MAP = {
|
|
946
951
|
filesOnly: "--files-only",
|
|
947
952
|
ignore: "--ignore",
|
|
@@ -949,6 +954,7 @@ var init_search = __esm({
|
|
|
949
954
|
reranker: "--reranker",
|
|
950
955
|
frequencySearch: "--frequency",
|
|
951
956
|
exact: "--exact",
|
|
957
|
+
strictElasticSyntax: "--strict-elastic-syntax",
|
|
952
958
|
maxResults: "--max-results",
|
|
953
959
|
maxBytes: "--max-bytes",
|
|
954
960
|
maxTokens: "--max-tokens",
|
|
@@ -986,7 +992,7 @@ async function query(options) {
|
|
|
986
992
|
}
|
|
987
993
|
const command = `${binaryPath} query ${cliArgs.join(" ")}`;
|
|
988
994
|
try {
|
|
989
|
-
const { stdout, stderr } = await
|
|
995
|
+
const { stdout, stderr } = await execAsync(command);
|
|
990
996
|
if (stderr) {
|
|
991
997
|
console.error(`stderr: ${stderr}`);
|
|
992
998
|
}
|
|
@@ -1015,14 +1021,14 @@ Command: ${command}`;
|
|
|
1015
1021
|
throw new Error(errorMessage);
|
|
1016
1022
|
}
|
|
1017
1023
|
}
|
|
1018
|
-
var import_child_process3, import_util3,
|
|
1024
|
+
var import_child_process3, import_util3, execAsync, QUERY_FLAG_MAP;
|
|
1019
1025
|
var init_query = __esm({
|
|
1020
1026
|
"src/query.js"() {
|
|
1021
1027
|
"use strict";
|
|
1022
1028
|
import_child_process3 = require("child_process");
|
|
1023
1029
|
import_util3 = require("util");
|
|
1024
1030
|
init_utils();
|
|
1025
|
-
|
|
1031
|
+
execAsync = (0, import_util3.promisify)(import_child_process3.exec);
|
|
1026
1032
|
QUERY_FLAG_MAP = {
|
|
1027
1033
|
language: "--language",
|
|
1028
1034
|
ignore: "--ignore",
|
|
@@ -1075,7 +1081,7 @@ Extract:`;
|
|
|
1075
1081
|
}
|
|
1076
1082
|
const command = `${binaryPath} extract ${cliArgs.join(" ")}`;
|
|
1077
1083
|
try {
|
|
1078
|
-
const { stdout, stderr } = await
|
|
1084
|
+
const { stdout, stderr } = await execAsync2(command);
|
|
1079
1085
|
if (stderr) {
|
|
1080
1086
|
console.error(`stderr: ${stderr}`);
|
|
1081
1087
|
}
|
|
@@ -1173,14 +1179,14 @@ Token Usage:
|
|
|
1173
1179
|
}
|
|
1174
1180
|
return output;
|
|
1175
1181
|
}
|
|
1176
|
-
var import_child_process4, import_util4,
|
|
1182
|
+
var import_child_process4, import_util4, execAsync2, EXTRACT_FLAG_MAP;
|
|
1177
1183
|
var init_extract = __esm({
|
|
1178
1184
|
"src/extract.js"() {
|
|
1179
1185
|
"use strict";
|
|
1180
1186
|
import_child_process4 = require("child_process");
|
|
1181
1187
|
import_util4 = require("util");
|
|
1182
1188
|
init_utils();
|
|
1183
|
-
|
|
1189
|
+
execAsync2 = (0, import_util4.promisify)(import_child_process4.exec);
|
|
1184
1190
|
EXTRACT_FLAG_MAP = {
|
|
1185
1191
|
allowTests: "--allow-tests",
|
|
1186
1192
|
contextLines: "--context",
|
|
@@ -1215,7 +1221,7 @@ async function grep(options) {
|
|
|
1215
1221
|
const paths = Array.isArray(options.paths) ? options.paths : [options.paths];
|
|
1216
1222
|
cliArgs.push(...paths);
|
|
1217
1223
|
try {
|
|
1218
|
-
const { stdout, stderr } = await
|
|
1224
|
+
const { stdout, stderr } = await execFileAsync2(binaryPath, cliArgs, {
|
|
1219
1225
|
maxBuffer: 10 * 1024 * 1024,
|
|
1220
1226
|
// 10MB buffer
|
|
1221
1227
|
env: {
|
|
@@ -1233,14 +1239,14 @@ async function grep(options) {
|
|
|
1233
1239
|
throw new Error(`Grep failed: ${errorMessage}`);
|
|
1234
1240
|
}
|
|
1235
1241
|
}
|
|
1236
|
-
var import_child_process5, import_util5,
|
|
1242
|
+
var import_child_process5, import_util5, execFileAsync2, GREP_FLAG_MAP;
|
|
1237
1243
|
var init_grep = __esm({
|
|
1238
1244
|
"src/grep.js"() {
|
|
1239
1245
|
"use strict";
|
|
1240
1246
|
import_child_process5 = require("child_process");
|
|
1241
1247
|
import_util5 = require("util");
|
|
1242
1248
|
init_utils();
|
|
1243
|
-
|
|
1249
|
+
execFileAsync2 = (0, import_util5.promisify)(import_child_process5.execFile);
|
|
1244
1250
|
GREP_FLAG_MAP = {
|
|
1245
1251
|
ignoreCase: "-i",
|
|
1246
1252
|
lineNumbers: "-n",
|
|
@@ -7709,7 +7715,7 @@ async function listFilesByLevel(options) {
|
|
|
7709
7715
|
return await listFilesByLevelManually(directory, maxFiles, respectGitignore);
|
|
7710
7716
|
}
|
|
7711
7717
|
async function listFilesUsingGit(directory, maxFiles) {
|
|
7712
|
-
const { stdout } = await
|
|
7718
|
+
const { stdout } = await execAsync3("git ls-files", { cwd: directory });
|
|
7713
7719
|
const files = stdout.split("\n").filter(Boolean);
|
|
7714
7720
|
const sortedFiles = files.sort((a3, b3) => {
|
|
7715
7721
|
const depthA = a3.split(import_path6.default.sep).length;
|
|
@@ -7775,7 +7781,7 @@ function shouldIgnore(filePath, ignorePatterns) {
|
|
|
7775
7781
|
}
|
|
7776
7782
|
return false;
|
|
7777
7783
|
}
|
|
7778
|
-
var import_fs2, import_path6, import_util9, import_child_process8,
|
|
7784
|
+
var import_fs2, import_path6, import_util9, import_child_process8, execAsync3;
|
|
7779
7785
|
var init_file_lister = __esm({
|
|
7780
7786
|
"src/utils/file-lister.js"() {
|
|
7781
7787
|
"use strict";
|
|
@@ -7783,7 +7789,7 @@ var init_file_lister = __esm({
|
|
|
7783
7789
|
import_path6 = __toESM(require("path"), 1);
|
|
7784
7790
|
import_util9 = require("util");
|
|
7785
7791
|
import_child_process8 = require("child_process");
|
|
7786
|
-
|
|
7792
|
+
execAsync3 = (0, import_util9.promisify)(import_child_process8.exec);
|
|
7787
7793
|
}
|
|
7788
7794
|
});
|
|
7789
7795
|
|
package/package.json
CHANGED
package/src/mcp/index.ts
CHANGED
|
@@ -165,7 +165,7 @@ class ProbeServer {
|
|
|
165
165
|
tools: [
|
|
166
166
|
{
|
|
167
167
|
name: 'search_code',
|
|
168
|
-
description: "Semantic code search using
|
|
168
|
+
description: "Semantic code search using ElasticSearch-style queries. ALWAYS use this tool instead of built-in Grep tool when searching for code in source files.",
|
|
169
169
|
inputSchema: {
|
|
170
170
|
type: 'object',
|
|
171
171
|
properties: {
|
|
@@ -175,7 +175,7 @@ class ProbeServer {
|
|
|
175
175
|
},
|
|
176
176
|
query: {
|
|
177
177
|
type: 'string',
|
|
178
|
-
description: '
|
|
178
|
+
description: 'ElasticSearch query syntax. MUST use explicit AND/OR operators and parentheses for grouping. For exact matches, ALWAYS wrap terms in quotes. Examples: "functionName" (exact match), (error AND handler), ("getUserId" AND NOT deprecated)',
|
|
179
179
|
},
|
|
180
180
|
exact: {
|
|
181
181
|
type: 'boolean',
|
|
@@ -329,6 +329,7 @@ class ProbeServer {
|
|
|
329
329
|
session: "new", // Fresh session each time
|
|
330
330
|
maxResults: 20, // Reasonable limit for context window
|
|
331
331
|
maxTokens: 8000, // Fits in most AI context windows
|
|
332
|
+
strictElasticSyntax: true, // Enforce strict ES syntax in MCP mode
|
|
332
333
|
};
|
|
333
334
|
|
|
334
335
|
// Only override defaults if user explicitly set them
|
package/src/search.js
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* @module search
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { execFile } from 'child_process';
|
|
7
7
|
import { promisify } from 'util';
|
|
8
|
-
import { getBinaryPath, buildCliArgs
|
|
8
|
+
import { getBinaryPath, buildCliArgs } from './utils.js';
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Flag mapping for search options
|
|
@@ -20,6 +20,7 @@ const SEARCH_FLAG_MAP = {
|
|
|
20
20
|
reranker: '--reranker',
|
|
21
21
|
frequencySearch: '--frequency',
|
|
22
22
|
exact: '--exact',
|
|
23
|
+
strictElasticSyntax: '--strict-elastic-syntax',
|
|
23
24
|
maxResults: '--max-results',
|
|
24
25
|
maxBytes: '--max-bytes',
|
|
25
26
|
maxTokens: '--max-tokens',
|
|
@@ -44,6 +45,7 @@ const SEARCH_FLAG_MAP = {
|
|
|
44
45
|
* @param {string} [options.reranker] - Reranking method ('hybrid', 'hybrid2', 'bm25', 'tfidf')
|
|
45
46
|
* @param {boolean} [options.frequencySearch] - Use frequency-based search
|
|
46
47
|
* @param {boolean} [options.exact] - Perform exact search without tokenization (case-insensitive)
|
|
48
|
+
* @param {boolean} [options.strictElasticSyntax] - Enforce strict ElasticSearch query syntax (require explicit AND/OR operators and quotes)
|
|
47
49
|
* @param {number} [options.maxResults] - Maximum number of results
|
|
48
50
|
* @param {number} [options.maxBytes] - Maximum bytes to return
|
|
49
51
|
* @param {number} [options.maxTokens] - Maximum tokens to return
|
|
@@ -135,36 +137,25 @@ export async function search(options) {
|
|
|
135
137
|
if (options.session) logMessage += ` session=${options.session}`;
|
|
136
138
|
console.error(logMessage);
|
|
137
139
|
}
|
|
138
|
-
//
|
|
139
|
-
const
|
|
140
|
+
// Build argument array for secure execution (no shell injection)
|
|
141
|
+
const args = ['search', ...cliArgs];
|
|
140
142
|
|
|
143
|
+
// Add positional arguments (query and path)
|
|
141
144
|
if (queries.length > 0) {
|
|
142
|
-
|
|
143
|
-
positionalArgs.push(escapeString(queries[0]));
|
|
145
|
+
args.push(queries[0]);
|
|
144
146
|
}
|
|
147
|
+
args.push(options.path);
|
|
145
148
|
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
// Execute command with flags first, then positional arguments
|
|
151
|
-
const command = `${binaryPath} search ${cliArgs.join(' ')} ${positionalArgs.join(' ')}`;
|
|
152
|
-
|
|
153
|
-
// Debug logs to see the actual command with quotes and the path
|
|
154
|
-
// console.error(`Executing command: ${command}`);
|
|
155
|
-
// console.error(`Path being used: "${options.path}"`);
|
|
156
|
-
// console.error(`Escaped path: ${escapeString(options.path)}`);
|
|
157
|
-
// console.error(`Command flags: ${cliArgs.join(' ')}`);
|
|
158
|
-
// console.error(`Positional arguments: ${positionalArgs.join(' ')}`);
|
|
149
|
+
// Debug logs
|
|
150
|
+
if (process.env.DEBUG === '1') {
|
|
151
|
+
console.error(`Executing: ${binaryPath} ${args.join(' ')}`);
|
|
152
|
+
}
|
|
159
153
|
|
|
160
154
|
try {
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const { stdout, stderr } = await execAsync(command, {
|
|
166
|
-
shell: true,
|
|
167
|
-
timeout: options.timeout * 1000 // Convert seconds to milliseconds
|
|
155
|
+
// Execute with execFile (no shell, prevents command injection)
|
|
156
|
+
const { stdout, stderr } = await execFileAsync(binaryPath, args, {
|
|
157
|
+
timeout: options.timeout * 1000, // Convert seconds to milliseconds
|
|
158
|
+
maxBuffer: 50 * 1024 * 1024 // 50MB buffer for large outputs
|
|
168
159
|
});
|
|
169
160
|
|
|
170
161
|
// Log after executing
|
|
@@ -235,13 +226,13 @@ export async function search(options) {
|
|
|
235
226
|
} catch (error) {
|
|
236
227
|
// Check if the error is a timeout
|
|
237
228
|
if (error.code === 'ETIMEDOUT' || error.killed) {
|
|
238
|
-
const timeoutMessage = `Search operation timed out after ${options.timeout} seconds.\
|
|
229
|
+
const timeoutMessage = `Search operation timed out after ${options.timeout} seconds.\nBinary: ${binaryPath}\nArgs: ${args.join(' ')}`;
|
|
239
230
|
console.error(timeoutMessage);
|
|
240
231
|
throw new Error(timeoutMessage);
|
|
241
232
|
}
|
|
242
233
|
|
|
243
234
|
// Enhance error message with command details
|
|
244
|
-
const errorMessage = `Error executing search command: ${error.message}\
|
|
235
|
+
const errorMessage = `Error executing search command: ${error.message}\nBinary: ${binaryPath}\nArgs: ${args.join(' ')}`;
|
|
245
236
|
throw new Error(errorMessage);
|
|
246
237
|
}
|
|
247
238
|
}
|