@zshuangmu/agenthub 0.4.14 → 0.4.16

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 (43) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +268 -268
  3. package/package.json +41 -41
  4. package/src/api-server.js +518 -244
  5. package/src/cli.js +714 -671
  6. package/src/commands/api.js +9 -9
  7. package/src/commands/doctor.js +335 -335
  8. package/src/commands/info.js +15 -15
  9. package/src/commands/install.js +56 -56
  10. package/src/commands/list.js +78 -78
  11. package/src/commands/pack.js +249 -156
  12. package/src/commands/publish-remote.js +9 -9
  13. package/src/commands/publish.js +7 -7
  14. package/src/commands/rollback.js +59 -59
  15. package/src/commands/search.js +14 -14
  16. package/src/commands/serve.js +9 -9
  17. package/src/commands/stats.js +105 -105
  18. package/src/commands/uninstall.js +76 -76
  19. package/src/commands/update.js +54 -54
  20. package/src/commands/verify.js +133 -133
  21. package/src/commands/versions.js +75 -75
  22. package/src/commands/web.js +9 -9
  23. package/src/index.js +18 -18
  24. package/src/lib/auth.js +301 -0
  25. package/src/lib/bundle-transfer.js +58 -58
  26. package/src/lib/colors.js +60 -60
  27. package/src/lib/database.js +450 -244
  28. package/src/lib/debug.js +135 -135
  29. package/src/lib/fs-utils.js +107 -50
  30. package/src/lib/html.js +2163 -1824
  31. package/src/lib/http.js +168 -168
  32. package/src/lib/install.js +60 -60
  33. package/src/lib/manifest.js +124 -124
  34. package/src/lib/openclaw-config.js +40 -40
  35. package/src/lib/permissions.js +105 -0
  36. package/src/lib/privacy-engine.js +220 -0
  37. package/src/lib/registry.js +130 -130
  38. package/src/lib/remote.js +11 -11
  39. package/src/lib/security-scanner.js +233 -233
  40. package/src/lib/signing.js +158 -0
  41. package/src/lib/version-manager.js +77 -77
  42. package/src/server.js +176 -176
  43. package/src/web-server.js +135 -135
package/src/cli.js CHANGED
@@ -1,671 +1,714 @@
1
- #!/usr/bin/env node
2
- /**
3
- * AgentHub CLI
4
- * AI Agent 打包与分发平台
5
- *
6
- * 根据 PRD v1.1 规范实现
7
- */
8
-
9
- import {
10
- infoCommand,
11
- installCommand,
12
- verifyCommand,
13
- formatVerifyOutput,
14
- packCommand,
15
- publishCommand,
16
- publishRemoteCommand,
17
- serveCommand,
18
- searchCommand,
19
- apiCommand,
20
- webCommand,
21
- updateCommand,
22
- rollbackCommand,
23
- listCommand,
24
- formatListOutput,
25
- statsCommand,
26
- formatStatsOutput,
27
- versionsCommand,
28
- formatVersionsOutput,
29
- doctorCommand,
30
- } from "./index.js";
31
- import { uninstallCommand, formatUninstallOutput } from "./commands/uninstall.js";
32
-
33
- import { success, error, warning, info as infoColor, highlight, muted, symbols } from "./lib/colors.js";
34
- import { setVerbose, debug } from "./lib/debug.js";
35
-
36
- import { createRequire } from "node:module";
37
- const require = createRequire(import.meta.url);
38
- const VERSION = require("../package.json").version;
39
-
40
- /**
41
- * 验证必需参数,如果缺失则打印错误并设置退出码
42
- * @param {string} arg - 要验证的参数
43
- * @param {string} message - 错误消息
44
- * @returns {boolean} 参数是否存在
45
- */
46
- function requireArg(arg, message) {
47
- if (!arg) {
48
- console.error(error(message));
49
- process.exitCode = 1;
50
- return false;
51
- }
52
- return true;
53
- }
54
-
55
- function printHelp() {
56
- console.log(`
57
- AgentHub v${VERSION} - AI Agent 打包与分发平台
58
-
59
- 用法:
60
- agenthub <command> [options]
61
-
62
- 命令:
63
- pack 打包 OpenClaw 工作区为 Agent Bundle
64
- publish 发布 Bundle 到本地 Registry
65
- publish-remote 发布 Bundle 到远程服务器
66
- install 安装 Agent 到目标工作区(默认当前目录)
67
- search 搜索 Registry 中的 Agent
68
- info 查看 Agent 详情
69
- list 列出当前目录/指定目录的已安装 Agent
70
- uninstall 卸载已安装的 Agent
71
- verify 校验已安装 Agent 是否完整可用
72
- versions 查看 Agent 版本历史
73
- update 更新已安装 Agent 到最新版
74
- rollback 回滚已安装 Agent 到指定版本
75
- stats 查看 Agent 统计信息
76
- doctor 诊断 AgentHub 安装和环境问题
77
- serve 启动 Web + API 服务
78
- api 仅启动 API 后端服务
79
- web 仅启动 Web 前端服务
80
-
81
- 选项:
82
- --help, -h 显示帮助信息
83
- --version, -v 显示版本号
84
- --verbose 显示详细日志信息
85
-
86
- 详细帮助:
87
- agenthub <command> --help
88
-
89
- 示例:
90
- # 打包 Agent
91
- agenthub pack --workspace ./my-workspace --config openclaw.json --output ./bundles
92
-
93
- # 发布 Agent
94
- agenthub publish ./bundles/my-agent.agent --registry ./.registry
95
-
96
- # 安装 Agent
97
- agenthub install my-agent --registry ./.registry --target-workspace ./workspace
98
-
99
- # 搜索 Agent
100
- agenthub search "code review" --registry ./.registry
101
-
102
- # 启动完整服务(前端+后端)
103
- agenthub serve --registry ./.registry --port 3000
104
-
105
- `);
106
- }
107
-
108
- function printCommandHelp(command) {
109
- const helps = {
110
- pack: `
111
- agenthub pack - 打包 Agent
112
-
113
- 用法:
114
- agenthub pack --workspace <dir> --config <file> --output <dir>
115
-
116
- 选项:
117
- --workspace <dir> OpenClaw 工作区目录 (必需)
118
- --config <file> openclaw.json 配置文件路径 (必需)
119
- --output <dir> 输出目录 (默认: ./bundles)
120
- --name <name> Agent 名称 (默认: 工作区目录名)
121
- --version <ver> 版本号 (默认: 1.0.0)
122
- --tags <tags> 标签,逗号分隔
123
- --category <cat> 分类
124
- --featured 标记为精选 Agent
125
-
126
- 示例:
127
- agenthub pack --workspace ./my-agent --config ./openclaw.json
128
- agenthub pack --workspace ./my-agent --config ./openclaw.json --version 2.0.0
129
- agenthub pack --workspace ./my-agent --config ./openclaw.json --name "Code Helper" --featured
130
- `,
131
- publish: `
132
- agenthub publish - 发布 Agent
133
-
134
- 用法:
135
- agenthub publish <bundle-dir> --registry <dir>
136
-
137
- 选项:
138
- --registry <dir> Registry 目录 (必需)
139
-
140
- 示例:
141
- agenthub publish ./bundles/my-agent.agent --registry ./.registry
142
- `,
143
- install: `
144
- agenthub install - 安装 Agent
145
-
146
- 用法:
147
- agenthub install <agent-slug>[:version] [--registry <dir> | --server <url>] --target-workspace <dir>
148
-
149
- 选项:
150
- --registry <dir> 本地 Registry 目录(与 --server 二选一)
151
- --server <url> 远程服务器地址(默认: https://agenthub.cyou)
152
- --target-workspace <dir> 目标工作区目录 (必需)
153
- --force 强制覆盖
154
-
155
- 示例:
156
- agenthub install code-review-assistant --registry ./.registry --target-workspace ./workspace
157
- agenthub install my-agent:1.0.0 --server https://agenthub.cyou --target-workspace ./workspace
158
- agenthub install meeting-minutes-assistant --target-workspace ./workspace
159
- `,
160
- search: `
161
- agenthub search - 搜索 Agent
162
-
163
- 用法:
164
- agenthub search <query> --registry <dir>
165
-
166
- 选项:
167
- --registry <dir> Registry 目录 (必需)
168
- --json JSON 格式输出
169
-
170
- 示例:
171
- agenthub search "code review" --registry ./.registry
172
- agenthub search "" --registry ./.registry # 列出所有
173
- agenthub search "code" --registry ./.registry --json
174
- `,
175
- list: `
176
- agenthub list - 列出已安装 Agent
177
-
178
- 用法:
179
- agenthub list [--target-workspace <dir>] [--json]
180
-
181
- 选项:
182
- --target-workspace <dir> 指定工作区目录(可选)
183
- --json JSON 格式输出
184
-
185
- 示例:
186
- agenthub list
187
- agenthub list --target-workspace ./my-workspace
188
- agenthub list --json
189
- agenthub list --target-workspace ./my-workspace
190
- `,
191
- uninstall: `
192
- agenthub uninstall - 卸载已安装 Agent
193
-
194
- 用法:
195
- agenthub uninstall <agent-slug> [--target-workspace <dir>]
196
-
197
- 选项:
198
- --target-workspace <dir> 指定工作区目录(可选)
199
-
200
- 示例:
201
- agenthub uninstall my-agent
202
- agenthub uninstall my-agent --target-workspace ./my-workspace
203
- `,
204
- verify: `
205
- agenthub verify - 校验已安装 Agent
206
-
207
- 用法:
208
- agenthub verify [agent-slug] [--registry <dir> | --server <url>] [--target-workspace <dir>]
209
-
210
- 选项:
211
- --registry <dir> 本地 Registry 目录(与 --server 二选一)
212
- --server <url> 远程服务器地址(默认: https://agenthub.cyou)
213
- --target-workspace <dir> 目标工作区目录(默认当前目录)
214
-
215
- 示例:
216
- agenthub verify workspace --registry ./.registry --target-workspace ./my-workspace
217
- agenthub verify workspace --server https://agenthub.cyou --target-workspace ./my-workspace
218
- `,
219
- versions: `
220
- agenthub versions - 查看版本历史
221
-
222
- 用法:
223
- agenthub versions <agent-slug> [--registry <dir> | --server <url>]
224
-
225
- 选项:
226
- --registry <dir> 本地 Registry 目录(与 --server 二选一)
227
- --server <url> 远程服务器地址(默认: https://agenthub.cyou)
228
-
229
- 示例:
230
- agenthub versions workspace --registry ./.registry
231
- agenthub versions workspace --server https://agenthub.cyou
232
- `,
233
- update: `
234
- agenthub update - 更新 Agent 到最新版
235
-
236
- 用法:
237
- agenthub update <agent-slug> [--registry <dir> | --server <url>] --target-workspace <dir>
238
-
239
- 选项:
240
- --registry <dir> 本地 Registry 目录(与 --server 二选一)
241
- --server <url> 远程服务器地址(默认: https://agenthub.cyou)
242
- --target-workspace <dir> 目标工作区目录 (必需)
243
-
244
- 示例:
245
- agenthub update workspace --registry ./.registry --target-workspace ./my-workspace
246
- agenthub update workspace --server https://agenthub.cyou --target-workspace ./my-workspace
247
- `,
248
- rollback: `
249
- agenthub rollback - 回滚 Agent 到指定版本
250
-
251
- 用法:
252
- agenthub rollback <agent-slug> --to <version> [--registry <dir> | --server <url>] --target-workspace <dir>
253
-
254
- 选项:
255
- --to <version> 目标版本 (必需)
256
- --registry <dir> 本地 Registry 目录(与 --server 二选一)
257
- --server <url> 远程服务器地址(默认: https://agenthub.cyou)
258
- --target-workspace <dir> 目标工作区目录 (必需)
259
-
260
- 示例:
261
- agenthub rollback workspace --to 1.0.0 --registry ./.registry --target-workspace ./my-workspace
262
- agenthub rollback workspace --to 1.0.0 --server https://agenthub.cyou --target-workspace ./my-workspace
263
- `,
264
- info: `
265
- agenthub info - 查看 Agent 详情
266
-
267
- 用法:
268
- agenthub info <agent-slug> [--registry <dir> | --server <url>]
269
-
270
- 选项:
271
- --registry <dir> 本地 Registry 目录(与 --server 二选一)
272
- --server <url> 远程服务器地址(默认: https://agenthub.cyou)
273
- --json JSON 格式输出
274
-
275
- 示例:
276
- agenthub info code-review-assistant --registry ./.registry
277
- agenthub info my-agent --server https://agenthub.cyou --json
278
- `,
279
- "publish-remote": `
280
- agenthub publish-remote - 发布 Agent 到远程服务器
281
-
282
- 用法:
283
- agenthub publish-remote <bundle-dir> --server <url>
284
-
285
- 选项:
286
- --server <url> 远程服务器地址(默认: https://agenthub.cyou)
287
-
288
- 示例:
289
- agenthub publish-remote ./bundles/my-agent.agent
290
- agenthub publish-remote ./bundles/my-agent.agent --server https://agenthub.cyou
291
- `,
292
- stats: `
293
- agenthub stats - 查看 Agent 统计信息
294
-
295
- 用法:
296
- agenthub stats <agent-slug> --registry <dir>
297
-
298
- 选项:
299
- --registry <dir> Registry 目录 (必需)
300
-
301
- 示例:
302
- agenthub stats workspace --registry ./.registry
303
- `,
304
- doctor: `
305
- agenthub doctor - 诊断 AgentHub 安装和环境问题
306
-
307
- 用法:
308
- agenthub doctor [options]
309
-
310
- 选项:
311
- --full 运行完整诊断(包括测试套件)
312
- --no-network 跳过网络连接检查
313
- --server <url> 指定服务器地址检查(默认: https://agenthub.cyou)
314
-
315
- 示例:
316
- agenthub doctor
317
- agenthub doctor --full
318
- agenthub doctor --no-network
319
- `,
320
- serve: `
321
- agenthub serve - 启动完整服务(前端+后端)
322
-
323
- 用法:
324
- agenthub serve --registry <dir> --port <port>
325
-
326
- 选项:
327
- --registry <dir> Registry 目录 (必需)
328
- --port <port> 前端端口号 (默认: 3000)
329
- --api-port <port> 后端 API 端口号 (默认: 3001)
330
- --host <host> 监听地址 (默认: 0.0.0.0)
331
-
332
- 示例:
333
- agenthub serve --registry ./.registry --port 3000
334
- agenthub serve --registry ./.registry --host 127.0.0.1
335
- `,
336
- api: `
337
- agenthub api - 仅启动 API 后端服务
338
-
339
- 用法:
340
- agenthub api --registry <dir> --port <port>
341
-
342
- 选项:
343
- --registry <dir> Registry 目录 (必需)
344
- --port <port> API 端口号 (默认: 3001)
345
- --host <host> 监听地址 (默认: 0.0.0.0)
346
-
347
- 示例:
348
- agenthub api --registry ./.registry --port 3001
349
- `,
350
- web: `
351
- agenthub web - 仅启动 Web 前端服务
352
-
353
- 用法:
354
- agenthub web --port <port> --api-base <url>
355
-
356
- 选项:
357
- --port <port> Web 端口号 (默认: 3000)
358
- --api-base <url> API 服务地址 (默认: http://127.0.0.1:3001)
359
- --host <host> 监听地址 (默认: 0.0.0.0)
360
-
361
- 示例:
362
- agenthub web --port 3000 --api-base http://127.0.0.1:3001
363
- `,
364
- };
365
-
366
- console.log(helps[command] || `未知命令: ${command}`);
367
- }
368
-
369
- function parseArgs(argv) {
370
- const positionals = [];
371
- const options = {};
372
- for (let index = 0; index < argv.length; index += 1) {
373
- const token = argv[index];
374
- if (token.startsWith("--")) {
375
- const rawKey = token.slice(2);
376
- const camelKey = rawKey.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
377
- const value = argv[index + 1];
378
- if (value && !value.startsWith("-")) {
379
- options[rawKey] = value;
380
- options[camelKey] = value;
381
- index += 1;
382
- } else {
383
- options[rawKey] = true;
384
- options[camelKey] = true;
385
- }
386
- } else if (token === "-h") {
387
- options.help = true;
388
- } else if (token === "-v") {
389
- options.version = true;
390
- } else {
391
- positionals.push(token);
392
- }
393
- }
394
- return { positionals, options };
395
- }
396
-
397
- async function main() {
398
- const { positionals, options } = parseArgs(process.argv.slice(2));
399
- const [command, ...rest] = positionals;
400
-
401
- // 设置 verbose 模式
402
- if (options.verbose) {
403
- setVerbose(true);
404
- debug("Verbose mode enabled");
405
- }
406
-
407
- // 全局选项 - only show version if --version/-v is a boolean flag, not a string value
408
- if (options.version === true) {
409
- console.log(`AgentHub v${VERSION}`);
410
- return;
411
- }
412
-
413
- if (!command) {
414
- printHelp();
415
- return;
416
- }
417
-
418
- // 命令帮助
419
- if (options.help) {
420
- printCommandHelp(command);
421
- return;
422
- }
423
-
424
- // 命令路由
425
- try {
426
- switch (command) {
427
- case "pack": {
428
- if (!options.workspace || !options.config) {
429
- console.error(error("错误: --workspace 和 --config 是必需的"));
430
- console.log(muted("\n运行 'agenthub pack --help' 查看帮助"));
431
- process.exitCode = 1;
432
- return;
433
- }
434
- const result = await packCommand(options);
435
- console.log(success(`${symbols.success} 打包完成: ${result.bundleDir}`));
436
- return;
437
- }
438
-
439
- case "publish": {
440
- if (!requireArg(rest[0], "错误: 需要指定 bundle 目录")) return;
441
- const result = await publishCommand(rest[0], options);
442
- console.log(success(`${symbols.success} 已发布 ${highlight(`${result.slug}@${result.version}`)}`));
443
- return;
444
- }
445
-
446
- case "publish-remote": {
447
- if (!requireArg(rest[0], "错误: 需要指定 bundle 目录")) return;
448
- const result = await publishRemoteCommand(rest[0], options);
449
- console.log(success(`${symbols.success} 已发布到远程 ${highlight(`${result.slug}@${result.version}`)}`));
450
- return;
451
- }
452
-
453
- case "search": {
454
- const results = await searchCommand(rest[0] || "", options);
455
- if (options.json) {
456
- console.log(JSON.stringify({ agents: results, count: results.length, query: rest[0] || "" }, null, 2));
457
- } else if (results.length === 0) {
458
- console.log(warning("未找到匹配的 Agent"));
459
- } else {
460
- console.log(`\n${infoColor(`找到 ${results.length} Agent:`)}\n`);
461
- for (const entry of results) {
462
- console.log(` ${highlight(entry.slug)}${muted("@")}${entry.version} ${muted("-")} ${entry.description || ""}`);
463
- }
464
- }
465
- return;
466
- }
467
-
468
- case "info": {
469
- if (!requireArg(rest[0], "错误: 需要指定 agent slug")) return;
470
- const result = await infoCommand(rest[0], options);
471
- if (options.json) {
472
- console.log(JSON.stringify(result, null, 2));
473
- } else {
474
- console.log(`\n${highlight("📦")} ${result.name} (${result.slug}@${result.version})`);
475
- console.log(` ${result.description}`);
476
- console.log(` ${muted("Runtime:")} ${result.runtime?.type || "openclaw"} ${result.runtime?.version || ""}`);
477
- const mem = result.includes?.memory || {};
478
- if (mem.count > 0) {
479
- console.log(` ${muted("Memory:")} ${mem.count} 条 (public: ${mem.public}, portable: ${mem.portable})`);
480
- }
481
- console.log(`\n ${infoColor("安装命令:")} agenthub install ${result.slug}`);
482
- }
483
- return;
484
- }
485
-
486
- case "install": {
487
- if (!requireArg(rest[0], "错误: 需要指定 agent slug")) return;
488
- console.log(`\n${infoColor("📥 正在安装")} ${highlight(rest[0])}...\n`);
489
- const installResult = await installCommand(rest[0], options);
490
- console.log(success(`${symbols.success} 已安装 ${highlight(`${installResult.manifest.slug}@${installResult.manifest.version}`)}`));
491
- console.log(` ${muted("位置:")} ${options.targetWorkspace || "当前目录"}`);
492
- return;
493
- }
494
-
495
- case "list": {
496
- const list = await listCommand(options);
497
- if (options.json) {
498
- console.log(JSON.stringify({ agents: list, count: list.length }, null, 2));
499
- } else {
500
- console.log(formatListOutput(list));
501
- }
502
- return;
503
- }
504
-
505
- case "uninstall": {
506
- if (!requireArg(rest[0], "错误: 需要指定 agent slug")) return;
507
- const result = await uninstallCommand(rest[0], options);
508
- console.log(formatUninstallOutput(result));
509
- return;
510
- }
511
-
512
- case "verify": {
513
- const result = await verifyCommand(rest[0], options);
514
- console.log(formatVerifyOutput(result));
515
- if (!result.verified) {
516
- process.exitCode = 1;
517
- }
518
- return;
519
- }
520
-
521
- case "versions": {
522
- if (!requireArg(rest[0], "错误: 需要指定 agent slug")) return;
523
- const versions = await versionsCommand(rest[0], options);
524
- console.log(formatVersionsOutput(rest[0], versions));
525
- return;
526
- }
527
-
528
- case "update": {
529
- if (!requireArg(rest[0], "错误: 需要指定 agent slug")) return;
530
- const updateResult = await updateCommand(rest[0], options);
531
- console.log(updateResult.message);
532
- return;
533
- }
534
-
535
- case "rollback": {
536
- if (!requireArg(rest[0], "错误: 需要指定 agent slug")) return;
537
- const rollbackResult = await rollbackCommand(rest[0], options);
538
- console.log(rollbackResult.message);
539
- return;
540
- }
541
-
542
- case "stats": {
543
- if (!requireArg(rest[0], "错误: 需要指定 agent slug")) return;
544
- const stats = await statsCommand(rest[0], options);
545
- console.log(formatStatsOutput(stats));
546
- return;
547
- }
548
-
549
- case "doctor": {
550
- const result = await doctorCommand(options);
551
- if (!result.healthy) {
552
- process.exitCode = 1;
553
- }
554
- return;
555
- }
556
-
557
- case "serve": {
558
- const result = await serveCommand(options);
559
- console.log(success(`Server listening at ${result.baseUrl}`));
560
- console.log(`\n${highlight("🌐 AgentHub 服务已启动")}`);
561
- console.log(` ${muted("地址:")} ${result.baseUrl}`);
562
- console.log(` ${muted("API:")} ${result.baseUrl}/api/agents`);
563
- console.log(`\n${muted("按 Ctrl+C 停止服务")}\n`);
564
-
565
- const shutdown = async () => {
566
- process.off("SIGINT", shutdown);
567
- process.off("SIGTERM", shutdown);
568
- await result.close();
569
- process.exit(0);
570
- };
571
- process.on("SIGINT", shutdown);
572
- process.on("SIGTERM", shutdown);
573
- return;
574
- }
575
-
576
- case "api": {
577
- const port = options.port || "3001";
578
- const result = await apiCommand({ ...options, port });
579
- console.log(success(`Server listening at ${result.baseUrl}`));
580
- console.log(`\n${highlight("🔧 API 服务已启动")}`);
581
- console.log(` ${muted("地址:")} ${result.baseUrl}`);
582
- console.log(` ${muted("端点:")} ${result.baseUrl}/api/agents`);
583
- console.log(` ${muted("统计:")} ${result.baseUrl}/api/stats`);
584
- console.log(`\n${muted("按 Ctrl+C 停止服务")}\n`);
585
-
586
- const shutdown = async () => {
587
- process.off("SIGINT", shutdown);
588
- process.off("SIGTERM", shutdown);
589
- await result.close();
590
- process.exit(0);
591
- };
592
- process.on("SIGINT", shutdown);
593
- process.on("SIGTERM", shutdown);
594
- return;
595
- }
596
-
597
- case "web": {
598
- const port = options.port || "3000";
599
- const apiBase = options.apiBase || "http://127.0.0.1:3001";
600
- const host = options.host || "0.0.0.0";
601
- const result = await webCommand({ port, apiBase, host });
602
- console.log(success(`Server listening at ${result.baseUrl}`));
603
- console.log(`\n${highlight("🌐 Web 服务已启动")}`);
604
- console.log(` ${muted("地址:")} ${result.baseUrl}`);
605
- console.log(` ${muted("API:")} ${apiBase}`);
606
- console.log(`\n${muted("按 Ctrl+C 停止服务")}\n`);
607
-
608
- const shutdown = async () => {
609
- process.off("SIGINT", shutdown);
610
- process.off("SIGTERM", shutdown);
611
- await result.close();
612
- process.exit(0);
613
- };
614
- process.on("SIGINT", shutdown);
615
- process.on("SIGTERM", shutdown);
616
- return;
617
- }
618
-
619
- default:
620
- console.error(error(`未知命令: ${command}`));
621
- console.log(muted("\n运行 'agenthub --help' 查看可用命令"));
622
- process.exitCode = 1;
623
- }
624
- } catch (err) {
625
- // 提取更详细的错误信息
626
- const causeMsg = err.cause?.errors?.[0]?.message || err.cause?.message || "";
627
- const detailMsg = causeMsg ? `${err.message}\n 原因: ${causeMsg}` : err.message;
628
- console.error(`\n${error(`${symbols.error} 错误:`)} ${detailMsg}`);
629
-
630
- // 提供友好的解决建议
631
- const errMsg = err.message.toLowerCase();
632
- if (errMsg.includes("not found") || errMsg.includes("does not exist") || errMsg.includes("enoent")) {
633
- console.log(`\n${warning("建议:")}`);
634
- console.log(` - 检查文件路径是否正确`);
635
- console.log(` - 确认 workspace 目录存在`);
636
- console.log(` - 运行 ${highlight("agenthub --help")} 查看命令用法`);
637
- } else if (errMsg.includes("permission") || errMsg.includes("eacces")) {
638
- console.log(`\n${warning("建议:")}`);
639
- console.log(` - 检查文件权限`);
640
- console.log(` - 尝试使用 ${highlight("sudo")} 命令`);
641
- } else if (errMsg.includes("network") || errMsg.includes("econnrefused") || errMsg.includes("timeout") || errMsg.includes("fetch failed")) {
642
- console.log(`\n${warning("建议:")}`);
643
- console.log(` - 检查网络连接`);
644
- console.log(` - 确认服务器地址正确`);
645
- console.log(` - 使用 ${highlight("--registry")} 指定本地 registry`);
646
- console.log(` - 运行 ${highlight("agenthub doctor")} 诊断环境问题`);
647
- } else if (errMsg.includes("agent not found") || errMsg.includes("no agent")) {
648
- console.log(`\n${warning("建议:")}`);
649
- console.log(` - 运行 ${highlight("agenthub search")} 查看可用 Agent`);
650
- console.log(` - 检查 Agent 名称拼写`);
651
- console.log(` - 确认使用正确的 --registry 路径`);
652
- } else if (errMsg.includes("invalid") || errMsg.includes("validation")) {
653
- console.log(`\n${warning("建议:")}`);
654
- console.log(` - 检查配置文件格式 (openclaw.json)`);
655
- console.log(` - 确认 workspace 包含必需文件 (AGENTS.md, SOUL.md 等)`);
656
- console.log(` - 运行 ${highlight("agenthub verify")} 检查安装完整性`);
657
- } else if (errMsg.includes("version") || errMsg.includes("already")) {
658
- console.log(`\n${warning("建议:")}`);
659
- console.log(` - 运行 ${highlight("agenthub versions <agent>")} 查看可用版本`);
660
- console.log(` - 使用 ${highlight("--force")} 强制覆盖安装`);
661
- console.log(` - 运行 ${highlight("agenthub list")} 查看已安装的 Agent`);
662
- }
663
-
664
- console.log(`\n${muted("如需更多帮助:")}`);
665
- console.log(`${muted(" - 运行: agenthub <command> --help")}`);
666
- console.log(`${muted(" - 诊断: agenthub doctor")}`);
667
- process.exitCode = 1;
668
- }
669
- }
670
-
671
- main();
1
+ #!/usr/bin/env node
2
+ /**
3
+ * AgentHub CLI
4
+ * AI Agent 打包与分发平台
5
+ *
6
+ * 根据 PRD v1.1 规范实现
7
+ */
8
+
9
+ import {
10
+ infoCommand,
11
+ installCommand,
12
+ verifyCommand,
13
+ formatVerifyOutput,
14
+ packCommand,
15
+ publishCommand,
16
+ publishRemoteCommand,
17
+ serveCommand,
18
+ searchCommand,
19
+ apiCommand,
20
+ webCommand,
21
+ updateCommand,
22
+ rollbackCommand,
23
+ listCommand,
24
+ formatListOutput,
25
+ statsCommand,
26
+ formatStatsOutput,
27
+ versionsCommand,
28
+ formatVersionsOutput,
29
+ doctorCommand,
30
+ } from "./index.js";
31
+ import { uninstallCommand, formatUninstallOutput } from "./commands/uninstall.js";
32
+
33
+ import { success, error, warning, info as infoColor, highlight, muted, symbols } from "./lib/colors.js";
34
+ import { setVerbose, debug } from "./lib/debug.js";
35
+
36
+ import { createRequire } from "node:module";
37
+ const require = createRequire(import.meta.url);
38
+ const VERSION = require("../package.json").version;
39
+
40
+ /**
41
+ * 验证必需参数,如果缺失则打印错误并设置退出码
42
+ * @param {string} arg - 要验证的参数
43
+ * @param {string} message - 错误消息
44
+ * @returns {boolean} 参数是否存在
45
+ */
46
+ function requireArg(arg, message) {
47
+ if (!arg) {
48
+ console.error(error(message));
49
+ process.exitCode = 1;
50
+ return false;
51
+ }
52
+ return true;
53
+ }
54
+
55
+ function printHelp() {
56
+ console.log(`
57
+ AgentHub v${VERSION} - AI Agent 打包与分发平台
58
+
59
+ 用法:
60
+ agenthub <command> [options]
61
+
62
+ 命令:
63
+ pack 打包 OpenClaw 工作区为 Agent Bundle
64
+ publish 发布 Bundle 到本地 Registry
65
+ publish-remote 发布 Bundle 到远程服务器
66
+ install 安装 Agent 到目标工作区(默认当前目录)
67
+ search 搜索 Registry 中的 Agent
68
+ info 查看 Agent 详情
69
+ list 列出当前目录/指定目录的已安装 Agent
70
+ uninstall 卸载已安装的 Agent
71
+ verify 校验已安装 Agent 是否完整可用
72
+ versions 查看 Agent 版本历史
73
+ update 更新已安装 Agent 到最新版
74
+ rollback 回滚已安装 Agent 到指定版本
75
+ stats 查看 Agent 统计信息
76
+ doctor 诊断 AgentHub 安装和环境问题
77
+ serve 启动 Web + API 服务
78
+ api 仅启动 API 后端服务
79
+ web 仅启动 Web 前端服务
80
+
81
+ 选项:
82
+ --help, -h 显示帮助信息
83
+ --version, -v 显示版本号
84
+ --verbose 显示详细日志信息
85
+
86
+ 详细帮助:
87
+ agenthub <command> --help
88
+
89
+ 示例:
90
+ # 打包 Agent
91
+ agenthub pack --workspace ./my-workspace --config openclaw.json --output ./bundles
92
+
93
+ # 发布 Agent
94
+ agenthub publish ./bundles/my-agent.agent --registry ./.registry
95
+
96
+ # 安装 Agent
97
+ agenthub install my-agent --registry ./.registry --target-workspace ./workspace
98
+
99
+ # 搜索 Agent
100
+ agenthub search "code review" --registry ./.registry
101
+
102
+ # 启动完整服务(前端+后端)
103
+ agenthub serve --registry ./.registry --port 3000
104
+
105
+ `);
106
+ }
107
+
108
+ function printCommandHelp(command) {
109
+ const helps = {
110
+ pack: `
111
+ agenthub pack - 打包 Agent
112
+
113
+ 用法:
114
+ agenthub pack --workspace <dir> --config <file> --output <dir>
115
+
116
+ 选项:
117
+ --workspace <dir> OpenClaw 工作区目录 (必需)
118
+ --config <file> openclaw.json 配置文件路径 (必需)
119
+ --output <dir> 输出目录 (默认: ./bundles)
120
+ --name <name> Agent 名称 (默认: 工作区目录名)
121
+ --version <ver> 版本号 (默认: 1.0.0)
122
+ --tags <tags> 标签,逗号分隔
123
+ --category <cat> 分类
124
+ --featured 标记为精选 Agent
125
+ --strict 严格模式:发现高危敏感信息时中止打包
126
+ --no-strip-private 不自动剥离私有数据(默认自动剥离)
127
+ --skip-scan 跳过安全扫描
128
+
129
+ 🛡️ 隐私防护(默认开启):
130
+ 打包时自动排除 memory/private、.env、API Key 等敏感数据
131
+ 使用 --strict 可在发现高危问题时中止打包
132
+
133
+ 示例:
134
+ agenthub pack --workspace ./my-agent --config ./openclaw.json
135
+ agenthub pack --workspace ./my-agent --config ./openclaw.json --strict
136
+ agenthub pack --workspace ./my-agent --config ./openclaw.json --skip-scan
137
+ `,
138
+ publish: `
139
+ agenthub publish - 发布 Agent
140
+
141
+ 用法:
142
+ agenthub publish <bundle-dir> --registry <dir>
143
+
144
+ 选项:
145
+ --registry <dir> Registry 目录 (必需)
146
+
147
+ 示例:
148
+ agenthub publish ./bundles/my-agent.agent --registry ./.registry
149
+ `,
150
+ install: `
151
+ agenthub install - 安装 Agent
152
+
153
+ 用法:
154
+ agenthub install <agent-slug>[:version] [--registry <dir> | --server <url>] --target-workspace <dir>
155
+
156
+ 选项:
157
+ --registry <dir> 本地 Registry 目录(与 --server 二选一)
158
+ --server <url> 远程服务器地址(默认: https://agenthub.cyou)
159
+ --target-workspace <dir> 目标工作区目录 (必需)
160
+ --force 强制覆盖
161
+
162
+ 示例:
163
+ agenthub install code-review-assistant --registry ./.registry --target-workspace ./workspace
164
+ agenthub install my-agent:1.0.0 --server https://agenthub.cyou --target-workspace ./workspace
165
+ agenthub install meeting-minutes-assistant --target-workspace ./workspace
166
+ `,
167
+ search: `
168
+ agenthub search - 搜索 Agent
169
+
170
+ 用法:
171
+ agenthub search <query> --registry <dir>
172
+
173
+ 选项:
174
+ --registry <dir> Registry 目录 (必需)
175
+ --json JSON 格式输出
176
+
177
+ 示例:
178
+ agenthub search "code review" --registry ./.registry
179
+ agenthub search "" --registry ./.registry # 列出所有
180
+ agenthub search "code" --registry ./.registry --json
181
+ `,
182
+ list: `
183
+ agenthub list - 列出已安装 Agent
184
+
185
+ 用法:
186
+ agenthub list [--target-workspace <dir>] [--json]
187
+
188
+ 选项:
189
+ --target-workspace <dir> 指定工作区目录(可选)
190
+ --json JSON 格式输出
191
+
192
+ 示例:
193
+ agenthub list
194
+ agenthub list --target-workspace ./my-workspace
195
+ agenthub list --json
196
+ agenthub list --target-workspace ./my-workspace
197
+ `,
198
+ uninstall: `
199
+ agenthub uninstall - 卸载已安装 Agent
200
+
201
+ 用法:
202
+ agenthub uninstall <agent-slug> [--target-workspace <dir>]
203
+
204
+ 选项:
205
+ --target-workspace <dir> 指定工作区目录(可选)
206
+
207
+ 示例:
208
+ agenthub uninstall my-agent
209
+ agenthub uninstall my-agent --target-workspace ./my-workspace
210
+ `,
211
+ verify: `
212
+ agenthub verify - 校验已安装 Agent
213
+
214
+ 用法:
215
+ agenthub verify [agent-slug] [--registry <dir> | --server <url>] [--target-workspace <dir>]
216
+
217
+ 选项:
218
+ --registry <dir> 本地 Registry 目录(与 --server 二选一)
219
+ --server <url> 远程服务器地址(默认: https://agenthub.cyou)
220
+ --target-workspace <dir> 目标工作区目录(默认当前目录)
221
+
222
+ 示例:
223
+ agenthub verify workspace --registry ./.registry --target-workspace ./my-workspace
224
+ agenthub verify workspace --server https://agenthub.cyou --target-workspace ./my-workspace
225
+ `,
226
+ versions: `
227
+ agenthub versions - 查看版本历史
228
+
229
+ 用法:
230
+ agenthub versions <agent-slug> [--registry <dir> | --server <url>]
231
+
232
+ 选项:
233
+ --registry <dir> 本地 Registry 目录(与 --server 二选一)
234
+ --server <url> 远程服务器地址(默认: https://agenthub.cyou)
235
+
236
+ 示例:
237
+ agenthub versions workspace --registry ./.registry
238
+ agenthub versions workspace --server https://agenthub.cyou
239
+ `,
240
+ update: `
241
+ agenthub update - 更新 Agent 到最新版
242
+
243
+ 用法:
244
+ agenthub update <agent-slug> [--registry <dir> | --server <url>] --target-workspace <dir>
245
+
246
+ 选项:
247
+ --registry <dir> 本地 Registry 目录(与 --server 二选一)
248
+ --server <url> 远程服务器地址(默认: https://agenthub.cyou)
249
+ --target-workspace <dir> 目标工作区目录 (必需)
250
+
251
+ 示例:
252
+ agenthub update workspace --registry ./.registry --target-workspace ./my-workspace
253
+ agenthub update workspace --server https://agenthub.cyou --target-workspace ./my-workspace
254
+ `,
255
+ rollback: `
256
+ agenthub rollback - 回滚 Agent 到指定版本
257
+
258
+ 用法:
259
+ agenthub rollback <agent-slug> --to <version> [--registry <dir> | --server <url>] --target-workspace <dir>
260
+
261
+ 选项:
262
+ --to <version> 目标版本 (必需)
263
+ --registry <dir> 本地 Registry 目录(与 --server 二选一)
264
+ --server <url> 远程服务器地址(默认: https://agenthub.cyou)
265
+ --target-workspace <dir> 目标工作区目录 (必需)
266
+
267
+ 示例:
268
+ agenthub rollback workspace --to 1.0.0 --registry ./.registry --target-workspace ./my-workspace
269
+ agenthub rollback workspace --to 1.0.0 --server https://agenthub.cyou --target-workspace ./my-workspace
270
+ `,
271
+ info: `
272
+ agenthub info - 查看 Agent 详情
273
+
274
+ 用法:
275
+ agenthub info <agent-slug> [--registry <dir> | --server <url>]
276
+
277
+ 选项:
278
+ --registry <dir> 本地 Registry 目录(与 --server 二选一)
279
+ --server <url> 远程服务器地址(默认: https://agenthub.cyou)
280
+ --json JSON 格式输出
281
+
282
+ 示例:
283
+ agenthub info code-review-assistant --registry ./.registry
284
+ agenthub info my-agent --server https://agenthub.cyou --json
285
+ `,
286
+ "publish-remote": `
287
+ agenthub publish-remote - 发布 Agent 到远程服务器
288
+
289
+ 用法:
290
+ agenthub publish-remote <bundle-dir> --server <url>
291
+
292
+ 选项:
293
+ --server <url> 远程服务器地址(默认: https://agenthub.cyou)
294
+
295
+ 示例:
296
+ agenthub publish-remote ./bundles/my-agent.agent
297
+ agenthub publish-remote ./bundles/my-agent.agent --server https://agenthub.cyou
298
+ `,
299
+ stats: `
300
+ agenthub stats - 查看 Agent 统计信息
301
+
302
+ 用法:
303
+ agenthub stats <agent-slug> --registry <dir>
304
+
305
+ 选项:
306
+ --registry <dir> Registry 目录 (必需)
307
+
308
+ 示例:
309
+ agenthub stats workspace --registry ./.registry
310
+ `,
311
+ doctor: `
312
+ agenthub doctor - 诊断 AgentHub 安装和环境问题
313
+
314
+ 用法:
315
+ agenthub doctor [options]
316
+
317
+ 选项:
318
+ --full 运行完整诊断(包括测试套件)
319
+ --no-network 跳过网络连接检查
320
+ --server <url> 指定服务器地址检查(默认: https://agenthub.cyou)
321
+
322
+ 示例:
323
+ agenthub doctor
324
+ agenthub doctor --full
325
+ agenthub doctor --no-network
326
+ `,
327
+ serve: `
328
+ agenthub serve - 启动完整服务(前端+后端)
329
+
330
+ 用法:
331
+ agenthub serve --registry <dir> --port <port>
332
+
333
+ 选项:
334
+ --registry <dir> Registry 目录 (必需)
335
+ --port <port> 前端端口号 (默认: 3000)
336
+ --api-port <port> 后端 API 端口号 (默认: 3001)
337
+ --host <host> 监听地址 (默认: 0.0.0.0)
338
+
339
+ 示例:
340
+ agenthub serve --registry ./.registry --port 3000
341
+ agenthub serve --registry ./.registry --host 127.0.0.1
342
+ `,
343
+ api: `
344
+ agenthub api - 仅启动 API 后端服务
345
+
346
+ 用法:
347
+ agenthub api --registry <dir> --port <port>
348
+
349
+ 选项:
350
+ --registry <dir> Registry 目录 (必需)
351
+ --port <port> API 端口号 (默认: 3001)
352
+ --host <host> 监听地址 (默认: 0.0.0.0)
353
+
354
+ 示例:
355
+ agenthub api --registry ./.registry --port 3001
356
+ `,
357
+ web: `
358
+ agenthub web - 仅启动 Web 前端服务
359
+
360
+ 用法:
361
+ agenthub web --port <port> --api-base <url>
362
+
363
+ 选项:
364
+ --port <port> Web 端口号 (默认: 3000)
365
+ --api-base <url> API 服务地址 (默认: http://127.0.0.1:3001)
366
+ --host <host> 监听地址 (默认: 0.0.0.0)
367
+
368
+ 示例:
369
+ agenthub web --port 3000 --api-base http://127.0.0.1:3001
370
+ `,
371
+ };
372
+
373
+ console.log(helps[command] || `未知命令: ${command}`);
374
+ }
375
+
376
+ function parseArgs(argv) {
377
+ const positionals = [];
378
+ const options = {};
379
+ for (let index = 0; index < argv.length; index += 1) {
380
+ const token = argv[index];
381
+ if (token.startsWith("--")) {
382
+ const rawKey = token.slice(2);
383
+ const camelKey = rawKey.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
384
+ const value = argv[index + 1];
385
+ if (value && !value.startsWith("-")) {
386
+ options[rawKey] = value;
387
+ options[camelKey] = value;
388
+ index += 1;
389
+ } else {
390
+ options[rawKey] = true;
391
+ options[camelKey] = true;
392
+ }
393
+ } else if (token === "-h") {
394
+ options.help = true;
395
+ } else if (token === "-v") {
396
+ options.version = true;
397
+ } else {
398
+ positionals.push(token);
399
+ }
400
+ }
401
+ return { positionals, options };
402
+ }
403
+
404
+ async function main() {
405
+ const { positionals, options } = parseArgs(process.argv.slice(2));
406
+ const [command, ...rest] = positionals;
407
+
408
+ // 设置 verbose 模式
409
+ if (options.verbose) {
410
+ setVerbose(true);
411
+ debug("Verbose mode enabled");
412
+ }
413
+
414
+ // 全局选项 - only show version if --version/-v is a boolean flag, not a string value
415
+ if (options.version === true) {
416
+ console.log(`AgentHub v${VERSION}`);
417
+ return;
418
+ }
419
+
420
+ if (!command) {
421
+ printHelp();
422
+ return;
423
+ }
424
+
425
+ // 命令帮助
426
+ if (options.help) {
427
+ printCommandHelp(command);
428
+ return;
429
+ }
430
+
431
+ // 命令路由
432
+ try {
433
+ switch (command) {
434
+ case "pack": {
435
+ if (!options.workspace || !options.config) {
436
+ console.error(error("错误: --workspace 和 --config 是必需的"));
437
+ console.log(muted("\n运行 'agenthub pack --help' 查看帮助"));
438
+ process.exitCode = 1;
439
+ return;
440
+ }
441
+ // 处理 --no-strip-private 标志
442
+ if (options['no-strip-private'] || options.noStripPrivate) {
443
+ options.stripPrivate = false;
444
+ }
445
+ const result = await packCommand(options);
446
+ console.log(success(`\n${symbols.success} 打包完成: ${result.bundleDir}`));
447
+ // 输出隐私防护报告
448
+ if (result.privacy) {
449
+ console.log(` ${muted('🛡️ 隐私防护:')} ${result.privacy.stripped ? '已启用' : '未启用'}`);
450
+ console.log(` ${muted('📁 已复制:')} ${result.privacy.copiedFiles} 个文件`);
451
+ if (result.privacy.skippedFiles > 0) {
452
+ console.log(` ${warning('🚫 已剥离 ' + result.privacy.skippedFiles + ' 个文件/目录:')}`);
453
+ for (const skipped of result.privacy.skippedList) {
454
+ // 根据路径类型标注图标
455
+ let icon = ' ◦';
456
+ if (skipped.includes('memory/private') || skipped === 'memory/private') {
457
+ icon = ' 🔒';
458
+ } else if (skipped.startsWith('.env') || skipped === '.npmrc' || skipped === '.netrc') {
459
+ icon = ' 🔑';
460
+ } else if (skipped === '.git' || skipped === '.vscode' || skipped === '.idea') {
461
+ icon = ' 📂';
462
+ } else if (skipped === 'node_modules') {
463
+ icon = ' 📦';
464
+ }
465
+ console.log(` ${icon} ${muted(skipped)}`);
466
+ }
467
+ }
468
+ }
469
+ if (result.security) {
470
+ if (result.security.findingsCount > 0) {
471
+ console.log(warning(` ⚠️ 安全扫描: 发现 ${result.security.findingsCount} 个潜在风险`));
472
+ for (const w of result.security.warnings.slice(0, 5)) {
473
+ console.log(` ${w}`);
474
+ }
475
+ } else {
476
+ console.log(` ${success('✅ 安全扫描: 未发现敏感信息')}`);
477
+ }
478
+ }
479
+ return;
480
+ }
481
+
482
+ case "publish": {
483
+ if (!requireArg(rest[0], "错误: 需要指定 bundle 目录")) return;
484
+ const result = await publishCommand(rest[0], options);
485
+ console.log(success(`${symbols.success} 已发布 ${highlight(`${result.slug}@${result.version}`)}`));
486
+ return;
487
+ }
488
+
489
+ case "publish-remote": {
490
+ if (!requireArg(rest[0], "错误: 需要指定 bundle 目录")) return;
491
+ const result = await publishRemoteCommand(rest[0], options);
492
+ console.log(success(`${symbols.success} 已发布到远程 ${highlight(`${result.slug}@${result.version}`)}`));
493
+ return;
494
+ }
495
+
496
+ case "search": {
497
+ const results = await searchCommand(rest[0] || "", options);
498
+ if (options.json) {
499
+ console.log(JSON.stringify({ agents: results, count: results.length, query: rest[0] || "" }, null, 2));
500
+ } else if (results.length === 0) {
501
+ console.log(warning("未找到匹配的 Agent"));
502
+ } else {
503
+ console.log(`\n${infoColor(`找到 ${results.length} 个 Agent:`)}\n`);
504
+ for (const entry of results) {
505
+ console.log(` ${highlight(entry.slug)}${muted("@")}${entry.version} ${muted("-")} ${entry.description || ""}`);
506
+ }
507
+ }
508
+ return;
509
+ }
510
+
511
+ case "info": {
512
+ if (!requireArg(rest[0], "错误: 需要指定 agent slug")) return;
513
+ const result = await infoCommand(rest[0], options);
514
+ if (options.json) {
515
+ console.log(JSON.stringify(result, null, 2));
516
+ } else {
517
+ console.log(`\n${highlight("📦")} ${result.name} (${result.slug}@${result.version})`);
518
+ console.log(` ${result.description}`);
519
+ console.log(` ${muted("Runtime:")} ${result.runtime?.type || "openclaw"} ${result.runtime?.version || ""}`);
520
+ const mem = result.includes?.memory || {};
521
+ if (mem.count > 0) {
522
+ console.log(` ${muted("Memory:")} ${mem.count} (public: ${mem.public}, portable: ${mem.portable})`);
523
+ }
524
+ console.log(`\n ${infoColor("安装命令:")} agenthub install ${result.slug}`);
525
+ }
526
+ return;
527
+ }
528
+
529
+ case "install": {
530
+ if (!requireArg(rest[0], "错误: 需要指定 agent slug")) return;
531
+ console.log(`\n${infoColor("📥 正在安装")} ${highlight(rest[0])}...\n`);
532
+ const installResult = await installCommand(rest[0], options);
533
+ console.log(success(`${symbols.success} 已安装 ${highlight(`${installResult.manifest.slug}@${installResult.manifest.version}`)}`));
534
+ console.log(` ${muted("位置:")} ${options.targetWorkspace || "当前目录"}`);
535
+ return;
536
+ }
537
+
538
+ case "list": {
539
+ const list = await listCommand(options);
540
+ if (options.json) {
541
+ console.log(JSON.stringify({ agents: list, count: list.length }, null, 2));
542
+ } else {
543
+ console.log(formatListOutput(list));
544
+ }
545
+ return;
546
+ }
547
+
548
+ case "uninstall": {
549
+ if (!requireArg(rest[0], "错误: 需要指定 agent slug")) return;
550
+ const result = await uninstallCommand(rest[0], options);
551
+ console.log(formatUninstallOutput(result));
552
+ return;
553
+ }
554
+
555
+ case "verify": {
556
+ const result = await verifyCommand(rest[0], options);
557
+ console.log(formatVerifyOutput(result));
558
+ if (!result.verified) {
559
+ process.exitCode = 1;
560
+ }
561
+ return;
562
+ }
563
+
564
+ case "versions": {
565
+ if (!requireArg(rest[0], "错误: 需要指定 agent slug")) return;
566
+ const versions = await versionsCommand(rest[0], options);
567
+ console.log(formatVersionsOutput(rest[0], versions));
568
+ return;
569
+ }
570
+
571
+ case "update": {
572
+ if (!requireArg(rest[0], "错误: 需要指定 agent slug")) return;
573
+ const updateResult = await updateCommand(rest[0], options);
574
+ console.log(updateResult.message);
575
+ return;
576
+ }
577
+
578
+ case "rollback": {
579
+ if (!requireArg(rest[0], "错误: 需要指定 agent slug")) return;
580
+ const rollbackResult = await rollbackCommand(rest[0], options);
581
+ console.log(rollbackResult.message);
582
+ return;
583
+ }
584
+
585
+ case "stats": {
586
+ if (!requireArg(rest[0], "错误: 需要指定 agent slug")) return;
587
+ const stats = await statsCommand(rest[0], options);
588
+ console.log(formatStatsOutput(stats));
589
+ return;
590
+ }
591
+
592
+ case "doctor": {
593
+ const result = await doctorCommand(options);
594
+ if (!result.healthy) {
595
+ process.exitCode = 1;
596
+ }
597
+ return;
598
+ }
599
+
600
+ case "serve": {
601
+ const result = await serveCommand(options);
602
+ console.log(success(`Server listening at ${result.baseUrl}`));
603
+ console.log(`\n${highlight("🌐 AgentHub 服务已启动")}`);
604
+ console.log(` ${muted("地址:")} ${result.baseUrl}`);
605
+ console.log(` ${muted("API:")} ${result.baseUrl}/api/agents`);
606
+ console.log(`\n${muted("按 Ctrl+C 停止服务")}\n`);
607
+
608
+ const shutdown = async () => {
609
+ process.off("SIGINT", shutdown);
610
+ process.off("SIGTERM", shutdown);
611
+ await result.close();
612
+ process.exit(0);
613
+ };
614
+ process.on("SIGINT", shutdown);
615
+ process.on("SIGTERM", shutdown);
616
+ return;
617
+ }
618
+
619
+ case "api": {
620
+ const port = options.port || "3001";
621
+ const result = await apiCommand({ ...options, port });
622
+ console.log(success(`Server listening at ${result.baseUrl}`));
623
+ console.log(`\n${highlight("🔧 API 服务已启动")}`);
624
+ console.log(` ${muted("地址:")} ${result.baseUrl}`);
625
+ console.log(` ${muted("端点:")} ${result.baseUrl}/api/agents`);
626
+ console.log(` ${muted("统计:")} ${result.baseUrl}/api/stats`);
627
+ console.log(`\n${muted("按 Ctrl+C 停止服务")}\n`);
628
+
629
+ const shutdown = async () => {
630
+ process.off("SIGINT", shutdown);
631
+ process.off("SIGTERM", shutdown);
632
+ await result.close();
633
+ process.exit(0);
634
+ };
635
+ process.on("SIGINT", shutdown);
636
+ process.on("SIGTERM", shutdown);
637
+ return;
638
+ }
639
+
640
+ case "web": {
641
+ const port = options.port || "3000";
642
+ const apiBase = options.apiBase || "http://127.0.0.1:3001";
643
+ const host = options.host || "0.0.0.0";
644
+ const result = await webCommand({ port, apiBase, host });
645
+ console.log(success(`Server listening at ${result.baseUrl}`));
646
+ console.log(`\n${highlight("🌐 Web 服务已启动")}`);
647
+ console.log(` ${muted("地址:")} ${result.baseUrl}`);
648
+ console.log(` ${muted("API:")} ${apiBase}`);
649
+ console.log(`\n${muted(" Ctrl+C 停止服务")}\n`);
650
+
651
+ const shutdown = async () => {
652
+ process.off("SIGINT", shutdown);
653
+ process.off("SIGTERM", shutdown);
654
+ await result.close();
655
+ process.exit(0);
656
+ };
657
+ process.on("SIGINT", shutdown);
658
+ process.on("SIGTERM", shutdown);
659
+ return;
660
+ }
661
+
662
+ default:
663
+ console.error(error(`未知命令: ${command}`));
664
+ console.log(muted("\n运行 'agenthub --help' 查看可用命令"));
665
+ process.exitCode = 1;
666
+ }
667
+ } catch (err) {
668
+ // 提取更详细的错误信息
669
+ const causeMsg = err.cause?.errors?.[0]?.message || err.cause?.message || "";
670
+ const detailMsg = causeMsg ? `${err.message}\n 原因: ${causeMsg}` : err.message;
671
+ console.error(`\n${error(`${symbols.error} 错误:`)} ${detailMsg}`);
672
+
673
+ // 提供友好的解决建议
674
+ const errMsg = err.message.toLowerCase();
675
+ if (errMsg.includes("not found") || errMsg.includes("does not exist") || errMsg.includes("enoent")) {
676
+ console.log(`\n${warning("建议:")}`);
677
+ console.log(` - 检查文件路径是否正确`);
678
+ console.log(` - 确认 workspace 目录存在`);
679
+ console.log(` - 运行 ${highlight("agenthub --help")} 查看命令用法`);
680
+ } else if (errMsg.includes("permission") || errMsg.includes("eacces")) {
681
+ console.log(`\n${warning("建议:")}`);
682
+ console.log(` - 检查文件权限`);
683
+ console.log(` - 尝试使用 ${highlight("sudo")} 命令`);
684
+ } else if (errMsg.includes("network") || errMsg.includes("econnrefused") || errMsg.includes("timeout") || errMsg.includes("fetch failed")) {
685
+ console.log(`\n${warning("建议:")}`);
686
+ console.log(` - 检查网络连接`);
687
+ console.log(` - 确认服务器地址正确`);
688
+ console.log(` - 使用 ${highlight("--registry")} 指定本地 registry`);
689
+ console.log(` - 运行 ${highlight("agenthub doctor")} 诊断环境问题`);
690
+ } else if (errMsg.includes("agent not found") || errMsg.includes("no agent")) {
691
+ console.log(`\n${warning("建议:")}`);
692
+ console.log(` - 运行 ${highlight("agenthub search")} 查看可用 Agent`);
693
+ console.log(` - 检查 Agent 名称拼写`);
694
+ console.log(` - 确认使用正确的 --registry 路径`);
695
+ } else if (errMsg.includes("invalid") || errMsg.includes("validation")) {
696
+ console.log(`\n${warning("建议:")}`);
697
+ console.log(` - 检查配置文件格式 (openclaw.json)`);
698
+ console.log(` - 确认 workspace 包含必需文件 (AGENTS.md, SOUL.md 等)`);
699
+ console.log(` - 运行 ${highlight("agenthub verify")} 检查安装完整性`);
700
+ } else if (errMsg.includes("version") || errMsg.includes("already")) {
701
+ console.log(`\n${warning("建议:")}`);
702
+ console.log(` - 运行 ${highlight("agenthub versions <agent>")} 查看可用版本`);
703
+ console.log(` - 使用 ${highlight("--force")} 强制覆盖安装`);
704
+ console.log(` - 运行 ${highlight("agenthub list")} 查看已安装的 Agent`);
705
+ }
706
+
707
+ console.log(`\n${muted("如需更多帮助:")}`);
708
+ console.log(`${muted(" - 运行: agenthub <command> --help")}`);
709
+ console.log(`${muted(" - 诊断: agenthub doctor")}`);
710
+ process.exitCode = 1;
711
+ }
712
+ }
713
+
714
+ main();