jarvis-ai-assistant 0.1.192__py3-none-any.whl → 0.1.194__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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +69 -37
- jarvis/jarvis_agent/builtin_input_handler.py +26 -4
- jarvis/jarvis_agent/jarvis.py +38 -22
- jarvis/jarvis_agent/main.py +20 -12
- jarvis/jarvis_agent/output_handler.py +7 -7
- jarvis/jarvis_agent/shell_input_handler.py +14 -11
- jarvis/jarvis_code_agent/code_agent.py +93 -90
- jarvis/jarvis_code_agent/lint.py +92 -105
- jarvis/jarvis_code_analysis/checklists/__init__.py +1 -1
- jarvis/jarvis_code_analysis/checklists/c_cpp.py +1 -1
- jarvis/jarvis_code_analysis/checklists/csharp.py +1 -1
- jarvis/jarvis_code_analysis/checklists/data_format.py +1 -1
- jarvis/jarvis_code_analysis/checklists/devops.py +1 -1
- jarvis/jarvis_code_analysis/checklists/docs.py +1 -1
- jarvis/jarvis_code_analysis/checklists/go.py +1 -1
- jarvis/jarvis_code_analysis/checklists/infrastructure.py +1 -1
- jarvis/jarvis_code_analysis/checklists/java.py +1 -1
- jarvis/jarvis_code_analysis/checklists/javascript.py +1 -1
- jarvis/jarvis_code_analysis/checklists/kotlin.py +1 -1
- jarvis/jarvis_code_analysis/checklists/loader.py +51 -35
- jarvis/jarvis_code_analysis/checklists/php.py +1 -1
- jarvis/jarvis_code_analysis/checklists/python.py +1 -1
- jarvis/jarvis_code_analysis/checklists/ruby.py +1 -1
- jarvis/jarvis_code_analysis/checklists/rust.py +1 -1
- jarvis/jarvis_code_analysis/checklists/shell.py +1 -1
- jarvis/jarvis_code_analysis/checklists/sql.py +1 -1
- jarvis/jarvis_code_analysis/checklists/swift.py +1 -1
- jarvis/jarvis_code_analysis/checklists/web.py +1 -1
- jarvis/jarvis_code_analysis/code_review.py +293 -192
- jarvis/jarvis_dev/main.py +73 -56
- jarvis/jarvis_git_details/main.py +29 -33
- jarvis/jarvis_git_squash/main.py +13 -11
- jarvis/jarvis_git_utils/git_commiter.py +12 -3
- jarvis/jarvis_mcp/__init__.py +8 -10
- jarvis/jarvis_mcp/sse_mcp_client.py +182 -205
- jarvis/jarvis_mcp/stdio_mcp_client.py +93 -120
- jarvis/jarvis_mcp/streamable_mcp_client.py +117 -142
- jarvis/jarvis_methodology/main.py +81 -47
- jarvis/jarvis_multi_agent/__init__.py +24 -16
- jarvis/jarvis_multi_agent/main.py +10 -4
- jarvis/jarvis_platform/__init__.py +1 -1
- jarvis/jarvis_platform/base.py +49 -21
- jarvis/jarvis_platform/human.py +5 -3
- jarvis/jarvis_platform/kimi.py +96 -72
- jarvis/jarvis_platform/openai.py +23 -28
- jarvis/jarvis_platform/registry.py +50 -33
- jarvis/jarvis_platform/tongyi.py +16 -10
- jarvis/jarvis_platform/yuanbao.py +205 -147
- jarvis/jarvis_platform_manager/main.py +4 -2
- jarvis/jarvis_smart_shell/main.py +35 -29
- jarvis/jarvis_tools/ask_user.py +8 -16
- jarvis/jarvis_tools/base.py +3 -2
- jarvis/jarvis_tools/chdir.py +7 -19
- jarvis/jarvis_tools/cli/main.py +14 -10
- jarvis/jarvis_tools/code_plan.py +10 -31
- jarvis/jarvis_tools/create_code_agent.py +10 -13
- jarvis/jarvis_tools/create_sub_agent.py +10 -22
- jarvis/jarvis_tools/edit_file.py +98 -76
- jarvis/jarvis_tools/execute_script.py +46 -46
- jarvis/jarvis_tools/file_analyzer.py +22 -34
- jarvis/jarvis_tools/file_operation.py +69 -62
- jarvis/jarvis_tools/generate_new_tool.py +0 -2
- jarvis/jarvis_tools/methodology.py +19 -23
- jarvis/jarvis_tools/read_code.py +42 -33
- jarvis/jarvis_tools/read_webpage.py +7 -16
- jarvis/jarvis_tools/registry.py +65 -32
- jarvis/jarvis_tools/rewrite_file.py +26 -29
- jarvis/jarvis_tools/search_web.py +5 -8
- jarvis/jarvis_tools/virtual_tty.py +133 -122
- jarvis/jarvis_utils/__init__.py +0 -1
- jarvis/jarvis_utils/builtin_replace_map.py +96 -8
- jarvis/jarvis_utils/config.py +59 -32
- jarvis/jarvis_utils/embedding.py +17 -14
- jarvis/jarvis_utils/file_processors.py +16 -9
- jarvis/jarvis_utils/git_utils.py +140 -99
- jarvis/jarvis_utils/globals.py +1 -1
- jarvis/jarvis_utils/input.py +84 -52
- jarvis/jarvis_utils/methodology.py +28 -21
- jarvis/jarvis_utils/output.py +159 -78
- jarvis/jarvis_utils/tag.py +2 -1
- jarvis/jarvis_utils/utils.py +85 -51
- {jarvis_ai_assistant-0.1.192.dist-info → jarvis_ai_assistant-0.1.194.dist-info}/METADATA +337 -204
- jarvis_ai_assistant-0.1.194.dist-info/RECORD +97 -0
- jarvis/jarvis_agent/file_input_handler.py +0 -112
- jarvis/jarvis_event/__init__.py +0 -0
- jarvis_ai_assistant-0.1.192.dist-info/RECORD +0 -99
- {jarvis_ai_assistant-0.1.192.dist-info → jarvis_ai_assistant-0.1.194.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.192.dist-info → jarvis_ai_assistant-0.1.194.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.192.dist-info → jarvis_ai_assistant-0.1.194.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.192.dist-info → jarvis_ai_assistant-0.1.194.dist-info}/top_level.txt +0 -0
jarvis/jarvis_utils/output.py
CHANGED
@@ -42,6 +42,7 @@ class OutputType(Enum):
|
|
42
42
|
USER: 用户输入
|
43
43
|
TOOL: 工具调用
|
44
44
|
"""
|
45
|
+
|
45
46
|
SYSTEM = "SYSTEM"
|
46
47
|
CODE = "CODE"
|
47
48
|
RESULT = "RESULT"
|
@@ -54,6 +55,8 @@ class OutputType(Enum):
|
|
54
55
|
DEBUG = "DEBUG"
|
55
56
|
USER = "USER"
|
56
57
|
TOOL = "TOOL"
|
58
|
+
|
59
|
+
|
57
60
|
class PrettyOutput:
|
58
61
|
"""
|
59
62
|
使用rich库格式化和显示富文本输出的类。
|
@@ -64,6 +67,7 @@ class PrettyOutput:
|
|
64
67
|
- 结构化内容的面板显示
|
65
68
|
- 渐进显示的流式输出
|
66
69
|
"""
|
70
|
+
|
67
71
|
# 不同输出类型的图标
|
68
72
|
_ICONS = {
|
69
73
|
OutputType.SYSTEM: "🤖",
|
@@ -81,39 +85,40 @@ class PrettyOutput:
|
|
81
85
|
}
|
82
86
|
# 语法高亮的语言映射
|
83
87
|
_lang_map = {
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
88
|
+
"Python": "python",
|
89
|
+
"JavaScript": "javascript",
|
90
|
+
"TypeScript": "typescript",
|
91
|
+
"Java": "java",
|
92
|
+
"C++": "cpp",
|
93
|
+
"C#": "csharp",
|
94
|
+
"Ruby": "ruby",
|
95
|
+
"PHP": "php",
|
96
|
+
"Go": "go",
|
97
|
+
"Rust": "rust",
|
98
|
+
"Bash": "bash",
|
99
|
+
"HTML": "html",
|
100
|
+
"CSS": "css",
|
101
|
+
"SQL": "sql",
|
102
|
+
"R": "r",
|
103
|
+
"Kotlin": "kotlin",
|
104
|
+
"Swift": "swift",
|
105
|
+
"Scala": "scala",
|
106
|
+
"Perl": "perl",
|
107
|
+
"Lua": "lua",
|
108
|
+
"YAML": "yaml",
|
109
|
+
"JSON": "json",
|
110
|
+
"XML": "xml",
|
111
|
+
"Markdown": "markdown",
|
112
|
+
"Text": "text",
|
113
|
+
"Shell": "bash",
|
114
|
+
"Dockerfile": "dockerfile",
|
115
|
+
"Makefile": "makefile",
|
116
|
+
"INI": "ini",
|
117
|
+
"TOML": "toml",
|
114
118
|
}
|
119
|
+
|
115
120
|
@staticmethod
|
116
|
-
def _detect_language(text: str, default_lang: str =
|
121
|
+
def _detect_language(text: str, default_lang: str = "markdown") -> str:
|
117
122
|
"""
|
118
123
|
检测给定文本的编程语言。
|
119
124
|
|
@@ -130,6 +135,7 @@ class PrettyOutput:
|
|
130
135
|
return PrettyOutput._lang_map.get(detected_lang, default_lang)
|
131
136
|
except (ClassNotFound, Exception):
|
132
137
|
return default_lang
|
138
|
+
|
133
139
|
@staticmethod
|
134
140
|
def _format(output_type: OutputType, timestamp: bool = True) -> str:
|
135
141
|
"""
|
@@ -145,13 +151,20 @@ class PrettyOutput:
|
|
145
151
|
icon = PrettyOutput._ICONS.get(output_type, "")
|
146
152
|
formatted = f"{icon} "
|
147
153
|
if timestamp:
|
148
|
-
formatted+=f"[{datetime.now().strftime('%H:%M:%S')}][{output_type.value}]"
|
154
|
+
formatted += f"[{datetime.now().strftime('%H:%M:%S')}][{output_type.value}]"
|
149
155
|
agent_info = get_agent_list()
|
150
156
|
if agent_info:
|
151
|
-
formatted+=f"[{agent_info}]"
|
157
|
+
formatted += f"[{agent_info}]"
|
152
158
|
return formatted
|
159
|
+
|
153
160
|
@staticmethod
|
154
|
-
def print(
|
161
|
+
def print(
|
162
|
+
text: str,
|
163
|
+
output_type: OutputType,
|
164
|
+
timestamp: bool = True,
|
165
|
+
lang: Optional[str] = None,
|
166
|
+
traceback: bool = False,
|
167
|
+
):
|
155
168
|
"""
|
156
169
|
使用样式和语法高亮打印格式化输出。
|
157
170
|
|
@@ -163,38 +176,101 @@ class PrettyOutput:
|
|
163
176
|
traceback: 是否显示错误的回溯信息
|
164
177
|
"""
|
165
178
|
styles = {
|
166
|
-
OutputType.SYSTEM: dict(
|
167
|
-
OutputType.CODE: dict(
|
168
|
-
OutputType.RESULT: dict(
|
169
|
-
OutputType.ERROR: dict(
|
170
|
-
OutputType.INFO: dict(
|
171
|
-
OutputType.PLANNING: dict(
|
172
|
-
OutputType.PROGRESS: dict(
|
173
|
-
OutputType.SUCCESS: dict(
|
174
|
-
OutputType.WARNING: dict(
|
175
|
-
OutputType.DEBUG: dict(
|
176
|
-
OutputType.USER: dict(
|
177
|
-
OutputType.TOOL: dict(
|
179
|
+
OutputType.SYSTEM: dict(bgcolor="#1e2b3c"),
|
180
|
+
OutputType.CODE: dict(bgcolor="#1c2b1c"),
|
181
|
+
OutputType.RESULT: dict(bgcolor="#1c1c2b"),
|
182
|
+
OutputType.ERROR: dict(bgcolor="#2b1c1c"),
|
183
|
+
OutputType.INFO: dict(bgcolor="#2b2b1c", meta={"icon": "ℹ️"}),
|
184
|
+
OutputType.PLANNING: dict(bgcolor="#2b1c2b"),
|
185
|
+
OutputType.PROGRESS: dict(bgcolor="#1c1c1c"),
|
186
|
+
OutputType.SUCCESS: dict(bgcolor="#1c2b1c"),
|
187
|
+
OutputType.WARNING: dict(bgcolor="#2b2b1c"),
|
188
|
+
OutputType.DEBUG: dict(bgcolor="#1c1c1c"),
|
189
|
+
OutputType.USER: dict(bgcolor="#1c2b2b"),
|
190
|
+
OutputType.TOOL: dict(bgcolor="#1c2b2b"),
|
178
191
|
}
|
179
192
|
|
180
193
|
header_styles = {
|
181
|
-
OutputType.SYSTEM: RichStyle(
|
182
|
-
|
183
|
-
|
184
|
-
OutputType.
|
185
|
-
|
186
|
-
|
187
|
-
OutputType.
|
188
|
-
|
189
|
-
|
190
|
-
OutputType.
|
191
|
-
|
192
|
-
|
194
|
+
OutputType.SYSTEM: RichStyle(
|
195
|
+
color="bright_cyan", bgcolor="#1e2b3c", frame=True, meta={"icon": "🤖"}
|
196
|
+
),
|
197
|
+
OutputType.CODE: RichStyle(
|
198
|
+
color="green", bgcolor="#1c2b1c", frame=True, meta={"icon": "📝"}
|
199
|
+
),
|
200
|
+
OutputType.RESULT: RichStyle(
|
201
|
+
color="bright_blue", bgcolor="#1c1c2b", frame=True, meta={"icon": "✨"}
|
202
|
+
),
|
203
|
+
OutputType.ERROR: RichStyle(
|
204
|
+
color="red", frame=True, bgcolor="#2b1c1c", meta={"icon": "❌"}
|
205
|
+
),
|
206
|
+
OutputType.INFO: RichStyle(
|
207
|
+
color="gold1", frame=True, bgcolor="#2b2b1c", meta={"icon": "ℹ️"}
|
208
|
+
),
|
209
|
+
OutputType.PLANNING: RichStyle(
|
210
|
+
color="purple",
|
211
|
+
bold=True,
|
212
|
+
frame=True,
|
213
|
+
bgcolor="#2b1c2b",
|
214
|
+
meta={"icon": "📋"},
|
215
|
+
),
|
216
|
+
OutputType.PROGRESS: RichStyle(
|
217
|
+
color="white",
|
218
|
+
encircle=True,
|
219
|
+
frame=True,
|
220
|
+
bgcolor="#1c1c1c",
|
221
|
+
meta={"icon": "⏳"},
|
222
|
+
),
|
223
|
+
OutputType.SUCCESS: RichStyle(
|
224
|
+
color="bright_green",
|
225
|
+
bold=True,
|
226
|
+
strike=False,
|
227
|
+
bgcolor="#1c2b1c",
|
228
|
+
meta={"icon": "✅"},
|
229
|
+
),
|
230
|
+
OutputType.WARNING: RichStyle(
|
231
|
+
color="yellow",
|
232
|
+
bold=True,
|
233
|
+
blink2=True,
|
234
|
+
bgcolor="#2b2b1c",
|
235
|
+
meta={"icon": "⚠️"},
|
236
|
+
),
|
237
|
+
OutputType.DEBUG: RichStyle(
|
238
|
+
color="grey58",
|
239
|
+
dim=True,
|
240
|
+
conceal=True,
|
241
|
+
bgcolor="#1c1c1c",
|
242
|
+
meta={"icon": "🔍"},
|
243
|
+
),
|
244
|
+
OutputType.USER: RichStyle(
|
245
|
+
color="spring_green2",
|
246
|
+
frame=True,
|
247
|
+
bgcolor="#1c2b2b",
|
248
|
+
meta={"icon": "👤"},
|
249
|
+
),
|
250
|
+
OutputType.TOOL: RichStyle(
|
251
|
+
color="dark_sea_green4",
|
252
|
+
bgcolor="#1c2b2b",
|
253
|
+
frame=True,
|
254
|
+
meta={"icon": "🔧"},
|
255
|
+
),
|
193
256
|
}
|
194
257
|
|
195
|
-
lang =
|
196
|
-
|
197
|
-
|
258
|
+
lang = (
|
259
|
+
lang
|
260
|
+
if lang is not None
|
261
|
+
else PrettyOutput._detect_language(text, default_lang="markdown")
|
262
|
+
)
|
263
|
+
header = Text(
|
264
|
+
PrettyOutput._format(output_type, timestamp),
|
265
|
+
style=header_styles[output_type],
|
266
|
+
)
|
267
|
+
content = Syntax(
|
268
|
+
text,
|
269
|
+
lang,
|
270
|
+
theme="monokai",
|
271
|
+
word_wrap=True,
|
272
|
+
background_color=styles[output_type]["bgcolor"],
|
273
|
+
)
|
198
274
|
panel = Panel(
|
199
275
|
content,
|
200
276
|
border_style=header_styles[output_type],
|
@@ -213,6 +289,7 @@ class PrettyOutput:
|
|
213
289
|
console.print(header, content)
|
214
290
|
if traceback:
|
215
291
|
console.print_exception()
|
292
|
+
|
216
293
|
@staticmethod
|
217
294
|
def section(title: str, output_type: OutputType = OutputType.INFO):
|
218
295
|
"""
|
@@ -223,38 +300,42 @@ class PrettyOutput:
|
|
223
300
|
output_type: 输出类型(影响样式)
|
224
301
|
"""
|
225
302
|
text = Text(title, style=output_type.value, justify="center")
|
226
|
-
panel = Panel(
|
227
|
-
text,
|
228
|
-
border_style=output_type.value
|
229
|
-
)
|
303
|
+
panel = Panel(text, border_style=output_type.value)
|
230
304
|
if get_pretty_output():
|
231
305
|
console.print(panel)
|
232
306
|
else:
|
233
307
|
console.print(text)
|
234
|
-
|
308
|
+
|
235
309
|
@staticmethod
|
236
|
-
def print_gradient_text(
|
310
|
+
def print_gradient_text(
|
311
|
+
text: str, start_color: Tuple[int, int, int], end_color: Tuple[int, int, int]
|
312
|
+
) -> None:
|
237
313
|
"""打印带有渐变色彩的文本。
|
238
|
-
|
314
|
+
|
239
315
|
Args:
|
240
316
|
text: 要打印的文本
|
241
317
|
start_color: 起始RGB颜色元组 (r, g, b)
|
242
318
|
end_color: 结束RGB颜色元组 (r, g, b)
|
243
319
|
"""
|
244
|
-
lines = text.strip(
|
320
|
+
lines = text.strip("\n").split("\n")
|
245
321
|
total_lines = len(lines)
|
246
322
|
colored_lines = []
|
247
323
|
for i, line in enumerate(lines):
|
248
324
|
# 计算当前行的渐变颜色
|
249
|
-
r = int(
|
250
|
-
|
251
|
-
|
252
|
-
|
325
|
+
r = int(
|
326
|
+
start_color[0] + (end_color[0] - start_color[0]) * i / (total_lines - 1)
|
327
|
+
)
|
328
|
+
g = int(
|
329
|
+
start_color[1] + (end_color[1] - start_color[1]) * i / (total_lines - 1)
|
330
|
+
)
|
331
|
+
b = int(
|
332
|
+
start_color[2] + (end_color[2] - start_color[2]) * i / (total_lines - 1)
|
333
|
+
)
|
334
|
+
|
253
335
|
# 使用ANSI转义序列设置颜色
|
254
336
|
colored_lines.append(f"\033[38;2;{r};{g};{b}m{line}\033[0m")
|
255
|
-
colored_text = Text(
|
256
|
-
|
257
|
-
colored_text,
|
258
|
-
box=SIMPLE
|
337
|
+
colored_text = Text(
|
338
|
+
"\n".join(colored_lines), style=OutputType.TOOL.value, justify="center"
|
259
339
|
)
|
260
|
-
|
340
|
+
panel = Panel(colored_text, box=SIMPLE)
|
341
|
+
console.print(panel)
|
jarvis/jarvis_utils/tag.py
CHANGED
@@ -10,6 +10,7 @@ def ot(tag_name: str) -> str:
|
|
10
10
|
"""
|
11
11
|
return f"<{tag_name}>"
|
12
12
|
|
13
|
+
|
13
14
|
def ct(tag_name: str) -> str:
|
14
15
|
"""生成HTML标签结束标记
|
15
16
|
|
@@ -19,4 +20,4 @@ def ct(tag_name: str) -> str:
|
|
19
20
|
返回:
|
20
21
|
格式化的结束标签字符串
|
21
22
|
"""
|
22
|
-
return f"</{tag_name}>"
|
23
|
+
return f"</{tag_name}>"
|
jarvis/jarvis_utils/utils.py
CHANGED
@@ -11,12 +11,17 @@ from typing import Any, Callable, Dict, Optional
|
|
11
11
|
import yaml
|
12
12
|
|
13
13
|
from jarvis import __version__
|
14
|
-
from jarvis.jarvis_utils.config import
|
14
|
+
from jarvis.jarvis_utils.config import (
|
15
|
+
get_data_dir,
|
16
|
+
get_max_big_content_size,
|
17
|
+
set_global_env_data,
|
18
|
+
)
|
15
19
|
from jarvis.jarvis_utils.embedding import get_context_token_count
|
16
20
|
from jarvis.jarvis_utils.input import get_single_line_input
|
17
21
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
18
22
|
from jarvis.jarvis_utils.globals import get_in_chat, get_interrupt, set_interrupt
|
19
23
|
|
24
|
+
g_config_file = None
|
20
25
|
|
21
26
|
|
22
27
|
def init_env(welcome_str: str, config_file: Optional[str] = None) -> None:
|
@@ -35,7 +40,7 @@ def init_env(welcome_str: str, config_file: Optional[str] = None) -> None:
|
|
35
40
|
"""
|
36
41
|
# 保存原始信号处理函数
|
37
42
|
original_sigint = signal.getsignal(signal.SIGINT)
|
38
|
-
|
43
|
+
|
39
44
|
def sigint_handler(signum, frame):
|
40
45
|
if get_in_chat():
|
41
46
|
set_interrupt(True)
|
@@ -44,7 +49,7 @@ def init_env(welcome_str: str, config_file: Optional[str] = None) -> None:
|
|
44
49
|
else:
|
45
50
|
if original_sigint and callable(original_sigint):
|
46
51
|
original_sigint(signum, frame)
|
47
|
-
|
52
|
+
|
48
53
|
signal.signal(signal.SIGINT, sigint_handler)
|
49
54
|
count_cmd_usage()
|
50
55
|
|
@@ -63,22 +68,16 @@ def init_env(welcome_str: str, config_file: Optional[str] = None) -> None:
|
|
63
68
|
if welcome_str:
|
64
69
|
PrettyOutput.print_gradient_text(jarvis_ascii_art, (0, 120, 255), (0, 255, 200))
|
65
70
|
|
66
|
-
|
71
|
+
global g_config_file
|
72
|
+
g_config_file = config_file
|
67
73
|
|
68
|
-
|
69
|
-
if not config_file_path.exists():
|
70
|
-
old_config_file = config_file_path.parent / "env"
|
71
|
-
if old_config_file.exists():# 旧的配置文件存在
|
72
|
-
_read_old_config_file(old_config_file)
|
73
|
-
else:
|
74
|
-
_read_config_file(config_file_path.parent, config_file_path)
|
74
|
+
load_config()
|
75
75
|
|
76
76
|
# 现在获取最终的数据目录(可能被配置文件修改)
|
77
77
|
data_dir = Path(get_data_dir())
|
78
78
|
script_dir = Path(os.path.dirname(os.path.dirname(__file__)))
|
79
79
|
hf_archive = script_dir / "jarvis_data" / "huggingface.tar.gz"
|
80
80
|
|
81
|
-
|
82
81
|
# 检查并解压huggingface模型
|
83
82
|
hf_dir = data_dir / "huggingface" / "hub"
|
84
83
|
if not hf_dir.exists() and hf_archive.exists():
|
@@ -88,22 +87,40 @@ def init_env(welcome_str: str, config_file: Optional[str] = None) -> None:
|
|
88
87
|
tar.extractall(path=data_dir)
|
89
88
|
PrettyOutput.print("HuggingFace模型解压完成", OutputType.SUCCESS)
|
90
89
|
except Exception as e:
|
91
|
-
PrettyOutput.print(f"解压HuggingFace模型失败: {e}", OutputType.ERROR)
|
90
|
+
PrettyOutput.print(f"解压HuggingFace模型失败: {e}", OutputType.ERROR)
|
92
91
|
|
93
92
|
# 检查是否是git仓库并更新
|
94
93
|
from jarvis.jarvis_utils.git_utils import check_and_update_git_repo
|
95
94
|
|
96
95
|
check_and_update_git_repo(str(script_dir))
|
97
96
|
|
97
|
+
|
98
|
+
def load_config():
|
99
|
+
config_file = g_config_file
|
100
|
+
config_file_path = (
|
101
|
+
Path(config_file)
|
102
|
+
if config_file is not None
|
103
|
+
else Path(os.path.expanduser("~/.jarvis/config.yaml"))
|
104
|
+
)
|
105
|
+
|
106
|
+
# 加载配置文件
|
107
|
+
if not config_file_path.exists():
|
108
|
+
old_config_file = config_file_path.parent / "env"
|
109
|
+
if old_config_file.exists(): # 旧的配置文件存在
|
110
|
+
_read_old_config_file(old_config_file)
|
111
|
+
else:
|
112
|
+
_read_config_file(config_file_path.parent, config_file_path)
|
113
|
+
|
114
|
+
|
98
115
|
def _read_config_file(jarvis_dir, config_file):
|
99
116
|
"""读取并解析YAML格式的配置文件
|
100
|
-
|
117
|
+
|
101
118
|
功能:
|
102
119
|
1. 读取配置文件内容
|
103
120
|
2. 检查并添加schema声明(如果缺失)
|
104
121
|
3. 将配置数据保存到全局变量
|
105
122
|
4. 设置环境变量(如果配置中有ENV字段)
|
106
|
-
|
123
|
+
|
107
124
|
参数:
|
108
125
|
jarvis_dir: Jarvis数据目录路径
|
109
126
|
config_file: 配置文件路径
|
@@ -112,31 +129,38 @@ def _read_config_file(jarvis_dir, config_file):
|
|
112
129
|
content = f.read()
|
113
130
|
config_data = yaml.safe_load(content) or {}
|
114
131
|
if isinstance(config_data, dict):
|
115
|
-
|
132
|
+
# 检查是否已有schema声明,没有则添加
|
116
133
|
if "# yaml-language-server: $schema=" not in content:
|
117
|
-
schema_path = Path(
|
118
|
-
|
119
|
-
|
120
|
-
|
134
|
+
schema_path = Path(
|
135
|
+
os.path.relpath(
|
136
|
+
Path(__file__).parent.parent
|
137
|
+
/ "jarvis_data"
|
138
|
+
/ "config_schema.json",
|
139
|
+
start=jarvis_dir,
|
140
|
+
)
|
141
|
+
)
|
121
142
|
with open(config_file, "w", encoding="utf-8") as f:
|
122
143
|
f.write(f"# yaml-language-server: $schema={schema_path}\n")
|
123
144
|
f.write(content)
|
124
145
|
# 保存到全局变量
|
125
146
|
set_global_env_data(config_data)
|
126
|
-
|
147
|
+
# 如果配置中有ENV键值对,则设置环境变量
|
127
148
|
if "ENV" in config_data and isinstance(config_data["ENV"], dict):
|
128
|
-
os.environ.update(
|
149
|
+
os.environ.update(
|
150
|
+
{str(k): str(v) for k, v in config_data["ENV"].items() if v is not None}
|
151
|
+
)
|
152
|
+
|
129
153
|
|
130
154
|
def _read_old_config_file(config_file):
|
131
155
|
"""读取并解析旧格式的env配置文件
|
132
|
-
|
156
|
+
|
133
157
|
功能:
|
134
158
|
1. 解析键值对格式的旧配置文件
|
135
159
|
2. 支持多行值的处理
|
136
160
|
3. 自动去除值的引号和空格
|
137
161
|
4. 将配置数据保存到全局变量
|
138
162
|
5. 设置环境变量并显示迁移警告
|
139
|
-
|
163
|
+
|
140
164
|
参数:
|
141
165
|
config_file: 旧格式配置文件路径
|
142
166
|
"""
|
@@ -149,7 +173,7 @@ def _read_old_config_file(config_file):
|
|
149
173
|
if not line or line.startswith(("#", ";")):
|
150
174
|
continue
|
151
175
|
if "=" in line and not line.startswith((" ", "\t")):
|
152
|
-
|
176
|
+
# 处理之前收集的多行值
|
153
177
|
if current_key is not None:
|
154
178
|
value = "\n".join(current_value).strip().strip("'").strip('"')
|
155
179
|
# 将字符串"true"/"false"转换为bool类型
|
@@ -159,12 +183,12 @@ def _read_old_config_file(config_file):
|
|
159
183
|
value = False
|
160
184
|
config_data[current_key] = value
|
161
185
|
current_value = []
|
162
|
-
|
186
|
+
# 解析新的键值对
|
163
187
|
key, value = line.split("=", 1)
|
164
188
|
current_key = key.strip()
|
165
189
|
current_value.append(value.strip())
|
166
190
|
elif current_key is not None:
|
167
|
-
|
191
|
+
# 多行值的后续行
|
168
192
|
current_value.append(line.strip())
|
169
193
|
# 处理最后一个键值对
|
170
194
|
if current_key is not None:
|
@@ -175,11 +199,16 @@ def _read_old_config_file(config_file):
|
|
175
199
|
elif value.lower() == "false":
|
176
200
|
value = False
|
177
201
|
config_data[current_key] = value
|
178
|
-
os.environ.update(
|
202
|
+
os.environ.update(
|
203
|
+
{str(k): str(v) for k, v in config_data.items() if v is not None}
|
204
|
+
)
|
179
205
|
set_global_env_data(config_data)
|
180
|
-
PrettyOutput.print(
|
206
|
+
PrettyOutput.print(
|
207
|
+
f"检测到旧格式配置文件,旧格式以后将不再支持,请尽快迁移到新格式",
|
208
|
+
OutputType.WARNING,
|
209
|
+
)
|
210
|
+
|
181
211
|
|
182
|
-
|
183
212
|
def while_success(func: Callable[[], Any], sleep_time: float = 0.1) -> Any:
|
184
213
|
"""循环执行函数直到成功
|
185
214
|
|
@@ -194,19 +223,23 @@ def while_success(func: Callable[[], Any], sleep_time: float = 0.1) -> Any:
|
|
194
223
|
try:
|
195
224
|
return func()
|
196
225
|
except Exception as e:
|
197
|
-
PrettyOutput.print(
|
226
|
+
PrettyOutput.print(
|
227
|
+
f"执行失败: {str(e)}, 等待 {sleep_time}s...", OutputType.WARNING
|
228
|
+
)
|
198
229
|
time.sleep(sleep_time)
|
199
230
|
continue
|
231
|
+
|
232
|
+
|
200
233
|
def while_true(func: Callable[[], bool], sleep_time: float = 0.1) -> Any:
|
201
234
|
"""循环执行函数直到返回True
|
202
|
-
|
235
|
+
|
203
236
|
参数:
|
204
237
|
func: 要执行的函数,必须返回布尔值
|
205
238
|
sleep_time: 每次失败后的等待时间(秒)
|
206
|
-
|
239
|
+
|
207
240
|
返回:
|
208
241
|
函数最终返回的True值
|
209
|
-
|
242
|
+
|
210
243
|
注意:
|
211
244
|
与while_success不同,此函数只检查返回是否为True,
|
212
245
|
不捕获异常,异常会直接抛出
|
@@ -218,7 +251,9 @@ def while_true(func: Callable[[], bool], sleep_time: float = 0.1) -> Any:
|
|
218
251
|
PrettyOutput.print(f"执行失败, 等待 {sleep_time}s...", OutputType.WARNING)
|
219
252
|
time.sleep(sleep_time)
|
220
253
|
return ret
|
221
|
-
|
254
|
+
|
255
|
+
|
256
|
+
def get_file_md5(filepath: str) -> str:
|
222
257
|
"""计算文件内容的MD5哈希值
|
223
258
|
|
224
259
|
参数:
|
@@ -227,7 +262,9 @@ def get_file_md5(filepath: str)->str:
|
|
227
262
|
返回:
|
228
263
|
str: 文件内容的MD5哈希值
|
229
264
|
"""
|
230
|
-
return hashlib.md5(open(filepath, "rb").read(100*1024*1024)).hexdigest()
|
265
|
+
return hashlib.md5(open(filepath, "rb").read(100 * 1024 * 1024)).hexdigest()
|
266
|
+
|
267
|
+
|
231
268
|
def user_confirm(tip: str, default: bool = True) -> bool:
|
232
269
|
"""提示用户确认是/否问题
|
233
270
|
|
@@ -242,6 +279,7 @@ def user_confirm(tip: str, default: bool = True) -> bool:
|
|
242
279
|
ret = get_single_line_input(f"{tip} {suffix}: ")
|
243
280
|
return default if ret == "" else ret.lower() == "y"
|
244
281
|
|
282
|
+
|
245
283
|
def get_file_line_count(filename: str) -> int:
|
246
284
|
"""计算文件中的行数
|
247
285
|
|
@@ -257,7 +295,6 @@ def get_file_line_count(filename: str) -> int:
|
|
257
295
|
return 0
|
258
296
|
|
259
297
|
|
260
|
-
|
261
298
|
def _get_cmd_stats() -> Dict[str, int]:
|
262
299
|
"""从数据目录获取命令调用统计"""
|
263
300
|
stats_file = Path(get_data_dir()) / "cmd_stat.yaml"
|
@@ -266,11 +303,10 @@ def _get_cmd_stats() -> Dict[str, int]:
|
|
266
303
|
with open(stats_file, "r", encoding="utf-8") as f:
|
267
304
|
return yaml.safe_load(f) or {}
|
268
305
|
except Exception as e:
|
269
|
-
PrettyOutput.print(
|
270
|
-
f"加载命令调用统计失败: {str(e)}", OutputType.WARNING
|
271
|
-
)
|
306
|
+
PrettyOutput.print(f"加载命令调用统计失败: {str(e)}", OutputType.WARNING)
|
272
307
|
return {}
|
273
308
|
|
309
|
+
|
274
310
|
def _update_cmd_stats(cmd_name: str) -> None:
|
275
311
|
"""更新命令调用统计"""
|
276
312
|
stats = _get_cmd_stats()
|
@@ -280,31 +316,29 @@ def _update_cmd_stats(cmd_name: str) -> None:
|
|
280
316
|
with open(stats_file, "w", encoding="utf-8") as f:
|
281
317
|
yaml.safe_dump(stats, f, allow_unicode=True)
|
282
318
|
except Exception as e:
|
283
|
-
PrettyOutput.print(
|
284
|
-
|
285
|
-
)
|
319
|
+
PrettyOutput.print(f"保存命令调用统计失败: {str(e)}", OutputType.WARNING)
|
320
|
+
|
286
321
|
|
287
322
|
def count_cmd_usage() -> None:
|
288
323
|
"""统计当前命令的使用次数"""
|
289
324
|
import sys
|
325
|
+
|
290
326
|
_update_cmd_stats(sys.argv[0])
|
291
327
|
|
328
|
+
|
292
329
|
def is_context_overflow(content: str) -> bool:
|
293
330
|
"""判断文件内容是否超出上下文限制"""
|
294
|
-
return get_context_token_count(content) > get_max_big_content_size()
|
331
|
+
return get_context_token_count(content) > get_max_big_content_size()
|
332
|
+
|
295
333
|
|
296
334
|
def get_loc_stats() -> str:
|
297
335
|
"""使用loc命令获取当前目录的代码统计信息
|
298
|
-
|
336
|
+
|
299
337
|
返回:
|
300
338
|
str: loc命令输出的原始字符串,失败时返回空字符串
|
301
339
|
"""
|
302
340
|
try:
|
303
|
-
result = subprocess.run(
|
304
|
-
['loc'],
|
305
|
-
capture_output=True,
|
306
|
-
text=True
|
307
|
-
)
|
341
|
+
result = subprocess.run(["loc"], capture_output=True, text=True)
|
308
342
|
return result.stdout if result.returncode == 0 else ""
|
309
343
|
except FileNotFoundError:
|
310
|
-
return ""
|
344
|
+
return ""
|