code-puppy 0.0.344__tar.gz → 0.0.345__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 (182) hide show
  1. {code_puppy-0.0.344 → code_puppy-0.0.345}/PKG-INFO +1 -1
  2. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/add_model_menu.py +8 -9
  3. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/catalog_server_installer.py +5 -6
  4. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/custom_server_installer.py +6 -7
  5. code_puppy-0.0.345/code_puppy/command_line/utils.py +93 -0
  6. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/managed_server.py +3 -2
  7. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/messaging/message_queue.py +11 -23
  8. {code_puppy-0.0.344 → code_puppy-0.0.345}/pyproject.toml +1 -1
  9. code_puppy-0.0.344/code_puppy/command_line/utils.py +0 -39
  10. {code_puppy-0.0.344 → code_puppy-0.0.345}/.gitignore +0 -0
  11. {code_puppy-0.0.344 → code_puppy-0.0.345}/LICENSE +0 -0
  12. {code_puppy-0.0.344 → code_puppy-0.0.345}/README.md +0 -0
  13. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/__init__.py +0 -0
  14. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/__main__.py +0 -0
  15. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/__init__.py +0 -0
  16. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_c_reviewer.py +0 -0
  17. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_code_puppy.py +0 -0
  18. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_code_reviewer.py +0 -0
  19. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_cpp_reviewer.py +0 -0
  20. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_creator_agent.py +0 -0
  21. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_golang_reviewer.py +0 -0
  22. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_javascript_reviewer.py +0 -0
  23. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_manager.py +0 -0
  24. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_planning.py +0 -0
  25. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_python_programmer.py +0 -0
  26. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_python_reviewer.py +0 -0
  27. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_qa_expert.py +0 -0
  28. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_qa_kitten.py +0 -0
  29. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_security_auditor.py +0 -0
  30. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/agent_typescript_reviewer.py +0 -0
  31. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/base_agent.py +0 -0
  32. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/json_agent.py +0 -0
  33. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/agents/prompt_reviewer.py +0 -0
  34. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/callbacks.py +0 -0
  35. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/chatgpt_codex_client.py +0 -0
  36. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/claude_cache_client.py +0 -0
  37. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/cli_runner.py +0 -0
  38. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/__init__.py +0 -0
  39. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/attachments.py +0 -0
  40. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/autosave_menu.py +0 -0
  41. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/clipboard.py +0 -0
  42. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/colors_menu.py +0 -0
  43. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/command_handler.py +0 -0
  44. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/command_registry.py +0 -0
  45. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/config_commands.py +0 -0
  46. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/core_commands.py +0 -0
  47. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/diff_menu.py +0 -0
  48. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/file_path_completion.py +0 -0
  49. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/load_context_completion.py +0 -0
  50. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/__init__.py +0 -0
  51. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/base.py +0 -0
  52. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
  53. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/edit_command.py +0 -0
  54. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/handler.py +0 -0
  55. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/help_command.py +0 -0
  56. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/install_command.py +0 -0
  57. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/install_menu.py +0 -0
  58. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/list_command.py +0 -0
  59. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/logs_command.py +0 -0
  60. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/remove_command.py +0 -0
  61. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/restart_command.py +0 -0
  62. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/search_command.py +0 -0
  63. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/start_all_command.py +0 -0
  64. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/start_command.py +0 -0
  65. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/status_command.py +0 -0
  66. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
  67. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/stop_command.py +0 -0
  68. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/test_command.py +0 -0
  69. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/utils.py +0 -0
  70. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
  71. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/mcp_completion.py +0 -0
  72. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/model_picker_completion.py +0 -0
  73. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/model_settings_menu.py +0 -0
  74. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/motd.py +0 -0
  75. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/onboarding_slides.py +0 -0
  76. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/onboarding_wizard.py +0 -0
  77. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/pin_command_completion.py +0 -0
  78. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
  79. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/command_line/session_commands.py +0 -0
  80. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/config.py +0 -0
  81. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/error_logging.py +0 -0
  82. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/gemini_code_assist.py +0 -0
  83. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/http_utils.py +0 -0
  84. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/keymap.py +0 -0
  85. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/main.py +0 -0
  86. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/__init__.py +0 -0
  87. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/async_lifecycle.py +0 -0
  88. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/blocking_startup.py +0 -0
  89. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/captured_stdio_server.py +0 -0
  90. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/circuit_breaker.py +0 -0
  91. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/config_wizard.py +0 -0
  92. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/dashboard.py +0 -0
  93. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/error_isolation.py +0 -0
  94. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/examples/retry_example.py +0 -0
  95. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/health_monitor.py +0 -0
  96. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/manager.py +0 -0
  97. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/mcp_logs.py +0 -0
  98. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/registry.py +0 -0
  99. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/retry_manager.py +0 -0
  100. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/server_registry_catalog.py +0 -0
  101. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/status_tracker.py +0 -0
  102. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/mcp_/system_tools.py +0 -0
  103. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/messaging/__init__.py +0 -0
  104. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/messaging/bus.py +0 -0
  105. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/messaging/commands.py +0 -0
  106. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/messaging/markdown_patches.py +0 -0
  107. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/messaging/messages.py +0 -0
  108. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/messaging/queue_console.py +0 -0
  109. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/messaging/renderers.py +0 -0
  110. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/messaging/rich_renderer.py +0 -0
  111. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/messaging/spinner/__init__.py +0 -0
  112. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/messaging/spinner/console_spinner.py +0 -0
  113. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/messaging/spinner/spinner_base.py +0 -0
  114. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/model_factory.py +0 -0
  115. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/model_utils.py +0 -0
  116. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/models.json +0 -0
  117. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/models_dev_api.json +0 -0
  118. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/models_dev_parser.py +0 -0
  119. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/__init__.py +0 -0
  120. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/antigravity_oauth/__init__.py +0 -0
  121. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/antigravity_oauth/accounts.py +0 -0
  122. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/antigravity_oauth/antigravity_model.py +0 -0
  123. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/antigravity_oauth/config.py +0 -0
  124. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/antigravity_oauth/constants.py +0 -0
  125. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/antigravity_oauth/oauth.py +0 -0
  126. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/antigravity_oauth/register_callbacks.py +0 -0
  127. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/antigravity_oauth/storage.py +0 -0
  128. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/antigravity_oauth/test_plugin.py +0 -0
  129. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/antigravity_oauth/token.py +0 -0
  130. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/antigravity_oauth/transport.py +0 -0
  131. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/antigravity_oauth/utils.py +0 -0
  132. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
  133. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
  134. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
  135. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
  136. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
  137. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
  138. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
  139. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
  140. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
  141. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
  142. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +0 -0
  143. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
  144. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/claude_code_oauth/utils.py +0 -0
  145. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
  146. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
  147. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/example_custom_command/README.md +0 -0
  148. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
  149. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
  150. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
  151. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/oauth_puppy_html.py +0 -0
  152. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/shell_safety/__init__.py +0 -0
  153. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
  154. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
  155. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
  156. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/prompts/codex_system_prompt.md +0 -0
  157. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/pydantic_patches.py +0 -0
  158. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/reopenable_async_client.py +0 -0
  159. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/round_robin_model.py +0 -0
  160. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/session_storage.py +0 -0
  161. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/status_display.py +0 -0
  162. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/summarization_agent.py +0 -0
  163. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/terminal_utils.py +0 -0
  164. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/__init__.py +0 -0
  165. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/agent_tools.py +0 -0
  166. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/browser/__init__.py +0 -0
  167. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/browser/browser_control.py +0 -0
  168. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/browser/browser_interactions.py +0 -0
  169. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/browser/browser_locators.py +0 -0
  170. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/browser/browser_navigation.py +0 -0
  171. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/browser/browser_screenshot.py +0 -0
  172. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/browser/browser_scripts.py +0 -0
  173. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/browser/browser_workflows.py +0 -0
  174. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/browser/camoufox_manager.py +0 -0
  175. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/browser/vqa_agent.py +0 -0
  176. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/command_runner.py +0 -0
  177. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/common.py +0 -0
  178. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/file_modifications.py +0 -0
  179. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/file_operations.py +0 -0
  180. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/tools/tools_content.py +0 -0
  181. {code_puppy-0.0.344 → code_puppy-0.0.345}/code_puppy/uvx_detection.py +0 -0
  182. {code_puppy-0.0.344 → code_puppy-0.0.345}/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.344
3
+ Version: 0.0.345
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
@@ -17,6 +17,7 @@ from prompt_toolkit.layout import Dimension, Layout, VSplit, Window
17
17
  from prompt_toolkit.layout.controls import FormattedTextControl
18
18
  from prompt_toolkit.widgets import Frame
19
19
 
20
+ from code_puppy.command_line.utils import safe_input
20
21
  from code_puppy.config import EXTRA_MODELS_FILE, set_config_value
21
22
  from code_puppy.messaging import emit_error, emit_info, emit_warning
22
23
  from code_puppy.models_dev_parser import ModelInfo, ModelsDevRegistry, ProviderInfo
@@ -724,8 +725,8 @@ class AddModelMenu:
724
725
  emit_info(f" {hint}")
725
726
 
726
727
  try:
727
- # Use regular input - simpler and works in threaded context
728
- value = input(f" Enter {env_var} (or press Enter to skip): ").strip()
728
+ # Use safe_input for cross-platform compatibility (Windows fix)
729
+ value = safe_input(f" Enter {env_var} (or press Enter to skip): ")
729
730
 
730
731
  if not value:
731
732
  emit_warning(
@@ -785,7 +786,7 @@ class AddModelMenu:
785
786
  )
786
787
 
787
788
  try:
788
- model_name = input(" Model ID: ").strip()
789
+ model_name = safe_input(" Model ID: ")
789
790
 
790
791
  if not model_name:
791
792
  emit_warning("No model name provided, cancelled.")
@@ -795,7 +796,7 @@ class AddModelMenu:
795
796
  emit_info("\n Enter the context window size (in tokens).")
796
797
  emit_info(" Common sizes: 8192, 32768, 128000, 200000, 1000000\n")
797
798
 
798
- context_input = input(" Context size [128000]: ").strip()
799
+ context_input = safe_input(" Context size [128000]: ")
799
800
 
800
801
  if not context_input:
801
802
  context_length = 128000 # Default
@@ -1045,11 +1046,9 @@ class AddModelMenu:
1045
1046
  f" It will be very limited for coding tasks."
1046
1047
  )
1047
1048
  try:
1048
- confirm = (
1049
- input("\n Are you sure you want to add this model? (y/N): ")
1050
- .strip()
1051
- .lower()
1052
- )
1049
+ confirm = safe_input(
1050
+ "\n Are you sure you want to add this model? (y/N): "
1051
+ ).lower()
1053
1052
  if confirm not in ("y", "yes"):
1054
1053
  emit_info("Model addition cancelled.")
1055
1054
  return False
@@ -7,6 +7,7 @@ MCP servers from the catalog.
7
7
  import os
8
8
  from typing import Dict, Optional
9
9
 
10
+ from code_puppy.command_line.utils import safe_input
10
11
  from code_puppy.messaging import emit_info, emit_success, emit_warning
11
12
 
12
13
  # Helpful hints for common environment variables
@@ -52,7 +53,7 @@ def prompt_for_server_config(manager, server) -> Optional[Dict]:
52
53
  # Get custom name
53
54
  default_name = server.name
54
55
  try:
55
- name_input = input(f" Server name [{default_name}]: ").strip()
56
+ name_input = safe_input(f" Server name [{default_name}]: ")
56
57
  server_name = name_input if name_input else default_name
57
58
  except (KeyboardInterrupt, EOFError):
58
59
  emit_info("")
@@ -63,9 +64,7 @@ def prompt_for_server_config(manager, server) -> Optional[Dict]:
63
64
  existing = find_server_id_by_name(manager, server_name)
64
65
  if existing:
65
66
  try:
66
- override = input(
67
- f" Server '{server_name}' exists. Override? [y/N]: "
68
- ).strip()
67
+ override = safe_input(f" Server '{server_name}' exists. Override? [y/N]: ")
69
68
  if not override.lower().startswith("y"):
70
69
  emit_warning("Installation cancelled")
71
70
  return None
@@ -91,7 +90,7 @@ def prompt_for_server_config(manager, server) -> Optional[Dict]:
91
90
  hint = get_env_var_hint(var)
92
91
  if hint:
93
92
  emit_info(f" {hint}")
94
- value = input(f" Enter {var}: ").strip()
93
+ value = safe_input(f" Enter {var}: ")
95
94
  if value:
96
95
  env_vars[var] = value
97
96
  # Save to config for future use
@@ -119,7 +118,7 @@ def prompt_for_server_config(manager, server) -> Optional[Dict]:
119
118
  prompt_str += " (optional)"
120
119
 
121
120
  try:
122
- value = input(f"{prompt_str}: ").strip()
121
+ value = safe_input(f"{prompt_str}: ")
123
122
  if value:
124
123
  cmd_args[name] = value
125
124
  elif default:
@@ -7,6 +7,7 @@ custom MCP servers with JSON configuration.
7
7
  import json
8
8
  import os
9
9
 
10
+ from code_puppy.command_line.utils import safe_input
10
11
  from code_puppy.messaging import emit_error, emit_info, emit_success, emit_warning
11
12
 
12
13
  # Example configurations for each server type
@@ -58,7 +59,7 @@ def prompt_and_install_custom_server(manager) -> bool:
58
59
 
59
60
  # Get server name
60
61
  try:
61
- server_name = input(" Server name: ").strip()
62
+ server_name = safe_input(" Server name: ")
62
63
  if not server_name:
63
64
  emit_warning("Server name is required")
64
65
  return False
@@ -71,9 +72,7 @@ def prompt_and_install_custom_server(manager) -> bool:
71
72
  existing = find_server_id_by_name(manager, server_name)
72
73
  if existing:
73
74
  try:
74
- override = input(
75
- f" Server '{server_name}' exists. Override? [y/N]: "
76
- ).strip()
75
+ override = safe_input(f" Server '{server_name}' exists. Override? [y/N]: ")
77
76
  if not override.lower().startswith("y"):
78
77
  emit_warning("Cancelled")
79
78
  return False
@@ -89,7 +88,7 @@ def prompt_and_install_custom_server(manager) -> bool:
89
88
  emit_info(" 3. 📡 sse - Server-Sent Events\n")
90
89
 
91
90
  try:
92
- type_choice = input(" Enter choice [1-3]: ").strip()
91
+ type_choice = safe_input(" Enter choice [1-3]: ")
93
92
  except (KeyboardInterrupt, EOFError):
94
93
  emit_info("")
95
94
  emit_warning("Cancelled")
@@ -115,8 +114,8 @@ def prompt_and_install_custom_server(manager) -> bool:
115
114
  empty_count = 0
116
115
  try:
117
116
  while True:
118
- line = input()
119
- if line.strip() == "":
117
+ line = safe_input("")
118
+ if line == "":
120
119
  empty_count += 1
121
120
  if empty_count >= 2:
122
121
  break
@@ -0,0 +1,93 @@
1
+ import os
2
+ from typing import List, Tuple
3
+
4
+ from rich.table import Table
5
+
6
+
7
+ def list_directory(path: str = None) -> Tuple[List[str], List[str]]:
8
+ """
9
+ Returns (dirs, files) for the specified path, splitting out directories and files.
10
+ """
11
+ if path is None:
12
+ path = os.getcwd()
13
+ entries = []
14
+ try:
15
+ entries = [e for e in os.listdir(path)]
16
+ except Exception as e:
17
+ raise RuntimeError(f"Error listing directory: {e}")
18
+ dirs = [e for e in entries if os.path.isdir(os.path.join(path, e))]
19
+ files = [e for e in entries if not os.path.isdir(os.path.join(path, e))]
20
+ return dirs, files
21
+
22
+
23
+ def make_directory_table(path: str = None) -> Table:
24
+ """
25
+ Returns a rich.Table object containing the directory listing.
26
+ """
27
+ if path is None:
28
+ path = os.getcwd()
29
+ dirs, files = list_directory(path)
30
+ table = Table(
31
+ title=f"\U0001f4c1 [bold blue]Current directory:[/bold blue] [cyan]{path}[/cyan]"
32
+ )
33
+ table.add_column("Type", style="dim", width=8)
34
+ table.add_column("Name", style="bold")
35
+ for d in sorted(dirs):
36
+ table.add_row("[green]dir[/green]", f"[cyan]{d}[/cyan]")
37
+ for f in sorted(files):
38
+ table.add_row("[yellow]file[/yellow]", f"{f}")
39
+ return table
40
+
41
+
42
+ def _reset_windows_console() -> None:
43
+ """Reset Windows console to normal input mode.
44
+
45
+ After a prompt_toolkit Application exits on Windows, the console can be
46
+ left in a weird state where Enter doesn't work properly. This resets it.
47
+ """
48
+ import sys
49
+
50
+ if sys.platform != "win32":
51
+ return
52
+
53
+ try:
54
+ import ctypes
55
+
56
+ kernel32 = ctypes.windll.kernel32
57
+ # Get handle to stdin
58
+ STD_INPUT_HANDLE = -10
59
+ handle = kernel32.GetStdHandle(STD_INPUT_HANDLE)
60
+
61
+ # Enable line input and echo (normal console mode)
62
+ # ENABLE_LINE_INPUT = 0x0002
63
+ # ENABLE_ECHO_INPUT = 0x0004
64
+ # ENABLE_PROCESSED_INPUT = 0x0001
65
+ NORMAL_MODE = 0x0007 # Line input + echo + processed
66
+ kernel32.SetConsoleMode(handle, NORMAL_MODE)
67
+ except Exception:
68
+ pass # Silently ignore errors - this is best-effort
69
+
70
+
71
+ def safe_input(prompt_text: str = "") -> str:
72
+ """Cross-platform safe input that works after prompt_toolkit Applications.
73
+
74
+ On Windows, raw input() can fail after a prompt_toolkit Application exits
75
+ because the terminal can be left in a weird state. This function resets
76
+ the Windows console mode before calling input().
77
+
78
+ Args:
79
+ prompt_text: The prompt to display to the user
80
+
81
+ Returns:
82
+ The user's input string (stripped)
83
+
84
+ Raises:
85
+ KeyboardInterrupt: If user presses Ctrl+C
86
+ EOFError: If user presses Ctrl+D/Ctrl+Z
87
+ """
88
+ # Reset Windows console to normal mode before reading input
89
+ _reset_windows_console()
90
+
91
+ # Use standard input() - now that console is reset, it should work
92
+ result = input(prompt_text)
93
+ return result.strip() if result else ""
@@ -219,8 +219,9 @@ class ManagedMCPServer:
219
219
  stdio_kwargs["env"] = _expand_env_vars(config["env"])
220
220
  if "cwd" in config:
221
221
  stdio_kwargs["cwd"] = _expand_env_vars(config["cwd"])
222
- if "timeout" in config:
223
- stdio_kwargs["timeout"] = config["timeout"]
222
+ # Default timeout of 60s for stdio servers - some servers like Serena take a while to start
223
+ # Users can override this in their config
224
+ stdio_kwargs["timeout"] = config.get("timeout", 60)
224
225
  if "read_timeout" in config:
225
226
  stdio_kwargs["read_timeout"] = config["read_timeout"]
226
227
 
@@ -329,31 +329,19 @@ def emit_divider(content: str = "─" * 100 + "\n", **metadata):
329
329
 
330
330
 
331
331
  def emit_prompt(prompt_text: str, timeout: float = None) -> str:
332
- """Emit a human input request and wait for response."""
333
- # TUI mode has been removed, always use interactive mode input
334
- if True:
335
- # Emit the prompt as a message for display
336
- from code_puppy.messaging import emit_info
332
+ """Emit a human input request and wait for response.
337
333
 
338
- emit_info(prompt_text)
334
+ Uses safe_input for cross-platform compatibility, especially on Windows
335
+ where raw input() can fail after prompt_toolkit Applications.
336
+ """
337
+ from code_puppy.command_line.utils import safe_input
338
+ from code_puppy.messaging import emit_info
339
339
 
340
- # Get input directly
341
- try:
342
- # Try to use rich console for better formatting
343
- from rich.console import Console
344
-
345
- console = Console()
346
- response = console.input("[cyan]>>> [/cyan]")
347
- return response
348
- except Exception:
349
- # Fallback to basic input
350
- response = input(">>> ")
351
- return response
352
-
353
- # In TUI mode, use the queue system
354
- queue = get_global_queue()
355
- prompt_id = queue.create_prompt_request(prompt_text)
356
- return queue.wait_for_prompt_response(prompt_id, timeout)
340
+ emit_info(prompt_text)
341
+
342
+ # Use safe_input which resets Windows console state before reading
343
+ response = safe_input(">>> ")
344
+ return response
357
345
 
358
346
 
359
347
  def provide_prompt_response(prompt_id: str, response: str):
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "code-puppy"
7
- version = "0.0.344"
7
+ version = "0.0.345"
8
8
  description = "Code generation agent"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11,<3.14"
@@ -1,39 +0,0 @@
1
- import os
2
- from typing import List, Tuple
3
-
4
- from rich.table import Table
5
-
6
-
7
- def list_directory(path: str = None) -> Tuple[List[str], List[str]]:
8
- """
9
- Returns (dirs, files) for the specified path, splitting out directories and files.
10
- """
11
- if path is None:
12
- path = os.getcwd()
13
- entries = []
14
- try:
15
- entries = [e for e in os.listdir(path)]
16
- except Exception as e:
17
- raise RuntimeError(f"Error listing directory: {e}")
18
- dirs = [e for e in entries if os.path.isdir(os.path.join(path, e))]
19
- files = [e for e in entries if not os.path.isdir(os.path.join(path, e))]
20
- return dirs, files
21
-
22
-
23
- def make_directory_table(path: str = None) -> Table:
24
- """
25
- Returns a rich.Table object containing the directory listing.
26
- """
27
- if path is None:
28
- path = os.getcwd()
29
- dirs, files = list_directory(path)
30
- table = Table(
31
- title=f"\U0001f4c1 [bold blue]Current directory:[/bold blue] [cyan]{path}[/cyan]"
32
- )
33
- table.add_column("Type", style="dim", width=8)
34
- table.add_column("Name", style="bold")
35
- for d in sorted(dirs):
36
- table.add_row("[green]dir[/green]", f"[cyan]{d}[/cyan]")
37
- for f in sorted(files):
38
- table.add_row("[yellow]file[/yellow]", f"{f}")
39
- return table
File without changes
File without changes
File without changes