Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
9.1 kB · 290 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reorderedimport { z } from 'zod/v4'import { lazySchema } from '../utils/lazySchema.js'import { type HookEvent, HOOK_EVENTS, type HookInput, type PermissionUpdate,} from 'src/entrypoints/agentSdkTypes.js'import type { HookJSONOutput, AsyncHookJSONOutput, SyncHookJSONOutput,} from 'src/entrypoints/agentSdkTypes.js'import type { Message } from 'src/types/message.js'import type { PermissionResult } from 'src/utils/permissions/PermissionResult.js'import { permissionBehaviorSchema } from 'src/utils/permissions/PermissionRule.js'import { permissionUpdateSchema } from 'src/utils/permissions/PermissionUpdateSchema.js'import type { AppState } from '../state/AppState.js'import type { AttributionState } from '../utils/commitAttribution.js'
export function isHookEvent(value: string): value is HookEvent { return HOOK_EVENTS.includes(value as HookEvent)}
// Prompt elicitation protocol types. The `prompt` key acts as discriminator// (mirroring the {async:true} pattern), with the id as its value.export const promptRequestSchema = lazySchema(() => z.object({ prompt: z.string(), // request id message: z.string(), options: z.array( z.object({ key: z.string(), label: z.string(), description: z.string().optional(), }), ), }),)
export type PromptRequest = z.infer<ReturnType<typeof promptRequestSchema>>
export type PromptResponse = { prompt_response: string // request id selected: string}
// Sync hook response schemaexport const syncHookResponseSchema = lazySchema(() => z.object({ continue: z .boolean() .describe('Whether Claude should continue after hook (default: true)') .optional(), suppressOutput: z .boolean() .describe('Hide stdout from transcript (default: false)') .optional(), stopReason: z .string() .describe('Message shown when continue is false') .optional(), decision: z.enum(['approve', 'block']).optional(), reason: z.string().describe('Explanation for the decision').optional(), systemMessage: z .string() .describe('Warning message shown to the user') .optional(), hookSpecificOutput: z .union([ z.object({ hookEventName: z.literal('PreToolUse'), permissionDecision: permissionBehaviorSchema().optional(), permissionDecisionReason: z.string().optional(), updatedInput: z.record(z.string(), z.unknown()).optional(), additionalContext: z.string().optional(), }), z.object({ hookEventName: z.literal('UserPromptSubmit'), additionalContext: z.string().optional(), }), z.object({ hookEventName: z.literal('SessionStart'), additionalContext: z.string().optional(), initialUserMessage: z.string().optional(), watchPaths: z .array(z.string()) .describe('Absolute paths to watch for FileChanged hooks') .optional(), }), z.object({ hookEventName: z.literal('Setup'), additionalContext: z.string().optional(), }), z.object({ hookEventName: z.literal('SubagentStart'), additionalContext: z.string().optional(), }), z.object({ hookEventName: z.literal('PostToolUse'), additionalContext: z.string().optional(), updatedMCPToolOutput: z .unknown() .describe('Updates the output for MCP tools') .optional(), }), z.object({ hookEventName: z.literal('PostToolUseFailure'), additionalContext: z.string().optional(), }), z.object({ hookEventName: z.literal('PermissionDenied'), retry: z.boolean().optional(), }), z.object({ hookEventName: z.literal('Notification'), additionalContext: z.string().optional(), }), z.object({ hookEventName: z.literal('PermissionRequest'), decision: z.union([ z.object({ behavior: z.literal('allow'), updatedInput: z.record(z.string(), z.unknown()).optional(), updatedPermissions: z.array(permissionUpdateSchema()).optional(), }), z.object({ behavior: z.literal('deny'), message: z.string().optional(), interrupt: z.boolean().optional(), }), ]), }), z.object({ hookEventName: z.literal('Elicitation'), action: z.enum(['accept', 'decline', 'cancel']).optional(), content: z.record(z.string(), z.unknown()).optional(), }), z.object({ hookEventName: z.literal('ElicitationResult'), action: z.enum(['accept', 'decline', 'cancel']).optional(), content: z.record(z.string(), z.unknown()).optional(), }), z.object({ hookEventName: z.literal('CwdChanged'), watchPaths: z .array(z.string()) .describe('Absolute paths to watch for FileChanged hooks') .optional(), }), z.object({ hookEventName: z.literal('FileChanged'), watchPaths: z .array(z.string()) .describe('Absolute paths to watch for FileChanged hooks') .optional(), }), z.object({ hookEventName: z.literal('WorktreeCreate'), worktreePath: z.string(), }), ]) .optional(), }),)
// Zod schema for hook JSON output validationexport const hookJSONOutputSchema = lazySchema(() => { // Async hook response schema const asyncHookResponseSchema = z.object({ async: z.literal(true), asyncTimeout: z.number().optional(), }) return z.union([asyncHookResponseSchema, syncHookResponseSchema()])})
// Infer the TypeScript type from the schematype SchemaHookJSONOutput = z.infer<ReturnType<typeof hookJSONOutputSchema>>
// Type guard function to check if response is syncexport function isSyncHookJSONOutput( json: HookJSONOutput,): json is SyncHookJSONOutput { return !('async' in json && json.async === true)}
// Type guard function to check if response is asyncexport function isAsyncHookJSONOutput( json: HookJSONOutput,): json is AsyncHookJSONOutput { return 'async' in json && json.async === true}
// Compile-time assertion that SDK and Zod types matchimport type { IsEqual } from 'type-fest'type Assert<T extends true> = Ttype _assertSDKTypesMatch = Assert< IsEqual<SchemaHookJSONOutput, HookJSONOutput>>
/** Context passed to callback hooks for state access */export type HookCallbackContext = { getAppState: () => AppState updateAttributionState: ( updater: (prev: AttributionState) => AttributionState, ) => void}
/** Hook that is a callback. */export type HookCallback = { type: 'callback' callback: ( input: HookInput, toolUseID: string | null, abort: AbortSignal | undefined, /** Hook index for SessionStart hooks to compute CLAUDE_ENV_FILE path */ hookIndex?: number, /** Optional context for accessing app state */ context?: HookCallbackContext, ) => Promise<HookJSONOutput> /** Timeout in seconds for this hook */ timeout?: number /** Internal hooks (e.g. session file access analytics) are excluded from tengu_run_hook metrics */ internal?: boolean}
export type HookCallbackMatcher = { matcher?: string hooks: HookCallback[] pluginName?: string}
export type HookProgress = { type: 'hook_progress' hookEvent: HookEvent hookName: string command: string promptText?: string statusMessage?: string}
export type HookBlockingError = { blockingError: string command: string}
export type PermissionRequestResult = | { behavior: 'allow' updatedInput?: Record<string, unknown> updatedPermissions?: PermissionUpdate[] } | { behavior: 'deny' message?: string interrupt?: boolean }
export type HookResult = { message?: Message systemMessage?: Message blockingError?: HookBlockingError outcome: 'success' | 'blocking' | 'non_blocking_error' | 'cancelled' preventContinuation?: boolean stopReason?: string permissionBehavior?: 'ask' | 'deny' | 'allow' | 'passthrough' hookPermissionDecisionReason?: string additionalContext?: string initialUserMessage?: string updatedInput?: Record<string, unknown> updatedMCPToolOutput?: unknown permissionRequestResult?: PermissionRequestResult retry?: boolean}
export type AggregatedHookResult = { message?: Message blockingErrors?: HookBlockingError[] preventContinuation?: boolean stopReason?: string hookPermissionDecisionReason?: string permissionBehavior?: PermissionResult['behavior'] additionalContexts?: string[] initialUserMessage?: string updatedInput?: Record<string, unknown> updatedMCPToolOutput?: unknown permissionRequestResult?: PermissionRequestResult retry?: boolean}