( command: PathCommand, operationTypeOverride?: FileOperationType, )
| 701 | } |
| 702 | |
| 703 | export function createPathChecker( |
| 704 | command: PathCommand, |
| 705 | operationTypeOverride?: FileOperationType, |
| 706 | ) { |
| 707 | return ( |
| 708 | args: string[], |
| 709 | cwd: string, |
| 710 | context: ToolPermissionContext, |
| 711 | compoundCommandHasCd?: boolean, |
| 712 | ): PermissionResult => { |
| 713 | // First check normal path validation (which includes explicit deny rules) |
| 714 | const result = validateCommandPaths( |
| 715 | command, |
| 716 | args, |
| 717 | cwd, |
| 718 | context, |
| 719 | compoundCommandHasCd, |
| 720 | operationTypeOverride, |
| 721 | ) |
| 722 | |
| 723 | // If explicitly denied, respect that (don't override with dangerous path message) |
| 724 | if (result.behavior === 'deny') { |
| 725 | return result |
| 726 | } |
| 727 | |
| 728 | // Check for dangerous removal paths AFTER explicit deny rules but BEFORE other results |
| 729 | // This ensures the check runs even if the user has allowlist rules or if glob patterns |
| 730 | // were rejected, but respects explicit deny rules. Dangerous patterns get a specific |
| 731 | // error message that overrides generic glob pattern rejection messages. |
| 732 | if (command === 'rm' || command === 'rmdir') { |
| 733 | const dangerousPathResult = checkDangerousRemovalPaths(command, args, cwd) |
| 734 | if (dangerousPathResult.behavior !== 'passthrough') { |
| 735 | return dangerousPathResult |
| 736 | } |
| 737 | } |
| 738 | |
| 739 | // If it's a passthrough, return it directly |
| 740 | if (result.behavior === 'passthrough') { |
| 741 | return result |
| 742 | } |
| 743 | |
| 744 | // If it's an ask decision, add suggestions based on the operation type |
| 745 | if (result.behavior === 'ask') { |
| 746 | const operationType = |
| 747 | operationTypeOverride ?? COMMAND_OPERATION_TYPE[command] |
| 748 | const suggestions: PermissionUpdate[] = [] |
| 749 | |
| 750 | // Only suggest adding directory/rules if we have a blocked path |
| 751 | if (result.blockedPath) { |
| 752 | if (operationType === 'read') { |
| 753 | // For read operations, suggest a Read rule for the directory (only if it exists) |
| 754 | const dirPath = getDirectoryForPath(result.blockedPath) |
| 755 | const suggestion = createReadRuleSuggestion(dirPath, 'session') |
| 756 | if (suggestion) { |
| 757 | suggestions.push(suggestion) |
| 758 | } |
| 759 | } else { |
| 760 | // For write/create operations, suggest adding the directory |
no test coverage detected