@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.
- package/CHANGELOG.md +302 -0
- package/cli.js +119 -4
- package/core/dependency_checker.py +250 -0
- package/core/env_checker.py +490 -0
- package/dependencies_lock.json +128 -0
- package/extensions/agents/assistant/entry.py +111 -1
- package/extensions/agents/assistant/server.py +279 -215
- package/extensions/channels/acp_channel/entry.py +111 -1
- package/extensions/channels/acp_channel/module.md +23 -22
- package/extensions/channels/acp_channel/server.py +279 -215
- package/extensions/event_hub_bench/entry.py +107 -1
- package/extensions/services/backup/entry.py +306 -21
- package/extensions/services/backup/module.md +24 -22
- package/extensions/services/evol/auth_manager.py +443 -0
- package/extensions/services/evol/config.yaml +149 -0
- package/extensions/services/evol/config_loader.py +117 -0
- package/extensions/services/evol/entry.py +406 -0
- package/extensions/services/evol/evol_api.py +173 -0
- package/extensions/services/evol/evol_config.json5 +29 -0
- package/extensions/services/evol/migrate_tokens.py +122 -0
- package/extensions/services/evol/module.md +32 -0
- package/extensions/services/evol/pairing.py +250 -0
- package/extensions/services/evol/pairing_codes.jsonl +1 -0
- package/extensions/services/evol/relay.py +682 -0
- package/extensions/services/evol/relay_config.json5 +67 -0
- package/extensions/services/evol/routes/__init__.py +1 -0
- package/extensions/services/evol/routes/routes_management_ws.py +127 -0
- package/extensions/services/evol/routes/routes_rpc.py +89 -0
- package/extensions/services/evol/routes/routes_test.py +61 -0
- package/extensions/services/evol/server.py +875 -0
- package/extensions/services/evol/static/css/style.css +1200 -0
- package/extensions/services/evol/static/index.html +781 -0
- package/extensions/services/evol/static/index_evol.html +14 -0
- package/extensions/services/evol/static/js/app.js +6304 -0
- package/extensions/services/evol/static/js/auth.js +326 -0
- package/extensions/services/evol/static/js/dialog.js +285 -0
- package/extensions/services/evol/static/js/evol-app-fixed.js +50 -0
- package/extensions/services/evol/static/js/evol-app.js +1949 -0
- package/extensions/services/evol/static/js/evol-app.js.bak +1800 -0
- package/extensions/services/evol/static/js/kernel-client-example.js +228 -0
- package/extensions/services/evol/static/js/kernel-client.js +396 -0
- package/extensions/services/evol/static/js/main.js +141 -0
- package/extensions/services/evol/static/js/registry-tests.js +585 -0
- package/extensions/services/evol/static/js/stats.js +217 -0
- package/extensions/services/evol/static/js/token-manager.js +175 -0
- package/extensions/services/evol/static/pairing.html +248 -0
- package/extensions/services/evol/static/test_registry.html +262 -0
- package/extensions/services/evol/static/test_relay.html +462 -0
- package/extensions/services/evol/stats_manager.py +240 -0
- package/extensions/services/model_service/entry.py +167 -19
- package/extensions/services/model_service/module.md +21 -22
- package/extensions/services/proxy/.claude/settings.local.json +13 -0
- package/extensions/services/proxy/CHANGELOG_20260308.md +258 -0
- package/extensions/services/proxy/_fix_prints.py +133 -0
- package/extensions/services/proxy/_fix_prints2.py +87 -0
- package/extensions/services/proxy/agentcp/LICENCE +178 -0
- package/extensions/services/proxy/agentcp/README copy.md +85 -0
- package/extensions/services/proxy/agentcp/README.md +260 -0
- package/extensions/services/proxy/agentcp/__init__.py +16 -0
- package/extensions/services/proxy/agentcp/agent.py +4 -0
- package/extensions/services/proxy/agentcp/agentcp.py +2494 -0
- package/extensions/services/proxy/agentcp/agentprofile.json +89 -0
- package/extensions/services/proxy/agentcp/ap/__init__.py +16 -0
- package/extensions/services/proxy/agentcp/ap/ap_client.py +316 -0
- package/extensions/services/proxy/agentcp/assets/images/wechat_qr.png +0 -0
- package/extensions/services/proxy/agentcp/backup/metrics.json +31 -0
- package/extensions/services/proxy/agentcp/base/__init__.py +20 -0
- package/extensions/services/proxy/agentcp/base/auth_client.py +257 -0
- package/extensions/services/proxy/agentcp/base/client.py +112 -0
- package/extensions/services/proxy/agentcp/base/env.py +34 -0
- package/extensions/services/proxy/agentcp/base/html_util.py +336 -0
- package/extensions/services/proxy/agentcp/base/log.py +98 -0
- package/extensions/services/proxy/agentcp/ca/__init__.py +17 -0
- package/extensions/services/proxy/agentcp/ca/ca_client.py +414 -0
- package/extensions/services/proxy/agentcp/ca/ca_root.py +74 -0
- package/extensions/services/proxy/agentcp/context/__init__.py +20 -0
- package/extensions/services/proxy/agentcp/context/context.py +73 -0
- package/extensions/services/proxy/agentcp/context/exceptions.py +114 -0
- package/extensions/services/proxy/agentcp/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/create_profile_weather.py +125 -0
- package/extensions/services/proxy/agentcp/db/__init__.py +15 -0
- package/extensions/services/proxy/agentcp/db/db_mananger.py +550 -0
- package/extensions/services/proxy/agentcp/docs/UDP_HEARTBEAT_FIX_REPORT.md +265 -0
- package/extensions/services/proxy/agentcp/docs/heartbeat_issue_analysis.md +291 -0
- package/extensions/services/proxy/agentcp/file/__init__.py +16 -0
- package/extensions/services/proxy/agentcp/file/file_client.py +141 -0
- package/extensions/services/proxy/agentcp/file/wss_binary_message.py +137 -0
- package/extensions/services/proxy/agentcp/hcp.py +299 -0
- package/extensions/services/proxy/agentcp/heartbeat/__init__.py +16 -0
- package/extensions/services/proxy/agentcp/heartbeat/heartbeat_client.py +360 -0
- package/extensions/services/proxy/agentcp/improved_scheduler.py +498 -0
- package/extensions/services/proxy/agentcp/llm_agent_utils.py +249 -0
- package/extensions/services/proxy/agentcp/llm_server.py +172 -0
- package/extensions/services/proxy/agentcp/mermaid.py +210 -0
- package/extensions/services/proxy/agentcp/message.py +149 -0
- package/extensions/services/proxy/agentcp/metrics.py +256 -0
- package/extensions/services/proxy/agentcp/monitoring/__init__.py +20 -0
- package/extensions/services/proxy/agentcp/monitoring/global_monitor.py +27 -0
- package/extensions/services/proxy/agentcp/monitoring/metrics_store.py +325 -0
- package/extensions/services/proxy/agentcp/monitoring/monitoring_service.py +269 -0
- package/extensions/services/proxy/agentcp/monitoring/sliding_window.py +222 -0
- package/extensions/services/proxy/agentcp/monitoring/standalone_reader.py +224 -0
- package/extensions/services/proxy/agentcp/msg/__init__.py +21 -0
- package/extensions/services/proxy/agentcp/msg/connection_manager.py +456 -0
- package/extensions/services/proxy/agentcp/msg/message_client.py +2058 -0
- package/extensions/services/proxy/agentcp/msg/message_serialize.py +263 -0
- package/extensions/services/proxy/agentcp/msg/open_ai_message.py +88 -0
- package/extensions/services/proxy/agentcp/msg/session_manager.py +1062 -0
- package/extensions/services/proxy/agentcp/msg/stream_client.py +267 -0
- package/extensions/services/proxy/agentcp/msg/websocket_file_receiver.py +89 -0
- package/extensions/services/proxy/agentcp/msg/ws_logger.py +685 -0
- package/extensions/services/proxy/agentcp/msg/wss_binary_message.py +137 -0
- package/extensions/services/proxy/agentcp/requirements.txt +7 -0
- package/extensions/services/proxy/agentcp/samples/agent_graph/README.md +37 -0
- package/extensions/services/proxy/agentcp/samples/agent_graph/agentprofile.json +89 -0
- package/extensions/services/proxy/agentcp/samples/agent_graph/create_profile.py +138 -0
- package/extensions/services/proxy/agentcp/samples/agent_graph/main.py +164 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/create_profile.py +123 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/llm/create_profile.py +129 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/llm/env.json +5 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/llm/main.py +146 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/main.py +123 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/readme.md +379 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/search/create_profile.py +129 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/search/main.py +28 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/tool/create_profile.py +129 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/tool/main.py +20 -0
- package/extensions/services/proxy/agentcp/samples/ali_amap/README.md +97 -0
- package/extensions/services/proxy/agentcp/samples/ali_amap/amap_agent.py +88 -0
- package/extensions/services/proxy/agentcp/samples/ali_amap/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/compute_agent/agent/powershell.py +228 -0
- package/extensions/services/proxy/agentcp/samples/compute_agent/agent/software.py +63 -0
- package/extensions/services/proxy/agentcp/samples/compute_agent/agent/tools.py +36 -0
- package/extensions/services/proxy/agentcp/samples/compute_agent/browser_user.py +41 -0
- package/extensions/services/proxy/agentcp/samples/deepseek/README.md +79 -0
- package/extensions/services/proxy/agentcp/samples/deepseek/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/deepseek/deepseek.py +42 -0
- package/extensions/services/proxy/agentcp/samples/dify_chat/README.md +78 -0
- package/extensions/services/proxy/agentcp/samples/dify_chat/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/dify_chat/dify_chat.py +47 -0
- package/extensions/services/proxy/agentcp/samples/dify_workflow/README.md +78 -0
- package/extensions/services/proxy/agentcp/samples/dify_workflow/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/dify_workflow/dify_workflow.py +46 -0
- package/extensions/services/proxy/agentcp/samples/executor/README.md +44 -0
- package/extensions/services/proxy/agentcp/samples/executor/agentprofile.json +89 -0
- package/extensions/services/proxy/agentcp/samples/executor/create_profile.py +139 -0
- package/extensions/services/proxy/agentcp/samples/executor/main.py +160 -0
- package/extensions/services/proxy/agentcp/samples/filereader/README.md +45 -0
- package/extensions/services/proxy/agentcp/samples/filereader/agentprofile.json +90 -0
- package/extensions/services/proxy/agentcp/samples/filereader/create_profile.py +137 -0
- package/extensions/services/proxy/agentcp/samples/filereader/main.py +253 -0
- package/extensions/services/proxy/agentcp/samples/filewriter/README.md +38 -0
- package/extensions/services/proxy/agentcp/samples/filewriter/agentprofile.json +91 -0
- package/extensions/services/proxy/agentcp/samples/filewriter/create_profile.py +138 -0
- package/extensions/services/proxy/agentcp/samples/filewriter/main.py +289 -0
- package/extensions/services/proxy/agentcp/samples/hcp/README.md +85 -0
- package/extensions/services/proxy/agentcp/samples/hcp/acp_weather_agent.zip +0 -0
- package/extensions/services/proxy/agentcp/samples/hcp/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/hcp/hcp.py +237 -0
- package/extensions/services/proxy/agentcp/samples/helloworld/README.md +68 -0
- package/extensions/services/proxy/agentcp/samples/helloworld/hello_world.py +40 -0
- package/extensions/services/proxy/agentcp/samples/llm_agent/MEADME.md +117 -0
- package/extensions/services/proxy/agentcp/samples/llm_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/llm_agent/qwen_agent.py +136 -0
- package/extensions/services/proxy/agentcp/samples/local_llm_agent/README.md +90 -0
- package/extensions/services/proxy/agentcp/samples/local_llm_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/local_llm_agent/main.py +49 -0
- package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/README.md +55 -0
- package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/main.py +23 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/README.md +103 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/main.py +69 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/README.md +58 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/main.py +25 -0
- package/extensions/services/proxy/agentcp/samples/qwen3/README.md +71 -0
- package/extensions/services/proxy/agentcp/samples/qwen3/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/qwen3/qwen3.py +37 -0
- package/extensions/services/proxy/agentcp/samples/qwen3_tools/README.md +133 -0
- package/extensions/services/proxy/agentcp/samples/qwen3_tools/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/qwen3_tools/qwen3_tools.py +98 -0
- package/extensions/services/proxy/agentcp/samples/search/create_profile_qwen.py +125 -0
- package/extensions/services/proxy/agentcp/samples/search/create_profile_search.py +125 -0
- package/extensions/services/proxy/agentcp/samples/search/qwen_agent.py +136 -0
- package/extensions/services/proxy/agentcp/samples/search/search_agent.py +170 -0
- package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/README.md +89 -0
- package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/main.py +44 -0
- package/extensions/services/proxy/agentcp/utils/__init__.py +15 -0
- package/extensions/services/proxy/agentcp/utils/file_util.py +117 -0
- package/extensions/services/proxy/agentcp/utils/proxy_bypass.py +99 -0
- package/extensions/services/proxy/agentcp/workflow.py +203 -0
- package/extensions/services/proxy/console_auth.py +109 -0
- package/extensions/services/proxy/evol/__init__.py +1 -0
- package/extensions/services/proxy/evol/config.py +37 -0
- package/extensions/services/proxy/evol/http/__init__.py +1 -0
- package/extensions/services/proxy/evol/http/async_http.py +551 -0
- package/extensions/services/proxy/evol/log.py +28 -0
- package/extensions/services/proxy/evol/presenter/__init__.py +2 -0
- package/extensions/services/proxy/evol/presenter/agentIdPresenter.py +1031 -0
- package/extensions/services/proxy/evol/presenter/apikeyPresenter.py +106 -0
- package/extensions/services/proxy/evol/presenter/configPresenter.py +1281 -0
- package/extensions/services/proxy/evol/presenter/userPresenter.py +477 -0
- package/extensions/services/proxy/evol/server/__init__.py +1 -0
- package/extensions/services/proxy/evol/server/claude_proxy_async.py +3430 -0
- package/extensions/services/proxy/evol/server/openclaw_proxy.py +1861 -0
- package/extensions/services/proxy/evol/server/proxy_config.py +15 -0
- package/extensions/services/proxy/evol/server/proxy_engine.py +501 -0
- package/extensions/services/proxy/evol/version.py +24 -0
- package/extensions/services/proxy/logs/websocket.log +260 -0
- package/extensions/services/proxy/main.py +240 -0
- package/extensions/services/proxy/requirements.txt +13 -0
- package/extensions/services/proxy/server.py +271 -0
- package/extensions/services/watchdog/entry.py +215 -26
- package/extensions/services/watchdog/module.md +1 -0
- package/extensions/services/watchdog/monitor.py +178 -38
- package/extensions/services/web/WEBSOCKET_STATUS.md +143 -0
- package/extensions/services/web/config_example.py +35 -0
- package/extensions/services/web/config_loader.py +110 -0
- package/extensions/services/web/entry.py +114 -26
- package/extensions/services/web/module.md +35 -24
- package/extensions/services/web/pairing.py +250 -0
- package/extensions/services/web/pairing_codes.jsonl +16 -0
- package/extensions/services/web/relay.py +643 -0
- package/extensions/services/web/relay_config.json5 +67 -0
- package/extensions/services/web/routes/routes_management_ws.py +127 -0
- package/extensions/services/web/routes/routes_rpc.py +89 -0
- package/extensions/services/web/routes/routes_test.py +61 -0
- package/extensions/services/web/routes/schemas.py +0 -22
- package/extensions/services/web/server.py +434 -99
- package/extensions/services/web/static/css/style.css +67 -28
- package/extensions/services/web/static/index.html +234 -44
- package/extensions/services/web/static/js/app.js +1335 -48
- package/extensions/services/web/static/js/kernel-client-example.js +161 -0
- package/extensions/services/web/static/js/kernel-client.js +383 -0
- package/extensions/services/web/static/js/registry-tests.js +558 -0
- package/extensions/services/web/static/js/token-manager.js +175 -0
- package/extensions/services/web/static/pairing.html +248 -0
- package/extensions/services/web/static/test_registry.html +262 -0
- package/extensions/services/web/web_config.json5 +29 -0
- package/kernel/entry.py +120 -32
- package/kernel/event_hub.py +141 -16
- package/kernel/module.md +60 -33
- package/kernel/registry_store.py +45 -36
- package/kernel/rpc_router.py +152 -59
- package/kernel/server.py +322 -26
- package/kite_cli/__init__.py +3 -0
- package/kite_cli/__main__.py +5 -0
- package/kite_cli/commands/__init__.py +1 -0
- package/kite_cli/commands/clean.py +101 -0
- package/kite_cli/commands/deps_install.py +67 -0
- package/kite_cli/commands/doctor.py +35 -0
- package/kite_cli/commands/env_check.py +45 -0
- package/kite_cli/commands/history.py +111 -0
- package/kite_cli/commands/info.py +96 -0
- package/kite_cli/commands/install.py +313 -0
- package/kite_cli/commands/list.py +143 -0
- package/kite_cli/commands/log.py +81 -0
- package/kite_cli/commands/prepare.py +49 -0
- package/kite_cli/commands/rollback.py +88 -0
- package/kite_cli/commands/search.py +73 -0
- package/kite_cli/commands/uninstall.py +85 -0
- package/kite_cli/commands/update.py +118 -0
- package/kite_cli/commands/venv_setup.py +56 -0
- package/kite_cli/core/__init__.py +1 -0
- package/kite_cli/core/checker.py +142 -0
- package/kite_cli/core/dependency.py +229 -0
- package/kite_cli/core/downloader.py +209 -0
- package/kite_cli/core/install_info.py +40 -0
- package/kite_cli/core/tool_installer.py +397 -0
- package/kite_cli/core/validator.py +78 -0
- package/kite_cli/main.py +317 -0
- package/kite_cli/utils/__init__.py +1 -0
- package/kite_cli/utils/i18n.py +252 -0
- package/kite_cli/utils/interactive.py +63 -0
- package/kite_cli/utils/operation_log.py +77 -0
- package/kite_cli/utils/paths.py +34 -0
- package/kite_cli/utils/version.py +308 -0
- package/launcher/entry.py +1124 -178
- package/launcher/logging_setup.py +104 -0
- package/launcher/module.md +46 -37
- package/launcher/module_scanner.py +11 -1
- package/main.py +4 -1
- package/package.json +9 -1
- package/python_version.json +4 -0
- package/requirements.txt +38 -0
- package/scripts/env-manager.js +328 -0
- package/scripts/plan_manager.py +315 -0
- package/scripts/python-env.js +79 -0
- package/scripts/scan_dependencies.py +461 -0
- package/scripts/setup-python-env.js +191 -0
- 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
|
package/launcher/module.md
CHANGED
|
@@ -1,37 +1,46 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: launcher
|
|
3
|
-
display_name:
|
|
4
|
-
version:
|
|
5
|
-
type: infrastructure
|
|
6
|
-
state: enabled
|
|
7
|
-
events:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
subscriptions: []
|
|
12
|
-
discovery:
|
|
13
|
-
test_modules:
|
|
14
|
-
type: scan_dir
|
|
15
|
-
path: test_modules
|
|
16
|
-
enabled: true
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
##
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
"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__/**",
|
package/requirements.txt
ADDED
|
@@ -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
|
+
};
|