@2api-store/activate 0.4.1 → 0.4.3

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 (2) hide show
  1. package/lib/cmds.mjs +33 -38
  2. package/package.json +1 -1
package/lib/cmds.mjs CHANGED
@@ -227,13 +227,37 @@ async function cmdRestore(argv) {
227
227
  byTime[tsKey].push(b)
228
228
  }
229
229
 
230
+ // 同时间组内按 origPath 去重(同 origPath 只保留 mtime 最大的)
231
+ for (const ts of timeOrder) {
232
+ const group = byTime[ts]
233
+ const byOrig = {}
234
+ for (const b of group) {
235
+ if (!byOrig[b.origPath] || b.mtime > byOrig[b.origPath].mtime) {
236
+ byOrig[b.origPath] = b
237
+ }
238
+ }
239
+ byTime[ts] = Object.values(byOrig).sort((a, b) => b.mtime - a.mtime)
240
+ }
241
+
230
242
  console.log()
231
243
  step(`选择恢复时间点(${chosenAppLabel})`)
232
244
  const timeItems = timeOrder.map((ts) => {
233
245
  const group = byTime[ts]
234
246
  const files = group.map((b) => path.basename(b.origPath)).join(', ')
235
247
  const tsDisplay = fmtTime(group[0].mtime)
236
- return { label: `${chalk.dim(tsDisplay)}(${group.length} 文件:${files})`, ts, group }
248
+ // 从备份内容提取 key 前缀(帮助用户区分不同激活)
249
+ let keyHint = ''
250
+ for (const b of group) {
251
+ try {
252
+ const content = fs.readFileSync(b.bakPath, 'utf8')
253
+ const m = content.match(/sk-[a-f0-9]{6,8}/i)
254
+ if (m) { keyHint = `sk-…${m[0].slice(-6)}`; break }
255
+ const m2 = content.match(/(?:api_key|API_KEY|OPENAI_API_KEY)["':\s]+(["']?)(sk-[a-f0-9]{6,8})/i)
256
+ if (m2) { keyHint = `sk-…${m2[2].slice(-6)}`; break }
257
+ } catch { /* ignore */ }
258
+ }
259
+ const hint = keyHint ? ` ${chalk.yellow(keyHint)}` : ''
260
+ return { label: `${chalk.dim(tsDisplay)}(${group.length} 文件:${files})${hint}`, ts, group }
237
261
  })
238
262
  const timeIdx = await select('选择时间点(回车=最新)', timeItems, { defaultIndex: 0 })
239
263
  if (timeIdx < 0 || timeIdx >= timeItems.length) {
@@ -464,17 +488,11 @@ async function cmdReconfig(argv) {
464
488
  info('识别为:API Key 模式(不创建账号,仅重拉模板写入配置)')
465
489
  console.log()
466
490
 
467
- // 询问是否限制平台(可选)
468
- const platformAnswer = (await ask('限制平台?(留空=全部,或输入 openai/anthropic/gemini/grok/antigravity)')).trim()
469
- const platform = platformAnswer || null
470
- if (platform) info(`平台过滤:${platform}`)
471
- console.log()
472
-
473
- // POST /cli/activate
474
- step('请求激活服务(key 模式重拉模板)')
491
+ // POST /cli/activate — 全平台,不问平台限制
492
+ step('请求激活服务(全量重拉模板)')
475
493
  let bundle
476
494
  try {
477
- bundle = await cliActivate({ credential: apiKey, platform, apiBase })
495
+ bundle = await cliActivate({ credential: apiKey, apiBase })
478
496
  } catch (err) {
479
497
  fail(`请求失败:${err.message}`)
480
498
  if (err.statusCode) fail(` HTTP ${err.statusCode}`)
@@ -487,7 +505,7 @@ async function cmdReconfig(argv) {
487
505
  if (bundle.base_url) info(`base_url:${bundle.base_url}`)
488
506
  console.log()
489
507
 
490
- // 过滤配置
508
+ // 过滤配置 — 按模型平台推断 + OS 过滤(与默认激活流程一致)
491
509
  const allowedPlatforms = new Set()
492
510
  for (const m of bundle.models || []) {
493
511
  const id = (typeof m === 'string' ? m : m?.id || '').toLowerCase()
@@ -496,12 +514,10 @@ async function cmdReconfig(argv) {
496
514
  else if (id.startsWith('gemini')) allowedPlatforms.add('gemini')
497
515
  else if (id.startsWith('grok')) allowedPlatforms.add('grok')
498
516
  }
499
- if (platform) allowedPlatforms.add(platform)
500
517
 
501
518
  const osConfigs = (bundle.configs || []).filter((c) => {
502
519
  if (!c) return false
503
520
  if (allowedPlatforms.size > 0 && !allowedPlatforms.has(c.platform)) return false
504
- if (platform && c.platform !== platform) return false
505
521
  if (env.os.isWindows) {
506
522
  return c.os_type === 'windows' || c.os_type === 'all'
507
523
  }
@@ -513,43 +529,22 @@ async function cmdReconfig(argv) {
513
529
  return 1
514
530
  }
515
531
 
516
- // dedupe by platform + client_type
532
+ // reconfig: 全选所有配置,不问 CLI 选择
517
533
  const seen = new Set()
518
- const cliItems = []
534
+ const selectedItems = []
519
535
  for (const c of osConfigs) {
520
536
  const key = `${c.platform}/${c.client_type}`
521
537
  if (seen.has(key)) continue
522
538
  seen.add(key)
523
539
  const meta = getCliMeta(c.client_type)
524
540
  const displayName = c.display_name || c.displayName || meta?.name || `${c.platform} ${c.client_type}`
525
- const installed = env.installed[c.client_type]?.path || (meta && env.installed[meta.detectBin]?.path)
526
- const primaryMark = isDefaultSelected(c.client_type) ? '' : '(独立 CLI)'
527
- const nameColored = installed ? chalk.green(displayName) : chalk.gray(`${displayName} (未装)`)
528
- cliItems.push({
529
- label: `${nameColored} ${chalk.dim(`[${c.platform}/${c.client_type}]`)}${primaryMark}`,
541
+ selectedItems.push({
530
542
  config: c,
531
543
  clientType: c.client_type,
532
544
  meta,
533
- alreadyInstalled: !!installed,
534
545
  })
535
546
  }
536
-
537
- const defaultSelected = cliItems
538
- .map((item, i) => ({ item, i }))
539
- .filter(({ item }) => isDefaultSelected(item.clientType))
540
- .map(({ i }) => i)
541
-
542
- step('选择要重配的 CLI')
543
- const selectedIdxes = await multiSelect(
544
- '选择 CLI(绿色=已装,灰色=未装;默认选主 CLI)',
545
- cliItems,
546
- { defaultSelected },
547
- )
548
- if (selectedIdxes.length === 0) {
549
- plain('未选择任何 CLI,退出。')
550
- return 0
551
- }
552
- const selectedItems = selectedIdxes.map((i) => cliItems[i])
547
+ ok(`将覆盖 ${selectedItems.length} 个 CLI 配置`)
553
548
  console.log()
554
549
 
555
550
  // 选默认模型
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2api-store/activate",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "TokenShop CLI 一键激活:配置本地 codex/claude/gemini/grok/opencode 指向 2api.store 中转(彩色输出 + 自动安装 CLI)",
5
5
  "type": "module",
6
6
  "bin": {