@@ -173,7 +173,7 @@ async function tryRunCli(cliContext: CliContext) {
173173 cliContext . logger . info ( cliContext . environment . packageVersion ) ;
174174 } else {
175175 cli . showHelp ( ) ;
176- cliContext . failAndThrow ( ) ;
176+ cliContext . failAndThrow ( undefined , undefined , { code : "CONFIG_ERROR" } ) ;
177177 }
178178 }
179179 )
@@ -319,14 +319,22 @@ function addInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
319319 }
320320 }
321321 if ( argv . api != null && argv . docs != null ) {
322- return cliContext . failWithoutThrowing ( "Cannot specify both --api and --docs. Please choose one." ) ;
322+ return cliContext . failWithoutThrowing (
323+ "Cannot specify both --api and --docs. Please choose one." ,
324+ undefined ,
325+ { code : "CONFIG_ERROR" }
326+ ) ;
323327 } else if ( argv . readme != null && argv . mintlify != null ) {
324328 return cliContext . failWithoutThrowing (
325- "Cannot specify both --readme and --mintlify. Please choose one."
329+ "Cannot specify both --readme and --mintlify. Please choose one." ,
330+ undefined ,
331+ { code : "CONFIG_ERROR" }
326332 ) ;
327333 } else if ( argv . openapi != null && argv [ "fern-definition" ] === true ) {
328334 return cliContext . failWithoutThrowing (
329- "Cannot specify both --openapi and --fern-definition. Please choose one."
335+ "Cannot specify both --openapi and --fern-definition. Please choose one." ,
336+ undefined ,
337+ { code : "CONFIG_ERROR" }
330338 ) ;
331339 } else if ( argv . readme != null ) {
332340 await cliContext . runTask ( async ( context ) => {
@@ -361,7 +369,7 @@ function addInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
361369 const result = await loadOpenAPIFromUrl ( { url : argv . openapi , logger : cliContext . logger } ) ;
362370
363371 if ( result . status === LoadOpenAPIStatus . Failure ) {
364- cliContext . failAndThrow ( result . errorMessage ) ;
372+ cliContext . failAndThrow ( result . errorMessage , undefined , { code : "NETWORK_ERROR" } ) ;
365373 }
366374
367375 const tmpFilepath = result . filePath ;
@@ -371,7 +379,9 @@ function addInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
371379 }
372380 const pathExists = await doesPathExist ( absoluteOpenApiPath ) ;
373381 if ( ! pathExists ) {
374- cliContext . failAndThrow ( `${ absoluteOpenApiPath } does not exist` ) ;
382+ cliContext . failAndThrow ( `${ absoluteOpenApiPath } does not exist` , undefined , {
383+ code : "CONFIG_ERROR"
384+ } ) ;
375385 }
376386 }
377387 await cliContext . runTask ( async ( context ) => {
@@ -424,9 +434,11 @@ function addDiffCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
424434 } )
425435 . middleware ( ( argv ) => {
426436 if ( ! haveSameNullishness ( argv . fromGeneratorVersion , argv . toGeneratorVersion ) ) {
427- throw new Error (
428- "Both --from-generator-version and --to-generator-version must be provided together, or neither should be provided"
429- ) ;
437+ throw new CliError ( {
438+ message :
439+ "Both --from-generator-version and --to-generator-version must be provided together, or neither should be provided" ,
440+ code : "VALIDATION_ERROR"
441+ } ) ;
430442 }
431443 } ) ,
432444 async ( argv ) => {
@@ -743,50 +755,84 @@ function addGenerateCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext)
743755 } ) ,
744756 async ( argv ) => {
745757 if ( argv . api != null && argv . docs != null ) {
746- return cliContext . failWithoutThrowing ( "Cannot specify both --api and --docs. Please choose one." ) ;
758+ return cliContext . failWithoutThrowing (
759+ "Cannot specify both --api and --docs. Please choose one." ,
760+ undefined ,
761+ { code : "CONFIG_ERROR" }
762+ ) ;
747763 }
748764 if ( argv . id != null && ! argv . preview ) {
749- return cliContext . failWithoutThrowing ( "The --id flag can only be used with --preview." ) ;
765+ return cliContext . failWithoutThrowing ( "The --id flag can only be used with --preview." , undefined , {
766+ code : "CONFIG_ERROR"
767+ } ) ;
750768 }
751769 if ( argv . id != null && argv . docs == null ) {
752- return cliContext . failWithoutThrowing ( "The --id flag can only be used with --docs." ) ;
770+ return cliContext . failWithoutThrowing ( "The --id flag can only be used with --docs." , undefined , {
771+ code : "CONFIG_ERROR"
772+ } ) ;
753773 }
754774 if ( argv . skipUpload && ! argv . preview ) {
755- return cliContext . failWithoutThrowing ( "The --skip-upload flag can only be used with --preview." ) ;
775+ return cliContext . failWithoutThrowing (
776+ "The --skip-upload flag can only be used with --preview." ,
777+ undefined ,
778+ { code : "CONFIG_ERROR" }
779+ ) ;
756780 }
757781 if ( argv . skipUpload && argv . docs == null ) {
758- return cliContext . failWithoutThrowing ( "The --skip-upload flag can only be used with --docs." ) ;
782+ return cliContext . failWithoutThrowing (
783+ "The --skip-upload flag can only be used with --docs." ,
784+ undefined ,
785+ { code : "CONFIG_ERROR" }
786+ ) ;
759787 }
760788 if ( argv . fernignore != null && ( argv . local || argv . runner != null ) ) {
761789 return cliContext . failWithoutThrowing (
762- "The --fernignore flag is not supported with local generation (--local or --runner). It can only be used with remote generation."
790+ "The --fernignore flag is not supported with local generation (--local or --runner). It can only be used with remote generation." ,
791+ undefined ,
792+ { code : "CONFIG_ERROR" }
763793 ) ;
764794 }
765795 if ( argv [ "skip-fernignore" ] && argv . fernignore != null ) {
766796 return cliContext . failWithoutThrowing (
767- "The --skip-fernignore and --fernignore flags cannot be used together."
797+ "The --skip-fernignore and --fernignore flags cannot be used together." ,
798+ undefined ,
799+ { code : "CONFIG_ERROR" }
768800 ) ;
769801 }
770802 if ( argv [ "dynamic-ir-only" ] && ( argv . local || argv . runner != null ) ) {
771803 return cliContext . failWithoutThrowing (
772- "The --dynamic-ir-only flag is not supported with local generation (--local or --runner). It can only be used with remote generation."
804+ "The --dynamic-ir-only flag is not supported with local generation (--local or --runner). It can only be used with remote generation." ,
805+ undefined ,
806+ { code : "CONFIG_ERROR" }
773807 ) ;
774808 }
775809 if ( argv [ "dynamic-ir-only" ] && argv . version == null ) {
776810 return cliContext . failWithoutThrowing (
777- "The --dynamic-ir-only flag requires a version to be specified with --version."
811+ "The --dynamic-ir-only flag requires a version to be specified with --version." ,
812+ undefined ,
813+ { code : "CONFIG_ERROR" }
778814 ) ;
779815 }
780816 if ( argv [ "dynamic-ir-only" ] && argv . docs != null ) {
781817 return cliContext . failWithoutThrowing (
782- "The --dynamic-ir-only flag can only be used for API generation, not docs generation."
818+ "The --dynamic-ir-only flag can only be used for API generation, not docs generation." ,
819+ undefined ,
820+ { code : "CONFIG_ERROR" }
783821 ) ;
784822 }
785823 if ( argv . output != null && ! argv . preview ) {
786- return cliContext . failWithoutThrowing ( "The --output flag currently only works with --preview." ) ;
824+ return cliContext . failWithoutThrowing (
825+ "The --output flag currently only works with --preview." ,
826+ undefined ,
827+ { code : "CONFIG_ERROR" }
828+ ) ;
787829 }
788830 if ( argv . output != null && argv . docs != null ) {
789- return cliContext . failWithoutThrowing ( "The --output flag is not supported for docs generation." ) ;
831+ return cliContext . failWithoutThrowing (
832+ "The --output flag is not supported for docs generation." ,
833+ undefined ,
834+ { code : "CONFIG_ERROR" }
835+ ) ;
790836 }
791837 const correctedGeneratorFilter =
792838 argv . generator != null ? warnAndCorrectIncorrectDockerOrg ( argv . generator , cliContext ) : undefined ;
@@ -1928,7 +1974,7 @@ function addDocsMdCheckCommand(cli: Argv<GlobalCliOptions>, cliContext: CliConte
19281974 } ) ;
19291975
19301976 if ( project . docsWorkspaces == null ) {
1931- cliContext . failAndThrow ( "No docs workspace found" ) ;
1977+ cliContext . failAndThrow ( "No docs workspace found" , undefined , { code : "CONFIG_ERROR" } ) ;
19321978 }
19331979
19341980 const docsWorkspace = project . docsWorkspaces ;
@@ -1947,7 +1993,7 @@ function addDocsMdCheckCommand(cli: Argv<GlobalCliOptions>, cliContext: CliConte
19471993 } ) ;
19481994
19491995 if ( hasErrors ) {
1950- cliContext . failWithoutThrowing ( ) ;
1996+ cliContext . failWithoutThrowing ( undefined , undefined , { code : "VALIDATION_ERROR" } ) ;
19511997 }
19521998 }
19531999 ) ;
@@ -2194,7 +2240,7 @@ function addBetaCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
21942240 await runCliV2 ( v2Args ) ;
21952241 } catch ( error ) {
21962242 cliContext . logger . error ( "CLI v2 failed:" , String ( error ) ) ;
2197- cliContext . failWithoutThrowing ( ) ;
2243+ cliContext . failWithoutThrowing ( undefined , error , { code : "INTERNAL_ERROR" } ) ;
21982244 }
21992245 }
22002246 ) ;
@@ -2339,7 +2385,11 @@ function addReplayInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContex
23392385
23402386 if ( githubRepo == null ) {
23412387 return cliContext . failAndThrow (
2342- "Missing required github config. Either use --group to read from generators.yml, or provide --github directly."
2388+ "Missing required github config. Either use --group to read from generators.yml, or provide --github directly." ,
2389+ undefined ,
2390+ {
2391+ code : "CONFIG_ERROR"
2392+ }
23432393 ) ;
23442394 }
23452395
@@ -2382,7 +2432,9 @@ function addReplayInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContex
23822432 }
23832433
23842434 if ( result . lockfileContent == null ) {
2385- return cliContext . failAndThrow ( "Bootstrap succeeded but lockfile content is missing." ) ;
2435+ return cliContext . failAndThrow ( "Bootstrap succeeded but lockfile content is missing." , undefined , {
2436+ code : "INTERNAL_ERROR"
2437+ } ) ;
23862438 }
23872439
23882440 // Send lockfile to Fiddle for server-side PR creation
@@ -2410,18 +2462,24 @@ function addReplayInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContex
24102462 if ( response . status === 404 ) {
24112463 return cliContext . failAndThrow (
24122464 "The Fern GitHub App is not installed on this repository. " +
2413- "Install it at https://github.com/apps/fern-api to enable server-side PR creation."
2465+ "Install it at https://github.com/apps/fern-api to enable server-side PR creation." ,
2466+ undefined ,
2467+ { code : "CONFIG_ERROR" }
24142468 ) ;
24152469 }
24162470 const body = await response . text ( ) ;
2417- return cliContext . failAndThrow ( `Failed to create PR via Fern: ${ body } ` ) ;
2471+ return cliContext . failAndThrow ( `Failed to create PR via Fern: ${ body } ` , undefined , {
2472+ code : "NETWORK_ERROR"
2473+ } ) ;
24182474 }
24192475
24202476 const data = ( await response . json ( ) ) as { prUrl : string } ;
24212477 cliContext . logger . info ( `\nPR created: ${ data . prUrl } ` ) ;
24222478 cliContext . logger . info ( "Merge the PR to enable Replay for this repository." ) ;
24232479 } catch ( error ) {
2424- cliContext . failAndThrow ( `Failed to initialize Replay: ${ extractErrorMessage ( error ) } ` ) ;
2480+ cliContext . failAndThrow ( `Failed to initialize Replay: ${ extractErrorMessage ( error ) } ` , error , {
2481+ code : "NETWORK_ERROR"
2482+ } ) ;
24252483 }
24262484 }
24272485 ) ;
@@ -2488,12 +2546,18 @@ function addReplayResolveCommand(cli: Argv<GlobalCliOptions>, cliContext: CliCon
24882546 }
24892547 cliContext . logger . warn ( `Resolve them first, then run \`fern replay resolve\` again.` ) ;
24902548 } else {
2491- cliContext . failAndThrow ( `Resolve failed: ${ result . reason ?? "unknown error" } ` ) ;
2549+ cliContext . failAndThrow (
2550+ `Resolve failed: ${ result . reason ?? "unknown error" } ` ,
2551+ undefined ,
2552+ { code : "INTERNAL_ERROR" }
2553+ ) ;
24922554 }
24932555 }
24942556 }
24952557 } catch ( error ) {
2496- cliContext . failAndThrow ( `Failed to resolve: ${ extractErrorMessage ( error ) } ` ) ;
2558+ cliContext . failAndThrow ( `Failed to resolve: ${ extractErrorMessage ( error ) } ` , error , {
2559+ code : "INTERNAL_ERROR"
2560+ } ) ;
24972561 }
24982562 }
24992563 ) ;
@@ -2753,7 +2817,7 @@ function parseOwnerRepo(githubRepo: string): { owner: string; repo: string } {
27532817 const owner = parts [ parts . length - 2 ] ;
27542818 const repo = parts [ parts . length - 1 ] ;
27552819 if ( owner == null || repo == null ) {
2756- throw new Error ( `Could not parse owner/repo from: ${ githubRepo } ` ) ;
2820+ throw new CliError ( { message : `Could not parse owner/repo from: ${ githubRepo } ` , code : "PARSE_ERROR" } ) ;
27572821 }
27582822 return { owner , repo } ;
27592823}
0 commit comments