code-puppy 0.0.593__tar.gz → 0.0.595__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 (407) hide show
  1. {code_puppy-0.0.593 → code_puppy-0.0.595}/PKG-INFO +1 -1
  2. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/_key_listeners.py +57 -5
  3. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/_runtime.py +104 -104
  4. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/callbacks.py +0 -19
  5. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/claude_cache_client.py +2 -9
  6. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/run_ui.py +44 -5
  7. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/claude_code_oauth/README.md +0 -4
  8. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +0 -5
  9. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/claude_code_oauth/utils.py +0 -22
  10. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/ask_user_question/terminal_ui.py +12 -13
  11. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/command_runner.py +38 -14
  12. {code_puppy-0.0.593 → code_puppy-0.0.595}/pyproject.toml +1 -1
  13. code_puppy-0.0.593/code_puppy/plugins/claude_code_oauth/auth_retry.py +0 -213
  14. {code_puppy-0.0.593 → code_puppy-0.0.595}/.gitignore +0 -0
  15. {code_puppy-0.0.593 → code_puppy-0.0.595}/LICENSE +0 -0
  16. {code_puppy-0.0.593 → code_puppy-0.0.595}/README.md +0 -0
  17. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/__init__.py +0 -0
  18. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/__main__.py +0 -0
  19. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/__init__.py +0 -0
  20. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/_builder.py +0 -0
  21. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/_compaction.py +0 -0
  22. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/_diagnostics.py +0 -0
  23. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/_history.py +0 -0
  24. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/_non_streaming_render.py +0 -0
  25. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/_run_signals.py +0 -0
  26. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/_steer_processor.py +0 -0
  27. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/agent_code_puppy.py +0 -0
  28. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/agent_creator_agent.py +0 -0
  29. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/agent_helios.py +0 -0
  30. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/agent_manager.py +0 -0
  31. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/agent_planning.py +0 -0
  32. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/agent_qa_kitten.py +0 -0
  33. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/base_agent.py +0 -0
  34. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/event_stream_handler.py +0 -0
  35. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/json_agent.py +0 -0
  36. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/run_stats.py +0 -0
  37. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/smooth_stream.py +0 -0
  38. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/agents/subagent_stream_handler.py +0 -0
  39. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/chatgpt_codex_client.py +0 -0
  40. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/cli_runner.py +0 -0
  41. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/__init__.py +0 -0
  42. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/add_model_menu.py +0 -0
  43. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/agent_menu.py +0 -0
  44. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/attachments.py +0 -0
  45. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/autosave_menu.py +0 -0
  46. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/autosave_search.py +0 -0
  47. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/clipboard.py +0 -0
  48. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/colors_menu.py +0 -0
  49. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/command_handler.py +0 -0
  50. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/command_registry.py +0 -0
  51. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/config_apply.py +0 -0
  52. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/config_commands.py +0 -0
  53. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/core_commands.py +0 -0
  54. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/diff_menu.py +0 -0
  55. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/file_index.py +0 -0
  56. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/file_path_completion.py +0 -0
  57. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/judges_menu.py +0 -0
  58. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/load_context_completion.py +0 -0
  59. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/__init__.py +0 -0
  60. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/base.py +0 -0
  61. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
  62. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
  63. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
  64. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/edit_command.py +0 -0
  65. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/handler.py +0 -0
  66. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/help_command.py +0 -0
  67. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/install_command.py +0 -0
  68. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/install_menu.py +0 -0
  69. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/list_command.py +0 -0
  70. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/logs_command.py +0 -0
  71. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/remove_command.py +0 -0
  72. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/restart_command.py +0 -0
  73. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/search_command.py +0 -0
  74. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/silence_warning_command.py +0 -0
  75. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/start_all_command.py +0 -0
  76. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/start_command.py +0 -0
  77. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/status_command.py +0 -0
  78. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
  79. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/stop_command.py +0 -0
  80. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/utils.py +0 -0
  81. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
  82. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp_binding_menu.py +0 -0
  83. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/mcp_completion.py +0 -0
  84. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/model_picker_completion.py +0 -0
  85. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/model_settings_menu.py +0 -0
  86. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/onboarding_slides.py +0 -0
  87. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/onboarding_wizard.py +0 -0
  88. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/pagination.py +0 -0
  89. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/pin_command_completion.py +0 -0
  90. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
  91. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/session_commands.py +0 -0
  92. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/set_menu.py +0 -0
  93. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/set_menu_catalog.py +0 -0
  94. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/set_menu_render.py +0 -0
  95. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/set_menu_schema.py +0 -0
  96. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/set_menu_settings.py +0 -0
  97. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/set_menu_shims.py +0 -0
  98. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/set_menu_values.py +0 -0
  99. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/shell_passthrough.py +0 -0
  100. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/skills_completion.py +0 -0
  101. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/uc_menu.py +0 -0
  102. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/utils.py +0 -0
  103. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/command_line/wiggum_state.py +0 -0
  104. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/config.py +0 -0
  105. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/error_logging.py +0 -0
  106. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/gemini_code_assist.py +0 -0
  107. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/gemini_model.py +0 -0
  108. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/hook_engine/README.md +0 -0
  109. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/hook_engine/__init__.py +0 -0
  110. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/hook_engine/aliases.py +0 -0
  111. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/hook_engine/engine.py +0 -0
  112. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/hook_engine/executor.py +0 -0
  113. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/hook_engine/matcher.py +0 -0
  114. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/hook_engine/models.py +0 -0
  115. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/hook_engine/registry.py +0 -0
  116. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/hook_engine/validator.py +0 -0
  117. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/http_utils.py +0 -0
  118. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/keymap.py +0 -0
  119. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/list_filtering.py +0 -0
  120. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/main.py +0 -0
  121. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/__init__.py +0 -0
  122. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/agent_bindings.py +0 -0
  123. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/async_lifecycle.py +0 -0
  124. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/blocking_startup.py +0 -0
  125. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/captured_stdio_server.py +0 -0
  126. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/circuit_breaker.py +0 -0
  127. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/config_wizard.py +0 -0
  128. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/dashboard.py +0 -0
  129. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/error_isolation.py +0 -0
  130. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/examples/retry_example.py +0 -0
  131. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/health_monitor.py +0 -0
  132. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/managed_server.py +0 -0
  133. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/manager.py +0 -0
  134. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/mcp_logs.py +0 -0
  135. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/registry.py +0 -0
  136. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/retry_manager.py +0 -0
  137. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/server_registry_catalog.py +0 -0
  138. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/status_tracker.py +0 -0
  139. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/system_tools.py +0 -0
  140. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_/tool_arg_coercion.py +0 -0
  141. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_prompts/__init__.py +0 -0
  142. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/mcp_prompts/hook_creator.py +0 -0
  143. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/__init__.py +0 -0
  144. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/bar_painters.py +0 -0
  145. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/bar_rendering.py +0 -0
  146. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/bottom_bar.py +0 -0
  147. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/bus.py +0 -0
  148. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/commands.py +0 -0
  149. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/editor_actions.py +0 -0
  150. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/editor_completion.py +0 -0
  151. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/editor_display.py +0 -0
  152. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/editor_history.py +0 -0
  153. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/editor_keys.py +0 -0
  154. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/editor_paste.py +0 -0
  155. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/line_editor.py +0 -0
  156. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/markdown_patches.py +0 -0
  157. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/message_queue.py +0 -0
  158. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/messages.py +0 -0
  159. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/pause_controller.py +0 -0
  160. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/prompt_prefix_style.py +0 -0
  161. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/queue_console.py +0 -0
  162. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/renderers.py +0 -0
  163. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/rich_renderer.py +0 -0
  164. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/run_ui_wiring.py +0 -0
  165. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/spinner/__init__.py +0 -0
  166. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/messaging/subagent_console.py +0 -0
  167. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/model_descriptions.py +0 -0
  168. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/model_factory.py +0 -0
  169. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/model_switching.py +0 -0
  170. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/model_utils.py +0 -0
  171. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/models.json +0 -0
  172. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/models_dev_api.json +0 -0
  173. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/models_dev_parser.py +0 -0
  174. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/__init__.py +0 -0
  175. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/agent_skills/__init__.py +0 -0
  176. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/agent_skills/config.py +0 -0
  177. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/agent_skills/discovery.py +0 -0
  178. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/agent_skills/downloader.py +0 -0
  179. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/agent_skills/enabled_skills.py +0 -0
  180. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/agent_skills/installer.py +0 -0
  181. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/agent_skills/metadata.py +0 -0
  182. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/agent_skills/prompt_builder.py +0 -0
  183. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/agent_skills/register_callbacks.py +0 -0
  184. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/agent_skills/remote_catalog.py +0 -0
  185. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/agent_skills/skill_catalog.py +0 -0
  186. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/agent_skills/skill_commands.py +0 -0
  187. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/agent_skills/skills_install_menu.py +0 -0
  188. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/agent_skills/skills_menu.py +0 -0
  189. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/aws_bedrock/__init__.py +0 -0
  190. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/aws_bedrock/config.py +0 -0
  191. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/aws_bedrock/register_callbacks.py +0 -0
  192. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/aws_bedrock/utils.py +0 -0
  193. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/azure_foundry/README.md +0 -0
  194. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/azure_foundry/__init__.py +0 -0
  195. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/azure_foundry/config.py +0 -0
  196. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/azure_foundry/discovery.py +0 -0
  197. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/azure_foundry/register_callbacks.py +0 -0
  198. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/azure_foundry/token.py +0 -0
  199. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/azure_foundry/utils.py +0 -0
  200. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/btw/__init__.py +0 -0
  201. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/btw/inline_view.py +0 -0
  202. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/btw/register_callbacks.py +0 -0
  203. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/btw/side_query.py +0 -0
  204. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
  205. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
  206. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
  207. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
  208. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
  209. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
  210. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/claude_code_hooks/__init__.py +0 -0
  211. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/claude_code_hooks/config.py +0 -0
  212. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/claude_code_hooks/register_callbacks.py +0 -0
  213. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
  214. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
  215. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
  216. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/claude_code_oauth/fast_mode.py +0 -0
  217. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/claude_code_oauth/prompt_handler.py +0 -0
  218. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/claude_code_oauth/test_fast_mode.py +0 -0
  219. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
  220. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +0 -0
  221. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/code_puppy_agent/SKILL.md +0 -0
  222. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/code_puppy_agent/__init__.py +0 -0
  223. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/code_puppy_agent/register_callbacks.py +0 -0
  224. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/config.py +0 -0
  225. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/context_indicator/__init__.py +0 -0
  226. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/context_indicator/register_callbacks.py +0 -0
  227. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/context_indicator/usage.py +0 -0
  228. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/copilot_auth/__init__.py +0 -0
  229. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/copilot_auth/config.py +0 -0
  230. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/copilot_auth/reasoning_client.py +0 -0
  231. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/copilot_auth/register_callbacks.py +0 -0
  232. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/copilot_auth/utils.py +0 -0
  233. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
  234. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
  235. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/dbos_durable_exec/__init__.py +0 -0
  236. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/dbos_durable_exec/cancel.py +0 -0
  237. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/dbos_durable_exec/commands.py +0 -0
  238. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/dbos_durable_exec/config.py +0 -0
  239. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/dbos_durable_exec/lifecycle.py +0 -0
  240. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/dbos_durable_exec/register_callbacks.py +0 -0
  241. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/dbos_durable_exec/runtime.py +0 -0
  242. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/dbos_durable_exec/startup_lock.py +0 -0
  243. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/dbos_durable_exec/workflow_ids.py +0 -0
  244. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/dbos_durable_exec/wrapper.py +0 -0
  245. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/destructive_command_guard/__init__.py +0 -0
  246. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/destructive_command_guard/detector.py +0 -0
  247. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/destructive_command_guard/register_callbacks.py +0 -0
  248. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/emoji_filter/__init__.py +0 -0
  249. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/emoji_filter/config.py +0 -0
  250. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/emoji_filter/register_callbacks.py +0 -0
  251. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/emoji_filter/stripper.py +0 -0
  252. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/example_custom_command/README.md +0 -0
  253. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
  254. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
  255. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
  256. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/force_push_guard/__init__.py +0 -0
  257. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/force_push_guard/detector.py +0 -0
  258. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/force_push_guard/register_callbacks.py +0 -0
  259. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/force_push_guard/test_detector.py +0 -0
  260. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/frontend_emitter/__init__.py +0 -0
  261. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/frontend_emitter/emitter.py +0 -0
  262. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/frontend_emitter/register_callbacks.py +0 -0
  263. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/frontend_emitter/session_context.py +0 -0
  264. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/hook_creator/__init__.py +0 -0
  265. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/hook_creator/register_callbacks.py +0 -0
  266. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/hook_manager/__init__.py +0 -0
  267. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/hook_manager/config.py +0 -0
  268. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/hook_manager/hooks_menu.py +0 -0
  269. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/hook_manager/register_callbacks.py +0 -0
  270. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/oauth_puppy_html.py +0 -0
  271. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/obsidian_agent/README.md +0 -0
  272. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/obsidian_agent/__init__.py +0 -0
  273. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/obsidian_agent/agent_obsidian.py +0 -0
  274. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/obsidian_agent/register_callbacks.py +0 -0
  275. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/ollama/__init__.py +0 -0
  276. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/ollama/register_callbacks.py +0 -0
  277. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/ollama_setup/__init__.py +0 -0
  278. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/ollama_setup/completer.py +0 -0
  279. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/ollama_setup/register_callbacks.py +0 -0
  280. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/plugin_list/__init__.py +0 -0
  281. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/plugin_list/plugin_contributions.py +0 -0
  282. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/plugin_list/plugin_meta.py +0 -0
  283. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/plugin_list/plugin_text_utils.py +0 -0
  284. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/plugin_list/plugins_menu.py +0 -0
  285. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/plugin_list/plugins_menu_render.py +0 -0
  286. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/plugin_list/register_callbacks.py +0 -0
  287. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/pop_command/__init__.py +0 -0
  288. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/pop_command/register_callbacks.py +0 -0
  289. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/prompt_newline/__init__.py +0 -0
  290. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/prompt_newline/config.py +0 -0
  291. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/prompt_newline/register_callbacks.py +0 -0
  292. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/prune/__init__.py +0 -0
  293. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/prune/prune_menu.py +0 -0
  294. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/prune/prune_model.py +0 -0
  295. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/prune/prune_render.py +0 -0
  296. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/prune/register_callbacks.py +0 -0
  297. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_kennel/README.md +0 -0
  298. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_kennel/__init__.py +0 -0
  299. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_kennel/commands.py +0 -0
  300. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_kennel/config.py +0 -0
  301. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_kennel/kennel.py +0 -0
  302. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_kennel/packer.py +0 -0
  303. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_kennel/recorder.py +0 -0
  304. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_kennel/register_callbacks.py +0 -0
  305. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_kennel/retriever.py +0 -0
  306. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_kennel/schema.py +0 -0
  307. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_kennel/state.py +0 -0
  308. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_kennel/tools.py +0 -0
  309. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_kennel/wings.py +0 -0
  310. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_spinner/__init__.py +0 -0
  311. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/puppy_spinner/register_callbacks.py +0 -0
  312. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/quick_resume/__init__.py +0 -0
  313. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/quick_resume/register_callbacks.py +0 -0
  314. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/review_pr/__init__.py +0 -0
  315. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/review_pr/register_callbacks.py +0 -0
  316. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/shell_safety/__init__.py +0 -0
  317. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
  318. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
  319. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
  320. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/statusline/__init__.py +0 -0
  321. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/statusline/config.py +0 -0
  322. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/statusline/payload.py +0 -0
  323. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/statusline/prompt_patch.py +0 -0
  324. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/statusline/register_callbacks.py +0 -0
  325. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/statusline/runner.py +0 -0
  326. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/statusline/statusline_command.py +0 -0
  327. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/steer_queue/__init__.py +0 -0
  328. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/steer_queue/queue_menu.py +0 -0
  329. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/steer_queue/register_callbacks.py +0 -0
  330. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/subagent_panel/README.md +0 -0
  331. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/subagent_panel/__init__.py +0 -0
  332. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/subagent_panel/coalesce_patch.py +0 -0
  333. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/subagent_panel/panel_render.py +0 -0
  334. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/subagent_panel/register_callbacks.py +0 -0
  335. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/subagent_panel/resume_repaint.py +0 -0
  336. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/subagent_panel/state.py +0 -0
  337. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/switch_agent_resume/__init__.py +0 -0
  338. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/switch_agent_resume/register_callbacks.py +0 -0
  339. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/theme/README.md +0 -0
  340. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/theme/__init__.py +0 -0
  341. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/theme/bundled_palettes.py +0 -0
  342. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/theme/content_styles.py +0 -0
  343. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/theme/osc_palette.py +0 -0
  344. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/theme/picker.py +0 -0
  345. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/theme/register_callbacks.py +0 -0
  346. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/theme/rich_themes.py +0 -0
  347. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/theme/themes.py +0 -0
  348. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/token_ratio_learner/__init__.py +0 -0
  349. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/token_ratio_learner/ratios.py +0 -0
  350. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/token_ratio_learner/register_callbacks.py +0 -0
  351. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/universal_constructor/__init__.py +0 -0
  352. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/universal_constructor/models.py +0 -0
  353. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/universal_constructor/register_callbacks.py +0 -0
  354. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/universal_constructor/registry.py +0 -0
  355. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/universal_constructor/sandbox.py +0 -0
  356. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/wide_completion_menu/__init__.py +0 -0
  357. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/wide_completion_menu/register_callbacks.py +0 -0
  358. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/wiggum/__init__.py +0 -0
  359. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/wiggum/judge.py +0 -0
  360. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/wiggum/judge_config.py +0 -0
  361. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/wiggum/register_callbacks.py +0 -0
  362. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/plugins/wiggum/state.py +0 -0
  363. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/provider_credentials.py +0 -0
  364. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/provider_identity.py +0 -0
  365. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/pydantic_patches.py +0 -0
  366. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/reopenable_async_client.py +0 -0
  367. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/round_robin_model.py +0 -0
  368. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/session_lifecycle.py +0 -0
  369. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/session_migration.py +0 -0
  370. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/session_storage.py +0 -0
  371. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/status_display.py +0 -0
  372. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/summarization_agent.py +0 -0
  373. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/terminal_utils.py +0 -0
  374. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/__init__.py +0 -0
  375. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/agent_tools.py +0 -0
  376. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/ask_user_question/__init__.py +0 -0
  377. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/ask_user_question/constants.py +0 -0
  378. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/ask_user_question/demo_tui.py +0 -0
  379. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/ask_user_question/handler.py +0 -0
  380. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/ask_user_question/models.py +0 -0
  381. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/ask_user_question/registration.py +0 -0
  382. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/ask_user_question/renderers.py +0 -0
  383. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/ask_user_question/theme.py +0 -0
  384. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/ask_user_question/tui_loop.py +0 -0
  385. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/browser/__init__.py +0 -0
  386. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/browser/browser_control.py +0 -0
  387. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/browser/browser_interactions.py +0 -0
  388. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/browser/browser_locators.py +0 -0
  389. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/browser/browser_manager.py +0 -0
  390. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/browser/browser_navigation.py +0 -0
  391. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/browser/browser_screenshot.py +0 -0
  392. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/browser/browser_scripts.py +0 -0
  393. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/browser/browser_workflows.py +0 -0
  394. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/common.py +0 -0
  395. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/display.py +0 -0
  396. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/file_modifications.py +0 -0
  397. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/file_operations.py +0 -0
  398. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/image_tools.py +0 -0
  399. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/model_tools.py +0 -0
  400. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/skills_tools.py +0 -0
  401. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/subagent_context.py +0 -0
  402. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/subagent_invocation.py +0 -0
  403. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/tools_content.py +0 -0
  404. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/tools/universal_constructor.py +0 -0
  405. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/undo_manager.py +0 -0
  406. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/uvx_detection.py +0 -0
  407. {code_puppy-0.0.593 → code_puppy-0.0.595}/code_puppy/version_checker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-puppy
3
- Version: 0.0.593
3
+ Version: 0.0.595
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
@@ -200,6 +200,38 @@ def get_active_handle() -> Optional[KeyListenerHandle]:
200
200
  return _active_handle
201
201
 
202
202
 
203
+ def acquire_listener(
204
+ stop_event: threading.Event,
205
+ on_escape: Callable[[], None],
206
+ on_cancel_agent: Optional[Callable[[], None]] = None,
207
+ ) -> tuple[Optional[KeyListenerHandle], bool]:
208
+ """Atomically reuse the live active listener or spawn + register one.
209
+
210
+ The historical bug: three call sites each did ``get_active_handle()``
211
+ → ``spawn_key_listener()`` → ``set_active_handle()`` as separate steps,
212
+ so two components racing through that window could both spawn — two
213
+ cbreak readers on one stdin, keystrokes split between them.
214
+
215
+ Returns:
216
+ ``(handle, spawned)`` — ``spawned`` is False when an existing live
217
+ listener was reused (the caller must NOT stop it). ``handle`` is
218
+ ``None`` (with ``spawned=True``) when stdin isn't a TTY.
219
+ """
220
+ global _active_handle
221
+ with _active_handle_lock:
222
+ existing = _active_handle
223
+ if (
224
+ existing is not None
225
+ and existing.thread.is_alive()
226
+ and not existing.stop_event.is_set()
227
+ ):
228
+ return existing, False
229
+ handle = spawn_key_listener(stop_event, on_escape, on_cancel_agent)
230
+ if handle is not None:
231
+ _active_handle = handle
232
+ return handle, True
233
+
234
+
203
235
  # =============================================================================
204
236
  # Spawn
205
237
  # =============================================================================
@@ -329,14 +361,24 @@ def _wait_while_suspended(
329
361
  Sets ``released_event`` (when given) to confirm we've parked. Polls
330
362
  every 50ms so we still respond to stop in a reasonable time.
331
363
 
364
+ The ack is LEVEL-triggered — re-asserted every lap — not edge-
365
+ triggered at park entry only. Rationale: back-to-back suspensions
366
+ (e.g. ``/resume``: one scope around ``handle_command``, another
367
+ around the picker) can resume+re-suspend within one 50ms poll lap.
368
+ The re-suspend clears ``released_event`` while we're STILL parked in
369
+ this loop (``suspend_event`` never read as clear), so an entry-only
370
+ ack would never be re-set and the new suspend would falsely time
371
+ out ("Key listener did not release stdin in time") even though
372
+ stdin was released the whole time.
373
+
332
374
  NOTE: we deliberately wait on ``stop_event`` (which is unset) rather
333
375
  than ``suspend_event`` (which IS set while we're parked here — waiting
334
376
  on it returns immediately and busy-spins, hogging the GIL and making
335
377
  raw-mode input prompts feel laggy while the listener is suspended).
336
378
  """
337
- if released_event is not None:
338
- released_event.set()
339
379
  while suspend_event.is_set() and not stop_event.is_set():
380
+ if released_event is not None:
381
+ released_event.set()
340
382
  stop_event.wait(timeout=0.05)
341
383
 
342
384
 
@@ -656,9 +698,18 @@ def suspended_key_listener(timeout: float = 1.0) -> Iterator[None]:
656
698
  if _suspend_depth == 1 and handle is not None:
657
699
  is_outermost = True
658
700
  if is_outermost:
659
- # Best-effort suspend; if it doesn't release in time we just
660
- # carry on quietly rather than spamming the user with a warning.
661
- handle.suspend(timeout=timeout)
701
+ # A silently-failed suspend means the caller launches its own stdin
702
+ # reader (prompt_toolkit, input()) while the listener is STILL in
703
+ # cbreak mode — two readers, keystrokes split between them. Give
704
+ # the listener one extended grace period, then warn loudly so the
705
+ # flakiness is at least diagnosable instead of "sometimes my keys
706
+ # vanish".
707
+ if not handle.suspend(timeout=timeout):
708
+ if not handle.released_event.wait(timeout=2.0):
709
+ emit_warning(
710
+ "Key listener did not release stdin in time; "
711
+ "input may be flaky until this prompt closes."
712
+ )
662
713
  try:
663
714
  yield
664
715
  finally:
@@ -671,6 +722,7 @@ def suspended_key_listener(timeout: float = 1.0) -> Iterator[None]:
671
722
 
672
723
  __all__ = [
673
724
  "KeyListenerHandle",
725
+ "acquire_listener",
674
726
  "get_active_handle",
675
727
  "get_line_editor",
676
728
  "set_active_handle",
@@ -19,7 +19,6 @@ from __future__ import annotations
19
19
  import asyncio
20
20
  import signal
21
21
  import threading
22
- import time
23
22
  import uuid
24
23
  from contextlib import AsyncExitStack
25
24
  from typing import Any, Callable, Iterator, List, Optional, Sequence, Type, Union
@@ -82,7 +81,6 @@ from code_puppy.agents._run_signals import (
82
81
  from code_puppy.agents.event_stream_handler import event_stream_handler
83
82
  from code_puppy.callbacks import (
84
83
  on_agent_exception,
85
- on_agent_retryable_exception,
86
84
  on_agent_run_cancel,
87
85
  on_agent_run_context,
88
86
  on_agent_run_end,
@@ -268,37 +266,9 @@ def should_retry_streaming(exc: Exception) -> bool:
268
266
  return any(_is_retryable_one(e) for e in _walk_cause_chain(exc))
269
267
 
270
268
 
271
- async def _plugin_says_retry(
272
- exc: Exception,
273
- model_name: Optional[str],
274
- attempt: int,
275
- max_attempts: int,
276
- ) -> bool:
277
- """Ask ``agent_retryable_exception`` hooks whether ``exc`` is retryable.
278
-
279
- Gives plugins a chance to (a) classify provider-specific failures the
280
- core classifier can't know about and (b) perform recovery work (e.g. an
281
- OAuth token refresh) before the retry fires. Any truthy result means
282
- retry. Hook machinery failures are swallowed: a broken plugin must never
283
- turn a genuine error into a hang, nor a retryable blip into a crash.
284
- """
285
- try:
286
- results = await on_agent_retryable_exception(
287
- exc,
288
- model_name=model_name,
289
- attempt=attempt,
290
- max_attempts=max_attempts,
291
- )
292
- except Exception: # pragma: no cover - defensive
293
- return False
294
- return any(bool(r) for r in results)
295
-
296
-
297
269
  def streaming_retry(
298
270
  max_attempts: int = 3,
299
271
  delays: Sequence[float] = (1, 2, 4),
300
- model_name: Optional[str] = None,
301
- progress_window: float = 120.0,
302
272
  ) -> Callable[[Callable[[], Any]], Callable[[], Any]]:
303
273
  """Wrap a no-arg async callable with streaming-retry semantics.
304
274
 
@@ -308,48 +278,34 @@ def streaming_retry(
308
278
  get the exception type, message, traceback, and which attempt it was. The
309
279
  on-disk log is the only way to measure the upstream-blip rate after the
310
280
  classifier silently absorbs it.
311
-
312
- Exceptions the built-in classifier rejects get one more chance via the
313
- ``agent_retryable_exception`` hook, so plugins can opt provider-specific
314
- failures (e.g. OAuth auth errors) into this same retry schedule.
315
- ``model_name`` is forwarded to the hook so plugins can scope themselves.
316
-
317
- ``max_attempts`` caps *consecutive rapid* failures, not total failures
318
- per run. An agent run wraps many model calls; a long run can hit several
319
- unrelated provider blips spread across minutes of successful work. If an
320
- attempt survives at least ``progress_window`` seconds before failing, it
321
- clearly made progress, so the failure streak resets and the blip gets a
322
- fresh retry budget. Only back-to-back quick failures — the actual
323
- hopeless-loop signature — burn through the cap.
324
281
  """
325
282
  from code_puppy.error_logging import log_error
326
283
 
327
284
  def decorator(factory: Callable[[], Any]) -> Callable[[], Any]:
328
285
  async def runner() -> Any:
329
- streak = 0 # consecutive rapid failures
330
- while True:
331
- attempt_started = time.monotonic()
286
+ last_exc: Optional[Exception] = None
287
+ for attempt in range(max_attempts):
332
288
  try:
333
289
  return await factory()
334
290
  except Exception as exc:
335
- made_progress = (
336
- time.monotonic() - attempt_started >= progress_window
337
- )
338
- if not should_retry_streaming(exc) and not await _plugin_says_retry(
339
- exc, model_name, streak + 1, max_attempts
340
- ):
291
+ if not should_retry_streaming(exc):
341
292
  raise
342
- if made_progress:
343
- streak = 0
344
- streak += 1
293
+ last_exc = exc
345
294
  log_error(
346
295
  exc,
347
296
  context=(
348
297
  f"streaming_retry: transient exception on attempt "
349
- f"{streak}/{max_attempts}"
298
+ f"{attempt + 1}/{max_attempts}"
350
299
  ),
351
300
  )
352
- if streak >= max_attempts:
301
+ if attempt < max_attempts - 1:
302
+ delay = delays[attempt] if attempt < len(delays) else delays[-1]
303
+ emit_warning(
304
+ f"\u26a1 Streaming interrupted, auto-retrying in {delay}s... "
305
+ f"(attempt {attempt + 1}/{max_attempts})"
306
+ )
307
+ await asyncio.sleep(delay)
308
+ else:
353
309
  log_error(
354
310
  exc,
355
311
  context=(
@@ -360,15 +316,8 @@ def streaming_retry(
360
316
  emit_error(
361
317
  f"\u274c Streaming failed after {max_attempts} attempts"
362
318
  )
363
- raise
364
- delay = (
365
- delays[streak - 1] if streak - 1 < len(delays) else delays[-1]
366
- )
367
- emit_warning(
368
- f"\u26a1 Streaming interrupted, auto-retrying in {delay}s... "
369
- f"(attempt {streak}/{max_attempts})"
370
- )
371
- await asyncio.sleep(delay)
319
+ assert last_exc is not None # loop always sets this before exiting
320
+ raise last_exc
372
321
 
373
322
  return runner
374
323
 
@@ -482,6 +431,16 @@ def _collect_exceptions(
482
431
  # ---- The main entry point ---------------------------------------------------
483
432
 
484
433
 
434
+ # Depth of in-flight ``run_with_mcp`` calls. Only touched from the main
435
+ # event loop's thread (every run is awaited on the same loop), so a plain
436
+ # int is race-free. Depth > 0 at entry means a NESTED run — e.g. the
437
+ # shell_safety plugin assessing a command while the primary agent runs.
438
+ # Nested runs must NOT touch process-wide interactive state: the
439
+ # PauseController (it would drain the user's queued steers!), the SIGINT
440
+ # handler, the shell cancel bridge, or the key-listener cancel hotkey.
441
+ _active_run_depth = 0
442
+
443
+
485
444
  async def run_with_mcp(
486
445
  agent: Any,
487
446
  prompt: str,
@@ -491,13 +450,48 @@ async def run_with_mcp(
491
450
  output_type: Optional[Type[Any]] = None,
492
451
  **kwargs: Any,
493
452
  ) -> Any:
494
- """Run ``agent`` against ``prompt`` with full MCP + cancellation support."""
453
+ """Run ``agent`` against ``prompt`` with full MCP + cancellation support.
454
+
455
+ Thin depth-tracking wrapper: nested calls (a run started while another
456
+ run is already in flight on this loop) skip the interactive-state
457
+ plumbing — see ``_active_run_depth``.
458
+ """
459
+ global _active_run_depth
460
+ is_nested_run = _active_run_depth > 0
461
+ _active_run_depth += 1
462
+ try:
463
+ return await _run_with_mcp_impl(
464
+ agent,
465
+ prompt,
466
+ attachments=attachments,
467
+ link_attachments=link_attachments,
468
+ output_type=output_type,
469
+ is_nested_run=is_nested_run,
470
+ **kwargs,
471
+ )
472
+ finally:
473
+ _active_run_depth -= 1
474
+
475
+
476
+ async def _run_with_mcp_impl(
477
+ agent: Any,
478
+ prompt: str,
479
+ *,
480
+ attachments: Optional[Sequence[BinaryContent]] = None,
481
+ link_attachments: Optional[Sequence[Union[ImageUrl, DocumentUrl]]] = None,
482
+ output_type: Optional[Type[Any]] = None,
483
+ is_nested_run: bool = False,
484
+ **kwargs: Any,
485
+ ) -> Any:
486
+ """Body of :func:`run_with_mcp` (depth bookkeeping lives in the wrapper)."""
495
487
 
496
488
  # Scrub any stale PauseController state from a previously-cancelled run
497
489
  # BEFORE we touch the prompt or build the agent. The controller is a
498
490
  # process-wide singleton; without this guard a leftover steer queue
499
- # would silently poison this run.
500
- reset_pause_state_at_run_start()
491
+ # would silently poison this run. NEVER from a nested run: the "stale"
492
+ # steers it would drain are the OUTER run's live ones.
493
+ if not is_nested_run:
494
+ reset_pause_state_at_run_start()
501
495
 
502
496
  prompt = _sanitize_prompt(prompt)
503
497
  group_id = str(uuid.uuid4())
@@ -542,7 +536,7 @@ async def run_with_mcp(
542
536
  # the non-streaming fallback render.
543
537
  skip_fallback_render = on_should_skip_fallback_render(agent)
544
538
 
545
- @streaming_retry(model_name=agent.get_model_name())
539
+ @streaming_retry()
546
540
  async def _call() -> Any:
547
541
  return await pydantic_agent.run(
548
542
  prompt_to_use,
@@ -582,7 +576,7 @@ async def run_with_mcp(
582
576
  # between ``agent.run()`` calls below — additive, won't interrupt
583
577
  # in-progress work.
584
578
  async def _follow_up_run(follow_up_prompt: Any) -> Any:
585
- @streaming_retry(model_name=agent.get_model_name())
579
+ @streaming_retry()
586
580
  async def _call_follow_up() -> Any:
587
581
  return await pydantic_agent.run(
588
582
  follow_up_prompt,
@@ -766,10 +760,12 @@ async def run_with_mcp(
766
760
  # Bridge the cancel callback to the shell SIGINT handler so a single
767
761
  # Ctrl+C while shells are running stops the whole agent/sub-agent swarm
768
762
  # (kill shells, then cancel every task) instead of only killing the
769
- # current batch of shells.
763
+ # current batch of shells. Nested runs must not clobber the outer
764
+ # run's bridge (clear_agent_cancel in their finally would disarm it).
770
765
  from code_puppy.tools import command_runner as _command_runner
771
766
 
772
- _command_runner.register_agent_cancel(schedule_agent_cancel)
767
+ if not is_nested_run:
768
+ _command_runner.register_agent_cancel(schedule_agent_cancel)
773
769
 
774
770
  def keyboard_interrupt_handler(_sig, _frame):
775
771
  # Let input() handle its own KeyboardInterrupt if we're mid-prompt.
@@ -820,27 +816,25 @@ async def run_with_mcp(
820
816
  run_usage_output_tokens: Optional[int] = None
821
817
 
822
818
  try:
823
- if cancel_agent_uses_signal():
824
- original_handler = signal.signal(signal.SIGINT, keyboard_interrupt_handler)
825
- cancel_cb: Optional[Callable[[], None]] = None # SIGINT owns cancel
826
- else:
827
- original_handler = signal.signal(signal.SIGINT, graceful_sigint_handler)
828
- cancel_cb = schedule_agent_cancel
829
- # Key listener: with the persistent prompt (Phase A) a REPL-
830
- # lifetime listener already owns stdin — just arm the per-run
831
- # cancel hotkey on it. Otherwise (headless -r, classic prompt,
832
- # embeds) spawn a per-run listener exactly as before.
833
- existing_handle = _key_listeners.get_active_handle()
834
- if (
835
- existing_handle is not None
836
- and existing_handle.thread.is_alive()
837
- and not existing_handle.stop_event.is_set()
838
- ):
839
- using_persistent_listener = True
840
- _key_listeners.set_cancel_handler(cancel_cb)
841
- else:
819
+ # Nested runs (e.g. shell_safety mid-run) leave the SIGINT handler
820
+ # and cancel hotkey alone — the outer run owns them, and cancelling
821
+ # the outer task propagates into this awaited one anyway.
822
+ if not is_nested_run:
823
+ if cancel_agent_uses_signal():
824
+ original_handler = signal.signal(
825
+ signal.SIGINT, keyboard_interrupt_handler
826
+ )
827
+ cancel_cb: Optional[Callable[[], None]] = None # SIGINT owns cancel
828
+ else:
829
+ original_handler = signal.signal(signal.SIGINT, graceful_sigint_handler)
830
+ cancel_cb = schedule_agent_cancel
831
+ # Key listener: with the persistent prompt (Phase A) a REPL-
832
+ # lifetime listener already owns stdin — just arm the per-run
833
+ # cancel hotkey on it. Otherwise (headless -r, classic prompt,
834
+ # embeds) spawn a per-run listener. ``acquire_listener`` makes
835
+ # the reuse-or-spawn decision atomic (no double-reader race).
842
836
  key_listener_stop_event = threading.Event()
843
- key_listener_handle = _key_listeners.spawn_key_listener(
837
+ handle, spawned = _key_listeners.acquire_listener(
844
838
  key_listener_stop_event,
845
839
  # Ctrl+X: command_runner installs a dynamic handler via
846
840
  # _key_listeners.set_escape_handler() while shell commands
@@ -848,10 +842,11 @@ async def run_with_mcp(
848
842
  on_escape=lambda: None,
849
843
  on_cancel_agent=cancel_cb,
850
844
  )
851
- # Publish the handle so other stdin consumers (prompt_toolkit
852
- # menus, TUIs) can suspend/resume the listener while they take
853
- # over stdin.
854
- _key_listeners.set_active_handle(key_listener_handle)
845
+ if spawned:
846
+ key_listener_handle = handle
847
+ else:
848
+ using_persistent_listener = True
849
+ _key_listeners.set_cancel_handler(cancel_cb)
855
850
 
856
851
  result = await agent_task
857
852
  run_success = True
@@ -868,22 +863,27 @@ async def run_with_mcp(
868
863
  except asyncio.CancelledError:
869
864
  run_response_text = ""
870
865
  agent_task.cancel()
871
- drain_pause_state_on_cancel()
866
+ # Nested runs never drain: the pending steers belong to the outer
867
+ # run, whose own cancel path (or run end) handles them.
868
+ if not is_nested_run:
869
+ drain_pause_state_on_cancel()
872
870
  except KeyboardInterrupt:
873
871
  run_response_text = ""
874
872
  if not agent_task.done():
875
873
  agent_task.cancel()
876
- drain_pause_state_on_cancel()
874
+ if not is_nested_run:
875
+ drain_pause_state_on_cancel()
877
876
  except Exception as e:
878
877
  run_error = e
879
878
  raise
880
879
  finally:
881
- try:
882
- from code_puppy.tools import command_runner as _command_runner
880
+ if not is_nested_run:
881
+ try:
882
+ from code_puppy.tools import command_runner as _command_runner
883
883
 
884
- _command_runner.clear_agent_cancel()
885
- except Exception:
886
- pass
884
+ _command_runner.clear_agent_cancel()
885
+ except Exception:
886
+ pass
887
887
  try:
888
888
  await on_agent_run_end(
889
889
  agent_name=agent.name,
@@ -8,7 +8,6 @@ PhaseType = Literal[
8
8
  "shutdown",
9
9
  "invoke_agent",
10
10
  "agent_exception",
11
- "agent_retryable_exception",
12
11
  "version_check",
13
12
  "edit_file",
14
13
  "create_file",
@@ -64,7 +63,6 @@ _callbacks: Dict[PhaseType, List[CallbackFunc]] = {
64
63
  "shutdown": [],
65
64
  "invoke_agent": [],
66
65
  "agent_exception": [],
67
- "agent_retryable_exception": [],
68
66
  "version_check": [],
69
67
  "edit_file": [],
70
68
  "create_file": [],
@@ -330,23 +328,6 @@ async def on_agent_exception(exception: Exception, *args, **kwargs) -> List[Any]
330
328
  return await _trigger_callbacks("agent_exception", exception, *args, **kwargs)
331
329
 
332
330
 
333
- async def on_agent_retryable_exception(
334
- exception: Exception, *args, **kwargs
335
- ) -> List[Any]:
336
- """Ask plugins whether an exception the core classifier rejected is retryable.
337
-
338
- Fired from the main agent retry loop (``streaming_retry``) when
339
- ``should_retry_streaming`` says an exception is NOT transient. Plugins
340
- receive ``(exception, model_name=..., attempt=..., max_attempts=...)`` and
341
- may perform recovery work (e.g. refreshing an OAuth token) before
342
- answering. Any truthy result opts the exception into the standard retry
343
- schedule (delays, banner, error-log, attempt cap).
344
- """
345
- return await _trigger_callbacks(
346
- "agent_retryable_exception", exception, *args, **kwargs
347
- )
348
-
349
-
350
331
  async def on_version_check(*args, **kwargs) -> List[Any]:
351
332
  return await _trigger_callbacks("version_check", *args, **kwargs)
352
333
 
@@ -440,15 +440,8 @@ class ClaudeCacheAsyncClient(httpx.AsyncClient):
440
440
  if response.status_code == 400:
441
441
  is_auth_error = await self._is_cloudflare_html_error(response)
442
442
  if is_auth_error:
443
- # cf-ray + request size make edge flaps diagnosable
444
- # (and reportable to Anthropic) from errors.log alone.
445
- request_body = self._extract_body_bytes(request) or b""
446
- logger.warning(
447
- "Detected Cloudflare HTML 400 (cf-ray=%s, "
448
- "request_bytes=%d, url=%s); attempting token refresh",
449
- response.headers.get("cf-ray"),
450
- len(request_body),
451
- request.url.path,
443
+ logger.info(
444
+ "Detected Cloudflare 400 error (likely auth-related), attempting token refresh"
452
445
  )
453
446
 
454
447
  if is_auth_error:
@@ -148,6 +148,10 @@ def stop_run_ui() -> None:
148
148
  # The UI outlives the run — just drop back to idle routing.
149
149
  _run_active = False
150
150
  _clear_status_row()
151
+ # Self-heal: if the REPL-lifetime listener died mid-run (its
152
+ # thread crashed, or a per-run listener replaced-then-stopped
153
+ # it), typing at the idle prompt would be dead forever.
154
+ _ensure_persistent_listener_locked()
151
155
  return
152
156
  editor = _editor
153
157
  _editor = None
@@ -403,17 +407,52 @@ def _spawn_persistent_listener() -> None:
403
407
  from code_puppy.agents import _key_listeners
404
408
  except ImportError:
405
409
  return # no listener infra: prompt still works via nothing-to-feed
406
- if _key_listeners.get_active_handle() is not None:
407
- return # someone else owns stdin already
408
410
  stop_event = threading.Event()
409
- handle = _key_listeners.spawn_key_listener(stop_event, on_escape=lambda: None)
410
- if handle is None:
411
+ # Atomic reuse-or-spawn: if someone else already owns stdin we back
412
+ # off (spawned=False) and deliberately do NOT record their handle as
413
+ # ours — stop_persistent_ui must never stop a listener it didn't spawn.
414
+ handle, spawned = _key_listeners.acquire_listener(
415
+ stop_event, on_escape=lambda: None
416
+ )
417
+ if handle is None or not spawned:
411
418
  return
412
- _key_listeners.set_active_handle(handle)
413
419
  with _lock:
414
420
  _listener_handle = handle
415
421
 
416
422
 
423
+ def _ensure_persistent_listener_locked() -> None:
424
+ """Respawn the persistent listener if it died. Caller holds ``_lock``.
425
+
426
+ Never raises — this runs on ``finally`` teardown paths.
427
+ """
428
+ global _listener_handle
429
+ handle = _listener_handle
430
+ if (
431
+ handle is not None
432
+ and handle.thread.is_alive()
433
+ and not handle.stop_event.is_set()
434
+ ):
435
+ return # healthy
436
+ try:
437
+ from code_puppy.agents import _key_listeners
438
+ except ImportError:
439
+ return
440
+ try:
441
+ # Drop the stale registration (if it's still ours) so
442
+ # acquire_listener doesn't refuse to spawn over a corpse.
443
+ if handle is not None and _key_listeners.get_active_handle() is handle:
444
+ _key_listeners.set_active_handle(None)
445
+ _listener_handle = None
446
+ stop_event = threading.Event()
447
+ new_handle, spawned = _key_listeners.acquire_listener(
448
+ stop_event, on_escape=lambda: None
449
+ )
450
+ if new_handle is not None and spawned:
451
+ _listener_handle = new_handle
452
+ except Exception:
453
+ logger.debug("persistent listener respawn failed", exc_info=True)
454
+
455
+
417
456
  # =============================================================================
418
457
  # Slash-command consumer (Phase 5)
419
458
  # =============================================================================
@@ -156,10 +156,6 @@ claude_code_oauth/
156
156
 
157
157
  - The plugin assumes Anthropic continues to expose the shared `claude-cli` OAuth client
158
158
  - Tokens are refreshed on subsequent API calls if the service returns refresh tokens
159
- - Auth failures (401/403, or Cloudflare HTML 400s) that escape the HTTP client's
160
- per-request refresh trigger an automatic token refresh and ride the main agent
161
- retry loop via the `agent_retryable_exception` hook (see `auth_retry.py`) —
162
- same delays and attempt cap as a 429, so users aren't interrupted
163
159
  - Models are prefixed with `claude-code-` to avoid collisions with other Anthropic models
164
160
 
165
161
  ## Contributing
@@ -23,7 +23,6 @@ from code_puppy.provider_identity import (
23
23
  )
24
24
 
25
25
  from ..oauth_puppy_html import oauth_failure_html, oauth_success_html
26
- from .auth_retry import handle_retryable_exception, register_runtime_token_updater
27
26
  from .config import CLAUDE_CODE_OAUTH_CONFIG, get_token_storage_path
28
27
  from .fast_mode import (
29
28
  FAST_SETTING_KEY,
@@ -457,9 +456,6 @@ def _create_claude_code_model(model_name: str, model_config: Dict, config: Dict)
457
456
  custom_endpoint["api_key"] = access_token
458
457
 
459
458
  client.set_token_update_callback(_update_runtime_token)
460
- # Also track the updater so agent-level auth-retry (auth_retry.py) can
461
- # broadcast a refreshed token into this live client before re-running.
462
- register_runtime_token_updater(_update_runtime_token)
463
459
  patch_anthropic_client_messages(anthropic_client)
464
460
  # Fast mode wrapper sits outside cache-control injector and re-reads
465
461
  # the setting on every call so /claude-code-fast takes effect live.
@@ -548,7 +544,6 @@ async def _on_agent_run_end(
548
544
  logger.debug("Error stopping token refresh heartbeat: %s", exc)
549
545
 
550
546
 
551
- register_callback("agent_retryable_exception", handle_retryable_exception)
552
547
  register_callback("custom_command_help", _custom_help)
553
548
  register_callback("custom_command", _handle_custom_command)
554
549
  register_callback("register_model_type", _register_model_types)
@@ -26,14 +26,6 @@ from .config import (
26
26
  TOKEN_REFRESH_BUFFER_SECONDS = 300
27
27
  MIN_REFRESH_BUFFER_SECONDS = 30
28
28
 
29
- # Cooldown for *forced* refreshes (seconds). Every refresh-token exchange
30
- # rotates the refresh token; hammering the endpoint during a flappy episode
31
- # (e.g. repeated Cloudflare 400s that a new token can't cure anyway) burns
32
- # through rotations for nothing and risks invalidating the token family.
33
- # If the stored tokens were refreshed within this window and are still
34
- # valid, force=True short-circuits to the existing access token.
35
- FORCE_REFRESH_COOLDOWN_SECONDS = 30
36
-
37
29
  logger = logging.getLogger(__name__)
38
30
 
39
31
 
@@ -221,19 +213,6 @@ def refresh_access_token(force: bool = False) -> Optional[str]:
221
213
  if not force and not is_token_expired(tokens):
222
214
  return tokens.get("access_token")
223
215
 
224
- # Forced-refresh cooldown: a token minted seconds ago is as fresh as a
225
- # new exchange would produce. Skip the rotation and reuse it.
226
- if force and tokens.get("access_token") and not is_token_expired(tokens):
227
- seconds_since_refresh = time.time() - float(tokens.get("refreshed_at") or 0)
228
- if seconds_since_refresh < FORCE_REFRESH_COOLDOWN_SECONDS:
229
- logger.info(
230
- "Skipping forced token refresh (last refresh %.0fs ago, "
231
- "cooldown %ds); reusing current access token",
232
- seconds_since_refresh,
233
- FORCE_REFRESH_COOLDOWN_SECONDS,
234
- )
235
- return tokens.get("access_token")
236
-
237
216
  refresh_token = tokens.get("refresh_token")
238
217
  if not refresh_token:
239
218
  logger.debug("No refresh_token available")
@@ -280,7 +259,6 @@ def refresh_access_token(force: bool = False) -> Optional[str]:
280
259
  if expires_in_value is not None:
281
260
  tokens["expires_in"] = expires_in_value
282
261
  tokens["expires_at"] = _calculate_expires_at(expires_in_value)
283
- tokens["refreshed_at"] = time.time()
284
262
  if save_tokens(tokens):
285
263
  update_claude_code_model_tokens(tokens["access_token"])
286
264
  return tokens["access_token"]