agent-resource-management 2.1.6 → 2.1.7

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/AGENTS.md ADDED
@@ -0,0 +1,368 @@
1
+ # ARM CLI 开发规范
2
+
3
+ > Agent Resource Management CLI 工具
4
+
5
+ ## 1. 项目概述
6
+
7
+ ARM CLI 是一个基于 Bun + TypeScript 的命令行工具,用于管理 Agent、Skill、Knowledge 资源。
8
+
9
+ ### 命令结构
10
+
11
+ ```
12
+ arm <entity> <action> [options]
13
+
14
+ Entities:
15
+ - auth # 认证
16
+ - skill # Skill 管理
17
+ - knowledge # Knowledge 管理
18
+ - agent # Agent 管理
19
+ - server # 服务端配置
20
+ - output # 输出模式配置
21
+ - me # 当前用户信息
22
+ ```
23
+
24
+ ---
25
+
26
+ ## 2. 技术栈
27
+
28
+ | 组件 | 技术 |
29
+ |------|------|
30
+ | Runtime | Bun |
31
+ | Language | TypeScript |
32
+ | HTTP Client | Fetch API |
33
+ | 类型 | `@pkg/types/skill` |
34
+
35
+ ---
36
+
37
+ ## 3. 目录结构
38
+
39
+ ```
40
+ cli/
41
+ ├── src/
42
+ │ ├── main.ts # CLI 入口,命令解析
43
+ │ ├── cmd/ # 命令实现
44
+ │ │ ├── auth.ts # login/logout/register
45
+ │ │ ├── skill.ts # Skill CRUD
46
+ │ │ ├── knowledge.ts # Knowledge CRUD
47
+ │ │ ├── agent.ts # Agent CRUD + bind/sync
48
+ │ │ └── server.ts # 服务端配置
49
+ │ └── lib/ # 工具库
50
+ │ ├── client.ts # ApiClient HTTP 客户端
51
+ │ ├── storage.ts # 本地配置存储 (~/.arm/)
52
+ │ ├── output.ts # JSON/Text 输出模式
53
+ │ ├── formatter.ts # 格式化输出
54
+ │ └── validate.ts # 本地验证
55
+ ├── package.json
56
+ └── tsconfig.json
57
+ ```
58
+
59
+ ---
60
+
61
+ ## 4. 核心库
62
+
63
+ ### 4.1 ApiClient
64
+
65
+ HTTP 客户端封装,基于 Fetch API:
66
+
67
+ ```typescript
68
+ import { ApiClient } from './lib/client';
69
+
70
+ const client = new ApiClient(serverUrl, token);
71
+
72
+ // 设置 Token
73
+ client.setToken(token);
74
+
75
+ // 认证
76
+ await client.login(apiKey);
77
+ await client.me();
78
+
79
+ // Skills
80
+ await client.listSkills(keyword?, page?, pageSize?);
81
+ await client.getSkill(name);
82
+ await client.uploadSkill(filePath);
83
+ await client.downloadSkill(name);
84
+
85
+ // Agents
86
+ await client.listAgents(keyword?, page?, pageSize?);
87
+ await client.getAgent(id);
88
+ await client.createAgent(data);
89
+ await client.updateAgent(id, data);
90
+ await client.deleteAgent(id);
91
+ await client.bindSkillToAgent(agentId, skillId, version, config?);
92
+ await client.unbindSkillFromAgent(agentId, skillId, version?);
93
+ ```
94
+
95
+ ### 4.2 Storage
96
+
97
+ 本地配置存储在 `~/.arm/config.json`:
98
+
99
+ ```typescript
100
+ import { loadConfig, saveConfig, clearConfig } from './lib/storage';
101
+
102
+ const config = loadConfig();
103
+ // { serverUrl, token, user, outputMode }
104
+
105
+ saveConfig({ serverUrl, token, user });
106
+ clearConfig(); // 只清除 token 和 user
107
+ ```
108
+
109
+ ### 4.3 Output
110
+
111
+ 支持 JSON 和 Text 两种输出模式:
112
+
113
+ ```typescript
114
+ import { shouldOutputJson, outputJson } from './lib/output';
115
+
116
+ // 检查是否应该输出 JSON
117
+ if (shouldOutputJson()) {
118
+ outputJson({ success: true, data: {...} });
119
+ return;
120
+ }
121
+
122
+ // Text 模式输出
123
+ console.log('Normal output');
124
+ ```
125
+
126
+ **JSON 输出格式**:
127
+
128
+ ```typescript
129
+ { success: true, data: {...} }
130
+ { success: false, error: { code: 'ERROR_CODE', message: '...' } }
131
+ ```
132
+
133
+ ---
134
+
135
+ ## 5. 命令开发规范
136
+
137
+ ### 5.1 命令模板
138
+
139
+ ```typescript
140
+ export async function myCommand(id: string, options: { flag?: boolean } = {}): Promise<void> {
141
+ // 1. 检查登录状态
142
+ const config = loadConfig();
143
+ if (!config?.token) {
144
+ if (shouldOutputJson()) {
145
+ outputJson({ success: false, error: { code: 'NOT_LOGGED_IN', message: '未登录' } });
146
+ process.exit(1);
147
+ }
148
+ error('未登录,请先运行 arm login');
149
+ process.exit(1);
150
+ }
151
+
152
+ // 2. 创建客户端
153
+ const client = new ApiClient(config.serverUrl, config.token);
154
+
155
+ try {
156
+ // 3. 业务逻辑
157
+ const result = await client.someMethod();
158
+
159
+ // 4. 输出结果
160
+ if (shouldOutputJson()) {
161
+ outputJson({ success: true, data: result });
162
+ return;
163
+ }
164
+ success('操作成功');
165
+
166
+ } catch (err) {
167
+ // 5. 错误处理
168
+ if (shouldOutputJson()) {
169
+ outputJson({ success: false, error: { code: 'METHOD_FAILED', message: err instanceof Error ? err.message : '未知错误' } });
170
+ process.exit(1);
171
+ }
172
+ error(`操作失败: ${err instanceof Error ? err.message : '未知错误'}`);
173
+ process.exit(1);
174
+ }
175
+ }
176
+ ```
177
+
178
+ ### 5.2 main.ts 命令注册
179
+
180
+ ```typescript
181
+ case 'entity':
182
+ switch (subCommand) {
183
+ case 'action':
184
+ if (!args[2]) {
185
+ console.error('用法: arm entity action <id> [--flag] [--json]');
186
+ process.exit(1);
187
+ }
188
+ await myCommand(args[2], { flag: args.includes('--flag') });
189
+ break;
190
+ default:
191
+ console.log(`可用命令: arm entity action <id>`);
192
+ }
193
+ break;
194
+ ```
195
+
196
+ ### 5.3 错误码规范
197
+
198
+ | 错误码 | 说明 |
199
+ |--------|------|
200
+ | `NOT_LOGGED_IN` | 未登录 |
201
+ | `NOT_FOUND` | 资源不存在 |
202
+ | `CREATE_FAILED` | 创建失败 |
203
+ | `UPDATE_FAILED` | 更新失败 |
204
+ | `DELETE_FAILED` | 删除失败 |
205
+ | `BIND_FAILED` | 绑定失败 |
206
+ | `UNBIND_FAILED` | 解绑失败 |
207
+ | `UPLOAD_FAILED` | 上传失败 |
208
+ | `DOWNLOAD_FAILED` | 下载失败 |
209
+ | `SYNC_FAILED` | 同步失败 |
210
+ | `VALIDATION_FAILED` | 验证失败 |
211
+ | `FILE_NOT_FOUND` | 文件不存在 |
212
+
213
+ ---
214
+
215
+ ## 6. 常用命令速查
216
+
217
+ ### 6.1 认证
218
+
219
+ ```bash
220
+ arm login <server-url> <api-key>
221
+ arm logout
222
+ arm me
223
+ ```
224
+
225
+ ### 6.2 Skill
226
+
227
+ ```bash
228
+ arm skill ls # 列出
229
+ arm skill search <keyword> # 搜索
230
+ arm skill info <name> # 详情
231
+ arm skill download <name> [dir] # 下载
232
+ arm skill upload <path> # 上传
233
+ arm skill my # 我的发布
234
+ arm skill delete <name> # 删除
235
+ arm skill validate <path> # 验证
236
+ ```
237
+
238
+ ### 6.3 Knowledge
239
+
240
+ ```bash
241
+ arm knowledge ls
242
+ arm knowledge search <keyword>
243
+ arm knowledge info <name>
244
+ arm knowledge download <name> [dir]
245
+ arm knowledge upload <path>
246
+ arm knowledge my
247
+ arm knowledge delete <name>
248
+ ```
249
+
250
+ ### 6.4 Agent
251
+
252
+ ```bash
253
+ # 基础 CRUD
254
+ arm agent ls
255
+ arm agent search <keyword>
256
+ arm agent info <name>
257
+ arm agent create <name> [--description=...] [--prompt=...]
258
+ arm agent create --from=<folder> # 从文件夹创建
259
+ arm agent update <id> [--name=...] [--description=...] [--prompt=...] [--status=active|draft]
260
+ arm agent delete <id>
261
+
262
+ # 绑定管理
263
+ arm agent bind <id> --skill=<skillId> [--skill-config='{...}']
264
+ arm agent unbind <id> --skill=<skillId> [--version=<ver>]
265
+ arm agent bind <id> --knowledge=<knowledgeId>
266
+ arm agent unbind <id> --knowledge=<knowledgeId> [--version=<ver>]
267
+
268
+ # 同步
269
+ arm agent sync <folder> [--dry-run] [--force]
270
+ ```
271
+
272
+ ### 6.5 配置
273
+
274
+ ```bash
275
+ arm output [json|text] # 输出模式
276
+ arm server # 显示服务端
277
+ arm server set <url> # 设置服务端
278
+ ```
279
+
280
+ ---
281
+
282
+ ## 7. Agent 文件夹结构
283
+
284
+ `arm agent create --from=<folder>` 支持的目录结构:
285
+
286
+ ```
287
+ <folder>/
288
+ ├── AGENT.md # Agent 元信息 (必填)
289
+ ├── skills/ # 可选: Skill 子目录
290
+ │ └── <skill-name>/
291
+ │ └── SKILL.md
292
+ └── knowledges/ # 可选: Knowledge 目录
293
+ └── <name>.md
294
+ ```
295
+
296
+ ### AGENT.md 格式
297
+
298
+ ```yaml
299
+ ---
300
+ name: my-agent
301
+ description: 我的 Agent 描述
302
+ prompt: |
303
+ You are a helpful assistant.
304
+ ---
305
+ ```
306
+
307
+ ---
308
+
309
+ ## 8. 开发命令
310
+
311
+ ```bash
312
+ cd cli
313
+
314
+ # 安装依赖
315
+ bun install
316
+
317
+ # 运行 CLI
318
+ bun run src/main.ts <command>
319
+
320
+ # 或全局链接
321
+ bun link
322
+ arm <command>
323
+
324
+ # 类型检查
325
+ bun run typecheck
326
+ ```
327
+
328
+ ---
329
+
330
+ ## 9. 关键实现细节
331
+
332
+ ### 9.1 API 路径前缀
333
+
334
+ ```typescript
335
+ // client.ts
336
+ `${this.serverUrl}/api/v1${path}`
337
+ ```
338
+
339
+ ### 9.2 分页参数
340
+
341
+ ```typescript
342
+ ?page=1&pageSize=20
343
+ ```
344
+
345
+ ### 9.3 搜索参数
346
+
347
+ ```typescript
348
+ ?keyword=<encoded-keyword>
349
+ ```
350
+
351
+ ### 9.4 状态过滤
352
+
353
+ ```typescript
354
+ ?status=active
355
+ ?status=draft
356
+ ```
357
+
358
+ ### 9.5 文件上传
359
+
360
+ 使用 `FormData` 而非 JSON:
361
+
362
+ ```typescript
363
+ const formData = new FormData();
364
+ const blob = new Blob([fileBuffer]);
365
+ formData.append('file', blob, fileName);
366
+
367
+ fetch(url, { method: 'POST', body: formData, headers });
368
+ ```
package/README.md CHANGED
@@ -294,3 +294,10 @@ npm run dev
294
294
  ## License
295
295
 
296
296
  MIT
297
+
298
+
299
+ ## 联系我
300
+
301
+ 442969153@qq.com
302
+
303
+ wechat:lkdm5201314
package/dist/main.js CHANGED
@@ -100,7 +100,6 @@ class ApiClient {
100
100
  body: formData
101
101
  });
102
102
  const data = await res.json();
103
- console.error("DEBUG server response:", JSON.stringify(data));
104
103
  if (!data.ok) {
105
104
  throw new Error(data.msg);
106
105
  }
@@ -813,7 +812,7 @@ function validateAgentDir(dirPath) {
813
812
  result.metadata.knowledges = knowledgesLines.map((l) => l.replace(/^\s*-\s*/, "").trim());
814
813
  }
815
814
  const contentAfterFrontmatter = agentMdContent.replace(/^---[\s\S]*?---\n/, "");
816
- const promptMatch = contentAfterFrontmatter.match(/#\s*System\s*Prompt\n([\s\S]*?)$/);
815
+ const promptMatch = contentAfterFrontmatter.match(/#\s*System\s*Prompt\n+([\s\S]*?)$/);
817
816
  if (promptMatch) {
818
817
  result.metadata.prompt = promptMatch[1].trim();
819
818
  } else if (contentAfterFrontmatter.trim()) {
@@ -2437,10 +2436,6 @@ async function main() {
2437
2436
  await downloadAgent(args[2], args[3]);
2438
2437
  break;
2439
2438
  case "create":
2440
- if (!args[2]) {
2441
- console.error(`用法: arm agent create <name> [--description="..."] [--prompt="..."] [--avatar="..."] [--skill=id] [--knowledge=id] [--skill-config='{...}'] [--knowledge-config='{...}'] [--from=<folder-path>] [--json]`);
2442
- process.exit(1);
2443
- }
2444
2439
  {
2445
2440
  const name = args[2];
2446
2441
  const options = {};
@@ -2449,6 +2444,12 @@ async function main() {
2449
2444
  const skillConfigs = [];
2450
2445
  const knowledgeConfigs = [];
2451
2446
  let fromFolder;
2447
+ if (name?.startsWith("--from=")) {
2448
+ fromFolder = name.split("=").slice(1).join("=");
2449
+ } else if (!name) {
2450
+ console.error(`用法: arm agent create <name> [--description="..."] [--prompt="..."] [--avatar="..."] [--skill=id] [--knowledge=id] [--skill-config='{...}'] [--knowledge-config='{...}'] [--from=<folder-path>] [--json]`);
2451
+ process.exit(1);
2452
+ }
2452
2453
  for (let i = 3;i < args.length; i++) {
2453
2454
  const arg = args[i];
2454
2455
  if (arg.startsWith("--description=")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-resource-management",
3
- "version": "2.1.6",
3
+ "version": "2.1.7",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "arm": "./dist/main.js"
package/src/lib/client.ts CHANGED
@@ -118,7 +118,6 @@ export class ApiClient {
118
118
  });
119
119
 
120
120
  const data = await res.json();
121
- console.error('DEBUG server response:', JSON.stringify(data));
122
121
  if (!data.ok) {
123
122
  throw new Error(data.msg);
124
123
  }
@@ -283,7 +283,7 @@ export function validateAgentDir(dirPath: string): AgentValidationResult {
283
283
  }
284
284
 
285
285
  const contentAfterFrontmatter = agentMdContent.replace(/^---[\s\S]*?---\n/, '');
286
- const promptMatch = contentAfterFrontmatter.match(/#\s*System\s*Prompt\n([\s\S]*?)$/);
286
+ const promptMatch = contentAfterFrontmatter.match(/#\s*System\s*Prompt\n+([\s\S]*?)$/);
287
287
  if (promptMatch) {
288
288
  result.metadata.prompt = promptMatch[1].trim();
289
289
  } else if (contentAfterFrontmatter.trim()) {
package/src/main.ts CHANGED
@@ -224,10 +224,6 @@ async function main() {
224
224
  await downloadAgent(args[2], args[3]);
225
225
  break;
226
226
  case 'create':
227
- if (!args[2]) {
228
- console.error('用法: arm agent create <name> [--description="..."] [--prompt="..."] [--avatar="..."] [--skill=id] [--knowledge=id] [--skill-config=\'{...}\'] [--knowledge-config=\'{...}\'] [--from=<folder-path>] [--json]');
229
- process.exit(1);
230
- }
231
227
  {
232
228
  const name = args[2];
233
229
  const options: Record<string, string | undefined> = {};
@@ -237,6 +233,13 @@ async function main() {
237
233
  const knowledgeConfigs: string[] = [];
238
234
  let fromFolder: string | undefined;
239
235
 
236
+ if (name?.startsWith('--from=')) {
237
+ fromFolder = name.split('=').slice(1).join('=');
238
+ } else if (!name) {
239
+ console.error('用法: arm agent create <name> [--description="..."] [--prompt="..."] [--avatar="..."] [--skill=id] [--knowledge=id] [--skill-config=\'{...}\'] [--knowledge-config=\'{...}\'] [--from=<folder-path>] [--json]');
240
+ process.exit(1);
241
+ }
242
+
240
243
  for (let i = 3; i < args.length; i++) {
241
244
  const arg = args[i];
242
245
  if (arg.startsWith('--description=')) {