@agentunion/kite 1.3.2 → 1.5.0

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 (293) hide show
  1. package/CHANGELOG.md +302 -0
  2. package/cli.js +119 -4
  3. package/core/dependency_checker.py +250 -0
  4. package/core/env_checker.py +490 -0
  5. package/dependencies_lock.json +128 -0
  6. package/extensions/agents/assistant/entry.py +111 -1
  7. package/extensions/agents/assistant/server.py +279 -215
  8. package/extensions/channels/acp_channel/entry.py +111 -1
  9. package/extensions/channels/acp_channel/module.md +23 -22
  10. package/extensions/channels/acp_channel/server.py +279 -215
  11. package/extensions/event_hub_bench/entry.py +107 -1
  12. package/extensions/services/backup/entry.py +306 -21
  13. package/extensions/services/backup/module.md +24 -22
  14. package/extensions/services/evol/auth_manager.py +443 -0
  15. package/extensions/services/evol/config.yaml +149 -0
  16. package/extensions/services/evol/config_loader.py +117 -0
  17. package/extensions/services/evol/entry.py +406 -0
  18. package/extensions/services/evol/evol_api.py +173 -0
  19. package/extensions/services/evol/evol_config.json5 +29 -0
  20. package/extensions/services/evol/migrate_tokens.py +122 -0
  21. package/extensions/services/evol/module.md +32 -0
  22. package/extensions/services/evol/pairing.py +250 -0
  23. package/extensions/services/evol/pairing_codes.jsonl +1 -0
  24. package/extensions/services/evol/relay.py +682 -0
  25. package/extensions/services/evol/relay_config.json5 +67 -0
  26. package/extensions/services/evol/routes/__init__.py +1 -0
  27. package/extensions/services/evol/routes/routes_management_ws.py +127 -0
  28. package/extensions/services/evol/routes/routes_rpc.py +89 -0
  29. package/extensions/services/evol/routes/routes_test.py +61 -0
  30. package/extensions/services/evol/server.py +875 -0
  31. package/extensions/services/evol/static/css/style.css +1200 -0
  32. package/extensions/services/evol/static/index.html +781 -0
  33. package/extensions/services/evol/static/index_evol.html +14 -0
  34. package/extensions/services/evol/static/js/app.js +6304 -0
  35. package/extensions/services/evol/static/js/auth.js +326 -0
  36. package/extensions/services/evol/static/js/dialog.js +285 -0
  37. package/extensions/services/evol/static/js/evol-app-fixed.js +50 -0
  38. package/extensions/services/evol/static/js/evol-app.js +1949 -0
  39. package/extensions/services/evol/static/js/evol-app.js.bak +1800 -0
  40. package/extensions/services/evol/static/js/kernel-client-example.js +228 -0
  41. package/extensions/services/evol/static/js/kernel-client.js +396 -0
  42. package/extensions/services/evol/static/js/main.js +141 -0
  43. package/extensions/services/evol/static/js/registry-tests.js +585 -0
  44. package/extensions/services/evol/static/js/stats.js +217 -0
  45. package/extensions/services/evol/static/js/token-manager.js +175 -0
  46. package/extensions/services/evol/static/pairing.html +248 -0
  47. package/extensions/services/evol/static/test_registry.html +262 -0
  48. package/extensions/services/evol/static/test_relay.html +462 -0
  49. package/extensions/services/evol/stats_manager.py +240 -0
  50. package/extensions/services/model_service/entry.py +167 -19
  51. package/extensions/services/model_service/module.md +21 -22
  52. package/extensions/services/proxy/.claude/settings.local.json +13 -0
  53. package/extensions/services/proxy/CHANGELOG_20260308.md +258 -0
  54. package/extensions/services/proxy/_fix_prints.py +133 -0
  55. package/extensions/services/proxy/_fix_prints2.py +87 -0
  56. package/extensions/services/proxy/agentcp/LICENCE +178 -0
  57. package/extensions/services/proxy/agentcp/README copy.md +85 -0
  58. package/extensions/services/proxy/agentcp/README.md +260 -0
  59. package/extensions/services/proxy/agentcp/__init__.py +16 -0
  60. package/extensions/services/proxy/agentcp/agent.py +4 -0
  61. package/extensions/services/proxy/agentcp/agentcp.py +2494 -0
  62. package/extensions/services/proxy/agentcp/agentprofile.json +89 -0
  63. package/extensions/services/proxy/agentcp/ap/__init__.py +16 -0
  64. package/extensions/services/proxy/agentcp/ap/ap_client.py +316 -0
  65. package/extensions/services/proxy/agentcp/assets/images/wechat_qr.png +0 -0
  66. package/extensions/services/proxy/agentcp/backup/metrics.json +31 -0
  67. package/extensions/services/proxy/agentcp/base/__init__.py +20 -0
  68. package/extensions/services/proxy/agentcp/base/auth_client.py +257 -0
  69. package/extensions/services/proxy/agentcp/base/client.py +112 -0
  70. package/extensions/services/proxy/agentcp/base/env.py +34 -0
  71. package/extensions/services/proxy/agentcp/base/html_util.py +336 -0
  72. package/extensions/services/proxy/agentcp/base/log.py +98 -0
  73. package/extensions/services/proxy/agentcp/ca/__init__.py +17 -0
  74. package/extensions/services/proxy/agentcp/ca/ca_client.py +414 -0
  75. package/extensions/services/proxy/agentcp/ca/ca_root.py +74 -0
  76. package/extensions/services/proxy/agentcp/context/__init__.py +20 -0
  77. package/extensions/services/proxy/agentcp/context/context.py +73 -0
  78. package/extensions/services/proxy/agentcp/context/exceptions.py +114 -0
  79. package/extensions/services/proxy/agentcp/create_profile.py +125 -0
  80. package/extensions/services/proxy/agentcp/create_profile_weather.py +125 -0
  81. package/extensions/services/proxy/agentcp/db/__init__.py +15 -0
  82. package/extensions/services/proxy/agentcp/db/db_mananger.py +550 -0
  83. package/extensions/services/proxy/agentcp/docs/UDP_HEARTBEAT_FIX_REPORT.md +265 -0
  84. package/extensions/services/proxy/agentcp/docs/heartbeat_issue_analysis.md +291 -0
  85. package/extensions/services/proxy/agentcp/file/__init__.py +16 -0
  86. package/extensions/services/proxy/agentcp/file/file_client.py +141 -0
  87. package/extensions/services/proxy/agentcp/file/wss_binary_message.py +137 -0
  88. package/extensions/services/proxy/agentcp/hcp.py +299 -0
  89. package/extensions/services/proxy/agentcp/heartbeat/__init__.py +16 -0
  90. package/extensions/services/proxy/agentcp/heartbeat/heartbeat_client.py +360 -0
  91. package/extensions/services/proxy/agentcp/improved_scheduler.py +498 -0
  92. package/extensions/services/proxy/agentcp/llm_agent_utils.py +249 -0
  93. package/extensions/services/proxy/agentcp/llm_server.py +172 -0
  94. package/extensions/services/proxy/agentcp/mermaid.py +210 -0
  95. package/extensions/services/proxy/agentcp/message.py +149 -0
  96. package/extensions/services/proxy/agentcp/metrics.py +256 -0
  97. package/extensions/services/proxy/agentcp/monitoring/__init__.py +20 -0
  98. package/extensions/services/proxy/agentcp/monitoring/global_monitor.py +27 -0
  99. package/extensions/services/proxy/agentcp/monitoring/metrics_store.py +325 -0
  100. package/extensions/services/proxy/agentcp/monitoring/monitoring_service.py +269 -0
  101. package/extensions/services/proxy/agentcp/monitoring/sliding_window.py +222 -0
  102. package/extensions/services/proxy/agentcp/monitoring/standalone_reader.py +224 -0
  103. package/extensions/services/proxy/agentcp/msg/__init__.py +21 -0
  104. package/extensions/services/proxy/agentcp/msg/connection_manager.py +456 -0
  105. package/extensions/services/proxy/agentcp/msg/message_client.py +2058 -0
  106. package/extensions/services/proxy/agentcp/msg/message_serialize.py +263 -0
  107. package/extensions/services/proxy/agentcp/msg/open_ai_message.py +88 -0
  108. package/extensions/services/proxy/agentcp/msg/session_manager.py +1062 -0
  109. package/extensions/services/proxy/agentcp/msg/stream_client.py +267 -0
  110. package/extensions/services/proxy/agentcp/msg/websocket_file_receiver.py +89 -0
  111. package/extensions/services/proxy/agentcp/msg/ws_logger.py +685 -0
  112. package/extensions/services/proxy/agentcp/msg/wss_binary_message.py +137 -0
  113. package/extensions/services/proxy/agentcp/requirements.txt +7 -0
  114. package/extensions/services/proxy/agentcp/samples/agent_graph/README.md +37 -0
  115. package/extensions/services/proxy/agentcp/samples/agent_graph/agentprofile.json +89 -0
  116. package/extensions/services/proxy/agentcp/samples/agent_graph/create_profile.py +138 -0
  117. package/extensions/services/proxy/agentcp/samples/agent_graph/main.py +164 -0
  118. package/extensions/services/proxy/agentcp/samples/agent_use/create_profile.py +123 -0
  119. package/extensions/services/proxy/agentcp/samples/agent_use/llm/create_profile.py +129 -0
  120. package/extensions/services/proxy/agentcp/samples/agent_use/llm/env.json +5 -0
  121. package/extensions/services/proxy/agentcp/samples/agent_use/llm/main.py +146 -0
  122. package/extensions/services/proxy/agentcp/samples/agent_use/main.py +123 -0
  123. package/extensions/services/proxy/agentcp/samples/agent_use/readme.md +379 -0
  124. package/extensions/services/proxy/agentcp/samples/agent_use/search/create_profile.py +129 -0
  125. package/extensions/services/proxy/agentcp/samples/agent_use/search/main.py +28 -0
  126. package/extensions/services/proxy/agentcp/samples/agent_use/tool/create_profile.py +129 -0
  127. package/extensions/services/proxy/agentcp/samples/agent_use/tool/main.py +20 -0
  128. package/extensions/services/proxy/agentcp/samples/ali_amap/README.md +97 -0
  129. package/extensions/services/proxy/agentcp/samples/ali_amap/amap_agent.py +88 -0
  130. package/extensions/services/proxy/agentcp/samples/ali_amap/create_profile.py +125 -0
  131. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/powershell.py +228 -0
  132. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/software.py +63 -0
  133. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/tools.py +36 -0
  134. package/extensions/services/proxy/agentcp/samples/compute_agent/browser_user.py +41 -0
  135. package/extensions/services/proxy/agentcp/samples/deepseek/README.md +79 -0
  136. package/extensions/services/proxy/agentcp/samples/deepseek/create_profile.py +126 -0
  137. package/extensions/services/proxy/agentcp/samples/deepseek/deepseek.py +42 -0
  138. package/extensions/services/proxy/agentcp/samples/dify_chat/README.md +78 -0
  139. package/extensions/services/proxy/agentcp/samples/dify_chat/create_profile.py +126 -0
  140. package/extensions/services/proxy/agentcp/samples/dify_chat/dify_chat.py +47 -0
  141. package/extensions/services/proxy/agentcp/samples/dify_workflow/README.md +78 -0
  142. package/extensions/services/proxy/agentcp/samples/dify_workflow/create_profile.py +126 -0
  143. package/extensions/services/proxy/agentcp/samples/dify_workflow/dify_workflow.py +46 -0
  144. package/extensions/services/proxy/agentcp/samples/executor/README.md +44 -0
  145. package/extensions/services/proxy/agentcp/samples/executor/agentprofile.json +89 -0
  146. package/extensions/services/proxy/agentcp/samples/executor/create_profile.py +139 -0
  147. package/extensions/services/proxy/agentcp/samples/executor/main.py +160 -0
  148. package/extensions/services/proxy/agentcp/samples/filereader/README.md +45 -0
  149. package/extensions/services/proxy/agentcp/samples/filereader/agentprofile.json +90 -0
  150. package/extensions/services/proxy/agentcp/samples/filereader/create_profile.py +137 -0
  151. package/extensions/services/proxy/agentcp/samples/filereader/main.py +253 -0
  152. package/extensions/services/proxy/agentcp/samples/filewriter/README.md +38 -0
  153. package/extensions/services/proxy/agentcp/samples/filewriter/agentprofile.json +91 -0
  154. package/extensions/services/proxy/agentcp/samples/filewriter/create_profile.py +138 -0
  155. package/extensions/services/proxy/agentcp/samples/filewriter/main.py +289 -0
  156. package/extensions/services/proxy/agentcp/samples/hcp/README.md +85 -0
  157. package/extensions/services/proxy/agentcp/samples/hcp/acp_weather_agent.zip +0 -0
  158. package/extensions/services/proxy/agentcp/samples/hcp/create_profile.py +125 -0
  159. package/extensions/services/proxy/agentcp/samples/hcp/hcp.py +237 -0
  160. package/extensions/services/proxy/agentcp/samples/helloworld/README.md +68 -0
  161. package/extensions/services/proxy/agentcp/samples/helloworld/hello_world.py +40 -0
  162. package/extensions/services/proxy/agentcp/samples/llm_agent/MEADME.md +117 -0
  163. package/extensions/services/proxy/agentcp/samples/llm_agent/create_profile.py +125 -0
  164. package/extensions/services/proxy/agentcp/samples/llm_agent/qwen_agent.py +136 -0
  165. package/extensions/services/proxy/agentcp/samples/local_llm_agent/README.md +90 -0
  166. package/extensions/services/proxy/agentcp/samples/local_llm_agent/create_profile.py +125 -0
  167. package/extensions/services/proxy/agentcp/samples/local_llm_agent/main.py +49 -0
  168. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/README.md +55 -0
  169. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/create_profile.py +125 -0
  170. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/main.py +23 -0
  171. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/README.md +103 -0
  172. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/create_profile.py +125 -0
  173. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/main.py +69 -0
  174. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/README.md +58 -0
  175. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/create_profile.py +125 -0
  176. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/main.py +25 -0
  177. package/extensions/services/proxy/agentcp/samples/qwen3/README.md +71 -0
  178. package/extensions/services/proxy/agentcp/samples/qwen3/create_profile.py +126 -0
  179. package/extensions/services/proxy/agentcp/samples/qwen3/qwen3.py +37 -0
  180. package/extensions/services/proxy/agentcp/samples/qwen3_tools/README.md +133 -0
  181. package/extensions/services/proxy/agentcp/samples/qwen3_tools/create_profile.py +126 -0
  182. package/extensions/services/proxy/agentcp/samples/qwen3_tools/qwen3_tools.py +98 -0
  183. package/extensions/services/proxy/agentcp/samples/search/create_profile_qwen.py +125 -0
  184. package/extensions/services/proxy/agentcp/samples/search/create_profile_search.py +125 -0
  185. package/extensions/services/proxy/agentcp/samples/search/qwen_agent.py +136 -0
  186. package/extensions/services/proxy/agentcp/samples/search/search_agent.py +170 -0
  187. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/README.md +89 -0
  188. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/create_profile.py +125 -0
  189. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/main.py +44 -0
  190. package/extensions/services/proxy/agentcp/utils/__init__.py +15 -0
  191. package/extensions/services/proxy/agentcp/utils/file_util.py +117 -0
  192. package/extensions/services/proxy/agentcp/utils/proxy_bypass.py +99 -0
  193. package/extensions/services/proxy/agentcp/workflow.py +203 -0
  194. package/extensions/services/proxy/console_auth.py +109 -0
  195. package/extensions/services/proxy/evol/__init__.py +1 -0
  196. package/extensions/services/proxy/evol/config.py +37 -0
  197. package/extensions/services/proxy/evol/http/__init__.py +1 -0
  198. package/extensions/services/proxy/evol/http/async_http.py +551 -0
  199. package/extensions/services/proxy/evol/log.py +28 -0
  200. package/extensions/services/proxy/evol/presenter/__init__.py +2 -0
  201. package/extensions/services/proxy/evol/presenter/agentIdPresenter.py +1031 -0
  202. package/extensions/services/proxy/evol/presenter/apikeyPresenter.py +106 -0
  203. package/extensions/services/proxy/evol/presenter/configPresenter.py +1281 -0
  204. package/extensions/services/proxy/evol/presenter/userPresenter.py +477 -0
  205. package/extensions/services/proxy/evol/server/__init__.py +1 -0
  206. package/extensions/services/proxy/evol/server/claude_proxy_async.py +3430 -0
  207. package/extensions/services/proxy/evol/server/openclaw_proxy.py +1861 -0
  208. package/extensions/services/proxy/evol/server/proxy_config.py +15 -0
  209. package/extensions/services/proxy/evol/server/proxy_engine.py +501 -0
  210. package/extensions/services/proxy/evol/version.py +24 -0
  211. package/extensions/services/proxy/logs/websocket.log +260 -0
  212. package/extensions/services/proxy/main.py +240 -0
  213. package/extensions/services/proxy/requirements.txt +13 -0
  214. package/extensions/services/proxy/server.py +271 -0
  215. package/extensions/services/watchdog/entry.py +215 -26
  216. package/extensions/services/watchdog/module.md +1 -0
  217. package/extensions/services/watchdog/monitor.py +178 -38
  218. package/extensions/services/web/WEBSOCKET_STATUS.md +143 -0
  219. package/extensions/services/web/config_example.py +35 -0
  220. package/extensions/services/web/config_loader.py +110 -0
  221. package/extensions/services/web/entry.py +114 -26
  222. package/extensions/services/web/module.md +35 -24
  223. package/extensions/services/web/pairing.py +250 -0
  224. package/extensions/services/web/pairing_codes.jsonl +16 -0
  225. package/extensions/services/web/relay.py +643 -0
  226. package/extensions/services/web/relay_config.json5 +67 -0
  227. package/extensions/services/web/routes/routes_management_ws.py +127 -0
  228. package/extensions/services/web/routes/routes_rpc.py +89 -0
  229. package/extensions/services/web/routes/routes_test.py +61 -0
  230. package/extensions/services/web/routes/schemas.py +0 -22
  231. package/extensions/services/web/server.py +434 -99
  232. package/extensions/services/web/static/css/style.css +67 -28
  233. package/extensions/services/web/static/index.html +234 -44
  234. package/extensions/services/web/static/js/app.js +1335 -48
  235. package/extensions/services/web/static/js/kernel-client-example.js +161 -0
  236. package/extensions/services/web/static/js/kernel-client.js +383 -0
  237. package/extensions/services/web/static/js/registry-tests.js +558 -0
  238. package/extensions/services/web/static/js/token-manager.js +175 -0
  239. package/extensions/services/web/static/pairing.html +248 -0
  240. package/extensions/services/web/static/test_registry.html +262 -0
  241. package/extensions/services/web/web_config.json5 +29 -0
  242. package/kernel/entry.py +120 -32
  243. package/kernel/event_hub.py +141 -16
  244. package/kernel/module.md +60 -33
  245. package/kernel/registry_store.py +45 -36
  246. package/kernel/rpc_router.py +152 -59
  247. package/kernel/server.py +322 -26
  248. package/kite_cli/__init__.py +3 -0
  249. package/kite_cli/__main__.py +5 -0
  250. package/kite_cli/commands/__init__.py +1 -0
  251. package/kite_cli/commands/clean.py +101 -0
  252. package/kite_cli/commands/deps_install.py +67 -0
  253. package/kite_cli/commands/doctor.py +35 -0
  254. package/kite_cli/commands/env_check.py +45 -0
  255. package/kite_cli/commands/history.py +111 -0
  256. package/kite_cli/commands/info.py +96 -0
  257. package/kite_cli/commands/install.py +313 -0
  258. package/kite_cli/commands/list.py +143 -0
  259. package/kite_cli/commands/log.py +81 -0
  260. package/kite_cli/commands/prepare.py +49 -0
  261. package/kite_cli/commands/rollback.py +88 -0
  262. package/kite_cli/commands/search.py +73 -0
  263. package/kite_cli/commands/uninstall.py +85 -0
  264. package/kite_cli/commands/update.py +118 -0
  265. package/kite_cli/commands/venv_setup.py +56 -0
  266. package/kite_cli/core/__init__.py +1 -0
  267. package/kite_cli/core/checker.py +142 -0
  268. package/kite_cli/core/dependency.py +229 -0
  269. package/kite_cli/core/downloader.py +209 -0
  270. package/kite_cli/core/install_info.py +40 -0
  271. package/kite_cli/core/tool_installer.py +397 -0
  272. package/kite_cli/core/validator.py +78 -0
  273. package/kite_cli/main.py +317 -0
  274. package/kite_cli/utils/__init__.py +1 -0
  275. package/kite_cli/utils/i18n.py +252 -0
  276. package/kite_cli/utils/interactive.py +63 -0
  277. package/kite_cli/utils/operation_log.py +77 -0
  278. package/kite_cli/utils/paths.py +34 -0
  279. package/kite_cli/utils/version.py +308 -0
  280. package/launcher/entry.py +1124 -178
  281. package/launcher/logging_setup.py +104 -0
  282. package/launcher/module.md +46 -37
  283. package/launcher/module_scanner.py +11 -1
  284. package/main.py +4 -1
  285. package/package.json +9 -1
  286. package/python_version.json +4 -0
  287. package/requirements.txt +38 -0
  288. package/scripts/env-manager.js +328 -0
  289. package/scripts/plan_manager.py +315 -0
  290. package/scripts/python-env.js +79 -0
  291. package/scripts/scan_dependencies.py +461 -0
  292. package/scripts/setup-python-env.js +191 -0
  293. package/extensions/services/web/routes/routes_modules.py +0 -249
@@ -0,0 +1,397 @@
1
+ """下载工具自动安装器 - 安装 pip/npm/git 等基础工具"""
2
+ import subprocess
3
+ import sys
4
+ import platform
5
+ from pathlib import Path
6
+
7
+
8
+ class ToolInstaller:
9
+ """下载工具安装器"""
10
+
11
+ @staticmethod
12
+ def check_tool(tool_name: str) -> bool:
13
+ """检查工具是否已安装"""
14
+ try:
15
+ # Windows 上某些命令需要 shell=True (如 npm.cmd)
16
+ result = subprocess.run(
17
+ [tool_name, "--version"],
18
+ capture_output=True,
19
+ timeout=5,
20
+ shell=True # Windows 兼容性
21
+ )
22
+ return result.returncode == 0
23
+ except (FileNotFoundError, subprocess.TimeoutExpired):
24
+ return False
25
+
26
+ @staticmethod
27
+ def install_python() -> bool:
28
+ """安装 Python(如果不存在)"""
29
+ if ToolInstaller.check_tool("python") or ToolInstaller.check_tool("python3"):
30
+ return True
31
+
32
+ print("[Install] Python 未安装,正在安装...")
33
+
34
+ system = platform.system()
35
+
36
+ if system == "Windows":
37
+ return ToolInstaller._install_python_windows()
38
+ elif system == "Darwin": # macOS
39
+ return ToolInstaller._install_python_macos()
40
+ elif system == "Linux":
41
+ return ToolInstaller._install_python_linux()
42
+ else:
43
+ print(f"[Error] 不支持的操作系统: {system}")
44
+ return False
45
+
46
+ @staticmethod
47
+ def _install_python_windows() -> bool:
48
+ """Windows 上安装 Python"""
49
+ print("[Info] Windows 系统需要手动安装 Python")
50
+ print("[Info] 请访问: https://www.python.org/downloads/")
51
+ print("[Info] 或使用 winget: winget install Python.Python.3.12")
52
+ return False
53
+
54
+ @staticmethod
55
+ def _install_python_macos() -> bool:
56
+ """macOS 上安装 Python"""
57
+ # 检查是否有 brew
58
+ if not ToolInstaller.check_tool("brew"):
59
+ print("[Error] 需要先安装 Homebrew")
60
+ print("[Info] 访问: https://brew.sh/")
61
+ return False
62
+
63
+ try:
64
+ print("[Install] 使用 Homebrew 安装 Python...")
65
+ result = subprocess.run(
66
+ ["brew", "install", "python@3.12"],
67
+ capture_output=True,
68
+ text=True,
69
+ timeout=300
70
+ )
71
+ if result.returncode == 0:
72
+ print("[Done] Python 安装完成")
73
+ return True
74
+ else:
75
+ print(f"[Error] 安装失败: {result.stderr}")
76
+ return False
77
+ except Exception as e:
78
+ print(f"[Error] 安装失败: {e}")
79
+ return False
80
+
81
+ @staticmethod
82
+ def _install_python_linux() -> bool:
83
+ """Linux 上安装 Python"""
84
+ # 检测包管理器
85
+ if ToolInstaller.check_tool("apt"):
86
+ pkg_manager = "apt"
87
+ install_cmd = ["sudo", "apt", "update", "&&", "sudo", "apt", "install", "-y", "python3", "python3-pip"]
88
+ elif ToolInstaller.check_tool("yum"):
89
+ pkg_manager = "yum"
90
+ install_cmd = ["sudo", "yum", "install", "-y", "python3", "python3-pip"]
91
+ elif ToolInstaller.check_tool("dnf"):
92
+ pkg_manager = "dnf"
93
+ install_cmd = ["sudo", "dnf", "install", "-y", "python3", "python3-pip"]
94
+ else:
95
+ print("[Error] 未检测到支持的包管理器 (apt/yum/dnf)")
96
+ return False
97
+
98
+ try:
99
+ print(f"[Install] 使用 {pkg_manager} 安装 Python...")
100
+ result = subprocess.run(
101
+ " ".join(install_cmd),
102
+ shell=True,
103
+ capture_output=True,
104
+ text=True,
105
+ timeout=300
106
+ )
107
+ if result.returncode == 0:
108
+ print("[Done] Python 安装完成")
109
+ return True
110
+ else:
111
+ print(f"[Error] 安装失败: {result.stderr}")
112
+ return False
113
+ except Exception as e:
114
+ print(f"[Error] 安装失败: {e}")
115
+ return False
116
+
117
+ @staticmethod
118
+ def install_pip() -> bool:
119
+ """安装 pip(如果不存在)"""
120
+ if ToolInstaller.check_tool("pip") or ToolInstaller.check_tool("pip3"):
121
+ return True
122
+
123
+ print("[Install] pip 未安装,正在安装...")
124
+
125
+ # 尝试使用 ensurepip
126
+ try:
127
+ python_cmd = "python" if ToolInstaller.check_tool("python") else "python3"
128
+ result = subprocess.run(
129
+ [python_cmd, "-m", "ensurepip", "--upgrade"],
130
+ capture_output=True,
131
+ text=True,
132
+ timeout=60
133
+ )
134
+ if result.returncode == 0:
135
+ print("[Done] pip 安装完成")
136
+ return True
137
+ except Exception:
138
+ pass
139
+
140
+ # 尝试使用 get-pip.py
141
+ try:
142
+ import urllib.request
143
+ print("[Install] 下载 get-pip.py...")
144
+ url = "https://bootstrap.pypa.io/get-pip.py"
145
+ get_pip_path = Path.home() / "get-pip.py"
146
+
147
+ urllib.request.urlretrieve(url, get_pip_path)
148
+
149
+ python_cmd = "python" if ToolInstaller.check_tool("python") else "python3"
150
+ result = subprocess.run(
151
+ [python_cmd, str(get_pip_path)],
152
+ capture_output=True,
153
+ text=True,
154
+ timeout=120
155
+ )
156
+
157
+ get_pip_path.unlink() # 删除临时文件
158
+
159
+ if result.returncode == 0:
160
+ print("[Done] pip 安装完成")
161
+ return True
162
+ else:
163
+ print(f"[Error] 安装失败: {result.stderr}")
164
+ return False
165
+
166
+ except Exception as e:
167
+ print(f"[Error] 安装失败: {e}")
168
+ return False
169
+
170
+ @staticmethod
171
+ def install_nodejs() -> bool:
172
+ """安装 Node.js 和 npm"""
173
+ if ToolInstaller.check_tool("node") and ToolInstaller.check_tool("npm"):
174
+ return True
175
+
176
+ print("[Install] Node.js/npm 未安装,正在安装...")
177
+
178
+ system = platform.system()
179
+
180
+ if system == "Windows":
181
+ return ToolInstaller._install_nodejs_windows()
182
+ elif system == "Darwin":
183
+ return ToolInstaller._install_nodejs_macos()
184
+ elif system == "Linux":
185
+ return ToolInstaller._install_nodejs_linux()
186
+ else:
187
+ print(f"[Error] 不支持的操作系统: {system}")
188
+ return False
189
+
190
+ @staticmethod
191
+ def _install_nodejs_windows() -> bool:
192
+ """Windows 上安装 Node.js"""
193
+ print("[Info] Windows 系统需要手动安装 Node.js")
194
+ print("[Info] 请访问: https://nodejs.org/")
195
+ print("[Info] 或使用 winget: winget install OpenJS.NodeJS")
196
+ return False
197
+
198
+ @staticmethod
199
+ def _install_nodejs_macos() -> bool:
200
+ """macOS 上安装 Node.js"""
201
+ if not ToolInstaller.check_tool("brew"):
202
+ print("[Error] 需要先安装 Homebrew")
203
+ print("[Info] 访问: https://brew.sh/")
204
+ return False
205
+
206
+ try:
207
+ print("[Install] 使用 Homebrew 安装 Node.js...")
208
+ result = subprocess.run(
209
+ ["brew", "install", "node"],
210
+ capture_output=True,
211
+ text=True,
212
+ timeout=300
213
+ )
214
+ if result.returncode == 0:
215
+ print("[Done] Node.js 安装完成")
216
+ return True
217
+ else:
218
+ print(f"[Error] 安装失败: {result.stderr}")
219
+ return False
220
+ except Exception as e:
221
+ print(f"[Error] 安装失败: {e}")
222
+ return False
223
+
224
+ @staticmethod
225
+ def _install_nodejs_linux() -> bool:
226
+ """Linux 上安装 Node.js"""
227
+ # 使用 NodeSource 仓库安装最新 LTS 版本
228
+ if ToolInstaller.check_tool("apt"):
229
+ try:
230
+ print("[Install] 添加 NodeSource 仓库...")
231
+ # 下载并执行 NodeSource 安装脚本
232
+ result = subprocess.run(
233
+ "curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -",
234
+ shell=True,
235
+ capture_output=True,
236
+ text=True,
237
+ timeout=120
238
+ )
239
+ if result.returncode != 0:
240
+ print(f"[Error] 添加仓库失败: {result.stderr}")
241
+ return False
242
+
243
+ print("[Install] 安装 Node.js...")
244
+ result = subprocess.run(
245
+ ["sudo", "apt", "install", "-y", "nodejs"],
246
+ capture_output=True,
247
+ text=True,
248
+ timeout=300
249
+ )
250
+ if result.returncode == 0:
251
+ print("[Done] Node.js 安装完成")
252
+ return True
253
+ else:
254
+ print(f"[Error] 安装失败: {result.stderr}")
255
+ return False
256
+ except Exception as e:
257
+ print(f"[Error] 安装失败: {e}")
258
+ return False
259
+
260
+ elif ToolInstaller.check_tool("yum") or ToolInstaller.check_tool("dnf"):
261
+ pkg_manager = "dnf" if ToolInstaller.check_tool("dnf") else "yum"
262
+ try:
263
+ print(f"[Install] 使用 {pkg_manager} 安装 Node.js...")
264
+ result = subprocess.run(
265
+ ["sudo", pkg_manager, "install", "-y", "nodejs", "npm"],
266
+ capture_output=True,
267
+ text=True,
268
+ timeout=300
269
+ )
270
+ if result.returncode == 0:
271
+ print("[Done] Node.js 安装完成")
272
+ return True
273
+ else:
274
+ print(f"[Error] 安装失败: {result.stderr}")
275
+ return False
276
+ except Exception as e:
277
+ print(f"[Error] 安装失败: {e}")
278
+ return False
279
+ else:
280
+ print("[Error] 未检测到支持的包管理器")
281
+ return False
282
+
283
+ @staticmethod
284
+ def install_git() -> bool:
285
+ """安装 Git"""
286
+ if ToolInstaller.check_tool("git"):
287
+ return True
288
+
289
+ print("[Install] Git 未安装,正在安装...")
290
+
291
+ system = platform.system()
292
+
293
+ if system == "Windows":
294
+ return ToolInstaller._install_git_windows()
295
+ elif system == "Darwin":
296
+ return ToolInstaller._install_git_macos()
297
+ elif system == "Linux":
298
+ return ToolInstaller._install_git_linux()
299
+ else:
300
+ print(f"[Error] 不支持的操作系统: {system}")
301
+ return False
302
+
303
+ @staticmethod
304
+ def _install_git_windows() -> bool:
305
+ """Windows 上安装 Git"""
306
+ print("[Info] Windows 系统需要手动安装 Git")
307
+ print("[Info] 请访问: https://git-scm.com/download/win")
308
+ print("[Info] 或使用 winget: winget install Git.Git")
309
+ return False
310
+
311
+ @staticmethod
312
+ def _install_git_macos() -> bool:
313
+ """macOS 上安装 Git"""
314
+ if not ToolInstaller.check_tool("brew"):
315
+ print("[Error] 需要先安装 Homebrew")
316
+ print("[Info] 访问: https://brew.sh/")
317
+ return False
318
+
319
+ try:
320
+ print("[Install] 使用 Homebrew 安装 Git...")
321
+ result = subprocess.run(
322
+ ["brew", "install", "git"],
323
+ capture_output=True,
324
+ text=True,
325
+ timeout=300
326
+ )
327
+ if result.returncode == 0:
328
+ print("[Done] Git 安装完成")
329
+ return True
330
+ else:
331
+ print(f"[Error] 安装失败: {result.stderr}")
332
+ return False
333
+ except Exception as e:
334
+ print(f"[Error] 安装失败: {e}")
335
+ return False
336
+
337
+ @staticmethod
338
+ def _install_git_linux() -> bool:
339
+ """Linux 上安装 Git"""
340
+ if ToolInstaller.check_tool("apt"):
341
+ pkg_manager = "apt"
342
+ install_cmd = ["sudo", "apt", "update", "&&", "sudo", "apt", "install", "-y", "git"]
343
+ elif ToolInstaller.check_tool("yum"):
344
+ pkg_manager = "yum"
345
+ install_cmd = ["sudo", "yum", "install", "-y", "git"]
346
+ elif ToolInstaller.check_tool("dnf"):
347
+ pkg_manager = "dnf"
348
+ install_cmd = ["sudo", "dnf", "install", "-y", "git"]
349
+ else:
350
+ print("[Error] 未检测到支持的包管理器")
351
+ return False
352
+
353
+ try:
354
+ print(f"[Install] 使用 {pkg_manager} 安装 Git...")
355
+ result = subprocess.run(
356
+ " ".join(install_cmd),
357
+ shell=True,
358
+ capture_output=True,
359
+ text=True,
360
+ timeout=300
361
+ )
362
+ if result.returncode == 0:
363
+ print("[Done] Git 安装完成")
364
+ return True
365
+ else:
366
+ print(f"[Error] 安装失败: {result.stderr}")
367
+ return False
368
+ except Exception as e:
369
+ print(f"[Error] 安装失败: {e}")
370
+ return False
371
+
372
+ @classmethod
373
+ def ensure_tool(cls, tool: str) -> bool:
374
+ """确保工具已安装,如果没有则尝试安装"""
375
+ if tool in ["python", "python3"]:
376
+ if cls.check_tool("python") or cls.check_tool("python3"):
377
+ return True
378
+ return cls.install_python()
379
+
380
+ elif tool in ["pip", "pip3"]:
381
+ if cls.check_tool("pip") or cls.check_tool("pip3"):
382
+ return True
383
+ return cls.install_pip()
384
+
385
+ elif tool in ["node", "npm"]:
386
+ if cls.check_tool("node") and cls.check_tool("npm"):
387
+ return True
388
+ return cls.install_nodejs()
389
+
390
+ elif tool == "git":
391
+ if cls.check_tool("git"):
392
+ return True
393
+ return cls.install_git()
394
+
395
+ else:
396
+ print(f"[Error] 未知工具: {tool}")
397
+ return False
@@ -0,0 +1,78 @@
1
+ """验证器 - 验证 module.md"""
2
+ import re
3
+ from pathlib import Path
4
+ from typing import Optional, Dict
5
+
6
+
7
+ class Validator:
8
+ """验证模块的 module.md"""
9
+
10
+ @staticmethod
11
+ def find_module_md(directory: Path) -> Optional[Path]:
12
+ """在目录中查找 module.md"""
13
+ # 直接查找
14
+ module_md = directory / "module.md"
15
+ if module_md.exists():
16
+ return module_md
17
+
18
+ # 递归查找(最多 2 层)
19
+ for md_file in directory.rglob("module.md"):
20
+ if md_file.relative_to(directory).parts.__len__() <= 2:
21
+ return md_file
22
+
23
+ return None
24
+
25
+ @staticmethod
26
+ def parse_module_md(path: Path) -> Optional[Dict]:
27
+ """解析 module.md 的 YAML frontmatter"""
28
+ try:
29
+ content = path.read_text(encoding="utf-8")
30
+
31
+ # 提取 YAML frontmatter (--- ... ---)
32
+ match = re.search(r"^---\s*\n(.*?)\n---", content, re.DOTALL | re.MULTILINE)
33
+ if not match:
34
+ return None
35
+
36
+ yaml_content = match.group(1)
37
+
38
+ # 简单解析 YAML(只解析我们需要的字段)
39
+ data = {}
40
+ for line in yaml_content.split("\n"):
41
+ line = line.strip()
42
+ if not line or line.startswith("#"):
43
+ continue
44
+ if ":" in line:
45
+ key, value = line.split(":", 1)
46
+ key = key.strip()
47
+ value = value.strip().strip('"').strip("'")
48
+ data[key] = value
49
+
50
+ return data
51
+ except Exception:
52
+ return None
53
+
54
+ @classmethod
55
+ def validate_module(cls, directory: Path, expected_name: str) -> tuple[bool, Optional[str], Optional[Dict]]:
56
+ """
57
+ 验证模块
58
+ 返回: (是否有效, 错误信息, module.md 数据)
59
+ """
60
+ # 查找 module.md
61
+ module_md = cls.find_module_md(directory)
62
+ if not module_md:
63
+ return False, "未找到 module.md", None
64
+
65
+ # 解析 module.md
66
+ data = cls.parse_module_md(module_md)
67
+ if not data:
68
+ return False, "无法解析 module.md", None
69
+
70
+ # 验证 name 字段
71
+ actual_name = data.get("name")
72
+ if not actual_name:
73
+ return False, "module.md 缺少 name 字段", None
74
+
75
+ if actual_name != expected_name:
76
+ return False, f"模块名不匹配: 期望 {expected_name}, 实际 {actual_name}", None
77
+
78
+ return True, None, data