diff --git a/packages/cli/binding/src/cli.rs b/packages/cli/binding/src/cli.rs index 6e2ac6ade5..f21b426974 100644 --- a/packages/cli/binding/src/cli.rs +++ b/packages/cli/binding/src/cli.rs @@ -671,12 +671,23 @@ impl CommandHandler for VitePlusCommandHandler { } // Parse "vp " using CLIArgs — always use "vp" as the program name // so clap shows "Usage: vp ..." even if the original command was "vite ..." - let cli_args = - CLIArgs::try_parse_from(iter::once("vp").chain(command.args.iter().map(Str::as_str)))?; + let cli_args = match CLIArgs::try_parse_from( + iter::once("vp").chain(command.args.iter().map(Str::as_str)), + ) { + Ok(args) => args, + Err(err) if err.kind() == ErrorKind::InvalidSubcommand => { + return Ok(HandledCommand::Synthesized( + command.to_synthetic_plan_request(UserCacheConfig::disabled()), + )); + } + Err(err) => return Err(err.into()), + }; match cli_args { CLIArgs::Synthesizable(SynthesizableSubcommand::Check { .. }) => { // Check is a composite command — run as a subprocess in task scripts - Ok(HandledCommand::Verbatim) + Ok(HandledCommand::Synthesized( + command.to_synthetic_plan_request(UserCacheConfig::disabled()), + )) } CLIArgs::Synthesizable(subcmd) => { let resolved = self.resolver.resolve(subcmd, &command.envs, &command.cwd).await?; @@ -685,7 +696,9 @@ impl CommandHandler for VitePlusCommandHandler { CLIArgs::ViteTask(cmd) => Ok(HandledCommand::ViteTaskCommand(cmd)), CLIArgs::Exec(_) => { // exec in task scripts should run as a subprocess - Ok(HandledCommand::Verbatim) + Ok(HandledCommand::Synthesized( + command.to_synthetic_plan_request(UserCacheConfig::disabled()), + )) } } } @@ -1660,4 +1673,20 @@ mod tests { let subcommand = SynthesizableSubcommand::Lint { args: vec!["src/index.ts".to_string()] }; assert!(!should_suppress_subcommand_stdout(&subcommand)); } + + #[test] + fn global_subcommands_produce_invalid_subcommand_error() { + use clap::error::ErrorKind; + + for subcommand in ["config", "create", "env", "migrate"] { + let error = CLIArgs::try_parse_from(["vp", subcommand]) + .expect_err(&format!("expected error for global subcommand '{subcommand}'")); + assert_eq!( + error.kind(), + ErrorKind::InvalidSubcommand, + "expected InvalidSubcommand for '{subcommand}', got {:?}", + error.kind() + ); + } + } } diff --git a/packages/cli/snap-tests/command-run-with-vp-config/package.json b/packages/cli/snap-tests/command-run-with-vp-config/package.json new file mode 100644 index 0000000000..25118402c5 --- /dev/null +++ b/packages/cli/snap-tests/command-run-with-vp-config/package.json @@ -0,0 +1,9 @@ +{ + "name": "command-run-with-vp-config", + "version": "1.0.0", + "scripts": { + "foo": "vp config", + "bar": "vp not-exist-command" + }, + "packageManager": "pnpm@10.19.0" +} diff --git a/packages/cli/snap-tests/command-run-with-vp-config/snap.txt b/packages/cli/snap-tests/command-run-with-vp-config/snap.txt new file mode 100644 index 0000000000..a7d8c33a45 --- /dev/null +++ b/packages/cli/snap-tests/command-run-with-vp-config/snap.txt @@ -0,0 +1,26 @@ +> vp run foo # should run vp config command +$ vp config ⊘ cache disabled +.git can't be found + +Created AGENTS.md with Vite+ instructions +◇ Add this MCP server config to your agent ─╮ + + { + "vite-plus": { + "command": "npx", + "args": [ + "vp", + "mcp" + ] + } + } + +╰────────────────────────────────────────────╯ + + +[2]> vp run bar # should throw error +$ vp not-exist-command ⊘ cache disabled +error: Command 'not-exist-command' not found + +Did you mean `vp test`? + diff --git a/packages/cli/snap-tests/command-run-with-vp-config/steps.json b/packages/cli/snap-tests/command-run-with-vp-config/steps.json new file mode 100644 index 0000000000..d6b0e1631e --- /dev/null +++ b/packages/cli/snap-tests/command-run-with-vp-config/steps.json @@ -0,0 +1,3 @@ +{ + "commands": ["vp run foo # should run vp config command", "vp run bar # should throw error"] +}