@@ -28,6 +28,7 @@ const extensionsDir = path.join(rootDir, "extensions");
2828const ROOT_HELP_RENDER_TIMEOUT_MS = 120_000 ;
2929const BROWSER_HELP_RENDER_TIMEOUT_MS = 120_000 ;
3030const COMMAND_HELP_RENDER_TIMEOUT_MS = 120_000 ;
31+ const PRECOMPUTED_SUBCOMMAND_HELP_COMMANDS = [ "doctor" , "gateway" , "models" , "plugins" ] as const ;
3132const CORE_CHANNEL_ORDER = [
3233 "telegram" ,
3334 "whatsapp" ,
@@ -50,6 +51,8 @@ type BundledChannelCatalog = {
5051 signature : string ;
5152} ;
5253
54+ type PrecomputedSubcommandHelpCommand = ( typeof PRECOMPUTED_SUBCOMMAND_HELP_COMMANDS ) [ number ] ;
55+ type PrecomputedSubcommandHelpText = Record < PrecomputedSubcommandHelpCommand , string > ;
5356type RootHelpRenderContext = Pick < RootHelpRenderOptions , "config" | "env" > ;
5457
5558function resolveRootHelpBundleIdentity (
@@ -143,6 +146,30 @@ function resolveNodesHelpSourceSignature(sourceRootDir: string = rootDir): strin
143146 return hash . digest ( "hex" ) ;
144147}
145148
149+ function resolveSubcommandHelpSourceSignature ( sourceRootDir : string = rootDir ) : string {
150+ const hash = createHash ( "sha1" ) ;
151+ updateHashFromFiles (
152+ hash ,
153+ [
154+ path . join ( sourceRootDir , "src/cli/program/help.ts" ) ,
155+ path . join ( sourceRootDir , "src/cli/program/context.ts" ) ,
156+ path . join ( sourceRootDir , "src/cli/banner.ts" ) ,
157+ path . join ( sourceRootDir , "src/cli/help-format.ts" ) ,
158+ path . join ( sourceRootDir , "src/cli/daemon-cli/register-service-commands.ts" ) ,
159+ path . join ( sourceRootDir , "src/cli/program/register.maintenance.ts" ) ,
160+ path . join ( sourceRootDir , "src/cli/gateway-cli.ts" ) ,
161+ path . join ( sourceRootDir , "src/cli/gateway-cli/register.ts" ) ,
162+ path . join ( sourceRootDir , "src/cli/gateway-cli/run-command.ts" ) ,
163+ path . join ( sourceRootDir , "src/cli/models-cli.ts" ) ,
164+ path . join ( sourceRootDir , "src/cli/plugins-cli.ts" ) ,
165+ path . join ( sourceRootDir , "src/terminal/links.ts" ) ,
166+ path . join ( sourceRootDir , "src/terminal/theme.ts" ) ,
167+ ] ,
168+ sourceRootDir ,
169+ ) ;
170+ return hash . digest ( "hex" ) ;
171+ }
172+
146173export function readBundledChannelCatalog (
147174 extensionsDirOverride : string = extensionsDir ,
148175) : BundledChannelCatalog {
@@ -362,7 +389,7 @@ function renderSourceBrowserHelpText(
362389}
363390
364391function renderSourceCommandHelpText (
365- command : "nodes" | "secrets" ,
392+ command : "nodes" | "secrets" | PrecomputedSubcommandHelpCommand ,
366393 renderContext : RootHelpRenderContext = createIsolatedRootHelpRenderContext ( ) ,
367394) : string {
368395 const result = spawnSync (
@@ -403,6 +430,16 @@ function renderSourceNodesHelpText(
403430 return renderSourceCommandHelpText ( "nodes" , renderContext ) ;
404431}
405432
433+ function renderSourceSubcommandHelpTextRecord (
434+ renderContext : RootHelpRenderContext = createIsolatedRootHelpRenderContext ( ) ,
435+ ) : PrecomputedSubcommandHelpText {
436+ const entries = PRECOMPUTED_SUBCOMMAND_HELP_COMMANDS . map ( ( commandName ) => [
437+ commandName ,
438+ renderSourceCommandHelpText ( commandName , renderContext ) ,
439+ ] ) ;
440+ return Object . fromEntries ( entries ) as PrecomputedSubcommandHelpText ;
441+ }
442+
406443export async function writeCliStartupMetadata ( options ?: {
407444 distDir ?: string ;
408445 outputPath ?: string ;
@@ -413,6 +450,7 @@ export async function writeCliStartupMetadata(options?: {
413450 renderSourceBrowserHelpText ?: typeof renderSourceBrowserHelpText ;
414451 renderSourceSecretsHelpText ?: typeof renderSourceSecretsHelpText ;
415452 renderSourceNodesHelpText ?: typeof renderSourceNodesHelpText ;
453+ renderSourceSubcommandHelpTextRecord ?: typeof renderSourceSubcommandHelpTextRecord ;
416454} ) : Promise < void > {
417455 const resolvedDistDir = options ?. distDir ?? distDir ;
418456 const resolvedOutputPath = options ?. outputPath ?? outputPath ;
@@ -423,6 +461,7 @@ export async function writeCliStartupMetadata(options?: {
423461 const browserHelpSourceSignature = resolveBrowserHelpSourceSignature ( resolvedSourceRootDir ) ;
424462 const secretsHelpSourceSignature = resolveSecretsHelpSourceSignature ( resolvedSourceRootDir ) ;
425463 const nodesHelpSourceSignature = resolveNodesHelpSourceSignature ( resolvedSourceRootDir ) ;
464+ const subcommandHelpSourceSignature = resolveSubcommandHelpSourceSignature ( resolvedSourceRootDir ) ;
426465 const bundledPluginsDir = path . join ( resolvedDistDir , "extensions" ) ;
427466 const renderContext = createIsolatedRootHelpRenderContext (
428467 existsSync ( bundledPluginsDir ) ? bundledPluginsDir : resolvedExtensionsDir ,
@@ -435,24 +474,28 @@ export async function writeCliStartupMetadata(options?: {
435474 browserHelpSourceSignature ?: unknown ;
436475 secretsHelpSourceSignature ?: unknown ;
437476 nodesHelpSourceSignature ?: unknown ;
477+ subcommandHelpSourceSignature ?: unknown ;
438478 channelCatalogSignature ?: unknown ;
439479 browserHelpText ?: unknown ;
440480 secretsHelpText ?: unknown ;
441481 nodesHelpText ?: unknown ;
482+ subcommandHelpText ?: unknown ;
442483 } ;
443484 if (
444485 bundleIdentity &&
445486 existing . rootHelpBundleSignature === bundleIdentity . signature &&
446487 existing . browserHelpSourceSignature === browserHelpSourceSignature &&
447488 existing . secretsHelpSourceSignature === secretsHelpSourceSignature &&
448489 existing . nodesHelpSourceSignature === nodesHelpSourceSignature &&
490+ existing . subcommandHelpSourceSignature === subcommandHelpSourceSignature &&
449491 existing . channelCatalogSignature === channelCatalog . signature &&
450492 typeof existing . browserHelpText === "string" &&
451493 existing . browserHelpText . length > 0 &&
452494 typeof existing . secretsHelpText === "string" &&
453495 existing . secretsHelpText . length > 0 &&
454496 typeof existing . nodesHelpText === "string" &&
455- existing . nodesHelpText . length > 0
497+ existing . nodesHelpText . length > 0 &&
498+ hasAllPrecomputedSubcommandHelpText ( existing . subcommandHelpText )
456499 ) {
457500 return ;
458501 }
@@ -478,6 +521,9 @@ export async function writeCliStartupMetadata(options?: {
478521 const nodesHelpText = ( options ?. renderSourceNodesHelpText ?? renderSourceNodesHelpText ) (
479522 renderContext ,
480523 ) ;
524+ const subcommandHelpText = (
525+ options ?. renderSourceSubcommandHelpTextRecord ?? renderSourceSubcommandHelpTextRecord
526+ ) ( renderContext ) ;
481527
482528 mkdirSync ( resolvedDistDir , { recursive : true } ) ;
483529 writeFileSync (
@@ -491,9 +537,11 @@ export async function writeCliStartupMetadata(options?: {
491537 browserHelpSourceSignature,
492538 secretsHelpSourceSignature,
493539 nodesHelpSourceSignature,
540+ subcommandHelpSourceSignature,
494541 browserHelpText,
495542 secretsHelpText,
496543 nodesHelpText,
544+ subcommandHelpText,
497545 rootHelpText,
498546 } ,
499547 null ,
@@ -503,6 +551,16 @@ export async function writeCliStartupMetadata(options?: {
503551 ) ;
504552}
505553
554+ function hasAllPrecomputedSubcommandHelpText ( value : unknown ) : boolean {
555+ if ( typeof value !== "object" || value === null ) {
556+ return false ;
557+ }
558+ const record = value as Partial < Record < PrecomputedSubcommandHelpCommand , unknown > > ;
559+ return PRECOMPUTED_SUBCOMMAND_HELP_COMMANDS . every (
560+ ( commandName ) => typeof record [ commandName ] === "string" && record [ commandName ] . length > 0 ,
561+ ) ;
562+ }
563+
506564if ( process . argv [ 1 ] && path . resolve ( process . argv [ 1 ] ) === scriptPath ) {
507565 await writeCliStartupMetadata ( ) ;
508566 process . exit ( 0 ) ;
0 commit comments