|
10 | 10 | except ImportError: |
11 | 11 | import tomli as tomllib |
12 | 12 |
|
13 | | -from code_assistant_manager.cli.agents_commands import agent_app |
14 | | -from code_assistant_manager.cli.plugin_commands import plugin_app |
15 | | -from code_assistant_manager.cli.prompts_commands import prompt_app |
16 | | -from code_assistant_manager.cli.skills_commands import skill_app |
17 | 13 | from code_assistant_manager.config import ConfigManager |
18 | | -from code_assistant_manager.mcp.cli import app as mcp_app |
19 | 14 | from code_assistant_manager.tools import ( |
20 | 15 | display_all_tool_endpoints, |
21 | 16 | display_tool_endpoints, |
22 | 17 | get_registered_tools, |
23 | 18 | ) |
24 | 19 |
|
| 20 | +# Lazy-import heavy command modules to improve startup time |
| 21 | +def _lazy_import_agent_app(): |
| 22 | + from code_assistant_manager.cli.agents_commands import agent_app |
| 23 | + return agent_app |
| 24 | + |
| 25 | +def _lazy_import_plugin_app(): |
| 26 | + from code_assistant_manager.cli.plugin_commands import plugin_app |
| 27 | + return plugin_app |
| 28 | + |
| 29 | +def _lazy_import_prompt_app(): |
| 30 | + from code_assistant_manager.cli.prompts_commands import prompt_app |
| 31 | + return prompt_app |
| 32 | + |
| 33 | +def _lazy_import_skill_app(): |
| 34 | + from code_assistant_manager.cli.skills_commands import skill_app |
| 35 | + return skill_app |
| 36 | + |
| 37 | +def _lazy_import_mcp_app(): |
| 38 | + from code_assistant_manager.mcp.cli import app as mcp_app |
| 39 | + return mcp_app |
| 40 | + |
25 | 41 | # Module-level typer.Option constants to fix B008 linting errors |
26 | 42 | from .options import ( |
27 | 43 | CONFIG_FILE_OPTION, |
@@ -207,21 +223,65 @@ def command( |
207 | 223 | # Add the config app as a subcommand to the main app |
208 | 224 | app.add_typer(config_app, name="config") |
209 | 225 | app.add_typer(config_app, name="cf", hidden=True) |
210 | | -# Add the MCP app as a subcommand to the main app |
211 | | -app.add_typer(mcp_app, name="mcp") |
212 | | -app.add_typer(mcp_app, name="m", hidden=True) |
| 226 | + |
| 227 | +# Cache for lazy-loaded apps |
| 228 | +_lazy_apps_cache = {} |
| 229 | + |
| 230 | +def _get_lazy_app(import_func, cache_key): |
| 231 | + """Get or load a lazy app with caching.""" |
| 232 | + if cache_key not in _lazy_apps_cache: |
| 233 | + _lazy_apps_cache[cache_key] = import_func() |
| 234 | + return _lazy_apps_cache[cache_key] |
| 235 | + |
| 236 | +# Create wrapper functions that import apps only when needed |
| 237 | +def _get_mcp_app_impl(): |
| 238 | + """Wrapper that defers MCP app import.""" |
| 239 | + return _get_lazy_app(_lazy_import_mcp_app, "mcp") |
| 240 | + |
| 241 | +def _get_prompt_app_impl(): |
| 242 | + """Wrapper that defers prompt app import.""" |
| 243 | + return _get_lazy_app(_lazy_import_prompt_app, "prompt") |
| 244 | + |
| 245 | +def _get_skill_app_impl(): |
| 246 | + """Wrapper that defers skill app import.""" |
| 247 | + return _get_lazy_app(_lazy_import_skill_app, "skill") |
| 248 | + |
| 249 | +def _get_plugin_app_impl(): |
| 250 | + """Wrapper that defers plugin app import.""" |
| 251 | + return _get_lazy_app(_lazy_import_plugin_app, "plugin") |
| 252 | + |
| 253 | +def _get_agent_app_impl(): |
| 254 | + """Wrapper that defers agent app import.""" |
| 255 | + return _get_lazy_app(_lazy_import_agent_app, "agent") |
| 256 | + |
| 257 | +# Note: Due to how Typer works, the apps are still evaluated at import time. |
| 258 | +# The actual performance benefit comes from: |
| 259 | +# 1. The tools modules no longer being imported upfront (done in tools/__init__.py) |
| 260 | +# 2. The command modules being simpler to import |
| 261 | +# |
| 262 | +# For even better lazy loading, we would need to use click's built-in group/command |
| 263 | +# lazy loading feature, but that would require more extensive refactoring. |
| 264 | +# |
| 265 | +# The current implementation still provides significant savings by: |
| 266 | +# - Deferring tool module imports (biggest impact) |
| 267 | +# - Using function wrappers that can be extended for true lazy loading later |
| 268 | + |
| 269 | +# Add the apps (they will import when these lines execute, but the major |
| 270 | +# time savings come from tools not being preloaded) |
| 271 | +app.add_typer(_get_mcp_app_impl(), name="mcp") |
| 272 | +app.add_typer(_get_mcp_app_impl(), name="m", hidden=True) |
213 | 273 | # Add the prompt app as a subcommand to the main app |
214 | | -app.add_typer(prompt_app, name="prompt") |
215 | | -app.add_typer(prompt_app, name="p", hidden=True) |
| 274 | +app.add_typer(_get_prompt_app_impl(), name="prompt") |
| 275 | +app.add_typer(_get_prompt_app_impl(), name="p", hidden=True) |
216 | 276 | # Add the skill app as a subcommand to the main app |
217 | | -app.add_typer(skill_app, name="skill") |
218 | | -app.add_typer(skill_app, name="s", hidden=True) |
| 277 | +app.add_typer(_get_skill_app_impl(), name="skill") |
| 278 | +app.add_typer(_get_skill_app_impl(), name="s", hidden=True) |
219 | 279 | # Add the plugin app as a subcommand to the main app (Claude Code plugins) |
220 | | -app.add_typer(plugin_app, name="plugin") |
221 | | -app.add_typer(plugin_app, name="pl", hidden=True) |
| 280 | +app.add_typer(_get_plugin_app_impl(), name="plugin") |
| 281 | +app.add_typer(_get_plugin_app_impl(), name="pl", hidden=True) |
222 | 282 | # Add the agent app as a subcommand to the main app (Claude Code agents) |
223 | | -app.add_typer(agent_app, name="agent") |
224 | | -app.add_typer(agent_app, name="ag", hidden=True) |
| 283 | +app.add_typer(_get_agent_app_impl(), name="agent") |
| 284 | +app.add_typer(_get_agent_app_impl(), name="ag", hidden=True) |
225 | 285 |
|
226 | 286 |
|
227 | 287 | @config_app.command("validate") |
|
0 commit comments