@jesdi/skills 0.0.24 → 0.0.26
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/package.json +1 -1
- package/skills/pr-visual-diff/SKILL.md +40 -22
- package/skills/to-openspec/SKILL.md +27 -20
- package/skills/to-openspec/templates/design.md +2 -2
- package/skills/to-openspec/templates/proposal.md +1 -2
- package/skills-manifest.json +6 -6
- package/skills/to-openspec/templates/tasks.md +0 -9
package/package.json
CHANGED
|
@@ -6,7 +6,8 @@ description: Capture before/after screenshots of UI views with Playwright and em
|
|
|
6
6
|
# PR Visual Diff
|
|
7
7
|
|
|
8
8
|
Produce before/after screenshots of the views affected by a branch's frontend
|
|
9
|
-
changes,
|
|
9
|
+
changes, push them to a hidden ref (never the PR branch), and embed them in the
|
|
10
|
+
PR body. Reviewers
|
|
10
11
|
should see what changed visually without checking out the branch.
|
|
11
12
|
|
|
12
13
|
The approach leans on the project's existing Playwright e2e harness with the
|
|
@@ -44,7 +45,6 @@ file as JSON:
|
|
|
44
45
|
| `deviceProjects` | the config's `projects` (default to a desktop + a mobile project) |
|
|
45
46
|
| `baseBranch` | the repo's default branch (`main`/`master`; `git symbolic-ref refs/remotes/origin/HEAD`) |
|
|
46
47
|
| `packageManager` | infer from lockfile: `pnpm-lock.yaml`→pnpm, `package-lock.json`→npm, `yarn.lock`→yarn, `bun.lockb`→bun |
|
|
47
|
-
| `screenshotDir` | default `docs/pr-screenshots` |
|
|
48
48
|
| `spinnerSelector` | the app's loading-indicator selector (search for a spinner/`role="status"`/`aria-busy` component) |
|
|
49
49
|
|
|
50
50
|
### Preconditions gate
|
|
@@ -66,14 +66,14 @@ screenshots.
|
|
|
66
66
|
## Always run the capture in a subagent
|
|
67
67
|
|
|
68
68
|
Steps 2–6 (writing the spec, capturing, **reading every PNG back to eyeball
|
|
69
|
-
it**,
|
|
69
|
+
it**, pushing them to the hidden ref, embedding) MUST run inside a single dispatched subagent — not
|
|
70
70
|
in the main context. Reading screenshots back is this skill's dominant token
|
|
71
71
|
cost, and those image bytes are worthless to the main thread; keeping them in a
|
|
72
72
|
subagent's throwaway context is the whole savings, with no loss of verification.
|
|
73
73
|
|
|
74
74
|
Main context does only: step 1 (map the diff, get the user's go-ahead), then
|
|
75
75
|
dispatch a subagent with the plan and the config values. The subagent returns a
|
|
76
|
-
compact report: the
|
|
76
|
+
compact report: the screenshot file names + pinned URLs, the PR-body
|
|
77
77
|
markdown, and any views it flagged. The main context creates/edits the PR from
|
|
78
78
|
that report — it never reads a PNG.
|
|
79
79
|
|
|
@@ -88,11 +88,11 @@ make it visible (open a modal, select a tab). Classify each view as **changed**
|
|
|
88
88
|
(existed at the merge base) or **new** (introduced by this branch) — new ones
|
|
89
89
|
get an after-only shot.
|
|
90
90
|
|
|
91
|
-
This capture is heavy (temp worktree, two Playwright passes,
|
|
92
|
-
|
|
91
|
+
This capture is heavy (temp worktree, two Playwright passes, images pushed to a
|
|
92
|
+
hidden ref, PR body rewritten). ALWAYS confirm with AskUserQuestion before
|
|
93
93
|
running any of it. The question must cover **both** (a) whether to run the whole
|
|
94
|
-
before/after capture at all, and (b) that it will
|
|
95
|
-
embed them in the PR. Include the proposed plan: which routes/states, and which
|
|
94
|
+
before/after capture at all, and (b) that it will push the screenshots to a
|
|
95
|
+
hidden ref on the remote and embed them in the PR. Include the proposed plan: which routes/states, and which
|
|
96
96
|
device projects — default to the config's `deviceProjects`; add more only when
|
|
97
97
|
the change is layout-sensitive. If they decline, create the PR normally and stop.
|
|
98
98
|
|
|
@@ -167,24 +167,43 @@ Remove the worktree when done:
|
|
|
167
167
|
`git worktree remove --force <scratchpad>/pr-before-shots` (`--force` because
|
|
168
168
|
install left untracked artifacts).
|
|
169
169
|
|
|
170
|
-
### 5.
|
|
170
|
+
### 5. Push the images to a hidden ref
|
|
171
171
|
|
|
172
|
+
The images must never land on the PR branch: once merged they would sit in the
|
|
173
|
+
base branch's history forever and every clone would download them. Instead,
|
|
174
|
+
build an orphan commit that holds only the PNGs and push it to a ref outside
|
|
175
|
+
`refs/heads/*`, which clones and fetches never transfer (GitHub's own
|
|
176
|
+
`refs/pull/*` works the same way). The working tree, the index and the PR
|
|
177
|
+
branch are not touched.
|
|
178
|
+
|
|
179
|
+
Collect the shots you'll reference into one flat directory, named
|
|
180
|
+
`<view>--<project>--{before|after}.png`, then:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
SLUG=$(git branch --show-current | tr / -)
|
|
184
|
+
TREE=$(for f in <scratchpad>/shots/*.png; do
|
|
185
|
+
printf '100644 blob %s\t%s\n' "$(git hash-object -w "$f")" "$(basename "$f")"
|
|
186
|
+
done | git mktree)
|
|
187
|
+
SHA=$(git commit-tree "$TREE" -m "pr-screenshots: ${SLUG}")
|
|
188
|
+
git push origin "${SHA}:refs/pr-screenshots/${SLUG}/${SHA}"
|
|
172
189
|
```
|
|
173
|
-
<screenshotDir>/<branch-slug>/<view>--<project>--{before|after}.png
|
|
174
|
-
```
|
|
175
190
|
|
|
176
|
-
|
|
177
|
-
|
|
191
|
+
Keep the braces in `${SHA}:` — zsh reads a bare `$SHA:r` as a modifier and
|
|
192
|
+
mangles the refspec. Each capture gets its own ref (the commit SHA is part of
|
|
193
|
+
the name), so a re-capture never needs a force push, two machines never
|
|
194
|
+
collide, and URLs from earlier captures keep working. Never delete these refs:
|
|
195
|
+
they are what keeps the images alive on GitHub.
|
|
196
|
+
|
|
197
|
+
Delete the temp spec. Nothing from this skill is committed to the PR branch.
|
|
178
198
|
|
|
179
199
|
### 6. Embed in the PR body
|
|
180
200
|
|
|
181
|
-
|
|
182
|
-
|
|
201
|
+
Pin image URLs to the orphan commit; they render regardless of what happens to
|
|
202
|
+
the PR branch:
|
|
183
203
|
|
|
184
204
|
```bash
|
|
185
|
-
SHA=$(git rev-parse HEAD)
|
|
186
205
|
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
|
|
187
|
-
# → https://github.com/$REPO/blob/$SHA/<
|
|
206
|
+
# → https://github.com/$REPO/blob/$SHA/<file>.png?raw=true
|
|
188
207
|
```
|
|
189
208
|
|
|
190
209
|
Per view, one table. Put **Before on the left and After on the right** (one
|
|
@@ -201,12 +220,11 @@ side:
|
|
|
201
220
|
```
|
|
202
221
|
|
|
203
222
|
If the repo is private, GitHub's image proxy may refuse to inline blob URLs in
|
|
204
|
-
the PR body. Add a one-line note under the tables linking to the
|
|
205
|
-
|
|
206
|
-
always render
|
|
207
|
-
viewers.
|
|
223
|
+
the PR body. Add a one-line note under the tables linking to the orphan
|
|
224
|
+
commit's tree (`https://github.com/$REPO/tree/$SHA`) as a fallback — the images
|
|
225
|
+
always render there for authenticated viewers.
|
|
208
226
|
|
|
209
|
-
The subagent's job ends here: it has pushed the
|
|
227
|
+
The subagent's job ends here: it has pushed the hidden ref and produced the PR-body
|
|
210
228
|
markdown, and returns both. The **main context** creates (or edits) the PR with
|
|
211
229
|
that body, then opens it (`gh pr view --web`) so the user can confirm the embeds
|
|
212
230
|
render.
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
name: to-openspec
|
|
3
3
|
description: >-
|
|
4
4
|
Turn settled discovery notes and a sketched data model into a spec folder
|
|
5
|
-
in openspec shape (proposal, spec, design
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"
|
|
5
|
+
in openspec shape (proposal, spec, design) under specs/<slug>/, plus ticket
|
|
6
|
+
files under .agent/tickets/ that implement-spec runs directly. Two stages:
|
|
7
|
+
stage 1 alone by default, with a human review before stage 2, or both at
|
|
8
|
+
once with "all". No interview, just synthesis of decisions already made.
|
|
9
|
+
Trigger on "write the spec", "to-openspec", or
|
|
10
|
+
"/to-openspec <slug> [stage 2 | all]".
|
|
9
11
|
---
|
|
10
12
|
|
|
11
13
|
# To openspec
|
|
@@ -21,13 +23,16 @@ instead of inventing it. Never invent prices, policies, deadlines, or permission
|
|
|
21
23
|
conversation.
|
|
22
24
|
- Shape: read every file in the repo's `specs/_template/`, or in this skill's `templates/` when
|
|
23
25
|
the repo has none. Keep the headings exactly; write "None." rather than dropping a section.
|
|
26
|
+
Ignore a `tasks.md` template: tickets replace it.
|
|
24
27
|
- Check command: the one the repo documents (`make check`, or what AGENTS.md names).
|
|
28
|
+
- Stages: no argument runs stage 1 and stops. `stage 2` runs stage 2 only. `all` runs both
|
|
29
|
+
without the stop in between.
|
|
25
30
|
|
|
26
31
|
## Stage 1: what and why
|
|
27
32
|
|
|
28
33
|
Write `specs/<slug>/proposal.md` and `specs/<slug>/spec.md`.
|
|
29
34
|
|
|
30
|
-
- **Goal** is one or two sentences. Every
|
|
35
|
+
- **Goal** is one or two sentences. Every ticket serves it.
|
|
31
36
|
- **Non-goals** carry over every "later" or "never" verdict from discovery.
|
|
32
37
|
- **Requirements** cover the v1 slice only: the smallest set that meets the goal. Each one is
|
|
33
38
|
testable and maps to at least one scenario.
|
|
@@ -35,13 +40,14 @@ Write `specs/<slug>/proposal.md` and `specs/<slug>/spec.md`.
|
|
|
35
40
|
Every invariant (overselling, expiry, refund permissions, and so on) gets a scenario for the
|
|
36
41
|
boundary and one for the violation.
|
|
37
42
|
|
|
38
|
-
Then **stop
|
|
39
|
-
the spec before the design is written. Don't write code.
|
|
43
|
+
Then **stop**, unless invoked with `all`. Print the requirement list and any open questions so
|
|
44
|
+
the human can cut or correct the spec before the design is written. Don't write code.
|
|
40
45
|
|
|
41
46
|
## Stage 2: how
|
|
42
47
|
|
|
43
|
-
Run only when asked
|
|
44
|
-
stage 1.
|
|
48
|
+
Run only when asked: "/to-openspec <slug> stage 2" after the human has reviewed stage 1, or
|
|
49
|
+
`all` straight after stage 1. On `stage 2`, re-read `proposal.md` and `spec.md` first; the
|
|
50
|
+
human may have edited them.
|
|
45
51
|
|
|
46
52
|
1. Run the `red-team-data-model` skill against the data model. Print the top 5, and its identity
|
|
47
53
|
inventory when the change widens a key; don't write them to a file.
|
|
@@ -50,23 +56,24 @@ stage 1. Re-read `proposal.md` and `spec.md` first; the human may have edited th
|
|
|
50
56
|
- **Data model**: every invariant a DB constraint can enforce (`CHECK`, `UNIQUE`, `NOT NULL`,
|
|
51
57
|
FK, conditional `UPDATE ... WHERE`) goes in the table, not only in app code.
|
|
52
58
|
- **Identities**: when the change widens a key, every item of the red-team's identity
|
|
53
|
-
inventory, marked covered (
|
|
59
|
+
inventory, marked covered (ticket numbers filled in step 3) or out of scope (why). Otherwise "None." Add the
|
|
54
60
|
heading when the repo's template lacks it.
|
|
55
61
|
- **Seams**: the endpoint, function, or command the tests drive through, marked existing or
|
|
56
62
|
new. Prefer one high seam.
|
|
57
63
|
- No implementation code anywhere in the spec folder. `implement-spec`'s test-writer reads it
|
|
58
64
|
and must not know the solution. A decision's shape (a type, a schema, a state machine, a
|
|
59
|
-
seam's signature) may appear; the function bodies that make the
|
|
60
|
-
3.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
seam's signature) may appear; the function bodies that make the tickets pass may not.
|
|
66
|
+
3. Run the `to-tickets` skill on `specs/<slug>/`, skipping its quiz (step 4): it writes
|
|
67
|
+
`.agent/tickets/<NN>-<slug>.md`, the task graph `implement-spec` runs directly. Don't write a
|
|
68
|
+
`tasks.md`. On top of its rules:
|
|
69
|
+
- Every scenario in `spec.md` is an acceptance criterion of some ticket.
|
|
70
|
+
- Each ticket's **Seam** is one of the seams from `design.md`.
|
|
65
71
|
- A slice adds only the tables and columns its own scenarios need, not the whole model up front.
|
|
66
|
-
- No standalone "run the checks"
|
|
67
|
-
- Then fill the
|
|
68
|
-
the
|
|
72
|
+
- No standalone "run the checks" ticket: every ticket already ends with the check command green.
|
|
73
|
+
- Then fill the ticket numbers into `design.md`'s **Identities**: every identity marked covered
|
|
74
|
+
names the ticket that rekeys it. A covered identity with no ticket is a missing ticket; add it.
|
|
69
75
|
|
|
70
|
-
Print the
|
|
76
|
+
Print the ticket list (number, title, blocked by, seam, touches), then **Open questions**: every
|
|
77
|
+
red-team finding the design leaves
|
|
71
78
|
unresolved, and every input the design assumes but the sources don't provide. Then stop. Don't
|
|
72
79
|
write code.
|
|
@@ -17,10 +17,10 @@ Tables/fields touched or added, and the invariants that go in DB constraints (no
|
|
|
17
17
|
## Identities
|
|
18
18
|
|
|
19
19
|
When this change widens a key, each identity built from the old key (file names, hashes,
|
|
20
|
-
dedupe keys, command args, dict keys): covered by which
|
|
20
|
+
dedupe keys, command args, dict keys): covered by which ticket, or out of scope and why. Otherwise
|
|
21
21
|
"None."
|
|
22
22
|
|
|
23
|
-
- `<identity>` — covered by <
|
|
23
|
+
- `<identity>` — covered by <ticket> | out of scope: <why>.
|
|
24
24
|
|
|
25
25
|
## Seams
|
|
26
26
|
|
|
@@ -10,8 +10,7 @@ The actor(s) this serves (e.g. customer, staff, owner).
|
|
|
10
10
|
|
|
11
11
|
## Goal
|
|
12
12
|
|
|
13
|
-
What "done" looks like for this slice. One or two sentences — this is what every
|
|
14
|
-
to.
|
|
13
|
+
What "done" looks like for this slice. One or two sentences — this is what every ticket serves.
|
|
15
14
|
|
|
16
15
|
## Non-goals
|
|
17
16
|
|
package/skills-manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"generatedAt": "2026-
|
|
3
|
+
"generatedAt": "2026-10-02T10:20:34.972Z",
|
|
4
4
|
"skills": [
|
|
5
5
|
{
|
|
6
6
|
"name": "backlog",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
"name": "pr-visual-diff",
|
|
55
|
-
"version": "0.1.
|
|
56
|
-
"hash": "sha256-
|
|
55
|
+
"version": "0.1.1",
|
|
56
|
+
"hash": "sha256-c90f308a7529ead883b4c379d034724a33da43e91f2d8ba0f2bdc5d79c894df2",
|
|
57
57
|
"description": "Capture before/after screenshots of UI views with Playwright and embed them in a PR. Use this skill whenever creating or preparing a pull request that touches frontend code (components, views, styles, layout, Tailwind classes) — even if the user just says \"open a PR\" or \"create the PR\" after UI work, and especially if they mention screenshots, visual diff, before/after, or \"show what changed\". Also use when the user asks to add screenshots to an existing PR."
|
|
58
58
|
},
|
|
59
59
|
{
|
|
@@ -76,9 +76,9 @@
|
|
|
76
76
|
},
|
|
77
77
|
{
|
|
78
78
|
"name": "to-openspec",
|
|
79
|
-
"version": "0.1.
|
|
80
|
-
"hash": "sha256-
|
|
81
|
-
"description": "Turn settled discovery notes and a sketched data model into a spec folder in openspec shape (proposal, spec, design
|
|
79
|
+
"version": "0.1.3",
|
|
80
|
+
"hash": "sha256-fa982c0960a4b07d6ec9c54076f831c1fb16a4e46b8ddd62acf86e5316345be7",
|
|
81
|
+
"description": "Turn settled discovery notes and a sketched data model into a spec folder in openspec shape (proposal, spec, design) under specs/<slug>/, plus ticket files under .agent/tickets/ that implement-spec runs directly. Two stages: stage 1 alone by default, with a human review before stage 2, or both at once with \"all\". No interview, just synthesis of decisions already made. Trigger on \"write the spec\", \"to-openspec\", or \"/to-openspec <slug> [stage 2 | all]\"."
|
|
82
82
|
},
|
|
83
83
|
{
|
|
84
84
|
"name": "to-spec",
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# <Feature title> — Tasks
|
|
2
|
-
|
|
3
|
-
Each task links to the goal in proposal.md. Work the frontier (tasks whose blockers are done);
|
|
4
|
-
commit per task with its ID.
|
|
5
|
-
|
|
6
|
-
- [ ] **T1** — <task>. _Goal: <one line, why this task serves proposal.md's goal>._
|
|
7
|
-
Seam: <endpoint / function / command from design.md>. Blocked by: none.
|
|
8
|
-
- [ ] **T2** — <task>. _Goal: ..._
|
|
9
|
-
Seam: .... Blocked by: T1.
|