lean-explore 0.1.1__tar.gz → 0.1.2__tar.gz
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.
- {lean_explore-0.1.1 → lean_explore-0.1.2}/PKG-INFO +1 -1
- {lean_explore-0.1.1 → lean_explore-0.1.2}/pyproject.toml +1 -1
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/cli/main.py +89 -57
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore.egg-info/PKG-INFO +1 -1
- {lean_explore-0.1.1 → lean_explore-0.1.2}/LICENSE +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/README.md +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/setup.cfg +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/__init__.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/api/__init__.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/api/client.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/cli/__init__.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/cli/agent.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/cli/config_utils.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/cli/data_commands.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/defaults.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/local/__init__.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/local/search.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/local/service.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/mcp/__init__.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/mcp/app.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/mcp/server.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/mcp/tools.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/shared/__init__.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/shared/models/__init__.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/shared/models/api.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore/shared/models/db.py +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore.egg-info/SOURCES.txt +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore.egg-info/dependency_links.txt +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore.egg-info/entry_points.txt +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore.egg-info/requires.txt +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/src/lean_explore.egg-info/top_level.txt +0 -0
- {lean_explore-0.1.1 → lean_explore-0.1.2}/tests/test_defaults.py +0 -0
|
@@ -60,6 +60,7 @@ app.command("chat", help="Interact with an AI agent using Lean Explore tools.")(
|
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
console = Console()
|
|
63
|
+
error_console = Console(stderr=True)
|
|
63
64
|
|
|
64
65
|
# Content width for panels.
|
|
65
66
|
PANEL_CONTENT_WIDTH = 80
|
|
@@ -75,9 +76,15 @@ def configure_lean_explore_api_key(
|
|
|
75
76
|
confirmation_prompt=True,
|
|
76
77
|
),
|
|
77
78
|
):
|
|
78
|
-
"""Configure and save your Lean Explore API key.
|
|
79
|
+
"""Configure and save your Lean Explore API key.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
api_key: The API key string to save. Prompts if not provided.
|
|
83
|
+
"""
|
|
79
84
|
if not api_key:
|
|
80
|
-
|
|
85
|
+
error_console.print(
|
|
86
|
+
"[bold red]Lean Explore API key cannot be empty.[/bold red]"
|
|
87
|
+
)
|
|
81
88
|
raise typer.Abort()
|
|
82
89
|
|
|
83
90
|
if config_utils.save_api_key(api_key):
|
|
@@ -87,7 +94,7 @@ def configure_lean_explore_api_key(
|
|
|
87
94
|
f"{config_path}[/bold green]"
|
|
88
95
|
)
|
|
89
96
|
else:
|
|
90
|
-
|
|
97
|
+
error_console.print(
|
|
91
98
|
"[bold red]Failed to save Lean Explore API key. "
|
|
92
99
|
"Check logs or permissions.[/bold red]"
|
|
93
100
|
)
|
|
@@ -107,9 +114,12 @@ def configure_openai_api_key(
|
|
|
107
114
|
"""Configure and save your OpenAI API key.
|
|
108
115
|
|
|
109
116
|
This key is used by agent functionalities that leverage OpenAI models.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
api_key: The OpenAI API key string to save. Prompts if not provided.
|
|
110
120
|
"""
|
|
111
121
|
if not api_key:
|
|
112
|
-
|
|
122
|
+
error_console.print("[bold red]OpenAI API key cannot be empty.[/bold red]")
|
|
113
123
|
raise typer.Abort()
|
|
114
124
|
|
|
115
125
|
if config_utils.save_openai_api_key(api_key):
|
|
@@ -119,7 +129,7 @@ def configure_openai_api_key(
|
|
|
119
129
|
f"{config_path}[/bold green]"
|
|
120
130
|
)
|
|
121
131
|
else:
|
|
122
|
-
|
|
132
|
+
error_console.print(
|
|
123
133
|
"[bold red]Failed to save OpenAI API key. "
|
|
124
134
|
"Check logs or permissions.[/bold red]"
|
|
125
135
|
)
|
|
@@ -130,12 +140,12 @@ def _get_api_client() -> Optional[APIClient]:
|
|
|
130
140
|
"""Loads Lean Explore API key and initializes the APIClient.
|
|
131
141
|
|
|
132
142
|
Returns:
|
|
133
|
-
APIClient instance if key is found, None otherwise.
|
|
143
|
+
Optional[APIClient]: APIClient instance if key is found, None otherwise.
|
|
134
144
|
"""
|
|
135
145
|
api_key = config_utils.load_api_key()
|
|
136
146
|
if not api_key:
|
|
137
147
|
config_path = config_utils.get_config_file_path()
|
|
138
|
-
|
|
148
|
+
error_console.print(
|
|
139
149
|
"[bold yellow]Lean Explore API key not configured. Please run:"
|
|
140
150
|
"[/bold yellow]\n"
|
|
141
151
|
f" `leanexplore configure api-key`\n"
|
|
@@ -146,7 +156,15 @@ def _get_api_client() -> Optional[APIClient]:
|
|
|
146
156
|
|
|
147
157
|
|
|
148
158
|
def _format_text_for_fixed_panel(text_content: Optional[str], width: int) -> str:
|
|
149
|
-
"""Wraps text and pads lines to ensure fixed content width for a Panel.
|
|
159
|
+
"""Wraps text and pads lines to ensure fixed content width for a Panel.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
text_content: The text content to wrap and pad.
|
|
163
|
+
width: The target width for text wrapping and padding.
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
A string with wrapped and padded text suitable for fixed-width display.
|
|
167
|
+
"""
|
|
150
168
|
if not text_content:
|
|
151
169
|
return " " * width
|
|
152
170
|
|
|
@@ -188,16 +206,23 @@ def _format_text_for_fixed_panel(text_content: Optional[str], width: int) -> str
|
|
|
188
206
|
if i < len(paragraphs) - 1 and (
|
|
189
207
|
paragraph.strip() or (not paragraph.strip() and not lines_in_paragraph)
|
|
190
208
|
):
|
|
209
|
+
# Add a blank padded line between paragraphs
|
|
191
210
|
final_output_lines.append(" " * width)
|
|
192
211
|
|
|
193
212
|
if not final_output_lines and text_content.strip():
|
|
213
|
+
# Fallback for content that becomes empty after processing but was not initially
|
|
194
214
|
return " " * width
|
|
195
215
|
|
|
196
216
|
return "\n".join(final_output_lines)
|
|
197
217
|
|
|
198
218
|
|
|
199
219
|
def _display_search_results(response: APISearchResponse, display_limit: int = 5):
|
|
200
|
-
"""Displays search results using fixed-width Panels for each item.
|
|
220
|
+
"""Displays search results using fixed-width Panels for each item.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
response: The APISearchResponse object from the backend.
|
|
224
|
+
display_limit: The maximum number of individual results to display in detail.
|
|
225
|
+
"""
|
|
201
226
|
console.print(
|
|
202
227
|
Panel(
|
|
203
228
|
f"[bold cyan]Search Query:[/bold cyan] {response.query}",
|
|
@@ -222,7 +247,7 @@ def _display_search_results(response: APISearchResponse, display_limit: int = 5)
|
|
|
222
247
|
console.print("[yellow]No results found.[/yellow]")
|
|
223
248
|
return
|
|
224
249
|
|
|
225
|
-
console.print("")
|
|
250
|
+
console.print("") # Adds a blank line for spacing
|
|
226
251
|
|
|
227
252
|
for i, item in enumerate(response.results):
|
|
228
253
|
if i >= display_limit:
|
|
@@ -288,7 +313,7 @@ def _display_search_results(response: APISearchResponse, display_limit: int = 5)
|
|
|
288
313
|
"code) available for this item.[/dim]"
|
|
289
314
|
)
|
|
290
315
|
|
|
291
|
-
if i < num_results_to_show - 1:
|
|
316
|
+
if i < num_results_to_show - 1: # Add spacing between items
|
|
292
317
|
console.print("")
|
|
293
318
|
|
|
294
319
|
console.rule(style="dim")
|
|
@@ -297,9 +322,12 @@ def _display_search_results(response: APISearchResponse, display_limit: int = 5)
|
|
|
297
322
|
f"...and {len(response.results) - num_results_to_show} more results "
|
|
298
323
|
"received from server but not shown due to limit."
|
|
299
324
|
)
|
|
300
|
-
elif response.count > len(
|
|
325
|
+
elif response.count > len(
|
|
326
|
+
response.results
|
|
327
|
+
): # Should be total_candidates_considered
|
|
301
328
|
console.print(
|
|
302
|
-
f"...and {response.
|
|
329
|
+
f"...and {response.total_candidates_considered - len(response.results)} "
|
|
330
|
+
"more results available "
|
|
303
331
|
"on server."
|
|
304
332
|
)
|
|
305
333
|
|
|
@@ -318,7 +346,13 @@ async def search_command(
|
|
|
318
346
|
5, "--limit", "-n", help="Number of search results to display."
|
|
319
347
|
),
|
|
320
348
|
):
|
|
321
|
-
"""Search for Lean statement groups using the Lean Explore API.
|
|
349
|
+
"""Search for Lean statement groups using the Lean Explore API.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
query_string: The natural language query to search for.
|
|
353
|
+
package: An optional list of package names to filter results by.
|
|
354
|
+
limit: The maximum number of search results to display to the user.
|
|
355
|
+
"""
|
|
322
356
|
client = _get_api_client()
|
|
323
357
|
if not client:
|
|
324
358
|
raise typer.Exit(code=1)
|
|
@@ -329,33 +363,33 @@ async def search_command(
|
|
|
329
363
|
_display_search_results(response, display_limit=limit)
|
|
330
364
|
except httpx.HTTPStatusError as e:
|
|
331
365
|
if e.response.status_code == 401:
|
|
332
|
-
|
|
366
|
+
error_console.print(
|
|
333
367
|
f"[bold red]API Error {e.response.status_code}: Unauthorized. "
|
|
334
368
|
"Your API key might be invalid or expired.[/bold red]"
|
|
335
369
|
)
|
|
336
|
-
|
|
370
|
+
error_console.print(
|
|
337
371
|
"Please reconfigure your API key using: `leanexplore configure api-key`"
|
|
338
372
|
)
|
|
339
373
|
else:
|
|
340
374
|
try:
|
|
341
375
|
error_detail = e.response.json().get("detail", e.response.text)
|
|
342
|
-
|
|
376
|
+
error_console.print(
|
|
343
377
|
f"[bold red]API Error {e.response.status_code}: "
|
|
344
378
|
f"{error_detail}[/bold red]"
|
|
345
379
|
)
|
|
346
380
|
except Exception:
|
|
347
|
-
|
|
381
|
+
error_console.print(
|
|
348
382
|
f"[bold red]API Error {e.response.status_code}: "
|
|
349
383
|
f"{e.response.text}[/bold red]"
|
|
350
384
|
)
|
|
351
385
|
raise typer.Exit(code=1)
|
|
352
386
|
except httpx.RequestError as e:
|
|
353
|
-
|
|
387
|
+
error_console.print(
|
|
354
388
|
f"[bold red]Network Error: Could not connect to the API. {e}[/bold red]"
|
|
355
389
|
)
|
|
356
390
|
raise typer.Exit(code=1)
|
|
357
391
|
except Exception as e:
|
|
358
|
-
|
|
392
|
+
error_console.print(f"[bold red]An unexpected error occurred: {e}[/bold red]")
|
|
359
393
|
raise typer.Exit(code=1)
|
|
360
394
|
|
|
361
395
|
|
|
@@ -366,7 +400,11 @@ async def get_by_id_command(
|
|
|
366
400
|
..., help="The ID of the statement group to retrieve."
|
|
367
401
|
),
|
|
368
402
|
):
|
|
369
|
-
"""Get detailed information about a specific statement group by its ID.
|
|
403
|
+
"""Get detailed information about a specific statement group by its ID.
|
|
404
|
+
|
|
405
|
+
Args:
|
|
406
|
+
group_id: The unique integer identifier of the statement group.
|
|
407
|
+
"""
|
|
370
408
|
client = _get_api_client()
|
|
371
409
|
if not client:
|
|
372
410
|
raise typer.Exit(code=1)
|
|
@@ -437,36 +475,36 @@ async def get_by_id_command(
|
|
|
437
475
|
)
|
|
438
476
|
|
|
439
477
|
else:
|
|
440
|
-
|
|
478
|
+
error_console.print( # Changed to error_console for error/warning message
|
|
441
479
|
f"[yellow]Statement group with ID {group_id} not found.[/yellow]"
|
|
442
480
|
)
|
|
443
481
|
|
|
444
482
|
except httpx.HTTPStatusError as e:
|
|
445
483
|
if e.response.status_code == 401:
|
|
446
|
-
|
|
484
|
+
error_console.print(
|
|
447
485
|
f"[bold red]API Error {e.response.status_code}: Unauthorized."
|
|
448
486
|
" Your API key might be invalid or expired.[/bold red]"
|
|
449
487
|
)
|
|
450
488
|
else:
|
|
451
489
|
try:
|
|
452
490
|
error_detail = e.response.json().get("detail", e.response.text)
|
|
453
|
-
|
|
491
|
+
error_console.print(
|
|
454
492
|
f"[bold red]API Error {e.response.status_code}: "
|
|
455
493
|
f"{error_detail}[/bold red]"
|
|
456
494
|
)
|
|
457
495
|
except Exception:
|
|
458
|
-
|
|
496
|
+
error_console.print(
|
|
459
497
|
f"[bold red]API Error {e.response.status_code}: "
|
|
460
498
|
f"{e.response.text}[/bold red]"
|
|
461
499
|
)
|
|
462
500
|
raise typer.Exit(code=1)
|
|
463
501
|
except httpx.RequestError as e:
|
|
464
|
-
|
|
502
|
+
error_console.print(
|
|
465
503
|
f"[bold red]Network Error: Could not connect to the API. {e}[/bold red]"
|
|
466
504
|
)
|
|
467
505
|
raise typer.Exit(code=1)
|
|
468
506
|
except Exception as e:
|
|
469
|
-
|
|
507
|
+
error_console.print(f"[bold red]An unexpected error occurred: {e}[/bold red]")
|
|
470
508
|
raise typer.Exit(code=1)
|
|
471
509
|
|
|
472
510
|
|
|
@@ -477,7 +515,11 @@ async def get_dependencies_command(
|
|
|
477
515
|
..., help="The ID of the statement group to get dependencies for."
|
|
478
516
|
),
|
|
479
517
|
):
|
|
480
|
-
"""Get dependencies (citations) for a specific statement group by its ID.
|
|
518
|
+
"""Get dependencies (citations) for a specific statement group by its ID.
|
|
519
|
+
|
|
520
|
+
Args:
|
|
521
|
+
group_id: The unique integer identifier of the statement group.
|
|
522
|
+
"""
|
|
481
523
|
client = _get_api_client()
|
|
482
524
|
if not client:
|
|
483
525
|
raise typer.Exit(code=1)
|
|
@@ -519,44 +561,40 @@ async def get_dependencies_command(
|
|
|
519
561
|
else:
|
|
520
562
|
console.print("[yellow]No citations found for this group.[/yellow]")
|
|
521
563
|
else:
|
|
522
|
-
|
|
564
|
+
error_console.print( # Changed to error_console for error/warning message
|
|
523
565
|
f"[yellow]Statement group with ID {group_id} not found or no "
|
|
524
566
|
"citations data available.[/yellow]"
|
|
525
567
|
)
|
|
526
568
|
|
|
527
569
|
except httpx.HTTPStatusError as e:
|
|
528
570
|
if e.response.status_code == 401:
|
|
529
|
-
|
|
571
|
+
error_console.print(
|
|
530
572
|
f"[bold red]API Error {e.response.status_code}: Unauthorized."
|
|
531
573
|
" Your API key might be invalid or expired.[/bold red]"
|
|
532
574
|
)
|
|
533
575
|
else:
|
|
534
576
|
try:
|
|
535
577
|
error_detail = e.response.json().get("detail", e.response.text)
|
|
536
|
-
|
|
578
|
+
error_console.print(
|
|
537
579
|
f"[bold red]API Error {e.response.status_code}: "
|
|
538
580
|
f"{error_detail}[/bold red]"
|
|
539
581
|
)
|
|
540
582
|
except Exception:
|
|
541
|
-
|
|
583
|
+
error_console.print(
|
|
542
584
|
f"[bold red]API Error {e.response.status_code}: "
|
|
543
585
|
f"{e.response.text}[/bold red]"
|
|
544
586
|
)
|
|
545
587
|
raise typer.Exit(code=1)
|
|
546
588
|
except httpx.RequestError as e:
|
|
547
|
-
|
|
589
|
+
error_console.print(
|
|
548
590
|
f"[bold red]Network Error: Could not connect to the API. {e}[/bold red]"
|
|
549
591
|
)
|
|
550
592
|
raise typer.Exit(code=1)
|
|
551
593
|
except Exception as e:
|
|
552
|
-
|
|
594
|
+
error_console.print(f"[bold red]An unexpected error occurred: {e}[/bold red]")
|
|
553
595
|
raise typer.Exit(code=1)
|
|
554
596
|
|
|
555
597
|
|
|
556
|
-
# The placeholder download-db command is removed as its functionality
|
|
557
|
-
# will be covered by the `leanexplore data fetch` command.
|
|
558
|
-
|
|
559
|
-
|
|
560
598
|
@mcp_app.command("serve")
|
|
561
599
|
def mcp_serve_command(
|
|
562
600
|
backend: str = typer.Option(
|
|
@@ -579,6 +617,10 @@ def mcp_serve_command(
|
|
|
579
617
|
The server communicates via stdio and provides Lean search functionalities
|
|
580
618
|
as MCP tools. The actual checks for local data presence or API key validity
|
|
581
619
|
are handled by the 'lean_explore.mcp.server' module when it starts.
|
|
620
|
+
|
|
621
|
+
Args:
|
|
622
|
+
backend: The backend choice ('api' or 'local').
|
|
623
|
+
api_key_override: Optional API key to override any stored key.
|
|
582
624
|
"""
|
|
583
625
|
command_parts = [
|
|
584
626
|
sys.executable,
|
|
@@ -589,41 +631,33 @@ def mcp_serve_command(
|
|
|
589
631
|
]
|
|
590
632
|
|
|
591
633
|
if backend.lower() == "api":
|
|
592
|
-
# API key will be loaded by mcp.server or passed if overridden
|
|
593
|
-
# We still check here to provide immediate feedback if --api-key
|
|
594
|
-
# is needed but not stored.
|
|
595
634
|
effective_lean_explore_api_key = api_key_override or config_utils.load_api_key()
|
|
596
635
|
if not effective_lean_explore_api_key:
|
|
597
|
-
|
|
636
|
+
error_console.print(
|
|
598
637
|
"[bold red]Lean Explore API key is required for 'api' backend."
|
|
599
638
|
"[/bold red]\n"
|
|
600
639
|
"Please configure it using `leanexplore configure api-key` "
|
|
601
640
|
"or provide it with the `--api-key` option for this command."
|
|
602
641
|
)
|
|
603
642
|
raise typer.Abort()
|
|
604
|
-
# Pass the override if provided; otherwise, mcp.server will load it.
|
|
605
643
|
if api_key_override:
|
|
606
644
|
command_parts.extend(["--api-key", api_key_override])
|
|
607
645
|
elif backend.lower() == "local":
|
|
608
|
-
#
|
|
609
|
-
# and provide user guidance. No explicit checks needed here in main.py.
|
|
610
|
-
console.print(
|
|
646
|
+
error_console.print( # Changed to error_console for consistency
|
|
611
647
|
"[dim]Attempting to start MCP server with 'local' backend. "
|
|
612
648
|
"The server will verify local data availability.[/dim]"
|
|
613
649
|
)
|
|
614
650
|
else:
|
|
615
|
-
|
|
616
|
-
# but as a safeguard.
|
|
617
|
-
console.print(
|
|
651
|
+
error_console.print(
|
|
618
652
|
f"[bold red]Invalid backend: '{backend}'. Must be 'api' or 'local'."
|
|
619
653
|
"[/bold red]"
|
|
620
654
|
)
|
|
621
655
|
raise typer.Abort()
|
|
622
656
|
|
|
623
|
-
|
|
657
|
+
error_console.print(
|
|
624
658
|
f"[green]Launching MCP server subprocess with '{backend}' backend...[/green]"
|
|
625
659
|
)
|
|
626
|
-
|
|
660
|
+
error_console.print(
|
|
627
661
|
"[dim]The server will now take over stdio. To stop it, the connected MCP "
|
|
628
662
|
"client should disconnect, or you may need to manually terminate this process "
|
|
629
663
|
"(e.g., Ctrl+C if no client is managing it).[/dim]"
|
|
@@ -632,24 +666,22 @@ def mcp_serve_command(
|
|
|
632
666
|
try:
|
|
633
667
|
process_result = subprocess.run(command_parts, check=False)
|
|
634
668
|
if process_result.returncode != 0:
|
|
635
|
-
|
|
636
|
-
# before exiting with a non-zero code.
|
|
637
|
-
console.print(
|
|
669
|
+
error_console.print(
|
|
638
670
|
f"[bold red]MCP server subprocess exited with code: "
|
|
639
671
|
f"{process_result.returncode}. Check server logs above for "
|
|
640
672
|
f"details.[/bold red]"
|
|
641
673
|
)
|
|
642
674
|
except FileNotFoundError:
|
|
643
|
-
|
|
675
|
+
error_console.print(
|
|
644
676
|
f"[bold red]Error: Could not find Python interpreter '{sys.executable}' "
|
|
645
677
|
f"or the MCP server module 'lean_explore.mcp.server'.[/bold red]"
|
|
646
678
|
)
|
|
647
|
-
|
|
679
|
+
error_console.print(
|
|
648
680
|
"Please ensure the package is installed correctly and "
|
|
649
681
|
"`python -m lean_explore.mcp.server` is runnable."
|
|
650
682
|
)
|
|
651
683
|
except Exception as e:
|
|
652
|
-
|
|
684
|
+
error_console.print(
|
|
653
685
|
f"[bold red]An error occurred while trying to launch or run the MCP "
|
|
654
686
|
f"server: {e}[/bold red]"
|
|
655
687
|
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|