ability-cli 0.3.2 → 0.3.4

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.
Files changed (3) hide show
  1. package/README.md +10 -4
  2. package/dist/index.js +129 -68
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -62,6 +62,8 @@ ability-cli inspect --ability-id 20001 --gen-template > params.json
62
62
 
63
63
  # 执行能力(对应 POST /ability-service/api/agent/v1/ability/call)
64
64
  ability-cli exec --ability-id 20001 --params '{"contact":"张三","message":"你好"}'
65
+ # 或使用工具名(与 ability-id 二选一)
66
+ ability-cli exec --tool-name my_tool --params '{}'
65
67
 
66
68
  # 健康检查
67
69
  ability-cli doctor
@@ -117,7 +119,8 @@ ability-cli doctor
117
119
 
118
120
  | 选项 | 说明 |
119
121
  |------|------|
120
- | `--ability-id <id>` | **必填**,能力 ID |
122
+ | `--ability-id <id>` | **条件必填**:能力 ID;与 `--tool-name` **至少填其一** |
123
+ | `--tool-name <name>` | **条件必填**:工具名;与 `--ability-id` **至少填其一**(二者同时填时仅用 `abilityId`) |
121
124
  | `--params <json>` | 参数:JSON 字符串,或指向 JSON 文件的路径 |
122
125
  | `--device-id <id>` | 设备 ID;默认可来自全局/环境变量/配置的合并结果 |
123
126
  | `--session-id <id>` | `sessionId` |
@@ -127,7 +130,6 @@ ability-cli doctor
127
130
  | `--trace-id <id>` | `traceId`;未指定时自动生成 |
128
131
  | `--timeout <ms>` | 超时(毫秒);不传则用配置文件 `defaults.timeout`,再默认 `30000` |
129
132
  | `--response-type <type>` | `NONE` / `MCP` / `CONVERT`(可选) |
130
- | `--mock-token <token>` | 模拟调用 token(可选,测试) |
131
133
  | `--json` | 以 JSON 展示返回 `data` |
132
134
 
133
135
  ### 下层命令:`raw`
@@ -167,13 +169,17 @@ GET `/ability-service/api/agent/v1/ability/abilityInfo`。
167
169
 
168
170
  #### `raw call`
169
171
 
170
- POST `/ability-service/api/agent/v1/ability/call`(请求体由 `--file` 提供完整 JSON)。
172
+ POST `/ability-service/api/agent/v1/ability/call`。
171
173
 
172
174
  | 选项 | 说明 |
173
175
  |------|------|
174
- | `--file <path>` | **必填**,请求体 JSON 文件路径 |
176
+ | `--file <path>` | 请求体 JSON 文件(可选);与 `--ability-id` / `--tool-name` 合并时 **CLI 优先** |
177
+ | `--ability-id <id>` | 能力 ID;与 `--tool-name` **至少填其一**(也可仅在 JSON 内提供其一) |
178
+ | `--tool-name <name>` | 工具名;与 `--ability-id` **至少填其一**(二者同时填时仅用 `abilityId`) |
175
179
  | `--json` | JSON 输出 |
176
180
 
181
+ 无 `--file` 时与 `exec` 类似,会组装最小请求体(含 `traceId`、`deviceId`、`timeoutMillis`、`params` 等默认值),仍须通过 CLI 或 JSON 解析出 `abilityId` / `toolName`。
182
+
177
183
  #### `raw category-list`
178
184
 
179
185
  GET `/ability-service/api/agent/v1/ability/category`。
package/dist/index.js CHANGED
@@ -190,6 +190,9 @@ function registerConfigCommand(program2) {
190
190
  });
191
191
  }
192
192
 
193
+ // src/commands/raw.ts
194
+ import { randomUUID as randomUUID2 } from "crypto";
195
+
193
196
  // src/context.ts
194
197
  function firstNonEmpty(...vals) {
195
198
  for (const v of vals) {
@@ -282,7 +285,7 @@ async function apiPost(ctx, path2, data) {
282
285
  }
283
286
 
284
287
  // src/commands/raw.ts
285
- import fs2 from "fs";
288
+ import fs3 from "fs";
286
289
 
287
290
  // src/agent-paths.ts
288
291
  var AGENT_API_PREFIX = "/ability-service/api/agent/v1";
@@ -294,6 +297,105 @@ var agentPath = {
294
297
  abilityCall: `${AGENT_API_PREFIX}/ability/call`
295
298
  };
296
299
 
300
+ // src/commands/exec.ts
301
+ import { randomUUID } from "crypto";
302
+ import fs2 from "fs";
303
+
304
+ // src/parse-cli-json.ts
305
+ function parseCliJsonString(raw, label) {
306
+ const s = raw.replace(/^\uFEFF/, "").trim();
307
+ if (!s) return {};
308
+ try {
309
+ return JSON.parse(s);
310
+ } catch (e) {
311
+ const msg = e instanceof Error ? e.message : String(e);
312
+ let hint = "";
313
+ if (/^\s*\{\s*'/.test(s)) {
314
+ hint = " JSON \u952E\u540D\u987B\u7528\u82F1\u6587\u53CC\u5F15\u53F7\uFF1B\u5F53\u524D\u5185\u5BB9\u5728 { \u540E\u51FA\u73B0\u4E86\u5355\u5F15\u53F7\u3002\u6700\u7A33\u59A5\uFF1A\u5C06 JSON \u5B58\u4E3A params.json\uFF08UTF-8\uFF09\uFF0C\u518D\u4F7F\u7528 --params params.json\u3002";
315
+ } else if (/[\u201c\u201d\u2018\u2019]/.test(s)) {
316
+ hint = ' \u68C0\u6D4B\u5230\u5F2F\u5F15\u53F7\uFF08\u201C \u201D \u2018 \u2019\uFF09\u3002\u8BF7\u6539\u4E3A ASCII \u53CC\u5F15\u53F7 " \u3002';
317
+ }
318
+ const preview = s.length > 160 ? `${s.slice(0, 160)}\u2026` : s;
319
+ throw new Error(`${label} \u89E3\u6790\u5931\u8D25\uFF1A${msg}.${hint}
320
+ \u5B9E\u9645\u6536\u5230\u7684\u5F00\u5934\uFF1A${JSON.stringify(preview.slice(0, 80))}`);
321
+ }
322
+ }
323
+
324
+ // src/commands/exec.ts
325
+ function pickAbilityOrTool(opts) {
326
+ const rawId = opts.abilityId !== void 0 ? String(opts.abilityId).trim() : "";
327
+ const rawName = opts.toolName !== void 0 ? String(opts.toolName).trim() : "";
328
+ if (!rawId && !rawName) {
329
+ throw new Error(
330
+ "\u5FC5\u987B\u63D0\u4F9B abilityId \u6216 toolName\uFF08\u547D\u4EE4\u884C --ability-id / --tool-name\uFF0C\u6216\u8BF7\u6C42 JSON \u5185\u5B57\u6BB5\uFF09"
331
+ );
332
+ }
333
+ if (rawId) {
334
+ const n = Number(rawId);
335
+ if (!Number.isFinite(n)) {
336
+ throw new Error(`--ability-id \u4E0D\u662F\u5408\u6CD5\u6570\u5B57: ${rawId}`);
337
+ }
338
+ return { abilityId: n };
339
+ }
340
+ return { toolName: rawName };
341
+ }
342
+ function applyAbilityOrToolToPayload(opts, data) {
343
+ const cliId = opts.abilityId !== void 0 && String(opts.abilityId).trim() !== "" ? String(opts.abilityId).trim() : "";
344
+ const cliName = opts.toolName !== void 0 && String(opts.toolName).trim() !== "" ? String(opts.toolName).trim() : "";
345
+ const fileId = data.abilityId != null && String(data.abilityId).trim() !== "" ? String(data.abilityId).trim() : "";
346
+ const fileName = data.toolName != null && String(data.toolName).trim() !== "" ? String(data.toolName).trim() : "";
347
+ const rawId = cliId || fileId;
348
+ const rawName = cliName || fileName;
349
+ const target = pickAbilityOrTool({
350
+ abilityId: rawId || void 0,
351
+ toolName: rawName || void 0
352
+ });
353
+ if (target.abilityId !== void 0) {
354
+ data.abilityId = target.abilityId;
355
+ delete data.toolName;
356
+ } else {
357
+ data.toolName = target.toolName;
358
+ delete data.abilityId;
359
+ }
360
+ }
361
+ function registerExecCommand(program2) {
362
+ program2.command("exec").description("\u6267\u884C\u80FD\u529B").addHelpText(
363
+ "after",
364
+ "\n\u63D0\u793A\uFF1A\u5FC5\u987B\u63D0\u4F9B --ability-id \u4E0E --tool-name \u4E8C\u8005\u4E4B\u4E00\uFF1B\u5176\u4F59\u9009\u9879\u8BF4\u660E\u4E2D\u5E26\u300C\u3010\u5FC5\u586B\u3011\u300D\u7684\u4E5F\u5FC5\u987B\u63D0\u4F9B\u3002\n"
365
+ ).option("--ability-id <id>", "\u3010\u6761\u4EF6\u5FC5\u586B\u3011\u80FD\u529B ID\uFF1B\u4E0E --tool-name \u81F3\u5C11\u586B\u5176\u4E00").option("--tool-name <name>", "\u3010\u6761\u4EF6\u5FC5\u586B\u3011\u5DE5\u5177\u540D\uFF1B\u4E0E --ability-id \u81F3\u5C11\u586B\u5176\u4E00").option("--params <json>", "\u80FD\u529B\u5165\u53C2 params\uFF1AJSON \u5B57\u7B26\u4E32\u6216\u6587\u4EF6\u8DEF\u5F84").option("--device-id <id>", "\u8BF7\u6C42\u4F53 deviceId\uFF1B\u672A\u6307\u5B9A\u65F6\u7528\u5168\u5C40/\u73AF\u5883\u53D8\u91CF/\u914D\u7F6E\u89E3\u6790\u7ED3\u679C").option("--session-id <id>", "sessionId").option("--tool-call-id <id>", "toolCallId").option("--task-id <id>", "taskId").option("--message-id <id>", "messageId").option("--trace-id <id>", "traceId\uFF1B\u672A\u6307\u5B9A\u65F6\u81EA\u52A8\u751F\u6210").option("--timeout <ms>", "timeoutMillis\uFF08\u6BEB\u79D2\uFF09\uFF1B\u4E0D\u4F20\u5219\u7528 defaults.timeout\uFF0C\u9ED8\u8BA4 30000").option("--response-type <type>", "responseType\uFF1ANONE | MCP | CONVERT").option("--json", "JSON \u8F93\u51FA").action(async (opts) => {
366
+ const merged = { ...program2.opts(), ...opts };
367
+ const ctx = buildAgentRequestContext(merged);
368
+ const cliCfg = loadConfig();
369
+ const timeoutMillis = opts.timeout !== void 0 && String(opts.timeout).trim() !== "" ? Number(opts.timeout) : cliCfg.defaults.timeout ?? 3e4;
370
+ let params = {};
371
+ if (opts.params) {
372
+ if (fs2.existsSync(opts.params)) {
373
+ const text = fs2.readFileSync(opts.params, "utf-8");
374
+ params = parseCliJsonString(text, "\u53C2\u6570\u6587\u4EF6");
375
+ } else {
376
+ params = parseCliJsonString(opts.params, "--params");
377
+ }
378
+ }
379
+ const body = {
380
+ traceId: opts.traceId !== void 0 && String(opts.traceId).trim() !== "" ? String(opts.traceId).trim() : randomUUID().replace(/-/g, ""),
381
+ sessionId: opts.sessionId !== void 0 ? String(opts.sessionId) : "",
382
+ toolCallId: opts.toolCallId !== void 0 ? String(opts.toolCallId) : "",
383
+ taskId: opts.taskId !== void 0 ? String(opts.taskId) : "",
384
+ messageId: opts.messageId !== void 0 ? String(opts.messageId) : "",
385
+ deviceId: ctx.deviceId ?? "",
386
+ timeoutMillis,
387
+ params
388
+ };
389
+ applyAbilityOrToolToPayload(opts, body);
390
+ if (opts.responseType) body.responseType = opts.responseType;
391
+ const res = await apiPost(ctx, agentPath.abilityCall, body);
392
+ handleApiResponse(res, opts.json, (data) => {
393
+ printSuccess("\u80FD\u529B\u6267\u884C\u5B8C\u6210");
394
+ printJson(data);
395
+ });
396
+ });
397
+ }
398
+
297
399
  // src/commands/raw.ts
298
400
  function registerRawCommand(program2) {
299
401
  const raw = program2.command("raw").description("\u539F\u59CB\u63A5\u53E3\u76F4\u901A\uFF08\u8054\u8C03/\u6392\u969C\uFF09");
@@ -330,11 +432,34 @@ function registerRawCommand(program2) {
330
432
  });
331
433
  raw.command("call").description("POST \u6267\u884C\u80FD\u529B\uFF08Agent API\uFF09").addHelpText(
332
434
  "after",
333
- "\n\u63D0\u793A\uFF1A\u9009\u9879\u8BF4\u660E\u4E2D\u4EE5\u300C\u3010\u5FC5\u586B\u3011\u300D\u5F00\u5934\u7684\u5FC5\u987B\u63D0\u4F9B\uFF0C\u5176\u4F59\u5747\u4E3A\u53EF\u9009\u3002\n"
334
- ).requiredOption("--file <path>", "\u3010\u5FC5\u586B\u3011\u8BF7\u6C42\u4F53 JSON \u6587\u4EF6\u8DEF\u5F84").option("--json", "JSON \u8F93\u51FA").action(async (opts) => {
435
+ "\n\u63D0\u793A\uFF1A\u987B\u80FD\u901A\u8FC7\u547D\u4EE4\u884C\u6216 JSON \u89E3\u6790\u51FA abilityId / toolName\uFF08\u4E8C\u8005\u5176\u4E00\uFF09\uFF1B\u65E0 --file \u65F6\u5FC5\u987B\u63D0\u4F9B --ability-id \u6216 --tool-name\u3002\n"
436
+ ).option("--file <path>", "\u8BF7\u6C42\u4F53 JSON \u6587\u4EF6\uFF08\u53EF\u9009\uFF1B\u4E0E CLI \u5B57\u6BB5\u5408\u5E76\uFF0CCLI \u4F18\u5148\uFF09").option("--ability-id <id>", "\u80FD\u529B ID\uFF1B\u4E0E --tool-name \u81F3\u5C11\u5176\u4E00\uFF08\u53EF\u4E0E --file \u7EC4\u5408\uFF09").option("--tool-name <name>", "\u5DE5\u5177\u540D\uFF1B\u4E0E --ability-id \u81F3\u5C11\u5176\u4E00\uFF08\u53EF\u4E0E --file \u7EC4\u5408\uFF09").option("--json", "JSON \u8F93\u51FA").action(async (opts) => {
335
437
  const merged = { ...program2.opts(), ...opts };
336
438
  const ctx = buildAgentRequestContext(merged);
337
- const data = JSON.parse(fs2.readFileSync(opts.file, "utf-8"));
439
+ const cliCfg = loadConfig();
440
+ const timeoutMillis = cliCfg.defaults.timeout ?? 3e4;
441
+ let data;
442
+ if (opts.file) {
443
+ const raw2 = fs3.readFileSync(opts.file, "utf-8");
444
+ const parsed = JSON.parse(raw2);
445
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
446
+ throw new Error("\u8BF7\u6C42\u4F53\u5FC5\u987B\u662F JSON \u5BF9\u8C61");
447
+ }
448
+ data = parsed;
449
+ applyAbilityOrToolToPayload(opts, data);
450
+ } else {
451
+ data = {
452
+ traceId: randomUUID2().replace(/-/g, ""),
453
+ sessionId: "",
454
+ toolCallId: "",
455
+ taskId: "",
456
+ messageId: "",
457
+ deviceId: ctx.deviceId ?? "",
458
+ timeoutMillis,
459
+ params: {}
460
+ };
461
+ applyAbilityOrToolToPayload(opts, data);
462
+ }
338
463
  const res = await apiPost(ctx, agentPath.abilityCall, data);
339
464
  handleApiResponse(res, opts.json, (data2) => printJson(data2));
340
465
  });
@@ -416,70 +541,6 @@ function registerInspectCommand(program2) {
416
541
  });
417
542
  }
418
543
 
419
- // src/commands/exec.ts
420
- import { randomUUID } from "crypto";
421
- import fs3 from "fs";
422
-
423
- // src/parse-cli-json.ts
424
- function parseCliJsonString(raw, label) {
425
- const s = raw.replace(/^\uFEFF/, "").trim();
426
- if (!s) return {};
427
- try {
428
- return JSON.parse(s);
429
- } catch (e) {
430
- const msg = e instanceof Error ? e.message : String(e);
431
- let hint = "";
432
- if (/^\s*\{\s*'/.test(s)) {
433
- hint = " JSON \u952E\u540D\u987B\u7528\u82F1\u6587\u53CC\u5F15\u53F7\uFF1B\u5F53\u524D\u5185\u5BB9\u5728 { \u540E\u51FA\u73B0\u4E86\u5355\u5F15\u53F7\u3002\u6700\u7A33\u59A5\uFF1A\u5C06 JSON \u5B58\u4E3A params.json\uFF08UTF-8\uFF09\uFF0C\u518D\u4F7F\u7528 --params params.json\u3002";
434
- } else if (/[\u201c\u201d\u2018\u2019]/.test(s)) {
435
- hint = ' \u68C0\u6D4B\u5230\u5F2F\u5F15\u53F7\uFF08\u201C \u201D \u2018 \u2019\uFF09\u3002\u8BF7\u6539\u4E3A ASCII \u53CC\u5F15\u53F7 " \u3002';
436
- }
437
- const preview = s.length > 160 ? `${s.slice(0, 160)}\u2026` : s;
438
- throw new Error(`${label} \u89E3\u6790\u5931\u8D25\uFF1A${msg}.${hint}
439
- \u5B9E\u9645\u6536\u5230\u7684\u5F00\u5934\uFF1A${JSON.stringify(preview.slice(0, 80))}`);
440
- }
441
- }
442
-
443
- // src/commands/exec.ts
444
- function registerExecCommand(program2) {
445
- program2.command("exec").description("\u6267\u884C\u80FD\u529B").addHelpText(
446
- "after",
447
- "\n\u63D0\u793A\uFF1A\u9009\u9879\u8BF4\u660E\u4E2D\u4EE5\u300C\u3010\u5FC5\u586B\u3011\u300D\u5F00\u5934\u7684\u5FC5\u987B\u63D0\u4F9B\uFF0C\u5176\u4F59\u5747\u4E3A\u53EF\u9009\u3002\n"
448
- ).requiredOption("--ability-id <id>", "\u3010\u5FC5\u586B\u3011\u80FD\u529B ID").option("--params <json>", "\u53C2\u6570 JSON \u5B57\u7B26\u4E32\u6216\u6587\u4EF6\u8DEF\u5F84").option("--device-id <id>", "\u8BBE\u5907ID").option("--message-id <id>", "messageId").option("--trace-id <id>", "traceId").option("--timeout <ms>", "\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09\uFF1B\u4E0D\u4F20\u5219\u7528\u914D\u7F6E\u6587\u4EF6 defaults.timeout\uFF0C\u9ED8\u8BA4 30000").option("--response-type <type>", "\u8FD4\u56DE\u503C\u5904\u7406\u65B9\u5F0F: NONE | MCP | CONVERT").option("--json", "JSON \u8F93\u51FA").action(async (opts) => {
449
- const merged = { ...program2.opts(), ...opts };
450
- const ctx = buildAgentRequestContext(merged);
451
- const cliCfg = loadConfig();
452
- const timeoutMillis = opts.timeout !== void 0 && String(opts.timeout).trim() !== "" ? Number(opts.timeout) : cliCfg.defaults.timeout ?? 3e4;
453
- let params = {};
454
- if (opts.params) {
455
- if (fs3.existsSync(opts.params)) {
456
- const text = fs3.readFileSync(opts.params, "utf-8");
457
- params = parseCliJsonString(text, "\u53C2\u6570\u6587\u4EF6");
458
- } else {
459
- params = parseCliJsonString(opts.params, "--params");
460
- }
461
- }
462
- const body = {
463
- abilityId: Number(opts.abilityId),
464
- traceId: opts.traceId ?? randomUUID().replace(/-/g, ""),
465
- sessionId: opts.sessionId ?? "",
466
- toolCallId: opts.toolCallId ?? "",
467
- taskId: opts.taskId ?? "",
468
- messageId: opts.messageId ?? "",
469
- deviceId: ctx.deviceId ?? "",
470
- timeoutMillis,
471
- params
472
- };
473
- if (opts.responseType) body.responseType = opts.responseType;
474
- if (opts.mockToken) body.mockToken = opts.mockToken;
475
- const res = await apiPost(ctx, agentPath.abilityCall, body);
476
- handleApiResponse(res, opts.json, (data) => {
477
- printSuccess("\u80FD\u529B\u6267\u884C\u5B8C\u6210");
478
- printJson(data);
479
- });
480
- });
481
- }
482
-
483
544
  // src/commands/sign.ts
484
545
  import chalk2 from "chalk";
485
546
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ability-cli",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "原子能力平台 CLI 工具",
5
5
  "repository": {
6
6
  "type": "git",