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.
This commit is contained in:
Paul Bakaus
2026-08-16 14:25:06 -07:00
committed by GitHub
parent 21ad321a97
commit 5050b66dbd
+43 -80
View File
@@ -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),
};
}