ability-cli 0.2.2 → 0.3.1
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/README.md +48 -58
- package/dist/index.js +199 -127
- package/package.json +53 -53
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## 1. 项目简介
|
|
4
4
|
|
|
5
|
-
**ability-cli**
|
|
5
|
+
**ability-cli** 是面向原子能力平台的命令行工具,用于在终端中搜索能力、查看详情、执行调用,以及直接访问 **Agent API**(路径前缀 `/ability-service/api/agent/v1`)。
|
|
6
6
|
|
|
7
7
|
采用**双层设计**:
|
|
8
8
|
|
|
@@ -48,20 +48,20 @@ pnpm link --global
|
|
|
48
48
|
## 3. 快速上手
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
|
-
#
|
|
52
|
-
ability-cli config set --
|
|
51
|
+
# 配置授权密钥(sk)与默认设备 ID(也可改用环境变量,见下文)
|
|
52
|
+
ability-cli config set --auth-token sk-xxxx --device-id <device-id>
|
|
53
53
|
|
|
54
|
-
#
|
|
55
|
-
ability-cli search
|
|
54
|
+
# 搜索能力(请求头:Authorization + zy-device-id,不发网关 zy-sign)
|
|
55
|
+
ability-cli search --natural-lang "发送一条微信消息"
|
|
56
56
|
|
|
57
|
-
#
|
|
58
|
-
ability-cli inspect --ability-id 20001
|
|
57
|
+
# 查看能力详情(端侧能力建议带设备 ID)
|
|
58
|
+
ability-cli inspect --ability-id 20001
|
|
59
59
|
|
|
60
60
|
# 生成参数模板
|
|
61
61
|
ability-cli inspect --ability-id 20001 --gen-template > params.json
|
|
62
62
|
|
|
63
|
-
#
|
|
64
|
-
ability-cli exec --ability-id 20001 --params
|
|
63
|
+
# 执行能力(对应 POST /ability-service/api/agent/v1/ability/call)
|
|
64
|
+
ability-cli exec --ability-id 20001 --params '{"contact":"张三","message":"你好"}'
|
|
65
65
|
|
|
66
66
|
# 健康检查
|
|
67
67
|
ability-cli doctor
|
|
@@ -73,16 +73,16 @@ ability-cli doctor
|
|
|
73
73
|
|
|
74
74
|
### 全局选项
|
|
75
75
|
|
|
76
|
-
下列选项可写在任意子命令**之前**,作用于本次整条命令(例如 `ability-cli --
|
|
76
|
+
下列选项可写在任意子命令**之前**,作用于本次整条命令(例如 `ability-cli --auth-token sk-xxx search --natural-lang "查询"`)。
|
|
77
|
+
|
|
78
|
+
同一字段的优先级为:**子命令参数 > 全局参数 > 环境变量 > 配置文件**(合并后的命令行优先于 `ABILITY_CLI_*` 与 `~/.ability-cli/config.json`)。
|
|
77
79
|
|
|
78
80
|
| 选项 | 说明 |
|
|
79
81
|
|------|------|
|
|
80
|
-
| `--env <env>` | 环境:`test` / `prod
|
|
81
|
-
| `--
|
|
82
|
-
| `--
|
|
83
|
-
| `--
|
|
84
|
-
| `--base-url <url>` | 网关根地址 |
|
|
85
|
-
| `--magic-sign` | 测试环境跳过验签(`zy-sign` 固定为测试用魔数) |
|
|
82
|
+
| `--env <env>` | 环境:`test` / `prod`,选用配置文件中哪一套 `profiles`(主要影响 `baseUrl`) |
|
|
83
|
+
| `--auth-token <token>` | 授权密钥 `sk-…`,写入请求头 `Authorization` |
|
|
84
|
+
| `--base-url <url>` | 网关根地址(真实路径为 `{baseUrl}/ability-service/api/agent/v1/...`) |
|
|
85
|
+
| `--device-id <id>` | 设备 ID,写入请求头 `zy-device-id`,并参与部分接口 query |
|
|
86
86
|
| `-v, --verbose` | 详细输出(请求 URL、头、体与响应等) |
|
|
87
87
|
|
|
88
88
|
### 上层命令
|
|
@@ -113,28 +113,30 @@ ability-cli doctor
|
|
|
113
113
|
|
|
114
114
|
#### `exec`
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
执行能力(`POST /ability-service/api/agent/v1/ability/call`,同步等待结果)。
|
|
117
117
|
|
|
118
118
|
| 选项 | 说明 |
|
|
119
119
|
|------|------|
|
|
120
120
|
| `--ability-id <id>` | **必填**,能力 ID |
|
|
121
121
|
| `--params <json>` | 参数:JSON 字符串,或指向 JSON 文件的路径 |
|
|
122
|
-
| `--device-id <id>` | 设备 ID
|
|
122
|
+
| `--device-id <id>` | 设备 ID;默认可来自全局/环境变量/配置的合并结果 |
|
|
123
123
|
| `--session-id <id>` | `sessionId` |
|
|
124
124
|
| `--tool-call-id <id>` | `toolCallId` |
|
|
125
125
|
| `--task-id <id>` | `taskId` |
|
|
126
126
|
| `--message-id <id>` | `messageId` |
|
|
127
127
|
| `--trace-id <id>` | `traceId`;未指定时自动生成 |
|
|
128
|
-
| `--timeout <ms>` |
|
|
128
|
+
| `--timeout <ms>` | 超时(毫秒);不传则用配置文件 `defaults.timeout`,再默认 `30000` |
|
|
129
|
+
| `--response-type <type>` | `NONE` / `MCP` / `CONVERT`(可选) |
|
|
130
|
+
| `--mock-token <token>` | 模拟调用 token(可选,测试) |
|
|
129
131
|
| `--json` | 以 JSON 展示返回 `data` |
|
|
130
132
|
|
|
131
133
|
### 下层命令:`raw`
|
|
132
134
|
|
|
133
|
-
`raw`
|
|
135
|
+
`raw` 子命令与 **Agent API** 路径一一对应(前缀 `/ability-service/api/agent/v1`)。
|
|
134
136
|
|
|
135
137
|
#### `raw ability-list`
|
|
136
138
|
|
|
137
|
-
GET
|
|
139
|
+
GET `/ability-service/api/agent/v1/ability/list`。
|
|
138
140
|
|
|
139
141
|
| 选项 | 说明 |
|
|
140
142
|
|------|------|
|
|
@@ -144,18 +146,9 @@ GET 能力列表。
|
|
|
144
146
|
| `--natural-lang <text>` | 自然语言筛选 |
|
|
145
147
|
| `--json` | JSON 输出 |
|
|
146
148
|
|
|
147
|
-
#### `raw ability-record`
|
|
148
|
-
|
|
149
|
-
POST 能力上报。
|
|
150
|
-
|
|
151
|
-
| 选项 | 说明 |
|
|
152
|
-
|------|------|
|
|
153
|
-
| `--file <path>` | **必填**,请求体 JSON 文件路径 |
|
|
154
|
-
| `--json` | JSON 输出 |
|
|
155
|
-
|
|
156
149
|
#### `raw app-info`
|
|
157
150
|
|
|
158
|
-
GET
|
|
151
|
+
GET `/ability-service/api/agent/v1/ability/appInfo`。
|
|
159
152
|
|
|
160
153
|
| 选项 | 说明 |
|
|
161
154
|
|------|------|
|
|
@@ -164,7 +157,7 @@ GET 应用信息。
|
|
|
164
157
|
|
|
165
158
|
#### `raw ability-info`
|
|
166
159
|
|
|
167
|
-
GET
|
|
160
|
+
GET `/ability-service/api/agent/v1/ability/abilityInfo`。
|
|
168
161
|
|
|
169
162
|
| 选项 | 说明 |
|
|
170
163
|
|------|------|
|
|
@@ -172,9 +165,9 @@ GET 能力详情。
|
|
|
172
165
|
| `--device-id <id>` | 设备 ID;**端侧能力**时通常必填;未指定时可使用 `defaults.deviceId` |
|
|
173
166
|
| `--json` | JSON 输出 |
|
|
174
167
|
|
|
175
|
-
#### `raw call
|
|
168
|
+
#### `raw call`
|
|
176
169
|
|
|
177
|
-
POST
|
|
170
|
+
POST `/ability-service/api/agent/v1/ability/call`(请求体由 `--file` 提供完整 JSON)。
|
|
178
171
|
|
|
179
172
|
| 选项 | 说明 |
|
|
180
173
|
|------|------|
|
|
@@ -183,7 +176,7 @@ POST 执行能力。
|
|
|
183
176
|
|
|
184
177
|
#### `raw category-list`
|
|
185
178
|
|
|
186
|
-
GET
|
|
179
|
+
GET `/ability-service/api/agent/v1/ability/category`。
|
|
187
180
|
|
|
188
181
|
| 选项 | 说明 |
|
|
189
182
|
|------|------|
|
|
@@ -198,13 +191,10 @@ GET 全量分类。
|
|
|
198
191
|
| 选项 | 说明 |
|
|
199
192
|
|------|------|
|
|
200
193
|
| `--env <env>` | 目标环境;影响写入哪一段 `profiles`,并更新当前 `env` |
|
|
201
|
-
| `--
|
|
202
|
-
| `--app-secret <secret>` | `appSecret` |
|
|
203
|
-
| `--auth-token <token>` | Authorization token |
|
|
194
|
+
| `--auth-token <token>` | 授权密钥 `sk-…`(写入 `profiles.*.authToken`) |
|
|
204
195
|
| `--base-url <url>` | 网关地址 |
|
|
205
196
|
| `--device-id <id>` | 默认设备 ID(`defaults.deviceId`) |
|
|
206
|
-
| `--
|
|
207
|
-
| `--os-version <ver>` | 默认系统版本 |
|
|
197
|
+
| `--timeout <ms>` | 默认调用超时毫秒数(`defaults.timeout`);`exec` 未带 `--timeout` 时使用 |
|
|
208
198
|
|
|
209
199
|
#### `config show`
|
|
210
200
|
|
|
@@ -216,14 +206,14 @@ GET 全量分类。
|
|
|
216
206
|
|
|
217
207
|
| 选项 | 说明 |
|
|
218
208
|
|------|------|
|
|
219
|
-
| `--app-id <id>` | 覆盖 `zy-app-id
|
|
220
|
-
| `--app-secret <secret>` |
|
|
209
|
+
| `--app-id <id>` | 覆盖 `zy-app-id`(或环境变量 `ABILITY_CLI_APP_ID`) |
|
|
210
|
+
| `--app-secret <secret>` | 覆盖密钥(或环境变量 `ABILITY_CLI_APP_SECRET`) |
|
|
221
211
|
| `--nonce <nonce>` | 固定 nonce |
|
|
222
212
|
| `--timestamp <ts>` | 固定时间戳 |
|
|
223
213
|
|
|
224
214
|
#### `doctor`
|
|
225
215
|
|
|
226
|
-
|
|
216
|
+
检查配置文件路径、当前环境、解析后的 **`Authorization(sk)`** / **`zy-device-id`** / **`baseUrl`**,并请求 `{baseUrl}/time` 做网关连通性探测。
|
|
227
217
|
|
|
228
218
|
---
|
|
229
219
|
|
|
@@ -233,39 +223,39 @@ GET 全量分类。
|
|
|
233
223
|
|
|
234
224
|
默认路径:**`~/.ability-cli/config.json`**。
|
|
235
225
|
|
|
236
|
-
首次运行若文件不存在,会使用内置默认:当前环境
|
|
226
|
+
首次运行若文件不存在,会使用内置默认:当前环境 **`prod`**,`test` / `prod` 各有一套 `baseUrl`;`profiles.*.authToken`(sk)、`defaults.deviceId` 等为空字符串。
|
|
237
227
|
|
|
238
|
-
通过 `ability-cli config set` 写入后,会按 `env` 更新对应 `profiles[env]` 下的 `baseUrl`、`
|
|
228
|
+
通过 `ability-cli config set` 写入后,会按 `env` 更新对应 `profiles[env]` 下的 `baseUrl`、`authToken`(sk)等;`defaults` 下可保存默认设备 ID 等。
|
|
239
229
|
|
|
240
230
|
### 环境变量
|
|
241
231
|
|
|
242
232
|
| 变量 | 作用 |
|
|
243
233
|
|------|------|
|
|
244
234
|
| `ABILITY_CLI_ENV` | 选用 `profiles` 的环境键(如 `test` / `prod`) |
|
|
245
|
-
| `
|
|
246
|
-
| `
|
|
247
|
-
| `
|
|
248
|
-
| `
|
|
235
|
+
| `ABILITY_CLI_AUTH_TOKEN` | 授权密钥 `sk-…`,对应请求头 `Authorization` |
|
|
236
|
+
| `ABILITY_CLI_DEVICE_ID` | 设备 ID,对应请求头 `zy-device-id`,并参与部分 query |
|
|
237
|
+
| `ABILITY_CLI_BASE_URL` | 网关根地址 |
|
|
238
|
+
| `ABILITY_CLI_APP_ID` | 仅用于 `sign debug`(网关 zy-sign 调试) |
|
|
239
|
+
| `ABILITY_CLI_APP_SECRET` | 仅用于 `sign debug`(网关 zy-sign 调试) |
|
|
249
240
|
|
|
250
241
|
### 优先级
|
|
251
242
|
|
|
252
|
-
对
|
|
243
|
+
对 **`authToken` / `deviceId` / `baseUrl`**:**子命令参数 > 全局参数 > 对应环境变量 > 配置文件**(子命令与全局选项先做对象合并,后者覆盖前者)。
|
|
253
244
|
|
|
254
245
|
当前激活的 **profile(test 或 prod)** 由 **`ABILITY_CLI_ENV`(若设置)** 与配置文件中的 **`env`** 字段共同决定(环境变量优先)。
|
|
255
246
|
|
|
256
247
|
---
|
|
257
248
|
|
|
258
|
-
## 6.
|
|
249
|
+
## 6. 鉴权说明(Agent API)
|
|
259
250
|
|
|
260
|
-
|
|
251
|
+
调用 **`/ability-service/api/agent/v1/**`** 时,CLI 仅发送:
|
|
261
252
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
2. 以 **`appSecret` 作为 HMAC 密钥**,对原串做 UTF-8 编码后的 HMAC-SHA256,结果取 **hex** 字符串,作为 `zy-sign`。
|
|
253
|
+
- `Authorization`:`sk-…`(由 `--auth-token` / `ABILITY_CLI_AUTH_TOKEN` / 配置文件 `authToken` 解析)
|
|
254
|
+
- `zy-device-id`:设备 ID(由 `--device-id` / `ABILITY_CLI_DEVICE_ID` / `defaults.deviceId` 解析)
|
|
265
255
|
|
|
266
|
-
|
|
256
|
+
**不发送**网关侧的 `zy-app-id`、`zy-nonce`、`zy-timestamp`、`zy-sign`。
|
|
267
257
|
|
|
268
|
-
|
|
258
|
+
如需调试历史网关 **HMAC 签名字段**,可使用 `ability-cli sign debug`(凭据为命令行 `--app-id` / `--app-secret` 或环境变量 `ABILITY_CLI_APP_ID` / `ABILITY_CLI_APP_SECRET`,与 Agent API 请求无关)。
|
|
269
259
|
|
|
270
260
|
---
|
|
271
261
|
|
|
@@ -284,7 +274,7 @@ GET 全量分类。
|
|
|
284
274
|
| 0 | 成功 |
|
|
285
275
|
| 1 | 参数错误或未捕获的运行时错误 |
|
|
286
276
|
| 2 | 网络错误(如连接被拒绝、DNS 失败等) |
|
|
287
|
-
| 3 |
|
|
277
|
+
| 3 | 认证失败(保留码位;Agent API 常见错误见服务端 `code`) |
|
|
288
278
|
| 4 | 业务错误(接口返回 `code !== 200`) |
|
|
289
279
|
|
|
290
280
|
---
|
package/dist/index.js
CHANGED
|
@@ -15,22 +15,16 @@ var DEFAULT_CONFIG = {
|
|
|
15
15
|
profiles: {
|
|
16
16
|
test: {
|
|
17
17
|
baseUrl: "https://biz-gw.zyqltest.com",
|
|
18
|
-
zyAppId: "",
|
|
19
|
-
appSecret: "",
|
|
20
18
|
authToken: ""
|
|
21
19
|
},
|
|
22
20
|
prod: {
|
|
23
21
|
baseUrl: "https://biz-gw.zyql.com",
|
|
24
|
-
zyAppId: "",
|
|
25
|
-
appSecret: "",
|
|
26
22
|
authToken: ""
|
|
27
23
|
}
|
|
28
24
|
},
|
|
29
25
|
defaults: {
|
|
30
26
|
deviceId: "",
|
|
31
|
-
|
|
32
|
-
osVersion: "",
|
|
33
|
-
timeout: 30
|
|
27
|
+
timeout: 3e4
|
|
34
28
|
}
|
|
35
29
|
};
|
|
36
30
|
function getDefaultConfigPath() {
|
|
@@ -101,7 +95,7 @@ function printAbilityDetail(a) {
|
|
|
101
95
|
console.log(` ${chalk.gray("\u5E94\u7528:")} ${a.appName} (${a.packageName})`);
|
|
102
96
|
console.log(` ${chalk.gray("\u63CF\u8FF0:")} ${a.description}`);
|
|
103
97
|
console.log(` ${chalk.gray("\u8C03\u7528\u65B9\u5F0F:")} ${a.callingMethod}`);
|
|
104
|
-
console.log(` ${chalk.gray("\u8D85\u65F6:")} ${a.timeout}
|
|
98
|
+
console.log(` ${chalk.gray("\u8D85\u65F6:")} ${a.timeout ?? ""} \u6BEB\u79D2`);
|
|
105
99
|
console.log(` ${chalk.gray("\u6743\u9650:")} ${a.permission}`);
|
|
106
100
|
console.log(` ${chalk.gray("\u8BBE\u5907\u7C7B\u578B:")} ${a.deviceType}`);
|
|
107
101
|
if (a.inputSchema) {
|
|
@@ -127,24 +121,36 @@ function handleApiResponse(res, jsonMode, formatter) {
|
|
|
127
121
|
}
|
|
128
122
|
|
|
129
123
|
// src/commands/config.ts
|
|
124
|
+
function mergeConfigSetOpts(program2, opts) {
|
|
125
|
+
const g = program2.opts();
|
|
126
|
+
return {
|
|
127
|
+
...g,
|
|
128
|
+
...opts,
|
|
129
|
+
env: opts.env ?? g.env,
|
|
130
|
+
authToken: opts.authToken ?? g.authToken,
|
|
131
|
+
baseUrl: opts.baseUrl ?? g.baseUrl,
|
|
132
|
+
deviceId: opts.deviceId ?? g.deviceId,
|
|
133
|
+
timeout: opts.timeout
|
|
134
|
+
};
|
|
135
|
+
}
|
|
130
136
|
function registerConfigCommand(program2) {
|
|
131
137
|
const cfg = program2.command("config").description("\u7BA1\u7406 CLI \u914D\u7F6E");
|
|
132
|
-
cfg.command("set").description("\u8BBE\u7F6E\u914D\u7F6E\u9879").option("--env <env>", "\u73AF\u5883 (test/prod)").option("--
|
|
138
|
+
cfg.command("set").description("\u8BBE\u7F6E\u914D\u7F6E\u9879").option("--env <env>", "\u73AF\u5883 (test/prod)").option("--auth-token <token>", "Authorization token\uFF08sk\uFF09").option("--base-url <url>", "\u7F51\u5173\u5730\u5740").option("--device-id <id>", "\u9ED8\u8BA4\u8BBE\u5907ID").option("--timeout <ms>", "\u9ED8\u8BA4\u8C03\u7528\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09\uFF0C\u5199\u5165 defaults.timeout").action((opts) => {
|
|
139
|
+
const m = mergeConfigSetOpts(program2, opts);
|
|
133
140
|
const configPath = getDefaultConfigPath();
|
|
134
141
|
const config = loadConfig(configPath);
|
|
135
|
-
const env =
|
|
142
|
+
const env = m.env ?? config.env;
|
|
136
143
|
config.env = env;
|
|
137
144
|
if (!config.profiles[env]) {
|
|
138
|
-
config.profiles[env] = { baseUrl: "",
|
|
145
|
+
config.profiles[env] = { baseUrl: "", authToken: "" };
|
|
139
146
|
}
|
|
140
147
|
const p = config.profiles[env];
|
|
141
|
-
if (
|
|
142
|
-
if (
|
|
143
|
-
if (
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (opts.osVersion) config.defaults.osVersion = opts.osVersion;
|
|
148
|
+
if (m.authToken) p.authToken = m.authToken;
|
|
149
|
+
if (m.baseUrl) p.baseUrl = m.baseUrl;
|
|
150
|
+
if (m.deviceId) config.defaults.deviceId = m.deviceId;
|
|
151
|
+
if (m.timeout !== void 0 && String(m.timeout).trim() !== "") {
|
|
152
|
+
config.defaults.timeout = Number(m.timeout);
|
|
153
|
+
}
|
|
148
154
|
saveConfig(configPath, config);
|
|
149
155
|
printSuccess(`\u914D\u7F6E\u5DF2\u4FDD\u5B58\u5230 ${configPath}`);
|
|
150
156
|
});
|
|
@@ -155,38 +161,38 @@ function registerConfigCommand(program2) {
|
|
|
155
161
|
}
|
|
156
162
|
|
|
157
163
|
// src/context.ts
|
|
158
|
-
function
|
|
164
|
+
function firstNonEmpty(...vals) {
|
|
165
|
+
for (const v of vals) {
|
|
166
|
+
if (v !== void 0 && v !== null && String(v).trim() !== "") return String(v).trim();
|
|
167
|
+
}
|
|
168
|
+
return "";
|
|
169
|
+
}
|
|
170
|
+
function buildAgentRequestContext(merged) {
|
|
159
171
|
const config = loadConfig();
|
|
160
|
-
if (
|
|
172
|
+
if (merged.env) config.env = merged.env;
|
|
161
173
|
const profile = getActiveProfile(config);
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
return createHmac("sha256", secret).update(message, "utf8").digest("hex");
|
|
180
|
-
}
|
|
181
|
-
function buildSignHeaders(appId, appSecret, opts = {}) {
|
|
182
|
-
const nonce = opts.nonce ?? randomBytes(8).toString("hex");
|
|
183
|
-
const timestamp = opts.timestamp ?? Date.now().toString();
|
|
184
|
-
const zySign = opts.magicSign ? "123456" : sign(`${appId}${nonce}${timestamp}${appSecret}`, appSecret);
|
|
174
|
+
const defaults = config.defaults;
|
|
175
|
+
const authToken = firstNonEmpty(
|
|
176
|
+
merged.authToken,
|
|
177
|
+
process.env.ABILITY_CLI_AUTH_TOKEN,
|
|
178
|
+
profile.authToken
|
|
179
|
+
);
|
|
180
|
+
const deviceId = firstNonEmpty(
|
|
181
|
+
merged.deviceId,
|
|
182
|
+
process.env.ABILITY_CLI_DEVICE_ID,
|
|
183
|
+
defaults.deviceId
|
|
184
|
+
);
|
|
185
|
+
const baseUrl = resolveOption(
|
|
186
|
+
merged.baseUrl,
|
|
187
|
+
process.env.ABILITY_CLI_BASE_URL,
|
|
188
|
+
profile.baseUrl,
|
|
189
|
+
"https://biz-gw.zyql.com"
|
|
190
|
+
);
|
|
185
191
|
return {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
192
|
+
baseUrl,
|
|
193
|
+
authToken,
|
|
194
|
+
deviceId,
|
|
195
|
+
verbose: merged.verbose
|
|
190
196
|
};
|
|
191
197
|
}
|
|
192
198
|
|
|
@@ -200,15 +206,23 @@ function buildUrl(base, path2, params) {
|
|
|
200
206
|
}
|
|
201
207
|
return url.toString();
|
|
202
208
|
}
|
|
203
|
-
function
|
|
204
|
-
const
|
|
205
|
-
|
|
209
|
+
function normalizeAuthorization(token) {
|
|
210
|
+
const t = token.trim();
|
|
211
|
+
return t;
|
|
212
|
+
}
|
|
213
|
+
function buildAgentHeaders(authToken, deviceId) {
|
|
214
|
+
const headers = {};
|
|
215
|
+
if (authToken) {
|
|
216
|
+
headers["Authorization"] = normalizeAuthorization(authToken);
|
|
217
|
+
}
|
|
218
|
+
if (deviceId) {
|
|
219
|
+
headers["zy-device-id"] = deviceId;
|
|
220
|
+
}
|
|
206
221
|
return headers;
|
|
207
222
|
}
|
|
208
223
|
async function apiGet(ctx, path2, params) {
|
|
209
|
-
const
|
|
210
|
-
const
|
|
211
|
-
const url = buildUrl(ctx.profile.baseUrl, path2, params);
|
|
224
|
+
const headers = buildAgentHeaders(ctx.authToken, ctx.deviceId);
|
|
225
|
+
const url = buildUrl(ctx.baseUrl, path2, params);
|
|
212
226
|
if (ctx.verbose) {
|
|
213
227
|
console.error(`[verbose] GET ${url}`);
|
|
214
228
|
console.error(`[verbose] Headers: ${JSON.stringify(headers, null, 2)}`);
|
|
@@ -219,10 +233,9 @@ async function apiGet(ctx, path2, params) {
|
|
|
219
233
|
return body;
|
|
220
234
|
}
|
|
221
235
|
async function apiPost(ctx, path2, data) {
|
|
222
|
-
const
|
|
223
|
-
const headers = buildRequestHeaders(signHeaders, ctx.profile.authToken);
|
|
236
|
+
const headers = buildAgentHeaders(ctx.authToken, ctx.deviceId);
|
|
224
237
|
headers["Content-Type"] = "application/json";
|
|
225
|
-
const url = buildUrl(ctx.
|
|
238
|
+
const url = buildUrl(ctx.baseUrl, path2);
|
|
226
239
|
if (ctx.verbose) {
|
|
227
240
|
console.error(`[verbose] POST ${url}`);
|
|
228
241
|
console.error(`[verbose] Headers: ${JSON.stringify(headers, null, 2)}`);
|
|
@@ -240,53 +253,65 @@ async function apiPost(ctx, path2, data) {
|
|
|
240
253
|
|
|
241
254
|
// src/commands/raw.ts
|
|
242
255
|
import fs2 from "fs";
|
|
256
|
+
|
|
257
|
+
// src/agent-paths.ts
|
|
258
|
+
var AGENT_API_PREFIX = "/ability-service/api/agent/v1";
|
|
259
|
+
var agentPath = {
|
|
260
|
+
abilityList: `${AGENT_API_PREFIX}/ability/list`,
|
|
261
|
+
abilityCategory: `${AGENT_API_PREFIX}/ability/category`,
|
|
262
|
+
appInfo: `${AGENT_API_PREFIX}/ability/appInfo`,
|
|
263
|
+
abilityInfo: `${AGENT_API_PREFIX}/ability/abilityInfo`,
|
|
264
|
+
abilityCall: `${AGENT_API_PREFIX}/ability/call`
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// src/commands/raw.ts
|
|
243
268
|
function registerRawCommand(program2) {
|
|
244
269
|
const raw = program2.command("raw").description("\u539F\u59CB\u63A5\u53E3\u76F4\u901A\uFF08\u8054\u8C03/\u6392\u969C\uFF09");
|
|
245
270
|
raw.command("ability-list").description("GET \u80FD\u529B\u5217\u8868").option("--device-id <id>", "\u8BBE\u5907ID").option("--app-name <name>", "\u5E94\u7528\u540D\u79F0").option("--category <category>", "\u4E09\u7EA7\u5206\u7C7B").option("--natural-lang <text>", "\u81EA\u7136\u8BED\u8A00\u7B5B\u9009").option("--json", "JSON \u8F93\u51FA").action(async (opts) => {
|
|
246
|
-
const
|
|
271
|
+
const merged = { ...program2.opts(), ...opts };
|
|
272
|
+
const ctx = buildAgentRequestContext(merged);
|
|
247
273
|
const params = {};
|
|
248
|
-
if (
|
|
274
|
+
if (ctx.deviceId) params.deviceId = ctx.deviceId;
|
|
249
275
|
if (opts.appName) params.appName = opts.appName;
|
|
250
276
|
if (opts.category) params.category = opts.category;
|
|
251
277
|
if (opts.naturalLang) params.naturalLang = opts.naturalLang;
|
|
252
|
-
const res = await apiGet(ctx,
|
|
278
|
+
const res = await apiGet(ctx, agentPath.abilityList, params);
|
|
253
279
|
handleApiResponse(res, opts.json, (data) => printAbilityTable(data));
|
|
254
280
|
});
|
|
255
|
-
raw.command("
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const ctx = buildContext(program2.opts());
|
|
263
|
-
const res = await apiGet(ctx, "/ability-service/api/v1/ability/appInfo", { packageName: opts.packageName });
|
|
281
|
+
raw.command("app-info").description("GET \u5E94\u7528\u4FE1\u606F").addHelpText(
|
|
282
|
+
"after",
|
|
283
|
+
"\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"
|
|
284
|
+
).requiredOption("--package-name <pkg>", "\u3010\u5FC5\u586B\u3011\u5E94\u7528\u5305\u540D").option("--json", "JSON \u8F93\u51FA").action(async (opts) => {
|
|
285
|
+
const merged = { ...program2.opts(), ...opts };
|
|
286
|
+
const ctx = buildAgentRequestContext(merged);
|
|
287
|
+
const res = await apiGet(ctx, agentPath.appInfo, { packageName: opts.packageName });
|
|
264
288
|
handleApiResponse(res, opts.json, (data) => printJson(data));
|
|
265
289
|
});
|
|
266
|
-
raw.command("ability-info").description("GET \u80FD\u529B\u8BE6\u60C5").
|
|
267
|
-
|
|
268
|
-
|
|
290
|
+
raw.command("ability-info").description("GET \u80FD\u529B\u8BE6\u60C5").addHelpText(
|
|
291
|
+
"after",
|
|
292
|
+
"\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"
|
|
293
|
+
).requiredOption("--ability-id <id>", "\u3010\u5FC5\u586B\u3011\u80FD\u529B ID").option("--device-id <id>", "\u8BBE\u5907 ID\uFF1B\u7AEF\u4FA7\u80FD\u529B\u5EFA\u8BAE\u586B\u5199").option("--json", "JSON \u8F93\u51FA").action(async (opts) => {
|
|
294
|
+
const merged = { ...program2.opts(), ...opts };
|
|
295
|
+
const ctx = buildAgentRequestContext(merged);
|
|
269
296
|
const params = { abilityId: opts.abilityId };
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const res = await apiGet(ctx, "/ability-service/api/v1/ability/abilityInfo", params);
|
|
297
|
+
if (ctx.deviceId) params.deviceId = ctx.deviceId;
|
|
298
|
+
const res = await apiGet(ctx, agentPath.abilityInfo, params);
|
|
273
299
|
handleApiResponse(res, opts.json, (data) => printJson(data));
|
|
274
300
|
});
|
|
275
|
-
raw.command("call
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
raw.command("ability-callback").description("POST \u4E0A\u62A5\u80FD\u529B\u6267\u884C\u7ED3\u679C").requiredOption("--file <path>", "JSON \u6587\u4EF6\u8DEF\u5F84\uFF0C\u9700\u5305\u542B requestId\uFF0Cbody \u53EF\u9009").option("--json", "JSON \u8F93\u51FA").action(async (opts) => {
|
|
282
|
-
const ctx = buildContext(program2.opts());
|
|
301
|
+
raw.command("call").description("POST \u6267\u884C\u80FD\u529B\uFF08Agent API\uFF09").addHelpText(
|
|
302
|
+
"after",
|
|
303
|
+
"\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"
|
|
304
|
+
).requiredOption("--file <path>", "\u3010\u5FC5\u586B\u3011\u8BF7\u6C42\u4F53 JSON \u6587\u4EF6\u8DEF\u5F84").option("--json", "JSON \u8F93\u51FA").action(async (opts) => {
|
|
305
|
+
const merged = { ...program2.opts(), ...opts };
|
|
306
|
+
const ctx = buildAgentRequestContext(merged);
|
|
283
307
|
const data = JSON.parse(fs2.readFileSync(opts.file, "utf-8"));
|
|
284
|
-
const res = await apiPost(ctx,
|
|
308
|
+
const res = await apiPost(ctx, agentPath.abilityCall, data);
|
|
285
309
|
handleApiResponse(res, opts.json, (data2) => printJson(data2));
|
|
286
310
|
});
|
|
287
311
|
raw.command("category-list").description("GET \u5168\u91CF\u5206\u7C7B").option("--json", "JSON \u8F93\u51FA").action(async (opts) => {
|
|
288
|
-
const
|
|
289
|
-
const
|
|
312
|
+
const merged = { ...program2.opts(), ...opts };
|
|
313
|
+
const ctx = buildAgentRequestContext(merged);
|
|
314
|
+
const res = await apiGet(ctx, agentPath.abilityCategory);
|
|
290
315
|
handleApiResponse(res, opts.json, (data) => printJson(data));
|
|
291
316
|
});
|
|
292
317
|
}
|
|
@@ -294,16 +319,15 @@ function registerRawCommand(program2) {
|
|
|
294
319
|
// src/commands/search.ts
|
|
295
320
|
function registerSearchCommand(program2) {
|
|
296
321
|
program2.command("search [query]").description("\u641C\u7D22\u80FD\u529B\uFF08\u652F\u6301\u81EA\u7136\u8BED\u8A00\uFF09").option("--device-id <id>", "\u8BBE\u5907ID").option("--app-name <name>", "\u5E94\u7528\u540D\u79F0").option("--category <category>", "\u4E09\u7EA7\u5206\u7C7B").option("--natural-lang <text>", "\u81EA\u7136\u8BED\u8A00\uFF08\u4F18\u5148\u4E8E query\uFF09").option("--json", "JSON \u8F93\u51FA").action(async (query, opts) => {
|
|
297
|
-
const
|
|
298
|
-
const
|
|
322
|
+
const merged = { ...program2.opts(), ...opts };
|
|
323
|
+
const ctx = buildAgentRequestContext(merged);
|
|
299
324
|
const params = {};
|
|
300
|
-
|
|
301
|
-
if (deviceId) params.deviceId = deviceId;
|
|
325
|
+
if (ctx.deviceId) params.deviceId = ctx.deviceId;
|
|
302
326
|
const naturalLang = opts.naturalLang ?? query;
|
|
303
327
|
if (naturalLang) params.naturalLang = naturalLang;
|
|
304
328
|
if (opts.appName) params.appName = opts.appName;
|
|
305
329
|
if (opts.category) params.category = opts.category;
|
|
306
|
-
const res = await apiGet(ctx,
|
|
330
|
+
const res = await apiGet(ctx, agentPath.abilityList, params);
|
|
307
331
|
handleApiResponse(res, opts.json, (data) => {
|
|
308
332
|
const list = Array.isArray(data) ? data : [];
|
|
309
333
|
if (list.length === 0) {
|
|
@@ -343,13 +367,15 @@ function generateTemplate(schema) {
|
|
|
343
367
|
return result;
|
|
344
368
|
}
|
|
345
369
|
function registerInspectCommand(program2) {
|
|
346
|
-
program2.command("inspect").description("\u67E5\u770B\u80FD\u529B\u8BE6\u60C5\u4E0E inputSchema").
|
|
347
|
-
|
|
348
|
-
|
|
370
|
+
program2.command("inspect").description("\u67E5\u770B\u80FD\u529B\u8BE6\u60C5\u4E0E inputSchema").addHelpText(
|
|
371
|
+
"after",
|
|
372
|
+
"\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"
|
|
373
|
+
).requiredOption("--ability-id <id>", "\u3010\u5FC5\u586B\u3011\u80FD\u529B ID").option("--device-id <id>", "\u8BBE\u5907 ID\uFF1B\u7AEF\u4FA7\u80FD\u529B\u5EFA\u8BAE\u586B\u5199").option("--gen-template", "\u751F\u6210\u53C2\u6570\u6A21\u677F JSON").option("--json", "JSON \u8F93\u51FA").action(async (opts) => {
|
|
374
|
+
const merged = { ...program2.opts(), ...opts };
|
|
375
|
+
const ctx = buildAgentRequestContext(merged);
|
|
349
376
|
const params = { abilityId: opts.abilityId };
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const res = await apiGet(ctx, "/ability-service/api/v1/ability/abilityInfo", params);
|
|
377
|
+
if (ctx.deviceId) params.deviceId = ctx.deviceId;
|
|
378
|
+
const res = await apiGet(ctx, agentPath.abilityInfo, params);
|
|
353
379
|
handleApiResponse(res, opts.json, (data) => {
|
|
354
380
|
if (opts.genTemplate && data.inputSchema) {
|
|
355
381
|
printJson(generateTemplate(data.inputSchema));
|
|
@@ -363,16 +389,44 @@ function registerInspectCommand(program2) {
|
|
|
363
389
|
// src/commands/exec.ts
|
|
364
390
|
import { randomUUID } from "crypto";
|
|
365
391
|
import fs3 from "fs";
|
|
392
|
+
|
|
393
|
+
// src/parse-cli-json.ts
|
|
394
|
+
function parseCliJsonString(raw, label) {
|
|
395
|
+
const s = raw.replace(/^\uFEFF/, "").trim();
|
|
396
|
+
if (!s) return {};
|
|
397
|
+
try {
|
|
398
|
+
return JSON.parse(s);
|
|
399
|
+
} catch (e) {
|
|
400
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
401
|
+
let hint = "";
|
|
402
|
+
if (/^\s*\{\s*'/.test(s)) {
|
|
403
|
+
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";
|
|
404
|
+
} else if (/[\u201c\u201d\u2018\u2019]/.test(s)) {
|
|
405
|
+
hint = ' \u68C0\u6D4B\u5230\u5F2F\u5F15\u53F7\uFF08\u201C \u201D \u2018 \u2019\uFF09\u3002\u8BF7\u6539\u4E3A ASCII \u53CC\u5F15\u53F7 " \u3002';
|
|
406
|
+
}
|
|
407
|
+
const preview = s.length > 160 ? `${s.slice(0, 160)}\u2026` : s;
|
|
408
|
+
throw new Error(`${label} \u89E3\u6790\u5931\u8D25\uFF1A${msg}.${hint}
|
|
409
|
+
\u5B9E\u9645\u6536\u5230\u7684\u5F00\u5934\uFF1A${JSON.stringify(preview.slice(0, 80))}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// src/commands/exec.ts
|
|
366
414
|
function registerExecCommand(program2) {
|
|
367
|
-
program2.command("exec").description("\u6267\u884C\u80FD\u529B").
|
|
368
|
-
|
|
369
|
-
|
|
415
|
+
program2.command("exec").description("\u6267\u884C\u80FD\u529B").addHelpText(
|
|
416
|
+
"after",
|
|
417
|
+
"\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"
|
|
418
|
+
).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) => {
|
|
419
|
+
const merged = { ...program2.opts(), ...opts };
|
|
420
|
+
const ctx = buildAgentRequestContext(merged);
|
|
421
|
+
const cliCfg = loadConfig();
|
|
422
|
+
const timeoutMillis = opts.timeout !== void 0 && String(opts.timeout).trim() !== "" ? Number(opts.timeout) : cliCfg.defaults.timeout ?? 3e4;
|
|
370
423
|
let params = {};
|
|
371
424
|
if (opts.params) {
|
|
372
425
|
if (fs3.existsSync(opts.params)) {
|
|
373
|
-
|
|
426
|
+
const text = fs3.readFileSync(opts.params, "utf-8");
|
|
427
|
+
params = parseCliJsonString(text, "\u53C2\u6570\u6587\u4EF6");
|
|
374
428
|
} else {
|
|
375
|
-
params =
|
|
429
|
+
params = parseCliJsonString(opts.params, "--params");
|
|
376
430
|
}
|
|
377
431
|
}
|
|
378
432
|
const body = {
|
|
@@ -382,11 +436,13 @@ function registerExecCommand(program2) {
|
|
|
382
436
|
toolCallId: opts.toolCallId ?? "",
|
|
383
437
|
taskId: opts.taskId ?? "",
|
|
384
438
|
messageId: opts.messageId ?? "",
|
|
385
|
-
deviceId:
|
|
386
|
-
timeoutMillis
|
|
439
|
+
deviceId: ctx.deviceId ?? "",
|
|
440
|
+
timeoutMillis,
|
|
387
441
|
params
|
|
388
442
|
};
|
|
389
|
-
|
|
443
|
+
if (opts.responseType) body.responseType = opts.responseType;
|
|
444
|
+
if (opts.mockToken) body.mockToken = opts.mockToken;
|
|
445
|
+
const res = await apiPost(ctx, agentPath.abilityCall, body);
|
|
390
446
|
handleApiResponse(res, opts.json, (data) => {
|
|
391
447
|
printSuccess("\u80FD\u529B\u6267\u884C\u5B8C\u6210");
|
|
392
448
|
printJson(data);
|
|
@@ -396,18 +452,36 @@ function registerExecCommand(program2) {
|
|
|
396
452
|
|
|
397
453
|
// src/commands/sign.ts
|
|
398
454
|
import chalk2 from "chalk";
|
|
455
|
+
|
|
456
|
+
// src/signer.ts
|
|
457
|
+
import { createHmac, randomBytes } from "crypto";
|
|
458
|
+
function sign(message, secret) {
|
|
459
|
+
return createHmac("sha256", secret).update(message, "utf8").digest("hex");
|
|
460
|
+
}
|
|
461
|
+
function buildSignHeaders(appId, appSecret, opts = {}) {
|
|
462
|
+
const nonce = opts.nonce ?? randomBytes(8).toString("hex");
|
|
463
|
+
const timestamp = opts.timestamp ?? Date.now().toString();
|
|
464
|
+
const zySign = opts.magicSign ? "123456" : sign(`${appId}${nonce}${timestamp}${appSecret}`, appSecret);
|
|
465
|
+
return {
|
|
466
|
+
"zy-app-id": appId,
|
|
467
|
+
"zy-nonce": nonce,
|
|
468
|
+
"zy-timestamp": timestamp,
|
|
469
|
+
"zy-sign": zySign
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/commands/sign.ts
|
|
399
474
|
function registerSignCommand(program2) {
|
|
400
|
-
const signCmd = program2.command("sign").description("\u7B7E\u540D\u5DE5\u5177");
|
|
401
|
-
signCmd.command("debug").description("\u8C03\u8BD5\u7B7E\u540D\uFF08\u6253\u5370\u539F\u4E32\u548C\
|
|
402
|
-
const
|
|
403
|
-
const
|
|
404
|
-
const secret = opts.appSecret ?? ctx.profile.appSecret;
|
|
475
|
+
const signCmd = program2.command("sign").description("\u7B7E\u540D\u5DE5\u5177\uFF08\u7F51\u5173 zy-sign \u8C03\u8BD5\uFF0C\u975E Agent API \u8BF7\u6C42\uFF09");
|
|
476
|
+
signCmd.command("debug").description("\u8C03\u8BD5\u7F51\u5173\u7B7E\u540D\uFF08\u6253\u5370\u539F\u4E32\u548C zy-sign\uFF09\uFF1B\u51ED\u636E\u6765\u81EA\u53C2\u6570\u6216\u73AF\u5883\u53D8\u91CF").option("--app-id <id>", "zy-app-id").option("--app-secret <secret>", "appSecret").option("--nonce <nonce>", "\u6307\u5B9A nonce").option("--timestamp <ts>", "\u6307\u5B9A timestamp").action((opts) => {
|
|
477
|
+
const appId = opts.appId ?? process.env.ABILITY_CLI_APP_ID ?? "";
|
|
478
|
+
const secret = opts.appSecret ?? process.env.ABILITY_CLI_APP_SECRET ?? "";
|
|
405
479
|
const headers = buildSignHeaders(appId, secret, {
|
|
406
480
|
nonce: opts.nonce,
|
|
407
481
|
timestamp: opts.timestamp
|
|
408
482
|
});
|
|
409
483
|
const rawStr = `${appId}${headers["zy-nonce"]}${headers["zy-timestamp"]}${secret}`;
|
|
410
|
-
console.log(chalk2.bold.cyan("\n\u2500\u2500 \u7B7E\u540D\u8C03\u8BD5 \u2500\u2500\n"));
|
|
484
|
+
console.log(chalk2.bold.cyan("\n\u2500\u2500 \u7F51\u5173\u7B7E\u540D\u8C03\u8BD5 \u2500\u2500\n"));
|
|
411
485
|
console.log(` ${chalk2.gray("appId:")} ${appId}`);
|
|
412
486
|
console.log(` ${chalk2.gray("nonce:")} ${headers["zy-nonce"]}`);
|
|
413
487
|
console.log(` ${chalk2.gray("timestamp:")} ${headers["zy-timestamp"]}`);
|
|
@@ -420,16 +494,19 @@ function registerSignCommand(program2) {
|
|
|
420
494
|
import chalk3 from "chalk";
|
|
421
495
|
function registerDoctorCommand(program2) {
|
|
422
496
|
program2.command("doctor").description("\u68C0\u67E5\u914D\u7F6E\u5B8C\u6574\u6027\u548C\u7F51\u5173\u8FDE\u901A\u6027").action(async () => {
|
|
423
|
-
const
|
|
424
|
-
const
|
|
497
|
+
const merged = program2.opts();
|
|
498
|
+
const ctx = buildAgentRequestContext(merged);
|
|
425
499
|
let ok = true;
|
|
426
500
|
console.log(chalk3.bold.cyan("\n\u2500\u2500 CLI \u5065\u5EB7\u68C0\u67E5 \u2500\u2500\n"));
|
|
501
|
+
const configPath = getDefaultConfigPath();
|
|
502
|
+
const config = loadConfig();
|
|
503
|
+
const effectiveEnv = process.env.ABILITY_CLI_ENV ?? merged.env ?? config.env;
|
|
427
504
|
const checks = [
|
|
428
|
-
["\u914D\u7F6E\u6587\u4EF6",
|
|
429
|
-
["\u5F53\u524D\u73AF\u5883",
|
|
430
|
-
["
|
|
431
|
-
["
|
|
432
|
-
["
|
|
505
|
+
["\u914D\u7F6E\u6587\u4EF6", configPath, true],
|
|
506
|
+
["\u5F53\u524D\u73AF\u5883", effectiveEnv, true],
|
|
507
|
+
["baseUrl", ctx.baseUrl || "(\u7A7A)", !!ctx.baseUrl],
|
|
508
|
+
["Authorization(sk)", ctx.authToken ? "******" : "(\u7A7A)", !!ctx.authToken],
|
|
509
|
+
["zy-device-id", ctx.deviceId || "(\u7A7A)", !!ctx.deviceId]
|
|
433
510
|
];
|
|
434
511
|
for (const [label, val, pass] of checks) {
|
|
435
512
|
const icon = pass ? chalk3.green("\u2714") : chalk3.red("\u2716");
|
|
@@ -437,21 +514,16 @@ function registerDoctorCommand(program2) {
|
|
|
437
514
|
if (!pass) ok = false;
|
|
438
515
|
}
|
|
439
516
|
try {
|
|
440
|
-
const res = await fetch(`${
|
|
517
|
+
const res = await fetch(`${ctx.baseUrl}/time`);
|
|
441
518
|
const body = await res.json();
|
|
442
519
|
if (body.code === 200) {
|
|
443
|
-
console.log(` ${chalk3.green("\u2714")} ${chalk3.gray("\u7F51\u5173\u8FDE\u901A:")} ${body.data}`);
|
|
444
|
-
const serverTs = Number(String(body.data).slice(0, -1) + "0");
|
|
445
|
-
const drift = Math.abs(Date.now() - serverTs);
|
|
446
|
-
if (drift > 3e4) {
|
|
447
|
-
console.log(` ${chalk3.yellow("\u26A0")} ${chalk3.gray("\u65F6\u949F\u504F\u5DEE:")} ${drift}ms\uFF08\u5EFA\u8BAE\u4F7F\u7528 --sync-time\uFF09`);
|
|
448
|
-
}
|
|
520
|
+
console.log(` ${chalk3.green("\u2714")} ${chalk3.gray("\u7F51\u5173\u8FDE\u901A(/time):")} ${body.data}`);
|
|
449
521
|
} else {
|
|
450
|
-
console.log(` ${chalk3.red("\u2716")} ${chalk3.gray("\u7F51\u5173\u8FDE\u901A:")} \u8FD4\u56DE code=${body.code}`);
|
|
522
|
+
console.log(` ${chalk3.red("\u2716")} ${chalk3.gray("\u7F51\u5173\u8FDE\u901A(/time):")} \u8FD4\u56DE code=${body.code}`);
|
|
451
523
|
ok = false;
|
|
452
524
|
}
|
|
453
525
|
} catch (e) {
|
|
454
|
-
console.log(` ${chalk3.red("\u2716")} ${chalk3.gray("\u7F51\u5173\u8FDE\u901A:")} ${e.message}`);
|
|
526
|
+
console.log(` ${chalk3.red("\u2716")} ${chalk3.gray("\u7F51\u5173\u8FDE\u901A(/time):")} ${e.message}`);
|
|
455
527
|
ok = false;
|
|
456
528
|
}
|
|
457
529
|
console.log();
|
|
@@ -471,7 +543,7 @@ function readPackageVersion() {
|
|
|
471
543
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
472
544
|
return pkg.version ?? "0.0.0";
|
|
473
545
|
}
|
|
474
|
-
program.name("ability-cli").description("\u539F\u5B50\u80FD\u529B\u5E73\u53F0 CLI \u5DE5\u5177").version(readPackageVersion()).option("--env <env>", "\u73AF\u5883 (test/prod)
|
|
546
|
+
program.name("ability-cli").description("\u539F\u5B50\u80FD\u529B\u5E73\u53F0 CLI \u5DE5\u5177").version(readPackageVersion()).option("--env <env>", "\u73AF\u5883 (test/prod)\uFF0C\u9009\u62E9 profiles \u4E2D\u54EA\u5957 baseUrl").option("--auth-token <token>", "Authorization\uFF08sk-\u2026\uFF09\uFF0C\u8986\u76D6\u73AF\u5883\u53D8\u91CF\u4E0E\u914D\u7F6E").option("--base-url <url>", "\u7F51\u5173\u6839\u5730\u5740\uFF0C\u8986\u76D6\u73AF\u5883\u53D8\u91CF\u4E0E\u914D\u7F6E").option("--device-id <id>", "\u8BBE\u5907 ID\uFF08zy-device-id \u8BF7\u6C42\u5934 / \u90E8\u5206 query\uFF09\uFF0C\u8986\u76D6\u73AF\u5883\u53D8\u91CF\u4E0E\u914D\u7F6E").option("-v, --verbose", "\u8BE6\u7EC6\u8F93\u51FA");
|
|
475
547
|
registerConfigCommand(program);
|
|
476
548
|
registerRawCommand(program);
|
|
477
549
|
registerSearchCommand(program);
|
package/package.json
CHANGED
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "ability-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "原子能力平台 CLI 工具",
|
|
5
|
-
"repository": {
|
|
6
|
-
"type": "git",
|
|
7
|
-
"url": "<repo-url>"
|
|
8
|
-
},
|
|
9
|
-
"homepage": "<repo-url>",
|
|
10
|
-
"bugs": {
|
|
11
|
-
"url": "<repo-url>/issues"
|
|
12
|
-
},
|
|
13
|
-
"type": "module",
|
|
14
|
-
"bin": {
|
|
15
|
-
"ability-cli": "./dist/index.js"
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"dist",
|
|
19
|
-
"README.md",
|
|
20
|
-
"LICENSE"
|
|
21
|
-
],
|
|
22
|
-
"scripts": {
|
|
23
|
-
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
24
|
-
"dev": "tsup src/index.ts --format esm --watch",
|
|
25
|
-
"test": "vitest run",
|
|
26
|
-
"test:watch": "vitest",
|
|
27
|
-
"prepublishOnly": "npm run build && npm test"
|
|
28
|
-
},
|
|
29
|
-
"keywords": [
|
|
30
|
-
"ability",
|
|
31
|
-
"cli",
|
|
32
|
-
"atomic-ability",
|
|
33
|
-
"mcp",
|
|
34
|
-
"zyql"
|
|
35
|
-
],
|
|
36
|
-
"author": "",
|
|
37
|
-
"license": "ISC",
|
|
38
|
-
"packageManager": "pnpm@10.28.2",
|
|
39
|
-
"dependencies": {
|
|
40
|
-
"chalk": "^5.6.2",
|
|
41
|
-
"cli-table3": "^0.6.5",
|
|
42
|
-
"commander": "^14.0.3"
|
|
43
|
-
},
|
|
44
|
-
"pnpm": {
|
|
45
|
-
"onlyBuiltDependencies": ["esbuild"]
|
|
46
|
-
},
|
|
47
|
-
"devDependencies": {
|
|
48
|
-
"@types/node": "^25.5.2",
|
|
49
|
-
"tsup": "^8.5.1",
|
|
50
|
-
"typescript": "^6.0.2",
|
|
51
|
-
"vitest": "^4.1.3"
|
|
52
|
-
}
|
|
53
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "ability-cli",
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "原子能力平台 CLI 工具",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "<repo-url>"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "<repo-url>",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "<repo-url>/issues"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"bin": {
|
|
15
|
+
"ability-cli": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
24
|
+
"dev": "tsup src/index.ts --format esm --watch",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:watch": "vitest",
|
|
27
|
+
"prepublishOnly": "npm run build && npm test"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"ability",
|
|
31
|
+
"cli",
|
|
32
|
+
"atomic-ability",
|
|
33
|
+
"mcp",
|
|
34
|
+
"zyql"
|
|
35
|
+
],
|
|
36
|
+
"author": "",
|
|
37
|
+
"license": "ISC",
|
|
38
|
+
"packageManager": "pnpm@10.28.2",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"chalk": "^5.6.2",
|
|
41
|
+
"cli-table3": "^0.6.5",
|
|
42
|
+
"commander": "^14.0.3"
|
|
43
|
+
},
|
|
44
|
+
"pnpm": {
|
|
45
|
+
"onlyBuiltDependencies": ["esbuild"]
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^25.5.2",
|
|
49
|
+
"tsup": "^8.5.1",
|
|
50
|
+
"typescript": "^6.0.2",
|
|
51
|
+
"vitest": "^4.1.3"
|
|
52
|
+
}
|
|
53
|
+
}
|