code-puppy 0.0.130__py3-none-any.whl → 0.0.131__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.
@@ -0,0 +1,171 @@
1
+ """
2
+ Modal component for human input requests.
3
+ """
4
+
5
+ from textual import on
6
+ from textual.app import ComposeResult
7
+ from textual.containers import Container, Horizontal
8
+ from textual.events import Key
9
+ from textual.screen import ModalScreen
10
+ from textual.widgets import Button, Label, Static, TextArea
11
+
12
+ try:
13
+ from .custom_widgets import CustomTextArea
14
+ except ImportError:
15
+ # Fallback to regular TextArea if CustomTextArea isn't available
16
+ CustomTextArea = TextArea
17
+
18
+
19
+ class HumanInputModal(ModalScreen):
20
+ """Modal for requesting human input."""
21
+
22
+ def __init__(self, prompt_text: str, prompt_id: str, **kwargs):
23
+ """Initialize the modal with prompt information.
24
+
25
+ Args:
26
+ prompt_text: The prompt to display to the user
27
+ prompt_id: Unique identifier for this prompt request
28
+ **kwargs: Additional arguments to pass to the parent class
29
+ """
30
+ super().__init__(**kwargs)
31
+ self.prompt_text = prompt_text
32
+ self.prompt_id = prompt_id
33
+ self.response = ""
34
+ print(f"[DEBUG] Created HumanInputModal for prompt_id: {prompt_id}")
35
+
36
+ DEFAULT_CSS = """
37
+ HumanInputModal {
38
+ align: center middle;
39
+ }
40
+
41
+ #modal-container {
42
+ width: 80%;
43
+ max-width: 80;
44
+ height: 16;
45
+ min-height: 12;
46
+ background: $surface;
47
+ border: solid $primary;
48
+ padding: 1 2;
49
+ layout: vertical;
50
+ }
51
+
52
+ #prompt-display {
53
+ width: 100%;
54
+ margin-bottom: 1;
55
+ color: $text;
56
+ text-align: left;
57
+ height: auto;
58
+ max-height: 6;
59
+ overflow: auto;
60
+ }
61
+
62
+ #input-container {
63
+ width: 100%;
64
+ height: 4;
65
+ margin-bottom: 1;
66
+ }
67
+
68
+ #response-input {
69
+ width: 100%;
70
+ height: 4;
71
+ border: solid $primary;
72
+ background: $surface-darken-1;
73
+ }
74
+
75
+ #button-container {
76
+ width: 100%;
77
+ height: 3;
78
+ align: center bottom;
79
+ layout: horizontal;
80
+ }
81
+
82
+ #submit-button, #cancel-button {
83
+ width: auto;
84
+ height: 3;
85
+ margin: 0 1;
86
+ min-width: 10;
87
+ }
88
+
89
+ #hint-text {
90
+ width: 100%;
91
+ color: $text-muted;
92
+ text-align: center;
93
+ height: 1;
94
+ margin-top: 1;
95
+ }
96
+ """
97
+
98
+ def compose(self) -> ComposeResult:
99
+ """Create the modal layout."""
100
+ with Container(id="modal-container"):
101
+ yield Static(self.prompt_text, id="prompt-display")
102
+ with Container(id="input-container"):
103
+ yield CustomTextArea("", id="response-input")
104
+ with Horizontal(id="button-container"):
105
+ yield Button("Submit", id="submit-button", variant="primary")
106
+ yield Button("Cancel", id="cancel-button", variant="default")
107
+ yield Static("Enter to submit • Escape to cancel", id="hint-text")
108
+
109
+ def on_mount(self) -> None:
110
+ """Focus the input field when modal opens."""
111
+ try:
112
+ print(f"[DEBUG] Modal on_mount called")
113
+ input_field = self.query_one("#response-input", CustomTextArea)
114
+ input_field.focus()
115
+ print(f"[DEBUG] Modal input field focused")
116
+ except Exception as e:
117
+ print(f"[DEBUG] Modal on_mount exception: {e}")
118
+ import traceback
119
+ traceback.print_exc()
120
+
121
+ @on(Button.Pressed, "#submit-button")
122
+ def on_submit_clicked(self) -> None:
123
+ """Handle submit button click."""
124
+ self._submit_response()
125
+
126
+ @on(Button.Pressed, "#cancel-button")
127
+ def on_cancel_clicked(self) -> None:
128
+ """Handle cancel button click."""
129
+ self._cancel_response()
130
+
131
+ def on_key(self, event: Key) -> None:
132
+ """Handle key events."""
133
+ if event.key == "escape":
134
+ self._cancel_response()
135
+ event.prevent_default()
136
+ elif event.key == "enter":
137
+ # Check if we're in the text area and it's not multi-line
138
+ try:
139
+ input_field = self.query_one("#response-input", CustomTextArea)
140
+ if input_field.has_focus and "\n" not in input_field.text:
141
+ self._submit_response()
142
+ event.prevent_default()
143
+ except Exception:
144
+ pass
145
+
146
+ def _submit_response(self) -> None:
147
+ """Submit the user's response."""
148
+ try:
149
+ input_field = self.query_one("#response-input", CustomTextArea)
150
+ self.response = input_field.text.strip()
151
+ print(f"[DEBUG] Modal submitting response: {self.response[:20]}...")
152
+
153
+ # Provide the response back to the message queue
154
+ from code_puppy.messaging import provide_prompt_response
155
+ provide_prompt_response(self.prompt_id, self.response)
156
+
157
+ # Close the modal using the same method as other modals
158
+ self.app.pop_screen()
159
+ except Exception as e:
160
+ print(f"[DEBUG] Modal error during submit: {e}")
161
+ # If something goes wrong, provide empty response
162
+ from code_puppy.messaging import provide_prompt_response
163
+ provide_prompt_response(self.prompt_id, "")
164
+ self.app.pop_screen()
165
+
166
+ def _cancel_response(self) -> None:
167
+ """Cancel the input request."""
168
+ print(f"[DEBUG] Modal cancelling response")
169
+ from code_puppy.messaging import provide_prompt_response
170
+ provide_prompt_response(self.prompt_id, "")
171
+ self.app.pop_screen()
@@ -5,9 +5,11 @@ TUI screens package.
5
5
  from .help import HelpScreen
6
6
  from .settings import SettingsScreen
7
7
  from .tools import ToolsScreen
8
+ from .mcp_install_wizard import MCPInstallWizardScreen
8
9
 
9
10
  __all__ = [
10
11
  "HelpScreen",
11
- "SettingsScreen",
12
+ "SettingsScreen",
12
13
  "ToolsScreen",
14
+ "MCPInstallWizardScreen",
13
15
  ]