jarvis-ai-assistant 0.1.179__py3-none-any.whl → 0.1.180__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_data/config_schema.json +260 -0
- jarvis/jarvis_git_utils/git_commiter.py +1 -1
- jarvis/jarvis_platform/kimi.py +0 -22
- jarvis/jarvis_platform/openai.py +0 -15
- jarvis/jarvis_platform/yuanbao.py +0 -23
- jarvis/jarvis_smart_shell/main.py +6 -3
- jarvis/jarvis_tools/edit_file.py +1 -1
- jarvis/jarvis_tools/registry.py +41 -35
- jarvis/jarvis_utils/config.py +61 -20
- jarvis/jarvis_utils/git_utils.py +28 -15
- jarvis/jarvis_utils/utils.py +101 -61
- {jarvis_ai_assistant-0.1.179.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/METADATA +44 -49
- {jarvis_ai_assistant-0.1.179.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/RECORD +18 -17
- {jarvis_ai_assistant-0.1.179.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.179.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.179.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.179.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/top_level.txt +0 -0
jarvis/jarvis_utils/config.py
CHANGED
|
@@ -2,10 +2,30 @@
|
|
|
2
2
|
import os
|
|
3
3
|
from functools import lru_cache
|
|
4
4
|
|
|
5
|
+
from typing import Any, Dict, List
|
|
6
|
+
|
|
7
|
+
|
|
5
8
|
import yaml
|
|
6
9
|
|
|
10
|
+
|
|
7
11
|
from jarvis.jarvis_utils.builtin_replace_map import BUILTIN_REPLACE_MAP
|
|
8
12
|
|
|
13
|
+
|
|
14
|
+
# 全局环境变量存储
|
|
15
|
+
|
|
16
|
+
GLOBAL_CONFIG_DATA: Dict[str, Any] = {}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def set_global_env_data(env_data: Dict[str, Any]) -> None:
|
|
20
|
+
"""设置全局环境变量数据"""
|
|
21
|
+
global GLOBAL_CONFIG_DATA
|
|
22
|
+
GLOBAL_CONFIG_DATA = env_data
|
|
23
|
+
|
|
24
|
+
def set_config(key: str, value: Any) -> None:
|
|
25
|
+
"""设置配置"""
|
|
26
|
+
GLOBAL_CONFIG_DATA[key] = value
|
|
27
|
+
|
|
28
|
+
|
|
9
29
|
"""配置管理模块。
|
|
10
30
|
|
|
11
31
|
该模块提供了获取Jarvis系统各种配置设置的函数。
|
|
@@ -19,7 +39,7 @@ def get_git_commit_prompt() -> str:
|
|
|
19
39
|
返回:
|
|
20
40
|
str: Git提交信息生成提示模板,如果未配置则返回空字符串
|
|
21
41
|
"""
|
|
22
|
-
return
|
|
42
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_GIT_COMMIT_PROMPT", "")
|
|
23
43
|
|
|
24
44
|
# 输出窗口预留大小
|
|
25
45
|
INPUT_WINDOW_REVERSE_SIZE = 2048
|
|
@@ -29,16 +49,27 @@ def get_replace_map() -> dict:
|
|
|
29
49
|
"""
|
|
30
50
|
获取替换映射表。
|
|
31
51
|
|
|
32
|
-
|
|
52
|
+
优先使用GLOBAL_CONFIG_DATA['JARVIS_REPLACE_MAP']的配置,
|
|
53
|
+
如果没有则从数据目录下的replace_map.yaml文件中读取替换映射表,
|
|
33
54
|
如果文件不存在则返回内置替换映射表。
|
|
34
55
|
|
|
35
56
|
返回:
|
|
36
57
|
dict: 合并后的替换映射表字典(内置+文件中的映射表)
|
|
37
58
|
"""
|
|
59
|
+
if 'JARVIS_REPLACE_MAP' in GLOBAL_CONFIG_DATA:
|
|
60
|
+
return {**BUILTIN_REPLACE_MAP, **GLOBAL_CONFIG_DATA['JARVIS_REPLACE_MAP']}
|
|
61
|
+
|
|
38
62
|
replace_map_path = os.path.join(get_data_dir(), 'replace_map.yaml')
|
|
39
63
|
if not os.path.exists(replace_map_path):
|
|
40
64
|
return BUILTIN_REPLACE_MAP.copy()
|
|
41
65
|
|
|
66
|
+
from jarvis.jarvis_utils.output import PrettyOutput, OutputType
|
|
67
|
+
PrettyOutput.print(
|
|
68
|
+
"警告:使用replace_map.yaml进行配置的方式已被弃用,将在未来版本中移除。"
|
|
69
|
+
"请迁移到使用GLOBAL_CONFIG_DATA中的JARVIS_REPLACE_MAP配置。",
|
|
70
|
+
output_type=OutputType.WARNING
|
|
71
|
+
)
|
|
72
|
+
|
|
42
73
|
with open(replace_map_path, 'r', encoding='utf-8', errors='ignore') as file:
|
|
43
74
|
file_map = yaml.safe_load(file) or {}
|
|
44
75
|
return {**BUILTIN_REPLACE_MAP, **file_map}
|
|
@@ -50,7 +81,7 @@ def get_max_token_count() -> int:
|
|
|
50
81
|
返回:
|
|
51
82
|
int: 模型能处理的最大token数量。
|
|
52
83
|
"""
|
|
53
|
-
return int(
|
|
84
|
+
return int(GLOBAL_CONFIG_DATA.get('JARVIS_MAX_TOKEN_COUNT', '960000'))
|
|
54
85
|
|
|
55
86
|
def get_max_input_token_count() -> int:
|
|
56
87
|
"""
|
|
@@ -59,7 +90,7 @@ def get_max_input_token_count() -> int:
|
|
|
59
90
|
返回:
|
|
60
91
|
int: 模型能处理的最大输入token数量。
|
|
61
92
|
"""
|
|
62
|
-
return int(
|
|
93
|
+
return int(GLOBAL_CONFIG_DATA.get('JARVIS_MAX_INPUT_TOKEN_COUNT', '32000'))
|
|
63
94
|
|
|
64
95
|
|
|
65
96
|
def is_auto_complete() -> bool:
|
|
@@ -69,7 +100,7 @@ def is_auto_complete() -> bool:
|
|
|
69
100
|
返回:
|
|
70
101
|
bool: 如果启用了自动补全则返回True,默认为False
|
|
71
102
|
"""
|
|
72
|
-
return
|
|
103
|
+
return GLOBAL_CONFIG_DATA.get('JARVIS_AUTO_COMPLETE', 'false') == 'true'
|
|
73
104
|
|
|
74
105
|
|
|
75
106
|
def get_shell_name() -> str:
|
|
@@ -79,7 +110,7 @@ def get_shell_name() -> str:
|
|
|
79
110
|
返回:
|
|
80
111
|
str: Shell名称(例如bash, zsh),默认为bash
|
|
81
112
|
"""
|
|
82
|
-
shell_path =
|
|
113
|
+
shell_path = GLOBAL_CONFIG_DATA.get('SHELL', '/bin/bash')
|
|
83
114
|
return os.path.basename(shell_path)
|
|
84
115
|
def get_normal_platform_name() -> str:
|
|
85
116
|
"""
|
|
@@ -88,7 +119,7 @@ def get_normal_platform_name() -> str:
|
|
|
88
119
|
返回:
|
|
89
120
|
str: 平台名称,默认为'yuanbao'
|
|
90
121
|
"""
|
|
91
|
-
return
|
|
122
|
+
return GLOBAL_CONFIG_DATA.get('JARVIS_PLATFORM', 'yuanbao')
|
|
92
123
|
def get_normal_model_name() -> str:
|
|
93
124
|
"""
|
|
94
125
|
获取正常操作的模型名称。
|
|
@@ -96,7 +127,7 @@ def get_normal_model_name() -> str:
|
|
|
96
127
|
返回:
|
|
97
128
|
str: 模型名称,默认为'deep_seek'
|
|
98
129
|
"""
|
|
99
|
-
return
|
|
130
|
+
return GLOBAL_CONFIG_DATA.get('JARVIS_MODEL', 'deep_seek_v3')
|
|
100
131
|
|
|
101
132
|
|
|
102
133
|
def get_thinking_platform_name() -> str:
|
|
@@ -106,7 +137,7 @@ def get_thinking_platform_name() -> str:
|
|
|
106
137
|
返回:
|
|
107
138
|
str: 平台名称,默认为'yuanbao'
|
|
108
139
|
"""
|
|
109
|
-
return
|
|
140
|
+
return GLOBAL_CONFIG_DATA.get('JARVIS_THINKING_PLATFORM', GLOBAL_CONFIG_DATA.get('JARVIS_PLATFORM', 'yuanbao'))
|
|
110
141
|
def get_thinking_model_name() -> str:
|
|
111
142
|
"""
|
|
112
143
|
获取思考操作的模型名称。
|
|
@@ -114,7 +145,7 @@ def get_thinking_model_name() -> str:
|
|
|
114
145
|
返回:
|
|
115
146
|
str: 模型名称,默认为'deep_seek'
|
|
116
147
|
"""
|
|
117
|
-
return
|
|
148
|
+
return GLOBAL_CONFIG_DATA.get('JARVIS_THINKING_MODEL', GLOBAL_CONFIG_DATA.get('JARVIS_MODEL', 'deep_seek'))
|
|
118
149
|
|
|
119
150
|
def is_execute_tool_confirm() -> bool:
|
|
120
151
|
"""
|
|
@@ -123,7 +154,7 @@ def is_execute_tool_confirm() -> bool:
|
|
|
123
154
|
返回:
|
|
124
155
|
bool: 如果需要确认则返回True,默认为False
|
|
125
156
|
"""
|
|
126
|
-
return
|
|
157
|
+
return GLOBAL_CONFIG_DATA.get('JARVIS_EXECUTE_TOOL_CONFIRM', 'false') == 'true'
|
|
127
158
|
def is_confirm_before_apply_patch() -> bool:
|
|
128
159
|
"""
|
|
129
160
|
检查应用补丁前是否需要确认。
|
|
@@ -131,7 +162,7 @@ def is_confirm_before_apply_patch() -> bool:
|
|
|
131
162
|
返回:
|
|
132
163
|
bool: 如果需要确认则返回True,默认为False
|
|
133
164
|
"""
|
|
134
|
-
return
|
|
165
|
+
return GLOBAL_CONFIG_DATA.get('JARVIS_CONFIRM_BEFORE_APPLY_PATCH', 'true') == 'true'
|
|
135
166
|
|
|
136
167
|
def get_max_tool_call_count() -> int:
|
|
137
168
|
"""
|
|
@@ -140,7 +171,7 @@ def get_max_tool_call_count() -> int:
|
|
|
140
171
|
返回:
|
|
141
172
|
int: 最大连续工具调用次数,默认为20
|
|
142
173
|
"""
|
|
143
|
-
return int(
|
|
174
|
+
return int(GLOBAL_CONFIG_DATA.get('JARVIS_MAX_TOOL_CALL_COUNT', '20'))
|
|
144
175
|
|
|
145
176
|
|
|
146
177
|
def get_data_dir() -> str:
|
|
@@ -151,7 +182,7 @@ def get_data_dir() -> str:
|
|
|
151
182
|
str: 数据目录路径,优先从JARVIS_DATA_PATH环境变量获取,
|
|
152
183
|
如果未设置或为空,则使用~/.jarvis作为默认值
|
|
153
184
|
"""
|
|
154
|
-
data_path =
|
|
185
|
+
data_path = GLOBAL_CONFIG_DATA.get('JARVIS_DATA_PATH', '').strip()
|
|
155
186
|
if not data_path:
|
|
156
187
|
return os.path.expanduser('~/.jarvis')
|
|
157
188
|
return data_path
|
|
@@ -163,7 +194,7 @@ def get_auto_update() -> bool:
|
|
|
163
194
|
返回:
|
|
164
195
|
bool: 如果需要自动更新则返回True,默认为True
|
|
165
196
|
"""
|
|
166
|
-
return
|
|
197
|
+
return GLOBAL_CONFIG_DATA.get('JARVIS_AUTO_UPDATE', 'true') == 'true'
|
|
167
198
|
|
|
168
199
|
def get_max_big_content_size() -> int:
|
|
169
200
|
"""
|
|
@@ -172,7 +203,7 @@ def get_max_big_content_size() -> int:
|
|
|
172
203
|
返回:
|
|
173
204
|
int: 最大大内容大小
|
|
174
205
|
"""
|
|
175
|
-
return int(
|
|
206
|
+
return int(GLOBAL_CONFIG_DATA.get('JARVIS_MAX_BIG_CONTENT_SIZE', '1024000'))
|
|
176
207
|
|
|
177
208
|
def get_pretty_output() -> bool:
|
|
178
209
|
"""
|
|
@@ -181,7 +212,7 @@ def get_pretty_output() -> bool:
|
|
|
181
212
|
返回:
|
|
182
213
|
bool: 如果启用PrettyOutput则返回True,默认为True
|
|
183
214
|
"""
|
|
184
|
-
return
|
|
215
|
+
return GLOBAL_CONFIG_DATA.get('JARVIS_PRETTY_OUTPUT', 'false') == 'true'
|
|
185
216
|
|
|
186
217
|
def is_use_methodology() -> bool:
|
|
187
218
|
"""
|
|
@@ -190,7 +221,7 @@ def is_use_methodology() -> bool:
|
|
|
190
221
|
返回:
|
|
191
222
|
bool: 如果启用方法论则返回True,默认为True
|
|
192
223
|
"""
|
|
193
|
-
return
|
|
224
|
+
return GLOBAL_CONFIG_DATA.get('JARVIS_USE_METHODOLOGY', 'false') == 'true'
|
|
194
225
|
|
|
195
226
|
def is_use_analysis() -> bool:
|
|
196
227
|
"""
|
|
@@ -199,7 +230,7 @@ def is_use_analysis() -> bool:
|
|
|
199
230
|
返回:
|
|
200
231
|
bool: 如果启用任务分析则返回True,默认为True
|
|
201
232
|
"""
|
|
202
|
-
return
|
|
233
|
+
return GLOBAL_CONFIG_DATA.get('JARVIS_USE_ANALYSIS', 'false') == 'true'
|
|
203
234
|
|
|
204
235
|
def is_print_prompt() -> bool:
|
|
205
236
|
"""
|
|
@@ -208,4 +239,14 @@ def is_print_prompt() -> bool:
|
|
|
208
239
|
返回:
|
|
209
240
|
bool: 如果打印提示则返回True,默认为True
|
|
210
241
|
"""
|
|
211
|
-
return
|
|
242
|
+
return GLOBAL_CONFIG_DATA.get('JARVIS_PRINT_PROMPT', 'false') == 'true'
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def get_mcp_config() -> List[Dict[str, Any]]:
|
|
246
|
+
"""
|
|
247
|
+
获取MCP配置列表。
|
|
248
|
+
|
|
249
|
+
返回:
|
|
250
|
+
List[Dict[str, Any]]: MCP配置项列表,如果未配置则返回空列表
|
|
251
|
+
"""
|
|
252
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_MCP", [])
|
jarvis/jarvis_utils/git_utils.py
CHANGED
|
@@ -139,7 +139,7 @@ def get_diff() -> str:
|
|
|
139
139
|
|
|
140
140
|
|
|
141
141
|
|
|
142
|
-
def revert_file(filepath: str):
|
|
142
|
+
def revert_file(filepath: str) -> None:
|
|
143
143
|
"""增强版git恢复,处理新文件"""
|
|
144
144
|
import subprocess
|
|
145
145
|
try:
|
|
@@ -162,7 +162,7 @@ def revert_file(filepath: str):
|
|
|
162
162
|
# 修改后的恢复函数
|
|
163
163
|
|
|
164
164
|
|
|
165
|
-
def revert_change():
|
|
165
|
+
def revert_change() -> None:
|
|
166
166
|
"""恢复所有未提交的修改到HEAD状态"""
|
|
167
167
|
import subprocess
|
|
168
168
|
try:
|
|
@@ -176,7 +176,7 @@ def revert_change():
|
|
|
176
176
|
subprocess.run(['git', 'reset', '--hard', 'HEAD'], check=True)
|
|
177
177
|
subprocess.run(['git', 'clean', '-fd'], check=True)
|
|
178
178
|
except subprocess.CalledProcessError as e:
|
|
179
|
-
|
|
179
|
+
PrettyOutput.print(f"恢复更改失败: {str(e)}", OutputType.ERROR)
|
|
180
180
|
|
|
181
181
|
|
|
182
182
|
def handle_commit_workflow() -> bool:
|
|
@@ -192,15 +192,15 @@ def handle_commit_workflow() -> bool:
|
|
|
192
192
|
import subprocess
|
|
193
193
|
try:
|
|
194
194
|
# 获取当前分支的提交总数
|
|
195
|
-
|
|
195
|
+
commit_result = subprocess.run(
|
|
196
196
|
['git', 'rev-list', '--count', 'HEAD'],
|
|
197
197
|
capture_output=True,
|
|
198
198
|
text=True
|
|
199
199
|
)
|
|
200
|
-
if
|
|
200
|
+
if commit_result.returncode != 0:
|
|
201
201
|
return False
|
|
202
202
|
|
|
203
|
-
commit_count = int(
|
|
203
|
+
commit_count = int(commit_result.stdout.strip())
|
|
204
204
|
|
|
205
205
|
# 暂存所有修改
|
|
206
206
|
subprocess.run(['git', 'add', '.'], check=True)
|
|
@@ -313,15 +313,28 @@ def check_and_update_git_repo(repo_path: str) -> bool:
|
|
|
313
313
|
if has_uncommitted_changes():
|
|
314
314
|
return False
|
|
315
315
|
|
|
316
|
-
#
|
|
317
|
-
subprocess.run(["git", "fetch"], cwd=git_root, check=True)
|
|
318
|
-
#
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
316
|
+
# 获取远程tag更新
|
|
317
|
+
subprocess.run(["git", "fetch", "--tags"], cwd=git_root, check=True)
|
|
318
|
+
# 获取最新本地tag
|
|
319
|
+
local_tag_result = subprocess.run(["git", "describe", "--tags", "--abbrev=0"],
|
|
320
|
+
cwd=git_root, capture_output=True, text=True)
|
|
321
|
+
# 获取最新远程tag
|
|
322
|
+
remote_tag_result = subprocess.run(
|
|
323
|
+
["git", "ls-remote", "--tags", "--refs", "origin"],
|
|
324
|
+
cwd=git_root, capture_output=True, text=True
|
|
325
|
+
)
|
|
326
|
+
if remote_tag_result.returncode == 0:
|
|
327
|
+
# 提取最新的tag名称
|
|
328
|
+
tags = [ref.split("/")[-1] for ref in remote_tag_result.stdout.splitlines()]
|
|
329
|
+
tags = sorted(tags, key=lambda x: [int(i) if i.isdigit() else i for i in re.split(r'([0-9]+)', x)])
|
|
330
|
+
remote_tag = tags[-1] if tags else ""
|
|
331
|
+
remote_tag_result.stdout = remote_tag
|
|
332
|
+
|
|
333
|
+
if (local_tag_result.returncode == 0 and remote_tag_result.returncode == 0 and
|
|
334
|
+
local_tag_result.stdout.strip() != remote_tag_result.stdout.strip()):
|
|
335
|
+
PrettyOutput.print(f"检测到新版本tag {remote_tag_result.stdout.strip()},正在更新Jarvis...", OutputType.INFO)
|
|
336
|
+
subprocess.run(["git", "checkout", remote_tag_result.stdout.strip()], cwd=git_root, check=True)
|
|
337
|
+
PrettyOutput.print(f"Jarvis已更新到tag {remote_tag_result.stdout.strip()}", OutputType.SUCCESS)
|
|
325
338
|
return True
|
|
326
339
|
return False
|
|
327
340
|
except Exception as e:
|
jarvis/jarvis_utils/utils.py
CHANGED
|
@@ -3,19 +3,19 @@ import hashlib
|
|
|
3
3
|
import os
|
|
4
4
|
import tarfile
|
|
5
5
|
import time
|
|
6
|
-
from datetime import datetime
|
|
7
6
|
from pathlib import Path
|
|
8
7
|
from typing import Any, Callable, Dict
|
|
9
8
|
|
|
10
9
|
import yaml
|
|
11
10
|
|
|
12
11
|
from jarvis import __version__
|
|
13
|
-
from jarvis.jarvis_utils.config import get_data_dir, get_max_big_content_size
|
|
12
|
+
from jarvis.jarvis_utils.config import get_data_dir, get_max_big_content_size, set_global_env_data
|
|
14
13
|
from jarvis.jarvis_utils.embedding import get_context_token_count
|
|
15
14
|
from jarvis.jarvis_utils.input import get_single_line_input
|
|
16
15
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
17
16
|
|
|
18
17
|
|
|
18
|
+
|
|
19
19
|
def init_env(welcome_str: str) -> None:
|
|
20
20
|
"""初始化环境变量从jarvis_data/env文件
|
|
21
21
|
功能:
|
|
@@ -43,15 +43,16 @@ def init_env(welcome_str: str) -> None:
|
|
|
43
43
|
PrettyOutput.print_gradient_text(jarvis_ascii_art, (0, 120, 255), (0, 255, 200))
|
|
44
44
|
|
|
45
45
|
jarvis_dir = Path(get_data_dir())
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
script_dir = Path(os.path.dirname(os.path.dirname(__file__)))
|
|
49
|
-
hf_archive = script_dir / "jarvis_data" / "huggingface.tar.gz"
|
|
46
|
+
config_file = jarvis_dir / "config.yaml"
|
|
50
47
|
|
|
51
48
|
# 检查jarvis_data目录是否存在
|
|
52
49
|
if not jarvis_dir.exists():
|
|
53
50
|
jarvis_dir.mkdir(parents=True)
|
|
54
51
|
|
|
52
|
+
script_dir = Path(os.path.dirname(os.path.dirname(__file__)))
|
|
53
|
+
hf_archive = script_dir / "jarvis_data" / "huggingface.tar.gz"
|
|
54
|
+
|
|
55
|
+
|
|
55
56
|
# 检查并解压huggingface模型
|
|
56
57
|
hf_dir = jarvis_dir / "huggingface" / "hub"
|
|
57
58
|
if not hf_dir.exists() and hf_archive.exists():
|
|
@@ -63,62 +64,91 @@ def init_env(welcome_str: str) -> None:
|
|
|
63
64
|
except Exception as e:
|
|
64
65
|
PrettyOutput.print(f"解压HuggingFace模型失败: {e}", OutputType.ERROR)
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
os.environ.update({str(k): str(v) for k, v in env_data.items() if v is not None})
|
|
74
|
-
return
|
|
75
|
-
except yaml.YAMLError:
|
|
76
|
-
pass
|
|
77
|
-
|
|
78
|
-
# 如果不是YAML格式,按旧格式处理
|
|
79
|
-
current_key = None
|
|
80
|
-
current_value = []
|
|
81
|
-
env_data = {}
|
|
82
|
-
with open(env_file, "r", encoding="utf-8", errors="ignore") as f:
|
|
83
|
-
for line in f:
|
|
84
|
-
line = line.rstrip()
|
|
85
|
-
if not line or line.startswith(("#", ";")):
|
|
86
|
-
continue
|
|
87
|
-
if "=" in line and not line.startswith((" ", "\t")):
|
|
88
|
-
# 处理之前收集的多行值
|
|
89
|
-
if current_key is not None:
|
|
90
|
-
env_data[current_key] = "\n".join(current_value).strip().strip("'").strip('"')
|
|
91
|
-
current_value = []
|
|
92
|
-
# 解析新的键值对
|
|
93
|
-
key, value = line.split("=", 1)
|
|
94
|
-
current_key = key.strip()
|
|
95
|
-
current_value.append(value.strip())
|
|
96
|
-
elif current_key is not None:
|
|
97
|
-
# 多行值的后续行
|
|
98
|
-
current_value.append(line.strip())
|
|
99
|
-
# 处理最后一个键值对
|
|
100
|
-
if current_key is not None:
|
|
101
|
-
env_data[current_key] = "\n".join(current_value).strip().strip("'").strip('"')
|
|
102
|
-
|
|
103
|
-
# 更新环境变量
|
|
104
|
-
os.environ.update(env_data)
|
|
105
|
-
|
|
106
|
-
# 如果是旧格式,转换为YAML并备份
|
|
107
|
-
backup_file = env_file.with_name(f"env.bak.{datetime.now().strftime('%Y%m%d%H%M%S')}")
|
|
108
|
-
env_file.rename(backup_file)
|
|
109
|
-
with open(env_file, "w", encoding="utf-8") as f:
|
|
110
|
-
yaml.dump(env_data, f, default_flow_style=False, allow_unicode=True)
|
|
111
|
-
|
|
112
|
-
PrettyOutput.print(f"检测到旧格式配置文件,已自动转换为YAML格式并备份到 {backup_file}", OutputType.INFO)
|
|
113
|
-
|
|
114
|
-
except Exception as e:
|
|
115
|
-
PrettyOutput.print(f"警告: 读取 {env_file} 失败: {e}", OutputType.WARNING)
|
|
67
|
+
|
|
68
|
+
if not config_file.exists():
|
|
69
|
+
old_config_file = jarvis_dir / "env"
|
|
70
|
+
if old_config_file.exists():# 旧的配置文件存在
|
|
71
|
+
_read_old_config_file(old_config_file)
|
|
72
|
+
else:
|
|
73
|
+
_read_config_file(jarvis_dir, config_file)
|
|
116
74
|
|
|
117
75
|
# 检查是否是git仓库并更新
|
|
118
76
|
from jarvis.jarvis_utils.git_utils import check_and_update_git_repo
|
|
119
77
|
|
|
120
78
|
check_and_update_git_repo(str(script_dir))
|
|
121
79
|
|
|
80
|
+
def _read_config_file(jarvis_dir, config_file):
|
|
81
|
+
"""读取并解析YAML格式的配置文件
|
|
82
|
+
|
|
83
|
+
功能:
|
|
84
|
+
1. 读取配置文件内容
|
|
85
|
+
2. 检查并添加schema声明(如果缺失)
|
|
86
|
+
3. 将配置数据保存到全局变量
|
|
87
|
+
4. 设置环境变量(如果配置中有ENV字段)
|
|
88
|
+
|
|
89
|
+
参数:
|
|
90
|
+
jarvis_dir: Jarvis数据目录路径
|
|
91
|
+
config_file: 配置文件路径
|
|
92
|
+
"""
|
|
93
|
+
with open(config_file, "r", encoding="utf-8") as f:
|
|
94
|
+
content = f.read()
|
|
95
|
+
config_data = yaml.safe_load(content) or {}
|
|
96
|
+
if isinstance(config_data, dict):
|
|
97
|
+
# 检查是否已有schema声明,没有则添加
|
|
98
|
+
if "# yaml-language-server: $schema=" not in content:
|
|
99
|
+
schema_path = Path(os.path.relpath(
|
|
100
|
+
Path(__file__).parent.parent / "jarvis_data" / "config_schema.json",
|
|
101
|
+
start=jarvis_dir
|
|
102
|
+
))
|
|
103
|
+
with open(config_file, "w", encoding="utf-8") as f:
|
|
104
|
+
f.write(f"# yaml-language-server: $schema={schema_path}\n")
|
|
105
|
+
f.write(content)
|
|
106
|
+
# 保存到全局变量
|
|
107
|
+
set_global_env_data(config_data)
|
|
108
|
+
# 如果配置中有ENV键值对,则设置环境变量
|
|
109
|
+
if "ENV" in config_data and isinstance(config_data["ENV"], dict):
|
|
110
|
+
os.environ.update({str(k): str(v) for k, v in config_data["ENV"].items() if v is not None})
|
|
111
|
+
|
|
112
|
+
def _read_old_config_file(config_file):
|
|
113
|
+
"""读取并解析旧格式的env配置文件
|
|
114
|
+
|
|
115
|
+
功能:
|
|
116
|
+
1. 解析键值对格式的旧配置文件
|
|
117
|
+
2. 支持多行值的处理
|
|
118
|
+
3. 自动去除值的引号和空格
|
|
119
|
+
4. 将配置数据保存到全局变量
|
|
120
|
+
5. 设置环境变量并显示迁移警告
|
|
121
|
+
|
|
122
|
+
参数:
|
|
123
|
+
config_file: 旧格式配置文件路径
|
|
124
|
+
"""
|
|
125
|
+
config_data = {}
|
|
126
|
+
current_key = None
|
|
127
|
+
current_value = []
|
|
128
|
+
with open(config_file, "r", encoding="utf-8", errors="ignore") as f:
|
|
129
|
+
for line in f:
|
|
130
|
+
line = line.rstrip()
|
|
131
|
+
if not line or line.startswith(("#", ";")):
|
|
132
|
+
continue
|
|
133
|
+
if "=" in line and not line.startswith((" ", "\t")):
|
|
134
|
+
# 处理之前收集的多行值
|
|
135
|
+
if current_key is not None:
|
|
136
|
+
config_data[current_key] = "\n".join(current_value).strip().strip("'").strip('"')
|
|
137
|
+
current_value = []
|
|
138
|
+
# 解析新的键值对
|
|
139
|
+
key, value = line.split("=", 1)
|
|
140
|
+
current_key = key.strip()
|
|
141
|
+
current_value.append(value.strip())
|
|
142
|
+
elif current_key is not None:
|
|
143
|
+
# 多行值的后续行
|
|
144
|
+
current_value.append(line.strip())
|
|
145
|
+
# 处理最后一个键值对
|
|
146
|
+
if current_key is not None:
|
|
147
|
+
config_data[current_key] = "\n".join(current_value).strip().strip("'").strip('"')
|
|
148
|
+
os.environ.update({str(k): str(v) for k, v in config_data.items() if v is not None})
|
|
149
|
+
set_global_env_data(config_data)
|
|
150
|
+
PrettyOutput.print(f"检测到旧格式配置文件,旧格式以后将不再支持,请尽快迁移到新格式", OutputType.WARNING)
|
|
151
|
+
|
|
122
152
|
|
|
123
153
|
def while_success(func: Callable[[], Any], sleep_time: float = 0.1) -> Any:
|
|
124
154
|
"""循环执行函数直到成功
|
|
@@ -138,7 +168,19 @@ def while_success(func: Callable[[], Any], sleep_time: float = 0.1) -> Any:
|
|
|
138
168
|
time.sleep(sleep_time)
|
|
139
169
|
continue
|
|
140
170
|
def while_true(func: Callable[[], bool], sleep_time: float = 0.1) -> Any:
|
|
141
|
-
"""循环执行函数直到返回True
|
|
171
|
+
"""循环执行函数直到返回True
|
|
172
|
+
|
|
173
|
+
参数:
|
|
174
|
+
func: 要执行的函数,必须返回布尔值
|
|
175
|
+
sleep_time: 每次失败后的等待时间(秒)
|
|
176
|
+
|
|
177
|
+
返回:
|
|
178
|
+
函数最终返回的True值
|
|
179
|
+
|
|
180
|
+
注意:
|
|
181
|
+
与while_success不同,此函数只检查返回是否为True,
|
|
182
|
+
不捕获异常,异常会直接抛出
|
|
183
|
+
"""
|
|
142
184
|
while True:
|
|
143
185
|
ret = func()
|
|
144
186
|
if ret:
|
|
@@ -206,7 +248,7 @@ def _update_cmd_stats(cmd_name: str) -> None:
|
|
|
206
248
|
stats_file = Path(get_data_dir()) / "cmd_stat.yaml"
|
|
207
249
|
try:
|
|
208
250
|
with open(stats_file, "w", encoding="utf-8") as f:
|
|
209
|
-
yaml.safe_dump(stats, f)
|
|
251
|
+
yaml.safe_dump(stats, f, allow_unicode=True)
|
|
210
252
|
except Exception as e:
|
|
211
253
|
PrettyOutput.print(
|
|
212
254
|
f"保存命令调用统计失败: {str(e)}", OutputType.WARNING
|
|
@@ -215,9 +257,7 @@ def _update_cmd_stats(cmd_name: str) -> None:
|
|
|
215
257
|
def count_cmd_usage() -> None:
|
|
216
258
|
"""统计当前命令的使用次数"""
|
|
217
259
|
import sys
|
|
218
|
-
|
|
219
|
-
cmd_name = sys.argv[1]
|
|
220
|
-
_update_cmd_stats(cmd_name)
|
|
260
|
+
_update_cmd_stats(sys.argv[0])
|
|
221
261
|
|
|
222
262
|
def is_context_overflow(content: str) -> bool:
|
|
223
263
|
"""判断文件内容是否超出上下文限制"""
|