code-puppy 0.0.169__py3-none-any.whl → 0.0.366__py3-none-any.whl

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 (243) hide show
  1. code_puppy/__init__.py +7 -1
  2. code_puppy/agents/__init__.py +8 -8
  3. code_puppy/agents/agent_c_reviewer.py +155 -0
  4. code_puppy/agents/agent_code_puppy.py +9 -2
  5. code_puppy/agents/agent_code_reviewer.py +90 -0
  6. code_puppy/agents/agent_cpp_reviewer.py +132 -0
  7. code_puppy/agents/agent_creator_agent.py +48 -9
  8. code_puppy/agents/agent_golang_reviewer.py +151 -0
  9. code_puppy/agents/agent_javascript_reviewer.py +160 -0
  10. code_puppy/agents/agent_manager.py +146 -199
  11. code_puppy/agents/agent_pack_leader.py +383 -0
  12. code_puppy/agents/agent_planning.py +163 -0
  13. code_puppy/agents/agent_python_programmer.py +165 -0
  14. code_puppy/agents/agent_python_reviewer.py +90 -0
  15. code_puppy/agents/agent_qa_expert.py +163 -0
  16. code_puppy/agents/agent_qa_kitten.py +208 -0
  17. code_puppy/agents/agent_security_auditor.py +181 -0
  18. code_puppy/agents/agent_terminal_qa.py +323 -0
  19. code_puppy/agents/agent_typescript_reviewer.py +166 -0
  20. code_puppy/agents/base_agent.py +1713 -1
  21. code_puppy/agents/event_stream_handler.py +350 -0
  22. code_puppy/agents/json_agent.py +12 -1
  23. code_puppy/agents/pack/__init__.py +34 -0
  24. code_puppy/agents/pack/bloodhound.py +304 -0
  25. code_puppy/agents/pack/husky.py +321 -0
  26. code_puppy/agents/pack/retriever.py +393 -0
  27. code_puppy/agents/pack/shepherd.py +348 -0
  28. code_puppy/agents/pack/terrier.py +287 -0
  29. code_puppy/agents/pack/watchdog.py +367 -0
  30. code_puppy/agents/prompt_reviewer.py +145 -0
  31. code_puppy/agents/subagent_stream_handler.py +276 -0
  32. code_puppy/api/__init__.py +13 -0
  33. code_puppy/api/app.py +169 -0
  34. code_puppy/api/main.py +21 -0
  35. code_puppy/api/pty_manager.py +446 -0
  36. code_puppy/api/routers/__init__.py +12 -0
  37. code_puppy/api/routers/agents.py +36 -0
  38. code_puppy/api/routers/commands.py +217 -0
  39. code_puppy/api/routers/config.py +74 -0
  40. code_puppy/api/routers/sessions.py +232 -0
  41. code_puppy/api/templates/terminal.html +361 -0
  42. code_puppy/api/websocket.py +154 -0
  43. code_puppy/callbacks.py +174 -4
  44. code_puppy/chatgpt_codex_client.py +283 -0
  45. code_puppy/claude_cache_client.py +586 -0
  46. code_puppy/cli_runner.py +916 -0
  47. code_puppy/command_line/add_model_menu.py +1079 -0
  48. code_puppy/command_line/agent_menu.py +395 -0
  49. code_puppy/command_line/attachments.py +395 -0
  50. code_puppy/command_line/autosave_menu.py +605 -0
  51. code_puppy/command_line/clipboard.py +527 -0
  52. code_puppy/command_line/colors_menu.py +520 -0
  53. code_puppy/command_line/command_handler.py +233 -627
  54. code_puppy/command_line/command_registry.py +150 -0
  55. code_puppy/command_line/config_commands.py +715 -0
  56. code_puppy/command_line/core_commands.py +792 -0
  57. code_puppy/command_line/diff_menu.py +863 -0
  58. code_puppy/command_line/load_context_completion.py +15 -22
  59. code_puppy/command_line/mcp/base.py +1 -4
  60. code_puppy/command_line/mcp/catalog_server_installer.py +175 -0
  61. code_puppy/command_line/mcp/custom_server_form.py +688 -0
  62. code_puppy/command_line/mcp/custom_server_installer.py +195 -0
  63. code_puppy/command_line/mcp/edit_command.py +148 -0
  64. code_puppy/command_line/mcp/handler.py +9 -4
  65. code_puppy/command_line/mcp/help_command.py +6 -5
  66. code_puppy/command_line/mcp/install_command.py +16 -27
  67. code_puppy/command_line/mcp/install_menu.py +685 -0
  68. code_puppy/command_line/mcp/list_command.py +3 -3
  69. code_puppy/command_line/mcp/logs_command.py +174 -65
  70. code_puppy/command_line/mcp/remove_command.py +2 -2
  71. code_puppy/command_line/mcp/restart_command.py +12 -4
  72. code_puppy/command_line/mcp/search_command.py +17 -11
  73. code_puppy/command_line/mcp/start_all_command.py +22 -13
  74. code_puppy/command_line/mcp/start_command.py +50 -31
  75. code_puppy/command_line/mcp/status_command.py +6 -7
  76. code_puppy/command_line/mcp/stop_all_command.py +11 -8
  77. code_puppy/command_line/mcp/stop_command.py +11 -10
  78. code_puppy/command_line/mcp/test_command.py +2 -2
  79. code_puppy/command_line/mcp/utils.py +1 -1
  80. code_puppy/command_line/mcp/wizard_utils.py +22 -18
  81. code_puppy/command_line/mcp_completion.py +174 -0
  82. code_puppy/command_line/model_picker_completion.py +89 -30
  83. code_puppy/command_line/model_settings_menu.py +884 -0
  84. code_puppy/command_line/motd.py +14 -8
  85. code_puppy/command_line/onboarding_slides.py +179 -0
  86. code_puppy/command_line/onboarding_wizard.py +340 -0
  87. code_puppy/command_line/pin_command_completion.py +329 -0
  88. code_puppy/command_line/prompt_toolkit_completion.py +626 -75
  89. code_puppy/command_line/session_commands.py +296 -0
  90. code_puppy/command_line/utils.py +54 -0
  91. code_puppy/config.py +1181 -51
  92. code_puppy/error_logging.py +118 -0
  93. code_puppy/gemini_code_assist.py +385 -0
  94. code_puppy/gemini_model.py +602 -0
  95. code_puppy/http_utils.py +220 -104
  96. code_puppy/keymap.py +128 -0
  97. code_puppy/main.py +5 -594
  98. code_puppy/{mcp → mcp_}/__init__.py +17 -0
  99. code_puppy/{mcp → mcp_}/async_lifecycle.py +35 -4
  100. code_puppy/{mcp → mcp_}/blocking_startup.py +70 -43
  101. code_puppy/{mcp → mcp_}/captured_stdio_server.py +2 -2
  102. code_puppy/{mcp → mcp_}/config_wizard.py +5 -5
  103. code_puppy/{mcp → mcp_}/dashboard.py +15 -6
  104. code_puppy/{mcp → mcp_}/examples/retry_example.py +4 -1
  105. code_puppy/{mcp → mcp_}/managed_server.py +66 -39
  106. code_puppy/{mcp → mcp_}/manager.py +146 -52
  107. code_puppy/mcp_/mcp_logs.py +224 -0
  108. code_puppy/{mcp → mcp_}/registry.py +6 -6
  109. code_puppy/{mcp → mcp_}/server_registry_catalog.py +25 -8
  110. code_puppy/messaging/__init__.py +199 -2
  111. code_puppy/messaging/bus.py +610 -0
  112. code_puppy/messaging/commands.py +167 -0
  113. code_puppy/messaging/markdown_patches.py +57 -0
  114. code_puppy/messaging/message_queue.py +17 -48
  115. code_puppy/messaging/messages.py +500 -0
  116. code_puppy/messaging/queue_console.py +1 -24
  117. code_puppy/messaging/renderers.py +43 -146
  118. code_puppy/messaging/rich_renderer.py +1027 -0
  119. code_puppy/messaging/spinner/__init__.py +33 -5
  120. code_puppy/messaging/spinner/console_spinner.py +92 -52
  121. code_puppy/messaging/spinner/spinner_base.py +29 -0
  122. code_puppy/messaging/subagent_console.py +461 -0
  123. code_puppy/model_factory.py +686 -80
  124. code_puppy/model_utils.py +167 -0
  125. code_puppy/models.json +86 -104
  126. code_puppy/models_dev_api.json +1 -0
  127. code_puppy/models_dev_parser.py +592 -0
  128. code_puppy/plugins/__init__.py +164 -10
  129. code_puppy/plugins/antigravity_oauth/__init__.py +10 -0
  130. code_puppy/plugins/antigravity_oauth/accounts.py +406 -0
  131. code_puppy/plugins/antigravity_oauth/antigravity_model.py +704 -0
  132. code_puppy/plugins/antigravity_oauth/config.py +42 -0
  133. code_puppy/plugins/antigravity_oauth/constants.py +136 -0
  134. code_puppy/plugins/antigravity_oauth/oauth.py +478 -0
  135. code_puppy/plugins/antigravity_oauth/register_callbacks.py +406 -0
  136. code_puppy/plugins/antigravity_oauth/storage.py +271 -0
  137. code_puppy/plugins/antigravity_oauth/test_plugin.py +319 -0
  138. code_puppy/plugins/antigravity_oauth/token.py +167 -0
  139. code_puppy/plugins/antigravity_oauth/transport.py +767 -0
  140. code_puppy/plugins/antigravity_oauth/utils.py +169 -0
  141. code_puppy/plugins/chatgpt_oauth/__init__.py +8 -0
  142. code_puppy/plugins/chatgpt_oauth/config.py +52 -0
  143. code_puppy/plugins/chatgpt_oauth/oauth_flow.py +328 -0
  144. code_puppy/plugins/chatgpt_oauth/register_callbacks.py +94 -0
  145. code_puppy/plugins/chatgpt_oauth/test_plugin.py +293 -0
  146. code_puppy/plugins/chatgpt_oauth/utils.py +489 -0
  147. code_puppy/plugins/claude_code_oauth/README.md +167 -0
  148. code_puppy/plugins/claude_code_oauth/SETUP.md +93 -0
  149. code_puppy/plugins/claude_code_oauth/__init__.py +6 -0
  150. code_puppy/plugins/claude_code_oauth/config.py +50 -0
  151. code_puppy/plugins/claude_code_oauth/register_callbacks.py +308 -0
  152. code_puppy/plugins/claude_code_oauth/test_plugin.py +283 -0
  153. code_puppy/plugins/claude_code_oauth/utils.py +518 -0
  154. code_puppy/plugins/customizable_commands/__init__.py +0 -0
  155. code_puppy/plugins/customizable_commands/register_callbacks.py +169 -0
  156. code_puppy/plugins/example_custom_command/README.md +280 -0
  157. code_puppy/plugins/example_custom_command/register_callbacks.py +51 -0
  158. code_puppy/plugins/file_permission_handler/__init__.py +4 -0
  159. code_puppy/plugins/file_permission_handler/register_callbacks.py +523 -0
  160. code_puppy/plugins/frontend_emitter/__init__.py +25 -0
  161. code_puppy/plugins/frontend_emitter/emitter.py +121 -0
  162. code_puppy/plugins/frontend_emitter/register_callbacks.py +261 -0
  163. code_puppy/plugins/oauth_puppy_html.py +228 -0
  164. code_puppy/plugins/shell_safety/__init__.py +6 -0
  165. code_puppy/plugins/shell_safety/agent_shell_safety.py +69 -0
  166. code_puppy/plugins/shell_safety/command_cache.py +156 -0
  167. code_puppy/plugins/shell_safety/register_callbacks.py +202 -0
  168. code_puppy/prompts/antigravity_system_prompt.md +1 -0
  169. code_puppy/prompts/codex_system_prompt.md +310 -0
  170. code_puppy/pydantic_patches.py +131 -0
  171. code_puppy/reopenable_async_client.py +8 -8
  172. code_puppy/round_robin_model.py +10 -15
  173. code_puppy/session_storage.py +294 -0
  174. code_puppy/status_display.py +21 -4
  175. code_puppy/summarization_agent.py +52 -14
  176. code_puppy/terminal_utils.py +418 -0
  177. code_puppy/tools/__init__.py +139 -6
  178. code_puppy/tools/agent_tools.py +548 -49
  179. code_puppy/tools/browser/__init__.py +37 -0
  180. code_puppy/tools/browser/browser_control.py +289 -0
  181. code_puppy/tools/browser/browser_interactions.py +545 -0
  182. code_puppy/tools/browser/browser_locators.py +640 -0
  183. code_puppy/tools/browser/browser_manager.py +316 -0
  184. code_puppy/tools/browser/browser_navigation.py +251 -0
  185. code_puppy/tools/browser/browser_screenshot.py +179 -0
  186. code_puppy/tools/browser/browser_scripts.py +462 -0
  187. code_puppy/tools/browser/browser_workflows.py +221 -0
  188. code_puppy/tools/browser/chromium_terminal_manager.py +259 -0
  189. code_puppy/tools/browser/terminal_command_tools.py +521 -0
  190. code_puppy/tools/browser/terminal_screenshot_tools.py +556 -0
  191. code_puppy/tools/browser/terminal_tools.py +525 -0
  192. code_puppy/tools/command_runner.py +941 -153
  193. code_puppy/tools/common.py +1146 -6
  194. code_puppy/tools/display.py +84 -0
  195. code_puppy/tools/file_modifications.py +288 -89
  196. code_puppy/tools/file_operations.py +352 -266
  197. code_puppy/tools/subagent_context.py +158 -0
  198. code_puppy/uvx_detection.py +242 -0
  199. code_puppy/version_checker.py +30 -11
  200. code_puppy-0.0.366.data/data/code_puppy/models.json +110 -0
  201. code_puppy-0.0.366.data/data/code_puppy/models_dev_api.json +1 -0
  202. {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/METADATA +184 -67
  203. code_puppy-0.0.366.dist-info/RECORD +217 -0
  204. {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/WHEEL +1 -1
  205. {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/entry_points.txt +1 -0
  206. code_puppy/agent.py +0 -231
  207. code_puppy/agents/agent_orchestrator.json +0 -26
  208. code_puppy/agents/runtime_manager.py +0 -272
  209. code_puppy/command_line/mcp/add_command.py +0 -183
  210. code_puppy/command_line/meta_command_handler.py +0 -153
  211. code_puppy/message_history_processor.py +0 -490
  212. code_puppy/messaging/spinner/textual_spinner.py +0 -101
  213. code_puppy/state_management.py +0 -200
  214. code_puppy/tui/__init__.py +0 -10
  215. code_puppy/tui/app.py +0 -986
  216. code_puppy/tui/components/__init__.py +0 -21
  217. code_puppy/tui/components/chat_view.py +0 -550
  218. code_puppy/tui/components/command_history_modal.py +0 -218
  219. code_puppy/tui/components/copy_button.py +0 -139
  220. code_puppy/tui/components/custom_widgets.py +0 -63
  221. code_puppy/tui/components/human_input_modal.py +0 -175
  222. code_puppy/tui/components/input_area.py +0 -167
  223. code_puppy/tui/components/sidebar.py +0 -309
  224. code_puppy/tui/components/status_bar.py +0 -182
  225. code_puppy/tui/messages.py +0 -27
  226. code_puppy/tui/models/__init__.py +0 -8
  227. code_puppy/tui/models/chat_message.py +0 -25
  228. code_puppy/tui/models/command_history.py +0 -89
  229. code_puppy/tui/models/enums.py +0 -24
  230. code_puppy/tui/screens/__init__.py +0 -15
  231. code_puppy/tui/screens/help.py +0 -130
  232. code_puppy/tui/screens/mcp_install_wizard.py +0 -803
  233. code_puppy/tui/screens/settings.py +0 -290
  234. code_puppy/tui/screens/tools.py +0 -74
  235. code_puppy-0.0.169.data/data/code_puppy/models.json +0 -128
  236. code_puppy-0.0.169.dist-info/RECORD +0 -112
  237. /code_puppy/{mcp → mcp_}/circuit_breaker.py +0 -0
  238. /code_puppy/{mcp → mcp_}/error_isolation.py +0 -0
  239. /code_puppy/{mcp → mcp_}/health_monitor.py +0 -0
  240. /code_puppy/{mcp → mcp_}/retry_manager.py +0 -0
  241. /code_puppy/{mcp → mcp_}/status_tracker.py +0 -0
  242. /code_puppy/{mcp → mcp_}/system_tools.py +0 -0
  243. {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,418 @@
1
+ """Terminal utilities for cross-platform terminal state management.
2
+
3
+ Handles Windows console mode resets and Unix terminal sanity restoration.
4
+ """
5
+
6
+ import os
7
+ import platform
8
+ import subprocess
9
+ import sys
10
+ from typing import TYPE_CHECKING, Callable, Optional
11
+
12
+ if TYPE_CHECKING:
13
+ from rich.console import Console
14
+
15
+ # Store the original console ctrl handler so we can restore it if needed
16
+ _original_ctrl_handler: Optional[Callable] = None
17
+
18
+
19
+ def reset_windows_terminal_ansi() -> None:
20
+ """Reset ANSI formatting on Windows stdout/stderr.
21
+
22
+ This is a lightweight reset that just clears ANSI escape sequences.
23
+ Use this for quick resets after output operations.
24
+ """
25
+ if platform.system() != "Windows":
26
+ return
27
+
28
+ try:
29
+ sys.stdout.write("\x1b[0m") # Reset ANSI formatting
30
+ sys.stdout.flush()
31
+ sys.stderr.write("\x1b[0m")
32
+ sys.stderr.flush()
33
+ except Exception:
34
+ pass # Silently ignore errors - best effort reset
35
+
36
+
37
+ def reset_windows_console_mode() -> None:
38
+ """Full Windows console mode reset using ctypes.
39
+
40
+ This resets both stdout and stdin console modes to restore proper
41
+ terminal behavior after interrupts (Ctrl+C, Ctrl+D). Without this,
42
+ the terminal can become unresponsive (can't type characters).
43
+ """
44
+ if platform.system() != "Windows":
45
+ return
46
+
47
+ try:
48
+ import ctypes
49
+
50
+ kernel32 = ctypes.windll.kernel32
51
+
52
+ # Reset stdout
53
+ STD_OUTPUT_HANDLE = -11
54
+ handle = kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
55
+
56
+ # Enable virtual terminal processing and line input
57
+ mode = ctypes.c_ulong()
58
+ kernel32.GetConsoleMode(handle, ctypes.byref(mode))
59
+
60
+ # Console mode flags for stdout
61
+ ENABLE_PROCESSED_OUTPUT = 0x0001
62
+ ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
63
+ ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
64
+
65
+ new_mode = (
66
+ mode.value
67
+ | ENABLE_PROCESSED_OUTPUT
68
+ | ENABLE_WRAP_AT_EOL_OUTPUT
69
+ | ENABLE_VIRTUAL_TERMINAL_PROCESSING
70
+ )
71
+ kernel32.SetConsoleMode(handle, new_mode)
72
+
73
+ # Reset stdin
74
+ STD_INPUT_HANDLE = -10
75
+ stdin_handle = kernel32.GetStdHandle(STD_INPUT_HANDLE)
76
+
77
+ # Console mode flags for stdin
78
+ ENABLE_LINE_INPUT = 0x0002
79
+ ENABLE_ECHO_INPUT = 0x0004
80
+ ENABLE_PROCESSED_INPUT = 0x0001
81
+
82
+ stdin_mode = ctypes.c_ulong()
83
+ kernel32.GetConsoleMode(stdin_handle, ctypes.byref(stdin_mode))
84
+
85
+ new_stdin_mode = (
86
+ stdin_mode.value
87
+ | ENABLE_LINE_INPUT
88
+ | ENABLE_ECHO_INPUT
89
+ | ENABLE_PROCESSED_INPUT
90
+ )
91
+ kernel32.SetConsoleMode(stdin_handle, new_stdin_mode)
92
+
93
+ except Exception:
94
+ pass # Silently ignore errors - best effort reset
95
+
96
+
97
+ def flush_windows_keyboard_buffer() -> None:
98
+ """Flush the Windows keyboard buffer.
99
+
100
+ Clears any pending keyboard input that could interfere with
101
+ subsequent input operations after an interrupt.
102
+ """
103
+ if platform.system() != "Windows":
104
+ return
105
+
106
+ try:
107
+ import msvcrt
108
+
109
+ while msvcrt.kbhit():
110
+ msvcrt.getch()
111
+ except Exception:
112
+ pass # Silently ignore errors - best effort flush
113
+
114
+
115
+ def reset_windows_terminal_full() -> None:
116
+ """Perform a full Windows terminal reset (ANSI + console mode + keyboard buffer).
117
+
118
+ Combines ANSI reset, console mode reset, and keyboard buffer flush
119
+ for complete terminal state restoration after interrupts.
120
+ """
121
+ if platform.system() != "Windows":
122
+ return
123
+
124
+ reset_windows_terminal_ansi()
125
+ reset_windows_console_mode()
126
+ flush_windows_keyboard_buffer()
127
+
128
+
129
+ def reset_unix_terminal() -> None:
130
+ """Reset Unix/Linux/macOS terminal to sane state.
131
+
132
+ Uses the `reset` command to restore terminal sanity.
133
+ Silently fails if the command isn't available.
134
+ """
135
+ if platform.system() == "Windows":
136
+ return
137
+
138
+ try:
139
+ subprocess.run(["reset"], check=True, capture_output=True)
140
+ except (subprocess.CalledProcessError, FileNotFoundError):
141
+ pass # Silently fail if reset command isn't available
142
+
143
+
144
+ def reset_terminal() -> None:
145
+ """Cross-platform terminal reset.
146
+
147
+ Automatically detects the platform and performs the appropriate
148
+ terminal reset operation.
149
+ """
150
+ if platform.system() == "Windows":
151
+ reset_windows_terminal_full()
152
+ else:
153
+ reset_unix_terminal()
154
+
155
+
156
+ def disable_windows_ctrl_c() -> bool:
157
+ """Disable Ctrl+C processing at the Windows console input level.
158
+
159
+ This removes ENABLE_PROCESSED_INPUT from stdin, which prevents
160
+ Ctrl+C from being interpreted as a signal at all. Instead, it
161
+ becomes just a regular character (^C) that gets ignored.
162
+
163
+ This is more reliable than SetConsoleCtrlHandler because it
164
+ prevents Ctrl+C from being processed before it reaches any handler.
165
+
166
+ Returns:
167
+ True if successfully disabled, False otherwise.
168
+ """
169
+ global _original_ctrl_handler
170
+
171
+ if platform.system() != "Windows":
172
+ return False
173
+
174
+ try:
175
+ import ctypes
176
+
177
+ kernel32 = ctypes.windll.kernel32
178
+
179
+ # Get stdin handle
180
+ STD_INPUT_HANDLE = -10
181
+ stdin_handle = kernel32.GetStdHandle(STD_INPUT_HANDLE)
182
+
183
+ # Get current console mode
184
+ mode = ctypes.c_ulong()
185
+ if not kernel32.GetConsoleMode(stdin_handle, ctypes.byref(mode)):
186
+ return False
187
+
188
+ # Save original mode for potential restoration
189
+ _original_ctrl_handler = mode.value
190
+
191
+ # Console mode flags
192
+ ENABLE_PROCESSED_INPUT = 0x0001 # This makes Ctrl+C generate signals
193
+
194
+ # Remove ENABLE_PROCESSED_INPUT to disable Ctrl+C signal generation
195
+ new_mode = mode.value & ~ENABLE_PROCESSED_INPUT
196
+
197
+ if kernel32.SetConsoleMode(stdin_handle, new_mode):
198
+ return True
199
+ return False
200
+
201
+ except Exception:
202
+ return False
203
+
204
+
205
+ def enable_windows_ctrl_c() -> bool:
206
+ """Re-enable Ctrl+C at the Windows console level.
207
+
208
+ Restores the original console mode saved by disable_windows_ctrl_c().
209
+
210
+ Returns:
211
+ True if successfully re-enabled, False otherwise.
212
+ """
213
+ global _original_ctrl_handler
214
+
215
+ if platform.system() != "Windows":
216
+ return False
217
+
218
+ if _original_ctrl_handler is None:
219
+ return True # Nothing to restore
220
+
221
+ try:
222
+ import ctypes
223
+
224
+ kernel32 = ctypes.windll.kernel32
225
+
226
+ # Get stdin handle
227
+ STD_INPUT_HANDLE = -10
228
+ stdin_handle = kernel32.GetStdHandle(STD_INPUT_HANDLE)
229
+
230
+ # Restore original mode
231
+ if kernel32.SetConsoleMode(stdin_handle, _original_ctrl_handler):
232
+ _original_ctrl_handler = None
233
+ return True
234
+ return False
235
+
236
+ except Exception:
237
+ return False
238
+
239
+
240
+ # Flag to track if we should keep Ctrl+C disabled
241
+ _keep_ctrl_c_disabled: bool = False
242
+
243
+
244
+ def set_keep_ctrl_c_disabled(value: bool) -> None:
245
+ """Set whether Ctrl+C should be kept disabled.
246
+
247
+ When True, ensure_ctrl_c_disabled() will re-disable Ctrl+C
248
+ even if something else (like prompt_toolkit) re-enables it.
249
+ """
250
+ global _keep_ctrl_c_disabled
251
+ _keep_ctrl_c_disabled = value
252
+
253
+
254
+ def ensure_ctrl_c_disabled() -> bool:
255
+ """Ensure Ctrl+C is disabled if it should be.
256
+
257
+ Call this after operations that might restore console mode
258
+ (like prompt_toolkit input).
259
+
260
+ Returns:
261
+ True if Ctrl+C is now disabled (or wasn't needed), False on error.
262
+ """
263
+ if not _keep_ctrl_c_disabled:
264
+ return True
265
+
266
+ if platform.system() != "Windows":
267
+ return True
268
+
269
+ try:
270
+ import ctypes
271
+
272
+ kernel32 = ctypes.windll.kernel32
273
+
274
+ # Get stdin handle
275
+ STD_INPUT_HANDLE = -10
276
+ stdin_handle = kernel32.GetStdHandle(STD_INPUT_HANDLE)
277
+
278
+ # Get current console mode
279
+ mode = ctypes.c_ulong()
280
+ if not kernel32.GetConsoleMode(stdin_handle, ctypes.byref(mode)):
281
+ return False
282
+
283
+ # Console mode flags
284
+ ENABLE_PROCESSED_INPUT = 0x0001
285
+
286
+ # Check if Ctrl+C processing is enabled
287
+ if mode.value & ENABLE_PROCESSED_INPUT:
288
+ # Disable it
289
+ new_mode = mode.value & ~ENABLE_PROCESSED_INPUT
290
+ return bool(kernel32.SetConsoleMode(stdin_handle, new_mode))
291
+
292
+ return True # Already disabled
293
+
294
+ except Exception:
295
+ return False
296
+
297
+
298
+ def detect_truecolor_support() -> bool:
299
+ """Detect if the terminal supports truecolor (24-bit color).
300
+
301
+ Checks multiple indicators:
302
+ 1. COLORTERM environment variable (most reliable)
303
+ 2. TERM environment variable patterns
304
+ 3. Rich's Console color_system detection as fallback
305
+
306
+ Returns:
307
+ True if truecolor is supported, False otherwise.
308
+ """
309
+ # Check COLORTERM - this is the most reliable indicator
310
+ colorterm = os.environ.get("COLORTERM", "").lower()
311
+ if colorterm in ("truecolor", "24bit"):
312
+ return True
313
+
314
+ # Check TERM for known truecolor-capable terminals
315
+ term = os.environ.get("TERM", "").lower()
316
+ truecolor_terms = (
317
+ "xterm-direct",
318
+ "xterm-truecolor",
319
+ "iterm2",
320
+ "vte-256color", # Many modern terminals set this
321
+ )
322
+ if any(t in term for t in truecolor_terms):
323
+ return True
324
+
325
+ # Some terminals like iTerm2, Kitty, Alacritty set specific env vars
326
+ if os.environ.get("ITERM_SESSION_ID"):
327
+ return True
328
+ if os.environ.get("KITTY_WINDOW_ID"):
329
+ return True
330
+ if os.environ.get("ALACRITTY_SOCKET"):
331
+ return True
332
+ if os.environ.get("WT_SESSION"): # Windows Terminal
333
+ return True
334
+
335
+ # Use Rich's detection as a fallback
336
+ try:
337
+ from rich.console import Console
338
+
339
+ console = Console(force_terminal=True)
340
+ color_system = console.color_system
341
+ return color_system == "truecolor"
342
+ except Exception:
343
+ pass
344
+
345
+ return False
346
+
347
+
348
+ def print_truecolor_warning(console: Optional["Console"] = None) -> None:
349
+ """Print a big fat red warning if truecolor is not supported.
350
+
351
+ Args:
352
+ console: Optional Rich Console instance. If None, creates a new one.
353
+ """
354
+ if detect_truecolor_support():
355
+ return # All good, no warning needed
356
+
357
+ if console is None:
358
+ try:
359
+ from rich.console import Console
360
+
361
+ console = Console()
362
+ except ImportError:
363
+ # Rich not available, fall back to plain print
364
+ print("\n" + "=" * 70)
365
+ print("⚠️ WARNING: TERMINAL DOES NOT SUPPORT TRUECOLOR (24-BIT COLOR)")
366
+ print("=" * 70)
367
+ print("Code Puppy looks best with truecolor support.")
368
+ print("Consider using a modern terminal like:")
369
+ print(" • iTerm2 (macOS)")
370
+ print(" • Windows Terminal (Windows)")
371
+ print(" • Kitty, Alacritty, or any modern terminal emulator")
372
+ print("")
373
+ print("You can also try setting: export COLORTERM=truecolor")
374
+ print("")
375
+ print("Note: The built-in macOS Terminal.app does not support truecolor")
376
+ print("(Sequoia and earlier). You'll need a different terminal app.")
377
+ print("=" * 70 + "\n")
378
+ return
379
+
380
+ # Get detected color system for diagnostic info
381
+ color_system = console.color_system or "unknown"
382
+
383
+ # Build the warning box
384
+ warning_lines = [
385
+ "",
386
+ "[bold bright_red on red]" + "━" * 72 + "[/]",
387
+ "[bold bright_red on red]┃[/][bold bright_white on red]"
388
+ + " " * 70
389
+ + "[/][bold bright_red on red]┃[/]",
390
+ "[bold bright_red on red]┃[/][bold bright_white on red] ⚠️ WARNING: TERMINAL DOES NOT SUPPORT TRUECOLOR (24-BIT COLOR) ⚠️ [/][bold bright_red on red]┃[/]",
391
+ "[bold bright_red on red]┃[/][bold bright_white on red]"
392
+ + " " * 70
393
+ + "[/][bold bright_red on red]┃[/]",
394
+ "[bold bright_red on red]" + "━" * 72 + "[/]",
395
+ "",
396
+ f"[yellow]Detected color system:[/] [bold]{color_system}[/]",
397
+ "",
398
+ "[bold white]Code Puppy uses rich colors and will look degraded without truecolor.[/]",
399
+ "",
400
+ "[cyan]Consider using a modern terminal emulator:[/]",
401
+ " [green]•[/] [bold]iTerm2[/] (macOS) - https://iterm2.com",
402
+ " [green]•[/] [bold]Windows Terminal[/] (Windows) - Built into Windows 11",
403
+ " [green]•[/] [bold]Kitty[/] - https://sw.kovidgoyal.net/kitty",
404
+ " [green]•[/] [bold]Alacritty[/] - https://alacritty.org",
405
+ " [green]•[/] [bold]Warp[/] (macOS) - https://warp.dev",
406
+ "",
407
+ "[cyan]Or try setting the COLORTERM environment variable:[/]",
408
+ " [dim]export COLORTERM=truecolor[/]",
409
+ "",
410
+ "[dim italic]Note: The built-in macOS Terminal.app does not support truecolor (Sequoia and earlier).[/]",
411
+ "[dim italic]Setting COLORTERM=truecolor won't help - you'll need a different terminal app.[/]",
412
+ "",
413
+ "[bold bright_red]" + "─" * 72 + "[/]",
414
+ "",
415
+ ]
416
+
417
+ for line in warning_lines:
418
+ console.print(line)
@@ -1,20 +1,93 @@
1
1
  from code_puppy.messaging import emit_warning
2
- from code_puppy.tools.agent_tools import (
3
- register_list_agents,
4
- register_invoke_agent,
2
+ from code_puppy.tools.agent_tools import register_invoke_agent, register_list_agents
3
+
4
+ # Browser automation tools
5
+ from code_puppy.tools.browser.browser_control import (
6
+ register_close_browser,
7
+ register_create_new_page,
8
+ register_get_browser_status,
9
+ register_initialize_browser,
10
+ register_list_pages,
11
+ )
12
+ from code_puppy.tools.browser.browser_interactions import (
13
+ register_browser_check,
14
+ register_browser_uncheck,
15
+ register_click_element,
16
+ register_double_click_element,
17
+ register_get_element_text,
18
+ register_get_element_value,
19
+ register_hover_element,
20
+ register_select_option,
21
+ register_set_element_text,
22
+ )
23
+ from code_puppy.tools.browser.browser_locators import (
24
+ register_find_buttons,
25
+ register_find_by_label,
26
+ register_find_by_placeholder,
27
+ register_find_by_role,
28
+ register_find_by_test_id,
29
+ register_find_by_text,
30
+ register_find_links,
31
+ register_run_xpath_query,
32
+ )
33
+ from code_puppy.tools.browser.browser_navigation import (
34
+ register_browser_go_back,
35
+ register_browser_go_forward,
36
+ register_get_page_info,
37
+ register_navigate_to_url,
38
+ register_reload_page,
39
+ register_wait_for_load_state,
40
+ )
41
+ from code_puppy.tools.browser.browser_screenshot import (
42
+ register_take_screenshot_and_analyze,
43
+ )
44
+ from code_puppy.tools.browser.browser_scripts import (
45
+ register_browser_clear_highlights,
46
+ register_browser_highlight_element,
47
+ register_execute_javascript,
48
+ register_scroll_page,
49
+ register_scroll_to_element,
50
+ register_set_viewport_size,
51
+ register_wait_for_element,
52
+ )
53
+ from code_puppy.tools.browser.browser_workflows import (
54
+ register_list_workflows,
55
+ register_read_workflow,
56
+ register_save_workflow,
57
+ )
58
+ from code_puppy.tools.browser.terminal_command_tools import (
59
+ register_run_terminal_command,
60
+ register_send_terminal_keys,
61
+ register_wait_terminal_output,
62
+ )
63
+ from code_puppy.tools.browser.terminal_screenshot_tools import (
64
+ register_load_image,
65
+ register_terminal_compare_mockup,
66
+ register_terminal_read_output,
67
+ register_terminal_screenshot,
68
+ )
69
+
70
+ # Terminal automation tools
71
+ from code_puppy.tools.browser.terminal_tools import (
72
+ register_check_terminal_server,
73
+ register_close_terminal,
74
+ register_open_terminal,
75
+ register_start_api_server,
5
76
  )
6
77
  from code_puppy.tools.command_runner import (
7
78
  register_agent_run_shell_command,
8
79
  register_agent_share_your_reasoning,
9
80
  )
10
- from code_puppy.tools.file_modifications import register_edit_file, register_delete_file
81
+ from code_puppy.tools.display import (
82
+ display_non_streamed_result as display_non_streamed_result,
83
+ )
84
+ from code_puppy.tools.file_modifications import register_delete_file, register_edit_file
11
85
  from code_puppy.tools.file_operations import (
86
+ register_grep,
12
87
  register_list_files,
13
88
  register_read_file,
14
- register_grep,
15
89
  )
16
90
 
17
-
18
91
  # Map of tool names to their individual registration functions
19
92
  TOOL_REGISTRY = {
20
93
  # Agent Tools
@@ -30,6 +103,66 @@ TOOL_REGISTRY = {
30
103
  # Command Runner
31
104
  "agent_run_shell_command": register_agent_run_shell_command,
32
105
  "agent_share_your_reasoning": register_agent_share_your_reasoning,
106
+ # Browser Control
107
+ "browser_initialize": register_initialize_browser,
108
+ "browser_close": register_close_browser,
109
+ "browser_status": register_get_browser_status,
110
+ "browser_new_page": register_create_new_page,
111
+ "browser_list_pages": register_list_pages,
112
+ # Browser Navigation
113
+ "browser_navigate": register_navigate_to_url,
114
+ "browser_get_page_info": register_get_page_info,
115
+ "browser_go_back": register_browser_go_back,
116
+ "browser_go_forward": register_browser_go_forward,
117
+ "browser_reload": register_reload_page,
118
+ "browser_wait_for_load": register_wait_for_load_state,
119
+ # Browser Element Discovery
120
+ "browser_find_by_role": register_find_by_role,
121
+ "browser_find_by_text": register_find_by_text,
122
+ "browser_find_by_label": register_find_by_label,
123
+ "browser_find_by_placeholder": register_find_by_placeholder,
124
+ "browser_find_by_test_id": register_find_by_test_id,
125
+ "browser_xpath_query": register_run_xpath_query,
126
+ "browser_find_buttons": register_find_buttons,
127
+ "browser_find_links": register_find_links,
128
+ # Browser Element Interactions
129
+ "browser_click": register_click_element,
130
+ "browser_double_click": register_double_click_element,
131
+ "browser_hover": register_hover_element,
132
+ "browser_set_text": register_set_element_text,
133
+ "browser_get_text": register_get_element_text,
134
+ "browser_get_value": register_get_element_value,
135
+ "browser_select_option": register_select_option,
136
+ "browser_check": register_browser_check,
137
+ "browser_uncheck": register_browser_uncheck,
138
+ # Browser Scripts and Advanced Features
139
+ "browser_execute_js": register_execute_javascript,
140
+ "browser_scroll": register_scroll_page,
141
+ "browser_scroll_to_element": register_scroll_to_element,
142
+ "browser_set_viewport": register_set_viewport_size,
143
+ "browser_wait_for_element": register_wait_for_element,
144
+ "browser_highlight_element": register_browser_highlight_element,
145
+ "browser_clear_highlights": register_browser_clear_highlights,
146
+ # Browser Screenshots
147
+ "browser_screenshot_analyze": register_take_screenshot_and_analyze,
148
+ # Browser Workflows
149
+ "browser_save_workflow": register_save_workflow,
150
+ "browser_list_workflows": register_list_workflows,
151
+ "browser_read_workflow": register_read_workflow,
152
+ # Terminal Connection Tools
153
+ "terminal_check_server": register_check_terminal_server,
154
+ "terminal_open": register_open_terminal,
155
+ "terminal_close": register_close_terminal,
156
+ "start_api_server": register_start_api_server,
157
+ # Terminal Command Execution Tools
158
+ "terminal_run_command": register_run_terminal_command,
159
+ "terminal_send_keys": register_send_terminal_keys,
160
+ "terminal_wait_output": register_wait_terminal_output,
161
+ # Terminal Screenshot Tools
162
+ "terminal_screenshot_analyze": register_terminal_screenshot,
163
+ "terminal_read_output": register_terminal_read_output,
164
+ "terminal_compare_mockup": register_terminal_compare_mockup,
165
+ "load_image_for_analysis": register_load_image,
33
166
  }
34
167
 
35
168