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.
Files changed (484) hide show
  1. {code_puppy-0.0.641 → code_puppy-0.0.643}/PKG-INFO +1 -1
  2. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_runtime.py +39 -8
  3. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/config.py +18 -0
  4. code_puppy-0.0.643/code_puppy/i18n/__init__.py +79 -0
  5. code_puppy-0.0.643/code_puppy/i18n/catalog.py +213 -0
  6. code_puppy-0.0.643/code_puppy/i18n/formats.py +90 -0
  7. code_puppy-0.0.643/code_puppy/i18n/locale.py +173 -0
  8. code_puppy-0.0.643/code_puppy/i18n/locales/en-US.json +23 -0
  9. code_puppy-0.0.643/code_puppy/i18n/locales/es-419.json +17 -0
  10. code_puppy-0.0.643/code_puppy/i18n/locales/es-AR.json +1 -0
  11. code_puppy-0.0.643/code_puppy/i18n/locales/es-CL.json +1 -0
  12. code_puppy-0.0.643/code_puppy/i18n/locales/es-CO.json +1 -0
  13. code_puppy-0.0.643/code_puppy/i18n/locales/es-MX.json +1 -0
  14. code_puppy-0.0.643/code_puppy/i18n/locales/es.json +23 -0
  15. code_puppy-0.0.643/code_puppy/i18n/locales/fr-CA.json +23 -0
  16. code_puppy-0.0.643/code_puppy/i18n/plurals.py +71 -0
  17. code_puppy-0.0.643/code_puppy/i18n/pseudo.py +108 -0
  18. code_puppy-0.0.643/code_puppy/i18n/translate.py +202 -0
  19. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/__init__.py +4 -4
  20. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/bottom_bar.py +26 -2
  21. code_puppy-0.0.643/code_puppy/messaging/inline_bar.py +190 -0
  22. code_puppy-0.0.643/code_puppy/messaging/markdown_patches.py +89 -0
  23. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/message_queue.py +14 -1
  24. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/renderers.py +14 -7
  25. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/rich_renderer.py +13 -11
  26. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_hooks/register_callbacks.py +2 -0
  27. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/code_puppy_agent/SKILL.md +81 -8
  28. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/pydantic_patches.py +28 -0
  29. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/version_checker.py +7 -6
  30. {code_puppy-0.0.641 → code_puppy-0.0.643}/pyproject.toml +1 -1
  31. code_puppy-0.0.641/code_puppy/messaging/markdown_patches.py +0 -57
  32. {code_puppy-0.0.641 → code_puppy-0.0.643}/.gitignore +0 -0
  33. {code_puppy-0.0.641 → code_puppy-0.0.643}/LICENSE +0 -0
  34. {code_puppy-0.0.641 → code_puppy-0.0.643}/README.md +0 -0
  35. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/__init__.py +0 -0
  36. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/__main__.py +0 -0
  37. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/__init__.py +0 -0
  38. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_builder.py +0 -0
  39. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_compaction.py +0 -0
  40. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_diagnostics.py +0 -0
  41. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_history.py +0 -0
  42. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_key_listeners.py +0 -0
  43. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_non_streaming_render.py +0 -0
  44. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_run_signals.py +0 -0
  45. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/_steer_processor.py +0 -0
  46. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/agent_code_puppy.py +0 -0
  47. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/agent_creator_agent.py +0 -0
  48. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/agent_helios.py +0 -0
  49. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/agent_manager.py +0 -0
  50. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/agent_planning.py +0 -0
  51. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/agent_qa_kitten.py +0 -0
  52. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/base_agent.py +0 -0
  53. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/event_stream_handler.py +0 -0
  54. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/json_agent.py +0 -0
  55. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/retry_profiles.py +0 -0
  56. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/run_stats.py +0 -0
  57. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/smooth_stream.py +0 -0
  58. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/agents/subagent_stream_handler.py +0 -0
  59. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/callbacks.py +0 -0
  60. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/chatgpt_codex_client.py +0 -0
  61. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/claude_cache_client.py +0 -0
  62. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/cli_runner.py +0 -0
  63. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/__init__.py +0 -0
  64. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/add_model_menu.py +0 -0
  65. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/agent_menu.py +0 -0
  66. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/attachments.py +0 -0
  67. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/autosave_menu.py +0 -0
  68. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/autosave_search.py +0 -0
  69. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/clipboard.py +0 -0
  70. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/colors_menu.py +0 -0
  71. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/command_handler.py +0 -0
  72. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/command_registry.py +0 -0
  73. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/config_apply.py +0 -0
  74. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/config_commands.py +0 -0
  75. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/core_commands.py +0 -0
  76. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/diff_menu.py +0 -0
  77. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/file_index.py +0 -0
  78. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/file_path_completion.py +0 -0
  79. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/judges_menu.py +0 -0
  80. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/load_context_completion.py +0 -0
  81. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/__init__.py +0 -0
  82. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/base.py +0 -0
  83. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
  84. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
  85. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
  86. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/edit_command.py +0 -0
  87. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/handler.py +0 -0
  88. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/help_command.py +0 -0
  89. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/install_command.py +0 -0
  90. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/install_menu.py +0 -0
  91. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/list_command.py +0 -0
  92. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/logs_command.py +0 -0
  93. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/remove_command.py +0 -0
  94. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/restart_command.py +0 -0
  95. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/search_command.py +0 -0
  96. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/silence_warning_command.py +0 -0
  97. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/start_all_command.py +0 -0
  98. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/start_command.py +0 -0
  99. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/status_command.py +0 -0
  100. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
  101. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/stop_command.py +0 -0
  102. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/trust_command.py +0 -0
  103. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/utils.py +0 -0
  104. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
  105. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp_binding_menu.py +0 -0
  106. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/mcp_completion.py +0 -0
  107. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/model_picker_completion.py +0 -0
  108. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/model_settings_menu.py +0 -0
  109. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/onboarding_slides.py +0 -0
  110. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/onboarding_wizard.py +0 -0
  111. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/pagination.py +0 -0
  112. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/pin_command_completion.py +0 -0
  113. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
  114. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/session_commands.py +0 -0
  115. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/set_menu.py +0 -0
  116. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/set_menu_catalog.py +0 -0
  117. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/set_menu_render.py +0 -0
  118. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/set_menu_schema.py +0 -0
  119. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/set_menu_settings.py +0 -0
  120. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/set_menu_shims.py +0 -0
  121. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/set_menu_values.py +0 -0
  122. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/shell_passthrough.py +0 -0
  123. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/skills_completion.py +0 -0
  124. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/uc_menu.py +0 -0
  125. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/utils.py +0 -0
  126. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/command_line/wiggum_state.py +0 -0
  127. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/error_logging.py +0 -0
  128. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/gemini_code_assist.py +0 -0
  129. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/gemini_model.py +0 -0
  130. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/README.md +0 -0
  131. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/__init__.py +0 -0
  132. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/aliases.py +0 -0
  133. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/engine.py +0 -0
  134. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/executor.py +0 -0
  135. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/matcher.py +0 -0
  136. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/models.py +0 -0
  137. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/registry.py +0 -0
  138. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/hook_engine/validator.py +0 -0
  139. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/http_utils.py +0 -0
  140. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/keymap.py +0 -0
  141. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/list_filtering.py +0 -0
  142. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/main.py +0 -0
  143. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/__init__.py +0 -0
  144. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/agent_bindings.py +0 -0
  145. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/async_lifecycle.py +0 -0
  146. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/blocking_startup.py +0 -0
  147. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/captured_stdio_server.py +0 -0
  148. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/circuit_breaker.py +0 -0
  149. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/config_wizard.py +0 -0
  150. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/dashboard.py +0 -0
  151. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/error_isolation.py +0 -0
  152. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/examples/retry_example.py +0 -0
  153. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/health_monitor.py +0 -0
  154. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/managed_server.py +0 -0
  155. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/manager.py +0 -0
  156. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/mcp_logs.py +0 -0
  157. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/project_config.py +0 -0
  158. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/registry.py +0 -0
  159. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/retry_manager.py +0 -0
  160. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/server_registry_catalog.py +0 -0
  161. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/status_tracker.py +0 -0
  162. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/system_tools.py +0 -0
  163. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_/tool_arg_coercion.py +0 -0
  164. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_prompts/__init__.py +0 -0
  165. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/mcp_prompts/hook_creator.py +0 -0
  166. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/bar_painters.py +0 -0
  167. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/bar_rendering.py +0 -0
  168. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/bus.py +0 -0
  169. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/chords.py +0 -0
  170. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/commands.py +0 -0
  171. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/editor_actions.py +0 -0
  172. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/editor_completion.py +0 -0
  173. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/editor_display.py +0 -0
  174. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/editor_history.py +0 -0
  175. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/editor_keys.py +0 -0
  176. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/editor_paste.py +0 -0
  177. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/external_editor.py +0 -0
  178. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/line_editor.py +0 -0
  179. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/messages.py +0 -0
  180. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/pause_controller.py +0 -0
  181. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/prompt_prefix_style.py +0 -0
  182. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/queue_console.py +0 -0
  183. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/run_ui.py +0 -0
  184. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/run_ui_wiring.py +0 -0
  185. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/spinner/__init__.py +0 -0
  186. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/subagent_console.py +0 -0
  187. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/messaging/transcript_guard.py +0 -0
  188. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/model_descriptions.py +0 -0
  189. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/model_factory.py +0 -0
  190. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/model_switching.py +0 -0
  191. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/model_utils.py +0 -0
  192. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/models.json +0 -0
  193. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/models_dev_api.json +0 -0
  194. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/models_dev_parser.py +0 -0
  195. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/__init__.py +0 -0
  196. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/README.md +0 -0
  197. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/__init__.py +0 -0
  198. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/agent.py +0 -0
  199. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/bridge.py +0 -0
  200. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/capabilities.py +0 -0
  201. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/commands.py +0 -0
  202. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/content.py +0 -0
  203. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/io_delegation.py +0 -0
  204. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/mcp_config.py +0 -0
  205. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/permissions.py +0 -0
  206. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/persistence.py +0 -0
  207. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/register_callbacks.py +0 -0
  208. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/replay.py +0 -0
  209. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/session.py +0 -0
  210. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/session_config.py +0 -0
  211. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/acp/state.py +0 -0
  212. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/__init__.py +0 -0
  213. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/config.py +0 -0
  214. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/discovery.py +0 -0
  215. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/downloader.py +0 -0
  216. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/enabled_skills.py +0 -0
  217. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/installer.py +0 -0
  218. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/metadata.py +0 -0
  219. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/prompt_builder.py +0 -0
  220. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/register_callbacks.py +0 -0
  221. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/remote_catalog.py +0 -0
  222. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/skill_catalog.py +0 -0
  223. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/skill_commands.py +0 -0
  224. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/skills_install_menu.py +0 -0
  225. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/agent_skills/skills_menu.py +0 -0
  226. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/aws_bedrock/__init__.py +0 -0
  227. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/aws_bedrock/config.py +0 -0
  228. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/aws_bedrock/register_callbacks.py +0 -0
  229. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/aws_bedrock/utils.py +0 -0
  230. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/azure_foundry/README.md +0 -0
  231. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/azure_foundry/__init__.py +0 -0
  232. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/azure_foundry/config.py +0 -0
  233. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/azure_foundry/discovery.py +0 -0
  234. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/azure_foundry/register_callbacks.py +0 -0
  235. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/azure_foundry/token.py +0 -0
  236. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/azure_foundry/utils.py +0 -0
  237. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/btw/__init__.py +0 -0
  238. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/btw/inline_view.py +0 -0
  239. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/btw/register_callbacks.py +0 -0
  240. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/btw/side_query.py +0 -0
  241. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
  242. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
  243. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
  244. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
  245. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
  246. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/chatgpt_oauth/usage.py +0 -0
  247. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
  248. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_hooks/__init__.py +0 -0
  249. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_hooks/config.py +0 -0
  250. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
  251. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
  252. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
  253. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
  254. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/fast_mode.py +0 -0
  255. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/prompt_handler.py +0 -0
  256. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +0 -0
  257. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/test_fast_mode.py +0 -0
  258. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
  259. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +0 -0
  260. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/claude_code_oauth/utils.py +0 -0
  261. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/code_puppy_agent/__init__.py +0 -0
  262. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/code_puppy_agent/register_callbacks.py +0 -0
  263. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/config.py +0 -0
  264. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/context_indicator/__init__.py +0 -0
  265. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/context_indicator/register_callbacks.py +0 -0
  266. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/context_indicator/usage.py +0 -0
  267. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/copilot_auth/__init__.py +0 -0
  268. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/copilot_auth/config.py +0 -0
  269. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/copilot_auth/reasoning_client.py +0 -0
  270. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/copilot_auth/register_callbacks.py +0 -0
  271. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/copilot_auth/utils.py +0 -0
  272. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
  273. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
  274. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/__init__.py +0 -0
  275. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/cancel.py +0 -0
  276. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/commands.py +0 -0
  277. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/config.py +0 -0
  278. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/lifecycle.py +0 -0
  279. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/register_callbacks.py +0 -0
  280. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/runtime.py +0 -0
  281. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/startup_lock.py +0 -0
  282. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/workflow_ids.py +0 -0
  283. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/dbos_durable_exec/wrapper.py +0 -0
  284. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/destructive_command_guard/__init__.py +0 -0
  285. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/destructive_command_guard/detector.py +0 -0
  286. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/destructive_command_guard/register_callbacks.py +0 -0
  287. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/emoji_filter/__init__.py +0 -0
  288. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/emoji_filter/config.py +0 -0
  289. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/emoji_filter/register_callbacks.py +0 -0
  290. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/emoji_filter/stripper.py +0 -0
  291. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/empty_html_comment_filter/register_callbacks.py +0 -0
  292. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/example_custom_command/README.md +0 -0
  293. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
  294. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
  295. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
  296. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/force_push_guard/__init__.py +0 -0
  297. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/force_push_guard/detector.py +0 -0
  298. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/force_push_guard/register_callbacks.py +0 -0
  299. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/force_push_guard/test_detector.py +0 -0
  300. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/fork/__init__.py +0 -0
  301. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/fork/register_callbacks.py +0 -0
  302. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/frontend_emitter/__init__.py +0 -0
  303. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/frontend_emitter/emitter.py +0 -0
  304. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/frontend_emitter/register_callbacks.py +0 -0
  305. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/frontend_emitter/session_context.py +0 -0
  306. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/grok_oauth/__init__.py +0 -0
  307. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/grok_oauth/config.py +0 -0
  308. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/grok_oauth/oauth_flow.py +0 -0
  309. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/grok_oauth/register_callbacks.py +0 -0
  310. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/grok_oauth/test_plugin.py +0 -0
  311. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/grok_oauth/utils.py +0 -0
  312. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/herdr/README.md +0 -0
  313. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/herdr/__init__.py +0 -0
  314. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/herdr/client.py +0 -0
  315. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/herdr/register_callbacks.py +0 -0
  316. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/herdr/reporter.py +0 -0
  317. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/hook_creator/__init__.py +0 -0
  318. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/hook_creator/register_callbacks.py +0 -0
  319. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/hook_manager/__init__.py +0 -0
  320. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/hook_manager/config.py +0 -0
  321. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/hook_manager/hooks_menu.py +0 -0
  322. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/hook_manager/register_callbacks.py +0 -0
  323. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/no_tools/__init__.py +0 -0
  324. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/no_tools/register_callbacks.py +0 -0
  325. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/oauth_pasteback.py +0 -0
  326. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/oauth_puppy_html.py +0 -0
  327. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/obsidian_agent/README.md +0 -0
  328. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/obsidian_agent/__init__.py +0 -0
  329. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/obsidian_agent/agent_obsidian.py +0 -0
  330. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/obsidian_agent/register_callbacks.py +0 -0
  331. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/ollama/__init__.py +0 -0
  332. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/ollama/register_callbacks.py +0 -0
  333. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/ollama_setup/__init__.py +0 -0
  334. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/ollama_setup/completer.py +0 -0
  335. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/ollama_setup/register_callbacks.py +0 -0
  336. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/__init__.py +0 -0
  337. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/plugin_contributions.py +0 -0
  338. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/plugin_meta.py +0 -0
  339. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/plugin_text_utils.py +0 -0
  340. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/plugins_menu.py +0 -0
  341. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/plugins_menu_layout.py +0 -0
  342. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/plugins_menu_render.py +0 -0
  343. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/project_trust_flow.py +0 -0
  344. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/plugin_list/register_callbacks.py +0 -0
  345. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/pop_command/__init__.py +0 -0
  346. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/pop_command/register_callbacks.py +0 -0
  347. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prompt_newline/__init__.py +0 -0
  348. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prompt_newline/config.py +0 -0
  349. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prompt_newline/register_callbacks.py +0 -0
  350. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prune/__init__.py +0 -0
  351. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prune/prune_menu.py +0 -0
  352. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prune/prune_model.py +0 -0
  353. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prune/prune_render.py +0 -0
  354. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/prune/register_callbacks.py +0 -0
  355. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/README.md +0 -0
  356. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/__init__.py +0 -0
  357. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/commands.py +0 -0
  358. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/config.py +0 -0
  359. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/kennel.py +0 -0
  360. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/packer.py +0 -0
  361. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/recorder.py +0 -0
  362. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/register_callbacks.py +0 -0
  363. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/retriever.py +0 -0
  364. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/schema.py +0 -0
  365. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/state.py +0 -0
  366. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/tools.py +0 -0
  367. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_kennel/wings.py +0 -0
  368. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_spinner/README.md +0 -0
  369. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_spinner/__init__.py +0 -0
  370. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_spinner/builtin_frames.py +0 -0
  371. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_spinner/commands.py +0 -0
  372. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_spinner/picker.py +0 -0
  373. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_spinner/register_callbacks.py +0 -0
  374. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/puppy_spinner/spinners.py +0 -0
  375. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/quick_resume/__init__.py +0 -0
  376. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/quick_resume/register_callbacks.py +0 -0
  377. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/review_pr/__init__.py +0 -0
  378. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/review_pr/register_callbacks.py +0 -0
  379. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/shell_safety/__init__.py +0 -0
  380. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
  381. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
  382. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
  383. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/stack_dump/__init__.py +0 -0
  384. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/stack_dump/register_callbacks.py +0 -0
  385. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/statusline/__init__.py +0 -0
  386. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/statusline/config.py +0 -0
  387. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/statusline/payload.py +0 -0
  388. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/statusline/prompt_patch.py +0 -0
  389. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/statusline/register_callbacks.py +0 -0
  390. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/statusline/runner.py +0 -0
  391. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/statusline/statusline_command.py +0 -0
  392. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/steer_queue/__init__.py +0 -0
  393. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/steer_queue/queue_menu.py +0 -0
  394. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/steer_queue/register_callbacks.py +0 -0
  395. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/subagent_panel/README.md +0 -0
  396. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/subagent_panel/__init__.py +0 -0
  397. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/subagent_panel/coalesce_patch.py +0 -0
  398. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/subagent_panel/panel_render.py +0 -0
  399. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/subagent_panel/register_callbacks.py +0 -0
  400. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/subagent_panel/resume_repaint.py +0 -0
  401. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/subagent_panel/state.py +0 -0
  402. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/switch_agent_resume/__init__.py +0 -0
  403. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/switch_agent_resume/register_callbacks.py +0 -0
  404. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/README.md +0 -0
  405. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/__init__.py +0 -0
  406. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/bundled_palettes.py +0 -0
  407. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/content_styles.py +0 -0
  408. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/osc_palette.py +0 -0
  409. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/picker.py +0 -0
  410. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/prompt_toolkit_theme.py +0 -0
  411. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/register_callbacks.py +0 -0
  412. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/rich_themes.py +0 -0
  413. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/theme/themes.py +0 -0
  414. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/token_ratio_learner/__init__.py +0 -0
  415. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/token_ratio_learner/ratios.py +0 -0
  416. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/token_ratio_learner/register_callbacks.py +0 -0
  417. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/trust.py +0 -0
  418. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/trust_notice.py +0 -0
  419. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/universal_constructor/__init__.py +0 -0
  420. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/universal_constructor/models.py +0 -0
  421. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/universal_constructor/register_callbacks.py +0 -0
  422. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/universal_constructor/registry.py +0 -0
  423. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/universal_constructor/sandbox.py +0 -0
  424. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/wide_completion_menu/__init__.py +0 -0
  425. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/wide_completion_menu/register_callbacks.py +0 -0
  426. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/wiggum/__init__.py +0 -0
  427. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/wiggum/judge.py +0 -0
  428. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/wiggum/judge_config.py +0 -0
  429. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/wiggum/register_callbacks.py +0 -0
  430. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/wiggum/state.py +0 -0
  431. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/yolo_cli/__init__.py +0 -0
  432. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/plugins/yolo_cli/register_callbacks.py +0 -0
  433. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/provider_credentials.py +0 -0
  434. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/provider_identity.py +0 -0
  435. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/reopenable_async_client.py +0 -0
  436. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/round_robin_model.py +0 -0
  437. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/secret_store.py +0 -0
  438. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/secret_store_backends.py +0 -0
  439. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/session_lifecycle.py +0 -0
  440. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/session_migration.py +0 -0
  441. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/session_storage.py +0 -0
  442. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/status_display.py +0 -0
  443. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/summarization_agent.py +0 -0
  444. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/terminal_utils.py +0 -0
  445. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/__init__.py +0 -0
  446. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/agent_tools.py +0 -0
  447. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/__init__.py +0 -0
  448. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/constants.py +0 -0
  449. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/demo_tui.py +0 -0
  450. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/handler.py +0 -0
  451. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/models.py +0 -0
  452. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/registration.py +0 -0
  453. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/renderers.py +0 -0
  454. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/terminal_ui.py +0 -0
  455. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/theme.py +0 -0
  456. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/ask_user_question/tui_loop.py +0 -0
  457. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/__init__.py +0 -0
  458. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_control.py +0 -0
  459. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_interactions.py +0 -0
  460. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_locator_resolver.py +0 -0
  461. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_locators.py +0 -0
  462. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_manager.py +0 -0
  463. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_navigation.py +0 -0
  464. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_page_snapshot.py +0 -0
  465. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_screenshot.py +0 -0
  466. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_scripts.py +0 -0
  467. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_semantic_interactions.py +0 -0
  468. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/browser/browser_workflows.py +0 -0
  469. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/command_runner.py +0 -0
  470. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/common.py +0 -0
  471. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/display.py +0 -0
  472. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/file_modifications.py +0 -0
  473. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/file_operations.py +0 -0
  474. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/fs_access.py +0 -0
  475. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/image_tools.py +0 -0
  476. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/io_backends.py +0 -0
  477. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/model_tools.py +0 -0
  478. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/shell_backgrounding.py +0 -0
  479. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/skills_tools.py +0 -0
  480. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/subagent_context.py +0 -0
  481. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/subagent_invocation.py +0 -0
  482. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/tools_content.py +0 -0
  483. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/tools/universal_constructor.py +0 -0
  484. {code_puppy-0.0.641 → code_puppy-0.0.643}/code_puppy/undo_manager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-puppy
3
- Version: 0.0.641
3
+ Version: 0.0.643
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
@@ -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
- run_usage_output_tokens: Optional[int] = None
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
- # Real billed output tokens -- calibrates the run-stats TG
1048
- # estimate (see run_stats.snapshot_cycle_into_aggregates).
1049
- run_usage_output_tokens = (
1050
- int(getattr(result.usage(), "output_tokens", 0) or 0) or None
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
- run_usage_output_tokens = None
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
- "usage_output_tokens": run_usage_output_tokens,
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
+ }