Skip to content

Commit 0d24eb9

Browse files
hakshu25claudefengmk2
authored
feat(cli): add explanations to migration prompts (#1270)
## Summary Closes #1030 When running `vp migrate` interactively, users are prompted with choices (which agents to use, whether to merge editor configs, whether to migrate ESLint/Prettier, etc.) but are given no context for why. This PR adds a brief gray explanation embedded directly in each prompt message so users understand what they're agreeing to before making a choice. ## Demo <!-- screenshot here --> <img width="1451" height="784" alt="スクリーンショット 2026-04-02 17 05 23" src="https://github.com/user-attachments/assets/92b605e0-037f-4e1d-982b-8219c32d6fe0" /> ## Test plan - [x] `vp check --fix` passes - [x] `pnpm bootstrap-cli && pnpm test` passes (snap tests unaffected — all new messages are inside `interactive` guards) - [x] GPG-signed commits 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: MK (fengmk2) <fengmk2@gmail.com>
1 parent 0c4e54f commit 0d24eb9

File tree

3 files changed

+53
-11
lines changed

3 files changed

+53
-11
lines changed

packages/cli/src/migration/bin.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,12 @@ function warnLegacyEslintConfig(legacyConfigFile: string) {
7575
async function confirmEslintMigration(interactive: boolean): Promise<boolean> {
7676
if (interactive) {
7777
const confirmed = await prompts.confirm({
78-
message: 'Migrate ESLint rules to Oxlint using @oxlint/migrate?',
78+
message:
79+
'Migrate ESLint rules to Oxlint using @oxlint/migrate?\n ' +
80+
styleText(
81+
'gray',
82+
"Oxlint is Vite+'s built-in linter — significantly faster than ESLint with compatible rule support. @oxlint/migrate converts your existing rules automatically.",
83+
),
7984
initialValue: true,
8085
});
8186
if (prompts.isCancel(confirmed)) {
@@ -129,7 +134,12 @@ function warnPackageLevelPrettier() {
129134
async function confirmPrettierMigration(interactive: boolean): Promise<boolean> {
130135
if (interactive) {
131136
const confirmed = await prompts.confirm({
132-
message: 'Migrate Prettier to Oxfmt?',
137+
message:
138+
'Migrate Prettier to Oxfmt?\n ' +
139+
styleText(
140+
'gray',
141+
"Oxfmt is Vite+'s built-in formatter that replaces Prettier with faster performance. Your configuration will be converted automatically.",
142+
),
133143
initialValue: true,
134144
});
135145
if (prompts.isCancel(confirmed)) {
@@ -392,7 +402,12 @@ async function collectMigrationPlan(
392402
for (const conflict of agentConflicts) {
393403
if (options.interactive) {
394404
const action = await prompts.select({
395-
message: `Agent instructions already exist at ${conflict.targetPath}.`,
405+
message:
406+
`Agent instructions already exist at ${conflict.targetPath}.\n ` +
407+
styleText(
408+
'gray',
409+
'The Vite+ template includes guidance on `vp` commands, the build pipeline, and project conventions.',
410+
),
396411
options: [
397412
{ label: 'Append', value: 'append' as const, hint: 'Add template content to the end' },
398413
{ label: 'Skip', value: 'skip' as const, hint: 'Leave existing file unchanged' },
@@ -424,7 +439,12 @@ async function collectMigrationPlan(
424439
for (const conflict of editorConflicts) {
425440
if (options.interactive) {
426441
const action = await prompts.select({
427-
message: `${conflict.displayPath} already exists.`,
442+
message:
443+
`${conflict.displayPath} already exists.\n ` +
444+
styleText(
445+
'gray',
446+
'Vite+ adds editor settings for the built-in linter and formatter. Merge adds new keys without overwriting existing ones.',
447+
),
428448
options: [
429449
{
430450
label: 'Merge',

packages/cli/src/utils/agent.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import fs from 'node:fs';
22
import fsPromises from 'node:fs/promises';
33
import path from 'node:path';
4+
import { styleText } from 'node:util';
45

56
import * as prompts from '@voidzero-dev/vite-plus-prompts';
67

@@ -210,7 +211,12 @@ export async function selectAgentTargetPaths({
210211

211212
if (interactive && !agent) {
212213
const selectedAgents = await prompts.multiselect({
213-
message: 'Which agents are you using?',
214+
message:
215+
'Which agents are you using?\n ' +
216+
styleText(
217+
'gray',
218+
'Writes an instruction file for each selected agent to help it understand `vp` commands and the project workflow.',
219+
),
214220
options: AGENTS.map((option) => ({
215221
label: option.label,
216222
value: option.id,
@@ -528,7 +534,12 @@ export async function writeAgentInstructions({
528534
conflictAction = preResolved;
529535
} else if (interactive) {
530536
const action = await prompts.select({
531-
message: `Agent instructions already exist at ${targetPathToWrite}.`,
537+
message:
538+
`Agent instructions already exist at ${targetPathToWrite}.\n ` +
539+
styleText(
540+
'gray',
541+
'The Vite+ template includes guidance on `vp` commands, the build pipeline, and project conventions.',
542+
),
532543
options: [
533544
{
534545
label: 'Append',

packages/cli/src/utils/editor.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import fs from 'node:fs';
22
import fsPromises from 'node:fs/promises';
33
import path from 'node:path';
4+
import { styleText } from 'node:util';
45

56
import * as prompts from '@voidzero-dev/vite-plus-prompts';
67

@@ -175,14 +176,19 @@ export async function selectEditor({
175176
value: option.id,
176177
hint: option.targetDir,
177178
}));
178-
const noneOption = {
179-
label: 'None',
179+
const otherOption = {
180+
label: 'Other',
180181
value: null,
181182
hint: 'Skip writing editor configs',
182183
};
183184
const selectedEditor = await prompts.select({
184-
message: 'Which editor are you using?',
185-
options: [...editorOptions, noneOption],
185+
message:
186+
'Which editor are you using?\n ' +
187+
styleText(
188+
'gray',
189+
'Writes editor config files to enable recommended extensions and Oxlint/Oxfmt integrations.',
190+
),
191+
options: [...editorOptions, otherOption],
186192
initialValue: 'vscode',
187193
});
188194

@@ -293,7 +299,12 @@ export async function writeEditorConfigs({
293299
conflictAction = preResolved;
294300
} else if (interactive) {
295301
const action = await prompts.select({
296-
message: `${displayPath} already exists.`,
302+
message:
303+
`${displayPath} already exists.\n ` +
304+
styleText(
305+
'gray',
306+
`Vite+ adds ${editorConfig.label} settings for the built-in linter and formatter. Merge adds new keys without overwriting existing ones.`,
307+
),
297308
options: [
298309
{
299310
label: 'Merge',

0 commit comments

Comments
 (0)