@simonyea/holysheep-cli 1.0.9 → 1.1.1
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/README.md +28 -20
- package/package.json +1 -1
- package/src/tools/aider.js +3 -2
- package/src/tools/continue.js +113 -48
- package/src/tools/cursor.js +26 -24
- package/src/tools/opencode.js +66 -28
package/README.md
CHANGED
|
@@ -34,16 +34,20 @@ Instead of manually editing config files and environment variables for each tool
|
|
|
34
34
|
|
|
35
35
|
### Supported Tools
|
|
36
36
|
|
|
37
|
-
| Tool | Install | Config Method |
|
|
38
|
-
|
|
39
|
-
| [Claude Code](https://docs.anthropic.com/claude-code) | `npm i -g @anthropic-ai/claude-code` | `~/.claude/settings.json` | ✅ |
|
|
40
|
-
| [Codex CLI](https://github.com/openai/codex) | `npm i -g @openai/codex` | `~/.codex/config.
|
|
41
|
-
| [
|
|
42
|
-
| [
|
|
43
|
-
| [
|
|
44
|
-
| [
|
|
45
|
-
| [Cursor](https://cursor.sh) | Download from website | GUI
|
|
46
|
-
| [
|
|
37
|
+
| Tool | Install | Config Method | Status |
|
|
38
|
+
|------|---------|---------------|--------|
|
|
39
|
+
| [Claude Code](https://docs.anthropic.com/claude-code) | `npm i -g @anthropic-ai/claude-code` | `~/.claude/settings.json` | ✅ Auto |
|
|
40
|
+
| [Codex CLI](https://github.com/openai/codex) | `npm i -g @openai/codex` | `~/.codex/config.toml` | ✅ Auto |
|
|
41
|
+
| [Aider](https://aider.chat) | `pip install aider-install && aider-install` | `~/.aider.conf.yml` | ✅ Auto |
|
|
42
|
+
| [Continue.dev](https://continue.dev) | VS Code marketplace | `~/.continue/config.yaml` | ✅ Auto |
|
|
43
|
+
| [OpenCode](https://opencode.ai) | `brew install anomalyco/tap/opencode` | `~/.config/opencode/opencode.json` | ✅ Auto |
|
|
44
|
+
| [OpenClaw](https://github.com/iOfficeAI/AionUi) | Download from website | `~/.openclaw/settings.json` | ✅ Auto |
|
|
45
|
+
| [Cursor](https://cursor.sh) | Download from website | GUI only (encrypted storage) | ⚠️ Manual |
|
|
46
|
+
| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | `npm i -g @google/gemini-cli` | Google protocol only | ❌ Not supported |
|
|
47
|
+
|
|
48
|
+
> **Note on Cursor**: Cursor (2025+) requires logging into the official Cursor account. API keys are stored in encrypted secret storage that CLI cannot access. Manual configuration via `Settings → Models → Override OpenAI Base URL` is required after login.
|
|
49
|
+
>
|
|
50
|
+
> **Note on Gemini CLI**: Gemini CLI uses Google's proprietary protocol and does not support custom relay endpoints. Use your own Google Gemini API Key from [aistudio.google.com](https://aistudio.google.com/apikey).
|
|
47
51
|
|
|
48
52
|
### Installation
|
|
49
53
|
|
|
@@ -124,16 +128,20 @@ HolySheep 是面向中国开发者的 Claude/GPT/Gemini 官方 API 中转服务
|
|
|
124
128
|
|
|
125
129
|
### 支持的工具
|
|
126
130
|
|
|
127
|
-
| 工具 | 安装方式 | 配置方式 |
|
|
128
|
-
|
|
129
|
-
| [Claude Code](https://docs.anthropic.com/claude-code) | `npm i -g @anthropic-ai/claude-code` | `~/.claude/settings.json` | ✅ |
|
|
130
|
-
| [Codex CLI](https://github.com/openai/codex) | `npm i -g @openai/codex` | `~/.codex/config.
|
|
131
|
-
| [
|
|
132
|
-
| [
|
|
133
|
-
| [
|
|
134
|
-
| [
|
|
135
|
-
| [Cursor](https://cursor.sh) | 官网下载 |
|
|
136
|
-
| [
|
|
131
|
+
| 工具 | 安装方式 | 配置方式 | 状态 |
|
|
132
|
+
|------|---------|---------|------|
|
|
133
|
+
| [Claude Code](https://docs.anthropic.com/claude-code) | `npm i -g @anthropic-ai/claude-code` | `~/.claude/settings.json` | ✅ 自动 |
|
|
134
|
+
| [Codex CLI](https://github.com/openai/codex) | `npm i -g @openai/codex` | `~/.codex/config.toml` | ✅ 自动 |
|
|
135
|
+
| [Aider](https://aider.chat) | `pip install aider-install && aider-install` | `~/.aider.conf.yml` | ✅ 自动 |
|
|
136
|
+
| [Continue.dev](https://continue.dev) | VS Code 插件市场 | `~/.continue/config.yaml` | ✅ 自动 |
|
|
137
|
+
| [OpenCode](https://opencode.ai) | `brew install anomalyco/tap/opencode` | `~/.config/opencode/opencode.json` | ✅ 自动 |
|
|
138
|
+
| [OpenClaw](https://github.com/iOfficeAI/AionUi) | 官网下载 | `~/.openclaw/settings.json` | ✅ 自动 |
|
|
139
|
+
| [Cursor](https://cursor.sh) | 官网下载 | GUI 手动配置(加密存储) | ⚠️ 手动 |
|
|
140
|
+
| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | `npm i -g @google/gemini-cli` | 仅支持 Google 官方协议 | ❌ 不支持 |
|
|
141
|
+
|
|
142
|
+
> **关于 Cursor**:Cursor 新版(2025+)必须登录官方账号,API Key 存储在加密区域,CLI 无法写入。需登录后在 `Settings → Models → Override OpenAI Base URL` 手动填入。
|
|
143
|
+
>
|
|
144
|
+
> **关于 Gemini CLI**:Gemini CLI 使用 Google 专有协议,不支持自定义中转地址。需使用从 [aistudio.google.com](https://aistudio.google.com/apikey) 获取的 Google Gemini API Key。
|
|
137
145
|
|
|
138
146
|
### 安装
|
|
139
147
|
|
package/package.json
CHANGED
package/src/tools/aider.js
CHANGED
|
@@ -44,10 +44,11 @@ module.exports = {
|
|
|
44
44
|
const content = readConfig()
|
|
45
45
|
return content.includes('holysheep')
|
|
46
46
|
},
|
|
47
|
-
configure(apiKey, baseUrlOpenAI) {
|
|
47
|
+
configure(apiKey, _baseUrlAnthropicNoV1, baseUrlOpenAI) {
|
|
48
48
|
let content = readConfig()
|
|
49
49
|
content = removeHsBlock(content)
|
|
50
|
-
// Aider 用 openai-api-base
|
|
50
|
+
// Aider 用 openai-api-base(OpenAI 兼容格式,带 /v1)
|
|
51
|
+
// model 格式: openai/<model-name> 表示使用 OpenAI 兼容接口
|
|
51
52
|
const block = `
|
|
52
53
|
# holysheep-cli managed — https://shop.holysheep.ai
|
|
53
54
|
openai-api-key: ${apiKey}
|
package/src/tools/continue.js
CHANGED
|
@@ -1,79 +1,144 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Continue.dev 适配器 (VS Code / JetBrains 插件)
|
|
3
|
-
* 配置文件: ~/.continue/config.json
|
|
4
3
|
*
|
|
5
|
-
* Continue
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
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
|
|
15
17
|
*/
|
|
16
18
|
const fs = require('fs')
|
|
17
19
|
const path = require('path')
|
|
18
20
|
const os = require('os')
|
|
19
21
|
|
|
20
|
-
const
|
|
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
|
+
}
|
|
21
41
|
|
|
22
|
-
function
|
|
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() {
|
|
23
48
|
try {
|
|
24
|
-
if (fs.existsSync(
|
|
49
|
+
if (fs.existsSync(CONFIG_YAML)) return fs.readFileSync(CONFIG_YAML, 'utf8')
|
|
25
50
|
} catch {}
|
|
26
|
-
return
|
|
51
|
+
return ''
|
|
27
52
|
}
|
|
28
53
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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')
|
|
32
84
|
}
|
|
33
85
|
|
|
34
|
-
const HS_MODELS =
|
|
35
|
-
{
|
|
36
|
-
|
|
37
|
-
provider: 'openai',
|
|
38
|
-
model: 'claude-sonnet-4-5',
|
|
39
|
-
apiKey,
|
|
40
|
-
apiBase: baseUrl,
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
title: 'HolySheep — Claude Opus',
|
|
44
|
-
provider: 'openai',
|
|
45
|
-
model: 'claude-opus-4-5',
|
|
46
|
-
apiKey,
|
|
47
|
-
apiBase: baseUrl,
|
|
48
|
-
},
|
|
86
|
+
const HS_MODELS = [
|
|
87
|
+
{ name: 'HolySheep — Claude Sonnet', model: 'claude-sonnet-4-5' },
|
|
88
|
+
{ name: 'HolySheep — Claude Opus', model: 'claude-opus-4-5' },
|
|
49
89
|
]
|
|
50
90
|
|
|
51
91
|
module.exports = {
|
|
52
92
|
name: 'Continue.dev',
|
|
53
93
|
id: 'continue',
|
|
54
94
|
checkInstalled() {
|
|
55
|
-
return fs.existsSync(
|
|
95
|
+
return fs.existsSync(CONTINUE_DIR)
|
|
56
96
|
},
|
|
57
97
|
isConfigured() {
|
|
58
|
-
|
|
98
|
+
if (fs.existsSync(CONFIG_YAML)) {
|
|
99
|
+
return readYamlRaw().includes('holysheep')
|
|
100
|
+
}
|
|
101
|
+
const c = readJsonConfig()
|
|
59
102
|
return (c.models || []).some(m => m.apiBase?.includes('holysheep'))
|
|
60
103
|
},
|
|
61
|
-
configure(apiKey, baseUrlOpenAI) {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
+
}
|
|
69
127
|
},
|
|
70
128
|
reset() {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
+
}
|
|
74
139
|
},
|
|
75
|
-
getConfigPath() { return
|
|
76
|
-
hint: '
|
|
140
|
+
getConfigPath() { return fs.existsSync(CONFIG_YAML) ? CONFIG_YAML : CONFIG_JSON },
|
|
141
|
+
hint: '新版使用 config.yaml;配置后在 VS Code Continue 面板选择 HolySheep 模型',
|
|
77
142
|
installCmd: 'VS Code 插件市场搜索 "Continue"',
|
|
78
143
|
docsUrl: 'https://continue.dev',
|
|
79
144
|
}
|
package/src/tools/cursor.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cursor 适配器
|
|
3
|
-
* Cursor 是基于 VSCode 的 AI 编辑器
|
|
4
3
|
*
|
|
5
|
-
* Cursor
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* ⚠️ 重要:Cursor 新版本(2025+)必须登录官方账号才能使用,
|
|
5
|
+
* 即使是「自带 API Key」模式也需要先登录 Cursor 账号。
|
|
6
|
+
* Cursor 的 API Key 和 Base URL 存储在加密的 secret storage 中,
|
|
7
|
+
* CLI 无法直接写入,且官方越来越绑定自己的账号体系。
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* 3. 生成 .cursor/mcp.json 供 Cursor MCP 功能使用
|
|
9
|
+
* 推荐替代方案:
|
|
10
|
+
* - Continue(VS Code/JetBrains 插件,完全支持自定义 API)
|
|
11
|
+
* - Claude Code(命令行,官方支持自定义 base_url)
|
|
12
|
+
* - Aider(命令行,完全支持自定义 API)
|
|
14
13
|
*
|
|
15
|
-
* Cursor
|
|
14
|
+
* 如果仍要手动配置 Cursor:
|
|
15
|
+
* Settings → Models → Override OpenAI Base URL + OpenAI API Key
|
|
16
16
|
*/
|
|
17
17
|
const fs = require('fs')
|
|
18
18
|
const path = require('path')
|
|
@@ -39,31 +39,33 @@ module.exports = {
|
|
|
39
39
|
id: 'cursor',
|
|
40
40
|
checkInstalled() { return checkCursorInstalled() },
|
|
41
41
|
isConfigured() {
|
|
42
|
-
//
|
|
43
|
-
return !!(process.env.OPENAI_API_KEY && process.env.OPENAI_BASE_URL?.includes('holysheep'))
|
|
42
|
+
return false // 无法检测(加密存储)
|
|
44
43
|
},
|
|
45
|
-
configure(apiKey, baseUrlOpenAI) {
|
|
46
|
-
// Cursor
|
|
47
|
-
// 返回 manual
|
|
44
|
+
configure(apiKey, _baseUrlAnthropicNoV1, baseUrlOpenAI) {
|
|
45
|
+
// Cursor 需要登录官方账号,且 API Key 存储在加密区域,CLI 无法写入
|
|
46
|
+
// 返回 manual + warning
|
|
48
47
|
return {
|
|
49
48
|
manual: true,
|
|
50
49
|
steps: [
|
|
51
|
-
'
|
|
52
|
-
'
|
|
50
|
+
'⚠️ Cursor 新版本需要先登录官方账号(免费账号即可)',
|
|
51
|
+
'打开 Cursor → Settings(⌘+, / Ctrl+,)→ 左侧 Models',
|
|
52
|
+
'找到 "OpenAI API Key" 区域,勾选 "Enable OpenAI API Key"',
|
|
53
53
|
`填入 API Key: ${apiKey}`,
|
|
54
|
-
`填入
|
|
55
|
-
'点击 "Verify"
|
|
56
|
-
'
|
|
54
|
+
`填入 Override OpenAI Base URL: ${baseUrlOpenAI}`,
|
|
55
|
+
'点击 "Verify" 验证连接,然后在模型列表中选择 claude-* 模型',
|
|
56
|
+
'💡 推荐使用 Continue(VS Code 插件)替代,配置更简单',
|
|
57
57
|
],
|
|
58
|
-
imageHint: '💡 Cursor Settings → Models → Override OpenAI Base URL',
|
|
59
58
|
}
|
|
60
59
|
},
|
|
61
60
|
reset() {
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
return {
|
|
62
|
+
manual: true,
|
|
63
|
+
steps: ['打开 Cursor Settings → Models → 清除 API Key 和 Override Base URL'],
|
|
64
|
+
}
|
|
64
65
|
},
|
|
65
66
|
getConfigPath() { return getCursorUserDir() },
|
|
66
|
-
hint: '
|
|
67
|
+
hint: '需要登录 Cursor 账号 + 在 GUI 中手动配置(推荐用 Continue 替代)',
|
|
67
68
|
installCmd: '访问 https://cursor.sh 下载安装',
|
|
68
69
|
docsUrl: 'https://cursor.sh',
|
|
70
|
+
unsupported: true,
|
|
69
71
|
}
|
package/src/tools/opencode.js
CHANGED
|
@@ -1,21 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OpenCode 适配器 (sst/opencode)
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* OpenCode 适配器 (anomalyco/opencode,原 sst/opencode)
|
|
3
|
+
*
|
|
4
|
+
* ⚠️ 重要:OpenCode 仓库已从 sst/opencode 迁移到 anomalyco/opencode
|
|
5
|
+
* 全局配置文件: ~/.config/opencode/opencode.json (不是 config.json!)
|
|
6
|
+
* 格式: JSON/JSONC,provider 配置格式如下:
|
|
5
7
|
*
|
|
6
|
-
* OpenCode provider 格式:
|
|
7
8
|
* {
|
|
8
|
-
* "
|
|
9
|
+
* "$schema": "https://opencode.ai/config.json",
|
|
10
|
+
* "model": "anthropic/claude-sonnet-4-5",
|
|
11
|
+
* "provider": {
|
|
9
12
|
* "anthropic": {
|
|
10
|
-
* "
|
|
11
|
-
*
|
|
13
|
+
* "options": {
|
|
14
|
+
* "baseURL": "https://api.holysheep.ai",
|
|
15
|
+
* "apiKey": "cr_xxx"
|
|
16
|
+
* }
|
|
12
17
|
* },
|
|
13
18
|
* "openai": {
|
|
14
|
-
* "
|
|
15
|
-
*
|
|
19
|
+
* "options": {
|
|
20
|
+
* "baseURL": "https://api.holysheep.ai/v1",
|
|
21
|
+
* "apiKey": "cr_xxx"
|
|
22
|
+
* }
|
|
16
23
|
* }
|
|
17
24
|
* }
|
|
18
25
|
* }
|
|
26
|
+
*
|
|
27
|
+
* 安装方式(推荐): brew install anomalyco/tap/opencode
|
|
28
|
+
* 或: npm i -g opencode-ai@latest
|
|
29
|
+
* 官方文档: https://opencode.ai/docs/config
|
|
19
30
|
*/
|
|
20
31
|
const fs = require('fs')
|
|
21
32
|
const path = require('path')
|
|
@@ -23,22 +34,30 @@ const os = require('os')
|
|
|
23
34
|
|
|
24
35
|
function getConfigFile() {
|
|
25
36
|
const candidates = [
|
|
37
|
+
// 新版标准路径(官方文档)
|
|
38
|
+
path.join(os.homedir(), '.config', 'opencode', 'opencode.json'),
|
|
39
|
+
// 旧版路径兼容
|
|
26
40
|
path.join(os.homedir(), '.config', 'opencode', 'config.json'),
|
|
41
|
+
path.join(os.homedir(), '.opencode', 'opencode.json'),
|
|
27
42
|
path.join(os.homedir(), '.opencode', 'config.json'),
|
|
28
43
|
// Windows
|
|
29
|
-
path.join(os.homedir(), 'AppData', 'Roaming', 'opencode', '
|
|
44
|
+
path.join(os.homedir(), 'AppData', 'Roaming', 'opencode', 'opencode.json'),
|
|
30
45
|
]
|
|
31
46
|
for (const f of candidates) {
|
|
32
47
|
if (fs.existsSync(f)) return f
|
|
33
48
|
}
|
|
34
|
-
//
|
|
35
|
-
return path.join(os.homedir(), '.config', 'opencode', '
|
|
49
|
+
// 默认路径(新版标准)
|
|
50
|
+
return path.join(os.homedir(), '.config', 'opencode', 'opencode.json')
|
|
36
51
|
}
|
|
37
52
|
|
|
38
53
|
function readConfig() {
|
|
39
54
|
const file = getConfigFile()
|
|
40
55
|
try {
|
|
41
|
-
if (fs.existsSync(file))
|
|
56
|
+
if (fs.existsSync(file)) {
|
|
57
|
+
// 支持 JSONC(带注释的 JSON)
|
|
58
|
+
const content = fs.readFileSync(file, 'utf8')
|
|
59
|
+
return JSON.parse(content.replace(/\/\/[^\n]*/g, '').replace(/\/\*[\s\S]*?\*\//g, ''))
|
|
60
|
+
}
|
|
42
61
|
} catch {}
|
|
43
62
|
return {}
|
|
44
63
|
}
|
|
@@ -57,33 +76,52 @@ module.exports = {
|
|
|
57
76
|
},
|
|
58
77
|
isConfigured() {
|
|
59
78
|
const c = readConfig()
|
|
60
|
-
return !!(
|
|
61
|
-
|
|
79
|
+
return !!(
|
|
80
|
+
c.provider?.anthropic?.options?.baseURL?.includes('holysheep') ||
|
|
81
|
+
c.provider?.openai?.options?.baseURL?.includes('holysheep')
|
|
82
|
+
)
|
|
62
83
|
},
|
|
63
84
|
configure(apiKey, baseUrlAnthropicNoV1, baseUrlOpenAI) {
|
|
64
85
|
const config = readConfig()
|
|
65
|
-
if (!config.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
86
|
+
if (!config.provider) config.provider = {}
|
|
87
|
+
|
|
88
|
+
// 设置 schema(方便编辑器自动补全)
|
|
89
|
+
if (!config['$schema']) config['$schema'] = 'https://opencode.ai/config.json'
|
|
90
|
+
|
|
91
|
+
// 配置 Anthropic provider(Claude 模型)
|
|
92
|
+
config.provider.anthropic = {
|
|
93
|
+
options: {
|
|
94
|
+
baseURL: baseUrlAnthropicNoV1, // https://api.holysheep.ai (无 /v1)
|
|
95
|
+
apiKey,
|
|
96
|
+
},
|
|
69
97
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
98
|
+
|
|
99
|
+
// 配置 OpenAI provider(GPT 模型)
|
|
100
|
+
config.provider.openai = {
|
|
101
|
+
options: {
|
|
102
|
+
baseURL: baseUrlOpenAI, // https://api.holysheep.ai/v1
|
|
103
|
+
apiKey,
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 设置默认模型
|
|
108
|
+
if (!config.model) {
|
|
109
|
+
config.model = 'anthropic/claude-sonnet-4-5'
|
|
73
110
|
}
|
|
111
|
+
|
|
74
112
|
writeConfig(config)
|
|
75
113
|
return { file: getConfigFile(), hot: false }
|
|
76
114
|
},
|
|
77
115
|
reset() {
|
|
78
116
|
const config = readConfig()
|
|
79
|
-
if (config.
|
|
80
|
-
delete config.
|
|
81
|
-
delete config.
|
|
117
|
+
if (config.provider) {
|
|
118
|
+
delete config.provider.anthropic
|
|
119
|
+
delete config.provider.openai
|
|
82
120
|
}
|
|
83
121
|
writeConfig(config)
|
|
84
122
|
},
|
|
85
123
|
getConfigPath() { return getConfigFile() },
|
|
86
|
-
hint: '切换后重启 OpenCode
|
|
87
|
-
installCmd: '
|
|
88
|
-
docsUrl: 'https://
|
|
124
|
+
hint: '切换后重启 OpenCode 生效;配置文件: ~/.config/opencode/opencode.json',
|
|
125
|
+
installCmd: 'brew install anomalyco/tap/opencode # 或: npm i -g opencode-ai@latest',
|
|
126
|
+
docsUrl: 'https://opencode.ai',
|
|
89
127
|
}
|