Download src/types/hooks.ts from chenbhao/codev: direct link, hf CLI and curl.
- Browser
- Download file 9.14 kB
-
https://huggingface.co/chenbhao/codev/resolve/main/src/types/hooks.ts
- Command line
-
hf download hf://chenbhao/codev/src/types/hooks.ts
-
curl -L -o hooks.ts https://huggingface.co/chenbhao/codev/resolve/main/src/types/hooks.ts
9.14 kB
| // biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered | |
| import { 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 schema | |
| export 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 validation | |
| export 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 schema | |
| type SchemaHookJSONOutput = z.infer<ReturnType<typeof hookJSONOutputSchema>> | |
| // Type guard function to check if response is sync | |
| export function isSyncHookJSONOutput( | |
| json: HookJSONOutput, | |
| ): json is SyncHookJSONOutput { | |
| return !('async' in json && json.async === true) | |
| } | |
| // Type guard function to check if response is async | |
| export function isAsyncHookJSONOutput( | |
| json: HookJSONOutput, | |
| ): json is AsyncHookJSONOutput { | |
| return 'async' in json && json.async === true | |
| } | |
| // Compile-time assertion that SDK and Zod types match | |
| import type { IsEqual } from 'type-fest' | |
| type Assert<T extends true> = T | |
| type _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 | |
| } | |