source dump of claude code
at main 185 lines 5.1 kB view raw
1import { 2 type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, 3 logEvent, 4} from '../../../services/analytics/index.js' 5import { sanitizeToolNameForAnalytics } from '../../../services/analytics/metadata.js' 6import type { ToolPermissionContext } from '../../../Tool.js' 7import { 8 CLAUDE_FOLDER_PERMISSION_PATTERN, 9 FILE_EDIT_TOOL_NAME, 10 GLOBAL_CLAUDE_FOLDER_PERMISSION_PATTERN, 11} from '../../../tools/FileEditTool/constants.js' 12import { env } from '../../../utils/env.js' 13import { generateSuggestions } from '../../../utils/permissions/filesystem.js' 14import type { PermissionUpdate } from '../../../utils/permissions/PermissionUpdateSchema.js' 15import { 16 type CompletionType, 17 logUnaryEvent, 18} from '../../../utils/unaryLogging.js' 19import type { ToolUseConfirm } from '../PermissionRequest.js' 20import type { 21 FileOperationType, 22 PermissionOption, 23} from './permissionOptions.js' 24 25function logPermissionEvent( 26 event: 'accept' | 'reject', 27 completionType: CompletionType, 28 languageName: string | Promise<string>, 29 messageId: string, 30 hasFeedback?: boolean, 31): void { 32 void logUnaryEvent({ 33 completion_type: completionType, 34 event, 35 metadata: { 36 language_name: languageName, 37 message_id: messageId, 38 platform: env.platform, 39 hasFeedback: hasFeedback ?? false, 40 }, 41 }) 42} 43 44export type PermissionHandlerParams = { 45 messageId: string 46 path: string | null 47 toolUseConfirm: ToolUseConfirm 48 toolPermissionContext: ToolPermissionContext 49 onDone: () => void 50 onReject: () => void 51 completionType: CompletionType 52 languageName: string | Promise<string> 53 operationType: FileOperationType 54} 55 56export type PermissionHandlerOptions = { 57 hasFeedback?: boolean 58 feedback?: string 59 enteredFeedbackMode?: boolean 60 scope?: 'claude-folder' | 'global-claude-folder' 61} 62 63function handleAcceptOnce( 64 params: PermissionHandlerParams, 65 options?: PermissionHandlerOptions, 66): void { 67 const { messageId, toolUseConfirm, onDone, completionType, languageName } = 68 params 69 70 logPermissionEvent('accept', completionType, languageName, messageId) 71 72 // Log accept submission with feedback context 73 logEvent('tengu_accept_submitted', { 74 toolName: sanitizeToolNameForAnalytics( 75 toolUseConfirm.tool.name, 76 ) as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, 77 isMcp: toolUseConfirm.tool.isMcp ?? false, 78 has_instructions: !!options?.feedback, 79 instructions_length: options?.feedback?.length ?? 0, 80 entered_feedback_mode: options?.enteredFeedbackMode ?? false, 81 }) 82 83 onDone() 84 toolUseConfirm.onAllow(toolUseConfirm.input, [], options?.feedback) 85} 86 87function handleAcceptSession( 88 params: PermissionHandlerParams, 89 options?: PermissionHandlerOptions, 90): void { 91 const { 92 messageId, 93 path, 94 toolUseConfirm, 95 toolPermissionContext, 96 onDone, 97 completionType, 98 languageName, 99 operationType, 100 } = params 101 102 logPermissionEvent('accept', completionType, languageName, messageId) 103 104 // For claude-folder scope, grant session-level access to all .claude/ files 105 if ( 106 options?.scope === 'claude-folder' || 107 options?.scope === 'global-claude-folder' 108 ) { 109 const pattern = 110 options.scope === 'global-claude-folder' 111 ? GLOBAL_CLAUDE_FOLDER_PERMISSION_PATTERN 112 : CLAUDE_FOLDER_PERMISSION_PATTERN 113 const suggestions: PermissionUpdate[] = [ 114 { 115 type: 'addRules', 116 rules: [ 117 { 118 toolName: FILE_EDIT_TOOL_NAME, 119 ruleContent: pattern, 120 }, 121 ], 122 behavior: 'allow', 123 destination: 'session', 124 }, 125 ] 126 onDone() 127 toolUseConfirm.onAllow(toolUseConfirm.input, suggestions) 128 return 129 } 130 131 // Generate permission updates if path is provided 132 const suggestions = path 133 ? generateSuggestions(path, operationType, toolPermissionContext) 134 : [] 135 136 onDone() 137 // Pass permission updates directly to onAllow 138 toolUseConfirm.onAllow(toolUseConfirm.input, suggestions) 139} 140 141function handleReject( 142 params: PermissionHandlerParams, 143 options?: PermissionHandlerOptions, 144): void { 145 const { 146 messageId, 147 toolUseConfirm, 148 onDone, 149 onReject, 150 completionType, 151 languageName, 152 } = params 153 154 logPermissionEvent( 155 'reject', 156 completionType, 157 languageName, 158 messageId, 159 options?.hasFeedback, 160 ) 161 162 // Log reject submission with feedback context 163 logEvent('tengu_reject_submitted', { 164 toolName: sanitizeToolNameForAnalytics( 165 toolUseConfirm.tool.name, 166 ) as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, 167 isMcp: toolUseConfirm.tool.isMcp ?? false, 168 has_instructions: !!options?.feedback, 169 instructions_length: options?.feedback?.length ?? 0, 170 entered_feedback_mode: options?.enteredFeedbackMode ?? false, 171 }) 172 173 onDone() 174 onReject() 175 toolUseConfirm.onReject(options?.feedback) 176} 177 178export const PERMISSION_HANDLERS: Record< 179 PermissionOption['type'], 180 (params: PermissionHandlerParams, options?: PermissionHandlerOptions) => void 181> = { 182 'accept-once': handleAcceptOnce, 183 'accept-session': handleAcceptSession, 184 reject: handleReject, 185}