Background
During the CLI application startup sequence in packages/cli/src/gemini.tsx, we currently call loadCliConfig twice:
partialConfig: Initial load to determine workspace settings, basic auth, and extension metadata.
config: Final load after authenticating and fetching remote admin policies, to ensure blocked MCP servers or tools are stripped out.
The Problem
Inside loadCliConfig (located in packages/cli/src/config/config.ts), a new instance of ExtensionManager is created and await extensionManager.loadExtensions() is called every time.
Because loadExtensions performs significant disk I/O (reading package.json, checking extension integrity signatures, parsing hooks.json), executing this twice on every CLI boot adds unnecessary latency.
It also historically caused side-effects, such as duplicate UserFeedback warnings being emitted for the same extensions (e.g., warnings about missing settings or the conductor -> sdd replacement). While these duplicate warnings have been temporarily suppressed using a deduplication Set in ExtensionManager.ts, the redundant I/O remains.
Proposed Solution
Refactor the CLI startup lifecycle so that ExtensionManager is instantiated and loaded exactly once.
- Instantiate the
ExtensionManager and call await loadExtensions() early in the gemini.tsx startup flow.
- Update the
loadCliConfig signature (and its LoadCliConfigOptions) to accept an already-initialized ExtensionManager instance rather than creating its own.
- Ensure that any admin policies fetched between the first and second config generation passes can be dynamically applied to the cached
ExtensionManager state.
Impact
- Performance: Faster startup by halving the extension parsing I/O.
- Code Quality: Removal of the
emittedWarnings deduplication hack in ExtensionManager.
- Note: This will require updating several test files (e.g.,
config.test.ts, workspace-policy-cli.test.ts) that currently invoke loadCliConfig() directly.
Background
During the CLI application startup sequence in
packages/cli/src/gemini.tsx, we currently callloadCliConfigtwice:partialConfig: Initial load to determine workspace settings, basic auth, and extension metadata.config: Final load after authenticating and fetching remote admin policies, to ensure blocked MCP servers or tools are stripped out.The Problem
Inside
loadCliConfig(located inpackages/cli/src/config/config.ts), a new instance ofExtensionManageris created andawait extensionManager.loadExtensions()is called every time.Because
loadExtensionsperforms significant disk I/O (readingpackage.json, checking extension integrity signatures, parsinghooks.json), executing this twice on every CLI boot adds unnecessary latency.It also historically caused side-effects, such as duplicate
UserFeedbackwarnings being emitted for the same extensions (e.g., warnings about missing settings or theconductor->sddreplacement). While these duplicate warnings have been temporarily suppressed using a deduplicationSetinExtensionManager.ts, the redundant I/O remains.Proposed Solution
Refactor the CLI startup lifecycle so that
ExtensionManageris instantiated and loaded exactly once.ExtensionManagerand callawait loadExtensions()early in thegemini.tsxstartup flow.loadCliConfigsignature (and itsLoadCliConfigOptions) to accept an already-initializedExtensionManagerinstance rather than creating its own.ExtensionManagerstate.Impact
emittedWarningsdeduplication hack inExtensionManager.config.test.ts,workspace-policy-cli.test.ts) that currently invokeloadCliConfig()directly.