@@ -42,7 +42,10 @@ import { isYarnBerry } from './yarn-version.mts'
4242
4343import type { ShadowBinOptions , ShadowBinResult } from '../shadow/npm-base.mts'
4444import type { CResult } from '../types.mts'
45- import type { SpawnExtra } from '@socketsecurity/registry/lib/spawn'
45+ import type {
46+ SpawnExtra ,
47+ SpawnOptions ,
48+ } from '@socketsecurity/registry/lib/spawn'
4649
4750const require = createRequire ( import . meta. url )
4851
@@ -228,7 +231,10 @@ async function spawnCoanaScriptViaNode(
228231 scriptPath : string ,
229232 args : string [ ] | readonly string [ ] ,
230233 finalEnv : NodeJS . ProcessEnv ,
231- options : { cwd ?: string | URL | undefined } ,
234+ options : {
235+ cwd ?: string | URL | undefined
236+ stdio ?: SpawnOptions [ 'stdio' ] | undefined
237+ } ,
232238 spawnExtra ?: SpawnExtra | undefined ,
233239) : Promise < CResult < string > > {
234240 const isBinary = ! scriptPath . endsWith ( '.js' ) && ! scriptPath . endsWith ( '.mjs' )
@@ -237,7 +243,7 @@ async function spawnCoanaScriptViaNode(
237243 const spawnResult = await spawn ( isBinary ? scriptPath : 'node' , spawnArgs , {
238244 cwd : options . cwd ,
239245 env : sanitizeEnvForCoanaSubprocess ( finalEnv ) ,
240- stdio : spawnExtra ?. [ 'stdio' ] || 'inherit' ,
246+ stdio : options . stdio ?? spawnExtra ?. [ 'stdio' ] ?? 'inherit' ,
241247 } )
242248
243249 return { ok : true , data : spawnResult . stdout }
@@ -322,7 +328,10 @@ async function spawnCoanaViaNpmInstall(
322328 args : string [ ] | readonly string [ ] ,
323329 version : string ,
324330 finalEnv : NodeJS . ProcessEnv ,
325- options : { cwd ?: string | URL | undefined } ,
331+ options : {
332+ cwd ?: string | URL | undefined
333+ stdio ?: SpawnOptions [ 'stdio' ] | undefined
334+ } ,
326335 spawnExtra ?: SpawnExtra | undefined ,
327336) : Promise < CResult < string > > {
328337 let scriptPath : string
@@ -454,6 +463,18 @@ export async function spawnCoanaDlx(
454463 const resolvedVersion =
455464 coanaVersion || constants . ENV . INLINED_SOCKET_CLI_COANA_TECH_CLI_VERSION
456465
466+ // `shadowNpmBase` (the dlx launcher) configures the child's stdio from its
467+ // `options` arg, NOT from the registry-spawn `extra` arg — the latter only
468+ // attaches metadata to the result. Callers that requested streaming via
469+ // `spawnExtra` (the 4th arg), e.g. `{ stdio: 'inherit' }` from
470+ // `socket manifest gradle`, were therefore silently ignored on this path:
471+ // Coana ran piped and its output — including the real failure reason — never
472+ // reached the user, leaving only an unhelpful "command failed". Resolve the
473+ // requested stdio from either argument and honor it on every launch path:
474+ // dlx, local-path, and npm-install (e.g. `socket fix --silence` requests
475+ // `stdio: 'pipe'` via options).
476+ const requestedStdio = spawnExtra ?. [ 'stdio' ] ?? getOwn ( dlxOptions , 'stdio' )
477+
457478 const localCoanaPath = process . env [ 'SOCKET_CLI_COANA_LOCAL_PATH' ]
458479 // Use local Coana CLI if path is provided.
459480 if ( localCoanaPath ) {
@@ -462,7 +483,7 @@ export async function spawnCoanaDlx(
462483 localCoanaPath ,
463484 args ,
464485 finalEnv ,
465- { cwd : dlxOptions . cwd } ,
486+ { cwd : dlxOptions . cwd , stdio : requestedStdio } ,
466487 spawnExtra ,
467488 )
468489 } catch ( e ) {
@@ -479,23 +500,11 @@ export async function spawnCoanaDlx(
479500 args ,
480501 resolvedVersion ,
481502 finalEnv ,
482- { cwd : dlxOptions . cwd } ,
503+ { cwd : dlxOptions . cwd , stdio : requestedStdio } ,
483504 spawnExtra ,
484505 )
485506 }
486507
487- // `shadowNpmBase` (the dlx launcher) configures the child's stdio from its
488- // `options` arg, NOT from the registry-spawn `extra` arg — the latter only
489- // attaches metadata to the result. Callers that requested streaming via
490- // `spawnExtra` (the 4th arg), e.g. `{ stdio: 'inherit' }` from
491- // `socket manifest gradle`, were therefore silently ignored on this path:
492- // Coana ran piped and its output — including the real failure reason — never
493- // reached the user, leaving only an unhelpful "command failed". Promote the
494- // requested stdio into the dlx options so it is honored here too.
495- // `spawnCoanaScriptViaNode` already reads `spawnExtra.stdio` for the
496- // local-path and npm-install branches, so this aligns all three paths.
497- const requestedStdio = spawnExtra ?. [ 'stdio' ] ?? getOwn ( dlxOptions , 'stdio' )
498-
499508 try {
500509 // Use npm/dlx version.
501510 const result = await spawnDlx (
@@ -549,7 +558,7 @@ export async function spawnCoanaDlx(
549558 args ,
550559 resolvedVersion ,
551560 finalEnv ,
552- { cwd : dlxOptions . cwd } ,
561+ { cwd : dlxOptions . cwd , stdio : requestedStdio } ,
553562 spawnExtra ,
554563 )
555564 if ( fallbackResult . ok ) {
0 commit comments