@ranger1/dx 0.1.48 → 0.1.49
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/__pycache__/test_pr_review_aggregate.cpython-314-pytest-9.0.2.pyc +0 -0
- package/@opencode/agents/__pycache__/test_pr_review_aggregate.cpython-314.pyc +0 -0
- package/@opencode/agents/claude-reviewer.md +6 -2
- package/@opencode/agents/codex-reviewer.md +6 -2
- package/@opencode/agents/gemini-reviewer.md +6 -2
- package/@opencode/agents/gh-thread-reviewer.md +6 -1
- package/@opencode/agents/pr-context.md +12 -0
- package/@opencode/agents/pr-fix.md +6 -1
- package/@opencode/agents/pr-precheck.md +4 -2
- package/@opencode/agents/pr-review-aggregate.md +18 -10
- package/@opencode/agents/pr_context.py +35 -19
- package/@opencode/agents/pr_precheck.py +210 -42
- package/@opencode/agents/test_pr_review_aggregate.py +234 -33
- package/@opencode/commands/pr-review-loop.md +61 -11
- package/package.json +1 -1
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -14,7 +14,7 @@ tools:
|
|
|
14
14
|
|
|
15
15
|
- `PR #<number>`
|
|
16
16
|
- `round: <number>`
|
|
17
|
-
- `runId: <string
|
|
17
|
+
- `runId: <string>`(必须透传,格式 `<PR>-<ROUND>-<HEAD_SHORT>`,禁止自行生成)
|
|
18
18
|
- `contextFile: <filename>`
|
|
19
19
|
|
|
20
20
|
## 输出(强制)
|
|
@@ -40,7 +40,11 @@ tools:
|
|
|
40
40
|
- 若你的发现 priority 比原问题高 ≥2 级(如 P3→P1, P2→P0),可以升级质疑
|
|
41
41
|
- 否则不再提出
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
4. **文件一致性**:
|
|
44
|
+
- 匹配 Decision Log 时,**必须检查 `file` 字段是否与当前 finding 的文件一致**。
|
|
45
|
+
- 若 decision-log 中的 `file` 与当前文件不一致(包括重命名、移动、删除),则**视为不同问题**,不进行 essence 匹配(即作为新问题处理)。
|
|
46
|
+
- 若 decision-log 条目缺少 `file` 字段,也视为不匹配。
|
|
47
|
+
|
|
44
48
|
|
|
45
49
|
### 禁止事项
|
|
46
50
|
- ⛔ 不质疑已修复问题的实现方式(除非发现修复引入了新 bug)
|
|
@@ -15,7 +15,7 @@ tools:
|
|
|
15
15
|
|
|
16
16
|
- `PR #<number>`
|
|
17
17
|
- `round: <number>`
|
|
18
|
-
- `runId: <string
|
|
18
|
+
- `runId: <string>`(必须透传,格式 `<PR>-<ROUND>-<HEAD_SHORT>`,禁止自行生成)
|
|
19
19
|
- `contextFile: <filename>`
|
|
20
20
|
|
|
21
21
|
## 输出(强制)
|
|
@@ -41,7 +41,11 @@ tools:
|
|
|
41
41
|
- 若你的发现 priority 比原问题高 ≥2 级(如 P3→P1, P2→P0),可以升级质疑
|
|
42
42
|
- 否则不再提出
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
4. **文件一致性**:
|
|
45
|
+
- 匹配 Decision Log 时,**必须检查 `file` 字段是否与当前 finding 的文件一致**。
|
|
46
|
+
- 若 decision-log 中的 `file` 与当前文件不一致(包括重命名、移动、删除),则**视为不同问题**,不进行 essence 匹配(即作为新问题处理)。
|
|
47
|
+
- 若 decision-log 条目缺少 `file` 字段,也视为不匹配。
|
|
48
|
+
|
|
45
49
|
|
|
46
50
|
### 禁止事项
|
|
47
51
|
- ⛔ 不质疑已修复问题的实现方式(除非发现修复引入了新 bug)
|
|
@@ -14,7 +14,7 @@ tools:
|
|
|
14
14
|
|
|
15
15
|
- `PR #<number>`
|
|
16
16
|
- `round: <number>`
|
|
17
|
-
- `runId: <string
|
|
17
|
+
- `runId: <string>`(必须透传,格式 `<PR>-<ROUND>-<HEAD_SHORT>`,禁止自行生成)
|
|
18
18
|
- `contextFile: <filename>`
|
|
19
19
|
|
|
20
20
|
## 输出(强制)
|
|
@@ -40,7 +40,11 @@ tools:
|
|
|
40
40
|
- 若你的发现 priority 比原问题高 ≥2 级(如 P3→P1, P2→P0),可以升级质疑
|
|
41
41
|
- 否则不再提出
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
4. **文件一致性**:
|
|
44
|
+
- 匹配 Decision Log 时,**必须检查 `file` 字段是否与当前 finding 的文件一致**。
|
|
45
|
+
- 若 decision-log 中的 `file` 与当前文件不一致(包括重命名、移动、删除),则**视为不同问题**,不进行 essence 匹配(即作为新问题处理)。
|
|
46
|
+
- 若 decision-log 条目缺少 `file` 字段,也视为不匹配。
|
|
47
|
+
|
|
44
48
|
|
|
45
49
|
### 禁止事项
|
|
46
50
|
- ⛔ 不质疑已修复问题的实现方式(除非发现修复引入了新 bug)
|
|
@@ -17,7 +17,7 @@ Harvest all GitHub PR review feedback (humans + bots, including Copilot) and nor
|
|
|
17
17
|
|
|
18
18
|
- `PR #<number>`
|
|
19
19
|
- `round: <number>`
|
|
20
|
-
- `runId: <string
|
|
20
|
+
- `runId: <string>`(必须透传,格式 `<PR>-<ROUND>-<HEAD_SHORT>`,禁止自行生成)
|
|
21
21
|
- `contextFile: <filename>`
|
|
22
22
|
|
|
23
23
|
## Cache 约定(强制)
|
|
@@ -110,6 +110,11 @@ python3 ~/.opencode/agents/gh_review_harvest.py \
|
|
|
110
110
|
- 若你的发现 priority 比原问题高 ≥2 级(如 P3→P1, P2→P0),可以升级质疑
|
|
111
111
|
- 否则不再提出
|
|
112
112
|
|
|
113
|
+
3. **文件一致性**:
|
|
114
|
+
- 匹配 Decision Log 时,**必须检查 `file` 字段是否与当前 finding 的文件一致**。
|
|
115
|
+
- 若 decision-log 中的 `file` 与当前文件不一致(包括重命名、移动、删除),则**视为不同问题**,不进行 essence 匹配(即作为新问题处理)。
|
|
116
|
+
- 若 decision-log 条目缺少 `file` 字段,也视为不匹配。
|
|
117
|
+
|
|
113
118
|
判断"问题本质相同"时,比对 decision-log 中的 `essence` 字段与你发现的问题描述。
|
|
114
119
|
|
|
115
120
|
### 禁止事项
|
|
@@ -18,6 +18,16 @@ tools:
|
|
|
18
18
|
- PR 编号(如:`PR #123` 或 `prNumber: 123`)
|
|
19
19
|
- round(如:`round: 1`;无则默认 1)
|
|
20
20
|
|
|
21
|
+
## 唯一标识 runId(强制)
|
|
22
|
+
|
|
23
|
+
- 脚本必须生成全局唯一标识 `runId`:`<PR>-<ROUND>-<HEAD_SHORT>`
|
|
24
|
+
- 其中:
|
|
25
|
+
- `<PR>`:PR 编号
|
|
26
|
+
- `<ROUND>`:当前轮次
|
|
27
|
+
- `<HEAD_SHORT>`:`headOid` 的前 7 位(git rev-parse --short HEAD)
|
|
28
|
+
- `runId` 必须包含在返回的 JSON 中,供后续步骤使用。
|
|
29
|
+
|
|
30
|
+
|
|
21
31
|
## 输出(强制)
|
|
22
32
|
|
|
23
33
|
脚本会写入项目内 `./.cache/`,stdout 只输出单一 JSON(可 `JSON.parse()`)。
|
|
@@ -25,6 +35,8 @@ tools:
|
|
|
25
35
|
## Cache 约定(强制)
|
|
26
36
|
|
|
27
37
|
- 缓存目录固定为 `./.cache/`;交接一律传 `./.cache/<file>`(repo 相对路径),禁止 basename-only(如 `foo.md`)。
|
|
38
|
+
- 文件命名:`./.cache/pr-context-pr<PR>-r<ROUND>-<RUN_ID>.md`
|
|
39
|
+
- `RUN_ID` 格式必须为 `<PR>-<ROUND>-<HEAD_SHORT>`
|
|
28
40
|
|
|
29
41
|
## 调用脚本(强制)
|
|
30
42
|
|
|
@@ -32,7 +32,7 @@ tools:
|
|
|
32
32
|
### 必需输入
|
|
33
33
|
|
|
34
34
|
- **PR 编号**:调用者必须在 prompt 中明确提供(如:`请修复 PR #123`)
|
|
35
|
-
- **runId**:调用者必须在 prompt
|
|
35
|
+
- **runId**:调用者必须在 prompt 中提供(必须透传,格式 `<PR>-<ROUND>-<HEAD_SHORT>`,禁止自行生成)
|
|
36
36
|
- **fixFile**:调用者必须在 prompt 中提供问题清单文件路径(repo 相对路径,例:`./.cache/fix-...md`)(Structured Handoff)
|
|
37
37
|
|
|
38
38
|
### 失败快速退出
|
|
@@ -154,12 +154,14 @@ PR: <PR_NUMBER>
|
|
|
154
154
|
### Fixed
|
|
155
155
|
|
|
156
156
|
- id: <FINDING_ID>
|
|
157
|
+
file: <FILE_PATH>
|
|
157
158
|
commit: <SHA>
|
|
158
159
|
essence: <问题本质的一句话描述>
|
|
159
160
|
|
|
160
161
|
### Rejected
|
|
161
162
|
|
|
162
163
|
- id: <FINDING_ID>
|
|
164
|
+
file: <FILE_PATH>
|
|
163
165
|
priority: <P0|P1|P2|P3>
|
|
164
166
|
reason: <拒绝原因>
|
|
165
167
|
essence: <问题本质的一句话描述>
|
|
@@ -170,6 +172,8 @@ PR: <PR_NUMBER>
|
|
|
170
172
|
- 如果文件不存在:创建新文件,包含 `# Decision Log` 头、`PR: <PR_NUMBER>` 字段,以及第一个 `## Round <ROUND>` 段落
|
|
171
173
|
- 如果文件存在:追加新的 `## Round <ROUND>` 段落到文件末尾
|
|
172
174
|
- **禁止删除或覆盖历史轮次的记录**
|
|
175
|
+
- **file 字段**:必须记录问题所在的文件路径(repo 相对路径)。
|
|
176
|
+
- 对于 `pr-precheck` 产生的修复,`file` 字段可填 `__precheck__`。
|
|
173
177
|
|
|
174
178
|
### essence 字段要求
|
|
175
179
|
|
|
@@ -178,6 +182,7 @@ essence 是问题本质的一句话描述,用于后续轮次的智能匹配和
|
|
|
178
182
|
- 简洁性:≤ 50 字
|
|
179
183
|
- 问题导向:描述问题核心(而非具体代码位置、文件行号)
|
|
180
184
|
- 可匹配性:后续轮次的 reviewer 能通过关键词匹配识别该问题
|
|
185
|
+
- **文件强绑定**:必须假设问题与当前文件强绑定(若文件重命名,视为不同问题)
|
|
181
186
|
|
|
182
187
|
**示例对比:**
|
|
183
188
|
|
|
@@ -16,13 +16,14 @@ tools:
|
|
|
16
16
|
## 输入(prompt 必须包含)
|
|
17
17
|
|
|
18
18
|
- `PR #<number>`
|
|
19
|
+
- `round: <number>`(默认 1)
|
|
19
20
|
|
|
20
21
|
## 一键脚本
|
|
21
22
|
|
|
22
23
|
脚本位置:`~/.opencode/agents/pr_precheck.py`
|
|
23
24
|
|
|
24
25
|
```bash
|
|
25
|
-
python3 ~/.opencode/agents/pr_precheck.py <PR_NUMBER>
|
|
26
|
+
python3 ~/.opencode/agents/pr_precheck.py --pr <PR_NUMBER> --round <ROUND>
|
|
26
27
|
```
|
|
27
28
|
|
|
28
29
|
## 脚本输出处理(强制)
|
|
@@ -30,6 +31,7 @@ python3 ~/.opencode/agents/pr_precheck.py <PR_NUMBER>
|
|
|
30
31
|
- 脚本 stdout 只会输出**单一一行 JSON**(可 `JSON.parse()`)。
|
|
31
32
|
- **成功时**:你的最终输出必须是**脚本 stdout 的那一行 JSON 原样内容**。
|
|
32
33
|
- 典型返回:`{"ok":true}` 或 `{"ok":false,"fixFile":"..."}`
|
|
34
|
+
- **重要**:如果返回 `fixFile`,请使用基于 `headOid` 的标准 runId(`<PR>-<ROUND>-<HEAD_SHORT>`)来命名文件。
|
|
33
35
|
- 禁止:解释/分析/补充文字
|
|
34
36
|
- 禁止:代码块(```)
|
|
35
37
|
- 禁止:前后空行
|
|
@@ -83,5 +85,5 @@ git commit -m "chore(pr #<PR_NUMBER>): resolve merge conflicts"
|
|
|
83
85
|
git push
|
|
84
86
|
|
|
85
87
|
# 5) 重新运行预检脚本
|
|
86
|
-
python3 ~/.opencode/agents/pr_precheck.py <PR_NUMBER>
|
|
88
|
+
python3 ~/.opencode/agents/pr_precheck.py --pr <PR_NUMBER> --round <ROUND>
|
|
87
89
|
```
|
|
@@ -19,7 +19,7 @@ tools:
|
|
|
19
19
|
|
|
20
20
|
- `PR #<number>`
|
|
21
21
|
- `round: <number>`
|
|
22
|
-
- `runId: <string
|
|
22
|
+
- `runId: <string>`(必须透传,格式 `<PR>-<ROUND>-<HEAD_SHORT>`,禁止自行生成)
|
|
23
23
|
- `contextFile: <path>`(例如:`./.cache/pr-context-...md`)
|
|
24
24
|
- `reviewFile: <path>`(多行,1+ 条;例如:`./.cache/review-...md`)
|
|
25
25
|
|
|
@@ -27,7 +27,7 @@ tools:
|
|
|
27
27
|
|
|
28
28
|
- `PR #<number>`
|
|
29
29
|
- `round: <number>`
|
|
30
|
-
- `runId: <string
|
|
30
|
+
- `runId: <string>`(必须透传,格式 `<PR>-<ROUND>-<HEAD_SHORT>`,禁止自行生成)
|
|
31
31
|
- `fixReportFile: <path>`(例如:`./.cache/fix-report-...md`)
|
|
32
32
|
|
|
33
33
|
示例:
|
|
@@ -35,11 +35,11 @@ tools:
|
|
|
35
35
|
```text
|
|
36
36
|
PR #123
|
|
37
37
|
round: 1
|
|
38
|
-
runId:
|
|
39
|
-
contextFile: ./.cache/pr-context-pr123-r1-
|
|
40
|
-
reviewFile: ./.cache/review-CDX-pr123-r1-
|
|
41
|
-
reviewFile: ./.cache/review-CLD-pr123-r1-
|
|
42
|
-
reviewFile: ./.cache/review-GMN-pr123-r1-
|
|
38
|
+
runId: 123-1-a1b2c3d
|
|
39
|
+
contextFile: ./.cache/pr-context-pr123-r1-123-1-a1b2c3d.md
|
|
40
|
+
reviewFile: ./.cache/review-CDX-pr123-r1-123-1-a1b2c3d.md
|
|
41
|
+
reviewFile: ./.cache/review-CLD-pr123-r1-123-1-a1b2c3d.md
|
|
42
|
+
reviewFile: ./.cache/review-GMN-pr123-r1-123-1-a1b2c3d.md
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
## 执行方式(强制)
|
|
@@ -65,11 +65,19 @@ runId: abcdef123456
|
|
|
65
65
|
|
|
66
66
|
如果 decision-log(`./.cache/decision-log-pr<PR_NUMBER>.md`)存在,你需要基于 LLM 判断每个新 finding 与已决策问题的本质是否相同,从而生成 **escalation_groups** 参数。
|
|
67
67
|
|
|
68
|
+
**匹配原则**:
|
|
69
|
+
- **Essence 匹配**:对比 `essence` 字段与新 finding 的问题本质。
|
|
70
|
+
- **文件强绑定**:仅当 decision-log 条目的 `file` 与新 finding 的 `file` **完全一致**时才进行匹配。
|
|
71
|
+
- 若文件被重命名/删除/拆分,视为不同问题(为了稳定性,不处理复杂的 rename 映射)。
|
|
72
|
+
- 若 decision-log 条目缺少 `file` 字段(旧数据),则跳过匹配(视为不相关)。
|
|
73
|
+
|
|
68
74
|
**流程**:
|
|
69
75
|
|
|
70
|
-
1. 读取 decision-log,提取已 rejected 问题的 `essence` 字段
|
|
71
|
-
2. 逐个新 finding
|
|
72
|
-
|
|
76
|
+
1. 读取 decision-log,提取已 rejected 问题的 `essence` 和 `file` 字段
|
|
77
|
+
2. 逐个新 finding,**先检查 file 是否匹配**
|
|
78
|
+
- 若 file 不匹配 → 视为 New Issue
|
|
79
|
+
- 若 file 匹配 → 继续对比 essence
|
|
80
|
+
3. 若 essence 也匹配("问题本质相同"):
|
|
73
81
|
4. 收集可升级的问题(重新质疑阈值):
|
|
74
82
|
- **升级阈值**:优先级差距 ≥ 2 级
|
|
75
83
|
- 例如:已 rejected P3 but finding 为 P1 → 可升级质疑
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
# - Prints exactly one JSON object to stdout
|
|
7
7
|
|
|
8
8
|
import argparse
|
|
9
|
-
import hashlib
|
|
10
9
|
import json
|
|
11
10
|
import os
|
|
12
11
|
import re
|
|
@@ -183,20 +182,28 @@ def main(argv):
|
|
|
183
182
|
pr_number = int(args.pr)
|
|
184
183
|
round_num = int(args.round)
|
|
185
184
|
|
|
185
|
+
def _json_err(error_code, extra=None):
|
|
186
|
+
obj = {"error": error_code, "prNumber": pr_number, "round": round_num}
|
|
187
|
+
if isinstance(extra, dict) and extra:
|
|
188
|
+
obj.update(extra)
|
|
189
|
+
_json_out(obj)
|
|
190
|
+
|
|
186
191
|
# Preconditions: be in a git repo and gh is authenticated.
|
|
187
192
|
rc, out, _ = _run_capture(["git", "rev-parse", "--is-inside-work-tree"])
|
|
188
193
|
if rc != 0 or out.strip() != "true":
|
|
189
|
-
|
|
194
|
+
_json_err("NOT_A_GIT_REPO")
|
|
190
195
|
return 1
|
|
191
196
|
|
|
192
197
|
host = _detect_git_remote_host() or "github.com"
|
|
193
198
|
rc, gh_out, gh_err = _run_capture(["gh", "auth", "status", "--hostname", host])
|
|
194
199
|
if rc == 127:
|
|
195
|
-
|
|
196
|
-
"
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
+
_json_err(
|
|
201
|
+
"GH_CLI_NOT_FOUND",
|
|
202
|
+
{
|
|
203
|
+
"detail": "gh not found in PATH",
|
|
204
|
+
"suggestion": "Install GitHub CLI: https://cli.github.com/",
|
|
205
|
+
},
|
|
206
|
+
)
|
|
200
207
|
return 1
|
|
201
208
|
if rc != 0:
|
|
202
209
|
# If host detection is wrong, a global check might still succeed.
|
|
@@ -207,44 +214,51 @@ def main(argv):
|
|
|
207
214
|
detail = (gh_err or gh_out or "").strip()
|
|
208
215
|
if len(detail) > 4000:
|
|
209
216
|
detail = detail[-4000:]
|
|
210
|
-
|
|
211
|
-
"
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
217
|
+
_json_err(
|
|
218
|
+
"GH_NOT_AUTHENTICATED",
|
|
219
|
+
{
|
|
220
|
+
"host": host,
|
|
221
|
+
"detail": detail,
|
|
222
|
+
"suggestion": f"Run: gh auth login --hostname {host}",
|
|
223
|
+
},
|
|
224
|
+
)
|
|
216
225
|
return 1
|
|
217
226
|
|
|
218
227
|
rc, owner_repo, _ = _run_capture(["gh", "repo", "view", "--json", "nameWithOwner", "--jq", ".nameWithOwner"])
|
|
219
228
|
owner_repo = owner_repo.strip() if rc == 0 else ""
|
|
220
229
|
if not owner_repo:
|
|
221
|
-
|
|
230
|
+
_json_err("REPO_NOT_FOUND")
|
|
222
231
|
return 1
|
|
223
232
|
|
|
224
233
|
fields = "number,url,title,body,isDraft,labels,baseRefName,headRefName,baseRefOid,headRefOid,comments"
|
|
225
234
|
rc, pr_json, _ = _run_capture(["gh", "pr", "view", str(pr_number), "--repo", owner_repo, "--json", fields])
|
|
226
235
|
if rc != 0:
|
|
227
|
-
|
|
236
|
+
_json_err("PR_NOT_FOUND_OR_NO_ACCESS")
|
|
228
237
|
return 1
|
|
229
238
|
try:
|
|
230
239
|
pr = json.loads(pr_json)
|
|
231
240
|
except Exception:
|
|
232
|
-
|
|
241
|
+
_json_err("PR_NOT_FOUND_OR_NO_ACCESS")
|
|
233
242
|
return 1
|
|
234
243
|
|
|
235
244
|
head_oid = (pr.get("headRefOid") or "").strip()
|
|
236
245
|
base_oid = (pr.get("baseRefOid") or "").strip()
|
|
237
246
|
base_ref = (pr.get("baseRefName") or "").strip()
|
|
247
|
+
|
|
248
|
+
if not head_oid:
|
|
249
|
+
_json_err("PR_HEAD_OID_NOT_FOUND")
|
|
250
|
+
return 1
|
|
251
|
+
|
|
252
|
+
head_short = head_oid[:7]
|
|
238
253
|
if not base_ref:
|
|
239
254
|
base_ref = _gh_default_branch(owner_repo)
|
|
240
255
|
if not base_ref and not base_oid:
|
|
241
|
-
|
|
256
|
+
_json_err("PR_BASE_REF_NOT_FOUND")
|
|
242
257
|
return 1
|
|
243
258
|
head_ref = (pr.get("headRefName") or "").strip()
|
|
244
259
|
url = (pr.get("url") or "").strip()
|
|
245
260
|
|
|
246
|
-
|
|
247
|
-
run_id = hashlib.sha1(seed).hexdigest()[:12]
|
|
261
|
+
run_id = f"{pr_number}-{round_num}-{head_short}"
|
|
248
262
|
|
|
249
263
|
if base_ref:
|
|
250
264
|
_git_fetch_origin(base_ref)
|
|
@@ -277,6 +291,7 @@ def main(argv):
|
|
|
277
291
|
fp.write(f"- RunId: {run_id}\n")
|
|
278
292
|
fp.write(f"- Base: {base_ref}\n")
|
|
279
293
|
fp.write(f"- Head: {head_ref}\n")
|
|
294
|
+
fp.write(f"- HeadShort: {head_short}\n")
|
|
280
295
|
fp.write(f"- HeadOid: {head_oid}\n")
|
|
281
296
|
fp.write(f"- Draft: {pr.get('isDraft')}\n")
|
|
282
297
|
fp.write(f"- Labels: {', '.join(labels) if labels else '(none)'}\n")
|
|
@@ -317,6 +332,7 @@ def main(argv):
|
|
|
317
332
|
"runId": run_id,
|
|
318
333
|
"repo": {"nameWithOwner": owner_repo},
|
|
319
334
|
"headOid": head_oid,
|
|
335
|
+
"headShort": head_short,
|
|
320
336
|
"existingMarkerCount": marker_count,
|
|
321
337
|
# Handoff should be repo-relative path so downstream agents can read it directly.
|
|
322
338
|
"contextFile": _repo_relpath(REPO_ROOT, context_path),
|