@yizhuan-cli/cli 0.1.16-beta.2 → 0.1.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yizhuan-cli/cli",
3
- "version": "0.1.16-beta.2",
3
+ "version": "0.1.16",
4
4
  "description": "易撰命令行工具,用于通过 API Key 查询易撰真实数据。",
5
5
  "private": false,
6
6
  "type": "module",
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "name": "yizhuan-cli",
4
- "version": "0.1.16-beta.2",
5
- "compatibleCliVersion": "0.1.16-beta.2",
6
- "source": "npm:@yizhuan-cli/cli@0.1.16-beta.2",
4
+ "version": "0.1.16",
5
+ "compatibleCliVersion": "0.1.16",
6
+ "source": "npm:@yizhuan-cli/cli@0.1.16",
7
7
  "digestAlgorithm": "sha256",
8
8
  "files": [
9
9
  {
package/src/doctor.js CHANGED
@@ -210,7 +210,7 @@ export function inspectSkill(
210
210
  }
211
211
  return check('pass', 'skill', `正式 Skill ${metadata.version} 来源和摘要有效:${resolved.target}`)
212
212
  } catch (error) {
213
- return check('fail', 'skill', `正式 Skill 校验失败:${error.message}`, '保留冲突内容并人工确认,或移走后重新运行 skill sync。')
213
+ return check('fail', 'skill', `正式 Skill 校验失败:${error.message}`, '人工确认后运行 yizhuan skill sync --repair,或移走冲突内容后重新同步。')
214
214
  }
215
215
  }
216
216
 
package/src/index.js CHANGED
@@ -59,7 +59,7 @@ Usage:
59
59
  yizhuan config init [--api-key-stdin] [--api-base-url <url>] [--force]
60
60
  yizhuan config path
61
61
  yizhuan config show
62
- yizhuan skill sync [--global]
62
+ yizhuan skill sync [--global] [--host <name>] [--repair]
63
63
  yizhuan doctor [--json]
64
64
 
65
65
  Examples:
@@ -323,6 +323,65 @@ function assignFlagParams(params, args) {
323
323
  return params
324
324
  }
325
325
 
326
+ const AUTHOR_RANKING_METRICS = [
327
+ {
328
+ key: 'friendsCount',
329
+ label: '关注数',
330
+ patterns: [/关注/, /friends(?:Count|_count)?/i]
331
+ },
332
+ {
333
+ key: 'followerCount',
334
+ label: '粉丝数',
335
+ patterns: [/粉丝/, /follower(?:Count|_count)?/i]
336
+ },
337
+ {
338
+ key: 'totalViews',
339
+ label: '阅读数',
340
+ patterns: [/阅读|播放/, /(?:total)?views?/i]
341
+ },
342
+ {
343
+ key: 'totalLikes',
344
+ label: '点赞数',
345
+ patterns: [/点赞/, /(?:total)?likes?/i]
346
+ }
347
+ ]
348
+
349
+ function rankingMetric(query, params) {
350
+ const text = [
351
+ query,
352
+ params?.metric,
353
+ params?.sortBy,
354
+ params?.sort_by,
355
+ params?.order
356
+ ].filter(Boolean).join(' ')
357
+ if (!/(最高|最多|最大|第一|排行|排名|top)/i.test(text)) return undefined
358
+ return AUTHOR_RANKING_METRICS.find((metric) => metric.patterns.some((pattern) => pattern.test(text)))
359
+ }
360
+
361
+ export function annotateUnavailableAuthorRanking(result, { query, params } = {}) {
362
+ const metric = rankingMetric(query, params)
363
+ const items = result?.data?.items
364
+ if (!metric || !Array.isArray(items) || items.length === 0) return result
365
+
366
+ const allValuesAreZero = items.every((item) => Number(item?.[metric.key]) === 0)
367
+ if (!allValuesAreZero) return result
368
+
369
+ const message = `查询到的作者${metric.label}均为 0,无法据此排序或判断最高作者`
370
+ return {
371
+ ...result,
372
+ message: result.message || message,
373
+ data: {
374
+ ...result.data,
375
+ ranking: {
376
+ metric: metric.key,
377
+ status: 'unavailable',
378
+ reason: 'all_returned_values_zero',
379
+ message
380
+ }
381
+ }
382
+ }
383
+ }
384
+
326
385
  export function buildExecuteParams(args) {
327
386
  if (args.jsonFile) {
328
387
  const conflictingKeys = ['params', 'query', ...PARAM_FLAG_KEYS].filter(
@@ -372,6 +431,7 @@ async function execute(args) {
372
431
  throw new Error(`未知 ability:${ability || ''},请执行 yizhuan --help 查看可用能力`)
373
432
  }
374
433
 
434
+ const requestParams = buildExecuteParams(args)
375
435
  const config = readConfig()
376
436
  const response = await fetch(`${config.apiBaseUrl}/api/cli.execute`, {
377
437
  method: 'POST',
@@ -384,7 +444,7 @@ async function execute(args) {
384
444
  json: {
385
445
  ability,
386
446
  query: typeof args.query === 'string' ? args.query : undefined,
387
- params: buildExecuteParams(args)
447
+ params: requestParams
388
448
  }
389
449
  })
390
450
  })
@@ -395,7 +455,6 @@ async function execute(args) {
395
455
  }
396
456
 
397
457
  let result = payloadResult(JSON.parse(text))
398
- const requestParams = buildExecuteParams(args)
399
458
  if (
400
459
  ability === 'detection' &&
401
460
  requestParams?.wait === true &&
@@ -426,6 +485,10 @@ async function execute(args) {
426
485
  result = payloadResult(JSON.parse(pollText))
427
486
  }
428
487
  }
488
+ result = annotateUnavailableAuthorRanking(result, {
489
+ query: typeof args.query === 'string' ? args.query : undefined,
490
+ params: requestParams
491
+ })
429
492
  console.log(JSON.stringify(result, null, 2))
430
493
  }
431
494
 
@@ -468,9 +531,11 @@ async function query(args) {
468
531
  })
469
532
  const text = await response.text()
470
533
  if (!response.ok) throw new Error(`请求失败 HTTP ${response.status}:${text}`)
471
- console.log(
472
- renderQuery(JSON.parse(text).result?.data?.json ?? JSON.parse(text), args.format || 'json')
473
- )
534
+ const result = annotateUnavailableAuthorRanking(payloadResult(JSON.parse(text)), {
535
+ query: request.query || request.keyword,
536
+ params: request
537
+ })
538
+ console.log(renderQuery(result, args.format || 'json'))
474
539
  }
475
540
 
476
541
  async function main() {
@@ -510,7 +575,7 @@ async function main() {
510
575
  }
511
576
 
512
577
  if (command === 'skill' && args._[1] === 'sync') {
513
- assertCommandArgs(args, 'skill sync', new Set(['global', 'host', 'help']), 2)
578
+ assertCommandArgs(args, 'skill sync', new Set(['global', 'host', 'repair', 'help']), 2)
514
579
  await runSkillSync(args)
515
580
  return
516
581
  }
package/src/skill.js CHANGED
@@ -90,7 +90,7 @@ export function loadOfficialSkill(resourceDir = DEFAULT_RESOURCE_DIR) {
90
90
  return { manifest, resourceDir }
91
91
  }
92
92
 
93
- export function readSkillMetadata(target) {
93
+ export function readSkillMetadata(target, { allowModified = false } = {}) {
94
94
  const metadataPath = path.join(target, SKILL_METADATA_FILE)
95
95
  if (!fs.existsSync(metadataPath)) {
96
96
  throw new Error(`目标存在未受易撰管理的同名内容,已停止同步:${target}`)
@@ -111,7 +111,7 @@ export function readSkillMetadata(target) {
111
111
  }
112
112
  for (const file of metadata.files) {
113
113
  const installedPath = safeResourcePath(target, file.path)
114
- if (!fs.existsSync(installedPath) || sha256File(installedPath) !== file.sha256) {
114
+ if (!allowModified && (!fs.existsSync(installedPath) || sha256File(installedPath) !== file.sha256)) {
115
115
  throw new Error(`已安装 Skill 包含未知修改,已停止覆盖:${file.path}`)
116
116
  }
117
117
  }
@@ -182,14 +182,15 @@ export function syncOfficialSkill(
182
182
  {
183
183
  loadBundle = loadOfficialSkill,
184
184
  installBundle = installStagedSkill,
185
- now = () => new Date()
185
+ now = () => new Date(),
186
+ repair = false
186
187
  } = {}
187
188
  ) {
188
189
  const bundle = loadBundle()
189
190
  const { manifest } = bundle
190
191
  let installed
191
192
  if (fs.existsSync(resolved.target)) {
192
- installed = readSkillMetadata(resolved.target)
193
+ installed = readSkillMetadata(resolved.target, { allowModified: repair })
193
194
  const comparison = compareVersions(installed.version, manifest.version)
194
195
  if (comparison > 0) {
195
196
  return { action: 'newer', metadata: installed, target: resolved.target }
@@ -257,11 +258,12 @@ export function resolveSkillTarget(
257
258
 
258
259
  export function printSkillSyncHelp() {
259
260
  console.log(`Usage:
260
- yizhuan skill sync [--global] [--host <name>]
261
+ yizhuan skill sync [--global] [--host <name>] [--repair]
261
262
 
262
263
  Options:
263
264
  --global 安装到当前受支持宿主的用户级 Skill 目录
264
265
  --host 明确指定 codex、agents、trae、claude 或 cursor
266
+ --repair 仅覆盖带官方托管元数据但内容校验失败的 Skill
265
267
  --help 显示本帮助`)
266
268
  }
267
269
 
@@ -272,7 +274,7 @@ export async function runSkillSync(args) {
272
274
  }
273
275
 
274
276
  const resolved = resolveSkillTarget({ global: Boolean(args.global), host: args.host })
275
- const result = syncOfficialSkill(resolved)
277
+ const result = syncOfficialSkill(resolved, { repair: Boolean(args.repair) })
276
278
  const actionText = {
277
279
  installed: '已安装',
278
280
  updated: '已更新',