sumulige-claude 1.2.1 → 1.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/.claude/.kickoff-hint.txt +1 -1
- package/.claude/AGENTS.md +6 -6
- package/.claude/USAGE.md +175 -0
- package/.claude/commands/fix.md +83 -0
- package/.claude/commands/plan.md +88 -0
- package/.claude/commands/refactor.md +102 -0
- package/.claude/hooks/pre-push.cjs +3 -2
- package/.claude/rag/skill-index.json +34 -15
- package/.claude/rules/coding-style.md +119 -0
- package/.claude/rules/hooks.md +288 -0
- package/.claude/rules/performance.md +78 -0
- package/.claude/rules/security.md +56 -0
- package/.claude/rules/testing.md +89 -0
- package/.claude/settings.local.json +19 -1
- package/.claude/skills/design-brain/SKILL.md +190 -0
- package/.claude/skills/design-brain/metadata.yaml +26 -0
- package/.claude/skills/quality-guard/SKILL.md +138 -0
- package/.claude/skills/quality-guard/metadata.yaml +27 -0
- package/.claude/skills/quick-fix/SKILL.md +138 -0
- package/.claude/skills/quick-fix/metadata.yaml +26 -0
- package/.claude/skills/test-master/SKILL.md +186 -0
- package/.claude/skills/test-master/metadata.yaml +29 -0
- package/AGENTS.md +25 -7
- package/CHANGELOG.md +39 -3
- package/README.md +57 -0
- package/config/official-skills.json +1 -1
- package/development/knowledge-base/.index.clean.json +1 -0
- package/package.json +1 -1
- package/.claude/skills/123-skill/SKILL.md +0 -61
- package/.claude/skills/123-skill/examples/basic.md +0 -3
- package/.claude/skills/123-skill/metadata.yaml +0 -30
- package/.claude/skills/123-skill/templates/default.md +0 -3
- package/.claude/skills/api-tester/SKILL.md +0 -90
- package/.claude/skills/api-tester/examples/basic.md +0 -3
- package/.claude/skills/api-tester/metadata.yaml +0 -30
- package/.claude/skills/api-tester/templates/default.md +0 -3
- package/.claude/skills/code-reviewer-123/SKILL.md +0 -61
- package/.claude/skills/code-reviewer-123/examples/basic.md +0 -3
- package/.claude/skills/code-reviewer-123/metadata.yaml +0 -30
- package/.claude/skills/code-reviewer-123/templates/default.md +0 -3
- package/.claude/skills/my-skill/SKILL.md +0 -61
- package/.claude/skills/my-skill/examples/basic.md +0 -3
- package/.claude/skills/my-skill/metadata.yaml +0 -30
- package/.claude/skills/my-skill/templates/default.md +0 -3
- package/.claude/skills/template/SKILL.md +0 -6
- package/.claude/skills/template/metadata.yaml +0 -30
- package/.claude/skills/test-skill-name/SKILL.md +0 -61
- package/.claude/skills/test-skill-name/examples/basic.md +0 -3
- package/.claude/skills/test-skill-name/metadata.yaml +0 -30
- package/.claude/skills/test-skill-name/templates/default.md +0 -3
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# Hooks 最佳实践
|
|
2
|
+
|
|
3
|
+
> 自动化钩子使用指南 - 融合自 everything-claude-code
|
|
4
|
+
|
|
5
|
+
## Hook 类型
|
|
6
|
+
|
|
7
|
+
| 类型 | 触发时机 | 用途 |
|
|
8
|
+
|------|---------|------|
|
|
9
|
+
| PreToolUse | 工具执行前 | 验证、准备、确认 |
|
|
10
|
+
| PostToolUse | 工具执行后 | 格式化、检查、通知 |
|
|
11
|
+
| Stop | 会话结束时 | 总结、清理、保存 |
|
|
12
|
+
|
|
13
|
+
## 推荐的 Hook 配置
|
|
14
|
+
|
|
15
|
+
### PreToolUse Hooks
|
|
16
|
+
|
|
17
|
+
**1. Git Push 审查**
|
|
18
|
+
|
|
19
|
+
在 `git push` 前确认分支和状态:
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
// hooks/git-push-review.cjs
|
|
23
|
+
module.exports = {
|
|
24
|
+
event: 'PreToolUse',
|
|
25
|
+
condition: (input) => {
|
|
26
|
+
return input.tool === 'Bash' &&
|
|
27
|
+
input.input?.command?.includes('git push')
|
|
28
|
+
},
|
|
29
|
+
action: async (input, context) => {
|
|
30
|
+
// 获取当前分支
|
|
31
|
+
const branch = execSync('git branch --show-current').toString().trim()
|
|
32
|
+
|
|
33
|
+
// 检查是否推送到 main/master
|
|
34
|
+
if (branch === 'main' || branch === 'master') {
|
|
35
|
+
return {
|
|
36
|
+
decision: 'ask',
|
|
37
|
+
message: `即将推送到 ${branch} 分支,确认继续?`
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return { decision: 'allow' }
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**2. 敏感文件保护**
|
|
47
|
+
|
|
48
|
+
防止修改关键配置文件:
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
// hooks/protect-sensitive.cjs
|
|
52
|
+
const PROTECTED_PATTERNS = [
|
|
53
|
+
'.env',
|
|
54
|
+
'credentials',
|
|
55
|
+
'secrets',
|
|
56
|
+
'*.pem',
|
|
57
|
+
'*.key'
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
module.exports = {
|
|
61
|
+
event: 'PreToolUse',
|
|
62
|
+
condition: (input) => {
|
|
63
|
+
return ['Write', 'Edit'].includes(input.tool)
|
|
64
|
+
},
|
|
65
|
+
action: async (input, context) => {
|
|
66
|
+
const filePath = input.input?.file_path || ''
|
|
67
|
+
|
|
68
|
+
for (const pattern of PROTECTED_PATTERNS) {
|
|
69
|
+
if (filePath.includes(pattern) ||
|
|
70
|
+
filePath.endsWith(pattern.replace('*', ''))) {
|
|
71
|
+
return {
|
|
72
|
+
decision: 'ask',
|
|
73
|
+
message: `即将修改敏感文件 ${filePath},确认继续?`
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { decision: 'allow' }
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### PostToolUse Hooks
|
|
84
|
+
|
|
85
|
+
**1. 自动格式化**
|
|
86
|
+
|
|
87
|
+
写入文件后自动运行 Prettier:
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
// hooks/auto-format.cjs
|
|
91
|
+
const { execSync } = require('child_process')
|
|
92
|
+
|
|
93
|
+
const FORMATTABLE_EXTENSIONS = [
|
|
94
|
+
'.js', '.jsx', '.ts', '.tsx',
|
|
95
|
+
'.json', '.md', '.css', '.scss'
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
module.exports = {
|
|
99
|
+
event: 'PostToolUse',
|
|
100
|
+
condition: (input, output) => {
|
|
101
|
+
if (!['Write', 'Edit'].includes(input.tool)) return false
|
|
102
|
+
|
|
103
|
+
const filePath = input.input?.file_path || ''
|
|
104
|
+
return FORMATTABLE_EXTENSIONS.some(ext => filePath.endsWith(ext))
|
|
105
|
+
},
|
|
106
|
+
action: async (input, output, context) => {
|
|
107
|
+
const filePath = input.input?.file_path
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
execSync(`npx prettier --write "${filePath}"`, {
|
|
111
|
+
stdio: 'pipe'
|
|
112
|
+
})
|
|
113
|
+
return { message: `已格式化: ${filePath}` }
|
|
114
|
+
} catch (error) {
|
|
115
|
+
// Prettier 未安装或格式化失败,静默处理
|
|
116
|
+
return null
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**2. TypeScript 类型检查**
|
|
123
|
+
|
|
124
|
+
编辑 TS 文件后检查类型:
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
// hooks/type-check.cjs
|
|
128
|
+
const { execSync } = require('child_process')
|
|
129
|
+
|
|
130
|
+
module.exports = {
|
|
131
|
+
event: 'PostToolUse',
|
|
132
|
+
condition: (input, output) => {
|
|
133
|
+
if (!['Write', 'Edit'].includes(input.tool)) return false
|
|
134
|
+
|
|
135
|
+
const filePath = input.input?.file_path || ''
|
|
136
|
+
return filePath.endsWith('.ts') || filePath.endsWith('.tsx')
|
|
137
|
+
},
|
|
138
|
+
action: async (input, output, context) => {
|
|
139
|
+
try {
|
|
140
|
+
execSync('npx tsc --noEmit', {
|
|
141
|
+
stdio: 'pipe',
|
|
142
|
+
timeout: 30000
|
|
143
|
+
})
|
|
144
|
+
return { message: '类型检查通过' }
|
|
145
|
+
} catch (error) {
|
|
146
|
+
const stderr = error.stderr?.toString() || ''
|
|
147
|
+
if (stderr.includes('error')) {
|
|
148
|
+
return {
|
|
149
|
+
message: `类型错误:\n${stderr.slice(0, 500)}`
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return null
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**3. Console.log 警告**
|
|
159
|
+
|
|
160
|
+
检测遗留的调试语句:
|
|
161
|
+
|
|
162
|
+
```javascript
|
|
163
|
+
// hooks/console-warning.cjs
|
|
164
|
+
const fs = require('fs')
|
|
165
|
+
|
|
166
|
+
module.exports = {
|
|
167
|
+
event: 'PostToolUse',
|
|
168
|
+
condition: (input, output) => {
|
|
169
|
+
if (!['Write', 'Edit'].includes(input.tool)) return false
|
|
170
|
+
|
|
171
|
+
const filePath = input.input?.file_path || ''
|
|
172
|
+
return filePath.endsWith('.ts') ||
|
|
173
|
+
filePath.endsWith('.tsx') ||
|
|
174
|
+
filePath.endsWith('.js') ||
|
|
175
|
+
filePath.endsWith('.jsx')
|
|
176
|
+
},
|
|
177
|
+
action: async (input, output, context) => {
|
|
178
|
+
const filePath = input.input?.file_path
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
const content = fs.readFileSync(filePath, 'utf-8')
|
|
182
|
+
const consoleMatches = content.match(/console\.(log|debug|info)\(/g)
|
|
183
|
+
|
|
184
|
+
if (consoleMatches && consoleMatches.length > 0) {
|
|
185
|
+
return {
|
|
186
|
+
message: `警告: 文件中有 ${consoleMatches.length} 个 console 语句,提交前请移除`
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
// 文件读取失败,静默处理
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return null
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Stop Hooks
|
|
199
|
+
|
|
200
|
+
**会话总结**
|
|
201
|
+
|
|
202
|
+
会话结束时生成进度总结:
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
// hooks/session-summary.cjs
|
|
206
|
+
module.exports = {
|
|
207
|
+
event: 'Stop',
|
|
208
|
+
action: async (context) => {
|
|
209
|
+
const summary = {
|
|
210
|
+
timestamp: new Date().toISOString(),
|
|
211
|
+
filesModified: context.modifiedFiles || [],
|
|
212
|
+
tasksCompleted: context.completedTasks || [],
|
|
213
|
+
pendingTasks: context.pendingTasks || []
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// 保存到会话日志
|
|
217
|
+
const logPath = '.claude/session-logs/latest.json'
|
|
218
|
+
fs.writeFileSync(logPath, JSON.stringify(summary, null, 2))
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
message: `会话已保存,修改了 ${summary.filesModified.length} 个文件`
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Hook 编写原则
|
|
228
|
+
|
|
229
|
+
### 1. 快速执行
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
Hook 不应阻塞主流程超过 2 秒
|
|
233
|
+
使用超时保护
|
|
234
|
+
异步操作不要等待
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### 2. 静默失败
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
Hook 失败不应中断主流程
|
|
241
|
+
记录错误但继续执行
|
|
242
|
+
提供有意义的错误信息
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### 3. 最小权限
|
|
246
|
+
|
|
247
|
+
```
|
|
248
|
+
只请求必要的权限
|
|
249
|
+
不修改不相关的文件
|
|
250
|
+
不执行危险命令
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### 4. 可配置
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
支持通过环境变量配置
|
|
257
|
+
允许禁用特定 hook
|
|
258
|
+
提供合理的默认值
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## 现有 Hooks 清单
|
|
262
|
+
|
|
263
|
+
当前项目 `.claude/hooks/` 已有:
|
|
264
|
+
|
|
265
|
+
| Hook | 功能 |
|
|
266
|
+
|------|------|
|
|
267
|
+
| code-formatter.cjs | 代码格式化 |
|
|
268
|
+
| multi-session.cjs | 多会话管理 |
|
|
269
|
+
| project-kickoff.cjs | 项目初始化 |
|
|
270
|
+
| rag-skill-loader.cjs | RAG 技能加载 |
|
|
271
|
+
| session-restore.cjs | 会话恢复 |
|
|
272
|
+
| session-save.cjs | 会话保存 |
|
|
273
|
+
| todo-manager.cjs | TODO 管理 |
|
|
274
|
+
| verify-work.cjs | 工作验证 |
|
|
275
|
+
|
|
276
|
+
## 调试 Hooks
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
# 启用 hook 调试日志
|
|
280
|
+
export CLAUDE_HOOK_DEBUG=true
|
|
281
|
+
|
|
282
|
+
# 查看 hook 执行日志
|
|
283
|
+
tail -f .claude/logs/hooks.log
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
**记住**:Hooks 是强大的自动化工具,但要谨慎使用。过多的 hooks 会影响性能,过于激进的 hooks 会干扰正常工作流程。
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Performance Rules
|
|
2
|
+
|
|
3
|
+
> 性能和资源管理规则
|
|
4
|
+
|
|
5
|
+
## 模型选择策略
|
|
6
|
+
|
|
7
|
+
根据任务复杂度选择合适的模型:
|
|
8
|
+
|
|
9
|
+
| 模型 | 适用场景 | 成本 |
|
|
10
|
+
|------|---------|------|
|
|
11
|
+
| **Haiku** | 简单任务、高频调用、轻量 agent | 最低 |
|
|
12
|
+
| **Sonnet** | 主要开发、代码生成、工作流编排 | 中等 |
|
|
13
|
+
| **Opus** | 复杂架构决策、深度推理、研究分析 | 最高 |
|
|
14
|
+
|
|
15
|
+
### 推荐配置
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Conductor → Sonnet (需要全局理解)
|
|
19
|
+
Architect → Opus (需要深度思考)
|
|
20
|
+
Builder → Sonnet (主要编码工作)
|
|
21
|
+
Reviewer → Opus (需要严谨分析)
|
|
22
|
+
Librarian → Haiku (文档整理)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Context Window 管理
|
|
26
|
+
|
|
27
|
+
**关键原则**:避免在 context 的最后 20% 进行复杂操作
|
|
28
|
+
|
|
29
|
+
### 高 Context 敏感任务(避免在 context 末尾)
|
|
30
|
+
- 大规模重构
|
|
31
|
+
- 跨多文件的功能实现
|
|
32
|
+
- 复杂交互调试
|
|
33
|
+
|
|
34
|
+
### 低 Context 敏感任务(可在任何时候)
|
|
35
|
+
- 单文件编辑
|
|
36
|
+
- 独立工具创建
|
|
37
|
+
- 文档更新
|
|
38
|
+
- 简单 bug 修复
|
|
39
|
+
|
|
40
|
+
## MCP 管理
|
|
41
|
+
|
|
42
|
+
**关键**:不要同时启用所有 MCP
|
|
43
|
+
|
|
44
|
+
- 200k context 可能被压缩到 70k
|
|
45
|
+
- 建议配置 20-30 个 MCP
|
|
46
|
+
- 每个项目启用不超过 10 个
|
|
47
|
+
- 活跃工具保持在 80 个以下
|
|
48
|
+
|
|
49
|
+
### 禁用不需要的 MCP
|
|
50
|
+
|
|
51
|
+
在项目 `settings.json` 中:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"disabledMcpServers": [
|
|
56
|
+
"unused-mcp-1",
|
|
57
|
+
"unused-mcp-2"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 构建故障排除
|
|
63
|
+
|
|
64
|
+
构建失败时:
|
|
65
|
+
|
|
66
|
+
1. 使用 **build-error-resolver** skill
|
|
67
|
+
2. 分析错误信息
|
|
68
|
+
3. 增量修复
|
|
69
|
+
4. 每次修复后验证
|
|
70
|
+
|
|
71
|
+
## 复杂任务策略
|
|
72
|
+
|
|
73
|
+
对于需要深度推理的任务:
|
|
74
|
+
|
|
75
|
+
1. 使用 `ultrathink` 模式增强思考
|
|
76
|
+
2. 启用 **Plan Mode** 进行结构化方案
|
|
77
|
+
3. 多轮自我批判优化
|
|
78
|
+
4. 使用分角色 sub-agents 进行多角度分析
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Security Rules
|
|
2
|
+
|
|
3
|
+
> 安全规则 - 所有提交必须遵守
|
|
4
|
+
|
|
5
|
+
## 提交前强制检查
|
|
6
|
+
|
|
7
|
+
每次提交代码前必须确认:
|
|
8
|
+
|
|
9
|
+
- [ ] **无硬编码密钥** - API keys, passwords, tokens 必须用环境变量
|
|
10
|
+
- [ ] **输入验证** - 所有用户输入已验证和清理
|
|
11
|
+
- [ ] **SQL 注入防护** - 使用参数化查询
|
|
12
|
+
- [ ] **XSS 防护** - HTML 输出已转义
|
|
13
|
+
- [ ] **CSRF 保护** - 表单提交有 token 验证
|
|
14
|
+
- [ ] **认证授权** - 敏感操作有权限检查
|
|
15
|
+
- [ ] **速率限制** - API 端点有请求限制
|
|
16
|
+
- [ ] **错误信息** - 不泄露敏感数据
|
|
17
|
+
|
|
18
|
+
## 密钥管理
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// ❌ 永远不要这样做
|
|
22
|
+
const apiKey = "sk-proj-xxxxx"
|
|
23
|
+
const password = "admin123"
|
|
24
|
+
|
|
25
|
+
// ✅ 正确方式
|
|
26
|
+
const apiKey = process.env.OPENAI_API_KEY
|
|
27
|
+
if (!apiKey) {
|
|
28
|
+
throw new Error('OPENAI_API_KEY not configured')
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 安全响应协议
|
|
33
|
+
|
|
34
|
+
发现安全问题时:
|
|
35
|
+
|
|
36
|
+
1. **立即停止** 当前工作
|
|
37
|
+
2. **调用** security-reviewer skill
|
|
38
|
+
3. **修复** CRITICAL 问题后才能继续
|
|
39
|
+
4. **轮换** 任何已暴露的密钥
|
|
40
|
+
5. **审查** 整个代码库是否有类似问题
|
|
41
|
+
|
|
42
|
+
## 敏感文件
|
|
43
|
+
|
|
44
|
+
以下文件永远不应提交:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
.env
|
|
48
|
+
.env.local
|
|
49
|
+
.env.production
|
|
50
|
+
*.pem
|
|
51
|
+
*.key
|
|
52
|
+
credentials.json
|
|
53
|
+
secrets.yaml
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
确保 `.gitignore` 包含这些模式。
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Testing Rules
|
|
2
|
+
|
|
3
|
+
> 测试规则 - 所有代码必须遵守
|
|
4
|
+
|
|
5
|
+
## 核心原则
|
|
6
|
+
|
|
7
|
+
**测试先于代码**:使用 TDD 工作流,先写测试再实现。
|
|
8
|
+
|
|
9
|
+
## 覆盖率要求
|
|
10
|
+
|
|
11
|
+
| 代码类型 | 最低覆盖率 |
|
|
12
|
+
|---------|-----------|
|
|
13
|
+
| 普通业务逻辑 | 80% |
|
|
14
|
+
| 金融计算 | 100% |
|
|
15
|
+
| 认证逻辑 | 100% |
|
|
16
|
+
| 安全相关代码 | 100% |
|
|
17
|
+
|
|
18
|
+
## 提交前检查
|
|
19
|
+
|
|
20
|
+
每次提交前必须:
|
|
21
|
+
|
|
22
|
+
- [ ] 所有测试通过
|
|
23
|
+
- [ ] 覆盖率达标(80%+)
|
|
24
|
+
- [ ] 新功能有单元测试
|
|
25
|
+
- [ ] API 有集成测试
|
|
26
|
+
- [ ] 关键流程有 E2E 测试
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# 提交前运行
|
|
30
|
+
npm test && npm run lint
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 测试类型要求
|
|
34
|
+
|
|
35
|
+
### 单元测试 (必须)
|
|
36
|
+
|
|
37
|
+
- 每个公共函数都有测试
|
|
38
|
+
- 测试边界情况(null, empty, max)
|
|
39
|
+
- 测试错误路径
|
|
40
|
+
|
|
41
|
+
### 集成测试 (必须)
|
|
42
|
+
|
|
43
|
+
- 每个 API 端点都有测试
|
|
44
|
+
- 测试正常响应和错误响应
|
|
45
|
+
- Mock 外部依赖
|
|
46
|
+
|
|
47
|
+
### E2E 测试 (关键流程)
|
|
48
|
+
|
|
49
|
+
- 登录/认证流程
|
|
50
|
+
- 核心业务流程
|
|
51
|
+
- 支付/金融流程
|
|
52
|
+
|
|
53
|
+
## 测试反模式 (禁止)
|
|
54
|
+
|
|
55
|
+
❌ **测试实现细节**
|
|
56
|
+
```typescript
|
|
57
|
+
// 不要测试内部状态
|
|
58
|
+
expect(component.state.count).toBe(5)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
❌ **测试相互依赖**
|
|
62
|
+
```typescript
|
|
63
|
+
// 每个测试必须独立
|
|
64
|
+
test('creates user', () => { ... })
|
|
65
|
+
test('updates same user', () => { ... }) // 依赖前一个
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
❌ **固定等待**
|
|
69
|
+
```typescript
|
|
70
|
+
// 不要用固定时间等待
|
|
71
|
+
await page.waitForTimeout(5000)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## CI 集成
|
|
75
|
+
|
|
76
|
+
CI 流水线必须:
|
|
77
|
+
|
|
78
|
+
1. 运行所有单元测试
|
|
79
|
+
2. 运行所有集成测试
|
|
80
|
+
3. 运行 E2E 测试(关键流程)
|
|
81
|
+
4. 检查覆盖率阈值
|
|
82
|
+
5. 上传测试报告
|
|
83
|
+
|
|
84
|
+
## 相关命令
|
|
85
|
+
|
|
86
|
+
- `/tdd` - 测试驱动开发流程
|
|
87
|
+
- `/e2e` - E2E 测试生成
|
|
88
|
+
- `/test` - 运行测试
|
|
89
|
+
- `/test-coverage` - 覆盖率分析
|
|
@@ -105,7 +105,25 @@
|
|
|
105
105
|
"WebFetch(domain:docs.bigmodel.cn)",
|
|
106
106
|
"WebFetch(domain:docs.z.ai)",
|
|
107
107
|
"Bash(CLAUDE_PROJECT_DIR=/Users/sumulige/Documents/Antigravity/talos node:*)",
|
|
108
|
-
"Bash(npm run test:coverage:*)"
|
|
108
|
+
"Bash(npm run test:coverage:*)",
|
|
109
|
+
"Bash(/opt/homebrew/bin/smc ultrathink)",
|
|
110
|
+
"Bash(fnm list:*)",
|
|
111
|
+
"Bash(zsh:*)",
|
|
112
|
+
"Bash(/opt/homebrew/bin/node:*)",
|
|
113
|
+
"mcp__zread__get_repo_structure",
|
|
114
|
+
"mcp__zread__search_doc",
|
|
115
|
+
"mcp__zread__read_file",
|
|
116
|
+
"Bash(printf:*)",
|
|
117
|
+
"Bash(export PATH=\"/opt/homebrew/bin:/usr/local/bin:$PATH\")",
|
|
118
|
+
"Bash(/usr/local/bin/node:*)",
|
|
119
|
+
"Bash(export PATH=\"/opt/homebrew/Cellar/node/25.3.0/bin:$PATH\")",
|
|
120
|
+
"Bash(/opt/homebrew/Cellar/node/25.3.0/bin/node --version)",
|
|
121
|
+
"Bash(/opt/homebrew/Cellar/node/25.3.0/bin/npm test)",
|
|
122
|
+
"Bash(/opt/homebrew/Cellar/node/25.3.0/bin/node -e \"const idx = require\\(''./.claude/rag/skill-index.json''\\); console.log\\(''Skills 数量:'', idx.skills.length\\); console.log\\(''\\\\n模型策略:''\\); idx.model_strategy.rules.forEach\\(r => console.log\\('' -'', r.pattern, ''→'', r.model, ''\\('' + r.reason + ''\\)''\\)\\);\")",
|
|
123
|
+
"Bash(/opt/homebrew/Cellar/node/25.3.0/bin/node -e \"const fs=require\\(''fs''\\); let d=''''; process.stdin.on\\(''data'',c=>d+=c\\); process.stdin.on\\(''end'',\\(\\)=>{const j=JSON.parse\\(d\\); console.log\\(''Skills:'', j.skills.length\\); console.log\\(''Model strategy:'', JSON.stringify\\(j.model_strategy, null, 2\\)\\);}\\)\")",
|
|
124
|
+
"Bash(/opt/homebrew/Cellar/node/25.3.0/bin/npm version 1.3.0 --no-git-tag-version)",
|
|
125
|
+
"Bash(git tag:*)",
|
|
126
|
+
"Bash(/opt/homebrew/Cellar/node/25.3.0/bin/npm publish)"
|
|
109
127
|
]
|
|
110
128
|
},
|
|
111
129
|
"hooks": {
|