From 40a4fafa7f2ebb894a49ad8f15cc569ad8e58bda Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Thu, 12 Feb 2026 15:58:59 -0800 Subject: [PATCH] fix: add async/timeout to hooks schema and validate in CI - hooks.schema.json: add async (boolean) and timeout (number) properties to hookItem definition, matching fields used in hooks.json - validate-hooks.js: validate async and timeout types when present - hooks.test.js: add SessionEnd to required event types check --- schemas/hooks.schema.json | 9 +++++++++ scripts/ci/validate-hooks.js | 10 ++++++++++ tests/hooks/hooks.test.js | 1 + 3 files changed, 20 insertions(+) diff --git a/schemas/hooks.schema.json b/schemas/hooks.schema.json index d07d61d..ceb2bd9 100644 --- a/schemas/hooks.schema.json +++ b/schemas/hooks.schema.json @@ -25,6 +25,15 @@ } } ] + }, + "async": { + "type": "boolean", + "description": "Run hook asynchronously in background without blocking" + }, + "timeout": { + "type": "number", + "minimum": 0, + "description": "Timeout in seconds for async hooks" } } }, diff --git a/scripts/ci/validate-hooks.js b/scripts/ci/validate-hooks.js index dc3f6f4..ddc08df 100644 --- a/scripts/ci/validate-hooks.js +++ b/scripts/ci/validate-hooks.js @@ -24,6 +24,16 @@ function validateHookEntry(hook, label) { hasErrors = true; } + // Validate optional async and timeout fields + if ('async' in hook && typeof hook.async !== 'boolean') { + console.error(`ERROR: ${label} 'async' must be a boolean`); + hasErrors = true; + } + if ('timeout' in hook && (typeof hook.timeout !== 'number' || hook.timeout < 0)) { + console.error(`ERROR: ${label} 'timeout' must be a non-negative number`); + hasErrors = true; + } + if (!hook.command || (typeof hook.command !== 'string' && !Array.isArray(hook.command))) { console.error(`ERROR: ${label} missing or invalid 'command' field`); hasErrors = true; diff --git a/tests/hooks/hooks.test.js b/tests/hooks/hooks.test.js index 7da7eb4..aebe0d2 100644 --- a/tests/hooks/hooks.test.js +++ b/tests/hooks/hooks.test.js @@ -278,6 +278,7 @@ async function runTests() { assert.ok(hooks.hooks.PreToolUse, 'Should have PreToolUse hooks'); assert.ok(hooks.hooks.PostToolUse, 'Should have PostToolUse hooks'); assert.ok(hooks.hooks.SessionStart, 'Should have SessionStart hooks'); + assert.ok(hooks.hooks.SessionEnd, 'Should have SessionEnd hooks'); assert.ok(hooks.hooks.Stop, 'Should have Stop hooks'); assert.ok(hooks.hooks.PreCompact, 'Should have PreCompact hooks'); })) passed++; else failed++;