@@ -290,32 +290,37 @@ function summarizeKnownExec(words: string[]): string {
290290// `run` is the only framework-injected verb in `summarizeKnownExec` output; every
291291// other leading word (`check git status`, `install dependencies`, `start app`,
292292// `show last 20 lines`) carries diagnostic meaning and must survive stripping.
293- // `summarizeKnownExec` also emits a small set of semantic `run <noun>` labels from
294- // the npm/pnpm/yarn subcommand map (`run tests`, `run build`, `run lint`,
295- // `run script`); those must also survive so the failure message keeps the
296- // package-manager script context. Any other `run <binary> ...` shape is
297- // framework-injected by the catch-all and is stripped so the backtick-wrapped
298- // text is exactly what was run (issue #97319).
299- const SEMANTIC_RUN_WORDS : ReadonlySet < string > = new Set ( [ "tests" , "build" , "lint" , "script" ] ) ;
293+ // `summarizeKnownExec` also emits `run <noun>` labels from the npm/pnpm/yarn
294+ // subcommand map — both fixed (`run tests`, `run build`, `run lint`, `run script`)
295+ // and arbitrary ( `run dev`, `run ${scriptName}`) — which must survive so the
296+ // failure message keeps the package-manager script context. Only the catch-all
297+ // `run <binary> <args>` shape is stripped; that shape always carries at least
298+ // one whitespace-separated argument after the binary, so a `run <single-token>`
299+ // meta is never ambiguous and never stripped (issue #97319).
300300
301301/**
302- * Strips a leading framework-injected `run` verb when it precedes a binary
303- * (e.g. `run python3 /path` -> `python3 /path`) so the action label is not
304- * backtick-wrapped together with the literal command (issue #97319).
302+ * Strips a leading framework-injected `run` verb when the rest carries both a
303+ * binary and its arguments (e.g. `run python3 /path` -> `python3 /path`) so the
304+ * action label is not backtick-wrapped together with the literal command
305+ * (issue #97319).
305306 *
306307 * Returns the original meta unchanged for any other shape — including action-
307- * bearing summaries like `install dependencies`, `start app`, `run tests`,
308- * `run build`, or `show last 20 lines` — so diagnostic verbs and package-manager
309- * script labels stay visible in failure warnings.
308+ * bearing summaries like `install dependencies`, `start app`, package-manager
309+ * script labels like `run dev`, `run tests`, `run build`, or `show last 20
310+ * lines` — so diagnostic verbs and arbitrary package-script names stay visible
311+ * in failure warnings.
310312 */
311313export function stripLeadingExecDisplayVerb ( meta : string ) : string {
312314 const match = meta . match ( / ^ r u n \s + ( \S .* ) $ / ) ;
313315 if ( ! match ) {
314316 return meta ;
315317 }
316318 const rest = match [ 1 ] ;
317- const firstWord = rest . match ( / ^ ( [ A - Z a - z 0 - 9 . _ - ] + ) / ) ?. [ 1 ] ;
318- if ( ! firstWord || SEMANTIC_RUN_WORDS . has ( firstWord ) ) {
319+ // Only strip when the meta unambiguously came from the catch-all — i.e. the
320+ // rest contains a binary AND its arguments. A single-token `run <X>` could be
321+ // an arbitrary package-script name (`npm run dev`) or a fixed semantic label
322+ // (`run tests`), so we preserve those to avoid dropping script context.
323+ if ( ! / \s / . test ( rest ) ) {
319324 return meta ;
320325 }
321326 return rest ;
0 commit comments