code-puppy 0.0.641__tar.gz → 0.0.643__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.641 → code_puppy-0.0.643}/PKG-INFO +1 -1
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_runtime.py +39 -8
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/config.py +18 -0
- code_puppy-0.0.643/code_puppy/i18n/__init__.py +79 -0
- code_puppy-0.0.643/code_puppy/i18n/catalog.py +213 -0
- code_puppy-0.0.643/code_puppy/i18n/formats.py +90 -0
- code_puppy-0.0.643/code_puppy/i18n/locale.py +173 -0
- code_puppy-0.0.643/code_puppy/i18n/locales/en-US.json +23 -0
- code_puppy-0.0.643/code_puppy/i18n/locales/es-419.json +17 -0
- code_puppy-0.0.643/code_puppy/i18n/locales/es-AR.json +1 -0
- code_puppy-0.0.643/code_puppy/i18n/locales/es-CL.json +1 -0
- code_puppy-0.0.643/code_puppy/i18n/locales/es-CO.json +1 -0
- code_puppy-0.0.643/code_puppy/i18n/locales/es-MX.json +1 -0
- code_puppy-0.0.643/code_puppy/i18n/locales/es.json +23 -0
- code_puppy-0.0.643/code_puppy/i18n/locales/fr-CA.json +23 -0
- code_puppy-0.0.643/code_puppy/i18n/plurals.py +71 -0
- code_puppy-0.0.643/code_puppy/i18n/pseudo.py +108 -0
- code_puppy-0.0.643/code_puppy/i18n/translate.py +202 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/__init__.py +4 -4
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/bottom_bar.py +26 -2
- code_puppy-0.0.643/code_puppy/messaging/inline_bar.py +190 -0
- code_puppy-0.0.643/code_puppy/messaging/markdown_patches.py +89 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/message_queue.py +14 -1
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/renderers.py +14 -7
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/rich_renderer.py +13 -11
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_hooks/register_callbacks.py +2 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/code_puppy_agent/SKILL.md +81 -8
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/pydantic_patches.py +28 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/version_checker.py +7 -6
- {code_puppy-0.0.641 → code_puppy-0.0.643}/pyproject.toml +1 -1
- code_puppy-0.0.641/code_puppy/messaging/markdown_patches.py +0 -57
- {code_puppy-0.0.641 → code_puppy-0.0.643}/.gitignore +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/LICENSE +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/README.md +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/__main__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_builder.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_compaction.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_diagnostics.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_history.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_key_listeners.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_non_streaming_render.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_run_signals.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_steer_processor.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/agent_code_puppy.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/agent_creator_agent.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/agent_helios.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/agent_manager.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/agent_planning.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/agent_qa_kitten.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/base_agent.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/event_stream_handler.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/json_agent.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/retry_profiles.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/run_stats.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/smooth_stream.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/subagent_stream_handler.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/chatgpt_codex_client.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/claude_cache_client.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/cli_runner.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/add_model_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/agent_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/attachments.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/autosave_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/autosave_search.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/clipboard.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/colors_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/command_handler.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/command_registry.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/config_apply.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/config_commands.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/core_commands.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/diff_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/file_index.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/file_path_completion.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/judges_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/load_context_completion.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/base.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/edit_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/handler.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/help_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/install_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/install_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/list_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/logs_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/remove_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/restart_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/search_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/silence_warning_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/start_all_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/start_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/status_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/stop_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/trust_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/utils.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp_binding_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp_completion.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/model_picker_completion.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/model_settings_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/onboarding_slides.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/onboarding_wizard.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/pagination.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/pin_command_completion.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/session_commands.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/set_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/set_menu_catalog.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/set_menu_render.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/set_menu_schema.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/set_menu_settings.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/set_menu_shims.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/set_menu_values.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/shell_passthrough.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/skills_completion.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/uc_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/utils.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/wiggum_state.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/error_logging.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/gemini_code_assist.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/gemini_model.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/README.md +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/aliases.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/engine.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/executor.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/matcher.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/models.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/registry.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/validator.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/http_utils.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/keymap.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/list_filtering.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/main.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/agent_bindings.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/async_lifecycle.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/blocking_startup.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/captured_stdio_server.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/circuit_breaker.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/config_wizard.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/dashboard.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/error_isolation.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/examples/retry_example.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/health_monitor.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/managed_server.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/manager.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/mcp_logs.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/project_config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/registry.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/retry_manager.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/server_registry_catalog.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/status_tracker.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/system_tools.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/tool_arg_coercion.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_prompts/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_prompts/hook_creator.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/bar_painters.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/bar_rendering.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/bus.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/chords.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/commands.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/editor_actions.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/editor_completion.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/editor_display.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/editor_history.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/editor_keys.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/editor_paste.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/external_editor.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/line_editor.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/messages.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/pause_controller.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/prompt_prefix_style.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/queue_console.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/run_ui.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/run_ui_wiring.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/spinner/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/subagent_console.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/transcript_guard.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/model_descriptions.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/model_factory.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/model_switching.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/model_utils.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/models.json +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/models_dev_api.json +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/models_dev_parser.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/README.md +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/agent.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/bridge.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/capabilities.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/commands.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/content.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/io_delegation.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/mcp_config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/permissions.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/persistence.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/replay.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/session.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/session_config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/state.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/discovery.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/downloader.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/enabled_skills.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/installer.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/metadata.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/prompt_builder.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/remote_catalog.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/skill_catalog.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/skill_commands.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/skills_install_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/skills_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/aws_bedrock/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/aws_bedrock/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/aws_bedrock/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/aws_bedrock/utils.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/azure_foundry/README.md +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/azure_foundry/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/azure_foundry/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/azure_foundry/discovery.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/azure_foundry/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/azure_foundry/token.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/azure_foundry/utils.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/btw/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/btw/inline_view.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/btw/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/btw/side_query.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/chatgpt_oauth/usage.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_hooks/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_hooks/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/fast_mode.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/prompt_handler.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/test_fast_mode.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/utils.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/code_puppy_agent/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/code_puppy_agent/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/context_indicator/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/context_indicator/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/context_indicator/usage.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/copilot_auth/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/copilot_auth/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/copilot_auth/reasoning_client.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/copilot_auth/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/copilot_auth/utils.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/cancel.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/commands.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/lifecycle.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/runtime.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/startup_lock.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/workflow_ids.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/wrapper.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/destructive_command_guard/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/destructive_command_guard/detector.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/destructive_command_guard/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/emoji_filter/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/emoji_filter/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/emoji_filter/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/emoji_filter/stripper.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/empty_html_comment_filter/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/example_custom_command/README.md +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/force_push_guard/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/force_push_guard/detector.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/force_push_guard/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/force_push_guard/test_detector.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/fork/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/fork/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/frontend_emitter/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/frontend_emitter/emitter.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/frontend_emitter/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/frontend_emitter/session_context.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/grok_oauth/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/grok_oauth/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/grok_oauth/oauth_flow.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/grok_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/grok_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/grok_oauth/utils.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/herdr/README.md +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/herdr/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/herdr/client.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/herdr/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/herdr/reporter.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/hook_creator/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/hook_creator/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/hook_manager/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/hook_manager/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/hook_manager/hooks_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/hook_manager/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/no_tools/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/no_tools/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/oauth_pasteback.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/oauth_puppy_html.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/obsidian_agent/README.md +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/obsidian_agent/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/obsidian_agent/agent_obsidian.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/obsidian_agent/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/ollama/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/ollama/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/ollama_setup/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/ollama_setup/completer.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/ollama_setup/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/plugin_contributions.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/plugin_meta.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/plugin_text_utils.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/plugins_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/plugins_menu_layout.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/plugins_menu_render.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/project_trust_flow.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/pop_command/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/pop_command/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prompt_newline/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prompt_newline/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prompt_newline/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prune/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prune/prune_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prune/prune_model.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prune/prune_render.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prune/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/README.md +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/commands.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/kennel.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/packer.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/recorder.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/retriever.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/schema.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/state.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/tools.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/wings.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_spinner/README.md +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_spinner/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_spinner/builtin_frames.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_spinner/commands.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_spinner/picker.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_spinner/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_spinner/spinners.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/quick_resume/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/quick_resume/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/review_pr/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/review_pr/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/shell_safety/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/stack_dump/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/stack_dump/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/statusline/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/statusline/config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/statusline/payload.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/statusline/prompt_patch.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/statusline/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/statusline/runner.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/statusline/statusline_command.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/steer_queue/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/steer_queue/queue_menu.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/steer_queue/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/subagent_panel/README.md +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/subagent_panel/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/subagent_panel/coalesce_patch.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/subagent_panel/panel_render.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/subagent_panel/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/subagent_panel/resume_repaint.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/subagent_panel/state.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/switch_agent_resume/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/switch_agent_resume/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/README.md +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/bundled_palettes.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/content_styles.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/osc_palette.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/picker.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/prompt_toolkit_theme.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/rich_themes.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/themes.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/token_ratio_learner/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/token_ratio_learner/ratios.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/token_ratio_learner/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/trust.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/trust_notice.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/universal_constructor/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/universal_constructor/models.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/universal_constructor/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/universal_constructor/registry.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/universal_constructor/sandbox.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/wide_completion_menu/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/wide_completion_menu/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/wiggum/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/wiggum/judge.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/wiggum/judge_config.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/wiggum/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/wiggum/state.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/yolo_cli/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/yolo_cli/register_callbacks.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/provider_credentials.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/provider_identity.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/reopenable_async_client.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/round_robin_model.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/secret_store.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/secret_store_backends.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/session_lifecycle.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/session_migration.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/session_storage.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/status_display.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/summarization_agent.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/terminal_utils.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/agent_tools.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/constants.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/demo_tui.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/handler.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/models.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/registration.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/renderers.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/terminal_ui.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/theme.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/tui_loop.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/__init__.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_control.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_interactions.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_locator_resolver.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_locators.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_manager.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_navigation.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_page_snapshot.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_screenshot.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_scripts.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_semantic_interactions.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_workflows.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/command_runner.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/common.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/display.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/file_modifications.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/file_operations.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/fs_access.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/image_tools.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/io_backends.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/model_tools.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/shell_backgrounding.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/skills_tools.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/subagent_context.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/subagent_invocation.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/tools_content.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/universal_constructor.py +0 -0
- {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/undo_manager.py +0 -0
|
@@ -987,7 +987,14 @@ async def _run_with_mcp_impl(
|
|
|
987
987
|
run_success = False
|
|
988
988
|
run_error: Optional[BaseException] = None
|
|
989
989
|
run_response_text = ""
|
|
990
|
-
|
|
990
|
+
run_usage_metadata: dict[str, int | None] = {
|
|
991
|
+
"usage_input_tokens": None,
|
|
992
|
+
"usage_output_tokens": None,
|
|
993
|
+
"usage_total_tokens": None,
|
|
994
|
+
"usage_cached_read_tokens": None,
|
|
995
|
+
"usage_cached_write_tokens": None,
|
|
996
|
+
"usage_thought_tokens": None,
|
|
997
|
+
}
|
|
991
998
|
|
|
992
999
|
try:
|
|
993
1000
|
# Nested runs (e.g. shell_safety mid-run) leave the SIGINT handler
|
|
@@ -1044,13 +1051,37 @@ async def _run_with_mcp_impl(
|
|
|
1044
1051
|
run_success = True
|
|
1045
1052
|
run_response_text = _extract_response_text(result)
|
|
1046
1053
|
try:
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1054
|
+
usage = result.usage()
|
|
1055
|
+
|
|
1056
|
+
def _pick_usage_int(*names: str) -> int | None:
|
|
1057
|
+
for name in names:
|
|
1058
|
+
value = getattr(usage, name, None)
|
|
1059
|
+
if value is not None:
|
|
1060
|
+
return int(value) or None
|
|
1061
|
+
return None
|
|
1062
|
+
|
|
1063
|
+
run_usage_metadata = {
|
|
1064
|
+
"usage_input_tokens": _pick_usage_int(
|
|
1065
|
+
"input_tokens", "request_tokens", "prompt_tokens"
|
|
1066
|
+
),
|
|
1067
|
+
# Real billed output tokens -- calibrates the run-stats TG
|
|
1068
|
+
# estimate (see run_stats.snapshot_cycle_into_aggregates).
|
|
1069
|
+
"usage_output_tokens": _pick_usage_int(
|
|
1070
|
+
"output_tokens", "response_tokens", "completion_tokens"
|
|
1071
|
+
),
|
|
1072
|
+
"usage_total_tokens": _pick_usage_int("total_tokens"),
|
|
1073
|
+
"usage_cached_read_tokens": _pick_usage_int(
|
|
1074
|
+
"cache_read_tokens", "cached_read_tokens"
|
|
1075
|
+
),
|
|
1076
|
+
"usage_cached_write_tokens": _pick_usage_int(
|
|
1077
|
+
"cache_write_tokens", "cached_write_tokens"
|
|
1078
|
+
),
|
|
1079
|
+
"usage_thought_tokens": _pick_usage_int(
|
|
1080
|
+
"thinking_tokens", "thought_tokens", "reasoning_tokens"
|
|
1081
|
+
),
|
|
1082
|
+
}
|
|
1052
1083
|
except Exception:
|
|
1053
|
-
|
|
1084
|
+
pass
|
|
1054
1085
|
return result
|
|
1055
1086
|
except asyncio.CancelledError:
|
|
1056
1087
|
run_response_text = ""
|
|
@@ -1086,7 +1117,7 @@ async def _run_with_mcp_impl(
|
|
|
1086
1117
|
response_text=run_response_text,
|
|
1087
1118
|
metadata={
|
|
1088
1119
|
"model": agent.get_model_name(),
|
|
1089
|
-
|
|
1120
|
+
**run_usage_metadata,
|
|
1090
1121
|
},
|
|
1091
1122
|
)
|
|
1092
1123
|
except Exception:
|
|
@@ -325,6 +325,23 @@ def get_owner_name():
|
|
|
325
325
|
return get_value("owner_name") or "Master"
|
|
326
326
|
|
|
327
327
|
|
|
328
|
+
def get_locale() -> str:
|
|
329
|
+
"""Return the active i18n locale (single source of truth).
|
|
330
|
+
|
|
331
|
+
Delegates to the i18n translator, seeding it once from the environment
|
|
332
|
+
and the persisted ``locale`` config key on first use. After a runtime
|
|
333
|
+
``/set locale`` (translator.set_locale), this reflects that override
|
|
334
|
+
rather than re-deriving from the environment.
|
|
335
|
+
|
|
336
|
+
Precedence when seeding: CODE_PUPPY_LOCALE env var > persisted ``locale``
|
|
337
|
+
config key > POSIX locale env vars > default (en-US). See
|
|
338
|
+
``code_puppy.i18n.locale.detect_locale``.
|
|
339
|
+
"""
|
|
340
|
+
from code_puppy.i18n import ensure_detected
|
|
341
|
+
|
|
342
|
+
return ensure_detected(get_value("locale"))
|
|
343
|
+
|
|
344
|
+
|
|
328
345
|
# Legacy function removed - message history limit is no longer used
|
|
329
346
|
# Message history is now managed by token-based compaction system
|
|
330
347
|
# using get_protected_token_count() and get_summarization_threshold()
|
|
@@ -388,6 +405,7 @@ def get_config_keys():
|
|
|
388
405
|
"frontend_emitter_enabled",
|
|
389
406
|
"frontend_emitter_max_recent_events",
|
|
390
407
|
"frontend_emitter_queue_size",
|
|
408
|
+
"locale",
|
|
391
409
|
]
|
|
392
410
|
# 'enable_dbos' is reserved for the dbos_durable_exec plugin and is read
|
|
393
411
|
# via the generic get_value API; intentionally not in default_keys.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Code Puppy internationalization (i18n) foundation.
|
|
2
|
+
|
|
3
|
+
Day-one localization framework: message catalogs with a fallback chain,
|
|
4
|
+
locale detection/override, plural-aware translation, locale-aware formatting,
|
|
5
|
+
and pseudolocalization for coverage testing. Stdlib-only by design.
|
|
6
|
+
|
|
7
|
+
Typical call-site usage::
|
|
8
|
+
|
|
9
|
+
from code_puppy.i18n import t, ngettext
|
|
10
|
+
|
|
11
|
+
emit_info(t("startup.welcome", name=owner))
|
|
12
|
+
emit_info(ngettext("files.deleted", count=n))
|
|
13
|
+
|
|
14
|
+
To resolve the active locale from the environment/config at boot::
|
|
15
|
+
|
|
16
|
+
from code_puppy.i18n import use_detected_locale
|
|
17
|
+
from code_puppy.config import get_value
|
|
18
|
+
|
|
19
|
+
use_detected_locale(get_value("locale"))
|
|
20
|
+
|
|
21
|
+
See ``PUP-473`` (epic) and ``PUP-475`` (this foundation story) for scope.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from .catalog import add_catalog_dir, available_locales, load_catalog, lookup, reset
|
|
25
|
+
from .formats import format_datetime, format_number
|
|
26
|
+
from .locale import (
|
|
27
|
+
DEFAULT_LOCALE,
|
|
28
|
+
detect_locale,
|
|
29
|
+
fallback_chain,
|
|
30
|
+
language_of,
|
|
31
|
+
normalize_locale,
|
|
32
|
+
)
|
|
33
|
+
from .plurals import plural_category
|
|
34
|
+
from .pseudo import PSEUDO_LOCALE, is_pseudo_locale, pseudolocalize
|
|
35
|
+
from .translate import (
|
|
36
|
+
LazyTranslation,
|
|
37
|
+
Translator,
|
|
38
|
+
ensure_detected,
|
|
39
|
+
get_locale,
|
|
40
|
+
get_translator,
|
|
41
|
+
lazy,
|
|
42
|
+
ngettext,
|
|
43
|
+
set_locale,
|
|
44
|
+
t,
|
|
45
|
+
use_detected_locale,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Common gettext-style alias so call sites can `from code_puppy.i18n import _`.
|
|
49
|
+
_ = t
|
|
50
|
+
|
|
51
|
+
__all__ = [
|
|
52
|
+
"_",
|
|
53
|
+
"t",
|
|
54
|
+
"ngettext",
|
|
55
|
+
"lazy",
|
|
56
|
+
"LazyTranslation",
|
|
57
|
+
"Translator",
|
|
58
|
+
"get_translator",
|
|
59
|
+
"get_locale",
|
|
60
|
+
"set_locale",
|
|
61
|
+
"use_detected_locale",
|
|
62
|
+
"ensure_detected",
|
|
63
|
+
"detect_locale",
|
|
64
|
+
"normalize_locale",
|
|
65
|
+
"fallback_chain",
|
|
66
|
+
"language_of",
|
|
67
|
+
"DEFAULT_LOCALE",
|
|
68
|
+
"plural_category",
|
|
69
|
+
"format_number",
|
|
70
|
+
"format_datetime",
|
|
71
|
+
"add_catalog_dir",
|
|
72
|
+
"available_locales",
|
|
73
|
+
"load_catalog",
|
|
74
|
+
"lookup",
|
|
75
|
+
"reset",
|
|
76
|
+
"pseudolocalize",
|
|
77
|
+
"is_pseudo_locale",
|
|
78
|
+
"PSEUDO_LOCALE",
|
|
79
|
+
]
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""Message catalog format, loader, and the missing-key fallback chain.
|
|
2
|
+
|
|
3
|
+
Catalogs are JSON files under ``code_puppy/i18n/locales/<locale>.json`` (plus
|
|
4
|
+
any extra directories registered via :func:`add_catalog_dir`, so plugins and
|
|
5
|
+
the private fork can ship their own strings without editing this package).
|
|
6
|
+
|
|
7
|
+
Catalog shape::
|
|
8
|
+
|
|
9
|
+
{
|
|
10
|
+
"startup.welcome": "Welcome to Code Puppy, {name}!",
|
|
11
|
+
"files.deleted": {
|
|
12
|
+
"one": "Deleted {count} file.",
|
|
13
|
+
"other": "Deleted {count} files."
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
A value is either a plain string or a plural dict keyed by CLDR plural
|
|
18
|
+
categories (``zero``/``one``/``two``/``few``/``many``/``other``). Only
|
|
19
|
+
``other`` is required in a plural dict; the rest are optional.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
import logging
|
|
26
|
+
import os
|
|
27
|
+
import re
|
|
28
|
+
import threading
|
|
29
|
+
from typing import Dict, List, Optional, Union
|
|
30
|
+
|
|
31
|
+
from .locale import DEFAULT_LOCALE, fallback_chain
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
# A catalog entry is a bare string or a plural-forms mapping.
|
|
36
|
+
CatalogEntry = Union[str, Dict[str, str]]
|
|
37
|
+
Catalog = Dict[str, CatalogEntry]
|
|
38
|
+
|
|
39
|
+
# Bundled catalogs ship next to this module.
|
|
40
|
+
_BUILTIN_DIR = os.path.join(os.path.dirname(__file__), "locales")
|
|
41
|
+
|
|
42
|
+
# Extra directories (plugins, private fork) searched *before* the builtin one,
|
|
43
|
+
# so downstream strings can override or extend the base catalog.
|
|
44
|
+
_extra_dirs: List[str] = []
|
|
45
|
+
|
|
46
|
+
# locale -> merged catalog. Cleared by reset() / add_catalog_dir().
|
|
47
|
+
_cache: Dict[str, Catalog] = {}
|
|
48
|
+
|
|
49
|
+
# Bumped whenever the search-dir set changes (reset/add_catalog_dir). A loader
|
|
50
|
+
# that released the lock for file I/O uses this to detect that its result went
|
|
51
|
+
# stale mid-flight and must not poison the cache (see load_catalog).
|
|
52
|
+
_generation = 0
|
|
53
|
+
|
|
54
|
+
# Guards ALL access to _cache, _extra_dirs, and _generation. lookup() runs on
|
|
55
|
+
# every t() call, which the message queue can dispatch from both the main
|
|
56
|
+
# thread and its daemon thread, so these globals are genuinely shared mutable
|
|
57
|
+
# state.
|
|
58
|
+
_lock = threading.RLock()
|
|
59
|
+
|
|
60
|
+
# A locale used to build a filename must be a plain BCP-47-ish tag. This is a
|
|
61
|
+
# defense-in-depth guard so the exported load_catalog()/lookup() can't be
|
|
62
|
+
# tricked into path traversal (e.g. "../../../../etc/passwd") even if a caller
|
|
63
|
+
# skips normalize_locale().
|
|
64
|
+
_SAFE_LOCALE_RE = re.compile(r"^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$")
|
|
65
|
+
|
|
66
|
+
# Windows reserved device names: open("con.json") resolves to the CON console
|
|
67
|
+
# device (extension ignored), which would hang json.load. normalize_locale
|
|
68
|
+
# happily emits "con"/"nul"/etc. as 3-letter lang subtags, so reject them.
|
|
69
|
+
_WIN_RESERVED = frozenset(
|
|
70
|
+
{"con", "prn", "aux", "nul"}
|
|
71
|
+
| {f"com{i}" for i in range(1, 10)}
|
|
72
|
+
| {f"lpt{i}" for i in range(1, 10)}
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _is_safe_locale(locale: str) -> bool:
|
|
77
|
+
if not locale or _SAFE_LOCALE_RE.match(locale) is None:
|
|
78
|
+
return False
|
|
79
|
+
return locale.lower() not in _WIN_RESERVED
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def add_catalog_dir(path: str) -> None:
|
|
83
|
+
"""Register an additional directory of ``<locale>.json`` catalogs.
|
|
84
|
+
|
|
85
|
+
Later-registered dirs win over earlier ones, and all registered dirs win
|
|
86
|
+
over the builtin catalogs. Registering invalidates the cache.
|
|
87
|
+
"""
|
|
88
|
+
global _generation
|
|
89
|
+
with _lock:
|
|
90
|
+
if path not in _extra_dirs:
|
|
91
|
+
_extra_dirs.append(path)
|
|
92
|
+
_cache.clear()
|
|
93
|
+
_generation += 1
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def reset() -> None:
|
|
97
|
+
"""Drop cached catalogs (and registered dirs). Mostly for tests."""
|
|
98
|
+
global _generation
|
|
99
|
+
with _lock:
|
|
100
|
+
_cache.clear()
|
|
101
|
+
_extra_dirs.clear()
|
|
102
|
+
_generation += 1
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _search_dirs() -> List[str]:
|
|
106
|
+
# Extra dirs are searched last so their entries overwrite the builtins
|
|
107
|
+
# during the dict merge below. Caller must hold _lock.
|
|
108
|
+
return [_BUILTIN_DIR, *_extra_dirs]
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _is_valid_entry(entry: object) -> bool:
|
|
112
|
+
"""Return whether an untrusted catalog value matches the public schema."""
|
|
113
|
+
if isinstance(entry, str):
|
|
114
|
+
return True
|
|
115
|
+
return (
|
|
116
|
+
isinstance(entry, dict)
|
|
117
|
+
and isinstance(entry.get("other"), str)
|
|
118
|
+
and all(
|
|
119
|
+
isinstance(category, str) and isinstance(text, str)
|
|
120
|
+
for category, text in entry.items()
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _load_file(path: str) -> Catalog:
|
|
126
|
+
try:
|
|
127
|
+
with open(path, "r", encoding="utf-8") as fh:
|
|
128
|
+
data = json.load(fh)
|
|
129
|
+
except FileNotFoundError:
|
|
130
|
+
return {}
|
|
131
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
132
|
+
logger.warning("Skipping malformed i18n catalog %s: %s", path, exc)
|
|
133
|
+
return {}
|
|
134
|
+
if not isinstance(data, dict):
|
|
135
|
+
logger.warning("i18n catalog %s is not a JSON object; skipping", path)
|
|
136
|
+
return {}
|
|
137
|
+
|
|
138
|
+
valid: Catalog = {}
|
|
139
|
+
for key, entry in data.items():
|
|
140
|
+
if _is_valid_entry(entry):
|
|
141
|
+
valid[key] = entry
|
|
142
|
+
else:
|
|
143
|
+
logger.warning("Skipping malformed i18n entry %r in catalog %s", key, path)
|
|
144
|
+
return valid
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def load_catalog(locale: str) -> Catalog:
|
|
148
|
+
"""Load and merge every ``<locale>.json`` for a single locale.
|
|
149
|
+
|
|
150
|
+
Does *not* apply the fallback chain — that happens at lookup time so a
|
|
151
|
+
key present in ``en`` but absent in ``fr`` still resolves. Cached per
|
|
152
|
+
locale.
|
|
153
|
+
"""
|
|
154
|
+
if not _is_safe_locale(locale):
|
|
155
|
+
# Reject anything that could escape the locales dir (path traversal)
|
|
156
|
+
# or otherwise isn't a plain locale tag. Defense-in-depth for the
|
|
157
|
+
# exported API; the normal path already normalizes upstream.
|
|
158
|
+
logger.warning("Refusing to load unsafe locale name: %r", locale)
|
|
159
|
+
return {}
|
|
160
|
+
|
|
161
|
+
with _lock:
|
|
162
|
+
cached = _cache.get(locale)
|
|
163
|
+
if cached is not None:
|
|
164
|
+
return cached
|
|
165
|
+
dirs = _search_dirs()
|
|
166
|
+
gen = _generation
|
|
167
|
+
|
|
168
|
+
merged: Catalog = {}
|
|
169
|
+
for directory in dirs:
|
|
170
|
+
merged.update(_load_file(os.path.join(directory, f"{locale}.json")))
|
|
171
|
+
|
|
172
|
+
with _lock:
|
|
173
|
+
if gen != _generation:
|
|
174
|
+
# The dir set changed (reset/add_catalog_dir) while we were doing
|
|
175
|
+
# file I/O, so ``merged`` may be stale. Return it for this call but
|
|
176
|
+
# do NOT cache it -- the next call recomputes against current dirs.
|
|
177
|
+
return merged
|
|
178
|
+
return _cache.setdefault(locale, merged)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def available_locales() -> List[str]:
|
|
182
|
+
"""Return the sorted set of locales that ship a ``<locale>.json`` catalog.
|
|
183
|
+
|
|
184
|
+
Scans the builtin dir plus any registered extra dirs. Useful for driving
|
|
185
|
+
``/set locale`` autocomplete and for validating the shipped catalogs.
|
|
186
|
+
"""
|
|
187
|
+
found = set()
|
|
188
|
+
with _lock:
|
|
189
|
+
dirs = _search_dirs()
|
|
190
|
+
for directory in dirs:
|
|
191
|
+
try:
|
|
192
|
+
entries = os.listdir(directory)
|
|
193
|
+
except OSError:
|
|
194
|
+
continue
|
|
195
|
+
for name in entries:
|
|
196
|
+
if name.endswith(".json"):
|
|
197
|
+
found.add(name[: -len(".json")])
|
|
198
|
+
return sorted(found)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def lookup(
|
|
202
|
+
key: str, locale: str, default_locale: str = DEFAULT_LOCALE
|
|
203
|
+
) -> Optional[CatalogEntry]:
|
|
204
|
+
"""Find ``key`` walking the locale fallback chain, most-specific first.
|
|
205
|
+
|
|
206
|
+
Returns the raw catalog entry (string or plural dict), or ``None`` if the
|
|
207
|
+
key is absent from every catalog in the chain.
|
|
208
|
+
"""
|
|
209
|
+
for candidate in fallback_chain(locale, default_locale):
|
|
210
|
+
entry = load_catalog(candidate).get(key)
|
|
211
|
+
if entry is not None:
|
|
212
|
+
return entry
|
|
213
|
+
return None
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Locale-aware formatting for numbers and dates (stdlib-only, best-effort).
|
|
2
|
+
|
|
3
|
+
This is the *foundation* seam, not the final implementation. Full CLDR-grade
|
|
4
|
+
formatting (grouping separators per locale, currency, compact "1.2K"
|
|
5
|
+
notation, RTL digit shaping) lands with Babel in a later workstream. For now
|
|
6
|
+
we provide a stable API with sensible en-US-ish defaults and per-locale digit
|
|
7
|
+
grouping/decimal separators for the handful of locales we know we'll hit
|
|
8
|
+
first, so call sites can migrate today without waiting on Babel.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from datetime import date, datetime
|
|
14
|
+
from typing import Optional, Union
|
|
15
|
+
|
|
16
|
+
from .translate import get_locale
|
|
17
|
+
|
|
18
|
+
# language subtag -> (thousands_sep, decimal_point). Fallback is en-style.
|
|
19
|
+
_SEPARATORS = {
|
|
20
|
+
"en": (",", "."),
|
|
21
|
+
"de": (".", ","),
|
|
22
|
+
"fr": ("\u202f", ","), # narrow no-break space
|
|
23
|
+
"es": (".", ","),
|
|
24
|
+
"it": (".", ","),
|
|
25
|
+
"pt": (".", ","),
|
|
26
|
+
"ru": ("\u00a0", ","),
|
|
27
|
+
"zh": (",", "."),
|
|
28
|
+
"ja": (",", "."),
|
|
29
|
+
"ko": (",", "."),
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
_DEFAULT_SEPARATORS = (",", ".")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _separators(locale: str) -> tuple[str, str]:
|
|
36
|
+
return _SEPARATORS.get(locale.split("-", 1)[0].lower(), _DEFAULT_SEPARATORS)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def format_number(
|
|
40
|
+
value: Union[int, float],
|
|
41
|
+
*,
|
|
42
|
+
decimals: Optional[int] = None,
|
|
43
|
+
locale: Optional[str] = None,
|
|
44
|
+
) -> str:
|
|
45
|
+
"""Format a number with locale-appropriate grouping/decimal separators.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
value: The number to format.
|
|
49
|
+
decimals: Fixed number of fraction digits, or ``None`` to keep the
|
|
50
|
+
value's natural precision (integers render with no fraction).
|
|
51
|
+
locale: Override the active locale for this call.
|
|
52
|
+
"""
|
|
53
|
+
loc = locale or get_locale()
|
|
54
|
+
thousands, decimal_point = _separators(loc)
|
|
55
|
+
|
|
56
|
+
if decimals is not None:
|
|
57
|
+
rendered = f"{value:,.{decimals}f}"
|
|
58
|
+
elif isinstance(value, int):
|
|
59
|
+
rendered = f"{value:,d}"
|
|
60
|
+
else:
|
|
61
|
+
rendered = f"{value:,}"
|
|
62
|
+
|
|
63
|
+
# Python always emits ","/".": swap to locale glyphs via placeholders to
|
|
64
|
+
# avoid clobbering a separator that happens to equal the other glyph.
|
|
65
|
+
return (
|
|
66
|
+
rendered.replace(",", "\0").replace(".", decimal_point).replace("\0", thousands)
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def format_datetime(
|
|
71
|
+
value: Union[datetime, date],
|
|
72
|
+
*,
|
|
73
|
+
date_only: bool = False,
|
|
74
|
+
locale: Optional[str] = None,
|
|
75
|
+
) -> str:
|
|
76
|
+
"""Format a datetime/date. Placeholder ISO-ish output for the foundation.
|
|
77
|
+
|
|
78
|
+
Deliberately conservative: ISO-8601 is unambiguous across locales, so we
|
|
79
|
+
lean on it until Babel provides real CLDR date skeletons. The ``locale``
|
|
80
|
+
arg is accepted now so call sites don't need to change when the richer
|
|
81
|
+
implementation lands.
|
|
82
|
+
"""
|
|
83
|
+
_ = locale or get_locale() # reserved for the Babel-backed upgrade
|
|
84
|
+
if date_only or (isinstance(value, date) and not isinstance(value, datetime)):
|
|
85
|
+
return value.strftime("%Y-%m-%d")
|
|
86
|
+
rendered = value.strftime("%Y-%m-%d %H:%M")
|
|
87
|
+
# Don't silently drop the timezone on aware datetimes.
|
|
88
|
+
if isinstance(value, datetime) and value.tzinfo is not None:
|
|
89
|
+
rendered += value.strftime("%z")
|
|
90
|
+
return rendered
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Locale detection, normalization, and the resolution chain.
|
|
2
|
+
|
|
3
|
+
The active locale is resolved with the following precedence (highest first):
|
|
4
|
+
|
|
5
|
+
1. ``CODE_PUPPY_LOCALE`` environment variable (explicit override)
|
|
6
|
+
2. The persisted ``locale`` config key (``puppy.cfg``) — the in-app
|
|
7
|
+
``/set locale`` preference, which beats the ambient OS locale
|
|
8
|
+
3. POSIX locale env vars: ``LC_ALL`` > ``LC_MESSAGES`` > ``LANG`` > ``LANGUAGE``
|
|
9
|
+
4. The default locale (``en-US``)
|
|
10
|
+
|
|
11
|
+
Everything here is intentionally stdlib-only. Babel/CLDR-backed niceties
|
|
12
|
+
(full plural rules, currency formatting) arrive in later i18n workstreams;
|
|
13
|
+
the foundation must not drag in a dependency just to boot.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
import re
|
|
20
|
+
from typing import Optional
|
|
21
|
+
|
|
22
|
+
DEFAULT_LOCALE = "en-US"
|
|
23
|
+
|
|
24
|
+
# Env vars checked, in POSIX precedence order, after the explicit override.
|
|
25
|
+
_POSIX_LOCALE_VARS = ("LC_ALL", "LC_MESSAGES", "LANG", "LANGUAGE")
|
|
26
|
+
|
|
27
|
+
# Matches things like "en", "en_US", "en-US", "en_US.UTF-8", "zh-Hans-CN".
|
|
28
|
+
_LOCALE_RE = re.compile(r"^[A-Za-z]{2,3}(?:[_-][A-Za-z0-9]+)*")
|
|
29
|
+
|
|
30
|
+
# CLDR parent-locale overrides: locales whose fallback parent is NOT simply
|
|
31
|
+
# their truncated form. The big one for us is Latin American Spanish, where
|
|
32
|
+
# every Central/South American country falls back through the ``es-419``
|
|
33
|
+
# umbrella before reaching generic (Iberian-ish) ``es``.
|
|
34
|
+
#
|
|
35
|
+
# Source: CLDR supplementalData <parentLocales>. Kept as an explicit map so
|
|
36
|
+
# adding a dialect is a one-line change and the behavior is testable.
|
|
37
|
+
_LATIN_AMERICAN_ES = (
|
|
38
|
+
# Central America (+ Mexico)
|
|
39
|
+
"es-MX",
|
|
40
|
+
"es-GT",
|
|
41
|
+
"es-HN",
|
|
42
|
+
"es-SV",
|
|
43
|
+
"es-NI",
|
|
44
|
+
"es-CR",
|
|
45
|
+
"es-PA",
|
|
46
|
+
"es-BZ",
|
|
47
|
+
# South America
|
|
48
|
+
"es-AR",
|
|
49
|
+
"es-BO",
|
|
50
|
+
"es-CL",
|
|
51
|
+
"es-CO",
|
|
52
|
+
"es-EC",
|
|
53
|
+
"es-PY",
|
|
54
|
+
"es-PE",
|
|
55
|
+
"es-UY",
|
|
56
|
+
"es-VE",
|
|
57
|
+
# Caribbean + US Spanish (also parented to 419 by CLDR)
|
|
58
|
+
"es-CU",
|
|
59
|
+
"es-DO",
|
|
60
|
+
"es-PR",
|
|
61
|
+
"es-US",
|
|
62
|
+
)
|
|
63
|
+
PARENT_LOCALES: dict = {loc: "es-419" for loc in _LATIN_AMERICAN_ES}
|
|
64
|
+
PARENT_LOCALES["es-419"] = "es"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def normalize_locale(raw: Optional[str]) -> Optional[str]:
|
|
68
|
+
"""Normalize a raw locale string to ``ll-CC`` (or ``ll``) form.
|
|
69
|
+
|
|
70
|
+
Strips encoding/modifier suffixes (``.UTF-8``, ``@euro``), converts
|
|
71
|
+
underscores to hyphens, lowercases the language subtag and uppercases a
|
|
72
|
+
2-letter region subtag. Returns ``None`` for empty/``"C"``/``"POSIX"``
|
|
73
|
+
placeholders so callers fall through to the next source.
|
|
74
|
+
"""
|
|
75
|
+
if not raw:
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
# Drop encoding (".UTF-8") and modifiers ("@euro").
|
|
79
|
+
candidate = raw.split(".", 1)[0].split("@", 1)[0].strip()
|
|
80
|
+
if not candidate or candidate.upper() in ("C", "POSIX"):
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
match = _LOCALE_RE.match(candidate)
|
|
84
|
+
if not match:
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
parts = re.split(r"[_-]", match.group(0))
|
|
88
|
+
lang = parts[0].lower()
|
|
89
|
+
if len(parts) == 1:
|
|
90
|
+
return lang
|
|
91
|
+
|
|
92
|
+
tail = parts[1:]
|
|
93
|
+
# A trailing 2-letter subtag is a region -> uppercase it. Anything else
|
|
94
|
+
# (e.g. a 4-letter script like "Hans") is title-cased, matching BCP-47.
|
|
95
|
+
normalized_tail = []
|
|
96
|
+
for part in tail:
|
|
97
|
+
if len(part) == 2:
|
|
98
|
+
normalized_tail.append(part.upper())
|
|
99
|
+
elif len(part) == 4:
|
|
100
|
+
normalized_tail.append(part.capitalize())
|
|
101
|
+
else:
|
|
102
|
+
normalized_tail.append(part.lower())
|
|
103
|
+
return "-".join([lang, *normalized_tail])
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def language_of(locale: str) -> str:
|
|
107
|
+
"""Return the bare language subtag of a locale (``en-US`` -> ``en``)."""
|
|
108
|
+
return locale.split("-", 1)[0].lower()
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def fallback_chain(locale: str, default: str = DEFAULT_LOCALE) -> list[str]:
|
|
112
|
+
"""Build the lookup chain for a locale, most-specific first.
|
|
113
|
+
|
|
114
|
+
Honors CLDR parent-locale overrides (see :data:`PARENT_LOCALES`), so
|
|
115
|
+
Latin American Spanish resolves through the ``es-419`` umbrella::
|
|
116
|
+
|
|
117
|
+
es-AR -> ["es-AR", "es-419", "es", "en-US"]
|
|
118
|
+
zh-Hans-CN -> ["zh-Hans-CN", "zh-Hans", "zh", "en-US"]
|
|
119
|
+
|
|
120
|
+
The default locale is always appended last (deduplicated) so a missing
|
|
121
|
+
key can never escape without at least trying the base catalog.
|
|
122
|
+
"""
|
|
123
|
+
chain: list[str] = []
|
|
124
|
+
current: Optional[str] = locale
|
|
125
|
+
while current and current not in chain:
|
|
126
|
+
chain.append(current)
|
|
127
|
+
override = PARENT_LOCALES.get(current)
|
|
128
|
+
if override:
|
|
129
|
+
current = override
|
|
130
|
+
elif "-" in current:
|
|
131
|
+
current = current.rsplit("-", 1)[0]
|
|
132
|
+
else:
|
|
133
|
+
current = None
|
|
134
|
+
if default not in chain:
|
|
135
|
+
chain.append(default)
|
|
136
|
+
return chain
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def detect_locale(
|
|
140
|
+
config_value: Optional[str] = None, default: str = DEFAULT_LOCALE
|
|
141
|
+
) -> str:
|
|
142
|
+
"""Resolve the active locale using the full precedence chain.
|
|
143
|
+
|
|
144
|
+
Precedence, highest first:
|
|
145
|
+
|
|
146
|
+
1. ``CODE_PUPPY_LOCALE`` env var (deliberate, explicit override)
|
|
147
|
+
2. The persisted ``locale`` config value (the in-app ``/set locale``
|
|
148
|
+
preference — an explicit user choice beats ambient OS locale, matching
|
|
149
|
+
git/VS Code/most CLIs)
|
|
150
|
+
3. POSIX locale env vars (``LC_ALL`` > ``LC_MESSAGES`` > ``LANG`` >
|
|
151
|
+
``LANGUAGE``) — ambient OS default
|
|
152
|
+
4. ``default`` (``en-US``)
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
config_value: The persisted ``locale`` config value, if any. Passed
|
|
156
|
+
in (rather than imported) to keep this module free of a hard
|
|
157
|
+
dependency on ``code_puppy.config`` and trivially testable.
|
|
158
|
+
default: Locale to fall back to when nothing else resolves.
|
|
159
|
+
"""
|
|
160
|
+
override = normalize_locale(os.environ.get("CODE_PUPPY_LOCALE"))
|
|
161
|
+
if override:
|
|
162
|
+
return override
|
|
163
|
+
|
|
164
|
+
from_config = normalize_locale(config_value)
|
|
165
|
+
if from_config:
|
|
166
|
+
return from_config
|
|
167
|
+
|
|
168
|
+
for var in _POSIX_LOCALE_VARS:
|
|
169
|
+
candidate = normalize_locale(os.environ.get(var))
|
|
170
|
+
if candidate:
|
|
171
|
+
return candidate
|
|
172
|
+
|
|
173
|
+
return normalize_locale(default) or DEFAULT_LOCALE
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"startup.welcome": "Welcome to Code Puppy, {name}!",
|
|
3
|
+
"startup.ready": "Ready to fetch some code. \ud83d\udc36",
|
|
4
|
+
"locale.set": "Locale set to {locale}.",
|
|
5
|
+
"locale.current": "Current locale: {locale}",
|
|
6
|
+
"files.deleted": {
|
|
7
|
+
"one": "Deleted {count} file.",
|
|
8
|
+
"other": "Deleted {count} files."
|
|
9
|
+
},
|
|
10
|
+
"files.written": {
|
|
11
|
+
"one": "Wrote {count} file.",
|
|
12
|
+
"other": "Wrote {count} files."
|
|
13
|
+
},
|
|
14
|
+
"error.generic": "Something went wrong: {detail}",
|
|
15
|
+
"version.current": "Current version: {version}",
|
|
16
|
+
"version.latest": "Latest version: {version}",
|
|
17
|
+
"version.update_available": "A new version of code puppy is available: {version}",
|
|
18
|
+
"version.please_update": "Please consider updating!",
|
|
19
|
+
"version.fetch_failed": "Error fetching version: {error}",
|
|
20
|
+
"version.undetected": "Could not detect current version, using fallback",
|
|
21
|
+
"confirm.yes": "Yes",
|
|
22
|
+
"confirm.no": "No"
|
|
23
|
+
}
|