From 1df0a53f226272c6214a09ac0da357539eb7656f Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Mon, 2 Mar 2026 22:15:46 -0800 Subject: [PATCH] =?UTF-8?q?fix:=20resolve=20CI=20failures=20on=20main=20?= =?UTF-8?q?=E2=80=94=20lint,=20hooks=20validator,=20and=20test=20alignment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix MD012 trailing blank lines in commands/projects.md and commands/promote.md - Fix MD050 strong-style in continuous-learning-v2 (escape __tests__ as inline code) - Extract doc-file-warning hook to standalone script to fix hooks validator regex parsing - Update session-end test to match #317 behavior (always update summary content) - Allow shell script hooks in integration test format validation All 992 tests passing. --- commands/projects.md | 1 - commands/promote.md | 1 - hooks/hooks.json | 2 +- scripts/hooks/doc-file-warning.js | 24 +++++++++++++++++++ skills/continuous-learning-v2/SKILL.md | 2 +- .../continuous-learning-v2/agents/observer.md | 2 +- tests/hooks/hooks.test.js | 10 ++++---- tests/integration/hooks.test.js | 5 ++-- 8 files changed, 35 insertions(+), 12 deletions(-) create mode 100644 scripts/hooks/doc-file-warning.js diff --git a/commands/projects.md b/commands/projects.md index 8fa924ea..5009a7b1 100644 --- a/commands/projects.md +++ b/commands/projects.md @@ -37,4 +37,3 @@ python3 ~/.claude/skills/continuous-learning-v2/scripts/instinct-cli.py projects - Observation event count - Last seen timestamp 3. Also display global instinct totals - diff --git a/commands/promote.md b/commands/promote.md index 4f02e27d..c2d13da6 100644 --- a/commands/promote.md +++ b/commands/promote.md @@ -39,4 +39,3 @@ python3 ~/.claude/skills/continuous-learning-v2/scripts/instinct-cli.py promote - Appear in at least 2 projects - Meet confidence threshold 4. Write promoted instincts to `~/.claude/homunculus/instincts/personal/` with `scope: global` - diff --git a/hooks/hooks.json b/hooks/hooks.json index 7ff868a8..43c04589 100644 --- a/hooks/hooks.json +++ b/hooks/hooks.json @@ -37,7 +37,7 @@ "hooks": [ { "type": "command", - "command": "node -e \"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|CHANGELOG|LICENSE|SKILL)\\.md$/i.test(p)&&!/\\.claude[\\/\\\\]plans[\\/\\\\]/.test(p)&&!/(^|[\\/\\\\])(docs|skills)[\\/\\\\]/.test(p)){console.error('[Hook] WARNING: Non-standard documentation file detected');console.error('[Hook] File: '+p);console.error('[Hook] Consider consolidating into README.md or docs/ directory')}}catch{}console.log(d)})\"" + "command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/doc-file-warning.js\"" } ], "description": "Doc file warning: warn about non-standard documentation files (exit code 0; warns only)" diff --git a/scripts/hooks/doc-file-warning.js b/scripts/hooks/doc-file-warning.js new file mode 100644 index 00000000..a3fd844e --- /dev/null +++ b/scripts/hooks/doc-file-warning.js @@ -0,0 +1,24 @@ +/** + * Doc file warning hook (PreToolUse - Write) + * Warns about non-standard documentation files. + * Exit code 0 always (warns only, never blocks). + */ + +let data = ''; +process.stdin.on('data', c => data += c); +process.stdin.on('end', () => { + try { + const input = JSON.parse(data); + const filePath = input.tool_input?.file_path || ''; + + if (/\.(md|txt)$/.test(filePath) && + !/(README|CLAUDE|AGENTS|CONTRIBUTING|CHANGELOG|LICENSE|SKILL)\.md$/i.test(filePath) && + !/\.claude[\/\\]plans[\/\\]/.test(filePath) && + !/(^|[\/\\])(docs|skills)[\/\\]/.test(filePath)) { + console.error('[Hook] WARNING: Non-standard documentation file detected'); + console.error('[Hook] File: ' + filePath); + console.error('[Hook] Consider consolidating into README.md or docs/ directory'); + } + } catch { /* ignore parse errors */ } + console.log(data); +}); diff --git a/skills/continuous-learning-v2/SKILL.md b/skills/continuous-learning-v2/SKILL.md index ee1b3391..0256e1cb 100644 --- a/skills/continuous-learning-v2/SKILL.md +++ b/skills/continuous-learning-v2/SKILL.md @@ -276,7 +276,7 @@ Other behavior (observation capture, instinct thresholds, project scoping, promo | Pattern Type | Scope | Examples | |-------------|-------|---------| | Language/framework conventions | **project** | "Use React hooks", "Follow Django REST patterns" | -| File structure preferences | **project** | "Tests in __tests__/", "Components in src/components/" | +| File structure preferences | **project** | "Tests in `__tests__`/", "Components in src/components/" | | Code style | **project** | "Use functional style", "Prefer dataclasses" | | Error handling strategies | **project** | "Use Result type for errors" | | Security practices | **global** | "Validate user input", "Sanitize SQL" | diff --git a/skills/continuous-learning-v2/agents/observer.md b/skills/continuous-learning-v2/agents/observer.md index 81abb9c1..f0062688 100644 --- a/skills/continuous-learning-v2/agents/observer.md +++ b/skills/continuous-learning-v2/agents/observer.md @@ -124,7 +124,7 @@ When creating instincts, determine scope based on these heuristics: | Pattern Type | Scope | Examples | |-------------|-------|---------| | Language/framework conventions | **project** | "Use React hooks", "Follow Django REST patterns" | -| File structure preferences | **project** | "Tests in __tests__/", "Components in src/components/" | +| File structure preferences | **project** | "Tests in `__tests__`/", "Components in src/components/" | | Code style | **project** | "Use functional style", "Prefer dataclasses" | | Error handling strategies | **project** (usually) | "Use Result type for errors" | | Security practices | **global** | "Validate user input", "Sanitize SQL" | diff --git a/tests/hooks/hooks.test.js b/tests/hooks/hooks.test.js index f4afd036..55877bcf 100644 --- a/tests/hooks/hooks.test.js +++ b/tests/hooks/hooks.test.js @@ -1724,7 +1724,7 @@ async function runTests() { assert.ok(updated.includes('/src/auth.ts'), 'Should include modified file'); })) passed++; else failed++; - if (await asyncTest('preserves existing session content when no blank template marker', async () => { + if (await asyncTest('always updates session summary content on session end', async () => { const testDir = createTestDir(); const sessionsDir = path.join(testDir, '.claude', 'sessions'); fs.mkdirSync(sessionsDir, { recursive: true }); @@ -1734,7 +1734,7 @@ async function runTests() { const shortId = 'update03'; const sessionFile = path.join(sessionsDir, `${today}-${shortId}-session.tmp`); - // Pre-existing file with ALREADY-FILLED summary (no blank template marker) + // Pre-existing file with already-filled summary const existingContent = `# Session: ${today}\n**Date:** ${today}\n**Started:** 08:00\n**Last Updated:** 08:30\n\n---\n\n## Session Summary\n\n### Tasks\n- Previous task from earlier\n`; fs.writeFileSync(sessionFile, existingContent); @@ -1749,9 +1749,9 @@ async function runTests() { assert.strictEqual(result.code, 0); const updated = fs.readFileSync(sessionFile, 'utf8'); - // Should NOT overwrite existing summary (no blank template marker found) - assert.ok(updated.includes('Previous task from earlier'), 'Should preserve existing content'); - assert.ok(!updated.includes('New task'), 'Should not replace non-template content'); + // Session summary should always be refreshed with current content (#317) + assert.ok(updated.includes('## Session Summary'), 'Should have Session Summary section'); + assert.ok(updated.includes('# Session:'), 'Should preserve session header'); })) passed++; else failed++; console.log('\nRound 23: pre-compact.js (glob specificity):'); diff --git a/tests/integration/hooks.test.js b/tests/integration/hooks.test.js index 6bf0f064..7e2a2733 100644 --- a/tests/integration/hooks.test.js +++ b/tests/integration/hooks.test.js @@ -692,10 +692,11 @@ async function runTests() { const isInline = hook.command.startsWith('node -e'); const isFilePath = hook.command.startsWith('node "'); + const isShellScript = hook.command.endsWith('.sh'); assert.ok( - isInline || isFilePath, - `Hook command in ${hookType} should be inline (node -e) or file path (node "), got: ${hook.command.substring(0, 50)}` + isInline || isFilePath || isShellScript, + `Hook command in ${hookType} should be inline (node -e), file path (node "), or shell script (.sh), got: ${hook.command.substring(0, 80)}` ); } }