@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,142 @@
1
+ """平台检查器 - 检查模块在各平台是否存在"""
2
+ import subprocess
3
+ import json
4
+ from typing import Optional, List, Dict
5
+ from concurrent.futures import ThreadPoolExecutor, as_completed
6
+
7
+
8
+ class PlatformChecker:
9
+ """检查模块在各平台的存在性"""
10
+
11
+ @staticmethod
12
+ def check_pypi(name: str) -> Optional[Dict]:
13
+ """检查 PyPI 是否存在该包"""
14
+ try:
15
+ # 使用 pip index versions
16
+ result = subprocess.run(
17
+ ["pip", "index", "versions", name],
18
+ capture_output=True,
19
+ text=True,
20
+ timeout=10
21
+ )
22
+ if result.returncode == 0 and "Available versions:" in result.stdout:
23
+ # 解析版本
24
+ lines = result.stdout.split("\n")
25
+ for line in lines:
26
+ if "Available versions:" in line:
27
+ versions_str = line.split(":", 1)[1].strip()
28
+ versions = [v.strip() for v in versions_str.split(",")]
29
+ return {
30
+ "platform": "pypi",
31
+ "name": name,
32
+ "versions": versions,
33
+ "latest": versions[0] if versions else None
34
+ }
35
+ except (subprocess.TimeoutExpired, FileNotFoundError):
36
+ pass
37
+ return None
38
+
39
+ @staticmethod
40
+ def check_npm(name: str) -> Optional[Dict]:
41
+ """检查 npm 是否存在该包"""
42
+ try:
43
+ # 获取所有版本
44
+ result = subprocess.run(
45
+ ["npm", "view", name, "versions", "--json"],
46
+ capture_output=True,
47
+ text=True,
48
+ timeout=10,
49
+ shell=True # Windows 兼容性
50
+ )
51
+ if result.returncode == 0:
52
+ try:
53
+ versions_data = json.loads(result.stdout)
54
+ # versions 可能是字符串(单版本)或列表(多版本)
55
+ if isinstance(versions_data, str):
56
+ versions = [versions_data]
57
+ elif isinstance(versions_data, list):
58
+ versions = versions_data
59
+ else:
60
+ versions = []
61
+
62
+ if versions:
63
+ return {
64
+ "platform": "npm",
65
+ "name": name,
66
+ "versions": versions,
67
+ "latest": versions[-1] if versions else None # npm 返回的版本是升序
68
+ }
69
+ except json.JSONDecodeError:
70
+ # 降级到只获取最新版本
71
+ result = subprocess.run(
72
+ ["npm", "view", name, "version"],
73
+ capture_output=True,
74
+ text=True,
75
+ timeout=10,
76
+ shell=True
77
+ )
78
+ if result.returncode == 0:
79
+ version = result.stdout.strip()
80
+ return {
81
+ "platform": "npm",
82
+ "name": name,
83
+ "versions": [version],
84
+ "latest": version
85
+ }
86
+ except (subprocess.TimeoutExpired, FileNotFoundError):
87
+ pass
88
+ return None
89
+
90
+ @staticmethod
91
+ def check_git(name: str) -> Optional[List[Dict]]:
92
+ """检查 GitHub 是否存在相关仓库"""
93
+ try:
94
+ # 搜索 GitHub 仓库
95
+ result = subprocess.run(
96
+ ["curl", "-s", f"https://api.github.com/search/repositories?q={name}+kite"],
97
+ capture_output=True,
98
+ text=True,
99
+ timeout=10
100
+ )
101
+ if result.returncode == 0:
102
+ data = json.loads(result.stdout)
103
+ if data.get("total_count", 0) > 0:
104
+ repos = []
105
+ for item in data.get("items", [])[:5]: # 最多返回 5 个
106
+ repos.append({
107
+ "platform": "git",
108
+ "name": item["name"],
109
+ "full_name": item["full_name"],
110
+ "url": item["clone_url"],
111
+ "description": item.get("description", "")
112
+ })
113
+ return repos
114
+ except (subprocess.TimeoutExpired, FileNotFoundError, json.JSONDecodeError):
115
+ pass
116
+ return None
117
+
118
+ @classmethod
119
+ def check_all(cls, name: str) -> Dict[str, any]:
120
+ """并行检查所有平台"""
121
+ results = {
122
+ "pypi": None,
123
+ "npm": None,
124
+ "git": None
125
+ }
126
+
127
+ with ThreadPoolExecutor(max_workers=3) as executor:
128
+ futures = {
129
+ executor.submit(cls.check_pypi, name): "pypi",
130
+ executor.submit(cls.check_npm, name): "npm",
131
+ executor.submit(cls.check_git, name): "git"
132
+ }
133
+
134
+ for future in as_completed(futures):
135
+ platform = futures[future]
136
+ try:
137
+ result = future.result()
138
+ results[platform] = result
139
+ except Exception:
140
+ pass
141
+
142
+ return results
@@ -0,0 +1,229 @@
1
+ """依赖管理 - 安装 Python/npm/Kite 模块依赖"""
2
+ import subprocess
3
+ import sys
4
+ from pathlib import Path
5
+ from kite_cli.core.tool_installer import ToolInstaller
6
+
7
+
8
+ class DependencyInstaller:
9
+ """依赖安装器"""
10
+
11
+ @staticmethod
12
+ def install_python_deps(module_dir: Path, packages: list) -> bool:
13
+ """安装 Python 依赖到模块内的 .venv"""
14
+ if not packages:
15
+ return True
16
+
17
+ # 确保 Python 和 pip 已安装
18
+ if not ToolInstaller.ensure_tool("python"):
19
+ print(" [Error] Python 未安装且自动安装失败")
20
+ return False
21
+ if not ToolInstaller.ensure_tool("pip"):
22
+ print(" [Error] pip 未安装且自动安装失败")
23
+ return False
24
+
25
+ print(f"[Install] 安装 Python 依赖: {', '.join(packages)}")
26
+
27
+ venv_dir = module_dir / ".venv"
28
+
29
+ try:
30
+ # 创建虚拟环境
31
+ if not venv_dir.exists():
32
+ print(" 创建虚拟环境...")
33
+ result = subprocess.run(
34
+ [sys.executable, "-m", "venv", str(venv_dir)],
35
+ capture_output=True,
36
+ text=True,
37
+ timeout=60
38
+ )
39
+ if result.returncode != 0:
40
+ print(f" [Error] 创建虚拟环境失败: {result.stderr}")
41
+ return False
42
+
43
+ # 确定 pip 路径
44
+ if sys.platform == "win32":
45
+ pip_path = venv_dir / "Scripts" / "pip.exe"
46
+ else:
47
+ pip_path = venv_dir / "bin" / "pip"
48
+
49
+ # 安装依赖
50
+ print(" 安装包...")
51
+ result = subprocess.run(
52
+ [str(pip_path), "install"] + packages,
53
+ capture_output=True,
54
+ text=True,
55
+ timeout=300
56
+ )
57
+
58
+ if result.returncode != 0:
59
+ print(f" [Error] 安装失败: {result.stderr}")
60
+ return False
61
+
62
+ print(" [Done] Python 依赖安装完成")
63
+ return True
64
+
65
+ except Exception as e:
66
+ print(f" [Error] 安装失败: {e}")
67
+ return False
68
+
69
+ @staticmethod
70
+ def install_npm_deps(module_dir: Path, packages: list) -> bool:
71
+ """安装 npm 依赖到模块内的 node_modules"""
72
+ if not packages:
73
+ return True
74
+
75
+ # 确保 npm 已安装
76
+ if not ToolInstaller.ensure_tool("npm"):
77
+ print(" [Error] npm 未安装且自动安装失败")
78
+ return False
79
+
80
+ print(f"[Install] 安装 npm 依赖: {', '.join(packages)}")
81
+
82
+ try:
83
+ # 检查是否有 package.json
84
+ package_json = module_dir / "package.json"
85
+ if not package_json.exists():
86
+ # 创建基础 package.json
87
+ import json
88
+ with open(package_json, "w") as f:
89
+ json.dump({
90
+ "name": module_dir.name,
91
+ "version": "1.0.0",
92
+ "dependencies": {}
93
+ }, f, indent=2)
94
+
95
+ # 安装依赖
96
+ result = subprocess.run(
97
+ ["npm", "install"] + packages,
98
+ cwd=str(module_dir),
99
+ capture_output=True,
100
+ text=True,
101
+ timeout=300
102
+ )
103
+
104
+ if result.returncode != 0:
105
+ print(f" [Error] 安装失败: {result.stderr}")
106
+ return False
107
+
108
+ print(" [Done] npm 依赖安装完成")
109
+ return True
110
+
111
+ except Exception as e:
112
+ print(f" [Error] 安装失败: {e}")
113
+ return False
114
+
115
+ @staticmethod
116
+ def install_git_deps(module_dir: Path, repos: list) -> bool:
117
+ """安装 Git 依赖到模块内的 .git_deps"""
118
+ if not repos:
119
+ return True
120
+
121
+ # 确保 git 已安装
122
+ if not ToolInstaller.ensure_tool("git"):
123
+ print(" [Error] git 未安装且自动安装失败")
124
+ return False
125
+
126
+ print(f"[Install] 安装 Git 依赖: {', '.join(repos)}")
127
+
128
+ git_deps_dir = module_dir / ".git_deps"
129
+ git_deps_dir.mkdir(exist_ok=True)
130
+
131
+ try:
132
+ for repo_url in repos:
133
+ # 提取仓库名
134
+ repo_name = repo_url.rstrip('/').split('/')[-1]
135
+ if repo_name.endswith('.git'):
136
+ repo_name = repo_name[:-4]
137
+
138
+ target_dir = git_deps_dir / repo_name
139
+
140
+ # 如果已存在,跳过
141
+ if target_dir.exists():
142
+ print(f" [Skip] {repo_name} 已存在")
143
+ continue
144
+
145
+ print(f" 克隆 {repo_name}...")
146
+ result = subprocess.run(
147
+ ["git", "clone", repo_url, str(target_dir)],
148
+ capture_output=True,
149
+ text=True,
150
+ timeout=120
151
+ )
152
+
153
+ if result.returncode != 0:
154
+ print(f" [Error] 克隆失败: {result.stderr}")
155
+ return False
156
+
157
+ print(" [Done] Git 依赖安装完成")
158
+ return True
159
+
160
+ except FileNotFoundError:
161
+ print(" [Error] git 命令未找到,请先安装 Git")
162
+ return False
163
+ except Exception as e:
164
+ print(f" [Error] 安装失败: {e}")
165
+ return False
166
+
167
+ @staticmethod
168
+ def install_kite_deps(modules: list, location: str) -> bool:
169
+ """递归安装 Kite 模块依赖"""
170
+ if not modules:
171
+ return True
172
+
173
+ print(f"[Install] 安装 Kite 模块依赖: {', '.join(modules)}")
174
+
175
+ # 这里需要递归调用 kite install
176
+ # 为了避免循环导入,使用 subprocess
177
+ for module in modules:
178
+ print(f" 安装 {module}...")
179
+ try:
180
+ result = subprocess.run(
181
+ [sys.executable, "-m", "kite_cli", "install", module, "-l", location, "-y"],
182
+ capture_output=True,
183
+ text=True,
184
+ timeout=300
185
+ )
186
+ if result.returncode != 0:
187
+ print(f" [Error] 安装 {module} 失败")
188
+ return False
189
+ except Exception as e:
190
+ print(f" [Error] 安装 {module} 失败: {e}")
191
+ return False
192
+
193
+ print(" [Done] Kite 模块依赖安装完成")
194
+ return True
195
+
196
+ @classmethod
197
+ def install_all_deps(cls, module_dir: Path, module_data: dict, location: str, skip_deps: bool = False) -> bool:
198
+ """安装所有依赖"""
199
+ if skip_deps:
200
+ print("[Warning] 跳过依赖安装 (--no-deps)")
201
+ return True
202
+
203
+ # 从 module.md 读取依赖
204
+ dependencies = module_data.get("dependencies", {})
205
+ if not dependencies:
206
+ print("[Info] 无依赖需要安装")
207
+ return True
208
+
209
+ # Python 依赖
210
+ python_deps = dependencies.get("python", [])
211
+ if python_deps and not cls.install_python_deps(module_dir, python_deps):
212
+ return False
213
+
214
+ # npm 依赖
215
+ npm_deps = dependencies.get("npm", [])
216
+ if npm_deps and not cls.install_npm_deps(module_dir, npm_deps):
217
+ return False
218
+
219
+ # Git 依赖
220
+ git_deps = dependencies.get("git", [])
221
+ if git_deps and not cls.install_git_deps(module_dir, git_deps):
222
+ return False
223
+
224
+ # Kite 模块依赖
225
+ kite_deps = dependencies.get("kite", [])
226
+ if kite_deps and not cls.install_kite_deps(kite_deps, location):
227
+ return False
228
+
229
+ return True
@@ -0,0 +1,209 @@
1
+ """下载器 - 从各平台下载模块(改进版,带详细错误提示)"""
2
+ import subprocess
3
+ import tempfile
4
+ import shutil
5
+ import zipfile
6
+ from pathlib import Path
7
+ from typing import Optional, Tuple
8
+ from kite_cli.core.tool_installer import ToolInstaller
9
+
10
+
11
+ class DownloadError(Exception):
12
+ """下载错误"""
13
+ pass
14
+
15
+
16
+ class Downloader:
17
+ """从各平台下载模块"""
18
+
19
+ @staticmethod
20
+ def download_pypi(name: str, dest: Path, version: str = None) -> Tuple[Optional[Path], Optional[str]]:
21
+ """
22
+ 从 PyPI 下载包
23
+ Args:
24
+ name: 包名
25
+ dest: 目标目录
26
+ version: 版本号(可选),如 "1.2.0"
27
+ 返回: (下载路径, 错误信息)
28
+ """
29
+ # 确保 pip 已安装
30
+ if not ToolInstaller.ensure_tool("pip"):
31
+ return None, "pip 未安装且自动安装失败,请手动安装 Python 和 pip"
32
+
33
+ # 构建包名(带版本)
34
+ package_spec = f"{name}=={version}" if version else name
35
+
36
+ try:
37
+ dest.mkdir(parents=True, exist_ok=True)
38
+ result = subprocess.run(
39
+ ["pip", "download", package_spec, "--dest", str(dest), "--no-deps"],
40
+ capture_output=True,
41
+ text=True,
42
+ timeout=60
43
+ )
44
+
45
+ if result.returncode != 0:
46
+ # pip 命令执行失败
47
+ error_msg = result.stderr.strip() if result.stderr else result.stdout.strip()
48
+ if "Could not find" in error_msg or "No matching distribution" in error_msg:
49
+ return None, f"PyPI 上未找到包 '{name}'"
50
+ elif "Network" in error_msg or "timeout" in error_msg.lower():
51
+ return None, f"网络错误: 无法连接到 PyPI"
52
+ else:
53
+ return None, f"pip 下载失败: {error_msg[:200]}"
54
+
55
+ # 查找下载的文件
56
+ files = list(dest.glob("*"))
57
+ if not files:
58
+ return None, "下载成功但未找到文件"
59
+
60
+ # 解压(.whl 或 .tar.gz)
61
+ downloaded_file = files[0]
62
+ extract_dir = dest / "extracted"
63
+ extract_dir.mkdir(exist_ok=True)
64
+
65
+ try:
66
+ # .whl 文件是 zip 格式
67
+ if downloaded_file.suffix == '.whl':
68
+ with zipfile.ZipFile(downloaded_file, 'r') as zip_ref:
69
+ zip_ref.extractall(extract_dir)
70
+ else:
71
+ shutil.unpack_archive(downloaded_file, extract_dir)
72
+ return extract_dir, None
73
+ except Exception as e:
74
+ return None, f"解压失败: {str(e)}"
75
+
76
+ except FileNotFoundError:
77
+ return None, "pip 命令未找到,请先安装 Python 和 pip"
78
+ except subprocess.TimeoutExpired:
79
+ return None, "下载超时(60秒),请检查网络连接"
80
+ except Exception as e:
81
+ return None, f"未知错误: {str(e)}"
82
+
83
+ @staticmethod
84
+ def download_npm(name: str, dest: Path, version: str = None) -> Tuple[Optional[Path], Optional[str]]:
85
+ """
86
+ 从 npm 下载包
87
+ Args:
88
+ name: 包名
89
+ dest: 目标目录
90
+ version: 版本号(可选),如 "1.2.0"
91
+ 返回: (下载路径, 错误信息)
92
+ """
93
+ # 确保 npm 已安装
94
+ if not ToolInstaller.ensure_tool("npm"):
95
+ return None, "npm 未安装且自动安装失败,请手动安装 Node.js 和 npm"
96
+
97
+ # 构建包名(带版本)
98
+ package_spec = f"{name}@{version}" if version else name
99
+
100
+ try:
101
+ dest.mkdir(parents=True, exist_ok=True)
102
+ result = subprocess.run(
103
+ ["npm", "pack", package_spec, "--pack-destination", str(dest)],
104
+ capture_output=True,
105
+ text=True,
106
+ timeout=60
107
+ )
108
+
109
+ if result.returncode != 0:
110
+ error_msg = result.stderr.strip() if result.stderr else result.stdout.strip()
111
+ if "404" in error_msg or "Not Found" in error_msg:
112
+ return None, f"npm 上未找到包 '{name}'"
113
+ elif "network" in error_msg.lower() or "ETIMEDOUT" in error_msg:
114
+ return None, "网络错误: 无法连接到 npm registry"
115
+ else:
116
+ return None, f"npm 下载失败: {error_msg[:200]}"
117
+
118
+ # 查找 .tgz 文件
119
+ tgz_files = list(dest.glob("*.tgz"))
120
+ if not tgz_files:
121
+ return None, "下载成功但未找到 .tgz 文件"
122
+
123
+ tgz_file = tgz_files[0]
124
+ extract_dir = dest / "extracted"
125
+ extract_dir.mkdir(exist_ok=True)
126
+
127
+ try:
128
+ shutil.unpack_archive(tgz_file, extract_dir)
129
+ # npm pack 会创建 package/ 子目录
130
+ package_dir = extract_dir / "package"
131
+ if package_dir.exists():
132
+ return package_dir, None
133
+ return extract_dir, None
134
+ except Exception as e:
135
+ return None, f"解压失败: {str(e)}"
136
+
137
+ except FileNotFoundError:
138
+ return None, "npm 命令未找到,请先安装 Node.js 和 npm"
139
+ except subprocess.TimeoutExpired:
140
+ return None, "下载超时(60秒),请检查网络连接"
141
+ except Exception as e:
142
+ return None, f"未知错误: {str(e)}"
143
+
144
+ @staticmethod
145
+ def download_git(url: str, dest: Path) -> Tuple[Optional[Path], Optional[str]]:
146
+ """
147
+ 从 Git 克隆仓库
148
+ 返回: (下载路径, 错误信息)
149
+ """
150
+ # 确保 git 已安装
151
+ if not ToolInstaller.ensure_tool("git"):
152
+ return None, "git 未安装且自动安装失败,请手动安装 Git"
153
+
154
+ try:
155
+ dest.mkdir(parents=True, exist_ok=True)
156
+ clone_dir = dest / "repo"
157
+ result = subprocess.run(
158
+ ["git", "clone", url, str(clone_dir)],
159
+ capture_output=True,
160
+ text=True,
161
+ timeout=120
162
+ )
163
+
164
+ if result.returncode != 0:
165
+ error_msg = result.stderr.strip() if result.stderr else result.stdout.strip()
166
+ if "not found" in error_msg.lower() or "does not exist" in error_msg.lower():
167
+ return None, f"Git 仓库不存在: {url}"
168
+ elif "Authentication failed" in error_msg or "Permission denied" in error_msg:
169
+ return None, "认证失败: 仓库可能是私有的或需要登录"
170
+ elif "network" in error_msg.lower() or "timeout" in error_msg.lower():
171
+ return None, "网络错误: 无法连接到 Git 服务器"
172
+ else:
173
+ return None, f"git clone 失败: {error_msg[:200]}"
174
+
175
+ if not clone_dir.exists():
176
+ return None, "克隆成功但目录不存在"
177
+
178
+ return clone_dir, None
179
+
180
+ except FileNotFoundError:
181
+ return None, "git 命令未找到,请先安装 Git"
182
+ except subprocess.TimeoutExpired:
183
+ return None, "克隆超时(120秒),仓库可能太大或网络太慢"
184
+ except Exception as e:
185
+ return None, f"未知错误: {str(e)}"
186
+
187
+ @staticmethod
188
+ def download_local(path: str, dest: Path) -> Tuple[Optional[Path], Optional[str]]:
189
+ """
190
+ 从本地路径复制
191
+ 返回: (下载路径, 错误信息)
192
+ """
193
+ try:
194
+ src = Path(path).resolve()
195
+ if not src.exists():
196
+ return None, f"本地路径不存在: {path}"
197
+
198
+ if not src.is_dir():
199
+ return None, f"路径不是目录: {path}"
200
+
201
+ dest.mkdir(parents=True, exist_ok=True)
202
+ copy_dir = dest / "local"
203
+ shutil.copytree(src, copy_dir)
204
+ return copy_dir, None
205
+
206
+ except PermissionError:
207
+ return None, f"权限不足: 无法读取 {path}"
208
+ except Exception as e:
209
+ return None, f"复制失败: {str(e)}"
@@ -0,0 +1,40 @@
1
+ """安装信息记录"""
2
+ import json
3
+ from datetime import datetime
4
+ from pathlib import Path
5
+ from kite_cli import __version__
6
+
7
+
8
+ def record_install_info(module_dir: Path, source_info: dict, module_data: dict, location: str):
9
+ """记录安装信息到 .kite_install.json"""
10
+ install_info = {
11
+ "name": module_data.get("name"),
12
+ "version": module_data.get("version", "unknown"),
13
+ "source": source_info,
14
+ "installed_at": datetime.utcnow().isoformat() + "Z",
15
+ "installed_by": f"kite-cli@{__version__}",
16
+ "location": location,
17
+ "dependencies": module_data.get("dependencies", {})
18
+ }
19
+
20
+ install_info_path = module_dir / ".kite_install.json"
21
+ try:
22
+ with open(install_info_path, "w", encoding="utf-8") as f:
23
+ json.dump(install_info, f, indent=2, ensure_ascii=False)
24
+ return True
25
+ except Exception as e:
26
+ print(f"[Warning] 记录安装信息失败: {e}")
27
+ return False
28
+
29
+
30
+ def read_install_info(module_dir: Path) -> dict:
31
+ """读取安装信息"""
32
+ install_info_path = module_dir / ".kite_install.json"
33
+ if not install_info_path.exists():
34
+ return None
35
+
36
+ try:
37
+ with open(install_info_path, encoding="utf-8") as f:
38
+ return json.load(f)
39
+ except Exception:
40
+ return None