claude-dev-env 1.35.0 → 1.36.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/agents/clean-coder.md +109 -1
- package/bin/install.mjs +28 -8
- package/bin/install.test.mjs +9 -1
- package/docs/CODE_RULES.md +3 -0
- package/docs/agents-md-alignment-plan.md +123 -0
- package/hooks/blocking/code_rules_enforcer.py +451 -39
- package/hooks/blocking/es_exe_path_rewriter.py +10 -4
- package/hooks/blocking/test_code_rules_enforcer.py +182 -0
- package/hooks/blocking/test_code_rules_enforcer_banned_identifier.py +106 -0
- package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +173 -0
- package/hooks/blocking/test_code_rules_enforcer_collection_prefix.py +191 -0
- package/hooks/blocking/test_code_rules_enforcer_constant_equality.py +40 -0
- package/hooks/blocking/test_code_rules_enforcer_hardcoded_user_path.py +291 -0
- package/hooks/blocking/test_code_rules_enforcer_loop_variable_naming.py +87 -3
- package/hooks/blocking/test_code_rules_enforcer_naming_pattern.py +49 -0
- package/hooks/blocking/test_code_rules_enforcer_sys_path_insert.py +157 -0
- package/hooks/blocking/test_code_rules_enforcer_unused_imports.py +244 -0
- package/hooks/blocking/test_es_exe_path_rewriter.py +81 -3
- package/hooks/blocking/test_windows_rmtree_blocker.py +120 -8
- package/hooks/blocking/windows_rmtree_blocker.py +23 -6
- package/hooks/config/banned_identifiers_constants.py +24 -0
- package/hooks/config/hardcoded_user_path_constants.py +12 -0
- package/hooks/config/hook_log_extractor_constants.py +1 -1
- package/hooks/config/pre_tool_use_stdin.py +48 -0
- package/hooks/config/setup_project_paths_constants.py +4 -0
- package/hooks/config/stuttering_check_config.py +14 -0
- package/hooks/config/stuttering_import_binding_constants.py +11 -0
- package/hooks/config/sys_path_insert_constants.py +4 -0
- package/hooks/config/test_banned_identifiers_constants.py +48 -0
- package/hooks/config/test_hardcoded_user_path_constants.py +78 -0
- package/hooks/config/test_hook_log_extractor_constants.py +3 -3
- package/hooks/config/test_pre_tool_use_stdin.py +80 -0
- package/hooks/config/unused_module_import_constants.py +7 -0
- package/hooks/config/windows_rmtree_blocker_constants.py +3 -0
- package/hooks/diagnostic/hook_log_stop_wrapper.py +7 -4
- package/hooks/git-hooks/config.py +3 -3
- package/hooks/git-hooks/test_gate_utils.py +10 -10
- package/hooks/mypy.ini +2 -0
- package/package.json +1 -1
- package/rules/gh-paginate.md +125 -0
- package/skills/bugteam/CONSTRAINTS.md +12 -6
- package/skills/bugteam/SKILL.md +364 -154
- package/skills/bugteam/SKILL_EVALS.md +25 -23
- package/skills/bugteam/reference/README.md +2 -0
- package/skills/bugteam/reference/audit-and-teammates.md +2 -2
- package/skills/bugteam/reference/teardown-publish-permissions.md +1 -1
- package/skills/bugteam/reference/workflow-path-a-orchestrated-teams.md +113 -0
- package/skills/bugteam/reference/workflow-path-b-task-harness.md +48 -0
- package/skills/bugteam/scripts/reflow_skill_md.py +298 -0
- package/skills/bugteam/test_skill_additions.py +13 -4
- package/skills/bugteam/test_team_lifecycle.py +103 -0
- package/skills/findbugs/SKILL.md +3 -3
- package/skills/fixbugs/SKILL.md +4 -4
- package/skills/monitor-open-prs/SKILL.md +32 -2
- package/skills/monitor-open-prs/test_team_lifecycle.py +46 -0
- package/skills/pr-converge/SKILL.md +1206 -131
- package/skills/pr-converge/scripts/README.md +145 -0
- package/skills/pr-converge/scripts/caller-window-pid.ps1 +86 -0
- package/skills/pr-converge/scripts/check_pr_mergeability.py +79 -0
- package/skills/pr-converge/scripts/config/pr_converge_constants.py +65 -0
- package/skills/pr-converge/scripts/config/test_pr_converge_constants.py +176 -0
- package/skills/pr-converge/scripts/cursor-agents-continue-caller.cmd +9 -0
- package/skills/pr-converge/scripts/cursor-agents-continue-stop-others.ps1 +16 -0
- package/skills/pr-converge/scripts/cursor-agents-continue.ahk +172 -0
- package/skills/pr-converge/scripts/cursor-agents-continue.cmd +2 -0
- package/skills/pr-converge/scripts/evict_cached_config_modules.py +20 -0
- package/skills/pr-converge/scripts/fetch_bugbot_inline_comments.py +110 -0
- package/skills/pr-converge/scripts/fetch_bugbot_reviews.py +103 -0
- package/skills/pr-converge/scripts/fetch_copilot_inline_comments.py +112 -0
- package/skills/pr-converge/scripts/fetch_copilot_reviews.py +121 -0
- package/skills/pr-converge/scripts/mark_pr_ready.py +54 -0
- package/skills/pr-converge/scripts/open_followup_copilot_pr.py +136 -0
- package/skills/pr-converge/scripts/post-bugbot-run.helpers.ps1 +49 -0
- package/skills/pr-converge/scripts/post-bugbot-run.ps1 +33 -0
- package/skills/pr-converge/scripts/reflow_skill_md.py +288 -0
- package/skills/pr-converge/scripts/reply_to_inline_comment.py +84 -0
- package/skills/pr-converge/scripts/request_copilot_review.py +71 -0
- package/skills/pr-converge/scripts/resolve_pr_head.py +58 -0
- package/skills/pr-converge/scripts/review_field_helpers.py +43 -0
- package/skills/pr-converge/scripts/test_check_pr_mergeability.py +126 -0
- package/skills/pr-converge/scripts/test_evict_cached_config_modules.py +22 -0
- package/skills/pr-converge/scripts/test_fetch_bugbot_inline_comments.py +342 -0
- package/skills/pr-converge/scripts/test_fetch_bugbot_reviews.py +220 -0
- package/skills/pr-converge/scripts/test_fetch_copilot_inline_comments.py +372 -0
- package/skills/pr-converge/scripts/test_fetch_copilot_reviews.py +280 -0
- package/skills/pr-converge/scripts/test_mark_pr_ready.py +69 -0
- package/skills/pr-converge/scripts/test_open_followup_copilot_pr.py +236 -0
- package/skills/pr-converge/scripts/test_post_bugbot_run.py +195 -0
- package/skills/pr-converge/scripts/test_reply_to_inline_comment.py +159 -0
- package/skills/pr-converge/scripts/test_request_copilot_review.py +101 -0
- package/skills/pr-converge/scripts/test_resolve_pr_head.py +79 -0
- package/skills/pr-converge/scripts/test_review_field_helpers.py +80 -0
- package/skills/pr-converge/scripts/test_trigger_bugbot.py +139 -0
- package/skills/pr-converge/scripts/test_view_pr_context.py +111 -0
- package/skills/pr-converge/scripts/trigger_bugbot.py +77 -0
- package/skills/pr-converge/scripts/view_pr_context.py +47 -0
- package/skills/pr-converge/test_team_lifecycle.py +56 -0
- package/skills/pr-converge/workflows/ahk-auto-continue-loop.md +108 -0
- package/skills/pr-converge/workflows/schedule-wakeup-loop.md +37 -0
- package/skills/qbug/SKILL.md +4 -4
- package/skills/qbug/test_qbug_skill_post_fix_audit.py +2 -2
- package/skills/resume-review/SKILL.md +261 -0
- package/skills/bugteam/scripts/README.md +0 -58
- package/skills/bugteam/scripts/_claude_permissions_common.py +0 -219
- package/skills/bugteam/scripts/bugteam_code_rules_gate.py +0 -633
- package/skills/bugteam/scripts/bugteam_fix_hookspath.py +0 -260
- package/skills/bugteam/scripts/bugteam_preflight.py +0 -201
- package/skills/bugteam/scripts/config/bugteam_fix_hookspath_constants.py +0 -17
- package/skills/bugteam/scripts/grant_project_claude_permissions.py +0 -109
- package/skills/bugteam/scripts/revoke_project_claude_permissions.py +0 -135
- package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +0 -271
- package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +0 -267
- package/skills/bugteam/scripts/test_bugteam_preflight.py +0 -189
- package/skills/bugteam/scripts/test_claude_permissions_common.py +0 -44
- /package/skills/{bugteam → pr-converge}/scripts/config/__init__.py +0 -0
package/skills/bugteam/SKILL.md
CHANGED
|
@@ -1,34 +1,120 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bugteam
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
Open pull request audit–fix until convergence: CODE_RULES gate, clean-room
|
|
5
|
+
audit (`code-quality-agent`, opus) and fix (`clean-coder`, opus), per-loop
|
|
6
|
+
GitHub reviews, 10-audit cap; grant then revoke `.claude/**`. **Path A** when
|
|
7
|
+
`CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` (orchestrated teams, `TeamCreate`).
|
|
8
|
+
**Path B** otherwise (Task harness — workflow in
|
|
9
|
+
`reference/workflow-path-b-task-harness.md`). **This `SKILL.md` holds only
|
|
10
|
+
shared steps**; per-path harness lives in `reference/workflow-path-*.md`.
|
|
11
|
+
Triggers: '/bugteam', 'run the bug team', 'auto-fix the PR until clean', 'loop
|
|
12
|
+
audit and fix'.
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
# Bugteam
|
|
16
16
|
|
|
17
|
-
**Core principle:**
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
**Core principle:** Audit–fix until convergence. **Bugfind:**
|
|
18
|
+
`code-quality-agent`, fresh context each loop. **Bugfix:** `clean-coder`. Hard
|
|
19
|
+
cap: 10 audit loops. Grant `.claude/**` at start, revoke always at end.
|
|
20
|
+
|
|
21
|
+
**Path routing** picks **Path A** (orchestrated teams) vs **Path B** (Task
|
|
22
|
+
harness). Harness execution — `TeamCreate`, `Agent`/`Task` spawns,
|
|
23
|
+
`SendMessage`, `TeamDelete`, who runs Step 2.5 `gh api` — lives only in
|
|
24
|
+
[`reference/workflow-path-a-orchestrated-teams.md`][path-a] and
|
|
25
|
+
[`reference/workflow-path-b-task-harness.md`][path-b]. Verbatim doc quotes and
|
|
26
|
+
URLs: [`sources.md`](sources.md).
|
|
27
|
+
|
|
28
|
+
## Path routing (mandatory first branch)
|
|
29
|
+
|
|
30
|
+
At `/bugteam` entry, evaluate **once** (same rule as pr-converge §Team
|
|
31
|
+
infrastructure detection):
|
|
32
|
+
|
|
33
|
+
- **Path A** — `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` set and equals **`1`**
|
|
34
|
+
after trim → load and follow
|
|
35
|
+
[`reference/workflow-path-a-orchestrated-teams.md`][path-a] for every harness
|
|
36
|
+
step (with this `SKILL.md` for shared material).
|
|
37
|
+
- **Path B** — otherwise → load and follow
|
|
38
|
+
[`reference/workflow-path-b-task-harness.md`][path-b] for every harness step
|
|
39
|
+
(with this `SKILL.md` for shared material).
|
|
40
|
+
|
|
41
|
+
Shared material is **everything else in this file** plus
|
|
42
|
+
[`PROMPTS.md`](PROMPTS.md), [`EXAMPLES.md`](EXAMPLES.md),
|
|
43
|
+
[`CONSTRAINTS.md`](CONSTRAINTS.md) — agent types, models, XML, gates, cycle
|
|
44
|
+
state machine, Step 2.5 payload shapes, shared teardown `rmtree`, revoke, final
|
|
45
|
+
report.
|
|
46
|
+
|
|
47
|
+
## Team lifecycle (Path A only)
|
|
48
|
+
|
|
49
|
+
The `TeamCreate` / `TeamDelete` pair has historically been bound to a single
|
|
50
|
+
`/bugteam` invocation. That coupling fails when an orchestrator (`pr-converge`
|
|
51
|
+
multi-PR mode, `monitor-open-prs`) needs to call `/bugteam` repeatedly inside
|
|
52
|
+
one parent session: only one team can be led at a time, and a missed Step 4
|
|
53
|
+
leaks the team. To decouple, every Path A invocation reads
|
|
54
|
+
`BUGTEAM_TEAM_LIFECYCLE` (defaults to `auto`) and may also read
|
|
55
|
+
`BUGTEAM_TEAM_NAME`.
|
|
56
|
+
|
|
57
|
+
**`owned`**
|
|
58
|
+
|
|
59
|
+
- **Step 2:** `TeamCreate(<computed_team_name>)`. If the runtime returns
|
|
60
|
+
`Already leading team "<existing>". A leader can only manage one team at a
|
|
61
|
+
time.` → **error**: `Already leading team <existing>; rerun with
|
|
62
|
+
BUGTEAM_TEAM_LIFECYCLE=attach BUGTEAM_TEAM_NAME=<existing>`.
|
|
63
|
+
- **Step 4:** `TeamDelete()` (lead-owned).
|
|
64
|
+
- **Use case:** Pre-decoupling behavior. Use only when you know the session
|
|
65
|
+
leads no other team.
|
|
66
|
+
|
|
67
|
+
**`attach`**
|
|
68
|
+
|
|
69
|
+
- **Step 2:** Require `BUGTEAM_TEAM_NAME`. Treat that team as already-led; do
|
|
70
|
+
**not** call `TeamCreate`.
|
|
71
|
+
- **Step 4:** **Skip** `TeamDelete` — the orchestrator owns teardown.
|
|
72
|
+
- **Use case:** Orchestrators (pr-converge multi-PR, monitor-open-prs) that
|
|
73
|
+
explicitly created a team and will tear it down themselves.
|
|
74
|
+
|
|
75
|
+
### `auto` (**default: `auto`**)
|
|
76
|
+
|
|
77
|
+
- **Step 2:** Try `TeamCreate(<computed_team_name>)`. On `Already leading team
|
|
78
|
+
"<existing>"` → parse `<existing>`, attach (do **not** call `TeamCreate`
|
|
79
|
+
again), set `team_owned=false`. On success → set `team_owned=true`.
|
|
80
|
+
- **Step 4:** If `team_owned=true` → `TeamDelete()`. Else → **skip**
|
|
81
|
+
`TeamDelete`.
|
|
82
|
+
- **Use case:** All callers when in doubt. Solo invocations behave like `owned`;
|
|
83
|
+
nested or repeated invocations attach safely.
|
|
84
|
+
|
|
85
|
+
**`team_owned` flag** — set in Step 2 by all three modes
|
|
86
|
+
(`owned` always `true`; `attach` always `false`; `auto` reflects the
|
|
87
|
+
`TeamCreate` outcome). Read in Step
|
|
88
|
+
4 to decide whether to call `TeamDelete`. The same flag also gates
|
|
89
|
+
`<team_temp_dir>` `rmtree`: when `team_owned=false`, only the per-PR subfolders
|
|
90
|
+
this invocation created (`<team_temp_dir>/pr-<N>/`) are removed; the
|
|
91
|
+
orchestrator's parent directory survives.
|
|
92
|
+
|
|
93
|
+
**Path B note:** Path B does not use `TeamCreate` / `TeamDelete`, so
|
|
94
|
+
`BUGTEAM_TEAM_LIFECYCLE` is read but only its `team_temp_dir` cleanup behavior
|
|
95
|
+
applies. `team_owned` is treated as `true` by default in Path B; orchestrators
|
|
96
|
+
driving Path B that share a temp directory should set
|
|
97
|
+
`BUGTEAM_TEAM_LIFECYCLE=attach` so the per-PR subfolder cleanup rule applies.
|
|
20
98
|
|
|
21
99
|
## Contents
|
|
22
100
|
|
|
23
|
-
Orchestration lives here; companion files hold prompts, invariants, examples,
|
|
24
|
-
|
|
25
|
-
|
|
101
|
+
Orchestration lives here; companion files hold prompts, invariants, examples,
|
|
102
|
+
citations, and domain reference notes. Scan this list before a partial read.
|
|
103
|
+
|
|
104
|
+
- [Path routing](#path-routing-mandatory-first-branch) — Path A vs Path B
|
|
105
|
+
- [Team lifecycle](#team-lifecycle-path-a-only) — `owned` / `attach` / `auto`
|
|
106
|
+
modes; orchestrator-owned teams
|
|
107
|
+
- [`reference/workflow-path-a-orchestrated-teams.md`][path-a] — Path A harness
|
|
108
|
+
(orchestrated teams)
|
|
109
|
+
- [`reference/workflow-path-b-task-harness.md`][path-b] — Path B harness (Task
|
|
110
|
+
harness)
|
|
111
|
+
- When this skill applies — refusal cases and trigger conditions
|
|
26
112
|
- Utility scripts — pre-flight (`scripts/`, executed not inlined)
|
|
27
113
|
- Pre-audit gate — `validate_content` before each AUDIT
|
|
28
114
|
- The Process — checklist + Steps 0–6
|
|
29
115
|
- Step 0 — Grant project permissions
|
|
30
116
|
- Step 1 — Resolve PR scope
|
|
31
|
-
- Step 2 —
|
|
117
|
+
- Step 2 — Path harness + loop state
|
|
32
118
|
- Step 2.5 — PR comment lifecycle (per-loop review + fix replies)
|
|
33
119
|
- Step 3 — Cycle (AUDIT ↔ FIX, exits)
|
|
34
120
|
- Step 4 — Teardown + clean tree
|
|
@@ -39,7 +125,8 @@ Orchestration lives here; companion files hold prompts, invariants, examples, ci
|
|
|
39
125
|
- [`EXAMPLES.md`](EXAMPLES.md) — exit scenarios
|
|
40
126
|
- [`CONSTRAINTS.md`](CONSTRAINTS.md) — invariants and design rationale
|
|
41
127
|
- [`sources.md`](sources.md) — doc URLs and verbatim quotes
|
|
42
|
-
- [`reference/README.md`](reference/README.md) — expanded prose by topic
|
|
128
|
+
- [`reference/README.md`](reference/README.md) — expanded prose by topic
|
|
129
|
+
(design, team setup, GitHub reviews, cycle, teardown)
|
|
43
130
|
|
|
44
131
|
## When this skill applies
|
|
45
132
|
|
|
@@ -47,31 +134,53 @@ Orchestration lives here; companion files hold prompts, invariants, examples, ci
|
|
|
47
134
|
|
|
48
135
|
Refusals — first match wins; respond with the quoted line exactly and stop:
|
|
49
136
|
|
|
50
|
-
- **Agent teams not enabled.** Check `claude config get env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` and `~/.claude/settings.json`. If neither is `"1"`: `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 not set. /bugteam requires the agent teams feature. See https://code.claude.com/docs/en/agent-teams#enable-agent-teams.`
|
|
51
137
|
- **No PR or upstream diff.** `No PR or upstream diff. /bugteam needs a target.`
|
|
52
|
-
- **Dirty tree.** `Uncommitted changes detected. Stash, commit, or revert before
|
|
53
|
-
|
|
54
|
-
- **
|
|
138
|
+
- **Dirty tree.** `Uncommitted changes detected. Stash, commit, or revert before
|
|
139
|
+
/bugteam.`
|
|
140
|
+
- **Missing subagents.** Before Step 0, confirm `code-quality-agent` and
|
|
141
|
+
`clean-coder` exist. Else: `Required subagent type <name> not installed.
|
|
142
|
+
/bugteam needs both code-quality-agent and clean-coder available.`
|
|
143
|
+
- **Lead role must be held by the orchestrator.** Run /bugteam in the session
|
|
144
|
+
that received the user's command. **Path A:** lead calls `TeamCreate` per
|
|
145
|
+
[`reference/workflow-path-a-orchestrated-teams.md`][path-a]; runtime may
|
|
146
|
+
return `Already leading team "<name>". A leader can only manage one team at a
|
|
147
|
+
time.` **Path B:** lead runs the Task harness per
|
|
148
|
+
[`reference/workflow-path-b-task-harness.md`][path-b]; no `TeamCreate`.
|
|
55
149
|
|
|
56
150
|
## Utility scripts
|
|
57
151
|
|
|
58
|
-
Shell-heavy steps live under
|
|
152
|
+
Shell-heavy steps live under
|
|
153
|
+
[`_shared/pr-loop/scripts/`](../../_shared/pr-loop/scripts/) (run, do not paste
|
|
154
|
+
into context). Utility scripts are **executed**, not loaded as primary context
|
|
155
|
+
([`sources.md`](sources.md) § Progressive disclosure and utility scripts).
|
|
59
156
|
|
|
60
157
|
### Pre-flight (before Step 0)
|
|
61
158
|
|
|
62
159
|
```bash
|
|
63
|
-
python "${CLAUDE_SKILL_DIR}/scripts/
|
|
160
|
+
python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/preflight.py"
|
|
64
161
|
```
|
|
65
162
|
|
|
66
|
-
Non-zero → fix before grant. `BUGTEAM_PREFLIGHT_SKIP=1` emergency only.
|
|
163
|
+
Non-zero → fix before grant. `BUGTEAM_PREFLIGHT_SKIP=1` emergency only.
|
|
164
|
+
`--pre-commit` if `.pre-commit-config.yaml` exists.
|
|
67
165
|
|
|
68
|
-
**Auto-remediation for `core.hooksPath`:** when preflight fails with stderr
|
|
166
|
+
**Auto-remediation for `core.hooksPath`:** when preflight fails with stderr
|
|
167
|
+
containing `core.hooksPath` (the message starts with `bugteam_preflight:
|
|
168
|
+
core.hooksPath is`, or `Git-side CODE_RULES enforcement is not active`), Claude
|
|
169
|
+
must auto-invoke the fix script — do not fall through to `AskUserQuestion`, do
|
|
170
|
+
not punt to the user, do not ask for confirmation:
|
|
69
171
|
|
|
70
172
|
```bash
|
|
71
|
-
python "${CLAUDE_SKILL_DIR}/scripts/
|
|
173
|
+
python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/fix_hookspath.py"
|
|
72
174
|
```
|
|
73
175
|
|
|
74
|
-
The fix script removes any non-canonical local-scope override on the active
|
|
176
|
+
The fix script removes any non-canonical local-scope override on the active
|
|
177
|
+
repository, sets the global `core.hooksPath` to `~/.claude/hooks/git-hooks` if
|
|
178
|
+
missing or wrong, and re-runs `preflight.py`. Its exit code becomes the
|
|
179
|
+
preflight outcome. Exit 0 → continue to Step 0. Non-zero only when the
|
|
180
|
+
canonical hooks directory is missing (run `npx claude-dev-env .` first) or
|
|
181
|
+
`git config --global` writes are blocked. Other preflight failures (pytest,
|
|
182
|
+
pre-commit) still require manual fixes —
|
|
183
|
+
the auto-remediation only applies to the `core.hooksPath` failure mode.
|
|
75
184
|
|
|
76
185
|
## The Process
|
|
77
186
|
|
|
@@ -80,7 +189,7 @@ The fix script removes any non-canonical local-scope override on the active repo
|
|
|
80
189
|
```
|
|
81
190
|
[ ] Step 0: project permissions granted
|
|
82
191
|
[ ] Step 1: PR scope resolved
|
|
83
|
-
[ ] Step 2:
|
|
192
|
+
[ ] Step 2: loop state set + path harness applied
|
|
84
193
|
[ ] Step 3: cycle complete (converged | cap reached | stuck | error)
|
|
85
194
|
[ ] Step 4: team torn down + working tree clean
|
|
86
195
|
[ ] Step 4.5: PR description rewritten (or skip warning logged)
|
|
@@ -91,14 +200,22 @@ The fix script removes any non-canonical local-scope override on the active repo
|
|
|
91
200
|
### Step 0: Grant project permissions (once, first)
|
|
92
201
|
|
|
93
202
|
```bash
|
|
94
|
-
python
|
|
203
|
+
python
|
|
204
|
+
"${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/grant_project_claude_permis \
|
|
205
|
+
sions.py"
|
|
95
206
|
```
|
|
96
207
|
|
|
97
|
-
`${CLAUDE_SKILL_DIR}` is host-substituted before the shell runs (unlike normal
|
|
208
|
+
`${CLAUDE_SKILL_DIR}` is host-substituted before the shell runs (unlike normal
|
|
209
|
+
env expansion). Idempotent writes to `~/.claude/settings.json` from repo root.
|
|
210
|
+
Non-zero → stop. Revoke in Step 5 on every exit path.
|
|
98
211
|
|
|
99
212
|
### Step 1: Resolve PR scope (once)
|
|
100
213
|
|
|
101
|
-
Accept one or more PR numbers from the invocation. For each PR, run `gh pr view
|
|
214
|
+
Accept one or more PR numbers from the invocation. For each PR, run `gh pr view
|
|
215
|
+
--json number,baseRefName,headRefName,url` (falling back to the merge-base diff
|
|
216
|
+
path when no PR exists). Capture `all_prs = [{number, owner, repo, baseRef,
|
|
217
|
+
headRef, url}, ...]`. A single-PR invocation produces a one-element list and
|
|
218
|
+
follows the same downstream rules.
|
|
102
219
|
|
|
103
220
|
Keep: owner/repo, branches, PR number, URL — for all loops.
|
|
104
221
|
|
|
@@ -110,31 +227,29 @@ For each PR in all_prs:
|
|
|
110
227
|
2. Run `git worktree add "<team_temp_dir>/pr-<N>/worktree" origin/<headRef>`.
|
|
111
228
|
3. Record the absolute worktree path alongside the PR's other fields.
|
|
112
229
|
|
|
113
|
-
Teammates
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
**`--bugbot-retrigger` flag:** when present on the `/bugteam` invocation, after every successful FIX push in Step 3, post an additional `bugbot run` issue comment via the Step 2.5 issue-comments fallback endpoint (`POST .../issues/{issue}/comments`) to re-trigger Cursor's bugbot on the new commit. Omit when the flag is absent.
|
|
230
|
+
Teammates or Task workers for a PR operate inside that PR's worktree. Step 4
|
|
231
|
+
teardown runs `git worktree remove "<team_temp_dir>/pr-<N>/worktree"` for each
|
|
232
|
+
PR, then path-specific harness teardown per
|
|
233
|
+
[`reference/workflow-path-a-orchestrated-teams.md`][path-a] or
|
|
234
|
+
[`reference/workflow-path-b-task-harness.md`][path-b] § Step 4.
|
|
235
|
+
|
|
236
|
+
### Step 2: Path harness + loop state
|
|
237
|
+
|
|
238
|
+
Apply the path you chose in [Path
|
|
239
|
+
routing](#path-routing-mandatory-first-branch): **Path A** —
|
|
240
|
+
[`reference/workflow-path-a-orchestrated-teams.md`][path-a] § Step 2
|
|
241
|
+
(`TeamCreate`, team name, `team_temp_dir`, roles, optional Groq FIX,
|
|
242
|
+
`--bugbot-retrigger`). **Path B** —
|
|
243
|
+
[`reference/workflow-path-b-task-harness.md`][path-b] § Step 2 (no `TeamCreate`
|
|
244
|
+
/ `TeamDelete`; same worktrees and variables).
|
|
245
|
+
|
|
246
|
+
Path A also resolves the team lifecycle here per [Team
|
|
247
|
+
lifecycle](#team-lifecycle-path-a-only): pick the mode (`owned` / `attach` /
|
|
248
|
+
`auto`) from `BUGTEAM_TEAM_LIFECYCLE`, set `team_name` (computed for
|
|
249
|
+
`owned`/`auto` create paths; required `BUGTEAM_TEAM_NAME` for `attach` and
|
|
250
|
+
`auto`'s attach branch), and set `team_owned` (`true` when `TeamCreate`
|
|
251
|
+
succeeded in this invocation; `false` when attaching to an existing team). Step
|
|
252
|
+
4 reads `team_owned` to decide whether to call `TeamDelete`.
|
|
138
253
|
|
|
139
254
|
**Loop state (lead; not a single script):**
|
|
140
255
|
|
|
@@ -146,46 +261,63 @@ audit_log=""
|
|
|
146
261
|
starting_sha="$(git rev-parse HEAD)"
|
|
147
262
|
team_name="bugteam-pr-<number>-<YYYYMMDDHHMMSS>"
|
|
148
263
|
team_temp_dir="<absolute-path>/<team_name>"
|
|
264
|
+
team_owned="true" # set by Step 2 lifecycle resolution; see Team lifecycle table
|
|
149
265
|
loop_comment_index=""
|
|
150
266
|
```
|
|
151
267
|
|
|
152
|
-
**`loop_comment_index`:** reset each AUDIT start; filled during AUDIT; FIX
|
|
268
|
+
**`loop_comment_index`:** reset each AUDIT start; filled during AUDIT; FIX
|
|
269
|
+
consumes for replies; cleared after FIX. Entries: `{loop, finding_id,
|
|
270
|
+
finding_comment_id, finding_comment_url, used_fallback, fix_status}`.
|
|
153
271
|
|
|
154
272
|
### Step 2.5: PR comments (one review per loop)
|
|
155
273
|
|
|
156
|
-
|
|
274
|
+
**Who posts:** Path A vs Path B —
|
|
275
|
+
[`reference/workflow-path-a-orchestrated-teams.md`][path-a] § Step 2.5 and
|
|
276
|
+
[`reference/workflow-path-b-task-harness.md`][path-b] § Step 2.5. Payloads and
|
|
277
|
+
endpoints below are identical for both paths.
|
|
157
278
|
|
|
158
|
-
Order: audit → buffer → validate anchors vs diff → single review POST.
|
|
279
|
+
Order: audit → buffer → validate anchors vs diff → single review POST.
|
|
280
|
+
Review body states counts; zero findings → still one review, `comments: []`,
|
|
281
|
+
body `## /bugteam loop <N> audit: 0P0 / 0P1 / 0P2 → clean`.
|
|
159
282
|
|
|
160
|
-
**Payloads:** build JSON with `jq --rawfile` / `-Rs`, pipe to `gh api ...
|
|
283
|
+
**Payloads:** build JSON with `jq --rawfile` / `-Rs`, pipe to `gh api ...
|
|
284
|
+
--input -` (avoids shell-quoting; satisfies `gh-body-backtick-guard`). Write
|
|
285
|
+
each markdown body to a temp file first.
|
|
161
286
|
|
|
162
|
-
**Review POST** (one `comments[]` object per anchored finding; single-line
|
|
287
|
+
**Review POST** (one `comments[]` object per anchored finding; single-line
|
|
288
|
+
`{path, line, side: "RIGHT", body}`; multi-line add `start_line`, `start_side:
|
|
289
|
+
"RIGHT"`):
|
|
163
290
|
|
|
164
291
|
```
|
|
165
292
|
jq -n \
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
293
|
+
--rawfile review_body <tmp_review_body.md> \
|
|
294
|
+
--arg commit_id "$(git rev-parse HEAD)" \
|
|
295
|
+
--rawfile finding_body_1 <tmp_finding_1.md> \
|
|
296
|
+
--arg path_1 "<file_1>" \
|
|
297
|
+
--argjson line_1 <line_1> \
|
|
298
|
+
[... one finding_body_K / path_K / line_K triple per finding ...] \
|
|
299
|
+
'{
|
|
300
|
+
commit_id: $commit_id,
|
|
301
|
+
event: "COMMENT",
|
|
302
|
+
body: $review_body,
|
|
303
|
+
comments: [
|
|
304
|
+
{path: $path_1, line: $line_1, side: "RIGHT", body: $finding_body_1}
|
|
305
|
+
[, ... ]
|
|
306
|
+
]
|
|
307
|
+
}' \
|
|
181
308
|
| gh api repos/<owner>/<repo>/pulls/<number>/reviews -X POST --input -
|
|
182
309
|
```
|
|
183
310
|
|
|
184
|
-
**Fix reply:** `jq -Rs '{body: .}' <tmp_reply.md | gh api
|
|
311
|
+
**Fix reply:** `jq -Rs '{body: .}' <tmp_reply.md | gh api
|
|
312
|
+
repos/<owner>/<repo>/pulls/<number>/comments/<finding_comment_id>/replies -X
|
|
313
|
+
POST --input -`
|
|
185
314
|
|
|
186
|
-
**Review POST fails:** issue comment fallback: `jq -Rs '{body: .}'
|
|
315
|
+
**Review POST fails:** issue comment fallback: `jq -Rs '{body: .}'
|
|
316
|
+
<tmp_fallback.md | gh api repos/<owner>/<repo>/issues/<number>/comments -X POST
|
|
317
|
+
--input -`
|
|
187
318
|
|
|
188
|
-
`<head_sha_at_post_time>`: `git rev-parse HEAD` in teammate cwd immediately
|
|
319
|
+
`<head_sha_at_post_time>`: `git rev-parse HEAD` in teammate cwd immediately
|
|
320
|
+
before POST.
|
|
189
321
|
|
|
190
322
|
**Review body template (`<tmp_review_body.md>`):**
|
|
191
323
|
|
|
@@ -197,55 +329,105 @@ jq -n \
|
|
|
197
329
|
- **[severity] title** — <file>:<line> — <one-line description>
|
|
198
330
|
```
|
|
199
331
|
|
|
200
|
-
**Anchor fallback:** lines not in diff → omit from `comments[]`, list under
|
|
332
|
+
**Anchor fallback:** lines not in diff → omit from `comments[]`, list under
|
|
333
|
+
`### Findings without a diff anchor`; outcome `used_fallback="true"`, empty
|
|
334
|
+
`finding_comment_id`, `finding_comment_url` = parent review URL.
|
|
201
335
|
|
|
202
|
-
**POST failure fallback:** one issue comment with full text; all findings
|
|
336
|
+
**POST failure fallback:** one issue comment with full text; all findings
|
|
337
|
+
`used_fallback="true"`, URLs = issue comment.
|
|
203
338
|
|
|
204
|
-
**Endpoints:** `POST .../pulls/{pull}/reviews`; `POST
|
|
339
|
+
**Endpoints:** `POST .../pulls/{pull}/reviews`; `POST
|
|
340
|
+
.../pulls/{pull}/comments/{id}/replies`; fallback `POST
|
|
341
|
+
.../issues/{issue}/comments` (`issue` = PR number).
|
|
205
342
|
|
|
206
343
|
### Step 3: The cycle
|
|
207
344
|
|
|
208
|
-
Run the AUDIT-FIX cycle for each PR in all_prs, reusing the same team across
|
|
345
|
+
Run the AUDIT-FIX cycle for each PR in all_prs, reusing the same team across
|
|
346
|
+
PRs. The 10-loop cap applies per PR. Exit reasons (converged, cap reached,
|
|
347
|
+
stuck, error) are tracked per PR; the final report lists one outcome line per
|
|
348
|
+
PR.
|
|
209
349
|
|
|
210
|
-
**Gate:** `validate_content` / `hooks/blocking/code_rules_enforcer.py` on
|
|
350
|
+
**Gate:** `validate_content` / `hooks/blocking/code_rules_enforcer.py` on
|
|
351
|
+
PR-scoped files before every AUDIT
|
|
352
|
+
(`_shared/pr-loop/scripts/code_rules_gate.py`). Lead runs gate; clean-coder
|
|
353
|
+
clears failures; then bugfind audits.
|
|
211
354
|
|
|
212
|
-
**Pre-cycle: walk prior bugteam reviews end-first** (once per PR, after Step 2
|
|
355
|
+
**Pre-cycle: walk prior bugteam reviews end-first** (once per PR, after Step 2
|
|
356
|
+
and before iteration begins, when `last_action == "fresh"`). A re-invocation of
|
|
357
|
+
`/bugteam` on a PR with prior loops detects whether the most recent loop already
|
|
358
|
+
cleaned this HEAD (short-circuit) and otherwise records that prior loops were
|
|
359
|
+
dirty so the AUDIT runs against the latest diff with that signal in mind:
|
|
213
360
|
|
|
214
361
|
```bash
|
|
215
362
|
dirty_review_count=0
|
|
216
363
|
gh api "repos/<owner>/<repo>/pulls/<number>/reviews" \
|
|
217
|
-
|
|
364
|
+
--jq '[.[] | select(.body | startswith("## /bugteam loop "))] |
|
|
365
|
+
sort_by(.submitted_at) | reverse'
|
|
218
366
|
```
|
|
219
367
|
|
|
220
368
|
Iterate from index 0 (most recent) toward older entries:
|
|
221
369
|
|
|
222
|
-
- A bugteam review body that ends with `→ clean` is **clean**; any other `##
|
|
223
|
-
|
|
224
|
-
-
|
|
225
|
-
|
|
226
|
-
|
|
370
|
+
- A bugteam review body that ends with `→ clean` is **clean**; any other `##
|
|
371
|
+
/bugteam loop ...` body is **dirty**.
|
|
372
|
+
- For a dirty review, increment `dirty_review_count` by one. The review's
|
|
373
|
+
specific finding bodies are not carried forward —
|
|
374
|
+
bugteam's AUDIT regenerates
|
|
375
|
+
findings against the current HEAD's diff each loop, so prior bodies are stale
|
|
376
|
+
by definition. The count alone is the carried signal.
|
|
377
|
+
- Stop at the first clean review. Older reviews are presumed addressed at that
|
|
378
|
+
clean checkpoint and are not re-read.
|
|
379
|
+
- When index 0 is itself clean AND its `commit_id` matches `git rev-parse HEAD`,
|
|
380
|
+
the PR is already converged on this HEAD — set `last_action="audited"`,
|
|
381
|
+
`last_findings='{"total": 0}'`, fall through to step 1's `converged` exit,
|
|
382
|
+
skip Step 3 iteration entirely.
|
|
383
|
+
- When `dirty_review_count > 0`, log the count and proceed into the normal
|
|
384
|
+
iteration; the next AUDIT regenerates anchored findings against the current
|
|
385
|
+
HEAD so `loop_comment_index` stays correct. Unlike `pr-converge` — where
|
|
386
|
+
Cursor Bugbot's prior dirty-review *bodies* are read back by the Fix protocol
|
|
387
|
+
because each dirty body lists specific findings the loop must still address
|
|
388
|
+
—
|
|
389
|
+
bugteam's per-loop bodies are anchored to the diff at *that loop's* HEAD, so
|
|
390
|
+
re-applying them against a newer diff would be incorrect. The count is
|
|
391
|
+
sufficient signal that "prior loops did not converge here."
|
|
227
392
|
|
|
228
393
|
1. From `last_action` / `last_findings`:
|
|
229
|
-
- `last_action == "audited"` and `last_findings.total == 0` → exit
|
|
230
|
-
|
|
394
|
+
- `last_action == "audited"` and `last_findings.total == 0` → exit
|
|
395
|
+
`converged`
|
|
396
|
+
- `last_action == "fixed"` and `git rev-parse HEAD` unchanged since
|
|
397
|
+
pre-FIX → exit `stuck`
|
|
231
398
|
- `last_action in {"fresh", "fixed"}` → **pre-audit** then **AUDIT**
|
|
232
399
|
- `last_action == "audited"` and `last_findings.total > 0` → **FIX**
|
|
233
400
|
|
|
234
401
|
2. **Pre-audit** (only when the next step is AUDIT):
|
|
235
402
|
|
|
236
403
|
```bash
|
|
237
|
-
python
|
|
404
|
+
python \
|
|
405
|
+
"${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/code_rules_gate.py" \
|
|
406
|
+
--base origin/<baseRefName>
|
|
238
407
|
```
|
|
239
408
|
|
|
240
|
-
|
|
409
|
+
Lead only; merge-base / diff semantics:
|
|
410
|
+
[`../../_shared/pr-loop/code-rules-gate.md`][path-code-rules]; shared script
|
|
411
|
+
inventory: [`../../_shared/pr-loop/scripts/README.md`][path-scripts-readme].
|
|
412
|
+
Non-zero → spawn **clean-coder** standards-fix (read stderr, edit, re-run
|
|
413
|
+
**this same** command, one commit, `git push`, shutdown) until exit **0** or
|
|
414
|
+
**5**
|
|
415
|
+
failed gate rounds → `error: code rules gate failed pre-audit`. After **0**:
|
|
416
|
+
`loop_count += 1`; if `loop_count > 10` → `cap reached`. Then **AUDIT**
|
|
417
|
+
(bugfind); print `Loop <N> audit: ...`.
|
|
241
418
|
|
|
242
|
-
3. **FIX** (`last_action == "audited"` and `last_findings.total > 0`):
|
|
419
|
+
3. **FIX** (`last_action == "audited"` and `last_findings.total > 0`):
|
|
420
|
+
`loop_count += 1`; if `loop_count > 10` → `cap reached`; **FIX** (bugfix);
|
|
421
|
+
print `Loop <N> fix: ...`; `last_action = "fixed"`, update `audit_log`; loop
|
|
422
|
+
to step 1.
|
|
243
423
|
|
|
244
|
-
4. After **AUDIT**: update `last_action`, `last_findings`, `audit_log`; print
|
|
424
|
+
4. After **AUDIT**: update `last_action`, `last_findings`, `audit_log`; print
|
|
425
|
+
audit line if not already printed.
|
|
245
426
|
|
|
246
427
|
5. Loop.
|
|
247
428
|
|
|
248
|
-
First pass: pre-audit → AUDIT. After a FIX, the next pass runs pre-audit again
|
|
429
|
+
First pass: pre-audit → AUDIT. After a FIX, the next pass runs pre-audit again
|
|
430
|
+
before the next AUDIT.
|
|
249
431
|
|
|
250
432
|
### AUDIT action
|
|
251
433
|
|
|
@@ -254,75 +436,95 @@ mkdir -p "<team_temp_dir>/pr-<N>"
|
|
|
254
436
|
gh pr diff <N> -R <owner>/<repo> > "<team_temp_dir>/pr-<N>/loop-<L>.patch"
|
|
255
437
|
```
|
|
256
438
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
team_name="<team_name>",
|
|
262
|
-
model="opus",
|
|
263
|
-
description="Bugfind audit PR <N> loop <L>",
|
|
264
|
-
prompt="<audit XML; see PROMPTS.md>"
|
|
265
|
-
)
|
|
266
|
-
```
|
|
439
|
+
**Spawn and shutdown:** Path A —
|
|
440
|
+
[`reference/workflow-path-a-orchestrated-teams.md`][path-a] § AUDIT. Path B —
|
|
441
|
+
[`reference/workflow-path-b-task-harness.md`][path-b] § AUDIT. Same
|
|
442
|
+
`prompt="<audit XML; see PROMPTS.md>"` and outcome files.
|
|
267
443
|
|
|
268
|
-
Fresh
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
SendMessage(
|
|
274
|
-
to="bugfind-pr<N>-loop<L>",
|
|
275
|
-
message={"type": "shutdown_request", "reason": "audit PR <N> loop <L> complete; outcome XML captured"}
|
|
276
|
-
)
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
`approve: false` → `error: bugfind teammate refused shutdown` → Step 4 then 5.
|
|
444
|
+
Fresh spawn each loop; Path A teammate context excludes lead history
|
|
445
|
+
([`sources.md`](sources.md) § Teammate context isolation). Path B: fresh Task
|
|
446
|
+
per loop for the same clean-room intent. [`PROMPTS.md`](PROMPTS.md): XML +
|
|
447
|
+
outcome schema. Lead reads `.bugteam-pr<N>-loop<L>.outcomes.xml`, fills
|
|
448
|
+
`loop_comment_index`.
|
|
280
449
|
|
|
281
450
|
`last_action = "audited"`; append audit line to `audit_log`.
|
|
282
451
|
|
|
283
|
-
**Parallel auditors (`loop_count >= 4`):** gate passes immediately before;
|
|
452
|
+
**Parallel auditors (`loop_count >= 4`):** gate passes immediately before;
|
|
453
|
+
after three full audit/fix rounds without convergence, issue three spawns in
|
|
454
|
+
one assistant message (parallel): Path A — three `Agent` calls; Path B —
|
|
455
|
+
three `Task` calls — full rules in the workflow files § parallel auditors.
|
|
456
|
+
`-a` posts
|
|
457
|
+
the review and merges outcomes from `-b`/`-c` (read
|
|
458
|
+
`.bugteam-pr<N>-loop<L>.outcomes.xml` plus
|
|
459
|
+
`<team_temp_dir>/pr-<N>/loop-<L>-b.outcomes.xml` and `...-c...`); merge key
|
|
460
|
+
`(file, line, category_letter)`; re-id `loopN-K`. `-b`/`-c` write sibling XML
|
|
461
|
+
only; prompts must pass literal absolute sibling paths. Shutdown order: Path A
|
|
462
|
+
workflow § parallel auditors; Path B: await all three Tasks.
|
|
284
463
|
|
|
285
464
|
### FIX action
|
|
286
465
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
name="bugfix-pr<N>-loop<L>",
|
|
291
|
-
team_name="<team_name>",
|
|
292
|
-
model="opus",
|
|
293
|
-
description="Bugfix PR <N> loop <L>",
|
|
294
|
-
prompt="<fix XML; see PROMPTS.md>"
|
|
295
|
-
)
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
Pass finding comment URLs/ids from `loop_comment_index` in XML. Replies: `Fixed in <sha>` or `Could not address this loop: <reason>`.
|
|
466
|
+
**Spawn and shutdown:** Path A —
|
|
467
|
+
[`reference/workflow-path-a-orchestrated-teams.md`][path-a] § FIX. Path B —
|
|
468
|
+
[`reference/workflow-path-b-task-harness.md`][path-b] § FIX.
|
|
299
469
|
|
|
300
|
-
|
|
470
|
+
Pass finding comment URLs/ids from `loop_comment_index` in XML. Replies: `Fixed
|
|
471
|
+
in <sha>` or `Could not address this loop: <reason>`.
|
|
301
472
|
|
|
302
|
-
[`PROMPTS.md`](PROMPTS.md): fix XML + schema. Verify: `git rev-parse HEAD`
|
|
473
|
+
[`PROMPTS.md`](PROMPTS.md): fix XML + schema. Verify: `git rev-parse HEAD`
|
|
474
|
+
advanced; `git fetch origin <branch> && git rev-parse origin/<branch>` matches
|
|
475
|
+
`HEAD`. Unchanged HEAD →
|
|
476
|
+
`stuck — bugfix teammate could not address findings`.
|
|
303
477
|
|
|
304
478
|
### Step 4: Teardown
|
|
305
479
|
|
|
306
|
-
1. For each
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
480
|
+
1. For each PR in `all_prs`: `git worktree remove
|
|
481
|
+
"<team_temp_dir>/pr-<N>/worktree"` (from Step 1) before tearing down the team
|
|
482
|
+
harness — tolerate already-removed worktrees.
|
|
483
|
+
|
|
484
|
+
2. Path-specific harness —
|
|
485
|
+
[`reference/workflow-path-a-orchestrated-teams.md`][path-a] § Step 4
|
|
486
|
+
(teammate `SendMessage`, `TeamDelete` **only when `team_owned=true`**) or
|
|
487
|
+
[`reference/workflow-path-b-task-harness.md`][path-b] § Step 4 (omit those).
|
|
488
|
+
|
|
489
|
+
3. **Windows-safe `rmtree` — gated by `team_owned` from [Team
|
|
490
|
+
lifecycle](#team-lifecycle-path-a-only).** The Windows-safe handler strips
|
|
491
|
+
the Windows ReadOnly attribute and retries the failing syscall (see
|
|
492
|
+
`~/.claude/rules/windows-filesystem-safe.md`).
|
|
493
|
+
|
|
494
|
+
- `team_owned=true` → remove the full `<team_temp_dir>`:
|
|
495
|
+
|
|
496
|
+
```bash
|
|
497
|
+
python -c "import os, shutil, stat, sys; \
|
|
498
|
+
h = lambda f, p, *_: (os.chmod(p, stat.S_IWRITE), f(p)); \
|
|
499
|
+
shutil.rmtree(r'<team_temp_dir>', **({'onexc': h} if sys.version_info >= (3, 12)
|
|
500
|
+
else {'onerror': h}))"
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
- `team_owned=false` (attach mode) → for each PR in `all_prs`, remove only
|
|
504
|
+
that PR's `<team_temp_dir>/pr-<N>/` subfolder. The orchestrator-owned
|
|
505
|
+
parent `<team_temp_dir>` survives so the next attached invocation can write
|
|
506
|
+
its own per-PR subfolders without colliding.
|
|
507
|
+
|
|
508
|
+
```bash
|
|
509
|
+
python -c "import os, shutil, stat, sys; \
|
|
510
|
+
h = lambda f, p, *_: (os.chmod(p, stat.S_IWRITE), f(p)); \
|
|
511
|
+
shutil.rmtree(r'<team_temp_dir>/pr-<N>', **({'onexc': h} if sys.version_info >=
|
|
512
|
+
(3, 12) else {'onerror': h}))"
|
|
513
|
+
```
|
|
317
514
|
|
|
318
515
|
### Step 4.5: PR description
|
|
319
516
|
|
|
320
|
-
Lead only; cumulative product narrative (not process). Delegate body to
|
|
517
|
+
Lead only; cumulative product narrative (not process). Delegate body to
|
|
518
|
+
`pr-description-writer` via `Agent` (else `general-purpose`) so the
|
|
519
|
+
mandatory-pr-description hook accepts `gh pr edit`.
|
|
321
520
|
|
|
322
521
|
1. `gh pr diff <number> -R <owner>/<repo> > .bugteam-final.diff`
|
|
323
|
-
2. `gh pr view <number> -R <owner>/<repo> --json body --jq .body >
|
|
324
|
-
|
|
325
|
-
|
|
522
|
+
2. `gh pr view <number> -R <owner>/<repo> --json body --jq .body >
|
|
523
|
+
.bugteam-original-body.md`
|
|
524
|
+
3. Agent brief: paths + branch names; describe merge-ready change from diff;
|
|
525
|
+
keep curated original sections intact; return markdown body.
|
|
526
|
+
4. Write `.bugteam-final-body.md`; `gh pr edit <number> -R <owner>/<repo>
|
|
527
|
+
--body-file .bugteam-final-body.md`
|
|
326
528
|
5. Delete the three temp files.
|
|
327
529
|
|
|
328
530
|
On failure: log in final report; continue to Step 5.
|
|
@@ -330,7 +532,9 @@ On failure: log in final report; continue to Step 5.
|
|
|
330
532
|
### Step 5: Revoke permissions (always)
|
|
331
533
|
|
|
332
534
|
```bash
|
|
333
|
-
python
|
|
535
|
+
python
|
|
536
|
+
"${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/revoke_project_claude_permi \
|
|
537
|
+
ssions.py"
|
|
334
538
|
```
|
|
335
539
|
|
|
336
540
|
Removes Step 0 grant — run even if Step 4 partially failed (log separately).
|
|
@@ -345,11 +549,12 @@ Final commit: <current_HEAD_sha7>
|
|
|
345
549
|
Net change: <total_files> files, +<total_add>/-<total_del>
|
|
346
550
|
|
|
347
551
|
Loop log:
|
|
348
|
-
|
|
349
|
-
|
|
552
|
+
1 audit: 3P0 2P1 0P2
|
|
553
|
+
...
|
|
350
554
|
```
|
|
351
555
|
|
|
352
|
-
`cap reached` → suggest `/findbugs`. `stuck` → which findings. `error` →
|
|
556
|
+
`cap reached` → suggest `/findbugs`. `stuck` → which findings. `error` →
|
|
557
|
+
detail + loop.
|
|
353
558
|
|
|
354
559
|
## Constraints
|
|
355
560
|
|
|
@@ -366,3 +571,8 @@ See [`reference/README.md`](reference/README.md).
|
|
|
366
571
|
## Sources
|
|
367
572
|
|
|
368
573
|
See [`sources.md`](sources.md).
|
|
574
|
+
|
|
575
|
+
[path-a]: reference/workflow-path-a-orchestrated-teams.md
|
|
576
|
+
[path-b]: reference/workflow-path-b-task-harness.md
|
|
577
|
+
[path-code-rules]: ../../_shared/pr-loop/code-rules-gate.md
|
|
578
|
+
[path-scripts-readme]: ../../_shared/pr-loop/scripts/README.md
|