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.
- package/.claude/settings.local.json +8 -0
- package/README.md +196 -0
- package/bun.lock +32 -0
- package/data/skills/bad-name-skill/SKILL.md +8 -0
- package/data/skills/github-tool/SKILL.md +11 -0
- package/data/skills/invalid-skill/SKILL.md +3 -0
- package/data/skills/pdf-tool/SKILL.md +11 -0
- package/data/skills/pdf-tool.zip +0 -0
- package/dist/main.js +1330 -0
- package/dist//344/273/277/347/234/237/350/260/203/350/257/225/345/212/251/346/211/213/AGENT.md +18 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/package.json +20 -0
- package/src/cmd/agent.ts +137 -0
- package/src/cmd/auth.ts +50 -0
- package/src/cmd/knowledge.ts +171 -0
- package/src/cmd/server.ts +11 -0
- package/src/cmd/skill.ts +220 -0
- package/src/lib/client.ts +274 -0
- package/src/lib/formatter.ts +196 -0
- package/src/lib/storage.ts +63 -0
- package/src/lib/validate.ts +210 -0
- package/src/main.ts +235 -0
- package/test-regression.sh +273 -0
- package/tsconfig.json +17 -0
package/src/cmd/auth.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ApiClient } from '../lib/client';
|
|
2
|
+
import { loadConfig, saveConfig } from '../lib/storage';
|
|
3
|
+
import { success, error, info } from '../lib/formatter';
|
|
4
|
+
|
|
5
|
+
export async function login(serverUrl: string, apiKey: string): Promise<void> {
|
|
6
|
+
try {
|
|
7
|
+
const client = new ApiClient(serverUrl);
|
|
8
|
+
const loginRes = await client.login(apiKey);
|
|
9
|
+
|
|
10
|
+
saveConfig({
|
|
11
|
+
serverUrl,
|
|
12
|
+
token: loginRes.token,
|
|
13
|
+
user: loginRes.user,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
success(`登录成功! 欢迎, ${loginRes.user.name}`);
|
|
17
|
+
} catch (err) {
|
|
18
|
+
error(`登录失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function logout(): Promise<void> {
|
|
24
|
+
const config = loadConfig();
|
|
25
|
+
if (config?.token) {
|
|
26
|
+
config.token = undefined;
|
|
27
|
+
config.user = undefined;
|
|
28
|
+
saveConfig(config);
|
|
29
|
+
success('已退出登录');
|
|
30
|
+
} else {
|
|
31
|
+
info('未登录');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function getCurrentUser(): Promise<void> {
|
|
36
|
+
const config = loadConfig();
|
|
37
|
+
if (!config?.token) {
|
|
38
|
+
error('未登录,请先运行 arm login');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
43
|
+
try {
|
|
44
|
+
const user = await client.me();
|
|
45
|
+
console.log(`当前用户: ${user.name} (${user.email})`);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
error(`获取用户信息失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { ApiClient } from '../lib/client';
|
|
2
|
+
import { loadConfig } from '../lib/storage';
|
|
3
|
+
import { formatKnowledge, formatKnowledgeDetail, success, error, info } from '../lib/formatter';
|
|
4
|
+
import { writeFileSync, existsSync, statSync } from 'fs';
|
|
5
|
+
import { join, basename, dirname } from 'path';
|
|
6
|
+
import { execSync } from 'child_process';
|
|
7
|
+
import { mkdtempSync, rmSync } from 'fs';
|
|
8
|
+
|
|
9
|
+
export async function listKnowledge(): Promise<void> {
|
|
10
|
+
const config = loadConfig();
|
|
11
|
+
if (!config?.token) {
|
|
12
|
+
error('未登录,请先运行 arm login');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
17
|
+
try {
|
|
18
|
+
const result = await client.listKnowledge();
|
|
19
|
+
if (result.knowledges.length === 0) {
|
|
20
|
+
info('暂无 Knowledge');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
console.log(`\n共 ${result.total} 个 Knowledge:\n`);
|
|
24
|
+
for (const knowledge of result.knowledges) {
|
|
25
|
+
console.log(formatKnowledge(knowledge));
|
|
26
|
+
console.log('');
|
|
27
|
+
}
|
|
28
|
+
} catch (err) {
|
|
29
|
+
error(`获取列表失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function searchKnowledge(keyword: string): Promise<void> {
|
|
35
|
+
const config = loadConfig();
|
|
36
|
+
if (!config?.token) {
|
|
37
|
+
error('未登录,请先运行 arm login');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
42
|
+
try {
|
|
43
|
+
const result = await client.listKnowledge(keyword);
|
|
44
|
+
if (result.knowledges.length === 0) {
|
|
45
|
+
info(`没有找到包含 "${keyword}" 的 Knowledge`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
console.log(`\n找到 ${result.total} 个结果:\n`);
|
|
49
|
+
for (const knowledge of result.knowledges) {
|
|
50
|
+
console.log(formatKnowledge(knowledge));
|
|
51
|
+
console.log('');
|
|
52
|
+
}
|
|
53
|
+
} catch (err) {
|
|
54
|
+
error(`搜索失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function infoKnowledge(name: string): Promise<void> {
|
|
60
|
+
const config = loadConfig();
|
|
61
|
+
if (!config?.token) {
|
|
62
|
+
error('未登录,请先运行 arm login');
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
67
|
+
try {
|
|
68
|
+
const knowledge = await client.getKnowledge(name);
|
|
69
|
+
console.log(formatKnowledgeDetail(knowledge));
|
|
70
|
+
} catch (err) {
|
|
71
|
+
error(`获取详情失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export async function downloadKnowledge(name: string, outputDir?: string): Promise<void> {
|
|
77
|
+
const config = loadConfig();
|
|
78
|
+
if (!config?.token) {
|
|
79
|
+
error('未登录,请先运行 arm login');
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
84
|
+
try {
|
|
85
|
+
info(`正在下载 ${name}...`);
|
|
86
|
+
const buffer = await client.downloadKnowledge(name);
|
|
87
|
+
const outputPath = join(outputDir || '.', `${name}.zip`);
|
|
88
|
+
writeFileSync(outputPath, Buffer.from(buffer));
|
|
89
|
+
success(`已下载到 ${outputPath}`);
|
|
90
|
+
} catch (err) {
|
|
91
|
+
error(`下载失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function uploadKnowledge(filePath: string): Promise<void> {
|
|
97
|
+
const config = loadConfig();
|
|
98
|
+
if (!config?.token) {
|
|
99
|
+
error('未登录,请先运行 arm login');
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!existsSync(filePath)) {
|
|
104
|
+
error(`上传失败: 目录不存在: ${filePath}`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const knowledgeName = basename(filePath);
|
|
109
|
+
const tempDir = mkdtempSync('/tmp/knowledge-upload-');
|
|
110
|
+
const zipPath = join(tempDir, `${knowledgeName}.zip`);
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
if (statSync(filePath).isDirectory()) {
|
|
114
|
+
execSync(`cd "${dirname(filePath)}" && zip -r "${zipPath}" "${basename(filePath)}" -x ".*"`, { stdio: 'pipe' });
|
|
115
|
+
} else {
|
|
116
|
+
execSync(`cp "${filePath}" "${zipPath}"`, { stdio: 'pipe' });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
120
|
+
info(`正在上传 ${filePath}...`);
|
|
121
|
+
const knowledge = await client.uploadKnowledge(zipPath);
|
|
122
|
+
success(`上传成功! Knowledge: ${knowledge.name}`);
|
|
123
|
+
} catch (err) {
|
|
124
|
+
error(`上传失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
} finally {
|
|
127
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function myKnowledge(): Promise<void> {
|
|
132
|
+
const config = loadConfig();
|
|
133
|
+
if (!config?.token) {
|
|
134
|
+
error('未登录,请先运行 arm login');
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
139
|
+
try {
|
|
140
|
+
const knowledges = await client.getMyKnowledge();
|
|
141
|
+
if (knowledges.length === 0) {
|
|
142
|
+
info('您还没有发布任何 Knowledge');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
console.log(`\n我发布的 Knowledge (共 ${knowledges.length}):\n`);
|
|
146
|
+
for (const knowledge of knowledges) {
|
|
147
|
+
console.log(formatKnowledge(knowledge));
|
|
148
|
+
console.log('');
|
|
149
|
+
}
|
|
150
|
+
} catch (err) {
|
|
151
|
+
error(`获取列表失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export async function deleteKnowledge(name: string): Promise<void> {
|
|
157
|
+
const config = loadConfig();
|
|
158
|
+
if (!config?.token) {
|
|
159
|
+
error('未登录,请先运行 arm login');
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
164
|
+
try {
|
|
165
|
+
await client.deleteKnowledge(name);
|
|
166
|
+
success(`已删除 ${name}`);
|
|
167
|
+
} catch (err) {
|
|
168
|
+
error(`删除失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { getServerUrl, setServerUrl } from '../lib/storage';
|
|
2
|
+
import { info } from '../lib/formatter';
|
|
3
|
+
|
|
4
|
+
export function showServer(): void {
|
|
5
|
+
info(`当前服务端: ${getServerUrl()}`);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function setServer(url: string): void {
|
|
9
|
+
setServerUrl(url);
|
|
10
|
+
info(`已设置服务端: ${url}`);
|
|
11
|
+
}
|
package/src/cmd/skill.ts
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { ApiClient } from '../lib/client';
|
|
2
|
+
import { loadConfig } from '../lib/storage';
|
|
3
|
+
import { formatSkill, formatSkillDetail, success, error, info } from '../lib/formatter';
|
|
4
|
+
import { validateZip, validateSkillDir } from '../lib/validate';
|
|
5
|
+
import { writeFileSync, createWriteStream, existsSync, mkdirSync, statSync } from 'fs';
|
|
6
|
+
import { join, basename, dirname } from 'path';
|
|
7
|
+
import { Readable } from 'stream';
|
|
8
|
+
import { finished } from 'stream/promises';
|
|
9
|
+
import { execSync } from 'child_process';
|
|
10
|
+
import { mkdtempSync, rmSync } from 'fs';
|
|
11
|
+
|
|
12
|
+
export async function listSkills(): Promise<void> {
|
|
13
|
+
const config = loadConfig();
|
|
14
|
+
if (!config?.token) {
|
|
15
|
+
error('未登录,请先运行 arm login');
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
20
|
+
try {
|
|
21
|
+
const result = await client.listSkills();
|
|
22
|
+
if (result.skills.length === 0) {
|
|
23
|
+
info('暂无 Skill');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
console.log(`\n共 ${result.total} 个 Skill:\n`);
|
|
27
|
+
for (const skill of result.skills) {
|
|
28
|
+
console.log(formatSkill(skill));
|
|
29
|
+
console.log('');
|
|
30
|
+
}
|
|
31
|
+
} catch (err) {
|
|
32
|
+
error(`获取列表失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function searchSkills(keyword: string): Promise<void> {
|
|
38
|
+
const config = loadConfig();
|
|
39
|
+
if (!config?.token) {
|
|
40
|
+
error('未登录,请先运行 arm login');
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
45
|
+
try {
|
|
46
|
+
const result = await client.listSkills(keyword);
|
|
47
|
+
if (result.skills.length === 0) {
|
|
48
|
+
info(`没有找到包含 "${keyword}" 的 Skill`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
console.log(`\n找到 ${result.total} 个结果:\n`);
|
|
52
|
+
for (const skill of result.skills) {
|
|
53
|
+
console.log(formatSkill(skill));
|
|
54
|
+
console.log('');
|
|
55
|
+
}
|
|
56
|
+
} catch (err) {
|
|
57
|
+
error(`搜索失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export async function infoSkill(name: string): Promise<void> {
|
|
63
|
+
const config = loadConfig();
|
|
64
|
+
if (!config?.token) {
|
|
65
|
+
error('未登录,请先运行 arm login');
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
70
|
+
try {
|
|
71
|
+
const skill = await client.getSkill(name);
|
|
72
|
+
console.log(formatSkillDetail(skill));
|
|
73
|
+
} catch (err) {
|
|
74
|
+
error(`获取详情失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function downloadSkill(name: string, outputDir?: string): Promise<void> {
|
|
80
|
+
const config = loadConfig();
|
|
81
|
+
if (!config?.token) {
|
|
82
|
+
error('未登录,请先运行 arm login');
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
87
|
+
try {
|
|
88
|
+
info(`正在下载 ${name}...`);
|
|
89
|
+
const buffer = await client.downloadSkill(name);
|
|
90
|
+
const outputPath = join(outputDir || '.', `${name}.zip`);
|
|
91
|
+
writeFileSync(outputPath, Buffer.from(buffer));
|
|
92
|
+
success(`已下载到 ${outputPath}`);
|
|
93
|
+
} catch (err) {
|
|
94
|
+
error(`下载失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function uploadSkill(filePath: string): Promise<void> {
|
|
100
|
+
const config = loadConfig();
|
|
101
|
+
if (!config?.token) {
|
|
102
|
+
error('未登录,请先运行 arm login');
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!existsSync(filePath)) {
|
|
107
|
+
error(`上传失败: 目录不存在: ${filePath}`);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const isZip = filePath.toLowerCase().endsWith('.zip');
|
|
112
|
+
const validation = isZip ? validateZip(filePath) : validateSkillDir(filePath);
|
|
113
|
+
if (!validation.valid) {
|
|
114
|
+
error(`上传失败: ${validation.errors.join(', ')}`);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const skillName = validation.metadata?.name || basename(filePath);
|
|
119
|
+
const tempDir = mkdtempSync('/tmp/skill-upload-');
|
|
120
|
+
const zipPath = join(tempDir, `${skillName}.zip`);
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
if (isZip) {
|
|
124
|
+
execSync(`cp "${filePath}" "${zipPath}"`, { stdio: 'pipe' });
|
|
125
|
+
} else {
|
|
126
|
+
execSync(`cd "${dirname(filePath)}" && zip -r "${zipPath}" "${basename(filePath)}" -x ".*"`, { stdio: 'pipe' });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
130
|
+
info(`正在上传 ${filePath}...`);
|
|
131
|
+
const skill = await client.uploadSkill(zipPath);
|
|
132
|
+
success(`上传成功! Skill: ${skill.name}`);
|
|
133
|
+
} catch (err) {
|
|
134
|
+
console.error('DEBUG upload error:', err);
|
|
135
|
+
error(`上传失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
136
|
+
process.exit(1);
|
|
137
|
+
} finally {
|
|
138
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export async function mySkills(): Promise<void> {
|
|
143
|
+
const config = loadConfig();
|
|
144
|
+
if (!config?.token) {
|
|
145
|
+
error('未登录,请先运行 arm login');
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
150
|
+
try {
|
|
151
|
+
const skills = await client.getMySkills();
|
|
152
|
+
if (skills.length === 0) {
|
|
153
|
+
info('您还没有发布任何 Skill');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
console.log(`\n我发布的 Skill (共 ${skills.length}):\n`);
|
|
157
|
+
for (const skill of skills) {
|
|
158
|
+
console.log(formatSkill(skill));
|
|
159
|
+
console.log('');
|
|
160
|
+
}
|
|
161
|
+
} catch (err) {
|
|
162
|
+
error(`获取列表失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export async function deleteSkill(name: string): Promise<void> {
|
|
168
|
+
const config = loadConfig();
|
|
169
|
+
if (!config?.token) {
|
|
170
|
+
error('未登录,请先运行 arm login');
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const client = new ApiClient(config.serverUrl, config.token);
|
|
175
|
+
try {
|
|
176
|
+
await client.deleteSkill(name);
|
|
177
|
+
success(`已删除 ${name}`);
|
|
178
|
+
} catch (err) {
|
|
179
|
+
error(`删除失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export async function validateSkill(filePath: string): Promise<void> {
|
|
185
|
+
const isDir = existsSync(filePath) && statSync(filePath).isDirectory();
|
|
186
|
+
const result = isDir ? validateSkillDir(filePath) : validateZip(filePath);
|
|
187
|
+
|
|
188
|
+
if (result.valid) {
|
|
189
|
+
success('验证通过!');
|
|
190
|
+
} else {
|
|
191
|
+
error('验证失败:');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (result.errors.length > 0) {
|
|
195
|
+
console.log('\n错误:');
|
|
196
|
+
for (const err of result.errors) {
|
|
197
|
+
console.log(` - ${err}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (result.warnings.length > 0) {
|
|
202
|
+
console.log('\n警告:');
|
|
203
|
+
for (const warn of result.warnings) {
|
|
204
|
+
console.log(` - ${warn}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (result.metadata) {
|
|
209
|
+
console.log('\n元数据:');
|
|
210
|
+
if (result.metadata.name) console.log(` name: ${result.metadata.name}`);
|
|
211
|
+
if (result.metadata.description) console.log(` description: ${result.metadata.description}`);
|
|
212
|
+
if (result.metadata.license) console.log(` license: ${result.metadata.license}`);
|
|
213
|
+
if (result.metadata.compatibility) console.log(` compatibility: ${result.metadata.compatibility}`);
|
|
214
|
+
if (result.metadata.allowedTools) console.log(` allowed-tools: ${result.metadata.allowedTools.join(', ')}`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (!result.valid) {
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
}
|