@probelabs/probe 0.6.0-rc196 → 0.6.0-rc197
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/bin/binaries/{probe-v0.6.0-rc196-aarch64-apple-darwin.tar.gz → probe-v0.6.0-rc197-aarch64-apple-darwin.tar.gz} +0 -0
- package/bin/binaries/probe-v0.6.0-rc197-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc197-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc197-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/{probe-v0.6.0-rc196-x86_64-unknown-linux-musl.tar.gz → probe-v0.6.0-rc197-x86_64-unknown-linux-musl.tar.gz} +0 -0
- package/build/agent/ProbeAgent.js +6 -2
- package/build/agent/index.js +132 -97
- package/build/tools/bash.js +9 -3
- package/build/tools/common.js +71 -4
- package/build/tools/index.js +4 -2
- package/build/tools/vercel.js +28 -19
- package/cjs/agent/ProbeAgent.cjs +324 -250
- package/cjs/index.cjs +329 -253
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +6 -2
- package/src/tools/bash.js +9 -3
- package/src/tools/common.js +71 -4
- package/src/tools/index.js +4 -2
- package/src/tools/vercel.js +28 -19
- package/bin/binaries/probe-v0.6.0-rc196-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc196-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc196-x86_64-pc-windows-msvc.zip +0 -0
package/package.json
CHANGED
package/src/agent/ProbeAgent.js
CHANGED
|
@@ -2458,9 +2458,13 @@ Follow these instructions carefully:
|
|
|
2458
2458
|
try {
|
|
2459
2459
|
// Add sessionId and workingDirectory to params for tool execution
|
|
2460
2460
|
// Validate and resolve workingDirectory
|
|
2461
|
-
|
|
2461
|
+
// Priority: explicit cwd > first allowed folder > process.cwd()
|
|
2462
|
+
let resolvedWorkingDirectory = this.cwd || (this.allowedFolders && this.allowedFolders[0]) || process.cwd();
|
|
2462
2463
|
if (params.workingDirectory) {
|
|
2463
|
-
|
|
2464
|
+
// Resolve relative paths against the current working directory context, not process.cwd()
|
|
2465
|
+
const requestedDir = isAbsolute(params.workingDirectory)
|
|
2466
|
+
? resolve(params.workingDirectory)
|
|
2467
|
+
: resolve(resolvedWorkingDirectory, params.workingDirectory);
|
|
2464
2468
|
// Check if the requested directory is within allowed folders
|
|
2465
2469
|
const isWithinAllowed = !this.allowedFolders || this.allowedFolders.length === 0 ||
|
|
2466
2470
|
this.allowedFolders.some(folder => {
|
package/src/tools/bash.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { tool } from 'ai';
|
|
7
|
-
import { resolve } from 'path';
|
|
7
|
+
import { resolve, isAbsolute, sep } from 'path';
|
|
8
8
|
import { BashPermissionChecker } from '../agent/bashPermissions.js';
|
|
9
9
|
import { executeBashCommand, formatExecutionResult, validateExecutionOptions } from '../agent/bashExecutor.js';
|
|
10
10
|
|
|
@@ -144,14 +144,20 @@ For code exploration, try these safe alternatives:
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
// Determine working directory
|
|
147
|
-
const
|
|
147
|
+
const defaultDir = getDefaultWorkingDirectory();
|
|
148
|
+
// Resolve relative paths against the default working directory context, not process.cwd()
|
|
149
|
+
const workingDir = workingDirectory
|
|
150
|
+
? (isAbsolute(workingDirectory) ? resolve(workingDirectory) : resolve(defaultDir, workingDirectory))
|
|
151
|
+
: defaultDir;
|
|
148
152
|
|
|
149
153
|
// Validate working directory is within allowed folders if specified
|
|
150
154
|
if (allowedFolders && allowedFolders.length > 0) {
|
|
151
155
|
const resolvedWorkingDir = resolve(workingDir);
|
|
152
156
|
const isAllowed = allowedFolders.some(folder => {
|
|
153
157
|
const resolvedFolder = resolve(folder);
|
|
154
|
-
|
|
158
|
+
// Use exact match OR startsWith with separator to prevent bypass attacks
|
|
159
|
+
// e.g., '/tmp-malicious' should NOT match allowed folder '/tmp'
|
|
160
|
+
return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + sep);
|
|
155
161
|
});
|
|
156
162
|
|
|
157
163
|
if (!isAllowed) {
|
package/src/tools/common.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { z } from 'zod';
|
|
7
|
+
import { resolve, isAbsolute } from 'path';
|
|
7
8
|
|
|
8
9
|
// Common schemas for tool parameters (used for internal execution after XML parsing)
|
|
9
10
|
export const searchSchema = z.object({
|
|
@@ -516,9 +517,9 @@ export function createMessagePreview(message, charsPerSide = 200) {
|
|
|
516
517
|
|
|
517
518
|
/**
|
|
518
519
|
* Parse targets string into array of file specifications
|
|
519
|
-
* Handles space-separated targets for extract tool
|
|
520
|
+
* Handles both space-separated and comma-separated targets for extract tool
|
|
520
521
|
*
|
|
521
|
-
* @param {string} targets - Space-separated file targets (e.g., "file1.rs:10-20 file2.rs#symbol")
|
|
522
|
+
* @param {string} targets - Space or comma-separated file targets (e.g., "file1.rs:10-20, file2.rs#symbol")
|
|
522
523
|
* @returns {string[]} Array of individual file specifications
|
|
523
524
|
*
|
|
524
525
|
* @example
|
|
@@ -526,6 +527,10 @@ export function createMessagePreview(message, charsPerSide = 200) {
|
|
|
526
527
|
* // Returns: ["file1.rs:10-20", "file2.rs:30-40"]
|
|
527
528
|
*
|
|
528
529
|
* @example
|
|
530
|
+
* parseTargets("file1.rs:10-20, file2.rs:30-40")
|
|
531
|
+
* // Returns: ["file1.rs:10-20", "file2.rs:30-40"]
|
|
532
|
+
*
|
|
533
|
+
* @example
|
|
529
534
|
* parseTargets("session.rs#AuthService.login auth.rs:2-100 config.rs#DatabaseConfig")
|
|
530
535
|
* // Returns: ["session.rs#AuthService.login", "auth.rs:2-100", "config.rs#DatabaseConfig"]
|
|
531
536
|
*/
|
|
@@ -534,6 +539,68 @@ export function parseTargets(targets) {
|
|
|
534
539
|
return [];
|
|
535
540
|
}
|
|
536
541
|
|
|
537
|
-
// Split on any whitespace (
|
|
538
|
-
return targets.split(
|
|
542
|
+
// Split on any whitespace or comma (with optional surrounding whitespace) and filter out empty strings
|
|
543
|
+
return targets.split(/[\s,]+/).filter(f => f.length > 0);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Parse and resolve paths from a comma-separated string
|
|
548
|
+
* Handles both relative and absolute paths, resolving relative paths against the cwd
|
|
549
|
+
*
|
|
550
|
+
* @param {string} pathStr - Path string, possibly comma-separated
|
|
551
|
+
* @param {string} cwd - Working directory for resolving relative paths
|
|
552
|
+
* @returns {string[]} Array of resolved paths
|
|
553
|
+
*/
|
|
554
|
+
export function parseAndResolvePaths(pathStr, cwd) {
|
|
555
|
+
if (!pathStr) return [];
|
|
556
|
+
|
|
557
|
+
// Split on comma and trim whitespace
|
|
558
|
+
const paths = pathStr.split(',').map(p => p.trim()).filter(p => p.length > 0);
|
|
559
|
+
|
|
560
|
+
// Resolve relative paths against cwd
|
|
561
|
+
return paths.map(p => {
|
|
562
|
+
if (isAbsolute(p)) {
|
|
563
|
+
return p;
|
|
564
|
+
}
|
|
565
|
+
// Resolve relative path against cwd
|
|
566
|
+
return cwd ? resolve(cwd, p) : p;
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Resolve a target path that may include line numbers or symbols
|
|
572
|
+
* Handles formats: "file.rs", "file.rs:10", "file.rs:10-20", "file.rs#symbol"
|
|
573
|
+
* On Windows, correctly handles drive letter colons (e.g., "C:\path\file.rs:42")
|
|
574
|
+
*
|
|
575
|
+
* @param {string} target - Target string with optional line number or symbol
|
|
576
|
+
* @param {string} cwd - Working directory for resolving relative paths
|
|
577
|
+
* @returns {string} Resolved target path with suffix preserved
|
|
578
|
+
*/
|
|
579
|
+
export function resolveTargetPath(target, cwd) {
|
|
580
|
+
// On Windows, skip the drive letter colon (e.g., "C:" at index 1)
|
|
581
|
+
const searchStart = (target.length > 2 && target[1] === ':' && /[a-zA-Z]/.test(target[0])) ? 2 : 0;
|
|
582
|
+
const colonIdx = target.indexOf(':', searchStart);
|
|
583
|
+
const hashIdx = target.indexOf('#');
|
|
584
|
+
let filePart, suffix;
|
|
585
|
+
|
|
586
|
+
if (colonIdx !== -1 && (hashIdx === -1 || colonIdx < hashIdx)) {
|
|
587
|
+
// Has line number (file.rs:10 or file.rs:10-20)
|
|
588
|
+
filePart = target.substring(0, colonIdx);
|
|
589
|
+
suffix = target.substring(colonIdx);
|
|
590
|
+
} else if (hashIdx !== -1) {
|
|
591
|
+
// Has symbol (file.rs#symbol)
|
|
592
|
+
filePart = target.substring(0, hashIdx);
|
|
593
|
+
suffix = target.substring(hashIdx);
|
|
594
|
+
} else {
|
|
595
|
+
// Just file path
|
|
596
|
+
filePart = target;
|
|
597
|
+
suffix = '';
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Resolve relative path
|
|
601
|
+
if (!isAbsolute(filePart) && cwd) {
|
|
602
|
+
filePart = resolve(cwd, filePart);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
return filePart + suffix;
|
|
539
606
|
}
|
package/src/tools/index.js
CHANGED
|
@@ -11,7 +11,7 @@ export { editTool, createTool } from './edit.js';
|
|
|
11
11
|
// Export LangChain tools
|
|
12
12
|
export { createSearchTool, createQueryTool, createExtractTool } from './langchain.js';
|
|
13
13
|
|
|
14
|
-
// Export common schemas
|
|
14
|
+
// Export common schemas and utilities
|
|
15
15
|
export {
|
|
16
16
|
searchSchema,
|
|
17
17
|
querySchema,
|
|
@@ -23,7 +23,9 @@ export {
|
|
|
23
23
|
bashDescription,
|
|
24
24
|
bashToolDefinition,
|
|
25
25
|
attemptCompletionSchema,
|
|
26
|
-
attemptCompletionToolDefinition
|
|
26
|
+
attemptCompletionToolDefinition,
|
|
27
|
+
parseAndResolvePaths,
|
|
28
|
+
resolveTargetPath
|
|
27
29
|
} from './common.js';
|
|
28
30
|
|
|
29
31
|
// Export edit and create schemas
|
package/src/tools/vercel.js
CHANGED
|
@@ -8,7 +8,7 @@ import { search } from '../search.js';
|
|
|
8
8
|
import { query } from '../query.js';
|
|
9
9
|
import { extract } from '../extract.js';
|
|
10
10
|
import { delegate } from '../delegate.js';
|
|
11
|
-
import { searchSchema, querySchema, extractSchema, delegateSchema, searchDescription, queryDescription, extractDescription, delegateDescription, parseTargets } from './common.js';
|
|
11
|
+
import { searchSchema, querySchema, extractSchema, delegateSchema, searchDescription, queryDescription, extractDescription, delegateDescription, parseTargets, parseAndResolvePaths, resolveTargetPath } from './common.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Search tool generator
|
|
@@ -31,17 +31,20 @@ export const searchTool = (options = {}) => {
|
|
|
31
31
|
// Use parameter maxTokens if provided, otherwise use the default
|
|
32
32
|
const effectiveMaxTokens = paramMaxTokens || maxTokens;
|
|
33
33
|
|
|
34
|
-
//
|
|
35
|
-
let
|
|
34
|
+
// Parse and resolve paths (supports comma-separated and relative paths)
|
|
35
|
+
let searchPaths;
|
|
36
|
+
if (path) {
|
|
37
|
+
searchPaths = parseAndResolvePaths(path, options.cwd);
|
|
38
|
+
}
|
|
36
39
|
|
|
37
|
-
//
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
console.error(`Using cwd "${options.cwd}" instead of "${searchPath}"`);
|
|
41
|
-
}
|
|
42
|
-
searchPath = options.cwd;
|
|
40
|
+
// Default to cwd or '.' if no paths provided
|
|
41
|
+
if (!searchPaths || searchPaths.length === 0) {
|
|
42
|
+
searchPaths = [options.cwd || '.'];
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
// Join paths with space for CLI (probe search supports multiple paths)
|
|
46
|
+
const searchPath = searchPaths.join(' ');
|
|
47
|
+
|
|
45
48
|
if (debug) {
|
|
46
49
|
console.error(`Executing search with query: "${searchQuery}", path: "${searchPath}", exact: ${exact ? 'true' : 'false'}, language: ${language || 'all'}, session: ${sessionId || 'none'}`);
|
|
47
50
|
}
|
|
@@ -90,17 +93,20 @@ export const queryTool = (options = {}) => {
|
|
|
90
93
|
inputSchema: querySchema,
|
|
91
94
|
execute: async ({ pattern, path, language, allow_tests }) => {
|
|
92
95
|
try {
|
|
93
|
-
//
|
|
94
|
-
let
|
|
96
|
+
// Parse and resolve paths (supports comma-separated and relative paths)
|
|
97
|
+
let queryPaths;
|
|
98
|
+
if (path) {
|
|
99
|
+
queryPaths = parseAndResolvePaths(path, options.cwd);
|
|
100
|
+
}
|
|
95
101
|
|
|
96
|
-
//
|
|
97
|
-
if (
|
|
98
|
-
|
|
99
|
-
console.error(`Using cwd "${options.cwd}" instead of "${queryPath}"`);
|
|
100
|
-
}
|
|
101
|
-
queryPath = options.cwd;
|
|
102
|
+
// Default to cwd or '.' if no paths provided
|
|
103
|
+
if (!queryPaths || queryPaths.length === 0) {
|
|
104
|
+
queryPaths = [options.cwd || '.'];
|
|
102
105
|
}
|
|
103
106
|
|
|
107
|
+
// Join paths with space for CLI (probe query supports multiple paths)
|
|
108
|
+
const queryPath = queryPaths.join(' ');
|
|
109
|
+
|
|
104
110
|
if (debug) {
|
|
105
111
|
console.error(`Executing query with pattern: "${pattern}", path: "${queryPath}", language: ${language || 'auto'}`);
|
|
106
112
|
}
|
|
@@ -185,8 +191,11 @@ export const extractTool = (options = {}) => {
|
|
|
185
191
|
};
|
|
186
192
|
} else if (targets) {
|
|
187
193
|
// Parse targets to handle line numbers and symbol names
|
|
188
|
-
//
|
|
189
|
-
const
|
|
194
|
+
// Now supports both whitespace and comma-separated targets
|
|
195
|
+
const parsedTargets = parseTargets(targets);
|
|
196
|
+
|
|
197
|
+
// Resolve relative paths in targets against cwd
|
|
198
|
+
const files = parsedTargets.map(target => resolveTargetPath(target, effectiveCwd));
|
|
190
199
|
|
|
191
200
|
// Apply format mapping for outline-xml to xml
|
|
192
201
|
let effectiveFormat = format;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|