mcp-vector-search 0.15.7__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.
Potentially problematic release.
This version of mcp-vector-search might be problematic. Click here for more details.
- mcp_vector_search/__init__.py +10 -0
- mcp_vector_search/cli/__init__.py +1 -0
- mcp_vector_search/cli/commands/__init__.py +1 -0
- mcp_vector_search/cli/commands/auto_index.py +397 -0
- mcp_vector_search/cli/commands/chat.py +534 -0
- mcp_vector_search/cli/commands/config.py +393 -0
- mcp_vector_search/cli/commands/demo.py +358 -0
- mcp_vector_search/cli/commands/index.py +762 -0
- mcp_vector_search/cli/commands/init.py +658 -0
- mcp_vector_search/cli/commands/install.py +869 -0
- mcp_vector_search/cli/commands/install_old.py +700 -0
- mcp_vector_search/cli/commands/mcp.py +1254 -0
- mcp_vector_search/cli/commands/reset.py +393 -0
- mcp_vector_search/cli/commands/search.py +796 -0
- mcp_vector_search/cli/commands/setup.py +1133 -0
- mcp_vector_search/cli/commands/status.py +584 -0
- mcp_vector_search/cli/commands/uninstall.py +404 -0
- mcp_vector_search/cli/commands/visualize/__init__.py +39 -0
- mcp_vector_search/cli/commands/visualize/cli.py +265 -0
- mcp_vector_search/cli/commands/visualize/exporters/__init__.py +12 -0
- mcp_vector_search/cli/commands/visualize/exporters/html_exporter.py +33 -0
- mcp_vector_search/cli/commands/visualize/exporters/json_exporter.py +29 -0
- mcp_vector_search/cli/commands/visualize/graph_builder.py +709 -0
- mcp_vector_search/cli/commands/visualize/layout_engine.py +469 -0
- mcp_vector_search/cli/commands/visualize/server.py +201 -0
- mcp_vector_search/cli/commands/visualize/state_manager.py +428 -0
- mcp_vector_search/cli/commands/visualize/templates/__init__.py +16 -0
- mcp_vector_search/cli/commands/visualize/templates/base.py +218 -0
- mcp_vector_search/cli/commands/visualize/templates/scripts.py +3670 -0
- mcp_vector_search/cli/commands/visualize/templates/styles.py +779 -0
- mcp_vector_search/cli/commands/visualize.py.original +2536 -0
- mcp_vector_search/cli/commands/watch.py +287 -0
- mcp_vector_search/cli/didyoumean.py +520 -0
- mcp_vector_search/cli/export.py +320 -0
- mcp_vector_search/cli/history.py +295 -0
- mcp_vector_search/cli/interactive.py +342 -0
- mcp_vector_search/cli/main.py +484 -0
- mcp_vector_search/cli/output.py +414 -0
- mcp_vector_search/cli/suggestions.py +375 -0
- mcp_vector_search/config/__init__.py +1 -0
- mcp_vector_search/config/constants.py +24 -0
- mcp_vector_search/config/defaults.py +200 -0
- mcp_vector_search/config/settings.py +146 -0
- mcp_vector_search/core/__init__.py +1 -0
- mcp_vector_search/core/auto_indexer.py +298 -0
- mcp_vector_search/core/config_utils.py +394 -0
- mcp_vector_search/core/connection_pool.py +360 -0
- mcp_vector_search/core/database.py +1237 -0
- mcp_vector_search/core/directory_index.py +318 -0
- mcp_vector_search/core/embeddings.py +294 -0
- mcp_vector_search/core/exceptions.py +89 -0
- mcp_vector_search/core/factory.py +318 -0
- mcp_vector_search/core/git_hooks.py +345 -0
- mcp_vector_search/core/indexer.py +1002 -0
- mcp_vector_search/core/llm_client.py +453 -0
- mcp_vector_search/core/models.py +294 -0
- mcp_vector_search/core/project.py +350 -0
- mcp_vector_search/core/scheduler.py +330 -0
- mcp_vector_search/core/search.py +952 -0
- mcp_vector_search/core/watcher.py +322 -0
- mcp_vector_search/mcp/__init__.py +5 -0
- mcp_vector_search/mcp/__main__.py +25 -0
- mcp_vector_search/mcp/server.py +752 -0
- mcp_vector_search/parsers/__init__.py +8 -0
- mcp_vector_search/parsers/base.py +296 -0
- mcp_vector_search/parsers/dart.py +605 -0
- mcp_vector_search/parsers/html.py +413 -0
- mcp_vector_search/parsers/javascript.py +643 -0
- mcp_vector_search/parsers/php.py +694 -0
- mcp_vector_search/parsers/python.py +502 -0
- mcp_vector_search/parsers/registry.py +223 -0
- mcp_vector_search/parsers/ruby.py +678 -0
- mcp_vector_search/parsers/text.py +186 -0
- mcp_vector_search/parsers/utils.py +265 -0
- mcp_vector_search/py.typed +1 -0
- mcp_vector_search/utils/__init__.py +42 -0
- mcp_vector_search/utils/gitignore.py +250 -0
- mcp_vector_search/utils/gitignore_updater.py +212 -0
- mcp_vector_search/utils/monorepo.py +339 -0
- mcp_vector_search/utils/timing.py +338 -0
- mcp_vector_search/utils/version.py +47 -0
- mcp_vector_search-0.15.7.dist-info/METADATA +884 -0
- mcp_vector_search-0.15.7.dist-info/RECORD +86 -0
- mcp_vector_search-0.15.7.dist-info/WHEEL +4 -0
- mcp_vector_search-0.15.7.dist-info/entry_points.txt +3 -0
- mcp_vector_search-0.15.7.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
"""Rich formatting and display utilities for CLI."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from loguru import logger
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.panel import Panel
|
|
10
|
+
from rich.progress import (
|
|
11
|
+
BarColumn,
|
|
12
|
+
MofNCompleteColumn,
|
|
13
|
+
Progress,
|
|
14
|
+
SpinnerColumn,
|
|
15
|
+
TextColumn,
|
|
16
|
+
TimeElapsedColumn,
|
|
17
|
+
)
|
|
18
|
+
from rich.syntax import Syntax
|
|
19
|
+
from rich.table import Table
|
|
20
|
+
|
|
21
|
+
from ..core.models import ProjectInfo, SearchResult
|
|
22
|
+
|
|
23
|
+
# Global console instance
|
|
24
|
+
console = Console()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def setup_logging(level: str = "WARNING") -> None:
|
|
28
|
+
"""Setup structured logging with rich formatting.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
level: Log level (DEBUG, INFO, WARNING, ERROR)
|
|
32
|
+
"""
|
|
33
|
+
# Remove all existing handlers
|
|
34
|
+
logger.remove()
|
|
35
|
+
|
|
36
|
+
# Only add console handler if level is DEBUG or INFO
|
|
37
|
+
# For WARNING and ERROR, we want minimal output
|
|
38
|
+
if level in ["DEBUG", "INFO"]:
|
|
39
|
+
logger.add(
|
|
40
|
+
sys.stderr,
|
|
41
|
+
level=level,
|
|
42
|
+
format="<green>{time:HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
|
|
43
|
+
colorize=True,
|
|
44
|
+
)
|
|
45
|
+
else:
|
|
46
|
+
# For WARNING and ERROR, use minimal format and only show WARNING+ messages
|
|
47
|
+
logger.add(
|
|
48
|
+
sys.stderr,
|
|
49
|
+
level=level,
|
|
50
|
+
format="<level>{level}</level>: <level>{message}</level>",
|
|
51
|
+
colorize=True,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def print_success(message: str) -> None:
|
|
56
|
+
"""Print success message."""
|
|
57
|
+
console.print(f"[green]ā[/green] {message}")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def print_error(message: str) -> None:
|
|
61
|
+
"""Print error message."""
|
|
62
|
+
console.print(f"[red]ā[/red] {message}")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def print_warning(message: str) -> None:
|
|
66
|
+
"""Print warning message."""
|
|
67
|
+
console.print(f"[yellow]ā [/yellow] {message}")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def print_info(message: str) -> None:
|
|
71
|
+
"""Print info message."""
|
|
72
|
+
console.print(f"[blue]ā¹[/blue] {message}")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def create_progress() -> Progress:
|
|
76
|
+
"""Create a progress bar for long-running operations."""
|
|
77
|
+
return Progress(
|
|
78
|
+
SpinnerColumn(),
|
|
79
|
+
TextColumn("[progress.description]{task.description}"),
|
|
80
|
+
BarColumn(),
|
|
81
|
+
MofNCompleteColumn(),
|
|
82
|
+
TimeElapsedColumn(),
|
|
83
|
+
console=console,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def print_project_info(project_info: ProjectInfo) -> None:
|
|
88
|
+
"""Print project information in a formatted table."""
|
|
89
|
+
table = Table(title="Project Information", show_header=False)
|
|
90
|
+
table.add_column("Property", style="cyan", no_wrap=True)
|
|
91
|
+
table.add_column("Value", style="white")
|
|
92
|
+
|
|
93
|
+
table.add_row("Name", project_info.name)
|
|
94
|
+
table.add_row("Root Path", str(project_info.root_path))
|
|
95
|
+
table.add_row("Config Path", str(project_info.config_path))
|
|
96
|
+
table.add_row("Index Path", str(project_info.index_path))
|
|
97
|
+
table.add_row("Initialized", "ā" if project_info.is_initialized else "ā")
|
|
98
|
+
table.add_row(
|
|
99
|
+
"Languages",
|
|
100
|
+
(
|
|
101
|
+
", ".join(project_info.languages)
|
|
102
|
+
if project_info.languages
|
|
103
|
+
else "None detected"
|
|
104
|
+
),
|
|
105
|
+
)
|
|
106
|
+
table.add_row("Indexable Files", str(project_info.file_count))
|
|
107
|
+
|
|
108
|
+
console.print(table)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def print_search_results(
|
|
112
|
+
results: list[SearchResult],
|
|
113
|
+
query: str,
|
|
114
|
+
show_content: bool = True,
|
|
115
|
+
max_content_lines: int = 10,
|
|
116
|
+
) -> None:
|
|
117
|
+
"""Print search results in a formatted display."""
|
|
118
|
+
if not results:
|
|
119
|
+
print_warning(f"No results found for query: '{query}'")
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
console.print(
|
|
123
|
+
f"\n[bold blue]Search Results for:[/bold blue] [green]'{query}'[/green]"
|
|
124
|
+
)
|
|
125
|
+
console.print(f"[dim]Found {len(results)} results[/dim]\n")
|
|
126
|
+
|
|
127
|
+
for i, result in enumerate(results, 1):
|
|
128
|
+
# Create result header
|
|
129
|
+
header = f"[bold]{i}. {result.file_path.name}[/bold]"
|
|
130
|
+
if result.function_name:
|
|
131
|
+
header += f" ā [cyan]{result.function_name}()[/cyan]"
|
|
132
|
+
if result.class_name:
|
|
133
|
+
header += f" in [yellow]{result.class_name}[/yellow]"
|
|
134
|
+
|
|
135
|
+
# Add location and similarity
|
|
136
|
+
location = f"[dim]{result.location}[/dim]"
|
|
137
|
+
similarity = f"[green]{result.similarity_score:.2%}[/green]"
|
|
138
|
+
|
|
139
|
+
console.print(f"{header}")
|
|
140
|
+
console.print(f" {location} | Similarity: {similarity}")
|
|
141
|
+
|
|
142
|
+
# Show code content if requested
|
|
143
|
+
if show_content and result.content:
|
|
144
|
+
content_lines = result.content.splitlines()
|
|
145
|
+
if len(content_lines) > max_content_lines:
|
|
146
|
+
content_lines = content_lines[:max_content_lines]
|
|
147
|
+
content_lines.append("...")
|
|
148
|
+
|
|
149
|
+
content = "\n".join(content_lines)
|
|
150
|
+
|
|
151
|
+
# Create syntax-highlighted code block
|
|
152
|
+
syntax = Syntax(
|
|
153
|
+
content,
|
|
154
|
+
result.language,
|
|
155
|
+
theme="monokai",
|
|
156
|
+
line_numbers=True,
|
|
157
|
+
start_line=result.start_line,
|
|
158
|
+
word_wrap=True,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
console.print(Panel(syntax, border_style="dim"))
|
|
162
|
+
|
|
163
|
+
console.print() # Empty line between results
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def print_index_stats(stats: dict[str, Any]) -> None:
|
|
167
|
+
"""Print indexing statistics."""
|
|
168
|
+
table = Table(title="Index Statistics", show_header=False)
|
|
169
|
+
table.add_column("Metric", style="cyan", no_wrap=True)
|
|
170
|
+
table.add_column("Value", style="white")
|
|
171
|
+
|
|
172
|
+
table.add_row("Total Files", str(stats.get("total_indexable_files", 0)))
|
|
173
|
+
table.add_row("Indexed Files", str(stats.get("indexed_files", 0)))
|
|
174
|
+
table.add_row("Total Chunks", str(stats.get("total_chunks", 0)))
|
|
175
|
+
|
|
176
|
+
# Language distribution
|
|
177
|
+
languages = stats.get("languages", {})
|
|
178
|
+
if languages:
|
|
179
|
+
lang_str = ", ".join(f"{lang}: {count}" for lang, count in languages.items())
|
|
180
|
+
table.add_row("Languages", lang_str)
|
|
181
|
+
|
|
182
|
+
# File extensions
|
|
183
|
+
extensions = stats.get("file_extensions", [])
|
|
184
|
+
if extensions:
|
|
185
|
+
table.add_row("Extensions", ", ".join(extensions))
|
|
186
|
+
|
|
187
|
+
console.print(table)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def print_config(config_dict: dict[str, Any]) -> None:
|
|
191
|
+
"""Print configuration in a formatted table."""
|
|
192
|
+
table = Table(title="Configuration", show_header=False)
|
|
193
|
+
table.add_column("Setting", style="cyan", no_wrap=True)
|
|
194
|
+
table.add_column("Value", style="white")
|
|
195
|
+
|
|
196
|
+
for key, value in config_dict.items():
|
|
197
|
+
if isinstance(value, list | dict):
|
|
198
|
+
value_str = str(value)
|
|
199
|
+
elif isinstance(value, Path):
|
|
200
|
+
value_str = str(value)
|
|
201
|
+
else:
|
|
202
|
+
value_str = str(value)
|
|
203
|
+
|
|
204
|
+
table.add_row(key.replace("_", " ").title(), value_str)
|
|
205
|
+
|
|
206
|
+
console.print(table)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def confirm_action(message: str, default: bool = False) -> bool:
|
|
210
|
+
"""Ask for user confirmation."""
|
|
211
|
+
default_str = "Y/n" if default else "y/N"
|
|
212
|
+
response = console.input(f"{message} [{default_str}]: ").strip().lower()
|
|
213
|
+
|
|
214
|
+
if not response:
|
|
215
|
+
return default
|
|
216
|
+
|
|
217
|
+
return response in ("y", "yes", "true", "1")
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def print_banner() -> None:
|
|
221
|
+
"""Print application banner."""
|
|
222
|
+
banner = """
|
|
223
|
+
[bold blue]MCP Vector Search[/bold blue]
|
|
224
|
+
[dim]CLI-first semantic code search with MCP integration[/dim]
|
|
225
|
+
"""
|
|
226
|
+
console.print(Panel(banner.strip(), border_style="blue"))
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def format_file_path(file_path: Path, project_root: Path | None = None) -> str:
|
|
230
|
+
"""Format file path for display (relative to project root if possible)."""
|
|
231
|
+
if project_root:
|
|
232
|
+
try:
|
|
233
|
+
relative_path = file_path.relative_to(project_root)
|
|
234
|
+
return str(relative_path)
|
|
235
|
+
except ValueError:
|
|
236
|
+
pass
|
|
237
|
+
|
|
238
|
+
return str(file_path)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def print_dependency_status(
|
|
242
|
+
name: str, available: bool, version: str | None = None
|
|
243
|
+
) -> None:
|
|
244
|
+
"""Print dependency status."""
|
|
245
|
+
if available:
|
|
246
|
+
version_str = f" ({version})" if version else ""
|
|
247
|
+
console.print(f"[green]ā[/green] {name}{version_str}")
|
|
248
|
+
else:
|
|
249
|
+
console.print(f"[red]ā[/red] {name} - Not available")
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def print_json(data: Any, title: str | None = None) -> None:
|
|
253
|
+
"""Print data as formatted JSON."""
|
|
254
|
+
import json
|
|
255
|
+
|
|
256
|
+
json_str = json.dumps(data, indent=2, default=str)
|
|
257
|
+
syntax = Syntax(json_str, "json", theme="monokai")
|
|
258
|
+
|
|
259
|
+
if title:
|
|
260
|
+
console.print(Panel(syntax, title=title, border_style="blue"))
|
|
261
|
+
else:
|
|
262
|
+
console.print(syntax)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def print_panel(
|
|
266
|
+
content: str,
|
|
267
|
+
title: str | None = None,
|
|
268
|
+
border_style: str = "blue",
|
|
269
|
+
padding: tuple[int, int] = (1, 2),
|
|
270
|
+
) -> None:
|
|
271
|
+
"""Print content in a Rich panel.
|
|
272
|
+
|
|
273
|
+
Args:
|
|
274
|
+
content: The content to display in the panel
|
|
275
|
+
title: Optional title for the panel
|
|
276
|
+
border_style: Border color/style (default: "blue")
|
|
277
|
+
padding: Tuple of (vertical, horizontal) padding
|
|
278
|
+
"""
|
|
279
|
+
console.print(
|
|
280
|
+
Panel(
|
|
281
|
+
content,
|
|
282
|
+
title=title,
|
|
283
|
+
border_style=border_style,
|
|
284
|
+
padding=padding,
|
|
285
|
+
)
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def print_next_steps(steps: list[str], title: str = "Next Steps") -> None:
|
|
290
|
+
"""Print next step hints after a command execution.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
steps: List of next step descriptions
|
|
294
|
+
title: Panel title (default: "Next Steps")
|
|
295
|
+
"""
|
|
296
|
+
content = "\n".join(f" {i}. {step}" for i, step in enumerate(steps, 1))
|
|
297
|
+
print_panel(content, title=f"š {title}", border_style="blue")
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def print_tip(message: str) -> None:
|
|
301
|
+
"""Print a helpful tip message.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
message: The tip message to display
|
|
305
|
+
"""
|
|
306
|
+
console.print(f"[dim]š” Tip: {message}[/dim]")
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def print_completion_status(
|
|
310
|
+
title: str,
|
|
311
|
+
completed_items: list[str],
|
|
312
|
+
pending_items: list[str] | None = None,
|
|
313
|
+
) -> None:
|
|
314
|
+
"""Print completion status with checkmarks.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
title: Status title
|
|
318
|
+
completed_items: List of completed items
|
|
319
|
+
pending_items: Optional list of pending items
|
|
320
|
+
"""
|
|
321
|
+
content_lines = []
|
|
322
|
+
|
|
323
|
+
if completed_items:
|
|
324
|
+
content_lines.append("[bold green]⨠Completed:[/bold green]")
|
|
325
|
+
for item in completed_items:
|
|
326
|
+
content_lines.append(f" ā
{item}")
|
|
327
|
+
|
|
328
|
+
if pending_items:
|
|
329
|
+
content_lines.append("\n[bold yellow]š Pending:[/bold yellow]")
|
|
330
|
+
for item in pending_items:
|
|
331
|
+
content_lines.append(f" ā {item}")
|
|
332
|
+
|
|
333
|
+
print_panel("\n".join(content_lines), title=title, border_style="green")
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def print_setup_progress(
|
|
337
|
+
completed_steps: list[str],
|
|
338
|
+
all_steps: list[tuple[str, str]] | None = None,
|
|
339
|
+
) -> None:
|
|
340
|
+
"""Display setup workflow progress.
|
|
341
|
+
|
|
342
|
+
Args:
|
|
343
|
+
completed_steps: List of completed step IDs
|
|
344
|
+
all_steps: Optional list of (step_id, step_name) tuples
|
|
345
|
+
"""
|
|
346
|
+
if all_steps is None:
|
|
347
|
+
all_steps = [
|
|
348
|
+
("initialize", "Initialize project"),
|
|
349
|
+
("configure", "Configure settings"),
|
|
350
|
+
("index", "Index codebase"),
|
|
351
|
+
("mcp_setup", "Setup MCP integration"),
|
|
352
|
+
("verify", "Verify installation"),
|
|
353
|
+
]
|
|
354
|
+
|
|
355
|
+
completed = len([s for s, _ in all_steps if s in completed_steps])
|
|
356
|
+
total = len(all_steps)
|
|
357
|
+
percentage = (completed / total) * 100
|
|
358
|
+
|
|
359
|
+
console.print(f"\nš Setup Progress: {completed}/{total} ({percentage:.0f}%)")
|
|
360
|
+
|
|
361
|
+
for step_id, step_name in all_steps:
|
|
362
|
+
status = "ā" if step_id in completed_steps else "ā"
|
|
363
|
+
style = "green" if step_id in completed_steps else "dim"
|
|
364
|
+
console.print(f" {status} {step_name}", style=style)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def print_error_with_recovery(error_message: str, recovery_steps: list[str]) -> None:
|
|
368
|
+
"""Print error message with recovery hints.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
error_message: The error message
|
|
372
|
+
recovery_steps: List of recovery step descriptions
|
|
373
|
+
"""
|
|
374
|
+
print_error(error_message)
|
|
375
|
+
|
|
376
|
+
console.print("\n[bold]How to fix:[/bold]")
|
|
377
|
+
for i, step in enumerate(recovery_steps, 1):
|
|
378
|
+
console.print(f" {i}. {step}")
|
|
379
|
+
|
|
380
|
+
console.print("\n[dim]For more help: mcp-vector-search --help[/dim]")
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def print_command_examples(
|
|
384
|
+
command: str,
|
|
385
|
+
examples: list[tuple[str, str]],
|
|
386
|
+
) -> None:
|
|
387
|
+
"""Print command examples in a formatted table.
|
|
388
|
+
|
|
389
|
+
Args:
|
|
390
|
+
command: Base command name
|
|
391
|
+
examples: List of (description, example) tuples
|
|
392
|
+
"""
|
|
393
|
+
table = Table(
|
|
394
|
+
title=f"Examples: {command}",
|
|
395
|
+
show_header=True,
|
|
396
|
+
header_style="bold cyan",
|
|
397
|
+
)
|
|
398
|
+
table.add_column("Description", style="white", no_wrap=False)
|
|
399
|
+
table.add_column("Command", style="green", no_wrap=False)
|
|
400
|
+
|
|
401
|
+
for description, example in examples:
|
|
402
|
+
table.add_row(description, example)
|
|
403
|
+
|
|
404
|
+
console.print(table)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def print_config_hint(config_type: str, config_path: str) -> None:
|
|
408
|
+
"""Print configuration file location hint.
|
|
409
|
+
|
|
410
|
+
Args:
|
|
411
|
+
config_type: Type of configuration (e.g., "Claude Code", "Project")
|
|
412
|
+
config_path: Path to the configuration file
|
|
413
|
+
"""
|
|
414
|
+
console.print(f"[dim]š” {config_type} config: {config_path}[/dim]")
|