@bradygaster/squad-cli 0.9.3-insider.1 → 0.9.4

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 (149) hide show
  1. package/README.md +33 -0
  2. package/dist/cli/commands/cast.d.ts.map +1 -1
  3. package/dist/cli/commands/cast.js +9 -2
  4. package/dist/cli/commands/cast.js.map +1 -1
  5. package/dist/cli/commands/externalize.d.ts +27 -0
  6. package/dist/cli/commands/externalize.d.ts.map +1 -0
  7. package/dist/cli/commands/externalize.js +209 -0
  8. package/dist/cli/commands/externalize.js.map +1 -0
  9. package/dist/cli/commands/loop.d.ts +6 -1
  10. package/dist/cli/commands/loop.d.ts.map +1 -1
  11. package/dist/cli/commands/loop.js +13 -13
  12. package/dist/cli/commands/loop.js.map +1 -1
  13. package/dist/cli/commands/migrate.js +2 -2
  14. package/dist/cli/commands/migrate.js.map +1 -1
  15. package/dist/cli/commands/plugin.d.ts.map +1 -1
  16. package/dist/cli/commands/plugin.js +2 -1
  17. package/dist/cli/commands/plugin.js.map +1 -1
  18. package/dist/cli/commands/rc.js +2 -2
  19. package/dist/cli/commands/rc.js.map +1 -1
  20. package/dist/cli/commands/skill.d.ts +31 -0
  21. package/dist/cli/commands/skill.d.ts.map +1 -0
  22. package/dist/cli/commands/skill.js +497 -0
  23. package/dist/cli/commands/skill.js.map +1 -0
  24. package/dist/cli/commands/start.d.ts.map +1 -1
  25. package/dist/cli/commands/start.js +31 -5
  26. package/dist/cli/commands/start.js.map +1 -1
  27. package/dist/cli/commands/watch/agent-spawn.d.ts +62 -0
  28. package/dist/cli/commands/watch/agent-spawn.d.ts.map +1 -0
  29. package/dist/cli/commands/watch/agent-spawn.js +127 -0
  30. package/dist/cli/commands/watch/agent-spawn.js.map +1 -0
  31. package/dist/cli/commands/watch/capabilities/decision-hygiene.js +3 -3
  32. package/dist/cli/commands/watch/capabilities/decision-hygiene.js.map +1 -1
  33. package/dist/cli/commands/watch/capabilities/execute.d.ts.map +1 -1
  34. package/dist/cli/commands/watch/capabilities/execute.js +15 -5
  35. package/dist/cli/commands/watch/capabilities/execute.js.map +1 -1
  36. package/dist/cli/commands/watch/capabilities/monitor-email.js +3 -3
  37. package/dist/cli/commands/watch/capabilities/monitor-email.js.map +1 -1
  38. package/dist/cli/commands/watch/capabilities/monitor-teams.js +3 -3
  39. package/dist/cli/commands/watch/capabilities/monitor-teams.js.map +1 -1
  40. package/dist/cli/commands/watch/capabilities/retro.js +3 -3
  41. package/dist/cli/commands/watch/capabilities/retro.js.map +1 -1
  42. package/dist/cli/commands/watch/capabilities/wave-dispatch.js +3 -3
  43. package/dist/cli/commands/watch/capabilities/wave-dispatch.js.map +1 -1
  44. package/dist/cli/commands/watch/config.d.ts +10 -8
  45. package/dist/cli/commands/watch/config.d.ts.map +1 -1
  46. package/dist/cli/commands/watch/config.js +27 -5
  47. package/dist/cli/commands/watch/config.js.map +1 -1
  48. package/dist/cli/commands/watch/external-loader.d.ts +14 -0
  49. package/dist/cli/commands/watch/external-loader.d.ts.map +1 -0
  50. package/dist/cli/commands/watch/external-loader.js +85 -0
  51. package/dist/cli/commands/watch/external-loader.js.map +1 -0
  52. package/dist/cli/commands/watch/health.js +10 -9
  53. package/dist/cli/commands/watch/health.js.map +1 -1
  54. package/dist/cli/commands/watch/index.d.ts +10 -0
  55. package/dist/cli/commands/watch/index.d.ts.map +1 -1
  56. package/dist/cli/commands/watch/index.js +53 -7
  57. package/dist/cli/commands/watch/index.js.map +1 -1
  58. package/dist/cli/commands/watch/pid-tracker.d.ts +35 -0
  59. package/dist/cli/commands/watch/pid-tracker.d.ts.map +1 -0
  60. package/dist/cli/commands/watch/pid-tracker.js +127 -0
  61. package/dist/cli/commands/watch/pid-tracker.js.map +1 -0
  62. package/dist/cli/commands/watch/types.d.ts +5 -0
  63. package/dist/cli/commands/watch/types.d.ts.map +1 -1
  64. package/dist/cli/core/email-scrub.js +2 -2
  65. package/dist/cli/core/email-scrub.js.map +1 -1
  66. package/dist/cli/core/gh-cli.d.ts +2 -1
  67. package/dist/cli/core/gh-cli.d.ts.map +1 -1
  68. package/dist/cli/core/gh-cli.js +3 -2
  69. package/dist/cli/core/gh-cli.js.map +1 -1
  70. package/dist/cli/core/init.d.ts.map +1 -1
  71. package/dist/cli/core/init.js +26 -31
  72. package/dist/cli/core/init.js.map +1 -1
  73. package/dist/cli/core/migrations.js +1 -1
  74. package/dist/cli/core/migrations.js.map +1 -1
  75. package/dist/cli/core/nap.js +2 -2
  76. package/dist/cli/core/nap.js.map +1 -1
  77. package/dist/cli/core/project-type.js +1 -1
  78. package/dist/cli/core/project-type.js.map +1 -1
  79. package/dist/cli/core/templates.d.ts.map +1 -1
  80. package/dist/cli/core/templates.js +48 -0
  81. package/dist/cli/core/templates.js.map +1 -1
  82. package/dist/cli/core/upgrade.d.ts +4 -2
  83. package/dist/cli/core/upgrade.d.ts.map +1 -1
  84. package/dist/cli/core/upgrade.js +46 -21
  85. package/dist/cli/core/upgrade.js.map +1 -1
  86. package/dist/cli/shell/index.d.ts.map +1 -1
  87. package/dist/cli/shell/index.js +22 -0
  88. package/dist/cli/shell/index.js.map +1 -1
  89. package/dist/cli/shell/session-store.js +2 -2
  90. package/dist/cli/shell/session-store.js.map +1 -1
  91. package/dist/cli-entry.js +101 -83
  92. package/dist/cli-entry.js.map +1 -1
  93. package/package.json +6 -2
  94. package/templates/casting-reference.md +104 -104
  95. package/templates/ceremonies.md +28 -28
  96. package/templates/fact-checker-charter.md +83 -0
  97. package/templates/mcp-config.md +0 -2
  98. package/templates/scribe-charter.md +1 -1
  99. package/templates/skills/external-comms/SKILL.md +329 -329
  100. package/templates/skills/gh-auth-isolation/SKILL.md +183 -183
  101. package/templates/skills/humanizer/SKILL.md +105 -105
  102. package/templates/skills/pr-review-response/SKILL.md +268 -0
  103. package/templates/skills/pr-screenshots/SKILL.md +149 -149
  104. package/templates/skills/versioning-policy/SKILL.md +119 -0
  105. package/templates/squad.agent.md.template +13 -6
  106. package/dist/cli/commands/watch/capabilities/budget-check.d.ts +0 -29
  107. package/dist/cli/commands/watch/capabilities/budget-check.d.ts.map +0 -1
  108. package/dist/cli/commands/watch/capabilities/budget-check.js +0 -38
  109. package/dist/cli/commands/watch/capabilities/budget-check.js.map +0 -1
  110. package/dist/cli/commands/watch/capabilities/circuit-breaker.d.ts +0 -52
  111. package/dist/cli/commands/watch/capabilities/circuit-breaker.d.ts.map +0 -1
  112. package/dist/cli/commands/watch/capabilities/circuit-breaker.js +0 -152
  113. package/dist/cli/commands/watch/capabilities/circuit-breaker.js.map +0 -1
  114. package/dist/cli/commands/watch/capabilities/health-check.d.ts +0 -29
  115. package/dist/cli/commands/watch/capabilities/health-check.d.ts.map +0 -1
  116. package/dist/cli/commands/watch/capabilities/health-check.js +0 -139
  117. package/dist/cli/commands/watch/capabilities/health-check.js.map +0 -1
  118. package/dist/cli/commands/watch/capabilities/heartbeat.d.ts +0 -48
  119. package/dist/cli/commands/watch/capabilities/heartbeat.d.ts.map +0 -1
  120. package/dist/cli/commands/watch/capabilities/heartbeat.js +0 -115
  121. package/dist/cli/commands/watch/capabilities/heartbeat.js.map +0 -1
  122. package/dist/cli/commands/watch/capabilities/lockfile.d.ts +0 -30
  123. package/dist/cli/commands/watch/capabilities/lockfile.d.ts.map +0 -1
  124. package/dist/cli/commands/watch/capabilities/lockfile.js +0 -100
  125. package/dist/cli/commands/watch/capabilities/lockfile.js.map +0 -1
  126. package/dist/cli/commands/watch/capabilities/machine-capabilities.d.ts +0 -30
  127. package/dist/cli/commands/watch/capabilities/machine-capabilities.d.ts.map +0 -1
  128. package/dist/cli/commands/watch/capabilities/machine-capabilities.js +0 -103
  129. package/dist/cli/commands/watch/capabilities/machine-capabilities.js.map +0 -1
  130. package/dist/cli/commands/watch/capabilities/post-failure.d.ts +0 -19
  131. package/dist/cli/commands/watch/capabilities/post-failure.d.ts.map +0 -1
  132. package/dist/cli/commands/watch/capabilities/post-failure.js +0 -58
  133. package/dist/cli/commands/watch/capabilities/post-failure.js.map +0 -1
  134. package/dist/cli/commands/watch/capabilities/priority.d.ts +0 -59
  135. package/dist/cli/commands/watch/capabilities/priority.d.ts.map +0 -1
  136. package/dist/cli/commands/watch/capabilities/priority.js +0 -101
  137. package/dist/cli/commands/watch/capabilities/priority.js.map +0 -1
  138. package/dist/cli/commands/watch/capabilities/rate-pool.d.ts +0 -67
  139. package/dist/cli/commands/watch/capabilities/rate-pool.d.ts.map +0 -1
  140. package/dist/cli/commands/watch/capabilities/rate-pool.js +0 -187
  141. package/dist/cli/commands/watch/capabilities/rate-pool.js.map +0 -1
  142. package/dist/cli/commands/watch/capabilities/stale-reclaim.d.ts +0 -23
  143. package/dist/cli/commands/watch/capabilities/stale-reclaim.d.ts.map +0 -1
  144. package/dist/cli/commands/watch/capabilities/stale-reclaim.js +0 -87
  145. package/dist/cli/commands/watch/capabilities/stale-reclaim.js.map +0 -1
  146. package/dist/cli/commands/watch/capabilities/webhook-alerts.d.ts +0 -29
  147. package/dist/cli/commands/watch/capabilities/webhook-alerts.d.ts.map +0 -1
  148. package/dist/cli/commands/watch/capabilities/webhook-alerts.js +0 -114
  149. package/dist/cli/commands/watch/capabilities/webhook-alerts.js.map +0 -1
@@ -0,0 +1,268 @@
1
+ ---
2
+ name: "pr-review-response"
3
+ description: "Teaches agents to reply to PR review comment threads after fixing issues, making resolutions traceable"
4
+ domain: "pull-requests, code-review, traceability"
5
+ confidence: "low"
6
+ source: "observed (agents fix review feedback silently — reviewers can't tell which comments were addressed)"
7
+ tools:
8
+ - name: "github-mcp-server-pull_request_read"
9
+ description: "Read PR review threads and comments"
10
+ when: "Step 1 — fetching review comments to understand what needs fixing"
11
+ - name: "gh api (REST)"
12
+ description: "Reply to review comment threads and resolve threads via GraphQL"
13
+ when: "Step 3 — posting reply to each comment thread after fixing"
14
+ ---
15
+
16
+ ## Context
17
+
18
+ When an agent fixes code in response to PR review comments (from Copilot, a human reviewer, or any GitHub reviewer), the fix alone is not enough. The reviewer needs to see — on the PR thread itself — which comments were addressed and how. Without replies, comments stay visually unresolved, reviewers must re-read the entire diff to verify fixes, and there's no traceable link between feedback and resolution.
19
+
20
+ Use this skill whenever:
21
+ - You are fixing code based on PR review feedback
22
+ - You are addressing Copilot review suggestions
23
+ - You are responding to reviewer-requested changes on a PR
24
+ - A squad member hands you review comments to resolve
25
+
26
+ ## SCOPE
27
+
28
+ ✅ THIS SKILL PRODUCES:
29
+ - Reply comments on each review thread explaining the fix
30
+ - Optionally resolved threads (via GraphQL when appropriate)
31
+ - Commit messages that reference the PR and review context
32
+
33
+ ❌ THIS SKILL DOES NOT PRODUCE:
34
+ - The code fixes themselves (that's the agent's domain work)
35
+ - New review comments or reviews
36
+ - PR descriptions or summaries
37
+
38
+ ## Patterns
39
+
40
+ ### Step 1: Read the review comments
41
+
42
+ **Using MCP tools (preferred when available):**
43
+
44
+ ```
45
+ github-mcp-server-pull_request_read
46
+ method: "get_review_comments"
47
+ owner: "{owner}"
48
+ repo: "{repo}"
49
+ pullNumber: {pr_number}
50
+ ```
51
+
52
+ This returns review threads with metadata: `isResolved`, `isOutdated`, `isCollapsed`, and their associated comments. Each comment has an `id` you'll need for replies.
53
+
54
+ **Using gh CLI (fallback):**
55
+
56
+ ```bash
57
+ gh api repos/{owner}/{repo}/pulls/{pr_number}/comments --paginate
58
+ ```
59
+
60
+ Each comment object contains `id`, `body`, `path`, `line`, and `in_reply_to_id`. Top-level comments have no `in_reply_to_id` — those are the ones you reply to.
61
+
62
+ ### Step 2: Fix the code
63
+
64
+ Make the actual code changes. This is your normal domain work — the skill doesn't prescribe how to fix, only how to communicate the fix.
65
+
66
+ **Track what you changed.** For each review comment, note:
67
+ - The comment `id` (top-level, not a reply)
68
+ - The file and line referenced
69
+ - What you actually changed (brief description)
70
+ - The commit SHA after pushing (if available)
71
+
72
+ ### Step 3: Reply to each review thread
73
+
74
+ After fixing and committing, reply to **each** review comment thread individually.
75
+
76
+ **REST API call (via gh CLI):**
77
+
78
+ ```bash
79
+ gh api repos/{owner}/{repo}/pulls/{pr_number}/comments/{comment_id}/replies \
80
+ -f body="Fixed in {sha_short} — {brief description of what was changed}"
81
+ ```
82
+
83
+ **Important:** `{comment_id}` must be the ID of the **top-level** comment in the thread. You cannot reply to a reply — only to the original review comment.
84
+
85
+ **Example replies:**
86
+
87
+ ```bash
88
+ # Specific and traceable
89
+ gh api repos/bradygaster/squad/pulls/42/comments/18234/replies \
90
+ -f body="Fixed in a1b2c3d — switched to path.dirname(squadDirInfo.path) for worktree consistency"
91
+
92
+ # When applying a suggested code change
93
+ gh api repos/bradygaster/squad/pulls/42/comments/18235/replies \
94
+ -f body="Applied suggestion — updated error message to include the file path for debuggability"
95
+
96
+ # When pushing back on a suggestion
97
+ gh api repos/bradygaster/squad/pulls/42/comments/18236/replies \
98
+ -f body="Considered but not applied — this path needs to stay absolute because worktree resolution depends on it. See detectSquadDir() in detect-squad-dir.ts."
99
+ ```
100
+
101
+ ### Step 4: Resolve threads (optional, GraphQL only)
102
+
103
+ Thread resolution is only available via the GitHub GraphQL API. Use this when your fix fully addresses the comment and no further discussion is needed.
104
+
105
+ **First, get the thread IDs** (they're different from comment IDs):
106
+
107
+ ```bash
108
+ gh api graphql -f query='
109
+ query {
110
+ repository(owner: "{owner}", name: "{repo}") {
111
+ pullRequest(number: {pr_number}) {
112
+ reviewThreads(first: 100) {
113
+ nodes {
114
+ id
115
+ isResolved
116
+ comments(first: 1) {
117
+ nodes { body databaseId }
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
123
+ }
124
+ '
125
+ ```
126
+
127
+ Match thread IDs to comment IDs using `databaseId`, then resolve:
128
+
129
+ ```bash
130
+ gh api graphql -f query='
131
+ mutation {
132
+ resolveReviewThread(input: {threadId: "{thread_node_id}"}) {
133
+ thread { id isResolved }
134
+ }
135
+ }
136
+ '
137
+ ```
138
+
139
+ **When to resolve vs. leave open:**
140
+ - ✅ Resolve: You fixed exactly what was requested, no ambiguity
141
+ - ❌ Don't resolve: You pushed back, applied a different fix, or the comment needs further discussion
142
+ - ❌ Don't resolve: The reviewer is a human — let them confirm and resolve themselves
143
+
144
+ **Rule of thumb:** Agent-to-agent threads (e.g., Copilot review → agent fix) can be resolved by the fixer. Human reviewer threads should be left for the human to resolve.
145
+
146
+ ### Step 5: Commit message traceability
147
+
148
+ Commit messages should reference the PR context:
149
+
150
+ ```
151
+ fix: address review feedback on PR #{pr_number}
152
+
153
+ - Switched to path.dirname() for worktree path resolution (comment #18234)
154
+ - Updated error message to include file path (comment #18235)
155
+
156
+ Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
157
+ ```
158
+
159
+ For single-comment fixes, a shorter format works:
160
+
161
+ ```
162
+ fix: use path.dirname() for worktree consistency (PR #{pr_number} review)
163
+
164
+ Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
165
+ ```
166
+
167
+ ## AGENT WORKFLOW (Summary)
168
+
169
+ 1. **READ** — Fetch review threads using MCP tool or `gh api`
170
+ 2. **FIX** — Make code changes, tracking comment ID → change mapping
171
+ 3. **COMMIT** — Push with traceable commit message referencing PR and comments
172
+ 4. **REPLY** — Post individual reply to each thread via `gh api .../replies`
173
+ 5. **RESOLVE** — (Optional) Resolve agent-to-agent threads via GraphQL
174
+ 6. **STOP** — Do not batch-reply, do not skip threads, do not resolve human threads
175
+
176
+ ## Examples
177
+
178
+ ### Example: Copilot flags a potential null dereference
179
+
180
+ **Review comment (id: 55123):**
181
+ > `squadDir` could be undefined here. Consider adding a null check.
182
+
183
+ **Agent workflow:**
184
+ 1. Read the comment via `get_review_comments`
185
+ 2. Add the null check in `src/cli/core/detect-squad-dir.ts`
186
+ 3. Commit: `fix: add null check for squadDir (PR #99 review)`
187
+ 4. Reply:
188
+ ```bash
189
+ gh api repos/bradygaster/squad/pulls/99/comments/55123/replies \
190
+ -f body="Fixed in f4e5d6c — added early return when squadDir is undefined, matching the pattern in loadConfig()"
191
+ ```
192
+ 5. Resolve the thread (Copilot → agent, safe to resolve)
193
+
194
+ ### Example: Multiple review comments on one PR
195
+
196
+ **Comments:**
197
+ - id: 55123 — "Null check needed" on `detect-squad-dir.ts:42`
198
+ - id: 55124 — "Consider using path.join()" on `detect-squad-dir.ts:58`
199
+ - id: 55125 — "This log message is too verbose" on `output.ts:15`
200
+
201
+ **Agent handles each individually:**
202
+ ```bash
203
+ # Fix all three, commit
204
+ git add packages/squad-cli/src/cli/core/detect-squad-dir.ts packages/squad-cli/src/cli/core/output.ts
205
+ git commit -m "fix: address 3 review comments on PR #99
206
+
207
+ - Added null check for squadDir (comment #55123)
208
+ - Switched to path.join() for cross-platform paths (comment #55124)
209
+ - Reduced log verbosity to debug level (comment #55125)"
210
+
211
+ git push
212
+
213
+ # Reply to each thread individually
214
+ gh api repos/bradygaster/squad/pulls/99/comments/55123/replies \
215
+ -f body="Fixed — added early return when squadDir is undefined"
216
+
217
+ gh api repos/bradygaster/squad/pulls/99/comments/55124/replies \
218
+ -f body="Fixed — switched to path.join(squadDir, 'config.json') for cross-platform consistency"
219
+
220
+ gh api repos/bradygaster/squad/pulls/99/comments/55125/replies \
221
+ -f body="Fixed — changed from console.log to debug() so it only shows with --verbose flag"
222
+ ```
223
+
224
+ ### Example: Handling Copilot suggestion blocks
225
+
226
+ Copilot sometimes provides `suggestion` blocks with exact code to apply:
227
+
228
+ **Review comment (id: 55130):**
229
+ ````
230
+ Consider using optional chaining:
231
+ ```suggestion
232
+ const name = config?.agent?.name ?? 'default';
233
+ ```
234
+ ````
235
+
236
+ **Reply format when applying:**
237
+ ```bash
238
+ gh api repos/bradygaster/squad/pulls/99/comments/55130/replies \
239
+ -f body="Applied suggestion — using optional chaining with nullish coalescing"
240
+ ```
241
+
242
+ **Reply format when not applying:**
243
+ ```bash
244
+ gh api repos/bradygaster/squad/pulls/99/comments/55130/replies \
245
+ -f body="Not applied — config is guaranteed non-null at this point (validated on line 12). Optional chaining would mask errors."
246
+ ```
247
+
248
+ ### Example: Pushing back on a review comment
249
+
250
+ Not every review comment should be accepted. When a suggestion is incorrect or doesn't apply:
251
+
252
+ ```bash
253
+ gh api repos/bradygaster/squad/pulls/99/comments/55140/replies \
254
+ -f body="Considered but not applied — this file is in the zero-dependency bootstrap set (see copilot-instructions.md § Protected Files). Adding path.join() would require importing from the SDK, which breaks the bootstrap constraint."
255
+ ```
256
+
257
+ Do NOT resolve the thread when pushing back. Leave it open for the reviewer to confirm.
258
+
259
+ ## Anti-Patterns
260
+
261
+ - ❌ **Fixing silently** — Making code changes without replying to the review thread. The reviewer has no way to know which comments were addressed.
262
+ - ❌ **Batch-replying "all fixed"** — A single comment saying "Addressed all review feedback" on the PR. Each thread needs its own reply so reviewers can verify individually.
263
+ - ❌ **Resolving without explaining** — Marking threads resolved without posting a reply first. The resolution gives no context on what was done.
264
+ - ❌ **Resolving human reviewer threads** — Only resolve threads from automated reviewers (Copilot, bots). Let human reviewers confirm and resolve their own threads.
265
+ - ❌ **Vague replies** — "Fixed" or "Done" without saying what was changed. The reply should be specific enough that the reviewer doesn't need to re-read the diff.
266
+ - ❌ **Replying before pushing** — Reply after your fix is committed and pushed, not before. The reply should reference actual committed code.
267
+ - ❌ **Ignoring comments you disagree with** — If you don't apply a suggestion, reply explaining why. Silence looks like you missed it.
268
+ - ❌ **Replying to replies** — The REST API only supports replying to top-level review comments. Attempting to reply to a reply will fail with a 404.
@@ -1,149 +1,149 @@
1
- ---
2
- name: "pr-screenshots"
3
- description: "Capture Playwright screenshots and embed them in GitHub PR descriptions"
4
- domain: "pull-requests, visual-review, docs, testing"
5
- confidence: "high"
6
- source: "earned (multiple sessions establishing the pattern for PR #11 TypeDoc API reference)"
7
- ---
8
-
9
- ## Context
10
-
11
- When a PR includes visual changes (docs sites, UI components, generated pages), reviewers
12
- need to see what the PR delivers without checking out the branch. Screenshots belong in
13
- the **PR description body**, not as committed files and not as text descriptions.
14
-
15
- Use this skill whenever:
16
- - A PR touches docs site pages (Astro, Starlight, etc.)
17
- - A PR adds or changes UI components
18
- - A PR generates visual artifacts (TypeDoc, Storybook, diagrams)
19
- - Playwright tests already capture screenshots as part of testing
20
-
21
- ## Patterns
22
-
23
- ### 1. Capture screenshots with Playwright
24
-
25
- If Playwright tests already exist and produce screenshots, reuse those. Otherwise,
26
- write a minimal capture script:
27
-
28
- ```javascript
29
- // scripts/capture-pr-screenshots.mjs
30
- import { chromium } from 'playwright';
31
-
32
- const browser = await chromium.launch();
33
- const page = await browser.newPage({ viewport: { width: 1280, height: 720 } });
34
-
35
- const screenshots = [
36
- { url: 'http://localhost:4321/path/to/page', name: 'feature-landing' },
37
- { url: 'http://localhost:4321/path/to/detail', name: 'feature-detail' },
38
- ];
39
-
40
- for (const { url, name } of screenshots) {
41
- await page.goto(url, { waitUntil: 'networkidle' });
42
- await page.screenshot({ path: `screenshots/${name}.png`, fullPage: false });
43
- }
44
-
45
- await browser.close();
46
- ```
47
-
48
- ### 2. Host screenshots on a temporary branch
49
-
50
- GitHub PR descriptions render images via URLs. The `gh` CLI cannot upload binary
51
- images directly. Use a temporary orphan branch to host the images:
52
-
53
- ```powershell
54
- # Save current branch
55
- $currentBranch = git branch --show-current
56
-
57
- # Create orphan branch with only screenshot files
58
- git checkout --orphan screenshots-temp
59
- git reset
60
- git add screenshots/*.png
61
- git commit -m "screenshots for PR review"
62
- git push origin screenshots-temp --force
63
-
64
- # Build raw URLs
65
- $base = "https://raw.githubusercontent.com/{owner}/{repo}/screenshots-temp/screenshots"
66
- # Each image: $base/{name}.png
67
-
68
- # Return to working branch
69
- git checkout -f $currentBranch
70
- ```
71
-
72
- ### 3. Embed in PR description
73
-
74
- Use `gh pr edit` with the raw URLs embedded as markdown images:
75
-
76
- ```powershell
77
- $base = "https://raw.githubusercontent.com/{owner}/{repo}/screenshots-temp/screenshots"
78
-
79
- gh pr edit {PR_NUMBER} --repo {owner}/{repo} --body @"
80
- ## {PR Title}
81
-
82
- ### What this PR delivers
83
- - {bullet points of changes}
84
-
85
- ---
86
-
87
- ### Screenshots
88
-
89
- #### {Page/Feature Name}
90
- ![{alt text}]($base/{name}.png)
91
-
92
- #### {Another Page}
93
- ![{alt text}]($base/{another-name}.png)
94
-
95
- ---
96
-
97
- ### To verify locally
98
- ```bash
99
- {commands to run locally}
100
- ```
101
- "@
102
- ```
103
-
104
- ### 4. Cleanup after merge
105
-
106
- After the PR is merged, delete the temporary branch:
107
-
108
- ```bash
109
- git push origin --delete screenshots-temp
110
- ```
111
-
112
- ### 5. Gitignore screenshots locally
113
-
114
- Screenshots are build artifacts — never commit them to feature branches:
115
-
116
- ```gitignore
117
- # PR screenshots (hosted on temp branch, not committed to features)
118
- screenshots/
119
- docs/tests/screenshots/
120
- ```
121
-
122
- ## Examples
123
-
124
- ### Example: Docs site PR with 3 pages
125
-
126
- 1. Start dev server: `cd docs && npm run dev`
127
- 2. Run Playwright tests (they capture screenshots as a side effect)
128
- 3. Push screenshots to `screenshots-temp` branch
129
- 4. Update PR body with embedded `![...]()` image references
130
- 5. Reviewer sees the pages inline without checking out the branch
131
-
132
- ### Example: Reusing existing Playwright test screenshots
133
-
134
- If tests at `docs/tests/*.spec.mjs` already save to `docs/tests/screenshots/`:
135
-
136
- ```powershell
137
- cd docs && npx playwright test tests/api-reference.spec.mjs
138
- # Screenshots now at docs/tests/screenshots/*.png
139
- # Push those to screenshots-temp and embed in PR
140
- ```
141
-
142
- ## Anti-Patterns
143
-
144
- - ❌ **Committing screenshots to feature branches** — they bloat the repo and go stale
145
- - ❌ **Posting text descriptions instead of actual images** — reviewers can't see what they're getting
146
- - ❌ **Using `gh` CLI to "upload" images** — `gh issue comment` and `gh pr edit` don't support binary uploads
147
- - ❌ **Asking the user to manually drag-drop images** — automate it with the temp branch pattern
148
- - ❌ **Skipping screenshots for visual PRs** — if the PR changes what users see, show what users see
149
- - ❌ **Leaving the screenshots-temp branch around forever** — clean up after merge
1
+ ---
2
+ name: "pr-screenshots"
3
+ description: "Capture Playwright screenshots and embed them in GitHub PR descriptions"
4
+ domain: "pull-requests, visual-review, docs, testing"
5
+ confidence: "high"
6
+ source: "earned (multiple sessions establishing the pattern for PR #11 TypeDoc API reference)"
7
+ ---
8
+
9
+ ## Context
10
+
11
+ When a PR includes visual changes (docs sites, UI components, generated pages), reviewers
12
+ need to see what the PR delivers without checking out the branch. Screenshots belong in
13
+ the **PR description body**, not as committed files and not as text descriptions.
14
+
15
+ Use this skill whenever:
16
+ - A PR touches docs site pages (Astro, Starlight, etc.)
17
+ - A PR adds or changes UI components
18
+ - A PR generates visual artifacts (TypeDoc, Storybook, diagrams)
19
+ - Playwright tests already capture screenshots as part of testing
20
+
21
+ ## Patterns
22
+
23
+ ### 1. Capture screenshots with Playwright
24
+
25
+ If Playwright tests already exist and produce screenshots, reuse those. Otherwise,
26
+ write a minimal capture script:
27
+
28
+ ```javascript
29
+ // scripts/capture-pr-screenshots.mjs
30
+ import { chromium } from 'playwright';
31
+
32
+ const browser = await chromium.launch();
33
+ const page = await browser.newPage({ viewport: { width: 1280, height: 720 } });
34
+
35
+ const screenshots = [
36
+ { url: 'http://localhost:4321/path/to/page', name: 'feature-landing' },
37
+ { url: 'http://localhost:4321/path/to/detail', name: 'feature-detail' },
38
+ ];
39
+
40
+ for (const { url, name } of screenshots) {
41
+ await page.goto(url, { waitUntil: 'networkidle' });
42
+ await page.screenshot({ path: `screenshots/${name}.png`, fullPage: false });
43
+ }
44
+
45
+ await browser.close();
46
+ ```
47
+
48
+ ### 2. Host screenshots on a temporary branch
49
+
50
+ GitHub PR descriptions render images via URLs. The `gh` CLI cannot upload binary
51
+ images directly. Use a temporary orphan branch to host the images:
52
+
53
+ ```powershell
54
+ # Save current branch
55
+ $currentBranch = git branch --show-current
56
+
57
+ # Create orphan branch with only screenshot files
58
+ git checkout --orphan screenshots-temp
59
+ git reset
60
+ git add screenshots/*.png
61
+ git commit -m "screenshots for PR review"
62
+ git push origin screenshots-temp --force
63
+
64
+ # Build raw URLs
65
+ $base = "https://raw.githubusercontent.com/{owner}/{repo}/screenshots-temp/screenshots"
66
+ # Each image: $base/{name}.png
67
+
68
+ # Return to working branch
69
+ git checkout -f $currentBranch
70
+ ```
71
+
72
+ ### 3. Embed in PR description
73
+
74
+ Use `gh pr edit` with the raw URLs embedded as markdown images:
75
+
76
+ ```powershell
77
+ $base = "https://raw.githubusercontent.com/{owner}/{repo}/screenshots-temp/screenshots"
78
+
79
+ gh pr edit {PR_NUMBER} --repo {owner}/{repo} --body @"
80
+ ## {PR Title}
81
+
82
+ ### What this PR delivers
83
+ - {bullet points of changes}
84
+
85
+ ---
86
+
87
+ ### Screenshots
88
+
89
+ #### {Page/Feature Name}
90
+ ![{alt text}]($base/{name}.png)
91
+
92
+ #### {Another Page}
93
+ ![{alt text}]($base/{another-name}.png)
94
+
95
+ ---
96
+
97
+ ### To verify locally
98
+ ```bash
99
+ {commands to run locally}
100
+ ```
101
+ "@
102
+ ```
103
+
104
+ ### 4. Cleanup after merge
105
+
106
+ After the PR is merged, delete the temporary branch:
107
+
108
+ ```bash
109
+ git push origin --delete screenshots-temp
110
+ ```
111
+
112
+ ### 5. Gitignore screenshots locally
113
+
114
+ Screenshots are build artifacts — never commit them to feature branches:
115
+
116
+ ```gitignore
117
+ # PR screenshots (hosted on temp branch, not committed to features)
118
+ screenshots/
119
+ docs/tests/screenshots/
120
+ ```
121
+
122
+ ## Examples
123
+
124
+ ### Example: Docs site PR with 3 pages
125
+
126
+ 1. Start dev server: `cd docs && npm run dev`
127
+ 2. Run Playwright tests (they capture screenshots as a side effect)
128
+ 3. Push screenshots to `screenshots-temp` branch
129
+ 4. Update PR body with embedded `![...]()` image references
130
+ 5. Reviewer sees the pages inline without checking out the branch
131
+
132
+ ### Example: Reusing existing Playwright test screenshots
133
+
134
+ If tests at `docs/tests/*.spec.mjs` already save to `docs/tests/screenshots/`:
135
+
136
+ ```powershell
137
+ cd docs && npx playwright test tests/api-reference.spec.mjs
138
+ # Screenshots now at docs/tests/screenshots/*.png
139
+ # Push those to screenshots-temp and embed in PR
140
+ ```
141
+
142
+ ## Anti-Patterns
143
+
144
+ - ❌ **Committing screenshots to feature branches** — they bloat the repo and go stale
145
+ - ❌ **Posting text descriptions instead of actual images** — reviewers can't see what they're getting
146
+ - ❌ **Using `gh` CLI to "upload" images** — `gh issue comment` and `gh pr edit` don't support binary uploads
147
+ - ❌ **Asking the user to manually drag-drop images** — automate it with the temp branch pattern
148
+ - ❌ **Skipping screenshots for visual PRs** — if the PR changes what users see, show what users see
149
+ - ❌ **Leaving the screenshots-temp branch around forever** — clean up after merge