From 6686cb9bda2cea2d5cb7170ba61ee1072fcae793 Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Thu, 12 Feb 2026 14:38:00 -0800 Subject: [PATCH] fix: add try-catch to inline hooks, fix schema drift MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Wrap JSON.parse in try-catch for all 6 inline hooks in hooks.json (dev-server blocker, tmux reminder, git-push reminder, doc blocker, PR create logger, build analysis) — previously unguarded JSON.parse would crash on empty/malformed stdin, preventing data passthrough - Add config parse error logging to evaluate-session.js - Fix plugin.schema.json: author can be string or {name,url} object, add version (semver pattern), homepage, keywords, skills, agents - Fix package-manager.schema.json: add setAt (date-time) field and make packageManager required to match actual code behavior --- hooks/hooks.json | 12 ++++++------ schemas/package-manager.schema.json | 8 +++++++- schemas/plugin.schema.json | 30 +++++++++++++++++++++++++++-- scripts/hooks/evaluate-session.js | 4 ++-- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/hooks/hooks.json b/hooks/hooks.json index 697d83c..7640268 100644 --- a/hooks/hooks.json +++ b/hooks/hooks.json @@ -7,7 +7,7 @@ "hooks": [ { "type": "command", - "command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const cmd=i.tool_input?.command||'';if(/(npm run dev|pnpm( run)? dev|yarn dev|bun run dev)/.test(cmd)){console.error('[Hook] BLOCKED: Dev server must run in tmux for log access');console.error('[Hook] Use: tmux new-session -d -s dev \\\"npm run dev\\\"');console.error('[Hook] Then: tmux attach -t dev');process.exit(2)}console.log(d)})\"" + "command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const i=JSON.parse(d);const cmd=i.tool_input?.command||'';if(/(npm run dev|pnpm( run)? dev|yarn dev|bun run dev)/.test(cmd)){console.error('[Hook] BLOCKED: Dev server must run in tmux for log access');console.error('[Hook] Use: tmux new-session -d -s dev \\\"npm run dev\\\"');console.error('[Hook] Then: tmux attach -t dev');process.exit(2)}}catch{}console.log(d)})\"" } ], "description": "Block dev servers outside tmux - ensures you can access logs" @@ -17,7 +17,7 @@ "hooks": [ { "type": "command", - "command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const cmd=i.tool_input?.command||'';if(!process.env.TMUX&&/(npm (install|test)|pnpm (install|test)|yarn (install|test)?|bun (install|test)|cargo build|make\\b|docker\\b|pytest|vitest|playwright)/.test(cmd)){console.error('[Hook] Consider running in tmux for session persistence');console.error('[Hook] tmux new -s dev | tmux attach -t dev')}console.log(d)})\"" + "command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const i=JSON.parse(d);const cmd=i.tool_input?.command||'';if(!process.env.TMUX&&/(npm (install|test)|pnpm (install|test)|yarn (install|test)?|bun (install|test)|cargo build|make\\b|docker\\b|pytest|vitest|playwright)/.test(cmd)){console.error('[Hook] Consider running in tmux for session persistence');console.error('[Hook] tmux new -s dev | tmux attach -t dev')}}catch{}console.log(d)})\"" } ], "description": "Reminder to use tmux for long-running commands" @@ -27,7 +27,7 @@ "hooks": [ { "type": "command", - "command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const cmd=i.tool_input?.command||'';if(/git push/.test(cmd)){console.error('[Hook] Review changes before push...');console.error('[Hook] Continuing with push (remove this hook to add interactive review)')}console.log(d)})\"" + "command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const i=JSON.parse(d);const cmd=i.tool_input?.command||'';if(/git push/.test(cmd)){console.error('[Hook] Review changes before push...');console.error('[Hook] Continuing with push (remove this hook to add interactive review)')}}catch{}console.log(d)})\"" } ], "description": "Reminder before git push to review changes" @@ -37,7 +37,7 @@ "hooks": [ { "type": "command", - "command": "node -e \"const fs=require('fs');let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const p=i.tool_input?.file_path||'';if(/\\.(md|txt)$/.test(p)&&!/(README|CLAUDE|AGENTS|CONTRIBUTING)\\.md$/.test(p)){console.error('[Hook] BLOCKED: Unnecessary documentation file creation');console.error('[Hook] File: '+p);console.error('[Hook] Use README.md for documentation instead');process.exit(2)}console.log(d)})\"" + "command": "node -e \"const fs=require('fs');let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const i=JSON.parse(d);const p=i.tool_input?.file_path||'';if(/\\.(md|txt)$/.test(p)&&!/(README|CLAUDE|AGENTS|CONTRIBUTING)\\.md$/.test(p)){console.error('[Hook] BLOCKED: Unnecessary documentation file creation');console.error('[Hook] File: '+p);console.error('[Hook] Use README.md for documentation instead');process.exit(2)}}catch{}console.log(d)})\"" } ], "description": "Block creation of random .md files - keeps docs consolidated" @@ -83,7 +83,7 @@ "hooks": [ { "type": "command", - "command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const cmd=i.tool_input?.command||'';if(/gh pr create/.test(cmd)){const out=i.tool_output?.output||'';const m=out.match(/https:\\/\\/github.com\\/[^/]+\\/[^/]+\\/pull\\/\\d+/);if(m){console.error('[Hook] PR created: '+m[0]);const repo=m[0].replace(/https:\\/\\/github.com\\/([^/]+\\/[^/]+)\\/pull\\/\\d+/,'$1');const pr=m[0].replace(/.*\\/pull\\/(\\d+)/,'$1');console.error('[Hook] To review: gh pr review '+pr+' --repo '+repo)}}console.log(d)})\"" + "command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const i=JSON.parse(d);const cmd=i.tool_input?.command||'';if(/gh pr create/.test(cmd)){const out=i.tool_output?.output||'';const m=out.match(/https:\\/\\/github.com\\/[^/]+\\/[^/]+\\/pull\\/\\d+/);if(m){console.error('[Hook] PR created: '+m[0]);const repo=m[0].replace(/https:\\/\\/github.com\\/([^/]+\\/[^/]+)\\/pull\\/\\d+/,'$1');const pr=m[0].replace(/.*\\/pull\\/(\\d+)/,'$1');console.error('[Hook] To review: gh pr review '+pr+' --repo '+repo)}}}catch{}console.log(d)})\"" } ], "description": "Log PR URL and provide review command after PR creation" @@ -93,7 +93,7 @@ "hooks": [ { "type": "command", - "command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const cmd=i.tool_input?.command||'';if(/(npm run build|pnpm build|yarn build)/.test(cmd)){console.error('[Hook] Build completed - async analysis running in background')}console.log(d)})\"", + "command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const i=JSON.parse(d);const cmd=i.tool_input?.command||'';if(/(npm run build|pnpm build|yarn build)/.test(cmd)){console.error('[Hook] Build completed - async analysis running in background')}}catch{}console.log(d)})\"", "async": true, "timeout": 30 } diff --git a/schemas/package-manager.schema.json b/schemas/package-manager.schema.json index 4047e83..883247f 100644 --- a/schemas/package-manager.schema.json +++ b/schemas/package-manager.schema.json @@ -11,7 +11,13 @@ "yarn", "bun" ] + }, + "setAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp when the preference was last set" } }, + "required": ["packageManager"], "additionalProperties": false -} \ No newline at end of file +} diff --git a/schemas/plugin.schema.json b/schemas/plugin.schema.json index d9fd1e2..834bb98 100644 --- a/schemas/plugin.schema.json +++ b/schemas/plugin.schema.json @@ -5,9 +5,35 @@ "required": ["name"], "properties": { "name": { "type": "string" }, + "version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" }, "description": { "type": "string" }, - "author": { "type": "string" }, + "author": { + "oneOf": [ + { "type": "string" }, + { + "type": "object", + "properties": { + "name": { "type": "string" }, + "url": { "type": "string", "format": "uri" } + }, + "required": ["name"] + } + ] + }, + "homepage": { "type": "string", "format": "uri" }, "repository": { "type": "string" }, - "license": { "type": "string" } + "license": { "type": "string" }, + "keywords": { + "type": "array", + "items": { "type": "string" } + }, + "skills": { + "type": "array", + "items": { "type": "string" } + }, + "agents": { + "type": "array", + "items": { "type": "string" } + } } } diff --git a/scripts/hooks/evaluate-session.js b/scripts/hooks/evaluate-session.js index 3cfaf2c..38a65bb 100644 --- a/scripts/hooks/evaluate-session.js +++ b/scripts/hooks/evaluate-session.js @@ -41,8 +41,8 @@ async function main() { // Handle ~ in path learnedSkillsPath = config.learned_skills_path.replace(/^~/, require('os').homedir()); } - } catch { - // Invalid config, use defaults + } catch (err) { + log(`[ContinuousLearning] Failed to parse config: ${err.message}, using defaults`); } }