claude-dev-env 1.37.0 → 1.38.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/CLAUDE.md +3 -0
- package/_shared/pr-loop/audit-contract.md +4 -3
- package/_shared/pr-loop/fix-protocol.md +2 -0
- package/_shared/pr-loop/gh-payloads.md +38 -37
- package/_shared/pr-loop/scripts/README.md +0 -1
- package/_shared/pr-loop/scripts/preflight.py +2 -1
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +2 -2
- package/_shared/pr-loop/scripts/tests/test_preflight.py +22 -0
- package/_shared/pr-loop/state-schema.md +10 -10
- package/agents/clean-coder.md +4 -0
- package/agents/code-quality-agent.md +23 -85
- package/agents/groq-coder.md +8 -6
- package/hooks/blocking/__init__.py +0 -0
- package/hooks/blocking/hedging_language_blocker.py +2 -2
- package/hooks/blocking/state_description_blocker.py +243 -0
- package/hooks/blocking/tdd_enforcer.py +94 -0
- package/hooks/blocking/test_hedging_language_blocker.py +1 -1
- package/hooks/blocking/test_state_description_blocker.py +618 -0
- package/hooks/blocking/test_tdd_enforcer.py +152 -0
- package/hooks/config/state_description_blocker_constants.py +130 -0
- package/hooks/hooks.json +10 -0
- package/package.json +1 -1
- package/rules/gh-paginate.md +4 -50
- package/rules/no-historical-clutter.md +57 -0
- package/scripts/config/groq_bugteam_config.py +13 -5
- package/skills/bugteam/CONSTRAINTS.md +20 -27
- package/skills/bugteam/EXAMPLES.md +1 -1
- package/skills/bugteam/PROMPTS.md +78 -42
- package/skills/bugteam/SKILL.md +76 -63
- package/skills/bugteam/SKILL_EVALS.md +12 -12
- package/skills/bugteam/reference/audit-and-teammates.md +21 -48
- package/skills/bugteam/reference/audit-contract.md +7 -7
- package/skills/bugteam/reference/github-pr-reviews.md +31 -31
- package/skills/bugteam/reference/team-setup.md +1 -1
- package/skills/bugteam/reference/teardown-publish-permissions.md +4 -4
- package/skills/copilot-review/SKILL.md +7 -14
- package/skills/findbugs/SKILL.md +2 -2
- package/skills/fixbugs/SKILL.md +1 -1
- package/skills/monitor-open-prs/SKILL.md +6 -6
- package/skills/pr-converge/SKILL.md +7 -6
- package/skills/pr-converge/reference/convergence-gates.md +46 -44
- package/skills/pr-converge/reference/examples.md +4 -4
- package/skills/pr-converge/reference/fix-protocol.md +8 -8
- package/skills/pr-converge/reference/multi-pr-orchestration.md +10 -10
- package/skills/pr-converge/reference/per-tick.md +24 -36
- package/skills/pr-converge/reference/stop-conditions.md +7 -7
- package/skills/pr-converge/scripts/README.md +65 -117
- package/skills/pr-review-responder/EXAMPLES.md +2 -2
- package/skills/pr-review-responder/PRINCIPLES.md +2 -8
- package/skills/pr-review-responder/README.md +7 -48
- package/skills/pr-review-responder/SKILL.md +2 -3
- package/skills/pr-review-responder/TESTING.md +8 -65
- package/skills/qbug/SKILL.md +10 -16
- package/_shared/pr-loop/scripts/config/gh_util_constants.py +0 -31
- package/_shared/pr-loop/scripts/gh_util.py +0 -193
- package/_shared/pr-loop/scripts/tests/test_gh_util.py +0 -257
- package/_shared/pr-loop/scripts/tests/test_gh_util_constants.py +0 -61
- package/skills/pr-converge/scripts/check_pr_mergeability.py +0 -78
- package/skills/pr-converge/scripts/config/pr_converge_constants.py +0 -118
- package/skills/pr-converge/scripts/config/test_pr_converge_constants.py +0 -152
- package/skills/pr-converge/scripts/fetch_bugbot_inline_comments.py +0 -70
- package/skills/pr-converge/scripts/fetch_bugbot_reviews.py +0 -57
- package/skills/pr-converge/scripts/fetch_claude_inline_comments.py +0 -70
- package/skills/pr-converge/scripts/fetch_claude_reviews.py +0 -61
- package/skills/pr-converge/scripts/fetch_copilot_inline_comments.py +0 -70
- package/skills/pr-converge/scripts/fetch_copilot_reviews.py +0 -61
- package/skills/pr-converge/scripts/mark_pr_ready.py +0 -54
- package/skills/pr-converge/scripts/post-bugbot-run.helpers.ps1 +0 -49
- package/skills/pr-converge/scripts/post-bugbot-run.ps1 +0 -33
- package/skills/pr-converge/scripts/reply_to_inline_comment.py +0 -84
- package/skills/pr-converge/scripts/request_copilot_review.py +0 -71
- package/skills/pr-converge/scripts/resolve_pr_head.py +0 -58
- package/skills/pr-converge/scripts/review_field_helpers.py +0 -43
- package/skills/pr-converge/scripts/reviewer_fetch_core.py +0 -153
- package/skills/pr-converge/scripts/reviewer_specs.py +0 -98
- package/skills/pr-converge/scripts/test_check_pr_mergeability.py +0 -126
- package/skills/pr-converge/scripts/test_fetch_bugbot_inline_comments.py +0 -443
- package/skills/pr-converge/scripts/test_fetch_bugbot_reviews.py +0 -299
- package/skills/pr-converge/scripts/test_fetch_claude_inline_comments.py +0 -485
- package/skills/pr-converge/scripts/test_fetch_claude_reviews.py +0 -368
- package/skills/pr-converge/scripts/test_fetch_copilot_inline_comments.py +0 -440
- package/skills/pr-converge/scripts/test_fetch_copilot_reviews.py +0 -366
- package/skills/pr-converge/scripts/test_mark_pr_ready.py +0 -69
- package/skills/pr-converge/scripts/test_post_bugbot_run.py +0 -195
- package/skills/pr-converge/scripts/test_reply_to_inline_comment.py +0 -159
- package/skills/pr-converge/scripts/test_request_copilot_review.py +0 -101
- package/skills/pr-converge/scripts/test_resolve_pr_head.py +0 -79
- package/skills/pr-converge/scripts/test_review_field_helpers.py +0 -80
- package/skills/pr-converge/scripts/test_reviewer_fetch_core.py +0 -448
- package/skills/pr-converge/scripts/test_reviewer_specs.py +0 -107
- package/skills/pr-converge/scripts/test_trigger_bugbot.py +0 -139
- package/skills/pr-converge/scripts/test_view_pr_context.py +0 -111
- package/skills/pr-converge/scripts/trigger_bugbot.py +0 -77
- package/skills/pr-converge/scripts/view_pr_context.py +0 -47
- package/skills/pr-review-responder/scripts/respond_to_reviews.py +0 -376
|
@@ -24,11 +24,11 @@ Repeat until an exit condition fires.
|
|
|
24
24
|
2. If exit code **0** → continue to step 2.5 (AUDIT spawn) below.
|
|
25
25
|
3. If exit code **non-zero** → spawn a new **clean-coder** teammate — **standards-fix pass** — with instructions: read the script’s stderr, edit the repo until a **re-run** of the **same** gate command exits **0**, then one commit, `git push`, shutdown. Repeat standards-fix spawns until the gate exits **0** or **5** failed gate rounds (each round = one teammate session after a non-zero gate). If still non-zero after 5 rounds → exit reason = `error: code rules gate failed pre-audit`.
|
|
26
26
|
4. After gate exit **0**, increment `loop_count`. If `loop_count > 10`, exit reason = `cap reached` (counts **audits**, not standards-only rounds).
|
|
27
|
-
5. Execute **AUDIT action** (spawn bugfind). Print progress: `Loop <
|
|
27
|
+
5. Execute **AUDIT action** (spawn bugfind). Print progress: `Loop <L> audit: ...`
|
|
28
28
|
|
|
29
29
|
3. **FIX path** (when `last_action == "audited"` and `last_findings.total > 0`):
|
|
30
30
|
1. Increment `loop_count`. If `loop_count > 10`, exit reason = `cap reached`.
|
|
31
|
-
2. Execute **FIX action** (spawn bugfix clean-coder for audit findings). Print: `Loop <
|
|
31
|
+
2. Execute **FIX action** (spawn bugfix clean-coder for audit findings). Print: `Loop <L> fix: commit ...`
|
|
32
32
|
3. Set `last_action = "fixed"`, update `audit_log`, loop to step 1 (next iteration hits **pre-audit path** before the next AUDIT).
|
|
33
33
|
|
|
34
34
|
4. After **AUDIT**, update `last_action`, `last_findings`, `audit_log`; print the audit progress line if not already printed.
|
|
@@ -39,62 +39,45 @@ Repeat until an exit condition fires.
|
|
|
39
39
|
|
|
40
40
|
## AUDIT action (clean-room teammate, fresh per loop)
|
|
41
41
|
|
|
42
|
-
Capture a fresh PR diff for this loop into the per-
|
|
42
|
+
Capture a fresh PR diff for this loop into the per-PR scoped directory so concurrent `/bugteam` runs keep patches isolated. Use the literal `<run_temp_dir>` resolved once in Step 2 — Claude resolves the absolute path; every shell receives the same literal value.
|
|
43
43
|
|
|
44
44
|
Commands and `Agent(...)` shape: `SKILL.md`.
|
|
45
45
|
|
|
46
|
-
`<
|
|
46
|
+
`<run_temp_dir>` includes the sanitized `team_name` and timestamp; `team_name` is already prefixed with `bugteam-`. Claude resolves `Path(tempfile.gettempdir()) / team_name` once and passes that absolute path to every shell. `tempfile.gettempdir()` honors `TMPDIR`, `TEMP`, `TMP` and falls back to the OS temp directory, so the same approach works on macOS, Linux, Windows cmd.exe, and PowerShell.
|
|
47
47
|
|
|
48
48
|
Each loop calls `Agent` again with a fresh invocation so the teammate starts with its own context window. Doc line on lead history: [`../sources.md`](../sources.md).
|
|
49
49
|
|
|
50
50
|
See [`../PROMPTS.md`](../PROMPTS.md) for AUDIT spawn-prompt XML and bugfind outcome schema. Substitute placeholders (`repo`, `branch`, `base_branch`, `pr_url`, `loop`, `diff_path`) into the `prompt` argument.
|
|
51
51
|
|
|
52
|
-
After the teammate returns, the lead reads `.bugteam-loop
|
|
52
|
+
After the teammate returns, the lead reads `.bugteam-pr<N>-loop<L>.outcomes.xml` from the worktree directory with the `Read` tool, parses it, and populates `loop_comment_index` from `<finding>` elements.
|
|
53
53
|
|
|
54
54
|
### Shutdown (bugfind)
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
**Fallback — lead-initiated shutdown:** If the teammate still appears active after `Agent` returns, send:
|
|
59
|
-
|
|
60
|
-
```
|
|
61
|
-
SendMessage(
|
|
62
|
-
to="bugfind",
|
|
63
|
-
message={
|
|
64
|
-
"type": "shutdown_request",
|
|
65
|
-
"reason": "audit loop <N> complete; outcome XML captured"
|
|
66
|
-
}
|
|
67
|
-
)
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
The teammate replies with `{type: "shutdown_response", approve: true}`. If `approve` is `false`, exit reason = `error: bugfind teammate refused shutdown` → Step 4 teardown then Step 5 revoke.
|
|
56
|
+
Teammates self-terminate when complete — the background-completion notification arrives and the lead reads the outcomes XML. If the notification does not arrive within the lead timeout (120s), treat as a hard blocker and abort the loop.
|
|
71
57
|
|
|
72
58
|
`last_action = "audited"`. Append audit metadata to `audit_log`.
|
|
73
59
|
|
|
74
60
|
### Parallel auditors (`loop_count >= 4`)
|
|
75
61
|
|
|
76
|
-
The pre-audit gate must pass immediately before this step. After three full audit/fix rounds without convergence, issue
|
|
62
|
+
The pre-audit gate must pass immediately before this step. After three full audit/fix rounds without convergence, issue eleven `Agent` calls in **one** assistant message so they run in parallel:
|
|
77
63
|
|
|
78
64
|
```
|
|
79
|
-
Agent(subagent_type="code-quality-agent", name="bugfind-
|
|
80
|
-
Agent(subagent_type="code-quality-agent", name="bugfind-
|
|
81
|
-
Agent(subagent_type="code-quality-agent", name="bugfind-
|
|
65
|
+
Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-a", team_name="<team_name>", model="opus", run_in_background=true, description="Bugfind audit PR <N> loop <L> validator", prompt="<audit XML; poll for all 10 sibling XMLs at <run_temp_dir>/pr-<N>/loop-<L>-b.outcomes.xml through <run_temp_dir>/pr-<N>/loop-<L>-k.outcomes.xml (60s timeout, 2s interval); on timeout: log diagnostics entry, proceed with validated findings from available XMLs; validate each finding: file exists, line in bounds, excerpt matches claimed line, category A-J, severity P0/P1/P2; quarantine hallucinated findings to <run_temp_dir>/pr-<N>/loop-<L>-diagnostics.json under validator_rejected; de-dup by (file, line, category), max severity wins, keep longest description on conflict; re-id as loop<L>-<K>; write <worktree_path>/.bugteam-pr<N>-loop<L>.outcomes.xml; post review>")
|
|
66
|
+
Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-b", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant b", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-b.outcomes.xml; skip PR posting>")
|
|
67
|
+
Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-c", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant c", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-c.outcomes.xml; skip PR posting>")
|
|
68
|
+
Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-d", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant d", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-d.outcomes.xml; skip PR posting>")
|
|
69
|
+
Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-e", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant e", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-e.outcomes.xml; skip PR posting>")
|
|
70
|
+
Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-f", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant f", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-f.outcomes.xml; skip PR posting>")
|
|
71
|
+
Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-g", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant g", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-g.outcomes.xml; skip PR posting>")
|
|
72
|
+
Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-h", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant h", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-h.outcomes.xml; skip PR posting>")
|
|
73
|
+
Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-i", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant i", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-i.outcomes.xml; skip PR posting>")
|
|
74
|
+
Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-j", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant j", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-j.outcomes.xml; skip PR posting>")
|
|
75
|
+
Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-k", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant k", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-k.outcomes.xml; skip PR posting>")
|
|
82
76
|
```
|
|
83
77
|
|
|
84
|
-
Teammate `-a` is the
|
|
85
|
-
|
|
86
|
-
Shutdown order: parallel `SendMessage` to `b` and `c`, then `a`:
|
|
78
|
+
Teammate `-a` is the opus validator: polls for all 10 sibling XMLs at explicit absolute paths under `<run_temp_dir>/pr-<N>` (60s timeout, 2s interval; on timeout: log diagnostics entry, proceed with validated findings from available XMLs), then validates each finding — file exists, line in bounds, excerpt matches claimed line, category is A–J, severity is P0/P1/P2. Hallucinated findings are quarantined to `<run_temp_dir>/pr-<N>/loop-<L>-diagnostics.json` under `validator_rejected`. Valid findings are de-duplicated by `(file, line, category)` (max severity wins, keep longest description on conflict) and re-assigned merged IDs as `loop<L>-<K>`. The `-a` prompt must embed sibling paths as literal absolutes so `Read` works without discovery.
|
|
87
79
|
|
|
88
|
-
|
|
89
|
-
SendMessage(to="bugfind-loop-<N>-b", message={"type": "shutdown_request", "reason": "variant XML captured"})
|
|
90
|
-
SendMessage(to="bugfind-loop-<N>-c", message={"type": "shutdown_request", "reason": "variant XML captured"})
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
then
|
|
94
|
-
|
|
95
|
-
```
|
|
96
|
-
SendMessage(to="bugfind-loop-<N>-a", message={"type": "shutdown_request", "reason": "merged review posted"})
|
|
97
|
-
```
|
|
80
|
+
All subagents self-terminate via background completion. The lead awaits only the validator (-a) notification (120s timeout). Missing notification → hard blocker.
|
|
98
81
|
|
|
99
82
|
## FIX action (fresh teammate)
|
|
100
83
|
|
|
@@ -106,17 +89,7 @@ After replies, the teammate writes outcome XML (schema in [`../PROMPTS.md`](../P
|
|
|
106
89
|
|
|
107
90
|
### Shutdown (bugfix)
|
|
108
91
|
|
|
109
|
-
Same self-termination
|
|
110
|
-
|
|
111
|
-
```
|
|
112
|
-
SendMessage(
|
|
113
|
-
to="bugfix",
|
|
114
|
-
message={
|
|
115
|
-
"type": "shutdown_request",
|
|
116
|
-
"reason": "fix loop <N> complete; commit <sha7> pushed"
|
|
117
|
-
}
|
|
118
|
-
)
|
|
119
|
-
```
|
|
92
|
+
Same self-termination model as bugfind. Missing notification → hard blocker.
|
|
120
93
|
|
|
121
94
|
`approve: false` → `error: bugfix teammate refused shutdown` → Step 4 then 5.
|
|
122
95
|
|
|
@@ -8,7 +8,7 @@ Shared output schema and audit-loop contract used by `/bugteam`, `/qbug`, `/find
|
|
|
8
8
|
- Adversarial second pass
|
|
9
9
|
- Haiku secondary auditor
|
|
10
10
|
- Post-fix self-audit
|
|
11
|
-
- Persistence (loop
|
|
11
|
+
- Persistence (loop-<L>-audit.json, loop-<L>-diagnostics.json)
|
|
12
12
|
|
|
13
13
|
## Finding schema
|
|
14
14
|
|
|
@@ -18,7 +18,7 @@ Each finding an audit produces MUST be one of exactly two shapes.
|
|
|
18
18
|
|
|
19
19
|
```json
|
|
20
20
|
{
|
|
21
|
-
"id": "loop<
|
|
21
|
+
"id": "loop<L>-<K>",
|
|
22
22
|
"file": "path/relative/to/repo/root.py",
|
|
23
23
|
"line": 123,
|
|
24
24
|
"category": "A | B | C | D | E | F | G | H | I | J",
|
|
@@ -29,7 +29,7 @@ Each finding an audit produces MUST be one of exactly two shapes.
|
|
|
29
29
|
}
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
`id` is `loop<
|
|
32
|
+
`id` is `loop<L>-<K>` where `L` is the loop counter (1-based) and `K` is the 1-based index within the loop. For `/findbugs` which runs once, use `find<K>`.
|
|
33
33
|
|
|
34
34
|
### Shape B — structured proof-of-absence
|
|
35
35
|
|
|
@@ -105,9 +105,9 @@ Merge rules:
|
|
|
105
105
|
- **Unique-to-Haiku findings**: added to the primary set with Haiku's severity and source annotation.
|
|
106
106
|
- **Unique-to-primary findings**: kept as-is.
|
|
107
107
|
- **Zero Haiku findings**: primary set trusted; proceed.
|
|
108
|
-
- **Malformed or non-parseable Haiku output**: lead trusts the primary set, logs the event in `loop-<
|
|
108
|
+
- **Malformed or non-parseable Haiku output**: lead trusts the primary set, logs the event in `loop-<L>-diagnostics.json` under `haiku_findings` as `[{"parse_error": "<message>"}]`.
|
|
109
109
|
|
|
110
|
-
For multi-subagent skills (`/bugteam`) the parallel-auditors pattern in [`audit-and-teammates.md`](audit-and-teammates.md) already provides cross-model coverage via
|
|
110
|
+
For multi-subagent skills (`/bugteam`) the parallel-auditors pattern in [`audit-and-teammates.md`](audit-and-teammates.md) already provides cross-model coverage via 10 haiku auditors + opus validator.
|
|
111
111
|
|
|
112
112
|
## Post-fix self-audit
|
|
113
113
|
|
|
@@ -131,7 +131,7 @@ Sequence:
|
|
|
131
131
|
|
|
132
132
|
Every audit loop writes two JSON files under the skill's scoped temp directory (resolved via `tempfile.gettempdir()`):
|
|
133
133
|
|
|
134
|
-
### `loop-<
|
|
134
|
+
### `loop-<L>-audit.json`
|
|
135
135
|
|
|
136
136
|
```json
|
|
137
137
|
{
|
|
@@ -141,7 +141,7 @@ Every audit loop writes two JSON files under the skill's scoped temp directory (
|
|
|
141
141
|
}
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
-
### `loop-<
|
|
144
|
+
### `loop-<L>-diagnostics.json`
|
|
145
145
|
|
|
146
146
|
```json
|
|
147
147
|
{
|
|
@@ -8,55 +8,55 @@ Per-loop pull-request reviews: findings render as a tree under one parent review
|
|
|
8
8
|
|
|
9
9
|
**Ordering:** Bugfind audits first, buffers findings, validates anchors against the captured diff, then posts the review **once** at the end. The review body states the finding count authoritatively. Keep all posting in that single end-of-loop review POST.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## MCP tool shapes (teammate)
|
|
12
12
|
|
|
13
|
-
All three POSTs use
|
|
13
|
+
All three POSTs use MCP tool calls. Body text with markdown (backticks, newlines, quotes) passes through safely as string parameters — no temp files, no jq, no shell pipes.
|
|
14
14
|
|
|
15
15
|
### Per-loop review (one POST creates parent + children)
|
|
16
16
|
|
|
17
17
|
Build `comments[]` programmatically from buffered, diff-anchored findings. Single-line shape: `{path, line, side: "RIGHT", body: <finding markdown>}`. Multi-line: `{path, start_line, start_side: "RIGHT", line, side: "RIGHT", body: ...}` (all four anchor fields required).
|
|
18
18
|
|
|
19
19
|
```
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
[
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
comments: [
|
|
32
|
-
{path: $path_1, line: $line_1, side: "RIGHT", body: $finding_body_1}
|
|
33
|
-
[, ... one object per anchored finding ...]
|
|
34
|
-
]
|
|
35
|
-
}' \
|
|
36
|
-
| gh api repos/<owner>/<repo>/pulls/<number>/reviews -X POST --input -
|
|
20
|
+
pull_request_review_write(
|
|
21
|
+
method="create",
|
|
22
|
+
event="COMMENT",
|
|
23
|
+
body=<review_body_markdown>,
|
|
24
|
+
commitID=<head_sha_at_post_time>,
|
|
25
|
+
owner=<owner>, repo=<repo>, pullNumber=<pull_number>,
|
|
26
|
+
comments=[
|
|
27
|
+
{path: <file_1>, line: <line_1>, side: "RIGHT", body: <finding_1_markdown>}
|
|
28
|
+
[, ... one object per anchored finding ...]
|
|
29
|
+
]
|
|
30
|
+
)
|
|
37
31
|
```
|
|
38
32
|
|
|
39
|
-
Response
|
|
33
|
+
Response includes the parent review `html_url` and a `comments` array of child comments (`id`, `html_url`). Harvest children in index order and align with the finding list.
|
|
40
34
|
|
|
41
35
|
### Fix reply
|
|
42
36
|
|
|
43
37
|
```
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
add_reply_to_pull_request_comment(
|
|
39
|
+
commentId=<finding_comment_id>,
|
|
40
|
+
body=<reply_markdown>,
|
|
41
|
+
owner=<owner>, repo=<repo>, pullNumber=<pull_number>
|
|
42
|
+
)
|
|
46
43
|
```
|
|
47
44
|
|
|
48
45
|
### Review POST failure fallback
|
|
49
46
|
|
|
50
|
-
Top-level PR comment via issue-comments (`
|
|
47
|
+
Top-level PR comment via issue-comments (`issue_number` is the PR number):
|
|
51
48
|
|
|
52
49
|
```
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
add_issue_comment(
|
|
51
|
+
owner=<owner>, repo=<repo>,
|
|
52
|
+
issueNumber=<pull_number>,
|
|
53
|
+
body=<full_fallback_markdown>
|
|
54
|
+
)
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
`<head_sha_at_post_time>` is the SHA at post time (`git rev-parse HEAD` in the teammate’s working directory immediately before the POST). The review anchors finding comments to the head SHA at audit time (before this loop’s fix lands).
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
Body text is passed directly as string parameters to the MCP tool calls — no temp files, no jq, no shell pipes.
|
|
60
60
|
|
|
61
61
|
## Review body template (`<tmp_review_body.md>`)
|
|
62
62
|
|
|
@@ -77,10 +77,10 @@ GitHub rejects the entire review POST if any `comments[]` entry targets a line n
|
|
|
77
77
|
|
|
78
78
|
## Review POST failure fallback
|
|
79
79
|
|
|
80
|
-
If the review POST fails (rate limit, network, malformed payload), fall back to one top-level issue comment containing the review body plus every finding inline (severity, file:line, description). Every finding in that run: `used_fallback="true"`, `finding_comment_url` = issue-comment URL. Use
|
|
80
|
+
If the review POST fails (rate limit, network, malformed payload), fall back to one top-level issue comment containing the review body plus every finding inline (severity, file:line, description). Every finding in that run: `used_fallback="true"`, `finding_comment_url` = issue-comment URL. Use `add_issue_comment` (see MCP tool reference below).
|
|
81
81
|
|
|
82
|
-
##
|
|
82
|
+
## MCP tool reference
|
|
83
83
|
|
|
84
|
-
- Per-loop batched review: `POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews`
|
|
85
|
-
- Fix reply: `POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies`
|
|
86
|
-
- Review-POST failure fallback: `POST /repos/{owner}/{repo}/issues/{issue_number}/comments`
|
|
84
|
+
- Per-loop batched review: `pull_request_review_write(method="create", event="COMMENT", body=..., commitID=..., owner=..., repo=..., pullNumber=..., comments=[...])` — wraps `POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews`
|
|
85
|
+
- Fix reply: `add_reply_to_pull_request_comment(commentId=..., body=..., owner=..., repo=..., pullNumber=...)` — wraps `POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies`
|
|
86
|
+
- Review-POST failure fallback: `add_issue_comment(owner=..., repo=..., issueNumber=..., body=...)` — wraps `POST /repos/{owner}/{repo}/issues/{issue_number}/comments`
|
|
@@ -14,7 +14,7 @@ This is the **first** action of every `/bugteam` invocation, before any subagent
|
|
|
14
14
|
|
|
15
15
|
Same resolution path as `/findbugs`:
|
|
16
16
|
|
|
17
|
-
1. `
|
|
17
|
+
1. `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` — extracts `number`, `baseRefName`, `headRefName`, `url` from response (`N` comes from the parent skill's PR context, or fall back to `pull_request_read` with the default branch lookup to recover the PR number).
|
|
18
18
|
2. Fall back to `git merge-base HEAD origin/<default>` then `git diff <merge-base>...HEAD`.
|
|
19
19
|
3. Neither → refuse per refusal cases in `SKILL.md`.
|
|
20
20
|
|
|
@@ -34,15 +34,15 @@ If that subagent is missing, fall back to `general-purpose` with the same brief
|
|
|
34
34
|
|
|
35
35
|
**Steps:**
|
|
36
36
|
|
|
37
|
-
1. Capture cumulative diff: `
|
|
38
|
-
2. Capture original body: `
|
|
37
|
+
1. Capture cumulative diff: `pull_request_read(method="get_diff", pullNumber=N, owner=O, repo=R)` → write output to `.bugteam-final.diff` with `Write` tool.
|
|
38
|
+
2. Capture original body: `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` → extract `.body` from response, write to `.bugteam-original-body.md` with `Write` tool.
|
|
39
39
|
3. Agent brief:
|
|
40
40
|
- **Inputs:** diff path, original body path, head branch, base branch.
|
|
41
41
|
- **Constraint:** describe what the PR delivers from the cumulative diff — behavior, user-visible effect, merge rationale. Process metadata (loops, fix counts, findings) stays in review comments.
|
|
42
|
-
- **Preservation rule:** if the original body has manually curated sections (linked issues, screenshots, test plan,
|
|
42
|
+
- **Preservation rule:** if the original body has manually curated sections (linked issues, screenshots, test plan, "Risk Assessment", etc.), preserve them verbatim and only rewrite narrative around them.
|
|
43
43
|
- **Output:** new body markdown.
|
|
44
44
|
4. Write `.bugteam-final-body.md`.
|
|
45
|
-
5. `
|
|
45
|
+
5. `update_pull_request(pullNumber=N, owner=O, repo=R, body=<body_text>)`.
|
|
46
46
|
6. Delete `.bugteam-final.diff`, `.bugteam-original-body.md`, `.bugteam-final-body.md`.
|
|
47
47
|
|
|
48
48
|
If Step 4.5 fails (agent error, hook block, network), report in the final report and continue to Step 5. The original PR body remains; commits and comments are unaffected.
|
|
@@ -26,10 +26,10 @@ The user is on a PR branch, wants Copilot (the GitHub Copilot reviewer bot) to k
|
|
|
26
26
|
From the current repo:
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
|
|
29
|
+
# MCP: pull_request_read(method="get") returns {number, url, head.sha, base.ref, head.ref, isDraft}
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
Capture `number`, `
|
|
32
|
+
Capture `number`, `head.sha`, owner/repo (from `url`), and branch name. Pass these to the subagent so it does not rediscover them.
|
|
33
33
|
|
|
34
34
|
### Step 2: Spawn the background subagent
|
|
35
35
|
|
|
@@ -57,23 +57,16 @@ Pass this verbatim to the subagent (substituting the bracketed values):
|
|
|
57
57
|
>
|
|
58
58
|
> **Per-tick work** (do this now, then on each wakeup):
|
|
59
59
|
>
|
|
60
|
-
> 1. Resolve current HEAD: `
|
|
61
|
-
> 2. Fetch latest Copilot review
|
|
62
|
-
> ```bash
|
|
63
|
-
> gh api repos/[OWNER]/[REPO]/pulls/[NUMBER]/reviews \
|
|
64
|
-
> --jq '[.[] | select(.user.login=="copilot-pull-request-reviewer[bot]")] | sort_by(.submitted_at) | last'
|
|
65
|
-
> ```
|
|
60
|
+
> 1. Resolve current HEAD: `pull_request_read(method="get", pullNumber=[NUMBER], owner="[OWNER]", repo="[REPO]")` and extract `.head.sha`.
|
|
61
|
+
> 2. Fetch latest Copilot review via `pull_request_read(method="get_reviews", pullNumber=[NUMBER], owner="[OWNER]", repo="[REPO]")`.
|
|
66
62
|
> Capture `commit_id`, `state`, `submitted_at`, `id`.
|
|
67
63
|
> 3. Decide the branch:
|
|
68
64
|
> - **No review exists:** re-request (step 4), schedule next wakeup, return.
|
|
69
65
|
> - **Latest review's `commit_id` != current HEAD:** re-request (step 4), schedule next wakeup, return.
|
|
70
66
|
> - **Latest review's `commit_id` == current HEAD with unresolved inline findings:** TDD-fix them, push, reply inline on each thread, re-request (step 4), schedule next wakeup, return.
|
|
71
67
|
> - **Latest review's `commit_id` == current HEAD and clean:** report convergence to the parent with a one-sentence summary and terminate. The loop is done; skip the ScheduleWakeup call.
|
|
72
|
-
> 4. Re-request Copilot
|
|
73
|
-
>
|
|
74
|
-
> gh api -X POST repos/[OWNER]/[REPO]/pulls/[NUMBER]/requested_reviewers \
|
|
75
|
-
> -f 'reviewers[]=copilot-pull-request-reviewer[bot]'
|
|
76
|
-
> ```
|
|
68
|
+
> 4. Re-request Copilot via `request_copilot_review(owner="[OWNER]", repo="[REPO]", pullNumber=[NUMBER])`.
|
|
69
|
+
> The reviewer ID **must** be `copilot-pull-request-reviewer[bot]` with the `[bot]` suffix — empirically verified: `Copilot`, `copilot`, and `github-copilot` all return `requested_reviewers: []` with no error, silently no-op.
|
|
77
70
|
> 5. Schedule the next wakeup with `ScheduleWakeup`:
|
|
78
71
|
> - `delaySeconds: 300`
|
|
79
72
|
> - `reason`: one short sentence on what you are waiting for.
|
|
@@ -86,7 +79,7 @@ Pass this verbatim to the subagent (substituting the bracketed values):
|
|
|
86
79
|
> - Implement the fix.
|
|
87
80
|
> - Stage the fix and create one new commit on the existing branch: `git add <files> && git commit -m "fix(review): ..."`.
|
|
88
81
|
> - Push the new commit: `git push origin [BRANCH]`.
|
|
89
|
-
> - Reply inline on each comment thread with `
|
|
82
|
+
> - Reply inline on each comment thread with `add_reply_to_pull_request_comment(owner="[OWNER]", repo="[REPO]", pullNumber=[NUMBER], body="...", commentId=<comment_id>)`, referencing the new commit SHA.
|
|
90
83
|
>
|
|
91
84
|
> When a pre-push, pre-commit, or other hook rejects the change, solve it. Read the hook's error message, diagnose the root cause in the code or test, and fix that. Then rerun the commit or push. Hooks exist to catch real problems; treat each rejection as new evidence to act on.
|
|
92
85
|
>
|
package/skills/findbugs/SKILL.md
CHANGED
|
@@ -24,7 +24,7 @@ If the current branch has no associated PR and no diff against the default branc
|
|
|
24
24
|
|
|
25
25
|
Determine the audit target in this order:
|
|
26
26
|
|
|
27
|
-
1. **Open PR for current branch.**
|
|
27
|
+
1. **Open PR for current branch.** Call `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` for the current branch (`N` comes from the parent skill's context, or fall back to `search_issues` MCP with the current branch name to recover the PR number). If a PR exists, capture its number, base ref, head ref, and URL.
|
|
28
28
|
2. **No PR but a remote default branch exists.** Diff against the default branch's merge-base: `git merge-base HEAD origin/<default>` then `git diff <merge-base>...HEAD`. Treat this as the audit scope.
|
|
29
29
|
3. **Neither.** Respond exactly: `No PR or upstream diff found. Push the branch or open a PR first.` and stop.
|
|
30
30
|
|
|
@@ -39,7 +39,7 @@ diff_temp_path = Path(tempfile.gettempdir()) / f"findbugs-pr-{os.getpid()}.patch
|
|
|
39
39
|
|
|
40
40
|
`os.getpid()` supplies the per-invocation suffix that prevents collisions with parallel `/findbugs` runs (a UUID or timestamp is equally acceptable). Capture the resolved absolute path as `<diff_temp_path>` and pass that **literal** path to every shell command that follows. Shell-side parameter expansion (`${TMPDIR:-/tmp}`, `$$`, `%TEMP%`) is forbidden because cmd.exe and PowerShell do not honor it.
|
|
41
41
|
|
|
42
|
-
When a PR exists: `
|
|
42
|
+
When a PR exists: call `pull_request_read(method="get_diff", pullNumber=N, owner=O, repo=R)` and save the returned diff content to `"<diff_temp_path>"`.
|
|
43
43
|
|
|
44
44
|
When falling back to merge-base diff: `git diff <merge-base>...HEAD > "<diff_temp_path>"`.
|
|
45
45
|
|
package/skills/fixbugs/SKILL.md
CHANGED
|
@@ -49,7 +49,7 @@ If the filtered set is empty, refuse per the refusal cases above.
|
|
|
49
49
|
|
|
50
50
|
Re-establish the same PR target `/findbugs` used:
|
|
51
51
|
|
|
52
|
-
1. `
|
|
52
|
+
1. `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` for the current branch (`N` comes from the parent skill's PR context, or fall back to `search_issues` MCP with the current branch name to recover the PR number).
|
|
53
53
|
2. Fall back to `git merge-base HEAD origin/<default>` then `git diff <merge-base>...HEAD`.
|
|
54
54
|
3. Neither → respond `No PR or upstream diff. Cannot scope fixes.` and stop.
|
|
55
55
|
|
|
@@ -12,12 +12,12 @@ description: >-
|
|
|
12
12
|
|
|
13
13
|
# Monitor Open PRs
|
|
14
14
|
|
|
15
|
-
**Core principle:** One sweep covers every open PR across both owner scopes. Claude discovers PRs live via `gh search prs
|
|
15
|
+
**Core principle:** One sweep covers every open PR across both owner scopes. Claude discovers PRs live via `scripts/discover_open_prs.py` which shells out to `gh search prs --owner <owner> --state open --json ...`, dispatches `/bugteam` per PR with `BUGTEAM_FIX_IMPLEMENTER=groq-coder` and `--bugbot-retrigger`, then polls Cursor's bugbot replies until each PR is quiet for a full backoff cycle.
|
|
16
16
|
|
|
17
17
|
## Contents
|
|
18
18
|
|
|
19
19
|
- When this skill applies — refusal cases and trigger conditions
|
|
20
|
-
- Discovery —
|
|
20
|
+
- Discovery — `scripts/discover_open_prs.py` queries via `gh search prs` across both owner scopes
|
|
21
21
|
- Wrapping — `bws run` for GROQ_API_KEY injection
|
|
22
22
|
- Dispatch — `/bugteam --bugbot-retrigger <pr_numbers...>` with groq-coder + retrigger
|
|
23
23
|
- Post-convergence polling — bugbot replies and re-invocation
|
|
@@ -30,13 +30,13 @@ description: >-
|
|
|
30
30
|
Refusals — first match wins; respond with the quoted line exactly and stop:
|
|
31
31
|
|
|
32
32
|
- **bws not on PATH.** `bws not installed. /monitor-open-prs injects GROQ_API_KEY via Bitwarden Secrets Manager.`
|
|
33
|
-
- **
|
|
33
|
+
- **GitHub API not accessible.** `get_me failed. /monitor-open-prs needs active GitHub MCP credentials.`
|
|
34
34
|
- **Dirty tree on the caller's repo.** `Uncommitted changes detected. Stash, commit, or revert before /monitor-open-prs.`
|
|
35
35
|
- **Required subagents missing.** Confirm `code-quality-agent`, `clean-coder`, and `groq-coder` exist. Else: `Required subagent type <name> not installed.`
|
|
36
36
|
|
|
37
37
|
## Discovery
|
|
38
38
|
|
|
39
|
-
Call `scripts/discover_open_prs.discover_open_prs(all_owners=["jl-cmd", "JonEcho"])` to merge the live open-PR list across both scopes. The helper
|
|
39
|
+
Call `scripts/discover_open_prs.discover_open_prs(all_owners=["jl-cmd", "JonEcho"])` to merge the live open-PR list across both scopes. The helper shells out to `gh search prs --owner <owner> --state open --json number,repository,url,headRefName,baseRefName` for each owner scope and flattens the result to a uniform dict shape with keys `number`, `owner`, `repo`, `head_ref`, `base_ref`, `url`. Empty scopes contribute empty lists; an entirely empty sweep returns `[]` and exits cleanly.
|
|
40
40
|
|
|
41
41
|
## Secret Wrapping
|
|
42
42
|
|
|
@@ -50,7 +50,7 @@ bws run \
|
|
|
50
50
|
/bugteam --bugbot-retrigger <pr_numbers...>
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
The `bws run` subshell resolves the project's secrets and exports them for the wrapped command. The `GROQ_API_KEY` secret's UUID inside that project is `b7e99a7f-2ecc-42b3-99a5-b434010622f9`. GitHub auth is not sourced through `bws` — existing
|
|
53
|
+
The `bws run` subshell resolves the project's secrets and exports them for the wrapped command. The `GROQ_API_KEY` secret's UUID inside that project is `b7e99a7f-2ecc-42b3-99a5-b434010622f9`. GitHub auth is not sourced through `bws` — existing MCP `get_me` credentials carry the session.
|
|
54
54
|
|
|
55
55
|
## Dispatch
|
|
56
56
|
|
|
@@ -68,7 +68,7 @@ For each discovered PR:
|
|
|
68
68
|
After a `/bugteam` invocation returns (converged, cap reached, stuck, or error), the PR may accumulate new Cursor bugbot comments within minutes. Poll for them:
|
|
69
69
|
|
|
70
70
|
1. Baseline: capture `since_timestamp` as the PR's last commit timestamp.
|
|
71
|
-
2. Every 60 seconds,
|
|
71
|
+
2. Every 60 seconds, call `pull_request_read(method="get", pullNumber=<pr_number>, owner=<owner>, repo=<repo>)` and filter the response's `comments` array for entries whose `.author.login` matches `"bugbot"` or `"cursor"` and `.createdAt` is after `<since_timestamp>`.
|
|
72
72
|
3. Back off: 60s → 120s → 240s → 480s → 960s. If five successive polls return empty, exit polling for this PR.
|
|
73
73
|
4. If bugbot posts a new finding in any poll, re-invoke `/bugteam <pr_number>` via the same `bws run` wrapper with the bugbot finding text seeded into the invocation's `bugs_to_fix` preamble. Reset the backoff.
|
|
74
74
|
|
|
@@ -41,10 +41,12 @@ post a fresh PR in a fresh branch based on origin main to the user.
|
|
|
41
41
|
- **Duplicate `bugbot run` while review queued** — skip Step 3 when the
|
|
42
42
|
latest `bugbot run` PR comment has an `:eyes:` or `:+1:` reaction;
|
|
43
43
|
wait for review or HEAD change before re-triggering.
|
|
44
|
-
- **Bot
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
- **Bot login fields differ by endpoint** — `get_reviews` returns
|
|
45
|
+
`.user.login` (object), but `get_review_comments` returns `.author`
|
|
46
|
+
(string, not an object). Threads use `is_outdated` (not `commit_id`) to
|
|
47
|
+
indicate staleness. Always check the correct fields and use
|
|
48
|
+
case-insensitive substring matching on login values, never strict
|
|
49
|
+
equality.
|
|
48
50
|
|
|
49
51
|
## First tick of a session
|
|
50
52
|
|
|
@@ -62,7 +64,7 @@ Read [`reference/state-schema.md`](reference/state-schema.md),
|
|
|
62
64
|
| Multi-PR session — `state.json` exists at `<TMPDIR>/pr-converge-<session_id>/` | [`reference/multi-pr-orchestration.md`](reference/multi-pr-orchestration.md) |
|
|
63
65
|
| Scheduling the next wakeup | [`workflows/schedule-wakeup-loop.md`](workflows/schedule-wakeup-loop.md) |
|
|
64
66
|
| Hard blocker, convergence reached, or user stops loop | [`reference/stop-conditions.md`](reference/stop-conditions.md) |
|
|
65
|
-
|
|
|
67
|
+
| All GitHub interactions use `plugin:github:github` MCP tools | [`reference/per-tick.md`](reference/per-tick.md) |
|
|
66
68
|
| Tick is ambiguous against the spokes above | [`reference/examples.md`](reference/examples.md) |
|
|
67
69
|
|
|
68
70
|
## Folder map
|
|
@@ -70,4 +72,3 @@ Read [`reference/state-schema.md`](reference/state-schema.md),
|
|
|
70
72
|
- `SKILL.md` — this hub.
|
|
71
73
|
- `reference/` — workflow detail per situation.
|
|
72
74
|
- `workflows/` — pacing implementations.
|
|
73
|
-
- `scripts/` — Python wrappers for `gh` API calls plus their tests.
|