mcp-vector-search 0.4.12__py3-none-any.whl → 0.4.13__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 +1 -1
- mcp_vector_search/cli/commands/reset.py +393 -0
- mcp_vector_search/cli/didyoumean.py +374 -75
- mcp_vector_search/cli/main.py +104 -3
- mcp_vector_search/cli/suggestions.py +325 -0
- mcp_vector_search/core/database.py +213 -6
- mcp_vector_search/core/exceptions.py +6 -0
- mcp_vector_search/core/search.py +24 -2
- mcp_vector_search/mcp/server.py +36 -12
- {mcp_vector_search-0.4.12.dist-info → mcp_vector_search-0.4.13.dist-info}/METADATA +1 -1
- {mcp_vector_search-0.4.12.dist-info → mcp_vector_search-0.4.13.dist-info}/RECORD +14 -12
- mcp_vector_search-0.4.13.dist-info/entry_points.txt +2 -0
- mcp_vector_search-0.4.12.dist-info/entry_points.txt +0 -2
- {mcp_vector_search-0.4.12.dist-info → mcp_vector_search-0.4.13.dist-info}/WHEEL +0 -0
- {mcp_vector_search-0.4.12.dist-info → mcp_vector_search-0.4.13.dist-info}/licenses/LICENSE +0 -0
mcp_vector_search/cli/main.py
CHANGED
|
@@ -28,7 +28,9 @@ from .commands.search import (
|
|
|
28
28
|
)
|
|
29
29
|
from .commands.status import status_app
|
|
30
30
|
from .commands.watch import app as watch_app
|
|
31
|
+
from .commands.reset import reset_app, health_main
|
|
31
32
|
from .didyoumean import create_enhanced_typer, add_common_suggestions
|
|
33
|
+
from .suggestions import get_contextual_suggestions, ContextualSuggestionProvider
|
|
32
34
|
from .output import print_error, setup_logging
|
|
33
35
|
|
|
34
36
|
# Install rich traceback handler
|
|
@@ -45,9 +47,11 @@ app = create_enhanced_typer(
|
|
|
45
47
|
rich_markup_mode="rich",
|
|
46
48
|
)
|
|
47
49
|
|
|
48
|
-
#
|
|
50
|
+
# Import command functions for direct registration and aliases
|
|
49
51
|
from .commands.install import main as install_main, demo as install_demo
|
|
50
52
|
from .commands.status import main as status_main
|
|
53
|
+
from .commands.index import main as index_main
|
|
54
|
+
# Note: config doesn't have a main function, it uses subcommands via config_app
|
|
51
55
|
app.command("install", help="🚀 Install mcp-vector-search in projects")(install_main)
|
|
52
56
|
app.command("demo", help="🎬 Run installation demo with sample project")(install_demo)
|
|
53
57
|
app.command("status", help="📊 Show project status and statistics")(status_main)
|
|
@@ -62,6 +66,7 @@ app.add_typer(config_app, name="config", help="Manage project configuration")
|
|
|
62
66
|
app.add_typer(watch_app, name="watch", help="Watch for file changes and update index")
|
|
63
67
|
app.add_typer(auto_index_app, name="auto-index", help="Manage automatic indexing")
|
|
64
68
|
app.add_typer(mcp_app, name="mcp", help="Manage Claude Code MCP integration")
|
|
69
|
+
app.add_typer(reset_app, name="reset", help="Reset and recovery operations")
|
|
65
70
|
|
|
66
71
|
# Add search command - simplified syntax as default
|
|
67
72
|
app.command("search", help="Search code semantically")(search_main)
|
|
@@ -69,13 +74,34 @@ app.command("search", help="Search code semantically")(search_main)
|
|
|
69
74
|
# Keep old nested structure for backward compatibility
|
|
70
75
|
app.add_typer(search_app, name="search-legacy", help="Legacy search commands", hidden=True)
|
|
71
76
|
app.add_typer(status_app, name="status-legacy", help="Legacy status commands", hidden=True)
|
|
77
|
+
|
|
78
|
+
# Add command aliases for better user experience
|
|
72
79
|
app.command("find", help="Search code semantically (alias for search)")(search_main)
|
|
80
|
+
app.command("f", help="Search code semantically (short alias)", hidden=True)(search_main) # Hidden short alias
|
|
81
|
+
app.command("s", help="Search code semantically (short alias)", hidden=True)(search_main) # Hidden short alias
|
|
82
|
+
app.command("query", help="Search code semantically (alias for search)", hidden=True)(search_main) # Hidden alias
|
|
83
|
+
|
|
84
|
+
# Index aliases
|
|
85
|
+
app.command("i", help="Index codebase (short alias)", hidden=True)(index_main) # Hidden short alias
|
|
86
|
+
app.command("build", help="Index codebase (alias for index)", hidden=True)(index_main) # Hidden alias
|
|
87
|
+
app.command("scan", help="Index codebase (alias for index)", hidden=True)(index_main) # Hidden alias
|
|
88
|
+
|
|
89
|
+
# Status aliases
|
|
90
|
+
app.command("st", help="Show status (short alias)", hidden=True)(status_main) # Hidden short alias
|
|
91
|
+
app.command("info", help="Show project information (alias for status)", hidden=True)(status_main) # Hidden alias
|
|
92
|
+
|
|
93
|
+
# Config aliases - Since config uses subcommands, these will be handled by the enhanced typer error resolution
|
|
94
|
+
# app.command("c", help="Manage configuration (short alias)", hidden=True) # Will be handled by typo resolution
|
|
95
|
+
# app.command("cfg", help="Manage configuration (alias for config)", hidden=True) # Will be handled by typo resolution
|
|
96
|
+
|
|
97
|
+
# Specialized search commands
|
|
73
98
|
app.command("search-similar", help="Find code similar to a specific file or function")(
|
|
74
99
|
search_similar_cmd
|
|
75
100
|
)
|
|
76
101
|
app.command("search-context", help="Search for code based on contextual description")(
|
|
77
102
|
search_context_cmd
|
|
78
103
|
)
|
|
104
|
+
app.command("health", help="Check index health and optionally repair")(health_main)
|
|
79
105
|
|
|
80
106
|
|
|
81
107
|
# Add interactive search command
|
|
@@ -208,6 +234,8 @@ def main(
|
|
|
208
234
|
if project_root:
|
|
209
235
|
logger.info(f"Using project root: {project_root}")
|
|
210
236
|
|
|
237
|
+
# Note: Contextual help moved to a separate command to avoid interfering with didyoumean
|
|
238
|
+
|
|
211
239
|
|
|
212
240
|
@app.command()
|
|
213
241
|
def version() -> None:
|
|
@@ -220,7 +248,7 @@ def version() -> None:
|
|
|
220
248
|
|
|
221
249
|
|
|
222
250
|
def handle_command_error(ctx, param, value):
|
|
223
|
-
"""Handle command errors with suggestions."""
|
|
251
|
+
"""Handle command errors with enhanced suggestions."""
|
|
224
252
|
if ctx.resilient_parsing:
|
|
225
253
|
return
|
|
226
254
|
|
|
@@ -235,10 +263,34 @@ def handle_command_error(ctx, param, value):
|
|
|
235
263
|
match = re.search(r"No such command '([^']+)'", str(e))
|
|
236
264
|
if match:
|
|
237
265
|
command_name = match.group(1)
|
|
266
|
+
|
|
267
|
+
# Use both the original suggestions and contextual suggestions
|
|
238
268
|
add_common_suggestions(ctx, command_name)
|
|
269
|
+
|
|
270
|
+
# Add contextual suggestions based on project state
|
|
271
|
+
try:
|
|
272
|
+
project_root = ctx.obj.get("project_root") if ctx.obj else None
|
|
273
|
+
get_contextual_suggestions(project_root, command_name)
|
|
274
|
+
except Exception:
|
|
275
|
+
# If contextual suggestions fail, don't break the error flow
|
|
276
|
+
pass
|
|
239
277
|
raise
|
|
240
278
|
|
|
241
279
|
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
@app.command()
|
|
283
|
+
def help_contextual() -> None:
|
|
284
|
+
"""Show contextual help and suggestions based on project state."""
|
|
285
|
+
try:
|
|
286
|
+
project_root = Path.cwd()
|
|
287
|
+
console.print(f"[bold blue]mcp-vector-search[/bold blue] version [green]{__version__}[/green]")
|
|
288
|
+
console.print("[dim]CLI-first semantic code search with MCP integration[/dim]")
|
|
289
|
+
get_contextual_suggestions(project_root)
|
|
290
|
+
except Exception as e:
|
|
291
|
+
console.print("\n[dim]Use [bold]mcp-vector-search --help[/bold] for more information.[/dim]")
|
|
292
|
+
|
|
293
|
+
|
|
242
294
|
@app.command()
|
|
243
295
|
def doctor() -> None:
|
|
244
296
|
"""Check system dependencies and configuration."""
|
|
@@ -261,5 +313,54 @@ def doctor() -> None:
|
|
|
261
313
|
|
|
262
314
|
|
|
263
315
|
|
|
316
|
+
def cli_with_suggestions():
|
|
317
|
+
"""CLI wrapper that catches errors and provides suggestions."""
|
|
318
|
+
import sys
|
|
319
|
+
import click
|
|
320
|
+
|
|
321
|
+
try:
|
|
322
|
+
# Call the app with standalone_mode=False to get exceptions instead of sys.exit
|
|
323
|
+
app(standalone_mode=False)
|
|
324
|
+
except click.UsageError as e:
|
|
325
|
+
# Check if it's a "No such command" error
|
|
326
|
+
if "No such command" in str(e):
|
|
327
|
+
# Extract the command name from the error
|
|
328
|
+
import re
|
|
329
|
+
match = re.search(r"No such command '([^']+)'", str(e))
|
|
330
|
+
if match:
|
|
331
|
+
command_name = match.group(1)
|
|
332
|
+
|
|
333
|
+
# Show enhanced suggestions
|
|
334
|
+
from rich.console import Console
|
|
335
|
+
console = Console(stderr=True)
|
|
336
|
+
console.print(f"\\n[red]Error:[/red] {e}")
|
|
337
|
+
|
|
338
|
+
# Show enhanced suggestions
|
|
339
|
+
add_common_suggestions(None, command_name)
|
|
340
|
+
|
|
341
|
+
# Show contextual suggestions too
|
|
342
|
+
try:
|
|
343
|
+
project_root = Path.cwd()
|
|
344
|
+
get_contextual_suggestions(project_root, command_name)
|
|
345
|
+
except Exception:
|
|
346
|
+
pass
|
|
347
|
+
|
|
348
|
+
sys.exit(2) # Exit with error code
|
|
349
|
+
|
|
350
|
+
# For other usage errors, show the default message and exit
|
|
351
|
+
click.echo(f"Error: {e}", err=True)
|
|
352
|
+
sys.exit(2)
|
|
353
|
+
except click.Abort:
|
|
354
|
+
# User interrupted (Ctrl+C)
|
|
355
|
+
sys.exit(1)
|
|
356
|
+
except SystemExit as e:
|
|
357
|
+
# Re-raise system exits
|
|
358
|
+
raise
|
|
359
|
+
except Exception as e:
|
|
360
|
+
# For other exceptions, show error and exit
|
|
361
|
+
click.echo(f"Unexpected error: {e}", err=True)
|
|
362
|
+
sys.exit(1)
|
|
363
|
+
|
|
364
|
+
|
|
264
365
|
if __name__ == "__main__":
|
|
265
|
-
|
|
366
|
+
cli_with_suggestions()
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
"""Contextual suggestion system for better user experience."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Dict, List, Optional, Set, Tuple
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
|
|
8
|
+
from ..core.project import ProjectManager
|
|
9
|
+
from ..core.exceptions import ProjectNotFoundError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ContextualSuggestionProvider:
|
|
13
|
+
"""Provides context-aware suggestions based on project state and user workflow."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, project_root: Optional[Path] = None):
|
|
16
|
+
"""Initialize the suggestion provider.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
project_root: Root directory of the project (defaults to current directory)
|
|
20
|
+
"""
|
|
21
|
+
self.project_root = project_root or Path.cwd()
|
|
22
|
+
self.console = Console(stderr=True)
|
|
23
|
+
|
|
24
|
+
def get_project_state(self) -> Dict[str, bool]:
|
|
25
|
+
"""Analyze the current project state.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Dictionary with boolean flags indicating project state
|
|
29
|
+
"""
|
|
30
|
+
state = {
|
|
31
|
+
'is_initialized': False,
|
|
32
|
+
'has_index': False,
|
|
33
|
+
'has_config': False,
|
|
34
|
+
'has_recent_changes': False,
|
|
35
|
+
'is_git_repo': False,
|
|
36
|
+
'has_mcp_config': False
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
# Check if project is initialized
|
|
41
|
+
config_dir = self.project_root / '.mcp-vector-search'
|
|
42
|
+
state['is_initialized'] = config_dir.exists()
|
|
43
|
+
|
|
44
|
+
if state['is_initialized']:
|
|
45
|
+
# Check for config
|
|
46
|
+
config_file = config_dir / 'config.json'
|
|
47
|
+
state['has_config'] = config_file.exists()
|
|
48
|
+
|
|
49
|
+
# Check for index
|
|
50
|
+
index_dir = config_dir / 'chroma_db'
|
|
51
|
+
state['has_index'] = index_dir.exists() and any(index_dir.iterdir())
|
|
52
|
+
|
|
53
|
+
# Check if it's a git repo
|
|
54
|
+
git_dir = self.project_root / '.git'
|
|
55
|
+
state['is_git_repo'] = git_dir.exists()
|
|
56
|
+
|
|
57
|
+
# Check for MCP configuration (Claude Desktop config)
|
|
58
|
+
home = Path.home()
|
|
59
|
+
claude_config = home / 'Library' / 'Application Support' / 'Claude' / 'claude_desktop_config.json'
|
|
60
|
+
if claude_config.exists():
|
|
61
|
+
try:
|
|
62
|
+
with open(claude_config) as f:
|
|
63
|
+
config_data = json.load(f)
|
|
64
|
+
mcp_servers = config_data.get('mcpServers', {})
|
|
65
|
+
state['has_mcp_config'] = 'mcp-vector-search' in mcp_servers
|
|
66
|
+
except (json.JSONDecodeError, IOError):
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
# TODO: Check for recent file changes (would need file system monitoring)
|
|
70
|
+
# For now, we'll assume false
|
|
71
|
+
state['has_recent_changes'] = False
|
|
72
|
+
|
|
73
|
+
except Exception:
|
|
74
|
+
# If we can't determine state, provide conservative defaults
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
return state
|
|
78
|
+
|
|
79
|
+
def get_workflow_suggestions(self, failed_command: str) -> List[Dict[str, str]]:
|
|
80
|
+
"""Get workflow-based suggestions for a failed command.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
failed_command: The command that failed
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
List of suggestion dictionaries with 'command', 'reason', and 'priority'
|
|
87
|
+
"""
|
|
88
|
+
suggestions = []
|
|
89
|
+
state = self.get_project_state()
|
|
90
|
+
|
|
91
|
+
# High priority suggestions based on project state
|
|
92
|
+
if not state['is_initialized']:
|
|
93
|
+
suggestions.append({
|
|
94
|
+
'command': 'init',
|
|
95
|
+
'reason': 'Project is not initialized for vector search',
|
|
96
|
+
'priority': 'high',
|
|
97
|
+
'description': 'Set up the project configuration and create necessary directories'
|
|
98
|
+
})
|
|
99
|
+
elif not state['has_index']:
|
|
100
|
+
suggestions.append({
|
|
101
|
+
'command': 'index',
|
|
102
|
+
'reason': 'No search index found - create one to enable searching',
|
|
103
|
+
'priority': 'high',
|
|
104
|
+
'description': 'Build the vector index for your codebase'
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
# Context-specific suggestions based on the failed command
|
|
108
|
+
if failed_command.lower() in ['search', 'find', 'query', 's', 'f']:
|
|
109
|
+
if not state['has_index']:
|
|
110
|
+
suggestions.append({
|
|
111
|
+
'command': 'index',
|
|
112
|
+
'reason': 'Cannot search without an index',
|
|
113
|
+
'priority': 'high',
|
|
114
|
+
'description': 'Build the search index first'
|
|
115
|
+
})
|
|
116
|
+
else:
|
|
117
|
+
suggestions.extend([
|
|
118
|
+
{
|
|
119
|
+
'command': 'search',
|
|
120
|
+
'reason': 'Correct command for semantic code search',
|
|
121
|
+
'priority': 'high',
|
|
122
|
+
'description': 'Search your codebase semantically'
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
'command': 'interactive',
|
|
126
|
+
'reason': 'Try interactive search for better experience',
|
|
127
|
+
'priority': 'medium',
|
|
128
|
+
'description': 'Start an interactive search session'
|
|
129
|
+
}
|
|
130
|
+
])
|
|
131
|
+
|
|
132
|
+
elif failed_command.lower() in ['index', 'build', 'scan', 'i', 'b']:
|
|
133
|
+
suggestions.append({
|
|
134
|
+
'command': 'index',
|
|
135
|
+
'reason': 'Correct command for building search index',
|
|
136
|
+
'priority': 'high',
|
|
137
|
+
'description': 'Index your codebase for semantic search'
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
elif failed_command.lower() in ['status', 'info', 'stat', 'st']:
|
|
141
|
+
suggestions.append({
|
|
142
|
+
'command': 'status',
|
|
143
|
+
'reason': 'Show project status and statistics',
|
|
144
|
+
'priority': 'high',
|
|
145
|
+
'description': 'Display current project information'
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
elif failed_command.lower() in ['config', 'configure', 'settings', 'c']:
|
|
149
|
+
suggestions.append({
|
|
150
|
+
'command': 'config',
|
|
151
|
+
'reason': 'Manage project configuration',
|
|
152
|
+
'priority': 'high',
|
|
153
|
+
'description': 'View or modify project settings'
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
# MCP-related suggestions
|
|
157
|
+
if not state['has_mcp_config'] and failed_command.lower() in ['mcp', 'claude', 'server']:
|
|
158
|
+
suggestions.append({
|
|
159
|
+
'command': 'init-mcp',
|
|
160
|
+
'reason': 'Set up Claude Code MCP integration',
|
|
161
|
+
'priority': 'medium',
|
|
162
|
+
'description': 'Configure MCP server for Claude Code integration'
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
# Remove duplicates while preserving order
|
|
166
|
+
seen = set()
|
|
167
|
+
unique_suggestions = []
|
|
168
|
+
for suggestion in suggestions:
|
|
169
|
+
key = suggestion['command']
|
|
170
|
+
if key not in seen:
|
|
171
|
+
seen.add(key)
|
|
172
|
+
unique_suggestions.append(suggestion)
|
|
173
|
+
|
|
174
|
+
return unique_suggestions
|
|
175
|
+
|
|
176
|
+
def get_next_steps(self) -> List[Dict[str, str]]:
|
|
177
|
+
"""Get suggested next steps based on current project state.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
List of suggested next step dictionaries
|
|
181
|
+
"""
|
|
182
|
+
state = self.get_project_state()
|
|
183
|
+
next_steps = []
|
|
184
|
+
|
|
185
|
+
if not state['is_initialized']:
|
|
186
|
+
next_steps.append({
|
|
187
|
+
'command': 'init',
|
|
188
|
+
'description': 'Initialize the project for semantic search',
|
|
189
|
+
'priority': 'high'
|
|
190
|
+
})
|
|
191
|
+
elif not state['has_index']:
|
|
192
|
+
next_steps.append({
|
|
193
|
+
'command': 'index',
|
|
194
|
+
'description': 'Build the search index for your codebase',
|
|
195
|
+
'priority': 'high'
|
|
196
|
+
})
|
|
197
|
+
else:
|
|
198
|
+
# Project is ready for use
|
|
199
|
+
next_steps.extend([
|
|
200
|
+
{
|
|
201
|
+
'command': 'search "your query here"',
|
|
202
|
+
'description': 'Search your codebase semantically',
|
|
203
|
+
'priority': 'high'
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
'command': 'status',
|
|
207
|
+
'description': 'Check project statistics and index health',
|
|
208
|
+
'priority': 'medium'
|
|
209
|
+
}
|
|
210
|
+
])
|
|
211
|
+
|
|
212
|
+
if state['has_recent_changes']:
|
|
213
|
+
next_steps.insert(0, {
|
|
214
|
+
'command': 'index --force',
|
|
215
|
+
'description': 'Update the index with recent changes',
|
|
216
|
+
'priority': 'high'
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
if not state['has_mcp_config'] and state['is_initialized']:
|
|
220
|
+
next_steps.append({
|
|
221
|
+
'command': 'init-mcp',
|
|
222
|
+
'description': 'Set up Claude Code integration',
|
|
223
|
+
'priority': 'low'
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
return next_steps
|
|
227
|
+
|
|
228
|
+
def show_contextual_help(self, failed_command: Optional[str] = None) -> None:
|
|
229
|
+
"""Show contextual help and suggestions.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
failed_command: The command that failed (if any)
|
|
233
|
+
"""
|
|
234
|
+
if failed_command:
|
|
235
|
+
self.console.print(f"\n[yellow]Command '{failed_command}' not recognized.[/yellow]")
|
|
236
|
+
|
|
237
|
+
suggestions = self.get_workflow_suggestions(failed_command)
|
|
238
|
+
if suggestions:
|
|
239
|
+
self.console.print("\n[bold]Based on your project state, you might want to try:[/bold]")
|
|
240
|
+
|
|
241
|
+
for i, suggestion in enumerate(suggestions[:3], 1): # Show top 3
|
|
242
|
+
priority_color = {
|
|
243
|
+
'high': 'red',
|
|
244
|
+
'medium': 'yellow',
|
|
245
|
+
'low': 'dim'
|
|
246
|
+
}.get(suggestion['priority'], 'white')
|
|
247
|
+
|
|
248
|
+
self.console.print(
|
|
249
|
+
f" [{priority_color}]{i}.[/{priority_color}] "
|
|
250
|
+
f"[bold cyan]mcp-vector-search {suggestion['command']}[/bold cyan]"
|
|
251
|
+
)
|
|
252
|
+
self.console.print(f" {suggestion['description']}")
|
|
253
|
+
if suggestion.get('reason'):
|
|
254
|
+
self.console.print(f" [dim]({suggestion['reason']})[/dim]")
|
|
255
|
+
else:
|
|
256
|
+
# Show general next steps
|
|
257
|
+
next_steps = self.get_next_steps()
|
|
258
|
+
if next_steps:
|
|
259
|
+
self.console.print("\n[bold]Suggested next steps:[/bold]")
|
|
260
|
+
|
|
261
|
+
for i, step in enumerate(next_steps[:3], 1):
|
|
262
|
+
priority_color = {
|
|
263
|
+
'high': 'green',
|
|
264
|
+
'medium': 'yellow',
|
|
265
|
+
'low': 'dim'
|
|
266
|
+
}.get(step['priority'], 'white')
|
|
267
|
+
|
|
268
|
+
self.console.print(
|
|
269
|
+
f" [{priority_color}]{i}.[/{priority_color}] "
|
|
270
|
+
f"[bold cyan]mcp-vector-search {step['command']}[/bold cyan]"
|
|
271
|
+
)
|
|
272
|
+
self.console.print(f" {step['description']}")
|
|
273
|
+
|
|
274
|
+
def get_command_completion_suggestions(self, partial_command: str) -> List[str]:
|
|
275
|
+
"""Get command completion suggestions for a partial command.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
partial_command: Partial command string
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
List of possible command completions
|
|
282
|
+
"""
|
|
283
|
+
all_commands = [
|
|
284
|
+
'search', 'index', 'status', 'config', 'init', 'mcp',
|
|
285
|
+
'doctor', 'version', 'watch', 'auto-index', 'history',
|
|
286
|
+
'interactive', 'demo', 'install', 'reset', 'health'
|
|
287
|
+
]
|
|
288
|
+
|
|
289
|
+
# Add common aliases and shortcuts
|
|
290
|
+
all_commands.extend(['s', 'i', 'st', 'c', 'f', 'find'])
|
|
291
|
+
|
|
292
|
+
partial_lower = partial_command.lower()
|
|
293
|
+
matches = [
|
|
294
|
+
cmd for cmd in all_commands
|
|
295
|
+
if cmd.startswith(partial_lower)
|
|
296
|
+
]
|
|
297
|
+
|
|
298
|
+
return sorted(matches)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def get_contextual_suggestions(project_root: Optional[Path] = None,
|
|
302
|
+
failed_command: Optional[str] = None) -> None:
|
|
303
|
+
"""Get and display contextual suggestions.
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
project_root: Root directory of the project
|
|
307
|
+
failed_command: The command that failed
|
|
308
|
+
"""
|
|
309
|
+
provider = ContextualSuggestionProvider(project_root)
|
|
310
|
+
provider.show_contextual_help(failed_command)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def suggest_workflow_commands(project_root: Optional[Path] = None) -> List[str]:
|
|
314
|
+
"""Get workflow command suggestions for the current project state.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
project_root: Root directory of the project
|
|
318
|
+
|
|
319
|
+
Returns:
|
|
320
|
+
List of suggested commands in priority order
|
|
321
|
+
"""
|
|
322
|
+
provider = ContextualSuggestionProvider(project_root)
|
|
323
|
+
next_steps = provider.get_next_steps()
|
|
324
|
+
|
|
325
|
+
return [step['command'] for step in next_steps]
|