Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
13 kB · 441 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442/** * Pure permission type definitions extracted to break import cycles. * * This file contains only type definitions and constants with no runtime dependencies. * Implementation files remain in src/utils/permissions/ but can now import from here * to avoid circular dependencies. */
import { feature } from 'bun:bundle'import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/messages.mjs'
// ============================================================================// Permission Modes// ============================================================================
export const EXTERNAL_PERMISSION_MODES = [ 'acceptEdits', 'bypassPermissions', 'default', 'dontAsk', 'plan',] as const
export type ExternalPermissionMode = (typeof EXTERNAL_PERMISSION_MODES)[number]
// Exhaustive mode union for typechecking. The user-addressable runtime set// is INTERNAL_PERMISSION_MODES below.export type InternalPermissionMode = ExternalPermissionMode | 'auto' | 'bubble'export type PermissionMode = InternalPermissionMode
// Runtime validation set: modes that are user-addressable (settings.json// defaultMode, --permission-mode CLI flag, conversation recovery).export const INTERNAL_PERMISSION_MODES = [ ...EXTERNAL_PERMISSION_MODES, ...(feature('TRANSCRIPT_CLASSIFIER') ? (['auto'] as const) : ([] as const)),] as const satisfies readonly PermissionMode[]
export const PERMISSION_MODES = INTERNAL_PERMISSION_MODES
// ============================================================================// Permission Behaviors// ============================================================================
export type PermissionBehavior = 'allow' | 'deny' | 'ask'
// ============================================================================// Permission Rules// ============================================================================
/** * Where a permission rule originated from. * Includes all SettingSource values plus additional rule-specific sources. */export type PermissionRuleSource = | 'userSettings' | 'projectSettings' | 'localSettings' | 'flagSettings' | 'policySettings' | 'cliArg' | 'command' | 'session'
/** * The value of a permission rule - specifies which tool and optional content */export type PermissionRuleValue = { toolName: string ruleContent?: string}
/** * A permission rule with its source and behavior */export type PermissionRule = { source: PermissionRuleSource ruleBehavior: PermissionBehavior ruleValue: PermissionRuleValue}
// ============================================================================// Permission Updates// ============================================================================
/** * Where a permission update should be persisted */export type PermissionUpdateDestination = | 'userSettings' | 'projectSettings' | 'localSettings' | 'session' | 'cliArg'
/** * Update operations for permission configuration */export type PermissionUpdate = | { type: 'addRules' destination: PermissionUpdateDestination rules: PermissionRuleValue[] behavior: PermissionBehavior } | { type: 'replaceRules' destination: PermissionUpdateDestination rules: PermissionRuleValue[] behavior: PermissionBehavior } | { type: 'removeRules' destination: PermissionUpdateDestination rules: PermissionRuleValue[] behavior: PermissionBehavior } | { type: 'setMode' destination: PermissionUpdateDestination mode: ExternalPermissionMode } | { type: 'addDirectories' destination: PermissionUpdateDestination directories: string[] } | { type: 'removeDirectories' destination: PermissionUpdateDestination directories: string[] }
/** * Source of an additional working directory permission. * Note: This is currently the same as PermissionRuleSource but kept as a * separate type for semantic clarity and potential future divergence. */export type WorkingDirectorySource = PermissionRuleSource
/** * An additional directory included in permission scope */export type AdditionalWorkingDirectory = { path: string source: WorkingDirectorySource}
// ============================================================================// Permission Decisions & Results// ============================================================================
/** * Minimal command shape for permission metadata. * This is intentionally a subset of the full Command type to avoid import cycles. * Only includes properties needed by permission-related components. */export type PermissionCommandMetadata = { name: string description?: string // Allow additional properties for forward compatibility [key: string]: unknown}
/** * Metadata attached to permission decisions */export type PermissionMetadata = | { command: PermissionCommandMetadata } | undefined
/** * Result when permission is granted */export type PermissionAllowDecision< Input extends { [key: string]: unknown } = { [key: string]: unknown },> = { behavior: 'allow' updatedInput?: Input userModified?: boolean decisionReason?: PermissionDecisionReason toolUseID?: string acceptFeedback?: string contentBlocks?: ContentBlockParam[]}
/** * Metadata for a pending classifier check that will run asynchronously. * Used to enable non-blocking allow classifier evaluation. */export type PendingClassifierCheck = { command: string cwd: string descriptions: string[]}
/** * Result when user should be prompted */export type PermissionAskDecision< Input extends { [key: string]: unknown } = { [key: string]: unknown },> = { behavior: 'ask' message: string updatedInput?: Input decisionReason?: PermissionDecisionReason suggestions?: PermissionUpdate[] blockedPath?: string metadata?: PermissionMetadata /** * If true, this ask decision was triggered by a bashCommandIsSafe_DEPRECATED security check * for patterns that splitCommand_DEPRECATED could misparse (e.g. line continuations, shell-quote * transformations). Used by bashToolHasPermission to block early before splitCommand_DEPRECATED * transforms the command. Not set for simple newline compound commands. */ isBashSecurityCheckForMisparsing?: boolean /** * If set, an allow classifier check should be run asynchronously. * The classifier may auto-approve the permission before the user responds. */ pendingClassifierCheck?: PendingClassifierCheck /** * Optional content blocks (e.g., images) to include alongside the rejection * message in the tool result. Used when users paste images as feedback. */ contentBlocks?: ContentBlockParam[]}
/** * Result when permission is denied */export type PermissionDenyDecision = { behavior: 'deny' message: string decisionReason: PermissionDecisionReason toolUseID?: string}
/** * A permission decision - allow, ask, or deny */export type PermissionDecision< Input extends { [key: string]: unknown } = { [key: string]: unknown },> = | PermissionAllowDecision<Input> | PermissionAskDecision<Input> | PermissionDenyDecision
/** * Permission result with additional passthrough option */export type PermissionResult< Input extends { [key: string]: unknown } = { [key: string]: unknown },> = | PermissionDecision<Input> | { behavior: 'passthrough' message: string decisionReason?: PermissionDecision<Input>['decisionReason'] suggestions?: PermissionUpdate[] blockedPath?: string /** * If set, an allow classifier check should be run asynchronously. * The classifier may auto-approve the permission before the user responds. */ pendingClassifierCheck?: PendingClassifierCheck }
/** * Explanation of why a permission decision was made */export type PermissionDecisionReason = | { type: 'rule' rule: PermissionRule } | { type: 'mode' mode: PermissionMode } | { type: 'subcommandResults' reasons: Map<string, PermissionResult> } | { type: 'permissionPromptTool' permissionPromptToolName: string toolResult: unknown } | { type: 'hook' hookName: string hookSource?: string reason?: string } | { type: 'asyncAgent' reason: string } | { type: 'sandboxOverride' reason: 'excludedCommand' | 'dangerouslyDisableSandbox' } | { type: 'classifier' classifier: string reason: string } | { type: 'workingDir' reason: string } | { type: 'safetyCheck' reason: string // When true, auto mode lets the classifier evaluate this instead of // forcing a prompt. True for sensitive-file paths (.claude/, .git/, // shell configs) — the classifier can see context and decide. False // for Windows path bypass attempts and cross-machine bridge messages. classifierApprovable: boolean } | { type: 'other' reason: string }
// ============================================================================// Bash Classifier Types// ============================================================================
export type ClassifierResult = { matches: boolean matchedDescription?: string confidence: 'high' | 'medium' | 'low' reason: string}
export type ClassifierBehavior = 'deny' | 'ask' | 'allow'
export type ClassifierUsage = { inputTokens: number outputTokens: number cacheReadInputTokens: number cacheCreationInputTokens: number}
export type YoloClassifierResult = { thinking?: string shouldBlock: boolean reason: string unavailable?: boolean /** * API returned "prompt is too long" — the classifier transcript exceeded * the context window. Deterministic (same transcript → same error), so * callers should fall back to normal prompting rather than retry/fail-closed. */ transcriptTooLong?: boolean /** The model used for this classifier call */ model: string /** Token usage from the classifier API call (for overhead telemetry) */ usage?: ClassifierUsage /** Duration of the classifier API call in ms */ durationMs?: number /** Character lengths of the prompt components sent to the classifier */ promptLengths?: { systemPrompt: number toolCalls: number userPrompts: number } /** Path where error prompts were dumped (only set when unavailable due to API error) */ errorDumpPath?: string /** Which classifier stage produced the final decision (2-stage XML only) */ stage?: 'fast' | 'thinking' /** Token usage from stage 1 (fast) when stage 2 was also run */ stage1Usage?: ClassifierUsage /** Duration of stage 1 in ms when stage 2 was also run */ stage1DurationMs?: number /** * API request_id (req_xxx) for stage 1. Enables joining to server-side * api_usage logs for cache-miss / routing attribution. Also used for the * legacy 1-stage (tool_use) classifier — the single request goes here. */ stage1RequestId?: string /** * API message id (msg_xxx) for stage 1. Enables joining the * tengu_auto_mode_decision analytics event to the classifier's actual * prompt/completion in post-analysis. */ stage1MsgId?: string /** Token usage from stage 2 (thinking) when stage 2 was run */ stage2Usage?: ClassifierUsage /** Duration of stage 2 in ms when stage 2 was run */ stage2DurationMs?: number /** API request_id for stage 2 (set whenever stage 2 ran) */ stage2RequestId?: string /** API message id (msg_xxx) for stage 2 (set whenever stage 2 ran) */ stage2MsgId?: string}
// ============================================================================// Permission Explainer Types// ============================================================================
export type RiskLevel = 'LOW' | 'MEDIUM' | 'HIGH'
export type PermissionExplanation = { riskLevel: RiskLevel explanation: string reasoning: string risk: string}
// ============================================================================// Tool Permission Context// ============================================================================
/** * Mapping of permission rules by their source */export type ToolPermissionRulesBySource = { [T in PermissionRuleSource]?: string[]}
/** * Context needed for permission checking in tools * Note: Uses a simplified DeepImmutable approximation for this types-only file */export type ToolPermissionContext = { readonly mode: PermissionMode readonly additionalWorkingDirectories: ReadonlyMap< string, AdditionalWorkingDirectory > readonly alwaysAllowRules: ToolPermissionRulesBySource readonly alwaysDenyRules: ToolPermissionRulesBySource readonly alwaysAskRules: ToolPermissionRulesBySource readonly isBypassPermissionsModeAvailable: boolean readonly strippedDangerousRules?: ToolPermissionRulesBySource readonly shouldAvoidPermissionPrompts?: boolean readonly awaitAutomatedChecksBeforeDialog?: boolean readonly prePlanMode?: PermissionMode}