@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,161 @@
1
+ /**
2
+ * Kernel Client 使用示例
3
+ *
4
+ * 在主页面(index.html)中集成 KernelClient
5
+ */
6
+
7
+ // 全局 Kernel 客户端实例
8
+ let kernelClient = null;
9
+
10
+ /**
11
+ * 初始化 Kernel 客户端
12
+ */
13
+ async function initKernelClient() {
14
+ const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
15
+ kernelClient = new KernelClient(`${proto}//${location.host}/ws/relay`);
16
+
17
+ // 检查是否已配对
18
+ const token = localStorage.getItem('frontend_token');
19
+
20
+ if (!token) {
21
+ // 未配对,跳转到配对页面
22
+ window.location.href = '/pairing.html';
23
+ return;
24
+ }
25
+
26
+ try {
27
+ // 连接
28
+ const result = await kernelClient.connect();
29
+ console.log('[Kernel] Connected:', result);
30
+
31
+ // 订阅事件
32
+ await kernelClient.subscribe([
33
+ 'module.starting',
34
+ 'module.started',
35
+ 'module.ready',
36
+ 'module.stopped',
37
+ 'module.exiting',
38
+ 'module.shutdown',
39
+ 'module.crashed',
40
+ 'system.ready',
41
+ 'registry.updated',
42
+ 'module.registered',
43
+ 'module.unregistered'
44
+ ]);
45
+
46
+ // 监听模块状态变化
47
+ kernelClient.on('module.started', (data) => {
48
+ console.log('[Kernel] Module started:', data.module_id);
49
+ updateModuleStatus(data.module_id, 'running');
50
+ });
51
+
52
+ kernelClient.on('module.stopped', (data) => {
53
+ console.log('[Kernel] Module stopped:', data.module_id);
54
+ updateModuleStatus(data.module_id, 'stopped');
55
+ });
56
+
57
+ kernelClient.on('module.crashed', (data) => {
58
+ console.log('[Kernel] Module crashed:', data.module_id);
59
+ updateModuleStatus(data.module_id, 'crashed');
60
+ });
61
+
62
+ kernelClient.on('registry.updated', (data) => {
63
+ console.log('[Kernel] Registry updated:', data);
64
+ // 触发缓存失效事件
65
+ window.dispatchEvent(new CustomEvent('registryCacheInvalidate', {
66
+ detail: data
67
+ }));
68
+ });
69
+
70
+ // 更新连接状态指示器
71
+ updateConnectionStatus(true);
72
+
73
+ // 触发连接成功事件
74
+ window.dispatchEvent(new CustomEvent('kernelClientReady'));
75
+
76
+ } catch (err) {
77
+ console.error('[Kernel] Connection failed:', err);
78
+
79
+ // 如果是 token 无效,跳转到配对页面
80
+ if (err.message.includes('Invalid') || err.message.includes('expired')) {
81
+ window.location.href = '/pairing.html';
82
+ } else {
83
+ updateConnectionStatus(false);
84
+ }
85
+ }
86
+ }
87
+
88
+ /**
89
+ * 更新连接状态指示器
90
+ */
91
+ function updateConnectionStatus(connected) {
92
+ const indicators = [
93
+ document.getElementById('ws-indicator'),
94
+ document.getElementById('ws-indicator-modules')
95
+ ];
96
+
97
+ indicators.forEach(indicator => {
98
+ if (indicator) {
99
+ if (connected) {
100
+ indicator.textContent = '● 已连线';
101
+ indicator.style.color = 'var(--success)';
102
+ } else {
103
+ indicator.textContent = '○ 未连线';
104
+ indicator.style.color = 'var(--gray-400)';
105
+ }
106
+ }
107
+ });
108
+ }
109
+
110
+ /**
111
+ * 更新模块状态
112
+ */
113
+ function updateModuleStatus(moduleName, status) {
114
+ // 这里调用现有的模块状态更新逻辑
115
+ if (typeof _onModuleStatusChange === 'function') {
116
+ _onModuleStatusChange(moduleName, status);
117
+ }
118
+ }
119
+
120
+ /**
121
+ * 调用 RPC 示例
122
+ */
123
+ async function exampleRpcCalls() {
124
+ if (!kernelClient) {
125
+ console.error('[Kernel] Client not initialized');
126
+ return;
127
+ }
128
+
129
+ try {
130
+ // 获取模块列表
131
+ const modules = await kernelClient.call('launcher.list_modules');
132
+ console.log('[Kernel] Modules:', modules);
133
+
134
+ // 启动模块
135
+ await kernelClient.call('launcher.start_module', { name: 'watchdog' });
136
+ console.log('[Kernel] Module started');
137
+
138
+ // 停止模块
139
+ await kernelClient.call('launcher.stop_module', { name: 'watchdog' });
140
+ console.log('[Kernel] Module stopped');
141
+
142
+ } catch (err) {
143
+ console.error('[Kernel] RPC error:', err);
144
+ }
145
+ }
146
+
147
+ /**
148
+ * 页面加载时初始化
149
+ */
150
+ document.addEventListener('DOMContentLoaded', () => {
151
+ initKernelClient();
152
+ });
153
+
154
+ /**
155
+ * 页面关闭时断开连接
156
+ */
157
+ window.addEventListener('beforeunload', () => {
158
+ if (kernelClient) {
159
+ kernelClient.disconnect();
160
+ }
161
+ });
@@ -0,0 +1,383 @@
1
+ /**
2
+ * Kernel WebSocket 客户端
3
+ *
4
+ * 功能:
5
+ * - 配对/认证
6
+ * - 自动重连
7
+ * - RPC 调用
8
+ * - 事件订阅
9
+ * - Token 续期
10
+ */
11
+
12
+ class KernelClient {
13
+ constructor(url) {
14
+ this.url = url;
15
+ this.ws = null;
16
+ this.moduleId = null;
17
+ this.role = null;
18
+ this.connected = false;
19
+ this.authenticated = false;
20
+
21
+ // RPC 请求管理
22
+ this.rpcId = 0;
23
+ this.pendingRpcs = new Map(); // id -> {resolve, reject, timeout}
24
+
25
+ // 事件监听器
26
+ this.eventListeners = new Map(); // event -> [callbacks]
27
+
28
+ // 重连配置
29
+ this.reconnectDelay = 1000; // 1秒
30
+ this.maxReconnectDelay = 10000; // 10秒
31
+ this.reconnectAttempts = 0;
32
+ this.reconnectTimer = null;
33
+
34
+ // 心跳配置
35
+ this.heartbeatInterval = 20000; // 20秒
36
+ this.heartbeatTimer = null;
37
+
38
+ // Token 管理
39
+ this.token = localStorage.getItem('frontend_token');
40
+ this.sessionToken = sessionStorage.getItem('session_token');
41
+
42
+ // 生成 session_token(如果没有)
43
+ if (!this.sessionToken) {
44
+ this.sessionToken = 'sess_' + this._randomString(6);
45
+ sessionStorage.setItem('session_token', this.sessionToken);
46
+ }
47
+ }
48
+
49
+ /**
50
+ * 配对(首次使用)
51
+ */
52
+ async pair(code) {
53
+ return new Promise((resolve, reject) => {
54
+ this._connect((ws) => {
55
+ // 发送配对消息
56
+ ws.send(JSON.stringify({
57
+ type: 'pair',
58
+ code: code
59
+ }));
60
+
61
+ // 等待响应
62
+ const handler = (event) => {
63
+ const msg = JSON.parse(event.data);
64
+
65
+ if (msg.type === 'paired') {
66
+ // 配对成功
67
+ this.token = msg.token;
68
+ this.sessionToken = msg.session_token;
69
+ this.moduleId = msg.module_id;
70
+ this.role = msg.role;
71
+
72
+ // 保存 token
73
+ localStorage.setItem('frontend_token', this.token);
74
+ sessionStorage.setItem('session_token', this.sessionToken);
75
+
76
+ this.authenticated = true;
77
+ ws.removeEventListener('message', handler);
78
+ resolve({
79
+ moduleId: this.moduleId,
80
+ role: this.role
81
+ });
82
+ } else if (msg.type === 'error') {
83
+ // 配对失败
84
+ ws.removeEventListener('message', handler);
85
+ reject(new Error(msg.message));
86
+ }
87
+ };
88
+
89
+ ws.addEventListener('message', handler);
90
+ }, reject);
91
+ });
92
+ }
93
+
94
+ /**
95
+ * 连接(已有 token)
96
+ */
97
+ async connect() {
98
+ if (!this.token) {
99
+ throw new Error('No token found, please pair first');
100
+ }
101
+
102
+ return new Promise((resolve, reject) => {
103
+ this._connect((ws) => {
104
+ // 发送认证消息
105
+ ws.send(JSON.stringify({
106
+ type: 'auth',
107
+ token: this.token,
108
+ session_token: this.sessionToken
109
+ }));
110
+
111
+ // 等待响应
112
+ const handler = (event) => {
113
+ const msg = JSON.parse(event.data);
114
+
115
+ if (msg.type === 'authenticated' || msg.type === 'reconnected') {
116
+ // 认证成功
117
+ this.moduleId = msg.module_id;
118
+ this.role = msg.role;
119
+ this.authenticated = true;
120
+
121
+ ws.removeEventListener('message', handler);
122
+ resolve({
123
+ moduleId: this.moduleId,
124
+ role: this.role,
125
+ reconnected: msg.type === 'reconnected'
126
+ });
127
+ } else if (msg.type === 'error') {
128
+ // 认证失败
129
+ ws.removeEventListener('message', handler);
130
+
131
+ // 如果是 token 无效,清除本地 token
132
+ if (msg.message.includes('Invalid') || msg.message.includes('expired')) {
133
+ localStorage.removeItem('frontend_token');
134
+ this.token = null;
135
+ }
136
+
137
+ reject(new Error(msg.message));
138
+ }
139
+ };
140
+
141
+ ws.addEventListener('message', handler);
142
+ }, reject);
143
+ });
144
+ }
145
+
146
+ /**
147
+ * 调用 RPC
148
+ */
149
+ async call(method, params = {}, timeout = 30000) {
150
+ if (!this.authenticated) {
151
+ throw new Error('Not authenticated');
152
+ }
153
+
154
+ return new Promise((resolve, reject) => {
155
+ const id = `rpc-${++this.rpcId}`;
156
+
157
+ // 发送 RPC 请求
158
+ this.ws.send(JSON.stringify({
159
+ jsonrpc: '2.0',
160
+ id: id,
161
+ method: method,
162
+ params: params
163
+ }));
164
+
165
+ // 设置超时
166
+ const timer = setTimeout(() => {
167
+ this.pendingRpcs.delete(id);
168
+ reject(new Error(`RPC timeout: ${method}`));
169
+ }, timeout);
170
+
171
+ // 保存 pending RPC
172
+ this.pendingRpcs.set(id, { resolve, reject, timeout: timer });
173
+ });
174
+ }
175
+
176
+ /**
177
+ * 订阅事件
178
+ */
179
+ async subscribe(events) {
180
+ return this.call('event.subscribe', { events });
181
+ }
182
+
183
+ /**
184
+ * 监听事件
185
+ */
186
+ on(event, callback) {
187
+ if (!this.eventListeners.has(event)) {
188
+ this.eventListeners.set(event, []);
189
+ }
190
+ this.eventListeners.get(event).push(callback);
191
+ }
192
+
193
+ /**
194
+ * 取消监听事件
195
+ */
196
+ off(event, callback) {
197
+ if (!this.eventListeners.has(event)) return;
198
+
199
+ const listeners = this.eventListeners.get(event);
200
+ const index = listeners.indexOf(callback);
201
+ if (index > -1) {
202
+ listeners.splice(index, 1);
203
+ }
204
+ }
205
+
206
+ /**
207
+ * 断开连接
208
+ */
209
+ disconnect() {
210
+ if (this.reconnectTimer) {
211
+ clearTimeout(this.reconnectTimer);
212
+ this.reconnectTimer = null;
213
+ }
214
+
215
+ this._stopHeartbeat();
216
+
217
+ if (this.ws) {
218
+ // 发送 disconnect 消息
219
+ try {
220
+ this.ws.send(JSON.stringify({ type: 'disconnect' }));
221
+ } catch (e) {
222
+ // Ignore
223
+ }
224
+
225
+ this.ws.close();
226
+ this.ws = null;
227
+ }
228
+
229
+ this.connected = false;
230
+ this.authenticated = false;
231
+ }
232
+
233
+ /**
234
+ * 启动心跳
235
+ */
236
+ _startHeartbeat() {
237
+ this._stopHeartbeat();
238
+ this.heartbeatTimer = setInterval(() => {
239
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
240
+ try {
241
+ // 发送 ping 消息
242
+ this.ws.send(JSON.stringify({ type: 'ping' }));
243
+ } catch (e) {
244
+ console.error('[KernelClient] Heartbeat failed:', e);
245
+ }
246
+ }
247
+ }, this.heartbeatInterval);
248
+ }
249
+
250
+ /**
251
+ * 停止心跳
252
+ */
253
+ _stopHeartbeat() {
254
+ if (this.heartbeatTimer) {
255
+ clearInterval(this.heartbeatTimer);
256
+ this.heartbeatTimer = null;
257
+ }
258
+ }
259
+
260
+ /**
261
+ * 内部:建立 WebSocket 连接
262
+ */
263
+ _connect(onOpen, onError) {
264
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
265
+ onOpen(this.ws);
266
+ return;
267
+ }
268
+
269
+ const ws = new WebSocket(this.url);
270
+
271
+ ws.onopen = () => {
272
+ console.log('[KernelClient] WebSocket connected');
273
+ this.ws = ws;
274
+ this.connected = true;
275
+ this.reconnectAttempts = 0;
276
+ this.reconnectDelay = 1000;
277
+ this._startHeartbeat();
278
+ onOpen(ws);
279
+ };
280
+
281
+ ws.onerror = (error) => {
282
+ console.error('[KernelClient] WebSocket error:', error);
283
+ if (onError) onError(error);
284
+ };
285
+
286
+ ws.onclose = () => {
287
+ console.log('[KernelClient] WebSocket closed');
288
+ this.connected = false;
289
+ this.authenticated = false;
290
+ this.ws = null;
291
+ this._stopHeartbeat();
292
+
293
+ // 自动重连(如果有 token)
294
+ if (this.token) {
295
+ this._scheduleReconnect();
296
+ }
297
+ };
298
+
299
+ ws.onmessage = (event) => {
300
+ this._handleMessage(event.data);
301
+ };
302
+ }
303
+
304
+ /**
305
+ * 内部:处理消息
306
+ */
307
+ _handleMessage(raw) {
308
+ try {
309
+ const msg = JSON.parse(raw);
310
+
311
+ // RPC 响应
312
+ if (msg.id && this.pendingRpcs.has(msg.id)) {
313
+ const { resolve, reject, timeout } = this.pendingRpcs.get(msg.id);
314
+ clearTimeout(timeout);
315
+ this.pendingRpcs.delete(msg.id);
316
+
317
+ if (msg.error) {
318
+ reject(new Error(msg.error.message || 'RPC error'));
319
+ } else {
320
+ resolve(msg.result);
321
+ }
322
+ return;
323
+ }
324
+
325
+ // 事件通知
326
+ if (msg.method === 'event' || !msg.id) {
327
+ const params = msg.params || {};
328
+ const event = params.event;
329
+ const data = params.data || {};
330
+
331
+ if (event && this.eventListeners.has(event)) {
332
+ const listeners = this.eventListeners.get(event);
333
+ listeners.forEach(callback => {
334
+ try {
335
+ callback(data);
336
+ } catch (e) {
337
+ console.error('[KernelClient] Event listener error:', e);
338
+ }
339
+ });
340
+ }
341
+ }
342
+ } catch (e) {
343
+ console.error('[KernelClient] Message parse error:', e);
344
+ }
345
+ }
346
+
347
+ /**
348
+ * 内部:安排重连
349
+ */
350
+ _scheduleReconnect() {
351
+ if (this.reconnectTimer) return;
352
+
353
+ this.reconnectAttempts++;
354
+ const delay = Math.min(
355
+ this.reconnectDelay * Math.pow(1.5, this.reconnectAttempts - 1),
356
+ this.maxReconnectDelay
357
+ );
358
+
359
+ console.log(`[KernelClient] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
360
+
361
+ this.reconnectTimer = setTimeout(() => {
362
+ this.reconnectTimer = null;
363
+ this.connect().catch(err => {
364
+ console.error('[KernelClient] Reconnect failed:', err);
365
+ });
366
+ }, delay);
367
+ }
368
+
369
+ /**
370
+ * 内部:生成随机字符串
371
+ */
372
+ _randomString(length) {
373
+ const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
374
+ let result = '';
375
+ for (let i = 0; i < length; i++) {
376
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
377
+ }
378
+ return result;
379
+ }
380
+ }
381
+
382
+ // 导出
383
+ window.KernelClient = KernelClient;