@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
@@ -50,6 +50,9 @@ def init_log_files():
50
50
  _log_dir = os.path.join(module_data, "log")
51
51
  os.makedirs(_log_dir, exist_ok=True)
52
52
 
53
+ # Clean up orphaned instance log files before initializing
54
+ _cleanup_orphaned_logs()
55
+
53
56
  suffix = os.environ.get("KITE_INSTANCE_SUFFIX", "")
54
57
 
55
58
  # latest.log — truncate on each startup
@@ -73,6 +76,107 @@ def init_log_files():
73
76
  _resolve_daily_log_path()
74
77
 
75
78
 
79
+ def _cleanup_orphaned_logs():
80
+ """Clean up log files from dead instances (files with ~N suffix whose launcher is not running)."""
81
+ if not _log_dir or not os.path.isdir(_log_dir):
82
+ return
83
+
84
+ try:
85
+ # Get state directory path
86
+ module_data = os.environ.get("KITE_MODULE_DATA")
87
+ if not module_data:
88
+ return
89
+ state_dir = os.path.join(os.path.dirname(module_data), "state")
90
+
91
+ # Scan for files with ~N suffix
92
+ import glob
93
+ orphaned_files = []
94
+
95
+ for pattern in ["latest~*.log", "crashes~*.jsonl"]:
96
+ for filepath in glob.glob(os.path.join(_log_dir, pattern)):
97
+ basename = os.path.basename(filepath)
98
+ # Extract instance number from filename
99
+ instance_num = _extract_instance_num(basename)
100
+ if instance_num is None:
101
+ continue
102
+
103
+ # Check if corresponding launcher is still running
104
+ if not _is_instance_alive(state_dir, instance_num):
105
+ orphaned_files.append(filepath)
106
+
107
+ # Delete orphaned files
108
+ if orphaned_files:
109
+ _builtin_print(f"[launcher] 清理 {len(orphaned_files)} 个孤儿日志文件:")
110
+ for filepath in orphaned_files:
111
+ try:
112
+ os.remove(filepath)
113
+ _builtin_print(f"[launcher] 已删除: {os.path.basename(filepath)}")
114
+ except Exception as e:
115
+ _builtin_print(f"[launcher] 删除失败 {os.path.basename(filepath)}: {e}")
116
+
117
+ except Exception as e:
118
+ _builtin_print(f"[launcher] 清理孤儿日志文件时出错: {e}")
119
+
120
+
121
+ def _extract_instance_num(filename: str) -> int | None:
122
+ """Extract instance number from log filename. Returns None if not a valid instance file."""
123
+ import re
124
+ # Match patterns like "latest~2.log" or "crashes~3.jsonl"
125
+ m = re.match(r"^(?:latest|crashes)~(\d+)\.(log|jsonl)$", filename)
126
+ return int(m.group(1)) if m else None
127
+
128
+
129
+ def _is_instance_alive(state_dir: str, instance_num: int) -> bool:
130
+ """Check if a launcher instance is still running by checking its processes file and PID."""
131
+ if not os.path.isdir(state_dir):
132
+ return False
133
+
134
+ # Determine processes filename
135
+ if instance_num == 1:
136
+ processes_file = os.path.join(state_dir, "processes.json")
137
+ else:
138
+ processes_file = os.path.join(state_dir, f"processes~{instance_num}.json")
139
+
140
+ # If processes file doesn't exist, instance is dead
141
+ if not os.path.isfile(processes_file):
142
+ return False
143
+
144
+ # Read launcher_pid from processes file
145
+ try:
146
+ import json
147
+ with open(processes_file, "r", encoding="utf-8") as f:
148
+ data = json.load(f)
149
+ launcher_pid = data.get("launcher_pid")
150
+ if not launcher_pid:
151
+ return False
152
+
153
+ # Check if process is still running
154
+ return _is_process_running(launcher_pid)
155
+ except Exception:
156
+ return False
157
+
158
+
159
+ def _is_process_running(pid: int) -> bool:
160
+ """Check if a process with given PID is running (cross-platform)."""
161
+ try:
162
+ if sys.platform == "win32":
163
+ # Windows: use tasklist
164
+ import subprocess
165
+ result = subprocess.run(
166
+ ["tasklist", "/FI", f"PID eq {pid}", "/NH"],
167
+ capture_output=True,
168
+ text=True,
169
+ timeout=2
170
+ )
171
+ return str(pid) in result.stdout
172
+ else:
173
+ # Unix: send signal 0
174
+ os.kill(pid, 0)
175
+ return True
176
+ except (OSError, subprocess.TimeoutExpired):
177
+ return False
178
+
179
+
76
180
  def _resolve_daily_log_path():
77
181
  """Resolve the daily log file path based on current date."""
78
182
  global _log_daily_path, _log_daily_date
@@ -1,37 +1,46 @@
1
- ---
2
- name: launcher
3
- display_name: "Launcher"
4
- version: "1.0"
5
- type: infrastructure
6
- state: enabled
7
- events:
8
- - module.started
9
- - module.stopped
10
- - module.state_changed
11
- subscriptions: []
12
- discovery:
13
- test_modules:
14
- type: scan_dir
15
- path: test_modules
16
- enabled: true
17
- ---
18
-
19
- # Launcher
20
-
21
- Kite 系统的启动器和进程管理器。与 main.py 在同一进程中运行,是整个系统的入口和控制台。
22
-
23
- ## 职责
24
-
25
- - 启动 Registry,等待就绪
26
- - 扫描 core/ 和 extensions/ 下的模块
27
- - 并行启动 state: enabled 的模块
28
- - 监控子进程状态,core 模块崩溃触发全量重启
29
- - 提供 Launcher API 供其他模块启停管理
30
- - 优雅退出时清理所有子进程
31
-
32
- ## API
33
-
34
- - `GET /launcher/modules` — 列出所有模块及状态
35
- - `POST /launcher/modules/{name}/start` — 启动模块
36
- - `POST /launcher/modules/{name}/stop` 停止模块
37
- - `PUT /launcher/modules/{name}/state` — 修改模块 state
1
+ ---
2
+ name: launcher
3
+ display_name: Launcher
4
+ version: '1.0'
5
+ type: infrastructure
6
+ state: enabled
7
+ events:
8
+ - module.started
9
+ - module.stopped
10
+ - module.state_changed
11
+ subscriptions: []
12
+ discovery:
13
+ test_modules:
14
+ type: scan_dir
15
+ path: test_modules
16
+ enabled: true
17
+ relay:
18
+ # 允许申请动态 Token 的模块白名单
19
+ modules:
20
+ - evol
21
+ - web
22
+ # 每个 relay 模块的 Token 限额
23
+ token_limits:
24
+ evol: 100
25
+ web: 50
26
+ monitor: true
27
+ ---
28
+ # Launcher
29
+
30
+ Kite 系统的启动器和进程管理器。与 main.py 在同一进程中运行,是整个系统的入口和控制台。
31
+
32
+ ## 职责
33
+
34
+ - 启动 Registry,等待就绪
35
+ - 扫描 core/ 和 extensions/ 下的模块
36
+ - 并行启动 state: enabled 的模块
37
+ - 监控子进程状态,core 模块崩溃触发全量重启
38
+ - 提供 Launcher API 供其他模块启停管理
39
+ - 优雅退出时清理所有子进程
40
+
41
+ ## API
42
+
43
+ - `GET /launcher/modules` — 列出所有模块及状态
44
+ - `POST /launcher/modules/{name}/start` — 启动模块
45
+ - `POST /launcher/modules/{name}/stop` — 停止模块
46
+ - `PUT /launcher/modules/{name}/state` — 修改模块 state
@@ -31,6 +31,7 @@ class ModuleInfo:
31
31
  preferred_port: int = 0 # 0 = OS assigns; non-zero = try this port first
32
32
  depends_on: list = field(default_factory=list) # module names this module depends on
33
33
  monitor: bool = True # whether Watchdog should monitor this module
34
+ display_order: int = 0 # 0-100, controls display order in module list (0=default, 100=highest)
34
35
  module_dir: str = "" # absolute path to the module directory
35
36
  launch: LaunchConfig = field(default_factory=LaunchConfig)
36
37
 
@@ -105,7 +106,8 @@ class ModuleScanner:
105
106
  # Note: launcher is not scanned (it's the scanner itself)
106
107
  kernel_dir = os.path.join(project_root, "kernel")
107
108
  if os.path.isdir(kernel_dir):
108
- self._scan_dir(kernel_dir, 0, modules)
109
+ # Kernel is at project root, check it directly
110
+ self._add_module(kernel_dir, modules)
109
111
  self._scan_dir(os.path.join(project_root, "extensions"), 2, modules)
110
112
 
111
113
  # Extra sources from discovery config
@@ -216,6 +218,13 @@ class ModuleScanner:
216
218
  monitor_val = fm.get("monitor", "true")
217
219
  monitor = str(monitor_val).lower() not in ("false", "0", "no")
218
220
 
221
+ # Parse display_order (0-100, default 0)
222
+ try:
223
+ display_order = int(fm.get("display_order", 0))
224
+ display_order = max(0, min(100, display_order)) # Clamp to [0, 100]
225
+ except (ValueError, TypeError):
226
+ display_order = 0
227
+
219
228
  # Parse optional launch config
220
229
  launch_raw = fm.get("launch", {})
221
230
  if not isinstance(launch_raw, dict):
@@ -254,6 +263,7 @@ class ModuleScanner:
254
263
  preferred_port=preferred_port,
255
264
  depends_on=depends_on,
256
265
  monitor=monitor,
266
+ display_order=display_order,
257
267
  module_dir=mod_dir,
258
268
  launch=launch,
259
269
  )
package/main.py CHANGED
@@ -2,12 +2,15 @@
2
2
  Kite development entry point.
3
3
  1. Run code stats
4
4
  2. Start launcher
5
+
6
+ 注意:环境检查已在 Node.js 层(cli.js)完成
5
7
  """
6
8
  import sys
7
9
  from pathlib import Path
8
10
 
9
11
  # Add project root to sys.path
10
- sys.path.insert(0, str(Path(__file__).parent))
12
+ project_root = Path(__file__).parent
13
+ sys.path.insert(0, str(project_root))
11
14
 
12
15
  # 1. Run code stats
13
16
  from launcher.count_lines import run_stats
package/package.json CHANGED
@@ -1,17 +1,25 @@
1
1
  {
2
2
  "name": "@agentunion/kite",
3
- "version": "1.3.2",
3
+ "version": "1.5.0",
4
4
  "description": "Kite framework launcher — start Kite from anywhere",
5
5
  "bin": {
6
6
  "kite": "./cli.js"
7
7
  },
8
+ "scripts": {
9
+ "postinstall": "node scripts/setup-python-env.js"
10
+ },
8
11
  "files": [
9
12
  "cli.js",
10
13
  "main.py",
14
+ "requirements.txt",
15
+ "python_version.json",
16
+ "dependencies_lock.json",
11
17
  "launcher/**",
12
18
  "kernel/**",
13
19
  "extensions/**",
20
+ "kite_cli/**",
14
21
  "scripts/**",
22
+ "core/**",
15
23
  "CHANGELOG.md",
16
24
  "!**/__pycache__",
17
25
  "!**/__pycache__/**",
@@ -0,0 +1,4 @@
1
+ {
2
+ "version": "3.13.12",
3
+ "note": "此文件在开发环境打包时生成,记录开发环境的 Python 版本。生产环境必须使用相同版本。"
4
+ }
@@ -0,0 +1,38 @@
1
+ # Kite 框架核心依赖
2
+ # 安装方法:pip install -r requirements.txt
3
+
4
+ # Web 框架
5
+ fastapi>=0.115.0
6
+ uvicorn>=0.32.0
7
+ starlette>=0.41.0
8
+
9
+ # WebSocket
10
+ websockets>=13.0
11
+
12
+ # HTTP 客户端
13
+ httpx>=0.27.0
14
+ aiohttp>=3.10.0
15
+ requests>=2.32.0
16
+
17
+ # 配置解析
18
+ json5>=0.9.25
19
+ pyyaml>=6.0.2
20
+ python-dotenv>=1.0.0
21
+
22
+ # 数据验证
23
+ pydantic>=2.9.0
24
+
25
+ # 异步 IO
26
+ aiofiles>=24.1.0
27
+
28
+ # 进程管理
29
+ psutil>=6.1.0
30
+
31
+ # 加密
32
+ cryptography>=43.0.0
33
+
34
+ # 进度条
35
+ tqdm>=4.66.0
36
+
37
+ # 类型扩展
38
+ typing-extensions>=4.12.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
+ };