From 5050b66dbdbf0a9b74e9bb7cae72c878e583b054 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Sun, 16 Aug 2026 17:25:06 -0400 Subject: [PATCH] Simplify hook manifest builders (#596) Centralize the shared Claude-compatible PostToolUse and Stop schema while preserving every provider-specific matcher, path, notice, and timeout.\n\nAI assistance: Codex prepared this behavior-preserving refactor under pbakaus's scheduled architecture-simplification authorization. --- scripts/lib/transformers/hooks.js | 123 +++++++++++------------------- 1 file changed, 43 insertions(+), 80 deletions(-) diff --git a/scripts/lib/transformers/hooks.js b/scripts/lib/transformers/hooks.js index ad4212eeb..e0fc046d6 100644 --- a/scripts/lib/transformers/hooks.js +++ b/scripts/lib/transformers/hooks.js @@ -46,6 +46,7 @@ function stopEntry(command) { ], }; } + const CLAUDE_PROJECT_HOOK = '${CLAUDE_PROJECT_DIR}/.claude/skills/impeccable/scripts/hook.mjs'; // The Node major the hook runtime requires, kept equal to the engines floor in // package.json. The probe and the notice both derive from it so they cannot @@ -85,6 +86,27 @@ const guardedNode = (hookPath, notice = '') => { : `! ${NODE_PROBE}`; return `[ ! -f "${hookPath}" ] || ${probe} || node "${hookPath}"`; }; + +function buildClaudeCompatibleHooks(matcher, hookPath, notice = '') { + const command = guardedNode(hookPath, notice); + return { + PostToolUse: [ + { + matcher, + hooks: [ + { + type: 'command', + command, + timeout: TIMEOUT_SECONDS, + statusMessage: STATUS_MESSAGE, + }, + ], + }, + ], + Stop: [stopEntry(command)], + }; +} + // The message says `on PATH` deliberately: the common cause is a hook shell // whose PATH misses the version manager, so a user already running Node 22 // needs to know the hook's PATH is at issue and not their install. Apostrophes @@ -116,22 +138,11 @@ 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.', - hooks: { - PostToolUse: [ - { - matcher: 'Edit|Write|MultiEdit', - hooks: [ - { - type: 'command', - command: guardedNode(CLAUDE_PROJECT_HOOK, SYSTEM_MESSAGE_NOTICE), - timeout: TIMEOUT_SECONDS, - statusMessage: STATUS_MESSAGE, - }, - ], - }, - ], - Stop: [stopEntry(guardedNode(CLAUDE_PROJECT_HOOK, SYSTEM_MESSAGE_NOTICE))], - }, + hooks: buildClaudeCompatibleHooks( + 'Edit|Write|MultiEdit', + CLAUDE_PROJECT_HOOK, + SYSTEM_MESSAGE_NOTICE, + ), }; } @@ -143,22 +154,11 @@ export function buildClaudeSettingsManifest() { // than `hooks`, failing the whole manifest (issue #330). export function buildClaudePluginHooksManifest() { return { - hooks: { - PostToolUse: [ - { - matcher: 'Edit|Write|MultiEdit', - hooks: [ - { - type: 'command', - command: guardedNode(CLAUDE_PLUGIN_HOOK, SYSTEM_MESSAGE_NOTICE), - timeout: TIMEOUT_SECONDS, - statusMessage: STATUS_MESSAGE, - }, - ], - }, - ], - Stop: [stopEntry(guardedNode(CLAUDE_PLUGIN_HOOK, SYSTEM_MESSAGE_NOTICE))], - }, + hooks: buildClaudeCompatibleHooks( + 'Edit|Write|MultiEdit', + CLAUDE_PLUGIN_HOOK, + SYSTEM_MESSAGE_NOTICE, + ), }; } @@ -167,22 +167,11 @@ export function buildClaudePluginHooksManifest() { // instead of relying on its Claude compatibility alias. export function buildCodexPluginHooksManifest() { return { - hooks: { - PostToolUse: [ - { - matcher: 'Edit|Write|apply_patch', - hooks: [ - { - type: 'command', - command: guardedNode(CODEX_PLUGIN_HOOK, SYSTEM_MESSAGE_NOTICE), - timeout: TIMEOUT_SECONDS, - statusMessage: STATUS_MESSAGE, - }, - ], - }, - ], - Stop: [stopEntry(guardedNode(CODEX_PLUGIN_HOOK, SYSTEM_MESSAGE_NOTICE))], - }, + hooks: buildClaudeCompatibleHooks( + 'Edit|Write|apply_patch', + CODEX_PLUGIN_HOOK, + SYSTEM_MESSAGE_NOTICE, + ), }; } @@ -192,22 +181,11 @@ export function buildCodexPluginHooksManifest() { export function buildCodexHooksManifest(skillDir = '.codex') { const hookPath = codexProjectHook(skillDir); return { - hooks: { - PostToolUse: [ - { - matcher: 'Edit|Write|apply_patch', - hooks: [ - { - type: 'command', - command: guardedNode(hookPath, SYSTEM_MESSAGE_NOTICE), - timeout: TIMEOUT_SECONDS, - statusMessage: STATUS_MESSAGE, - }, - ], - }, - ], - Stop: [stopEntry(guardedNode(hookPath, SYSTEM_MESSAGE_NOTICE))], - }, + hooks: buildClaudeCompatibleHooks( + 'Edit|Write|apply_patch', + hookPath, + SYSTEM_MESSAGE_NOTICE, + ), }; } @@ -259,22 +237,7 @@ export function buildGitHubHooksManifest() { // https://docs.x.ai/build/features/hooks export function buildGrokHooksManifest() { return { - hooks: { - PostToolUse: [ - { - matcher: 'Edit|Write|MultiEdit', - hooks: [ - { - type: 'command', - command: guardedNode(GROK_PROJECT_HOOK), - timeout: TIMEOUT_SECONDS, - statusMessage: STATUS_MESSAGE, - }, - ], - }, - ], - Stop: [stopEntry(guardedNode(GROK_PROJECT_HOOK))], - }, + hooks: buildClaudeCompatibleHooks('Edit|Write|MultiEdit', GROK_PROJECT_HOOK), }; }