jarvis-ai-assistant 0.1.208__py3-none-any.whl → 0.1.210__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.
@@ -9,18 +9,19 @@ Git工具模块
9
9
  - 获取最新提交的哈希值
10
10
  - 从Git差异中提取修改的行范围
11
11
  """
12
+ import datetime
12
13
  import os
13
14
  import re
14
15
  import subprocess
16
+ import sys
15
17
  from typing import Any, Dict, List, Set, Tuple
16
18
 
17
- from jarvis.jarvis_utils.config import (get_auto_update,
18
- is_confirm_before_apply_patch)
19
+ from jarvis.jarvis_utils.config import is_confirm_before_apply_patch
19
20
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
20
21
  from jarvis.jarvis_utils.utils import user_confirm
21
22
 
22
23
 
23
- def find_git_root(start_dir: str = ".") -> str:
24
+ def find_git_root_and_cd(start_dir: str = ".") -> str:
24
25
  """
25
26
  切换到给定路径的Git根目录,如果不是Git仓库则初始化。
26
27
 
@@ -213,7 +214,9 @@ def handle_commit_workflow() -> bool:
213
214
  Returns:
214
215
  bool: 提交是否成功
215
216
  """
216
- if is_confirm_before_apply_patch() and not user_confirm("是否要提交代码?", default=True):
217
+ if is_confirm_before_apply_patch() and not user_confirm(
218
+ "是否要提交代码?", default=True
219
+ ):
217
220
  revert_change()
218
221
  return False
219
222
 
@@ -337,13 +340,24 @@ def check_and_update_git_repo(repo_path: str) -> bool:
337
340
  bool: 是否执行了更新
338
341
  """
339
342
  curr_dir = os.path.abspath(os.getcwd())
340
- git_root = find_git_root(repo_path)
343
+ git_root = find_git_root_and_cd(repo_path)
341
344
  if git_root is None:
342
345
  return False
343
346
 
344
347
  try:
345
- if not get_auto_update():
346
- return False
348
+ # 检查最新提交时间是否为今天
349
+ commit_date_result = subprocess.run(
350
+ ["git", "log", "-1", "--format=%cd", "--date=short"],
351
+ cwd=git_root,
352
+ capture_output=True,
353
+ text=True,
354
+ )
355
+ if commit_date_result.returncode == 0:
356
+ commit_date = commit_date_result.stdout.strip()
357
+ today = datetime.date.today().strftime("%Y-%m-%d")
358
+ if commit_date == today:
359
+ return False
360
+
347
361
  # 检查是否有未提交的修改
348
362
  if has_uncommitted_changes():
349
363
  return False
@@ -394,7 +408,49 @@ def check_and_update_git_repo(repo_path: str) -> bool:
394
408
  f"Jarvis已更新到tag {remote_tag_result.stdout.strip()}",
395
409
  OutputType.SUCCESS,
396
410
  )
397
- return True
411
+
412
+ # 执行pip安装更新代码
413
+ try:
414
+ PrettyOutput.print("正在安装更新后的代码...", OutputType.INFO)
415
+
416
+ # 检查是否在虚拟环境中
417
+ in_venv = hasattr(sys, 'real_prefix') or (
418
+ hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix
419
+ )
420
+
421
+ # 尝试普通安装
422
+ install_cmd = [sys.executable, "-m", "pip", "install", "-e", "."]
423
+ result = subprocess.run(
424
+ install_cmd,
425
+ cwd=git_root,
426
+ capture_output=True,
427
+ text=True
428
+ )
429
+
430
+ if result.returncode == 0:
431
+ PrettyOutput.print("代码更新安装成功", OutputType.SUCCESS)
432
+ return True
433
+
434
+ # 处理权限错误
435
+ error_msg = result.stderr.strip()
436
+ if not in_venv and ("Permission denied" in error_msg or "not writeable" in error_msg):
437
+ if user_confirm("检测到权限问题,是否尝试用户级安装(--user)?", True):
438
+ user_result = subprocess.run(
439
+ install_cmd + ["--user"],
440
+ cwd=git_root,
441
+ capture_output=True,
442
+ text=True
443
+ )
444
+ if user_result.returncode == 0:
445
+ PrettyOutput.print("用户级代码安装成功", OutputType.SUCCESS)
446
+ return True
447
+ error_msg = user_result.stderr.strip()
448
+
449
+ PrettyOutput.print(f"代码安装失败: {error_msg}", OutputType.ERROR)
450
+ return False
451
+ except Exception as e:
452
+ PrettyOutput.print(f"安装过程中发生意外错误: {str(e)}", OutputType.ERROR)
453
+ return False
398
454
  return False
399
455
  except Exception as e:
400
456
  PrettyOutput.print(f"Git仓库更新检查失败: {e}", OutputType.WARNING)
@@ -424,7 +480,9 @@ def get_diff_file_list() -> List[str]:
424
480
  subprocess.run(["git", "reset"], check=True)
425
481
 
426
482
  if result.returncode != 0:
427
- PrettyOutput.print(f"获取差异文件列表失败: {result.stderr}", OutputType.ERROR)
483
+ PrettyOutput.print(
484
+ f"获取差异文件列表失败: {result.stderr}", OutputType.ERROR
485
+ )
428
486
  return []
429
487
 
430
488
  return [f for f in result.stdout.splitlines() if f]
@@ -559,7 +617,9 @@ def confirm_add_new_files() -> None:
559
617
  need_confirm = True
560
618
 
561
619
  if binary_files:
562
- output_lines.append(f"检测到{len(binary_files)}个二进制文件(选择N将重新检测)")
620
+ output_lines.append(
621
+ f"检测到{len(binary_files)}个二进制文件(选择N将重新检测)"
622
+ )
563
623
  output_lines.append("二进制文件列表:")
564
624
  output_lines.extend(f" - {file}" for file in binary_files)
565
625
  need_confirm = True
@@ -580,7 +640,10 @@ def confirm_add_new_files() -> None:
580
640
  if not _check_conditions(new_files, added_lines, binary_files):
581
641
  break
582
642
 
583
- if not user_confirm("是否要添加这些变更(如果不需要请修改.gitignore文件以忽略不需要的文件)?", False):
643
+ if not user_confirm(
644
+ "是否要添加这些变更(如果不需要请修改.gitignore文件以忽略不需要的文件)?",
645
+ False,
646
+ ):
584
647
  continue
585
648
 
586
649
  break
@@ -0,0 +1,169 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import httpx
4
+ from typing import Any, Dict, Optional, Union, AsyncGenerator, Generator
5
+
6
+
7
+ def get_httpx_client() -> httpx.Client:
8
+ """
9
+ 获取一个配置好的 httpx.Client 对象
10
+
11
+ 返回:
12
+ httpx.Client 对象
13
+ """
14
+ client = httpx.Client(
15
+ timeout=httpx.Timeout(None), # 永不超时
16
+ headers={
17
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
18
+ },
19
+ )
20
+ return client
21
+
22
+
23
+ def get_async_httpx_client() -> httpx.AsyncClient:
24
+ """
25
+ 获取一个配置好的 httpx.AsyncClient 对象
26
+
27
+ 返回:
28
+ httpx.AsyncClient 对象
29
+ """
30
+ client = httpx.AsyncClient(
31
+ timeout=httpx.Timeout(None), # 永不超时
32
+ headers={
33
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
34
+ },
35
+ )
36
+ return client
37
+
38
+
39
+ # 增强版本的 HTTP 请求方法(使用 httpx 实现,带重试机制,解决连接中断问题)
40
+ def post(
41
+ url: str,
42
+ data: Optional[Any] = None,
43
+ json: Optional[Dict[str, Any]] = None,
44
+ **kwargs,
45
+ ) -> httpx.Response:
46
+ """
47
+ 发送增强版永不超时的 POST 请求,使用 httpx 实现,包含重试机制
48
+
49
+ 参数:
50
+ url: 请求的 URL
51
+ data: (可选) 请求体数据 (表单数据或原始数据)
52
+ json: (可选) JSON 数据,会自动设置 Content-Type
53
+ **kwargs: 其他传递给 httpx.post 的参数
54
+
55
+ 返回:
56
+ httpx.Response 对象
57
+
58
+ 注意:
59
+ 此方法使用 httpx 实现,包含自动重试机制,适用于解决"Response ended prematurely"等连接问题
60
+ """
61
+ client = get_httpx_client()
62
+ try:
63
+ response = client.post(url=url, data=data, json=json, **kwargs)
64
+ response.raise_for_status()
65
+ return response
66
+ finally:
67
+ client.close()
68
+
69
+
70
+ def get(url: str, **kwargs) -> httpx.Response:
71
+ """
72
+ 发送增强版永不超时的 GET 请求,使用 httpx 实现,包含重试机制
73
+
74
+ 参数:
75
+ url: 请求的 URL
76
+ **kwargs: 其他传递给 httpx.get 的参数
77
+
78
+ 返回:
79
+ httpx.Response 对象
80
+
81
+ 注意:
82
+ 此方法使用 httpx 实现,包含自动重试机制,适用于解决"Response ended prematurely"等连接问题
83
+ """
84
+ client = get_httpx_client()
85
+ try:
86
+ response = client.get(url=url, **kwargs)
87
+ response.raise_for_status()
88
+ return response
89
+ finally:
90
+ client.close()
91
+
92
+
93
+ def put(url: str, data: Optional[Any] = None, **kwargs) -> httpx.Response:
94
+ """
95
+ 发送增强版永不超时的 PUT 请求,使用 httpx 实现,包含重试机制
96
+
97
+ 参数:
98
+ url: 请求的 URL
99
+ data: (可选) 请求体数据 (表单数据或原始数据)
100
+ **kwargs: 其他传递给 httpx.put 的参数
101
+
102
+ 返回:
103
+ httpx.Response 对象
104
+
105
+ 注意:
106
+ 此方法使用 httpx 实现,包含自动重试机制,适用于解决"Response ended prematurely"等连接问题
107
+ """
108
+ client = get_httpx_client()
109
+ try:
110
+ response = client.put(url=url, data=data, **kwargs)
111
+ response.raise_for_status()
112
+ return response
113
+ finally:
114
+ client.close()
115
+
116
+
117
+ def delete(url: str, **kwargs) -> httpx.Response:
118
+ """
119
+ 发送增强版永不超时的 DELETE 请求,使用 httpx 实现,包含重试机制
120
+
121
+ 参数:
122
+ url: 请求的 URL
123
+ **kwargs: 其他传递给 httpx.delete 的参数
124
+
125
+ 返回:
126
+ httpx.Response 对象
127
+
128
+ 注意:
129
+ 此方法使用 httpx 实现,包含自动重试机制,适用于解决"Response ended prematurely"等连接问题
130
+ """
131
+ client = get_httpx_client()
132
+ try:
133
+ response = client.delete(url=url, **kwargs)
134
+ response.raise_for_status()
135
+ return response
136
+ finally:
137
+ client.close()
138
+
139
+
140
+ # 同步流式POST请求方法
141
+ def stream_post(
142
+ url: str,
143
+ data: Optional[Any] = None,
144
+ json: Optional[Dict[str, Any]] = None,
145
+ **kwargs,
146
+ ) -> Generator[bytes, None, None]:
147
+ """
148
+ 发送流式 POST 请求,使用 httpx 实现,返回标准 Generator
149
+
150
+ 参数:
151
+ url: 请求的 URL
152
+ data: (可选) 请求体数据 (表单数据或原始数据)
153
+ json: (可选) JSON 数据,会自动设置 Content-Type
154
+ **kwargs: 其他传递给 httpx.post 的参数
155
+
156
+ 返回:
157
+ Generator[bytes, None, None]: 字节流生成器
158
+
159
+ 注意:
160
+ 此方法使用 httpx 实现流式请求,适用于处理大文件下载或流式响应
161
+ """
162
+ client = get_httpx_client()
163
+ try:
164
+ with client.stream("POST", url, data=data, json=json, **kwargs) as response:
165
+ response.raise_for_status()
166
+ for chunk in response.iter_bytes():
167
+ yield chunk
168
+ finally:
169
+ client.close()
@@ -1,5 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  import hashlib
3
+ import json
3
4
  import os
4
5
  import signal
5
6
  import subprocess
@@ -9,35 +10,24 @@ import time
9
10
  from pathlib import Path
10
11
  from typing import Any, Callable, Dict, Optional
11
12
 
12
- import yaml
13
+ import yaml # type: ignore
13
14
 
14
15
  from jarvis import __version__
15
- from jarvis.jarvis_utils.config import (get_data_dir, get_max_big_content_size,
16
- set_global_env_data)
16
+ from jarvis.jarvis_utils.config import (
17
+ get_data_dir,
18
+ get_max_big_content_size,
19
+ set_global_env_data,
20
+ )
17
21
  from jarvis.jarvis_utils.embedding import get_context_token_count
18
- from jarvis.jarvis_utils.globals import (get_in_chat, get_interrupt,
19
- set_interrupt)
22
+ from jarvis.jarvis_utils.globals import get_in_chat, get_interrupt, set_interrupt
20
23
  from jarvis.jarvis_utils.input import get_single_line_input
21
24
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
22
25
 
23
26
  g_config_file = None
24
27
 
25
28
 
26
- def init_env(welcome_str: str, config_file: Optional[str] = None) -> None:
27
- """初始化环境变量从jarvis_data/env文件
28
- 功能:
29
- 1. 创建不存在的jarvis_data目录
30
- 2. 加载环境变量到os.environ
31
- 3. 处理文件读取异常
32
- 4. 检查git仓库状态并在落后时更新
33
- 5. 统计当前命令使用次数
34
- 6. 注册SIGINT信号处理函数
35
-
36
- 参数:
37
- welcome_str: 欢迎信息字符串
38
- config_file: 配置文件路径,默认为None(使用~/.jarvis/config.yaml)
39
- """
40
- # 保存原始信号处理函数
29
+ def _setup_signal_handler() -> None:
30
+ """设置SIGINT信号处理函数"""
41
31
  original_sigint = signal.getsignal(signal.SIGINT)
42
32
 
43
33
  def sigint_handler(signum, frame):
@@ -50,7 +40,16 @@ def init_env(welcome_str: str, config_file: Optional[str] = None) -> None:
50
40
  original_sigint(signum, frame)
51
41
 
52
42
  signal.signal(signal.SIGINT, sigint_handler)
53
- count_cmd_usage()
43
+
44
+
45
+ def _show_welcome_message(welcome_str: str) -> None:
46
+ """显示欢迎信息
47
+
48
+ 参数:
49
+ welcome_str: 欢迎信息字符串
50
+ """
51
+ if not welcome_str:
52
+ return
54
53
 
55
54
  jarvis_ascii_art = f"""
56
55
  ██╗ █████╗ ██████╗ ██╗ ██╗██╗███████╗
@@ -64,21 +63,16 @@ def init_env(welcome_str: str, config_file: Optional[str] = None) -> None:
64
63
  https://github.com/skyfireitdiy/Jarvis
65
64
  v{__version__}
66
65
  """
67
- if welcome_str:
68
- PrettyOutput.print_gradient_text(jarvis_ascii_art, (0, 120, 255), (0, 255, 200))
66
+ PrettyOutput.print_gradient_text(jarvis_ascii_art, (0, 120, 255), (0, 255, 200))
69
67
 
70
- global g_config_file
71
- g_config_file = config_file
72
68
 
73
- load_config()
74
-
75
- # 现在获取最终的数据目录(可能被配置文件修改)
69
+ def _extract_huggingface_models() -> None:
70
+ """解压HuggingFace模型"""
76
71
  data_dir = Path(get_data_dir())
77
72
  script_dir = Path(os.path.dirname(os.path.dirname(__file__)))
78
73
  hf_archive = script_dir / "jarvis_data" / "huggingface.tar.gz"
79
-
80
- # 检查并解压huggingface模型
81
74
  hf_dir = data_dir / "huggingface" / "hub"
75
+
82
76
  if not hf_dir.exists() and hf_archive.exists():
83
77
  try:
84
78
  PrettyOutput.print("正在解压HuggingFace模型...", OutputType.INFO)
@@ -88,13 +82,47 @@ def init_env(welcome_str: str, config_file: Optional[str] = None) -> None:
88
82
  except Exception as e:
89
83
  PrettyOutput.print(f"解压HuggingFace模型失败: {e}", OutputType.ERROR)
90
84
 
91
- # 检查是否是git仓库并更新
85
+
86
+ def _check_git_updates() -> bool:
87
+ """检查并更新git仓库
88
+
89
+ 返回:
90
+ bool: 是否需要重启进程
91
+ """
92
+ script_dir = Path(os.path.dirname(os.path.dirname(__file__)))
92
93
  from jarvis.jarvis_utils.git_utils import check_and_update_git_repo
93
94
 
94
- if check_and_update_git_repo(str(script_dir)):
95
- # 更新成功,用当前命令行参数启动新进程
95
+ return check_and_update_git_repo(str(script_dir))
96
+
97
+
98
+ def init_env(welcome_str: str, config_file: Optional[str] = None) -> None:
99
+ """初始化Jarvis环境
100
+
101
+ 参数:
102
+ welcome_str: 欢迎信息字符串
103
+ config_file: 配置文件路径,默认为None(使用~/.jarvis/config.yaml)
104
+ """
105
+ # 1. 设置信号处理
106
+ _setup_signal_handler()
107
+
108
+ # 2. 统计命令使用
109
+ count_cmd_usage()
110
+
111
+ # 3. 显示欢迎信息
112
+ if welcome_str:
113
+ _show_welcome_message(welcome_str)
114
+
115
+ # 4. 设置配置文件
116
+ global g_config_file
117
+ g_config_file = config_file
118
+ load_config()
119
+
120
+ # 5. 解压模型
121
+ _extract_huggingface_models()
122
+
123
+ # 6. 检查git更新
124
+ if _check_git_updates():
96
125
  os.execv(sys.executable, [sys.executable] + sys.argv)
97
- # 如果execv失败,退出当前进程
98
126
  sys.exit(0)
99
127
 
100
128
 
@@ -111,47 +139,142 @@ def load_config():
111
139
  old_config_file = config_file_path.parent / "env"
112
140
  if old_config_file.exists(): # 旧的配置文件存在
113
141
  _read_old_config_file(old_config_file)
142
+ else:
143
+ # 生成默认配置文件
144
+ schema_path = (
145
+ Path(__file__).parent.parent / "jarvis_data" / "config_schema.json"
146
+ )
147
+ if schema_path.exists():
148
+ try:
149
+ config_file_path.parent.mkdir(parents=True, exist_ok=True)
150
+ generate_default_config(str(schema_path), str(config_file_path))
151
+ PrettyOutput.print(
152
+ f"已生成默认配置文件: {config_file_path}", OutputType.INFO
153
+ )
154
+ except Exception as e:
155
+ PrettyOutput.print(f"生成默认配置文件失败: {e}", OutputType.ERROR)
114
156
  else:
115
- _read_config_file(config_file_path.parent, config_file_path)
157
+ _load_and_process_config(str(config_file_path.parent), str(config_file_path))
116
158
 
117
159
 
118
- def _read_config_file(jarvis_dir, config_file):
119
- """读取并解析YAML格式的配置文件
160
+ from typing import Tuple
120
161
 
121
- 功能:
122
- 1. 读取配置文件内容
123
- 2. 检查并添加schema声明(如果缺失)
124
- 3. 将配置数据保存到全局变量
125
- 4. 设置环境变量(如果配置中有ENV字段)
162
+
163
+ def _load_config_file(config_file: str) -> Tuple[str, dict]:
164
+ """读取并解析YAML格式的配置文件
126
165
 
127
166
  参数:
128
- jarvis_dir: Jarvis数据目录路径
129
167
  config_file: 配置文件路径
168
+
169
+ 返回:
170
+ Tuple[str, dict]: (文件原始内容, 解析后的配置字典)
130
171
  """
131
172
  with open(config_file, "r", encoding="utf-8") as f:
132
173
  content = f.read()
133
174
  config_data = yaml.safe_load(content) or {}
134
- if isinstance(config_data, dict):
135
- # 检查是否已有schema声明,没有则添加
136
- if "# yaml-language-server: $schema=" not in content:
137
- schema_path = Path(
138
- os.path.relpath(
139
- Path(__file__).parent.parent
140
- / "jarvis_data"
141
- / "config_schema.json",
142
- start=jarvis_dir,
143
- )
144
- )
145
- with open(config_file, "w", encoding="utf-8") as f:
146
- f.write(f"# yaml-language-server: $schema={schema_path}\n")
147
- f.write(content)
148
- # 保存到全局变量
149
- set_global_env_data(config_data)
150
- # 如果配置中有ENV键值对,则设置环境变量
151
- if "ENV" in config_data and isinstance(config_data["ENV"], dict):
152
- os.environ.update(
153
- {str(k): str(v) for k, v in config_data["ENV"].items() if v is not None}
175
+ return content, config_data
176
+
177
+
178
+ def _ensure_schema_declaration(
179
+ jarvis_dir: str, config_file: str, content: str, config_data: dict
180
+ ) -> None:
181
+ """确保配置文件包含schema声明
182
+
183
+ 参数:
184
+ jarvis_dir: Jarvis数据目录路径
185
+ config_file: 配置文件路径
186
+ content: 配置文件原始内容
187
+ config_data: 解析后的配置字典
188
+ """
189
+ if (
190
+ isinstance(config_data, dict)
191
+ and "# yaml-language-server: $schema=" not in content
192
+ ):
193
+ schema_path = Path(
194
+ os.path.relpath(
195
+ Path(__file__).parent.parent / "jarvis_data" / "config_schema.json",
196
+ start=jarvis_dir,
154
197
  )
198
+ )
199
+ with open(config_file, "w", encoding="utf-8") as f:
200
+ f.write(f"# yaml-language-server: $schema={schema_path}\n")
201
+ f.write(content)
202
+
203
+
204
+ def _process_env_variables(config_data: dict) -> None:
205
+ """处理配置中的环境变量
206
+
207
+ 参数:
208
+ config_data: 解析后的配置字典
209
+ """
210
+ if "ENV" in config_data and isinstance(config_data["ENV"], dict):
211
+ os.environ.update(
212
+ {str(k): str(v) for k, v in config_data["ENV"].items() if v is not None}
213
+ )
214
+
215
+
216
+ def _load_and_process_config(jarvis_dir: str, config_file: str) -> None:
217
+ """加载并处理配置文件
218
+
219
+ 功能:
220
+ 1. 读取配置文件
221
+ 2. 确保schema声明存在
222
+ 3. 保存配置到全局变量
223
+ 4. 处理环境变量
224
+
225
+ 参数:
226
+ jarvis_dir: Jarvis数据目录路径
227
+ config_file: 配置文件路径
228
+ """
229
+ content, config_data = _load_config_file(config_file)
230
+ _ensure_schema_declaration(jarvis_dir, config_file, content, config_data)
231
+ set_global_env_data(config_data)
232
+ _process_env_variables(config_data)
233
+
234
+
235
+ def generate_default_config(schema_path: str, output_path: str) -> None:
236
+ """从schema文件生成默认的YAML格式配置文件
237
+
238
+ 功能:
239
+ 1. 从schema文件读取配置结构
240
+ 2. 根据schema中的default值生成默认配置
241
+ 3. 自动添加schema声明
242
+ 4. 处理嵌套的schema结构
243
+ 5. 保留注释和格式
244
+
245
+ 参数:
246
+ schema_path: schema文件路径
247
+ output_path: 生成的配置文件路径
248
+ """
249
+ with open(schema_path, "r", encoding="utf-8") as f:
250
+ schema = json.load(f)
251
+
252
+ def _generate_from_schema(schema_dict: Dict[str, Any]) -> Dict[str, Any]:
253
+ config = {}
254
+ if "properties" in schema_dict:
255
+ for key, value in schema_dict["properties"].items():
256
+ if "default" in value:
257
+ config[key] = value["default"]
258
+ elif "properties" in value: # 处理嵌套对象
259
+ config[key] = _generate_from_schema(value)
260
+ elif value.get("type") == "array": # 处理列表类型
261
+ config[key] = []
262
+ return config
263
+
264
+ default_config = _generate_from_schema(schema)
265
+
266
+ # 添加schema声明
267
+ rel_schema_path = Path(
268
+ os.path.relpath(
269
+ Path(schema_path),
270
+ start=Path(output_path).parent,
271
+ )
272
+ )
273
+ content = f"# yaml-language-server: $schema={rel_schema_path}\n"
274
+ content += yaml.dump(default_config, allow_unicode=True, sort_keys=False)
275
+
276
+ with open(output_path, "w", encoding="utf-8") as f:
277
+ f.write(content)
155
278
 
156
279
 
157
280
  def _read_old_config_file(config_file):