code-puppy 0.0.287__py3-none-any.whl ā 0.0.323__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 +3 -1
- code_puppy/agents/agent_code_puppy.py +5 -4
- code_puppy/agents/agent_creator_agent.py +22 -18
- code_puppy/agents/agent_manager.py +2 -2
- code_puppy/agents/base_agent.py +496 -102
- code_puppy/callbacks.py +8 -0
- code_puppy/chatgpt_codex_client.py +283 -0
- code_puppy/cli_runner.py +795 -0
- code_puppy/command_line/add_model_menu.py +19 -16
- code_puppy/command_line/attachments.py +10 -5
- code_puppy/command_line/autosave_menu.py +269 -41
- code_puppy/command_line/colors_menu.py +515 -0
- code_puppy/command_line/command_handler.py +10 -24
- code_puppy/command_line/config_commands.py +106 -25
- code_puppy/command_line/core_commands.py +32 -20
- code_puppy/command_line/mcp/add_command.py +3 -16
- code_puppy/command_line/mcp/base.py +0 -3
- code_puppy/command_line/mcp/catalog_server_installer.py +15 -15
- code_puppy/command_line/mcp/custom_server_form.py +66 -5
- code_puppy/command_line/mcp/custom_server_installer.py +17 -17
- code_puppy/command_line/mcp/edit_command.py +15 -22
- code_puppy/command_line/mcp/handler.py +7 -2
- code_puppy/command_line/mcp/help_command.py +2 -2
- code_puppy/command_line/mcp/install_command.py +10 -14
- code_puppy/command_line/mcp/install_menu.py +2 -6
- code_puppy/command_line/mcp/list_command.py +2 -2
- 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 +7 -2
- code_puppy/command_line/mcp/search_command.py +16 -10
- code_puppy/command_line/mcp/start_all_command.py +16 -6
- code_puppy/command_line/mcp/start_command.py +12 -10
- code_puppy/command_line/mcp/status_command.py +4 -5
- code_puppy/command_line/mcp/stop_all_command.py +5 -1
- code_puppy/command_line/mcp/stop_command.py +6 -4
- code_puppy/command_line/mcp/test_command.py +2 -2
- code_puppy/command_line/mcp/wizard_utils.py +20 -16
- code_puppy/command_line/model_settings_menu.py +53 -7
- code_puppy/command_line/motd.py +1 -1
- code_puppy/command_line/pin_command_completion.py +82 -7
- code_puppy/command_line/prompt_toolkit_completion.py +32 -9
- code_puppy/command_line/session_commands.py +11 -4
- code_puppy/config.py +217 -53
- code_puppy/error_logging.py +118 -0
- code_puppy/gemini_code_assist.py +385 -0
- code_puppy/keymap.py +126 -0
- code_puppy/main.py +5 -745
- code_puppy/mcp_/__init__.py +17 -0
- code_puppy/mcp_/blocking_startup.py +63 -36
- code_puppy/mcp_/captured_stdio_server.py +1 -1
- code_puppy/mcp_/config_wizard.py +4 -4
- code_puppy/mcp_/dashboard.py +15 -6
- code_puppy/mcp_/managed_server.py +25 -5
- code_puppy/mcp_/manager.py +65 -0
- code_puppy/mcp_/mcp_logs.py +224 -0
- code_puppy/mcp_/registry.py +6 -6
- code_puppy/messaging/__init__.py +184 -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 +3 -3
- code_puppy/messaging/messages.py +470 -0
- code_puppy/messaging/renderers.py +43 -141
- code_puppy/messaging/rich_renderer.py +900 -0
- code_puppy/messaging/spinner/console_spinner.py +39 -2
- code_puppy/model_factory.py +292 -53
- code_puppy/model_utils.py +57 -48
- code_puppy/models.json +19 -5
- code_puppy/plugins/__init__.py +152 -10
- code_puppy/plugins/chatgpt_oauth/config.py +20 -12
- code_puppy/plugins/chatgpt_oauth/oauth_flow.py +5 -6
- code_puppy/plugins/chatgpt_oauth/register_callbacks.py +3 -3
- code_puppy/plugins/chatgpt_oauth/test_plugin.py +30 -13
- code_puppy/plugins/chatgpt_oauth/utils.py +180 -65
- code_puppy/plugins/claude_code_oauth/config.py +15 -11
- code_puppy/plugins/claude_code_oauth/register_callbacks.py +28 -0
- code_puppy/plugins/claude_code_oauth/utils.py +6 -1
- code_puppy/plugins/example_custom_command/register_callbacks.py +2 -2
- code_puppy/plugins/oauth_puppy_html.py +3 -0
- code_puppy/plugins/shell_safety/agent_shell_safety.py +1 -134
- code_puppy/plugins/shell_safety/command_cache.py +156 -0
- code_puppy/plugins/shell_safety/register_callbacks.py +77 -3
- code_puppy/prompts/codex_system_prompt.md +310 -0
- code_puppy/pydantic_patches.py +131 -0
- code_puppy/session_storage.py +2 -1
- code_puppy/status_display.py +7 -5
- code_puppy/terminal_utils.py +126 -0
- code_puppy/tools/agent_tools.py +131 -70
- code_puppy/tools/browser/browser_control.py +10 -14
- code_puppy/tools/browser/browser_interactions.py +20 -28
- code_puppy/tools/browser/browser_locators.py +27 -29
- code_puppy/tools/browser/browser_navigation.py +9 -9
- code_puppy/tools/browser/browser_screenshot.py +12 -14
- code_puppy/tools/browser/browser_scripts.py +17 -29
- code_puppy/tools/browser/browser_workflows.py +24 -25
- code_puppy/tools/browser/camoufox_manager.py +22 -26
- code_puppy/tools/command_runner.py +410 -88
- code_puppy/tools/common.py +51 -38
- code_puppy/tools/file_modifications.py +98 -24
- code_puppy/tools/file_operations.py +113 -202
- code_puppy/version_checker.py +28 -13
- {code_puppy-0.0.287.data ā code_puppy-0.0.323.data}/data/code_puppy/models.json +19 -5
- {code_puppy-0.0.287.dist-info ā code_puppy-0.0.323.dist-info}/METADATA +3 -8
- code_puppy-0.0.323.dist-info/RECORD +168 -0
- code_puppy/tui_state.py +0 -55
- code_puppy-0.0.287.dist-info/RECORD +0 -153
- {code_puppy-0.0.287.data ā code_puppy-0.0.323.data}/data/code_puppy/models_dev_api.json +0 -0
- {code_puppy-0.0.287.dist-info ā code_puppy-0.0.323.dist-info}/WHEEL +0 -0
- {code_puppy-0.0.287.dist-info ā code_puppy-0.0.323.dist-info}/entry_points.txt +0 -0
- {code_puppy-0.0.287.dist-info ā code_puppy-0.0.323.dist-info}/licenses/LICENSE +0 -0
|
@@ -27,6 +27,8 @@ def get_commands_help():
|
|
|
27
27
|
)
|
|
28
28
|
def handle_show_command(command: str) -> bool:
|
|
29
29
|
"""Show current puppy configuration."""
|
|
30
|
+
from rich.text import Text
|
|
31
|
+
|
|
30
32
|
from code_puppy.agents import get_current_agent
|
|
31
33
|
from code_puppy.command_line.model_picker_completion import get_active_model
|
|
32
34
|
from code_puppy.config import (
|
|
@@ -79,14 +81,14 @@ def handle_show_command(command: str) -> bool:
|
|
|
79
81
|
[bold]temperature:[/bold] [cyan]{effective_temperature if effective_temperature is not None else "(model default)"}[/cyan]{" (per-model)" if effective_temperature != global_temperature and effective_temperature is not None else ""}
|
|
80
82
|
|
|
81
83
|
"""
|
|
82
|
-
emit_info(status_msg)
|
|
84
|
+
emit_info(Text.from_markup(status_msg))
|
|
83
85
|
return True
|
|
84
86
|
|
|
85
87
|
|
|
86
88
|
@register_command(
|
|
87
89
|
name="reasoning",
|
|
88
90
|
description="Set OpenAI reasoning effort for GPT-5 models (e.g., /reasoning high)",
|
|
89
|
-
usage="/reasoning <low|medium|high>",
|
|
91
|
+
usage="/reasoning <minimal|low|medium|high|xhigh>",
|
|
90
92
|
category="config",
|
|
91
93
|
)
|
|
92
94
|
def handle_reasoning_command(command: str) -> bool:
|
|
@@ -95,7 +97,7 @@ def handle_reasoning_command(command: str) -> bool:
|
|
|
95
97
|
|
|
96
98
|
tokens = command.split()
|
|
97
99
|
if len(tokens) != 2:
|
|
98
|
-
emit_warning("Usage: /reasoning <low|medium|high>")
|
|
100
|
+
emit_warning("Usage: /reasoning <minimal|low|medium|high|xhigh>")
|
|
99
101
|
return True
|
|
100
102
|
|
|
101
103
|
effort = tokens[1]
|
|
@@ -171,6 +173,8 @@ def handle_verbosity_command(command: str) -> bool:
|
|
|
171
173
|
)
|
|
172
174
|
def handle_set_command(command: str) -> bool:
|
|
173
175
|
"""Set configuration values."""
|
|
176
|
+
from rich.text import Text
|
|
177
|
+
|
|
174
178
|
from code_puppy.config import set_config_value
|
|
175
179
|
from code_puppy.messaging import emit_error, emit_info, emit_success, emit_warning
|
|
176
180
|
|
|
@@ -197,14 +201,18 @@ def handle_set_command(command: str) -> bool:
|
|
|
197
201
|
"\n [cyan]auto_save_session[/cyan] Auto-save chat after every response (true/false)"
|
|
198
202
|
)
|
|
199
203
|
emit_warning(
|
|
200
|
-
|
|
204
|
+
Text.from_markup(
|
|
205
|
+
f"Usage: /set KEY=VALUE or /set KEY VALUE\nConfig keys: {', '.join(config_keys)}\n[dim]Note: compaction_strategy can be 'summarization' or 'truncation'[/dim]{session_help}"
|
|
206
|
+
)
|
|
201
207
|
)
|
|
202
208
|
return True
|
|
203
209
|
if key:
|
|
204
210
|
# Check if we're toggling DBOS enablement
|
|
205
211
|
if key == "enable_dbos":
|
|
206
212
|
emit_info(
|
|
207
|
-
|
|
213
|
+
Text.from_markup(
|
|
214
|
+
"[yellow]ā ļø DBOS configuration changed. Please restart Code Puppy for this change to take effect.[/yellow]"
|
|
215
|
+
)
|
|
208
216
|
)
|
|
209
217
|
|
|
210
218
|
set_config_value(key, value)
|
|
@@ -216,7 +224,7 @@ def handle_set_command(command: str) -> bool:
|
|
|
216
224
|
try:
|
|
217
225
|
current_agent = get_current_agent()
|
|
218
226
|
current_agent.reload_code_generation_agent()
|
|
219
|
-
emit_info("
|
|
227
|
+
emit_info("Agent reloaded with updated config")
|
|
220
228
|
except Exception as reload_error:
|
|
221
229
|
emit_warning(f"Config saved but agent reload failed: {reload_error}")
|
|
222
230
|
else:
|
|
@@ -224,6 +232,23 @@ def handle_set_command(command: str) -> bool:
|
|
|
224
232
|
return True
|
|
225
233
|
|
|
226
234
|
|
|
235
|
+
def _get_json_agents_pinned_to_model(model_name: str) -> list:
|
|
236
|
+
"""Get JSON agents that have this model pinned in their JSON file."""
|
|
237
|
+
from code_puppy.agents.json_agent import discover_json_agents
|
|
238
|
+
|
|
239
|
+
pinned = []
|
|
240
|
+
json_agents = discover_json_agents()
|
|
241
|
+
for agent_name, agent_path in json_agents.items():
|
|
242
|
+
try:
|
|
243
|
+
with open(agent_path, "r") as f:
|
|
244
|
+
agent_data = json.load(f)
|
|
245
|
+
if agent_data.get("model") == model_name:
|
|
246
|
+
pinned.append(agent_name)
|
|
247
|
+
except Exception:
|
|
248
|
+
continue
|
|
249
|
+
return pinned
|
|
250
|
+
|
|
251
|
+
|
|
227
252
|
@register_command(
|
|
228
253
|
name="pin_model",
|
|
229
254
|
description="Pin a specific model to an agent",
|
|
@@ -252,17 +277,17 @@ def handle_pin_model_command(command: str) -> bool:
|
|
|
252
277
|
|
|
253
278
|
emit_info("Available models:")
|
|
254
279
|
for model in available_models:
|
|
255
|
-
emit_info(f"
|
|
280
|
+
emit_info(f" {model}")
|
|
256
281
|
|
|
257
282
|
if builtin_agents:
|
|
258
283
|
emit_info("\nAvailable built-in agents:")
|
|
259
284
|
for agent_name, description in builtin_agents.items():
|
|
260
|
-
emit_info(f"
|
|
285
|
+
emit_info(f" {agent_name} - {description}")
|
|
261
286
|
|
|
262
287
|
if json_agents:
|
|
263
288
|
emit_info("\nAvailable JSON agents:")
|
|
264
289
|
for agent_name, agent_path in json_agents.items():
|
|
265
|
-
emit_info(f"
|
|
290
|
+
emit_info(f" {agent_name} ({agent_path})")
|
|
266
291
|
return True
|
|
267
292
|
|
|
268
293
|
agent_name = tokens[1].lower()
|
|
@@ -298,12 +323,12 @@ def handle_pin_model_command(command: str) -> bool:
|
|
|
298
323
|
if builtin_agents:
|
|
299
324
|
emit_info("Available built-in agents:")
|
|
300
325
|
for name, desc in builtin_agents.items():
|
|
301
|
-
emit_info(f"
|
|
326
|
+
emit_info(f" {name} - {desc}")
|
|
302
327
|
|
|
303
328
|
if json_agents:
|
|
304
329
|
emit_info("\nAvailable JSON agents:")
|
|
305
330
|
for name, path in json_agents.items():
|
|
306
|
-
emit_info(f"
|
|
331
|
+
emit_info(f" {name} ({path})")
|
|
307
332
|
return True
|
|
308
333
|
|
|
309
334
|
# Handle different agent types
|
|
@@ -359,6 +384,7 @@ def handle_pin_model_command(command: str) -> bool:
|
|
|
359
384
|
def handle_unpin_command(command: str) -> bool:
|
|
360
385
|
"""Unpin a model from an agent (resets to default)."""
|
|
361
386
|
from code_puppy.agents.json_agent import discover_json_agents
|
|
387
|
+
from code_puppy.config import get_agent_pinned_model
|
|
362
388
|
from code_puppy.messaging import emit_error, emit_info, emit_success, emit_warning
|
|
363
389
|
|
|
364
390
|
tokens = command.split()
|
|
@@ -377,12 +403,26 @@ def handle_unpin_command(command: str) -> bool:
|
|
|
377
403
|
if builtin_agents:
|
|
378
404
|
emit_info("Available built-in agents:")
|
|
379
405
|
for agent_name, description in builtin_agents.items():
|
|
380
|
-
|
|
406
|
+
pinned_model = get_agent_pinned_model(agent_name)
|
|
407
|
+
if pinned_model:
|
|
408
|
+
emit_info(f" {agent_name} - {description} [ā {pinned_model}]")
|
|
409
|
+
else:
|
|
410
|
+
emit_info(f" {agent_name} - {description}")
|
|
381
411
|
|
|
382
412
|
if json_agents:
|
|
383
413
|
emit_info("\nAvailable JSON agents:")
|
|
384
414
|
for agent_name, agent_path in json_agents.items():
|
|
385
|
-
|
|
415
|
+
# Read the JSON file to check for pinned model
|
|
416
|
+
try:
|
|
417
|
+
with open(agent_path, "r") as f:
|
|
418
|
+
agent_config = json.load(f)
|
|
419
|
+
pinned_model = agent_config.get("model")
|
|
420
|
+
if pinned_model:
|
|
421
|
+
emit_info(f" {agent_name} ({agent_path}) [ā {pinned_model}]")
|
|
422
|
+
else:
|
|
423
|
+
emit_info(f" {agent_name} ({agent_path})")
|
|
424
|
+
except Exception:
|
|
425
|
+
emit_info(f" {agent_name} ({agent_path})")
|
|
386
426
|
return True
|
|
387
427
|
|
|
388
428
|
agent_name_input = tokens[1].lower()
|
|
@@ -422,12 +462,12 @@ def handle_unpin_command(command: str) -> bool:
|
|
|
422
462
|
if builtin_agents:
|
|
423
463
|
emit_info("Available built-in agents:")
|
|
424
464
|
for name, desc in builtin_agents.items():
|
|
425
|
-
emit_info(f"
|
|
465
|
+
emit_info(f" {name} - {desc}")
|
|
426
466
|
|
|
427
467
|
if json_agents:
|
|
428
468
|
emit_info("\nAvailable JSON agents:")
|
|
429
469
|
for name, path in json_agents.items():
|
|
430
|
-
emit_info(f"
|
|
470
|
+
emit_info(f" {name} ({path})")
|
|
431
471
|
return True
|
|
432
472
|
|
|
433
473
|
try:
|
|
@@ -507,6 +547,37 @@ def handle_diff_command(command: str) -> bool:
|
|
|
507
547
|
return True
|
|
508
548
|
|
|
509
549
|
|
|
550
|
+
@register_command(
|
|
551
|
+
name="colors",
|
|
552
|
+
description="Configure banner colors for tool outputs (THINKING, SHELL COMMAND, etc.)",
|
|
553
|
+
usage="/colors",
|
|
554
|
+
category="config",
|
|
555
|
+
)
|
|
556
|
+
def handle_colors_command(command: str) -> bool:
|
|
557
|
+
"""Configure banner colors via interactive TUI."""
|
|
558
|
+
import asyncio
|
|
559
|
+
import concurrent.futures
|
|
560
|
+
|
|
561
|
+
from code_puppy.command_line.colors_menu import interactive_colors_picker
|
|
562
|
+
from code_puppy.config import set_banner_color
|
|
563
|
+
from code_puppy.messaging import emit_error, emit_success
|
|
564
|
+
|
|
565
|
+
# Show interactive picker for banner color configuration
|
|
566
|
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
|
567
|
+
future = executor.submit(lambda: asyncio.run(interactive_colors_picker()))
|
|
568
|
+
result = future.result(timeout=300) # 5 min timeout
|
|
569
|
+
|
|
570
|
+
if result:
|
|
571
|
+
# Apply the changes
|
|
572
|
+
try:
|
|
573
|
+
for banner_name, color in result.items():
|
|
574
|
+
set_banner_color(banner_name, color)
|
|
575
|
+
emit_success("Banner colors saved! šØ")
|
|
576
|
+
except Exception as e:
|
|
577
|
+
emit_error(f"Failed to apply banner color settings: {e}")
|
|
578
|
+
return True
|
|
579
|
+
|
|
580
|
+
|
|
510
581
|
# ============================================================================
|
|
511
582
|
# UTILITY FUNCTIONS
|
|
512
583
|
# ============================================================================
|
|
@@ -518,6 +589,8 @@ def _show_color_options(color_type: str):
|
|
|
518
589
|
# ============================================================================
|
|
519
590
|
|
|
520
591
|
"""Show available Rich color options organized by category."""
|
|
592
|
+
from rich.text import Text
|
|
593
|
+
|
|
521
594
|
from code_puppy.messaging import emit_info
|
|
522
595
|
|
|
523
596
|
# Standard Rich colors organized by category
|
|
@@ -575,11 +648,15 @@ def _show_color_options(color_type: str):
|
|
|
575
648
|
("sea_green1", "š¢"),
|
|
576
649
|
]
|
|
577
650
|
emit_info(
|
|
578
|
-
|
|
651
|
+
Text.from_markup(
|
|
652
|
+
"[bold white on green]šØ Recommended Colors for Additions:[/bold white on green]"
|
|
653
|
+
)
|
|
579
654
|
)
|
|
580
655
|
for color, emoji in suggestions:
|
|
581
656
|
emit_info(
|
|
582
|
-
|
|
657
|
+
Text.from_markup(
|
|
658
|
+
f" [cyan]{color:<16}[/cyan] [white on {color}]ā ā ā ā ā ā ā ā ā ā [/white on {color}] {emoji}"
|
|
659
|
+
)
|
|
583
660
|
)
|
|
584
661
|
elif color_type == "deletions":
|
|
585
662
|
suggestions = [
|
|
@@ -590,22 +667,26 @@ def _show_color_options(color_type: str):
|
|
|
590
667
|
("dark_red", "š“"),
|
|
591
668
|
]
|
|
592
669
|
emit_info(
|
|
593
|
-
|
|
670
|
+
Text.from_markup(
|
|
671
|
+
"[bold white on orange1]šØ Recommended Colors for Deletions:[/bold white on orange1]"
|
|
672
|
+
)
|
|
594
673
|
)
|
|
595
674
|
for color, emoji in suggestions:
|
|
596
675
|
emit_info(
|
|
597
|
-
|
|
676
|
+
Text.from_markup(
|
|
677
|
+
f" [cyan]{color:<16}[/cyan] [white on {color}]ā ā ā ā ā ā ā ā ā ā [/white on {color}] {emoji}"
|
|
678
|
+
)
|
|
598
679
|
)
|
|
599
680
|
|
|
600
|
-
emit_info("\n
|
|
681
|
+
emit_info("\nšØ All Available Rich Colors:")
|
|
601
682
|
for category, colors in color_categories.items():
|
|
602
|
-
emit_info(f"\n
|
|
683
|
+
emit_info(f"\n{category}:")
|
|
603
684
|
# Display in columns for better readability
|
|
604
685
|
for i in range(0, len(colors), 4):
|
|
605
686
|
row = colors[i : i + 4]
|
|
606
687
|
row_text = " ".join([f"[{color}]ā [/{color}] {color}" for color, _ in row])
|
|
607
|
-
emit_info(f" {row_text}")
|
|
688
|
+
emit_info(Text.from_markup(f" {row_text}"))
|
|
608
689
|
|
|
609
|
-
emit_info("\
|
|
610
|
-
emit_info("
|
|
611
|
-
emit_info("
|
|
690
|
+
emit_info("\nUsage: /diff {color_type} <color_name>")
|
|
691
|
+
emit_info("All diffs use white text on your chosen background colors")
|
|
692
|
+
emit_info("You can also use hex colors like #ff0000 or rgb(255,0,0)")
|
|
@@ -145,6 +145,8 @@ def handle_exit_command(command: str) -> bool:
|
|
|
145
145
|
)
|
|
146
146
|
def handle_agent_command(command: str) -> bool:
|
|
147
147
|
"""Handle agent switching."""
|
|
148
|
+
from rich.text import Text
|
|
149
|
+
|
|
148
150
|
from code_puppy.agents import (
|
|
149
151
|
get_agent_descriptions,
|
|
150
152
|
get_available_agents,
|
|
@@ -199,9 +201,11 @@ def handle_agent_command(command: str) -> bool:
|
|
|
199
201
|
f"Switched to agent: {new_agent.display_name}",
|
|
200
202
|
message_group=group_id,
|
|
201
203
|
)
|
|
202
|
-
emit_info(f"
|
|
204
|
+
emit_info(f"{new_agent.description}", message_group=group_id)
|
|
203
205
|
emit_info(
|
|
204
|
-
|
|
206
|
+
Text.from_markup(
|
|
207
|
+
f"[dim]Auto-save session rotated to: {new_session_id}[/dim]"
|
|
208
|
+
),
|
|
205
209
|
message_group=group_id,
|
|
206
210
|
)
|
|
207
211
|
else:
|
|
@@ -224,15 +228,19 @@ def handle_agent_command(command: str) -> bool:
|
|
|
224
228
|
group_id = str(uuid.uuid4())
|
|
225
229
|
|
|
226
230
|
emit_info(
|
|
227
|
-
|
|
231
|
+
Text.from_markup(
|
|
232
|
+
f"[bold green]Current Agent:[/bold green] {current_agent.display_name}"
|
|
233
|
+
),
|
|
228
234
|
message_group=group_id,
|
|
229
235
|
)
|
|
230
236
|
emit_info(
|
|
231
|
-
f"[dim]{current_agent.description}[/dim]\n",
|
|
237
|
+
Text.from_markup(f"[dim]{current_agent.description}[/dim]\n"),
|
|
238
|
+
message_group=group_id,
|
|
232
239
|
)
|
|
233
240
|
|
|
234
241
|
emit_info(
|
|
235
|
-
"[bold magenta]Available Agents:[/bold magenta]",
|
|
242
|
+
Text.from_markup("[bold magenta]Available Agents:[/bold magenta]"),
|
|
243
|
+
message_group=group_id,
|
|
236
244
|
)
|
|
237
245
|
for name, display_name in available_agents.items():
|
|
238
246
|
description = descriptions.get(name, "No description")
|
|
@@ -240,13 +248,15 @@ def handle_agent_command(command: str) -> bool:
|
|
|
240
248
|
" [green]ā current[/green]" if name == current_agent.name else ""
|
|
241
249
|
)
|
|
242
250
|
emit_info(
|
|
243
|
-
|
|
251
|
+
Text.from_markup(
|
|
252
|
+
f" [cyan]{name:<12}[/cyan] {display_name}{current_marker}"
|
|
253
|
+
),
|
|
244
254
|
message_group=group_id,
|
|
245
255
|
)
|
|
246
|
-
emit_info(f"
|
|
256
|
+
emit_info(f" {description}", message_group=group_id)
|
|
247
257
|
|
|
248
258
|
emit_info(
|
|
249
|
-
"\n[yellow]Usage:[/yellow] /agent <agent-name>",
|
|
259
|
+
Text.from_markup("\n[yellow]Usage:[/yellow] /agent <agent-name>"),
|
|
250
260
|
message_group=group_id,
|
|
251
261
|
)
|
|
252
262
|
return True
|
|
@@ -290,9 +300,11 @@ def handle_agent_command(command: str) -> bool:
|
|
|
290
300
|
f"Switched to agent: {new_agent.display_name}",
|
|
291
301
|
message_group=group_id,
|
|
292
302
|
)
|
|
293
|
-
emit_info(f"
|
|
303
|
+
emit_info(f"{new_agent.description}", message_group=group_id)
|
|
294
304
|
emit_info(
|
|
295
|
-
|
|
305
|
+
Text.from_markup(
|
|
306
|
+
f"[dim]Auto-save session rotated to: {new_session_id}[/dim]"
|
|
307
|
+
),
|
|
296
308
|
message_group=group_id,
|
|
297
309
|
)
|
|
298
310
|
return True
|
|
@@ -366,10 +378,10 @@ async def interactive_agent_picker() -> str | None:
|
|
|
366
378
|
set_awaiting_user_input(True)
|
|
367
379
|
time.sleep(0.3) # Let spinners fully stop
|
|
368
380
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
381
|
+
local_console = Console()
|
|
382
|
+
emit_info("")
|
|
383
|
+
local_console.print(panel)
|
|
384
|
+
emit_info("")
|
|
373
385
|
|
|
374
386
|
# Flush output before prompt_toolkit takes control
|
|
375
387
|
sys.stdout.flush()
|
|
@@ -401,7 +413,7 @@ async def interactive_agent_picker() -> str | None:
|
|
|
401
413
|
selected_agent = agent_name
|
|
402
414
|
|
|
403
415
|
except (KeyboardInterrupt, EOFError):
|
|
404
|
-
|
|
416
|
+
emit_error("Cancelled by user")
|
|
405
417
|
selected_agent = None
|
|
406
418
|
|
|
407
419
|
finally:
|
|
@@ -460,10 +472,10 @@ async def interactive_model_picker() -> str | None:
|
|
|
460
472
|
set_awaiting_user_input(True)
|
|
461
473
|
time.sleep(0.3) # Let spinners fully stop
|
|
462
474
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
475
|
+
local_console = Console()
|
|
476
|
+
emit_info("")
|
|
477
|
+
local_console.print(panel)
|
|
478
|
+
emit_info("")
|
|
467
479
|
|
|
468
480
|
# Flush output before prompt_toolkit takes control
|
|
469
481
|
sys.stdout.flush()
|
|
@@ -490,7 +502,7 @@ async def interactive_model_picker() -> str | None:
|
|
|
490
502
|
selected_model = selected_model[:-10].strip()
|
|
491
503
|
|
|
492
504
|
except (KeyboardInterrupt, EOFError):
|
|
493
|
-
|
|
505
|
+
emit_error("Cancelled by user")
|
|
494
506
|
selected_model = None
|
|
495
507
|
|
|
496
508
|
finally:
|
|
@@ -7,8 +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
|
|
11
|
-
from code_puppy.tui_state import is_tui_mode
|
|
10
|
+
from code_puppy.messaging import emit_error, emit_info
|
|
12
11
|
|
|
13
12
|
from .base import MCPCommandBase
|
|
14
13
|
from .wizard_utils import run_interactive_install_wizard
|
|
@@ -42,18 +41,6 @@ class AddCommand(MCPCommandBase):
|
|
|
42
41
|
if group_id is None:
|
|
43
42
|
group_id = self.generate_group_id()
|
|
44
43
|
|
|
45
|
-
# Check if in TUI mode and guide user to use Ctrl+T instead
|
|
46
|
-
if is_tui_mode() and not args:
|
|
47
|
-
emit_info(
|
|
48
|
-
"š” In TUI mode, press Ctrl+T to open the MCP Install Wizard",
|
|
49
|
-
message_group=group_id,
|
|
50
|
-
)
|
|
51
|
-
emit_info(
|
|
52
|
-
" The wizard provides a better interface for browsing and installing MCP servers.",
|
|
53
|
-
message_group=group_id,
|
|
54
|
-
)
|
|
55
|
-
return
|
|
56
|
-
|
|
57
44
|
try:
|
|
58
45
|
if args:
|
|
59
46
|
# Parse JSON from arguments
|
|
@@ -115,7 +102,7 @@ class AddCommand(MCPCommandBase):
|
|
|
115
102
|
emit_info("Required module not available", message_group=group_id)
|
|
116
103
|
except Exception as e:
|
|
117
104
|
logger.error(f"Error in add command: {e}")
|
|
118
|
-
|
|
105
|
+
emit_error(f"Error adding server: {e}", message_group=group_id)
|
|
119
106
|
|
|
120
107
|
def _add_server_from_json(self, config_dict: dict, group_id: str) -> bool:
|
|
121
108
|
"""
|
|
@@ -179,5 +166,5 @@ class AddCommand(MCPCommandBase):
|
|
|
179
166
|
|
|
180
167
|
except Exception as e:
|
|
181
168
|
logger.error(f"Error adding server from JSON: {e}")
|
|
182
|
-
|
|
169
|
+
emit_error(f"Failed to add server: {e}", message_group=group_id)
|
|
183
170
|
return False
|
|
@@ -6,8 +6,6 @@ Provides base classes and common utilities used across all MCP command modules.
|
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
8
|
|
|
9
|
-
from rich.console import Console
|
|
10
|
-
|
|
11
9
|
from code_puppy.mcp_.manager import get_mcp_manager
|
|
12
10
|
|
|
13
11
|
# Configure logging
|
|
@@ -24,7 +22,6 @@ class MCPCommandBase:
|
|
|
24
22
|
|
|
25
23
|
def __init__(self):
|
|
26
24
|
"""Initialize the base command handler."""
|
|
27
|
-
self.console = Console()
|
|
28
25
|
self.manager = get_mcp_manager()
|
|
29
26
|
logger.debug(f"Initialized {self.__class__.__name__}")
|
|
30
27
|
|
|
@@ -7,7 +7,7 @@ MCP servers from the catalog.
|
|
|
7
7
|
import os
|
|
8
8
|
from typing import Dict, Optional
|
|
9
9
|
|
|
10
|
-
from code_puppy.messaging import emit_warning
|
|
10
|
+
from code_puppy.messaging import emit_info, emit_success, emit_warning
|
|
11
11
|
|
|
12
12
|
# Helpful hints for common environment variables
|
|
13
13
|
ENV_VAR_HINTS = {
|
|
@@ -46,8 +46,8 @@ def prompt_for_server_config(manager, server) -> Optional[Dict]:
|
|
|
46
46
|
|
|
47
47
|
from .utils import find_server_id_by_name
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
emit_info(f"\nš¦ Installing: {server.display_name}\n")
|
|
50
|
+
emit_info(f" {server.description}\n")
|
|
51
51
|
|
|
52
52
|
# Get custom name
|
|
53
53
|
default_name = server.name
|
|
@@ -55,7 +55,7 @@ def prompt_for_server_config(manager, server) -> Optional[Dict]:
|
|
|
55
55
|
name_input = input(f" Server name [{default_name}]: ").strip()
|
|
56
56
|
server_name = name_input if name_input else default_name
|
|
57
57
|
except (KeyboardInterrupt, EOFError):
|
|
58
|
-
|
|
58
|
+
emit_info("")
|
|
59
59
|
emit_warning("Installation cancelled")
|
|
60
60
|
return None
|
|
61
61
|
|
|
@@ -70,7 +70,7 @@ def prompt_for_server_config(manager, server) -> Optional[Dict]:
|
|
|
70
70
|
emit_warning("Installation cancelled")
|
|
71
71
|
return None
|
|
72
72
|
except (KeyboardInterrupt, EOFError):
|
|
73
|
-
|
|
73
|
+
emit_info("")
|
|
74
74
|
emit_warning("Installation cancelled")
|
|
75
75
|
return None
|
|
76
76
|
|
|
@@ -80,17 +80,17 @@ def prompt_for_server_config(manager, server) -> Optional[Dict]:
|
|
|
80
80
|
# Collect environment variables
|
|
81
81
|
required_env_vars = server.get_environment_vars()
|
|
82
82
|
if required_env_vars:
|
|
83
|
-
|
|
83
|
+
emit_info("\n š Environment Variables:")
|
|
84
84
|
for var in required_env_vars:
|
|
85
85
|
current_value = os.environ.get(var, "")
|
|
86
86
|
if current_value:
|
|
87
|
-
|
|
87
|
+
emit_info(f" ā {var}: Already set")
|
|
88
88
|
env_vars[var] = current_value
|
|
89
89
|
else:
|
|
90
90
|
try:
|
|
91
91
|
hint = get_env_var_hint(var)
|
|
92
92
|
if hint:
|
|
93
|
-
|
|
93
|
+
emit_info(f" {hint}")
|
|
94
94
|
value = input(f" Enter {var}: ").strip()
|
|
95
95
|
if value:
|
|
96
96
|
env_vars[var] = value
|
|
@@ -98,14 +98,14 @@ def prompt_for_server_config(manager, server) -> Optional[Dict]:
|
|
|
98
98
|
set_config_value(var, value)
|
|
99
99
|
os.environ[var] = value
|
|
100
100
|
except (KeyboardInterrupt, EOFError):
|
|
101
|
-
|
|
101
|
+
emit_info("")
|
|
102
102
|
emit_warning("Installation cancelled")
|
|
103
103
|
return None
|
|
104
104
|
|
|
105
105
|
# Collect command line arguments
|
|
106
106
|
required_cmd_args = server.get_command_line_args()
|
|
107
107
|
if required_cmd_args:
|
|
108
|
-
|
|
108
|
+
emit_info("\n āļø Configuration:")
|
|
109
109
|
for arg_config in required_cmd_args:
|
|
110
110
|
name = arg_config.get("name", "")
|
|
111
111
|
prompt_text = arg_config.get("prompt", name)
|
|
@@ -128,7 +128,7 @@ def prompt_for_server_config(manager, server) -> Optional[Dict]:
|
|
|
128
128
|
emit_warning(f"Required value '{name}' not provided")
|
|
129
129
|
return None
|
|
130
130
|
except (KeyboardInterrupt, EOFError):
|
|
131
|
-
|
|
131
|
+
emit_info("")
|
|
132
132
|
emit_warning("Installation cancelled")
|
|
133
133
|
return None
|
|
134
134
|
|
|
@@ -161,16 +161,16 @@ def install_catalog_server(manager, server, config: Dict) -> bool:
|
|
|
161
161
|
# Generate a group ID for messages
|
|
162
162
|
group_id = f"mcp-install-{uuid.uuid4().hex[:8]}"
|
|
163
163
|
|
|
164
|
-
|
|
164
|
+
emit_info(f"\n š¦ Installing {server.display_name} as '{server_name}'...")
|
|
165
165
|
|
|
166
166
|
success = install_server_from_catalog(
|
|
167
167
|
manager, server, server_name, env_vars, cmd_args, group_id
|
|
168
168
|
)
|
|
169
169
|
|
|
170
170
|
if success:
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
emit_success(f"\n ā
Successfully installed '{server_name}'!")
|
|
172
|
+
emit_info(f" Use '/mcp start {server_name}' to start the server.\n")
|
|
173
173
|
else:
|
|
174
|
-
|
|
174
|
+
emit_warning("\n ā Installation failed.\n")
|
|
175
175
|
|
|
176
176
|
return success
|