codepp 0.0.437__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 (288) hide show
  1. code_puppy/__init__.py +10 -0
  2. code_puppy/__main__.py +10 -0
  3. code_puppy/agents/__init__.py +31 -0
  4. code_puppy/agents/agent_c_reviewer.py +155 -0
  5. code_puppy/agents/agent_code_puppy.py +117 -0
  6. code_puppy/agents/agent_code_reviewer.py +90 -0
  7. code_puppy/agents/agent_cpp_reviewer.py +132 -0
  8. code_puppy/agents/agent_creator_agent.py +638 -0
  9. code_puppy/agents/agent_golang_reviewer.py +151 -0
  10. code_puppy/agents/agent_helios.py +124 -0
  11. code_puppy/agents/agent_javascript_reviewer.py +160 -0
  12. code_puppy/agents/agent_manager.py +742 -0
  13. code_puppy/agents/agent_pack_leader.py +385 -0
  14. code_puppy/agents/agent_planning.py +165 -0
  15. code_puppy/agents/agent_python_programmer.py +169 -0
  16. code_puppy/agents/agent_python_reviewer.py +90 -0
  17. code_puppy/agents/agent_qa_expert.py +163 -0
  18. code_puppy/agents/agent_qa_kitten.py +208 -0
  19. code_puppy/agents/agent_scheduler.py +121 -0
  20. code_puppy/agents/agent_security_auditor.py +181 -0
  21. code_puppy/agents/agent_terminal_qa.py +323 -0
  22. code_puppy/agents/agent_typescript_reviewer.py +166 -0
  23. code_puppy/agents/base_agent.py +2156 -0
  24. code_puppy/agents/event_stream_handler.py +348 -0
  25. code_puppy/agents/json_agent.py +202 -0
  26. code_puppy/agents/pack/__init__.py +34 -0
  27. code_puppy/agents/pack/bloodhound.py +304 -0
  28. code_puppy/agents/pack/husky.py +327 -0
  29. code_puppy/agents/pack/retriever.py +393 -0
  30. code_puppy/agents/pack/shepherd.py +348 -0
  31. code_puppy/agents/pack/terrier.py +287 -0
  32. code_puppy/agents/pack/watchdog.py +367 -0
  33. code_puppy/agents/prompt_reviewer.py +145 -0
  34. code_puppy/agents/subagent_stream_handler.py +276 -0
  35. code_puppy/api/__init__.py +13 -0
  36. code_puppy/api/app.py +169 -0
  37. code_puppy/api/main.py +21 -0
  38. code_puppy/api/pty_manager.py +453 -0
  39. code_puppy/api/routers/__init__.py +12 -0
  40. code_puppy/api/routers/agents.py +36 -0
  41. code_puppy/api/routers/commands.py +217 -0
  42. code_puppy/api/routers/config.py +75 -0
  43. code_puppy/api/routers/sessions.py +234 -0
  44. code_puppy/api/templates/terminal.html +361 -0
  45. code_puppy/api/websocket.py +154 -0
  46. code_puppy/callbacks.py +692 -0
  47. code_puppy/chatgpt_codex_client.py +338 -0
  48. code_puppy/claude_cache_client.py +672 -0
  49. code_puppy/cli_runner.py +1073 -0
  50. code_puppy/command_line/__init__.py +1 -0
  51. code_puppy/command_line/add_model_menu.py +1092 -0
  52. code_puppy/command_line/agent_menu.py +662 -0
  53. code_puppy/command_line/attachments.py +395 -0
  54. code_puppy/command_line/autosave_menu.py +704 -0
  55. code_puppy/command_line/clipboard.py +527 -0
  56. code_puppy/command_line/colors_menu.py +532 -0
  57. code_puppy/command_line/command_handler.py +293 -0
  58. code_puppy/command_line/command_registry.py +150 -0
  59. code_puppy/command_line/config_commands.py +719 -0
  60. code_puppy/command_line/core_commands.py +867 -0
  61. code_puppy/command_line/diff_menu.py +865 -0
  62. code_puppy/command_line/file_path_completion.py +73 -0
  63. code_puppy/command_line/load_context_completion.py +52 -0
  64. code_puppy/command_line/mcp/__init__.py +10 -0
  65. code_puppy/command_line/mcp/base.py +32 -0
  66. code_puppy/command_line/mcp/catalog_server_installer.py +175 -0
  67. code_puppy/command_line/mcp/custom_server_form.py +688 -0
  68. code_puppy/command_line/mcp/custom_server_installer.py +195 -0
  69. code_puppy/command_line/mcp/edit_command.py +148 -0
  70. code_puppy/command_line/mcp/handler.py +138 -0
  71. code_puppy/command_line/mcp/help_command.py +147 -0
  72. code_puppy/command_line/mcp/install_command.py +214 -0
  73. code_puppy/command_line/mcp/install_menu.py +705 -0
  74. code_puppy/command_line/mcp/list_command.py +94 -0
  75. code_puppy/command_line/mcp/logs_command.py +235 -0
  76. code_puppy/command_line/mcp/remove_command.py +82 -0
  77. code_puppy/command_line/mcp/restart_command.py +100 -0
  78. code_puppy/command_line/mcp/search_command.py +123 -0
  79. code_puppy/command_line/mcp/start_all_command.py +135 -0
  80. code_puppy/command_line/mcp/start_command.py +117 -0
  81. code_puppy/command_line/mcp/status_command.py +184 -0
  82. code_puppy/command_line/mcp/stop_all_command.py +112 -0
  83. code_puppy/command_line/mcp/stop_command.py +80 -0
  84. code_puppy/command_line/mcp/test_command.py +107 -0
  85. code_puppy/command_line/mcp/utils.py +129 -0
  86. code_puppy/command_line/mcp/wizard_utils.py +334 -0
  87. code_puppy/command_line/mcp_completion.py +174 -0
  88. code_puppy/command_line/model_picker_completion.py +197 -0
  89. code_puppy/command_line/model_settings_menu.py +932 -0
  90. code_puppy/command_line/motd.py +96 -0
  91. code_puppy/command_line/onboarding_slides.py +179 -0
  92. code_puppy/command_line/onboarding_wizard.py +342 -0
  93. code_puppy/command_line/pin_command_completion.py +329 -0
  94. code_puppy/command_line/prompt_toolkit_completion.py +846 -0
  95. code_puppy/command_line/session_commands.py +302 -0
  96. code_puppy/command_line/shell_passthrough.py +145 -0
  97. code_puppy/command_line/skills_completion.py +160 -0
  98. code_puppy/command_line/uc_menu.py +893 -0
  99. code_puppy/command_line/utils.py +93 -0
  100. code_puppy/command_line/wiggum_state.py +78 -0
  101. code_puppy/config.py +1770 -0
  102. code_puppy/error_logging.py +134 -0
  103. code_puppy/gemini_code_assist.py +385 -0
  104. code_puppy/gemini_model.py +754 -0
  105. code_puppy/hook_engine/README.md +105 -0
  106. code_puppy/hook_engine/__init__.py +21 -0
  107. code_puppy/hook_engine/aliases.py +155 -0
  108. code_puppy/hook_engine/engine.py +221 -0
  109. code_puppy/hook_engine/executor.py +296 -0
  110. code_puppy/hook_engine/matcher.py +156 -0
  111. code_puppy/hook_engine/models.py +240 -0
  112. code_puppy/hook_engine/registry.py +106 -0
  113. code_puppy/hook_engine/validator.py +144 -0
  114. code_puppy/http_utils.py +361 -0
  115. code_puppy/keymap.py +128 -0
  116. code_puppy/main.py +10 -0
  117. code_puppy/mcp_/__init__.py +66 -0
  118. code_puppy/mcp_/async_lifecycle.py +286 -0
  119. code_puppy/mcp_/blocking_startup.py +469 -0
  120. code_puppy/mcp_/captured_stdio_server.py +275 -0
  121. code_puppy/mcp_/circuit_breaker.py +290 -0
  122. code_puppy/mcp_/config_wizard.py +507 -0
  123. code_puppy/mcp_/dashboard.py +308 -0
  124. code_puppy/mcp_/error_isolation.py +407 -0
  125. code_puppy/mcp_/examples/retry_example.py +226 -0
  126. code_puppy/mcp_/health_monitor.py +589 -0
  127. code_puppy/mcp_/managed_server.py +428 -0
  128. code_puppy/mcp_/manager.py +807 -0
  129. code_puppy/mcp_/mcp_logs.py +224 -0
  130. code_puppy/mcp_/registry.py +451 -0
  131. code_puppy/mcp_/retry_manager.py +337 -0
  132. code_puppy/mcp_/server_registry_catalog.py +1126 -0
  133. code_puppy/mcp_/status_tracker.py +355 -0
  134. code_puppy/mcp_/system_tools.py +209 -0
  135. code_puppy/mcp_prompts/__init__.py +1 -0
  136. code_puppy/mcp_prompts/hook_creator.py +103 -0
  137. code_puppy/messaging/__init__.py +255 -0
  138. code_puppy/messaging/bus.py +613 -0
  139. code_puppy/messaging/commands.py +167 -0
  140. code_puppy/messaging/markdown_patches.py +57 -0
  141. code_puppy/messaging/message_queue.py +361 -0
  142. code_puppy/messaging/messages.py +569 -0
  143. code_puppy/messaging/queue_console.py +271 -0
  144. code_puppy/messaging/renderers.py +311 -0
  145. code_puppy/messaging/rich_renderer.py +1158 -0
  146. code_puppy/messaging/spinner/__init__.py +83 -0
  147. code_puppy/messaging/spinner/console_spinner.py +240 -0
  148. code_puppy/messaging/spinner/spinner_base.py +95 -0
  149. code_puppy/messaging/subagent_console.py +460 -0
  150. code_puppy/model_factory.py +848 -0
  151. code_puppy/model_switching.py +63 -0
  152. code_puppy/model_utils.py +168 -0
  153. code_puppy/models.json +174 -0
  154. code_puppy/models_dev_api.json +1 -0
  155. code_puppy/models_dev_parser.py +592 -0
  156. code_puppy/plugins/__init__.py +186 -0
  157. code_puppy/plugins/agent_skills/__init__.py +22 -0
  158. code_puppy/plugins/agent_skills/config.py +175 -0
  159. code_puppy/plugins/agent_skills/discovery.py +136 -0
  160. code_puppy/plugins/agent_skills/downloader.py +392 -0
  161. code_puppy/plugins/agent_skills/installer.py +22 -0
  162. code_puppy/plugins/agent_skills/metadata.py +219 -0
  163. code_puppy/plugins/agent_skills/prompt_builder.py +60 -0
  164. code_puppy/plugins/agent_skills/register_callbacks.py +241 -0
  165. code_puppy/plugins/agent_skills/remote_catalog.py +322 -0
  166. code_puppy/plugins/agent_skills/skill_catalog.py +257 -0
  167. code_puppy/plugins/agent_skills/skills_install_menu.py +664 -0
  168. code_puppy/plugins/agent_skills/skills_menu.py +781 -0
  169. code_puppy/plugins/antigravity_oauth/__init__.py +10 -0
  170. code_puppy/plugins/antigravity_oauth/accounts.py +406 -0
  171. code_puppy/plugins/antigravity_oauth/antigravity_model.py +706 -0
  172. code_puppy/plugins/antigravity_oauth/config.py +42 -0
  173. code_puppy/plugins/antigravity_oauth/constants.py +133 -0
  174. code_puppy/plugins/antigravity_oauth/oauth.py +478 -0
  175. code_puppy/plugins/antigravity_oauth/register_callbacks.py +518 -0
  176. code_puppy/plugins/antigravity_oauth/storage.py +288 -0
  177. code_puppy/plugins/antigravity_oauth/test_plugin.py +319 -0
  178. code_puppy/plugins/antigravity_oauth/token.py +167 -0
  179. code_puppy/plugins/antigravity_oauth/transport.py +863 -0
  180. code_puppy/plugins/antigravity_oauth/utils.py +168 -0
  181. code_puppy/plugins/chatgpt_oauth/__init__.py +8 -0
  182. code_puppy/plugins/chatgpt_oauth/config.py +52 -0
  183. code_puppy/plugins/chatgpt_oauth/oauth_flow.py +329 -0
  184. code_puppy/plugins/chatgpt_oauth/register_callbacks.py +176 -0
  185. code_puppy/plugins/chatgpt_oauth/test_plugin.py +301 -0
  186. code_puppy/plugins/chatgpt_oauth/utils.py +523 -0
  187. code_puppy/plugins/claude_code_hooks/__init__.py +1 -0
  188. code_puppy/plugins/claude_code_hooks/config.py +137 -0
  189. code_puppy/plugins/claude_code_hooks/register_callbacks.py +175 -0
  190. code_puppy/plugins/claude_code_oauth/README.md +167 -0
  191. code_puppy/plugins/claude_code_oauth/SETUP.md +93 -0
  192. code_puppy/plugins/claude_code_oauth/__init__.py +25 -0
  193. code_puppy/plugins/claude_code_oauth/config.py +52 -0
  194. code_puppy/plugins/claude_code_oauth/register_callbacks.py +453 -0
  195. code_puppy/plugins/claude_code_oauth/test_plugin.py +283 -0
  196. code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +241 -0
  197. code_puppy/plugins/claude_code_oauth/utils.py +640 -0
  198. code_puppy/plugins/customizable_commands/__init__.py +0 -0
  199. code_puppy/plugins/customizable_commands/register_callbacks.py +152 -0
  200. code_puppy/plugins/example_custom_command/README.md +280 -0
  201. code_puppy/plugins/example_custom_command/register_callbacks.py +51 -0
  202. code_puppy/plugins/file_permission_handler/__init__.py +4 -0
  203. code_puppy/plugins/file_permission_handler/register_callbacks.py +470 -0
  204. code_puppy/plugins/frontend_emitter/__init__.py +25 -0
  205. code_puppy/plugins/frontend_emitter/emitter.py +121 -0
  206. code_puppy/plugins/frontend_emitter/register_callbacks.py +261 -0
  207. code_puppy/plugins/hook_creator/__init__.py +1 -0
  208. code_puppy/plugins/hook_creator/register_callbacks.py +33 -0
  209. code_puppy/plugins/hook_manager/__init__.py +1 -0
  210. code_puppy/plugins/hook_manager/config.py +290 -0
  211. code_puppy/plugins/hook_manager/hooks_menu.py +564 -0
  212. code_puppy/plugins/hook_manager/register_callbacks.py +227 -0
  213. code_puppy/plugins/oauth_puppy_html.py +228 -0
  214. code_puppy/plugins/scheduler/__init__.py +1 -0
  215. code_puppy/plugins/scheduler/register_callbacks.py +88 -0
  216. code_puppy/plugins/scheduler/scheduler_menu.py +522 -0
  217. code_puppy/plugins/scheduler/scheduler_wizard.py +341 -0
  218. code_puppy/plugins/shell_safety/__init__.py +6 -0
  219. code_puppy/plugins/shell_safety/agent_shell_safety.py +69 -0
  220. code_puppy/plugins/shell_safety/command_cache.py +156 -0
  221. code_puppy/plugins/shell_safety/register_callbacks.py +202 -0
  222. code_puppy/plugins/synthetic_status/__init__.py +1 -0
  223. code_puppy/plugins/synthetic_status/register_callbacks.py +132 -0
  224. code_puppy/plugins/synthetic_status/status_api.py +147 -0
  225. code_puppy/plugins/universal_constructor/__init__.py +13 -0
  226. code_puppy/plugins/universal_constructor/models.py +138 -0
  227. code_puppy/plugins/universal_constructor/register_callbacks.py +47 -0
  228. code_puppy/plugins/universal_constructor/registry.py +302 -0
  229. code_puppy/plugins/universal_constructor/sandbox.py +584 -0
  230. code_puppy/prompts/antigravity_system_prompt.md +1 -0
  231. code_puppy/pydantic_patches.py +356 -0
  232. code_puppy/reopenable_async_client.py +232 -0
  233. code_puppy/round_robin_model.py +150 -0
  234. code_puppy/scheduler/__init__.py +41 -0
  235. code_puppy/scheduler/__main__.py +9 -0
  236. code_puppy/scheduler/cli.py +118 -0
  237. code_puppy/scheduler/config.py +126 -0
  238. code_puppy/scheduler/daemon.py +280 -0
  239. code_puppy/scheduler/executor.py +155 -0
  240. code_puppy/scheduler/platform.py +19 -0
  241. code_puppy/scheduler/platform_unix.py +22 -0
  242. code_puppy/scheduler/platform_win.py +32 -0
  243. code_puppy/session_storage.py +338 -0
  244. code_puppy/status_display.py +257 -0
  245. code_puppy/summarization_agent.py +176 -0
  246. code_puppy/terminal_utils.py +418 -0
  247. code_puppy/tools/__init__.py +501 -0
  248. code_puppy/tools/agent_tools.py +603 -0
  249. code_puppy/tools/ask_user_question/__init__.py +26 -0
  250. code_puppy/tools/ask_user_question/constants.py +73 -0
  251. code_puppy/tools/ask_user_question/demo_tui.py +55 -0
  252. code_puppy/tools/ask_user_question/handler.py +232 -0
  253. code_puppy/tools/ask_user_question/models.py +304 -0
  254. code_puppy/tools/ask_user_question/registration.py +26 -0
  255. code_puppy/tools/ask_user_question/renderers.py +309 -0
  256. code_puppy/tools/ask_user_question/terminal_ui.py +329 -0
  257. code_puppy/tools/ask_user_question/theme.py +155 -0
  258. code_puppy/tools/ask_user_question/tui_loop.py +423 -0
  259. code_puppy/tools/browser/__init__.py +37 -0
  260. code_puppy/tools/browser/browser_control.py +289 -0
  261. code_puppy/tools/browser/browser_interactions.py +545 -0
  262. code_puppy/tools/browser/browser_locators.py +640 -0
  263. code_puppy/tools/browser/browser_manager.py +378 -0
  264. code_puppy/tools/browser/browser_navigation.py +251 -0
  265. code_puppy/tools/browser/browser_screenshot.py +179 -0
  266. code_puppy/tools/browser/browser_scripts.py +462 -0
  267. code_puppy/tools/browser/browser_workflows.py +221 -0
  268. code_puppy/tools/browser/chromium_terminal_manager.py +259 -0
  269. code_puppy/tools/browser/terminal_command_tools.py +534 -0
  270. code_puppy/tools/browser/terminal_screenshot_tools.py +552 -0
  271. code_puppy/tools/browser/terminal_tools.py +525 -0
  272. code_puppy/tools/command_runner.py +1346 -0
  273. code_puppy/tools/common.py +1409 -0
  274. code_puppy/tools/display.py +84 -0
  275. code_puppy/tools/file_modifications.py +886 -0
  276. code_puppy/tools/file_operations.py +802 -0
  277. code_puppy/tools/scheduler_tools.py +412 -0
  278. code_puppy/tools/skills_tools.py +244 -0
  279. code_puppy/tools/subagent_context.py +158 -0
  280. code_puppy/tools/tools_content.py +51 -0
  281. code_puppy/tools/universal_constructor.py +889 -0
  282. code_puppy/uvx_detection.py +242 -0
  283. code_puppy/version_checker.py +82 -0
  284. codepp-0.0.437.dist-info/METADATA +766 -0
  285. codepp-0.0.437.dist-info/RECORD +288 -0
  286. codepp-0.0.437.dist-info/WHEEL +4 -0
  287. codepp-0.0.437.dist-info/entry_points.txt +3 -0
  288. codepp-0.0.437.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,73 @@
1
+ import glob
2
+ import os
3
+ from typing import Iterable
4
+
5
+ from prompt_toolkit.completion import Completer, Completion
6
+ from prompt_toolkit.document import Document
7
+
8
+
9
+ class FilePathCompleter(Completer):
10
+ """A simple file path completer that works with a trigger symbol."""
11
+
12
+ def __init__(self, symbol: str = "@"):
13
+ self.symbol = symbol
14
+
15
+ def get_completions(
16
+ self, document: Document, complete_event
17
+ ) -> Iterable[Completion]:
18
+ text = document.text
19
+ cursor_position = document.cursor_position
20
+ text_before_cursor = text[:cursor_position]
21
+ if self.symbol not in text_before_cursor:
22
+ return
23
+ symbol_pos = text_before_cursor.rfind(self.symbol)
24
+ text_after_symbol = text_before_cursor[symbol_pos + len(self.symbol) :]
25
+ start_position = -(len(text_after_symbol))
26
+ try:
27
+ pattern = text_after_symbol + "*"
28
+ if not pattern.strip("*") or pattern.strip("*").endswith("/"):
29
+ base_path = pattern.strip("*")
30
+ if not base_path:
31
+ base_path = "."
32
+ if base_path.startswith("~"):
33
+ base_path = os.path.expanduser(base_path)
34
+ if os.path.isdir(base_path):
35
+ paths = [
36
+ os.path.join(base_path, f)
37
+ for f in os.listdir(base_path)
38
+ if not f.startswith(".") or text_after_symbol.endswith(".")
39
+ ]
40
+ else:
41
+ paths = []
42
+ else:
43
+ paths = glob.glob(pattern)
44
+ if not pattern.startswith(".") and not pattern.startswith("*/."):
45
+ paths = [
46
+ p for p in paths if not os.path.basename(p).startswith(".")
47
+ ]
48
+ paths.sort()
49
+ for path in paths:
50
+ is_dir = os.path.isdir(path)
51
+ display = os.path.basename(path)
52
+ if os.path.isabs(path):
53
+ display_path = path
54
+ else:
55
+ if text_after_symbol.startswith("/"):
56
+ display_path = os.path.abspath(path)
57
+ elif text_after_symbol.startswith("~"):
58
+ home = os.path.expanduser("~")
59
+ if path.startswith(home):
60
+ display_path = "~" + path[len(home) :]
61
+ else:
62
+ display_path = path
63
+ else:
64
+ display_path = path
65
+ display_meta = "Directory" if is_dir else "File"
66
+ yield Completion(
67
+ display_path,
68
+ start_position=start_position,
69
+ display=display,
70
+ display_meta=display_meta,
71
+ )
72
+ except (PermissionError, FileNotFoundError, OSError):
73
+ pass
@@ -0,0 +1,52 @@
1
+ from pathlib import Path
2
+
3
+ from prompt_toolkit.completion import Completer, Completion
4
+
5
+ from code_puppy.config import CONFIG_DIR
6
+
7
+
8
+ class LoadContextCompleter(Completer):
9
+ def __init__(self, trigger: str = "/load_context"):
10
+ self.trigger = trigger
11
+
12
+ def get_completions(self, document, complete_event):
13
+ cursor_position = document.cursor_position
14
+ text_before_cursor = document.text_before_cursor
15
+ stripped_text_for_trigger_check = text_before_cursor.lstrip()
16
+
17
+ # If user types just /load_context (no space), suggest adding a space
18
+ if stripped_text_for_trigger_check == self.trigger:
19
+ yield Completion(
20
+ self.trigger + " ",
21
+ start_position=-len(self.trigger),
22
+ display=self.trigger + " ",
23
+ display_meta="load saved context",
24
+ )
25
+ return
26
+
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))
36
+
37
+ # Get available context files
38
+ try:
39
+ contexts_dir = Path(CONFIG_DIR) / "contexts"
40
+ if contexts_dir.exists():
41
+ for pkl_file in contexts_dir.glob("*.pkl"):
42
+ session_name = pkl_file.stem # removes .pkl extension
43
+ if session_name.startswith(session_filter):
44
+ yield Completion(
45
+ session_name,
46
+ start_position=start_position,
47
+ display=session_name,
48
+ display_meta="saved context session",
49
+ )
50
+ except Exception:
51
+ # Silently ignore errors (e.g., permission issues, non-existent dir)
52
+ pass
@@ -0,0 +1,10 @@
1
+ """
2
+ MCP Command Line Interface - Namespace package for MCP server management commands.
3
+
4
+ This package provides a modular command interface for managing MCP servers.
5
+ Each command is implemented in its own module for better maintainability.
6
+ """
7
+
8
+ from .handler import MCPCommandHandler
9
+
10
+ __all__ = ["MCPCommandHandler"]
@@ -0,0 +1,32 @@
1
+ """
2
+ MCP Command Base Classes - Shared functionality for MCP command handlers.
3
+
4
+ Provides base classes and common utilities used across all MCP command modules.
5
+ """
6
+
7
+ import logging
8
+
9
+ from code_puppy.mcp_.manager import get_mcp_manager
10
+
11
+ # Configure logging
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class MCPCommandBase:
16
+ """
17
+ Base class for MCP command handlers.
18
+
19
+ Provides common functionality like console access and MCP manager access
20
+ that all command handlers need.
21
+ """
22
+
23
+ def __init__(self):
24
+ """Initialize the base command handler."""
25
+ self.manager = get_mcp_manager()
26
+ logger.debug(f"Initialized {self.__class__.__name__}")
27
+
28
+ def generate_group_id(self) -> str:
29
+ """Generate a unique group ID for message grouping."""
30
+ import uuid
31
+
32
+ return str(uuid.uuid4())
@@ -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