@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/tools/droid.js
DELETED
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Droid CLI 适配器
|
|
3
|
-
* 配置文件: ~/.factory/settings.json
|
|
4
|
-
*
|
|
5
|
-
* 使用 Droid 原生 customModels 配置 HolySheep 的多个模型入口:
|
|
6
|
-
* - GPT 走 OpenAI 兼容入口: https://api.holysheep.ai/v1
|
|
7
|
-
* - Claude 走 Anthropic 入口: https://api.holysheep.ai
|
|
8
|
-
* - MiniMax 走 Anthropic 入口: https://api.holysheep.ai/minimax
|
|
9
|
-
*
|
|
10
|
-
* Droid 的 GPT-5+ BYOK 校验要求 provider=openai。
|
|
11
|
-
* Droid 当前会把这类模型发到 /responses,因此 baseUrl 仍然必须是
|
|
12
|
-
* https://api.holysheep.ai/v1,并依赖服务端将 gpt-5.4 的 Responses 请求
|
|
13
|
-
* 兼容桥接到 /v1/chat/completions。
|
|
14
|
-
*/
|
|
15
|
-
const fs = require('fs')
|
|
16
|
-
const path = require('path')
|
|
17
|
-
const os = require('os')
|
|
18
|
-
|
|
19
|
-
const CONFIG_DIR = path.join(os.homedir(), '.factory')
|
|
20
|
-
const SETTINGS_FILE = path.join(CONFIG_DIR, 'settings.json')
|
|
21
|
-
const LEGACY_CONFIG_FILE = path.join(CONFIG_DIR, 'config.json')
|
|
22
|
-
|
|
23
|
-
// Platform-specific install command. Windows previously read the macOS-only
|
|
24
|
-
// `brew install --cask droid` which always fails on fresh Win10/11 boxes —
|
|
25
|
-
// users reported this explicitly in 2.1.12/13. Factory ships an official
|
|
26
|
-
// winget package; Linux gets the official shell installer. macOS keeps brew.
|
|
27
|
-
function installCmdForPlatform() {
|
|
28
|
-
if (process.platform === 'win32') {
|
|
29
|
-
return 'winget install --id Factory.Droid -e --accept-source-agreements --accept-package-agreements'
|
|
30
|
-
}
|
|
31
|
-
if (process.platform === 'darwin') {
|
|
32
|
-
return 'brew install --cask droid'
|
|
33
|
-
}
|
|
34
|
-
// Linux — Factory's official installer supports Linux amd64/arm64.
|
|
35
|
-
return 'curl -fsSL https://app.factory.ai/install.sh | bash'
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const DEFAULT_MODELS = [
|
|
39
|
-
{
|
|
40
|
-
model: 'gpt-5.4',
|
|
41
|
-
id: 'custom:gpt-5.4-0',
|
|
42
|
-
baseUrlSuffix: '',
|
|
43
|
-
displayName: 'GPT-5.4',
|
|
44
|
-
provider: 'openai',
|
|
45
|
-
route: 'openai',
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
model: 'claude-sonnet-4-6',
|
|
49
|
-
id: 'custom:claude-sonnet-4-6-0',
|
|
50
|
-
baseUrlSuffix: '',
|
|
51
|
-
displayName: 'Sonnet 4.6',
|
|
52
|
-
provider: 'anthropic',
|
|
53
|
-
route: 'anthropic',
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
model: 'claude-opus-4-6',
|
|
57
|
-
id: 'custom:claude-opus-4-6-0',
|
|
58
|
-
baseUrlSuffix: '',
|
|
59
|
-
displayName: 'Opus 4.6',
|
|
60
|
-
provider: 'anthropic',
|
|
61
|
-
route: 'anthropic',
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
model: 'MiniMax-M2.7-highspeed',
|
|
65
|
-
id: 'custom:MiniMax-M2.7-highspeed-0',
|
|
66
|
-
baseUrlSuffix: '/minimax',
|
|
67
|
-
displayName: 'MiniMax 2.7 Highspeed',
|
|
68
|
-
provider: 'anthropic',
|
|
69
|
-
route: 'anthropic',
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
model: 'claude-haiku-4-5',
|
|
73
|
-
id: 'custom:claude-haiku-4-5-0',
|
|
74
|
-
baseUrlSuffix: '',
|
|
75
|
-
displayName: 'Haiku 4.5',
|
|
76
|
-
provider: 'anthropic',
|
|
77
|
-
route: 'anthropic',
|
|
78
|
-
},
|
|
79
|
-
]
|
|
80
|
-
|
|
81
|
-
function readSettings() {
|
|
82
|
-
try {
|
|
83
|
-
if (fs.existsSync(SETTINGS_FILE)) {
|
|
84
|
-
return JSON.parse(fs.readFileSync(SETTINGS_FILE, 'utf8'))
|
|
85
|
-
}
|
|
86
|
-
} catch {}
|
|
87
|
-
return {}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function writeSettings(data) {
|
|
91
|
-
fs.mkdirSync(CONFIG_DIR, { recursive: true })
|
|
92
|
-
fs.writeFileSync(SETTINGS_FILE, JSON.stringify(data, null, 2), 'utf8')
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function readLegacyConfig() {
|
|
96
|
-
try {
|
|
97
|
-
if (fs.existsSync(LEGACY_CONFIG_FILE)) {
|
|
98
|
-
return JSON.parse(fs.readFileSync(LEGACY_CONFIG_FILE, 'utf8'))
|
|
99
|
-
}
|
|
100
|
-
} catch {}
|
|
101
|
-
return {}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function writeLegacyConfig(data) {
|
|
105
|
-
fs.mkdirSync(CONFIG_DIR, { recursive: true })
|
|
106
|
-
fs.writeFileSync(LEGACY_CONFIG_FILE, JSON.stringify(data, null, 2), 'utf8')
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function isHolySheepModel(item) {
|
|
110
|
-
return typeof item?.baseUrl === 'string' && item.baseUrl.includes('api.holysheep.ai')
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function normalizeSelectedModels(selectedModels) {
|
|
114
|
-
const selected = new Set(
|
|
115
|
-
Array.isArray(selectedModels) && selectedModels.length > 0
|
|
116
|
-
? selectedModels
|
|
117
|
-
: DEFAULT_MODELS.map((item) => item.model)
|
|
118
|
-
)
|
|
119
|
-
const models = DEFAULT_MODELS.filter((item) => selected.has(item.model)).map((item, index) => ({
|
|
120
|
-
model: item.model,
|
|
121
|
-
id: item.id,
|
|
122
|
-
index,
|
|
123
|
-
baseUrlSuffix: item.baseUrlSuffix,
|
|
124
|
-
displayName: item.displayName,
|
|
125
|
-
provider: item.provider,
|
|
126
|
-
route: item.route,
|
|
127
|
-
}))
|
|
128
|
-
|
|
129
|
-
return models.length > 0 ? models : DEFAULT_MODELS.map((item, index) => ({ ...item, index }))
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function buildCustomModels(apiKey, baseUrlAnthropic, baseUrlOpenAI, selectedModels) {
|
|
133
|
-
const anthropicRootUrl = String(baseUrlAnthropic || '').replace(/\/+$/, '')
|
|
134
|
-
const openaiRootUrl = String(baseUrlOpenAI || '').replace(/\/+$/, '')
|
|
135
|
-
return normalizeSelectedModels(selectedModels).map((item) => ({
|
|
136
|
-
model: item.model,
|
|
137
|
-
id: item.id,
|
|
138
|
-
index: item.index,
|
|
139
|
-
baseUrl:
|
|
140
|
-
item.route === 'openai'
|
|
141
|
-
? `${openaiRootUrl}${item.baseUrlSuffix}`
|
|
142
|
-
: `${anthropicRootUrl}${item.baseUrlSuffix}`,
|
|
143
|
-
apiKey,
|
|
144
|
-
displayName: item.displayName,
|
|
145
|
-
maxOutputTokens: 64000,
|
|
146
|
-
noImageSupport: true,
|
|
147
|
-
provider: item.provider,
|
|
148
|
-
}))
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
module.exports = {
|
|
152
|
-
name: 'Droid CLI',
|
|
153
|
-
id: 'droid',
|
|
154
|
-
checkInstalled() {
|
|
155
|
-
return require('../utils/which').commandExists('droid')
|
|
156
|
-
},
|
|
157
|
-
isConfigured() {
|
|
158
|
-
const settings = readSettings()
|
|
159
|
-
const customModels = Array.isArray(settings.customModels) ? settings.customModels : []
|
|
160
|
-
if (customModels.some(isHolySheepModel)) return true
|
|
161
|
-
|
|
162
|
-
const legacy = readLegacyConfig()
|
|
163
|
-
const legacyModels = Array.isArray(legacy.customModels) ? legacy.customModels : []
|
|
164
|
-
return legacyModels.some(isHolySheepModel)
|
|
165
|
-
},
|
|
166
|
-
configure(apiKey, baseUrlAnthropic, baseUrlOpenAI, _primaryModel, selectedModels) {
|
|
167
|
-
const nextModels = buildCustomModels(apiKey, baseUrlAnthropic, baseUrlOpenAI, selectedModels)
|
|
168
|
-
|
|
169
|
-
// [HolySheep fork v2.1.19] Pick a preferred default model. Droid CLI hardcodes
|
|
170
|
-
// `claude-opus-4-6` as the default when `sessionDefaultSettings.model` is
|
|
171
|
-
// absent, and HolySheep upstream often has no opus accounts available —
|
|
172
|
-
// producing "503 No available Claude accounts support claude-opus-4-6" in
|
|
173
|
-
// hs web. Prefer sonnet-4-6 when present; fall back to the first HolySheep
|
|
174
|
-
// model so the user at least lands on a working route.
|
|
175
|
-
const preferredDefault =
|
|
176
|
-
nextModels.find((m) => m.id === 'custom:claude-sonnet-4-6-0') ||
|
|
177
|
-
nextModels.find((m) => /sonnet/i.test(m.model)) ||
|
|
178
|
-
nextModels[0]
|
|
179
|
-
const defaultModelId = preferredDefault ? preferredDefault.id : null
|
|
180
|
-
|
|
181
|
-
const settings = readSettings()
|
|
182
|
-
const preservedModels = Array.isArray(settings.customModels)
|
|
183
|
-
? settings.customModels.filter((item) => !isHolySheepModel(item))
|
|
184
|
-
: []
|
|
185
|
-
settings.customModels = [
|
|
186
|
-
...nextModels,
|
|
187
|
-
...preservedModels,
|
|
188
|
-
]
|
|
189
|
-
settings.logoAnimation = 'off'
|
|
190
|
-
if (defaultModelId) {
|
|
191
|
-
settings.sessionDefaultSettings = {
|
|
192
|
-
...(settings.sessionDefaultSettings || {}),
|
|
193
|
-
model: defaultModelId,
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
writeSettings(settings)
|
|
197
|
-
|
|
198
|
-
const legacy = readLegacyConfig()
|
|
199
|
-
const preservedLegacyModels = Array.isArray(legacy.customModels)
|
|
200
|
-
? legacy.customModels.filter((item) => !isHolySheepModel(item))
|
|
201
|
-
: []
|
|
202
|
-
legacy.customModels = [
|
|
203
|
-
...nextModels,
|
|
204
|
-
...preservedLegacyModels,
|
|
205
|
-
]
|
|
206
|
-
legacy.logoAnimation = 'off'
|
|
207
|
-
if (defaultModelId) {
|
|
208
|
-
legacy.sessionDefaultSettings = {
|
|
209
|
-
...(legacy.sessionDefaultSettings || {}),
|
|
210
|
-
model: defaultModelId,
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
writeLegacyConfig(legacy)
|
|
214
|
-
|
|
215
|
-
// Windows: also write FACTORY_API_KEY to user env via setx so a freshly
|
|
216
|
-
// opened PowerShell / cmd.exe picks it up without requiring the user to
|
|
217
|
-
// manually edit env vars. Non-Windows shells don't need this because the
|
|
218
|
-
// config.json → settings.json path already wires the key through Factory's
|
|
219
|
-
// own auth resolution.
|
|
220
|
-
if (process.platform === 'win32') {
|
|
221
|
-
try {
|
|
222
|
-
const { execSync } = require('child_process')
|
|
223
|
-
execSync(`setx FACTORY_API_KEY "${apiKey}"`, { stdio: 'ignore', timeout: 10000 })
|
|
224
|
-
} catch {
|
|
225
|
-
// setx can fail in locked-down corp images; best-effort only.
|
|
226
|
-
// The settings.json / config.json path still works inside Droid CLI itself.
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return {
|
|
231
|
-
file: SETTINGS_FILE,
|
|
232
|
-
hot: true,
|
|
233
|
-
}
|
|
234
|
-
},
|
|
235
|
-
reset() {
|
|
236
|
-
const settings = readSettings()
|
|
237
|
-
// Collect ids of HolySheep customModels BEFORE filtering so we can clean
|
|
238
|
-
// up any sessionDefaultSettings.model pointing at them.
|
|
239
|
-
const hsIds = new Set(
|
|
240
|
-
(Array.isArray(settings.customModels) ? settings.customModels : [])
|
|
241
|
-
.filter(isHolySheepModel)
|
|
242
|
-
.map((m) => m?.id)
|
|
243
|
-
.filter(Boolean)
|
|
244
|
-
)
|
|
245
|
-
if (Array.isArray(settings.customModels)) {
|
|
246
|
-
settings.customModels = settings.customModels.filter((item) => !isHolySheepModel(item))
|
|
247
|
-
}
|
|
248
|
-
if (
|
|
249
|
-
settings.sessionDefaultSettings &&
|
|
250
|
-
typeof settings.sessionDefaultSettings === 'object' &&
|
|
251
|
-
hsIds.has(settings.sessionDefaultSettings.model)
|
|
252
|
-
) {
|
|
253
|
-
delete settings.sessionDefaultSettings.model
|
|
254
|
-
}
|
|
255
|
-
writeSettings(settings)
|
|
256
|
-
|
|
257
|
-
const legacy = readLegacyConfig()
|
|
258
|
-
const hsLegacyIds = new Set(
|
|
259
|
-
(Array.isArray(legacy.customModels) ? legacy.customModels : [])
|
|
260
|
-
.filter(isHolySheepModel)
|
|
261
|
-
.map((m) => m?.id)
|
|
262
|
-
.filter(Boolean)
|
|
263
|
-
)
|
|
264
|
-
if (Array.isArray(legacy.customModels)) {
|
|
265
|
-
legacy.customModels = legacy.customModels.filter((item) => !isHolySheepModel(item))
|
|
266
|
-
}
|
|
267
|
-
if (
|
|
268
|
-
legacy.sessionDefaultSettings &&
|
|
269
|
-
typeof legacy.sessionDefaultSettings === 'object' &&
|
|
270
|
-
hsLegacyIds.has(legacy.sessionDefaultSettings.model)
|
|
271
|
-
) {
|
|
272
|
-
delete legacy.sessionDefaultSettings.model
|
|
273
|
-
}
|
|
274
|
-
writeLegacyConfig(legacy)
|
|
275
|
-
},
|
|
276
|
-
getConfigPath() { return SETTINGS_FILE },
|
|
277
|
-
hint: '已写入 ~/.factory/settings.json;重启 Droid 后可见 HolySheep 模型列表',
|
|
278
|
-
launchCmd: 'droid',
|
|
279
|
-
installCmd: installCmdForPlatform(),
|
|
280
|
-
docsUrl: 'https://docs.factory.ai/cli/getting-started/overview',
|
|
281
|
-
}
|
package/src/tools/env-config.js
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 全局环境变量适配器
|
|
3
|
-
*
|
|
4
|
-
* 一键将 HolySheep API 配置写入系统环境变量,
|
|
5
|
-
* 让所有读取标准 env 的编程工具(VS Code Claude 扩展、Cursor、Continue、Cline、Windsurf 等)
|
|
6
|
-
* 无需单独配置即可使用 HolySheep 中继。
|
|
7
|
-
*
|
|
8
|
-
* 写入的环境变量:
|
|
9
|
-
* ANTHROPIC_API_KEY — Anthropic SDK 标准 key
|
|
10
|
-
* ANTHROPIC_AUTH_TOKEN — Claude Code 优先读取
|
|
11
|
-
* ANTHROPIC_BASE_URL — Anthropic API 基地址(不带 /v1)
|
|
12
|
-
* OPENAI_API_KEY — OpenAI SDK 标准 key
|
|
13
|
-
* OPENAI_BASE_URL — OpenAI API 基地址(带 /v1)
|
|
14
|
-
*
|
|
15
|
-
* Mac/Linux: 写入 .zshrc / .bashrc / config.fish(holysheep managed 块)
|
|
16
|
-
* Windows: 通过 setx 写入用户级环境变量(需重启终端生效)
|
|
17
|
-
*/
|
|
18
|
-
'use strict'
|
|
19
|
-
|
|
20
|
-
const { writeEnvToShell, removeEnvFromShell, getShellRcFiles } = require('../utils/shell')
|
|
21
|
-
const { execSync } = require('child_process')
|
|
22
|
-
const fs = require('fs')
|
|
23
|
-
const path = require('path')
|
|
24
|
-
const os = require('os')
|
|
25
|
-
|
|
26
|
-
const MANAGED_KEYS = [
|
|
27
|
-
'ANTHROPIC_API_KEY',
|
|
28
|
-
'ANTHROPIC_AUTH_TOKEN',
|
|
29
|
-
'ANTHROPIC_BASE_URL',
|
|
30
|
-
'OPENAI_API_KEY',
|
|
31
|
-
'OPENAI_BASE_URL',
|
|
32
|
-
]
|
|
33
|
-
|
|
34
|
-
const MARKER = '# >>> holysheep-cli managed >>>'
|
|
35
|
-
const STATE_FILE = path.join(os.homedir(), '.holysheep', 'env-config.json')
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Windows: 用 PowerShell 写入用户级环境变量(比 setx 更可靠)
|
|
39
|
-
*/
|
|
40
|
-
function winSetEnvVar(key, value) {
|
|
41
|
-
try {
|
|
42
|
-
execSync(
|
|
43
|
-
`powershell.exe -NoProfile -Command "[Environment]::SetEnvironmentVariable('${key}', '${value}', 'User')"`,
|
|
44
|
-
{ stdio: 'ignore', timeout: 10000, windowsHide: true }
|
|
45
|
-
)
|
|
46
|
-
return true
|
|
47
|
-
} catch {
|
|
48
|
-
return false
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Windows: 用 PowerShell 删除用户级环境变量
|
|
54
|
-
*/
|
|
55
|
-
function winRemoveEnvVar(key) {
|
|
56
|
-
try {
|
|
57
|
-
execSync(
|
|
58
|
-
`powershell.exe -NoProfile -Command "[Environment]::SetEnvironmentVariable('${key}', $null, 'User')"`,
|
|
59
|
-
{ stdio: 'ignore', timeout: 10000, windowsHide: true }
|
|
60
|
-
)
|
|
61
|
-
} catch {}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Windows: 用 PowerShell 读取用户级环境变量
|
|
66
|
-
*/
|
|
67
|
-
function winGetEnvVar(key) {
|
|
68
|
-
try {
|
|
69
|
-
const out = execSync(
|
|
70
|
-
`powershell.exe -NoProfile -Command "[Environment]::GetEnvironmentVariable('${key}', 'User')"`,
|
|
71
|
-
{ encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 5000, windowsHide: true }
|
|
72
|
-
)
|
|
73
|
-
const val = (out || '').trim()
|
|
74
|
-
return val || null
|
|
75
|
-
} catch {
|
|
76
|
-
return null
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function isConfiguredInShell() {
|
|
81
|
-
if (process.platform === 'win32') {
|
|
82
|
-
const val = winGetEnvVar('ANTHROPIC_BASE_URL')
|
|
83
|
-
return !!(val && val.includes('holysheep'))
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Mac/Linux: 检查 shell rc 文件里是否有 managed 块
|
|
87
|
-
try {
|
|
88
|
-
const files = getShellRcFiles()
|
|
89
|
-
for (const file of files) {
|
|
90
|
-
try {
|
|
91
|
-
const content = fs.readFileSync(file, 'utf8')
|
|
92
|
-
if (content.includes(MARKER) && content.includes('holysheep')) {
|
|
93
|
-
return true
|
|
94
|
-
}
|
|
95
|
-
} catch {}
|
|
96
|
-
}
|
|
97
|
-
} catch {}
|
|
98
|
-
return false
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function saveState(envVars) {
|
|
102
|
-
try {
|
|
103
|
-
const dir = path.dirname(STATE_FILE)
|
|
104
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })
|
|
105
|
-
fs.writeFileSync(STATE_FILE, JSON.stringify({ configuredAt: new Date().toISOString(), keys: Object.keys(envVars) }, null, 2), 'utf8')
|
|
106
|
-
} catch {}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function clearState() {
|
|
110
|
-
try { fs.unlinkSync(STATE_FILE) } catch {}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
module.exports = {
|
|
114
|
-
name: '全局环境变量',
|
|
115
|
-
id: 'env-config',
|
|
116
|
-
|
|
117
|
-
checkInstalled() {
|
|
118
|
-
return true // 不依赖任何 CLI,总是可用
|
|
119
|
-
},
|
|
120
|
-
|
|
121
|
-
isConfigured() {
|
|
122
|
-
return isConfiguredInShell()
|
|
123
|
-
},
|
|
124
|
-
|
|
125
|
-
configure(apiKey, baseUrlAnthropic, baseUrlOpenAI) {
|
|
126
|
-
const envVars = {
|
|
127
|
-
ANTHROPIC_API_KEY: apiKey,
|
|
128
|
-
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
129
|
-
ANTHROPIC_BASE_URL: baseUrlAnthropic,
|
|
130
|
-
OPENAI_API_KEY: apiKey,
|
|
131
|
-
OPENAI_BASE_URL: baseUrlOpenAI,
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
let written
|
|
135
|
-
if (process.platform === 'win32') {
|
|
136
|
-
// Windows: 用 PowerShell 直接写用户级环境变量
|
|
137
|
-
written = []
|
|
138
|
-
for (const [k, v] of Object.entries(envVars)) {
|
|
139
|
-
if (winSetEnvVar(k, v)) {
|
|
140
|
-
written.push(k)
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
} else {
|
|
144
|
-
// Mac/Linux: 写入 shell rc 文件
|
|
145
|
-
written = writeEnvToShell(envVars)
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
saveState(envVars)
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
file: written.join(', ') || 'shell env',
|
|
152
|
-
hot: false,
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
|
|
156
|
-
reset() {
|
|
157
|
-
if (process.platform === 'win32') {
|
|
158
|
-
for (const k of MANAGED_KEYS) winRemoveEnvVar(k)
|
|
159
|
-
} else {
|
|
160
|
-
removeEnvFromShell(MANAGED_KEYS)
|
|
161
|
-
}
|
|
162
|
-
clearState()
|
|
163
|
-
},
|
|
164
|
-
|
|
165
|
-
getConfigPath() { return null },
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* 获取已配置的环境变量值(Windows 从注册表读,其他从 process.env 读)
|
|
169
|
-
*/
|
|
170
|
-
getConfiguredValues() {
|
|
171
|
-
const result = {}
|
|
172
|
-
for (const key of MANAGED_KEYS) {
|
|
173
|
-
if (process.platform === 'win32') {
|
|
174
|
-
result[key] = winGetEnvVar(key) || null
|
|
175
|
-
} else {
|
|
176
|
-
result[key] = process.env[key] || null
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
return result
|
|
180
|
-
},
|
|
181
|
-
|
|
182
|
-
hint: '一键配置全局终端环境变量(ANTHROPIC / OPENAI API Key + Base URL)',
|
|
183
|
-
launchCmd: null,
|
|
184
|
-
docsUrl: 'https://holysheep.ai',
|
|
185
|
-
}
|
package/src/tools/gemini-cli.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Gemini CLI 适配器 (@google/gemini-cli)
|
|
3
|
-
*
|
|
4
|
-
* ⚠️ 重要:Gemini CLI 不支持自定义 base_url/中继
|
|
5
|
-
* 它只能连接 Google 官方 Gemini API。
|
|
6
|
-
*
|
|
7
|
-
* 配置方式:
|
|
8
|
-
* 1. settings.json 写入 selectedAuthType = "gemini-api-key"(跳过登录向导)
|
|
9
|
-
* 2. 设置环境变量 GEMINI_API_KEY(需要 Google Gemini API Key,从 aistudio.google.com 获取)
|
|
10
|
-
*
|
|
11
|
-
* HolySheep 暂不支持 Gemini CLI 中继(Gemini CLI 使用 Google 专有协议,非 OpenAI 兼容格式)
|
|
12
|
-
* 建议用户使用 Claude Code / Codex / Aider 等支持中继的工具。
|
|
13
|
-
*/
|
|
14
|
-
const fs = require('fs')
|
|
15
|
-
const path = require('path')
|
|
16
|
-
const os = require('os')
|
|
17
|
-
|
|
18
|
-
const GEMINI_DIR = path.join(os.homedir(), '.gemini')
|
|
19
|
-
const SETTINGS_FILE = path.join(GEMINI_DIR, 'settings.json')
|
|
20
|
-
|
|
21
|
-
function readSettings() {
|
|
22
|
-
try {
|
|
23
|
-
if (fs.existsSync(SETTINGS_FILE)) {
|
|
24
|
-
return JSON.parse(fs.readFileSync(SETTINGS_FILE, 'utf8'))
|
|
25
|
-
}
|
|
26
|
-
} catch {}
|
|
27
|
-
return {}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function writeSettings(data) {
|
|
31
|
-
if (!fs.existsSync(GEMINI_DIR)) fs.mkdirSync(GEMINI_DIR, { recursive: true })
|
|
32
|
-
fs.writeFileSync(SETTINGS_FILE, JSON.stringify(data, null, 2), 'utf8')
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
module.exports = {
|
|
36
|
-
name: 'Gemini CLI',
|
|
37
|
-
id: 'gemini-cli',
|
|
38
|
-
|
|
39
|
-
checkInstalled() {
|
|
40
|
-
return require('../utils/which').commandExists('gemini')
|
|
41
|
-
},
|
|
42
|
-
|
|
43
|
-
isConfigured() {
|
|
44
|
-
// 检查是否设置了 GEMINI_API_KEY 环境变量
|
|
45
|
-
if (process.env.GEMINI_API_KEY) return true
|
|
46
|
-
// 检查 settings.json 是否已跳过向导
|
|
47
|
-
const s = readSettings()
|
|
48
|
-
return s.selectedAuthType === 'gemini-api-key'
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
configure(apiKey, _baseUrlAnthropicNoV1, _baseUrlOpenAI) {
|
|
52
|
-
// Gemini CLI 不支持 HolySheep 中继,只能配置为使用官方 Gemini API Key 模式
|
|
53
|
-
// 写入 settings.json 跳过认证向导
|
|
54
|
-
const settings = readSettings()
|
|
55
|
-
settings.selectedAuthType = 'gemini-api-key'
|
|
56
|
-
writeSettings(settings)
|
|
57
|
-
|
|
58
|
-
// 环境变量:GEMINI_API_KEY 需要用户自己的 Google Gemini API Key
|
|
59
|
-
// HolySheep API Key (cr_xxx) 无法用于 Gemini CLI
|
|
60
|
-
return {
|
|
61
|
-
file: SETTINGS_FILE,
|
|
62
|
-
hot: false,
|
|
63
|
-
// 不注入 GEMINI_API_KEY,因为 HolySheep key 对 Gemini CLI 无效
|
|
64
|
-
// 用户需要手动设置真正的 Gemini API Key
|
|
65
|
-
envVars: {},
|
|
66
|
-
warning: 'Gemini CLI 需要 Google 官方 Gemini API Key,无法使用 HolySheep 中继。\n请从 https://aistudio.google.com/apikey 获取 API Key 后设置环境变量:\n export GEMINI_API_KEY="your-google-api-key"',
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
reset() {
|
|
71
|
-
const settings = readSettings()
|
|
72
|
-
delete settings.selectedAuthType
|
|
73
|
-
writeSettings(settings)
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
getConfigPath() { return SETTINGS_FILE },
|
|
77
|
-
hint: 'Gemini CLI 不支持 HolySheep 中继,需使用 Google 官方 Gemini API Key',
|
|
78
|
-
installCmd: 'npm install -g @google/gemini-cli',
|
|
79
|
-
docsUrl: 'https://github.com/google-gemini/gemini-cli',
|
|
80
|
-
envVarFormat: 'gemini',
|
|
81
|
-
unsupported: true, // 标记为不支持中继
|
|
82
|
-
}
|