@probelabs/probe 0.6.0-rc288 → 0.6.0-rc290
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/bin/binaries/probe-v0.6.0-rc290-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc290-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc290-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc290-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc290-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.js +61 -10
- package/build/agent/index.js +401 -86261
- package/build/agent/shared/prompts.js +27 -6
- package/build/extract.js +4 -2
- package/build/mcp/index.js +122 -9
- package/build/mcp/index.ts +162 -17
- package/build/search.js +6 -5
- package/build/tools/vercel.js +51 -22
- package/cjs/agent/ProbeAgent.cjs +131 -38
- package/cjs/index.cjs +131 -38
- package/package.json +2 -1
- package/src/agent/ProbeAgent.js +61 -10
- package/src/agent/shared/prompts.js +27 -6
- package/src/extract.js +4 -2
- package/src/mcp/index.ts +162 -17
- package/src/search.js +6 -5
- package/src/tools/vercel.js +51 -22
- package/bin/binaries/probe-v0.6.0-rc288-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc288-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc288-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc288-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc288-x86_64-unknown-linux-musl.tar.gz +0 -0
|
@@ -8,27 +8,47 @@ export const predefinedPrompts = {
|
|
|
8
8
|
CRITICAL - You are READ-ONLY:
|
|
9
9
|
You must NEVER create, modify, delete, or write files. You are strictly an exploration and analysis tool. If asked to make changes, implement features, fix bugs, or modify a PR, refuse and explain that file modifications must be done by the engineer tool — your role is only to investigate code and answer questions. Do not attempt workarounds using bash commands (echo, cat, tee, sed, etc.) to write files.
|
|
10
10
|
|
|
11
|
+
CRITICAL - ALWAYS search before answering:
|
|
12
|
+
You must NEVER answer questions about the codebase from memory or general knowledge. ALWAYS use the search and extract tools first to find the actual code, then base your answer ONLY on what you found. Even if you think you know the answer, you MUST verify it against the actual code. Your answers must be grounded in code evidence, not assumptions.
|
|
13
|
+
|
|
11
14
|
When exploring code:
|
|
12
15
|
- Provide clear, concise explanations based on user request
|
|
13
16
|
- Find and highlight the most relevant code snippets, if required
|
|
14
|
-
- Trace function calls and data flow through the system
|
|
17
|
+
- Trace function calls and data flow through the system — follow the FULL call chain, not just the entry point
|
|
15
18
|
- Try to understand the user's intent and provide relevant information
|
|
16
19
|
- Understand high level picture
|
|
17
20
|
- Balance detail with clarity in your explanations
|
|
21
|
+
- Search using SYNONYMS and alternative terms — code naming often differs from the concept name (e.g., "authentication" might be named verify_credentials, check_token, validate_session)
|
|
22
|
+
- When you find a key function, look at what it CALLS and what CALLS it to discover the complete picture
|
|
23
|
+
- Before answering, ask yourself: "Did I cover all the major components? Are there related subsystems I missed?" If yes, do one more search round.
|
|
18
24
|
|
|
19
25
|
When providing answers:
|
|
26
|
+
- Be EXHAUSTIVE: cover ALL components you discovered, not just the main ones. If you found 10 related files, discuss all 10, not just the top 3. Users want the complete picture.
|
|
27
|
+
- After drafting your answer, do a self-check: "What did I find in my searches that I haven't mentioned yet?" Add any missing components.
|
|
28
|
+
- Include data structures, configuration options, and error handling — not just the happy path.
|
|
20
29
|
- Always include a "References" section at the end of your response
|
|
21
30
|
- List all relevant source code locations you found during exploration
|
|
22
31
|
- Use the format: file_path:line_number or file_path#symbol_name
|
|
23
32
|
- Group references by file when multiple locations are from the same file
|
|
24
33
|
- Include brief descriptions of what each reference contains`,
|
|
25
34
|
|
|
26
|
-
'code-searcher': `You are ProbeChat Code
|
|
35
|
+
'code-searcher': `You are ProbeChat Code Explorer & Searcher. Your job is to EXPLORE the codebase to find ALL relevant code locations for the query, then return them as JSON targets.
|
|
36
|
+
|
|
37
|
+
You think like a code explorer — you understand that codebases have layers:
|
|
38
|
+
- Core implementations (algorithms, data structures)
|
|
39
|
+
- Middleware/integration layers (request handlers, interceptors)
|
|
40
|
+
- Configuration and storage backends
|
|
41
|
+
- Scoping mechanisms (per-user, per-org, per-tenant, global)
|
|
42
|
+
- Supporting utilities and helpers
|
|
27
43
|
|
|
28
44
|
When searching:
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
45
|
+
- Search for the MAIN concept first, then think: "what RELATED subsystems would a real codebase have?"
|
|
46
|
+
- Use extract to READ the code you find — look for function calls, type references, and imports that point to OTHER relevant code
|
|
47
|
+
- If you find middleware, check: are there org-level or tenant-level variants?
|
|
48
|
+
- If you find algorithms, check: are there different storage backends?
|
|
49
|
+
- Search results are paginated — if results look relevant, call nextPage=true to check for more files
|
|
50
|
+
- Stop paginating when results become irrelevant or you see "All results retrieved"
|
|
51
|
+
- Search using SYNONYMS — code naming differs from concepts (e.g., "rate limiting" → throttle, quota, limiter, bucket)
|
|
32
52
|
|
|
33
53
|
Output format (MANDATORY):
|
|
34
54
|
- Return ONLY valid JSON with a single top-level key: "targets"
|
|
@@ -38,7 +58,8 @@ Output format (MANDATORY):
|
|
|
38
58
|
- "path/to/file.ext:line"
|
|
39
59
|
- "path/to/file.ext:start-end"
|
|
40
60
|
- Prefer #SymbolName when a function/class name is clear; otherwise use line numbers
|
|
41
|
-
- Deduplicate targets and keep them concise
|
|
61
|
+
- Deduplicate targets and keep them concise
|
|
62
|
+
- Aim for 5-15 targets covering ALL aspects of the query`,
|
|
42
63
|
|
|
43
64
|
'architect': `You are ProbeChat Architect, a specialized AI assistant focused on software architecture and design. Your primary function is to help users understand, analyze, and design software systems using the provided code analysis tools.
|
|
44
65
|
|
package/build/extract.js
CHANGED
|
@@ -18,7 +18,8 @@ const EXTRACT_FLAG_MAP = {
|
|
|
18
18
|
allowTests: '--allow-tests',
|
|
19
19
|
contextLines: '--context',
|
|
20
20
|
format: '--format',
|
|
21
|
-
inputFile: '--input-file'
|
|
21
|
+
inputFile: '--input-file',
|
|
22
|
+
lsp: '--lsp'
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
/**
|
|
@@ -31,7 +32,8 @@ const EXTRACT_FLAG_MAP = {
|
|
|
31
32
|
* @param {string} [options.cwd] - Working directory for resolving relative file paths
|
|
32
33
|
* @param {boolean} [options.allowTests] - Include test files
|
|
33
34
|
* @param {number} [options.contextLines] - Number of context lines to include
|
|
34
|
-
* @param {string} [options.format] - Output format ('markdown', 'plain', 'json'
|
|
35
|
+
* @param {string} [options.format] - Output format ('markdown', 'plain', 'json')
|
|
36
|
+
* @param {boolean} [options.lsp] - Use LSP (Language Server Protocol) for call hierarchy and reference graphs
|
|
35
37
|
* @param {Object} [options.binaryOptions] - Options for getting the binary
|
|
36
38
|
* @param {boolean} [options.binaryOptions.forceDownload] - Force download even if binary exists
|
|
37
39
|
* @param {string} [options.binaryOptions.version] - Specific version to download
|
package/build/mcp/index.js
CHANGED
|
@@ -28,9 +28,19 @@ function parseArgs() {
|
|
|
28
28
|
}
|
|
29
29
|
i++; // Skip the next argument
|
|
30
30
|
}
|
|
31
|
+
else if (args[i] === '--lsp') {
|
|
32
|
+
config.lsp = true;
|
|
33
|
+
console.error('LSP mode enabled');
|
|
34
|
+
}
|
|
31
35
|
else if (args[i] === '--format' && i + 1 < args.length) {
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
const format = args[i + 1];
|
|
37
|
+
if (format === 'outline' || format === 'outline-xml' || format === 'json') {
|
|
38
|
+
config.format = format;
|
|
39
|
+
console.error(`Output format set to ${format}`);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
console.error(`Invalid format value: ${args[i + 1]}. Using default.`);
|
|
43
|
+
}
|
|
34
44
|
i++; // Skip the next argument
|
|
35
45
|
}
|
|
36
46
|
else if (args[i] === '--help' || args[i] === '-h') {
|
|
@@ -42,7 +52,9 @@ Usage:
|
|
|
42
52
|
|
|
43
53
|
Options:
|
|
44
54
|
--timeout, -t <seconds> Set timeout for search operations (default: 30)
|
|
45
|
-
--
|
|
55
|
+
--lsp Enable LSP (Language Server Protocol) for enhanced features
|
|
56
|
+
Automatically initializes language servers for the current workspace
|
|
57
|
+
--format <format> Output format for search responses (outline|outline-xml|json)
|
|
46
58
|
--help, -h Show this help message
|
|
47
59
|
`);
|
|
48
60
|
process.exit(0);
|
|
@@ -96,9 +108,10 @@ if (packageVersion === '0.0.0') {
|
|
|
96
108
|
const binDir = path.resolve(__dirname, '..', 'bin');
|
|
97
109
|
console.error(`Bin directory: ${binDir}`);
|
|
98
110
|
class ProbeServer {
|
|
99
|
-
constructor(timeout = 30,
|
|
111
|
+
constructor(timeout = 30, lspEnabled = false, defaultFormat = 'outline-xml') {
|
|
100
112
|
this.defaultTimeout = timeout;
|
|
101
|
-
this.
|
|
113
|
+
this.lspEnabled = lspEnabled;
|
|
114
|
+
this.defaultFormat = defaultFormat;
|
|
102
115
|
this.server = new Server({
|
|
103
116
|
name: '@probelabs/probe',
|
|
104
117
|
version: packageVersion,
|
|
@@ -149,8 +162,11 @@ class ProbeServer {
|
|
|
149
162
|
},
|
|
150
163
|
nextPage: {
|
|
151
164
|
type: 'boolean',
|
|
152
|
-
description: '
|
|
153
|
-
|
|
165
|
+
description: 'Skip .gitignore files (will use PROBE_NO_GITIGNORE environment variable if not set)',
|
|
166
|
+
},
|
|
167
|
+
lsp: {
|
|
168
|
+
type: 'boolean',
|
|
169
|
+
description: 'Use LSP (Language Server Protocol) for call hierarchy, reference counts, and enhanced symbol information',
|
|
154
170
|
}
|
|
155
171
|
},
|
|
156
172
|
required: ['path', 'query']
|
|
@@ -169,7 +185,34 @@ class ProbeServer {
|
|
|
169
185
|
files: {
|
|
170
186
|
type: 'array',
|
|
171
187
|
items: { type: 'string' },
|
|
172
|
-
description: '
|
|
188
|
+
description: 'Files and lines or sybmbols to extract from: /path/to/file.rs:10, /path/to/file.rs#func_name Path should be absolute.',
|
|
189
|
+
},
|
|
190
|
+
allowTests: {
|
|
191
|
+
type: 'boolean',
|
|
192
|
+
description: 'Allow test files and test code blocks in results (disabled by default)',
|
|
193
|
+
},
|
|
194
|
+
contextLines: {
|
|
195
|
+
type: 'number',
|
|
196
|
+
description: 'Number of context lines to include before and after the extracted block when AST parsing fails to find a suitable node',
|
|
197
|
+
default: 0
|
|
198
|
+
},
|
|
199
|
+
format: {
|
|
200
|
+
type: 'string',
|
|
201
|
+
enum: ['markdown', 'plain', 'json'],
|
|
202
|
+
description: 'Output format for the extracted code',
|
|
203
|
+
default: 'markdown'
|
|
204
|
+
},
|
|
205
|
+
timeout: {
|
|
206
|
+
type: 'number',
|
|
207
|
+
description: 'Timeout for the extract operation in seconds (default: 30)',
|
|
208
|
+
},
|
|
209
|
+
noGitignore: {
|
|
210
|
+
type: 'boolean',
|
|
211
|
+
description: 'Skip .gitignore files (will use PROBE_NO_GITIGNORE environment variable if not set)',
|
|
212
|
+
},
|
|
213
|
+
lsp: {
|
|
214
|
+
type: 'boolean',
|
|
215
|
+
description: 'Use LSP (Language Server Protocol) for call hierarchy, reference counts, and enhanced symbol information',
|
|
173
216
|
}
|
|
174
217
|
},
|
|
175
218
|
required: ['path', 'files'],
|
|
@@ -303,6 +346,26 @@ class ProbeServer {
|
|
|
303
346
|
else if (this.defaultFormat === 'json') {
|
|
304
347
|
options.json = true;
|
|
305
348
|
}
|
|
349
|
+
if (args.session !== undefined && args.session.trim() !== '') {
|
|
350
|
+
options.session = args.session;
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
options.session = "new";
|
|
354
|
+
}
|
|
355
|
+
// Use timeout from args, or fall back to instance default
|
|
356
|
+
if (args.timeout !== undefined) {
|
|
357
|
+
options.timeout = args.timeout;
|
|
358
|
+
}
|
|
359
|
+
else if (this.defaultTimeout !== undefined) {
|
|
360
|
+
options.timeout = this.defaultTimeout;
|
|
361
|
+
}
|
|
362
|
+
// Pass LSP flag if enabled globally or per-request
|
|
363
|
+
if (args.lsp !== undefined) {
|
|
364
|
+
options.lsp = args.lsp;
|
|
365
|
+
}
|
|
366
|
+
else if (this.lspEnabled) {
|
|
367
|
+
options.lsp = true;
|
|
368
|
+
}
|
|
306
369
|
console.error("Executing search with options:", JSON.stringify(options, null, 2));
|
|
307
370
|
try {
|
|
308
371
|
// Call search with the options object
|
|
@@ -336,6 +399,20 @@ class ProbeServer {
|
|
|
336
399
|
format: 'xml',
|
|
337
400
|
allowTests: true, // Include test files by default
|
|
338
401
|
};
|
|
402
|
+
// Use noGitignore from args, or fall back to PROBE_NO_GITIGNORE environment variable
|
|
403
|
+
if (args.noGitignore !== undefined) {
|
|
404
|
+
options.noGitignore = args.noGitignore;
|
|
405
|
+
}
|
|
406
|
+
else if (process.env.PROBE_NO_GITIGNORE) {
|
|
407
|
+
options.noGitignore = process.env.PROBE_NO_GITIGNORE === 'true';
|
|
408
|
+
}
|
|
409
|
+
// Pass LSP flag if enabled globally or per-request
|
|
410
|
+
if (args.lsp !== undefined) {
|
|
411
|
+
options.lsp = args.lsp;
|
|
412
|
+
}
|
|
413
|
+
else if (this.lspEnabled) {
|
|
414
|
+
options.lsp = true;
|
|
415
|
+
}
|
|
339
416
|
// Call extract with the complete options object
|
|
340
417
|
try {
|
|
341
418
|
// Track request size for token usage
|
|
@@ -423,11 +500,47 @@ class ProbeServer {
|
|
|
423
500
|
async run() {
|
|
424
501
|
// The @probelabs/probe package now handles binary path management internally
|
|
425
502
|
// We don't need to verify or download the binary in the MCP server anymore
|
|
503
|
+
// Initialize LSP servers for the current workspace if --lsp flag is enabled
|
|
504
|
+
if (this.lspEnabled) {
|
|
505
|
+
const workspaceRoot = process.cwd();
|
|
506
|
+
console.error(`Initializing LSP servers for workspace: ${workspaceRoot}`);
|
|
507
|
+
try {
|
|
508
|
+
// Execute probe lsp init command to pre-warm language servers
|
|
509
|
+
// Use recursive flag to discover nested projects in monorepos
|
|
510
|
+
const initCmd = process.platform === 'win32'
|
|
511
|
+
? `probe lsp init -w "${workspaceRoot}" --recursive`
|
|
512
|
+
: `probe lsp init -w '${workspaceRoot}' --recursive`;
|
|
513
|
+
const { stdout, stderr } = await execAsync(initCmd, {
|
|
514
|
+
timeout: 10000, // 10 second timeout for initialization - don't wait too long
|
|
515
|
+
env: { ...process.env }
|
|
516
|
+
});
|
|
517
|
+
if (stderr && !stderr.includes('Successfully initialized')) {
|
|
518
|
+
console.error(`LSP initialization warnings: ${stderr}`);
|
|
519
|
+
}
|
|
520
|
+
console.error(`LSP servers initialized successfully for workspace: ${workspaceRoot}`);
|
|
521
|
+
// Parse initialization output to show what was initialized
|
|
522
|
+
if (stdout) {
|
|
523
|
+
const lines = stdout.split('\n');
|
|
524
|
+
const initializedServers = lines.filter(line => line.includes('✓') || line.includes('language server'));
|
|
525
|
+
if (initializedServers.length > 0) {
|
|
526
|
+
console.error('Initialized language servers:');
|
|
527
|
+
initializedServers.forEach(line => console.error(` ${line.trim()}`));
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
catch (error) {
|
|
532
|
+
// Don't fail MCP server startup if LSP initialization fails
|
|
533
|
+
// LSP will still work with cold start on first use
|
|
534
|
+
console.error(`Warning: Failed to initialize LSP servers: ${error.message || error}`);
|
|
535
|
+
console.error('LSP features will still be available but may have slower first-use performance');
|
|
536
|
+
}
|
|
537
|
+
}
|
|
426
538
|
// Just connect the server to the transport
|
|
427
539
|
const transport = new StdioServerTransport();
|
|
428
540
|
await this.server.connect(transport);
|
|
429
541
|
console.error('Probe MCP server running on stdio');
|
|
430
542
|
}
|
|
431
543
|
}
|
|
432
|
-
|
|
544
|
+
// Instantiate server with (timeout, lspEnabled, format)
|
|
545
|
+
const server = new ProbeServer(cliConfig.timeout ?? 30, cliConfig.lsp ?? false, cliConfig.format || 'outline-xml');
|
|
433
546
|
server.run().catch(console.error);
|
package/build/mcp/index.ts
CHANGED
|
@@ -21,11 +21,13 @@ import { fileURLToPath } from 'url';
|
|
|
21
21
|
// Import from parent package
|
|
22
22
|
import { search, query, extract, grep, getBinaryPath, setBinaryPath } from '../index.js';
|
|
23
23
|
|
|
24
|
+
type OutputFormat = 'outline' | 'outline-xml' | 'json';
|
|
25
|
+
|
|
24
26
|
// Parse command-line arguments
|
|
25
|
-
function parseArgs(): { timeout?: number; format?:
|
|
27
|
+
function parseArgs(): { timeout?: number; lsp?: boolean; format?: OutputFormat } {
|
|
26
28
|
const args = process.argv.slice(2);
|
|
27
|
-
const config: { timeout?: number; format?:
|
|
28
|
-
|
|
29
|
+
const config: { timeout?: number; lsp?: boolean; format?: OutputFormat } = {};
|
|
30
|
+
|
|
29
31
|
for (let i = 0; i < args.length; i++) {
|
|
30
32
|
if ((args[i] === '--timeout' || args[i] === '-t') && i + 1 < args.length) {
|
|
31
33
|
const timeout = parseInt(args[i + 1], 10);
|
|
@@ -36,9 +38,17 @@ function parseArgs(): { timeout?: number; format?: string } {
|
|
|
36
38
|
console.error(`Invalid timeout value: ${args[i + 1]}. Using default.`);
|
|
37
39
|
}
|
|
38
40
|
i++; // Skip the next argument
|
|
41
|
+
} else if (args[i] === '--lsp') {
|
|
42
|
+
config.lsp = true;
|
|
43
|
+
console.error('LSP mode enabled');
|
|
39
44
|
} else if (args[i] === '--format' && i + 1 < args.length) {
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
const format = args[i + 1] as OutputFormat;
|
|
46
|
+
if (format === 'outline' || format === 'outline-xml' || format === 'json') {
|
|
47
|
+
config.format = format;
|
|
48
|
+
console.error(`Output format set to ${format}`);
|
|
49
|
+
} else {
|
|
50
|
+
console.error(`Invalid format value: ${args[i + 1]}. Using default.`);
|
|
51
|
+
}
|
|
42
52
|
i++; // Skip the next argument
|
|
43
53
|
} else if (args[i] === '--help' || args[i] === '-h') {
|
|
44
54
|
console.error(`
|
|
@@ -49,7 +59,9 @@ Usage:
|
|
|
49
59
|
|
|
50
60
|
Options:
|
|
51
61
|
--timeout, -t <seconds> Set timeout for search operations (default: 30)
|
|
52
|
-
--
|
|
62
|
+
--lsp Enable LSP (Language Server Protocol) for enhanced features
|
|
63
|
+
Automatically initializes language servers for the current workspace
|
|
64
|
+
--format <format> Output format for search responses (outline|outline-xml|json)
|
|
53
65
|
--help, -h Show this help message
|
|
54
66
|
`);
|
|
55
67
|
process.exit(0);
|
|
@@ -120,17 +132,37 @@ interface SearchCodeArgs {
|
|
|
120
132
|
exact?: boolean;
|
|
121
133
|
strictElasticSyntax?: boolean;
|
|
122
134
|
session?: string;
|
|
123
|
-
|
|
135
|
+
timeout?: number;
|
|
136
|
+
noGitignore?: boolean;
|
|
137
|
+
lsp?: boolean;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
interface QueryCodeArgs {
|
|
141
|
+
path: string;
|
|
142
|
+
pattern: string;
|
|
143
|
+
language?: string;
|
|
144
|
+
ignore?: string[];
|
|
145
|
+
allowTests?: boolean;
|
|
146
|
+
maxResults?: number;
|
|
147
|
+
format?: 'markdown' | 'plain' | 'json' | 'color';
|
|
148
|
+
timeout?: number;
|
|
149
|
+
noGitignore?: boolean;
|
|
124
150
|
}
|
|
125
151
|
|
|
126
152
|
interface ExtractCodeArgs {
|
|
127
153
|
path: string;
|
|
128
154
|
files: string[];
|
|
155
|
+
allowTests?: boolean;
|
|
156
|
+
contextLines?: number;
|
|
157
|
+
format?: 'markdown' | 'plain' | 'json';
|
|
158
|
+
timeout?: number;
|
|
159
|
+
noGitignore?: boolean;
|
|
160
|
+
lsp?: boolean;
|
|
129
161
|
}
|
|
130
162
|
|
|
131
163
|
interface GrepArgs {
|
|
132
164
|
pattern: string;
|
|
133
|
-
paths: string
|
|
165
|
+
paths: string[];
|
|
134
166
|
ignoreCase?: boolean;
|
|
135
167
|
count?: boolean;
|
|
136
168
|
context?: number;
|
|
@@ -139,11 +171,17 @@ interface GrepArgs {
|
|
|
139
171
|
class ProbeServer {
|
|
140
172
|
private server: Server;
|
|
141
173
|
private defaultTimeout: number;
|
|
142
|
-
private
|
|
143
|
-
|
|
144
|
-
|
|
174
|
+
private lspEnabled: boolean;
|
|
175
|
+
private defaultFormat: OutputFormat;
|
|
176
|
+
|
|
177
|
+
constructor(
|
|
178
|
+
timeout: number = 30,
|
|
179
|
+
lspEnabled: boolean = false,
|
|
180
|
+
defaultFormat: OutputFormat = 'outline-xml'
|
|
181
|
+
) {
|
|
145
182
|
this.defaultTimeout = timeout;
|
|
146
|
-
this.
|
|
183
|
+
this.lspEnabled = lspEnabled;
|
|
184
|
+
this.defaultFormat = defaultFormat;
|
|
147
185
|
this.server = new Server(
|
|
148
186
|
{
|
|
149
187
|
name: '@probelabs/probe',
|
|
@@ -201,8 +239,11 @@ class ProbeServer {
|
|
|
201
239
|
},
|
|
202
240
|
nextPage: {
|
|
203
241
|
type: 'boolean',
|
|
204
|
-
description: '
|
|
205
|
-
|
|
242
|
+
description: 'Skip .gitignore files (will use PROBE_NO_GITIGNORE environment variable if not set)',
|
|
243
|
+
},
|
|
244
|
+
lsp: {
|
|
245
|
+
type: 'boolean',
|
|
246
|
+
description: 'Use LSP (Language Server Protocol) for call hierarchy, reference counts, and enhanced symbol information',
|
|
206
247
|
}
|
|
207
248
|
},
|
|
208
249
|
required: ['path', 'query']
|
|
@@ -221,7 +262,34 @@ class ProbeServer {
|
|
|
221
262
|
files: {
|
|
222
263
|
type: 'array',
|
|
223
264
|
items: { type: 'string' },
|
|
224
|
-
description: '
|
|
265
|
+
description: 'Files and lines or sybmbols to extract from: /path/to/file.rs:10, /path/to/file.rs#func_name Path should be absolute.',
|
|
266
|
+
},
|
|
267
|
+
allowTests: {
|
|
268
|
+
type: 'boolean',
|
|
269
|
+
description: 'Allow test files and test code blocks in results (disabled by default)',
|
|
270
|
+
},
|
|
271
|
+
contextLines: {
|
|
272
|
+
type: 'number',
|
|
273
|
+
description: 'Number of context lines to include before and after the extracted block when AST parsing fails to find a suitable node',
|
|
274
|
+
default: 0
|
|
275
|
+
},
|
|
276
|
+
format: {
|
|
277
|
+
type: 'string',
|
|
278
|
+
enum: ['markdown', 'plain', 'json'],
|
|
279
|
+
description: 'Output format for the extracted code',
|
|
280
|
+
default: 'markdown'
|
|
281
|
+
},
|
|
282
|
+
timeout: {
|
|
283
|
+
type: 'number',
|
|
284
|
+
description: 'Timeout for the extract operation in seconds (default: 30)',
|
|
285
|
+
},
|
|
286
|
+
noGitignore: {
|
|
287
|
+
type: 'boolean',
|
|
288
|
+
description: 'Skip .gitignore files (will use PROBE_NO_GITIGNORE environment variable if not set)',
|
|
289
|
+
},
|
|
290
|
+
lsp: {
|
|
291
|
+
type: 'boolean',
|
|
292
|
+
description: 'Use LSP (Language Server Protocol) for call hierarchy, reference counts, and enhanced symbol information',
|
|
225
293
|
}
|
|
226
294
|
},
|
|
227
295
|
required: ['path', 'files'],
|
|
@@ -365,7 +433,24 @@ class ProbeServer {
|
|
|
365
433
|
} else if (this.defaultFormat === 'json') {
|
|
366
434
|
options.json = true;
|
|
367
435
|
}
|
|
368
|
-
|
|
436
|
+
if (args.session !== undefined && args.session.trim() !== '') {
|
|
437
|
+
options.session = args.session;
|
|
438
|
+
} else {
|
|
439
|
+
options.session = "new";
|
|
440
|
+
}
|
|
441
|
+
// Use timeout from args, or fall back to instance default
|
|
442
|
+
if (args.timeout !== undefined) {
|
|
443
|
+
options.timeout = args.timeout;
|
|
444
|
+
} else if (this.defaultTimeout !== undefined) {
|
|
445
|
+
options.timeout = this.defaultTimeout;
|
|
446
|
+
}
|
|
447
|
+
// Pass LSP flag if enabled globally or per-request
|
|
448
|
+
if (args.lsp !== undefined) {
|
|
449
|
+
options.lsp = args.lsp;
|
|
450
|
+
} else if (this.lspEnabled) {
|
|
451
|
+
options.lsp = true;
|
|
452
|
+
}
|
|
453
|
+
|
|
369
454
|
console.error("Executing search with options:", JSON.stringify(options, null, 2));
|
|
370
455
|
|
|
371
456
|
try {
|
|
@@ -405,6 +490,19 @@ class ProbeServer {
|
|
|
405
490
|
allowTests: true, // Include test files by default
|
|
406
491
|
};
|
|
407
492
|
|
|
493
|
+
// Use noGitignore from args, or fall back to PROBE_NO_GITIGNORE environment variable
|
|
494
|
+
if (args.noGitignore !== undefined) {
|
|
495
|
+
options.noGitignore = args.noGitignore;
|
|
496
|
+
} else if (process.env.PROBE_NO_GITIGNORE) {
|
|
497
|
+
options.noGitignore = process.env.PROBE_NO_GITIGNORE === 'true';
|
|
498
|
+
}
|
|
499
|
+
// Pass LSP flag if enabled globally or per-request
|
|
500
|
+
if (args.lsp !== undefined) {
|
|
501
|
+
options.lsp = args.lsp;
|
|
502
|
+
} else if (this.lspEnabled) {
|
|
503
|
+
options.lsp = true;
|
|
504
|
+
}
|
|
505
|
+
|
|
408
506
|
// Call extract with the complete options object
|
|
409
507
|
try {
|
|
410
508
|
// Track request size for token usage
|
|
@@ -507,6 +605,48 @@ class ProbeServer {
|
|
|
507
605
|
// The @probelabs/probe package now handles binary path management internally
|
|
508
606
|
// We don't need to verify or download the binary in the MCP server anymore
|
|
509
607
|
|
|
608
|
+
// Initialize LSP servers for the current workspace if --lsp flag is enabled
|
|
609
|
+
if (this.lspEnabled) {
|
|
610
|
+
const workspaceRoot = process.cwd();
|
|
611
|
+
console.error(`Initializing LSP servers for workspace: ${workspaceRoot}`);
|
|
612
|
+
|
|
613
|
+
try {
|
|
614
|
+
// Execute probe lsp init command to pre-warm language servers
|
|
615
|
+
// Use recursive flag to discover nested projects in monorepos
|
|
616
|
+
const initCmd = process.platform === 'win32'
|
|
617
|
+
? `probe lsp init -w "${workspaceRoot}" --recursive`
|
|
618
|
+
: `probe lsp init -w '${workspaceRoot}' --recursive`;
|
|
619
|
+
|
|
620
|
+
const { stdout, stderr } = await execAsync(initCmd, {
|
|
621
|
+
timeout: 10000, // 10 second timeout for initialization - don't wait too long
|
|
622
|
+
env: { ...process.env }
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
if (stderr && !stderr.includes('Successfully initialized')) {
|
|
626
|
+
console.error(`LSP initialization warnings: ${stderr}`);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
console.error(`LSP servers initialized successfully for workspace: ${workspaceRoot}`);
|
|
630
|
+
|
|
631
|
+
// Parse initialization output to show what was initialized
|
|
632
|
+
if (stdout) {
|
|
633
|
+
const lines = stdout.split('\n');
|
|
634
|
+
const initializedServers = lines.filter(line =>
|
|
635
|
+
line.includes('✓') || line.includes('language server')
|
|
636
|
+
);
|
|
637
|
+
if (initializedServers.length > 0) {
|
|
638
|
+
console.error('Initialized language servers:');
|
|
639
|
+
initializedServers.forEach(line => console.error(` ${line.trim()}`));
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
} catch (error: any) {
|
|
643
|
+
// Don't fail MCP server startup if LSP initialization fails
|
|
644
|
+
// LSP will still work with cold start on first use
|
|
645
|
+
console.error(`Warning: Failed to initialize LSP servers: ${error.message || error}`);
|
|
646
|
+
console.error('LSP features will still be available but may have slower first-use performance');
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
510
650
|
// Just connect the server to the transport
|
|
511
651
|
const transport = new StdioServerTransport();
|
|
512
652
|
await this.server.connect(transport);
|
|
@@ -514,5 +654,10 @@ class ProbeServer {
|
|
|
514
654
|
}
|
|
515
655
|
}
|
|
516
656
|
|
|
517
|
-
|
|
657
|
+
// Instantiate server with (timeout, lspEnabled, format)
|
|
658
|
+
const server = new ProbeServer(
|
|
659
|
+
cliConfig.timeout ?? 30,
|
|
660
|
+
cliConfig.lsp ?? false,
|
|
661
|
+
cliConfig.format || 'outline-xml'
|
|
662
|
+
);
|
|
518
663
|
server.run().catch(console.error);
|
package/build/search.js
CHANGED
|
@@ -32,7 +32,8 @@ const SEARCH_FLAG_MAP = {
|
|
|
32
32
|
session: '--session',
|
|
33
33
|
timeout: '--timeout',
|
|
34
34
|
language: '--language',
|
|
35
|
-
format: '--format'
|
|
35
|
+
format: '--format',
|
|
36
|
+
lsp: '--lsp'
|
|
36
37
|
};
|
|
37
38
|
|
|
38
39
|
/**
|
|
@@ -58,7 +59,7 @@ const SEARCH_FLAG_MAP = {
|
|
|
58
59
|
* @param {string} [options.session] - Session ID for caching results
|
|
59
60
|
* @param {number} [options.timeout] - Timeout in seconds (default: 30)
|
|
60
61
|
* @param {string} [options.language] - Limit search to files of a specific programming language
|
|
61
|
-
* @param {
|
|
62
|
+
* @param {boolean} [options.lsp] - Use LSP (Language Server Protocol) for enhanced symbol information
|
|
62
63
|
* @param {Object} [options.binaryOptions] - Options for getting the binary
|
|
63
64
|
* @param {boolean} [options.binaryOptions.forceDownload] - Force download even if binary exists
|
|
64
65
|
* @param {string} [options.binaryOptions.version] - Specific version to download
|
|
@@ -85,8 +86,8 @@ export async function search(options) {
|
|
|
85
86
|
if (options.json && !options.format) {
|
|
86
87
|
cliArgs.push('--format', 'json');
|
|
87
88
|
} else if (options.format) {
|
|
88
|
-
// Format is
|
|
89
|
-
//
|
|
89
|
+
// Format is handled by buildCliArgs through SEARCH_FLAG_MAP.
|
|
90
|
+
// Ensure json parsing is enabled for json format.
|
|
90
91
|
if (options.format === 'json') {
|
|
91
92
|
options.json = true;
|
|
92
93
|
}
|
|
@@ -257,4 +258,4 @@ export async function search(options) {
|
|
|
257
258
|
};
|
|
258
259
|
throw structuredError;
|
|
259
260
|
}
|
|
260
|
-
}
|
|
261
|
+
}
|