jarvis-ai-assistant 0.1.138__py3-none-any.whl → 0.1.141__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 jarvis-ai-assistant might be problematic. Click here for more details.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +62 -14
- jarvis/jarvis_agent/builtin_input_handler.py +4 -14
- jarvis/jarvis_agent/main.py +1 -1
- jarvis/jarvis_agent/patch.py +37 -40
- jarvis/jarvis_agent/shell_input_handler.py +2 -3
- jarvis/jarvis_code_agent/code_agent.py +23 -30
- jarvis/jarvis_code_analysis/checklists/__init__.py +3 -0
- jarvis/jarvis_code_analysis/checklists/c_cpp.py +50 -0
- jarvis/jarvis_code_analysis/checklists/csharp.py +75 -0
- jarvis/jarvis_code_analysis/checklists/data_format.py +82 -0
- jarvis/jarvis_code_analysis/checklists/devops.py +107 -0
- jarvis/jarvis_code_analysis/checklists/docs.py +87 -0
- jarvis/jarvis_code_analysis/checklists/go.py +52 -0
- jarvis/jarvis_code_analysis/checklists/infrastructure.py +98 -0
- jarvis/jarvis_code_analysis/checklists/java.py +66 -0
- jarvis/jarvis_code_analysis/checklists/javascript.py +73 -0
- jarvis/jarvis_code_analysis/checklists/kotlin.py +107 -0
- jarvis/jarvis_code_analysis/checklists/loader.py +76 -0
- jarvis/jarvis_code_analysis/checklists/php.py +77 -0
- jarvis/jarvis_code_analysis/checklists/python.py +56 -0
- jarvis/jarvis_code_analysis/checklists/ruby.py +107 -0
- jarvis/jarvis_code_analysis/checklists/rust.py +58 -0
- jarvis/jarvis_code_analysis/checklists/shell.py +75 -0
- jarvis/jarvis_code_analysis/checklists/sql.py +72 -0
- jarvis/jarvis_code_analysis/checklists/swift.py +77 -0
- jarvis/jarvis_code_analysis/checklists/web.py +97 -0
- jarvis/jarvis_code_analysis/code_review.py +660 -0
- jarvis/jarvis_dev/main.py +61 -88
- jarvis/jarvis_git_squash/main.py +3 -3
- jarvis/jarvis_git_utils/git_commiter.py +242 -0
- jarvis/jarvis_init/main.py +62 -0
- jarvis/jarvis_platform/base.py +4 -0
- jarvis/jarvis_platform/kimi.py +173 -5
- jarvis/jarvis_platform/openai.py +3 -0
- jarvis/jarvis_platform/registry.py +1 -0
- jarvis/jarvis_platform/yuanbao.py +275 -5
- jarvis/jarvis_tools/ask_codebase.py +6 -9
- jarvis/jarvis_tools/ask_user.py +17 -5
- jarvis/jarvis_tools/base.py +3 -1
- jarvis/jarvis_tools/chdir.py +1 -0
- jarvis/jarvis_tools/create_code_agent.py +4 -3
- jarvis/jarvis_tools/create_sub_agent.py +1 -0
- jarvis/jarvis_tools/execute_script.py +170 -0
- jarvis/jarvis_tools/file_analyzer.py +90 -239
- jarvis/jarvis_tools/file_operation.py +99 -31
- jarvis/jarvis_tools/{find_methodolopy.py → find_methodology.py} +2 -1
- jarvis/jarvis_tools/lsp_get_diagnostics.py +2 -0
- jarvis/jarvis_tools/methodology.py +11 -11
- jarvis/jarvis_tools/read_code.py +2 -0
- jarvis/jarvis_tools/read_webpage.py +33 -196
- jarvis/jarvis_tools/registry.py +68 -131
- jarvis/jarvis_tools/search_web.py +14 -6
- jarvis/jarvis_tools/virtual_tty.py +399 -0
- jarvis/jarvis_utils/config.py +29 -3
- jarvis/jarvis_utils/embedding.py +0 -317
- jarvis/jarvis_utils/file_processors.py +343 -0
- jarvis/jarvis_utils/input.py +0 -1
- jarvis/jarvis_utils/methodology.py +94 -435
- jarvis/jarvis_utils/utils.py +207 -9
- {jarvis_ai_assistant-0.1.138.dist-info → jarvis_ai_assistant-0.1.141.dist-info}/METADATA +4 -4
- jarvis_ai_assistant-0.1.141.dist-info/RECORD +94 -0
- {jarvis_ai_assistant-0.1.138.dist-info → jarvis_ai_assistant-0.1.141.dist-info}/entry_points.txt +4 -4
- jarvis/jarvis_code_agent/file_select.py +0 -202
- jarvis/jarvis_platform/ai8.py +0 -268
- jarvis/jarvis_platform/ollama.py +0 -137
- jarvis/jarvis_platform/oyi.py +0 -307
- jarvis/jarvis_rag/file_processors.py +0 -138
- jarvis/jarvis_rag/main.py +0 -1734
- jarvis/jarvis_tools/code_review.py +0 -333
- jarvis/jarvis_tools/execute_python_script.py +0 -58
- jarvis/jarvis_tools/execute_shell.py +0 -97
- jarvis/jarvis_tools/execute_shell_script.py +0 -58
- jarvis/jarvis_tools/find_caller.py +0 -278
- jarvis/jarvis_tools/find_symbol.py +0 -295
- jarvis/jarvis_tools/function_analyzer.py +0 -331
- jarvis/jarvis_tools/git_commiter.py +0 -167
- jarvis/jarvis_tools/project_analyzer.py +0 -304
- jarvis/jarvis_tools/rag.py +0 -143
- jarvis/jarvis_tools/tool_generator.py +0 -221
- jarvis_ai_assistant-0.1.138.dist-info/RECORD +0 -85
- /jarvis/{jarvis_rag → jarvis_init}/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.138.dist-info → jarvis_ai_assistant-0.1.141.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.138.dist-info → jarvis_ai_assistant-0.1.141.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.138.dist-info → jarvis_ai_assistant-0.1.141.dist-info}/top_level.txt +0 -0
jarvis/jarvis_utils/utils.py
CHANGED
|
@@ -2,13 +2,13 @@ import os
|
|
|
2
2
|
import time
|
|
3
3
|
import hashlib
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import Dict
|
|
6
|
-
import
|
|
7
|
-
from jarvis.jarvis_utils.config import
|
|
5
|
+
from typing import Union, List, Dict, Any, Callable, cast
|
|
6
|
+
from bs4 import BeautifulSoup, Tag
|
|
7
|
+
from jarvis.jarvis_utils.config import get_max_input_token_count
|
|
8
8
|
from jarvis.jarvis_utils.embedding import get_context_token_count
|
|
9
9
|
from jarvis.jarvis_utils.input import get_single_line_input
|
|
10
10
|
from jarvis.jarvis_utils.output import PrettyOutput, OutputType
|
|
11
|
-
def init_env():
|
|
11
|
+
def init_env() -> None:
|
|
12
12
|
"""初始化环境变量从~/.jarvis/env文件
|
|
13
13
|
|
|
14
14
|
功能:
|
|
@@ -35,7 +35,7 @@ def init_env():
|
|
|
35
35
|
continue
|
|
36
36
|
except Exception as e:
|
|
37
37
|
PrettyOutput.print(f"警告: 读取 {env_file} 失败: {e}", OutputType.WARNING)
|
|
38
|
-
def while_success(func, sleep_time: float = 0.1):
|
|
38
|
+
def while_success(func: Callable[[], Any], sleep_time: float = 0.1) -> Any:
|
|
39
39
|
"""循环执行函数直到成功
|
|
40
40
|
|
|
41
41
|
参数:
|
|
@@ -52,7 +52,7 @@ def while_success(func, sleep_time: float = 0.1):
|
|
|
52
52
|
PrettyOutput.print(f"执行失败: {str(e)}, 等待 {sleep_time}s...", OutputType.ERROR)
|
|
53
53
|
time.sleep(sleep_time)
|
|
54
54
|
continue
|
|
55
|
-
def while_true(func, sleep_time: float = 0.1):
|
|
55
|
+
def while_true(func: Callable[[], bool], sleep_time: float = 0.1) -> Any:
|
|
56
56
|
"""Loop execution function, until the function returns True"""
|
|
57
57
|
while True:
|
|
58
58
|
ret = func()
|
|
@@ -100,7 +100,7 @@ def get_file_line_count(filename: str) -> int:
|
|
|
100
100
|
return 0
|
|
101
101
|
|
|
102
102
|
|
|
103
|
-
def is_long_context(files:
|
|
103
|
+
def is_long_context(files: List[str]) -> bool:
|
|
104
104
|
"""检查文件列表是否属于长上下文
|
|
105
105
|
|
|
106
106
|
判断标准:
|
|
@@ -112,8 +112,8 @@ def is_long_context(files: list) -> bool:
|
|
|
112
112
|
返回:
|
|
113
113
|
布尔值表示是否属于长上下文
|
|
114
114
|
"""
|
|
115
|
-
|
|
116
|
-
threshold =
|
|
115
|
+
max_input_token_count = get_max_input_token_count()
|
|
116
|
+
threshold = max_input_token_count * 0.8
|
|
117
117
|
total_tokens = 0
|
|
118
118
|
|
|
119
119
|
for file_path in files:
|
|
@@ -152,3 +152,201 @@ def ct(tag_name: str) -> str:
|
|
|
152
152
|
格式化的结束标签字符串
|
|
153
153
|
"""
|
|
154
154
|
return f"</{tag_name}>"
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def create_soup_element(content: Union[str, Tag, List[Any]]) -> List[Union[Tag, str]]:
|
|
158
|
+
"""Safely create a BeautifulSoup element, ensuring it's treated as markup
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
content: Input content to convert to BeautifulSoup elements
|
|
162
|
+
Returns:
|
|
163
|
+
List of BeautifulSoup elements or strings
|
|
164
|
+
"""
|
|
165
|
+
if isinstance(content, str):
|
|
166
|
+
# Create a wrapper tag to ensure proper parsing
|
|
167
|
+
soup_div = BeautifulSoup(f"<div>{content}</div>", 'html.parser').div
|
|
168
|
+
if soup_div is not None:
|
|
169
|
+
return [cast(Union[Tag, str], el) for el in soup_div.contents]
|
|
170
|
+
return []
|
|
171
|
+
elif isinstance(content, list):
|
|
172
|
+
return content
|
|
173
|
+
return [content]
|
|
174
|
+
|
|
175
|
+
def extract_interactive_elements(html_content: str) -> List[Dict[str, Any]]:
|
|
176
|
+
"""Extract all interactive elements from HTML content with their properties.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
html_content: HTML content to parse
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
List of dictionaries containing element properties:
|
|
183
|
+
- xpath: XPath of the element
|
|
184
|
+
- tag: HTML tag name
|
|
185
|
+
- text: Text content
|
|
186
|
+
- is_clickable: Whether element is clickable
|
|
187
|
+
- is_input: Whether element is an input field
|
|
188
|
+
- is_select: Whether element is a select dropdown
|
|
189
|
+
"""
|
|
190
|
+
soup = BeautifulSoup(html_content, 'html.parser')
|
|
191
|
+
interactive_elements = []
|
|
192
|
+
|
|
193
|
+
# Define interactive tags
|
|
194
|
+
clickable_tags = {'a', 'button', 'input', 'select', 'textarea'}
|
|
195
|
+
input_tags = {'input', 'textarea', 'select'}
|
|
196
|
+
|
|
197
|
+
def get_xpath(element: Tag) -> str:
|
|
198
|
+
"""Generate XPath for an element"""
|
|
199
|
+
components = []
|
|
200
|
+
current = element
|
|
201
|
+
|
|
202
|
+
while current and current.name:
|
|
203
|
+
siblings = current.find_previous_siblings(current.name)
|
|
204
|
+
index = len(siblings) + 1
|
|
205
|
+
components.append(f"{current.name}[{index}]")
|
|
206
|
+
current = current.parent
|
|
207
|
+
|
|
208
|
+
return "/".join(reversed(components))
|
|
209
|
+
|
|
210
|
+
def process_element(element: Tag) -> None:
|
|
211
|
+
"""Process a single element and add it to interactive_elements if it's interactive"""
|
|
212
|
+
tag_name = element.name.lower()
|
|
213
|
+
|
|
214
|
+
# Skip non-interactive elements
|
|
215
|
+
if tag_name not in clickable_tags and not element.find_parent(clickable_tags):
|
|
216
|
+
return
|
|
217
|
+
|
|
218
|
+
# Get element properties
|
|
219
|
+
element_info = {
|
|
220
|
+
'xpath': get_xpath(element),
|
|
221
|
+
'tag': tag_name,
|
|
222
|
+
'text': element.get_text().strip(),
|
|
223
|
+
'is_clickable': tag_name in clickable_tags or bool(element.find_parent('a')) or bool(element.find_parent('button')),
|
|
224
|
+
'is_input': tag_name in input_tags,
|
|
225
|
+
'is_select': tag_name == 'select'
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
# Add additional properties for input elements
|
|
229
|
+
if element_info['is_input']:
|
|
230
|
+
element_info['input_type'] = element.get('type', 'text')
|
|
231
|
+
element_info['name'] = element.get('name', '')
|
|
232
|
+
element_info['value'] = element.get('value', '')
|
|
233
|
+
|
|
234
|
+
# Add options for select elements
|
|
235
|
+
if element_info['is_select']:
|
|
236
|
+
element_info['options'] = [
|
|
237
|
+
{'value': opt.get('value', ''), 'text': opt.get_text().strip()}
|
|
238
|
+
for opt in element.find_all('option')
|
|
239
|
+
if isinstance(opt, Tag)
|
|
240
|
+
]
|
|
241
|
+
|
|
242
|
+
interactive_elements.append(element_info)
|
|
243
|
+
|
|
244
|
+
# Process all elements
|
|
245
|
+
for element in soup.find_all():
|
|
246
|
+
if isinstance(element, Tag):
|
|
247
|
+
process_element(element)
|
|
248
|
+
|
|
249
|
+
return interactive_elements
|
|
250
|
+
|
|
251
|
+
def extract_display_elements(html_content: str) -> List[Dict[str, Any]]:
|
|
252
|
+
"""Extract all display elements from HTML content with their properties.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
html_content: HTML content to parse
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
List of dictionaries containing element properties:
|
|
259
|
+
- xpath: XPath of the element
|
|
260
|
+
- tag: HTML tag name
|
|
261
|
+
- text: Text content
|
|
262
|
+
- heading_level: Heading level (1-6) if the element is a heading
|
|
263
|
+
- is_list: Whether the element is a list
|
|
264
|
+
- is_list_item: Whether the element is a list item
|
|
265
|
+
- is_table: Whether the element is a table
|
|
266
|
+
- is_table_cell: Whether the element is a table cell
|
|
267
|
+
"""
|
|
268
|
+
soup = BeautifulSoup(html_content, 'html.parser')
|
|
269
|
+
display_elements = []
|
|
270
|
+
|
|
271
|
+
# Define display tags
|
|
272
|
+
display_tags = {
|
|
273
|
+
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', # Headings
|
|
274
|
+
'p', 'div', 'span', # Text containers
|
|
275
|
+
'ul', 'ol', 'li', # Lists
|
|
276
|
+
'table', 'tr', 'td', 'th', # Tables
|
|
277
|
+
'article', 'section', 'main', # Content sections
|
|
278
|
+
'header', 'footer', 'nav', # Layout sections
|
|
279
|
+
'aside', 'figure', 'figcaption' # Side content
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
# Define interactive tags to exclude
|
|
283
|
+
interactive_tags = {'a', 'button', 'input', 'select', 'textarea', 'form'}
|
|
284
|
+
|
|
285
|
+
def get_xpath(element: Tag) -> str:
|
|
286
|
+
"""Generate XPath for an element"""
|
|
287
|
+
components = []
|
|
288
|
+
current = element
|
|
289
|
+
|
|
290
|
+
while current and current.name:
|
|
291
|
+
siblings = current.find_previous_siblings(current.name)
|
|
292
|
+
index = len(siblings) + 1
|
|
293
|
+
components.append(f"{current.name}[{index}]")
|
|
294
|
+
current = current.parent
|
|
295
|
+
|
|
296
|
+
return "/".join(reversed(components))
|
|
297
|
+
|
|
298
|
+
def process_element(element: Tag) -> None:
|
|
299
|
+
"""Process a single element and add it to display_elements if it's a display element"""
|
|
300
|
+
tag_name = element.name.lower()
|
|
301
|
+
|
|
302
|
+
# Skip non-display elements and interactive elements
|
|
303
|
+
if tag_name not in display_tags or element.find_parent(interactive_tags):
|
|
304
|
+
return
|
|
305
|
+
|
|
306
|
+
# Get text content
|
|
307
|
+
text = element.get_text().strip()
|
|
308
|
+
if not text: # Skip empty elements
|
|
309
|
+
return
|
|
310
|
+
|
|
311
|
+
# Get element properties
|
|
312
|
+
element_info = {
|
|
313
|
+
'xpath': get_xpath(element),
|
|
314
|
+
'tag': tag_name,
|
|
315
|
+
'text': text,
|
|
316
|
+
'heading_level': int(tag_name[1]) if tag_name.startswith('h') and len(tag_name) == 2 else None,
|
|
317
|
+
'is_list': tag_name in {'ul', 'ol'},
|
|
318
|
+
'is_list_item': tag_name == 'li',
|
|
319
|
+
'is_table': tag_name == 'table',
|
|
320
|
+
'is_table_cell': tag_name in {'td', 'th'}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
# Add list-specific properties
|
|
324
|
+
if element_info['is_list']:
|
|
325
|
+
element_info['list_items'] = [
|
|
326
|
+
{'text': li.get_text().strip()}
|
|
327
|
+
for li in element.find_all('li')
|
|
328
|
+
if isinstance(li, Tag)
|
|
329
|
+
]
|
|
330
|
+
|
|
331
|
+
# Add table-specific properties
|
|
332
|
+
if element_info['is_table']:
|
|
333
|
+
element_info['table_rows'] = [
|
|
334
|
+
{
|
|
335
|
+
'cells': [
|
|
336
|
+
{'text': cell.get_text().strip(), 'is_header': cell.name == 'th'}
|
|
337
|
+
for cell in row.find_all(['td', 'th'])
|
|
338
|
+
if isinstance(cell, Tag)
|
|
339
|
+
]
|
|
340
|
+
}
|
|
341
|
+
for row in element.find_all('tr')
|
|
342
|
+
if isinstance(row, Tag)
|
|
343
|
+
]
|
|
344
|
+
|
|
345
|
+
display_elements.append(element_info)
|
|
346
|
+
|
|
347
|
+
# Process all elements
|
|
348
|
+
for element in soup.find_all():
|
|
349
|
+
if isinstance(element, Tag):
|
|
350
|
+
process_element(element)
|
|
351
|
+
|
|
352
|
+
return display_elements
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: jarvis-ai-assistant
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.141
|
|
4
4
|
Summary: Jarvis: An AI assistant that uses tools to interact with the system
|
|
5
5
|
Home-page: https://github.com/skyfireitdiy/Jarvis
|
|
6
6
|
Author: skyfire
|
|
@@ -45,7 +45,6 @@ Requires-Dist: pyyaml>=5.1
|
|
|
45
45
|
Requires-Dist: colorama>=0.4.6
|
|
46
46
|
Requires-Dist: prompt-toolkit>=3.0.0
|
|
47
47
|
Requires-Dist: openai>=1.20.0
|
|
48
|
-
Requires-Dist: playwright>=1.41.1
|
|
49
48
|
Requires-Dist: numpy>=1.19.5
|
|
50
49
|
Requires-Dist: faiss-cpu>=1.8.0
|
|
51
50
|
Requires-Dist: sentence-transformers>=2.2.2
|
|
@@ -55,7 +54,7 @@ Requires-Dist: python-docx>=0.8.11
|
|
|
55
54
|
Requires-Dist: tiktoken>=0.3.0
|
|
56
55
|
Requires-Dist: tqdm>=4.65.0
|
|
57
56
|
Requires-Dist: docx>=0.2.4
|
|
58
|
-
Requires-Dist: yaspin>=2.
|
|
57
|
+
Requires-Dist: yaspin>=2.4.0
|
|
59
58
|
Requires-Dist: rich>=13.3.1
|
|
60
59
|
Requires-Dist: pygments>=2.15.0
|
|
61
60
|
Requires-Dist: fuzzywuzzy>=0.18.0
|
|
@@ -66,6 +65,7 @@ Requires-Dist: fastapi>=0.115.4
|
|
|
66
65
|
Requires-Dist: uvicorn>=0.33.0
|
|
67
66
|
Requires-Dist: python-pptx>=1.0.0
|
|
68
67
|
Requires-Dist: pandas>=2.0.0
|
|
68
|
+
Requires-Dist: html2text>=2024.2.26
|
|
69
69
|
Provides-Extra: dev
|
|
70
70
|
Requires-Dist: pytest; extra == "dev"
|
|
71
71
|
Requires-Dist: black; extra == "dev"
|
|
@@ -165,7 +165,7 @@ jarvis-ask-codebase --help
|
|
|
165
165
|
|----------|------|
|
|
166
166
|
| read_code | 支持行号和范围的代码文件读取 |
|
|
167
167
|
| execute_shell | 执行系统命令并捕获输出 |
|
|
168
|
-
|
|
|
168
|
+
| execute_script | 执行脚本并返回结果,支持Shell命令、Shell脚本和Python脚本 |
|
|
169
169
|
| ask_codebase | 智能代码库查询和分析,用于定位功能所在文件和理解单点实现,适合查询特定功能位置和实现原理 |
|
|
170
170
|
| ask_user | 交互式用户输入收集 |
|
|
171
171
|
| file_operation | 基础文件操作(读取/写入/存在性检查) |
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
jarvis/__init__.py,sha256=qDMhmaE2-m_heV7fzBRSqmELTVxciZSojL01NXLJgCU,50
|
|
2
|
+
jarvis/jarvis_agent/__init__.py,sha256=doFjWa2a6nVGkKkuQkgrupswqqY8dBNJxUDxUfckvPo,23557
|
|
3
|
+
jarvis/jarvis_agent/builtin_input_handler.py,sha256=aWb5RiKaY5-07LtiLi_mMh9Z-l4DaA_3nLbmFbBGb-w,2429
|
|
4
|
+
jarvis/jarvis_agent/file_input_handler.py,sha256=6rIF_FgC9_3UcQhFCmoMoECG4tjKaLBZZ5zDtBl037I,3235
|
|
5
|
+
jarvis/jarvis_agent/jarvis.py,sha256=NmxVJ8KwSc4fumntNL1T5TWj-FvcRgssLeBhG4sA3xk,5368
|
|
6
|
+
jarvis/jarvis_agent/main.py,sha256=Hx1cavfGkrGVEk_HrOJX6FNE0fEh2CDLy7Efr_VSiKI,2636
|
|
7
|
+
jarvis/jarvis_agent/output_handler.py,sha256=4limQ-Kf-YYvQjT5SMjJIyyvD1DVG8tINv1A_qbv4ho,405
|
|
8
|
+
jarvis/jarvis_agent/patch.py,sha256=ZVde3b7MobwGWR0KFKaGXfeCrMQjmT47GWoGpt2nM3c,19796
|
|
9
|
+
jarvis/jarvis_agent/shell_input_handler.py,sha256=Pcm__ldcBp7GcHm5r3hbRc4nKe86LLWvNl0UE5JlAiU,1173
|
|
10
|
+
jarvis/jarvis_code_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
jarvis/jarvis_code_agent/code_agent.py,sha256=c6UBBJku-yoH70f-uapsewewp4EKYxevTnMCZ-KqWKA,12599
|
|
12
|
+
jarvis/jarvis_code_analysis/code_review.py,sha256=I_Bc0hDPz3m5textX9Yqreq7_f28CGd7KDW_-i4Cjgs,29543
|
|
13
|
+
jarvis/jarvis_code_analysis/checklists/__init__.py,sha256=PCjlyxLa939613cAzS7pfEPgP57setO-1RvcdzzPivw,54
|
|
14
|
+
jarvis/jarvis_code_analysis/checklists/c_cpp.py,sha256=8lfWmhImAxeTBdHPOgVXDjMllaq280Qki1ZOOSDBnvk,1293
|
|
15
|
+
jarvis/jarvis_code_analysis/checklists/csharp.py,sha256=fg35Iima2nIsirEmAjianfAybVjwRYml9BtbSQFff7w,2396
|
|
16
|
+
jarvis/jarvis_code_analysis/checklists/data_format.py,sha256=g8lubTeEY2Sx5bdPaMmn2PmaSIpxDZu5d1GgPc-DlDk,2981
|
|
17
|
+
jarvis/jarvis_code_analysis/checklists/devops.py,sha256=kTvzFybZ0i1uo5ABD-pbn__h3t8n4QaURSrJ2o-MplQ,3518
|
|
18
|
+
jarvis/jarvis_code_analysis/checklists/docs.py,sha256=7Tq9woxeYqbqmiql3PkbFZ59ui7uIHKRAOUFUGhjCPc,3317
|
|
19
|
+
jarvis/jarvis_code_analysis/checklists/go.py,sha256=yF4gu1YNxyv6Ptgx9Qj4bxeyQHIwAgPQzt4Nm6gdhUc,1364
|
|
20
|
+
jarvis/jarvis_code_analysis/checklists/infrastructure.py,sha256=l64mExwNc49Z8Ol1hy6qdVGFc00SMbagyvn0gOTOR04,3741
|
|
21
|
+
jarvis/jarvis_code_analysis/checklists/java.py,sha256=KIQMukhnMqI8oRsm8oVLaX_s_dggECo2OX8eXqjjG_4,2061
|
|
22
|
+
jarvis/jarvis_code_analysis/checklists/javascript.py,sha256=a0RAqQUfnhK6IItXT_zU5PW5_IH7uwc8BWKo49KuX2c,2316
|
|
23
|
+
jarvis/jarvis_code_analysis/checklists/kotlin.py,sha256=FDtEa2Dyzd4bTSZkusllaLbGFhQKD6OW4g0yvKkBNgw,4412
|
|
24
|
+
jarvis/jarvis_code_analysis/checklists/loader.py,sha256=l6k6Z7oeo1Hy4KAIeM5bGfcqZ7ftwzZoCDNUxAwkm9g,1895
|
|
25
|
+
jarvis/jarvis_code_analysis/checklists/php.py,sha256=LoWeE-I5KonZCc_7fDcekgbPVbK7oVgyUwqq7ZqnDsc,2457
|
|
26
|
+
jarvis/jarvis_code_analysis/checklists/python.py,sha256=ULPQoJBe5B_XKzbAqUv3DOCB7posc4sSv2IWFA4_7lA,1428
|
|
27
|
+
jarvis/jarvis_code_analysis/checklists/ruby.py,sha256=qbaRNGk0VFeZFUYJSJRhLVdZK0JSmlGygHZOHr806YU,4250
|
|
28
|
+
jarvis/jarvis_code_analysis/checklists/rust.py,sha256=6qNtIPxb4VWlyVx6dukMKITkYxqD_jLi5MlB-_jjzHQ,1622
|
|
29
|
+
jarvis/jarvis_code_analysis/checklists/shell.py,sha256=UBtGhi3d5sIhyUSGmDckYOXwpeaQEAfJ-FKCH4izSC8,2595
|
|
30
|
+
jarvis/jarvis_code_analysis/checklists/sql.py,sha256=-bGfYhaFJyHrbcJrUMbkMyPCNVbk8UljNqebqVJJKxM,2331
|
|
31
|
+
jarvis/jarvis_code_analysis/checklists/swift.py,sha256=d-zPPbM_J1G8fgZ2M2-ASQbIxEocsdL1owL4Z2PCnOc,2542
|
|
32
|
+
jarvis/jarvis_code_analysis/checklists/web.py,sha256=phdvLGqRHNijA0OyEwVtgHgz1Hi4ldtJJscOhEQvbSQ,3919
|
|
33
|
+
jarvis/jarvis_dev/main.py,sha256=Rl2COZqMUds-SFyjrroLPfs056gtwTcIliMTJhrtWnM,27751
|
|
34
|
+
jarvis/jarvis_git_details/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
|
+
jarvis/jarvis_git_details/main.py,sha256=YowncVxYyJ3y2EvGrZhAJeR4yizXp6aB3dqvoYTepFY,6117
|
|
36
|
+
jarvis/jarvis_git_squash/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
|
+
jarvis/jarvis_git_squash/main.py,sha256=xBNkAl7_8_pQC-C6RcUImA1mEU4KTqhjtA57rG_mMJ8,2179
|
|
38
|
+
jarvis/jarvis_git_utils/git_commiter.py,sha256=6q70zosBrTM6vHqp01DV4780-y3zmazdSfJFGJT9jiw,10643
|
|
39
|
+
jarvis/jarvis_init/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
|
+
jarvis/jarvis_init/main.py,sha256=Mb41DdhkWRYxdqEqCJPiQRAT4IspbRmak6la9ITcXdg,2102
|
|
41
|
+
jarvis/jarvis_lsp/base.py,sha256=CWfiqiQ6ZBc_lrW64Y1YAsFQeNPGoWcgTBGKgOrPVQg,2047
|
|
42
|
+
jarvis/jarvis_lsp/cpp.py,sha256=SOXFhpipvbdhlwUZ7Rh0hdWGXWnrNOxZVsmTN6ZXoZk,3148
|
|
43
|
+
jarvis/jarvis_lsp/go.py,sha256=h7vA0ArGSq9rhLZcrPXg5HdnEbKwnjVr322IkYI1jHw,3465
|
|
44
|
+
jarvis/jarvis_lsp/python.py,sha256=xMqSVJn8w6CZEquSIO2I-6TJ7-YOABgpt3SjNOV6UAk,1860
|
|
45
|
+
jarvis/jarvis_lsp/registry.py,sha256=LduRCEVH5y75IODdY8lZ3ZB3OHKpgwbZnYNxuhUmA_o,6439
|
|
46
|
+
jarvis/jarvis_lsp/rust.py,sha256=9UOiYTUwMwz2raj1G8Uec0aB5Oun7wMiWYGDhC4JMpI,3693
|
|
47
|
+
jarvis/jarvis_methodology/main.py,sha256=IBv87UOmdCailgooMtWEcqZcQHmNLhZD-kkGw5jOcVg,3375
|
|
48
|
+
jarvis/jarvis_multi_agent/__init__.py,sha256=SX8lBErhltKyYRM-rymrMz3sJ0Zl3hBXrpsPdFgzkQc,4399
|
|
49
|
+
jarvis/jarvis_multi_agent/main.py,sha256=aGuUC3YQmahabqwDwZXJjfQLYsZ3KIZdf8DZDlVNMe4,1543
|
|
50
|
+
jarvis/jarvis_platform/__init__.py,sha256=WIJtD5J7lOrWLX2bsgZGkmlMcN0NOJsnh_reybmHPjg,58
|
|
51
|
+
jarvis/jarvis_platform/base.py,sha256=Ge-UgZGCHICFWOqrHzg-_qXQXjS1I2lZSxfYs5Angwo,3234
|
|
52
|
+
jarvis/jarvis_platform/kimi.py,sha256=N2iNIjJzB57SMAgrfbCvRd595DvlbKtg038wXAz4BqU,16578
|
|
53
|
+
jarvis/jarvis_platform/openai.py,sha256=V_76W4hwKXRQ4Je7qj4nrTOedgQDc2_8l_NUuJq3Q2U,4115
|
|
54
|
+
jarvis/jarvis_platform/registry.py,sha256=QuH8V65uwqf-x_Y-T_rmvIDtPLzkX_COWPfzsH1eH0s,7612
|
|
55
|
+
jarvis/jarvis_platform/yuanbao.py,sha256=MjJVD0z28HHCSxpZaBFQAYxUCDIQdaYjuGv08uIWP-w,21754
|
|
56
|
+
jarvis/jarvis_platform_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
|
+
jarvis/jarvis_platform_manager/main.py,sha256=o7UDrcCkLf9dTh2LOO-_bQVHjWf2X6RuSY5XRtCGvZs,20245
|
|
58
|
+
jarvis/jarvis_platform_manager/openai_test.py,sha256=8L9Xx-oR82X8l38NsVhkymYucICwMb-6yrH17Usk2TI,4954
|
|
59
|
+
jarvis/jarvis_smart_shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
60
|
+
jarvis/jarvis_smart_shell/main.py,sha256=slP_8CwpfMjWFZis0At1ANRlPb3gx1KteAg1B7R7dl4,4546
|
|
61
|
+
jarvis/jarvis_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
62
|
+
jarvis/jarvis_tools/ask_codebase.py,sha256=xQTcuDl7cbH6uVkWlkA1HXJAo4_3r09-3SboUkBEBDU,10062
|
|
63
|
+
jarvis/jarvis_tools/ask_user.py,sha256=yafF6D54rFTIuRzIZKg6OiYZD35ZT5n8LrmVclZbfk0,2203
|
|
64
|
+
jarvis/jarvis_tools/base.py,sha256=MqUyC0R0Q960dioO0EYrcN25XrRWFwnUcxpA4Gp37Jo,1249
|
|
65
|
+
jarvis/jarvis_tools/chdir.py,sha256=tijYhhGbaAiTcA877w9thlxt0smoK2SX2AntcBBETmA,2727
|
|
66
|
+
jarvis/jarvis_tools/create_code_agent.py,sha256=7AOte1Ua6tOXjLYuetN6qwBx6ID0XX29IEjXmMAouxY,4295
|
|
67
|
+
jarvis/jarvis_tools/create_sub_agent.py,sha256=Hpu50UO-ekakYHxD6-5Civi9lvti5aPnRpTwSxAbFVo,3046
|
|
68
|
+
jarvis/jarvis_tools/execute_script.py,sha256=dMUwg_8nFkYqL-9gFO6LHM1kEKXYLW8PXHRtEWLFcBI,6485
|
|
69
|
+
jarvis/jarvis_tools/file_analyzer.py,sha256=b8FuU6zRlAO_g2p_AbBaCyEfgc7U3yPwfoAKgHwvCiQ,4870
|
|
70
|
+
jarvis/jarvis_tools/file_operation.py,sha256=efFTysX7G-4O8GyChZZRi_ozlDUV14ybflri_cGHRx0,10374
|
|
71
|
+
jarvis/jarvis_tools/find_methodology.py,sha256=zLxDPhoxrkECu_K6OlUDgvOWKewokCOp8VJMdomQns0,2276
|
|
72
|
+
jarvis/jarvis_tools/lsp_get_diagnostics.py,sha256=v_tnnaOgXBWog_73pbZdK-vR3MW2vC6BDmHVxlOF1GA,5363
|
|
73
|
+
jarvis/jarvis_tools/methodology.py,sha256=Nh5dvsUuRaWuLtN9TjdSa1qdAtWk2eLj_bNpKZfQJKE,5200
|
|
74
|
+
jarvis/jarvis_tools/read_code.py,sha256=8TFvORPxu_juMAPqj-UBa3qo810AMqXh8S3Gbq_IXaY,6133
|
|
75
|
+
jarvis/jarvis_tools/read_webpage.py,sha256=6ILzxZm45lW1zke4_01RLclFUbxgI_7mKgaTQtTovYU,2231
|
|
76
|
+
jarvis/jarvis_tools/registry.py,sha256=2rWau4Ib8AtJ2ZsckkNQp3CMC06wBQwSMktzGbv3v8I,17187
|
|
77
|
+
jarvis/jarvis_tools/search_web.py,sha256=ZM1LKb7VApSBn7H1a7oawkhkv7_KBPcCSBKfETED7vo,1397
|
|
78
|
+
jarvis/jarvis_tools/virtual_tty.py,sha256=9aSA14thmJ1e0PVhi0TNAj5lICiVD5j8DVIvzknDupc,15524
|
|
79
|
+
jarvis/jarvis_utils/__init__.py,sha256=KMg-KY5rZIhGTeOD5e2Xo5CU7DX1DUz4ULWAaTQ-ZNw,825
|
|
80
|
+
jarvis/jarvis_utils/config.py,sha256=W0N7aD0uMAQPLLbFapzK02uzGFtjlfotBQt6FbCIlwA,5190
|
|
81
|
+
jarvis/jarvis_utils/embedding.py,sha256=NjbhqoUrSH0p0upQCalGO3O34CyXQ8MMvF1eQTRn5JQ,7129
|
|
82
|
+
jarvis/jarvis_utils/file_processors.py,sha256=VchHOIXxxGWqSu5q0Q_epVWUHJTxaKz2wmqiDoRy5Ik,14324
|
|
83
|
+
jarvis/jarvis_utils/git_utils.py,sha256=rAMXKlAYIvqF64iDFc_FDLxi5SMqEuKYH8GzC7RaZGY,4967
|
|
84
|
+
jarvis/jarvis_utils/globals.py,sha256=DaQ-lfLtK8bDyGVlR6jtkenkkgxQVsIkSZCZwklelzc,2769
|
|
85
|
+
jarvis/jarvis_utils/input.py,sha256=yBrak_UP9ZN3fgV7G19o6TDBjEYVdh3UOyjQ_IpRvz8,6585
|
|
86
|
+
jarvis/jarvis_utils/methodology.py,sha256=A_LA-J2eOY22H0_NSTovcQA8f7BVwgpV6eWCoEZmvdM,6003
|
|
87
|
+
jarvis/jarvis_utils/output.py,sha256=EUJQ1pnCj7PcD9-gXIXMFNrxAwyZBeUd8X-fNEJYJ1k,8443
|
|
88
|
+
jarvis/jarvis_utils/utils.py,sha256=ZYclSrkrHBxatxYQkoNpAgIupO0j9CjiLIp8xBijWXc,12164
|
|
89
|
+
jarvis_ai_assistant-0.1.141.dist-info/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
|
|
90
|
+
jarvis_ai_assistant-0.1.141.dist-info/METADATA,sha256=McbbEQVqMZ1quCSQKwEbgQq21MvzZfVabCgSvo1N1wU,10004
|
|
91
|
+
jarvis_ai_assistant-0.1.141.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
|
92
|
+
jarvis_ai_assistant-0.1.141.dist-info/entry_points.txt,sha256=vuvEtcYSta_LgCFHS4m0OjtF7z1jKX_Dy2pG0rOMNIE,972
|
|
93
|
+
jarvis_ai_assistant-0.1.141.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
|
|
94
|
+
jarvis_ai_assistant-0.1.141.dist-info/RECORD,,
|
{jarvis_ai_assistant-0.1.138.dist-info → jarvis_ai_assistant-0.1.141.dist-info}/entry_points.txt
RENAMED
|
@@ -3,17 +3,17 @@ jarvis = jarvis.jarvis_agent.jarvis:main
|
|
|
3
3
|
jarvis-agent = jarvis.jarvis_agent.main:main
|
|
4
4
|
jarvis-ask-codebase = jarvis.jarvis_tools.ask_codebase:main
|
|
5
5
|
jarvis-code-agent = jarvis.jarvis_code_agent.code_agent:main
|
|
6
|
-
jarvis-code-review = jarvis.
|
|
6
|
+
jarvis-code-review = jarvis.jarvis_code_analysis.code_review:main
|
|
7
7
|
jarvis-dev = jarvis.jarvis_dev.main:main
|
|
8
|
-
jarvis-git-commit = jarvis.
|
|
8
|
+
jarvis-git-commit = jarvis.jarvis_git_utils.git_commiter:main
|
|
9
9
|
jarvis-git-details = jarvis.jarvis_git_details.main:main
|
|
10
10
|
jarvis-git-squash = jarvis.jarvis_git_squash.main:main
|
|
11
|
+
jarvis-init = jarvis.jarvis_init.main:main
|
|
11
12
|
jarvis-methodology = jarvis.jarvis_methodology.main:main
|
|
12
13
|
jarvis-multi-agent = jarvis.jarvis_multi_agent.main:main
|
|
13
14
|
jarvis-platform-manager = jarvis.jarvis_platform_manager.main:main
|
|
14
|
-
jarvis-rag = jarvis.jarvis_rag.main:main
|
|
15
15
|
jarvis-smart-shell = jarvis.jarvis_smart_shell.main:main
|
|
16
16
|
jarvis-tool = jarvis.jarvis_tools.registry:main
|
|
17
17
|
jca = jarvis.jarvis_code_agent.code_agent:main
|
|
18
|
-
jgc = jarvis.
|
|
18
|
+
jgc = jarvis.jarvis_git_utils.git_commiter:main
|
|
19
19
|
jss = jarvis.jarvis_smart_shell.main:main
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import re
|
|
3
|
-
from typing import Dict, List
|
|
4
|
-
from prompt_toolkit import PromptSession
|
|
5
|
-
from prompt_toolkit.completion import Completer, Completion
|
|
6
|
-
|
|
7
|
-
from jarvis.jarvis_utils.input import get_single_line_input
|
|
8
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
9
|
-
from jarvis.jarvis_utils.utils import user_confirm
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def _parse_file_selection(input_str: str, max_index: int) -> List[int]:
|
|
13
|
-
selected = set()
|
|
14
|
-
|
|
15
|
-
# Remove all whitespace characters
|
|
16
|
-
input_str = "".join(input_str.split())
|
|
17
|
-
|
|
18
|
-
# Process comma-separated parts
|
|
19
|
-
for part in input_str.split(","):
|
|
20
|
-
if not part:
|
|
21
|
-
continue
|
|
22
|
-
|
|
23
|
-
# Process range (e.g.: 3-6)
|
|
24
|
-
if "-" in part:
|
|
25
|
-
try:
|
|
26
|
-
start, end = map(int, part.split("-"))
|
|
27
|
-
# Convert to index starting from 0
|
|
28
|
-
start = max(0, start - 1)
|
|
29
|
-
end = min(max_index, end - 1)
|
|
30
|
-
if start <= end:
|
|
31
|
-
selected.update(range(start, end + 1))
|
|
32
|
-
except ValueError:
|
|
33
|
-
PrettyOutput.print(f"忽略无效的范围表达式: {part}", OutputType.WARNING)
|
|
34
|
-
# Process single number
|
|
35
|
-
else:
|
|
36
|
-
try:
|
|
37
|
-
index = int(part) - 1 # Convert to index starting from 0
|
|
38
|
-
if 0 <= index < max_index:
|
|
39
|
-
selected.add(index)
|
|
40
|
-
else:
|
|
41
|
-
PrettyOutput.print(f"忽略超出范围的索引: {part}", OutputType.WARNING)
|
|
42
|
-
except ValueError:
|
|
43
|
-
PrettyOutput.print(f"忽略无效的数字: {part}", OutputType.WARNING)
|
|
44
|
-
|
|
45
|
-
return sorted(list(selected))
|
|
46
|
-
|
|
47
|
-
def _get_file_completer(root_dir: str) -> Completer:
|
|
48
|
-
"""Create file path completer"""
|
|
49
|
-
class FileCompleter(Completer):
|
|
50
|
-
def __init__(self, root_dir: str):
|
|
51
|
-
self.root_dir = root_dir
|
|
52
|
-
|
|
53
|
-
def get_completions(self, document, complete_event):
|
|
54
|
-
text = document.text_before_cursor
|
|
55
|
-
|
|
56
|
-
if not text:
|
|
57
|
-
for path in self._list_files(""):
|
|
58
|
-
yield Completion(path, start_position=0)
|
|
59
|
-
return
|
|
60
|
-
|
|
61
|
-
# Generate fuzzy matching pattern
|
|
62
|
-
pattern = '.*'.join(map(re.escape, text))
|
|
63
|
-
try:
|
|
64
|
-
regex = re.compile(pattern, re.IGNORECASE)
|
|
65
|
-
except re.error:
|
|
66
|
-
return
|
|
67
|
-
|
|
68
|
-
for path in self._list_files(""):
|
|
69
|
-
if regex.search(path):
|
|
70
|
-
yield Completion(path, start_position=-len(text))
|
|
71
|
-
|
|
72
|
-
def _list_files(self, current_dir: str) -> List[str]:
|
|
73
|
-
"""List all files in the specified directory (recursively)"""
|
|
74
|
-
files = []
|
|
75
|
-
search_dir = os.path.join(self.root_dir, current_dir)
|
|
76
|
-
|
|
77
|
-
for root, _, filenames in os.walk(search_dir):
|
|
78
|
-
for filename in filenames:
|
|
79
|
-
full_path = os.path.join(root, filename)
|
|
80
|
-
rel_path = os.path.relpath(full_path, self.root_dir)
|
|
81
|
-
if not any(part.startswith('.') for part in rel_path.split(os.sep)):
|
|
82
|
-
files.append(rel_path)
|
|
83
|
-
|
|
84
|
-
return sorted(files)
|
|
85
|
-
|
|
86
|
-
return FileCompleter(root_dir)
|
|
87
|
-
|
|
88
|
-
def _fuzzy_match_files(root_dir: str, pattern: str) -> List[str]:
|
|
89
|
-
"""Fuzzy match file path
|
|
90
|
-
|
|
91
|
-
Args:
|
|
92
|
-
pattern: Matching pattern
|
|
93
|
-
|
|
94
|
-
Returns:
|
|
95
|
-
List[str]: List of matching file paths
|
|
96
|
-
"""
|
|
97
|
-
matches = []
|
|
98
|
-
|
|
99
|
-
# 将模式转换为正则表达式
|
|
100
|
-
pattern = pattern.replace('.', r'\.').replace('*', '.*').replace('?', '.')
|
|
101
|
-
pattern = f".*{pattern}.*" # 允许部分匹配
|
|
102
|
-
regex = re.compile(pattern, re.IGNORECASE)
|
|
103
|
-
|
|
104
|
-
# 遍历所有文件
|
|
105
|
-
for root, _, files in os.walk(root_dir):
|
|
106
|
-
for file in files:
|
|
107
|
-
full_path = os.path.join(root, file)
|
|
108
|
-
rel_path = os.path.relpath(full_path, root_dir)
|
|
109
|
-
# 忽略 .git 目录和其他隐藏文件
|
|
110
|
-
if not any(part.startswith('.') for part in rel_path.split(os.sep)):
|
|
111
|
-
if regex.match(rel_path):
|
|
112
|
-
matches.append(rel_path)
|
|
113
|
-
|
|
114
|
-
return sorted(matches)
|
|
115
|
-
|
|
116
|
-
def select_files(related_files: List[Dict[str, str]], root_dir: str) -> List[Dict[str, str]]:
|
|
117
|
-
"""Let the user select and supplement related files"""
|
|
118
|
-
output = ""
|
|
119
|
-
# Display found files
|
|
120
|
-
selected_files = list(related_files) # Default select all
|
|
121
|
-
for i, file in enumerate(related_files, 1):
|
|
122
|
-
output += f"[{i}] {file['file']} ({file['reason']})\n"
|
|
123
|
-
|
|
124
|
-
# Filter out files that do not exist
|
|
125
|
-
related_files = [f for f in related_files if os.path.isfile(os.path.join(root_dir, f["file"]))]
|
|
126
|
-
|
|
127
|
-
if output:
|
|
128
|
-
PrettyOutput.section("相关文件", OutputType.INFO)
|
|
129
|
-
PrettyOutput.print(output, OutputType.INFO, lang="markdown")
|
|
130
|
-
|
|
131
|
-
if len(related_files) > 0:
|
|
132
|
-
# Ask the user if they need to adjust the file list
|
|
133
|
-
if user_confirm("是否需要调整文件列表?", False):
|
|
134
|
-
# Let the user select files
|
|
135
|
-
numbers = get_single_line_input("请输入要包含的文件编号(支持: 1,3-6格式, 按回车保持当前选择)").strip()
|
|
136
|
-
if numbers:
|
|
137
|
-
selected_indices = _parse_file_selection(numbers, len(related_files))
|
|
138
|
-
if selected_indices:
|
|
139
|
-
selected_files = [related_files[i] for i in selected_indices]
|
|
140
|
-
else:
|
|
141
|
-
PrettyOutput.print("没有有效的文件被选择, 保持当前选择", OutputType.WARNING)
|
|
142
|
-
|
|
143
|
-
tips = ""
|
|
144
|
-
# Ask if they need to supplement files
|
|
145
|
-
if user_confirm("是否需要补充其他文件?", False):
|
|
146
|
-
# Create file completion session
|
|
147
|
-
session = PromptSession(
|
|
148
|
-
completer=_get_file_completer(root_dir),
|
|
149
|
-
complete_while_typing=True
|
|
150
|
-
)
|
|
151
|
-
PrettyOutput.print("请输入要补充的文件路径(支持Tab补全和*?通配符, 输入空行结束)", OutputType.INFO)
|
|
152
|
-
while True:
|
|
153
|
-
try:
|
|
154
|
-
file_path = session.prompt(">>> ").strip()
|
|
155
|
-
except KeyboardInterrupt:
|
|
156
|
-
break
|
|
157
|
-
|
|
158
|
-
if not file_path:
|
|
159
|
-
break
|
|
160
|
-
|
|
161
|
-
# Process wildcard matching
|
|
162
|
-
if '*' in file_path or '?' in file_path:
|
|
163
|
-
matches = _fuzzy_match_files(root_dir, file_path)
|
|
164
|
-
if not matches:
|
|
165
|
-
PrettyOutput.print("没有找到匹配的文件", OutputType.WARNING)
|
|
166
|
-
continue
|
|
167
|
-
|
|
168
|
-
# Display matching files
|
|
169
|
-
tips = "找到以下匹配的文件:"
|
|
170
|
-
for i, path in enumerate(matches, 1):
|
|
171
|
-
tips += f"\n[{i}] {path}"
|
|
172
|
-
PrettyOutput.print(tips, OutputType.INFO)
|
|
173
|
-
|
|
174
|
-
# Let the user select
|
|
175
|
-
numbers = get_single_line_input("请选择要添加的文件编号(支持: 1,3-6格式, 按回车选择所有)").strip()
|
|
176
|
-
if numbers:
|
|
177
|
-
indices = _parse_file_selection(numbers, len(matches))
|
|
178
|
-
if not indices:
|
|
179
|
-
continue
|
|
180
|
-
paths_to_add = [matches[i] for i in indices]
|
|
181
|
-
else:
|
|
182
|
-
paths_to_add = matches
|
|
183
|
-
else:
|
|
184
|
-
paths_to_add = [file_path]
|
|
185
|
-
|
|
186
|
-
# Add selected files
|
|
187
|
-
tips = "添加以下文件:"
|
|
188
|
-
for path in paths_to_add:
|
|
189
|
-
full_path = os.path.join(root_dir, path)
|
|
190
|
-
if not os.path.isfile(full_path):
|
|
191
|
-
tips += f"\n文件不存在: {path}"
|
|
192
|
-
continue
|
|
193
|
-
|
|
194
|
-
try:
|
|
195
|
-
selected_files.append({"file": path, "reason": "I Added"})
|
|
196
|
-
tips += f"\n文件已添加: {path}"
|
|
197
|
-
except Exception as e:
|
|
198
|
-
tips += f"\n读取文件失败: {str(e)}"
|
|
199
|
-
selected_files = [f for f in selected_files if os.path.isfile(os.path.join(root_dir, f["file"]))]
|
|
200
|
-
if tips:
|
|
201
|
-
PrettyOutput.print(tips, OutputType.INFO)
|
|
202
|
-
return selected_files
|