claude-dev-env 1.37.1 → 1.38.1
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/code_rules_enforcer.py +93 -32
- 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_code_rules_enforcer_unused_imports.py +158 -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/no-historical-clutter.md +31 -10
- 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 +60 -31
- package/skills/bugteam/SKILL.md +47 -47
- package/skills/bugteam/SKILL_EVALS.md +8 -8
- 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 +28 -30
- package/skills/pr-converge/reference/examples.md +4 -4
- package/skills/pr-converge/reference/fix-protocol.md +6 -8
- package/skills/pr-converge/reference/multi-pr-orchestration.md +10 -10
- package/skills/pr-converge/reference/per-tick.md +18 -33
- 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 -134
- 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 -155
- package/skills/pr-converge/scripts/trigger_bugbot.py +0 -77
- package/skills/pr-converge/scripts/view_pr_context.py +0 -78
- package/skills/pr-review-responder/scripts/respond_to_reviews.py +0 -376
|
@@ -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.
|
|
@@ -11,12 +11,13 @@ Fetch latest Copilot reviewer (`copilot-pull-request-reviewer[bot]`) review
|
|
|
11
11
|
plus inline comments anchored to most recent Copilot review on
|
|
12
12
|
`current_head`:
|
|
13
13
|
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
```
|
|
15
|
+
pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get_reviews")
|
|
16
|
+
→ filter `.user.login` for copilot (case-insensitive substring "copilot")
|
|
17
|
+
→ sort by `.submitted_at` descending
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get_review_comments")
|
|
20
|
+
→ filter threads where `is_outdated == false` AND any comment has `.author` matching Copilot (case-insensitive substring "copilot")
|
|
20
21
|
```
|
|
21
22
|
|
|
22
23
|
Decide (four branches; match first whose predicate holds):
|
|
@@ -24,7 +25,7 @@ Decide (four branches; match first whose predicate holds):
|
|
|
24
25
|
- **`classification == "dirty"` with non-empty inline comments matching
|
|
25
26
|
`pull_request_review_id`:** Fix protocol input (same shape as bugbot
|
|
26
27
|
dirty). Spawn Agent (subagent_type: clean-coder) to implement → push → reply inline on each thread via
|
|
27
|
-
`
|
|
28
|
+
`add_reply_to_pull_request_comment` MCP → Step 3 in same tick (see
|
|
28
29
|
[Single-PR fix workflow](fix-protocol.md#single-pr-fix-workflow) for
|
|
29
30
|
full contract).
|
|
30
31
|
Reset `bugbot_clean_at = null` AND `copilot_clean_at = null`, `phase =
|
|
@@ -34,9 +35,7 @@ Decide (four branches; match first whose predicate holds):
|
|
|
34
35
|
`pull_request_review_id`:** Copilot posted findings only in review body
|
|
35
36
|
(`CHANGES_REQUESTED` or `COMMENTED` with non-empty body, no inline
|
|
36
37
|
threads). Parse body for actionable findings. Spawn Agent (subagent_type: clean-coder) to implement → push → post
|
|
37
|
-
top-level review reply citing new HEAD SHA → Step 3 in same tick
|
|
38
|
-
[Single-PR fix workflow](fix-protocol.md#single-pr-fix-workflow) for
|
|
39
|
-
full contract).
|
|
38
|
+
top-level review reply using `pull_request_review_write(method="create", event="COMMENT", body)` citing new HEAD SHA → Step 3 in same tick.
|
|
40
39
|
Reset
|
|
41
40
|
`bugbot_clean_at = null` AND
|
|
42
41
|
`copilot_clean_at = null`, `phase = BUGBOT`, Step 3 on new HEAD,
|
|
@@ -51,16 +50,16 @@ Decide (four branches; match first whose predicate holds):
|
|
|
51
50
|
|
|
52
51
|
Resolve PR's mergeability state:
|
|
53
52
|
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
```
|
|
54
|
+
pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get")
|
|
55
|
+
→ `.mergeable_state`, `.mergeable`
|
|
57
56
|
```
|
|
58
57
|
|
|
59
|
-
Persist `
|
|
58
|
+
Persist `mergeable_state` into `merge_state_status`. Decide:
|
|
60
59
|
|
|
61
|
-
- **`
|
|
60
|
+
- **`mergeable_state == "clean"` AND `mergeable == true`:**
|
|
62
61
|
Continue to gate (c).
|
|
63
|
-
- **`
|
|
62
|
+
- **`mergeable_state == "dirty"` (or `mergeable == false`):** Do
|
|
64
63
|
**not** mark ready. Invoke **`rebase`** skill
|
|
65
64
|
([`../../rebase/SKILL.md`](../../rebase/SKILL.md)) Phase 1–4 against PR's
|
|
66
65
|
base ref. After rebase + force-with-lease push, new HEAD invalidates
|
|
@@ -68,22 +67,23 @@ Persist `mergeStateStatus` into `merge_state_status`. Decide:
|
|
|
68
67
|
`copilot_clean_at = null`, `merge_state_status = null`, `phase = BUGBOT`,
|
|
69
68
|
Step 3 on new HEAD, schedule next wakeup, return. Loop re-runs from
|
|
70
69
|
scratch on new HEAD.
|
|
71
|
-
- **`
|
|
70
|
+
- **`mergeable_state` is `"blocked"`, `"behind"`, or `"unknown"` for
|
|
72
71
|
non-conflict reasons** (required checks pending, branch behind base
|
|
73
72
|
without conflicts GitHub cannot auto-resolve): **hard blocker** per
|
|
74
73
|
[stop-conditions.md](stop-conditions.md) — do not invent a fix. Report specific
|
|
75
|
-
`
|
|
74
|
+
`mergeable_state`, omit loop pacing.
|
|
76
75
|
|
|
77
76
|
## (c) Post-convergence Copilot review request
|
|
78
77
|
|
|
79
78
|
Once gates (a) and (b) both pass (Copilot clean at `current_head` *or* no
|
|
80
|
-
Copilot review yet, AND `
|
|
79
|
+
Copilot review yet, AND `mergeable_state == "clean"`), request Copilot
|
|
81
80
|
review:
|
|
82
81
|
|
|
83
|
-
```bash
|
|
84
|
-
python "${CLAUDE_SKILL_DIR}/scripts/request_copilot_review.py" \
|
|
85
|
-
--owner <OWNER> --repo <REPO> --number <NUMBER>
|
|
86
82
|
```
|
|
83
|
+
request_copilot_review(owner=OWNER, repo=REPO, pullNumber=NUMBER)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
When the `request_copilot_review` MCP tool is unavailable, use `add_issue_comment` as fallback: `add_issue_comment(owner=OWNER, repo=REPO, issueNumber=NUMBER, body="@copilot review")`.
|
|
87
87
|
|
|
88
88
|
After request, schedule next wakeup and return — next tick checks response.
|
|
89
89
|
|
|
@@ -91,7 +91,7 @@ Next tick with `phase == BUGTEAM` and prior state preserved → re-run gate
|
|
|
91
91
|
(a) first. Decide:
|
|
92
92
|
|
|
93
93
|
- **Copilot review `clean` (state `APPROVED`):** Set `copilot_clean_at =
|
|
94
|
-
current_head`. Mark PR ready (`
|
|
94
|
+
current_head`. Mark PR ready (`update_pull_request(pullNumber=NUMBER, owner=OWNER, repo=REPO, draft=false)`), report convergence
|
|
95
95
|
per §(d), terminate per [stop-conditions.md](stop-conditions.md) / Convergence.
|
|
96
96
|
- **Copilot review `dirty`:** Treat identically to gate (a) dirty path —
|
|
97
97
|
spawn Agent (subagent_type: clean-coder) to fix in same PR, restart convergence from BUGBOT. Follow [Single-PR fix workflow](fix-protocol.md#single-pr-fix-workflow).
|
|
@@ -107,16 +107,14 @@ Next tick with `phase == BUGTEAM` and prior state preserved → re-run gate
|
|
|
107
107
|
## (d) Mark ready and report
|
|
108
108
|
|
|
109
109
|
Only when all four gates pass — bugbot CLEAN ∧ bugteam CLEAN ∧
|
|
110
|
-
`
|
|
110
|
+
`mergeable_state == "clean"` ∧ Copilot CLEAN at HEAD — run:
|
|
111
111
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
```
|
|
112
|
+
Use the `update_pull_request` MCP tool:
|
|
113
|
+
|
|
114
|
+
update_pull_request(pullNumber=NUMBER, owner=OWNER, repo=REPO, draft=false)
|
|
116
115
|
|
|
117
|
-
|
|
118
|
-
equivalent. With `state.json`, append convergence row to
|
|
116
|
+
With `state.json`, append convergence row to
|
|
119
117
|
`<TMPDIR>/pr-converge-<session_id>/converged.log` per `multi-pr-orchestration.md` §Memory; else skip.
|
|
120
118
|
Report: `PR #<NUMBER> converged: bugbot CLEAN at <SHA>, bugteam CLEAN at
|
|
121
|
-
<SHA>,
|
|
119
|
+
<SHA>, mergeable_state CLEAN, copilot CLEAN at <SHA>; marked ready for
|
|
122
120
|
review`. **Omit loop pacing** per **Convergence** of active pacing workflow.
|
|
@@ -25,7 +25,7 @@ convergence or stop]
|
|
|
25
25
|
</example>
|
|
26
26
|
|
|
27
27
|
<example> BUGTEAM phase, bugteam reports convergence and `bugbot_clean_at
|
|
28
|
-
== current_head`. Claude: [runs `
|
|
28
|
+
== current_head`. Claude: [runs `update_pull_request(pullNumber=NUMBER, owner=OWNER, repo=REPO, draft=false)`, reports "PR
|
|
29
29
|
converged: bugbot CLEAN at <SHA>, bugteam CLEAN at <SHA>; marked ready for
|
|
30
30
|
review", applies **Convergence** from `workflows/schedule-wakeup-loop.md`]
|
|
31
31
|
</example>
|
|
@@ -58,11 +58,11 @@ HEAD, schedules next wakeup]
|
|
|
58
58
|
</example>
|
|
59
59
|
|
|
60
60
|
<example> Back-to-back clean, mergeability CLEAN, no Copilot review on
|
|
61
|
-
`current_head`. Claude requests Copilot via `
|
|
61
|
+
`current_head`. Claude requests Copilot via `add_issue_comment(owner=OWNER, repo=REPO, issueNumber=NUMBER, body="@copilot review")`,
|
|
62
62
|
waits one tick. Next tick: Copilot review `state: APPROVED`. Claude: [sets
|
|
63
|
-
`copilot_clean_at = current_head`; runs `
|
|
63
|
+
`copilot_clean_at = current_head`; runs `update_pull_request(pullNumber=NUMBER, owner=OWNER, repo=REPO, draft=false)`; reports "PR
|
|
64
64
|
#N converged: bugbot CLEAN at <SHA>, bugteam CLEAN at <SHA>,
|
|
65
|
-
|
|
65
|
+
mergeable_state clean, copilot CLEAN; marked ready for review"]
|
|
66
66
|
</example>
|
|
67
67
|
|
|
68
68
|
<example> Back-to-back clean, mergeability CLEAN, post-convergence Copilot
|
|
@@ -8,8 +8,8 @@ per [ground-rules.md](ground-rules.md).
|
|
|
8
8
|
**Multi-PR (`state.json`) teammate obligations** (plus TDD, commit, push):
|
|
9
9
|
|
|
10
10
|
- Replies inline on each addressed finding via
|
|
11
|
-
`
|
|
12
|
-
matching §Audit result → fix worker step 4 — **before** writing
|
|
11
|
+
`add_reply_to_pull_request_comment(owner, repo, pullNumber, commentId, body)`
|
|
12
|
+
(what changed + commit identifier), matching §Audit result → fix worker step 4 — **before** writing
|
|
13
13
|
`state.json` and going idle.
|
|
14
14
|
- Writes `last_action: "fix_pushed"`, `current_head: <new SHA>`,
|
|
15
15
|
`bugbot_clean_at: null`, `phase: "BUGBOT"`, `status: "awaiting_bugbot"`,
|
|
@@ -40,12 +40,10 @@ git push origin <BRANCH>
|
|
|
40
40
|
```
|
|
41
41
|
**Pre-push gate:** honor hooks; full-stop on bypass. Capture new HEAD
|
|
42
42
|
only after both gates pass; set `current_head`, `bugbot_clean_at = null`.
|
|
43
|
-
- Reply inline on each addressed comment thread using
|
|
44
|
-
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
--owner <OWNER> --repo <REPO> --number <NUMBER> \
|
|
48
|
-
--comment-id <COMMENT_ID> --body-file <path/to/reply.md>
|
|
43
|
+
- Reply inline on each addressed comment thread using the `add_reply_to_pull_request_comment` MCP tool:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
add_reply_to_pull_request_comment(owner=OWNER, repo=REPO, pullNumber=NUMBER, commentId=COMMENT_ID, body="Fixed in <SHA> — <what changed>")
|
|
49
47
|
```
|
|
50
48
|
- **After pushing a fix, always run Step 3 (`bugbot run`) in the same
|
|
51
49
|
tick** regardless of phase. New commit **resets full convergence cycle**:
|
|
@@ -25,7 +25,7 @@ Create once at session start. Each teammate writes result before going idle.
|
|
|
25
25
|
|
|
26
26
|
**Directory lifecycle:** Keep `<TMPDIR>/pr-converge-<session_id>/` until every
|
|
27
27
|
`prs[...]` is `converged` or `blocked`, or user stops. Then delete folder.
|
|
28
|
-
`
|
|
28
|
+
`update_pull_request(draft=false)` on GitHub is canonical record. See
|
|
29
29
|
[Memory](#memory) for optional append-only log.
|
|
30
30
|
|
|
31
31
|
**Barebones schema:**
|
|
@@ -107,7 +107,7 @@ Bugfind subagent completes (findings or clean):
|
|
|
107
107
|
2. Applies TDD fixes (test first, then production).
|
|
108
108
|
3. Commits, pushes one fix commit.
|
|
109
109
|
4. Replies inline on each addressed finding via
|
|
110
|
-
`
|
|
110
|
+
`add_reply_to_pull_request_comment(owner, repo, pullNumber, commentId, body)`.
|
|
111
111
|
5. Writes `state.json` (per §Concurrency): `last_action: "fix_pushed"`,
|
|
112
112
|
`current_head: <new SHA>`, `bugbot_clean_at: null`, `phase:
|
|
113
113
|
"BUGBOT"`, `status: "awaiting_bugbot"`, `last_updated` ISO-8601 UTC.
|
|
@@ -116,7 +116,7 @@ Bugfind subagent completes (findings or clean):
|
|
|
116
116
|
- **PRs with zero findings:** spawn one `general-purpose` subagent per PR via
|
|
117
117
|
`Agent(subagent_type="general-purpose", run_in_background=true)`. Subagent:
|
|
118
118
|
1. `bugbot_clean_at == current_head` (back-to-back clean): run
|
|
119
|
-
`
|
|
119
|
+
`update_pull_request(pullNumber=PR_NUMBER, owner=OWNER, repo=REPO, draft=false)`, append convergence row to
|
|
120
120
|
`<TMPDIR>/pr-converge-<session_id>/converged.log` per §Memory, then
|
|
121
121
|
write `state.json` (per §Concurrency) with `status: "converged"`,
|
|
122
122
|
`last_action: "converged"` (or `marked_ready`), `phase: "BUGBOT"`,
|
|
@@ -125,7 +125,7 @@ Bugfind subagent completes (findings or clean):
|
|
|
125
125
|
duplicate work.
|
|
126
126
|
2. Else: update `state.json` (per §Concurrency) with `last_action:
|
|
127
127
|
"audit_clean"`, `status: "awaiting_bugbot"`, `phase: "BUGBOT"`, then
|
|
128
|
-
trigger bugbot via `
|
|
128
|
+
trigger bugbot via `add_issue_comment(owner, repo, issueNumber, body="bugbot run")`.
|
|
129
129
|
3. Goes idle.
|
|
130
130
|
|
|
131
131
|
### Fix result → general-purpose per PR
|
|
@@ -135,11 +135,11 @@ When bugfix (clean-coder) subagent completes after push:
|
|
|
135
135
|
- Spawn one `general-purpose` subagent per PR via
|
|
136
136
|
`Agent(subagent_type="general-purpose", run_in_background=true)`. Subagent:
|
|
137
137
|
1. Reads `state.json` for its PR.
|
|
138
|
-
2. Triggers bugbot via `
|
|
139
|
-
3. Polls `
|
|
140
|
-
anchored to `current_head` appears
|
|
138
|
+
2. Triggers bugbot via `add_issue_comment(owner, repo, issueNumber, body="bugbot run")`.
|
|
139
|
+
3. Polls `pull_request_read(method="get_reviews")` every 60s (up to 10 polls) until review
|
|
140
|
+
anchored to `current_head` appears with `commit_id == current_head`.
|
|
141
141
|
4. **Poll / classify loop** (repeat from 4a whenever 4c retries):
|
|
142
|
-
- **4a.** Fetch inline comments via `
|
|
142
|
+
- **4a.** Fetch inline comments via `pull_request_read(method="get_review_comments")` filtered by review ID and `commit_id == current_head`.
|
|
143
143
|
- **4b.** Classify — three outcomes (same as `SKILL.md` Step 2 BUGBOT):
|
|
144
144
|
- **`clean`:** review body clean, zero unaddressed inline findings.
|
|
145
145
|
- **`dirty`:** ≥1 unaddressed inline finding for `current_head`
|
|
@@ -186,7 +186,7 @@ When bugfix (clean-coder) subagent completes after push:
|
|
|
186
186
|
Run directory `<TMPDIR>/pr-converge-<session_id>/` holds `state.json` and
|
|
187
187
|
optional `converged.log`. Keep from first create until every PR under `prs`
|
|
188
188
|
is `converged` or `blocked`, or **Stop conditions** ends loop. Safe to
|
|
189
|
-
delete folder after — `
|
|
189
|
+
delete folder after — `update_pull_request(draft=false)` on GitHub is
|
|
190
190
|
canonical record. Folder skill, not a plugin package; do **not** rely
|
|
191
191
|
on `${CLAUDE_PLUGIN_DATA}`. OS/disk cleanup of `<TMPDIR>` (reboot, policy)
|
|
192
192
|
can remove files mid-run — environmental risk.
|
|
@@ -196,7 +196,7 @@ can remove files mid-run — environmental risk.
|
|
|
196
196
|
- **Path:** sibling of `state.json`.
|
|
197
197
|
- **Format:** one tab-separated row per converged PR: ISO8601 UTC,
|
|
198
198
|
owner/repo#number, bugbot SHA, bugteam SHA.
|
|
199
|
-
- **Append site:** agent running `
|
|
199
|
+
- **Append site:** agent running `update_pull_request(pullNumber=PR_NUMBER, owner=OWNER, repo=REPO, draft=false)`. Append **before**
|
|
200
200
|
locked `state.json` publish so log row survives failed merge.
|
|
201
201
|
- **Never read inside loop.** User / follow-up tooling only.
|
|
202
202
|
|
|
@@ -37,12 +37,12 @@ state line when **no** `state.json` (single-PR only). With `state.json`, do
|
|
|
37
37
|
**not** increment here — orchestrator's per-tick bump is sole increment.
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
|
|
40
|
+
pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get") → `.head.sha`
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
If owner/repo/number are not yet known, extract them from the PR URL
|
|
43
|
+
If owner/repo/number are not yet known, extract them from the PR URL.
|
|
44
44
|
|
|
45
|
-
Capture `number`, `
|
|
45
|
+
Capture `number`, `head.sha` (= `current_head`), owner/repo, branch.
|
|
46
46
|
|
|
47
47
|
## Step 2: Branch on `phase`
|
|
48
48
|
|
|
@@ -50,15 +50,14 @@ Capture `number`, `headRefOid` (= `current_head`), owner/repo, branch.
|
|
|
50
50
|
|
|
51
51
|
a. Fetch Cursor Bugbot reviews newest-first, walk back until first clean:
|
|
52
52
|
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
```
|
|
54
|
+
pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get_reviews")
|
|
55
|
+
→ filter `.user.login` for cursor/bugbot, sort by `.submitted_at` descending
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
Track dirty entries
|
|
59
|
-
this tick.
|
|
58
|
+
Track dirty entries (review body contains `BUGBOT_REVIEW` markers with finding content); Fix protocol reads them back later this tick.
|
|
60
59
|
|
|
61
|
-
Iterate from index 0 (most recent) toward older:
|
|
60
|
+
Iterate from index 0 (most recent) toward older:
|
|
62
61
|
|
|
63
62
|
- Dirty review → append JSON line with `{review_id, commit_id,
|
|
64
63
|
submitted_at, body}`.
|
|
@@ -71,14 +70,12 @@ review for decisions below. When branch routes to **Fix protocol**, address
|
|
|
71
70
|
**every** entry in `$dirty_reviews_path` — not just index 0.
|
|
72
71
|
|
|
73
72
|
b. Fetch unaddressed inline comments from `cursor[bot]` for newest Bugbot
|
|
74
|
-
review on `current_head
|
|
75
|
-
resolves review via reviews list, returns only inline rows whose
|
|
76
|
-
`pull_request_review_id` matches that review (excludes stale threads from
|
|
77
|
-
older reviews on same SHA).
|
|
73
|
+
review on `current_head`:
|
|
78
74
|
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
```
|
|
76
|
+
pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get_review_comments")
|
|
77
|
+
→ filter threads where `is_outdated == false` AND `is_resolved == false`
|
|
78
|
+
AND any comment has `.author` matching cursor/bugbot (case-insensitive substring)
|
|
82
79
|
```
|
|
83
80
|
|
|
84
81
|
c. Decide (four branches; match first whose predicate holds):
|
|
@@ -96,7 +93,7 @@ c. Decide (four branches; match first whose predicate holds):
|
|
|
96
93
|
`state.json`, goes idle; Step 3 on new HEAD runs after via
|
|
97
94
|
orchestrator-spawned follow-up agent (§Fix result → general-purpose).
|
|
98
95
|
No `state.json` (single-PR): spawn Agent (subagent_type: clean-coder) to implement → push → reply inline on each thread
|
|
99
|
-
via `
|
|
96
|
+
via `add_reply_to_pull_request_comment` MCP → Step 3 in same tick (see
|
|
100
97
|
[Single-PR fix workflow](fix-protocol.md#single-pr-fix-workflow) for
|
|
101
98
|
full contract).
|
|
102
99
|
Schedule next wakeup, return.
|
|
@@ -125,8 +122,7 @@ Skill({skill: "bugteam", args:
|
|
|
125
122
|
b. **Re-resolve current HEAD** — bugteam may have pushed commits during
|
|
126
123
|
its run. `current_head` from Step 1 is potentially stale:
|
|
127
124
|
```bash
|
|
128
|
-
|
|
129
|
-
--owner <OWNER> --repo <REPO> --number <NUMBER>)
|
|
125
|
+
pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get") → `.head.sha`
|
|
130
126
|
```
|
|
131
127
|
If `new_head != current_head`, set `current_head = new_head` AND
|
|
132
128
|
`bugbot_clean_at = null`. New commits invalidate bugbot's prior clean.
|
|
@@ -146,25 +142,14 @@ never falsely terminates:
|
|
|
146
142
|
**omit loop pacing** per **Convergence** of active pacing workflow.
|
|
147
143
|
- **Convergence BUT `bugbot_clean_at != current_head` (no push):**
|
|
148
144
|
`phase = BUGBOT`, schedule next wakeup, return.
|
|
149
|
-
- **Findings without committed fixes:** spawn Agent (subagent_type: clean-coder) to implement fixes and push, then reply inline via `
|
|
145
|
+
- **Findings without committed fixes:** spawn Agent (subagent_type: clean-coder) to implement fixes and push, then reply inline via `add_reply_to_pull_request_comment` MCP, following [Single-PR fix workflow](fix-protocol.md#single-pr-fix-workflow).
|
|
150
146
|
`phase = BUGBOT`, schedule next wakeup, return.
|
|
151
147
|
|
|
152
148
|
## Step 3: Re-trigger bugbot
|
|
153
149
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
```bash
|
|
157
|
-
python "${CLAUDE_SKILL_DIR}/scripts/trigger_bugbot.py" \
|
|
158
|
-
--owner <OWNER> --repo <REPO> --number <NUMBER>
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
**Bundled PowerShell alternative** (same gh-body-file contract):
|
|
150
|
+
Use the `add_issue_comment` MCP tool:
|
|
162
151
|
|
|
163
|
-
|
|
164
|
-
POST_BUGBOT_RUN="$HOME/.claude/skills/pr-converge/scripts/post-bugbot-run.ps1"
|
|
165
|
-
pwsh -NoProfile -ExecutionPolicy Bypass -File "$POST_BUGBOT_RUN" \
|
|
166
|
-
"https://github.com/<OWNER>/<REPO>/pull/<NUMBER>"
|
|
167
|
-
```
|
|
152
|
+
add_issue_comment(owner="OWNER", repo="REPO", issueNumber=NUMBER, body="bugbot run")
|
|
168
153
|
|
|
169
154
|
`bugbot run` is empirically the only re-trigger Cursor Bugbot recognizes;
|
|
170
155
|
alternative phrasings (`re-review`, `bugbot please`, etc.) silently no-op.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Stop conditions
|
|
2
2
|
|
|
3
3
|
- **Convergence** (back-to-back clean ∧ no outstanding Copilot findings
|
|
4
|
-
on `current_head` ∧ `
|
|
5
|
-
|
|
6
|
-
`current_head`):
|
|
4
|
+
on `current_head` ∧ `mergeable_state == "clean"` with `mergeable ==
|
|
5
|
+
true` ∧ post-convergence Copilot request returned `clean` at
|
|
6
|
+
`current_head`): use `update_pull_request(pullNumber=NUMBER, owner=OWNER, repo=REPO, draft=false)`. With
|
|
7
7
|
`state.json`, append convergence row to
|
|
8
8
|
`<TMPDIR>/pr-converge-<session_id>/converged.log` per `multi-pr-orchestration.md` §Memory; else
|
|
9
9
|
skip. Report [convergence-gates.md](convergence-gates.md) (d) summary, then **omit loop pacing**
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
`current_head` after three consecutive wakeups. Report specific
|
|
17
17
|
blocker and diagnosis, **omit loop pacing** per
|
|
18
18
|
`../workflows/schedule-wakeup-loop.md`.
|
|
19
|
-
- **Hard blocker (`
|
|
20
|
-
`
|
|
19
|
+
- **Hard blocker (`mergeable_state` non-clean non-dirty):**
|
|
20
|
+
`mergeable_state` is `"blocked"`, `"unknown"`, or `"behind"` (required
|
|
21
21
|
checks pending, branch behind base without textual conflicts, or
|
|
22
22
|
GitHub indeterminate). Investigate before retrying; `rebase` skill
|
|
23
|
-
handles `
|
|
24
|
-
`
|
|
23
|
+
handles `"dirty"` (textual conflicts) only. Report specific
|
|
24
|
+
`mergeable_state`, **omit loop pacing**.
|
|
25
25
|
- **User stops loop:** "stop the converge loop" → **omit loop pacing**
|
|
26
26
|
per `../workflows/schedule-wakeup-loop.md`.
|