@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,461 @@
1
+ """
2
+ 依赖扫描工具
3
+
4
+ 在开发环境执行,扫描所有模块的依赖库,生成 dependencies_lock.json
5
+
6
+ 用法:
7
+ python scripts/scan_dependencies.py
8
+ """
9
+
10
+ import ast
11
+ import json
12
+ import os
13
+ import subprocess
14
+ import sys
15
+ from datetime import datetime, timezone
16
+ from pathlib import Path
17
+ from typing import Dict, List, Set
18
+
19
+
20
+ def get_project_root() -> Path:
21
+ """获取项目根目录"""
22
+ return Path(__file__).parent.parent
23
+
24
+
25
+ def get_python_version() -> str:
26
+ """获取当前 Python 版本"""
27
+ v = sys.version_info
28
+ return f"{v.major}.{v.minor}.{v.micro}"
29
+
30
+
31
+ def scan_imports_in_file(file_path: Path) -> Set[str]:
32
+ """扫描单个 Python 文件的 import 语句"""
33
+ imports = set()
34
+
35
+ try:
36
+ with open(file_path, "r", encoding="utf-8") as f:
37
+ tree = ast.parse(f.read(), filename=str(file_path))
38
+
39
+ for node in ast.walk(tree):
40
+ if isinstance(node, ast.Import):
41
+ for alias in node.names:
42
+ # import xxx
43
+ imports.add(alias.name.split('.')[0])
44
+ elif isinstance(node, ast.ImportFrom):
45
+ # from xxx import yyy
46
+ if node.module:
47
+ imports.add(node.module.split('.')[0])
48
+
49
+ except Exception as e:
50
+ print(f"[警告] 解析文件失败: {file_path} - {e}")
51
+
52
+ return imports
53
+
54
+
55
+ def scan_module_imports(module_path: Path) -> Set[str]:
56
+ """扫描模块目录下所有 Python 文件的 import"""
57
+ all_imports = set()
58
+
59
+ # 排除的目录(不扫描这些目录中的依赖)
60
+ exclude_dirs = {'__pycache__', 'samples', 'vendor', 'tests', 'test', '.dev'}
61
+
62
+ for py_file in module_path.rglob("*.py"):
63
+ # 跳过排除的目录
64
+ if any(excluded in py_file.parts for excluded in exclude_dirs):
65
+ continue
66
+
67
+ imports = scan_imports_in_file(py_file)
68
+ all_imports.update(imports)
69
+
70
+ return all_imports
71
+
72
+
73
+ def is_stdlib_module(module_name: str) -> bool:
74
+ """判断是否是标准库模块"""
75
+ stdlib_modules = {
76
+ '__future__', 'abc', 'argparse', 'asyncio', 'atexit', 'base64', 'builtins',
77
+ 'calendar', 'collections', 'concurrent', 'contextlib', 'copy', 'ctypes',
78
+ 'dataclasses', 'datetime', 'enum', 'fcntl', 'fnmatch', 'functools', 'glob', 'gzip',
79
+ 'hashlib', 'hmac', 'http', 'importlib', 'inspect', 'io', 'json', 'locale',
80
+ 'logging', 'msvcrt', 'ntpath', 'numbers', 'os', 'pathlib', 'platform',
81
+ 'queue', 'random', 're', 'secrets', 'shutil', 'signal', 'socket',
82
+ 'sqlite3', 'ssl', 'statistics', 'string', 'struct', 'subprocess',
83
+ 'sys', 'tempfile', 'threading', 'time', 'traceback', 'types', 'typing',
84
+ 'typing_extensions', 'urllib', 'uuid', 'wave', 'wsgiref', 'zipfile',
85
+ 'zlib'
86
+ }
87
+
88
+ return module_name in stdlib_modules
89
+
90
+
91
+ # import 名称到 package 名称的映射表(仅包含不一致的情况)
92
+ IMPORT_TO_PACKAGE = {
93
+ # 配置和数据格式
94
+ 'yaml': 'pyyaml',
95
+ 'dotenv': 'python-dotenv',
96
+ 'json5': 'json5',
97
+
98
+ # 图像处理
99
+ 'cv2': 'opencv-python',
100
+ 'cv2_headless': 'opencv-python-headless',
101
+ 'PIL': 'pillow',
102
+ 'skimage': 'scikit-image',
103
+
104
+ # 机器学习和数据科学
105
+ 'sklearn': 'scikit-learn',
106
+
107
+ # Web 开发
108
+ 'bs4': 'beautifulsoup4',
109
+ 'flask_cors': 'flask-cors',
110
+ 'flask_restful': 'flask-restful',
111
+ 'flask_sqlalchemy': 'flask-sqlalchemy',
112
+ 'flask_login': 'flask-login',
113
+ 'flask_migrate': 'flask-migrate',
114
+ 'flask_wtf': 'flask-wtf',
115
+ 'django_rest_framework': 'djangorestframework',
116
+ 'rest_framework': 'djangorestframework',
117
+
118
+ # 网络和 WebSocket
119
+ 'websocket': 'websocket-client', # 单数版本
120
+ # 'websockets' 包名和导入名一致,不需要映射
121
+
122
+ # 日期时间
123
+ 'dateutil': 'python-dateutil',
124
+
125
+ # 加密和安全
126
+ 'OpenSSL': 'pyopenssl',
127
+ 'nacl': 'pynacl',
128
+ 'jwt': 'pyjwt',
129
+ 'Crypto': 'pycryptodome',
130
+ 'Cryptodome': 'pycryptodomex',
131
+
132
+ # 文件和文档处理
133
+ 'magic': 'python-magic',
134
+ 'docx': 'python-docx',
135
+ 'pptx': 'python-pptx',
136
+ 'slugify': 'python-slugify',
137
+
138
+ # 数据库
139
+ 'MySQLdb': 'mysqlclient',
140
+ 'psycopg2': 'psycopg2-binary',
141
+ 'bson': 'pymongo',
142
+
143
+ # 硬件和系统
144
+ 'serial': 'pyserial',
145
+ 'usb': 'pyusb',
146
+ 'gi': 'pygobject',
147
+ 'win32com': 'pywin32',
148
+ 'win32api': 'pywin32',
149
+ 'win32con': 'pywin32',
150
+ 'win32file': 'pywin32',
151
+ 'win32event': 'pywin32',
152
+ 'win32process': 'pywin32',
153
+ 'win32security': 'pywin32',
154
+ 'win32service': 'pywin32',
155
+ 'pywintypes': 'pywin32',
156
+ 'pythoncom': 'pywin32',
157
+
158
+ # GUI
159
+ 'wx': 'wxpython',
160
+ 'tkinter': 'tk',
161
+ 'PyQt5': 'pyqt5',
162
+ 'PyQt6': 'pyqt6',
163
+ 'PySide2': 'pyside2',
164
+ 'PySide6': 'pyside6',
165
+
166
+ # 网络和协议
167
+ 'dns': 'dnspython',
168
+ 'google': 'google-api-python-client',
169
+ 'googleapiclient': 'google-api-python-client',
170
+
171
+ # 日志和监控
172
+ 'sentry_sdk': 'sentry-sdk',
173
+
174
+ # 测试和开发工具
175
+ 'pytest_cov': 'pytest-cov',
176
+ 'pytest_django': 'pytest-django',
177
+ 'pytest_mock': 'pytest-mock',
178
+
179
+ # 异步和任务队列
180
+ 'aiomysql': 'aiomysql',
181
+ 'aiopg': 'aiopg',
182
+
183
+ # 其他常用
184
+ 'attr': 'attrs',
185
+ 'cattr': 'cattrs',
186
+ 'msgpack': 'msgpack-python',
187
+ 'ruamel': 'ruamel.yaml',
188
+ }
189
+
190
+
191
+ def get_installed_version(import_name: str) -> str:
192
+ """获取已安装包的版本"""
193
+ # 先尝试映射
194
+ package_name = IMPORT_TO_PACKAGE.get(import_name, import_name)
195
+
196
+ try:
197
+ import importlib.metadata
198
+ return importlib.metadata.version(package_name)
199
+ except:
200
+ return "unknown"
201
+
202
+
203
+ def is_project_module(module_name: str) -> bool:
204
+ """判断是否是项目内部模块"""
205
+ project_modules = {
206
+ # 核心模块
207
+ 'core', 'kernel', 'launcher', 'extensions', 'kite_cli',
208
+ # 子模块
209
+ 'config', 'storage', 'tools', 'conversation', 'task', 'bluetooth',
210
+ 'asr', 'llm', 'tts', 'vad', 'webhook', 'routes', 'server',
211
+ 'registry', 'event_hub', 'dedup', 'router', 'rpc_router', 'registry_store',
212
+ 'relay', 'pairing', 'entry', 'logging_setup', 'module_scanner', 'process_manager',
213
+ 'types', 'utils', 'models', 'exceptions', 'context', 'log', 'store',
214
+ 'presenter', 'userPresenter', 'configPresenter', 'config_loader',
215
+ 'console_auth', 'proxy_config', 'monitoring_service', 'metrics_store',
216
+ 'llm_server', 'sliding_window', 'standalone_reader', 'ws_logger',
217
+ 'mermaid', 'version', 'vendor', 'scripts', 'evol'
218
+ }
219
+
220
+ return module_name in project_modules
221
+
222
+
223
+ def scan_all_modules() -> Dict[str, Set[str]]:
224
+ """扫描所有模块的依赖"""
225
+ project_root = get_project_root()
226
+
227
+ modules_to_scan = {
228
+ "core": project_root / "core",
229
+ "kernel": project_root / "kernel",
230
+ "launcher": project_root / "launcher",
231
+ "extensions": project_root / "extensions",
232
+ "kite_cli": project_root / "kite_cli",
233
+ }
234
+
235
+ module_imports = {}
236
+
237
+ for module_name, module_path in modules_to_scan.items():
238
+ if not module_path.exists():
239
+ continue
240
+
241
+ print(f"[扫描] {module_name}...")
242
+ imports = scan_module_imports(module_path)
243
+
244
+ # 过滤掉标准库和项目内部模块
245
+ third_party = {
246
+ imp for imp in imports
247
+ if not is_stdlib_module(imp)
248
+ and not is_project_module(imp)
249
+ }
250
+
251
+ if third_party:
252
+ module_imports[module_name] = third_party
253
+ print(f" 发现 {len(third_party)} 个第三方依赖")
254
+
255
+ return module_imports
256
+
257
+
258
+ def analyze_skipped_package(import_name: str, module_imports: Dict[str, Set[str]]) -> Dict:
259
+ """分析被跳过的包的使用情况"""
260
+ project_root = get_project_root()
261
+
262
+ # 找出哪些模块使用了这个包
263
+ used_by_modules = [
264
+ module_name
265
+ for module_name, imports in module_imports.items()
266
+ if import_name in imports
267
+ ]
268
+
269
+ # 搜索具体的使用位置
270
+ usage_locations = []
271
+ for module_name in used_by_modules:
272
+ module_path = project_root / module_name
273
+ if not module_path.exists():
274
+ continue
275
+
276
+ # 搜索 import 语句
277
+ for py_file in module_path.rglob("*.py"):
278
+ # 跳过排除的目录
279
+ exclude_dirs = {'__pycache__', 'samples', 'vendor', 'tests', 'test', '.dev'}
280
+ if any(excluded in py_file.parts for excluded in exclude_dirs):
281
+ continue
282
+
283
+ try:
284
+ with open(py_file, "r", encoding="utf-8") as f:
285
+ content = f.read()
286
+
287
+ # 检查是否包含该包的 import
288
+ if f"import {import_name}" in content or f"from {import_name}" in content:
289
+ # 判断是否是条件导入
290
+ is_conditional = False
291
+ lines = content.split('\n')
292
+ for i, line in enumerate(lines):
293
+ if f"import {import_name}" in line or f"from {import_name}" in line:
294
+ # 检查前几行是否有 try
295
+ for j in range(max(0, i-5), i):
296
+ if 'try:' in lines[j]:
297
+ is_conditional = True
298
+ break
299
+ break
300
+
301
+ # 获取相对路径
302
+ rel_path = py_file.relative_to(project_root)
303
+ usage_locations.append({
304
+ "file": str(rel_path),
305
+ "conditional": is_conditional
306
+ })
307
+ except:
308
+ pass
309
+
310
+ # 检查是否有包名映射
311
+ package_name = IMPORT_TO_PACKAGE.get(import_name, import_name)
312
+ has_mapping = package_name != import_name
313
+
314
+ return {
315
+ "import_name": import_name,
316
+ "package_name": package_name,
317
+ "has_mapping": has_mapping,
318
+ "used_by_modules": used_by_modules,
319
+ "usage_locations": usage_locations,
320
+ "is_conditional": any(loc["conditional"] for loc in usage_locations) if usage_locations else False
321
+ }
322
+
323
+
324
+ def build_dependency_lock(module_imports: Dict[str, Set[str]]) -> tuple[Dict, List[Dict]]:
325
+ """构建依赖锁定文件,返回 (lock_data, skipped_packages_analysis)"""
326
+
327
+ # 收集所有第三方包
328
+ all_packages = set()
329
+ for imports in module_imports.values():
330
+ all_packages.update(imports)
331
+
332
+ # 获取每个包的版本和使用者
333
+ dependencies = {}
334
+ skipped_packages = []
335
+
336
+ for import_name in sorted(all_packages):
337
+ version = get_installed_version(import_name)
338
+
339
+ # 收集未安装的包信息
340
+ if version == "unknown":
341
+ print(f"[警告] 跳过未安装的包: {import_name}")
342
+
343
+ # 分析这个包的使用情况
344
+ analysis = analyze_skipped_package(import_name, module_imports)
345
+ skipped_packages.append(analysis)
346
+ continue
347
+
348
+ # 获取真实的 package 名称(用于 pip install)
349
+ package_name = IMPORT_TO_PACKAGE.get(import_name, import_name)
350
+
351
+ # 找出哪些模块使用了这个包
352
+ used_by = [
353
+ module_name
354
+ for module_name, imports in module_imports.items()
355
+ if import_name in imports
356
+ ]
357
+
358
+ dependencies[package_name] = {
359
+ "version": version,
360
+ "used_by": used_by
361
+ }
362
+
363
+ print(f"[依赖] {package_name}=={version} (used by: {', '.join(used_by)})")
364
+
365
+ lock_data = {
366
+ "scan_time": datetime.now(timezone.utc).isoformat(),
367
+ "python_version": get_python_version(),
368
+ "dependencies": dependencies
369
+ }
370
+
371
+ return lock_data, skipped_packages
372
+
373
+
374
+ def main():
375
+ print("=" * 60)
376
+ print(" Kite 依赖扫描工具")
377
+ print("=" * 60)
378
+ print()
379
+
380
+ # 1. 扫描所有模块
381
+ print("[步骤 1] 扫描模块依赖...")
382
+ module_imports = scan_all_modules()
383
+ print()
384
+
385
+ # 2. 构建依赖锁定
386
+ print("[步骤 2] 构建依赖锁定...")
387
+ lock_data, skipped_packages = build_dependency_lock(module_imports)
388
+ print()
389
+
390
+ # 3. 保存到文件
391
+ output_file = get_project_root() / "dependencies_lock.json"
392
+ with open(output_file, "w", encoding="utf-8") as f:
393
+ json.dump(lock_data, f, indent=2, ensure_ascii=False)
394
+
395
+ print(f"[完成] 依赖锁定文件已生成: {output_file}")
396
+ print(f"[统计] 共 {len(lock_data['dependencies'])} 个第三方依赖")
397
+ print()
398
+
399
+ # 4. 同步更新 python_version.json
400
+ version_file = get_project_root() / "python_version.json"
401
+ version_data = {
402
+ "version": get_python_version(),
403
+ "note": "此文件在开发环境打包时生成,记录开发环境的 Python 版本。生产环境必须使用相同版本。"
404
+ }
405
+
406
+ with open(version_file, "w", encoding="utf-8") as f:
407
+ json.dump(version_data, f, indent=2, ensure_ascii=False)
408
+
409
+ print(f"[完成] Python 版本文件已更新: {version_file}")
410
+ print(f"[版本] Python {get_python_version()}")
411
+ print()
412
+
413
+ # 5. 输出跳过包的详细分析
414
+ if skipped_packages:
415
+ print("=" * 60)
416
+ print(" 未安装包分析报告")
417
+ print("=" * 60)
418
+ print()
419
+ print(f"共发现 {len(skipped_packages)} 个未安装的包,详细信息如下:")
420
+ print()
421
+
422
+ for pkg in skipped_packages:
423
+ print(f"包名: {pkg['import_name']}")
424
+ if pkg['has_mapping']:
425
+ print(f" → 映射到: {pkg['package_name']}")
426
+ print(f" 使用模块: {', '.join(pkg['used_by_modules'])}")
427
+ print(f" 导入类型: {'条件导入 (try-except)' if pkg['is_conditional'] else '直接导入'}")
428
+
429
+ if pkg['usage_locations']:
430
+ print(f" 使用位置:")
431
+ for loc in pkg['usage_locations'][:3]: # 最多显示 3 个位置
432
+ conditional_mark = " [条件]" if loc['conditional'] else ""
433
+ print(f" - {loc['file']}{conditional_mark}")
434
+ if len(pkg['usage_locations']) > 3:
435
+ print(f" ... 还有 {len(pkg['usage_locations']) - 3} 个位置")
436
+ else:
437
+ print(f" 使用位置: 未找到(可能已被排除)")
438
+
439
+ # 给出建议
440
+ if pkg['is_conditional']:
441
+ print(f" 建议: ✅ 可选依赖,跳过即可")
442
+ elif not pkg['usage_locations']:
443
+ print(f" 建议: ✅ 已被排除(samples/vendor),跳过即可")
444
+ elif not pkg['has_mapping']:
445
+ print(f" 建议: ⚠️ 检查是否需要添加包名映射")
446
+ else:
447
+ print(f" 建议: ⚠️ 检查是否需要安装该包")
448
+
449
+ print()
450
+
451
+ print("=" * 60)
452
+ print()
453
+ print("如果有需要处理的包,请:")
454
+ print(" 1. 检查是否需要添加到 IMPORT_TO_PACKAGE 映射表")
455
+ print(" 2. 检查是否需要安装该包")
456
+ print(" 3. 检查是否需要标记为可选依赖")
457
+ print()
458
+
459
+
460
+ if __name__ == "__main__":
461
+ main()
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Kite Python 环境准备脚本(版本锁定)
5
+ *
6
+ * 在 npm install 后自动执行,负责:
7
+ * 1. 读取 python_version.json 获取要求的 Python 版本
8
+ * 2. 检测系统是否有该精确版本的 Python
9
+ * 3. 如果没有,下载并安装该版本到 ~/.kite/python/(仅 Windows)
10
+ *
11
+ * 注意:不创建虚拟环境,不安装依赖
12
+ * 这些由 Python 层的 env_checker.py 负责
13
+ */
14
+
15
+ const { execSync } = require('child_process');
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const os = require('os');
19
+
20
+ // 颜色输出
21
+ const colors = {
22
+ reset: '\x1b[0m',
23
+ green: '\x1b[32m',
24
+ yellow: '\x1b[33m',
25
+ red: '\x1b[31m',
26
+ cyan: '\x1b[36m'
27
+ };
28
+
29
+ function log(msg, color = 'reset') {
30
+ console.log(`${colors[color]}[Kite Setup]${colors.reset} ${msg}`);
31
+ }
32
+
33
+ function error(msg) {
34
+ console.error(`${colors.red}[Kite Setup Error]${colors.reset} ${msg}`);
35
+ }
36
+
37
+ // 获取 KITE_DATA 路径
38
+ function getKiteDataPath() {
39
+ return path.join(os.homedir(), '.kite');
40
+ }
41
+
42
+ // 获取 Python 安装路径
43
+ function getPythonInstallPath() {
44
+ return path.join(getKiteDataPath(), 'python');
45
+ }
46
+
47
+ // 读取要求的 Python 版本
48
+ function getRequiredPythonVersion() {
49
+ const versionFile = path.join(__dirname, '..', 'python_version.json');
50
+
51
+ if (!fs.existsSync(versionFile)) {
52
+ error('python_version.json 不存在');
53
+ return null;
54
+ }
55
+
56
+ try {
57
+ const data = JSON.parse(fs.readFileSync(versionFile, 'utf-8'));
58
+ return data.version;
59
+ } catch (e) {
60
+ error(`读取 python_version.json 失败: ${e.message}`);
61
+ return null;
62
+ }
63
+ }
64
+
65
+ // 检测系统 Python(精确版本匹配)
66
+ function detectSystemPython(requiredVersion) {
67
+ const pythonCommands = ['python3', 'python'];
68
+
69
+ for (const cmd of pythonCommands) {
70
+ try {
71
+ const version = execSync(`${cmd} --version`, {
72
+ encoding: 'utf8',
73
+ stdio: ['pipe', 'pipe', 'ignore']
74
+ }).trim();
75
+
76
+ // 解析版本号
77
+ const match = version.match(/Python (\d+\.\d+\.\d+)/);
78
+ if (match) {
79
+ const installedVersion = match[1];
80
+
81
+ if (installedVersion === requiredVersion) {
82
+ log(`检测到系统 Python: ${version}`, 'green');
83
+ return cmd;
84
+ } else {
85
+ log(`系统 Python 版本不匹配: ${installedVersion} (需要 ${requiredVersion})`, 'yellow');
86
+ }
87
+ }
88
+ } catch (e) {
89
+ // 命令不存在,继续尝试下一个
90
+ }
91
+ }
92
+
93
+ return null;
94
+ }
95
+
96
+ // 下载 Python(精确版本)
97
+ async function downloadPython(requiredVersion) {
98
+ log(`系统未检测到 Python ${requiredVersion}`, 'yellow');
99
+ log('正在下载 Python embeddable 版本...', 'cyan');
100
+
101
+ const arch = process.arch === 'x64' ? 'amd64' : 'win32';
102
+ const filename = `python-${requiredVersion}-embed-${arch}.zip`;
103
+ const url = `https://www.python.org/ftp/python/${requiredVersion}/${filename}`;
104
+
105
+ const installPath = getPythonInstallPath();
106
+
107
+ // 如果已经安装过,跳过
108
+ const pythonExe = path.join(installPath, 'python.exe');
109
+ if (fs.existsSync(pythonExe)) {
110
+ log('Python 已安装,跳过下载', 'green');
111
+ return pythonExe;
112
+ }
113
+
114
+ const zipPath = path.join(os.tmpdir(), filename);
115
+
116
+ // 下载
117
+ log(`下载地址: ${url}`, 'cyan');
118
+ log('这可能需要几分钟...', 'cyan');
119
+
120
+ try {
121
+ // 使用 PowerShell 下载
122
+ execSync(`powershell -Command "Invoke-WebRequest -Uri '${url}' -OutFile '${zipPath}'"`, {
123
+ stdio: 'inherit'
124
+ });
125
+ } catch (e) {
126
+ error('下载失败');
127
+ throw e;
128
+ }
129
+
130
+ // 解压
131
+ log('正在解压 Python...', 'cyan');
132
+ fs.mkdirSync(installPath, { recursive: true });
133
+
134
+ execSync(`powershell -Command "Expand-Archive -Path '${zipPath}' -DestinationPath '${installPath}' -Force"`, {
135
+ stdio: 'inherit'
136
+ });
137
+
138
+ // 清理
139
+ fs.unlinkSync(zipPath);
140
+
141
+ log(`Python ${requiredVersion} 已安装到: ${installPath}`, 'green');
142
+
143
+ return pythonExe;
144
+ }
145
+
146
+ // 主流程
147
+ async function main() {
148
+ try {
149
+ log('检查 Python 环境...', 'cyan');
150
+
151
+ // 1. 读取要求的 Python 版本
152
+ const requiredVersion = getRequiredPythonVersion();
153
+
154
+ if (!requiredVersion) {
155
+ error('无法读取要求的 Python 版本');
156
+ return;
157
+ }
158
+
159
+ log(`要求的 Python 版本: ${requiredVersion}`, 'cyan');
160
+
161
+ // 2. 检测系统 Python
162
+ let pythonCmd = detectSystemPython(requiredVersion);
163
+
164
+ // 3. 如果没有,下载安装(仅 Windows)
165
+ if (!pythonCmd) {
166
+ if (process.platform === 'win32') {
167
+ pythonCmd = await downloadPython(requiredVersion);
168
+ } else {
169
+ log(`未检测到 Python ${requiredVersion}`, 'yellow');
170
+ log('请手动安装 Python 后重试', 'yellow');
171
+ log(`下载地址: https://www.python.org/downloads/release/python-${requiredVersion.replace(/\./g, '')}/`, 'cyan');
172
+ // 不退出,让 Python 层的检查器处理
173
+ }
174
+ }
175
+
176
+ if (pythonCmd) {
177
+ log('Python 环境检查完成', 'green');
178
+ log(`Python 命令: ${pythonCmd}`, 'cyan');
179
+ }
180
+
181
+ log('虚拟环境和依赖将在首次运行 kite 时自动准备', 'cyan');
182
+
183
+ } catch (e) {
184
+ error('环境准备失败');
185
+ console.error(e);
186
+ // 不退出,让 Python 层的检查器处理
187
+ }
188
+ }
189
+
190
+ // 执行
191
+ main();