code-puppy 0.0.960__tar.gz → 0.0.962__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.960 → code_puppy-0.0.962}/PKG-INFO +4 -3
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/install_menu.py +6 -6
- code_puppy-0.0.962/code_puppy/early_startup.py +93 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/i18n/locales/en-US.json +52 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/i18n/locales/es.json +52 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/i18n/locales/fr-CA.json +52 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/main.py +8 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/blocking_startup.py +13 -98
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/menu_lifecycle.py +0 -1
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/browser/browser_scripts.py +81 -17
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/browser/browser_workflows.py +18 -11
- {code_puppy-0.0.960 → code_puppy-0.0.962}/pyproject.toml +7 -3
- {code_puppy-0.0.960 → code_puppy-0.0.962}/.gitignore +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/LICENSE +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/README.md +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/__main__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/_plugin_i18n_lifecycle.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/_pydantic_tool_helpers.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/_pydantic_video_patch.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agent_completion_inbox.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agent_execution_context.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_builder.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_code_mode.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_code_mode_guidance.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_code_mode_session.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_compaction.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_diagnostics.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_foreign_thinking.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_history.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_key_listeners.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_mcp.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_model_message_transform.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_multimodal_error_hint.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_non_streaming_render.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_output_limits.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_rules.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_run_signals.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_runtime.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_steer_processor.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_subagent_recursion.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_token_limit_hint.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_tty_modes.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_windows_console.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/_wire_tool_names.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/agent_code_puppy.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/agent_creator_agent.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/agent_helios.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/agent_manager.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/agent_model_judge.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/agent_planning.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/agent_qa_kitten.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/agent_web_retriever.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/base_agent.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/event_stream_handler.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/json_agent.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/retry_checkpoint.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/retry_profiles.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/run_invocation.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/run_stats.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/smooth_stream.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/stream_status.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/subagent_stream_handler.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/agents/thinking_output.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/asyncio_cleanup.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/atomic_io.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/atomic_json.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/ca_bundle.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/callbacks.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/capabilities/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/capabilities/compaction.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/capabilities/eager_timing.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/chatgpt_codex_client.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/claude_cache_client.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/claude_oauth_transport.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/claude_thinking_display.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/cli_runner.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/add_model_details.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/add_model_menu.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/add_model_menus.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/add_model_vllm.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/agent_menu.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/attachments.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/autosave_menu.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/autosave_search.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/clipboard.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/colors_menu.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/command_handler.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/command_registry.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/completers.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/completion_cache.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/config_apply.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/config_commands.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/core_commands.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/file_index.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/file_path_completion.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/help_catalog.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/help_overlay.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/image_utils.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/load_context_completion.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/base.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/edit_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/handler.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/help_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/install_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/list_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/logs_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/mcp_servers_store.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/remove_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/restart_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/search_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/silence_warning_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/start_all_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/start_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/status_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/stop_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/trust_command.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/utils.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp_binding_menu.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/mcp_completion.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/menu_session.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/model_picker_completion.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/model_settings_defs.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/model_settings_menu.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/onboarding_slides.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/onboarding_wizard.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/pagination.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/pin_command_completion.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/refresh_models.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/session_browser.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/session_browser_data.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/session_commands.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/set_menu.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/set_menu_catalog.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/set_menu_schema.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/set_menu_settings.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/set_menu_shims.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/set_menu_values.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/shell_passthrough.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/skills_completion.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/tui_style.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/uc_menu.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/command_line/utils.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/config.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/config_file.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/context_accounting.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/diagnostics.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/error_format.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/error_hooks.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/error_logging.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/error_policy.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/error_redaction.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/events/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/events/bridge.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/file_completion_io.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/file_completion_tokens.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/gemini_code_assist.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/gemini_common.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/gemini_model.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/hook_engine/README.md +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/hook_engine/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/hook_engine/aliases.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/hook_engine/engine.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/hook_engine/executor.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/hook_engine/matcher.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/hook_engine/models.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/hook_engine/registry.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/hook_engine/validator.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/http_retry.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/http_utils.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/httpx2_utils.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/i18n/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/i18n/audit.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/i18n/catalog.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/i18n/formats.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/i18n/interpolation.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/i18n/locale.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/i18n/plugin_catalog.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/i18n/plurals.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/i18n/pseudo.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/i18n/translate.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/kennel_provider.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/keymap.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/list_filtering.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/malloc_noise_guard.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/agent_bindings.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/async_lifecycle.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/circuit_breaker.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/config_wizard.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/dashboard.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/error_isolation.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/examples/retry_example.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/health_monitor.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/http_auth.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/managed_server.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/manager.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/manager_lifecycle.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/mcp_logs.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/project_config.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/registry.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/retry_manager.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/server_registry_catalog.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/status_tracker.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/system_tools.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/tool_arg_coercion.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_/toolset_utils.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_prompts/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/mcp_prompts/hook_creator.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/bar_painters.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/bar_rendering.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/bottom_bar.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/bus.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/chords.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/commands.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/editor_actions.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/editor_completion.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/editor_display.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/editor_history.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/editor_keys.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/editor_paste.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/editor_queue.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/editor_submission.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/editor_undo.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/external_editor.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/identity_line.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/idle_status.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/inline_bar.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/line_editor.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/markdown_patches.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/message_queue.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/messages.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/pause_controller.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/prompt_prefix_style.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/queue_console.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/renderers.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/rich_renderer.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/run_ui.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/run_ui_wiring.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/safe_console.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/safe_stream.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/speculation_line.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/speculation_stats.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/speculation_toggle.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/spinner/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/status_line.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/subagent_console.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/theme_accent.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/tool_output.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/messaging/transcript_guard.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/model_descriptions.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/model_factory.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/model_switching.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/model_utils.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/models.json +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/models_dev_api.json +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/models_dev_family.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/models_dev_parser.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/observability.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/platform_utils.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/plugins/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/plugins/config.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/plugins/oauth_pasteback.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/plugins/oauth_puppy_html.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/plugins/prewarm_sdks/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/plugins/prewarm_sdks/prewarm.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/plugins/prewarm_sdks/register_callbacks.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/plugins/trust.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/plugins/trust_notice.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/private_inference.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/provider_credentials.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/provider_identity.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/pydantic_patches.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/reopenable_async_client.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/round_robin_model.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/secret_store.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/secret_store_backends.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/session_format_migration.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/session_lifecycle.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/session_migration.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/session_storage.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/session_surrogate_unpickler.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/shared_credentials.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/skill_provider.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/splash.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/status_display.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/steer_metadata.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/terminal_utils.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/token_usage.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/_browser_registry.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/_lazy.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/agent_tools.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/approval_feedback.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/ask_user_question/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/ask_user_question/constants.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/ask_user_question/demo_tui.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/ask_user_question/handler.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/ask_user_question/models.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/ask_user_question/registration.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/ask_user_question/renderers.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/ask_user_question/terminal_ui.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/ask_user_question/theme.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/ask_user_question/tui_loop.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/browser/__init__.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/browser/browser_control.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/browser/browser_interactions.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/browser/browser_locator_resolver.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/browser/browser_locators.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/browser/browser_manager.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/browser/browser_navigation.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/browser/browser_page_snapshot.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/browser/browser_screenshot.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/browser/browser_semantic_interactions.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/browser/tool_registry.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/command_runner.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/common.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/display.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/file_modifications.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/file_operations.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/file_permission_state.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/fs_access.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/image_tools.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/io_backends.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/model_tools.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/ripgrep.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/shell_backgrounding.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/skills_tools.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/subagent_context.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/subagent_invocation.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/subagent_usage_metrics.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/tools_content.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/universal_constructor.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/tools/win_shell_io.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/undo_manager.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/universal_constructor_provider.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/version_checker.py +0 -0
- {code_puppy-0.0.960 → code_puppy-0.0.962}/code_puppy/zai_model.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: code-puppy
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.962
|
|
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
|
|
@@ -20,7 +20,8 @@ Requires-Dist: anthropic<2,>=1.0.0
|
|
|
20
20
|
Requires-Dist: anyio>=4.14.2
|
|
21
21
|
Requires-Dist: azure-identity>=1.15.0
|
|
22
22
|
Requires-Dist: boto3>=1.43.9
|
|
23
|
-
Requires-Dist: code-puppy-core-plugins>=0.0.
|
|
23
|
+
Requires-Dist: code-puppy-core-plugins>=0.0.103
|
|
24
|
+
Requires-Dist: cryptography<49; sys_platform == 'darwin' and platform_machine == 'x86_64'
|
|
24
25
|
Requires-Dist: fastmcp-slim[client]<5,>=3.3.0
|
|
25
26
|
Requires-Dist: httpx2>=2.7
|
|
26
27
|
Requires-Dist: httpx[http2]>=0.24.1
|
|
@@ -47,7 +48,7 @@ Requires-Dist: websockets>=14.0
|
|
|
47
48
|
Provides-Extra: bedrock
|
|
48
49
|
Requires-Dist: boto3>=1.35.0; extra == 'bedrock'
|
|
49
50
|
Provides-Extra: computer-use
|
|
50
|
-
Requires-Dist: code-puppy-core-plugins[computer-use]>=0.0.
|
|
51
|
+
Requires-Dist: code-puppy-core-plugins[computer-use]>=0.0.103; extra == 'computer-use'
|
|
51
52
|
Provides-Extra: durable
|
|
52
53
|
Requires-Dist: dbos>=2.11.0; extra == 'durable'
|
|
53
54
|
Description-Content-Type: text/markdown
|
|
@@ -11,7 +11,8 @@ import os
|
|
|
11
11
|
import textwrap
|
|
12
12
|
from typing import Callable, List
|
|
13
13
|
|
|
14
|
-
from code_puppy.
|
|
14
|
+
from code_puppy.i18n import t
|
|
15
|
+
from code_puppy.messaging import emit_error, emit_warning
|
|
15
16
|
from code_puppy.tools.command_runner import set_awaiting_user_input
|
|
16
17
|
|
|
17
18
|
from .catalog_server_installer import (
|
|
@@ -54,13 +55,13 @@ def load_catalog():
|
|
|
54
55
|
|
|
55
56
|
categories = [CUSTOM_SERVER_CATEGORY] + catalog.list_categories()
|
|
56
57
|
if len(categories) <= 1: # Only custom category
|
|
57
|
-
emit_error("
|
|
58
|
+
emit_error(t("mcp.install_menu.no_categories"))
|
|
58
59
|
return catalog, categories
|
|
59
60
|
except ImportError as e:
|
|
60
|
-
emit_error(
|
|
61
|
+
emit_error(t("mcp.install_menu.catalog_unavailable", error=e))
|
|
61
62
|
return None, [CUSTOM_SERVER_CATEGORY]
|
|
62
63
|
except Exception as e:
|
|
63
|
-
emit_error(
|
|
64
|
+
emit_error(t("mcp.install_menu.load_error", error=e))
|
|
64
65
|
return None, [CUSTOM_SERVER_CATEGORY]
|
|
65
66
|
|
|
66
67
|
|
|
@@ -289,7 +290,7 @@ def run_mcp_install_menu(manager) -> bool:
|
|
|
289
290
|
|
|
290
291
|
catalog, categories = load_catalog()
|
|
291
292
|
if not categories:
|
|
292
|
-
emit_warning("
|
|
293
|
+
emit_warning(t("mcp.install_menu.no_catalog"))
|
|
293
294
|
return False
|
|
294
295
|
|
|
295
296
|
set_awaiting_user_input(True)
|
|
@@ -300,7 +301,6 @@ def run_mcp_install_menu(manager) -> bool:
|
|
|
300
301
|
set_awaiting_user_input(False)
|
|
301
302
|
|
|
302
303
|
if selection is None:
|
|
303
|
-
emit_info("Exited MCP server browser")
|
|
304
304
|
return False
|
|
305
305
|
|
|
306
306
|
# Custom server: hand off to the form (it owns its own session).
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Pre-import startup hooks for in-tree plugins.
|
|
2
|
+
|
|
3
|
+
``code_puppy/main.py`` calls :func:`run_early_startup` while the splash is on
|
|
4
|
+
screen and BEFORE the heavy ``cli_runner`` import (pydantic-ai, prompt_toolkit,
|
|
5
|
+
rich, ...). It exists for setup that has to happen before those imports, such
|
|
6
|
+
as sanitising proxy or certificate environment variables that would otherwise
|
|
7
|
+
break them.
|
|
8
|
+
|
|
9
|
+
A plugin opts in by shipping ``code_puppy/plugins/<name>/early_startup.py``
|
|
10
|
+
with a zero-argument ``run()``. The rules:
|
|
11
|
+
|
|
12
|
+
* Keep the hook, and the plugin's package ``__init__``, light. Everything here
|
|
13
|
+
runs before the app is ready, so stdlib-only is the goal.
|
|
14
|
+
* Only in-tree plugin directories are scanned. User and project plugins are
|
|
15
|
+
untrusted code and go through the trust-gated loader later, never from here.
|
|
16
|
+
* The plugin enable/disable list is not consulted (configuration is not loaded
|
|
17
|
+
yet), so a hook that needs a kill switch should read its own environment
|
|
18
|
+
variable.
|
|
19
|
+
* A hook that raises is skipped and recorded in ``errors.log`` via
|
|
20
|
+
:func:`report_failures`; startup continues. ``main.py`` calls it right after
|
|
21
|
+
the hooks and before the heavy import, so even a later import crash leaves
|
|
22
|
+
the hook failure on record. ``KeyboardInterrupt`` and ``SystemExit`` still
|
|
23
|
+
propagate.
|
|
24
|
+
|
|
25
|
+
This module is stdlib-only by design, like ``code_puppy.splash`` -- do not
|
|
26
|
+
import anything else from ``code_puppy`` here. The lazy
|
|
27
|
+
``code_puppy.error_logging`` import inside :func:`report_failures` is the
|
|
28
|
+
deliberate exception; it only runs when a hook actually failed.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
import importlib
|
|
34
|
+
import logging
|
|
35
|
+
import os
|
|
36
|
+
from pathlib import Path
|
|
37
|
+
|
|
38
|
+
logger = logging.getLogger(__name__)
|
|
39
|
+
|
|
40
|
+
HOOK_FILE = "early_startup.py"
|
|
41
|
+
_PLUGINS_DIR = Path(__file__).resolve().parent / "plugins"
|
|
42
|
+
_PLUGINS_PACKAGE = "code_puppy.plugins"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def discover() -> list[str]:
|
|
46
|
+
"""Names of in-tree plugins that ship an ``early_startup.py``, sorted."""
|
|
47
|
+
try:
|
|
48
|
+
with os.scandir(_PLUGINS_DIR) as entries:
|
|
49
|
+
return sorted(
|
|
50
|
+
entry.name
|
|
51
|
+
for entry in entries
|
|
52
|
+
if not entry.name.startswith(("_", "."))
|
|
53
|
+
and entry.is_dir()
|
|
54
|
+
and os.path.isfile(os.path.join(entry.path, HOOK_FILE))
|
|
55
|
+
)
|
|
56
|
+
except OSError:
|
|
57
|
+
return []
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def run_early_startup() -> list[tuple[str, Exception]]:
|
|
61
|
+
"""Run every discovered plugin's ``run()``, in name order. Never raises.
|
|
62
|
+
|
|
63
|
+
Returns ``(plugin name, exception)`` for each hook that failed, for
|
|
64
|
+
:func:`report_failures`.
|
|
65
|
+
"""
|
|
66
|
+
failures: list[tuple[str, Exception]] = []
|
|
67
|
+
for name in discover():
|
|
68
|
+
try:
|
|
69
|
+
module = importlib.import_module(f"{_PLUGINS_PACKAGE}.{name}.early_startup")
|
|
70
|
+
module.run()
|
|
71
|
+
except Exception as exc:
|
|
72
|
+
logger.debug("early startup hook of plugin %r failed", name, exc_info=True)
|
|
73
|
+
failures.append((name, exc))
|
|
74
|
+
return failures
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def report_failures(failures: list[tuple[str, Exception]]) -> None:
|
|
78
|
+
"""Record failed hooks in ``errors.log``. Never raises."""
|
|
79
|
+
if not failures:
|
|
80
|
+
return
|
|
81
|
+
try:
|
|
82
|
+
from code_puppy.error_logging import log_error
|
|
83
|
+
|
|
84
|
+
for name, exc in failures:
|
|
85
|
+
log_error(
|
|
86
|
+
exc,
|
|
87
|
+
context=(
|
|
88
|
+
"code_puppy.early_startup::run_early_startup: "
|
|
89
|
+
f"early startup hook of plugin {name!r} failed"
|
|
90
|
+
),
|
|
91
|
+
)
|
|
92
|
+
except Exception:
|
|
93
|
+
logger.debug("reporting early startup hook failures failed", exc_info=True)
|
|
@@ -53,6 +53,52 @@
|
|
|
53
53
|
"ask_user_question.question.select_multiple": "(select multiple)",
|
|
54
54
|
"ask_user_question.render.error": "[render error: {error_type}: {error}]",
|
|
55
55
|
"ask_user_question.timeout.warning": "Timeout in {remaining}s - press any key to continue",
|
|
56
|
+
"browser.automation.clear_highlights": "BROWSER CLEAR HIGHLIGHTS 🧹",
|
|
57
|
+
"browser.automation.element_highlighted": "Highlighted element: {selector}",
|
|
58
|
+
"browser.automation.element_now_attached": "Element {selector} is now attached",
|
|
59
|
+
"browser.automation.element_now_detached": "Element {selector} is now detached",
|
|
60
|
+
"browser.automation.element_now_hidden": "Element {selector} is now hidden",
|
|
61
|
+
"browser.automation.element_now_visible": "Element {selector} is now visible",
|
|
62
|
+
"browser.automation.execute_js": "BROWSER EXECUTE JS 📜 {details}",
|
|
63
|
+
"browser.automation.highlight_element": "BROWSER HIGHLIGHT ELEMENT 🔦 {details}",
|
|
64
|
+
"browser.automation.highlights_cleared": {
|
|
65
|
+
"one": "Cleared {count} highlight",
|
|
66
|
+
"other": "Cleared {count} highlights"
|
|
67
|
+
},
|
|
68
|
+
"browser.automation.js_executed": "JavaScript executed successfully",
|
|
69
|
+
"browser.automation.js_failed": "JavaScript execution failed: {error}",
|
|
70
|
+
"browser.automation.list_workflows": "LIST WORKFLOWS",
|
|
71
|
+
"browser.automation.read_workflow": "READ WORKFLOW {details}",
|
|
72
|
+
"browser.automation.save_workflow": "SAVE WORKFLOW 💾 {details}",
|
|
73
|
+
"browser.automation.scroll": "BROWSER SCROLL {details}",
|
|
74
|
+
"browser.automation.scroll_direction_unknown": "Unknown scroll direction: '{direction}'",
|
|
75
|
+
"browser.automation.scroll_to_element": "BROWSER SCROLL TO ELEMENT 🎯 {details}",
|
|
76
|
+
"browser.automation.scrolled_element_down": "Scrolled element '{selector}' down",
|
|
77
|
+
"browser.automation.scrolled_element_left": "Scrolled element '{selector}' left",
|
|
78
|
+
"browser.automation.scrolled_element_right": "Scrolled element '{selector}' right",
|
|
79
|
+
"browser.automation.scrolled_element_up": "Scrolled element '{selector}' up",
|
|
80
|
+
"browser.automation.scrolled_page_down": "Scrolled page down",
|
|
81
|
+
"browser.automation.scrolled_page_left": "Scrolled page left",
|
|
82
|
+
"browser.automation.scrolled_page_right": "Scrolled page right",
|
|
83
|
+
"browser.automation.scrolled_page_up": "Scrolled page up",
|
|
84
|
+
"browser.automation.scrolled_to_element": "Scrolled to element: {selector}",
|
|
85
|
+
"browser.automation.set_viewport": "BROWSER SET VIEWPORT 🖥️ {details}",
|
|
86
|
+
"browser.automation.viewport_set": "Set viewport size to {size}",
|
|
87
|
+
"browser.automation.wait_for_element": "BROWSER WAIT FOR ELEMENT {details}",
|
|
88
|
+
"browser.automation.workflow_not_found": "Workflow not found: {name}",
|
|
89
|
+
"browser.automation.workflow_read": {
|
|
90
|
+
"one": "Workflow read successfully: {count} character",
|
|
91
|
+
"other": "Workflow read successfully: {count} characters"
|
|
92
|
+
},
|
|
93
|
+
"browser.automation.workflow_read_failed": "Failed to read workflow: {error}",
|
|
94
|
+
"browser.automation.workflow_save_failed": "Failed to save workflow: {error}",
|
|
95
|
+
"browser.automation.workflow_saved": "Workflow saved successfully: {path}",
|
|
96
|
+
"browser.automation.workflow_unreadable": "Could not read {path}: {error}",
|
|
97
|
+
"browser.automation.workflows_found": {
|
|
98
|
+
"one": "Found {count} workflow",
|
|
99
|
+
"other": "Found {count} workflows"
|
|
100
|
+
},
|
|
101
|
+
"browser.automation.workflows_list_failed": "Failed to list workflows: {error}",
|
|
56
102
|
"browser.chromium.install_failed": "Chromium is missing and automatic installation failed (exit code {exit_code}). Run this command and retry:\n{command}\n\nInstaller output:\n{output}",
|
|
57
103
|
"browser.chromium.install_no_output": "No installer output was produced.",
|
|
58
104
|
"browser.chromium.install_start_failed": "Chromium is missing and its installer could not start: {error}\nRun this command and retry:\n{command}",
|
|
@@ -436,6 +482,10 @@
|
|
|
436
482
|
"mcp.install.no_description": "No description available",
|
|
437
483
|
"mcp.install.no_server_found": "No server found matching '{server}'",
|
|
438
484
|
"mcp.install.registry_unavailable": "Server registry not available",
|
|
485
|
+
"mcp.install_menu.catalog_unavailable": "Server catalog not available: {error}",
|
|
486
|
+
"mcp.install_menu.load_error": "Error loading server catalog: {error}",
|
|
487
|
+
"mcp.install_menu.no_catalog": "No MCP server catalog available.",
|
|
488
|
+
"mcp.install_menu.no_categories": "No categories found in server catalog",
|
|
439
489
|
"mcp.install_wizard.already_set": "Already set",
|
|
440
490
|
"mcp.install_wizard.cancelled": "Installation cancelled",
|
|
441
491
|
"mcp.install_wizard.catalog_unavailable": "Server catalog not available",
|
|
@@ -597,6 +647,8 @@
|
|
|
597
647
|
"other": "✓ Also unbound from {count} agents: {agents}"
|
|
598
648
|
},
|
|
599
649
|
"mcp.server.usage": "Usage: /mcp {command} <server_name>",
|
|
650
|
+
"mcp.startup.not_started": "MCP server '{server}' didn't start. Run {logs_command} to investigate, or unbind it via {agents_command}.",
|
|
651
|
+
"mcp.startup.stderr_line": "MCP {server}: {line}",
|
|
600
652
|
"mcp.state.error": "⚠ Err",
|
|
601
653
|
"mcp.state.quarantined": "⏸ Quar",
|
|
602
654
|
"mcp.state.running": "✓ Run",
|
|
@@ -53,6 +53,52 @@
|
|
|
53
53
|
"ask_user_question.question.select_multiple": "(selección múltiple)",
|
|
54
54
|
"ask_user_question.render.error": "[error de renderizado: {error_type}: {error}]",
|
|
55
55
|
"ask_user_question.timeout.warning": "Tiempo de espera en {remaining}s - pulsa cualquier tecla para continuar",
|
|
56
|
+
"browser.automation.clear_highlights": "QUITAR RESALTADOS EN EL NAVEGADOR 🧹",
|
|
57
|
+
"browser.automation.element_highlighted": "Elemento resaltado: {selector}",
|
|
58
|
+
"browser.automation.element_now_attached": "El elemento {selector} ya está en el DOM",
|
|
59
|
+
"browser.automation.element_now_detached": "El elemento {selector} ya no está en el DOM",
|
|
60
|
+
"browser.automation.element_now_hidden": "El elemento {selector} ahora está oculto",
|
|
61
|
+
"browser.automation.element_now_visible": "El elemento {selector} ahora está visible",
|
|
62
|
+
"browser.automation.execute_js": "EJECUTAR JS EN EL NAVEGADOR 📜 {details}",
|
|
63
|
+
"browser.automation.highlight_element": "RESALTAR ELEMENTO EN EL NAVEGADOR 🔦 {details}",
|
|
64
|
+
"browser.automation.highlights_cleared": {
|
|
65
|
+
"one": "Se quitó {count} resaltado",
|
|
66
|
+
"other": "Se quitaron {count} resaltados"
|
|
67
|
+
},
|
|
68
|
+
"browser.automation.js_executed": "JavaScript se ejecutó correctamente",
|
|
69
|
+
"browser.automation.js_failed": "No se pudo ejecutar JavaScript: {error}",
|
|
70
|
+
"browser.automation.list_workflows": "LISTAR FLUJOS DE TRABAJO",
|
|
71
|
+
"browser.automation.read_workflow": "LEER FLUJO DE TRABAJO {details}",
|
|
72
|
+
"browser.automation.save_workflow": "GUARDAR FLUJO DE TRABAJO 💾 {details}",
|
|
73
|
+
"browser.automation.scroll": "DESPLAZAR EN EL NAVEGADOR {details}",
|
|
74
|
+
"browser.automation.scroll_direction_unknown": "Dirección de desplazamiento desconocida: '{direction}'",
|
|
75
|
+
"browser.automation.scroll_to_element": "DESPLAZAR HASTA EL ELEMENTO EN EL NAVEGADOR 🎯 {details}",
|
|
76
|
+
"browser.automation.scrolled_element_down": "Se desplazó el elemento '{selector}' hacia abajo",
|
|
77
|
+
"browser.automation.scrolled_element_left": "Se desplazó el elemento '{selector}' hacia la izquierda",
|
|
78
|
+
"browser.automation.scrolled_element_right": "Se desplazó el elemento '{selector}' hacia la derecha",
|
|
79
|
+
"browser.automation.scrolled_element_up": "Se desplazó el elemento '{selector}' hacia arriba",
|
|
80
|
+
"browser.automation.scrolled_page_down": "Se desplazó la página hacia abajo",
|
|
81
|
+
"browser.automation.scrolled_page_left": "Se desplazó la página hacia la izquierda",
|
|
82
|
+
"browser.automation.scrolled_page_right": "Se desplazó la página hacia la derecha",
|
|
83
|
+
"browser.automation.scrolled_page_up": "Se desplazó la página hacia arriba",
|
|
84
|
+
"browser.automation.scrolled_to_element": "Se desplazó hasta el elemento: {selector}",
|
|
85
|
+
"browser.automation.set_viewport": "AJUSTAR VENTANA GRÁFICA DEL NAVEGADOR 🖥️ {details}",
|
|
86
|
+
"browser.automation.viewport_set": "Tamaño de la ventana gráfica establecido en {size}",
|
|
87
|
+
"browser.automation.wait_for_element": "ESPERAR ELEMENTO EN EL NAVEGADOR {details}",
|
|
88
|
+
"browser.automation.workflow_not_found": "Flujo de trabajo no encontrado: {name}",
|
|
89
|
+
"browser.automation.workflow_read": {
|
|
90
|
+
"one": "Flujo de trabajo leído correctamente: {count} carácter",
|
|
91
|
+
"other": "Flujo de trabajo leído correctamente: {count} caracteres"
|
|
92
|
+
},
|
|
93
|
+
"browser.automation.workflow_read_failed": "No se pudo leer el flujo de trabajo: {error}",
|
|
94
|
+
"browser.automation.workflow_save_failed": "No se pudo guardar el flujo de trabajo: {error}",
|
|
95
|
+
"browser.automation.workflow_saved": "Flujo de trabajo guardado correctamente: {path}",
|
|
96
|
+
"browser.automation.workflow_unreadable": "No se pudo leer {path}: {error}",
|
|
97
|
+
"browser.automation.workflows_found": {
|
|
98
|
+
"one": "Se encontró {count} flujo de trabajo",
|
|
99
|
+
"other": "Se encontraron {count} flujos de trabajo"
|
|
100
|
+
},
|
|
101
|
+
"browser.automation.workflows_list_failed": "No se pudieron listar los flujos de trabajo: {error}",
|
|
56
102
|
"browser.chromium.install_failed": "Chromium no está instalado y la instalación automática falló (código de salida {exit_code}). Ejecuta este comando y vuelve a intentarlo:\n{command}\n\nSalida del instalador:\n{output}",
|
|
57
103
|
"browser.chromium.install_no_output": "El instalador no produjo ninguna salida.",
|
|
58
104
|
"browser.chromium.install_start_failed": "Chromium no está instalado y no se pudo iniciar su instalador: {error}\nEjecuta este comando y vuelve a intentarlo:\n{command}",
|
|
@@ -436,6 +482,10 @@
|
|
|
436
482
|
"mcp.install.no_description": "No hay descripción disponible",
|
|
437
483
|
"mcp.install.no_server_found": "No se encontró ningún servidor que coincida con '{server}'",
|
|
438
484
|
"mcp.install.registry_unavailable": "Registro de servidores no disponible",
|
|
485
|
+
"mcp.install_menu.catalog_unavailable": "El catálogo de servidores no está disponible: {error}",
|
|
486
|
+
"mcp.install_menu.load_error": "Error al cargar el catálogo de servidores: {error}",
|
|
487
|
+
"mcp.install_menu.no_catalog": "No hay ningún catálogo de servidores MCP disponible.",
|
|
488
|
+
"mcp.install_menu.no_categories": "No se encontraron categorías en el catálogo de servidores",
|
|
439
489
|
"mcp.install_wizard.already_set": "Ya configurada",
|
|
440
490
|
"mcp.install_wizard.cancelled": "Instalación cancelada",
|
|
441
491
|
"mcp.install_wizard.catalog_unavailable": "El catálogo de servidores no está disponible",
|
|
@@ -597,6 +647,8 @@
|
|
|
597
647
|
"other": "✓ También se desvinculó de {count} agentes: {agents}"
|
|
598
648
|
},
|
|
599
649
|
"mcp.server.usage": "Uso: /mcp {command} <server_name>",
|
|
650
|
+
"mcp.startup.not_started": "El servidor MCP '{server}' no se inició. Ejecuta {logs_command} para investigar o desvincúlalo con {agents_command}.",
|
|
651
|
+
"mcp.startup.stderr_line": "MCP {server}: {line}",
|
|
600
652
|
"mcp.state.error": "⚠ Error",
|
|
601
653
|
"mcp.state.quarantined": "⏸ Cuarentena",
|
|
602
654
|
"mcp.state.running": "✓ Activo",
|
|
@@ -53,6 +53,52 @@
|
|
|
53
53
|
"ask_user_question.question.select_multiple": "(sélection multiple)",
|
|
54
54
|
"ask_user_question.render.error": "[erreur de rendu : {error_type} : {error}]",
|
|
55
55
|
"ask_user_question.timeout.warning": "Délai dans {remaining}s - appuyez sur une touche pour continuer",
|
|
56
|
+
"browser.automation.clear_highlights": "EFFACER LES SURLIGNAGES DANS LE NAVIGATEUR 🧹",
|
|
57
|
+
"browser.automation.element_highlighted": "Élément surligné : {selector}",
|
|
58
|
+
"browser.automation.element_now_attached": "L’élément {selector} est maintenant dans le DOM",
|
|
59
|
+
"browser.automation.element_now_detached": "L’élément {selector} n’est plus dans le DOM",
|
|
60
|
+
"browser.automation.element_now_hidden": "L’élément {selector} est maintenant masqué",
|
|
61
|
+
"browser.automation.element_now_visible": "L’élément {selector} est maintenant visible",
|
|
62
|
+
"browser.automation.execute_js": "EXÉCUTER DU JS DANS LE NAVIGATEUR 📜 {details}",
|
|
63
|
+
"browser.automation.highlight_element": "SURLIGNER UN ÉLÉMENT DANS LE NAVIGATEUR 🔦 {details}",
|
|
64
|
+
"browser.automation.highlights_cleared": {
|
|
65
|
+
"one": "{count} surlignage effacé",
|
|
66
|
+
"other": "{count} surlignages effacés"
|
|
67
|
+
},
|
|
68
|
+
"browser.automation.js_executed": "JavaScript exécuté avec succès",
|
|
69
|
+
"browser.automation.js_failed": "Échec de l’exécution du JavaScript : {error}",
|
|
70
|
+
"browser.automation.list_workflows": "LISTER LES FLUX DE TRAVAIL",
|
|
71
|
+
"browser.automation.read_workflow": "LIRE LE FLUX DE TRAVAIL {details}",
|
|
72
|
+
"browser.automation.save_workflow": "ENREGISTRER LE FLUX DE TRAVAIL 💾 {details}",
|
|
73
|
+
"browser.automation.scroll": "FAIRE DÉFILER DANS LE NAVIGATEUR {details}",
|
|
74
|
+
"browser.automation.scroll_direction_unknown": "Direction de défilement inconnue : « {direction} »",
|
|
75
|
+
"browser.automation.scroll_to_element": "FAIRE DÉFILER JUSQU’À L’ÉLÉMENT DANS LE NAVIGATEUR 🎯 {details}",
|
|
76
|
+
"browser.automation.scrolled_element_down": "Défilement de l’élément « {selector} » vers le bas",
|
|
77
|
+
"browser.automation.scrolled_element_left": "Défilement de l’élément « {selector} » vers la gauche",
|
|
78
|
+
"browser.automation.scrolled_element_right": "Défilement de l’élément « {selector} » vers la droite",
|
|
79
|
+
"browser.automation.scrolled_element_up": "Défilement de l’élément « {selector} » vers le haut",
|
|
80
|
+
"browser.automation.scrolled_page_down": "Défilement de la page vers le bas",
|
|
81
|
+
"browser.automation.scrolled_page_left": "Défilement de la page vers la gauche",
|
|
82
|
+
"browser.automation.scrolled_page_right": "Défilement de la page vers la droite",
|
|
83
|
+
"browser.automation.scrolled_page_up": "Défilement de la page vers le haut",
|
|
84
|
+
"browser.automation.scrolled_to_element": "Défilement jusqu’à l’élément : {selector}",
|
|
85
|
+
"browser.automation.set_viewport": "DÉFINIR LA FENÊTRE D’AFFICHAGE DU NAVIGATEUR 🖥️ {details}",
|
|
86
|
+
"browser.automation.viewport_set": "Taille de la fenêtre d’affichage définie à {size}",
|
|
87
|
+
"browser.automation.wait_for_element": "ATTENDRE UN ÉLÉMENT DANS LE NAVIGATEUR {details}",
|
|
88
|
+
"browser.automation.workflow_not_found": "Flux de travail introuvable : {name}",
|
|
89
|
+
"browser.automation.workflow_read": {
|
|
90
|
+
"one": "Flux de travail lu avec succès : {count} caractère",
|
|
91
|
+
"other": "Flux de travail lu avec succès : {count} caractères"
|
|
92
|
+
},
|
|
93
|
+
"browser.automation.workflow_read_failed": "Échec de la lecture du flux de travail : {error}",
|
|
94
|
+
"browser.automation.workflow_save_failed": "Échec de l’enregistrement du flux de travail : {error}",
|
|
95
|
+
"browser.automation.workflow_saved": "Flux de travail enregistré avec succès : {path}",
|
|
96
|
+
"browser.automation.workflow_unreadable": "Impossible de lire {path} : {error}",
|
|
97
|
+
"browser.automation.workflows_found": {
|
|
98
|
+
"one": "{count} flux de travail trouvé",
|
|
99
|
+
"other": "{count} flux de travail trouvés"
|
|
100
|
+
},
|
|
101
|
+
"browser.automation.workflows_list_failed": "Impossible de lister les flux de travail : {error}",
|
|
56
102
|
"browser.chromium.install_failed": "Chromium n’est pas installé et l’installation automatique a échoué (code de sortie {exit_code}). Exécutez cette commande et réessayez :\n{command}\n\nSortie de l’installateur :\n{output}",
|
|
57
103
|
"browser.chromium.install_no_output": "L’installateur n’a produit aucune sortie.",
|
|
58
104
|
"browser.chromium.install_start_failed": "Chromium n’est pas installé et son installateur n’a pas pu démarrer : {error}\nExécutez cette commande et réessayez :\n{command}",
|
|
@@ -436,6 +482,10 @@
|
|
|
436
482
|
"mcp.install.no_description": "Aucune description disponible",
|
|
437
483
|
"mcp.install.no_server_found": "Aucun serveur ne correspond à « {server} »",
|
|
438
484
|
"mcp.install.registry_unavailable": "Registre de serveurs indisponible",
|
|
485
|
+
"mcp.install_menu.catalog_unavailable": "Catalogue de serveurs non disponible : {error}",
|
|
486
|
+
"mcp.install_menu.load_error": "Erreur de chargement du catalogue de serveurs : {error}",
|
|
487
|
+
"mcp.install_menu.no_catalog": "Aucun catalogue de serveurs MCP disponible.",
|
|
488
|
+
"mcp.install_menu.no_categories": "Aucune catégorie trouvée dans le catalogue de serveurs",
|
|
439
489
|
"mcp.install_wizard.already_set": "Déjà configurée",
|
|
440
490
|
"mcp.install_wizard.cancelled": "Installation annulée",
|
|
441
491
|
"mcp.install_wizard.catalog_unavailable": "Catalogue de serveurs non disponible",
|
|
@@ -597,6 +647,8 @@
|
|
|
597
647
|
"other": "✓ Également dissocié de {count} agents : {agents}"
|
|
598
648
|
},
|
|
599
649
|
"mcp.server.usage": "Utilisation : /mcp {command} <server_name>",
|
|
650
|
+
"mcp.startup.not_started": "Le serveur MCP « {server} » n’a pas démarré. Exécutez {logs_command} pour enquêter, ou dissociez-le via {agents_command}.",
|
|
651
|
+
"mcp.startup.stderr_line": "MCP {server} : {line}",
|
|
600
652
|
"mcp.state.error": "⚠ Erreur",
|
|
601
653
|
"mcp.state.quarantined": "⏸ Quarantaine",
|
|
602
654
|
"mcp.state.running": "✓ Actif",
|
|
@@ -7,6 +7,9 @@ The neon splash starts BEFORE the cli_runner import below: that import pulls
|
|
|
7
7
|
in pydantic-ai, prompt_toolkit, rich, and friends (~seconds of cold start),
|
|
8
8
|
which is exactly the window the shimmer covers. ``code_puppy.splash`` is
|
|
9
9
|
stdlib-only by design -- keep it that way, and keep it first.
|
|
10
|
+
|
|
11
|
+
In-tree plugins that must run setup before those heavy imports (see
|
|
12
|
+
``code_puppy.early_startup``) are given their turn inside the same window.
|
|
10
13
|
"""
|
|
11
14
|
|
|
12
15
|
from code_puppy.splash import start_splash
|
|
@@ -24,6 +27,11 @@ try:
|
|
|
24
27
|
logging.getLogger(__name__).debug(
|
|
25
28
|
"installing the error hooks failed", exc_info=True
|
|
26
29
|
)
|
|
30
|
+
# Plugin setup that must precede the heavy imports. Failed hooks are
|
|
31
|
+
# recorded in errors.log before the runner import; never raises.
|
|
32
|
+
from code_puppy.early_startup import report_failures, run_early_startup
|
|
33
|
+
|
|
34
|
+
report_failures(run_early_startup())
|
|
27
35
|
from code_puppy.cli_runner import main_entry
|
|
28
36
|
finally:
|
|
29
37
|
_splash.stop()
|
|
@@ -20,6 +20,7 @@ from typing import Any, List, Optional, Sequence
|
|
|
20
20
|
from fastmcp.client.transports import StdioTransport
|
|
21
21
|
from pydantic_ai.mcp import MCPToolset
|
|
22
22
|
|
|
23
|
+
from code_puppy.i18n import t
|
|
23
24
|
from code_puppy.mcp_.mcp_logs import get_log_file_path, rotate_log_if_needed, write_log
|
|
24
25
|
from code_puppy.messaging import emit_info
|
|
25
26
|
|
|
@@ -105,7 +106,11 @@ class StderrFileCapture:
|
|
|
105
106
|
self.captured_lines.append(line)
|
|
106
107
|
if self.emit_to_user:
|
|
107
108
|
emit_info(
|
|
108
|
-
|
|
109
|
+
t(
|
|
110
|
+
"mcp.startup.stderr_line",
|
|
111
|
+
server=self.server_name,
|
|
112
|
+
line=line,
|
|
113
|
+
),
|
|
109
114
|
message_group=self.message_group,
|
|
110
115
|
)
|
|
111
116
|
except Exception:
|
|
@@ -218,10 +223,14 @@ class BlockingStdioToolset(MCPToolset):
|
|
|
218
223
|
|
|
219
224
|
# Point the user to /mcp logs; error_details stay out of the prompt
|
|
220
225
|
# (already in the log file — no stack-trace spam on every run).
|
|
226
|
+
# Commands are placeholders so translations cannot break them.
|
|
221
227
|
emit_info(
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
228
|
+
t(
|
|
229
|
+
"mcp.startup.not_started",
|
|
230
|
+
server=self.server_name,
|
|
231
|
+
logs_command=f"/mcp logs {self.server_name}",
|
|
232
|
+
agents_command="/agents → B",
|
|
233
|
+
),
|
|
225
234
|
style="yellow",
|
|
226
235
|
message_group=self.message_group,
|
|
227
236
|
)
|
|
@@ -281,97 +290,3 @@ class BlockingStdioToolset(MCPToolset):
|
|
|
281
290
|
def is_ready(self) -> bool:
|
|
282
291
|
"""Check if server is ready without blocking."""
|
|
283
292
|
return self._ready_event.is_set() and self._init_error is None
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
class StartupMonitor:
|
|
287
|
-
"""
|
|
288
|
-
Monitor for tracking multiple server startups.
|
|
289
|
-
|
|
290
|
-
This class helps coordinate startup of multiple MCP servers
|
|
291
|
-
and ensures all are ready before proceeding.
|
|
292
|
-
"""
|
|
293
|
-
|
|
294
|
-
def __init__(self, message_group: Optional[uuid.UUID] = None):
|
|
295
|
-
self.servers = {}
|
|
296
|
-
self.startup_times = {}
|
|
297
|
-
self.message_group = message_group or uuid.uuid4()
|
|
298
|
-
|
|
299
|
-
def add_server(self, name: str, server: BlockingStdioToolset):
|
|
300
|
-
"""Add a server to monitor."""
|
|
301
|
-
self.servers[name] = server
|
|
302
|
-
|
|
303
|
-
async def wait_all_ready(self, timeout: float = 30.0) -> dict:
|
|
304
|
-
"""
|
|
305
|
-
Wait for all servers to be ready.
|
|
306
|
-
|
|
307
|
-
Args:
|
|
308
|
-
timeout: Maximum time to wait for all servers
|
|
309
|
-
|
|
310
|
-
Returns:
|
|
311
|
-
Dictionary of server names to ready status
|
|
312
|
-
"""
|
|
313
|
-
import time
|
|
314
|
-
|
|
315
|
-
results = {}
|
|
316
|
-
|
|
317
|
-
# Create tasks for all servers
|
|
318
|
-
async def wait_server(name: str, server: BlockingStdioToolset):
|
|
319
|
-
start = time.time()
|
|
320
|
-
try:
|
|
321
|
-
await server.wait_until_ready(timeout)
|
|
322
|
-
self.startup_times[name] = time.time() - start
|
|
323
|
-
results[name] = True
|
|
324
|
-
emit_info(
|
|
325
|
-
f" {name}: Ready in {self.startup_times[name]:.2f}s",
|
|
326
|
-
style="dim green",
|
|
327
|
-
message_group=self.message_group,
|
|
328
|
-
)
|
|
329
|
-
except Exception as e:
|
|
330
|
-
self.startup_times[name] = time.time() - start
|
|
331
|
-
results[name] = False
|
|
332
|
-
emit_info(
|
|
333
|
-
f" {name}: Failed after {self.startup_times[name]:.2f}s - {e}",
|
|
334
|
-
style="dim red",
|
|
335
|
-
message_group=self.message_group,
|
|
336
|
-
)
|
|
337
|
-
|
|
338
|
-
# Wait for all servers in parallel
|
|
339
|
-
emit_info(
|
|
340
|
-
f"Waiting for {len(self.servers)} MCP servers to initialize...",
|
|
341
|
-
style="cyan",
|
|
342
|
-
message_group=self.message_group,
|
|
343
|
-
)
|
|
344
|
-
|
|
345
|
-
tasks = [
|
|
346
|
-
asyncio.create_task(wait_server(name, server))
|
|
347
|
-
for name, server in self.servers.items()
|
|
348
|
-
]
|
|
349
|
-
|
|
350
|
-
await asyncio.gather(*tasks, return_exceptions=True)
|
|
351
|
-
|
|
352
|
-
# Report summary
|
|
353
|
-
ready_count = sum(1 for r in results.values() if r)
|
|
354
|
-
total_count = len(results)
|
|
355
|
-
|
|
356
|
-
if ready_count == total_count:
|
|
357
|
-
emit_info(
|
|
358
|
-
f"All {total_count} servers ready!",
|
|
359
|
-
style="green bold",
|
|
360
|
-
message_group=self.message_group,
|
|
361
|
-
)
|
|
362
|
-
else:
|
|
363
|
-
emit_info(
|
|
364
|
-
f"{ready_count}/{total_count} servers ready",
|
|
365
|
-
style="yellow",
|
|
366
|
-
message_group=self.message_group,
|
|
367
|
-
)
|
|
368
|
-
|
|
369
|
-
return results
|
|
370
|
-
|
|
371
|
-
def get_startup_report(self) -> str:
|
|
372
|
-
"""Get a report of startup times."""
|
|
373
|
-
lines = ["Server Startup Times:"]
|
|
374
|
-
for name, time_taken in self.startup_times.items():
|
|
375
|
-
status = "[ok]" if self.servers[name].is_ready() else "[failed]"
|
|
376
|
-
lines.append(f" {status} {name}: {time_taken:.2f}s")
|
|
377
|
-
return "\n".join(lines)
|