@probelabs/probe 0.6.0-rc178 → 0.6.0-rc186
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 +17 -1
- package/build/agent/bashCommandUtils.js +63 -0
- package/build/agent/bashExecutor.js +34 -19
- package/build/agent/bashPermissions.js +74 -13
- package/build/agent/index.js +185 -37
- package/cjs/agent/ProbeAgent.cjs +2798 -1843
- package/cjs/index.cjs +2798 -1843
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +17 -1
- package/src/agent/bashCommandUtils.js +63 -0
- package/src/agent/bashExecutor.js +34 -19
- package/src/agent/bashPermissions.js +74 -13
|
@@ -2501,10 +2501,26 @@ When troubleshooting:
|
|
|
2501
2501
|
// Execute native tool
|
|
2502
2502
|
try {
|
|
2503
2503
|
// Add sessionId and workingDirectory to params for tool execution
|
|
2504
|
+
// Validate and resolve workingDirectory
|
|
2505
|
+
let resolvedWorkingDirectory = (this.allowedFolders && this.allowedFolders[0]) || process.cwd();
|
|
2506
|
+
if (params.workingDirectory) {
|
|
2507
|
+
const requestedDir = resolve(params.workingDirectory);
|
|
2508
|
+
// Check if the requested directory is within allowed folders
|
|
2509
|
+
const isWithinAllowed = !this.allowedFolders || this.allowedFolders.length === 0 ||
|
|
2510
|
+
this.allowedFolders.some(folder => {
|
|
2511
|
+
const resolvedFolder = resolve(folder);
|
|
2512
|
+
return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + sep);
|
|
2513
|
+
});
|
|
2514
|
+
if (isWithinAllowed) {
|
|
2515
|
+
resolvedWorkingDirectory = requestedDir;
|
|
2516
|
+
} else if (this.debug) {
|
|
2517
|
+
console.error(`[DEBUG] Rejected workingDirectory "${params.workingDirectory}" - not within allowed folders`);
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2504
2520
|
const toolParams = {
|
|
2505
2521
|
...params,
|
|
2506
2522
|
sessionId: this.sessionId,
|
|
2507
|
-
workingDirectory:
|
|
2523
|
+
workingDirectory: resolvedWorkingDirectory
|
|
2508
2524
|
};
|
|
2509
2525
|
|
|
2510
2526
|
// Log tool execution in debug mode
|
|
@@ -159,6 +159,69 @@ export function isComplexCommand(command) {
|
|
|
159
159
|
return result.isComplex;
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Check if a pattern is a complex pattern (contains shell operators)
|
|
164
|
+
* Complex patterns are used to match full command strings including operators
|
|
165
|
+
* @param {string} pattern - Pattern to check
|
|
166
|
+
* @returns {boolean} True if pattern contains shell operators
|
|
167
|
+
*/
|
|
168
|
+
export function isComplexPattern(pattern) {
|
|
169
|
+
if (!pattern || typeof pattern !== 'string') return false;
|
|
170
|
+
|
|
171
|
+
// Check for operators in the pattern (aligned with complexPatterns in parseSimpleCommand)
|
|
172
|
+
const operatorPatterns = [
|
|
173
|
+
/\|/, // Pipes
|
|
174
|
+
/&&/, // Logical AND
|
|
175
|
+
/\|\|/, // Logical OR
|
|
176
|
+
/;/, // Command separator
|
|
177
|
+
/&$/, // Background execution
|
|
178
|
+
/\$\(/, // Command substitution $()
|
|
179
|
+
/`/, // Command substitution ``
|
|
180
|
+
/>/, // Redirection >
|
|
181
|
+
/</, // Redirection <
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
return operatorPatterns.some(p => p.test(pattern));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Convert a glob-style pattern to regex for matching
|
|
189
|
+
* Supports * as wildcard (matches any characters except operators)
|
|
190
|
+
* @param {string} pattern - Glob pattern
|
|
191
|
+
* @returns {RegExp} Compiled regex
|
|
192
|
+
*/
|
|
193
|
+
function globToRegex(pattern) {
|
|
194
|
+
// Escape regex special characters except *
|
|
195
|
+
let escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
|
|
196
|
+
// Convert * to .*? (non-greedy match)
|
|
197
|
+
escaped = escaped.replace(/\*/g, '.*?');
|
|
198
|
+
// Make it match the full string
|
|
199
|
+
return new RegExp('^' + escaped + '$', 'i');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Match a command string against a complex pattern
|
|
204
|
+
* Complex patterns use glob-style wildcards (*) for matching
|
|
205
|
+
* @param {string} command - Full command string
|
|
206
|
+
* @param {string} pattern - Complex pattern with wildcards
|
|
207
|
+
* @returns {boolean} True if command matches the pattern
|
|
208
|
+
*/
|
|
209
|
+
export function matchesComplexPattern(command, pattern) {
|
|
210
|
+
if (!command || !pattern) return false;
|
|
211
|
+
|
|
212
|
+
// Normalize whitespace
|
|
213
|
+
const normalizedCommand = command.trim().replace(/\s+/g, ' ');
|
|
214
|
+
const normalizedPattern = pattern.trim().replace(/\s+/g, ' ');
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
const regex = globToRegex(normalizedPattern);
|
|
218
|
+
return regex.test(normalizedCommand);
|
|
219
|
+
} catch (e) {
|
|
220
|
+
// If regex fails, fall back to exact match
|
|
221
|
+
return normalizedCommand === normalizedPattern;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
162
225
|
/**
|
|
163
226
|
* Legacy compatibility function - parses command for permission checking
|
|
164
227
|
* @param {string} command - Command to parse
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { spawn } from 'child_process';
|
|
7
7
|
import { resolve, join } from 'path';
|
|
8
8
|
import { existsSync } from 'fs';
|
|
9
|
-
import { parseCommandForExecution } from './bashCommandUtils.js';
|
|
9
|
+
import { parseCommandForExecution, isComplexCommand } from './bashCommandUtils.js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Execute a bash command with security controls
|
|
@@ -63,31 +63,46 @@ export async function executeBashCommand(command, options = {}) {
|
|
|
63
63
|
...env
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
const args = parseCommandForExecution(command);
|
|
69
|
-
if (!args || args.length === 0) {
|
|
70
|
-
resolve({
|
|
71
|
-
success: false,
|
|
72
|
-
error: 'Failed to parse command',
|
|
73
|
-
stdout: '',
|
|
74
|
-
stderr: '',
|
|
75
|
-
exitCode: 1,
|
|
76
|
-
command,
|
|
77
|
-
workingDirectory: cwd,
|
|
78
|
-
duration: Date.now() - startTime
|
|
79
|
-
});
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
66
|
+
// Check if this is a complex command (contains pipes, operators, etc.)
|
|
67
|
+
const isComplex = isComplexCommand(command);
|
|
82
68
|
|
|
83
|
-
|
|
69
|
+
let cmd, cmdArgs, useShell;
|
|
70
|
+
|
|
71
|
+
if (isComplex) {
|
|
72
|
+
// For complex commands, use sh -c to execute through shell
|
|
73
|
+
// This is only reached if the permission checker allowed the complex command
|
|
74
|
+
cmd = 'sh';
|
|
75
|
+
cmdArgs = ['-c', command];
|
|
76
|
+
useShell = false; // We explicitly use sh -c, not spawn's shell option
|
|
77
|
+
if (debug) {
|
|
78
|
+
console.log(`[BashExecutor] Complex command - using sh -c`);
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
// Parse simple command for direct execution
|
|
82
|
+
const args = parseCommandForExecution(command);
|
|
83
|
+
if (!args || args.length === 0) {
|
|
84
|
+
resolve({
|
|
85
|
+
success: false,
|
|
86
|
+
error: 'Failed to parse command',
|
|
87
|
+
stdout: '',
|
|
88
|
+
stderr: '',
|
|
89
|
+
exitCode: 1,
|
|
90
|
+
command,
|
|
91
|
+
workingDirectory: cwd,
|
|
92
|
+
duration: Date.now() - startTime
|
|
93
|
+
});
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
[cmd, ...cmdArgs] = args;
|
|
97
|
+
useShell = false;
|
|
98
|
+
}
|
|
84
99
|
|
|
85
100
|
// Spawn the process
|
|
86
101
|
const child = spawn(cmd, cmdArgs, {
|
|
87
102
|
cwd,
|
|
88
103
|
env: processEnv,
|
|
89
104
|
stdio: ['ignore', 'pipe', 'pipe'], // stdin ignored, capture stdout/stderr
|
|
90
|
-
shell:
|
|
105
|
+
shell: useShell, // false for security
|
|
91
106
|
windowsHide: true
|
|
92
107
|
});
|
|
93
108
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { DEFAULT_ALLOW_PATTERNS, DEFAULT_DENY_PATTERNS } from './bashDefaults.js';
|
|
7
|
-
import { parseCommand, isComplexCommand } from './bashCommandUtils.js';
|
|
7
|
+
import { parseCommand, isComplexCommand, isComplexPattern, matchesComplexPattern } from './bashCommandUtils.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Check if a pattern matches a parsed command
|
|
@@ -125,7 +125,7 @@ export class BashPermissionChecker {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
/**
|
|
128
|
-
* Check if a simple command is allowed (
|
|
128
|
+
* Check if a simple command is allowed (complex commands allowed if they match patterns)
|
|
129
129
|
* @param {string} command - Command to check
|
|
130
130
|
* @returns {Object} Permission result
|
|
131
131
|
*/
|
|
@@ -138,19 +138,17 @@ export class BashPermissionChecker {
|
|
|
138
138
|
};
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
isComplex: true
|
|
148
|
-
};
|
|
141
|
+
// Check if this is a complex command
|
|
142
|
+
const commandIsComplex = isComplexCommand(command);
|
|
143
|
+
|
|
144
|
+
if (commandIsComplex) {
|
|
145
|
+
// For complex commands, check against complex patterns in allow/deny lists
|
|
146
|
+
return this._checkComplexCommand(command);
|
|
149
147
|
}
|
|
150
148
|
|
|
151
149
|
// Parse the simple command
|
|
152
150
|
const parsed = parseCommand(command);
|
|
153
|
-
|
|
151
|
+
|
|
154
152
|
if (parsed.error) {
|
|
155
153
|
return {
|
|
156
154
|
allowed: false,
|
|
@@ -203,14 +201,77 @@ export class BashPermissionChecker {
|
|
|
203
201
|
parsed: parsed,
|
|
204
202
|
isComplex: false
|
|
205
203
|
};
|
|
206
|
-
|
|
204
|
+
|
|
207
205
|
if (this.debug) {
|
|
208
206
|
console.log(`[BashPermissions] ALLOWED - command passed all checks`);
|
|
209
207
|
}
|
|
210
|
-
|
|
208
|
+
|
|
211
209
|
return result;
|
|
212
210
|
}
|
|
213
211
|
|
|
212
|
+
/**
|
|
213
|
+
* Check a complex command against complex patterns in allow/deny lists
|
|
214
|
+
* @private
|
|
215
|
+
* @param {string} command - Complex command to check
|
|
216
|
+
* @returns {Object} Permission result
|
|
217
|
+
*/
|
|
218
|
+
_checkComplexCommand(command) {
|
|
219
|
+
if (this.debug) {
|
|
220
|
+
console.log(`[BashPermissions] Checking complex command: "${command}"`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Get complex patterns from allow and deny lists
|
|
224
|
+
const complexAllowPatterns = this.allowPatterns.filter(p => isComplexPattern(p));
|
|
225
|
+
const complexDenyPatterns = this.denyPatterns.filter(p => isComplexPattern(p));
|
|
226
|
+
|
|
227
|
+
if (this.debug) {
|
|
228
|
+
console.log(`[BashPermissions] Complex allow patterns: ${complexAllowPatterns.length}`);
|
|
229
|
+
console.log(`[BashPermissions] Complex deny patterns: ${complexDenyPatterns.length}`);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Check deny patterns first (deny takes precedence)
|
|
233
|
+
for (const pattern of complexDenyPatterns) {
|
|
234
|
+
if (matchesComplexPattern(command, pattern)) {
|
|
235
|
+
if (this.debug) {
|
|
236
|
+
console.log(`[BashPermissions] DENIED - matches complex deny pattern: ${pattern}`);
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
allowed: false,
|
|
240
|
+
reason: `Command matches deny pattern: ${pattern}`,
|
|
241
|
+
command: command,
|
|
242
|
+
isComplex: true,
|
|
243
|
+
matchedPatterns: [pattern]
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Check allow patterns
|
|
249
|
+
for (const pattern of complexAllowPatterns) {
|
|
250
|
+
if (matchesComplexPattern(command, pattern)) {
|
|
251
|
+
if (this.debug) {
|
|
252
|
+
console.log(`[BashPermissions] ALLOWED - matches complex allow pattern: ${pattern}`);
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
allowed: true,
|
|
256
|
+
command: command,
|
|
257
|
+
isComplex: true,
|
|
258
|
+
matchedPattern: pattern
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// No matching complex pattern found - reject complex command
|
|
264
|
+
if (this.debug) {
|
|
265
|
+
console.log(`[BashPermissions] DENIED - no matching complex pattern found`);
|
|
266
|
+
}
|
|
267
|
+
return {
|
|
268
|
+
allowed: false,
|
|
269
|
+
reason: 'Complex shell commands require explicit allow patterns (e.g., "cd * && git *")',
|
|
270
|
+
command: command,
|
|
271
|
+
isComplex: true
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
214
275
|
/**
|
|
215
276
|
* Get configuration summary
|
|
216
277
|
* @returns {Object} Configuration info
|
package/build/agent/index.js
CHANGED
|
@@ -9136,6 +9136,46 @@ function isComplexCommand(command) {
|
|
|
9136
9136
|
const result = parseSimpleCommand(command);
|
|
9137
9137
|
return result.isComplex;
|
|
9138
9138
|
}
|
|
9139
|
+
function isComplexPattern(pattern) {
|
|
9140
|
+
if (!pattern || typeof pattern !== "string") return false;
|
|
9141
|
+
const operatorPatterns = [
|
|
9142
|
+
/\|/,
|
|
9143
|
+
// Pipes
|
|
9144
|
+
/&&/,
|
|
9145
|
+
// Logical AND
|
|
9146
|
+
/\|\|/,
|
|
9147
|
+
// Logical OR
|
|
9148
|
+
/;/,
|
|
9149
|
+
// Command separator
|
|
9150
|
+
/&$/,
|
|
9151
|
+
// Background execution
|
|
9152
|
+
/\$\(/,
|
|
9153
|
+
// Command substitution $()
|
|
9154
|
+
/`/,
|
|
9155
|
+
// Command substitution ``
|
|
9156
|
+
/>/,
|
|
9157
|
+
// Redirection >
|
|
9158
|
+
/</
|
|
9159
|
+
// Redirection <
|
|
9160
|
+
];
|
|
9161
|
+
return operatorPatterns.some((p) => p.test(pattern));
|
|
9162
|
+
}
|
|
9163
|
+
function globToRegex(pattern) {
|
|
9164
|
+
let escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
9165
|
+
escaped = escaped.replace(/\*/g, ".*?");
|
|
9166
|
+
return new RegExp("^" + escaped + "$", "i");
|
|
9167
|
+
}
|
|
9168
|
+
function matchesComplexPattern(command, pattern) {
|
|
9169
|
+
if (!command || !pattern) return false;
|
|
9170
|
+
const normalizedCommand = command.trim().replace(/\s+/g, " ");
|
|
9171
|
+
const normalizedPattern = pattern.trim().replace(/\s+/g, " ");
|
|
9172
|
+
try {
|
|
9173
|
+
const regex = globToRegex(normalizedPattern);
|
|
9174
|
+
return regex.test(normalizedCommand);
|
|
9175
|
+
} catch (e) {
|
|
9176
|
+
return normalizedCommand === normalizedPattern;
|
|
9177
|
+
}
|
|
9178
|
+
}
|
|
9139
9179
|
function parseCommand(command) {
|
|
9140
9180
|
const result = parseSimpleCommand(command);
|
|
9141
9181
|
if (!result.success) {
|
|
@@ -9250,7 +9290,7 @@ var init_bashPermissions = __esm({
|
|
|
9250
9290
|
}
|
|
9251
9291
|
}
|
|
9252
9292
|
/**
|
|
9253
|
-
* Check if a simple command is allowed (
|
|
9293
|
+
* Check if a simple command is allowed (complex commands allowed if they match patterns)
|
|
9254
9294
|
* @param {string} command - Command to check
|
|
9255
9295
|
* @returns {Object} Permission result
|
|
9256
9296
|
*/
|
|
@@ -9262,13 +9302,9 @@ var init_bashPermissions = __esm({
|
|
|
9262
9302
|
command
|
|
9263
9303
|
};
|
|
9264
9304
|
}
|
|
9265
|
-
|
|
9266
|
-
|
|
9267
|
-
|
|
9268
|
-
reason: "Complex shell commands with pipes, operators, or redirections are not supported for security reasons",
|
|
9269
|
-
command,
|
|
9270
|
-
isComplex: true
|
|
9271
|
-
};
|
|
9305
|
+
const commandIsComplex = isComplexCommand(command);
|
|
9306
|
+
if (commandIsComplex) {
|
|
9307
|
+
return this._checkComplexCommand(command);
|
|
9272
9308
|
}
|
|
9273
9309
|
const parsed = parseCommand(command);
|
|
9274
9310
|
if (parsed.error) {
|
|
@@ -9320,6 +9356,59 @@ var init_bashPermissions = __esm({
|
|
|
9320
9356
|
}
|
|
9321
9357
|
return result;
|
|
9322
9358
|
}
|
|
9359
|
+
/**
|
|
9360
|
+
* Check a complex command against complex patterns in allow/deny lists
|
|
9361
|
+
* @private
|
|
9362
|
+
* @param {string} command - Complex command to check
|
|
9363
|
+
* @returns {Object} Permission result
|
|
9364
|
+
*/
|
|
9365
|
+
_checkComplexCommand(command) {
|
|
9366
|
+
if (this.debug) {
|
|
9367
|
+
console.log(`[BashPermissions] Checking complex command: "${command}"`);
|
|
9368
|
+
}
|
|
9369
|
+
const complexAllowPatterns = this.allowPatterns.filter((p) => isComplexPattern(p));
|
|
9370
|
+
const complexDenyPatterns = this.denyPatterns.filter((p) => isComplexPattern(p));
|
|
9371
|
+
if (this.debug) {
|
|
9372
|
+
console.log(`[BashPermissions] Complex allow patterns: ${complexAllowPatterns.length}`);
|
|
9373
|
+
console.log(`[BashPermissions] Complex deny patterns: ${complexDenyPatterns.length}`);
|
|
9374
|
+
}
|
|
9375
|
+
for (const pattern of complexDenyPatterns) {
|
|
9376
|
+
if (matchesComplexPattern(command, pattern)) {
|
|
9377
|
+
if (this.debug) {
|
|
9378
|
+
console.log(`[BashPermissions] DENIED - matches complex deny pattern: ${pattern}`);
|
|
9379
|
+
}
|
|
9380
|
+
return {
|
|
9381
|
+
allowed: false,
|
|
9382
|
+
reason: `Command matches deny pattern: ${pattern}`,
|
|
9383
|
+
command,
|
|
9384
|
+
isComplex: true,
|
|
9385
|
+
matchedPatterns: [pattern]
|
|
9386
|
+
};
|
|
9387
|
+
}
|
|
9388
|
+
}
|
|
9389
|
+
for (const pattern of complexAllowPatterns) {
|
|
9390
|
+
if (matchesComplexPattern(command, pattern)) {
|
|
9391
|
+
if (this.debug) {
|
|
9392
|
+
console.log(`[BashPermissions] ALLOWED - matches complex allow pattern: ${pattern}`);
|
|
9393
|
+
}
|
|
9394
|
+
return {
|
|
9395
|
+
allowed: true,
|
|
9396
|
+
command,
|
|
9397
|
+
isComplex: true,
|
|
9398
|
+
matchedPattern: pattern
|
|
9399
|
+
};
|
|
9400
|
+
}
|
|
9401
|
+
}
|
|
9402
|
+
if (this.debug) {
|
|
9403
|
+
console.log(`[BashPermissions] DENIED - no matching complex pattern found`);
|
|
9404
|
+
}
|
|
9405
|
+
return {
|
|
9406
|
+
allowed: false,
|
|
9407
|
+
reason: 'Complex shell commands require explicit allow patterns (e.g., "cd * && git *")',
|
|
9408
|
+
command,
|
|
9409
|
+
isComplex: true
|
|
9410
|
+
};
|
|
9411
|
+
}
|
|
9323
9412
|
/**
|
|
9324
9413
|
* Get configuration summary
|
|
9325
9414
|
* @returns {Object} Configuration info
|
|
@@ -9378,28 +9467,40 @@ async function executeBashCommand(command, options = {}) {
|
|
|
9378
9467
|
...process.env,
|
|
9379
9468
|
...env
|
|
9380
9469
|
};
|
|
9381
|
-
const
|
|
9382
|
-
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
|
|
9386
|
-
|
|
9387
|
-
|
|
9388
|
-
|
|
9389
|
-
|
|
9390
|
-
|
|
9391
|
-
|
|
9392
|
-
|
|
9393
|
-
|
|
9470
|
+
const isComplex = isComplexCommand(command);
|
|
9471
|
+
let cmd, cmdArgs, useShell;
|
|
9472
|
+
if (isComplex) {
|
|
9473
|
+
cmd = "sh";
|
|
9474
|
+
cmdArgs = ["-c", command];
|
|
9475
|
+
useShell = false;
|
|
9476
|
+
if (debug) {
|
|
9477
|
+
console.log(`[BashExecutor] Complex command - using sh -c`);
|
|
9478
|
+
}
|
|
9479
|
+
} else {
|
|
9480
|
+
const args = parseCommandForExecution(command);
|
|
9481
|
+
if (!args || args.length === 0) {
|
|
9482
|
+
resolve6({
|
|
9483
|
+
success: false,
|
|
9484
|
+
error: "Failed to parse command",
|
|
9485
|
+
stdout: "",
|
|
9486
|
+
stderr: "",
|
|
9487
|
+
exitCode: 1,
|
|
9488
|
+
command,
|
|
9489
|
+
workingDirectory: cwd,
|
|
9490
|
+
duration: Date.now() - startTime
|
|
9491
|
+
});
|
|
9492
|
+
return;
|
|
9493
|
+
}
|
|
9494
|
+
[cmd, ...cmdArgs] = args;
|
|
9495
|
+
useShell = false;
|
|
9394
9496
|
}
|
|
9395
|
-
const [cmd, ...cmdArgs] = args;
|
|
9396
9497
|
const child = spawn2(cmd, cmdArgs, {
|
|
9397
9498
|
cwd,
|
|
9398
9499
|
env: processEnv,
|
|
9399
9500
|
stdio: ["ignore", "pipe", "pipe"],
|
|
9400
9501
|
// stdin ignored, capture stdout/stderr
|
|
9401
|
-
shell:
|
|
9402
|
-
//
|
|
9502
|
+
shell: useShell,
|
|
9503
|
+
// false for security
|
|
9403
9504
|
windowsHide: true
|
|
9404
9505
|
});
|
|
9405
9506
|
let stdout = "";
|
|
@@ -23000,6 +23101,16 @@ var init_regexp_parser = __esm({
|
|
|
23000
23101
|
case "!":
|
|
23001
23102
|
type = "NegativeLookahead";
|
|
23002
23103
|
break;
|
|
23104
|
+
case "<": {
|
|
23105
|
+
switch (this.popChar()) {
|
|
23106
|
+
case "=":
|
|
23107
|
+
type = "Lookbehind";
|
|
23108
|
+
break;
|
|
23109
|
+
case "!":
|
|
23110
|
+
type = "NegativeLookbehind";
|
|
23111
|
+
}
|
|
23112
|
+
break;
|
|
23113
|
+
}
|
|
23003
23114
|
}
|
|
23004
23115
|
ASSERT_EXISTS(type);
|
|
23005
23116
|
const disjunction = this.disjunction();
|
|
@@ -23491,9 +23602,9 @@ var init_regexp_parser = __esm({
|
|
|
23491
23602
|
default:
|
|
23492
23603
|
return false;
|
|
23493
23604
|
}
|
|
23494
|
-
// '(?=' or '(?!'
|
|
23605
|
+
// '(?=' or '(?!' or `(?<=` or `(?<!`
|
|
23495
23606
|
case "(":
|
|
23496
|
-
return this.peekChar(1) === "?" && (this.peekChar(2) === "=" || this.peekChar(2) === "!");
|
|
23607
|
+
return this.peekChar(1) === "?" && (this.peekChar(2) === "=" || this.peekChar(2) === "!" || this.peekChar(2) === "<" && (this.peekChar(3) === "=" || this.peekChar(3) === "!"));
|
|
23497
23608
|
default:
|
|
23498
23609
|
return false;
|
|
23499
23610
|
}
|
|
@@ -23618,6 +23729,12 @@ var init_base_regexp_visitor = __esm({
|
|
|
23618
23729
|
case "NegativeLookahead":
|
|
23619
23730
|
this.visitNegativeLookahead(node);
|
|
23620
23731
|
break;
|
|
23732
|
+
case "Lookbehind":
|
|
23733
|
+
this.visitLookbehind(node);
|
|
23734
|
+
break;
|
|
23735
|
+
case "NegativeLookbehind":
|
|
23736
|
+
this.visitNegativeLookbehind(node);
|
|
23737
|
+
break;
|
|
23621
23738
|
case "Character":
|
|
23622
23739
|
this.visitCharacter(node);
|
|
23623
23740
|
break;
|
|
@@ -23657,6 +23774,10 @@ var init_base_regexp_visitor = __esm({
|
|
|
23657
23774
|
}
|
|
23658
23775
|
visitNegativeLookahead(node) {
|
|
23659
23776
|
}
|
|
23777
|
+
visitLookbehind(node) {
|
|
23778
|
+
}
|
|
23779
|
+
visitNegativeLookbehind(node) {
|
|
23780
|
+
}
|
|
23660
23781
|
// atoms
|
|
23661
23782
|
visitCharacter(node) {
|
|
23662
23783
|
}
|
|
@@ -23750,6 +23871,8 @@ function firstCharOptimizedIndices(ast, result, ignoreCase) {
|
|
|
23750
23871
|
// assertions do not affect potential starting codes
|
|
23751
23872
|
case "Lookahead":
|
|
23752
23873
|
case "NegativeLookahead":
|
|
23874
|
+
case "Lookbehind":
|
|
23875
|
+
case "NegativeLookbehind":
|
|
23753
23876
|
case "StartAnchor":
|
|
23754
23877
|
case "WordBoundary":
|
|
23755
23878
|
case "NonWordBoundary":
|
|
@@ -23894,6 +24017,12 @@ var init_reg_exp = __esm({
|
|
|
23894
24017
|
case "NegativeLookahead":
|
|
23895
24018
|
this.visitNegativeLookahead(node);
|
|
23896
24019
|
return;
|
|
24020
|
+
case "Lookbehind":
|
|
24021
|
+
this.visitLookbehind(node);
|
|
24022
|
+
return;
|
|
24023
|
+
case "NegativeLookbehind":
|
|
24024
|
+
this.visitNegativeLookbehind(node);
|
|
24025
|
+
return;
|
|
23897
24026
|
}
|
|
23898
24027
|
super.visitChildren(node);
|
|
23899
24028
|
}
|
|
@@ -24333,24 +24462,27 @@ function findUnreachablePatterns(tokenTypes) {
|
|
|
24333
24462
|
}
|
|
24334
24463
|
return result;
|
|
24335
24464
|
}, []);
|
|
24336
|
-
forEach_default(tokenTypes, (
|
|
24337
|
-
forEach_default(canBeTested, ({ str, idx, tokenType }) => {
|
|
24338
|
-
if (
|
|
24339
|
-
const msg = `Token: ->${
|
|
24340
|
-
Because it appears AFTER the Token Type ->${
|
|
24465
|
+
forEach_default(tokenTypes, (aTokType, aIdx) => {
|
|
24466
|
+
forEach_default(canBeTested, ({ str: bStr, idx: bIdx, tokenType: bTokType }) => {
|
|
24467
|
+
if (aIdx < bIdx && tryToMatchStrToPattern(bStr, aTokType.PATTERN)) {
|
|
24468
|
+
const msg = `Token: ->${bTokType.name}<- can never be matched.
|
|
24469
|
+
Because it appears AFTER the Token Type ->${aTokType.name}<-in the lexer's definition.
|
|
24341
24470
|
See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#UNREACHABLE`;
|
|
24342
24471
|
errors.push({
|
|
24343
24472
|
message: msg,
|
|
24344
24473
|
type: LexerDefinitionErrorType.UNREACHABLE_PATTERN,
|
|
24345
|
-
tokenTypes: [
|
|
24474
|
+
tokenTypes: [aTokType, bTokType]
|
|
24346
24475
|
});
|
|
24347
24476
|
}
|
|
24348
24477
|
});
|
|
24349
24478
|
});
|
|
24350
24479
|
return errors;
|
|
24351
24480
|
}
|
|
24352
|
-
function
|
|
24481
|
+
function tryToMatchStrToPattern(str, pattern) {
|
|
24353
24482
|
if (isRegExp_default(pattern)) {
|
|
24483
|
+
if (usesLookAheadOrBehind(pattern)) {
|
|
24484
|
+
return false;
|
|
24485
|
+
}
|
|
24354
24486
|
const regExpArray = pattern.exec(str);
|
|
24355
24487
|
return regExpArray !== null && regExpArray.index === 0;
|
|
24356
24488
|
} else if (isFunction_default(pattern)) {
|
|
@@ -24381,6 +24513,9 @@ function noMetaChar(regExp) {
|
|
|
24381
24513
|
];
|
|
24382
24514
|
return find_default(metaChars, (char) => regExp.source.indexOf(char) !== -1) === void 0;
|
|
24383
24515
|
}
|
|
24516
|
+
function usesLookAheadOrBehind(regExp) {
|
|
24517
|
+
return /(\(\?=)|(\(\?!)|(\(\?<=)|(\(\?<!)/.test(regExp.source);
|
|
24518
|
+
}
|
|
24384
24519
|
function addStartOfInput(pattern) {
|
|
24385
24520
|
const flags = pattern.ignoreCase ? "i" : "";
|
|
24386
24521
|
return new RegExp(`^(?:${pattern.source})`, flags);
|
|
@@ -24728,7 +24863,7 @@ var init_lexer_errors_public = __esm({
|
|
|
24728
24863
|
buildUnableToPopLexerModeMessage(token) {
|
|
24729
24864
|
return `Unable to pop Lexer Mode after encountering Token ->${token.image}<- The Mode Stack is empty`;
|
|
24730
24865
|
},
|
|
24731
|
-
buildUnexpectedCharactersMessage(fullText, startOffset, length, line, column) {
|
|
24866
|
+
buildUnexpectedCharactersMessage(fullText, startOffset, length, line, column, mode) {
|
|
24732
24867
|
return `unexpected character: ->${fullText.charAt(startOffset)}<- at offset: ${startOffset}, skipped ${length} characters.`;
|
|
24733
24868
|
}
|
|
24734
24869
|
};
|
|
@@ -25169,7 +25304,7 @@ var init_lexer_public = __esm({
|
|
|
25169
25304
|
}
|
|
25170
25305
|
errLength = offset - errorStartOffset;
|
|
25171
25306
|
column = this.computeNewColumn(column, errLength);
|
|
25172
|
-
msg = this.config.errorMessageProvider.buildUnexpectedCharactersMessage(orgText, errorStartOffset, errLength, errorLine, errorColumn);
|
|
25307
|
+
msg = this.config.errorMessageProvider.buildUnexpectedCharactersMessage(orgText, errorStartOffset, errLength, errorLine, errorColumn, last_default(modeStack));
|
|
25173
25308
|
errors.push({
|
|
25174
25309
|
offset: errorStartOffset,
|
|
25175
25310
|
line: errorLine,
|
|
@@ -25282,7 +25417,7 @@ var init_lexer_public = __esm({
|
|
|
25282
25417
|
return regExpArray !== null ? regExpArray[0] : null;
|
|
25283
25418
|
}
|
|
25284
25419
|
};
|
|
25285
|
-
Lexer.SKIPPED = "This marks a skipped Token pattern, this means each token identified by it
|
|
25420
|
+
Lexer.SKIPPED = "This marks a skipped Token pattern, this means each token identified by it will be consumed and then thrown into oblivion, this can be used to for example to completely ignore whitespace.";
|
|
25286
25421
|
Lexer.NA = /NOT_APPLICABLE/;
|
|
25287
25422
|
}
|
|
25288
25423
|
});
|
|
@@ -61086,10 +61221,23 @@ ${toolResultContent}
|
|
|
61086
61221
|
}
|
|
61087
61222
|
} else if (this.toolImplementations[toolName]) {
|
|
61088
61223
|
try {
|
|
61224
|
+
let resolvedWorkingDirectory = this.allowedFolders && this.allowedFolders[0] || process.cwd();
|
|
61225
|
+
if (params.workingDirectory) {
|
|
61226
|
+
const requestedDir = resolve4(params.workingDirectory);
|
|
61227
|
+
const isWithinAllowed = !this.allowedFolders || this.allowedFolders.length === 0 || this.allowedFolders.some((folder) => {
|
|
61228
|
+
const resolvedFolder = resolve4(folder);
|
|
61229
|
+
return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + sep3);
|
|
61230
|
+
});
|
|
61231
|
+
if (isWithinAllowed) {
|
|
61232
|
+
resolvedWorkingDirectory = requestedDir;
|
|
61233
|
+
} else if (this.debug) {
|
|
61234
|
+
console.error(`[DEBUG] Rejected workingDirectory "${params.workingDirectory}" - not within allowed folders`);
|
|
61235
|
+
}
|
|
61236
|
+
}
|
|
61089
61237
|
const toolParams = {
|
|
61090
61238
|
...params,
|
|
61091
61239
|
sessionId: this.sessionId,
|
|
61092
|
-
workingDirectory:
|
|
61240
|
+
workingDirectory: resolvedWorkingDirectory
|
|
61093
61241
|
};
|
|
61094
61242
|
if (this.debug) {
|
|
61095
61243
|
console.error(`
|