@silverassist/agents-toolkit 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -3
- package/bin/cli.js +6 -5
- package/package.json +1 -1
- package/src/index.js +6 -1
- package/templates/agents/AGENTS.codex.md +2 -0
- package/templates/agents/AGENTS.md +9 -5
- package/templates/shared/instructions/caching.instructions.md +37 -13
- package/templates/shared/instructions/tsdoc-standards.instructions.md +182 -0
- package/templates/shared/prompts/README.md +22 -10
- package/templates/shared/prompts/create-github-pr.prompt.md +47 -3
- package/templates/shared/prompts/finalize-github-pr.prompt.md +7 -1
- package/templates/shared/prompts/resolve-github-reviews.prompt.md +323 -0
- package/templates/shared/skills/README.md +21 -3
- package/templates/shared/skills/ai-seo-optimization/SKILL.md +11 -2
- package/templates/shared/skills/core-review/SKILL.md +251 -0
- package/templates/shared/skills/domain-driven-design/SKILL.md +8 -3
- package/templates/shared/skills/github-review-management/SKILL.md +215 -0
- package/templates/shared/skills/nextjs-caching/SKILL.md +100 -31
- package/templates/shared/skills/release-management/SKILL.md +25 -5
- package/templates/shared/skills/testing-patterns/SKILL.md +38 -0
- package/templates/shared/skills/tsdoc-standards/SKILL.md +225 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
---
|
|
2
|
+
agent: agent
|
|
3
|
+
description: Fetch, respond to, resolve, and close GitHub PR review comments (Copilot or human)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Resolve GitHub PR Reviews
|
|
7
|
+
|
|
8
|
+
Clear a pull request's review threads end-to-end: **fetch → address → reply → resolve → verify `0` unresolved**.
|
|
9
|
+
Works for both **Copilot** and **human** reviews.
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
- `gh` CLI authenticated (`gh auth status`) with `repo` scope — the GraphQL thread-resolve mutation needs it
|
|
13
|
+
- Reference: `.github/prompts/_partials/github-integration.md`
|
|
14
|
+
- Reference: `.github/prompts/_partials/git-operations.md`
|
|
15
|
+
|
|
16
|
+
## Inputs
|
|
17
|
+
- `{pr-number}` *(optional)* — target PR. Defaults to the PR for the current branch.
|
|
18
|
+
- `{repo}` *(optional)* — `owner/repo` for cross-repo review (adds `--repo` / fills the GraphQL vars).
|
|
19
|
+
|
|
20
|
+
> **Key fact:** the REST API **cannot** mark a review thread resolved — only the GraphQL
|
|
21
|
+
> `resolveReviewThread` mutation can. **GraphQL** both *lists* threads (`reviewThreads`, Step 2) and
|
|
22
|
+
> *resolves* them (Step 5.4); **REST** is used only to post *replies* (Steps 5.2–5.3).
|
|
23
|
+
|
|
24
|
+
## Steps
|
|
25
|
+
|
|
26
|
+
### 1. Locate the PR
|
|
27
|
+
|
|
28
|
+
> `{repo}` and `{pr-number}` are prompt-template placeholders substituted by the prompt engine
|
|
29
|
+
> **before the script runs**. When the user does not supply them, they stay as the literal strings
|
|
30
|
+
> `{repo}` / `{pr-number}`, so the guards below compare against those literals to detect the
|
|
31
|
+
> "not provided" case. Capture each into a shell variable once and check it with `-n` plus the
|
|
32
|
+
> literal-placeholder guard.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Copy the (possibly substituted) template values into shell vars.
|
|
36
|
+
REPO_INPUT="{repo}"
|
|
37
|
+
PR_INPUT="{pr-number}"
|
|
38
|
+
|
|
39
|
+
# Resolve owner/repo — use REPO_INPUT for cross-repo review, else fall back to the current repo.
|
|
40
|
+
if [ -n "$REPO_INPUT" ] && [ "$REPO_INPUT" != "{repo}" ]; then
|
|
41
|
+
REPO_SLUG="$REPO_INPUT" # cross-repo, e.g. owner/name
|
|
42
|
+
else
|
|
43
|
+
REPO_SLUG=$(gh repo view --json nameWithOwner -q .nameWithOwner)
|
|
44
|
+
fi
|
|
45
|
+
OWNER=${REPO_SLUG%/*}
|
|
46
|
+
REPO=${REPO_SLUG#*/}
|
|
47
|
+
|
|
48
|
+
# `gh` global flag reused by every later `gh pr` command so cross-repo works transparently.
|
|
49
|
+
GH_REPO_FLAG=(--repo "$REPO_SLUG")
|
|
50
|
+
|
|
51
|
+
# Current branch's PR (or pass an explicit number as {pr-number}).
|
|
52
|
+
if [ -n "$PR_INPUT" ] && [ "$PR_INPUT" != "{pr-number}" ]; then
|
|
53
|
+
PR="$PR_INPUT"
|
|
54
|
+
else
|
|
55
|
+
PR=$(gh pr view "${GH_REPO_FLAG[@]}" --json number -q .number)
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
echo "Reviewing $OWNER/$REPO PR #$PR"
|
|
59
|
+
gh pr view "${GH_REPO_FLAG[@]}" "$PR" --json title,state,reviewDecision,url | cat
|
|
60
|
+
|
|
61
|
+
# Make the fixes in Steps 3–4 land on the PR under review — not whatever branch happens
|
|
62
|
+
# to be checked out. Check out the PR's head branch before editing anything:
|
|
63
|
+
gh pr checkout "$PR" "${GH_REPO_FLAG[@]}"
|
|
64
|
+
echo "On branch: $(git branch --show-current)"
|
|
65
|
+
# Cross-repo ({repo} set): run this prompt from a local clone of that repo — editing,
|
|
66
|
+
# committing, and pushing need the target repo's working tree, not just API access.
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 2. Fetch unresolved review threads (paginated)
|
|
70
|
+
|
|
71
|
+
Walk the GraphQL `reviewThreads` connection with `pageInfo { endCursor hasNextPage }` — a PR
|
|
72
|
+
can have more than 100 threads, so a single `first:100` page is not enough. Capture each
|
|
73
|
+
thread's `id` (needed to resolve it) and its first comment's `databaseId`, `path`, and `line`
|
|
74
|
+
(needed to reply).
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
> /tmp/review-threads.jsonl
|
|
78
|
+
CURSOR=null
|
|
79
|
+
while : ; do
|
|
80
|
+
PAGE=$(gh api graphql -F owner="$OWNER" -F repo="$REPO" -F pr="$PR" -F after="$CURSOR" -f query='
|
|
81
|
+
query($owner:String!, $repo:String!, $pr:Int!, $after:String) {
|
|
82
|
+
repository(owner:$owner, name:$repo) {
|
|
83
|
+
pullRequest(number:$pr) {
|
|
84
|
+
reviewThreads(first:100, after:$after) {
|
|
85
|
+
pageInfo { endCursor hasNextPage }
|
|
86
|
+
nodes {
|
|
87
|
+
id
|
|
88
|
+
isResolved
|
|
89
|
+
isOutdated
|
|
90
|
+
path
|
|
91
|
+
line
|
|
92
|
+
comments(first:1) { nodes { databaseId body author { login } } }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}')
|
|
98
|
+
# Fail fast: an API/auth/network error must not be mistaken for "no threads".
|
|
99
|
+
if ! echo "$PAGE" | jq -e '.data.repository.pullRequest.reviewThreads' >/dev/null 2>&1; then
|
|
100
|
+
echo "ERROR: GraphQL request failed or returned an unexpected shape:" >&2
|
|
101
|
+
echo "$PAGE" >&2
|
|
102
|
+
exit 1
|
|
103
|
+
fi
|
|
104
|
+
echo "$PAGE" | jq -c '.data.repository.pullRequest.reviewThreads.nodes[]' >> /tmp/review-threads.jsonl
|
|
105
|
+
HAS_NEXT=$(echo "$PAGE" | jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.hasNextPage')
|
|
106
|
+
CURSOR=$(echo "$PAGE" | jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.endCursor')
|
|
107
|
+
[ "$HAS_NEXT" = "true" ] || break
|
|
108
|
+
done
|
|
109
|
+
|
|
110
|
+
# Unresolved threads only, one compact record per line.
|
|
111
|
+
jq -r '
|
|
112
|
+
select(.isResolved == false)
|
|
113
|
+
| {
|
|
114
|
+
threadId: .id,
|
|
115
|
+
commentId: .comments.nodes[0].databaseId,
|
|
116
|
+
path: .path,
|
|
117
|
+
line: .line,
|
|
118
|
+
outdated: .isOutdated,
|
|
119
|
+
author: .comments.nodes[0].author.login,
|
|
120
|
+
body: (.comments.nodes[0].body | gsub("\n"; " ") | .[0:120])
|
|
121
|
+
}' /tmp/review-threads.jsonl
|
|
122
|
+
|
|
123
|
+
# Count what is left to do (drives the final assertion in Step 6).
|
|
124
|
+
UNRESOLVED=$(jq -s '[.[] | select(.isResolved == false)] | length' /tmp/review-threads.jsonl)
|
|
125
|
+
echo "Unresolved threads: $UNRESOLVED"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 3. Apply each fix and run checks
|
|
129
|
+
|
|
130
|
+
For every unresolved thread from Step 2:
|
|
131
|
+
|
|
132
|
+
1. **Apply the fix** in code (or decide it is a false positive — record the reasoning for Step 4).
|
|
133
|
+
2. **Run the project's checks** so the reply reflects a verified change:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
npm run lint --if-present
|
|
137
|
+
npm run type-check --if-present
|
|
138
|
+
if [ -f tsconfig.json ]; then npx tsc --noEmit; fi
|
|
139
|
+
npm run test --if-present
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Then — once per batch, not per thread** — after **all** the per-thread fixes above are applied,
|
|
143
|
+
run a single **whole-repo** consistency pass (the *core review*) before committing the batch. Use
|
|
144
|
+
the **`core-review` skill** (`.agents/skills/core-review/SKILL.md`) as a dedicated read-only pass
|
|
145
|
+
(inline on Copilot/Codex; optionally a subagent on Claude Code). A fix often leaves or introduces
|
|
146
|
+
an adjacent issue (a now-stale doc line, a broken link, a table missing the new asset) that would
|
|
147
|
+
trigger yet another Copilot round. Apply everything the pass flags, re-run the checks above, and
|
|
148
|
+
only then proceed to Step 4. Running this once over the completed batch — rather than per thread —
|
|
149
|
+
keeps the (whole-repo) review cost bounded.
|
|
150
|
+
|
|
151
|
+
### 4. Commit and push fixes (before replying)
|
|
152
|
+
|
|
153
|
+
Reply bodies reference the fixing commit SHA, so **commit and push first** — otherwise the SHA
|
|
154
|
+
does not exist on the remote branch yet and the reply link is dead.
|
|
155
|
+
|
|
156
|
+
> Run the whole-repo **core review** from Step 3 *before* this commit — pushing an adjacent,
|
|
157
|
+
> unfixed issue starts a fresh Copilot round and defeats the purpose of resolving in batches.
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Stage only the files you changed for these fixes. Avoid `git add -A` — Step 1 does not
|
|
161
|
+
# require a clean worktree, so it could sweep in unrelated pre-existing changes.
|
|
162
|
+
git add <files you edited>
|
|
163
|
+
if git diff --cached --quiet; then
|
|
164
|
+
# Nothing staged — every finding was a false positive. A bare `git commit` would fail,
|
|
165
|
+
# and `$SHA` would wrongly point at an unrelated existing HEAD. Leave `$SHA` empty and
|
|
166
|
+
# reply to those threads in Step 5 with reasoning only (never "Fixed in <sha>").
|
|
167
|
+
SHA=""
|
|
168
|
+
echo "No staged changes — skipping the fix commit; Step 5 replies with rationale only."
|
|
169
|
+
else
|
|
170
|
+
git commit -m "fix: Address PR #$PR review comments"
|
|
171
|
+
if ! git push; then
|
|
172
|
+
echo "ERROR: git push failed. Do not proceed to Step 5 — \$SHA is not on the remote yet." >&2
|
|
173
|
+
echo "Diagnose the failure before retrying:" >&2
|
|
174
|
+
echo " - Non-fast-forward: run 'git pull --rebase' then 'git push' again." >&2
|
|
175
|
+
echo " - Branch protection / required status checks: fix locally and re-run this step," >&2
|
|
176
|
+
echo " or contact a repo admin if the branch is protected against your role." >&2
|
|
177
|
+
echo " - Auth: run 'gh auth status' and re-authenticate with 'repo' scope if needed." >&2
|
|
178
|
+
exit 1
|
|
179
|
+
fi
|
|
180
|
+
SHA=$(git rev-parse HEAD)
|
|
181
|
+
echo "Fix commit: $SHA"
|
|
182
|
+
fi
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
If a single commit already covers all fixes, capture that SHA and skip the commit step; the point
|
|
186
|
+
is that `$SHA` must be **pushed** before Step 5 references it. **Do not advance to Step 5 unless
|
|
187
|
+
the push succeeded** — every reply body links to `$SHA` on the remote.
|
|
188
|
+
|
|
189
|
+
### 5. Reply and resolve each thread
|
|
190
|
+
|
|
191
|
+
For each unresolved thread from Step 2, run the following sub-procedure **in order**. `$COMMENT_ID`
|
|
192
|
+
is the first comment's `databaseId`; `$THREAD_ID` is the thread `id`. Steps 5.1–5.3 pick exactly
|
|
193
|
+
one reply path; Step 5.4 **always** runs afterward regardless of which reply path was taken.
|
|
194
|
+
|
|
195
|
+
#### 5.1 — If `$COMMENT_ID` is null: PR-level acknowledgement, then go to 5.4
|
|
196
|
+
|
|
197
|
+
Copilot low-confidence / suppressed notes have no inline comment id (`databaseId` is `null`) and
|
|
198
|
+
cannot be replied to per-thread. Acknowledge them once with a PR-level comment, then skip to 5.4
|
|
199
|
+
to resolve the thread:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
if [ -z "$COMMENT_ID" ] || [ "$COMMENT_ID" = "null" ]; then
|
|
203
|
+
gh pr comment "${GH_REPO_FLAG[@]}" "$PR" --body "Addressed Copilot's low-confidence suggestions: <summary>."
|
|
204
|
+
# Skip 5.2 and 5.3; proceed directly to 5.4 for this thread.
|
|
205
|
+
fi
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### 5.2 — Otherwise: attempt the direct replies endpoint
|
|
209
|
+
|
|
210
|
+
If the finding was a **false positive** (no fix commit — `$SHA` is empty), reply with your
|
|
211
|
+
reasoning instead of a SHA, e.g. `-f body="Not applicable — <why>."`. Otherwise reference the
|
|
212
|
+
fix commit:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
gh api "repos/$OWNER/$REPO/pulls/$PR/comments/$COMMENT_ID/replies" \
|
|
216
|
+
-f body="Fixed in $SHA: <what changed>. Thanks!"
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
#### 5.3 — Only if 5.2 returned HTTP 404: fall back to `in_reply_to`
|
|
220
|
+
|
|
221
|
+
Some threads reject the direct replies endpoint (404). Only in that case, post a new review
|
|
222
|
+
comment linked to the original via `in_reply_to`:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
gh api "repos/$OWNER/$REPO/pulls/$PR/comments" \
|
|
226
|
+
-f body="Fixed in $SHA: <what changed>." \
|
|
227
|
+
-F in_reply_to="$COMMENT_ID"
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Do **not** run 5.3 unless 5.2 failed with 404; running both duplicates the reply.
|
|
231
|
+
|
|
232
|
+
#### 5.4 — Resolve the thread via the GraphQL mutation (REST cannot)
|
|
233
|
+
|
|
234
|
+
If you address threads one at a time, resolve each one here after replying (from 5.1, 5.2, or 5.3).
|
|
235
|
+
Prefer to resolve them all at once? Skip this per-thread call and use the batch loop in 5.5 instead —
|
|
236
|
+
use **either** 5.4 **or** 5.5, never both, or every mutation runs twice.
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
gh api graphql -f id="$THREAD_ID" -f query='
|
|
240
|
+
mutation($id:ID!) {
|
|
241
|
+
resolveReviewThread(input:{threadId:$id}) {
|
|
242
|
+
thread { isResolved }
|
|
243
|
+
}
|
|
244
|
+
}'
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### 5.5 — Alternative: batch-resolve every addressed thread at once
|
|
248
|
+
|
|
249
|
+
Instead of the per-thread call in 5.4, resolve everything in one loop once all replies are posted
|
|
250
|
+
(use **either** 5.4 per thread **or** this batch loop, not both). Check the mutation response inside
|
|
251
|
+
the loop — a missing `repo` scope on the token succeeds at listing but fails at resolving, and
|
|
252
|
+
without this check the failure is silent and Step 6 reports leftover threads with no explanation.
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
jq -r 'select(.isResolved == false) | .id' /tmp/review-threads.jsonl | while read -r THREAD_ID; do
|
|
256
|
+
RESULT=$(gh api graphql -f id="$THREAD_ID" -f query='mutation($id:ID!){ resolveReviewThread(input:{threadId:$id}){ thread { isResolved } } }')
|
|
257
|
+
if [ "$(echo "$RESULT" | jq -r '.data.resolveReviewThread.thread.isResolved')" != "true" ]; then
|
|
258
|
+
echo "ERROR: failed to resolve $THREAD_ID: $RESULT" >&2
|
|
259
|
+
exit 1
|
|
260
|
+
fi
|
|
261
|
+
done
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
> **`isOutdated` threads** — a thread whose code moved is marked `isOutdated` but stays
|
|
265
|
+
> **unresolved**. Resolve it the same way once the concern is handled; it will not clear itself.
|
|
266
|
+
|
|
267
|
+
### 6. Close the loop
|
|
268
|
+
|
|
269
|
+
Re-query with the same pagination pattern and assert **zero** unresolved threads. Exit non-zero
|
|
270
|
+
when threads remain so this step can gate CI or a script.
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
> /tmp/review-threads-remaining.jsonl
|
|
274
|
+
CURSOR=null
|
|
275
|
+
while : ; do
|
|
276
|
+
PAGE=$(gh api graphql -F owner="$OWNER" -F repo="$REPO" -F pr="$PR" -F after="$CURSOR" -f query='
|
|
277
|
+
query($owner:String!, $repo:String!, $pr:Int!, $after:String) {
|
|
278
|
+
repository(owner:$owner, name:$repo) {
|
|
279
|
+
pullRequest(number:$pr) {
|
|
280
|
+
reviewThreads(first:100, after:$after) {
|
|
281
|
+
pageInfo { endCursor hasNextPage }
|
|
282
|
+
nodes { isResolved }
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}')
|
|
287
|
+
# Fail fast: an API/auth/network error must not be mistaken for "0 remaining".
|
|
288
|
+
if ! echo "$PAGE" | jq -e '.data.repository.pullRequest.reviewThreads' >/dev/null 2>&1; then
|
|
289
|
+
echo "ERROR: GraphQL request failed or returned an unexpected shape:" >&2
|
|
290
|
+
echo "$PAGE" >&2
|
|
291
|
+
exit 1
|
|
292
|
+
fi
|
|
293
|
+
echo "$PAGE" | jq -c '.data.repository.pullRequest.reviewThreads.nodes[]' >> /tmp/review-threads-remaining.jsonl
|
|
294
|
+
HAS_NEXT=$(echo "$PAGE" | jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.hasNextPage')
|
|
295
|
+
CURSOR=$(echo "$PAGE" | jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.endCursor')
|
|
296
|
+
[ "$HAS_NEXT" = "true" ] || break
|
|
297
|
+
done
|
|
298
|
+
|
|
299
|
+
REMAINING=$(jq -s '[.[] | select(.isResolved == false)] | length' /tmp/review-threads-remaining.jsonl)
|
|
300
|
+
echo "Remaining unresolved threads: $REMAINING"
|
|
301
|
+
if [ "$REMAINING" -eq 0 ]; then
|
|
302
|
+
echo "✅ All review threads resolved"
|
|
303
|
+
else
|
|
304
|
+
echo "❌ $REMAINING thread(s) still open"
|
|
305
|
+
exit 1
|
|
306
|
+
fi
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Then summarize:
|
|
310
|
+
- Threads addressed and how (fix commit SHA per finding).
|
|
311
|
+
- Any threads intentionally left with a reply explaining a false positive (resolve those too).
|
|
312
|
+
- Commit(s) pushed and the resulting `reviewDecision`.
|
|
313
|
+
|
|
314
|
+
## Notes & edge cases
|
|
315
|
+
|
|
316
|
+
- **Per-commit review rounds** — Copilot re-reviews after each push. New threads can appear;
|
|
317
|
+
re-run Steps 2–6 until Step 6 reports `0`. Request a fresh review if needed:
|
|
318
|
+
`gh pr comment "${GH_REPO_FLAG[@]}" "$PR" --body "@copilot review"` (or re-request a human reviewer).
|
|
319
|
+
- **Review submissions vs comments vs threads** — a *review* (`gh pr review`) is the top-level
|
|
320
|
+
approval/verdict; *review comments* are inline; a *review thread* groups an inline comment with
|
|
321
|
+
its replies and carries the `isResolved` flag. Only threads are resolvable.
|
|
322
|
+
- **Auth** — resolving needs the GraphQL API with `repo` scope; a token missing it fails the
|
|
323
|
+
mutation with a permissions error even though listing works.
|
|
@@ -19,10 +19,16 @@ skills directory contains symlinks to it (single source of truth):
|
|
|
19
19
|
│ └── SKILL.md
|
|
20
20
|
├── component-architecture/
|
|
21
21
|
│ └── SKILL.md
|
|
22
|
+
├── core-review/
|
|
23
|
+
│ └── SKILL.md
|
|
22
24
|
├── create-component/
|
|
23
25
|
│ └── SKILL.md
|
|
24
26
|
├── domain-driven-design/
|
|
25
27
|
│ └── SKILL.md
|
|
28
|
+
├── github-review-management/
|
|
29
|
+
│ └── SKILL.md
|
|
30
|
+
├── nextjs-caching/
|
|
31
|
+
│ └── SKILL.md
|
|
26
32
|
├── plugin-creation/
|
|
27
33
|
│ └── SKILL.md
|
|
28
34
|
├── quality-checks/
|
|
@@ -31,7 +37,9 @@ skills directory contains symlinks to it (single source of truth):
|
|
|
31
37
|
│ └── SKILL.md
|
|
32
38
|
├── testing/
|
|
33
39
|
│ └── SKILL.md
|
|
34
|
-
|
|
40
|
+
├── testing-patterns/
|
|
41
|
+
│ └── SKILL.md
|
|
42
|
+
└── tsdoc-standards/
|
|
35
43
|
└── SKILL.md
|
|
36
44
|
|
|
37
45
|
.github/skills/ → symlinks to ../../.agents/skills/* (Copilot, Codex)
|
|
@@ -54,9 +62,19 @@ description: When to use this skill. Agents use this to decide relevance.
|
|
|
54
62
|
|
|
55
63
|
| Skill | Description |
|
|
56
64
|
|-------|-------------|
|
|
65
|
+
| `ai-seo-optimization` | Optimize sites for Google generative AI features, agent-friendly HTML, E-E-A-T signals |
|
|
57
66
|
| `component-architecture` | React component patterns, folder structure, naming conventions |
|
|
67
|
+
| `core-review` | Whole-repo pre-review (before a PR / before pushing review fixes) run as a read-only pass — inline on Copilot/Codex, optionally a subagent on Claude Code — to preempt Copilot iterations |
|
|
68
|
+
| `create-component` | Scaffold a new component in a Silver Assist WordPress plugin (LoadableInterface pattern) |
|
|
58
69
|
| `domain-driven-design` | DDD principles, domain organization, barrel exports |
|
|
70
|
+
| `github-review-management` | Fetch, reply to, resolve & close GitHub PR review threads via `gh` CLI + GraphQL |
|
|
71
|
+
| `nextjs-caching` | Next.js caching strategy: read-vs-mutation fetch, ISR tiers, CDN invalidation, dynamic-render diagnosis |
|
|
72
|
+
| `plugin-creation` | Scaffold a new Silver Assist WordPress plugin from scratch (PSR-4, LoadableInterface, CI/CD) |
|
|
73
|
+
| `quality-checks` | Run PHPCS, PHPStan (level 8), and PHPUnit for Silver Assist WordPress plugins |
|
|
74
|
+
| `release-management` | Create and manage releases for Silver Assist WordPress plugins (unified build + GH Actions) |
|
|
75
|
+
| `testing` | Write and run PHPUnit tests for Silver Assist WordPress plugins (WP_UnitTestCase) |
|
|
59
76
|
| `testing-patterns` | Jest + RTL patterns for Next.js 15 and Server Actions |
|
|
77
|
+
| `tsdoc-standards` | Write & enforce TSDoc (not JSDoc): allowed tags, forbidden JSDoc patterns, templates |
|
|
60
78
|
|
|
61
79
|
## Usage
|
|
62
80
|
|
|
@@ -71,5 +89,5 @@ Skills are automatically picked up by agents when relevant to your question. You
|
|
|
71
89
|
1. Create a folder: `.agents/skills/your-skill-name/` (canonical store)
|
|
72
90
|
2. Create `SKILL.md` with frontmatter
|
|
73
91
|
3. Run `npx @silverassist/agents-toolkit install --skills-only` to symlink it into `.github/skills/` and `.claude/skills/`
|
|
74
|
-
|
|
75
|
-
|
|
92
|
+
4. Document patterns, examples, and conventions
|
|
93
|
+
5. Include ✅ CORRECT and ❌ INCORRECT examples
|
|
@@ -7,8 +7,11 @@ description: Optimize websites for Google's generative AI features and browser a
|
|
|
7
7
|
|
|
8
8
|
Comprehensive guide for optimizing Next.js sites for Google's generative AI features (AI Overviews, AI Mode) and emerging browser agent interactions.
|
|
9
9
|
|
|
10
|
-
> **
|
|
11
|
-
|
|
10
|
+
> **Framework note**: Although examples use Next.js conventions (e.g., `generateMetadata`), all checklist items apply to any web framework. For non-Next.js sites, substitute framework-equivalent SSR and metadata APIs.
|
|
11
|
+
|
|
12
|
+
> **Source**: [Google AI Optimization Guide](https://developers.google.com/search/docs/fundamentals/ai-optimization-guide)
|
|
13
|
+
> **Companion**: [Build Agent-Friendly Websites](https://web.dev/articles/ai-agent-site-ux)
|
|
14
|
+
> **Verify current guidance**: These references reflect guidance as of the skill's authoring date. Always verify current Google documentation before advising clients.
|
|
12
15
|
|
|
13
16
|
---
|
|
14
17
|
|
|
@@ -321,6 +324,12 @@ These are explicitly confirmed as **unnecessary or harmful** by Google:
|
|
|
321
324
|
|
|
322
325
|
## 9. Audit Workflow
|
|
323
326
|
|
|
327
|
+
Before beginning the audit, confirm you have access to: (1) the site URL or representative page HTML, (2) Google Search Console data if available, and (3) the page types to audit (home, landing, blog, etc.).
|
|
328
|
+
|
|
329
|
+
If no site URL, HTML, or page content is provided, respond: "To perform this audit, please share the site URL, representative page HTML, or specific components you want evaluated."
|
|
330
|
+
|
|
331
|
+
Representative HTML alone cannot support checks that need live signals — **index status, live crawl/HTTP accessibility, Core Web Vitals field data, and Search Console signals**. When the corresponding source is not provided (no live URL, no CrUX/PageSpeed access, no Search Console), report those items as **"Not verifiable — requires \<live URL | CrUX/PSI | Search Console\>"** rather than inferring a pass/fail from static markup.
|
|
332
|
+
|
|
324
333
|
When asked to audit a site for AI optimization, follow this order:
|
|
325
334
|
|
|
326
335
|
1. **Technical baseline** — Verify indexing, SSR, canonical tags, Core Web Vitals
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: core-review
|
|
3
|
+
description: Run a thorough, whole-repo consistency review before opening a PR or before pushing fixes in response to a reviewer — as a dedicated read-only pass (inline on Copilot/Codex; optionally a subagent on Claude Code) — to preempt Copilot/reviewer iterations. Use when about to push a branch for review or to push a batch of review fixes.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Silver Assist — Core Review (Pre-Review)
|
|
7
|
+
|
|
8
|
+
A **pre-emptive, whole-repo consistency review** that runs *before* a reviewer (Copilot or a
|
|
9
|
+
human) ever sees the branch. It catches the classes of issues that trigger multi-round review
|
|
10
|
+
loops — doc↔code drift, invalid code examples, broken links, stale indexes — so they are fixed
|
|
11
|
+
in the first push instead of round 5.
|
|
12
|
+
|
|
13
|
+
This skill is the reviewer's knowledge; the **action** (run the review, apply the findings) is
|
|
14
|
+
invoked as a step from `create-github-pr`, `resolve-github-reviews`, and `finalize-github-pr`.
|
|
15
|
+
|
|
16
|
+
## When to Use
|
|
17
|
+
|
|
18
|
+
Run this review at **two integration points**:
|
|
19
|
+
|
|
20
|
+
1. **Pre-PR** — after the code is written and local checks pass, **before** `create-github-pr`
|
|
21
|
+
pushes the branch and opens the PR.
|
|
22
|
+
2. **Pre-push during review resolution** — inside `resolve-github-reviews` / `finalize-github-pr`,
|
|
23
|
+
**before** pushing each batch of fixes, so a fix does not leave (or introduce) an adjacent
|
|
24
|
+
issue that triggers yet another reviewer round.
|
|
25
|
+
|
|
26
|
+
## Why whole-repo, not just the diff
|
|
27
|
+
|
|
28
|
+
Copilot re-reviews **entire files**, not just your hunks — and each push opens a fresh round.
|
|
29
|
+
In recent work the rounds went `18 → 2 → 3 → 1 → 9 → 3 → 1 → 1 …`: every push surfaced new,
|
|
30
|
+
mostly *valid* findings in code the diff only brushed against (a doc line that no longer matches
|
|
31
|
+
the changed code, a table missing the asset you just added, a link that now resolves elsewhere).
|
|
32
|
+
A review scoped to the whole repo — or at least every file that imports, re-exports, documents,
|
|
33
|
+
or enumerates the changed symbol or asset, plus every index/README that lists its siblings —
|
|
34
|
+
catches those before the reviewer does. Reviewing only the diff reproduces exactly the slow loop
|
|
35
|
+
this flow exists to avoid.
|
|
36
|
+
|
|
37
|
+
## How to run it (portable across agents)
|
|
38
|
+
|
|
39
|
+
Run the review as a **dedicated, read-only pass**: it inspects and reports; it does **not** edit.
|
|
40
|
+
The caller applies the fixes, so the review stays unbiased by the intent behind the change. The
|
|
41
|
+
pass works the same on every agent — **Copilot** (the primary reviewer to preempt), **Codex**,
|
|
42
|
+
and **Claude Code**; only the *mechanism* differs, and **subagents are a Claude-Code-only
|
|
43
|
+
optimization, never a requirement**:
|
|
44
|
+
|
|
45
|
+
- **GitHub Copilot** — no subagents; run the checklist **inline as a distinct pass** before
|
|
46
|
+
pushing (not folded into the edit under review), over the **whole repository — not just the
|
|
47
|
+
diff**. Copilot's built-in code review can help on the diff, but only this whole-repo pass
|
|
48
|
+
covers the drift that triggers new review rounds.
|
|
49
|
+
- **Codex** — no subagents either; the same **inline whole-repo pass**, producing the same
|
|
50
|
+
prioritized findings list.
|
|
51
|
+
- **Claude Code** — *optionally* delegate the pass to a read-only **subagent** (`Explore` or
|
|
52
|
+
`general-purpose`) with the brief: "Review this whole repository against the core-review
|
|
53
|
+
checklist; report findings as `severity | file:line | problem | suggested fix`; do not edit any
|
|
54
|
+
files." Relay its findings back to the main flow. Running it inline works too.
|
|
55
|
+
|
|
56
|
+
Whichever agent, the contract is identical: **read-only in, prioritized findings out**, then the
|
|
57
|
+
caller fixes and re-runs until clean.
|
|
58
|
+
|
|
59
|
+
## The review checklist
|
|
60
|
+
|
|
61
|
+
Each item lists what to look for and a concrete ❌→✅ example. These are the failure modes that
|
|
62
|
+
actually caused review rounds.
|
|
63
|
+
|
|
64
|
+
### 1. Docs ↔ code consistency
|
|
65
|
+
|
|
66
|
+
- Docs claiming behavior the code does not have.
|
|
67
|
+
- A symbol/asset categorized differently across files (e.g. a metadata array vs a README table row).
|
|
68
|
+
- An instruction that contradicts the actual code convention (barrel vs internal import path;
|
|
69
|
+
an auto-merge `if:` guard that differs from the shipped workflow).
|
|
70
|
+
- A table/tree/index entry for a file that does not exist in the repo (or a file missing from it).
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
❌ "The REST API lists review threads and marks them resolved."
|
|
74
|
+
✅ "GraphQL lists review threads (reviewThreads) and resolves them (resolveReviewThread);
|
|
75
|
+
REST only posts replies." (matches what the code actually calls)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 2. Code-example validity
|
|
79
|
+
|
|
80
|
+
Every "correct" snippet must actually compile and match the standard it illustrates.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// ❌ Non-void function with an empty body — does not compile
|
|
84
|
+
export function formatDate(dateString: string): string {}
|
|
85
|
+
|
|
86
|
+
// ✅ Real body that returns the declared type
|
|
87
|
+
export function formatDate(dateString: string): string {
|
|
88
|
+
return new Date(dateString).toLocaleDateString("en-US", { dateStyle: "long" });
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- No JSDoc patterns inside a TSDoc example (`@param {string} x`, `@param props.child`, `{type}` braces).
|
|
93
|
+
- No syntactically invalid inline snippets (e.g. `foo(a: 1)` where an object was meant: `foo({ a: 1 })`).
|
|
94
|
+
- A JSX component used as an example must return an element, not infer `void`.
|
|
95
|
+
|
|
96
|
+
### 3. Links & references
|
|
97
|
+
|
|
98
|
+
- Broken relative links — count the `../` hops from the file's real location.
|
|
99
|
+
|
|
100
|
+
```text
|
|
101
|
+
❌ From .github/instructions/, linking a test as ../commands/__tests__/init.test.ts
|
|
102
|
+
✅ ../../src/commands/__tests__/init.test.ts (correct number of ../ hops)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
- Outdated version/path references (a GitHub Action pinned `@v4` when the repo standard is `@v7`;
|
|
106
|
+
a deep module path where the repo convention is a barrel import such as `@/transformer`).
|
|
107
|
+
|
|
108
|
+
### 4. Markdown hygiene
|
|
109
|
+
|
|
110
|
+
- Every fenced code block has a language tag (` ```bash `, ` ```typescript `, ` ```text `).
|
|
111
|
+
- Nested backtick spans render correctly (use longer outer fences when a snippet contains backticks).
|
|
112
|
+
- No stray empty bullets or blank list items in templates — use an HTML comment placeholder instead.
|
|
113
|
+
|
|
114
|
+
### 5. Inventories / tables completeness
|
|
115
|
+
|
|
116
|
+
README instructions/skills/prompts tables, `AGENTS.md` indexes, directory trees, and any
|
|
117
|
+
"N total" counts must list **all** shipped assets — or be explicitly marked truncated with a total.
|
|
118
|
+
When you add or rename an asset, grep for every index that enumerates its siblings and update each.
|
|
119
|
+
|
|
120
|
+
### 6. Shell / script robustness (for prompt & skill snippets)
|
|
121
|
+
|
|
122
|
+
- Stage specific paths, not `git add -A`, so the commit does not sweep unrelated pre-existing changes.
|
|
123
|
+
- Paginate past the first 100 items (walk `pageInfo { endCursor hasNextPage }`), don't stop at page one.
|
|
124
|
+
- A failed API call must **fail fast**, not be treated as an empty result.
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# ❌ An auth/network failure looks identical to "no threads" — the assertion passes on error
|
|
128
|
+
COUNT=$(gh api graphql -f query='...' | jq '.data.repository.pullRequest.reviewThreads.nodes | length')
|
|
129
|
+
|
|
130
|
+
# ✅ Fail fast: distinguish an error shape from a genuine empty result before counting
|
|
131
|
+
if ! echo "$PAGE" | jq -e '.data.repository.pullRequest.reviewThreads' >/dev/null 2>&1; then
|
|
132
|
+
echo "ERROR: GraphQL request failed or returned an unexpected shape" >&2
|
|
133
|
+
exit 1
|
|
134
|
+
fi
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- An "assertion" whose failure branch still exits `0` is not an assertion — exit non-zero on failure.
|
|
138
|
+
- Handle the "all findings were false positives → nothing to commit" case so a referenced `$SHA`
|
|
139
|
+
is not an unrelated existing HEAD (guard with `git diff --cached --quiet`).
|
|
140
|
+
- Cross-platform test assertions: don't hard-code the `/` path separator (`[\\/]` in regexes),
|
|
141
|
+
and include `stderr` in failure messages so CI shows why a spawned CLI exited non-zero.
|
|
142
|
+
|
|
143
|
+
### 7. Repo health
|
|
144
|
+
|
|
145
|
+
- `package-lock.json` in sync — after a dependency bump, `npm ci` must exit `0`
|
|
146
|
+
(a drifted lockfile fails with `Missing … from lock file`). Regenerate with
|
|
147
|
+
`npm install --package-lock-only` and verify `npm ci`.
|
|
148
|
+
- CI matrix / workflow config sanity (a `workflow_run` trigger names a workflow whose `name:`
|
|
149
|
+
actually exists; `on:` events match intent; least-privilege `permissions:`).
|
|
150
|
+
|
|
151
|
+
## Highest-recall patterns (from real review rounds)
|
|
152
|
+
|
|
153
|
+
A few patterns account for **most** reviewer findings — and they are exactly the ones a
|
|
154
|
+
diff-focused read misses, because the defect lives in a file the change only touches the
|
|
155
|
+
*meaning* of. **Check these first.** (Percentages below are from an actual review round of this
|
|
156
|
+
skill's own PR, where a reviewer found 10 issues the initial self-review missed.)
|
|
157
|
+
|
|
158
|
+
### P1 — Propagate a reframe to *every* description of the concept (highest yield)
|
|
159
|
+
|
|
160
|
+
When you rename or reframe anything (a term, a default, a capability), the change must reach
|
|
161
|
+
**every surface that describes it** — not only the canonical/body text, but each one-line
|
|
162
|
+
description: README tables, per-agent asset maps (`AGENTS.md`, `AGENTS.codex.md`), directory
|
|
163
|
+
trees, and the CHANGELOG summary. **A concept described two ways is a guaranteed finding** — half
|
|
164
|
+
the findings in the reference round were this single class (the body was reframed; the index rows
|
|
165
|
+
still advertised the old wording).
|
|
166
|
+
|
|
167
|
+
**Technique — the reframe sweep:** after any rename/reframe, grep the whole repo for the *old*
|
|
168
|
+
term and each synonym, then reconcile every hit.
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# e.g. after reframing "subagent" → "read-only pass", hunt every lingering description
|
|
172
|
+
grep -rn "subagent" . --include="*.md"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### P2 — Keep the *mechanism* branch-specific, never the *scope/contract*
|
|
176
|
+
|
|
177
|
+
When guidance branches per agent / platform / environment, only the **mechanism** may differ; the
|
|
178
|
+
**scope or contract** must stay identical across every branch.
|
|
179
|
+
|
|
180
|
+
```text
|
|
181
|
+
❌ "Copilot runs it inline over the changed files and their neighbors." (silently narrowed scope)
|
|
182
|
+
✅ "Copilot runs it inline over the whole repository." (mechanism differs, scope constant)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### P3 — "We updated X" must match the diff
|
|
186
|
+
|
|
187
|
+
Every CHANGELOG / PR / summary claim that an artifact was changed must correspond to a file
|
|
188
|
+
**actually in the diff**, and the named target must be a place that could plausibly hold that
|
|
189
|
+
content.
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
❌ CHANGELOG: "the prompts README now lists the new skill" (that file is not in the diff, and a
|
|
193
|
+
prompts index would not list skills anyway)
|
|
194
|
+
✅ Record only the indexes actually updated (here: the skills README + the asset maps).
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### P4 — When you touch an inventory, cross-check *every* sibling
|
|
198
|
+
|
|
199
|
+
Editing a tree/table to add your entry re-presents the whole inventory as complete — so a
|
|
200
|
+
**pre-existing** omission now reads as your bug. Enumerate what exists on disk and reconcile.
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
# every skill directory here must appear in the README tree AND the skills table
|
|
204
|
+
# (list directories only — a plain `ls` would also print the skills README.md)
|
|
205
|
+
ls -d templates/shared/skills/*/
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### P5 — A generated procedure that makes fixes must commit before it pushes
|
|
209
|
+
|
|
210
|
+
Any documented step that can create fixes and then pushes must **explicitly commit** them and
|
|
211
|
+
confirm a clean worktree (`git status`) first — otherwise the fixes are silently omitted from the
|
|
212
|
+
push, and a referenced `$SHA` points at the wrong commit.
|
|
213
|
+
|
|
214
|
+
## Output contract
|
|
215
|
+
|
|
216
|
+
Report findings as a **prioritized list**, most severe first, one row each:
|
|
217
|
+
|
|
218
|
+
```text
|
|
219
|
+
severity | file:line | problem | suggested fix
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
- **severity** — `critical` (compile/CI break, wrong behavior claim), `warning` (stale doc,
|
|
223
|
+
broken link, missing index entry), `nit` (wording, formatting).
|
|
224
|
+
- **file:line** — a clickable anchor so the fix is one jump away.
|
|
225
|
+
- **suggested fix** — concrete enough to apply directly.
|
|
226
|
+
|
|
227
|
+
Empty output ("no findings") is a valid, good result — say so explicitly rather than inventing nits.
|
|
228
|
+
|
|
229
|
+
## Acting on findings & convergence
|
|
230
|
+
|
|
231
|
+
These steps are performed by the **caller** (the agent flow that invoked this skill), not by the
|
|
232
|
+
read-only review pass itself — the pass only inspects and reports.
|
|
233
|
+
|
|
234
|
+
1. The caller applies every `critical` and `warning`; applies `nit`s unless there is a reason not to.
|
|
235
|
+
2. The caller re-runs the project's checks (`lint`, `type-check`, `tsc --noEmit`, `test`, `build` — whichever exist).
|
|
236
|
+
3. The caller re-runs the review over the whole repo. **Loop until the pass reports zero findings
|
|
237
|
+
*within the change's blast radius***, *then* push. Pre-existing issues outside that scope are
|
|
238
|
+
noted (see "What NOT to flag" below) but do not block convergence.
|
|
239
|
+
|
|
240
|
+
Because these repos guide agents, an inaccurate doc induces downstream errors — so it is worth
|
|
241
|
+
iterating N times to reach an optimal, consistent result rather than stopping at the first
|
|
242
|
+
"good enough" pass. Convergence here means the review pass finds nothing new, not merely
|
|
243
|
+
that CI is green.
|
|
244
|
+
|
|
245
|
+
## What NOT to flag (avoid false positives)
|
|
246
|
+
|
|
247
|
+
- Intentional, documented deviations (a snippet explicitly labeled "❌ INCORRECT" is *meant* to be wrong).
|
|
248
|
+
- Style preferences the repo has not adopted — match the surrounding code, don't impose new conventions.
|
|
249
|
+
- Truncated inventories that already declare a total ("… 13 skills total").
|
|
250
|
+
- Pre-existing, unrelated issues outside the change's blast radius — note them separately, do not
|
|
251
|
+
block the push on them.
|