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,94 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP List Command - Lists all registered MCP servers in a formatted table.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import List, Optional
|
|
7
|
+
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
from rich.text import Text
|
|
10
|
+
|
|
11
|
+
from code_puppy.mcp_.managed_server import ServerState
|
|
12
|
+
from code_puppy.messaging import emit_error, emit_info
|
|
13
|
+
|
|
14
|
+
from .base import MCPCommandBase
|
|
15
|
+
from .utils import format_state_indicator, format_uptime
|
|
16
|
+
|
|
17
|
+
# Configure logging
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ListCommand(MCPCommandBase):
|
|
22
|
+
"""
|
|
23
|
+
Command handler for listing MCP servers.
|
|
24
|
+
|
|
25
|
+
Displays all registered MCP servers in a formatted table with status information.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def execute(self, args: List[str], group_id: Optional[str] = None) -> None:
|
|
29
|
+
"""
|
|
30
|
+
List all registered MCP servers in a formatted table.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
args: Command arguments (unused for list command)
|
|
34
|
+
group_id: Optional message group ID for grouping related messages
|
|
35
|
+
"""
|
|
36
|
+
if group_id is None:
|
|
37
|
+
group_id = self.generate_group_id()
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
servers = self.manager.list_servers()
|
|
41
|
+
|
|
42
|
+
if not servers:
|
|
43
|
+
emit_info("No MCP servers registered", message_group=group_id)
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
# Create table for server list
|
|
47
|
+
table = Table(title="🔌 MCP Server Status Dashboard")
|
|
48
|
+
table.add_column("Name", style="cyan", no_wrap=True)
|
|
49
|
+
table.add_column("Type", style="dim", no_wrap=True)
|
|
50
|
+
table.add_column("State", justify="center")
|
|
51
|
+
table.add_column("Enabled", justify="center")
|
|
52
|
+
table.add_column("Uptime", style="dim")
|
|
53
|
+
table.add_column("Status", style="dim")
|
|
54
|
+
|
|
55
|
+
for server in servers:
|
|
56
|
+
# Format state with appropriate color and icon
|
|
57
|
+
state_display = format_state_indicator(server.state)
|
|
58
|
+
|
|
59
|
+
# Format enabled status
|
|
60
|
+
enabled_display = "✓" if server.enabled else "✗"
|
|
61
|
+
enabled_style = "green" if server.enabled else "red"
|
|
62
|
+
|
|
63
|
+
# Format uptime
|
|
64
|
+
uptime_display = format_uptime(server.uptime_seconds)
|
|
65
|
+
|
|
66
|
+
# Format status message
|
|
67
|
+
status_display = server.error_message or "OK"
|
|
68
|
+
if server.quarantined:
|
|
69
|
+
status_display = "Quarantined"
|
|
70
|
+
|
|
71
|
+
table.add_row(
|
|
72
|
+
server.name,
|
|
73
|
+
server.type.upper(),
|
|
74
|
+
state_display,
|
|
75
|
+
Text(enabled_display, style=enabled_style),
|
|
76
|
+
uptime_display,
|
|
77
|
+
status_display,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
emit_info(table, message_group=group_id)
|
|
81
|
+
|
|
82
|
+
# Show summary
|
|
83
|
+
total = len(servers)
|
|
84
|
+
running = sum(
|
|
85
|
+
1 for s in servers if s.state == ServerState.RUNNING and s.enabled
|
|
86
|
+
)
|
|
87
|
+
emit_info(
|
|
88
|
+
f"\n📊 Summary: {running}/{total} servers running",
|
|
89
|
+
message_group=group_id,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
except Exception as e:
|
|
93
|
+
logger.error(f"Error listing MCP servers: {e}")
|
|
94
|
+
emit_error(f"Error listing servers: {e}", message_group=group_id)
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Logs Command - Shows server logs from persistent log files.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import List, Optional
|
|
7
|
+
|
|
8
|
+
from rich.panel import Panel
|
|
9
|
+
from rich.syntax import Syntax
|
|
10
|
+
from rich.text import Text
|
|
11
|
+
|
|
12
|
+
from code_puppy.mcp_.mcp_logs import (
|
|
13
|
+
clear_logs,
|
|
14
|
+
get_log_file_path,
|
|
15
|
+
get_log_stats,
|
|
16
|
+
list_servers_with_logs,
|
|
17
|
+
read_logs,
|
|
18
|
+
)
|
|
19
|
+
from code_puppy.messaging import emit_error, emit_info
|
|
20
|
+
|
|
21
|
+
from .base import MCPCommandBase
|
|
22
|
+
from .utils import find_server_id_by_name, suggest_similar_servers
|
|
23
|
+
|
|
24
|
+
# Configure logging
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class LogsCommand(MCPCommandBase):
|
|
29
|
+
"""
|
|
30
|
+
Command handler for showing MCP server logs.
|
|
31
|
+
|
|
32
|
+
Shows logs from persistent log files stored in ~/.code_puppy/mcp_logs/.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def execute(self, args: List[str], group_id: Optional[str] = None) -> None:
|
|
36
|
+
"""
|
|
37
|
+
Show logs for a server.
|
|
38
|
+
|
|
39
|
+
Usage:
|
|
40
|
+
/mcp logs - List servers with logs
|
|
41
|
+
/mcp logs <server_name> - Show last 50 lines
|
|
42
|
+
/mcp logs <server_name> 100 - Show last 100 lines
|
|
43
|
+
/mcp logs <server_name> all - Show all logs
|
|
44
|
+
/mcp logs <server_name> --clear - Clear logs for server
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
args: Command arguments
|
|
48
|
+
group_id: Optional message group ID for grouping related messages
|
|
49
|
+
"""
|
|
50
|
+
if group_id is None:
|
|
51
|
+
group_id = self.generate_group_id()
|
|
52
|
+
|
|
53
|
+
# No args - list servers with logs
|
|
54
|
+
if not args:
|
|
55
|
+
self._list_servers_with_logs(group_id)
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
server_name = args[0]
|
|
59
|
+
|
|
60
|
+
# Check for --clear flag
|
|
61
|
+
if len(args) > 1 and args[1] == "--clear":
|
|
62
|
+
self._clear_logs(server_name, group_id)
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
# Determine number of lines
|
|
66
|
+
lines = 50 # Default
|
|
67
|
+
show_all = False
|
|
68
|
+
|
|
69
|
+
if len(args) > 1:
|
|
70
|
+
if args[1].lower() == "all":
|
|
71
|
+
show_all = True
|
|
72
|
+
else:
|
|
73
|
+
try:
|
|
74
|
+
lines = int(args[1])
|
|
75
|
+
if lines <= 0:
|
|
76
|
+
emit_info(
|
|
77
|
+
"Lines must be positive, using default: 50",
|
|
78
|
+
message_group=group_id,
|
|
79
|
+
)
|
|
80
|
+
lines = 50
|
|
81
|
+
except ValueError:
|
|
82
|
+
emit_info(
|
|
83
|
+
f"Invalid number '{args[1]}', using default: 50",
|
|
84
|
+
message_group=group_id,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
self._show_logs(server_name, lines if not show_all else None, group_id)
|
|
88
|
+
|
|
89
|
+
def _list_servers_with_logs(self, group_id: str) -> None:
|
|
90
|
+
"""List all servers that have log files."""
|
|
91
|
+
servers = list_servers_with_logs()
|
|
92
|
+
|
|
93
|
+
if not servers:
|
|
94
|
+
emit_info(
|
|
95
|
+
"📋 No MCP server logs found.\n"
|
|
96
|
+
"Logs are created when servers are started.",
|
|
97
|
+
message_group=group_id,
|
|
98
|
+
)
|
|
99
|
+
return
|
|
100
|
+
|
|
101
|
+
lines = ["📋 **Servers with logs:**\n"]
|
|
102
|
+
|
|
103
|
+
for server in servers:
|
|
104
|
+
stats = get_log_stats(server)
|
|
105
|
+
size_kb = stats["total_size_bytes"] / 1024
|
|
106
|
+
size_str = (
|
|
107
|
+
f"{size_kb:.1f} KB" if size_kb < 1024 else f"{size_kb / 1024:.1f} MB"
|
|
108
|
+
)
|
|
109
|
+
rotated = (
|
|
110
|
+
f" (+{stats['rotated_count']} rotated)"
|
|
111
|
+
if stats["rotated_count"]
|
|
112
|
+
else ""
|
|
113
|
+
)
|
|
114
|
+
lines.append(
|
|
115
|
+
f" • **{server}** - {stats['line_count']} lines, {size_str}{rotated}"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
lines.append("\n**Usage:** `/mcp logs <server_name> [lines|all]`")
|
|
119
|
+
|
|
120
|
+
emit_info("\n".join(lines), message_group=group_id)
|
|
121
|
+
|
|
122
|
+
def _show_logs(self, server_name: str, lines: Optional[int], group_id: str) -> None:
|
|
123
|
+
"""
|
|
124
|
+
Show logs for a specific server.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
server_name: Name of the server
|
|
128
|
+
lines: Number of lines to show, or None for all
|
|
129
|
+
group_id: Message group ID
|
|
130
|
+
"""
|
|
131
|
+
try:
|
|
132
|
+
# Verify server exists in manager
|
|
133
|
+
server_id = find_server_id_by_name(self.manager, server_name)
|
|
134
|
+
if not server_id:
|
|
135
|
+
# Server not configured, but might have logs from before
|
|
136
|
+
stats = get_log_stats(server_name)
|
|
137
|
+
if not stats["exists"]:
|
|
138
|
+
emit_info(
|
|
139
|
+
f"Server '{server_name}' not found and has no logs.",
|
|
140
|
+
message_group=group_id,
|
|
141
|
+
)
|
|
142
|
+
suggest_similar_servers(
|
|
143
|
+
self.manager, server_name, group_id=group_id
|
|
144
|
+
)
|
|
145
|
+
return
|
|
146
|
+
|
|
147
|
+
# Read logs
|
|
148
|
+
log_lines = read_logs(server_name, lines=lines)
|
|
149
|
+
|
|
150
|
+
if not log_lines:
|
|
151
|
+
emit_info(
|
|
152
|
+
f"📋 No logs found for server: **{server_name}**\n"
|
|
153
|
+
f"Log file: `{get_log_file_path(server_name)}`",
|
|
154
|
+
message_group=group_id,
|
|
155
|
+
)
|
|
156
|
+
return
|
|
157
|
+
|
|
158
|
+
# Get stats for header
|
|
159
|
+
stats = get_log_stats(server_name)
|
|
160
|
+
total_lines = stats["line_count"]
|
|
161
|
+
showing = len(log_lines)
|
|
162
|
+
|
|
163
|
+
# Format header
|
|
164
|
+
if lines is None:
|
|
165
|
+
header = f"📋 Logs for {server_name} (all {total_lines} lines)"
|
|
166
|
+
else:
|
|
167
|
+
header = (
|
|
168
|
+
f"📋 Logs for {server_name} (last {showing} of {total_lines} lines)"
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Format log content with syntax highlighting
|
|
172
|
+
log_content = "\n".join(log_lines)
|
|
173
|
+
|
|
174
|
+
# Create a panel with the logs
|
|
175
|
+
syntax = Syntax(
|
|
176
|
+
log_content,
|
|
177
|
+
"log",
|
|
178
|
+
theme="monokai",
|
|
179
|
+
word_wrap=True,
|
|
180
|
+
line_numbers=False,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
panel = Panel(
|
|
184
|
+
syntax,
|
|
185
|
+
title=header,
|
|
186
|
+
subtitle=f"Log file: {get_log_file_path(server_name)}",
|
|
187
|
+
border_style="dim",
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
emit_info(panel, message_group=group_id)
|
|
191
|
+
|
|
192
|
+
# Show hint for more options
|
|
193
|
+
if lines is not None and showing < total_lines:
|
|
194
|
+
emit_info(
|
|
195
|
+
Text.from_markup(
|
|
196
|
+
f"[dim]💡 Use `/mcp logs {server_name} all` to see all logs, "
|
|
197
|
+
f"or `/mcp logs {server_name} <number>` for specific count[/dim]"
|
|
198
|
+
),
|
|
199
|
+
message_group=group_id,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
except Exception as e:
|
|
203
|
+
logger.error(f"Error getting logs for server '{server_name}': {e}")
|
|
204
|
+
emit_error(f"Error getting logs: {e}", message_group=group_id)
|
|
205
|
+
|
|
206
|
+
def _clear_logs(self, server_name: str, group_id: str) -> None:
|
|
207
|
+
"""
|
|
208
|
+
Clear logs for a specific server.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
server_name: Name of the server
|
|
212
|
+
group_id: Message group ID
|
|
213
|
+
"""
|
|
214
|
+
try:
|
|
215
|
+
stats = get_log_stats(server_name)
|
|
216
|
+
|
|
217
|
+
if not stats["exists"] and stats["rotated_count"] == 0:
|
|
218
|
+
emit_info(
|
|
219
|
+
f"No logs to clear for server: {server_name}",
|
|
220
|
+
message_group=group_id,
|
|
221
|
+
)
|
|
222
|
+
return
|
|
223
|
+
|
|
224
|
+
# Clear the logs
|
|
225
|
+
clear_logs(server_name, include_rotated=True)
|
|
226
|
+
|
|
227
|
+
cleared_count = 1 + stats["rotated_count"]
|
|
228
|
+
emit_info(
|
|
229
|
+
f"🗑️ Cleared {cleared_count} log file(s) for **{server_name}**",
|
|
230
|
+
message_group=group_id,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
except Exception as e:
|
|
234
|
+
logger.error(f"Error clearing logs for server '{server_name}': {e}")
|
|
235
|
+
emit_error(f"Error clearing logs: {e}", message_group=group_id)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Remove Command - Removes an MCP server.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
from typing import List, Optional
|
|
9
|
+
|
|
10
|
+
from code_puppy.messaging import emit_error, emit_info
|
|
11
|
+
|
|
12
|
+
from .base import MCPCommandBase
|
|
13
|
+
from .utils import find_server_id_by_name, suggest_similar_servers
|
|
14
|
+
|
|
15
|
+
# Configure logging
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class RemoveCommand(MCPCommandBase):
|
|
20
|
+
"""
|
|
21
|
+
Command handler for removing MCP servers.
|
|
22
|
+
|
|
23
|
+
Removes a specific MCP server from the manager and configuration.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def execute(self, args: List[str], group_id: Optional[str] = None) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Remove an MCP server.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
args: Command arguments, expects [server_name]
|
|
32
|
+
group_id: Optional message group ID for grouping related messages
|
|
33
|
+
"""
|
|
34
|
+
if group_id is None:
|
|
35
|
+
group_id = self.generate_group_id()
|
|
36
|
+
|
|
37
|
+
if not args:
|
|
38
|
+
emit_info("Usage: /mcp remove <server_name>", message_group=group_id)
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
server_name = args[0]
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
# Find server by name
|
|
45
|
+
server_id = find_server_id_by_name(self.manager, server_name)
|
|
46
|
+
if not server_id:
|
|
47
|
+
emit_info(f"Server '{server_name}' not found", message_group=group_id)
|
|
48
|
+
suggest_similar_servers(self.manager, server_name, group_id=group_id)
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
# Actually remove the server
|
|
52
|
+
success = self.manager.remove_server(server_id)
|
|
53
|
+
|
|
54
|
+
if success:
|
|
55
|
+
emit_info(f"✓ Removed server: {server_name}", message_group=group_id)
|
|
56
|
+
|
|
57
|
+
# Also remove from mcp_servers.json
|
|
58
|
+
from code_puppy.config import MCP_SERVERS_FILE
|
|
59
|
+
|
|
60
|
+
if os.path.exists(MCP_SERVERS_FILE):
|
|
61
|
+
try:
|
|
62
|
+
with open(MCP_SERVERS_FILE, "r") as f:
|
|
63
|
+
data = json.load(f)
|
|
64
|
+
servers = data.get("mcp_servers", {})
|
|
65
|
+
|
|
66
|
+
# Remove the server if it exists
|
|
67
|
+
if server_name in servers:
|
|
68
|
+
del servers[server_name]
|
|
69
|
+
|
|
70
|
+
# Save back
|
|
71
|
+
with open(MCP_SERVERS_FILE, "w") as f:
|
|
72
|
+
json.dump(data, f, indent=2)
|
|
73
|
+
except Exception as e:
|
|
74
|
+
logger.warning(f"Could not update mcp_servers.json: {e}")
|
|
75
|
+
else:
|
|
76
|
+
emit_info(
|
|
77
|
+
f"✗ Failed to remove server: {server_name}", message_group=group_id
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
except Exception as e:
|
|
81
|
+
logger.error(f"Error removing server '{server_name}': {e}")
|
|
82
|
+
emit_error(f"Error removing server: {e}", message_group=group_id)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Restart Command - Restarts a specific MCP server.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import List, Optional
|
|
7
|
+
|
|
8
|
+
from rich.text import Text
|
|
9
|
+
|
|
10
|
+
from code_puppy.messaging import emit_info
|
|
11
|
+
|
|
12
|
+
from .base import MCPCommandBase
|
|
13
|
+
from .utils import find_server_id_by_name, suggest_similar_servers
|
|
14
|
+
|
|
15
|
+
# Configure logging
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class RestartCommand(MCPCommandBase):
|
|
20
|
+
"""
|
|
21
|
+
Command handler for restarting MCP servers.
|
|
22
|
+
|
|
23
|
+
Stops, reloads configuration, and starts a specific MCP server.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def execute(self, args: List[str], group_id: Optional[str] = None) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Restart a specific MCP server.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
args: Command arguments, expects [server_name]
|
|
32
|
+
group_id: Optional message group ID for grouping related messages
|
|
33
|
+
"""
|
|
34
|
+
if group_id is None:
|
|
35
|
+
group_id = self.generate_group_id()
|
|
36
|
+
|
|
37
|
+
if not args:
|
|
38
|
+
emit_info("Usage: /mcp restart <server_name>", message_group=group_id)
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
server_name = args[0]
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
# Find server by name
|
|
45
|
+
server_id = find_server_id_by_name(self.manager, server_name)
|
|
46
|
+
if not server_id:
|
|
47
|
+
emit_info(f"Server '{server_name}' not found", message_group=group_id)
|
|
48
|
+
suggest_similar_servers(self.manager, server_name, group_id=group_id)
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
# Stop the server first
|
|
52
|
+
emit_info(f"Stopping server: {server_name}", message_group=group_id)
|
|
53
|
+
self.manager.stop_server_sync(server_id)
|
|
54
|
+
|
|
55
|
+
# Then reload and start it
|
|
56
|
+
emit_info("Reloading configuration...", message_group=group_id)
|
|
57
|
+
reload_success = self.manager.reload_server(server_id)
|
|
58
|
+
|
|
59
|
+
if reload_success:
|
|
60
|
+
emit_info(f"Starting server: {server_name}", message_group=group_id)
|
|
61
|
+
start_success = self.manager.start_server_sync(server_id)
|
|
62
|
+
|
|
63
|
+
if start_success:
|
|
64
|
+
emit_info(
|
|
65
|
+
f"✓ Restarted server: {server_name}", message_group=group_id
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Reload the agent to pick up the server changes
|
|
69
|
+
try:
|
|
70
|
+
from code_puppy.agents import get_current_agent
|
|
71
|
+
|
|
72
|
+
agent = get_current_agent()
|
|
73
|
+
agent.reload_code_generation_agent()
|
|
74
|
+
# Update MCP tool cache immediately so token counts reflect the change
|
|
75
|
+
agent.update_mcp_tool_cache_sync()
|
|
76
|
+
emit_info(
|
|
77
|
+
Text.from_markup(
|
|
78
|
+
"[dim]Agent reloaded with updated servers[/dim]"
|
|
79
|
+
),
|
|
80
|
+
message_group=group_id,
|
|
81
|
+
)
|
|
82
|
+
except Exception as e:
|
|
83
|
+
logger.warning(f"Could not reload agent: {e}")
|
|
84
|
+
else:
|
|
85
|
+
emit_info(
|
|
86
|
+
f"✗ Failed to start server after reload: {server_name}",
|
|
87
|
+
message_group=group_id,
|
|
88
|
+
)
|
|
89
|
+
else:
|
|
90
|
+
emit_info(
|
|
91
|
+
f"✗ Failed to reload server configuration: {server_name}",
|
|
92
|
+
message_group=group_id,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
except Exception as e:
|
|
96
|
+
logger.error(f"Error restarting server '{server_name}': {e}")
|
|
97
|
+
emit_info(
|
|
98
|
+
Text.from_markup(f"[red]Failed to restart server: {e}[/red]"),
|
|
99
|
+
message_group=group_id,
|
|
100
|
+
)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Search Command - Searches for pre-configured MCP servers in the registry.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import List, Optional
|
|
7
|
+
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
from rich.text import Text
|
|
10
|
+
|
|
11
|
+
from code_puppy.messaging import emit_info, emit_system_message, emit_warning
|
|
12
|
+
|
|
13
|
+
from .base import MCPCommandBase
|
|
14
|
+
|
|
15
|
+
# Configure logging
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SearchCommand(MCPCommandBase):
|
|
20
|
+
"""
|
|
21
|
+
Command handler for searching MCP server registry.
|
|
22
|
+
|
|
23
|
+
Searches for pre-configured MCP servers with optional query terms.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def execute(self, args: List[str], group_id: Optional[str] = None) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Search for pre-configured MCP servers in the registry.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
args: Search query terms
|
|
32
|
+
group_id: Optional message group ID for grouping related messages
|
|
33
|
+
"""
|
|
34
|
+
if group_id is None:
|
|
35
|
+
group_id = self.generate_group_id()
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
from code_puppy.mcp_.server_registry_catalog import catalog
|
|
39
|
+
|
|
40
|
+
if not args:
|
|
41
|
+
# Show popular servers if no query
|
|
42
|
+
emit_info(
|
|
43
|
+
"Popular MCP Servers:\n",
|
|
44
|
+
message_group=group_id,
|
|
45
|
+
)
|
|
46
|
+
servers = catalog.get_popular(15)
|
|
47
|
+
else:
|
|
48
|
+
query = " ".join(args)
|
|
49
|
+
emit_info(
|
|
50
|
+
f"Searching for: {query}\n",
|
|
51
|
+
message_group=group_id,
|
|
52
|
+
)
|
|
53
|
+
servers = catalog.search(query)
|
|
54
|
+
|
|
55
|
+
if not servers:
|
|
56
|
+
emit_warning(
|
|
57
|
+
"No servers found matching your search",
|
|
58
|
+
message_group=group_id,
|
|
59
|
+
)
|
|
60
|
+
emit_info(
|
|
61
|
+
"Try: /mcp search database, /mcp search file, /mcp search git",
|
|
62
|
+
message_group=group_id,
|
|
63
|
+
)
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
# Create results table
|
|
67
|
+
table = Table(show_header=True, header_style="bold magenta")
|
|
68
|
+
table.add_column("ID", style="cyan", width=20)
|
|
69
|
+
table.add_column("Name", style="green")
|
|
70
|
+
table.add_column("Category", style="yellow")
|
|
71
|
+
table.add_column("Description", style="white")
|
|
72
|
+
table.add_column("Tags", style="dim")
|
|
73
|
+
|
|
74
|
+
for server in servers[:20]: # Limit to 20 results
|
|
75
|
+
tags = ", ".join(server.tags[:3]) # Show first 3 tags
|
|
76
|
+
if len(server.tags) > 3:
|
|
77
|
+
tags += "..."
|
|
78
|
+
|
|
79
|
+
# Add verified/popular indicators
|
|
80
|
+
indicators = []
|
|
81
|
+
if server.verified:
|
|
82
|
+
indicators.append("✓")
|
|
83
|
+
if server.popular:
|
|
84
|
+
indicators.append("⭐")
|
|
85
|
+
name_display = server.display_name
|
|
86
|
+
if indicators:
|
|
87
|
+
name_display += f" {''.join(indicators)}"
|
|
88
|
+
|
|
89
|
+
table.add_row(
|
|
90
|
+
server.id,
|
|
91
|
+
name_display,
|
|
92
|
+
server.category,
|
|
93
|
+
server.description[:50] + "..."
|
|
94
|
+
if len(server.description) > 50
|
|
95
|
+
else server.description,
|
|
96
|
+
tags,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# The first message established the group, subsequent messages will auto-group
|
|
100
|
+
emit_system_message(table, message_group=group_id)
|
|
101
|
+
emit_info("\n✓ = Verified ⭐ = Popular", message_group=group_id)
|
|
102
|
+
emit_info(
|
|
103
|
+
Text.from_markup("[yellow]To install:[/yellow] /mcp install <id>"),
|
|
104
|
+
message_group=group_id,
|
|
105
|
+
)
|
|
106
|
+
emit_info(
|
|
107
|
+
Text.from_markup(
|
|
108
|
+
"[yellow]For details:[/yellow] /mcp search <specific-term>"
|
|
109
|
+
),
|
|
110
|
+
message_group=group_id,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
except ImportError:
|
|
114
|
+
emit_info(
|
|
115
|
+
Text.from_markup("[red]Server registry not available[/red]"),
|
|
116
|
+
message_group=group_id,
|
|
117
|
+
)
|
|
118
|
+
except Exception as e:
|
|
119
|
+
logger.error(f"Error searching server registry: {e}")
|
|
120
|
+
emit_info(
|
|
121
|
+
Text.from_markup(f"[red]Error searching servers: {e}[/red]"),
|
|
122
|
+
message_group=group_id,
|
|
123
|
+
)
|