code-puppy 0.0.169__py3-none-any.whl → 0.0.366__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. code_puppy/__init__.py +7 -1
  2. code_puppy/agents/__init__.py +8 -8
  3. code_puppy/agents/agent_c_reviewer.py +155 -0
  4. code_puppy/agents/agent_code_puppy.py +9 -2
  5. code_puppy/agents/agent_code_reviewer.py +90 -0
  6. code_puppy/agents/agent_cpp_reviewer.py +132 -0
  7. code_puppy/agents/agent_creator_agent.py +48 -9
  8. code_puppy/agents/agent_golang_reviewer.py +151 -0
  9. code_puppy/agents/agent_javascript_reviewer.py +160 -0
  10. code_puppy/agents/agent_manager.py +146 -199
  11. code_puppy/agents/agent_pack_leader.py +383 -0
  12. code_puppy/agents/agent_planning.py +163 -0
  13. code_puppy/agents/agent_python_programmer.py +165 -0
  14. code_puppy/agents/agent_python_reviewer.py +90 -0
  15. code_puppy/agents/agent_qa_expert.py +163 -0
  16. code_puppy/agents/agent_qa_kitten.py +208 -0
  17. code_puppy/agents/agent_security_auditor.py +181 -0
  18. code_puppy/agents/agent_terminal_qa.py +323 -0
  19. code_puppy/agents/agent_typescript_reviewer.py +166 -0
  20. code_puppy/agents/base_agent.py +1713 -1
  21. code_puppy/agents/event_stream_handler.py +350 -0
  22. code_puppy/agents/json_agent.py +12 -1
  23. code_puppy/agents/pack/__init__.py +34 -0
  24. code_puppy/agents/pack/bloodhound.py +304 -0
  25. code_puppy/agents/pack/husky.py +321 -0
  26. code_puppy/agents/pack/retriever.py +393 -0
  27. code_puppy/agents/pack/shepherd.py +348 -0
  28. code_puppy/agents/pack/terrier.py +287 -0
  29. code_puppy/agents/pack/watchdog.py +367 -0
  30. code_puppy/agents/prompt_reviewer.py +145 -0
  31. code_puppy/agents/subagent_stream_handler.py +276 -0
  32. code_puppy/api/__init__.py +13 -0
  33. code_puppy/api/app.py +169 -0
  34. code_puppy/api/main.py +21 -0
  35. code_puppy/api/pty_manager.py +446 -0
  36. code_puppy/api/routers/__init__.py +12 -0
  37. code_puppy/api/routers/agents.py +36 -0
  38. code_puppy/api/routers/commands.py +217 -0
  39. code_puppy/api/routers/config.py +74 -0
  40. code_puppy/api/routers/sessions.py +232 -0
  41. code_puppy/api/templates/terminal.html +361 -0
  42. code_puppy/api/websocket.py +154 -0
  43. code_puppy/callbacks.py +174 -4
  44. code_puppy/chatgpt_codex_client.py +283 -0
  45. code_puppy/claude_cache_client.py +586 -0
  46. code_puppy/cli_runner.py +916 -0
  47. code_puppy/command_line/add_model_menu.py +1079 -0
  48. code_puppy/command_line/agent_menu.py +395 -0
  49. code_puppy/command_line/attachments.py +395 -0
  50. code_puppy/command_line/autosave_menu.py +605 -0
  51. code_puppy/command_line/clipboard.py +527 -0
  52. code_puppy/command_line/colors_menu.py +520 -0
  53. code_puppy/command_line/command_handler.py +233 -627
  54. code_puppy/command_line/command_registry.py +150 -0
  55. code_puppy/command_line/config_commands.py +715 -0
  56. code_puppy/command_line/core_commands.py +792 -0
  57. code_puppy/command_line/diff_menu.py +863 -0
  58. code_puppy/command_line/load_context_completion.py +15 -22
  59. code_puppy/command_line/mcp/base.py +1 -4
  60. code_puppy/command_line/mcp/catalog_server_installer.py +175 -0
  61. code_puppy/command_line/mcp/custom_server_form.py +688 -0
  62. code_puppy/command_line/mcp/custom_server_installer.py +195 -0
  63. code_puppy/command_line/mcp/edit_command.py +148 -0
  64. code_puppy/command_line/mcp/handler.py +9 -4
  65. code_puppy/command_line/mcp/help_command.py +6 -5
  66. code_puppy/command_line/mcp/install_command.py +16 -27
  67. code_puppy/command_line/mcp/install_menu.py +685 -0
  68. code_puppy/command_line/mcp/list_command.py +3 -3
  69. code_puppy/command_line/mcp/logs_command.py +174 -65
  70. code_puppy/command_line/mcp/remove_command.py +2 -2
  71. code_puppy/command_line/mcp/restart_command.py +12 -4
  72. code_puppy/command_line/mcp/search_command.py +17 -11
  73. code_puppy/command_line/mcp/start_all_command.py +22 -13
  74. code_puppy/command_line/mcp/start_command.py +50 -31
  75. code_puppy/command_line/mcp/status_command.py +6 -7
  76. code_puppy/command_line/mcp/stop_all_command.py +11 -8
  77. code_puppy/command_line/mcp/stop_command.py +11 -10
  78. code_puppy/command_line/mcp/test_command.py +2 -2
  79. code_puppy/command_line/mcp/utils.py +1 -1
  80. code_puppy/command_line/mcp/wizard_utils.py +22 -18
  81. code_puppy/command_line/mcp_completion.py +174 -0
  82. code_puppy/command_line/model_picker_completion.py +89 -30
  83. code_puppy/command_line/model_settings_menu.py +884 -0
  84. code_puppy/command_line/motd.py +14 -8
  85. code_puppy/command_line/onboarding_slides.py +179 -0
  86. code_puppy/command_line/onboarding_wizard.py +340 -0
  87. code_puppy/command_line/pin_command_completion.py +329 -0
  88. code_puppy/command_line/prompt_toolkit_completion.py +626 -75
  89. code_puppy/command_line/session_commands.py +296 -0
  90. code_puppy/command_line/utils.py +54 -0
  91. code_puppy/config.py +1181 -51
  92. code_puppy/error_logging.py +118 -0
  93. code_puppy/gemini_code_assist.py +385 -0
  94. code_puppy/gemini_model.py +602 -0
  95. code_puppy/http_utils.py +220 -104
  96. code_puppy/keymap.py +128 -0
  97. code_puppy/main.py +5 -594
  98. code_puppy/{mcp → mcp_}/__init__.py +17 -0
  99. code_puppy/{mcp → mcp_}/async_lifecycle.py +35 -4
  100. code_puppy/{mcp → mcp_}/blocking_startup.py +70 -43
  101. code_puppy/{mcp → mcp_}/captured_stdio_server.py +2 -2
  102. code_puppy/{mcp → mcp_}/config_wizard.py +5 -5
  103. code_puppy/{mcp → mcp_}/dashboard.py +15 -6
  104. code_puppy/{mcp → mcp_}/examples/retry_example.py +4 -1
  105. code_puppy/{mcp → mcp_}/managed_server.py +66 -39
  106. code_puppy/{mcp → mcp_}/manager.py +146 -52
  107. code_puppy/mcp_/mcp_logs.py +224 -0
  108. code_puppy/{mcp → mcp_}/registry.py +6 -6
  109. code_puppy/{mcp → mcp_}/server_registry_catalog.py +25 -8
  110. code_puppy/messaging/__init__.py +199 -2
  111. code_puppy/messaging/bus.py +610 -0
  112. code_puppy/messaging/commands.py +167 -0
  113. code_puppy/messaging/markdown_patches.py +57 -0
  114. code_puppy/messaging/message_queue.py +17 -48
  115. code_puppy/messaging/messages.py +500 -0
  116. code_puppy/messaging/queue_console.py +1 -24
  117. code_puppy/messaging/renderers.py +43 -146
  118. code_puppy/messaging/rich_renderer.py +1027 -0
  119. code_puppy/messaging/spinner/__init__.py +33 -5
  120. code_puppy/messaging/spinner/console_spinner.py +92 -52
  121. code_puppy/messaging/spinner/spinner_base.py +29 -0
  122. code_puppy/messaging/subagent_console.py +461 -0
  123. code_puppy/model_factory.py +686 -80
  124. code_puppy/model_utils.py +167 -0
  125. code_puppy/models.json +86 -104
  126. code_puppy/models_dev_api.json +1 -0
  127. code_puppy/models_dev_parser.py +592 -0
  128. code_puppy/plugins/__init__.py +164 -10
  129. code_puppy/plugins/antigravity_oauth/__init__.py +10 -0
  130. code_puppy/plugins/antigravity_oauth/accounts.py +406 -0
  131. code_puppy/plugins/antigravity_oauth/antigravity_model.py +704 -0
  132. code_puppy/plugins/antigravity_oauth/config.py +42 -0
  133. code_puppy/plugins/antigravity_oauth/constants.py +136 -0
  134. code_puppy/plugins/antigravity_oauth/oauth.py +478 -0
  135. code_puppy/plugins/antigravity_oauth/register_callbacks.py +406 -0
  136. code_puppy/plugins/antigravity_oauth/storage.py +271 -0
  137. code_puppy/plugins/antigravity_oauth/test_plugin.py +319 -0
  138. code_puppy/plugins/antigravity_oauth/token.py +167 -0
  139. code_puppy/plugins/antigravity_oauth/transport.py +767 -0
  140. code_puppy/plugins/antigravity_oauth/utils.py +169 -0
  141. code_puppy/plugins/chatgpt_oauth/__init__.py +8 -0
  142. code_puppy/plugins/chatgpt_oauth/config.py +52 -0
  143. code_puppy/plugins/chatgpt_oauth/oauth_flow.py +328 -0
  144. code_puppy/plugins/chatgpt_oauth/register_callbacks.py +94 -0
  145. code_puppy/plugins/chatgpt_oauth/test_plugin.py +293 -0
  146. code_puppy/plugins/chatgpt_oauth/utils.py +489 -0
  147. code_puppy/plugins/claude_code_oauth/README.md +167 -0
  148. code_puppy/plugins/claude_code_oauth/SETUP.md +93 -0
  149. code_puppy/plugins/claude_code_oauth/__init__.py +6 -0
  150. code_puppy/plugins/claude_code_oauth/config.py +50 -0
  151. code_puppy/plugins/claude_code_oauth/register_callbacks.py +308 -0
  152. code_puppy/plugins/claude_code_oauth/test_plugin.py +283 -0
  153. code_puppy/plugins/claude_code_oauth/utils.py +518 -0
  154. code_puppy/plugins/customizable_commands/__init__.py +0 -0
  155. code_puppy/plugins/customizable_commands/register_callbacks.py +169 -0
  156. code_puppy/plugins/example_custom_command/README.md +280 -0
  157. code_puppy/plugins/example_custom_command/register_callbacks.py +51 -0
  158. code_puppy/plugins/file_permission_handler/__init__.py +4 -0
  159. code_puppy/plugins/file_permission_handler/register_callbacks.py +523 -0
  160. code_puppy/plugins/frontend_emitter/__init__.py +25 -0
  161. code_puppy/plugins/frontend_emitter/emitter.py +121 -0
  162. code_puppy/plugins/frontend_emitter/register_callbacks.py +261 -0
  163. code_puppy/plugins/oauth_puppy_html.py +228 -0
  164. code_puppy/plugins/shell_safety/__init__.py +6 -0
  165. code_puppy/plugins/shell_safety/agent_shell_safety.py +69 -0
  166. code_puppy/plugins/shell_safety/command_cache.py +156 -0
  167. code_puppy/plugins/shell_safety/register_callbacks.py +202 -0
  168. code_puppy/prompts/antigravity_system_prompt.md +1 -0
  169. code_puppy/prompts/codex_system_prompt.md +310 -0
  170. code_puppy/pydantic_patches.py +131 -0
  171. code_puppy/reopenable_async_client.py +8 -8
  172. code_puppy/round_robin_model.py +10 -15
  173. code_puppy/session_storage.py +294 -0
  174. code_puppy/status_display.py +21 -4
  175. code_puppy/summarization_agent.py +52 -14
  176. code_puppy/terminal_utils.py +418 -0
  177. code_puppy/tools/__init__.py +139 -6
  178. code_puppy/tools/agent_tools.py +548 -49
  179. code_puppy/tools/browser/__init__.py +37 -0
  180. code_puppy/tools/browser/browser_control.py +289 -0
  181. code_puppy/tools/browser/browser_interactions.py +545 -0
  182. code_puppy/tools/browser/browser_locators.py +640 -0
  183. code_puppy/tools/browser/browser_manager.py +316 -0
  184. code_puppy/tools/browser/browser_navigation.py +251 -0
  185. code_puppy/tools/browser/browser_screenshot.py +179 -0
  186. code_puppy/tools/browser/browser_scripts.py +462 -0
  187. code_puppy/tools/browser/browser_workflows.py +221 -0
  188. code_puppy/tools/browser/chromium_terminal_manager.py +259 -0
  189. code_puppy/tools/browser/terminal_command_tools.py +521 -0
  190. code_puppy/tools/browser/terminal_screenshot_tools.py +556 -0
  191. code_puppy/tools/browser/terminal_tools.py +525 -0
  192. code_puppy/tools/command_runner.py +941 -153
  193. code_puppy/tools/common.py +1146 -6
  194. code_puppy/tools/display.py +84 -0
  195. code_puppy/tools/file_modifications.py +288 -89
  196. code_puppy/tools/file_operations.py +352 -266
  197. code_puppy/tools/subagent_context.py +158 -0
  198. code_puppy/uvx_detection.py +242 -0
  199. code_puppy/version_checker.py +30 -11
  200. code_puppy-0.0.366.data/data/code_puppy/models.json +110 -0
  201. code_puppy-0.0.366.data/data/code_puppy/models_dev_api.json +1 -0
  202. {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/METADATA +184 -67
  203. code_puppy-0.0.366.dist-info/RECORD +217 -0
  204. {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/WHEEL +1 -1
  205. {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/entry_points.txt +1 -0
  206. code_puppy/agent.py +0 -231
  207. code_puppy/agents/agent_orchestrator.json +0 -26
  208. code_puppy/agents/runtime_manager.py +0 -272
  209. code_puppy/command_line/mcp/add_command.py +0 -183
  210. code_puppy/command_line/meta_command_handler.py +0 -153
  211. code_puppy/message_history_processor.py +0 -490
  212. code_puppy/messaging/spinner/textual_spinner.py +0 -101
  213. code_puppy/state_management.py +0 -200
  214. code_puppy/tui/__init__.py +0 -10
  215. code_puppy/tui/app.py +0 -986
  216. code_puppy/tui/components/__init__.py +0 -21
  217. code_puppy/tui/components/chat_view.py +0 -550
  218. code_puppy/tui/components/command_history_modal.py +0 -218
  219. code_puppy/tui/components/copy_button.py +0 -139
  220. code_puppy/tui/components/custom_widgets.py +0 -63
  221. code_puppy/tui/components/human_input_modal.py +0 -175
  222. code_puppy/tui/components/input_area.py +0 -167
  223. code_puppy/tui/components/sidebar.py +0 -309
  224. code_puppy/tui/components/status_bar.py +0 -182
  225. code_puppy/tui/messages.py +0 -27
  226. code_puppy/tui/models/__init__.py +0 -8
  227. code_puppy/tui/models/chat_message.py +0 -25
  228. code_puppy/tui/models/command_history.py +0 -89
  229. code_puppy/tui/models/enums.py +0 -24
  230. code_puppy/tui/screens/__init__.py +0 -15
  231. code_puppy/tui/screens/help.py +0 -130
  232. code_puppy/tui/screens/mcp_install_wizard.py +0 -803
  233. code_puppy/tui/screens/settings.py +0 -290
  234. code_puppy/tui/screens/tools.py +0 -74
  235. code_puppy-0.0.169.data/data/code_puppy/models.json +0 -128
  236. code_puppy-0.0.169.dist-info/RECORD +0 -112
  237. /code_puppy/{mcp → mcp_}/circuit_breaker.py +0 -0
  238. /code_puppy/{mcp → mcp_}/error_isolation.py +0 -0
  239. /code_puppy/{mcp → mcp_}/health_monitor.py +0 -0
  240. /code_puppy/{mcp → mcp_}/retry_manager.py +0 -0
  241. /code_puppy/{mcp → mcp_}/status_tracker.py +0 -0
  242. /code_puppy/{mcp → mcp_}/system_tools.py +0 -0
  243. {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/licenses/LICENSE +0 -0
@@ -10,36 +10,29 @@ class LoadContextCompleter(Completer):
10
10
  self.trigger = trigger
11
11
 
12
12
  def get_completions(self, document, complete_event):
13
+ cursor_position = document.cursor_position
13
14
  text_before_cursor = document.text_before_cursor
14
15
  stripped_text_for_trigger_check = text_before_cursor.lstrip()
15
16
 
16
- if not stripped_text_for_trigger_check.startswith(self.trigger):
17
- return
18
-
19
- # Determine the part of the text that is relevant for this completer
20
- actual_trigger_pos = text_before_cursor.find(self.trigger)
21
- effective_input = text_before_cursor[actual_trigger_pos:]
22
-
23
- tokens = effective_input.split()
24
-
25
- # Case 1: Input is exactly the trigger (e.g., "/load_context") and nothing more
26
- if (
27
- len(tokens) == 1
28
- and tokens[0] == self.trigger
29
- and not effective_input.endswith(" ")
30
- ):
17
+ # If user types just /load_context (no space), suggest adding a space
18
+ if stripped_text_for_trigger_check == self.trigger:
31
19
  yield Completion(
32
- text=self.trigger + " ",
33
- start_position=-len(tokens[0]),
20
+ self.trigger + " ",
21
+ start_position=-len(self.trigger),
34
22
  display=self.trigger + " ",
35
23
  display_meta="load saved context",
36
24
  )
37
25
  return
38
26
 
39
- # Case 2: Input is trigger + space or trigger + partial session name
40
- session_filter = ""
41
- if len(tokens) > 1: # e.g., ["/load_context", "partial"]
42
- session_filter = tokens[1]
27
+ # Require a space after /load_context before showing completions (consistency with other completers)
28
+ if not stripped_text_for_trigger_check.startswith(self.trigger + " "):
29
+ return
30
+
31
+ # Extract the session name after /load_context and space (up to cursor)
32
+ actual_trigger_pos = text_before_cursor.find(self.trigger)
33
+ trigger_end = actual_trigger_pos + len(self.trigger) + 1 # +1 for the space
34
+ session_filter = text_before_cursor[trigger_end:cursor_position].lstrip()
35
+ start_position = -(len(session_filter))
43
36
 
44
37
  # Get available context files
45
38
  try:
@@ -50,7 +43,7 @@ class LoadContextCompleter(Completer):
50
43
  if session_name.startswith(session_filter):
51
44
  yield Completion(
52
45
  session_name,
53
- start_position=-len(session_filter),
46
+ start_position=start_position,
54
47
  display=session_name,
55
48
  display_meta="saved context session",
56
49
  )
@@ -6,9 +6,7 @@ Provides base classes and common utilities used across all MCP command modules.
6
6
 
7
7
  import logging
8
8
 
9
- from rich.console import Console
10
-
11
- from code_puppy.mcp.manager import get_mcp_manager
9
+ from code_puppy.mcp_.manager import get_mcp_manager
12
10
 
13
11
  # Configure logging
14
12
  logger = logging.getLogger(__name__)
@@ -24,7 +22,6 @@ class MCPCommandBase:
24
22
 
25
23
  def __init__(self):
26
24
  """Initialize the base command handler."""
27
- self.console = Console()
28
25
  self.manager = get_mcp_manager()
29
26
  logger.debug(f"Initialized {self.__class__.__name__}")
30
27
 
@@ -0,0 +1,175 @@
1
+ """Catalog MCP server installation logic.
2
+
3
+ Handles prompting users for configuration and installing
4
+ MCP servers from the catalog.
5
+ """
6
+
7
+ import os
8
+ from typing import Dict, Optional
9
+
10
+ from code_puppy.command_line.utils import safe_input
11
+ from code_puppy.messaging import emit_info, emit_success, emit_warning
12
+
13
+ # Helpful hints for common environment variables
14
+ ENV_VAR_HINTS = {
15
+ "GITHUB_TOKEN": "šŸ’” Get from https://github.com/settings/tokens",
16
+ "GITLAB_TOKEN": "šŸ’” Get from GitLab > Preferences > Access Tokens",
17
+ "SLACK_TOKEN": "šŸ’” Get from https://api.slack.com/apps",
18
+ "DISCORD_TOKEN": "šŸ’” Get from Discord Developer Portal",
19
+ "OPENAI_API_KEY": "šŸ’” Get from https://platform.openai.com/api-keys",
20
+ "ANTHROPIC_API_KEY": "šŸ’” Get from https://console.anthropic.com/",
21
+ "GOOGLE_CLIENT_ID": "šŸ’” Get from Google Cloud Console",
22
+ "GOOGLE_CLIENT_SECRET": "šŸ’” Get from Google Cloud Console",
23
+ "NOTION_TOKEN": "šŸ’” Get from https://www.notion.so/my-integrations",
24
+ "CONFLUENCE_TOKEN": "šŸ’” Get from Atlassian API tokens",
25
+ "JIRA_TOKEN": "šŸ’” Get from Atlassian API tokens",
26
+ "GRAFANA_TOKEN": "šŸ’” Get from Grafana > Configuration > API Keys",
27
+ "DATABASE_URL": "šŸ’” Format: postgresql://user:pass@host:5432/db",
28
+ }
29
+
30
+
31
+ def get_env_var_hint(env_var: str) -> str:
32
+ """Get a helpful hint for common environment variables."""
33
+ return ENV_VAR_HINTS.get(env_var, "")
34
+
35
+
36
+ def prompt_for_server_config(manager, server) -> Optional[Dict]:
37
+ """Prompt user for server configuration (env vars and cmd args).
38
+
39
+ Args:
40
+ manager: MCP manager instance
41
+ server: Server template from catalog
42
+
43
+ Returns:
44
+ Dict with 'name', 'env_vars', 'cmd_args' if successful, None if cancelled
45
+ """
46
+ from code_puppy.config import set_config_value
47
+
48
+ from .utils import find_server_id_by_name
49
+
50
+ emit_info(f"\nšŸ“¦ Installing: {server.display_name}\n")
51
+ emit_info(f" {server.description}\n")
52
+
53
+ # Get custom name
54
+ default_name = server.name
55
+ try:
56
+ name_input = safe_input(f" Server name [{default_name}]: ")
57
+ server_name = name_input if name_input else default_name
58
+ except (KeyboardInterrupt, EOFError):
59
+ emit_info("")
60
+ emit_warning("Installation cancelled")
61
+ return None
62
+
63
+ # Check if server already exists
64
+ existing = find_server_id_by_name(manager, server_name)
65
+ if existing:
66
+ try:
67
+ override = safe_input(f" Server '{server_name}' exists. Override? [y/N]: ")
68
+ if not override.lower().startswith("y"):
69
+ emit_warning("Installation cancelled")
70
+ return None
71
+ except (KeyboardInterrupt, EOFError):
72
+ emit_info("")
73
+ emit_warning("Installation cancelled")
74
+ return None
75
+
76
+ env_vars = {}
77
+ cmd_args = {}
78
+
79
+ # Collect environment variables
80
+ required_env_vars = server.get_environment_vars()
81
+ if required_env_vars:
82
+ emit_info("\n šŸ”‘ Environment Variables:")
83
+ for var in required_env_vars:
84
+ current_value = os.environ.get(var, "")
85
+ if current_value:
86
+ emit_info(f" āœ“ {var}: Already set")
87
+ env_vars[var] = current_value
88
+ else:
89
+ try:
90
+ hint = get_env_var_hint(var)
91
+ if hint:
92
+ emit_info(f" {hint}")
93
+ value = safe_input(f" Enter {var}: ")
94
+ if value:
95
+ env_vars[var] = value
96
+ # Save to config for future use
97
+ set_config_value(var, value)
98
+ os.environ[var] = value
99
+ except (KeyboardInterrupt, EOFError):
100
+ emit_info("")
101
+ emit_warning("Installation cancelled")
102
+ return None
103
+
104
+ # Collect command line arguments
105
+ required_cmd_args = server.get_command_line_args()
106
+ if required_cmd_args:
107
+ emit_info("\n āš™ļø Configuration:")
108
+ for arg_config in required_cmd_args:
109
+ name = arg_config.get("name", "")
110
+ prompt_text = arg_config.get("prompt", name)
111
+ default = arg_config.get("default", "")
112
+ required = arg_config.get("required", True)
113
+
114
+ prompt_str = f" {prompt_text}"
115
+ if default:
116
+ prompt_str += f" [{default}]"
117
+ if not required:
118
+ prompt_str += " (optional)"
119
+
120
+ try:
121
+ value = safe_input(f"{prompt_str}: ")
122
+ if value:
123
+ cmd_args[name] = value
124
+ elif default:
125
+ cmd_args[name] = default
126
+ elif required:
127
+ emit_warning(f"Required value '{name}' not provided")
128
+ return None
129
+ except (KeyboardInterrupt, EOFError):
130
+ emit_info("")
131
+ emit_warning("Installation cancelled")
132
+ return None
133
+
134
+ return {
135
+ "name": server_name,
136
+ "env_vars": env_vars,
137
+ "cmd_args": cmd_args,
138
+ }
139
+
140
+
141
+ def install_catalog_server(manager, server, config: Dict) -> bool:
142
+ """Install a server from the catalog with the given configuration.
143
+
144
+ Args:
145
+ manager: MCP manager instance
146
+ server: Server template from catalog
147
+ config: Configuration dict with 'name', 'env_vars', 'cmd_args'
148
+
149
+ Returns:
150
+ True if successful, False otherwise
151
+ """
152
+ import uuid
153
+
154
+ from .wizard_utils import install_server_from_catalog
155
+
156
+ server_name = config["name"]
157
+ env_vars = config["env_vars"]
158
+ cmd_args = config["cmd_args"]
159
+
160
+ # Generate a group ID for messages
161
+ group_id = f"mcp-install-{uuid.uuid4().hex[:8]}"
162
+
163
+ emit_info(f"\n šŸ“¦ Installing {server.display_name} as '{server_name}'...")
164
+
165
+ success = install_server_from_catalog(
166
+ manager, server, server_name, env_vars, cmd_args, group_id
167
+ )
168
+
169
+ if success:
170
+ emit_success(f"\n āœ… Successfully installed '{server_name}'!")
171
+ emit_info(f" Use '/mcp start {server_name}' to start the server.\n")
172
+ else:
173
+ emit_warning("\n āŒ Installation failed.\n")
174
+
175
+ return success