Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
b662966
docs(rfc): vp migrate upgrade path for existing Vite+ projects
fengmk2 Jun 10, 2026
8998baf
docs(rfc): cover real 0.1.24->0.2.0 upgrade failure in vp migrate
fengmk2 Jun 18, 2026
94aa32f
docs(rfc): align vp migrate upgrade with the v0.2.1 prompt spec
fengmk2 Jun 18, 2026
3d30ccc
fix(migrate): make vp migrate upgrade v0.1.x projects to v0.2.x
fengmk2 Jun 18, 2026
8eb837d
feat(migrate): manage vitest only when the project uses it directly
fengmk2 Jun 18, 2026
e82435a
feat(migrate): align the full @vitest/* ecosystem to the bundled vitest
fengmk2 Jun 19, 2026
26968b3
docs(rfc): revise migrate RFC for vitest provisioning and ecosystem r…
fengmk2 Jun 19, 2026
f2b0fda
fix(migrate): make upgrade provisioning peer-safe
fengmk2 Jun 19, 2026
744e9d8
fix(migrate): validate upgrade scenarios in snapshots
fengmk2 Jun 19, 2026
c8b175b
test(migrate): update default vitest snapshots
fengmk2 Jun 21, 2026
15ca945
fix(migrate): handle peer and override edge cases
fengmk2 Jun 21, 2026
04c57a6
fix(migrate): cover remaining vitest upgrade cases
fengmk2 Jun 21, 2026
f443a5b
fix(test): normalize snapshot file endings
fengmk2 Jun 21, 2026
4e3e6e1
test(migrate): sync idempotency snapshots
fengmk2 Jun 21, 2026
bfc958b
test(create): update standalone Yarn catalog snapshot
fengmk2 Jun 21, 2026
e282708
fix(migrate): preserve vitest imports for Nuxt tests
fengmk2 Jun 23, 2026
774bc8f
test(ecosystem-ci): update npmx.dev fixture
fengmk2 Jun 23, 2026
461bbc6
test(cli): stabilize Nuxt lint snapshot
fengmk2 Jun 23, 2026
92c88a0
fix(migrate): preserve Vitest across Nuxt packages
fengmk2 Jun 23, 2026
3606535
fix(migrate): convert Yarn PnP projects
fengmk2 Jun 23, 2026
b2b6d6e
test(ecosystem): install Playwright for npmx.dev
fengmk2 Jun 23, 2026
b814002
test(migrate): cover conservative monorepo retention
fengmk2 Jun 23, 2026
d7ea7f9
fix(migrate): pin pkg.pr.new targets in test helper
fengmk2 Jun 23, 2026
63a0861
fix(test): keep pkg.pr.new overrides minimal
fengmk2 Jun 23, 2026
d199e90
fix(migrate): allow pkg.pr.new pnpm subdependencies
fengmk2 Jun 23, 2026
9f245c9
fix(test): refresh mutable pkg.pr.new installs
fengmk2 Jun 24, 2026
4a0bac7
fix(migrate): preserve Vitest ecosystem catalogs
fengmk2 Jun 24, 2026
c88d00d
fix(migrate): pin vite-plus toolchain versions
fengmk2 Jun 24, 2026
23832e1
fix(test): reuse unchanged pkg.pr.new install
fengmk2 Jun 24, 2026
26343f3
fix(test): run pkg.pr.new migration from project root
fengmk2 Jun 24, 2026
cbc03da
fix(migrate): isolate config compatibility checks
fengmk2 Jun 24, 2026
3292590
fix(test): pin pkg.pr.new migration builds by commit
fengmk2 Jun 24, 2026
a593aa3
fix(migrate): move pnpm settings to workspace config
fengmk2 Jun 25, 2026
94937cd
docs(migrate): document user-facing migration rules
fengmk2 Jun 25, 2026
27034b4
test(migrate): update migration snapshots
fengmk2 Jun 25, 2026
ed11ef3
docs(migrate): clarify pnpm vite dependency rule
fengmk2 Jun 25, 2026
bea36b2
fix(migrate): format projects after migration
fengmk2 Jun 25, 2026
a960740
fix(migrate): preserve unmigrated Prettier projects
fengmk2 Jun 25, 2026
98fa5c8
fix(migrate): detect legacy browser providers
fengmk2 Jun 25, 2026
18a6a56
fix(ci): upgrade affected pnpm 11 versions for pkg.pr.new tests
fengmk2 Jun 26, 2026
d71857e
fix(migrate): preserve Bun config arrays
fengmk2 Jun 26, 2026
b579b81
fix(migrate): avoid Bun peer suppression
fengmk2 Jun 26, 2026
2a9225a
fix(ci): support Bun pkg.pr.new migration tests
fengmk2 Jun 26, 2026
aa5a0c7
fix(ci): satisfy lint in Bun pkg helper
fengmk2 Jun 26, 2026
3ff95bb
fix(migrate): rewrite tools invoked through bunx
fengmk2 Jun 26, 2026
95ea87f
fix(migrate): limit automatic formatting to changed files
fengmk2 Jun 26, 2026
1194a1d
fix(migrate): defer supported formats to oxfmt
fengmk2 Jun 26, 2026
c8432dc
fix(ci): upgrade affected pnpm 10 pkg-pr-new tests
fengmk2 Jun 26, 2026
fa32021
fix(migrate): address review feedback
fengmk2 Jun 26, 2026
b3f6c55
fix(migrate): preserve pnpm catalog layouts
fengmk2 Jun 26, 2026
7da35ef
test(migrate): use release version for default catalog
fengmk2 Jun 26, 2026
bd63c0d
fix(migrate): address remaining review feedback
fengmk2 Jun 27, 2026
c70b63c
fix(migrate): address upgrade-path review findings
fengmk2 Jun 27, 2026
19f44cc
ci(migrate): verify pkg.pr.new builds through the registry bridge
fengmk2 Jun 27, 2026
1cde19e
chore(migrate): fix oxfmt formatting and refresh global migration snaps
fengmk2 Jun 27, 2026
d13148f
ci(migrate): persist bridge registry into project .npmrc and .yarnrc.yml
fengmk2 Jun 27, 2026
7d73cd9
fix(migrate): do not duplicate vite-plus into devDependencies
fengmk2 Jun 27, 2026
094397c
refactor(migrate): split migrator.ts into category modules
fengmk2 Jun 27, 2026
64b580a
docs(agents): point to the migrator/ structure guide
fengmk2 Jun 27, 2026
089f609
chore(skills): add test-pkg-pr-new-migrate skill
fengmk2 Jun 27, 2026
f359808
fix(migrate): normalize protocol-pinned vite-plus under force-override
fengmk2 Jun 27, 2026
142e5e9
fix(migrate): address PR review feedback
fengmk2 Jun 27, 2026
87b376d
test(migrate): drop pkg.pr.new force-override in favor of the bridge
fengmk2 Jun 27, 2026
d83d6fd
test: regenerate command-upgrade-check for the bounded normalizer
fengmk2 Jun 27, 2026
a1f7495
ci(pkg-pr-new): comment the bridge version on the PR after registration
fengmk2 Jun 27, 2026
b06c350
style: run oxfmt on bridge-comment-template.md
fengmk2 Jun 27, 2026
0e26437
refactor(migrate): group Rolldown compat files under compat/
fengmk2 Jun 27, 2026
c0970dc
fix(migrate): preserve the bunx --bun flag when rewriting to vp
fengmk2 Jun 27, 2026
823decd
fix(migrate): clear the progress spinner before the upgrade prompts
fengmk2 Jun 27, 2026
5e3e95e
feat(migrate): upgrade below-range Node versions to the latest supported
fengmk2 Jun 28, 2026
104bf6d
fix(migrate): make the rolldown-compat worker-path test Windows-safe
fengmk2 Jun 28, 2026
d9c74ff
chore(skills): add verify-interactive-cli
fengmk2 Jun 28, 2026
941383b
refactor(ci): build the pkg.pr.new bridge comment with github-script
fengmk2 Jun 28, 2026
fbe8d5c
refactor(migrate): simplify node-version binding, format, and vitest …
fengmk2 Jun 28, 2026
26a7c5d
Merge remote-tracking branch 'origin/main' into rfc/migrate-upgrade-path
fengmk2 Jun 28, 2026
8ec6428
docs(migrate): drop the interactive-confirm note from Node.js version…
fengmk2 Jun 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .claude/skills/test-pkg-pr-new-migrate/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
name: test-pkg-pr-new-migrate
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.
allowed-tools: Bash, Read
---

# Verify a pkg.pr.new build against one project

Installs an isolated global `vp` from a pkg.pr.new commit and runs `vp migrate` on a specified local project. The result pins `vite-plus`/`vite` to `0.0.0-commit.<sha>` resolved through the registry bridge, persisted into the project's `.npmrc` (and `.yarnrc.yml` for Yarn Berry) so the project's own CI installs the build too.

Required inputs: a `<PR-or-SHA>` (the pkg.pr.new 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.

```bash
.github/scripts/test-pkg-pr-new-migrate.sh <PR-or-SHA> <project-path> [migrate-options...]
# e.g.
.github/scripts/test-pkg-pr-new-migrate.sh 1891 /path/to/npmx.dev --no-interactive
```

- First arg is a PR number or commit SHA; the script resolves the immutable commit and verifies the bridge serves it (the pkg.pr.new publish workflow registers each commit).
- Never touches `~/.vite-plus`; 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.

Then confirm the resolved versions (`-r` across workspaces for monorepos):

```bash
cd <project-path>
vp why -r vite-plus vite vitest
```

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.
55 changes: 55 additions & 0 deletions .claude/skills/verify-interactive-cli/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
name: verify-interactive-cli
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.
allowed-tools: Bash, Read
---

# Verify vp's interactive CLI prompts

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).

## Prerequisites

- `tmux` (macOS has none by default): `brew install tmux`.
- 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`.

## Driver

`interactive-cli-tmux-driver.sh` is bundled in this skill's directory.

```bash
# Run to completion, auto-accepting every prompt's DEFAULT; prints a clean transcript.
.claude/skills/verify-interactive-cli/interactive-cli-tmux-driver.sh <project-dir> "vp migrate"

# STOP at a specific prompt (do NOT answer it) and check for a spinner animating under it.
.claude/skills/verify-interactive-cli/interactive-cli-tmux-driver.sh <project-dir> "vp migrate" "Upgrade Node.js"
```

How it works:

- 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.
- 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.
- 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).
- 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.

## Setting up a target project

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:

```bash
mkdir -p /tmp/vp-demo && cd /tmp/vp-demo
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
echo "24.3.0" > .node-version
printf 'import { defineConfig } from "vite";\nexport default defineConfig({});\n' > vite.config.ts
git init -q && git add -A && git -c user.email=x@x -c user.name=x commit -qm init
```

## When you find a spinner-over-prompt bug

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`.

## Gotchas

- clack's active-prompt marker here is `›` (not always `◆`); detect a waiting prompt by pane stability, not a specific glyph.
- `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.
- 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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/bin/bash
# Drive and capture an interactive `vp` (clack) prompt flow inside tmux, to verify
# interactive UX that snap tests (which run non-interactively) never cover.
#
# Usage:
# interactive-cli-tmux-driver.sh <project-dir> "<command>" [STOP_AT_REGEX]
# interactive-cli-tmux-driver.sh /tmp/demo "vp migrate"
# interactive-cli-tmux-driver.sh /tmp/demo "vp migrate" "Upgrade Node.js"
#
# No STOP_AT : run to completion, auto-accepting every prompt's DEFAULT (Enter),
# then print a clean transcript.
# With STOP_AT: drive prompts until one matching the regex appears, then STOP
# (do NOT answer it) and capture the pane twice 3s apart. Identical
# captures => prompt is static (good). Differing captures (or a
# "Checking ... (Xs)" line) => a spinner is animating UNDER the
# prompt -- a real UX bug (this is how the Node-upgrade confirm
# spinner-overlap was found).
#
# Why tmux and not `expect`: expect's raw capture is full of ANSI cursor/redraw
# noise; `tmux capture-pane -p` returns clean text because in-place redraws
# overwrite and only the resolved lines remain in scrollback.
# macOS has no tmux/timeout by default: `brew install tmux`.
set -u
DIR="${1:?project dir}"; CMD="${2:?command, e.g. \"vp migrate\"}"; STOP_AT="${3:-}"
command -v tmux >/dev/null || { echo "need tmux: brew install tmux" >&2; exit 1; }
S="clicap_$$"
cap1="$(mktemp)"; cap2="$(mktemp)"

tmux kill-session -t "$S" 2>/dev/null
tmux new-session -d -s "$S" -x 100 -y 50
tmux set-option -t "$S" history-limit 50000
# M1/M2 are split so the end marker never appears in the TYPED command line --
# otherwise a grep for it matches the echoed command, not the program output.
tmux send-keys -t "$S" 'export PS1="$ " PROMPT="%% " M1=CLI M2=CAPDONE' Enter; sleep 1
tmux send-keys -t "$S" "cd '$DIR'" Enter; sleep 1
tmux send-keys -t "$S" 'clear' Enter; sleep 1
tmux send-keys -t "$S" "$CMD"'; echo "$M1$M2 exit=$?"' Enter

prev=""; stable=0; sent=0
for i in $(seq 1 180); do
sleep 2
pane="$(tmux capture-pane -t "$S" -p -S -120 2>/dev/null)"
# reached the prompt we want to inspect -> stop without answering it
if [ -n "$STOP_AT" ] && printf '%s' "$pane" | grep -q "$STOP_AT"; then
tmux capture-pane -t "$S" -p -S -60 > "$cap1"; sleep 3
tmux capture-pane -t "$S" -p -S -60 > "$cap2"
if diff -q "$cap1" "$cap2" >/dev/null; then
echo "STATIC prompt (nothing animating underneath) -- OK"
else
echo "ANIMATING under the prompt (likely spinner-over-prompt bug):"
diff "$cap1" "$cap2"
fi
echo "--- prompt ---"; sed -n "/$STOP_AT/,\$p" "$cap1"
tmux kill-session -t "$S" 2>/dev/null; rm -f "$cap1" "$cap2"; exit 0
fi
# program finished
printf '%s' "$pane" | grep -q "CLICAPDONE exit=" && break
# A waiting prompt makes the pane STABLE; animating spinners keep it changing,
# so this won't fire mid-work. Accept the default with Enter, once per state.
if [ "$pane" = "$prev" ]; then
stable=$((stable+1))
if [ "$stable" -ge 2 ] && [ "$sent" -eq 0 ]; then tmux send-keys -t "$S" Enter; sent=1; fi
else
prev="$pane"; stable=0; sent=0
fi
done

echo "=== clean transcript ==="
tmux capture-pane -t "$S" -p -S -3000
tmux kill-session -t "$S" 2>/dev/null; rm -f "$cap1" "$cap2"
Loading
Loading