@@ -119,13 +119,11 @@ export const mcpOptions = {
119119 experimentalFfmpegPath : {
120120 type : 'string' ,
121121 describe : 'Path to ffmpeg executable for screencast recording.' ,
122- implies : 'experimentalScreencast' ,
123122 } ,
124123 experimentalScreencastFps : {
125124 type : 'number' ,
126125 describe :
127126 'Frames per second to use for screencast recording. Lower values can reduce memory pressure on pages that produce frames faster than ffmpeg can encode them.' ,
128- implies : 'experimentalScreencast' ,
129127 coerce : ( value : number | undefined ) => {
130128 if ( value === undefined ) {
131129 return ;
@@ -324,10 +322,16 @@ export const mcpOptions = {
324322 } ,
325323} satisfies Record < string , YargsOptions > ;
326324
327- export type ParsedArguments = ReturnType <
325+ type RawParsedArguments = ReturnType <
328326 ReturnType < typeof buildCliParser < typeof mcpOptions > > [ 'parseSync' ]
329327> ;
330328
329+ export type ParsedArguments = {
330+ [ K in keyof RawParsedArguments as K extends '_' | '$0'
331+ ? never
332+ : K ] : RawParsedArguments [ K ] ;
333+ } ;
334+
331335export function getMcpOptionsForViaCli ( ) : Record <
332336 keyof typeof mcpOptions ,
333337 YargsOptions
@@ -373,9 +377,8 @@ export function getMcpOptionsForViaCli(): Record<
373377export function getCliOptions ( ) : Partial <
374378 Record < keyof typeof mcpOptions , YargsOptions >
375379> {
376- const options : Partial < Record < keyof typeof mcpOptions , YargsOptions > > = {
377- ...getMcpOptionsForViaCli ( ) ,
378- } ;
380+ const options : Partial < Record < keyof typeof mcpOptions , YargsOptions > > =
381+ withoutDefaults ( getMcpOptionsForViaCli ( ) ) ;
379382
380383 // Missing CLI serialization.
381384 delete options . viewport ;
@@ -384,19 +387,6 @@ export function getCliOptions(): Partial<
384387 delete options . experimentalStructuredContent ;
385388 delete options . experimentalInteropTools ;
386389
387- const recordOptions : Record < string , YargsOptions | undefined > = options ;
388- for ( const [ key , option ] of Object . entries ( recordOptions ) ) {
389- if ( option ?. default !== undefined ) {
390- const copy : YargsOptions = {
391- ...option ,
392- defaultDescription :
393- option . defaultDescription ?? JSON . stringify ( option . default ) ,
394- } ;
395- delete copy . default ;
396- recordOptions [ key ] = copy ;
397- }
398- }
399-
400390 return options ;
401391}
402392
@@ -475,6 +465,13 @@ const CONFLICTING_ARGS: Array<Array<keyof typeof mcpOptions>> = [
475465 [ 'categoryExtensions' , 'browserUrl' , 'wsEndpoint' ] ,
476466] ;
477467
468+ const IMPLICATIONS : Array < [ keyof typeof mcpOptions , keyof typeof mcpOptions ] > =
469+ [
470+ [ 'wsHeaders' , 'wsEndpoint' ] ,
471+ [ 'experimentalFfmpegPath' , 'experimentalScreencast' ] ,
472+ [ 'experimentalScreencastFps' , 'experimentalScreencast' ] ,
473+ ] ;
474+
478475function isPlainObject ( value : unknown ) : value is Record < string , unknown > {
479476 return typeof value === 'object' && value !== null && ! Array . isArray ( value ) ;
480477}
@@ -518,12 +515,11 @@ function withoutDefaults(
518515 return result ;
519516}
520517
521- function stripYargsPositionalArgs (
522- parsed : Partial < ParsedArguments > ,
523- ) : Partial < ParsedArguments > {
524- delete ( parsed as { _ ?: unknown } ) . _ ;
525- delete ( parsed as { $0 ?: unknown } ) . $0 ;
526- return parsed ;
518+ function stripYargsPositionalArgs < T extends { _ ?: unknown ; $0 ?: unknown } > (
519+ parsed : T ,
520+ ) : Omit < T , '_' | '$0' > {
521+ const { _ : _positionals , $0 : _scriptName , ...rest } = parsed ;
522+ return rest ;
527523}
528524
529525/**
@@ -598,6 +594,20 @@ export function validateConflicts(
598594 }
599595}
600596
597+ export function validateImplications (
598+ explicitArgs : Partial < ParsedArguments > ,
599+ ) : void {
600+ for ( const [ key , implied ] of IMPLICATIONS ) {
601+ const isKeySet =
602+ explicitArgs [ key ] !== undefined && explicitArgs [ key ] !== false ;
603+ const isImpliedSet =
604+ explicitArgs [ implied ] !== undefined && explicitArgs [ implied ] !== false ;
605+ if ( isKeySet && ! isImpliedSet ) {
606+ throw new Error ( `Implications failed:\n ${ key } -> ${ implied } ` ) ;
607+ }
608+ }
609+ }
610+
601611/**
602612 * Step 5: fills in defaults for everything that was not set explicitly.
603613 * `viaCli` is an explicit input like any other; it selects which defaults
@@ -674,6 +684,7 @@ export function parseArguments(
674684 const explicitArgs = { ...configFileArgs , ...cliArgs } ;
675685 warnUnknownArgs ( cliArgs ) ;
676686 validateConflicts ( explicitArgs ) ;
687+ validateImplications ( explicitArgs ) ;
677688 const resolvedArgs = applyDefaults ( explicitArgs , env ) ;
678689
679690 // The merge and the default loop lose the static type that yargs infers from
0 commit comments