(params: zod.infer<typeof ExecCommandSchema>)
| 411 | // ============ Tool Handlers ============ |
| 412 | |
| 413 | async function handleExecCommand(params: zod.infer<typeof ExecCommandSchema>) { |
| 414 | const config = getExecConfig(); |
| 415 | |
| 416 | // Check if command is allowed |
| 417 | const {allowed, reason} = isCommandAllowed(params.command); |
| 418 | if (!allowed) { |
| 419 | return { |
| 420 | success: false, |
| 421 | error: `Command not allowed: ${reason}`, |
| 422 | }; |
| 423 | } |
| 424 | |
| 425 | // Determine working directory with scope enforcement |
| 426 | let dir: string; |
| 427 | const folders = listFolders(); |
| 428 | |
| 429 | if (folders.length > 0) { |
| 430 | // Scope enforcement: dir must resolve to a folder with `exec` scope |
| 431 | const target = params.dir || process.cwd(); |
| 432 | const resolved = resolveFolderForPath(target, 'exec'); |
| 433 | if (!resolved) { |
| 434 | const err = folderScopeError(target, 'exec'); |
| 435 | return { |
| 436 | success: false, |
| 437 | error: `${err.error.code}: ${err.error.message}`, |
| 438 | }; |
| 439 | } |
| 440 | dir = resolved.absPath; |
| 441 | } else { |
| 442 | // Backwards-compatibility fallback — no folders registered |
| 443 | dir = params.dir || config.defaultDir || DEFAULT_EXEC_DIR; |
| 444 | if (!warnedFoldersEmpty) { |
| 445 | warnedFoldersEmpty = true; |
| 446 | console.warn( |
| 447 | '[corebrain] DEPRECATION: no folders registered; falling back to ExecConfig.defaultDir. ' + |
| 448 | 'Register folders with `corebrain folder add <path> --scopes exec` to enforce path scope.', |
| 449 | ); |
| 450 | } |
| 451 | } |
| 452 | |
| 453 | // Ensure directory exists |
| 454 | if (!existsSync(dir)) { |
| 455 | return { |
| 456 | success: false, |
| 457 | error: `Directory "${dir}" does not exist`, |
| 458 | }; |
| 459 | } |
| 460 | |
| 461 | // Execute command |
| 462 | const timeout = params.timeout || 30000; |
| 463 | const maxStdoutBytes = readByteCap( |
| 464 | config.maxStdoutBytes, |
| 465 | 'COREBRAIN_EXEC_MAX_STDOUT_BYTES', |
| 466 | DEFAULT_MAX_STDOUT_BYTES, |
| 467 | ); |
| 468 | const maxStderrBytes = readByteCap( |
| 469 | config.maxStderrBytes, |
| 470 | 'COREBRAIN_EXEC_MAX_STDERR_BYTES', |
no test coverage detected