diff --git a/plugin/skills/impeccable/reference/hooks.md b/plugin/skills/impeccable/reference/hooks.md index 28fa8b424..0cd15c91d 100644 --- a/plugin/skills/impeccable/reference/hooks.md +++ b/plugin/skills/impeccable/reference/hooks.md @@ -44,7 +44,7 @@ The first argument is the action. Defaults to `status`. ``` 3. If `` is `off`, follow up with a one-line note: "Done. New edits will not trigger the design hook in this project until you run `/impeccable hooks on`." -4. If `` is `on`, follow up with: "Done. The design hook will fire after the next Edit/Write/MultiEdit on a UI file." +4. If `` is `on`, follow up with: "Done. The design hook will fire after the next Edit/Write on a UI file." 5. If `` is `ignore-value`, `ignore-file`, or `ignore-rule`, just print the script output. The default scope is shared `.impeccable/config.json`; add `--local` only when the user explicitly asks for a private exception. 6. If `` is `status`, just print the script output. Do not add commentary unless the user asked a follow-up question. diff --git a/plugin/skills/impeccable/scripts/hook-admin.mjs b/plugin/skills/impeccable/scripts/hook-admin.mjs index e8d9e2ada..0d8cbaf94 100644 --- a/plugin/skills/impeccable/scripts/hook-admin.mjs +++ b/plugin/skills/impeccable/scripts/hook-admin.mjs @@ -75,11 +75,11 @@ const HOOK_MANIFEST_TARGETS = [ destRel: '.claude/settings.local.json', sharedDestRel: '.claude/settings.json', manifest: () => ({ - description: 'Impeccable design detector: immediate-tier checks after Edit/Write/MultiEdit on UI files, full-rule deep pass on Stop.', + description: 'Impeccable design detector: immediate-tier checks after Edit/Write on UI files, full-rule deep pass on Stop.', hooks: { PostToolUse: [ { - matcher: 'Edit|Write|MultiEdit', + matcher: 'Edit|Write', hooks: [ { type: 'command', diff --git a/tests/hook-build.test.mjs b/tests/hook-build.test.mjs index e82987979..11ad34cbb 100644 --- a/tests/hook-build.test.mjs +++ b/tests/hook-build.test.mjs @@ -376,6 +376,15 @@ describe('generated hook artifacts in repo', () => { assert.ok(fs.existsSync(path.join(REPO_ROOT, 'plugin/skills/impeccable/scripts/hook-lib.mjs'))); }); + it('keeps the marketplace hook repair matcher aligned with Claude Code', () => { + const hookAdmin = fs.readFileSync( + path.join(REPO_ROOT, 'plugin/skills/impeccable/scripts/hook-admin.mjs'), + 'utf8', + ); + assert.match(hookAdmin, /matcher: 'Edit\|Write'/); + assert.doesNotMatch(hookAdmin, /matcher: 'Edit\|Write\|MultiEdit'/); + }); + it('generated hook runtime can import the bundled detector', async () => { for (const scriptDir of [ '.claude/skills/impeccable/scripts', diff --git a/tests/hook.test.mjs b/tests/hook.test.mjs index 1a3d08e57..cfcbf26dc 100644 --- a/tests/hook.test.mjs +++ b/tests/hook.test.mjs @@ -950,6 +950,7 @@ describe('hook-admin.mjs', () => { const claudeManifest = JSON.parse(claude); const impeccableGroup = claudeManifest.hooks.PostToolUse.find((group) => group.hooks?.some((hook) => hook.command?.includes('skills/impeccable/scripts/hook.mjs'))); + assert.ok(impeccableGroup, 'repaired Claude settings should contain the Impeccable PostToolUse group'); assert.equal(impeccableGroup.matcher, 'Edit|Write'); const codex = fs.readFileSync(path.join(cwd, '.codex', 'hooks.json'), 'utf-8');