code-puppy 0.0.338__tar.gz → 0.0.340__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.338 → code_puppy-0.0.340}/PKG-INFO +2 -1
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/claude_cache_client.py +76 -18
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/cli_runner.py +46 -5
- code_puppy-0.0.340/code_puppy/command_line/clipboard.py +527 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/core_commands.py +34 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/prompt_toolkit_completion.py +112 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/managed_server.py +7 -11
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/common.py +3 -9
- {code_puppy-0.0.338 → code_puppy-0.0.340}/pyproject.toml +2 -1
- {code_puppy-0.0.338 → code_puppy-0.0.340}/.gitignore +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/LICENSE +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/README.md +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/__main__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_c_reviewer.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_code_puppy.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_code_reviewer.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_cpp_reviewer.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_creator_agent.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_golang_reviewer.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_javascript_reviewer.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_manager.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_planning.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_python_programmer.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_python_reviewer.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_qa_expert.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_qa_kitten.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_security_auditor.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/agent_typescript_reviewer.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/base_agent.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/json_agent.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/agents/prompt_reviewer.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/callbacks.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/chatgpt_codex_client.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/add_model_menu.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/attachments.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/autosave_menu.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/colors_menu.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/command_handler.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/command_registry.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/config_commands.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/diff_menu.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/file_path_completion.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/load_context_completion.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/add_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/base.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/edit_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/handler.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/help_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/install_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/install_menu.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/list_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/logs_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/remove_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/restart_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/search_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/start_all_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/start_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/status_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/stop_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/test_command.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/utils.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/mcp_completion.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/model_picker_completion.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/model_settings_menu.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/motd.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/onboarding_slides.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/onboarding_wizard.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/pin_command_completion.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/session_commands.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/command_line/utils.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/config.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/error_logging.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/gemini_code_assist.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/http_utils.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/keymap.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/main.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/async_lifecycle.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/blocking_startup.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/captured_stdio_server.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/circuit_breaker.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/config_wizard.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/dashboard.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/error_isolation.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/examples/retry_example.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/health_monitor.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/manager.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/mcp_logs.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/registry.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/retry_manager.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/server_registry_catalog.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/status_tracker.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/mcp_/system_tools.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/messaging/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/messaging/bus.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/messaging/commands.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/messaging/markdown_patches.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/messaging/message_queue.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/messaging/messages.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/messaging/queue_console.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/messaging/renderers.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/messaging/rich_renderer.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/messaging/spinner/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/messaging/spinner/console_spinner.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/messaging/spinner/spinner_base.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/model_factory.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/model_utils.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/models.json +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/models_dev_api.json +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/models_dev_parser.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/antigravity_oauth/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/antigravity_oauth/accounts.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/antigravity_oauth/antigravity_model.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/antigravity_oauth/config.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/antigravity_oauth/constants.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/antigravity_oauth/oauth.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/antigravity_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/antigravity_oauth/storage.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/antigravity_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/antigravity_oauth/token.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/antigravity_oauth/transport.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/antigravity_oauth/utils.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/claude_code_oauth/utils.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/example_custom_command/README.md +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/oauth_puppy_html.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/shell_safety/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/prompts/codex_system_prompt.md +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/pydantic_patches.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/reopenable_async_client.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/round_robin_model.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/session_storage.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/status_display.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/summarization_agent.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/terminal_utils.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/agent_tools.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/browser/__init__.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/browser/browser_control.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/browser/browser_interactions.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/browser/browser_locators.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/browser/browser_navigation.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/browser/browser_screenshot.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/browser/browser_scripts.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/browser/browser_workflows.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/browser/camoufox_manager.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/browser/vqa_agent.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/command_runner.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/file_modifications.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/file_operations.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/tools/tools_content.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/uvx_detection.py +0 -0
- {code_puppy-0.0.338 → code_puppy-0.0.340}/code_puppy/version_checker.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-puppy
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.340
|
|
4
4
|
Summary: Code generation agent
|
|
5
5
|
Project-URL: repository, https://github.com/mpfaffenberger/code_puppy
|
|
6
6
|
Project-URL: HomePage, https://github.com/mpfaffenberger/code_puppy
|
|
@@ -22,6 +22,7 @@ Requires-Dist: httpx[http2]>=0.24.1
|
|
|
22
22
|
Requires-Dist: json-repair>=0.46.2
|
|
23
23
|
Requires-Dist: logfire>=0.7.1
|
|
24
24
|
Requires-Dist: openai>=1.99.1
|
|
25
|
+
Requires-Dist: pillow>=10.0.0
|
|
25
26
|
Requires-Dist: playwright>=1.40.0
|
|
26
27
|
Requires-Dist: prompt-toolkit>=3.0.52
|
|
27
28
|
Requires-Dist: pydantic-ai==1.25.0
|
|
@@ -10,10 +10,13 @@ serialization, avoiding httpx/Pydantic internals.
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
12
|
import json
|
|
13
|
+
import logging
|
|
13
14
|
from typing import Any, Callable, MutableMapping
|
|
14
15
|
|
|
15
16
|
import httpx
|
|
16
17
|
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
17
20
|
try:
|
|
18
21
|
from anthropic import AsyncAnthropic
|
|
19
22
|
except ImportError: # pragma: no cover - optional dep
|
|
@@ -58,25 +61,44 @@ class ClaudeCacheAsyncClient(httpx.AsyncClient):
|
|
|
58
61
|
pass
|
|
59
62
|
response = await super().send(request, *args, **kwargs)
|
|
60
63
|
try:
|
|
61
|
-
|
|
64
|
+
# Check for both 401 and 400 - Anthropic/Cloudflare may return 400 for auth errors
|
|
65
|
+
# Also check if it's a Cloudflare HTML error response
|
|
66
|
+
if response.status_code in (400, 401) and not request.extensions.get(
|
|
62
67
|
"claude_oauth_refresh_attempted"
|
|
63
68
|
):
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
self.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
69
|
+
# Determine if this is an auth error (including Cloudflare HTML errors)
|
|
70
|
+
is_auth_error = response.status_code == 401
|
|
71
|
+
|
|
72
|
+
if response.status_code == 400:
|
|
73
|
+
# Check if this is a Cloudflare HTML error
|
|
74
|
+
is_auth_error = self._is_cloudflare_html_error(response)
|
|
75
|
+
if is_auth_error:
|
|
76
|
+
logger.info(
|
|
77
|
+
"Detected Cloudflare 400 error (likely auth-related), attempting token refresh"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if is_auth_error:
|
|
81
|
+
refreshed_token = self._refresh_claude_oauth_token()
|
|
82
|
+
if refreshed_token:
|
|
83
|
+
logger.info("Token refreshed successfully, retrying request")
|
|
84
|
+
await response.aclose()
|
|
85
|
+
body_bytes = self._extract_body_bytes(request)
|
|
86
|
+
headers = dict(request.headers)
|
|
87
|
+
self._update_auth_headers(headers, refreshed_token)
|
|
88
|
+
retry_request = self.build_request(
|
|
89
|
+
method=request.method,
|
|
90
|
+
url=request.url,
|
|
91
|
+
headers=headers,
|
|
92
|
+
content=body_bytes,
|
|
93
|
+
)
|
|
94
|
+
retry_request.extensions["claude_oauth_refresh_attempted"] = (
|
|
95
|
+
True
|
|
96
|
+
)
|
|
97
|
+
return await super().send(retry_request, *args, **kwargs)
|
|
98
|
+
else:
|
|
99
|
+
logger.warning("Token refresh failed, returning original error")
|
|
100
|
+
except Exception as exc:
|
|
101
|
+
logger.debug("Error during token refresh attempt: %s", exc)
|
|
80
102
|
return response
|
|
81
103
|
|
|
82
104
|
@staticmethod
|
|
@@ -111,15 +133,51 @@ class ClaudeCacheAsyncClient(httpx.AsyncClient):
|
|
|
111
133
|
else:
|
|
112
134
|
headers["Authorization"] = bearer_value
|
|
113
135
|
|
|
136
|
+
@staticmethod
|
|
137
|
+
def _is_cloudflare_html_error(response: httpx.Response) -> bool:
|
|
138
|
+
"""Check if this is a Cloudflare HTML error response.
|
|
139
|
+
|
|
140
|
+
Cloudflare often returns HTML error pages with status 400 when
|
|
141
|
+
there are authentication issues.
|
|
142
|
+
"""
|
|
143
|
+
# Check content type
|
|
144
|
+
content_type = response.headers.get("content-type", "")
|
|
145
|
+
if "text/html" not in content_type.lower():
|
|
146
|
+
return False
|
|
147
|
+
|
|
148
|
+
# Check if body contains Cloudflare markers
|
|
149
|
+
try:
|
|
150
|
+
# Read response body if not already consumed
|
|
151
|
+
if hasattr(response, "_content") and response._content:
|
|
152
|
+
body = response._content.decode("utf-8", errors="ignore")
|
|
153
|
+
else:
|
|
154
|
+
# Try to read the text (this might be already consumed)
|
|
155
|
+
try:
|
|
156
|
+
body = response.text
|
|
157
|
+
except Exception:
|
|
158
|
+
return False
|
|
159
|
+
|
|
160
|
+
# Look for Cloudflare and 400 Bad Request markers
|
|
161
|
+
body_lower = body.lower()
|
|
162
|
+
return "cloudflare" in body_lower and "400 bad request" in body_lower
|
|
163
|
+
except Exception as exc:
|
|
164
|
+
logger.debug("Error checking for Cloudflare error: %s", exc)
|
|
165
|
+
return False
|
|
166
|
+
|
|
114
167
|
def _refresh_claude_oauth_token(self) -> str | None:
|
|
115
168
|
try:
|
|
116
169
|
from code_puppy.plugins.claude_code_oauth.utils import refresh_access_token
|
|
117
170
|
|
|
171
|
+
logger.info("Attempting to refresh Claude Code OAuth token...")
|
|
118
172
|
refreshed_token = refresh_access_token(force=True)
|
|
119
173
|
if refreshed_token:
|
|
120
174
|
self._update_auth_headers(self.headers, refreshed_token)
|
|
175
|
+
logger.info("Successfully refreshed Claude Code OAuth token")
|
|
176
|
+
else:
|
|
177
|
+
logger.warning("Token refresh returned None")
|
|
121
178
|
return refreshed_token
|
|
122
|
-
except Exception:
|
|
179
|
+
except Exception as exc:
|
|
180
|
+
logger.error("Exception during token refresh: %s", exc)
|
|
123
181
|
return None
|
|
124
182
|
|
|
125
183
|
@staticmethod
|
|
@@ -22,6 +22,7 @@ from rich.console import Console
|
|
|
22
22
|
from code_puppy import __version__, callbacks, plugins
|
|
23
23
|
from code_puppy.agents import get_current_agent
|
|
24
24
|
from code_puppy.command_line.attachments import parse_prompt_attachments
|
|
25
|
+
from code_puppy.command_line.clipboard import get_clipboard_manager
|
|
25
26
|
from code_puppy.config import (
|
|
26
27
|
AUTOSAVE_DIR,
|
|
27
28
|
COMMAND_HISTORY_FILE,
|
|
@@ -143,8 +144,8 @@ async def main():
|
|
|
143
144
|
except ImportError:
|
|
144
145
|
emit_system_message("🐶 Code Puppy is Loading...")
|
|
145
146
|
|
|
146
|
-
#
|
|
147
|
-
|
|
147
|
+
# Truecolor warning moved to interactive_mode() so it prints LAST
|
|
148
|
+
# after all the help stuff - max visibility for the ugly red box!
|
|
148
149
|
|
|
149
150
|
available_port = find_available_port()
|
|
150
151
|
if available_port is None:
|
|
@@ -354,6 +355,13 @@ async def interactive_mode(message_renderer, initial_command: str = None) -> Non
|
|
|
354
355
|
emit_system_message(
|
|
355
356
|
"Type @ for path completion, or /model to pick a model. Toggle multiline with Alt+M or F2; newline: Ctrl+J."
|
|
356
357
|
)
|
|
358
|
+
emit_system_message("Paste images: Ctrl+V (even on Mac!), F3, or /paste command.")
|
|
359
|
+
import platform
|
|
360
|
+
|
|
361
|
+
if platform.system() == "Darwin":
|
|
362
|
+
emit_system_message(
|
|
363
|
+
"💡 macOS tip: Use Ctrl+V (not Cmd+V) to paste images in terminal."
|
|
364
|
+
)
|
|
357
365
|
cancel_key = get_cancel_agent_display_name()
|
|
358
366
|
emit_system_message(
|
|
359
367
|
f"Press {cancel_key} during processing to cancel the current task or inference. Use Ctrl+X to interrupt running shell commands."
|
|
@@ -374,6 +382,10 @@ async def interactive_mode(message_renderer, initial_command: str = None) -> Non
|
|
|
374
382
|
|
|
375
383
|
emit_warning(f"MOTD error: {e}")
|
|
376
384
|
|
|
385
|
+
# Print truecolor warning LAST so it's the most visible thing on startup
|
|
386
|
+
# Big ugly red box should be impossible to miss! 🔴
|
|
387
|
+
print_truecolor_warning(display_console)
|
|
388
|
+
|
|
377
389
|
# Initialize the runtime agent manager
|
|
378
390
|
if initial_command:
|
|
379
391
|
from code_puppy.agents import get_current_agent
|
|
@@ -567,6 +579,7 @@ async def interactive_mode(message_renderer, initial_command: str = None) -> Non
|
|
|
567
579
|
|
|
568
580
|
# Check for clear command (supports both `clear` and `/clear`)
|
|
569
581
|
if task.strip().lower() in ("clear", "/clear"):
|
|
582
|
+
from code_puppy.command_line.clipboard import get_clipboard_manager
|
|
570
583
|
from code_puppy.messaging import (
|
|
571
584
|
emit_info,
|
|
572
585
|
emit_system_message,
|
|
@@ -579,6 +592,13 @@ async def interactive_mode(message_renderer, initial_command: str = None) -> Non
|
|
|
579
592
|
emit_warning("Conversation history cleared!")
|
|
580
593
|
emit_system_message("The agent will not remember previous interactions.")
|
|
581
594
|
emit_info(f"Auto-save session rotated to: {new_session_id}")
|
|
595
|
+
|
|
596
|
+
# Also clear pending clipboard images
|
|
597
|
+
clipboard_manager = get_clipboard_manager()
|
|
598
|
+
clipboard_count = clipboard_manager.get_pending_count()
|
|
599
|
+
clipboard_manager.clear_pending()
|
|
600
|
+
if clipboard_count > 0:
|
|
601
|
+
emit_info(f"Cleared {clipboard_count} pending clipboard image(s)")
|
|
582
602
|
continue
|
|
583
603
|
|
|
584
604
|
# Parse attachments first so leading paths aren't misread as commands
|
|
@@ -761,6 +781,7 @@ async def run_prompt_with_attachments(
|
|
|
761
781
|
tuple: (result, task) where result is the agent response and task is the asyncio task
|
|
762
782
|
"""
|
|
763
783
|
import asyncio
|
|
784
|
+
import re
|
|
764
785
|
|
|
765
786
|
from code_puppy.messaging import emit_system_message, emit_warning
|
|
766
787
|
|
|
@@ -769,21 +790,41 @@ async def run_prompt_with_attachments(
|
|
|
769
790
|
for warning in processed_prompt.warnings:
|
|
770
791
|
emit_warning(warning)
|
|
771
792
|
|
|
793
|
+
# Get clipboard images and merge with file attachments
|
|
794
|
+
clipboard_manager = get_clipboard_manager()
|
|
795
|
+
clipboard_images = clipboard_manager.get_pending_images()
|
|
796
|
+
|
|
797
|
+
# Clear pending clipboard images after retrieval
|
|
798
|
+
clipboard_manager.clear_pending()
|
|
799
|
+
|
|
800
|
+
# Build summary of all attachments
|
|
772
801
|
summary_parts = []
|
|
773
802
|
if processed_prompt.attachments:
|
|
774
|
-
summary_parts.append(f"
|
|
803
|
+
summary_parts.append(f"files: {len(processed_prompt.attachments)}")
|
|
804
|
+
if clipboard_images:
|
|
805
|
+
summary_parts.append(f"clipboard images: {len(clipboard_images)}")
|
|
775
806
|
if processed_prompt.link_attachments:
|
|
776
807
|
summary_parts.append(f"urls: {len(processed_prompt.link_attachments)}")
|
|
777
808
|
if summary_parts:
|
|
778
809
|
emit_system_message("Attachments detected -> " + ", ".join(summary_parts))
|
|
779
810
|
|
|
780
|
-
|
|
811
|
+
# Clean up clipboard placeholders from the prompt text
|
|
812
|
+
cleaned_prompt = processed_prompt.prompt
|
|
813
|
+
if clipboard_images and cleaned_prompt:
|
|
814
|
+
cleaned_prompt = re.sub(
|
|
815
|
+
r"\[📋 clipboard image \d+\]\s*", "", cleaned_prompt
|
|
816
|
+
).strip()
|
|
817
|
+
|
|
818
|
+
if not cleaned_prompt:
|
|
781
819
|
emit_warning(
|
|
782
820
|
"Prompt is empty after removing attachments; add instructions and retry."
|
|
783
821
|
)
|
|
784
822
|
return None, None
|
|
785
823
|
|
|
824
|
+
# Combine file attachments with clipboard images
|
|
786
825
|
attachments = [attachment.content for attachment in processed_prompt.attachments]
|
|
826
|
+
attachments.extend(clipboard_images) # Add clipboard images
|
|
827
|
+
|
|
787
828
|
link_attachments = [link.url_part for link in processed_prompt.link_attachments]
|
|
788
829
|
|
|
789
830
|
# IMPORTANT: Set the shared console on the agent so that streaming output
|
|
@@ -795,7 +836,7 @@ async def run_prompt_with_attachments(
|
|
|
795
836
|
# Create the agent task first so we can track and cancel it
|
|
796
837
|
agent_task = asyncio.create_task(
|
|
797
838
|
agent.run_with_mcp(
|
|
798
|
-
|
|
839
|
+
cleaned_prompt, # Use cleaned prompt (clipboard placeholders removed)
|
|
799
840
|
attachments=attachments,
|
|
800
841
|
link_attachments=link_attachments,
|
|
801
842
|
)
|