diff --git a/.claude/hooks/auto-format.mjs b/.claude/hooks/auto-format.mjs index 66de977..d4fe276 100644 --- a/.claude/hooks/auto-format.mjs +++ b/.claude/hooks/auto-format.mjs @@ -2,14 +2,14 @@ // PostToolUse hook: auto-formats files after Write|Edit operations via prettier import { readFileSync, existsSync } from 'fs'; -import { execSync } from 'child_process'; +import { execFileSync } from 'child_process'; import { extname } from 'path'; let input; try { - input = JSON.parse(readFileSync(0, 'utf8')); + input = JSON.parse(readFileSync(0, 'utf8')); } catch { - process.exit(0); + process.exit(0); } const filePath = input?.tool_input?.file_path; @@ -22,14 +22,14 @@ const formattable = new Set(['.ts', '.js', '.mjs', '.svelte', '.json', '.css', ' const ext = extname(filePath); try { - if (formattable.has(ext)) { - execSync(`pnpm prettier --write "${filePath}"`, { - cwd: projectDir, - stdio: 'ignore', - }); - } + if (formattable.has(ext)) { + execFileSync('pnpm', ['prettier', '--write', filePath], { + cwd: projectDir, + stdio: 'ignore' + }); + } } catch { - // Formatting is best-effort + // Formatting is best-effort } process.exit(0); diff --git a/.claude/skills/address-review/SKILL.md b/.claude/skills/address-review/SKILL.md new file mode 100644 index 0000000..aaf96ed --- /dev/null +++ b/.claude/skills/address-review/SKILL.md @@ -0,0 +1,73 @@ +--- +description: Read PR review comments from GitHub, evaluate, address, and reply +user-invocable: true +argument-hint: '[PR number]' +--- + +# /address-review + +Read review comments on a GitHub PR, evaluate each one, and address it appropriately. + +## Steps + +1. **Resolve the PR number.** If an argument is provided, use it. Otherwise, detect from current branch: + +```bash +gh pr view --json number,title,url +``` + +2. **Fetch all review comments** (includes inline code comments and review threads): + +```bash +gh api repos/{owner}/{repo}/pulls/{number}/comments +gh api repos/{owner}/{repo}/pulls/{number}/reviews +``` + +Filter to only unresolved threads with actual review content. Read the full thread (all replies in each discussion), not just the first comment. + +3. **For each unresolved thread, evaluate what type of comment it is:** + +### A. Change request ("change this", "use X instead of Y", "add Z") + +1. Read the referenced file + surrounding context +2. Evaluate if the change is correct, factual, and worth it +3. If yes: make the change, reply with what was changed and which commit +4. If the change would break something or is incorrect: explain why and propose an alternative + +### B. Question ("why is this here?", "doesn't X already handle...?") + +Reply with a clear explanation. Reference specific code/docs. If the answer reveals a real issue, fix it too. + +### C. Suggestion / discussion ("we could...", "what if we...") + +Evaluate effort vs impact. Reply with one of: + +- "Good idea, I'll do it in this PR" (and do it) +- "Makes sense, but better as a follow-up" (explain why) +- "I don't think it's needed because..." (explain reasoning) + +### D. Factual correction ("that's not true", "table doesn't have column X") + +Verify the claim by reading the actual code/schema. If the reviewer is right, fix it. If wrong, explain with evidence. + +4. **Reply to each thread:** + +```bash +gh api repos/{owner}/{repo}/pulls/{number}/comments/{comment_id}/replies --method POST -f "body=" +``` + +Do NOT resolve threads that need further discussion from the reviewer. + +5. **After addressing all comments**, run `/verify`. + +6. **Commit and push** with a descriptive message like `fix: address review - `. + +## Rules + +- Read the FULL thread before responding (earlier replies give context) +- Reference specific commits when you make a change +- Never resolve a thread without either fixing the code or explaining why no change is needed +- If review comments contradict each other, flag the conflict for the user instead of trying to satisfy each of them +- Group related fixes into a single commit when they address the same concern +- Run `/verify` before pushing +- No em dashes in replies