@ranger1/dx 0.1.41 → 0.1.43
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/pr-review-aggregate.md +2 -2
- package/@opencode/agents/pr_context.py +41 -6
- package/@opencode/agents/pr_precheck.py +3 -12
- package/@opencode/commands/doctor.md +30 -2
- package/@opencode/commands/git-commit-and-pr.md +4 -2
- package/@opencode/commands/oh_attach.json +9 -9
- package/@opencode/commands/opencode_attach.json +2 -2
- package/@opencode/commands/pr-review-loop.md +6 -0
- package/lib/worktree.js +1 -1
- package/package.json +1 -1
|
Binary file
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: aggregate PR reviews + create fix file
|
|
3
3
|
mode: subagent
|
|
4
|
-
model:
|
|
4
|
+
model: github-copilot/claude-sonnet-4.5
|
|
5
5
|
temperature: 0.1
|
|
6
6
|
tools:
|
|
7
7
|
bash: true
|
|
@@ -133,7 +133,7 @@ python3 ~/.opencode/agents/pr_review_aggregate.py \
|
|
|
133
133
|
- 禁止:前后空行
|
|
134
134
|
- **失败/异常时**:
|
|
135
135
|
- 若脚本 stdout 已输出合法 JSON(包含 `error` 或其他字段)→ 仍然**原样返回该 JSON**。
|
|
136
|
-
- 若脚本未输出合法 JSON / 退出异常 →
|
|
136
|
+
- 若脚本未输出合法 JSON / 退出异常 → 仅返回一行 JSON:`{"error":"PR_REVIEW_AGGREGATE_AGENT_FAILED"}`(必要时可加 `detail` 字段)。
|
|
137
137
|
|
|
138
138
|
## fixFile 结构(补充说明)
|
|
139
139
|
|
|
@@ -116,9 +116,37 @@ def _git_fetch_origin(ref):
|
|
|
116
116
|
subprocess.run(["git", "fetch", "origin", ref], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
117
117
|
|
|
118
118
|
|
|
119
|
-
def
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
def _gh_default_branch(owner_repo):
|
|
120
|
+
if not owner_repo:
|
|
121
|
+
return ""
|
|
122
|
+
rc, out, _ = _run_capture(
|
|
123
|
+
[
|
|
124
|
+
"gh",
|
|
125
|
+
"repo",
|
|
126
|
+
"view",
|
|
127
|
+
"--repo",
|
|
128
|
+
owner_repo,
|
|
129
|
+
"--json",
|
|
130
|
+
"defaultBranchRef",
|
|
131
|
+
"--jq",
|
|
132
|
+
".defaultBranchRef.name",
|
|
133
|
+
]
|
|
134
|
+
)
|
|
135
|
+
if rc != 0:
|
|
136
|
+
return ""
|
|
137
|
+
return (out or "").strip()
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _git_numstat(base_ref, base_oid):
|
|
141
|
+
# Prefer commit-oid diff when available; it's unambiguous for stacked PRs.
|
|
142
|
+
candidates = []
|
|
143
|
+
if base_oid:
|
|
144
|
+
candidates.append(f"{base_oid}...HEAD")
|
|
145
|
+
if base_ref:
|
|
146
|
+
candidates.append(f"origin/{base_ref}...HEAD")
|
|
147
|
+
candidates.append(f"{base_ref}...HEAD")
|
|
148
|
+
|
|
149
|
+
for lhs in candidates:
|
|
122
150
|
rc, out, _ = _run_capture(["git", "diff", "--numstat", lhs])
|
|
123
151
|
if rc == 0:
|
|
124
152
|
return out
|
|
@@ -205,15 +233,22 @@ def main(argv):
|
|
|
205
233
|
return 1
|
|
206
234
|
|
|
207
235
|
head_oid = (pr.get("headRefOid") or "").strip()
|
|
208
|
-
|
|
236
|
+
base_oid = (pr.get("baseRefOid") or "").strip()
|
|
237
|
+
base_ref = (pr.get("baseRefName") or "").strip()
|
|
238
|
+
if not base_ref:
|
|
239
|
+
base_ref = _gh_default_branch(owner_repo)
|
|
240
|
+
if not base_ref and not base_oid:
|
|
241
|
+
_json_out({"error": "PR_BASE_REF_NOT_FOUND"})
|
|
242
|
+
return 1
|
|
209
243
|
head_ref = (pr.get("headRefName") or "").strip()
|
|
210
244
|
url = (pr.get("url") or "").strip()
|
|
211
245
|
|
|
212
246
|
seed = f"{pr_number}:{round_num}:{head_oid}".encode("utf-8")
|
|
213
247
|
run_id = hashlib.sha1(seed).hexdigest()[:12]
|
|
214
248
|
|
|
215
|
-
|
|
216
|
-
|
|
249
|
+
if base_ref:
|
|
250
|
+
_git_fetch_origin(base_ref)
|
|
251
|
+
file_rows = _parse_numstat(_git_numstat(base_ref, base_oid))
|
|
217
252
|
|
|
218
253
|
labels = []
|
|
219
254
|
for l in (pr.get("labels") or []):
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# - Verify GitHub auth (gh)
|
|
5
5
|
# - Read PR info (headRefName/baseRefName/mergeable)
|
|
6
6
|
# - Checkout PR branch (gh pr checkout) if needed
|
|
7
|
-
# - Fetch base branch (origin/<base
|
|
7
|
+
# - Fetch base branch (origin/<base>)
|
|
8
8
|
# - If mergeable == CONFLICTING: return {"error":"PR_MERGE_CONFLICTS_UNRESOLVED"}
|
|
9
9
|
# - Run dx cache clear
|
|
10
10
|
# - Run dx lint and dx build all concurrently
|
|
@@ -227,17 +227,8 @@ def main():
|
|
|
227
227
|
return 1
|
|
228
228
|
|
|
229
229
|
if run(["git", "fetch", "origin", base]) != 0:
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if fallback == base:
|
|
233
|
-
continue
|
|
234
|
-
if run(["git", "fetch", "origin", fallback]) == 0:
|
|
235
|
-
base = fallback
|
|
236
|
-
ok = True
|
|
237
|
-
break
|
|
238
|
-
if not ok:
|
|
239
|
-
print(json.dumps({"error": "PR_BASE_REF_FETCH_FAILED"}))
|
|
240
|
-
return 1
|
|
230
|
+
print(json.dumps({"error": "PR_BASE_REF_FETCH_FAILED", "baseRefName": base}))
|
|
231
|
+
return 1
|
|
241
232
|
|
|
242
233
|
if mergeable == "CONFLICTING":
|
|
243
234
|
print(json.dumps({"error": "PR_MERGE_CONFLICTS_UNRESOLVED"}))
|
|
@@ -18,13 +18,14 @@ pnpm add -g @ranger1/dx@latest && dx initial
|
|
|
18
18
|
|
|
19
19
|
## Step 1: 并行检测
|
|
20
20
|
|
|
21
|
-
**同时执行以下
|
|
21
|
+
**同时执行以下 5 个 Bash 调用(真正并行):**
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
24
|
# 批次 1: CLI 版本检测
|
|
25
25
|
echo "=== CLI_VERSIONS ===";
|
|
26
26
|
echo "opencode:" && (which opencode && opencode --version 2>/dev/null || echo "NOT_FOUND");
|
|
27
27
|
echo "dx:" && (which dx && dx --version 2>/dev/null || echo "NOT_FOUND");
|
|
28
|
+
echo "rg:" && (which rg && rg --version 2>/dev/null | head -n 1 || echo "NOT_FOUND");
|
|
28
29
|
echo "agent-browser:" && (which agent-browser && agent-browser --version 2>/dev/null || echo "NOT_FOUND");
|
|
29
30
|
```
|
|
30
31
|
|
|
@@ -65,6 +66,7 @@ echo "python:" && (which python && python --version 2>/dev/null || echo "NOT_FOU
|
|
|
65
66
|
工具 | 状态 | 版本
|
|
66
67
|
opencode | <状态> | <版本>
|
|
67
68
|
dx | <状态> | <版本>
|
|
69
|
+
rg | <状态> | <版本>
|
|
68
70
|
python3 | <状态> | <版本>
|
|
69
71
|
python(软链接) | <状态> | <版本>
|
|
70
72
|
AGENTS.md | <状态> | -
|
|
@@ -82,7 +84,7 @@ attach(全局配置写入) | <状态> | -
|
|
|
82
84
|
|
|
83
85
|
`AskUserQuestion`: 检测到以下缺失项,是否自动安装/配置所有?
|
|
84
86
|
|
|
85
|
-
|
|
87
|
+
确认后按顺序处理(需要直接执行对应安装/配置命令,不要只输出提示):
|
|
86
88
|
|
|
87
89
|
### 3.1 opencode CLI 未安装
|
|
88
90
|
|
|
@@ -100,6 +102,32 @@ brew install opencode || npm install -g opencode
|
|
|
100
102
|
- AGENTS.md 文件不存在,OpenCode 需要此文件作为项目指令入口
|
|
101
103
|
- 建议创建或检查文件路径
|
|
102
104
|
|
|
105
|
+
### 3.3 rg(ripgrep)未安装
|
|
106
|
+
|
|
107
|
+
执行安装(幂等:已安装会跳过;缺少包管理器会报错并提示手动安装):
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
set -e
|
|
111
|
+
|
|
112
|
+
if command -v rg >/dev/null 2>&1; then
|
|
113
|
+
rg --version 2>/dev/null | head -n 1 || true
|
|
114
|
+
exit 0
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
if command -v brew >/dev/null 2>&1; then
|
|
118
|
+
brew install ripgrep
|
|
119
|
+
elif command -v apt-get >/dev/null 2>&1; then
|
|
120
|
+
sudo apt-get update
|
|
121
|
+
sudo apt-get install -y ripgrep
|
|
122
|
+
else
|
|
123
|
+
echo "ripgrep (rg) NOT_FOUND, and no supported package manager (brew/apt-get) detected"
|
|
124
|
+
echo "Please install ripgrep manually: https://github.com/BurntSushi/ripgrep#installation"
|
|
125
|
+
exit 1
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
rg --version 2>/dev/null | head -n 1 || true
|
|
129
|
+
```
|
|
130
|
+
|
|
103
131
|
### 3.6 agent-browser 未安装
|
|
104
132
|
|
|
105
133
|
执行安装:
|
|
@@ -223,8 +223,10 @@ git push -u origin HEAD
|
|
|
223
223
|
#### 4.2 分析变更
|
|
224
224
|
|
|
225
225
|
```bash
|
|
226
|
-
|
|
227
|
-
git
|
|
226
|
+
# 优先使用 origin/HEAD(远端默认分支),避免硬编码 main/master。
|
|
227
|
+
# 如需指定基准分支,使用:/git-commit-and-pr --pr --base <BRANCH>
|
|
228
|
+
git log origin/HEAD..HEAD --oneline
|
|
229
|
+
git diff origin/HEAD...HEAD --stat
|
|
228
230
|
```
|
|
229
231
|
|
|
230
232
|
#### 4.3 创建 PR
|
|
@@ -7,18 +7,18 @@
|
|
|
7
7
|
},
|
|
8
8
|
"agents": {
|
|
9
9
|
"sisyphus": {
|
|
10
|
-
"model": "openai/gpt-5.
|
|
10
|
+
"model": "openai/gpt-5.3-codex",
|
|
11
11
|
"variant": "none"
|
|
12
12
|
},
|
|
13
13
|
"oracle": {
|
|
14
|
-
"model": "openai/gpt-5.
|
|
14
|
+
"model": "openai/gpt-5.3-codex",
|
|
15
15
|
"variant": "high"
|
|
16
16
|
},
|
|
17
17
|
"librarian": {
|
|
18
|
-
"model": "
|
|
18
|
+
"model": "openai/gpt-5.1-codex-mini"
|
|
19
19
|
},
|
|
20
20
|
"explore": {
|
|
21
|
-
"model": "
|
|
21
|
+
"model": "openai/gpt-5.1-codex-mini"
|
|
22
22
|
},
|
|
23
23
|
"multimodal-looker": {
|
|
24
24
|
"model": "github-copilot/gemini-3-flash-preview"
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
"variant": "medium"
|
|
37
37
|
},
|
|
38
38
|
"atlas": {
|
|
39
|
-
"model": "openai/gpt-5.
|
|
39
|
+
"model": "openai/gpt-5.3-codex"
|
|
40
40
|
},
|
|
41
41
|
"codex-reviewer": {
|
|
42
|
-
"model": "openai/gpt-5.
|
|
42
|
+
"model": "openai/gpt-5.3-codex",
|
|
43
43
|
"variant": "xhigh",
|
|
44
44
|
"temperature": 0.1
|
|
45
45
|
},
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"variant": "high"
|
|
65
65
|
},
|
|
66
66
|
"ultrabrain": {
|
|
67
|
-
"model": "openai/gpt-5.
|
|
67
|
+
"model": "openai/gpt-5.3-codex",
|
|
68
68
|
"variant": "xhigh"
|
|
69
69
|
},
|
|
70
70
|
"artistry": {
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"variant": "max"
|
|
73
73
|
},
|
|
74
74
|
"quick": {
|
|
75
|
-
"model": "
|
|
75
|
+
"model": "openai/gpt-5.1-codex-mini"
|
|
76
76
|
},
|
|
77
77
|
"middle": {
|
|
78
78
|
"model": "github-copilot/claude-sonnet-4.5"
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"variant": "medium"
|
|
83
83
|
},
|
|
84
84
|
"unspecified-high": {
|
|
85
|
-
"model": "openai/gpt-5.
|
|
85
|
+
"model": "openai/gpt-5.3-codex",
|
|
86
86
|
"variant": "medium"
|
|
87
87
|
},
|
|
88
88
|
"writing": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
],
|
|
11
11
|
"agent": {
|
|
12
12
|
"quick": {
|
|
13
|
-
"model": "
|
|
13
|
+
"model": "openai/gpt-5.1-codex-mini"
|
|
14
14
|
},
|
|
15
15
|
"middle": {
|
|
16
16
|
"model": "github-copilot/claude-sonnet-4.5"
|
|
@@ -22,5 +22,5 @@
|
|
|
22
22
|
"*.env.*": "allow"
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
|
-
"model": "openai/gpt-5.
|
|
25
|
+
"model": "openai/gpt-5.3-codex"
|
|
26
26
|
}
|
|
@@ -6,6 +6,12 @@ agent: sisyphus
|
|
|
6
6
|
|
|
7
7
|
# PR Review Loop
|
|
8
8
|
|
|
9
|
+
## Stacked PR / PR -> PR(重要)
|
|
10
|
+
|
|
11
|
+
- 本流程的 diff 基准来自 GitHub PR 元数据的 `baseRefName`(不是硬编码 main/master),因此天然支持“PR 合并到另一个 PR 分支”的 stacked PR。
|
|
12
|
+
- 当 `baseRefName` 缺失时:会回退到仓库默认分支(`defaultBranchRef.name`)。
|
|
13
|
+
- 当 base 分支 fetch 失败时:会直接报错终止(不再静默回退到 main/master),避免 review/changed-files 基准悄悄跑偏。
|
|
14
|
+
|
|
9
15
|
## 输入
|
|
10
16
|
|
|
11
17
|
- `{{PR_NUMBER}}`
|
package/lib/worktree.js
CHANGED
|
@@ -685,7 +685,7 @@ class WorktreeManager {
|
|
|
685
685
|
|
|
686
686
|
// 检查未推送的提交
|
|
687
687
|
const unpushed = execSync(
|
|
688
|
-
`git log origin/${branchName}..${branchName} --oneline 2>/dev/null || git log origin/
|
|
688
|
+
`git log origin/${branchName}..${branchName} --oneline 2>/dev/null || git log origin/HEAD..${branchName} --oneline`,
|
|
689
689
|
).toString()
|
|
690
690
|
if (unpushed.trim()) {
|
|
691
691
|
hasUnpushedCommits = true
|