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.
- code_puppy/__init__.py +10 -0
- code_puppy/__main__.py +10 -0
- code_puppy/agents/__init__.py +31 -0
- code_puppy/agents/agent_c_reviewer.py +155 -0
- code_puppy/agents/agent_code_puppy.py +117 -0
- code_puppy/agents/agent_code_reviewer.py +90 -0
- code_puppy/agents/agent_cpp_reviewer.py +132 -0
- code_puppy/agents/agent_creator_agent.py +638 -0
- code_puppy/agents/agent_golang_reviewer.py +151 -0
- code_puppy/agents/agent_helios.py +124 -0
- code_puppy/agents/agent_javascript_reviewer.py +160 -0
- code_puppy/agents/agent_manager.py +742 -0
- code_puppy/agents/agent_pack_leader.py +385 -0
- code_puppy/agents/agent_planning.py +165 -0
- code_puppy/agents/agent_python_programmer.py +169 -0
- code_puppy/agents/agent_python_reviewer.py +90 -0
- code_puppy/agents/agent_qa_expert.py +163 -0
- code_puppy/agents/agent_qa_kitten.py +208 -0
- code_puppy/agents/agent_scheduler.py +121 -0
- code_puppy/agents/agent_security_auditor.py +181 -0
- code_puppy/agents/agent_terminal_qa.py +323 -0
- code_puppy/agents/agent_typescript_reviewer.py +166 -0
- code_puppy/agents/base_agent.py +2156 -0
- code_puppy/agents/event_stream_handler.py +348 -0
- code_puppy/agents/json_agent.py +202 -0
- code_puppy/agents/pack/__init__.py +34 -0
- code_puppy/agents/pack/bloodhound.py +304 -0
- code_puppy/agents/pack/husky.py +327 -0
- code_puppy/agents/pack/retriever.py +393 -0
- code_puppy/agents/pack/shepherd.py +348 -0
- code_puppy/agents/pack/terrier.py +287 -0
- code_puppy/agents/pack/watchdog.py +367 -0
- code_puppy/agents/prompt_reviewer.py +145 -0
- code_puppy/agents/subagent_stream_handler.py +276 -0
- code_puppy/api/__init__.py +13 -0
- code_puppy/api/app.py +169 -0
- code_puppy/api/main.py +21 -0
- code_puppy/api/pty_manager.py +453 -0
- code_puppy/api/routers/__init__.py +12 -0
- code_puppy/api/routers/agents.py +36 -0
- code_puppy/api/routers/commands.py +217 -0
- code_puppy/api/routers/config.py +75 -0
- code_puppy/api/routers/sessions.py +234 -0
- code_puppy/api/templates/terminal.html +361 -0
- code_puppy/api/websocket.py +154 -0
- code_puppy/callbacks.py +692 -0
- code_puppy/chatgpt_codex_client.py +338 -0
- code_puppy/claude_cache_client.py +672 -0
- code_puppy/cli_runner.py +1073 -0
- code_puppy/command_line/__init__.py +1 -0
- code_puppy/command_line/add_model_menu.py +1092 -0
- code_puppy/command_line/agent_menu.py +662 -0
- code_puppy/command_line/attachments.py +395 -0
- code_puppy/command_line/autosave_menu.py +704 -0
- code_puppy/command_line/clipboard.py +527 -0
- code_puppy/command_line/colors_menu.py +532 -0
- code_puppy/command_line/command_handler.py +293 -0
- code_puppy/command_line/command_registry.py +150 -0
- code_puppy/command_line/config_commands.py +719 -0
- code_puppy/command_line/core_commands.py +867 -0
- code_puppy/command_line/diff_menu.py +865 -0
- code_puppy/command_line/file_path_completion.py +73 -0
- code_puppy/command_line/load_context_completion.py +52 -0
- code_puppy/command_line/mcp/__init__.py +10 -0
- code_puppy/command_line/mcp/base.py +32 -0
- code_puppy/command_line/mcp/catalog_server_installer.py +175 -0
- code_puppy/command_line/mcp/custom_server_form.py +688 -0
- code_puppy/command_line/mcp/custom_server_installer.py +195 -0
- code_puppy/command_line/mcp/edit_command.py +148 -0
- code_puppy/command_line/mcp/handler.py +138 -0
- code_puppy/command_line/mcp/help_command.py +147 -0
- code_puppy/command_line/mcp/install_command.py +214 -0
- code_puppy/command_line/mcp/install_menu.py +705 -0
- code_puppy/command_line/mcp/list_command.py +94 -0
- code_puppy/command_line/mcp/logs_command.py +235 -0
- code_puppy/command_line/mcp/remove_command.py +82 -0
- code_puppy/command_line/mcp/restart_command.py +100 -0
- code_puppy/command_line/mcp/search_command.py +123 -0
- code_puppy/command_line/mcp/start_all_command.py +135 -0
- code_puppy/command_line/mcp/start_command.py +117 -0
- code_puppy/command_line/mcp/status_command.py +184 -0
- code_puppy/command_line/mcp/stop_all_command.py +112 -0
- code_puppy/command_line/mcp/stop_command.py +80 -0
- code_puppy/command_line/mcp/test_command.py +107 -0
- code_puppy/command_line/mcp/utils.py +129 -0
- code_puppy/command_line/mcp/wizard_utils.py +334 -0
- code_puppy/command_line/mcp_completion.py +174 -0
- code_puppy/command_line/model_picker_completion.py +197 -0
- code_puppy/command_line/model_settings_menu.py +932 -0
- code_puppy/command_line/motd.py +96 -0
- code_puppy/command_line/onboarding_slides.py +179 -0
- code_puppy/command_line/onboarding_wizard.py +342 -0
- code_puppy/command_line/pin_command_completion.py +329 -0
- code_puppy/command_line/prompt_toolkit_completion.py +846 -0
- code_puppy/command_line/session_commands.py +302 -0
- code_puppy/command_line/shell_passthrough.py +145 -0
- code_puppy/command_line/skills_completion.py +160 -0
- code_puppy/command_line/uc_menu.py +893 -0
- code_puppy/command_line/utils.py +93 -0
- code_puppy/command_line/wiggum_state.py +78 -0
- code_puppy/config.py +1770 -0
- code_puppy/error_logging.py +134 -0
- code_puppy/gemini_code_assist.py +385 -0
- code_puppy/gemini_model.py +754 -0
- code_puppy/hook_engine/README.md +105 -0
- code_puppy/hook_engine/__init__.py +21 -0
- code_puppy/hook_engine/aliases.py +155 -0
- code_puppy/hook_engine/engine.py +221 -0
- code_puppy/hook_engine/executor.py +296 -0
- code_puppy/hook_engine/matcher.py +156 -0
- code_puppy/hook_engine/models.py +240 -0
- code_puppy/hook_engine/registry.py +106 -0
- code_puppy/hook_engine/validator.py +144 -0
- code_puppy/http_utils.py +361 -0
- code_puppy/keymap.py +128 -0
- code_puppy/main.py +10 -0
- code_puppy/mcp_/__init__.py +66 -0
- code_puppy/mcp_/async_lifecycle.py +286 -0
- code_puppy/mcp_/blocking_startup.py +469 -0
- code_puppy/mcp_/captured_stdio_server.py +275 -0
- code_puppy/mcp_/circuit_breaker.py +290 -0
- code_puppy/mcp_/config_wizard.py +507 -0
- code_puppy/mcp_/dashboard.py +308 -0
- code_puppy/mcp_/error_isolation.py +407 -0
- code_puppy/mcp_/examples/retry_example.py +226 -0
- code_puppy/mcp_/health_monitor.py +589 -0
- code_puppy/mcp_/managed_server.py +428 -0
- code_puppy/mcp_/manager.py +807 -0
- code_puppy/mcp_/mcp_logs.py +224 -0
- code_puppy/mcp_/registry.py +451 -0
- code_puppy/mcp_/retry_manager.py +337 -0
- code_puppy/mcp_/server_registry_catalog.py +1126 -0
- code_puppy/mcp_/status_tracker.py +355 -0
- code_puppy/mcp_/system_tools.py +209 -0
- code_puppy/mcp_prompts/__init__.py +1 -0
- code_puppy/mcp_prompts/hook_creator.py +103 -0
- code_puppy/messaging/__init__.py +255 -0
- code_puppy/messaging/bus.py +613 -0
- code_puppy/messaging/commands.py +167 -0
- code_puppy/messaging/markdown_patches.py +57 -0
- code_puppy/messaging/message_queue.py +361 -0
- code_puppy/messaging/messages.py +569 -0
- code_puppy/messaging/queue_console.py +271 -0
- code_puppy/messaging/renderers.py +311 -0
- code_puppy/messaging/rich_renderer.py +1158 -0
- code_puppy/messaging/spinner/__init__.py +83 -0
- code_puppy/messaging/spinner/console_spinner.py +240 -0
- code_puppy/messaging/spinner/spinner_base.py +95 -0
- code_puppy/messaging/subagent_console.py +460 -0
- code_puppy/model_factory.py +848 -0
- code_puppy/model_switching.py +63 -0
- code_puppy/model_utils.py +168 -0
- code_puppy/models.json +174 -0
- code_puppy/models_dev_api.json +1 -0
- code_puppy/models_dev_parser.py +592 -0
- code_puppy/plugins/__init__.py +186 -0
- code_puppy/plugins/agent_skills/__init__.py +22 -0
- code_puppy/plugins/agent_skills/config.py +175 -0
- code_puppy/plugins/agent_skills/discovery.py +136 -0
- code_puppy/plugins/agent_skills/downloader.py +392 -0
- code_puppy/plugins/agent_skills/installer.py +22 -0
- code_puppy/plugins/agent_skills/metadata.py +219 -0
- code_puppy/plugins/agent_skills/prompt_builder.py +60 -0
- code_puppy/plugins/agent_skills/register_callbacks.py +241 -0
- code_puppy/plugins/agent_skills/remote_catalog.py +322 -0
- code_puppy/plugins/agent_skills/skill_catalog.py +257 -0
- code_puppy/plugins/agent_skills/skills_install_menu.py +664 -0
- code_puppy/plugins/agent_skills/skills_menu.py +781 -0
- code_puppy/plugins/antigravity_oauth/__init__.py +10 -0
- code_puppy/plugins/antigravity_oauth/accounts.py +406 -0
- code_puppy/plugins/antigravity_oauth/antigravity_model.py +706 -0
- code_puppy/plugins/antigravity_oauth/config.py +42 -0
- code_puppy/plugins/antigravity_oauth/constants.py +133 -0
- code_puppy/plugins/antigravity_oauth/oauth.py +478 -0
- code_puppy/plugins/antigravity_oauth/register_callbacks.py +518 -0
- code_puppy/plugins/antigravity_oauth/storage.py +288 -0
- code_puppy/plugins/antigravity_oauth/test_plugin.py +319 -0
- code_puppy/plugins/antigravity_oauth/token.py +167 -0
- code_puppy/plugins/antigravity_oauth/transport.py +863 -0
- code_puppy/plugins/antigravity_oauth/utils.py +168 -0
- code_puppy/plugins/chatgpt_oauth/__init__.py +8 -0
- code_puppy/plugins/chatgpt_oauth/config.py +52 -0
- code_puppy/plugins/chatgpt_oauth/oauth_flow.py +329 -0
- code_puppy/plugins/chatgpt_oauth/register_callbacks.py +176 -0
- code_puppy/plugins/chatgpt_oauth/test_plugin.py +301 -0
- code_puppy/plugins/chatgpt_oauth/utils.py +523 -0
- code_puppy/plugins/claude_code_hooks/__init__.py +1 -0
- code_puppy/plugins/claude_code_hooks/config.py +137 -0
- code_puppy/plugins/claude_code_hooks/register_callbacks.py +175 -0
- code_puppy/plugins/claude_code_oauth/README.md +167 -0
- code_puppy/plugins/claude_code_oauth/SETUP.md +93 -0
- code_puppy/plugins/claude_code_oauth/__init__.py +25 -0
- code_puppy/plugins/claude_code_oauth/config.py +52 -0
- code_puppy/plugins/claude_code_oauth/register_callbacks.py +453 -0
- code_puppy/plugins/claude_code_oauth/test_plugin.py +283 -0
- code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +241 -0
- code_puppy/plugins/claude_code_oauth/utils.py +640 -0
- code_puppy/plugins/customizable_commands/__init__.py +0 -0
- code_puppy/plugins/customizable_commands/register_callbacks.py +152 -0
- code_puppy/plugins/example_custom_command/README.md +280 -0
- code_puppy/plugins/example_custom_command/register_callbacks.py +51 -0
- code_puppy/plugins/file_permission_handler/__init__.py +4 -0
- code_puppy/plugins/file_permission_handler/register_callbacks.py +470 -0
- code_puppy/plugins/frontend_emitter/__init__.py +25 -0
- code_puppy/plugins/frontend_emitter/emitter.py +121 -0
- code_puppy/plugins/frontend_emitter/register_callbacks.py +261 -0
- code_puppy/plugins/hook_creator/__init__.py +1 -0
- code_puppy/plugins/hook_creator/register_callbacks.py +33 -0
- code_puppy/plugins/hook_manager/__init__.py +1 -0
- code_puppy/plugins/hook_manager/config.py +290 -0
- code_puppy/plugins/hook_manager/hooks_menu.py +564 -0
- code_puppy/plugins/hook_manager/register_callbacks.py +227 -0
- code_puppy/plugins/oauth_puppy_html.py +228 -0
- code_puppy/plugins/scheduler/__init__.py +1 -0
- code_puppy/plugins/scheduler/register_callbacks.py +88 -0
- code_puppy/plugins/scheduler/scheduler_menu.py +522 -0
- code_puppy/plugins/scheduler/scheduler_wizard.py +341 -0
- code_puppy/plugins/shell_safety/__init__.py +6 -0
- code_puppy/plugins/shell_safety/agent_shell_safety.py +69 -0
- code_puppy/plugins/shell_safety/command_cache.py +156 -0
- code_puppy/plugins/shell_safety/register_callbacks.py +202 -0
- code_puppy/plugins/synthetic_status/__init__.py +1 -0
- code_puppy/plugins/synthetic_status/register_callbacks.py +132 -0
- code_puppy/plugins/synthetic_status/status_api.py +147 -0
- code_puppy/plugins/universal_constructor/__init__.py +13 -0
- code_puppy/plugins/universal_constructor/models.py +138 -0
- code_puppy/plugins/universal_constructor/register_callbacks.py +47 -0
- code_puppy/plugins/universal_constructor/registry.py +302 -0
- code_puppy/plugins/universal_constructor/sandbox.py +584 -0
- code_puppy/prompts/antigravity_system_prompt.md +1 -0
- code_puppy/pydantic_patches.py +356 -0
- code_puppy/reopenable_async_client.py +232 -0
- code_puppy/round_robin_model.py +150 -0
- code_puppy/scheduler/__init__.py +41 -0
- code_puppy/scheduler/__main__.py +9 -0
- code_puppy/scheduler/cli.py +118 -0
- code_puppy/scheduler/config.py +126 -0
- code_puppy/scheduler/daemon.py +280 -0
- code_puppy/scheduler/executor.py +155 -0
- code_puppy/scheduler/platform.py +19 -0
- code_puppy/scheduler/platform_unix.py +22 -0
- code_puppy/scheduler/platform_win.py +32 -0
- code_puppy/session_storage.py +338 -0
- code_puppy/status_display.py +257 -0
- code_puppy/summarization_agent.py +176 -0
- code_puppy/terminal_utils.py +418 -0
- code_puppy/tools/__init__.py +501 -0
- code_puppy/tools/agent_tools.py +603 -0
- code_puppy/tools/ask_user_question/__init__.py +26 -0
- code_puppy/tools/ask_user_question/constants.py +73 -0
- code_puppy/tools/ask_user_question/demo_tui.py +55 -0
- code_puppy/tools/ask_user_question/handler.py +232 -0
- code_puppy/tools/ask_user_question/models.py +304 -0
- code_puppy/tools/ask_user_question/registration.py +26 -0
- code_puppy/tools/ask_user_question/renderers.py +309 -0
- code_puppy/tools/ask_user_question/terminal_ui.py +329 -0
- code_puppy/tools/ask_user_question/theme.py +155 -0
- code_puppy/tools/ask_user_question/tui_loop.py +423 -0
- code_puppy/tools/browser/__init__.py +37 -0
- code_puppy/tools/browser/browser_control.py +289 -0
- code_puppy/tools/browser/browser_interactions.py +545 -0
- code_puppy/tools/browser/browser_locators.py +640 -0
- code_puppy/tools/browser/browser_manager.py +378 -0
- code_puppy/tools/browser/browser_navigation.py +251 -0
- code_puppy/tools/browser/browser_screenshot.py +179 -0
- code_puppy/tools/browser/browser_scripts.py +462 -0
- code_puppy/tools/browser/browser_workflows.py +221 -0
- code_puppy/tools/browser/chromium_terminal_manager.py +259 -0
- code_puppy/tools/browser/terminal_command_tools.py +534 -0
- code_puppy/tools/browser/terminal_screenshot_tools.py +552 -0
- code_puppy/tools/browser/terminal_tools.py +525 -0
- code_puppy/tools/command_runner.py +1346 -0
- code_puppy/tools/common.py +1409 -0
- code_puppy/tools/display.py +84 -0
- code_puppy/tools/file_modifications.py +886 -0
- code_puppy/tools/file_operations.py +802 -0
- code_puppy/tools/scheduler_tools.py +412 -0
- code_puppy/tools/skills_tools.py +244 -0
- code_puppy/tools/subagent_context.py +158 -0
- code_puppy/tools/tools_content.py +51 -0
- code_puppy/tools/universal_constructor.py +889 -0
- code_puppy/uvx_detection.py +242 -0
- code_puppy/version_checker.py +82 -0
- codepp-0.0.437.dist-info/METADATA +766 -0
- codepp-0.0.437.dist-info/RECORD +288 -0
- codepp-0.0.437.dist-info/WHEEL +4 -0
- codepp-0.0.437.dist-info/entry_points.txt +3 -0
- 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
|