@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,130 +1,130 @@
1
- import path from "node:path";
2
- import { copyDir, ensureDir, pathExists, readJson, writeJson } from "./fs-utils.js";
3
-
4
- /**
5
- * 解析 agentSpec,支持两种格式:
6
- * - 短名格式:slug 或 slug:version
7
- * - URI 格式:agenthub://owner/slug@version
8
- */
9
- export function parseSpec(agentSpec) {
10
- // URI 格式:agenthub://owner/slug@version
11
- if (agentSpec.startsWith("agenthub://")) {
12
- const uri = agentSpec.slice("agenthub://".length);
13
- const parts = uri.split("/");
14
- const lastPart = parts[parts.length - 1] || parts[parts.length - 2];
15
- const [slug, version] = lastPart.split("@");
16
- return { slug, version: version || undefined };
17
- }
18
- // 短名格式:slug 或 slug:version
19
- const [slug, version] = agentSpec.split(":");
20
- return { slug, version: version || undefined };
21
- }
22
-
23
- /**
24
- * 版本比较函数(用于排序)
25
- * 按 semver 降序排列
26
- */
27
- export function compareVersionsDesc(a, b) {
28
- return b.version.localeCompare(a.version, undefined, { numeric: true });
29
- }
30
-
31
- /**
32
- * 从 agent 条目中获取最新版本
33
- */
34
- export function getLatestVersion(entries) {
35
- if (!entries || entries.length === 0) return null;
36
- return [...entries].sort(compareVersionsDesc)[0];
37
- }
38
-
39
- /**
40
- * 按下载量和更新时间排序 Agent 列表
41
- * 下载量降序,下载量一致时按更新时间降序
42
- */
43
- export function sortByDownloadsAndTime(agents) {
44
- return agents.sort((a, b) => {
45
- if (b.downloads !== a.downloads) {
46
- return b.downloads - a.downloads;
47
- }
48
- const timeA = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
49
- const timeB = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
50
- return timeB - timeA;
51
- });
52
- }
53
-
54
- export async function publishBundle(bundleDir, registryDir) {
55
- const manifest = await readJson(path.join(bundleDir, "MANIFEST.json"));
56
- if (manifest.runtime?.type !== "openclaw") {
57
- throw new Error("Only OpenClaw bundles are supported.");
58
- }
59
- if ((manifest.includes?.memory?.private ?? 0) > 0) {
60
- throw new Error("Public publish rejected: private memory detected.");
61
- }
62
-
63
- const targetDir = path.join(registryDir, "agents", manifest.slug, manifest.version);
64
- await ensureDir(path.join(registryDir, "agents", manifest.slug));
65
- await copyDir(bundleDir, targetDir);
66
-
67
- const indexPath = path.join(registryDir, "index.json");
68
- const index = (await pathExists(indexPath)) ? await readJson(indexPath) : { agents: [] };
69
- index.agents = index.agents.filter(
70
- (entry) => !(entry.slug === manifest.slug && entry.version === manifest.version),
71
- );
72
- index.agents.push({
73
- slug: manifest.slug,
74
- version: manifest.version,
75
- name: manifest.name,
76
- description: manifest.description,
77
- runtime: manifest.runtime,
78
- updatedAt: new Date().toISOString(),
79
- tags: manifest.metadata?.tags || [],
80
- category: manifest.metadata?.category || 'General',
81
- });
82
- index.agents.sort((left, right) => left.slug.localeCompare(right.slug));
83
- await writeJson(indexPath, index);
84
-
85
- return manifest;
86
- }
87
-
88
- export async function searchRegistry(registryDir, query) {
89
- const indexPath = path.join(registryDir, "index.json");
90
- if (!(await pathExists(indexPath))) {
91
- return [];
92
- }
93
- const index = await readJson(indexPath);
94
- const normalized = query.toLowerCase().trim();
95
-
96
- // 空查询返回所有
97
- if (!normalized) {
98
- return index.agents;
99
- }
100
-
101
- return index.agents.filter((entry) => {
102
- // 搜索 slug
103
- if (entry.slug?.toLowerCase().includes(normalized)) return true;
104
- // 搜索 name
105
- if (entry.name?.toLowerCase().includes(normalized)) return true;
106
- // 搜索 description
107
- if (entry.description?.toLowerCase().includes(normalized)) return true;
108
- // 搜索 tags
109
- if (entry.tags?.some(tag => tag.toLowerCase().includes(normalized))) return true;
110
- // 搜索 category
111
- if (entry.category?.toLowerCase().includes(normalized)) return true;
112
- return false;
113
- });
114
- }
115
-
116
- export async function readAgentInfo(registryDir, agentSpec) {
117
- const { slug, version } = parseSpec(agentSpec);
118
- const baseDir = path.join(registryDir, "agents", slug);
119
- if (!(await pathExists(baseDir))) {
120
- throw new Error(`Agent not found: ${slug}`);
121
- }
122
-
123
- let selectedVersion = version;
124
- if (!selectedVersion) {
125
- const index = await readJson(path.join(registryDir, "index.json"));
126
- const versions = index.agents.filter((entry) => entry.slug === slug).map((entry) => entry.version).sort();
127
- selectedVersion = versions.at(-1);
128
- }
129
- return readJson(path.join(baseDir, selectedVersion, "MANIFEST.json"));
130
- }
1
+ import path from "node:path";
2
+ import { copyDir, ensureDir, pathExists, readJson, writeJson } from "./fs-utils.js";
3
+
4
+ /**
5
+ * 解析 agentSpec,支持两种格式:
6
+ * - 短名格式:slug 或 slug:version
7
+ * - URI 格式:agenthub://owner/slug@version
8
+ */
9
+ export function parseSpec(agentSpec) {
10
+ // URI 格式:agenthub://owner/slug@version
11
+ if (agentSpec.startsWith("agenthub://")) {
12
+ const uri = agentSpec.slice("agenthub://".length);
13
+ const parts = uri.split("/");
14
+ const lastPart = parts[parts.length - 1] || parts[parts.length - 2];
15
+ const [slug, version] = lastPart.split("@");
16
+ return { slug, version: version || undefined };
17
+ }
18
+ // 短名格式:slug 或 slug:version
19
+ const [slug, version] = agentSpec.split(":");
20
+ return { slug, version: version || undefined };
21
+ }
22
+
23
+ /**
24
+ * 版本比较函数(用于排序)
25
+ * 按 semver 降序排列
26
+ */
27
+ export function compareVersionsDesc(a, b) {
28
+ return b.version.localeCompare(a.version, undefined, { numeric: true });
29
+ }
30
+
31
+ /**
32
+ * 从 agent 条目中获取最新版本
33
+ */
34
+ export function getLatestVersion(entries) {
35
+ if (!entries || entries.length === 0) return null;
36
+ return [...entries].sort(compareVersionsDesc)[0];
37
+ }
38
+
39
+ /**
40
+ * 按下载量和更新时间排序 Agent 列表
41
+ * 下载量降序,下载量一致时按更新时间降序
42
+ */
43
+ export function sortByDownloadsAndTime(agents) {
44
+ return agents.sort((a, b) => {
45
+ if (b.downloads !== a.downloads) {
46
+ return b.downloads - a.downloads;
47
+ }
48
+ const timeA = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
49
+ const timeB = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
50
+ return timeB - timeA;
51
+ });
52
+ }
53
+
54
+ export async function publishBundle(bundleDir, registryDir) {
55
+ const manifest = await readJson(path.join(bundleDir, "MANIFEST.json"));
56
+ if (manifest.runtime?.type !== "openclaw") {
57
+ throw new Error("Only OpenClaw bundles are supported.");
58
+ }
59
+ if ((manifest.includes?.memory?.private ?? 0) > 0) {
60
+ throw new Error("Public publish rejected: private memory detected.");
61
+ }
62
+
63
+ const targetDir = path.join(registryDir, "agents", manifest.slug, manifest.version);
64
+ await ensureDir(path.join(registryDir, "agents", manifest.slug));
65
+ await copyDir(bundleDir, targetDir);
66
+
67
+ const indexPath = path.join(registryDir, "index.json");
68
+ const index = (await pathExists(indexPath)) ? await readJson(indexPath) : { agents: [] };
69
+ index.agents = index.agents.filter(
70
+ (entry) => !(entry.slug === manifest.slug && entry.version === manifest.version),
71
+ );
72
+ index.agents.push({
73
+ slug: manifest.slug,
74
+ version: manifest.version,
75
+ name: manifest.name,
76
+ description: manifest.description,
77
+ runtime: manifest.runtime,
78
+ updatedAt: new Date().toISOString(),
79
+ tags: manifest.metadata?.tags || [],
80
+ category: manifest.metadata?.category || 'General',
81
+ });
82
+ index.agents.sort((left, right) => left.slug.localeCompare(right.slug));
83
+ await writeJson(indexPath, index);
84
+
85
+ return manifest;
86
+ }
87
+
88
+ export async function searchRegistry(registryDir, query) {
89
+ const indexPath = path.join(registryDir, "index.json");
90
+ if (!(await pathExists(indexPath))) {
91
+ return [];
92
+ }
93
+ const index = await readJson(indexPath);
94
+ const normalized = query.toLowerCase().trim();
95
+
96
+ // 空查询返回所有
97
+ if (!normalized) {
98
+ return index.agents;
99
+ }
100
+
101
+ return index.agents.filter((entry) => {
102
+ // 搜索 slug
103
+ if (entry.slug?.toLowerCase().includes(normalized)) return true;
104
+ // 搜索 name
105
+ if (entry.name?.toLowerCase().includes(normalized)) return true;
106
+ // 搜索 description
107
+ if (entry.description?.toLowerCase().includes(normalized)) return true;
108
+ // 搜索 tags
109
+ if (entry.tags?.some(tag => tag.toLowerCase().includes(normalized))) return true;
110
+ // 搜索 category
111
+ if (entry.category?.toLowerCase().includes(normalized)) return true;
112
+ return false;
113
+ });
114
+ }
115
+
116
+ export async function readAgentInfo(registryDir, agentSpec) {
117
+ const { slug, version } = parseSpec(agentSpec);
118
+ const baseDir = path.join(registryDir, "agents", slug);
119
+ if (!(await pathExists(baseDir))) {
120
+ throw new Error(`Agent not found: ${slug}`);
121
+ }
122
+
123
+ let selectedVersion = version;
124
+ if (!selectedVersion) {
125
+ const index = await readJson(path.join(registryDir, "index.json"));
126
+ const versions = index.agents.filter((entry) => entry.slug === slug).map((entry) => entry.version).sort();
127
+ selectedVersion = versions.at(-1);
128
+ }
129
+ return readJson(path.join(baseDir, selectedVersion, "MANIFEST.json"));
130
+ }
package/src/lib/remote.js CHANGED
@@ -1,11 +1,11 @@
1
- import { fetchJsonWithFallback } from "./http.js";
2
-
3
- export function resolveServerUrl(options = {}) {
4
- return options.server || "https://agenthub.cyou";
5
- }
6
-
7
- export async function fetchRemoteJson(pathname, options = {}) {
8
- const serverUrl = resolveServerUrl(options);
9
- const url = new URL(pathname, serverUrl).toString();
10
- return fetchJsonWithFallback(url);
11
- }
1
+ import { fetchJsonWithFallback } from "./http.js";
2
+
3
+ export function resolveServerUrl(options = {}) {
4
+ return options.server || "https://agenthub.cyou";
5
+ }
6
+
7
+ export async function fetchRemoteJson(pathname, options = {}) {
8
+ const serverUrl = resolveServerUrl(options);
9
+ const url = new URL(pathname, serverUrl).toString();
10
+ return fetchJsonWithFallback(url);
11
+ }