siada-cli 0.0.1__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.
- agent_config.yaml +34 -0
- siada/__init__.py +13 -0
- siada/agent_hub/__init__.py +10 -0
- siada/agent_hub/coder/bug_fix_agent.py +398 -0
- siada/agent_hub/coder/code_gen_agent.py +235 -0
- siada/agent_hub/coder/fe_gen_agent.py +37 -0
- siada/agent_hub/coder/issue_review_agent.py +68 -0
- siada/agent_hub/coder/prompt/__init__.py +0 -0
- siada/agent_hub/coder/prompt/base/__init__.py +0 -0
- siada/agent_hub/coder/prompt/base/capabilities.py +18 -0
- siada/agent_hub/coder/prompt/base/non_interactive.py +14 -0
- siada/agent_hub/coder/prompt/base/prompt_builder.py +33 -0
- siada/agent_hub/coder/prompt/base/rules.py +40 -0
- siada/agent_hub/coder/prompt/base/tool_use.py +14 -0
- siada/agent_hub/coder/prompt/bug_prompt/bug_fix_prompt.py +51 -0
- siada/agent_hub/coder/prompt/bug_prompt/rules.py +53 -0
- siada/agent_hub/coder/prompt/code_gen_prompt.py +45 -0
- siada/agent_hub/coder/prompt/fe_gen_prompt.py +45 -0
- siada/agent_hub/coder/prompt/issue_review_prompt.py +121 -0
- siada/agent_hub/coder/tracing/__init__.py +22 -0
- siada/agent_hub/coder/tracing/logger_tracing_processor.py +458 -0
- siada/agent_hub/hooks/__init__.py +0 -0
- siada/agent_hub/hooks/io_hooks.py +30 -0
- siada/agent_hub/siada_agent.py +214 -0
- siada/config/__init__.py +0 -0
- siada/config/config_loader.py +67 -0
- siada/entrypoint/__init__.py +3 -0
- siada/entrypoint/args_parser/__init__.py +0 -0
- siada/entrypoint/args_parser/args.py +195 -0
- siada/entrypoint/interaction/__init__.py +0 -0
- siada/entrypoint/interaction/base_turn.py +107 -0
- siada/entrypoint/interaction/config.py +30 -0
- siada/entrypoint/interaction/controller.py +122 -0
- siada/entrypoint/interaction/nointeractive_controller.py +27 -0
- siada/entrypoint/interaction/turn/interface.py +116 -0
- siada/entrypoint/interaction/turn/models.py +34 -0
- siada/entrypoint/interaction/turn/run_turn.py +641 -0
- siada/entrypoint/interaction/turn_factory.py +35 -0
- siada/entrypoint/interaction/turn_models.py +28 -0
- siada/entrypoint/siadahub.py +413 -0
- siada/foundation/__init__.py +0 -0
- siada/foundation/code_agent_context.py +48 -0
- siada/foundation/config.py +59 -0
- siada/foundation/constants.py +2 -0
- siada/foundation/context.py +76 -0
- siada/foundation/logging.py +341 -0
- siada/foundation/tools/__init__.py +0 -0
- siada/foundation/tools/get_git_diff.py +105 -0
- siada/io/__init__.py +0 -0
- siada/io/banner.py +148 -0
- siada/io/color_settings.py +207 -0
- siada/io/color_utils.py +16 -0
- siada/io/components/__init__.py +0 -0
- siada/io/components/mdstream.py +204 -0
- siada/io/console_printer.py +68 -0
- siada/io/io.py +661 -0
- siada/io/key_bindings.py +129 -0
- siada/io/notification_command.py +40 -0
- siada/io/test_banner.py +64 -0
- siada/models/__init__.py +0 -0
- siada/models/agent.py +47 -0
- siada/models/coder/__init__.py +0 -0
- siada/models/converter.py +27 -0
- siada/models/model_base_config.py +121 -0
- siada/models/model_run_config.py +153 -0
- siada/provider/__init__.py +0 -0
- siada/provider/client_factory.py +112 -0
- siada/provider/llm_client.py +11 -0
- siada/provider/openrouter/__init__.py +0 -0
- siada/provider/openrouter/coverter.py +17 -0
- siada/provider/openrouter/openroute_provider.py +33 -0
- siada/provider/provider_factory.py +53 -0
- siada/queries/tree-sitter-language-pack/README.md +7 -0
- siada/queries/tree-sitter-language-pack/arduino-tags.scm +5 -0
- siada/queries/tree-sitter-language-pack/c-tags.scm +9 -0
- siada/queries/tree-sitter-language-pack/chatito-tags.scm +16 -0
- siada/queries/tree-sitter-language-pack/commonlisp-tags.scm +122 -0
- siada/queries/tree-sitter-language-pack/cpp-tags.scm +15 -0
- siada/queries/tree-sitter-language-pack/csharp-tags.scm +26 -0
- siada/queries/tree-sitter-language-pack/d-tags.scm +26 -0
- siada/queries/tree-sitter-language-pack/dart-tags.scm +92 -0
- siada/queries/tree-sitter-language-pack/elisp-tags.scm +5 -0
- siada/queries/tree-sitter-language-pack/elixir-tags.scm +54 -0
- siada/queries/tree-sitter-language-pack/elm-tags.scm +19 -0
- siada/queries/tree-sitter-language-pack/gleam-tags.scm +41 -0
- siada/queries/tree-sitter-language-pack/go-tags.scm +42 -0
- siada/queries/tree-sitter-language-pack/java-tags.scm +20 -0
- siada/queries/tree-sitter-language-pack/javascript-tags.scm +88 -0
- siada/queries/tree-sitter-language-pack/lua-tags.scm +34 -0
- siada/queries/tree-sitter-language-pack/ocaml-tags.scm +115 -0
- siada/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +98 -0
- siada/queries/tree-sitter-language-pack/pony-tags.scm +39 -0
- siada/queries/tree-sitter-language-pack/properties-tags.scm +5 -0
- siada/queries/tree-sitter-language-pack/python-tags.scm +14 -0
- siada/queries/tree-sitter-language-pack/r-tags.scm +21 -0
- siada/queries/tree-sitter-language-pack/racket-tags.scm +12 -0
- siada/queries/tree-sitter-language-pack/ruby-tags.scm +64 -0
- siada/queries/tree-sitter-language-pack/rust-tags.scm +60 -0
- siada/queries/tree-sitter-language-pack/solidity-tags.scm +43 -0
- siada/queries/tree-sitter-language-pack/swift-tags.scm +51 -0
- siada/queries/tree-sitter-language-pack/udev-tags.scm +20 -0
- siada/queries/tree-sitter-languages/README.md +23 -0
- siada/queries/tree-sitter-languages/c-tags.scm +9 -0
- siada/queries/tree-sitter-languages/c_sharp-tags.scm +46 -0
- siada/queries/tree-sitter-languages/cpp-tags.scm +15 -0
- siada/queries/tree-sitter-languages/dart-tags.scm +91 -0
- siada/queries/tree-sitter-languages/elisp-tags.scm +8 -0
- siada/queries/tree-sitter-languages/elixir-tags.scm +54 -0
- siada/queries/tree-sitter-languages/elm-tags.scm +19 -0
- siada/queries/tree-sitter-languages/go-tags.scm +30 -0
- siada/queries/tree-sitter-languages/hcl-tags.scm +77 -0
- siada/queries/tree-sitter-languages/java-tags.scm +20 -0
- siada/queries/tree-sitter-languages/javascript-tags.scm +88 -0
- siada/queries/tree-sitter-languages/kotlin-tags.scm +27 -0
- siada/queries/tree-sitter-languages/ocaml-tags.scm +115 -0
- siada/queries/tree-sitter-languages/ocaml_interface-tags.scm +98 -0
- siada/queries/tree-sitter-languages/php-tags.scm +26 -0
- siada/queries/tree-sitter-languages/python-tags.scm +12 -0
- siada/queries/tree-sitter-languages/ql-tags.scm +26 -0
- siada/queries/tree-sitter-languages/ruby-tags.scm +64 -0
- siada/queries/tree-sitter-languages/rust-tags.scm +60 -0
- siada/queries/tree-sitter-languages/scala-tags.scm +65 -0
- siada/queries/tree-sitter-languages/typescript-tags.scm +41 -0
- siada/services/__init__.py +30 -0
- siada/services/at_file_recommendation_design_document.md +1213 -0
- siada/services/code_context_manager.py +136 -0
- siada/services/enhanced_fix_result_check.py +546 -0
- siada/services/execution_trace_collector.py +207 -0
- siada/services/file_recommendation/__init__.py +136 -0
- siada/services/file_recommendation/core/__init__.py +17 -0
- siada/services/file_recommendation/core/completion_engine.py +351 -0
- siada/services/file_recommendation/core/config.py +62 -0
- siada/services/file_recommendation/core/file_discovery.py +353 -0
- siada/services/file_recommendation/core/suggestion.py +110 -0
- siada/services/file_recommendation/utils/__init__.py +22 -0
- siada/services/file_recommendation/utils/path_utils.py +138 -0
- siada/services/file_recommendation/utils/text_utils.py +253 -0
- siada/services/fix_result_check.py +377 -0
- siada/services/handle_at_command/README.md +247 -0
- siada/services/handle_at_command/__init__.py +115 -0
- siada/services/handle_at_command/exceptions.py +46 -0
- siada/services/handle_at_command/models.py +92 -0
- siada/services/handle_at_command/parser.py +189 -0
- siada/services/handle_at_command/processor.py +321 -0
- siada/services/handle_at_command/resolver.py +318 -0
- siada/services/handle_at_command/utils.py +345 -0
- siada/services/model_info_service.py +103 -0
- siada/services/siada_runner.py +170 -0
- siada/session/__init__.py +29 -0
- siada/session/session_manager.py +66 -0
- siada/session/session_models.py +43 -0
- siada/support/__init__.py +0 -0
- siada/support/completer.py +204 -0
- siada/support/editor.py +146 -0
- siada/support/envprocessor.py +54 -0
- siada/support/repo.py +51 -0
- siada/support/slash_commands.py +410 -0
- siada/support/spinner.py +320 -0
- siada/tools/__init__.py +0 -0
- siada/tools/ast/README.md +345 -0
- siada/tools/ast/ast_tool.py +341 -0
- siada/tools/ast/models.py +11 -0
- siada/tools/coder/__init__.py +0 -0
- siada/tools/coder/ask_followup_question.py +70 -0
- siada/tools/coder/cmd_runner.py +132 -0
- siada/tools/coder/file_operator.py +284 -0
- siada/tools/coder/file_search/README.md +223 -0
- siada/tools/coder/file_search/__init__.py +10 -0
- siada/tools/coder/file_search/bin/rg-linux-arm64 +0 -0
- siada/tools/coder/file_search/bin/rg-linux-x64 +0 -0
- siada/tools/coder/file_search/bin/rg-macos-arm64 +0 -0
- siada/tools/coder/file_search/bin/rg-macos-x64 +0 -0
- siada/tools/coder/file_search/bin/rg.exe +0 -0
- siada/tools/coder/file_search/search.py +437 -0
- siada/tools/coder/file_search/setup_package.py +150 -0
- siada/tools/coder/file_search/test_search.py +142 -0
- siada/tools/coder/files.py +147 -0
- siada/tools/coder/fix_attempt_completion.py +58 -0
- siada/tools/coder/issue_review_completion.py +29 -0
- siada/tools/coder/observation/__init__.py +0 -0
- siada/tools/coder/observation/error.py +22 -0
- siada/tools/coder/observation/file_observation.py +216 -0
- siada/tools/coder/observation/observation.py +71 -0
- siada/tools/coder/repo_map/__init__.py +157 -0
- siada/tools/coder/repo_map/dump.py +29 -0
- siada/tools/coder/repo_map/io.py +226 -0
- siada/tools/coder/repo_map/repo_map.py +881 -0
- siada/tools/coder/repo_map/special.py +203 -0
- siada/tools/coder/repo_map/token_counter.py +154 -0
- siada/tools/coder/repo_map/waiting.py +221 -0
- siada/tools/coder/reproduce_completion.py +39 -0
- siada/tools/coder/run_cmd.py +60 -0
- siada/tools/coder/test_completion.py +25 -0
- siada/tools/coder/tool_docs.py +44 -0
- siada/tools/compression_tool.py +200 -0
- siada/tools/read_many_files/README.md +220 -0
- siada/tools/read_many_files/__init__.py +25 -0
- siada/tools/read_many_files/file_processor.py +486 -0
- siada/tools/read_many_files/filters.py +326 -0
- siada/tools/read_many_files/formatters.py +204 -0
- siada/tools/read_many_files/models.py +189 -0
- siada/tools/read_many_files_tool.py +233 -0
- siada/tools/tool_call_format/__init__.py +55 -0
- siada/tools/tool_call_format/file_to_language.py +231 -0
- siada/tools/tool_call_format/formatter_factory.py +80 -0
- siada/tools/tool_call_format/formatters.py +282 -0
- siada/tools/tool_call_format/tool_call_formatter.py +54 -0
- siada/tools/web/__init__.py +0 -0
- siada/tools/web/web_crawl.py +208 -0
- siada/utils.py +194 -0
- siada_cli-0.0.1.dist-info/LICENSE +201 -0
- siada_cli-0.0.1.dist-info/METADATA +457 -0
- siada_cli-0.0.1.dist-info/RECORD +215 -0
- siada_cli-0.0.1.dist-info/WHEEL +4 -0
- siada_cli-0.0.1.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Completion engine for file recommendation system.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import time
|
|
7
|
+
from typing import List, Optional
|
|
8
|
+
|
|
9
|
+
from .config import CompletionConfig, FilterOptions
|
|
10
|
+
from .file_discovery import FileDiscoveryService
|
|
11
|
+
from .suggestion import Suggestion, sort_suggestions, limit_suggestions
|
|
12
|
+
from ..utils.text_utils import parse_at_command_path, extract_at_path_from_text
|
|
13
|
+
from ..utils.path_utils import escape_path
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CompletionEngine:
|
|
17
|
+
"""
|
|
18
|
+
Main completion engine that coordinates all components
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, search_directories: List[str], config: CompletionConfig):
|
|
22
|
+
"""
|
|
23
|
+
Initialize completion engine
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
search_directories: List of directories to search in
|
|
27
|
+
config: Completion configuration
|
|
28
|
+
"""
|
|
29
|
+
self.search_directories = search_directories
|
|
30
|
+
self.config = config
|
|
31
|
+
self.file_discovery_services = {}
|
|
32
|
+
|
|
33
|
+
# Initialize file discovery services for each directory
|
|
34
|
+
for directory in search_directories:
|
|
35
|
+
self.file_discovery_services[directory] = FileDiscoveryService(directory)
|
|
36
|
+
|
|
37
|
+
async def get_suggestions(self, text: str) -> List[Suggestion]:
|
|
38
|
+
"""
|
|
39
|
+
Get file suggestions for the given text
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
text: Input text containing @ command
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
List of file suggestions
|
|
46
|
+
"""
|
|
47
|
+
start_time = time.time()
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
# Extract @ path from text
|
|
51
|
+
at_path = extract_at_path_from_text(text)
|
|
52
|
+
if not at_path:
|
|
53
|
+
return []
|
|
54
|
+
|
|
55
|
+
# Parse the @ command path
|
|
56
|
+
base_dir, prefix, partial_path = parse_at_command_path(text)
|
|
57
|
+
|
|
58
|
+
# If no prefix, return directory listing
|
|
59
|
+
if not prefix and base_dir == ".":
|
|
60
|
+
return await self._get_directory_listing()
|
|
61
|
+
|
|
62
|
+
# Search for matching files
|
|
63
|
+
suggestions = await self._search_files(base_dir, prefix)
|
|
64
|
+
|
|
65
|
+
# Sort and limit results
|
|
66
|
+
sorted_suggestions = sort_suggestions(suggestions)
|
|
67
|
+
limited_suggestions = limit_suggestions(sorted_suggestions, self.config.max_results)
|
|
68
|
+
|
|
69
|
+
return limited_suggestions
|
|
70
|
+
|
|
71
|
+
except Exception as e:
|
|
72
|
+
# Return empty list on error, with optional logging
|
|
73
|
+
print(f"Error in completion engine: {e}")
|
|
74
|
+
return []
|
|
75
|
+
|
|
76
|
+
finally:
|
|
77
|
+
# Optional: track performance
|
|
78
|
+
elapsed_time = time.time() - start_time
|
|
79
|
+
if elapsed_time > self.config.search_timeout_ms / 1000:
|
|
80
|
+
print(f"Warning: Search took {elapsed_time:.2f}s, exceeding timeout")
|
|
81
|
+
|
|
82
|
+
async def _get_directory_listing(self) -> List[Suggestion]:
|
|
83
|
+
"""
|
|
84
|
+
Get listing of current directory files
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
List of suggestions for current directory
|
|
88
|
+
"""
|
|
89
|
+
all_suggestions = []
|
|
90
|
+
filter_options = self.config.get_filter_options()
|
|
91
|
+
|
|
92
|
+
for directory in self.search_directories:
|
|
93
|
+
if directory in self.file_discovery_services:
|
|
94
|
+
service = self.file_discovery_services[directory]
|
|
95
|
+
suggestions = service.find_files_in_directory(
|
|
96
|
+
directory,
|
|
97
|
+
"",
|
|
98
|
+
filter_options,
|
|
99
|
+
self.config.max_results
|
|
100
|
+
)
|
|
101
|
+
all_suggestions.extend(suggestions)
|
|
102
|
+
|
|
103
|
+
return all_suggestions
|
|
104
|
+
|
|
105
|
+
async def _search_files(self, base_dir: str, prefix: str) -> List[Suggestion]:
|
|
106
|
+
"""
|
|
107
|
+
Search for files matching the prefix
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
base_dir: Base directory to search in
|
|
111
|
+
prefix: Search prefix
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
List of matching suggestions
|
|
115
|
+
"""
|
|
116
|
+
all_suggestions = []
|
|
117
|
+
filter_options = self.config.get_filter_options()
|
|
118
|
+
|
|
119
|
+
# Create search tasks for all directories
|
|
120
|
+
search_tasks = []
|
|
121
|
+
|
|
122
|
+
for directory in self.search_directories:
|
|
123
|
+
if directory in self.file_discovery_services:
|
|
124
|
+
service = self.file_discovery_services[directory]
|
|
125
|
+
|
|
126
|
+
# Determine actual search directory
|
|
127
|
+
if base_dir == ".":
|
|
128
|
+
search_dir = directory
|
|
129
|
+
else:
|
|
130
|
+
search_dir = self._resolve_search_directory(directory, base_dir)
|
|
131
|
+
if not search_dir:
|
|
132
|
+
continue
|
|
133
|
+
|
|
134
|
+
# Create search task
|
|
135
|
+
if self.config.enable_recursive_search:
|
|
136
|
+
task = service.find_files_recursively(
|
|
137
|
+
search_dir,
|
|
138
|
+
prefix,
|
|
139
|
+
filter_options,
|
|
140
|
+
"",
|
|
141
|
+
0,
|
|
142
|
+
self.config.max_search_depth,
|
|
143
|
+
self.config.max_results
|
|
144
|
+
)
|
|
145
|
+
else:
|
|
146
|
+
# Use synchronous method wrapped in async
|
|
147
|
+
task = asyncio.create_task(
|
|
148
|
+
asyncio.to_thread(
|
|
149
|
+
service.find_files_in_directory,
|
|
150
|
+
search_dir,
|
|
151
|
+
prefix,
|
|
152
|
+
filter_options,
|
|
153
|
+
self.config.max_results
|
|
154
|
+
)
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
search_tasks.append(task)
|
|
158
|
+
|
|
159
|
+
# Execute search tasks with timeout
|
|
160
|
+
try:
|
|
161
|
+
results = await asyncio.wait_for(
|
|
162
|
+
asyncio.gather(*search_tasks, return_exceptions=True),
|
|
163
|
+
timeout=self.config.search_timeout_ms / 1000
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
# Collect results from successful tasks
|
|
167
|
+
for result in results:
|
|
168
|
+
if isinstance(result, list):
|
|
169
|
+
all_suggestions.extend(result)
|
|
170
|
+
elif isinstance(result, Exception):
|
|
171
|
+
# Log exception but continue
|
|
172
|
+
print(f"Search task failed: {result}")
|
|
173
|
+
|
|
174
|
+
except asyncio.TimeoutError:
|
|
175
|
+
# Handle timeout - return partial results
|
|
176
|
+
print(f"Search timeout after {self.config.search_timeout_ms}ms")
|
|
177
|
+
|
|
178
|
+
# Cancel remaining tasks
|
|
179
|
+
for task in search_tasks:
|
|
180
|
+
if not task.done():
|
|
181
|
+
task.cancel()
|
|
182
|
+
|
|
183
|
+
# Collect results from completed tasks
|
|
184
|
+
for task in search_tasks:
|
|
185
|
+
if task.done() and not task.cancelled():
|
|
186
|
+
try:
|
|
187
|
+
result = task.result()
|
|
188
|
+
if isinstance(result, list):
|
|
189
|
+
all_suggestions.extend(result)
|
|
190
|
+
except Exception:
|
|
191
|
+
pass
|
|
192
|
+
|
|
193
|
+
return all_suggestions
|
|
194
|
+
|
|
195
|
+
def _resolve_search_directory(self, base_directory: str, relative_path: str) -> Optional[str]:
|
|
196
|
+
"""
|
|
197
|
+
Resolve search directory from base directory and relative path
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
base_directory: Base directory
|
|
201
|
+
relative_path: Relative path from @ command
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
Resolved directory path or None if invalid
|
|
205
|
+
"""
|
|
206
|
+
import os
|
|
207
|
+
|
|
208
|
+
try:
|
|
209
|
+
# Remove trailing slash from relative_path if present
|
|
210
|
+
relative_path = relative_path.rstrip('/')
|
|
211
|
+
|
|
212
|
+
# Join paths
|
|
213
|
+
resolved_path = os.path.join(base_directory, relative_path)
|
|
214
|
+
resolved_path = os.path.abspath(resolved_path)
|
|
215
|
+
|
|
216
|
+
# Security check - ensure resolved path is within base directory
|
|
217
|
+
base_abs = os.path.abspath(base_directory)
|
|
218
|
+
if not resolved_path.startswith(base_abs):
|
|
219
|
+
return None
|
|
220
|
+
|
|
221
|
+
# Check if directory exists
|
|
222
|
+
if os.path.exists(resolved_path) and os.path.isdir(resolved_path):
|
|
223
|
+
return resolved_path
|
|
224
|
+
|
|
225
|
+
return None
|
|
226
|
+
|
|
227
|
+
except Exception:
|
|
228
|
+
return None
|
|
229
|
+
|
|
230
|
+
def get_suggestions_sync(self, text: str) -> List[Suggestion]:
|
|
231
|
+
"""
|
|
232
|
+
Synchronous version of get_suggestions
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
text: Input text containing @ command
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
List of file suggestions
|
|
239
|
+
"""
|
|
240
|
+
try:
|
|
241
|
+
loop = asyncio.get_event_loop()
|
|
242
|
+
return loop.run_until_complete(self.get_suggestions(text))
|
|
243
|
+
except RuntimeError:
|
|
244
|
+
# No event loop running, create a new one
|
|
245
|
+
return asyncio.run(self.get_suggestions(text))
|
|
246
|
+
|
|
247
|
+
def should_show_suggestions(self, text: str) -> bool:
|
|
248
|
+
"""
|
|
249
|
+
Check if suggestions should be shown for the given text
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
text: Input text
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
bool: True if suggestions should be shown
|
|
256
|
+
"""
|
|
257
|
+
# Basic check - look for @ character
|
|
258
|
+
at_path = extract_at_path_from_text(text)
|
|
259
|
+
if at_path is None:
|
|
260
|
+
return False
|
|
261
|
+
|
|
262
|
+
# Don't show suggestions for lone @ symbol
|
|
263
|
+
if at_path == '@':
|
|
264
|
+
return False
|
|
265
|
+
|
|
266
|
+
# Check if the path corresponds to a complete existing file
|
|
267
|
+
path_content = at_path[1:] # Remove @ prefix
|
|
268
|
+
if self._is_complete_file_path(path_content):
|
|
269
|
+
return False
|
|
270
|
+
|
|
271
|
+
# Show suggestions for @ with content
|
|
272
|
+
return True
|
|
273
|
+
|
|
274
|
+
def _is_complete_file_path(self, path: str) -> bool:
|
|
275
|
+
"""
|
|
276
|
+
Check if path corresponds to a complete existing file
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
path: Path to check (without @ prefix)
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
bool: True if path points to an existing file
|
|
283
|
+
"""
|
|
284
|
+
import os
|
|
285
|
+
|
|
286
|
+
if not path:
|
|
287
|
+
return False
|
|
288
|
+
|
|
289
|
+
# Check in all search directories
|
|
290
|
+
for search_dir in self.search_directories:
|
|
291
|
+
full_path = os.path.join(search_dir, path)
|
|
292
|
+
if os.path.isfile(full_path):
|
|
293
|
+
return True
|
|
294
|
+
|
|
295
|
+
return False
|
|
296
|
+
|
|
297
|
+
def update_config(self, config: CompletionConfig):
|
|
298
|
+
"""
|
|
299
|
+
Update completion configuration
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
config: New configuration
|
|
303
|
+
"""
|
|
304
|
+
self.config = config
|
|
305
|
+
|
|
306
|
+
def add_search_directory(self, directory: str):
|
|
307
|
+
"""
|
|
308
|
+
Add a new search directory
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
directory: Directory to add
|
|
312
|
+
"""
|
|
313
|
+
if directory not in self.search_directories:
|
|
314
|
+
self.search_directories.append(directory)
|
|
315
|
+
self.file_discovery_services[directory] = FileDiscoveryService(directory)
|
|
316
|
+
|
|
317
|
+
def remove_search_directory(self, directory: str):
|
|
318
|
+
"""
|
|
319
|
+
Remove a search directory
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
directory: Directory to remove
|
|
323
|
+
"""
|
|
324
|
+
if directory in self.search_directories:
|
|
325
|
+
self.search_directories.remove(directory)
|
|
326
|
+
if directory in self.file_discovery_services:
|
|
327
|
+
del self.file_discovery_services[directory]
|
|
328
|
+
|
|
329
|
+
def clear_cache(self):
|
|
330
|
+
"""
|
|
331
|
+
Clear any cached data (for future cache implementation)
|
|
332
|
+
"""
|
|
333
|
+
# Placeholder for cache clearing functionality
|
|
334
|
+
pass
|
|
335
|
+
|
|
336
|
+
def get_stats(self) -> dict:
|
|
337
|
+
"""
|
|
338
|
+
Get performance and usage statistics
|
|
339
|
+
|
|
340
|
+
Returns:
|
|
341
|
+
Dictionary containing stats
|
|
342
|
+
"""
|
|
343
|
+
return {
|
|
344
|
+
'search_directories': len(self.search_directories),
|
|
345
|
+
'config': {
|
|
346
|
+
'max_results': self.config.max_results,
|
|
347
|
+
'max_depth': self.config.max_search_depth,
|
|
348
|
+
'recursive_search': self.config.enable_recursive_search,
|
|
349
|
+
'git_ignore': self.config.respect_git_ignore
|
|
350
|
+
}
|
|
351
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration classes for file recommendation system.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import List
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class FilterOptions:
|
|
11
|
+
"""File filtering configuration options"""
|
|
12
|
+
respect_git_ignore: bool = True
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class CompletionConfig:
|
|
17
|
+
"""Auto-completion configuration"""
|
|
18
|
+
|
|
19
|
+
# Search configuration
|
|
20
|
+
enable_recursive_search: bool = True
|
|
21
|
+
max_search_depth: int = 10
|
|
22
|
+
max_results: int = 50
|
|
23
|
+
debounce_delay_ms: int = 100
|
|
24
|
+
|
|
25
|
+
# Display configuration
|
|
26
|
+
max_visible_suggestions: int = 8
|
|
27
|
+
suggestion_width: int = 60
|
|
28
|
+
|
|
29
|
+
# Filtering configuration
|
|
30
|
+
respect_git_ignore: bool = True
|
|
31
|
+
|
|
32
|
+
# Performance configuration
|
|
33
|
+
search_timeout_ms: int = 5000
|
|
34
|
+
|
|
35
|
+
# User experience configuration
|
|
36
|
+
show_loading_indicator: bool = True
|
|
37
|
+
auto_select_first: bool = True
|
|
38
|
+
|
|
39
|
+
def get_filter_options(self) -> FilterOptions:
|
|
40
|
+
"""Get filter options from config"""
|
|
41
|
+
return FilterOptions(
|
|
42
|
+
respect_git_ignore=self.respect_git_ignore
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class WorkspaceConfig:
|
|
48
|
+
"""Workspace configuration"""
|
|
49
|
+
directories: List[str]
|
|
50
|
+
current_directory: str
|
|
51
|
+
project_root: str
|
|
52
|
+
|
|
53
|
+
def get_search_directories(self) -> List[str]:
|
|
54
|
+
"""Get search directory list"""
|
|
55
|
+
return self.directories if self.directories else [self.current_directory]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# Default configuration instance
|
|
59
|
+
DEFAULT_COMPLETION_CONFIG = CompletionConfig()
|
|
60
|
+
|
|
61
|
+
# Default filter options
|
|
62
|
+
DEFAULT_FILTER_OPTIONS = FilterOptions()
|