Skip to content

Commit 2fe06ab

Browse files
authored
Merge branch 'main' into docs/github-actions-task-cache
2 parents ec324fd + 6a5c472 commit 2fe06ab

446 files changed

Lines changed: 22891 additions & 8434 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
name: test-pkg-pr-new-migrate
3+
description: Verify a pkg.pr.new build of vite-plus against a real project before release — run `vp migrate` from the pkg.pr.new commit against a local project, deps resolved through the registry bridge. Use when asked to verify/e2e-test a pkg.pr.new build against a project, "test PR #<N> on <project>", or check a prerelease against a repo.
4+
allowed-tools: Bash, Read
5+
---
6+
7+
# Verify a pkg.pr.new build against one project
8+
9+
Installs an isolated global `vp` built from a registry bridge commit build and runs `vp migrate` on a specified local project. The global CLI and the migrated project both pin `vite-plus`/`vite` to the clearly-defined `0.0.0-commit.<sha>` build. `vp migrate` itself writes the bridge registry into the project's `.npmrc` (or `.yarnrc.yml` for Yarn Berry) so the deps resolve, during this run and in the project's own CI; this script only force-stages that file past `.gitignore`.
10+
11+
Required inputs: a `<PR-or-SHA>` (the build to verify) and a `<project-path>`. If either is missing from the request, **ask the user** for it — never guess the PR/SHA, as the build under test is the user's choice.
12+
13+
```bash
14+
.github/scripts/test-pkg-pr-new-migrate.sh <PR-or-SHA> <project-path> [migrate-options...]
15+
# e.g.
16+
.github/scripts/test-pkg-pr-new-migrate.sh 1891 /path/to/npmx.dev --no-interactive
17+
```
18+
19+
- First arg is a PR number or commit SHA; the script resolves the immutable commit via the bridge `x-commit-key` header and verifies the bridge serves it (the pkg.pr.new publish workflow registers each commit).
20+
- Never touches `~/.vite-plus`; clears only the workspace ROOT lockfile + `node_modules` before migrating; refuses a dirty worktree unless `ALLOW_DIRTY=1`; prints the project's `git status`/`diff` at the end — inspect that to confirm the migration result.
21+
22+
**The build under test must include the "migrate writes the bridge registry" feature** (this session's work / current branch head onward). The harness no longer writes the registry itself — it relies on `vp migrate` doing it. Testing an older build with this harness would leave the project with no bridge registry, so its deps resolve from npmjs (`ERR_PNPM_NO_MATCHING_VERSION` on the `0.0.0-commit.<sha>` version). Always verify a fresh build of the branch, not a stale published commit.
23+
24+
The script prints the resolved versions at the end, querying one package at a time (npm/yarn/bun `why` only accept a single package; `-r` is pnpm-only). Each must resolve to exactly ONE version: `vite-plus` and `vite` at the expected `0.0.0-commit.<sha>` (vite via the `@voidzero-dev/vite-plus-core` alias), `vitest` at the bundled upstream version. Multiple versions, or a stale/wrong version, means the migration or install is broken. To re-check by hand:
25+
26+
```bash
27+
cd <project-path>
28+
# pnpm: one call, recursive across workspaces
29+
vp why -r vite-plus vite vitest
30+
# npm / yarn / bun: one package per call, no -r
31+
vp why vite-plus && vp why vite && vp why vitest
32+
```
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
name: verify-interactive-cli
3+
description: Drive and capture vp's interactive (clack) prompts in a tmux session to verify interactive UX and catch spinner-over-prompt bugs that snap tests (which run non-interactively) miss. Use when asked to test/verify/capture an interactive vp command's prompts (vp migrate, vp create, ...), reproduce a prompt-rendering bug, or show the real interactive CLI output for a PR.
4+
allowed-tools: Bash, Read
5+
---
6+
7+
# Verify vp's interactive CLI prompts
8+
9+
Snap tests run `vp` non-interactively, so interactive clack prompts (hooks / agent / editor confirms, the Node-version upgrade confirm) and TTY-only rendering bugs are never exercised. This skill drives the real prompts in a TTY (via tmux), captures clean output, and can catch a spinner animating underneath an active prompt (a real, recurring UX bug class, e.g. the "Preparing migration" and "Checking Node.js version support" spinners).
10+
11+
## Prerequisites
12+
13+
- `tmux` (macOS has none by default): `brew install tmux`.
14+
- The global `vp` must contain the code under test. To exercise working-tree changes, rebuild first: `pnpm bootstrap-cli` (~5 min), then confirm with `vp --version`.
15+
16+
## Driver
17+
18+
`interactive-cli-tmux-driver.sh` is bundled in this skill's directory.
19+
20+
```bash
21+
# Run to completion, auto-accepting every prompt's DEFAULT; prints a clean transcript.
22+
.claude/skills/verify-interactive-cli/interactive-cli-tmux-driver.sh <project-dir> "vp migrate"
23+
24+
# STOP at a specific prompt (do NOT answer it) and check for a spinner animating under it.
25+
.claude/skills/verify-interactive-cli/interactive-cli-tmux-driver.sh <project-dir> "vp migrate" "Upgrade Node.js"
26+
```
27+
28+
How it works:
29+
30+
- Runs the command in a detached tmux session; `tmux capture-pane -p` yields clean text (clack's in-place redraws overwrite, so only resolved lines remain), far cleaner than `expect`'s raw ANSI capture.
31+
- Auto-accepts each prompt's default by sending Enter when the pane goes STABLE. A waiting prompt is static; animating spinners keep the pane changing, so Enter never fires mid-work.
32+
- End-detection uses `; echo "$M1$M2 exit=$?"` where M1/M2 are split vars, so the literal end marker is not in the typed command line (otherwise a grep matches the echoed command, not the program output).
33+
- With a STOP_AT regex it halts at the target prompt and captures twice ~3s apart: identical captures = static prompt (OK); differing captures (or a `Checking ... (Xs)` line) = a spinner is animating under the prompt = a UX bug.
34+
35+
## Setting up a target project
36+
37+
Create a throwaway project that triggers the prompts you want to see, e.g. a fresh Vite app whose `.node-version` is below the supported range to exercise the Node-upgrade confirm:
38+
39+
```bash
40+
mkdir -p /tmp/vp-demo && cd /tmp/vp-demo
41+
printf '{\n "name":"d","private":true,"type":"module","packageManager":"pnpm@10.18.0",\n "scripts":{"build":"vite build","test":"vitest run"},\n "devDependencies":{"vite":"^8.0.0","vitest":"^4.1.0"}\n}\n' > package.json
42+
echo "24.3.0" > .node-version
43+
printf 'import { defineConfig } from "vite";\nexport default defineConfig({});\n' > vite.config.ts
44+
git init -q && git add -A && git -c user.email=x@x -c user.name=x commit -qm init
45+
```
46+
47+
## When you find a spinner-over-prompt bug
48+
49+
Fix it test-first: the prompt's code must pause the migration progress spinner before the confirm renders. Assert the call order is `['pause', 'confirm']`. Reference fix: `upgradeUnsupportedNodeVersions` (in `packages/cli/src/migration/migrator/setup.ts`) takes a `pauseProgress` callback that `bin.ts` wires to `clearMigrationProgress`, called right before `prompts.confirm`.
50+
51+
## Gotchas
52+
53+
- clack's active-prompt marker here is `` (not always ``); detect a waiting prompt by pane stability, not a specific glyph.
54+
- `VP_SKIP_INSTALL=1` skips the dependency install but breaks steps that load `vite.config.ts` (e.g. the prettier auto-migration) because `vite` isn't installed; use it only when you stop before the install step.
55+
- A `&` inside a background task detaches the script, so the task reports "completed" early while it keeps running; poll a status file or `capture-pane` to track real progress.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#!/bin/bash
2+
# Drive and capture an interactive `vp` (clack) prompt flow inside tmux, to verify
3+
# interactive UX that snap tests (which run non-interactively) never cover.
4+
#
5+
# Usage:
6+
# interactive-cli-tmux-driver.sh <project-dir> "<command>" [STOP_AT_REGEX]
7+
# interactive-cli-tmux-driver.sh /tmp/demo "vp migrate"
8+
# interactive-cli-tmux-driver.sh /tmp/demo "vp migrate" "Upgrade Node.js"
9+
#
10+
# No STOP_AT : run to completion, auto-accepting every prompt's DEFAULT (Enter),
11+
# then print a clean transcript.
12+
# With STOP_AT: drive prompts until one matching the regex appears, then STOP
13+
# (do NOT answer it) and capture the pane twice 3s apart. Identical
14+
# captures => prompt is static (good). Differing captures (or a
15+
# "Checking ... (Xs)" line) => a spinner is animating UNDER the
16+
# prompt -- a real UX bug (this is how the Node-upgrade confirm
17+
# spinner-overlap was found).
18+
#
19+
# Why tmux and not `expect`: expect's raw capture is full of ANSI cursor/redraw
20+
# noise; `tmux capture-pane -p` returns clean text because in-place redraws
21+
# overwrite and only the resolved lines remain in scrollback.
22+
# macOS has no tmux/timeout by default: `brew install tmux`.
23+
set -u
24+
DIR="${1:?project dir}"; CMD="${2:?command, e.g. \"vp migrate\"}"; STOP_AT="${3:-}"
25+
command -v tmux >/dev/null || { echo "need tmux: brew install tmux" >&2; exit 1; }
26+
S="clicap_$$"
27+
cap1="$(mktemp)"; cap2="$(mktemp)"
28+
29+
tmux kill-session -t "$S" 2>/dev/null
30+
tmux new-session -d -s "$S" -x 100 -y 50
31+
tmux set-option -t "$S" history-limit 50000
32+
# M1/M2 are split so the end marker never appears in the TYPED command line --
33+
# otherwise a grep for it matches the echoed command, not the program output.
34+
tmux send-keys -t "$S" 'export PS1="$ " PROMPT="%% " M1=CLI M2=CAPDONE' Enter; sleep 1
35+
tmux send-keys -t "$S" "cd '$DIR'" Enter; sleep 1
36+
tmux send-keys -t "$S" 'clear' Enter; sleep 1
37+
tmux send-keys -t "$S" "$CMD"'; echo "$M1$M2 exit=$?"' Enter
38+
39+
prev=""; stable=0; sent=0
40+
for i in $(seq 1 180); do
41+
sleep 2
42+
pane="$(tmux capture-pane -t "$S" -p -S -120 2>/dev/null)"
43+
# reached the prompt we want to inspect -> stop without answering it
44+
if [ -n "$STOP_AT" ] && printf '%s' "$pane" | grep -q "$STOP_AT"; then
45+
tmux capture-pane -t "$S" -p -S -60 > "$cap1"; sleep 3
46+
tmux capture-pane -t "$S" -p -S -60 > "$cap2"
47+
if diff -q "$cap1" "$cap2" >/dev/null; then
48+
echo "STATIC prompt (nothing animating underneath) -- OK"
49+
else
50+
echo "ANIMATING under the prompt (likely spinner-over-prompt bug):"
51+
diff "$cap1" "$cap2"
52+
fi
53+
echo "--- prompt ---"; sed -n "/$STOP_AT/,\$p" "$cap1"
54+
tmux kill-session -t "$S" 2>/dev/null; rm -f "$cap1" "$cap2"; exit 0
55+
fi
56+
# program finished
57+
printf '%s' "$pane" | grep -q "CLICAPDONE exit=" && break
58+
# A waiting prompt makes the pane STABLE; animating spinners keep it changing,
59+
# so this won't fire mid-work. Accept the default with Enter, once per state.
60+
if [ "$pane" = "$prev" ]; then
61+
stable=$((stable+1))
62+
if [ "$stable" -ge 2 ] && [ "$sent" -eq 0 ]; then tmux send-keys -t "$S" Enter; sent=1; fi
63+
else
64+
prev="$pane"; stable=0; sent=0
65+
fi
66+
done
67+
68+
echo "=== clean transcript ==="
69+
tmux capture-pane -t "$S" -p -S -3000
70+
tmux kill-session -t "$S" 2>/dev/null; rm -f "$cap1" "$cap2"

0 commit comments

Comments
 (0)