@probelabs/probe 0.6.0-rc138 → 0.6.0-rc140
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 +101 -47
- package/build/extract.js +142 -59
- package/cjs/agent/ProbeAgent.cjs +375 -315
- package/cjs/index.cjs +375 -315
- package/index.d.ts +10 -2
- package/package.json +1 -1
- package/src/extract.js +142 -59
package/index.d.ts
CHANGED
|
@@ -350,13 +350,21 @@ export interface QueryParams {
|
|
|
350
350
|
*/
|
|
351
351
|
export interface ExtractParams {
|
|
352
352
|
/** Files and line numbers or symbols to extract */
|
|
353
|
-
files
|
|
353
|
+
files?: string[];
|
|
354
|
+
/** Path to a file containing unstructured text to extract file paths from */
|
|
355
|
+
inputFile?: string;
|
|
356
|
+
/** Content to pipe to stdin (e.g., git diff output). Alternative to inputFile or files. */
|
|
357
|
+
content?: string | Buffer;
|
|
354
358
|
/** Path to search in */
|
|
355
359
|
path?: string;
|
|
356
360
|
/** Number of context lines */
|
|
357
361
|
contextLines?: number;
|
|
358
362
|
/** Output format */
|
|
359
|
-
format?: 'markdown' | 'plain' | 'json';
|
|
363
|
+
format?: 'markdown' | 'plain' | 'json' | 'xml' | 'color' | 'outline-xml' | 'outline-diff';
|
|
364
|
+
/** Include test files */
|
|
365
|
+
allowTests?: boolean;
|
|
366
|
+
/** Return results as parsed JSON instead of string */
|
|
367
|
+
json?: boolean;
|
|
360
368
|
/** Session ID */
|
|
361
369
|
sessionId?: string;
|
|
362
370
|
}
|
package/package.json
CHANGED
package/src/extract.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module extract
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { exec } from 'child_process';
|
|
6
|
+
import { exec, spawn } from 'child_process';
|
|
7
7
|
import { promisify } from 'util';
|
|
8
8
|
import { getBinaryPath, buildCliArgs, escapeString } from './utils.js';
|
|
9
9
|
|
|
@@ -22,13 +22,14 @@ const EXTRACT_FLAG_MAP = {
|
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Extract code blocks from files
|
|
25
|
-
*
|
|
25
|
+
*
|
|
26
26
|
* @param {Object} options - Extract options
|
|
27
27
|
* @param {string[]} [options.files] - Files to extract from (can include line numbers with colon, e.g., "/path/to/file.rs:10")
|
|
28
28
|
* @param {string} [options.inputFile] - Path to a file containing unstructured text to extract file paths from
|
|
29
|
+
* @param {string|Buffer} [options.content] - Content to pipe to stdin (e.g., git diff output). Alternative to inputFile.
|
|
29
30
|
* @param {boolean} [options.allowTests] - Include test files
|
|
30
31
|
* @param {number} [options.contextLines] - Number of context lines to include
|
|
31
|
-
* @param {string} [options.format] - Output format ('markdown', 'plain', 'json')
|
|
32
|
+
* @param {string} [options.format] - Output format ('markdown', 'plain', 'json', 'xml', 'color', 'outline-xml', 'outline-diff')
|
|
32
33
|
* @param {Object} [options.binaryOptions] - Options for getting the binary
|
|
33
34
|
* @param {boolean} [options.binaryOptions.forceDownload] - Force download even if binary exists
|
|
34
35
|
* @param {string} [options.binaryOptions.version] - Specific version to download
|
|
@@ -41,16 +42,22 @@ export async function extract(options) {
|
|
|
41
42
|
throw new Error('Options object is required');
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
// Either files or
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
// Either files, inputFile, or content must be provided
|
|
46
|
+
const hasFiles = options.files && Array.isArray(options.files) && options.files.length > 0;
|
|
47
|
+
const hasInputFile = !!options.inputFile;
|
|
48
|
+
const hasContent = options.content !== undefined && options.content !== null;
|
|
49
|
+
|
|
50
|
+
if (!hasFiles && !hasInputFile && !hasContent) {
|
|
51
|
+
throw new Error('Either files array, inputFile, or content must be provided');
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
// Get the binary path
|
|
50
55
|
const binaryPath = await getBinaryPath(options.binaryOptions || {});
|
|
51
56
|
|
|
52
|
-
// Build CLI arguments from options
|
|
53
|
-
const
|
|
57
|
+
// Build CLI arguments from options (excluding content which goes via stdin)
|
|
58
|
+
const filteredOptions = { ...options };
|
|
59
|
+
delete filteredOptions.content;
|
|
60
|
+
const cliArgs = buildCliArgs(filteredOptions, EXTRACT_FLAG_MAP);
|
|
54
61
|
|
|
55
62
|
// If json option is true, override format to json
|
|
56
63
|
if (options.json && !options.format) {
|
|
@@ -58,7 +65,7 @@ export async function extract(options) {
|
|
|
58
65
|
}
|
|
59
66
|
|
|
60
67
|
// Add files as positional arguments if provided
|
|
61
|
-
if (
|
|
68
|
+
if (hasFiles) {
|
|
62
69
|
for (const file of options.files) {
|
|
63
70
|
cliArgs.push(escapeString(file));
|
|
64
71
|
}
|
|
@@ -71,6 +78,7 @@ export async function extract(options) {
|
|
|
71
78
|
logMessage += ` files="${options.files.join(', ')}"`;
|
|
72
79
|
}
|
|
73
80
|
if (options.inputFile) logMessage += ` inputFile="${options.inputFile}"`;
|
|
81
|
+
if (options.content) logMessage += ` content=(${typeof options.content === 'string' ? options.content.length : options.content.byteLength} bytes)`;
|
|
74
82
|
if (options.allowTests) logMessage += " allowTests=true";
|
|
75
83
|
if (options.contextLines) logMessage += ` contextLines=${options.contextLines}`;
|
|
76
84
|
if (options.format) logMessage += ` format=${options.format}`;
|
|
@@ -78,7 +86,12 @@ export async function extract(options) {
|
|
|
78
86
|
console.error(logMessage);
|
|
79
87
|
}
|
|
80
88
|
|
|
81
|
-
//
|
|
89
|
+
// If content is provided, use spawn with stdin piping
|
|
90
|
+
if (hasContent) {
|
|
91
|
+
return extractWithStdin(binaryPath, cliArgs, options.content, options);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Otherwise use exec for simple command execution
|
|
82
95
|
const command = `${binaryPath} extract ${cliArgs.join(' ')}`;
|
|
83
96
|
|
|
84
97
|
try {
|
|
@@ -88,62 +101,132 @@ export async function extract(options) {
|
|
|
88
101
|
console.error(`stderr: ${stderr}`);
|
|
89
102
|
}
|
|
90
103
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// Calculate approximate request tokens
|
|
99
|
-
if (options.files && Array.isArray(options.files)) {
|
|
100
|
-
tokenUsage.requestTokens = options.files.join(' ').length / 4;
|
|
101
|
-
} else if (options.inputFile) {
|
|
102
|
-
tokenUsage.requestTokens = options.inputFile.length / 4;
|
|
103
|
-
}
|
|
104
|
+
return processExtractOutput(stdout, options);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
// Enhance error message with command details
|
|
107
|
+
const errorMessage = `Error executing extract command: ${error.message}\nCommand: ${command}`;
|
|
108
|
+
throw new Error(errorMessage);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
104
111
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
112
|
+
/**
|
|
113
|
+
* Extract with content piped to stdin
|
|
114
|
+
* @private
|
|
115
|
+
*/
|
|
116
|
+
function extractWithStdin(binaryPath, cliArgs, content, options) {
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
const childProcess = spawn(binaryPath, ['extract', ...cliArgs], {
|
|
119
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
let stdout = '';
|
|
123
|
+
let stderr = '';
|
|
124
|
+
|
|
125
|
+
// Collect stdout
|
|
126
|
+
childProcess.stdout.on('data', (data) => {
|
|
127
|
+
stdout += data.toString();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Collect stderr
|
|
131
|
+
childProcess.stderr.on('data', (data) => {
|
|
132
|
+
stderr += data.toString();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Handle process exit
|
|
136
|
+
childProcess.on('close', (code) => {
|
|
137
|
+
if (stderr && process.env.DEBUG === '1') {
|
|
138
|
+
console.error(`stderr: ${stderr}`);
|
|
111
139
|
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Add token usage information to the output
|
|
115
|
-
let output = stdout;
|
|
116
140
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
141
|
+
if (code !== 0) {
|
|
142
|
+
reject(new Error(`Extract command failed with exit code ${code}: ${stderr}`));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
121
145
|
|
|
122
|
-
// Parse JSON if requested or if format is json
|
|
123
|
-
if (options.json || options.format === 'json') {
|
|
124
146
|
try {
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
// Add token usage to JSON output
|
|
128
|
-
if (!jsonOutput.token_usage) {
|
|
129
|
-
jsonOutput.token_usage = {
|
|
130
|
-
request_tokens: tokenUsage.requestTokens,
|
|
131
|
-
response_tokens: tokenUsage.responseTokens,
|
|
132
|
-
total_tokens: tokenUsage.totalTokens
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return jsonOutput;
|
|
147
|
+
const result = processExtractOutput(stdout, options);
|
|
148
|
+
resolve(result);
|
|
137
149
|
} catch (error) {
|
|
138
|
-
|
|
139
|
-
return output; // Fall back to string output with token usage
|
|
150
|
+
reject(error);
|
|
140
151
|
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Handle errors
|
|
155
|
+
childProcess.on('error', (error) => {
|
|
156
|
+
reject(new Error(`Failed to spawn extract process: ${error.message}`));
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Write content to stdin and close
|
|
160
|
+
if (typeof content === 'string') {
|
|
161
|
+
childProcess.stdin.write(content);
|
|
162
|
+
} else {
|
|
163
|
+
childProcess.stdin.write(content);
|
|
141
164
|
}
|
|
165
|
+
childProcess.stdin.end();
|
|
166
|
+
});
|
|
167
|
+
}
|
|
142
168
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
169
|
+
/**
|
|
170
|
+
* Process extract output and add token usage information
|
|
171
|
+
* @private
|
|
172
|
+
*/
|
|
173
|
+
function processExtractOutput(stdout, options) {
|
|
174
|
+
// Parse the output to extract token usage information
|
|
175
|
+
let tokenUsage = {
|
|
176
|
+
requestTokens: 0,
|
|
177
|
+
responseTokens: 0,
|
|
178
|
+
totalTokens: 0
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// Calculate approximate request tokens
|
|
182
|
+
if (options.files && Array.isArray(options.files)) {
|
|
183
|
+
tokenUsage.requestTokens = options.files.join(' ').length / 4;
|
|
184
|
+
} else if (options.inputFile) {
|
|
185
|
+
tokenUsage.requestTokens = options.inputFile.length / 4;
|
|
186
|
+
} else if (options.content) {
|
|
187
|
+
const contentLength = typeof options.content === 'string'
|
|
188
|
+
? options.content.length
|
|
189
|
+
: options.content.byteLength;
|
|
190
|
+
tokenUsage.requestTokens = contentLength / 4;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Try to extract token information from the output
|
|
194
|
+
if (stdout.includes('Total tokens returned:')) {
|
|
195
|
+
const tokenMatch = stdout.match(/Total tokens returned: (\d+)/);
|
|
196
|
+
if (tokenMatch && tokenMatch[1]) {
|
|
197
|
+
tokenUsage.responseTokens = parseInt(tokenMatch[1], 10);
|
|
198
|
+
tokenUsage.totalTokens = tokenUsage.requestTokens + tokenUsage.responseTokens;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Add token usage information to the output
|
|
203
|
+
let output = stdout;
|
|
204
|
+
|
|
205
|
+
// Add token usage information at the end if not already present
|
|
206
|
+
if (!output.includes('Token Usage:')) {
|
|
207
|
+
output += `\nToken Usage:\n Request tokens: ${tokenUsage.requestTokens}\n Response tokens: ${tokenUsage.responseTokens}\n Total tokens: ${tokenUsage.totalTokens}\n`;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Parse JSON if requested or if format is json
|
|
211
|
+
if (options.json || options.format === 'json') {
|
|
212
|
+
try {
|
|
213
|
+
const jsonOutput = JSON.parse(stdout);
|
|
214
|
+
|
|
215
|
+
// Add token usage to JSON output
|
|
216
|
+
if (!jsonOutput.token_usage) {
|
|
217
|
+
jsonOutput.token_usage = {
|
|
218
|
+
request_tokens: tokenUsage.requestTokens,
|
|
219
|
+
response_tokens: tokenUsage.responseTokens,
|
|
220
|
+
total_tokens: tokenUsage.totalTokens
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return jsonOutput;
|
|
225
|
+
} catch (error) {
|
|
226
|
+
console.error('Error parsing JSON output:', error);
|
|
227
|
+
return output; // Fall back to string output with token usage
|
|
228
|
+
}
|
|
148
229
|
}
|
|
149
|
-
|
|
230
|
+
|
|
231
|
+
return output;
|
|
232
|
+
}
|