runcc 0.1.4 → 0.1.6
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/CHANGELOG.md +16 -0
- package/README.md +32 -9
- package/dist/index.js +132 -17
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.1.6] - 2026-01-26
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Added token set/clean commands for managing provider tokens
|
|
12
|
+
|
|
13
|
+
## [0.1.5] - 2026-01-23
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- Fixed incorrect key/env configuration in Claude settings
|
|
17
|
+
- Migrated from apiUrl/anthropicApiKey fields to env.ANTHROPIC_* variables
|
|
18
|
+
- Fixed Claude Code integration to match actual configuration structure
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- Added support for model mappings (ANTHROPIC_DEFAULT_*_MODEL) in --claude persistent mode
|
|
22
|
+
- Simplified installation instructions in README
|
|
23
|
+
|
|
8
24
|
## [0.1.4] - 2026-01-19
|
|
9
25
|
|
|
10
26
|
### Added
|
package/README.md
CHANGED
|
@@ -13,11 +13,7 @@ Claude CLI 启动器,支持切换不同的 API endpoint。
|
|
|
13
13
|
## 安装
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
|
|
17
|
-
bun install -g .
|
|
18
|
-
|
|
19
|
-
# 或使用 npm
|
|
20
|
-
npm install -g .
|
|
16
|
+
npm install runcc@latest -g
|
|
21
17
|
```
|
|
22
18
|
|
|
23
19
|
## 快速开始
|
|
@@ -52,12 +48,14 @@ runcc
|
|
|
52
48
|
| `runcc list` | 列出所有 endpoints |
|
|
53
49
|
| `runcc add <name> <endpoint> [token]` | 添加自定义 endpoint |
|
|
54
50
|
| `runcc remove <name>` | 删除自定义 endpoint |
|
|
51
|
+
| `runcc token set <provider> [token]` | 设置指定 provider 的 token |
|
|
52
|
+
| `runcc token clean <provider>` | 清除指定 provider 的 token(`clean`/`clear` 均可) |
|
|
55
53
|
|
|
56
|
-
###
|
|
54
|
+
### 原生命令配置(持久化)
|
|
57
55
|
|
|
58
56
|
| 命令 | 说明 |
|
|
59
57
|
|------|------|
|
|
60
|
-
| `runcc <provider> --claude` | 配置原生 `claude` 命令使用第三方 endpoint |
|
|
58
|
+
| `runcc <provider> --claude` | 配置原生 `claude` 命令使用第三方 endpoint,持久化到 `~/.claude/settings.json` |
|
|
61
59
|
| `runcc --claude` | 恢复原生 `claude` 命令使用官方 endpoint |
|
|
62
60
|
|
|
63
61
|
### 代理管理
|
|
@@ -106,8 +104,18 @@ runcc
|
|
|
106
104
|
|
|
107
105
|
### ~/.claude/settings.json
|
|
108
106
|
|
|
107
|
+
**使用官方 endpoint 时:**
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"proxy": "http://agent.baidu.com:8891"
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**运行 `runcc glm --claude` 后(使用第三方 endpoint):**
|
|
109
115
|
```json
|
|
110
116
|
{
|
|
117
|
+
"apiUrl": "https://open.bigmodel.cn/api/paas/v4/",
|
|
118
|
+
"anthropicApiKey": "sk-glm-token",
|
|
111
119
|
"proxy": "http://agent.baidu.com:8891"
|
|
112
120
|
}
|
|
113
121
|
```
|
|
@@ -146,19 +154,24 @@ runcc proxy status
|
|
|
146
154
|
runcc proxy off
|
|
147
155
|
```
|
|
148
156
|
|
|
149
|
-
###
|
|
157
|
+
### 配置原生命令(持久化)
|
|
158
|
+
|
|
159
|
+
`--claude` 参数会将 endpoint 配置持久化写入 `~/.claude/settings.json`,之后直接运行 `claude` 命令时会使用指定的 endpoint。
|
|
150
160
|
|
|
151
161
|
```bash
|
|
152
162
|
# 让原生 claude 命令使用 glm
|
|
163
|
+
# 这会将 glm 配置写入 ~/.claude/settings.json
|
|
153
164
|
runcc glm --claude
|
|
154
165
|
|
|
155
|
-
# 之后直接使用 claude
|
|
166
|
+
# 之后直接使用 claude 命令即可,无需通过 runcc
|
|
156
167
|
claude "你好"
|
|
157
168
|
|
|
158
169
|
# 恢复使用官方 endpoint
|
|
159
170
|
runcc --claude
|
|
160
171
|
```
|
|
161
172
|
|
|
173
|
+
**注意**:`--claude` 配置是持久的,关闭 Claude 后仍然生效。如需切换回官方 endpoint,需运行 `runcc --claude`。
|
|
174
|
+
|
|
162
175
|
## Token 管理
|
|
163
176
|
|
|
164
177
|
首次使用某个 endpoint 时,如果未配置 token,会提示输入:
|
|
@@ -170,6 +183,16 @@ $ runcc glm
|
|
|
170
183
|
|
|
171
184
|
Token 会被保存到 `~/.runcc/config.json`,下次使用时无需再次输入。
|
|
172
185
|
|
|
186
|
+
也可以通过命令行直接设置或清除:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# 设置/覆盖 token(不传 token 会交互输入)
|
|
190
|
+
runcc token set glm sk-xxxx
|
|
191
|
+
|
|
192
|
+
# 清除 token
|
|
193
|
+
runcc token clean glm
|
|
194
|
+
```
|
|
195
|
+
|
|
173
196
|
## 开发
|
|
174
197
|
|
|
175
198
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -1995,6 +1995,33 @@ function saveToken(provider, token) {
|
|
|
1995
1995
|
config.tokens[provider] = token;
|
|
1996
1996
|
writeConfig(config);
|
|
1997
1997
|
}
|
|
1998
|
+
function clearToken(provider) {
|
|
1999
|
+
const config = readConfig();
|
|
2000
|
+
if (!config.tokens || !(provider in config.tokens)) {
|
|
2001
|
+
return;
|
|
2002
|
+
}
|
|
2003
|
+
delete config.tokens[provider];
|
|
2004
|
+
writeConfig(config);
|
|
2005
|
+
}
|
|
2006
|
+
function setCustomEndpointToken(name, token) {
|
|
2007
|
+
const config = readConfig();
|
|
2008
|
+
if (!config.endpoints) {
|
|
2009
|
+
return false;
|
|
2010
|
+
}
|
|
2011
|
+
const existingIndex = config.endpoints.findIndex((ep) => ep.name === name);
|
|
2012
|
+
if (existingIndex === -1) {
|
|
2013
|
+
return false;
|
|
2014
|
+
}
|
|
2015
|
+
const endpoint = config.endpoints[existingIndex];
|
|
2016
|
+
if (token === undefined) {
|
|
2017
|
+
delete endpoint.token;
|
|
2018
|
+
} else {
|
|
2019
|
+
endpoint.token = token;
|
|
2020
|
+
}
|
|
2021
|
+
config.endpoints[existingIndex] = endpoint;
|
|
2022
|
+
writeConfig(config);
|
|
2023
|
+
return true;
|
|
2024
|
+
}
|
|
1998
2025
|
function setLastUsed(provider) {
|
|
1999
2026
|
const config = readConfig();
|
|
2000
2027
|
config.lastUsed = provider;
|
|
@@ -2097,8 +2124,70 @@ function remove(name) {
|
|
|
2097
2124
|
}
|
|
2098
2125
|
}
|
|
2099
2126
|
|
|
2100
|
-
// src/commands/
|
|
2127
|
+
// src/commands/token.ts
|
|
2101
2128
|
import { createInterface as createInterface2 } from "node:readline";
|
|
2129
|
+
function isCustomEndpoint(name) {
|
|
2130
|
+
const endpoints = getCustomEndpoints();
|
|
2131
|
+
return endpoints.some((ep) => ep.name === name);
|
|
2132
|
+
}
|
|
2133
|
+
function assertProviderExists(name) {
|
|
2134
|
+
if (isBuiltinEndpoint(name) || isCustomEndpoint(name)) {
|
|
2135
|
+
return;
|
|
2136
|
+
}
|
|
2137
|
+
console.error(`错误: 未找到 endpoint "${name}"`);
|
|
2138
|
+
console.log('使用 "runcc list" 查看可用的 endpoints');
|
|
2139
|
+
process.exit(1);
|
|
2140
|
+
}
|
|
2141
|
+
async function promptToken(providerName) {
|
|
2142
|
+
const rl = createInterface2({
|
|
2143
|
+
input: process.stdin,
|
|
2144
|
+
output: process.stdout
|
|
2145
|
+
});
|
|
2146
|
+
return new Promise((resolve) => {
|
|
2147
|
+
rl.question(`请输入 ${providerName} 的 API Token: `, (answer) => {
|
|
2148
|
+
rl.close();
|
|
2149
|
+
resolve(answer.trim());
|
|
2150
|
+
});
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
async function tokenSet(provider, token) {
|
|
2154
|
+
assertProviderExists(provider);
|
|
2155
|
+
let finalToken = token;
|
|
2156
|
+
if (!finalToken) {
|
|
2157
|
+
finalToken = await promptToken(provider);
|
|
2158
|
+
}
|
|
2159
|
+
if (isBuiltinEndpoint(provider)) {
|
|
2160
|
+
saveToken(provider, finalToken);
|
|
2161
|
+
} else {
|
|
2162
|
+
setCustomEndpointToken(provider, finalToken);
|
|
2163
|
+
}
|
|
2164
|
+
console.log(`已保存 ${provider} 的 token`);
|
|
2165
|
+
}
|
|
2166
|
+
function tokenClean(provider) {
|
|
2167
|
+
assertProviderExists(provider);
|
|
2168
|
+
if (isBuiltinEndpoint(provider)) {
|
|
2169
|
+
const existing = getToken(provider);
|
|
2170
|
+
if (existing) {
|
|
2171
|
+
clearToken(provider);
|
|
2172
|
+
console.log(`已清除 ${provider} 的 token`);
|
|
2173
|
+
} else {
|
|
2174
|
+
console.log(`未配置 ${provider} 的 token`);
|
|
2175
|
+
}
|
|
2176
|
+
return;
|
|
2177
|
+
}
|
|
2178
|
+
const endpoints = getCustomEndpoints();
|
|
2179
|
+
const endpoint = endpoints.find((ep) => ep.name === provider);
|
|
2180
|
+
const hadToken = !!endpoint?.token;
|
|
2181
|
+
setCustomEndpointToken(provider, undefined);
|
|
2182
|
+
if (hadToken) {
|
|
2183
|
+
console.log(`已清除 ${provider} 的 token`);
|
|
2184
|
+
} else {
|
|
2185
|
+
console.log(`未配置 ${provider} 的 token`);
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
// src/commands/proxy.ts
|
|
2190
|
+
import { createInterface as createInterface3 } from "node:readline";
|
|
2102
2191
|
|
|
2103
2192
|
// src/utils/claude-settings.ts
|
|
2104
2193
|
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
|
|
@@ -2148,16 +2237,38 @@ function removeClaudeProxy() {
|
|
|
2148
2237
|
delete settings.proxy;
|
|
2149
2238
|
writeClaudeSettings(settings);
|
|
2150
2239
|
}
|
|
2151
|
-
function setThirdPartyApi(apiUrl, apiKey) {
|
|
2240
|
+
function setThirdPartyApi(apiUrl, apiKey, models) {
|
|
2152
2241
|
const settings = readClaudeSettings();
|
|
2153
|
-
settings.
|
|
2154
|
-
|
|
2242
|
+
if (!settings.env) {
|
|
2243
|
+
settings.env = {};
|
|
2244
|
+
}
|
|
2245
|
+
settings.env.ANTHROPIC_BASE_URL = apiUrl;
|
|
2246
|
+
settings.env.ANTHROPIC_AUTH_TOKEN = apiKey;
|
|
2247
|
+
if (models) {
|
|
2248
|
+
if (models.haiku) {
|
|
2249
|
+
settings.env.ANTHROPIC_DEFAULT_HAIKU_MODEL = models.haiku;
|
|
2250
|
+
}
|
|
2251
|
+
if (models.opus) {
|
|
2252
|
+
settings.env.ANTHROPIC_DEFAULT_OPUS_MODEL = models.opus;
|
|
2253
|
+
}
|
|
2254
|
+
if (models.sonnet) {
|
|
2255
|
+
settings.env.ANTHROPIC_DEFAULT_SONNET_MODEL = models.sonnet;
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2155
2258
|
writeClaudeSettings(settings);
|
|
2156
2259
|
}
|
|
2157
2260
|
function removeThirdPartyApi() {
|
|
2158
2261
|
const settings = readClaudeSettings();
|
|
2159
|
-
|
|
2160
|
-
|
|
2262
|
+
if (settings.env) {
|
|
2263
|
+
delete settings.env.ANTHROPIC_BASE_URL;
|
|
2264
|
+
delete settings.env.ANTHROPIC_AUTH_TOKEN;
|
|
2265
|
+
delete settings.env.ANTHROPIC_DEFAULT_HAIKU_MODEL;
|
|
2266
|
+
delete settings.env.ANTHROPIC_DEFAULT_OPUS_MODEL;
|
|
2267
|
+
delete settings.env.ANTHROPIC_DEFAULT_SONNET_MODEL;
|
|
2268
|
+
if (Object.keys(settings.env).length === 0) {
|
|
2269
|
+
delete settings.env;
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2161
2272
|
writeClaudeSettings(settings);
|
|
2162
2273
|
}
|
|
2163
2274
|
function backupClaudeSettings() {
|
|
@@ -2248,7 +2359,7 @@ function proxyHelp() {
|
|
|
2248
2359
|
`);
|
|
2249
2360
|
}
|
|
2250
2361
|
async function promptProxyUrl() {
|
|
2251
|
-
const rl =
|
|
2362
|
+
const rl = createInterface3({
|
|
2252
2363
|
input: process.stdin,
|
|
2253
2364
|
output: process.stdout
|
|
2254
2365
|
});
|
|
@@ -2261,7 +2372,7 @@ async function promptProxyUrl() {
|
|
|
2261
2372
|
}
|
|
2262
2373
|
|
|
2263
2374
|
// src/commands/run.ts
|
|
2264
|
-
import { createInterface as
|
|
2375
|
+
import { createInterface as createInterface4 } from "node:readline";
|
|
2265
2376
|
|
|
2266
2377
|
// src/utils/launcher.ts
|
|
2267
2378
|
import { spawn } from "node:child_process";
|
|
@@ -2333,7 +2444,7 @@ async function runOfficial(passthroughArgs = []) {
|
|
|
2333
2444
|
const claudeProxy = getClaudeProxy();
|
|
2334
2445
|
const backup = backupClaudeSettings();
|
|
2335
2446
|
let needsRestore = false;
|
|
2336
|
-
if (backup.
|
|
2447
|
+
if (backup.env?.ANTHROPIC_BASE_URL || backup.env?.ANTHROPIC_AUTH_TOKEN) {
|
|
2337
2448
|
removeThirdPartyApi();
|
|
2338
2449
|
needsRestore = true;
|
|
2339
2450
|
console.log("已临时清除第三方 endpoint 配置");
|
|
@@ -2365,7 +2476,7 @@ async function runProvider(providerName, configureClaude, passthroughArgs = [])
|
|
|
2365
2476
|
}
|
|
2366
2477
|
let token = endpoint.token || getToken(providerName);
|
|
2367
2478
|
if (!token) {
|
|
2368
|
-
token = await
|
|
2479
|
+
token = await promptToken2(providerName);
|
|
2369
2480
|
saveToken(providerName, token);
|
|
2370
2481
|
}
|
|
2371
2482
|
setLastUsed(providerName);
|
|
@@ -2380,11 +2491,11 @@ async function runProvider(providerName, configureClaude, passthroughArgs = [])
|
|
|
2380
2491
|
needsRestore = true;
|
|
2381
2492
|
console.log("已临时清除 settings.json 中的 ANTHROPIC 配置");
|
|
2382
2493
|
}
|
|
2383
|
-
if (needsRestore) {
|
|
2494
|
+
if (needsRestore && !configureClaude) {
|
|
2384
2495
|
console.log("Claude 退出后将恢复配置...");
|
|
2385
2496
|
}
|
|
2386
2497
|
if (configureClaude) {
|
|
2387
|
-
setThirdPartyApi(endpoint.endpoint, token);
|
|
2498
|
+
setThirdPartyApi(endpoint.endpoint, token, endpoint.models);
|
|
2388
2499
|
console.log(`已配置原生 claude 命令使用 ${providerName}`);
|
|
2389
2500
|
console.log('使用 "runcc --claude" 可恢复官方配置');
|
|
2390
2501
|
}
|
|
@@ -2395,7 +2506,7 @@ async function runProvider(providerName, configureClaude, passthroughArgs = [])
|
|
|
2395
2506
|
models: endpoint.models
|
|
2396
2507
|
}, passthroughArgs);
|
|
2397
2508
|
const exitCode = await waitForExit(child);
|
|
2398
|
-
if (needsRestore) {
|
|
2509
|
+
if (needsRestore && !configureClaude) {
|
|
2399
2510
|
restoreClaudeSettings(backup);
|
|
2400
2511
|
console.log("已恢复配置");
|
|
2401
2512
|
}
|
|
@@ -2417,8 +2528,8 @@ function getEndpointConfig(name) {
|
|
|
2417
2528
|
const custom = getCustomEndpoints();
|
|
2418
2529
|
return custom.find((ep) => ep.name === name);
|
|
2419
2530
|
}
|
|
2420
|
-
async function
|
|
2421
|
-
const rl =
|
|
2531
|
+
async function promptToken2(providerName) {
|
|
2532
|
+
const rl = createInterface4({
|
|
2422
2533
|
input: process.stdin,
|
|
2423
2534
|
output: process.stdout
|
|
2424
2535
|
});
|
|
@@ -2486,13 +2597,16 @@ program2.name("runcc").description("Claude 启动器 - 支持切换不同的 API
|
|
|
2486
2597
|
program2.command("list").description("列出所有可用的 endpoints").action(list);
|
|
2487
2598
|
program2.command("add").description("添加自定义 endpoint").argument("<name>", "endpoint 名称").argument("<endpoint>", "API 地址").action(add);
|
|
2488
2599
|
program2.command("remove").description("删除自定义 endpoint").argument("<name>", "endpoint 名称").action(remove);
|
|
2600
|
+
var tokenCmd = program2.command("token").description("token 管理");
|
|
2601
|
+
tokenCmd.command("set").description("设置 token").argument("<provider>", "provider 名称 (glm, deepseek, minimax 或自定义)").argument("[token]", "API Token(可选,不传则交互输入)").action(tokenSet);
|
|
2602
|
+
tokenCmd.command("clean").alias("clear").description("清除 token").argument("<provider>", "provider 名称 (glm, deepseek, minimax 或自定义)").action(tokenClean);
|
|
2489
2603
|
var proxyCmd = program2.command("proxy").description("代理管理");
|
|
2490
2604
|
proxyCmd.command("on").description("开启代理").action(proxyOn);
|
|
2491
2605
|
proxyCmd.command("off").description("关闭代理").action(proxyOff);
|
|
2492
2606
|
proxyCmd.command("reset").description("重置代理配置").action(proxyReset);
|
|
2493
2607
|
proxyCmd.command("status").description("查看代理状态").action(proxyStatus);
|
|
2494
2608
|
proxyCmd.command("help").description("代理帮助信息").action(proxyHelp);
|
|
2495
|
-
program2.argument("[provider]", "provider 名称 (glm, deepseek, minimax 或自定义)").option("--claude", "
|
|
2609
|
+
program2.argument("[provider]", "provider 名称 (glm, deepseek, minimax 或自定义)").option("--claude", "持久化配置到 ~/.claude/settings.json,让 claude 命令使用指定 endpoint").allowExcessArguments(true).action(async (provider, options) => {
|
|
2496
2610
|
try {
|
|
2497
2611
|
validateDashPosition(process.argv);
|
|
2498
2612
|
const passthroughArgs = extractPassthroughArgs(process.argv);
|
|
@@ -2513,9 +2627,10 @@ program2.argument("[provider]", "provider 名称 (glm, deepseek, minimax 或自
|
|
|
2513
2627
|
console.error(" runcc -- <claude参数> # 启动官方 Claude 并透传参数");
|
|
2514
2628
|
console.error(" runcc glm -- <claude参数> # 使用 glm provider 并透传参数");
|
|
2515
2629
|
console.error(" runcc --claude -- <参数> # 恢复官方配置并透传参数");
|
|
2516
|
-
console.error(" runcc glm --claude -- <参数> # 配置原生 claude 命令使用 glm");
|
|
2630
|
+
console.error(" runcc glm --claude -- <参数> # 配置原生 claude 命令使用 glm(持久化)");
|
|
2517
2631
|
console.error("");
|
|
2518
2632
|
console.error("说明: -- 分隔符用于将后续参数透传给 Claude CLI");
|
|
2633
|
+
console.error(" --claude 会将配置写入 ~/.claude/settings.json,之后直接运行 claude 即可使用指定 endpoint");
|
|
2519
2634
|
process.exit(1);
|
|
2520
2635
|
}
|
|
2521
2636
|
throw error;
|