4444)
4545
4646
47+ def _get_newest_extension_mtime ():
48+ """
49+ Get the newest modification time among all extension files.
50+ Used to validate if the cache is stale.
51+ """
52+ try :
53+ command_files = _get_cached_extension_files ()
54+ if not command_files :
55+ return 0
56+ return max (os .path .getmtime (f ) for f in command_files if os .path .exists (f ))
57+ except Exception as e :
58+ logging .debug (f"Could not get extension file mtimes: { e } " )
59+ return 0
60+
61+
4762def _get_extension_metadata_cache ():
4863 """
4964 Get cached extension metadata (commands, settings) without importing modules.
5065 This enables lazy loading - modules are only imported when commands are executed.
66+
67+ The cache is automatically invalidated when any extension file has been modified
68+ since the cache was built.
5169 """
5270 global _extension_metadata_cache
5371
@@ -65,11 +83,21 @@ def _get_extension_metadata_cache():
6583 and "commands" in cached
6684 and "extensions" in cached
6785 ):
68- _extension_metadata_cache = cached
69- logging .debug (
70- f"Loaded extension metadata cache with { len (cached ['commands' ])} commands"
71- )
72- return _extension_metadata_cache
86+ # Check if cache is stale by comparing against newest extension file mtime
87+ cache_built_at = cached .get ("built_at" , 0 )
88+ newest_mtime = _get_newest_extension_mtime ()
89+
90+ if newest_mtime > cache_built_at :
91+ logging .info (
92+ f"Extension metadata cache is stale (cache built at { cache_built_at } , "
93+ f"newest file at { newest_mtime } ). Rebuilding..."
94+ )
95+ else :
96+ _extension_metadata_cache = cached
97+ logging .debug (
98+ f"Loaded extension metadata cache with { len (cached ['commands' ])} commands"
99+ )
100+ return _extension_metadata_cache
73101 except Exception as e :
74102 logging .debug (f"Could not load extension metadata cache: { e } " )
75103
0 commit comments