agent-resource-management 2.1.8 → 2.1.9
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 +128 -29
- package/package.json +1 -1
- package/src/cmd/agent.ts +4 -4
- package/src/cmd/auth.ts +25 -13
- package/src/cmd/token.ts +57 -0
- package/src/lib/client.ts +7 -3
- package/src/lib/storage.ts +3 -2
- package/src/main.ts +31 -9
package/dist/main.js
CHANGED
|
@@ -16,6 +16,9 @@ class ApiClient {
|
|
|
16
16
|
clearToken() {
|
|
17
17
|
this.token = null;
|
|
18
18
|
}
|
|
19
|
+
getToken() {
|
|
20
|
+
return this.token;
|
|
21
|
+
}
|
|
19
22
|
async request(path, options = {}) {
|
|
20
23
|
const headers = {
|
|
21
24
|
"Content-Type": "application/json",
|
|
@@ -170,7 +173,7 @@ class ApiClient {
|
|
|
170
173
|
async listKnowledge(keyword, page = 1, pageSize = 20) {
|
|
171
174
|
let path = `/knowledges?page=${page}&pageSize=${pageSize}`;
|
|
172
175
|
if (keyword) {
|
|
173
|
-
path += `&
|
|
176
|
+
path += `&search=${encodeURIComponent(keyword)}`;
|
|
174
177
|
}
|
|
175
178
|
const res = await this.request(path);
|
|
176
179
|
if (!res.ok) {
|
|
@@ -288,10 +291,10 @@ class ApiClient {
|
|
|
288
291
|
throw new Error(res.msg);
|
|
289
292
|
}
|
|
290
293
|
}
|
|
291
|
-
async bindKnowledgeToAgent(agentId, knowledgeId, version, retrievalConfig) {
|
|
294
|
+
async bindKnowledgeToAgent(agentId, knowledgeId, version, retrievalConfig, kind) {
|
|
292
295
|
const res = await this.request(`/agents/${agentId}/knowledges`, {
|
|
293
296
|
method: "POST",
|
|
294
|
-
body: JSON.stringify({ knowledgeId, version, retrievalConfig })
|
|
297
|
+
body: JSON.stringify({ knowledgeId, version, retrievalConfig, kind })
|
|
295
298
|
});
|
|
296
299
|
if (!res.ok) {
|
|
297
300
|
throw new Error(res.msg);
|
|
@@ -323,7 +326,7 @@ class ApiClient {
|
|
|
323
326
|
}
|
|
324
327
|
|
|
325
328
|
// src/lib/storage.ts
|
|
326
|
-
import { writeFileSync, readFileSync, existsSync, mkdirSync } from "fs";
|
|
329
|
+
import { writeFileSync, readFileSync, existsSync, mkdirSync, chmodSync } from "fs";
|
|
327
330
|
import { join } from "path";
|
|
328
331
|
var CONFIG_DIR = join(process.env.HOME || "/root", ".arm");
|
|
329
332
|
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
@@ -334,7 +337,8 @@ function ensureConfigDir() {
|
|
|
334
337
|
}
|
|
335
338
|
function saveConfig(config) {
|
|
336
339
|
ensureConfigDir();
|
|
337
|
-
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
340
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 384 });
|
|
341
|
+
chmodSync(CONFIG_FILE, 384);
|
|
338
342
|
}
|
|
339
343
|
function loadConfig() {
|
|
340
344
|
try {
|
|
@@ -527,18 +531,32 @@ async function register(name, email, password) {
|
|
|
527
531
|
process.exit(1);
|
|
528
532
|
}
|
|
529
533
|
}
|
|
530
|
-
async function login(
|
|
534
|
+
async function login() {
|
|
535
|
+
console.log("请在浏览器打开:" + (loadConfig()?.serverUrl || "http://localhost:3000") + "/settings/tokens");
|
|
536
|
+
console.log("生成一个 PAT(建议命名包含机器名),复制粘贴到此处:");
|
|
537
|
+
const { readline } = await import("readline");
|
|
538
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
539
|
+
const token = await new Promise((resolve) => rl.question("PAT> ", (a) => {
|
|
540
|
+
rl.close();
|
|
541
|
+
resolve(a);
|
|
542
|
+
}));
|
|
543
|
+
const trimmed = token.trim();
|
|
544
|
+
if (!trimmed.startsWith("arm_pat_")) {
|
|
545
|
+
error("格式错误:应以 arm_pat_ 开头");
|
|
546
|
+
process.exit(1);
|
|
547
|
+
}
|
|
548
|
+
const config = loadConfig() || { serverUrl: "http://localhost:3000" };
|
|
549
|
+
config.serverUrl = config.serverUrl || "http://localhost:3000";
|
|
550
|
+
config.token = trimmed;
|
|
551
|
+
saveConfig(config);
|
|
552
|
+
const client = new ApiClient(config.serverUrl, trimmed);
|
|
531
553
|
try {
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
saveConfig(
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
});
|
|
539
|
-
success(`登录成功! 欢迎, ${loginRes.user.name}`);
|
|
540
|
-
} catch (err) {
|
|
541
|
-
error(`登录失败: ${err instanceof Error ? err.message : "未知错误"}`);
|
|
554
|
+
const me = await client.me();
|
|
555
|
+
config.user = { id: me.id, name: me.name, email: me.email };
|
|
556
|
+
saveConfig(config);
|
|
557
|
+
success(`登录成功! 欢迎, ${me.name}`);
|
|
558
|
+
} catch (e) {
|
|
559
|
+
error(`Token 无效:${e instanceof Error ? e.message : e}`);
|
|
542
560
|
process.exit(1);
|
|
543
561
|
}
|
|
544
562
|
}
|
|
@@ -1352,7 +1370,7 @@ async function unbindSkill(id, skillId, version) {
|
|
|
1352
1370
|
process.exit(1);
|
|
1353
1371
|
}
|
|
1354
1372
|
}
|
|
1355
|
-
async function bindKnowledge(id, knowledgeId, version = "1.0.0", retrievalConfig) {
|
|
1373
|
+
async function bindKnowledge(id, knowledgeId, version = "1.0.0", retrievalConfig, kind) {
|
|
1356
1374
|
const configStore = loadConfig();
|
|
1357
1375
|
if (!configStore?.token) {
|
|
1358
1376
|
if (shouldOutputJson()) {
|
|
@@ -1365,12 +1383,12 @@ async function bindKnowledge(id, knowledgeId, version = "1.0.0", retrievalConfig
|
|
|
1365
1383
|
const client = new ApiClient(configStore.serverUrl, configStore.token);
|
|
1366
1384
|
try {
|
|
1367
1385
|
const parsedConfig = retrievalConfig ? JSON.parse(retrievalConfig) : undefined;
|
|
1368
|
-
await client.bindKnowledgeToAgent(id, knowledgeId, version, parsedConfig);
|
|
1386
|
+
await client.bindKnowledgeToAgent(id, knowledgeId, version, parsedConfig, kind);
|
|
1369
1387
|
if (shouldOutputJson()) {
|
|
1370
|
-
outputJson({ success: true, data: { agentId: id, knowledgeId, version, retrievalConfig: parsedConfig } });
|
|
1388
|
+
outputJson({ success: true, data: { agentId: id, knowledgeId, version, kind: kind ?? "experience", retrievalConfig: parsedConfig } });
|
|
1371
1389
|
return;
|
|
1372
1390
|
}
|
|
1373
|
-
success(`Knowledge "${knowledgeId}@${version}"
|
|
1391
|
+
success(`Knowledge "${knowledgeId}@${version}"(${kind ?? "experience"})已绑定到 Agent "${id}"`);
|
|
1374
1392
|
} catch (err) {
|
|
1375
1393
|
if (shouldOutputJson()) {
|
|
1376
1394
|
outputJson({ success: false, error: { code: "BIND_FAILED", message: err instanceof Error ? err.message : "未知错误" } });
|
|
@@ -2227,6 +2245,67 @@ function setServer(url) {
|
|
|
2227
2245
|
info(`已设置服务端: ${url}`);
|
|
2228
2246
|
}
|
|
2229
2247
|
|
|
2248
|
+
// src/cmd/token.ts
|
|
2249
|
+
async function ensureClient() {
|
|
2250
|
+
const config = loadConfig();
|
|
2251
|
+
if (!config?.token) {
|
|
2252
|
+
error("未登录,请先运行 arm login");
|
|
2253
|
+
process.exit(1);
|
|
2254
|
+
}
|
|
2255
|
+
return { client: new ApiClient(config.serverUrl, config.token), serverUrl: config.serverUrl };
|
|
2256
|
+
}
|
|
2257
|
+
async function listTokens() {
|
|
2258
|
+
const { client, serverUrl } = await ensureClient();
|
|
2259
|
+
const headers = { Authorization: `Bearer ${client.getToken() ?? ""}` };
|
|
2260
|
+
const res = await fetch(`${serverUrl}/api/v1/tokens`, { headers });
|
|
2261
|
+
const j = await res.json();
|
|
2262
|
+
if (!j.ok) {
|
|
2263
|
+
error(j.msg);
|
|
2264
|
+
process.exit(1);
|
|
2265
|
+
}
|
|
2266
|
+
console.table(j.data.tokens.map((t) => ({
|
|
2267
|
+
id: t.id,
|
|
2268
|
+
name: t.name,
|
|
2269
|
+
created: t.createdAt,
|
|
2270
|
+
lastUsed: t.lastUsedAt ?? "(never)",
|
|
2271
|
+
expires: t.expiresAt ?? "(never)"
|
|
2272
|
+
})));
|
|
2273
|
+
success("完成");
|
|
2274
|
+
}
|
|
2275
|
+
async function createToken(name, expiresAt) {
|
|
2276
|
+
const { client, serverUrl } = await ensureClient();
|
|
2277
|
+
const headers = {
|
|
2278
|
+
"Content-Type": "application/json",
|
|
2279
|
+
Authorization: `Bearer ${client.getToken() ?? ""}`
|
|
2280
|
+
};
|
|
2281
|
+
const res = await fetch(`${serverUrl}/api/v1/tokens`, {
|
|
2282
|
+
method: "POST",
|
|
2283
|
+
headers,
|
|
2284
|
+
body: JSON.stringify({ name, expiresAt })
|
|
2285
|
+
});
|
|
2286
|
+
const j = await res.json();
|
|
2287
|
+
if (!j.ok) {
|
|
2288
|
+
error(j.msg);
|
|
2289
|
+
process.exit(1);
|
|
2290
|
+
}
|
|
2291
|
+
success("Token 已创建(仅此一次展示,请妥善保存):");
|
|
2292
|
+
console.log(j.data.token);
|
|
2293
|
+
}
|
|
2294
|
+
async function revokeToken(id) {
|
|
2295
|
+
const { client, serverUrl } = await ensureClient();
|
|
2296
|
+
const headers = { Authorization: `Bearer ${client.getToken() ?? ""}` };
|
|
2297
|
+
const res = await fetch(`${serverUrl}/api/v1/tokens/${id}`, {
|
|
2298
|
+
method: "DELETE",
|
|
2299
|
+
headers
|
|
2300
|
+
});
|
|
2301
|
+
const j = await res.json();
|
|
2302
|
+
if (!j.ok) {
|
|
2303
|
+
error(j.msg);
|
|
2304
|
+
process.exit(1);
|
|
2305
|
+
}
|
|
2306
|
+
success(`已撤销 ${id}`);
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2230
2309
|
// src/main.ts
|
|
2231
2310
|
import { readFileSync as readFileSync4 } from "fs";
|
|
2232
2311
|
import { join as join6 } from "path";
|
|
@@ -2257,11 +2336,7 @@ async function main() {
|
|
|
2257
2336
|
}
|
|
2258
2337
|
break;
|
|
2259
2338
|
case "login":
|
|
2260
|
-
|
|
2261
|
-
console.error("用法: arm login <server-url> <api-key>");
|
|
2262
|
-
process.exit(1);
|
|
2263
|
-
}
|
|
2264
|
-
await login(args[1], args[2]);
|
|
2339
|
+
await login();
|
|
2265
2340
|
break;
|
|
2266
2341
|
case "logout":
|
|
2267
2342
|
await logout();
|
|
@@ -2326,7 +2401,7 @@ async function main() {
|
|
|
2326
2401
|
default:
|
|
2327
2402
|
console.log(`
|
|
2328
2403
|
可用命令:
|
|
2329
|
-
arm login
|
|
2404
|
+
arm login 登录(粘贴 PAT)
|
|
2330
2405
|
arm logout 登出
|
|
2331
2406
|
arm skill ls 列出所有 Skill
|
|
2332
2407
|
arm skill search <keyword> 搜索 Skill
|
|
@@ -2400,6 +2475,26 @@ async function main() {
|
|
|
2400
2475
|
case "me":
|
|
2401
2476
|
await getCurrentUser();
|
|
2402
2477
|
break;
|
|
2478
|
+
case "token":
|
|
2479
|
+
if (subCommand === "list") {
|
|
2480
|
+
await listTokens();
|
|
2481
|
+
} else if (subCommand === "create") {
|
|
2482
|
+
if (!args[2]) {
|
|
2483
|
+
console.error("用法: arm token create <name> [expiresAt]");
|
|
2484
|
+
process.exit(1);
|
|
2485
|
+
}
|
|
2486
|
+
await createToken(args[2], args[3]);
|
|
2487
|
+
} else if (subCommand === "revoke") {
|
|
2488
|
+
if (!args[2]) {
|
|
2489
|
+
console.error("用法: arm token revoke <id>");
|
|
2490
|
+
process.exit(1);
|
|
2491
|
+
}
|
|
2492
|
+
await revokeToken(args[2]);
|
|
2493
|
+
} else {
|
|
2494
|
+
console.error("用法: arm token list|create <name> [expiresAt]|revoke <id>");
|
|
2495
|
+
process.exit(1);
|
|
2496
|
+
}
|
|
2497
|
+
break;
|
|
2403
2498
|
case "output":
|
|
2404
2499
|
if (subCommand === "json" || subCommand === "text") {
|
|
2405
2500
|
setOutputMode(subCommand);
|
|
@@ -2535,6 +2630,7 @@ async function main() {
|
|
|
2535
2630
|
let knowledgeId;
|
|
2536
2631
|
let skillConfig;
|
|
2537
2632
|
let knowledgeConfig;
|
|
2633
|
+
let knowledgeKind;
|
|
2538
2634
|
for (let i = 3;i < args.length; i++) {
|
|
2539
2635
|
const arg = args[i];
|
|
2540
2636
|
if (arg.startsWith("--skill=")) {
|
|
@@ -2545,14 +2641,17 @@ async function main() {
|
|
|
2545
2641
|
skillConfig = arg.split("=").slice(1).join("=");
|
|
2546
2642
|
} else if (arg.startsWith("--knowledge-config=")) {
|
|
2547
2643
|
knowledgeConfig = arg.split("=").slice(1).join("=");
|
|
2644
|
+
} else if (arg.startsWith("--kind=")) {
|
|
2645
|
+
knowledgeKind = arg.split("=").slice(1).join("=");
|
|
2548
2646
|
}
|
|
2549
2647
|
}
|
|
2550
2648
|
if (skillId) {
|
|
2551
2649
|
await bindSkill(id, skillId, undefined, skillConfig);
|
|
2552
2650
|
} else if (knowledgeId) {
|
|
2553
|
-
|
|
2651
|
+
const kind = knowledgeKind === "essential" || knowledgeKind === "experience" ? knowledgeKind : undefined;
|
|
2652
|
+
await bindKnowledge(id, knowledgeId, undefined, knowledgeConfig, kind);
|
|
2554
2653
|
} else {
|
|
2555
|
-
console.error("用法: arm agent bind <id> --skill=<skillId> 或 --knowledge=<knowledgeId>");
|
|
2654
|
+
console.error("用法: arm agent bind <id> --skill=<skillId> 或 --knowledge=<knowledgeId> [--kind=essential|experience]");
|
|
2556
2655
|
process.exit(1);
|
|
2557
2656
|
}
|
|
2558
2657
|
}
|
|
@@ -2646,7 +2745,7 @@ Agent Resource Management (arm)
|
|
|
2646
2745
|
|
|
2647
2746
|
用法:
|
|
2648
2747
|
arm register [--name=<name>] [--email=<email>] [--password=<password>] 注册 (交互式或参数)
|
|
2649
|
-
arm login
|
|
2748
|
+
arm login 登录(粘贴 PAT)
|
|
2650
2749
|
arm logout 登出
|
|
2651
2750
|
arm output [json|text] 设置/查看输出模式 (默认json)
|
|
2652
2751
|
arm skill ls 列出所有 Skill
|
package/package.json
CHANGED
package/src/cmd/agent.ts
CHANGED
|
@@ -217,7 +217,7 @@ export async function unbindSkill(id: string, skillId: string, version?: string)
|
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
export async function bindKnowledge(id: string, knowledgeId: string, version: string = '1.0.0', retrievalConfig?: string): Promise<void> {
|
|
220
|
+
export async function bindKnowledge(id: string, knowledgeId: string, version: string = '1.0.0', retrievalConfig?: string, kind?: 'essential' | 'experience'): Promise<void> {
|
|
221
221
|
const configStore = loadConfig();
|
|
222
222
|
if (!configStore?.token) {
|
|
223
223
|
if (shouldOutputJson()) {
|
|
@@ -231,13 +231,13 @@ export async function bindKnowledge(id: string, knowledgeId: string, version: st
|
|
|
231
231
|
const client = new ApiClient(configStore.serverUrl, configStore.token);
|
|
232
232
|
try {
|
|
233
233
|
const parsedConfig = retrievalConfig ? JSON.parse(retrievalConfig) : undefined;
|
|
234
|
-
await client.bindKnowledgeToAgent(id, knowledgeId, version, parsedConfig);
|
|
234
|
+
await client.bindKnowledgeToAgent(id, knowledgeId, version, parsedConfig, kind);
|
|
235
235
|
|
|
236
236
|
if (shouldOutputJson()) {
|
|
237
|
-
outputJson({ success: true, data: { agentId: id, knowledgeId, version, retrievalConfig: parsedConfig } });
|
|
237
|
+
outputJson({ success: true, data: { agentId: id, knowledgeId, version, kind: kind ?? 'experience', retrievalConfig: parsedConfig } });
|
|
238
238
|
return;
|
|
239
239
|
}
|
|
240
|
-
success(`Knowledge "${knowledgeId}@${version}"
|
|
240
|
+
success(`Knowledge "${knowledgeId}@${version}"(${kind ?? 'experience'})已绑定到 Agent "${id}"`);
|
|
241
241
|
} catch (err) {
|
|
242
242
|
if (shouldOutputJson()) {
|
|
243
243
|
outputJson({ success: false, error: { code: 'BIND_FAILED', message: err instanceof Error ? err.message : '未知错误' } });
|
package/src/cmd/auth.ts
CHANGED
|
@@ -52,20 +52,32 @@ export async function register(name?: string, email?: string, password?: string)
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
export async function login(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
export async function login(): Promise<void> {
|
|
56
|
+
console.log('请在浏览器打开:' + (loadConfig()?.serverUrl || 'http://localhost:3000') + '/settings/tokens');
|
|
57
|
+
console.log('生成一个 PAT(建议命名包含机器名),复制粘贴到此处:');
|
|
58
|
+
const { readline } = await import('readline');
|
|
59
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
60
|
+
const token = await new Promise<string>((resolve) => rl.question('PAT> ', (a) => { rl.close(); resolve(a); }));
|
|
61
|
+
const trimmed = token.trim();
|
|
62
|
+
if (!trimmed.startsWith('arm_pat_')) {
|
|
63
|
+
error('格式错误:应以 arm_pat_ 开头');
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
59
66
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
});
|
|
67
|
+
const config = loadConfig() || { serverUrl: 'http://localhost:3000' };
|
|
68
|
+
config.serverUrl = config.serverUrl || 'http://localhost:3000';
|
|
69
|
+
config.token = trimmed;
|
|
70
|
+
saveConfig(config);
|
|
65
71
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
// 顺便用这个 token 拉一次用户信息
|
|
73
|
+
const client = new ApiClient(config.serverUrl, trimmed);
|
|
74
|
+
try {
|
|
75
|
+
const me = await client.me();
|
|
76
|
+
config.user = { id: me.id, name: me.name, email: me.email };
|
|
77
|
+
saveConfig(config);
|
|
78
|
+
success(`登录成功! 欢迎, ${me.name}`);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
error(`Token 无效:${e instanceof Error ? e.message : e}`);
|
|
69
81
|
process.exit(1);
|
|
70
82
|
}
|
|
71
83
|
}
|
|
@@ -97,4 +109,4 @@ export async function getCurrentUser(): Promise<void> {
|
|
|
97
109
|
error(`获取用户信息失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
|
98
110
|
process.exit(1);
|
|
99
111
|
}
|
|
100
|
-
}
|
|
112
|
+
}
|
package/src/cmd/token.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { ApiClient } from '../lib/client';
|
|
2
|
+
import { loadConfig } from '../lib/storage';
|
|
3
|
+
import { success, error } from '../lib/formatter';
|
|
4
|
+
|
|
5
|
+
async function ensureClient(): Promise<{ client: ApiClient; serverUrl: string }> {
|
|
6
|
+
const config = loadConfig();
|
|
7
|
+
if (!config?.token) {
|
|
8
|
+
error('未登录,请先运行 arm login');
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
return { client: new ApiClient(config.serverUrl, config.token), serverUrl: config.serverUrl };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function listTokens(): Promise<void> {
|
|
15
|
+
const { client, serverUrl } = await ensureClient();
|
|
16
|
+
const headers = { Authorization: `Bearer ${client.getToken() ?? ''}` };
|
|
17
|
+
const res = await fetch(`${serverUrl}/api/v1/tokens`, { headers });
|
|
18
|
+
const j = await res.json();
|
|
19
|
+
if (!j.ok) { error(j.msg); process.exit(1); }
|
|
20
|
+
console.table(j.data.tokens.map((t: any) => ({
|
|
21
|
+
id: t.id,
|
|
22
|
+
name: t.name,
|
|
23
|
+
created: t.createdAt,
|
|
24
|
+
lastUsed: t.lastUsedAt ?? '(never)',
|
|
25
|
+
expires: t.expiresAt ?? '(never)',
|
|
26
|
+
})));
|
|
27
|
+
success('完成');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function createToken(name: string, expiresAt?: string): Promise<void> {
|
|
31
|
+
const { client, serverUrl } = await ensureClient();
|
|
32
|
+
const headers = {
|
|
33
|
+
'Content-Type': 'application/json',
|
|
34
|
+
Authorization: `Bearer ${client.getToken() ?? ''}`,
|
|
35
|
+
};
|
|
36
|
+
const res = await fetch(`${serverUrl}/api/v1/tokens`, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers,
|
|
39
|
+
body: JSON.stringify({ name, expiresAt }),
|
|
40
|
+
});
|
|
41
|
+
const j = await res.json();
|
|
42
|
+
if (!j.ok) { error(j.msg); process.exit(1); }
|
|
43
|
+
success('Token 已创建(仅此一次展示,请妥善保存):');
|
|
44
|
+
console.log(j.data.token);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function revokeToken(id: string): Promise<void> {
|
|
48
|
+
const { client, serverUrl } = await ensureClient();
|
|
49
|
+
const headers = { Authorization: `Bearer ${client.getToken() ?? ''}` };
|
|
50
|
+
const res = await fetch(`${serverUrl}/api/v1/tokens/${id}`, {
|
|
51
|
+
method: 'DELETE',
|
|
52
|
+
headers,
|
|
53
|
+
});
|
|
54
|
+
const j = await res.json();
|
|
55
|
+
if (!j.ok) { error(j.msg); process.exit(1); }
|
|
56
|
+
success(`已撤销 ${id}`);
|
|
57
|
+
}
|
package/src/lib/client.ts
CHANGED
|
@@ -17,6 +17,10 @@ export class ApiClient {
|
|
|
17
17
|
this.token = null;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
getToken(): string | null {
|
|
21
|
+
return this.token;
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
private async request<T>(
|
|
21
25
|
path: string,
|
|
22
26
|
options: RequestInit = {}
|
|
@@ -200,7 +204,7 @@ export class ApiClient {
|
|
|
200
204
|
async listKnowledge(keyword?: string, page = 1, pageSize = 20): Promise<{ knowledges: any[]; total: number }> {
|
|
201
205
|
let path = `/knowledges?page=${page}&pageSize=${pageSize}`;
|
|
202
206
|
if (keyword) {
|
|
203
|
-
path += `&
|
|
207
|
+
path += `&search=${encodeURIComponent(keyword)}`;
|
|
204
208
|
}
|
|
205
209
|
const res = await this.request<{ knowledges: any[]; total: number }>(path);
|
|
206
210
|
if (!res.ok) {
|
|
@@ -349,10 +353,10 @@ export class ApiClient {
|
|
|
349
353
|
}
|
|
350
354
|
}
|
|
351
355
|
|
|
352
|
-
async bindKnowledgeToAgent(agentId: string, knowledgeId: string, version: string, retrievalConfig?: { topK?: number; similarityThreshold?: number }): Promise<void> {
|
|
356
|
+
async bindKnowledgeToAgent(agentId: string, knowledgeId: string, version: string, retrievalConfig?: { topK?: number; similarityThreshold?: number }, kind?: 'essential' | 'experience'): Promise<void> {
|
|
353
357
|
const res = await this.request<null>(`/agents/${agentId}/knowledges`, {
|
|
354
358
|
method: 'POST',
|
|
355
|
-
body: JSON.stringify({ knowledgeId, version, retrievalConfig }),
|
|
359
|
+
body: JSON.stringify({ knowledgeId, version, retrievalConfig, kind }),
|
|
356
360
|
});
|
|
357
361
|
if (!res.ok) {
|
|
358
362
|
throw new Error(res.msg);
|
package/src/lib/storage.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { writeFileSync, readFileSync, existsSync, mkdirSync } from 'fs';
|
|
1
|
+
import { writeFileSync, readFileSync, existsSync, mkdirSync, chmodSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
|
|
4
4
|
const CONFIG_DIR = join(process.env.HOME || '/root', '.arm');
|
|
@@ -23,7 +23,8 @@ function ensureConfigDir() {
|
|
|
23
23
|
|
|
24
24
|
export function saveConfig(config: Config): void {
|
|
25
25
|
ensureConfigDir();
|
|
26
|
-
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
26
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
27
|
+
chmodSync(CONFIG_FILE, 0o600);
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
export function loadConfig(): Config | null {
|
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, createAgentFromFolder, syncAgent } 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 { listTokens, createToken, revokeToken } from './cmd/token';
|
|
6
7
|
import { getOutputMode, setOutputMode } from './lib/output';
|
|
7
8
|
|
|
8
9
|
import { readFileSync } from 'fs';
|
|
@@ -38,11 +39,7 @@ async function main() {
|
|
|
38
39
|
break;
|
|
39
40
|
|
|
40
41
|
case 'login':
|
|
41
|
-
|
|
42
|
-
console.error('用法: arm login <server-url> <api-key>');
|
|
43
|
-
process.exit(1);
|
|
44
|
-
}
|
|
45
|
-
await login(args[1], args[2]);
|
|
42
|
+
await login();
|
|
46
43
|
break;
|
|
47
44
|
|
|
48
45
|
case 'logout':
|
|
@@ -110,7 +107,7 @@ async function main() {
|
|
|
110
107
|
default:
|
|
111
108
|
console.log(`
|
|
112
109
|
可用命令:
|
|
113
|
-
arm login
|
|
110
|
+
arm login 登录(粘贴 PAT)
|
|
114
111
|
arm logout 登出
|
|
115
112
|
arm skill ls 列出所有 Skill
|
|
116
113
|
arm skill search <keyword> 搜索 Skill
|
|
@@ -187,6 +184,27 @@ async function main() {
|
|
|
187
184
|
await getCurrentUser();
|
|
188
185
|
break;
|
|
189
186
|
|
|
187
|
+
case 'token':
|
|
188
|
+
if (subCommand === 'list') {
|
|
189
|
+
await listTokens();
|
|
190
|
+
} else if (subCommand === 'create') {
|
|
191
|
+
if (!args[2]) {
|
|
192
|
+
console.error('用法: arm token create <name> [expiresAt]');
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
await createToken(args[2], args[3]);
|
|
196
|
+
} else if (subCommand === 'revoke') {
|
|
197
|
+
if (!args[2]) {
|
|
198
|
+
console.error('用法: arm token revoke <id>');
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
await revokeToken(args[2]);
|
|
202
|
+
} else {
|
|
203
|
+
console.error('用法: arm token list|create <name> [expiresAt]|revoke <id>');
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
break;
|
|
207
|
+
|
|
190
208
|
case 'output':
|
|
191
209
|
if (subCommand === 'json' || subCommand === 'text') {
|
|
192
210
|
setOutputMode(subCommand);
|
|
@@ -328,6 +346,7 @@ async function main() {
|
|
|
328
346
|
let knowledgeId: string | undefined;
|
|
329
347
|
let skillConfig: string | undefined;
|
|
330
348
|
let knowledgeConfig: string | undefined;
|
|
349
|
+
let knowledgeKind: string | undefined;
|
|
331
350
|
|
|
332
351
|
for (let i = 3; i < args.length; i++) {
|
|
333
352
|
const arg = args[i];
|
|
@@ -339,15 +358,18 @@ async function main() {
|
|
|
339
358
|
skillConfig = arg.split('=').slice(1).join('=');
|
|
340
359
|
} else if (arg.startsWith('--knowledge-config=')) {
|
|
341
360
|
knowledgeConfig = arg.split('=').slice(1).join('=');
|
|
361
|
+
} else if (arg.startsWith('--kind=')) {
|
|
362
|
+
knowledgeKind = arg.split('=').slice(1).join('=');
|
|
342
363
|
}
|
|
343
364
|
}
|
|
344
365
|
|
|
345
366
|
if (skillId) {
|
|
346
367
|
await bindSkill(id, skillId, undefined, skillConfig);
|
|
347
368
|
} else if (knowledgeId) {
|
|
348
|
-
|
|
369
|
+
const kind = (knowledgeKind === 'essential' || knowledgeKind === 'experience') ? knowledgeKind : undefined;
|
|
370
|
+
await bindKnowledge(id, knowledgeId, undefined, knowledgeConfig, kind);
|
|
349
371
|
} else {
|
|
350
|
-
console.error('用法: arm agent bind <id> --skill=<skillId> 或 --knowledge=<knowledgeId>');
|
|
372
|
+
console.error('用法: arm agent bind <id> --skill=<skillId> 或 --knowledge=<knowledgeId> [--kind=essential|experience]');
|
|
351
373
|
process.exit(1);
|
|
352
374
|
}
|
|
353
375
|
}
|
|
@@ -444,7 +466,7 @@ Agent Resource Management (arm)
|
|
|
444
466
|
|
|
445
467
|
用法:
|
|
446
468
|
arm register [--name=<name>] [--email=<email>] [--password=<password>] 注册 (交互式或参数)
|
|
447
|
-
arm login
|
|
469
|
+
arm login 登录(粘贴 PAT)
|
|
448
470
|
arm logout 登出
|
|
449
471
|
arm output [json|text] 设置/查看输出模式 (默认json)
|
|
450
472
|
arm skill ls 列出所有 Skill
|