@probelabs/probe 0.6.0-rc115 → 0.6.0-rc117
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/ProbeAgent.js +100 -10
- package/build/agent/index.js +3853 -306
- package/build/agent/probeTool.js +93 -18
- package/build/agent/schemaUtils.js +1 -1
- package/build/index.js +4 -0
- package/cjs/agent/ProbeAgent.cjs +3856 -309
- package/cjs/index.cjs +3601 -50
- package/package.json +2 -2
- package/src/agent/ProbeAgent.js +100 -10
- package/src/agent/probeTool.js +93 -18
- package/src/agent/schemaUtils.js +1 -1
- package/src/index.js +4 -0
package/build/agent/probeTool.js
CHANGED
|
@@ -213,45 +213,99 @@ export function createWrappedTools(baseTools) {
|
|
|
213
213
|
return wrappedTools;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
// Simple file listing tool
|
|
216
|
+
// Simple file listing tool with ls-like formatted output
|
|
217
217
|
export const listFilesTool = {
|
|
218
218
|
execute: async (params) => {
|
|
219
219
|
const { directory = '.', workingDirectory } = params;
|
|
220
|
-
|
|
220
|
+
|
|
221
221
|
// Use the provided working directory, or fall back to process.cwd()
|
|
222
222
|
const baseCwd = workingDirectory || process.cwd();
|
|
223
|
-
|
|
223
|
+
|
|
224
224
|
// Security: Validate path to prevent traversal attacks
|
|
225
225
|
const secureBaseDir = path.resolve(baseCwd);
|
|
226
226
|
const targetDir = path.resolve(secureBaseDir, directory);
|
|
227
227
|
if (!targetDir.startsWith(secureBaseDir + path.sep) && targetDir !== secureBaseDir) {
|
|
228
228
|
throw new Error('Path traversal attempt detected. Access denied.');
|
|
229
229
|
}
|
|
230
|
-
|
|
230
|
+
|
|
231
|
+
const debug = process.env.DEBUG === '1';
|
|
232
|
+
|
|
233
|
+
if (debug) {
|
|
234
|
+
console.log(`[DEBUG] Listing files in directory: ${targetDir}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
231
237
|
try {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
238
|
+
// Read the directory contents
|
|
239
|
+
const files = await fsPromises.readdir(targetDir, { withFileTypes: true });
|
|
240
|
+
|
|
241
|
+
// Format size for human readability
|
|
242
|
+
const formatSize = (size) => {
|
|
243
|
+
if (size < 1024) return `${size}B`;
|
|
244
|
+
if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)}K`;
|
|
245
|
+
if (size < 1024 * 1024 * 1024) return `${(size / (1024 * 1024)).toFixed(1)}M`;
|
|
246
|
+
return `${(size / (1024 * 1024 * 1024)).toFixed(1)}G`;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Format the results as ls-style output
|
|
250
|
+
const entries = await Promise.all(files.map(async (file) => {
|
|
251
|
+
const isDirectory = file.isDirectory();
|
|
252
|
+
const fullPath = path.join(targetDir, file.name);
|
|
253
|
+
|
|
254
|
+
let size = 0;
|
|
255
|
+
try {
|
|
256
|
+
const stats = await fsPromises.stat(fullPath);
|
|
257
|
+
size = stats.size;
|
|
258
|
+
} catch (statError) {
|
|
259
|
+
if (debug) {
|
|
260
|
+
console.log(`[DEBUG] Could not stat file ${file.name}:`, statError.message);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
name: file.name,
|
|
266
|
+
isDirectory,
|
|
267
|
+
size
|
|
268
|
+
};
|
|
269
|
+
}));
|
|
270
|
+
|
|
271
|
+
// Sort: directories first, then files, both alphabetically
|
|
272
|
+
entries.sort((a, b) => {
|
|
273
|
+
if (a.isDirectory && !b.isDirectory) return -1;
|
|
274
|
+
if (!a.isDirectory && b.isDirectory) return 1;
|
|
275
|
+
return a.name.localeCompare(b.name);
|
|
237
276
|
});
|
|
238
|
-
|
|
239
|
-
|
|
277
|
+
|
|
278
|
+
// Format entries
|
|
279
|
+
const formatted = entries.map(entry => {
|
|
280
|
+
const type = entry.isDirectory ? 'dir ' : 'file';
|
|
281
|
+
const sizeStr = formatSize(entry.size).padStart(8);
|
|
282
|
+
return `${type} ${sizeStr} ${entry.name}`;
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
if (debug) {
|
|
286
|
+
console.log(`[DEBUG] Found ${entries.length} files/directories in ${targetDir}`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Return as formatted text output
|
|
290
|
+
const header = `${targetDir}:\n`;
|
|
291
|
+
const output = header + formatted.join('\n');
|
|
292
|
+
|
|
293
|
+
return output;
|
|
240
294
|
} catch (error) {
|
|
241
295
|
throw new Error(`Failed to list files: ${error.message}`);
|
|
242
296
|
}
|
|
243
297
|
}
|
|
244
298
|
};
|
|
245
299
|
|
|
246
|
-
// Simple file search tool
|
|
300
|
+
// Simple file search tool with timeout protection
|
|
247
301
|
export const searchFilesTool = {
|
|
248
302
|
execute: async (params) => {
|
|
249
303
|
const { pattern, directory = '.', recursive = true, workingDirectory } = params;
|
|
250
|
-
|
|
304
|
+
|
|
251
305
|
if (!pattern) {
|
|
252
306
|
throw new Error('Pattern is required for file search');
|
|
253
307
|
}
|
|
254
|
-
|
|
308
|
+
|
|
255
309
|
// Security: Validate path to prevent traversal attacks
|
|
256
310
|
const baseCwd = workingDirectory || process.cwd();
|
|
257
311
|
const secureBaseDir = path.resolve(baseCwd);
|
|
@@ -259,19 +313,40 @@ export const searchFilesTool = {
|
|
|
259
313
|
if (!targetDir.startsWith(secureBaseDir + path.sep) && targetDir !== secureBaseDir) {
|
|
260
314
|
throw new Error('Path traversal attempt detected. Access denied.');
|
|
261
315
|
}
|
|
262
|
-
|
|
316
|
+
|
|
317
|
+
// Validate pattern complexity to prevent DoS
|
|
318
|
+
if (pattern.includes('**/**') || pattern.split('*').length > 10) {
|
|
319
|
+
throw new Error('Pattern too complex. Please use a simpler glob pattern.');
|
|
320
|
+
}
|
|
321
|
+
|
|
263
322
|
try {
|
|
264
323
|
const options = {
|
|
265
324
|
cwd: targetDir,
|
|
266
325
|
ignore: ['node_modules/**', '.git/**'],
|
|
267
326
|
absolute: false
|
|
268
327
|
};
|
|
269
|
-
|
|
328
|
+
|
|
270
329
|
if (!recursive) {
|
|
271
330
|
options.deep = 1;
|
|
272
331
|
}
|
|
273
|
-
|
|
274
|
-
|
|
332
|
+
|
|
333
|
+
// Create a timeout promise (10 seconds)
|
|
334
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
335
|
+
setTimeout(() => reject(new Error('Search operation timed out after 10 seconds')), 10000);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// Race glob against timeout
|
|
339
|
+
const files = await Promise.race([
|
|
340
|
+
glob(pattern, options),
|
|
341
|
+
timeoutPromise
|
|
342
|
+
]);
|
|
343
|
+
|
|
344
|
+
// Limit results to prevent memory issues
|
|
345
|
+
const maxResults = 1000;
|
|
346
|
+
if (files.length > maxResults) {
|
|
347
|
+
return files.slice(0, maxResults);
|
|
348
|
+
}
|
|
349
|
+
|
|
275
350
|
return files;
|
|
276
351
|
} catch (error) {
|
|
277
352
|
throw new Error(`Failed to search files: ${error.message}`);
|
|
@@ -813,7 +813,7 @@ When presented with a broken Mermaid diagram, analyze it thoroughly and provide
|
|
|
813
813
|
debug: this.options.debug,
|
|
814
814
|
tracer: this.options.tracer,
|
|
815
815
|
allowEdit: this.options.allowEdit,
|
|
816
|
-
maxIterations:
|
|
816
|
+
maxIterations: 10, // Allow more iterations for mermaid fixing to handle complex diagrams
|
|
817
817
|
disableMermaidValidation: true // CRITICAL: Disable mermaid validation in nested agent to prevent infinite recursion
|
|
818
818
|
});
|
|
819
819
|
}
|
package/build/index.js
CHANGED
|
@@ -34,6 +34,7 @@ import { searchTool, queryTool, extractTool, delegateTool } from './tools/vercel
|
|
|
34
34
|
import { bashTool } from './tools/bash.js';
|
|
35
35
|
import { ProbeAgent } from './agent/ProbeAgent.js';
|
|
36
36
|
import { SimpleTelemetry, SimpleAppTracer, initializeSimpleTelemetryFromOptions } from './agent/simpleTelemetry.js';
|
|
37
|
+
import { listFilesToolInstance, searchFilesToolInstance } from './agent/probeTool.js';
|
|
37
38
|
|
|
38
39
|
export {
|
|
39
40
|
search,
|
|
@@ -57,6 +58,9 @@ export {
|
|
|
57
58
|
extractTool,
|
|
58
59
|
delegateTool,
|
|
59
60
|
bashTool,
|
|
61
|
+
// Export tool instances
|
|
62
|
+
listFilesToolInstance,
|
|
63
|
+
searchFilesToolInstance,
|
|
60
64
|
// Export schemas
|
|
61
65
|
searchSchema,
|
|
62
66
|
querySchema,
|