Skip to content

fix: resolve commands executed with vp exec - #2285

Merged
webpro merged 4 commits into
webpro-nl:mainfrom
everton-dgn:fix/vp-exec-command
Nov 3, 2026
Merged

webpro merged 4 commits into
webpro-nl:mainfrom
everton-dgn:fix/vp-exec-command

Conversation

@everton-dgn

Copy link
Copy Markdown
Contributor

Fixes #2284.

Follow the command passed to vp exec so its scripts are discovered without manual entry configuration. The resolver preserves quoted arguments, -- and the three leading -C forms, including absolute paths. Other subcommands return only the vp binary.

Registering vp as a package manager also lets mise tasks follow its commands and apply the same binary checks as package scripts.

Tested with parser regressions that fail without the fix, the CLI reproduction from the issue, pnpm run ci and the full pnpm qa.

@pkg-pr-new

pkg-pr-new Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/knip@2285
npm i https://pkg.pr.new/@knip/language-server@2285
npm i https://pkg.pr.new/@knip/mcp@2285

commit: 3e87cd9

@webpro webpro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Γ‰verton, this finds the script for the case in #2284. Two forms still resolve the wrong file: -c with more than one argument, and -w. Suggestions for both are inline, with tests and two small cleanups.


const dir = C ? toAbsolute(C, options.cwd) : undefined;
const rest = words.slice(commandIndex);
const script = execOptions['shell-mode'] && rest.length === 1 ? rest[0].value : rest.map(word => word.text).join(' ');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With -c, Vite+ joins all arguments and passes the result to the shell, so vp exec -c "node ./scripts/proof.mjs" --flag runs scripts/proof.mjs. With more than one word here, the whole quoted command becomes a single entry and the script is still reported as unused. Using word.value for every word in shell mode covers both cases:

Suggested change
const script = execOptions['shell-mode'] && rest.length === 1 ? rest[0].value : rest.map(word => word.text).join(' ');
const script = rest.map(word => (execOptions['shell-mode'] ? word.value : word.text)).join(' ');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@webpro

Fixed in 4b2e73a. Shell mode now joins word.value for every argument, with a regression for -c "node ./script.js" --flag.

const execOptions = parseArgs(words.slice(execIndex + 1, commandIndex), parseOptions);
if (execOptions.filter && !execOptions.recursive) return [binary];

const dir = C ? toAbsolute(C, options.cwd) : undefined;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-w runs the command in the workspace root, so vp exec -w node ./scripts/root.mjs in a package script runs the root's scripts/root.mjs. Since it's resolved against the package, a scripts/root.mjs in the package is marked as used instead, and the root file is still reported as unused:

Suggested change
const dir = C ? toAbsolute(C, options.cwd) : undefined;
const dir = execOptions['workspace-root'] ? options.rootCwd : C ? toAbsolute(C, options.cwd) : undefined;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@webpro

-w now resolves against options.rootCwd in 4b2e73a, including when -C is set. Added cases for a package cwd and workspace-root precedence.

if (commandIndex === undefined) return [binary];

const execOptions = parseArgs(words.slice(execIndex + 1, commandIndex), parseOptions);
if (execOptions.filter && !execOptions.recursive) return [binary];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vite+ rejects --filter together with --recursive ("--filter and --recursive cannot be used together"), so this can be simpler:

Suggested change
if (execOptions.filter && !execOptions.recursive) return [binary];
if (execOptions.filter) return [binary];

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@webpro

Simplified to if (execOptions.filter) return [binary]; in 4b2e73a.


const parseOptions = {
isStorePositions: true,
string: ['C', 'filter', 'resume-from'],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A leading -C is already handled by parseLeadingChdir, and after exec Vite+ treats -C as the command, so 'C' isn't needed here:

Suggested change
string: ['C', 'filter', 'resume-from'],
string: ['filter', 'resume-from'],

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@webpro

Removed C from the string options in 4b2e73a. Leading directory changes remain handled by parseLeadingChdir.

t('vp exec vitest --filter smoke', [toBinary('vp'), toBinary('vitest')]);
t(`vp -C ${app.dir} exec node ./scripts/task.mjs`, [toBinary('vp'), toBinary('node', app), toDeferResolveEntry('./scripts/task.mjs', { ...opt, ...app })]);
t('vp -Cpackages/app exec node ./scripts/task.mjs', [toBinary('vp'), toBinary('node', app), toDeferResolveEntry('./scripts/task.mjs', { ...opt, ...app })]);
t(`vp -C${app.dir} exec node ./scripts/task.mjs`, [toBinary('vp'), toBinary('node', app), toDeferResolveEntry('./scripts/task.mjs', { ...opt, ...app })]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add cases for these? The -c and -w lines fail without the changes above, and the -t line guards the flags that take no value:

Suggested change
t(`vp -C${app.dir} exec node ./scripts/task.mjs`, [toBinary('vp'), toBinary('node', app), toDeferResolveEntry('./scripts/task.mjs', { ...opt, ...app })]);
t(`vp -C${app.dir} exec node ./scripts/task.mjs`, [toBinary('vp'), toBinary('node', app), toDeferResolveEntry('./scripts/task.mjs', { ...opt, ...app })]);
t('vp exec -c "node ./script.js" --flag', [toBinary('vp'), toBinary('node'), js]);
t('vp exec -t node ./script.js', [toBinary('vp'), toBinary('node'), js]);
t('vp exec -w node ./script.js', [toBinary('vp'), toBinary('node', { dir: cwd }), toDeferResolveEntry('./script.js', { ...opt, dir: cwd })], { cwd: app.dir });

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@webpro

Added the -c, -t, and package-cwd -w cases in 4b2e73a, plus precedence of --workspace-root over -C. The compact absolute -C case was already covered. Both bug regressions fail without the fix and pass with it.

@everton-dgn

Copy link
Copy Markdown
Contributor Author

Fixed in 4b2e73a: shell-mode arguments, workspace-root resolution, the requested tests and both parser cleanups. pnpm run ci and pnpm qa pass (1,639 tests, 8 skipped).

@everton-dgn
everton-dgn requested a review from webpro November 3, 2026 16:46

@webpro webpro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, all five are in, and the extra --workspace-root case is a nice touch.

@webpro
webpro merged commit 406a776 into webpro-nl:main Nov 3, 2026
32 checks passed
@webpro

webpro commented Nov 3, 2026

Copy link
Copy Markdown
Member

πŸš€ This pull request is included in v6.44.2. See Release 6.44.2 for release notes.

Using Knip in a commercial project? Please consider becoming a sponsor.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

vp exec does not expose the executed script as an entry

2 participants