@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.
Files changed (115) hide show
  1. package/README.md +583 -0
  2. package/bin/.gitkeep +0 -0
  3. package/bin/probe +158 -0
  4. package/bin/probe-binary +0 -0
  5. package/build/agent/ProbeAgent.d.ts +199 -0
  6. package/build/agent/ProbeAgent.js +1486 -0
  7. package/build/agent/acp/README.md +347 -0
  8. package/build/agent/acp/connection.js +237 -0
  9. package/build/agent/acp/connection.test.js +311 -0
  10. package/build/agent/acp/examples/simple-client.js +212 -0
  11. package/build/agent/acp/examples/tool-lifecycle.js +230 -0
  12. package/build/agent/acp/final-test.js +173 -0
  13. package/build/agent/acp/index.js +5 -0
  14. package/build/agent/acp/integration.test.js +385 -0
  15. package/build/agent/acp/manual-test.js +410 -0
  16. package/build/agent/acp/protocol-test.js +190 -0
  17. package/build/agent/acp/server.js +448 -0
  18. package/build/agent/acp/server.test.js +371 -0
  19. package/build/agent/acp/test-runner.js +216 -0
  20. package/build/agent/acp/test-utils/README.md +315 -0
  21. package/build/agent/acp/test-utils/acp-tester.js +484 -0
  22. package/build/agent/acp/test-utils/mock-acp-client.js +434 -0
  23. package/build/agent/acp/tools.js +368 -0
  24. package/build/agent/acp/tools.test.js +334 -0
  25. package/build/agent/acp/types.js +218 -0
  26. package/build/agent/acp/types.test.js +327 -0
  27. package/build/agent/appTracer.js +360 -0
  28. package/build/agent/fileSpanExporter.js +169 -0
  29. package/build/agent/index.js +7426 -0
  30. package/build/agent/mcp/client.js +338 -0
  31. package/build/agent/mcp/config.js +313 -0
  32. package/build/agent/mcp/index.js +64 -0
  33. package/build/agent/mcp/xmlBridge.js +371 -0
  34. package/build/agent/mockProvider.js +53 -0
  35. package/build/agent/probeTool.js +257 -0
  36. package/build/agent/schemaUtils.js +1726 -0
  37. package/build/agent/simpleTelemetry.js +267 -0
  38. package/build/agent/telemetry.js +225 -0
  39. package/build/agent/tokenCounter.js +395 -0
  40. package/build/agent/tools.js +163 -0
  41. package/build/cli.js +49 -0
  42. package/build/delegate.js +267 -0
  43. package/build/directory-resolver.js +237 -0
  44. package/build/downloader.js +750 -0
  45. package/build/extract.js +149 -0
  46. package/build/index.js +70 -0
  47. package/build/mcp/index.js +514 -0
  48. package/build/mcp/index.ts +608 -0
  49. package/build/query.js +116 -0
  50. package/build/search.js +247 -0
  51. package/build/tools/common.js +410 -0
  52. package/build/tools/index.js +40 -0
  53. package/build/tools/langchain.js +88 -0
  54. package/build/tools/system-message.js +121 -0
  55. package/build/tools/vercel.js +271 -0
  56. package/build/utils/file-lister.js +193 -0
  57. package/build/utils.js +128 -0
  58. package/cjs/agent/ProbeAgent.cjs +5829 -0
  59. package/cjs/index.cjs +6217 -0
  60. package/cjs/package.json +3 -0
  61. package/index.d.ts +401 -0
  62. package/package.json +114 -0
  63. package/scripts/postinstall.js +172 -0
  64. package/src/agent/ProbeAgent.d.ts +199 -0
  65. package/src/agent/ProbeAgent.js +1486 -0
  66. package/src/agent/acp/README.md +347 -0
  67. package/src/agent/acp/connection.js +237 -0
  68. package/src/agent/acp/connection.test.js +311 -0
  69. package/src/agent/acp/examples/simple-client.js +212 -0
  70. package/src/agent/acp/examples/tool-lifecycle.js +230 -0
  71. package/src/agent/acp/final-test.js +173 -0
  72. package/src/agent/acp/index.js +5 -0
  73. package/src/agent/acp/integration.test.js +385 -0
  74. package/src/agent/acp/manual-test.js +410 -0
  75. package/src/agent/acp/protocol-test.js +190 -0
  76. package/src/agent/acp/server.js +448 -0
  77. package/src/agent/acp/server.test.js +371 -0
  78. package/src/agent/acp/test-runner.js +216 -0
  79. package/src/agent/acp/test-utils/README.md +315 -0
  80. package/src/agent/acp/test-utils/acp-tester.js +484 -0
  81. package/src/agent/acp/test-utils/mock-acp-client.js +434 -0
  82. package/src/agent/acp/tools.js +368 -0
  83. package/src/agent/acp/tools.test.js +334 -0
  84. package/src/agent/acp/types.js +218 -0
  85. package/src/agent/acp/types.test.js +327 -0
  86. package/src/agent/appTracer.js +360 -0
  87. package/src/agent/fileSpanExporter.js +169 -0
  88. package/src/agent/index.js +813 -0
  89. package/src/agent/mcp/client.js +338 -0
  90. package/src/agent/mcp/config.js +313 -0
  91. package/src/agent/mcp/index.js +64 -0
  92. package/src/agent/mcp/xmlBridge.js +371 -0
  93. package/src/agent/mockProvider.js +53 -0
  94. package/src/agent/probeTool.js +257 -0
  95. package/src/agent/schemaUtils.js +1726 -0
  96. package/src/agent/simpleTelemetry.js +267 -0
  97. package/src/agent/telemetry.js +225 -0
  98. package/src/agent/tokenCounter.js +395 -0
  99. package/src/agent/tools.js +163 -0
  100. package/src/cli.js +49 -0
  101. package/src/delegate.js +267 -0
  102. package/src/directory-resolver.js +237 -0
  103. package/src/downloader.js +750 -0
  104. package/src/extract.js +149 -0
  105. package/src/index.js +70 -0
  106. package/src/mcp/index.ts +608 -0
  107. package/src/query.js +116 -0
  108. package/src/search.js +247 -0
  109. package/src/tools/common.js +410 -0
  110. package/src/tools/index.js +40 -0
  111. package/src/tools/langchain.js +88 -0
  112. package/src/tools/system-message.js +121 -0
  113. package/src/tools/vercel.js +271 -0
  114. package/src/utils/file-lister.js +193 -0
  115. package/src/utils.js +128 -0
package/build/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
+ }
@@ -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
+ }