@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,426 @@
|
|
|
1
|
+
# Frontend Vue/Nuxt Checklist
|
|
2
|
+
|
|
3
|
+
Comprehensive review checklist for Vue 3/Nuxt 3 frontend PRs (tradeit, tradeit-admin, audit-dashboard-frontend, etc.)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. State Management
|
|
8
|
+
|
|
9
|
+
### CRITICAL - Must Check
|
|
10
|
+
|
|
11
|
+
| Check | Pattern | Why |
|
|
12
|
+
|-------|---------|-----|
|
|
13
|
+
| Vuex vs Pinia correct | `rootState.x` vs `useXStore()` | Vuex can't access Pinia |
|
|
14
|
+
| Store registered | Module in `store/index.js` | Undefined state |
|
|
15
|
+
| Computed get/set pattern | `computed({ get, set })` | Two-way binding |
|
|
16
|
+
| storeToRefs for destructuring | `storeToRefs(store)` | Maintains reactivity |
|
|
17
|
+
|
|
18
|
+
### Detection Patterns
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
// CRITICAL: Vuex accessing Pinia store (will be undefined)
|
|
22
|
+
// In Vuex action:
|
|
23
|
+
const rate = rootState.currency.selectedRate // currency is Pinia!
|
|
24
|
+
|
|
25
|
+
// SECURE: Use Pinia directly
|
|
26
|
+
import { useCurrencyStore } from '~/store/useCurrencyStore'
|
|
27
|
+
const currencyStore = useCurrencyStore()
|
|
28
|
+
const rate = currencyStore.selectedRate
|
|
29
|
+
|
|
30
|
+
// CRITICAL: Store not registered
|
|
31
|
+
// store/index.js missing:
|
|
32
|
+
modules: {
|
|
33
|
+
// currency: currencyModule // MISSING!
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// WARNING: Destructuring loses reactivity
|
|
37
|
+
const { items, loading } = useInventoryStore() // Not reactive!
|
|
38
|
+
|
|
39
|
+
// SECURE: Use storeToRefs
|
|
40
|
+
const store = useInventoryStore()
|
|
41
|
+
const { items, loading } = storeToRefs(store)
|
|
42
|
+
|
|
43
|
+
// CRITICAL: Direct mutation (Vuex)
|
|
44
|
+
state.items.push(newItem) // Mutation outside mutation handler!
|
|
45
|
+
|
|
46
|
+
// SECURE: Use mutation
|
|
47
|
+
commit('ADD_ITEM', newItem)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 2. Reactivity
|
|
53
|
+
|
|
54
|
+
### CRITICAL - Must Check
|
|
55
|
+
|
|
56
|
+
| Check | Pattern | Why |
|
|
57
|
+
|-------|---------|-----|
|
|
58
|
+
| ref() for primitives | `ref(0)` not `reactive(0)` | reactive() doesn't work on primitives |
|
|
59
|
+
| .value in script | `count.value++` | Required for refs in script |
|
|
60
|
+
| toRefs for destructuring | `toRefs(props)` | Maintains reactivity |
|
|
61
|
+
| No direct prop mutation | `emit('update:x', newVal)` | One-way data flow |
|
|
62
|
+
|
|
63
|
+
### Detection Patterns
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
// WARNING: reactive() on primitive
|
|
67
|
+
const count = reactive(0) // Won't work!
|
|
68
|
+
|
|
69
|
+
// SECURE: ref() for primitives
|
|
70
|
+
const count = ref(0)
|
|
71
|
+
|
|
72
|
+
// CRITICAL: Missing .value in script
|
|
73
|
+
const count = ref(0)
|
|
74
|
+
count++ // Wrong! count is a ref object
|
|
75
|
+
|
|
76
|
+
// SECURE: Use .value
|
|
77
|
+
count.value++
|
|
78
|
+
|
|
79
|
+
// CRITICAL: Mutating prop directly
|
|
80
|
+
props.items.push(newItem) // Mutating parent state!
|
|
81
|
+
|
|
82
|
+
// SECURE: Emit event
|
|
83
|
+
emit('add-item', newItem)
|
|
84
|
+
|
|
85
|
+
// WARNING: Destructuring props loses reactivity
|
|
86
|
+
const { modelValue } = defineProps(['modelValue'])
|
|
87
|
+
watch(modelValue, ...) // Won't trigger!
|
|
88
|
+
|
|
89
|
+
// SECURE: Use toRefs or computed
|
|
90
|
+
const props = defineProps(['modelValue'])
|
|
91
|
+
watch(() => props.modelValue, ...)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 3. Network Calls
|
|
97
|
+
|
|
98
|
+
### CRITICAL - Must Check
|
|
99
|
+
|
|
100
|
+
| Check | Pattern | Why |
|
|
101
|
+
|-------|---------|-----|
|
|
102
|
+
| Use getAxiosInstance() | Not raw axios | Includes auth, base URL |
|
|
103
|
+
| Error handling | try/catch or .catch() | User feedback |
|
|
104
|
+
| Loading state managed | `loading.value = true/false` | UX |
|
|
105
|
+
| Response fields validated | Check before access | Defensive coding |
|
|
106
|
+
|
|
107
|
+
### Detection Patterns
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
// WARNING: Raw axios
|
|
111
|
+
import axios from 'axios'
|
|
112
|
+
const { data } = await axios.get('/api/user')
|
|
113
|
+
|
|
114
|
+
// SECURE: Use instance
|
|
115
|
+
import { getAxiosInstance } from '~/network/axiosInstance'
|
|
116
|
+
const axios = getAxiosInstance()
|
|
117
|
+
const { data } = await axios.get('/api/user')
|
|
118
|
+
|
|
119
|
+
// CRITICAL: No error handling
|
|
120
|
+
const fetchData = async () => {
|
|
121
|
+
const { data } = await axios.get('/api/items')
|
|
122
|
+
items.value = data.items
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// SECURE: With error handling
|
|
126
|
+
const fetchData = async () => {
|
|
127
|
+
try {
|
|
128
|
+
loading.value = true
|
|
129
|
+
const { data } = await axios.get('/api/items')
|
|
130
|
+
items.value = data.items
|
|
131
|
+
} catch (e) {
|
|
132
|
+
error.value = e.message
|
|
133
|
+
} finally {
|
|
134
|
+
loading.value = false
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// CRITICAL: Assuming response field exists (PR #1101 issue!)
|
|
139
|
+
const imgUrl = item.imgURL // undefined if backend changed!
|
|
140
|
+
|
|
141
|
+
// SECURE: Defensive access
|
|
142
|
+
const imgUrl = item.imgURL ?? getFallbackImage(item.groupId)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 4. Component Patterns
|
|
148
|
+
|
|
149
|
+
### CRITICAL - Must Check
|
|
150
|
+
|
|
151
|
+
| Check | Pattern | Why |
|
|
152
|
+
|-------|---------|-----|
|
|
153
|
+
| Props typed | `defineProps<{ x: string }>()` | Type safety |
|
|
154
|
+
| Emits declared | `defineEmits(['update:x'])` | Documentation |
|
|
155
|
+
| v-if/v-for not on same element | Use template wrapper | Vue limitation |
|
|
156
|
+
| Key on v-for | `:key="item.id"` | Efficient updates |
|
|
157
|
+
|
|
158
|
+
### Detection Patterns
|
|
159
|
+
|
|
160
|
+
```vue
|
|
161
|
+
<!-- CRITICAL: v-if and v-for on same element -->
|
|
162
|
+
<div v-for="item in items" v-if="item.active"> <!-- Wrong! -->
|
|
163
|
+
|
|
164
|
+
<!-- SECURE: Use template -->
|
|
165
|
+
<template v-for="item in items" :key="item.id">
|
|
166
|
+
<div v-if="item.active">...</div>
|
|
167
|
+
</template>
|
|
168
|
+
|
|
169
|
+
<!-- WARNING: Missing key -->
|
|
170
|
+
<div v-for="item in items"> <!-- No key! -->
|
|
171
|
+
|
|
172
|
+
<!-- SECURE: With key -->
|
|
173
|
+
<div v-for="item in items" :key="item.id">
|
|
174
|
+
|
|
175
|
+
<!-- WARNING: Untyped props -->
|
|
176
|
+
const props = defineProps(['modelValue', 'items'])
|
|
177
|
+
|
|
178
|
+
<!-- SECURE: Typed props -->
|
|
179
|
+
interface Props {
|
|
180
|
+
modelValue: string
|
|
181
|
+
items: Item[]
|
|
182
|
+
}
|
|
183
|
+
const props = defineProps<Props>()
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## 5. Composables
|
|
189
|
+
|
|
190
|
+
### CRITICAL - Must Check
|
|
191
|
+
|
|
192
|
+
| Check | Pattern | Why |
|
|
193
|
+
|-------|---------|-----|
|
|
194
|
+
| Returns reactive refs | `return { items, loading }` | Reactivity preserved |
|
|
195
|
+
| No `this` usage | Composables don't have `this` | Runtime error |
|
|
196
|
+
| Cleanup on unmount | `onUnmounted(() => ...)` | Memory leaks |
|
|
197
|
+
| Named exports | `export function useX()` | Tree shaking |
|
|
198
|
+
|
|
199
|
+
### Detection Patterns
|
|
200
|
+
|
|
201
|
+
```javascript
|
|
202
|
+
// CRITICAL: Using this in composable
|
|
203
|
+
export function useInventory() {
|
|
204
|
+
this.items = [] // TypeError! No 'this' in composables
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// SECURE: Use refs
|
|
208
|
+
export function useInventory() {
|
|
209
|
+
const items = ref([])
|
|
210
|
+
return { items }
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// WARNING: Not returning reactive
|
|
214
|
+
export function useCounter() {
|
|
215
|
+
let count = 0 // Not reactive!
|
|
216
|
+
return { count }
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// SECURE: Return refs
|
|
220
|
+
export function useCounter() {
|
|
221
|
+
const count = ref(0)
|
|
222
|
+
return { count }
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// WARNING: No cleanup
|
|
226
|
+
export function useWebSocket() {
|
|
227
|
+
const ws = new WebSocket(url)
|
|
228
|
+
// Never closed!
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// SECURE: Cleanup on unmount
|
|
232
|
+
export function useWebSocket() {
|
|
233
|
+
const ws = new WebSocket(url)
|
|
234
|
+
onUnmounted(() => ws.close())
|
|
235
|
+
return { ws }
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## 6. Nuxt-Specific
|
|
242
|
+
|
|
243
|
+
### CRITICAL - Must Check
|
|
244
|
+
|
|
245
|
+
| Check | Pattern | Why |
|
|
246
|
+
|-------|---------|-----|
|
|
247
|
+
| Client-only code guarded | `import.meta.client` | SSR errors |
|
|
248
|
+
| Auto-imports from composables/ | Not utils/ | Only composables auto-imported |
|
|
249
|
+
| useFetch for SSR data | Not axios in setup | SSR hydration |
|
|
250
|
+
| definePageMeta for layouts | `definePageMeta({ layout: 'x' })` | Nuxt convention |
|
|
251
|
+
|
|
252
|
+
### Detection Patterns
|
|
253
|
+
|
|
254
|
+
```javascript
|
|
255
|
+
// CRITICAL: Browser API in SSR
|
|
256
|
+
const width = window.innerWidth // ReferenceError on server!
|
|
257
|
+
|
|
258
|
+
// SECURE: Guard with import.meta.client
|
|
259
|
+
const width = import.meta.client ? window.innerWidth : 0
|
|
260
|
+
|
|
261
|
+
// Or use onMounted
|
|
262
|
+
onMounted(() => {
|
|
263
|
+
width.value = window.innerWidth
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
// CRITICAL: Using function from utils/ without import
|
|
267
|
+
// In component:
|
|
268
|
+
stripImageSizeFromUrl(url) // undefined! utils/ not auto-imported
|
|
269
|
+
|
|
270
|
+
// SECURE: Import explicitly
|
|
271
|
+
import { stripImageSizeFromUrl } from '~/utils/helpers'
|
|
272
|
+
|
|
273
|
+
// WARNING: axios in setup (SSR issues)
|
|
274
|
+
const { data } = await axios.get('/api/items')
|
|
275
|
+
|
|
276
|
+
// SECURE: useFetch for SSR
|
|
277
|
+
const { data } = await useFetch('/api/items')
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## 7. i18n / Localization
|
|
283
|
+
|
|
284
|
+
### WARNING - Should Check
|
|
285
|
+
|
|
286
|
+
| Check | Pattern | Why |
|
|
287
|
+
|-------|---------|-----|
|
|
288
|
+
| No hardcoded strings | Use `$t('key')` | Localization |
|
|
289
|
+
| Keys exist in locale files | Check en.js | Runtime errors |
|
|
290
|
+
| Interpolation correct | `$t('key', { name })` | Dynamic content |
|
|
291
|
+
|
|
292
|
+
### Detection Patterns
|
|
293
|
+
|
|
294
|
+
```vue
|
|
295
|
+
<!-- WARNING: Hardcoded string -->
|
|
296
|
+
<button>Submit</button>
|
|
297
|
+
|
|
298
|
+
<!-- SECURE: Use i18n -->
|
|
299
|
+
<button>{{ $t('common.submit') }}</button>
|
|
300
|
+
|
|
301
|
+
<!-- WARNING: Missing interpolation -->
|
|
302
|
+
<p>{{ $t('welcome') }}</p> <!-- "Welcome, {name}" shows literally -->
|
|
303
|
+
|
|
304
|
+
<!-- SECURE: With interpolation -->
|
|
305
|
+
<p>{{ $t('welcome', { name: user.name }) }}</p>
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## 8. Images & CDN
|
|
311
|
+
|
|
312
|
+
### CRITICAL - Must Check
|
|
313
|
+
|
|
314
|
+
| Check | Pattern | Why |
|
|
315
|
+
|-------|---------|-----|
|
|
316
|
+
| Use useCDNImage() | Not raw URLs | CDN optimization |
|
|
317
|
+
| ImageWithFallback component | For item images | Handles missing images |
|
|
318
|
+
| Lazy loading | `loading="lazy"` | Performance |
|
|
319
|
+
|
|
320
|
+
### Detection Patterns
|
|
321
|
+
|
|
322
|
+
```vue
|
|
323
|
+
<!-- WARNING: Raw image URL -->
|
|
324
|
+
<img :src="item.imgURL"> <!-- No fallback if undefined! -->
|
|
325
|
+
|
|
326
|
+
<!-- SECURE: Use ImageWithFallback -->
|
|
327
|
+
<ImageWithFallback :src="item.imgURL" :fallback="getFallback(item)" />
|
|
328
|
+
|
|
329
|
+
<!-- WARNING: No lazy loading -->
|
|
330
|
+
<img :src="url">
|
|
331
|
+
|
|
332
|
+
<!-- SECURE: Lazy load -->
|
|
333
|
+
<img :src="url" loading="lazy">
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## 9. Breaking Change Detection
|
|
339
|
+
|
|
340
|
+
### Auto-Flag These Changes
|
|
341
|
+
|
|
342
|
+
| Signal | Severity | Action |
|
|
343
|
+
|--------|----------|--------|
|
|
344
|
+
| Store module removed | CRITICAL | Search all consumers |
|
|
345
|
+
| Composable return value changed | CRITICAL | Search all usages |
|
|
346
|
+
| Network function signature changed | CRITICAL | Search all callers |
|
|
347
|
+
| Component prop removed | WARNING | Search all usages |
|
|
348
|
+
| Emit event renamed | WARNING | Search parent listeners |
|
|
349
|
+
|
|
350
|
+
### Consumer Search Required
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
# For store changes
|
|
354
|
+
grep -rn "useXStore" ./
|
|
355
|
+
grep -rn "rootState.x" ./
|
|
356
|
+
|
|
357
|
+
# For composable changes
|
|
358
|
+
grep -rn "useComposable" ./
|
|
359
|
+
|
|
360
|
+
# For component changes
|
|
361
|
+
grep -rn "<ComponentName" ./
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## 10. Performance Checks
|
|
367
|
+
|
|
368
|
+
### WARNING - Should Check
|
|
369
|
+
|
|
370
|
+
| Check | Pattern | Why |
|
|
371
|
+
|-------|---------|-----|
|
|
372
|
+
| Large lists virtualized | `vue-virtual-scroller` | Memory |
|
|
373
|
+
| Computed for derived state | Not methods | Caching |
|
|
374
|
+
| v-once for static content | `<div v-once>` | Skip re-renders |
|
|
375
|
+
| Async components for heavy | `defineAsyncComponent` | Code splitting |
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## Quick Checklist
|
|
380
|
+
|
|
381
|
+
Copy this for PR reviews:
|
|
382
|
+
|
|
383
|
+
```markdown
|
|
384
|
+
## Vue/Nuxt Frontend Review
|
|
385
|
+
|
|
386
|
+
### State Management
|
|
387
|
+
- [ ] Vuex/Pinia used correctly (not mixed)
|
|
388
|
+
- [ ] Store modules registered
|
|
389
|
+
- [ ] storeToRefs used for destructuring
|
|
390
|
+
- [ ] No direct state mutation
|
|
391
|
+
|
|
392
|
+
### Reactivity
|
|
393
|
+
- [ ] ref() for primitives, reactive() for objects
|
|
394
|
+
- [ ] .value used in script
|
|
395
|
+
- [ ] Props not mutated directly
|
|
396
|
+
|
|
397
|
+
### Network
|
|
398
|
+
- [ ] getAxiosInstance() used (not raw axios)
|
|
399
|
+
- [ ] Error handling present
|
|
400
|
+
- [ ] Loading states managed
|
|
401
|
+
- [ ] Response fields validated (defensive)
|
|
402
|
+
|
|
403
|
+
### Components
|
|
404
|
+
- [ ] Props typed with TypeScript
|
|
405
|
+
- [ ] Emits declared
|
|
406
|
+
- [ ] v-if/v-for not on same element
|
|
407
|
+
- [ ] Keys on v-for
|
|
408
|
+
|
|
409
|
+
### Nuxt-Specific
|
|
410
|
+
- [ ] Client-only code guarded (import.meta.client)
|
|
411
|
+
- [ ] Auto-imports only from composables/
|
|
412
|
+
- [ ] useFetch for SSR data
|
|
413
|
+
|
|
414
|
+
### i18n
|
|
415
|
+
- [ ] No hardcoded user-facing strings
|
|
416
|
+
- [ ] $t() keys exist in locale files
|
|
417
|
+
|
|
418
|
+
### Images
|
|
419
|
+
- [ ] useCDNImage() or ImageWithFallback used
|
|
420
|
+
- [ ] Fallbacks for missing images
|
|
421
|
+
|
|
422
|
+
### Breaking Changes
|
|
423
|
+
- [ ] No store modules removed without consumer check
|
|
424
|
+
- [ ] No composable signatures changed without search
|
|
425
|
+
- [ ] No component props removed without search
|
|
426
|
+
```
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# PR Review Checklist
|
|
2
|
+
|
|
3
|
+
Use this checklist for every PR review. Check off each item as you complete it.
|
|
4
|
+
|
|
5
|
+
## Setup Check (Phase -2)
|
|
6
|
+
|
|
7
|
+
- [ ] Check if `.opencode/code-reviewer.json` exists
|
|
8
|
+
- [ ] If exists: read `stack` field → resolve framework rule files → store as `$FRAMEWORK_RULES`
|
|
9
|
+
- [ ] If exists: read `agents` field → validate workspace_root, AGENTS.md, .agents/ dirs exist
|
|
10
|
+
- [ ] If missing (or `/review --setup`): read `references/setup-wizard.md`, run wizard, write config
|
|
11
|
+
- [ ] Confirm which framework rule files will be loaded (only stack-matching files)
|
|
12
|
+
- [ ] Confirm agents knowledge base paths (workspace_root + which dirs found)
|
|
13
|
+
|
|
14
|
+
## Resume Detection (Phase -1)
|
|
15
|
+
|
|
16
|
+
- [ ] Look for existing checkpoint: `find /tmp -maxdepth 1 -type d -name "pr-review-${repo}-${pr_number}-*"`
|
|
17
|
+
- [ ] If found: read `manifest.json` from `.checkpoints/`
|
|
18
|
+
- [ ] Validate checkpoint: check PR number and head SHA match
|
|
19
|
+
- [ ] Ask user: "Resume from phase {next_phase}? (y/n)"
|
|
20
|
+
- [ ] If yes: load manifest + phase files, jump to `next_phase`
|
|
21
|
+
- [ ] If no or invalid: delete old directory, start fresh from Phase 0
|
|
22
|
+
|
|
23
|
+
## Pre-Review (Phase 0)
|
|
24
|
+
|
|
25
|
+
- [ ] Extract repo info: `owner/repo`, `pr_number`, `head_branch`
|
|
26
|
+
- [ ] Create unique temp dir: `/tmp/pr-review-{repo}-{pr}-{timestamp}`
|
|
27
|
+
- [ ] Clone repo to temp dir (shallow clone with `--depth=1`)
|
|
28
|
+
- [ ] Verify correct branch is checked out (`git log --oneline -1`)
|
|
29
|
+
- [ ] Record `$REVIEW_DIR` path for all subsequent phases
|
|
30
|
+
- [ ] Print confirmation with path and branch name
|
|
31
|
+
- [ ] Save checkpoint: `.checkpoints/phase-0-clone.json`
|
|
32
|
+
- [ ] Update manifest: `completed_phase: 0`, `next_phase: 1`
|
|
33
|
+
|
|
34
|
+
## Context Gathering (Phase 1)
|
|
35
|
+
|
|
36
|
+
- [ ] Read `{workspace_root}/AGENTS.md` → identify PR repo's domain
|
|
37
|
+
- [ ] Read `.agents/_repos/{repo-name}.md` → repo-specific context
|
|
38
|
+
- [ ] Read `.agents/_domains/{domain}.md` → domain context
|
|
39
|
+
- [ ] Store combined as `$AGENTS_CONTEXT`
|
|
40
|
+
- [ ] Get PR metadata: title, description, author, base branch
|
|
41
|
+
- [ ] Get changed files with diff
|
|
42
|
+
- [ ] Read full file context from `$REVIEW_DIR` (not workspace repo)
|
|
43
|
+
- [ ] Classify each file: LOGIC / DELETION / STYLE / REFACTOR / NEW
|
|
44
|
+
- [ ] Query nano-brain for past context on changed modules
|
|
45
|
+
- [ ] Save checkpoint: `.checkpoints/phase-1-context.json`
|
|
46
|
+
- [ ] Update manifest: `completed_phase: 1`, `next_phase: 1.5`
|
|
47
|
+
|
|
48
|
+
## Linear Ticket Context (Phase 1.5)
|
|
49
|
+
|
|
50
|
+
- [ ] Extract ticket ID from branch name, PR description, or PR title
|
|
51
|
+
- [ ] If found: `linear_get_issue(id)` → fetch ticket details
|
|
52
|
+
- [ ] If found: `linear_list_comments(issueId)` → fetch discussion
|
|
53
|
+
- [ ] Extract acceptance criteria from ticket description
|
|
54
|
+
- [ ] If images in description: `linear_extract_images(description)`
|
|
55
|
+
- [ ] If not found: skip silently, continue without ticket context
|
|
56
|
+
- [ ] Save checkpoint: `.checkpoints/phase-1.5-linear.json`
|
|
57
|
+
- [ ] Update manifest: `completed_phase: 1.5`, `next_phase: 2`
|
|
58
|
+
|
|
59
|
+
## Smart Tracing (Phase 2)
|
|
60
|
+
|
|
61
|
+
- [ ] LOGIC changes: trace callers, callees, tests, types, data flow
|
|
62
|
+
- [ ] STYLE changes: verify no hidden logic changes
|
|
63
|
+
- [ ] REFACTOR changes: verify behavior preservation
|
|
64
|
+
- [ ] Query nano-brain for known issues on changed functions
|
|
65
|
+
- [ ] Save checkpoint: `.checkpoints/phase-2-tracing.json`
|
|
66
|
+
- [ ] Update manifest: `completed_phase: 2`, `next_phase: 2.5`
|
|
67
|
+
|
|
68
|
+
## PR Summary (Phase 2.5)
|
|
69
|
+
|
|
70
|
+
- [ ] Write "What This PR Does" (1-3 sentences)
|
|
71
|
+
- [ ] Categorize key changes (Feature/Bugfix/Refactor/etc.)
|
|
72
|
+
- [ ] File-by-file summary with line numbers
|
|
73
|
+
- [ ] Save checkpoint: `.checkpoints/phase-2.5-summary.json`
|
|
74
|
+
- [ ] Update manifest: `completed_phase: 2.5`, `next_phase: 3`
|
|
75
|
+
|
|
76
|
+
## Subagent Execution (Phase 3)
|
|
77
|
+
|
|
78
|
+
- [ ] Include `$REVIEW_DIR` path in ALL subagent prompts
|
|
79
|
+
- [ ] Launch Code Quality agent (explore)
|
|
80
|
+
- [ ] After Code Quality completes: update `.checkpoints/phase-3-subagents.json` + manifest subagent_status
|
|
81
|
+
- [ ] Launch Security & Logic agent (oracle)
|
|
82
|
+
- [ ] After Security & Logic completes: update `.checkpoints/phase-3-subagents.json` + manifest subagent_status
|
|
83
|
+
- [ ] Launch Docs & Best Practices agent (librarian)
|
|
84
|
+
- [ ] After Docs & Best Practices completes: update `.checkpoints/phase-3-subagents.json` + manifest subagent_status
|
|
85
|
+
- [ ] Launch Tests & Integration agent (general/quick)
|
|
86
|
+
- [ ] After Tests & Integration completes: update `.checkpoints/phase-3-subagents.json` + manifest subagent_status
|
|
87
|
+
- [ ] Collect ALL results (especially Oracle — never skip)
|
|
88
|
+
- [ ] Update manifest: `completed_phase: 3`, `next_phase: 4`
|
|
89
|
+
|
|
90
|
+
## Refinement (Phase 4)
|
|
91
|
+
|
|
92
|
+
- [ ] Merge and deduplicate findings across agents
|
|
93
|
+
- [ ] Consensus scoring: 2+ agents flagged same issue → boost confidence to high
|
|
94
|
+
- [ ] Auto-downgrade: single agent + no evidence + critical/warning → suggestion
|
|
95
|
+
- [ ] Apply severity filter (critical/warning keep, suggestion count-only)
|
|
96
|
+
- [ ] Gap analysis — any subagent fail? Unreviewed files?
|
|
97
|
+
- [ ] Second pass on gaps if needed
|
|
98
|
+
- [ ] Save checkpoint: `.checkpoints/phase-4-refined.json`
|
|
99
|
+
- [ ] Update manifest: `completed_phase: 4`, `next_phase: 4.5`
|
|
100
|
+
|
|
101
|
+
## Verification Spot-Check (Phase 4.5)
|
|
102
|
+
|
|
103
|
+
- [ ] Read `references/verification-protocol.md`
|
|
104
|
+
- [ ] For each critical/warning finding: read cited code at evidence file:line in `$REVIEW_DIR`
|
|
105
|
+
- [ ] Mark each: `verified:true` (keep) | `verified:false` (drop) | `verified:unverifiable` (downgrade to suggestion)
|
|
106
|
+
- [ ] If no critical/warning findings: skip to Phase 4.6
|
|
107
|
+
- [ ] Save checkpoint: `.checkpoints/phase-4.5-verification.json`
|
|
108
|
+
- [ ] Update manifest: `completed_phase: 4.5`, `next_phase: 4.6`
|
|
109
|
+
|
|
110
|
+
## Confidence Scoring (Phase 4.6)
|
|
111
|
+
|
|
112
|
+
- [ ] Read `references/confidence-scoring.md`
|
|
113
|
+
- [ ] Compute accuracy_rate, consensus_rate, evidence_rate
|
|
114
|
+
- [ ] Compute overall score (0–100)
|
|
115
|
+
- [ ] Apply gate: < 60 → add 🔴 warning, 60–79 → add ⚠️ warning, 80+ → proceed normally
|
|
116
|
+
- [ ] Save checkpoint: `.checkpoints/phase-4.6-confidence.json`
|
|
117
|
+
- [ ] Update manifest: `completed_phase: 4.6`, `next_phase: 5`
|
|
118
|
+
|
|
119
|
+
## Report (Phase 5)
|
|
120
|
+
|
|
121
|
+
- [ ] Save to `.opencode/reviews/{type}_{identifier}_{date}.md`
|
|
122
|
+
- [ ] TL;DR with verdict and counts
|
|
123
|
+
- [ ] Critical issues with full detail
|
|
124
|
+
- [ ] Warnings with full detail
|
|
125
|
+
- [ ] Improvements as one-liners
|
|
126
|
+
- [ ] File summary table
|
|
127
|
+
- [ ] Save checkpoint: `.checkpoints/phase-5-report.md`
|
|
128
|
+
- [ ] Update manifest: `completed_phase: 5`, `next_phase: 5.5`
|
|
129
|
+
|
|
130
|
+
## Save to Memory (Phase 5.5)
|
|
131
|
+
|
|
132
|
+
- [ ] Write key findings to nano-brain with tags: review, {repo}
|
|
133
|
+
- [ ] Verify searchable (`curl -s localhost:3100/api/search -d '{"query":"PR {number}"}'`)
|
|
134
|
+
- [ ] Update manifest: `completed_phase: 5.5`, `next_phase: 6`
|
|
135
|
+
|
|
136
|
+
## Cleanup (Phase 6)
|
|
137
|
+
|
|
138
|
+
- [ ] Show temp folder path and size to user
|
|
139
|
+
- [ ] **ASK user** before removing (NEVER auto-delete)
|
|
140
|
+
- [ ] If user confirms → `rm -rf "$REVIEW_DIR"` (also removes `.checkpoints/`)
|
|
141
|
+
- [ ] If user declines → remind them to clean up later
|
|
142
|
+
- [ ] For multiple PRs: ask about each temp folder individually
|
|
143
|
+
- [ ] Note: Checkpoints auto-removed with clone dir (PR reviews) or remain in `.checkpoints/` (local reviews)
|
|
144
|
+
|
|
145
|
+
## Final Notification
|
|
146
|
+
|
|
147
|
+
- [ ] Report path shown to user
|
|
148
|
+
- [ ] Issue counts (critical/warning/suggestion) displayed
|
|
149
|
+
- [ ] Temp folder cleanup status communicated
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Checkpoint System
|
|
2
|
+
|
|
3
|
+
Reviews are resumable via checkpoints saved at each phase. If the agent crashes mid-review, you can resume from the last completed phase instead of starting over.
|
|
4
|
+
|
|
5
|
+
## Checkpoint Directory
|
|
6
|
+
|
|
7
|
+
**For PR Reviews:** `$REVIEW_DIR/.checkpoints/` (inside the temp clone directory)
|
|
8
|
+
**For Local Reviews (`--staged`):** `{current_working_directory}/.checkpoints/`
|
|
9
|
+
|
|
10
|
+
Checkpoints are automatically removed when the clone directory is deleted (Phase 6 cleanup).
|
|
11
|
+
|
|
12
|
+
## Checkpoint Files
|
|
13
|
+
|
|
14
|
+
| File | Content | Updated When |
|
|
15
|
+
|------|---------|--------------|
|
|
16
|
+
| `manifest.json` | Master state tracker | After every phase |
|
|
17
|
+
| `phase-0-clone.json` | Clone metadata (clone_dir, branches, head_sha, files_changed) | Phase 0 |
|
|
18
|
+
| `phase-1-context.json` | PR metadata, file classifications | Phase 1 |
|
|
19
|
+
| `phase-1.5-linear.json` | Linear ticket context, acceptance criteria | Phase 1.5 |
|
|
20
|
+
| `phase-2-tracing.json` | Smart tracing results per file | Phase 2 |
|
|
21
|
+
| `phase-2.5-summary.json` | PR summary text | Phase 2.5 |
|
|
22
|
+
| `phase-3-subagents.json` | Subagent findings (updated after EACH subagent completes) | Phase 3 |
|
|
23
|
+
| `phase-4-refined.json` | Deduplicated/filtered findings | Phase 4 |
|
|
24
|
+
| `phase-4.5-verification.json` | Verification results (verified/false/unverifiable counts, dropped/downgraded findings) | Phase 4.5 |
|
|
25
|
+
| `phase-4.6-confidence.json` | Result confidence score, per-finding confidence, gate action | Phase 4.6 |
|
|
26
|
+
| `phase-5-report.md` | Copy of final report | Phase 5 |
|
|
27
|
+
|
|
28
|
+
## Manifest Schema
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"version": "1.0",
|
|
33
|
+
"pr": { "repo": "owner/repo", "number": 123, "url": "..." },
|
|
34
|
+
"clone_dir": "/tmp/pr-review-...",
|
|
35
|
+
"started_at": "ISO-8601",
|
|
36
|
+
"last_updated": "ISO-8601",
|
|
37
|
+
"completed_phase": 2,
|
|
38
|
+
"next_phase": 2.5,
|
|
39
|
+
"phase_status": {
|
|
40
|
+
"0": "complete", "1": "complete", "1.5": "complete",
|
|
41
|
+
"2": "complete", "2.5": "pending", "3": "pending",
|
|
42
|
+
"4": "pending", "4.5": "pending", "4.6": "pending", "5": "pending"
|
|
43
|
+
},
|
|
44
|
+
"subagent_status": {
|
|
45
|
+
"explore": "pending", "oracle": "pending",
|
|
46
|
+
"librarian": "pending", "general": "pending"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Phase 3 Special Handling
|
|
52
|
+
|
|
53
|
+
Phase 3 runs 4 parallel subagents. After **EACH** subagent completes:
|
|
54
|
+
1. Update `phase-3-subagents.json` with that subagent's findings and status
|
|
55
|
+
2. Update `manifest.json` subagent_status to `"complete"` for that subagent
|
|
56
|
+
3. On resume: only run subagents with status != `"complete"`
|
|
57
|
+
|
|
58
|
+
This allows resuming mid-Phase-3 if only some subagents completed before a crash.
|