From 6dc21b3b7f650c3ef90cce1bf4cd18f705c3ae0d Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 3 Apr 2026 18:14:12 +0900 Subject: [PATCH] Fix Claude user rule skipping for disabled hooks Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../hooks/create-tool-guard-hooks.test.ts | 66 +++++++++++++++++++ src/plugin/hooks/create-tool-guard-hooks.ts | 7 +- 2 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 src/plugin/hooks/create-tool-guard-hooks.test.ts diff --git a/src/plugin/hooks/create-tool-guard-hooks.test.ts b/src/plugin/hooks/create-tool-guard-hooks.test.ts new file mode 100644 index 000000000..f06e9ef6f --- /dev/null +++ b/src/plugin/hooks/create-tool-guard-hooks.test.ts @@ -0,0 +1,66 @@ +import { beforeEach, describe, expect, it, mock } from "bun:test" +import type { OhMyOpenCodeConfig } from "../../config" +import type { ModelCacheState } from "../../plugin-state" +import type { PluginContext } from "../types" + +const mockContext = { + directory: "/tmp", +} as PluginContext + +const mockModelCacheState = { + anthropicContext1MEnabled: false, +} satisfies ModelCacheState + +let capturedRulesInjectorOptions: { skipClaudeUserRules?: boolean } | undefined + +mock.module("../../hooks", () => ({ + createCommentCheckerHooks: () => ({ name: "comment-checker" }), + createToolOutputTruncatorHook: () => ({ name: "tool-output-truncator" }), + createDirectoryAgentsInjectorHook: () => ({ name: "directory-agents-injector" }), + createDirectoryReadmeInjectorHook: () => ({ name: "directory-readme-injector" }), + createEmptyTaskResponseDetectorHook: () => ({ name: "empty-task-response-detector" }), + createRulesInjectorHook: ( + _ctx: PluginContext, + _modelCacheState: ModelCacheState, + options?: { skipClaudeUserRules?: boolean }, + ) => { + capturedRulesInjectorOptions = options + return { name: "rules-injector" } + }, + createTasksTodowriteDisablerHook: () => ({ name: "tasks-todowrite-disabler" }), + createWriteExistingFileGuardHook: () => ({ name: "write-existing-file-guard" }), + createBashFileReadGuardHook: () => ({ name: "bash-file-read-guard" }), + createHashlineReadEnhancerHook: () => ({ name: "hashline-read-enhancer" }), + createReadImageResizerHook: () => ({ name: "read-image-resizer" }), + createJsonErrorRecoveryHook: () => ({ name: "json-error-recovery" }), + createTodoDescriptionOverrideHook: () => ({ name: "todo-description-override" }), + createWebFetchRedirectGuardHook: () => ({ name: "webfetch-redirect-guard" }), +})) + +describe("createToolGuardHooks", () => { + beforeEach(() => { + capturedRulesInjectorOptions = undefined + }) + + it("skips Claude user rules when claude_code.hooks is false", async () => { + // given + const pluginConfig = { + claude_code: { + hooks: false, + }, + } as OhMyOpenCodeConfig + const { createToolGuardHooks } = await import("./create-tool-guard-hooks") + + // when + createToolGuardHooks({ + ctx: mockContext, + pluginConfig, + modelCacheState: mockModelCacheState, + isHookEnabled: (hookName) => hookName === "rules-injector", + safeHookEnabled: true, + }) + + // then + expect(capturedRulesInjectorOptions).toEqual({ skipClaudeUserRules: true }) + }) +}) diff --git a/src/plugin/hooks/create-tool-guard-hooks.ts b/src/plugin/hooks/create-tool-guard-hooks.ts index 2eba9eb30..01b671e6b 100644 --- a/src/plugin/hooks/create-tool-guard-hooks.ts +++ b/src/plugin/hooks/create-tool-guard-hooks.ts @@ -92,14 +92,11 @@ export function createToolGuardHooks(args: { : null const cc = pluginConfig.claude_code - const claudeCodeDisabled = cc != null - && cc.hooks === false - && cc.skills === false - && cc.agents === false + const skipClaudeUserRules = cc?.hooks === false const rulesInjector = isHookEnabled("rules-injector") ? safeHook("rules-injector", () => createRulesInjectorHook(ctx, modelCacheState, { - skipClaudeUserRules: claudeCodeDisabled ?? false, + skipClaudeUserRules, })) : null