From 741982b1c58b4022857d35d563008e56ddf30c43 Mon Sep 17 00:00:00 2001 From: omerakben Date: Sat, 30 May 2026 11:04:39 -0400 Subject: [PATCH] fix(plugins): drop redundant hooks key so the code-oz plugin loads Installing the code-oz plugin from the marketplace failed at load time: Hook load failed: Duplicate hooks file detected: ./hooks/hooks.json ... The standard hooks/hooks.json is loaded automatically, so manifest.hooks should only reference additional hook files. Claude Code auto-discovers hooks/hooks.json from the plugin root, so declaring it again in plugin.json's `hooks` key loads it twice and the whole plugin (commands included) fails to load. `claude plugin validate` and the offline suite passed because they asserted the broken value rather than load behavior; only a real `marketplace add` + `plugin install` surfaced it. Remove the `hooks` key from plugins/code-oz/.claude-plugin/plugin.json. The SessionStart router hook still loads via the conventional path (confirmed against the plugin reference docs). Flip the manifest test RED-first to assert the key is absent. Verified: real install of both plugins from a local marketplace now shows code-oz Status: enabled (was "failed to load"); code-oz-discipline unchanged. 3812 offline tests pass; typecheck clean; claude plugin validate passes. --- plugins/code-oz/.claude-plugin/plugin.json | 3 +-- tests/plugins/manifest-shape.test.ts | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/code-oz/.claude-plugin/plugin.json b/plugins/code-oz/.claude-plugin/plugin.json index 20faea5..a306f47 100644 --- a/plugins/code-oz/.claude-plugin/plugin.json +++ b/plugins/code-oz/.claude-plugin/plugin.json @@ -12,6 +12,5 @@ "./commands/code-oz-init.md", "./commands/code-oz-doctor.md", "./commands/code-oz-resume.md" - ], - "hooks": "./hooks/hooks.json" + ] } diff --git a/tests/plugins/manifest-shape.test.ts b/tests/plugins/manifest-shape.test.ts index 757d261..c132f30 100644 --- a/tests/plugins/manifest-shape.test.ts +++ b/tests/plugins/manifest-shape.test.ts @@ -42,7 +42,11 @@ describe('plugins/code-oz manifest shape', () => { expect(plugin.name).toBe('code-oz') expect(typeof plugin.description).toBe('string') expect((plugin.description as string).length).toBeGreaterThan(0) - expect(plugin.hooks).toBe('./hooks/hooks.json') + // The standard hooks/hooks.json auto-loads. Declaring it in manifest.hooks + // makes Claude Code load it twice and the plugin fails to load entirely + // ("Duplicate hooks file detected"). manifest.hooks must reference only + // ADDITIONAL hook files, so the code-oz plugin must not set it. + expect(plugin.hooks).toBeUndefined() expect(Array.isArray(plugin.commands)).toBe(true) expect(plugin.commands).toEqual(EXPECTED_COMMANDS) })