@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.
@@ -2689,21 +2689,26 @@ var init_query = __esm({
2689
2689
  });
2690
2690
 
2691
2691
  // src/extract.js
2692
- import { exec as exec4 } from "child_process";
2692
+ import { exec as exec4, spawn } from "child_process";
2693
2693
  import { promisify as promisify4 } from "util";
2694
2694
  async function extract(options) {
2695
2695
  if (!options) {
2696
2696
  throw new Error("Options object is required");
2697
2697
  }
2698
- if ((!options.files || !Array.isArray(options.files) || options.files.length === 0) && !options.inputFile) {
2699
- throw new Error("Either files array or inputFile must be provided");
2698
+ const hasFiles = options.files && Array.isArray(options.files) && options.files.length > 0;
2699
+ const hasInputFile = !!options.inputFile;
2700
+ const hasContent = options.content !== void 0 && options.content !== null;
2701
+ if (!hasFiles && !hasInputFile && !hasContent) {
2702
+ throw new Error("Either files array, inputFile, or content must be provided");
2700
2703
  }
2701
2704
  const binaryPath = await getBinaryPath(options.binaryOptions || {});
2702
- const cliArgs = buildCliArgs(options, EXTRACT_FLAG_MAP);
2705
+ const filteredOptions = { ...options };
2706
+ delete filteredOptions.content;
2707
+ const cliArgs = buildCliArgs(filteredOptions, EXTRACT_FLAG_MAP);
2703
2708
  if (options.json && !options.format) {
2704
2709
  cliArgs.push("--format", "json");
2705
2710
  }
2706
- if (options.files && Array.isArray(options.files) && options.files.length > 0) {
2711
+ if (hasFiles) {
2707
2712
  for (const file of options.files) {
2708
2713
  cliArgs.push(escapeString(file));
2709
2714
  }
@@ -2715,66 +2720,115 @@ Extract:`;
2715
2720
  logMessage += ` files="${options.files.join(", ")}"`;
2716
2721
  }
2717
2722
  if (options.inputFile) logMessage += ` inputFile="${options.inputFile}"`;
2723
+ if (options.content) logMessage += ` content=(${typeof options.content === "string" ? options.content.length : options.content.byteLength} bytes)`;
2718
2724
  if (options.allowTests) logMessage += " allowTests=true";
2719
2725
  if (options.contextLines) logMessage += ` contextLines=${options.contextLines}`;
2720
2726
  if (options.format) logMessage += ` format=${options.format}`;
2721
2727
  if (options.json) logMessage += " json=true";
2722
2728
  console.error(logMessage);
2723
2729
  }
2730
+ if (hasContent) {
2731
+ return extractWithStdin(binaryPath, cliArgs, options.content, options);
2732
+ }
2724
2733
  const command = `${binaryPath} extract ${cliArgs.join(" ")}`;
2725
2734
  try {
2726
2735
  const { stdout, stderr } = await execAsync3(command);
2727
2736
  if (stderr) {
2728
2737
  console.error(`stderr: ${stderr}`);
2729
2738
  }
2730
- let tokenUsage = {
2731
- requestTokens: 0,
2732
- responseTokens: 0,
2733
- totalTokens: 0
2734
- };
2735
- if (options.files && Array.isArray(options.files)) {
2736
- tokenUsage.requestTokens = options.files.join(" ").length / 4;
2737
- } else if (options.inputFile) {
2738
- tokenUsage.requestTokens = options.inputFile.length / 4;
2739
- }
2740
- if (stdout.includes("Total tokens returned:")) {
2741
- const tokenMatch = stdout.match(/Total tokens returned: (\d+)/);
2742
- if (tokenMatch && tokenMatch[1]) {
2743
- tokenUsage.responseTokens = parseInt(tokenMatch[1], 10);
2744
- tokenUsage.totalTokens = tokenUsage.requestTokens + tokenUsage.responseTokens;
2739
+ return processExtractOutput(stdout, options);
2740
+ } catch (error) {
2741
+ const errorMessage = `Error executing extract command: ${error.message}
2742
+ Command: ${command}`;
2743
+ throw new Error(errorMessage);
2744
+ }
2745
+ }
2746
+ function extractWithStdin(binaryPath, cliArgs, content, options) {
2747
+ return new Promise((resolve5, reject2) => {
2748
+ const childProcess = spawn(binaryPath, ["extract", ...cliArgs], {
2749
+ stdio: ["pipe", "pipe", "pipe"]
2750
+ });
2751
+ let stdout = "";
2752
+ let stderr = "";
2753
+ childProcess.stdout.on("data", (data) => {
2754
+ stdout += data.toString();
2755
+ });
2756
+ childProcess.stderr.on("data", (data) => {
2757
+ stderr += data.toString();
2758
+ });
2759
+ childProcess.on("close", (code) => {
2760
+ if (stderr && process.env.DEBUG === "1") {
2761
+ console.error(`stderr: ${stderr}`);
2762
+ }
2763
+ if (code !== 0) {
2764
+ reject2(new Error(`Extract command failed with exit code ${code}: ${stderr}`));
2765
+ return;
2745
2766
  }
2767
+ try {
2768
+ const result = processExtractOutput(stdout, options);
2769
+ resolve5(result);
2770
+ } catch (error) {
2771
+ reject2(error);
2772
+ }
2773
+ });
2774
+ childProcess.on("error", (error) => {
2775
+ reject2(new Error(`Failed to spawn extract process: ${error.message}`));
2776
+ });
2777
+ if (typeof content === "string") {
2778
+ childProcess.stdin.write(content);
2779
+ } else {
2780
+ childProcess.stdin.write(content);
2746
2781
  }
2747
- let output = stdout;
2748
- if (!output.includes("Token Usage:")) {
2749
- output += `
2782
+ childProcess.stdin.end();
2783
+ });
2784
+ }
2785
+ function processExtractOutput(stdout, options) {
2786
+ let tokenUsage = {
2787
+ requestTokens: 0,
2788
+ responseTokens: 0,
2789
+ totalTokens: 0
2790
+ };
2791
+ if (options.files && Array.isArray(options.files)) {
2792
+ tokenUsage.requestTokens = options.files.join(" ").length / 4;
2793
+ } else if (options.inputFile) {
2794
+ tokenUsage.requestTokens = options.inputFile.length / 4;
2795
+ } else if (options.content) {
2796
+ const contentLength = typeof options.content === "string" ? options.content.length : options.content.byteLength;
2797
+ tokenUsage.requestTokens = contentLength / 4;
2798
+ }
2799
+ if (stdout.includes("Total tokens returned:")) {
2800
+ const tokenMatch = stdout.match(/Total tokens returned: (\d+)/);
2801
+ if (tokenMatch && tokenMatch[1]) {
2802
+ tokenUsage.responseTokens = parseInt(tokenMatch[1], 10);
2803
+ tokenUsage.totalTokens = tokenUsage.requestTokens + tokenUsage.responseTokens;
2804
+ }
2805
+ }
2806
+ let output = stdout;
2807
+ if (!output.includes("Token Usage:")) {
2808
+ output += `
2750
2809
  Token Usage:
2751
2810
  Request tokens: ${tokenUsage.requestTokens}
2752
2811
  Response tokens: ${tokenUsage.responseTokens}
2753
2812
  Total tokens: ${tokenUsage.totalTokens}
2754
2813
  `;
2755
- }
2756
- if (options.json || options.format === "json") {
2757
- try {
2758
- const jsonOutput = JSON.parse(stdout);
2759
- if (!jsonOutput.token_usage) {
2760
- jsonOutput.token_usage = {
2761
- request_tokens: tokenUsage.requestTokens,
2762
- response_tokens: tokenUsage.responseTokens,
2763
- total_tokens: tokenUsage.totalTokens
2764
- };
2765
- }
2766
- return jsonOutput;
2767
- } catch (error) {
2768
- console.error("Error parsing JSON output:", error);
2769
- return output;
2814
+ }
2815
+ if (options.json || options.format === "json") {
2816
+ try {
2817
+ const jsonOutput = JSON.parse(stdout);
2818
+ if (!jsonOutput.token_usage) {
2819
+ jsonOutput.token_usage = {
2820
+ request_tokens: tokenUsage.requestTokens,
2821
+ response_tokens: tokenUsage.responseTokens,
2822
+ total_tokens: tokenUsage.totalTokens
2823
+ };
2770
2824
  }
2825
+ return jsonOutput;
2826
+ } catch (error) {
2827
+ console.error("Error parsing JSON output:", error);
2828
+ return output;
2771
2829
  }
2772
- return output;
2773
- } catch (error) {
2774
- const errorMessage = `Error executing extract command: ${error.message}
2775
- Command: ${command}`;
2776
- throw new Error(errorMessage);
2777
2830
  }
2831
+ return output;
2778
2832
  }
2779
2833
  var execAsync3, EXTRACT_FLAG_MAP;
2780
2834
  var init_extract = __esm({
@@ -7275,7 +7329,7 @@ I have refactored the search module according to the requirements and verified t
7275
7329
  });
7276
7330
 
7277
7331
  // src/delegate.js
7278
- import { spawn } from "child_process";
7332
+ import { spawn as spawn2 } from "child_process";
7279
7333
  import { randomUUID } from "crypto";
7280
7334
  async function delegate({ task, timeout = 300, debug = false, currentIteration = 0, maxIterations = 30, tracer = null }) {
7281
7335
  if (!task || typeof task !== "string") {
@@ -7318,7 +7372,7 @@ async function delegate({ task, timeout = 300, debug = false, currentIteration =
7318
7372
  }
7319
7373
  return new Promise((resolve5, reject2) => {
7320
7374
  const delegationSpan = tracer ? tracer.createDelegationSpan(sessionId, task) : null;
7321
- const process2 = spawn(binaryPath, args, {
7375
+ const process2 = spawn2(binaryPath, args, {
7322
7376
  stdio: ["pipe", "pipe", "pipe"],
7323
7377
  timeout: timeout * 1e3
7324
7378
  });
@@ -8476,7 +8530,7 @@ var init_bashPermissions = __esm({
8476
8530
  });
8477
8531
 
8478
8532
  // src/agent/bashExecutor.js
8479
- import { spawn as spawn2 } from "child_process";
8533
+ import { spawn as spawn3 } from "child_process";
8480
8534
  import { resolve, join } from "path";
8481
8535
  import { existsSync } from "fs";
8482
8536
  async function executeBashCommand(command, options = {}) {
@@ -8533,7 +8587,7 @@ async function executeBashCommand(command, options = {}) {
8533
8587
  return;
8534
8588
  }
8535
8589
  const [cmd, ...cmdArgs] = args;
8536
- const child = spawn2(cmd, cmdArgs, {
8590
+ const child = spawn3(cmd, cmdArgs, {
8537
8591
  cwd,
8538
8592
  env: processEnv,
8539
8593
  stdio: ["ignore", "pipe", "pipe"],
package/build/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 inputFile must be provided
45
- if ((!options.files || !Array.isArray(options.files) || options.files.length === 0) && !options.inputFile) {
46
- throw new Error('Either files array or inputFile must be provided');
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 cliArgs = buildCliArgs(options, EXTRACT_FLAG_MAP);
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 (options.files && Array.isArray(options.files) && options.files.length > 0) {
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
- // Execute command
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
- // Parse the output to extract token usage information
92
- let tokenUsage = {
93
- requestTokens: 0,
94
- responseTokens: 0,
95
- totalTokens: 0
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
- // Try to extract token information from the output
106
- if (stdout.includes('Total tokens returned:')) {
107
- const tokenMatch = stdout.match(/Total tokens returned: (\d+)/);
108
- if (tokenMatch && tokenMatch[1]) {
109
- tokenUsage.responseTokens = parseInt(tokenMatch[1], 10);
110
- tokenUsage.totalTokens = tokenUsage.requestTokens + tokenUsage.responseTokens;
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
- // Add token usage information at the end if not already present
118
- if (!output.includes('Token Usage:')) {
119
- output += `\nToken Usage:\n Request tokens: ${tokenUsage.requestTokens}\n Response tokens: ${tokenUsage.responseTokens}\n Total tokens: ${tokenUsage.totalTokens}\n`;
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 jsonOutput = JSON.parse(stdout);
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
- console.error('Error parsing JSON output:', error);
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
- return output;
144
- } catch (error) {
145
- // Enhance error message with command details
146
- const errorMessage = `Error executing extract command: ${error.message}\nCommand: ${command}`;
147
- throw new Error(errorMessage);
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
+ }