@nano-step/skill-manager 5.6.1 → 5.7.0
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/dist/utils.d.ts +1 -1
- package/dist/utils.js +1 -1
- package/package.json +1 -1
- package/private-catalog.json +7 -2
- package/skills/deep-design/SKILL.md +402 -0
- package/skills/deep-design/evals/evals.json +23 -0
- package/skills/deep-design/skill.json +7 -0
- package/skills/feature-analysis/SKILL.md +290 -0
- package/skills/feature-analysis/skill.json +15 -0
- package/skills/nano-brain/skill.json +7 -0
- package/skills/pr-code-reviewer/CHANGELOG.md +329 -0
- package/skills/pr-code-reviewer/RESEARCH.md +60 -0
- package/skills/pr-code-reviewer/SKILL.md +537 -0
- package/skills/pr-code-reviewer/assets/config.json +60 -0
- package/skills/pr-code-reviewer/checklists/backend-express.md +357 -0
- package/skills/pr-code-reviewer/checklists/ci-cd.md +428 -0
- package/skills/pr-code-reviewer/checklists/consumer-search-matrix.md +339 -0
- package/skills/pr-code-reviewer/checklists/database.md +382 -0
- package/skills/pr-code-reviewer/checklists/frontend-vue-nuxt.md +426 -0
- package/skills/pr-code-reviewer/checklists/review-checklist.md +149 -0
- package/skills/pr-code-reviewer/references/checkpoint-system.md +58 -0
- package/skills/pr-code-reviewer/references/confidence-scoring.md +98 -0
- package/skills/pr-code-reviewer/references/framework-rules/express.md +39 -0
- package/skills/pr-code-reviewer/references/framework-rules/nestjs.md +41 -0
- package/skills/pr-code-reviewer/references/framework-rules/nextjs.md +58 -0
- package/skills/pr-code-reviewer/references/framework-rules/prisma.md +54 -0
- package/skills/pr-code-reviewer/references/framework-rules/react.md +61 -0
- package/skills/pr-code-reviewer/references/framework-rules/typeorm.md +52 -0
- package/skills/pr-code-reviewer/references/framework-rules/typescript.md +50 -0
- package/skills/pr-code-reviewer/references/framework-rules/vue-nuxt.md +53 -0
- package/skills/pr-code-reviewer/references/nano-brain-integration.md +46 -0
- package/skills/pr-code-reviewer/references/performance-patterns.md +26 -0
- package/skills/pr-code-reviewer/references/quality-patterns.md +25 -0
- package/skills/pr-code-reviewer/references/report-template.md +172 -0
- package/skills/pr-code-reviewer/references/security-patterns.md +31 -0
- package/skills/pr-code-reviewer/references/setup-wizard.md +207 -0
- package/skills/pr-code-reviewer/references/subagent-prompts.md +344 -0
- package/skills/pr-code-reviewer/references/verification-protocol.md +56 -0
- package/skills/pr-code-reviewer/skill.json +15 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Confidence Scoring (Phase 4.6)
|
|
2
|
+
|
|
3
|
+
Re-review the final findings to score how confident we are in the review's **results** — are the findings correct and complete?
|
|
4
|
+
|
|
5
|
+
**Always run this phase**, even if no critical/warning findings remain. The confidence score reflects the entire review quality, not just individual findings.
|
|
6
|
+
|
|
7
|
+
## Per-Finding Confidence
|
|
8
|
+
|
|
9
|
+
For each surviving finding (post Phase 4.5), assign a confidence level:
|
|
10
|
+
|
|
11
|
+
| Level | Criteria |
|
|
12
|
+
|-------|----------|
|
|
13
|
+
| 🟢 High | Verified with concrete file:line evidence AND 2+ agents independently flagged it |
|
|
14
|
+
| 🟡 Medium | Verified but single agent, OR 2+ agents agreed but evidence is indirect |
|
|
15
|
+
| 🔴 Low | Unverifiable, pattern-based reasoning, no agent consensus |
|
|
16
|
+
|
|
17
|
+
## Overall Confidence Score (0–100)
|
|
18
|
+
|
|
19
|
+
Compute from three measurable rates:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
# Inputs (from Phase 4 + 4.5)
|
|
23
|
+
raw_findings = total findings from all 4 subagents (before dedup)
|
|
24
|
+
false_positives = findings dropped in Phase 4.5 as verified:false
|
|
25
|
+
verified = findings confirmed real in Phase 4.5 (verified:true)
|
|
26
|
+
unverifiable = findings marked unverifiable in Phase 4.5
|
|
27
|
+
final_findings = all findings in the final report (critical + warning + improvement + suggestion)
|
|
28
|
+
consensus_findings = final findings that were flagged by 2+ agents independently
|
|
29
|
+
evidence_findings = final findings that cite concrete file:line proof
|
|
30
|
+
|
|
31
|
+
# Rates
|
|
32
|
+
accuracy_rate = verified / max(verified + false_positives, 1) # How often we're right (0.0–1.0)
|
|
33
|
+
consensus_rate = consensus_findings / max(final_findings, 1) # Agreement level (0.0–1.0)
|
|
34
|
+
evidence_rate = evidence_findings / max(final_findings, 1) # Proof quality (0.0–1.0)
|
|
35
|
+
|
|
36
|
+
# Weighted score
|
|
37
|
+
overall = round((accuracy_rate * 40) + (consensus_rate * 30) + (evidence_rate * 30))
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Special Cases
|
|
41
|
+
|
|
42
|
+
- If Phase 4.5 was skipped (no critical/warning to verify): `accuracy_rate = 1.0` (no false positives possible)
|
|
43
|
+
- If `final_findings == 0` (clean review, no issues found): `overall = 100` (nothing to be wrong about)
|
|
44
|
+
- If all subagents returned empty findings: `overall = 100` with note "No issues found by any agent"
|
|
45
|
+
|
|
46
|
+
## Confidence Thresholds & Gate Behavior
|
|
47
|
+
|
|
48
|
+
| Score | Label | Gate Action |
|
|
49
|
+
|-------|-------|-------------|
|
|
50
|
+
| 80–100 | 🟢 High | Proceed normally — findings are reliable |
|
|
51
|
+
| 60–79 | 🟡 Medium | Add ⚠️ in report: "Some findings may be inaccurate — verify manually" |
|
|
52
|
+
| < 60 | 🔴 Low | Add 🔴 in report: "Low confidence review — significant uncertainty in findings. Manual review recommended." |
|
|
53
|
+
|
|
54
|
+
## Display Format (included in Phase 5 TL;DR)
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
📊 Result Confidence: 🟢 92/100
|
|
58
|
+
Accuracy: 85% (3 false positives caught and removed)
|
|
59
|
+
Consensus: 100% (all findings had 2+ agent agreement)
|
|
60
|
+
Evidence: 100% (all findings cite file:line proof)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
For low confidence:
|
|
64
|
+
```
|
|
65
|
+
📊 Result Confidence: 🔴 45/100
|
|
66
|
+
Accuracy: 50% (4 of 8 findings were false positives)
|
|
67
|
+
Consensus: 30% (most findings from single agent only)
|
|
68
|
+
Evidence: 60% (some findings lack concrete proof)
|
|
69
|
+
⚠️ Low confidence — manual review recommended for: [list specific uncertain findings]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Checkpoint Schema
|
|
73
|
+
|
|
74
|
+
Save results to `.checkpoints/phase-4.6-confidence.json`:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"raw_findings": 16,
|
|
79
|
+
"false_positives": 3,
|
|
80
|
+
"verified": 5,
|
|
81
|
+
"unverifiable": 0,
|
|
82
|
+
"final_findings": 6,
|
|
83
|
+
"consensus_findings": 4,
|
|
84
|
+
"evidence_findings": 6,
|
|
85
|
+
"accuracy_rate": 0.625,
|
|
86
|
+
"consensus_rate": 0.667,
|
|
87
|
+
"evidence_rate": 1.0,
|
|
88
|
+
"overall_score": 75,
|
|
89
|
+
"label": "medium",
|
|
90
|
+
"per_finding_confidence": [
|
|
91
|
+
{ "file": "src/service.js", "line": 42, "severity": "warning", "confidence": "high" },
|
|
92
|
+
{ "file": "src/utils.js", "line": 10, "severity": "improvement", "confidence": "medium" }
|
|
93
|
+
],
|
|
94
|
+
"gate_action": "Add warning to report"
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Update `manifest.json` (`completed_phase: 4.6`, `next_phase: 5`).
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Express Code Review Rules
|
|
2
|
+
|
|
3
|
+
## Critical Rules
|
|
4
|
+
- Unhandled async errors in route handlers → use express-async-handler or try-catch
|
|
5
|
+
- SQL injection in raw queries → use parameterized queries
|
|
6
|
+
- Missing authentication middleware on protected routes
|
|
7
|
+
- Exposing sensitive data in error responses
|
|
8
|
+
|
|
9
|
+
## Warning Rules
|
|
10
|
+
- Missing input validation → use express-validator or joi
|
|
11
|
+
- Exposing stack traces in production → check NODE_ENV
|
|
12
|
+
- Missing rate limiting on public endpoints
|
|
13
|
+
- No request body size limit → use express.json({ limit: '10kb' })
|
|
14
|
+
|
|
15
|
+
## Suggestions
|
|
16
|
+
- Use helmet for security headers
|
|
17
|
+
- Use compression middleware
|
|
18
|
+
- Centralize error handling middleware
|
|
19
|
+
- Use router.param() for parameter validation
|
|
20
|
+
|
|
21
|
+
## Detection Patterns
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
// CRITICAL: Unhandled async
|
|
25
|
+
app.get('/api', async (req, res) => {
|
|
26
|
+
const data = await fetchData() // if throws, crashes server
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
// SECURE: Wrapped async
|
|
30
|
+
app.get('/api', asyncHandler(async (req, res) => {
|
|
31
|
+
const data = await fetchData()
|
|
32
|
+
}))
|
|
33
|
+
|
|
34
|
+
// CRITICAL: SQL injection
|
|
35
|
+
db.query(`SELECT * FROM users WHERE id = ${req.params.id}`)
|
|
36
|
+
|
|
37
|
+
// SECURE: Parameterized
|
|
38
|
+
db.query('SELECT * FROM users WHERE id = ?', [req.params.id])
|
|
39
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# NestJS Code Review Rules
|
|
2
|
+
|
|
3
|
+
## Critical Rules
|
|
4
|
+
- Missing `@Injectable()` decorator on service class
|
|
5
|
+
- Circular dependency without `forwardRef()`
|
|
6
|
+
- Missing guards on sensitive endpoints → use `@UseGuards()`
|
|
7
|
+
- Raw SQL without parameterization in repositories
|
|
8
|
+
|
|
9
|
+
## Warning Rules
|
|
10
|
+
- Missing DTO validation → use `class-validator` decorators
|
|
11
|
+
- Missing `@ApiTags()` / `@ApiOperation()` for Swagger docs
|
|
12
|
+
- Injecting repository directly in controller → use service layer
|
|
13
|
+
- Missing `@Transactional()` on multi-step database operations
|
|
14
|
+
|
|
15
|
+
## Suggestions
|
|
16
|
+
- Use `ConfigService` instead of `process.env` directly
|
|
17
|
+
- Use custom exceptions extending `HttpException`
|
|
18
|
+
- Use interceptors for response transformation
|
|
19
|
+
- Use pipes for input transformation
|
|
20
|
+
|
|
21
|
+
## Detection Patterns
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// CRITICAL: Missing Injectable
|
|
25
|
+
class UserService { // should be @Injectable()
|
|
26
|
+
constructor(private repo: UserRepository) {}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// WARNING: Missing validation
|
|
30
|
+
@Post()
|
|
31
|
+
create(@Body() dto: CreateUserDto) {} // dto needs class-validator decorators
|
|
32
|
+
|
|
33
|
+
// CRITICAL: Circular dependency
|
|
34
|
+
@Injectable()
|
|
35
|
+
export class ServiceA {
|
|
36
|
+
constructor(private serviceB: ServiceB) {} // if B also injects A
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// SECURE: Forward ref
|
|
40
|
+
constructor(@Inject(forwardRef(() => ServiceB)) private serviceB: ServiceB) {}
|
|
41
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Next.js Code Review Rules
|
|
2
|
+
|
|
3
|
+
## Critical Rules
|
|
4
|
+
|
|
5
|
+
### Data Fetching
|
|
6
|
+
- `getServerSideProps` fetching data that doesn't change per-request → use `getStaticProps` + ISR
|
|
7
|
+
- Missing `revalidate` in `getStaticProps` for dynamic content → stale data
|
|
8
|
+
- Calling internal API routes from `getServerSideProps` → call the handler function directly
|
|
9
|
+
- `fetch` in Server Components without `{ cache: 'no-store' }` when fresh data required → unexpected caching
|
|
10
|
+
|
|
11
|
+
### Routing & Navigation
|
|
12
|
+
- `useRouter().push()` for external URLs → use `window.location.href`
|
|
13
|
+
- Missing `loading.tsx` for slow data fetches → no loading state shown
|
|
14
|
+
- Dynamic route params accessed before null check → crash on direct URL access
|
|
15
|
+
|
|
16
|
+
### App Router (Next.js 13+)
|
|
17
|
+
- `'use client'` on a component that has no client-side interactivity → unnecessary client bundle
|
|
18
|
+
- `useState` / `useEffect` in Server Component → runtime error
|
|
19
|
+
- Passing non-serializable props from Server → Client component → crash
|
|
20
|
+
|
|
21
|
+
### Server Actions
|
|
22
|
+
- No input validation in Server Actions → security hole
|
|
23
|
+
- Missing `revalidatePath` / `revalidateTag` after mutations → stale cache
|
|
24
|
+
|
|
25
|
+
## Warning Rules
|
|
26
|
+
|
|
27
|
+
### Performance
|
|
28
|
+
- Large `node_modules` imports in `'use client'` components → bundle bloat (use dynamic imports)
|
|
29
|
+
- Missing `next/image` for `<img>` tags → no lazy loading / optimization
|
|
30
|
+
- Missing `next/font` for Google Fonts → layout shift (CLS)
|
|
31
|
+
- `useEffect` for data fetching → waterfall; prefer Server Components
|
|
32
|
+
|
|
33
|
+
### Auth & Security
|
|
34
|
+
- Middleware not protecting `/api` routes that require auth
|
|
35
|
+
- `cookies()` / `headers()` in cached Server Components → dynamic rendering forced silently
|
|
36
|
+
- Sensitive env vars without `NEXT_PUBLIC_` prefix check — public prefix exposes to client
|
|
37
|
+
|
|
38
|
+
## Suggestions
|
|
39
|
+
- Use `next/dynamic` for heavy components with `ssr: false` when not needed server-side
|
|
40
|
+
- Use `unstable_cache` for expensive DB queries in Server Components
|
|
41
|
+
- Wrap `<Suspense>` around async Server Components for streaming
|
|
42
|
+
|
|
43
|
+
## Detection Patterns
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
// CRITICAL: useState in Server Component
|
|
47
|
+
// app/page.tsx (no 'use client')
|
|
48
|
+
const [count, setCount] = useState(0) // Error: hooks in Server Component
|
|
49
|
+
|
|
50
|
+
// CRITICAL: internal API fetch in getServerSideProps
|
|
51
|
+
export async function getServerSideProps() {
|
|
52
|
+
const res = await fetch('http://localhost:3000/api/data') // Wrong
|
|
53
|
+
// Should: import and call the handler directly
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// WARNING: img instead of next/image
|
|
57
|
+
<img src={user.avatar} /> // Use <Image> from 'next/image'
|
|
58
|
+
```
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Prisma Code Review Rules
|
|
2
|
+
|
|
3
|
+
## Critical Rules
|
|
4
|
+
|
|
5
|
+
### Data Safety
|
|
6
|
+
- `prisma.user.deleteMany({})` with empty where → deletes all rows
|
|
7
|
+
- Raw queries with string interpolation → SQL injection (`prisma.$queryRaw` must use tagged template literal `Prisma.sql`)
|
|
8
|
+
- Missing `select` / `omit` on queries that return sensitive fields (e.g., `password`, `token`) → data leak
|
|
9
|
+
- `prisma.$transaction` with non-atomic operations that should be atomic → partial write on failure
|
|
10
|
+
|
|
11
|
+
### Migrations
|
|
12
|
+
- Renaming a column by adding new + deleting old in one migration → data loss if deployed without backfill
|
|
13
|
+
- `@default(now())` added to existing non-nullable column → migration fails on non-empty table
|
|
14
|
+
- Missing `migrate deploy` step noted in release process for schema changes
|
|
15
|
+
|
|
16
|
+
## Warning Rules
|
|
17
|
+
|
|
18
|
+
### Performance
|
|
19
|
+
- `findMany` without `take` (limit) → unbounded query, potential OOM
|
|
20
|
+
- N+1: loop calling `findUnique` per item → use `findMany` with `in` filter or `include`
|
|
21
|
+
- Missing `index` on columns used in `where`, `orderBy`, or `join` → full table scan
|
|
22
|
+
- `include` nesting 3+ levels deep → over-fetching
|
|
23
|
+
|
|
24
|
+
### Patterns
|
|
25
|
+
- Using `upsert` when only create or only update is semantically correct → confusing intent
|
|
26
|
+
- `update` without checking record exists → silent no-op if not found (use `update` which throws, not `upsert`)
|
|
27
|
+
- Accessing `prisma` directly in route handlers → should go through a repository/service layer
|
|
28
|
+
|
|
29
|
+
## Suggestions
|
|
30
|
+
- Use `select` to fetch only needed columns (reduces payload size)
|
|
31
|
+
- Use `prisma.$transaction([...])` for related writes that must succeed together
|
|
32
|
+
- Add `@@index` directives for common query patterns in schema
|
|
33
|
+
|
|
34
|
+
## Detection Patterns
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
// CRITICAL: SQL injection via raw query
|
|
38
|
+
const user = await prisma.$queryRaw(`SELECT * FROM users WHERE id = ${userId}`)
|
|
39
|
+
// SAFE:
|
|
40
|
+
const user = await prisma.$queryRaw(Prisma.sql`SELECT * FROM users WHERE id = ${userId}`)
|
|
41
|
+
|
|
42
|
+
// CRITICAL: missing field exclusion
|
|
43
|
+
const user = await prisma.user.findUnique({ where: { id } })
|
|
44
|
+
// user.password is returned — should use select or omit
|
|
45
|
+
|
|
46
|
+
// WARNING: N+1
|
|
47
|
+
for (const order of orders) {
|
|
48
|
+
const user = await prisma.user.findUnique({ where: { id: order.userId } })
|
|
49
|
+
}
|
|
50
|
+
// FIX: findMany with where: { id: { in: orders.map(o => o.userId) } }
|
|
51
|
+
|
|
52
|
+
// WARNING: unbounded query
|
|
53
|
+
const all = await prisma.product.findMany() // missing take:
|
|
54
|
+
```
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# React Code Review Rules
|
|
2
|
+
|
|
3
|
+
## Critical Rules
|
|
4
|
+
|
|
5
|
+
### Hooks
|
|
6
|
+
- Hooks called conditionally → violates Rules of Hooks, runtime error
|
|
7
|
+
- `useEffect` with missing dependency → stale closure / infinite loop
|
|
8
|
+
- `useEffect` with object/array literal in deps → new reference every render, infinite loop
|
|
9
|
+
- Mutating state directly (`state.items.push(x)`) → no re-render triggered
|
|
10
|
+
|
|
11
|
+
### State & Props
|
|
12
|
+
- Derived state stored in `useState` when it can be computed inline → sync issues
|
|
13
|
+
- Prop drilling 3+ levels deep without context or state manager → maintenance burden (flag as warning)
|
|
14
|
+
- Reading stale ref value in async callback after unmount → memory leak / crash
|
|
15
|
+
|
|
16
|
+
### Event Handling
|
|
17
|
+
- Missing cleanup in `useEffect` (subscriptions, timers, event listeners) → memory leak
|
|
18
|
+
- `onClick` on non-interactive element without keyboard equivalent → accessibility gap
|
|
19
|
+
|
|
20
|
+
## Warning Rules
|
|
21
|
+
|
|
22
|
+
### Performance
|
|
23
|
+
- Anonymous functions / object literals as props to memoized components → memo is bypassed
|
|
24
|
+
- Missing `useCallback` on functions passed to child components with `React.memo`
|
|
25
|
+
- Large lists rendered without virtualization (`react-window` / `react-virtual`) → slow paint
|
|
26
|
+
- `useContext` on frequently-changing context → unnecessary re-renders
|
|
27
|
+
|
|
28
|
+
### Patterns
|
|
29
|
+
- `index` as `key` in lists that can reorder/filter → wrong element reconciled
|
|
30
|
+
- Multiple `useState` for related state → use `useReducer`
|
|
31
|
+
- `useEffect` for synchronizing with external system vs for side effects — distinguish them
|
|
32
|
+
|
|
33
|
+
## Suggestions
|
|
34
|
+
- Use `React.lazy` + `<Suspense>` for code-splitting heavy routes
|
|
35
|
+
- Consider `useMemo` for expensive calculations with stable inputs
|
|
36
|
+
- Use `<ErrorBoundary>` around async components
|
|
37
|
+
|
|
38
|
+
## Detection Patterns
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
// CRITICAL: conditional hook
|
|
42
|
+
if (user) {
|
|
43
|
+
const [name, setName] = useState(user.name) // Error: conditional hook
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// CRITICAL: missing cleanup
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
const sub = eventBus.subscribe(handler)
|
|
49
|
+
// Missing: return () => sub.unsubscribe()
|
|
50
|
+
}, [])
|
|
51
|
+
|
|
52
|
+
// CRITICAL: stale closure
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
setInterval(() => {
|
|
55
|
+
console.log(count) // stale if count not in deps
|
|
56
|
+
}, 1000)
|
|
57
|
+
}, []) // Missing: count in deps
|
|
58
|
+
|
|
59
|
+
// WARNING: object literal breaks memo
|
|
60
|
+
<MyMemo style={{ color: 'red' }} /> // new object every render
|
|
61
|
+
```
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# TypeORM Code Review Rules
|
|
2
|
+
|
|
3
|
+
## Critical Rules
|
|
4
|
+
- Raw SQL with string interpolation → SQL injection risk
|
|
5
|
+
- Missing `@Transaction()` on multi-entity operations
|
|
6
|
+
- Forgetting to `await` repository methods → silent failures
|
|
7
|
+
- Using `save()` in loops → N+1 writes, use `save([entities])`
|
|
8
|
+
|
|
9
|
+
## Warning Rules
|
|
10
|
+
- N+1 query pattern → use `relations` option or `leftJoinAndSelect`
|
|
11
|
+
- Missing indexes on frequently queried columns
|
|
12
|
+
- Using `find()` without `take` limit on large tables
|
|
13
|
+
- Eager loading too many relations → performance hit
|
|
14
|
+
|
|
15
|
+
## Suggestions
|
|
16
|
+
- Use QueryBuilder for complex queries
|
|
17
|
+
- Use `@Index()` decorator for query optimization
|
|
18
|
+
- Use `createQueryBuilder().insert()` for bulk inserts
|
|
19
|
+
- Consider `@DeleteDateColumn()` for soft deletes
|
|
20
|
+
|
|
21
|
+
## Detection Patterns
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// CRITICAL: SQL injection
|
|
25
|
+
repository.query(`SELECT * FROM users WHERE name = '${name}'`)
|
|
26
|
+
|
|
27
|
+
// SECURE: Parameterized
|
|
28
|
+
repository.query('SELECT * FROM users WHERE name = ?', [name])
|
|
29
|
+
|
|
30
|
+
// CRITICAL: N+1 in loop
|
|
31
|
+
for (const user of users) {
|
|
32
|
+
await userRepo.save(user) // N writes
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// SECURE: Batch save
|
|
36
|
+
await userRepo.save(users) // 1 write
|
|
37
|
+
|
|
38
|
+
// WARNING: N+1 query
|
|
39
|
+
const users = await userRepo.find()
|
|
40
|
+
for (const user of users) {
|
|
41
|
+
const posts = await postRepo.find({ where: { userId: user.id } })
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// SECURE: Eager load
|
|
45
|
+
const users = await userRepo.find({ relations: ['posts'] })
|
|
46
|
+
|
|
47
|
+
// WARNING: Missing limit
|
|
48
|
+
await userRepo.find({ where: { status: 'active' } }) // could return millions
|
|
49
|
+
|
|
50
|
+
// SECURE: With limit
|
|
51
|
+
await userRepo.find({ where: { status: 'active' }, take: 100 })
|
|
52
|
+
```
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# TypeScript Code Review Rules
|
|
2
|
+
|
|
3
|
+
## Critical Rules
|
|
4
|
+
- Using `any` type to bypass type checking
|
|
5
|
+
- Using `@ts-ignore` or `@ts-expect-error` without justification
|
|
6
|
+
- Type assertion (`as Type`) on untrusted external data
|
|
7
|
+
- Missing null checks before accessing optional properties
|
|
8
|
+
|
|
9
|
+
## Warning Rules
|
|
10
|
+
- Non-null assertion (`!`) without prior validation
|
|
11
|
+
- Using `as unknown as Type` double assertion
|
|
12
|
+
- Implicit `any` from missing return types
|
|
13
|
+
- Using `Object` or `{}` as type → too permissive
|
|
14
|
+
|
|
15
|
+
## Suggestions
|
|
16
|
+
- Use `unknown` instead of `any` for external data, then narrow
|
|
17
|
+
- Use discriminated unions for state machines
|
|
18
|
+
- Use `satisfies` operator for type checking without widening
|
|
19
|
+
- Use `readonly` for immutable data structures
|
|
20
|
+
|
|
21
|
+
## Detection Patterns
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// CRITICAL: any type
|
|
25
|
+
const data: any = await fetchData()
|
|
26
|
+
data.whatever.you.want // no type safety
|
|
27
|
+
|
|
28
|
+
// SECURE: unknown + narrowing
|
|
29
|
+
const data: unknown = await fetchData()
|
|
30
|
+
if (isUserData(data)) {
|
|
31
|
+
data.name // type-safe
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// CRITICAL: Unsafe assertion
|
|
35
|
+
const user = JSON.parse(input) as User // input could be anything
|
|
36
|
+
|
|
37
|
+
// SECURE: Runtime validation
|
|
38
|
+
const user = userSchema.parse(JSON.parse(input)) // zod/yup validation
|
|
39
|
+
|
|
40
|
+
// WARNING: Non-null assertion without check
|
|
41
|
+
function process(user?: User) {
|
|
42
|
+
return user!.name // crashes if undefined
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// SECURE: With guard
|
|
46
|
+
function process(user?: User) {
|
|
47
|
+
if (!user) throw new Error('User required')
|
|
48
|
+
return user.name
|
|
49
|
+
}
|
|
50
|
+
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Vue 3 / Nuxt 3 Code Review Rules
|
|
2
|
+
|
|
3
|
+
## Critical Rules
|
|
4
|
+
|
|
5
|
+
### State Management (Vuex ↔ Pinia)
|
|
6
|
+
- `rootState.{module}` where module is Pinia store → Vuex cannot access Pinia state
|
|
7
|
+
- `useStore()` in Pinia-only context → wrong store type
|
|
8
|
+
- Store module exists but not registered in `store/index.js`
|
|
9
|
+
- Pinia store file missing `export` or `defineStore`
|
|
10
|
+
|
|
11
|
+
### Auto-Import Gotchas (Nuxt)
|
|
12
|
+
- Using function from `utils/` without import → only `composables/` auto-imported
|
|
13
|
+
- Using `defineStore` without import when `@pinia/nuxt` not in modules
|
|
14
|
+
|
|
15
|
+
### Component Issues
|
|
16
|
+
- Mutating props directly
|
|
17
|
+
- `v-if` and `v-for` on same element
|
|
18
|
+
|
|
19
|
+
## Warning Rules
|
|
20
|
+
|
|
21
|
+
### State Management
|
|
22
|
+
- Mixed `useStore()` and `use*Store()` in same composable
|
|
23
|
+
- Vuex action accessing Pinia store via workaround
|
|
24
|
+
- `rootState.{x}` or `rootGetters['{x}/...']` → verify module exists
|
|
25
|
+
|
|
26
|
+
### Reactivity
|
|
27
|
+
- Using `reactive()` for primitives → use `ref()`
|
|
28
|
+
- Destructuring reactive object without `toRefs()` or `storeToRefs()`
|
|
29
|
+
- Missing `.value` on ref in script (not template)
|
|
30
|
+
|
|
31
|
+
### Composables
|
|
32
|
+
- Composable not returning reactive refs
|
|
33
|
+
- Using `this` in composable (not available in setup)
|
|
34
|
+
|
|
35
|
+
## Suggestions
|
|
36
|
+
- Use `storeToRefs()` when destructuring Pinia store
|
|
37
|
+
- Use `computed` for derived state
|
|
38
|
+
- Prefer Pinia for new stores (migration in progress)
|
|
39
|
+
- Use `<script setup>` syntax for components
|
|
40
|
+
|
|
41
|
+
## Detection Patterns
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
// CRITICAL: Vuex accessing Pinia (will be undefined)
|
|
45
|
+
rootState.currency.selectedRate // if currency is Pinia store
|
|
46
|
+
|
|
47
|
+
// WARNING: Check if module exists
|
|
48
|
+
rootState.{moduleName} // verify in store/index.js modules: { {moduleName} }
|
|
49
|
+
|
|
50
|
+
// CRITICAL: Missing import in utils (not auto-imported)
|
|
51
|
+
// In component using function from utils/helpers.js without import
|
|
52
|
+
stripImageSizeFromUrl(url) // will be undefined if not imported
|
|
53
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# nano-brain Integration
|
|
2
|
+
|
|
3
|
+
nano-brain provides persistent memory across sessions. The reviewer uses it for historical context about changed files:
|
|
4
|
+
- Past review findings and architectural decisions
|
|
5
|
+
- Known issues and tech debt in affected modules
|
|
6
|
+
- Prior discussions about the same code areas
|
|
7
|
+
|
|
8
|
+
## Access Method: HTTP API
|
|
9
|
+
|
|
10
|
+
All nano-brain operations use HTTP API (nano-brain runs as Docker service on port 3100):
|
|
11
|
+
|
|
12
|
+
| Need | Command |
|
|
13
|
+
|------|---------|
|
|
14
|
+
| Hybrid search (best quality) | `curl -s localhost:3100/api/query -d '{"query":"search terms"}'` |
|
|
15
|
+
| Keyword search (function name, error) | `curl -s localhost:3100/api/search -d '{"query":"exact term"}'` |
|
|
16
|
+
| Save review findings | `curl -s localhost:3100/api/write -d '{"content":"...","tags":"review"}'` |
|
|
17
|
+
|
|
18
|
+
## Phase 1 Memory Queries
|
|
19
|
+
|
|
20
|
+
For each significantly changed file/module:
|
|
21
|
+
- **Hybrid search**: `curl -s localhost:3100/api/query -d '{"query":"<module-name>"}'` (best quality, combines BM25 + vector + reranking)
|
|
22
|
+
- **Scoped search**: `curl -s localhost:3100/api/query -d '{"query":"<function-name>","collection":"codebase"}'` for code-specific results
|
|
23
|
+
|
|
24
|
+
Specific queries:
|
|
25
|
+
- Past review findings: `curl -s localhost:3100/api/query -d '{"query":"review <module-name>"}'`
|
|
26
|
+
- Architectural decisions: `curl -s localhost:3100/api/query -d '{"query":"<module-name> architecture design decision"}'`
|
|
27
|
+
- Known issues: `curl -s localhost:3100/api/query -d '{"query":"<function-name> bug issue regression"}'`
|
|
28
|
+
|
|
29
|
+
Collect relevant memory hits as `projectMemory` context for subagents.
|
|
30
|
+
|
|
31
|
+
## Phase 2 Memory Queries (LOGIC changes)
|
|
32
|
+
|
|
33
|
+
Query nano-brain for known issues:
|
|
34
|
+
```bash
|
|
35
|
+
curl -s localhost:3100/api/query -d '{"query":"<function-name> bug issue edge case regression"}'
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Phase 5.5: Save Review to nano-brain
|
|
39
|
+
|
|
40
|
+
After generating the report, save key findings for future sessions:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
curl -s localhost:3100/api/write -d '{"content":"## Code Review: PR #<number> - <title>\nDate: <date>\nFiles: <changed_files>\n\n### Key Findings\n<critical_issues_summary>\n<warnings_summary>\n\n### Decisions\n<architectural_decisions_noted>\n\n### Recommendation: <APPROVE|REQUEST_CHANGES|COMMENT>","tags":"review,pr-<number>"}'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This ensures future reviews can reference past findings on the same codebase areas.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Performance Patterns
|
|
2
|
+
|
|
3
|
+
## N+1 Queries
|
|
4
|
+
```javascript
|
|
5
|
+
// CRITICAL: N+1 pattern
|
|
6
|
+
const users = await db.query('SELECT * FROM users');
|
|
7
|
+
for (const user of users) {
|
|
8
|
+
const posts = await db.query('SELECT * FROM posts WHERE user_id = ?', [user.id]);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// SECURE: Eager loading
|
|
12
|
+
const users = await db.query(`
|
|
13
|
+
SELECT u.*, p.* FROM users u
|
|
14
|
+
LEFT JOIN posts p ON u.id = p.user_id
|
|
15
|
+
`);
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## React Re-renders
|
|
19
|
+
```jsx
|
|
20
|
+
// WARNING: Inline function
|
|
21
|
+
<button onClick={() => handleClick(id)}>
|
|
22
|
+
|
|
23
|
+
// BETTER: useCallback
|
|
24
|
+
const handleClick = useCallback(() => { ... }, [id]);
|
|
25
|
+
<button onClick={handleClick}>
|
|
26
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Quality Patterns
|
|
2
|
+
|
|
3
|
+
## Type Safety
|
|
4
|
+
```typescript
|
|
5
|
+
// WARNING: any type
|
|
6
|
+
const data: any = getData();
|
|
7
|
+
|
|
8
|
+
// BETTER: Proper typing
|
|
9
|
+
interface UserData { id: string; name: string; }
|
|
10
|
+
const data: UserData = getData();
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Error Handling
|
|
14
|
+
```javascript
|
|
15
|
+
// CRITICAL: Silent catch
|
|
16
|
+
try { await doSomething(); } catch (e) { }
|
|
17
|
+
|
|
18
|
+
// BETTER: Proper handling
|
|
19
|
+
try {
|
|
20
|
+
await doSomething();
|
|
21
|
+
} catch (error) {
|
|
22
|
+
logger.error('Operation failed', { error });
|
|
23
|
+
throw new CustomError('Operation failed', error);
|
|
24
|
+
}
|
|
25
|
+
```
|