From a27cac96d52e32bdf32fdb3086405fff736b7c03 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 9 Dec 2025 17:36:12 +0900 Subject: [PATCH] feat(hooks): add Claude Code hooks type definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit πŸ€– GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) --- notepad.md | 35 ++++++ src/hooks/claude-code-hooks/types.ts | 173 +++++++++++++++++++++++++-- 2 files changed, 201 insertions(+), 7 deletions(-) diff --git a/notepad.md b/notepad.md index 1f63da3..da9395b 100644 --- a/notepad.md +++ b/notepad.md @@ -431,3 +431,38 @@ All tasks execution STARTED: Thu Dec 4 16:52:57 KST 2025 --- +## [2025-12-09 17:34] - Task 1: types.ts ν¬νŒ… + +### DISCOVERED ISSUES +- Stub types.ts had `PluginConfig` interface needed by hook-disabled.ts (from Task 0) +- Full types.ts from opencode-cc-plugin did NOT have `PluginConfig` +- Typecheck initially failed: Module has no exported member 'PluginConfig' + +### IMPLEMENTATION DECISIONS +- Copied full types.ts (181 lines) from opencode-cc-plugin β†’ oh-my-opencode +- Preserved ALL types: ClaudeHooksConfig, HookMatcher, PreToolUseInput/Output, PostToolUseInput/Output +- Preserved deprecated decision fields: `decision?: "allow" | "deny" | "approve" | "block" | "ask"` +- Added `PluginConfig` interface at end (oh-my-opencode specific type needed by hook-disabled.ts) +- Kept line 150 comment (`// "pending" | "in_progress" | "completed"`) - existing source comment + +### PROBLEMS FOR NEXT TASKS +- PluginConfig is now available for all subsequent tasks +- Full type definitions ready for Task 2, 3, 4+ to use + +### VERIFICATION RESULTS +- Ran: `bun run typecheck` β†’ exit 0, no errors +- Verified: ClaudeHooksConfig, HookMatcher, HookCommand types exist +- Verified: PreToolUseInput/Output, PostToolUseInput/Output types exist +- Verified: deprecated decision field (approve/block) included in PreToolUseOutput +- Verified: PluginConfig export added (fixes hook-disabled.ts import) + +### LEARNINGS +- opencode-cc-plugin types.ts: 181 lines, no PluginConfig +- oh-my-opencode requires PluginConfig for hook disabling functionality +- Stub-to-full replacement pattern works: stub allows Task 0 typecheck, Task 1 replaces with full implementation +- Must preserve project-specific types (PluginConfig) when porting from different codebases + +μ†Œμš” μ‹œκ°„: ~2λΆ„ + +--- + diff --git a/src/hooks/claude-code-hooks/types.ts b/src/hooks/claude-code-hooks/types.ts index 3c517f9..a2272c2 100644 --- a/src/hooks/claude-code-hooks/types.ts +++ b/src/hooks/claude-code-hooks/types.ts @@ -1,16 +1,24 @@ -// Temporary stub types for Task 0 - will be fully implemented in Task 1 -// These are minimal definitions to allow shared utilities to type-check +/** + * Claude Code Hooks Type Definitions + * Maps Claude Code hook concepts to OpenCode plugin events + */ -export interface HookCommand { - type: string - command: string -} +export type ClaudeHookEvent = + | "PreToolUse" + | "PostToolUse" + | "UserPromptSubmit" + | "Stop" export interface HookMatcher { matcher: string hooks: HookCommand[] } +export interface HookCommand { + type: "command" + command: string +} + export interface ClaudeHooksConfig { PreToolUse?: HookMatcher[] PostToolUse?: HookMatcher[] @@ -18,7 +26,158 @@ export interface ClaudeHooksConfig { Stop?: HookMatcher[] } -export type ClaudeHookEvent = "PreToolUse" | "PostToolUse" | "UserPromptSubmit" | "Stop" +export interface PreToolUseInput { + session_id: string + transcript_path?: string + cwd: string + permission_mode?: PermissionMode + hook_event_name: "PreToolUse" + tool_name: string + tool_input: Record + tool_use_id?: string + hook_source?: HookSource +} + +export interface PostToolUseInput { + session_id: string + transcript_path?: string + cwd: string + permission_mode?: PermissionMode + hook_event_name: "PostToolUse" + tool_name: string + tool_input: Record + tool_response: { + title?: string + output?: string + [key: string]: unknown + } + tool_use_id?: string + hook_source?: HookSource +} + +export interface UserPromptSubmitInput { + session_id: string + cwd: string + permission_mode?: PermissionMode + hook_event_name: "UserPromptSubmit" + prompt: string + session?: { + id: string + } + hook_source?: HookSource +} + +export type PermissionMode = "default" | "plan" | "acceptEdits" | "bypassPermissions" + +export type HookSource = "opencode-plugin" + +export interface StopInput { + session_id: string + transcript_path?: string + cwd: string + permission_mode?: PermissionMode + hook_event_name: "Stop" + stop_hook_active: boolean + todo_path?: string + hook_source?: HookSource +} + +export type PermissionDecision = "allow" | "deny" | "ask" + +/** + * Common JSON fields for all hook outputs (Claude Code spec) + */ +export interface HookCommonOutput { + /** If false, Claude stops entirely */ + continue?: boolean + /** Message shown to user when continue=false */ + stopReason?: string + /** Suppress output from transcript */ + suppressOutput?: boolean + /** Warning/message displayed to user */ + systemMessage?: string +} + +export interface PreToolUseOutput extends HookCommonOutput { + /** Deprecated: use hookSpecificOutput.permissionDecision instead */ + decision?: "allow" | "deny" | "approve" | "block" | "ask" + /** Deprecated: use hookSpecificOutput.permissionDecisionReason instead */ + reason?: string + hookSpecificOutput?: { + hookEventName: "PreToolUse" + permissionDecision: PermissionDecision + permissionDecisionReason?: string + updatedInput?: Record + } +} + +export interface PostToolUseOutput extends HookCommonOutput { + decision?: "block" + reason?: string + hookSpecificOutput?: { + hookEventName: "PostToolUse" + /** Additional context to provide to Claude */ + additionalContext?: string + } +} + +export interface HookResult { + exitCode: number + stdout?: string + stderr?: string +} + +export interface TranscriptEntry { + type: "tool_use" | "tool_result" | "user" | "assistant" + timestamp: string + tool_name?: string + tool_input?: Record + tool_output?: Record + content?: string +} + +export interface TodoItem { + id: string + content: string + status: "pending" | "in_progress" | "completed" | "cancelled" + priority?: "low" | "medium" | "high" + created_at: string + updated_at?: string +} + +export interface ClaudeCodeTodoItem { + content: string + status: string // "pending" | "in_progress" | "completed" + activeForm: string +} + +export interface TodoFile { + session_id: string + items: TodoItem[] + created_at: string + updated_at: string +} + +export interface StopOutput { + decision?: "block" | "continue" + reason?: string + stop_hook_active?: boolean + permission_mode?: PermissionMode + inject_prompt?: string +} + +export type ClaudeCodeContent = + | { type: "text"; text: string } + | { type: "tool_use"; id: string; name: string; input: Record } + | { type: "tool_result"; tool_use_id: string; content: string } + +export interface ClaudeCodeMessage { + type: "user" | "assistant" + message: { + role: "user" | "assistant" + content: ClaudeCodeContent[] + } +} export interface PluginConfig { disabledHooks?: boolean | ClaudeHookEvent[]