@simonyea/holysheep-cli 1.7.9 → 1.7.11

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.7.9",
3
+ "version": "1.7.11",
4
4
  "description": "Claude Code/Cursor/Cline API relay for China — ¥1=$1, WeChat/Alipay payment, no credit card, no VPN. One command setup for all AI coding tools.",
5
5
  "keywords": [
6
6
  "openai-china",
@@ -7,7 +7,12 @@ const ora = require('ora')
7
7
  const { execSync, spawnSync } = require('child_process')
8
8
  const pkg = require('../../package.json')
9
9
  const { saveConfig, getApiKey, BASE_URL_ANTHROPIC, BASE_URL_OPENAI, SHOP_URL } = require('../utils/config')
10
- const { writeEnvToShell, ensureWindowsUserPathHasNpmBin } = require('../utils/shell')
10
+ const {
11
+ writeEnvToShell,
12
+ ensureWindowsUserPathHasNpmBin,
13
+ installWindowsCliShims,
14
+ removeWindowsUserEnvVars,
15
+ } = require('../utils/shell')
11
16
  const { commandExists } = require('../utils/which')
12
17
  const TOOLS = require('../tools')
13
18
 
@@ -53,7 +58,7 @@ function getWindowsImmediateLaunchCmd(tool) {
53
58
 
54
59
  function getPreferredCliPrefix() {
55
60
  if (process.platform === 'win32') {
56
- return 'npx @simonyea/holysheep-cli@latest'
61
+ return 'hs'
57
62
  }
58
63
 
59
64
  const mainEntry = String(require.main?.filename || '')
@@ -122,6 +127,14 @@ async function tryAutoInstall(tool) {
122
127
  }
123
128
 
124
129
  async function setup(options) {
130
+ let windowsCliArtifacts = []
131
+ if (process.platform === 'win32') {
132
+ windowsCliArtifacts = [
133
+ ...installWindowsCliShims(),
134
+ ...ensureWindowsUserPathHasNpmBin(),
135
+ ]
136
+ }
137
+
125
138
  console.log()
126
139
  console.log(chalk.bold('🐑 HolySheep CLI — 一键配置 AI 工具'))
127
140
  console.log(chalk.gray('━'.repeat(50)))
@@ -137,8 +150,8 @@ async function setup(options) {
137
150
  console.log(chalk.gray(` (¥10 起充,按量计费,支持微信/支付宝)`))
138
151
  console.log(chalk.gray(`提示:可先运行 ${chalk.cyan('hs login')} 登录并保存 Key,之后 setup 将自动读取。`))
139
152
  if (process.platform === 'win32') {
140
- console.log(chalk.gray(` ⚠️ Windows 用户:如果 ${chalk.cyan('hs')} 命令找不到,请用以下方式运行:`))
141
- console.log(chalk.gray(` ${chalk.white('npx @simonyea/holysheep-cli login')} (无需安装,直接用)`))
153
+ console.log(chalk.gray(` ⚠️ Windows 用户:如果 ${chalk.cyan('hs')} 命令暂时找不到,请先运行:`))
154
+ console.log(chalk.gray(` ${chalk.white('npx @simonyea/holysheep-cli@latest login')}`))
142
155
  console.log(chalk.gray(` 或重启终端后再试`))
143
156
  }
144
157
  console.log()
@@ -302,14 +315,25 @@ async function setup(options) {
302
315
  }
303
316
 
304
317
  // Step 5: 写入通用环境变量
305
- const needsEnvVars = toConfigureTools.some(t => t.id === 'codex' || t.id === 'aider')
306
- if (needsEnvVars || Object.keys(envVarsToWrite).length > 0) {
307
- Object.assign(envVarsToWrite, {
308
- ANTHROPIC_API_KEY: apiKey,
309
- ANTHROPIC_BASE_URL: BASE_URL_ANTHROPIC,
310
- OPENAI_API_KEY: apiKey,
311
- OPENAI_BASE_URL: BASE_URL_OPENAI,
312
- })
318
+ const needsAnthropicEnv = toConfigureTools.some(t => t.id === 'claude-code')
319
+ const needsOpenAIEnv = toConfigureTools.some(t => t.id === 'codex' || t.id === 'aider')
320
+ if (needsAnthropicEnv || needsOpenAIEnv || Object.keys(envVarsToWrite).length > 0) {
321
+ if (needsAnthropicEnv) {
322
+ Object.assign(envVarsToWrite, {
323
+ ANTHROPIC_API_KEY: apiKey,
324
+ ANTHROPIC_BASE_URL: BASE_URL_ANTHROPIC,
325
+ })
326
+ }
327
+ if (needsOpenAIEnv) {
328
+ Object.assign(envVarsToWrite, {
329
+ OPENAI_API_KEY: apiKey,
330
+ })
331
+ if (toConfigureTools.some(t => t.id === 'aider')) {
332
+ Object.assign(envVarsToWrite, {
333
+ OPENAI_BASE_URL: BASE_URL_OPENAI,
334
+ })
335
+ }
336
+ }
313
337
  }
314
338
 
315
339
  if (Object.keys(envVarsToWrite).length > 0) {
@@ -322,6 +346,19 @@ async function setup(options) {
322
346
  }
323
347
  }
324
348
 
349
+ if (process.platform === 'win32' && toConfigureTools.some(t => t.id === 'codex') && !toConfigureTools.some(t => t.id === 'aider')) {
350
+ const removed = removeWindowsUserEnvVars(['OPENAI_BASE_URL'])
351
+ if (removed.length > 0) {
352
+ console.log(chalk.gray(`已移除过时环境变量: ${removed.map(item => chalk.cyan(item)).join(', ')}`))
353
+ console.log()
354
+ }
355
+ }
356
+
357
+ if (process.platform === 'win32' && windowsCliArtifacts.length > 0) {
358
+ console.log(chalk.gray(`Windows 启动器已就绪: ${windowsCliArtifacts.map(item => chalk.cyan(item)).join(', ')}`))
359
+ console.log()
360
+ }
361
+
325
362
  // Step 6: 保存 API Key
326
363
  saveConfig({ apiKey })
327
364
 
package/src/index.js CHANGED
@@ -4,12 +4,13 @@
4
4
  const { program } = require('commander')
5
5
  const chalk = require('chalk')
6
6
  const pkg = require('../package.json')
7
+ const { installWindowsCliShims, ensureWindowsUserPathHasNpmBin } = require('./utils/shell')
7
8
 
8
9
  // Windows 用户:检测 npm bin 路径是否在 PATH 中
9
10
  if (process.platform === 'win32') {
10
- const { execSync } = require('child_process')
11
11
  try {
12
- // 静默检查,只在首次遇到问题时才会走到这(因为已经能运行 node 了)
12
+ installWindowsCliShims()
13
+ ensureWindowsUserPathHasNpmBin()
13
14
  } catch {}
14
15
  }
15
16
 
@@ -12,10 +12,11 @@
12
12
  * [model_providers.holysheep]
13
13
  * name = "HolySheep"
14
14
  * base_url = "https://api.holysheep.ai/v1"
15
- * api_key = "cr_xxx"
15
+ * env_key = "OPENAI_API_KEY"
16
+ * wire_api = "responses"
16
17
  *
17
18
  * 注意:旧的 config.json 会被 Rust Codex 忽略!
18
- * 注意:使用 api_key 而非 env_key,避免 Windows 上需要重启终端才能生效的问题
19
+ * 注意:Rust Codex 当前读取 env_key,不读取自定义 api_key 字段。
19
20
  */
20
21
  const fs = require('fs')
21
22
  const path = require('path')
@@ -88,7 +89,8 @@ function isConfiguredInToml() {
88
89
  const content = readTomlConfig()
89
90
  return content.includes('model_provider = "holysheep"') &&
90
91
  content.includes('base_url') &&
91
- content.includes('holysheep.ai')
92
+ content.includes('holysheep.ai') &&
93
+ content.includes('env_key = "OPENAI_API_KEY"')
92
94
  }
93
95
 
94
96
  /**
@@ -111,7 +113,8 @@ function writeTomlConfig(apiKey, baseUrlOpenAI, model) {
111
113
  `[model_providers.holysheep]`,
112
114
  `name = "HolySheep"`,
113
115
  `base_url = "${baseUrlOpenAI}"`,
114
- `api_key = "${apiKey}"`,
116
+ `env_key = "OPENAI_API_KEY"`,
117
+ `wire_api = "responses"`,
115
118
  '',
116
119
  ].join('\n')
117
120
 
@@ -135,12 +138,13 @@ function writeJsonConfigIfNeeded(apiKey, baseUrlOpenAI, model) {
135
138
  jsonConfig.model_providers.holysheep = {
136
139
  name: 'HolySheep',
137
140
  base_url: baseUrlOpenAI,
138
- api_key: apiKey,
141
+ env_key: 'OPENAI_API_KEY',
142
+ wire_api: 'responses',
139
143
  }
140
144
  jsonConfig.providers.holysheep = {
141
145
  name: 'HolySheep',
142
146
  baseURL: baseUrlOpenAI,
143
- apiKey,
147
+ envKey: 'OPENAI_API_KEY',
144
148
  }
145
149
  fs.writeFileSync(CONFIG_FILE_JSON, JSON.stringify(jsonConfig, null, 2), 'utf8')
146
150
  } catch {}
@@ -169,7 +173,6 @@ module.exports = {
169
173
  hot: false,
170
174
  envVars: {
171
175
  OPENAI_API_KEY: apiKey,
172
- OPENAI_BASE_URL: baseUrlOpenAI,
173
176
  },
174
177
  }
175
178
  },
@@ -109,6 +109,46 @@ function ensureWindowsUserPathHasNpmBin() {
109
109
  }
110
110
  }
111
111
 
112
+ function installWindowsCliShims() {
113
+ if (process.platform !== 'win32') return []
114
+
115
+ const appData = process.env.APPDATA
116
+ if (!appData) return []
117
+
118
+ const npmBin = path.join(appData, 'npm')
119
+ fs.mkdirSync(npmBin, { recursive: true })
120
+
121
+ const cmdContent = [
122
+ '@echo off',
123
+ 'setlocal',
124
+ 'if exist "%~dp0npx.cmd" (',
125
+ ' call "%~dp0npx.cmd" @simonyea/holysheep-cli@latest %*',
126
+ ') else (',
127
+ ' call npx @simonyea/holysheep-cli@latest %*',
128
+ ')',
129
+ ''
130
+ ].join('\r\n')
131
+
132
+ const ps1Content = [
133
+ '$npxCmd = Join-Path $PSScriptRoot "npx.cmd"',
134
+ 'if (Test-Path $npxCmd) {',
135
+ ' & $npxCmd "@simonyea/holysheep-cli@latest" @args',
136
+ '} else {',
137
+ ' & npx "@simonyea/holysheep-cli@latest" @args',
138
+ '}',
139
+ ''
140
+ ].join('\r\n')
141
+
142
+ const written = []
143
+ for (const name of ['hs', 'holysheep']) {
144
+ fs.writeFileSync(path.join(npmBin, `${name}.cmd`), cmdContent, 'utf8')
145
+ fs.writeFileSync(path.join(npmBin, `${name}.ps1`), ps1Content, 'utf8')
146
+ written.push(`[启动器] %APPDATA%\\npm\\${name}.cmd`)
147
+ }
148
+
149
+ return written
150
+ }
151
+
112
152
  function writeEnvToShell(envVars) {
113
153
  // Windows: 用 setx 写入用户级环境变量(需重启终端生效)
114
154
  if (process.platform === 'win32') {
@@ -119,6 +159,7 @@ function writeEnvToShell(envVars) {
119
159
  written.push(`[系统环境变量] ${k}`)
120
160
  } catch {}
121
161
  }
162
+ written.push(...installWindowsCliShims())
122
163
  written.push(...ensureWindowsUserPathHasNpmBin())
123
164
  if (written.length > 0) {
124
165
  const chalk = require('chalk')
@@ -146,6 +187,22 @@ function writeEnvToShell(envVars) {
146
187
  return written
147
188
  }
148
189
 
190
+ function removeWindowsUserEnvVars(keys = []) {
191
+ if (process.platform !== 'win32') return []
192
+
193
+ const removed = []
194
+ for (const key of keys) {
195
+ try {
196
+ execSync(
197
+ `powershell.exe -NoProfile -Command "[Environment]::SetEnvironmentVariable('${key}', $null, 'User')"`,
198
+ { stdio: 'ignore' }
199
+ )
200
+ removed.push(`[系统环境变量] ${key}`)
201
+ } catch {}
202
+ }
203
+ return removed
204
+ }
205
+
149
206
  function removeEnvFromShell(extraKeys = []) {
150
207
  // 默认清理的 key 列表(holysheep 相关的所有环境变量)
151
208
  const HS_KEYS = [
@@ -174,4 +231,11 @@ function escapeRegex(s) {
174
231
  return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
175
232
  }
176
233
 
177
- module.exports = { getShellRcFiles, writeEnvToShell, removeEnvFromShell, ensureWindowsUserPathHasNpmBin }
234
+ module.exports = {
235
+ getShellRcFiles,
236
+ writeEnvToShell,
237
+ removeEnvFromShell,
238
+ ensureWindowsUserPathHasNpmBin,
239
+ installWindowsCliShims,
240
+ removeWindowsUserEnvVars
241
+ }