Files
everything-claude-code/rules/web/hooks.md
Affaan Mustafa b39d2244cf docs: salvage focused stale PR contributions
- add Vite and Redis pattern skills from closed stale PRs

- add frontend-slides support assets

- port skill-comply runner fixes and LLM prompt/provider regressions

- harden agent frontmatter validation and sync catalog counts
2026-05-11 05:31:12 -04:00

3.4 KiB

This file extends common/hooks.md with web-specific hook recommendations.

Web Hooks

Prefer project-local tooling. Do not wire hooks to remote one-off package execution.

Format on Save

Use the project's existing formatter entrypoint after edits:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "pnpm prettier --write \"$FILE_PATH\"",
        "description": "Format edited frontend files"
      }
    ]
  }
}

Equivalent local commands via yarn prettier or npm exec prettier -- are fine when they use repo-owned dependencies.

Lint Check

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "pnpm eslint --fix \"$FILE_PATH\"",
        "description": "Run ESLint on edited frontend files"
      }
    ]
  }
}

Type Check

Use --incremental so re-runs reuse the previous .tsbuildinfo (1-3s on unchanged code instead of 30-60s every time). Wrap in timeout so a stuck tsc gets reaped by the OS instead of accumulating across edits — this prevents the multi-process buildup that happens when edits fire faster than tsc finishes.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "timeout 60 pnpm tsc --noEmit --pretty false --incremental --tsBuildInfoFile node_modules/.cache/tsc-hook.tsbuildinfo",
        "description": "Type-check after frontend edits (incremental + timeout-capped)"
      }
    ]
  }
}

Why both flags matter:

  • Without --incremental, every edit re-checks the entire program from scratch. On a real Next.js project this stacks fast: edits at 5-10s intervals + 30-60s tsc runs = N concurrent tsc processes.
  • Without timeout, a tsc that hangs (transitive dep change, type-checker stuck on a recursive type) never exits and orphans when the parent shell does.
  • --tsBuildInfoFile is required because --noEmit normally suppresses the buildinfo write; specifying the path explicitly keeps incremental working.

If you're on Windows without GNU coreutils, swap timeout 60 for a PowerShell wrapper or rely on a Stop/SessionEnd hook to sweep stale tsc processes.

CSS Lint

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "pnpm stylelint --fix \"$FILE_PATH\"",
        "description": "Lint edited stylesheets"
      }
    ]
  }
}

PreToolUse Hooks

Guard File Size

Block oversized writes from tool input content, not from a file that may not exist yet:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write",
        "command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const c=i.tool_input?.content||'';const lines=c.split('\\n').length;if(lines>800){console.error('[Hook] BLOCKED: File exceeds 800 lines ('+lines+' lines)');console.error('[Hook] Split into smaller modules');process.exit(2)}console.log(d)})\"",
        "description": "Block writes that exceed 800 lines"
      }
    ]
  }
}

Stop Hooks

Final Build Verification

{
  "hooks": {
    "Stop": [
      {
        "command": "pnpm build",
        "description": "Verify the production build at session end"
      }
    ]
  }
}

Ordering

Recommended order:

  1. format
  2. lint
  3. type check
  4. build verification