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
@@ -8,11 +8,11 @@ appropriately for their respective interfaces.
8
8
  import asyncio
9
9
  import threading
10
10
  from abc import ABC, abstractmethod
11
- from io import StringIO
12
11
  from typing import Optional
13
12
 
14
13
  from rich.console import Console
15
14
  from rich.markdown import Markdown
15
+ from rich.markup import escape as escape_rich_markup
16
16
 
17
17
  from .message_queue import MessageQueue, MessageType, UIMessage
18
18
 
@@ -64,7 +64,10 @@ class MessageRenderer(ABC):
64
64
  break
65
65
  except Exception as e:
66
66
  # Log error but continue processing
67
- print(f"Error rendering message: {e}")
67
+ # Note: Using sys.stderr - can't use messaging in renderer
68
+ import sys
69
+
70
+ sys.stderr.write(f"Error rendering message: {e}\n")
68
71
 
69
72
 
70
73
  class InteractiveRenderer(MessageRenderer):
@@ -103,10 +106,18 @@ class InteractiveRenderer(MessageRenderer):
103
106
  # Special handling for agent responses - they'll be rendered as markdown
104
107
  style = None
105
108
  elif message.type == MessageType.SYSTEM:
106
- style = None
109
+ style = "dim"
107
110
  else:
108
111
  style = None
109
112
 
113
+ # Make version messages dim regardless of message type
114
+ if isinstance(message.content, str):
115
+ if (
116
+ "Current version:" in message.content
117
+ or "Latest version:" in message.content
118
+ ):
119
+ style = "dim"
120
+
110
121
  # Render the content
111
122
  if isinstance(message.content, str):
112
123
  if message.type == MessageType.AGENT_RESPONSE:
@@ -116,11 +127,15 @@ class InteractiveRenderer(MessageRenderer):
116
127
  self.console.print(markdown)
117
128
  except Exception:
118
129
  # Fallback to plain text if markdown parsing fails
119
- self.console.print(message.content)
130
+ safe_content = escape_rich_markup(message.content)
131
+ self.console.print(safe_content)
120
132
  elif style:
121
- self.console.print(message.content, style=style)
133
+ # Escape Rich markup to prevent crashes from malformed tags
134
+ safe_content = escape_rich_markup(message.content)
135
+ self.console.print(safe_content, style=style)
122
136
  else:
123
- self.console.print(message.content)
137
+ safe_content = escape_rich_markup(message.content)
138
+ self.console.print(safe_content)
124
139
  else:
125
140
  # For complex Rich objects (Tables, Markdown, Text, etc.)
126
141
  self.console.print(message.content)
@@ -135,144 +150,12 @@ class InteractiveRenderer(MessageRenderer):
135
150
  # This renderer is not currently used in practice, but if it were:
136
151
  # We would need async input handling here
137
152
  # For now, just render as a system message
138
- self.console.print(f"[bold cyan]INPUT REQUESTED:[/bold cyan] {message.content}")
153
+ safe_content = escape_rich_markup(str(message.content))
154
+ self.console.print(f"[bold cyan]INPUT REQUESTED:[/bold cyan] {safe_content}")
139
155
  if hasattr(self.console.file, "flush"):
140
156
  self.console.file.flush()
141
157
 
142
158
 
143
- class TUIRenderer(MessageRenderer):
144
- """Renderer for TUI mode that adds messages to the chat view."""
145
-
146
- def __init__(self, queue: MessageQueue, tui_app=None):
147
- super().__init__(queue)
148
- self.tui_app = tui_app
149
-
150
- def set_tui_app(self, app):
151
- """Set the TUI app reference."""
152
- self.tui_app = app
153
-
154
- async def render_message(self, message: UIMessage):
155
- """Render a message in the TUI chat view."""
156
- if not self.tui_app:
157
- return
158
-
159
- # Handle human input requests
160
- if message.type == MessageType.HUMAN_INPUT_REQUEST:
161
- await self._handle_human_input_request(message)
162
- return
163
-
164
- # Extract group_id from message metadata (fixing the key name)
165
- group_id = message.metadata.get("message_group") if message.metadata else None
166
-
167
- # For INFO messages with Rich objects (like Markdown), preserve them for proper rendering
168
- if message.type == MessageType.INFO and hasattr(
169
- message.content, "__rich_console__"
170
- ):
171
- # Pass the Rich object directly to maintain markdown formatting
172
- self.tui_app.add_system_message_rich(
173
- message.content, message_group=group_id
174
- )
175
- return
176
-
177
- # Convert content to string for TUI display (for all other cases)
178
- if hasattr(message.content, "__rich_console__"):
179
- # For Rich objects, render to plain text using a Console
180
- string_io = StringIO()
181
- # Use markup=False to prevent interpretation of square brackets as markup
182
- temp_console = Console(
183
- file=string_io, width=80, legacy_windows=False, markup=False
184
- )
185
- temp_console.print(message.content)
186
- content_str = string_io.getvalue().rstrip("\n")
187
- else:
188
- content_str = str(message.content)
189
-
190
- # Map message types to TUI message types - ALL get group_id now
191
- if message.type in (MessageType.ERROR,):
192
- self.tui_app.add_error_message(content_str, message_group=group_id)
193
- elif message.type in (
194
- MessageType.SYSTEM,
195
- MessageType.INFO,
196
- MessageType.WARNING,
197
- MessageType.SUCCESS,
198
- ):
199
- self.tui_app.add_system_message(content_str, message_group=group_id)
200
- elif message.type == MessageType.AGENT_REASONING:
201
- # Agent reasoning messages should use the dedicated method
202
- self.tui_app.add_agent_reasoning_message(
203
- content_str, message_group=group_id
204
- )
205
- elif message.type == MessageType.PLANNED_NEXT_STEPS:
206
- # Agent reasoning messages should use the dedicated method
207
- self.tui_app.add_planned_next_steps_message(
208
- content_str, message_group=group_id
209
- )
210
- elif message.type in (
211
- MessageType.TOOL_OUTPUT,
212
- MessageType.COMMAND_OUTPUT,
213
- MessageType.AGENT_RESPONSE,
214
- ):
215
- # These are typically agent/tool outputs
216
- self.tui_app.add_agent_message(content_str, message_group=group_id)
217
- else:
218
- # Default to system message
219
- self.tui_app.add_system_message(content_str, message_group=group_id)
220
-
221
- async def _handle_human_input_request(self, message: UIMessage):
222
- """Handle a human input request in TUI mode."""
223
- try:
224
- print("[DEBUG] TUI renderer handling human input request")
225
-
226
- # Check if tui_app is available
227
- if not self.tui_app:
228
- print("[DEBUG] No tui_app available, falling back to error response")
229
- prompt_id = (
230
- message.metadata.get("prompt_id") if message.metadata else None
231
- )
232
- if prompt_id:
233
- from code_puppy.messaging import provide_prompt_response
234
-
235
- provide_prompt_response(prompt_id, "")
236
- return
237
-
238
- prompt_id = message.metadata.get("prompt_id") if message.metadata else None
239
- if not prompt_id:
240
- print("[DEBUG] No prompt_id in message metadata")
241
- self.tui_app.add_error_message("Error: Invalid human input request")
242
- return
243
-
244
- # For now, use a simple fallback instead of modal to avoid crashes
245
- print("[DEBUG] Using fallback approach - showing prompt as message")
246
- self.tui_app.add_system_message(
247
- f"[yellow]INPUT NEEDED:[/yellow] {str(message.content)}"
248
- )
249
- self.tui_app.add_system_message(
250
- "[dim]This would normally show a modal, but using fallback to prevent crashes[/dim]"
251
- )
252
-
253
- # Provide empty response for now to unblock the waiting thread
254
- from code_puppy.messaging import provide_prompt_response
255
-
256
- provide_prompt_response(prompt_id, "")
257
-
258
- except Exception as e:
259
- print(f"[DEBUG] Top-level exception in _handle_human_input_request: {e}")
260
- import traceback
261
-
262
- traceback.print_exc()
263
- # Last resort - provide empty response to prevent hanging
264
- try:
265
- prompt_id = (
266
- message.metadata.get("prompt_id") if message.metadata else None
267
- )
268
- if prompt_id:
269
- from code_puppy.messaging import provide_prompt_response
270
-
271
- provide_prompt_response(prompt_id, "")
272
- except Exception:
273
- pass # Can't do anything more
274
-
275
-
276
159
  class SynchronousInteractiveRenderer:
277
160
  """
278
161
  Synchronous renderer for interactive mode that doesn't require async.
@@ -355,10 +238,18 @@ class SynchronousInteractiveRenderer:
355
238
  # Special handling for agent responses - they'll be rendered as markdown
356
239
  style = None
357
240
  elif message.type == MessageType.SYSTEM:
358
- style = None
241
+ style = "dim"
359
242
  else:
360
243
  style = None
361
244
 
245
+ # Make version messages dim regardless of message type
246
+ if isinstance(message.content, str):
247
+ if (
248
+ "Current version:" in message.content
249
+ or "Latest version:" in message.content
250
+ ):
251
+ style = "dim"
252
+
362
253
  # Render the content
363
254
  if isinstance(message.content, str):
364
255
  if message.type == MessageType.AGENT_RESPONSE:
@@ -368,11 +259,16 @@ class SynchronousInteractiveRenderer:
368
259
  self.console.print(markdown)
369
260
  except Exception:
370
261
  # Fallback to plain text if markdown parsing fails
371
- self.console.print(message.content)
262
+ safe_content = escape_rich_markup(message.content)
263
+ self.console.print(safe_content)
372
264
  elif style:
373
- self.console.print(message.content, style=style)
265
+ # Escape Rich markup to prevent crashes from malformed tags
266
+ # in shell output or other user-provided content
267
+ safe_content = escape_rich_markup(message.content)
268
+ self.console.print(safe_content, style=style)
374
269
  else:
375
- self.console.print(message.content)
270
+ safe_content = escape_rich_markup(message.content)
271
+ self.console.print(safe_content)
376
272
  else:
377
273
  # For complex Rich objects (Tables, Markdown, Text, etc.)
378
274
  self.console.print(message.content)
@@ -391,8 +287,9 @@ class SynchronousInteractiveRenderer:
391
287
  )
392
288
  return
393
289
 
394
- # Display the prompt
395
- self.console.print(f"[bold cyan]{message.content}[/bold cyan]")
290
+ # Display the prompt - escape to prevent markup injection
291
+ safe_content = escape_rich_markup(str(message.content))
292
+ self.console.print(f"[bold cyan]{safe_content}[/bold cyan]")
396
293
  if hasattr(self.console.file, "flush"):
397
294
  self.console.file.flush()
398
295