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.

@@ -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 os.getenv("JARVIS_GIT_COMMIT_PROMPT", "")
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
- 从数据目录下的replace_map.yaml文件中读取替换映射表,
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(os.getenv('JARVIS_MAX_TOKEN_COUNT', '960000'))
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(os.getenv('JARVIS_MAX_INPUT_TOKEN_COUNT', '32000'))
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 os.getenv('JARVIS_AUTO_COMPLETE', 'false') == 'true'
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 = os.getenv('SHELL', '/bin/bash')
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 os.getenv('JARVIS_PLATFORM', 'yuanbao')
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 os.getenv('JARVIS_MODEL', 'deep_seek_v3')
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 os.getenv('JARVIS_THINKING_PLATFORM', os.getenv('JARVIS_PLATFORM', 'yuanbao'))
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 os.getenv('JARVIS_THINKING_MODEL', os.getenv('JARVIS_MODEL', 'deep_seek'))
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 os.getenv('JARVIS_EXECUTE_TOOL_CONFIRM', 'false') == 'true'
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 os.getenv('JARVIS_CONFIRM_BEFORE_APPLY_PATCH', 'true') == 'true'
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(os.getenv('JARVIS_MAX_TOOL_CALL_COUNT', '20'))
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 = os.getenv('JARVIS_DATA_PATH', '').strip()
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 os.getenv('JARVIS_AUTO_UPDATE', 'true') == 'true'
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(os.getenv('JARVIS_MAX_BIG_CONTENT_SIZE', '1024000'))
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 os.getenv('JARVIS_PRETTY_OUTPUT', 'false') == 'true'
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 os.getenv('JARVIS_USE_METHODOLOGY', 'false') == 'true'
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 os.getenv('JARVIS_USE_ANALYSIS', 'false') == 'true'
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 os.getenv('JARVIS_PRINT_PROMPT', 'false') == 'true'
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", [])
@@ -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
- return f"恢复更改失败: {str(e)}"
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
- commit_count = subprocess.run(
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 commit_count.returncode != 0:
200
+ if commit_result.returncode != 0:
201
201
  return False
202
202
 
203
- commit_count = int(commit_count.stdout.strip())
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
- result = subprocess.run(["git", "rev-list", "--count", "HEAD..origin/main"],
320
- cwd=git_root, capture_output=True, text=True)
321
- if result.returncode == 0 and int(result.stdout.strip()) > 0:
322
- PrettyOutput.print("检测到新版本,正在更新Jarvis...", OutputType.INFO)
323
- subprocess.run(["git", "pull"], cwd=git_root, check=True)
324
- PrettyOutput.print("Jarvis已更新到最新版本", OutputType.SUCCESS)
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:
@@ -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
- env_file = jarvis_dir / "env"
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
- if env_file.exists():
67
- try:
68
- # 首先尝试作为YAML文件读取
69
- try:
70
- with open(env_file, "r", encoding="utf-8") as f:
71
- env_data = yaml.safe_load(f) or {}
72
- if isinstance(env_data, dict):
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
- if len(sys.argv) > 1:
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
  """判断文件内容是否超出上下文限制"""