@simonyea/holysheep-cli 1.1.1 → 1.1.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simonyea/holysheep-cli",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "一键配置所有 AI 编程工具接入 HolySheep API — Claude Code / Codex / Gemini CLI / OpenCode / OpenClaw / Aider / Cursor",
5
5
  "keywords": [
6
6
  "claude",
@@ -0,0 +1,211 @@
1
+ /**
2
+ * hs login — 登录并保存 API Key
3
+ * hs logout — 清除本地 API Key
4
+ * hs whoami — 显示当前登录状态
5
+ */
6
+ 'use strict'
7
+
8
+ const inquirer = require('inquirer')
9
+ const chalk = require('chalk')
10
+ const ora = require('ora')
11
+ const fetch = require('node-fetch')
12
+ const { execSync } = require('child_process')
13
+ const { loadConfig, saveConfig, getApiKey, BASE_URL_OPENAI, SHOP_URL, CONFIG_FILE } = require('../utils/config')
14
+ const fs = require('fs')
15
+
16
+ const MODELS_URL = `${BASE_URL_OPENAI}/models`
17
+
18
+ function maskKey(key) {
19
+ if (!key || key.length < 8) return '****'
20
+ return key.slice(0, 8) + '...' + key.slice(-4)
21
+ }
22
+
23
+ /**
24
+ * 调用 /v1/models 验证 API Key 是否有效
25
+ * @returns {boolean}
26
+ */
27
+ async function validateApiKey(apiKey) {
28
+ const res = await fetch(MODELS_URL, {
29
+ method: 'GET',
30
+ headers: {
31
+ Authorization: `Bearer ${apiKey}`,
32
+ 'Content-Type': 'application/json',
33
+ },
34
+ timeout: 10000,
35
+ })
36
+ return res.status === 200
37
+ }
38
+
39
+ // ── login ────────────────────────────────────────────────────────────────────
40
+ async function login() {
41
+ console.log()
42
+ console.log(chalk.bold('🐑 HolySheep — 登录'))
43
+ console.log(chalk.gray('━'.repeat(50)))
44
+ console.log()
45
+
46
+ // 检查是否已登录
47
+ const existing = getApiKey()
48
+ if (existing) {
49
+ console.log(`${chalk.green('✓')} 已登录,当前 API Key: ${chalk.cyan(maskKey(existing))}`)
50
+ const { relogin } = await inquirer.prompt([{
51
+ type: 'confirm',
52
+ name: 'relogin',
53
+ message: '是否使用新的 API Key 重新登录?',
54
+ default: false,
55
+ }])
56
+ if (!relogin) {
57
+ console.log(chalk.gray('保持当前登录,退出。'))
58
+ console.log()
59
+ return
60
+ }
61
+ console.log()
62
+ }
63
+
64
+ // 提示用户获取 key 的方式
65
+ console.log(chalk.cyan('获取 API Key 的方式:'))
66
+ console.log(` ${chalk.bold('a)')} 输入已有的 API Key (cr_xxx)`)
67
+ console.log(` ${chalk.bold('b)')} 打开浏览器前往 ${chalk.cyan(SHOP_URL)} 注册`)
68
+ console.log()
69
+
70
+ const { choice } = await inquirer.prompt([{
71
+ type: 'list',
72
+ name: 'choice',
73
+ message: '请选择:',
74
+ choices: [
75
+ { name: '输入已有的 API Key', value: 'input' },
76
+ { name: `打开浏览器注册 (${SHOP_URL})`, value: 'browser' },
77
+ ],
78
+ }])
79
+
80
+ if (choice === 'browser') {
81
+ console.log(chalk.gray(`\n正在打开浏览器: ${SHOP_URL}`))
82
+ try {
83
+ const platform = process.platform
84
+ if (platform === 'darwin') execSync(`open "${SHOP_URL}"`)
85
+ else if (platform === 'win32') execSync(`start "" "${SHOP_URL}"`)
86
+ else execSync(`xdg-open "${SHOP_URL}"`)
87
+ } catch {
88
+ console.log(chalk.yellow(`无法自动打开浏览器,请手动访问: ${SHOP_URL}`))
89
+ }
90
+ console.log()
91
+ }
92
+
93
+ // 输入 API Key
94
+ const { apiKey } = await inquirer.prompt([{
95
+ type: 'password',
96
+ name: 'apiKey',
97
+ message: '请输入 API Key (cr_xxx):',
98
+ validate: v => {
99
+ if (!v || !v.trim()) return '请输入 API Key'
100
+ if (!v.trim().startsWith('cr_')) return '请输入以 cr_ 开头的 API Key'
101
+ return true
102
+ },
103
+ }])
104
+
105
+ const key = apiKey.trim()
106
+
107
+ // 验证 API Key
108
+ const spinner = ora('正在验证 API Key...').start()
109
+ try {
110
+ const valid = await validateApiKey(key)
111
+ if (!valid) {
112
+ spinner.fail(chalk.red('API Key 无效,请检查后重试'))
113
+ console.log(chalk.gray(` 前往获取有效 Key: ${SHOP_URL}`))
114
+ console.log()
115
+ process.exit(1)
116
+ }
117
+ } catch (e) {
118
+ spinner.fail(`验证失败: ${e.message}`)
119
+ console.log(chalk.yellow(' 网络异常,请检查网络连接后重试'))
120
+ console.log()
121
+ process.exit(1)
122
+ }
123
+
124
+ // 保存
125
+ saveConfig({ apiKey: key, savedAt: new Date().toISOString() })
126
+ spinner.succeed(chalk.green('API Key 验证成功并已保存!'))
127
+
128
+ console.log()
129
+ console.log(` Key: ${chalk.cyan(maskKey(key))}`)
130
+ console.log(` 配置文件: ${chalk.gray(CONFIG_FILE)}`)
131
+ console.log()
132
+ console.log(chalk.bold('接下来:'))
133
+ console.log(` 运行 ${chalk.cyan('hs setup')} 一键配置 AI 工具`)
134
+ console.log(` 运行 ${chalk.cyan('hs whoami')} 查看登录状态`)
135
+ console.log()
136
+ }
137
+
138
+ // ── logout ───────────────────────────────────────────────────────────────────
139
+ async function logout() {
140
+ console.log()
141
+ const existing = getApiKey()
142
+ if (!existing) {
143
+ console.log(chalk.yellow('当前未登录(无本地 API Key)'))
144
+ console.log()
145
+ return
146
+ }
147
+
148
+ const { confirm } = await inquirer.prompt([{
149
+ type: 'confirm',
150
+ name: 'confirm',
151
+ message: `确认退出登录?将删除本地 API Key (${maskKey(existing)})`,
152
+ default: false,
153
+ }])
154
+
155
+ if (!confirm) {
156
+ console.log(chalk.gray('取消,保持当前登录。'))
157
+ console.log()
158
+ return
159
+ }
160
+
161
+ try {
162
+ const config = loadConfig()
163
+ delete config.apiKey
164
+ delete config.savedAt
165
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2))
166
+ console.log(chalk.green('✓ 已退出登录,本地 API Key 已清除'))
167
+ } catch (e) {
168
+ console.log(chalk.red(`退出失败: ${e.message}`))
169
+ }
170
+ console.log()
171
+ }
172
+
173
+ // ── whoami ───────────────────────────────────────────────────────────────────
174
+ async function whoami() {
175
+ console.log()
176
+ console.log(chalk.bold('🐑 HolySheep — 登录状态'))
177
+ console.log(chalk.gray('━'.repeat(50)))
178
+ console.log()
179
+
180
+ const apiKey = getApiKey()
181
+ if (!apiKey) {
182
+ console.log(chalk.yellow('未登录 — 本地无 API Key'))
183
+ console.log(chalk.gray(`运行 ${chalk.cyan('hs login')} 登录`))
184
+ console.log()
185
+ return
186
+ }
187
+
188
+ console.log(`状态: ${chalk.green('● 已登录')}`)
189
+ console.log(`Key: ${chalk.cyan(maskKey(apiKey))}`)
190
+
191
+ const config = loadConfig()
192
+ if (config.savedAt) {
193
+ console.log(`保存时间: ${chalk.gray(new Date(config.savedAt).toLocaleString())}`)
194
+ }
195
+
196
+ // 验证 key 是否仍然有效
197
+ const spinner = ora('验证 Key 有效性...').start()
198
+ try {
199
+ const valid = await validateApiKey(apiKey)
200
+ if (valid) {
201
+ spinner.succeed(chalk.green('Key 有效'))
202
+ } else {
203
+ spinner.fail(chalk.red('Key 已失效,请重新登录 (hs login)'))
204
+ }
205
+ } catch (e) {
206
+ spinner.warn(`无法验证(网络异常): ${e.message}`)
207
+ }
208
+ console.log()
209
+ }
210
+
211
+ module.exports = { login, logout, whoami }
@@ -74,7 +74,14 @@ async function setup(options) {
74
74
 
75
75
  if (!apiKey) {
76
76
  console.log(chalk.yellow('需要 API Key 才能配置工具。'))
77
- console.log(chalk.cyan(`还没有账号?前往注册:${SHOP_URL}\n`))
77
+ console.log(chalk.cyan(`还没有账号?前往注册:${SHOP_URL}`))
78
+ console.log(chalk.gray(`提示:可先运行 ${chalk.cyan('hs login')} 登录并保存 Key,之后 setup 将自动读取。`))
79
+ if (process.platform === 'win32') {
80
+ console.log(chalk.gray(` ⚠️ Windows 用户:如果 ${chalk.cyan('hs')} 命令找不到,请用以下方式运行:`))
81
+ console.log(chalk.gray(` ${chalk.white('npx @simonyea/holysheep-cli login')} (无需安装,直接用)`))
82
+ console.log(chalk.gray(` 或重启终端后再试`))
83
+ }
84
+ console.log()
78
85
 
79
86
  const { key } = await inquirer.prompt([{
80
87
  type: 'password',
package/src/index.js CHANGED
@@ -5,11 +5,19 @@ const { program } = require('commander')
5
5
  const chalk = require('chalk')
6
6
  const pkg = require('../package.json')
7
7
 
8
+ // Windows 用户:检测 npm bin 路径是否在 PATH 中
9
+ if (process.platform === 'win32') {
10
+ const { execSync } = require('child_process')
11
+ try {
12
+ // 静默检查,只在首次遇到问题时才会走到这(因为已经能运行 node 了)
13
+ } catch {}
14
+ }
15
+
8
16
  // Banner
9
17
  function printBanner() {
10
18
  console.log()
11
19
  console.log(chalk.bold('🐑 ' + chalk.hex('#e8a46a')('HolySheep CLI') + ' v' + pkg.version))
12
- console.log(chalk.gray('官方 Claude/GPT/Gemini API · ¥1=$1 · shop.holysheep.ai'))
20
+ console.log(chalk.gray('官方 Claude/GPT/Gemini API · ¥1=$1 · holysheep.ai'))
13
21
  }
14
22
 
15
23
  program
@@ -18,11 +26,38 @@ program
18
26
  .version(pkg.version, '-v, --version')
19
27
  .addHelpText('before', `
20
28
  🐑 HolySheep CLI v${pkg.version}
21
- 官方 Claude / GPT / Gemini API · ¥1=$1 · https://shop.holysheep.ai
29
+ 官方 Claude / GPT / Gemini API · ¥1=$1 · https://holysheep.ai
22
30
 
23
31
  支持工具: Claude Code · Codex · Gemini CLI · OpenCode · OpenClaw · Aider · Cursor · Continue
24
32
  `)
25
33
 
34
+ // ── login ────────────────────────────────────────────────────────────────────
35
+ program
36
+ .command('login')
37
+ .description('登录 HolySheep,保存 API Key 到本地')
38
+ .action(async () => {
39
+ const { login } = require('./commands/login')
40
+ await login()
41
+ })
42
+
43
+ // ── logout ───────────────────────────────────────────────────────────────────
44
+ program
45
+ .command('logout')
46
+ .description('退出登录,清除本地 API Key')
47
+ .action(async () => {
48
+ const { logout } = require('./commands/login')
49
+ await logout()
50
+ })
51
+
52
+ // ── whoami ───────────────────────────────────────────────────────────────────
53
+ program
54
+ .command('whoami')
55
+ .description('显示当前登录状态')
56
+ .action(async () => {
57
+ const { whoami } = require('./commands/login')
58
+ await whoami()
59
+ })
60
+
26
61
  // ── setup ────────────────────────────────────────────────────────────────────
27
62
  program
28
63
  .command('setup')
@@ -86,12 +121,14 @@ program
86
121
  printBanner()
87
122
  console.log()
88
123
  console.log(chalk.cyan('快速开始:'))
124
+ console.log(` ${chalk.bold('hs login')} 登录并保存 API Key`)
89
125
  console.log(` ${chalk.bold('hs setup')} 一键配置所有 AI 工具`)
126
+ console.log(` ${chalk.bold('hs whoami')} 查看当前登录状态`)
90
127
  console.log(` ${chalk.bold('hs doctor')} 检查配置状态`)
91
128
  console.log(` ${chalk.bold('hs balance')} 查看账户余额`)
92
129
  console.log(` ${chalk.bold('hs tools')} 查看支持的工具列表`)
93
130
  console.log()
94
- console.log(chalk.gray(`注册账号: https://shop.holysheep.ai`))
131
+ console.log(chalk.gray(`注册账号: https://holysheep.ai`))
95
132
  console.log()
96
133
  })
97
134
 
@@ -50,7 +50,7 @@ module.exports = {
50
50
  // Aider 用 openai-api-base(OpenAI 兼容格式,带 /v1)
51
51
  // model 格式: openai/<model-name> 表示使用 OpenAI 兼容接口
52
52
  const block = `
53
- # holysheep-cli managed — https://shop.holysheep.ai
53
+ # holysheep-cli managed — https://holysheep.ai
54
54
  openai-api-key: ${apiKey}
55
55
  openai-api-base: ${baseUrlOpenAI}
56
56
  model: openai/claude-sonnet-4-5
@@ -11,7 +11,7 @@ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json')
11
11
 
12
12
  const BASE_URL_ANTHROPIC = 'https://api.holysheep.ai' // 不带 /v1 (Anthropic SDK)
13
13
  const BASE_URL_OPENAI = 'https://api.holysheep.ai/v1' // 带 /v1 (OpenAI 兼容)
14
- const SHOP_URL = 'https://shop.holysheep.ai'
14
+ const SHOP_URL = 'https://holysheep.ai'
15
15
 
16
16
  function ensureDir() {
17
17
  if (!fs.existsSync(CONFIG_DIR)) {