newcode 0.1.5__tar.gz → 0.1.7__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 (289) hide show
  1. {newcode-0.1.5 → newcode-0.1.7}/PKG-INFO +1 -1
  2. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/__init__.py +1 -1
  3. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_creator_agent.py +2 -2
  4. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/config.py +1 -3
  5. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/hook_engine/__init__.py +8 -2
  6. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/hook_engine/aliases.py +17 -17
  7. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/hook_engine/engine.py +38 -12
  8. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/hook_engine/executor.py +15 -12
  9. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/hook_engine/matcher.py +15 -4
  10. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/hook_engine/models.py +24 -6
  11. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/hook_engine/registry.py +3 -3
  12. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/hook_engine/validator.py +14 -11
  13. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/managed_server.py +9 -8
  14. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/messaging/rich_renderer.py +1 -1
  15. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/agent_skills/skills_install_menu.py +2 -2
  16. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/agent_skills/skills_menu.py +2 -2
  17. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/claude_code_hooks/config.py +26 -20
  18. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/claude_code_hooks/register_callbacks.py +18 -6
  19. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/hook_creator/register_callbacks.py +4 -4
  20. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/hook_manager/__init__.py +1 -1
  21. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/hook_manager/config.py +27 -14
  22. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/hook_manager/hooks_menu.py +35 -22
  23. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/hook_manager/register_callbacks.py +41 -19
  24. newcode-0.1.7/code_puppy/plugins/oauth_puppy_html.py +70 -0
  25. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/agent_tools.py +64 -4
  26. newcode-0.1.7/code_puppy/tools/ask_user_question/registration.py +87 -0
  27. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/browser/terminal_screenshot_tools.py +6 -2
  28. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/file_modifications.py +117 -6
  29. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/file_operations.py +127 -3
  30. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/skills_tools.py +6 -0
  31. {newcode-0.1.5 → newcode-0.1.7}/pyproject.toml +1 -1
  32. newcode-0.1.5/code_puppy/agents/agent_helios.py +0 -119
  33. newcode-0.1.5/code_puppy/plugins/oauth_puppy_html.py +0 -224
  34. newcode-0.1.5/code_puppy/tools/ask_user_question/registration.py +0 -36
  35. {newcode-0.1.5 → newcode-0.1.7}/.gitignore +0 -0
  36. {newcode-0.1.5 → newcode-0.1.7}/LICENSE +0 -0
  37. {newcode-0.1.5 → newcode-0.1.7}/README.md +0 -0
  38. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/__main__.py +0 -0
  39. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/__init__.py +0 -0
  40. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_c_reviewer.py +0 -0
  41. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_code_puppy.py +0 -0
  42. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_code_reviewer.py +0 -0
  43. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_cpp_reviewer.py +0 -0
  44. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_golang_reviewer.py +0 -0
  45. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_javascript_reviewer.py +0 -0
  46. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_manager.py +0 -0
  47. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_pack_leader.py +0 -0
  48. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_planning.py +0 -0
  49. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_python_programmer.py +0 -0
  50. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_python_reviewer.py +0 -0
  51. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_qa_expert.py +0 -0
  52. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_qa_kitten.py +0 -0
  53. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_scheduler.py +0 -0
  54. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_security_auditor.py +0 -0
  55. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_terminal_qa.py +0 -0
  56. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/agent_typescript_reviewer.py +0 -0
  57. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/base_agent.py +0 -0
  58. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/event_stream_handler.py +0 -0
  59. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/json_agent.py +0 -0
  60. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/pack/__init__.py +0 -0
  61. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/pack/bloodhound.py +0 -0
  62. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/pack/husky.py +0 -0
  63. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/pack/retriever.py +0 -0
  64. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/pack/shepherd.py +0 -0
  65. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/pack/terrier.py +0 -0
  66. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/pack/watchdog.py +0 -0
  67. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/prompt_reviewer.py +0 -0
  68. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/agents/subagent_stream_handler.py +0 -0
  69. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/api/__init__.py +0 -0
  70. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/api/app.py +0 -0
  71. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/api/main.py +0 -0
  72. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/api/pty_manager.py +0 -0
  73. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/api/routers/__init__.py +0 -0
  74. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/api/routers/agents.py +0 -0
  75. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/api/routers/commands.py +0 -0
  76. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/api/routers/config.py +0 -0
  77. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/api/routers/sessions.py +0 -0
  78. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/api/templates/terminal.html +0 -0
  79. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/api/websocket.py +0 -0
  80. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/callbacks.py +0 -0
  81. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/chatgpt_codex_client.py +0 -0
  82. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/claude_cache_client.py +0 -0
  83. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/cli_runner.py +0 -0
  84. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/__init__.py +0 -0
  85. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/add_model_menu.py +0 -0
  86. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/agent_menu.py +0 -0
  87. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/attachments.py +0 -0
  88. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/autosave_menu.py +0 -0
  89. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/clipboard.py +0 -0
  90. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/colors_menu.py +0 -0
  91. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/command_handler.py +0 -0
  92. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/command_registry.py +0 -0
  93. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/config_commands.py +0 -0
  94. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/core_commands.py +0 -0
  95. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/diff_menu.py +0 -0
  96. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/file_path_completion.py +0 -0
  97. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/load_context_completion.py +0 -0
  98. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/__init__.py +0 -0
  99. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/base.py +0 -0
  100. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
  101. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
  102. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
  103. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/edit_command.py +0 -0
  104. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/handler.py +0 -0
  105. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/help_command.py +0 -0
  106. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/install_command.py +0 -0
  107. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/install_menu.py +0 -0
  108. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/list_command.py +0 -0
  109. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/logs_command.py +0 -0
  110. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/remove_command.py +0 -0
  111. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/restart_command.py +0 -0
  112. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/search_command.py +0 -0
  113. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/start_all_command.py +0 -0
  114. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/start_command.py +0 -0
  115. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/status_command.py +0 -0
  116. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
  117. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/stop_command.py +0 -0
  118. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/test_command.py +0 -0
  119. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/utils.py +0 -0
  120. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
  121. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/mcp_completion.py +0 -0
  122. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/model_picker_completion.py +0 -0
  123. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/model_settings_menu.py +0 -0
  124. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/motd.py +0 -0
  125. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/onboarding_slides.py +0 -0
  126. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/onboarding_wizard.py +0 -0
  127. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/pin_command_completion.py +0 -0
  128. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
  129. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/session_commands.py +0 -0
  130. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/skills_completion.py +0 -0
  131. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/uc_menu.py +0 -0
  132. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/utils.py +0 -0
  133. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/command_line/wiggum_state.py +0 -0
  134. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/error_logging.py +0 -0
  135. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/gemini_code_assist.py +0 -0
  136. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/gemini_model.py +0 -0
  137. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/hook_engine/README.md +0 -0
  138. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/http_utils.py +0 -0
  139. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/keymap.py +0 -0
  140. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/main.py +0 -0
  141. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/__init__.py +0 -0
  142. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/async_lifecycle.py +0 -0
  143. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/blocking_startup.py +0 -0
  144. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/captured_stdio_server.py +0 -0
  145. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/circuit_breaker.py +0 -0
  146. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/config_wizard.py +0 -0
  147. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/dashboard.py +0 -0
  148. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/error_isolation.py +0 -0
  149. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/examples/retry_example.py +0 -0
  150. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/health_monitor.py +0 -0
  151. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/manager.py +0 -0
  152. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/mcp_logs.py +0 -0
  153. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/registry.py +0 -0
  154. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/retry_manager.py +0 -0
  155. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/server_registry_catalog.py +0 -0
  156. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/status_tracker.py +0 -0
  157. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_/system_tools.py +0 -0
  158. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_prompts/__init__.py +0 -0
  159. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/mcp_prompts/hook_creator.py +0 -0
  160. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/messaging/__init__.py +0 -0
  161. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/messaging/bus.py +0 -0
  162. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/messaging/commands.py +0 -0
  163. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/messaging/markdown_patches.py +0 -0
  164. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/messaging/message_queue.py +0 -0
  165. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/messaging/messages.py +0 -0
  166. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/messaging/queue_console.py +0 -0
  167. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/messaging/renderers.py +0 -0
  168. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/messaging/spinner/__init__.py +0 -0
  169. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/messaging/spinner/console_spinner.py +0 -0
  170. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/messaging/spinner/spinner_base.py +0 -0
  171. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/messaging/subagent_console.py +0 -0
  172. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/model_factory.py +0 -0
  173. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/model_switching.py +0 -0
  174. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/model_utils.py +0 -0
  175. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/models.json +0 -0
  176. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/models_dev_api.json +0 -0
  177. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/models_dev_parser.py +0 -0
  178. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/__init__.py +0 -0
  179. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/agent_skills/__init__.py +0 -0
  180. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/agent_skills/config.py +0 -0
  181. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/agent_skills/discovery.py +0 -0
  182. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/agent_skills/downloader.py +0 -0
  183. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/agent_skills/installer.py +0 -0
  184. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/agent_skills/metadata.py +0 -0
  185. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/agent_skills/prompt_builder.py +0 -0
  186. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/agent_skills/register_callbacks.py +0 -0
  187. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/agent_skills/remote_catalog.py +0 -0
  188. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/agent_skills/skill_catalog.py +0 -0
  189. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/antigravity_oauth/__init__.py +0 -0
  190. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/antigravity_oauth/accounts.py +0 -0
  191. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/antigravity_oauth/antigravity_model.py +0 -0
  192. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/antigravity_oauth/config.py +0 -0
  193. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/antigravity_oauth/constants.py +0 -0
  194. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/antigravity_oauth/oauth.py +0 -0
  195. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/antigravity_oauth/register_callbacks.py +0 -0
  196. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/antigravity_oauth/storage.py +0 -0
  197. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/antigravity_oauth/test_plugin.py +0 -0
  198. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/antigravity_oauth/token.py +0 -0
  199. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/antigravity_oauth/transport.py +0 -0
  200. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/antigravity_oauth/utils.py +0 -0
  201. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
  202. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
  203. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
  204. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
  205. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
  206. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
  207. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/claude_code_hooks/__init__.py +0 -0
  208. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
  209. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
  210. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
  211. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
  212. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +0 -0
  213. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
  214. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +0 -0
  215. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/claude_code_oauth/utils.py +0 -0
  216. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
  217. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
  218. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/example_custom_command/README.md +0 -0
  219. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
  220. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
  221. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
  222. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/frontend_emitter/__init__.py +0 -0
  223. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/frontend_emitter/emitter.py +0 -0
  224. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/frontend_emitter/register_callbacks.py +0 -0
  225. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/hook_creator/__init__.py +0 -0
  226. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/scheduler/__init__.py +0 -0
  227. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/scheduler/register_callbacks.py +0 -0
  228. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/scheduler/scheduler_menu.py +0 -0
  229. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/scheduler/scheduler_wizard.py +0 -0
  230. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/shell_safety/__init__.py +0 -0
  231. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
  232. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
  233. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
  234. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/synthetic_status/__init__.py +0 -0
  235. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/synthetic_status/register_callbacks.py +0 -0
  236. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/synthetic_status/status_api.py +0 -0
  237. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/universal_constructor/__init__.py +0 -0
  238. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/universal_constructor/models.py +0 -0
  239. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/universal_constructor/register_callbacks.py +0 -0
  240. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/universal_constructor/registry.py +0 -0
  241. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/plugins/universal_constructor/sandbox.py +0 -0
  242. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/prompts/antigravity_system_prompt.md +0 -0
  243. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/pydantic_patches.py +0 -0
  244. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/reopenable_async_client.py +0 -0
  245. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/round_robin_model.py +0 -0
  246. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/scheduler/__init__.py +0 -0
  247. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/scheduler/__main__.py +0 -0
  248. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/scheduler/cli.py +0 -0
  249. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/scheduler/config.py +0 -0
  250. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/scheduler/daemon.py +0 -0
  251. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/scheduler/executor.py +0 -0
  252. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/scheduler/platform.py +0 -0
  253. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/scheduler/platform_unix.py +0 -0
  254. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/scheduler/platform_win.py +0 -0
  255. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/session_storage.py +0 -0
  256. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/status_display.py +0 -0
  257. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/summarization_agent.py +0 -0
  258. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/terminal_utils.py +0 -0
  259. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/__init__.py +0 -0
  260. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/ask_user_question/__init__.py +0 -0
  261. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/ask_user_question/constants.py +0 -0
  262. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/ask_user_question/demo_tui.py +0 -0
  263. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/ask_user_question/handler.py +0 -0
  264. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/ask_user_question/models.py +0 -0
  265. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/ask_user_question/renderers.py +0 -0
  266. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/ask_user_question/terminal_ui.py +0 -0
  267. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/ask_user_question/theme.py +0 -0
  268. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/ask_user_question/tui_loop.py +0 -0
  269. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/browser/__init__.py +0 -0
  270. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/browser/browser_control.py +0 -0
  271. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/browser/browser_interactions.py +0 -0
  272. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/browser/browser_locators.py +0 -0
  273. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/browser/browser_manager.py +0 -0
  274. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/browser/browser_navigation.py +0 -0
  275. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/browser/browser_screenshot.py +0 -0
  276. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/browser/browser_scripts.py +0 -0
  277. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/browser/browser_workflows.py +0 -0
  278. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/browser/chromium_terminal_manager.py +0 -0
  279. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/browser/terminal_command_tools.py +0 -0
  280. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/browser/terminal_tools.py +0 -0
  281. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/command_runner.py +0 -0
  282. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/common.py +0 -0
  283. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/display.py +0 -0
  284. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/scheduler_tools.py +0 -0
  285. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/subagent_context.py +0 -0
  286. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/tools_content.py +0 -0
  287. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/tools/universal_constructor.py +0 -0
  288. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/uvx_detection.py +0 -0
  289. {newcode-0.1.5 → newcode-0.1.7}/code_puppy/version_checker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: newcode
3
- Version: 0.1.5
3
+ Version: 0.1.7
4
4
  Summary: AI-powered code generation agent - a fedstew fork of code-puppy
5
5
  Project-URL: repository, https://github.com/janfeddersen-wq/new_code
6
6
  Project-URL: HomePage, https://github.com/janfeddersen-wq/new_code
@@ -2,7 +2,7 @@ import importlib.metadata
2
2
 
3
3
  # Version detection
4
4
  try:
5
- _detected_version = importlib.metadata.version("code-puppy")
5
+ _detected_version = importlib.metadata.version("newcode")
6
6
  # Ensure we never end up with None or empty string
7
7
  __version__ = _detected_version if _detected_version else "0.0.0-dev"
8
8
  except Exception:
@@ -50,7 +50,7 @@ class AgentCreatorAgent(BaseAgent):
50
50
  uc_tools_section = "\n".join(uc_tools_info)
51
51
  else:
52
52
  uc_tools_section = (
53
- "No custom UC tools created yet. Use Helios to create some!"
53
+ "No custom UC tools created yet."
54
54
  )
55
55
 
56
56
  # Load available models dynamically
@@ -163,7 +163,7 @@ Users can optionally pin a specific model to their agent to override the global
163
163
  - `invoke_agent` - Invoke other agents with specific prompts (recommended for agent managers)
164
164
 
165
165
  ### 🔧 **Universal Constructor Tools** (custom tools):
166
- - These are tools created by Helios or via the Universal Constructor
166
+ - These are tools created via the Universal Constructor
167
167
  - They persist across sessions and can be bound to any agent
168
168
  - Use `universal_constructor(action="list")` to see available custom tools
169
169
  - Bind them by adding their full name to the agent's tools array
@@ -104,7 +104,7 @@ PACK_AGENT_NAMES = frozenset(
104
104
  )
105
105
 
106
106
  # Agents that require Universal Constructor to be enabled
107
- UC_AGENT_NAMES = frozenset(["helios"])
107
+ UC_AGENT_NAMES = frozenset()
108
108
 
109
109
 
110
110
  def get_pack_agents_enabled() -> bool:
@@ -1469,8 +1469,6 @@ DEFAULT_BANNER_COLORS = {
1469
1469
  "universal_constructor": "dark_cyan", # Teal - constructing tools
1470
1470
  # Browser/Terminal tools - same color as edit_file (gold)
1471
1471
  "terminal_tool": "dark_goldenrod", # Gold - browser terminal operations
1472
- # MCP tools - distinct from builtin tools
1473
- "mcp_tool_call": "dark_cyan", # Teal - external MCP tool calls
1474
1472
  }
1475
1473
 
1476
1474
 
@@ -1,8 +1,14 @@
1
1
  """Hook engine package."""
2
2
 
3
- from .engine import HookEngine
4
- from .models import HookConfig, EventData, ExecutionResult, ProcessEventResult, HookRegistry
5
3
  from . import aliases
4
+ from .engine import HookEngine
5
+ from .models import (
6
+ EventData,
7
+ ExecutionResult,
8
+ HookConfig,
9
+ HookRegistry,
10
+ ProcessEventResult,
11
+ )
6
12
 
7
13
  __all__ = [
8
14
  "HookEngine",
@@ -19,30 +19,29 @@ Adding a new provider
19
19
 
20
20
  from typing import Dict, FrozenSet, Optional
21
21
 
22
-
23
22
  # ---------------------------------------------------------------------------
24
23
  # Claude Code (Anthropic)
25
24
  # Source: `claude mcp serve` → tools/list (verified against v2.1.52)
26
25
  # ---------------------------------------------------------------------------
27
26
  CLAUDE_CODE_ALIASES: Dict[str, str] = {
28
27
  # Shell execution
29
- "Bash": "agent_run_shell_command",
28
+ "Bash": "agent_run_shell_command",
30
29
  # File system — read
31
- "Glob": "list_files",
32
- "Read": "read_file",
33
- "Grep": "grep",
30
+ "Glob": "list_files",
31
+ "Read": "read_file",
32
+ "Grep": "grep",
34
33
  # File system — write
35
- "Edit": "edit_file",
36
- "Write": "edit_file", # Write = full overwrite; same internal tool
34
+ "Edit": "edit_file",
35
+ "Write": "edit_file", # Write = full overwrite; same tool in puppy
37
36
  # File system — delete
38
- "Delete": "delete_file",
37
+ "Delete": "delete_file",
39
38
  # User interaction
40
- "AskUserQuestion": "ask_user_question",
39
+ "AskUserQuestion": "ask_user_question",
41
40
  # Agent / task orchestration
42
- "Task": "invoke_agent",
41
+ "Task": "invoke_agent",
43
42
  # Skills
44
- "Skill": "activate_skill",
45
- "ToolSearch": "list_or_search_skills",
43
+ "Skill": "activate_skill",
44
+ "ToolSearch": "list_or_search_skills",
46
45
  # NOTE: the tools below have no direct code_puppy equivalent yet.
47
46
  # They are listed here for documentation and future mapping:
48
47
  # "TaskOutput" -> (no equivalent)
@@ -92,10 +91,10 @@ SWARM_ALIASES: Dict[str, str] = {
92
91
  # To disable a provider's aliases, remove its entry from this dict.
93
92
  # ---------------------------------------------------------------------------
94
93
  PROVIDER_ALIASES: Dict[str, Dict[str, str]] = {
95
- "claude": CLAUDE_CODE_ALIASES,
96
- "gemini": GEMINI_ALIASES, # placeholder — empty until populated
97
- "codex": CODEX_ALIASES, # placeholder — empty until populated
98
- "swarm": SWARM_ALIASES, # placeholder — empty until populated
94
+ "claude": CLAUDE_CODE_ALIASES,
95
+ "gemini": GEMINI_ALIASES, # placeholder — empty until populated
96
+ "codex": CODEX_ALIASES, # placeholder — empty until populated
97
+ "swarm": SWARM_ALIASES, # placeholder — empty until populated
99
98
  }
100
99
 
101
100
 
@@ -103,6 +102,7 @@ PROVIDER_ALIASES: Dict[str, Dict[str, str]] = {
103
102
  # Flattened lookup structures — built once at import time for O(1) access.
104
103
  # ---------------------------------------------------------------------------
105
104
 
105
+
106
106
  def _build_lookup() -> Dict[str, FrozenSet[str]]:
107
107
  """
108
108
  Return a dict mapping every known name (provider *and* internal) to the
@@ -152,4 +152,4 @@ def resolve_internal_name(provider_tool_name: str) -> Optional[str]:
152
152
  for pname, internal in provider_aliases.items():
153
153
  if pname.lower() == provider_tool_name.lower():
154
154
  return internal
155
- return None
155
+ return None
@@ -6,17 +6,20 @@ import logging
6
6
  import time
7
7
  from typing import Any, Dict, List, Optional
8
8
 
9
+ from .executor import execute_hooks_sequential, get_blocking_result
10
+ from .matcher import matches
9
11
  from .models import (
10
12
  EventData,
11
- ExecutionResult,
12
13
  HookConfig,
13
14
  HookRegistry,
14
15
  ProcessEventResult,
15
16
  )
16
- from .matcher import matches
17
- from .executor import execute_hook, execute_hooks_sequential, get_blocking_result
18
17
  from .registry import build_registry_from_config, get_registry_stats
19
- from .validator import validate_hooks_config, format_validation_report, get_config_suggestions
18
+ from .validator import (
19
+ format_validation_report,
20
+ get_config_suggestions,
21
+ validate_hooks_config,
22
+ )
20
23
 
21
24
  logger = logging.getLogger(__name__)
22
25
 
@@ -61,7 +64,9 @@ class HookEngine:
61
64
 
62
65
  try:
63
66
  self._registry = build_registry_from_config(config)
64
- logger.info(f"Loaded hook configuration: {self._registry.count_hooks()} total hooks")
67
+ logger.info(
68
+ f"Loaded hook configuration: {self._registry.count_hooks()} total hooks"
69
+ )
65
70
  except Exception as e:
66
71
  if self.strict_validation:
67
72
  raise ValueError(f"Failed to build hook registry: {e}") from e
@@ -83,21 +88,37 @@ class HookEngine:
83
88
  start_time = time.perf_counter()
84
89
 
85
90
  if not self._registry:
86
- return ProcessEventResult(blocked=False, executed_hooks=0, results=[], total_duration_ms=0.0)
91
+ return ProcessEventResult(
92
+ blocked=False, executed_hooks=0, results=[], total_duration_ms=0.0
93
+ )
87
94
 
88
95
  all_hooks = self._registry.get_hooks_for_event(event_type)
89
96
 
90
97
  if not all_hooks:
91
98
  duration_ms = (time.perf_counter() - start_time) * 1000
92
- return ProcessEventResult(blocked=False, executed_hooks=0, results=[], total_duration_ms=duration_ms)
99
+ return ProcessEventResult(
100
+ blocked=False,
101
+ executed_hooks=0,
102
+ results=[],
103
+ total_duration_ms=duration_ms,
104
+ )
93
105
 
94
- matching_hooks = self._filter_hooks_by_matcher(all_hooks, event_data.tool_name, event_data.tool_args)
106
+ matching_hooks = self._filter_hooks_by_matcher(
107
+ all_hooks, event_data.tool_name, event_data.tool_args
108
+ )
95
109
 
96
110
  if not matching_hooks:
97
111
  duration_ms = (time.perf_counter() - start_time) * 1000
98
- return ProcessEventResult(blocked=False, executed_hooks=0, results=[], total_duration_ms=duration_ms)
112
+ return ProcessEventResult(
113
+ blocked=False,
114
+ executed_hooks=0,
115
+ results=[],
116
+ total_duration_ms=duration_ms,
117
+ )
99
118
 
100
- logger.debug(f"Processing {event_type}: {len(matching_hooks)} matching hook(s) for tool '{event_data.tool_name}'")
119
+ logger.debug(
120
+ f"Processing {event_type}: {len(matching_hooks)} matching hook(s) for tool '{event_data.tool_name}'"
121
+ )
101
122
 
102
123
  if sequential:
103
124
  results = await execute_hooks_sequential(
@@ -105,7 +126,10 @@ class HookEngine:
105
126
  )
106
127
  else:
107
128
  from .executor import execute_hooks_parallel
108
- results = await execute_hooks_parallel(matching_hooks, event_data, self.env_vars)
129
+
130
+ results = await execute_hooks_parallel(
131
+ matching_hooks, event_data, self.env_vars
132
+ )
109
133
 
110
134
  for hook, result in zip(matching_hooks, results):
111
135
  if hook.once and result.success:
@@ -142,7 +166,9 @@ class HookEngine:
142
166
  if matches(hook.matcher, tool_name, tool_args):
143
167
  matching_hooks.append(hook)
144
168
  except Exception as e:
145
- logger.error(f"Error matching hook '{hook.matcher}': {e}", exc_info=True)
169
+ logger.error(
170
+ f"Error matching hook '{hook.matcher}': {e}", exc_info=True
171
+ )
146
172
  return matching_hooks
147
173
 
148
174
  def get_stats(self) -> Dict[str, Any]:
@@ -20,8 +20,8 @@ import re
20
20
  import time
21
21
  from typing import Any, Dict, List, Optional
22
22
 
23
- from .models import HookConfig, EventData, ExecutionResult
24
23
  from .matcher import _extract_file_path
24
+ from .models import EventData, ExecutionResult, HookConfig
25
25
 
26
26
  logger = logging.getLogger(__name__)
27
27
 
@@ -40,6 +40,7 @@ def _build_stdin_payload(event_data: EventData) -> bytes:
40
40
  "permission_mode": "default"
41
41
  }
42
42
  """
43
+
43
44
  def _make_serializable(obj: Any) -> Any:
44
45
  if isinstance(obj, dict):
45
46
  return {k: _make_serializable(v) for k, v in obj.items()}
@@ -192,7 +193,7 @@ def _substitute_variables(
192
193
  result = command
193
194
  for var, value in substitutions.items():
194
195
  result = result.replace(f"${{{var}}}", str(value))
195
- result = re.sub(rf'\${re.escape(var)}(?=\W|$)', str(value), result)
196
+ result = re.sub(rf"\${re.escape(var)}(?=\W|$)", str(value), result)
196
197
  return result
197
198
 
198
199
 
@@ -228,16 +229,18 @@ async def execute_hooks_parallel(
228
229
  final_results = []
229
230
  for i, result in enumerate(results):
230
231
  if isinstance(result, Exception):
231
- final_results.append(ExecutionResult(
232
- blocked=False,
233
- hook_command=hooks[i].command,
234
- stdout="",
235
- stderr=str(result),
236
- exit_code=-1,
237
- duration_ms=0.0,
238
- error=f"Hook execution failed: {result}",
239
- hook_id=hooks[i].id,
240
- ))
232
+ final_results.append(
233
+ ExecutionResult(
234
+ blocked=False,
235
+ hook_command=hooks[i].command,
236
+ stdout="",
237
+ stderr=str(result),
238
+ exit_code=-1,
239
+ duration_ms=0.0,
240
+ error=f"Hook execution failed: {result}",
241
+ hook_id=hooks[i].id,
242
+ )
243
+ )
241
244
  else:
242
245
  final_results.append(result)
243
246
  return final_results
@@ -79,14 +79,25 @@ def _match_single(pattern: str, tool_name: str, tool_args: Dict[str, Any]) -> bo
79
79
 
80
80
 
81
81
  def _extract_file_path(tool_args: Dict[str, Any]) -> Optional[str]:
82
- file_keys = ["file_path", "file", "path", "target", "input_file",
83
- "output_file", "source", "destination", "src", "dest", "filename"]
82
+ file_keys = [
83
+ "file_path",
84
+ "file",
85
+ "path",
86
+ "target",
87
+ "input_file",
88
+ "output_file",
89
+ "source",
90
+ "destination",
91
+ "src",
92
+ "dest",
93
+ "filename",
94
+ ]
84
95
  for key in file_keys:
85
96
  if key in tool_args:
86
97
  value = tool_args[key]
87
98
  if isinstance(value, str):
88
99
  return value
89
- if hasattr(value, '__fspath__'):
100
+ if hasattr(value, "__fspath__"):
90
101
  return str(value)
91
102
  for value in tool_args.values():
92
103
  if isinstance(value, str) and _looks_like_file_path(value):
@@ -107,7 +118,7 @@ def _looks_like_file_path(value: str) -> bool:
107
118
 
108
119
 
109
120
  def _is_regex_pattern(pattern: str) -> bool:
110
- regex_chars = ['^', '$', '.', '+', '?', '[', ']', '(', ')', '{', '}', '|', '\\']
121
+ regex_chars = ["^", "$", ".", "+", "?", "[", "]", "(", ")", "{", "}", "|", "\\"]
111
122
  return any(char in pattern for char in regex_chars)
112
123
 
113
124
 
@@ -23,6 +23,7 @@ class HookConfig:
23
23
  enabled: Whether this hook is enabled (default: True)
24
24
  id: Optional unique identifier for this hook
25
25
  """
26
+
26
27
  matcher: str
27
28
  type: Literal["command", "prompt"]
28
29
  command: str
@@ -37,7 +38,9 @@ class HookConfig:
37
38
  raise ValueError("Hook matcher cannot be empty")
38
39
 
39
40
  if self.type not in ("command", "prompt"):
40
- raise ValueError(f"Hook type must be 'command' or 'prompt', got: {self.type}")
41
+ raise ValueError(
42
+ f"Hook type must be 'command' or 'prompt', got: {self.type}"
43
+ )
41
44
 
42
45
  if not self.command:
43
46
  raise ValueError("Hook command cannot be empty")
@@ -47,6 +50,7 @@ class HookConfig:
47
50
 
48
51
  if self.id is None:
49
52
  import hashlib
53
+
50
54
  content = f"{self.matcher}:{self.type}:{self.command}"
51
55
  self.id = hashlib.sha256(content.encode()).hexdigest()[:12]
52
56
 
@@ -62,6 +66,7 @@ class EventData:
62
66
  tool_args: Arguments passed to the tool
63
67
  context: Optional context metadata (result, duration, etc.)
64
68
  """
69
+
65
70
  event_type: str
66
71
  tool_name: str
67
72
  tool_args: Dict[str, Any] = field(default_factory=dict)
@@ -89,6 +94,7 @@ class ExecutionResult:
89
94
  error: Error message if execution failed
90
95
  hook_id: ID of the hook that was executed
91
96
  """
97
+
92
98
  blocked: bool
93
99
  hook_command: str
94
100
  stdout: str = ""
@@ -117,6 +123,7 @@ class ExecutionResult:
117
123
  @dataclass
118
124
  class HookGroup:
119
125
  """A group of hooks that share the same matcher."""
126
+
120
127
  matcher: str
121
128
  hooks: List[HookConfig] = field(default_factory=list)
122
129
 
@@ -128,6 +135,7 @@ class HookGroup:
128
135
  @dataclass
129
136
  class HookRegistry:
130
137
  """Registry of all hooks organized by event type."""
138
+
131
139
  pre_tool_use: List[HookConfig] = field(default_factory=list)
132
140
  post_tool_use: List[HookConfig] = field(default_factory=list)
133
141
  session_start: List[HookConfig] = field(default_factory=list)
@@ -163,8 +171,9 @@ class HookRegistry:
163
171
  @staticmethod
164
172
  def _normalize_event_type(event_type: str) -> str:
165
173
  import re
166
- s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', event_type)
167
- return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
174
+
175
+ s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", event_type)
176
+ return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower()
168
177
 
169
178
  def add_hook(self, event_type: str, hook: HookConfig) -> None:
170
179
  attr_name = self._normalize_event_type(event_type)
@@ -186,9 +195,17 @@ class HookRegistry:
186
195
  def count_hooks(self, event_type: Optional[str] = None) -> int:
187
196
  if event_type is None:
188
197
  total = 0
189
- for attr in ['pre_tool_use', 'post_tool_use', 'session_start',
190
- 'session_end', 'pre_compact', 'user_prompt_submit', 'notification',
191
- 'stop', 'subagent_stop']:
198
+ for attr in [
199
+ "pre_tool_use",
200
+ "post_tool_use",
201
+ "session_start",
202
+ "session_end",
203
+ "pre_compact",
204
+ "user_prompt_submit",
205
+ "notification",
206
+ "stop",
207
+ "subagent_stop",
208
+ ]:
192
209
  total += len(getattr(self, attr))
193
210
  return total
194
211
  attr_name = self._normalize_event_type(event_type)
@@ -200,6 +217,7 @@ class HookRegistry:
200
217
  @dataclass
201
218
  class ProcessEventResult:
202
219
  """Result from processing an event through the hook engine."""
220
+
203
221
  blocked: bool
204
222
  executed_hooks: int
205
223
  results: List[ExecutionResult]
@@ -6,7 +6,7 @@ Builds and manages the HookRegistry from configuration dictionaries.
6
6
 
7
7
  import logging
8
8
  import re
9
- from typing import Any, Dict, List, Optional
9
+ from typing import Any, Dict
10
10
 
11
11
  from .models import HookConfig, HookRegistry
12
12
 
@@ -86,8 +86,8 @@ def get_registry_stats(registry: HookRegistry) -> Dict[str, Any]:
86
86
  }
87
87
 
88
88
  def _to_attr(event_type: str) -> str:
89
- s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', event_type)
90
- return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
89
+ s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", event_type)
90
+ return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower()
91
91
 
92
92
  for event_type in SUPPORTED_EVENT_TYPES:
93
93
  attr = _to_attr(event_type)
@@ -53,7 +53,9 @@ def validate_hooks_config(config: Dict[str, Any]) -> Tuple[bool, List[str]]:
53
53
 
54
54
  for i, group in enumerate(hook_groups):
55
55
  if not isinstance(group, dict):
56
- errors.append(f"'{event_type}[{i}]' must be a dict with 'matcher' and 'hooks'")
56
+ errors.append(
57
+ f"'{event_type}[{i}]' must be a dict with 'matcher' and 'hooks'"
58
+ )
57
59
  continue
58
60
 
59
61
  if "matcher" not in group:
@@ -74,8 +76,9 @@ def validate_hooks_config(config: Dict[str, Any]) -> Tuple[bool, List[str]]:
74
76
  return len(errors) == 0, errors
75
77
 
76
78
 
77
- def _validate_hook(event_type: str, group_idx: int, hook_idx: int,
78
- hook: Any) -> List[str]:
79
+ def _validate_hook(
80
+ event_type: str, group_idx: int, hook_idx: int, hook: Any
81
+ ) -> List[str]:
79
82
  errors: List[str] = []
80
83
  prefix = f"'{event_type}[{group_idx}].hooks[{hook_idx}]'"
81
84
 
@@ -86,7 +89,9 @@ def _validate_hook(event_type: str, group_idx: int, hook_idx: int,
86
89
  if not hook_type:
87
90
  errors.append(f"{prefix} missing required field 'type'")
88
91
  elif hook_type not in VALID_HOOK_TYPES:
89
- errors.append(f"{prefix} invalid type '{hook_type}'. Must be one of: {', '.join(VALID_HOOK_TYPES)}")
92
+ errors.append(
93
+ f"{prefix} invalid type '{hook_type}'. Must be one of: {', '.join(VALID_HOOK_TYPES)}"
94
+ )
90
95
 
91
96
  if hook_type == "command" and not hook.get("command"):
92
97
  errors.append(f"{prefix} missing required field 'command' for type 'command'")
@@ -103,8 +108,9 @@ def _validate_hook(event_type: str, group_idx: int, hook_idx: int,
103
108
  return errors
104
109
 
105
110
 
106
- def format_validation_report(is_valid: bool, errors: List[str],
107
- suggestions: Optional[List[str]] = None) -> str:
111
+ def format_validation_report(
112
+ is_valid: bool, errors: List[str], suggestions: Optional[List[str]] = None
113
+ ) -> str:
108
114
  lines = []
109
115
  if is_valid:
110
116
  lines.append("✓ Configuration is valid")
@@ -121,15 +127,12 @@ def format_validation_report(is_valid: bool, errors: List[str],
121
127
  return "\n".join(lines)
122
128
 
123
129
 
124
- def get_config_suggestions(config: Dict[str, Any],
125
- errors: List[str]) -> List[str]:
130
+ def get_config_suggestions(config: Dict[str, Any], errors: List[str]) -> List[str]:
126
131
  suggestions: List[str] = []
127
132
 
128
133
  for error in errors:
129
134
  if "Unknown event type" in error:
130
- suggestions.append(
131
- "Valid event types are: " + ", ".join(VALID_EVENT_TYPES)
132
- )
135
+ suggestions.append("Valid event types are: " + ", ".join(VALID_EVENT_TYPES))
133
136
  break
134
137
 
135
138
  if any("missing required field 'command'" in e for e in errors):
@@ -5,6 +5,7 @@ This module provides a managed wrapper around pydantic-ai MCP server classes
5
5
  that adds management capabilities while maintaining 100% compatibility.
6
6
  """
7
7
 
8
+ import json
8
9
  import os
9
10
  import uuid
10
11
  from dataclasses import dataclass, field
@@ -24,6 +25,7 @@ from pydantic_ai.mcp import (
24
25
 
25
26
  from code_puppy.http_utils import create_async_client
26
27
  from code_puppy.mcp_.blocking_startup import BlockingMCPServerStdio
28
+ from code_puppy.messaging import emit_info
27
29
 
28
30
 
29
31
  def _expand_env_vars(value: Any) -> Any:
@@ -80,14 +82,13 @@ async def process_tool_call(
80
82
  tool_args: dict[str, Any],
81
83
  ) -> ToolResult:
82
84
  """A tool call processor that passes along the deps."""
83
- from rich.console import Console
84
-
85
- from code_puppy.config import get_banner_color
86
-
87
- console = Console()
88
- color = get_banner_color("mcp_tool_call")
89
- banner = f"[{color}]───[/{color}] [bold]MCP TOOL CALL[/bold] [{color}]───[/{color}]"
90
- console.print(f"\n{banner} [bold cyan]{name}[/bold cyan]")
85
+ group_id = uuid.uuid4()
86
+ emit_info(
87
+ f"\nMCP Tool Call - {name}",
88
+ message_group=group_id,
89
+ )
90
+ emit_info("\nArgs:", message_group=group_id)
91
+ emit_info(json.dumps(tool_args, indent=2), message_group=group_id)
91
92
  return await call_tool(name, tool_args, {"deps": ctx.deps})
92
93
 
93
94
 
@@ -480,7 +480,7 @@ class RichConsoleRenderer:
480
480
  count += get_recursive_file_count(sub)
481
481
  return count
482
482
 
483
- indent = " " * depth
483
+ indent = " " * (depth + 1)
484
484
 
485
485
  # For root level, just show contents
486
486
  if dir_path == root_key:
@@ -586,8 +586,8 @@ class SkillsInstallMenu:
586
586
  import termios
587
587
 
588
588
  termios.tcflush(sys.stdin.fileno(), termios.TCIFLUSH)
589
- except (ImportError, termios.error, OSError):
590
- pass # Windows or not a tty
589
+ except Exception:
590
+ pass # ImportError on Windows, termios.error, or not a tty
591
591
 
592
592
  # Small delay to let terminal settle before any output
593
593
  time.sleep(0.1)
@@ -468,8 +468,8 @@ class SkillsMenu:
468
468
  import termios
469
469
 
470
470
  termios.tcflush(sys.stdin.fileno(), termios.TCIFLUSH)
471
- except (ImportError, termios.error, OSError):
472
- pass # Windows or not a tty
471
+ except Exception:
472
+ pass # ImportError on Windows, termios.error, or not a tty
473
473
 
474
474
  # Small delay to let terminal settle before any output
475
475
  time.sleep(0.1)