@@ -262,6 +262,24 @@ const getCommandSuggestion = (argv: ReadonlyArray<string>): string | null => {
262262 return null ;
263263} ;
264264
265+ const getPreAuthCommandMismatchMessage = ( argv : ReadonlyArray < string > ) : string | null => {
266+ const args = normalizeArgsForSuggestion ( argv ) ;
267+ const first = args [ 0 ] ;
268+ if ( ! first ) return null ;
269+
270+ if ( ! ROOT_COMMANDS . includes ( first as ( typeof ROOT_COMMANDS ) [ number ] ) ) {
271+ return getCommandSuggestion ( argv ) ?? "Need command help? Run 'ep-admin --help'." ;
272+ }
273+
274+ const nested = NESTED_COMMANDS [ first ] ;
275+ const second = args [ 1 ] ;
276+ if ( nested && second && ! nested . includes ( second ) ) {
277+ return getCommandSuggestion ( argv ) ?? "Need command help? Run 'ep-admin --help'." ;
278+ }
279+
280+ return null ;
281+ } ;
282+
265283const isAuthExemptArgv = ( argv : ReadonlyArray < string > ) : boolean => {
266284 const args = argv . slice ( 2 ) ;
267285 if ( args . length === 0 ) return true ;
@@ -318,51 +336,152 @@ const normalizeLegacyArgs = (
318336 return { argv : args , warnings } ;
319337} ;
320338
339+ type TaggedAuthError = {
340+ readonly _tag : string ;
341+ readonly message : string ;
342+ readonly expectedUser ?: string ;
343+ readonly currentUser ?: string ;
344+ } ;
345+
346+ const isTaggedAuthError = ( value : unknown ) : value is TaggedAuthError =>
347+ typeof value === "object" &&
348+ value !== null &&
349+ "_tag" in value &&
350+ typeof ( value as { _tag ?: unknown } ) . _tag === "string" &&
351+ "message" in value &&
352+ typeof ( value as { message ?: unknown } ) . message === "string" ;
353+
354+ const extractFailureFromCause = ( cause : unknown ) : unknown | undefined => {
355+ if ( typeof cause !== "object" || cause === null ) {
356+ return undefined ;
357+ }
358+
359+ const taggedCause = cause as {
360+ readonly _tag ?: string ;
361+ readonly error ?: unknown ;
362+ readonly defect ?: unknown ;
363+ readonly failure ?: unknown ;
364+ readonly cause ?: unknown ;
365+ readonly left ?: unknown ;
366+ readonly right ?: unknown ;
367+ } ;
368+
369+ switch ( taggedCause . _tag ) {
370+ case "Fail" :
371+ return taggedCause . error ?? taggedCause . failure ;
372+ case "Die" :
373+ return taggedCause . defect ?? taggedCause . error ?? taggedCause . failure ;
374+ case "Traced" :
375+ return extractFailureFromCause ( taggedCause . cause ) ;
376+ case "Sequential" :
377+ case "Parallel" : {
378+ const left = extractFailureFromCause ( taggedCause . left ) ;
379+ if ( left !== undefined ) return left ;
380+ return extractFailureFromCause ( taggedCause . right ) ;
381+ }
382+ default :
383+ return undefined ;
384+ }
385+ } ;
386+
387+ const unwrapFiberFailure = ( error : unknown ) : unknown => {
388+ if ( typeof error !== "object" || error === null ) {
389+ return error ;
390+ }
391+
392+ for ( const symbol of Object . getOwnPropertySymbols ( error ) ) {
393+ if ( ! String ( symbol ) . includes ( "FiberFailure/Cause" ) ) {
394+ continue ;
395+ }
396+ const cause = ( error as Record < symbol , unknown > ) [ symbol ] ;
397+ const failure = extractFailureFromCause ( cause ) ;
398+ if ( failure !== undefined ) {
399+ return failure ;
400+ }
401+ }
402+
403+ return error ;
404+ } ;
405+
321406const extractErrorMessage = ( error : unknown , argv : ReadonlyArray < string > ) : string | null => {
322- if ( error instanceof AuthNotInitializedError ) {
407+ const resolvedError = unwrapFiberFailure ( error ) ;
408+
409+ if ( resolvedError instanceof AuthNotInitializedError ) {
323410 return [
324411 "ep-admin authentication is not initialized." ,
325412 "Run: ep-admin auth init" ,
326413 `Docs: ${ EP_ADMIN_DOCS_URL } ` ,
327414 ] . join ( "\n" ) ;
328415 }
329416
330- if ( error instanceof AuthInvalidCredentialsError ) {
417+ if ( resolvedError instanceof AuthInvalidCredentialsError ) {
331418 return [
332419 "ep-admin login required." ,
333420 "Run: ep-admin auth login" ,
334421 `Docs: ${ EP_ADMIN_DOCS_URL } ` ,
335422 ] . join ( "\n" ) ;
336423 }
337424
338- if ( error instanceof AuthSessionExpiredError ) {
425+ if ( resolvedError instanceof AuthSessionExpiredError ) {
339426 return [
340427 "ep-admin session expired." ,
341428 "Run: ep-admin auth login" ,
342429 `Docs: ${ EP_ADMIN_DOCS_URL } ` ,
343430 ] . join ( "\n" ) ;
344431 }
345432
346- if ( error instanceof AuthUnauthorizedUserError ) {
433+ if ( resolvedError instanceof AuthUnauthorizedUserError ) {
347434 return [
348- `Unauthorized OS user '${ error . currentUser } '.` ,
349- `Authorized user: '${ error . expectedUser } '.` ,
435+ `Unauthorized OS user '${ resolvedError . currentUser } '.` ,
436+ `Authorized user: '${ resolvedError . expectedUser } '.` ,
350437 `Docs: ${ EP_ADMIN_DOCS_URL } ` ,
351438 ] . join ( "\n" ) ;
352439 }
353440
354- if ( error instanceof AuthServiceTokenError ) {
355- return `${ error . message } \nDocs: ${ EP_ADMIN_DOCS_URL } ` ;
441+ if ( resolvedError instanceof AuthServiceTokenError ) {
442+ return `${ resolvedError . message } \nDocs: ${ EP_ADMIN_DOCS_URL } ` ;
356443 }
357444
358- if ( error instanceof AuthConfigurationError ) {
359- return `${ error . message } \nDocs: ${ EP_ADMIN_DOCS_URL } ` ;
445+ if ( resolvedError instanceof AuthConfigurationError ) {
446+ return `${ resolvedError . message } \nDocs: ${ EP_ADMIN_DOCS_URL } ` ;
360447 }
361448
362- if ( typeof error === "string" ) return error ;
449+ if ( isTaggedAuthError ( resolvedError ) ) {
450+ switch ( resolvedError . _tag ) {
451+ case "AuthNotInitializedError" :
452+ return [
453+ "ep-admin authentication is not initialized." ,
454+ "Run: ep-admin auth init" ,
455+ `Docs: ${ EP_ADMIN_DOCS_URL } ` ,
456+ ] . join ( "\n" ) ;
457+ case "AuthInvalidCredentialsError" :
458+ return [
459+ "ep-admin login required." ,
460+ "Run: ep-admin auth login" ,
461+ `Docs: ${ EP_ADMIN_DOCS_URL } ` ,
462+ ] . join ( "\n" ) ;
463+ case "AuthSessionExpiredError" :
464+ return [
465+ "ep-admin session expired." ,
466+ "Run: ep-admin auth login" ,
467+ `Docs: ${ EP_ADMIN_DOCS_URL } ` ,
468+ ] . join ( "\n" ) ;
469+ case "AuthUnauthorizedUserError" :
470+ return [
471+ `Unauthorized OS user '${ resolvedError . currentUser ?? "unknown" } '.` ,
472+ `Authorized user: '${ resolvedError . expectedUser ?? "unknown" } '.` ,
473+ `Docs: ${ EP_ADMIN_DOCS_URL } ` ,
474+ ] . join ( "\n" ) ;
475+ case "AuthServiceTokenError" :
476+ case "AuthConfigurationError" :
477+ return `${ resolvedError . message } \nDocs: ${ EP_ADMIN_DOCS_URL } ` ;
478+ }
479+ }
480+
481+ if ( typeof resolvedError === "string" ) return resolvedError ;
363482
364- if ( error instanceof Error ) {
365- const combined = [ error . message , error . stack ] . filter ( Boolean ) . join ( "\n" ) ;
483+ if ( resolvedError instanceof Error ) {
484+ const combined = [ resolvedError . message , resolvedError . stack ] . filter ( Boolean ) . join ( "\n" ) ;
366485 if ( combined . includes ( "CommandMismatch" ) ) {
367486 const suggestion = getCommandSuggestion ( argv ) ;
368487 return [
@@ -371,12 +490,12 @@ const extractErrorMessage = (error: unknown, argv: ReadonlyArray<string>): strin
371490 ] . join ( "\n" ) ;
372491 }
373492
374- if ( error . message . trim ( ) ) {
375- return `${ error . message . trim ( ) } \nDocs: ${ EP_ADMIN_DOCS_URL } ` ;
493+ if ( resolvedError . message . trim ( ) ) {
494+ return `${ resolvedError . message . trim ( ) } \nDocs: ${ EP_ADMIN_DOCS_URL } ` ;
376495 }
377496 }
378497
379- return String ( error ) ;
498+ return String ( resolvedError ) ;
380499} ;
381500
382501export const createAdminProgram = (
@@ -396,6 +515,11 @@ export const runCli = (
396515 yield * validateEnvironment ;
397516
398517 if ( ! isAuthExemptArgv ( prepared . argv ) ) {
518+ const commandMismatchMessage = getPreAuthCommandMismatchMessage ( prepared . argv ) ;
519+ if ( commandMismatchMessage ) {
520+ return yield * Effect . fail ( new Error ( commandMismatchMessage ) ) ;
521+ }
522+
399523 const auth = yield * Auth ;
400524 yield * auth . ensureAuthorized ( process . env . EP_ADMIN_SERVICE_TOKEN ) ;
401525 }
0 commit comments