@@ -192,7 +192,7 @@ async function tryRunCli(cliContext: CliContext) {
192192 cliContext . logger . info ( cliContext . environment . packageVersion ) ;
193193 } else {
194194 cli . showHelp ( ) ;
195- cliContext . failAndThrow ( ) ;
195+ cliContext . failAndThrow ( undefined , undefined , { code : "CONFIG_ERROR" } ) ;
196196 }
197197 }
198198 )
@@ -338,14 +338,22 @@ function addInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
338338 }
339339 }
340340 if ( argv . api != null && argv . docs != null ) {
341- return cliContext . failWithoutThrowing ( "Cannot specify both --api and --docs. Please choose one." ) ;
341+ return cliContext . failWithoutThrowing (
342+ "Cannot specify both --api and --docs. Please choose one." ,
343+ undefined ,
344+ { code : "CONFIG_ERROR" }
345+ ) ;
342346 } else if ( argv . readme != null && argv . mintlify != null ) {
343347 return cliContext . failWithoutThrowing (
344- "Cannot specify both --readme and --mintlify. Please choose one."
348+ "Cannot specify both --readme and --mintlify. Please choose one." ,
349+ undefined ,
350+ { code : "CONFIG_ERROR" }
345351 ) ;
346352 } else if ( argv . openapi != null && argv [ "fern-definition" ] === true ) {
347353 return cliContext . failWithoutThrowing (
348- "Cannot specify both --openapi and --fern-definition. Please choose one."
354+ "Cannot specify both --openapi and --fern-definition. Please choose one." ,
355+ undefined ,
356+ { code : "CONFIG_ERROR" }
349357 ) ;
350358 } else if ( argv . readme != null ) {
351359 await cliContext . runTask ( async ( context ) => {
@@ -380,7 +388,7 @@ function addInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
380388 const result = await loadOpenAPIFromUrl ( { url : argv . openapi , logger : cliContext . logger } ) ;
381389
382390 if ( result . status === LoadOpenAPIStatus . Failure ) {
383- cliContext . failAndThrow ( result . errorMessage ) ;
391+ cliContext . failAndThrow ( result . errorMessage , undefined , { code : "NETWORK_ERROR" } ) ;
384392 }
385393
386394 const tmpFilepath = result . filePath ;
@@ -390,7 +398,9 @@ function addInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
390398 }
391399 const pathExists = await doesPathExist ( absoluteOpenApiPath ) ;
392400 if ( ! pathExists ) {
393- cliContext . failAndThrow ( `${ absoluteOpenApiPath } does not exist` ) ;
401+ cliContext . failAndThrow ( `${ absoluteOpenApiPath } does not exist` , undefined , {
402+ code : "CONFIG_ERROR"
403+ } ) ;
394404 }
395405 }
396406 await cliContext . runTask ( async ( context ) => {
@@ -443,9 +453,11 @@ function addDiffCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
443453 } )
444454 . middleware ( ( argv ) => {
445455 if ( ! haveSameNullishness ( argv . fromGeneratorVersion , argv . toGeneratorVersion ) ) {
446- throw new Error (
447- "Both --from-generator-version and --to-generator-version must be provided together, or neither should be provided"
448- ) ;
456+ throw new CliError ( {
457+ message :
458+ "Both --from-generator-version and --to-generator-version must be provided together, or neither should be provided" ,
459+ code : "VALIDATION_ERROR"
460+ } ) ;
449461 }
450462 } ) ,
451463 async ( argv ) => {
@@ -762,50 +774,84 @@ function addGenerateCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext)
762774 } ) ,
763775 async ( argv ) => {
764776 if ( argv . api != null && argv . docs != null ) {
765- return cliContext . failWithoutThrowing ( "Cannot specify both --api and --docs. Please choose one." ) ;
777+ return cliContext . failWithoutThrowing (
778+ "Cannot specify both --api and --docs. Please choose one." ,
779+ undefined ,
780+ { code : "CONFIG_ERROR" }
781+ ) ;
766782 }
767783 if ( argv . id != null && ! argv . preview ) {
768- return cliContext . failWithoutThrowing ( "The --id flag can only be used with --preview." ) ;
784+ return cliContext . failWithoutThrowing ( "The --id flag can only be used with --preview." , undefined , {
785+ code : "CONFIG_ERROR"
786+ } ) ;
769787 }
770788 if ( argv . id != null && argv . docs == null ) {
771- return cliContext . failWithoutThrowing ( "The --id flag can only be used with --docs." ) ;
789+ return cliContext . failWithoutThrowing ( "The --id flag can only be used with --docs." , undefined , {
790+ code : "CONFIG_ERROR"
791+ } ) ;
772792 }
773793 if ( argv . skipUpload && ! argv . preview ) {
774- return cliContext . failWithoutThrowing ( "The --skip-upload flag can only be used with --preview." ) ;
794+ return cliContext . failWithoutThrowing (
795+ "The --skip-upload flag can only be used with --preview." ,
796+ undefined ,
797+ { code : "CONFIG_ERROR" }
798+ ) ;
775799 }
776800 if ( argv . skipUpload && argv . docs == null ) {
777- return cliContext . failWithoutThrowing ( "The --skip-upload flag can only be used with --docs." ) ;
801+ return cliContext . failWithoutThrowing (
802+ "The --skip-upload flag can only be used with --docs." ,
803+ undefined ,
804+ { code : "CONFIG_ERROR" }
805+ ) ;
778806 }
779807 if ( argv . fernignore != null && ( argv . local || argv . runner != null ) ) {
780808 return cliContext . failWithoutThrowing (
781- "The --fernignore flag is not supported with local generation (--local or --runner). It can only be used with remote generation."
809+ "The --fernignore flag is not supported with local generation (--local or --runner). It can only be used with remote generation." ,
810+ undefined ,
811+ { code : "CONFIG_ERROR" }
782812 ) ;
783813 }
784814 if ( argv [ "skip-fernignore" ] && argv . fernignore != null ) {
785815 return cliContext . failWithoutThrowing (
786- "The --skip-fernignore and --fernignore flags cannot be used together."
816+ "The --skip-fernignore and --fernignore flags cannot be used together." ,
817+ undefined ,
818+ { code : "CONFIG_ERROR" }
787819 ) ;
788820 }
789821 if ( argv [ "dynamic-ir-only" ] && ( argv . local || argv . runner != null ) ) {
790822 return cliContext . failWithoutThrowing (
791- "The --dynamic-ir-only flag is not supported with local generation (--local or --runner). It can only be used with remote generation."
823+ "The --dynamic-ir-only flag is not supported with local generation (--local or --runner). It can only be used with remote generation." ,
824+ undefined ,
825+ { code : "CONFIG_ERROR" }
792826 ) ;
793827 }
794828 if ( argv [ "dynamic-ir-only" ] && argv . version == null ) {
795829 return cliContext . failWithoutThrowing (
796- "The --dynamic-ir-only flag requires a version to be specified with --version."
830+ "The --dynamic-ir-only flag requires a version to be specified with --version." ,
831+ undefined ,
832+ { code : "CONFIG_ERROR" }
797833 ) ;
798834 }
799835 if ( argv [ "dynamic-ir-only" ] && argv . docs != null ) {
800836 return cliContext . failWithoutThrowing (
801- "The --dynamic-ir-only flag can only be used for API generation, not docs generation."
837+ "The --dynamic-ir-only flag can only be used for API generation, not docs generation." ,
838+ undefined ,
839+ { code : "CONFIG_ERROR" }
802840 ) ;
803841 }
804842 if ( argv . output != null && ! argv . preview ) {
805- return cliContext . failWithoutThrowing ( "The --output flag currently only works with --preview." ) ;
843+ return cliContext . failWithoutThrowing (
844+ "The --output flag currently only works with --preview." ,
845+ undefined ,
846+ { code : "CONFIG_ERROR" }
847+ ) ;
806848 }
807849 if ( argv . output != null && argv . docs != null ) {
808- return cliContext . failWithoutThrowing ( "The --output flag is not supported for docs generation." ) ;
850+ return cliContext . failWithoutThrowing (
851+ "The --output flag is not supported for docs generation." ,
852+ undefined ,
853+ { code : "CONFIG_ERROR" }
854+ ) ;
809855 }
810856 const correctedGeneratorFilter =
811857 argv . generator != null ? warnAndCorrectIncorrectDockerOrg ( argv . generator , cliContext ) : undefined ;
@@ -1942,7 +1988,7 @@ function addDocsMdCheckCommand(cli: Argv<GlobalCliOptions>, cliContext: CliConte
19421988 } ) ;
19431989
19441990 if ( project . docsWorkspaces == null ) {
1945- cliContext . failAndThrow ( "No docs workspace found" ) ;
1991+ cliContext . failAndThrow ( "No docs workspace found" , undefined , { code : "CONFIG_ERROR" } ) ;
19461992 }
19471993
19481994 const docsWorkspace = project . docsWorkspaces ;
@@ -1961,7 +2007,7 @@ function addDocsMdCheckCommand(cli: Argv<GlobalCliOptions>, cliContext: CliConte
19612007 } ) ;
19622008
19632009 if ( hasErrors ) {
1964- cliContext . failWithoutThrowing ( ) ;
2010+ cliContext . failWithoutThrowing ( undefined , undefined , { code : "VALIDATION_ERROR" } ) ;
19652011 }
19662012 }
19672013 ) ;
@@ -2208,7 +2254,7 @@ function addBetaCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
22082254 await runCliV2 ( v2Args ) ;
22092255 } catch ( error ) {
22102256 cliContext . logger . error ( "CLI v2 failed:" , String ( error ) ) ;
2211- cliContext . failWithoutThrowing ( ) ;
2257+ cliContext . failWithoutThrowing ( undefined , error , { code : "INTERNAL_ERROR" } ) ;
22122258 }
22132259 }
22142260 ) ;
@@ -2354,7 +2400,9 @@ function addReplayInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContex
23542400 githubRepo != null
23552401 ? "Repository found but no token. Pass --token or set GITHUB_TOKEN environment variable."
23562402 : "Either use --group to read from generators.yml, or provide --github and --token directly." ;
2357- return cliContext . failAndThrow ( `Missing required github config. ${ hint } ` ) ;
2403+ return cliContext . failAndThrow ( `Missing required github config. ${ hint } ` , undefined , {
2404+ code : "CONFIG_ERROR"
2405+ } ) ;
23582406 }
23592407
23602408 cliContext . logger . info ( `Initializing Replay for: ${ githubRepo } ` ) ;
@@ -2390,7 +2438,9 @@ function addReplayInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContex
23902438 }
23912439
23922440 if ( result . lockfileContent == null ) {
2393- return cliContext . failAndThrow ( "Bootstrap succeeded but lockfile content is missing." ) ;
2441+ return cliContext . failAndThrow ( "Bootstrap succeeded but lockfile content is missing." , undefined , {
2442+ code : "INTERNAL_ERROR"
2443+ } ) ;
23942444 }
23952445
23962446 // Send lockfile to Fiddle for server-side PR creation
@@ -2418,18 +2468,24 @@ function addReplayInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContex
24182468 if ( response . status === 404 ) {
24192469 return cliContext . failAndThrow (
24202470 "The Fern GitHub App is not installed on this repository. " +
2421- "Install it at https://github.com/apps/fern-api to enable server-side PR creation."
2471+ "Install it at https://github.com/apps/fern-api to enable server-side PR creation." ,
2472+ undefined ,
2473+ { code : "CONFIG_ERROR" }
24222474 ) ;
24232475 }
24242476 const body = await response . text ( ) ;
2425- return cliContext . failAndThrow ( `Failed to create PR via Fern: ${ body } ` ) ;
2477+ return cliContext . failAndThrow ( `Failed to create PR via Fern: ${ body } ` , undefined , {
2478+ code : "NETWORK_ERROR"
2479+ } ) ;
24262480 }
24272481
24282482 const data = ( await response . json ( ) ) as { prUrl : string } ;
24292483 cliContext . logger . info ( `\nPR created: ${ data . prUrl } ` ) ;
24302484 cliContext . logger . info ( "Merge the PR to enable Replay for this repository." ) ;
24312485 } catch ( error ) {
2432- cliContext . failAndThrow ( `Failed to initialize Replay: ${ extractErrorMessage ( error ) } ` ) ;
2486+ cliContext . failAndThrow ( `Failed to initialize Replay: ${ extractErrorMessage ( error ) } ` , error , {
2487+ code : "NETWORK_ERROR"
2488+ } ) ;
24332489 }
24342490 }
24352491 ) ;
@@ -2496,12 +2552,18 @@ function addReplayResolveCommand(cli: Argv<GlobalCliOptions>, cliContext: CliCon
24962552 }
24972553 cliContext . logger . warn ( `Resolve them first, then run \`fern replay resolve\` again.` ) ;
24982554 } else {
2499- cliContext . failAndThrow ( `Resolve failed: ${ result . reason ?? "unknown error" } ` ) ;
2555+ cliContext . failAndThrow (
2556+ `Resolve failed: ${ result . reason ?? "unknown error" } ` ,
2557+ undefined ,
2558+ { code : "INTERNAL_ERROR" }
2559+ ) ;
25002560 }
25012561 }
25022562 }
25032563 } catch ( error ) {
2504- cliContext . failAndThrow ( `Failed to resolve: ${ extractErrorMessage ( error ) } ` ) ;
2564+ cliContext . failAndThrow ( `Failed to resolve: ${ extractErrorMessage ( error ) } ` , error , {
2565+ code : "INTERNAL_ERROR"
2566+ } ) ;
25052567 }
25062568 }
25072569 ) ;
@@ -2516,7 +2578,7 @@ function parseOwnerRepo(githubRepo: string): { owner: string; repo: string } {
25162578 const owner = parts [ parts . length - 2 ] ;
25172579 const repo = parts [ parts . length - 1 ] ;
25182580 if ( owner == null || repo == null ) {
2519- throw new Error ( `Could not parse owner/repo from: ${ githubRepo } ` ) ;
2581+ throw new CliError ( { message : `Could not parse owner/repo from: ${ githubRepo } ` , code : "PARSE_ERROR" } ) ;
25202582 }
25212583 return { owner , repo } ;
25222584}
0 commit comments