code-puppy 0.0.214__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 +2 -0
- code_puppy/agents/agent_c_reviewer.py +59 -6
- code_puppy/agents/agent_code_puppy.py +7 -1
- code_puppy/agents/agent_code_reviewer.py +12 -2
- code_puppy/agents/agent_cpp_reviewer.py +73 -6
- code_puppy/agents/agent_creator_agent.py +45 -4
- code_puppy/agents/agent_golang_reviewer.py +92 -3
- code_puppy/agents/agent_javascript_reviewer.py +101 -8
- code_puppy/agents/agent_manager.py +81 -4
- 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 +28 -6
- code_puppy/agents/agent_qa_expert.py +98 -6
- code_puppy/agents/agent_qa_kitten.py +12 -7
- code_puppy/agents/agent_security_auditor.py +113 -3
- code_puppy/agents/agent_terminal_qa.py +323 -0
- code_puppy/agents/agent_typescript_reviewer.py +106 -7
- code_puppy/agents/base_agent.py +802 -176
- code_puppy/agents/event_stream_handler.py +350 -0
- 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 +142 -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 +10 -5
- 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 +176 -738
- 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 +0 -3
- 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 +15 -26
- code_puppy/command_line/mcp/install_menu.py +685 -0
- 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 +12 -4
- code_puppy/command_line/mcp/search_command.py +16 -10
- code_puppy/command_line/mcp/start_all_command.py +18 -6
- code_puppy/command_line/mcp/start_command.py +47 -25
- code_puppy/command_line/mcp/status_command.py +4 -5
- code_puppy/command_line/mcp/stop_all_command.py +7 -1
- code_puppy/command_line/mcp/stop_command.py +8 -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/mcp_completion.py +174 -0
- code_puppy/command_line/model_picker_completion.py +75 -25
- 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 +463 -63
- code_puppy/command_line/session_commands.py +296 -0
- code_puppy/command_line/utils.py +54 -0
- code_puppy/config.py +898 -112
- 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 +210 -148
- code_puppy/keymap.py +128 -0
- code_puppy/main.py +5 -698
- code_puppy/mcp_/__init__.py +17 -0
- code_puppy/mcp_/async_lifecycle.py +35 -4
- code_puppy/mcp_/blocking_startup.py +70 -43
- code_puppy/mcp_/captured_stdio_server.py +2 -2
- code_puppy/mcp_/config_wizard.py +4 -4
- code_puppy/mcp_/dashboard.py +15 -6
- code_puppy/mcp_/managed_server.py +65 -38
- code_puppy/mcp_/manager.py +146 -52
- code_puppy/mcp_/mcp_logs.py +224 -0
- code_puppy/mcp_/registry.py +6 -6
- code_puppy/mcp_/server_registry_catalog.py +24 -5
- 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 +21 -5
- code_puppy/messaging/spinner/console_spinner.py +86 -51
- code_puppy/messaging/subagent_console.py +461 -0
- code_puppy/model_factory.py +634 -83
- code_puppy/model_utils.py +167 -0
- code_puppy/models.json +66 -68
- 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 +2 -2
- 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 +9 -12
- code_puppy/session_storage.py +2 -1
- code_puppy/status_display.py +21 -4
- code_puppy/summarization_agent.py +41 -13
- code_puppy/terminal_utils.py +418 -0
- code_puppy/tools/__init__.py +37 -1
- code_puppy/tools/agent_tools.py +536 -52
- code_puppy/tools/browser/__init__.py +37 -0
- code_puppy/tools/browser/browser_control.py +19 -23
- code_puppy/tools/browser/browser_interactions.py +41 -48
- code_puppy/tools/browser/browser_locators.py +36 -38
- code_puppy/tools/browser/browser_manager.py +316 -0
- code_puppy/tools/browser/browser_navigation.py +16 -16
- code_puppy/tools/browser/browser_screenshot.py +79 -143
- code_puppy/tools/browser/browser_scripts.py +32 -42
- code_puppy/tools/browser/browser_workflows.py +44 -27
- 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 +930 -147
- code_puppy/tools/common.py +1113 -5
- code_puppy/tools/display.py +84 -0
- code_puppy/tools/file_modifications.py +288 -89
- code_puppy/tools/file_operations.py +226 -154
- 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.214.dist-info ā code_puppy-0.0.366.dist-info}/METADATA +149 -75
- code_puppy-0.0.366.dist-info/RECORD +217 -0
- {code_puppy-0.0.214.dist-info ā code_puppy-0.0.366.dist-info}/WHEEL +1 -1
- code_puppy/command_line/mcp/add_command.py +0 -183
- code_puppy/messaging/spinner/textual_spinner.py +0 -106
- code_puppy/tools/browser/camoufox_manager.py +0 -216
- code_puppy/tools/browser/vqa_agent.py +0 -70
- code_puppy/tui/__init__.py +0 -10
- code_puppy/tui/app.py +0 -1105
- code_puppy/tui/components/__init__.py +0 -21
- code_puppy/tui/components/chat_view.py +0 -551
- 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 -185
- 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 -17
- code_puppy/tui/screens/autosave_picker.py +0 -175
- 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 -306
- code_puppy/tui/screens/tools.py +0 -74
- code_puppy/tui_state.py +0 -55
- code_puppy-0.0.214.data/data/code_puppy/models.json +0 -112
- code_puppy-0.0.214.dist-info/RECORD +0 -131
- {code_puppy-0.0.214.dist-info ā code_puppy-0.0.366.dist-info}/entry_points.txt +0 -0
- {code_puppy-0.0.214.dist-info ā code_puppy-0.0.366.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
"""Command handlers for Code Puppy - CONFIG commands.
|
|
2
|
+
|
|
3
|
+
This module contains @register_command decorated handlers that are automatically
|
|
4
|
+
discovered by the command registry system.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
from code_puppy.command_line.command_registry import register_command
|
|
10
|
+
from code_puppy.config import get_config_keys
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Import get_commands_help from command_handler to avoid circular imports
|
|
14
|
+
# This will be defined in command_handler.py
|
|
15
|
+
def get_commands_help():
|
|
16
|
+
"""Lazy import to avoid circular dependency."""
|
|
17
|
+
from code_puppy.command_line.command_handler import get_commands_help as _gch
|
|
18
|
+
|
|
19
|
+
return _gch()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@register_command(
|
|
23
|
+
name="show",
|
|
24
|
+
description="Show puppy config key-values",
|
|
25
|
+
usage="/show",
|
|
26
|
+
category="config",
|
|
27
|
+
)
|
|
28
|
+
def handle_show_command(command: str) -> bool:
|
|
29
|
+
"""Show current puppy configuration."""
|
|
30
|
+
from rich.text import Text
|
|
31
|
+
|
|
32
|
+
from code_puppy.agents import get_current_agent
|
|
33
|
+
from code_puppy.command_line.model_picker_completion import get_active_model
|
|
34
|
+
from code_puppy.config import (
|
|
35
|
+
get_auto_save_session,
|
|
36
|
+
get_compaction_strategy,
|
|
37
|
+
get_compaction_threshold,
|
|
38
|
+
get_default_agent,
|
|
39
|
+
get_effective_temperature,
|
|
40
|
+
get_openai_reasoning_effort,
|
|
41
|
+
get_openai_verbosity,
|
|
42
|
+
get_owner_name,
|
|
43
|
+
get_protected_token_count,
|
|
44
|
+
get_puppy_name,
|
|
45
|
+
get_temperature,
|
|
46
|
+
get_use_dbos,
|
|
47
|
+
get_yolo_mode,
|
|
48
|
+
)
|
|
49
|
+
from code_puppy.keymap import get_cancel_agent_display_name
|
|
50
|
+
from code_puppy.messaging import emit_info
|
|
51
|
+
|
|
52
|
+
puppy_name = get_puppy_name()
|
|
53
|
+
owner_name = get_owner_name()
|
|
54
|
+
model = get_active_model()
|
|
55
|
+
yolo_mode = get_yolo_mode()
|
|
56
|
+
auto_save = get_auto_save_session()
|
|
57
|
+
protected_tokens = get_protected_token_count()
|
|
58
|
+
compaction_threshold = get_compaction_threshold()
|
|
59
|
+
compaction_strategy = get_compaction_strategy()
|
|
60
|
+
global_temperature = get_temperature()
|
|
61
|
+
effective_temperature = get_effective_temperature(model)
|
|
62
|
+
|
|
63
|
+
# Get current agent info
|
|
64
|
+
current_agent = get_current_agent()
|
|
65
|
+
default_agent = get_default_agent()
|
|
66
|
+
|
|
67
|
+
status_msg = f"""[bold magenta]š¶ Puppy Status[/bold magenta]
|
|
68
|
+
|
|
69
|
+
[bold]puppy_name:[/bold] [cyan]{puppy_name}[/cyan]
|
|
70
|
+
[bold]owner_name:[/bold] [cyan]{owner_name}[/cyan]
|
|
71
|
+
[bold]current_agent:[/bold] [magenta]{current_agent.display_name}[/magenta]
|
|
72
|
+
[bold]default_agent:[/bold] [cyan]{default_agent}[/cyan]
|
|
73
|
+
[bold]model:[/bold] [green]{model}[/green]
|
|
74
|
+
[bold]YOLO_MODE:[/bold] {"[red]ON[/red]" if yolo_mode else "[yellow]off[/yellow]"}
|
|
75
|
+
[bold]DBOS:[/bold] {"[green]enabled[/green]" if get_use_dbos() else "[yellow]disabled[/yellow]"} (toggle: /set enable_dbos true|false)
|
|
76
|
+
[bold]auto_save_session:[/bold] {"[green]enabled[/green]" if auto_save else "[yellow]disabled[/yellow]"}
|
|
77
|
+
[bold]protected_tokens:[/bold] [cyan]{protected_tokens:,}[/cyan] recent tokens preserved
|
|
78
|
+
[bold]compaction_threshold:[/bold] [cyan]{compaction_threshold:.1%}[/cyan] context usage triggers compaction
|
|
79
|
+
[bold]compaction_strategy:[/bold] [cyan]{compaction_strategy}[/cyan] (summarization or truncation)
|
|
80
|
+
[bold]reasoning_effort:[/bold] [cyan]{get_openai_reasoning_effort()}[/cyan]
|
|
81
|
+
[bold]verbosity:[/bold] [cyan]{get_openai_verbosity()}[/cyan]
|
|
82
|
+
[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 ""}
|
|
83
|
+
[bold]cancel_agent_key:[/bold] [cyan]{get_cancel_agent_display_name()}[/cyan] (options: ctrl+c, ctrl+k, ctrl+q)
|
|
84
|
+
|
|
85
|
+
"""
|
|
86
|
+
emit_info(Text.from_markup(status_msg))
|
|
87
|
+
return True
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@register_command(
|
|
91
|
+
name="reasoning",
|
|
92
|
+
description="Set OpenAI reasoning effort for GPT-5 models (e.g., /reasoning high)",
|
|
93
|
+
usage="/reasoning <minimal|low|medium|high|xhigh>",
|
|
94
|
+
category="config",
|
|
95
|
+
)
|
|
96
|
+
def handle_reasoning_command(command: str) -> bool:
|
|
97
|
+
"""Set OpenAI reasoning effort level."""
|
|
98
|
+
from code_puppy.messaging import emit_error, emit_success, emit_warning
|
|
99
|
+
|
|
100
|
+
tokens = command.split()
|
|
101
|
+
if len(tokens) != 2:
|
|
102
|
+
emit_warning("Usage: /reasoning <minimal|low|medium|high|xhigh>")
|
|
103
|
+
return True
|
|
104
|
+
|
|
105
|
+
effort = tokens[1]
|
|
106
|
+
try:
|
|
107
|
+
from code_puppy.config import set_openai_reasoning_effort
|
|
108
|
+
|
|
109
|
+
set_openai_reasoning_effort(effort)
|
|
110
|
+
except ValueError as exc:
|
|
111
|
+
emit_error(str(exc))
|
|
112
|
+
return True
|
|
113
|
+
|
|
114
|
+
from code_puppy.config import get_openai_reasoning_effort
|
|
115
|
+
|
|
116
|
+
normalized_effort = get_openai_reasoning_effort()
|
|
117
|
+
|
|
118
|
+
from code_puppy.agents.agent_manager import get_current_agent
|
|
119
|
+
|
|
120
|
+
agent = get_current_agent()
|
|
121
|
+
agent.reload_code_generation_agent()
|
|
122
|
+
emit_success(
|
|
123
|
+
f"Reasoning effort set to '{normalized_effort}' and active agent reloaded"
|
|
124
|
+
)
|
|
125
|
+
return True
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@register_command(
|
|
129
|
+
name="verbosity",
|
|
130
|
+
description="Set OpenAI verbosity for GPT-5 models (e.g., /verbosity high)",
|
|
131
|
+
usage="/verbosity <low|medium|high>",
|
|
132
|
+
category="config",
|
|
133
|
+
)
|
|
134
|
+
def handle_verbosity_command(command: str) -> bool:
|
|
135
|
+
"""Set OpenAI verbosity level.
|
|
136
|
+
|
|
137
|
+
Controls how concise vs. verbose the model's responses are:
|
|
138
|
+
- low: more concise responses
|
|
139
|
+
- medium: balanced (default)
|
|
140
|
+
- high: more verbose responses
|
|
141
|
+
"""
|
|
142
|
+
from code_puppy.messaging import emit_error, emit_success, emit_warning
|
|
143
|
+
|
|
144
|
+
tokens = command.split()
|
|
145
|
+
if len(tokens) != 2:
|
|
146
|
+
emit_warning("Usage: /verbosity <low|medium|high>")
|
|
147
|
+
return True
|
|
148
|
+
|
|
149
|
+
verbosity = tokens[1]
|
|
150
|
+
try:
|
|
151
|
+
from code_puppy.config import set_openai_verbosity
|
|
152
|
+
|
|
153
|
+
set_openai_verbosity(verbosity)
|
|
154
|
+
except ValueError as exc:
|
|
155
|
+
emit_error(str(exc))
|
|
156
|
+
return True
|
|
157
|
+
|
|
158
|
+
from code_puppy.config import get_openai_verbosity
|
|
159
|
+
|
|
160
|
+
normalized_verbosity = get_openai_verbosity()
|
|
161
|
+
|
|
162
|
+
from code_puppy.agents.agent_manager import get_current_agent
|
|
163
|
+
|
|
164
|
+
agent = get_current_agent()
|
|
165
|
+
agent.reload_code_generation_agent()
|
|
166
|
+
emit_success(f"Verbosity set to '{normalized_verbosity}' and active agent reloaded")
|
|
167
|
+
return True
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@register_command(
|
|
171
|
+
name="set",
|
|
172
|
+
description="Set puppy config (e.g., /set yolo_mode true)",
|
|
173
|
+
usage="/set <key> <value>",
|
|
174
|
+
category="config",
|
|
175
|
+
)
|
|
176
|
+
def handle_set_command(command: str) -> bool:
|
|
177
|
+
"""Set configuration values."""
|
|
178
|
+
from rich.text import Text
|
|
179
|
+
|
|
180
|
+
from code_puppy.config import set_config_value
|
|
181
|
+
from code_puppy.messaging import emit_error, emit_info, emit_success, emit_warning
|
|
182
|
+
|
|
183
|
+
tokens = command.split(None, 2)
|
|
184
|
+
argstr = command[len("/set") :].strip()
|
|
185
|
+
key = None
|
|
186
|
+
value = None
|
|
187
|
+
if "=" in argstr:
|
|
188
|
+
key, value = argstr.split("=", 1)
|
|
189
|
+
key = key.strip()
|
|
190
|
+
value = value.strip()
|
|
191
|
+
elif len(tokens) >= 3:
|
|
192
|
+
key = tokens[1]
|
|
193
|
+
value = tokens[2]
|
|
194
|
+
elif len(tokens) == 2:
|
|
195
|
+
key = tokens[1]
|
|
196
|
+
value = ""
|
|
197
|
+
else:
|
|
198
|
+
config_keys = get_config_keys()
|
|
199
|
+
if "compaction_strategy" not in config_keys:
|
|
200
|
+
config_keys.append("compaction_strategy")
|
|
201
|
+
session_help = (
|
|
202
|
+
"\n[yellow]Session Management[/yellow]"
|
|
203
|
+
"\n [cyan]auto_save_session[/cyan] Auto-save chat after every response (true/false)"
|
|
204
|
+
)
|
|
205
|
+
keymap_help = (
|
|
206
|
+
"\n[yellow]Keyboard Shortcuts[/yellow]"
|
|
207
|
+
"\n [cyan]cancel_agent_key[/cyan] Key to cancel agent tasks (ctrl+c, ctrl+k, or ctrl+q)"
|
|
208
|
+
)
|
|
209
|
+
emit_warning(
|
|
210
|
+
Text.from_markup(
|
|
211
|
+
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}{keymap_help}"
|
|
212
|
+
)
|
|
213
|
+
)
|
|
214
|
+
return True
|
|
215
|
+
if key:
|
|
216
|
+
# Check if we're toggling DBOS enablement
|
|
217
|
+
if key == "enable_dbos":
|
|
218
|
+
emit_info(
|
|
219
|
+
Text.from_markup(
|
|
220
|
+
"[yellow]ā ļø DBOS configuration changed. Please restart Code Puppy for this change to take effect.[/yellow]"
|
|
221
|
+
)
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
# Validate cancel_agent_key before setting
|
|
225
|
+
if key == "cancel_agent_key":
|
|
226
|
+
from code_puppy.keymap import VALID_CANCEL_KEYS
|
|
227
|
+
|
|
228
|
+
normalized_value = value.strip().lower()
|
|
229
|
+
if normalized_value not in VALID_CANCEL_KEYS:
|
|
230
|
+
emit_error(
|
|
231
|
+
f"Invalid cancel_agent_key '{value}'. Valid options: {', '.join(sorted(VALID_CANCEL_KEYS))}"
|
|
232
|
+
)
|
|
233
|
+
return True
|
|
234
|
+
value = normalized_value # Use normalized value
|
|
235
|
+
emit_info(
|
|
236
|
+
Text.from_markup(
|
|
237
|
+
"[yellow]ā ļø cancel_agent_key changed. Please restart Code Puppy for this change to take effect.[/yellow]"
|
|
238
|
+
)
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
set_config_value(key, value)
|
|
242
|
+
emit_success(f'Set {key} = "{value}" in puppy.cfg!')
|
|
243
|
+
|
|
244
|
+
# Reload the current agent to pick up the new config
|
|
245
|
+
from code_puppy.agents import get_current_agent
|
|
246
|
+
|
|
247
|
+
try:
|
|
248
|
+
current_agent = get_current_agent()
|
|
249
|
+
current_agent.reload_code_generation_agent()
|
|
250
|
+
emit_info("Agent reloaded with updated config")
|
|
251
|
+
except Exception as reload_error:
|
|
252
|
+
emit_warning(f"Config saved but agent reload failed: {reload_error}")
|
|
253
|
+
else:
|
|
254
|
+
emit_error("You must supply a key.")
|
|
255
|
+
return True
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _get_json_agents_pinned_to_model(model_name: str) -> list:
|
|
259
|
+
"""Get JSON agents that have this model pinned in their JSON file."""
|
|
260
|
+
from code_puppy.agents.json_agent import discover_json_agents
|
|
261
|
+
|
|
262
|
+
pinned = []
|
|
263
|
+
json_agents = discover_json_agents()
|
|
264
|
+
for agent_name, agent_path in json_agents.items():
|
|
265
|
+
try:
|
|
266
|
+
with open(agent_path, "r") as f:
|
|
267
|
+
agent_data = json.load(f)
|
|
268
|
+
if agent_data.get("model") == model_name:
|
|
269
|
+
pinned.append(agent_name)
|
|
270
|
+
except Exception:
|
|
271
|
+
continue
|
|
272
|
+
return pinned
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
@register_command(
|
|
276
|
+
name="pin_model",
|
|
277
|
+
description="Pin a specific model to an agent",
|
|
278
|
+
usage="/pin_model <agent> <model>",
|
|
279
|
+
category="config",
|
|
280
|
+
)
|
|
281
|
+
def handle_pin_model_command(command: str) -> bool:
|
|
282
|
+
"""Pin a specific model to an agent."""
|
|
283
|
+
from code_puppy.agents.json_agent import discover_json_agents
|
|
284
|
+
from code_puppy.command_line.model_picker_completion import load_model_names
|
|
285
|
+
from code_puppy.messaging import emit_error, emit_info, emit_success, emit_warning
|
|
286
|
+
|
|
287
|
+
tokens = command.split()
|
|
288
|
+
|
|
289
|
+
if len(tokens) != 3:
|
|
290
|
+
emit_warning("Usage: /pin_model <agent-name> <model-name>")
|
|
291
|
+
|
|
292
|
+
# Show available models and agents
|
|
293
|
+
available_models = load_model_names()
|
|
294
|
+
json_agents = discover_json_agents()
|
|
295
|
+
|
|
296
|
+
# Get built-in agents
|
|
297
|
+
from code_puppy.agents.agent_manager import get_agent_descriptions
|
|
298
|
+
|
|
299
|
+
builtin_agents = get_agent_descriptions()
|
|
300
|
+
|
|
301
|
+
emit_info("Available models:")
|
|
302
|
+
for model in available_models:
|
|
303
|
+
emit_info(f" {model}")
|
|
304
|
+
|
|
305
|
+
if builtin_agents:
|
|
306
|
+
emit_info("\nAvailable built-in agents:")
|
|
307
|
+
for agent_name, description in builtin_agents.items():
|
|
308
|
+
emit_info(f" {agent_name} - {description}")
|
|
309
|
+
|
|
310
|
+
if json_agents:
|
|
311
|
+
emit_info("\nAvailable JSON agents:")
|
|
312
|
+
for agent_name, agent_path in json_agents.items():
|
|
313
|
+
emit_info(f" {agent_name} ({agent_path})")
|
|
314
|
+
return True
|
|
315
|
+
|
|
316
|
+
agent_name = tokens[1].lower()
|
|
317
|
+
model_name = tokens[2]
|
|
318
|
+
|
|
319
|
+
# Handle special case: (unpin) option (case-insensitive)
|
|
320
|
+
if model_name.lower() == "(unpin)":
|
|
321
|
+
# Delegate to unpin command
|
|
322
|
+
return handle_unpin_command(f"/unpin {agent_name}")
|
|
323
|
+
|
|
324
|
+
# Check if model exists
|
|
325
|
+
available_models = load_model_names()
|
|
326
|
+
if model_name not in available_models:
|
|
327
|
+
emit_error(f"Model '{model_name}' not found")
|
|
328
|
+
emit_warning(f"Available models: {', '.join(available_models)}")
|
|
329
|
+
return True
|
|
330
|
+
|
|
331
|
+
# Check if this is a JSON agent or a built-in Python agent
|
|
332
|
+
json_agents = discover_json_agents()
|
|
333
|
+
|
|
334
|
+
# Get list of available built-in agents
|
|
335
|
+
from code_puppy.agents.agent_manager import get_agent_descriptions
|
|
336
|
+
|
|
337
|
+
builtin_agents = get_agent_descriptions()
|
|
338
|
+
|
|
339
|
+
is_json_agent = agent_name in json_agents
|
|
340
|
+
is_builtin_agent = agent_name in builtin_agents
|
|
341
|
+
|
|
342
|
+
if not is_json_agent and not is_builtin_agent:
|
|
343
|
+
emit_error(f"Agent '{agent_name}' not found")
|
|
344
|
+
|
|
345
|
+
# Show available agents
|
|
346
|
+
if builtin_agents:
|
|
347
|
+
emit_info("Available built-in agents:")
|
|
348
|
+
for name, desc in builtin_agents.items():
|
|
349
|
+
emit_info(f" {name} - {desc}")
|
|
350
|
+
|
|
351
|
+
if json_agents:
|
|
352
|
+
emit_info("\nAvailable JSON agents:")
|
|
353
|
+
for name, path in json_agents.items():
|
|
354
|
+
emit_info(f" {name} ({path})")
|
|
355
|
+
return True
|
|
356
|
+
|
|
357
|
+
# Handle different agent types
|
|
358
|
+
try:
|
|
359
|
+
if is_json_agent:
|
|
360
|
+
# Handle JSON agent - modify the JSON file
|
|
361
|
+
agent_file_path = json_agents[agent_name]
|
|
362
|
+
|
|
363
|
+
with open(agent_file_path, "r", encoding="utf-8") as f:
|
|
364
|
+
agent_config = json.load(f)
|
|
365
|
+
|
|
366
|
+
# Set the model
|
|
367
|
+
agent_config["model"] = model_name
|
|
368
|
+
|
|
369
|
+
# Save the updated configuration
|
|
370
|
+
with open(agent_file_path, "w", encoding="utf-8") as f:
|
|
371
|
+
json.dump(agent_config, f, indent=2, ensure_ascii=False)
|
|
372
|
+
|
|
373
|
+
else:
|
|
374
|
+
# Handle built-in Python agent - store in config
|
|
375
|
+
from code_puppy.config import set_agent_pinned_model
|
|
376
|
+
|
|
377
|
+
set_agent_pinned_model(agent_name, model_name)
|
|
378
|
+
|
|
379
|
+
emit_success(f"Model '{model_name}' pinned to agent '{agent_name}'")
|
|
380
|
+
|
|
381
|
+
# If this is the current agent, refresh it so the prompt updates immediately
|
|
382
|
+
from code_puppy.agents import get_current_agent
|
|
383
|
+
|
|
384
|
+
current_agent = get_current_agent()
|
|
385
|
+
if current_agent.name == agent_name:
|
|
386
|
+
try:
|
|
387
|
+
if is_json_agent and hasattr(current_agent, "refresh_config"):
|
|
388
|
+
current_agent.refresh_config()
|
|
389
|
+
current_agent.reload_code_generation_agent()
|
|
390
|
+
emit_info(f"Active agent reloaded with pinned model '{model_name}'")
|
|
391
|
+
except Exception as reload_error:
|
|
392
|
+
emit_warning(f"Pinned model applied but reload failed: {reload_error}")
|
|
393
|
+
|
|
394
|
+
return True
|
|
395
|
+
|
|
396
|
+
except Exception as e:
|
|
397
|
+
emit_error(f"Failed to pin model to agent '{agent_name}': {e}")
|
|
398
|
+
return True
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
@register_command(
|
|
402
|
+
name="unpin",
|
|
403
|
+
description="Unpin a model from an agent (resets to default)",
|
|
404
|
+
usage="/unpin <agent>",
|
|
405
|
+
category="config",
|
|
406
|
+
)
|
|
407
|
+
def handle_unpin_command(command: str) -> bool:
|
|
408
|
+
"""Unpin a model from an agent (resets to default)."""
|
|
409
|
+
from code_puppy.agents.json_agent import discover_json_agents
|
|
410
|
+
from code_puppy.config import get_agent_pinned_model
|
|
411
|
+
from code_puppy.messaging import emit_error, emit_info, emit_success, emit_warning
|
|
412
|
+
|
|
413
|
+
tokens = command.split()
|
|
414
|
+
|
|
415
|
+
if len(tokens) != 2:
|
|
416
|
+
emit_warning("Usage: /unpin <agent-name>")
|
|
417
|
+
|
|
418
|
+
# Show available agents
|
|
419
|
+
json_agents = discover_json_agents()
|
|
420
|
+
|
|
421
|
+
# Get built-in agents
|
|
422
|
+
from code_puppy.agents.agent_manager import get_agent_descriptions
|
|
423
|
+
|
|
424
|
+
builtin_agents = get_agent_descriptions()
|
|
425
|
+
|
|
426
|
+
if builtin_agents:
|
|
427
|
+
emit_info("Available built-in agents:")
|
|
428
|
+
for agent_name, description in builtin_agents.items():
|
|
429
|
+
pinned_model = get_agent_pinned_model(agent_name)
|
|
430
|
+
if pinned_model:
|
|
431
|
+
emit_info(f" {agent_name} - {description} [ā {pinned_model}]")
|
|
432
|
+
else:
|
|
433
|
+
emit_info(f" {agent_name} - {description}")
|
|
434
|
+
|
|
435
|
+
if json_agents:
|
|
436
|
+
emit_info("\nAvailable JSON agents:")
|
|
437
|
+
for agent_name, agent_path in json_agents.items():
|
|
438
|
+
# Read the JSON file to check for pinned model
|
|
439
|
+
try:
|
|
440
|
+
with open(agent_path, "r") as f:
|
|
441
|
+
agent_config = json.load(f)
|
|
442
|
+
pinned_model = agent_config.get("model")
|
|
443
|
+
if pinned_model:
|
|
444
|
+
emit_info(f" {agent_name} ({agent_path}) [ā {pinned_model}]")
|
|
445
|
+
else:
|
|
446
|
+
emit_info(f" {agent_name} ({agent_path})")
|
|
447
|
+
except Exception:
|
|
448
|
+
emit_info(f" {agent_name} ({agent_path})")
|
|
449
|
+
return True
|
|
450
|
+
|
|
451
|
+
agent_name_input = tokens[1].lower()
|
|
452
|
+
|
|
453
|
+
# Check if this is a JSON agent or a built-in Python agent
|
|
454
|
+
json_agents = discover_json_agents()
|
|
455
|
+
|
|
456
|
+
# Get list of available built-in agents
|
|
457
|
+
from code_puppy.agents.agent_manager import get_agent_descriptions
|
|
458
|
+
|
|
459
|
+
builtin_agents = get_agent_descriptions()
|
|
460
|
+
|
|
461
|
+
# Find matching agent (case-insensitive)
|
|
462
|
+
agent_name = None
|
|
463
|
+
is_json_agent = False
|
|
464
|
+
is_builtin_agent = False
|
|
465
|
+
|
|
466
|
+
# Check JSON agents (case-insensitive)
|
|
467
|
+
for json_agent_name in json_agents:
|
|
468
|
+
if json_agent_name.lower() == agent_name_input:
|
|
469
|
+
agent_name = json_agent_name
|
|
470
|
+
is_json_agent = True
|
|
471
|
+
break
|
|
472
|
+
|
|
473
|
+
# Check built-in agents (case-insensitive)
|
|
474
|
+
if not is_json_agent:
|
|
475
|
+
for builtin_agent_name in builtin_agents:
|
|
476
|
+
if builtin_agent_name.lower() == agent_name_input:
|
|
477
|
+
agent_name = builtin_agent_name
|
|
478
|
+
is_builtin_agent = True
|
|
479
|
+
break
|
|
480
|
+
|
|
481
|
+
if not is_json_agent and not is_builtin_agent:
|
|
482
|
+
emit_error(f"Agent '{agent_name_input}' not found")
|
|
483
|
+
|
|
484
|
+
# Show available agents
|
|
485
|
+
if builtin_agents:
|
|
486
|
+
emit_info("Available built-in agents:")
|
|
487
|
+
for name, desc in builtin_agents.items():
|
|
488
|
+
emit_info(f" {name} - {desc}")
|
|
489
|
+
|
|
490
|
+
if json_agents:
|
|
491
|
+
emit_info("\nAvailable JSON agents:")
|
|
492
|
+
for name, path in json_agents.items():
|
|
493
|
+
emit_info(f" {name} ({path})")
|
|
494
|
+
return True
|
|
495
|
+
|
|
496
|
+
try:
|
|
497
|
+
if is_json_agent:
|
|
498
|
+
# Handle JSON agent - remove the model from JSON file
|
|
499
|
+
agent_file_path = json_agents[agent_name]
|
|
500
|
+
|
|
501
|
+
with open(agent_file_path, "r", encoding="utf-8") as f:
|
|
502
|
+
agent_config = json.load(f)
|
|
503
|
+
|
|
504
|
+
# Remove the model key if it exists
|
|
505
|
+
if "model" in agent_config:
|
|
506
|
+
del agent_config["model"]
|
|
507
|
+
|
|
508
|
+
# Save the updated configuration
|
|
509
|
+
with open(agent_file_path, "w", encoding="utf-8") as f:
|
|
510
|
+
json.dump(agent_config, f, indent=2, ensure_ascii=False)
|
|
511
|
+
|
|
512
|
+
else:
|
|
513
|
+
# Handle built-in Python agent - clear from config
|
|
514
|
+
from code_puppy.config import clear_agent_pinned_model
|
|
515
|
+
|
|
516
|
+
clear_agent_pinned_model(agent_name)
|
|
517
|
+
|
|
518
|
+
emit_success(f"Model unpinned from agent '{agent_name}' (reset to default)")
|
|
519
|
+
|
|
520
|
+
# If this is the current agent, refresh it so the prompt updates immediately
|
|
521
|
+
from code_puppy.agents import get_current_agent
|
|
522
|
+
|
|
523
|
+
current_agent = get_current_agent()
|
|
524
|
+
if current_agent.name == agent_name:
|
|
525
|
+
try:
|
|
526
|
+
if is_json_agent and hasattr(current_agent, "refresh_config"):
|
|
527
|
+
current_agent.refresh_config()
|
|
528
|
+
current_agent.reload_code_generation_agent()
|
|
529
|
+
emit_info("Active agent reloaded with default model")
|
|
530
|
+
except Exception as reload_error:
|
|
531
|
+
emit_warning(f"Model unpinned but reload failed: {reload_error}")
|
|
532
|
+
|
|
533
|
+
return True
|
|
534
|
+
|
|
535
|
+
except Exception as e:
|
|
536
|
+
emit_error(f"Failed to unpin model from agent '{agent_name}': {e}")
|
|
537
|
+
return True
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
@register_command(
|
|
541
|
+
name="diff",
|
|
542
|
+
description="Configure diff highlighting colors (additions, deletions)",
|
|
543
|
+
usage="/diff",
|
|
544
|
+
category="config",
|
|
545
|
+
)
|
|
546
|
+
def handle_diff_command(command: str) -> bool:
|
|
547
|
+
"""Configure diff highlighting colors."""
|
|
548
|
+
import asyncio
|
|
549
|
+
import concurrent.futures
|
|
550
|
+
|
|
551
|
+
from code_puppy.command_line.diff_menu import interactive_diff_picker
|
|
552
|
+
from code_puppy.config import (
|
|
553
|
+
set_diff_addition_color,
|
|
554
|
+
set_diff_deletion_color,
|
|
555
|
+
)
|
|
556
|
+
from code_puppy.messaging import emit_error
|
|
557
|
+
|
|
558
|
+
# Show interactive picker for diff configuration
|
|
559
|
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
|
560
|
+
future = executor.submit(lambda: asyncio.run(interactive_diff_picker()))
|
|
561
|
+
result = future.result(timeout=300) # 5 min timeout
|
|
562
|
+
|
|
563
|
+
if result:
|
|
564
|
+
# Apply the changes silently (no console output)
|
|
565
|
+
try:
|
|
566
|
+
set_diff_addition_color(result["add_color"])
|
|
567
|
+
set_diff_deletion_color(result["del_color"])
|
|
568
|
+
except Exception as e:
|
|
569
|
+
emit_error(f"Failed to apply diff settings: {e}")
|
|
570
|
+
return True
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
@register_command(
|
|
574
|
+
name="colors",
|
|
575
|
+
description="Configure banner colors for tool outputs (THINKING, SHELL COMMAND, etc.)",
|
|
576
|
+
usage="/colors",
|
|
577
|
+
category="config",
|
|
578
|
+
)
|
|
579
|
+
def handle_colors_command(command: str) -> bool:
|
|
580
|
+
"""Configure banner colors via interactive TUI."""
|
|
581
|
+
import asyncio
|
|
582
|
+
import concurrent.futures
|
|
583
|
+
|
|
584
|
+
from code_puppy.command_line.colors_menu import interactive_colors_picker
|
|
585
|
+
from code_puppy.config import set_banner_color
|
|
586
|
+
from code_puppy.messaging import emit_error, emit_success
|
|
587
|
+
|
|
588
|
+
# Show interactive picker for banner color configuration
|
|
589
|
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
|
590
|
+
future = executor.submit(lambda: asyncio.run(interactive_colors_picker()))
|
|
591
|
+
result = future.result(timeout=300) # 5 min timeout
|
|
592
|
+
|
|
593
|
+
if result:
|
|
594
|
+
# Apply the changes
|
|
595
|
+
try:
|
|
596
|
+
for banner_name, color in result.items():
|
|
597
|
+
set_banner_color(banner_name, color)
|
|
598
|
+
emit_success("Banner colors saved! šØ")
|
|
599
|
+
except Exception as e:
|
|
600
|
+
emit_error(f"Failed to apply banner color settings: {e}")
|
|
601
|
+
return True
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
# ============================================================================
|
|
605
|
+
# UTILITY FUNCTIONS
|
|
606
|
+
# ============================================================================
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
def _show_color_options(color_type: str):
|
|
610
|
+
# ============================================================================
|
|
611
|
+
# UTILITY FUNCTIONS
|
|
612
|
+
# ============================================================================
|
|
613
|
+
|
|
614
|
+
"""Show available Rich color options organized by category."""
|
|
615
|
+
from rich.text import Text
|
|
616
|
+
|
|
617
|
+
from code_puppy.messaging import emit_info
|
|
618
|
+
|
|
619
|
+
# Standard Rich colors organized by category
|
|
620
|
+
color_categories = {
|
|
621
|
+
"Basic Colors": [
|
|
622
|
+
("black", "ā«"),
|
|
623
|
+
("red", "š“"),
|
|
624
|
+
("green", "š¢"),
|
|
625
|
+
("yellow", "š”"),
|
|
626
|
+
("blue", "šµ"),
|
|
627
|
+
("magenta", "š£"),
|
|
628
|
+
("cyan", "š·"),
|
|
629
|
+
("white", "āŖ"),
|
|
630
|
+
],
|
|
631
|
+
"Bright Colors": [
|
|
632
|
+
("bright_black", "ā«"),
|
|
633
|
+
("bright_red", "š“"),
|
|
634
|
+
("bright_green", "š¢"),
|
|
635
|
+
("bright_yellow", "š”"),
|
|
636
|
+
("bright_blue", "šµ"),
|
|
637
|
+
("bright_magenta", "š£"),
|
|
638
|
+
("bright_cyan", "š·"),
|
|
639
|
+
("bright_white", "āŖ"),
|
|
640
|
+
],
|
|
641
|
+
"Special Colors": [
|
|
642
|
+
("orange1", "š "),
|
|
643
|
+
("orange3", "š "),
|
|
644
|
+
("orange4", "š "),
|
|
645
|
+
("deep_sky_blue1", "š·"),
|
|
646
|
+
("deep_sky_blue2", "š·"),
|
|
647
|
+
("deep_sky_blue3", "š·"),
|
|
648
|
+
("deep_sky_blue4", "š·"),
|
|
649
|
+
("turquoise2", "š·"),
|
|
650
|
+
("turquoise4", "š·"),
|
|
651
|
+
("steel_blue1", "š·"),
|
|
652
|
+
("steel_blue3", "š·"),
|
|
653
|
+
("chartreuse1", "š¢"),
|
|
654
|
+
("chartreuse2", "š¢"),
|
|
655
|
+
("chartreuse3", "š¢"),
|
|
656
|
+
("chartreuse4", "š¢"),
|
|
657
|
+
("gold1", "š”"),
|
|
658
|
+
("gold3", "š”"),
|
|
659
|
+
("rosy_brown", "š“"),
|
|
660
|
+
("indian_red", "š“"),
|
|
661
|
+
],
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
# Suggested colors for each type
|
|
665
|
+
if color_type == "additions":
|
|
666
|
+
suggestions = [
|
|
667
|
+
("green", "š¢"),
|
|
668
|
+
("bright_green", "š¢"),
|
|
669
|
+
("chartreuse1", "š¢"),
|
|
670
|
+
("green3", "š¢"),
|
|
671
|
+
("sea_green1", "š¢"),
|
|
672
|
+
]
|
|
673
|
+
emit_info(
|
|
674
|
+
Text.from_markup(
|
|
675
|
+
"[bold white on green]šØ Recommended Colors for Additions:[/bold white on green]"
|
|
676
|
+
)
|
|
677
|
+
)
|
|
678
|
+
for color, emoji in suggestions:
|
|
679
|
+
emit_info(
|
|
680
|
+
Text.from_markup(
|
|
681
|
+
f" [cyan]{color:<16}[/cyan] [white on {color}]ā ā ā ā ā ā ā ā ā ā [/white on {color}] {emoji}"
|
|
682
|
+
)
|
|
683
|
+
)
|
|
684
|
+
elif color_type == "deletions":
|
|
685
|
+
suggestions = [
|
|
686
|
+
("orange1", "š "),
|
|
687
|
+
("red", "š“"),
|
|
688
|
+
("bright_red", "š“"),
|
|
689
|
+
("indian_red", "š“"),
|
|
690
|
+
("dark_red", "š“"),
|
|
691
|
+
]
|
|
692
|
+
emit_info(
|
|
693
|
+
Text.from_markup(
|
|
694
|
+
"[bold white on orange1]šØ Recommended Colors for Deletions:[/bold white on orange1]"
|
|
695
|
+
)
|
|
696
|
+
)
|
|
697
|
+
for color, emoji in suggestions:
|
|
698
|
+
emit_info(
|
|
699
|
+
Text.from_markup(
|
|
700
|
+
f" [cyan]{color:<16}[/cyan] [white on {color}]ā ā ā ā ā ā ā ā ā ā [/white on {color}] {emoji}"
|
|
701
|
+
)
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
emit_info("\nšØ All Available Rich Colors:")
|
|
705
|
+
for category, colors in color_categories.items():
|
|
706
|
+
emit_info(f"\n{category}:")
|
|
707
|
+
# Display in columns for better readability
|
|
708
|
+
for i in range(0, len(colors), 4):
|
|
709
|
+
row = colors[i : i + 4]
|
|
710
|
+
row_text = " ".join([f"[{color}]ā [/{color}] {color}" for color, _ in row])
|
|
711
|
+
emit_info(Text.from_markup(f" {row_text}"))
|
|
712
|
+
|
|
713
|
+
emit_info("\nUsage: /diff {color_type} <color_name>")
|
|
714
|
+
emit_info("All diffs use white text on your chosen background colors")
|
|
715
|
+
emit_info("You can also use hex colors like #ff0000 or rgb(255,0,0)")
|