From 72d9d1385ba0a8d86d776551e00939411da1490a Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 16 Dec 2025 21:02:38 +0900 Subject: [PATCH] fix(hook-message-injector): add validation to prevent empty message injection and improve logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add content validation in injectHookMessage() to prevent empty hook content injection - Add logging to claude-code-hooks and keyword-detector for better debugging - Document timing issues in empty-message-sanitizer comments - Update README with improved setup instructions 🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) --- README.md | 36 +++++++++++++++---- .../hook-message-injector/injector.ts | 10 ++++++ src/hooks/claude-code-hooks/index.ts | 1 + src/hooks/empty-message-sanitizer/index.ts | 6 ++++ src/hooks/keyword-detector/index.ts | 1 + 5 files changed, 48 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1b1dcc0..83fca80 100644 --- a/README.md +++ b/README.md @@ -129,10 +129,26 @@ Let the LLM Agent handle the grunt work. Paste this link and ask it to install a
Instructions for LLM Agents (click to expand) -If you're an LLM Agent helping set up oh-my-opencode, follow these steps: +If you're an LLM Agent helping set up oh-my-opencode, Welcome! You'll now help your user to install the best agent harness, OhMyOpenCode. Tell user this with greetings, with test 'oMoMoMoMo...' +follow these steps: -### Step 1: Verify OpenCode Installation +### Step 0: Ask user about the setup. + +Since OpenCode Supports various models, and our plugin suggests various frontier LLMs. Thus, you must ask user, following questions: +1. Do you have a Claude Pro/Max Subscription? Otherwise, we'll use 'opencode/big-pickle' (known for glm 4.6) as a main orchestrator model (not recommended) + -> If user said yes, add ToDo: "Setup user Claude Pro/Max Auth" + -> If user said no, add ToDo: "Override OmO agent model on oh-my-opencode.json as opencode/big-pickle" +2. Do you have a ChatGPT Subscription? Otherwise, we'll use 'claude-opus-4-5' with 32k thinking option for oracle agent. + -> If user said yes, add ToDo: "Setup user ChatGPT Auth" + -> If user said no, add ToDo: "Override oracle agent model on oh-my-opencode.json as claude-opus-4-5 with 32k thinking" +3. Will you integrate Gemini models? Otherwise, you cannot enjoy the beautiful design. + -> If user said yes, add ToDo: "Setup Google OAuth" + -> If user said no, add ToDo: "Override frontend-ui-ux-engineer agent model on oh-my-opencode.json as claude-opus-4-5 with 32k thinking" + +### Step 1: Install OpenCode, if not + +Run following command to verify OpenCode Installation: ```bash if command -v opencode &> /dev/null; then @@ -143,10 +159,17 @@ else fi ``` -If OpenCode isn't installed, check the [OpenCode Installation Guide](https://opencode.ai/docs). To save context, spawn a subagent to handle installation and report back. +If OpenCode isn't installed, check the [OpenCode Installation Guide](https://opencode.ai/docs). +Spawn a subagent to handle installation and report back - to save context. ### Step 2: Configure oh-my-opencode Plugin +#### JSONC +- If `~/.config/opencode/opencode.jsonc` exists, work in there to add `oh-my-opencode` plugin + +#### JSON +- If no opencode.jsonc exists, run following command to create and register it. + ```bash mkdir -p ~/.config/opencode @@ -169,14 +192,15 @@ fi ```bash opencode --version # Should be 1.0.132 or higher -cat ~/.config/opencode/opencode.json # Should contain "oh-my-opencode" in plugin array +cat ~/.config/opencode/opencode.json # Should contain "oh-my-opencode" in plugin array, or maybe check jsonc ``` ### Step 4: Configure Authentication -Once oh-my-opencode is in the plugin list, use tmux to walk the user through authentication. Complete all steps below. +As your todo, please configure authentication as user have answered to you. +Following is the configuration guides for each providers. Please use interactive terminal like tmux to do following: -#### 4.1 Anthropic (Claude) +#### Anthropic (Claude) ```bash opencode auth login diff --git a/src/features/hook-message-injector/injector.ts b/src/features/hook-message-injector/injector.ts index 3e7b9d4..e2fdafb 100644 --- a/src/features/hook-message-injector/injector.ts +++ b/src/features/hook-message-injector/injector.ts @@ -71,6 +71,16 @@ export function injectHookMessage( hookContent: string, originalMessage: OriginalMessageContext ): boolean { + // Validate hook content to prevent empty message injection + if (!hookContent || hookContent.trim().length === 0) { + console.warn("[hook-message-injector] Attempted to inject empty hook content, skipping injection", { + sessionID, + hasAgent: !!originalMessage.agent, + hasModel: !!(originalMessage.model?.providerID && originalMessage.model?.modelID) + }) + return false + } + const messageDir = getOrCreateMessageDir(sessionID) const needsFallback = diff --git a/src/hooks/claude-code-hooks/index.ts b/src/hooks/claude-code-hooks/index.ts index 5640c26..6a2c341 100644 --- a/src/hooks/claude-code-hooks/index.ts +++ b/src/hooks/claude-code-hooks/index.ts @@ -111,6 +111,7 @@ export function createClaudeCodeHooksHook(ctx: PluginInput, config: PluginConfig if (result.messages.length > 0) { const hookContent = result.messages.join("\n\n") + log(`[claude-code-hooks] Injecting ${result.messages.length} hook messages`, { sessionID: input.sessionID, contentLength: hookContent.length }) const message = output.message as { agent?: string model?: { modelID?: string; providerID?: string } diff --git a/src/hooks/empty-message-sanitizer/index.ts b/src/hooks/empty-message-sanitizer/index.ts index 8c2e13c..ccd5199 100644 --- a/src/hooks/empty-message-sanitizer/index.ts +++ b/src/hooks/empty-message-sanitizer/index.ts @@ -8,6 +8,12 @@ interface MessageWithParts { } type MessagesTransformHook = { +// NOTE: This sanitizer runs on experimental.chat.messages.transform hook, +// which executes AFTER chat.message hooks. Filesystem-injected messages +// from hooks like claude-code-hooks and keyword-detector may bypass this +// sanitizer if they inject empty content. Validation should be done at +// injection time in injectHookMessage(). + "experimental.chat.messages.transform"?: ( input: Record, output: { messages: MessageWithParts[] } diff --git a/src/hooks/keyword-detector/index.ts b/src/hooks/keyword-detector/index.ts index 9cf1db0..1d44be8 100644 --- a/src/hooks/keyword-detector/index.ts +++ b/src/hooks/keyword-detector/index.ts @@ -43,6 +43,7 @@ export function createKeywordDetectorHook() { } const context = messages.join("\n") + log(`[keyword-detector] Injecting context for ${messages.length} keywords`, { sessionID: input.sessionID, contextLength: context.length }) const success = injectHookMessage(input.sessionID, context, { agent: message.agent, model: message.model,