@yizhuan-cli/cli 0.1.12 → 0.1.14-beta.0
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 +2 -2
- package/package.json +1 -1
- package/resources/yizhuan-cli/SKILL.md +2 -0
- package/resources/yizhuan-cli/manifest.json +3 -3
- package/src/doctor.js +2 -2
- package/src/index.js +77 -24
package/README.md
CHANGED
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
需要 Node.js 22 或更高版本。
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npm install -g @yizhuan-cli/cli@0.1.
|
|
10
|
+
npm install -g @yizhuan-cli/cli@0.1.13
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
如果发布在私有 npm registry,请加上对应 registry:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npm install -g @yizhuan-cli/cli@0.1.
|
|
16
|
+
npm install -g @yizhuan-cli/cli@0.1.13 --registry=https://your-private-registry.example
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
## 配置
|
package/package.json
CHANGED
|
@@ -45,6 +45,8 @@ yizhuan doctor
|
|
|
45
45
|
| 作者查询 | `yizhuan execute --ability accounts --query "张三"` |
|
|
46
46
|
| 作者指标筛选 | `yizhuan execute --ability author_query --params '{"platform_id":2,"min_follower":500000,"min_total_likes":100000}'` |
|
|
47
47
|
| 作者全网搜索 | `yizhuan query --json '{"intent":"author_search","scope":"public","platform":"douyin","keyword":"张三"}'` |
|
|
48
|
+
| 微信公众号作者 | `yizhuan execute --ability accounts --params '{"mode":"public_search","platform":"wechat","keyword":"科技"}'` |
|
|
49
|
+
| 微信公众号作品 | `yizhuan execute --ability works --params '{"mode":"search","platform":"wechat","platform_id":9,"keyword":"人工智能"}'` |
|
|
48
50
|
| 热点 | `yizhuan query --json '{"intent":"hot_topics","scope":"platform","platform":"douyin","timeRange":"today"}'` |
|
|
49
51
|
| 我的关注 | `yizhuan execute --ability radar --params '{"mode":"following"}'` |
|
|
50
52
|
| 竞品动态 | `yizhuan execute --ability radar --mode timeline --timeRange 7d` |
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"name": "yizhuan-cli",
|
|
4
|
-
"version": "0.1.
|
|
5
|
-
"compatibleCliVersion": "0.1.
|
|
6
|
-
"source": "npm:@yizhuan-cli/cli@0.1.
|
|
4
|
+
"version": "0.1.14-beta.0",
|
|
5
|
+
"compatibleCliVersion": "0.1.14-beta.0",
|
|
6
|
+
"source": "npm:@yizhuan-cli/cli@0.1.14-beta.0",
|
|
7
7
|
"digestAlgorithm": "sha256",
|
|
8
8
|
"files": [
|
|
9
9
|
{
|
package/src/doctor.js
CHANGED
|
@@ -53,9 +53,9 @@ export function inspectLocalEnvironment(
|
|
|
53
53
|
? check('pass', 'node', `Node.js ${nodeVersion} 满足 >=${minimumNode}`)
|
|
54
54
|
: check('fail', 'node', `Node.js ${nodeVersion} 不满足 ${packageJson.engines?.node || '版本要求'}`, `安装 Node.js ${minimumNode || 22} 或更高版本。`))
|
|
55
55
|
|
|
56
|
-
checks.push(packageJson.version === '0.1.
|
|
56
|
+
checks.push(packageJson.version === '0.1.13'
|
|
57
57
|
? check('pass', 'cli_version', `CLI ${packageJson.version}`)
|
|
58
|
-
: check('fail', 'cli_version', `CLI 版本为 ${packageJson.version},预期 0.1.
|
|
58
|
+
: check('fail', 'cli_version', `CLI 版本为 ${packageJson.version},预期 0.1.13`, '安装 @yizhuan-cli/cli@0.1.13。'))
|
|
59
59
|
|
|
60
60
|
if (!exists(configPath)) {
|
|
61
61
|
checks.push(check('fail', 'config', `配置不存在:${configPath}`, '运行 yizhuan config init。'))
|
package/src/index.js
CHANGED
|
@@ -17,6 +17,7 @@ const ABILITIES = new Set([
|
|
|
17
17
|
'membership',
|
|
18
18
|
'favorites',
|
|
19
19
|
'public_author_search',
|
|
20
|
+
'public_work_search',
|
|
20
21
|
'author_query',
|
|
21
22
|
'statistics',
|
|
22
23
|
'content_search',
|
|
@@ -24,8 +25,8 @@ const ABILITIES = new Set([
|
|
|
24
25
|
'hot_topic_analysis',
|
|
25
26
|
'work_query',
|
|
26
27
|
'membership_info',
|
|
27
|
-
'favorites_query'
|
|
28
|
-
|
|
28
|
+
'favorites_query',
|
|
29
|
+
'detection'
|
|
29
30
|
])
|
|
30
31
|
|
|
31
32
|
const PARAM_FLAG_KEYS = [
|
|
@@ -89,6 +90,7 @@ Abilities:
|
|
|
89
90
|
membership 会员查询
|
|
90
91
|
favorites 收藏查询
|
|
91
92
|
public_author_search 作者全网搜索,兼容低层能力
|
|
93
|
+
public_work_search 作品全网搜索,兼容低层能力
|
|
92
94
|
detection 一键检测(原创/风险)
|
|
93
95
|
|
|
94
96
|
Config:
|
|
@@ -146,13 +148,31 @@ function readFlagValue(argv, startIndex, key) {
|
|
|
146
148
|
|
|
147
149
|
if ((key === 'params' || key === 'json') && /[{\[]/.test(raw)) {
|
|
148
150
|
let joined = raw
|
|
149
|
-
while (
|
|
151
|
+
while (
|
|
152
|
+
!isBalancedJsonLike(joined) &&
|
|
153
|
+
index + 1 < argv.length &&
|
|
154
|
+
!String(argv[index + 1]).startsWith('--')
|
|
155
|
+
) {
|
|
150
156
|
index += 1
|
|
151
157
|
joined += argv[index]
|
|
152
158
|
}
|
|
153
159
|
return { value: joined, nextIndex: index }
|
|
154
160
|
}
|
|
155
161
|
|
|
162
|
+
// Accept comma-separated key=value fragments commonly pasted into PowerShell.
|
|
163
|
+
if (key === 'json' && /^[A-Za-z_][\w-]*\s*[:=]/.test(String(raw))) {
|
|
164
|
+
let joined = raw
|
|
165
|
+
while (
|
|
166
|
+
index + 1 < argv.length &&
|
|
167
|
+
!String(argv[index + 1]).startsWith('--') &&
|
|
168
|
+
/^[A-Za-z_][\w-]*\s*[:=]/.test(String(argv[index + 1]))
|
|
169
|
+
) {
|
|
170
|
+
index += 1
|
|
171
|
+
joined += ` ${argv[index]}`
|
|
172
|
+
}
|
|
173
|
+
return { value: joined, nextIndex: index }
|
|
174
|
+
}
|
|
175
|
+
|
|
156
176
|
return { value: raw, nextIndex: index }
|
|
157
177
|
}
|
|
158
178
|
|
|
@@ -215,8 +235,11 @@ function stripWrappingQuotes(text) {
|
|
|
215
235
|
return value
|
|
216
236
|
}
|
|
217
237
|
|
|
218
|
-
|
|
219
|
-
|
|
238
|
+
const OPAQUE_ID_KEYS = new Set(['extAuthorId', 'ext_author_id', 'author_id'])
|
|
239
|
+
|
|
240
|
+
function coerceScalar(value, key) {
|
|
241
|
+
const text = stripWrappingQuotes(value).replace(/\\_/g, '_').trim()
|
|
242
|
+
if (OPAQUE_ID_KEYS.has(key)) return text
|
|
220
243
|
if (text === 'true') return true
|
|
221
244
|
if (text === 'false') return false
|
|
222
245
|
if (text === 'null') return null
|
|
@@ -241,7 +264,10 @@ function parseLooseObject(text) {
|
|
|
241
264
|
let body = String(text).trim()
|
|
242
265
|
if (!body) return undefined
|
|
243
266
|
|
|
244
|
-
if (
|
|
267
|
+
if (
|
|
268
|
+
(body.startsWith('{') && body.endsWith('}')) ||
|
|
269
|
+
(body.startsWith('[') && body.endsWith(']'))
|
|
270
|
+
) {
|
|
245
271
|
body = body.slice(1, -1).trim()
|
|
246
272
|
}
|
|
247
273
|
if (!body) return {}
|
|
@@ -254,11 +280,9 @@ function parseLooseObject(text) {
|
|
|
254
280
|
|
|
255
281
|
const result = {}
|
|
256
282
|
for (const pair of pairs) {
|
|
257
|
-
const matched = pair.match(
|
|
258
|
-
/^(?:["']?)([A-Za-z_][\w-]*)(?:["']?)\s*[:=]\s*(.+)$/
|
|
259
|
-
)
|
|
283
|
+
const matched = pair.match(/^(?:["']?)([A-Za-z_][\w-]*)(?:["']?)\s*[:=]\s*(.+)$/)
|
|
260
284
|
if (!matched) return undefined
|
|
261
|
-
result[matched[1]] = coerceScalar(matched[2])
|
|
285
|
+
result[matched[1]] = coerceScalar(matched[2], matched[1])
|
|
262
286
|
}
|
|
263
287
|
return result
|
|
264
288
|
}
|
|
@@ -294,7 +318,7 @@ function assignFlagParams(params, args) {
|
|
|
294
318
|
for (const key of PARAM_FLAG_KEYS) {
|
|
295
319
|
if (args[key] == null || args[key] === true) continue
|
|
296
320
|
if (params[key] != null) continue
|
|
297
|
-
params[key] = coerceScalar(args[key])
|
|
321
|
+
params[key] = coerceScalar(args[key], key)
|
|
298
322
|
}
|
|
299
323
|
return params
|
|
300
324
|
}
|
|
@@ -331,9 +355,7 @@ export function assertCommandArgs(args, command, allowedFlags, positionalCount =
|
|
|
331
355
|
)
|
|
332
356
|
}
|
|
333
357
|
|
|
334
|
-
const unknownFlags = Object.keys(args).filter(
|
|
335
|
-
(key) => key !== '_' && !allowedFlags.has(key)
|
|
336
|
-
)
|
|
358
|
+
const unknownFlags = Object.keys(args).filter((key) => key !== '_' && !allowedFlags.has(key))
|
|
337
359
|
if (unknownFlags.length > 0) {
|
|
338
360
|
throw new Error(`${command} 存在未知参数:${unknownFlags.map((key) => `--${key}`).join(', ')}`)
|
|
339
361
|
}
|
|
@@ -374,16 +396,30 @@ async function execute(args) {
|
|
|
374
396
|
|
|
375
397
|
let result = payloadResult(JSON.parse(text))
|
|
376
398
|
const requestParams = buildExecuteParams(args)
|
|
377
|
-
if (
|
|
378
|
-
|
|
399
|
+
if (
|
|
400
|
+
ability === 'detection' &&
|
|
401
|
+
requestParams?.wait === true &&
|
|
402
|
+
result?.status === 'pending' &&
|
|
403
|
+
result?.data?.id
|
|
404
|
+
) {
|
|
405
|
+
const timeoutSeconds =
|
|
406
|
+
Number(requestParams.timeoutSeconds) > 0 ? Number(requestParams.timeoutSeconds) : 120
|
|
379
407
|
const deadline = Date.now() + timeoutSeconds * 1000
|
|
380
408
|
while (Date.now() < deadline && result.status === 'pending') {
|
|
381
|
-
await new Promise((resolve) =>
|
|
409
|
+
await new Promise((resolve) =>
|
|
410
|
+
setTimeout(resolve, Math.max(500, Number(result.data.pollAfterSeconds || 3) * 1000))
|
|
411
|
+
)
|
|
382
412
|
if (Date.now() >= deadline) break
|
|
383
413
|
const poll = await fetch(`${config.apiBaseUrl}/api/cli.execute`, {
|
|
384
414
|
method: 'POST',
|
|
385
|
-
headers: {
|
|
386
|
-
|
|
415
|
+
headers: {
|
|
416
|
+
authorization: config.apiKey,
|
|
417
|
+
'content-type': 'application/json',
|
|
418
|
+
'x-device-type': 'pc'
|
|
419
|
+
},
|
|
420
|
+
body: JSON.stringify({
|
|
421
|
+
json: { ability: 'detection', params: { mode: 'get', id: result.data.id } }
|
|
422
|
+
})
|
|
387
423
|
})
|
|
388
424
|
const pollText = await poll.text()
|
|
389
425
|
if (!poll.ok) throw new Error(`请求失败 HTTP ${poll.status}:${pollText}`)
|
|
@@ -402,8 +438,13 @@ function renderQuery(payload, format) {
|
|
|
402
438
|
if (payload.status === 'error') return `${payload.error.code}: ${payload.error.message}`
|
|
403
439
|
const items = payload.data?.items
|
|
404
440
|
if (!Array.isArray(items)) return JSON.stringify(payload, null, 2)
|
|
405
|
-
if (format === 'markdown')
|
|
406
|
-
|
|
441
|
+
if (format === 'markdown')
|
|
442
|
+
return items
|
|
443
|
+
.map((item, index) => `| ${index + 1} | ${item.title || item.name || item.nickname || ''} |`)
|
|
444
|
+
.join('\n')
|
|
445
|
+
return items
|
|
446
|
+
.map((item, index) => `${index + 1}\t${item.title || item.name || item.nickname || ''}`)
|
|
447
|
+
.join('\n')
|
|
407
448
|
}
|
|
408
449
|
|
|
409
450
|
async function query(args) {
|
|
@@ -417,12 +458,19 @@ async function query(args) {
|
|
|
417
458
|
if (!request) throw new Error('query 必须提供 --json 请求对象')
|
|
418
459
|
const config = readConfig()
|
|
419
460
|
const response = await fetch(`${config.apiBaseUrl}/api/agent.query`, {
|
|
420
|
-
method: 'POST',
|
|
461
|
+
method: 'POST',
|
|
462
|
+
headers: {
|
|
463
|
+
authorization: config.apiKey,
|
|
464
|
+
'content-type': 'application/json',
|
|
465
|
+
'x-device-type': 'pc'
|
|
466
|
+
},
|
|
421
467
|
body: JSON.stringify({ json: request })
|
|
422
468
|
})
|
|
423
469
|
const text = await response.text()
|
|
424
470
|
if (!response.ok) throw new Error(`请求失败 HTTP ${response.status}:${text}`)
|
|
425
|
-
console.log(
|
|
471
|
+
console.log(
|
|
472
|
+
renderQuery(JSON.parse(text).result?.data?.json ?? JSON.parse(text), args.format || 'json')
|
|
473
|
+
)
|
|
426
474
|
}
|
|
427
475
|
|
|
428
476
|
async function main() {
|
|
@@ -445,7 +493,12 @@ async function main() {
|
|
|
445
493
|
}
|
|
446
494
|
|
|
447
495
|
if (command === 'config' && args._[1] === 'init') {
|
|
448
|
-
assertCommandArgs(
|
|
496
|
+
assertCommandArgs(
|
|
497
|
+
args,
|
|
498
|
+
'config init',
|
|
499
|
+
new Set(['apiBaseUrl', 'apiKey', 'apiKeyStdin', 'force', 'help']),
|
|
500
|
+
2
|
|
501
|
+
)
|
|
449
502
|
await runConfigInit(args)
|
|
450
503
|
return
|
|
451
504
|
}
|