openclaw-agent-dashboard 1.0.4

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 (111) hide show
  1. package/.github/workflows/release.yml +56 -0
  2. package/README.md +302 -0
  3. package/docs/CHANGELOG_AGENT_MODIFICATIONS.md +132 -0
  4. package/docs/RELEASE-LATEST.md +189 -0
  5. package/docs/RELEASE-MODEL-CONFIG.md +95 -0
  6. package/docs/release-guide.md +259 -0
  7. package/docs/release-operations-manual.md +167 -0
  8. package/docs/specs/tr3-install-system.md +580 -0
  9. package/docs/windows-collaboration-model-paths-troubleshooting.md +0 -0
  10. package/frontend/index.html +12 -0
  11. package/frontend/package-lock.json +1240 -0
  12. package/frontend/package.json +19 -0
  13. package/frontend/src/App.vue +331 -0
  14. package/frontend/src/components/AgentCard.vue +796 -0
  15. package/frontend/src/components/AgentConfigPanel.vue +539 -0
  16. package/frontend/src/components/AgentDetailPanel.vue +738 -0
  17. package/frontend/src/components/ErrorAnalysisView.vue +546 -0
  18. package/frontend/src/components/ErrorCenterPanel.vue +844 -0
  19. package/frontend/src/components/PerformanceMonitor.vue +515 -0
  20. package/frontend/src/components/SettingsPanel.vue +236 -0
  21. package/frontend/src/components/TokenAnalysisPanel.vue +683 -0
  22. package/frontend/src/components/chain/ChainEdge.vue +85 -0
  23. package/frontend/src/components/chain/ChainNode.vue +166 -0
  24. package/frontend/src/components/chain/TaskChainView.vue +425 -0
  25. package/frontend/src/components/chain/index.ts +3 -0
  26. package/frontend/src/components/chain/types.ts +70 -0
  27. package/frontend/src/components/collaboration/CollaborationFlowSection.vue +1032 -0
  28. package/frontend/src/components/collaboration/CollaborationFlowWrapper.vue +113 -0
  29. package/frontend/src/components/performance/PerformancePanel.vue +119 -0
  30. package/frontend/src/components/performance/PerformanceSection.vue +1137 -0
  31. package/frontend/src/components/tasks/TaskStatusSection.vue +973 -0
  32. package/frontend/src/components/timeline/TimelineConnector.vue +31 -0
  33. package/frontend/src/components/timeline/TimelineRound.vue +135 -0
  34. package/frontend/src/components/timeline/TimelineStep.vue +691 -0
  35. package/frontend/src/components/timeline/TimelineToolLink.vue +109 -0
  36. package/frontend/src/components/timeline/TimelineView.vue +540 -0
  37. package/frontend/src/components/timeline/index.ts +5 -0
  38. package/frontend/src/components/timeline/types.ts +120 -0
  39. package/frontend/src/composables/index.ts +7 -0
  40. package/frontend/src/composables/useDebounce.ts +48 -0
  41. package/frontend/src/composables/useRealtime.ts +52 -0
  42. package/frontend/src/composables/useState.ts +52 -0
  43. package/frontend/src/composables/useThrottle.ts +46 -0
  44. package/frontend/src/composables/useVirtualScroll.ts +106 -0
  45. package/frontend/src/main.ts +4 -0
  46. package/frontend/src/managers/EventDispatcher.ts +127 -0
  47. package/frontend/src/managers/RealtimeDataManager.ts +293 -0
  48. package/frontend/src/managers/StateManager.ts +128 -0
  49. package/frontend/src/managers/index.ts +5 -0
  50. package/frontend/src/types/collaboration.ts +135 -0
  51. package/frontend/src/types/index.ts +20 -0
  52. package/frontend/src/types/performance.ts +105 -0
  53. package/frontend/src/types/task.ts +38 -0
  54. package/frontend/vite.config.ts +18 -0
  55. package/package.json +22 -0
  56. package/plugin/README.md +99 -0
  57. package/plugin/config.json.example +1 -0
  58. package/plugin/index.js +250 -0
  59. package/plugin/openclaw.plugin.json +17 -0
  60. package/plugin/package.json +21 -0
  61. package/scripts/build-plugin.js +67 -0
  62. package/scripts/bundle.sh +62 -0
  63. package/scripts/install-plugin.sh +162 -0
  64. package/scripts/install-python-deps.js +346 -0
  65. package/scripts/install-python-deps.sh +226 -0
  66. package/scripts/install.js +512 -0
  67. package/scripts/install.sh +367 -0
  68. package/scripts/lib/common.js +490 -0
  69. package/scripts/lib/common.sh +137 -0
  70. package/scripts/release-pack.sh +110 -0
  71. package/scripts/start.js +50 -0
  72. package/scripts/test_available_models.py +284 -0
  73. package/scripts/test_websocket_ping.py +44 -0
  74. package/src/backend/agents.py +73 -0
  75. package/src/backend/api/__init__.py +1 -0
  76. package/src/backend/api/agent_config_api.py +90 -0
  77. package/src/backend/api/agents.py +73 -0
  78. package/src/backend/api/agents_config.py +75 -0
  79. package/src/backend/api/chains.py +126 -0
  80. package/src/backend/api/collaboration.py +902 -0
  81. package/src/backend/api/debug_paths.py +39 -0
  82. package/src/backend/api/error_analysis.py +146 -0
  83. package/src/backend/api/errors.py +281 -0
  84. package/src/backend/api/performance.py +784 -0
  85. package/src/backend/api/subagents.py +770 -0
  86. package/src/backend/api/timeline.py +144 -0
  87. package/src/backend/api/websocket.py +251 -0
  88. package/src/backend/collaboration.py +405 -0
  89. package/src/backend/data/__init__.py +1 -0
  90. package/src/backend/data/agent_config_manager.py +270 -0
  91. package/src/backend/data/chain_reader.py +299 -0
  92. package/src/backend/data/config_reader.py +153 -0
  93. package/src/backend/data/error_analyzer.py +430 -0
  94. package/src/backend/data/session_reader.py +445 -0
  95. package/src/backend/data/subagent_reader.py +244 -0
  96. package/src/backend/data/task_history.py +118 -0
  97. package/src/backend/data/timeline_reader.py +981 -0
  98. package/src/backend/errors.py +63 -0
  99. package/src/backend/main.py +89 -0
  100. package/src/backend/mechanism_reader.py +131 -0
  101. package/src/backend/mechanisms.py +32 -0
  102. package/src/backend/performance.py +474 -0
  103. package/src/backend/requirements.txt +5 -0
  104. package/src/backend/session_reader.py +238 -0
  105. package/src/backend/status/__init__.py +1 -0
  106. package/src/backend/status/error_detector.py +122 -0
  107. package/src/backend/status/status_calculator.py +301 -0
  108. package/src/backend/status_calculator.py +121 -0
  109. package/src/backend/subagent_reader.py +229 -0
  110. package/src/backend/watchers/__init__.py +4 -0
  111. package/src/backend/watchers/file_watcher.py +159 -0
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # OpenClaw Agent Dashboard 插件 - 安装/升级脚本
4
+ # 用法: npm run deploy(推荐)或 ./scripts/install-plugin.sh
5
+ #
6
+ # 选项:
7
+ # VERBOSE=1 显示详细输出(包括 npm/pip 的错误信息)
8
+ # DRY_RUN=1 仅预览,不执行实际安装
9
+ #
10
+ # 配置目录与 OpenClaw 一致:OPENCLAW_STATE_DIR > OPENCLAW_HOME > HOME
11
+ #
12
+ set -euo pipefail
13
+
14
+ cd "$(dirname "$0")/.."
15
+ ROOT=$(pwd)
16
+ SCRIPT_DIR="$ROOT/scripts"
17
+
18
+ # 引入公共库
19
+ source "$SCRIPT_DIR/lib/common.sh"
20
+
21
+ # 环境变量
22
+ VERBOSE="${VERBOSE:-0}"
23
+ DRY_RUN="${DRY_RUN:-0}"
24
+
25
+ # ============================================
26
+ # 本脚本特有函数
27
+ # ============================================
28
+
29
+ # 获取已安装版本
30
+ get_installed_version() {
31
+ local plugin_path="$1"
32
+ if [ -f "$plugin_path/openclaw.plugin.json" ]; then
33
+ parse_json_version "$plugin_path/openclaw.plugin.json"
34
+ else
35
+ echo ""
36
+ fi
37
+ }
38
+
39
+ # 检查命令是否存在
40
+ check_cmd() {
41
+ if ! command -v "$1" &>/dev/null; then
42
+ log_error "未找到 $1,请先安装: $2"
43
+ exit 1
44
+ fi
45
+ }
46
+
47
+ # ============================================
48
+ # 主流程
49
+ # ============================================
50
+
51
+ OPENCLAW_CONFIG_DIR=$(resolve_openclaw_config_dir)
52
+ PLUGIN_PATH="${OPENCLAW_CONFIG_DIR}/extensions/openclaw-agent-dashboard"
53
+ NEW_VERSION=$(parse_json_version "$ROOT/plugin/openclaw.plugin.json")
54
+ OLD_VERSION=$(get_installed_version "$PLUGIN_PATH")
55
+
56
+ log_info "[安装] 配置目录: $OPENCLAW_CONFIG_DIR"
57
+ log_info "[安装] 插件路径: $PLUGIN_PATH"
58
+ echo ""
59
+
60
+ # 显示标题(区分安装/升级)
61
+ if [ -n "$OLD_VERSION" ] && [ -d "$PLUGIN_PATH" ]; then
62
+ log_info "=== OpenClaw Agent Dashboard 插件升级 ==="
63
+ echo ""
64
+ log_info " $OLD_VERSION → $NEW_VERSION"
65
+ else
66
+ log_info "=== OpenClaw Agent Dashboard 插件安装 ==="
67
+ echo ""
68
+ log_info " 版本: $NEW_VERSION"
69
+ fi
70
+
71
+ # dry-run 模式:仅预览
72
+ if [ "$DRY_RUN" = "1" ]; then
73
+ echo ""
74
+ log_info "[DRY-RUN] 将执行以下操作:"
75
+ log_info " - 安装插件到: $PLUGIN_PATH"
76
+ log_info " - 安装 Python 依赖到 venv 或 --user"
77
+ log_ok "预览完成,未执行实际安装"
78
+ exit 0
79
+ fi
80
+
81
+ # 1. 检查前置条件
82
+ check_cmd node "https://nodejs.org"
83
+ check_cmd python3 "https://www.python.org"
84
+ check_cmd openclaw "npm install -g openclaw"
85
+
86
+ echo ""
87
+ log_ok "前置条件检查通过"
88
+
89
+ # 2. 构建前端(若通过 npm run deploy 调用,pack 已构建,跳过)
90
+ if [ -d "$ROOT/frontend/dist" ] && [ -n "$(ls -A "$ROOT/frontend/dist" 2>/dev/null)" ]; then
91
+ log_step "1/4 前端已构建,跳过"
92
+ else
93
+ log_step "1/4 构建前端..."
94
+ (cd frontend && run_silent npm install && npm run build)
95
+ fi
96
+
97
+ # 3. 打包插件(若通过 npm run deploy 调用,pack 已完成,跳过)
98
+ if [ -d "$ROOT/plugin/dashboard" ] && [ -f "$ROOT/plugin/dashboard/main.py" ]; then
99
+ log_step "2/4 插件已打包,跳过"
100
+ else
101
+ log_step "2/4 打包插件..."
102
+ node scripts/build-plugin.js
103
+ fi
104
+
105
+ # 4. 安装插件(升级时用 uninstall 清理配置+目录,避免 plugins.allow 引用已删目录导致校验失败)
106
+ PLUGIN_ID="openclaw-agent-dashboard"
107
+ if [ -d "$PLUGIN_PATH" ]; then
108
+ log_step "3/4 移除旧版本后安装..."
109
+ log_info " 执行: openclaw plugins uninstall $PLUGIN_ID"
110
+ if run_silent openclaw plugins uninstall "$PLUGIN_ID" --force; then
111
+ log_ok " 已卸载(配置记录)"
112
+ else
113
+ log_warn " uninstall 失败(可能未注册)"
114
+ fi
115
+ # uninstall 只删除配置记录,需要手动删除物理目录
116
+ rm -rf "$PLUGIN_PATH"
117
+ log_ok " 已删除旧目录"
118
+ else
119
+ log_step "3/4 安装插件..."
120
+ fi
121
+ log_info " 目标: $PLUGIN_PATH"
122
+ log_info " 执行: openclaw plugins install ./plugin"
123
+ if ! openclaw plugins install ./plugin; then
124
+ log_error "插件安装失败"
125
+ exit 1
126
+ fi
127
+ log_ok " 插件已安装"
128
+
129
+ # 5. 安装 Python 依赖
130
+ # 详见 docs/python-environment-compatibility.md
131
+ if [ -f "$PLUGIN_PATH/dashboard/requirements.txt" ]; then
132
+ if [ -n "$OLD_VERSION" ]; then
133
+ log_step "4/4 检查 Python 依赖..."
134
+ else
135
+ log_step "4/4 安装 Python 依赖..."
136
+ fi
137
+
138
+ # 调用独立的 Python 依赖安装脚本
139
+ DEPS_OPTS=""
140
+ [ "$VERBOSE" = "1" ] && DEPS_OPTS="--verbose"
141
+
142
+ if ! bash "$SCRIPT_DIR/install-python-deps.sh" "$PLUGIN_PATH" $DEPS_OPTS; then
143
+ exit 1
144
+ fi
145
+ else
146
+ log_warn "插件未正确安装(缺少 requirements.txt)"
147
+ fi
148
+
149
+ # 完成
150
+ echo ""
151
+ if [ -n "$OLD_VERSION" ]; then
152
+ log_ok "=== 升级完成 ($OLD_VERSION → $NEW_VERSION) ==="
153
+ else
154
+ log_ok "=== 安装完成 (v$NEW_VERSION) ==="
155
+ fi
156
+ echo ""
157
+ log_info "执行任意 openclaw 命令(如 openclaw tui)时,Dashboard 会自动启动。"
158
+ log_info "访问地址: http://localhost:38271"
159
+ echo ""
160
+ log_info "若端口被占用,可创建 ~/.openclaw-agent-dashboard/config.json 设置端口:"
161
+ log_info ' {"port": 38271}'
162
+ echo ""
@@ -0,0 +1,346 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Python 依赖安装脚本(跨平台)
4
+ * 用法: node scripts/install-python-deps.js <plugin_dir> [--verbose]
5
+ *
6
+ * 策略:
7
+ * 1. venv(推荐,不受 PEP 668 影响)
8
+ * 2. pip --user(兜底)
9
+ *
10
+ * 选项:
11
+ * --verbose, -v 显示详细输出
12
+ * --venv-only 仅使用 venv,不回退 pip
13
+ */
14
+
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+ const {
18
+ logInfo,
19
+ logOk,
20
+ logWarn,
21
+ logError,
22
+ detectOS,
23
+ commandExists,
24
+ runCommand,
25
+ rmrf,
26
+ } = require('./lib/common');
27
+
28
+ // ============================================
29
+ // 参数解析
30
+ // ============================================
31
+
32
+ /**
33
+ * 解析命令行参数
34
+ * @returns {{ pluginDir: string | null, verbose: boolean, venvOnly: boolean }}
35
+ */
36
+ function parseArgs() {
37
+ const args = process.argv.slice(2);
38
+ let pluginDir = null;
39
+ let verbose = false;
40
+ let venvOnly = false;
41
+
42
+ for (const arg of args) {
43
+ if (arg === '--verbose' || arg === '-v') {
44
+ verbose = true;
45
+ } else if (arg === '--venv-only') {
46
+ venvOnly = true;
47
+ } else if (!arg.startsWith('-')) {
48
+ pluginDir = arg;
49
+ }
50
+ }
51
+
52
+ return { pluginDir, verbose, venvOnly };
53
+ }
54
+
55
+ // ============================================
56
+ // Python 环境检测
57
+ // ============================================
58
+
59
+ /**
60
+ * 检查 venv 模块是否可用
61
+ * @returns {boolean}
62
+ */
63
+ function checkVenvModule() {
64
+ const result = runCommand('python3', ['-c', 'import venv'], { silent: true });
65
+ return result.success;
66
+ }
67
+
68
+ /**
69
+ * 检查 pip 模块是否可用
70
+ * @returns {boolean}
71
+ */
72
+ function checkPipModule() {
73
+ // 尝试 python3 -m pip
74
+ let result = runCommand('python3', ['-m', 'pip', '--version'], { silent: true });
75
+ if (result.success) return true;
76
+
77
+ // 尝试 pip3
78
+ if (commandExists('pip3')) return true;
79
+
80
+ // 尝试 pip
81
+ if (commandExists('pip')) return true;
82
+
83
+ return false;
84
+ }
85
+
86
+ /**
87
+ * 获取 venv Python 路径
88
+ * @param {string} venvDir
89
+ * @returns {string | null}
90
+ */
91
+ function getVenvPython(venvDir) {
92
+ // Unix: venv/bin/python
93
+ const unixPath = path.join(venvDir, 'bin', 'python');
94
+ if (fs.existsSync(unixPath)) return unixPath;
95
+
96
+ // Windows: venv\Scripts\python.exe
97
+ const winPath = path.join(venvDir, 'Scripts', 'python.exe');
98
+ if (fs.existsSync(winPath)) return winPath;
99
+
100
+ return null;
101
+ }
102
+
103
+ // ============================================
104
+ // Python 依赖安装
105
+ // ============================================
106
+
107
+ /**
108
+ * 使用 venv 安装依赖
109
+ * @param {string} reqFile
110
+ * @param {string} venvDir
111
+ * @param {boolean} silent
112
+ * @returns {boolean}
113
+ */
114
+ function installWithVenv(reqFile, venvDir, silent) {
115
+ logInfo(' 尝试: venv(推荐,不受 PEP 668 影响)');
116
+
117
+ // 清理旧 venv
118
+ if (fs.existsSync(venvDir)) {
119
+ rmrf(venvDir);
120
+ }
121
+
122
+ // 创建 venv
123
+ logInfo(' 创建虚拟环境...');
124
+ const createResult = runCommand('python3', ['-m', 'venv', venvDir], { silent });
125
+ if (!createResult.success) {
126
+ logWarn(' venv 创建失败');
127
+ if (!silent) {
128
+ console.log(' 错误:', createResult.output);
129
+ }
130
+ return false;
131
+ }
132
+
133
+ // 获取 venv Python 路径
134
+ const venvPython = getVenvPython(venvDir);
135
+ if (!venvPython) {
136
+ logWarn(' 无法找到 venv Python');
137
+ return false;
138
+ }
139
+
140
+ // 升级 pip(静默,失败不影响)
141
+ runCommand(venvPython, ['-m', 'pip', 'install', '--upgrade', 'pip', '-q'], { silent: true });
142
+
143
+ // 安装依赖
144
+ logInfo(' 安装依赖...');
145
+ const installResult = runCommand(
146
+ venvPython,
147
+ ['-m', 'pip', 'install', '-r', reqFile, '-q'],
148
+ { silent, timeout: 180000 }
149
+ );
150
+
151
+ if (!installResult.success) {
152
+ logWarn(' venv 安装依赖失败');
153
+ if (!silent) {
154
+ console.log(' 错误:', installResult.output);
155
+ }
156
+ return false;
157
+ }
158
+
159
+ return true;
160
+ }
161
+
162
+ /**
163
+ * 使用 pip --user 安装依赖
164
+ * @param {string} reqFile
165
+ * @param {boolean} silent
166
+ * @returns {{ success: boolean, method: string | null }}
167
+ */
168
+ function installWithPipUser(reqFile, silent) {
169
+ logInfo(' 尝试: pip --user(PEP 668 兜底)');
170
+
171
+ const pipCommands = [
172
+ { cmd: 'python3', args: ['-m', 'pip', 'install', '-r', reqFile, '-q', '--user'], name: 'python3 -m pip --user' },
173
+ { cmd: 'python3', args: ['-m', 'pip', 'install', '-r', reqFile, '-q'], name: 'python3 -m pip' },
174
+ { cmd: 'pip', args: ['install', '-r', reqFile, '-q', '--user'], name: 'pip --user' },
175
+ { cmd: 'pip3', args: ['install', '-r', reqFile, '-q', '--user'], name: 'pip3 --user' },
176
+ ];
177
+
178
+ for (const { cmd, args, name } of pipCommands) {
179
+ if (!commandExists(cmd)) continue;
180
+
181
+ const result = runCommand(cmd, args, { silent, timeout: 180000 });
182
+ if (result.success) {
183
+ return { success: true, method: name };
184
+ }
185
+ }
186
+
187
+ return { success: false, method: null };
188
+ }
189
+
190
+ /**
191
+ * 安装 Python 依赖
192
+ * @param {string} pluginDir
193
+ * @param {object} options
194
+ * @param {boolean} [options.verbose]
195
+ * @param {boolean} [options.venvOnly]
196
+ * @returns {boolean}
197
+ */
198
+ function installPythonDeps(pluginDir, options = {}) {
199
+ const { verbose = false, venvOnly = false } = options;
200
+ const reqFile = path.join(pluginDir, 'dashboard', 'requirements.txt');
201
+ const venvDir = path.join(pluginDir, 'dashboard', '.venv');
202
+
203
+ // 检查 requirements.txt
204
+ if (!fs.existsSync(reqFile)) {
205
+ logWarn('未找到 requirements.txt');
206
+ return false;
207
+ }
208
+
209
+ const silent = !verbose;
210
+ let success = false;
211
+ let method = null;
212
+
213
+ // 策略 1: venv(推荐)
214
+ if (checkVenvModule()) {
215
+ if (installWithVenv(reqFile, venvDir, silent)) {
216
+ success = true;
217
+ method = 'venv';
218
+ }
219
+ } else {
220
+ logWarn(' venv 模块不可用');
221
+ }
222
+
223
+ // 策略 2: pip --user 兜底
224
+ if (!success && !venvOnly) {
225
+ const result = installWithPipUser(reqFile, silent);
226
+ if (result.success) {
227
+ success = true;
228
+ method = result.method;
229
+ }
230
+ }
231
+
232
+ // 结果
233
+ if (success) {
234
+ logOk(`Python 依赖已就绪 (${method})`);
235
+ return true;
236
+ } else {
237
+ logError('Python 依赖安装失败');
238
+ printPythonDepsHelp(reqFile);
239
+ return false;
240
+ }
241
+ }
242
+
243
+ // ============================================
244
+ // 帮助信息
245
+ // ============================================
246
+
247
+ /**
248
+ * 打印 Python 依赖安装帮助
249
+ * @param {string} reqFile
250
+ */
251
+ function printPythonDepsHelp(reqFile) {
252
+ const os = detectOS();
253
+
254
+ console.log('');
255
+ console.log('========================================');
256
+ console.log('请检查以下系统依赖是否已安装:');
257
+ console.log('========================================');
258
+ console.log('');
259
+
260
+ switch (os) {
261
+ case 'linux':
262
+ console.log('检测到 Linux 系统');
263
+ console.log('');
264
+ console.log('Debian/Ubuntu:');
265
+ console.log(' sudo apt update && sudo apt install python3 python3-pip python3-venv');
266
+ console.log('');
267
+ console.log('Fedora/CentOS/RHEL:');
268
+ console.log(' sudo dnf install python3 python3-pip');
269
+ console.log('');
270
+ break;
271
+
272
+ case 'macos':
273
+ console.log('检测到 macOS 系统');
274
+ console.log('');
275
+ console.log('使用 Homebrew:');
276
+ console.log(' brew install python3');
277
+ console.log('');
278
+ break;
279
+
280
+ case 'windows':
281
+ console.log('检测到 Windows 系统');
282
+ console.log('');
283
+ console.log('1. 从 https://www.python.org 下载安装 Python 3');
284
+ console.log('2. 安装时务必勾选 "Add Python to PATH"');
285
+ console.log('3. 安装完成后重新打开终端');
286
+ console.log('');
287
+ break;
288
+
289
+ default:
290
+ console.log('请确保已安装:');
291
+ console.log(' - Python 3');
292
+ console.log(' - pip (python3-pip)');
293
+ console.log(' - venv 模块 (python3-venv,Linux 通常需要单独安装)');
294
+ console.log('');
295
+ }
296
+
297
+ console.log('========================================');
298
+ console.log('安装系统依赖后,重新执行:');
299
+ console.log('========================================');
300
+ console.log('');
301
+ console.log(' npm run deploy');
302
+ console.log('');
303
+ console.log('或手动安装依赖:');
304
+ console.log('');
305
+ console.log(` python3 -m pip install -r ${reqFile} --user`);
306
+ console.log('');
307
+ console.log('========================================');
308
+ console.log('调试模式:');
309
+ console.log('========================================');
310
+ console.log('');
311
+ console.log(' VERBOSE=1 npm run deploy');
312
+ console.log('');
313
+ }
314
+
315
+ // ============================================
316
+ // 主函数
317
+ // ============================================
318
+
319
+ function main() {
320
+ const { pluginDir, verbose, venvOnly } = parseArgs();
321
+
322
+ // 检查参数
323
+ if (!pluginDir) {
324
+ console.log('用法: node scripts/install-python-deps.js <plugin_dir> [options]');
325
+ console.log('');
326
+ console.log('参数:');
327
+ console.log(' plugin_dir 插件安装目录 (必须)');
328
+ console.log('');
329
+ console.log('选项:');
330
+ console.log(' --verbose, -v 显示详细输出');
331
+ console.log(' --venv-only 仅使用 venv,不回退 pip');
332
+ process.exit(1);
333
+ }
334
+
335
+ // 检查目录
336
+ if (!fs.existsSync(pluginDir)) {
337
+ logError(`插件目录不存在: ${pluginDir}`);
338
+ process.exit(1);
339
+ }
340
+
341
+ // 执行安装
342
+ const success = installPythonDeps(pluginDir, { verbose, venvOnly });
343
+ process.exit(success ? 0 : 1);
344
+ }
345
+
346
+ main();