@done-coding/cli-cc-switch 0.2.0 → 0.3.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.
@@ -0,0 +1,659 @@
1
+ #!/usr/bin/env node
2
+ import { spawn as le } from "node:child_process";
3
+ import C from "node:os";
4
+ import k from "node:path";
5
+ import { resolveHandlerContext as Y, xPrompts as q } from "@done-coding/cli-utils";
6
+ import v from "node:fs";
7
+ import de from "node:readline";
8
+ const l = k.join(
9
+ C.homedir(),
10
+ ".done-coding",
11
+ "cc-switch",
12
+ "profile.json"
13
+ ), c = k.join(
14
+ C.homedir(),
15
+ ".done-coding",
16
+ "cc-switch",
17
+ "settings.json"
18
+ ), A = "--meta-profile=", I = "--meta-pick", b = "--meta-silent", O = "--meta-generate", E = "--meta-apiKey=", w = "--meta-model-name=", $ = "--meta-provider=", N = "--meta-provider-list", j = "--meta-model-list", M = "--meta-help", L = "--meta-version", J = {
19
+ run: 0,
20
+ profile: 1,
21
+ pick: 2,
22
+ setkey: 3,
23
+ addmodel: 4,
24
+ providerlist: 5,
25
+ modellist: 6,
26
+ generate: 7,
27
+ version: 8,
28
+ help: 9
29
+ }, u = (e, r) => J[r] > J[e] ? r : e, pe = (e) => e.startsWith("--meta-") && e !== I && e !== b && e !== O && e !== M && e !== L && e !== N && e !== j && !e.startsWith(A) && !e.startsWith(E) && !e.startsWith(w) && !e.startsWith($), fe = () => {
30
+ process.stdout.write(
31
+ [
32
+ "dc-cc-switch(cc-router)— claude-code 模型路由透传",
33
+ "",
34
+ "用法:",
35
+ " dc-cc-switch [meta 选项] <claude 参数...>",
36
+ "",
37
+ "meta 选项(cc-switch 自身命令面,不透传给 claude):",
38
+ ` ${A}<name> 显式指定 profile 启动`,
39
+ ` ${I} 终端交互选择 profile 启动`,
40
+ ` ${b} 压制 output.* 输出(MCP/AI 调用避免污染)`,
41
+ ` ${O} 从 settings.json 重新生成 profile.json`,
42
+ ` ${E}<key> 更新指定提供商 apiKey(自动重建)`,
43
+ ` ${w}<name> 添加模型(自动重建)`,
44
+ ` ${$}<id> 显式指定 provider(供 apiKey/model-name 跳过选择)`,
45
+ ` ${N} 输出提供商列表(id + name)`,
46
+ ` ${j} 输出模型列表(name + 所属 provider)`,
47
+ ` ${M} 显示本帮助`,
48
+ ` ${L} 显示版本`,
49
+ "",
50
+ "其余所有参数原样透传给 claude。",
51
+ `配置: ${l}`,
52
+ `源: ${c}(--meta-generate 消费,provider 内嵌 models)`,
53
+ ""
54
+ ].join(`
55
+ `)
56
+ );
57
+ }, me = (e) => {
58
+ process.stdout.write(`${e}
59
+ `);
60
+ }, D = async (e) => {
61
+ const r = Object.keys(e.profiles);
62
+ r.length === 0 && (process.stderr.write(
63
+ `配置中没有可用 profile,请先编辑 ${l}。
64
+ `
65
+ ), process.exit(1)), Y().interactive || (process.stderr.write(
66
+ `--meta-pick 需要交互式终端,请改用 --meta-profile=<name> 显式指定。
67
+ `
68
+ ), process.exit(1));
69
+ const { profile: t } = await q({
70
+ type: "select",
71
+ name: "profile",
72
+ message: "选择以哪个配置启动 claude",
73
+ choices: r.map((o) => ({ title: o, value: o }))
74
+ });
75
+ return t;
76
+ }, ue = async (e) => {
77
+ const r = Object.keys(e.providers);
78
+ r.length === 0 && (process.stderr.write(
79
+ `settings.json 没有可用提供商,请先编辑 ${c}。
80
+ `
81
+ ), process.exit(1)), Y().interactive || (process.stderr.write(
82
+ `需要交互式终端选择提供商,请改用 ${$}<id> 显式指定。
83
+ `
84
+ ), process.exit(1));
85
+ const { provider: t } = await q({
86
+ type: "select",
87
+ name: "provider",
88
+ message: "选择提供商",
89
+ choices: r.map((o) => ({
90
+ title: `${o}(${e.providers[o].name})`,
91
+ value: o
92
+ }))
93
+ });
94
+ return t;
95
+ }, Ee = (e) => {
96
+ let r, t, o, s, n = "run", a = !1;
97
+ const d = [];
98
+ for (const i of e) {
99
+ if (i.startsWith(A)) {
100
+ r = i.slice(A.length), n = u(n, "profile");
101
+ continue;
102
+ }
103
+ if (i.startsWith(E)) {
104
+ if (t = i.slice(E.length), !t)
105
+ throw new Error(`${E} 需提供 apiKey 值`);
106
+ n = u(n, "setkey");
107
+ continue;
108
+ }
109
+ if (i.startsWith(w)) {
110
+ if (o = i.slice(w.length), !o)
111
+ throw new Error(`${w} 需提供模型名`);
112
+ n = u(n, "addmodel");
113
+ continue;
114
+ }
115
+ if (i.startsWith($)) {
116
+ if (s = i.slice($.length), !s)
117
+ throw new Error(`${$} 需提供 provider id`);
118
+ continue;
119
+ }
120
+ if (i === I) {
121
+ n = u(n, "pick");
122
+ continue;
123
+ }
124
+ if (i === b) {
125
+ a = !0;
126
+ continue;
127
+ }
128
+ if (i === O) {
129
+ n = u(n, "generate");
130
+ continue;
131
+ }
132
+ if (i === N) {
133
+ n = u(n, "providerlist");
134
+ continue;
135
+ }
136
+ if (i === j) {
137
+ n = u(n, "modellist");
138
+ continue;
139
+ }
140
+ if (i === M) {
141
+ n = u(n, "help");
142
+ continue;
143
+ }
144
+ if (i === L) {
145
+ n = u(n, "version");
146
+ continue;
147
+ }
148
+ if (pe(i))
149
+ throw new Error(
150
+ `未知 meta 选项:${i}。可用选项:${A}<name>、${I}、${b}、${O}、${E}<key>、${w}<name>、${$}<id>、${N}、${j}、${M}、${L}`
151
+ );
152
+ d.push(i);
153
+ }
154
+ return we({ action: n, apiKey: t, modelName: o, providerId: s }), {
155
+ action: n,
156
+ profileName: r,
157
+ apiKey: t,
158
+ modelName: o,
159
+ providerId: s,
160
+ silent: a,
161
+ passthrough: d
162
+ };
163
+ }, we = (e) => {
164
+ const { action: r, apiKey: t, modelName: o, providerId: s } = e, n = [t, o].filter((a) => a !== void 0).length;
165
+ if (n > 1)
166
+ throw new Error(
167
+ `不能同时指定 ${E} 与 ${w}`
168
+ );
169
+ if (r === "generate" && n > 0)
170
+ throw new Error(
171
+ `${O} 不能与 ${E} / ${w} 同时使用`
172
+ );
173
+ if (s !== void 0 && r !== "setkey" && r !== "addmodel" && r !== "help" && r !== "version")
174
+ throw new Error(
175
+ `${$} 仅用于 ${E} / ${w}`
176
+ );
177
+ }, ve = (e, r) => {
178
+ const t = r ?? e.defaultProfile, o = e.profiles[t];
179
+ if (!o) {
180
+ const s = Object.keys(e.profiles).join(", ") || "(无)";
181
+ throw new Error(
182
+ `profile "${t}" 不存在。可用 profile:${s}。配置文件:${l}。若需从 provider.json + model.json 重建,请运行 --meta-generate`
183
+ );
184
+ }
185
+ return { name: t, profile: o };
186
+ }, $e = /^ANTHROPIC_/, he = [
187
+ "CLAUDE_CODE_SUBAGENT_MODEL",
188
+ "CLAUDE_CODE_EFFORT_LEVEL"
189
+ ], z = k.join(
190
+ C.homedir(),
191
+ ".claude",
192
+ "settings.json"
193
+ ), Q = (e) => $e.test(e) || he.includes(e), ye = (e, r) => {
194
+ const t = {};
195
+ for (const [o, s] of Object.entries(e))
196
+ s !== void 0 && (Q(o) || (t[o] = s));
197
+ for (const [o, s] of Object.entries(r))
198
+ t[o] = s;
199
+ return t;
200
+ }, Se = (e) => !e || typeof e != "object" ? [] : Object.keys(e).filter((r) => Q(r)), Pe = () => {
201
+ let e;
202
+ try {
203
+ e = JSON.parse(v.readFileSync(z, "utf8"));
204
+ } catch {
205
+ return null;
206
+ }
207
+ if (typeof e != "object" || e === null)
208
+ return null;
209
+ const r = e.env;
210
+ return typeof r != "object" || r === null || Array.isArray(r) ? null : r;
211
+ }, W = {
212
+ defaultProfile: "deepseek-pro",
213
+ providers: {
214
+ deepseek: {
215
+ name: "DeepSeek",
216
+ url: "https://api.deepseek.com/anthropic",
217
+ apiKey: "",
218
+ envExtraParams: { CLAUDE_CODE_EFFORT_LEVEL: "max" },
219
+ models: [
220
+ { id: "flash", name: "deepseek-v4-flash[1m]" },
221
+ {
222
+ id: "pro",
223
+ name: "deepseek-v4-pro[1m]",
224
+ envExtraParams: {
225
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: "deepseek-v4-flash[1m]"
226
+ }
227
+ }
228
+ ]
229
+ }
230
+ }
231
+ }, Z = (e, r) => {
232
+ v.mkdirSync(k.dirname(e), { recursive: !0 }), v.writeFileSync(e, JSON.stringify(r, null, 2)), v.chmodSync(e, 384);
233
+ }, x = (e) => Z(l, e), K = (e) => Z(c, e), Te = () => {
234
+ if (!v.existsSync(l)) {
235
+ if (v.existsSync(c))
236
+ throw new Error(
237
+ `${l} 不存在,但已检测到 settings.json 源。请运行 --meta-generate 生成配置。`
238
+ );
239
+ K(W);
240
+ const o = re(W);
241
+ return x(o), o;
242
+ }
243
+ const e = v.readFileSync(l, "utf8");
244
+ let r;
245
+ try {
246
+ r = JSON.parse(e);
247
+ } catch (o) {
248
+ const s = o instanceof Error ? o.message : String(o);
249
+ throw new Error(`配置文件非法 JSON:${l}(${s})`);
250
+ }
251
+ if (typeof r != "object" || r === null)
252
+ throw new Error(`配置文件结构非法:${l}(应为 JSON 对象)`);
253
+ const t = r;
254
+ if (ee(t, l, "配置文件的"), typeof t.profiles != "object" || t.profiles === null || Array.isArray(t.profiles))
255
+ throw new Error(`配置文件缺少对象字段 profiles:${l}`);
256
+ return t;
257
+ }, T = (e) => typeof e == "object" && e !== null && !Array.isArray(e), ee = (e, r, t) => {
258
+ if (e.defaultProfile !== void 0 && (typeof e.defaultProfile != "string" || e.defaultProfile.length === 0))
259
+ throw new Error(
260
+ `${t} defaultProfile [MUST] 为非空字符串(可省略):${r}`
261
+ );
262
+ if (e.disabledDefault !== void 0 && typeof e.disabledDefault != "boolean")
263
+ throw new Error(`${t} disabledDefault [MUST] 为布尔:${r}`);
264
+ if (e.output !== void 0) {
265
+ if (!T(e.output))
266
+ throw new Error(`${t} output [MUST] 为对象:${r}`);
267
+ if (e.output.profileName !== void 0 && typeof e.output.profileName != "boolean")
268
+ throw new Error(
269
+ `${t} output.profileName [MUST] 为布尔:${r}`
270
+ );
271
+ }
272
+ }, B = (e, r) => {
273
+ if (e === void 0) return {};
274
+ if (!T(e))
275
+ throw new Error(`${r} [MUST] 为字符串键值对象`);
276
+ const t = {};
277
+ for (const [o, s] of Object.entries(e)) {
278
+ if (typeof s != "string")
279
+ throw new Error(`${r}.${o} [MUST] 为字符串`);
280
+ t[o] = s;
281
+ }
282
+ return t;
283
+ }, ge = (e, r) => {
284
+ if (!v.existsSync(e))
285
+ throw new Error(`源配置文件不存在:${e}(请先创建 ${r})`);
286
+ const t = v.readFileSync(e, "utf8");
287
+ let o;
288
+ try {
289
+ o = JSON.parse(t);
290
+ } catch (s) {
291
+ const n = s instanceof Error ? s.message : String(s);
292
+ throw new Error(`${r} 非法 JSON:${e}(${n})`);
293
+ }
294
+ if (!T(o))
295
+ throw new Error(`${r} 结构非法:${e}(应为 JSON 对象)`);
296
+ return o;
297
+ }, Ae = (e, r) => {
298
+ const { name: t, url: o, apiKey: s, models: n } = r;
299
+ if (typeof t != "string" || t.length === 0)
300
+ throw new Error(`provider「${e}」缺字符串字段 name:${c}`);
301
+ if (typeof o != "string" || o.length === 0)
302
+ throw new Error(`provider「${e}」缺字符串字段 url:${c}`);
303
+ if (typeof s != "string")
304
+ throw new Error(`provider「${e}」缺字符串字段 apiKey:${c}`);
305
+ const a = B(
306
+ r.envExtraParams,
307
+ `provider「${e}」envExtraParams`
308
+ );
309
+ if (!Array.isArray(n))
310
+ throw new Error(`provider「${e}」缺少数组字段 models:${c}`);
311
+ if (n.length === 0)
312
+ throw new Error(`provider「${e}」models 为空:${c}`);
313
+ const d = [];
314
+ for (const i of n) {
315
+ if (!T(i))
316
+ throw new Error(`provider「${e}」models 项 [MUST] 为对象:${c}`);
317
+ const { id: p, name: g } = i;
318
+ if (typeof p != "string" || p.length === 0)
319
+ throw new Error(
320
+ `provider「${e}」models 项缺字符串字段 id:${c}`
321
+ );
322
+ if (typeof g != "string" || g.length === 0)
323
+ throw new Error(
324
+ `provider「${e}」models 项缺字符串字段 name:${c}`
325
+ );
326
+ const y = B(
327
+ i.envExtraParams,
328
+ `provider「${e}」models 项 envExtraParams`
329
+ );
330
+ d.push({
331
+ id: p,
332
+ name: g,
333
+ ...Object.keys(y).length > 0 ? { envExtraParams: y } : {}
334
+ });
335
+ }
336
+ return {
337
+ name: t,
338
+ url: o,
339
+ apiKey: s,
340
+ ...Object.keys(a).length > 0 ? { envExtraParams: a } : {},
341
+ models: d
342
+ };
343
+ }, S = () => {
344
+ const e = ge(c, "settings.json");
345
+ ee(e, c, "settings.json");
346
+ const r = e.providers;
347
+ if (!T(r))
348
+ throw new Error(`settings.json 缺少对象字段 providers:${c}`);
349
+ const t = {};
350
+ for (const [o, s] of Object.entries(r)) {
351
+ if (!T(s))
352
+ throw new Error(`provider「${o}」[MUST] 为对象:${c}`);
353
+ t[o] = Ae(o, s);
354
+ }
355
+ return {
356
+ ...e.defaultProfile !== void 0 ? { defaultProfile: e.defaultProfile } : {},
357
+ ...e.disabledDefault !== void 0 ? { disabledDefault: e.disabledDefault } : {},
358
+ ...e.output !== void 0 ? { output: e.output } : {},
359
+ providers: t
360
+ };
361
+ }, Oe = (e, r) => ({
362
+ ANTHROPIC_BASE_URL: e.url,
363
+ ANTHROPIC_AUTH_TOKEN: e.apiKey,
364
+ ANTHROPIC_MODEL: r.name,
365
+ ANTHROPIC_DEFAULT_OPUS_MODEL: r.name,
366
+ ANTHROPIC_DEFAULT_SONNET_MODEL: r.name,
367
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: r.name,
368
+ CLAUDE_CODE_SUBAGENT_MODEL: r.name,
369
+ ...e.envExtraParams ?? {},
370
+ ...r.envExtraParams ?? {}
371
+ }), re = (e) => {
372
+ const r = {}, t = /* @__PURE__ */ new Set();
373
+ for (const [o, s] of Object.entries(e.providers))
374
+ for (const n of s.models) {
375
+ const a = `${o}-${n.id}`;
376
+ if (t.has(a))
377
+ throw new Error(
378
+ `profile 名重复:${a}(provider+id 组合重复):${c}`
379
+ );
380
+ t.add(a), r[a] = { env: Oe(s, n) };
381
+ }
382
+ if (Object.keys(r).length === 0)
383
+ throw new Error(`settings.json 无可生成 profile:${c}`);
384
+ if (e.defaultProfile !== void 0 && !r[e.defaultProfile]) {
385
+ const o = Object.keys(r).join(", ");
386
+ throw new Error(
387
+ `defaultProfile「${e.defaultProfile}」不在生成的 profile 中。可用:${o}。配置文件:${c}`
388
+ );
389
+ }
390
+ return {
391
+ ...e.defaultProfile !== void 0 ? { defaultProfile: e.defaultProfile } : {},
392
+ ...e.disabledDefault !== void 0 ? { disabledDefault: e.disabledDefault } : {},
393
+ ...e.output !== void 0 ? { output: e.output } : {},
394
+ profiles: r
395
+ };
396
+ }, U = () => {
397
+ const e = re(S());
398
+ return x(e), e;
399
+ }, te = (e) => {
400
+ const r = e.trim();
401
+ if (r.length === 0)
402
+ throw new Error("模型名为空(--meta-model-name 值不可为空)");
403
+ const t = r.replace(/\[1m\]$/, "");
404
+ return { id: t, name: `${t}[1m]` };
405
+ }, _e = (e, r) => {
406
+ const t = S(), o = t.providers[e];
407
+ if (!o)
408
+ throw new Error(
409
+ `provider「${e}」不存在。可用:${Object.keys(t.providers).join(", ")}。配置文件:${c}`
410
+ );
411
+ return o.apiKey = r, K(t), U();
412
+ }, Ie = (e, r) => {
413
+ const { id: t, name: o } = te(r), s = S(), n = s.providers[e];
414
+ if (!n)
415
+ throw new Error(
416
+ `provider「${e}」不存在。可用:${Object.keys(s.providers).join(", ")}。配置文件:${c}`
417
+ );
418
+ const a = n.models.find((d) => d.id === t);
419
+ if (a)
420
+ throw new Error(
421
+ `model「${e}/${t}」已存在(name=${a.name}):${c}`
422
+ );
423
+ return n.models.push({ id: t, name: o }), K(s), U();
424
+ }, be = (e) => Object.entries(e.providers).map(([r, t]) => `${r}(${t.name})`), Ne = (e) => Object.entries(e.providers).flatMap(
425
+ ([r, t]) => t.models.map((o) => `${o.name}(${r})`)
426
+ ), je = /TOKEN|KEY|SECRET/i;
427
+ class F extends Error {
428
+ constructor() {
429
+ super("用户中断输入"), this.name = "PromptAbortError";
430
+ }
431
+ }
432
+ const Me = (e) => je.test(e), qe = (e) => e === "" ? "" : "******", oe = (e) => Object.keys(e).filter((r) => e[r] === "");
433
+ let R = !1, P = null;
434
+ const Le = (e) => new Promise((r, t) => {
435
+ const o = de.createInterface({
436
+ input: process.stdin,
437
+ output: process.stderr
438
+ });
439
+ P = o, o.on("close", () => {
440
+ P === o && (P = null);
441
+ }), o.question(e, (s) => {
442
+ o.close(), r(s);
443
+ }), o.on("SIGINT", () => {
444
+ o.close(), t(new F());
445
+ });
446
+ }), ke = 3, De = 4, Re = 127, Ce = (e) => new Promise((r, t) => {
447
+ process.stderr.write(e);
448
+ const o = process.stdin;
449
+ typeof o.setRawMode == "function" && (o.setRawMode(!0), R = !0), o.resume(), o.setEncoding("utf8");
450
+ let s = "";
451
+ const n = () => {
452
+ o.removeListener("data", a);
453
+ }, a = (d) => {
454
+ for (const i of d) {
455
+ const p = i.charCodeAt(0);
456
+ if (i === "\r" || i === `
457
+ `) {
458
+ n(), process.stderr.write(`
459
+ `), r(s);
460
+ return;
461
+ }
462
+ if (p === ke || p === De) {
463
+ n(), process.stderr.write(`
464
+ `), t(new F());
465
+ return;
466
+ }
467
+ if (p === Re || i === "\b") {
468
+ s = s.slice(0, -1);
469
+ continue;
470
+ }
471
+ s += i;
472
+ }
473
+ };
474
+ o.on("data", a);
475
+ }), xe = async (e) => {
476
+ const r = oe(e.env);
477
+ for (const t of r) {
478
+ const o = Me(t);
479
+ let s = "";
480
+ for (; s === ""; ) {
481
+ const n = `请输入 ${t}: `;
482
+ s = o ? await Ce(n) : await Le(n);
483
+ }
484
+ e.env[t] = s;
485
+ }
486
+ }, Ke = () => {
487
+ P && (P.close(), P = null);
488
+ const e = process.stdin;
489
+ R && typeof e.setRawMode == "function" && (e.setRawMode(!1), R = !1), e.removeAllListeners("data"), e.removeAllListeners("keypress"), e.removeAllListeners("readable"), e.pause();
490
+ }, se = {
491
+ version: "0.3.0",
492
+ cliConfig: {
493
+ moduleName: "cc-switch"
494
+ }
495
+ }, Ue = async (e, r, t) => r === "pick" ? D(e) : t || (e.disabledDefault ? D(e) : e.defaultProfile ? e.defaultProfile : D(e)), Fe = "claude", ne = async (e) => {
496
+ var V;
497
+ const {
498
+ action: r,
499
+ profileName: t,
500
+ apiKey: o,
501
+ modelName: s,
502
+ providerId: n,
503
+ silent: a,
504
+ passthrough: d
505
+ } = Ee(e ?? process.argv.slice(2));
506
+ if (r === "help" && (fe(), process.exit(0)), r === "version" && (me(se.version), process.exit(0)), r === "generate") {
507
+ const f = U();
508
+ process.stdout.write(
509
+ `已生成 ${Object.keys(f.profiles).length} 个 profile → ${l}
510
+ `
511
+ ), process.exit(0);
512
+ }
513
+ if (r === "providerlist" || r === "modellist") {
514
+ const f = r === "providerlist" ? be(S()) : Ne(S());
515
+ for (const m of f)
516
+ process.stdout.write(`${m}
517
+ `);
518
+ process.exit(0);
519
+ }
520
+ if (r === "setkey" || r === "addmodel") {
521
+ const f = S(), m = n ?? await ue(f), h = r === "setkey" ? _e(m, o) : Ie(m, s);
522
+ process.stdout.write(
523
+ r === "setkey" ? `已更新 provider「${m}」apiKey,重建 ${Object.keys(h.profiles).length} 个 profile → ${l}
524
+ ` : `已添加 model「${m}/${te(s).id}」,重建 ${Object.keys(h.profiles).length} 个 profile → ${l}
525
+ `
526
+ ), process.exit(0);
527
+ }
528
+ const i = Te(), p = await Ue(i, r, t), { name: g, profile: y } = ve(i, p);
529
+ if (oe(y.env).length > 0) {
530
+ try {
531
+ await xe(y);
532
+ } catch (f) {
533
+ if (f instanceof F)
534
+ return process.stderr.write(`已取消,未写入配置。
535
+ `), process.exit(1);
536
+ throw f;
537
+ }
538
+ x(i), Ke();
539
+ }
540
+ const ie = Pe(), H = Se(ie);
541
+ if (H.length > 0)
542
+ return process.stderr.write(
543
+ `检测到 ${z} 的 env 块含模型路由类 key:${H.join(", ")}。请手动清理这些 key 后重试。
544
+ `
545
+ ), process.exit(1);
546
+ !a && ((V = i.output) == null ? void 0 : V.profileName) !== !1 && process.stdout.write(`${g}
547
+ `);
548
+ const ce = ye(process.env, y.env), G = le(Fe, d, {
549
+ stdio: "inherit",
550
+ shell: !1,
551
+ env: ce
552
+ });
553
+ return new Promise((f, m) => {
554
+ G.on("error", (h) => {
555
+ try {
556
+ if (h.code === "ENOENT") {
557
+ process.stderr.write(
558
+ `未找到 claude 可执行文件,请确认 claude-code 已安装并在 PATH 中。
559
+ `
560
+ ), process.exit(127);
561
+ return;
562
+ }
563
+ process.stderr.write(`启动 claude 失败:${h.message}
564
+ `), process.exit(1);
565
+ } catch (_) {
566
+ m(_);
567
+ }
568
+ }), G.on("exit", (h, _) => {
569
+ try {
570
+ if (_) {
571
+ process.exit(128 + He(_));
572
+ return;
573
+ }
574
+ process.exit(h ?? 1);
575
+ } catch (ae) {
576
+ m(ae);
577
+ }
578
+ });
579
+ });
580
+ }, He = (e) => ({
581
+ SIGHUP: 1,
582
+ SIGINT: 2,
583
+ SIGQUIT: 3,
584
+ SIGILL: 4,
585
+ SIGABRT: 6,
586
+ SIGFPE: 8,
587
+ SIGKILL: 9,
588
+ SIGSEGV: 11,
589
+ SIGPIPE: 13,
590
+ SIGALRM: 14,
591
+ SIGTERM: 15
592
+ })[e] ?? 1, {
593
+ cliConfig: { moduleName: X }
594
+ } = se, ze = async () => {
595
+ try {
596
+ await ne();
597
+ } catch (e) {
598
+ const r = e instanceof Error ? e.message : String(e);
599
+ process.stderr.write(`${r}
600
+ `), process.exit(1);
601
+ }
602
+ }, Qe = () => ({
603
+ command: X,
604
+ describe: "claude-code 模型路由透传(dc-cc-switch / cc-router)",
605
+ builder(e) {
606
+ return e.strict(!1).option("meta-profile", {
607
+ type: "string",
608
+ describe: "选择 profile(~/.done-coding/cc-switch/profile.json 中的 profile 名)"
609
+ }).option("meta-pick", {
610
+ type: "boolean",
611
+ describe: "终端交互选择 profile 启动"
612
+ }).option("meta-silent", {
613
+ type: "boolean",
614
+ describe: "压制 output.* 输出(MCP/AI 调用避免污染上下文)"
615
+ }).option("meta-generate", {
616
+ type: "boolean",
617
+ describe: "从 provider.json + model.json 重建 profile.json"
618
+ }).option("meta-apiKey", {
619
+ type: "string",
620
+ describe: "更新指定提供商 apiKey(自动重建)"
621
+ }).option("meta-model-name", {
622
+ type: "string",
623
+ describe: "添加模型到指定提供商(自动重建)"
624
+ }).option("meta-provider", {
625
+ type: "string",
626
+ describe: "显式指定 provider id(供 apiKey/model-name 跳过选择)"
627
+ }).option("meta-provider-list", {
628
+ type: "boolean",
629
+ describe: "输出提供商列表(id + name)"
630
+ }).option("meta-model-list", {
631
+ type: "boolean",
632
+ describe: "输出模型列表(name + 所属 provider)"
633
+ }).option("meta-help", {
634
+ type: "boolean",
635
+ describe: "显示 cc-switch 自身帮助"
636
+ }).option("meta-version", {
637
+ type: "boolean",
638
+ describe: "显示 cc-switch 自身版本"
639
+ });
640
+ },
641
+ handler() {
642
+ const e = process.argv.findIndex((t) => t === X), r = e >= 0 ? process.argv.slice(e + 1) : process.argv.slice(2);
643
+ return ne(r);
644
+ }
645
+ });
646
+ export {
647
+ W as D,
648
+ l as P,
649
+ c as S,
650
+ ze as a,
651
+ ye as b,
652
+ Qe as c,
653
+ oe as f,
654
+ Se as h,
655
+ Me as i,
656
+ qe as m,
657
+ Ee as p,
658
+ ve as s
659
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@done-coding/cli-cc-switch",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "claude-code路由",
5
5
  "private": false,
6
6
  "module": "es/index.mjs",
@@ -58,5 +58,5 @@
58
58
  "engines": {
59
59
  "node": ">=18.0.0"
60
60
  },
61
- "gitHead": "f56359da7c5f246511bedf8f814369c702f5456c"
61
+ "gitHead": "f0189a3f80367fcd5cbe408bb696dc190e960b10"
62
62
  }