Skip to content

Commit 58b2307

Browse files
authored
fix: resolve vp run crash when task script contains global CLI subcommands (#766)
## Summary - `vp run` crashed when a task script contained global-only commands like `vp config` because `CLIArgs::try_parse_from` failed on unrecognized subcommands with `ErrorKind::InvalidSubcommand` - Now `InvalidSubcommand` errors return `HandledCommand::Synthesized` with `UserCacheConfig::disabled()`, letting the global CLI binary handle them as regular subprocesses without caching - Also disabled cache for `vp exec` and `vp check` in task scripts, since they run arbitrary/composite commands with side effects ## Test plan - [x] Added unit test `global_subcommands_produce_invalid_subcommand_error` confirming `config`, `create`, `env`, `migrate` produce `InvalidSubcommand` - [x] Added snap test `command-run-with-vp-config` verifying `vp run foo` with `"foo": "vp config"` no longer crashes - [x] All existing snap tests pass
1 parent 52a4778 commit 58b2307

4 files changed

Lines changed: 71 additions & 4 deletions

File tree

packages/cli/binding/src/cli.rs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -671,12 +671,23 @@ impl CommandHandler for VitePlusCommandHandler {
671671
}
672672
// Parse "vp <args>" using CLIArgs — always use "vp" as the program name
673673
// so clap shows "Usage: vp ..." even if the original command was "vite ..."
674-
let cli_args =
675-
CLIArgs::try_parse_from(iter::once("vp").chain(command.args.iter().map(Str::as_str)))?;
674+
let cli_args = match CLIArgs::try_parse_from(
675+
iter::once("vp").chain(command.args.iter().map(Str::as_str)),
676+
) {
677+
Ok(args) => args,
678+
Err(err) if err.kind() == ErrorKind::InvalidSubcommand => {
679+
return Ok(HandledCommand::Synthesized(
680+
command.to_synthetic_plan_request(UserCacheConfig::disabled()),
681+
));
682+
}
683+
Err(err) => return Err(err.into()),
684+
};
676685
match cli_args {
677686
CLIArgs::Synthesizable(SynthesizableSubcommand::Check { .. }) => {
678687
// Check is a composite command — run as a subprocess in task scripts
679-
Ok(HandledCommand::Verbatim)
688+
Ok(HandledCommand::Synthesized(
689+
command.to_synthetic_plan_request(UserCacheConfig::disabled()),
690+
))
680691
}
681692
CLIArgs::Synthesizable(subcmd) => {
682693
let resolved = self.resolver.resolve(subcmd, &command.envs, &command.cwd).await?;
@@ -685,7 +696,9 @@ impl CommandHandler for VitePlusCommandHandler {
685696
CLIArgs::ViteTask(cmd) => Ok(HandledCommand::ViteTaskCommand(cmd)),
686697
CLIArgs::Exec(_) => {
687698
// exec in task scripts should run as a subprocess
688-
Ok(HandledCommand::Verbatim)
699+
Ok(HandledCommand::Synthesized(
700+
command.to_synthetic_plan_request(UserCacheConfig::disabled()),
701+
))
689702
}
690703
}
691704
}
@@ -1660,4 +1673,20 @@ mod tests {
16601673
let subcommand = SynthesizableSubcommand::Lint { args: vec!["src/index.ts".to_string()] };
16611674
assert!(!should_suppress_subcommand_stdout(&subcommand));
16621675
}
1676+
1677+
#[test]
1678+
fn global_subcommands_produce_invalid_subcommand_error() {
1679+
use clap::error::ErrorKind;
1680+
1681+
for subcommand in ["config", "create", "env", "migrate"] {
1682+
let error = CLIArgs::try_parse_from(["vp", subcommand])
1683+
.expect_err(&format!("expected error for global subcommand '{subcommand}'"));
1684+
assert_eq!(
1685+
error.kind(),
1686+
ErrorKind::InvalidSubcommand,
1687+
"expected InvalidSubcommand for '{subcommand}', got {:?}",
1688+
error.kind()
1689+
);
1690+
}
1691+
}
16631692
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "command-run-with-vp-config",
3+
"version": "1.0.0",
4+
"scripts": {
5+
"foo": "vp config",
6+
"bar": "vp not-exist-command"
7+
},
8+
"packageManager": "pnpm@10.19.0"
9+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
> vp run foo # should run vp config command
2+
$ vp config ⊘ cache disabled
3+
.git can't be found
4+
5+
Created AGENTS.md with Vite+ instructions
6+
◇ Add this MCP server config to your agent ─╮
7+
8+
{
9+
"vite-plus": {
10+
"command": "npx",
11+
"args": [
12+
"vp",
13+
"mcp"
14+
]
15+
}
16+
}
17+
18+
╰────────────────────────────────────────────╯
19+
20+
21+
[2]> vp run bar # should throw error
22+
$ vp not-exist-command ⊘ cache disabled
23+
error: Command 'not-exist-command' not found
24+
25+
Did you mean `vp test`?
26+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"commands": ["vp run foo # should run vp config command", "vp run bar # should throw error"]
3+
}

0 commit comments

Comments
 (0)