@hustle-together/api-dev-tools 3.12.3 → 4.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/adr-requests/.gitkeep +10 -0
- package/.claude/agents/adr-researcher.md +109 -0
- package/.claude/agents/visual-analyzer.md +183 -0
- package/.claude/api-dev-state.json +7 -463
- package/.claude/documentation-audit.json +114 -0
- package/.claude/registry.json +289 -0
- package/.claude/settings.json +45 -1
- package/.claude/workflow-logs/None.json +49 -0
- package/.claude/workflow-logs/session-20251230-143727.json +106 -0
- package/.skills/adr-deep-research/SKILL.md +351 -0
- package/.skills/api-create/SKILL.md +116 -17
- package/.skills/api-research/SKILL.md +130 -0
- package/.skills/docs-sync/SKILL.md +260 -0
- package/.skills/docs-update/SKILL.md +205 -0
- package/.skills/hustle-brand/SKILL.md +368 -0
- package/.skills/hustle-build/SKILL.md +786 -0
- package/.skills/hustle-build-review/SKILL.md +518 -0
- package/.skills/parallel-spawn/SKILL.md +212 -0
- package/.skills/ralph-continue/SKILL.md +151 -0
- package/.skills/ralph-loop/SKILL.md +341 -0
- package/.skills/ralph-status/SKILL.md +87 -0
- package/.skills/refactor/SKILL.md +59 -0
- package/.skills/shadcn/SKILL.md +522 -0
- package/.skills/test-all/SKILL.md +210 -0
- package/.skills/test-builds/SKILL.md +208 -0
- package/.skills/test-debug/SKILL.md +212 -0
- package/.skills/test-e2e/SKILL.md +168 -0
- package/.skills/test-review/SKILL.md +707 -0
- package/.skills/test-unit/SKILL.md +143 -0
- package/.skills/test-visual/SKILL.md +301 -0
- package/.skills/token-report/SKILL.md +132 -0
- package/CHANGELOG.md +575 -0
- package/README.md +426 -56
- package/bin/cli.js +1538 -88
- package/commands/hustle-api-create.md +22 -0
- package/commands/hustle-build.md +259 -0
- package/commands/hustle-combine.md +81 -2
- package/commands/hustle-ui-create-page.md +84 -2
- package/commands/hustle-ui-create.md +82 -2
- package/hooks/__pycache__/api-workflow-check.cpython-314.pyc +0 -0
- package/hooks/__pycache__/auto-answer.cpython-314.pyc +0 -0
- package/hooks/__pycache__/cache-research.cpython-314.pyc +0 -0
- package/hooks/__pycache__/check-api-routes.cpython-314.pyc +0 -0
- package/hooks/__pycache__/check-playwright-setup.cpython-314.pyc +0 -0
- package/hooks/__pycache__/check-storybook-setup.cpython-314.pyc +0 -0
- package/hooks/__pycache__/check-update.cpython-314.pyc +0 -0
- package/hooks/__pycache__/completion-promise-detector.cpython-314.pyc +0 -0
- package/hooks/__pycache__/context-capacity-warning.cpython-314.pyc +0 -0
- package/hooks/__pycache__/detect-interruption.cpython-314.pyc +0 -0
- package/hooks/__pycache__/docs-update-check.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-a11y-audit.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-brand-guide.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-component-type-confirm.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-deep-research.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-disambiguation.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-documentation.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-dry-run.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-environment.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-external-research.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-freshness.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-interview.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-page-components.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-page-data-schema.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-questions-sourced.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-refactor.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-research.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-schema-from-interview.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-schema.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-scope.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-tdd-red.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-ui-disambiguation.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-ui-interview.cpython-314.pyc +0 -0
- package/hooks/__pycache__/enforce-verify.cpython-314.pyc +0 -0
- package/hooks/__pycache__/generate-adr-options.cpython-314.pyc +0 -0
- package/hooks/__pycache__/generate-manifest-entry.cpython-314.pyc +0 -0
- package/hooks/__pycache__/hook_utils.cpython-314.pyc +0 -0
- package/hooks/__pycache__/notify-input-needed.cpython-314.pyc +0 -0
- package/hooks/__pycache__/notify-phase-complete.cpython-314.pyc +0 -0
- package/hooks/__pycache__/ntfy-on-question.cpython-314.pyc +0 -0
- package/hooks/__pycache__/orchestrator-completion.cpython-314.pyc +0 -0
- package/hooks/__pycache__/orchestrator-handoff.cpython-314.pyc +0 -0
- package/hooks/__pycache__/orchestrator-session-startup.cpython-314.pyc +0 -0
- package/hooks/__pycache__/parallel-orchestrator.cpython-314.pyc +0 -0
- package/hooks/__pycache__/periodic-reground.cpython-314.pyc +0 -0
- package/hooks/__pycache__/project-document-prompt.cpython-314.pyc +0 -0
- package/hooks/__pycache__/remote-question-proxy.cpython-314.pyc +0 -0
- package/hooks/__pycache__/remote-question-server.cpython-314.pyc +0 -0
- package/hooks/__pycache__/run-code-review.cpython-314.pyc +0 -0
- package/hooks/__pycache__/run-visual-qa.cpython-314.pyc +0 -0
- package/hooks/__pycache__/session-logger.cpython-314.pyc +0 -0
- package/hooks/__pycache__/session-startup.cpython-314.pyc +0 -0
- package/hooks/__pycache__/track-scope-coverage.cpython-314.pyc +0 -0
- package/hooks/__pycache__/track-token-usage.cpython-314.pyc +0 -0
- package/hooks/__pycache__/track-tool-use.cpython-314.pyc +0 -0
- package/hooks/__pycache__/update-adr-decision.cpython-314.pyc +0 -0
- package/hooks/__pycache__/update-api-showcase.cpython-314.pyc +0 -0
- package/hooks/__pycache__/update-registry.cpython-314.pyc +0 -0
- package/hooks/__pycache__/update-ui-showcase.cpython-314.pyc +0 -0
- package/hooks/__pycache__/verify-after-green.cpython-314.pyc +0 -0
- package/hooks/__pycache__/verify-implementation.cpython-314.pyc +0 -0
- package/hooks/api-workflow-check.py +34 -0
- package/hooks/auto-answer.py +305 -0
- package/hooks/check-update.py +132 -0
- package/hooks/completion-promise-detector.py +293 -0
- package/hooks/context-capacity-warning.py +171 -0
- package/hooks/docs-update-check.py +120 -0
- package/hooks/enforce-dry-run.py +134 -0
- package/hooks/enforce-external-research.py +25 -0
- package/hooks/enforce-interview.py +20 -0
- package/hooks/generate-adr-options.py +282 -0
- package/hooks/hook_utils.py +609 -0
- package/hooks/lib/__pycache__/__init__.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/greptile.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/ntfy.cpython-314.pyc +0 -0
- package/hooks/ntfy-on-question.py +240 -0
- package/hooks/orchestrator-completion.py +313 -0
- package/hooks/orchestrator-handoff.py +267 -0
- package/hooks/orchestrator-session-startup.py +146 -0
- package/hooks/parallel-orchestrator.py +451 -0
- package/hooks/periodic-reground.py +270 -67
- package/hooks/project-document-prompt.py +302 -0
- package/hooks/remote-question-proxy.py +284 -0
- package/hooks/remote-question-server.py +1224 -0
- package/hooks/run-code-review.py +176 -29
- package/hooks/run-visual-qa.py +338 -0
- package/hooks/session-logger.py +27 -1
- package/hooks/session-startup.py +113 -0
- package/hooks/update-adr-decision.py +236 -0
- package/hooks/update-api-showcase.py +13 -1
- package/hooks/update-testing-checklist.py +195 -0
- package/hooks/update-ui-showcase.py +13 -1
- package/package.json +7 -3
- package/scripts/extract-schema-docs.cjs +322 -0
- package/templates/.skills/hustle-interview/SKILL.md +174 -0
- package/templates/CLAUDE-SECTION.md +89 -64
- package/templates/adr-viewer/_components/ADRViewer.tsx +326 -0
- package/templates/api-dev-state.json +33 -1
- package/templates/api-showcase/_components/APIModal.tsx +100 -8
- package/templates/api-showcase/_components/APIShowcase.tsx +36 -4
- package/templates/api-showcase/_components/APITester.tsx +367 -58
- package/templates/brand-page/page.tsx +645 -0
- package/templates/component/Component.visual.spec.ts +30 -24
- package/templates/docs/page.tsx +230 -0
- package/templates/eslint-plugin-zod-schema/index.js +446 -0
- package/templates/eslint-plugin-zod-schema/package.json +26 -0
- package/templates/github-workflows/security.yml +274 -0
- package/templates/hustle-build-defaults.json +136 -0
- package/templates/hustle-dev-dashboard/page.tsx +365 -0
- package/templates/page/page.e2e.test.ts +30 -26
- package/templates/performance-budgets.json +63 -5
- package/templates/playwright-report/page.tsx +258 -0
- package/templates/registry.json +279 -3
- package/templates/review-dashboard/page.tsx +510 -0
- package/templates/settings.json +155 -7
- package/templates/test-results/page.tsx +237 -0
- package/templates/typedoc.json +19 -0
- package/templates/ui-showcase/_components/UIShowcase.tsx +48 -1
- package/templates/ui-showcase/_components/VisualTestingDashboard.tsx +579 -0
- package/templates/ui-showcase/page.tsx +1 -1
|
@@ -0,0 +1,707 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-review
|
|
3
|
+
description: AI-powered code review for antipatterns, security, and performance
|
|
4
|
+
tools: Bash, Read, Glob, Grep, Task
|
|
5
|
+
model: sonnet
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Test Review Skill
|
|
9
|
+
|
|
10
|
+
Analyze code for security vulnerabilities, performance issues, antipatterns, and best practice violations using a tiered approach: deterministic ESLint rules + structured AI review.
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
- After implementing a feature
|
|
15
|
+
- Before creating a pull request
|
|
16
|
+
- To audit existing code
|
|
17
|
+
- During code review phase (Phase 11)
|
|
18
|
+
|
|
19
|
+
## Tiered Strategy for Large Codebases
|
|
20
|
+
|
|
21
|
+
> **Reality Check:** AI cannot hold 5000 files in context at once.
|
|
22
|
+
> We use a tiered approach to ensure comprehensive coverage.
|
|
23
|
+
|
|
24
|
+
### Tier 1: ESLint (ALL Files - Deterministic)
|
|
25
|
+
|
|
26
|
+
ESLint runs on **every file**, every time. This is fast pattern matching that scales infinitely.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Run on entire codebase
|
|
30
|
+
pnpm eslint src/ --plugin security --plugin no-unsanitized --format json > eslint-report.json
|
|
31
|
+
|
|
32
|
+
# Count files scanned
|
|
33
|
+
jq '.length' eslint-report.json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**What ESLint Catches (100% Coverage):**
|
|
37
|
+
- XSS via innerHTML/insertAdjacentHTML
|
|
38
|
+
- eval() with user input
|
|
39
|
+
- Path traversal via fs calls
|
|
40
|
+
- Prototype pollution via bracket notation
|
|
41
|
+
- Regex DoS patterns
|
|
42
|
+
- Command injection via child_process
|
|
43
|
+
|
|
44
|
+
### Tier 2: AI Review - Changed Files (Per Commit/PR)
|
|
45
|
+
|
|
46
|
+
Only review files that changed in the current branch/PR.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Get changed files
|
|
50
|
+
git diff --name-only main...HEAD | grep -E '\.(ts|tsx|js|jsx)$'
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Limit:** 50-100 files max per AI review session.
|
|
54
|
+
|
|
55
|
+
### Tier 3: AI Review - Critical Paths (Always Included)
|
|
56
|
+
|
|
57
|
+
Even if unchanged, always include security-critical files:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Critical paths that ALWAYS get reviewed
|
|
61
|
+
CRITICAL_PATHS=(
|
|
62
|
+
"src/app/api/**/*" # All API routes
|
|
63
|
+
"src/middleware*" # Middleware
|
|
64
|
+
"src/lib/auth*" # Auth utilities
|
|
65
|
+
"src/lib/db*" # Database utilities
|
|
66
|
+
"src/lib/crypto*" # Cryptography
|
|
67
|
+
"src/hooks/useAuth*" # Auth hooks
|
|
68
|
+
)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Tier 4: Full Scan (Weekly/Scheduled)
|
|
72
|
+
|
|
73
|
+
For complete codebase audits, batch files:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Split files into batches of 200
|
|
77
|
+
find src -name "*.ts" -o -name "*.tsx" | split -l 200 - batch_
|
|
78
|
+
|
|
79
|
+
# Review each batch separately
|
|
80
|
+
for batch in batch_*; do
|
|
81
|
+
/test-review $(cat $batch | tr '\n' ' ')
|
|
82
|
+
done
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Output:** Aggregate report with all findings across batches.
|
|
86
|
+
|
|
87
|
+
## How We Know Everything Was Reviewed
|
|
88
|
+
|
|
89
|
+
### Coverage Tracking
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# Total files in codebase
|
|
93
|
+
TOTAL=$(find src -name "*.ts" -o -name "*.tsx" | wc -l)
|
|
94
|
+
|
|
95
|
+
# Files covered by ESLint
|
|
96
|
+
ESLINT_COVERED=$(jq '.length' eslint-report.json)
|
|
97
|
+
|
|
98
|
+
# Files reviewed by AI
|
|
99
|
+
AI_REVIEWED=$(cat .claude/review-log.json | jq '.files_reviewed | length')
|
|
100
|
+
|
|
101
|
+
# Coverage report
|
|
102
|
+
echo "ESLint Coverage: $ESLINT_COVERED / $TOTAL (100%)"
|
|
103
|
+
echo "AI Review Coverage: $AI_REVIEWED files (changed + critical)"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Review Log (Written After Each Review)
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
// .claude/review-log.json
|
|
110
|
+
{
|
|
111
|
+
"last_full_scan": "2025-12-29T10:00:00Z",
|
|
112
|
+
"last_pr_review": "2025-12-29T15:30:00Z",
|
|
113
|
+
"files_reviewed": [
|
|
114
|
+
"src/app/api/users/route.ts",
|
|
115
|
+
"src/lib/auth.ts"
|
|
116
|
+
],
|
|
117
|
+
"findings_count": {
|
|
118
|
+
"critical": 0,
|
|
119
|
+
"warning": 2,
|
|
120
|
+
"suggestion": 5
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## AI Security Detection Patterns
|
|
126
|
+
|
|
127
|
+
### What AI Catches (That ESLint Cannot)
|
|
128
|
+
|
|
129
|
+
These require understanding context and data flow:
|
|
130
|
+
|
|
131
|
+
#### 1. SQL Injection
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// DETECT: Raw SQL with template literals
|
|
135
|
+
const result = await db.query(`SELECT * FROM users WHERE id = ${userId}`);
|
|
136
|
+
|
|
137
|
+
// SAFE: Parameterized queries
|
|
138
|
+
const result = await db.query('SELECT * FROM users WHERE id = $1', [userId]);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**AI Pattern:** Look for SQL keywords (SELECT, INSERT, UPDATE, DELETE) with template literals containing variables.
|
|
142
|
+
|
|
143
|
+
#### 2. Authentication Bypass
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
// DETECT: API route without auth check
|
|
147
|
+
export async function GET(request: Request) {
|
|
148
|
+
const data = await fetchSensitiveData();
|
|
149
|
+
return Response.json(data);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// SAFE: Auth middleware applied
|
|
153
|
+
export async function GET(request: Request) {
|
|
154
|
+
const session = await auth();
|
|
155
|
+
if (!session) return new Response('Unauthorized', { status: 401 });
|
|
156
|
+
const data = await fetchSensitiveData();
|
|
157
|
+
return Response.json(data);
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**AI Pattern:** Check every API route for authentication calls (auth(), getSession(), validateToken()).
|
|
162
|
+
|
|
163
|
+
#### 3. CSRF Vulnerabilities
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// DETECT: Mutation without CSRF token
|
|
167
|
+
export async function POST(request: Request) {
|
|
168
|
+
const data = await request.json();
|
|
169
|
+
await updateUser(data);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// SAFE: CSRF token validated
|
|
173
|
+
export async function POST(request: Request) {
|
|
174
|
+
const token = request.headers.get('X-CSRF-Token');
|
|
175
|
+
if (!validateCsrfToken(token)) throw new Error('Invalid CSRF');
|
|
176
|
+
const data = await request.json();
|
|
177
|
+
await updateUser(data);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**AI Pattern:** POST/PUT/DELETE endpoints without CSRF validation.
|
|
182
|
+
|
|
183
|
+
#### 4. Insecure Direct Object Reference (IDOR)
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
// DETECT: No ownership check
|
|
187
|
+
export async function GET(request: Request, { params }: { params: { id: string } }) {
|
|
188
|
+
const order = await getOrder(params.id);
|
|
189
|
+
return Response.json(order);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// SAFE: Ownership verified
|
|
193
|
+
export async function GET(request: Request, { params }: { params: { id: string } }) {
|
|
194
|
+
const session = await auth();
|
|
195
|
+
const order = await getOrder(params.id);
|
|
196
|
+
if (order.userId !== session.user.id) {
|
|
197
|
+
return new Response('Forbidden', { status: 403 });
|
|
198
|
+
}
|
|
199
|
+
return Response.json(order);
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**AI Pattern:** Route handlers that fetch resources without checking ownership.
|
|
204
|
+
|
|
205
|
+
#### 5. Mass Assignment
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
// DETECT: Spreading user input to database
|
|
209
|
+
const user = await prisma.user.update({
|
|
210
|
+
where: { id: userId },
|
|
211
|
+
data: { ...request.body } // User could set role: 'admin'
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// SAFE: Allowlist fields
|
|
215
|
+
const { name, email } = request.body;
|
|
216
|
+
const user = await prisma.user.update({
|
|
217
|
+
where: { id: userId },
|
|
218
|
+
data: { name, email }
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**AI Pattern:** Spread operators with user input into database operations.
|
|
223
|
+
|
|
224
|
+
#### 6. Sensitive Data Exposure
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
// DETECT: Password in response
|
|
228
|
+
return Response.json({ user }); // user object includes password field
|
|
229
|
+
|
|
230
|
+
// SAFE: Exclude sensitive fields
|
|
231
|
+
const { password, ...safeUser } = user;
|
|
232
|
+
return Response.json({ user: safeUser });
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**AI Pattern:** API responses that include fields named password, secret, token, key.
|
|
236
|
+
|
|
237
|
+
## Multi-Pass Review System
|
|
238
|
+
|
|
239
|
+
> **Why Multi-Pass?** Each pass focuses on ONE category. This prevents context dilution
|
|
240
|
+
> and ensures deterministic checklist completion.
|
|
241
|
+
|
|
242
|
+
### Pass Structure
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
246
|
+
│ MULTI-PASS REVIEW │
|
|
247
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
248
|
+
│ │
|
|
249
|
+
│ PASS 1: Logic & Bugs │
|
|
250
|
+
│ ├─ Null/undefined handling │
|
|
251
|
+
│ ├─ Off-by-one errors │
|
|
252
|
+
│ ├─ Race conditions │
|
|
253
|
+
│ ├─ Type coercion issues │
|
|
254
|
+
│ └─ Dead code paths │
|
|
255
|
+
│ │
|
|
256
|
+
│ PASS 2: Security │
|
|
257
|
+
│ ├─ Authentication bypass │
|
|
258
|
+
│ ├─ Authorization gaps │
|
|
259
|
+
│ ├─ Input validation │
|
|
260
|
+
│ ├─ Data exposure │
|
|
261
|
+
│ └─ Injection vulnerabilities │
|
|
262
|
+
│ │
|
|
263
|
+
│ PASS 3: Performance │
|
|
264
|
+
│ ├─ N+1 queries │
|
|
265
|
+
│ ├─ Missing indexes │
|
|
266
|
+
│ ├─ Unbounded loops │
|
|
267
|
+
│ ├─ Memory leaks │
|
|
268
|
+
│ └─ Unnecessary re-renders │
|
|
269
|
+
│ │
|
|
270
|
+
│ PASS 4: Miscellaneous (AI Judgment) │
|
|
271
|
+
│ ├─ Code clarity │
|
|
272
|
+
│ ├─ Pattern consistency │
|
|
273
|
+
│ ├─ Error handling gaps │
|
|
274
|
+
│ └─ Documentation needs │
|
|
275
|
+
│ │
|
|
276
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Pass 1: Logic & Bugs (Deterministic Checklist)
|
|
280
|
+
|
|
281
|
+
Each item is a YES/NO question. The AI must answer ALL items.
|
|
282
|
+
|
|
283
|
+
```markdown
|
|
284
|
+
## Pass 1: Logic & Bugs Checklist
|
|
285
|
+
|
|
286
|
+
### Null/Undefined Handling
|
|
287
|
+
- [ ] All optional properties checked before access
|
|
288
|
+
- [ ] Array/object spread on potentially null values
|
|
289
|
+
- [ ] Promise rejections properly caught
|
|
290
|
+
- [ ] Default values provided for destructuring
|
|
291
|
+
|
|
292
|
+
### Off-by-One Errors
|
|
293
|
+
- [ ] Loop bounds correct (< vs <=)
|
|
294
|
+
- [ ] Array indices valid (0-based accounting)
|
|
295
|
+
- [ ] String slice/substring bounds correct
|
|
296
|
+
- [ ] Pagination offset/limit calculations
|
|
297
|
+
|
|
298
|
+
### Race Conditions
|
|
299
|
+
- [ ] State updates batched appropriately
|
|
300
|
+
- [ ] Async operations don't have stale closures
|
|
301
|
+
- [ ] Concurrent modifications handled
|
|
302
|
+
- [ ] Loading states prevent double-submits
|
|
303
|
+
|
|
304
|
+
### Type Coercion
|
|
305
|
+
- [ ] === used instead of == for comparisons
|
|
306
|
+
- [ ] Number parsing handles NaN
|
|
307
|
+
- [ ] Boolean coercion is intentional
|
|
308
|
+
- [ ] String concatenation vs addition clear
|
|
309
|
+
|
|
310
|
+
### Dead Code
|
|
311
|
+
- [ ] No unreachable code after returns
|
|
312
|
+
- [ ] Switch cases have breaks/returns
|
|
313
|
+
- [ ] Conditional logic can be triggered
|
|
314
|
+
- [ ] Unused variables and imports
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Pass 2: Security (Deterministic Checklist)
|
|
318
|
+
|
|
319
|
+
```markdown
|
|
320
|
+
## Pass 2: Security Checklist
|
|
321
|
+
|
|
322
|
+
### Authentication
|
|
323
|
+
- [ ] All API routes check session/token validity
|
|
324
|
+
- [ ] JWT tokens verified for expiration
|
|
325
|
+
- [ ] Sensitive routes require re-authentication
|
|
326
|
+
- [ ] Password reset tokens are single-use
|
|
327
|
+
|
|
328
|
+
### Authorization
|
|
329
|
+
- [ ] Role-based access enforced
|
|
330
|
+
- [ ] Resource ownership verified (IDOR prevention)
|
|
331
|
+
- [ ] Admin routes protected
|
|
332
|
+
- [ ] Elevated actions logged
|
|
333
|
+
|
|
334
|
+
### Input Validation
|
|
335
|
+
- [ ] User inputs validated with Zod/joi/yup
|
|
336
|
+
- [ ] SQL queries use parameterized statements
|
|
337
|
+
- [ ] File uploads checked (type, size, content)
|
|
338
|
+
- [ ] URL parameters sanitized
|
|
339
|
+
|
|
340
|
+
### Data Protection
|
|
341
|
+
- [ ] Passwords excluded from API responses
|
|
342
|
+
- [ ] Error messages don't leak internals
|
|
343
|
+
- [ ] Logs sanitized of PII/secrets
|
|
344
|
+
- [ ] HTTPS enforced
|
|
345
|
+
|
|
346
|
+
### Session Security
|
|
347
|
+
- [ ] Session tokens HTTP-only cookies
|
|
348
|
+
- [ ] CSRF tokens on mutations
|
|
349
|
+
- [ ] Session expiration enforced
|
|
350
|
+
- [ ] Logout invalidates server-side
|
|
351
|
+
|
|
352
|
+
### API Security
|
|
353
|
+
- [ ] Rate limiting on auth endpoints
|
|
354
|
+
- [ ] CORS allows specific origins only
|
|
355
|
+
- [ ] API keys are environment variables
|
|
356
|
+
- [ ] Webhook signatures verified
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Pass 3: Performance (Deterministic Checklist)
|
|
360
|
+
|
|
361
|
+
```markdown
|
|
362
|
+
## Pass 3: Performance Checklist
|
|
363
|
+
|
|
364
|
+
### Database
|
|
365
|
+
- [ ] No N+1 queries (use eager loading)
|
|
366
|
+
- [ ] Queries have appropriate indexes
|
|
367
|
+
- [ ] Large result sets paginated
|
|
368
|
+
- [ ] Expensive queries cached
|
|
369
|
+
|
|
370
|
+
### Memory
|
|
371
|
+
- [ ] Event listeners cleaned up
|
|
372
|
+
- [ ] Large objects garbage collected
|
|
373
|
+
- [ ] Streams used for large files
|
|
374
|
+
- [ ] Subscriptions unsubscribed
|
|
375
|
+
|
|
376
|
+
### Rendering (React)
|
|
377
|
+
- [ ] useMemo for expensive calculations
|
|
378
|
+
- [ ] useCallback for stable references
|
|
379
|
+
- [ ] Keys on list items are stable
|
|
380
|
+
- [ ] Components split for isolation
|
|
381
|
+
|
|
382
|
+
### Network
|
|
383
|
+
- [ ] Requests debounced/throttled
|
|
384
|
+
- [ ] Responses compressed
|
|
385
|
+
- [ ] Assets lazy loaded
|
|
386
|
+
- [ ] API calls batched when possible
|
|
387
|
+
|
|
388
|
+
### Async
|
|
389
|
+
- [ ] Parallel execution where possible
|
|
390
|
+
- [ ] Timeouts on external calls
|
|
391
|
+
- [ ] Retries with backoff
|
|
392
|
+
- [ ] Loading states prevent waterfalls
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Pass 4: Miscellaneous (AI Judgment)
|
|
396
|
+
|
|
397
|
+
> Unlike Passes 1-3, this pass uses AI judgment for subjective items.
|
|
398
|
+
|
|
399
|
+
```markdown
|
|
400
|
+
## Pass 4: Miscellaneous
|
|
401
|
+
|
|
402
|
+
### Code Clarity
|
|
403
|
+
- Is the code self-documenting?
|
|
404
|
+
- Are variable names descriptive?
|
|
405
|
+
- Are complex algorithms commented?
|
|
406
|
+
- Could any logic be simplified?
|
|
407
|
+
|
|
408
|
+
### Pattern Consistency
|
|
409
|
+
- Does it follow project conventions?
|
|
410
|
+
- Is error handling consistent?
|
|
411
|
+
- Are similar operations handled similarly?
|
|
412
|
+
- Does it match surrounding code style?
|
|
413
|
+
|
|
414
|
+
### Error Handling
|
|
415
|
+
- Are all error cases covered?
|
|
416
|
+
- Are errors user-friendly?
|
|
417
|
+
- Is error context preserved?
|
|
418
|
+
- Are failures graceful?
|
|
419
|
+
|
|
420
|
+
### Documentation Needs
|
|
421
|
+
- Do public APIs have JSDoc?
|
|
422
|
+
- Are complex types documented?
|
|
423
|
+
- Are edge cases noted?
|
|
424
|
+
- Is the README updated if needed?
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
## Review Execution
|
|
428
|
+
|
|
429
|
+
### Sequential Pass Execution
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
# Each pass runs independently and reports findings
|
|
433
|
+
/test-review --pass logic # Pass 1
|
|
434
|
+
/test-review --pass security # Pass 2
|
|
435
|
+
/test-review --pass perf # Pass 3
|
|
436
|
+
/test-review --pass misc # Pass 4
|
|
437
|
+
|
|
438
|
+
# Or run all passes in sequence
|
|
439
|
+
/test-review --all-passes
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Pass Output Format
|
|
443
|
+
|
|
444
|
+
```
|
|
445
|
+
═══════════════════════════════════════════════════════════════
|
|
446
|
+
PASS 1: LOGIC & BUGS
|
|
447
|
+
═══════════════════════════════════════════════════════════════
|
|
448
|
+
|
|
449
|
+
Files Reviewed: 45
|
|
450
|
+
Time: 2m 34s
|
|
451
|
+
|
|
452
|
+
Checklist Results:
|
|
453
|
+
┌────────────────────────────────────────────────────┬─────────┐
|
|
454
|
+
│ Item │ Status │
|
|
455
|
+
├────────────────────────────────────────────────────┼─────────┤
|
|
456
|
+
│ Null/Undefined Handling │ │
|
|
457
|
+
│ ├─ Optional properties checked │ ✅ Pass │
|
|
458
|
+
│ ├─ Spread on null values │ ⚠️ Warn │
|
|
459
|
+
│ ├─ Promise rejections caught │ ✅ Pass │
|
|
460
|
+
│ └─ Default values for destructuring │ ✅ Pass │
|
|
461
|
+
├────────────────────────────────────────────────────┼─────────┤
|
|
462
|
+
│ Off-by-One Errors │ │
|
|
463
|
+
│ ├─ Loop bounds correct │ ✅ Pass │
|
|
464
|
+
│ ├─ Array indices valid │ ✅ Pass │
|
|
465
|
+
│ ├─ String slice bounds │ ✅ Pass │
|
|
466
|
+
│ └─ Pagination calculations │ ❌ Fail │
|
|
467
|
+
└────────────────────────────────────────────────────┴─────────┘
|
|
468
|
+
|
|
469
|
+
Findings:
|
|
470
|
+
───────────────────────────────────────────────────────────────
|
|
471
|
+
|
|
472
|
+
❌ FAIL: Pagination calculations
|
|
473
|
+
File: src/app/api/users/route.ts:67
|
|
474
|
+
Code: const offset = (page - 1) * limit + 1
|
|
475
|
+
Issue: Off-by-one error - offset should not add 1
|
|
476
|
+
Fix: const offset = (page - 1) * limit
|
|
477
|
+
|
|
478
|
+
⚠️ WARN: Spread on null values
|
|
479
|
+
File: src/lib/merge.ts:23
|
|
480
|
+
Code: const result = { ...maybeNull }
|
|
481
|
+
Issue: maybeNull could be null/undefined
|
|
482
|
+
Fix: const result = { ...(maybeNull ?? {}) }
|
|
483
|
+
|
|
484
|
+
═══════════════════════════════════════════════════════════════
|
|
485
|
+
Pass 1 Complete: 1 Failure, 1 Warning
|
|
486
|
+
═══════════════════════════════════════════════════════════════
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Combined Report
|
|
490
|
+
|
|
491
|
+
After all passes:
|
|
492
|
+
|
|
493
|
+
```
|
|
494
|
+
═══════════════════════════════════════════════════════════════
|
|
495
|
+
MULTI-PASS REVIEW SUMMARY
|
|
496
|
+
═══════════════════════════════════════════════════════════════
|
|
497
|
+
|
|
498
|
+
Pass Results:
|
|
499
|
+
───────────────────────────────────────────────────────────────
|
|
500
|
+
Pass 1 - Logic & Bugs: 1 ❌ 1 ⚠️ 18 ✅
|
|
501
|
+
Pass 2 - Security: 0 ❌ 2 ⚠️ 22 ✅
|
|
502
|
+
Pass 3 - Performance: 2 ❌ 0 ⚠️ 14 ✅
|
|
503
|
+
Pass 4 - Miscellaneous: 0 ❌ 3 ⚠️ 4 ✅
|
|
504
|
+
───────────────────────────────────────────────────────────────
|
|
505
|
+
TOTAL: 3 ❌ 6 ⚠️ 58 ✅ (87% Pass Rate)
|
|
506
|
+
───────────────────────────────────────────────────────────────
|
|
507
|
+
|
|
508
|
+
Critical Issues (Must Fix):
|
|
509
|
+
1. [Logic] Off-by-one in pagination (users/route.ts:67)
|
|
510
|
+
2. [Perf] N+1 query in orders loop (orders/route.ts:34)
|
|
511
|
+
3. [Perf] Missing useCallback causing re-renders (Dashboard.tsx:89)
|
|
512
|
+
|
|
513
|
+
Warnings (Should Fix):
|
|
514
|
+
1. [Logic] Spread on potential null (merge.ts:23)
|
|
515
|
+
2. [Security] CORS allows localhost in prod (middleware.ts:12)
|
|
516
|
+
3. [Security] Session cookie missing SameSite (auth.ts:45)
|
|
517
|
+
4. [Misc] Complex function needs comment (utils.ts:123)
|
|
518
|
+
5. [Misc] Inconsistent error handling (api/orders)
|
|
519
|
+
6. [Misc] Missing JSDoc on public API (types.ts)
|
|
520
|
+
|
|
521
|
+
═══════════════════════════════════════════════════════════════
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
## Execution Steps
|
|
525
|
+
|
|
526
|
+
### Step 1: Run ESLint Security Scan (All Files)
|
|
527
|
+
|
|
528
|
+
```bash
|
|
529
|
+
# Ensure security plugins installed
|
|
530
|
+
pnpm add -D eslint-plugin-security eslint-plugin-no-unsanitized
|
|
531
|
+
|
|
532
|
+
# Run full scan
|
|
533
|
+
pnpm eslint src/ --plugin security --plugin no-unsanitized --format json > eslint-security.json
|
|
534
|
+
|
|
535
|
+
# Count issues
|
|
536
|
+
CRITICAL=$(jq '[.[] | .messages[] | select(.severity == 2)] | length' eslint-security.json)
|
|
537
|
+
echo "ESLint found $CRITICAL critical issues"
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### Step 2: Identify Files for AI Review
|
|
541
|
+
|
|
542
|
+
```bash
|
|
543
|
+
# Changed files
|
|
544
|
+
CHANGED=$(git diff --name-only main...HEAD | grep -E '\.(ts|tsx|js|jsx)$')
|
|
545
|
+
|
|
546
|
+
# Critical paths (always review)
|
|
547
|
+
CRITICAL_PATHS="src/app/api src/middleware src/lib/auth"
|
|
548
|
+
|
|
549
|
+
# Combine and deduplicate
|
|
550
|
+
FILES_TO_REVIEW=$(echo "$CHANGED" "$CRITICAL_PATHS" | tr ' ' '\n' | sort -u)
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### Step 3: Spawn AI Review (Batched if Needed)
|
|
554
|
+
|
|
555
|
+
```javascript
|
|
556
|
+
// If > 100 files, batch
|
|
557
|
+
const batches = chunk(filesToReview, 100);
|
|
558
|
+
|
|
559
|
+
for (const batch of batches) {
|
|
560
|
+
Task({
|
|
561
|
+
subagent_type: "code-reviewer",
|
|
562
|
+
model: "sonnet",
|
|
563
|
+
prompt: `Review these files using the security checklist:
|
|
564
|
+
${batch.join('\n')}
|
|
565
|
+
|
|
566
|
+
Check for:
|
|
567
|
+
1. SQL Injection (template literals with SQL)
|
|
568
|
+
2. Auth Bypass (API routes without auth)
|
|
569
|
+
3. CSRF (mutations without token validation)
|
|
570
|
+
4. IDOR (no ownership verification)
|
|
571
|
+
5. Mass Assignment (spreading user input)
|
|
572
|
+
6. Data Exposure (passwords in responses)
|
|
573
|
+
|
|
574
|
+
Return JSON: {findings: [{file, line, type, severity, detail, fix}]}`
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
### Step 4: Generate Coverage Report
|
|
580
|
+
|
|
581
|
+
```
|
|
582
|
+
═══════════════════════════════════════════════════════════════
|
|
583
|
+
SECURITY REVIEW REPORT
|
|
584
|
+
═══════════════════════════════════════════════════════════════
|
|
585
|
+
|
|
586
|
+
Coverage:
|
|
587
|
+
───────────────────────────────────────────────────────────────
|
|
588
|
+
ESLint (Deterministic): 1,234 / 1,234 files (100%)
|
|
589
|
+
AI Review (Changed): 45 files
|
|
590
|
+
AI Review (Critical Paths): 12 files
|
|
591
|
+
───────────────────────────────────────────────────────────────
|
|
592
|
+
|
|
593
|
+
ESLint Findings:
|
|
594
|
+
───────────────────────────────────────────────────────────────
|
|
595
|
+
✅ No critical issues
|
|
596
|
+
⚠️ 2 warnings (see eslint-security.json)
|
|
597
|
+
───────────────────────────────────────────────────────────────
|
|
598
|
+
|
|
599
|
+
AI Review Findings:
|
|
600
|
+
───────────────────────────────────────────────────────────────
|
|
601
|
+
🔴 Critical: 1
|
|
602
|
+
- src/app/api/users/route.ts:45 - SQL Injection
|
|
603
|
+
Code: `SELECT * FROM users WHERE id = ${userId}`
|
|
604
|
+
Fix: Use parameterized query
|
|
605
|
+
|
|
606
|
+
🟠 Warning: 2
|
|
607
|
+
- src/app/api/orders/route.ts:23 - Missing ownership check
|
|
608
|
+
- src/lib/auth.ts:89 - Session token not HTTP-only
|
|
609
|
+
|
|
610
|
+
🟡 Suggestion: 3
|
|
611
|
+
- src/hooks/useData.ts:12 - Add error boundary
|
|
612
|
+
───────────────────────────────────────────────────────────────
|
|
613
|
+
|
|
614
|
+
Last Full Scan: 2025-12-29
|
|
615
|
+
Next Scheduled: 2026-01-05 (weekly)
|
|
616
|
+
|
|
617
|
+
═══════════════════════════════════════════════════════════════
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
## Arguments
|
|
621
|
+
|
|
622
|
+
| Argument | Description | Default |
|
|
623
|
+
|----------|-------------|---------|
|
|
624
|
+
| `[files]` | Specific files to review | Changed files |
|
|
625
|
+
| `--security` | Security-focused review | false |
|
|
626
|
+
| `--performance` | Performance-focused review | false |
|
|
627
|
+
| `--all` | Review all files (batched) | false |
|
|
628
|
+
| `--full-scan` | Force full codebase scan | false |
|
|
629
|
+
|
|
630
|
+
## Examples
|
|
631
|
+
|
|
632
|
+
```bash
|
|
633
|
+
# Review changed files + critical paths
|
|
634
|
+
/test-review
|
|
635
|
+
|
|
636
|
+
# Security audit only
|
|
637
|
+
/test-review --security
|
|
638
|
+
|
|
639
|
+
# Full codebase scan (batched)
|
|
640
|
+
/test-review --full-scan
|
|
641
|
+
|
|
642
|
+
# Review specific file
|
|
643
|
+
/test-review src/app/api/users/route.ts
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
## Autonomous Loop Completion (Ralph Wiggum Pattern)
|
|
647
|
+
|
|
648
|
+
When running in autonomous mode (`--auto` flag or `/ralph-loop`), this skill supports
|
|
649
|
+
self-terminating loops for iterative code review cycles.
|
|
650
|
+
|
|
651
|
+
### Promise Signal
|
|
652
|
+
|
|
653
|
+
After completing all passes and addressing all findings, output:
|
|
654
|
+
|
|
655
|
+
```
|
|
656
|
+
<promise>REVIEW_CLEAN</promise>
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
This signal is detected by the `completion-promise-detector.py` hook, which:
|
|
660
|
+
1. Records the promise in `.claude/completion-promises.json`
|
|
661
|
+
2. Allows graceful workflow termination
|
|
662
|
+
3. Prevents infinite review loops
|
|
663
|
+
|
|
664
|
+
### When to Output the Promise
|
|
665
|
+
|
|
666
|
+
Output `<promise>REVIEW_CLEAN</promise>` when:
|
|
667
|
+
- All 4 passes have been executed
|
|
668
|
+
- All critical issues have been fixed
|
|
669
|
+
- Re-review confirms no new issues
|
|
670
|
+
- The codebase is ready for merge
|
|
671
|
+
|
|
672
|
+
### Iterative Review Loop
|
|
673
|
+
|
|
674
|
+
```
|
|
675
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
676
|
+
│ REVIEW LOOP (Ralph Wiggum) │
|
|
677
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
678
|
+
│ │
|
|
679
|
+
│ 1. Run multi-pass review │
|
|
680
|
+
│ └─ Findings? → Fix issues │
|
|
681
|
+
│ │
|
|
682
|
+
│ 2. Re-run review on changed files │
|
|
683
|
+
│ └─ New findings? → Loop back to step 1 │
|
|
684
|
+
│ │
|
|
685
|
+
│ 3. All clean? │
|
|
686
|
+
│ └─ Output: <promise>REVIEW_CLEAN</promise> │
|
|
687
|
+
│ └─ Hook detects → Workflow terminates gracefully │
|
|
688
|
+
│ │
|
|
689
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
**Credit:** Ralph Wiggum pattern by [Geoffrey Huntley](https://ghuntley.com/ralph/)
|
|
693
|
+
|
|
694
|
+
## Integration
|
|
695
|
+
|
|
696
|
+
This skill is invoked during:
|
|
697
|
+
- Phase 11 (Code Review) of all workflows
|
|
698
|
+
- `/test-all` final step
|
|
699
|
+
- Weekly scheduled audits (CI/CD)
|
|
700
|
+
|
|
701
|
+
## See Also
|
|
702
|
+
|
|
703
|
+
- `/test-all` - Complete test suite
|
|
704
|
+
- `/test-debug` - Debug issues
|
|
705
|
+
- `/ralph-loop` - Autonomous loop execution
|
|
706
|
+
- [docs/AUTONOMOUS_LOOPS.md](../../docs/AUTONOMOUS_LOOPS.md) - Pattern documentation
|
|
707
|
+
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|