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 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 += `&keyword=${encodeURIComponent(keyword)}`;
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 || "http://localhost:3000";
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 { readline } = await import("readline");
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 || "http://localhost:3000";
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(serverUrl, apiKey) {
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 client = new ApiClient(serverUrl);
533
- const loginRes = await client.login(apiKey);
534
- saveConfig({
535
- serverUrl,
536
- token: loginRes.token,
537
- user: loginRes.user
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}" 已绑定到 Agent "${id}"`);
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
- if (!args[1] || !args[2]) {
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 <server-url> <api-key> 登录
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
- await bindKnowledge(id, knowledgeId, undefined, knowledgeConfig);
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 <server-url> <api-key> 登录
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-resource-management",
3
- "version": "2.1.8",
3
+ "version": "2.1.10",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "arm": "./dist/main.js"
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}" 已绑定到 Agent "${id}"`);
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 { readline } = await import('readline');
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 || 'http://localhost:3000';
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(serverUrl: string, apiKey: string): Promise<void> {
56
- try {
57
- const client = new ApiClient(serverUrl);
58
- const loginRes = await client.login(apiKey);
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
- saveConfig({
61
- serverUrl,
62
- token: loginRes.token,
63
- user: loginRes.user,
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
- success(`登录成功! 欢迎, ${loginRes.user.name}`);
67
- } catch (err) {
68
- error(`登录失败: ${err instanceof Error ? err.message : '未知错误'}`);
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
+ }
@@ -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 += `&keyword=${encodeURIComponent(keyword)}`;
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);
@@ -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 || 'http://localhost:3000';
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
- if (!args[1] || !args[2]) {
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 <server-url> <api-key> 登录
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
- await bindKnowledge(id, knowledgeId, undefined, knowledgeConfig);
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 <server-url> <api-key> 登录
469
+ arm login 登录(粘贴 PAT)
448
470
  arm logout 登出
449
471
  arm output [json|text] 设置/查看输出模式 (默认json)
450
472
  arm skill ls 列出所有 Skill