@agentunion/kite 1.4.0 → 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 (235) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/cli.js +44 -5
  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/server.py +33 -17
  7. package/extensions/channels/acp_channel/server.py +33 -17
  8. package/extensions/services/backup/entry.py +23 -16
  9. package/extensions/services/evol/auth_manager.py +443 -0
  10. package/extensions/services/evol/config.yaml +149 -0
  11. package/extensions/services/evol/config_loader.py +117 -0
  12. package/extensions/services/evol/entry.py +406 -0
  13. package/extensions/services/evol/evol_api.py +173 -0
  14. package/extensions/services/evol/evol_config.json5 +29 -0
  15. package/extensions/services/evol/migrate_tokens.py +122 -0
  16. package/extensions/services/evol/module.md +32 -0
  17. package/extensions/services/evol/pairing.py +250 -0
  18. package/extensions/services/evol/pairing_codes.jsonl +1 -0
  19. package/extensions/services/evol/relay.py +682 -0
  20. package/extensions/services/evol/relay_config.json5 +67 -0
  21. package/extensions/services/evol/routes/__init__.py +1 -0
  22. package/extensions/services/evol/routes/routes_management_ws.py +127 -0
  23. package/extensions/services/evol/routes/routes_rpc.py +89 -0
  24. package/extensions/services/evol/routes/routes_test.py +61 -0
  25. package/extensions/services/evol/server.py +875 -0
  26. package/extensions/services/evol/static/css/style.css +1200 -0
  27. package/extensions/services/evol/static/index.html +781 -0
  28. package/extensions/services/evol/static/index_evol.html +14 -0
  29. package/extensions/services/evol/static/js/app.js +6304 -0
  30. package/extensions/services/evol/static/js/auth.js +326 -0
  31. package/extensions/services/evol/static/js/dialog.js +285 -0
  32. package/extensions/services/evol/static/js/evol-app-fixed.js +50 -0
  33. package/extensions/services/evol/static/js/evol-app.js +1949 -0
  34. package/extensions/services/evol/static/js/evol-app.js.bak +1800 -0
  35. package/extensions/services/evol/static/js/kernel-client-example.js +228 -0
  36. package/extensions/services/evol/static/js/kernel-client.js +396 -0
  37. package/extensions/services/evol/static/js/main.js +141 -0
  38. package/extensions/services/evol/static/js/registry-tests.js +585 -0
  39. package/extensions/services/evol/static/js/stats.js +217 -0
  40. package/extensions/services/evol/static/js/token-manager.js +175 -0
  41. package/extensions/services/evol/static/pairing.html +248 -0
  42. package/extensions/services/evol/static/test_registry.html +262 -0
  43. package/extensions/services/evol/static/test_relay.html +462 -0
  44. package/extensions/services/evol/stats_manager.py +240 -0
  45. package/extensions/services/model_service/entry.py +23 -1
  46. package/extensions/services/proxy/.claude/settings.local.json +13 -0
  47. package/extensions/services/proxy/CHANGELOG_20260308.md +258 -0
  48. package/extensions/services/proxy/_fix_prints.py +133 -0
  49. package/extensions/services/proxy/_fix_prints2.py +87 -0
  50. package/extensions/services/proxy/agentcp/LICENCE +178 -0
  51. package/extensions/services/proxy/agentcp/README copy.md +85 -0
  52. package/extensions/services/proxy/agentcp/README.md +260 -0
  53. package/extensions/services/proxy/agentcp/__init__.py +16 -0
  54. package/extensions/services/proxy/agentcp/agent.py +4 -0
  55. package/extensions/services/proxy/agentcp/agentcp.py +2494 -0
  56. package/extensions/services/proxy/agentcp/agentprofile.json +89 -0
  57. package/extensions/services/proxy/agentcp/ap/__init__.py +16 -0
  58. package/extensions/services/proxy/agentcp/ap/ap_client.py +316 -0
  59. package/extensions/services/proxy/agentcp/assets/images/wechat_qr.png +0 -0
  60. package/extensions/services/proxy/agentcp/backup/metrics.json +31 -0
  61. package/extensions/services/proxy/agentcp/base/__init__.py +20 -0
  62. package/extensions/services/proxy/agentcp/base/auth_client.py +257 -0
  63. package/extensions/services/proxy/agentcp/base/client.py +112 -0
  64. package/extensions/services/proxy/agentcp/base/env.py +34 -0
  65. package/extensions/services/proxy/agentcp/base/html_util.py +336 -0
  66. package/extensions/services/proxy/agentcp/base/log.py +98 -0
  67. package/extensions/services/proxy/agentcp/ca/__init__.py +17 -0
  68. package/extensions/services/proxy/agentcp/ca/ca_client.py +414 -0
  69. package/extensions/services/proxy/agentcp/ca/ca_root.py +74 -0
  70. package/extensions/services/proxy/agentcp/context/__init__.py +20 -0
  71. package/extensions/services/proxy/agentcp/context/context.py +73 -0
  72. package/extensions/services/proxy/agentcp/context/exceptions.py +114 -0
  73. package/extensions/services/proxy/agentcp/create_profile.py +125 -0
  74. package/extensions/services/proxy/agentcp/create_profile_weather.py +125 -0
  75. package/extensions/services/proxy/agentcp/db/__init__.py +15 -0
  76. package/extensions/services/proxy/agentcp/db/db_mananger.py +550 -0
  77. package/extensions/services/proxy/agentcp/docs/UDP_HEARTBEAT_FIX_REPORT.md +265 -0
  78. package/extensions/services/proxy/agentcp/docs/heartbeat_issue_analysis.md +291 -0
  79. package/extensions/services/proxy/agentcp/file/__init__.py +16 -0
  80. package/extensions/services/proxy/agentcp/file/file_client.py +141 -0
  81. package/extensions/services/proxy/agentcp/file/wss_binary_message.py +137 -0
  82. package/extensions/services/proxy/agentcp/hcp.py +299 -0
  83. package/extensions/services/proxy/agentcp/heartbeat/__init__.py +16 -0
  84. package/extensions/services/proxy/agentcp/heartbeat/heartbeat_client.py +360 -0
  85. package/extensions/services/proxy/agentcp/improved_scheduler.py +498 -0
  86. package/extensions/services/proxy/agentcp/llm_agent_utils.py +249 -0
  87. package/extensions/services/proxy/agentcp/llm_server.py +172 -0
  88. package/extensions/services/proxy/agentcp/mermaid.py +210 -0
  89. package/extensions/services/proxy/agentcp/message.py +149 -0
  90. package/extensions/services/proxy/agentcp/metrics.py +256 -0
  91. package/extensions/services/proxy/agentcp/monitoring/__init__.py +20 -0
  92. package/extensions/services/proxy/agentcp/monitoring/global_monitor.py +27 -0
  93. package/extensions/services/proxy/agentcp/monitoring/metrics_store.py +325 -0
  94. package/extensions/services/proxy/agentcp/monitoring/monitoring_service.py +269 -0
  95. package/extensions/services/proxy/agentcp/monitoring/sliding_window.py +222 -0
  96. package/extensions/services/proxy/agentcp/monitoring/standalone_reader.py +224 -0
  97. package/extensions/services/proxy/agentcp/msg/__init__.py +21 -0
  98. package/extensions/services/proxy/agentcp/msg/connection_manager.py +456 -0
  99. package/extensions/services/proxy/agentcp/msg/message_client.py +2058 -0
  100. package/extensions/services/proxy/agentcp/msg/message_serialize.py +263 -0
  101. package/extensions/services/proxy/agentcp/msg/open_ai_message.py +88 -0
  102. package/extensions/services/proxy/agentcp/msg/session_manager.py +1062 -0
  103. package/extensions/services/proxy/agentcp/msg/stream_client.py +267 -0
  104. package/extensions/services/proxy/agentcp/msg/websocket_file_receiver.py +89 -0
  105. package/extensions/services/proxy/agentcp/msg/ws_logger.py +685 -0
  106. package/extensions/services/proxy/agentcp/msg/wss_binary_message.py +137 -0
  107. package/extensions/services/proxy/agentcp/requirements.txt +7 -0
  108. package/extensions/services/proxy/agentcp/samples/agent_graph/README.md +37 -0
  109. package/extensions/services/proxy/agentcp/samples/agent_graph/agentprofile.json +89 -0
  110. package/extensions/services/proxy/agentcp/samples/agent_graph/create_profile.py +138 -0
  111. package/extensions/services/proxy/agentcp/samples/agent_graph/main.py +164 -0
  112. package/extensions/services/proxy/agentcp/samples/agent_use/create_profile.py +123 -0
  113. package/extensions/services/proxy/agentcp/samples/agent_use/llm/create_profile.py +129 -0
  114. package/extensions/services/proxy/agentcp/samples/agent_use/llm/env.json +5 -0
  115. package/extensions/services/proxy/agentcp/samples/agent_use/llm/main.py +146 -0
  116. package/extensions/services/proxy/agentcp/samples/agent_use/main.py +123 -0
  117. package/extensions/services/proxy/agentcp/samples/agent_use/readme.md +379 -0
  118. package/extensions/services/proxy/agentcp/samples/agent_use/search/create_profile.py +129 -0
  119. package/extensions/services/proxy/agentcp/samples/agent_use/search/main.py +28 -0
  120. package/extensions/services/proxy/agentcp/samples/agent_use/tool/create_profile.py +129 -0
  121. package/extensions/services/proxy/agentcp/samples/agent_use/tool/main.py +20 -0
  122. package/extensions/services/proxy/agentcp/samples/ali_amap/README.md +97 -0
  123. package/extensions/services/proxy/agentcp/samples/ali_amap/amap_agent.py +88 -0
  124. package/extensions/services/proxy/agentcp/samples/ali_amap/create_profile.py +125 -0
  125. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/powershell.py +228 -0
  126. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/software.py +63 -0
  127. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/tools.py +36 -0
  128. package/extensions/services/proxy/agentcp/samples/compute_agent/browser_user.py +41 -0
  129. package/extensions/services/proxy/agentcp/samples/deepseek/README.md +79 -0
  130. package/extensions/services/proxy/agentcp/samples/deepseek/create_profile.py +126 -0
  131. package/extensions/services/proxy/agentcp/samples/deepseek/deepseek.py +42 -0
  132. package/extensions/services/proxy/agentcp/samples/dify_chat/README.md +78 -0
  133. package/extensions/services/proxy/agentcp/samples/dify_chat/create_profile.py +126 -0
  134. package/extensions/services/proxy/agentcp/samples/dify_chat/dify_chat.py +47 -0
  135. package/extensions/services/proxy/agentcp/samples/dify_workflow/README.md +78 -0
  136. package/extensions/services/proxy/agentcp/samples/dify_workflow/create_profile.py +126 -0
  137. package/extensions/services/proxy/agentcp/samples/dify_workflow/dify_workflow.py +46 -0
  138. package/extensions/services/proxy/agentcp/samples/executor/README.md +44 -0
  139. package/extensions/services/proxy/agentcp/samples/executor/agentprofile.json +89 -0
  140. package/extensions/services/proxy/agentcp/samples/executor/create_profile.py +139 -0
  141. package/extensions/services/proxy/agentcp/samples/executor/main.py +160 -0
  142. package/extensions/services/proxy/agentcp/samples/filereader/README.md +45 -0
  143. package/extensions/services/proxy/agentcp/samples/filereader/agentprofile.json +90 -0
  144. package/extensions/services/proxy/agentcp/samples/filereader/create_profile.py +137 -0
  145. package/extensions/services/proxy/agentcp/samples/filereader/main.py +253 -0
  146. package/extensions/services/proxy/agentcp/samples/filewriter/README.md +38 -0
  147. package/extensions/services/proxy/agentcp/samples/filewriter/agentprofile.json +91 -0
  148. package/extensions/services/proxy/agentcp/samples/filewriter/create_profile.py +138 -0
  149. package/extensions/services/proxy/agentcp/samples/filewriter/main.py +289 -0
  150. package/extensions/services/proxy/agentcp/samples/hcp/README.md +85 -0
  151. package/extensions/services/proxy/agentcp/samples/hcp/acp_weather_agent.zip +0 -0
  152. package/extensions/services/proxy/agentcp/samples/hcp/create_profile.py +125 -0
  153. package/extensions/services/proxy/agentcp/samples/hcp/hcp.py +237 -0
  154. package/extensions/services/proxy/agentcp/samples/helloworld/README.md +68 -0
  155. package/extensions/services/proxy/agentcp/samples/helloworld/hello_world.py +40 -0
  156. package/extensions/services/proxy/agentcp/samples/llm_agent/MEADME.md +117 -0
  157. package/extensions/services/proxy/agentcp/samples/llm_agent/create_profile.py +125 -0
  158. package/extensions/services/proxy/agentcp/samples/llm_agent/qwen_agent.py +136 -0
  159. package/extensions/services/proxy/agentcp/samples/local_llm_agent/README.md +90 -0
  160. package/extensions/services/proxy/agentcp/samples/local_llm_agent/create_profile.py +125 -0
  161. package/extensions/services/proxy/agentcp/samples/local_llm_agent/main.py +49 -0
  162. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/README.md +55 -0
  163. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/create_profile.py +125 -0
  164. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/main.py +23 -0
  165. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/README.md +103 -0
  166. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/create_profile.py +125 -0
  167. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/main.py +69 -0
  168. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/README.md +58 -0
  169. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/create_profile.py +125 -0
  170. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/main.py +25 -0
  171. package/extensions/services/proxy/agentcp/samples/qwen3/README.md +71 -0
  172. package/extensions/services/proxy/agentcp/samples/qwen3/create_profile.py +126 -0
  173. package/extensions/services/proxy/agentcp/samples/qwen3/qwen3.py +37 -0
  174. package/extensions/services/proxy/agentcp/samples/qwen3_tools/README.md +133 -0
  175. package/extensions/services/proxy/agentcp/samples/qwen3_tools/create_profile.py +126 -0
  176. package/extensions/services/proxy/agentcp/samples/qwen3_tools/qwen3_tools.py +98 -0
  177. package/extensions/services/proxy/agentcp/samples/search/create_profile_qwen.py +125 -0
  178. package/extensions/services/proxy/agentcp/samples/search/create_profile_search.py +125 -0
  179. package/extensions/services/proxy/agentcp/samples/search/qwen_agent.py +136 -0
  180. package/extensions/services/proxy/agentcp/samples/search/search_agent.py +170 -0
  181. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/README.md +89 -0
  182. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/create_profile.py +125 -0
  183. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/main.py +44 -0
  184. package/extensions/services/proxy/agentcp/utils/__init__.py +15 -0
  185. package/extensions/services/proxy/agentcp/utils/file_util.py +117 -0
  186. package/extensions/services/proxy/agentcp/utils/proxy_bypass.py +99 -0
  187. package/extensions/services/proxy/agentcp/workflow.py +203 -0
  188. package/extensions/services/proxy/console_auth.py +109 -0
  189. package/extensions/services/proxy/evol/__init__.py +1 -0
  190. package/extensions/services/proxy/evol/config.py +37 -0
  191. package/extensions/services/proxy/evol/http/__init__.py +1 -0
  192. package/extensions/services/proxy/evol/http/async_http.py +551 -0
  193. package/extensions/services/proxy/evol/log.py +28 -0
  194. package/extensions/services/proxy/evol/presenter/__init__.py +2 -0
  195. package/extensions/services/proxy/evol/presenter/agentIdPresenter.py +1031 -0
  196. package/extensions/services/proxy/evol/presenter/apikeyPresenter.py +106 -0
  197. package/extensions/services/proxy/evol/presenter/configPresenter.py +1281 -0
  198. package/extensions/services/proxy/evol/presenter/userPresenter.py +477 -0
  199. package/extensions/services/proxy/evol/server/__init__.py +1 -0
  200. package/extensions/services/proxy/evol/server/claude_proxy_async.py +3430 -0
  201. package/extensions/services/proxy/evol/server/openclaw_proxy.py +1861 -0
  202. package/extensions/services/proxy/evol/server/proxy_config.py +15 -0
  203. package/extensions/services/proxy/evol/server/proxy_engine.py +501 -0
  204. package/extensions/services/proxy/evol/version.py +24 -0
  205. package/extensions/services/proxy/logs/websocket.log +260 -0
  206. package/extensions/services/proxy/main.py +240 -0
  207. package/extensions/services/proxy/requirements.txt +13 -0
  208. package/extensions/services/proxy/server.py +271 -0
  209. package/extensions/services/watchdog/entry.py +42 -16
  210. package/extensions/services/watchdog/module.md +1 -0
  211. package/extensions/services/watchdog/monitor.py +34 -4
  212. package/extensions/services/web/module.md +1 -1
  213. package/extensions/services/web/server.py +30 -18
  214. package/extensions/services/web/static/js/token-manager.js +10 -10
  215. package/kernel/entry.py +1 -1
  216. package/kernel/module.md +25 -1
  217. package/kernel/registry_store.py +2 -26
  218. package/kernel/rpc_router.py +36 -10
  219. package/kernel/server.py +106 -17
  220. package/kite_cli/commands/deps_install.py +67 -0
  221. package/kite_cli/commands/env_check.py +45 -0
  222. package/kite_cli/commands/prepare.py +49 -0
  223. package/kite_cli/commands/venv_setup.py +56 -0
  224. package/kite_cli/main.py +29 -1
  225. package/launcher/entry.py +306 -21
  226. package/launcher/module.md +9 -0
  227. package/launcher/module_scanner.py +11 -1
  228. package/main.py +4 -1
  229. package/package.json +8 -1
  230. package/python_version.json +4 -0
  231. package/requirements.txt +38 -0
  232. package/scripts/env-manager.js +328 -0
  233. package/scripts/python-env.js +79 -0
  234. package/scripts/scan_dependencies.py +461 -0
  235. package/scripts/setup-python-env.js +191 -0
@@ -0,0 +1,328 @@
1
+ /**
2
+ * Kite 环境管理模块
3
+ *
4
+ * 负责在 Node.js 层检查和准备 Python 环境
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const os = require('os');
10
+ const { execSync, spawnSync } = require('child_process');
11
+
12
+ // 颜色输出
13
+ const colors = {
14
+ reset: '\x1b[0m',
15
+ green: '\x1b[32m',
16
+ yellow: '\x1b[33m',
17
+ red: '\x1b[31m',
18
+ cyan: '\x1b[36m'
19
+ };
20
+
21
+ function log(msg, color = 'reset') {
22
+ console.log(`${colors[color]}[Kite Env]${colors.reset} ${msg}`);
23
+ }
24
+
25
+ function error(msg) {
26
+ console.error(`${colors.red}[Kite Env Error]${colors.reset} ${msg}`);
27
+ }
28
+
29
+ /**
30
+ * 获取 KITE_DATA 路径
31
+ */
32
+ function getKiteDataPath() {
33
+ return path.join(os.homedir(), '.kite');
34
+ }
35
+
36
+ /**
37
+ * 获取环境状态文件路径
38
+ */
39
+ function getEnvStatusPath() {
40
+ return path.join(getKiteDataPath(), 'env_status.json');
41
+ }
42
+
43
+ /**
44
+ * 读取环境状态
45
+ */
46
+ function loadEnvStatus() {
47
+ const statusFile = getEnvStatusPath();
48
+
49
+ if (!fs.existsSync(statusFile)) {
50
+ return null;
51
+ }
52
+
53
+ try {
54
+ const data = fs.readFileSync(statusFile, 'utf-8');
55
+ return JSON.parse(data);
56
+ } catch (e) {
57
+ error(`读取环境状态失败: ${e.message}`);
58
+ return null;
59
+ }
60
+ }
61
+
62
+ /**
63
+ * 检查是否需要准备 Python
64
+ */
65
+ function needsPythonSetup(versionDir) {
66
+ const pythonVersionFile = path.join(versionDir, 'python_version.json');
67
+
68
+ if (!fs.existsSync(pythonVersionFile)) {
69
+ return false; // 没有版本要求文件,跳过
70
+ }
71
+
72
+ try {
73
+ const versionData = JSON.parse(fs.readFileSync(pythonVersionFile, 'utf-8'));
74
+ const requiredVersion = versionData.version;
75
+
76
+ // 检测系统 Python
77
+ const pythonCommands = ['python3', 'python'];
78
+
79
+ for (const cmd of pythonCommands) {
80
+ try {
81
+ const version = execSync(`${cmd} --version`, {
82
+ encoding: 'utf8',
83
+ stdio: ['pipe', 'pipe', 'ignore']
84
+ }).trim();
85
+
86
+ const match = version.match(/Python (\d+\.\d+\.\d+)/);
87
+ if (match && match[1] === requiredVersion) {
88
+ return false; // 找到匹配的 Python 版本
89
+ }
90
+ } catch (e) {
91
+ // 命令不存在,继续
92
+ }
93
+ }
94
+
95
+ return true; // 没有找到匹配的 Python 版本
96
+ } catch (e) {
97
+ error(`检查 Python 版本失败: ${e.message}`);
98
+ return true; // 出错时保守处理,执行安装
99
+ }
100
+ }
101
+
102
+ /**
103
+ * 准备 Python 环境
104
+ */
105
+ function setupPython(versionDir) {
106
+ log('准备 Python 环境...', 'cyan');
107
+
108
+ const setupScript = path.join(versionDir, 'scripts', 'setup-python-env.js');
109
+
110
+ if (!fs.existsSync(setupScript)) {
111
+ error('setup-python-env.js 不存在');
112
+ return false;
113
+ }
114
+
115
+ try {
116
+ execSync(`node "${setupScript}"`, {
117
+ stdio: 'inherit',
118
+ cwd: versionDir
119
+ });
120
+ return true;
121
+ } catch (e) {
122
+ error('Python 环境准备失败');
123
+ return false;
124
+ }
125
+ }
126
+
127
+ /**
128
+ * 检查是否需要准备虚拟环境
129
+ */
130
+ function needsVenvSetup(status) {
131
+ // 1. 状态文件不存在
132
+ if (!status) {
133
+ return true;
134
+ }
135
+
136
+ // 2. 上次检查失败
137
+ if (status.status !== 'success') {
138
+ return true;
139
+ }
140
+
141
+ // 3. 虚拟环境不存在
142
+ const venvPath = path.join(getKiteDataPath(), 'venv');
143
+ if (!fs.existsSync(venvPath)) {
144
+ return true;
145
+ }
146
+
147
+ return false;
148
+ }
149
+
150
+ /**
151
+ * 检查是否需要安装依赖
152
+ */
153
+ function needsDepsInstall(status) {
154
+ // 1. 状态文件不存在
155
+ if (!status) {
156
+ return true;
157
+ }
158
+
159
+ // 2. 上次检查失败
160
+ if (status.status !== 'success') {
161
+ return true;
162
+ }
163
+
164
+ // 3. 依赖未安装
165
+ if (!status.dependencies || !status.dependencies.installed) {
166
+ return true;
167
+ }
168
+
169
+ return false;
170
+ }
171
+
172
+ /**
173
+ * 准备虚拟环境
174
+ */
175
+ function setupVenv(versionDir) {
176
+ log('准备虚拟环境...', 'cyan');
177
+
178
+ const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
179
+
180
+ try {
181
+ const result = spawnSync(
182
+ pythonCmd,
183
+ ['-m', 'kite_cli', 'venv-setup'],
184
+ {
185
+ cwd: versionDir,
186
+ stdio: 'inherit',
187
+ encoding: 'utf-8',
188
+ env: {
189
+ ...process.env,
190
+ PYTHONPATH: versionDir
191
+ }
192
+ }
193
+ );
194
+
195
+ return result.status === 0;
196
+ } catch (e) {
197
+ error('虚拟环境准备失败');
198
+ return false;
199
+ }
200
+ }
201
+
202
+ /**
203
+ * 安装依赖
204
+ */
205
+ function installDeps(versionDir) {
206
+ log('安装依赖库...', 'cyan');
207
+
208
+ const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
209
+
210
+ try {
211
+ const result = spawnSync(
212
+ pythonCmd,
213
+ ['-m', 'kite_cli', 'deps-install'],
214
+ {
215
+ cwd: versionDir,
216
+ stdio: 'inherit',
217
+ encoding: 'utf-8',
218
+ env: {
219
+ ...process.env,
220
+ PYTHONPATH: versionDir
221
+ }
222
+ }
223
+ );
224
+
225
+ return result.status === 0;
226
+ } catch (e) {
227
+ error('依赖安装失败');
228
+ return false;
229
+ }
230
+ }
231
+
232
+ /**
233
+ * 完整的环境检查和准备流程(三步)
234
+ */
235
+ function ensureEnvironment(versionDir) {
236
+ log('检查环境...', 'cyan');
237
+
238
+ // 1. 读取环境状态
239
+ const status = loadEnvStatus();
240
+
241
+ // 步骤 1: 检查是否需要准备 Python
242
+ if (needsPythonSetup(versionDir)) {
243
+ log('步骤 1/3: 准备 Python 环境', 'yellow');
244
+
245
+ if (!setupPython(versionDir)) {
246
+ error('Python 环境准备失败,无法启动 Kite');
247
+ markEnvFailed('python_setup_failed');
248
+ return false;
249
+ }
250
+
251
+ log('Python 环境准备完成', 'green');
252
+ } else {
253
+ log('步骤 1/3: Python 环境已就绪', 'green');
254
+ }
255
+
256
+ // 步骤 2: 检查是否需要准备虚拟环境
257
+ if (needsVenvSetup(status)) {
258
+ log('步骤 2/3: 准备虚拟环境', 'yellow');
259
+
260
+ if (!setupVenv(versionDir)) {
261
+ error('虚拟环境准备失败,无法启动 Kite');
262
+ markEnvFailed('venv_setup_failed');
263
+ return false;
264
+ }
265
+
266
+ log('虚拟环境准备完成', 'green');
267
+ } else {
268
+ log('步骤 2/3: 虚拟环境已就绪', 'green');
269
+ }
270
+
271
+ // 步骤 3: 检查是否需要安装依赖
272
+ if (needsDepsInstall(status)) {
273
+ log('步骤 3/3: 安装依赖库', 'yellow');
274
+
275
+ if (!installDeps(versionDir)) {
276
+ error('依赖安装失败,无法启动 Kite');
277
+ markEnvFailed('deps_install_failed');
278
+ return false;
279
+ }
280
+
281
+ log('依赖安装完成', 'green');
282
+ } else {
283
+ log('步骤 3/3: 依赖库已就绪', 'green');
284
+ }
285
+
286
+ log('环境准备完成', 'green');
287
+ return true;
288
+ }
289
+
290
+ /**
291
+ * 标记环境失败(用于异常处理)
292
+ */
293
+ function markEnvFailed(reason) {
294
+ const statusFile = getEnvStatusPath();
295
+ const statusData = {
296
+ version: '1.0',
297
+ last_check: new Date().toISOString(),
298
+ status: 'failed',
299
+ error: {
300
+ type: reason,
301
+ message: '环境准备失败',
302
+ timestamp: new Date().toISOString()
303
+ }
304
+ };
305
+
306
+ try {
307
+ const kiteData = getKiteDataPath();
308
+ if (!fs.existsSync(kiteData)) {
309
+ fs.mkdirSync(kiteData, { recursive: true });
310
+ }
311
+
312
+ fs.writeFileSync(statusFile, JSON.stringify(statusData, null, 2));
313
+ } catch (e) {
314
+ error(`无法写入状态文件: ${e.message}`);
315
+ }
316
+ }
317
+
318
+ module.exports = {
319
+ ensureEnvironment,
320
+ loadEnvStatus,
321
+ needsPythonSetup,
322
+ needsVenvSetup,
323
+ needsDepsInstall,
324
+ setupPython,
325
+ setupVenv,
326
+ installDeps,
327
+ markEnvFailed
328
+ };
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Python 环境工具模块
3
+ *
4
+ * 提供获取虚拟环境 Python 路径的工具函数
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const os = require('os');
10
+
11
+ /**
12
+ * 获取 KITE_DATA 路径
13
+ */
14
+ function getKiteDataPath() {
15
+ return path.join(os.homedir(), '.kite');
16
+ }
17
+
18
+ /**
19
+ * 获取虚拟环境路径
20
+ */
21
+ function getVenvPath() {
22
+ return path.join(getKiteDataPath(), 'venv');
23
+ }
24
+
25
+ /**
26
+ * 获取虚拟环境的 Python 可执行文件路径
27
+ */
28
+ function getVenvPython() {
29
+ const venvPath = getVenvPath();
30
+
31
+ if (process.platform === 'win32') {
32
+ return path.join(venvPath, 'Scripts', 'python.exe');
33
+ } else {
34
+ return path.join(venvPath, 'bin', 'python');
35
+ }
36
+ }
37
+
38
+ /**
39
+ * 获取虚拟环境的 pip 可执行文件路径
40
+ */
41
+ function getVenvPip() {
42
+ const venvPath = getVenvPath();
43
+
44
+ if (process.platform === 'win32') {
45
+ return path.join(venvPath, 'Scripts', 'pip.exe');
46
+ } else {
47
+ return path.join(venvPath, 'bin', 'pip');
48
+ }
49
+ }
50
+
51
+ /**
52
+ * 检查虚拟环境是否存在
53
+ */
54
+ function venvExists() {
55
+ const pythonPath = getVenvPython();
56
+ return fs.existsSync(pythonPath);
57
+ }
58
+
59
+ /**
60
+ * 检查 Python 环境是否就绪
61
+ */
62
+ function isPythonReady() {
63
+ if (!venvExists()) {
64
+ return false;
65
+ }
66
+
67
+ // 检查 pip 是否存在
68
+ const pipPath = getVenvPip();
69
+ return fs.existsSync(pipPath);
70
+ }
71
+
72
+ module.exports = {
73
+ getKiteDataPath,
74
+ getVenvPath,
75
+ getVenvPython,
76
+ getVenvPip,
77
+ venvExists,
78
+ isPythonReady
79
+ };