|
| 1 | +# picker-demo.tape Refresh Implementation Plan |
| 2 | + |
| 3 | +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. |
| 4 | +
|
| 5 | +**Goal:** Refresh `docs/assets/picker-demo.tape` (and regenerate the GIF) so it reflects the post-PR-#71 picker TUI (3-line rows, 🌲 prefix, right-margin reservation). |
| 6 | + |
| 7 | +**Architecture:** Minimum-diff refresh. Comments inside the tape are updated to the new TUI vocabulary, hover Sleeps are unified to 3000ms, and `picker-demo-setup.sh` gets a small assertion that `chore/cleanup` is recognized as DIRTY (and not prunable). The GIF is regenerated with `vhs`. Picker source code is not touched. |
| 8 | + |
| 9 | +**Tech Stack:** [vhs](https://github.com/charmbracelet/vhs) tape DSL, bash, git. |
| 10 | + |
| 11 | +--- |
| 12 | + |
| 13 | +## File Structure |
| 14 | + |
| 15 | +| File | Responsibility | Action | |
| 16 | +|---|---|---| |
| 17 | +| `docs/assets/picker-demo.tape` | vhs script that drives the picker walkthrough | Modify (comments + Sleep values) | |
| 18 | +| `docs/assets/picker-demo-setup.sh` | Build sandbox repo + 4 worktrees + mock `gh` + fake `HOME` | Modify (add 1 sanity assertion) | |
| 19 | +| `docs/assets/picker-demo.gif` | Demo GIF embedded in `README.md` and `docs/README.ja.md` | Regenerate | |
| 20 | +| `docs/superpowers/specs/2026-04-26-picker-demo-tape-refresh-design.md` | Source spec | Read-only reference | |
| 21 | + |
| 22 | +No new files. No source-code changes. |
| 23 | + |
| 24 | +--- |
| 25 | + |
| 26 | +## Task 1: Update tape comments and Sleep values |
| 27 | + |
| 28 | +**Files:** |
| 29 | + |
| 30 | +- Modify: `docs/assets/picker-demo.tape` |
| 31 | + |
| 32 | +- [ ] **Step 1: Validate the current tape parses** |
| 33 | + |
| 34 | +Run: |
| 35 | + |
| 36 | +```bash |
| 37 | +vhs validate docs/assets/picker-demo.tape |
| 38 | +``` |
| 39 | + |
| 40 | +Expected: exit 0, no output (or `valid` summary). Establishes a clean baseline before edits. |
| 41 | + |
| 42 | +- [ ] **Step 2: Replace the file contents with the refreshed tape** |
| 43 | + |
| 44 | +Open `docs/assets/picker-demo.tape` and replace the entire file with: |
| 45 | + |
| 46 | +```text |
| 47 | +Output "/tmp/ccw-demo.gif" |
| 48 | +
|
| 49 | +Env CCW_LANG en |
| 50 | +
|
| 51 | +Set Shell "bash" |
| 52 | +Set FontSize 24 |
| 53 | +Set Width 1440 |
| 54 | +Set Height 640 |
| 55 | +Set Padding 20 |
| 56 | +Set Theme "Catppuccin Mocha" |
| 57 | +Set TypingSpeed 110ms |
| 58 | +Set PlaybackSpeed 1.0 |
| 59 | +
|
| 60 | +Hide |
| 61 | +Type "cd /tmp/ccw-demo && export HOME=/tmp/ccw-demo-home PATH=/tmp/ccw-demo-bin:/tmp/fake-gh:$PATH && clear" |
| 62 | +Enter |
| 63 | +Sleep 1000ms |
| 64 | +Show |
| 65 | +
|
| 66 | +Type "ccw" |
| 67 | +Enter |
| 68 | +# initial picker view — rows render as 3 lines (🌲 name + status / branch / pr) |
| 69 | +# top row hovered: 🌲 feat-login · [PUSHED] + RESUME + [OPEN] #42 |
| 70 | +Sleep 7000ms |
| 71 | +
|
| 72 | +# walk through every worktree row to show the 4 status × 4 PR-state combos: |
| 73 | +# 🌲 feat-login [PUSHED] [OPEN] → 🌲 feat-dashboard [PUSHED] [MERGED] |
| 74 | +Down |
| 75 | +Sleep 3000ms |
| 76 | +# 🌲 feat-dashboard [PUSHED] [MERGED] → 🌲 feat-picker [LOCAL] [DRAFT] |
| 77 | +Down |
| 78 | +Sleep 3000ms |
| 79 | +# 🌲 feat-picker [LOCAL] [DRAFT] → 🌲 chore-cleanup [DIRTY] [CLOSED] |
| 80 | +Down |
| 81 | +Sleep 3000ms |
| 82 | +
|
| 83 | +# return to feat-dashboard ([PUSHED] + [MERGED] + RESUME) for the submenu demo |
| 84 | +Up |
| 85 | +Sleep 2500ms |
| 86 | +Up |
| 87 | +Sleep 2500ms |
| 88 | +
|
| 89 | +# submenu shows the full worktree path (replaces the path row that used to be in the list) |
| 90 | +# [r] run / [d] delete / [b] back |
| 91 | +Enter |
| 92 | +Sleep 5000ms |
| 93 | +Type "b" |
| 94 | +Sleep 2500ms |
| 95 | +
|
| 96 | +# jump to [clean pushed] — past chore-cleanup and [delete all] |
| 97 | +Down 4 |
| 98 | +Sleep 2500ms |
| 99 | +Enter |
| 100 | +# bulk-confirm screen — preview of pushed targets |
| 101 | +Sleep 5500ms |
| 102 | +
|
| 103 | +# cancel |
| 104 | +Type "N" |
| 105 | +Sleep 2500ms |
| 106 | +
|
| 107 | +# quit picker |
| 108 | +Type "q" |
| 109 | +Sleep 1500ms |
| 110 | +``` |
| 111 | + |
| 112 | +- [ ] **Step 3: Validate the refreshed tape parses** |
| 113 | + |
| 114 | +Run: |
| 115 | + |
| 116 | +```bash |
| 117 | +vhs validate docs/assets/picker-demo.tape |
| 118 | +``` |
| 119 | + |
| 120 | +Expected: exit 0, no errors. Catches typos in `Down` / `Type` / `Sleep` etc. before Task 3. |
| 121 | + |
| 122 | +- [ ] **Step 4: Commit** |
| 123 | + |
| 124 | +```bash |
| 125 | +git add docs/assets/picker-demo.tape |
| 126 | +git commit -m "docs(tape): refresh picker-demo.tape comments for new TUI" |
| 127 | +``` |
| 128 | + |
| 129 | +--- |
| 130 | + |
| 131 | +## Task 2: Add a DIRTY/prunable sanity assertion to setup.sh |
| 132 | + |
| 133 | +**Files:** |
| 134 | + |
| 135 | +- Modify: `docs/assets/picker-demo-setup.sh` (insert block after the chore/cleanup worktree creation) |
| 136 | + |
| 137 | +- [ ] **Step 1: Insert the assertion** |
| 138 | + |
| 139 | +After the `chore/cleanup` worktree creation block (the line that creates `stray.txt` / `extra.md`) and before the `# 4. mock gh` block, insert this snippet: |
| 140 | + |
| 141 | +```bash |
| 142 | +# 3.1 sanity-check: chore/cleanup must be DIRTY and no worktree may be prunable. |
| 143 | +# Both invariants are required for the demo GIF to render the expected badges |
| 144 | +# ([DIRTY] for chore-cleanup, no `(missing on disk)` lines anywhere). |
| 145 | +chore_status=$(cd /tmp/ccw-demo/.claude/worktrees/chore-cleanup && git status --porcelain) |
| 146 | +if [ -z "$chore_status" ]; then |
| 147 | + echo "picker-demo-setup: chore/cleanup is unexpectedly clean — abort." >&2 |
| 148 | + exit 1 |
| 149 | +fi |
| 150 | +if git -C /tmp/ccw-demo worktree list --porcelain | grep -q '^prunable'; then |
| 151 | + echo "picker-demo-setup: a worktree is prunable — abort." >&2 |
| 152 | + exit 1 |
| 153 | +fi |
| 154 | +``` |
| 155 | + |
| 156 | +The exact insertion point: |
| 157 | + |
| 158 | +```bash |
| 159 | +# chore/cleanup: DIRTY (untracked files) + CLOSED PR #45 |
| 160 | +git -C /tmp/ccw-demo worktree add -q -b chore/cleanup .claude/worktrees/chore-cleanup |
| 161 | +(cd /tmp/ccw-demo/.claude/worktrees/chore-cleanup && echo untracked >stray.txt && echo more >extra.md) |
| 162 | + |
| 163 | +# 3.1 sanity-check: chore/cleanup must be DIRTY and no worktree may be prunable. |
| 164 | +# Both invariants are required for the demo GIF to render the expected badges |
| 165 | +# ([DIRTY] for chore-cleanup, no `(missing on disk)` lines anywhere). |
| 166 | +chore_status=$(cd /tmp/ccw-demo/.claude/worktrees/chore-cleanup && git status --porcelain) |
| 167 | +if [ -z "$chore_status" ]; then |
| 168 | + echo "picker-demo-setup: chore/cleanup is unexpectedly clean — abort." >&2 |
| 169 | + exit 1 |
| 170 | +fi |
| 171 | +if git -C /tmp/ccw-demo worktree list --porcelain | grep -q '^prunable'; then |
| 172 | + echo "picker-demo-setup: a worktree is prunable — abort." >&2 |
| 173 | + exit 1 |
| 174 | +fi |
| 175 | + |
| 176 | +# 4. mock gh that returns canned PR rows covering every PR state |
| 177 | +``` |
| 178 | + |
| 179 | +- [ ] **Step 2: Run shellcheck on the script** |
| 180 | + |
| 181 | +Run: |
| 182 | + |
| 183 | +```bash |
| 184 | +shellcheck docs/assets/picker-demo-setup.sh |
| 185 | +``` |
| 186 | + |
| 187 | +Expected: exit 0, no errors. (If `shellcheck` is unavailable locally, lefthook will run it on commit.) |
| 188 | + |
| 189 | +- [ ] **Step 3: Run the setup script end-to-end to confirm the assertions pass** |
| 190 | + |
| 191 | +Run: |
| 192 | + |
| 193 | +```bash |
| 194 | +bash docs/assets/picker-demo-setup.sh |
| 195 | +``` |
| 196 | + |
| 197 | +Expected: |
| 198 | + |
| 199 | +- exit 0 |
| 200 | +- final stdout line: `ready. now run: vhs docs/assets/picker-demo.tape` |
| 201 | +- no `picker-demo-setup: ... — abort.` message on stderr |
| 202 | + |
| 203 | +- [ ] **Step 4: Commit** |
| 204 | + |
| 205 | +```bash |
| 206 | +git add docs/assets/picker-demo-setup.sh |
| 207 | +git commit -m "docs(tape): assert chore/cleanup is DIRTY and no worktree is prunable" |
| 208 | +``` |
| 209 | + |
| 210 | +--- |
| 211 | + |
| 212 | +## Task 3: Regenerate the demo GIF |
| 213 | + |
| 214 | +**Files:** |
| 215 | + |
| 216 | +- Modify: `docs/assets/picker-demo.gif` |
| 217 | + |
| 218 | +- [ ] **Step 1: Run setup** |
| 219 | + |
| 220 | +Run: |
| 221 | + |
| 222 | +```bash |
| 223 | +bash docs/assets/picker-demo-setup.sh |
| 224 | +``` |
| 225 | + |
| 226 | +Expected: exit 0, ends with `ready. now run: vhs docs/assets/picker-demo.tape`. Required even if Task 2 already ran the script — the demo dirs are throwaway. |
| 227 | + |
| 228 | +- [ ] **Step 2: Render the GIF** |
| 229 | + |
| 230 | +Run: |
| 231 | + |
| 232 | +```bash |
| 233 | +vhs docs/assets/picker-demo.tape |
| 234 | +``` |
| 235 | + |
| 236 | +Expected: |
| 237 | + |
| 238 | +- exit 0 |
| 239 | +- `/tmp/ccw-demo.gif` exists and is non-empty |
| 240 | + |
| 241 | +If the command fails because vhs is not installed: install it first (`brew install vhs`) and re-run. |
| 242 | + |
| 243 | +- [ ] **Step 3: Copy the GIF into the repo** |
| 244 | + |
| 245 | +Run: |
| 246 | + |
| 247 | +```bash |
| 248 | +cp /tmp/ccw-demo.gif docs/assets/picker-demo.gif |
| 249 | +``` |
| 250 | + |
| 251 | +- [ ] **Step 4: Visual verification** |
| 252 | + |
| 253 | +Open `docs/assets/picker-demo.gif` in an image viewer and confirm each item below. Stop and re-record (back to Step 1) if any fails. |
| 254 | + |
| 255 | +1. Each worktree row renders as 3 lines: header (`🌲 <name>` + status + indicators), `branch:`, `pr:`. |
| 256 | +2. The 🌲 prefix is visible on every worktree row. |
| 257 | +3. `↑0 ↓0` and other right-aligned indicators are not clipped at the right edge. |
| 258 | +4. The walk-through hovers all four worktrees in this order: |
| 259 | + - `feat/login`: `[PUSHED]` + `[OPEN] #42` + RESUME |
| 260 | + - `feat/dashboard`: `[PUSHED]` + `[MERGED] #44` + RESUME |
| 261 | + - `feat/picker`: `[LOCAL]` + `[DRAFT] #43` + NEW |
| 262 | + - `chore/cleanup`: `[DIRTY]` + `[CLOSED] #45` + NEW |
| 263 | +5. The submenu shows the **full worktree path** along with `[r] run / [d] delete / [b] back`. |
| 264 | +6. The bulk-confirm screen (after `[clean pushed]`) lists the pushed targets as a preview. |
| 265 | +7. `N` cancels back to the picker; `q` quits cleanly. |
| 266 | + |
| 267 | +- [ ] **Step 5: Commit** |
| 268 | + |
| 269 | +```bash |
| 270 | +git add docs/assets/picker-demo.gif |
| 271 | +git commit -m "docs(tape): regenerate picker-demo.gif against new TUI" |
| 272 | +``` |
| 273 | + |
| 274 | +--- |
| 275 | + |
| 276 | +## Self-Review Checklist (already run) |
| 277 | + |
| 278 | +- **Spec coverage:** Comments updated (Task 1), Sleep adjusted to 3000ms (Task 1), setup.sh sanity check (Task 2), regeneration steps (Task 3), all 7 spec verification points covered in Task 3 Step 4. Terminal size unchanged (Task 1 keeps `Width 1440 / Height 640 / FontSize 24`). |
| 279 | +- **Placeholders:** None — every step contains the exact file content, command, or checklist item. |
| 280 | +- **Type / name consistency:** `picker-demo.tape`, `picker-demo-setup.sh`, `picker-demo.gif`, `/tmp/ccw-demo.gif` are spelled identically across tasks. |
0 commit comments