@simonyea/holysheep-cli 1.7.5 → 1.7.7
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 +1 -1
- package/src/commands/setup.js +33 -11
- package/src/utils/shell.js +41 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simonyea/holysheep-cli",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.7",
|
|
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",
|
package/src/commands/setup.js
CHANGED
|
@@ -5,17 +5,19 @@ const inquirer = require('inquirer')
|
|
|
5
5
|
const chalk = require('chalk')
|
|
6
6
|
const ora = require('ora')
|
|
7
7
|
const { execSync, spawnSync } = require('child_process')
|
|
8
|
+
const pkg = require('../../package.json')
|
|
8
9
|
const { saveConfig, getApiKey, BASE_URL_ANTHROPIC, BASE_URL_OPENAI, SHOP_URL } = require('../utils/config')
|
|
9
|
-
const { writeEnvToShell } = require('../utils/shell')
|
|
10
|
+
const { writeEnvToShell, ensureWindowsUserPathHasNpmBin } = require('../utils/shell')
|
|
11
|
+
const { commandExists } = require('../utils/which')
|
|
10
12
|
const TOOLS = require('../tools')
|
|
11
13
|
|
|
12
14
|
// 工具的自动安装命令(npm/pip)
|
|
13
15
|
const AUTO_INSTALL = {
|
|
14
16
|
'claude-code': {
|
|
15
17
|
cmd: process.platform === 'win32'
|
|
16
|
-
? 'powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://claude.ai/install.ps1 | iex"'
|
|
18
|
+
? 'powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "irm https://claude.ai/install.ps1 | iex"'
|
|
17
19
|
: 'curl -fsSL https://claude.ai/install.sh | bash',
|
|
18
|
-
mgr: process.platform === 'win32' ? 'powershell' : 'bash',
|
|
20
|
+
mgr: process.platform === 'win32' ? 'powershell.exe' : 'bash',
|
|
19
21
|
},
|
|
20
22
|
'codex': { cmd: 'npm install -g @openai/codex', mgr: 'npm' },
|
|
21
23
|
'gemini-cli': { cmd: 'npm install -g @google/gemini-cli', mgr: 'npm' },
|
|
@@ -45,6 +47,19 @@ function getWindowsImmediateLaunchCmd(tool) {
|
|
|
45
47
|
return null
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
function getPreferredCliPrefix() {
|
|
51
|
+
return commandExists('hs')
|
|
52
|
+
? 'hs'
|
|
53
|
+
: `npx @simonyea/holysheep-cli@${pkg.version}`
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getPreferredLaunchCmd(tool) {
|
|
57
|
+
if (!tool?.launchCmd) return null
|
|
58
|
+
if (!tool.launchCmd.startsWith('hs')) return tool.launchCmd
|
|
59
|
+
const prefix = getPreferredCliPrefix()
|
|
60
|
+
return tool.launchCmd.replace(/^hs\b/, prefix)
|
|
61
|
+
}
|
|
62
|
+
|
|
48
63
|
function canAutoInstall(toolId) {
|
|
49
64
|
return !!AUTO_INSTALL[toolId]
|
|
50
65
|
}
|
|
@@ -55,7 +70,11 @@ async function tryAutoInstall(tool) {
|
|
|
55
70
|
|
|
56
71
|
// 检查 npm/pip 是否可用
|
|
57
72
|
try {
|
|
58
|
-
|
|
73
|
+
if (process.platform === 'win32' && info.mgr.toLowerCase() === 'powershell.exe') {
|
|
74
|
+
execSync('where powershell.exe', { stdio: 'ignore' })
|
|
75
|
+
} else {
|
|
76
|
+
execSync(`${info.mgr} --version`, { stdio: 'ignore' })
|
|
77
|
+
}
|
|
59
78
|
} catch {
|
|
60
79
|
console.log(chalk.red(` ✗ 未找到 ${info.mgr},无法自动安装 ${tool.name}`))
|
|
61
80
|
return false
|
|
@@ -75,6 +94,7 @@ async function tryAutoInstall(tool) {
|
|
|
75
94
|
console.log(chalk.yellow(` ⚠ 安装后未检测到命令,尝试直接配置...`))
|
|
76
95
|
}
|
|
77
96
|
if (process.platform === 'win32') {
|
|
97
|
+
ensureWindowsUserPathHasNpmBin()
|
|
78
98
|
tool._winJustInstalled = true // 标记为 Windows 刚装的,摘要里特殊处理
|
|
79
99
|
}
|
|
80
100
|
return true // 安装成功就视为可配置
|
|
@@ -312,12 +332,13 @@ async function setup(options) {
|
|
|
312
332
|
console.log(` ${chalk.gray(` ${i + 1}.`)} ${chalk.cyan.bold(s.cmd)} ${chalk.gray(s.note)}`)
|
|
313
333
|
})
|
|
314
334
|
} else if (r.tool.launchCmd) {
|
|
335
|
+
const preferredLaunchCmd = getPreferredLaunchCmd(r.tool)
|
|
315
336
|
if (r.tool._winJustInstalled) {
|
|
316
|
-
const immediateCmd = getWindowsImmediateLaunchCmd(r.tool)
|
|
317
|
-
console.log(` ${chalk.gray('▶ 立即启动:')} ${chalk.cyan.bold(immediateCmd || r.tool.launchCmd)}`)
|
|
318
|
-
console.log(` ${chalk.gray('▶ 新开终端后:')} ${chalk.cyan.bold(r.tool.launchCmd)}`)
|
|
337
|
+
const immediateCmd = getWindowsImmediateLaunchCmd({ ...r.tool, launchCmd: preferredLaunchCmd || r.tool.launchCmd })
|
|
338
|
+
console.log(` ${chalk.gray('▶ 立即启动:')} ${chalk.cyan.bold(immediateCmd || preferredLaunchCmd || r.tool.launchCmd)}`)
|
|
339
|
+
console.log(` ${chalk.gray('▶ 新开终端后:')} ${chalk.cyan.bold(preferredLaunchCmd || r.tool.launchCmd)}`)
|
|
319
340
|
} else {
|
|
320
|
-
console.log(` ${chalk.gray('▶ 启动命令:')} ${chalk.cyan.bold(r.tool.launchCmd)}`)
|
|
341
|
+
console.log(` ${chalk.gray('▶ 启动命令:')} ${chalk.cyan.bold(preferredLaunchCmd || r.tool.launchCmd)}`)
|
|
321
342
|
}
|
|
322
343
|
if (r.tool.launchNote) console.log(` ${chalk.gray(' ' + r.tool.launchNote)}`)
|
|
323
344
|
} else if (r.tool.launchNote) {
|
|
@@ -338,9 +359,10 @@ async function setup(options) {
|
|
|
338
359
|
console.log()
|
|
339
360
|
}
|
|
340
361
|
|
|
341
|
-
|
|
342
|
-
console.log(chalk.gray(
|
|
343
|
-
console.log(chalk.gray(
|
|
362
|
+
const cliPrefix = getPreferredCliPrefix()
|
|
363
|
+
console.log(chalk.gray(`如需切换其他工具,运行: ${cliPrefix} setup`))
|
|
364
|
+
console.log(chalk.gray(`查看余额: ${cliPrefix} balance`))
|
|
365
|
+
console.log(chalk.gray(`检查配置: ${cliPrefix} doctor`))
|
|
344
366
|
console.log()
|
|
345
367
|
|
|
346
368
|
// 注册引导 banner
|
package/src/utils/shell.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
const fs = require('fs')
|
|
5
5
|
const path = require('path')
|
|
6
6
|
const os = require('os')
|
|
7
|
+
const { execSync } = require('child_process')
|
|
7
8
|
|
|
8
9
|
const MARKER_START = '# >>> holysheep-cli managed >>>'
|
|
9
10
|
const MARKER_END = '# <<< holysheep-cli managed <<<'
|
|
@@ -70,10 +71,47 @@ function buildEnvBlock(envVars, isFish = false) {
|
|
|
70
71
|
return '\n' + lines.join('\n') + '\n'
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
function ensureWindowsUserPathHasNpmBin() {
|
|
75
|
+
if (process.platform !== 'win32') return []
|
|
76
|
+
|
|
77
|
+
const appData = process.env.APPDATA
|
|
78
|
+
if (!appData) return []
|
|
79
|
+
|
|
80
|
+
const npmBin = path.join(appData, 'npm')
|
|
81
|
+
let currentPath = ''
|
|
82
|
+
try {
|
|
83
|
+
currentPath = execSync(
|
|
84
|
+
'powershell.exe -NoProfile -Command "[Environment]::GetEnvironmentVariable(\'Path\', \'User\')"',
|
|
85
|
+
{ encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }
|
|
86
|
+
).trim()
|
|
87
|
+
} catch {
|
|
88
|
+
currentPath = process.env.PATH || ''
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const parts = currentPath
|
|
92
|
+
.split(';')
|
|
93
|
+
.map((item) => item.trim())
|
|
94
|
+
.filter(Boolean)
|
|
95
|
+
|
|
96
|
+
const hasNpmBin = parts.some((item) => item.toLowerCase() === npmBin.toLowerCase())
|
|
97
|
+
if (hasNpmBin) return []
|
|
98
|
+
|
|
99
|
+
const nextPath = [...parts, npmBin].join(';')
|
|
100
|
+
try {
|
|
101
|
+
const escapedPath = nextPath.replace(/'/g, "''")
|
|
102
|
+
execSync(
|
|
103
|
+
`powershell.exe -NoProfile -Command "[Environment]::SetEnvironmentVariable('Path', '${escapedPath}', 'User')"`,
|
|
104
|
+
{ stdio: 'ignore' }
|
|
105
|
+
)
|
|
106
|
+
return ['[用户 PATH] %APPDATA%\\npm']
|
|
107
|
+
} catch {
|
|
108
|
+
return []
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
73
112
|
function writeEnvToShell(envVars) {
|
|
74
113
|
// Windows: 用 setx 写入用户级环境变量(需重启终端生效)
|
|
75
114
|
if (process.platform === 'win32') {
|
|
76
|
-
const { execSync } = require('child_process')
|
|
77
115
|
const written = []
|
|
78
116
|
for (const [k, v] of Object.entries(envVars)) {
|
|
79
117
|
try {
|
|
@@ -81,6 +119,7 @@ function writeEnvToShell(envVars) {
|
|
|
81
119
|
written.push(`[系统环境变量] ${k}`)
|
|
82
120
|
} catch {}
|
|
83
121
|
}
|
|
122
|
+
written.push(...ensureWindowsUserPathHasNpmBin())
|
|
84
123
|
if (written.length > 0) {
|
|
85
124
|
const chalk = require('chalk')
|
|
86
125
|
console.log(chalk.yellow('\n ⚠️ Windows 环境变量已写入,需要重启终端后生效'))
|
|
@@ -135,4 +174,4 @@ function escapeRegex(s) {
|
|
|
135
174
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
136
175
|
}
|
|
137
176
|
|
|
138
|
-
module.exports = { getShellRcFiles, writeEnvToShell, removeEnvFromShell }
|
|
177
|
+
module.exports = { getShellRcFiles, writeEnvToShell, removeEnvFromShell, ensureWindowsUserPathHasNpmBin }
|