@@ -176,7 +176,7 @@ async function tryRunCli(cliContext: CliContext) {
176176 cliContext . logger . info ( cliContext . environment . packageVersion ) ;
177177 } else {
178178 cli . showHelp ( ) ;
179- cliContext . failAndThrow ( ) ;
179+ cliContext . failAndThrow ( undefined , undefined , { code : "CONFIG_ERROR" } ) ;
180180 }
181181 }
182182 )
@@ -322,14 +322,22 @@ function addInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
322322 }
323323 }
324324 if ( argv . api != null && argv . docs != null ) {
325- return cliContext . failWithoutThrowing ( "Cannot specify both --api and --docs. Please choose one." ) ;
325+ return cliContext . failWithoutThrowing (
326+ "Cannot specify both --api and --docs. Please choose one." ,
327+ undefined ,
328+ { code : "CONFIG_ERROR" }
329+ ) ;
326330 } else if ( argv . readme != null && argv . mintlify != null ) {
327331 return cliContext . failWithoutThrowing (
328- "Cannot specify both --readme and --mintlify. Please choose one."
332+ "Cannot specify both --readme and --mintlify. Please choose one." ,
333+ undefined ,
334+ { code : "CONFIG_ERROR" }
329335 ) ;
330336 } else if ( argv . openapi != null && argv [ "fern-definition" ] === true ) {
331337 return cliContext . failWithoutThrowing (
332- "Cannot specify both --openapi and --fern-definition. Please choose one."
338+ "Cannot specify both --openapi and --fern-definition. Please choose one." ,
339+ undefined ,
340+ { code : "CONFIG_ERROR" }
333341 ) ;
334342 } else if ( argv . readme != null ) {
335343 await cliContext . runTask ( async ( context ) => {
@@ -364,7 +372,7 @@ function addInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
364372 const result = await loadOpenAPIFromUrl ( { url : argv . openapi , logger : cliContext . logger } ) ;
365373
366374 if ( result . status === LoadOpenAPIStatus . Failure ) {
367- cliContext . failAndThrow ( result . errorMessage ) ;
375+ cliContext . failAndThrow ( result . errorMessage , undefined , { code : "NETWORK_ERROR" } ) ;
368376 }
369377
370378 const tmpFilepath = result . filePath ;
@@ -374,7 +382,9 @@ function addInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
374382 }
375383 const pathExists = await doesPathExist ( absoluteOpenApiPath ) ;
376384 if ( ! pathExists ) {
377- cliContext . failAndThrow ( `${ absoluteOpenApiPath } does not exist` ) ;
385+ cliContext . failAndThrow ( `${ absoluteOpenApiPath } does not exist` , undefined , {
386+ code : "CONFIG_ERROR"
387+ } ) ;
378388 }
379389 }
380390 await cliContext . runTask ( async ( context ) => {
@@ -427,9 +437,11 @@ function addDiffCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
427437 } )
428438 . middleware ( ( argv ) => {
429439 if ( ! haveSameNullishness ( argv . fromGeneratorVersion , argv . toGeneratorVersion ) ) {
430- throw new Error (
431- "Both --from-generator-version and --to-generator-version must be provided together, or neither should be provided"
432- ) ;
440+ throw new CliError ( {
441+ message :
442+ "Both --from-generator-version and --to-generator-version must be provided together, or neither should be provided" ,
443+ code : "VALIDATION_ERROR"
444+ } ) ;
433445 }
434446 } ) ,
435447 async ( argv ) => {
@@ -746,50 +758,84 @@ function addGenerateCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext)
746758 } ) ,
747759 async ( argv ) => {
748760 if ( argv . api != null && argv . docs != null ) {
749- return cliContext . failWithoutThrowing ( "Cannot specify both --api and --docs. Please choose one." ) ;
761+ return cliContext . failWithoutThrowing (
762+ "Cannot specify both --api and --docs. Please choose one." ,
763+ undefined ,
764+ { code : "CONFIG_ERROR" }
765+ ) ;
750766 }
751767 if ( argv . id != null && ! argv . preview ) {
752- return cliContext . failWithoutThrowing ( "The --id flag can only be used with --preview." ) ;
768+ return cliContext . failWithoutThrowing ( "The --id flag can only be used with --preview." , undefined , {
769+ code : "CONFIG_ERROR"
770+ } ) ;
753771 }
754772 if ( argv . id != null && argv . docs == null ) {
755- return cliContext . failWithoutThrowing ( "The --id flag can only be used with --docs." ) ;
773+ return cliContext . failWithoutThrowing ( "The --id flag can only be used with --docs." , undefined , {
774+ code : "CONFIG_ERROR"
775+ } ) ;
756776 }
757777 if ( argv . skipUpload && ! argv . preview ) {
758- return cliContext . failWithoutThrowing ( "The --skip-upload flag can only be used with --preview." ) ;
778+ return cliContext . failWithoutThrowing (
779+ "The --skip-upload flag can only be used with --preview." ,
780+ undefined ,
781+ { code : "CONFIG_ERROR" }
782+ ) ;
759783 }
760784 if ( argv . skipUpload && argv . docs == null ) {
761- return cliContext . failWithoutThrowing ( "The --skip-upload flag can only be used with --docs." ) ;
785+ return cliContext . failWithoutThrowing (
786+ "The --skip-upload flag can only be used with --docs." ,
787+ undefined ,
788+ { code : "CONFIG_ERROR" }
789+ ) ;
762790 }
763791 if ( argv . fernignore != null && ( argv . local || argv . runner != null ) ) {
764792 return cliContext . failWithoutThrowing (
765- "The --fernignore flag is not supported with local generation (--local or --runner). It can only be used with remote generation."
793+ "The --fernignore flag is not supported with local generation (--local or --runner). It can only be used with remote generation." ,
794+ undefined ,
795+ { code : "CONFIG_ERROR" }
766796 ) ;
767797 }
768798 if ( argv [ "skip-fernignore" ] && argv . fernignore != null ) {
769799 return cliContext . failWithoutThrowing (
770- "The --skip-fernignore and --fernignore flags cannot be used together."
800+ "The --skip-fernignore and --fernignore flags cannot be used together." ,
801+ undefined ,
802+ { code : "CONFIG_ERROR" }
771803 ) ;
772804 }
773805 if ( argv [ "dynamic-ir-only" ] && ( argv . local || argv . runner != null ) ) {
774806 return cliContext . failWithoutThrowing (
775- "The --dynamic-ir-only flag is not supported with local generation (--local or --runner). It can only be used with remote generation."
807+ "The --dynamic-ir-only flag is not supported with local generation (--local or --runner). It can only be used with remote generation." ,
808+ undefined ,
809+ { code : "CONFIG_ERROR" }
776810 ) ;
777811 }
778812 if ( argv [ "dynamic-ir-only" ] && argv . version == null ) {
779813 return cliContext . failWithoutThrowing (
780- "The --dynamic-ir-only flag requires a version to be specified with --version."
814+ "The --dynamic-ir-only flag requires a version to be specified with --version." ,
815+ undefined ,
816+ { code : "CONFIG_ERROR" }
781817 ) ;
782818 }
783819 if ( argv [ "dynamic-ir-only" ] && argv . docs != null ) {
784820 return cliContext . failWithoutThrowing (
785- "The --dynamic-ir-only flag can only be used for API generation, not docs generation."
821+ "The --dynamic-ir-only flag can only be used for API generation, not docs generation." ,
822+ undefined ,
823+ { code : "CONFIG_ERROR" }
786824 ) ;
787825 }
788826 if ( argv . output != null && ! argv . preview ) {
789- return cliContext . failWithoutThrowing ( "The --output flag currently only works with --preview." ) ;
827+ return cliContext . failWithoutThrowing (
828+ "The --output flag currently only works with --preview." ,
829+ undefined ,
830+ { code : "CONFIG_ERROR" }
831+ ) ;
790832 }
791833 if ( argv . output != null && argv . docs != null ) {
792- return cliContext . failWithoutThrowing ( "The --output flag is not supported for docs generation." ) ;
834+ return cliContext . failWithoutThrowing (
835+ "The --output flag is not supported for docs generation." ,
836+ undefined ,
837+ { code : "CONFIG_ERROR" }
838+ ) ;
793839 }
794840 const correctedGeneratorFilter =
795841 argv . generator != null ? warnAndCorrectIncorrectDockerOrg ( argv . generator , cliContext ) : undefined ;
@@ -1931,7 +1977,7 @@ function addDocsMdCheckCommand(cli: Argv<GlobalCliOptions>, cliContext: CliConte
19311977 } ) ;
19321978
19331979 if ( project . docsWorkspaces == null ) {
1934- cliContext . failAndThrow ( "No docs workspace found" ) ;
1980+ cliContext . failAndThrow ( "No docs workspace found" , undefined , { code : "CONFIG_ERROR" } ) ;
19351981 }
19361982
19371983 const docsWorkspace = project . docsWorkspaces ;
@@ -1950,7 +1996,7 @@ function addDocsMdCheckCommand(cli: Argv<GlobalCliOptions>, cliContext: CliConte
19501996 } ) ;
19511997
19521998 if ( hasErrors ) {
1953- cliContext . failWithoutThrowing ( ) ;
1999+ cliContext . failWithoutThrowing ( undefined , undefined , { code : "VALIDATION_ERROR" } ) ;
19542000 }
19552001 }
19562002 ) ;
@@ -2205,7 +2251,7 @@ function addBetaCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContext) {
22052251 await runCliV2 ( v2Args ) ;
22062252 } catch ( error ) {
22072253 cliContext . logger . error ( "CLI v2 failed:" , String ( error ) ) ;
2208- cliContext . failWithoutThrowing ( ) ;
2254+ cliContext . failWithoutThrowing ( undefined , error , { code : "INTERNAL_ERROR" } ) ;
22092255 }
22102256 }
22112257 ) ;
@@ -2350,7 +2396,11 @@ function addReplayInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContex
23502396
23512397 if ( githubRepo == null ) {
23522398 return cliContext . failAndThrow (
2353- "Missing required github config. Either use --group to read from generators.yml, or provide --github directly."
2399+ "Missing required github config. Either use --group to read from generators.yml, or provide --github directly." ,
2400+ undefined ,
2401+ {
2402+ code : "CONFIG_ERROR"
2403+ }
23542404 ) ;
23552405 }
23562406
@@ -2393,7 +2443,9 @@ function addReplayInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContex
23932443 }
23942444
23952445 if ( result . lockfileContent == null ) {
2396- return cliContext . failAndThrow ( "Bootstrap succeeded but lockfile content is missing." ) ;
2446+ return cliContext . failAndThrow ( "Bootstrap succeeded but lockfile content is missing." , undefined , {
2447+ code : "INTERNAL_ERROR"
2448+ } ) ;
23972449 }
23982450
23992451 // Send lockfile to Fiddle for server-side PR creation
@@ -2421,18 +2473,24 @@ function addReplayInitCommand(cli: Argv<GlobalCliOptions>, cliContext: CliContex
24212473 if ( response . status === 404 ) {
24222474 return cliContext . failAndThrow (
24232475 "The Fern GitHub App is not installed on this repository. " +
2424- "Install it at https://github.com/apps/fern-api to enable server-side PR creation."
2476+ "Install it at https://github.com/apps/fern-api to enable server-side PR creation." ,
2477+ undefined ,
2478+ { code : "CONFIG_ERROR" }
24252479 ) ;
24262480 }
24272481 const body = await response . text ( ) ;
2428- return cliContext . failAndThrow ( `Failed to create PR via Fern: ${ body } ` ) ;
2482+ return cliContext . failAndThrow ( `Failed to create PR via Fern: ${ body } ` , undefined , {
2483+ code : "NETWORK_ERROR"
2484+ } ) ;
24292485 }
24302486
24312487 const data = ( await response . json ( ) ) as { prUrl : string } ;
24322488 cliContext . logger . info ( `\nPR created: ${ data . prUrl } ` ) ;
24332489 cliContext . logger . info ( "Merge the PR to enable Replay for this repository." ) ;
24342490 } catch ( error ) {
2435- cliContext . failAndThrow ( `Failed to initialize Replay: ${ extractErrorMessage ( error ) } ` ) ;
2491+ cliContext . failAndThrow ( `Failed to initialize Replay: ${ extractErrorMessage ( error ) } ` , error , {
2492+ code : "NETWORK_ERROR"
2493+ } ) ;
24362494 }
24372495 }
24382496 ) ;
@@ -2499,12 +2557,18 @@ function addReplayResolveCommand(cli: Argv<GlobalCliOptions>, cliContext: CliCon
24992557 }
25002558 cliContext . logger . warn ( `Resolve them first, then run \`fern replay resolve\` again.` ) ;
25012559 } else {
2502- cliContext . failAndThrow ( `Resolve failed: ${ result . reason ?? "unknown error" } ` ) ;
2560+ cliContext . failAndThrow (
2561+ `Resolve failed: ${ result . reason ?? "unknown error" } ` ,
2562+ undefined ,
2563+ { code : "INTERNAL_ERROR" }
2564+ ) ;
25032565 }
25042566 }
25052567 }
25062568 } catch ( error ) {
2507- cliContext . failAndThrow ( `Failed to resolve: ${ extractErrorMessage ( error ) } ` ) ;
2569+ cliContext . failAndThrow ( `Failed to resolve: ${ extractErrorMessage ( error ) } ` , error , {
2570+ code : "INTERNAL_ERROR"
2571+ } ) ;
25082572 }
25092573 }
25102574 ) ;
@@ -2764,7 +2828,7 @@ function parseOwnerRepo(githubRepo: string): { owner: string; repo: string } {
27642828 const owner = parts [ parts . length - 2 ] ;
27652829 const repo = parts [ parts . length - 1 ] ;
27662830 if ( owner == null || repo == null ) {
2767- throw new Error ( `Could not parse owner/repo from: ${ githubRepo } ` ) ;
2831+ throw new CliError ( { message : `Could not parse owner/repo from: ${ githubRepo } ` , code : "PARSE_ERROR" } ) ;
27682832 }
27692833 return { owner , repo } ;
27702834}
0 commit comments