newcode 0.1.1__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 (289) hide show
  1. code_puppy/__init__.py +10 -0
  2. code_puppy/__main__.py +10 -0
  3. code_puppy/agents/__init__.py +31 -0
  4. code_puppy/agents/agent_c_reviewer.py +155 -0
  5. code_puppy/agents/agent_code_puppy.py +147 -0
  6. code_puppy/agents/agent_code_reviewer.py +90 -0
  7. code_puppy/agents/agent_cpp_reviewer.py +132 -0
  8. code_puppy/agents/agent_creator_agent.py +630 -0
  9. code_puppy/agents/agent_golang_reviewer.py +151 -0
  10. code_puppy/agents/agent_helios.py +122 -0
  11. code_puppy/agents/agent_javascript_reviewer.py +160 -0
  12. code_puppy/agents/agent_manager.py +742 -0
  13. code_puppy/agents/agent_pack_leader.py +380 -0
  14. code_puppy/agents/agent_planning.py +165 -0
  15. code_puppy/agents/agent_python_programmer.py +167 -0
  16. code_puppy/agents/agent_python_reviewer.py +90 -0
  17. code_puppy/agents/agent_qa_expert.py +163 -0
  18. code_puppy/agents/agent_qa_kitten.py +208 -0
  19. code_puppy/agents/agent_scheduler.py +121 -0
  20. code_puppy/agents/agent_security_auditor.py +181 -0
  21. code_puppy/agents/agent_terminal_qa.py +323 -0
  22. code_puppy/agents/agent_typescript_reviewer.py +166 -0
  23. code_puppy/agents/base_agent.py +2145 -0
  24. code_puppy/agents/event_stream_handler.py +348 -0
  25. code_puppy/agents/json_agent.py +202 -0
  26. code_puppy/agents/pack/__init__.py +34 -0
  27. code_puppy/agents/pack/bloodhound.py +296 -0
  28. code_puppy/agents/pack/husky.py +307 -0
  29. code_puppy/agents/pack/retriever.py +380 -0
  30. code_puppy/agents/pack/shepherd.py +327 -0
  31. code_puppy/agents/pack/terrier.py +281 -0
  32. code_puppy/agents/pack/watchdog.py +357 -0
  33. code_puppy/agents/prompt_reviewer.py +145 -0
  34. code_puppy/agents/subagent_stream_handler.py +276 -0
  35. code_puppy/api/__init__.py +13 -0
  36. code_puppy/api/app.py +169 -0
  37. code_puppy/api/main.py +21 -0
  38. code_puppy/api/pty_manager.py +453 -0
  39. code_puppy/api/routers/__init__.py +12 -0
  40. code_puppy/api/routers/agents.py +36 -0
  41. code_puppy/api/routers/commands.py +217 -0
  42. code_puppy/api/routers/config.py +75 -0
  43. code_puppy/api/routers/sessions.py +234 -0
  44. code_puppy/api/templates/terminal.html +361 -0
  45. code_puppy/api/websocket.py +154 -0
  46. code_puppy/callbacks.py +674 -0
  47. code_puppy/chatgpt_codex_client.py +338 -0
  48. code_puppy/claude_cache_client.py +664 -0
  49. code_puppy/cli_runner.py +1038 -0
  50. code_puppy/command_line/__init__.py +1 -0
  51. code_puppy/command_line/add_model_menu.py +1092 -0
  52. code_puppy/command_line/agent_menu.py +662 -0
  53. code_puppy/command_line/attachments.py +395 -0
  54. code_puppy/command_line/autosave_menu.py +704 -0
  55. code_puppy/command_line/clipboard.py +527 -0
  56. code_puppy/command_line/colors_menu.py +526 -0
  57. code_puppy/command_line/command_handler.py +283 -0
  58. code_puppy/command_line/command_registry.py +150 -0
  59. code_puppy/command_line/config_commands.py +719 -0
  60. code_puppy/command_line/core_commands.py +853 -0
  61. code_puppy/command_line/diff_menu.py +865 -0
  62. code_puppy/command_line/file_path_completion.py +73 -0
  63. code_puppy/command_line/load_context_completion.py +52 -0
  64. code_puppy/command_line/mcp/__init__.py +10 -0
  65. code_puppy/command_line/mcp/base.py +32 -0
  66. code_puppy/command_line/mcp/catalog_server_installer.py +175 -0
  67. code_puppy/command_line/mcp/custom_server_form.py +688 -0
  68. code_puppy/command_line/mcp/custom_server_installer.py +195 -0
  69. code_puppy/command_line/mcp/edit_command.py +148 -0
  70. code_puppy/command_line/mcp/handler.py +138 -0
  71. code_puppy/command_line/mcp/help_command.py +147 -0
  72. code_puppy/command_line/mcp/install_command.py +214 -0
  73. code_puppy/command_line/mcp/install_menu.py +705 -0
  74. code_puppy/command_line/mcp/list_command.py +94 -0
  75. code_puppy/command_line/mcp/logs_command.py +235 -0
  76. code_puppy/command_line/mcp/remove_command.py +82 -0
  77. code_puppy/command_line/mcp/restart_command.py +100 -0
  78. code_puppy/command_line/mcp/search_command.py +123 -0
  79. code_puppy/command_line/mcp/start_all_command.py +135 -0
  80. code_puppy/command_line/mcp/start_command.py +117 -0
  81. code_puppy/command_line/mcp/status_command.py +184 -0
  82. code_puppy/command_line/mcp/stop_all_command.py +112 -0
  83. code_puppy/command_line/mcp/stop_command.py +80 -0
  84. code_puppy/command_line/mcp/test_command.py +107 -0
  85. code_puppy/command_line/mcp/utils.py +129 -0
  86. code_puppy/command_line/mcp/wizard_utils.py +334 -0
  87. code_puppy/command_line/mcp_completion.py +174 -0
  88. code_puppy/command_line/model_picker_completion.py +197 -0
  89. code_puppy/command_line/model_settings_menu.py +932 -0
  90. code_puppy/command_line/motd.py +91 -0
  91. code_puppy/command_line/onboarding_slides.py +179 -0
  92. code_puppy/command_line/onboarding_wizard.py +342 -0
  93. code_puppy/command_line/pin_command_completion.py +329 -0
  94. code_puppy/command_line/prompt_toolkit_completion.py +846 -0
  95. code_puppy/command_line/session_commands.py +302 -0
  96. code_puppy/command_line/skills_completion.py +160 -0
  97. code_puppy/command_line/uc_menu.py +893 -0
  98. code_puppy/command_line/utils.py +93 -0
  99. code_puppy/command_line/wiggum_state.py +78 -0
  100. code_puppy/config.py +1787 -0
  101. code_puppy/error_logging.py +133 -0
  102. code_puppy/gemini_code_assist.py +385 -0
  103. code_puppy/gemini_model.py +754 -0
  104. code_puppy/hook_engine/README.md +105 -0
  105. code_puppy/hook_engine/__init__.py +15 -0
  106. code_puppy/hook_engine/aliases.py +155 -0
  107. code_puppy/hook_engine/engine.py +195 -0
  108. code_puppy/hook_engine/executor.py +293 -0
  109. code_puppy/hook_engine/matcher.py +145 -0
  110. code_puppy/hook_engine/models.py +222 -0
  111. code_puppy/hook_engine/registry.py +106 -0
  112. code_puppy/hook_engine/validator.py +141 -0
  113. code_puppy/http_utils.py +361 -0
  114. code_puppy/keymap.py +128 -0
  115. code_puppy/main.py +10 -0
  116. code_puppy/mcp_/__init__.py +66 -0
  117. code_puppy/mcp_/async_lifecycle.py +286 -0
  118. code_puppy/mcp_/blocking_startup.py +469 -0
  119. code_puppy/mcp_/captured_stdio_server.py +275 -0
  120. code_puppy/mcp_/circuit_breaker.py +290 -0
  121. code_puppy/mcp_/config_wizard.py +507 -0
  122. code_puppy/mcp_/dashboard.py +308 -0
  123. code_puppy/mcp_/error_isolation.py +407 -0
  124. code_puppy/mcp_/examples/retry_example.py +226 -0
  125. code_puppy/mcp_/health_monitor.py +589 -0
  126. code_puppy/mcp_/managed_server.py +428 -0
  127. code_puppy/mcp_/manager.py +807 -0
  128. code_puppy/mcp_/mcp_logs.py +224 -0
  129. code_puppy/mcp_/registry.py +451 -0
  130. code_puppy/mcp_/retry_manager.py +337 -0
  131. code_puppy/mcp_/server_registry_catalog.py +1126 -0
  132. code_puppy/mcp_/status_tracker.py +355 -0
  133. code_puppy/mcp_/system_tools.py +209 -0
  134. code_puppy/mcp_prompts/__init__.py +1 -0
  135. code_puppy/mcp_prompts/hook_creator.py +103 -0
  136. code_puppy/messaging/__init__.py +255 -0
  137. code_puppy/messaging/bus.py +613 -0
  138. code_puppy/messaging/commands.py +167 -0
  139. code_puppy/messaging/markdown_patches.py +57 -0
  140. code_puppy/messaging/message_queue.py +361 -0
  141. code_puppy/messaging/messages.py +569 -0
  142. code_puppy/messaging/queue_console.py +271 -0
  143. code_puppy/messaging/renderers.py +311 -0
  144. code_puppy/messaging/rich_renderer.py +1153 -0
  145. code_puppy/messaging/spinner/__init__.py +83 -0
  146. code_puppy/messaging/spinner/console_spinner.py +240 -0
  147. code_puppy/messaging/spinner/spinner_base.py +96 -0
  148. code_puppy/messaging/subagent_console.py +460 -0
  149. code_puppy/model_factory.py +848 -0
  150. code_puppy/model_switching.py +63 -0
  151. code_puppy/model_utils.py +168 -0
  152. code_puppy/models.json +130 -0
  153. code_puppy/models_dev_api.json +1 -0
  154. code_puppy/models_dev_parser.py +592 -0
  155. code_puppy/plugins/__init__.py +186 -0
  156. code_puppy/plugins/agent_skills/__init__.py +22 -0
  157. code_puppy/plugins/agent_skills/config.py +175 -0
  158. code_puppy/plugins/agent_skills/discovery.py +136 -0
  159. code_puppy/plugins/agent_skills/downloader.py +392 -0
  160. code_puppy/plugins/agent_skills/installer.py +22 -0
  161. code_puppy/plugins/agent_skills/metadata.py +219 -0
  162. code_puppy/plugins/agent_skills/prompt_builder.py +100 -0
  163. code_puppy/plugins/agent_skills/register_callbacks.py +241 -0
  164. code_puppy/plugins/agent_skills/remote_catalog.py +322 -0
  165. code_puppy/plugins/agent_skills/skill_catalog.py +257 -0
  166. code_puppy/plugins/agent_skills/skills_install_menu.py +664 -0
  167. code_puppy/plugins/agent_skills/skills_menu.py +781 -0
  168. code_puppy/plugins/antigravity_oauth/__init__.py +10 -0
  169. code_puppy/plugins/antigravity_oauth/accounts.py +406 -0
  170. code_puppy/plugins/antigravity_oauth/antigravity_model.py +706 -0
  171. code_puppy/plugins/antigravity_oauth/config.py +42 -0
  172. code_puppy/plugins/antigravity_oauth/constants.py +133 -0
  173. code_puppy/plugins/antigravity_oauth/oauth.py +478 -0
  174. code_puppy/plugins/antigravity_oauth/register_callbacks.py +518 -0
  175. code_puppy/plugins/antigravity_oauth/storage.py +288 -0
  176. code_puppy/plugins/antigravity_oauth/test_plugin.py +319 -0
  177. code_puppy/plugins/antigravity_oauth/token.py +167 -0
  178. code_puppy/plugins/antigravity_oauth/transport.py +863 -0
  179. code_puppy/plugins/antigravity_oauth/utils.py +168 -0
  180. code_puppy/plugins/chatgpt_oauth/__init__.py +8 -0
  181. code_puppy/plugins/chatgpt_oauth/config.py +52 -0
  182. code_puppy/plugins/chatgpt_oauth/oauth_flow.py +328 -0
  183. code_puppy/plugins/chatgpt_oauth/register_callbacks.py +176 -0
  184. code_puppy/plugins/chatgpt_oauth/test_plugin.py +295 -0
  185. code_puppy/plugins/chatgpt_oauth/utils.py +499 -0
  186. code_puppy/plugins/claude_code_hooks/__init__.py +1 -0
  187. code_puppy/plugins/claude_code_hooks/config.py +131 -0
  188. code_puppy/plugins/claude_code_hooks/register_callbacks.py +163 -0
  189. code_puppy/plugins/claude_code_oauth/README.md +167 -0
  190. code_puppy/plugins/claude_code_oauth/SETUP.md +93 -0
  191. code_puppy/plugins/claude_code_oauth/__init__.py +25 -0
  192. code_puppy/plugins/claude_code_oauth/config.py +52 -0
  193. code_puppy/plugins/claude_code_oauth/register_callbacks.py +453 -0
  194. code_puppy/plugins/claude_code_oauth/test_plugin.py +283 -0
  195. code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +241 -0
  196. code_puppy/plugins/claude_code_oauth/utils.py +601 -0
  197. code_puppy/plugins/customizable_commands/__init__.py +0 -0
  198. code_puppy/plugins/customizable_commands/register_callbacks.py +152 -0
  199. code_puppy/plugins/example_custom_command/README.md +280 -0
  200. code_puppy/plugins/example_custom_command/register_callbacks.py +48 -0
  201. code_puppy/plugins/file_permission_handler/__init__.py +4 -0
  202. code_puppy/plugins/file_permission_handler/register_callbacks.py +528 -0
  203. code_puppy/plugins/frontend_emitter/__init__.py +25 -0
  204. code_puppy/plugins/frontend_emitter/emitter.py +121 -0
  205. code_puppy/plugins/frontend_emitter/register_callbacks.py +261 -0
  206. code_puppy/plugins/hook_creator/__init__.py +1 -0
  207. code_puppy/plugins/hook_creator/register_callbacks.py +33 -0
  208. code_puppy/plugins/hook_manager/__init__.py +1 -0
  209. code_puppy/plugins/hook_manager/config.py +277 -0
  210. code_puppy/plugins/hook_manager/hooks_menu.py +551 -0
  211. code_puppy/plugins/hook_manager/register_callbacks.py +205 -0
  212. code_puppy/plugins/oauth_puppy_html.py +224 -0
  213. code_puppy/plugins/scheduler/__init__.py +1 -0
  214. code_puppy/plugins/scheduler/register_callbacks.py +88 -0
  215. code_puppy/plugins/scheduler/scheduler_menu.py +522 -0
  216. code_puppy/plugins/scheduler/scheduler_wizard.py +341 -0
  217. code_puppy/plugins/shell_safety/__init__.py +6 -0
  218. code_puppy/plugins/shell_safety/agent_shell_safety.py +69 -0
  219. code_puppy/plugins/shell_safety/command_cache.py +156 -0
  220. code_puppy/plugins/shell_safety/register_callbacks.py +202 -0
  221. code_puppy/plugins/synthetic_status/__init__.py +1 -0
  222. code_puppy/plugins/synthetic_status/register_callbacks.py +132 -0
  223. code_puppy/plugins/synthetic_status/status_api.py +147 -0
  224. code_puppy/plugins/universal_constructor/__init__.py +13 -0
  225. code_puppy/plugins/universal_constructor/models.py +138 -0
  226. code_puppy/plugins/universal_constructor/register_callbacks.py +47 -0
  227. code_puppy/plugins/universal_constructor/registry.py +302 -0
  228. code_puppy/plugins/universal_constructor/sandbox.py +584 -0
  229. code_puppy/prompts/antigravity_system_prompt.md +1 -0
  230. code_puppy/pydantic_patches.py +317 -0
  231. code_puppy/reopenable_async_client.py +232 -0
  232. code_puppy/round_robin_model.py +150 -0
  233. code_puppy/scheduler/__init__.py +41 -0
  234. code_puppy/scheduler/__main__.py +9 -0
  235. code_puppy/scheduler/cli.py +118 -0
  236. code_puppy/scheduler/config.py +126 -0
  237. code_puppy/scheduler/daemon.py +280 -0
  238. code_puppy/scheduler/executor.py +155 -0
  239. code_puppy/scheduler/platform.py +19 -0
  240. code_puppy/scheduler/platform_unix.py +22 -0
  241. code_puppy/scheduler/platform_win.py +32 -0
  242. code_puppy/session_storage.py +338 -0
  243. code_puppy/status_display.py +257 -0
  244. code_puppy/summarization_agent.py +176 -0
  245. code_puppy/terminal_utils.py +418 -0
  246. code_puppy/tools/__init__.py +470 -0
  247. code_puppy/tools/agent_tools.py +616 -0
  248. code_puppy/tools/ask_user_question/__init__.py +26 -0
  249. code_puppy/tools/ask_user_question/constants.py +73 -0
  250. code_puppy/tools/ask_user_question/demo_tui.py +55 -0
  251. code_puppy/tools/ask_user_question/handler.py +232 -0
  252. code_puppy/tools/ask_user_question/models.py +304 -0
  253. code_puppy/tools/ask_user_question/registration.py +36 -0
  254. code_puppy/tools/ask_user_question/renderers.py +309 -0
  255. code_puppy/tools/ask_user_question/terminal_ui.py +329 -0
  256. code_puppy/tools/ask_user_question/theme.py +155 -0
  257. code_puppy/tools/ask_user_question/tui_loop.py +423 -0
  258. code_puppy/tools/browser/__init__.py +37 -0
  259. code_puppy/tools/browser/browser_control.py +289 -0
  260. code_puppy/tools/browser/browser_interactions.py +545 -0
  261. code_puppy/tools/browser/browser_locators.py +640 -0
  262. code_puppy/tools/browser/browser_manager.py +378 -0
  263. code_puppy/tools/browser/browser_navigation.py +251 -0
  264. code_puppy/tools/browser/browser_screenshot.py +179 -0
  265. code_puppy/tools/browser/browser_scripts.py +462 -0
  266. code_puppy/tools/browser/browser_workflows.py +221 -0
  267. code_puppy/tools/browser/chromium_terminal_manager.py +259 -0
  268. code_puppy/tools/browser/terminal_command_tools.py +534 -0
  269. code_puppy/tools/browser/terminal_screenshot_tools.py +552 -0
  270. code_puppy/tools/browser/terminal_tools.py +525 -0
  271. code_puppy/tools/command_runner.py +1346 -0
  272. code_puppy/tools/common.py +1409 -0
  273. code_puppy/tools/display.py +84 -0
  274. code_puppy/tools/file_modifications.py +739 -0
  275. code_puppy/tools/file_operations.py +802 -0
  276. code_puppy/tools/scheduler_tools.py +412 -0
  277. code_puppy/tools/skills_tools.py +251 -0
  278. code_puppy/tools/subagent_context.py +158 -0
  279. code_puppy/tools/tools_content.py +51 -0
  280. code_puppy/tools/universal_constructor.py +889 -0
  281. code_puppy/uvx_detection.py +242 -0
  282. code_puppy/version_checker.py +82 -0
  283. newcode-0.1.1.data/data/code_puppy/models.json +130 -0
  284. newcode-0.1.1.data/data/code_puppy/models_dev_api.json +1 -0
  285. newcode-0.1.1.dist-info/METADATA +154 -0
  286. newcode-0.1.1.dist-info/RECORD +289 -0
  287. newcode-0.1.1.dist-info/WHEEL +4 -0
  288. newcode-0.1.1.dist-info/entry_points.txt +3 -0
  289. newcode-0.1.1.dist-info/licenses/LICENSE +21 -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("The application 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]The application 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)