source dump of claude code
at main 115 lines 3.3 kB view raw
1import type { z } from 'zod/v4' 2import type { ToolPermissionContext } from '../../Tool.js' 3import { splitCommand_DEPRECATED } from '../../utils/bash/commands.js' 4import type { PermissionResult } from '../../utils/permissions/PermissionResult.js' 5import type { BashTool } from './BashTool.js' 6 7const ACCEPT_EDITS_ALLOWED_COMMANDS = [ 8 'mkdir', 9 'touch', 10 'rm', 11 'rmdir', 12 'mv', 13 'cp', 14 'sed', 15] as const 16 17type FilesystemCommand = (typeof ACCEPT_EDITS_ALLOWED_COMMANDS)[number] 18 19function isFilesystemCommand(command: string): command is FilesystemCommand { 20 return ACCEPT_EDITS_ALLOWED_COMMANDS.includes(command as FilesystemCommand) 21} 22 23function validateCommandForMode( 24 cmd: string, 25 toolPermissionContext: ToolPermissionContext, 26): PermissionResult { 27 const trimmedCmd = cmd.trim() 28 const [baseCmd] = trimmedCmd.split(/\s+/) 29 30 if (!baseCmd) { 31 return { 32 behavior: 'passthrough', 33 message: 'Base command not found', 34 } 35 } 36 37 // In Accept Edits mode, auto-allow filesystem operations 38 if ( 39 toolPermissionContext.mode === 'acceptEdits' && 40 isFilesystemCommand(baseCmd) 41 ) { 42 return { 43 behavior: 'allow', 44 updatedInput: { command: cmd }, 45 decisionReason: { 46 type: 'mode', 47 mode: 'acceptEdits', 48 }, 49 } 50 } 51 52 return { 53 behavior: 'passthrough', 54 message: `No mode-specific handling for '${baseCmd}' in ${toolPermissionContext.mode} mode`, 55 } 56} 57 58/** 59 * Checks if commands should be handled differently based on the current permission mode 60 * 61 * This is the main entry point for mode-based permission logic. 62 * Currently handles Accept Edits mode for filesystem commands, 63 * but designed to be extended for other modes. 64 * 65 * @param input - The bash command input 66 * @param toolPermissionContext - Context containing mode and permissions 67 * @returns 68 * - 'allow' if the current mode permits auto-approval 69 * - 'ask' if the command needs approval in current mode 70 * - 'passthrough' if no mode-specific handling applies 71 */ 72export function checkPermissionMode( 73 input: z.infer<typeof BashTool.inputSchema>, 74 toolPermissionContext: ToolPermissionContext, 75): PermissionResult { 76 // Skip if in bypass mode (handled elsewhere) 77 if (toolPermissionContext.mode === 'bypassPermissions') { 78 return { 79 behavior: 'passthrough', 80 message: 'Bypass mode is handled in main permission flow', 81 } 82 } 83 84 // Skip if in dontAsk mode (handled in main permission flow) 85 if (toolPermissionContext.mode === 'dontAsk') { 86 return { 87 behavior: 'passthrough', 88 message: 'DontAsk mode is handled in main permission flow', 89 } 90 } 91 92 const commands = splitCommand_DEPRECATED(input.command) 93 94 // Check each subcommand 95 for (const cmd of commands) { 96 const result = validateCommandForMode(cmd, toolPermissionContext) 97 98 // If any command triggers mode-specific behavior, return that result 99 if (result.behavior !== 'passthrough') { 100 return result 101 } 102 } 103 104 // No mode-specific handling needed 105 return { 106 behavior: 'passthrough', 107 message: 'No mode-specific validation required', 108 } 109} 110 111export function getAutoAllowedCommands( 112 mode: ToolPermissionContext['mode'], 113): readonly string[] { 114 return mode === 'acceptEdits' ? ACCEPT_EDITS_ALLOWED_COMMANDS : [] 115}