agent-resource-management 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/README.md +196 -0
  3. package/bun.lock +32 -0
  4. package/data/skills/bad-name-skill/SKILL.md +8 -0
  5. package/data/skills/github-tool/SKILL.md +11 -0
  6. package/data/skills/invalid-skill/SKILL.md +3 -0
  7. package/data/skills/pdf-tool/SKILL.md +11 -0
  8. package/data/skills/pdf-tool.zip +0 -0
  9. package/dist/main.js +1330 -0
  10. package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/AGENT.md +18 -0
  11. package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/knowledges//344/273/277/347/234/237/345/271/263/345/217/260Loki/346/227/245/345/277/227/346/216/222/346/237/245/346/226/271/346/263/225.md +27 -0
  12. package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/knowledges//344/273/277/347/234/237/345/271/263/345/217/260/344/273/273/345/212/241/350/247/246/345/217/221/345/220/270/346/224/266/345/231/250/344/270/216/345/215/240/344/275/215/350/247/246/345/217/221/345/220/270/346/224/266/345/231/250/344/275/277/347/224/250/345/234/272/346/231/257.md +18 -0
  13. package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/knowledges//344/273/277/347/234/237/345/271/263/345/217/260/345/220/216/347/253/257Swagger/346/216/245/345/217/243/346/226/207/346/241/243.md +22 -0
  14. package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/knowledges//344/273/277/347/234/237/345/271/263/345/217/260/345/275/223/345/211/215/350/277/220/350/241/214/345/256/236/344/276/213/345/217/212/345/256/236/344/276/213/350/277/220/350/241/214/346/227/245/345/277/227/346/216/222/346/237/245.md +39 -0
  15. package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/knowledges//344/273/277/347/234/237/345/271/263/345/217/260/346/216/245/345/217/243/346/216/222/346/237/245/350/203/214/346/231/257/347/237/245/350/257/206.md +49 -0
  16. package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/knowledges//344/273/277/347/234/237/350/264/247/350/275/275/347/224/237/345/221/275/345/221/250/346/234/237/346/237/245/350/257/242/346/265/201/347/250/213.md +165 -0
  17. package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/knowledges//345/244/251/350/275/246/350/260/203/345/272/246/347/263/273/347/273/237/351/207/215/347/273/204/346/216/245/345/217/243/350/260/203/347/224/250/344/270/216/346/227/245/345/277/227/345/210/206/346/236/220/346/226/271/346/263/225.md +137 -0
  18. package/package.json +20 -0
  19. package/src/cmd/agent.ts +137 -0
  20. package/src/cmd/auth.ts +50 -0
  21. package/src/cmd/knowledge.ts +171 -0
  22. package/src/cmd/server.ts +11 -0
  23. package/src/cmd/skill.ts +220 -0
  24. package/src/lib/client.ts +274 -0
  25. package/src/lib/formatter.ts +196 -0
  26. package/src/lib/storage.ts +63 -0
  27. package/src/lib/validate.ts +210 -0
  28. package/src/main.ts +235 -0
  29. package/test-regression.sh +273 -0
  30. package/tsconfig.json +17 -0
@@ -0,0 +1,210 @@
1
+ import { readFileSync, existsSync, statSync } from 'fs';
2
+ import { execSync } from 'child_process';
3
+ import { join, extname } from 'path';
4
+ import { mkdtempSync, rmSync } from 'fs';
5
+
6
+ export interface ValidationResult {
7
+ valid: boolean;
8
+ errors: string[];
9
+ warnings: string[];
10
+ metadata?: {
11
+ name?: string;
12
+ description?: string;
13
+ license?: string;
14
+ compatibility?: string;
15
+ allowedTools?: string[];
16
+ metadata?: Record<string, string>;
17
+ };
18
+ }
19
+
20
+ export function validateZip(filePath: string): ValidationResult {
21
+ const result: ValidationResult = {
22
+ valid: true,
23
+ errors: [],
24
+ warnings: [],
25
+ };
26
+
27
+ if (!existsSync(filePath)) {
28
+ result.valid = false;
29
+ result.errors.push(`文件不存在: ${filePath}`);
30
+ return result;
31
+ }
32
+
33
+ if (extname(filePath).toLowerCase() !== '.zip') {
34
+ result.valid = false;
35
+ result.errors.push('文件必须是 ZIP 格式');
36
+ return result;
37
+ }
38
+
39
+ const stats = statSync(filePath);
40
+ if (stats.size === 0) {
41
+ result.valid = false;
42
+ result.errors.push('ZIP 文件为空');
43
+ return result;
44
+ }
45
+
46
+ try {
47
+ const tempDir = mkdtempSync('/tmp/skill-validate-');
48
+ execSync(`unzip -o "${filePath}" -d "${tempDir}"`, { stdio: 'pipe' });
49
+
50
+ const entries = execSync(`unzip -l "${filePath}"`, { encoding: 'utf-8' });
51
+ const hasSkillMd = entries.includes('SKILL.md');
52
+
53
+ if (!hasSkillMd) {
54
+ result.valid = false;
55
+ result.errors.push('ZIP 包内缺少 SKILL.md 文件');
56
+ }
57
+
58
+ const skillMdPath = join(tempDir, 'SKILL.md');
59
+ if (existsSync(skillMdPath)) {
60
+ const skillMdContent = readFileSync(skillMdPath, 'utf-8');
61
+ const frontmatterMatch = skillMdContent.match(/^---\n([\s\S]*?)\n---/);
62
+
63
+ if (frontmatterMatch) {
64
+ const frontmatter = frontmatterMatch[1];
65
+ result.metadata = {};
66
+
67
+ const nameMatch = frontmatter.match(/name:\s*(.+)/);
68
+ const descMatch = frontmatter.match(/description:\s*(.+)/);
69
+ const licenseMatch = frontmatter.match(/license:\s*(.+)/);
70
+ const compatMatch = frontmatter.match(/compatibility:\s*(.+)/);
71
+ const toolsMatch = frontmatter.match(/allowed-tools:\s*(.+)/);
72
+ const metaMatch = frontmatter.match(/metadata:\s*([\s\S]*?)(?=\n\w|$)/);
73
+
74
+ if (nameMatch) {
75
+ const name = nameMatch[1].trim();
76
+ if (name.length < 1 || name.length > 64) {
77
+ result.valid = false;
78
+ result.errors.push('name 长度必须在 1-64 字符之间');
79
+ }
80
+ if (!/^[a-z0-9-]+$/.test(name)) {
81
+ result.valid = false;
82
+ result.errors.push('name 只能包含小写字母、数字和连字符');
83
+ }
84
+ result.metadata.name = name;
85
+ } else {
86
+ result.valid = false;
87
+ result.errors.push('缺少 name 字段');
88
+ }
89
+
90
+ if (descMatch) {
91
+ const desc = descMatch[1].trim();
92
+ if (desc.length < 1 || desc.length > 1024) {
93
+ result.valid = false;
94
+ result.errors.push('description 长度必须在 1-1024 字符之间');
95
+ }
96
+ result.metadata.description = desc;
97
+ } else {
98
+ result.valid = false;
99
+ result.errors.push('缺少 description 字段');
100
+ }
101
+
102
+ if (licenseMatch) {
103
+ result.metadata.license = licenseMatch[1].trim();
104
+ }
105
+
106
+ if (compatMatch) {
107
+ result.metadata.compatibility = compatMatch[1].trim();
108
+ }
109
+
110
+ if (toolsMatch) {
111
+ result.metadata.allowedTools = toolsMatch[1].split(',').map(t => t.trim());
112
+ }
113
+
114
+ if (metaMatch) {
115
+ try {
116
+ result.metadata.metadata = {};
117
+ const metaLines = metaMatch[1].split('\n').filter(l => l.trim());
118
+ for (const line of metaLines) {
119
+ const [key, ...valueParts] = line.split(':');
120
+ if (key && valueParts.length) {
121
+ result.metadata.metadata[key.trim()] = valueParts.join(':').trim();
122
+ }
123
+ }
124
+ } catch {
125
+ result.warnings.push('metadata 格式解析失败');
126
+ }
127
+ }
128
+ } else {
129
+ result.valid = false;
130
+ result.errors.push('SKILL.md 缺少 frontmatter (--- 包裹的 YAML)');
131
+ }
132
+ }
133
+
134
+ rmSync(tempDir, { recursive: true, force: true });
135
+ } catch (err) {
136
+ result.valid = false;
137
+ result.errors.push(`解压失败: ${err instanceof Error ? err.message : '未知错误'}`);
138
+ }
139
+
140
+ return result;
141
+ }
142
+
143
+ export function validateSkillDir(dirPath: string): ValidationResult {
144
+ const result: ValidationResult = {
145
+ valid: true,
146
+ errors: [],
147
+ warnings: [],
148
+ };
149
+
150
+ if (!existsSync(dirPath)) {
151
+ result.valid = false;
152
+ result.errors.push(`目录不存在: ${dirPath}`);
153
+ return result;
154
+ }
155
+
156
+ const skillMdPath = join(dirPath, 'SKILL.md');
157
+ if (!existsSync(skillMdPath)) {
158
+ result.valid = false;
159
+ result.errors.push('目录内缺少 SKILL.md 文件');
160
+ return result;
161
+ }
162
+
163
+ try {
164
+ const skillMdContent = readFileSync(skillMdPath, 'utf-8');
165
+ const frontmatterMatch = skillMdContent.match(/^---\n([\s\S]*?)\n---/);
166
+
167
+ if (frontmatterMatch) {
168
+ const frontmatter = frontmatterMatch[1];
169
+ result.metadata = {};
170
+
171
+ const nameMatch = frontmatter.match(/name:\s*(.+)/);
172
+ const descMatch = frontmatter.match(/description:\s*(.+)/);
173
+
174
+ if (nameMatch) {
175
+ const name = nameMatch[1].trim();
176
+ if (name.length < 1 || name.length > 64) {
177
+ result.valid = false;
178
+ result.errors.push('name 长度必须在 1-64 字符之间');
179
+ }
180
+ if (!/^[a-z0-9-]+$/.test(name)) {
181
+ result.valid = false;
182
+ result.errors.push('name 只能包含小写字母、数字和连字符');
183
+ }
184
+ result.metadata.name = name;
185
+ } else {
186
+ result.valid = false;
187
+ result.errors.push('缺少 name 字段');
188
+ }
189
+
190
+ if (descMatch) {
191
+ const desc = descMatch[1].trim();
192
+ if (desc.length < 1 || desc.length > 1024) {
193
+ result.valid = false;
194
+ result.errors.push('description 长度必须在 1-1024 字符之间');
195
+ }
196
+ result.metadata.description = desc;
197
+ } else {
198
+ result.valid = false;
199
+ result.errors.push('缺少 description 字段');
200
+ }
201
+ } else {
202
+ result.valid = false;
203
+ result.errors.push('SKILL.md 缺少 frontmatter (--- 包裹的 YAML)');
204
+ }
205
+ } catch (err) {
206
+ result.warnings.push(`SKILL.md 读取失败: ${err instanceof Error ? err.message : '未知错误'}`);
207
+ }
208
+
209
+ return result;
210
+ }
package/src/main.ts ADDED
@@ -0,0 +1,235 @@
1
+ import { login, logout, getCurrentUser } from './cmd/auth';
2
+ import { listSkills, searchSkills, infoSkill, downloadSkill, uploadSkill, mySkills, deleteSkill, validateSkill } from './cmd/skill';
3
+ import { listAgents, searchAgents, infoAgent, downloadAgent } from './cmd/agent';
4
+ import { listKnowledge, searchKnowledge, infoKnowledge, downloadKnowledge, uploadKnowledge, myKnowledge, deleteKnowledge } from './cmd/knowledge';
5
+ import { showServer, setServer } from './cmd/server';
6
+
7
+ const args = process.argv.slice(2);
8
+ const command = args[0];
9
+ const subCommand = args[1];
10
+
11
+ async function main() {
12
+ switch (command) {
13
+ case 'login':
14
+ if (!args[1] || !args[2]) {
15
+ console.error('用法: arm login <server-url> <api-key>');
16
+ process.exit(1);
17
+ }
18
+ await login(args[1], args[2]);
19
+ break;
20
+
21
+ case 'logout':
22
+ await logout();
23
+ break;
24
+
25
+ case 'server':
26
+ if (subCommand === 'set' && args[2]) {
27
+ setServer(args[2]);
28
+ } else {
29
+ showServer();
30
+ }
31
+ break;
32
+
33
+ case 'skill':
34
+ switch (subCommand) {
35
+ case 'ls':
36
+ await listSkills();
37
+ break;
38
+ case 'search':
39
+ if (!args[2]) {
40
+ console.error('用法: arm skill search <keyword>');
41
+ process.exit(1);
42
+ }
43
+ await searchSkills(args[2]);
44
+ break;
45
+ case 'info':
46
+ if (!args[2]) {
47
+ console.error('用法: arm skill info <name>');
48
+ process.exit(1);
49
+ }
50
+ await infoSkill(args[2]);
51
+ break;
52
+ case 'download':
53
+ if (!args[2]) {
54
+ console.error('用法: arm skill download <name> [output-dir]');
55
+ process.exit(1);
56
+ }
57
+ await downloadSkill(args[2], args[3]);
58
+ break;
59
+ case 'upload':
60
+ if (!args[2]) {
61
+ console.error('用法: arm skill upload <path>');
62
+ process.exit(1);
63
+ }
64
+ await uploadSkill(args[2]);
65
+ break;
66
+ case 'my':
67
+ await mySkills();
68
+ break;
69
+ case 'delete':
70
+ if (!args[2]) {
71
+ console.error('用法: arm skill delete <name>');
72
+ process.exit(1);
73
+ }
74
+ await deleteSkill(args[2]);
75
+ break;
76
+ case 'validate':
77
+ if (!args[2]) {
78
+ console.error('用法: arm skill validate <path>');
79
+ process.exit(1);
80
+ }
81
+ await validateSkill(args[2]);
82
+ break;
83
+ default:
84
+ console.log(`
85
+ 可用命令:
86
+ arm login <server-url> <api-key> 登录
87
+ arm logout 登出
88
+ arm skill ls 列出所有 Skill
89
+ arm skill search <keyword> 搜索 Skill
90
+ arm skill info <name> 查看 Skill 详情
91
+ arm skill download <name> [dir] 下载 Skill
92
+ arm skill upload <path> 上传 Skill
93
+ arm skill my 我的发布
94
+ arm skill delete <name> 删除 Skill
95
+ arm skill validate <path> 验证 Skill 格式
96
+ arm server 显示当前服务端
97
+ arm server set <url> 设置服务端
98
+ `);
99
+ }
100
+ break;
101
+
102
+ case 'knowledge':
103
+ switch (subCommand) {
104
+ case 'ls':
105
+ await listKnowledge();
106
+ break;
107
+ case 'search':
108
+ if (!args[2]) {
109
+ console.error('用法: arm knowledge search <keyword>');
110
+ process.exit(1);
111
+ }
112
+ await searchKnowledge(args[2]);
113
+ break;
114
+ case 'info':
115
+ if (!args[2]) {
116
+ console.error('用法: arm knowledge info <name>');
117
+ process.exit(1);
118
+ }
119
+ await infoKnowledge(args[2]);
120
+ break;
121
+ case 'download':
122
+ if (!args[2]) {
123
+ console.error('用法: arm knowledge download <name> [output-dir]');
124
+ process.exit(1);
125
+ }
126
+ await downloadKnowledge(args[2], args[3]);
127
+ break;
128
+ case 'upload':
129
+ if (!args[2]) {
130
+ console.error('用法: arm knowledge upload <path>');
131
+ process.exit(1);
132
+ }
133
+ await uploadKnowledge(args[2]);
134
+ break;
135
+ case 'my':
136
+ await myKnowledge();
137
+ break;
138
+ case 'delete':
139
+ if (!args[2]) {
140
+ console.error('用法: arm knowledge delete <name>');
141
+ process.exit(1);
142
+ }
143
+ await deleteKnowledge(args[2]);
144
+ break;
145
+ default:
146
+ console.log(`
147
+ 可用命令:
148
+ arm knowledge ls 列出所有 Knowledge
149
+ arm knowledge search <keyword> 搜索 Knowledge
150
+ arm knowledge info <name> 查看 Knowledge 详情
151
+ arm knowledge download <name> [dir] 下载 Knowledge
152
+ arm knowledge upload <path> 上传 Knowledge
153
+ arm knowledge my 我的发布
154
+ arm knowledge delete <name> 删除 Knowledge
155
+ `);
156
+ }
157
+ break;
158
+
159
+ case 'me':
160
+ await getCurrentUser();
161
+ break;
162
+
163
+ case 'agent':
164
+ switch (subCommand) {
165
+ case 'ls':
166
+ await listAgents();
167
+ break;
168
+ case 'search':
169
+ if (!args[2]) {
170
+ console.error('用法: arm agent search <keyword>');
171
+ process.exit(1);
172
+ }
173
+ await searchAgents(args[2]);
174
+ break;
175
+ case 'info':
176
+ if (!args[2]) {
177
+ console.error('用法: arm agent info <name>');
178
+ process.exit(1);
179
+ }
180
+ await infoAgent(args[2]);
181
+ break;
182
+ case 'download':
183
+ if (!args[2]) {
184
+ console.error('用法: arm agent download <name> [output-dir]');
185
+ process.exit(1);
186
+ }
187
+ await downloadAgent(args[2], args[3]);
188
+ break;
189
+ default:
190
+ console.log(`
191
+ 可用命令:
192
+ arm agent ls 列出所有 Agent
193
+ arm agent search <keyword> 搜索 Agent
194
+ arm agent info <name> 查看 Agent 详情
195
+ arm agent download <name> [dir] 下载 Agent
196
+ `);
197
+ }
198
+ break;
199
+
200
+ default:
201
+ console.log(`
202
+ Agent Resource Management (arm)
203
+
204
+ 用法:
205
+ arm login <server-url> <api-key> 登录
206
+ arm logout 登出
207
+ arm skill ls 列出所有 Skill
208
+ arm skill search <keyword> 搜索 Skill
209
+ arm skill info <name> 查看 Skill 详情
210
+ arm skill download <name> [dir] 下载 Skill
211
+ arm skill upload <path> 上传 Skill
212
+ arm skill my 我的发布
213
+ arm skill delete <name> 删除 Skill
214
+ arm skill validate <path> 验证 Skill 格式
215
+ arm knowledge ls 列出所有 Knowledge
216
+ arm knowledge search <keyword> 搜索 Knowledge
217
+ arm knowledge info <name> 查看 Knowledge 详情
218
+ arm knowledge download <name> [dir] 下载 Knowledge
219
+ arm knowledge upload <path> 上传 Knowledge
220
+ arm knowledge my 我的发布
221
+ arm knowledge delete <name> 删除 Knowledge
222
+ arm agent ls 列出所有 Agent
223
+ arm agent search <keyword> 搜索 Agent
224
+ arm agent info <name> 查看 Agent 详情
225
+ arm agent download <name> [dir] 下载 Agent
226
+ arm server 显示当前服务端
227
+ arm server set <url> 设置服务端
228
+ `);
229
+ }
230
+ }
231
+
232
+ main().catch((err) => {
233
+ console.error('Error:', err);
234
+ process.exit(1);
235
+ });