@simonyea/holysheep-cli 2.1.38 → 2.1.41
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/dist/configure-worker.js +4491 -0
- package/dist/index.js +9591 -0
- package/dist/process-proxy-inject.js +117 -0
- package/package.json +19 -6
- package/.gitea/workflows/sanity.yml +0 -125
- package/scripts/check-tarball-size.js +0 -44
- package/src/commands/balance.js +0 -57
- package/src/commands/claude-proxy.js +0 -248
- package/src/commands/claude.js +0 -135
- package/src/commands/doctor.js +0 -282
- package/src/commands/login.js +0 -211
- package/src/commands/openclaw.js +0 -258
- package/src/commands/reset.js +0 -53
- package/src/commands/setup.js +0 -493
- package/src/commands/upgrade.js +0 -168
- package/src/commands/webui.js +0 -622
- package/src/index.js +0 -226
- package/src/tools/aider.js +0 -78
- package/src/tools/antigravity.js +0 -42
- package/src/tools/claude-code.js +0 -228
- package/src/tools/claude-process-proxy.js +0 -1030
- package/src/tools/codex.js +0 -254
- package/src/tools/continue.js +0 -146
- package/src/tools/cursor.js +0 -71
- package/src/tools/droid.js +0 -281
- package/src/tools/env-config.js +0 -185
- package/src/tools/gemini-cli.js +0 -82
- package/src/tools/hermes.js +0 -354
- package/src/tools/index.js +0 -13
- package/src/tools/openclaw-bridge.js +0 -987
- package/src/tools/openclaw.js +0 -925
- package/src/tools/opencode.js +0 -227
- package/src/tools/process-proxy-inject.js +0 -142
- package/src/utils/config.js +0 -54
- package/src/utils/shell.js +0 -342
- package/src/utils/which.js +0 -63
- package/src/webui/aionui-runtime-fetcher.js +0 -429
- package/src/webui/aionui-runtime.js +0 -139
- package/src/webui/aionui-wrapper.js +0 -734
- package/src/webui/configure-worker.js +0 -67
- package/src/webui/server.js +0 -1566
- package/src/webui/workspace-runtime.js +0 -288
- package/src/webui/workspace-store.js +0 -325
- /package/{src/webui → dist}/index.html +0 -0
- /package/{src/tools → dist}/pty-hermes-wrapper.py +0 -0
package/src/index.js
DELETED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
const { program } = require('commander')
|
|
5
|
-
const chalk = require('chalk')
|
|
6
|
-
const pkg = require('../package.json')
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// 异步检查最新版本(不阻塞主流程)
|
|
11
|
-
function checkLatestVersion() {
|
|
12
|
-
try {
|
|
13
|
-
const https = require('https')
|
|
14
|
-
const req = https.get(
|
|
15
|
-
`https://registry.npmjs.org/@simonyea/holysheep-cli/latest`,
|
|
16
|
-
{ timeout: 3000 },
|
|
17
|
-
(res) => {
|
|
18
|
-
let data = ''
|
|
19
|
-
res.on('data', chunk => { data += chunk })
|
|
20
|
-
res.on('end', () => {
|
|
21
|
-
try {
|
|
22
|
-
const latest = JSON.parse(data).version
|
|
23
|
-
if (latest && latest !== pkg.version) {
|
|
24
|
-
console.log()
|
|
25
|
-
console.log(chalk.yellow(`⚠️ 发现新版本 v${latest}(当前 v${pkg.version})`))
|
|
26
|
-
console.log(chalk.cyan(` 建议运行: npx @simonyea/holysheep-cli@latest setup`))
|
|
27
|
-
console.log(chalk.gray(` 或更新: npm install -g @simonyea/holysheep-cli@latest`))
|
|
28
|
-
}
|
|
29
|
-
} catch {}
|
|
30
|
-
})
|
|
31
|
-
}
|
|
32
|
-
)
|
|
33
|
-
req.on('error', () => {})
|
|
34
|
-
req.setTimeout(3000, () => req.destroy())
|
|
35
|
-
} catch {}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Banner
|
|
39
|
-
function printBanner() {
|
|
40
|
-
console.log()
|
|
41
|
-
console.log(chalk.bold('🐑 ' + chalk.hex('#e8a46a')('HolySheep CLI') + ' v' + pkg.version))
|
|
42
|
-
console.log(chalk.gray('官方 Claude/GPT/Gemini API · ¥1=$1 · holysheep.ai'))
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
program
|
|
46
|
-
.name('hs')
|
|
47
|
-
.enablePositionalOptions()
|
|
48
|
-
.description('一键配置所有 AI 编程工具接入 HolySheep API')
|
|
49
|
-
.version(pkg.version, '-v, --version')
|
|
50
|
-
.addHelpText('before', `
|
|
51
|
-
🐑 HolySheep CLI v${pkg.version}
|
|
52
|
-
官方 Claude / GPT / Gemini API · ¥1=$1 · https://holysheep.ai
|
|
53
|
-
|
|
54
|
-
支持工具: Claude Code · Codex · Droid · Gemini CLI · OpenCode · OpenClaw · Aider · Cursor · Continue
|
|
55
|
-
`)
|
|
56
|
-
|
|
57
|
-
// ── login ────────────────────────────────────────────────────────────────────
|
|
58
|
-
program
|
|
59
|
-
.command('login')
|
|
60
|
-
.description('登录 HolySheep,保存 API Key 到本地')
|
|
61
|
-
.action(async () => {
|
|
62
|
-
const { login } = require('./commands/login')
|
|
63
|
-
await login()
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
// ── logout ───────────────────────────────────────────────────────────────────
|
|
67
|
-
program
|
|
68
|
-
.command('logout')
|
|
69
|
-
.description('退出登录,清除本地 API Key')
|
|
70
|
-
.action(async () => {
|
|
71
|
-
const { logout } = require('./commands/login')
|
|
72
|
-
await logout()
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
// ── whoami ───────────────────────────────────────────────────────────────────
|
|
76
|
-
program
|
|
77
|
-
.command('whoami')
|
|
78
|
-
.description('显示当前登录状态')
|
|
79
|
-
.action(async () => {
|
|
80
|
-
const { whoami } = require('./commands/login')
|
|
81
|
-
await whoami()
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
// ── setup ────────────────────────────────────────────────────────────────────
|
|
85
|
-
program
|
|
86
|
-
.command('setup')
|
|
87
|
-
.description('一键配置 AI 工具接入 HolySheep API')
|
|
88
|
-
.option('-k, --key <apiKey>', '直接指定 API Key(跳过交互)')
|
|
89
|
-
.option('-a, --all', '配置所有已安装的工具(跳过选择)')
|
|
90
|
-
.action(async (opts) => {
|
|
91
|
-
printBanner()
|
|
92
|
-
checkLatestVersion() // 异步检查版本,不阻塞
|
|
93
|
-
await require('./commands/setup')(opts)
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
// ── doctor ───────────────────────────────────────────────────────────────────
|
|
97
|
-
program
|
|
98
|
-
.command('doctor')
|
|
99
|
-
.alias('check')
|
|
100
|
-
.description('检查环境配置和各工具状态')
|
|
101
|
-
.action(async () => {
|
|
102
|
-
await require('./commands/doctor')()
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
// ── balance ──────────────────────────────────────────────────────────────────
|
|
106
|
-
program
|
|
107
|
-
.command('balance')
|
|
108
|
-
.alias('bal')
|
|
109
|
-
.description('查看账户余额和今日用量')
|
|
110
|
-
.action(async () => {
|
|
111
|
-
await require('./commands/balance')()
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
// ── reset ────────────────────────────────────────────────────────────────────
|
|
115
|
-
program
|
|
116
|
-
.command('reset')
|
|
117
|
-
.description('清除所有 HolySheep 配置,恢复默认')
|
|
118
|
-
.option('-y, --yes', '跳过确认直接执行')
|
|
119
|
-
.action(async (opts) => {
|
|
120
|
-
await require('./commands/reset')(opts)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
// ── upgrade ──────────────────────────────────────────────────────────────────
|
|
124
|
-
program
|
|
125
|
-
.command('upgrade')
|
|
126
|
-
.alias('update')
|
|
127
|
-
.description('升级 Claude Code / Codex / Gemini CLI 到最新版本')
|
|
128
|
-
.action(async () => {
|
|
129
|
-
printBanner()
|
|
130
|
-
await require('./commands/upgrade')()
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
// ── tools ────────────────────────────────────────────────────────────────────
|
|
134
|
-
program
|
|
135
|
-
.command('tools')
|
|
136
|
-
.description('列出所有支持的 AI 工具')
|
|
137
|
-
.action(() => {
|
|
138
|
-
const TOOLS = require('./tools')
|
|
139
|
-
console.log()
|
|
140
|
-
console.log(chalk.bold('支持的 AI 工具:'))
|
|
141
|
-
console.log()
|
|
142
|
-
TOOLS.forEach(t => {
|
|
143
|
-
const installed = t.checkInstalled()
|
|
144
|
-
const icon = installed ? chalk.green('●') : chalk.gray('○')
|
|
145
|
-
const status = installed ? chalk.green('已安装') : chalk.gray('未安装')
|
|
146
|
-
console.log(` ${icon} ${t.name.padEnd(20)} ${status}`)
|
|
147
|
-
console.log(` ${chalk.gray('安装: ' + t.installCmd)}`)
|
|
148
|
-
console.log()
|
|
149
|
-
})
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
// ── openclaw ─────────────────────────────────────────────────────────────────
|
|
153
|
-
program
|
|
154
|
-
.command('openclaw')
|
|
155
|
-
.description('启动 HolySheep 桥接版 OpenClaw(自动启动 Bridge + Gateway 并打开 Dashboard)')
|
|
156
|
-
.action(async () => {
|
|
157
|
-
await require('./commands/openclaw')()
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
// ── openclaw-bridge ──────────────────────────────────────────────────────────
|
|
161
|
-
program
|
|
162
|
-
.command('openclaw-bridge')
|
|
163
|
-
.description('启动 HolySheep 的 OpenClaw 本地桥接服务')
|
|
164
|
-
.option('--port <port>', '指定桥接服务端口')
|
|
165
|
-
.action((opts) => {
|
|
166
|
-
const { startBridge } = require('./tools/openclaw-bridge')
|
|
167
|
-
startBridge({
|
|
168
|
-
port: opts.port ? Number(opts.port) : null,
|
|
169
|
-
host: '127.0.0.1',
|
|
170
|
-
})
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
// ── webui ──────────────────────────────────────────────────────────────────
|
|
174
|
-
program
|
|
175
|
-
.command('web')
|
|
176
|
-
.alias('webui')
|
|
177
|
-
.description('启动 HolySheep WebUI 本地管理面板 (默认 HolySheep API Key 登录)')
|
|
178
|
-
.option('-p, --port <port>', '指定端口', '9876')
|
|
179
|
-
.option('--no-open', '不自动打开浏览器')
|
|
180
|
-
.option('--aionui', '强制使用 HolySheep runtime (兼容 flag 名保留;需本地已安装 runtime)')
|
|
181
|
-
.option('--setup-runtime', '允许首次运行时自动下载 HolySheep runtime')
|
|
182
|
-
.action(async (opts) => {
|
|
183
|
-
printBanner()
|
|
184
|
-
await require('./commands/webui')(opts)
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
// ── claude ──────────────────────────────────────────────────────────────────
|
|
188
|
-
program
|
|
189
|
-
.command('claude [args...]')
|
|
190
|
-
.allowUnknownOption(true)
|
|
191
|
-
.passThroughOptions()
|
|
192
|
-
.description('通过 HolySheep 整进程代理启动 Claude Code')
|
|
193
|
-
.action(async (args = []) => {
|
|
194
|
-
const runClaude = require('./commands/claude')
|
|
195
|
-
const code = await runClaude(args)
|
|
196
|
-
process.exit(code)
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
// ── claude-proxy ────────────────────────────────────────────────────────────
|
|
200
|
-
program
|
|
201
|
-
.command('claude-proxy [args...]')
|
|
202
|
-
.allowUnknownOption(true)
|
|
203
|
-
.description('启动 Claude 代理服务(让 VS Code Claude 扩展也能用 HolySheep)')
|
|
204
|
-
.action(async (args = []) => {
|
|
205
|
-
const claudeProxy = require('./commands/claude-proxy')
|
|
206
|
-
await claudeProxy(args)
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
program.parse(process.argv)
|
|
210
|
-
|
|
211
|
-
// 默认:无子命令时显示帮助 + 提示 setup
|
|
212
|
-
if (process.argv.slice(2).length === 0) {
|
|
213
|
-
printBanner()
|
|
214
|
-
console.log()
|
|
215
|
-
console.log(chalk.cyan('快速开始:'))
|
|
216
|
-
console.log(` ${chalk.bold('hs login')} 登录并保存 API Key`)
|
|
217
|
-
console.log(` ${chalk.bold('hs setup')} 一键配置所有 AI 工具`)
|
|
218
|
-
console.log(` ${chalk.bold('hs whoami')} 查看当前登录状态`)
|
|
219
|
-
console.log(` ${chalk.bold('hs doctor')} 检查配置状态`)
|
|
220
|
-
console.log(` ${chalk.bold('hs balance')} 查看账户余额`)
|
|
221
|
-
console.log(` ${chalk.bold('hs upgrade')} 升级 Claude Code / Codex / Gemini CLI`)
|
|
222
|
-
console.log(` ${chalk.bold('hs tools')} 查看支持的工具列表`)
|
|
223
|
-
console.log()
|
|
224
|
-
console.log(chalk.gray(`注册账号: https://holysheep.ai`))
|
|
225
|
-
console.log()
|
|
226
|
-
}
|
package/src/tools/aider.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Aider 适配器
|
|
3
|
-
* Aider 是最流行的命令行 AI 结对编程工具
|
|
4
|
-
*
|
|
5
|
-
* 配置方式:
|
|
6
|
-
* 环境变量: AIDER_OPENAI_API_BASE + OPENAI_API_KEY
|
|
7
|
-
* 或: --openai-api-base + --anthropic-api-key
|
|
8
|
-
*
|
|
9
|
-
* Aider 支持 litellm 格式,可以接入任何 OpenAI 兼容端点
|
|
10
|
-
* 配置文件: ~/.aider.conf.yml
|
|
11
|
-
*/
|
|
12
|
-
const fs = require('fs')
|
|
13
|
-
const path = require('path')
|
|
14
|
-
const os = require('os')
|
|
15
|
-
|
|
16
|
-
const CONFIG_FILE = path.join(os.homedir(), '.aider.conf.yml')
|
|
17
|
-
|
|
18
|
-
function readConfig() {
|
|
19
|
-
try {
|
|
20
|
-
if (fs.existsSync(CONFIG_FILE)) return fs.readFileSync(CONFIG_FILE, 'utf8')
|
|
21
|
-
} catch {}
|
|
22
|
-
return ''
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function removeHsBlock(content) {
|
|
26
|
-
const lines = content.split('\n')
|
|
27
|
-
const result = []
|
|
28
|
-
let skip = false
|
|
29
|
-
for (const line of lines) {
|
|
30
|
-
if (line.includes('# holysheep-cli')) { skip = true; continue }
|
|
31
|
-
if (skip && line.startsWith('#')) { skip = false }
|
|
32
|
-
if (!skip) result.push(line)
|
|
33
|
-
}
|
|
34
|
-
return result.join('\n')
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
module.exports = {
|
|
38
|
-
name: 'Aider',
|
|
39
|
-
id: 'aider',
|
|
40
|
-
checkInstalled() {
|
|
41
|
-
return require('../utils/which').commandExists('aider')
|
|
42
|
-
},
|
|
43
|
-
isConfigured() {
|
|
44
|
-
const content = readConfig()
|
|
45
|
-
return content.includes('holysheep')
|
|
46
|
-
},
|
|
47
|
-
configure(apiKey, _baseUrlAnthropicNoV1, baseUrlOpenAI, primaryModel) {
|
|
48
|
-
let content = readConfig()
|
|
49
|
-
content = removeHsBlock(content)
|
|
50
|
-
// Aider 用 openai-api-base(OpenAI 兼容格式,带 /v1)
|
|
51
|
-
// model 格式: openai/<model-name> 表示使用 OpenAI 兼容接口
|
|
52
|
-
const model = primaryModel || 'claude-sonnet-4-6'
|
|
53
|
-
const block = `
|
|
54
|
-
# holysheep-cli managed — https://holysheep.ai
|
|
55
|
-
openai-api-key: ${apiKey}
|
|
56
|
-
openai-api-base: ${baseUrlOpenAI}
|
|
57
|
-
model: openai/${model}
|
|
58
|
-
`
|
|
59
|
-
content += block
|
|
60
|
-
fs.writeFileSync(CONFIG_FILE, content.trim() + '\n', 'utf8')
|
|
61
|
-
return { file: CONFIG_FILE, hot: false }
|
|
62
|
-
},
|
|
63
|
-
reset() {
|
|
64
|
-
let content = readConfig()
|
|
65
|
-
content = removeHsBlock(content)
|
|
66
|
-
fs.writeFileSync(CONFIG_FILE, content, 'utf8')
|
|
67
|
-
},
|
|
68
|
-
getConfigPath() { return CONFIG_FILE },
|
|
69
|
-
hint: '也可用 aider --openai-api-base https://api.holysheep.ai/v1',
|
|
70
|
-
launchCmd: 'aider',
|
|
71
|
-
installCmd: 'pip install aider-chat',
|
|
72
|
-
docsUrl: 'https://aider.chat',
|
|
73
|
-
envVars: (apiKey, baseUrlOpenAI) => ({
|
|
74
|
-
OPENAI_API_KEY: apiKey,
|
|
75
|
-
OPENAI_BASE_URL: baseUrlOpenAI,
|
|
76
|
-
AIDER_OPENAI_API_BASE: baseUrlOpenAI,
|
|
77
|
-
}),
|
|
78
|
-
}
|
package/src/tools/antigravity.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Antigravity 适配器 (Google Antigravity IDE)
|
|
3
|
-
*
|
|
4
|
-
* ⚠️ 重要:Antigravity 不支持自定义 API 代理
|
|
5
|
-
* 它使用 Google OAuth + 专有后端 (cloudcode-pa.googleapis.com),和 Gemini CLI 一样。
|
|
6
|
-
*
|
|
7
|
-
* HolySheep 暂不支持 Antigravity 中继。
|
|
8
|
-
* 建议用户使用 Claude Code / Codex / OpenCode / Aider 等支持中继的工具。
|
|
9
|
-
*/
|
|
10
|
-
'use strict'
|
|
11
|
-
|
|
12
|
-
const { commandExists } = require('../utils/which')
|
|
13
|
-
|
|
14
|
-
module.exports = {
|
|
15
|
-
name: 'Antigravity',
|
|
16
|
-
id: 'antigravity',
|
|
17
|
-
|
|
18
|
-
checkInstalled() {
|
|
19
|
-
return commandExists('agy')
|
|
20
|
-
},
|
|
21
|
-
|
|
22
|
-
isConfigured() {
|
|
23
|
-
return false
|
|
24
|
-
},
|
|
25
|
-
|
|
26
|
-
configure() {
|
|
27
|
-
return {
|
|
28
|
-
manual: true,
|
|
29
|
-
steps: [
|
|
30
|
-
'Antigravity 使用 Google OAuth 认证 + Google 专有后端,无法配置自定义 API 代理',
|
|
31
|
-
'建议使用 Claude Code / Codex / OpenCode / Aider 等支持自定义 API 的工具',
|
|
32
|
-
],
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
|
|
36
|
-
reset() {},
|
|
37
|
-
|
|
38
|
-
getConfigPath() { return null },
|
|
39
|
-
hint: 'Antigravity 使用 Google 专有协议,不支持 HolySheep 中继',
|
|
40
|
-
docsUrl: 'https://antigravity.google',
|
|
41
|
-
unsupported: true,
|
|
42
|
-
}
|
package/src/tools/claude-code.js
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude Code 适配器
|
|
3
|
-
* 配置文件: ~/.claude/settings.json
|
|
4
|
-
* 支持热切换(不需要重启终端)
|
|
5
|
-
*
|
|
6
|
-
* 官方 env 字段:
|
|
7
|
-
* ANTHROPIC_AUTH_TOKEN — API Key (优先级最高)
|
|
8
|
-
* ANTHROPIC_BASE_URL — 不带 /v1
|
|
9
|
-
* CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC — 关闭遥测/更新检查
|
|
10
|
-
*/
|
|
11
|
-
const fs = require('fs')
|
|
12
|
-
const path = require('path')
|
|
13
|
-
const os = require('os')
|
|
14
|
-
const crypto = require('crypto')
|
|
15
|
-
const { execSync } = require('child_process')
|
|
16
|
-
const {
|
|
17
|
-
BASE_URL_ANTHROPIC,
|
|
18
|
-
BASE_URL_CLAUDE_RELAY,
|
|
19
|
-
} = require('../utils/config')
|
|
20
|
-
const { readConfig, writeConfig } = require('./claude-process-proxy')
|
|
21
|
-
|
|
22
|
-
const SETTINGS_FILE = path.join(os.homedir(), '.claude', 'settings.json')
|
|
23
|
-
|
|
24
|
-
function buildBridgeConfig(apiKey, baseUrl, bridge = {}) {
|
|
25
|
-
const relayUrl = bridge.relayUrl || BASE_URL_CLAUDE_RELAY || ''
|
|
26
|
-
return {
|
|
27
|
-
port: bridge.port || 14555,
|
|
28
|
-
processProxyPort: bridge.processProxyPort || 14556,
|
|
29
|
-
apiKey,
|
|
30
|
-
baseUrlAnthropic: baseUrl || BASE_URL_ANTHROPIC,
|
|
31
|
-
controlPlaneUrl: bridge.controlPlaneUrl || relayUrl || baseUrl || BASE_URL_ANTHROPIC,
|
|
32
|
-
relayUrl: relayUrl || bridge.controlPlaneUrl || baseUrl || BASE_URL_ANTHROPIC,
|
|
33
|
-
bridgeId: bridge.bridgeId || crypto.randomUUID(),
|
|
34
|
-
deviceId: bridge.deviceId || crypto.randomUUID(),
|
|
35
|
-
bridgeSecret: bridge.bridgeSecret || crypto.randomBytes(32).toString('hex'),
|
|
36
|
-
nodeId: bridge.nodeId || '',
|
|
37
|
-
sessionMode: bridge.sessionMode || 'pinned-node',
|
|
38
|
-
installSource: bridge.installSource || 'holysheep-cli',
|
|
39
|
-
proxyMode: 'claude-process',
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function readSettings() {
|
|
44
|
-
try {
|
|
45
|
-
const raw = fs.readFileSync(SETTINGS_FILE, 'utf8')
|
|
46
|
-
// Claude 的 settings.json 可能有控制字符,用容错解析
|
|
47
|
-
return JSON.parse(raw.replace(/[\x00-\x1F\x7F]/g, ' '))
|
|
48
|
-
} catch {
|
|
49
|
-
return {}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function writeSettings(data) {
|
|
54
|
-
const dir = path.dirname(SETTINGS_FILE)
|
|
55
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })
|
|
56
|
-
fs.writeFileSync(SETTINGS_FILE, JSON.stringify(data, null, 2), 'utf8')
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function cloneSettings(data) {
|
|
60
|
-
return JSON.parse(JSON.stringify(data || {}))
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function applyRuntimeSettingsOverride(overrides = {}) {
|
|
64
|
-
const previous = readSettings()
|
|
65
|
-
const next = cloneSettings(previous)
|
|
66
|
-
next.env = { ...(next.env || {}) }
|
|
67
|
-
|
|
68
|
-
for (const [key, value] of Object.entries(overrides)) {
|
|
69
|
-
if (value === undefined || value === null) {
|
|
70
|
-
delete next.env[key]
|
|
71
|
-
continue
|
|
72
|
-
}
|
|
73
|
-
next.env[key] = value
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
writeSettings(next)
|
|
77
|
-
|
|
78
|
-
return () => {
|
|
79
|
-
writeSettings(previous)
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function resolveCommandPath(cmd) {
|
|
84
|
-
try {
|
|
85
|
-
if (process.platform === 'win32') {
|
|
86
|
-
const out = execSync(`where ${cmd}`, { stdio: 'pipe' }).toString().trim()
|
|
87
|
-
const first = out.split(/\r?\n/).find(Boolean)
|
|
88
|
-
return first ? fs.realpathSync(first) : null
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const out = execSync(`which ${cmd}`, { stdio: 'pipe' }).toString().trim()
|
|
92
|
-
const first = out.split(/\r?\n/).find(Boolean)
|
|
93
|
-
return first ? fs.realpathSync(first) : null
|
|
94
|
-
} catch {
|
|
95
|
-
return null
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function detectBinaryFormat(buffer) {
|
|
100
|
-
if (!buffer || buffer.length < 4) return null
|
|
101
|
-
if (buffer[0] === 0x23 && buffer[1] === 0x21) return 'script'
|
|
102
|
-
|
|
103
|
-
const magic = buffer.slice(0, 4).toString('hex')
|
|
104
|
-
if (magic === '7f454c46') return 'elf'
|
|
105
|
-
if (magic === 'feedface' || magic === 'feedfacf' || magic === 'cefaedfe' || magic === 'cffaedfe') return 'mach-o'
|
|
106
|
-
if (buffer[0] === 0x4d && buffer[1] === 0x5a) return 'pe'
|
|
107
|
-
|
|
108
|
-
return null
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function detectClaudeRuntime() {
|
|
112
|
-
const executablePath = resolveCommandPath('claude')
|
|
113
|
-
if (!executablePath) {
|
|
114
|
-
return {
|
|
115
|
-
available: false,
|
|
116
|
-
path: null,
|
|
117
|
-
kind: 'missing',
|
|
118
|
-
launchMode: 'unknown',
|
|
119
|
-
display: '未找到 claude',
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
const fd = fs.openSync(executablePath, 'r')
|
|
125
|
-
const buffer = Buffer.alloc(16)
|
|
126
|
-
fs.readSync(fd, buffer, 0, buffer.length, 0)
|
|
127
|
-
fs.closeSync(fd)
|
|
128
|
-
|
|
129
|
-
const format = detectBinaryFormat(buffer)
|
|
130
|
-
if (format === 'script') {
|
|
131
|
-
return {
|
|
132
|
-
available: true,
|
|
133
|
-
path: executablePath,
|
|
134
|
-
kind: 'script',
|
|
135
|
-
launchMode: 'node-inject',
|
|
136
|
-
display: '脚本入口(使用 NODE_OPTIONS 注入)',
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (format) {
|
|
141
|
-
return {
|
|
142
|
-
available: true,
|
|
143
|
-
path: executablePath,
|
|
144
|
-
kind: 'binary',
|
|
145
|
-
launchMode: 'env-proxy',
|
|
146
|
-
display: `独立二进制(${format},使用 HTTP(S)_PROXY)`,
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
} catch {}
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
available: true,
|
|
153
|
-
path: executablePath,
|
|
154
|
-
kind: 'unknown',
|
|
155
|
-
launchMode: 'env-proxy',
|
|
156
|
-
display: '未知入口类型(默认使用 HTTP(S)_PROXY)',
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
module.exports = {
|
|
161
|
-
name: 'Claude Code',
|
|
162
|
-
id: 'claude-code',
|
|
163
|
-
checkInstalled() {
|
|
164
|
-
return require('../utils/which').commandExists('claude')
|
|
165
|
-
},
|
|
166
|
-
isConfigured() {
|
|
167
|
-
const s = readSettings()
|
|
168
|
-
const bridge = readConfig()
|
|
169
|
-
return Boolean(
|
|
170
|
-
s.env?.ANTHROPIC_AUTH_TOKEN &&
|
|
171
|
-
bridge.apiKey &&
|
|
172
|
-
bridge.bridgeSecret &&
|
|
173
|
-
bridge.controlPlaneUrl &&
|
|
174
|
-
bridge.bridgeId &&
|
|
175
|
-
bridge.deviceId &&
|
|
176
|
-
bridge.processProxyPort
|
|
177
|
-
)
|
|
178
|
-
},
|
|
179
|
-
configure(apiKey, baseUrl, baseUrlOpenAI, primaryModel) {
|
|
180
|
-
const bridgeConfig = buildBridgeConfig(apiKey, baseUrl, readConfig())
|
|
181
|
-
writeConfig(bridgeConfig)
|
|
182
|
-
|
|
183
|
-
const settings = readSettings()
|
|
184
|
-
if (!settings.env) settings.env = {}
|
|
185
|
-
settings.env.ANTHROPIC_AUTH_TOKEN = apiKey
|
|
186
|
-
// ANTHROPIC_BASE_URL 不写入 settings.json,由 hs claude 运行时通过 env 动态注入
|
|
187
|
-
delete settings.env.ANTHROPIC_BASE_URL
|
|
188
|
-
settings.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1'
|
|
189
|
-
settings.env.HOLYSHEEP_CLAUDE_LAUNCHER = 'hs'
|
|
190
|
-
if (primaryModel) settings.model = primaryModel
|
|
191
|
-
// 清理旧的同义字段
|
|
192
|
-
delete settings.env.ANTHROPIC_API_KEY
|
|
193
|
-
delete settings.env.HOLYSHEEP_CLAUDE_BRIDGE
|
|
194
|
-
writeSettings(settings)
|
|
195
|
-
return {
|
|
196
|
-
file: SETTINGS_FILE,
|
|
197
|
-
hot: true,
|
|
198
|
-
extraFiles: ['~/.holysheep/claude-proxy.json'],
|
|
199
|
-
}
|
|
200
|
-
},
|
|
201
|
-
reset() {
|
|
202
|
-
const settings = readSettings()
|
|
203
|
-
if (settings.env) {
|
|
204
|
-
delete settings.env.ANTHROPIC_AUTH_TOKEN
|
|
205
|
-
delete settings.env.ANTHROPIC_API_KEY
|
|
206
|
-
delete settings.env.ANTHROPIC_BASE_URL
|
|
207
|
-
delete settings.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC
|
|
208
|
-
delete settings.env.HOLYSHEEP_CLAUDE_BRIDGE
|
|
209
|
-
delete settings.env.HOLYSHEEP_CLAUDE_LAUNCHER
|
|
210
|
-
}
|
|
211
|
-
writeSettings(settings)
|
|
212
|
-
},
|
|
213
|
-
getConfigPath() { return SETTINGS_FILE },
|
|
214
|
-
hint: '通过 hs claude 以整进程代理方式启动 Claude Code',
|
|
215
|
-
launchCmd: 'hs claude',
|
|
216
|
-
installCmd: process.platform === 'win32'
|
|
217
|
-
? 'irm https://claude.ai/install.ps1 | iex'
|
|
218
|
-
: 'curl -fsSL https://claude.ai/install.sh | bash',
|
|
219
|
-
docsUrl: 'https://docs.anthropic.com/claude-code',
|
|
220
|
-
getProcessProxyConfig() {
|
|
221
|
-
return readConfig()
|
|
222
|
-
},
|
|
223
|
-
buildBridgeConfig,
|
|
224
|
-
detectClaudeRuntime,
|
|
225
|
-
readSettings,
|
|
226
|
-
writeSettings,
|
|
227
|
-
applyRuntimeSettingsOverride,
|
|
228
|
-
}
|