source dump of claude code
at main 245 lines 7.0 kB view raw
1import type { PermissionRule } from 'src/utils/permissions/PermissionRule.js' 2import { getSettingsForSource } from 'src/utils/settings/settings.js' 3import type { SettingsJson } from 'src/utils/settings/types.js' 4import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' 5import { SAFE_ENV_VARS } from '../../utils/managedEnvConstants.js' 6import { getPermissionRulesForSource } from '../../utils/permissions/permissionsLoader.js' 7 8function hasHooks(settings: SettingsJson | null): boolean { 9 if (settings === null || settings.disableAllHooks) { 10 return false 11 } 12 if (settings.statusLine) { 13 return true 14 } 15 if (settings.fileSuggestion) { 16 return true 17 } 18 if (!settings.hooks) { 19 return false 20 } 21 for (const hookConfig of Object.values(settings.hooks)) { 22 if (hookConfig.length > 0) { 23 return true 24 } 25 } 26 return false 27} 28 29export function getHooksSources(): string[] { 30 const sources: string[] = [] 31 32 const projectSettings = getSettingsForSource('projectSettings') 33 if (hasHooks(projectSettings)) { 34 sources.push('.claude/settings.json') 35 } 36 37 const localSettings = getSettingsForSource('localSettings') 38 if (hasHooks(localSettings)) { 39 sources.push('.claude/settings.local.json') 40 } 41 42 return sources 43} 44 45function hasBashPermission(rules: PermissionRule[]): boolean { 46 return rules.some( 47 rule => 48 rule.ruleBehavior === 'allow' && 49 (rule.ruleValue.toolName === BASH_TOOL_NAME || 50 rule.ruleValue.toolName.startsWith(BASH_TOOL_NAME + '(')), 51 ) 52} 53 54/** 55 * Get which setting sources have bash allow rules. 56 * Returns an array of file paths that have bash permissions. 57 */ 58export function getBashPermissionSources(): string[] { 59 const sources: string[] = [] 60 61 const projectRules = getPermissionRulesForSource('projectSettings') 62 if (hasBashPermission(projectRules)) { 63 sources.push('.claude/settings.json') 64 } 65 66 const localRules = getPermissionRulesForSource('localSettings') 67 if (hasBashPermission(localRules)) { 68 sources.push('.claude/settings.local.json') 69 } 70 71 return sources 72} 73 74/** 75 * Format a list of items with proper "and" conjunction. 76 * @param items - Array of items to format 77 * @param limit - Optional limit for how many items to show before summarizing (ignored if 0) 78 */ 79export function formatListWithAnd(items: string[], limit?: number): string { 80 if (items.length === 0) return '' 81 82 // Ignore limit if it's 0 83 const effectiveLimit = limit === 0 ? undefined : limit 84 85 // If no limit or items are within limit, use normal formatting 86 if (!effectiveLimit || items.length <= effectiveLimit) { 87 if (items.length === 1) return items[0]! 88 if (items.length === 2) return `${items[0]} and ${items[1]}` 89 90 const lastItem = items[items.length - 1]! 91 const allButLast = items.slice(0, -1) 92 return `${allButLast.join(', ')}, and ${lastItem}` 93 } 94 95 // If we have more items than the limit, show first few and count the rest 96 const shown = items.slice(0, effectiveLimit) 97 const remaining = items.length - effectiveLimit 98 99 if (shown.length === 1) { 100 return `${shown[0]} and ${remaining} more` 101 } 102 103 return `${shown.join(', ')}, and ${remaining} more` 104} 105 106/** 107 * Check if settings have otelHeadersHelper configured 108 */ 109function hasOtelHeadersHelper(settings: SettingsJson | null): boolean { 110 return !!settings?.otelHeadersHelper 111} 112 113/** 114 * Get which setting sources have otelHeadersHelper configured. 115 * Returns an array of file paths that have otelHeadersHelper. 116 */ 117export function getOtelHeadersHelperSources(): string[] { 118 const sources: string[] = [] 119 120 const projectSettings = getSettingsForSource('projectSettings') 121 if (hasOtelHeadersHelper(projectSettings)) { 122 sources.push('.claude/settings.json') 123 } 124 125 const localSettings = getSettingsForSource('localSettings') 126 if (hasOtelHeadersHelper(localSettings)) { 127 sources.push('.claude/settings.local.json') 128 } 129 130 return sources 131} 132 133/** 134 * Check if settings have apiKeyHelper configured 135 */ 136function hasApiKeyHelper(settings: SettingsJson | null): boolean { 137 return !!settings?.apiKeyHelper 138} 139 140/** 141 * Get which setting sources have apiKeyHelper configured. 142 * Returns an array of file paths that have apiKeyHelper. 143 */ 144export function getApiKeyHelperSources(): string[] { 145 const sources: string[] = [] 146 147 const projectSettings = getSettingsForSource('projectSettings') 148 if (hasApiKeyHelper(projectSettings)) { 149 sources.push('.claude/settings.json') 150 } 151 152 const localSettings = getSettingsForSource('localSettings') 153 if (hasApiKeyHelper(localSettings)) { 154 sources.push('.claude/settings.local.json') 155 } 156 157 return sources 158} 159 160/** 161 * Check if settings have AWS commands configured 162 */ 163function hasAwsCommands(settings: SettingsJson | null): boolean { 164 return !!(settings?.awsAuthRefresh || settings?.awsCredentialExport) 165} 166 167/** 168 * Get which setting sources have AWS commands configured. 169 * Returns an array of file paths that have awsAuthRefresh or awsCredentialExport. 170 */ 171export function getAwsCommandsSources(): string[] { 172 const sources: string[] = [] 173 174 const projectSettings = getSettingsForSource('projectSettings') 175 if (hasAwsCommands(projectSettings)) { 176 sources.push('.claude/settings.json') 177 } 178 179 const localSettings = getSettingsForSource('localSettings') 180 if (hasAwsCommands(localSettings)) { 181 sources.push('.claude/settings.local.json') 182 } 183 184 return sources 185} 186 187/** 188 * Check if settings have GCP commands configured 189 */ 190function hasGcpCommands(settings: SettingsJson | null): boolean { 191 return !!settings?.gcpAuthRefresh 192} 193 194/** 195 * Get which setting sources have GCP commands configured. 196 * Returns an array of file paths that have gcpAuthRefresh. 197 */ 198export function getGcpCommandsSources(): string[] { 199 const sources: string[] = [] 200 201 const projectSettings = getSettingsForSource('projectSettings') 202 if (hasGcpCommands(projectSettings)) { 203 sources.push('.claude/settings.json') 204 } 205 206 const localSettings = getSettingsForSource('localSettings') 207 if (hasGcpCommands(localSettings)) { 208 sources.push('.claude/settings.local.json') 209 } 210 211 return sources 212} 213 214/** 215 * Check if settings have dangerous environment variables configured. 216 * Any env var NOT in SAFE_ENV_VARS is considered dangerous. 217 */ 218function hasDangerousEnvVars(settings: SettingsJson | null): boolean { 219 if (!settings?.env) { 220 return false 221 } 222 return Object.keys(settings.env).some( 223 key => !SAFE_ENV_VARS.has(key.toUpperCase()), 224 ) 225} 226 227/** 228 * Get which setting sources have dangerous environment variables configured. 229 * Returns an array of file paths that have env vars not in SAFE_ENV_VARS. 230 */ 231export function getDangerousEnvVarsSources(): string[] { 232 const sources: string[] = [] 233 234 const projectSettings = getSettingsForSource('projectSettings') 235 if (hasDangerousEnvVars(projectSettings)) { 236 sources.push('.claude/settings.json') 237 } 238 239 const localSettings = getSettingsForSource('localSettings') 240 if (hasDangerousEnvVars(localSettings)) { 241 sources.push('.claude/settings.local.json') 242 } 243 244 return sources 245}