@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
@@ -1,335 +1,335 @@
1
- /**
2
- * Doctor Command
3
- * 诊断 AgentHub 安装和环境问题
4
- */
5
-
6
- import { execSync } from "node:child_process";
7
- import { access, constants, readFile } from "node:fs/promises";
8
- import path from "node:path";
9
- import { success, error, warning, info as infoColor, highlight, muted } from "../lib/colors.js";
10
-
11
- const PROJECT_ROOT = path.resolve(import.meta.dirname, "../..");
12
-
13
- /**
14
- * 检查 Node.js 版本
15
- */
16
- function checkNodeVersion() {
17
- const version = process.version;
18
- const major = parseInt(version.slice(1).split(".")[0], 10);
19
- const required = 18;
20
- const passed = major >= required;
21
- return {
22
- name: "Node.js 版本",
23
- passed,
24
- message: passed
25
- ? `${version} (需要 >= ${required})`
26
- : `${version} (需要 >= ${required})`,
27
- severity: passed ? "ok" : "error",
28
- fix: passed ? null : `升级 Node.js 到 v${required} 或更高版本`,
29
- };
30
- }
31
-
32
- /**
33
- * 检查 npm 包安装
34
- */
35
- async function checkNpmPackage() {
36
- try {
37
- const packageJson = await readFile(
38
- path.join(PROJECT_ROOT, "package.json"),
39
- "utf8"
40
- );
41
- const pkg = JSON.parse(packageJson);
42
- return {
43
- name: "AgentHub 包",
44
- passed: true,
45
- message: `v${pkg.version} 已安装`,
46
- severity: "ok",
47
- fix: null,
48
- };
49
- } catch {
50
- return {
51
- name: "AgentHub 包",
52
- passed: false,
53
- message: "无法读取 package.json",
54
- severity: "error",
55
- fix: "重新安装 AgentHub: npm install -g @zshuangmu/agenthub",
56
- };
57
- }
58
- }
59
-
60
- /**
61
- * 检查 CLI 可执行文件
62
- */
63
- async function checkCliExecutable() {
64
- try {
65
- const result = execSync("node src/cli.js --version", {
66
- cwd: PROJECT_ROOT,
67
- encoding: "utf8",
68
- stdio: ["pipe", "pipe", "pipe"],
69
- });
70
- const version = result.trim();
71
- return {
72
- name: "CLI 可执行文件",
73
- passed: true,
74
- message: version,
75
- severity: "ok",
76
- fix: null,
77
- };
78
- } catch (err) {
79
- return {
80
- name: "CLI 可执行文件",
81
- passed: false,
82
- message: "CLI 无法执行",
83
- severity: "error",
84
- fix: "检查 Node.js 安装和文件权限",
85
- };
86
- }
87
- }
88
-
89
- /**
90
- * 检查测试套件
91
- */
92
- async function checkTests() {
93
- try {
94
- const result = execSync("npm test", {
95
- cwd: PROJECT_ROOT,
96
- encoding: "utf8",
97
- stdio: ["pipe", "pipe", "pipe"],
98
- timeout: 30000,
99
- });
100
- const match = result.match(/ℹ tests (\d+).*ℹ pass (\d+).*ℹ fail (\d+)/s);
101
- if (match) {
102
- const [, total, passed, failed] = match;
103
- const passRate = (parseInt(passed, 10) / parseInt(total, 10)) * 100;
104
- return {
105
- name: "测试套件",
106
- passed: parseInt(failed, 10) === 0,
107
- message: `${passed}/${total} 通过 (${passRate.toFixed(0)}%)`,
108
- severity: parseInt(failed, 10) > 0 ? "warning" : "ok",
109
- fix: parseInt(failed, 10) > 0 ? "运行 npm test 查看失败详情" : null,
110
- };
111
- }
112
- return {
113
- name: "测试套件",
114
- passed: true,
115
- message: "测试通过",
116
- severity: "ok",
117
- fix: null,
118
- };
119
- } catch (err) {
120
- return {
121
- name: "测试套件",
122
- passed: false,
123
- message: "测试执行失败",
124
- severity: "warning",
125
- fix: "运行 npm test 查看失败详情",
126
- };
127
- }
128
- }
129
-
130
- /**
131
- * 检查样本 Agent
132
- */
133
- async function checkSampleAgents() {
134
- const samplesDir = path.join(PROJECT_ROOT, "samples");
135
- const expectedSamples = [
136
- "code-review-assistant",
137
- "team-knowledge-assistant",
138
- "product-doc-writer",
139
- ];
140
- const results = [];
141
-
142
- for (const sample of expectedSamples) {
143
- const samplePath = path.join(samplesDir, sample);
144
- try {
145
- await access(samplePath, constants.R_OK);
146
- results.push({ name: sample, exists: true });
147
- } catch {
148
- results.push({ name: sample, exists: false });
149
- }
150
- }
151
-
152
- const existing = results.filter((r) => r.exists).length;
153
- const passed = existing === expectedSamples.length;
154
-
155
- return {
156
- name: "样本 Agent",
157
- passed,
158
- message: `${existing}/${expectedSamples.length} 可用`,
159
- severity: passed ? "ok" : "warning",
160
- fix: passed ? null : `缺失样本: ${results
161
- .filter((r) => !r.exists)
162
- .map((r) => r.name)
163
- .join(", ")}`,
164
- };
165
- }
166
-
167
- /**
168
- * 检查文档
169
- */
170
- async function checkDocumentation() {
171
- const docsDir = path.join(PROJECT_ROOT, "docs");
172
- const expectedDocs = [
173
- "faq.md",
174
- "growth-plan.md",
175
- "team-distribution-guide.md",
176
- "quick-start-3-steps.md",
177
- ];
178
- const results = [];
179
-
180
- for (const doc of expectedDocs) {
181
- const docPath = path.join(docsDir, doc);
182
- try {
183
- await access(docPath, constants.R_OK);
184
- results.push({ name: doc, exists: true });
185
- } catch {
186
- results.push({ name: doc, exists: false });
187
- }
188
- }
189
-
190
- const existing = results.filter((r) => r.exists).length;
191
- const passed = existing >= expectedDocs.length - 1; // 允许缺少1个
192
-
193
- return {
194
- name: "文档完整性",
195
- passed,
196
- message: `${existing}/${expectedDocs.length} 文档可用`,
197
- severity: passed ? "ok" : "warning",
198
- fix: passed ? null : `检查 docs/ 目录`,
199
- };
200
- }
201
-
202
- /**
203
- * 检查网络连接 (可选)
204
- */
205
- async function checkNetworkConnection(serverUrl) {
206
- const url = serverUrl || "https://agenthub.cyou";
207
- try {
208
- const controller = new AbortController();
209
- const timeout = setTimeout(() => controller.abort(), 5000);
210
-
211
- const response = await fetch(url, {
212
- method: "HEAD",
213
- signal: controller.signal,
214
- });
215
- clearTimeout(timeout);
216
-
217
- return {
218
- name: "网络连接",
219
- passed: response.ok,
220
- message: `${url} - ${response.status}`,
221
- severity: response.ok ? "ok" : "warning",
222
- fix: response.ok ? null : "检查网络连接或服务器状态",
223
- };
224
- } catch (err) {
225
- return {
226
- name: "网络连接",
227
- passed: false,
228
- message: `${url} - 连接失败`,
229
- severity: "warning",
230
- fix: "检查网络连接或稍后重试",
231
- };
232
- }
233
- }
234
-
235
- /**
236
- * 运行所有诊断检查
237
- */
238
- export async function doctorCommand(options) {
239
- const checks = [];
240
-
241
- console.log(`\n${highlight("🔍 AgentHub 诊断检查")}\n`);
242
- console.log(`${muted("检查 AgentHub 安装和环境配置...")}\n`);
243
-
244
- // 基础检查
245
- checks.push(checkNodeVersion());
246
- checks.push(await checkNpmPackage());
247
- checks.push(await checkCliExecutable());
248
-
249
- // 测试检查
250
- if (options.full) {
251
- checks.push(await checkTests());
252
- }
253
-
254
- // 内容检查
255
- checks.push(await checkSampleAgents());
256
- checks.push(await checkDocumentation());
257
-
258
- // 网络检查
259
- if (options.network !== false) {
260
- checks.push(await checkNetworkConnection(options.server));
261
- }
262
-
263
- // 输出结果
264
- let passed = 0;
265
- let warnings = 0;
266
- let errors = 0;
267
-
268
- for (const check of checks) {
269
- let symbol;
270
- let colorFn;
271
- switch (check.severity) {
272
- case "ok":
273
- symbol = "✅";
274
- colorFn = success;
275
- passed++;
276
- break;
277
- case "warning":
278
- symbol = "⚠️";
279
- colorFn = warning;
280
- warnings++;
281
- break;
282
- case "error":
283
- symbol = "❌";
284
- colorFn = error;
285
- errors++;
286
- break;
287
- }
288
-
289
- console.log(` ${symbol} ${check.name}: ${colorFn(check.message)}`);
290
- if (check.fix) {
291
- console.log(` ${muted("建议:")} ${check.fix}`);
292
- }
293
- }
294
-
295
- // 总结
296
- console.log(`\n${muted("─".repeat(40))}\n`);
297
-
298
- const total = checks.length;
299
- if (errors === 0 && warnings === 0) {
300
- console.log(success(`🎉 所有检查通过!(${passed}/${total})`));
301
- console.log(`${infoColor("AgentHub 已就绪,可以正常使用。")}\n`);
302
- } else if (errors === 0) {
303
- console.log(warning(`⚠️ 检查完成,有 ${warnings} 个警告 (${passed}/${total} 通过)`));
304
- console.log(`${infoColor("AgentHub 可以使用,但建议解决上述警告。")}\n`);
305
- } else {
306
- console.log(error(`❌ 检查失败,有 ${errors} 个错误 (${passed}/${total} 通过)`));
307
- console.log(`${infoColor("请先解决上述错误再使用 AgentHub。")}\n`);
308
- }
309
-
310
- return {
311
- passed,
312
- warnings,
313
- errors,
314
- total,
315
- healthy: errors === 0,
316
- checks,
317
- };
318
- }
319
-
320
- /**
321
- * 格式化输出
322
- */
323
- export function formatDoctorOutput(result) {
324
- const lines = [];
325
- lines.push(`\n${highlight("🔍 AgentHub 诊断检查")}\n`);
326
- lines.push(`${muted("检查结果:")} ${result.passed}/${result.total} 通过\n`);
327
-
328
- if (result.healthy) {
329
- lines.push(success("✅ AgentHub 健康状态良好"));
330
- } else {
331
- lines.push(error("❌ AgentHub 需要修复"));
332
- }
333
-
334
- return lines.join("\n");
335
- }
1
+ /**
2
+ * Doctor Command
3
+ * 诊断 AgentHub 安装和环境问题
4
+ */
5
+
6
+ import { execSync } from "node:child_process";
7
+ import { access, constants, readFile } from "node:fs/promises";
8
+ import path from "node:path";
9
+ import { success, error, warning, info as infoColor, highlight, muted } from "../lib/colors.js";
10
+
11
+ const PROJECT_ROOT = path.resolve(import.meta.dirname, "../..");
12
+
13
+ /**
14
+ * 检查 Node.js 版本
15
+ */
16
+ function checkNodeVersion() {
17
+ const version = process.version;
18
+ const major = parseInt(version.slice(1).split(".")[0], 10);
19
+ const required = 18;
20
+ const passed = major >= required;
21
+ return {
22
+ name: "Node.js 版本",
23
+ passed,
24
+ message: passed
25
+ ? `${version} (需要 >= ${required})`
26
+ : `${version} (需要 >= ${required})`,
27
+ severity: passed ? "ok" : "error",
28
+ fix: passed ? null : `升级 Node.js 到 v${required} 或更高版本`,
29
+ };
30
+ }
31
+
32
+ /**
33
+ * 检查 npm 包安装
34
+ */
35
+ async function checkNpmPackage() {
36
+ try {
37
+ const packageJson = await readFile(
38
+ path.join(PROJECT_ROOT, "package.json"),
39
+ "utf8"
40
+ );
41
+ const pkg = JSON.parse(packageJson);
42
+ return {
43
+ name: "AgentHub 包",
44
+ passed: true,
45
+ message: `v${pkg.version} 已安装`,
46
+ severity: "ok",
47
+ fix: null,
48
+ };
49
+ } catch {
50
+ return {
51
+ name: "AgentHub 包",
52
+ passed: false,
53
+ message: "无法读取 package.json",
54
+ severity: "error",
55
+ fix: "重新安装 AgentHub: npm install -g @zshuangmu/agenthub",
56
+ };
57
+ }
58
+ }
59
+
60
+ /**
61
+ * 检查 CLI 可执行文件
62
+ */
63
+ async function checkCliExecutable() {
64
+ try {
65
+ const result = execSync("node src/cli.js --version", {
66
+ cwd: PROJECT_ROOT,
67
+ encoding: "utf8",
68
+ stdio: ["pipe", "pipe", "pipe"],
69
+ });
70
+ const version = result.trim();
71
+ return {
72
+ name: "CLI 可执行文件",
73
+ passed: true,
74
+ message: version,
75
+ severity: "ok",
76
+ fix: null,
77
+ };
78
+ } catch (err) {
79
+ return {
80
+ name: "CLI 可执行文件",
81
+ passed: false,
82
+ message: "CLI 无法执行",
83
+ severity: "error",
84
+ fix: "检查 Node.js 安装和文件权限",
85
+ };
86
+ }
87
+ }
88
+
89
+ /**
90
+ * 检查测试套件
91
+ */
92
+ async function checkTests() {
93
+ try {
94
+ const result = execSync("npm test", {
95
+ cwd: PROJECT_ROOT,
96
+ encoding: "utf8",
97
+ stdio: ["pipe", "pipe", "pipe"],
98
+ timeout: 30000,
99
+ });
100
+ const match = result.match(/ℹ tests (\d+).*ℹ pass (\d+).*ℹ fail (\d+)/s);
101
+ if (match) {
102
+ const [, total, passed, failed] = match;
103
+ const passRate = (parseInt(passed, 10) / parseInt(total, 10)) * 100;
104
+ return {
105
+ name: "测试套件",
106
+ passed: parseInt(failed, 10) === 0,
107
+ message: `${passed}/${total} 通过 (${passRate.toFixed(0)}%)`,
108
+ severity: parseInt(failed, 10) > 0 ? "warning" : "ok",
109
+ fix: parseInt(failed, 10) > 0 ? "运行 npm test 查看失败详情" : null,
110
+ };
111
+ }
112
+ return {
113
+ name: "测试套件",
114
+ passed: true,
115
+ message: "测试通过",
116
+ severity: "ok",
117
+ fix: null,
118
+ };
119
+ } catch (err) {
120
+ return {
121
+ name: "测试套件",
122
+ passed: false,
123
+ message: "测试执行失败",
124
+ severity: "warning",
125
+ fix: "运行 npm test 查看失败详情",
126
+ };
127
+ }
128
+ }
129
+
130
+ /**
131
+ * 检查样本 Agent
132
+ */
133
+ async function checkSampleAgents() {
134
+ const samplesDir = path.join(PROJECT_ROOT, "samples");
135
+ const expectedSamples = [
136
+ "code-review-assistant",
137
+ "team-knowledge-assistant",
138
+ "product-doc-writer",
139
+ ];
140
+ const results = [];
141
+
142
+ for (const sample of expectedSamples) {
143
+ const samplePath = path.join(samplesDir, sample);
144
+ try {
145
+ await access(samplePath, constants.R_OK);
146
+ results.push({ name: sample, exists: true });
147
+ } catch {
148
+ results.push({ name: sample, exists: false });
149
+ }
150
+ }
151
+
152
+ const existing = results.filter((r) => r.exists).length;
153
+ const passed = existing === expectedSamples.length;
154
+
155
+ return {
156
+ name: "样本 Agent",
157
+ passed,
158
+ message: `${existing}/${expectedSamples.length} 可用`,
159
+ severity: passed ? "ok" : "warning",
160
+ fix: passed ? null : `缺失样本: ${results
161
+ .filter((r) => !r.exists)
162
+ .map((r) => r.name)
163
+ .join(", ")}`,
164
+ };
165
+ }
166
+
167
+ /**
168
+ * 检查文档
169
+ */
170
+ async function checkDocumentation() {
171
+ const docsDir = path.join(PROJECT_ROOT, "docs");
172
+ const expectedDocs = [
173
+ "faq.md",
174
+ "growth-plan.md",
175
+ "team-distribution-guide.md",
176
+ "quick-start-3-steps.md",
177
+ ];
178
+ const results = [];
179
+
180
+ for (const doc of expectedDocs) {
181
+ const docPath = path.join(docsDir, doc);
182
+ try {
183
+ await access(docPath, constants.R_OK);
184
+ results.push({ name: doc, exists: true });
185
+ } catch {
186
+ results.push({ name: doc, exists: false });
187
+ }
188
+ }
189
+
190
+ const existing = results.filter((r) => r.exists).length;
191
+ const passed = existing >= expectedDocs.length - 1; // 允许缺少1个
192
+
193
+ return {
194
+ name: "文档完整性",
195
+ passed,
196
+ message: `${existing}/${expectedDocs.length} 文档可用`,
197
+ severity: passed ? "ok" : "warning",
198
+ fix: passed ? null : `检查 docs/ 目录`,
199
+ };
200
+ }
201
+
202
+ /**
203
+ * 检查网络连接 (可选)
204
+ */
205
+ async function checkNetworkConnection(serverUrl) {
206
+ const url = serverUrl || "https://agenthub.cyou";
207
+ try {
208
+ const controller = new AbortController();
209
+ const timeout = setTimeout(() => controller.abort(), 5000);
210
+
211
+ const response = await fetch(url, {
212
+ method: "HEAD",
213
+ signal: controller.signal,
214
+ });
215
+ clearTimeout(timeout);
216
+
217
+ return {
218
+ name: "网络连接",
219
+ passed: response.ok,
220
+ message: `${url} - ${response.status}`,
221
+ severity: response.ok ? "ok" : "warning",
222
+ fix: response.ok ? null : "检查网络连接或服务器状态",
223
+ };
224
+ } catch (err) {
225
+ return {
226
+ name: "网络连接",
227
+ passed: false,
228
+ message: `${url} - 连接失败`,
229
+ severity: "warning",
230
+ fix: "检查网络连接或稍后重试",
231
+ };
232
+ }
233
+ }
234
+
235
+ /**
236
+ * 运行所有诊断检查
237
+ */
238
+ export async function doctorCommand(options) {
239
+ const checks = [];
240
+
241
+ console.log(`\n${highlight("🔍 AgentHub 诊断检查")}\n`);
242
+ console.log(`${muted("检查 AgentHub 安装和环境配置...")}\n`);
243
+
244
+ // 基础检查
245
+ checks.push(checkNodeVersion());
246
+ checks.push(await checkNpmPackage());
247
+ checks.push(await checkCliExecutable());
248
+
249
+ // 测试检查
250
+ if (options.full) {
251
+ checks.push(await checkTests());
252
+ }
253
+
254
+ // 内容检查
255
+ checks.push(await checkSampleAgents());
256
+ checks.push(await checkDocumentation());
257
+
258
+ // 网络检查
259
+ if (options.network !== false) {
260
+ checks.push(await checkNetworkConnection(options.server));
261
+ }
262
+
263
+ // 输出结果
264
+ let passed = 0;
265
+ let warnings = 0;
266
+ let errors = 0;
267
+
268
+ for (const check of checks) {
269
+ let symbol;
270
+ let colorFn;
271
+ switch (check.severity) {
272
+ case "ok":
273
+ symbol = "✅";
274
+ colorFn = success;
275
+ passed++;
276
+ break;
277
+ case "warning":
278
+ symbol = "⚠️";
279
+ colorFn = warning;
280
+ warnings++;
281
+ break;
282
+ case "error":
283
+ symbol = "❌";
284
+ colorFn = error;
285
+ errors++;
286
+ break;
287
+ }
288
+
289
+ console.log(` ${symbol} ${check.name}: ${colorFn(check.message)}`);
290
+ if (check.fix) {
291
+ console.log(` ${muted("建议:")} ${check.fix}`);
292
+ }
293
+ }
294
+
295
+ // 总结
296
+ console.log(`\n${muted("─".repeat(40))}\n`);
297
+
298
+ const total = checks.length;
299
+ if (errors === 0 && warnings === 0) {
300
+ console.log(success(`🎉 所有检查通过!(${passed}/${total})`));
301
+ console.log(`${infoColor("AgentHub 已就绪,可以正常使用。")}\n`);
302
+ } else if (errors === 0) {
303
+ console.log(warning(`⚠️ 检查完成,有 ${warnings} 个警告 (${passed}/${total} 通过)`));
304
+ console.log(`${infoColor("AgentHub 可以使用,但建议解决上述警告。")}\n`);
305
+ } else {
306
+ console.log(error(`❌ 检查失败,有 ${errors} 个错误 (${passed}/${total} 通过)`));
307
+ console.log(`${infoColor("请先解决上述错误再使用 AgentHub。")}\n`);
308
+ }
309
+
310
+ return {
311
+ passed,
312
+ warnings,
313
+ errors,
314
+ total,
315
+ healthy: errors === 0,
316
+ checks,
317
+ };
318
+ }
319
+
320
+ /**
321
+ * 格式化输出
322
+ */
323
+ export function formatDoctorOutput(result) {
324
+ const lines = [];
325
+ lines.push(`\n${highlight("🔍 AgentHub 诊断检查")}\n`);
326
+ lines.push(`${muted("检查结果:")} ${result.passed}/${result.total} 通过\n`);
327
+
328
+ if (result.healthy) {
329
+ lines.push(success("✅ AgentHub 健康状态良好"));
330
+ } else {
331
+ lines.push(error("❌ AgentHub 需要修复"));
332
+ }
333
+
334
+ return lines.join("\n");
335
+ }