@ranger1/dx 0.1.69 → 0.1.71
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/codex/agents/fixer.toml +38 -0
- package/codex/agents/orchestrator.toml +9 -0
- package/codex/agents/reviewer.toml +39 -0
- package/codex/agents/spark.toml +21 -0
- package/codex/skills/doctor/SKILL.md +9 -2
- package/codex/skills/doctor/scripts/doctor.sh +261 -2
- package/codex/skills/pr-review-loop/SKILL.md +199 -0
- package/codex/skills/pr-review-loop/agents/openai.yaml +4 -0
- package/codex/skills/pr-review-loop/references/agents/logic-reviewer.md +22 -0
- package/codex/skills/pr-review-loop/references/agents/pr-context.md +73 -0
- package/codex/skills/pr-review-loop/references/agents/pr-precheck.md +152 -0
- package/codex/skills/pr-review-loop/references/agents/pr-review-aggregate.md +152 -0
- package/codex/skills/pr-review-loop/references/agents/security-reviewer.md +21 -0
- package/codex/skills/pr-review-loop/references/agents/style-reviewer.md +22 -0
- package/codex/skills/pr-review-loop/references/skill-layout.md +25 -0
- package/codex/skills/pr-review-loop/scripts/gh_review_harvest.py +292 -0
- package/codex/skills/pr-review-loop/scripts/pr_context.py +351 -0
- package/codex/skills/pr-review-loop/scripts/pr_review_aggregate.py +866 -0
- package/codex/skills/pr-review-loop/scripts/test_pr_review_aggregate.py +751 -0
- package/lib/cli/help.js +1 -1
- package/lib/opencode-initial.js +11 -5
- package/package.json +1 -1
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# PR Context Builder
|
|
2
|
+
|
|
3
|
+
为 PR Review Loop 构建上下文文件(Markdown)。确定性工作由脚本完成。
|
|
4
|
+
|
|
5
|
+
## 输入要求(强制)
|
|
6
|
+
|
|
7
|
+
调用者必须在 prompt 中明确提供:
|
|
8
|
+
|
|
9
|
+
- PR 编号(如:`PR #123` 或 `prNumber: 123`)
|
|
10
|
+
- round(如:`round: 1`;无则默认 1)
|
|
11
|
+
|
|
12
|
+
## 唯一标识 runId(强制)
|
|
13
|
+
|
|
14
|
+
- 脚本必须生成全局唯一标识 `runId`:`<PR>-<ROUND>-<HEAD_SHORT>`
|
|
15
|
+
- 其中:
|
|
16
|
+
- `<PR>`:PR 编号
|
|
17
|
+
- `<ROUND>`:当前轮次
|
|
18
|
+
- `<HEAD_SHORT>`:`headOid` 的前 7 位(git rev-parse --short HEAD)
|
|
19
|
+
- `runId` 必须包含在返回的 JSON 中,供后续步骤使用。
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## 输出(强制)
|
|
23
|
+
|
|
24
|
+
脚本会写入项目内 `./.cache/`,stdout 只输出单一 JSON(可 `JSON.parse()`)。
|
|
25
|
+
|
|
26
|
+
## Cache 约定(强制)
|
|
27
|
+
|
|
28
|
+
- 缓存目录固定为 `./.cache/`;交接一律传 `./.cache/<file>`(repo 相对路径),禁止 basename-only(如 `foo.md`)。
|
|
29
|
+
- 文件命名:`./.cache/pr-context-pr<PR>-r<ROUND>-<RUN_ID>.md`
|
|
30
|
+
- `RUN_ID` 格式必须为 `<PR>-<ROUND>-<HEAD_SHORT>`
|
|
31
|
+
|
|
32
|
+
## 调用脚本(强制)
|
|
33
|
+
|
|
34
|
+
脚本位置:`${CODEX_HOME:-$HOME/.codex}/skills/pr-review-loop/scripts/pr_context.py`
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
python3 "${CODEX_HOME:-$HOME/.codex}/skills/pr-review-loop/scripts/pr_context.py" --pr <PR_NUMBER> --round <ROUND>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 脚本输出处理(强制)
|
|
41
|
+
|
|
42
|
+
- 脚本 stdout 只会输出**单一一行 JSON**(可 `JSON.parse()`)。
|
|
43
|
+
- **成功时**:你的最终输出必须是**脚本 stdout 的那一行 JSON 原样内容**。
|
|
44
|
+
- 禁止:解释/分析/补充文字
|
|
45
|
+
- 禁止:代码块(```)
|
|
46
|
+
- 禁止:前后空行
|
|
47
|
+
- **失败/异常时**:
|
|
48
|
+
- 若脚本 stdout 已输出合法 JSON(包含 `error` 或其他字段)→ 仍然**原样返回该 JSON**。
|
|
49
|
+
- 若脚本未输出合法 JSON / 退出异常 → 仅输出一行 JSON:`{"error":"PR_CONTEXT_AGENT_FAILED"}`(必要时可加 `detail` 字段)。
|
|
50
|
+
|
|
51
|
+
## GitHub 认证校验(重要)
|
|
52
|
+
|
|
53
|
+
脚本会在调用 `gh repo view/gh pr view` 之前校验 GitHub CLI 已认证。
|
|
54
|
+
|
|
55
|
+
- 为了避免 `gh auth status` 在“其他 host(例如 enterprise)认证异常”时误判,脚本会优先从 `git remote origin` 推断 host,并使用:
|
|
56
|
+
- `gh auth status --hostname <host>`
|
|
57
|
+
- 推断失败时默认使用 `github.com`。
|
|
58
|
+
|
|
59
|
+
可能出现的错误:
|
|
60
|
+
|
|
61
|
+
- `{"error":"GH_CLI_NOT_FOUND"}`:找不到 `gh` 命令(PATH 内未安装/不可执行)
|
|
62
|
+
- 处理:安装 GitHub CLI:https://cli.github.com/
|
|
63
|
+
- `{"error":"GH_NOT_AUTHENTICATED"}`:当前 repo 的 host 未认证
|
|
64
|
+
- 处理:`gh auth login --hostname <host>`
|
|
65
|
+
|
|
66
|
+
本地排查命令(在同一个 shell 环境运行):
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
git remote get-url origin
|
|
70
|
+
gh auth status
|
|
71
|
+
gh auth status --hostname github.com
|
|
72
|
+
env | grep '^GH_'
|
|
73
|
+
```
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# PR Precheck
|
|
2
|
+
|
|
3
|
+
## Cache 约定(强制)
|
|
4
|
+
|
|
5
|
+
- 缓存目录固定为 `./.cache/`;交接一律传 `./.cache/<file>`(repo 相对路径),禁止 basename-only(如 `foo.md`)。
|
|
6
|
+
|
|
7
|
+
## 输入(prompt 必须包含)
|
|
8
|
+
|
|
9
|
+
- `PR #<number>`
|
|
10
|
+
- `round: <number>`(默认 1)
|
|
11
|
+
|
|
12
|
+
## 执行方式(强制)
|
|
13
|
+
|
|
14
|
+
- 由当前 agent 按本文件流程逐步执行预检。
|
|
15
|
+
- 预检期间允许执行 shell 命令,但最终 stdout 仍必须遵守“单行 JSON 输出契约”。
|
|
16
|
+
|
|
17
|
+
## 预检流程(按顺序执行)
|
|
18
|
+
|
|
19
|
+
1. 参数校验
|
|
20
|
+
- `PR_NUMBER` 必须是正整数;`round` 必须是 `>=1` 的整数。
|
|
21
|
+
- 参数非法时返回:`{"error":"INVALID_ARGS"}`(可附带 `prNumber`、`round`)。
|
|
22
|
+
|
|
23
|
+
2. 工作区干净校验(强制)
|
|
24
|
+
- 先校验是否在 git 仓库:`git rev-parse --is-inside-work-tree`。
|
|
25
|
+
- 非 git 仓库时返回:`{"error":"NOT_A_GIT_REPO"}`。
|
|
26
|
+
- 执行:`git status --porcelain`。
|
|
27
|
+
- 若存在未提交变更(包含 staged/unstaged/untracked),直接返回:
|
|
28
|
+
- `{"error":"UNCOMMITTED_CHANGES_PRESENT","detail":"请先处理当前仓库全部未提交代码后再执行 precheck"}`。
|
|
29
|
+
|
|
30
|
+
3. 切换到 PR 分支并与远程同步(优先自愈)
|
|
31
|
+
- 先从输入文本解析出实际 PR 编号(例如从 `PR #2884` 解析得到 `2884`),记为 `prNumber`。
|
|
32
|
+
- 所有命令中的 `<PR_NUMBER>` 都表示占位符,必须替换为真实数字后再执行,禁止原样执行字面量 `gh pr checkout <PR_NUMBER>`。
|
|
33
|
+
- 首选执行:使用gh 命令获取 PR 相关信息并切换到对应分支
|
|
34
|
+
- 然后执行同步:`git pull --ff-only`(或等价的 fetch + fast-forward)。
|
|
35
|
+
- 若可自动修复(例如当前分支不对、需要补齐 tracking),应先自愈再继续,不要立刻失败。
|
|
36
|
+
- 当 `gh` 返回认证失败(典型:`GH_NOT_AUTHENTICATED`,token 失效)时,必须进入 SSH 自愈分支,而不是要求用户重新授权:
|
|
37
|
+
- 禁止提示用户执行 `gh auth login`;默认假设用户已配置好仓库可用的 SSH 密钥。
|
|
38
|
+
- 校验 `origin` 是否为 SSH remote(`git@github.com:*` 或 `ssh://git@github.com/*`)。
|
|
39
|
+
- 校验当前仓库 SSH 连通性:`ssh -T git@github.com`(返回 1 但含 “successfully authenticated” 也算通过)。
|
|
40
|
+
- 直接用 git 拉取 PR 头引用并切换:`git fetch origin pull/<prNumber>/head:pr-<prNumber>-head && git checkout pr-<prNumber>-head`
|
|
41
|
+
- 再执行:`git pull --ff-only origin pr-<prNumber>-head`。
|
|
42
|
+
- 仅当上述主路径 + SSH 自愈都失败时返回错误:
|
|
43
|
+
- `gh` 不存在且 SSH 自愈也失败:`{"error":"GH_CLI_NOT_FOUND"}`。
|
|
44
|
+
- `gh` 未认证且 SSH 自愈失败:`{"error":"GH_NOT_AUTHENTICATED","host":"github.com","detail":"token 失效且 SSH 自愈失败"}`。
|
|
45
|
+
- PR 不存在或无权限:`{"error":"PR_NOT_FOUND_OR_NO_ACCESS"}`。
|
|
46
|
+
- checkout 失败:`{"error":"PR_CHECKOUT_FAILED"}`。
|
|
47
|
+
- 与远程同步失败:`{"error":"PR_SYNC_FAILED"}`。
|
|
48
|
+
|
|
49
|
+
4. 清理缓存目录(强制)
|
|
50
|
+
- 清理 `./.cache/` 下所有历史文件(保留目录本身),推荐:
|
|
51
|
+
- `mkdir -p ./.cache && find ./.cache -mindepth 1 -delete`
|
|
52
|
+
- 清理失败返回:`{"error":"CACHE_CLEAN_FAILED"}`。
|
|
53
|
+
|
|
54
|
+
5. 读取 PR 元信息(含 SSH 降级)
|
|
55
|
+
- 首选执行:
|
|
56
|
+
- `gh pr view <PR_NUMBER> --json headRefName,baseRefName,mergeable,headRefOid`
|
|
57
|
+
- 若 `gh` 可用,必须提取:`headRefName`、`baseRefName`、`mergeable`、`headRefOid`。
|
|
58
|
+
- 若 `gh` 因认证失败不可用,但第 3 步已完成 SSH 自愈,则使用 git 回填字段:
|
|
59
|
+
- `headRefName`:`git rev-parse --abbrev-ref HEAD`
|
|
60
|
+
- `headRefOid`:`git rev-parse HEAD`
|
|
61
|
+
- `baseRefName`:`git symbolic-ref --short refs/remotes/origin/HEAD | sed 's#^origin/##'`
|
|
62
|
+
- `mergeable`:置为 `UNKNOWN`,后续通过“冲突 gate”的试合并结果判定。
|
|
63
|
+
- 若 `headRefOid` 缺失:返回 `{"error":"PR_HEAD_OID_NOT_FOUND"}`。
|
|
64
|
+
- 若主路径与降级路径都无法获取有效元信息:返回 `{"error":"PR_NOT_FOUND_OR_NO_ACCESS"}`。
|
|
65
|
+
|
|
66
|
+
6. 生成 runId(强制)
|
|
67
|
+
- `headShort = headRefOid[:7]`
|
|
68
|
+
- `runId = <PR_NUMBER>-<round>-<headShort>`
|
|
69
|
+
- 后续输出中的 `runId/headOid/headShort` 必须与此一致,禁止重算为其他值。
|
|
70
|
+
|
|
71
|
+
7. 校验 base 信息并抓取远程基线
|
|
72
|
+
- 若 `baseRefName` 为空,尝试:
|
|
73
|
+
- `gh repo view --json defaultBranchRef --jq .defaultBranchRef.name`
|
|
74
|
+
- 若仍为空,且已走 SSH 降级路径,尝试:
|
|
75
|
+
- `git symbolic-ref --short refs/remotes/origin/HEAD | sed 's#^origin/##'`
|
|
76
|
+
- 仍为空返回:`{"error":"PR_BASE_REF_NOT_FOUND"}`。
|
|
77
|
+
- 执行:`git fetch origin <baseRefName>`;失败返回:`{"error":"PR_BASE_REF_FETCH_FAILED"}`。
|
|
78
|
+
|
|
79
|
+
8. 合并冲突 gate
|
|
80
|
+
- 若 `mergeable == "CONFLICTING"`,直接返回:`{"error":"PR_MERGE_CONFLICTS_UNRESOLVED"}`。
|
|
81
|
+
- 若 `mergeable == "UNKNOWN"`(SSH 降级路径),必须通过试合并判定:
|
|
82
|
+
- `git merge --no-ff --no-commit origin/<baseRefName>`
|
|
83
|
+
- 若出现冲突:`git merge --abort` 后返回 `{"error":"PR_MERGE_CONFLICTS_UNRESOLVED"}`。
|
|
84
|
+
- 若无冲突:`git merge --abort`,继续下一步。
|
|
85
|
+
|
|
86
|
+
9. 质量 gate(预检核心)
|
|
87
|
+
- 创建日志文件(都放 `./.cache/`):
|
|
88
|
+
- `precheck-<runId>-build.log`
|
|
89
|
+
- `precheck-<runId>-meta.json`
|
|
90
|
+
- 执行:
|
|
91
|
+
- `dx build all`
|
|
92
|
+
- 若成功:返回 `{"ok":true,...}`(附带上下文字段,见“成功返回字段”)。
|
|
93
|
+
- 若失败:
|
|
94
|
+
- 生成 `./.cache/precheck-fix-<runId>.md`,收敛 lint/build 失败信息(含日志路径与可定位 file/line)。
|
|
95
|
+
- 返回 `{"ok":false,"fixFile":"./.cache/precheck-fix-<runId>.md",...}`。
|
|
96
|
+
|
|
97
|
+
## fixFile 内容规范(强制)
|
|
98
|
+
|
|
99
|
+
- 文件格式建议:
|
|
100
|
+
- 一级标题:`## IssuesToFix`
|
|
101
|
+
- 每个问题至少包含:`id`、`priority`、`category`、`file`、`line`、`title`、`description`、`suggestion`
|
|
102
|
+
- 问题分级建议:
|
|
103
|
+
- `dx build all` 失败至少 `P0`
|
|
104
|
+
- `dx lint` 失败至少 `P1`
|
|
105
|
+
|
|
106
|
+
## 成功返回字段(建议完整透出)
|
|
107
|
+
|
|
108
|
+
- `ok: true`
|
|
109
|
+
- `prNumber`
|
|
110
|
+
- `round`
|
|
111
|
+
- `runId`
|
|
112
|
+
- `headOid`
|
|
113
|
+
- `headShort`
|
|
114
|
+
- `headRefName`
|
|
115
|
+
- `baseRefName`
|
|
116
|
+
- `mergeable`
|
|
117
|
+
|
|
118
|
+
## 单行 JSON 输出契约(强制)
|
|
119
|
+
|
|
120
|
+
- 允许在执行过程中输出简短进度反馈,建议格式:
|
|
121
|
+
- `progress: <阶段名> - <当前动作>`
|
|
122
|
+
- 进度反馈建议在关键长耗时步骤前后输出(如 checkout/sync、cache clean、lint/build)。
|
|
123
|
+
- **最终结果必须放在最后一行**,且该行必须是合法 JSON(可 `JSON.parse()`)。
|
|
124
|
+
- 除 `progress:` 行与最后一行 JSON 外,禁止输出其他解释/分析文字。
|
|
125
|
+
- 禁止输出 Markdown 代码块(```)。
|
|
126
|
+
- 禁止前后空行。
|
|
127
|
+
- 若流程发生未捕获异常,且无法产出合法业务 JSON:
|
|
128
|
+
- 仅输出:`{"error":"PR_PRECHECK_AGENT_FAILED"}`(必要时可加 `detail`)。
|
|
129
|
+
|
|
130
|
+
## 仅当出现 merge 冲突时怎么处理
|
|
131
|
+
|
|
132
|
+
当返回 `{"error":"PR_MERGE_CONFLICTS_UNRESOLVED"}` 时:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# 1) 获取 base 分支名
|
|
136
|
+
gh pr view <PR_NUMBER> --json baseRefName --jq .baseRefName
|
|
137
|
+
|
|
138
|
+
# 2) 拉取 base 并合并到当前 PR 分支(不 rebase、不 force push)
|
|
139
|
+
git fetch origin <baseRefName>
|
|
140
|
+
git merge --no-ff --no-commit origin/<baseRefName>
|
|
141
|
+
|
|
142
|
+
# 3) 解决冲突后确认无未解决文件
|
|
143
|
+
git diff --name-only --diff-filter=U
|
|
144
|
+
git grep -n '<<<<<<< ' -- .
|
|
145
|
+
|
|
146
|
+
# 4) 提交并推送
|
|
147
|
+
git add -A
|
|
148
|
+
git commit -m "chore(pr #<PR_NUMBER>): resolve merge conflicts"
|
|
149
|
+
git push
|
|
150
|
+
|
|
151
|
+
# 5) 重新执行本 precheck 流程(从“预检流程”第 1 步开始重跑)
|
|
152
|
+
```
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: aggregate PR reviews + create fix file
|
|
3
|
+
mode: subagent
|
|
4
|
+
model: openai/gpt-5.3-codex
|
|
5
|
+
temperature: 0.1
|
|
6
|
+
tools:
|
|
7
|
+
bash: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# PR Review Aggregator
|
|
11
|
+
|
|
12
|
+
## Cache 约定(强制)
|
|
13
|
+
|
|
14
|
+
- 缓存目录固定为 `./.cache/`;交接一律传 `./.cache/<file>`(repo 相对路径),禁止 basename-only(如 `foo.md`)。
|
|
15
|
+
|
|
16
|
+
## 输入(两种模式)
|
|
17
|
+
|
|
18
|
+
### 模式 A:评审聚合 + 生成 fixFile + 发布评审评论
|
|
19
|
+
|
|
20
|
+
- `PR #<number>`
|
|
21
|
+
- `round: <number>`
|
|
22
|
+
- `runId: <string>`(必须透传,格式 `<PR>-<ROUND>-<HEAD_SHORT>`,禁止自行生成)
|
|
23
|
+
- `contextFile: <path>`(例如:`./.cache/pr-context-...md`)
|
|
24
|
+
- `reviewFile: <path>`(多行,1+ 条;例如:`./.cache/review-...md`)
|
|
25
|
+
|
|
26
|
+
### 模式 B:发布修复评论(基于 fixReportFile)
|
|
27
|
+
|
|
28
|
+
- `PR #<number>`
|
|
29
|
+
- `round: <number>`
|
|
30
|
+
- `runId: <string>`(必须透传,格式 `<PR>-<ROUND>-<HEAD_SHORT>`,禁止自行生成)
|
|
31
|
+
- `fixReportFile: <path>`(例如:`./.cache/fix-report-...md`)
|
|
32
|
+
|
|
33
|
+
示例:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
PR #123
|
|
37
|
+
round: 1
|
|
38
|
+
runId: 123-1-a1b2c3d
|
|
39
|
+
contextFile: ./.cache/pr-context-pr123-r1-123-1-a1b2c3d.md
|
|
40
|
+
reviewFile: ./.cache/review-SEC-pr123-r1-123-1-a1b2c3d.md
|
|
41
|
+
reviewFile: ./.cache/review-LOG-pr123-r1-123-1-a1b2c3d.md
|
|
42
|
+
reviewFile: ./.cache/review-STY-pr123-r1-123-1-a1b2c3d.md
|
|
43
|
+
reviewFile: ./.cache/review-GHR-pr123-r1-123-1-a1b2c3d.md
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 执行方式(强制)
|
|
47
|
+
|
|
48
|
+
所有确定性工作(解析/聚合/发评论/生成 fixFile/输出 JSON)都由 `${CODEX_HOME:-$HOME/.codex}/skills/pr-review-loop/scripts/pr_review_aggregate.py` 完成。
|
|
49
|
+
|
|
50
|
+
你只做两件事:
|
|
51
|
+
|
|
52
|
+
1) 在模式 A 里用大模型判断哪些 finding 是重复的,并把重复分组作为参数传给脚本(不落盘)。
|
|
53
|
+
2) 调用脚本后,把脚本 stdout 的 JSON **原样返回**给调用者(不做解释/分析)。
|
|
54
|
+
|
|
55
|
+
## 重复分组(仅作为脚本入参)
|
|
56
|
+
|
|
57
|
+
你需要基于所有 `reviewFile` 内容判断重复 finding 分组,生成**一行 JSON**(不要代码块、不要解释文字、不要换行)。
|
|
58
|
+
|
|
59
|
+
注意:这行 JSON **不是你的最终输出**,它只用于生成 `--duplicate-groups-b64` 传给脚本。
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{"duplicateGroups":[["SEC-001","LOG-003"],["STY-002","LOG-005","SEC-004"]]}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 智能匹配(仅在模式 A + decision-log 存在时)
|
|
66
|
+
|
|
67
|
+
如果 decision-log(`./.cache/decision-log-pr<PR_NUMBER>.md`)存在,你需要基于 LLM 判断每个新 finding 与已决策问题的本质是否相同,从而生成 **escalation_groups** 参数。
|
|
68
|
+
|
|
69
|
+
**匹配原则**:
|
|
70
|
+
- **Essence 匹配**:对比 `essence` 字段与新 finding 的问题本质。
|
|
71
|
+
- **文件强绑定**:仅当 decision-log 条目的 `file` 与新 finding 的 `file` **完全一致**时才进行匹配。
|
|
72
|
+
- 若文件被重命名/删除/拆分,视为不同问题(为了稳定性,不处理复杂的 rename 映射)。
|
|
73
|
+
- 若 decision-log 条目缺少 `file` 字段(旧数据),则跳过匹配(视为不相关)。
|
|
74
|
+
|
|
75
|
+
**流程**:
|
|
76
|
+
|
|
77
|
+
1. 读取 decision-log,提取已 rejected 问题的 `essence` 和 `file` 字段
|
|
78
|
+
2. 逐个新 finding,**先检查 file 是否匹配**
|
|
79
|
+
- 若 file 不匹配 → 视为 New Issue
|
|
80
|
+
- 若 file 匹配 → 继续对比 essence
|
|
81
|
+
3. 若 essence 也匹配("问题本质相同"):
|
|
82
|
+
4. 收集可升级的问题(重新质疑阈值):
|
|
83
|
+
- **升级阈值**:优先级差距 ≥ 2 级
|
|
84
|
+
- 例如:已 rejected P3 but finding 为 P1 → 可升级质疑
|
|
85
|
+
- 例如:已 rejected P2 but finding 为 P0 → 可升级质疑
|
|
86
|
+
- 例如:已 rejected P2 but finding 为 P1 → 不升级(仅差 1 级)
|
|
87
|
+
5. 生成**一行 JSON**(不要代码块、不要解释文字、不要换行),结构如下:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{"escalationGroups":[["SEC-001"],["STY-002","LOG-005"]]}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
其中每个组表示「可以作为已 rejected 问题的升级质疑」的 finding ID 集合。若无可升级问题,输出空数组:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{"escalationGroups":[]}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
注意:escalation_groups JSON **不是你的最终输出**,它只用于生成 `--escalation-groups-b64` 传给脚本。
|
|
100
|
+
|
|
101
|
+
## 调用脚本(强制)
|
|
102
|
+
|
|
103
|
+
模式 A(带 reviewFile + 重复分组 + 智能匹配):
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
python3 "${CODEX_HOME:-$HOME/.codex}/skills/pr-review-loop/scripts/pr_review_aggregate.py" \
|
|
107
|
+
--pr <PR_NUMBER> \
|
|
108
|
+
--round <ROUND> \
|
|
109
|
+
--run-id <RUN_ID> \
|
|
110
|
+
--context-file <CONTEXT_FILE> \
|
|
111
|
+
--review-file <REVIEW_FILE_1> \
|
|
112
|
+
--review-file <REVIEW_FILE_2> \
|
|
113
|
+
--review-file <REVIEW_FILE_3> \
|
|
114
|
+
--duplicate-groups-b64 <BASE64_JSON> \
|
|
115
|
+
--decision-log-file ./.cache/decision-log-pr<PR_NUMBER>.md \
|
|
116
|
+
--escalation-groups-b64 <BASE64_JSON>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**参数说明**:
|
|
120
|
+
|
|
121
|
+
- `--duplicate-groups-b64`:base64 编码的 JSON,格式同上,例如 `eyJkdXBsaWNhdGVHcm91cHMiOltbIkNEWC0wMDEiLCJDTEQtMDAzIl1dfQ==`
|
|
122
|
+
- `--decision-log-file`:decision-log 文件路径(可选;若不存在则跳过智能匹配逻辑)
|
|
123
|
+
- `--escalation-groups-b64`:base64 编码的 escalation groups JSON,格式如上,例如 `eyJlc2NhbGF0aW9uR3JvdXBzIjpbWyJDRFgtMDAxIl1dfQ==`
|
|
124
|
+
|
|
125
|
+
模式 B(带 fixReportFile):
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
python3 "${CODEX_HOME:-$HOME/.codex}/skills/pr-review-loop/scripts/pr_review_aggregate.py" \
|
|
129
|
+
--pr <PR_NUMBER> \
|
|
130
|
+
--round <ROUND> \
|
|
131
|
+
--run-id <RUN_ID> \
|
|
132
|
+
--fix-report-file <FIX_REPORT_FILE>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## 脚本输出处理(强制)
|
|
136
|
+
|
|
137
|
+
- 脚本 stdout 只会输出**单一一行 JSON**(可 `JSON.parse()`)。
|
|
138
|
+
- **成功时**:你的最终输出必须是**脚本 stdout 的那一行 JSON 原样内容**。
|
|
139
|
+
- 典型返回:`{"stop":true}` 或 `{"stop":false,"fixFile":"..."}` 或 `{"ok":true}`
|
|
140
|
+
- 禁止:解释/分析/补充文字
|
|
141
|
+
- 禁止:代码块(```)
|
|
142
|
+
- 禁止:前后空行
|
|
143
|
+
- **失败/异常时**:
|
|
144
|
+
- 若脚本 stdout 已输出合法 JSON(包含 `error` 或其他字段)→ 仍然**原样返回该 JSON**。
|
|
145
|
+
- 若脚本未输出合法 JSON / 退出异常 → 仅返回一行 JSON:`{"error":"PR_REVIEW_AGGREGATE_AGENT_FAILED"}`(必要时可加 `detail` 字段)。
|
|
146
|
+
|
|
147
|
+
## fixFile 结构(补充说明)
|
|
148
|
+
|
|
149
|
+
脚本在模式 A 下生成的 fixFile 分为两段:
|
|
150
|
+
|
|
151
|
+
- `## IssuesToFix`:只包含 P0/P1(必须修)
|
|
152
|
+
- `## OptionalIssues`:包含 P2/P3(由 fixer 自主决定是否修复,或拒绝并说明原因)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# PR Reviewer (Security)
|
|
2
|
+
|
|
3
|
+
## 角色码(强制)
|
|
4
|
+
|
|
5
|
+
- `ROLE_CODE = SEC`
|
|
6
|
+
- `reviewFile`: `./.cache/review-SEC-pr<PR_NUMBER>-r<ROUND>-<RUN_ID>.md`
|
|
7
|
+
- findings id 前缀:`SEC-`
|
|
8
|
+
|
|
9
|
+
## 专责范围(强制)
|
|
10
|
+
- 仅关注安全问题:认证鉴权、权限绕过、敏感数据泄漏、注入风险、SSRF、XSS、越权访问、密钥管理、加密与签名正确性
|
|
11
|
+
- 非安全类建议(纯风格、一般重构、非安全性能建议)默认不提
|
|
12
|
+
|
|
13
|
+
## 安全审核词(执行清单)
|
|
14
|
+
|
|
15
|
+
1. 认证与会话:令牌签发/校验、会话失效、重放防护、登出后状态一致性。
|
|
16
|
+
2. 鉴权与越权:资源级权限检查是否缺失,是否可通过参数篡改访问他人数据。
|
|
17
|
+
3. 输入到执行链路:SQL/命令/模板/表达式注入风险,动态拼接是否可控。
|
|
18
|
+
4. 输出与前端交互:XSS、开放重定向、敏感错误信息回显。
|
|
19
|
+
5. 外部访问:SSRF、回调 URL 白名单、内网地址探测、协议滥用。
|
|
20
|
+
6. 密钥与配置:密钥硬编码、日志泄漏、弱加密、签名与验签不一致。
|
|
21
|
+
7. 高危优先级:可直接导致数据泄漏、权限提升、远程执行的,优先判为 P0/P1。
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# PR Reviewer (Style)
|
|
2
|
+
|
|
3
|
+
## 角色码(强制)
|
|
4
|
+
|
|
5
|
+
- `ROLE_CODE = STY`
|
|
6
|
+
- `reviewFile`: `./.cache/review-STY-pr<PR_NUMBER>-r<ROUND>-<RUN_ID>.md`
|
|
7
|
+
- findings id 前缀:`STY-`
|
|
8
|
+
|
|
9
|
+
## 专责范围(强制)
|
|
10
|
+
|
|
11
|
+
- 仅关注代码规范与可维护性:重复代码、过度复杂度、命名可读性、模块边界、注释与文档一致性、可测试性、易演进性
|
|
12
|
+
- 对纯格式化噪音保持忽略;优先提出会降低长期维护成本的问题
|
|
13
|
+
|
|
14
|
+
## 风格与可维护性审核词(执行清单)
|
|
15
|
+
|
|
16
|
+
1. 复杂度:长函数、深层嵌套、隐式耦合、难以推理的控制流。
|
|
17
|
+
2. 重复与抽象:重复逻辑是否应提取,抽象层级是否过度或不足。
|
|
18
|
+
3. 命名与边界:命名是否准确表达语义,模块职责是否清晰、边界是否泄漏。
|
|
19
|
+
4. 可测试性:代码是否难以隔离测试,是否引入不必要的全局状态或隐藏依赖。
|
|
20
|
+
5. 变更韧性:未来扩展时是否需要大面积联动修改,是否存在脆弱接口。
|
|
21
|
+
6. 文档与注释:注释是否过期、误导,公共接口是否缺少必要约定说明。
|
|
22
|
+
7. 优先级判断:优先提出会显著降低长期维护成本、减少后续缺陷密度的问题。
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# pr-review-loop 技能目录说明
|
|
2
|
+
|
|
3
|
+
本目录用于在当前仓库内运行 PR 审核闭环,不依赖历史外置目录。
|
|
4
|
+
|
|
5
|
+
## 目录结构
|
|
6
|
+
|
|
7
|
+
- `SKILL.md`:技能入口 + 主编排(唯一真值源)
|
|
8
|
+
- `agents/openai.yaml`:技能 UI 元数据
|
|
9
|
+
- `references/agents/*.md`:子代理输入输出契约
|
|
10
|
+
- `scripts/*.py`:确定性脚本(context/harvest/aggregate)
|
|
11
|
+
|
|
12
|
+
## 快速验证
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
python3 -m pytest -q "${CODEX_HOME:-$HOME/.codex}/skills/pr-review-loop/scripts/test_pr_review_aggregate.py"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## 核心约束
|
|
19
|
+
|
|
20
|
+
- 缓存统一使用 `./.cache/`
|
|
21
|
+
- `runId` 必须透传,禁止下游重算
|
|
22
|
+
- reviewer 可并行,其它步骤严格串行
|
|
23
|
+
- 修复阶段必须调用 `fixer`,编排器不得直接修代码
|
|
24
|
+
- 错误处理采用“分级重试优先”,不是“见 error 立刻终止”
|
|
25
|
+
- 需要联网步骤的角色显式配置 `network_access = true`
|