@cloverleaf/reference-impl 0.12.0 → 0.13.1
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/.claude-plugin/plugin.json +1 -1
- package/README.md +101 -37
- package/VERSION +1 -1
- package/config/council.json +10 -2
- package/dist/cli.mjs +29 -10
- package/dist/council.mjs +285 -64
- package/dist/events.mjs +3 -8
- package/dist/ids.mjs +7 -0
- package/dist/qa-rules.mjs +19 -3
- package/dist/task.mjs +6 -25
- package/dist/work-item.mjs +2 -3
- package/lib/cli.ts +30 -10
- package/lib/council-config.ts +1 -0
- package/lib/council.ts +343 -67
- package/lib/events.ts +4 -8
- package/lib/ids.ts +7 -0
- package/lib/qa-rules.ts +24 -3
- package/lib/task.ts +7 -33
- package/lib/work-item.ts +2 -4
- package/package.json +5 -3
- package/prompts/documenter.md +1 -1
- package/prompts/implementer.md +8 -2
- package/prompts/qa.md +6 -9
- package/prompts/reviewer.md +4 -2
- package/prompts/ui-reviewer.md +83 -11
- package/skills/cloverleaf-approve-baselines/SKILL.md +18 -26
- package/skills/cloverleaf-discover/SKILL.md +7 -1
- package/skills/cloverleaf-document/SKILL.md +5 -6
- package/skills/cloverleaf-implement/SKILL.md +24 -30
- package/skills/cloverleaf-merge/SKILL.md +14 -23
- package/skills/cloverleaf-new-task/SKILL.md +23 -4
- package/skills/cloverleaf-qa/SKILL.md +25 -24
- package/skills/cloverleaf-review/SKILL.md +24 -18
- package/skills/cloverleaf-run/SKILL.md +45 -106
- package/skills/cloverleaf-run-plan/SKILL.md +19 -26
- package/skills/cloverleaf-security-review/SKILL.md +22 -17
- package/skills/cloverleaf-ui-review/SKILL.md +59 -35
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cloverleaf-ui-review
|
|
3
|
-
description: Run the UI Reviewer
|
|
3
|
+
description: Run the UI Reviewer council member on a task's feature branch as a standalone one-off. Computes diff-affected routes via CLI; if empty, skips axe and emits a trivial pass. Otherwise dispatches a subagent with Playwright + axe-core scoped to those routes, capturing per-engine visual baselines. Emit-only — it writes a feedback envelope + reports the verdict (and surfaces baselines_pending) for the delivery council or a human to apply. It does NOT advance the task FSM. Usage — /cloverleaf-ui-review <TASK-ID>.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Cloverleaf — ui-review
|
|
6
|
+
# Cloverleaf — ui-review (emit-only council member)
|
|
7
|
+
|
|
8
|
+
The delivery states `ui-review`/`qa` no longer exist — the `@cloverleaf/standard` task FSM collapsed the delivery
|
|
9
|
+
gates into a single `council` phase (Council Slice 4). The UI Reviewer is now a **council member** that the runner
|
|
10
|
+
(`/cloverleaf-run`) dispatches and aggregates alongside the other members. A single member cannot drive the
|
|
11
|
+
multi-member council forward (that would bypass the others' gating), so this standalone skill is **emit-only**: it
|
|
12
|
+
computes the affected routes, dispatches the UI reviewer prompt (capturing per-engine visual baselines), emits the
|
|
13
|
+
feedback envelope, and reports the verdict. **It does not advance the FSM** — the council or a human applies the
|
|
14
|
+
aggregated verdict via `apply-council-verdict`.
|
|
15
|
+
|
|
16
|
+
**Baselines still gate at the council.** The per-engine (cross-browser) baseline capture and the `baselines_pending`
|
|
17
|
+
sidecar mechanism survive unchanged: when the UI reviewer captures new or resized baselines it sets
|
|
18
|
+
`baselines_pending=true` via `write-ui-review-state`. The old `ui-review → qa` hold moved to the **council pass**:
|
|
19
|
+
the runner holds a council `pass` at `baselines_pending` until `/cloverleaf-approve-baselines <TASK-ID>` clears it and
|
|
20
|
+
re-runs the council. This standalone skill just **surfaces** `baselines_pending` in its report; it does not advance
|
|
21
|
+
the FSM.
|
|
7
22
|
|
|
8
23
|
## Steps
|
|
9
24
|
|
|
@@ -27,7 +42,7 @@ description: Run the UI Reviewer agent on a task in the `ui-review` state (full
|
|
|
27
42
|
```
|
|
28
43
|
cloverleaf-cli load-task <repo_root> <TASK-ID>
|
|
29
44
|
```
|
|
30
|
-
|
|
45
|
+
Light guard only: confirm the task exists and is not terminal (`merged`/`rejected`/`escalated`). Do NOT hard-require any particular state — this skill reviews the branch, not a specific FSM state. If the task is terminal, report and stop.
|
|
31
46
|
|
|
32
47
|
3. Confirm feature branch exists: `git rev-parse --verify cloverleaf/<TASK-ID>`. If missing, report and stop.
|
|
33
48
|
|
|
@@ -42,14 +57,13 @@ description: Run the UI Reviewer agent on a task in the `ui-review` state (full
|
|
|
42
57
|
AFFECTED=$(cloverleaf-cli affected-routes <repo_root> <TASK-ID>)
|
|
43
58
|
```
|
|
44
59
|
|
|
45
|
-
6. **Empty-set early-exit.** If `AFFECTED` is `[]`, skip the subagent entirely:
|
|
60
|
+
6. **Empty-set early-exit.** If `AFFECTED` is `[]`, skip the subagent entirely — there are no renderable routes to check, so the UI member's verdict is a trivial `pass`. Do NOT advance the FSM:
|
|
46
61
|
```bash
|
|
47
|
-
cloverleaf-cli advance-status <repo_root> <TASK-ID> qa agent '' full_pipeline
|
|
48
62
|
cd <repo_root>
|
|
49
63
|
git add .cloverleaf/
|
|
50
|
-
git commit -m "cloverleaf: <TASK-ID> ui-review skipped (no renderable routes)
|
|
64
|
+
git diff --cached --quiet || git commit -m "cloverleaf: <TASK-ID> ui-review skipped (no renderable routes)"
|
|
51
65
|
```
|
|
52
|
-
Report: "✓ UI
|
|
66
|
+
Report: "✓ UI Reviewer verdict: **pass** (skipped — no renderable routes affected). This is one council member's verdict — the delivery council (`/cloverleaf-run <TASK-ID>`) or a human applies the aggregated verdict; this skill does not advance the FSM."
|
|
53
67
|
Stop here.
|
|
54
68
|
|
|
55
69
|
7. Allocate a free preview port:
|
|
@@ -62,21 +76,30 @@ description: Run the UI Reviewer agent on a task in the `ui-review` state (full
|
|
|
62
76
|
git diff main..cloverleaf/<TASK-ID>
|
|
63
77
|
```
|
|
64
78
|
|
|
65
|
-
9. **Browser cache env var.** Before the Task-tool dispatch,
|
|
79
|
+
9. **Browser cache env var.** Before the Task-tool dispatch, export the Playwright cache location so the subagent inherits it. This keeps Playwright from re-downloading ~300 MB of browser binaries inside the worktree.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
export PLAYWRIGHT_BROWSERS_PATH="${PLAYWRIGHT_BROWSERS_PATH:-$HOME/.cache/ms-playwright}"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Defer to a value the operator already set — `README.md` documents `PLAYWRIGHT_BROWSERS_PATH` as a supported override for a non-default cache directory, and hard-coding `~/.cache/ms-playwright` here would silently discard it. `ui-reviewer.md` runs the same expression itself, so this step is an optimisation, not a precondition the member depends on.
|
|
66
86
|
|
|
67
87
|
10. Dispatch the UI Reviewer subagent via the Task tool:
|
|
68
88
|
- `subagent_type`: `general-purpose`
|
|
69
89
|
- `model`: `sonnet`
|
|
70
90
|
- Prompt: contents of `$(cloverleaf-cli plugin-root)/prompts/ui-reviewer.md` with substitutions:
|
|
71
91
|
- `{{task}}`, `{{diff}}`, `{{branch}}`, `{{base_branch}}`, `{{repo_root}}`, `{{preview_port}}`
|
|
92
|
+
- `{{taskId}}` → the TASK-ID from step 1 (**required** — the prompt roots its run artifacts and the `state.json` sidecar at `{{repo_root}}/.cloverleaf/runs/{{taskId}}/ui-review/`. Left unsubstituted, the sidecar lands under a literal `{{taskId}}` directory, step 12's `read-ui-review-state` finds nothing, `baselines_pending` reads `false`, and the human baseline-approval gate silently passes with unapproved baselines)
|
|
72
93
|
- `{{affected_routes}}` → the value of `$AFFECTED` (verbatim — may be `"all"`, a JSON array, or `[]` but step 6 handled `[]` already)
|
|
73
94
|
- `{{ui_review_config}}` → JSON-stringified result of `cloverleaf-cli ui-review-config <repo_root>` (used by the subagent to scope viewport sizes, thresholds, and axe rule overrides)
|
|
74
95
|
|
|
96
|
+
Substitute **every** `{{…}}` token above before dispatch: `ui-reviewer.md` declares exactly these nine, and none may reach the subagent literal.
|
|
97
|
+
|
|
75
98
|
**Dispatch conventions:** invoke the Task tool in foreground mode (its default — do NOT pass `run_in_background: true`). The Task tool returns the subagent's final message as a string in the result. Do NOT use Bash `sleep` to poll an output file — the harness blocks foreground `sleep`, and background dispatch is unnecessary here because the foreground Task tool already blocks until the subagent finishes.
|
|
76
99
|
|
|
77
100
|
11. Parse the subagent's response. Expect `{"verdict": "pass"|"bounce"|"escalate", "summary": "...", "findings": [...]}`.
|
|
78
101
|
|
|
79
|
-
12. **Read the baseline-approval sidecar** (after the subagent completes, regardless of verdict):
|
|
102
|
+
12. **Read the baseline-approval sidecar** (after the subagent completes, regardless of verdict — the per-engine baseline capture + `baselines_pending` mechanism survives the collapse):
|
|
80
103
|
```bash
|
|
81
104
|
UI_STATE=$(cloverleaf-cli read-ui-review-state <repo_root> <TASK-ID>)
|
|
82
105
|
BASELINES_PENDING=$(echo "$UI_STATE" | node -e "process.stdout.write(JSON.parse(require('fs').readFileSync('/dev/stdin','utf-8')).baselines_pending ? 'true' : 'false')")
|
|
@@ -86,49 +109,50 @@ description: Run the UI Reviewer agent on a task in the `ui-review` state (full
|
|
|
86
109
|
BASELINES_PENDING=$(cloverleaf-cli read-ui-review-state <repo_root> <TASK-ID> | node -e "const s=require('fs').readFileSync('/dev/stdin','utf-8'); process.stdout.write(JSON.parse(s).baselines_pending?'true':'false')")
|
|
87
110
|
```
|
|
88
111
|
|
|
89
|
-
13.
|
|
112
|
+
13. **Emit the verdict + envelope (no FSM advance).**
|
|
90
113
|
|
|
91
|
-
**
|
|
114
|
+
Persist artifacts + the feedback envelope, then report the verdict and surface `baselines_pending`. **Never call `advance-status`** — the council/human applies the aggregated verdict.
|
|
92
115
|
|
|
93
|
-
|
|
116
|
+
**Pass:**
|
|
117
|
+
1. Commit artifacts: `git add .cloverleaf/ && (git diff --cached --quiet || git commit -m "cloverleaf: <TASK-ID> ui-review verdict (emit-only)")`.
|
|
118
|
+
2. Report, branching on `BASELINES_PENDING`:
|
|
94
119
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
- Report:
|
|
99
|
-
> "✓ UI Review passed (no a11y errors), but **baselines_pending** is true: one or more new or resized visual baselines were captured and require human approval before advancing to qa.
|
|
100
|
-
> Run `/cloverleaf-approve-baselines <TASK-ID>` to review the new baseline images and approve them, which will clear the flag and advance the task to qa."
|
|
101
|
-
- Stop here (task remains in `ui-review` status).
|
|
120
|
+
- If `BASELINES_PENDING` is `true`:
|
|
121
|
+
> "✓ UI Reviewer verdict: **pass** (no a11y errors), but **baselines_pending** is true: one or more new or resized visual baselines were captured and require human approval.
|
|
122
|
+
> This is one council member's verdict — the delivery council (`/cloverleaf-run <TASK-ID>`) or a human applies the aggregated verdict; this skill does not advance the FSM. The runner holds a council **pass** at `baselines_pending`: inspect the new baseline images, then run `/cloverleaf-approve-baselines <TASK-ID>` (which clears the flag) so the re-run's council pass applies."
|
|
102
123
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
cloverleaf-cli advance-status <repo_root> <TASK-ID> qa agent '' full_pipeline
|
|
106
|
-
```
|
|
107
|
-
Commit: `git add .cloverleaf/ && git commit -m "cloverleaf: <TASK-ID> ui-review passed → qa"`.
|
|
108
|
-
Report: "✓ UI Review passed. State → qa. Next: `/cloverleaf-qa <TASK-ID>`."
|
|
124
|
+
- If `BASELINES_PENDING` is `false` (or state.json is absent):
|
|
125
|
+
> "✓ UI Reviewer verdict: **pass** (no a11y errors, no baselines pending). This is one council member's verdict — the delivery council (`/cloverleaf-run <TASK-ID>`) or a human applies the aggregated verdict (`apply-council-verdict`); this skill does not advance the FSM."
|
|
109
126
|
|
|
110
127
|
**Bounce:**
|
|
111
128
|
1. Write feedback: `echo '<envelope-json>' > /tmp/cloverleaf-fb-u.json`
|
|
112
129
|
2. `cloverleaf-cli write-feedback <repo_root> <TASK-ID> /tmp/cloverleaf-fb-u.json --prefix=u`
|
|
113
|
-
3. Commit the persisted feedback file
|
|
130
|
+
3. Commit the persisted feedback file:
|
|
114
131
|
```bash
|
|
115
132
|
cd <repo_root>
|
|
116
133
|
git add .cloverleaf/feedback/
|
|
117
134
|
git commit -m "cloverleaf: <TASK-ID> ui-review feedback"
|
|
118
135
|
```
|
|
119
|
-
4.
|
|
120
|
-
5. Commit: `git add .cloverleaf/ && git commit -m "cloverleaf: <TASK-ID> ui-review bounced → implementing"`.
|
|
121
|
-
6. Report: "✗ UI Review bounced. Findings: <summary by severity>. State → implementing. Next: `/cloverleaf-implement <TASK-ID>`."
|
|
136
|
+
4. Report: "✗ UI Reviewer verdict: **bounce**. Findings: <summary by severity>. Feedback emitted to `.cloverleaf/feedback/<TASK-ID>-u<N>.json`. The delivery council or a human applies the verdict (a council bounce loops the task back to `implementing`); this skill does not advance the FSM."
|
|
122
137
|
|
|
123
138
|
**Escalate:**
|
|
124
|
-
1.
|
|
125
|
-
2.
|
|
126
|
-
3.
|
|
139
|
+
1. Write feedback: `echo '<envelope-json>' > /tmp/cloverleaf-fb-u.json`
|
|
140
|
+
2. `cloverleaf-cli write-feedback <repo_root> <TASK-ID> /tmp/cloverleaf-fb-u.json --prefix=u`
|
|
141
|
+
3. Commit the persisted feedback file:
|
|
142
|
+
```bash
|
|
143
|
+
cd <repo_root>
|
|
144
|
+
git add .cloverleaf/feedback/
|
|
145
|
+
git commit -m "cloverleaf: <TASK-ID> ui-review feedback"
|
|
146
|
+
```
|
|
147
|
+
4. Report: "✗ UI Reviewer verdict: **escalate** (infrastructure issue). Feedback emitted to `.cloverleaf/feedback/<TASK-ID>-u<N>.json`. The council or a human applies the verdict (a council escalate → `escalated`); this skill does not advance the FSM. Review and retry manually."
|
|
127
148
|
|
|
128
149
|
## Rules
|
|
129
150
|
|
|
130
151
|
- Never push.
|
|
131
152
|
- Do not modify source code — UI Reviewer is read-only.
|
|
132
|
-
-
|
|
133
|
-
-
|
|
134
|
-
-
|
|
153
|
+
- **The subagent owns preview-server and worktree teardown** (`ui-reviewer.md` step 13) — including on error. It holds the only handles: `$SERVER_PID` from the backgrounded dev server and `$WT` from `git worktree add`. Neither variable exists in your shell; you never created either resource.
|
|
154
|
+
- Your own cleanup is bounded to what you can reach from the repo root: `git -C <repo_root> worktree prune` clears any worktree registration the subagent left behind.
|
|
155
|
+
- **Never kill by command-line pattern.** `pkill -f "astro dev"` — or `pkill -f "port=$PREVIEW_PORT"` — also matches the command line of the shell running it, so the shell kills itself: exit 144, and every command after it in the same compound statement silently never runs. Cleanup that looked issued never ran.
|
|
156
|
+
- If `$PREVIEW_PORT` is still listening after the subagent returns, report the port rather than killing blind.
|
|
157
|
+
- Empty-set early-exit (step 6) skips the browser entirely — no Playwright invocation, no worktree — and emits a trivial `pass`.
|
|
158
|
+
- Emit-only: never call `advance-status`. This is one council member's verdict; the council/human applies it.
|