@ranger1/dx 0.1.29 → 0.1.30
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/agents/__pycache__/pr_context.cpython-314.pyc +0 -0
- package/@opencode/agents/__pycache__/pr_precheck.cpython-314.pyc +0 -0
- package/@opencode/agents/__pycache__/pr_review_aggregate.cpython-314.pyc +0 -0
- package/@opencode/agents/claude-reviewer.md +8 -3
- package/@opencode/agents/codex-reviewer.md +9 -3
- package/@opencode/agents/gemini-reviewer.md +9 -3
- package/@opencode/agents/pr-context.md +6 -166
- package/@opencode/agents/pr-fix.md +11 -6
- package/@opencode/agents/pr-precheck.md +25 -341
- package/@opencode/agents/pr-review-aggregate.md +36 -72
- package/@opencode/agents/pr_context.py +211 -0
- package/@opencode/agents/pr_precheck.py +256 -0
- package/@opencode/agents/pr_review_aggregate.py +428 -0
- package/@opencode/commands/doctor.md +0 -1
- package/@opencode/commands/pr-review-loop.md +11 -6
- package/package.json +6 -4
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -14,21 +14,26 @@ tools:
|
|
|
14
14
|
|
|
15
15
|
- `PR #<number>`
|
|
16
16
|
- `round: <number>`
|
|
17
|
-
- `contextFile: <
|
|
17
|
+
- `contextFile: <filename>`
|
|
18
18
|
|
|
19
19
|
## 输出(强制)
|
|
20
20
|
|
|
21
21
|
只输出一行:
|
|
22
22
|
|
|
23
|
-
`reviewFile: <
|
|
23
|
+
`reviewFile: <filename>`
|
|
24
|
+
|
|
24
25
|
|
|
25
26
|
## 规则
|
|
26
27
|
|
|
27
28
|
- 默认已在 PR head 分支(可直接读工作区代码)
|
|
28
29
|
- 可用 `git`/`gh` 只读命令获取 diff/上下文
|
|
29
|
-
- 写入 reviewFile
|
|
30
|
+
- 写入 reviewFile:`review-CLD-pr<PR_NUMBER>-r<ROUND>-<RUN_ID>.md`
|
|
30
31
|
- findings id 必须以 `CLD-` 开头
|
|
31
32
|
|
|
33
|
+
## Cache 约定(强制)
|
|
34
|
+
- 本流程所有中间文件都存放在 `~/.opencode/cache/`
|
|
35
|
+
- agent/命令之间仅传递文件名(basename),不传目录
|
|
36
|
+
|
|
32
37
|
## reviewFile 格式(强制)
|
|
33
38
|
|
|
34
39
|
```md
|
|
@@ -15,21 +15,27 @@ tools:
|
|
|
15
15
|
|
|
16
16
|
- `PR #<number>`
|
|
17
17
|
- `round: <number>`
|
|
18
|
-
- `contextFile: <
|
|
18
|
+
- `contextFile: <filename>`
|
|
19
19
|
|
|
20
20
|
## 输出(强制)
|
|
21
21
|
|
|
22
22
|
只输出一行:
|
|
23
23
|
|
|
24
|
-
`reviewFile: <
|
|
24
|
+
`reviewFile: <filename>`
|
|
25
|
+
|
|
25
26
|
|
|
26
27
|
## 规则
|
|
27
28
|
|
|
28
29
|
- 默认已在 PR head 分支(可直接读工作区代码)
|
|
29
30
|
- 可用 `git`/`gh` 只读命令获取 diff/上下文
|
|
30
|
-
- 写入 reviewFile
|
|
31
|
+
- 写入 reviewFile:`review-CDX-pr<PR_NUMBER>-r<ROUND>-<RUN_ID>.md`
|
|
31
32
|
- findings id 必须以 `CDX-` 开头
|
|
32
33
|
|
|
34
|
+
## Cache 约定(强制)
|
|
35
|
+
- 本流程所有中间文件都存放在 `~/.opencode/cache/`
|
|
36
|
+
- agent/命令之间仅传递文件名(basename),不传目录
|
|
37
|
+
|
|
38
|
+
|
|
33
39
|
## reviewFile 格式(强制)
|
|
34
40
|
|
|
35
41
|
```md
|
|
@@ -14,21 +14,27 @@ tools:
|
|
|
14
14
|
|
|
15
15
|
- `PR #<number>`
|
|
16
16
|
- `round: <number>`
|
|
17
|
-
- `contextFile: <
|
|
17
|
+
- `contextFile: <filename>`
|
|
18
18
|
|
|
19
19
|
## 输出(强制)
|
|
20
20
|
|
|
21
21
|
只输出一行:
|
|
22
22
|
|
|
23
|
-
`reviewFile: <
|
|
23
|
+
`reviewFile: <filename>`
|
|
24
|
+
|
|
24
25
|
|
|
25
26
|
## 规则
|
|
26
27
|
|
|
27
28
|
- 默认已在 PR head 分支(可直接读工作区代码)
|
|
28
29
|
- 可用 `git`/`gh` 只读命令获取 diff/上下文
|
|
29
|
-
- 写入 reviewFile
|
|
30
|
+
- 写入 reviewFile:`review-GMN-pr<PR_NUMBER>-r<ROUND>-<RUN_ID>.md`
|
|
30
31
|
- findings id 必须以 `GMN-` 开头
|
|
31
32
|
|
|
33
|
+
## Cache 约定(强制)
|
|
34
|
+
- 本流程所有中间文件都存放在 `~/.opencode/cache/`
|
|
35
|
+
- agent/命令之间仅传递文件名(basename),不传目录
|
|
36
|
+
|
|
37
|
+
|
|
32
38
|
## reviewFile 格式(强制)
|
|
33
39
|
|
|
34
40
|
```md
|
|
@@ -4,22 +4,12 @@ mode: subagent
|
|
|
4
4
|
model: openai/gpt-5.1-codex-mini
|
|
5
5
|
temperature: 0.1
|
|
6
6
|
tools:
|
|
7
|
-
write: false
|
|
8
|
-
edit: false
|
|
9
7
|
bash: true
|
|
10
8
|
---
|
|
11
9
|
|
|
12
10
|
# PR Context Builder
|
|
13
11
|
|
|
14
|
-
为 PR Review Loop
|
|
15
|
-
|
|
16
|
-
目标:
|
|
17
|
-
|
|
18
|
-
- 生成 PR context 文件(标题/描述/labels/分支/修改文件清单/评论摘要)
|
|
19
|
-
- 默认假设已通过 pr-precheck:gh 已认证、PR 可访问、当前分支已切到 PR head 分支
|
|
20
|
-
- 把信息拼成适合大模型阅读的 Markdown(不追求严格 schema)
|
|
21
|
-
- 落盘到按 `prNumber + round + runId` 命名的文件
|
|
22
|
-
- 返回“单一 JSON 对象”,只包含文件路径等元信息
|
|
12
|
+
为 PR Review Loop 构建上下文文件(Markdown)。确定性工作由脚本完成。
|
|
23
13
|
|
|
24
14
|
## 输入要求(强制)
|
|
25
15
|
|
|
@@ -28,168 +18,18 @@ tools:
|
|
|
28
18
|
- PR 编号(如:`PR #123` 或 `prNumber: 123`)
|
|
29
19
|
- round(如:`round: 1`;无则默认 1)
|
|
30
20
|
|
|
31
|
-
## 允许/禁止
|
|
32
|
-
|
|
33
|
-
- ✅ 允许使用 `gh` 只读获取 PR 信息与评论
|
|
34
|
-
- ✅ 允许使用 `git` 获取修改文件清单(推荐)
|
|
35
|
-
- ✅ 允许写入缓存文件到 `~/.opencode/cache/`
|
|
36
|
-
- ✅ 允许使用本地脚本(python)拼接/裁剪内容
|
|
37
|
-
- ⛔ 禁止修改业务代码(只允许写入 `~/.opencode/cache/`)
|
|
38
|
-
- ⛔ 禁止发布 GitHub 评论(不调用 `gh pr comment/review`)
|
|
39
|
-
- ⛔ 禁止 push/force push/rebase
|
|
40
|
-
|
|
41
21
|
## 输出(强制)
|
|
42
22
|
|
|
43
|
-
|
|
23
|
+
脚本会写入 `~/.opencode/cache/`,stdout 只输出单一 JSON(可 `JSON.parse()`)。
|
|
44
24
|
|
|
45
|
-
|
|
46
|
-
type PRContextBuildResult = {
|
|
47
|
-
agent: 'pr-context'
|
|
48
|
-
prNumber: number
|
|
49
|
-
round: number
|
|
50
|
-
runId: string
|
|
51
|
-
repo: { nameWithOwner: string }
|
|
52
|
-
headOid: string
|
|
53
|
-
existingMarkerCount?: number
|
|
54
|
-
contextFile: string
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## 生成规则(强制)
|
|
25
|
+
## Cache 约定(强制)
|
|
59
26
|
|
|
60
|
-
1. 假设已完成 pr-precheck(gh 已认证、PR 可访问、当前分支已切到 PR head 分支、工作区可用)
|
|
61
|
-
2. 获取 PR 元信息(title/body/labels/base/head oid/ref/url/isDraft)
|
|
62
|
-
3. 获取修改文件清单(优先用 git diff 与 baseRefName 对比;不包含 patch)
|
|
63
|
-
4. 获取评论:最多最近 10 条,正文截断 300 字符
|
|
64
|
-
5. 生成 runId:必须包含 prNumber 与 round;使用 `sha1(prNumber:round:headOid)` 的前 12 位(不使用时间)
|
|
65
|
-
6. 写入 `~/.opencode/cache/pr-context-pr<PR_NUMBER>-r<ROUND>-<RUN_ID>.md`
|
|
66
|
-
7. 上下文文件内容必须包含:
|
|
67
27
|
|
|
68
|
-
- PR 基本信息(repo/pr/url/base/head/headOid/labels)
|
|
69
|
-
- Title / Body 摘要
|
|
70
|
-
- 变更文件清单(每文件 additions/deletions)
|
|
71
|
-
- 最近评论摘要
|
|
72
|
-
- 历史 marker 计数(用于提示是否已跑过 loop)
|
|
73
28
|
|
|
74
|
-
##
|
|
29
|
+
## 调用脚本(强制)
|
|
75
30
|
|
|
76
|
-
|
|
31
|
+
脚本位置:`~/.opencode/agents/pr_context.py`
|
|
77
32
|
|
|
78
33
|
```bash
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
mkdir -p "$HOME/.opencode/cache"
|
|
82
|
-
|
|
83
|
-
OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
|
|
84
|
-
|
|
85
|
-
PR_JSON=$(gh pr view "$PR_NUMBER" --repo "$OWNER_REPO" \
|
|
86
|
-
--json number,url,title,body,isDraft,labels,baseRefName,headRefName,baseRefOid,headRefOid,comments)
|
|
87
|
-
|
|
88
|
-
BASE_REF=$(echo "$PR_JSON" | python3 -c 'import json,sys;print(json.load(sys.stdin).get("baseRefName") or "")')
|
|
89
|
-
test -n "$BASE_REF" || BASE_REF="main"
|
|
90
|
-
|
|
91
|
-
git fetch origin "$BASE_REF" > /dev/null 2>&1 || true
|
|
92
|
-
FILES_TXT=$(git diff --name-status "origin/$BASE_REF...HEAD" 2>/dev/null || git diff --name-status "$BASE_REF...HEAD" 2>/dev/null || true)
|
|
93
|
-
|
|
94
|
-
OWNER_REPO="$OWNER_REPO" PR_NUMBER="$PR_NUMBER" ROUND="$ROUND" PR_JSON="$PR_JSON" FILES_TXT="$FILES_TXT" \
|
|
95
|
-
python3 - <<'PY'
|
|
96
|
-
import json, os, hashlib
|
|
97
|
-
|
|
98
|
-
pr_number = int(os.environ['PR_NUMBER'])
|
|
99
|
-
round_num = int(os.environ.get('ROUND') or '1')
|
|
100
|
-
owner_repo = os.environ['OWNER_REPO']
|
|
101
|
-
pr = json.loads(os.environ['PR_JSON'])
|
|
102
|
-
files_txt = os.environ.get('FILES_TXT') or ''
|
|
103
|
-
|
|
104
|
-
head_oid = pr.get('headRefOid') or ''
|
|
105
|
-
run_seed = f"{pr_number}:{round_num}:{head_oid}".encode('utf-8')
|
|
106
|
-
run_id = hashlib.sha1(run_seed).hexdigest()[:12]
|
|
107
|
-
|
|
108
|
-
def clip(s, n):
|
|
109
|
-
if s is None:
|
|
110
|
-
return ''
|
|
111
|
-
s = str(s)
|
|
112
|
-
return s if len(s) <= n else (s[:n] + '...')
|
|
113
|
-
|
|
114
|
-
labels = [l.get('name') for l in (pr.get('labels') or []) if isinstance(l, dict) and l.get('name')]
|
|
115
|
-
|
|
116
|
-
dir_path = os.path.join(os.path.expanduser('~'), '.opencode', 'cache')
|
|
117
|
-
os.makedirs(dir_path, exist_ok=True)
|
|
118
|
-
context_file = os.path.join(dir_path, f"pr-context-pr{pr_number}-r{round_num}-{run_id}.md")
|
|
119
|
-
|
|
120
|
-
base_ref = pr.get('baseRefName') or ''
|
|
121
|
-
head_ref = pr.get('headRefName') or ''
|
|
122
|
-
url = pr.get('url') or ''
|
|
123
|
-
|
|
124
|
-
file_rows = []
|
|
125
|
-
for line in files_txt.splitlines():
|
|
126
|
-
parts = line.split('\t')
|
|
127
|
-
if not parts:
|
|
128
|
-
continue
|
|
129
|
-
status = parts[0].strip()
|
|
130
|
-
path = parts[-1].strip() if len(parts) >= 2 else ''
|
|
131
|
-
if not path:
|
|
132
|
-
continue
|
|
133
|
-
file_rows.append((status, path))
|
|
134
|
-
|
|
135
|
-
comments = pr.get('comments') or []
|
|
136
|
-
recent = comments[-10:] if isinstance(comments, list) else []
|
|
137
|
-
|
|
138
|
-
with open(context_file, 'w', encoding='utf-8', newline='\n') as fp:
|
|
139
|
-
fp.write('# PR Context\n\n')
|
|
140
|
-
fp.write(f"- Repo: {owner_repo}\n")
|
|
141
|
-
fp.write(f"- PR: #{pr_number} {url}\n")
|
|
142
|
-
fp.write(f"- Round: {round_num}\n")
|
|
143
|
-
fp.write(f"- RunId: {run_id}\n")
|
|
144
|
-
fp.write(f"- Base: {base_ref}\n")
|
|
145
|
-
fp.write(f"- Head: {head_ref}\n")
|
|
146
|
-
fp.write(f"- HeadOid: {head_oid}\n")
|
|
147
|
-
fp.write(f"- Draft: {pr.get('isDraft')}\n")
|
|
148
|
-
marker = '<!-- pr-review-loop-marker'
|
|
149
|
-
marker_count = 0
|
|
150
|
-
for c in recent:
|
|
151
|
-
if not isinstance(c, dict):
|
|
152
|
-
continue
|
|
153
|
-
body = c.get('body') or ''
|
|
154
|
-
if isinstance(body, str) and marker in body:
|
|
155
|
-
marker_count += 1
|
|
156
|
-
|
|
157
|
-
fp.write(f"- Labels: {', '.join(labels) if labels else '(none)'}\n")
|
|
158
|
-
fp.write(f"- ExistingLoopMarkers: {marker_count}\n\n")
|
|
159
|
-
|
|
160
|
-
fp.write('## Title\n\n')
|
|
161
|
-
fp.write(clip(pr.get('title') or '', 200) + '\n\n')
|
|
162
|
-
|
|
163
|
-
fp.write('## Body (excerpt)\n\n')
|
|
164
|
-
fp.write(clip(pr.get('body') or '', 2000) or '(empty)')
|
|
165
|
-
fp.write('\n\n')
|
|
166
|
-
|
|
167
|
-
fp.write(f"## Changed Files ({len(file_rows)})\n\n")
|
|
168
|
-
for (status, path) in file_rows:
|
|
169
|
-
fp.write(f"- {status} {path}\n")
|
|
170
|
-
fp.write('\n')
|
|
171
|
-
|
|
172
|
-
fp.write('## Recent Comments (excerpt)\n\n')
|
|
173
|
-
if recent:
|
|
174
|
-
for c in recent:
|
|
175
|
-
if not isinstance(c, dict):
|
|
176
|
-
continue
|
|
177
|
-
author = (c.get('author') or {}).get('login') if isinstance(c.get('author'), dict) else None
|
|
178
|
-
fp.write(f"- {author or 'unknown'}: {clip(c.get('body') or '', 300)}\n")
|
|
179
|
-
else:
|
|
180
|
-
fp.write('(none)\n')
|
|
181
|
-
|
|
182
|
-
result = {
|
|
183
|
-
'agent': 'pr-context',
|
|
184
|
-
'prNumber': pr_number,
|
|
185
|
-
'round': round_num,
|
|
186
|
-
'runId': run_id,
|
|
187
|
-
'repo': {'nameWithOwner': owner_repo},
|
|
188
|
-
'headOid': head_oid,
|
|
189
|
-
'existingMarkerCount': marker_count,
|
|
190
|
-
'contextFile': context_file,
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
print(json.dumps(result, ensure_ascii=True))
|
|
194
|
-
PY
|
|
34
|
+
python3 ~/.opencode/agents/pr_context.py --pr <PR_NUMBER> --round <ROUND>
|
|
195
35
|
```
|
|
@@ -19,16 +19,20 @@ tools:
|
|
|
19
19
|
| -------------- | ------------------------------------------------------------------------ |
|
|
20
20
|
| **角色** | 代码修复 Specialist(执行层) |
|
|
21
21
|
| **上下文隔离** | 仅处理问题列表;不重新获取评审意见(默认不调用 `gh` 拉取 PR 上下文) |
|
|
22
|
-
| **输入** | PR 编号 + `fixFile`(Markdown
|
|
23
|
-
| **输出** | fixReportFile(Markdown
|
|
22
|
+
| **输入** | PR 编号 + `fixFile`(Markdown 文件名,Structured Handoff) |
|
|
23
|
+
| **输出** | fixReportFile(Markdown 文件名) |
|
|
24
24
|
| **边界** | ✅ 可修改代码、提交并推送;⛔ 不发布 GitHub 评论(由 Orchestrator 负责) |
|
|
25
25
|
|
|
26
26
|
## 前置条件
|
|
27
27
|
|
|
28
|
+
### Cache 约定(强制)
|
|
29
|
+
- 本流程所有中间文件都存放在 `~/.opencode/cache/`
|
|
30
|
+
- agent/命令之间仅传递文件名(basename),不传目录
|
|
31
|
+
|
|
28
32
|
### 必需输入
|
|
29
33
|
|
|
30
34
|
- **PR 编号**:调用者必须在 prompt 中明确提供(如:`请修复 PR #123`)
|
|
31
|
-
- **fixFile**:调用者必须在 prompt
|
|
35
|
+
- **fixFile**:调用者必须在 prompt 中提供问题清单文件名(basename)(Structured Handoff)
|
|
32
36
|
|
|
33
37
|
### 失败快速退出
|
|
34
38
|
|
|
@@ -122,11 +126,12 @@ Round: 2
|
|
|
122
126
|
|
|
123
127
|
## 输出(强制)
|
|
124
128
|
|
|
125
|
-
|
|
129
|
+
写入:`fix-report-pr<PR_NUMBER>-r<ROUND>-<RUN_ID>.md`
|
|
126
130
|
|
|
127
131
|
最终只输出一行:
|
|
128
132
|
|
|
129
|
-
`fixReportFile: <
|
|
133
|
+
`fixReportFile: <filename>`
|
|
134
|
+
|
|
130
135
|
|
|
131
136
|
## fixReportFile 内容格式(强制)
|
|
132
137
|
|
|
@@ -167,4 +172,4 @@ Rejected: <n>
|
|
|
167
172
|
## 输出有效性保证
|
|
168
173
|
|
|
169
174
|
- fixReportFile 必须成功写入
|
|
170
|
-
- stdout 只能输出一行 `fixReportFile: <
|
|
175
|
+
- stdout 只能输出一行 `fixReportFile: <filename>`
|