@olegkoval/agent-skills 1.49.2 โ†’ 1.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/.github/copilot-instructions.md +1 -0
  2. package/.github/prompts/coderabbitloop.prompt.md +90 -15
  3. package/.github/prompts/codexloop.prompt.md +33 -6
  4. package/.github/prompts/copilotloop.prompt.md +302 -0
  5. package/.github/prompts/geminiloop.prompt.md +34 -6
  6. package/.github/prompts/qodoloop.prompt.md +18 -0
  7. package/.kiro/steering/coderabbitloop.md +90 -15
  8. package/.kiro/steering/codexloop.md +33 -6
  9. package/.kiro/steering/copilotloop.md +301 -0
  10. package/.kiro/steering/geminiloop.md +34 -6
  11. package/.kiro/steering/qodoloop.md +18 -0
  12. package/.windsurf/rules/coderabbitloop.md +90 -15
  13. package/.windsurf/rules/codexloop.md +33 -6
  14. package/.windsurf/rules/copilotloop.md +300 -0
  15. package/.windsurf/rules/geminiloop.md +34 -6
  16. package/.windsurf/rules/qodoloop.md +18 -0
  17. package/README.md +1 -0
  18. package/adapters/claude/olko-github-pr/skills/coderabbitloop/SKILL.md +91 -16
  19. package/adapters/claude/olko-github-pr/skills/coderabbitloop/references/graphql-queries.md +41 -9
  20. package/adapters/claude/olko-github-pr/skills/codexloop/SKILL.md +35 -8
  21. package/adapters/claude/olko-github-pr/skills/copilotloop/SKILL.md +309 -0
  22. package/adapters/claude/olko-github-pr/skills/geminiloop/SKILL.md +36 -8
  23. package/adapters/claude/olko-github-pr/skills/lekker-review/SKILL.md +26 -1
  24. package/adapters/claude/olko-github-pr/skills/lekker-review/references/agents/completeness-critic.md +12 -0
  25. package/adapters/claude/olko-github-pr/skills/lekker-review/references/agents/implementation.md +26 -1
  26. package/adapters/claude/olko-github-pr/skills/lekker-review/references/agents/prover.md +8 -1
  27. package/adapters/claude/olko-github-pr/skills/lekker-review/references/agents/test-quality.md +20 -2
  28. package/adapters/claude/olko-github-pr/skills/lekker-review/references/agents/verifier.md +25 -0
  29. package/adapters/claude/olko-github-pr/skills/lekker-review/references/fix-mode.md +23 -0
  30. package/adapters/claude/olko-github-pr/skills/qodoloop/SKILL.md +19 -1
  31. package/adapters/claude/olko-github-pr/skills/qodoloop/references/graphql-queries.md +19 -2
  32. package/adapters/codex/olko-github-pr/README.md +1 -0
  33. package/adapters/cursor/olko-github-pr/skills/coderabbitloop/SKILL.md +91 -16
  34. package/adapters/cursor/olko-github-pr/skills/coderabbitloop/references/graphql-queries.md +41 -9
  35. package/adapters/cursor/olko-github-pr/skills/codexloop/SKILL.md +35 -8
  36. package/adapters/cursor/olko-github-pr/skills/copilotloop/SKILL.md +309 -0
  37. package/adapters/cursor/olko-github-pr/skills/geminiloop/SKILL.md +36 -8
  38. package/adapters/cursor/olko-github-pr/skills/qodoloop/SKILL.md +19 -1
  39. package/adapters/cursor/olko-github-pr/skills/qodoloop/references/graphql-queries.md +19 -2
  40. package/adapters/grok/olko-github-pr/skills/coderabbitloop/SKILL.md +91 -16
  41. package/adapters/grok/olko-github-pr/skills/coderabbitloop/references/graphql-queries.md +41 -9
  42. package/adapters/grok/olko-github-pr/skills/codexloop/SKILL.md +35 -8
  43. package/adapters/grok/olko-github-pr/skills/copilotloop/SKILL.md +309 -0
  44. package/adapters/grok/olko-github-pr/skills/geminiloop/SKILL.md +36 -8
  45. package/adapters/grok/olko-github-pr/skills/qodoloop/SKILL.md +19 -1
  46. package/adapters/grok/olko-github-pr/skills/qodoloop/references/graphql-queries.md +19 -2
  47. package/catalog/skills.json +23 -0
  48. package/package.json +1 -1
  49. package/plugins/olko-apple-kit/.claude-plugin/plugin.json +1 -1
  50. package/plugins/olko-creative/.claude-plugin/plugin.json +1 -1
  51. package/plugins/olko-garmin-kit/.claude-plugin/plugin.json +1 -1
  52. package/plugins/olko-git-tools/.claude-plugin/plugin.json +1 -1
  53. package/plugins/olko-github-pr/.claude-plugin/plugin.json +1 -1
  54. package/plugins/olko-github-pr/skills/coderabbitloop/SKILL.md +91 -16
  55. package/plugins/olko-github-pr/skills/coderabbitloop/references/graphql-queries.md +41 -9
  56. package/plugins/olko-github-pr/skills/codexloop/SKILL.md +35 -8
  57. package/plugins/olko-github-pr/skills/copilotloop/SKILL.md +308 -0
  58. package/plugins/olko-github-pr/skills/geminiloop/SKILL.md +36 -8
  59. package/plugins/olko-github-pr/skills/lekker-review/SKILL.md +26 -1
  60. package/plugins/olko-github-pr/skills/lekker-review/references/agents/completeness-critic.md +12 -0
  61. package/plugins/olko-github-pr/skills/lekker-review/references/agents/implementation.md +26 -1
  62. package/plugins/olko-github-pr/skills/lekker-review/references/agents/prover.md +8 -1
  63. package/plugins/olko-github-pr/skills/lekker-review/references/agents/test-quality.md +20 -2
  64. package/plugins/olko-github-pr/skills/lekker-review/references/agents/verifier.md +25 -0
  65. package/plugins/olko-github-pr/skills/lekker-review/references/fix-mode.md +23 -0
  66. package/plugins/olko-github-pr/skills/lekker-review/workflow.js +87 -5
  67. package/plugins/olko-github-pr/skills/qodoloop/SKILL.md +19 -1
  68. package/plugins/olko-github-pr/skills/qodoloop/references/graphql-queries.md +19 -2
  69. package/plugins/olko-obsidian/.claude-plugin/plugin.json +1 -1
  70. package/plugins/olko-product/.claude-plugin/plugin.json +1 -1
  71. package/plugins/olko-reflection/.claude-plugin/plugin.json +1 -1
  72. package/plugins/olko-release/.claude-plugin/plugin.json +1 -1
  73. package/plugins/olko-skill-meta/.claude-plugin/plugin.json +1 -1
  74. package/plugins/olko-web-ops/.claude-plugin/plugin.json +1 -1
  75. package/scripts/lib/catalog.mjs +1 -1
@@ -6,9 +6,9 @@ description: >
6
6
  ones, and rebut + resolve false positives WITHOUT changing correct code. Repeat until no
7
7
  unresolved Codex comments remain. Use when the user says "satisfy codex", "clear the codex
8
8
  review", "fix codex comments", "codex loop", or wants to iterate on Codex PR review feedback.
9
- compatibility: GitHub only (Codex code review is a GitHub app). Requires git + gh (GitHub CLI) authenticated, and the Codex / ChatGPT connector app installed on the repo with code review enabled.
9
+ compatibility: GitHub only (Codex code review is a GitHub app). Requires git + jq + gh (GitHub CLI) authenticated, and the Codex / ChatGPT connector app installed on the repo with code review enabled.
10
10
  metadata:
11
- version: "1.1"
11
+ version: "1.2"
12
12
  allowed-tools: Bash(gh:*) Bash(git:*)
13
13
  ---
14
14
  <!-- Generated by scripts/build-adapters.sh. Do not edit directly. -->
@@ -37,7 +37,7 @@ suggestion applied is worse than the comment itself.
37
37
  ## Not for
38
38
 
39
39
  - GitLab / Perforce (Codex code review is a GitHub app). For other review bots this catalog ships
40
- `geminiloop`, `coderabbitloop`, and `qodoloop`; for CI failures rather than review comments, use
40
+ `copilotloop`, `geminiloop`, `coderabbitloop`, and `qodoloop`; for CI failures rather than review comments, use
41
41
  `ci-fix-loop`.
42
42
 
43
43
  ## 0. Resolve the Codex bot login (do this first, do not hardcode)
@@ -84,9 +84,13 @@ report and list what is still unresolved rather than starting a sixth.
84
84
 
85
85
  ```bash
86
86
  HEAD_SHA=$(gh pr view <PR> --json headRefOid -q .headRefOid)
87
- # Only trigger if no Codex review already exists for this exact SHA:
88
- HAVE=$(gh api repos/{owner}/{repo}/pulls/<PR>/reviews --paginate \
89
- --jq "[.[] | select(.user.login==\"$BOT\" and .commit_id==\"$HEAD_SHA\")] | length")
87
+ # Only trigger if no Codex review already exists for this exact SHA.
88
+ # gh cannot combine --slurp with --jq, so pipe to `jq -s`: it folds every page
89
+ # into one array. Without it the filter runs once per page and HAVE becomes a
90
+ # multi-line count that never equals "0", silently skipping the trigger.
91
+ HAVE=$(gh api repos/{owner}/{repo}/pulls/<PR>/reviews --paginate |
92
+ jq -s --arg bot "$BOT" --arg head "$HEAD_SHA" \
93
+ '[.[][] | select(.user.login==$bot and .commit_id==$head)] | length')
90
94
  if [ "$HAVE" = "0" ]; then gh pr comment <PR> --body "@codex review"; fi
91
95
  ```
92
96
 
@@ -100,8 +104,9 @@ an honest timeout, not hang it.
100
104
  wait_for_review() { # $1 = attempt label
101
105
  local deadline=$(( SECONDS + 600 ))
102
106
  while [ "$SECONDS" -lt "$deadline" ]; do
103
- R=$(gh api repos/{owner}/{repo}/pulls/<PR>/reviews --paginate \
104
- --jq "[.[] | select(.user.login==\"$BOT\" and .commit_id==\"$HEAD_SHA\")] | last")
107
+ R=$(gh api repos/{owner}/{repo}/pulls/<PR>/reviews --paginate |
108
+ jq -s --arg bot "$BOT" --arg head "$HEAD_SHA" \
109
+ '[.[][] | select(.user.login==$bot and .commit_id==$head)] | sort_by(.submitted_at, .id) | last')
105
110
  if [ -n "$R" ] && [ "$R" != "null" ]; then return 0; fi
106
111
  echo "waiting for Codex review of $HEAD_SHA ($1)..."; sleep 15
107
112
  done
@@ -135,6 +140,13 @@ gh api repos/{owner}/{repo}/pulls/<PR>/comments --paginate \
135
140
  Also pull the review threads + their resolved state via GraphQL (see step F) so you only act on
136
141
  unresolved ones.
137
142
 
143
+ Mark each unresolved comment as seen, so the bot and a watching human can tell it is being handled.
144
+ GitHub's reaction set is fixed; `eyes` is the only "looking at it" value:
145
+
146
+ ```bash
147
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<COMMENT_ID>/reactions -f content=eyes
148
+ ```
149
+
138
150
  ### C. Critically evaluate EACH comment (the core of this skill)
139
151
 
140
152
  For every comment, **verify the claim against the actual code and repo conventions before touching
@@ -236,6 +248,21 @@ then resolve:
236
248
  gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: "THREAD_ID"}) { thread { isResolved } } }'
237
249
  ```
238
250
 
251
+ Then record the disposition as a reaction on the bot's own comment: the learning signal, and a
252
+ visible marker for a human scanning the PR:
253
+
254
+ - ๐Ÿ‘ (`+1`): the finding was accepted and fixed.
255
+ - ๐Ÿ‘Ž (`-1`): the finding was rebutted as a false positive. **This is the correction signal.**
256
+
257
+ ```bash
258
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<COMMENT_ID>/reactions -f content=+1
259
+ # rebutted finding:
260
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<COMMENT_ID>/reactions -f content=-1
261
+ ```
262
+
263
+ Reply first, then react, then resolve: the reaction is not a substitute for the reply, and a
264
+ resolved thread with no reply loses the reasoning.
265
+
239
266
  Resolve a thread only for comments authored by `$BOT` that you have fixed or rebutted: never
240
267
  blanket-resolve, and never resolve a human reviewer's thread. For each fixed comment, verify the
241
268
  push first, reply with the change made, then resolve the thread and verify `isResolved: true`.
@@ -0,0 +1,309 @@
1
+ ---
2
+ name: copilotloop
3
+ description: >
4
+ Iteratively satisfy GitHub Copilot's code review on a GitHub PR, but treat every Copilot comment
5
+ SKEPTICALLY: verify each finding against the real code first, fix ONLY the genuinely-correct
6
+ ones, and rebut + resolve false positives WITHOUT changing correct code. Repeat until no
7
+ unresolved Copilot comments remain. Use when the user says "satisfy Copilot", "clear the Copilot
8
+ review", "fix Copilot comments", "Copilot loop", or wants to iterate on Copilot PR feedback.
9
+ compatibility: GitHub only (Copilot code review is a GitHub feature). Requires git + jq + gh (GitHub CLI) authenticated, Copilot code review enabled, and permission to request reviewers on the repository.
10
+ metadata:
11
+ version: "1.1"
12
+ allowed-tools: Bash(gh:*) Bash(git:*)
13
+ ---
14
+ <!-- Generated by scripts/build-adapters.sh. Do not edit directly. -->
15
+
16
+ # Copilotloop
17
+
18
+ Drive a GitHub PR until Copilot has no unresolved review comments, **but do not cargo-cult its
19
+ suggestions.** Every comment is a *claim to verify*, not an instruction to obey. A wrong
20
+ suggestion applied is worse than the comment itself.
21
+
22
+ ## How Copilot differs from other review bots
23
+
24
+ - **No check-run, no score.** Copilot posts an overview comment and a PR review with inline review
25
+ comments. Detection is by polling the reviews endpoint and paginated review threads. "Satisfied"
26
+ means zero unresolved Copilot threads and zero unaddressed body findings after each finding is
27
+ fixed or rebutted with a recorded reply.
28
+ - **Request through the reviewers API.** Copilot does not use a reliable slash-command trigger.
29
+ Request `copilot-pull-request-reviewer[bot]` through the pull request reviewers endpoint. A
30
+ repository may also be configured to review new pushes automatically.
31
+ - **Copilot may repeat comments.** A re-review can repeat comments that were resolved or downvoted,
32
+ so match findings to the current head and prior replies before reopening work, including body
33
+ findings that have no inline thread.
34
+ - **Copilot is concise and can reason from the diff alone.** Its characteristic failure is
35
+ confidently asserting a bug based only on the changed hunk, without the surrounding file or the
36
+ call sites. That makes "read the whole file before believing it" the single highest-value check.
37
+
38
+ ## Not for
39
+
40
+ - GitLab / Perforce. For other review bots this catalog ships `codexloop`, `geminiloop`,
41
+ `coderabbitloop`, and `qodoloop`; for CI failures rather than review comments, use
42
+ `ci-fix-loop`.
43
+
44
+ ## 0. Resolve the Copilot bot login (do this first)
45
+
46
+ The bot login is normally stable, but confirm it from the PR rather than assuming it:
47
+
48
+ ```bash
49
+ gh api repos/{owner}/{repo}/pulls/<PR>/reviews --paginate --jq '.[].user.login' | sort -u
50
+ gh api repos/{owner}/{repo}/pulls/<PR>/comments --paginate --jq '.[].user.login' | sort -u
51
+ ```
52
+
53
+ Use `copilot-pull-request-reviewer[bot]` as `BOT`. Confirm it appears after the first requested
54
+ review; if GitHub uses a different login for the installation, use the exact Copilot-looking login
55
+ returned by the probe rather than guessing.
56
+
57
+ **Finding nothing here is NOT a stop condition.** On a PR Copilot has never reviewed there is no bot
58
+ login to find yet. Fall through to step 2A, request the reviewer, and re-run this probe once a
59
+ review lands. Only conclude Copilot is unavailable after the bounded wait expires with no review.
60
+
61
+ ## 1. Identify the PR
62
+
63
+ ```bash
64
+ gh pr view --json number,headRefName,headRefOid -q '{number,branch:.headRefName,head:.headRefOid}'
65
+ ```
66
+
67
+ Switch to the PR branch if not already on it. Capture `OWNER`/`REPO` (`gh repo view --json owner,name`).
68
+
69
+ ## 2. The loop (max 5 iterations)
70
+
71
+ Keep an explicit iteration counter and stop at 5: the cap is a real bound to enforce, not a
72
+ figure of speech. Each pass through Aโ€“G is one iteration; on hitting the cap, go straight to the
73
+ report and list what is still unresolved rather than starting a sixth.
74
+
75
+ ### A. Ensure a fresh Copilot review on the current head
76
+
77
+ ```bash
78
+ HEAD_SHA=$(gh pr view <PR> --json headRefOid -q .headRefOid)
79
+ # Only trigger if no Copilot review exists for this exact SHA:
80
+ HAVE=$(gh api repos/{owner}/{repo}/pulls/<PR>/reviews --paginate |
81
+ jq -s --arg bot "$BOT" --arg head "$HEAD_SHA" \
82
+ '[.[][] | select(.user.login==$bot and .commit_id==$head)] | length')
83
+ if [ "$HAVE" = "0" ]; then
84
+ gh api --method POST repos/{owner}/{repo}/pulls/<PR>/requested_reviewers \
85
+ -f 'reviewers[]=copilot-pull-request-reviewer[bot]'
86
+ fi
87
+ ```
88
+
89
+ Poll for the review of THIS head to land. No check-run exists, so poll the reviews endpoint, and
90
+ poll it on a **deadline**, never `while true`: a review that never arrives must end the skill with
91
+ an honest timeout, not hang it.
92
+
93
+ ```bash
94
+ # 10-minute deadline, one retry, then give up. DEADLINE/RETRIES are the
95
+ # enforcement of the bounds this skill claims: do not drop them.
96
+ wait_for_review() { # $1 = attempt label
97
+ local deadline=$(( SECONDS + 600 ))
98
+ while [ "$SECONDS" -lt "$deadline" ]; do
99
+ R=$(gh api repos/{owner}/{repo}/pulls/<PR>/reviews --paginate |
100
+ jq -s --arg bot "$BOT" --arg head "$HEAD_SHA" \
101
+ '[.[][] | select(.user.login==$bot and .commit_id==$head)] | sort_by(.submitted_at, .id) | last')
102
+ if [ -n "$R" ] && [ "$R" != "null" ]; then return 0; fi
103
+ echo "waiting for Copilot review of $HEAD_SHA ($1)..."; sleep 15
104
+ done
105
+ return 1
106
+ }
107
+
108
+ if ! wait_for_review "first wait"; then
109
+ echo "no Copilot review after 10m, retrying once" # say the retry out loud
110
+ gh api --method POST repos/{owner}/{repo}/pulls/<PR>/requested_reviewers \
111
+ -f 'reviewers[]=copilot-pull-request-reviewer[bot]'
112
+ if ! wait_for_review "after retry"; then
113
+ echo "Copilot did not review $HEAD_SHA after a retry; stopping and reporting."
114
+ exit 1 # honest timeout, never a success claim
115
+ fi
116
+ fi
117
+ ```
118
+
119
+ Copilot usually reviews quickly, but large diffs can take longer; the deadline is bounded. Report the
120
+ retry in the final summary; two silent timeouts are the failure mode this guard exists to prevent.
121
+
122
+ ### B. Fetch the findings
123
+
124
+ - **Summary**: read the Copilot overview comment and review `.body`, including all matching reviews
125
+ for the current head. Extract and classify actionable claims even when they have no inline thread;
126
+ an approval assessment or lack of inline comments does not make those findings complete.
127
+ Track each body finding across iterations by source review/comment ID and item, with its
128
+ classification, fix commit or evidence-based rebuttal, PR-level reply URL, and completion status.
129
+ Link duplicates to the same finding so they are counted once; retain pending findings after a push.
130
+ - **Unresolved inline comments** on the current head:
131
+
132
+ ```bash
133
+ gh api repos/{owner}/{repo}/pulls/<PR>/comments --paginate \
134
+ --jq ".[] | select(.user.login==\"$BOT\") | {id, path, line, body}"
135
+ ```
136
+
137
+ Also pull the review threads + their resolved state via GraphQL (see step F) so you only act on
138
+ unresolved ones.
139
+
140
+ Mark each unresolved inline comment as seen, so the bot and a watching human can tell it is being
141
+ handled. GitHub's reaction set is fixed; `eyes` is the only "looking at it" value:
142
+
143
+ ```bash
144
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<COMMENT_ID>/reactions -f content=eyes
145
+ ```
146
+
147
+ Body findings (no inline thread) have no comment to react to; track them in step B's register and
148
+ give each a PR-level reply in step F instead.
149
+
150
+ ### C. Critically evaluate EACH finding (the core of this skill)
151
+
152
+ For every inline or body finding, **verify the claim against the actual code and repo conventions
153
+ before touching anything.** Read the whole file, not just the diff hunk Copilot saw, plus the types
154
+ and the call sites. Then classify:
155
+
156
+ 1. **CORRECT + actionable**: the finding is real and the fix improves the code. โ†’ fix it (step D).
157
+ 2. **FALSE POSITIVE / technically wrong**: the claim doesn't hold. โ†’ do **NOT** change code; write a
158
+ specific, evidence-based reply (cite the exact code/line/behavior that disproves it), then resolve
159
+ its thread or record completion for a body finding (step F).
160
+ 3. **Valid but out-of-scope / stylistic nit** that conflicts with repo convention or the PR's intent
161
+ โ†’ briefly decline with evidence of that convention or scope, then resolve its thread or record
162
+ completion for a body finding (step F). Do not expand the PR's scope to satisfy a nit.
163
+
164
+ **Hard rules:**
165
+ - **Never modify correct code just to silence Copilot.** Prefer a reasoned rebuttal.
166
+ - When uncertain whether a claim holds, **investigate** (read more code, run the type-checker / tests)
167
+ rather than assume Copilot is right. Default to skepticism.
168
+ - If a suggested change would break other call sites, alter public behavior, or contradict a verified
169
+ repo convention, it is a category-2 rebuttal, not a fix.
170
+ - Never fabricate identifiers to satisfy a comment (e.g. a Linear/ticket prefix). If Copilot asks for a
171
+ ticket reference and none exists, say so; do not invent one.
172
+
173
+ **Copilot's common failure modes to watch for (default these to category 2):**
174
+ - Diff-local reasoning: asserts a bug that the unchanged surrounding code already handles.
175
+ - "This can be null/undefined here" where the type or an earlier guard already rules it out.
176
+ - Invented race conditions or error paths with no actual trigger.
177
+ - Suggestions that compile-break or break other callers.
178
+ - Security/perf warnings with no exploit path or measurable cost.
179
+ - Restating library/framework semantics incorrectly.
180
+ - Style demands that contradict the repo's existing, consistent pattern.
181
+
182
+ ### D. Apply fixes: category 1 only
183
+
184
+ Make the minimal correct change. Re-run the local gate if the repo has one (typecheck/tests) before
185
+ moving on.
186
+
187
+ ### E. Commit and push FIRST, before resolving anything
188
+
189
+ Order matters. A resolved thread is a claim that the fix is on the branch, so the push has to
190
+ succeed before the claim is made: otherwise a failed commit or push leaves the PR unfixed with the
191
+ finding marked resolved, and nobody looks at it again.
192
+
193
+ If step D changed code:
194
+
195
+ ```bash
196
+ # Stage ONLY the files your fixes touched: never `git add -A`, which sweeps up
197
+ # unrelated work and untracked secrets sitting in the worktree.
198
+ git status --short # look before you stage
199
+ git add <path> [<path>...] # the files named in the findings you fixed
200
+ git commit -m "address Copilot review feedback (copilotloop iteration N)"
201
+ git push
202
+ ```
203
+
204
+ Author the commit per the repo's norms (e.g. the user's identity; no AI attribution if that is the
205
+ convention). Confirm the push actually landed before continuing:
206
+
207
+ ```bash
208
+ git rev-parse HEAD
209
+ gh pr view <PR> --json headRefOid -q .headRefOid # must match
210
+ ```
211
+
212
+ If they differ, stop: the fix is not on the PR, so nothing may be resolved yet.
213
+
214
+ ### F. Reply to every addressed finding and resolve its inline threads
215
+
216
+ Only now, with the fixes pushed, reply and resolve. Fetch unresolved threads, **following
217
+ pagination**: a PR with more than 100 threads will otherwise look clean while unresolved findings
218
+ sit on page two:
219
+
220
+ ```bash
221
+ # Loop until hasNextPage is false, passing endCursor back in as $cursor.
222
+ CURSOR=null
223
+ while : ; do
224
+ PAGE=$(gh api graphql -F cursor="$CURSOR" -f query='
225
+ query($cursor: String) {
226
+ repository(owner: "OWNER", name: "REPO") {
227
+ pullRequest(number: PR_NUMBER) {
228
+ reviewThreads(first: 100, after: $cursor) {
229
+ pageInfo { hasNextPage endCursor }
230
+ nodes { id isResolved comments(first: 1) { nodes { databaseId author { login } path body } } }
231
+ }
232
+ }
233
+ }
234
+ }')
235
+ echo "$PAGE" # collect nodes from every page before deciding the PR is clean
236
+ PI='.data.repository.pullRequest.reviewThreads.pageInfo'
237
+ [ "$(echo "$PAGE" | jq -r "$PI.hasNextPage")" = "true" ] || break
238
+ CURSOR=$(echo "$PAGE" | jq -r "$PI.endCursor")
239
+ done
240
+ ```
241
+
242
+ Reply on a thread's comment via `gh api repos/{owner}/{repo}/pulls/<PR>/comments -f body="..." -F in_reply_to=<comment_id>`,
243
+ then resolve:
244
+
245
+ ```bash
246
+ gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: "THREAD_ID"}) { thread { isResolved } } }'
247
+ ```
248
+
249
+ Then record the disposition of each inline finding as a reaction on Copilot's own comment: the
250
+ learning signal, and a visible marker for a human scanning the PR:
251
+
252
+ - ๐Ÿ‘ (`+1`): the finding was accepted and fixed.
253
+ - ๐Ÿ‘Ž (`-1`): the finding was rebutted as a false positive. **This is the correction signal.**
254
+
255
+ ```bash
256
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<COMMENT_ID>/reactions -f content=+1
257
+ # rebutted finding:
258
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<COMMENT_ID>/reactions -f content=-1
259
+ ```
260
+
261
+ Reply first, then react, then resolve: the reaction is not a substitute for the reply, and a
262
+ resolved thread with no reply loses the reasoning.
263
+
264
+ Resolve a thread only for comments authored by `$BOT` that you have fixed or rebutted: never
265
+ blanket-resolve, and never resolve a human reviewer's thread.
266
+
267
+ Threads you are **rebutting** need no push, so they may be replied to and resolved regardless of
268
+ whether step D changed code.
269
+
270
+ For each body finding, post a PR-level reply (for example, using
271
+ `gh pr comment <PR> --body-file <reply-file>`) identifying the source review/comment and item.
272
+ Record the pushed fix commit and validation, or an evidence-based rebuttal, including the reason
273
+ for declining an out-of-scope finding. Record the reply URL in the tracking entry before marking
274
+ it complete. One reply may cover multiple explicitly identified findings. Fixed body findings
275
+ require the same successful push check as fixed threads; rebuttals need no push. If a finding also
276
+ has an inline thread, that thread still requires a reply and resolution.
277
+
278
+ ### G. Re-review
279
+
280
+ Pushing re-triggers Copilot when automatic review of new pushes is on; otherwise request Copilot again
281
+ through the reviewers endpoint. Go back to **A**
282
+ with the new head SHA. If step D changed nothing (all comments were rebutted), skip the push,
283
+ ensure all Copilot threads are resolved and all tracked body findings have recorded PR-level
284
+ replies and are complete, then exit.
285
+
286
+ ## 3. Exit conditions
287
+
288
+ Stop when **any** is true:
289
+ - Zero unresolved `$BOT` threads and zero pending body findings remain across iterations. Every
290
+ finding was fixed or rebutted with evidence, every inline thread was replied to and resolved,
291
+ and every body finding has a recorded PR-level reply. (There is no score to hit:
292
+ this is "done".)
293
+ - Max iterations (5) reached: report what remains.
294
+ - Copilot never responded after one retry: report the timeout honestly; do not claim success.
295
+
296
+ ## 4. Report
297
+
298
+ ```text
299
+ Copilotloop complete.
300
+ PR: #<n>
301
+ Bot login: <resolved $BOT>
302
+ Iterations: N
303
+ Findings fixed: N (inline + body findings, deduplicated)
304
+ Findings rebutted: N (inline + body findings, with recorded evidence-based replies)
305
+ Remaining: 0 (unresolved inline + pending body findings, deduplicated)
306
+ ```
307
+
308
+ If it stopped at max iterations, list the remaining threads and body findings with your current
309
+ assessment (fix-pending vs disputed) so a human can arbitrate.
@@ -6,9 +6,9 @@ description: >
6
6
  against the real code first, fix ONLY the genuinely-correct ones, and rebut + resolve false
7
7
  positives WITHOUT changing correct code. Repeat until no unresolved Gemini comments remain. Use
8
8
  when the user wants to clear a PR's Gemini Code Assist review.
9
- compatibility: GitHub only (Gemini Code Assist is a GitHub app). Requires git + gh (GitHub CLI) authenticated, and the Gemini Code Assist app installed on the repo.
9
+ compatibility: GitHub only (Gemini Code Assist is a GitHub app). Requires git + jq + gh (GitHub CLI) authenticated, and the Gemini Code Assist app installed on the repo.
10
10
  metadata:
11
- version: "1.0"
11
+ version: "1.1"
12
12
  allowed-tools: Bash(gh:*) Bash(git:*)
13
13
  ---
14
14
  <!-- Generated by scripts/build-adapters.sh. Do not edit directly. -->
@@ -37,7 +37,7 @@ instruction to obey. A wrong suggestion applied is worse than the comment itself
37
37
  ## Not for
38
38
 
39
39
  - GitLab / Perforce (Gemini Code Assist is GitHub-only). For other review bots this catalog ships
40
- `codexloop`, `coderabbitloop`, and `qodoloop`; for CI failures rather than review comments, use
40
+ `copilotloop`, `codexloop`, `coderabbitloop`, and `qodoloop`; for CI failures rather than review comments, use
41
41
  `ci-fix-loop`.
42
42
 
43
43
  ## 1. Identify the PR
@@ -60,9 +60,13 @@ Gemini auto-reviews new commits, but force a deterministic pass and record the h
60
60
 
61
61
  ```bash
62
62
  HEAD_SHA=$(gh pr view <PR> --json headRefOid -q .headRefOid)
63
- # Only trigger if no gemini review already exists for this exact SHA:
64
- HAVE=$(gh api repos/{owner}/{repo}/pulls/<PR>/reviews --paginate \
65
- --jq "[.[] | select(.user.login==\"gemini-code-assist[bot]\" and .commit_id==\"$HEAD_SHA\")] | length")
63
+ # Only trigger if no gemini review already exists for this exact SHA.
64
+ # gh cannot combine --slurp with --jq, so pipe to `jq -s`: it folds every page
65
+ # into one array. Without it the filter runs once per page and HAVE becomes a
66
+ # multi-line count that never equals "0", silently skipping the trigger.
67
+ HAVE=$(gh api repos/{owner}/{repo}/pulls/<PR>/reviews --paginate |
68
+ jq -s --arg head "$HEAD_SHA" \
69
+ '[.[][] | select(.user.login=="gemini-code-assist[bot]" and .commit_id==$head)] | length')
66
70
  if [ "$HAVE" = "0" ]; then gh pr comment <PR> --body "/gemini review"; fi
67
71
  ```
68
72
 
@@ -75,8 +79,9 @@ an honest timeout, not hang it.
75
79
  wait_for_review() { # $1 = attempt label
76
80
  local deadline=$(( SECONDS + 600 ))
77
81
  while [ "$SECONDS" -lt "$deadline" ]; do
78
- R=$(gh api repos/{owner}/{repo}/pulls/<PR>/reviews --paginate \
79
- --jq "[.[] | select(.user.login==\"gemini-code-assist[bot]\" and .commit_id==\"$HEAD_SHA\")] | last")
82
+ R=$(gh api repos/{owner}/{repo}/pulls/<PR>/reviews --paginate |
83
+ jq -s --arg head "$HEAD_SHA" \
84
+ '[.[][] | select(.user.login=="gemini-code-assist[bot]" and .commit_id==$head)] | sort_by(.submitted_at, .id) | last')
80
85
  if [ -n "$R" ] && [ "$R" != "null" ]; then return 0; fi
81
86
  echo "waiting for Gemini review of $HEAD_SHA ($1)..."; sleep 15
82
87
  done
@@ -110,6 +115,13 @@ gh api repos/{owner}/{repo}/pulls/<PR>/comments --paginate \
110
115
  Also pull the review threads + their resolved state via GraphQL (see step F) so you only act on
111
116
  unresolved ones.
112
117
 
118
+ Mark each unresolved comment as seen, so the bot and a watching human can tell it is being handled.
119
+ GitHub's reaction set is fixed; `eyes` is the only "looking at it" value:
120
+
121
+ ```bash
122
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<COMMENT_ID>/reactions -f content=eyes
123
+ ```
124
+
113
125
  ### C. Critically evaluate EACH comment (the core of this skill)
114
126
 
115
127
  For every comment, **verify the claim against the actual code and repo conventions before touching
@@ -205,6 +217,21 @@ then resolve:
205
217
  gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: "THREAD_ID"}) { thread { isResolved } } }'
206
218
  ```
207
219
 
220
+ Then record the disposition as a reaction on the bot's own comment: the learning signal, and a
221
+ visible marker for a human scanning the PR:
222
+
223
+ - ๐Ÿ‘ (`+1`): the finding was accepted and fixed.
224
+ - ๐Ÿ‘Ž (`-1`): the finding was rebutted as a false positive. **This is the correction signal.**
225
+
226
+ ```bash
227
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<COMMENT_ID>/reactions -f content=+1
228
+ # rebutted finding:
229
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<COMMENT_ID>/reactions -f content=-1
230
+ ```
231
+
232
+ Reply first, then react, then resolve: the reaction is not a substitute for the reply, and a
233
+ resolved thread with no reply loses the reasoning.
234
+
208
235
  Resolve a thread only for comments authored by `gemini-code-assist[bot]` that you have fixed or
209
236
  rebutted: never blanket-resolve, and never resolve a human reviewer's thread.
210
237
 
@@ -222,6 +249,7 @@ Stop when **any** is true:
222
249
  - Zero unresolved `gemini-code-assist[bot]` comments remain, and every comment this round was fixed
223
250
  or rebutted+resolved. (There is no score to hit: this is "done".)
224
251
  - Max iterations (5) reached: report what remains.
252
+ - Gemini never responded after one retry: report the timeout honestly; do not claim success.
225
253
 
226
254
  ## 4. Report
227
255
 
@@ -8,7 +8,7 @@ description: >
8
8
  addressed against Qodo's review, or says "run qodoloop" / "satisfy Qodo" / "resolve Qodo comments".
9
9
  compatibility: Requires git and gh (GitHub CLI) authenticated, with Qodo Merge installed on the repo.
10
10
  metadata:
11
- version: "1.0"
11
+ version: "1.1"
12
12
  allowed-tools: Bash(gh:*) Bash(git:*)
13
13
  ---
14
14
  <!-- Generated by scripts/build-adapters.sh. Do not edit directly. -->
@@ -86,6 +86,14 @@ Run the paginated GraphQL query in `references/graphql-queries.md` (`unresolvedQ
86
86
 
87
87
  Build the working set: all `recommended` threads, plus `optional` ones too if `--include-optional`.
88
88
 
89
+ Mark each thread as seen with an ๐Ÿ‘€ reaction on its first comment (`databaseId` from the query), so
90
+ the bot and a watching human can tell it is being worked. GitHub's reaction set is fixed; `eyes` is
91
+ the only "looking at it" value:
92
+
93
+ ```bash
94
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<DATABASE_ID>/reactions -f content=eyes
95
+ ```
96
+
89
97
  #### C. Check exit conditions
90
98
 
91
99
  Stop if the working set is empty, or max iterations reached.
@@ -122,6 +130,16 @@ This is the "answer to the comments" half of the job, not optional cleanup, and
122
130
  Pass the thread id and reply text as GraphQL **variables** (`-f threadId=... -f body=...`), never interpolated into the query string itself: a reply containing a quote, backtick, or newline breaks (or worse, injects into) a hand-built query. Then resolve with `resolveReviewThread` (see references file).
123
131
  - **Blocked** findings: reply explaining exactly why (false positive / needs a human call), but **do not resolve**: leave the thread open. A blocked finding that gets silently resolved is a false "done".
124
132
 
133
+ Then record each disposition as a reaction on the thread's first comment: the learning signal, and
134
+ a visible marker for a human scanning the PR. ๐Ÿ‘ (`+1`) for a fixed finding, ๐Ÿ‘Ž (`-1`) for a
135
+ blocked/rebutted one. Reply first, react, then resolve: a reaction never replaces the reply.
136
+
137
+ ```bash
138
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<DATABASE_ID>/reactions -f content=+1
139
+ # blocked/rebutted finding:
140
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<DATABASE_ID>/reactions -f content=-1
141
+ ```
142
+
125
143
  Go back to step A.
126
144
 
127
145
  ### 3. Report
@@ -26,7 +26,7 @@ query($cursor: String) {
26
26
  id
27
27
  isResolved
28
28
  comments(first: 1) {
29
- nodes { body path line author { login } }
29
+ nodes { databaseId body path line author { login } }
30
30
  }
31
31
  }
32
32
  }
@@ -60,7 +60,7 @@ while :; do
60
60
  nodes {
61
61
  id
62
62
  isResolved
63
- comments(first: 1) { nodes { body path line author { login } } }
63
+ comments(first: 1) { nodes { databaseId body path line author { login } } }
64
64
  }
65
65
  }
66
66
  }
@@ -126,6 +126,23 @@ the branch (SKILL.md ยง2E-F): resolving first and pushing second means a
126
126
  failed push leaves GitHub showing the finding as handled when it isn't. Never
127
127
  resolve a blocked/skipped finding at all; reply to it and leave it open.
128
128
 
129
+ ## React to a comment (the bot's learning signal)
130
+
131
+ Reacting needs the comment's REST id, which is why `databaseId` is selected in
132
+ the thread query above. The reaction set is fixed; only eight values exist:
133
+ `+1`, `-1`, `laugh`, `confused`, `heart`, `hooray`, `rocket`, `eyes`.
134
+
135
+ ```bash
136
+ # ๐Ÿ‘€ as soon as you start working a finding
137
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<DATABASE_ID>/reactions -f content=eyes
138
+ # ๐Ÿ‘ when it was accepted and fixed, ๐Ÿ‘Ž when it was rebutted (the correction signal)
139
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<DATABASE_ID>/reactions -f content=+1
140
+ gh api --method POST repos/{owner}/{repo}/pulls/comments/<DATABASE_ID>/reactions -f content=-1
141
+ ```
142
+
143
+ React after the reply and before the resolve, so GitHub records the reason and
144
+ the disposition together. A reaction never replaces the reply.
145
+
129
146
  ## Fetch the rollup issue comment (context only, not the source of truth)
130
147
 
131
148
  Useful for the human-readable summary counts (bugs/rule-violations) in your