diff --git a/cli/bin/commands/skills.mjs b/cli/bin/commands/skills.mjs index c62a2558b..a36f67900 100644 --- a/cli/bin/commands/skills.mjs +++ b/cli/bin/commands/skills.mjs @@ -1534,7 +1534,8 @@ function hookInstalledForProvider(root, provider) { function valueHasImpeccableHookMarker(value) { if (typeof value === 'string') { - return IMPECCABLE_HOOK_COMMAND_MARKERS.some(marker => value.includes(marker)); + const normalized = value.replace(/\\/g, '/'); + return IMPECCABLE_HOOK_COMMAND_MARKERS.some(marker => normalized.includes(marker)); } if (Array.isArray(value)) return value.some(valueHasImpeccableHookMarker); if (value && typeof value === 'object') { diff --git a/tests/skills-cli.test.js b/tests/skills-cli.test.js index f4e9b799d..e024f0b78 100644 --- a/tests/skills-cli.test.js +++ b/tests/skills-cli.test.js @@ -1649,6 +1649,35 @@ describe('hook manifest merge helpers', () => { 'node .cursor/skills/impeccable/scripts/hook-before-edit.mjs', ]); }); + + test('mergeHookManifests replaces legacy Windows-path Claude hooks (#604)', () => { + const legacyPath = 'C:\\Users\\alice\\.claude\\skills\\impeccable\\scripts\\hook.mjs'; + const legacyCommand = `[ ! -f "${legacyPath}" ] || node "${legacyPath}"`; + const freshCommand = `node -e "guard" "${legacyPath}"`; + const merged = mergeHookManifests( + { + hooks: { + PostToolUse: [{ matcher: 'Edit|Write|MultiEdit', hooks: [ + { type: 'command', command: legacyCommand }, + ] }], + Stop: [{ hooks: [{ type: 'command', command: legacyCommand }] }], + }, + }, + { + hooks: { + PostToolUse: [{ matcher: 'Edit|Write|MultiEdit', hooks: [ + { type: 'command', command: freshCommand }, + ] }], + Stop: [{ hooks: [{ type: 'command', command: freshCommand }] }], + }, + }, + ); + + expect(merged.hooks.PostToolUse).toHaveLength(1); + expect(merged.hooks.Stop).toHaveLength(1); + expect(merged.hooks.PostToolUse[0].hooks[0].command).toBe(freshCommand); + expect(merged.hooks.Stop[0].hooks[0].command).toBe(freshCommand); + }); }); // ─── Hook command path resolution (issue #399, part 1) ───────────────────────