@@ -73,7 +73,7 @@ def __init__(self, **kwargs):
7373 register_ids_argument , register_global_subscription_argument , register_global_policy_argument )
7474 from azure .cli .core .cloud import get_active_cloud
7575 from azure .cli .core .commands .transform import register_global_transforms
76- from azure .cli .core ._session import ACCOUNT , CONFIG , SESSION , INDEX , EXTENSION_INDEX , HELP_INDEX , VERSIONS
76+ from azure .cli .core ._session import ACCOUNT , CONFIG , SESSION , INDEX , EXTENSION_INDEX , HELP_INDEX , EXTENSION_HELP_INDEX , VERSIONS
7777 from azure .cli .core .util import handle_version_update
7878
7979 from knack .util import ensure_dir
@@ -92,6 +92,7 @@ def __init__(self, **kwargs):
9292 INDEX .load (os .path .join (azure_folder , 'commandIndex.json' ))
9393 EXTENSION_INDEX .load (os .path .join (azure_folder , 'extensionIndex.json' ))
9494 HELP_INDEX .load (os .path .join (azure_folder , 'helpIndex.json' ))
95+ EXTENSION_HELP_INDEX .load (os .path .join (azure_folder , 'extensionHelpIndex.json' ))
9596 VERSIONS .load (os .path .join (azure_folder , 'versionCheck.json' ))
9697 handle_version_update ()
9798
@@ -744,10 +745,11 @@ def __init__(self, cli_ctx=None):
744745
745746 :param cli_ctx: Only needed when `get` or `update` is called.
746747 """
747- from azure .cli .core ._session import INDEX , EXTENSION_INDEX , HELP_INDEX
748+ from azure .cli .core ._session import INDEX , EXTENSION_INDEX , HELP_INDEX , EXTENSION_HELP_INDEX
748749 self .INDEX = INDEX
749750 self .EXTENSION_INDEX = EXTENSION_INDEX
750751 self .HELP_INDEX = HELP_INDEX
752+ self .EXTENSION_HELP_INDEX = EXTENSION_HELP_INDEX
751753 if cli_ctx :
752754 self .version = __version__
753755 self .cloud_profile = cli_ctx .cloud .profile
@@ -782,6 +784,13 @@ def _is_extension_index_valid(self):
782784 return (index_version and index_version == self .version and
783785 cloud_profile and cloud_profile == self .cloud_profile )
784786
787+ def _is_extension_help_index_valid (self ):
788+ """Check if the extension help index version and cloud profile are valid."""
789+ index_version = self .EXTENSION_HELP_INDEX .get (self ._COMMAND_INDEX_VERSION )
790+ cloud_profile = self .EXTENSION_HELP_INDEX .get (self ._COMMAND_INDEX_CLOUD_PROFILE )
791+ return (index_version and index_version == self .version and
792+ cloud_profile and cloud_profile == self .cloud_profile )
793+
785794 def _get_top_level_completion_commands (self , index = None ):
786795 """Get top-level command names for tab completion optimization.
787796
@@ -918,6 +927,34 @@ def _blend_command_indices(core_index, extension_index):
918927 blended [cmd ].append (mod )
919928 return blended
920929
930+ @staticmethod
931+ def _blend_help_indices (base_help_index , extension_help_index ):
932+ """Blend packaged core help with extension-only help overlay."""
933+ blended = {
934+ 'groups' : dict ((base_help_index or {}).get ('groups' ) or {}),
935+ 'commands' : dict ((base_help_index or {}).get ('commands' ) or {})
936+ }
937+ ext_help_index = extension_help_index or {}
938+ for section in ('groups' , 'commands' ):
939+ blended_section = blended [section ]
940+ for key , value in (ext_help_index .get (section ) or {}).items ():
941+ blended_section [key ] = value
942+ return blended
943+
944+ @staticmethod
945+ def _build_extension_help_overlay (base_help_index , full_help_index ):
946+ """Build extension-only help overlay by diffing full help against packaged core help."""
947+ overlay = {'groups' : {}, 'commands' : {}}
948+ base_help_index = base_help_index or {}
949+ full_help_index = full_help_index or {}
950+ for section in ('groups' , 'commands' ):
951+ base_section = base_help_index .get (section ) or {}
952+ full_section = full_help_index .get (section ) or {}
953+ for key , value in full_section .items ():
954+ if key not in base_section or base_section [key ] != value :
955+ overlay [section ][key ] = value
956+ return overlay
957+
921958 def _get_blended_latest_index (self ):
922959 """Get effective index for latest profile by blending core and extension indices."""
923960 if self .cloud_profile != 'latest' :
@@ -1095,20 +1132,39 @@ def get_help_index(self):
10951132 :return: Dictionary mapping top-level commands to their short summaries, or None if not available
10961133 """
10971134 if self .cloud_profile == 'latest' :
1098- # Prefer local cache if available and valid, as it may include extension-specific help entries.
1099- if self ._is_index_valid ():
1100- help_index = self .HELP_INDEX .get (self ._HELP_INDEX , {})
1101- if not help_index :
1102- help_index = self ._migrate_legacy_help_index () or {}
1103- if help_index :
1104- logger .debug ("Using cached local help index with %d entries" , len (help_index ))
1105- return help_index
1106-
1135+ # Packaged help is the base for latest profile.
11071136 packaged_help_index = self ._load_packaged_help_index ()
1108- if packaged_help_index :
1109- logger .debug ("Using packaged help index with %d entries" , len (packaged_help_index ))
1110- return packaged_help_index
1111- return None
1137+ if not packaged_help_index :
1138+ # Defensive fallback to local cache if packaged asset is unavailable.
1139+ if self ._is_index_valid ():
1140+ help_index = self .HELP_INDEX .get (self ._HELP_INDEX , {})
1141+ if not help_index :
1142+ help_index = self ._migrate_legacy_help_index () or {}
1143+ if help_index :
1144+ logger .debug ("Using cached local help index with %d entries" , len (help_index ))
1145+ return help_index
1146+ return None
1147+
1148+ if self ._is_extension_help_index_valid ():
1149+ extension_help_index = self .EXTENSION_HELP_INDEX .get (self ._HELP_INDEX , {})
1150+ if extension_help_index :
1151+ logger .debug ("Blending packaged help index with extension help overlay (%d groups, %d commands)." ,
1152+ len (extension_help_index .get ('groups' ) or {}),
1153+ len (extension_help_index .get ('commands' ) or {}))
1154+ return self ._blend_help_indices (packaged_help_index , extension_help_index )
1155+
1156+ # Clear stale overlay cache if schema exists but metadata is invalid.
1157+ if self .EXTENSION_HELP_INDEX .get (self ._HELP_INDEX ):
1158+ self .EXTENSION_HELP_INDEX [self ._COMMAND_INDEX_VERSION ] = ""
1159+ self .EXTENSION_HELP_INDEX [self ._COMMAND_INDEX_CLOUD_PROFILE ] = ""
1160+ self .EXTENSION_HELP_INDEX [self ._HELP_INDEX ] = {}
1161+
1162+ if self ._has_non_always_loaded_extensions ():
1163+ logger .debug ("Extension help overlay unavailable on latest profile. Triggering refresh via full load." )
1164+ return None
1165+
1166+ logger .debug ("Using packaged help index with %d entries" , len (packaged_help_index ))
1167+ return packaged_help_index
11121168
11131169 if not self ._is_index_valid ():
11141170 return None
@@ -1127,6 +1183,20 @@ def set_help_index(self, help_data):
11271183
11281184 :param help_data: Help index data structure containing groups and commands
11291185 """
1186+ if self .cloud_profile == 'latest' :
1187+ packaged_help_index = self ._load_packaged_help_index () or {'groups' : {}, 'commands' : {}}
1188+ extension_help_overlay = self ._build_extension_help_overlay (packaged_help_index , help_data )
1189+
1190+ self .EXTENSION_HELP_INDEX [self ._COMMAND_INDEX_VERSION ] = __version__
1191+ self .EXTENSION_HELP_INDEX [self ._COMMAND_INDEX_CLOUD_PROFILE ] = self .cloud_profile
1192+ self .EXTENSION_HELP_INDEX [self ._HELP_INDEX ] = extension_help_overlay
1193+
1194+ # Keep local full help cache empty for latest; packaged base + extension overlay are authoritative.
1195+ self .HELP_INDEX [self ._HELP_INDEX ] = {}
1196+ if self .INDEX .get (self ._HELP_INDEX ):
1197+ self .INDEX [self ._HELP_INDEX ] = {}
1198+ return
1199+
11301200 self .HELP_INDEX [self ._HELP_INDEX ] = help_data
11311201 # Clear legacy key if it exists in commandIndex.json.
11321202 if self .INDEX .get (self ._HELP_INDEX ):
@@ -1187,6 +1257,9 @@ def invalidate(self):
11871257 self .EXTENSION_INDEX [self ._COMMAND_INDEX_VERSION ] = ""
11881258 self .EXTENSION_INDEX [self ._COMMAND_INDEX_CLOUD_PROFILE ] = ""
11891259 self .EXTENSION_INDEX [self ._COMMAND_INDEX ] = {}
1260+ self .EXTENSION_HELP_INDEX [self ._COMMAND_INDEX_VERSION ] = ""
1261+ self .EXTENSION_HELP_INDEX [self ._COMMAND_INDEX_CLOUD_PROFILE ] = ""
1262+ self .EXTENSION_HELP_INDEX [self ._HELP_INDEX ] = {}
11901263 self .HELP_INDEX [self ._HELP_INDEX ] = {}
11911264 # Clear legacy key if it exists in commandIndex.json.
11921265 if self .INDEX .get (self ._HELP_INDEX ):
0 commit comments