diff --git a/.claude/settings.json b/.claude/settings.json index 3fd3a722e..e7b27c9ea 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,9 +1,9 @@ { - "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/plugin/hooks/hooks.json b/plugin/hooks/hooks.json index ae71a3106..ca87389b1 100644 --- a/plugin/hooks/hooks.json +++ b/plugin/hooks/hooks.json @@ -2,7 +2,7 @@ "hooks": { "PostToolUse": [ { - "matcher": "Edit|Write|MultiEdit", + "matcher": "Edit|Write", "hooks": [ { "type": "command", diff --git a/scripts/lib/transformers/hooks.js b/scripts/lib/transformers/hooks.js index e0fc046d6..51828a56b 100644 --- a/scripts/lib/transformers/hooks.js +++ b/scripts/lib/transformers/hooks.js @@ -137,9 +137,9 @@ const GROK_PROJECT_HOOK = '.grok/skills/impeccable/scripts/hook.mjs'; export function buildClaudeSettingsManifest() { return { - 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: buildClaudeCompatibleHooks( - 'Edit|Write|MultiEdit', + 'Edit|Write', CLAUDE_PROJECT_HOOK, SYSTEM_MESSAGE_NOTICE, ), @@ -155,7 +155,7 @@ export function buildClaudeSettingsManifest() { export function buildClaudePluginHooksManifest() { return { hooks: buildClaudeCompatibleHooks( - 'Edit|Write|MultiEdit', + 'Edit|Write', CLAUDE_PLUGIN_HOOK, SYSTEM_MESSAGE_NOTICE, ), diff --git a/skill/reference/hooks.md b/skill/reference/hooks.md index d6df929de..e990b1641 100644 --- a/skill/reference/hooks.md +++ b/skill/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 `{{command_prefix}}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/skill/scripts/hook-admin.mjs b/skill/scripts/hook-admin.mjs index e8d9e2ada..0d8cbaf94 100644 --- a/skill/scripts/hook-admin.mjs +++ b/skill/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 0928bde25..e82987979 100644 --- a/tests/hook-build.test.mjs +++ b/tests/hook-build.test.mjs @@ -72,7 +72,8 @@ describe('hook manifest builders', () => { const group = manifest.hooks.PostToolUse[0]; const handler = group.hooks[0]; - assert.equal(group.matcher, 'Edit|Write|MultiEdit'); + assert.equal(group.matcher, 'Edit|Write'); + assert.doesNotMatch(manifest.description, /MultiEdit/); assert.equal(handler.type, 'command'); assert.equal(handler.timeout, 5); assert.equal(handler.statusMessage, 'Checking UI changes'); @@ -356,7 +357,7 @@ describe('generated hook artifacts in repo', () => { assert.equal(manifest.description, undefined); const handler = manifest.hooks.PostToolUse[0].hooks[0]; - assert.equal(manifest.hooks.PostToolUse[0].matcher, 'Edit|Write|MultiEdit'); + assert.equal(manifest.hooks.PostToolUse[0].matcher, 'Edit|Write'); expectCommand(handler.command, 'skills/impeccable/scripts/hook.mjs'); // Resolves relative to the installed plugin, not a `.claude/skills/` layout. assert.ok(handler.command.includes('${CLAUDE_PLUGIN_ROOT}'), diff --git a/tests/hook.test.mjs b/tests/hook.test.mjs index 412c04ccb..1a3d08e57 100644 --- a/tests/hook.test.mjs +++ b/tests/hook.test.mjs @@ -947,6 +947,10 @@ describe('hook-admin.mjs', () => { // impeccable entry must have been stripped, not accumulated. assert.equal(claude.split('skills/impeccable/scripts/hook.mjs').length - 1, 2); assert.match(claude, /"Stop"/); + 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.equal(impeccableGroup.matcher, 'Edit|Write'); const codex = fs.readFileSync(path.join(cwd, '.codex', 'hooks.json'), 'utf-8'); assert.match(codex, /\.agents\/skills\/impeccable\/scripts\/hook\.mjs/);