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,593 @@
1
+ """
2
+ MCP Install Wizard Screen - TUI interface for installing MCP servers.
3
+ """
4
+
5
+ import json
6
+ import os
7
+ from typing import Dict, List, Optional
8
+
9
+ from textual import on
10
+ from textual.app import ComposeResult
11
+ from textual.containers import Container, Horizontal, Vertical
12
+ from textual.screen import ModalScreen
13
+ from textual.widgets import (
14
+ Button,
15
+ Input,
16
+ Label,
17
+ ListItem,
18
+ ListView,
19
+ Static,
20
+ Select,
21
+ TextArea
22
+ )
23
+
24
+ from code_puppy.messaging import emit_info
25
+
26
+
27
+ class MCPInstallWizardScreen(ModalScreen):
28
+ """Modal screen for installing MCP servers with full wizard support."""
29
+
30
+ def __init__(self, **kwargs):
31
+ super().__init__(**kwargs)
32
+ self.selected_server = None
33
+ self.env_vars = {}
34
+ self.step = "search" # search -> configure -> install
35
+ self.search_counter = 0 # Counter to ensure unique IDs
36
+
37
+ DEFAULT_CSS = """
38
+ MCPInstallWizardScreen {
39
+ align: center middle;
40
+ }
41
+
42
+ #wizard-container {
43
+ width: 90%;
44
+ max-width: 100;
45
+ height: 80%;
46
+ max-height: 40;
47
+ background: $surface;
48
+ border: solid $primary;
49
+ padding: 1 2;
50
+ layout: vertical;
51
+ }
52
+
53
+ #wizard-header {
54
+ width: 100%;
55
+ height: 3;
56
+ text-align: center;
57
+ color: $accent;
58
+ margin-bottom: 1;
59
+ }
60
+
61
+ #search-container {
62
+ width: 100%;
63
+ height: auto;
64
+ layout: vertical;
65
+ }
66
+
67
+ #search-input {
68
+ width: 100%;
69
+ margin-bottom: 1;
70
+ border: solid $primary;
71
+ }
72
+
73
+ #results-list {
74
+ width: 100%;
75
+ height: 20;
76
+ border: solid $primary;
77
+ margin-bottom: 1;
78
+ }
79
+
80
+ #config-container {
81
+ width: 100%;
82
+ height: 1fr;
83
+ layout: vertical;
84
+ }
85
+
86
+ #server-info {
87
+ width: 100%;
88
+ height: auto;
89
+ max-height: 8;
90
+ border: solid $success;
91
+ padding: 1;
92
+ margin-bottom: 1;
93
+ background: $surface-lighten-1;
94
+ }
95
+
96
+ #env-vars-container {
97
+ width: 100%;
98
+ height: 1fr;
99
+ layout: vertical;
100
+ border: solid $warning;
101
+ padding: 1;
102
+ margin-bottom: 1;
103
+ overflow-y: scroll;
104
+ }
105
+
106
+ #env-var-input {
107
+ width: 100%;
108
+ margin-bottom: 1;
109
+ border: solid $primary;
110
+ }
111
+
112
+ #button-container {
113
+ width: 100%;
114
+ height: 4;
115
+ layout: horizontal;
116
+ align: center bottom;
117
+ }
118
+
119
+ #back-button, #next-button, #install-button, #cancel-button {
120
+ width: auto;
121
+ height: 3;
122
+ margin: 0 1;
123
+ min-width: 12;
124
+ }
125
+
126
+ .env-var-row {
127
+ width: 100%;
128
+ layout: horizontal;
129
+ height: 3;
130
+ margin-bottom: 1;
131
+ }
132
+
133
+ .env-var-label {
134
+ width: 1fr;
135
+ padding: 1 0;
136
+ }
137
+
138
+ .env-var-input {
139
+ width: 2fr;
140
+ border: solid $primary;
141
+ }
142
+ """
143
+
144
+ def compose(self) -> ComposeResult:
145
+ """Create the wizard layout."""
146
+ with Container(id="wizard-container"):
147
+ yield Static("🔌 MCP Server Install Wizard", id="wizard-header")
148
+
149
+ # Step 1: Search and select server
150
+ with Container(id="search-container"):
151
+ yield Input(placeholder="Search MCP servers (e.g. 'github', 'postgres')...", id="search-input")
152
+ yield ListView(id="results-list")
153
+
154
+ # Step 2: Configure server (hidden initially)
155
+ with Container(id="config-container"):
156
+ yield Static("Server Configuration", id="config-header")
157
+ yield Container(id="server-info")
158
+ yield Container(id="env-vars-container")
159
+
160
+ # Navigation buttons
161
+ with Horizontal(id="button-container"):
162
+ yield Button("Cancel", id="cancel-button", variant="default")
163
+ yield Button("Back", id="back-button", variant="default")
164
+ yield Button("Next", id="next-button", variant="primary")
165
+ yield Button("Install", id="install-button", variant="success")
166
+
167
+ def on_mount(self) -> None:
168
+ """Initialize the wizard."""
169
+ self._show_search_step()
170
+ self._load_popular_servers()
171
+
172
+ # Focus the search input
173
+ search_input = self.query_one("#search-input", Input)
174
+ search_input.focus()
175
+
176
+ def _show_search_step(self) -> None:
177
+ """Show the search step."""
178
+ self.step = "search"
179
+ self.query_one("#search-container").display = True
180
+ self.query_one("#config-container").display = False
181
+
182
+ self.query_one("#back-button").display = False
183
+ self.query_one("#next-button").display = True
184
+ self.query_one("#install-button").display = False
185
+
186
+ def _show_config_step(self) -> None:
187
+ """Show the configuration step."""
188
+ self.step = "configure"
189
+ self.query_one("#search-container").display = False
190
+ self.query_one("#config-container").display = True
191
+
192
+ self.query_one("#back-button").display = True
193
+ self.query_one("#next-button").display = False
194
+ self.query_one("#install-button").display = True
195
+
196
+ self._setup_server_config()
197
+
198
+ def _load_popular_servers(self) -> None:
199
+ """Load popular servers into the list."""
200
+ self.search_counter += 1
201
+ counter = self.search_counter
202
+
203
+ try:
204
+ from code_puppy.mcp.server_registry_catalog import catalog
205
+ servers = catalog.get_popular(10)
206
+
207
+ results_list = self.query_one("#results-list", ListView)
208
+ # Force clear by removing all children
209
+ results_list.remove_children()
210
+
211
+ if servers:
212
+ for i, server in enumerate(servers):
213
+ indicators = []
214
+ if server.verified:
215
+ indicators.append("✓")
216
+ if server.popular:
217
+ indicators.append("⭐")
218
+
219
+ display_name = f"{server.display_name} {''.join(indicators)}"
220
+ description = server.description[:60] + "..." if len(server.description) > 60 else server.description
221
+
222
+ item_text = f"{display_name}\n[dim]{description}[/dim]"
223
+ # Use counter to ensure globally unique IDs
224
+ item = ListItem(Static(item_text), id=f"item-{counter}-{i}")
225
+ item.server_data = server
226
+ results_list.append(item)
227
+ else:
228
+ no_servers_item = ListItem(Static("No servers found"), id=f"no-results-{counter}")
229
+ results_list.append(no_servers_item)
230
+
231
+ except ImportError:
232
+ results_list = self.query_one("#results-list", ListView)
233
+ results_list.remove_children()
234
+ error_item = ListItem(Static("[red]Server registry not available[/red]"), id=f"error-{counter}")
235
+ results_list.append(error_item)
236
+
237
+ @on(Input.Changed, "#search-input")
238
+ def on_search_changed(self, event: Input.Changed) -> None:
239
+ """Handle search input changes."""
240
+ query = event.value.strip()
241
+
242
+ if not query:
243
+ self._load_popular_servers()
244
+ return
245
+
246
+ self.search_counter += 1
247
+ counter = self.search_counter
248
+
249
+ try:
250
+ from code_puppy.mcp.server_registry_catalog import catalog
251
+ servers = catalog.search(query)
252
+
253
+ results_list = self.query_one("#results-list", ListView)
254
+ # Force clear by removing all children
255
+ results_list.remove_children()
256
+
257
+ if servers:
258
+ for i, server in enumerate(servers[:15]): # Limit results
259
+ indicators = []
260
+ if server.verified:
261
+ indicators.append("✓")
262
+ if server.popular:
263
+ indicators.append("⭐")
264
+
265
+ display_name = f"{server.display_name} {''.join(indicators)}"
266
+ description = server.description[:60] + "..." if len(server.description) > 60 else server.description
267
+
268
+ item_text = f"{display_name}\n[dim]{description}[/dim]"
269
+ # Use counter to ensure globally unique IDs
270
+ item = ListItem(Static(item_text), id=f"item-{counter}-{i}")
271
+ item.server_data = server
272
+ results_list.append(item)
273
+ else:
274
+ no_results_item = ListItem(Static(f"No servers found for '{query}'"), id=f"no-results-{counter}")
275
+ results_list.append(no_results_item)
276
+
277
+ except ImportError:
278
+ results_list = self.query_one("#results-list", ListView)
279
+ results_list.remove_children()
280
+ error_item = ListItem(Static("[red]Server registry not available[/red]"), id=f"error-{counter}")
281
+ results_list.append(error_item)
282
+
283
+ @on(ListView.Selected, "#results-list")
284
+ def on_server_selected(self, event: ListView.Selected) -> None:
285
+ """Handle server selection."""
286
+ if hasattr(event.item, 'server_data'):
287
+ self.selected_server = event.item.server_data
288
+
289
+ @on(Button.Pressed, "#next-button")
290
+ def on_next_clicked(self) -> None:
291
+ """Handle next button click."""
292
+ if self.step == "search":
293
+ if self.selected_server:
294
+ self._show_config_step()
295
+ else:
296
+ # Show error - no server selected
297
+ pass
298
+
299
+ @on(Button.Pressed, "#back-button")
300
+ def on_back_clicked(self) -> None:
301
+ """Handle back button click."""
302
+ if self.step == "configure":
303
+ self._show_search_step()
304
+
305
+ @on(Button.Pressed, "#install-button")
306
+ def on_install_clicked(self) -> None:
307
+ """Handle install button click."""
308
+ if self.step == "configure" and self.selected_server:
309
+ self._install_server()
310
+
311
+ @on(Button.Pressed, "#cancel-button")
312
+ def on_cancel_clicked(self) -> None:
313
+ """Handle cancel button click."""
314
+ self.dismiss({"success": False, "message": "Installation cancelled"})
315
+
316
+ def _setup_server_config(self) -> None:
317
+ """Setup the server configuration step."""
318
+ if not self.selected_server:
319
+ return
320
+
321
+ # Show server info
322
+ server_info = self.query_one("#server-info", Container)
323
+ server_info.remove_children()
324
+
325
+ info_text = f"""[bold]{self.selected_server.display_name}[/bold]
326
+ {self.selected_server.description}
327
+
328
+ [yellow]Category:[/yellow] {self.selected_server.category}
329
+ [yellow]Type:[/yellow] {getattr(self.selected_server, 'type', 'stdio')}"""
330
+
331
+ # Show requirements summary
332
+ requirements = self.selected_server.get_requirements()
333
+ req_items = []
334
+ if requirements.required_tools:
335
+ req_items.append(f"Tools: {', '.join(requirements.required_tools)}")
336
+ if requirements.environment_vars:
337
+ req_items.append(f"Env vars: {len(requirements.environment_vars)}")
338
+ if requirements.command_line_args:
339
+ req_items.append(f"Config args: {len(requirements.command_line_args)}")
340
+
341
+ if req_items:
342
+ info_text += f"\n[yellow]Requirements:[/yellow] {' | '.join(req_items)}"
343
+
344
+ server_info.mount(Static(info_text))
345
+
346
+ # Setup configuration requirements
347
+ config_container = self.query_one("#env-vars-container", Container)
348
+ config_container.remove_children()
349
+ config_container.mount(Static("[bold]Server Configuration:[/bold]"))
350
+
351
+ # Add server name input
352
+ config_container.mount(Static("\n[bold blue]Server Name:[/bold blue]"))
353
+ name_row = Horizontal(classes="env-var-row")
354
+ config_container.mount(name_row)
355
+ name_row.mount(Static("🏷️ Custom name:", classes="env-var-label"))
356
+ name_input = Input(
357
+ placeholder=f"Default: {self.selected_server.name}",
358
+ value=self.selected_server.name,
359
+ classes="env-var-input",
360
+ id="server-name-input"
361
+ )
362
+ name_row.mount(name_input)
363
+
364
+ try:
365
+ # Check system requirements first
366
+ self._setup_system_requirements(config_container)
367
+
368
+ # Setup environment variables
369
+ self._setup_environment_variables(config_container)
370
+
371
+ # Setup command line arguments
372
+ self._setup_command_line_args(config_container)
373
+
374
+ # Show package dependencies info
375
+ self._setup_package_dependencies(config_container)
376
+
377
+ except Exception as e:
378
+ config_container.mount(Static(f"[red]Error loading configuration: {e}[/red]"))
379
+
380
+ def _setup_system_requirements(self, parent: Container) -> None:
381
+ """Setup system requirements validation."""
382
+ required_tools = self.selected_server.get_required_tools()
383
+
384
+ if not required_tools:
385
+ return
386
+
387
+ parent.mount(Static("\n[bold cyan]System Tools:[/bold cyan]"))
388
+
389
+ # Import here to avoid circular imports
390
+ from code_puppy.mcp.system_tools import detector
391
+
392
+ tool_status = detector.detect_tools(required_tools)
393
+
394
+ for tool_name, tool_info in tool_status.items():
395
+ if tool_info.available:
396
+ status_text = f"✅ {tool_name}"
397
+ if tool_info.version:
398
+ status_text += f" ({tool_info.version})"
399
+ parent.mount(Static(status_text))
400
+ else:
401
+ status_text = f"❌ {tool_name} - {tool_info.error or 'Not found'}"
402
+ parent.mount(Static(f"[red]{status_text}[/red]"))
403
+
404
+ # Show installation suggestions
405
+ suggestions = detector.get_installation_suggestions(tool_name)
406
+ if suggestions:
407
+ parent.mount(Static(f"[dim] Install: {suggestions[0]}[/dim]"))
408
+
409
+ def _setup_environment_variables(self, parent: Container) -> None:
410
+ """Setup environment variables inputs."""
411
+ env_vars = self.selected_server.get_environment_vars()
412
+
413
+ if not env_vars:
414
+ return
415
+
416
+ parent.mount(Static("\n[bold yellow]Environment Variables:[/bold yellow]"))
417
+
418
+ for var in env_vars:
419
+ # Check if already set
420
+ import os
421
+ current_value = os.environ.get(var, "")
422
+
423
+ row_container = Horizontal(classes="env-var-row")
424
+ parent.mount(row_container)
425
+
426
+ status_indicator = "✅" if current_value else "📝"
427
+ row_container.mount(Static(f"{status_indicator} {var}:", classes="env-var-label"))
428
+
429
+ env_input = Input(
430
+ placeholder=f"Enter {var} value..." if not current_value else "Already set",
431
+ value=current_value,
432
+ classes="env-var-input",
433
+ id=f"env-{var}"
434
+ )
435
+ row_container.mount(env_input)
436
+
437
+ def _setup_command_line_args(self, parent: Container) -> None:
438
+ """Setup command line arguments inputs."""
439
+ cmd_args = self.selected_server.get_command_line_args()
440
+
441
+ if not cmd_args:
442
+ return
443
+
444
+ parent.mount(Static("\n[bold green]Command Line Arguments:[/bold green]"))
445
+
446
+ for arg_config in cmd_args:
447
+ name = arg_config.get("name", "")
448
+ prompt = arg_config.get("prompt", name)
449
+ default = arg_config.get("default", "")
450
+ required = arg_config.get("required", True)
451
+
452
+ row_container = Horizontal(classes="env-var-row")
453
+ parent.mount(row_container)
454
+
455
+ indicator = "⚡" if required else "🔧"
456
+ label_text = f"{indicator} {prompt}:"
457
+ if not required:
458
+ label_text += " (optional)"
459
+
460
+ row_container.mount(Static(label_text, classes="env-var-label"))
461
+
462
+ arg_input = Input(
463
+ placeholder=f"Default: {default}" if default else f"Enter {name}...",
464
+ value=default,
465
+ classes="env-var-input",
466
+ id=f"arg-{name}"
467
+ )
468
+ row_container.mount(arg_input)
469
+
470
+ def _setup_package_dependencies(self, parent: Container) -> None:
471
+ """Setup package dependencies information."""
472
+ packages = self.selected_server.get_package_dependencies()
473
+
474
+ if not packages:
475
+ return
476
+
477
+ parent.mount(Static("\n[bold magenta]Package Dependencies:[/bold magenta]"))
478
+
479
+ # Import here to avoid circular imports
480
+ from code_puppy.mcp.system_tools import detector
481
+
482
+ package_status = detector.check_package_dependencies(packages)
483
+
484
+ for package, available in package_status.items():
485
+ if available:
486
+ parent.mount(Static(f"✅ {package} (installed)"))
487
+ else:
488
+ parent.mount(Static(f"[yellow]📦 {package} (will be installed automatically)[/yellow]"))
489
+
490
+ def _install_server(self) -> None:
491
+ """Install the selected server with configuration."""
492
+ if not self.selected_server:
493
+ return
494
+
495
+ try:
496
+ # Collect configuration inputs
497
+ env_vars = {}
498
+ cmd_args = {}
499
+ server_name = self.selected_server.name # Default fallback
500
+
501
+ all_inputs = self.query(Input)
502
+
503
+ for input_widget in all_inputs:
504
+ if input_widget.id == "server-name-input":
505
+ custom_name = input_widget.value.strip()
506
+ if custom_name:
507
+ server_name = custom_name
508
+ elif input_widget.id and input_widget.id.startswith("env-"):
509
+ var_name = input_widget.id[4:] # Remove "env-" prefix
510
+ value = input_widget.value.strip()
511
+ if value:
512
+ env_vars[var_name] = value
513
+ elif input_widget.id and input_widget.id.startswith("arg-"):
514
+ arg_name = input_widget.id[4:] # Remove "arg-" prefix
515
+ value = input_widget.value.strip()
516
+ if value:
517
+ cmd_args[arg_name] = value
518
+
519
+ # Set environment variables in the current environment
520
+ for var, value in env_vars.items():
521
+ os.environ[var] = value
522
+
523
+ # Get server config with command line argument overrides
524
+ config_dict = self.selected_server.to_server_config(server_name, **cmd_args)
525
+
526
+ # Update the config with actual environment variable values
527
+ if 'env' in config_dict:
528
+ for env_key, env_value in config_dict['env'].items():
529
+ # If it's a placeholder like $GITHUB_TOKEN, replace with actual value
530
+ if env_value.startswith('$'):
531
+ var_name = env_value[1:] # Remove the $
532
+ if var_name in env_vars:
533
+ config_dict['env'][env_key] = env_vars[var_name]
534
+
535
+ # Create and register the server
536
+ from code_puppy.mcp import ServerConfig
537
+ from code_puppy.mcp.manager import get_mcp_manager
538
+
539
+ server_config = ServerConfig(
540
+ id=server_name,
541
+ name=server_name,
542
+ type=config_dict.pop('type'),
543
+ enabled=True,
544
+ config=config_dict
545
+ )
546
+
547
+ manager = get_mcp_manager()
548
+ server_id = manager.register_server(server_config)
549
+
550
+ if server_id:
551
+ # Save to mcp_servers.json
552
+ from code_puppy.config import MCP_SERVERS_FILE
553
+
554
+ if os.path.exists(MCP_SERVERS_FILE):
555
+ with open(MCP_SERVERS_FILE, 'r') as f:
556
+ data = json.load(f)
557
+ servers = data.get("mcp_servers", {})
558
+ else:
559
+ servers = {}
560
+ data = {"mcp_servers": servers}
561
+
562
+ servers[server_name] = config_dict
563
+ servers[server_name]['type'] = server_config.type
564
+
565
+ os.makedirs(os.path.dirname(MCP_SERVERS_FILE), exist_ok=True)
566
+ with open(MCP_SERVERS_FILE, 'w') as f:
567
+ json.dump(data, f, indent=2)
568
+
569
+ # Reload MCP servers
570
+ from code_puppy.agent import reload_mcp_servers
571
+ reload_mcp_servers()
572
+
573
+ self.dismiss({
574
+ "success": True,
575
+ "message": f"Successfully installed '{server_name}' from {self.selected_server.display_name}",
576
+ "server_name": server_name
577
+ })
578
+ else:
579
+ self.dismiss({
580
+ "success": False,
581
+ "message": "Failed to register server"
582
+ })
583
+
584
+ except Exception as e:
585
+ self.dismiss({
586
+ "success": False,
587
+ "message": f"Installation failed: {str(e)}"
588
+ })
589
+
590
+ def on_key(self, event) -> None:
591
+ """Handle key events."""
592
+ if event.key == "escape":
593
+ self.on_cancel_clicked()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-puppy
3
- Version: 0.0.130
3
+ Version: 0.0.131
4
4
  Summary: Code generation agent
5
5
  Project-URL: repository, https://github.com/mpfaffenberger/code_puppy
6
6
  Project-URL: HomePage, https://github.com/mpfaffenberger/code_puppy
@@ -25,7 +25,7 @@ code_puppy/command_line/__init__.py,sha256=y7WeRemfYppk8KVbCGeAIiTuiOszIURCDjOMZ
25
25
  code_puppy/command_line/command_handler.py,sha256=IhDaDa0GmpW0BCFfmkgpL_6iQBJlXEKQC9SDmpj_XeI,20730
26
26
  code_puppy/command_line/file_path_completion.py,sha256=gw8NpIxa6GOpczUJRyh7VNZwoXKKn-yvCqit7h2y6Gg,2931
27
27
  code_puppy/command_line/load_context_completion.py,sha256=6eZxV6Bs-EFwZjN93V8ZDZUC-6RaWxvtZk-04Wtikyw,2240
28
- code_puppy/command_line/mcp_commands.py,sha256=qqEdac7zR4Wydn0JE3lTVnLi3dh_Lc8DJmjOq8dQeJM,55379
28
+ code_puppy/command_line/mcp_commands.py,sha256=YlBzJ9-skZy-anND6fHv4rFipbajhrUTVd50O-TLZEE,81156
29
29
  code_puppy/command_line/meta_command_handler.py,sha256=02NU4Lspf5qRMPTsrGiMRLSUshZhdmS0XQA26k8vUjw,5665
30
30
  code_puppy/command_line/model_picker_completion.py,sha256=xvwgthVmLRA9a8RJG6iFImxR2yD6rJYPJJav0YJoVCc,3599
31
31
  code_puppy/command_line/motd.py,sha256=PEdkp3ZnydVfvd7mNJylm8YyFNUKg9jmY6uwkA1em8c,2152
@@ -34,7 +34,7 @@ code_puppy/command_line/utils.py,sha256=7eyxDHjPjPB9wGDJQQcXV_zOsGdYsFgI0SGCetVm
34
34
  code_puppy/mcp/__init__.py,sha256=LJd9mGStskhXYBEp1UhtHlrAQ3rCHnfTa7KSmqtZe34,1143
35
35
  code_puppy/mcp/async_lifecycle.py,sha256=45tw7ZcDV6LVBrTvvNkMCDhnTapgQCYcc01W8Gp9c5A,8064
36
36
  code_puppy/mcp/circuit_breaker.py,sha256=TF0ukl_d4EithPQbiq1yDfFPkCZ7bRBe0jiEx_tnMR4,8630
37
- code_puppy/mcp/config_wizard.py,sha256=JsIyzyP8mFZLPzz4-bSEXg0S6IRuBDkDRK_nAWO6SYA,14321
37
+ code_puppy/mcp/config_wizard.py,sha256=d0o29ZcnGLdpV778nwTUAPH7B8lHAC2XggU-ql37Fzo,16777
38
38
  code_puppy/mcp/dashboard.py,sha256=fHBdAVidQUWuhjMjF7hIy0SjrQlrz31zSqzqJv8H2eI,9396
39
39
  code_puppy/mcp/error_isolation.py,sha256=xw8DGTItT8-RY5TVYzORtrtfdI1s1ZfUUT88Pr7h_pI,12270
40
40
  code_puppy/mcp/health_monitor.py,sha256=oNgPyEwzkF61gNc7nk-FJU_yO2MERjASn4g5shcabic,20428
@@ -42,13 +42,14 @@ code_puppy/mcp/managed_server.py,sha256=oeVNJIunn5IyT_Qy5j4rWfnIfAJgQyD3UKp9XRaY
42
42
  code_puppy/mcp/manager.py,sha256=ZfYoz3nmQqrkSnDzgr9s_QvGKFCthA1bvt3gQm0W6VI,27280
43
43
  code_puppy/mcp/registry.py,sha256=YJ-VPFjk1ZFrSftbu9bKVIWvGYX4zIk2TnrM_h_us1M,15841
44
44
  code_puppy/mcp/retry_manager.py,sha256=B4q1MyzZQ9RZRW3FKhyqhq-ebSG8Do01j4A70zHTxgA,10988
45
- code_puppy/mcp/server_registry_catalog.py,sha256=j-fAs8eCutXNYfHJPSYX30k4SfqKQLJR8MKnMxo32IU,23814
45
+ code_puppy/mcp/server_registry_catalog.py,sha256=7ZoGlt5s3F3mpZUvkRdzBHNt4Ka0rL1FD7153sZ0QpA,37779
46
46
  code_puppy/mcp/status_tracker.py,sha256=JJcAjE8mr30stEfmAhtPmTcLp1zBt5x3aynm_O4kyvY,12748
47
+ code_puppy/mcp/system_tools.py,sha256=djc0nLSZP9swfdxI5ZNCI3PZ1VL6DbmHad2MwfZU-r8,7610
47
48
  code_puppy/mcp/examples/retry_example.py,sha256=L9wB1H4JTzmEx1FkSR2x4jXCyfR8AoUjSngjbRXhyCQ,7201
48
- code_puppy/messaging/__init__.py,sha256=0rfN3q3ODVp3d1M3WQjDLG35IexrauSuClF25DFzwaQ,1080
49
- code_puppy/messaging/message_queue.py,sha256=G61mwR4zf_F9ccHQtU5UaEVlVh0ANQpCr0NmSZxiZlk,9213
49
+ code_puppy/messaging/__init__.py,sha256=h2eZ7nJblKF71_dNUIBj3vL5RDw7WGy8nh6T_EYVrcA,1176
50
+ code_puppy/messaging/message_queue.py,sha256=sdn_c8eM93BvaFq9JEaCc_wgCA4Yw6oU7xgPjCpGgTc,12626
50
51
  code_puppy/messaging/queue_console.py,sha256=L4QFUsR_emAFsIRan3-rnL-F1LODF4DG6je-IlUTxNc,10864
51
- code_puppy/messaging/renderers.py,sha256=-DJprhnK46cDCf6BrIQKZrT_8Y09NN_Eo61AVLhe-r8,11633
52
+ code_puppy/messaging/renderers.py,sha256=DYwM2cdqItFoHsCxBPtY8zCORwHNFgzrNhpixrv4Lt4,16028
52
53
  code_puppy/messaging/spinner/__init__.py,sha256=9mkXPYojafydBOAMh9ZUrB4X6uH5Iqz_-E-Obpd72ko,1365
53
54
  code_puppy/messaging/spinner/console_spinner.py,sha256=cuOXQH99dJ1cq0l_rpCLVCGNsH-iVcUWtE6fC3kjZCg,6931
54
55
  code_puppy/messaging/spinner/spinner_base.py,sha256=474qMrTYpNfWcprFzmhaOJEOC-2rRHpTFCLsnl54bXA,1689
@@ -62,13 +63,14 @@ code_puppy/tools/file_operations.py,sha256=WKGNSGTw3vGdDqGGUBHIPh1uCjaDLJmgIa8Ua
62
63
  code_puppy/tools/token_check.py,sha256=cNrGOOKahXsnWsvh5xnMkL1NS9FjYur9QIRZGQFW-pE,1189
63
64
  code_puppy/tools/tools_content.py,sha256=pi9ig2qahZFkUj7gBBN2TX2QldvwnqmTHrRKP8my_2k,2209
64
65
  code_puppy/tui/__init__.py,sha256=XesAxIn32zLPOmvpR2wIDxDAnnJr81a5pBJB4cZp1Xs,321
65
- code_puppy/tui/app.py,sha256=T_9rQ3LeWm6_9zKwDwgeFSO22WpzLxibsxDWvTilAYA,36220
66
+ code_puppy/tui/app.py,sha256=zeth1Kbj9k-3ltnBV_QZlDBmu3jwTxOJEwyvB6j8AcY,37340
66
67
  code_puppy/tui/messages.py,sha256=zQoToWI0eWdT36NEsY6RdCFzcDfAmfvoPlHv8jiCbgo,720
67
68
  code_puppy/tui/components/__init__.py,sha256=uj5pnk3s6SEN3SbFI0ZnzaA2KK1NNg8TfUj6U-Z732U,455
68
- code_puppy/tui/components/chat_view.py,sha256=u6yFqz7sz5RYxVpobnAHXDfDeIDRwDnXXTBwBl5Wn7M,17995
69
+ code_puppy/tui/components/chat_view.py,sha256=5y4LA-93SnPKVZmfVhYG43fiwkxVHkKATuiC44d4Wew,18572
69
70
  code_puppy/tui/components/command_history_modal.py,sha256=pUPEQvoCWa2iUnuMgNwO22y8eUbyw0HpcPH3wAosHvU,7097
70
71
  code_puppy/tui/components/copy_button.py,sha256=E4-OJYk5YNzDf-E81NyiVGKsTRPrUX-RnQ8qFuVnabw,4375
71
72
  code_puppy/tui/components/custom_widgets.py,sha256=pnjkB3ZNa5lwSrAXUFlhN9AHNh4uMTpSap8AdbpecKw,1986
73
+ code_puppy/tui/components/human_input_modal.py,sha256=y4M1PrZtU1PY9XBT_cUqFbL4noc2pYiwIacYZhPFG_M,5454
72
74
  code_puppy/tui/components/input_area.py,sha256=R4R32eXPZ2R8KFisIbldNGq60KMk7kCxWrdbeTgJUr8,4395
73
75
  code_puppy/tui/components/sidebar.py,sha256=nGtCiYzZalPmiFaJ4dwj2S4EJBu5wQZVzhoigYYY7U4,10369
74
76
  code_puppy/tui/components/status_bar.py,sha256=GgznJqF8Wk6XkurBuKohLyu75eT_ucBTvl9oPcySmnM,6338
@@ -76,8 +78,9 @@ code_puppy/tui/models/__init__.py,sha256=5Eq7BMibz-z_t_v7B4H4tCdKRG41i2CaCuNQf_l
76
78
  code_puppy/tui/models/chat_message.py,sha256=2fSqsl4EHKgGsi_cVKWBbFq1NQwZyledGuJ9djovtLY,477
77
79
  code_puppy/tui/models/command_history.py,sha256=bPWr_xnyQvjG5tPg_5pwqlEzn2fR170HlvBJwAXRpAE,2895
78
80
  code_puppy/tui/models/enums.py,sha256=1ulsei95Gxy4r1sk-m-Sm5rdmejYCGRI-YtUwJmKFfM,501
79
- code_puppy/tui/screens/__init__.py,sha256=iQ_pzTdF9095l-kCWHcaxvWyP8ndFbZaGySWDpCxQwU,201
81
+ code_puppy/tui/screens/__init__.py,sha256=Sa_R_caykfsa7D55Zuc9VYpFfmQZAYxBFxfn_7Qe41M,287
80
82
  code_puppy/tui/screens/help.py,sha256=eJuPaOOCp7ZSUlecearqsuX6caxWv7NQszUh0tZJjBM,3232
83
+ code_puppy/tui/screens/mcp_install_wizard.py,sha256=bw16ygvulKYaz8TkYXl0C6wGsMoay4oIIHyVWXnCA2I,21641
81
84
  code_puppy/tui/screens/settings.py,sha256=GMpv-qa08rorAE9mj3AjmqjZFPhmeJ_GWd-DBHG6iAA,10671
82
85
  code_puppy/tui/screens/tools.py,sha256=3pr2Xkpa9Js6Yhf1A3_wQVRzFOui-KDB82LwrsdBtyk,1715
83
86
  code_puppy/tui/tests/__init__.py,sha256=Fzb4un4eeKfaKsIa5tqI5pTuwfpS8qD7Z6W7KeqWe84,23
@@ -100,9 +103,9 @@ code_puppy/tui/tests/test_sidebar_history_navigation.py,sha256=JGiyua8A2B8dLfwiE
100
103
  code_puppy/tui/tests/test_status_bar.py,sha256=nYT_FZGdmqnnbn6o0ZuOkLtNUtJzLSmtX8P72liQ5Vo,1797
101
104
  code_puppy/tui/tests/test_timestamped_history.py,sha256=nVXt9hExZZ_8MFP-AZj4L4bB_1Eo_mc-ZhVICzTuw3I,1799
102
105
  code_puppy/tui/tests/test_tools.py,sha256=kgzzAkK4r0DPzQwHHD4cePpVNgrHor6cFr05Pg6DBWg,2687
103
- code_puppy-0.0.130.data/data/code_puppy/models.json,sha256=GpvtWnBKERm6T7HCZJQUIVAS5256-tZ_bFuRtnKXEsY,3128
104
- code_puppy-0.0.130.dist-info/METADATA,sha256=4ZUO2tCKE7Iztu63OFd-FDXLU5_hTXyjyfbddKu8hbI,19873
105
- code_puppy-0.0.130.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
106
- code_puppy-0.0.130.dist-info/entry_points.txt,sha256=d8YkBvIUxF-dHNJAj-x4fPEqizbY5d_TwvYpc01U5kw,58
107
- code_puppy-0.0.130.dist-info/licenses/LICENSE,sha256=31u8x0SPgdOq3izJX41kgFazWsM43zPEF9eskzqbJMY,1075
108
- code_puppy-0.0.130.dist-info/RECORD,,
106
+ code_puppy-0.0.131.data/data/code_puppy/models.json,sha256=GpvtWnBKERm6T7HCZJQUIVAS5256-tZ_bFuRtnKXEsY,3128
107
+ code_puppy-0.0.131.dist-info/METADATA,sha256=FrlQgWQL53BSHH9iHvCIarsXR2xPJFulj7QWDdv-_BQ,19873
108
+ code_puppy-0.0.131.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
109
+ code_puppy-0.0.131.dist-info/entry_points.txt,sha256=d8YkBvIUxF-dHNJAj-x4fPEqizbY5d_TwvYpc01U5kw,58
110
+ code_puppy-0.0.131.dist-info/licenses/LICENSE,sha256=31u8x0SPgdOq3izJX41kgFazWsM43zPEF9eskzqbJMY,1075
111
+ code_puppy-0.0.131.dist-info/RECORD,,