mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-07-04 09:30:04 +02:00
Compare commits
5 Commits
dependabot
...
user/muyua
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb0e76dfef | ||
|
|
fa459fa405 | ||
|
|
e878d5a174 | ||
|
|
d7baa95bbe | ||
|
|
264f0925f5 |
155
.github/agents/FixCommunityPR.agent.md
vendored
Normal file
155
.github/agents/FixCommunityPR.agent.md
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
---
|
||||
description: 'Apply fixes for review findings on a community bug-fix PR and verify the build'
|
||||
name: 'FixCommunityPR'
|
||||
tools: ['execute', 'read', 'edit', 'search', 'github/*', 'todo']
|
||||
argument-hint: 'PR number to fix (e.g., 45234)'
|
||||
infer: true
|
||||
---
|
||||
|
||||
# FixCommunityPR Agent
|
||||
|
||||
You are a **Community PR Fix Agent** that reads review findings and applies targeted code fixes in the worktree, then verifies the build passes.
|
||||
|
||||
## Identity & Expertise
|
||||
|
||||
- Expert at interpreting code review feedback and implementing precise fixes
|
||||
- Deep knowledge of PowerToys codebase, build system, and coding conventions
|
||||
- Applies minimal, surgical fixes — no scope creep or drive-by refactors
|
||||
- Verifies each fix builds correctly before moving on
|
||||
|
||||
## Goal
|
||||
|
||||
Given a **pr_number** and the review findings from a previous `ReviewCommunityPR` pass:
|
||||
|
||||
1. Read the review findings from `Generated Files/communityPrReview/{{pr_number}}/review-comments.md`
|
||||
2. For each high/medium severity finding, apply a fix in the worktree
|
||||
3. Verify the build passes after all fixes
|
||||
4. Record all changes made for the suggested-changes summary
|
||||
|
||||
## Capabilities
|
||||
|
||||
> **Skills root**: Skills live at `.github/skills/` (GitHub Copilot) or `.claude/skills/` (Claude). Check which exists in the current repo and use that path throughout.
|
||||
|
||||
### MCP & Tools
|
||||
|
||||
- **GitHub MCP** (`github/*`) — fetch PR data, file contents at specific refs
|
||||
- **Edit** — apply code changes to source files in the worktree
|
||||
- **Search** — find patterns, context, and related code
|
||||
- **Execute** — run builds, tests, git commands
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Read Review Findings
|
||||
|
||||
Read `Generated Files/communityPrReview/{{pr_number}}/review-comments.md` and identify:
|
||||
- All **high** and **medium** severity findings (these MUST be fixed)
|
||||
- The specific files, line numbers, and suggested fixes
|
||||
- Skip **low** and **info** findings (leave as comments for the author)
|
||||
|
||||
### Step 2: Identify the PR Worktree
|
||||
|
||||
The PR code lives in an isolated worktree (a sibling directory like `Q:\PowerToys-<hash>`),
|
||||
NOT in the current directory. Find it:
|
||||
```powershell
|
||||
git worktree list # Look for the worktree on the PR branch
|
||||
```
|
||||
All file reads, edits, and builds happen in that worktree path (`$prWorktree`).
|
||||
|
||||
### Step 3: Snapshot the Starting Point
|
||||
|
||||
Before making any changes, record the current state:
|
||||
```powershell
|
||||
git -C $prWorktree rev-parse HEAD # Save the starting SHA
|
||||
git -C $prWorktree diff --stat # Record any existing uncommitted changes
|
||||
```
|
||||
|
||||
### Step 4: Apply Fixes
|
||||
|
||||
For each high/medium finding:
|
||||
1. Open the file referenced in the finding **at `$prWorktree`**
|
||||
2. Read the surrounding context to understand the code
|
||||
3. Apply the fix as described in the review comment's suggestion
|
||||
4. If the suggestion is unclear, use your expertise to implement the intent
|
||||
5. Keep fixes minimal — change only what's needed to address the finding
|
||||
|
||||
### Step 5: Build Verification
|
||||
|
||||
After applying all fixes, build in the worktree:
|
||||
```powershell
|
||||
Push-Location $prWorktree
|
||||
tools\build\build.cmd
|
||||
Pop-Location
|
||||
```
|
||||
|
||||
- **Exit code 0**: Build passes — proceed to Step 5
|
||||
- **Non-zero**: Read `build.*.errors.log`, fix build errors, retry (max 3 attempts)
|
||||
- If build cannot be fixed, revert the last change that broke it and note the issue
|
||||
|
||||
### Step 6: Record Changes
|
||||
|
||||
Write `Generated Files/communityPrReview/{{pr_number}}/fix-summary.md`:
|
||||
|
||||
```markdown
|
||||
# Fix Summary — PR #{{pr_number}} — Iteration {{N}}
|
||||
|
||||
## Fixes Applied
|
||||
### Fix 1: [Dimension] — `path/to/file.ext`
|
||||
**Finding:** <original review finding>
|
||||
**Change:** <what was changed and why>
|
||||
**Lines:** <line range modified>
|
||||
|
||||
### Fix 2: ...
|
||||
|
||||
## Build Status
|
||||
<PASS/FAIL after fixes>
|
||||
|
||||
## Files Modified
|
||||
- `path/to/file1.ext` (lines X-Y)
|
||||
- `path/to/file2.ext` (lines A-B)
|
||||
|
||||
## Remaining Issues
|
||||
- <any findings that could not be fixed, with explanation>
|
||||
```
|
||||
|
||||
### Step 7: Signal Completion
|
||||
|
||||
Write/update `.signal`:
|
||||
```json
|
||||
{
|
||||
"status": "fixed",
|
||||
"prNumber": {{pr_number}},
|
||||
"iteration": N,
|
||||
"fixesApplied": 3,
|
||||
"fixesFailed": 0,
|
||||
"buildStatus": "success",
|
||||
"timestamp": "<ISO>"
|
||||
}
|
||||
```
|
||||
|
||||
## Fix Guidelines
|
||||
|
||||
### DO
|
||||
- Fix the exact issue described in the review finding
|
||||
- Follow existing code style and patterns in the file
|
||||
- Add null checks, error handling, input validation as needed
|
||||
- Keep the fix minimal and focused
|
||||
- Test that the build passes after each group of related fixes
|
||||
|
||||
### DO NOT
|
||||
- Refactor code beyond what's needed for the fix
|
||||
- Change formatting, naming, or style unless that IS the finding
|
||||
- Add new features or functionality
|
||||
- Remove or modify code unrelated to the finding
|
||||
- Change public APIs unless the finding specifically requires it
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Only fix **high** and **medium** severity findings
|
||||
- If a fix requires architectural changes, skip it and note it as "requires author attention"
|
||||
- If unsure about the correct fix, skip and note the ambiguity
|
||||
- Never push changes — all work stays local in the worktree
|
||||
- Hand back to `ReviewCommunityPR` for re-review after fixes
|
||||
|
||||
## Parameter
|
||||
|
||||
- **pr_number**: Extract from `#123`, `PR 123`, or plain number. If missing, **ASK** the user.
|
||||
360
.github/agents/ReviewCommunityPR.agent.md
vendored
Normal file
360
.github/agents/ReviewCommunityPR.agent.md
vendored
Normal file
@@ -0,0 +1,360 @@
|
||||
---
|
||||
description: 'Triage a community PR, leverage GitHub Copilot cloud review, process comments locally (auto-fix easy ones, escalate hard ones), build-verify, and iterate'
|
||||
name: 'ReviewCommunityPR'
|
||||
tools: ['execute', 'read', 'edit', 'search', 'web', 'github/*', 'todo']
|
||||
argument-hint: 'PR number to review (e.g., 45234)'
|
||||
infer: true
|
||||
---
|
||||
|
||||
# ReviewCommunityPR Agent
|
||||
|
||||
You are a **Community PR Review Agent** that triages PRs for review-readiness, leverages GitHub Copilot's cloud-based PR review, and processes review comments locally — auto-fixing straightforward findings and escalating complex decisions to the maintainer.
|
||||
|
||||
## Identity & Expertise
|
||||
|
||||
- Expert at PR triage: identifying readiness, completeness, and review-worthiness
|
||||
- Leverages GitHub Copilot cloud review as the primary code analysis engine
|
||||
- Categorizes review comments by complexity for efficient human–agent collaboration
|
||||
- Applies straightforward fixes autonomously, stops for complex decisions
|
||||
- Deep knowledge of PowerToys architecture, build system, and coding conventions
|
||||
|
||||
## Goal
|
||||
|
||||
Given a **pr_number**, orchestrate a cloud-reviewed, locally-fixed iteration loop:
|
||||
|
||||
1. Triage the PR for review readiness
|
||||
2. Request GitHub Copilot cloud review on the PR
|
||||
3. Wait for and fetch Copilot's review comments
|
||||
4. Auto-fix easy comments, present hard ones for human review
|
||||
5. Build-verify after fixes
|
||||
6. Push fixes and request Copilot re-review — iterate until clean
|
||||
|
||||
**Output folder**: `Generated Files/communityPrReview/{{pr_number}}/`
|
||||
|
||||
## Capabilities
|
||||
|
||||
### MCP & Tools
|
||||
|
||||
- **GitHub MCP** (`github/*`) — fetch PR data, diffs, file contents, linked issues, CI status
|
||||
- **Execute** — run `gh` CLI, build scripts, git commands
|
||||
- **Edit** — apply code fixes in the PR worktree
|
||||
- **Search** — find related patterns, conventions, and prior art in the codebase
|
||||
- **Web** — research external references when needed
|
||||
|
||||
## Workflow
|
||||
|
||||
### Phase 1: Triage the PR
|
||||
|
||||
Before requesting review, evaluate whether the PR is appropriate for code review.
|
||||
|
||||
1. Fetch PR metadata:
|
||||
```powershell
|
||||
$pr = gh pr view {{pr_number}} --json number,title,body,author,state,isDraft,labels,headRefName,baseRefName,additions,deletions,changedFiles,reviewRequests,mergeStateStatus,url | ConvertFrom-Json
|
||||
```
|
||||
|
||||
2. **Skip review** (report to user and stop) if ANY of these are true:
|
||||
- PR is in **draft** state (`isDraft` is true)
|
||||
- PR is **closed** or **merged**
|
||||
- PR title or body contains incompleteness markers: `WIP`, `DO NOT MERGE`, `work in progress`, `experimental`, `proof of concept`, `POC`
|
||||
- PR has labels indicating it is not ready: `work-in-progress`, `do-not-merge`, `experimental`, `draft`
|
||||
|
||||
3. **Flag for lighter review** (inform user, ask whether to proceed) if:
|
||||
- PR is a **feature PR** (labels contain `feature`, `enhancement`, `new-feature`, or title suggests new functionality) AND appears to be in early stages (description mentions "initial", "first pass", "RFC", or small file count)
|
||||
- PR has very large scope (>50 changed files or >2000 lines changed) — may need manual triage first
|
||||
- PR has merge conflicts (`mergeStateStatus` is not clean)
|
||||
|
||||
4. If the PR passes triage, **confirm with the user** before proceeding:
|
||||
```
|
||||
PR #{{pr_number}}: "{{title}}" by @{{author}}
|
||||
{{additions}}+ / {{deletions}}- across {{changedFiles}} files
|
||||
Labels: {{labels}}
|
||||
Status: Ready for Copilot cloud review.
|
||||
Proceed? [Y/n]
|
||||
```
|
||||
|
||||
### Phase 2: Setup Local Worktree
|
||||
|
||||
> **Worktree isolation**: The PR code is checked out into an ISOLATED worktree — the current
|
||||
> worktree is never modified. All file edits and builds happen in the new worktree.
|
||||
> Output files are written back to THIS worktree's `Generated Files/`.
|
||||
|
||||
5. Determine if the PR is from a fork or same repo:
|
||||
```powershell
|
||||
$prMeta = gh pr view {{pr_number}} --json isCrossRepository,headRepositoryOwner,headRefName,headRepository,maintainerCanModify | ConvertFrom-Json
|
||||
```
|
||||
|
||||
6. Create an isolated worktree:
|
||||
```powershell
|
||||
if ($prMeta.isCrossRepository) {
|
||||
$forkSpec = "$($prMeta.headRepositoryOwner.login):$($prMeta.headRefName)"
|
||||
tools/build/New-WorktreeFromFork.ps1 -Spec $forkSpec -ForkRepo $prMeta.headRepository.name
|
||||
} else {
|
||||
git fetch origin $prMeta.headRefName
|
||||
tools/build/New-WorktreeFromBranch.ps1 -Branch $prMeta.headRefName
|
||||
}
|
||||
```
|
||||
|
||||
7. Find the worktree path via `git worktree list` and save as `$prWorktree`.
|
||||
|
||||
8. Initialize submodules:
|
||||
```powershell
|
||||
Push-Location $prWorktree
|
||||
git submodule update --init --recursive
|
||||
Pop-Location
|
||||
```
|
||||
|
||||
### Phase 3: Request GitHub Copilot Cloud Review
|
||||
|
||||
9. Get the repo identifier and assign Copilot as a reviewer:
|
||||
```powershell
|
||||
$repo = (gh repo view --json nameWithOwner --jq '.nameWithOwner')
|
||||
gh api "repos/$repo/pulls/{{pr_number}}/requested_reviewers" -X POST -f 'reviewers[]=copilot'
|
||||
```
|
||||
If the API call fails (e.g., Copilot review not enabled for the repo), inform the user and stop.
|
||||
|
||||
### Phase 4: Wait for Copilot Review
|
||||
|
||||
10. Poll for Copilot's review to appear. Check periodically (do NOT use `Start-Sleep`;
|
||||
instead, run the check command, use `get_terminal_output` to check later if needed):
|
||||
```powershell
|
||||
$reviews = gh api "repos/$repo/pulls/{{pr_number}}/reviews" | ConvertFrom-Json
|
||||
$copilotReview = $reviews | Where-Object {
|
||||
$_.user.login -match 'copilot' -or
|
||||
($_.user.type -eq 'Bot' -and $_.user.login -match 'copilot')
|
||||
} | Sort-Object -Property submitted_at -Descending | Select-Object -First 1
|
||||
```
|
||||
Wait until a Copilot review appears with state `CHANGES_REQUESTED` or `COMMENTED`.
|
||||
|
||||
**Timeout**: If no review appears after 5 minutes of polling, inform the user and ask
|
||||
whether to continue waiting or abort.
|
||||
|
||||
### Phase 5: Fetch and Categorize Comments
|
||||
|
||||
11. Fetch all review comments from Copilot's review:
|
||||
```powershell
|
||||
# Inline review comments
|
||||
$allComments = gh api "repos/$repo/pulls/{{pr_number}}/comments" | ConvertFrom-Json
|
||||
$copilotComments = $allComments | Where-Object { $_.user.login -match 'copilot' }
|
||||
|
||||
# Top-level review body
|
||||
$reviewBody = $copilotReview.body
|
||||
```
|
||||
|
||||
12. For each Copilot comment, categorize as **easy** or **hard**:
|
||||
|
||||
**Easy** (auto-fix without asking):
|
||||
- Style / formatting fixes (naming, whitespace, casing)
|
||||
- Adding missing null checks or simple input validation
|
||||
- Simple refactors (rename variable, extract constant, remove dead code)
|
||||
- Adding or removing `using` / `#include` statements
|
||||
- Removing unused imports or variables
|
||||
- Simple string or comment fixes
|
||||
- Adding missing braces, parentheses, or semicolons
|
||||
- Copilot provides a concrete code suggestion that is clearly correct and localized
|
||||
|
||||
**Hard** (requires human decision):
|
||||
- Architectural or design changes
|
||||
- Logic changes that could affect runtime behavior
|
||||
- Performance trade-offs with no clear winner
|
||||
- Suggestions that conflict with existing PowerToys patterns
|
||||
- Changes that span multiple files or components
|
||||
- Security-related changes that need careful consideration
|
||||
- Ambiguous suggestions where multiple valid approaches exist
|
||||
- Suggestions the agent disagrees with or finds incorrect
|
||||
|
||||
13. Write categorized comments to `Generated Files/communityPrReview/{{pr_number}}/copilot-comments.md`:
|
||||
```markdown
|
||||
# Copilot Review Comments — PR #{{pr_number}} — Iteration N
|
||||
|
||||
## Easy (will auto-fix)
|
||||
| # | File | Line | Comment Summary | Planned Fix |
|
||||
|---|------|------|-----------------|-------------|
|
||||
| 1 | ... | ... | ... | ... |
|
||||
|
||||
## Hard (needs human review)
|
||||
| # | File | Line | Comment Summary | Why It's Hard |
|
||||
|---|------|------|-----------------|---------------|
|
||||
| 1 | ... | ... | ... | ... |
|
||||
```
|
||||
|
||||
### Phase 6: Fix Easy Comments
|
||||
|
||||
14. In the worktree (`$prWorktree`), apply fixes for all **easy** comments:
|
||||
- Read the file and surrounding context
|
||||
- Apply the fix as suggested by Copilot (or as the agent deems correct)
|
||||
- Keep fixes minimal and surgical — no scope creep
|
||||
|
||||
15. After all easy fixes are applied, commit them:
|
||||
```powershell
|
||||
Push-Location $prWorktree
|
||||
git add -A
|
||||
git commit -m "Address Copilot review: auto-fix simple comments (PR #{{pr_number}})"
|
||||
Pop-Location
|
||||
```
|
||||
|
||||
### Phase 7: Build Verification
|
||||
|
||||
16. Build the project in the worktree:
|
||||
```powershell
|
||||
Push-Location $prWorktree
|
||||
tools\build\build-essentials.cmd
|
||||
tools\build\build.cmd
|
||||
Pop-Location
|
||||
```
|
||||
|
||||
17. If build fails (exit code non-zero):
|
||||
- Read `build.*.errors.log`
|
||||
- If errors are simple (typos, missing semicolons, obvious type mismatches introduced by
|
||||
the fixes), fix them and rebuild (max 3 attempts)
|
||||
- If errors are complex or pre-existing, document them for the user
|
||||
- Commit any build-fix changes separately
|
||||
|
||||
18. Record build results in `Generated Files/communityPrReview/{{pr_number}}/build-report.md`
|
||||
|
||||
### Phase 8: Present Results and STOP
|
||||
|
||||
19. Present a summary to the user:
|
||||
|
||||
```
|
||||
## PR #{{pr_number}} — Copilot Review Summary (Iteration N)
|
||||
|
||||
### Copilot Review
|
||||
- Total comments: X
|
||||
- Easy (auto-fixed): Y
|
||||
- Hard (needs your review): Z
|
||||
|
||||
### Auto-Fixes Applied
|
||||
1. file.cs:42 — <what was fixed>
|
||||
2. file.cpp:108 — <what was fixed>
|
||||
...
|
||||
|
||||
### Build Status
|
||||
✅ Build passed / ❌ Build failed (see build-report.md)
|
||||
|
||||
### Hard Comments — Need Your Input
|
||||
1. **file.cs:42** — Copilot: "<summary>" → <why it's hard>
|
||||
2. **file.cpp:108** — Copilot: "<summary>" → <why it's hard>
|
||||
...
|
||||
|
||||
For each hard comment, tell me:
|
||||
- "fix N" — accept and implement Copilot's suggestion
|
||||
- "skip N" — dismiss the comment
|
||||
- Or provide your own guidance
|
||||
```
|
||||
|
||||
20. **STOP here and wait for the user's response** on hard comments.
|
||||
Do NOT proceed until the user provides guidance.
|
||||
|
||||
### Phase 9: Process User Decisions on Hard Comments
|
||||
|
||||
21. After the user provides guidance:
|
||||
- Apply fixes for comments the user approved (`fix N`)
|
||||
- Skip dismissed comments (`skip N`)
|
||||
- Implement user-provided alternative approaches
|
||||
|
||||
22. Commit the changes:
|
||||
```powershell
|
||||
Push-Location $prWorktree
|
||||
git add -A
|
||||
git commit -m "Address Copilot review: fix complex comments per maintainer guidance (PR #{{pr_number}})"
|
||||
Pop-Location
|
||||
```
|
||||
|
||||
23. Rebuild to verify:
|
||||
```powershell
|
||||
Push-Location $prWorktree
|
||||
tools\build\build-essentials.cmd
|
||||
tools\build\build.cmd
|
||||
Pop-Location
|
||||
```
|
||||
|
||||
### Phase 10: Push and Request Re-Review
|
||||
|
||||
24. Push the fixes to the PR branch:
|
||||
```powershell
|
||||
Push-Location $prWorktree
|
||||
git push
|
||||
Pop-Location
|
||||
```
|
||||
If push fails (e.g., fork doesn't allow maintainer edits), inform the user and provide
|
||||
the diff as a patch or suggested changes instead (fall back to
|
||||
`{skills_root}/community-pr-review/scripts/Format-SuggestedChanges.ps1`).
|
||||
|
||||
25. Request Copilot re-review:
|
||||
```powershell
|
||||
gh api "repos/$repo/pulls/{{pr_number}}/requested_reviewers" -X POST -f 'reviewers[]=copilot'
|
||||
```
|
||||
|
||||
26. **Iterate**: Go back to **Phase 4** (wait for new review) and repeat.
|
||||
- Max **3 full iterations** of the review-fix cycle
|
||||
- If after 3 iterations there are still unresolved comments, stop and present the final state
|
||||
|
||||
### Phase 11: Finalize
|
||||
|
||||
27. After the loop completes (Copilot approves, no more actionable comments, or max iterations reached),
|
||||
write final outputs:
|
||||
- `Generated Files/communityPrReview/{{pr_number}}/final-summary.md`
|
||||
- `Generated Files/communityPrReview/{{pr_number}}/.signal`
|
||||
|
||||
28. Present a final summary:
|
||||
```
|
||||
## Final Review Status — PR #{{pr_number}}
|
||||
|
||||
- Iterations: N
|
||||
- Total Copilot comments addressed: X
|
||||
- Auto-fixed: Y
|
||||
- Human-guided fixes: Z
|
||||
- Skipped / dismissed: W
|
||||
- Build: ✅ / ❌
|
||||
|
||||
The PR branch has been updated with all fixes.
|
||||
Remaining action: verify E2E and approve/merge when ready.
|
||||
```
|
||||
|
||||
29. **Cleanup note**: The PR worktree can be removed with:
|
||||
```powershell
|
||||
tools/build/Delete-Worktree.ps1 -Pattern "<branch>" -Force
|
||||
```
|
||||
|
||||
## Output Files
|
||||
|
||||
All outputs go to `Generated Files/communityPrReview/{{pr_number}}/`:
|
||||
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `copilot-comments.md` | Categorized Copilot review comments per iteration |
|
||||
| `fix-summary.md` | Record of all fixes applied (auto + human-guided) |
|
||||
| `build-report.md` | Build verification results |
|
||||
| `final-summary.md` | Complete review record across all iterations |
|
||||
| `.signal` | Completion signal |
|
||||
|
||||
## Signal File Format
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"prNumber": 0,
|
||||
"iterations": 2,
|
||||
"copilotComments": { "total": 12, "autoFixed": 8, "humanGuided": 3, "skipped": 1 },
|
||||
"buildStatus": "success",
|
||||
"timestamp": "2026-04-14T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
Status values: `success`, `partial` (review done, build failed), `failure`
|
||||
|
||||
## Boundaries
|
||||
|
||||
- **Never approve or merge PRs** — leave final approval to the human maintainer
|
||||
- **Never force-push** — always use regular `git push`
|
||||
- **Stop for hard comments** — do not make complex or ambiguous decisions autonomously
|
||||
- **Max 3 iterations** — do not loop indefinitely on Copilot re-reviews
|
||||
- **Confirm triage** — always confirm triage results with the user before starting the review cycle
|
||||
- If push fails and cannot be resolved, fall back to generating suggested changes for the PR author
|
||||
- Stop when human interaction is needed (E2E verification, subjective design decisions)
|
||||
- If the PR is not a bug fix (feature, refactor, etc.), note this but still review
|
||||
- Maximum 3 review→fix iterations — if issues persist, report remaining issues for human decision
|
||||
|
||||
## Parameter
|
||||
|
||||
- **pr_number**: Extract from `#123`, `PR 123`, or plain number. If missing, **ASK** the user.
|
||||
46
.github/prompts/review-community-pr.prompt.md
vendored
Normal file
46
.github/prompts/review-community-pr.prompt.md
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
agent: 'ReviewCommunityPR'
|
||||
description: 'Triage a community PR, request GitHub Copilot cloud review, process comments locally (auto-fix easy ones, escalate hard ones), build-verify, and iterate'
|
||||
tools: ['execute', 'read', 'edit', 'search', 'web', 'github/*']
|
||||
argument-hint: 'PR number (e.g., #45234 or 45234)'
|
||||
---
|
||||
|
||||
# Review Community PR
|
||||
|
||||
Review a community-contributed PR using GitHub Copilot cloud review. This prompt invokes the `ReviewCommunityPR` agent.
|
||||
|
||||
## What It Does
|
||||
|
||||
Given a PR number, this workflow:
|
||||
|
||||
1. **Triages the PR** — checks if it's ready for review (skips drafts, WIP, incomplete PRs; flags early-stage feature PRs)
|
||||
2. **Requests Copilot cloud review** — assigns GitHub Copilot as a reviewer on the PR
|
||||
3. **Waits for Copilot comments** — polls until Copilot posts its review
|
||||
4. **Categorizes comments** — separates easy (auto-fixable) from hard (needs human decision)
|
||||
5. **Auto-fixes easy comments** — applies straightforward fixes without asking
|
||||
6. **Builds the project** — runs `build-essentials` then `build` to verify fixes don't break anything
|
||||
7. **Stops for hard comments** — presents complex comments for your review and guidance
|
||||
8. **Iterates** — pushes fixes and requests Copilot re-review (up to 3 cycles)
|
||||
9. **Generates outputs**:
|
||||
- `copilot-comments.md` — Categorized Copilot review comments per iteration
|
||||
- `fix-summary.md` — Record of all fixes applied (auto + human-guided)
|
||||
- `build-report.md` — Build status and actions taken
|
||||
- `final-summary.md` — Complete review record across all iterations
|
||||
|
||||
## Usage
|
||||
|
||||
Provide a PR number:
|
||||
|
||||
```
|
||||
Review community PR #45234
|
||||
```
|
||||
|
||||
Or run the script directly:
|
||||
|
||||
```powershell
|
||||
.github/skills/community-pr-review/scripts/Start-CommunityPRReview.ps1 -PRNumber 45234
|
||||
```
|
||||
|
||||
## Output Location
|
||||
|
||||
`Generated Files/communityPrReview/<PR>/`
|
||||
21
.github/skills/community-pr-review/LICENSE.txt
vendored
Normal file
21
.github/skills/community-pr-review/LICENSE.txt
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
173
.github/skills/community-pr-review/SKILL.md
vendored
Normal file
173
.github/skills/community-pr-review/SKILL.md
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
---
|
||||
name: community-pr-review
|
||||
description: Triage and review community PRs using GitHub Copilot cloud review. Use when asked to review a community PR, triage a PR for review readiness, request Copilot review on GitHub, process Copilot review comments locally, auto-fix simple review findings, or iterate on PR review feedback.
|
||||
license: Complete terms in LICENSE.txt
|
||||
---
|
||||
|
||||
# Community PR Review Skill
|
||||
|
||||
**Triage**, **request Copilot cloud review**, **process comments locally**, **build-verify**, and **iterate** on community PRs. Auto-fixes straightforward findings, escalates complex decisions to the maintainer.
|
||||
|
||||
## Skill Contents
|
||||
|
||||
```
|
||||
.github/skills/community-pr-review/
|
||||
├── SKILL.md # This file
|
||||
├── LICENSE.txt # MIT License
|
||||
├── scripts/
|
||||
│ ├── Start-CommunityPRReview.ps1 # Main orchestrator (loop-aware)
|
||||
│ ├── Format-SuggestedChanges.ps1 # Generate GitHub suggestion blocks from diff (fallback)
|
||||
│ └── ReviewLib.ps1 # Shared helpers
|
||||
└── references/
|
||||
├── review-community-pr.prompt.md # Detailed review prompt
|
||||
└── review-dimensions.md # Review criteria reference (for manual use)
|
||||
```
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
- Triage a PR to decide if it's ready for code review
|
||||
- Review a community-contributed PR using GitHub Copilot cloud review
|
||||
- Process Copilot review comments: auto-fix easy ones, escalate hard ones
|
||||
- Verify a PR builds cleanly after applying fixes
|
||||
- Iterate: push fixes and re-request Copilot review until clean
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- GitHub CLI (`gh`) installed and authenticated
|
||||
- GitHub Copilot code review enabled for the repository
|
||||
- PowerShell 7+
|
||||
- Visual Studio 2022 17.4+ or Visual Studio 2026 (for build verification)
|
||||
- Git submodules initialized (`git submodule update --init --recursive`)
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Option A: Use the agent directly
|
||||
|
||||
Invoke the `ReviewCommunityPR` agent with a PR number:
|
||||
```
|
||||
Review community PR #45234
|
||||
```
|
||||
|
||||
### Option B: Run the orchestrator script
|
||||
|
||||
```powershell
|
||||
.github/skills/community-pr-review/scripts/Start-CommunityPRReview.ps1 -PRNumber 45234
|
||||
```
|
||||
|
||||
### Option C: Use the prompt
|
||||
|
||||
Run `.github/prompts/review-community-pr.prompt.md` with a PR number.
|
||||
|
||||
## Workflow Overview
|
||||
|
||||
### Phase 1: Triage the PR
|
||||
Evaluate whether the PR is appropriate for review:
|
||||
- **Skip** drafts, closed/merged PRs, WIP/experimental PRs
|
||||
- **Flag** early-stage feature PRs, very large PRs, PRs with merge conflicts
|
||||
- **Confirm** with user before proceeding
|
||||
|
||||
### Phase 2: Setup Local Worktree
|
||||
1. Determine fork vs same-repo: `gh pr view <PR> --json isCrossRepository,...`
|
||||
2. Fork: `tools/build/New-WorktreeFromFork.ps1 -Spec <user>:<branch>`
|
||||
3. Same-repo: `tools/build/New-WorktreeFromBranch.ps1 -Branch <branch>`
|
||||
4. Initialize submodules
|
||||
|
||||
### Phase 3: Request GitHub Copilot Cloud Review
|
||||
Assign Copilot as a reviewer on the PR via the GitHub API:
|
||||
```powershell
|
||||
$repo = (gh repo view --json nameWithOwner --jq '.nameWithOwner')
|
||||
gh api "repos/$repo/pulls/<PR>/requested_reviewers" -X POST -f 'reviewers[]=copilot'
|
||||
```
|
||||
|
||||
### Phase 4: Wait for and Fetch Comments
|
||||
Poll until Copilot posts a review, then fetch all inline comments.
|
||||
|
||||
### Phase 5: Categorize and Fix
|
||||
|
||||
```
|
||||
┌──────────────────────────────┐
|
||||
│ Fetch Copilot review │
|
||||
│ comments from GitHub │
|
||||
└──────────┬───────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────┐
|
||||
│ Categorize each comment │
|
||||
│ as EASY or HARD │
|
||||
└──────────┬───────────────────┘
|
||||
│
|
||||
┌──────┴──────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────┐ ┌──────────────┐
|
||||
│ EASY │ │ HARD │
|
||||
│ Auto- │ │ Present to │
|
||||
│ fix │ │ user, STOP │
|
||||
└────┬────┘ └──────┬───────┘
|
||||
│ │
|
||||
▼ │ (user provides guidance)
|
||||
┌──────────────┐ │
|
||||
│ Build check │ ▼
|
||||
│ (essentials │ ┌──────────────┐
|
||||
│ + modules) │ │ Apply user │
|
||||
└──────┬───────┘ │ decisions │
|
||||
│ └──────┬───────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌──────────────────────────────┐
|
||||
│ Push fixes, request │
|
||||
│ Copilot re-review │
|
||||
└──────────┬───────────────────┘
|
||||
│
|
||||
(loop back, max 3x)
|
||||
```
|
||||
|
||||
**Easy comments** (auto-fix): style fixes, missing null checks, unused imports, simple refactors, concrete Copilot suggestions.
|
||||
|
||||
**Hard comments** (need human): architecture changes, logic changes, performance trade-offs, multi-file changes, security decisions, ambiguous suggestions.
|
||||
|
||||
### Phase 6: Build Verification
|
||||
After fixes, build in the worktree:
|
||||
```powershell
|
||||
Push-Location $prWorktree
|
||||
tools\build\build-essentials.cmd
|
||||
tools\build\build.cmd
|
||||
Pop-Location
|
||||
```
|
||||
Fix simple build-breaking changes automatically (max 3 attempts).
|
||||
|
||||
### Phase 7: Push and Iterate
|
||||
Push fixes → request Copilot re-review → repeat (max 3 full iterations).
|
||||
|
||||
## Output
|
||||
|
||||
All outputs go to `Generated Files/communityPrReview/<PR>/`:
|
||||
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `copilot-comments.md` | Categorized Copilot review comments per iteration |
|
||||
| `fix-summary.md` | Record of all fixes applied (auto + human-guided) |
|
||||
| `build-report.md` | Build status, errors encountered, fix-up actions taken |
|
||||
| `final-summary.md` | Complete review record across all iterations |
|
||||
| `.signal` | Completion signal for tooling |
|
||||
|
||||
### Signal File Format
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"prNumber": 45234,
|
||||
"iterations": 2,
|
||||
"copilotComments": { "total": 12, "autoFixed": 8, "humanGuided": 3, "skipped": 1 },
|
||||
"buildStatus": "success",
|
||||
"timestamp": "2026-04-14T10:05:23Z"
|
||||
}
|
||||
```
|
||||
|
||||
Status values: `success`, `partial` (review done, build failed), `failure`
|
||||
|
||||
## Related Skills
|
||||
|
||||
| Skill | Purpose |
|
||||
|-------|---------|
|
||||
| `pr-fix` | Fix review comments after review identifies issues |
|
||||
383
.github/skills/community-pr-review/references/review-community-pr.prompt.md
vendored
Normal file
383
.github/skills/community-pr-review/references/review-community-pr.prompt.md
vendored
Normal file
@@ -0,0 +1,383 @@
|
||||
---
|
||||
agent: 'agent'
|
||||
description: 'Review a community bug-fix PR: 7-dimension review, review→fix loop, build verification, and GitHub suggested changes'
|
||||
tools: ['execute', 'read', 'edit', 'search', 'web', 'github/*']
|
||||
argument-hint: 'PR number (e.g., #45234 or 45234)'
|
||||
---
|
||||
|
||||
# Review Community Bug-Fix PR
|
||||
|
||||
**Goal**: Given `{{pr_number}}`, run a review→fix loop: review across 7 dimensions, fix high/medium issues, re-review until clean, verify build, then generate GitHub suggested changes and verification instructions.
|
||||
|
||||
**Output folder**: `Generated Files/communityPrReview/{{pr_number}}/`
|
||||
|
||||
## PR Selection
|
||||
|
||||
Resolve the target PR:
|
||||
1. Parse the invocation text for an explicit PR number (first integer following `#` or `PR`).
|
||||
2. If not found, run `gh pr view --json number` for the current branch.
|
||||
3. If still unknown, **ASK** the user.
|
||||
|
||||
## Phase 1: Understand the PR
|
||||
|
||||
### 1.1 Fetch PR Metadata
|
||||
```
|
||||
gh pr view {{pr_number}} --json number,title,body,author,baseRefName,headRefName,baseRefOid,headRefOid,labels,url,state
|
||||
```
|
||||
|
||||
### 1.2 Identify the Bug
|
||||
- Parse the PR description for linked issue references (`Fixes #XXXX`, `Closes #XXXX`)
|
||||
- If linked issue found, fetch it: `gh issue view <issue_number> --json title,body,labels`
|
||||
- Understand: what is the bug? what is the expected behavior? what is the actual behavior?
|
||||
|
||||
### 1.3 Fetch Changed Files
|
||||
```
|
||||
gh pr diff {{pr_number}}
|
||||
```
|
||||
Also fetch the file list:
|
||||
```
|
||||
gh pr view {{pr_number}} --json files
|
||||
```
|
||||
|
||||
### 1.4 Record Original Head SHA
|
||||
Save the PR's head commit SHA as `originalHeadSha` — this is the baseline for generating suggested changes later.
|
||||
```powershell
|
||||
$originalHeadSha = (gh pr view {{pr_number}} --json headRefOid --jq .headRefOid)
|
||||
```
|
||||
|
||||
### 1.5 Create Worktree and Initial Build
|
||||
|
||||
> **Worktree isolation**: Do NOT use `gh pr checkout` — it would overwrite the current branch.
|
||||
> Instead, create an ISOLATED worktree for the PR's branch using the existing scripts in
|
||||
> `tools/build/`. All file reads, edits, and builds happen in the new worktree.
|
||||
> Output files go to the original worktree's `Generated Files/`.
|
||||
|
||||
#### Step 1: Determine fork vs same-repo
|
||||
```powershell
|
||||
$prMeta = gh pr view {{pr_number}} --json isCrossRepository,headRepositoryOwner,headRefName,headRepository | ConvertFrom-Json
|
||||
```
|
||||
|
||||
#### Step 2: Create the worktree
|
||||
```powershell
|
||||
# Fork PR:
|
||||
if ($prMeta.isCrossRepository) {
|
||||
$forkSpec = "$($prMeta.headRepositoryOwner.login):$($prMeta.headRefName)"
|
||||
tools/build/New-WorktreeFromFork.ps1 -Spec $forkSpec -ForkRepo $prMeta.headRepository.name
|
||||
}
|
||||
# Same-repo PR:
|
||||
else {
|
||||
git fetch origin $prMeta.headRefName
|
||||
tools/build/New-WorktreeFromBranch.ps1 -Branch $prMeta.headRefName
|
||||
}
|
||||
```
|
||||
|
||||
#### Step 3: Find the new worktree path
|
||||
```powershell
|
||||
# Parse git worktree list to find the newly created worktree
|
||||
git worktree list
|
||||
# The new worktree is a sibling directory, e.g., Q:\PowerToys-<hash>
|
||||
# Save it as $prWorktree
|
||||
```
|
||||
|
||||
#### Step 4: Initialize and build
|
||||
```powershell
|
||||
Push-Location $prWorktree
|
||||
git submodule update --init --recursive
|
||||
tools\build\build-essentials.cmd
|
||||
tools\build\build.cmd
|
||||
Pop-Location
|
||||
```
|
||||
|
||||
**IMPORTANT**: From this point on, ALL file operations on PR code use `$prWorktree` paths:
|
||||
- Reading files: `$prWorktree\src\modules\...`
|
||||
- Editing fixes: edit files at `$prWorktree\...`
|
||||
- Building: run `build.cmd` from `$prWorktree`
|
||||
- Git operations: `git -C $prWorktree ...`
|
||||
|
||||
If the initial build fails, try merging main in the worktree:
|
||||
```powershell
|
||||
Push-Location $prWorktree
|
||||
git fetch origin main
|
||||
git merge origin/main --no-edit
|
||||
tools\build\build.cmd
|
||||
Pop-Location
|
||||
```
|
||||
Record the build result. Even if it fails, proceed to code review.
|
||||
|
||||
## Phase 2: Review→Fix Loop (max 3 iterations)
|
||||
|
||||
For each iteration, perform the code review then fix. Track `iteration` starting at 1.
|
||||
|
||||
### Step 2a: Code Review (7 Dimensions)
|
||||
|
||||
For each dimension below, analyze ALL changed files and produce findings. Skip a dimension only if no changed files are relevant to it.
|
||||
|
||||
### Dimension 1: Correctness
|
||||
- Does the fix actually solve the reported bug?
|
||||
- Are all code paths to the bug covered?
|
||||
- Are edge cases handled (null, empty, boundary values, concurrent access)?
|
||||
- Could the fix introduce new bugs or regressions?
|
||||
- Are tests updated/added to cover the fix?
|
||||
- Is the fix complete or only partial?
|
||||
|
||||
### Dimension 2: Security
|
||||
- Is user input validated before use?
|
||||
- Are file paths canonicalized to prevent traversal?
|
||||
- Are shell commands avoided or properly escaped?
|
||||
- Is elevation (UAC) used only when necessary and scoped minimally?
|
||||
- Are credentials, tokens, or PII never logged or exposed?
|
||||
- For native code: buffer overflow prevention, format string safety, P/Invoke correctness?
|
||||
- Are IPC messages validated before processing?
|
||||
- Reference: OWASP Top 10, CWE Top 25, Microsoft SDL
|
||||
|
||||
### Dimension 3: Performance
|
||||
- Are hot paths (hooks, tight loops, event handlers) kept efficient?
|
||||
- No unnecessary allocations in frequently called code?
|
||||
- Are async patterns used correctly (no sync-over-async, proper cancellation)?
|
||||
- Are collections appropriately sized?
|
||||
- Are expensive operations (file I/O, registry, network) minimized?
|
||||
- No logging in performance-critical paths?
|
||||
|
||||
### Dimension 4: Reliability
|
||||
- Are errors handled gracefully (try/catch, HRESULT checks, null guards)?
|
||||
- Are resources properly disposed (IDisposable, COM objects, handles)?
|
||||
- Are race conditions prevented (thread safety, locking)?
|
||||
- Are event subscriptions balanced (subscribe ↔ unsubscribe)?
|
||||
- Does the fix handle process/module lifecycle correctly?
|
||||
- Are retries and timeouts appropriate?
|
||||
|
||||
### Dimension 5: Design
|
||||
- Is the fix appropriately scoped (not over-engineered)?
|
||||
- Does it follow SOLID principles?
|
||||
- Is the abstraction level appropriate?
|
||||
- Could the fix be simpler while still being correct?
|
||||
- Are there any code smells introduced (magic numbers, god methods, deep nesting)?
|
||||
- Is the fix in the right layer/module?
|
||||
|
||||
### Dimension 6: Compatibility
|
||||
- Are there breaking changes to public APIs or IPC contracts?
|
||||
- Is backward compatibility maintained for settings/config files?
|
||||
- Does the fix work across supported Windows versions (10 1803+)?
|
||||
- Are there implications for the installer or upgrade path?
|
||||
- If modifying shared code (`src/common/`), is ABI stability preserved?
|
||||
|
||||
### Dimension 7: Repo Patterns
|
||||
- Does the code follow PowerToys naming conventions?
|
||||
- Is the style consistent with surrounding code (check `.editorconfig`, `.clang-format`)?
|
||||
- Are new strings localized (`.resx` files)?
|
||||
- Is logging following the PowerToys pattern (spdlog for C++, Logger for C#)?
|
||||
- Are module interface contracts preserved?
|
||||
- Is the PR atomic (one logical change)?
|
||||
|
||||
### Step 2b: Write Review Comments
|
||||
|
||||
Write findings to `Generated Files/communityPrReview/{{pr_number}}/review-comments.md`.
|
||||
|
||||
For **high** and **medium** findings, ALWAYS include a ` ```suggestion ` block with replacement code:
|
||||
|
||||
```markdown
|
||||
# Review Comments — PR #{{pr_number}} — Iteration {{iteration}}
|
||||
|
||||
## Summary
|
||||
- **High severity**: <count>
|
||||
- **Medium severity**: <count>
|
||||
- **Low severity**: <count>
|
||||
- **Info**: <count>
|
||||
|
||||
## Overall Assessment
|
||||
<2-3 sentence assessment>
|
||||
|
||||
---
|
||||
|
||||
### [HIGH] Correctness — `path/to/file.ext`:42-48
|
||||
|
||||
<Clear description of the issue>
|
||||
|
||||
` ```suggestion `
|
||||
<replacement code that fixes the issue>
|
||||
` ``` `
|
||||
|
||||
---
|
||||
|
||||
### [MEDIUM] Security — `path/to/file.ext`:15-18
|
||||
|
||||
<Clear description of the issue>
|
||||
|
||||
` ```suggestion `
|
||||
<replacement code that fixes the issue>
|
||||
` ``` `
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
### Step 2c: Check Exit Condition
|
||||
|
||||
**Exit the loop if ANY of these are true:**
|
||||
- No **high** or **medium** severity findings in this iteration
|
||||
- This is iteration 3 (maximum reached)
|
||||
- All high/medium findings are architectural or require author decision (cannot be auto-fixed)
|
||||
|
||||
If exiting → go to Phase 3.
|
||||
|
||||
### Step 2d: Apply Fixes
|
||||
|
||||
For each **high** and **medium** finding from Step 2b:
|
||||
1. Open the file at the referenced line range **in `$prWorktree`**
|
||||
2. Apply the fix from the ` ```suggestion ` block (or implement the intent if suggestion is conceptual)
|
||||
3. Keep fixes minimal — only what's needed
|
||||
|
||||
After all fixes:
|
||||
- Run `tools\build\build.cmd` **from `$prWorktree`**
|
||||
- If build fails, read `build.*.errors.log` and fix build errors (max 3 attempts)
|
||||
- Record all fixes in `fix-summary.md`
|
||||
|
||||
### Step 2e: Increment and Loop
|
||||
|
||||
Increment `iteration` and go back to Step 2a to re-review the fixed code.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Generate Suggested Changes
|
||||
|
||||
After the review→fix loop completes, generate GitHub suggested changes from the diff:
|
||||
|
||||
```powershell
|
||||
# Compare worktree (with fixes) against original PR head
|
||||
git -C $prWorktree diff <originalHeadSha> HEAD
|
||||
```
|
||||
|
||||
For each changed hunk, write a suggested change using GitHub's native format.
|
||||
|
||||
Write `Generated Files/communityPrReview/{{pr_number}}/suggested-changes.md`:
|
||||
|
||||
```markdown
|
||||
# Suggested Changes — PR #{{pr_number}}
|
||||
|
||||
These changes address review findings from {{iteration}} review→fix iteration(s).
|
||||
Each suggestion uses GitHub's suggested changes format — post as PR review comments.
|
||||
|
||||
## Summary
|
||||
- **Total suggestions**: <count>
|
||||
- **Files affected**: <count>
|
||||
- **Iterations needed**: <count>
|
||||
|
||||
## Fixes Applied
|
||||
<Brief list of what each fix addresses>
|
||||
|
||||
---
|
||||
|
||||
## `path/to/file.ext`
|
||||
|
||||
### Suggestion 1 (lines X-Y)
|
||||
**Addresses:** [SEVERITY] Dimension — <brief finding description>
|
||||
|
||||
` ```suggestion `
|
||||
<replacement code>
|
||||
` ``` `
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
If no fixes were needed (clean review), write:
|
||||
```markdown
|
||||
# Suggested Changes — PR #{{pr_number}}
|
||||
|
||||
No code changes needed. The review found no high/medium issues.
|
||||
```
|
||||
|
||||
## Phase 4: Build Report
|
||||
|
||||
Write `Generated Files/communityPrReview/{{pr_number}}/build-report.md`:
|
||||
```markdown
|
||||
# Build Report — PR #{{pr_number}}
|
||||
|
||||
## Build Status: SUCCESS | FAILURE | SUCCESS_AFTER_MERGE
|
||||
|
||||
## Environment
|
||||
- Branch: <head branch>
|
||||
- Base: <base branch>
|
||||
- Head SHA: <sha>
|
||||
- Build date: <ISO timestamp>
|
||||
- Review iterations: <count>
|
||||
|
||||
## Build Steps
|
||||
1. <Step taken> — <result>
|
||||
2. <Step taken> — <result>
|
||||
|
||||
## Actions Taken to Fix Build (if any)
|
||||
- <action 1>
|
||||
- <action 2>
|
||||
|
||||
## Remaining Build Errors (if any)
|
||||
` ``` `
|
||||
<error details>
|
||||
` ``` `
|
||||
|
||||
## Suggestions for Author
|
||||
- <suggestion for the PR author if build issues need their attention>
|
||||
```
|
||||
|
||||
## Phase 5: Verification Guide
|
||||
|
||||
Write `Generated Files/communityPrReview/{{pr_number}}/verification-guide.md`:
|
||||
|
||||
```markdown
|
||||
# Verification Guide — PR #{{pr_number}}
|
||||
|
||||
## Bug Summary
|
||||
<1-2 sentence description of the bug from the linked issue>
|
||||
|
||||
## Steps to Reproduce the Original Bug
|
||||
1. <step>
|
||||
2. <step>
|
||||
3. <step>
|
||||
|
||||
## How to Verify the Fix
|
||||
1. <step>
|
||||
2. <step>
|
||||
3. <step>
|
||||
|
||||
## Expected Behavior After Fix
|
||||
- <what should happen>
|
||||
|
||||
## Edge Cases to Test
|
||||
- <edge case 1>
|
||||
- <edge case 2>
|
||||
|
||||
## Regression Areas to Smoke-Test
|
||||
- <area 1 — why it might be affected>
|
||||
- <area 2 — why it might be affected>
|
||||
|
||||
## Module/Feature Affected
|
||||
- **Module**: <module name>
|
||||
- **Settings path**: <if applicable>
|
||||
- **Hotkey**: <if applicable>
|
||||
```
|
||||
|
||||
## Phase 6: Signal File
|
||||
|
||||
Write `Generated Files/communityPrReview/{{pr_number}}/.signal`:
|
||||
```json
|
||||
{
|
||||
"status": "success|partial|failure",
|
||||
"prNumber": {{pr_number}},
|
||||
"originalHeadSha": "<original PR head SHA before any fixes>",
|
||||
"iterations": <number of review-fix iterations>,
|
||||
"reviewFindings": { "high": 0, "medium": 0, "low": 0, "info": 0 },
|
||||
"fixesApplied": <count of fixes applied>,
|
||||
"suggestedChanges": <count of GitHub suggestions generated>,
|
||||
"buildStatus": "success|failure|success_after_merge",
|
||||
"buildActions": ["list of actions taken"],
|
||||
"timestamp": "<ISO timestamp>"
|
||||
}
|
||||
```
|
||||
|
||||
## Constraints
|
||||
|
||||
- Keep fixes minimal — only address high/medium review findings
|
||||
- **Build verification may modify** the worktree (merge main, apply fixes) but these changes are NOT pushed
|
||||
- All fixes are presented as **suggested changes** for the PR author to accept
|
||||
- Keep comments specific, actionable, and fix-oriented
|
||||
- Reference file paths and line numbers in all findings
|
||||
- Stop and present results when human interaction is needed
|
||||
- Maximum 3 review→fix iterations — report remaining issues if loop doesn't converge
|
||||
210
.github/skills/community-pr-review/references/review-dimensions.md
vendored
Normal file
210
.github/skills/community-pr-review/references/review-dimensions.md
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
# Review Dimensions Reference
|
||||
|
||||
Detailed criteria for each of the 7 review dimensions used in community bug-fix PR review.
|
||||
|
||||
## 1. Correctness
|
||||
|
||||
**Goal**: Verify the fix solves the reported bug without introducing regressions.
|
||||
|
||||
### Checklist
|
||||
- [ ] Fix addresses the root cause described in the linked issue
|
||||
- [ ] All code paths to the bug are covered
|
||||
- [ ] Edge cases handled: null, empty, boundary values, max/min, concurrent access
|
||||
- [ ] No new bugs introduced by the fix
|
||||
- [ ] Tests added or updated to cover the fix
|
||||
- [ ] Fix is complete (not partial — all scenarios in the bug report addressed)
|
||||
- [ ] Conditional branches handle all expected cases
|
||||
- [ ] Loops terminate correctly (no infinite loops, off-by-one errors)
|
||||
- [ ] State properly initialized, used, and cleaned up
|
||||
|
||||
### PowerToys-Specific
|
||||
- [ ] Module interface contract remains intact
|
||||
- [ ] Hotkey registration and unregistration balanced
|
||||
- [ ] Feature works correctly with Runner lifecycle (enable/disable)
|
||||
- [ ] Settings UI changes reflected in module behavior
|
||||
|
||||
### Severity Guide
|
||||
| Severity | Criteria |
|
||||
|----------|----------|
|
||||
| High | Fix doesn't solve the bug, introduces crash, data loss |
|
||||
| Medium | Partial fix, edge cases broken, degraded UX |
|
||||
| Low | Minor issues, cosmetic, suboptimal but working |
|
||||
| Info | Suggestions for improvement |
|
||||
|
||||
---
|
||||
|
||||
## 2. Security
|
||||
|
||||
**Goal**: Identify security vulnerabilities and unsafe practices.
|
||||
|
||||
### Checklist
|
||||
- [ ] User input validated before use
|
||||
- [ ] File paths canonicalized (no `..` traversal)
|
||||
- [ ] Shell commands avoided or properly escaped
|
||||
- [ ] Elevation (UAC) used only when necessary, scoped minimally
|
||||
- [ ] Credentials, tokens, PII never logged or exposed
|
||||
- [ ] Temporary files created securely
|
||||
- [ ] Named pipes/shared memory secured with ACLs
|
||||
- [ ] IPC messages validated before processing
|
||||
- [ ] DLL search paths secured
|
||||
- [ ] No format string vulnerabilities
|
||||
|
||||
### Native Code (C/C++)
|
||||
- [ ] Buffer overflow prevention
|
||||
- [ ] P/Invoke signatures correct (buffer sizes)
|
||||
- [ ] Memory zeroed before freeing (for secrets)
|
||||
- [ ] No use-after-free patterns
|
||||
- [ ] RAII patterns for resource management
|
||||
|
||||
### Severity Guide
|
||||
| Severity | Criteria |
|
||||
|----------|----------|
|
||||
| High | RCE, privilege escalation, data breach possible |
|
||||
| Medium | Local exploit, information disclosure, weak crypto |
|
||||
| Low | Defense in depth improvement, hardening opportunity |
|
||||
| Info | Security best practice suggestions |
|
||||
|
||||
### References
|
||||
- OWASP Top 10: https://owasp.org/www-project-top-ten/
|
||||
- CWE Top 25: https://cwe.mitre.org/top25/
|
||||
- Microsoft SDL: https://www.microsoft.com/en-us/securityengineering/sdl
|
||||
|
||||
---
|
||||
|
||||
## 3. Performance
|
||||
|
||||
**Goal**: Ensure no performance regressions, especially in hot paths.
|
||||
|
||||
### Checklist
|
||||
- [ ] Hot paths (hooks, tight loops, event handlers) kept efficient
|
||||
- [ ] No unnecessary allocations in frequently called code
|
||||
- [ ] Async patterns correct (no sync-over-async, proper cancellation tokens)
|
||||
- [ ] Collections appropriately sized (no repeated resizing)
|
||||
- [ ] Expensive operations (file I/O, registry, network) minimized
|
||||
- [ ] No logging in performance-critical paths
|
||||
- [ ] LINQ used appropriately (no repeated enumeration)
|
||||
- [ ] String operations efficient (StringBuilder for loops)
|
||||
- [ ] No blocking on UI thread
|
||||
|
||||
### PowerToys-Specific
|
||||
- [ ] Hook callbacks execute quickly (< 1ms)
|
||||
- [ ] Settings reads cached appropriately
|
||||
- [ ] Module enable/disable is fast
|
||||
- [ ] No startup time regression
|
||||
|
||||
### Severity Guide
|
||||
| Severity | Criteria |
|
||||
|----------|----------|
|
||||
| High | Noticeable lag, UI freeze, O(n²) in common path |
|
||||
| Medium | Subtle perf regression, unnecessary work |
|
||||
| Low | Minor optimization opportunity |
|
||||
| Info | Performance best practice |
|
||||
|
||||
---
|
||||
|
||||
## 4. Reliability
|
||||
|
||||
**Goal**: Verify robust error handling and resource management.
|
||||
|
||||
### Checklist
|
||||
- [ ] Errors handled gracefully (try/catch, HRESULT checks, null guards)
|
||||
- [ ] Resources properly disposed (IDisposable, COM objects, handles)
|
||||
- [ ] Race conditions prevented (thread safety, proper locking)
|
||||
- [ ] Event subscriptions balanced (subscribe ↔ unsubscribe)
|
||||
- [ ] Process/module lifecycle handled correctly
|
||||
- [ ] Retries and timeouts appropriate
|
||||
- [ ] Graceful degradation on failure (don't crash the whole app)
|
||||
- [ ] Exception types appropriate (not catching all Exception)
|
||||
- [ ] Finalizers/destructors not relying on other managed objects
|
||||
|
||||
### PowerToys-Specific
|
||||
- [ ] Module crash doesn't take down Runner
|
||||
- [ ] Named pipe disconnection handled
|
||||
- [ ] Settings file corruption handled
|
||||
- [ ] Multi-monitor/DPI changes handled
|
||||
|
||||
### Severity Guide
|
||||
| Severity | Criteria |
|
||||
|----------|----------|
|
||||
| High | Crash, hang, resource leak causing system impact |
|
||||
| Medium | Intermittent failure, poor error recovery |
|
||||
| Low | Missing error handling in rare path |
|
||||
| Info | Reliability improvement suggestion |
|
||||
|
||||
---
|
||||
|
||||
## 5. Design
|
||||
|
||||
**Goal**: Assess code quality and architectural fit.
|
||||
|
||||
### Checklist
|
||||
- [ ] Fix appropriately scoped (not over-engineered)
|
||||
- [ ] SOLID principles followed
|
||||
- [ ] Abstraction level appropriate
|
||||
- [ ] Could be simpler while still correct?
|
||||
- [ ] No code smells (magic numbers, god methods, deep nesting)
|
||||
- [ ] Fix is in the right layer/module
|
||||
- [ ] No unnecessary coupling introduced
|
||||
- [ ] API surface changes are intentional and minimal
|
||||
|
||||
### Severity Guide
|
||||
| Severity | Criteria |
|
||||
|----------|----------|
|
||||
| High | Architectural violation, wrong abstraction layer |
|
||||
| Medium | Design smell, maintainability concern |
|
||||
| Low | Minor refactoring opportunity |
|
||||
| Info | Design improvement suggestion |
|
||||
|
||||
---
|
||||
|
||||
## 6. Compatibility
|
||||
|
||||
**Goal**: Ensure no breaking changes or compatibility issues.
|
||||
|
||||
### Checklist
|
||||
- [ ] No breaking changes to public APIs
|
||||
- [ ] IPC contracts (named pipes, JSON) preserved
|
||||
- [ ] Backward compatibility for settings/config files
|
||||
- [ ] Works across Windows 10 1803+ and Windows 11
|
||||
- [ ] Installer/upgrade path not affected
|
||||
- [ ] If modifying `src/common/`: ABI stability preserved
|
||||
- [ ] Schema migrations handled (if settings format changed)
|
||||
- [ ] GPO/policy paths not broken
|
||||
|
||||
### Severity Guide
|
||||
| Severity | Criteria |
|
||||
|----------|----------|
|
||||
| High | Breaking change, data loss on upgrade |
|
||||
| Medium | Partial compat issue, workaround exists |
|
||||
| Low | Minor compat concern, future risk |
|
||||
| Info | Compatibility best practice |
|
||||
|
||||
---
|
||||
|
||||
## 7. Repo Patterns
|
||||
|
||||
**Goal**: Verify adherence to PowerToys conventions.
|
||||
|
||||
### Checklist
|
||||
- [ ] Naming conventions followed (check `.editorconfig`, `.clang-format`)
|
||||
- [ ] Style consistent with surrounding code
|
||||
- [ ] New strings localized (`.resx` files)
|
||||
- [ ] Logging follows pattern (spdlog for C++, Logger for C#)
|
||||
- [ ] Module interface contracts preserved
|
||||
- [ ] PR is atomic (one logical change)
|
||||
- [ ] No drive-by refactors mixed in
|
||||
- [ ] New dependencies listed in `NOTICE.md`
|
||||
- [ ] Test coverage appropriate
|
||||
|
||||
### Style References
|
||||
- C#: `src/.editorconfig`, StyleCop.Analyzers
|
||||
- C++: `src/.clang-format`
|
||||
- XAML: XamlStyler
|
||||
|
||||
### Severity Guide
|
||||
| Severity | Criteria |
|
||||
|----------|----------|
|
||||
| High | Contract violation, ABI break |
|
||||
| Medium | Convention violation, inconsistent pattern |
|
||||
| Low | Minor style issue |
|
||||
| Info | Pattern improvement suggestion |
|
||||
228
.github/skills/community-pr-review/scripts/Format-SuggestedChanges.ps1
vendored
Normal file
228
.github/skills/community-pr-review/scripts/Format-SuggestedChanges.ps1
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Generate GitHub suggested changes from the diff between original PR and fixed code.
|
||||
|
||||
.DESCRIPTION
|
||||
Compares the current worktree state (with fixes applied) against the original PR
|
||||
head commit. For each changed hunk, generates a GitHub review comment with a
|
||||
```suggestion``` code block that the PR author can apply directly.
|
||||
|
||||
.PARAMETER PRNumber
|
||||
The PR number (required).
|
||||
|
||||
.PARAMETER OriginalSha
|
||||
The original HEAD SHA of the PR before fixes were applied.
|
||||
If not provided, reads from the .signal file.
|
||||
|
||||
.PARAMETER OutputDir
|
||||
Directory containing review outputs. Default: Generated Files/communityPrReview/<PR>
|
||||
|
||||
.PARAMETER WorktreeDir
|
||||
Path to the PR worktree. If provided, runs git commands there instead of the current repo.
|
||||
|
||||
.PARAMETER MinContextLines
|
||||
Number of context lines around each change. Default: 3.
|
||||
|
||||
.EXAMPLE
|
||||
./Format-SuggestedChanges.ps1 -PRNumber 45234 -OriginalSha abc123
|
||||
|
||||
.EXAMPLE
|
||||
./Format-SuggestedChanges.ps1 -PRNumber 45234
|
||||
#>
|
||||
param(
|
||||
[int]$PRNumber,
|
||||
[string]$OriginalSha,
|
||||
[string]$OutputDir,
|
||||
[string]$WorktreeDir,
|
||||
[int]$MinContextLines = 3,
|
||||
[switch]$Help
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
if ($Help) {
|
||||
Get-Help $MyInvocation.MyCommand.Path -Full
|
||||
return
|
||||
}
|
||||
|
||||
if (-not $PRNumber -or $PRNumber -eq 0) {
|
||||
Write-Error 'Format-SuggestedChanges: -PRNumber is required.'
|
||||
return
|
||||
}
|
||||
|
||||
# Load helpers
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
. "$scriptDir/ReviewLib.ps1"
|
||||
|
||||
$repoRoot = Get-RepoRoot
|
||||
|
||||
# Use WorktreeDir for git operations if provided, otherwise the current repo
|
||||
$gitDir = if (-not [string]::IsNullOrWhiteSpace($WorktreeDir)) { $WorktreeDir } else { $repoRoot }
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($OutputDir)) {
|
||||
$OutputDir = Join-Path $repoRoot "Generated Files/communityPrReview/$PRNumber"
|
||||
}
|
||||
|
||||
# Resolve original SHA from signal file if not provided
|
||||
if ([string]::IsNullOrWhiteSpace($OriginalSha)) {
|
||||
$signalPath = Join-Path $OutputDir '.signal'
|
||||
if (Test-Path $signalPath) {
|
||||
$signal = Get-Content $signalPath -Raw | ConvertFrom-Json
|
||||
$OriginalSha = $signal.originalHeadSha
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($OriginalSha)) {
|
||||
Write-Error 'Format-SuggestedChanges: -OriginalSha is required (or must be in .signal file).'
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Info "Generating suggested changes for PR #$PRNumber"
|
||||
Info "Original SHA: $OriginalSha"
|
||||
Info "Current HEAD: $(git -C $gitDir rev-parse HEAD)"
|
||||
Info "Git dir: $gitDir"
|
||||
|
||||
# Get the diff between original PR and current state
|
||||
$diffOutput = git -C $gitDir diff $OriginalSha HEAD --unified=$MinContextLines --no-color 2>&1
|
||||
if (-not $diffOutput) {
|
||||
Info "No changes between original PR and current state."
|
||||
$noChangesReport = @"
|
||||
# Suggested Changes — PR #$PRNumber
|
||||
|
||||
No code changes were needed. The review found no high/medium issues requiring fixes.
|
||||
"@
|
||||
$noChangesReport | Set-Content (Join-Path $OutputDir 'suggested-changes.md') -Force
|
||||
return
|
||||
}
|
||||
|
||||
# Parse the unified diff into per-file, per-hunk suggestions
|
||||
$suggestions = [System.Collections.Generic.List[hashtable]]::new()
|
||||
$currentFile = $null
|
||||
$currentHunk = $null
|
||||
$oldLines = @()
|
||||
$newLines = @()
|
||||
$hunkStartLine = 0
|
||||
|
||||
function Flush-Hunk {
|
||||
if ($null -eq $script:currentFile -or $null -eq $script:currentHunk) { return }
|
||||
if (($script:oldLines.Count -eq 0) -and ($script:newLines.Count -eq 0)) { return }
|
||||
|
||||
# Build the suggestion text (what the new code should be)
|
||||
$suggestionText = ($script:newLines -join "`n")
|
||||
|
||||
$script:suggestions.Add(@{
|
||||
File = $script:currentFile
|
||||
StartLine = $script:hunkStartLine
|
||||
EndLine = $script:hunkStartLine + $script:oldLines.Count - 1
|
||||
OldCode = ($script:oldLines -join "`n")
|
||||
NewCode = $suggestionText
|
||||
LineCount = $script:oldLines.Count
|
||||
})
|
||||
|
||||
$script:oldLines = @()
|
||||
$script:newLines = @()
|
||||
}
|
||||
|
||||
foreach ($line in ($diffOutput -split "`n")) {
|
||||
if ($line -match '^diff --git a/(.+) b/(.+)$') {
|
||||
Flush-Hunk
|
||||
$currentFile = $Matches[2]
|
||||
$currentHunk = $null
|
||||
continue
|
||||
}
|
||||
|
||||
if ($line -match '^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@') {
|
||||
Flush-Hunk
|
||||
$currentHunk = $true
|
||||
$hunkStartLine = [int]$Matches[2]
|
||||
$oldLines = @()
|
||||
$newLines = @()
|
||||
$lineCounter = [int]$Matches[2]
|
||||
continue
|
||||
}
|
||||
|
||||
if ($null -eq $currentHunk) { continue }
|
||||
|
||||
# Track context and changes within a hunk
|
||||
if ($line.StartsWith('+')) {
|
||||
# Added line (new code)
|
||||
$newLines += $line.Substring(1)
|
||||
}
|
||||
elseif ($line.StartsWith('-')) {
|
||||
# Removed line (old code)
|
||||
if ($oldLines.Count -eq 0) {
|
||||
$hunkStartLine = $lineCounter
|
||||
}
|
||||
$oldLines += $line.Substring(1)
|
||||
}
|
||||
else {
|
||||
# Context line — if we have accumulated changes, flush them
|
||||
if ($oldLines.Count -gt 0 -or $newLines.Count -gt 0) {
|
||||
Flush-Hunk
|
||||
}
|
||||
$lineCounter++
|
||||
# Context lines are part of both old and new
|
||||
$newLines = @()
|
||||
$oldLines = @()
|
||||
continue
|
||||
}
|
||||
}
|
||||
Flush-Hunk
|
||||
|
||||
# Generate the suggested-changes.md
|
||||
$output = [System.Text.StringBuilder]::new()
|
||||
[void]$output.AppendLine("# Suggested Changes — PR #$PRNumber")
|
||||
[void]$output.AppendLine("")
|
||||
[void]$output.AppendLine("These changes address review findings. Each suggestion can be applied directly on GitHub.")
|
||||
[void]$output.AppendLine("")
|
||||
[void]$output.AppendLine("## Summary")
|
||||
[void]$output.AppendLine("- **Total suggestions**: $($suggestions.Count)")
|
||||
$fileGroups = $suggestions | Group-Object { $_.File }
|
||||
[void]$output.AppendLine("- **Files affected**: $($fileGroups.Count)")
|
||||
[void]$output.AppendLine("")
|
||||
|
||||
$suggestionNum = 0
|
||||
foreach ($group in $fileGroups) {
|
||||
[void]$output.AppendLine("---")
|
||||
[void]$output.AppendLine("")
|
||||
[void]$output.AppendLine("## ``$($group.Name)``")
|
||||
[void]$output.AppendLine("")
|
||||
|
||||
foreach ($suggestion in $group.Group) {
|
||||
$suggestionNum++
|
||||
$lineRange = if ($suggestion.StartLine -eq $suggestion.EndLine) {
|
||||
"line $($suggestion.StartLine)"
|
||||
} else {
|
||||
"lines $($suggestion.StartLine)-$($suggestion.EndLine)"
|
||||
}
|
||||
|
||||
[void]$output.AppendLine("### Suggestion $suggestionNum ($lineRange)")
|
||||
[void]$output.AppendLine("")
|
||||
[void]$output.AppendLine("``````suggestion")
|
||||
[void]$output.AppendLine($suggestion.NewCode)
|
||||
[void]$output.AppendLine("``````")
|
||||
[void]$output.AppendLine("")
|
||||
}
|
||||
}
|
||||
|
||||
# Also generate a machine-readable JSON for posting via API
|
||||
$jsonSuggestions = $suggestions | ForEach-Object {
|
||||
@{
|
||||
path = $_.File
|
||||
start_line = $_.StartLine
|
||||
end_line = $_.EndLine
|
||||
body = "``````suggestion`n$($_.NewCode)`n``````"
|
||||
}
|
||||
}
|
||||
|
||||
$output.ToString() | Set-Content (Join-Path $OutputDir 'suggested-changes.md') -Force
|
||||
$jsonSuggestions | ConvertTo-Json -Depth 5 | Set-Content (Join-Path $OutputDir 'suggested-changes.json') -Force
|
||||
|
||||
Success "Generated $($suggestions.Count) suggestions across $($fileGroups.Count) files."
|
||||
Info "Output: $(Join-Path $OutputDir 'suggested-changes.md')"
|
||||
Info "JSON: $(Join-Path $OutputDir 'suggested-changes.json')"
|
||||
|
||||
return @{
|
||||
SuggestionCount = $suggestions.Count
|
||||
FileCount = $fileGroups.Count
|
||||
Suggestions = $suggestions
|
||||
}
|
||||
48
.github/skills/community-pr-review/scripts/ReviewLib.ps1
vendored
Normal file
48
.github/skills/community-pr-review/scripts/ReviewLib.ps1
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
# ReviewLib.ps1 - Shared helpers for community PR review workflow
|
||||
|
||||
#region Console Output Helpers
|
||||
function Info { param([string]$Message) Write-Host $Message -ForegroundColor Cyan }
|
||||
function Warn { param([string]$Message) Write-Host $Message -ForegroundColor Yellow }
|
||||
function Err { param([string]$Message) Write-Host $Message -ForegroundColor Red }
|
||||
function Success { param([string]$Message) Write-Host $Message -ForegroundColor Green }
|
||||
#endregion
|
||||
|
||||
#region Repository Helpers
|
||||
function Get-RepoRoot {
|
||||
$root = git rev-parse --show-toplevel 2>$null
|
||||
if (-not $root) { throw 'Not inside a git repository.' }
|
||||
return (Resolve-Path $root).Path
|
||||
}
|
||||
|
||||
function Get-SkillsRoot {
|
||||
$repoRoot = Get-RepoRoot
|
||||
if (Test-Path (Join-Path $repoRoot '.github/skills')) { return '.github/skills' }
|
||||
if (Test-Path (Join-Path $repoRoot '.claude/skills')) { return '.claude/skills' }
|
||||
throw 'No skills directory found (.github/skills or .claude/skills).'
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Signal File Helpers
|
||||
function Write-Signal {
|
||||
param(
|
||||
[string]$OutputDir,
|
||||
[hashtable]$Data
|
||||
)
|
||||
$signalPath = Join-Path $OutputDir '.signal'
|
||||
$Data['timestamp'] = (Get-Date).ToString('o')
|
||||
$Data | ConvertTo-Json -Depth 5 | Set-Content $signalPath -Force
|
||||
Info "Signal written: $signalPath"
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Build Helpers
|
||||
function Get-BuildErrorLog {
|
||||
param([string]$BuildDir)
|
||||
$errorLogs = Get-ChildItem -Path $BuildDir -Filter 'build.*.errors.log' -Recurse -ErrorAction SilentlyContinue |
|
||||
Sort-Object LastWriteTime -Descending
|
||||
if ($errorLogs) {
|
||||
return $errorLogs[0].FullName
|
||||
}
|
||||
return $null
|
||||
}
|
||||
#endregion
|
||||
257
.github/skills/community-pr-review/scripts/Start-CommunityPRReview.ps1
vendored
Normal file
257
.github/skills/community-pr-review/scripts/Start-CommunityPRReview.ps1
vendored
Normal file
@@ -0,0 +1,257 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Orchestrate a full community PR review: code review + build verification + verification guide.
|
||||
|
||||
.DESCRIPTION
|
||||
Runs the ReviewCommunityPR agent workflow for a given PR number.
|
||||
Spawns Copilot CLI or Claude CLI with the review prompt and monitors completion.
|
||||
|
||||
.PARAMETER PRNumber
|
||||
The PR number to review (required).
|
||||
|
||||
.PARAMETER CLIType
|
||||
AI CLI to use: copilot or claude. Default: copilot.
|
||||
|
||||
.PARAMETER Model
|
||||
Model override for Copilot CLI.
|
||||
|
||||
.PARAMETER SkipBuild
|
||||
Skip the build verification phase.
|
||||
|
||||
.PARAMETER OutputRoot
|
||||
Root folder for review outputs. Default: Generated Files/communityPrReview
|
||||
|
||||
.PARAMETER Force
|
||||
Re-review PRs that already have completed reviews.
|
||||
|
||||
.PARAMETER DryRun
|
||||
Show what would be done without executing.
|
||||
|
||||
.EXAMPLE
|
||||
./Start-CommunityPRReview.ps1 -PRNumber 45234
|
||||
|
||||
.EXAMPLE
|
||||
./Start-CommunityPRReview.ps1 -PRNumber 45234 -CLIType claude -SkipBuild
|
||||
|
||||
.EXAMPLE
|
||||
./Start-CommunityPRReview.ps1 -PRNumber 45234 -Force
|
||||
#>
|
||||
param(
|
||||
[int]$PRNumber,
|
||||
[string]$CLIType = 'copilot',
|
||||
[string]$Model,
|
||||
[int]$MaxIterations = 3,
|
||||
[switch]$SkipBuild,
|
||||
[string]$OutputRoot = 'Generated Files/communityPrReview',
|
||||
[string]$LogPath,
|
||||
[switch]$Force,
|
||||
[switch]$DryRun,
|
||||
[switch]$Help
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
if ($Help) {
|
||||
Get-Help $MyInvocation.MyCommand.Path -Full
|
||||
return
|
||||
}
|
||||
|
||||
if (-not $PRNumber -or $PRNumber -eq 0) {
|
||||
Write-Error 'Start-CommunityPRReview: -PRNumber is required.'
|
||||
return
|
||||
}
|
||||
|
||||
if ($CLIType -notin 'copilot', 'claude') {
|
||||
Write-Error "Start-CommunityPRReview: Invalid -CLIType '$CLIType'. Must be 'copilot' or 'claude'."
|
||||
return
|
||||
}
|
||||
|
||||
# Load helpers
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
. "$scriptDir/ReviewLib.ps1"
|
||||
|
||||
$repoRoot = Get-RepoRoot
|
||||
|
||||
# Resolve config directory name (.github or .claude) from script location
|
||||
$_cfgDir = if ($PSScriptRoot -match '[\\/](\.github|\.claude)[\\/]') { $Matches[1] } else { '.github' }
|
||||
|
||||
# ── Setup logging ────────────────────────────────────────────────────────
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($LogPath)) {
|
||||
$LogPath = Join-Path (Get-Location) 'Start-CommunityPRReview.log'
|
||||
}
|
||||
$logDir = Split-Path -Parent $LogPath
|
||||
if (-not [string]::IsNullOrWhiteSpace($logDir) -and -not (Test-Path $logDir)) {
|
||||
New-Item -ItemType Directory -Path $logDir -Force | Out-Null
|
||||
}
|
||||
|
||||
function Write-LogHost {
|
||||
param(
|
||||
[Parameter(Position = 0, ValueFromRemainingArguments = $true)]
|
||||
[object[]]$Object,
|
||||
[object]$ForegroundColor,
|
||||
[object]$BackgroundColor,
|
||||
[switch]$NoNewline,
|
||||
[Object]$Separator
|
||||
)
|
||||
$message = [string]::Join(' ', ($Object | ForEach-Object { [string]$_ }))
|
||||
"[$(Get-Date -Format o)] $message" | Out-File -FilePath $LogPath -Encoding utf8 -Append
|
||||
$invokeParams = @{}
|
||||
if ($PSBoundParameters.ContainsKey('ForegroundColor') -and -not [string]::IsNullOrWhiteSpace([string]$ForegroundColor)) { $invokeParams.ForegroundColor = $ForegroundColor }
|
||||
if ($PSBoundParameters.ContainsKey('BackgroundColor') -and -not [string]::IsNullOrWhiteSpace([string]$BackgroundColor)) { $invokeParams.BackgroundColor = $BackgroundColor }
|
||||
if ($NoNewline) { $invokeParams.NoNewline = $true }
|
||||
if ($PSBoundParameters.ContainsKey('Separator')) { $invokeParams.Separator = $Separator }
|
||||
Microsoft.PowerShell.Utility\Write-Host @invokeParams -Object $message
|
||||
}
|
||||
Set-Alias -Name Write-Host -Value Write-LogHost -Scope Script -Force
|
||||
|
||||
# ── Resolve output directory ─────────────────────────────────────────────
|
||||
|
||||
$reviewRoot = if ([System.IO.Path]::IsPathRooted($OutputRoot)) {
|
||||
$OutputRoot
|
||||
} else {
|
||||
Join-Path $repoRoot $OutputRoot
|
||||
}
|
||||
|
||||
$reviewDir = Join-Path $reviewRoot "$PRNumber"
|
||||
|
||||
# Check for existing review
|
||||
if (-not $Force -and (Test-Path (Join-Path $reviewDir 'review-comments.md'))) {
|
||||
Info "PR #$PRNumber already has a completed review at $reviewDir"
|
||||
Info "Use -Force to re-review."
|
||||
return
|
||||
}
|
||||
|
||||
if (-not (Test-Path $reviewDir)) {
|
||||
New-Item -ItemType Directory -Path $reviewDir -Force | Out-Null
|
||||
}
|
||||
|
||||
# ── Prepare prompt ───────────────────────────────────────────────────────
|
||||
|
||||
Info "=" * 80
|
||||
Info "Community PR Review — PR #$PRNumber"
|
||||
Info "=" * 80
|
||||
Info "Repository root: $repoRoot"
|
||||
Info "Output directory: $reviewDir"
|
||||
Info "CLI type: $CLIType"
|
||||
Info "Max iterations: $MaxIterations"
|
||||
Info "Skip build: $SkipBuild"
|
||||
|
||||
$reviewPromptPath = Join-Path $repoRoot "$_cfgDir/skills/community-pr-review/references/review-community-pr.prompt.md"
|
||||
$reviewDirForPrompt = ($reviewDir -replace '\\', '/')
|
||||
|
||||
if (Test-Path $reviewPromptPath) {
|
||||
$rawPrompt = Get-Content $reviewPromptPath -Raw
|
||||
$rawPrompt = $rawPrompt -replace '\{\{pr_number\}\}', [string]$PRNumber
|
||||
$rawPrompt = $rawPrompt -replace '\{\{iteration\}\}', '1'
|
||||
$rawPrompt = $rawPrompt -replace 'Generated Files/communityPrReview/\{\{pr_number\}\}', $reviewDirForPrompt
|
||||
}
|
||||
else {
|
||||
Warn "Review prompt not found at $reviewPromptPath, using inline prompt."
|
||||
$rawPrompt = @"
|
||||
Review community bug-fix PR #$PRNumber with a review-fix loop (max $MaxIterations iterations).
|
||||
1. Fetch PR data and linked issue. Record original head SHA.
|
||||
2. Checkout and build. If build fails, try merging main.
|
||||
3. Review-fix loop: review 7 dimensions, fix high/medium issues, re-review until clean.
|
||||
4. Generate suggested-changes.md with GitHub suggestion blocks from diff.
|
||||
5. Write build-report.md and verification-guide.md.
|
||||
6. Write .signal file.
|
||||
Output to: $reviewDirForPrompt/
|
||||
"@
|
||||
}
|
||||
|
||||
$skipBuildNote = if ($SkipBuild) { "`n`nIMPORTANT: Skip the build verification phase. Set buildStatus to 'skipped' in the signal file." } else { '' }
|
||||
$loopNote = "`n`nReview-fix loop: max $MaxIterations iterations. Exit when no high/medium findings remain or max iterations reached."
|
||||
|
||||
$prompt = @"
|
||||
You are running a community PR review workflow for PR #$PRNumber.
|
||||
Execute the workflow below exactly and write all outputs to $reviewDirForPrompt/.
|
||||
$skipBuildNote$loopNote
|
||||
|
||||
$rawPrompt
|
||||
"@
|
||||
|
||||
$flatPrompt = ($prompt -replace "[\r\n]+", ' ').Trim()
|
||||
|
||||
if ($DryRun) {
|
||||
Info "`nDry run — would execute:"
|
||||
Info " CLI: $CLIType"
|
||||
Info " Agent: ReviewCommunityPR"
|
||||
Info " Output: $reviewDir"
|
||||
Info "`nPrompt (first 500 chars):"
|
||||
Info $flatPrompt.Substring(0, [Math]::Min($flatPrompt.Length, 500))
|
||||
return
|
||||
}
|
||||
|
||||
# Write in-progress signal
|
||||
Write-Signal -OutputDir $reviewDir -Data @{
|
||||
status = 'in-progress'
|
||||
prNumber = $PRNumber
|
||||
}
|
||||
|
||||
# ── Execute CLI ──────────────────────────────────────────────────────────
|
||||
|
||||
$logFile = Join-Path $reviewDir "_review.log"
|
||||
|
||||
if ($CLIType -eq 'copilot') {
|
||||
$copilotExe = (Get-Command copilot -ErrorAction SilentlyContinue).Source
|
||||
if (-not $copilotExe) { $copilotExe = 'copilot' }
|
||||
|
||||
$cliArgs = @('-p', $flatPrompt, '--yolo', '--no-custom-instructions', '--agent', 'ReviewCommunityPR')
|
||||
if ($Model) { $cliArgs += @('--model', $Model) }
|
||||
|
||||
Info "`nLaunching Copilot CLI..."
|
||||
Info "Log file: $logFile"
|
||||
|
||||
& $copilotExe @cliArgs 2>&1 | Tee-Object -FilePath $logFile
|
||||
$exitCode = $LASTEXITCODE
|
||||
}
|
||||
else {
|
||||
$cliArgs = @('-p', $flatPrompt, '--dangerously-skip-permissions', '--agent', 'ReviewCommunityPR')
|
||||
|
||||
Info "`nLaunching Claude CLI..."
|
||||
Info "Log file: $logFile"
|
||||
|
||||
& claude @cliArgs 2>&1 | Tee-Object -FilePath $logFile
|
||||
$exitCode = $LASTEXITCODE
|
||||
}
|
||||
|
||||
# ── Finalize ─────────────────────────────────────────────────────────────
|
||||
|
||||
$hasReview = Test-Path (Join-Path $reviewDir 'review-comments.md')
|
||||
$hasBuild = Test-Path (Join-Path $reviewDir 'build-report.md')
|
||||
$hasVerification = Test-Path (Join-Path $reviewDir 'verification-guide.md')
|
||||
$hasSuggestions = Test-Path (Join-Path $reviewDir 'suggested-changes.md')
|
||||
$hasFixSummary = Test-Path (Join-Path $reviewDir 'fix-summary.md')
|
||||
|
||||
$status = if ($hasReview -and ($hasBuild -or $SkipBuild) -and $hasVerification) {
|
||||
'success'
|
||||
} elseif ($hasReview) {
|
||||
'partial'
|
||||
} else {
|
||||
'failure'
|
||||
}
|
||||
|
||||
Write-Signal -OutputDir $reviewDir -Data @{
|
||||
status = $status
|
||||
prNumber = $PRNumber
|
||||
exitCode = $exitCode
|
||||
hasReview = $hasReview
|
||||
hasBuild = $hasBuild
|
||||
hasVerification = $hasVerification
|
||||
hasSuggestions = $hasSuggestions
|
||||
hasFixSummary = $hasFixSummary
|
||||
}
|
||||
|
||||
Info "`n$("=" * 80)"
|
||||
Info "COMMUNITY PR REVIEW COMPLETE"
|
||||
Info "=" * 80
|
||||
Info "PR: #$PRNumber"
|
||||
Info "Status: $status"
|
||||
Info "Review comments: $(if ($hasReview) { 'YES' } else { 'NO' })"
|
||||
Info "Suggested changes: $(if ($hasSuggestions) { 'YES' } else { 'NO' })"
|
||||
Info "Fix summary: $(if ($hasFixSummary) { 'YES' } else { 'NO' })"
|
||||
Info "Build report: $(if ($hasBuild) { 'YES' } else { 'NO' })"
|
||||
Info "Verification: $(if ($hasVerification) { 'YES' } else { 'NO' })"
|
||||
Info "Output: $reviewDir"
|
||||
Info "=" * 80
|
||||
Reference in New Issue
Block a user