@@ -198,6 +198,63 @@ const NESTED_COMMANDS: Record<string, readonly string[]> = {
198198 release : [ "preview" , "create" ] ,
199199} ;
200200
201+ const ROOT_HELP_COMMANDS : ReadonlyArray < {
202+ readonly name : string ;
203+ readonly description : string ;
204+ } > = [
205+ { name : "auth" , description : "Initialize/login/logout and check admin session state" } ,
206+ { name : "publish" , description : "Validate, test, publish, and generate release artifacts" } ,
207+ { name : "pattern" , description : "Search patterns and generate skill assets" } ,
208+ { name : "data" , description : "Run ingest, Discord, and QA workflows" } ,
209+ { name : "db" , description : "Inspect, test, and migrate database state" } ,
210+ { name : "dev" , description : "Run development utilities and autofix tools" } ,
211+ { name : "ops" , description : "Run health checks and maintenance commands" } ,
212+ { name : "config" , description : "Install rules/skills and manage entities" } ,
213+ { name : "system" , description : "Generate/install shell completions" } ,
214+ { name : "release" , description : "Preview and create tagged releases" } ,
215+ ] ;
216+
217+ const renderCompactRootHelp = ( ) : string => {
218+ const lines = [
219+ `${ CLI . RUNNER_NAME } ${ CLI . VERSION } ` ,
220+ "" ,
221+ CLI . DESCRIPTION ,
222+ "" ,
223+ "USAGE" ,
224+ " ep-admin <command> [subcommand] [options]" ,
225+ "" ,
226+ "Top-level commands:" ,
227+ ...ROOT_HELP_COMMANDS . map (
228+ ( command ) => ` ${ command . name . padEnd ( 10 ) } ${ command . description } `
229+ ) ,
230+ "" ,
231+ "Get detailed help:" ,
232+ " ep-admin <command> --help" ,
233+ "" ,
234+ "Quick start:" ,
235+ " ep-admin auth init" ,
236+ " ep-admin auth login" ,
237+ " ep-admin ops health-check" ,
238+ " ep-admin publish pipeline" ,
239+ "" ,
240+ `Docs: ${ EP_ADMIN_DOCS_URL } ` ,
241+ ] ;
242+ return lines . join ( "\n" ) ;
243+ } ;
244+
245+ const isRootHelpRequest = ( argv : ReadonlyArray < string > ) : boolean => {
246+ const args = argv . slice ( 2 ) ;
247+ if ( args . length === 0 ) return true ;
248+
249+ const hasHelpFlag = args . includes ( "--help" ) || args . includes ( "-h" ) ;
250+ if ( ! hasHelpFlag ) return false ;
251+
252+ const hasPositional = args . some (
253+ ( token ) => token . length > 0 && ! token . startsWith ( "-" )
254+ ) ;
255+ return ! hasPositional ;
256+ } ;
257+
201258const normalizeArgsForSuggestion = ( argv : ReadonlyArray < string > ) : string [ ] =>
202259 argv . slice ( 2 ) . filter ( ( token ) => token . length > 0 && ! token . startsWith ( "-" ) ) ;
203260
@@ -280,6 +337,34 @@ const getPreAuthCommandMismatchMessage = (argv: ReadonlyArray<string>): string |
280337 return null ;
281338} ;
282339
340+ const getContextualHelpCommand = ( argv : ReadonlyArray < string > ) : string => {
341+ const args = normalizeArgsForSuggestion ( argv ) ;
342+ const first = args [ 0 ] ;
343+ if ( first && ROOT_COMMANDS . includes ( first as ( typeof ROOT_COMMANDS ) [ number ] ) ) {
344+ return `ep-admin ${ first } --help` ;
345+ }
346+ return "ep-admin --help" ;
347+ } ;
348+
349+ const appendStandardErrorGuidance = (
350+ message : string ,
351+ argv : ReadonlyArray < string >
352+ ) : string => {
353+ const trimmed = message . trim ( ) ;
354+ const lines = trimmed . length > 0 ? [ trimmed ] : [ ] ;
355+ const hasRunLine = / \b R u n : \s * e p - a d m i n \b / i. test ( trimmed ) ;
356+ const hasDocsLine = / \b D o c s : \s * h t t p s ? : \/ \/ / i. test ( trimmed ) ;
357+
358+ if ( ! hasRunLine ) {
359+ lines . push ( `Run: ${ getContextualHelpCommand ( argv ) } ` ) ;
360+ }
361+ if ( ! hasDocsLine ) {
362+ lines . push ( `Docs: ${ EP_ADMIN_DOCS_URL } ` ) ;
363+ }
364+
365+ return lines . join ( "\n" ) ;
366+ } ;
367+
283368const isAuthExemptArgv = ( argv : ReadonlyArray < string > ) : boolean => {
284369 const args = argv . slice ( 2 ) ;
285370 if ( args . length === 0 ) return true ;
@@ -478,24 +563,26 @@ const extractErrorMessage = (error: unknown, argv: ReadonlyArray<string>): strin
478563 }
479564 }
480565
481- if ( typeof resolvedError === "string" ) return resolvedError ;
566+ if ( typeof resolvedError === "string" ) {
567+ return appendStandardErrorGuidance ( resolvedError , argv ) ;
568+ }
482569
483570 if ( resolvedError instanceof Error ) {
484571 const combined = [ resolvedError . message , resolvedError . stack ] . filter ( Boolean ) . join ( "\n" ) ;
485572 if ( combined . includes ( "CommandMismatch" ) ) {
486573 const suggestion = getCommandSuggestion ( argv ) ;
487- return [
574+ return appendStandardErrorGuidance (
488575 suggestion ? suggestion : "Need command help? Run 'ep-admin --help'." ,
489- `Docs: ${ EP_ADMIN_DOCS_URL } ` ,
490- ] . join ( "\n" ) ;
576+ argv
577+ ) ;
491578 }
492579
493580 if ( resolvedError . message . trim ( ) ) {
494- return ` ${ resolvedError . message . trim ( ) } \nDocs: ${ EP_ADMIN_DOCS_URL } ` ;
581+ return appendStandardErrorGuidance ( resolvedError . message , argv ) ;
495582 }
496583 }
497584
498- return String ( resolvedError ) ;
585+ return appendStandardErrorGuidance ( String ( resolvedError ) , argv ) ;
499586} ;
500587
501588export const createAdminProgram = (
@@ -506,6 +593,11 @@ export const runCli = (
506593 argv : ReadonlyArray < string > = process . argv
507594) : Effect . Effect < void , unknown , never > =>
508595 Effect . gen ( function * ( ) {
596+ if ( isRootHelpRequest ( argv ) ) {
597+ yield * Console . log ( renderCompactRootHelp ( ) ) ;
598+ return ;
599+ }
600+
509601 const prepared = normalizeLegacyArgs ( argv ) ;
510602 for ( const warning of prepared . warnings ) {
511603 yield * Console . error ( `⚠ ${ warning } ` ) ;
0 commit comments