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 CHANGED
@@ -1,193 +1,143 @@
1
- [![npm version][npm-version-src]][npm-version-href]
2
- [![npm downloads][npm-downloads-src]][npm-downloads-href]
3
- [![License][license-src]][license-href]
4
- [![Claude Code][claude-code-src]][claude-code-href]
5
- [![codecov][codecov-src]][codecov-href]
6
- [![JSDocs][jsdocs-src]][jsdocs-href]
7
- [![Ask DeepWiki][deepwiki-src]][deepwiki-href]
8
-
9
- <div align="center">
10
- <img src="./src/assets/banner.webp" alt="Banner"/>
11
-
12
- <h1>
13
- ZCF - Zero-Config Code Flow
14
- </h1>
15
-
16
- <p align="center">
17
- <b>English</b> | <a href="README_zh-CN.md">中文</a> | <a href="README_ja-JP.md">日本語</a> | <a href="CHANGELOG.md">Changelog</a>
18
-
19
- **✨ Full Documentation**: [ZCF Docs](https://zcf.ufomiao.com/)
20
-
21
- > Zero-config, one-click setup for Claude Code & Codex with bilingual support, intelligent agent system and personalized AI assistant
22
- </p>
23
- </div>
24
-
25
- ## ♥️ Sponsors
26
-
27
- [![GLM](./src/assets/GLM-en.png)](https://z.ai/subscribe?ic=8JVLJQFSKB)
28
-
29
- This project is sponsored by Z.ai, supporting us with their GLM CODING PLAN.
30
- GLM CODING PLAN is a subscription service designed for AI coding, starting at just $10/month. It provides access to their flagship GLM-4.7 & (GLM-5 Only Available for Pro Users)model across 10+ popular AI coding tools (Claude Code, Cline, Roo Code, etc.), offering developers top-tier, fast, and stable coding experiences.
31
- Get 10% OFF GLM CODING PLAN:https://z.ai/subscribe?ic=8JVLJQFSKB
32
-
33
- ---
34
-
35
- [![Sponsor PatewayAI](./src/assets/pateway.ai-en.png)](https://pateway.ai/?ch=vnr0h5&aff=9AWWH87C)
36
- PatewayAI is a high-quality model API relay service provider focused on official direct connections for serious AI developers, offering the full range of Claude and Codex series models. 100% official source supply with no adulteration — open to inspection. Transparent billing with token-level invoices auditable line by line. Enterprise-grade concurrency support with a dedicated management platform for enterprise customers, including formal contracts and invoicing. PatewayAI offers an exclusive benefit for ZCF users: register via <a href="https://pateway.ai/?ch=vnr0h5&aff=9AWWH87C">this link</a> to get $3 free trial credit, recharges as low as 60% off, with bilateral invite rewards up to $150!
37
-
38
- ---
39
-
40
- [![Sponsor AI API](./src/assets/302.ai-en.jpg)](https://share.302.ai/gAT9VG)
41
- [302.AI](https://share.302.ai/gAT9VG) is a pay-as-you-go enterprise AI resource hub that offers the latest and most comprehensive AI models and APIs on the market, along with a variety of ready-to-use online AI applications.
42
-
43
- ---
44
-
45
- <table>
46
- <tbody>
47
- <tr>
48
- <td width="180"><a href="https://www.packyapi.com/register?aff=zcf"><img src="./src/assets/packycode.png" alt="PackyCode" width="150"></a></td>
49
- <td>Thanks to PackyCode for sponsoring this project! PackyCode is a reliable and efficient API relay service provider, offering relay services for Claude Code, Codex, Gemini, and more. PackyCode provides special discounts for our software users: register using <a href="https://www.packyapi.com/register?aff=zcf">this link</a> and enter the "zcf" promo code during recharge to get 10% off.</td>
50
- </tr>
51
- <tr>
52
- <td width="180"><a href="https://apikey.fun/register?aff=ZCFZCF"><img src="./src/assets/apikey-fun.png" alt="APIKEY.FUN" width="150"></a></td>
53
- <td>Thanks to APIKEY.FUN for sponsoring this project! APIKEY.FUN is a professional enterprise-grade AI relay platform dedicated to providing stable, efficient, and low-cost API access for both companies and individual developers. The platform supports popular models including Claude, OpenAI, and Gemini, with pricing as low as 7% of official rates. Register via <a href="https://apikey.fun/register?aff=ZCFZCF">this link</a> to enjoy an exclusive offer of up to permanent 95% recharge pricing (5% off).</td>
54
- </tr>
55
- <tr>
56
- <td width="180"><a href="https://www.aicodemirror.com/register?invitecode=ZCFZCF"><img src="./src/assets/AICodeMirror.jpg" alt="AICodeMirror" width="150"></a></td>
57
- <td>Thanks to AICodeMirror for sponsoring this project! AICodeMirror provides official high-stability relay services for Claude Code/Codex/Gemini CLI, supporting enterprise-level high concurrency, fast invoicing, and 7x24 dedicated technical support. Official channels for Claude Code/Codex/Gemini at discounts as low as 38%/2%/10.9% off, with additional discounts on top-ups! AICodeMirror offers special benefits for ZCF users: users who register through <a href="https://www.aicodemirror.com/register?invitecode=ZCFZCF">this link</a> can enjoy 20% off on first top-up, and enterprise customers can get up to 25% off!</td>
58
- </tr>
59
- <tr>
60
- <td width="180"><a href="https://crazyrouter.com/?utm_source=github&utm_medium=sponsor&utm_campaign=zcf&aff=yJFo"><img src="./src/assets/crazyrouter.svg" alt="Crazyrouter" width="150"></a></td>
61
- <td>Thanks to Crazyrouter for sponsoring this project! Crazyrouter is a high-performance AI API aggregation gateway — one API key for 300+ models (GPT, Claude, Gemini, DeepSeek, and more). All models at 55% of official pricing with auto-failover, smart routing, and unlimited concurrency. Fully OpenAI-compatible, works seamlessly with Claude Code, Codex, and Gemini CLI. Crazyrouter offers an exclusive deal for ZCF users: register via <a href="https://crazyrouter.com/?utm_source=github&utm_medium=sponsor&utm_campaign=zcf&aff=yJFo">this link</a> to get $2 free credit instantly!</td>
62
- </tr>
63
- </tbody>
64
- </table>
65
-
66
- ## 🚀 Quick Start
67
-
68
- - Recommended: `npx zcf` opens the interactive menu — pick what you need.
69
- - Common commands:
70
-
71
- ```bash
72
- npx zcf i # Full initialization: install + workflows + API/CCR + MCP
73
- npx zcf u # Update workflows only
74
- npx zcf --lang zh-CN # Switch interface language (example)
75
- ```
76
-
77
- - Non-interactive example (provider preset):
78
-
79
- ```bash
80
- npx zcf i -s -p 302ai -k "sk-xxx"
81
- ```
82
-
83
- More usage, options, and workflows: see documentation.
84
-
85
- ## 📖 Full Documentation
86
-
87
- - https://zcf.ufomiao.com/
88
-
89
- ## 💬 Community
90
-
91
- Join our Telegram group for support, discussions, and updates:
92
-
93
- [![Telegram](https://img.shields.io/badge/Telegram-Join%20Chat-blue?style=flat&logo=telegram)](https://t.me/ufomiao_zcf)
94
-
95
- ## 🙏 Acknowledgments
96
-
97
- This project is inspired by and incorporates work from:
98
-
99
- - [LINUX DO - New Ideal Community](https://linux.do)
100
- - [CCR](https://github.com/musistudio/claude-code-router)
101
- - [CCometixLine](https://github.com/Haleclipse/CCometixLine)
102
- - [ccusage](https://github.com/ryoppippi/ccusage)
103
- - [BMad Method](https://github.com/bmad-code-org/BMAD-METHOD)
104
-
105
- Thanks to these community contributors for sharing!
106
-
107
- ## ❤️ Support & Sponsors
108
-
109
- If you find this project helpful, please consider sponsoring its development. Your support is greatly appreciated!
110
-
111
- [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/UfoMiao)
112
-
113
- <table>
114
- <tr>
115
- <td><img src="/src/assets/alipay.webp" width="200" alt="Alipay" /></td>
116
- <td><img src="/src/assets/wechat.webp" width="200" alt="WeChat Pay" /></td>
117
- </tr>
118
- </table>
119
-
120
- ### Our Sponsors
121
-
122
- A huge thank you to all our sponsors for their generous support!
123
-
124
- 【Corporate Sponsors】
125
-
126
- - [302.AI](https://share.302.ai/gAT9VG) (first corporate sponsorship 🤠)
127
- - [GLM](https://z.ai/subscribe?ic=8JVLJQFSKB) (first AI model sponsorship 🤖)
128
- - [PackyCode](https://www.packyapi.com/register?aff=zcf) (first API proxy service sponsor 🧝🏻‍♀️)
129
- - [APIKEY.FUN](https://apikey.fun/register?aff=ZCFZCF) (enterprise AI relay sponsor 🎁)
130
- - [AICodeMirror](https://www.aicodemirror.com/register?invitecode=ZCFZCF) (official high-stability relay service sponsor 🪞)
131
- - [UUCode](https://www.uucode.org/auth?ref=JQ2DJ1T8) (sponsored $100 proxy credits 💰)
132
- - [Crazyrouter](https://crazyrouter.com/?utm_source=github&utm_medium=sponsor&utm_campaign=zcf&aff=yJFo) (AI API aggregation gateway sponsor 🚀)
133
- - [PatewayAI](https://pateway.ai/?ch=vnr0h5&aff=9AWWH87C) (official direct-connect relay service sponsor 🛡️)
134
-
135
- 【Individual Sponsors】
136
-
137
- - Tc (first sponsor)
138
- - Argolinhas (first ko-fi sponsor ٩(•̤̀ᵕ•̤́๑))
139
- - r\*r (first anonymous sponsor 🤣)
140
- - \*\*康 (first KFC sponsor 🍗)
141
- - \*东 (first coffee sponsor ☕️)
142
- - 炼\*3 (first Termux user sponsor 📱)
143
- - [chamo101](https://github.com/chamo101) (first GitHub issue sponsor 🎉)
144
- - 初屿贤 (first Codex user sponsor 🙅🏻‍♂️)
145
- - Protein (first 1688 sponsor 😏)
146
- - [musistudio](https://github.com/musistudio) (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
- [![Star History Chart](https://api.star-history.com/svg?repos=UfoMiao/zcf&type=Date)](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
+ [![npm version](https://img.shields.io/npm/v/srpllm.svg)](https://www.npmjs.com/package/srpllm)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./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, G as version } from './shared/srpllm.BB4ML_UM.mjs';
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, F as buildModelsChoices, o as clearClaudeApiConfig, t as clearCodexApiConfig, c as commandExists, y as detectInstalledVersion, p as displayClaudeConfig, v as displayCodexConfig, l as ensureClaudeDir, E 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, r as resolveCodeToolType, z as selectInstallMethod, u as uninstall, B as uninstallTool, w as writeClaudeApiConfig, s as writeCodexApiConfig } from './shared/srpllm.BB4ML_UM.mjs';
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 { writeFileSync, existsSync, readFileSync, mkdirSync } from 'node:fs';
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.0.0";
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
- { name: "Claude Code", value: "claude-code" },
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 model = await promptModelFromList(models, "\u8BF7\u9009\u62E9\u4E3B\u6A21\u578B (ANTHROPIC_MODEL)\uFF1A", options.model, options.skipPrompt);
641
- const opusModel = await promptModelFromList(models, "\u8BF7\u9009\u62E9 Opus \u6863\u6A21\u578B (ANTHROPIC_DEFAULT_OPUS_MODEL)\uFF1A", options.opusModel, options.skipPrompt);
642
- const sonnetModel = await promptModelFromList(models, "\u8BF7\u9009\u62E9 Sonnet \u6863\u6A21\u578B (ANTHROPIC_DEFAULT_SONNET_MODEL)\uFF1A", options.sonnetModel, options.skipPrompt);
643
- const haikuModel = await promptModelFromList(models, "\u8BF7\u9009\u62E9 Haiku \u6863\u6A21\u578B (ANTHROPIC_DEFAULT_HAIKU_MODEL)\uFF1A", options.haikuModel, options.skipPrompt);
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 tool = options.codeType ? resolveCodeToolType(options.codeType) : options.skipPrompt ? "claude-code" : await selectCodeTool();
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, fetchModels as E, buildModelsChoices as F, version as G, 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 };
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 };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srpllm",
3
3
  "type": "module",
4
- "version": "1.0.0",
4
+ "version": "1.1.0",
5
5
  "packageManager": "pnpm@10.17.1",
6
6
  "description": "SrP-LLM 中转站客户端一键配置工具:安装 Claude Code / Codex 并引导填写 base_url、api_token 与模型",
7
7
  "author": {