specops 0.2.4 → 0.3.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/.opencode/agent/specops-codebase-mapper.md +764 -0
- package/.opencode/agent/specops-debugger.md +1246 -0
- package/.opencode/agent/specops-executor.md +469 -0
- package/.opencode/agent/specops-integration-checker.md +443 -0
- package/.opencode/agent/specops-phase-researcher.md +547 -0
- package/.opencode/agent/specops-plan-checker.md +690 -0
- package/.opencode/agent/specops-planner.md +575 -0
- package/.opencode/agent/specops-project-researcher.md +354 -0
- package/.opencode/agent/specops-research-synthesizer.md +239 -0
- package/.opencode/agent/specops-roadmapper.md +642 -0
- package/.opencode/agent/specops-work-verifier.md +573 -0
- package/.opencode/references/checkpoints.md +776 -0
- package/.opencode/references/continuation-format.md +249 -0
- package/.opencode/references/decimal-phase-calculation.md +65 -0
- package/.opencode/references/git-integration.md +248 -0
- package/.opencode/references/git-planning-commit.md +38 -0
- package/.opencode/references/model-profile-resolution.md +34 -0
- package/.opencode/references/model-profiles.md +92 -0
- package/.opencode/references/phase-argument-parsing.md +61 -0
- package/.opencode/references/planning-config.md +196 -0
- package/.opencode/references/questioning.md +145 -0
- package/.opencode/references/tdd.md +263 -0
- package/.opencode/references/ui-brand.md +160 -0
- package/.opencode/references/verification-patterns.md +612 -0
- package/.opencode/skills/demand-analysis/SKILL.md +142 -10
- package/.opencode/templates/DEBUG.md +164 -0
- package/.opencode/templates/UAT.md +180 -0
- package/.opencode/templates/VALIDATION.md +76 -0
- package/.opencode/templates/codebase/architecture.md +255 -0
- package/.opencode/templates/codebase/concerns.md +310 -0
- package/.opencode/templates/codebase/conventions.md +307 -0
- package/.opencode/templates/codebase/integrations.md +280 -0
- package/.opencode/templates/codebase/stack.md +186 -0
- package/.opencode/templates/codebase/structure.md +285 -0
- package/.opencode/templates/codebase/testing.md +480 -0
- package/.opencode/templates/context.md +221 -0
- package/.opencode/templates/continue-here.md +78 -0
- package/.opencode/templates/debug-subagent-prompt.md +91 -0
- package/.opencode/templates/discovery.md +147 -0
- package/.opencode/templates/milestone-archive.md +123 -0
- package/.opencode/templates/milestone.md +115 -0
- package/.opencode/templates/phase-prompt.md +333 -0
- package/.opencode/templates/planner-subagent-prompt.md +117 -0
- package/.opencode/templates/project.md +184 -0
- package/.opencode/templates/requirements.md +130 -0
- package/.opencode/templates/research-project/ARCHITECTURE.md +204 -0
- package/.opencode/templates/research-project/FEATURES.md +147 -0
- package/.opencode/templates/research-project/PITFALLS.md +200 -0
- package/.opencode/templates/research-project/STACK.md +120 -0
- package/.opencode/templates/research-project/SUMMARY.md +170 -0
- package/.opencode/templates/research.md +278 -0
- package/.opencode/templates/retrospective.md +54 -0
- package/.opencode/templates/roadmap.md +202 -0
- package/.opencode/templates/state.md +176 -0
- package/.opencode/templates/summary-complex.md +59 -0
- package/.opencode/templates/summary-minimal.md +41 -0
- package/.opencode/templates/summary-standard.md +48 -0
- package/.opencode/templates/summary.md +248 -0
- package/.opencode/templates/user-setup.md +311 -0
- package/.opencode/templates/verification-report.md +322 -0
- package/.opencode/workflows/add-phase.md +111 -0
- package/.opencode/workflows/add-tests.md +350 -0
- package/.opencode/workflows/add-todo.md +157 -0
- package/.opencode/workflows/audit-milestone.md +297 -0
- package/.opencode/workflows/check-todos.md +176 -0
- package/.opencode/workflows/cleanup.md +152 -0
- package/.opencode/workflows/complete-milestone.md +763 -0
- package/.opencode/workflows/diagnose-issues.md +219 -0
- package/.opencode/workflows/discovery-phase.md +288 -0
- package/.opencode/workflows/discuss-phase.md +542 -0
- package/.opencode/workflows/execute-phase.md +449 -0
- package/.opencode/workflows/execute-plan.md +447 -0
- package/.opencode/workflows/health.md +156 -0
- package/.opencode/workflows/help.md +489 -0
- package/.opencode/workflows/insert-phase.md +129 -0
- package/.opencode/workflows/list-phase-assumptions.md +178 -0
- package/.opencode/workflows/map-codebase.md +315 -0
- package/.opencode/workflows/new-milestone.md +382 -0
- package/.opencode/workflows/new-project.md +1116 -0
- package/.opencode/workflows/pause-work.md +122 -0
- package/.opencode/workflows/plan-milestone-gaps.md +274 -0
- package/.opencode/workflows/plan-phase.md +569 -0
- package/.opencode/workflows/progress.md +381 -0
- package/.opencode/workflows/quick.md +453 -0
- package/.opencode/workflows/remove-phase.md +154 -0
- package/.opencode/workflows/research-phase.md +73 -0
- package/.opencode/workflows/resume-project.md +304 -0
- package/.opencode/workflows/set-profile.md +80 -0
- package/.opencode/workflows/settings.md +213 -0
- package/.opencode/workflows/transition.md +544 -0
- package/.opencode/workflows/update.md +219 -0
- package/.opencode/workflows/verify-phase.md +242 -0
- package/.opencode/workflows/verify-work.md +569 -0
- package/commands/specops/add-phase.md +43 -0
- package/commands/specops/add-tests.md +41 -0
- package/commands/specops/add-todo.md +47 -0
- package/commands/specops/audit-milestone.md +36 -0
- package/commands/specops/check-todos.md +45 -0
- package/commands/specops/cleanup.md +18 -0
- package/commands/specops/complete-milestone.md +136 -0
- package/commands/specops/debug.md +167 -0
- package/commands/specops/discuss-phase.md +83 -0
- package/commands/specops/execute-phase.md +41 -0
- package/commands/specops/health.md +22 -0
- package/commands/specops/help.md +22 -0
- package/commands/specops/insert-phase.md +32 -0
- package/commands/specops/join-discord.md +18 -0
- package/commands/specops/list-phase-assumptions.md +46 -0
- package/commands/specops/map-codebase.md +71 -0
- package/commands/specops/new-milestone.md +44 -0
- package/commands/specops/new-project.md +42 -0
- package/commands/specops/pause-work.md +38 -0
- package/commands/specops/plan-milestone-gaps.md +34 -0
- package/commands/specops/plan-phase.md +45 -0
- package/commands/specops/progress.md +24 -0
- package/commands/specops/quick.md +41 -0
- package/commands/specops/reapply-patches.md +111 -0
- package/commands/specops/remove-phase.md +31 -0
- package/commands/specops/research-phase.md +189 -0
- package/commands/specops/resume-work.md +40 -0
- package/commands/specops/set-profile.md +34 -0
- package/commands/specops/settings.md +36 -0
- package/commands/specops/update.md +37 -0
- package/commands/specops/verify-work.md +38 -0
- package/dist/__e2e__/01-state-engine.e2e.test.js +1 -1
- package/dist/acceptance/lazyDetector.js +1 -1
- package/dist/acceptance/lazyDetector.test.js +1 -1
- package/dist/acceptance/reporter.js +1 -1
- package/dist/acceptance/reporter.test.js +1 -1
- package/dist/acceptance/runner.js +1 -1
- package/dist/acceptance/runner.test.js +1 -1
- package/dist/cli.js +1 -1
- package/dist/context/index.js +1 -1
- package/dist/context/promptTemplate.js +1 -1
- package/dist/context/promptTemplate.test.js +1 -1
- package/dist/context/techContextLoader.js +1 -1
- package/dist/context/techContextLoader.test.js +1 -1
- package/dist/engine.js +1 -1
- package/dist/evolution/distiller.js +1 -1
- package/dist/evolution/index.js +1 -1
- package/dist/evolution/memoryGraph.js +1 -1
- package/dist/evolution/selector.js +1 -1
- package/dist/evolution/signals.js +1 -1
- package/dist/evolution/solidify.js +1 -1
- package/dist/evolution/store.js +1 -1
- package/dist/evolution/types.js +1 -1
- package/dist/init.d.ts +4 -3
- package/dist/init.js +1 -1
- package/dist/machines/agentMachine.js +1 -1
- package/dist/machines/agentMachine.test.js +1 -1
- package/dist/machines/supervisorMachine.js +1 -1
- package/dist/machines/supervisorMachine.test.js +1 -1
- package/dist/persistence/schema.js +1 -1
- package/dist/persistence/stateFile.js +1 -1
- package/dist/persistence/stateFile.test.js +1 -1
- package/dist/plugin-engine.js +1 -1
- package/dist/plugin.js +1 -1
- package/dist/types/index.js +1 -1
- package/dist/utils/id.js +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
# 验证模式
|
|
2
|
+
|
|
3
|
+
如何验证不同类型的产物是真正的实现,而非桩代码或占位符。
|
|
4
|
+
|
|
5
|
+
<core_principle>
|
|
6
|
+
**存在 ≠ 实现**
|
|
7
|
+
|
|
8
|
+
文件存在不代表特性可用。验证必须检查:
|
|
9
|
+
1. **存在** - 文件在预期路径
|
|
10
|
+
2. **实质性** - 内容是真正的实现,不是占位符
|
|
11
|
+
3. **连接** - 与系统其余部分相连
|
|
12
|
+
4. **功能性** - 调用时确实能工作
|
|
13
|
+
|
|
14
|
+
第 1-3 级可以通过程序化检查。第 4 级通常需要人工验证。
|
|
15
|
+
</core_principle>
|
|
16
|
+
|
|
17
|
+
<stub_detection>
|
|
18
|
+
|
|
19
|
+
## 通用桩代码模式
|
|
20
|
+
|
|
21
|
+
这些模式表示占位符代码,与文件类型无关:
|
|
22
|
+
|
|
23
|
+
**基于注释的桩代码:**
|
|
24
|
+
```bash
|
|
25
|
+
# 桩代码注释的 grep 模式
|
|
26
|
+
grep -E "(TODO|FIXME|XXX|HACK|PLACEHOLDER)" "$file"
|
|
27
|
+
grep -E "implement|add later|coming soon|will be" "$file" -i
|
|
28
|
+
grep -E "// \.\.\.|/\* \.\.\. \*/|# \.\.\." "$file"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**输出中的占位符文本:**
|
|
32
|
+
```bash
|
|
33
|
+
# UI 占位符模式
|
|
34
|
+
grep -E "placeholder|lorem ipsum|coming soon|under construction" "$file" -i
|
|
35
|
+
grep -E "sample|example|test data|dummy" "$file" -i
|
|
36
|
+
grep -E "\[.*\]|<.*>|\{.*\}" "$file" # 遗留的模板括号
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**空或简单的实现:**
|
|
40
|
+
```bash
|
|
41
|
+
# 什么都不做的函数
|
|
42
|
+
grep -E "return null|return undefined|return \{\}|return \[\]" "$file"
|
|
43
|
+
grep -E "pass$|\.\.\.|\bnothing\b" "$file"
|
|
44
|
+
grep -E "console\.(log|warn|error).*only" "$file" # 仅有日志的函数
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**应该是动态的地方使用了硬编码值:**
|
|
48
|
+
```bash
|
|
49
|
+
# 硬编码的 ID、计数或内容
|
|
50
|
+
grep -E "id.*=.*['\"].*['\"]" "$file" # 硬编码字符串 ID
|
|
51
|
+
grep -E "count.*=.*\d+|length.*=.*\d+" "$file" # 硬编码计数
|
|
52
|
+
grep -E "\\\$\d+\.\d{2}|\d+ items" "$file" # 硬编码显示值
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
</stub_detection>
|
|
56
|
+
|
|
57
|
+
<react_components>
|
|
58
|
+
|
|
59
|
+
## React/Next.js 组件
|
|
60
|
+
|
|
61
|
+
**存在性检查:**
|
|
62
|
+
```bash
|
|
63
|
+
# 文件存在且导出组件
|
|
64
|
+
[ -f "$component_path" ] && grep -E "export (default |)function|export const.*=.*\(" "$component_path"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**实质性检查:**
|
|
68
|
+
```bash
|
|
69
|
+
# 返回实际 JSX,不是占位符
|
|
70
|
+
grep -E "return.*<" "$component_path" | grep -v "return.*null" | grep -v "placeholder" -i
|
|
71
|
+
|
|
72
|
+
# 有有意义的内容(不只是包装 div)
|
|
73
|
+
grep -E "<[A-Z][a-zA-Z]+|className=|onClick=|onChange=" "$component_path"
|
|
74
|
+
|
|
75
|
+
# 使用 props 或 state(不是静态的)
|
|
76
|
+
grep -E "props\.|useState|useEffect|useContext|\{.*\}" "$component_path"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**React 特有的桩代码模式:**
|
|
80
|
+
```javascript
|
|
81
|
+
// 红旗 - 这些是桩代码:
|
|
82
|
+
return <div>Component</div>
|
|
83
|
+
return <div>Placeholder</div>
|
|
84
|
+
return <div>{/* TODO */}</div>
|
|
85
|
+
return <p>Coming soon</p>
|
|
86
|
+
return null
|
|
87
|
+
return <></>
|
|
88
|
+
|
|
89
|
+
// 也是桩代码 - 空处理器:
|
|
90
|
+
onClick={() => {}}
|
|
91
|
+
onChange={() => console.log('clicked')}
|
|
92
|
+
onSubmit={(e) => e.preventDefault()} // 只阻止默认行为,什么都不做
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**连接检查:**
|
|
96
|
+
```bash
|
|
97
|
+
# 组件导入了它需要的东西
|
|
98
|
+
grep -E "^import.*from" "$component_path"
|
|
99
|
+
|
|
100
|
+
# Props 确实被使用了(不只是接收)
|
|
101
|
+
# 查找解构或 props.X 用法
|
|
102
|
+
grep -E "\{ .* \}.*props|\bprops\.[a-zA-Z]+" "$component_path"
|
|
103
|
+
|
|
104
|
+
# API 调用存在(对于数据获取组件)
|
|
105
|
+
grep -E "fetch\(|axios\.|useSWR|useQuery|getServerSideProps|getStaticProps" "$component_path"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**功能验证(需要人工):**
|
|
109
|
+
- 组件是否渲染了可见内容?
|
|
110
|
+
- 交互元素是否响应点击?
|
|
111
|
+
- 数据是否加载并显示?
|
|
112
|
+
- 错误状态是否适当显示?
|
|
113
|
+
|
|
114
|
+
</react_components>
|
|
115
|
+
|
|
116
|
+
<api_routes>
|
|
117
|
+
|
|
118
|
+
## API 路由(Next.js App Router / Express / 等)
|
|
119
|
+
|
|
120
|
+
**存在性检查:**
|
|
121
|
+
```bash
|
|
122
|
+
# 路由文件存在
|
|
123
|
+
[ -f "$route_path" ]
|
|
124
|
+
|
|
125
|
+
# 导出 HTTP 方法处理器(Next.js App Router)
|
|
126
|
+
grep -E "export (async )?(function|const) (GET|POST|PUT|PATCH|DELETE)" "$route_path"
|
|
127
|
+
|
|
128
|
+
# 或 Express 风格处理器
|
|
129
|
+
grep -E "\.(get|post|put|patch|delete)\(" "$route_path"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**实质性检查:**
|
|
133
|
+
```bash
|
|
134
|
+
# 有实际逻辑,不只是 return 语句
|
|
135
|
+
wc -l "$route_path" # 超过 10-15 行表示真正的实现
|
|
136
|
+
|
|
137
|
+
# 与数据源交互
|
|
138
|
+
grep -E "prisma\.|db\.|mongoose\.|sql|query|find|create|update|delete" "$route_path" -i
|
|
139
|
+
|
|
140
|
+
# 有错误处理
|
|
141
|
+
grep -E "try|catch|throw|error|Error" "$route_path"
|
|
142
|
+
|
|
143
|
+
# 返回有意义的响应
|
|
144
|
+
grep -E "Response\.json|res\.json|res\.send|return.*\{" "$route_path" | grep -v "message.*not implemented" -i
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**API 路由特有的桩代码模式:**
|
|
148
|
+
```typescript
|
|
149
|
+
// 红旗 - 这些是桩代码:
|
|
150
|
+
export async function POST() {
|
|
151
|
+
return Response.json({ message: "Not implemented" })
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export async function GET() {
|
|
155
|
+
return Response.json([]) // 没有 DB 查询的空数组
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export async function PUT() {
|
|
159
|
+
return new Response() // 空响应
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// 仅有 console log:
|
|
163
|
+
export async function POST(req) {
|
|
164
|
+
console.log(await req.json())
|
|
165
|
+
return Response.json({ ok: true })
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**连接检查:**
|
|
170
|
+
```bash
|
|
171
|
+
# 导入数据库/服务客户端
|
|
172
|
+
grep -E "^import.*prisma|^import.*db|^import.*client" "$route_path"
|
|
173
|
+
|
|
174
|
+
# 确实使用了请求体(对于 POST/PUT)
|
|
175
|
+
grep -E "req\.json\(\)|req\.body|request\.json\(\)" "$route_path"
|
|
176
|
+
|
|
177
|
+
# 验证输入(不只是信任请求)
|
|
178
|
+
grep -E "schema\.parse|validate|zod|yup|joi" "$route_path"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**功能验证(人工或自动化):**
|
|
182
|
+
- GET 是否从数据库返回真实数据?
|
|
183
|
+
- POST 是否确实创建了记录?
|
|
184
|
+
- 错误响应是否有正确的状态码?
|
|
185
|
+
- 认证检查是否确实被执行?
|
|
186
|
+
|
|
187
|
+
</api_routes>
|
|
188
|
+
|
|
189
|
+
<database_schema>
|
|
190
|
+
|
|
191
|
+
## 数据库 Schema(Prisma / Drizzle / SQL)
|
|
192
|
+
|
|
193
|
+
**存在性检查:**
|
|
194
|
+
```bash
|
|
195
|
+
# Schema 文件存在
|
|
196
|
+
[ -f "prisma/schema.prisma" ] || [ -f "drizzle/schema.ts" ] || [ -f "src/db/schema.sql" ]
|
|
197
|
+
|
|
198
|
+
# 模型/表已定义
|
|
199
|
+
grep -E "^model $model_name|CREATE TABLE $table_name|export const $table_name" "$schema_path"
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**实质性检查:**
|
|
203
|
+
```bash
|
|
204
|
+
# 有预期的字段(不只是 id)
|
|
205
|
+
grep -A 20 "model $model_name" "$schema_path" | grep -E "^\s+\w+\s+\w+"
|
|
206
|
+
|
|
207
|
+
# 如果预期有关系
|
|
208
|
+
grep -E "@relation|REFERENCES|FOREIGN KEY" "$schema_path"
|
|
209
|
+
|
|
210
|
+
# 有适当的字段类型(不全是 String)
|
|
211
|
+
grep -A 20 "model $model_name" "$schema_path" | grep -E "Int|DateTime|Boolean|Float|Decimal|Json"
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Schema 特有的桩代码模式:**
|
|
215
|
+
```prisma
|
|
216
|
+
// 红旗 - 这些是桩代码:
|
|
217
|
+
model User {
|
|
218
|
+
id String @id
|
|
219
|
+
// TODO: add fields
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
model Message {
|
|
223
|
+
id String @id
|
|
224
|
+
content String // 只有一个真实字段
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// 缺少关键字段:
|
|
228
|
+
model Order {
|
|
229
|
+
id String @id
|
|
230
|
+
// 没有:userId、items、total、status、createdAt
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**连接检查:**
|
|
235
|
+
```bash
|
|
236
|
+
# 迁移存在且已应用
|
|
237
|
+
ls prisma/migrations/ 2>/dev/null | wc -l # 应该 > 0
|
|
238
|
+
npx prisma migrate status 2>/dev/null | grep -v "pending"
|
|
239
|
+
|
|
240
|
+
# 客户端已生成
|
|
241
|
+
[ -d "node_modules/.prisma/client" ]
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**功能验证:**
|
|
245
|
+
```bash
|
|
246
|
+
# 可以查询表(自动化)
|
|
247
|
+
npx prisma db execute --stdin <<< "SELECT COUNT(*) FROM $table_name"
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
</database_schema>
|
|
251
|
+
|
|
252
|
+
<hooks_utilities>
|
|
253
|
+
|
|
254
|
+
## 自定义 Hooks 和工具函数
|
|
255
|
+
|
|
256
|
+
**存在性检查:**
|
|
257
|
+
```bash
|
|
258
|
+
# 文件存在且导出函数
|
|
259
|
+
[ -f "$hook_path" ] && grep -E "export (default )?(function|const)" "$hook_path"
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**实质性检查:**
|
|
263
|
+
```bash
|
|
264
|
+
# Hook 使用了 React hooks(对于自定义 hooks)
|
|
265
|
+
grep -E "useState|useEffect|useCallback|useMemo|useRef|useContext" "$hook_path"
|
|
266
|
+
|
|
267
|
+
# 有有意义的返回值
|
|
268
|
+
grep -E "return \{|return \[" "$hook_path"
|
|
269
|
+
|
|
270
|
+
# 超过简单长度
|
|
271
|
+
[ $(wc -l < "$hook_path") -gt 10 ]
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Hooks 特有的桩代码模式:**
|
|
275
|
+
```typescript
|
|
276
|
+
// 红旗 - 这些是桩代码:
|
|
277
|
+
export function useAuth() {
|
|
278
|
+
return { user: null, login: () => {}, logout: () => {} }
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export function useCart() {
|
|
282
|
+
const [items, setItems] = useState([])
|
|
283
|
+
return { items, addItem: () => console.log('add'), removeItem: () => {} }
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// 硬编码返回:
|
|
287
|
+
export function useUser() {
|
|
288
|
+
return { name: "Test User", email: "test@example.com" }
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**连接检查:**
|
|
293
|
+
```bash
|
|
294
|
+
# Hook 确实在某处被导入
|
|
295
|
+
grep -r "import.*$hook_name" src/ --include="*.tsx" --include="*.ts" | grep -v "$hook_path"
|
|
296
|
+
|
|
297
|
+
# Hook 确实被调用
|
|
298
|
+
grep -r "$hook_name()" src/ --include="*.tsx" --include="*.ts" | grep -v "$hook_path"
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
</hooks_utilities>
|
|
302
|
+
|
|
303
|
+
<environment_config>
|
|
304
|
+
|
|
305
|
+
## 环境变量和配置
|
|
306
|
+
|
|
307
|
+
**存在性检查:**
|
|
308
|
+
```bash
|
|
309
|
+
# .env 文件存在
|
|
310
|
+
[ -f ".env" ] || [ -f ".env.local" ]
|
|
311
|
+
|
|
312
|
+
# 必需的变量已定义
|
|
313
|
+
grep -E "^$VAR_NAME=" .env .env.local 2>/dev/null
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**实质性检查:**
|
|
317
|
+
```bash
|
|
318
|
+
# 变量有实际值(不是占位符)
|
|
319
|
+
grep -E "^$VAR_NAME=.+" .env .env.local 2>/dev/null | grep -v "your-.*-here|xxx|placeholder|TODO" -i
|
|
320
|
+
|
|
321
|
+
# 值看起来对类型有效:
|
|
322
|
+
# - URL 应以 http 开头
|
|
323
|
+
# - 密钥应足够长
|
|
324
|
+
# - 布尔值应为 true/false
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**环境变量特有的桩代码模式:**
|
|
328
|
+
```bash
|
|
329
|
+
# 红旗 - 这些是桩代码:
|
|
330
|
+
DATABASE_URL=your-database-url-here
|
|
331
|
+
STRIPE_SECRET_KEY=sk_test_xxx
|
|
332
|
+
API_KEY=placeholder
|
|
333
|
+
NEXT_PUBLIC_API_URL=http://localhost:3000 # 生产环境仍指向 localhost
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
**连接检查:**
|
|
337
|
+
```bash
|
|
338
|
+
# 变量确实在代码中使用
|
|
339
|
+
grep -r "process\.env\.$VAR_NAME|env\.$VAR_NAME" src/ --include="*.ts" --include="*.tsx"
|
|
340
|
+
|
|
341
|
+
# 变量在验证 schema 中(如果使用 zod 等验证 env)
|
|
342
|
+
grep -E "$VAR_NAME" src/env.ts src/env.mjs 2>/dev/null
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
</environment_config>
|
|
346
|
+
|
|
347
|
+
<wiring_verification>
|
|
348
|
+
|
|
349
|
+
## 连接验证模式
|
|
350
|
+
|
|
351
|
+
连接验证检查组件之间是否确实在通信。这是大多数桩代码隐藏的地方。
|
|
352
|
+
|
|
353
|
+
### 模式:组件 -> API
|
|
354
|
+
|
|
355
|
+
**检查:** 组件是否确实调用了 API?
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
# 找到 fetch/axios 调用
|
|
359
|
+
grep -E "fetch\(['\"].*$api_path|axios\.(get|post).*$api_path" "$component_path"
|
|
360
|
+
|
|
361
|
+
# 验证没有被注释掉
|
|
362
|
+
grep -E "fetch\(|axios\." "$component_path" | grep -v "^.*//.*fetch"
|
|
363
|
+
|
|
364
|
+
# 检查响应是否被使用
|
|
365
|
+
grep -E "await.*fetch|\.then\(|setData|setState" "$component_path"
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**红旗:**
|
|
369
|
+
```typescript
|
|
370
|
+
// Fetch 存在但响应被忽略:
|
|
371
|
+
fetch('/api/messages') // 没有 await,没有 .then,没有赋值
|
|
372
|
+
|
|
373
|
+
// Fetch 在注释中:
|
|
374
|
+
// fetch('/api/messages').then(r => r.json()).then(setMessages)
|
|
375
|
+
|
|
376
|
+
// Fetch 到错误的端点:
|
|
377
|
+
fetch('/api/message') // 拼写错误 - 应该是 /api/messages
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### 模式:API -> 数据库
|
|
381
|
+
|
|
382
|
+
**检查:** API 路由是否确实查询了数据库?
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
# 找到数据库调用
|
|
386
|
+
grep -E "prisma\.$model|db\.query|Model\.find" "$route_path"
|
|
387
|
+
|
|
388
|
+
# 验证已 await
|
|
389
|
+
grep -E "await.*prisma|await.*db\." "$route_path"
|
|
390
|
+
|
|
391
|
+
# 检查结果是否被返回
|
|
392
|
+
grep -E "return.*json.*data|res\.json.*result" "$route_path"
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**红旗:**
|
|
396
|
+
```typescript
|
|
397
|
+
// 查询存在但结果未返回:
|
|
398
|
+
await prisma.message.findMany()
|
|
399
|
+
return Response.json({ ok: true }) // 返回静态值,不是查询结果
|
|
400
|
+
|
|
401
|
+
// 查询未 await:
|
|
402
|
+
const messages = prisma.message.findMany() // 缺少 await
|
|
403
|
+
return Response.json(messages) // 返回 Promise,不是数据
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### 模式:表单 -> 处理器
|
|
407
|
+
|
|
408
|
+
**检查:** 表单提交是否确实做了什么?
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
# 找到 onSubmit 处理器
|
|
412
|
+
grep -E "onSubmit=\{|handleSubmit" "$component_path"
|
|
413
|
+
|
|
414
|
+
# 检查处理器有内容
|
|
415
|
+
grep -A 10 "onSubmit.*=" "$component_path" | grep -E "fetch|axios|mutate|dispatch"
|
|
416
|
+
|
|
417
|
+
# 验证不只是 preventDefault
|
|
418
|
+
grep -A 5 "onSubmit" "$component_path" | grep -v "only.*preventDefault" -i
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
**红旗:**
|
|
422
|
+
```typescript
|
|
423
|
+
// 处理器只阻止默认行为:
|
|
424
|
+
onSubmit={(e) => e.preventDefault()}
|
|
425
|
+
|
|
426
|
+
// 处理器只打日志:
|
|
427
|
+
const handleSubmit = (data) => {
|
|
428
|
+
console.log(data)
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// 处理器是空的:
|
|
432
|
+
onSubmit={() => {}}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### 模式:状态 -> 渲染
|
|
436
|
+
|
|
437
|
+
**检查:** 组件是否渲染状态,而非硬编码内容?
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
# 找到 JSX 中的状态使用
|
|
441
|
+
grep -E "\{.*messages.*\}|\{.*data.*\}|\{.*items.*\}" "$component_path"
|
|
442
|
+
|
|
443
|
+
# 检查状态的 map/render
|
|
444
|
+
grep -E "\.map\(|\.filter\(|\.reduce\(" "$component_path"
|
|
445
|
+
|
|
446
|
+
# 验证动态内容
|
|
447
|
+
grep -E "\{[a-zA-Z_]+\." "$component_path" # 变量插值
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
**红旗:**
|
|
451
|
+
```tsx
|
|
452
|
+
// 硬编码而非状态:
|
|
453
|
+
return <div>
|
|
454
|
+
<p>Message 1</p>
|
|
455
|
+
<p>Message 2</p>
|
|
456
|
+
</div>
|
|
457
|
+
|
|
458
|
+
// 状态存在但未渲染:
|
|
459
|
+
const [messages, setMessages] = useState([])
|
|
460
|
+
return <div>No messages</div> // 总是显示 "no messages"
|
|
461
|
+
|
|
462
|
+
// 渲染了错误的状态:
|
|
463
|
+
const [messages, setMessages] = useState([])
|
|
464
|
+
return <div>{otherData.map(...)}</div> // 使用了不同的数据
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
</wiring_verification>
|
|
468
|
+
|
|
469
|
+
<verification_checklist>
|
|
470
|
+
|
|
471
|
+
## 快速验证清单
|
|
472
|
+
|
|
473
|
+
对每种产物类型,逐项检查:
|
|
474
|
+
|
|
475
|
+
### 组件清单
|
|
476
|
+
- [ ] 文件在预期路径存在
|
|
477
|
+
- [ ] 导出了函数/const 组件
|
|
478
|
+
- [ ] 返回 JSX(不是 null/空)
|
|
479
|
+
- [ ] 渲染中没有占位符文本
|
|
480
|
+
- [ ] 使用了 props 或 state(不是静态的)
|
|
481
|
+
- [ ] 事件处理器有真正的实现
|
|
482
|
+
- [ ] 导入正确解析
|
|
483
|
+
- [ ] 在应用中某处被使用
|
|
484
|
+
|
|
485
|
+
### API 路由清单
|
|
486
|
+
- [ ] 文件在预期路径存在
|
|
487
|
+
- [ ] 导出了 HTTP 方法处理器
|
|
488
|
+
- [ ] 处理器超过 5 行
|
|
489
|
+
- [ ] 查询了数据库或服务
|
|
490
|
+
- [ ] 返回有意义的响应(不是空/占位符)
|
|
491
|
+
- [ ] 有错误处理
|
|
492
|
+
- [ ] 验证了输入
|
|
493
|
+
- [ ] 从前端被调用
|
|
494
|
+
|
|
495
|
+
### Schema 清单
|
|
496
|
+
- [ ] 模型/表已定义
|
|
497
|
+
- [ ] 有所有预期字段
|
|
498
|
+
- [ ] 字段有适当的类型
|
|
499
|
+
- [ ] 如需要已定义关系
|
|
500
|
+
- [ ] 迁移存在且已应用
|
|
501
|
+
- [ ] 客户端已生成
|
|
502
|
+
|
|
503
|
+
### Hook/工具函数清单
|
|
504
|
+
- [ ] 文件在预期路径存在
|
|
505
|
+
- [ ] 导出了函数
|
|
506
|
+
- [ ] 有有意义的实现(不是空返回)
|
|
507
|
+
- [ ] 在应用中某处被使用
|
|
508
|
+
- [ ] 返回值被消费
|
|
509
|
+
|
|
510
|
+
### 连接清单
|
|
511
|
+
- [ ] 组件 -> API:fetch/axios 调用存在且使用了响应
|
|
512
|
+
- [ ] API -> 数据库:查询存在且结果被返回
|
|
513
|
+
- [ ] 表单 -> 处理器:onSubmit 调用了 API/mutation
|
|
514
|
+
- [ ] 状态 -> 渲染:状态变量出现在 JSX 中
|
|
515
|
+
|
|
516
|
+
</verification_checklist>
|
|
517
|
+
|
|
518
|
+
<automated_verification_script>
|
|
519
|
+
|
|
520
|
+
## 自动化验证方法
|
|
521
|
+
|
|
522
|
+
对于验证子代理,使用此模式:
|
|
523
|
+
|
|
524
|
+
```bash
|
|
525
|
+
# 1. 检查存在性
|
|
526
|
+
check_exists() {
|
|
527
|
+
[ -f "$1" ] && echo "EXISTS: $1" || echo "MISSING: $1"
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
# 2. 检查桩代码模式
|
|
531
|
+
check_stubs() {
|
|
532
|
+
local file="$1"
|
|
533
|
+
local stubs=$(grep -c -E "TODO|FIXME|placeholder|not implemented" "$file" 2>/dev/null || echo 0)
|
|
534
|
+
[ "$stubs" -gt 0 ] && echo "STUB_PATTERNS: $stubs in $file"
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
# 3. 检查连接(组件调用 API)
|
|
538
|
+
check_wiring() {
|
|
539
|
+
local component="$1"
|
|
540
|
+
local api_path="$2"
|
|
541
|
+
grep -q "$api_path" "$component" && echo "WIRED: $component → $api_path" || echo "NOT_WIRED: $component → $api_path"
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
# 4. 检查实质性(超过 N 行,有预期模式)
|
|
545
|
+
check_substantive() {
|
|
546
|
+
local file="$1"
|
|
547
|
+
local min_lines="$2"
|
|
548
|
+
local pattern="$3"
|
|
549
|
+
local lines=$(wc -l < "$file" 2>/dev/null || echo 0)
|
|
550
|
+
local has_pattern=$(grep -c -E "$pattern" "$file" 2>/dev/null || echo 0)
|
|
551
|
+
[ "$lines" -ge "$min_lines" ] && [ "$has_pattern" -gt 0 ] && echo "SUBSTANTIVE: $file" || echo "THIN: $file ($lines lines, $has_pattern matches)"
|
|
552
|
+
}
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
对每个必须有的产物运行这些检查。将结果汇总到 VERIFICATION.md。
|
|
556
|
+
|
|
557
|
+
</automated_verification_script>
|
|
558
|
+
|
|
559
|
+
<human_verification_triggers>
|
|
560
|
+
|
|
561
|
+
## 何时需要人工验证
|
|
562
|
+
|
|
563
|
+
有些东西无法通过程序化验证。将这些标记为需要人工测试:
|
|
564
|
+
|
|
565
|
+
**始终需要人工:**
|
|
566
|
+
- 视觉外观(看起来对吗?)
|
|
567
|
+
- 用户流程完成(你确实能完成这件事吗?)
|
|
568
|
+
- 实时行为(WebSocket、SSE)
|
|
569
|
+
- 外部服务集成(Stripe、邮件发送)
|
|
570
|
+
- 错误消息清晰度(消息有帮助吗?)
|
|
571
|
+
- 性能感受(感觉快吗?)
|
|
572
|
+
|
|
573
|
+
**不确定时需要人工:**
|
|
574
|
+
- grep 无法追踪的复杂连接
|
|
575
|
+
- 依赖状态的动态行为
|
|
576
|
+
- 边界情况和错误状态
|
|
577
|
+
- 移动端响应式
|
|
578
|
+
- 无障碍性
|
|
579
|
+
|
|
580
|
+
**人工验证请求的格式:**
|
|
581
|
+
```markdown
|
|
582
|
+
## 需要人工验证
|
|
583
|
+
|
|
584
|
+
### 1. 聊天消息发送
|
|
585
|
+
**测试:** 输入消息并点击发送
|
|
586
|
+
**预期:** 消息出现在列表中,输入框清空
|
|
587
|
+
**检查:** 刷新后消息是否持久化?
|
|
588
|
+
|
|
589
|
+
### 2. 错误处理
|
|
590
|
+
**测试:** 断开网络,尝试发送
|
|
591
|
+
**预期:** 出现错误消息,消息不丢失
|
|
592
|
+
**检查:** 重新连接后能否重试?
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
</human_verification_triggers>
|
|
596
|
+
|
|
597
|
+
<checkpoint_automation_reference>
|
|
598
|
+
|
|
599
|
+
## 检查点前的自动化
|
|
600
|
+
|
|
601
|
+
关于自动化优先的检查点模式、服务器生命周期管理、CLI 安装处理和错误恢复协议,参见:
|
|
602
|
+
|
|
603
|
+
**@.opencode/references/checkpoints.md** -> `<automation_reference>` 部分
|
|
604
|
+
|
|
605
|
+
关键原则:
|
|
606
|
+
- Claude 在呈现检查点之前设置验证环境
|
|
607
|
+
- 用户从不运行 CLI 命令(只访问 URL)
|
|
608
|
+
- 服务器生命周期:在检查点前启动,处理端口冲突,在持续期间保持运行
|
|
609
|
+
- CLI 安装:安全时自动安装,否则设置检查点让用户选择
|
|
610
|
+
- 错误处理:在检查点前修复损坏的环境,永远不要呈现设置失败的检查点
|
|
611
|
+
|
|
612
|
+
</checkpoint_automation_reference>
|