code-puppy 0.0.169__py3-none-any.whl → 0.0.366__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- code_puppy/__init__.py +7 -1
- code_puppy/agents/__init__.py +8 -8
- code_puppy/agents/agent_c_reviewer.py +155 -0
- code_puppy/agents/agent_code_puppy.py +9 -2
- 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 +48 -9
- code_puppy/agents/agent_golang_reviewer.py +151 -0
- code_puppy/agents/agent_javascript_reviewer.py +160 -0
- code_puppy/agents/agent_manager.py +146 -199
- code_puppy/agents/agent_pack_leader.py +383 -0
- code_puppy/agents/agent_planning.py +163 -0
- code_puppy/agents/agent_python_programmer.py +165 -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_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 +1713 -1
- code_puppy/agents/event_stream_handler.py +350 -0
- code_puppy/agents/json_agent.py +12 -1
- code_puppy/agents/pack/__init__.py +34 -0
- code_puppy/agents/pack/bloodhound.py +304 -0
- code_puppy/agents/pack/husky.py +321 -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 +446 -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 +74 -0
- code_puppy/api/routers/sessions.py +232 -0
- code_puppy/api/templates/terminal.html +361 -0
- code_puppy/api/websocket.py +154 -0
- code_puppy/callbacks.py +174 -4
- code_puppy/chatgpt_codex_client.py +283 -0
- code_puppy/claude_cache_client.py +586 -0
- code_puppy/cli_runner.py +916 -0
- code_puppy/command_line/add_model_menu.py +1079 -0
- code_puppy/command_line/agent_menu.py +395 -0
- code_puppy/command_line/attachments.py +395 -0
- code_puppy/command_line/autosave_menu.py +605 -0
- code_puppy/command_line/clipboard.py +527 -0
- code_puppy/command_line/colors_menu.py +520 -0
- code_puppy/command_line/command_handler.py +233 -627
- code_puppy/command_line/command_registry.py +150 -0
- code_puppy/command_line/config_commands.py +715 -0
- code_puppy/command_line/core_commands.py +792 -0
- code_puppy/command_line/diff_menu.py +863 -0
- code_puppy/command_line/load_context_completion.py +15 -22
- code_puppy/command_line/mcp/base.py +1 -4
- 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 +9 -4
- code_puppy/command_line/mcp/help_command.py +6 -5
- code_puppy/command_line/mcp/install_command.py +16 -27
- code_puppy/command_line/mcp/install_menu.py +685 -0
- code_puppy/command_line/mcp/list_command.py +3 -3
- code_puppy/command_line/mcp/logs_command.py +174 -65
- code_puppy/command_line/mcp/remove_command.py +2 -2
- code_puppy/command_line/mcp/restart_command.py +12 -4
- code_puppy/command_line/mcp/search_command.py +17 -11
- code_puppy/command_line/mcp/start_all_command.py +22 -13
- code_puppy/command_line/mcp/start_command.py +50 -31
- code_puppy/command_line/mcp/status_command.py +6 -7
- code_puppy/command_line/mcp/stop_all_command.py +11 -8
- code_puppy/command_line/mcp/stop_command.py +11 -10
- code_puppy/command_line/mcp/test_command.py +2 -2
- code_puppy/command_line/mcp/utils.py +1 -1
- code_puppy/command_line/mcp/wizard_utils.py +22 -18
- code_puppy/command_line/mcp_completion.py +174 -0
- code_puppy/command_line/model_picker_completion.py +89 -30
- code_puppy/command_line/model_settings_menu.py +884 -0
- code_puppy/command_line/motd.py +14 -8
- code_puppy/command_line/onboarding_slides.py +179 -0
- code_puppy/command_line/onboarding_wizard.py +340 -0
- code_puppy/command_line/pin_command_completion.py +329 -0
- code_puppy/command_line/prompt_toolkit_completion.py +626 -75
- code_puppy/command_line/session_commands.py +296 -0
- code_puppy/command_line/utils.py +54 -0
- code_puppy/config.py +1181 -51
- code_puppy/error_logging.py +118 -0
- code_puppy/gemini_code_assist.py +385 -0
- code_puppy/gemini_model.py +602 -0
- code_puppy/http_utils.py +220 -104
- code_puppy/keymap.py +128 -0
- code_puppy/main.py +5 -594
- code_puppy/{mcp → mcp_}/__init__.py +17 -0
- code_puppy/{mcp → mcp_}/async_lifecycle.py +35 -4
- code_puppy/{mcp → mcp_}/blocking_startup.py +70 -43
- code_puppy/{mcp → mcp_}/captured_stdio_server.py +2 -2
- code_puppy/{mcp → mcp_}/config_wizard.py +5 -5
- code_puppy/{mcp → mcp_}/dashboard.py +15 -6
- code_puppy/{mcp → mcp_}/examples/retry_example.py +4 -1
- code_puppy/{mcp → mcp_}/managed_server.py +66 -39
- code_puppy/{mcp → mcp_}/manager.py +146 -52
- code_puppy/mcp_/mcp_logs.py +224 -0
- code_puppy/{mcp → mcp_}/registry.py +6 -6
- code_puppy/{mcp → mcp_}/server_registry_catalog.py +25 -8
- code_puppy/messaging/__init__.py +199 -2
- code_puppy/messaging/bus.py +610 -0
- code_puppy/messaging/commands.py +167 -0
- code_puppy/messaging/markdown_patches.py +57 -0
- code_puppy/messaging/message_queue.py +17 -48
- code_puppy/messaging/messages.py +500 -0
- code_puppy/messaging/queue_console.py +1 -24
- code_puppy/messaging/renderers.py +43 -146
- code_puppy/messaging/rich_renderer.py +1027 -0
- code_puppy/messaging/spinner/__init__.py +33 -5
- code_puppy/messaging/spinner/console_spinner.py +92 -52
- code_puppy/messaging/spinner/spinner_base.py +29 -0
- code_puppy/messaging/subagent_console.py +461 -0
- code_puppy/model_factory.py +686 -80
- code_puppy/model_utils.py +167 -0
- code_puppy/models.json +86 -104
- code_puppy/models_dev_api.json +1 -0
- code_puppy/models_dev_parser.py +592 -0
- code_puppy/plugins/__init__.py +164 -10
- 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 +704 -0
- code_puppy/plugins/antigravity_oauth/config.py +42 -0
- code_puppy/plugins/antigravity_oauth/constants.py +136 -0
- code_puppy/plugins/antigravity_oauth/oauth.py +478 -0
- code_puppy/plugins/antigravity_oauth/register_callbacks.py +406 -0
- code_puppy/plugins/antigravity_oauth/storage.py +271 -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 +767 -0
- code_puppy/plugins/antigravity_oauth/utils.py +169 -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 +328 -0
- code_puppy/plugins/chatgpt_oauth/register_callbacks.py +94 -0
- code_puppy/plugins/chatgpt_oauth/test_plugin.py +293 -0
- code_puppy/plugins/chatgpt_oauth/utils.py +489 -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 +6 -0
- code_puppy/plugins/claude_code_oauth/config.py +50 -0
- code_puppy/plugins/claude_code_oauth/register_callbacks.py +308 -0
- code_puppy/plugins/claude_code_oauth/test_plugin.py +283 -0
- code_puppy/plugins/claude_code_oauth/utils.py +518 -0
- code_puppy/plugins/customizable_commands/__init__.py +0 -0
- code_puppy/plugins/customizable_commands/register_callbacks.py +169 -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 +523 -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/oauth_puppy_html.py +228 -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/prompts/antigravity_system_prompt.md +1 -0
- code_puppy/prompts/codex_system_prompt.md +310 -0
- code_puppy/pydantic_patches.py +131 -0
- code_puppy/reopenable_async_client.py +8 -8
- code_puppy/round_robin_model.py +10 -15
- code_puppy/session_storage.py +294 -0
- code_puppy/status_display.py +21 -4
- code_puppy/summarization_agent.py +52 -14
- code_puppy/terminal_utils.py +418 -0
- code_puppy/tools/__init__.py +139 -6
- code_puppy/tools/agent_tools.py +548 -49
- 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 +316 -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 +521 -0
- code_puppy/tools/browser/terminal_screenshot_tools.py +556 -0
- code_puppy/tools/browser/terminal_tools.py +525 -0
- code_puppy/tools/command_runner.py +941 -153
- code_puppy/tools/common.py +1146 -6
- code_puppy/tools/display.py +84 -0
- code_puppy/tools/file_modifications.py +288 -89
- code_puppy/tools/file_operations.py +352 -266
- code_puppy/tools/subagent_context.py +158 -0
- code_puppy/uvx_detection.py +242 -0
- code_puppy/version_checker.py +30 -11
- code_puppy-0.0.366.data/data/code_puppy/models.json +110 -0
- code_puppy-0.0.366.data/data/code_puppy/models_dev_api.json +1 -0
- {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/METADATA +184 -67
- code_puppy-0.0.366.dist-info/RECORD +217 -0
- {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/WHEEL +1 -1
- {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/entry_points.txt +1 -0
- code_puppy/agent.py +0 -231
- code_puppy/agents/agent_orchestrator.json +0 -26
- code_puppy/agents/runtime_manager.py +0 -272
- code_puppy/command_line/mcp/add_command.py +0 -183
- code_puppy/command_line/meta_command_handler.py +0 -153
- code_puppy/message_history_processor.py +0 -490
- code_puppy/messaging/spinner/textual_spinner.py +0 -101
- code_puppy/state_management.py +0 -200
- code_puppy/tui/__init__.py +0 -10
- code_puppy/tui/app.py +0 -986
- code_puppy/tui/components/__init__.py +0 -21
- code_puppy/tui/components/chat_view.py +0 -550
- code_puppy/tui/components/command_history_modal.py +0 -218
- code_puppy/tui/components/copy_button.py +0 -139
- code_puppy/tui/components/custom_widgets.py +0 -63
- code_puppy/tui/components/human_input_modal.py +0 -175
- code_puppy/tui/components/input_area.py +0 -167
- code_puppy/tui/components/sidebar.py +0 -309
- code_puppy/tui/components/status_bar.py +0 -182
- code_puppy/tui/messages.py +0 -27
- code_puppy/tui/models/__init__.py +0 -8
- code_puppy/tui/models/chat_message.py +0 -25
- code_puppy/tui/models/command_history.py +0 -89
- code_puppy/tui/models/enums.py +0 -24
- code_puppy/tui/screens/__init__.py +0 -15
- code_puppy/tui/screens/help.py +0 -130
- code_puppy/tui/screens/mcp_install_wizard.py +0 -803
- code_puppy/tui/screens/settings.py +0 -290
- code_puppy/tui/screens/tools.py +0 -74
- code_puppy-0.0.169.data/data/code_puppy/models.json +0 -128
- code_puppy-0.0.169.dist-info/RECORD +0 -112
- /code_puppy/{mcp → mcp_}/circuit_breaker.py +0 -0
- /code_puppy/{mcp → mcp_}/error_isolation.py +0 -0
- /code_puppy/{mcp → mcp_}/health_monitor.py +0 -0
- /code_puppy/{mcp → mcp_}/retry_manager.py +0 -0
- /code_puppy/{mcp → mcp_}/status_tracker.py +0 -0
- /code_puppy/{mcp → mcp_}/system_tools.py +0 -0
- {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
"""
|
|
2
|
-
MCP Logs Command - Shows
|
|
2
|
+
MCP Logs Command - Shows server logs from persistent log files.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
|
-
from datetime import datetime
|
|
7
6
|
from typing import List, Optional
|
|
8
7
|
|
|
9
|
-
from rich.
|
|
8
|
+
from rich.panel import Panel
|
|
9
|
+
from rich.syntax import Syntax
|
|
10
10
|
from rich.text import Text
|
|
11
11
|
|
|
12
|
-
from code_puppy.
|
|
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
|
|
13
20
|
|
|
14
21
|
from .base import MCPCommandBase
|
|
15
22
|
from .utils import find_server_id_by_name, suggest_similar_servers
|
|
@@ -22,105 +29,207 @@ class LogsCommand(MCPCommandBase):
|
|
|
22
29
|
"""
|
|
23
30
|
Command handler for showing MCP server logs.
|
|
24
31
|
|
|
25
|
-
Shows
|
|
32
|
+
Shows logs from persistent log files stored in ~/.code_puppy/mcp_logs/.
|
|
26
33
|
"""
|
|
27
34
|
|
|
28
35
|
def execute(self, args: List[str], group_id: Optional[str] = None) -> None:
|
|
29
36
|
"""
|
|
30
|
-
Show
|
|
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
|
|
31
45
|
|
|
32
46
|
Args:
|
|
33
|
-
args: Command arguments
|
|
47
|
+
args: Command arguments
|
|
34
48
|
group_id: Optional message group ID for grouping related messages
|
|
35
49
|
"""
|
|
36
50
|
if group_id is None:
|
|
37
51
|
group_id = self.generate_group_id()
|
|
38
52
|
|
|
53
|
+
# No args - list servers with logs
|
|
39
54
|
if not args:
|
|
40
|
-
|
|
55
|
+
self._list_servers_with_logs(group_id)
|
|
41
56
|
return
|
|
42
57
|
|
|
43
58
|
server_name = args[0]
|
|
44
|
-
|
|
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
|
|
45
68
|
|
|
46
69
|
if len(args) > 1:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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:
|
|
50
82
|
emit_info(
|
|
51
|
-
"
|
|
83
|
+
f"Invalid number '{args[1]}', using default: 50",
|
|
52
84
|
message_group=group_id,
|
|
53
85
|
)
|
|
54
|
-
limit = 10
|
|
55
|
-
except ValueError:
|
|
56
|
-
emit_info(
|
|
57
|
-
f"Invalid limit '{args[1]}', using default: 10",
|
|
58
|
-
message_group=group_id,
|
|
59
|
-
)
|
|
60
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
|
+
"""
|
|
61
131
|
try:
|
|
62
|
-
#
|
|
132
|
+
# Verify server exists in manager
|
|
63
133
|
server_id = find_server_id_by_name(self.manager, server_name)
|
|
64
134
|
if not server_id:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
|
68
146
|
|
|
69
|
-
#
|
|
70
|
-
|
|
147
|
+
# Read logs
|
|
148
|
+
log_lines = read_logs(server_name, lines=lines)
|
|
71
149
|
|
|
72
|
-
if not
|
|
150
|
+
if not log_lines:
|
|
73
151
|
emit_info(
|
|
74
|
-
f"
|
|
152
|
+
f"📋 No logs found for server: **{server_name}**\n"
|
|
153
|
+
f"Log file: `{get_log_file_path(server_name)}`",
|
|
75
154
|
message_group=group_id,
|
|
76
155
|
)
|
|
77
156
|
return
|
|
78
157
|
|
|
79
|
-
|
|
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)
|
|
80
173
|
|
|
81
|
-
|
|
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:
|
|
82
194
|
emit_info(
|
|
83
|
-
|
|
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
|
+
),
|
|
84
199
|
message_group=group_id,
|
|
85
200
|
)
|
|
86
|
-
return
|
|
87
201
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
table.add_column("Event", style="cyan")
|
|
92
|
-
table.add_column("Details", style="dim")
|
|
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)
|
|
93
205
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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)
|
|
98
216
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
# Format details
|
|
105
|
-
details = event.get("details", {})
|
|
106
|
-
details_str = details.get("message", "")
|
|
107
|
-
if not details_str and "error" in details:
|
|
108
|
-
details_str = str(details["error"])
|
|
109
|
-
|
|
110
|
-
# Color code event types
|
|
111
|
-
event_style = "cyan"
|
|
112
|
-
if "error" in event_type.lower():
|
|
113
|
-
event_style = "red"
|
|
114
|
-
elif event_type in ["started", "enabled", "registered"]:
|
|
115
|
-
event_style = "green"
|
|
116
|
-
elif event_type in ["stopped", "disabled"]:
|
|
117
|
-
event_style = "yellow"
|
|
118
|
-
|
|
119
|
-
table.add_row(
|
|
120
|
-
time_str, Text(event_type, style=event_style), details_str or "-"
|
|
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,
|
|
121
221
|
)
|
|
122
|
-
|
|
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
|
+
)
|
|
123
232
|
|
|
124
233
|
except Exception as e:
|
|
125
|
-
logger.error(f"Error
|
|
126
|
-
|
|
234
|
+
logger.error(f"Error clearing logs for server '{server_name}': {e}")
|
|
235
|
+
emit_error(f"Error clearing logs: {e}", message_group=group_id)
|
|
@@ -7,7 +7,7 @@ import logging
|
|
|
7
7
|
import os
|
|
8
8
|
from typing import List, Optional
|
|
9
9
|
|
|
10
|
-
from code_puppy.messaging import emit_info
|
|
10
|
+
from code_puppy.messaging import emit_error, emit_info
|
|
11
11
|
|
|
12
12
|
from .base import MCPCommandBase
|
|
13
13
|
from .utils import find_server_id_by_name, suggest_similar_servers
|
|
@@ -79,4 +79,4 @@ class RemoveCommand(MCPCommandBase):
|
|
|
79
79
|
|
|
80
80
|
except Exception as e:
|
|
81
81
|
logger.error(f"Error removing server '{server_name}': {e}")
|
|
82
|
-
|
|
82
|
+
emit_error(f"Error removing server: {e}", message_group=group_id)
|
|
@@ -5,6 +5,8 @@ MCP Restart Command - Restarts a specific MCP server.
|
|
|
5
5
|
import logging
|
|
6
6
|
from typing import List, Optional
|
|
7
7
|
|
|
8
|
+
from rich.text import Text
|
|
9
|
+
|
|
8
10
|
from code_puppy.messaging import emit_info
|
|
9
11
|
|
|
10
12
|
from .base import MCPCommandBase
|
|
@@ -65,11 +67,16 @@ class RestartCommand(MCPCommandBase):
|
|
|
65
67
|
|
|
66
68
|
# Reload the agent to pick up the server changes
|
|
67
69
|
try:
|
|
68
|
-
from code_puppy.
|
|
70
|
+
from code_puppy.agents import get_current_agent
|
|
69
71
|
|
|
70
|
-
|
|
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()
|
|
71
76
|
emit_info(
|
|
72
|
-
|
|
77
|
+
Text.from_markup(
|
|
78
|
+
"[dim]Agent reloaded with updated servers[/dim]"
|
|
79
|
+
),
|
|
73
80
|
message_group=group_id,
|
|
74
81
|
)
|
|
75
82
|
except Exception as e:
|
|
@@ -88,5 +95,6 @@ class RestartCommand(MCPCommandBase):
|
|
|
88
95
|
except Exception as e:
|
|
89
96
|
logger.error(f"Error restarting server '{server_name}': {e}")
|
|
90
97
|
emit_info(
|
|
91
|
-
f"[red]Failed to restart server: {e}[/red]",
|
|
98
|
+
Text.from_markup(f"[red]Failed to restart server: {e}[/red]"),
|
|
99
|
+
message_group=group_id,
|
|
92
100
|
)
|
|
@@ -6,8 +6,9 @@ import logging
|
|
|
6
6
|
from typing import List, Optional
|
|
7
7
|
|
|
8
8
|
from rich.table import Table
|
|
9
|
+
from rich.text import Text
|
|
9
10
|
|
|
10
|
-
from code_puppy.messaging import emit_info, emit_system_message
|
|
11
|
+
from code_puppy.messaging import emit_info, emit_system_message, emit_warning
|
|
11
12
|
|
|
12
13
|
from .base import MCPCommandBase
|
|
13
14
|
|
|
@@ -34,26 +35,26 @@ class SearchCommand(MCPCommandBase):
|
|
|
34
35
|
group_id = self.generate_group_id()
|
|
35
36
|
|
|
36
37
|
try:
|
|
37
|
-
from code_puppy.
|
|
38
|
+
from code_puppy.mcp_.server_registry_catalog import catalog
|
|
38
39
|
|
|
39
40
|
if not args:
|
|
40
41
|
# Show popular servers if no query
|
|
41
42
|
emit_info(
|
|
42
|
-
"
|
|
43
|
+
"Popular MCP Servers:\n",
|
|
43
44
|
message_group=group_id,
|
|
44
45
|
)
|
|
45
46
|
servers = catalog.get_popular(15)
|
|
46
47
|
else:
|
|
47
48
|
query = " ".join(args)
|
|
48
49
|
emit_info(
|
|
49
|
-
f"
|
|
50
|
+
f"Searching for: {query}\n",
|
|
50
51
|
message_group=group_id,
|
|
51
52
|
)
|
|
52
53
|
servers = catalog.search(query)
|
|
53
54
|
|
|
54
55
|
if not servers:
|
|
55
|
-
|
|
56
|
-
"
|
|
56
|
+
emit_warning(
|
|
57
|
+
"No servers found matching your search",
|
|
57
58
|
message_group=group_id,
|
|
58
59
|
)
|
|
59
60
|
emit_info(
|
|
@@ -97,21 +98,26 @@ class SearchCommand(MCPCommandBase):
|
|
|
97
98
|
|
|
98
99
|
# The first message established the group, subsequent messages will auto-group
|
|
99
100
|
emit_system_message(table, message_group=group_id)
|
|
100
|
-
emit_info("\n
|
|
101
|
+
emit_info("\n✓ = Verified ⭐ = Popular", message_group=group_id)
|
|
101
102
|
emit_info(
|
|
102
|
-
"[yellow]To install:[/yellow] /mcp install <id>",
|
|
103
|
+
Text.from_markup("[yellow]To install:[/yellow] /mcp install <id>"),
|
|
104
|
+
message_group=group_id,
|
|
103
105
|
)
|
|
104
106
|
emit_info(
|
|
105
|
-
|
|
107
|
+
Text.from_markup(
|
|
108
|
+
"[yellow]For details:[/yellow] /mcp search <specific-term>"
|
|
109
|
+
),
|
|
106
110
|
message_group=group_id,
|
|
107
111
|
)
|
|
108
112
|
|
|
109
113
|
except ImportError:
|
|
110
114
|
emit_info(
|
|
111
|
-
"[red]Server registry not available[/red]",
|
|
115
|
+
Text.from_markup("[red]Server registry not available[/red]"),
|
|
116
|
+
message_group=group_id,
|
|
112
117
|
)
|
|
113
118
|
except Exception as e:
|
|
114
119
|
logger.error(f"Error searching server registry: {e}")
|
|
115
120
|
emit_info(
|
|
116
|
-
f"[red]Error searching servers: {e}[/red]",
|
|
121
|
+
Text.from_markup(f"[red]Error searching servers: {e}[/red]"),
|
|
122
|
+
message_group=group_id,
|
|
117
123
|
)
|
|
@@ -6,9 +6,12 @@ import logging
|
|
|
6
6
|
import time
|
|
7
7
|
from typing import List, Optional
|
|
8
8
|
|
|
9
|
-
from
|
|
9
|
+
from rich.text import Text
|
|
10
|
+
|
|
11
|
+
from code_puppy.mcp_.managed_server import ServerState
|
|
10
12
|
from code_puppy.messaging import emit_info
|
|
11
13
|
|
|
14
|
+
from ...agents import get_current_agent
|
|
12
15
|
from .base import MCPCommandBase
|
|
13
16
|
|
|
14
17
|
# Configure logging
|
|
@@ -66,20 +69,23 @@ class StartAllCommand(MCPCommandBase):
|
|
|
66
69
|
if success:
|
|
67
70
|
started_count += 1
|
|
68
71
|
emit_info(
|
|
69
|
-
f" [green]✓ Started: {server_name}[/green]",
|
|
72
|
+
Text.from_markup(f" [green]✓ Started: {server_name}[/green]"),
|
|
70
73
|
message_group=group_id,
|
|
71
74
|
)
|
|
72
75
|
else:
|
|
73
76
|
failed_count += 1
|
|
74
77
|
emit_info(
|
|
75
|
-
f" [red]✗ Failed: {server_name}[/red]",
|
|
78
|
+
Text.from_markup(f" [red]✗ Failed: {server_name}[/red]"),
|
|
79
|
+
message_group=group_id,
|
|
76
80
|
)
|
|
77
81
|
|
|
78
82
|
# Summary
|
|
79
83
|
emit_info("", message_group=group_id)
|
|
80
84
|
if started_count > 0:
|
|
81
85
|
emit_info(
|
|
82
|
-
|
|
86
|
+
Text.from_markup(
|
|
87
|
+
f"[green]Started {started_count} server(s)[/green]"
|
|
88
|
+
),
|
|
83
89
|
message_group=group_id,
|
|
84
90
|
)
|
|
85
91
|
if already_running > 0:
|
|
@@ -89,7 +95,9 @@ class StartAllCommand(MCPCommandBase):
|
|
|
89
95
|
)
|
|
90
96
|
if failed_count > 0:
|
|
91
97
|
emit_info(
|
|
92
|
-
|
|
98
|
+
Text.from_markup(
|
|
99
|
+
f"[yellow]Failed to start {failed_count} server(s)[/yellow]"
|
|
100
|
+
),
|
|
93
101
|
message_group=group_id,
|
|
94
102
|
)
|
|
95
103
|
|
|
@@ -106,14 +114,14 @@ class StartAllCommand(MCPCommandBase):
|
|
|
106
114
|
pass # No async loop, servers will start when agent uses them
|
|
107
115
|
|
|
108
116
|
try:
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
manager = get_runtime_agent_manager()
|
|
114
|
-
manager.reload_agent()
|
|
117
|
+
agent = get_current_agent()
|
|
118
|
+
agent.reload_code_generation_agent()
|
|
119
|
+
# Update MCP tool cache immediately so token counts reflect the change
|
|
120
|
+
agent.update_mcp_tool_cache_sync()
|
|
115
121
|
emit_info(
|
|
116
|
-
|
|
122
|
+
Text.from_markup(
|
|
123
|
+
"[dim]Agent reloaded with updated servers[/dim]"
|
|
124
|
+
),
|
|
117
125
|
message_group=group_id,
|
|
118
126
|
)
|
|
119
127
|
except Exception as e:
|
|
@@ -122,5 +130,6 @@ class StartAllCommand(MCPCommandBase):
|
|
|
122
130
|
except Exception as e:
|
|
123
131
|
logger.error(f"Error starting all servers: {e}")
|
|
124
132
|
emit_info(
|
|
125
|
-
f"[red]Failed to start servers: {e}[/red]",
|
|
133
|
+
Text.from_markup(f"[red]Failed to start servers: {e}[/red]"),
|
|
134
|
+
message_group=group_id,
|
|
126
135
|
)
|
|
@@ -3,11 +3,13 @@ MCP Start Command - Starts a specific MCP server.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
|
-
import time
|
|
7
6
|
from typing import List, Optional
|
|
8
7
|
|
|
9
|
-
from
|
|
8
|
+
from rich.text import Text
|
|
10
9
|
|
|
10
|
+
from code_puppy.messaging import emit_error, emit_info, emit_success
|
|
11
|
+
|
|
12
|
+
from ...agents import get_current_agent
|
|
11
13
|
from .base import MCPCommandBase
|
|
12
14
|
from .utils import find_server_id_by_name, suggest_similar_servers
|
|
13
15
|
|
|
@@ -20,6 +22,7 @@ class StartCommand(MCPCommandBase):
|
|
|
20
22
|
Command handler for starting MCP servers.
|
|
21
23
|
|
|
22
24
|
Starts a specific MCP server by name and reloads the agent.
|
|
25
|
+
The server subprocess starts asynchronously in the background.
|
|
23
26
|
"""
|
|
24
27
|
|
|
25
28
|
def execute(self, args: List[str], group_id: Optional[str] = None) -> None:
|
|
@@ -35,7 +38,7 @@ class StartCommand(MCPCommandBase):
|
|
|
35
38
|
|
|
36
39
|
if not args:
|
|
37
40
|
emit_info(
|
|
38
|
-
"[yellow]Usage: /mcp start <server_name>[/yellow]",
|
|
41
|
+
Text.from_markup("[yellow]Usage: /mcp start <server_name>[/yellow]"),
|
|
39
42
|
message_group=group_id,
|
|
40
43
|
)
|
|
41
44
|
return
|
|
@@ -46,53 +49,69 @@ class StartCommand(MCPCommandBase):
|
|
|
46
49
|
# Find server by name
|
|
47
50
|
server_id = find_server_id_by_name(self.manager, server_name)
|
|
48
51
|
if not server_id:
|
|
49
|
-
|
|
50
|
-
f"
|
|
52
|
+
emit_error(
|
|
53
|
+
f"Server '{server_name}' not found",
|
|
51
54
|
message_group=group_id,
|
|
52
55
|
)
|
|
53
56
|
suggest_similar_servers(self.manager, server_name, group_id=group_id)
|
|
54
57
|
return
|
|
55
58
|
|
|
56
|
-
#
|
|
59
|
+
# Get server info for better messaging (safely handle missing method)
|
|
60
|
+
server_type = "unknown"
|
|
61
|
+
try:
|
|
62
|
+
if hasattr(self.manager, "get_server_by_name"):
|
|
63
|
+
server_config = self.manager.get_server_by_name(server_name)
|
|
64
|
+
server_type = (
|
|
65
|
+
getattr(server_config, "type", "unknown")
|
|
66
|
+
if server_config
|
|
67
|
+
else "unknown"
|
|
68
|
+
)
|
|
69
|
+
except Exception:
|
|
70
|
+
pass # Default to unknown type if we can't determine it
|
|
71
|
+
|
|
72
|
+
# Start the server (schedules async start in background)
|
|
57
73
|
success = self.manager.start_server_sync(server_id)
|
|
58
74
|
|
|
59
75
|
if success:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
if server_type == "stdio":
|
|
77
|
+
# Stdio servers start subprocess asynchronously
|
|
78
|
+
emit_success(
|
|
79
|
+
f"🚀 Starting server: {server_name} (subprocess starting in background)",
|
|
80
|
+
message_group=group_id,
|
|
81
|
+
)
|
|
82
|
+
emit_info(
|
|
83
|
+
Text.from_markup(
|
|
84
|
+
"[dim]Tip: Use /mcp status to check if the server is fully initialized[/dim]"
|
|
85
|
+
),
|
|
86
|
+
message_group=group_id,
|
|
87
|
+
)
|
|
88
|
+
else:
|
|
89
|
+
# SSE/HTTP servers connect on first use
|
|
90
|
+
emit_success(
|
|
91
|
+
f"✅ Enabled server: {server_name}",
|
|
92
|
+
message_group=group_id,
|
|
93
|
+
)
|
|
75
94
|
|
|
76
95
|
# Reload the agent to pick up the newly enabled server
|
|
96
|
+
# NOTE: We don't block or wait - the server will be ready
|
|
97
|
+
# when the next prompt runs (pydantic-ai handles connection)
|
|
77
98
|
try:
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
manager = get_runtime_agent_manager()
|
|
83
|
-
manager.reload_agent()
|
|
99
|
+
agent = get_current_agent()
|
|
100
|
+
agent.reload_code_generation_agent()
|
|
101
|
+
# Clear MCP tool cache - it will be repopulated on next run
|
|
102
|
+
agent.update_mcp_tool_cache_sync()
|
|
84
103
|
emit_info(
|
|
85
|
-
"
|
|
104
|
+
"Agent reloaded with updated servers",
|
|
86
105
|
message_group=group_id,
|
|
87
106
|
)
|
|
88
107
|
except Exception as e:
|
|
89
108
|
logger.warning(f"Could not reload agent: {e}")
|
|
90
109
|
else:
|
|
91
|
-
|
|
92
|
-
f"
|
|
110
|
+
emit_error(
|
|
111
|
+
f"Failed to start server: {server_name}",
|
|
93
112
|
message_group=group_id,
|
|
94
113
|
)
|
|
95
114
|
|
|
96
115
|
except Exception as e:
|
|
97
116
|
logger.error(f"Error starting server '{server_name}': {e}")
|
|
98
|
-
|
|
117
|
+
emit_error(f"Failed to start server: {e}", message_group=group_id)
|