agent-resource-management 2.1.8 → 2.1.10
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 +132 -32
- package/package.json +1 -1
- package/src/cmd/agent.ts +4 -4
- package/src/cmd/auth.ts +28 -16
- package/src/cmd/token.ts +57 -0
- package/src/lib/client.ts +7 -3
- package/src/lib/storage.ts +6 -3
- 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,10 +326,11 @@ 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");
|
|
333
|
+
var DEFAULT_SERVER_URL = "http://arm.agent-platform.dev.aimstek.cn";
|
|
330
334
|
function ensureConfigDir() {
|
|
331
335
|
if (!existsSync(CONFIG_DIR)) {
|
|
332
336
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
@@ -334,7 +338,8 @@ function ensureConfigDir() {
|
|
|
334
338
|
}
|
|
335
339
|
function saveConfig(config) {
|
|
336
340
|
ensureConfigDir();
|
|
337
|
-
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
341
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 384 });
|
|
342
|
+
chmodSync(CONFIG_FILE, 384);
|
|
338
343
|
}
|
|
339
344
|
function loadConfig() {
|
|
340
345
|
try {
|
|
@@ -350,7 +355,7 @@ function loadConfig() {
|
|
|
350
355
|
}
|
|
351
356
|
function getServerUrl() {
|
|
352
357
|
const config = loadConfig();
|
|
353
|
-
return config?.serverUrl ||
|
|
358
|
+
return config?.serverUrl || DEFAULT_SERVER_URL;
|
|
354
359
|
}
|
|
355
360
|
function setServerUrl(url) {
|
|
356
361
|
const config = loadConfig() || {};
|
|
@@ -487,7 +492,7 @@ function formatKnowledgeDetail(knowledge) {
|
|
|
487
492
|
|
|
488
493
|
// src/cmd/auth.ts
|
|
489
494
|
async function register(name, email, password) {
|
|
490
|
-
const
|
|
495
|
+
const readline = await import("readline");
|
|
491
496
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
492
497
|
const ask = (question) => new Promise((resolve) => rl.question(question, resolve));
|
|
493
498
|
let finalEmail = email;
|
|
@@ -512,7 +517,7 @@ async function register(name, email, password) {
|
|
|
512
517
|
process.exit(1);
|
|
513
518
|
}
|
|
514
519
|
const config = loadConfig();
|
|
515
|
-
const serverUrl = config?.serverUrl ||
|
|
520
|
+
const serverUrl = config?.serverUrl || DEFAULT_SERVER_URL;
|
|
516
521
|
const client = new ApiClient(serverUrl);
|
|
517
522
|
try {
|
|
518
523
|
const result = await client.register(finalEmail, finalPassword, finalName);
|
|
@@ -527,18 +532,32 @@ async function register(name, email, password) {
|
|
|
527
532
|
process.exit(1);
|
|
528
533
|
}
|
|
529
534
|
}
|
|
530
|
-
async function login(
|
|
535
|
+
async function login() {
|
|
536
|
+
console.log("请在浏览器打开:" + (loadConfig()?.serverUrl || DEFAULT_SERVER_URL) + "/settings/tokens");
|
|
537
|
+
console.log("生成一个 PAT(建议命名包含机器名),复制粘贴到此处:");
|
|
538
|
+
const readline = await import("readline");
|
|
539
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
540
|
+
const token = await new Promise((resolve) => rl.question("PAT> ", (a) => {
|
|
541
|
+
rl.close();
|
|
542
|
+
resolve(a);
|
|
543
|
+
}));
|
|
544
|
+
const trimmed = token.trim();
|
|
545
|
+
if (!trimmed.startsWith("arm_pat_")) {
|
|
546
|
+
error("格式错误:应以 arm_pat_ 开头");
|
|
547
|
+
process.exit(1);
|
|
548
|
+
}
|
|
549
|
+
const config = loadConfig() || { serverUrl: DEFAULT_SERVER_URL };
|
|
550
|
+
config.serverUrl = config.serverUrl || DEFAULT_SERVER_URL;
|
|
551
|
+
config.token = trimmed;
|
|
552
|
+
saveConfig(config);
|
|
553
|
+
const client = new ApiClient(config.serverUrl, trimmed);
|
|
531
554
|
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 : "未知错误"}`);
|
|
555
|
+
const me = await client.me();
|
|
556
|
+
config.user = { id: me.id, name: me.name, email: me.email };
|
|
557
|
+
saveConfig(config);
|
|
558
|
+
success(`登录成功! 欢迎, ${me.name}`);
|
|
559
|
+
} catch (e) {
|
|
560
|
+
error(`Token 无效:${e instanceof Error ? e.message : e}`);
|
|
542
561
|
process.exit(1);
|
|
543
562
|
}
|
|
544
563
|
}
|
|
@@ -1352,7 +1371,7 @@ async function unbindSkill(id, skillId, version) {
|
|
|
1352
1371
|
process.exit(1);
|
|
1353
1372
|
}
|
|
1354
1373
|
}
|
|
1355
|
-
async function bindKnowledge(id, knowledgeId, version = "1.0.0", retrievalConfig) {
|
|
1374
|
+
async function bindKnowledge(id, knowledgeId, version = "1.0.0", retrievalConfig, kind) {
|
|
1356
1375
|
const configStore = loadConfig();
|
|
1357
1376
|
if (!configStore?.token) {
|
|
1358
1377
|
if (shouldOutputJson()) {
|
|
@@ -1365,12 +1384,12 @@ async function bindKnowledge(id, knowledgeId, version = "1.0.0", retrievalConfig
|
|
|
1365
1384
|
const client = new ApiClient(configStore.serverUrl, configStore.token);
|
|
1366
1385
|
try {
|
|
1367
1386
|
const parsedConfig = retrievalConfig ? JSON.parse(retrievalConfig) : undefined;
|
|
1368
|
-
await client.bindKnowledgeToAgent(id, knowledgeId, version, parsedConfig);
|
|
1387
|
+
await client.bindKnowledgeToAgent(id, knowledgeId, version, parsedConfig, kind);
|
|
1369
1388
|
if (shouldOutputJson()) {
|
|
1370
|
-
outputJson({ success: true, data: { agentId: id, knowledgeId, version, retrievalConfig: parsedConfig } });
|
|
1389
|
+
outputJson({ success: true, data: { agentId: id, knowledgeId, version, kind: kind ?? "experience", retrievalConfig: parsedConfig } });
|
|
1371
1390
|
return;
|
|
1372
1391
|
}
|
|
1373
|
-
success(`Knowledge "${knowledgeId}@${version}"
|
|
1392
|
+
success(`Knowledge "${knowledgeId}@${version}"(${kind ?? "experience"})已绑定到 Agent "${id}"`);
|
|
1374
1393
|
} catch (err) {
|
|
1375
1394
|
if (shouldOutputJson()) {
|
|
1376
1395
|
outputJson({ success: false, error: { code: "BIND_FAILED", message: err instanceof Error ? err.message : "未知错误" } });
|
|
@@ -2227,6 +2246,67 @@ function setServer(url) {
|
|
|
2227
2246
|
info(`已设置服务端: ${url}`);
|
|
2228
2247
|
}
|
|
2229
2248
|
|
|
2249
|
+
// src/cmd/token.ts
|
|
2250
|
+
async function ensureClient() {
|
|
2251
|
+
const config = loadConfig();
|
|
2252
|
+
if (!config?.token) {
|
|
2253
|
+
error("未登录,请先运行 arm login");
|
|
2254
|
+
process.exit(1);
|
|
2255
|
+
}
|
|
2256
|
+
return { client: new ApiClient(config.serverUrl, config.token), serverUrl: config.serverUrl };
|
|
2257
|
+
}
|
|
2258
|
+
async function listTokens() {
|
|
2259
|
+
const { client, serverUrl } = await ensureClient();
|
|
2260
|
+
const headers = { Authorization: `Bearer ${client.getToken() ?? ""}` };
|
|
2261
|
+
const res = await fetch(`${serverUrl}/api/v1/tokens`, { headers });
|
|
2262
|
+
const j = await res.json();
|
|
2263
|
+
if (!j.ok) {
|
|
2264
|
+
error(j.msg);
|
|
2265
|
+
process.exit(1);
|
|
2266
|
+
}
|
|
2267
|
+
console.table(j.data.tokens.map((t) => ({
|
|
2268
|
+
id: t.id,
|
|
2269
|
+
name: t.name,
|
|
2270
|
+
created: t.createdAt,
|
|
2271
|
+
lastUsed: t.lastUsedAt ?? "(never)",
|
|
2272
|
+
expires: t.expiresAt ?? "(never)"
|
|
2273
|
+
})));
|
|
2274
|
+
success("完成");
|
|
2275
|
+
}
|
|
2276
|
+
async function createToken(name, expiresAt) {
|
|
2277
|
+
const { client, serverUrl } = await ensureClient();
|
|
2278
|
+
const headers = {
|
|
2279
|
+
"Content-Type": "application/json",
|
|
2280
|
+
Authorization: `Bearer ${client.getToken() ?? ""}`
|
|
2281
|
+
};
|
|
2282
|
+
const res = await fetch(`${serverUrl}/api/v1/tokens`, {
|
|
2283
|
+
method: "POST",
|
|
2284
|
+
headers,
|
|
2285
|
+
body: JSON.stringify({ name, expiresAt })
|
|
2286
|
+
});
|
|
2287
|
+
const j = await res.json();
|
|
2288
|
+
if (!j.ok) {
|
|
2289
|
+
error(j.msg);
|
|
2290
|
+
process.exit(1);
|
|
2291
|
+
}
|
|
2292
|
+
success("Token 已创建(仅此一次展示,请妥善保存):");
|
|
2293
|
+
console.log(j.data.token);
|
|
2294
|
+
}
|
|
2295
|
+
async function revokeToken(id) {
|
|
2296
|
+
const { client, serverUrl } = await ensureClient();
|
|
2297
|
+
const headers = { Authorization: `Bearer ${client.getToken() ?? ""}` };
|
|
2298
|
+
const res = await fetch(`${serverUrl}/api/v1/tokens/${id}`, {
|
|
2299
|
+
method: "DELETE",
|
|
2300
|
+
headers
|
|
2301
|
+
});
|
|
2302
|
+
const j = await res.json();
|
|
2303
|
+
if (!j.ok) {
|
|
2304
|
+
error(j.msg);
|
|
2305
|
+
process.exit(1);
|
|
2306
|
+
}
|
|
2307
|
+
success(`已撤销 ${id}`);
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2230
2310
|
// src/main.ts
|
|
2231
2311
|
import { readFileSync as readFileSync4 } from "fs";
|
|
2232
2312
|
import { join as join6 } from "path";
|
|
@@ -2257,11 +2337,7 @@ async function main() {
|
|
|
2257
2337
|
}
|
|
2258
2338
|
break;
|
|
2259
2339
|
case "login":
|
|
2260
|
-
|
|
2261
|
-
console.error("用法: arm login <server-url> <api-key>");
|
|
2262
|
-
process.exit(1);
|
|
2263
|
-
}
|
|
2264
|
-
await login(args[1], args[2]);
|
|
2340
|
+
await login();
|
|
2265
2341
|
break;
|
|
2266
2342
|
case "logout":
|
|
2267
2343
|
await logout();
|
|
@@ -2326,7 +2402,7 @@ async function main() {
|
|
|
2326
2402
|
default:
|
|
2327
2403
|
console.log(`
|
|
2328
2404
|
可用命令:
|
|
2329
|
-
arm login
|
|
2405
|
+
arm login 登录(粘贴 PAT)
|
|
2330
2406
|
arm logout 登出
|
|
2331
2407
|
arm skill ls 列出所有 Skill
|
|
2332
2408
|
arm skill search <keyword> 搜索 Skill
|
|
@@ -2400,6 +2476,26 @@ async function main() {
|
|
|
2400
2476
|
case "me":
|
|
2401
2477
|
await getCurrentUser();
|
|
2402
2478
|
break;
|
|
2479
|
+
case "token":
|
|
2480
|
+
if (subCommand === "list") {
|
|
2481
|
+
await listTokens();
|
|
2482
|
+
} else if (subCommand === "create") {
|
|
2483
|
+
if (!args[2]) {
|
|
2484
|
+
console.error("用法: arm token create <name> [expiresAt]");
|
|
2485
|
+
process.exit(1);
|
|
2486
|
+
}
|
|
2487
|
+
await createToken(args[2], args[3]);
|
|
2488
|
+
} else if (subCommand === "revoke") {
|
|
2489
|
+
if (!args[2]) {
|
|
2490
|
+
console.error("用法: arm token revoke <id>");
|
|
2491
|
+
process.exit(1);
|
|
2492
|
+
}
|
|
2493
|
+
await revokeToken(args[2]);
|
|
2494
|
+
} else {
|
|
2495
|
+
console.error("用法: arm token list|create <name> [expiresAt]|revoke <id>");
|
|
2496
|
+
process.exit(1);
|
|
2497
|
+
}
|
|
2498
|
+
break;
|
|
2403
2499
|
case "output":
|
|
2404
2500
|
if (subCommand === "json" || subCommand === "text") {
|
|
2405
2501
|
setOutputMode(subCommand);
|
|
@@ -2535,6 +2631,7 @@ async function main() {
|
|
|
2535
2631
|
let knowledgeId;
|
|
2536
2632
|
let skillConfig;
|
|
2537
2633
|
let knowledgeConfig;
|
|
2634
|
+
let knowledgeKind;
|
|
2538
2635
|
for (let i = 3;i < args.length; i++) {
|
|
2539
2636
|
const arg = args[i];
|
|
2540
2637
|
if (arg.startsWith("--skill=")) {
|
|
@@ -2545,14 +2642,17 @@ async function main() {
|
|
|
2545
2642
|
skillConfig = arg.split("=").slice(1).join("=");
|
|
2546
2643
|
} else if (arg.startsWith("--knowledge-config=")) {
|
|
2547
2644
|
knowledgeConfig = arg.split("=").slice(1).join("=");
|
|
2645
|
+
} else if (arg.startsWith("--kind=")) {
|
|
2646
|
+
knowledgeKind = arg.split("=").slice(1).join("=");
|
|
2548
2647
|
}
|
|
2549
2648
|
}
|
|
2550
2649
|
if (skillId) {
|
|
2551
2650
|
await bindSkill(id, skillId, undefined, skillConfig);
|
|
2552
2651
|
} else if (knowledgeId) {
|
|
2553
|
-
|
|
2652
|
+
const kind = knowledgeKind === "essential" || knowledgeKind === "experience" ? knowledgeKind : undefined;
|
|
2653
|
+
await bindKnowledge(id, knowledgeId, undefined, knowledgeConfig, kind);
|
|
2554
2654
|
} else {
|
|
2555
|
-
console.error("用法: arm agent bind <id> --skill=<skillId> 或 --knowledge=<knowledgeId>");
|
|
2655
|
+
console.error("用法: arm agent bind <id> --skill=<skillId> 或 --knowledge=<knowledgeId> [--kind=essential|experience]");
|
|
2556
2656
|
process.exit(1);
|
|
2557
2657
|
}
|
|
2558
2658
|
}
|
|
@@ -2646,7 +2746,7 @@ Agent Resource Management (arm)
|
|
|
2646
2746
|
|
|
2647
2747
|
用法:
|
|
2648
2748
|
arm register [--name=<name>] [--email=<email>] [--password=<password>] 注册 (交互式或参数)
|
|
2649
|
-
arm login
|
|
2749
|
+
arm login 登录(粘贴 PAT)
|
|
2650
2750
|
arm logout 登出
|
|
2651
2751
|
arm output [json|text] 设置/查看输出模式 (默认json)
|
|
2652
2752
|
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
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ApiClient } from '../lib/client';
|
|
2
|
-
import { loadConfig, saveConfig } from '../lib/storage';
|
|
2
|
+
import { loadConfig, saveConfig, DEFAULT_SERVER_URL } from '../lib/storage';
|
|
3
3
|
import { success, error, info } from '../lib/formatter';
|
|
4
4
|
|
|
5
5
|
export async function register(name?: string, email?: string, password?: string): Promise<void> {
|
|
6
|
-
const
|
|
6
|
+
const readline = await import('readline');
|
|
7
7
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
8
8
|
|
|
9
9
|
const ask = (question: string): Promise<string> =>
|
|
@@ -35,7 +35,7 @@ export async function register(name?: string, email?: string, password?: string)
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const config = loadConfig();
|
|
38
|
-
const serverUrl = config?.serverUrl ||
|
|
38
|
+
const serverUrl = config?.serverUrl || DEFAULT_SERVER_URL;
|
|
39
39
|
const client = new ApiClient(serverUrl);
|
|
40
40
|
|
|
41
41
|
try {
|
|
@@ -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 || DEFAULT_SERVER_URL) + '/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: DEFAULT_SERVER_URL };
|
|
68
|
+
config.serverUrl = config.serverUrl || DEFAULT_SERVER_URL;
|
|
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,9 +1,11 @@
|
|
|
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');
|
|
5
5
|
const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
6
6
|
|
|
7
|
+
export const DEFAULT_SERVER_URL = 'http://arm.agent-platform.dev.aimstek.cn';
|
|
8
|
+
|
|
7
9
|
interface Config {
|
|
8
10
|
serverUrl: string;
|
|
9
11
|
token?: string;
|
|
@@ -23,7 +25,8 @@ function ensureConfigDir() {
|
|
|
23
25
|
|
|
24
26
|
export function saveConfig(config: Config): void {
|
|
25
27
|
ensureConfigDir();
|
|
26
|
-
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
28
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
29
|
+
chmodSync(CONFIG_FILE, 0o600);
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
export function loadConfig(): Config | null {
|
|
@@ -54,7 +57,7 @@ export function clearConfig(): void {
|
|
|
54
57
|
|
|
55
58
|
export function getServerUrl(): string {
|
|
56
59
|
const config = loadConfig();
|
|
57
|
-
return config?.serverUrl ||
|
|
60
|
+
return config?.serverUrl || DEFAULT_SERVER_URL;
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
export function setServerUrl(url: string): void {
|
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
|