code-puppy 0.0.577__tar.gz → 0.0.579__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 (393) hide show
  1. {code_puppy-0.0.577 → code_puppy-0.0.579}/PKG-INFO +1 -1
  2. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/cli_runner.py +170 -126
  3. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/autosave_menu.py +49 -6
  4. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/session_commands.py +79 -47
  5. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/config.py +172 -27
  6. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_skills/config.py +9 -5
  7. code_puppy-0.0.579/code_puppy/plugins/plugin_list/plugin_contributions.py +355 -0
  8. code_puppy-0.0.579/code_puppy/plugins/plugin_list/plugin_meta.py +67 -0
  9. code_puppy-0.0.579/code_puppy/plugins/plugin_list/plugin_text_utils.py +177 -0
  10. code_puppy-0.0.579/code_puppy/plugins/plugin_list/plugins_menu.py +419 -0
  11. code_puppy-0.0.579/code_puppy/plugins/plugin_list/plugins_menu_render.py +297 -0
  12. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/plugin_list/register_callbacks.py +69 -60
  13. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/switch_agent_resume/register_callbacks.py +4 -4
  14. code_puppy-0.0.579/code_puppy/session_lifecycle.py +317 -0
  15. code_puppy-0.0.579/code_puppy/session_migration.py +222 -0
  16. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/session_storage.py +2 -2
  17. {code_puppy-0.0.577 → code_puppy-0.0.579}/pyproject.toml +1 -1
  18. code_puppy-0.0.577/code_puppy/plugins/plugin_list/plugins_menu.py +0 -328
  19. {code_puppy-0.0.577 → code_puppy-0.0.579}/.gitignore +0 -0
  20. {code_puppy-0.0.577 → code_puppy-0.0.579}/LICENSE +0 -0
  21. {code_puppy-0.0.577 → code_puppy-0.0.579}/README.md +0 -0
  22. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/__init__.py +0 -0
  23. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/__main__.py +0 -0
  24. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/__init__.py +0 -0
  25. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/_builder.py +0 -0
  26. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/_compaction.py +0 -0
  27. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/_diagnostics.py +0 -0
  28. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/_history.py +0 -0
  29. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/_key_listeners.py +0 -0
  30. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/_non_streaming_render.py +0 -0
  31. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/_run_signals.py +0 -0
  32. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/_runtime.py +0 -0
  33. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/_steer_processor.py +0 -0
  34. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/agent_code_puppy.py +0 -0
  35. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/agent_creator_agent.py +0 -0
  36. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/agent_helios.py +0 -0
  37. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/agent_manager.py +0 -0
  38. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/agent_planning.py +0 -0
  39. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/agent_qa_kitten.py +0 -0
  40. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/base_agent.py +0 -0
  41. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/event_stream_handler.py +0 -0
  42. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/json_agent.py +0 -0
  43. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/run_stats.py +0 -0
  44. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/smooth_stream.py +0 -0
  45. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/agents/subagent_stream_handler.py +0 -0
  46. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/callbacks.py +0 -0
  47. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/chatgpt_codex_client.py +0 -0
  48. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/claude_cache_client.py +0 -0
  49. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/__init__.py +0 -0
  50. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/add_model_menu.py +0 -0
  51. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/agent_menu.py +0 -0
  52. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/attachments.py +0 -0
  53. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/autosave_search.py +0 -0
  54. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/clipboard.py +0 -0
  55. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/colors_menu.py +0 -0
  56. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/command_handler.py +0 -0
  57. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/command_registry.py +0 -0
  58. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/config_apply.py +0 -0
  59. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/config_commands.py +0 -0
  60. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/core_commands.py +0 -0
  61. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/diff_menu.py +0 -0
  62. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/file_index.py +0 -0
  63. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/file_path_completion.py +0 -0
  64. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/judges_menu.py +0 -0
  65. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/load_context_completion.py +0 -0
  66. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/__init__.py +0 -0
  67. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/base.py +0 -0
  68. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
  69. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
  70. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
  71. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/edit_command.py +0 -0
  72. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/handler.py +0 -0
  73. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/help_command.py +0 -0
  74. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/install_command.py +0 -0
  75. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/install_menu.py +0 -0
  76. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/list_command.py +0 -0
  77. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/logs_command.py +0 -0
  78. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/remove_command.py +0 -0
  79. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/restart_command.py +0 -0
  80. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/search_command.py +0 -0
  81. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/silence_warning_command.py +0 -0
  82. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/start_all_command.py +0 -0
  83. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/start_command.py +0 -0
  84. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/status_command.py +0 -0
  85. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
  86. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/stop_command.py +0 -0
  87. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/utils.py +0 -0
  88. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
  89. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp_binding_menu.py +0 -0
  90. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/mcp_completion.py +0 -0
  91. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/model_picker_completion.py +0 -0
  92. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/model_settings_menu.py +0 -0
  93. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/onboarding_slides.py +0 -0
  94. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/onboarding_wizard.py +0 -0
  95. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/pagination.py +0 -0
  96. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/pin_command_completion.py +0 -0
  97. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
  98. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/set_menu.py +0 -0
  99. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/set_menu_catalog.py +0 -0
  100. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/set_menu_render.py +0 -0
  101. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/set_menu_schema.py +0 -0
  102. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/set_menu_settings.py +0 -0
  103. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/set_menu_shims.py +0 -0
  104. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/set_menu_values.py +0 -0
  105. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/shell_passthrough.py +0 -0
  106. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/skills_completion.py +0 -0
  107. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/uc_menu.py +0 -0
  108. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/utils.py +0 -0
  109. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/command_line/wiggum_state.py +0 -0
  110. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/error_logging.py +0 -0
  111. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/gemini_code_assist.py +0 -0
  112. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/gemini_model.py +0 -0
  113. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/hook_engine/README.md +0 -0
  114. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/hook_engine/__init__.py +0 -0
  115. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/hook_engine/aliases.py +0 -0
  116. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/hook_engine/engine.py +0 -0
  117. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/hook_engine/executor.py +0 -0
  118. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/hook_engine/matcher.py +0 -0
  119. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/hook_engine/models.py +0 -0
  120. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/hook_engine/registry.py +0 -0
  121. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/hook_engine/validator.py +0 -0
  122. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/http_utils.py +0 -0
  123. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/keymap.py +0 -0
  124. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/list_filtering.py +0 -0
  125. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/main.py +0 -0
  126. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/__init__.py +0 -0
  127. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/agent_bindings.py +0 -0
  128. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/async_lifecycle.py +0 -0
  129. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/blocking_startup.py +0 -0
  130. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/captured_stdio_server.py +0 -0
  131. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/circuit_breaker.py +0 -0
  132. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/config_wizard.py +0 -0
  133. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/dashboard.py +0 -0
  134. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/error_isolation.py +0 -0
  135. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/examples/retry_example.py +0 -0
  136. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/health_monitor.py +0 -0
  137. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/managed_server.py +0 -0
  138. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/manager.py +0 -0
  139. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/mcp_logs.py +0 -0
  140. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/registry.py +0 -0
  141. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/retry_manager.py +0 -0
  142. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/server_registry_catalog.py +0 -0
  143. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/status_tracker.py +0 -0
  144. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_/system_tools.py +0 -0
  145. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_prompts/__init__.py +0 -0
  146. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/mcp_prompts/hook_creator.py +0 -0
  147. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/messaging/__init__.py +0 -0
  148. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/messaging/bus.py +0 -0
  149. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/messaging/commands.py +0 -0
  150. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/messaging/markdown_patches.py +0 -0
  151. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/messaging/message_queue.py +0 -0
  152. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/messaging/messages.py +0 -0
  153. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/messaging/pause_controller.py +0 -0
  154. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/messaging/queue_console.py +0 -0
  155. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/messaging/renderers.py +0 -0
  156. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/messaging/rich_renderer.py +0 -0
  157. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/messaging/spinner/__init__.py +0 -0
  158. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/messaging/spinner/console_spinner.py +0 -0
  159. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/messaging/spinner/spinner_base.py +0 -0
  160. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/messaging/subagent_console.py +0 -0
  161. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/model_descriptions.py +0 -0
  162. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/model_factory.py +0 -0
  163. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/model_switching.py +0 -0
  164. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/model_utils.py +0 -0
  165. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/models.json +0 -0
  166. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/models_dev_api.json +0 -0
  167. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/models_dev_parser.py +0 -0
  168. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/__init__.py +0 -0
  169. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_skills/__init__.py +0 -0
  170. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_skills/discovery.py +0 -0
  171. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_skills/downloader.py +0 -0
  172. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_skills/enabled_skills.py +0 -0
  173. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_skills/installer.py +0 -0
  174. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_skills/metadata.py +0 -0
  175. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_skills/prompt_builder.py +0 -0
  176. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_skills/register_callbacks.py +0 -0
  177. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_skills/remote_catalog.py +0 -0
  178. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_skills/skill_catalog.py +0 -0
  179. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_skills/skill_commands.py +0 -0
  180. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_skills/skills_install_menu.py +0 -0
  181. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_skills/skills_menu.py +0 -0
  182. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_steering/README.md +0 -0
  183. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_steering/__init__.py +0 -0
  184. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_steering/line_editor.py +0 -0
  185. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_steering/register_callbacks.py +0 -0
  186. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/agent_steering/steering_prompt.py +0 -0
  187. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/aws_bedrock/__init__.py +0 -0
  188. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/aws_bedrock/config.py +0 -0
  189. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/aws_bedrock/register_callbacks.py +0 -0
  190. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/aws_bedrock/utils.py +0 -0
  191. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/azure_foundry/README.md +0 -0
  192. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/azure_foundry/__init__.py +0 -0
  193. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/azure_foundry/config.py +0 -0
  194. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/azure_foundry/discovery.py +0 -0
  195. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/azure_foundry/register_callbacks.py +0 -0
  196. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/azure_foundry/token.py +0 -0
  197. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/azure_foundry/utils.py +0 -0
  198. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
  199. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
  200. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
  201. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
  202. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
  203. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
  204. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/claude_code_hooks/__init__.py +0 -0
  205. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/claude_code_hooks/config.py +0 -0
  206. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/claude_code_hooks/register_callbacks.py +0 -0
  207. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
  208. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
  209. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
  210. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
  211. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/claude_code_oauth/fast_mode.py +0 -0
  212. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/claude_code_oauth/prompt_handler.py +0 -0
  213. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +0 -0
  214. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/claude_code_oauth/test_fast_mode.py +0 -0
  215. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
  216. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +0 -0
  217. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/claude_code_oauth/utils.py +0 -0
  218. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/code_puppy_agent/SKILL.md +0 -0
  219. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/code_puppy_agent/__init__.py +0 -0
  220. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/code_puppy_agent/register_callbacks.py +0 -0
  221. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/config.py +0 -0
  222. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/context_indicator/__init__.py +0 -0
  223. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/context_indicator/register_callbacks.py +0 -0
  224. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/context_indicator/usage.py +0 -0
  225. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/copilot_auth/__init__.py +0 -0
  226. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/copilot_auth/config.py +0 -0
  227. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/copilot_auth/reasoning_client.py +0 -0
  228. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/copilot_auth/register_callbacks.py +0 -0
  229. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/copilot_auth/utils.py +0 -0
  230. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
  231. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
  232. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/dbos_durable_exec/__init__.py +0 -0
  233. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/dbos_durable_exec/cancel.py +0 -0
  234. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/dbos_durable_exec/commands.py +0 -0
  235. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/dbos_durable_exec/config.py +0 -0
  236. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/dbos_durable_exec/lifecycle.py +0 -0
  237. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/dbos_durable_exec/register_callbacks.py +0 -0
  238. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/dbos_durable_exec/runtime.py +0 -0
  239. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/dbos_durable_exec/startup_lock.py +0 -0
  240. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/dbos_durable_exec/workflow_ids.py +0 -0
  241. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/dbos_durable_exec/wrapper.py +0 -0
  242. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/destructive_command_guard/__init__.py +0 -0
  243. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/destructive_command_guard/detector.py +0 -0
  244. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/destructive_command_guard/register_callbacks.py +0 -0
  245. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/emoji_filter/__init__.py +0 -0
  246. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/emoji_filter/config.py +0 -0
  247. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/emoji_filter/register_callbacks.py +0 -0
  248. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/emoji_filter/stripper.py +0 -0
  249. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/example_custom_command/README.md +0 -0
  250. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
  251. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
  252. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
  253. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/force_push_guard/__init__.py +0 -0
  254. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/force_push_guard/detector.py +0 -0
  255. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/force_push_guard/register_callbacks.py +0 -0
  256. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/force_push_guard/test_detector.py +0 -0
  257. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/frontend_emitter/__init__.py +0 -0
  258. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/frontend_emitter/emitter.py +0 -0
  259. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/frontend_emitter/register_callbacks.py +0 -0
  260. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/frontend_emitter/session_context.py +0 -0
  261. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/hook_creator/__init__.py +0 -0
  262. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/hook_creator/register_callbacks.py +0 -0
  263. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/hook_manager/__init__.py +0 -0
  264. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/hook_manager/config.py +0 -0
  265. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/hook_manager/hooks_menu.py +0 -0
  266. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/hook_manager/register_callbacks.py +0 -0
  267. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/oauth_puppy_html.py +0 -0
  268. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/obsidian_agent/README.md +0 -0
  269. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/obsidian_agent/__init__.py +0 -0
  270. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/obsidian_agent/agent_obsidian.py +0 -0
  271. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/obsidian_agent/register_callbacks.py +0 -0
  272. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/ollama/__init__.py +0 -0
  273. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/ollama/register_callbacks.py +0 -0
  274. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/ollama_setup/__init__.py +0 -0
  275. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/ollama_setup/completer.py +0 -0
  276. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/ollama_setup/register_callbacks.py +0 -0
  277. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/plugin_list/__init__.py +0 -0
  278. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/pop_command/__init__.py +0 -0
  279. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/pop_command/register_callbacks.py +0 -0
  280. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/prompt_newline/__init__.py +0 -0
  281. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/prompt_newline/config.py +0 -0
  282. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/prompt_newline/register_callbacks.py +0 -0
  283. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/prune/__init__.py +0 -0
  284. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/prune/prune_menu.py +0 -0
  285. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/prune/prune_model.py +0 -0
  286. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/prune/prune_render.py +0 -0
  287. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/prune/register_callbacks.py +0 -0
  288. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/puppy_kennel/README.md +0 -0
  289. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/puppy_kennel/__init__.py +0 -0
  290. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/puppy_kennel/commands.py +0 -0
  291. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/puppy_kennel/config.py +0 -0
  292. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/puppy_kennel/kennel.py +0 -0
  293. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/puppy_kennel/packer.py +0 -0
  294. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/puppy_kennel/recorder.py +0 -0
  295. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/puppy_kennel/register_callbacks.py +0 -0
  296. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/puppy_kennel/retriever.py +0 -0
  297. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/puppy_kennel/schema.py +0 -0
  298. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/puppy_kennel/state.py +0 -0
  299. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/puppy_kennel/tools.py +0 -0
  300. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/puppy_kennel/wings.py +0 -0
  301. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/quick_resume/__init__.py +0 -0
  302. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/quick_resume/register_callbacks.py +0 -0
  303. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/review_pr/__init__.py +0 -0
  304. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/review_pr/register_callbacks.py +0 -0
  305. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/shell_safety/__init__.py +0 -0
  306. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
  307. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
  308. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
  309. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/statusline/__init__.py +0 -0
  310. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/statusline/config.py +0 -0
  311. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/statusline/payload.py +0 -0
  312. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/statusline/prompt_patch.py +0 -0
  313. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/statusline/register_callbacks.py +0 -0
  314. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/statusline/runner.py +0 -0
  315. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/statusline/statusline_command.py +0 -0
  316. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/subagent_panel/README.md +0 -0
  317. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/subagent_panel/__init__.py +0 -0
  318. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/subagent_panel/coalesce_patch.py +0 -0
  319. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/subagent_panel/register_callbacks.py +0 -0
  320. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/subagent_panel/resume_repaint.py +0 -0
  321. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/subagent_panel/state.py +0 -0
  322. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/switch_agent_resume/__init__.py +0 -0
  323. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/synthetic_status/__init__.py +0 -0
  324. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/synthetic_status/register_callbacks.py +0 -0
  325. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/synthetic_status/status_api.py +0 -0
  326. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/theme/README.md +0 -0
  327. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/theme/__init__.py +0 -0
  328. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/theme/bundled_palettes.py +0 -0
  329. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/theme/content_styles.py +0 -0
  330. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/theme/osc_palette.py +0 -0
  331. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/theme/picker.py +0 -0
  332. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/theme/register_callbacks.py +0 -0
  333. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/theme/rich_themes.py +0 -0
  334. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/theme/themes.py +0 -0
  335. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/token_ratio_learner/__init__.py +0 -0
  336. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/token_ratio_learner/ratios.py +0 -0
  337. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/token_ratio_learner/register_callbacks.py +0 -0
  338. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/universal_constructor/__init__.py +0 -0
  339. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/universal_constructor/models.py +0 -0
  340. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/universal_constructor/register_callbacks.py +0 -0
  341. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/universal_constructor/registry.py +0 -0
  342. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/universal_constructor/sandbox.py +0 -0
  343. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/wide_completion_menu/__init__.py +0 -0
  344. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/wide_completion_menu/register_callbacks.py +0 -0
  345. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/wiggum/__init__.py +0 -0
  346. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/wiggum/judge.py +0 -0
  347. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/wiggum/judge_config.py +0 -0
  348. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/wiggum/register_callbacks.py +0 -0
  349. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/plugins/wiggum/state.py +0 -0
  350. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/provider_credentials.py +0 -0
  351. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/provider_identity.py +0 -0
  352. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/pydantic_patches.py +0 -0
  353. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/reopenable_async_client.py +0 -0
  354. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/round_robin_model.py +0 -0
  355. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/status_display.py +0 -0
  356. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/summarization_agent.py +0 -0
  357. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/terminal_utils.py +0 -0
  358. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/__init__.py +0 -0
  359. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/agent_tools.py +0 -0
  360. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/ask_user_question/__init__.py +0 -0
  361. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/ask_user_question/constants.py +0 -0
  362. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/ask_user_question/demo_tui.py +0 -0
  363. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/ask_user_question/handler.py +0 -0
  364. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/ask_user_question/models.py +0 -0
  365. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/ask_user_question/registration.py +0 -0
  366. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/ask_user_question/renderers.py +0 -0
  367. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/ask_user_question/terminal_ui.py +0 -0
  368. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/ask_user_question/theme.py +0 -0
  369. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/ask_user_question/tui_loop.py +0 -0
  370. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/browser/__init__.py +0 -0
  371. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/browser/browser_control.py +0 -0
  372. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/browser/browser_interactions.py +0 -0
  373. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/browser/browser_locators.py +0 -0
  374. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/browser/browser_manager.py +0 -0
  375. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/browser/browser_navigation.py +0 -0
  376. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/browser/browser_screenshot.py +0 -0
  377. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/browser/browser_scripts.py +0 -0
  378. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/browser/browser_workflows.py +0 -0
  379. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/command_runner.py +0 -0
  380. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/common.py +0 -0
  381. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/display.py +0 -0
  382. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/file_modifications.py +0 -0
  383. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/file_operations.py +0 -0
  384. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/image_tools.py +0 -0
  385. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/model_tools.py +0 -0
  386. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/skills_tools.py +0 -0
  387. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/subagent_context.py +0 -0
  388. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/subagent_invocation.py +0 -0
  389. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/tools_content.py +0 -0
  390. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/tools/universal_constructor.py +0 -0
  391. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/undo_manager.py +0 -0
  392. {code_puppy-0.0.577 → code_puppy-0.0.579}/code_puppy/uvx_detection.py +0 -0
  393. {code_puppy-0.0.577 → code_puppy-0.0.579}/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.577
3
+ Version: 0.0.579
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
@@ -27,7 +27,7 @@ from code_puppy.config import (
27
27
  COMMAND_HISTORY_FILE,
28
28
  ensure_config_exists,
29
29
  finalize_autosave_session,
30
- get_current_autosave_session_name,
30
+ get_current_session_name,
31
31
  initialize_command_history_file,
32
32
  record_terminal_session,
33
33
  save_command_to_history,
@@ -82,57 +82,6 @@ def _render_turn_exception(exc: Exception) -> None:
82
82
  get_queue_console().print_exception()
83
83
 
84
84
 
85
- def _resume_session_from_path(raw_path: str) -> None:
86
- """Restore agent message history from a saved .pkl session file.
87
-
88
- Accepts any path (autosaves, contexts, somewhere weird on disk). We don't
89
- care where it lives — we just decompose into (parent_dir, stem) and reuse
90
- ``session_storage.load_session`` so we stay DRY.
91
- """
92
- from code_puppy.agents.agent_manager import get_current_agent
93
- from code_puppy.messaging import emit_error, emit_success
94
- from code_puppy.session_storage import load_session
95
-
96
- session_path = Path(raw_path).expanduser().resolve()
97
-
98
- if not session_path.exists():
99
- emit_error(f"--resume: session file not found: {session_path}")
100
- sys.exit(1)
101
-
102
- if session_path.suffix != ".pkl":
103
- emit_error(
104
- f"--resume: expected a .pkl session file, got '{session_path.suffix}': {session_path}"
105
- )
106
- sys.exit(1)
107
-
108
- try:
109
- history = load_session(session_path.stem, session_path.parent)
110
- except Exception as exc:
111
- emit_error(f"--resume: failed to load session: {exc}")
112
- sys.exit(1)
113
-
114
- try:
115
- agent = get_current_agent()
116
- agent.set_message_history(history)
117
- except Exception as exc:
118
- emit_error(f"--resume: failed to attach history to agent: {exc}")
119
- sys.exit(1)
120
-
121
- # Rotate autosave id so we don't clobber the original file we just resumed.
122
- try:
123
- from code_puppy.config import rotate_autosave_id
124
-
125
- rotate_autosave_id()
126
- except Exception:
127
- pass # autosave rotation is best-effort
128
-
129
- total_tokens = sum(agent.estimate_tokens_for_message(m) for m in history)
130
- emit_success(
131
- f"✅ Resumed session: {len(history)} messages ({total_tokens} tokens)\n"
132
- f"📁 From: {session_path}"
133
- )
134
-
135
-
136
85
  def apply_quick_resume(args) -> bool:
137
86
  """Resolve ``--quick-resume [PATH]`` into ``args.resume`` so the existing
138
87
  resume machinery loads it.
@@ -447,14 +396,98 @@ async def main():
447
396
  else:
448
397
  default_version_mismatch_behavior(current_version)
449
398
 
399
+ # One-shot sweep of legacy ~/.code_puppy/contexts/ into the unified
400
+ # autosaves/ store. Idempotent via a sentinel; safe to call every
401
+ # startup. MUST run before any plugin startup callback can read
402
+ # AUTOSAVE_DIR (otherwise a plugin could miss freshly-swept files)
403
+ # and before the resume block below resolves -r NAME.
404
+ try:
405
+ from code_puppy.session_migration import sweep_contexts_to_autosaves
406
+
407
+ sweep_contexts_to_autosaves()
408
+ except Exception:
409
+ # Sweep failure must never block startup -- it logs internally.
410
+ pass
411
+
450
412
  await callbacks.on_startup()
451
413
 
452
414
  # Resolve --quick-resume [PATH] into --resume so the resume machinery below
453
415
  # loads the most recent session for that canonical (git-root + branch) scope.
454
416
  apply_quick_resume(args)
455
417
 
418
+ # Holds the resolved (normalised) session name when -r/--resume is in
419
+ # effect, so save-back paths can persist into the same file the resolver
420
+ # opened — not the raw user input (which might be ``foo.pkl`` or an
421
+ # absolute path that the resolver normalised to a bare slug).
422
+ resolved_resume_session: str | None = None
423
+
456
424
  if args.resume:
457
- _resume_session_from_path(args.resume)
425
+ from code_puppy.agents.agent_manager import get_current_agent
426
+ from code_puppy.config import AUTOSAVE_DIR, pin_current_session_name
427
+ from code_puppy.messaging import emit_error, emit_info, emit_success
428
+ from code_puppy.session_lifecycle import (
429
+ ResumeTargetError,
430
+ resolve_or_create_resume_target,
431
+ )
432
+ from code_puppy.session_storage import list_sessions, load_session
433
+
434
+ resume_target = args.resume
435
+ sessions_dir = Path(AUTOSAVE_DIR)
436
+
437
+ # Lazy-create is symmetric across modes: both headless and
438
+ # interactive accept ``-r missing-name`` and materialise an
439
+ # empty session. The typo-guard concern is preserved by the
440
+ # visible ``Created new session: NAME`` info line plus the
441
+ # empty ``message_count: 0`` initial state.
442
+ try:
443
+ session_name, session_dir, lazy_created = resolve_or_create_resume_target(
444
+ resume_target,
445
+ sessions_dir=sessions_dir,
446
+ allow_lazy_create=True,
447
+ )
448
+ except ResumeTargetError as resolve_exc:
449
+ emit_error(resolve_exc.message)
450
+ if resolve_exc.hint:
451
+ emit_info(resolve_exc.hint)
452
+ available = list_sessions(sessions_dir)
453
+ if available:
454
+ emit_info(f"Available sessions: {', '.join(available[:10])}")
455
+ sys.exit(1)
456
+
457
+ # When lazy-create fired, announce it so scripts and users can
458
+ # distinguish first-run creation from a normal resume.
459
+ if lazy_created:
460
+ emit_info(f"Created new session: {session_name}")
461
+
462
+ try:
463
+ history = load_session(session_name, session_dir)
464
+ agent = get_current_agent()
465
+ agent.set_message_history(history)
466
+ total_tokens = sum(agent.estimate_tokens_for_message(m) for m in history)
467
+
468
+ # Pin the singleton so periodic autosave AND headless save-back
469
+ # both update this named file in place. Replaces the old
470
+ # rotate_autosave_id() call, which under unification would
471
+ # actively undo the named-session wiring we want.
472
+ #
473
+ # Note: even when the user resumed via an absolute path
474
+ # (resolver branches 1 or 3), we pin the *stem* and let
475
+ # subsequent writes land in AUTOSAVE_DIR. That keeps cross-mode
476
+ # resume by name consistent; users who passed a one-off path
477
+ # can copy the resulting AUTOSAVE_DIR file back if they care.
478
+ pin_current_session_name(session_name)
479
+
480
+ # Record the resolved name for the headless save-back path below.
481
+ resolved_resume_session = session_name
482
+
483
+ if not lazy_created:
484
+ emit_success(
485
+ f"Resumed: {len(history)} messages "
486
+ f"({total_tokens} tokens) from {session_name}"
487
+ )
488
+ except Exception as e:
489
+ emit_error(f"Failed to resume from {resume_target}: {e}")
490
+ sys.exit(1)
458
491
 
459
492
  global shutdown_flag
460
493
  shutdown_flag = False
@@ -470,7 +503,11 @@ async def main():
470
503
  prompt_only_mode = False
471
504
 
472
505
  if prompt_only_mode:
473
- await execute_single_prompt(initial_command, message_renderer)
506
+ await execute_single_prompt(
507
+ initial_command,
508
+ message_renderer,
509
+ session_name=resolved_resume_session,
510
+ )
474
511
  else:
475
512
  # Default to interactive mode (no args = same as -i)
476
513
  await interactive_mode(message_renderer, initial_command=initial_command)
@@ -652,55 +689,7 @@ async def interactive_mode(message_renderer, initial_command: str = None) -> Non
652
689
 
653
690
  # Autosave loading is now manual - use /autosave_load command
654
691
 
655
- # Track this terminal's active session for /switch-agent auto-resume
656
- record_terminal_session(get_current_autosave_session_name(), overwrite=False)
657
-
658
- # Auto-run tutorial on first startup
659
- try:
660
- from code_puppy.command_line.onboarding_wizard import should_show_onboarding
661
-
662
- if should_show_onboarding():
663
- import concurrent.futures
664
-
665
- from code_puppy.command_line.onboarding_wizard import run_onboarding_wizard
666
- from code_puppy.config import set_model_name
667
- from code_puppy.messaging import emit_info
668
-
669
- from code_puppy.command_line.onboarding_wizard import (
670
- require_model_setup_if_needed,
671
- )
672
-
673
- with concurrent.futures.ThreadPoolExecutor() as executor:
674
- future = executor.submit(lambda: asyncio.run(run_onboarding_wizard()))
675
- result = future.result(timeout=300)
676
-
677
- if result == "chatgpt":
678
- emit_info("🔐 Starting ChatGPT OAuth flow...")
679
- from code_puppy.plugins.chatgpt_oauth.oauth_flow import run_oauth_flow
680
-
681
- run_oauth_flow()
682
- set_model_name("chatgpt-gpt-5.4")
683
- elif result == "claude":
684
- emit_info("🔐 Starting Claude Code OAuth flow...")
685
- from code_puppy.plugins.claude_code_oauth.register_callbacks import (
686
- _perform_authentication,
687
- )
688
-
689
- _perform_authentication()
690
- set_model_name("claude-code-claude-opus-4-7")
691
- elif result == "completed":
692
- emit_info("🎉 Tutorial complete! Happy coding!")
693
- elif result == "skipped":
694
- emit_info("⏭️ Tutorial skipped. Run /tutorial anytime!")
695
-
696
- # No bundled default model anymore: if the user skipped OAuth they
697
- # must add a model explicitly.
698
- require_model_setup_if_needed(result)
699
- except Exception as e:
700
- from code_puppy.messaging import emit_warning
701
-
702
- emit_warning(f"Tutorial auto-start failed: {e}")
703
-
692
+ record_terminal_session(get_current_session_name(), overwrite=False)
704
693
  # Track the current agent task for cancellation on quit
705
694
  current_agent_task = None
706
695
 
@@ -856,7 +845,7 @@ async def interactive_mode(message_renderer, initial_command: str = None) -> Non
856
845
  interactive_autosave_picker,
857
846
  )
858
847
  from code_puppy.config import (
859
- set_current_autosave_from_session_name,
848
+ pin_current_session_name,
860
849
  )
861
850
  from code_puppy.messaging import (
862
851
  emit_error,
@@ -882,7 +871,7 @@ async def interactive_mode(message_renderer, initial_command: str = None) -> Non
882
871
  agent.set_message_history(history)
883
872
 
884
873
  # Set current autosave session
885
- set_current_autosave_from_session_name(chosen_session)
874
+ pin_current_session_name(chosen_session)
886
875
 
887
876
  total_tokens = sum(
888
877
  agent.estimate_tokens_for_message(msg)
@@ -1196,8 +1185,28 @@ async def run_prompt_with_attachments(
1196
1185
  return None, agent_task
1197
1186
 
1198
1187
 
1199
- async def execute_single_prompt(prompt: str, message_renderer) -> None:
1200
- """Execute a single prompt and exit (for -p flag)."""
1188
+ async def execute_single_prompt(
1189
+ prompt: str,
1190
+ message_renderer,
1191
+ *,
1192
+ session_name: str | None = None,
1193
+ ) -> None:
1194
+ """Execute a single prompt and exit (for -p flag).
1195
+
1196
+ When ``session_name`` is supplied (i.e. the user passed ``-r NAME``),
1197
+ history is persisted back to that named session in a ``finally`` block
1198
+ so partial state still lands on cancel / error paths. The runtime
1199
+ prunes interrupted tool calls before returning so the saved history is
1200
+ coherent (see ``agents/_runtime.py`` -- the two ``_message_history``
1201
+ commit/prune sites around lines 446 and 498).
1202
+
1203
+ Edge case worth knowing: when the agent returns ``(None, None)`` for an
1204
+ empty-prompt scenario, the response emit is skipped but the ``finally``
1205
+ still fires, producing a no-op idempotent rewrite of an existing
1206
+ session (and a phantom ``post_autosave`` event for plugin authors who
1207
+ count saves). Acceptable trade-off versus the complexity of a
1208
+ 'something-actually-ran' tracking flag.
1209
+ """
1201
1210
  # Shell pass-through: !<cmd> bypasses the agent even in -p mode
1202
1211
  from code_puppy.command_line.shell_passthrough import (
1203
1212
  execute_shell_passthrough,
@@ -1206,9 +1215,26 @@ async def execute_single_prompt(prompt: str, message_renderer) -> None:
1206
1215
 
1207
1216
  if is_shell_passthrough(prompt):
1208
1217
  execute_shell_passthrough(prompt)
1218
+ # Agent never ran — do NOT touch the named session, otherwise
1219
+ # `-r mywork -p '!ls'` would clobber existing history with an empty
1220
+ # save-back. Return before the try/finally so the save path is
1221
+ # genuinely unreachable, not just guarded.
1209
1222
  return
1210
1223
 
1211
- from code_puppy.messaging import emit_info
1224
+ from code_puppy.messaging import (
1225
+ emit_error,
1226
+ emit_info,
1227
+ emit_warning,
1228
+ get_message_bus,
1229
+ )
1230
+ from code_puppy.messaging.messages import AgentResponseMessage
1231
+
1232
+ # Hoist save-back imports here rather than into the ``finally`` block --
1233
+ # if the user passed ``-r`` we will exercise these on every code path,
1234
+ # and lazy-importing inside ``finally`` just hides the dependency without
1235
+ # buying any actual startup savings (the module is already loaded).
1236
+ from code_puppy.config import AUTOSAVE_DIR
1237
+ from code_puppy.session_lifecycle import persist_named_session
1212
1238
 
1213
1239
  emit_info(f"Executing prompt: {prompt}")
1214
1240
 
@@ -1220,29 +1246,47 @@ async def execute_single_prompt(prompt: str, message_renderer) -> None:
1220
1246
  prompt,
1221
1247
  spinner_console=message_renderer.console,
1222
1248
  )
1223
- if result is None:
1224
- return
1225
-
1226
- agent_response = result.output
1227
-
1228
- # Emit structured message for proper markdown rendering
1229
- from code_puppy.messaging import get_message_bus
1230
- from code_puppy.messaging.messages import AgentResponseMessage
1231
-
1232
- response_msg = AgentResponseMessage(
1233
- content=agent_response,
1234
- is_markdown=True,
1235
- )
1236
- get_message_bus().emit(response_msg)
1249
+ if result is not None:
1250
+ response_msg = AgentResponseMessage(
1251
+ content=result.output,
1252
+ is_markdown=True,
1253
+ )
1254
+ get_message_bus().emit(response_msg)
1255
+
1256
+ # Commit the completed turn (user prompt + assistant response)
1257
+ # into the agent's history BEFORE the finally-block save-back.
1258
+ # Without this, headless -r save-back persists only user prompts
1259
+ # (the normal _do_run path never writes result.all_messages()
1260
+ # back to agent._message_history), so resumed sessions feed the
1261
+ # model a pile of unanswered prompts and it re-answers them all.
1262
+ # Mirrors interactive_mode's post-run set_message_history call.
1263
+ if hasattr(result, "all_messages"):
1264
+ agent.set_message_history(list(result.all_messages()))
1237
1265
 
1238
1266
  except asyncio.CancelledError:
1239
- from code_puppy.messaging import emit_warning
1240
-
1241
1267
  emit_warning("Execution cancelled by user")
1242
1268
  except Exception as e:
1243
- from code_puppy.messaging import emit_error
1244
-
1245
1269
  emit_error(f"Error executing prompt: {str(e)}")
1270
+ finally:
1271
+ if session_name:
1272
+ try:
1273
+ persist_named_session(
1274
+ get_current_agent(),
1275
+ session_name,
1276
+ base_dir=Path(AUTOSAVE_DIR),
1277
+ # Headless -r save-back is automated (user passed a
1278
+ # flag and walked away) rather than an explicit
1279
+ # /dump_context-style intent, so it carries the same
1280
+ # auto_saved=True bit as autosave proper. Plugins
1281
+ # that filter on `metadata.auto_saved` get the right
1282
+ # signal.
1283
+ auto_saved=True,
1284
+ )
1285
+ except Exception as save_exc:
1286
+ # The user's primary deliverable (the agent response) has
1287
+ # already been emitted. Report the save failure but do not
1288
+ # re-raise -- a save bug shouldn't mask a successful turn.
1289
+ emit_error(f"Failed to save session {session_name}: {save_exc}")
1246
1290
 
1247
1291
 
1248
1292
  def _force_utf8_stdio():
@@ -48,8 +48,26 @@ def _get_session_metadata(base_dir: Path, session_name: str) -> dict:
48
48
  return {}
49
49
 
50
50
 
51
+ def _is_auto_flavored(session_name: str) -> bool:
52
+ """Return True for system-generated session names.
53
+
54
+ Matches the ``auto_session_`` prefix reserved by
55
+ ``code_puppy.session_lifecycle.is_valid_session_name``. Pre-unification,
56
+ all autosaves carried this prefix; the unified-autosave migration introduces user-named
57
+ entries (from ``-r NAME``, ``/dump_context``, ``/load_context``) into
58
+ the same store, hence the need to distinguish.
59
+ """
60
+ return session_name.startswith("auto_session_")
61
+
62
+
51
63
  def _get_session_entries(base_dir: Path) -> List[Tuple[str, dict]]:
52
- """Get all sessions with their metadata, sorted by timestamp."""
64
+ """Get all sessions with their metadata.
65
+
66
+ Returns entries grouped "named first, auto-flavored second", each group
67
+ sorted mtime-descending. Section headers (if any) are inserted at
68
+ render time -- see ``_render_menu_panel`` -- to keep this function's
69
+ return shape stable and pagination math straightforward.
70
+ """
53
71
  try:
54
72
  sessions = list_sessions(base_dir)
55
73
  except (FileNotFoundError, PermissionError):
@@ -75,8 +93,11 @@ def _get_session_entries(base_dir: Path) -> List[Tuple[str, dict]]:
75
93
  return datetime.min
76
94
  return datetime.min
77
95
 
78
- entries.sort(key=sort_key, reverse=True)
79
- return entries
96
+ named = [e for e in entries if not _is_auto_flavored(e[0])]
97
+ auto = [e for e in entries if _is_auto_flavored(e[0])]
98
+ named.sort(key=sort_key, reverse=True)
99
+ auto.sort(key=sort_key, reverse=True)
100
+ return named + auto
80
101
 
81
102
 
82
103
  def _extract_last_user_message(history: list) -> str:
@@ -216,10 +237,24 @@ def _render_menu_panel(
216
237
  lines.append(("", "Cancel"))
217
238
  return lines
218
239
 
219
- # Show sessions for current page
240
+ # Show sessions for current page. We inject visual section headers
241
+ # at named->auto boundaries within the visible page (and at the very
242
+ # top if the page starts in either section). Section headers do NOT
243
+ # consume entry indices -- they're cosmetic only -- so selection and
244
+ # pagination math stay untouched.
245
+ prev_section = None
220
246
  for i in range(start_idx, end_idx):
221
247
  session_name, metadata = entries[i]
222
248
  is_selected = i == selected_idx
249
+ section = "auto" if _is_auto_flavored(session_name) else "named"
250
+
251
+ if section != prev_section:
252
+ header = "Named sessions" if section == "named" else "Auto-saved sessions"
253
+ # Blank line between sections (skip for the very first one).
254
+ if prev_section is not None:
255
+ lines.append(("", "\n"))
256
+ lines.append(("fg:ansibrightcyan bold", f" {header}\n"))
257
+ prev_section = section
223
258
 
224
259
  # Format timestamp
225
260
  timestamp = metadata.get("timestamp", "unknown")
@@ -232,11 +267,19 @@ def _render_menu_panel(
232
267
  # Format message count
233
268
  msg_count = metadata.get("message_count", "?")
234
269
 
270
+ # For named sessions, include the name so users can tell them
271
+ # apart at a glance. Auto-flavored sessions keep the existing
272
+ # timestamp+count summary -- the auto_session_* names are noise.
273
+ if section == "named":
274
+ label = f"{time_str} \u2022 {msg_count} msgs ({session_name})"
275
+ else:
276
+ label = f"{time_str} \u2022 {msg_count} msgs"
277
+
235
278
  # Highlight selected item
236
279
  if is_selected:
237
- lines.append(("fg:ansibrightblack", f" > {time_str} • {msg_count} msgs"))
280
+ lines.append(("fg:ansibrightblack", f" > {label}"))
238
281
  else:
239
- lines.append(("fg:ansibrightblack", f" {time_str} • {msg_count} msgs"))
282
+ lines.append(("fg:ansibrightblack", f" {label}"))
240
283
 
241
284
  lines.append(("", "\n"))
242
285
 
@@ -4,13 +4,12 @@ This module contains @register_command decorated handlers that are automatically
4
4
  discovered by the command registry system.
5
5
  """
6
6
 
7
- from datetime import datetime
8
7
  import logging
9
8
  from pathlib import Path
10
9
 
11
10
  from code_puppy.command_line.command_registry import register_command
12
- from code_puppy.config import CONTEXTS_DIR
13
- from code_puppy.session_storage import list_sessions, load_session, save_session
11
+ from code_puppy.config import AUTOSAVE_DIR
12
+ from code_puppy.session_storage import list_sessions, load_session
14
13
 
15
14
  logger = logging.getLogger(__name__)
16
15
 
@@ -64,25 +63,23 @@ def get_commands_help():
64
63
  def handle_session_command(command: str) -> bool:
65
64
  """Handle /session command."""
66
65
  from code_puppy.config import (
67
- AUTOSAVE_DIR,
68
- get_current_autosave_id,
69
- get_current_autosave_session_name,
70
- rotate_autosave_id,
66
+ get_current_session_name,
67
+ rotate_session_name,
71
68
  )
72
69
  from code_puppy.messaging import emit_info, emit_success, emit_warning
73
70
 
74
71
  tokens = command.split()
75
72
 
76
73
  if len(tokens) == 1 or tokens[1] == "id":
77
- sid = get_current_autosave_id()
74
+ session_name = get_current_session_name()
78
75
  emit_info(
79
- f"[bold magenta]Autosave Session[/bold magenta]: {sid}\n"
80
- f"Files prefix: {Path(AUTOSAVE_DIR) / get_current_autosave_session_name()}"
76
+ f"[bold magenta]Autosave Session[/bold magenta]: {session_name}\n"
77
+ f"Files prefix: {Path(AUTOSAVE_DIR) / session_name}"
81
78
  )
82
79
  return True
83
80
  if tokens[1] == "new":
84
- new_sid = rotate_autosave_id()
85
- emit_success(f"New autosave session id: {new_sid}")
81
+ new_name = rotate_session_name()
82
+ emit_success(f"New autosave session: {new_name}")
86
83
  return True
87
84
  emit_warning("Usage: /session [id|new]")
88
85
  return True
@@ -350,7 +347,11 @@ def handle_quick_resume_command(command: str) -> bool:
350
347
  def handle_dump_context_command(command: str) -> bool:
351
348
  """Dump message history to a file."""
352
349
  from code_puppy.agents.agent_manager import get_current_agent
353
- from code_puppy.messaging import emit_error, emit_success, emit_warning
350
+ from code_puppy.messaging import emit_error, emit_warning
351
+ from code_puppy.session_lifecycle import (
352
+ is_valid_session_name,
353
+ persist_named_session,
354
+ )
354
355
 
355
356
  tokens = command.split()
356
357
  if len(tokens) != 2:
@@ -358,24 +359,38 @@ def handle_dump_context_command(command: str) -> bool:
358
359
  return True
359
360
 
360
361
  session_name = tokens[1]
361
- agent = get_current_agent()
362
- history = agent.get_message_history()
362
+ # Enforce reserved-prefix + slug rules at every user-input write site
363
+ # (the resolver enforces them for ``-r NAME``; this is the parallel
364
+ # gate for ``/dump_context``). Without it, /dump_context bypasses
365
+ # the validator that ``-r`` runs and lets a user squat the
366
+ # ``auto_session_`` namespace or smuggle in a path-traversal name.
367
+ if not is_valid_session_name(session_name, allow_reserved_prefix=False):
368
+ emit_error(
369
+ f"Invalid session name: {session_name!r}. "
370
+ "Session names must be 1-128 chars of [A-Za-z0-9._-] "
371
+ "and may not start with 'auto_session_' (reserved)."
372
+ )
373
+ return True
363
374
 
364
- if not history:
375
+ agent = get_current_agent()
376
+ if not agent.get_message_history():
365
377
  emit_warning("No message history to dump!")
366
378
  return True
367
379
 
368
380
  try:
369
- metadata = save_session(
370
- history=history,
371
- session_name=session_name,
372
- base_dir=Path(CONTEXTS_DIR),
373
- timestamp=datetime.now().isoformat(),
374
- token_estimator=agent.estimate_tokens_for_message,
375
- )
376
- emit_success(
377
- f"✅ Context saved: {metadata.message_count} messages ({metadata.total_tokens} tokens)\n"
378
- f"📁 Files: {metadata.pickle_path}, {metadata.metadata_path}"
381
+ # The user-facing success line is preserved verbatim via
382
+ # ``success_message_template`` so /dump_context UX doesn't
383
+ # regress. The silent save-back paths (``-r``, periodic
384
+ # autosave) omit the template and stay quiet.
385
+ persist_named_session(
386
+ agent,
387
+ session_name,
388
+ base_dir=Path(AUTOSAVE_DIR),
389
+ success_message_template=(
390
+ "\u2705 Context saved: {message_count} messages "
391
+ "({total_tokens} tokens)\n"
392
+ "\U0001f4c1 Files: {pickle_path}, {metadata_path}"
393
+ ),
379
394
  )
380
395
  return True
381
396
 
@@ -392,10 +407,8 @@ def handle_dump_context_command(command: str) -> bool:
392
407
  )
393
408
  def handle_load_context_command(command: str) -> bool:
394
409
  """Load message history from a file."""
395
- from rich.text import Text
396
-
397
410
  from code_puppy.agents.agent_manager import get_current_agent
398
- from code_puppy.config import rotate_autosave_id
411
+ from code_puppy.config import rotate_session_name
399
412
  from code_puppy.messaging import emit_error, emit_info, emit_success, emit_warning
400
413
 
401
414
  tokens = command.split()
@@ -404,14 +417,14 @@ def handle_load_context_command(command: str) -> bool:
404
417
  return True
405
418
 
406
419
  session_name = tokens[1]
407
- contexts_dir = Path(CONTEXTS_DIR)
408
- session_path = contexts_dir / f"{session_name}.pkl"
420
+ sessions_dir = Path(AUTOSAVE_DIR)
421
+ session_path = sessions_dir / f"{session_name}.pkl"
409
422
 
410
423
  try:
411
- history = load_session(session_name, contexts_dir)
424
+ history = load_session(session_name, sessions_dir)
412
425
  except FileNotFoundError:
413
426
  emit_error(f"Context file not found: {session_path}")
414
- available = list_sessions(contexts_dir)
427
+ available = list_sessions(sessions_dir)
415
428
  if available:
416
429
  emit_info(f"Available contexts: {', '.join(available)}")
417
430
  return True
@@ -423,22 +436,41 @@ def handle_load_context_command(command: str) -> bool:
423
436
  agent.set_message_history(history)
424
437
  total_tokens = sum(agent.estimate_tokens_for_message(m) for m in history)
425
438
 
426
- # Rotate autosave id to avoid overwriting any existing autosave
427
- try:
428
- new_id = rotate_autosave_id()
429
- autosave_info = Text.from_markup(
430
- f"\n[dim]Autosave session rotated to: {new_id}[/dim]"
431
- )
432
- except Exception:
433
- autosave_info = Text("")
439
+ # Rotate the singleton to a fresh ``auto_session_<TS>`` so subsequent
440
+ # autosaves do NOT overwrite the loaded snapshot. This asymmetry with
441
+ # ``-r NAME`` (which pins and saves back in place) is INTENTIONAL --
442
+ # the two verbs encode two different intents:
443
+ #
444
+ # * ``/dump_context NAME`` + ``/load_context NAME`` are a snapshot
445
+ # pair (think ``pg_dump`` / ``pg_restore``, save games, git
446
+ # stash). The named file is a stable reference point; loading
447
+ # it lets you inspect / branch from it without dirtying the
448
+ # original.
449
+ # * ``-r NAME`` / ``--resume NAME`` is a continuation verb (pick
450
+ # up where you left off). That path pins and saves back.
451
+ #
452
+ # Origin: commit ``cc04629b`` (Mike Pfaffenberger, 2025-10-11)
453
+ # introduced this rotate-on-load behavior as a deliberate design
454
+ # choice; the commit message explicitly says "Automatically rotate
455
+ # session ID when loading saved context to prevent overwrites." The
456
+ # ``-r`` flag was added 4 months later (commit ``92bb0f90``) and
457
+ # the asymmetry was preserved -- on purpose. Do NOT "unify" these
458
+ # two paths in the name of symmetry; you'd be deleting the encoded
459
+ # distinction between snapshot-load and continuation-resume.
460
+ #
461
+ # If a user wants to continue working on the loaded snapshot in
462
+ # place, the explicit move is ``/load_context NAME`` followed by
463
+ # ``/dump_context NAME`` later -- or relaunch via ``-r NAME``.
464
+ new_autosave_id = rotate_session_name()
434
465
 
435
- # Build the success message with proper Text concatenation
436
- success_msg = Text(
437
- f"✅ Context loaded: {len(history)} messages ({total_tokens} tokens)\n"
438
- f"📁 From: {session_path}"
466
+ emit_success(
467
+ f"\u2705 Context loaded: {len(history)} messages "
468
+ f"({total_tokens} tokens)\n"
469
+ f"\U0001f4c1 From: {session_path}\n"
470
+ f"\U0001f504 Autosave rotated to: {new_autosave_id} "
471
+ f"(snapshot at {session_path.name} is preserved; further "
472
+ f"autosaves land in the new session)"
439
473
  )
440
- success_msg.append_text(autosave_info)
441
- emit_success(success_msg)
442
474
 
443
475
  # Display recent message history for context
444
476
  from code_puppy.command_line.autosave_menu import display_resumed_history