mcp-vector-search 0.4.11__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 +2 -2
- mcp_vector_search/cli/commands/init.py +5 -6
- mcp_vector_search/cli/commands/reset.py +393 -0
- mcp_vector_search/cli/didyoumean.py +374 -75
- mcp_vector_search/cli/main.py +117 -5
- 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 +38 -14
- {mcp_vector_search-0.4.11.dist-info → mcp_vector_search-0.4.13.dist-info}/METADATA +1 -1
- {mcp_vector_search-0.4.11.dist-info → mcp_vector_search-0.4.13.dist-info}/RECORD +15 -13
- mcp_vector_search-0.4.13.dist-info/entry_points.txt +2 -0
- mcp_vector_search-0.4.11.dist-info/entry_points.txt +0 -2
- {mcp_vector_search-0.4.11.dist-info → mcp_vector_search-0.4.13.dist-info}/WHEEL +0 -0
- {mcp_vector_search-0.4.11.dist-info → mcp_vector_search-0.4.13.dist-info}/licenses/LICENSE +0 -0
mcp_vector_search/cli/main.py
CHANGED
|
@@ -11,7 +11,13 @@ from .. import __build__, __version__
|
|
|
11
11
|
from .commands.auto_index import auto_index_app
|
|
12
12
|
from .commands.config import config_app
|
|
13
13
|
from .commands.index import index_app
|
|
14
|
-
from .commands.init import
|
|
14
|
+
from .commands.init import (
|
|
15
|
+
init_app,
|
|
16
|
+
main as init_main,
|
|
17
|
+
check_initialization as init_check,
|
|
18
|
+
init_mcp_integration,
|
|
19
|
+
list_embedding_models,
|
|
20
|
+
)
|
|
15
21
|
from .commands.install import install_app
|
|
16
22
|
from .commands.mcp import mcp_app
|
|
17
23
|
from .commands.search import (
|
|
@@ -22,7 +28,9 @@ from .commands.search import (
|
|
|
22
28
|
)
|
|
23
29
|
from .commands.status import status_app
|
|
24
30
|
from .commands.watch import app as watch_app
|
|
31
|
+
from .commands.reset import reset_app, health_main
|
|
25
32
|
from .didyoumean import create_enhanced_typer, add_common_suggestions
|
|
33
|
+
from .suggestions import get_contextual_suggestions, ContextualSuggestionProvider
|
|
26
34
|
from .output import print_error, setup_logging
|
|
27
35
|
|
|
28
36
|
# Install rich traceback handler
|
|
@@ -39,18 +47,26 @@ app = create_enhanced_typer(
|
|
|
39
47
|
rich_markup_mode="rich",
|
|
40
48
|
)
|
|
41
49
|
|
|
42
|
-
#
|
|
50
|
+
# Import command functions for direct registration and aliases
|
|
43
51
|
from .commands.install import main as install_main, demo as install_demo
|
|
44
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
|
|
45
55
|
app.command("install", help="🚀 Install mcp-vector-search in projects")(install_main)
|
|
46
56
|
app.command("demo", help="🎬 Run installation demo with sample project")(install_demo)
|
|
47
57
|
app.command("status", help="📊 Show project status and statistics")(status_main)
|
|
48
|
-
|
|
58
|
+
# Register init as a direct command
|
|
59
|
+
app.command("init", help="🔧 Initialize project for semantic search")(init_main)
|
|
60
|
+
# Add init subcommands as separate commands
|
|
61
|
+
app.command("init-check", help="Check if project is initialized")(init_check)
|
|
62
|
+
app.command("init-mcp", help="Install/fix Claude Code MCP integration")(init_mcp_integration)
|
|
63
|
+
app.command("init-models", help="List available embedding models")(list_embedding_models)
|
|
49
64
|
app.add_typer(index_app, name="index", help="Index codebase for semantic search")
|
|
50
65
|
app.add_typer(config_app, name="config", help="Manage project configuration")
|
|
51
66
|
app.add_typer(watch_app, name="watch", help="Watch for file changes and update index")
|
|
52
67
|
app.add_typer(auto_index_app, name="auto-index", help="Manage automatic indexing")
|
|
53
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")
|
|
54
70
|
|
|
55
71
|
# Add search command - simplified syntax as default
|
|
56
72
|
app.command("search", help="Search code semantically")(search_main)
|
|
@@ -58,13 +74,34 @@ app.command("search", help="Search code semantically")(search_main)
|
|
|
58
74
|
# Keep old nested structure for backward compatibility
|
|
59
75
|
app.add_typer(search_app, name="search-legacy", help="Legacy search commands", hidden=True)
|
|
60
76
|
app.add_typer(status_app, name="status-legacy", help="Legacy status commands", hidden=True)
|
|
77
|
+
|
|
78
|
+
# Add command aliases for better user experience
|
|
61
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
|
|
62
98
|
app.command("search-similar", help="Find code similar to a specific file or function")(
|
|
63
99
|
search_similar_cmd
|
|
64
100
|
)
|
|
65
101
|
app.command("search-context", help="Search for code based on contextual description")(
|
|
66
102
|
search_context_cmd
|
|
67
103
|
)
|
|
104
|
+
app.command("health", help="Check index health and optionally repair")(health_main)
|
|
68
105
|
|
|
69
106
|
|
|
70
107
|
# Add interactive search command
|
|
@@ -197,6 +234,8 @@ def main(
|
|
|
197
234
|
if project_root:
|
|
198
235
|
logger.info(f"Using project root: {project_root}")
|
|
199
236
|
|
|
237
|
+
# Note: Contextual help moved to a separate command to avoid interfering with didyoumean
|
|
238
|
+
|
|
200
239
|
|
|
201
240
|
@app.command()
|
|
202
241
|
def version() -> None:
|
|
@@ -209,7 +248,7 @@ def version() -> None:
|
|
|
209
248
|
|
|
210
249
|
|
|
211
250
|
def handle_command_error(ctx, param, value):
|
|
212
|
-
"""Handle command errors with suggestions."""
|
|
251
|
+
"""Handle command errors with enhanced suggestions."""
|
|
213
252
|
if ctx.resilient_parsing:
|
|
214
253
|
return
|
|
215
254
|
|
|
@@ -224,10 +263,34 @@ def handle_command_error(ctx, param, value):
|
|
|
224
263
|
match = re.search(r"No such command '([^']+)'", str(e))
|
|
225
264
|
if match:
|
|
226
265
|
command_name = match.group(1)
|
|
266
|
+
|
|
267
|
+
# Use both the original suggestions and contextual suggestions
|
|
227
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
|
|
228
277
|
raise
|
|
229
278
|
|
|
230
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
|
+
|
|
231
294
|
@app.command()
|
|
232
295
|
def doctor() -> None:
|
|
233
296
|
"""Check system dependencies and configuration."""
|
|
@@ -250,5 +313,54 @@ def doctor() -> None:
|
|
|
250
313
|
|
|
251
314
|
|
|
252
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
|
+
|
|
253
365
|
if __name__ == "__main__":
|
|
254
|
-
|
|
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]
|