From 562746263b00edc1d62ec61f5ffbed243fa4db92 Mon Sep 17 00:00:00 2001 From: Erwann Mest Date: Wed, 1 Jul 2026 15:30:11 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(revu):=20add=20revu=20plugin?= =?UTF-8?q?=20v1.1.0=20to=20marketplace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Register the revu plugin in marketplace.json (bumps marketplace to v2.3.0), add plugin.json with setup instructions for @kud/revu-cli, and overhaul all three skills: - discuss/implement: prefer live `revu --export --format json --out -` over static file fallbacks; honour severity, status (skip dismissed/resolved), and captured code range - implement: filter by triage state before presenting checklist - watch (new): poll-based live-review partner designed to run under /loop; diffs annotation signatures per run and discusses only new/changed items --- .claude-plugin/marketplace.json | 9 +++- VERSION | 2 +- plugins/revu/.claude-plugin/plugin.json | 15 ++++++ plugins/revu/skills/discuss/SKILL.md | 49 ++++++++++++------- plugins/revu/skills/implement/SKILL.md | 65 +++++++++++++++---------- plugins/revu/skills/watch/SKILL.md | 60 +++++++++++++++++++++++ 6 files changed, 155 insertions(+), 45 deletions(-) create mode 100644 plugins/revu/.claude-plugin/plugin.json create mode 100644 plugins/revu/skills/watch/SKILL.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index e260c36..444ec26 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -6,7 +6,7 @@ "name": "kud" }, "metadata": { - "version": "2.2.0" + "version": "2.3.0" }, "plugins": [ { @@ -71,6 +71,13 @@ "description": "Search and fetch freely-licensed photos from Unsplash — keyword search, random photos, full metadata, collections, and editorial topics.", "source": "./plugins/unsplash", "category": "productivity" + }, + { + "name": "revu", + "version": "1.1.0", + "description": "Turn a revu code review into action — discuss, apply, or live-watch the line annotations you captured in the revu TUI.", + "source": "./plugins/revu", + "category": "development" } ] } diff --git a/VERSION b/VERSION index ccbccc3..276cbf9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.0 +2.3.0 diff --git a/plugins/revu/.claude-plugin/plugin.json b/plugins/revu/.claude-plugin/plugin.json new file mode 100644 index 0000000..59ade96 --- /dev/null +++ b/plugins/revu/.claude-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "revu", + "description": "Turn a revu code review into action — discuss, apply, or live-watch the line annotations you captured in the revu TUI.", + "version": "1.1.0", + "author": { + "name": "kud", + "url": "https://github.com/kud" + }, + "homepage": "https://github.com/kud/revu-cli", + "license": "MIT", + "setup": { + "instructions": "Install the CLI with `npm install -g @kud/revu-cli`, then run `revu` in a git repo to annotate a diff (press ↵ on a line). The skills read the annotations revu autosaves to .revu.json. Verify with: revu --help", + "command": "npm install -g @kud/revu-cli" + } +} diff --git a/plugins/revu/skills/discuss/SKILL.md b/plugins/revu/skills/discuss/SKILL.md index a1630da..e8a1de5 100644 --- a/plugins/revu/skills/discuss/SKILL.md +++ b/plugins/revu/skills/discuss/SKILL.md @@ -1,38 +1,51 @@ --- name: discuss -description: "Reads the revu review export (revu-review.md) or autosave (.revu.json) from the current directory, presents the annotated diff comments for AI review discussion, then asks whether to delete the export file." +description: "Reads the annotations you captured in revu (from .revu.json, via a live headless export) and talks the review through as a senior engineer — leading with blockers, respecting triage state — then offers to clean up any export file." --- -## Step 1 — Find the review data +You are discussing a code review the user captured with revu. Talk it through — you do not implement here (that is the `implement` skill). Lead with the most severe items and honour the user's triage. -Look for `revu-review.md` in the current directory first. If it exists, use it (it contains an optional AI prompt followed by the annotated diff). +## Step 1 — Get the review data -If `revu-review.md` does not exist, fall back to `.revu.json` and parse it as structured JSON (`{ comments: [{ file, startLine, endLine, text }] }`). +Prefer the live, structured export — it carries severity, status, source, and the captured code range, and never needs a file: -If neither file exists, tell the user: +```sh +revu --export --format json --out - +``` -"No review found. Run revu, annotate the diff, then press `e` to export to `revu-review.md`." +Run that in the current directory (add `--against ` if the user is reviewing a PR branch). It prints JSON: `{ prompt, comments: [{ file, startLine, endLine, side, severity, status, source, text, code }] }`. + +Fallbacks, in order, if that command is unavailable or errors: + +1. Read `.revu.json` directly (revu autosaves it on every annotation — same fields, minus `code`). +2. Read `revu-review.md` (the markdown export; parse the annotated sections). + +If none exist, tell the user: + +"No revu review found. Run `revu` in this repo, annotate the diff (press `↵` on a line), and I'll pick it up — no export needed." Then stop. -## Step 2 — Read the review prompt (if present) +## Step 2 — Read the review prompt -If reading `revu-review.md`, check whether it starts with a prompt section before the `---` separator. If so, treat that text as the user's intent for the review — use it to frame your responses throughout the discussion. +If a `prompt` is present (JSON `prompt` field, or the text before the `---` in `revu-review.md`), treat it as the user's intent for the review and let it frame your responses. -## Step 3 — Discuss each annotated section +## Step 3 — Order and filter by triage -Work through each annotation the user left. For each one: +- **Skip** annotations whose `status` is `dismissed` or `resolved` unless the user explicitly asks to include them — the user has already triaged those away. +- **Order** the rest by severity: `blocker` → `concern` → `nitpick` → unset. Discuss blockers first. +- Note the `source`: an annotation with `source: "agent"` came from another AI pass — treat it as a proposal the human is triaging, not a settled decision. -- Acknowledge what the user has flagged -- Respond as a senior code reviewer: surface concrete risks, suggest specific improvements, and ask clarifying questions where the intent behind a change is unclear -- Reference the actual code shown in the snippet — be precise, not generic +## Step 4 — Discuss each annotation -Treat the user's annotations as the primary input. Do not produce a general review of the whole diff; only engage with what the user has marked. +Work through the surviving annotations in severity order. For each: -## Step 4 — Offer to delete the export file +- Name it by `file` and line(s), and its severity if set (e.g. "**blocker** — src/auth.ts:42"). +- Respond as a senior reviewer: surface concrete risks, suggest specific improvements, and ask a clarifying question where the intent is unclear. +- Reference the actual `code` in the snippet — be precise, not generic. -After the full discussion, ask: +Treat the user's annotations as the only agenda. Do not produce a general review of the whole diff; engage only with what they marked. -"Delete `revu-review.md`?" +## Step 5 — Offer to clean up -If the user confirms yes, delete it using `trash revu-review.md` (fallback: `rm revu-review.md`). Do not delete `.revu.json` — that is the autosave and should persist across sessions. +If you read `revu-review.md`, ask at the end: "Delete `revu-review.md`?" — and if yes, remove it with `trash revu-review.md` (fallback `rm`). Never delete `.revu.json`: it is the live autosave and must persist across sessions. diff --git a/plugins/revu/skills/implement/SKILL.md b/plugins/revu/skills/implement/SKILL.md index 638926e..f60447d 100644 --- a/plugins/revu/skills/implement/SKILL.md +++ b/plugins/revu/skills/implement/SKILL.md @@ -1,59 +1,74 @@ --- name: implement -description: "Apply the review comments from a revu export (.revu.json or revu-review.md) in the current directory: present them as a checklist, confirm, implement each exactly as written, then offer to delete the export." +description: "Apply the review annotations you captured in revu: read them (via a live headless export), present a severity-ordered checklist, skip anything dismissed, confirm, implement each exactly as written, then offer to clean up and run lint/tests." --- -You are implementing the review comments captured by revu. Your job is to read the review data, present it clearly, get explicit confirmation, then implement each comment exactly as written. This is the counterpart to `discuss`: `discuss` talks the review through, `implement` applies it. +You are implementing the review annotations captured by revu. Read the review data, present it clearly, get explicit confirmation, then implement each annotation exactly as written. This is the counterpart to `discuss`: `discuss` talks the review through, `implement` applies it. -## Step 1 — Find the review data +## Step 1 — Get the review data -Look for these in the current working directory, in order: +Prefer the live, structured export — it carries severity, status, source, and the captured code range: -1. `.revu.json` — structured JSON, preferred because it is directly implementable. Accept either a root array or an object with a `comments` key: - - `{ "comments": [ { "file": "...", "startLine": 42, "endLine": 42, "text": "..." }, ... ] }` - - or a root array of the same comment objects. -2. `revu-review.md` — fall back to parsing the annotated diff comments if no `.revu.json` exists. +```sh +revu --export --format json --out - +``` + +Run that in the current directory (add `--against ` for a PR-branch review). It prints `{ prompt, comments: [{ file, startLine, endLine, side, severity, status, source, text, code }] }`. + +Fallbacks, in order, if that command is unavailable or errors: + +1. Read `.revu.json` directly (accept an object with a `comments` key, or a root array of the same objects). +2. Read `revu-review.md` and parse the annotated sections. + +If none exists, tell the user to annotate a diff in `revu` first, then stop. If the data is empty or malformed, say so and stop. + +## Step 2 — Filter by triage + +Before listing anything: + +- **Skip** annotations whose `status` is `dismissed` (the user rejected them) or `resolved` (already handled). Do not implement these. Note how many you skipped and why. +- Keep `open` and `accepted` annotations — those are the work. -If neither file exists, tell the user to export a review from revu first, then stop. If the file is empty or malformed, tell the user and stop. +If filtering leaves nothing to do, tell the user everything is dismissed/resolved and stop. -## Step 2 — Display the checklist +## Step 3 — Display the checklist -Group comments by file and present a numbered TODO checklist: +Group the surviving annotations by file, **ordered by severity** (blocker → concern → nitpick → unset), and show severity + source per item: ``` Files to update: src/foo.ts - [ ] 1. Line 42 — Extract this into a named function - [ ] 2. Line 87 — Remove dead code + [ ] 1. blocker · L42 — Extract this into a named function + [ ] 2. nitpick · L87 — Remove dead code (source: agent) src/bar.ts - [ ] 3. Line 12 — Rename variable for clarity + [ ] 3. concern · L12 — Rename variable for clarity ``` -Show the total: **N comments across M files**. +Show the total: **N annotations across M files** (and **K skipped as dismissed/resolved**). -## Step 3 — Confirmation gate +## Step 4 — Confirmation gate -Ask explicitly: **"Proceed to implement all N comments? (yes / no)"** +Ask explicitly: **"Proceed to implement all N annotations? (yes / no)"** Do not change anything until the user says yes. If they don't, stop and wait. -## Step 4 — Implement +## Step 5 — Implement -Work file by file. For each comment, make exactly the change its text describes at the given line — no unrelated edits, no scope creep. Batch the edits per file. If a comment is ambiguous, implement your best interpretation and flag it to the user afterwards. +Work file by file, blockers first. For each annotation, make exactly the change its `text` describes at the given line — no unrelated edits, no scope creep. Use the `code` snippet to locate the exact spot. Batch the edits per file. If an annotation is ambiguous, implement your best interpretation and flag it to the user afterwards. -## Step 5 — Offer to delete the export +## Step 6 — Offer to clean up -Once every comment has been implemented, ask: **"Delete the review export (.revu.json / revu-review.md)? (yes / no)"** Delete it only if the user agrees and all comments were processed without error. +Once every annotation is implemented, ask: **"Delete the review export? (yes / no)"** — this refers to `revu-review.md` only. Delete it with `trash` (fallback `rm`) if the user agrees and all annotations were processed without error. Never delete `.revu.json` — it is the live autosave. -## Step 6 — Offer lint/tests +## Step 7 — Offer lint/tests Ask whether to run the project's lint and tests, and run them if the user agrees. ## Constraints -- Never implement anything before explicit confirmation in step 3. -- Implement comments exactly as written — do not interpret loosely or add unrequested changes. -- Do not delete the export unless all comments were processed successfully. +- Never implement anything before explicit confirmation in step 4. +- Never implement a `dismissed` or `resolved` annotation. +- Implement annotations exactly as written — do not interpret loosely or add unrequested changes. - If any edit fails, pause and ask the user how to proceed before continuing. diff --git a/plugins/revu/skills/watch/SKILL.md b/plugins/revu/skills/watch/SKILL.md new file mode 100644 index 0000000..2799890 --- /dev/null +++ b/plugins/revu/skills/watch/SKILL.md @@ -0,0 +1,60 @@ +--- +name: watch +description: "Live-watch the revu review: on each run, detect annotations added or changed in .revu.json since last time and discuss just those. Designed to run under /loop for a hands-free side-by-side session (you annotate in revu, Claude reacts). Discusses only — never edits code." +--- + +This skill turns revu into a live review partner. You annotate lines in revu on one side; on the other, this skill picks up each new annotation and discusses it — as it happens. + +Claude Code cannot be woken by a file change, so "live" means **polling**: run this skill under the `/loop` primitive. Each run is cheap when nothing changed. + +**Recommended invocation:** + +``` +/loop 15s /revu:watch +``` + +Stop the loop when you're done reviewing (or it stops itself after a period of no changes — see Step 4). + +## Step 1 — Snapshot the current annotations + +Get the current review (prefer the live export, which carries severity/status/source): + +```sh +revu --export --format json --out - +``` + +Fall back to reading `.revu.json` directly if that errors. If there are no annotations at all, say "waiting for annotations…" briefly and stop this run. + +## Step 2 — Load the last-seen state + +Read the state file for this repo: + +``` +${TMPDIR:-/tmp}/revu-watch-.json +``` + +It holds the signatures seen on the previous run. A signature per annotation is: `file:side:startLine:endLine` + `|` + `severity` + `|` + `status` + `|` + a short hash (or the first ~40 chars) of `text`. If the state file is missing, treat every current annotation as new. + +## Step 3 — Diff and discuss the new/changed ones + +Compute which annotations are **new** (signature not in last-seen) or **changed** (same location, different severity/status/text). If there are none, say "no new annotations" in one line and go to Step 4. + +For each new or changed annotation, in severity order (blocker → concern → nitpick → unset): + +- Name it (`file:line`, severity) and, if it changed, what changed (e.g. "you bumped this to blocker", "you marked this dismissed"). +- Give a short, senior-engineer take: the risk, a concrete suggestion, or a clarifying question. Keep it tight — this is a live stream, not a full report. +- Skip anything now `dismissed` or `resolved` except to acknowledge in one line that the user triaged it away. + +Do **not** edit any code. This skill discusses only. If the user wants changes applied, they run `/revu:implement` explicitly. + +## Step 4 — Update state and pace the loop + +Write the current signatures back to the state file so the next run only surfaces what's newer. + +To avoid spinning forever: keep a small counter in the state file of consecutive "no new annotations" runs. After ~20 idle runs (e.g. ~5 minutes at 15s), say the review looks idle and suggest stopping the loop — do not schedule another wake-up yourself; the `/loop` harness controls cadence. + +## Constraints + +- Discuss only — never modify files. `implement` is the only skill that edits code, and only behind its confirmation gate. +- Never delete `.revu.json` — it is the live channel. +- Keep each run's output short; this is meant to stream alongside an open revu session.