@probelabs/probe 0.6.0-rc100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +583 -0
- package/bin/.gitkeep +0 -0
- package/bin/probe +158 -0
- package/bin/probe-binary +0 -0
- package/build/agent/ProbeAgent.d.ts +199 -0
- package/build/agent/ProbeAgent.js +1486 -0
- package/build/agent/acp/README.md +347 -0
- package/build/agent/acp/connection.js +237 -0
- package/build/agent/acp/connection.test.js +311 -0
- package/build/agent/acp/examples/simple-client.js +212 -0
- package/build/agent/acp/examples/tool-lifecycle.js +230 -0
- package/build/agent/acp/final-test.js +173 -0
- package/build/agent/acp/index.js +5 -0
- package/build/agent/acp/integration.test.js +385 -0
- package/build/agent/acp/manual-test.js +410 -0
- package/build/agent/acp/protocol-test.js +190 -0
- package/build/agent/acp/server.js +448 -0
- package/build/agent/acp/server.test.js +371 -0
- package/build/agent/acp/test-runner.js +216 -0
- package/build/agent/acp/test-utils/README.md +315 -0
- package/build/agent/acp/test-utils/acp-tester.js +484 -0
- package/build/agent/acp/test-utils/mock-acp-client.js +434 -0
- package/build/agent/acp/tools.js +368 -0
- package/build/agent/acp/tools.test.js +334 -0
- package/build/agent/acp/types.js +218 -0
- package/build/agent/acp/types.test.js +327 -0
- package/build/agent/appTracer.js +360 -0
- package/build/agent/fileSpanExporter.js +169 -0
- package/build/agent/index.js +7426 -0
- package/build/agent/mcp/client.js +338 -0
- package/build/agent/mcp/config.js +313 -0
- package/build/agent/mcp/index.js +64 -0
- package/build/agent/mcp/xmlBridge.js +371 -0
- package/build/agent/mockProvider.js +53 -0
- package/build/agent/probeTool.js +257 -0
- package/build/agent/schemaUtils.js +1726 -0
- package/build/agent/simpleTelemetry.js +267 -0
- package/build/agent/telemetry.js +225 -0
- package/build/agent/tokenCounter.js +395 -0
- package/build/agent/tools.js +163 -0
- package/build/cli.js +49 -0
- package/build/delegate.js +267 -0
- package/build/directory-resolver.js +237 -0
- package/build/downloader.js +750 -0
- package/build/extract.js +149 -0
- package/build/index.js +70 -0
- package/build/mcp/index.js +514 -0
- package/build/mcp/index.ts +608 -0
- package/build/query.js +116 -0
- package/build/search.js +247 -0
- package/build/tools/common.js +410 -0
- package/build/tools/index.js +40 -0
- package/build/tools/langchain.js +88 -0
- package/build/tools/system-message.js +121 -0
- package/build/tools/vercel.js +271 -0
- package/build/utils/file-lister.js +193 -0
- package/build/utils.js +128 -0
- package/cjs/agent/ProbeAgent.cjs +5829 -0
- package/cjs/index.cjs +6217 -0
- package/cjs/package.json +3 -0
- package/index.d.ts +401 -0
- package/package.json +114 -0
- package/scripts/postinstall.js +172 -0
- package/src/agent/ProbeAgent.d.ts +199 -0
- package/src/agent/ProbeAgent.js +1486 -0
- package/src/agent/acp/README.md +347 -0
- package/src/agent/acp/connection.js +237 -0
- package/src/agent/acp/connection.test.js +311 -0
- package/src/agent/acp/examples/simple-client.js +212 -0
- package/src/agent/acp/examples/tool-lifecycle.js +230 -0
- package/src/agent/acp/final-test.js +173 -0
- package/src/agent/acp/index.js +5 -0
- package/src/agent/acp/integration.test.js +385 -0
- package/src/agent/acp/manual-test.js +410 -0
- package/src/agent/acp/protocol-test.js +190 -0
- package/src/agent/acp/server.js +448 -0
- package/src/agent/acp/server.test.js +371 -0
- package/src/agent/acp/test-runner.js +216 -0
- package/src/agent/acp/test-utils/README.md +315 -0
- package/src/agent/acp/test-utils/acp-tester.js +484 -0
- package/src/agent/acp/test-utils/mock-acp-client.js +434 -0
- package/src/agent/acp/tools.js +368 -0
- package/src/agent/acp/tools.test.js +334 -0
- package/src/agent/acp/types.js +218 -0
- package/src/agent/acp/types.test.js +327 -0
- package/src/agent/appTracer.js +360 -0
- package/src/agent/fileSpanExporter.js +169 -0
- package/src/agent/index.js +813 -0
- package/src/agent/mcp/client.js +338 -0
- package/src/agent/mcp/config.js +313 -0
- package/src/agent/mcp/index.js +64 -0
- package/src/agent/mcp/xmlBridge.js +371 -0
- package/src/agent/mockProvider.js +53 -0
- package/src/agent/probeTool.js +257 -0
- package/src/agent/schemaUtils.js +1726 -0
- package/src/agent/simpleTelemetry.js +267 -0
- package/src/agent/telemetry.js +225 -0
- package/src/agent/tokenCounter.js +395 -0
- package/src/agent/tools.js +163 -0
- package/src/cli.js +49 -0
- package/src/delegate.js +267 -0
- package/src/directory-resolver.js +237 -0
- package/src/downloader.js +750 -0
- package/src/extract.js +149 -0
- package/src/index.js +70 -0
- package/src/mcp/index.ts +608 -0
- package/src/query.js +116 -0
- package/src/search.js +247 -0
- package/src/tools/common.js +410 -0
- package/src/tools/index.js +40 -0
- package/src/tools/langchain.js +88 -0
- package/src/tools/system-message.js +121 -0
- package/src/tools/vercel.js +271 -0
- package/src/utils/file-lister.js +193 -0
- package/src/utils.js +128 -0
package/src/query.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query functionality for the probe package
|
|
3
|
+
* @module query
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { exec } from 'child_process';
|
|
7
|
+
import { promisify } from 'util';
|
|
8
|
+
import { getBinaryPath, buildCliArgs, escapeString } from './utils.js';
|
|
9
|
+
|
|
10
|
+
const execAsync = promisify(exec);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Flag mapping for query options
|
|
14
|
+
* Maps option keys to command-line flags
|
|
15
|
+
*/
|
|
16
|
+
const QUERY_FLAG_MAP = {
|
|
17
|
+
language: '--language',
|
|
18
|
+
ignore: '--ignore',
|
|
19
|
+
allowTests: '--allow-tests',
|
|
20
|
+
maxResults: '--max-results',
|
|
21
|
+
format: '--format'
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Query code in a specified directory using tree-sitter patterns
|
|
26
|
+
*
|
|
27
|
+
* @param {Object} options - Query options
|
|
28
|
+
* @param {string} options.path - Path to search in
|
|
29
|
+
* @param {string} options.pattern - The ast-grep pattern to search for
|
|
30
|
+
* @param {string} [options.language] - Programming language to search in
|
|
31
|
+
* @param {string[]} [options.ignore] - Patterns to ignore
|
|
32
|
+
* @param {boolean} [options.allowTests] - Include test files
|
|
33
|
+
* @param {number} [options.maxResults] - Maximum number of results
|
|
34
|
+
* @param {string} [options.format] - Output format ('markdown', 'plain', 'json', 'color')
|
|
35
|
+
* @param {Object} [options.binaryOptions] - Options for getting the binary
|
|
36
|
+
* @param {boolean} [options.binaryOptions.forceDownload] - Force download even if binary exists
|
|
37
|
+
* @param {string} [options.binaryOptions.version] - Specific version to download
|
|
38
|
+
* @param {boolean} [options.json] - Return results as parsed JSON instead of string
|
|
39
|
+
* @returns {Promise<string|Object>} - Query results as string or parsed JSON
|
|
40
|
+
* @throws {Error} If the query fails
|
|
41
|
+
*/
|
|
42
|
+
export async function query(options) {
|
|
43
|
+
if (!options || !options.path) {
|
|
44
|
+
throw new Error('Path is required');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!options.pattern) {
|
|
48
|
+
throw new Error('Pattern is required');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Get the binary path
|
|
52
|
+
const binaryPath = await getBinaryPath(options.binaryOptions || {});
|
|
53
|
+
|
|
54
|
+
// Build CLI arguments from options
|
|
55
|
+
const cliArgs = buildCliArgs(options, QUERY_FLAG_MAP);
|
|
56
|
+
|
|
57
|
+
// If json option is true, override format to json
|
|
58
|
+
if (options.json && !options.format) {
|
|
59
|
+
cliArgs.push('--format', 'json');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Add pattern and path as positional arguments
|
|
63
|
+
cliArgs.push(escapeString(options.pattern), escapeString(options.path));
|
|
64
|
+
|
|
65
|
+
// Create a single log record with all query parameters (only in debug mode)
|
|
66
|
+
if (process.env.DEBUG === '1') {
|
|
67
|
+
let logMessage = `Query: pattern="${options.pattern}" path="${options.path}"`;
|
|
68
|
+
if (options.language) logMessage += ` language=${options.language}`;
|
|
69
|
+
if (options.maxResults) logMessage += ` maxResults=${options.maxResults}`;
|
|
70
|
+
if (options.allowTests) logMessage += " allowTests=true";
|
|
71
|
+
console.error(logMessage);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Execute command
|
|
75
|
+
const command = `${binaryPath} query ${cliArgs.join(' ')}`;
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const { stdout, stderr } = await execAsync(command);
|
|
79
|
+
|
|
80
|
+
if (stderr) {
|
|
81
|
+
console.error(`stderr: ${stderr}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Count results
|
|
85
|
+
let resultCount = 0;
|
|
86
|
+
|
|
87
|
+
// Try to count results from stdout
|
|
88
|
+
const lines = stdout.split('\n');
|
|
89
|
+
for (const line of lines) {
|
|
90
|
+
if (line.startsWith('```') && !line.includes('```language')) {
|
|
91
|
+
resultCount++;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Log the results count (only in debug mode)
|
|
96
|
+
if (process.env.DEBUG === '1') {
|
|
97
|
+
console.error(`Query results: ${resultCount} matches`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Parse JSON if requested or if format is json
|
|
101
|
+
if (options.json || options.format === 'json') {
|
|
102
|
+
try {
|
|
103
|
+
return JSON.parse(stdout);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error('Error parsing JSON output:', error);
|
|
106
|
+
return stdout; // Fall back to string output
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return stdout;
|
|
111
|
+
} catch (error) {
|
|
112
|
+
// Enhance error message with command details
|
|
113
|
+
const errorMessage = `Error executing query command: ${error.message}\nCommand: ${command}`;
|
|
114
|
+
throw new Error(errorMessage);
|
|
115
|
+
}
|
|
116
|
+
}
|
package/src/search.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search functionality for the probe package
|
|
3
|
+
* @module search
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { exec } from 'child_process';
|
|
7
|
+
import { promisify } from 'util';
|
|
8
|
+
import { getBinaryPath, buildCliArgs, escapeString } from './utils.js';
|
|
9
|
+
|
|
10
|
+
const execAsync = promisify(exec);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Flag mapping for search options
|
|
14
|
+
* Maps option keys to command-line flags
|
|
15
|
+
*/
|
|
16
|
+
const SEARCH_FLAG_MAP = {
|
|
17
|
+
filesOnly: '--files-only',
|
|
18
|
+
ignore: '--ignore',
|
|
19
|
+
excludeFilenames: '--exclude-filenames',
|
|
20
|
+
reranker: '--reranker',
|
|
21
|
+
frequencySearch: '--frequency',
|
|
22
|
+
exact: '--exact',
|
|
23
|
+
maxResults: '--max-results',
|
|
24
|
+
maxBytes: '--max-bytes',
|
|
25
|
+
maxTokens: '--max-tokens',
|
|
26
|
+
allowTests: '--allow-tests',
|
|
27
|
+
noMerge: '--no-merge',
|
|
28
|
+
mergeThreshold: '--merge-threshold',
|
|
29
|
+
session: '--session',
|
|
30
|
+
timeout: '--timeout',
|
|
31
|
+
language: '--language',
|
|
32
|
+
format: '--format'
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Search code in a specified directory
|
|
37
|
+
*
|
|
38
|
+
* @param {Object} options - Search options
|
|
39
|
+
* @param {string} options.path - Path to search in
|
|
40
|
+
* @param {string|string[]} options.query - Search query or queries
|
|
41
|
+
* @param {boolean} [options.filesOnly] - Only output file paths
|
|
42
|
+
* @param {string[]} [options.ignore] - Patterns to ignore
|
|
43
|
+
* @param {boolean} [options.excludeFilenames] - Exclude filenames from search
|
|
44
|
+
* @param {string} [options.reranker] - Reranking method ('hybrid', 'hybrid2', 'bm25', 'tfidf')
|
|
45
|
+
* @param {boolean} [options.frequencySearch] - Use frequency-based search
|
|
46
|
+
* @param {boolean} [options.exact] - Perform exact search without tokenization (case-insensitive)
|
|
47
|
+
* @param {number} [options.maxResults] - Maximum number of results
|
|
48
|
+
* @param {number} [options.maxBytes] - Maximum bytes to return
|
|
49
|
+
* @param {number} [options.maxTokens] - Maximum tokens to return
|
|
50
|
+
* @param {boolean} [options.allowTests] - Include test files
|
|
51
|
+
* @param {boolean} [options.noMerge] - Don't merge adjacent blocks
|
|
52
|
+
* @param {number} [options.mergeThreshold] - Merge threshold
|
|
53
|
+
* @param {string} [options.session] - Session ID for caching results
|
|
54
|
+
* @param {number} [options.timeout] - Timeout in seconds (default: 30)
|
|
55
|
+
* @param {string} [options.language] - Limit search to files of a specific programming language
|
|
56
|
+
* @param {string} [options.format] - Output format ('json', 'outline-xml', etc.)
|
|
57
|
+
* @param {Object} [options.binaryOptions] - Options for getting the binary
|
|
58
|
+
* @param {boolean} [options.binaryOptions.forceDownload] - Force download even if binary exists
|
|
59
|
+
* @param {string} [options.binaryOptions.version] - Specific version to download
|
|
60
|
+
* @param {boolean} [options.json] - Return results as parsed JSON instead of string
|
|
61
|
+
* @returns {Promise<string|Object>} - Search results as string or parsed JSON
|
|
62
|
+
* @throws {Error} If the search fails
|
|
63
|
+
*/
|
|
64
|
+
export async function search(options) {
|
|
65
|
+
if (!options || !options.path) {
|
|
66
|
+
throw new Error('Path is required');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!options.query) {
|
|
70
|
+
throw new Error('Query is required');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Get the binary path
|
|
74
|
+
const binaryPath = await getBinaryPath(options.binaryOptions || {});
|
|
75
|
+
|
|
76
|
+
// Build CLI arguments from options
|
|
77
|
+
const cliArgs = buildCliArgs(options, SEARCH_FLAG_MAP);
|
|
78
|
+
|
|
79
|
+
// Add format if specified, with json option taking precedence for backwards compatibility
|
|
80
|
+
if (options.json && !options.format) {
|
|
81
|
+
cliArgs.push('--format', 'json');
|
|
82
|
+
} else if (options.format) {
|
|
83
|
+
// Format is already handled by buildCliArgs through SEARCH_FLAG_MAP
|
|
84
|
+
// but we need to ensure json parsing for json format
|
|
85
|
+
if (options.format === 'json') {
|
|
86
|
+
options.json = true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Set default maxTokens if not provided
|
|
91
|
+
if (!options.maxTokens) {
|
|
92
|
+
options.maxTokens = 10000;
|
|
93
|
+
cliArgs.push('--max-tokens', '10000');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Set default timeout if not provided
|
|
97
|
+
if (!options.timeout) {
|
|
98
|
+
options.timeout = 30;
|
|
99
|
+
cliArgs.push('--timeout', '30');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Ensure language is properly passed if provided
|
|
103
|
+
if (options.language) {
|
|
104
|
+
// Ensure language flag is in cliArgs
|
|
105
|
+
if (!cliArgs.includes('--language')) {
|
|
106
|
+
cliArgs.push('--language', options.language);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Ensure exact search is properly passed if enabled
|
|
111
|
+
if (options.exact) {
|
|
112
|
+
// Ensure exact flag is in cliArgs
|
|
113
|
+
if (!cliArgs.includes('--exact')) {
|
|
114
|
+
cliArgs.push('--exact');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Add session ID from environment variable if not provided in options
|
|
119
|
+
if (!options.session && process.env.PROBE_SESSION_ID) {
|
|
120
|
+
options.session = process.env.PROBE_SESSION_ID;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Add query and path as positional arguments
|
|
124
|
+
const queries = Array.isArray(options.query) ? options.query : [options.query];
|
|
125
|
+
|
|
126
|
+
// Create a single log record with all search parameters (only in debug mode)
|
|
127
|
+
if (process.env.DEBUG === '1') {
|
|
128
|
+
let logMessage = `\nSearch: query="${queries[0]}" path="${options.path}"`;
|
|
129
|
+
if (options.maxResults) logMessage += ` maxResults=${options.maxResults}`;
|
|
130
|
+
logMessage += ` maxTokens=${options.maxTokens}`;
|
|
131
|
+
logMessage += ` timeout=${options.timeout}`;
|
|
132
|
+
if (options.allowTests) logMessage += " allowTests=true";
|
|
133
|
+
if (options.language) logMessage += ` language=${options.language}`;
|
|
134
|
+
if (options.exact) logMessage += " exact=true";
|
|
135
|
+
if (options.session) logMessage += ` session=${options.session}`;
|
|
136
|
+
console.error(logMessage);
|
|
137
|
+
}
|
|
138
|
+
// Create positional arguments array separate from flags
|
|
139
|
+
const positionalArgs = [];
|
|
140
|
+
|
|
141
|
+
if (queries.length > 0) {
|
|
142
|
+
// Escape the query to handle special characters
|
|
143
|
+
positionalArgs.push(escapeString(queries[0]));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Escape the path to handle spaces and special characters
|
|
147
|
+
positionalArgs.push(escapeString(options.path));
|
|
148
|
+
// Don't add the path to cliArgs, it should only be a positional argument
|
|
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(' ')}`);
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
// Log before executing
|
|
162
|
+
// console.error(`About to execute command: ${command}`);
|
|
163
|
+
|
|
164
|
+
// Execute the command with options to preserve quotes and apply timeout
|
|
165
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
166
|
+
shell: true,
|
|
167
|
+
timeout: options.timeout * 1000 // Convert seconds to milliseconds
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Log after executing
|
|
171
|
+
// console.error(`Command executed successfully`);
|
|
172
|
+
|
|
173
|
+
if (stderr && process.env.DEBUG) {
|
|
174
|
+
console.error(`stderr: ${stderr}`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Count results, tokens, and bytes
|
|
178
|
+
let resultCount = 0;
|
|
179
|
+
let tokenCount = 0;
|
|
180
|
+
let bytesCount = 0;
|
|
181
|
+
|
|
182
|
+
// Try to count results from stdout
|
|
183
|
+
const lines = stdout.split('\n');
|
|
184
|
+
for (const line of lines) {
|
|
185
|
+
if (line.startsWith('```') && !line.includes('```language')) {
|
|
186
|
+
resultCount++;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Look for the specific "Total bytes returned: X" line in the output
|
|
191
|
+
const totalBytesMatch = stdout.match(/Total bytes returned:\s*(\d+)/i);
|
|
192
|
+
if (totalBytesMatch && totalBytesMatch[1]) {
|
|
193
|
+
bytesCount = parseInt(totalBytesMatch[1], 10);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Look for the specific "Total tokens returned: X" line in the output
|
|
197
|
+
const totalTokensMatch = stdout.match(/Total tokens returned:\s*(\d+)/i);
|
|
198
|
+
if (totalTokensMatch && totalTokensMatch[1]) {
|
|
199
|
+
tokenCount = parseInt(totalTokensMatch[1], 10);
|
|
200
|
+
} else {
|
|
201
|
+
// Try other patterns if the specific format isn't found
|
|
202
|
+
const tokenMatch = stdout.match(/Tokens:?\s*(\d+)/i) ||
|
|
203
|
+
stdout.match(/(\d+)\s*tokens/i) ||
|
|
204
|
+
stdout.match(/token count:?\s*(\d+)/i);
|
|
205
|
+
|
|
206
|
+
if (tokenMatch && tokenMatch[1]) {
|
|
207
|
+
tokenCount = parseInt(tokenMatch[1], 10);
|
|
208
|
+
} else {
|
|
209
|
+
// If we still can't find the token count, use the default maxTokens value
|
|
210
|
+
// This is a fallback, but the command should be returning the actual count
|
|
211
|
+
tokenCount = options.maxTokens;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Log the results count, token count, and bytes count (only in debug mode)
|
|
216
|
+
if (process.env.DEBUG === '1') {
|
|
217
|
+
let resultsMessage = `\nSearch results: ${resultCount} matches, ${tokenCount} tokens`;
|
|
218
|
+
if (bytesCount > 0) {
|
|
219
|
+
resultsMessage += `, ${bytesCount} bytes`;
|
|
220
|
+
}
|
|
221
|
+
console.error(resultsMessage);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Parse JSON if requested
|
|
225
|
+
if (options.json) {
|
|
226
|
+
try {
|
|
227
|
+
return JSON.parse(stdout);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
console.error('Error parsing JSON output:', error);
|
|
230
|
+
return stdout; // Fall back to string output
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return stdout;
|
|
235
|
+
} catch (error) {
|
|
236
|
+
// Check if the error is a timeout
|
|
237
|
+
if (error.code === 'ETIMEDOUT' || error.killed) {
|
|
238
|
+
const timeoutMessage = `Search operation timed out after ${options.timeout} seconds.\nCommand: ${command}`;
|
|
239
|
+
console.error(timeoutMessage);
|
|
240
|
+
throw new Error(timeoutMessage);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Enhance error message with command details
|
|
244
|
+
const errorMessage = `Error executing search command: ${error.message}\nCommand: ${command}`;
|
|
245
|
+
throw new Error(errorMessage);
|
|
246
|
+
}
|
|
247
|
+
}
|