agent-resource-management 1.4.1 → 2.1.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/dist/main.js +318 -32
- package/package.json +1 -1
- package/src/cmd/agent.ts +82 -40
- package/src/cmd/knowledge.ts +95 -2
- package/src/cmd/skill.ts +115 -2
- package/src/lib/output.ts +35 -0
- package/src/lib/storage.ts +1 -0
- package/src/main.ts +12 -0
- package/test-regression.sh +1 -1
package/src/cmd/skill.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ApiClient } from '../lib/client';
|
|
2
2
|
import { loadConfig } from '../lib/storage';
|
|
3
3
|
import { formatSkill, formatSkillDetail, success, error, info } from '../lib/formatter';
|
|
4
|
+
import { shouldOutputJson, outputJson } from '../lib/output';
|
|
4
5
|
import { validateZip, validateSkillDir } from '../lib/validate';
|
|
5
6
|
import { writeFileSync, createWriteStream, existsSync, mkdirSync, statSync } from 'fs';
|
|
6
7
|
import { join, basename, dirname } from 'path';
|
|
@@ -12,6 +13,10 @@ import { mkdtempSync, rmSync } from 'fs';
|
|
|
12
13
|
export async function listSkills(): Promise<void> {
|
|
13
14
|
const config = loadConfig();
|
|
14
15
|
if (!config?.token) {
|
|
16
|
+
if (shouldOutputJson()) {
|
|
17
|
+
outputJson({ success: false, error: { code: 'NOT_LOGGED_IN', message: '未登录,请先运行 arm login' } });
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
15
20
|
error('未登录,请先运行 arm login');
|
|
16
21
|
process.exit(1);
|
|
17
22
|
}
|
|
@@ -19,6 +24,10 @@ export async function listSkills(): Promise<void> {
|
|
|
19
24
|
const client = new ApiClient(config.serverUrl, config.token);
|
|
20
25
|
try {
|
|
21
26
|
const result = await client.listSkills();
|
|
27
|
+
if (shouldOutputJson()) {
|
|
28
|
+
outputJson({ success: true, data: result });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
22
31
|
if (result.skills.length === 0) {
|
|
23
32
|
info('暂无 Skill');
|
|
24
33
|
return;
|
|
@@ -29,6 +38,10 @@ export async function listSkills(): Promise<void> {
|
|
|
29
38
|
console.log('');
|
|
30
39
|
}
|
|
31
40
|
} catch (err) {
|
|
41
|
+
if (shouldOutputJson()) {
|
|
42
|
+
outputJson({ success: false, error: { code: 'LIST_FAILED', message: err instanceof Error ? err.message : '未知错误' } });
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
32
45
|
error(`获取列表失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
33
46
|
process.exit(1);
|
|
34
47
|
}
|
|
@@ -37,6 +50,10 @@ export async function listSkills(): Promise<void> {
|
|
|
37
50
|
export async function searchSkills(keyword: string): Promise<void> {
|
|
38
51
|
const config = loadConfig();
|
|
39
52
|
if (!config?.token) {
|
|
53
|
+
if (shouldOutputJson()) {
|
|
54
|
+
outputJson({ success: false, error: { code: 'NOT_LOGGED_IN', message: '未登录,请先运行 arm login' } });
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
40
57
|
error('未登录,请先运行 arm login');
|
|
41
58
|
process.exit(1);
|
|
42
59
|
}
|
|
@@ -44,6 +61,10 @@ export async function searchSkills(keyword: string): Promise<void> {
|
|
|
44
61
|
const client = new ApiClient(config.serverUrl, config.token);
|
|
45
62
|
try {
|
|
46
63
|
const result = await client.listSkills(keyword);
|
|
64
|
+
if (shouldOutputJson()) {
|
|
65
|
+
outputJson({ success: true, data: result });
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
47
68
|
if (result.skills.length === 0) {
|
|
48
69
|
info(`没有找到包含 "${keyword}" 的 Skill`);
|
|
49
70
|
return;
|
|
@@ -54,6 +75,10 @@ export async function searchSkills(keyword: string): Promise<void> {
|
|
|
54
75
|
console.log('');
|
|
55
76
|
}
|
|
56
77
|
} catch (err) {
|
|
78
|
+
if (shouldOutputJson()) {
|
|
79
|
+
outputJson({ success: false, error: { code: 'SEARCH_FAILED', message: err instanceof Error ? err.message : '未知错误' } });
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
57
82
|
error(`搜索失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
58
83
|
process.exit(1);
|
|
59
84
|
}
|
|
@@ -62,6 +87,10 @@ export async function searchSkills(keyword: string): Promise<void> {
|
|
|
62
87
|
export async function infoSkill(name: string): Promise<void> {
|
|
63
88
|
const config = loadConfig();
|
|
64
89
|
if (!config?.token) {
|
|
90
|
+
if (shouldOutputJson()) {
|
|
91
|
+
outputJson({ success: false, error: { code: 'NOT_LOGGED_IN', message: '未登录,请先运行 arm login' } });
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
65
94
|
error('未登录,请先运行 arm login');
|
|
66
95
|
process.exit(1);
|
|
67
96
|
}
|
|
@@ -69,8 +98,16 @@ export async function infoSkill(name: string): Promise<void> {
|
|
|
69
98
|
const client = new ApiClient(config.serverUrl, config.token);
|
|
70
99
|
try {
|
|
71
100
|
const skill = await client.getSkill(name);
|
|
101
|
+
if (shouldOutputJson()) {
|
|
102
|
+
outputJson({ success: true, data: skill });
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
72
105
|
console.log(formatSkillDetail(skill));
|
|
73
106
|
} catch (err) {
|
|
107
|
+
if (shouldOutputJson()) {
|
|
108
|
+
outputJson({ success: false, error: { code: 'INFO_FAILED', message: err instanceof Error ? err.message : '未知错误' } });
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
74
111
|
error(`获取详情失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
75
112
|
process.exit(1);
|
|
76
113
|
}
|
|
@@ -79,18 +116,32 @@ export async function infoSkill(name: string): Promise<void> {
|
|
|
79
116
|
export async function downloadSkill(name: string, outputDir?: string): Promise<void> {
|
|
80
117
|
const config = loadConfig();
|
|
81
118
|
if (!config?.token) {
|
|
119
|
+
if (shouldOutputJson()) {
|
|
120
|
+
outputJson({ success: false, error: { code: 'NOT_LOGGED_IN', message: '未登录,请先运行 arm login' } });
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
82
123
|
error('未登录,请先运行 arm login');
|
|
83
124
|
process.exit(1);
|
|
84
125
|
}
|
|
85
126
|
|
|
86
127
|
const client = new ApiClient(config.serverUrl, config.token);
|
|
87
128
|
try {
|
|
88
|
-
|
|
129
|
+
if (shouldOutputJson()) {
|
|
130
|
+
info(`正在下载 ${name}...`);
|
|
131
|
+
}
|
|
89
132
|
const buffer = await client.downloadSkill(name);
|
|
90
133
|
const outputPath = join(outputDir || '.', `${name}.zip`);
|
|
91
134
|
writeFileSync(outputPath, Buffer.from(buffer));
|
|
135
|
+
if (shouldOutputJson()) {
|
|
136
|
+
outputJson({ success: true, data: { path: outputPath } });
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
92
139
|
success(`已下载到 ${outputPath}`);
|
|
93
140
|
} catch (err) {
|
|
141
|
+
if (shouldOutputJson()) {
|
|
142
|
+
outputJson({ success: false, error: { code: 'DOWNLOAD_FAILED', message: err instanceof Error ? err.message : '未知错误' } });
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
94
145
|
error(`下载失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
95
146
|
process.exit(1);
|
|
96
147
|
}
|
|
@@ -99,11 +150,19 @@ export async function downloadSkill(name: string, outputDir?: string): Promise<v
|
|
|
99
150
|
export async function uploadSkill(filePath: string): Promise<void> {
|
|
100
151
|
const config = loadConfig();
|
|
101
152
|
if (!config?.token) {
|
|
153
|
+
if (shouldOutputJson()) {
|
|
154
|
+
outputJson({ success: false, error: { code: 'NOT_LOGGED_IN', message: '未登录,请先运行 arm login' } });
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
102
157
|
error('未登录,请先运行 arm login');
|
|
103
158
|
process.exit(1);
|
|
104
159
|
}
|
|
105
160
|
|
|
106
161
|
if (!existsSync(filePath)) {
|
|
162
|
+
if (shouldOutputJson()) {
|
|
163
|
+
outputJson({ success: false, error: { code: 'FILE_NOT_FOUND', message: `上传失败: 目录不存在: ${filePath}` } });
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
107
166
|
error(`上传失败: 目录不存在: ${filePath}`);
|
|
108
167
|
process.exit(1);
|
|
109
168
|
}
|
|
@@ -111,6 +170,10 @@ export async function uploadSkill(filePath: string): Promise<void> {
|
|
|
111
170
|
const isZip = filePath.toLowerCase().endsWith('.zip');
|
|
112
171
|
const validation = isZip ? validateZip(filePath) : validateSkillDir(filePath);
|
|
113
172
|
if (!validation.valid) {
|
|
173
|
+
if (shouldOutputJson()) {
|
|
174
|
+
outputJson({ success: false, error: { code: 'VALIDATION_FAILED', message: validation.errors.join(', ') } });
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
114
177
|
error(`上传失败: ${validation.errors.join(', ')}`);
|
|
115
178
|
process.exit(1);
|
|
116
179
|
}
|
|
@@ -127,11 +190,21 @@ export async function uploadSkill(filePath: string): Promise<void> {
|
|
|
127
190
|
}
|
|
128
191
|
|
|
129
192
|
const client = new ApiClient(config.serverUrl, config.token);
|
|
130
|
-
|
|
193
|
+
if (shouldOutputJson()) {
|
|
194
|
+
info(`正在上传 ${filePath}...`);
|
|
195
|
+
}
|
|
131
196
|
const skill = await client.uploadSkill(zipPath);
|
|
197
|
+
if (shouldOutputJson()) {
|
|
198
|
+
outputJson({ success: true, data: skill });
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
132
201
|
success(`上传成功! Skill: ${skill.name}`);
|
|
133
202
|
} catch (err) {
|
|
134
203
|
console.error('DEBUG upload error:', err);
|
|
204
|
+
if (shouldOutputJson()) {
|
|
205
|
+
outputJson({ success: false, error: { code: 'UPLOAD_FAILED', message: err instanceof Error ? err.message : '未知错误' } });
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
135
208
|
error(`上传失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
136
209
|
process.exit(1);
|
|
137
210
|
} finally {
|
|
@@ -142,6 +215,10 @@ export async function uploadSkill(filePath: string): Promise<void> {
|
|
|
142
215
|
export async function mySkills(): Promise<void> {
|
|
143
216
|
const config = loadConfig();
|
|
144
217
|
if (!config?.token) {
|
|
218
|
+
if (shouldOutputJson()) {
|
|
219
|
+
outputJson({ success: false, error: { code: 'NOT_LOGGED_IN', message: '未登录,请先运行 arm login' } });
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
145
222
|
error('未登录,请先运行 arm login');
|
|
146
223
|
process.exit(1);
|
|
147
224
|
}
|
|
@@ -149,6 +226,10 @@ export async function mySkills(): Promise<void> {
|
|
|
149
226
|
const client = new ApiClient(config.serverUrl, config.token);
|
|
150
227
|
try {
|
|
151
228
|
const skills = await client.getMySkills();
|
|
229
|
+
if (shouldOutputJson()) {
|
|
230
|
+
outputJson({ success: true, data: skills });
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
152
233
|
if (skills.length === 0) {
|
|
153
234
|
info('您还没有发布任何 Skill');
|
|
154
235
|
return;
|
|
@@ -159,6 +240,10 @@ export async function mySkills(): Promise<void> {
|
|
|
159
240
|
console.log('');
|
|
160
241
|
}
|
|
161
242
|
} catch (err) {
|
|
243
|
+
if (shouldOutputJson()) {
|
|
244
|
+
outputJson({ success: false, error: { code: 'LIST_FAILED', message: err instanceof Error ? err.message : '未知错误' } });
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
162
247
|
error(`获取列表失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
163
248
|
process.exit(1);
|
|
164
249
|
}
|
|
@@ -167,6 +252,10 @@ export async function mySkills(): Promise<void> {
|
|
|
167
252
|
export async function deleteSkill(name: string): Promise<void> {
|
|
168
253
|
const config = loadConfig();
|
|
169
254
|
if (!config?.token) {
|
|
255
|
+
if (shouldOutputJson()) {
|
|
256
|
+
outputJson({ success: false, error: { code: 'NOT_LOGGED_IN', message: '未登录,请先运行 arm login' } });
|
|
257
|
+
process.exit(1);
|
|
258
|
+
}
|
|
170
259
|
error('未登录,请先运行 arm login');
|
|
171
260
|
process.exit(1);
|
|
172
261
|
}
|
|
@@ -174,8 +263,16 @@ export async function deleteSkill(name: string): Promise<void> {
|
|
|
174
263
|
const client = new ApiClient(config.serverUrl, config.token);
|
|
175
264
|
try {
|
|
176
265
|
await client.deleteSkill(name);
|
|
266
|
+
if (shouldOutputJson()) {
|
|
267
|
+
outputJson({ success: true, data: { name } });
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
177
270
|
success(`已删除 ${name}`);
|
|
178
271
|
} catch (err) {
|
|
272
|
+
if (shouldOutputJson()) {
|
|
273
|
+
outputJson({ success: false, error: { code: 'DELETE_FAILED', message: err instanceof Error ? err.message : '未知错误' } });
|
|
274
|
+
process.exit(1);
|
|
275
|
+
}
|
|
179
276
|
error(`删除失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
180
277
|
process.exit(1);
|
|
181
278
|
}
|
|
@@ -185,6 +282,22 @@ export async function validateSkill(filePath: string): Promise<void> {
|
|
|
185
282
|
const isDir = existsSync(filePath) && statSync(filePath).isDirectory();
|
|
186
283
|
const result = isDir ? validateSkillDir(filePath) : validateZip(filePath);
|
|
187
284
|
|
|
285
|
+
if (shouldOutputJson()) {
|
|
286
|
+
outputJson({
|
|
287
|
+
success: result.valid,
|
|
288
|
+
data: {
|
|
289
|
+
valid: result.valid,
|
|
290
|
+
errors: result.errors,
|
|
291
|
+
warnings: result.warnings,
|
|
292
|
+
metadata: result.metadata,
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
if (!result.valid) {
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
188
301
|
if (result.valid) {
|
|
189
302
|
success('验证通过!');
|
|
190
303
|
} else {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { loadConfig, saveConfig } from './storage';
|
|
2
|
+
|
|
3
|
+
export type OutputMode = 'json' | 'text';
|
|
4
|
+
|
|
5
|
+
export interface JsonResult<T = unknown> {
|
|
6
|
+
success: boolean;
|
|
7
|
+
data?: T;
|
|
8
|
+
error?: {
|
|
9
|
+
code: string;
|
|
10
|
+
message: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function outputJson<T>(result: JsonResult<T>): void {
|
|
15
|
+
console.log(JSON.stringify(result, null, 2));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function shouldOutputJson(): boolean {
|
|
19
|
+
if (process.argv.includes('--json') || process.argv.includes('-j')) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
const config = loadConfig();
|
|
23
|
+
return config.outputMode !== 'text';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function getOutputMode(): OutputMode {
|
|
27
|
+
const config = loadConfig();
|
|
28
|
+
return config.outputMode || 'json';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function setOutputMode(mode: OutputMode): void {
|
|
32
|
+
const config = loadConfig() || {};
|
|
33
|
+
config.outputMode = mode;
|
|
34
|
+
saveConfig(config);
|
|
35
|
+
}
|
package/src/lib/storage.ts
CHANGED
package/src/main.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { listSkills, searchSkills, infoSkill, downloadSkill, uploadSkill, mySkil
|
|
|
3
3
|
import { listAgents, searchAgents, infoAgent, downloadAgent, createAgent, updateAgent, deleteAgent, bindSkill, unbindSkill, bindKnowledge, unbindKnowledge } from './cmd/agent';
|
|
4
4
|
import { listKnowledge, searchKnowledge, infoKnowledge, downloadKnowledge, uploadKnowledge, myKnowledge, deleteKnowledge } from './cmd/knowledge';
|
|
5
5
|
import { showServer, setServer } from './cmd/server';
|
|
6
|
+
import { getOutputMode, setOutputMode } from './lib/output';
|
|
6
7
|
|
|
7
8
|
const args = process.argv.slice(2);
|
|
8
9
|
const command = args[0];
|
|
@@ -160,6 +161,16 @@ async function main() {
|
|
|
160
161
|
await getCurrentUser();
|
|
161
162
|
break;
|
|
162
163
|
|
|
164
|
+
case 'output':
|
|
165
|
+
if (subCommand === 'json' || subCommand === 'text') {
|
|
166
|
+
setOutputMode(subCommand);
|
|
167
|
+
console.log(`输出模式已设置为: ${subCommand}`);
|
|
168
|
+
} else {
|
|
169
|
+
const mode = getOutputMode();
|
|
170
|
+
console.log(`当前输出模式: ${mode}`);
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
|
|
163
174
|
case 'agent':
|
|
164
175
|
switch (subCommand) {
|
|
165
176
|
case 'ls':
|
|
@@ -359,6 +370,7 @@ Agent Resource Management (arm)
|
|
|
359
370
|
用法:
|
|
360
371
|
arm login <server-url> <api-key> 登录
|
|
361
372
|
arm logout 登出
|
|
373
|
+
arm output [json|text] 设置/查看输出模式 (默认json)
|
|
362
374
|
arm skill ls 列出所有 Skill
|
|
363
375
|
arm skill search <keyword> 搜索 Skill
|
|
364
376
|
arm skill info <name> 查看 Skill 详情
|
package/test-regression.sh
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
|
|
3
|
-
CLI_DIR="/Users/lk/Documents/Dev/aims/xuanwu/xuanwu-agents/agent-sdk/agent-
|
|
3
|
+
CLI_DIR="/Users/lk/Documents/Dev/aims/xuanwu/xuanwu-agents/agent-sdk/agent-resource-management/cli"
|
|
4
4
|
DATA_DIR="$CLI_DIR/data/skills"
|
|
5
5
|
SERVER_URL="http://localhost:3000"
|
|
6
6
|
API_KEY="4567c9e607564e91b3898c46d89cb68dc4e40ec4a52b456699b695cf800fd446"
|