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 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/proxy.ts
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.apiUrl = apiUrl;
2154
- settings.anthropicApiKey = apiKey;
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
- delete settings.apiUrl;
2160
- delete settings.anthropicApiKey;
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 = createInterface2({
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 createInterface3 } from "node:readline";
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.apiUrl || backup.anthropicApiKey) {
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 promptToken(providerName);
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 promptToken(providerName) {
2421
- const rl = createInterface3({
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", "配置原生 claude 命令").allowExcessArguments(true).action(async (provider, options) => {
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runcc",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "CC launcher with endpoint switching support",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",