@simonyea/holysheep-cli 2.1.40 → 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 +20 -7
- 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 -176
- 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 -1572
- 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/codex.js
DELETED
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Codex CLI 适配器 (@openai/codex v0.111+, Rust 版)
|
|
3
|
-
*
|
|
4
|
-
* ⚠️ 重要:v0.111.0 起 Codex 已切换到 Rust 实现(codex-rs)
|
|
5
|
-
* 配置文件变更:~/.codex/config.toml(TOML 格式,不是 JSON!)
|
|
6
|
-
*
|
|
7
|
-
* 正确格式(config.toml):
|
|
8
|
-
*
|
|
9
|
-
* model = "gpt-5.4"
|
|
10
|
-
* model_provider = "holysheep"
|
|
11
|
-
*
|
|
12
|
-
* [model_providers.holysheep]
|
|
13
|
-
* name = "HolySheep"
|
|
14
|
-
* base_url = "https://api.holysheep.ai/v1"
|
|
15
|
-
* wire_api = "responses"
|
|
16
|
-
*
|
|
17
|
-
* [model_providers.holysheep.http_headers]
|
|
18
|
-
* Authorization = "Bearer cr_xxx"
|
|
19
|
-
*
|
|
20
|
-
* 注意:Codex RS 不支持 api_key 字段,env_key 需要环境变量(Windows 需重启终端)。
|
|
21
|
-
* 改用 http_headers 直接设置 Authorization header,配置即生效。
|
|
22
|
-
*/
|
|
23
|
-
const fs = require('fs')
|
|
24
|
-
const path = require('path')
|
|
25
|
-
const os = require('os')
|
|
26
|
-
|
|
27
|
-
const CONFIG_DIR = path.join(os.homedir(), '.codex')
|
|
28
|
-
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.toml')
|
|
29
|
-
// 保留 JSON 兼容性(老版本 TypeScript Codex 用)
|
|
30
|
-
const CONFIG_FILE_JSON = path.join(CONFIG_DIR, 'config.json')
|
|
31
|
-
const AUTH_FILE = path.join(CONFIG_DIR, 'auth.json')
|
|
32
|
-
|
|
33
|
-
function normalizeToml(content) {
|
|
34
|
-
return String(content || '').replace(/\r\n/g, '\n')
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function cleanupToml(content) {
|
|
38
|
-
return normalizeToml(content)
|
|
39
|
-
.replace(/\n{3,}/g, '\n\n')
|
|
40
|
-
.trim()
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function stripManagedTomlConfig(content) {
|
|
44
|
-
const lines = normalizeToml(content).split('\n')
|
|
45
|
-
const output = []
|
|
46
|
-
let currentSection = null
|
|
47
|
-
let skipHolySheepBlock = false
|
|
48
|
-
|
|
49
|
-
for (const line of lines) {
|
|
50
|
-
const trimmed = line.trim()
|
|
51
|
-
|
|
52
|
-
if (/^\[[^\]]+\]$/.test(trimmed)) {
|
|
53
|
-
if (trimmed === '[model_providers.holysheep]' ||
|
|
54
|
-
trimmed === '[model_providers.holysheep.http_headers]') {
|
|
55
|
-
currentSection = trimmed
|
|
56
|
-
skipHolySheepBlock = true
|
|
57
|
-
continue
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
currentSection = trimmed
|
|
61
|
-
skipHolySheepBlock = false
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (skipHolySheepBlock) continue
|
|
65
|
-
|
|
66
|
-
if (!currentSection) {
|
|
67
|
-
if (/^model\s*=\s*"[^"]*"\s*$/.test(trimmed)) continue
|
|
68
|
-
if (/^model_provider\s*=/.test(trimmed)) continue
|
|
69
|
-
if (/^preferred_auth_method\s*=/.test(trimmed)) continue
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
output.push(line)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return cleanupToml(output.join('\n'))
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* 读取 TOML config(简单解析,不依赖 toml 库)
|
|
80
|
-
*/
|
|
81
|
-
function readTomlConfig() {
|
|
82
|
-
try {
|
|
83
|
-
if (fs.existsSync(CONFIG_FILE)) {
|
|
84
|
-
return fs.readFileSync(CONFIG_FILE, 'utf8')
|
|
85
|
-
}
|
|
86
|
-
} catch {}
|
|
87
|
-
return ''
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* 检查 TOML 里是否已配置 holysheep
|
|
92
|
-
*/
|
|
93
|
-
function isConfiguredInToml() {
|
|
94
|
-
const content = readTomlConfig()
|
|
95
|
-
return content.includes('model_provider = "holysheep"') &&
|
|
96
|
-
content.includes('base_url') &&
|
|
97
|
-
content.includes('holysheep.ai')
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* 写入 TOML config(合并方式:保留已有内容,只更新 holysheep 部分)
|
|
102
|
-
*/
|
|
103
|
-
function writeTomlConfig(apiKey, baseUrlOpenAI, model) {
|
|
104
|
-
if (!fs.existsSync(CONFIG_DIR)) {
|
|
105
|
-
fs.mkdirSync(CONFIG_DIR, { recursive: true })
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const content = stripManagedTomlConfig(readTomlConfig())
|
|
109
|
-
|
|
110
|
-
// 在开头插入 holysheep 配置
|
|
111
|
-
// 使用 http_headers 直接设置 Authorization,不依赖环境变量
|
|
112
|
-
const newConfig = [
|
|
113
|
-
`model = "${model || 'gpt-5.4'}"`,
|
|
114
|
-
`model_provider = "holysheep"`,
|
|
115
|
-
'',
|
|
116
|
-
content,
|
|
117
|
-
'',
|
|
118
|
-
`[model_providers.holysheep]`,
|
|
119
|
-
`name = "HolySheep"`,
|
|
120
|
-
`base_url = "${baseUrlOpenAI}"`,
|
|
121
|
-
`wire_api = "responses"`,
|
|
122
|
-
'',
|
|
123
|
-
`[model_providers.holysheep.http_headers]`,
|
|
124
|
-
`Authorization = "Bearer ${apiKey}"`,
|
|
125
|
-
'',
|
|
126
|
-
].join('\n')
|
|
127
|
-
|
|
128
|
-
fs.writeFileSync(CONFIG_FILE, cleanupToml(newConfig) + '\n', 'utf8')
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* 同时写 JSON(兼容旧版 TypeScript Codex,如果存在的话)
|
|
133
|
-
*/
|
|
134
|
-
function writeJsonConfigIfNeeded(apiKey, baseUrlOpenAI, model) {
|
|
135
|
-
try {
|
|
136
|
-
let jsonConfig = {}
|
|
137
|
-
if (fs.existsSync(CONFIG_FILE_JSON)) {
|
|
138
|
-
jsonConfig = JSON.parse(fs.readFileSync(CONFIG_FILE_JSON, 'utf8'))
|
|
139
|
-
}
|
|
140
|
-
jsonConfig.model = model || 'gpt-5.4'
|
|
141
|
-
jsonConfig.model_provider = 'holysheep'
|
|
142
|
-
jsonConfig.provider = 'holysheep'
|
|
143
|
-
if (!jsonConfig.model_providers) jsonConfig.model_providers = {}
|
|
144
|
-
if (!jsonConfig.providers) jsonConfig.providers = {}
|
|
145
|
-
jsonConfig.model_providers.holysheep = {
|
|
146
|
-
name: 'HolySheep',
|
|
147
|
-
base_url: baseUrlOpenAI,
|
|
148
|
-
api_key: apiKey,
|
|
149
|
-
wire_api: 'responses',
|
|
150
|
-
}
|
|
151
|
-
jsonConfig.providers.holysheep = {
|
|
152
|
-
name: 'HolySheep',
|
|
153
|
-
baseURL: baseUrlOpenAI,
|
|
154
|
-
apiKey: apiKey,
|
|
155
|
-
}
|
|
156
|
-
fs.writeFileSync(CONFIG_FILE_JSON, JSON.stringify(jsonConfig, null, 2), 'utf8')
|
|
157
|
-
} catch {}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* 清除 auth.json 中的 ChatGPT OAuth 认证,避免干扰 holysheep provider
|
|
162
|
-
* Codex RS bug: auth_mode=chatgpt 时 OAuth token 会覆盖自定义 provider 的 api_key
|
|
163
|
-
*
|
|
164
|
-
* Windows: Defender occasionally holds an open handle to auth.json during the
|
|
165
|
-
* first post-install scan, so an immediate `unlinkSync` returns EBUSY. Retry
|
|
166
|
-
* up to 5 times with a short backoff. On non-Windows a single pass suffices.
|
|
167
|
-
*/
|
|
168
|
-
function neutralizeAuthJson() {
|
|
169
|
-
const MAX_ATTEMPTS = process.platform === 'win32' ? 5 : 1
|
|
170
|
-
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
171
|
-
try {
|
|
172
|
-
fs.unlinkSync(AUTH_FILE)
|
|
173
|
-
return
|
|
174
|
-
} catch (e) {
|
|
175
|
-
if (e && e.code === 'ENOENT') return // already gone — success
|
|
176
|
-
if (attempt === MAX_ATTEMPTS) {
|
|
177
|
-
// Last try failed — on Windows fall back to truncating the file to
|
|
178
|
-
// an empty JSON object. Codex RS treats `{}` as "no chatgpt session",
|
|
179
|
-
// so the config.toml's `http_headers.Authorization` takes over.
|
|
180
|
-
try { fs.writeFileSync(AUTH_FILE, '{}\n', 'utf8') } catch {}
|
|
181
|
-
return
|
|
182
|
-
}
|
|
183
|
-
// Sleep ~200ms via a synchronous shell command. We avoid pulling in a
|
|
184
|
-
// new dep or using Atomics.wait here to keep the tool footprint small.
|
|
185
|
-
try {
|
|
186
|
-
require('child_process').execSync(
|
|
187
|
-
process.platform === 'win32'
|
|
188
|
-
? 'powershell -NoProfile -Command "Start-Sleep -Milliseconds 200"'
|
|
189
|
-
: 'sleep 0.2',
|
|
190
|
-
{ stdio: 'ignore' }
|
|
191
|
-
)
|
|
192
|
-
} catch {}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
module.exports = {
|
|
198
|
-
name: 'Codex CLI',
|
|
199
|
-
id: 'codex',
|
|
200
|
-
checkInstalled() {
|
|
201
|
-
return require('../utils/which').commandExists('codex')
|
|
202
|
-
},
|
|
203
|
-
isConfigured() {
|
|
204
|
-
return isConfiguredInToml()
|
|
205
|
-
},
|
|
206
|
-
configure(apiKey, _baseUrlAnthropicNoV1, baseUrlOpenAI) {
|
|
207
|
-
const model = 'gpt-5.4'
|
|
208
|
-
|
|
209
|
-
// 写入 TOML(Rust Codex v0.111+ 使用)
|
|
210
|
-
// Codex RS 不支持 api_key 字段,必须用 env_key 指向环境变量
|
|
211
|
-
writeTomlConfig(apiKey, baseUrlOpenAI, model)
|
|
212
|
-
|
|
213
|
-
// 同时写 JSON(兼容旧版 TypeScript Codex)
|
|
214
|
-
writeJsonConfigIfNeeded(apiKey, baseUrlOpenAI, model)
|
|
215
|
-
|
|
216
|
-
// 清除 auth.json 中的 ChatGPT OAuth 认证,避免干扰
|
|
217
|
-
neutralizeAuthJson()
|
|
218
|
-
|
|
219
|
-
return {
|
|
220
|
-
file: CONFIG_FILE,
|
|
221
|
-
hot: false,
|
|
222
|
-
}
|
|
223
|
-
},
|
|
224
|
-
reset() {
|
|
225
|
-
// 清理 TOML
|
|
226
|
-
if (fs.existsSync(CONFIG_FILE)) {
|
|
227
|
-
const content = stripManagedTomlConfig(readTomlConfig())
|
|
228
|
-
fs.writeFileSync(CONFIG_FILE, (content ? content + '\n' : ''), 'utf8')
|
|
229
|
-
}
|
|
230
|
-
// 清理 JSON
|
|
231
|
-
if (fs.existsSync(CONFIG_FILE_JSON)) {
|
|
232
|
-
try {
|
|
233
|
-
const c = JSON.parse(fs.readFileSync(CONFIG_FILE_JSON, 'utf8'))
|
|
234
|
-
if (c.model_provider === 'holysheep') {
|
|
235
|
-
delete c.model_provider
|
|
236
|
-
}
|
|
237
|
-
if (c.provider === 'holysheep') {
|
|
238
|
-
delete c.provider
|
|
239
|
-
}
|
|
240
|
-
delete c.model_providers?.holysheep
|
|
241
|
-
delete c.providers?.holysheep
|
|
242
|
-
if (c.model_providers && Object.keys(c.model_providers).length === 0) delete c.model_providers
|
|
243
|
-
if (c.providers && Object.keys(c.providers).length === 0) delete c.providers
|
|
244
|
-
fs.writeFileSync(CONFIG_FILE_JSON, JSON.stringify(c, null, 2), 'utf8')
|
|
245
|
-
} catch {}
|
|
246
|
-
}
|
|
247
|
-
},
|
|
248
|
-
getConfigPath() { return CONFIG_FILE },
|
|
249
|
-
hint: '切换后重开终端生效;Rust Codex (v0.111+) 使用 config.toml',
|
|
250
|
-
launchCmd: 'codex',
|
|
251
|
-
installCmd: 'npm install -g @openai/codex',
|
|
252
|
-
docsUrl: 'https://github.com/openai/codex',
|
|
253
|
-
envVarFormat: 'openai',
|
|
254
|
-
}
|
package/src/tools/continue.js
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Continue.dev 适配器 (VS Code / JetBrains 插件)
|
|
3
|
-
*
|
|
4
|
-
* ⚠️ 重要:Continue 新版本已将配置文件从 config.json 迁移到 config.yaml (YAML格式)
|
|
5
|
-
* 配置文件: ~/.continue/config.yaml (优先) 或 ~/.continue/config.json (旧版兼容)
|
|
6
|
-
*
|
|
7
|
-
* YAML 格式示例:
|
|
8
|
-
* models:
|
|
9
|
-
* - name: HolySheep Claude Sonnet
|
|
10
|
-
* provider: openai
|
|
11
|
-
* model: claude-sonnet-4-5
|
|
12
|
-
* apiKey: cr_xxx
|
|
13
|
-
* apiBase: https://api.holysheep.ai/v1
|
|
14
|
-
*
|
|
15
|
-
* Continue 支持 OpenAI 兼容 provider,可接入任何兼容端点
|
|
16
|
-
* 官方文档: https://docs.continue.dev
|
|
17
|
-
*/
|
|
18
|
-
const fs = require('fs')
|
|
19
|
-
const path = require('path')
|
|
20
|
-
const os = require('os')
|
|
21
|
-
|
|
22
|
-
const CONTINUE_DIR = path.join(os.homedir(), '.continue')
|
|
23
|
-
const CONFIG_YAML = path.join(CONTINUE_DIR, 'config.yaml')
|
|
24
|
-
const CONFIG_JSON = path.join(CONTINUE_DIR, 'config.json')
|
|
25
|
-
|
|
26
|
-
function getConfigFile() {
|
|
27
|
-
// 优先使用 config.yaml (新版)
|
|
28
|
-
if (fs.existsSync(CONFIG_YAML)) return { file: CONFIG_YAML, format: 'yaml' }
|
|
29
|
-
if (fs.existsSync(CONFIG_JSON)) return { file: CONFIG_JSON, format: 'json' }
|
|
30
|
-
// 默认创建 yaml
|
|
31
|
-
return { file: CONFIG_YAML, format: 'yaml' }
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function readJsonConfig() {
|
|
35
|
-
try {
|
|
36
|
-
return JSON.parse(fs.readFileSync(CONFIG_JSON, 'utf8'))
|
|
37
|
-
} catch {
|
|
38
|
-
return { models: [] }
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function writeJsonConfig(data) {
|
|
43
|
-
fs.mkdirSync(CONTINUE_DIR, { recursive: true })
|
|
44
|
-
fs.writeFileSync(CONFIG_JSON, JSON.stringify(data, null, 2), 'utf8')
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function readYamlRaw() {
|
|
48
|
-
try {
|
|
49
|
-
if (fs.existsSync(CONFIG_YAML)) return fs.readFileSync(CONFIG_YAML, 'utf8')
|
|
50
|
-
} catch {}
|
|
51
|
-
return ''
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* 写入 YAML 配置(简单字符串追加/替换方式,不依赖 yaml 库)
|
|
56
|
-
* 先移除已有 HolySheep 模型块,再在 models: 下插入新的
|
|
57
|
-
*/
|
|
58
|
-
function writeYamlConfig(apiKey, baseUrl, models) {
|
|
59
|
-
fs.mkdirSync(CONTINUE_DIR, { recursive: true })
|
|
60
|
-
|
|
61
|
-
let content = readYamlRaw()
|
|
62
|
-
|
|
63
|
-
// 移除旧的 holysheep 模型块(以 " - name: HolySheep" 开头到下一个 " - " 或 EOF)
|
|
64
|
-
content = content.replace(/ - name: HolySheep[^\n]*\n( [^\n]*\n)*/g, '')
|
|
65
|
-
|
|
66
|
-
// 如果没有 models: 段,则加上
|
|
67
|
-
if (!content.includes('models:')) {
|
|
68
|
-
content = 'models:\n' + content
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// 构建要插入的模型 YAML 块
|
|
72
|
-
const modelBlocks = models.map(m => [
|
|
73
|
-
` - name: ${m.name}`,
|
|
74
|
-
` provider: openai`,
|
|
75
|
-
` model: ${m.model}`,
|
|
76
|
-
` apiKey: ${apiKey}`,
|
|
77
|
-
` apiBase: ${baseUrl}`,
|
|
78
|
-
].join('\n')).join('\n')
|
|
79
|
-
|
|
80
|
-
// 在 models: 之后插入
|
|
81
|
-
content = content.replace('models:\n', `models:\n${modelBlocks}\n`)
|
|
82
|
-
|
|
83
|
-
fs.writeFileSync(CONFIG_YAML, content.replace(/\n{3,}/g, '\n\n').trimStart(), 'utf8')
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const HS_MODELS = [
|
|
87
|
-
{ name: 'HolySheep — Claude Sonnet', model: 'claude-sonnet-4-6' },
|
|
88
|
-
{ name: 'HolySheep — Claude Opus', model: 'claude-opus-4-6' },
|
|
89
|
-
]
|
|
90
|
-
|
|
91
|
-
module.exports = {
|
|
92
|
-
name: 'Continue.dev',
|
|
93
|
-
id: 'continue',
|
|
94
|
-
checkInstalled() {
|
|
95
|
-
return fs.existsSync(CONTINUE_DIR)
|
|
96
|
-
},
|
|
97
|
-
isConfigured() {
|
|
98
|
-
if (fs.existsSync(CONFIG_YAML)) {
|
|
99
|
-
return readYamlRaw().includes('holysheep')
|
|
100
|
-
}
|
|
101
|
-
const c = readJsonConfig()
|
|
102
|
-
return (c.models || []).some(m => m.apiBase?.includes('holysheep'))
|
|
103
|
-
},
|
|
104
|
-
configure(apiKey, _baseUrlAnthropicNoV1, baseUrlOpenAI) {
|
|
105
|
-
const { format } = getConfigFile()
|
|
106
|
-
|
|
107
|
-
if (format === 'yaml') {
|
|
108
|
-
writeYamlConfig(apiKey, baseUrlOpenAI, HS_MODELS)
|
|
109
|
-
return { file: CONFIG_YAML, hot: true }
|
|
110
|
-
} else {
|
|
111
|
-
// 兼容旧版 JSON 格式
|
|
112
|
-
const config = readJsonConfig()
|
|
113
|
-
config.models = (config.models || []).filter(m => !m.apiBase?.includes('holysheep'))
|
|
114
|
-
config.models = [
|
|
115
|
-
...HS_MODELS.map(m => ({
|
|
116
|
-
title: m.name,
|
|
117
|
-
provider: 'openai',
|
|
118
|
-
model: m.model,
|
|
119
|
-
apiKey,
|
|
120
|
-
apiBase: baseUrlOpenAI,
|
|
121
|
-
})),
|
|
122
|
-
...config.models,
|
|
123
|
-
]
|
|
124
|
-
writeJsonConfig(config)
|
|
125
|
-
return { file: CONFIG_JSON, hot: true }
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
reset() {
|
|
129
|
-
if (fs.existsSync(CONFIG_YAML)) {
|
|
130
|
-
let content = readYamlRaw()
|
|
131
|
-
content = content.replace(/ - name: HolySheep[^\n]*\n( [^\n]*\n)*/g, '')
|
|
132
|
-
fs.writeFileSync(CONFIG_YAML, content, 'utf8')
|
|
133
|
-
}
|
|
134
|
-
if (fs.existsSync(CONFIG_JSON)) {
|
|
135
|
-
const config = readJsonConfig()
|
|
136
|
-
config.models = (config.models || []).filter(m => !m.apiBase?.includes('holysheep'))
|
|
137
|
-
writeJsonConfig(config)
|
|
138
|
-
}
|
|
139
|
-
},
|
|
140
|
-
getConfigPath() { return fs.existsSync(CONFIG_YAML) ? CONFIG_YAML : CONFIG_JSON },
|
|
141
|
-
hint: '新版使用 config.yaml;配置后在 VS Code Continue 面板选择 HolySheep 模型',
|
|
142
|
-
launchCmd: null, // VS Code 插件,在编辑器内使用
|
|
143
|
-
launchNote: '在 VS Code 侧边栏打开 Continue 面板即可使用',
|
|
144
|
-
installCmd: 'VS Code 插件市场搜索 "Continue"',
|
|
145
|
-
docsUrl: 'https://continue.dev',
|
|
146
|
-
}
|
package/src/tools/cursor.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cursor 适配器
|
|
3
|
-
*
|
|
4
|
-
* ⚠️ 重要:Cursor 新版本(2025+)必须登录官方账号才能使用,
|
|
5
|
-
* 即使是「自带 API Key」模式也需要先登录 Cursor 账号。
|
|
6
|
-
* Cursor 的 API Key 和 Base URL 存储在加密的 secret storage 中,
|
|
7
|
-
* CLI 无法直接写入,且官方越来越绑定自己的账号体系。
|
|
8
|
-
*
|
|
9
|
-
* 推荐替代方案:
|
|
10
|
-
* - Continue(VS Code/JetBrains 插件,完全支持自定义 API)
|
|
11
|
-
* - Claude Code(命令行,官方支持自定义 base_url)
|
|
12
|
-
* - Aider(命令行,完全支持自定义 API)
|
|
13
|
-
*
|
|
14
|
-
* 如果仍要手动配置 Cursor:
|
|
15
|
-
* Settings → Models → Override OpenAI Base URL + OpenAI API Key
|
|
16
|
-
*/
|
|
17
|
-
const fs = require('fs')
|
|
18
|
-
const path = require('path')
|
|
19
|
-
const os = require('os')
|
|
20
|
-
const { execSync } = require('child_process')
|
|
21
|
-
|
|
22
|
-
function getCursorUserDir() {
|
|
23
|
-
const p = process.platform
|
|
24
|
-
if (p === 'darwin') return path.join(os.homedir(), 'Library', 'Application Support', 'Cursor', 'User')
|
|
25
|
-
if (p === 'win32') return path.join(os.homedir(), 'AppData', 'Roaming', 'Cursor', 'User')
|
|
26
|
-
return path.join(os.homedir(), '.config', 'Cursor', 'User')
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function checkCursorInstalled() {
|
|
30
|
-
const p = process.platform
|
|
31
|
-
if (p === 'darwin') return fs.existsSync('/Applications/Cursor.app') || fs.existsSync(path.join(os.homedir(), 'Applications', 'Cursor.app'))
|
|
32
|
-
if (p === 'win32') return fs.existsSync(path.join(os.homedir(), 'AppData', 'Local', 'Programs', 'cursor', 'Cursor.exe'))
|
|
33
|
-
try { execSync('which cursor', { stdio: 'ignore' }); return true } catch {}
|
|
34
|
-
return false
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
module.exports = {
|
|
38
|
-
name: 'Cursor',
|
|
39
|
-
id: 'cursor',
|
|
40
|
-
checkInstalled() { return checkCursorInstalled() },
|
|
41
|
-
isConfigured() {
|
|
42
|
-
return false // 无法检测(加密存储)
|
|
43
|
-
},
|
|
44
|
-
configure(apiKey, _baseUrlAnthropicNoV1, baseUrlOpenAI) {
|
|
45
|
-
// Cursor 需要登录官方账号,且 API Key 存储在加密区域,CLI 无法写入
|
|
46
|
-
// 返回 manual + warning
|
|
47
|
-
return {
|
|
48
|
-
manual: true,
|
|
49
|
-
steps: [
|
|
50
|
-
'⚠️ Cursor 新版本需要先登录官方账号(免费账号即可)',
|
|
51
|
-
'打开 Cursor → Settings(⌘+, / Ctrl+,)→ 左侧 Models',
|
|
52
|
-
'找到 "OpenAI API Key" 区域,勾选 "Enable OpenAI API Key"',
|
|
53
|
-
`填入 API Key: ${apiKey}`,
|
|
54
|
-
`填入 Override OpenAI Base URL: ${baseUrlOpenAI}`,
|
|
55
|
-
'点击 "Verify" 验证连接,然后在模型列表中选择 claude-* 模型',
|
|
56
|
-
'💡 推荐使用 Continue(VS Code 插件)替代,配置更简单',
|
|
57
|
-
],
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
reset() {
|
|
61
|
-
return {
|
|
62
|
-
manual: true,
|
|
63
|
-
steps: ['打开 Cursor Settings → Models → 清除 API Key 和 Override Base URL'],
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
getConfigPath() { return getCursorUserDir() },
|
|
67
|
-
hint: '需要登录 Cursor 账号 + 在 GUI 中手动配置(推荐用 Continue 替代)',
|
|
68
|
-
installCmd: '访问 https://cursor.sh 下载安装',
|
|
69
|
-
docsUrl: 'https://cursor.sh',
|
|
70
|
-
unsupported: true,
|
|
71
|
-
}
|