code-puppy 0.0.327__tar.gz → 0.0.329__tar.gz
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-0.0.327 → code_puppy-0.0.329}/PKG-INFO +1 -1
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/base_agent.py +34 -2
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/cli_runner.py +2 -1
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/command_runner.py +89 -4
- {code_puppy-0.0.327 → code_puppy-0.0.329}/pyproject.toml +1 -1
- {code_puppy-0.0.327 → code_puppy-0.0.329}/.gitignore +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/LICENSE +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/README.md +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/__main__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_c_reviewer.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_code_puppy.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_code_reviewer.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_cpp_reviewer.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_creator_agent.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_golang_reviewer.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_javascript_reviewer.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_manager.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_planning.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_python_programmer.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_python_reviewer.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_qa_expert.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_qa_kitten.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_security_auditor.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/agent_typescript_reviewer.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/json_agent.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/agents/prompt_reviewer.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/callbacks.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/chatgpt_codex_client.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/claude_cache_client.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/add_model_menu.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/attachments.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/autosave_menu.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/colors_menu.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/command_handler.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/command_registry.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/config_commands.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/core_commands.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/diff_menu.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/file_path_completion.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/load_context_completion.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/add_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/base.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/edit_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/handler.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/help_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/install_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/install_menu.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/list_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/logs_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/remove_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/restart_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/search_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/start_all_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/start_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/status_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/stop_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/test_command.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/utils.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp_completion.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/model_picker_completion.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/model_settings_menu.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/motd.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/pin_command_completion.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/session_commands.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/utils.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/config.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/error_logging.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/gemini_code_assist.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/http_utils.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/keymap.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/main.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/async_lifecycle.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/blocking_startup.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/captured_stdio_server.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/circuit_breaker.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/config_wizard.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/dashboard.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/error_isolation.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/examples/retry_example.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/health_monitor.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/managed_server.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/manager.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/mcp_logs.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/registry.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/retry_manager.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/server_registry_catalog.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/status_tracker.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/mcp_/system_tools.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/messaging/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/messaging/bus.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/messaging/commands.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/messaging/markdown_patches.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/messaging/message_queue.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/messaging/messages.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/messaging/queue_console.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/messaging/renderers.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/messaging/rich_renderer.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/messaging/spinner/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/messaging/spinner/console_spinner.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/messaging/spinner/spinner_base.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/model_factory.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/model_utils.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/models.json +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/models_dev_api.json +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/models_dev_parser.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/claude_code_oauth/utils.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/example_custom_command/README.md +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/oauth_puppy_html.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/shell_safety/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/prompts/codex_system_prompt.md +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/pydantic_patches.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/reopenable_async_client.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/round_robin_model.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/session_storage.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/status_display.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/summarization_agent.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/terminal_utils.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/agent_tools.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/browser/__init__.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/browser/browser_control.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/browser/browser_interactions.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/browser/browser_locators.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/browser/browser_navigation.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/browser/browser_screenshot.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/browser/browser_scripts.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/browser/browser_workflows.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/browser/camoufox_manager.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/browser/vqa_agent.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/common.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/file_modifications.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/file_operations.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/tools/tools_content.py +0 -0
- {code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/version_checker.py +0 -0
|
@@ -75,6 +75,8 @@ from code_puppy.model_factory import ModelFactory, make_model_settings
|
|
|
75
75
|
from code_puppy.summarization_agent import run_summarization_sync
|
|
76
76
|
from code_puppy.tools.agent_tools import _active_subagent_tasks
|
|
77
77
|
from code_puppy.tools.command_runner import (
|
|
78
|
+
_add_windows_ctrl_handler,
|
|
79
|
+
_remove_windows_ctrl_handler,
|
|
78
80
|
is_awaiting_user_input,
|
|
79
81
|
)
|
|
80
82
|
|
|
@@ -1951,8 +1953,6 @@ class BaseAgent(ABC):
|
|
|
1951
1953
|
def graceful_sigint_handler(_sig, _frame):
|
|
1952
1954
|
# When using keyboard-based cancel, SIGINT should be a no-op
|
|
1953
1955
|
# (just show a hint to user about the configured cancel key)
|
|
1954
|
-
import sys
|
|
1955
|
-
|
|
1956
1956
|
from code_puppy.keymap import get_cancel_agent_display_name
|
|
1957
1957
|
|
|
1958
1958
|
cancel_key = get_cancel_agent_display_name()
|
|
@@ -1961,6 +1961,12 @@ class BaseAgent(ABC):
|
|
|
1961
1961
|
original_handler = None
|
|
1962
1962
|
key_listener_stop_event = None
|
|
1963
1963
|
_key_listener_thread = None
|
|
1964
|
+
windows_ctrl_handler = None
|
|
1965
|
+
|
|
1966
|
+
# Check if we're on Windows
|
|
1967
|
+
import sys
|
|
1968
|
+
|
|
1969
|
+
is_windows = sys.platform.startswith("win")
|
|
1964
1970
|
|
|
1965
1971
|
try:
|
|
1966
1972
|
if cancel_agent_uses_signal():
|
|
@@ -1968,10 +1974,27 @@ class BaseAgent(ABC):
|
|
|
1968
1974
|
original_handler = signal.signal(
|
|
1969
1975
|
signal.SIGINT, keyboard_interrupt_handler
|
|
1970
1976
|
)
|
|
1977
|
+
# On Windows, also use SetConsoleCtrlHandler for reliable Ctrl+C with uvx
|
|
1978
|
+
if is_windows:
|
|
1979
|
+
windows_ctrl_handler = _add_windows_ctrl_handler(
|
|
1980
|
+
schedule_agent_cancel
|
|
1981
|
+
)
|
|
1971
1982
|
else:
|
|
1972
1983
|
# Use keyboard listener for agent cancellation
|
|
1973
1984
|
# Set a graceful SIGINT handler that shows a hint
|
|
1974
1985
|
original_handler = signal.signal(signal.SIGINT, graceful_sigint_handler)
|
|
1986
|
+
# On Windows, SetConsoleCtrlHandler should also show the hint
|
|
1987
|
+
if is_windows:
|
|
1988
|
+
|
|
1989
|
+
def graceful_ctrl_handler():
|
|
1990
|
+
from code_puppy.keymap import get_cancel_agent_display_name
|
|
1991
|
+
|
|
1992
|
+
cancel_key = get_cancel_agent_display_name()
|
|
1993
|
+
emit_info(f"Use {cancel_key} to cancel the agent task.")
|
|
1994
|
+
|
|
1995
|
+
windows_ctrl_handler = _add_windows_ctrl_handler(
|
|
1996
|
+
graceful_ctrl_handler
|
|
1997
|
+
)
|
|
1975
1998
|
# Spawn keyboard listener with the cancel agent callback
|
|
1976
1999
|
key_listener_stop_event = threading.Event()
|
|
1977
2000
|
_key_listener_thread = self._spawn_ctrl_x_key_listener(
|
|
@@ -2001,8 +2024,17 @@ class BaseAgent(ABC):
|
|
|
2001
2024
|
# Stop keyboard listener if it was started
|
|
2002
2025
|
if key_listener_stop_event is not None:
|
|
2003
2026
|
key_listener_stop_event.set()
|
|
2027
|
+
# Remove Windows console handler
|
|
2028
|
+
if windows_ctrl_handler is not None:
|
|
2029
|
+
_remove_windows_ctrl_handler(windows_ctrl_handler)
|
|
2004
2030
|
# Restore original signal handler
|
|
2005
2031
|
if (
|
|
2006
2032
|
original_handler is not None
|
|
2007
2033
|
): # Explicit None check - SIG_DFL can be 0/falsy!
|
|
2008
2034
|
signal.signal(signal.SIGINT, original_handler)
|
|
2035
|
+
# Windows-specific: Reset terminal after Ctrl+C to prevent corruption
|
|
2036
|
+
# This fixes the issue where Enter key shows as 'm' after interrupting with uvx
|
|
2037
|
+
if is_windows:
|
|
2038
|
+
from code_puppy.terminal_utils import reset_windows_terminal_full
|
|
2039
|
+
|
|
2040
|
+
reset_windows_terminal_full()
|
|
@@ -604,7 +604,8 @@ async def interactive_mode(message_renderer, initial_command: str = None) -> Non
|
|
|
604
604
|
# Check if the task was cancelled (but don't show message if we just killed processes)
|
|
605
605
|
if result is None:
|
|
606
606
|
# Windows-specific: Reset terminal state after cancellation
|
|
607
|
-
|
|
607
|
+
# Use full reset (ANSI + console mode) to fix stdin after Ctrl+C
|
|
608
|
+
reset_windows_terminal_full()
|
|
608
609
|
continue
|
|
609
610
|
# Get the structured response
|
|
610
611
|
agent_response = result.output
|
|
@@ -44,9 +44,70 @@ def _truncate_line(line: str) -> str:
|
|
|
44
44
|
if sys.platform.startswith("win"):
|
|
45
45
|
import msvcrt
|
|
46
46
|
|
|
47
|
-
# Load kernel32 for PeekNamedPipe
|
|
47
|
+
# Load kernel32 for PeekNamedPipe and SetConsoleCtrlHandler
|
|
48
48
|
_kernel32 = ctypes.windll.kernel32
|
|
49
49
|
|
|
50
|
+
# SetConsoleCtrlHandler types for Ctrl+C handling on Windows
|
|
51
|
+
# This is more reliable than signal.SIGINT when running under uvx
|
|
52
|
+
_CTRL_C_EVENT = 0
|
|
53
|
+
_CTRL_BREAK_EVENT = 1
|
|
54
|
+
_HANDLER_ROUTINE = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_ulong)
|
|
55
|
+
|
|
56
|
+
# Track registered handlers to prevent garbage collection
|
|
57
|
+
_registered_console_handlers: list = []
|
|
58
|
+
|
|
59
|
+
def _add_windows_ctrl_handler(callback: Callable[[], None]) -> Optional[Callable]:
|
|
60
|
+
"""Register a Windows console control handler for Ctrl+C/Ctrl+Break.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
callback: Function to call when Ctrl+C or Ctrl+Break is pressed.
|
|
64
|
+
Should take no arguments.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
The wrapped handler function (needed for removal), or None if failed.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
def handler(ctrl_type: int) -> int:
|
|
71
|
+
if ctrl_type in (_CTRL_C_EVENT, _CTRL_BREAK_EVENT):
|
|
72
|
+
try:
|
|
73
|
+
callback()
|
|
74
|
+
except Exception:
|
|
75
|
+
pass
|
|
76
|
+
return 1 # TRUE = we handled it, don't pass to next handler
|
|
77
|
+
return 0 # FALSE = let next handler deal with it
|
|
78
|
+
|
|
79
|
+
# Wrap in WINFUNCTYPE to make it callable from C
|
|
80
|
+
wrapped = _HANDLER_ROUTINE(handler)
|
|
81
|
+
# Keep reference to prevent GC
|
|
82
|
+
_registered_console_handlers.append(wrapped)
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
if _kernel32.SetConsoleCtrlHandler(wrapped, True):
|
|
86
|
+
return wrapped
|
|
87
|
+
except Exception:
|
|
88
|
+
pass
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
def _remove_windows_ctrl_handler(handler: Callable) -> bool:
|
|
92
|
+
"""Remove a previously registered Windows console control handler.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
handler: The handler returned by _add_windows_ctrl_handler.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
True if successfully removed, False otherwise.
|
|
99
|
+
"""
|
|
100
|
+
if handler is None:
|
|
101
|
+
return False
|
|
102
|
+
try:
|
|
103
|
+
result = _kernel32.SetConsoleCtrlHandler(handler, False)
|
|
104
|
+
# Clean up our reference
|
|
105
|
+
if handler in _registered_console_handlers:
|
|
106
|
+
_registered_console_handlers.remove(handler)
|
|
107
|
+
return bool(result)
|
|
108
|
+
except Exception:
|
|
109
|
+
return False
|
|
110
|
+
|
|
50
111
|
def _win32_pipe_has_data(pipe) -> bool:
|
|
51
112
|
"""Check if a Windows pipe has data available without blocking.
|
|
52
113
|
|
|
@@ -87,8 +148,15 @@ if sys.platform.startswith("win"):
|
|
|
87
148
|
except (ValueError, OSError, ctypes.ArgumentError):
|
|
88
149
|
# Handle closed, invalid, or other errors
|
|
89
150
|
return False
|
|
151
|
+
|
|
90
152
|
else:
|
|
91
|
-
#
|
|
153
|
+
# Non-Windows: provide no-op stubs
|
|
154
|
+
def _add_windows_ctrl_handler(callback: Callable[[], None]) -> Optional[Callable]:
|
|
155
|
+
return None
|
|
156
|
+
|
|
157
|
+
def _remove_windows_ctrl_handler(handler: Callable) -> bool:
|
|
158
|
+
return False
|
|
159
|
+
|
|
92
160
|
def _win32_pipe_has_data(pipe) -> bool:
|
|
93
161
|
return False
|
|
94
162
|
|
|
@@ -106,6 +174,7 @@ _USER_KILLED_PROCESSES = set()
|
|
|
106
174
|
_SHELL_CTRL_X_STOP_EVENT: Optional[threading.Event] = None
|
|
107
175
|
_SHELL_CTRL_X_THREAD: Optional[threading.Thread] = None
|
|
108
176
|
_ORIGINAL_SIGINT_HANDLER = None
|
|
177
|
+
_WINDOWS_CTRL_HANDLER = None # For SetConsoleCtrlHandler on Windows
|
|
109
178
|
|
|
110
179
|
# Stop event to signal reader threads to terminate
|
|
111
180
|
_READER_STOP_EVENT: Optional[threading.Event] = None
|
|
@@ -435,8 +504,10 @@ def _shell_command_keyboard_context():
|
|
|
435
504
|
1. Disables the agent's Ctrl-C handler (so it doesn't cancel the agent)
|
|
436
505
|
2. Enables a Ctrl-X listener to kill the running shell process
|
|
437
506
|
3. Restores the original Ctrl-C handler when done
|
|
507
|
+
4. On Windows, uses SetConsoleCtrlHandler for reliable Ctrl+C with uvx
|
|
438
508
|
"""
|
|
439
509
|
global _SHELL_CTRL_X_STOP_EVENT, _SHELL_CTRL_X_THREAD, _ORIGINAL_SIGINT_HANDLER
|
|
510
|
+
global _WINDOWS_CTRL_HANDLER
|
|
440
511
|
|
|
441
512
|
# Handler for Ctrl-X: kill all running shell processes
|
|
442
513
|
def handle_ctrl_x_press() -> None:
|
|
@@ -444,11 +515,15 @@ def _shell_command_keyboard_context():
|
|
|
444
515
|
kill_all_running_shell_processes()
|
|
445
516
|
|
|
446
517
|
# Handler for Ctrl-C during shell execution: just kill the shell process, don't cancel agent
|
|
447
|
-
def
|
|
518
|
+
def shell_ctrl_c_callback():
|
|
448
519
|
"""During shell execution, Ctrl-C kills the shell but doesn't cancel the agent."""
|
|
449
520
|
emit_warning("\n🛑 Ctrl-C detected! Interrupting shell command...")
|
|
450
521
|
kill_all_running_shell_processes()
|
|
451
522
|
|
|
523
|
+
def shell_sigint_handler(_sig, _frame):
|
|
524
|
+
"""Signal handler wrapper for SIGINT."""
|
|
525
|
+
shell_ctrl_c_callback()
|
|
526
|
+
|
|
452
527
|
# Set up Ctrl-X listener
|
|
453
528
|
_SHELL_CTRL_X_STOP_EVENT = threading.Event()
|
|
454
529
|
_SHELL_CTRL_X_THREAD = _spawn_ctrl_x_key_listener(
|
|
@@ -456,7 +531,12 @@ def _shell_command_keyboard_context():
|
|
|
456
531
|
handle_ctrl_x_press,
|
|
457
532
|
)
|
|
458
533
|
|
|
459
|
-
#
|
|
534
|
+
# On Windows, use SetConsoleCtrlHandler for reliable Ctrl+C handling
|
|
535
|
+
# This works even when running under uvx where SIGINT doesn't propagate properly
|
|
536
|
+
if sys.platform.startswith("win"):
|
|
537
|
+
_WINDOWS_CTRL_HANDLER = _add_windows_ctrl_handler(shell_ctrl_c_callback)
|
|
538
|
+
|
|
539
|
+
# Also set SIGINT handler (works on POSIX, may work on some Windows setups)
|
|
460
540
|
try:
|
|
461
541
|
_ORIGINAL_SIGINT_HANDLER = signal.signal(signal.SIGINT, shell_sigint_handler)
|
|
462
542
|
except (ValueError, OSError):
|
|
@@ -476,6 +556,10 @@ def _shell_command_keyboard_context():
|
|
|
476
556
|
except Exception:
|
|
477
557
|
pass
|
|
478
558
|
|
|
559
|
+
# Remove Windows console handler
|
|
560
|
+
if _WINDOWS_CTRL_HANDLER is not None:
|
|
561
|
+
_remove_windows_ctrl_handler(_WINDOWS_CTRL_HANDLER)
|
|
562
|
+
|
|
479
563
|
# Restore original SIGINT handler
|
|
480
564
|
if _ORIGINAL_SIGINT_HANDLER is not None:
|
|
481
565
|
try:
|
|
@@ -487,6 +571,7 @@ def _shell_command_keyboard_context():
|
|
|
487
571
|
_SHELL_CTRL_X_STOP_EVENT = None
|
|
488
572
|
_SHELL_CTRL_X_THREAD = None
|
|
489
573
|
_ORIGINAL_SIGINT_HANDLER = None
|
|
574
|
+
_WINDOWS_CTRL_HANDLER = None
|
|
490
575
|
|
|
491
576
|
|
|
492
577
|
def run_shell_command_streaming(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/load_context_completion.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/catalog_server_installer.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/mcp/custom_server_installer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/model_picker_completion.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/command_line/prompt_toolkit_completion.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/claude_code_oauth/register_callbacks.py
RENAMED
|
File without changes
|
{code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/claude_code_oauth/test_plugin.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/customizable_commands/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/example_custom_command/README.md
RENAMED
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/file_permission_handler/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/shell_safety/agent_shell_safety.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.327 → code_puppy-0.0.329}/code_puppy/plugins/shell_safety/register_callbacks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|