gitinstall 1.1.0__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.
Files changed (59) hide show
  1. gitinstall/__init__.py +61 -0
  2. gitinstall/_sdk.py +541 -0
  3. gitinstall/academic.py +831 -0
  4. gitinstall/admin.html +327 -0
  5. gitinstall/auto_update.py +384 -0
  6. gitinstall/autopilot.py +349 -0
  7. gitinstall/badge.py +476 -0
  8. gitinstall/checkpoint.py +330 -0
  9. gitinstall/cicd.py +499 -0
  10. gitinstall/clawhub.html +718 -0
  11. gitinstall/config_schema.py +353 -0
  12. gitinstall/db.py +984 -0
  13. gitinstall/db_backend.py +445 -0
  14. gitinstall/dep_chain.py +337 -0
  15. gitinstall/dependency_audit.py +1153 -0
  16. gitinstall/detector.py +542 -0
  17. gitinstall/doctor.py +493 -0
  18. gitinstall/education.py +869 -0
  19. gitinstall/enterprise.py +802 -0
  20. gitinstall/error_fixer.py +953 -0
  21. gitinstall/event_bus.py +251 -0
  22. gitinstall/executor.py +577 -0
  23. gitinstall/feature_flags.py +138 -0
  24. gitinstall/fetcher.py +921 -0
  25. gitinstall/huggingface.py +922 -0
  26. gitinstall/hw_detect.py +988 -0
  27. gitinstall/i18n.py +664 -0
  28. gitinstall/installer_registry.py +362 -0
  29. gitinstall/knowledge_base.py +379 -0
  30. gitinstall/license_check.py +605 -0
  31. gitinstall/llm.py +569 -0
  32. gitinstall/log.py +236 -0
  33. gitinstall/main.py +1408 -0
  34. gitinstall/mcp_agent.py +841 -0
  35. gitinstall/mcp_server.py +386 -0
  36. gitinstall/monorepo.py +810 -0
  37. gitinstall/multi_source.py +425 -0
  38. gitinstall/onboard.py +276 -0
  39. gitinstall/planner.py +222 -0
  40. gitinstall/planner_helpers.py +323 -0
  41. gitinstall/planner_known_projects.py +1010 -0
  42. gitinstall/planner_templates.py +996 -0
  43. gitinstall/remote_gpu.py +633 -0
  44. gitinstall/resilience.py +608 -0
  45. gitinstall/run_tests.py +572 -0
  46. gitinstall/skills.py +476 -0
  47. gitinstall/tool_schemas.py +324 -0
  48. gitinstall/trending.py +279 -0
  49. gitinstall/uninstaller.py +415 -0
  50. gitinstall/validate_top100.py +607 -0
  51. gitinstall/watchdog.py +180 -0
  52. gitinstall/web.py +1277 -0
  53. gitinstall/web_ui.html +2277 -0
  54. gitinstall-1.1.0.dist-info/METADATA +275 -0
  55. gitinstall-1.1.0.dist-info/RECORD +59 -0
  56. gitinstall-1.1.0.dist-info/WHEEL +5 -0
  57. gitinstall-1.1.0.dist-info/entry_points.txt +3 -0
  58. gitinstall-1.1.0.dist-info/licenses/LICENSE +21 -0
  59. gitinstall-1.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,353 @@
1
+ """
2
+ config_schema.py - gitinstall 配置 Schema 验证
3
+ ================================================
4
+
5
+ 灵感来源:OpenClaw 的 Zod Schema 配置验证 + 热重载
6
+
7
+ 功能:
8
+ 1. 定义配置文件的完整 Schema(类似 Zod 但纯 Python)
9
+ 2. 验证 ~/.gitinstall/config.json 格式合法性
10
+ 3. 提供默认值合并
11
+ 4. 类型检查 + 范围校验
12
+ 5. 友好的错误提示
13
+
14
+ 零外部依赖,纯 Python 标准库。
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import json
20
+ import os
21
+ from dataclasses import dataclass, field
22
+ from pathlib import Path
23
+ from typing import Any, Optional
24
+
25
+
26
+ @dataclass
27
+ class ValidationError:
28
+ """验证错误"""
29
+ path: str # 配置路径,如 "install_mode"
30
+ message: str # 错误消息
31
+ expected: str # 期望值描述
32
+ actual: Any # 实际值
33
+
34
+
35
+ @dataclass
36
+ class ValidationResult:
37
+ """验证结果"""
38
+ valid: bool
39
+ errors: list[ValidationError] = field(default_factory=list)
40
+ warnings: list[str] = field(default_factory=list)
41
+ config: dict = field(default_factory=dict) # 合并默认值后的完整配置
42
+
43
+
44
+ # ─────────────────────────────────────────────
45
+ # Schema 定义
46
+ # ─────────────────────────────────────────────
47
+
48
+ # 配置项 Schema:(类型, 默认值, 描述, 可选的验证函数)
49
+ CONFIG_SCHEMA = {
50
+ "version": {
51
+ "type": str,
52
+ "default": "1.0",
53
+ "description": "配置文件版本",
54
+ },
55
+ "default_install_dir": {
56
+ "type": str,
57
+ "default": "~/projects",
58
+ "description": "默认安装目录",
59
+ },
60
+ "install_mode": {
61
+ "type": str,
62
+ "default": "safe",
63
+ "description": "安装模式",
64
+ "enum": ["safe", "fast", "strict"],
65
+ },
66
+ "telemetry": {
67
+ "type": bool,
68
+ "default": True,
69
+ "description": "是否启用匿名遥测",
70
+ },
71
+ "github_token": {
72
+ "type": str,
73
+ "default": "",
74
+ "description": "GitHub Personal Access Token",
75
+ "secret": True,
76
+ },
77
+ "llm_preference": {
78
+ "type": str,
79
+ "default": "",
80
+ "description": "首选 LLM 服务",
81
+ "enum": ["", "anthropic", "openai", "groq", "deepseek", "gemini", "ollama", "lmstudio", "none"],
82
+ },
83
+ "llm_key": {
84
+ "type": dict,
85
+ "default": {},
86
+ "description": "LLM API Key 存储",
87
+ },
88
+ "cache_ttl": {
89
+ "type": int,
90
+ "default": 86400,
91
+ "description": "缓存 TTL(秒)",
92
+ "min": 0,
93
+ "max": 604800, # 最多 7 天
94
+ },
95
+ "max_readme_size": {
96
+ "type": int,
97
+ "default": 50000,
98
+ "description": "README 最大读取字节数",
99
+ "min": 1000,
100
+ "max": 500000,
101
+ },
102
+ "auto_venv": {
103
+ "type": bool,
104
+ "default": True,
105
+ "description": "Python 项目自动创建 virtualenv",
106
+ },
107
+ "docker_prefer": {
108
+ "type": bool,
109
+ "default": False,
110
+ "description": "优先使用 Docker(当 Dockerfile 存在时)",
111
+ },
112
+ "skills_initialized": {
113
+ "type": bool,
114
+ "default": False,
115
+ "description": "内建 Skills 是否已初始化",
116
+ },
117
+ "onboard_completed": {
118
+ "type": bool,
119
+ "default": False,
120
+ "description": "引导向导是否已完成",
121
+ },
122
+ "web_port": {
123
+ "type": int,
124
+ "default": 8080,
125
+ "description": "Web UI 端口",
126
+ "min": 1024,
127
+ "max": 65535,
128
+ },
129
+ "web_host": {
130
+ "type": str,
131
+ "default": "127.0.0.1",
132
+ "description": "Web UI 绑定地址",
133
+ },
134
+ "preferred_platform": {
135
+ "type": str,
136
+ "default": "github",
137
+ "description": "默认代码托管平台",
138
+ "enum": ["github", "gitlab", "bitbucket", "gitee", "codeberg"],
139
+ },
140
+ "detected_env": {
141
+ "type": dict,
142
+ "default": {},
143
+ "description": "检测到的系统环境信息(自动填充)",
144
+ },
145
+ # ── 镜像加速(中国用户 / 企业内网)──
146
+ "mirror_pypi": {
147
+ "type": str,
148
+ "default": "",
149
+ "description": "PyPI 镜像(如 https://pypi.tuna.tsinghua.edu.cn/simple)",
150
+ },
151
+ "mirror_npm": {
152
+ "type": str,
153
+ "default": "",
154
+ "description": "npm 镜像(如 https://registry.npmmirror.com)",
155
+ },
156
+ "mirror_github": {
157
+ "type": str,
158
+ "default": "",
159
+ "description": "GitHub 加速镜像(如 https://ghproxy.com)",
160
+ },
161
+ # ── 代理 ──
162
+ "http_proxy": {
163
+ "type": str,
164
+ "default": "",
165
+ "description": "HTTP/HTTPS 代理(如 http://127.0.0.1:7890)",
166
+ },
167
+ # ── GPU / 硬件 ──
168
+ "gpu_memory_override_gb": {
169
+ "type": float,
170
+ "default": 0.0,
171
+ "description": "手动指定 GPU 显存(GB),0 表示自动检测",
172
+ "min": 0.0,
173
+ "max": 1024.0,
174
+ },
175
+ # ── 并发 ──
176
+ "max_concurrent_downloads": {
177
+ "type": int,
178
+ "default": 3,
179
+ "description": "最大并发下载数",
180
+ "min": 1,
181
+ "max": 16,
182
+ },
183
+ # ── 企业 ──
184
+ "enterprise_mode": {
185
+ "type": bool,
186
+ "default": False,
187
+ "description": "启用企业功能(SSO/RBAC/审计)",
188
+ },
189
+ "sso_provider": {
190
+ "type": str,
191
+ "default": "",
192
+ "description": "SSO 提供商",
193
+ "enum": ["", "oidc", "saml"],
194
+ },
195
+ "sso_issuer": {
196
+ "type": str,
197
+ "default": "",
198
+ "description": "SSO OIDC Issuer URL",
199
+ },
200
+ }
201
+
202
+
203
+ # ─────────────────────────────────────────────
204
+ # 验证逻辑
205
+ # ─────────────────────────────────────────────
206
+
207
+ def validate_config(config: dict) -> ValidationResult:
208
+ """
209
+ 验证配置文件。
210
+
211
+ 返回 ValidationResult:
212
+ - valid: 是否通过验证(有 error 则为 False)
213
+ - errors: 错误列表
214
+ - warnings: 警告列表
215
+ - config: 合并默认值后的完整配置
216
+ """
217
+ errors = []
218
+ warnings = []
219
+ merged = {}
220
+
221
+ # 类型防御:config 必须是 dict
222
+ if not isinstance(config, dict):
223
+ return ValidationResult(
224
+ valid=False,
225
+ errors=[ValidationError(
226
+ path="<root>",
227
+ message="配置必须是 dict 类型",
228
+ expected="dict",
229
+ actual=type(config).__name__,
230
+ )],
231
+ warnings=[],
232
+ config={key: schema["default"] for key, schema in CONFIG_SCHEMA.items()},
233
+ )
234
+
235
+ # 合并默认值
236
+ for key, schema in CONFIG_SCHEMA.items():
237
+ if key in config:
238
+ merged[key] = config[key]
239
+ else:
240
+ merged[key] = schema["default"]
241
+
242
+ # 检查未知字段
243
+ known_keys = set(CONFIG_SCHEMA.keys())
244
+ # 允许一些额外字段
245
+ extra_allowed = {"onboard_time"}
246
+ for key in config:
247
+ if key not in known_keys and key not in extra_allowed:
248
+ warnings.append(f"未知配置项 '{key}' 将被忽略")
249
+
250
+ # 逐项验证
251
+ for key, schema in CONFIG_SCHEMA.items():
252
+ if key not in config:
253
+ continue
254
+
255
+ value = config[key]
256
+ expected_type = schema["type"]
257
+
258
+ # 类型检查
259
+ if not isinstance(value, expected_type):
260
+ # int 和 float 互容
261
+ if expected_type in (int, float) and isinstance(value, (int, float)):
262
+ merged[key] = expected_type(value)
263
+ else:
264
+ errors.append(ValidationError(
265
+ path=key,
266
+ message=f"类型错误",
267
+ expected=expected_type.__name__,
268
+ actual=type(value).__name__,
269
+ ))
270
+ continue
271
+
272
+ # 枚举检查
273
+ if "enum" in schema and value not in schema["enum"]:
274
+ errors.append(ValidationError(
275
+ path=key,
276
+ message=f"值不在允许范围内",
277
+ expected=f"之一: {schema['enum']}",
278
+ actual=value,
279
+ ))
280
+
281
+ # 数值范围检查
282
+ if "min" in schema and isinstance(value, (int, float)):
283
+ if value < schema["min"]:
284
+ errors.append(ValidationError(
285
+ path=key,
286
+ message=f"值过小",
287
+ expected=f">= {schema['min']}",
288
+ actual=value,
289
+ ))
290
+ if "max" in schema and isinstance(value, (int, float)):
291
+ if value > schema["max"]:
292
+ errors.append(ValidationError(
293
+ path=key,
294
+ message=f"值过大",
295
+ expected=f"<= {schema['max']}",
296
+ actual=value,
297
+ ))
298
+
299
+ return ValidationResult(
300
+ valid=len(errors) == 0,
301
+ errors=errors,
302
+ warnings=warnings,
303
+ config=merged,
304
+ )
305
+
306
+
307
+ def load_and_validate(config_path: Path = None) -> ValidationResult:
308
+ """加载并验证配置文件"""
309
+ config_path = config_path or (Path.home() / ".gitinstall" / "config.json")
310
+
311
+ if not config_path.exists():
312
+ # 配置文件不存在,返回全默认值
313
+ defaults = {k: v["default"] for k, v in CONFIG_SCHEMA.items()}
314
+ return ValidationResult(valid=True, config=defaults)
315
+
316
+ try:
317
+ with open(config_path, encoding="utf-8") as f:
318
+ config = json.load(f)
319
+ except json.JSONDecodeError as e:
320
+ return ValidationResult(
321
+ valid=False,
322
+ errors=[ValidationError("(file)", f"JSON 解析失败: {e}", "合法 JSON", str(e))],
323
+ )
324
+ except OSError as e:
325
+ return ValidationResult(
326
+ valid=False,
327
+ errors=[ValidationError("(file)", f"文件读取失败: {e}", "可读文件", str(e))],
328
+ )
329
+
330
+ return validate_config(config)
331
+
332
+
333
+ def get_config_value(key: str, fallback=None):
334
+ """快速获取单个配置值(带默认值回退)"""
335
+ result = load_and_validate()
336
+ return result.config.get(key, fallback)
337
+
338
+
339
+ def format_validation_result(result: ValidationResult) -> str:
340
+ """格式化验证结果"""
341
+ lines = []
342
+ if result.valid:
343
+ lines.append(" ✅ 配置文件验证通过")
344
+ else:
345
+ lines.append(" ❌ 配置文件存在错误:")
346
+ for err in result.errors:
347
+ lines.append(f" • {err.path}: {err.message} (期望: {err.expected}, 实际: {err.actual})")
348
+
349
+ if result.warnings:
350
+ for w in result.warnings:
351
+ lines.append(f" ⚠️ {w}")
352
+
353
+ return "\n".join(lines)