code-puppy 0.0.135__py3-none-any.whl → 0.0.137__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 (61) hide show
  1. code_puppy/agent.py +15 -17
  2. code_puppy/agents/agent_manager.py +320 -9
  3. code_puppy/agents/base_agent.py +58 -2
  4. code_puppy/agents/runtime_manager.py +68 -42
  5. code_puppy/command_line/command_handler.py +82 -33
  6. code_puppy/command_line/mcp/__init__.py +10 -0
  7. code_puppy/command_line/mcp/add_command.py +183 -0
  8. code_puppy/command_line/mcp/base.py +35 -0
  9. code_puppy/command_line/mcp/handler.py +133 -0
  10. code_puppy/command_line/mcp/help_command.py +146 -0
  11. code_puppy/command_line/mcp/install_command.py +176 -0
  12. code_puppy/command_line/mcp/list_command.py +94 -0
  13. code_puppy/command_line/mcp/logs_command.py +126 -0
  14. code_puppy/command_line/mcp/remove_command.py +82 -0
  15. code_puppy/command_line/mcp/restart_command.py +92 -0
  16. code_puppy/command_line/mcp/search_command.py +117 -0
  17. code_puppy/command_line/mcp/start_all_command.py +126 -0
  18. code_puppy/command_line/mcp/start_command.py +98 -0
  19. code_puppy/command_line/mcp/status_command.py +185 -0
  20. code_puppy/command_line/mcp/stop_all_command.py +109 -0
  21. code_puppy/command_line/mcp/stop_command.py +79 -0
  22. code_puppy/command_line/mcp/test_command.py +107 -0
  23. code_puppy/command_line/mcp/utils.py +129 -0
  24. code_puppy/command_line/mcp/wizard_utils.py +259 -0
  25. code_puppy/command_line/model_picker_completion.py +21 -4
  26. code_puppy/command_line/prompt_toolkit_completion.py +9 -0
  27. code_puppy/config.py +5 -5
  28. code_puppy/main.py +23 -17
  29. code_puppy/mcp/__init__.py +42 -16
  30. code_puppy/mcp/async_lifecycle.py +51 -49
  31. code_puppy/mcp/blocking_startup.py +125 -113
  32. code_puppy/mcp/captured_stdio_server.py +63 -70
  33. code_puppy/mcp/circuit_breaker.py +63 -47
  34. code_puppy/mcp/config_wizard.py +169 -136
  35. code_puppy/mcp/dashboard.py +79 -71
  36. code_puppy/mcp/error_isolation.py +147 -100
  37. code_puppy/mcp/examples/retry_example.py +55 -42
  38. code_puppy/mcp/health_monitor.py +152 -141
  39. code_puppy/mcp/managed_server.py +100 -93
  40. code_puppy/mcp/manager.py +168 -156
  41. code_puppy/mcp/registry.py +148 -110
  42. code_puppy/mcp/retry_manager.py +63 -61
  43. code_puppy/mcp/server_registry_catalog.py +271 -225
  44. code_puppy/mcp/status_tracker.py +80 -80
  45. code_puppy/mcp/system_tools.py +47 -52
  46. code_puppy/messaging/message_queue.py +20 -13
  47. code_puppy/messaging/renderers.py +30 -15
  48. code_puppy/state_management.py +103 -0
  49. code_puppy/tui/app.py +64 -7
  50. code_puppy/tui/components/chat_view.py +3 -3
  51. code_puppy/tui/components/human_input_modal.py +12 -8
  52. code_puppy/tui/screens/__init__.py +2 -2
  53. code_puppy/tui/screens/mcp_install_wizard.py +208 -179
  54. code_puppy/tui/tests/test_agent_command.py +3 -3
  55. {code_puppy-0.0.135.dist-info → code_puppy-0.0.137.dist-info}/METADATA +1 -1
  56. {code_puppy-0.0.135.dist-info → code_puppy-0.0.137.dist-info}/RECORD +60 -42
  57. code_puppy/command_line/mcp_commands.py +0 -1789
  58. {code_puppy-0.0.135.data → code_puppy-0.0.137.data}/data/code_puppy/models.json +0 -0
  59. {code_puppy-0.0.135.dist-info → code_puppy-0.0.137.dist-info}/WHEEL +0 -0
  60. {code_puppy-0.0.135.dist-info → code_puppy-0.0.137.dist-info}/entry_points.txt +0 -0
  61. {code_puppy-0.0.135.dist-info → code_puppy-0.0.137.dist-info}/licenses/LICENSE +0 -0
@@ -201,45 +201,50 @@ class MessageQueue:
201
201
  """Create a human input request and return its unique ID."""
202
202
  self._prompt_id_counter += 1
203
203
  prompt_id = f"prompt_{self._prompt_id_counter}"
204
-
204
+
205
205
  # Emit the human input request message
206
206
  message = UIMessage(
207
207
  type=MessageType.HUMAN_INPUT_REQUEST,
208
208
  content=prompt_text,
209
- metadata={"prompt_id": prompt_id}
209
+ metadata={"prompt_id": prompt_id},
210
210
  )
211
211
  self.emit(message)
212
-
212
+
213
213
  return prompt_id
214
214
 
215
215
  def wait_for_prompt_response(self, prompt_id: str, timeout: float = None) -> str:
216
216
  """Wait for a response to a human input request."""
217
217
  import time
218
+
218
219
  start_time = time.time()
219
-
220
+
220
221
  # Check if we're in TUI mode - if so, try to yield control to the event loop
221
222
  from code_puppy.state_management import is_tui_mode
223
+
222
224
  sleep_interval = 0.05 if is_tui_mode() else 0.1
223
-
225
+
224
226
  # Debug logging for TUI mode
225
227
  if is_tui_mode():
226
228
  print(f"[DEBUG] Waiting for prompt response: {prompt_id}")
227
-
229
+
228
230
  while True:
229
231
  if prompt_id in self._prompt_responses:
230
232
  response = self._prompt_responses.pop(prompt_id)
231
233
  if is_tui_mode():
232
234
  print(f"[DEBUG] Got response for {prompt_id}: {response[:20]}...")
233
235
  return response
234
-
236
+
235
237
  if timeout and (time.time() - start_time) > timeout:
236
- raise TimeoutError(f"No response received for prompt {prompt_id} within {timeout} seconds")
237
-
238
+ raise TimeoutError(
239
+ f"No response received for prompt {prompt_id} within {timeout} seconds"
240
+ )
241
+
238
242
  time.sleep(sleep_interval)
239
243
 
240
244
  def provide_prompt_response(self, prompt_id: str, response: str):
241
245
  """Provide a response to a human input request."""
242
246
  from code_puppy.state_management import is_tui_mode
247
+
243
248
  if is_tui_mode():
244
249
  print(f"[DEBUG] Providing response for {prompt_id}: {response[:20]}...")
245
250
  self._prompt_responses[prompt_id] = response
@@ -343,25 +348,27 @@ def emit_divider(content: str = "[dim]" + "─" * 100 + "\n" + "[/dim]", **metad
343
348
  def emit_prompt(prompt_text: str, timeout: float = None) -> str:
344
349
  """Emit a human input request and wait for response."""
345
350
  from code_puppy.state_management import is_tui_mode
346
-
351
+
347
352
  # In interactive mode, use direct input instead of the queue system
348
353
  if not is_tui_mode():
349
354
  # Emit the prompt as a message for display
350
355
  from code_puppy.messaging import emit_info
356
+
351
357
  emit_info(f"[yellow]{prompt_text}[/yellow]")
352
-
358
+
353
359
  # Get input directly
354
360
  try:
355
361
  # Try to use rich console for better formatting
356
362
  from rich.console import Console
363
+
357
364
  console = Console()
358
365
  response = console.input("[cyan]>>> [/cyan]")
359
366
  return response
360
- except:
367
+ except Exception:
361
368
  # Fallback to basic input
362
369
  response = input(">>> ")
363
370
  return response
364
-
371
+
365
372
  # In TUI mode, use the queue system
366
373
  queue = get_global_queue()
367
374
  prompt_id = queue.create_prompt_request(prompt_text)
@@ -221,41 +221,53 @@ class TUIRenderer(MessageRenderer):
221
221
  async def _handle_human_input_request(self, message: UIMessage):
222
222
  """Handle a human input request in TUI mode."""
223
223
  try:
224
- print(f"[DEBUG] TUI renderer handling human input request")
225
-
224
+ print("[DEBUG] TUI renderer handling human input request")
225
+
226
226
  # Check if tui_app is available
227
227
  if not self.tui_app:
228
- print(f"[DEBUG] No tui_app available, falling back to error response")
229
- prompt_id = message.metadata.get("prompt_id") if message.metadata else None
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
+ )
230
232
  if prompt_id:
231
233
  from code_puppy.messaging import provide_prompt_response
234
+
232
235
  provide_prompt_response(prompt_id, "")
233
236
  return
234
-
237
+
235
238
  prompt_id = message.metadata.get("prompt_id") if message.metadata else None
236
239
  if not prompt_id:
237
- print(f"[DEBUG] No prompt_id in message metadata")
240
+ print("[DEBUG] No prompt_id in message metadata")
238
241
  self.tui_app.add_error_message("Error: Invalid human input request")
239
242
  return
240
243
 
241
244
  # For now, use a simple fallback instead of modal to avoid crashes
242
- print(f"[DEBUG] Using fallback approach - showing prompt as message")
243
- self.tui_app.add_system_message(f"[yellow]INPUT NEEDED:[/yellow] {str(message.content)}")
244
- self.tui_app.add_system_message("[dim]This would normally show a modal, but using fallback to prevent crashes[/dim]")
245
-
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
+
246
253
  # Provide empty response for now to unblock the waiting thread
247
254
  from code_puppy.messaging import provide_prompt_response
255
+
248
256
  provide_prompt_response(prompt_id, "")
249
-
257
+
250
258
  except Exception as e:
251
259
  print(f"[DEBUG] Top-level exception in _handle_human_input_request: {e}")
252
260
  import traceback
261
+
253
262
  traceback.print_exc()
254
263
  # Last resort - provide empty response to prevent hanging
255
264
  try:
256
- prompt_id = message.metadata.get("prompt_id") if message.metadata else None
265
+ prompt_id = (
266
+ message.metadata.get("prompt_id") if message.metadata else None
267
+ )
257
268
  if prompt_id:
258
269
  from code_puppy.messaging import provide_prompt_response
270
+
259
271
  provide_prompt_response(prompt_id, "")
260
272
  except Exception:
261
273
  pass # Can't do anything more
@@ -374,7 +386,9 @@ class SynchronousInteractiveRenderer:
374
386
  """Handle a human input request in interactive mode."""
375
387
  prompt_id = message.metadata.get("prompt_id") if message.metadata else None
376
388
  if not prompt_id:
377
- self.console.print("[bold red]Error: Invalid human input request[/bold red]")
389
+ self.console.print(
390
+ "[bold red]Error: Invalid human input request[/bold red]"
391
+ )
378
392
  return
379
393
 
380
394
  # Display the prompt
@@ -386,11 +400,12 @@ class SynchronousInteractiveRenderer:
386
400
  try:
387
401
  # Use basic input for now - could be enhanced with prompt_toolkit later
388
402
  response = input(">>> ")
389
-
403
+
390
404
  # Provide the response back to the queue
391
405
  from .message_queue import provide_prompt_response
406
+
392
407
  provide_prompt_response(prompt_id, response)
393
-
408
+
394
409
  except (EOFError, KeyboardInterrupt):
395
410
  # Handle Ctrl+C or Ctrl+D
396
411
  provide_prompt_response(prompt_id, "")
@@ -1,18 +1,43 @@
1
1
  from typing import Any, List
2
2
 
3
+ # Legacy global state - maintained for backward compatibility
3
4
  _message_history: List[Any] = []
4
5
  _compacted_message_hashes = set()
6
+
7
+ # Flag to control whether to use agent-specific history (True) or global history (False)
8
+ _use_agent_specific_history = True
5
9
  _tui_mode: bool = False
6
10
  _tui_app_instance: Any = None
7
11
 
8
12
 
9
13
  def add_compacted_message_hash(message_hash: str) -> None:
10
14
  """Add a message hash to the set of compacted message hashes."""
15
+ if _use_agent_specific_history:
16
+ try:
17
+ from code_puppy.agents.agent_manager import (
18
+ add_current_agent_compacted_message_hash,
19
+ )
20
+
21
+ add_current_agent_compacted_message_hash(message_hash)
22
+ return
23
+ except Exception:
24
+ # Fallback to global if agent system fails
25
+ pass
11
26
  _compacted_message_hashes.add(message_hash)
12
27
 
13
28
 
14
29
  def get_compacted_message_hashes():
15
30
  """Get the set of compacted message hashes."""
31
+ if _use_agent_specific_history:
32
+ try:
33
+ from code_puppy.agents.agent_manager import (
34
+ get_current_agent_compacted_message_hashes,
35
+ )
36
+
37
+ return get_current_agent_compacted_message_hashes()
38
+ except Exception:
39
+ # Fallback to global if agent system fails
40
+ pass
16
41
  return _compacted_message_hashes
17
42
 
18
43
 
@@ -64,27 +89,105 @@ def get_tui_mode() -> bool:
64
89
 
65
90
 
66
91
  def get_message_history() -> List[Any]:
92
+ """Get message history - uses agent-specific history if enabled, otherwise global."""
93
+ if _use_agent_specific_history:
94
+ try:
95
+ from code_puppy.agents.agent_manager import (
96
+ get_current_agent_message_history,
97
+ )
98
+
99
+ return get_current_agent_message_history()
100
+ except Exception:
101
+ # Fallback to global if agent system fails
102
+ return _message_history
67
103
  return _message_history
68
104
 
69
105
 
70
106
  def set_message_history(history: List[Any]) -> None:
107
+ """Set message history - uses agent-specific history if enabled, otherwise global."""
108
+ if _use_agent_specific_history:
109
+ try:
110
+ from code_puppy.agents.agent_manager import (
111
+ set_current_agent_message_history,
112
+ )
113
+
114
+ set_current_agent_message_history(history)
115
+ return
116
+ except Exception:
117
+ # Fallback to global if agent system fails
118
+ pass
71
119
  global _message_history
72
120
  _message_history = history
73
121
 
74
122
 
75
123
  def clear_message_history() -> None:
124
+ """Clear message history - uses agent-specific history if enabled, otherwise global."""
125
+ if _use_agent_specific_history:
126
+ try:
127
+ from code_puppy.agents.agent_manager import (
128
+ clear_current_agent_message_history,
129
+ )
130
+
131
+ clear_current_agent_message_history()
132
+ return
133
+ except Exception:
134
+ # Fallback to global if agent system fails
135
+ pass
76
136
  global _message_history
77
137
  _message_history = []
78
138
 
79
139
 
80
140
  def append_to_message_history(message: Any) -> None:
141
+ """Append to message history - uses agent-specific history if enabled, otherwise global."""
142
+ if _use_agent_specific_history:
143
+ try:
144
+ from code_puppy.agents.agent_manager import (
145
+ append_to_current_agent_message_history,
146
+ )
147
+
148
+ append_to_current_agent_message_history(message)
149
+ return
150
+ except Exception:
151
+ # Fallback to global if agent system fails
152
+ pass
81
153
  _message_history.append(message)
82
154
 
83
155
 
84
156
  def extend_message_history(history: List[Any]) -> None:
157
+ """Extend message history - uses agent-specific history if enabled, otherwise global."""
158
+ if _use_agent_specific_history:
159
+ try:
160
+ from code_puppy.agents.agent_manager import (
161
+ extend_current_agent_message_history,
162
+ )
163
+
164
+ extend_current_agent_message_history(history)
165
+ return
166
+ except Exception:
167
+ # Fallback to global if agent system fails
168
+ pass
85
169
  _message_history.extend(history)
86
170
 
87
171
 
172
+ def set_use_agent_specific_history(enabled: bool) -> None:
173
+ """Enable or disable agent-specific message history.
174
+
175
+ Args:
176
+ enabled: True to use per-agent history, False to use global history.
177
+ """
178
+ global _use_agent_specific_history
179
+ _use_agent_specific_history = enabled
180
+
181
+
182
+ def is_using_agent_specific_history() -> bool:
183
+ """Check if agent-specific message history is enabled.
184
+
185
+ Returns:
186
+ True if using per-agent history, False if using global history.
187
+ """
188
+ return _use_agent_specific_history
189
+
190
+
88
191
  def hash_message(message):
89
192
  hashable_entities = []
90
193
  for part in message.parts:
code_puppy/tui/app.py CHANGED
@@ -46,7 +46,7 @@ from .. import state_management
46
46
  # Import shared message classes
47
47
  from .messages import CommandSelected, HistoryEntrySelected
48
48
  from .models import ChatMessage, MessageType
49
- from .screens import HelpScreen, SettingsScreen, ToolsScreen, MCPInstallWizardScreen
49
+ from .screens import HelpScreen, MCPInstallWizardScreen, SettingsScreen, ToolsScreen
50
50
 
51
51
 
52
52
  class CodePuppyTUI(App):
@@ -88,6 +88,7 @@ class CodePuppyTUI(App):
88
88
  # Reactive variables for app state
89
89
  current_model = reactive("")
90
90
  puppy_name = reactive("")
91
+ current_agent = reactive("")
91
92
  agent_busy = reactive(False)
92
93
 
93
94
  def watch_agent_busy(self) -> None:
@@ -95,6 +96,35 @@ class CodePuppyTUI(App):
95
96
  # Update the submit/cancel button state when agent_busy changes
96
97
  self._update_submit_cancel_button(self.agent_busy)
97
98
 
99
+ def watch_current_agent(self) -> None:
100
+ """Watch for changes to current_agent and update title."""
101
+ self._update_title()
102
+
103
+ def _update_title(self) -> None:
104
+ """Update the application title to include current agent."""
105
+ if self.current_agent:
106
+ self.title = f"Code Puppy - {self.current_agent}"
107
+ self.sub_title = "TUI Mode"
108
+ else:
109
+ self.title = "Code Puppy - AI Code Assistant"
110
+ self.sub_title = "TUI Mode"
111
+
112
+ def _on_agent_reload(self, agent_id: str, agent_name: str) -> None:
113
+ """Callback for when agent is reloaded/changed."""
114
+ # Get the updated agent configuration
115
+ from code_puppy.agents.agent_manager import get_current_agent_config
116
+
117
+ current_agent_config = get_current_agent_config()
118
+ new_agent_display = (
119
+ current_agent_config.display_name if current_agent_config else "code-puppy"
120
+ )
121
+
122
+ # Update the reactive variable (this will trigger watch_current_agent)
123
+ self.current_agent = new_agent_display
124
+
125
+ # Add a system message to notify the user
126
+ self.add_system_message(f"🔄 Switched to agent: {new_agent_display}")
127
+
98
128
  def __init__(self, initial_command: str = None, **kwargs):
99
129
  super().__init__(**kwargs)
100
130
  self.agent_manager = None
@@ -123,10 +153,26 @@ class CodePuppyTUI(App):
123
153
 
124
154
  set_tui_app_instance(self)
125
155
 
156
+ # Register callback for agent reload events
157
+ from code_puppy.callbacks import register_callback
158
+
159
+ register_callback("agent_reload", self._on_agent_reload)
160
+
126
161
  # Load configuration
127
162
  self.current_model = get_model_name()
128
163
  self.puppy_name = get_puppy_name()
129
164
 
165
+ # Get current agent information
166
+ from code_puppy.agents.agent_manager import get_current_agent_config
167
+
168
+ current_agent_config = get_current_agent_config()
169
+ self.current_agent = (
170
+ current_agent_config.display_name if current_agent_config else "code-puppy"
171
+ )
172
+
173
+ # Initial title update
174
+ self._update_title()
175
+
130
176
  # Use runtime manager to ensure we always have the current agent
131
177
  self.agent_manager = get_runtime_agent_manager()
132
178
 
@@ -143,7 +189,9 @@ class CodePuppyTUI(App):
143
189
 
144
190
  # Get current agent and display info
145
191
  get_code_generation_agent()
146
- self.add_system_message(f"🐕 Loaded agent '{self.puppy_name}' with model '{self.current_model}'")
192
+ self.add_system_message(
193
+ f"🐕 Loaded agent '{self.puppy_name}' with model '{self.current_model}'"
194
+ )
147
195
 
148
196
  # Start the message renderer EARLY to catch startup messages
149
197
  # Using call_after_refresh to start it as soon as possible after mount
@@ -632,16 +680,20 @@ class CodePuppyTUI(App):
632
680
 
633
681
  def action_open_mcp_wizard(self) -> None:
634
682
  """Open the MCP Install Wizard."""
635
-
683
+
636
684
  def handle_wizard_result(result):
637
685
  if result and result.get("success"):
638
686
  # Show success message
639
- self.add_system_message(result.get("message", "MCP server installed successfully"))
640
-
687
+ self.add_system_message(
688
+ result.get("message", "MCP server installed successfully")
689
+ )
690
+
641
691
  # If a server was installed, suggest starting it
642
692
  if result.get("server_name"):
643
693
  server_name = result["server_name"]
644
- self.add_system_message(f"💡 Use '/mcp start {server_name}' to start the server")
694
+ self.add_system_message(
695
+ f"💡 Use '/mcp start {server_name}' to start the server"
696
+ )
645
697
  elif (
646
698
  result
647
699
  and not result.get("success")
@@ -649,7 +701,7 @@ class CodePuppyTUI(App):
649
701
  ):
650
702
  # Show error message (but not for cancellation)
651
703
  self.add_error_message(result.get("message", "MCP installation failed"))
652
-
704
+
653
705
  self.push_screen(MCPInstallWizardScreen(), handle_wizard_result)
654
706
 
655
707
  def process_initial_command(self) -> None:
@@ -905,6 +957,11 @@ class CodePuppyTUI(App):
905
957
  async def on_unmount(self):
906
958
  """Clean up when the app is unmounted."""
907
959
  try:
960
+ # Unregister the agent reload callback
961
+ from code_puppy.callbacks import unregister_callback
962
+
963
+ unregister_callback("agent_reload", self._on_agent_reload)
964
+
908
965
  await self.stop_message_renderer()
909
966
  except Exception as e:
910
967
  # Log unmount errors but don't crash during cleanup
@@ -11,7 +11,7 @@ from rich.syntax import Syntax
11
11
  from rich.text import Text
12
12
  from textual import on
13
13
  from textual.containers import Vertical, VerticalScroll
14
- from textual.widgets import Static, Collapsible
14
+ from textual.widgets import Static
15
15
 
16
16
  from ..models import ChatMessage, MessageType
17
17
  from .copy_button import CopyButton
@@ -342,14 +342,14 @@ class ChatView(VerticalScroll):
342
342
 
343
343
  if message.type == MessageType.USER:
344
344
  # Add user indicator and make it stand out
345
- content_lines = message.content.split('\n')
345
+ content_lines = message.content.split("\n")
346
346
  if len(content_lines) > 1:
347
347
  # Multi-line user message
348
348
  formatted_content = f"╔══ USER ══╗\n{message.content}\n╚══════════╝"
349
349
  else:
350
350
  # Single line user message
351
351
  formatted_content = f"▶ USER: {message.content}"
352
-
352
+
353
353
  message_widget = Static(Text(formatted_content), classes=css_class)
354
354
  # User messages are not collapsible - mount directly
355
355
  self.mount(message_widget)
@@ -7,7 +7,7 @@ from textual.app import ComposeResult
7
7
  from textual.containers import Container, Horizontal
8
8
  from textual.events import Key
9
9
  from textual.screen import ModalScreen
10
- from textual.widgets import Button, Label, Static, TextArea
10
+ from textual.widgets import Button, Static, TextArea
11
11
 
12
12
  try:
13
13
  from .custom_widgets import CustomTextArea
@@ -109,13 +109,14 @@ class HumanInputModal(ModalScreen):
109
109
  def on_mount(self) -> None:
110
110
  """Focus the input field when modal opens."""
111
111
  try:
112
- print(f"[DEBUG] Modal on_mount called")
112
+ print("[DEBUG] Modal on_mount called")
113
113
  input_field = self.query_one("#response-input", CustomTextArea)
114
114
  input_field.focus()
115
- print(f"[DEBUG] Modal input field focused")
115
+ print("[DEBUG] Modal input field focused")
116
116
  except Exception as e:
117
117
  print(f"[DEBUG] Modal on_mount exception: {e}")
118
118
  import traceback
119
+
119
120
  traceback.print_exc()
120
121
 
121
122
  @on(Button.Pressed, "#submit-button")
@@ -123,7 +124,7 @@ class HumanInputModal(ModalScreen):
123
124
  """Handle submit button click."""
124
125
  self._submit_response()
125
126
 
126
- @on(Button.Pressed, "#cancel-button")
127
+ @on(Button.Pressed, "#cancel-button")
127
128
  def on_cancel_clicked(self) -> None:
128
129
  """Handle cancel button click."""
129
130
  self._cancel_response()
@@ -149,23 +150,26 @@ class HumanInputModal(ModalScreen):
149
150
  input_field = self.query_one("#response-input", CustomTextArea)
150
151
  self.response = input_field.text.strip()
151
152
  print(f"[DEBUG] Modal submitting response: {self.response[:20]}...")
152
-
153
+
153
154
  # Provide the response back to the message queue
154
155
  from code_puppy.messaging import provide_prompt_response
156
+
155
157
  provide_prompt_response(self.prompt_id, self.response)
156
-
158
+
157
159
  # Close the modal using the same method as other modals
158
160
  self.app.pop_screen()
159
161
  except Exception as e:
160
162
  print(f"[DEBUG] Modal error during submit: {e}")
161
163
  # If something goes wrong, provide empty response
162
164
  from code_puppy.messaging import provide_prompt_response
165
+
163
166
  provide_prompt_response(self.prompt_id, "")
164
167
  self.app.pop_screen()
165
168
 
166
169
  def _cancel_response(self) -> None:
167
170
  """Cancel the input request."""
168
- print(f"[DEBUG] Modal cancelling response")
171
+ print("[DEBUG] Modal cancelling response")
169
172
  from code_puppy.messaging import provide_prompt_response
173
+
170
174
  provide_prompt_response(self.prompt_id, "")
171
- self.app.pop_screen()
175
+ self.app.pop_screen()
@@ -3,13 +3,13 @@ TUI screens package.
3
3
  """
4
4
 
5
5
  from .help import HelpScreen
6
+ from .mcp_install_wizard import MCPInstallWizardScreen
6
7
  from .settings import SettingsScreen
7
8
  from .tools import ToolsScreen
8
- from .mcp_install_wizard import MCPInstallWizardScreen
9
9
 
10
10
  __all__ = [
11
11
  "HelpScreen",
12
- "SettingsScreen",
12
+ "SettingsScreen",
13
13
  "ToolsScreen",
14
14
  "MCPInstallWizardScreen",
15
15
  ]