srpllm 1.0.0 → 1.1.0
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 +143 -193
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +26 -2
- package/dist/index.d.ts +26 -2
- package/dist/index.mjs +1 -1
- package/dist/shared/{srpllm.BB4ML_UM.mjs → srpllm.BDtiig24.mjs} +68 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,193 +1,143 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
[ (first open source project author sponsor, the author of [CCR](https://github.com/musistudio/claude-code-router) 🤩)
|
|
147
|
-
- \*年 (first 100 CNY sponsor 💴)
|
|
148
|
-
- [BeatSeat](https://github.com/BeatSeat) (community expert 😎, provided $1000 Claude credits)
|
|
149
|
-
- [wenwen](https://github.com/wenwen12345) (community expert 🤓, provided daily $100 Claude&GPT credits)
|
|
150
|
-
- 16°C coffee (My best friend 🤪, offered ChatGPT Pro $200 package)
|
|
151
|
-
|
|
152
|
-
### Promotion Thanks
|
|
153
|
-
|
|
154
|
-
Thanks to the following authors for promoting this project:
|
|
155
|
-
|
|
156
|
-
- 逛逛 GitHub, article: https://mp.weixin.qq.com/s/phqwSRb16MKCHHVozTFeiQ
|
|
157
|
-
- Geek, tweet: https://x.com/geekbb/status/1955174718618866076
|
|
158
|
-
|
|
159
|
-
## 📄 License
|
|
160
|
-
|
|
161
|
-
[MIT License](LICENSE)
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
## 🚀 Contributors
|
|
166
|
-
|
|
167
|
-
<a href="https://github.com/UfoMiao/zcf/graphs/contributors">
|
|
168
|
-
<img src="https://contrib.rocks/image?repo=UfoMiao/zcf" />
|
|
169
|
-
</a>
|
|
170
|
-
<br /><br />
|
|
171
|
-
|
|
172
|
-
## ⭐️ Star History
|
|
173
|
-
|
|
174
|
-
If this project helps you, please give me a ⭐️ Star!
|
|
175
|
-
|
|
176
|
-
[](https://star-history.com/#UfoMiao/zcf&Date)
|
|
177
|
-
|
|
178
|
-
<!-- Badges -->
|
|
179
|
-
|
|
180
|
-
[npm-version-src]: https://img.shields.io/npm/v/zcf?style=flat&colorA=080f12&colorB=1fa669
|
|
181
|
-
[npm-version-href]: https://npmjs.com/package/zcf
|
|
182
|
-
[npm-downloads-src]: https://img.shields.io/npm/dm/zcf?style=flat&colorA=080f12&colorB=1fa669
|
|
183
|
-
[npm-downloads-href]: https://npmjs.com/package/zcf
|
|
184
|
-
[license-src]: https://img.shields.io/github/license/ufomiao/zcf.svg?style=flat&colorA=080f12&colorB=1fa669
|
|
185
|
-
[license-href]: https://github.com/ufomiao/zcf/blob/main/LICENSE
|
|
186
|
-
[claude-code-src]: https://img.shields.io/badge/Claude-Code-1fa669?style=flat&colorA=080f12&colorB=1fa669
|
|
187
|
-
[claude-code-href]: https://claude.ai/code
|
|
188
|
-
[codecov-src]: https://codecov.io/gh/UfoMiao/zcf/graph/badge.svg?token=HZI6K4Y7D7&style=flat&colorA=080f12&colorB=1fa669
|
|
189
|
-
[codecov-href]: https://codecov.io/gh/UfoMiao/zcf
|
|
190
|
-
[jsdocs-src]: https://img.shields.io/badge/jsdocs-reference-1fa669?style=flat&colorA=080f12&colorB=1fa669
|
|
191
|
-
[jsdocs-href]: https://www.jsdocs.io/package/zcf
|
|
192
|
-
[deepwiki-src]: https://img.shields.io/badge/Ask-DeepWiki-1fa669?style=flat&colorA=080f12&colorB=1fa669
|
|
193
|
-
[deepwiki-href]: https://deepwiki.com/UfoMiao/zcf
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# SrP-LLM 配置工具
|
|
4
|
+
|
|
5
|
+
中转站客户端一键配置:安装 Claude Code / Codex · 填写 base_url 与 api_token · 从 litellm 拉取并选择模型
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/srpllm)
|
|
8
|
+
[](./LICENSE)
|
|
9
|
+
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
## 简介
|
|
13
|
+
|
|
14
|
+
`srpllm` 是为 **SrP-LLM 中转站**(基于 litellm 后端)准备的客户端配置脚本。一条命令即可:
|
|
15
|
+
|
|
16
|
+
1. 安装 Claude Code / Codex CLI
|
|
17
|
+
2. 引导填写中转站的 `base_url` 与 `api_token`
|
|
18
|
+
3. 从中转站后端 `GET {base_url}/v1/models` 拉取可用模型列表并选择
|
|
19
|
+
4. 把配置写入对应客户端的配置文件(Claude Code 的 `settings.json` / Codex 的 `config.toml` + `auth.json`)
|
|
20
|
+
|
|
21
|
+
仅做「安装 + 配置接入中转站」这一件事,不做更多设置。
|
|
22
|
+
|
|
23
|
+
## 快速开始
|
|
24
|
+
|
|
25
|
+
无需全局安装,直接用 `npx` 运行:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx srpllm
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
按提示选择工具、输入中转站地址和 token、选择模型即可完成。
|
|
32
|
+
|
|
33
|
+
## 命令
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx srpllm # 交互式引导配置(默认)
|
|
37
|
+
npx srpllm init # 安装 CLI 并配置中转站(同上)
|
|
38
|
+
npx srpllm uninstall # 清除中转站配置(可选同时卸载 CLI)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 非交互模式(CI / 脚本)
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx srpllm init -s \
|
|
45
|
+
-T claude-code \
|
|
46
|
+
-u https://api.srpllm.com \
|
|
47
|
+
-k sk-xxxx \
|
|
48
|
+
-m glm-5.2 \
|
|
49
|
+
-O glm-5.2 \
|
|
50
|
+
-S glm-5-turbo \
|
|
51
|
+
-H glm-5-turbo
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 参数
|
|
55
|
+
|
|
56
|
+
| 参数 | 简写 | 说明 |
|
|
57
|
+
|------|------|------|
|
|
58
|
+
| `--code-type` | `-T` | 工具类型:`claude-code` / `codex`(简写 `cc` / `cx`) |
|
|
59
|
+
| `--base-url` | `-u` | 中转站 base_url(例如 `https://api.srpllm.com`) |
|
|
60
|
+
| `--token` | `-k` | api_token |
|
|
61
|
+
| `--model` | `-m` | 主模型,写入 `ANTHROPIC_MODEL` |
|
|
62
|
+
| `--opus-model` | `-O` | Opus 档模型,写入 `ANTHROPIC_DEFAULT_OPUS_MODEL` |
|
|
63
|
+
| `--sonnet-model` | `-S` | Sonnet 档模型,写入 `ANTHROPIC_DEFAULT_SONNET_MODEL` |
|
|
64
|
+
| `--haiku-model` | `-H` | Haiku 档模型,写入 `ANTHROPIC_DEFAULT_HAIKU_MODEL` |
|
|
65
|
+
| `--skip-prompt` | `-s` | 非交互模式,跳过所有交互提示 |
|
|
66
|
+
| `--help` | `-h` | 显示帮助 |
|
|
67
|
+
| `--version` | `-v` | 显示版本 |
|
|
68
|
+
|
|
69
|
+
> Opus / Sonnet / Haiku 三档模型参数仅对 Claude Code 生效;Codex 只使用 `--model`。
|
|
70
|
+
|
|
71
|
+
## 配置写入位置
|
|
72
|
+
|
|
73
|
+
### Claude Code
|
|
74
|
+
|
|
75
|
+
写入 `~/.claude/settings.json` 的 `env` 段(合并式,保留其它字段):
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"env": {
|
|
80
|
+
"ANTHROPIC_BASE_URL": "https://api.srpllm.com",
|
|
81
|
+
"ANTHROPIC_AUTH_TOKEN": "sk-xxxx",
|
|
82
|
+
"ANTHROPIC_MODEL": "glm-5.2",
|
|
83
|
+
"ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-5.2",
|
|
84
|
+
"ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-5-turbo",
|
|
85
|
+
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "glm-5-turbo",
|
|
86
|
+
"CLAUDE_CODE_AUTO_COMPACT_WINDOW": "1000000",
|
|
87
|
+
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- 统一使用 `ANTHROPIC_AUTH_TOKEN`(Bearer token 鉴权),清除原 `ANTHROPIC_API_KEY`
|
|
93
|
+
- 额外附加 `CLAUDE_CODE_AUTO_COMPACT_WINDOW` 与 `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` 两个默认值
|
|
94
|
+
|
|
95
|
+
### Codex
|
|
96
|
+
|
|
97
|
+
写入 `~/.codex/config.toml`(合并式,保留用户其它 provider / mcp / projects 等配置,修改前自动备份):
|
|
98
|
+
|
|
99
|
+
```toml
|
|
100
|
+
# --- SrP-LLM 中转站配置 ---
|
|
101
|
+
model = "gpt-5.2"
|
|
102
|
+
model_provider = "srpllm"
|
|
103
|
+
|
|
104
|
+
[model_providers.srpllm]
|
|
105
|
+
name = "SrP-LLM"
|
|
106
|
+
base_url = "https://api.srpllm.com"
|
|
107
|
+
wire_api = "responses"
|
|
108
|
+
temp_env_key = "SRPLLM_API_KEY"
|
|
109
|
+
requires_openai_auth = false
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
并把 `~/.codex/auth.json` 中的 `SRPLLM_API_KEY` 与 `OPENAI_API_KEY` 设为 token(合并保留其它 key)。
|
|
113
|
+
|
|
114
|
+
## 卸载
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npx srpllm uninstall
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
- Claude Code:从 `settings.json` 清除中转站相关 env 字段,保留其它设置
|
|
121
|
+
- Codex:移除 `[model_providers.srpllm]` 段与顶层 `model`/`model_provider`,保留其它配置(修改前自动备份)
|
|
122
|
+
- 可选择同时卸载 Claude Code / Codex CLI
|
|
123
|
+
|
|
124
|
+
## 模型列表获取
|
|
125
|
+
|
|
126
|
+
模型列表从中转站后端 litellm 的标准接口拉取:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
GET {base_url}/v1/models
|
|
130
|
+
Authorization: Bearer {api_token}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
返回 `data: [{ id, owned_by, ... }]` 格式,工具会列出全部模型供选择。若拉取失败(网络不通 / token 无效),交互模式下可手动输入模型名,非交互模式下跳过模型配置。
|
|
134
|
+
|
|
135
|
+
## 平台支持
|
|
136
|
+
|
|
137
|
+
- macOS / Linux / Windows / WSL / Termux
|
|
138
|
+
- Claude Code 安装方式:npm / Homebrew / curl / PowerShell
|
|
139
|
+
- Codex 安装方式:npm / Homebrew
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
[MIT](./LICENSE)
|
package/dist/cli.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import cac from 'cac';
|
|
3
3
|
import ansis from 'ansis';
|
|
4
|
-
import { i as init, u as uninstall,
|
|
4
|
+
import { i as init, u as uninstall, J as version } from './shared/srpllm.BDtiig24.mjs';
|
|
5
5
|
import 'node:process';
|
|
6
6
|
import 'inquirer';
|
|
7
7
|
import 'ora';
|
package/dist/index.d.mts
CHANGED
|
@@ -70,6 +70,30 @@ declare function selectInstallMethod(tool: CodeToolType): Promise<InstallMethod>
|
|
|
70
70
|
declare function installTool(tool: CodeToolType, skipMethodSelection?: boolean): Promise<void>;
|
|
71
71
|
declare function uninstallTool(tool: CodeToolType): Promise<boolean>;
|
|
72
72
|
|
|
73
|
+
interface LocalConfig {
|
|
74
|
+
/** 上次选的工具 */
|
|
75
|
+
codeType?: 'claude-code' | 'codex';
|
|
76
|
+
/** 上次输入的中转站 base_url */
|
|
77
|
+
baseUrl?: string;
|
|
78
|
+
/** 上次输入的 api_token(明文存储,文件权限 600) */
|
|
79
|
+
token?: string;
|
|
80
|
+
/** 上次为 Claude Code 选的四档模型 */
|
|
81
|
+
claude?: {
|
|
82
|
+
model?: string;
|
|
83
|
+
opusModel?: string;
|
|
84
|
+
sonnetModel?: string;
|
|
85
|
+
haikuModel?: string;
|
|
86
|
+
};
|
|
87
|
+
/** 上次为 Codex 选的模型 */
|
|
88
|
+
codex?: {
|
|
89
|
+
model?: string;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
declare function readLocalConfig(): LocalConfig;
|
|
93
|
+
declare function writeLocalConfig(config: LocalConfig): void;
|
|
94
|
+
/** 合并更新本地记忆 */
|
|
95
|
+
declare function updateLocalConfig(patch: Partial<LocalConfig>): void;
|
|
96
|
+
|
|
73
97
|
interface RemoteModel {
|
|
74
98
|
id: string;
|
|
75
99
|
ownedBy?: string;
|
|
@@ -90,5 +114,5 @@ declare function getPlatform(): Platform;
|
|
|
90
114
|
declare function isWindows(): boolean;
|
|
91
115
|
declare function commandExists(command: string): Promise<boolean>;
|
|
92
116
|
|
|
93
|
-
export { CLAUDE_DIR, CLAUDE_SETTINGS_FILE, CODEX_AUTH_FILE, CODEX_CONFIG_FILE, CODEX_DIR, CODE_TOOL_ALIASES, CODE_TOOL_LABELS, CODE_TOOL_TYPES, DEFAULT_CODE_TOOL_TYPE, RELAY_PROVIDER_ID, buildModelsChoices, clearClaudeApiConfig, clearCodexApiConfig, commandExists, detectInstalledVersion, displayClaudeConfig, displayCodexConfig, ensureClaudeDir, fetchModels, getExistingClaudeApiConfig, getExistingCodexConfig, getPlatform, init, installTool, isToolInstalled, isWindows, readClaudeSettings, resolveCodeToolType, selectInstallMethod, uninstall, uninstallTool, writeClaudeApiConfig, writeCodexApiConfig };
|
|
94
|
-
export type { ClaudeApiConfig, CodeToolType, CodexApiConfig, InstallMethod, RemoteModel };
|
|
117
|
+
export { CLAUDE_DIR, CLAUDE_SETTINGS_FILE, CODEX_AUTH_FILE, CODEX_CONFIG_FILE, CODEX_DIR, CODE_TOOL_ALIASES, CODE_TOOL_LABELS, CODE_TOOL_TYPES, DEFAULT_CODE_TOOL_TYPE, RELAY_PROVIDER_ID, buildModelsChoices, clearClaudeApiConfig, clearCodexApiConfig, commandExists, detectInstalledVersion, displayClaudeConfig, displayCodexConfig, ensureClaudeDir, fetchModels, getExistingClaudeApiConfig, getExistingCodexConfig, getPlatform, init, installTool, isToolInstalled, isWindows, readClaudeSettings, readLocalConfig, resolveCodeToolType, selectInstallMethod, uninstall, uninstallTool, updateLocalConfig, writeClaudeApiConfig, writeCodexApiConfig, writeLocalConfig };
|
|
118
|
+
export type { ClaudeApiConfig, CodeToolType, CodexApiConfig, InstallMethod, LocalConfig, RemoteModel };
|
package/dist/index.d.ts
CHANGED
|
@@ -70,6 +70,30 @@ declare function selectInstallMethod(tool: CodeToolType): Promise<InstallMethod>
|
|
|
70
70
|
declare function installTool(tool: CodeToolType, skipMethodSelection?: boolean): Promise<void>;
|
|
71
71
|
declare function uninstallTool(tool: CodeToolType): Promise<boolean>;
|
|
72
72
|
|
|
73
|
+
interface LocalConfig {
|
|
74
|
+
/** 上次选的工具 */
|
|
75
|
+
codeType?: 'claude-code' | 'codex';
|
|
76
|
+
/** 上次输入的中转站 base_url */
|
|
77
|
+
baseUrl?: string;
|
|
78
|
+
/** 上次输入的 api_token(明文存储,文件权限 600) */
|
|
79
|
+
token?: string;
|
|
80
|
+
/** 上次为 Claude Code 选的四档模型 */
|
|
81
|
+
claude?: {
|
|
82
|
+
model?: string;
|
|
83
|
+
opusModel?: string;
|
|
84
|
+
sonnetModel?: string;
|
|
85
|
+
haikuModel?: string;
|
|
86
|
+
};
|
|
87
|
+
/** 上次为 Codex 选的模型 */
|
|
88
|
+
codex?: {
|
|
89
|
+
model?: string;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
declare function readLocalConfig(): LocalConfig;
|
|
93
|
+
declare function writeLocalConfig(config: LocalConfig): void;
|
|
94
|
+
/** 合并更新本地记忆 */
|
|
95
|
+
declare function updateLocalConfig(patch: Partial<LocalConfig>): void;
|
|
96
|
+
|
|
73
97
|
interface RemoteModel {
|
|
74
98
|
id: string;
|
|
75
99
|
ownedBy?: string;
|
|
@@ -90,5 +114,5 @@ declare function getPlatform(): Platform;
|
|
|
90
114
|
declare function isWindows(): boolean;
|
|
91
115
|
declare function commandExists(command: string): Promise<boolean>;
|
|
92
116
|
|
|
93
|
-
export { CLAUDE_DIR, CLAUDE_SETTINGS_FILE, CODEX_AUTH_FILE, CODEX_CONFIG_FILE, CODEX_DIR, CODE_TOOL_ALIASES, CODE_TOOL_LABELS, CODE_TOOL_TYPES, DEFAULT_CODE_TOOL_TYPE, RELAY_PROVIDER_ID, buildModelsChoices, clearClaudeApiConfig, clearCodexApiConfig, commandExists, detectInstalledVersion, displayClaudeConfig, displayCodexConfig, ensureClaudeDir, fetchModels, getExistingClaudeApiConfig, getExistingCodexConfig, getPlatform, init, installTool, isToolInstalled, isWindows, readClaudeSettings, resolveCodeToolType, selectInstallMethod, uninstall, uninstallTool, writeClaudeApiConfig, writeCodexApiConfig };
|
|
94
|
-
export type { ClaudeApiConfig, CodeToolType, CodexApiConfig, InstallMethod, RemoteModel };
|
|
117
|
+
export { CLAUDE_DIR, CLAUDE_SETTINGS_FILE, CODEX_AUTH_FILE, CODEX_CONFIG_FILE, CODEX_DIR, CODE_TOOL_ALIASES, CODE_TOOL_LABELS, CODE_TOOL_TYPES, DEFAULT_CODE_TOOL_TYPE, RELAY_PROVIDER_ID, buildModelsChoices, clearClaudeApiConfig, clearCodexApiConfig, commandExists, detectInstalledVersion, displayClaudeConfig, displayCodexConfig, ensureClaudeDir, fetchModels, getExistingClaudeApiConfig, getExistingCodexConfig, getPlatform, init, installTool, isToolInstalled, isWindows, readClaudeSettings, readLocalConfig, resolveCodeToolType, selectInstallMethod, uninstall, uninstallTool, updateLocalConfig, writeClaudeApiConfig, writeCodexApiConfig, writeLocalConfig };
|
|
118
|
+
export type { ClaudeApiConfig, CodeToolType, CodexApiConfig, InstallMethod, LocalConfig, RemoteModel };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as CLAUDE_DIR, b as CLAUDE_SETTINGS_FILE, f as CODEX_AUTH_FILE, e as CODEX_CONFIG_FILE, d as CODEX_DIR, j as CODE_TOOL_ALIASES, k as CODE_TOOL_LABELS, h as CODE_TOOL_TYPES, D as DEFAULT_CODE_TOOL_TYPE, R as RELAY_PROVIDER_ID,
|
|
1
|
+
export { C as CLAUDE_DIR, b as CLAUDE_SETTINGS_FILE, f as CODEX_AUTH_FILE, e as CODEX_CONFIG_FILE, d as CODEX_DIR, j as CODE_TOOL_ALIASES, k as CODE_TOOL_LABELS, h as CODE_TOOL_TYPES, D as DEFAULT_CODE_TOOL_TYPE, R as RELAY_PROVIDER_ID, I as buildModelsChoices, o as clearClaudeApiConfig, t as clearCodexApiConfig, c as commandExists, y as detectInstalledVersion, p as displayClaudeConfig, v as displayCodexConfig, l as ensureClaudeDir, H as fetchModels, n as getExistingClaudeApiConfig, q as getExistingCodexConfig, g as getPlatform, i as init, A as installTool, x as isToolInstalled, a as isWindows, m as readClaudeSettings, E as readLocalConfig, r as resolveCodeToolType, z as selectInstallMethod, u as uninstall, B as uninstallTool, G as updateLocalConfig, w as writeClaudeApiConfig, s as writeCodexApiConfig, F as writeLocalConfig } from './shared/srpllm.BDtiig24.mjs';
|
|
2
2
|
import 'node:process';
|
|
3
3
|
import 'ansis';
|
|
4
4
|
import 'inquirer';
|
|
@@ -4,7 +4,7 @@ import inquirer from 'inquirer';
|
|
|
4
4
|
import ora from 'ora';
|
|
5
5
|
import { homedir, platform } from 'node:os';
|
|
6
6
|
import { join, dirname } from 'pathe';
|
|
7
|
-
import {
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from 'node:fs';
|
|
8
8
|
import { exec } from 'tinyexec';
|
|
9
9
|
|
|
10
10
|
const CLAUDE_DIR = join(homedir(), ".claude");
|
|
@@ -479,6 +479,24 @@ async function uninstallTool(tool) {
|
|
|
479
479
|
}
|
|
480
480
|
}
|
|
481
481
|
|
|
482
|
+
const SRPLLM_DIR = join(homedir(), ".srpllm");
|
|
483
|
+
const SRPLLM_CONFIG_FILE = join(SRPLLM_DIR, "config.json");
|
|
484
|
+
function readLocalConfig() {
|
|
485
|
+
return readJson(SRPLLM_CONFIG_FILE) || {};
|
|
486
|
+
}
|
|
487
|
+
function writeLocalConfig(config) {
|
|
488
|
+
ensureDir(SRPLLM_DIR);
|
|
489
|
+
writeJson(SRPLLM_CONFIG_FILE, config);
|
|
490
|
+
try {
|
|
491
|
+
chmodSync(SRPLLM_CONFIG_FILE, 384);
|
|
492
|
+
} catch {
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
function updateLocalConfig(patch) {
|
|
496
|
+
const existing = readLocalConfig();
|
|
497
|
+
writeLocalConfig({ ...existing, ...patch });
|
|
498
|
+
}
|
|
499
|
+
|
|
482
500
|
async function fetchModels(baseUrl, token) {
|
|
483
501
|
const url = `${baseUrl.replace(/\/$/, "")}/v1/models`;
|
|
484
502
|
const spinner = ora(`\u6B63\u5728\u4ECE ${url} \u62C9\u53D6\u6A21\u578B\u5217\u8868...`).start();
|
|
@@ -518,7 +536,7 @@ function buildModelsChoices(models) {
|
|
|
518
536
|
}));
|
|
519
537
|
}
|
|
520
538
|
|
|
521
|
-
const version = "1.
|
|
539
|
+
const version = "1.1.0";
|
|
522
540
|
|
|
523
541
|
function displayBanner(codeTool) {
|
|
524
542
|
const tool = codeTool ? ` ${ansis.gray(`\xB7 ${CODE_TOOL_LABELS[codeTool]}`)}` : "";
|
|
@@ -526,23 +544,26 @@ function displayBanner(codeTool) {
|
|
|
526
544
|
SrP-LLM \u914D\u7F6E\u5DE5\u5177 v${version}${tool}`));
|
|
527
545
|
console.log(ansis.gray(" \u4E2D\u8F6C\u7AD9\u5BA2\u6237\u7AEF\u4E00\u952E\u914D\u7F6E\uFF1A\u5B89\u88C5 CLI \xB7 \u586B\u5199 base_url / api_token \xB7 \u9009\u62E9\u6A21\u578B\n"));
|
|
528
546
|
}
|
|
529
|
-
async function selectCodeTool() {
|
|
547
|
+
async function selectCodeTool(defaultTool) {
|
|
548
|
+
const choices = [
|
|
549
|
+
{ name: "Claude Code", value: "claude-code" },
|
|
550
|
+
{ name: "Codex", value: "codex" }
|
|
551
|
+
];
|
|
530
552
|
const { tool } = await inquirer.prompt({
|
|
531
553
|
type: "list",
|
|
532
554
|
name: "tool",
|
|
533
555
|
message: "\u8BF7\u9009\u62E9\u8981\u914D\u7F6E\u7684\u5BA2\u6237\u7AEF\u5DE5\u5177\uFF1A",
|
|
534
|
-
choices
|
|
535
|
-
|
|
536
|
-
{ name: "Codex", value: "codex" }
|
|
537
|
-
]
|
|
556
|
+
choices,
|
|
557
|
+
default: defaultTool
|
|
538
558
|
});
|
|
539
559
|
return tool;
|
|
540
560
|
}
|
|
541
|
-
async function inputBaseUrl() {
|
|
561
|
+
async function inputBaseUrl(defaultUrl) {
|
|
542
562
|
const { url } = await inquirer.prompt({
|
|
543
563
|
type: "input",
|
|
544
564
|
name: "url",
|
|
545
565
|
message: "\u8BF7\u8F93\u5165\u4E2D\u8F6C\u7AD9 base_url\uFF08\u4F8B\u5982 https://api.srpllm.com\uFF09\uFF1A",
|
|
566
|
+
default: defaultUrl,
|
|
546
567
|
validate: (value) => {
|
|
547
568
|
const v = value.trim();
|
|
548
569
|
if (!v)
|
|
@@ -556,7 +577,13 @@ async function inputBaseUrl() {
|
|
|
556
577
|
});
|
|
557
578
|
return url.trim();
|
|
558
579
|
}
|
|
559
|
-
async function inputApiToken() {
|
|
580
|
+
async function inputApiToken(existingToken) {
|
|
581
|
+
if (existingToken) {
|
|
582
|
+
console.log(ansis.gray(` \u4E0A\u6B21 token\uFF1A${maskToken(existingToken)}`));
|
|
583
|
+
const reuse = await confirm("\u662F\u5426\u590D\u7528\u4E0A\u6B21\u7684 api_token\uFF1F", true);
|
|
584
|
+
if (reuse)
|
|
585
|
+
return existingToken;
|
|
586
|
+
}
|
|
560
587
|
const { token } = await inquirer.prompt({
|
|
561
588
|
type: "password",
|
|
562
589
|
name: "token",
|
|
@@ -591,7 +618,7 @@ async function fetchModelList(baseUrl, token) {
|
|
|
591
618
|
return null;
|
|
592
619
|
}
|
|
593
620
|
}
|
|
594
|
-
async function promptModelFromList(models, message, preset, skipPrompt) {
|
|
621
|
+
async function promptModelFromList(models, message, preset, skipPrompt, defaultModel) {
|
|
595
622
|
if (preset && preset.trim())
|
|
596
623
|
return preset.trim();
|
|
597
624
|
if (!models) {
|
|
@@ -601,7 +628,8 @@ async function promptModelFromList(models, message, preset, skipPrompt) {
|
|
|
601
628
|
const { manual } = await inquirer.prompt({
|
|
602
629
|
type: "input",
|
|
603
630
|
name: "manual",
|
|
604
|
-
message
|
|
631
|
+
message,
|
|
632
|
+
default: defaultModel
|
|
605
633
|
});
|
|
606
634
|
return manual.trim() || void 0;
|
|
607
635
|
}
|
|
@@ -612,11 +640,12 @@ async function promptModelFromList(models, message, preset, skipPrompt) {
|
|
|
612
640
|
choices: [
|
|
613
641
|
...buildModelsChoices(models),
|
|
614
642
|
{ name: "\u6682\u4E0D\u8BBE\u7F6E\uFF08\u8DF3\u8FC7\uFF09", value: "__none__" }
|
|
615
|
-
]
|
|
643
|
+
],
|
|
644
|
+
default: defaultModel
|
|
616
645
|
});
|
|
617
646
|
return choice === "__none__" ? void 0 : choice;
|
|
618
647
|
}
|
|
619
|
-
async function configureClaudeCode(options, baseUrl, token) {
|
|
648
|
+
async function configureClaudeCode(options, baseUrl, token, memory) {
|
|
620
649
|
const existing = getExistingClaudeApiConfig();
|
|
621
650
|
if (existing && !options.skipPrompt) {
|
|
622
651
|
console.log(ansis.blue("\n\u2139 \u68C0\u6D4B\u5230\u5DF2\u6709 Claude Code \u914D\u7F6E\uFF1A"));
|
|
@@ -637,16 +666,18 @@ async function configureClaudeCode(options, baseUrl, token) {
|
|
|
637
666
|
}
|
|
638
667
|
}
|
|
639
668
|
const models = await fetchModelList(baseUrl, token);
|
|
640
|
-
const
|
|
641
|
-
const
|
|
642
|
-
const
|
|
643
|
-
const
|
|
669
|
+
const m = memory.claude;
|
|
670
|
+
const model = await promptModelFromList(models, "\u8BF7\u9009\u62E9\u4E3B\u6A21\u578B (ANTHROPIC_MODEL)\uFF1A", options.model, options.skipPrompt, m?.model);
|
|
671
|
+
const opusModel = await promptModelFromList(models, "\u8BF7\u9009\u62E9 Opus \u6863\u6A21\u578B (ANTHROPIC_DEFAULT_OPUS_MODEL)\uFF1A", options.opusModel, options.skipPrompt, m?.opusModel);
|
|
672
|
+
const sonnetModel = await promptModelFromList(models, "\u8BF7\u9009\u62E9 Sonnet \u6863\u6A21\u578B (ANTHROPIC_DEFAULT_SONNET_MODEL)\uFF1A", options.sonnetModel, options.skipPrompt, m?.sonnetModel);
|
|
673
|
+
const haikuModel = await promptModelFromList(models, "\u8BF7\u9009\u62E9 Haiku \u6863\u6A21\u578B (ANTHROPIC_DEFAULT_HAIKU_MODEL)\uFF1A", options.haikuModel, options.skipPrompt, m?.haikuModel);
|
|
644
674
|
const config = { baseUrl, token, model, opusModel, sonnetModel, haikuModel };
|
|
645
675
|
writeClaudeApiConfig(config);
|
|
646
676
|
console.log(ansis.green("\n\u2714 Claude Code \u914D\u7F6E\u5B8C\u6210"));
|
|
647
677
|
displayClaudeConfig(config);
|
|
678
|
+
updateLocalConfig({ claude: { model, opusModel, sonnetModel, haikuModel } });
|
|
648
679
|
}
|
|
649
|
-
async function configureCodex(options, baseUrl, token) {
|
|
680
|
+
async function configureCodex(options, baseUrl, token, memory) {
|
|
650
681
|
const existing = getExistingCodexConfig();
|
|
651
682
|
if (existing && !options.skipPrompt) {
|
|
652
683
|
console.log(ansis.blue("\n\u2139 \u68C0\u6D4B\u5230\u5DF2\u6709 Codex \u914D\u7F6E\uFF1A"));
|
|
@@ -661,15 +692,17 @@ async function configureCodex(options, baseUrl, token) {
|
|
|
661
692
|
}
|
|
662
693
|
}
|
|
663
694
|
const models = await fetchModelList(baseUrl, token);
|
|
664
|
-
const model = await promptModelFromList(models, "\u8BF7\u9009\u62E9\u9ED8\u8BA4\u4F7F\u7528\u7684\u6A21\u578B\uFF1A", options.model, options.skipPrompt);
|
|
695
|
+
const model = await promptModelFromList(models, "\u8BF7\u9009\u62E9\u9ED8\u8BA4\u4F7F\u7528\u7684\u6A21\u578B\uFF1A", options.model, options.skipPrompt, memory.codex?.model);
|
|
665
696
|
const config = { baseUrl, token, model };
|
|
666
697
|
writeCodexApiConfig(config);
|
|
667
698
|
console.log(ansis.green("\n\u2714 Codex \u914D\u7F6E\u5B8C\u6210"));
|
|
668
699
|
displayCodexConfig(config);
|
|
700
|
+
updateLocalConfig({ codex: { model } });
|
|
669
701
|
}
|
|
670
702
|
async function init(options = {}) {
|
|
671
703
|
try {
|
|
672
|
-
const
|
|
704
|
+
const memory = readLocalConfig();
|
|
705
|
+
const tool = options.codeType ? resolveCodeToolType(options.codeType) : options.skipPrompt ? "claude-code" : await selectCodeTool(memory.codeType);
|
|
673
706
|
displayBanner(tool);
|
|
674
707
|
if (options.skipPrompt) {
|
|
675
708
|
await installTool(tool, true);
|
|
@@ -686,21 +719,22 @@ async function init(options = {}) {
|
|
|
686
719
|
console.log(ansis.green(`\u2714 ${tool === "claude-code" ? "Claude Code" : "Codex"} \u5DF2\u5B89\u88C5`));
|
|
687
720
|
}
|
|
688
721
|
}
|
|
689
|
-
const baseUrl = options.baseUrl || (options.skipPrompt ? "" : await inputBaseUrl());
|
|
722
|
+
const baseUrl = options.baseUrl || (options.skipPrompt ? memory.baseUrl || "" : await inputBaseUrl(memory.baseUrl));
|
|
690
723
|
if (!baseUrl) {
|
|
691
724
|
console.error(ansis.red("\u2716 \u7F3A\u5C11 base_url\uFF0C\u65E0\u6CD5\u7EE7\u7EED\u914D\u7F6E"));
|
|
692
725
|
process.exit(1);
|
|
693
726
|
}
|
|
694
|
-
const token = options.token || (options.skipPrompt ? "" : await inputApiToken());
|
|
727
|
+
const token = options.token || (options.skipPrompt ? memory.token || "" : await inputApiToken(memory.token));
|
|
695
728
|
if (!token) {
|
|
696
729
|
console.error(ansis.red("\u2716 \u7F3A\u5C11 api_token\uFF0C\u65E0\u6CD5\u7EE7\u7EED\u914D\u7F6E"));
|
|
697
730
|
process.exit(1);
|
|
698
731
|
}
|
|
699
732
|
if (tool === "claude-code") {
|
|
700
|
-
await configureClaudeCode(options, baseUrl, token);
|
|
733
|
+
await configureClaudeCode(options, baseUrl, token, memory);
|
|
701
734
|
} else {
|
|
702
|
-
await configureCodex(options, baseUrl, token);
|
|
735
|
+
await configureCodex(options, baseUrl, token, memory);
|
|
703
736
|
}
|
|
737
|
+
updateLocalConfig({ codeType: tool, baseUrl, token });
|
|
704
738
|
console.log(`
|
|
705
739
|
${ansis.cyan("\u{1F389} \u914D\u7F6E\u5B8C\u6210\uFF01\u73B0\u5728\u53EF\u4EE5\u76F4\u63A5\u4F7F\u7528\u5BF9\u5E94 CLI \u5DE5\u5177\u8FDE\u63A5 SrP-LLM \u4E2D\u8F6C\u7AD9\u3002")}`);
|
|
706
740
|
} catch (error) {
|
|
@@ -727,6 +761,15 @@ async function uninstall(options = {}) {
|
|
|
727
761
|
clearCodexApiConfig();
|
|
728
762
|
}
|
|
729
763
|
console.log(ansis.green("\u2714 \u4E2D\u8F6C\u7AD9\u914D\u7F6E\u5DF2\u6E05\u9664"));
|
|
764
|
+
const memory = readLocalConfig();
|
|
765
|
+
if (tool === "claude-code")
|
|
766
|
+
delete memory.claude;
|
|
767
|
+
else
|
|
768
|
+
delete memory.codex;
|
|
769
|
+
if (memory.codeType === tool)
|
|
770
|
+
delete memory.codeType;
|
|
771
|
+
writeLocalConfig(memory);
|
|
772
|
+
console.log(ansis.gray("\u2714 \u5DF2\u6E05\u9664\u672C\u5730\u8BB0\u5FC6"));
|
|
730
773
|
if (removeCli) {
|
|
731
774
|
const ok = await uninstallTool(tool);
|
|
732
775
|
if (!ok)
|
|
@@ -744,4 +787,4 @@ ${ansis.cyan("\u{1F389} \u6E05\u7406\u5B8C\u6210")}`);
|
|
|
744
787
|
}
|
|
745
788
|
}
|
|
746
789
|
|
|
747
|
-
export { installTool as A, uninstallTool as B, CLAUDE_DIR as C, DEFAULT_CODE_TOOL_TYPE as D,
|
|
790
|
+
export { installTool as A, uninstallTool as B, CLAUDE_DIR as C, DEFAULT_CODE_TOOL_TYPE as D, readLocalConfig as E, writeLocalConfig as F, updateLocalConfig as G, fetchModels as H, buildModelsChoices as I, version as J, RELAY_PROVIDER_ID as R, isWindows as a, CLAUDE_SETTINGS_FILE as b, commandExists as c, CODEX_DIR as d, CODEX_CONFIG_FILE as e, CODEX_AUTH_FILE as f, getPlatform as g, CODE_TOOL_TYPES as h, init as i, CODE_TOOL_ALIASES as j, CODE_TOOL_LABELS as k, ensureClaudeDir as l, readClaudeSettings as m, getExistingClaudeApiConfig as n, clearClaudeApiConfig as o, displayClaudeConfig as p, getExistingCodexConfig as q, resolveCodeToolType as r, writeCodexApiConfig as s, clearCodexApiConfig as t, uninstall as u, displayCodexConfig as v, writeClaudeApiConfig as w, isToolInstalled as x, detectInstalledVersion as y, selectInstallMethod as z };
|