code-puppy 0.0.130__py3-none-any.whl → 0.0.132__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.
- code_puppy/command_line/mcp_commands.py +591 -106
- code_puppy/mcp/blocking_startup.py +404 -0
- code_puppy/mcp/captured_stdio_server.py +282 -0
- code_puppy/mcp/config_wizard.py +151 -117
- code_puppy/mcp/managed_server.py +55 -1
- code_puppy/mcp/server_registry_catalog.py +346 -46
- code_puppy/mcp/system_tools.py +214 -0
- code_puppy/messaging/__init__.py +4 -0
- code_puppy/messaging/message_queue.py +86 -0
- code_puppy/messaging/renderers.py +94 -0
- code_puppy/tui/app.py +24 -1
- code_puppy/tui/components/chat_view.py +33 -18
- code_puppy/tui/components/human_input_modal.py +171 -0
- code_puppy/tui/screens/__init__.py +3 -1
- code_puppy/tui/screens/mcp_install_wizard.py +593 -0
- {code_puppy-0.0.130.dist-info → code_puppy-0.0.132.dist-info}/METADATA +1 -1
- {code_puppy-0.0.130.dist-info → code_puppy-0.0.132.dist-info}/RECORD +21 -16
- {code_puppy-0.0.130.data → code_puppy-0.0.132.data}/data/code_puppy/models.json +0 -0
- {code_puppy-0.0.130.dist-info → code_puppy-0.0.132.dist-info}/WHEEL +0 -0
- {code_puppy-0.0.130.dist-info → code_puppy-0.0.132.dist-info}/entry_points.txt +0 -0
- {code_puppy-0.0.130.dist-info → code_puppy-0.0.132.dist-info}/licenses/LICENSE +0 -0
|
@@ -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
|
]
|