@andyqiu/codeforge 0.3.14 → 0.5.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/README.md +12 -8
- package/agents/codeforge.md +109 -64
- package/agents/coder-deep.md +41 -28
- package/agents/coder-quick.md +41 -28
- package/agents/coder.md +28 -28
- package/agents/planner.md +10 -7
- package/agents/reviewer-lite.md +248 -0
- package/agents/reviewer.md +177 -42
- package/bin/codeforge.mjs +4 -1
- package/commands/discard-session.md +63 -0
- package/commands/merge.md +80 -0
- package/dist/index.js +3631 -2238
- package/install.ps1 +8 -7
- package/install.sh +7 -6
- package/package.json +2 -1
- package/review-profiles/adr.md +72 -0
- package/review-profiles/code-c.md +46 -0
- package/review-profiles/code-csharp-lua-c.md +73 -0
- package/review-profiles/code-csharp.md +41 -0
- package/review-profiles/code-lua.md +42 -0
- package/review-profiles/code-python.md +43 -0
- package/review-profiles/code-typescript.md +45 -0
- package/review-profiles/code.md +51 -0
- package/review-profiles/decision-only.md +61 -0
- package/review-profiles/docs.md +46 -0
- package/review-profiles/plan-only.md +67 -0
- package/workflows/feature-dev.yaml +37 -7
package/install.ps1
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
2. 把 dist/index.js 复制到 ~/.config/opencode/codeforge/index.js
|
|
14
14
|
3. 在 ~/.config/opencode/opencode.json 的 "plugin" 数组追加 file:// URL
|
|
15
15
|
4. 把 agents/commands 用 file-by-file copy 注入(带白名单)
|
|
16
|
-
5. 把 workflows/context-templates 拷贝过去
|
|
16
|
+
5. 把 workflows/context-templates/review-profiles 拷贝过去
|
|
17
17
|
5b. 把 skills/ 目录拷贝到 $TargetRoot/skills/(与 install.sh 对称)
|
|
18
18
|
6. 智能合并 AGENTS.md:
|
|
19
19
|
- 项目模式 + 已有 AGENTS.md → 替换 <!-- knowledge-hub:start -->...<!-- knowledge-hub:end --> 块(带 .bak 备份)
|
|
@@ -87,8 +87,8 @@ $CodeforgeCfgDir = Join-Path $XdgConfigBase 'codeforge'
|
|
|
87
87
|
|
|
88
88
|
# v0.1 之前 install.ps1 装的目录(卸载时一并清掉)
|
|
89
89
|
$LegacyDirs = @('agent', 'command', 'tool', 'tools', 'plugin', 'plugins', 'lib')
|
|
90
|
-
# v0.1+
|
|
91
|
-
$ManagedDirs = @('codeforge', 'agents', 'commands', 'workflows', 'context-templates')
|
|
90
|
+
# v0.1+ 才有的目录(review-profiles 由 ADR:reviewer-multi-profile 引入)
|
|
91
|
+
$ManagedDirs = @('codeforge', 'agents', 'commands', 'workflows', 'context-templates', 'review-profiles')
|
|
92
92
|
|
|
93
93
|
# v0.1+ 文件分发计划
|
|
94
94
|
$BundleSrcRel = 'dist/index.js'
|
|
@@ -102,10 +102,11 @@ $MdCopyMap = @(
|
|
|
102
102
|
@{ Src='agents'; Dst='agents' },
|
|
103
103
|
@{ Src='commands'; Dst='commands' }
|
|
104
104
|
)
|
|
105
|
-
# 普通整目录 copy
|
|
105
|
+
# 普通整目录 copy(review-profiles 由 ADR:reviewer-multi-profile 引入)
|
|
106
106
|
$CopyMap = @(
|
|
107
107
|
@{ Src='workflows'; Dst='workflows' },
|
|
108
|
-
@{ Src='context-templates'; Dst='context-templates' }
|
|
108
|
+
@{ Src='context-templates'; Dst='context-templates' },
|
|
109
|
+
@{ Src='review-profiles'; Dst='review-profiles' }
|
|
109
110
|
)
|
|
110
111
|
|
|
111
112
|
# ────────────── opencode.json 管理 ──────────────
|
|
@@ -430,8 +431,8 @@ if (-not $DryRun) {
|
|
|
430
431
|
}
|
|
431
432
|
Write-Ok "VERSION -> $versionFile ($cfVersion)"
|
|
432
433
|
|
|
433
|
-
# Step 5/7: 装 agents / commands / workflows / context-templates
|
|
434
|
-
Write-Section 'Step 5/7: 装 agents / commands / workflows / context-templates'
|
|
434
|
+
# Step 5/7: 装 agents / commands / workflows / context-templates / review-profiles
|
|
435
|
+
Write-Section 'Step 5/7: 装 agents / commands / workflows / context-templates / review-profiles'
|
|
435
436
|
foreach ($entry in $MdCopyMap) {
|
|
436
437
|
$src = Join-Path $SourceRoot $entry.Src
|
|
437
438
|
$dst = Join-Path $TargetRoot $entry.Dst
|
package/install.sh
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# 3. 把 dist/index.js 复制到 ~/.config/opencode/codeforge/index.js
|
|
14
14
|
# 4. 在 ~/.config/opencode/opencode.json 的 "plugin" 数组追加 file:// URL
|
|
15
15
|
# 5. 把 agents/commands 用 file-by-file copy 注入(带白名单)
|
|
16
|
-
# 6. 把 workflows/context-templates 整目录拷贝
|
|
16
|
+
# 6. 把 workflows/context-templates/review-profiles 整目录拷贝
|
|
17
17
|
# 7. 智能合并 AGENTS.md:
|
|
18
18
|
# - 项目模式 + 已有 AGENTS.md → 替换 <!-- knowledge-hub:start -->...<!-- knowledge-hub:end --> 块(带 .bak 备份)
|
|
19
19
|
# - 项目模式 + 无 AGENTS.md → 生成含 marker 块的短版骨架
|
|
@@ -117,15 +117,16 @@ CODEFORGE_CFG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/codeforge"
|
|
|
117
117
|
|
|
118
118
|
# v0.1 之前装的目录(卸载时一并清掉)
|
|
119
119
|
LEGACY_DIRS=(agent command tool tools plugin plugins lib)
|
|
120
|
-
# v0.1+
|
|
121
|
-
MANAGED_DIRS=(codeforge agents commands workflows context-templates)
|
|
120
|
+
# v0.1+ 才有的目录(review-profiles 由 ADR:reviewer-multi-profile 引入)
|
|
121
|
+
MANAGED_DIRS=(codeforge agents commands workflows context-templates review-profiles)
|
|
122
122
|
|
|
123
123
|
BUNDLE_SRC_REL="dist/index.js"
|
|
124
124
|
BUNDLE_DST_REL="codeforge/index.js"
|
|
125
125
|
|
|
126
126
|
# 文件级 copy 白名单(.md,排除 README/_*/.bak/.*)
|
|
127
127
|
MD_COPY_DIRS=("agents:agents" "commands:commands")
|
|
128
|
-
|
|
128
|
+
# 整目录拷贝(review-profiles 由 ADR:reviewer-multi-profile 引入,避开 maxdepth 1 限制)
|
|
129
|
+
COPY_DIRS=("workflows:workflows" "context-templates:context-templates" "review-profiles:review-profiles")
|
|
129
130
|
|
|
130
131
|
# KH 行为规范模板(B3 智能合并的输入)
|
|
131
132
|
KH_TEMPLATE_REL="context-templates/kh-instructions.md"
|
|
@@ -499,8 +500,8 @@ if [[ $DRY_RUN -eq 0 ]]; then
|
|
|
499
500
|
fi
|
|
500
501
|
ok "VERSION → ${VERSION_FILE} (${CF_VERSION})"
|
|
501
502
|
|
|
502
|
-
# Step 5/8: 装 agents / commands / workflows / context-templates
|
|
503
|
-
log "Step 5/8: 装 agents / commands / workflows / context-templates"
|
|
503
|
+
# Step 5/8: 装 agents / commands / workflows / context-templates / review-profiles
|
|
504
|
+
log "Step 5/8: 装 agents / commands / workflows / context-templates / review-profiles"
|
|
504
505
|
for entry in "${MD_COPY_DIRS[@]}"; do
|
|
505
506
|
src_name="${entry%%:*}"; dst_name="${entry##*:}"
|
|
506
507
|
src_path="$SOURCE_ROOT/$src_name"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andyqiu/codeforge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "CodeForge — opencode 的零侵入扩展包",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -121,6 +121,7 @@
|
|
|
121
121
|
"workflows/",
|
|
122
122
|
"context-templates/",
|
|
123
123
|
"skills/",
|
|
124
|
+
"review-profiles/",
|
|
124
125
|
"scripts/check-bun.mjs",
|
|
125
126
|
"scripts/merge-agents-md.mjs",
|
|
126
127
|
"scripts/sync-agent-models.mjs",
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Review Profile: adr(ADR 决策记录审阅)
|
|
2
|
+
|
|
3
|
+
<!-- ADR:reviewer-multi-profile -->
|
|
4
|
+
|
|
5
|
+
> 适用:`review_target=adr`,审 `docs/adr/<slug>.md` 类决策文档。
|
|
6
|
+
> 本 profile **替代**通用 code.md 清单。
|
|
7
|
+
|
|
8
|
+
## 适用场景
|
|
9
|
+
|
|
10
|
+
- planner 新写 ADR + stage 进 pending,codeforge 派 reviewer 审
|
|
11
|
+
- 用户手动 `/review adr` 审某个 ADR PR
|
|
12
|
+
- workflow 含「新增/修改 ADR 时自动派 adr review」步骤
|
|
13
|
+
|
|
14
|
+
**不审什么**:不审引用 ADR 的代码改动(那是 `code` profile 的事)。
|
|
15
|
+
|
|
16
|
+
## 审阅维度(按优先级,逐项过)
|
|
17
|
+
|
|
18
|
+
| # | 维度 | 权重 | 检查 | 反例(必拒) |
|
|
19
|
+
|---|---|---|---|---|
|
|
20
|
+
| 1 | 问题陈述清晰度 | P0 | Context 段是否清晰描述「**为什么**需要这个决策」?当前痛点 / 触发场景是否具体? | Context 只写「需要更好的 X」无具体痛点 |
|
|
21
|
+
| 2 | 备选方案完备性 | P0 | Options Considered 是否至少列了 **2 个备选**(含 status quo「不改」)?每个备选是否有优缺点? | 只写一个选项就 Decision;备选只写名字没分析 |
|
|
22
|
+
| 3 | 决策论证 | P0 | 选定方案的理由是否基于**具体 tradeoff** 而非主观偏好?是否引用了数据 / 实验 / 参考资料? | 写「选 A 因为感觉更优雅」 |
|
|
23
|
+
| 4 | 三向引用完整性 | P0 | frontmatter `code-refs` 是否列出受影响的代码文件(不能 `[TBD]`,除非确实尚未实现)?`prd-refs` 是否引用 PRD 章节或显式注明「无对应 PRD」?`related` 是否引用上下游 ADR?`tests` 是否列出至少 1 个测试文件或显式 `[TBD]`? | 新 ADR 没 code-refs;改了 X 模块但 code-refs 不含 X;prd-refs 留 `[TBD]` 却已实施 |
|
|
24
|
+
| 5 | 后续行动 | P1 | Consequences 段是否列了**正面 + 负面**后果?是否有 follow-up 任务(Phase 拆分 / 待评估窗口)? | 只写正面没负面;没列 follow-up |
|
|
25
|
+
| 6 | 状态合法性 | P1 | `status` 是否合法(Proposed / Implementing / Accepted / Superseded / Deprecated / Rejected)?Superseded 是否填了 `superseded-by`?slug 命名是否符合 `docs/adr/README.md` 规范(kebab-slug,无数字前缀)? | status 写「Done」(非法);Superseded 没填新 slug;新 ADR 用了 `NNNN-` 前缀 |
|
|
26
|
+
| 7 | ADR 冲突检测 | P1 | 新 ADR 是否与现有 ADR 冲突未声明(应在 `supersedes` 或 Decision 段说明)?是否会让某条铁律失效? | 新 ADR 与 ADR:apply-hard-gate 冲突但 supersedes 为空 |
|
|
27
|
+
|
|
28
|
+
## 强制章节检查(按 `docs/adr/template.md`)
|
|
29
|
+
|
|
30
|
+
- [ ] frontmatter 含 `title` / `status` / `date` / `deciders` / `code-refs`(5 个必填字段)
|
|
31
|
+
- [ ] frontmatter 含 `layer`(principle / architecture / implementation / process / meta 之一)
|
|
32
|
+
- [ ] `## Context` 存在且 ≥ 3 行
|
|
33
|
+
- [ ] `## Options Considered` ≥ 2 个选项
|
|
34
|
+
- [ ] `## Decision` 段含「选哪个 + 理由」
|
|
35
|
+
- [ ] `## Consequences` 含正面 + 负面 + 后续行动
|
|
36
|
+
- [ ] `## References` 段(推荐但非强制)
|
|
37
|
+
|
|
38
|
+
## 三向引用机审清单(必跑)
|
|
39
|
+
|
|
40
|
+
针对 frontmatter,逐字段核对:
|
|
41
|
+
|
|
42
|
+
1. **code-refs**:对每个列出的代码路径,跑 `test -e <path>` 校验存在。任一不存在 → REQUEST_CHANGES,提示「code-refs 中 X 不存在,确认是否文件重命名 / 路径漂移」
|
|
43
|
+
2. **prd-refs**:每个 `§N.N` 章节号在 `docs/PRD.md` 是否找得到(grep `^## .*<sectionId>` 或类似);找不到 → 提醒补
|
|
44
|
+
3. **related + related-types**:两数组等长;types 用合法值(`implements` / `depends-on` 等)
|
|
45
|
+
4. **supersedes / superseded-by**:被 supersedes 的 ADR 是否同步加了 `superseded-by`(双向闭合)
|
|
46
|
+
5. **tests**:列出的测试路径存在(与 code-refs 同样校验)
|
|
47
|
+
|
|
48
|
+
## 输出格式调整
|
|
49
|
+
|
|
50
|
+
`## File-by-File` 改为「ADR 段-by-段」:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
## 段-by-段
|
|
54
|
+
|
|
55
|
+
### frontmatter
|
|
56
|
+
- ✗ `code-refs` 缺失:本 ADR 涉及 lib/x.ts 应列出
|
|
57
|
+
- ⚠ `prd-refs` 留 `[TBD]` 但 status=Accepted,应回填具体章节
|
|
58
|
+
|
|
59
|
+
### `## Options Considered`
|
|
60
|
+
- ⚠ 只有 2 个选项,建议补 status quo(保留现状)作为第 3 选项
|
|
61
|
+
|
|
62
|
+
### `## Decision`
|
|
63
|
+
- ✓ 引用了 ADR-Y 的关联决策
|
|
64
|
+
|
|
65
|
+
### `## Consequences`
|
|
66
|
+
- ✗ 只有正面,缺负面 / 代价段
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## 失败回退
|
|
70
|
+
|
|
71
|
+
- pending 不含 `docs/adr/*.md` → 报「未找到 ADR 文件」
|
|
72
|
+
- ADR 是 typo 级修改(仅改 status Proposed → Accepted)→ APPROVE + 备注「仅状态变更,简审通过」
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Review Profile: code:c(C / C++ 专项)
|
|
2
|
+
|
|
3
|
+
<!-- ADR:reviewer-multi-profile -->
|
|
4
|
+
|
|
5
|
+
> 适用:`review_target=code:c` 或检测到 `.c` / `.cpp` / `.cc` / `.cxx` / `.h` / `.hpp` 文件时**追加加载**。
|
|
6
|
+
> 本 profile 是通用 `code.md` 的**补充**(不替代),需先加载 `code.md` 的 8 维度清单。
|
|
7
|
+
>
|
|
8
|
+
> ⚠ **编号与 C# profile 的区分**:本文件用 `[C#N]`(C 语言),C# profile 用 `[CS#N]`(多了 S);视觉相近但归属不同,标注时注意。
|
|
9
|
+
|
|
10
|
+
## 适用场景
|
|
11
|
+
|
|
12
|
+
- 系统编程(用户态守护进程 / CLI 工具 / 系统库)
|
|
13
|
+
- 嵌入式(裸机 / RTOS / FreeRTOS / Zephyr)
|
|
14
|
+
- C/C++ 库开发(含 ABI 稳定性要求场景)
|
|
15
|
+
- 内核驱动 / 内核模块
|
|
16
|
+
- 跨语言 native 扩展(Lua C API / Python C API / Node native addon)
|
|
17
|
+
|
|
18
|
+
## C / C++ 特有陷阱(适用 `.c` / `.cpp` / `.cc` / `.cxx` / `.h` / `.hpp`)
|
|
19
|
+
|
|
20
|
+
| # | 陷阱 | 等级 | 反例 | 正确写法 |
|
|
21
|
+
|---|---|---|---|---|
|
|
22
|
+
| C#1 | 缓冲区溢出风险函数 | ✗ | `strcpy(dst, src)` / `gets(buf)` / `sprintf` 无长度限 | `strncpy` / `fgets` / `snprintf` |
|
|
23
|
+
| C#2 | 未检查 `malloc` 返回值 | ✗ | `p = malloc(n); *p = 0;` p 可能为 NULL | `p = malloc(n); if (!p) return -1; *p = 0;` |
|
|
24
|
+
| C#3 | 整数溢出 | ⚠ | `int n = a + b;` a/b 接近 INT_MAX | 用 `size_t` 或显式范围检查 `if (a > INT_MAX - b)` |
|
|
25
|
+
| C#4 | use-after-free | ✗ | `free(p); printf("%s", p);` | `free(p); p = NULL;` 之后任何访问立刻段错误 |
|
|
26
|
+
| C#5 | 内存泄漏(错误分支未 free) | ✗ | `p = malloc(...); if (err) return -1;` 漏 free | 统一在 cleanup label 释放,或用 RAII(C++) |
|
|
27
|
+
| C#6 | C++ raw pointer 替代 smart pointer | ⚠ | `User* u = new User();` | `auto u = std::make_unique<User>();` |
|
|
28
|
+
| C#7 | 格式化字符串漏洞 | ✗ | `printf(user_input);` | `printf("%s", user_input);` |
|
|
29
|
+
| C#8 | C++ 拷贝构造未实现 rule of three/five | ⚠ | 类含 raw pointer 未定义 copy ctor / op= / dtor | 三定律齐全,或 `=delete` 禁用拷贝 |
|
|
30
|
+
|
|
31
|
+
## 与通用清单的协同
|
|
32
|
+
|
|
33
|
+
- 通用 #3 安全:额外检查格式化字符串漏洞 + 整数符号扩展 + TOCTOU 文件竞态
|
|
34
|
+
- 通用 #6 测试:检查 CMocka / Unity(C)/ GoogleTest / Catch2(C++)覆盖
|
|
35
|
+
- 通用 #4 性能:注意 cache line / false sharing;嵌入式注意栈深度与中断上下文长度
|
|
36
|
+
|
|
37
|
+
## 输出格式调整
|
|
38
|
+
|
|
39
|
+
`## File-by-File` 标注命中编号 `[C#x]`(注意与 C# profile 的 `[CS#x]` 区分):
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
### `src/parser.c`
|
|
43
|
+
- ✗ Line 78 [C#1 strcpy]: `strcpy(buf, input)` 应改为 `snprintf(buf, sizeof(buf), "%s", input)`
|
|
44
|
+
- ✗ Line 102 [C#4 use-after-free]: `free(node); return node->next;` 应在 free 前保存 next
|
|
45
|
+
- ⚠ Line 145 [C#3 整数溢出]: `int len = a + b;` a/b 来自外部输入,应改为 `size_t` 并先校验
|
|
46
|
+
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Review Profile: code:csharp-lua-c(C# / Lua / C 专项)
|
|
2
|
+
|
|
3
|
+
> ⚠ **已废弃**:本文件已拆分为 `code-csharp.md` / `code-lua.md` / `code-c.md`,此文件保留作历史参考,不再维护。新代码请按文件扩展名自动加载三个独立 profile(详见 `agents/reviewer.md` 语言映射表)。
|
|
4
|
+
|
|
5
|
+
<!-- ADR:reviewer-multi-profile -->
|
|
6
|
+
|
|
7
|
+
> 适用:`review_target=code:csharp-lua-c` 或检测到 `.cs` / `.lua` / `.c` / `.cpp` / `.cc` / `.cxx` / `.h` / `.hpp` 文件时**追加加载**。
|
|
8
|
+
> 本 profile 是通用 `code.md` 的**补充**(不替代),需先加载 `code.md` 的 8 维度清单。
|
|
9
|
+
> **注意**:三种语言风格差异大,本 profile 按语言分段,按文件扩展名匹配对应段。
|
|
10
|
+
|
|
11
|
+
## 适用场景
|
|
12
|
+
|
|
13
|
+
- C# 项目(Unity / .NET / Mono / ASP.NET / Blazor)
|
|
14
|
+
- Lua 脚本(Roblox / 游戏脚本 / Neovim 插件 / OpenResty)
|
|
15
|
+
- C / C++ 项目(系统编程 / 嵌入式 / 库 / 内核驱动)
|
|
16
|
+
|
|
17
|
+
## C# 特有陷阱(适用 `.cs`)
|
|
18
|
+
|
|
19
|
+
| # | 陷阱 | 等级 | 反例 | 正确写法 |
|
|
20
|
+
|---|---|---|---|---|
|
|
21
|
+
| CS#1 | `async void` 方法(异常无法捕获) | ✗ | `async void OnClick()` 非事件 handler | `async Task OnClickAsync()`;事件 handler 内 try/catch 全包 |
|
|
22
|
+
| CS#2 | 引用类型未检查 null | ✗ | `user.Name.ToLower()` | `user?.Name?.ToLower()` 或启用 nullable reference types `string?` |
|
|
23
|
+
| CS#3 | LINQ 懒求值陷阱(多次 enumerate) | ⚠ | `var q = list.Where(p); q.Count(); q.ToList();` 跑两次 | `var q = list.Where(p).ToList();` 一次物化 |
|
|
24
|
+
| CS#4 | `using` 块外用 disposable | ✗ | `var conn = new SqlConnection(...); ...` 不在 using 内 | `using var conn = new SqlConnection(...)` |
|
|
25
|
+
| CS#5 | `.Result` / `.Wait()` 同步等异步(死锁风险) | ✗ | `var data = FetchAsync().Result;` | `var data = await FetchAsync();` |
|
|
26
|
+
| CS#6 | `Dictionary[key]` 未先 `TryGetValue` | ⚠ | `var v = dict[key];` key 不存在则抛 | `if (dict.TryGetValue(key, out var v)) { ... }` |
|
|
27
|
+
| CS#7 | 在 `foreach` 内修改集合 | ✗ | `foreach (var x in list) list.Remove(x)` | 用 `for (int i = list.Count - 1; i >= 0; i--)` 倒序删 |
|
|
28
|
+
|
|
29
|
+
## Lua 特有陷阱(适用 `.lua`)
|
|
30
|
+
|
|
31
|
+
| # | 陷阱 | 等级 | 反例 | 正确写法 |
|
|
32
|
+
|---|---|---|---|---|
|
|
33
|
+
| L#1 | 全局变量污染(未用 `local`) | ✗ | `x = 10` 顶层赋值 | `local x = 10`;模块全 local |
|
|
34
|
+
| L#2 | table 索引从 1 开始却混用 0 | ✗ | `t[0] = "a"; t[1] = "b"` 然后 `#t` 行为不定 | 索引一律从 1 开始 |
|
|
35
|
+
| L#3 | `#` 操作符在非序列 table 上 | ⚠ | `t = {[1]=1, [3]=3}; print(#t)` 结果不确定 | 自己维护 length 字段或保持纯序列 table |
|
|
36
|
+
| L#4 | 闭包捕获循环变量(部分 Lua 版本变量共享) | ⚠ | `for i = 1, 10 do funcs[i] = function() return i end end` | 用 `local _i = i` 隔离 |
|
|
37
|
+
| L#5 | `require` 路径硬编码 | ⚠ | `require("foo.bar.baz")` 在 package.path 里没配 | 检查 `package.path` 兼容性,或动态拼路径 |
|
|
38
|
+
| L#6 | pcall 后忽略 err 信息 | ⚠ | `pcall(f)` 不接 `ok, err = pcall(f)` | `local ok, err = pcall(f); if not ok then log(err) end` |
|
|
39
|
+
| L#7 | 非整数键破坏序列语义(risk: medium)<br>规则:避免用浮点或非整数值作 table 序列索引<br>反例:`t[tonumber(userInput)] = "x"`(若 userInput 为 "1.5",破坏 # 运算符语义)<br>正例:`assert(math.type(idx) == "integer"); t[idx] = "x"` | ⚠ | 见反例 | 见正例 |
|
|
40
|
+
|
|
41
|
+
## C / C++ 特有陷阱(适用 `.c` / `.cpp` / `.cc` / `.cxx` / `.h` / `.hpp`)
|
|
42
|
+
|
|
43
|
+
| # | 陷阱 | 等级 | 反例 | 正确写法 |
|
|
44
|
+
|---|---|---|---|---|
|
|
45
|
+
| K#1 | 缓冲区溢出风险函数 | ✗ | `strcpy(dst, src)` / `gets(buf)` / `sprintf` 无长度限 | `strncpy` / `fgets` / `snprintf` |
|
|
46
|
+
| K#2 | 未检查 `malloc` 返回值 | ✗ | `p = malloc(n); *p = 0;` p 可能为 NULL | `p = malloc(n); if (!p) return -1; *p = 0;` |
|
|
47
|
+
| K#3 | 整数溢出 | ⚠ | `int n = a + b;` a/b 接近 INT_MAX | 用 `size_t` 或显式范围检查 `if (a > INT_MAX - b)` |
|
|
48
|
+
| K#4 | use-after-free | ✗ | `free(p); printf("%s", p);` | `free(p); p = NULL;` 之后任何访问立刻段错误 |
|
|
49
|
+
| K#5 | 内存泄漏(错误分支未 free) | ✗ | `p = malloc(...); if (err) return -1;` 漏 free | 统一在 cleanup label 释放,或用 RAII(C++) |
|
|
50
|
+
| K#6 | C++ raw pointer 替代 smart pointer | ⚠ | `User* u = new User();` | `auto u = std::make_unique<User>();` |
|
|
51
|
+
| K#7 | 格式化字符串漏洞 | ✗ | `printf(user_input);` | `printf("%s", user_input);` |
|
|
52
|
+
| K#8 | C++ 拷贝构造未实现 rule of three/five | ⚠ | 类含 raw pointer 未定义 copy ctor / op= / dtor | 三定律齐全,或 `=delete` 禁用拷贝 |
|
|
53
|
+
|
|
54
|
+
## 与通用清单的协同
|
|
55
|
+
|
|
56
|
+
- 通用 #3 安全:C/C++ 项目额外检查格式化字符串漏洞 + 整数符号扩展;C# 检查反序列化(`BinaryFormatter` 已弃用)
|
|
57
|
+
- 通用 #6 测试:Lua 项目检查 busted 测试覆盖;C 项目检查 CMocka / Unity;C# 检查 xUnit/NUnit
|
|
58
|
+
|
|
59
|
+
## 输出格式调整
|
|
60
|
+
|
|
61
|
+
`## File-by-File` 标注命中编号(C#: `[CS#x]` / Lua: `[L#x]` / C: `[K#x]`):
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
### `path/handler.cs`
|
|
65
|
+
- ✗ Line 22 [CS#1 async void]: `async void OnRequest` 应改为 `async Task OnRequestAsync`
|
|
66
|
+
- ⚠ Line 55 [CS#3 LINQ 多次 enumerate]: 建议 `.ToList()` 物化
|
|
67
|
+
|
|
68
|
+
### `scripts/init.lua`
|
|
69
|
+
- ✗ Line 3 [L#1 全局变量]: `config = {}` 应改为 `local config = {}`
|
|
70
|
+
|
|
71
|
+
### `src/parser.c`
|
|
72
|
+
- ✗ Line 78 [K#1 strcpy]: `strcpy(buf, input)` 应改为 `snprintf(buf, sizeof(buf), "%s", input)`
|
|
73
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Review Profile: code:csharp(C# 专项)
|
|
2
|
+
|
|
3
|
+
<!-- ADR:reviewer-multi-profile -->
|
|
4
|
+
|
|
5
|
+
> 适用:`review_target=code:csharp` 或检测到 `.cs` 文件时**追加加载**。
|
|
6
|
+
> 本 profile 是通用 `code.md` 的**补充**(不替代),需先加载 `code.md` 的 8 维度清单。
|
|
7
|
+
|
|
8
|
+
## 适用场景
|
|
9
|
+
|
|
10
|
+
- Unity(含 IL2CPP / Mono 后端)
|
|
11
|
+
- .NET / .NET Framework / Mono 桌面与服务端
|
|
12
|
+
- ASP.NET / ASP.NET Core / Blazor Web 应用
|
|
13
|
+
- Xamarin / MAUI 移动端
|
|
14
|
+
|
|
15
|
+
## C# 特有陷阱(适用 `.cs`)
|
|
16
|
+
|
|
17
|
+
| # | 陷阱 | 等级 | 反例 | 正确写法 |
|
|
18
|
+
|---|---|---|---|---|
|
|
19
|
+
| CS#1 | `async void` 方法(异常无法捕获) | ✗ | `async void OnClick()` 非事件 handler | `async Task OnClickAsync()`;事件 handler 内 try/catch 全包 |
|
|
20
|
+
| CS#2 | 引用类型未检查 null | ✗ | `user.Name.ToLower()` | `user?.Name?.ToLower()` 或启用 nullable reference types `string?` |
|
|
21
|
+
| CS#3 | LINQ 懒求值陷阱(多次 enumerate) | ⚠ | `var q = list.Where(p); q.Count(); q.ToList();` 跑两次 | `var q = list.Where(p).ToList();` 一次物化 |
|
|
22
|
+
| CS#4 | `using` 块外用 disposable | ✗ | `var conn = new SqlConnection(...); ...` 不在 using 内 | `using var conn = new SqlConnection(...)` |
|
|
23
|
+
| CS#5 | `.Result` / `.Wait()` 同步等异步(死锁风险) | ✗ | `var data = FetchAsync().Result;` | `var data = await FetchAsync();` |
|
|
24
|
+
| CS#6 | `Dictionary[key]` 未先 `TryGetValue` | ⚠ | `var v = dict[key];` key 不存在则抛 | `if (dict.TryGetValue(key, out var v)) { ... }` |
|
|
25
|
+
| CS#7 | 在 `foreach` 内修改集合 | ✗ | `foreach (var x in list) list.Remove(x)` | 用 `for (int i = list.Count - 1; i >= 0; i--)` 倒序删 |
|
|
26
|
+
|
|
27
|
+
## 与通用清单的协同
|
|
28
|
+
|
|
29
|
+
- 通用 #3 安全:检查反序列化漏洞(`BinaryFormatter` 已弃用,改用 `System.Text.Json` / `DataContractSerializer`)
|
|
30
|
+
- 通用 #6 测试:检查 xUnit / NUnit / MSTest 覆盖,Theory + InlineData 优于多个相似 Fact
|
|
31
|
+
|
|
32
|
+
## 输出格式调整
|
|
33
|
+
|
|
34
|
+
`## File-by-File` 标注命中编号 `[CS#x]`:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
### `path/handler.cs`
|
|
38
|
+
- ✗ Line 22 [CS#1 async void]: `async void OnRequest` 应改为 `async Task OnRequestAsync`
|
|
39
|
+
- ⚠ Line 55 [CS#3 LINQ 多次 enumerate]: 建议 `.ToList()` 物化
|
|
40
|
+
- ✗ Line 88 [CS#5 .Result 死锁]: `FetchAsync().Result` 应改为 `await FetchAsync()`
|
|
41
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Review Profile: code:lua(Lua 专项)
|
|
2
|
+
|
|
3
|
+
<!-- ADR:reviewer-multi-profile -->
|
|
4
|
+
|
|
5
|
+
> 适用:`review_target=code:lua` 或检测到 `.lua` 文件时**追加加载**。
|
|
6
|
+
> 本 profile 是通用 `code.md` 的**补充**(不替代),需先加载 `code.md` 的 8 维度清单。
|
|
7
|
+
|
|
8
|
+
## 适用场景
|
|
9
|
+
|
|
10
|
+
- Roblox 游戏脚本(Luau)
|
|
11
|
+
- 通用游戏脚本(Defold / Love2D / Solar2D / Cocos2d-x)
|
|
12
|
+
- Neovim 插件 / 配置脚本
|
|
13
|
+
- OpenResty / Nginx Lua 模块
|
|
14
|
+
- 服务端 Lua(Skynet / 业务嵌入)
|
|
15
|
+
|
|
16
|
+
## Lua 特有陷阱(适用 `.lua`)
|
|
17
|
+
|
|
18
|
+
| # | 陷阱 | 等级 | 反例 | 正确写法 |
|
|
19
|
+
|---|---|---|---|---|
|
|
20
|
+
| L#1 | 全局变量污染(未用 `local`) | ✗ | `x = 10` 顶层赋值 | `local x = 10`;模块全 local |
|
|
21
|
+
| L#2 | table 索引从 1 开始却混用 0 | ✗ | `t[0] = "a"; t[1] = "b"` 然后 `#t` 行为不定 | 索引一律从 1 开始 |
|
|
22
|
+
| L#3 | `#` 操作符在非序列 table 上 | ⚠ | `t = {[1]=1, [3]=3}; print(#t)` 结果不确定 | 自己维护 length 字段或保持纯序列 table |
|
|
23
|
+
| L#4 | 闭包捕获循环变量(部分 Lua 版本变量共享) | ⚠ | `for i = 1, 10 do funcs[i] = function() return i end end` | 用 `local _i = i` 隔离 |
|
|
24
|
+
| L#5 | `require` 路径硬编码 | ⚠ | `require("foo.bar.baz")` 在 package.path 里没配 | 检查 `package.path` 兼容性,或动态拼路径 |
|
|
25
|
+
| L#6 | pcall 后忽略 err 信息 | ⚠ | `pcall(f)` 不接 `ok, err = pcall(f)` | `local ok, err = pcall(f); if not ok then log(err) end` |
|
|
26
|
+
| L#7 | 非整数键破坏序列语义(risk: medium)<br>规则:避免用浮点或非整数值作 table 序列索引<br>反例:`t[tonumber(userInput)] = "x"`(若 userInput 为 "1.5",破坏 # 运算符语义)<br>正例:`assert(math.type(idx) == "integer"); t[idx] = "x"` | ⚠ | 见反例 | 见正例 |
|
|
27
|
+
|
|
28
|
+
## 与通用清单的协同
|
|
29
|
+
|
|
30
|
+
- 通用 #3 安全:OpenResty / 嵌入 Lua 检查 `loadstring` / `load` 注入风险;用户输入禁止直接 `load`
|
|
31
|
+
- 通用 #6 测试:检查 busted / luaunit 覆盖;Roblox 项目检查 TestEZ
|
|
32
|
+
- 通用 #4 性能:游戏脚本注意 `__index` 链路过深、热路径 table 频繁创建(GC 压力)
|
|
33
|
+
|
|
34
|
+
## 输出格式调整
|
|
35
|
+
|
|
36
|
+
`## File-by-File` 标注命中编号 `[L#x]`:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
### `scripts/init.lua`
|
|
40
|
+
- ✗ Line 3 [L#1 全局变量]: `config = {}` 应改为 `local config = {}`
|
|
41
|
+
- ⚠ Line 27 [L#6 pcall 忽略 err]: `pcall(handler)` 应改为 `local ok, err = pcall(handler); if not ok then log(err) end`
|
|
42
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Review Profile: code:python(Python 专项)
|
|
2
|
+
|
|
3
|
+
<!-- ADR:reviewer-multi-profile -->
|
|
4
|
+
|
|
5
|
+
> 适用:`review_target=code:python` 或检测到 `.py` / `.pyi` 文件时**追加加载**。
|
|
6
|
+
> 本 profile 是通用 `code.md` 的**补充**(不替代),需先加载 `code.md` 的 8 维度清单。
|
|
7
|
+
|
|
8
|
+
## 适用场景
|
|
9
|
+
|
|
10
|
+
- Python 应用(含 Django / Flask / FastAPI / asyncio / 数据科学)
|
|
11
|
+
- 库 / SDK / CLI 工具
|
|
12
|
+
|
|
13
|
+
## Python 特有高频陷阱
|
|
14
|
+
|
|
15
|
+
| # | 陷阱 | 等级 | 反例 | 正确写法 |
|
|
16
|
+
|---|---|---|---|---|
|
|
17
|
+
| PY#1 | 可变默认参数 | ✗ | `def f(x=[]):` 每次调用共享同一 list | `def f(x=None): \n if x is None: x = []` |
|
|
18
|
+
| PY#2 | 过宽 `except Exception` 或裸 `except:` 遮蔽真实错误 | ✗ | `try: ... \nexcept Exception: pass` | 捕获具体异常 + 至少 log;裸 `except:` 一律拒 |
|
|
19
|
+
| PY#3 | GIL 下用 threading 跑 CPU 密集任务 | ⚠ | `Thread(target=heavy_compute).start()` | 改用 `multiprocessing` / `concurrent.futures.ProcessPoolExecutor` |
|
|
20
|
+
| PY#4 | 未用 context manager 管理资源 | ✗ | `f = open(path); ...; f.close()` 异常时 leak | `with open(path) as f: ...` |
|
|
21
|
+
| PY#5 | f-string 内副作用调用 | ⚠ | `f"{db.query()}"` 字符串构造时跑 IO | 先赋值 `result = db.query()` 再 `f"{result}"` |
|
|
22
|
+
| PY#6 | `__init__.py` 循环导入 | ✗ | A 顶层 `from .b import x`,B 顶层又 `from .a import y` | 延迟导入 `def f(): from .b import x`;或重构依赖方向 |
|
|
23
|
+
| PY#7 | 在 `for` 里修改正在遍历的 list | ✗ | `for x in lst: lst.remove(x)` | `lst[:] = [x for x in lst if cond]` |
|
|
24
|
+
| PY#8 | `is` 比较非 None/True/False 字面量 | ⚠ | `if name is "foo"` | `if name == "foo"`;`is` 仅用于 `is None` / `is True` / `is False` |
|
|
25
|
+
| PY#9 | 异步函数里跑阻塞 IO | ✗ | `async def f(): time.sleep(1)` 或同步 `requests.get` | `await asyncio.sleep(1)` / `aiohttp` / `loop.run_in_executor` |
|
|
26
|
+
| PY#10 | 用 `==` 比较 `None` | ⚠ | `if x == None` | `if x is None` |
|
|
27
|
+
| PY#11 | 字符串拼接 SQL(注入风险) | ✗ | `cursor.execute(f"SELECT * FROM u WHERE id={uid}")` | `cursor.execute("SELECT * FROM u WHERE id=?", (uid,))` 参数化 |
|
|
28
|
+
| PY#12 | `pickle.loads` 反序列化不可信数据 | ✗ | `pickle.loads(request.body)` RCE 风险 | 改用 `json` / `msgpack`;不可信数据**绝不**用 pickle |
|
|
29
|
+
|
|
30
|
+
## 与通用清单的协同
|
|
31
|
+
|
|
32
|
+
- 通用 #3 安全:Python 额外检查 `pickle.loads(untrusted)` / `eval(user_input)` / `subprocess(shell=True)` 未 escape
|
|
33
|
+
- 通用 #6 测试:检查是否用 pytest fixture 而非全局变量;`unittest.mock.patch` 的路径要 patch 「使用处」而非「定义处」
|
|
34
|
+
|
|
35
|
+
## 输出格式调整
|
|
36
|
+
|
|
37
|
+
`## File-by-File` 命中陷阱时标注编号:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
### `path/a.py`
|
|
41
|
+
- ✗ Line 12 [PY#1 可变默认参数]: `def fetch(items=[])` 应改为 `def fetch(items=None)`
|
|
42
|
+
- ✗ Line 33 [PY#2 过宽 except]: `except Exception: pass` 必须缩窄到具体异常
|
|
43
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Review Profile: code:typescript(TypeScript/JavaScript 专项)
|
|
2
|
+
|
|
3
|
+
<!-- ADR:reviewer-multi-profile -->
|
|
4
|
+
|
|
5
|
+
> 适用:`review_target=code:typescript` 或检测到 `.ts` / `.tsx` / `.js` / `.jsx` / `.mjs` / `.cjs` 文件时**追加加载**。
|
|
6
|
+
> 本 profile 是通用 `code.md` 的**补充**(不替代),需先加载 `code.md` 的 8 维度清单。
|
|
7
|
+
|
|
8
|
+
## 适用场景
|
|
9
|
+
|
|
10
|
+
- TypeScript 项目(含 Node.js / Deno / Bun / 前端 React/Vue/Svelte)
|
|
11
|
+
- JavaScript 项目(含 ES modules / CJS / 浏览器 / Node.js)
|
|
12
|
+
- React/Vue/Svelte/SolidJS 等组件项目
|
|
13
|
+
|
|
14
|
+
## TS/JS 特有高频陷阱(必拒 = ✗,建议改 = ⚠)
|
|
15
|
+
|
|
16
|
+
| # | 陷阱 | 等级 | 反例 | 正确写法 |
|
|
17
|
+
|---|---|---|---|---|
|
|
18
|
+
| TS#1 | `any` 类型滥用(无注释说明) | ✗ | `function f(x: any) { ... }` | `function f(x: unknown)` 或具体类型 + `// any-reason: <理由>` 注释 |
|
|
19
|
+
| TS#2 | `as` 类型断言替代类型守卫 | ⚠ | `(obj as User).name` | 用类型守卫 `if ('name' in obj) ...` 或 zod `User.parse(obj)` |
|
|
20
|
+
| TS#3 | Promise 未 await(async 函数返回值未消费) | ✗ | `someAsyncFn(); doNext();` | `await someAsyncFn(); doNext();` 或显式 `void someAsyncFn();` 表明故意 |
|
|
21
|
+
| TS#4 | 未处理的 Promise rejection | ✗ | `fetch(url).then(...)` 无 `.catch` | `.catch(handleError)` 或 `try { await fetch }` |
|
|
22
|
+
| TS#5 | 可选链 `?.` 后接不安全操作 | ⚠ | `user?.posts.map(...)`(应为 `user?.posts?.map`) | 链路上每一步都 `?.` 或显式判空 |
|
|
23
|
+
| TS#6 | React useEffect 依赖数组遗漏 | ✗ | `useEffect(() => { fetch(userId); }, [])` 缺 `userId` | `useEffect(() => { fetch(userId); }, [userId])` |
|
|
24
|
+
| TS#7 | `==` 代替 `===` | ⚠ | `if (x == 0)` | 一律 `===`;仅 `== null` 双判 null/undefined 惯用法可放 |
|
|
25
|
+
| TS#8 | `Number()` / `parseInt()` 无 radix | ⚠ | `parseInt(str)` | `parseInt(str, 10)` |
|
|
26
|
+
| TS#9 | `JSON.parse` 未 try/catch | ✗ | `const data = JSON.parse(input)` | `try { JSON.parse(input) } catch { ... }` 或 zod 解析 |
|
|
27
|
+
| TS#10 | 在 React render 期发起副作用 | ✗ | 函数组件 body 里直接 `fetch()` | 放到 `useEffect` 内 |
|
|
28
|
+
| TS#11 | 在循环里 `await` 串行可并发的任务 | ⚠ | `for (const u of users) await fetch(u)` 每条 IO 串行 | `await Promise.all(users.map(fetch))` 除非有依赖 |
|
|
29
|
+
| TS#12 | `setState` 内直接读 prevState 而不用 updater | ⚠ | `setX(x + 1)` 多次连续调用 | `setX(prev => prev + 1)` |
|
|
30
|
+
|
|
31
|
+
## 与通用清单的协同
|
|
32
|
+
|
|
33
|
+
- 通用 #2 正确性:TS 项目额外检查「TypeScript strict 模式下的类型完整性」
|
|
34
|
+
- 通用 #3 安全:TS 额外检查 `eval()` / `new Function()` / `dangerouslySetInnerHTML`
|
|
35
|
+
- 通用 #6 测试:TS 项目期望测试用 `expect(x).toBe(y)` 而非 `console.log`
|
|
36
|
+
|
|
37
|
+
## 输出格式调整
|
|
38
|
+
|
|
39
|
+
在 `## File-by-File` 每个 `.ts` / `.js` 文件意见中,**明确标注**命中的陷阱编号:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
### `path/a.ts`
|
|
43
|
+
- ✗ Line 42 [TS#3 Promise 未 await]: `fetchUser(id); render(user)` 应改为 `const user = await fetchUser(id); render(user);`
|
|
44
|
+
- ⚠ Line 88 [TS#2 as 断言]: `as User` 建议改为 zod 类型守卫
|
|
45
|
+
```
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Review Profile: code(通用代码审阅 + 兜底)
|
|
2
|
+
|
|
3
|
+
<!-- ADR:reviewer-multi-profile -->
|
|
4
|
+
|
|
5
|
+
> 适用:`review_target=code` 或未指定 review_target 的默认场景。
|
|
6
|
+
> 本 profile 也是**语言自动检测入口**:检测到具体语言时**追加加载**对应专项 profile。
|
|
7
|
+
|
|
8
|
+
## 适用场景
|
|
9
|
+
|
|
10
|
+
- 用户派 reviewer 但未指定 review_target(默认走本 profile)
|
|
11
|
+
- pending 文件扩展名无法映射到已知专项 profile(兜底)
|
|
12
|
+
- 多语言混合 pending(本 profile + 各语言专项 profile 都加载)
|
|
13
|
+
|
|
14
|
+
## 语言自动检测(必做)
|
|
15
|
+
|
|
16
|
+
调 `pending_changes.list()` 后,按扩展名映射加载额外 profile:
|
|
17
|
+
|
|
18
|
+
| 扩展名 | 加载的 profile |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `.ts` / `.tsx` / `.js` / `.jsx` / `.mjs` / `.cjs` | `code-typescript.md` |
|
|
21
|
+
| `.py` / `.pyi` | `code-python.md` |
|
|
22
|
+
| `.cs` / `.lua` / `.c` / `.cpp` / `.cc` / `.cxx` / `.h` / `.hpp` | `code-csharp-lua-c.md` |
|
|
23
|
+
| 其他 / 未列出扩展名 | 仅用本 profile(通用清单覆盖) |
|
|
24
|
+
|
|
25
|
+
**混合语言**:pending 同时含多种扩展名 → **全部加载**对应 profile,reviewer 在 Review Summary 段明示「检测到语言 X+Y,加载 profile A+B」。
|
|
26
|
+
|
|
27
|
+
## 审阅维度(按优先级,逐项过)
|
|
28
|
+
|
|
29
|
+
| # | 维度 | 权重 | 检查 | 反例(必拒) |
|
|
30
|
+
|---|---|---|---|---|
|
|
31
|
+
| 1 | 与方案一致性 | P0 | 改动是否完全对应 planner 步骤?有无擅自加戏? | coder 多改了一个无关文件没有方案依据 |
|
|
32
|
+
| 2 | 正确性 | P0 | 边界条件 / 空值 / 异常分支是否覆盖?返回值有无类型不匹配? | 函数文档写「返回 user 对象」实际可能 `undefined` |
|
|
33
|
+
| 3 | 安全 | P0 | SQL 注入 / XSS / 敏感信息硬编码 / 权限绕过 / 路径穿越? | `db.query("SELECT * WHERE id=" + userId)` 字符串拼接 |
|
|
34
|
+
| 4 | 性能 | P1 | N+1 查询 / 未限流循环 / 阻塞主线程 / 大对象未分页? | for 循环里跑 `await db.find()`,每条数据 1 次 IO |
|
|
35
|
+
| 5 | 可读性 | P2 | 命名是否清晰?复杂逻辑有无注释(why 不是 what)? | 函数名 `handleData` 内部 50 行无注释 |
|
|
36
|
+
| 6 | 测试 | P1 | 单元测试覆盖关键路径?测试是否有真实断言(不是 `expect(true).toBe(true)`)? | 加了 if-else 分支但只测了 if |
|
|
37
|
+
| 7 | 风格 | P2 | 与项目既有风格一致?lint 是否通过? | 项目用 `const` 你新写 `var` |
|
|
38
|
+
| 8 | 历史经验 | P1 | `smart_search` 是否有 anti_pattern 提示要避免某种模式? | KH 有「不要在 X 模块用 Y 模式」该 PR 正踩坑 |
|
|
39
|
+
|
|
40
|
+
## 输出格式调整
|
|
41
|
+
|
|
42
|
+
沿用 reviewer.md 默认模板(`## Review Summary` / `## File-by-File` / `## Decision`),但在 `## Review Summary` 开头**必须加一行**:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
**加载的 profile**: code + <语言专项 profile 列表,无则写「无」>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 失败回退
|
|
49
|
+
|
|
50
|
+
- pending 是空(list 返回 0)→ 报「无待审内容」,**不要硬出审阅**
|
|
51
|
+
- 全是二进制文件 / 无法解析的格式 → 报「跳过 N 个二进制文件」并仅审文本部分
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Review Profile: decision_only(临时决策审阅 / 中审)
|
|
2
|
+
|
|
3
|
+
<!-- ADR:reviewer-multi-profile -->
|
|
4
|
+
|
|
5
|
+
> 适用:`review_target=decision_only`,审 codeforge 传来的「用户选择 + 拟派单方案」。
|
|
6
|
+
> 本 profile **替代**通用 code.md 清单。
|
|
7
|
+
|
|
8
|
+
## 适用场景
|
|
9
|
+
|
|
10
|
+
- ADR:full-chain-auto-review-gating 决策 review 门控(Q3-a 范围):用户选择直接驱动「派哪个 agent 做什么任务」
|
|
11
|
+
- **不适用**:纯确认型 / 偏好选择(codeforge 已收窄触发条件,不应进入本 profile)
|
|
12
|
+
|
|
13
|
+
## 审阅力度(中审)
|
|
14
|
+
|
|
15
|
+
> **用户已定**:识别明显风险 + 关键遗漏,给出替代建议(≤ 2 条),**无大问题 APPROVE**,避免过度干预用户决策。
|
|
16
|
+
|
|
17
|
+
## 审阅维度(按优先级,逐项过)
|
|
18
|
+
|
|
19
|
+
| # | 维度 | 权重 | 检查 | 反例(必拒) |
|
|
20
|
+
|---|---|---|---|---|
|
|
21
|
+
| 1 | 决策风险识别 | P0 | 选择是否存在**明显**技术/安全/数据风险?是否会产生不可逆后果? | 用户选「跳过备份直接 apply 数据库迁移」 |
|
|
22
|
+
| 2 | 关键遗漏 | P1 | 决策是否**漏考虑**前置条件 / 依赖项 / 兼容性影响? | 用户选「升级 plugin」但漏了与其他 plugin 版本冲突 |
|
|
23
|
+
| 3 | 假设前提合理性 | P1 | 用户选择是否基于错误假设?codeforge 给出的派单方案是否匹配用户实际意图? | 用户问「修个小 bug」codeforge 派 planner(应该 short-circuit 派 coder) |
|
|
24
|
+
| 4 | 执行可行性 | P2 | 拟派的 agent / 步骤在当前 session 状态下能否执行?有无 tool / permission / 依赖缺失? | 选「派 reviewer 跑 npm test」但 reviewer bash 被 deny |
|
|
25
|
+
|
|
26
|
+
## 输出维度
|
|
27
|
+
|
|
28
|
+
- **如无明显问题** → **直接 APPROVE**(避免过度干预)
|
|
29
|
+
- **REQUEST_CHANGES** → 给出**替代建议**(≤ 2 条),格式:「建议改派 X:理由 ___;或保持原派单但补充 Y」;**不必给「改哪行」**
|
|
30
|
+
- **BLOCK** → 仅在「不可逆数据损坏 / 安全严重风险」时使用,给一句话理由
|
|
31
|
+
|
|
32
|
+
## 输出格式调整
|
|
33
|
+
|
|
34
|
+
跳过 `## File-by-File`(没有文件可逐个评),改为:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
## Review Summary
|
|
38
|
+
|
|
39
|
+
**加载的 profile**: decision_only
|
|
40
|
+
**用户选择**: <复述用户选项>
|
|
41
|
+
**拟派单方案**: <复述 codeforge 派 X 做 Y>
|
|
42
|
+
|
|
43
|
+
## 风险与遗漏
|
|
44
|
+
|
|
45
|
+
- ✓ 无明显风险(或具体列出 1-2 条)
|
|
46
|
+
|
|
47
|
+
## 替代建议(仅 REQUEST_CHANGES 时)
|
|
48
|
+
|
|
49
|
+
1. 建议改派 X:理由 ___
|
|
50
|
+
2. (可选)建议补充 Y:理由 ___
|
|
51
|
+
|
|
52
|
+
## Decision
|
|
53
|
+
|
|
54
|
+
`APPROVE`
|
|
55
|
+
|
|
56
|
+
**理由**:用户选择基于合理假设,拟派单方案与意图匹配,未识别到明显风险。
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 失败回退
|
|
60
|
+
|
|
61
|
+
- codeforge 未在 prompt 里给出「用户选项 + 拟派单方案」 → 报「decision_only 缺必要上下文,让 codeforge 补充选项原文」
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Review Profile: docs(文档 / README 审阅)
|
|
2
|
+
|
|
3
|
+
<!-- ADR:reviewer-multi-profile -->
|
|
4
|
+
|
|
5
|
+
> 适用:`review_target=docs`,审 `README.md` / `docs/**/*.md` / changelog 等文档类文件。
|
|
6
|
+
> 本 profile **替代**通用 code.md 清单。
|
|
7
|
+
|
|
8
|
+
## 适用场景
|
|
9
|
+
|
|
10
|
+
- 新增 / 修改项目文档(README / 开发指南 / 用户手册)
|
|
11
|
+
- API 文档 / changelog / migration guide
|
|
12
|
+
- 教程类长文
|
|
13
|
+
|
|
14
|
+
**不审什么**:不审 ADR(用 `adr` profile);不审方案文档(用 `plan_only` profile);不审代码注释(在 code profile 内顺审)。
|
|
15
|
+
|
|
16
|
+
## 审阅维度(按优先级,逐项过)
|
|
17
|
+
|
|
18
|
+
| # | 维度 | 权重 | 检查 | 反例(必拒) |
|
|
19
|
+
|---|---|---|---|---|
|
|
20
|
+
| 1 | 目标读者明确 | P0 | 开篇 / 第一段是否明确**目标读者**(开发者 / 用户 / 运维)?内容深度是否匹配读者水平? | README 同时给开发者 + 终端用户讲两套不分段 |
|
|
21
|
+
| 2 | 步骤可复现 | P0 | 操作步骤是否**一字不差能跑通**?命令是否有复制错误风险(中文标点 / 全角空格 / 不显式的 line continuation)? | `npm i && npm run build` 用了全角 `&&`;`npm install`(双空格被复制后变错) |
|
|
22
|
+
| 3 | 信息完整性 | P0 | 前置条件 / 依赖版本 / 环境要求是否列清楚?「opencode 1.14+」「Node ≥ 20」这类硬要求是否在文档头部声明? | 命令需要 `bun` 但前置条件没列;步骤 5 需要超管权限但没说 |
|
|
23
|
+
| 4 | 技术准确性 | P0 | 版本号 / 命令 / 路径 / 配置 key 是否与**当前实现一致**?是否有 stale 内容(讲的是已删除的功能)? | 文档说 `--global` flag,代码已改成 `--user`;引用的文件路径不存在 |
|
|
24
|
+
| 5 | 结构合理性 | P1 | 标题层级是否合理(不跳级 H1 → H3)?能否通过目录 / 导航快速定位信息?长文是否有 TOC? | H1 下直接 H3;2000 字的页面没分小节 |
|
|
25
|
+
| 6 | 陷阱 / 注意事项 | P1 | 是否标注了**常见误操作**或**注意事项**("⚠️ 此操作不可逆" / "首次跑必须 X")? | 讲数据库 migrate 没提"先备份";讲 `--force` 没提"会丢工作区改动" |
|
|
26
|
+
| 7 | 链接有效性 | P2 | 内链 / 外链是否有效?相对路径在 GitHub web 渲染下是否正常? | `[详见 X](./xxx.md)` 但 xxx.md 不存在;用了绝对路径 `/home/...` |
|
|
27
|
+
|
|
28
|
+
## 输出格式调整
|
|
29
|
+
|
|
30
|
+
`## File-by-File` 标注章节定位:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
### `README.md`
|
|
34
|
+
- ✗ `## Quick Start` 第 3 步: `npm i && npm run buld` typo(buld → build)
|
|
35
|
+
- ⚠ `## 配置` 段: 引用 `docs/config.md` 文件不存在
|
|
36
|
+
- ✗ `## 部署` 段: 缺前置条件「Node ≥ 20」声明
|
|
37
|
+
|
|
38
|
+
### `docs/api.md`
|
|
39
|
+
- ⚠ H1 下直接 H3,建议补 H2 章节划分
|
|
40
|
+
- ✓ 注意事项段已标注「此 API 已 deprecated」
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 失败回退
|
|
44
|
+
|
|
45
|
+
- pending 全是非 markdown 文件 → 报「未找到文档文件」
|
|
46
|
+
- 仅 typo 级改动 → 可 APPROVE 但保留快速 verify
|