cc-mirror 1.0.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/LICENSE +21 -0
- package/README.md +192 -0
- package/dist/cc-mirror.mjs +4506 -0
- package/dist/tui.mjs +42061 -0
- package/package.json +83 -0
|
@@ -0,0 +1,4506 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli/args.ts
|
|
4
|
+
var parseArgs = (argv) => {
|
|
5
|
+
const opts = { _: [], env: [] };
|
|
6
|
+
const args = [...argv];
|
|
7
|
+
while (args.length > 0) {
|
|
8
|
+
const arg = args.shift();
|
|
9
|
+
if (!arg.startsWith("-")) {
|
|
10
|
+
opts._.push(arg);
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
if (arg === "--yes") {
|
|
14
|
+
opts.yes = true;
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (arg === "--no-tweak") {
|
|
18
|
+
opts.noTweak = true;
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (arg === "--tui") {
|
|
22
|
+
opts.tui = true;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (arg === "--quick" || arg === "--simple") {
|
|
26
|
+
opts.quick = true;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (arg === "--no-tui") {
|
|
30
|
+
opts.noTui = true;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (arg.startsWith("--env=")) {
|
|
34
|
+
opts.env.push(arg.slice("--env=".length));
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (arg === "--env") {
|
|
38
|
+
const value2 = args.shift();
|
|
39
|
+
if (value2) opts.env.push(value2);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const [key, inlineValue] = arg.startsWith("--") ? arg.slice(2).split("=") : [null, null];
|
|
43
|
+
if (!key) continue;
|
|
44
|
+
const value = inlineValue ?? args.shift();
|
|
45
|
+
if (value !== void 0) {
|
|
46
|
+
opts[key] = value;
|
|
47
|
+
} else {
|
|
48
|
+
opts[key] = true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return opts;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// src/tui/content/haikus.ts
|
|
55
|
+
var COMPLETION_HAIKUS = {
|
|
56
|
+
zai: [
|
|
57
|
+
["Gold streams, code dreams\u2014", "your variant awaits you now.", "GLM starts to gleam."],
|
|
58
|
+
["Calibrated well,", "the mirror reflects your code.", "Zai hears your call."]
|
|
59
|
+
],
|
|
60
|
+
minimax: [
|
|
61
|
+
["Coral light shines bright,", "MiniMax pulses with power.", "AGI for all."],
|
|
62
|
+
["Resonating deep,", "the model learns to listen.", "Your code takes its leap."]
|
|
63
|
+
],
|
|
64
|
+
openrouter: [
|
|
65
|
+
["Many paths, one door\u2014", "OpenRouter finds the way.", "Models at your core."],
|
|
66
|
+
["Routes converge as one,", "your choice echoes through the wire.", "The journey begun."]
|
|
67
|
+
],
|
|
68
|
+
ccrouter: [
|
|
69
|
+
["Local models shine,", "routed through the mirror's edge.", "Your code, your design."],
|
|
70
|
+
["Proxied through the night,", "your models stand at the ready.", "Code takes its first flight."]
|
|
71
|
+
],
|
|
72
|
+
default: [
|
|
73
|
+
["Mirror reflects true,", "your variant is ready now.", "Go build something new."],
|
|
74
|
+
["Configuration done,", "the wrapper awaits your call.", "Your coding has begun."]
|
|
75
|
+
]
|
|
76
|
+
};
|
|
77
|
+
var getRandomHaiku = (providerKey) => {
|
|
78
|
+
const haikus = COMPLETION_HAIKUS[providerKey || ""] || COMPLETION_HAIKUS.default;
|
|
79
|
+
return haikus[Math.floor(Math.random() * haikus.length)];
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// src/cli/help.ts
|
|
83
|
+
var printHelp = () => {
|
|
84
|
+
console.log(`
|
|
85
|
+
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
86
|
+
\u2551 CC-MIRROR \u2551
|
|
87
|
+
\u2551 Create Claude Code Variants with Custom Providers \u2551
|
|
88
|
+
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
89
|
+
|
|
90
|
+
WHAT IS CC-MIRROR?
|
|
91
|
+
CC-MIRROR creates isolated Claude Code installations that connect to
|
|
92
|
+
different AI providers. Each variant is independent with its own
|
|
93
|
+
config, theme, and settings.
|
|
94
|
+
|
|
95
|
+
QUICK START
|
|
96
|
+
cc-mirror quick # Fast setup: provider + key \u2192 done
|
|
97
|
+
cc-mirror create # Full wizard with all options
|
|
98
|
+
|
|
99
|
+
COMMANDS
|
|
100
|
+
create [options] Create a new variant
|
|
101
|
+
quick [options] Fast: provider + API key only
|
|
102
|
+
list List all variants
|
|
103
|
+
update [name] Update to latest Claude Code
|
|
104
|
+
remove <name> Remove a variant
|
|
105
|
+
doctor Health check all variants
|
|
106
|
+
tweak <name> Launch tweakcc customization
|
|
107
|
+
|
|
108
|
+
OPTIONS (create/quick)
|
|
109
|
+
--name <name> Variant name (becomes CLI command)
|
|
110
|
+
--provider <name> Provider: zai | minimax | openrouter | ccrouter
|
|
111
|
+
--api-key <key> Provider API key
|
|
112
|
+
--brand <preset> Theme: auto | none | zai | minimax
|
|
113
|
+
--quick Fast path mode
|
|
114
|
+
--tui / --no-tui Force TUI on/off
|
|
115
|
+
|
|
116
|
+
OPTIONS (advanced)
|
|
117
|
+
--base-url <url> ANTHROPIC_BASE_URL override
|
|
118
|
+
--model-sonnet <name> Default Sonnet model
|
|
119
|
+
--model-opus <name> Default Opus model
|
|
120
|
+
--model-haiku <name> Default Haiku model
|
|
121
|
+
--root <path> Variants root (default: ~/.cc-mirror)
|
|
122
|
+
--bin-dir <path> Wrapper install dir (default: ~/.local/bin)
|
|
123
|
+
--no-tweak Skip tweakcc theming
|
|
124
|
+
--no-prompt-pack Skip provider prompt pack
|
|
125
|
+
--prompt-pack-mode <mode> minimal | maximal
|
|
126
|
+
--shell-env Write env vars to shell profile (Z.ai)
|
|
127
|
+
|
|
128
|
+
EXAMPLES
|
|
129
|
+
cc-mirror quick --provider zai
|
|
130
|
+
cc-mirror create --provider minimax --brand minimax
|
|
131
|
+
cc-mirror update zai
|
|
132
|
+
cc-mirror doctor
|
|
133
|
+
|
|
134
|
+
LEARN MORE
|
|
135
|
+
https://github.com/numman-ali/cc-mirror
|
|
136
|
+
|
|
137
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
138
|
+
Created by Numman Ali \u2022 https://x.com/nummanali
|
|
139
|
+
`);
|
|
140
|
+
};
|
|
141
|
+
var printHaiku = () => {
|
|
142
|
+
const haiku = getRandomHaiku();
|
|
143
|
+
console.log(`
|
|
144
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
145
|
+
${haiku[0]}
|
|
146
|
+
${haiku[1]}
|
|
147
|
+
${haiku[2]}
|
|
148
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
149
|
+
`);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// src/cli/tui.ts
|
|
153
|
+
import fs from "node:fs";
|
|
154
|
+
import path from "node:path";
|
|
155
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
156
|
+
var dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
157
|
+
var shouldLaunchTui = (cmd, opts) => {
|
|
158
|
+
if (opts.noTui) return false;
|
|
159
|
+
if (opts.tui) return true;
|
|
160
|
+
if (!process.stdout.isTTY) return false;
|
|
161
|
+
if (cmd === "create") {
|
|
162
|
+
const hasArgs = opts.yes || Boolean(opts.name) || Boolean(opts.provider) || Boolean(opts["base-url"]) || Boolean(opts["api-key"]) || (opts._?.length ?? 0) > 0;
|
|
163
|
+
return !hasArgs;
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
};
|
|
167
|
+
var runTui = async () => {
|
|
168
|
+
const candidates = [
|
|
169
|
+
process.env.CC_MIRROR_TUI_PATH,
|
|
170
|
+
path.join(dirname, "..", "tui", "index.tsx"),
|
|
171
|
+
path.join(dirname, "..", "tui", "index.mjs"),
|
|
172
|
+
path.join(dirname, "tui.mjs")
|
|
173
|
+
].filter(Boolean);
|
|
174
|
+
const target = candidates.find((filePath) => fs.existsSync(filePath));
|
|
175
|
+
if (!target) {
|
|
176
|
+
throw new Error("Unable to locate TUI entrypoint.");
|
|
177
|
+
}
|
|
178
|
+
await import(pathToFileURL(target).href);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// src/core/index.ts
|
|
182
|
+
import fs11 from "node:fs";
|
|
183
|
+
import path20 from "node:path";
|
|
184
|
+
|
|
185
|
+
// src/core/constants.ts
|
|
186
|
+
import os from "node:os";
|
|
187
|
+
import path2 from "node:path";
|
|
188
|
+
var DEFAULT_ROOT = path2.join(os.homedir(), ".cc-mirror");
|
|
189
|
+
var DEFAULT_BIN_DIR = path2.join(os.homedir(), ".local", "bin");
|
|
190
|
+
var TWEAKCC_VERSION = "3.2.2";
|
|
191
|
+
var DEFAULT_NPM_PACKAGE = "@anthropic-ai/claude-code";
|
|
192
|
+
var DEFAULT_NPM_VERSION = "2.0.76";
|
|
193
|
+
|
|
194
|
+
// src/core/fs.ts
|
|
195
|
+
import fs2 from "node:fs";
|
|
196
|
+
var ensureDir = (dir) => {
|
|
197
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
198
|
+
};
|
|
199
|
+
var writeJson = (filePath, data) => {
|
|
200
|
+
fs2.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
201
|
+
};
|
|
202
|
+
var readJson = (filePath) => {
|
|
203
|
+
try {
|
|
204
|
+
return JSON.parse(fs2.readFileSync(filePath, "utf8"));
|
|
205
|
+
} catch {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
// src/core/paths.ts
|
|
211
|
+
import { spawnSync } from "node:child_process";
|
|
212
|
+
import os2 from "node:os";
|
|
213
|
+
import path3 from "node:path";
|
|
214
|
+
var expandTilde = (input) => {
|
|
215
|
+
if (!input) return input;
|
|
216
|
+
if (input === "~") return os2.homedir();
|
|
217
|
+
if (input.startsWith("~/")) return path3.join(os2.homedir(), input.slice(2));
|
|
218
|
+
return input;
|
|
219
|
+
};
|
|
220
|
+
var commandExists = (cmd) => {
|
|
221
|
+
const result = spawnSync(process.platform === "win32" ? "where" : "which", [cmd], {
|
|
222
|
+
encoding: "utf8"
|
|
223
|
+
});
|
|
224
|
+
return result.status === 0 && result.stdout.trim().length > 0;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
// src/core/tweakcc.ts
|
|
228
|
+
import fs3 from "node:fs";
|
|
229
|
+
import { spawn, spawnSync as spawnSync2 } from "node:child_process";
|
|
230
|
+
import path4 from "node:path";
|
|
231
|
+
import { createRequire } from "node:module";
|
|
232
|
+
|
|
233
|
+
// src/brands/defaultThemes.ts
|
|
234
|
+
var DEFAULT_THEMES = [
|
|
235
|
+
{
|
|
236
|
+
name: "Dark mode",
|
|
237
|
+
id: "dark",
|
|
238
|
+
colors: {
|
|
239
|
+
autoAccept: "rgb(175,135,255)",
|
|
240
|
+
bashBorder: "rgb(253,93,177)",
|
|
241
|
+
claude: "rgb(215,119,87)",
|
|
242
|
+
claudeShimmer: "rgb(235,159,127)",
|
|
243
|
+
claudeBlue_FOR_SYSTEM_SPINNER: "rgb(147,165,255)",
|
|
244
|
+
claudeBlueShimmer_FOR_SYSTEM_SPINNER: "rgb(177,195,255)",
|
|
245
|
+
permission: "rgb(177,185,249)",
|
|
246
|
+
permissionShimmer: "rgb(207,215,255)",
|
|
247
|
+
planMode: "rgb(72,150,140)",
|
|
248
|
+
ide: "rgb(71,130,200)",
|
|
249
|
+
promptBorder: "rgb(136,136,136)",
|
|
250
|
+
promptBorderShimmer: "rgb(166,166,166)",
|
|
251
|
+
text: "rgb(255,255,255)",
|
|
252
|
+
inverseText: "rgb(0,0,0)",
|
|
253
|
+
inactive: "rgb(153,153,153)",
|
|
254
|
+
subtle: "rgb(80,80,80)",
|
|
255
|
+
suggestion: "rgb(177,185,249)",
|
|
256
|
+
remember: "rgb(177,185,249)",
|
|
257
|
+
background: "rgb(0,204,204)",
|
|
258
|
+
success: "rgb(78,186,101)",
|
|
259
|
+
error: "rgb(255,107,128)",
|
|
260
|
+
warning: "rgb(255,193,7)",
|
|
261
|
+
warningShimmer: "rgb(255,223,57)",
|
|
262
|
+
diffAdded: "rgb(34,92,43)",
|
|
263
|
+
diffRemoved: "rgb(122,41,54)",
|
|
264
|
+
diffAddedDimmed: "rgb(71,88,74)",
|
|
265
|
+
diffRemovedDimmed: "rgb(105,72,77)",
|
|
266
|
+
diffAddedWord: "rgb(56,166,96)",
|
|
267
|
+
diffRemovedWord: "rgb(179,89,107)",
|
|
268
|
+
diffAddedWordDimmed: "rgb(46,107,58)",
|
|
269
|
+
diffRemovedWordDimmed: "rgb(139,57,69)",
|
|
270
|
+
red_FOR_SUBAGENTS_ONLY: "rgb(220,38,38)",
|
|
271
|
+
blue_FOR_SUBAGENTS_ONLY: "rgb(37,99,235)",
|
|
272
|
+
green_FOR_SUBAGENTS_ONLY: "rgb(22,163,74)",
|
|
273
|
+
yellow_FOR_SUBAGENTS_ONLY: "rgb(202,138,4)",
|
|
274
|
+
purple_FOR_SUBAGENTS_ONLY: "rgb(147,51,234)",
|
|
275
|
+
orange_FOR_SUBAGENTS_ONLY: "rgb(234,88,12)",
|
|
276
|
+
pink_FOR_SUBAGENTS_ONLY: "rgb(219,39,119)",
|
|
277
|
+
cyan_FOR_SUBAGENTS_ONLY: "rgb(8,145,178)",
|
|
278
|
+
professionalBlue: "rgb(106,155,204)",
|
|
279
|
+
rainbow_red: "rgb(235,95,87)",
|
|
280
|
+
rainbow_orange: "rgb(245,139,87)",
|
|
281
|
+
rainbow_yellow: "rgb(250,195,95)",
|
|
282
|
+
rainbow_green: "rgb(145,200,130)",
|
|
283
|
+
rainbow_blue: "rgb(130,170,220)",
|
|
284
|
+
rainbow_indigo: "rgb(155,130,200)",
|
|
285
|
+
rainbow_violet: "rgb(200,130,180)",
|
|
286
|
+
rainbow_red_shimmer: "rgb(250,155,147)",
|
|
287
|
+
rainbow_orange_shimmer: "rgb(255,185,137)",
|
|
288
|
+
rainbow_yellow_shimmer: "rgb(255,225,155)",
|
|
289
|
+
rainbow_green_shimmer: "rgb(185,230,180)",
|
|
290
|
+
rainbow_blue_shimmer: "rgb(180,205,240)",
|
|
291
|
+
rainbow_indigo_shimmer: "rgb(195,180,230)",
|
|
292
|
+
rainbow_violet_shimmer: "rgb(230,180,210)",
|
|
293
|
+
clawd_body: "rgb(215,119,87)",
|
|
294
|
+
clawd_background: "rgb(0,0,0)",
|
|
295
|
+
userMessageBackground: "rgb(55, 55, 55)",
|
|
296
|
+
bashMessageBackgroundColor: "rgb(65, 60, 65)",
|
|
297
|
+
memoryBackgroundColor: "rgb(55, 65, 70)",
|
|
298
|
+
rate_limit_fill: "rgb(177,185,249)",
|
|
299
|
+
rate_limit_empty: "rgb(80,83,112)"
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
name: "Light mode",
|
|
304
|
+
id: "light",
|
|
305
|
+
colors: {
|
|
306
|
+
autoAccept: "rgb(135,0,255)",
|
|
307
|
+
bashBorder: "rgb(255,0,135)",
|
|
308
|
+
claude: "rgb(215,119,87)",
|
|
309
|
+
claudeShimmer: "rgb(245,149,117)",
|
|
310
|
+
claudeBlue_FOR_SYSTEM_SPINNER: "rgb(87,105,247)",
|
|
311
|
+
claudeBlueShimmer_FOR_SYSTEM_SPINNER: "rgb(117,135,255)",
|
|
312
|
+
permission: "rgb(87,105,247)",
|
|
313
|
+
permissionShimmer: "rgb(137,155,255)",
|
|
314
|
+
planMode: "rgb(0,102,102)",
|
|
315
|
+
ide: "rgb(71,130,200)",
|
|
316
|
+
promptBorder: "rgb(153,153,153)",
|
|
317
|
+
promptBorderShimmer: "rgb(183,183,183)",
|
|
318
|
+
text: "rgb(0,0,0)",
|
|
319
|
+
inverseText: "rgb(255,255,255)",
|
|
320
|
+
inactive: "rgb(102,102,102)",
|
|
321
|
+
subtle: "rgb(175,175,175)",
|
|
322
|
+
suggestion: "rgb(87,105,247)",
|
|
323
|
+
remember: "rgb(0,0,255)",
|
|
324
|
+
background: "rgb(0,153,153)",
|
|
325
|
+
success: "rgb(44,122,57)",
|
|
326
|
+
error: "rgb(171,43,63)",
|
|
327
|
+
warning: "rgb(150,108,30)",
|
|
328
|
+
warningShimmer: "rgb(200,158,80)",
|
|
329
|
+
diffAdded: "rgb(105,219,124)",
|
|
330
|
+
diffRemoved: "rgb(255,168,180)",
|
|
331
|
+
diffAddedDimmed: "rgb(199,225,203)",
|
|
332
|
+
diffRemovedDimmed: "rgb(253,210,216)",
|
|
333
|
+
diffAddedWord: "rgb(47,157,68)",
|
|
334
|
+
diffRemovedWord: "rgb(209,69,75)",
|
|
335
|
+
diffAddedWordDimmed: "rgb(144,194,156)",
|
|
336
|
+
diffRemovedWordDimmed: "rgb(232,165,173)",
|
|
337
|
+
red_FOR_SUBAGENTS_ONLY: "rgb(220,38,38)",
|
|
338
|
+
blue_FOR_SUBAGENTS_ONLY: "rgb(37,99,235)",
|
|
339
|
+
green_FOR_SUBAGENTS_ONLY: "rgb(22,163,74)",
|
|
340
|
+
yellow_FOR_SUBAGENTS_ONLY: "rgb(202,138,4)",
|
|
341
|
+
purple_FOR_SUBAGENTS_ONLY: "rgb(147,51,234)",
|
|
342
|
+
orange_FOR_SUBAGENTS_ONLY: "rgb(234,88,12)",
|
|
343
|
+
pink_FOR_SUBAGENTS_ONLY: "rgb(219,39,119)",
|
|
344
|
+
cyan_FOR_SUBAGENTS_ONLY: "rgb(8,145,178)",
|
|
345
|
+
professionalBlue: "rgb(106,155,204)",
|
|
346
|
+
rainbow_red: "rgb(235,95,87)",
|
|
347
|
+
rainbow_orange: "rgb(245,139,87)",
|
|
348
|
+
rainbow_yellow: "rgb(250,195,95)",
|
|
349
|
+
rainbow_green: "rgb(145,200,130)",
|
|
350
|
+
rainbow_blue: "rgb(130,170,220)",
|
|
351
|
+
rainbow_indigo: "rgb(155,130,200)",
|
|
352
|
+
rainbow_violet: "rgb(200,130,180)",
|
|
353
|
+
rainbow_red_shimmer: "rgb(250,155,147)",
|
|
354
|
+
rainbow_orange_shimmer: "rgb(255,185,137)",
|
|
355
|
+
rainbow_yellow_shimmer: "rgb(255,225,155)",
|
|
356
|
+
rainbow_green_shimmer: "rgb(185,230,180)",
|
|
357
|
+
rainbow_blue_shimmer: "rgb(180,205,240)",
|
|
358
|
+
rainbow_indigo_shimmer: "rgb(195,180,230)",
|
|
359
|
+
rainbow_violet_shimmer: "rgb(230,180,210)",
|
|
360
|
+
clawd_body: "rgb(215,119,87)",
|
|
361
|
+
clawd_background: "rgb(0,0,0)",
|
|
362
|
+
userMessageBackground: "rgb(240, 240, 240)",
|
|
363
|
+
bashMessageBackgroundColor: "rgb(250, 245, 250)",
|
|
364
|
+
memoryBackgroundColor: "rgb(230, 245, 250)",
|
|
365
|
+
rate_limit_fill: "rgb(87,105,247)",
|
|
366
|
+
rate_limit_empty: "rgb(39,47,111)"
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
name: "Light mode (ANSI colors only)",
|
|
371
|
+
id: "light-ansi",
|
|
372
|
+
colors: {
|
|
373
|
+
autoAccept: "ansi:magenta",
|
|
374
|
+
bashBorder: "ansi:magenta",
|
|
375
|
+
claude: "ansi:redBright",
|
|
376
|
+
claudeShimmer: "ansi:yellowBright",
|
|
377
|
+
claudeBlue_FOR_SYSTEM_SPINNER: "ansi:blue",
|
|
378
|
+
claudeBlueShimmer_FOR_SYSTEM_SPINNER: "ansi:blueBright",
|
|
379
|
+
permission: "ansi:blue",
|
|
380
|
+
permissionShimmer: "ansi:blueBright",
|
|
381
|
+
planMode: "ansi:cyan",
|
|
382
|
+
ide: "ansi:blueBright",
|
|
383
|
+
promptBorder: "ansi:white",
|
|
384
|
+
promptBorderShimmer: "ansi:whiteBright",
|
|
385
|
+
text: "ansi:black",
|
|
386
|
+
inverseText: "ansi:white",
|
|
387
|
+
inactive: "ansi:blackBright",
|
|
388
|
+
subtle: "ansi:blackBright",
|
|
389
|
+
suggestion: "ansi:blue",
|
|
390
|
+
remember: "ansi:blue",
|
|
391
|
+
background: "ansi:cyan",
|
|
392
|
+
success: "ansi:green",
|
|
393
|
+
error: "ansi:red",
|
|
394
|
+
warning: "ansi:yellow",
|
|
395
|
+
warningShimmer: "ansi:yellowBright",
|
|
396
|
+
diffAdded: "ansi:green",
|
|
397
|
+
diffRemoved: "ansi:red",
|
|
398
|
+
diffAddedDimmed: "ansi:green",
|
|
399
|
+
diffRemovedDimmed: "ansi:red",
|
|
400
|
+
diffAddedWord: "ansi:greenBright",
|
|
401
|
+
diffRemovedWord: "ansi:redBright",
|
|
402
|
+
diffAddedWordDimmed: "ansi:green",
|
|
403
|
+
diffRemovedWordDimmed: "ansi:red",
|
|
404
|
+
red_FOR_SUBAGENTS_ONLY: "ansi:red",
|
|
405
|
+
blue_FOR_SUBAGENTS_ONLY: "ansi:blue",
|
|
406
|
+
green_FOR_SUBAGENTS_ONLY: "ansi:green",
|
|
407
|
+
yellow_FOR_SUBAGENTS_ONLY: "ansi:yellow",
|
|
408
|
+
purple_FOR_SUBAGENTS_ONLY: "ansi:magenta",
|
|
409
|
+
orange_FOR_SUBAGENTS_ONLY: "ansi:redBright",
|
|
410
|
+
pink_FOR_SUBAGENTS_ONLY: "ansi:magentaBright",
|
|
411
|
+
cyan_FOR_SUBAGENTS_ONLY: "ansi:cyan",
|
|
412
|
+
professionalBlue: "ansi:blueBright",
|
|
413
|
+
rainbow_red: "ansi:red",
|
|
414
|
+
rainbow_orange: "ansi:redBright",
|
|
415
|
+
rainbow_yellow: "ansi:yellow",
|
|
416
|
+
rainbow_green: "ansi:green",
|
|
417
|
+
rainbow_blue: "ansi:cyan",
|
|
418
|
+
rainbow_indigo: "ansi:blue",
|
|
419
|
+
rainbow_violet: "ansi:magenta",
|
|
420
|
+
rainbow_red_shimmer: "ansi:redBright",
|
|
421
|
+
rainbow_orange_shimmer: "ansi:yellow",
|
|
422
|
+
rainbow_yellow_shimmer: "ansi:yellowBright",
|
|
423
|
+
rainbow_green_shimmer: "ansi:greenBright",
|
|
424
|
+
rainbow_blue_shimmer: "ansi:cyanBright",
|
|
425
|
+
rainbow_indigo_shimmer: "ansi:blueBright",
|
|
426
|
+
rainbow_violet_shimmer: "ansi:magentaBright",
|
|
427
|
+
clawd_body: "ansi:redBright",
|
|
428
|
+
clawd_background: "ansi:black",
|
|
429
|
+
userMessageBackground: "ansi:white",
|
|
430
|
+
bashMessageBackgroundColor: "ansi:whiteBright",
|
|
431
|
+
memoryBackgroundColor: "ansi:white",
|
|
432
|
+
rate_limit_fill: "ansi:yellow",
|
|
433
|
+
rate_limit_empty: "ansi:black"
|
|
434
|
+
}
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
name: "Dark mode (ANSI colors only)",
|
|
438
|
+
id: "dark-ansi",
|
|
439
|
+
colors: {
|
|
440
|
+
autoAccept: "ansi:magentaBright",
|
|
441
|
+
bashBorder: "ansi:magentaBright",
|
|
442
|
+
claude: "ansi:redBright",
|
|
443
|
+
claudeShimmer: "ansi:yellowBright",
|
|
444
|
+
claudeBlue_FOR_SYSTEM_SPINNER: "ansi:blueBright",
|
|
445
|
+
claudeBlueShimmer_FOR_SYSTEM_SPINNER: "ansi:blueBright",
|
|
446
|
+
permission: "ansi:blueBright",
|
|
447
|
+
permissionShimmer: "ansi:blueBright",
|
|
448
|
+
planMode: "ansi:cyanBright",
|
|
449
|
+
ide: "ansi:blue",
|
|
450
|
+
promptBorder: "ansi:white",
|
|
451
|
+
promptBorderShimmer: "ansi:whiteBright",
|
|
452
|
+
text: "ansi:whiteBright",
|
|
453
|
+
inverseText: "ansi:black",
|
|
454
|
+
inactive: "ansi:white",
|
|
455
|
+
subtle: "ansi:white",
|
|
456
|
+
suggestion: "ansi:blueBright",
|
|
457
|
+
remember: "ansi:blueBright",
|
|
458
|
+
background: "ansi:cyanBright",
|
|
459
|
+
success: "ansi:greenBright",
|
|
460
|
+
error: "ansi:redBright",
|
|
461
|
+
warning: "ansi:yellowBright",
|
|
462
|
+
warningShimmer: "ansi:yellowBright",
|
|
463
|
+
diffAdded: "ansi:green",
|
|
464
|
+
diffRemoved: "ansi:red",
|
|
465
|
+
diffAddedDimmed: "ansi:green",
|
|
466
|
+
diffRemovedDimmed: "ansi:red",
|
|
467
|
+
diffAddedWord: "ansi:greenBright",
|
|
468
|
+
diffRemovedWord: "ansi:redBright",
|
|
469
|
+
diffAddedWordDimmed: "ansi:green",
|
|
470
|
+
diffRemovedWordDimmed: "ansi:red",
|
|
471
|
+
red_FOR_SUBAGENTS_ONLY: "ansi:redBright",
|
|
472
|
+
blue_FOR_SUBAGENTS_ONLY: "ansi:blueBright",
|
|
473
|
+
green_FOR_SUBAGENTS_ONLY: "ansi:greenBright",
|
|
474
|
+
yellow_FOR_SUBAGENTS_ONLY: "ansi:yellowBright",
|
|
475
|
+
purple_FOR_SUBAGENTS_ONLY: "ansi:magentaBright",
|
|
476
|
+
orange_FOR_SUBAGENTS_ONLY: "ansi:redBright",
|
|
477
|
+
pink_FOR_SUBAGENTS_ONLY: "ansi:magentaBright",
|
|
478
|
+
cyan_FOR_SUBAGENTS_ONLY: "ansi:cyanBright",
|
|
479
|
+
professionalBlue: "rgb(106,155,204)",
|
|
480
|
+
rainbow_red: "ansi:red",
|
|
481
|
+
rainbow_orange: "ansi:redBright",
|
|
482
|
+
rainbow_yellow: "ansi:yellow",
|
|
483
|
+
rainbow_green: "ansi:green",
|
|
484
|
+
rainbow_blue: "ansi:cyan",
|
|
485
|
+
rainbow_indigo: "ansi:blue",
|
|
486
|
+
rainbow_violet: "ansi:magenta",
|
|
487
|
+
rainbow_red_shimmer: "ansi:redBright",
|
|
488
|
+
rainbow_orange_shimmer: "ansi:yellow",
|
|
489
|
+
rainbow_yellow_shimmer: "ansi:yellowBright",
|
|
490
|
+
rainbow_green_shimmer: "ansi:greenBright",
|
|
491
|
+
rainbow_blue_shimmer: "ansi:cyanBright",
|
|
492
|
+
rainbow_indigo_shimmer: "ansi:blueBright",
|
|
493
|
+
rainbow_violet_shimmer: "ansi:magentaBright",
|
|
494
|
+
clawd_body: "ansi:redBright",
|
|
495
|
+
clawd_background: "ansi:black",
|
|
496
|
+
userMessageBackground: "ansi:blackBright",
|
|
497
|
+
bashMessageBackgroundColor: "ansi:black",
|
|
498
|
+
memoryBackgroundColor: "ansi:blackBright",
|
|
499
|
+
rate_limit_fill: "ansi:yellow",
|
|
500
|
+
rate_limit_empty: "ansi:white"
|
|
501
|
+
}
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
name: "Light mode (colorblind-friendly)",
|
|
505
|
+
id: "light-daltonized",
|
|
506
|
+
colors: {
|
|
507
|
+
autoAccept: "rgb(135,0,255)",
|
|
508
|
+
bashBorder: "rgb(0,102,204)",
|
|
509
|
+
claude: "rgb(255,153,51)",
|
|
510
|
+
claudeShimmer: "rgb(255,183,101)",
|
|
511
|
+
claudeBlue_FOR_SYSTEM_SPINNER: "rgb(51,102,255)",
|
|
512
|
+
claudeBlueShimmer_FOR_SYSTEM_SPINNER: "rgb(101,152,255)",
|
|
513
|
+
permission: "rgb(51,102,255)",
|
|
514
|
+
permissionShimmer: "rgb(101,152,255)",
|
|
515
|
+
planMode: "rgb(51,102,102)",
|
|
516
|
+
ide: "rgb(71,130,200)",
|
|
517
|
+
promptBorder: "rgb(153,153,153)",
|
|
518
|
+
promptBorderShimmer: "rgb(183,183,183)",
|
|
519
|
+
text: "rgb(0,0,0)",
|
|
520
|
+
inverseText: "rgb(255,255,255)",
|
|
521
|
+
inactive: "rgb(102,102,102)",
|
|
522
|
+
subtle: "rgb(175,175,175)",
|
|
523
|
+
suggestion: "rgb(51,102,255)",
|
|
524
|
+
remember: "rgb(51,102,255)",
|
|
525
|
+
background: "rgb(0,153,153)",
|
|
526
|
+
success: "rgb(0,102,153)",
|
|
527
|
+
error: "rgb(204,0,0)",
|
|
528
|
+
warning: "rgb(255,153,0)",
|
|
529
|
+
warningShimmer: "rgb(255,183,50)",
|
|
530
|
+
diffAdded: "rgb(153,204,255)",
|
|
531
|
+
diffRemoved: "rgb(255,204,204)",
|
|
532
|
+
diffAddedDimmed: "rgb(209,231,253)",
|
|
533
|
+
diffRemovedDimmed: "rgb(255,233,233)",
|
|
534
|
+
diffAddedWord: "rgb(51,102,204)",
|
|
535
|
+
diffRemovedWord: "rgb(153,51,51)",
|
|
536
|
+
diffAddedWordDimmed: "rgb(102,153,204)",
|
|
537
|
+
diffRemovedWordDimmed: "rgb(204,153,153)",
|
|
538
|
+
red_FOR_SUBAGENTS_ONLY: "rgb(204,0,0)",
|
|
539
|
+
blue_FOR_SUBAGENTS_ONLY: "rgb(0,102,204)",
|
|
540
|
+
green_FOR_SUBAGENTS_ONLY: "rgb(0,204,0)",
|
|
541
|
+
yellow_FOR_SUBAGENTS_ONLY: "rgb(255,204,0)",
|
|
542
|
+
purple_FOR_SUBAGENTS_ONLY: "rgb(128,0,128)",
|
|
543
|
+
orange_FOR_SUBAGENTS_ONLY: "rgb(255,128,0)",
|
|
544
|
+
pink_FOR_SUBAGENTS_ONLY: "rgb(255,102,178)",
|
|
545
|
+
cyan_FOR_SUBAGENTS_ONLY: "rgb(0,178,178)",
|
|
546
|
+
professionalBlue: "rgb(106,155,204)",
|
|
547
|
+
rainbow_red: "rgb(235,95,87)",
|
|
548
|
+
rainbow_orange: "rgb(245,139,87)",
|
|
549
|
+
rainbow_yellow: "rgb(250,195,95)",
|
|
550
|
+
rainbow_green: "rgb(145,200,130)",
|
|
551
|
+
rainbow_blue: "rgb(130,170,220)",
|
|
552
|
+
rainbow_indigo: "rgb(155,130,200)",
|
|
553
|
+
rainbow_violet: "rgb(200,130,180)",
|
|
554
|
+
rainbow_red_shimmer: "rgb(250,155,147)",
|
|
555
|
+
rainbow_orange_shimmer: "rgb(255,185,137)",
|
|
556
|
+
rainbow_yellow_shimmer: "rgb(255,225,155)",
|
|
557
|
+
rainbow_green_shimmer: "rgb(185,230,180)",
|
|
558
|
+
rainbow_blue_shimmer: "rgb(180,205,240)",
|
|
559
|
+
rainbow_indigo_shimmer: "rgb(195,180,230)",
|
|
560
|
+
rainbow_violet_shimmer: "rgb(230,180,210)",
|
|
561
|
+
clawd_body: "rgb(215,119,87)",
|
|
562
|
+
clawd_background: "rgb(0,0,0)",
|
|
563
|
+
userMessageBackground: "rgb(220, 220, 220)",
|
|
564
|
+
bashMessageBackgroundColor: "rgb(250, 245, 250)",
|
|
565
|
+
memoryBackgroundColor: "rgb(230, 245, 250)",
|
|
566
|
+
rate_limit_fill: "rgb(51,102,255)",
|
|
567
|
+
rate_limit_empty: "rgb(23,46,114)"
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
name: "Dark mode (colorblind-friendly)",
|
|
572
|
+
id: "dark-daltonized",
|
|
573
|
+
colors: {
|
|
574
|
+
autoAccept: "rgb(175,135,255)",
|
|
575
|
+
bashBorder: "rgb(51,153,255)",
|
|
576
|
+
claude: "rgb(255,153,51)",
|
|
577
|
+
claudeShimmer: "rgb(255,183,101)",
|
|
578
|
+
claudeBlue_FOR_SYSTEM_SPINNER: "rgb(153,204,255)",
|
|
579
|
+
claudeBlueShimmer_FOR_SYSTEM_SPINNER: "rgb(183,224,255)",
|
|
580
|
+
permission: "rgb(153,204,255)",
|
|
581
|
+
permissionShimmer: "rgb(183,224,255)",
|
|
582
|
+
planMode: "rgb(102,153,153)",
|
|
583
|
+
ide: "rgb(71,130,200)",
|
|
584
|
+
promptBorder: "rgb(136,136,136)",
|
|
585
|
+
promptBorderShimmer: "rgb(166,166,166)",
|
|
586
|
+
text: "rgb(255,255,255)",
|
|
587
|
+
inverseText: "rgb(0,0,0)",
|
|
588
|
+
inactive: "rgb(153,153,153)",
|
|
589
|
+
subtle: "rgb(80,80,80)",
|
|
590
|
+
suggestion: "rgb(153,204,255)",
|
|
591
|
+
remember: "rgb(153,204,255)",
|
|
592
|
+
background: "rgb(0,204,204)",
|
|
593
|
+
success: "rgb(51,153,255)",
|
|
594
|
+
error: "rgb(255,102,102)",
|
|
595
|
+
warning: "rgb(255,204,0)",
|
|
596
|
+
warningShimmer: "rgb(255,234,50)",
|
|
597
|
+
diffAdded: "rgb(0,68,102)",
|
|
598
|
+
diffRemoved: "rgb(102,0,0)",
|
|
599
|
+
diffAddedDimmed: "rgb(62,81,91)",
|
|
600
|
+
diffRemovedDimmed: "rgb(62,44,44)",
|
|
601
|
+
diffAddedWord: "rgb(0,119,179)",
|
|
602
|
+
diffRemovedWord: "rgb(179,0,0)",
|
|
603
|
+
diffAddedWordDimmed: "rgb(26,99,128)",
|
|
604
|
+
diffRemovedWordDimmed: "rgb(128,21,21)",
|
|
605
|
+
red_FOR_SUBAGENTS_ONLY: "rgb(255,102,102)",
|
|
606
|
+
blue_FOR_SUBAGENTS_ONLY: "rgb(102,178,255)",
|
|
607
|
+
green_FOR_SUBAGENTS_ONLY: "rgb(102,255,102)",
|
|
608
|
+
yellow_FOR_SUBAGENTS_ONLY: "rgb(255,255,102)",
|
|
609
|
+
purple_FOR_SUBAGENTS_ONLY: "rgb(178,102,255)",
|
|
610
|
+
orange_FOR_SUBAGENTS_ONLY: "rgb(255,178,102)",
|
|
611
|
+
pink_FOR_SUBAGENTS_ONLY: "rgb(255,153,204)",
|
|
612
|
+
cyan_FOR_SUBAGENTS_ONLY: "rgb(102,204,204)",
|
|
613
|
+
professionalBlue: "rgb(106,155,204)",
|
|
614
|
+
rainbow_red: "rgb(235,95,87)",
|
|
615
|
+
rainbow_orange: "rgb(245,139,87)",
|
|
616
|
+
rainbow_yellow: "rgb(250,195,95)",
|
|
617
|
+
rainbow_green: "rgb(145,200,130)",
|
|
618
|
+
rainbow_blue: "rgb(130,170,220)",
|
|
619
|
+
rainbow_indigo: "rgb(155,130,200)",
|
|
620
|
+
rainbow_violet: "rgb(200,130,180)",
|
|
621
|
+
rainbow_red_shimmer: "rgb(250,155,147)",
|
|
622
|
+
rainbow_orange_shimmer: "rgb(255,185,137)",
|
|
623
|
+
rainbow_yellow_shimmer: "rgb(255,225,155)",
|
|
624
|
+
rainbow_green_shimmer: "rgb(185,230,180)",
|
|
625
|
+
rainbow_blue_shimmer: "rgb(180,205,240)",
|
|
626
|
+
rainbow_indigo_shimmer: "rgb(195,180,230)",
|
|
627
|
+
rainbow_violet_shimmer: "rgb(230,180,210)",
|
|
628
|
+
clawd_body: "rgb(215,119,87)",
|
|
629
|
+
clawd_background: "rgb(0,0,0)",
|
|
630
|
+
userMessageBackground: "rgb(55, 55, 55)",
|
|
631
|
+
bashMessageBackgroundColor: "rgb(65, 60, 65)",
|
|
632
|
+
memoryBackgroundColor: "rgb(55, 65, 70)",
|
|
633
|
+
rate_limit_fill: "rgb(153,204,255)",
|
|
634
|
+
rate_limit_empty: "rgb(69,92,115)"
|
|
635
|
+
}
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
name: "Monochrome",
|
|
639
|
+
id: "monochrome",
|
|
640
|
+
colors: {
|
|
641
|
+
autoAccept: "rgb(200,200,200)",
|
|
642
|
+
bashBorder: "rgb(180,180,180)",
|
|
643
|
+
claude: "rgb(255,255,255)",
|
|
644
|
+
claudeShimmer: "rgb(230,230,230)",
|
|
645
|
+
claudeBlue_FOR_SYSTEM_SPINNER: "rgb(200,200,200)",
|
|
646
|
+
claudeBlueShimmer_FOR_SYSTEM_SPINNER: "rgb(220,220,220)",
|
|
647
|
+
permission: "rgb(200,200,200)",
|
|
648
|
+
permissionShimmer: "rgb(220,220,220)",
|
|
649
|
+
planMode: "rgb(180,180,180)",
|
|
650
|
+
ide: "rgb(190,190,190)",
|
|
651
|
+
promptBorder: "rgb(160,160,160)",
|
|
652
|
+
promptBorderShimmer: "rgb(180,180,180)",
|
|
653
|
+
text: "rgb(255,255,255)",
|
|
654
|
+
inverseText: "rgb(40,40,40)",
|
|
655
|
+
inactive: "rgb(120,120,120)",
|
|
656
|
+
subtle: "rgb(100,100,100)",
|
|
657
|
+
suggestion: "rgb(200,200,200)",
|
|
658
|
+
remember: "rgb(200,200,200)",
|
|
659
|
+
background: "rgb(180,180,180)",
|
|
660
|
+
success: "rgb(220,220,220)",
|
|
661
|
+
error: "rgb(180,180,180)",
|
|
662
|
+
warning: "rgb(200,200,200)",
|
|
663
|
+
warningShimmer: "rgb(220,220,220)",
|
|
664
|
+
diffAdded: "rgb(90,90,90)",
|
|
665
|
+
diffRemoved: "rgb(60,60,60)",
|
|
666
|
+
diffAddedDimmed: "rgb(110,110,110)",
|
|
667
|
+
diffRemovedDimmed: "rgb(80,80,80)",
|
|
668
|
+
diffAddedWord: "rgb(200,200,200)",
|
|
669
|
+
diffRemovedWord: "rgb(80,80,80)",
|
|
670
|
+
diffAddedWordDimmed: "rgb(160,160,160)",
|
|
671
|
+
diffRemovedWordDimmed: "rgb(70,70,70)",
|
|
672
|
+
red_FOR_SUBAGENTS_ONLY: "rgb(200,200,200)",
|
|
673
|
+
blue_FOR_SUBAGENTS_ONLY: "rgb(180,180,180)",
|
|
674
|
+
green_FOR_SUBAGENTS_ONLY: "rgb(210,210,210)",
|
|
675
|
+
yellow_FOR_SUBAGENTS_ONLY: "rgb(190,190,190)",
|
|
676
|
+
purple_FOR_SUBAGENTS_ONLY: "rgb(170,170,170)",
|
|
677
|
+
orange_FOR_SUBAGENTS_ONLY: "rgb(195,195,195)",
|
|
678
|
+
pink_FOR_SUBAGENTS_ONLY: "rgb(205,205,205)",
|
|
679
|
+
cyan_FOR_SUBAGENTS_ONLY: "rgb(185,185,185)",
|
|
680
|
+
professionalBlue: "rgb(190,190,190)",
|
|
681
|
+
rainbow_red: "rgb(240,240,240)",
|
|
682
|
+
rainbow_orange: "rgb(230,230,230)",
|
|
683
|
+
rainbow_yellow: "rgb(220,220,220)",
|
|
684
|
+
rainbow_green: "rgb(210,210,210)",
|
|
685
|
+
rainbow_blue: "rgb(200,200,200)",
|
|
686
|
+
rainbow_indigo: "rgb(190,190,190)",
|
|
687
|
+
rainbow_violet: "rgb(180,180,180)",
|
|
688
|
+
rainbow_red_shimmer: "rgb(255,255,255)",
|
|
689
|
+
rainbow_orange_shimmer: "rgb(245,245,245)",
|
|
690
|
+
rainbow_yellow_shimmer: "rgb(235,235,235)",
|
|
691
|
+
rainbow_green_shimmer: "rgb(225,225,225)",
|
|
692
|
+
rainbow_blue_shimmer: "rgb(215,215,215)",
|
|
693
|
+
rainbow_indigo_shimmer: "rgb(205,205,205)",
|
|
694
|
+
rainbow_violet_shimmer: "rgb(195,195,195)",
|
|
695
|
+
clawd_body: "rgb(255,255,255)",
|
|
696
|
+
clawd_background: "rgb(40,40,40)",
|
|
697
|
+
userMessageBackground: "rgb(70,70,70)",
|
|
698
|
+
bashMessageBackgroundColor: "rgb(65,65,65)",
|
|
699
|
+
memoryBackgroundColor: "rgb(75,75,75)",
|
|
700
|
+
rate_limit_fill: "rgb(200,200,200)",
|
|
701
|
+
rate_limit_empty: "rgb(90,90,90)"
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
];
|
|
705
|
+
|
|
706
|
+
// src/brands/userLabel.ts
|
|
707
|
+
import os3 from "node:os";
|
|
708
|
+
var sanitizeLabel = (value) => {
|
|
709
|
+
if (!value) return null;
|
|
710
|
+
const trimmed = value.trim();
|
|
711
|
+
if (!trimmed) return null;
|
|
712
|
+
return trimmed;
|
|
713
|
+
};
|
|
714
|
+
var getUserLabel = () => {
|
|
715
|
+
const candidates = [
|
|
716
|
+
sanitizeLabel(process.env.CLAUDE_CODE_USER_LABEL),
|
|
717
|
+
sanitizeLabel(process.env.USER),
|
|
718
|
+
sanitizeLabel(process.env.USERNAME)
|
|
719
|
+
];
|
|
720
|
+
for (const candidate of candidates) {
|
|
721
|
+
if (candidate) return candidate;
|
|
722
|
+
}
|
|
723
|
+
try {
|
|
724
|
+
const info = os3.userInfo();
|
|
725
|
+
const name = sanitizeLabel(info.username);
|
|
726
|
+
if (name) return name;
|
|
727
|
+
} catch {
|
|
728
|
+
}
|
|
729
|
+
return "user";
|
|
730
|
+
};
|
|
731
|
+
var formatUserMessage = (label) => ` [${label}] {} `;
|
|
732
|
+
|
|
733
|
+
// src/brands/zai.ts
|
|
734
|
+
var clamp = (value) => Math.max(0, Math.min(255, Math.round(value)));
|
|
735
|
+
var hexToRgb = (hex) => {
|
|
736
|
+
const normalized = hex.replace("#", "").trim();
|
|
737
|
+
if (normalized.length === 3) {
|
|
738
|
+
const [r, g, b] = normalized.split("");
|
|
739
|
+
return {
|
|
740
|
+
r: clamp(parseInt(r + r, 16)),
|
|
741
|
+
g: clamp(parseInt(g + g, 16)),
|
|
742
|
+
b: clamp(parseInt(b + b, 16))
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
if (normalized.length !== 6) {
|
|
746
|
+
throw new Error(`Unsupported hex color: ${hex}`);
|
|
747
|
+
}
|
|
748
|
+
return {
|
|
749
|
+
r: clamp(parseInt(normalized.slice(0, 2), 16)),
|
|
750
|
+
g: clamp(parseInt(normalized.slice(2, 4), 16)),
|
|
751
|
+
b: clamp(parseInt(normalized.slice(4, 6), 16))
|
|
752
|
+
};
|
|
753
|
+
};
|
|
754
|
+
var rgb = (hex) => {
|
|
755
|
+
const { r, g, b } = hexToRgb(hex);
|
|
756
|
+
return `rgb(${r},${g},${b})`;
|
|
757
|
+
};
|
|
758
|
+
var mix = (hexA, hexB, weight) => {
|
|
759
|
+
const a = hexToRgb(hexA);
|
|
760
|
+
const b = hexToRgb(hexB);
|
|
761
|
+
const w = Math.max(0, Math.min(1, weight));
|
|
762
|
+
return `rgb(${clamp(a.r + (b.r - a.r) * w)},${clamp(a.g + (b.g - a.g) * w)},${clamp(a.b + (b.b - a.b) * w)})`;
|
|
763
|
+
};
|
|
764
|
+
var lighten = (hex, weight) => mix(hex, "#ffffff", weight);
|
|
765
|
+
var palette = {
|
|
766
|
+
base: "#1b1d1f",
|
|
767
|
+
surface: "#25272b",
|
|
768
|
+
panel: "#282a30",
|
|
769
|
+
border: "#353842",
|
|
770
|
+
borderStrong: "#484a58",
|
|
771
|
+
text: "#e8e8e8",
|
|
772
|
+
textMuted: "#c3c4cc",
|
|
773
|
+
textDim: "#8d8e99",
|
|
774
|
+
gold: "#ffd373",
|
|
775
|
+
goldSoft: "#ffdc8f",
|
|
776
|
+
goldDeep: "#b2892e",
|
|
777
|
+
blue: "#0080ff",
|
|
778
|
+
blueSoft: "#66b3ff",
|
|
779
|
+
blueDeep: "#134cff",
|
|
780
|
+
green: "#37d995",
|
|
781
|
+
red: "#fb2c36",
|
|
782
|
+
orange: "#ff8e42",
|
|
783
|
+
purple: "#9c8bff"
|
|
784
|
+
};
|
|
785
|
+
var theme = {
|
|
786
|
+
name: "Z.ai Carbon",
|
|
787
|
+
id: "zai-carbon",
|
|
788
|
+
colors: {
|
|
789
|
+
autoAccept: rgb(palette.green),
|
|
790
|
+
bashBorder: rgb(palette.gold),
|
|
791
|
+
claude: rgb(palette.gold),
|
|
792
|
+
claudeShimmer: rgb(palette.goldSoft),
|
|
793
|
+
claudeBlue_FOR_SYSTEM_SPINNER: rgb(palette.blue),
|
|
794
|
+
claudeBlueShimmer_FOR_SYSTEM_SPINNER: rgb(palette.blueSoft),
|
|
795
|
+
permission: rgb(palette.blue),
|
|
796
|
+
permissionShimmer: rgb(palette.blueSoft),
|
|
797
|
+
planMode: rgb(palette.green),
|
|
798
|
+
ide: rgb(palette.blueSoft),
|
|
799
|
+
promptBorder: rgb(palette.border),
|
|
800
|
+
promptBorderShimmer: rgb(palette.borderStrong),
|
|
801
|
+
text: rgb(palette.text),
|
|
802
|
+
inverseText: rgb(palette.base),
|
|
803
|
+
inactive: rgb(palette.textDim),
|
|
804
|
+
subtle: rgb(palette.border),
|
|
805
|
+
suggestion: rgb(palette.blueSoft),
|
|
806
|
+
remember: rgb(palette.gold),
|
|
807
|
+
background: rgb(palette.base),
|
|
808
|
+
success: rgb(palette.green),
|
|
809
|
+
error: rgb(palette.red),
|
|
810
|
+
warning: rgb(palette.orange),
|
|
811
|
+
warningShimmer: rgb(palette.goldSoft),
|
|
812
|
+
diffAdded: mix(palette.base, palette.green, 0.18),
|
|
813
|
+
diffRemoved: mix(palette.base, palette.red, 0.18),
|
|
814
|
+
diffAddedDimmed: mix(palette.base, palette.green, 0.1),
|
|
815
|
+
diffRemovedDimmed: mix(palette.base, palette.red, 0.1),
|
|
816
|
+
diffAddedWord: mix(palette.base, palette.green, 0.45),
|
|
817
|
+
diffRemovedWord: mix(palette.base, palette.red, 0.45),
|
|
818
|
+
diffAddedWordDimmed: mix(palette.base, palette.green, 0.3),
|
|
819
|
+
diffRemovedWordDimmed: mix(palette.base, palette.red, 0.3),
|
|
820
|
+
red_FOR_SUBAGENTS_ONLY: rgb(palette.red),
|
|
821
|
+
blue_FOR_SUBAGENTS_ONLY: rgb(palette.blueDeep),
|
|
822
|
+
green_FOR_SUBAGENTS_ONLY: rgb(palette.green),
|
|
823
|
+
yellow_FOR_SUBAGENTS_ONLY: rgb(palette.gold),
|
|
824
|
+
purple_FOR_SUBAGENTS_ONLY: rgb(palette.purple),
|
|
825
|
+
orange_FOR_SUBAGENTS_ONLY: rgb(palette.orange),
|
|
826
|
+
pink_FOR_SUBAGENTS_ONLY: rgb(palette.goldSoft),
|
|
827
|
+
cyan_FOR_SUBAGENTS_ONLY: rgb(palette.blueSoft),
|
|
828
|
+
professionalBlue: rgb(palette.blueSoft),
|
|
829
|
+
rainbow_red: rgb(palette.red),
|
|
830
|
+
rainbow_orange: rgb(palette.orange),
|
|
831
|
+
rainbow_yellow: rgb(palette.gold),
|
|
832
|
+
rainbow_green: rgb(palette.green),
|
|
833
|
+
rainbow_blue: rgb(palette.blue),
|
|
834
|
+
rainbow_indigo: rgb(palette.blueDeep),
|
|
835
|
+
rainbow_violet: rgb(palette.purple),
|
|
836
|
+
rainbow_red_shimmer: lighten(palette.red, 0.35),
|
|
837
|
+
rainbow_orange_shimmer: lighten(palette.orange, 0.35),
|
|
838
|
+
rainbow_yellow_shimmer: lighten(palette.gold, 0.25),
|
|
839
|
+
rainbow_green_shimmer: lighten(palette.green, 0.35),
|
|
840
|
+
rainbow_blue_shimmer: lighten(palette.blue, 0.35),
|
|
841
|
+
rainbow_indigo_shimmer: lighten(palette.blueDeep, 0.35),
|
|
842
|
+
rainbow_violet_shimmer: lighten(palette.purple, 0.35),
|
|
843
|
+
clawd_body: rgb(palette.gold),
|
|
844
|
+
clawd_background: rgb(palette.base),
|
|
845
|
+
userMessageBackground: rgb(palette.panel),
|
|
846
|
+
bashMessageBackgroundColor: rgb(palette.surface),
|
|
847
|
+
memoryBackgroundColor: rgb(palette.panel),
|
|
848
|
+
rate_limit_fill: rgb(palette.gold),
|
|
849
|
+
rate_limit_empty: rgb(palette.borderStrong)
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
var buildZaiTweakccConfig = () => ({
|
|
853
|
+
ccVersion: "",
|
|
854
|
+
ccInstallationPath: null,
|
|
855
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString(),
|
|
856
|
+
changesApplied: false,
|
|
857
|
+
hidePiebaldAnnouncement: true,
|
|
858
|
+
settings: {
|
|
859
|
+
themes: [theme, ...DEFAULT_THEMES],
|
|
860
|
+
thinkingVerbs: {
|
|
861
|
+
format: "{}... ",
|
|
862
|
+
verbs: [
|
|
863
|
+
"Calibrating",
|
|
864
|
+
"Indexing",
|
|
865
|
+
"Synthesizing",
|
|
866
|
+
"Optimizing",
|
|
867
|
+
"Routing",
|
|
868
|
+
"Vectorizing",
|
|
869
|
+
"Mapping",
|
|
870
|
+
"Compiling",
|
|
871
|
+
"Refining",
|
|
872
|
+
"Auditing",
|
|
873
|
+
"Aligning",
|
|
874
|
+
"Balancing",
|
|
875
|
+
"Forecasting",
|
|
876
|
+
"Resolving",
|
|
877
|
+
"Validating",
|
|
878
|
+
"Benchmarking",
|
|
879
|
+
"Assembling",
|
|
880
|
+
"Delivering"
|
|
881
|
+
]
|
|
882
|
+
},
|
|
883
|
+
thinkingStyle: {
|
|
884
|
+
updateInterval: 110,
|
|
885
|
+
phases: [".", "o", "O", "0", "O", "o"],
|
|
886
|
+
reverseMirror: false
|
|
887
|
+
},
|
|
888
|
+
userMessageDisplay: {
|
|
889
|
+
format: formatUserMessage(getUserLabel()),
|
|
890
|
+
styling: ["bold"],
|
|
891
|
+
foregroundColor: "default",
|
|
892
|
+
backgroundColor: "default",
|
|
893
|
+
borderStyle: "topBottomBold",
|
|
894
|
+
borderColor: rgb(palette.gold),
|
|
895
|
+
paddingX: 1,
|
|
896
|
+
paddingY: 0,
|
|
897
|
+
fitBoxToContent: true
|
|
898
|
+
},
|
|
899
|
+
inputBox: {
|
|
900
|
+
removeBorder: true
|
|
901
|
+
},
|
|
902
|
+
misc: {
|
|
903
|
+
showTweakccVersion: false,
|
|
904
|
+
showPatchesApplied: false,
|
|
905
|
+
expandThinkingBlocks: true,
|
|
906
|
+
enableConversationTitle: true,
|
|
907
|
+
hideStartupBanner: true,
|
|
908
|
+
hideCtrlGToEditPrompt: true,
|
|
909
|
+
hideStartupClawd: true,
|
|
910
|
+
increaseFileReadLimit: true
|
|
911
|
+
},
|
|
912
|
+
toolsets: [
|
|
913
|
+
{
|
|
914
|
+
name: "zai",
|
|
915
|
+
allowedTools: "*"
|
|
916
|
+
}
|
|
917
|
+
],
|
|
918
|
+
defaultToolset: "zai",
|
|
919
|
+
planModeToolset: "zai"
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
// src/brands/minimax.ts
|
|
924
|
+
var clamp2 = (value) => Math.max(0, Math.min(255, Math.round(value)));
|
|
925
|
+
var hexToRgb2 = (hex) => {
|
|
926
|
+
const normalized = hex.replace("#", "").trim();
|
|
927
|
+
if (normalized.length === 3) {
|
|
928
|
+
const [r, g, b] = normalized.split("");
|
|
929
|
+
return {
|
|
930
|
+
r: clamp2(parseInt(r + r, 16)),
|
|
931
|
+
g: clamp2(parseInt(g + g, 16)),
|
|
932
|
+
b: clamp2(parseInt(b + b, 16))
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
if (normalized.length !== 6) {
|
|
936
|
+
throw new Error(`Unsupported hex color: ${hex}`);
|
|
937
|
+
}
|
|
938
|
+
return {
|
|
939
|
+
r: clamp2(parseInt(normalized.slice(0, 2), 16)),
|
|
940
|
+
g: clamp2(parseInt(normalized.slice(2, 4), 16)),
|
|
941
|
+
b: clamp2(parseInt(normalized.slice(4, 6), 16))
|
|
942
|
+
};
|
|
943
|
+
};
|
|
944
|
+
var rgb2 = (hex) => {
|
|
945
|
+
const { r, g, b } = hexToRgb2(hex);
|
|
946
|
+
return `rgb(${r},${g},${b})`;
|
|
947
|
+
};
|
|
948
|
+
var mix2 = (hexA, hexB, weight) => {
|
|
949
|
+
const a = hexToRgb2(hexA);
|
|
950
|
+
const b = hexToRgb2(hexB);
|
|
951
|
+
const w = Math.max(0, Math.min(1, weight));
|
|
952
|
+
return `rgb(${clamp2(a.r + (b.r - a.r) * w)},${clamp2(a.g + (b.g - a.g) * w)},${clamp2(a.b + (b.b - a.b) * w)})`;
|
|
953
|
+
};
|
|
954
|
+
var lighten2 = (hex, weight) => mix2(hex, "#ffffff", weight);
|
|
955
|
+
var MINIMAX_CORE = "#ff5733";
|
|
956
|
+
var palette2 = {
|
|
957
|
+
base: "#0b0b0f",
|
|
958
|
+
surface: "#15151d",
|
|
959
|
+
panel: "#1b1b24",
|
|
960
|
+
border: "#2b2b36",
|
|
961
|
+
borderStrong: "#3a3a4a",
|
|
962
|
+
text: "#f7f7fb",
|
|
963
|
+
textMuted: "#d1d1db",
|
|
964
|
+
textDim: "#9b9bac",
|
|
965
|
+
core: MINIMAX_CORE,
|
|
966
|
+
deep: "#c70039",
|
|
967
|
+
orange: "#ff8c42",
|
|
968
|
+
yellow: "#ffeb3b",
|
|
969
|
+
cyan: "#4db5ff",
|
|
970
|
+
blue: "#3a7dff",
|
|
971
|
+
green: "#22c55e",
|
|
972
|
+
red: "#ff3b3b"
|
|
973
|
+
};
|
|
974
|
+
var makeTheme = () => {
|
|
975
|
+
const tint = (hex, weight) => mix2(palette2.base, hex, weight);
|
|
976
|
+
return {
|
|
977
|
+
name: "MiniMax Pulse",
|
|
978
|
+
id: "minimax-pulse",
|
|
979
|
+
colors: {
|
|
980
|
+
autoAccept: rgb2(palette2.green),
|
|
981
|
+
bashBorder: rgb2(palette2.core),
|
|
982
|
+
claude: rgb2(palette2.core),
|
|
983
|
+
claudeShimmer: lighten2(palette2.core, 0.28),
|
|
984
|
+
claudeBlue_FOR_SYSTEM_SPINNER: rgb2(palette2.blue),
|
|
985
|
+
claudeBlueShimmer_FOR_SYSTEM_SPINNER: lighten2(palette2.blue, 0.3),
|
|
986
|
+
permission: rgb2(palette2.orange),
|
|
987
|
+
permissionShimmer: lighten2(palette2.orange, 0.25),
|
|
988
|
+
planMode: rgb2(palette2.core),
|
|
989
|
+
ide: rgb2(palette2.cyan),
|
|
990
|
+
promptBorder: rgb2(palette2.border),
|
|
991
|
+
promptBorderShimmer: rgb2(palette2.borderStrong),
|
|
992
|
+
text: rgb2(palette2.text),
|
|
993
|
+
inverseText: rgb2(palette2.base),
|
|
994
|
+
inactive: rgb2(palette2.textDim),
|
|
995
|
+
subtle: tint(palette2.core, 0.18),
|
|
996
|
+
suggestion: rgb2(palette2.deep),
|
|
997
|
+
remember: rgb2(palette2.core),
|
|
998
|
+
background: rgb2(palette2.base),
|
|
999
|
+
success: rgb2(palette2.green),
|
|
1000
|
+
error: rgb2(palette2.red),
|
|
1001
|
+
warning: rgb2(palette2.yellow),
|
|
1002
|
+
warningShimmer: lighten2(palette2.yellow, 0.2),
|
|
1003
|
+
diffAdded: mix2(palette2.base, palette2.green, 0.18),
|
|
1004
|
+
diffRemoved: mix2(palette2.base, palette2.red, 0.18),
|
|
1005
|
+
diffAddedDimmed: mix2(palette2.base, palette2.green, 0.1),
|
|
1006
|
+
diffRemovedDimmed: mix2(palette2.base, palette2.red, 0.1),
|
|
1007
|
+
diffAddedWord: mix2(palette2.base, palette2.green, 0.45),
|
|
1008
|
+
diffRemovedWord: mix2(palette2.base, palette2.red, 0.45),
|
|
1009
|
+
diffAddedWordDimmed: mix2(palette2.base, palette2.green, 0.3),
|
|
1010
|
+
diffRemovedWordDimmed: mix2(palette2.base, palette2.red, 0.3),
|
|
1011
|
+
red_FOR_SUBAGENTS_ONLY: rgb2(palette2.red),
|
|
1012
|
+
blue_FOR_SUBAGENTS_ONLY: rgb2(palette2.blue),
|
|
1013
|
+
green_FOR_SUBAGENTS_ONLY: rgb2(palette2.green),
|
|
1014
|
+
yellow_FOR_SUBAGENTS_ONLY: rgb2(palette2.yellow),
|
|
1015
|
+
purple_FOR_SUBAGENTS_ONLY: rgb2(palette2.deep),
|
|
1016
|
+
orange_FOR_SUBAGENTS_ONLY: rgb2(palette2.orange),
|
|
1017
|
+
pink_FOR_SUBAGENTS_ONLY: rgb2(palette2.core),
|
|
1018
|
+
cyan_FOR_SUBAGENTS_ONLY: rgb2(palette2.cyan),
|
|
1019
|
+
professionalBlue: rgb2(palette2.blue),
|
|
1020
|
+
rainbow_red: rgb2(palette2.red),
|
|
1021
|
+
rainbow_orange: rgb2(palette2.orange),
|
|
1022
|
+
rainbow_yellow: rgb2(palette2.yellow),
|
|
1023
|
+
rainbow_green: rgb2(palette2.green),
|
|
1024
|
+
rainbow_blue: rgb2(palette2.cyan),
|
|
1025
|
+
rainbow_indigo: rgb2(palette2.blue),
|
|
1026
|
+
rainbow_violet: rgb2(palette2.core),
|
|
1027
|
+
rainbow_red_shimmer: lighten2(palette2.red, 0.35),
|
|
1028
|
+
rainbow_orange_shimmer: lighten2(palette2.orange, 0.35),
|
|
1029
|
+
rainbow_yellow_shimmer: lighten2(palette2.yellow, 0.25),
|
|
1030
|
+
rainbow_green_shimmer: lighten2(palette2.green, 0.35),
|
|
1031
|
+
rainbow_blue_shimmer: lighten2(palette2.cyan, 0.35),
|
|
1032
|
+
rainbow_indigo_shimmer: lighten2(palette2.blue, 0.35),
|
|
1033
|
+
rainbow_violet_shimmer: lighten2(palette2.core, 0.35),
|
|
1034
|
+
clawd_body: rgb2(palette2.core),
|
|
1035
|
+
clawd_background: rgb2(palette2.base),
|
|
1036
|
+
userMessageBackground: rgb2(palette2.panel),
|
|
1037
|
+
bashMessageBackgroundColor: rgb2(palette2.surface),
|
|
1038
|
+
memoryBackgroundColor: tint(palette2.panel, 0.2),
|
|
1039
|
+
rate_limit_fill: rgb2(palette2.core),
|
|
1040
|
+
rate_limit_empty: rgb2(palette2.borderStrong)
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
};
|
|
1044
|
+
var pulseTheme = makeTheme();
|
|
1045
|
+
var buildMinimaxTweakccConfig = () => ({
|
|
1046
|
+
ccVersion: "",
|
|
1047
|
+
ccInstallationPath: null,
|
|
1048
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1049
|
+
changesApplied: false,
|
|
1050
|
+
hidePiebaldAnnouncement: true,
|
|
1051
|
+
settings: {
|
|
1052
|
+
themes: [pulseTheme, ...DEFAULT_THEMES],
|
|
1053
|
+
thinkingVerbs: {
|
|
1054
|
+
format: "{}... ",
|
|
1055
|
+
verbs: [
|
|
1056
|
+
"Resonating",
|
|
1057
|
+
"Prisming",
|
|
1058
|
+
"Spectralizing",
|
|
1059
|
+
"Phase-locking",
|
|
1060
|
+
"Lensing",
|
|
1061
|
+
"Vectorizing",
|
|
1062
|
+
"Harmonizing",
|
|
1063
|
+
"Amplifying",
|
|
1064
|
+
"Stabilizing",
|
|
1065
|
+
"Optimizing",
|
|
1066
|
+
"Synthesizing",
|
|
1067
|
+
"Refining",
|
|
1068
|
+
"Resolving",
|
|
1069
|
+
"Transmitting"
|
|
1070
|
+
]
|
|
1071
|
+
},
|
|
1072
|
+
thinkingStyle: {
|
|
1073
|
+
updateInterval: 90,
|
|
1074
|
+
phases: ["\xB7", "\u2022", "\u25E6", "\u2022"],
|
|
1075
|
+
reverseMirror: false
|
|
1076
|
+
},
|
|
1077
|
+
userMessageDisplay: {
|
|
1078
|
+
format: formatUserMessage(getUserLabel()),
|
|
1079
|
+
styling: ["bold"],
|
|
1080
|
+
foregroundColor: "default",
|
|
1081
|
+
backgroundColor: "default",
|
|
1082
|
+
borderStyle: "topBottomDouble",
|
|
1083
|
+
borderColor: rgb2(palette2.core),
|
|
1084
|
+
paddingX: 1,
|
|
1085
|
+
paddingY: 0,
|
|
1086
|
+
fitBoxToContent: true
|
|
1087
|
+
},
|
|
1088
|
+
inputBox: {
|
|
1089
|
+
removeBorder: true
|
|
1090
|
+
},
|
|
1091
|
+
misc: {
|
|
1092
|
+
showTweakccVersion: false,
|
|
1093
|
+
showPatchesApplied: false,
|
|
1094
|
+
expandThinkingBlocks: true,
|
|
1095
|
+
enableConversationTitle: true,
|
|
1096
|
+
hideStartupBanner: true,
|
|
1097
|
+
hideCtrlGToEditPrompt: true,
|
|
1098
|
+
hideStartupClawd: true,
|
|
1099
|
+
increaseFileReadLimit: true
|
|
1100
|
+
},
|
|
1101
|
+
toolsets: [
|
|
1102
|
+
{
|
|
1103
|
+
name: "minimax",
|
|
1104
|
+
allowedTools: "*"
|
|
1105
|
+
}
|
|
1106
|
+
],
|
|
1107
|
+
defaultToolset: "minimax",
|
|
1108
|
+
planModeToolset: "minimax"
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1112
|
+
// src/brands/openrouter.ts
|
|
1113
|
+
var clamp3 = (value) => Math.max(0, Math.min(255, Math.round(value)));
|
|
1114
|
+
var hexToRgb3 = (hex) => {
|
|
1115
|
+
const normalized = hex.replace("#", "").trim();
|
|
1116
|
+
if (normalized.length === 3) {
|
|
1117
|
+
const [r, g, b] = normalized.split("");
|
|
1118
|
+
return {
|
|
1119
|
+
r: clamp3(parseInt(r + r, 16)),
|
|
1120
|
+
g: clamp3(parseInt(g + g, 16)),
|
|
1121
|
+
b: clamp3(parseInt(b + b, 16))
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
if (normalized.length !== 6) {
|
|
1125
|
+
throw new Error(`Unsupported hex color: ${hex}`);
|
|
1126
|
+
}
|
|
1127
|
+
return {
|
|
1128
|
+
r: clamp3(parseInt(normalized.slice(0, 2), 16)),
|
|
1129
|
+
g: clamp3(parseInt(normalized.slice(2, 4), 16)),
|
|
1130
|
+
b: clamp3(parseInt(normalized.slice(4, 6), 16))
|
|
1131
|
+
};
|
|
1132
|
+
};
|
|
1133
|
+
var rgb3 = (hex) => {
|
|
1134
|
+
const { r, g, b } = hexToRgb3(hex);
|
|
1135
|
+
return `rgb(${r},${g},${b})`;
|
|
1136
|
+
};
|
|
1137
|
+
var mix3 = (hexA, hexB, weight) => {
|
|
1138
|
+
const a = hexToRgb3(hexA);
|
|
1139
|
+
const b = hexToRgb3(hexB);
|
|
1140
|
+
const w = Math.max(0, Math.min(1, weight));
|
|
1141
|
+
return `rgb(${clamp3(a.r + (b.r - a.r) * w)},${clamp3(a.g + (b.g - a.g) * w)},${clamp3(a.b + (b.b - a.b) * w)})`;
|
|
1142
|
+
};
|
|
1143
|
+
var lighten3 = (hex, weight) => mix3(hex, "#ffffff", weight);
|
|
1144
|
+
var palette3 = {
|
|
1145
|
+
base: "#eef1f4",
|
|
1146
|
+
surface: "#f5f7f9",
|
|
1147
|
+
panel: "#e5e9ee",
|
|
1148
|
+
border: "#b0d4d4",
|
|
1149
|
+
borderStrong: "#7ec4c4",
|
|
1150
|
+
text: "#1f2430",
|
|
1151
|
+
textMuted: "#475569",
|
|
1152
|
+
textDim: "#6b7280",
|
|
1153
|
+
// Teal/cyan palette matching ASCII art colors
|
|
1154
|
+
teal: "#00a896",
|
|
1155
|
+
// Primary teal (matches ANSI 43)
|
|
1156
|
+
tealBright: "#00d4aa",
|
|
1157
|
+
// Bright teal (matches ANSI 49)
|
|
1158
|
+
tealDeep: "#008080",
|
|
1159
|
+
// Deep teal (matches ANSI 37)
|
|
1160
|
+
tealMuted: "#5fb3a8",
|
|
1161
|
+
// Softer teal for accents
|
|
1162
|
+
cyan: "#20b2aa",
|
|
1163
|
+
green: "#2f9b6d",
|
|
1164
|
+
red: "#d04b5a",
|
|
1165
|
+
orange: "#d28a3c",
|
|
1166
|
+
purple: "#6a5ad6"
|
|
1167
|
+
};
|
|
1168
|
+
var theme2 = {
|
|
1169
|
+
name: "OpenRouter Teal",
|
|
1170
|
+
id: "openrouter-teal",
|
|
1171
|
+
colors: {
|
|
1172
|
+
autoAccept: rgb3(palette3.green),
|
|
1173
|
+
bashBorder: rgb3(palette3.teal),
|
|
1174
|
+
claude: rgb3(palette3.tealDeep),
|
|
1175
|
+
claudeShimmer: lighten3(palette3.teal, 0.35),
|
|
1176
|
+
claudeBlue_FOR_SYSTEM_SPINNER: rgb3(palette3.teal),
|
|
1177
|
+
claudeBlueShimmer_FOR_SYSTEM_SPINNER: lighten3(palette3.tealMuted, 0.2),
|
|
1178
|
+
permission: rgb3(palette3.cyan),
|
|
1179
|
+
permissionShimmer: lighten3(palette3.cyan, 0.25),
|
|
1180
|
+
planMode: rgb3(palette3.tealDeep),
|
|
1181
|
+
ide: rgb3(palette3.tealMuted),
|
|
1182
|
+
promptBorder: rgb3(palette3.border),
|
|
1183
|
+
promptBorderShimmer: rgb3(palette3.borderStrong),
|
|
1184
|
+
text: rgb3(palette3.text),
|
|
1185
|
+
inverseText: rgb3(palette3.base),
|
|
1186
|
+
inactive: rgb3(palette3.textDim),
|
|
1187
|
+
subtle: mix3(palette3.base, palette3.tealMuted, 0.12),
|
|
1188
|
+
suggestion: rgb3(palette3.tealMuted),
|
|
1189
|
+
remember: rgb3(palette3.tealDeep),
|
|
1190
|
+
background: rgb3(palette3.base),
|
|
1191
|
+
success: rgb3(palette3.green),
|
|
1192
|
+
error: rgb3(palette3.red),
|
|
1193
|
+
warning: rgb3(palette3.orange),
|
|
1194
|
+
warningShimmer: lighten3(palette3.orange, 0.28),
|
|
1195
|
+
diffAdded: mix3(palette3.base, palette3.green, 0.2),
|
|
1196
|
+
diffRemoved: mix3(palette3.base, palette3.red, 0.2),
|
|
1197
|
+
diffAddedDimmed: mix3(palette3.base, palette3.green, 0.12),
|
|
1198
|
+
diffRemovedDimmed: mix3(palette3.base, palette3.red, 0.12),
|
|
1199
|
+
diffAddedWord: mix3(palette3.base, palette3.green, 0.42),
|
|
1200
|
+
diffRemovedWord: mix3(palette3.base, palette3.red, 0.42),
|
|
1201
|
+
diffAddedWordDimmed: mix3(palette3.base, palette3.green, 0.28),
|
|
1202
|
+
diffRemovedWordDimmed: mix3(palette3.base, palette3.red, 0.28),
|
|
1203
|
+
red_FOR_SUBAGENTS_ONLY: rgb3(palette3.red),
|
|
1204
|
+
blue_FOR_SUBAGENTS_ONLY: rgb3(palette3.tealDeep),
|
|
1205
|
+
green_FOR_SUBAGENTS_ONLY: rgb3(palette3.green),
|
|
1206
|
+
yellow_FOR_SUBAGENTS_ONLY: rgb3(palette3.orange),
|
|
1207
|
+
purple_FOR_SUBAGENTS_ONLY: rgb3(palette3.purple),
|
|
1208
|
+
orange_FOR_SUBAGENTS_ONLY: rgb3(palette3.orange),
|
|
1209
|
+
pink_FOR_SUBAGENTS_ONLY: lighten3(palette3.purple, 0.32),
|
|
1210
|
+
cyan_FOR_SUBAGENTS_ONLY: rgb3(palette3.cyan),
|
|
1211
|
+
professionalBlue: rgb3(palette3.teal),
|
|
1212
|
+
rainbow_red: rgb3(palette3.red),
|
|
1213
|
+
rainbow_orange: rgb3(palette3.orange),
|
|
1214
|
+
rainbow_yellow: lighten3(palette3.orange, 0.18),
|
|
1215
|
+
rainbow_green: rgb3(palette3.green),
|
|
1216
|
+
rainbow_blue: rgb3(palette3.tealMuted),
|
|
1217
|
+
rainbow_indigo: rgb3(palette3.tealDeep),
|
|
1218
|
+
rainbow_violet: rgb3(palette3.purple),
|
|
1219
|
+
rainbow_red_shimmer: lighten3(palette3.red, 0.35),
|
|
1220
|
+
rainbow_orange_shimmer: lighten3(palette3.orange, 0.35),
|
|
1221
|
+
rainbow_yellow_shimmer: lighten3(palette3.orange, 0.3),
|
|
1222
|
+
rainbow_green_shimmer: lighten3(palette3.green, 0.35),
|
|
1223
|
+
rainbow_blue_shimmer: lighten3(palette3.tealMuted, 0.35),
|
|
1224
|
+
rainbow_indigo_shimmer: lighten3(palette3.tealDeep, 0.35),
|
|
1225
|
+
rainbow_violet_shimmer: lighten3(palette3.purple, 0.35),
|
|
1226
|
+
clawd_body: rgb3(palette3.tealDeep),
|
|
1227
|
+
clawd_background: rgb3(palette3.base),
|
|
1228
|
+
userMessageBackground: rgb3(palette3.panel),
|
|
1229
|
+
bashMessageBackgroundColor: rgb3(palette3.surface),
|
|
1230
|
+
memoryBackgroundColor: mix3(palette3.panel, palette3.tealMuted, 0.12),
|
|
1231
|
+
rate_limit_fill: rgb3(palette3.teal),
|
|
1232
|
+
rate_limit_empty: rgb3(palette3.borderStrong)
|
|
1233
|
+
}
|
|
1234
|
+
};
|
|
1235
|
+
var buildOpenRouterTweakccConfig = () => ({
|
|
1236
|
+
ccVersion: "",
|
|
1237
|
+
ccInstallationPath: null,
|
|
1238
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1239
|
+
changesApplied: false,
|
|
1240
|
+
hidePiebaldAnnouncement: true,
|
|
1241
|
+
settings: {
|
|
1242
|
+
themes: [theme2, ...DEFAULT_THEMES],
|
|
1243
|
+
thinkingVerbs: {
|
|
1244
|
+
format: "{}... ",
|
|
1245
|
+
verbs: [
|
|
1246
|
+
"Routing",
|
|
1247
|
+
"Switchboarding",
|
|
1248
|
+
"Proxying",
|
|
1249
|
+
"Negotiating",
|
|
1250
|
+
"Handshake",
|
|
1251
|
+
"Bridging",
|
|
1252
|
+
"Mapping",
|
|
1253
|
+
"Tunneling",
|
|
1254
|
+
"Resolving",
|
|
1255
|
+
"Balancing",
|
|
1256
|
+
"Rewriting",
|
|
1257
|
+
"Indexing",
|
|
1258
|
+
"Synchronizing",
|
|
1259
|
+
"Aligning"
|
|
1260
|
+
]
|
|
1261
|
+
},
|
|
1262
|
+
thinkingStyle: {
|
|
1263
|
+
updateInterval: 120,
|
|
1264
|
+
phases: ["\xB7", "\u2022", "\u25E6", "\u2022"],
|
|
1265
|
+
reverseMirror: false
|
|
1266
|
+
},
|
|
1267
|
+
userMessageDisplay: {
|
|
1268
|
+
format: formatUserMessage(getUserLabel()),
|
|
1269
|
+
styling: ["bold"],
|
|
1270
|
+
foregroundColor: "default",
|
|
1271
|
+
backgroundColor: "default",
|
|
1272
|
+
borderStyle: "topBottomSingle",
|
|
1273
|
+
borderColor: rgb3(palette3.teal),
|
|
1274
|
+
paddingX: 1,
|
|
1275
|
+
paddingY: 0,
|
|
1276
|
+
fitBoxToContent: true
|
|
1277
|
+
},
|
|
1278
|
+
inputBox: {
|
|
1279
|
+
removeBorder: true
|
|
1280
|
+
},
|
|
1281
|
+
misc: {
|
|
1282
|
+
showTweakccVersion: false,
|
|
1283
|
+
showPatchesApplied: false,
|
|
1284
|
+
expandThinkingBlocks: true,
|
|
1285
|
+
enableConversationTitle: true,
|
|
1286
|
+
hideStartupBanner: true,
|
|
1287
|
+
hideCtrlGToEditPrompt: true,
|
|
1288
|
+
hideStartupClawd: true,
|
|
1289
|
+
increaseFileReadLimit: true
|
|
1290
|
+
},
|
|
1291
|
+
toolsets: [
|
|
1292
|
+
{
|
|
1293
|
+
name: "openrouter",
|
|
1294
|
+
allowedTools: "*"
|
|
1295
|
+
}
|
|
1296
|
+
],
|
|
1297
|
+
defaultToolset: "openrouter",
|
|
1298
|
+
planModeToolset: "openrouter"
|
|
1299
|
+
}
|
|
1300
|
+
});
|
|
1301
|
+
|
|
1302
|
+
// src/brands/ccrouter.ts
|
|
1303
|
+
var clamp4 = (value) => Math.max(0, Math.min(255, Math.round(value)));
|
|
1304
|
+
var hexToRgb4 = (hex) => {
|
|
1305
|
+
const normalized = hex.replace("#", "").trim();
|
|
1306
|
+
if (normalized.length === 3) {
|
|
1307
|
+
const [r, g, b] = normalized.split("");
|
|
1308
|
+
return {
|
|
1309
|
+
r: clamp4(parseInt(r + r, 16)),
|
|
1310
|
+
g: clamp4(parseInt(g + g, 16)),
|
|
1311
|
+
b: clamp4(parseInt(b + b, 16))
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
if (normalized.length !== 6) {
|
|
1315
|
+
throw new Error(`Unsupported hex color: ${hex}`);
|
|
1316
|
+
}
|
|
1317
|
+
return {
|
|
1318
|
+
r: clamp4(parseInt(normalized.slice(0, 2), 16)),
|
|
1319
|
+
g: clamp4(parseInt(normalized.slice(2, 4), 16)),
|
|
1320
|
+
b: clamp4(parseInt(normalized.slice(4, 6), 16))
|
|
1321
|
+
};
|
|
1322
|
+
};
|
|
1323
|
+
var rgb4 = (hex) => {
|
|
1324
|
+
const { r, g, b } = hexToRgb4(hex);
|
|
1325
|
+
return `rgb(${r},${g},${b})`;
|
|
1326
|
+
};
|
|
1327
|
+
var mix4 = (hexA, hexB, weight) => {
|
|
1328
|
+
const a = hexToRgb4(hexA);
|
|
1329
|
+
const b = hexToRgb4(hexB);
|
|
1330
|
+
const w = Math.max(0, Math.min(1, weight));
|
|
1331
|
+
return `rgb(${clamp4(a.r + (b.r - a.r) * w)},${clamp4(a.g + (b.g - a.g) * w)},${clamp4(a.b + (b.b - a.b) * w)})`;
|
|
1332
|
+
};
|
|
1333
|
+
var lighten4 = (hex, weight) => mix4(hex, "#ffffff", weight);
|
|
1334
|
+
var palette4 = {
|
|
1335
|
+
base: "#edf6ff",
|
|
1336
|
+
surface: "#f6fbff",
|
|
1337
|
+
panel: "#e3f0fb",
|
|
1338
|
+
border: "#c5d9ee",
|
|
1339
|
+
borderStrong: "#9fb9d8",
|
|
1340
|
+
text: "#162434",
|
|
1341
|
+
textMuted: "#3f546b",
|
|
1342
|
+
textDim: "#6b7f95",
|
|
1343
|
+
sky: "#4da3ff",
|
|
1344
|
+
skySoft: "#7bbcff",
|
|
1345
|
+
skyDeep: "#2a6fcb",
|
|
1346
|
+
cyan: "#6cc7ff",
|
|
1347
|
+
green: "#3aa876",
|
|
1348
|
+
red: "#d34e5c",
|
|
1349
|
+
orange: "#e59b3e",
|
|
1350
|
+
purple: "#6b7dd8"
|
|
1351
|
+
};
|
|
1352
|
+
var theme3 = {
|
|
1353
|
+
name: "CCRouter Sky",
|
|
1354
|
+
id: "ccrouter-sky",
|
|
1355
|
+
colors: {
|
|
1356
|
+
autoAccept: rgb4(palette4.green),
|
|
1357
|
+
bashBorder: rgb4(palette4.sky),
|
|
1358
|
+
claude: rgb4(palette4.skyDeep),
|
|
1359
|
+
claudeShimmer: lighten4(palette4.sky, 0.35),
|
|
1360
|
+
claudeBlue_FOR_SYSTEM_SPINNER: rgb4(palette4.sky),
|
|
1361
|
+
claudeBlueShimmer_FOR_SYSTEM_SPINNER: lighten4(palette4.skySoft, 0.2),
|
|
1362
|
+
permission: rgb4(palette4.cyan),
|
|
1363
|
+
permissionShimmer: lighten4(palette4.cyan, 0.25),
|
|
1364
|
+
planMode: rgb4(palette4.skyDeep),
|
|
1365
|
+
ide: rgb4(palette4.cyan),
|
|
1366
|
+
promptBorder: rgb4(palette4.border),
|
|
1367
|
+
promptBorderShimmer: rgb4(palette4.borderStrong),
|
|
1368
|
+
text: rgb4(palette4.text),
|
|
1369
|
+
inverseText: rgb4(palette4.base),
|
|
1370
|
+
inactive: rgb4(palette4.textDim),
|
|
1371
|
+
subtle: mix4(palette4.base, palette4.skySoft, 0.15),
|
|
1372
|
+
suggestion: rgb4(palette4.skySoft),
|
|
1373
|
+
remember: rgb4(palette4.skyDeep),
|
|
1374
|
+
background: rgb4(palette4.base),
|
|
1375
|
+
success: rgb4(palette4.green),
|
|
1376
|
+
error: rgb4(palette4.red),
|
|
1377
|
+
warning: rgb4(palette4.orange),
|
|
1378
|
+
warningShimmer: lighten4(palette4.orange, 0.28),
|
|
1379
|
+
diffAdded: mix4(palette4.base, palette4.green, 0.2),
|
|
1380
|
+
diffRemoved: mix4(palette4.base, palette4.red, 0.2),
|
|
1381
|
+
diffAddedDimmed: mix4(palette4.base, palette4.green, 0.12),
|
|
1382
|
+
diffRemovedDimmed: mix4(palette4.base, palette4.red, 0.12),
|
|
1383
|
+
diffAddedWord: mix4(palette4.base, palette4.green, 0.42),
|
|
1384
|
+
diffRemovedWord: mix4(palette4.base, palette4.red, 0.42),
|
|
1385
|
+
diffAddedWordDimmed: mix4(palette4.base, palette4.green, 0.28),
|
|
1386
|
+
diffRemovedWordDimmed: mix4(palette4.base, palette4.red, 0.28),
|
|
1387
|
+
red_FOR_SUBAGENTS_ONLY: rgb4(palette4.red),
|
|
1388
|
+
blue_FOR_SUBAGENTS_ONLY: rgb4(palette4.skyDeep),
|
|
1389
|
+
green_FOR_SUBAGENTS_ONLY: rgb4(palette4.green),
|
|
1390
|
+
yellow_FOR_SUBAGENTS_ONLY: rgb4(palette4.orange),
|
|
1391
|
+
purple_FOR_SUBAGENTS_ONLY: rgb4(palette4.purple),
|
|
1392
|
+
orange_FOR_SUBAGENTS_ONLY: rgb4(palette4.orange),
|
|
1393
|
+
pink_FOR_SUBAGENTS_ONLY: lighten4(palette4.purple, 0.32),
|
|
1394
|
+
cyan_FOR_SUBAGENTS_ONLY: rgb4(palette4.cyan),
|
|
1395
|
+
professionalBlue: rgb4(palette4.sky),
|
|
1396
|
+
rainbow_red: rgb4(palette4.red),
|
|
1397
|
+
rainbow_orange: rgb4(palette4.orange),
|
|
1398
|
+
rainbow_yellow: lighten4(palette4.orange, 0.18),
|
|
1399
|
+
rainbow_green: rgb4(palette4.green),
|
|
1400
|
+
rainbow_blue: rgb4(palette4.skySoft),
|
|
1401
|
+
rainbow_indigo: rgb4(palette4.skyDeep),
|
|
1402
|
+
rainbow_violet: rgb4(palette4.purple),
|
|
1403
|
+
rainbow_red_shimmer: lighten4(palette4.red, 0.35),
|
|
1404
|
+
rainbow_orange_shimmer: lighten4(palette4.orange, 0.35),
|
|
1405
|
+
rainbow_yellow_shimmer: lighten4(palette4.orange, 0.3),
|
|
1406
|
+
rainbow_green_shimmer: lighten4(palette4.green, 0.35),
|
|
1407
|
+
rainbow_blue_shimmer: lighten4(palette4.skySoft, 0.35),
|
|
1408
|
+
rainbow_indigo_shimmer: lighten4(palette4.skyDeep, 0.35),
|
|
1409
|
+
rainbow_violet_shimmer: lighten4(palette4.purple, 0.35),
|
|
1410
|
+
clawd_body: rgb4(palette4.skyDeep),
|
|
1411
|
+
clawd_background: rgb4(palette4.base),
|
|
1412
|
+
userMessageBackground: rgb4(palette4.panel),
|
|
1413
|
+
bashMessageBackgroundColor: rgb4(palette4.surface),
|
|
1414
|
+
memoryBackgroundColor: mix4(palette4.panel, palette4.skySoft, 0.12),
|
|
1415
|
+
rate_limit_fill: rgb4(palette4.sky),
|
|
1416
|
+
rate_limit_empty: rgb4(palette4.borderStrong)
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1419
|
+
var buildCCRouterTweakccConfig = () => ({
|
|
1420
|
+
ccVersion: "",
|
|
1421
|
+
ccInstallationPath: null,
|
|
1422
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1423
|
+
changesApplied: false,
|
|
1424
|
+
hidePiebaldAnnouncement: true,
|
|
1425
|
+
settings: {
|
|
1426
|
+
themes: [theme3, ...DEFAULT_THEMES],
|
|
1427
|
+
thinkingVerbs: {
|
|
1428
|
+
format: "{}... ",
|
|
1429
|
+
verbs: [
|
|
1430
|
+
"Routing",
|
|
1431
|
+
"Switching",
|
|
1432
|
+
"Proxying",
|
|
1433
|
+
"Forwarding",
|
|
1434
|
+
"Dispatching",
|
|
1435
|
+
"Negotiating",
|
|
1436
|
+
"Bridging",
|
|
1437
|
+
"Mapping",
|
|
1438
|
+
"Tunneling",
|
|
1439
|
+
"Resolving",
|
|
1440
|
+
"Balancing",
|
|
1441
|
+
"Indexing",
|
|
1442
|
+
"Synchronizing",
|
|
1443
|
+
"Finalizing"
|
|
1444
|
+
]
|
|
1445
|
+
},
|
|
1446
|
+
thinkingStyle: {
|
|
1447
|
+
updateInterval: 115,
|
|
1448
|
+
phases: ["\xB7", "\u2022", "\u25E6", "\u2022"],
|
|
1449
|
+
reverseMirror: false
|
|
1450
|
+
},
|
|
1451
|
+
userMessageDisplay: {
|
|
1452
|
+
format: formatUserMessage(getUserLabel()),
|
|
1453
|
+
styling: ["bold"],
|
|
1454
|
+
foregroundColor: "default",
|
|
1455
|
+
backgroundColor: "default",
|
|
1456
|
+
borderStyle: "topBottomDouble",
|
|
1457
|
+
borderColor: rgb4(palette4.sky),
|
|
1458
|
+
paddingX: 1,
|
|
1459
|
+
paddingY: 0,
|
|
1460
|
+
fitBoxToContent: true
|
|
1461
|
+
},
|
|
1462
|
+
inputBox: {
|
|
1463
|
+
removeBorder: true
|
|
1464
|
+
},
|
|
1465
|
+
misc: {
|
|
1466
|
+
showTweakccVersion: false,
|
|
1467
|
+
showPatchesApplied: false,
|
|
1468
|
+
expandThinkingBlocks: true,
|
|
1469
|
+
enableConversationTitle: true,
|
|
1470
|
+
hideStartupBanner: true,
|
|
1471
|
+
hideCtrlGToEditPrompt: true,
|
|
1472
|
+
hideStartupClawd: true,
|
|
1473
|
+
increaseFileReadLimit: true
|
|
1474
|
+
},
|
|
1475
|
+
toolsets: [
|
|
1476
|
+
{
|
|
1477
|
+
name: "ccrouter",
|
|
1478
|
+
allowedTools: "*"
|
|
1479
|
+
}
|
|
1480
|
+
],
|
|
1481
|
+
defaultToolset: "ccrouter",
|
|
1482
|
+
planModeToolset: "ccrouter"
|
|
1483
|
+
}
|
|
1484
|
+
});
|
|
1485
|
+
|
|
1486
|
+
// src/brands/index.ts
|
|
1487
|
+
var BRAND_PRESETS = {
|
|
1488
|
+
zai: {
|
|
1489
|
+
key: "zai",
|
|
1490
|
+
label: "Z.ai Carbon",
|
|
1491
|
+
description: "Dark carbon palette, gold + blue accents, Z.ai toolset label.",
|
|
1492
|
+
buildTweakccConfig: buildZaiTweakccConfig
|
|
1493
|
+
},
|
|
1494
|
+
minimax: {
|
|
1495
|
+
key: "minimax",
|
|
1496
|
+
label: "MiniMax Pulse",
|
|
1497
|
+
description: "Vibrant spectrum accents (red/orange/pink/violet) with MiniMax toolset label.",
|
|
1498
|
+
buildTweakccConfig: buildMinimaxTweakccConfig
|
|
1499
|
+
},
|
|
1500
|
+
openrouter: {
|
|
1501
|
+
key: "openrouter",
|
|
1502
|
+
label: "OpenRouter Teal",
|
|
1503
|
+
description: "Light UI with teal/cyan accents and OpenRouter toolset label.",
|
|
1504
|
+
buildTweakccConfig: buildOpenRouterTweakccConfig
|
|
1505
|
+
},
|
|
1506
|
+
ccrouter: {
|
|
1507
|
+
key: "ccrouter",
|
|
1508
|
+
label: "CCRouter Sky",
|
|
1509
|
+
description: "Airy sky-blue accents for Claude Code Router.",
|
|
1510
|
+
buildTweakccConfig: buildCCRouterTweakccConfig
|
|
1511
|
+
}
|
|
1512
|
+
};
|
|
1513
|
+
var listBrandPresets = () => Object.values(BRAND_PRESETS);
|
|
1514
|
+
var resolveBrandKey = (providerKey, requested) => {
|
|
1515
|
+
const normalized = requested?.trim().toLowerCase();
|
|
1516
|
+
if (!normalized || normalized === "auto") {
|
|
1517
|
+
return BRAND_PRESETS[providerKey] ? providerKey : null;
|
|
1518
|
+
}
|
|
1519
|
+
if (normalized === "none" || normalized === "default" || normalized === "off") {
|
|
1520
|
+
return null;
|
|
1521
|
+
}
|
|
1522
|
+
if (!BRAND_PRESETS[normalized]) {
|
|
1523
|
+
throw new Error(`Unknown brand preset: ${requested}`);
|
|
1524
|
+
}
|
|
1525
|
+
return normalized;
|
|
1526
|
+
};
|
|
1527
|
+
var buildBrandConfig = (brandKey) => {
|
|
1528
|
+
const preset = BRAND_PRESETS[brandKey];
|
|
1529
|
+
if (!preset) {
|
|
1530
|
+
throw new Error(`Unknown brand preset: ${brandKey}`);
|
|
1531
|
+
}
|
|
1532
|
+
return preset.buildTweakccConfig();
|
|
1533
|
+
};
|
|
1534
|
+
var getBrandThemeId = (brandKey) => {
|
|
1535
|
+
if (!brandKey) return null;
|
|
1536
|
+
const config = buildBrandConfig(brandKey);
|
|
1537
|
+
const theme4 = config.settings?.themes?.[0];
|
|
1538
|
+
return theme4?.id ?? null;
|
|
1539
|
+
};
|
|
1540
|
+
|
|
1541
|
+
// src/core/tweakcc.ts
|
|
1542
|
+
var require2 = createRequire(import.meta.url);
|
|
1543
|
+
var ensureTweakccConfig = (tweakDir, brandKey) => {
|
|
1544
|
+
if (!brandKey) return false;
|
|
1545
|
+
const configPath = path4.join(tweakDir, "config.json");
|
|
1546
|
+
const brandConfig = buildBrandConfig(brandKey);
|
|
1547
|
+
const desiredDisplay = brandConfig.settings.userMessageDisplay;
|
|
1548
|
+
const normalizeFormat = (format) => (format || "").replace(/\s+/g, "").toLowerCase();
|
|
1549
|
+
const legacyFormats = /* @__PURE__ */ new Set(["[z.ai]{}", "[minimax]{}"]);
|
|
1550
|
+
const themeMatches = (a, b) => !!a?.id && !!b?.id && a.id === b.id || !!a?.name && !!b?.name && a.name === b.name;
|
|
1551
|
+
if (fs3.existsSync(configPath)) {
|
|
1552
|
+
try {
|
|
1553
|
+
const existing = JSON.parse(fs3.readFileSync(configPath, "utf8"));
|
|
1554
|
+
let existingThemes = Array.isArray(existing.settings?.themes) ? existing.settings?.themes : [];
|
|
1555
|
+
const brandThemes = Array.isArray(brandConfig.settings.themes) ? brandConfig.settings.themes : [];
|
|
1556
|
+
const brandThemeId = brandThemes[0]?.id;
|
|
1557
|
+
const looksLikeLegacy = existingThemes.length === 1 && brandThemeId && existingThemes[0]?.id === brandThemeId;
|
|
1558
|
+
let didUpdate = false;
|
|
1559
|
+
if (brandKey === "minimax" && existingThemes.length > 0) {
|
|
1560
|
+
const filtered = existingThemes.filter(
|
|
1561
|
+
(theme4) => theme4?.id !== "minimax-ember" && theme4?.id !== "minimax-glass" && theme4?.id !== "minimax-blade" && theme4?.name !== "MiniMax Ember" && theme4?.name !== "MiniMax Glass" && theme4?.name !== "MiniMax Blade"
|
|
1562
|
+
);
|
|
1563
|
+
if (filtered.length !== existingThemes.length) {
|
|
1564
|
+
existingThemes = filtered;
|
|
1565
|
+
existing.settings = { ...existing.settings, themes: existingThemes };
|
|
1566
|
+
didUpdate = true;
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
if (looksLikeLegacy) {
|
|
1570
|
+
existing.settings = { ...brandConfig.settings, ...existing.settings, themes: brandConfig.settings.themes };
|
|
1571
|
+
didUpdate = true;
|
|
1572
|
+
}
|
|
1573
|
+
const existingDisplay = existing.settings?.userMessageDisplay;
|
|
1574
|
+
const desiredMisc = brandConfig.settings.misc;
|
|
1575
|
+
if (desiredDisplay) {
|
|
1576
|
+
if (!existingDisplay) {
|
|
1577
|
+
existing.settings = { ...existing.settings, userMessageDisplay: desiredDisplay };
|
|
1578
|
+
didUpdate = true;
|
|
1579
|
+
} else {
|
|
1580
|
+
const existingFormat = normalizeFormat(existingDisplay.format);
|
|
1581
|
+
const desiredFormat = normalizeFormat(desiredDisplay.format);
|
|
1582
|
+
if (legacyFormats.has(existingFormat) && existingFormat !== desiredFormat) {
|
|
1583
|
+
existing.settings = {
|
|
1584
|
+
...existing.settings,
|
|
1585
|
+
userMessageDisplay: { ...desiredDisplay, ...existingDisplay, format: desiredDisplay.format }
|
|
1586
|
+
};
|
|
1587
|
+
didUpdate = true;
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
if (desiredMisc) {
|
|
1592
|
+
const existingMisc = existing.settings?.misc || {};
|
|
1593
|
+
const nextMisc = { ...existingMisc, ...desiredMisc };
|
|
1594
|
+
const miscChanged = Object.entries(desiredMisc).some(
|
|
1595
|
+
([key, value]) => existingMisc[key] !== value
|
|
1596
|
+
);
|
|
1597
|
+
if (miscChanged) {
|
|
1598
|
+
existing.settings = { ...existing.settings, misc: nextMisc };
|
|
1599
|
+
didUpdate = true;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
if (brandThemes.length > 0) {
|
|
1603
|
+
const mergedThemes = [
|
|
1604
|
+
...brandThemes,
|
|
1605
|
+
...existingThemes.filter((existingTheme) => !brandThemes.some((theme4) => themeMatches(existingTheme, theme4)))
|
|
1606
|
+
];
|
|
1607
|
+
const sameLength = mergedThemes.length === existingThemes.length;
|
|
1608
|
+
const sameOrder = sameLength && mergedThemes.every((theme4, idx) => themeMatches(theme4, existingThemes[idx]));
|
|
1609
|
+
if (!sameOrder) {
|
|
1610
|
+
existing.settings = { ...existing.settings, themes: mergedThemes };
|
|
1611
|
+
didUpdate = true;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
if (didUpdate) {
|
|
1615
|
+
fs3.writeFileSync(configPath, JSON.stringify(existing, null, 2));
|
|
1616
|
+
return true;
|
|
1617
|
+
}
|
|
1618
|
+
} catch {
|
|
1619
|
+
}
|
|
1620
|
+
return false;
|
|
1621
|
+
}
|
|
1622
|
+
fs3.writeFileSync(configPath, JSON.stringify(brandConfig, null, 2));
|
|
1623
|
+
return true;
|
|
1624
|
+
};
|
|
1625
|
+
var resolveLocalTweakcc = (args) => {
|
|
1626
|
+
try {
|
|
1627
|
+
const entry = require2.resolve("tweakcc/dist/index.js");
|
|
1628
|
+
return { cmd: process.execPath, args: [entry, ...args] };
|
|
1629
|
+
} catch {
|
|
1630
|
+
return null;
|
|
1631
|
+
}
|
|
1632
|
+
};
|
|
1633
|
+
var runTweakcc = (tweakDir, binaryPath, stdio = "inherit") => {
|
|
1634
|
+
const env = {
|
|
1635
|
+
...process.env,
|
|
1636
|
+
TWEAKCC_CONFIG_DIR: tweakDir,
|
|
1637
|
+
TWEAKCC_CC_INSTALLATION_PATH: binaryPath
|
|
1638
|
+
};
|
|
1639
|
+
const local = resolveLocalTweakcc(["--apply"]);
|
|
1640
|
+
if (local) {
|
|
1641
|
+
const result2 = spawnSync2(local.cmd, local.args, { stdio: "pipe", env, encoding: "utf8" });
|
|
1642
|
+
if (stdio === "inherit") {
|
|
1643
|
+
if (result2.stdout) process.stdout.write(result2.stdout);
|
|
1644
|
+
if (result2.stderr) process.stderr.write(result2.stderr);
|
|
1645
|
+
}
|
|
1646
|
+
return result2;
|
|
1647
|
+
}
|
|
1648
|
+
if (commandExists("tweakcc")) {
|
|
1649
|
+
const result2 = spawnSync2("tweakcc", ["--apply"], { stdio: "pipe", env, encoding: "utf8" });
|
|
1650
|
+
if (stdio === "inherit") {
|
|
1651
|
+
if (result2.stdout) process.stdout.write(result2.stdout);
|
|
1652
|
+
if (result2.stderr) process.stderr.write(result2.stderr);
|
|
1653
|
+
}
|
|
1654
|
+
return result2;
|
|
1655
|
+
}
|
|
1656
|
+
if (!commandExists("npx")) {
|
|
1657
|
+
return { status: 1, stderr: "npx not found", stdout: "" };
|
|
1658
|
+
}
|
|
1659
|
+
const result = spawnSync2("npx", [`tweakcc@${TWEAKCC_VERSION}`, "--apply"], { stdio: "pipe", env, encoding: "utf8" });
|
|
1660
|
+
if (stdio === "inherit") {
|
|
1661
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
1662
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
1663
|
+
}
|
|
1664
|
+
return result;
|
|
1665
|
+
};
|
|
1666
|
+
var launchTweakccUi = (tweakDir, binaryPath) => {
|
|
1667
|
+
const env = {
|
|
1668
|
+
...process.env,
|
|
1669
|
+
TWEAKCC_CONFIG_DIR: tweakDir,
|
|
1670
|
+
TWEAKCC_CC_INSTALLATION_PATH: binaryPath
|
|
1671
|
+
};
|
|
1672
|
+
const local = resolveLocalTweakcc([]);
|
|
1673
|
+
if (local) {
|
|
1674
|
+
return spawnSync2(local.cmd, local.args, { stdio: "inherit", env, encoding: "utf8" });
|
|
1675
|
+
}
|
|
1676
|
+
if (commandExists("tweakcc")) {
|
|
1677
|
+
return spawnSync2("tweakcc", [], { stdio: "inherit", env, encoding: "utf8" });
|
|
1678
|
+
}
|
|
1679
|
+
if (!commandExists("npx")) {
|
|
1680
|
+
return { status: 1, stderr: "npx not found", stdout: "" };
|
|
1681
|
+
}
|
|
1682
|
+
return spawnSync2("npx", [`tweakcc@${TWEAKCC_VERSION}`], { stdio: "inherit", env, encoding: "utf8" });
|
|
1683
|
+
};
|
|
1684
|
+
var spawnTweakccAsync = (cmd, args, env, stdio) => {
|
|
1685
|
+
return new Promise((resolve) => {
|
|
1686
|
+
const child = spawn(cmd, args, { stdio: "pipe", env });
|
|
1687
|
+
let stdout = "";
|
|
1688
|
+
let stderr = "";
|
|
1689
|
+
child.stdout?.on("data", (d) => {
|
|
1690
|
+
stdout += d.toString();
|
|
1691
|
+
if (stdio === "inherit") process.stdout.write(d);
|
|
1692
|
+
});
|
|
1693
|
+
child.stderr?.on("data", (d) => {
|
|
1694
|
+
stderr += d.toString();
|
|
1695
|
+
if (stdio === "inherit") process.stderr.write(d);
|
|
1696
|
+
});
|
|
1697
|
+
child.on("close", (status) => {
|
|
1698
|
+
resolve({ status, stdout, stderr });
|
|
1699
|
+
});
|
|
1700
|
+
child.on("error", (err) => {
|
|
1701
|
+
resolve({ status: 1, stdout: "", stderr: err.message });
|
|
1702
|
+
});
|
|
1703
|
+
});
|
|
1704
|
+
};
|
|
1705
|
+
var runTweakccAsync = async (tweakDir, binaryPath, stdio = "inherit") => {
|
|
1706
|
+
const env = {
|
|
1707
|
+
...process.env,
|
|
1708
|
+
TWEAKCC_CONFIG_DIR: tweakDir,
|
|
1709
|
+
TWEAKCC_CC_INSTALLATION_PATH: binaryPath
|
|
1710
|
+
};
|
|
1711
|
+
const local = resolveLocalTweakcc(["--apply"]);
|
|
1712
|
+
if (local) {
|
|
1713
|
+
return spawnTweakccAsync(local.cmd, local.args, env, stdio);
|
|
1714
|
+
}
|
|
1715
|
+
if (commandExists("tweakcc")) {
|
|
1716
|
+
return spawnTweakccAsync("tweakcc", ["--apply"], env, stdio);
|
|
1717
|
+
}
|
|
1718
|
+
if (!commandExists("npx")) {
|
|
1719
|
+
return { status: 1, stderr: "npx not found", stdout: "" };
|
|
1720
|
+
}
|
|
1721
|
+
return spawnTweakccAsync("npx", [`tweakcc@${TWEAKCC_VERSION}`, "--apply"], env, stdio);
|
|
1722
|
+
};
|
|
1723
|
+
|
|
1724
|
+
// src/core/errors.ts
|
|
1725
|
+
var extractErrorHint = (text) => {
|
|
1726
|
+
const normalized = text.toLowerCase();
|
|
1727
|
+
if (normalized.includes("could not extract js from native binary")) {
|
|
1728
|
+
return "tweakcc reported a native Claude Code binary. cc-mirror uses npm installs only; update or recreate the variant, or run with --no-tweak.";
|
|
1729
|
+
}
|
|
1730
|
+
if (normalized.includes("node-lief")) {
|
|
1731
|
+
return "tweakcc requires node-lief for native Claude Code binaries. cc-mirror uses npm installs only; update or recreate the variant, or run with --no-tweak.";
|
|
1732
|
+
}
|
|
1733
|
+
return null;
|
|
1734
|
+
};
|
|
1735
|
+
var formatTweakccFailure = (output) => {
|
|
1736
|
+
const hint = extractErrorHint(output);
|
|
1737
|
+
if (hint) return hint;
|
|
1738
|
+
const lines = output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
1739
|
+
if (lines.length === 0) return "tweakcc failed.";
|
|
1740
|
+
const errorLine = lines.find((line) => line.toLowerCase().startsWith("error:"));
|
|
1741
|
+
if (errorLine) return errorLine;
|
|
1742
|
+
const tail = lines.slice(-3).join(" | ");
|
|
1743
|
+
return tail.length > 0 ? tail : "tweakcc failed.";
|
|
1744
|
+
};
|
|
1745
|
+
|
|
1746
|
+
// src/core/variants.ts
|
|
1747
|
+
import fs4 from "node:fs";
|
|
1748
|
+
import path5 from "node:path";
|
|
1749
|
+
var loadVariantMeta = (variantDir) => {
|
|
1750
|
+
const metaPath = path5.join(variantDir, "variant.json");
|
|
1751
|
+
if (!fs4.existsSync(metaPath)) return null;
|
|
1752
|
+
return readJson(metaPath);
|
|
1753
|
+
};
|
|
1754
|
+
var listVariants = (rootDir) => {
|
|
1755
|
+
if (!fs4.existsSync(rootDir)) return [];
|
|
1756
|
+
return fs4.readdirSync(rootDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => fs4.existsSync(path5.join(rootDir, name, "variant.json"))).map((name) => ({ name, meta: loadVariantMeta(path5.join(rootDir, name)) }));
|
|
1757
|
+
};
|
|
1758
|
+
|
|
1759
|
+
// src/core/variant-builder/VariantBuilder.ts
|
|
1760
|
+
import path15 from "node:path";
|
|
1761
|
+
|
|
1762
|
+
// src/providers/index.ts
|
|
1763
|
+
var DEFAULT_TIMEOUT_MS = "3000000";
|
|
1764
|
+
var CCROUTER_AUTH_FALLBACK = "ccrouter-proxy";
|
|
1765
|
+
var PROVIDERS = {
|
|
1766
|
+
zai: {
|
|
1767
|
+
key: "zai",
|
|
1768
|
+
label: "Zai Cloud",
|
|
1769
|
+
description: "GLM Coding Plan via Anthropic-compatible endpoint",
|
|
1770
|
+
baseUrl: "https://api.z.ai/api/anthropic",
|
|
1771
|
+
env: {
|
|
1772
|
+
API_TIMEOUT_MS: DEFAULT_TIMEOUT_MS,
|
|
1773
|
+
ANTHROPIC_DEFAULT_HAIKU_MODEL: "glm-4.5-air",
|
|
1774
|
+
ANTHROPIC_DEFAULT_SONNET_MODEL: "glm-4.7",
|
|
1775
|
+
ANTHROPIC_DEFAULT_OPUS_MODEL: "glm-4.7",
|
|
1776
|
+
CC_MIRROR_SPLASH: 1,
|
|
1777
|
+
CC_MIRROR_PROVIDER_LABEL: "Zai Cloud",
|
|
1778
|
+
CC_MIRROR_SPLASH_STYLE: "zai"
|
|
1779
|
+
},
|
|
1780
|
+
apiKeyLabel: "Zai API key"
|
|
1781
|
+
},
|
|
1782
|
+
minimax: {
|
|
1783
|
+
key: "minimax",
|
|
1784
|
+
label: "MiniMax Cloud",
|
|
1785
|
+
description: "MiniMax-M2.1 via Anthropic-compatible endpoint",
|
|
1786
|
+
baseUrl: "https://api.minimax.io/anthropic",
|
|
1787
|
+
env: {
|
|
1788
|
+
API_TIMEOUT_MS: DEFAULT_TIMEOUT_MS,
|
|
1789
|
+
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: 1,
|
|
1790
|
+
ANTHROPIC_MODEL: "MiniMax-M2.1",
|
|
1791
|
+
ANTHROPIC_SMALL_FAST_MODEL: "MiniMax-M2.1",
|
|
1792
|
+
ANTHROPIC_DEFAULT_SONNET_MODEL: "MiniMax-M2.1",
|
|
1793
|
+
ANTHROPIC_DEFAULT_OPUS_MODEL: "MiniMax-M2.1",
|
|
1794
|
+
ANTHROPIC_DEFAULT_HAIKU_MODEL: "MiniMax-M2.1",
|
|
1795
|
+
CC_MIRROR_SPLASH: 1,
|
|
1796
|
+
CC_MIRROR_PROVIDER_LABEL: "MiniMax Cloud",
|
|
1797
|
+
CC_MIRROR_SPLASH_STYLE: "minimax"
|
|
1798
|
+
},
|
|
1799
|
+
apiKeyLabel: "MiniMax API key"
|
|
1800
|
+
},
|
|
1801
|
+
openrouter: {
|
|
1802
|
+
key: "openrouter",
|
|
1803
|
+
label: "OpenRouter",
|
|
1804
|
+
description: "OpenRouter gateway for Anthropic-compatible requests",
|
|
1805
|
+
baseUrl: "https://openrouter.ai/api",
|
|
1806
|
+
env: {
|
|
1807
|
+
API_TIMEOUT_MS: DEFAULT_TIMEOUT_MS,
|
|
1808
|
+
CC_MIRROR_SPLASH: 1,
|
|
1809
|
+
CC_MIRROR_PROVIDER_LABEL: "OpenRouter",
|
|
1810
|
+
CC_MIRROR_SPLASH_STYLE: "openrouter"
|
|
1811
|
+
},
|
|
1812
|
+
apiKeyLabel: "OpenRouter API key",
|
|
1813
|
+
authMode: "authToken",
|
|
1814
|
+
requiresModelMapping: true
|
|
1815
|
+
},
|
|
1816
|
+
ccrouter: {
|
|
1817
|
+
key: "ccrouter",
|
|
1818
|
+
label: "Claude Code Router",
|
|
1819
|
+
description: "Route requests to any model via Claude Code Router",
|
|
1820
|
+
baseUrl: "http://127.0.0.1:3456",
|
|
1821
|
+
env: {
|
|
1822
|
+
API_TIMEOUT_MS: DEFAULT_TIMEOUT_MS,
|
|
1823
|
+
CC_MIRROR_SPLASH: 1,
|
|
1824
|
+
CC_MIRROR_PROVIDER_LABEL: "Claude Code Router",
|
|
1825
|
+
CC_MIRROR_SPLASH_STYLE: "ccrouter"
|
|
1826
|
+
},
|
|
1827
|
+
apiKeyLabel: "Router URL",
|
|
1828
|
+
authMode: "authToken",
|
|
1829
|
+
requiresModelMapping: false,
|
|
1830
|
+
// Models configured in ~/.claude-code-router/config.json
|
|
1831
|
+
credentialOptional: true
|
|
1832
|
+
// No API key needed - CCRouter handles auth
|
|
1833
|
+
},
|
|
1834
|
+
custom: {
|
|
1835
|
+
key: "custom",
|
|
1836
|
+
label: "Custom",
|
|
1837
|
+
description: "Coming Soon \u2014 Bring your own endpoint",
|
|
1838
|
+
baseUrl: "",
|
|
1839
|
+
env: {
|
|
1840
|
+
API_TIMEOUT_MS: DEFAULT_TIMEOUT_MS
|
|
1841
|
+
},
|
|
1842
|
+
apiKeyLabel: "API key",
|
|
1843
|
+
experimental: true
|
|
1844
|
+
}
|
|
1845
|
+
};
|
|
1846
|
+
var getProvider = (key) => PROVIDERS[key];
|
|
1847
|
+
var listProviders = (includeExperimental = false) => {
|
|
1848
|
+
const providers = Object.values(PROVIDERS);
|
|
1849
|
+
if (includeExperimental) {
|
|
1850
|
+
return providers;
|
|
1851
|
+
}
|
|
1852
|
+
return providers.filter((p) => !p.experimental);
|
|
1853
|
+
};
|
|
1854
|
+
var normalizeModelValue = (value) => (value ?? "").trim();
|
|
1855
|
+
var applyModelOverrides = (env, overrides) => {
|
|
1856
|
+
if (!overrides) return;
|
|
1857
|
+
const entries = [
|
|
1858
|
+
["ANTHROPIC_DEFAULT_SONNET_MODEL", overrides.sonnet],
|
|
1859
|
+
["ANTHROPIC_DEFAULT_OPUS_MODEL", overrides.opus],
|
|
1860
|
+
["ANTHROPIC_DEFAULT_HAIKU_MODEL", overrides.haiku],
|
|
1861
|
+
["ANTHROPIC_SMALL_FAST_MODEL", overrides.smallFast],
|
|
1862
|
+
["ANTHROPIC_MODEL", overrides.defaultModel],
|
|
1863
|
+
["CLAUDE_CODE_SUBAGENT_MODEL", overrides.subagentModel]
|
|
1864
|
+
];
|
|
1865
|
+
for (const [key, value] of entries) {
|
|
1866
|
+
const trimmed = normalizeModelValue(value);
|
|
1867
|
+
if (trimmed) {
|
|
1868
|
+
env[key] = trimmed;
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
};
|
|
1872
|
+
var buildEnv = ({ providerKey, baseUrl, apiKey, extraEnv, modelOverrides }) => {
|
|
1873
|
+
const provider = getProvider(providerKey);
|
|
1874
|
+
if (!provider) {
|
|
1875
|
+
throw new Error(`Unknown provider: ${providerKey}`);
|
|
1876
|
+
}
|
|
1877
|
+
const env = { ...provider.env };
|
|
1878
|
+
const authMode = provider.authMode ?? "apiKey";
|
|
1879
|
+
if (!Object.hasOwn(env, "DISABLE_AUTOUPDATER")) {
|
|
1880
|
+
env.DISABLE_AUTOUPDATER = "1";
|
|
1881
|
+
}
|
|
1882
|
+
if (!Object.hasOwn(env, "CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION")) {
|
|
1883
|
+
env.CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION = "1";
|
|
1884
|
+
}
|
|
1885
|
+
if (baseUrl) env.ANTHROPIC_BASE_URL = baseUrl;
|
|
1886
|
+
if (authMode === "authToken") {
|
|
1887
|
+
const trimmed = normalizeModelValue(apiKey);
|
|
1888
|
+
if (trimmed) {
|
|
1889
|
+
env.ANTHROPIC_AUTH_TOKEN = trimmed;
|
|
1890
|
+
} else if (providerKey === "ccrouter") {
|
|
1891
|
+
env.ANTHROPIC_AUTH_TOKEN = CCROUTER_AUTH_FALLBACK;
|
|
1892
|
+
}
|
|
1893
|
+
if (Object.hasOwn(env, "ANTHROPIC_API_KEY")) {
|
|
1894
|
+
delete env.ANTHROPIC_API_KEY;
|
|
1895
|
+
}
|
|
1896
|
+
} else if (apiKey) {
|
|
1897
|
+
env.ANTHROPIC_API_KEY = apiKey;
|
|
1898
|
+
env.CC_MIRROR_UNSET_AUTH_TOKEN = "1";
|
|
1899
|
+
if (providerKey === "zai") {
|
|
1900
|
+
env.Z_AI_API_KEY = apiKey;
|
|
1901
|
+
}
|
|
1902
|
+
} else if (authMode === "apiKey") {
|
|
1903
|
+
env.CC_MIRROR_UNSET_AUTH_TOKEN = "1";
|
|
1904
|
+
}
|
|
1905
|
+
applyModelOverrides(env, modelOverrides);
|
|
1906
|
+
if (Array.isArray(extraEnv)) {
|
|
1907
|
+
for (const entry of extraEnv) {
|
|
1908
|
+
const idx = entry.indexOf("=");
|
|
1909
|
+
if (idx === -1) continue;
|
|
1910
|
+
const key = entry.slice(0, idx).trim();
|
|
1911
|
+
const value = entry.slice(idx + 1).trim();
|
|
1912
|
+
if (!key) continue;
|
|
1913
|
+
env[key] = value;
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
if (authMode === "authToken" && Object.hasOwn(env, "ANTHROPIC_API_KEY")) {
|
|
1917
|
+
delete env.ANTHROPIC_API_KEY;
|
|
1918
|
+
}
|
|
1919
|
+
if (authMode !== "authToken" && Object.hasOwn(env, "ANTHROPIC_AUTH_TOKEN")) {
|
|
1920
|
+
delete env.ANTHROPIC_AUTH_TOKEN;
|
|
1921
|
+
}
|
|
1922
|
+
return env;
|
|
1923
|
+
};
|
|
1924
|
+
|
|
1925
|
+
// src/core/variant-builder/steps/PrepareDirectoriesStep.ts
|
|
1926
|
+
var PrepareDirectoriesStep = class {
|
|
1927
|
+
name = "PrepareDirectories";
|
|
1928
|
+
execute(ctx) {
|
|
1929
|
+
ctx.report("Preparing directories...");
|
|
1930
|
+
ensureDir(ctx.paths.variantDir);
|
|
1931
|
+
ensureDir(ctx.paths.configDir);
|
|
1932
|
+
ensureDir(ctx.paths.tweakDir);
|
|
1933
|
+
ensureDir(ctx.paths.resolvedBin);
|
|
1934
|
+
ensureDir(ctx.paths.npmDir);
|
|
1935
|
+
}
|
|
1936
|
+
async executeAsync(ctx) {
|
|
1937
|
+
await ctx.report("Preparing directories...");
|
|
1938
|
+
ensureDir(ctx.paths.variantDir);
|
|
1939
|
+
ensureDir(ctx.paths.configDir);
|
|
1940
|
+
ensureDir(ctx.paths.tweakDir);
|
|
1941
|
+
ensureDir(ctx.paths.resolvedBin);
|
|
1942
|
+
ensureDir(ctx.paths.npmDir);
|
|
1943
|
+
}
|
|
1944
|
+
};
|
|
1945
|
+
|
|
1946
|
+
// src/core/install.ts
|
|
1947
|
+
import fs5 from "node:fs";
|
|
1948
|
+
import path6 from "node:path";
|
|
1949
|
+
import { spawn as spawn2, spawnSync as spawnSync3 } from "node:child_process";
|
|
1950
|
+
var resolveNpmCliPath = (npmDir, npmPackage) => {
|
|
1951
|
+
const packageParts = npmPackage.split("/");
|
|
1952
|
+
return path6.join(npmDir, "node_modules", ...packageParts, "cli.js");
|
|
1953
|
+
};
|
|
1954
|
+
var installNpmClaude = (params) => {
|
|
1955
|
+
if (!commandExists("npm")) {
|
|
1956
|
+
throw new Error("npm is required for npm-based installs.");
|
|
1957
|
+
}
|
|
1958
|
+
const stdio = params.stdio ?? "inherit";
|
|
1959
|
+
const pkgSpec = params.npmVersion ? `${params.npmPackage}@${params.npmVersion}` : params.npmPackage;
|
|
1960
|
+
const result = spawnSync3("npm", ["install", "--prefix", params.npmDir, "--no-save", pkgSpec], {
|
|
1961
|
+
stdio: "pipe",
|
|
1962
|
+
encoding: "utf8"
|
|
1963
|
+
});
|
|
1964
|
+
if (stdio === "inherit") {
|
|
1965
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
1966
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
1967
|
+
}
|
|
1968
|
+
if (result.status !== 0) {
|
|
1969
|
+
const output = `${result.stderr ?? ""}
|
|
1970
|
+
${result.stdout ?? ""}`.trim();
|
|
1971
|
+
const tail = output.length > 0 ? `
|
|
1972
|
+
${output}` : "";
|
|
1973
|
+
throw new Error(`npm install failed for ${pkgSpec}.${tail}`);
|
|
1974
|
+
}
|
|
1975
|
+
const cliPath = resolveNpmCliPath(params.npmDir, params.npmPackage);
|
|
1976
|
+
if (!fs5.existsSync(cliPath)) {
|
|
1977
|
+
throw new Error(`npm install succeeded but cli.js was not found at ${cliPath}`);
|
|
1978
|
+
}
|
|
1979
|
+
return { cliPath };
|
|
1980
|
+
};
|
|
1981
|
+
var installNpmClaudeAsync = (params) => {
|
|
1982
|
+
return new Promise((resolve, reject) => {
|
|
1983
|
+
if (!commandExists("npm")) {
|
|
1984
|
+
reject(new Error("npm is required for npm-based installs."));
|
|
1985
|
+
return;
|
|
1986
|
+
}
|
|
1987
|
+
const stdio = params.stdio ?? "inherit";
|
|
1988
|
+
const pkgSpec = params.npmVersion ? `${params.npmPackage}@${params.npmVersion}` : params.npmPackage;
|
|
1989
|
+
const child = spawn2("npm", ["install", "--prefix", params.npmDir, "--no-save", pkgSpec], {
|
|
1990
|
+
stdio: "pipe"
|
|
1991
|
+
});
|
|
1992
|
+
let stdout = "";
|
|
1993
|
+
let stderr = "";
|
|
1994
|
+
child.stdout?.on("data", (data) => {
|
|
1995
|
+
stdout += data.toString();
|
|
1996
|
+
if (stdio === "inherit") process.stdout.write(data);
|
|
1997
|
+
});
|
|
1998
|
+
child.stderr?.on("data", (data) => {
|
|
1999
|
+
stderr += data.toString();
|
|
2000
|
+
if (stdio === "inherit") process.stderr.write(data);
|
|
2001
|
+
});
|
|
2002
|
+
child.on("close", (code) => {
|
|
2003
|
+
if (code !== 0) {
|
|
2004
|
+
const output = `${stderr}
|
|
2005
|
+
${stdout}`.trim();
|
|
2006
|
+
const tail = output.length > 0 ? `
|
|
2007
|
+
${output}` : "";
|
|
2008
|
+
reject(new Error(`npm install failed for ${pkgSpec}.${tail}`));
|
|
2009
|
+
return;
|
|
2010
|
+
}
|
|
2011
|
+
const cliPath = resolveNpmCliPath(params.npmDir, params.npmPackage);
|
|
2012
|
+
if (!fs5.existsSync(cliPath)) {
|
|
2013
|
+
reject(new Error(`npm install succeeded but cli.js was not found at ${cliPath}`));
|
|
2014
|
+
return;
|
|
2015
|
+
}
|
|
2016
|
+
resolve({ cliPath });
|
|
2017
|
+
});
|
|
2018
|
+
child.on("error", (err) => {
|
|
2019
|
+
reject(new Error(`Failed to spawn npm: ${err.message}`));
|
|
2020
|
+
});
|
|
2021
|
+
});
|
|
2022
|
+
};
|
|
2023
|
+
|
|
2024
|
+
// src/core/variant-builder/steps/InstallNpmStep.ts
|
|
2025
|
+
var InstallNpmStep = class {
|
|
2026
|
+
name = "InstallNpm";
|
|
2027
|
+
execute(ctx) {
|
|
2028
|
+
const { prefs, paths, state } = ctx;
|
|
2029
|
+
ctx.report(`Installing ${prefs.resolvedNpmPackage}@${prefs.resolvedNpmVersion}...`);
|
|
2030
|
+
const install = installNpmClaude({
|
|
2031
|
+
npmDir: paths.npmDir,
|
|
2032
|
+
npmPackage: prefs.resolvedNpmPackage,
|
|
2033
|
+
npmVersion: prefs.resolvedNpmVersion,
|
|
2034
|
+
stdio: prefs.commandStdio
|
|
2035
|
+
});
|
|
2036
|
+
state.binaryPath = install.cliPath;
|
|
2037
|
+
state.claudeBinary = `npm:${prefs.resolvedNpmPackage}@${prefs.resolvedNpmVersion}`;
|
|
2038
|
+
}
|
|
2039
|
+
async executeAsync(ctx) {
|
|
2040
|
+
const { prefs, paths, state } = ctx;
|
|
2041
|
+
await ctx.report(`Installing ${prefs.resolvedNpmPackage}@${prefs.resolvedNpmVersion}...`);
|
|
2042
|
+
const install = await installNpmClaudeAsync({
|
|
2043
|
+
npmDir: paths.npmDir,
|
|
2044
|
+
npmPackage: prefs.resolvedNpmPackage,
|
|
2045
|
+
npmVersion: prefs.resolvedNpmVersion,
|
|
2046
|
+
stdio: prefs.commandStdio
|
|
2047
|
+
});
|
|
2048
|
+
state.binaryPath = install.cliPath;
|
|
2049
|
+
state.claudeBinary = `npm:${prefs.resolvedNpmPackage}@${prefs.resolvedNpmVersion}`;
|
|
2050
|
+
}
|
|
2051
|
+
};
|
|
2052
|
+
|
|
2053
|
+
// src/core/variant-builder/steps/WriteConfigStep.ts
|
|
2054
|
+
import path8 from "node:path";
|
|
2055
|
+
|
|
2056
|
+
// src/core/claude-config.ts
|
|
2057
|
+
import fs6 from "node:fs";
|
|
2058
|
+
import path7 from "node:path";
|
|
2059
|
+
var SETTINGS_FILE = "settings.json";
|
|
2060
|
+
var CLAUDE_CONFIG_FILE = ".claude.json";
|
|
2061
|
+
var PLACEHOLDER_KEY = "<API_KEY>";
|
|
2062
|
+
var toStringOrNull = (value) => {
|
|
2063
|
+
if (typeof value !== "string") return null;
|
|
2064
|
+
const trimmed = value.trim();
|
|
2065
|
+
if (!trimmed || trimmed === PLACEHOLDER_KEY) return null;
|
|
2066
|
+
return trimmed;
|
|
2067
|
+
};
|
|
2068
|
+
var readSettingsApiKey = (configDir) => {
|
|
2069
|
+
const settingsPath = path7.join(configDir, SETTINGS_FILE);
|
|
2070
|
+
const settings = readJson(settingsPath);
|
|
2071
|
+
if (!settings?.env) return null;
|
|
2072
|
+
const env = settings.env;
|
|
2073
|
+
return toStringOrNull(env.ANTHROPIC_API_KEY);
|
|
2074
|
+
};
|
|
2075
|
+
var ZAI_DENY_TOOLS = [
|
|
2076
|
+
"mcp__4_5v_mcp__analyze_image",
|
|
2077
|
+
"mcp__milk_tea_server__claim_milk_tea_coupon",
|
|
2078
|
+
"mcp__web_reader__webReader"
|
|
2079
|
+
];
|
|
2080
|
+
var ensureZaiMcpDeny = (configDir) => {
|
|
2081
|
+
const settingsPath = path7.join(configDir, SETTINGS_FILE);
|
|
2082
|
+
const existing = readJson(settingsPath) || {};
|
|
2083
|
+
const permissions = existing.permissions || {};
|
|
2084
|
+
const deny = Array.isArray(permissions.deny) ? [...permissions.deny] : [];
|
|
2085
|
+
let changed = false;
|
|
2086
|
+
for (const tool of ZAI_DENY_TOOLS) {
|
|
2087
|
+
if (!deny.includes(tool)) {
|
|
2088
|
+
deny.push(tool);
|
|
2089
|
+
changed = true;
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
if (!changed) return false;
|
|
2093
|
+
const next = {
|
|
2094
|
+
...existing,
|
|
2095
|
+
permissions: {
|
|
2096
|
+
...permissions,
|
|
2097
|
+
deny
|
|
2098
|
+
}
|
|
2099
|
+
};
|
|
2100
|
+
writeJson(settingsPath, next);
|
|
2101
|
+
return true;
|
|
2102
|
+
};
|
|
2103
|
+
var ensureSettingsEnvDefaults = (configDir, defaults) => {
|
|
2104
|
+
const settingsPath = path7.join(configDir, SETTINGS_FILE);
|
|
2105
|
+
const existing = readJson(settingsPath) || {};
|
|
2106
|
+
const env = { ...existing.env ?? {} };
|
|
2107
|
+
let changed = false;
|
|
2108
|
+
for (const [key, value] of Object.entries(defaults)) {
|
|
2109
|
+
if (!Object.hasOwn(env, key)) {
|
|
2110
|
+
env[key] = value;
|
|
2111
|
+
changed = true;
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
if (!changed) return false;
|
|
2115
|
+
writeJson(settingsPath, { ...existing, env });
|
|
2116
|
+
return true;
|
|
2117
|
+
};
|
|
2118
|
+
var ensureSettingsEnvOverrides = (configDir, overrides) => {
|
|
2119
|
+
const settingsPath = path7.join(configDir, SETTINGS_FILE);
|
|
2120
|
+
const existing = readJson(settingsPath) || {};
|
|
2121
|
+
const env = { ...existing.env ?? {} };
|
|
2122
|
+
let changed = false;
|
|
2123
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
2124
|
+
if (value === void 0) continue;
|
|
2125
|
+
if (env[key] !== value) {
|
|
2126
|
+
env[key] = value;
|
|
2127
|
+
changed = true;
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
if (!changed) return false;
|
|
2131
|
+
writeJson(settingsPath, { ...existing, env });
|
|
2132
|
+
return true;
|
|
2133
|
+
};
|
|
2134
|
+
var ensureApiKeyApproval = (configDir, apiKey) => {
|
|
2135
|
+
const resolvedKey = toStringOrNull(apiKey) || readSettingsApiKey(configDir);
|
|
2136
|
+
if (!resolvedKey) return false;
|
|
2137
|
+
const approvedToken = resolvedKey.slice(-20);
|
|
2138
|
+
const configPath = path7.join(configDir, CLAUDE_CONFIG_FILE);
|
|
2139
|
+
const exists = fs6.existsSync(configPath);
|
|
2140
|
+
let config = null;
|
|
2141
|
+
if (exists) {
|
|
2142
|
+
config = readJson(configPath);
|
|
2143
|
+
if (!config) return false;
|
|
2144
|
+
} else {
|
|
2145
|
+
config = {};
|
|
2146
|
+
}
|
|
2147
|
+
const approved = Array.isArray(config.customApiKeyResponses?.approved) ? [...config.customApiKeyResponses.approved] : [];
|
|
2148
|
+
const rejected = Array.isArray(config.customApiKeyResponses?.rejected) ? [...config.customApiKeyResponses.rejected] : [];
|
|
2149
|
+
if (approved.includes(approvedToken)) return false;
|
|
2150
|
+
approved.push(approvedToken);
|
|
2151
|
+
const next = {
|
|
2152
|
+
...config,
|
|
2153
|
+
customApiKeyResponses: {
|
|
2154
|
+
...config.customApiKeyResponses,
|
|
2155
|
+
approved,
|
|
2156
|
+
rejected
|
|
2157
|
+
}
|
|
2158
|
+
};
|
|
2159
|
+
writeJson(configPath, next);
|
|
2160
|
+
return true;
|
|
2161
|
+
};
|
|
2162
|
+
var ensureOnboardingState = (configDir, opts = {}) => {
|
|
2163
|
+
const configPath = path7.join(configDir, CLAUDE_CONFIG_FILE);
|
|
2164
|
+
const exists = fs6.existsSync(configPath);
|
|
2165
|
+
let config = null;
|
|
2166
|
+
if (exists) {
|
|
2167
|
+
config = readJson(configPath);
|
|
2168
|
+
if (!config) {
|
|
2169
|
+
return { updated: false, themeChanged: false, onboardingChanged: false };
|
|
2170
|
+
}
|
|
2171
|
+
} else {
|
|
2172
|
+
config = {};
|
|
2173
|
+
}
|
|
2174
|
+
let changed = false;
|
|
2175
|
+
let themeChanged = false;
|
|
2176
|
+
let onboardingChanged = false;
|
|
2177
|
+
if (opts.themeId) {
|
|
2178
|
+
const shouldSetTheme = opts.forceTheme || !config.theme;
|
|
2179
|
+
if (shouldSetTheme && config.theme !== opts.themeId) {
|
|
2180
|
+
config.theme = opts.themeId;
|
|
2181
|
+
changed = true;
|
|
2182
|
+
themeChanged = true;
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
if (config.hasCompletedOnboarding !== true) {
|
|
2186
|
+
config.hasCompletedOnboarding = true;
|
|
2187
|
+
changed = true;
|
|
2188
|
+
onboardingChanged = true;
|
|
2189
|
+
}
|
|
2190
|
+
if (!changed) {
|
|
2191
|
+
return { updated: false, themeChanged: false, onboardingChanged: false };
|
|
2192
|
+
}
|
|
2193
|
+
writeJson(configPath, config);
|
|
2194
|
+
return { updated: true, themeChanged, onboardingChanged };
|
|
2195
|
+
};
|
|
2196
|
+
var ensureMinimaxMcpServer = (configDir, apiKey) => {
|
|
2197
|
+
const resolvedKey = toStringOrNull(apiKey) || readSettingsApiKey(configDir);
|
|
2198
|
+
const configPath = path7.join(configDir, CLAUDE_CONFIG_FILE);
|
|
2199
|
+
const exists = fs6.existsSync(configPath);
|
|
2200
|
+
let config = null;
|
|
2201
|
+
if (exists) {
|
|
2202
|
+
config = readJson(configPath);
|
|
2203
|
+
if (!config) return false;
|
|
2204
|
+
} else {
|
|
2205
|
+
config = {};
|
|
2206
|
+
}
|
|
2207
|
+
const existingServers = config.mcpServers ?? {};
|
|
2208
|
+
if (existingServers.MiniMax) return false;
|
|
2209
|
+
const mcpServer = {
|
|
2210
|
+
command: "uvx",
|
|
2211
|
+
args: ["minimax-coding-plan-mcp", "-y"],
|
|
2212
|
+
env: {
|
|
2213
|
+
MINIMAX_API_KEY: resolvedKey ?? "Enter your API key",
|
|
2214
|
+
MINIMAX_API_HOST: "https://api.minimax.io"
|
|
2215
|
+
}
|
|
2216
|
+
};
|
|
2217
|
+
const next = {
|
|
2218
|
+
...config,
|
|
2219
|
+
mcpServers: {
|
|
2220
|
+
...existingServers,
|
|
2221
|
+
MiniMax: mcpServer
|
|
2222
|
+
}
|
|
2223
|
+
};
|
|
2224
|
+
writeJson(configPath, next);
|
|
2225
|
+
return true;
|
|
2226
|
+
};
|
|
2227
|
+
|
|
2228
|
+
// src/core/variant-builder/steps/WriteConfigStep.ts
|
|
2229
|
+
var WriteConfigStep = class {
|
|
2230
|
+
name = "WriteConfig";
|
|
2231
|
+
execute(ctx) {
|
|
2232
|
+
this.writeConfig(ctx);
|
|
2233
|
+
}
|
|
2234
|
+
async executeAsync(ctx) {
|
|
2235
|
+
await ctx.report("Writing configuration...");
|
|
2236
|
+
this.writeConfig(ctx);
|
|
2237
|
+
}
|
|
2238
|
+
writeConfig(ctx) {
|
|
2239
|
+
const { params, provider, paths, state } = ctx;
|
|
2240
|
+
ctx.report("Writing configuration...");
|
|
2241
|
+
const env = buildEnv({
|
|
2242
|
+
providerKey: params.providerKey,
|
|
2243
|
+
baseUrl: params.baseUrl,
|
|
2244
|
+
apiKey: params.apiKey,
|
|
2245
|
+
extraEnv: params.extraEnv,
|
|
2246
|
+
modelOverrides: params.modelOverrides
|
|
2247
|
+
});
|
|
2248
|
+
if (!Object.hasOwn(env, "TWEAKCC_CONFIG_DIR")) {
|
|
2249
|
+
env.TWEAKCC_CONFIG_DIR = paths.tweakDir;
|
|
2250
|
+
}
|
|
2251
|
+
const authMode = provider.authMode ?? "apiKey";
|
|
2252
|
+
if (authMode === "apiKey" && !env.ANTHROPIC_API_KEY) {
|
|
2253
|
+
env.ANTHROPIC_API_KEY = "<API_KEY>";
|
|
2254
|
+
}
|
|
2255
|
+
const config = { env };
|
|
2256
|
+
writeJson(path8.join(paths.configDir, "settings.json"), config);
|
|
2257
|
+
state.env = env;
|
|
2258
|
+
state.resolvedApiKey = typeof env.ANTHROPIC_API_KEY === "string" ? env.ANTHROPIC_API_KEY : void 0;
|
|
2259
|
+
ensureApiKeyApproval(paths.configDir, state.resolvedApiKey);
|
|
2260
|
+
if (provider.authMode === "authToken" && !env.ANTHROPIC_AUTH_TOKEN) {
|
|
2261
|
+
state.notes.push("ANTHROPIC_AUTH_TOKEN not set; provider auth may fail.");
|
|
2262
|
+
}
|
|
2263
|
+
if (params.providerKey === "openrouter") {
|
|
2264
|
+
const missing = [];
|
|
2265
|
+
if (!env.ANTHROPIC_DEFAULT_SONNET_MODEL) missing.push("ANTHROPIC_DEFAULT_SONNET_MODEL");
|
|
2266
|
+
if (!env.ANTHROPIC_DEFAULT_OPUS_MODEL) missing.push("ANTHROPIC_DEFAULT_OPUS_MODEL");
|
|
2267
|
+
if (!env.ANTHROPIC_DEFAULT_HAIKU_MODEL) missing.push("ANTHROPIC_DEFAULT_HAIKU_MODEL");
|
|
2268
|
+
if (missing.length > 0) {
|
|
2269
|
+
state.notes.push(`Model mapping incomplete; add ${missing.join(", ")} if needed.`);
|
|
2270
|
+
}
|
|
2271
|
+
state.notes.push("Feature support varies by provider. WebSearch/Image tools may require special models.");
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
};
|
|
2275
|
+
|
|
2276
|
+
// src/core/variant-builder/steps/BrandThemeStep.ts
|
|
2277
|
+
var BrandThemeStep = class {
|
|
2278
|
+
name = "BrandTheme";
|
|
2279
|
+
execute(ctx) {
|
|
2280
|
+
ctx.report("Setting up brand theme...");
|
|
2281
|
+
this.setupBrand(ctx);
|
|
2282
|
+
}
|
|
2283
|
+
async executeAsync(ctx) {
|
|
2284
|
+
await ctx.report("Setting up brand theme...");
|
|
2285
|
+
this.setupBrand(ctx);
|
|
2286
|
+
if (ctx.params.providerKey === "minimax") {
|
|
2287
|
+
await ctx.report("Configuring MiniMax MCP server...");
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
setupBrand(ctx) {
|
|
2291
|
+
const { params, paths, prefs, state } = ctx;
|
|
2292
|
+
const brandKey = resolveBrandKey(params.providerKey, params.brand);
|
|
2293
|
+
prefs.brandKey = brandKey;
|
|
2294
|
+
ensureTweakccConfig(paths.tweakDir, brandKey);
|
|
2295
|
+
const brandThemeId = !params.noTweak && brandKey ? getBrandThemeId(brandKey) : null;
|
|
2296
|
+
const onboarding = ensureOnboardingState(paths.configDir, {
|
|
2297
|
+
themeId: brandThemeId ?? "dark",
|
|
2298
|
+
forceTheme: Boolean(brandThemeId)
|
|
2299
|
+
});
|
|
2300
|
+
if (onboarding.themeChanged) {
|
|
2301
|
+
state.notes.push(`Default theme set to ${brandThemeId ?? "dark"}.`);
|
|
2302
|
+
}
|
|
2303
|
+
if (onboarding.onboardingChanged) {
|
|
2304
|
+
state.notes.push("Onboarding marked complete.");
|
|
2305
|
+
}
|
|
2306
|
+
if (params.providerKey === "minimax") {
|
|
2307
|
+
ctx.report("Configuring MiniMax MCP server...");
|
|
2308
|
+
ensureMinimaxMcpServer(paths.configDir, state.resolvedApiKey);
|
|
2309
|
+
}
|
|
2310
|
+
if (params.providerKey === "zai") {
|
|
2311
|
+
const blockedZaiTools = ensureZaiMcpDeny(paths.configDir);
|
|
2312
|
+
if (blockedZaiTools) {
|
|
2313
|
+
state.notes.push("Blocked Z.ai-injected MCP tools in settings.json.");
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
if (params.noTweak && prefs.promptPackPreference) {
|
|
2317
|
+
state.notes.push(`Prompt pack skipped (tweakcc disabled, ${prefs.promptPackModePreference}).`);
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
};
|
|
2321
|
+
|
|
2322
|
+
// src/core/prompt-pack.ts
|
|
2323
|
+
import fs7 from "node:fs";
|
|
2324
|
+
import path9 from "node:path";
|
|
2325
|
+
|
|
2326
|
+
// src/core/prompt-pack/sanitize.ts
|
|
2327
|
+
var BACKTICK_REGEX = /`/g;
|
|
2328
|
+
var sanitizeOverlayText = (text) => text.replace(BACKTICK_REGEX, "'");
|
|
2329
|
+
var sanitizeOverlayMap = (overlays) => {
|
|
2330
|
+
const sanitized = {};
|
|
2331
|
+
for (const [key, value] of Object.entries(overlays)) {
|
|
2332
|
+
if (!value || !value.trim()) continue;
|
|
2333
|
+
sanitized[key] = sanitizeOverlayText(value);
|
|
2334
|
+
}
|
|
2335
|
+
return sanitized;
|
|
2336
|
+
};
|
|
2337
|
+
|
|
2338
|
+
// src/core/prompt-pack/shared.ts
|
|
2339
|
+
var verbositySpec = `
|
|
2340
|
+
<output_verbosity_spec>
|
|
2341
|
+
- Default: 3-6 sentences or <=6 bullets.
|
|
2342
|
+
- For multi-step / multi-file work: 1 short overview paragraph, then <=6 bullets:
|
|
2343
|
+
What changed, Where, How to verify, Risks, Next steps, Open questions.
|
|
2344
|
+
</output_verbosity_spec>
|
|
2345
|
+
`.trim();
|
|
2346
|
+
var operatingSpec = (mode) => `
|
|
2347
|
+
<system_reminder>
|
|
2348
|
+
- Operate like an ambitious, senior engineer: proactive, high-ownership, and precise.
|
|
2349
|
+
- Prefer concrete outputs: commands, file paths, diffs, and validation steps.
|
|
2350
|
+
- Respect permissions and confirm before destructive actions.
|
|
2351
|
+
${mode === "maximal" ? "- Parallelize independent work with Task/subagents when useful." : ""}
|
|
2352
|
+
</system_reminder>
|
|
2353
|
+
`.trim();
|
|
2354
|
+
var subjectiveWorkSpec = `
|
|
2355
|
+
<subjective_work_guardrails>
|
|
2356
|
+
- For creative, subjective, or open-ended tasks, ask clarifying questions first (use AskUserQuestion when available).
|
|
2357
|
+
- Treat phrases like "impress me", "make it cool", "build something amazing" as signals to clarify preferences, not invitations to execute.
|
|
2358
|
+
- For design or aesthetic work, ask about purpose, audience, style preferences, inspirations, constraints, and tech stack before generating.
|
|
2359
|
+
- When you catch yourself making assumptions about subjective quality, pause and ask instead.
|
|
2360
|
+
</subjective_work_guardrails>
|
|
2361
|
+
`.trim();
|
|
2362
|
+
|
|
2363
|
+
// src/core/prompt-pack/providers/zai.ts
|
|
2364
|
+
var ZAI_BLOCKED_MCP_TOOLS = [
|
|
2365
|
+
"mcp__4_5v_mcp__analyze_image",
|
|
2366
|
+
"mcp__milk_tea_server__claim_milk_tea_coupon",
|
|
2367
|
+
"mcp__web_reader__webReader"
|
|
2368
|
+
];
|
|
2369
|
+
var ZAI_CLI_TEXT = `
|
|
2370
|
+
# ZAI CLI (embedded reference)
|
|
2371
|
+
Access Z.AI capabilities via 'npx zai-cli'. The CLI is self-documenting - use '--help' at any level.
|
|
2372
|
+
|
|
2373
|
+
Setup:
|
|
2374
|
+
- Required env: 'Z_AI_API_KEY'
|
|
2375
|
+
- Get a key at: https://z.ai/manage-apikey/apikey-list
|
|
2376
|
+
|
|
2377
|
+
Commands:
|
|
2378
|
+
- vision: Analyze images, screenshots, videos (many subcommands)
|
|
2379
|
+
- search: Real-time web search (domain/recency/location/count filters)
|
|
2380
|
+
- read: Fetch web pages as markdown/text (format/no-images/with-links/timeout)
|
|
2381
|
+
- repo: GitHub exploration (tree/search/read). Run npx zai-cli repo --help for subcommands.
|
|
2382
|
+
- tools/tool/call: MCP tool discovery + raw calls (advanced)
|
|
2383
|
+
- code: TypeScript tool chaining (advanced)
|
|
2384
|
+
- doctor: Environment + connectivity checks
|
|
2385
|
+
|
|
2386
|
+
Quick start examples:
|
|
2387
|
+
- npx zai-cli vision analyze ./screenshot.png "What errors do you see?"
|
|
2388
|
+
- npx zai-cli search "React 19 new features" --count 5
|
|
2389
|
+
- npx zai-cli read https://docs.example.com/api
|
|
2390
|
+
- npx zai-cli repo search facebook/react "server components"
|
|
2391
|
+
- npx zai-cli repo --help
|
|
2392
|
+
- npx zai-cli doctor
|
|
2393
|
+
|
|
2394
|
+
Output:
|
|
2395
|
+
- Default: data-only (token efficient).
|
|
2396
|
+
- Use '--output-format json' for { success, data, timestamp } wrapping.
|
|
2397
|
+
`.trim();
|
|
2398
|
+
var buildZaiContract = (mode) => `
|
|
2399
|
+
<explicit_guidance>
|
|
2400
|
+
Provider: z.ai (GLM)
|
|
2401
|
+
|
|
2402
|
+
<authentication>
|
|
2403
|
+
- Use API-key auth only.
|
|
2404
|
+
- Ignore ANTHROPIC_AUTH_TOKEN if present.
|
|
2405
|
+
- Required env:
|
|
2406
|
+
- ANTHROPIC_API_KEY (Claude Code API-key mode)
|
|
2407
|
+
- Z_AI_API_KEY (for zai-cli)
|
|
2408
|
+
</authentication>
|
|
2409
|
+
|
|
2410
|
+
<tool_info>
|
|
2411
|
+
${ZAI_CLI_TEXT}
|
|
2412
|
+
|
|
2413
|
+
Important:
|
|
2414
|
+
- zai-cli is NOT installed as a Claude Code Skill in this variant. Do not use Skill for this.
|
|
2415
|
+
</tool_info>
|
|
2416
|
+
|
|
2417
|
+
<tool_routing priority="critical">
|
|
2418
|
+
When you need external info, web content, or image understanding, follow this routing (use the Bash tool):
|
|
2419
|
+
1) Web search:
|
|
2420
|
+
npx --yes zai-cli search "<query>" --count 5 --output-format json
|
|
2421
|
+
2) Read a URL:
|
|
2422
|
+
npx --yes zai-cli read <url> --output-format json
|
|
2423
|
+
3) Image analysis:
|
|
2424
|
+
npx --yes zai-cli vision analyze <image_url_or_path> "<prompt>" --output-format json
|
|
2425
|
+
4) GitHub repo exploration (public repos only):
|
|
2426
|
+
- Search: npx --yes zai-cli repo search <owner/repo> "<query>" --output-format json
|
|
2427
|
+
- Tree: npx --yes zai-cli repo tree <owner/repo> --depth 2 --output-format json
|
|
2428
|
+
- Read: npx --yes zai-cli repo read <owner/repo> <path> --output-format json
|
|
2429
|
+
5) Troubleshooting:
|
|
2430
|
+
npx --yes zai-cli doctor --output-format json
|
|
2431
|
+
|
|
2432
|
+
Only fall back to builtin WebSearch/WebFetch if Bash is unavailable or the user explicitly requests it.
|
|
2433
|
+
</tool_routing>
|
|
2434
|
+
|
|
2435
|
+
<warning priority="critical">
|
|
2436
|
+
Z.ai-injected MCP tools MUST be treated as non-existent (ignore them even if you see them in tool lists).
|
|
2437
|
+
Rules:
|
|
2438
|
+
- NEVER select or call these tools.
|
|
2439
|
+
- Prefer zai-cli via Bash for web/search/vision.
|
|
2440
|
+
- Other MCP tools may exist if the user configured them; use them only if explicitly requested or clearly needed.
|
|
2441
|
+
Blocked tools:
|
|
2442
|
+
${ZAI_BLOCKED_MCP_TOOLS.map((tool) => `- ${tool}`).join("\n")}
|
|
2443
|
+
</warning>
|
|
2444
|
+
|
|
2445
|
+
${operatingSpec(mode)}
|
|
2446
|
+
|
|
2447
|
+
${subjectiveWorkSpec}
|
|
2448
|
+
|
|
2449
|
+
${verbositySpec}
|
|
2450
|
+
</explicit_guidance>
|
|
2451
|
+
`.trim();
|
|
2452
|
+
var buildZaiExcerpt = () => `
|
|
2453
|
+
<tool_info>
|
|
2454
|
+
Z.ai tool routing:
|
|
2455
|
+
- Use Bash + npx --yes zai-cli for web/search/vision.
|
|
2456
|
+
- Ignore the Z.ai-injected MCP tools listed below (treat them as non-existent).
|
|
2457
|
+
- No zai-cli skill is installed; do not use Skill for this.
|
|
2458
|
+
Blocked MCP tool names (treat as non-existent):
|
|
2459
|
+
${ZAI_BLOCKED_MCP_TOOLS.map((tool) => `- ${tool}`).join("\n")}
|
|
2460
|
+
</tool_info>
|
|
2461
|
+
|
|
2462
|
+
${subjectiveWorkSpec}
|
|
2463
|
+
`.trim();
|
|
2464
|
+
var buildZaiOverlays = (mode) => ({
|
|
2465
|
+
main: buildZaiContract(mode),
|
|
2466
|
+
mcpCli: `
|
|
2467
|
+
${buildZaiExcerpt()}
|
|
2468
|
+
|
|
2469
|
+
<warning priority="critical">
|
|
2470
|
+
Z.ai MCP policy: Ignore the blocked Z.ai-injected MCP tools (treat them as non-existent).
|
|
2471
|
+
</warning>
|
|
2472
|
+
|
|
2473
|
+
If you need web/search/vision, use zai-cli via Bash.
|
|
2474
|
+
`.trim(),
|
|
2475
|
+
taskAgent: `
|
|
2476
|
+
<explicit_guidance>
|
|
2477
|
+
You are a Task subagent. Stay within requested scope, but be proactive about missing prerequisites.
|
|
2478
|
+
Verify key claims with tools when possible; cite file paths and command outputs.
|
|
2479
|
+
</explicit_guidance>
|
|
2480
|
+
|
|
2481
|
+
${buildZaiExcerpt()}
|
|
2482
|
+
|
|
2483
|
+
${verbositySpec}
|
|
2484
|
+
`.trim(),
|
|
2485
|
+
bash: `
|
|
2486
|
+
${ZAI_CLI_TEXT}
|
|
2487
|
+
|
|
2488
|
+
<explicit_guidance>
|
|
2489
|
+
When you need web/search/vision, prefer these exact commands:
|
|
2490
|
+
- Web search:
|
|
2491
|
+
npx --yes zai-cli search "<query>" --count 5 --output-format json
|
|
2492
|
+
- Read a URL:
|
|
2493
|
+
npx --yes zai-cli read <url> --output-format json
|
|
2494
|
+
- Vision:
|
|
2495
|
+
npx --yes zai-cli vision analyze <image_url_or_path> "<prompt>" --output-format json
|
|
2496
|
+
</explicit_guidance>
|
|
2497
|
+
|
|
2498
|
+
<warning priority="critical">
|
|
2499
|
+
Z.ai MCP policy: ignore the blocked Z.ai-injected MCP tools (treat them as non-existent).
|
|
2500
|
+
Prefer zai-cli via Bash for web/search/vision.
|
|
2501
|
+
</warning>
|
|
2502
|
+
`.trim(),
|
|
2503
|
+
webfetch: `
|
|
2504
|
+
<explicit_guidance>
|
|
2505
|
+
Z.ai routing: prefer Bash + npx --yes zai-cli read <url> --output-format json.
|
|
2506
|
+
</explicit_guidance>
|
|
2507
|
+
`.trim(),
|
|
2508
|
+
websearch: `
|
|
2509
|
+
<explicit_guidance>
|
|
2510
|
+
Z.ai routing: prefer Bash + npx --yes zai-cli search "<query>" --count 5 --output-format json.
|
|
2511
|
+
</explicit_guidance>
|
|
2512
|
+
`.trim(),
|
|
2513
|
+
mcpsearch: `
|
|
2514
|
+
<warning priority="critical">
|
|
2515
|
+
Z.ai MCP policy: never select these Z.ai-injected MCP tools (treat them as non-existent):
|
|
2516
|
+
${ZAI_BLOCKED_MCP_TOOLS.map((tool) => `- ${tool}`).join("\n")}
|
|
2517
|
+
</warning>
|
|
2518
|
+
|
|
2519
|
+
<explicit_guidance>
|
|
2520
|
+
Prefer zai-cli via Bash for web/search/vision. Only use other MCP tools if the user explicitly configured them and they are clearly relevant.
|
|
2521
|
+
</explicit_guidance>
|
|
2522
|
+
`.trim()
|
|
2523
|
+
});
|
|
2524
|
+
|
|
2525
|
+
// src/core/prompt-pack/providers/minimax.ts
|
|
2526
|
+
var MINIMAX_WEB_SEARCH = "mcp__MiniMax__web_search";
|
|
2527
|
+
var MINIMAX_UNDERSTAND_IMAGE = "mcp__MiniMax__understand_image";
|
|
2528
|
+
var buildMinimaxContract = (mode) => `
|
|
2529
|
+
<explicit_guidance>
|
|
2530
|
+
Provider: MiniMax
|
|
2531
|
+
|
|
2532
|
+
<authentication>
|
|
2533
|
+
- Use API-key auth only.
|
|
2534
|
+
- Ignore ANTHROPIC_AUTH_TOKEN if present.
|
|
2535
|
+
</authentication>
|
|
2536
|
+
|
|
2537
|
+
<tool_routing priority="critical">
|
|
2538
|
+
MiniMax MCP tools available (and ONLY these for web + vision):
|
|
2539
|
+
- ${MINIMAX_WEB_SEARCH} (web search)
|
|
2540
|
+
- ${MINIMAX_UNDERSTAND_IMAGE} (image understanding)
|
|
2541
|
+
|
|
2542
|
+
<warning priority="critical">
|
|
2543
|
+
For MiniMax variants, the builtin WebSearch tool does NOT exist (treat it as unavailable).
|
|
2544
|
+
You MUST use ${MINIMAX_WEB_SEARCH} for all web discovery/search.
|
|
2545
|
+
</warning>
|
|
2546
|
+
|
|
2547
|
+
MCP usage requirement:
|
|
2548
|
+
- Before calling an MCP tool, you MUST load it using MCPSearch:
|
|
2549
|
+
- MCPSearch query: select:<full_tool_name>
|
|
2550
|
+
|
|
2551
|
+
Web search (MANDATORY):
|
|
2552
|
+
1) Load: MCPSearch query select:${MINIMAX_WEB_SEARCH}
|
|
2553
|
+
2) Call: ${MINIMAX_WEB_SEARCH} with:
|
|
2554
|
+
- query: 3-5 keywords; include the current date for time-sensitive queries
|
|
2555
|
+
- If results are weak: change keywords and retry
|
|
2556
|
+
|
|
2557
|
+
Image understanding (MANDATORY):
|
|
2558
|
+
1) Load: MCPSearch query select:${MINIMAX_UNDERSTAND_IMAGE}
|
|
2559
|
+
2) Call: ${MINIMAX_UNDERSTAND_IMAGE} for ANY image you need to interpret.
|
|
2560
|
+
- Only jpeg/png/webp are supported (per tool description).
|
|
2561
|
+
|
|
2562
|
+
Single-page URL retrieval:
|
|
2563
|
+
- Use WebFetch for fetching and extracting from a specific URL.
|
|
2564
|
+
- Do NOT misuse web_search to fetch full page content.
|
|
2565
|
+
</tool_routing>
|
|
2566
|
+
|
|
2567
|
+
${operatingSpec(mode)}
|
|
2568
|
+
|
|
2569
|
+
${subjectiveWorkSpec}
|
|
2570
|
+
|
|
2571
|
+
${verbositySpec}
|
|
2572
|
+
</explicit_guidance>
|
|
2573
|
+
`.trim();
|
|
2574
|
+
var buildMinimaxExcerpt = () => `
|
|
2575
|
+
<tool_info>
|
|
2576
|
+
MiniMax tool routing:
|
|
2577
|
+
- Web search MUST use ${MINIMAX_WEB_SEARCH} (load via MCPSearch first).
|
|
2578
|
+
- Image understanding MUST use ${MINIMAX_UNDERSTAND_IMAGE} (load via MCPSearch first).
|
|
2579
|
+
- Builtin WebSearch does NOT exist (treat as unavailable); always use ${MINIMAX_WEB_SEARCH}.
|
|
2580
|
+
- Use WebFetch only for single-page URL retrieval/extraction.
|
|
2581
|
+
</tool_info>
|
|
2582
|
+
|
|
2583
|
+
${subjectiveWorkSpec}
|
|
2584
|
+
`.trim();
|
|
2585
|
+
var buildMinimaxOverlays = (mode) => ({
|
|
2586
|
+
main: buildMinimaxContract(mode),
|
|
2587
|
+
mcpCli: `
|
|
2588
|
+
${buildMinimaxExcerpt()}
|
|
2589
|
+
|
|
2590
|
+
The MiniMax MCP server is preconfigured. Use MCPSearch to load the MCP tools before calling them.
|
|
2591
|
+
`.trim(),
|
|
2592
|
+
taskAgent: `
|
|
2593
|
+
<explicit_guidance>
|
|
2594
|
+
You are a Task subagent. Stay within requested scope, but be proactive about missing prerequisites.
|
|
2595
|
+
Verify key claims with tools when possible; cite file paths and command outputs.
|
|
2596
|
+
</explicit_guidance>
|
|
2597
|
+
|
|
2598
|
+
${buildMinimaxExcerpt()}
|
|
2599
|
+
|
|
2600
|
+
${verbositySpec}
|
|
2601
|
+
`.trim(),
|
|
2602
|
+
webfetch: `
|
|
2603
|
+
<explicit_guidance>
|
|
2604
|
+
MiniMax routing:
|
|
2605
|
+
- Use WebFetch for fetching and extracting from a specific URL.
|
|
2606
|
+
- Use ${MINIMAX_WEB_SEARCH} for discovery/search, not for fetching full page content.
|
|
2607
|
+
</explicit_guidance>
|
|
2608
|
+
`.trim(),
|
|
2609
|
+
websearch: `
|
|
2610
|
+
<explicit_guidance>
|
|
2611
|
+
MiniMax routing: WebSearch does NOT exist (treat as unavailable).
|
|
2612
|
+
Use MCPSearch + ${MINIMAX_WEB_SEARCH} for all web discovery/search instead.
|
|
2613
|
+
</explicit_guidance>
|
|
2614
|
+
`.trim(),
|
|
2615
|
+
mcpsearch: `
|
|
2616
|
+
<explicit_guidance>
|
|
2617
|
+
MiniMax MCP tools:
|
|
2618
|
+
- Web search: ${MINIMAX_WEB_SEARCH}
|
|
2619
|
+
- Image understanding: ${MINIMAX_UNDERSTAND_IMAGE}
|
|
2620
|
+
|
|
2621
|
+
You MUST load the tool first:
|
|
2622
|
+
- MCPSearch query: select:${MINIMAX_WEB_SEARCH} or select:${MINIMAX_UNDERSTAND_IMAGE}
|
|
2623
|
+
</explicit_guidance>
|
|
2624
|
+
`.trim()
|
|
2625
|
+
});
|
|
2626
|
+
|
|
2627
|
+
// src/core/prompt-pack/overlays.ts
|
|
2628
|
+
var mergeOverlays = (base, extra) => ({
|
|
2629
|
+
...base,
|
|
2630
|
+
...Object.fromEntries(Object.entries(extra).filter(([, value]) => value && value.trim().length > 0))
|
|
2631
|
+
});
|
|
2632
|
+
var buildProviderExcerpt = (provider) => provider === "zai" ? buildZaiExcerpt() : buildMinimaxExcerpt();
|
|
2633
|
+
var buildMaximalOverlays = (provider) => ({
|
|
2634
|
+
explore: `
|
|
2635
|
+
<system_reminder>
|
|
2636
|
+
- You are in Explore mode: go wide before deep.
|
|
2637
|
+
- Use tools early to validate assumptions and reduce guesswork.
|
|
2638
|
+
- Output: Findings (bullets), Risks/unknowns, Next steps.
|
|
2639
|
+
</system_reminder>
|
|
2640
|
+
|
|
2641
|
+
${buildProviderExcerpt(provider)}
|
|
2642
|
+
`.trim(),
|
|
2643
|
+
planEnhanced: `
|
|
2644
|
+
<system_reminder>
|
|
2645
|
+
- Provide 2-3 viable options with tradeoffs.
|
|
2646
|
+
- Include risks, unknowns, and a validation checklist.
|
|
2647
|
+
- Output structure: Overview, Options, Recommendation, Steps, Verification, Risks.
|
|
2648
|
+
</system_reminder>
|
|
2649
|
+
|
|
2650
|
+
${buildProviderExcerpt(provider)}
|
|
2651
|
+
`.trim(),
|
|
2652
|
+
planReminder: `
|
|
2653
|
+
<system_reminder>
|
|
2654
|
+
- In Plan Mode: surface options, tradeoffs, risks, and validation steps explicitly.
|
|
2655
|
+
</system_reminder>
|
|
2656
|
+
`.trim(),
|
|
2657
|
+
planReminderSub: `
|
|
2658
|
+
<system_reminder>
|
|
2659
|
+
- In Plan Mode (subagents): surface options, tradeoffs, risks, and validation steps explicitly.
|
|
2660
|
+
</system_reminder>
|
|
2661
|
+
`.trim(),
|
|
2662
|
+
taskTool: `
|
|
2663
|
+
Maximal mode: use Task to parallelize independent research/debugging and to keep the main thread focused.
|
|
2664
|
+
`.trim(),
|
|
2665
|
+
enterPlan: `
|
|
2666
|
+
Maximal mode: enter Plan Mode early for ambiguous, multi-step, or high-risk tasks.
|
|
2667
|
+
`.trim(),
|
|
2668
|
+
exitPlan: `
|
|
2669
|
+
Maximal mode: return a crisp plan with options, checkpoints, verification, and rollback considerations.
|
|
2670
|
+
`.trim(),
|
|
2671
|
+
skill: `
|
|
2672
|
+
Maximal mode: use Skills when they provide sharper domain knowledge or integrations; otherwise proceed normally.
|
|
2673
|
+
`.trim(),
|
|
2674
|
+
conversationSummary: `
|
|
2675
|
+
<system_reminder>
|
|
2676
|
+
- Capture decisions, constraints, open questions, and next steps.
|
|
2677
|
+
- Preserve critical commands, configs, and file paths.
|
|
2678
|
+
</system_reminder>
|
|
2679
|
+
`.trim(),
|
|
2680
|
+
conversationSummaryExtended: `
|
|
2681
|
+
<system_reminder>
|
|
2682
|
+
- Capture decisions, constraints, open questions, and next steps.
|
|
2683
|
+
- Preserve critical commands, configs, and file paths.
|
|
2684
|
+
</system_reminder>
|
|
2685
|
+
`.trim(),
|
|
2686
|
+
webfetchSummary: `
|
|
2687
|
+
<system_reminder>
|
|
2688
|
+
- Extract key facts, titles, and constraints.
|
|
2689
|
+
- Preserve URLs and important context verbatim.
|
|
2690
|
+
</system_reminder>
|
|
2691
|
+
`.trim()
|
|
2692
|
+
});
|
|
2693
|
+
var buildProviderOverlays = (provider, mode) => {
|
|
2694
|
+
if (provider === "zai") return buildZaiOverlays(mode);
|
|
2695
|
+
return buildMinimaxOverlays(mode);
|
|
2696
|
+
};
|
|
2697
|
+
var resolveOverlays = (provider, mode) => {
|
|
2698
|
+
const base = buildProviderOverlays(provider, mode);
|
|
2699
|
+
const overlays = mode === "maximal" ? mergeOverlays(base, buildMaximalOverlays(provider)) : base;
|
|
2700
|
+
return sanitizeOverlayMap(overlays);
|
|
2701
|
+
};
|
|
2702
|
+
|
|
2703
|
+
// src/core/prompt-pack/targets.ts
|
|
2704
|
+
var OVERLAY_MARKERS = {
|
|
2705
|
+
start: "<!-- cc-mirror:provider-overlay start -->",
|
|
2706
|
+
end: "<!-- cc-mirror:provider-overlay end -->"
|
|
2707
|
+
};
|
|
2708
|
+
var PROMPT_PACK_TARGETS = [
|
|
2709
|
+
{ key: "main", filename: "system-prompt-main-system-prompt.md" },
|
|
2710
|
+
{ key: "mcpCli", filename: "system-prompt-mcp-cli.md" },
|
|
2711
|
+
{ key: "bash", filename: "tool-description-bash.md" },
|
|
2712
|
+
{ key: "webfetch", filename: "tool-description-webfetch.md" },
|
|
2713
|
+
{ key: "websearch", filename: "tool-description-websearch.md" },
|
|
2714
|
+
{ key: "mcpsearch", filename: "tool-description-mcpsearch.md" },
|
|
2715
|
+
{ key: "mcpsearch", filename: "tool-description-mcpsearch-with-available-tools.md" },
|
|
2716
|
+
{ key: "explore", filename: "agent-prompt-explore.md" },
|
|
2717
|
+
{ key: "planEnhanced", filename: "agent-prompt-plan-mode-enhanced.md" },
|
|
2718
|
+
{ key: "taskAgent", filename: "agent-prompt-task-tool.md" },
|
|
2719
|
+
{ key: "planReminder", filename: "system-reminder-plan-mode-is-active.md" },
|
|
2720
|
+
{ key: "planReminderSub", filename: "system-reminder-plan-mode-is-active-for-subagents.md" },
|
|
2721
|
+
{ key: "taskTool", filename: "tool-description-task.md" },
|
|
2722
|
+
{ key: "enterPlan", filename: "tool-description-enterplanmode.md" },
|
|
2723
|
+
{ key: "exitPlan", filename: "tool-description-exitplanmode-v2.md" },
|
|
2724
|
+
{ key: "skill", filename: "tool-description-skill.md" },
|
|
2725
|
+
{ key: "conversationSummary", filename: "agent-prompt-conversation-summarization.md" },
|
|
2726
|
+
{
|
|
2727
|
+
key: "conversationSummaryExtended",
|
|
2728
|
+
filename: "agent-prompt-conversation-summarization-with-additional-instructions.md"
|
|
2729
|
+
},
|
|
2730
|
+
{ key: "webfetchSummary", filename: "agent-prompt-webfetch-summarizer.md" }
|
|
2731
|
+
];
|
|
2732
|
+
|
|
2733
|
+
// src/core/prompt-pack.ts
|
|
2734
|
+
var isPromptPackKey = (value) => value === "zai" || value === "minimax";
|
|
2735
|
+
var insertOverlay = (content, overlay) => {
|
|
2736
|
+
if (!overlay.trim()) return content;
|
|
2737
|
+
const block = `${OVERLAY_MARKERS.start}
|
|
2738
|
+
${overlay.trim()}
|
|
2739
|
+
${OVERLAY_MARKERS.end}`;
|
|
2740
|
+
if (content.includes(OVERLAY_MARKERS.start) && content.includes(OVERLAY_MARKERS.end)) {
|
|
2741
|
+
const start = content.indexOf(OVERLAY_MARKERS.start);
|
|
2742
|
+
const end = content.indexOf(OVERLAY_MARKERS.end, start);
|
|
2743
|
+
const before = content.slice(0, start).trimEnd();
|
|
2744
|
+
const after = content.slice(end + OVERLAY_MARKERS.end.length).trimStart();
|
|
2745
|
+
return `${before}
|
|
2746
|
+
|
|
2747
|
+
${block}
|
|
2748
|
+
|
|
2749
|
+
${after}`.trimEnd() + "\n";
|
|
2750
|
+
}
|
|
2751
|
+
return `${content.trimEnd()}
|
|
2752
|
+
|
|
2753
|
+
${block}
|
|
2754
|
+
`.trimEnd() + "\n";
|
|
2755
|
+
};
|
|
2756
|
+
var updatePromptFile = (filePath, overlay) => {
|
|
2757
|
+
if (!overlay) return false;
|
|
2758
|
+
if (!fs7.existsSync(filePath)) return false;
|
|
2759
|
+
const content = fs7.readFileSync(filePath, "utf8");
|
|
2760
|
+
const updated = insertOverlay(content, overlay);
|
|
2761
|
+
if (updated === content) return false;
|
|
2762
|
+
fs7.writeFileSync(filePath, updated);
|
|
2763
|
+
return true;
|
|
2764
|
+
};
|
|
2765
|
+
var applyOverlays = (systemPromptsDir, overlays) => {
|
|
2766
|
+
const updated = [];
|
|
2767
|
+
for (const target of PROMPT_PACK_TARGETS) {
|
|
2768
|
+
const filePath = path9.join(systemPromptsDir, target.filename);
|
|
2769
|
+
const overlay = overlays[target.key];
|
|
2770
|
+
if (updatePromptFile(filePath, overlay)) {
|
|
2771
|
+
updated.push(target.filename);
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
return updated;
|
|
2775
|
+
};
|
|
2776
|
+
var applyPromptPack = (tweakDir, providerKey, mode = "minimal") => {
|
|
2777
|
+
if (!isPromptPackKey(providerKey)) {
|
|
2778
|
+
return { changed: false, updated: [], mode };
|
|
2779
|
+
}
|
|
2780
|
+
const overlays = resolveOverlays(providerKey, mode);
|
|
2781
|
+
const systemPromptsDir = path9.join(tweakDir, "system-prompts");
|
|
2782
|
+
const updated = applyOverlays(systemPromptsDir, overlays);
|
|
2783
|
+
return { changed: updated.length > 0, updated, mode };
|
|
2784
|
+
};
|
|
2785
|
+
|
|
2786
|
+
// src/core/variant-builder/steps/TweakccStep.ts
|
|
2787
|
+
var TweakccStep = class {
|
|
2788
|
+
name = "Tweakcc";
|
|
2789
|
+
execute(ctx) {
|
|
2790
|
+
const { params, paths, prefs, state } = ctx;
|
|
2791
|
+
if (params.noTweak) {
|
|
2792
|
+
return;
|
|
2793
|
+
}
|
|
2794
|
+
ctx.report("Running tweakcc patches...");
|
|
2795
|
+
state.tweakResult = runTweakcc(paths.tweakDir, state.binaryPath, prefs.commandStdio);
|
|
2796
|
+
if (state.tweakResult.status !== 0) {
|
|
2797
|
+
const output = `${state.tweakResult.stderr ?? ""}
|
|
2798
|
+
${state.tweakResult.stdout ?? ""}`.trim();
|
|
2799
|
+
throw new Error(formatTweakccFailure(output));
|
|
2800
|
+
}
|
|
2801
|
+
if (prefs.promptPackEnabled) {
|
|
2802
|
+
ctx.report(`Applying prompt pack (${prefs.promptPackModePreference})...`);
|
|
2803
|
+
const packResult = applyPromptPack(paths.tweakDir, params.providerKey, prefs.promptPackModePreference);
|
|
2804
|
+
if (packResult.changed) {
|
|
2805
|
+
state.notes.push(`Prompt pack applied (${packResult.mode}, ${packResult.updated.join(", ")})`);
|
|
2806
|
+
ctx.report("Re-applying tweakcc...");
|
|
2807
|
+
const reapply = runTweakcc(paths.tweakDir, state.binaryPath, prefs.commandStdio);
|
|
2808
|
+
state.tweakResult = reapply;
|
|
2809
|
+
if (reapply.status !== 0) {
|
|
2810
|
+
const output = `${reapply.stderr ?? ""}
|
|
2811
|
+
${reapply.stdout ?? ""}`.trim();
|
|
2812
|
+
throw new Error(formatTweakccFailure(output));
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
async executeAsync(ctx) {
|
|
2818
|
+
const { params, paths, prefs, state } = ctx;
|
|
2819
|
+
if (params.noTweak) {
|
|
2820
|
+
return;
|
|
2821
|
+
}
|
|
2822
|
+
await ctx.report("Running tweakcc patches...");
|
|
2823
|
+
state.tweakResult = await runTweakccAsync(paths.tweakDir, state.binaryPath, prefs.commandStdio);
|
|
2824
|
+
if (state.tweakResult.status !== 0) {
|
|
2825
|
+
const output = `${state.tweakResult.stderr ?? ""}
|
|
2826
|
+
${state.tweakResult.stdout ?? ""}`.trim();
|
|
2827
|
+
throw new Error(formatTweakccFailure(output));
|
|
2828
|
+
}
|
|
2829
|
+
if (prefs.promptPackEnabled) {
|
|
2830
|
+
await ctx.report(`Applying prompt pack (${prefs.promptPackModePreference})...`);
|
|
2831
|
+
const packResult = applyPromptPack(paths.tweakDir, params.providerKey, prefs.promptPackModePreference);
|
|
2832
|
+
if (packResult.changed) {
|
|
2833
|
+
state.notes.push(`Prompt pack applied (${packResult.mode}, ${packResult.updated.join(", ")})`);
|
|
2834
|
+
await ctx.report("Re-applying tweakcc...");
|
|
2835
|
+
const reapply = await runTweakccAsync(paths.tweakDir, state.binaryPath, prefs.commandStdio);
|
|
2836
|
+
state.tweakResult = reapply;
|
|
2837
|
+
if (reapply.status !== 0) {
|
|
2838
|
+
const output = `${reapply.stderr ?? ""}
|
|
2839
|
+
${reapply.stdout ?? ""}`.trim();
|
|
2840
|
+
throw new Error(formatTweakccFailure(output));
|
|
2841
|
+
}
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
};
|
|
2846
|
+
|
|
2847
|
+
// src/core/wrapper.ts
|
|
2848
|
+
import fs8 from "node:fs";
|
|
2849
|
+
import path10 from "node:path";
|
|
2850
|
+
var writeWrapper = (wrapperPath, configDir, binaryPath, runtime = "node") => {
|
|
2851
|
+
const tweakDir = path10.join(path10.dirname(configDir), "tweakcc");
|
|
2852
|
+
const execLine = runtime === "node" ? `exec node "${binaryPath}" "$@"` : `exec "${binaryPath}" "$@"`;
|
|
2853
|
+
const envLoader = [
|
|
2854
|
+
"if command -v node >/dev/null 2>&1; then",
|
|
2855
|
+
' __cc_mirror_env_file="$(mktemp)"',
|
|
2856
|
+
` node - <<'NODE' > "$__cc_mirror_env_file" || true`,
|
|
2857
|
+
"const fs = require('fs');",
|
|
2858
|
+
"const path = require('path');",
|
|
2859
|
+
"const dir = process.env.CLAUDE_CONFIG_DIR;",
|
|
2860
|
+
"if (!dir) process.exit(0);",
|
|
2861
|
+
"const file = path.join(dir, 'settings.json');",
|
|
2862
|
+
`const escape = (value) => "'" + String(value).replace(/'/g, "'\\"'\\"'") + "'";`,
|
|
2863
|
+
"try {",
|
|
2864
|
+
" if (fs.existsSync(file)) {",
|
|
2865
|
+
" const data = JSON.parse(fs.readFileSync(file, 'utf8'));",
|
|
2866
|
+
" const env = data && typeof data === 'object' ? data.env : null;",
|
|
2867
|
+
" if (env && typeof env === 'object') {",
|
|
2868
|
+
" for (const [key, value] of Object.entries(env)) {",
|
|
2869
|
+
" if (!key) continue;",
|
|
2870
|
+
" process.stdout.write(`export ${key}=${escape(value)}\\n`);",
|
|
2871
|
+
" }",
|
|
2872
|
+
" }",
|
|
2873
|
+
" }",
|
|
2874
|
+
"} catch {",
|
|
2875
|
+
" // ignore malformed settings",
|
|
2876
|
+
"}",
|
|
2877
|
+
"NODE",
|
|
2878
|
+
' if [[ -s "$__cc_mirror_env_file" ]]; then',
|
|
2879
|
+
" # shellcheck disable=SC1090",
|
|
2880
|
+
' source "$__cc_mirror_env_file"',
|
|
2881
|
+
" fi",
|
|
2882
|
+
' rm -f "$__cc_mirror_env_file" || true',
|
|
2883
|
+
"fi"
|
|
2884
|
+
];
|
|
2885
|
+
const C = {
|
|
2886
|
+
reset: "\x1B[0m",
|
|
2887
|
+
// Zai: Gold/Amber gradient
|
|
2888
|
+
zaiPrimary: "\x1B[38;5;220m",
|
|
2889
|
+
// Gold
|
|
2890
|
+
zaiSecondary: "\x1B[38;5;214m",
|
|
2891
|
+
// Orange-gold
|
|
2892
|
+
zaiAccent: "\x1B[38;5;208m",
|
|
2893
|
+
// Dark orange
|
|
2894
|
+
zaiDim: "\x1B[38;5;172m",
|
|
2895
|
+
// Muted gold
|
|
2896
|
+
// MiniMax: Coral/Red/Orange gradient (from brand image)
|
|
2897
|
+
mmPrimary: "\x1B[38;5;203m",
|
|
2898
|
+
// Coral/salmon red
|
|
2899
|
+
mmSecondary: "\x1B[38;5;209m",
|
|
2900
|
+
// Light coral/orange
|
|
2901
|
+
mmAccent: "\x1B[38;5;208m",
|
|
2902
|
+
// Orange
|
|
2903
|
+
mmDim: "\x1B[38;5;167m",
|
|
2904
|
+
// Muted coral/dark red
|
|
2905
|
+
// OpenRouter: Cyan/Teal gradient
|
|
2906
|
+
orPrimary: "\x1B[38;5;43m",
|
|
2907
|
+
// Teal
|
|
2908
|
+
orSecondary: "\x1B[38;5;49m",
|
|
2909
|
+
// Bright teal
|
|
2910
|
+
orAccent: "\x1B[38;5;37m",
|
|
2911
|
+
// Deep cyan
|
|
2912
|
+
orDim: "\x1B[38;5;30m",
|
|
2913
|
+
// Muted teal
|
|
2914
|
+
// CCRouter: Sky blue gradient
|
|
2915
|
+
ccrPrimary: "\x1B[38;5;39m",
|
|
2916
|
+
// Sky blue
|
|
2917
|
+
ccrSecondary: "\x1B[38;5;45m",
|
|
2918
|
+
// Bright cyan
|
|
2919
|
+
ccrAccent: "\x1B[38;5;33m",
|
|
2920
|
+
// Deep blue
|
|
2921
|
+
ccrDim: "\x1B[38;5;31m",
|
|
2922
|
+
// Muted blue
|
|
2923
|
+
// Default: White/Gray
|
|
2924
|
+
defPrimary: "\x1B[38;5;255m",
|
|
2925
|
+
// White
|
|
2926
|
+
defDim: "\x1B[38;5;245m"
|
|
2927
|
+
// Gray
|
|
2928
|
+
};
|
|
2929
|
+
const splash = [
|
|
2930
|
+
'if [[ "${CC_MIRROR_SPLASH:-0}" != "0" ]] && [[ -t 1 ]]; then',
|
|
2931
|
+
' if [[ "$*" != *"--output-format"* ]]; then',
|
|
2932
|
+
' __cc_label="${CC_MIRROR_PROVIDER_LABEL:-cc-mirror}"',
|
|
2933
|
+
' __cc_style="${CC_MIRROR_SPLASH_STYLE:-default}"',
|
|
2934
|
+
' __cc_show_label="1"',
|
|
2935
|
+
' printf "\\n"',
|
|
2936
|
+
' case "$__cc_style" in',
|
|
2937
|
+
" zai)",
|
|
2938
|
+
" cat <<'CCMZAI'",
|
|
2939
|
+
"",
|
|
2940
|
+
`${C.zaiPrimary} \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557${C.reset}`,
|
|
2941
|
+
`${C.zaiPrimary} \u255A\u2550\u2550\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551${C.reset}`,
|
|
2942
|
+
`${C.zaiSecondary} \u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551${C.reset}`,
|
|
2943
|
+
`${C.zaiSecondary} \u2588\u2588\u2588\u2554\u255D ${C.zaiAccent}\u2588\u2588\u2557${C.zaiSecondary} \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551${C.reset}`,
|
|
2944
|
+
`${C.zaiAccent} \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u255A\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551${C.reset}`,
|
|
2945
|
+
`${C.zaiAccent} \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D${C.reset}`,
|
|
2946
|
+
"",
|
|
2947
|
+
`${C.zaiDim} \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${C.zaiPrimary}\u25C6${C.zaiDim}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${C.reset}`,
|
|
2948
|
+
`${C.zaiSecondary} GLM Coding Plan${C.reset}`,
|
|
2949
|
+
"",
|
|
2950
|
+
"CCMZAI",
|
|
2951
|
+
' __cc_show_label="0"',
|
|
2952
|
+
" ;;",
|
|
2953
|
+
" minimax)",
|
|
2954
|
+
" cat <<'CCMMIN'",
|
|
2955
|
+
"",
|
|
2956
|
+
`${C.mmPrimary} \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557${C.reset}`,
|
|
2957
|
+
`${C.mmPrimary} \u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u255A\u2588\u2588\u2557\u2588\u2588\u2554\u255D${C.reset}`,
|
|
2958
|
+
`${C.mmSecondary} \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2554\u255D${C.reset}`,
|
|
2959
|
+
`${C.mmSecondary} \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2557${C.reset}`,
|
|
2960
|
+
`${C.mmAccent} \u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u255D \u2588\u2588\u2557${C.reset}`,
|
|
2961
|
+
`${C.mmAccent} \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D${C.reset}`,
|
|
2962
|
+
"",
|
|
2963
|
+
`${C.mmDim} \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${C.mmPrimary}\u25C6${C.mmDim}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${C.reset}`,
|
|
2964
|
+
`${C.mmSecondary} MiniMax-M2.1 ${C.mmDim}\u2501${C.mmSecondary} AGI for All${C.reset}`,
|
|
2965
|
+
"",
|
|
2966
|
+
"CCMMIN",
|
|
2967
|
+
' __cc_show_label="0"',
|
|
2968
|
+
" ;;",
|
|
2969
|
+
" openrouter)",
|
|
2970
|
+
" cat <<'CCMORT'",
|
|
2971
|
+
"",
|
|
2972
|
+
`${C.orPrimary} \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557${C.reset}`,
|
|
2973
|
+
`${C.orPrimary} \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551${C.reset}`,
|
|
2974
|
+
`${C.orSecondary} \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551${C.reset}`,
|
|
2975
|
+
`${C.orSecondary} \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551${C.reset}`,
|
|
2976
|
+
`${C.orAccent} \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551${C.reset}`,
|
|
2977
|
+
`${C.orAccent} \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D${C.reset}`,
|
|
2978
|
+
`${C.orPrimary} \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557${C.reset}`,
|
|
2979
|
+
`${C.orPrimary} \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557${C.reset}`,
|
|
2980
|
+
`${C.orSecondary} \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D${C.reset}`,
|
|
2981
|
+
`${C.orSecondary} \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557${C.reset}`,
|
|
2982
|
+
`${C.orAccent} \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551${C.reset}`,
|
|
2983
|
+
`${C.orAccent} \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D${C.reset}`,
|
|
2984
|
+
"",
|
|
2985
|
+
`${C.orDim} \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${C.orPrimary}\u25C6${C.orDim}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${C.reset}`,
|
|
2986
|
+
`${C.orSecondary} One API ${C.orDim}\u2501${C.orSecondary} Any Model${C.reset}`,
|
|
2987
|
+
"",
|
|
2988
|
+
"CCMORT",
|
|
2989
|
+
' __cc_show_label="0"',
|
|
2990
|
+
" ;;",
|
|
2991
|
+
" ccrouter)",
|
|
2992
|
+
" cat <<'CCMCCR'",
|
|
2993
|
+
"",
|
|
2994
|
+
`${C.ccrPrimary} \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557${C.reset}`,
|
|
2995
|
+
`${C.ccrPrimary} \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557${C.reset}`,
|
|
2996
|
+
`${C.ccrSecondary} \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D${C.reset}`,
|
|
2997
|
+
`${C.ccrSecondary} \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557${C.reset}`,
|
|
2998
|
+
`${C.ccrAccent} \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551${C.reset}`,
|
|
2999
|
+
`${C.ccrAccent} \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D${C.reset}`,
|
|
3000
|
+
"",
|
|
3001
|
+
`${C.ccrDim} \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${C.ccrPrimary}\u25C6${C.ccrDim}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${C.reset}`,
|
|
3002
|
+
`${C.ccrSecondary} Claude Code Router ${C.ccrDim}\u2501${C.ccrSecondary} Any Model${C.reset}`,
|
|
3003
|
+
"",
|
|
3004
|
+
"CCMCCR",
|
|
3005
|
+
' __cc_show_label="0"',
|
|
3006
|
+
" ;;",
|
|
3007
|
+
" *)",
|
|
3008
|
+
" cat <<'CCMGEN'",
|
|
3009
|
+
"",
|
|
3010
|
+
`${C.defPrimary} \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ${C.defDim}\u2501\u2501 M I R R O R${C.reset}`,
|
|
3011
|
+
`${C.defPrimary} \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D${C.reset}`,
|
|
3012
|
+
`${C.defPrimary} \u2588\u2588\u2551 \u2588\u2588\u2551 ${C.defDim}Claude Code Variants${C.reset}`,
|
|
3013
|
+
`${C.defPrimary} \u2588\u2588\u2551 \u2588\u2588\u2551 ${C.defDim}Custom Providers${C.reset}`,
|
|
3014
|
+
`${C.defPrimary} \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557${C.reset}`,
|
|
3015
|
+
`${C.defPrimary} \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D${C.reset}`,
|
|
3016
|
+
"",
|
|
3017
|
+
"CCMGEN",
|
|
3018
|
+
" ;;",
|
|
3019
|
+
" esac",
|
|
3020
|
+
' if [[ "$__cc_show_label" == "1" ]]; then',
|
|
3021
|
+
' printf " %s\\n\\n" "$__cc_label"',
|
|
3022
|
+
" else",
|
|
3023
|
+
' printf "\\n"',
|
|
3024
|
+
" fi",
|
|
3025
|
+
" fi",
|
|
3026
|
+
"fi"
|
|
3027
|
+
];
|
|
3028
|
+
const content = [
|
|
3029
|
+
"#!/usr/bin/env bash",
|
|
3030
|
+
"set -euo pipefail",
|
|
3031
|
+
`export CLAUDE_CONFIG_DIR="${configDir}"`,
|
|
3032
|
+
`export TWEAKCC_CONFIG_DIR="${tweakDir}"`,
|
|
3033
|
+
...envLoader,
|
|
3034
|
+
'if [[ "${CC_MIRROR_UNSET_AUTH_TOKEN:-0}" != "0" ]]; then',
|
|
3035
|
+
" unset ANTHROPIC_AUTH_TOKEN",
|
|
3036
|
+
"fi",
|
|
3037
|
+
...splash,
|
|
3038
|
+
execLine,
|
|
3039
|
+
""
|
|
3040
|
+
].join("\n");
|
|
3041
|
+
fs8.writeFileSync(wrapperPath, content, { mode: 493 });
|
|
3042
|
+
};
|
|
3043
|
+
|
|
3044
|
+
// src/core/variant-builder/steps/WrapperStep.ts
|
|
3045
|
+
var WrapperStep = class {
|
|
3046
|
+
name = "Wrapper";
|
|
3047
|
+
execute(ctx) {
|
|
3048
|
+
ctx.report("Writing CLI wrapper...");
|
|
3049
|
+
writeWrapper(ctx.paths.wrapperPath, ctx.paths.configDir, ctx.state.binaryPath, "node");
|
|
3050
|
+
}
|
|
3051
|
+
async executeAsync(ctx) {
|
|
3052
|
+
await ctx.report("Writing CLI wrapper...");
|
|
3053
|
+
writeWrapper(ctx.paths.wrapperPath, ctx.paths.configDir, ctx.state.binaryPath, "node");
|
|
3054
|
+
}
|
|
3055
|
+
};
|
|
3056
|
+
|
|
3057
|
+
// src/core/shell-env.ts
|
|
3058
|
+
import fs9 from "node:fs";
|
|
3059
|
+
import os4 from "node:os";
|
|
3060
|
+
import path11 from "node:path";
|
|
3061
|
+
var SETTINGS_FILE2 = "settings.json";
|
|
3062
|
+
var BLOCK_START = "# cc-mirror: Z.ai env start";
|
|
3063
|
+
var BLOCK_END = "# cc-mirror: Z.ai env end";
|
|
3064
|
+
var PLACEHOLDER_KEY2 = "<API_KEY>";
|
|
3065
|
+
var normalizeApiKey = (value) => {
|
|
3066
|
+
if (!value) return null;
|
|
3067
|
+
const trimmed = value.trim();
|
|
3068
|
+
if (!trimmed || trimmed === PLACEHOLDER_KEY2) return null;
|
|
3069
|
+
return trimmed;
|
|
3070
|
+
};
|
|
3071
|
+
var resolveShellProfile = () => {
|
|
3072
|
+
const home = os4.homedir();
|
|
3073
|
+
const shell = process.env.SHELL || "";
|
|
3074
|
+
const name = path11.basename(shell);
|
|
3075
|
+
if (name === "zsh") {
|
|
3076
|
+
return path11.join(home, ".zshrc");
|
|
3077
|
+
}
|
|
3078
|
+
if (name === "bash") {
|
|
3079
|
+
const bashrc = path11.join(home, ".bashrc");
|
|
3080
|
+
if (fs9.existsSync(bashrc)) return bashrc;
|
|
3081
|
+
return path11.join(home, ".bash_profile");
|
|
3082
|
+
}
|
|
3083
|
+
return null;
|
|
3084
|
+
};
|
|
3085
|
+
var readSettingsApiKey2 = (configDir) => {
|
|
3086
|
+
const settingsPath = path11.join(configDir, SETTINGS_FILE2);
|
|
3087
|
+
if (!fs9.existsSync(settingsPath)) return null;
|
|
3088
|
+
const settings = readJson(settingsPath);
|
|
3089
|
+
const key = settings?.env?.ANTHROPIC_API_KEY;
|
|
3090
|
+
if (typeof key !== "string") return null;
|
|
3091
|
+
return normalizeApiKey(key);
|
|
3092
|
+
};
|
|
3093
|
+
var renderBlock = (apiKey) => `${BLOCK_START}
|
|
3094
|
+
export Z_AI_API_KEY="${apiKey}"
|
|
3095
|
+
${BLOCK_END}
|
|
3096
|
+
`;
|
|
3097
|
+
var upsertBlock = (content, block) => {
|
|
3098
|
+
if (content.includes(BLOCK_START) && content.includes(BLOCK_END)) {
|
|
3099
|
+
const start = content.indexOf(BLOCK_START);
|
|
3100
|
+
const end = content.indexOf(BLOCK_END, start);
|
|
3101
|
+
const before = content.slice(0, start).trimEnd();
|
|
3102
|
+
const after = content.slice(end + BLOCK_END.length).trimStart();
|
|
3103
|
+
return `${before}
|
|
3104
|
+
|
|
3105
|
+
${block}
|
|
3106
|
+
${after}`.trimEnd() + "\n";
|
|
3107
|
+
}
|
|
3108
|
+
return `${content.trimEnd()}
|
|
3109
|
+
|
|
3110
|
+
${block}`.trimEnd() + "\n";
|
|
3111
|
+
};
|
|
3112
|
+
var hasZaiKeyInProfile = (content) => {
|
|
3113
|
+
const lines = content.split("\n");
|
|
3114
|
+
for (const line of lines) {
|
|
3115
|
+
const trimmed = line.trim();
|
|
3116
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
3117
|
+
const exportStripped = trimmed.startsWith("export ") ? trimmed.slice(7).trim() : trimmed;
|
|
3118
|
+
if (!exportStripped.startsWith("Z_AI_API_KEY")) continue;
|
|
3119
|
+
const equalsIndex = exportStripped.indexOf("=");
|
|
3120
|
+
if (equalsIndex === -1) continue;
|
|
3121
|
+
let value = exportStripped.slice(equalsIndex + 1).trim();
|
|
3122
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
3123
|
+
value = value.slice(1, -1);
|
|
3124
|
+
}
|
|
3125
|
+
if (normalizeApiKey(value)) return true;
|
|
3126
|
+
}
|
|
3127
|
+
return false;
|
|
3128
|
+
};
|
|
3129
|
+
var ensureZaiShellEnv = (opts) => {
|
|
3130
|
+
const apiKey = normalizeApiKey(opts.apiKey) || readSettingsApiKey2(opts.configDir);
|
|
3131
|
+
if (!apiKey) {
|
|
3132
|
+
return { status: "skipped", message: "Z_AI_API_KEY not set (missing API key)" };
|
|
3133
|
+
}
|
|
3134
|
+
const envKey = normalizeApiKey(process.env.Z_AI_API_KEY);
|
|
3135
|
+
if (envKey) {
|
|
3136
|
+
return { status: "skipped", message: "Z_AI_API_KEY already set in environment" };
|
|
3137
|
+
}
|
|
3138
|
+
const profile = opts.profilePath ?? resolveShellProfile();
|
|
3139
|
+
if (!profile) {
|
|
3140
|
+
return { status: "failed", message: "Unsupported shell; set Z_AI_API_KEY manually" };
|
|
3141
|
+
}
|
|
3142
|
+
const existing = fs9.existsSync(profile) ? fs9.readFileSync(profile, "utf8") : "";
|
|
3143
|
+
if (hasZaiKeyInProfile(existing)) {
|
|
3144
|
+
return { status: "skipped", message: "Z_AI_API_KEY already set in shell profile", path: profile };
|
|
3145
|
+
}
|
|
3146
|
+
const next = upsertBlock(existing, renderBlock(apiKey));
|
|
3147
|
+
if (next === existing) {
|
|
3148
|
+
return { status: "skipped", message: "Shell profile already up to date", path: profile };
|
|
3149
|
+
}
|
|
3150
|
+
fs9.writeFileSync(profile, next);
|
|
3151
|
+
return { status: "updated", path: profile, message: `Run: source ${profile}` };
|
|
3152
|
+
};
|
|
3153
|
+
|
|
3154
|
+
// src/core/variant-builder/steps/ShellEnvStep.ts
|
|
3155
|
+
var ShellEnvStep = class {
|
|
3156
|
+
name = "ShellEnv";
|
|
3157
|
+
execute(ctx) {
|
|
3158
|
+
this.setupShellEnv(ctx);
|
|
3159
|
+
}
|
|
3160
|
+
async executeAsync(ctx) {
|
|
3161
|
+
if (ctx.prefs.shellEnvEnabled && ctx.params.providerKey === "zai") {
|
|
3162
|
+
await ctx.report("Configuring shell environment...");
|
|
3163
|
+
}
|
|
3164
|
+
this.setupShellEnv(ctx);
|
|
3165
|
+
}
|
|
3166
|
+
setupShellEnv(ctx) {
|
|
3167
|
+
const { params, paths, prefs, state } = ctx;
|
|
3168
|
+
if (prefs.shellEnvEnabled && params.providerKey === "zai") {
|
|
3169
|
+
ctx.report("Configuring shell environment...");
|
|
3170
|
+
const shellResult = ensureZaiShellEnv({
|
|
3171
|
+
apiKey: state.resolvedApiKey ?? null,
|
|
3172
|
+
configDir: paths.configDir
|
|
3173
|
+
});
|
|
3174
|
+
if (shellResult.status === "updated") {
|
|
3175
|
+
const suffix = shellResult.message ? ` (${shellResult.message})` : "";
|
|
3176
|
+
state.notes.push(`Z_AI_API_KEY written to ${shellResult.path}${suffix}`);
|
|
3177
|
+
} else if (shellResult.status === "failed") {
|
|
3178
|
+
state.notes.push(`Z_AI_API_KEY not written: ${shellResult.message || "unknown error"}`);
|
|
3179
|
+
} else if (shellResult.message) {
|
|
3180
|
+
state.notes.push(`Z_AI_API_KEY: ${shellResult.message}`);
|
|
3181
|
+
}
|
|
3182
|
+
} else if (params.providerKey === "zai") {
|
|
3183
|
+
state.notes.push("Z_AI_API_KEY not written to shell profile. Set it manually in your shell rc file.");
|
|
3184
|
+
}
|
|
3185
|
+
}
|
|
3186
|
+
};
|
|
3187
|
+
|
|
3188
|
+
// src/core/variant-builder/steps/SkillInstallStep.ts
|
|
3189
|
+
import path13 from "node:path";
|
|
3190
|
+
|
|
3191
|
+
// src/core/skills.ts
|
|
3192
|
+
import fs10 from "node:fs";
|
|
3193
|
+
import os5 from "node:os";
|
|
3194
|
+
import path12 from "node:path";
|
|
3195
|
+
import { spawn as spawn3, spawnSync as spawnSync4 } from "node:child_process";
|
|
3196
|
+
var DEV_BROWSER_REPO = "https://github.com/SawyerHood/dev-browser.git";
|
|
3197
|
+
var DEV_BROWSER_ARCHIVE = "https://github.com/SawyerHood/dev-browser/archive/refs/heads/main.tar.gz";
|
|
3198
|
+
var SKILL_SUBDIR = path12.join("skills", "dev-browser");
|
|
3199
|
+
var MANAGED_MARKER = ".cc-mirror-managed";
|
|
3200
|
+
var ensureDir2 = (dir) => {
|
|
3201
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
3202
|
+
};
|
|
3203
|
+
var copyDir = (source, target) => {
|
|
3204
|
+
fs10.cpSync(source, target, { recursive: true });
|
|
3205
|
+
};
|
|
3206
|
+
var resolveSkillSourceDir = (repoDir) => {
|
|
3207
|
+
const direct = path12.join(repoDir, SKILL_SUBDIR);
|
|
3208
|
+
if (fs10.existsSync(direct)) return direct;
|
|
3209
|
+
const nested = fs10.readdirSync(repoDir).find((entry) => entry.startsWith("dev-browser-"));
|
|
3210
|
+
if (nested) {
|
|
3211
|
+
const candidate = path12.join(repoDir, nested, SKILL_SUBDIR);
|
|
3212
|
+
if (fs10.existsSync(candidate)) return candidate;
|
|
3213
|
+
}
|
|
3214
|
+
return null;
|
|
3215
|
+
};
|
|
3216
|
+
var cloneRepo = (targetDir) => {
|
|
3217
|
+
if (!commandExists("git")) return { ok: false, message: "git not found" };
|
|
3218
|
+
const result = spawnSync4("git", ["clone", "--depth", "1", DEV_BROWSER_REPO, targetDir], {
|
|
3219
|
+
encoding: "utf8"
|
|
3220
|
+
});
|
|
3221
|
+
if (result.status === 0) return { ok: true };
|
|
3222
|
+
return { ok: false, message: result.stderr?.trim() || result.stdout?.trim() || "git clone failed" };
|
|
3223
|
+
};
|
|
3224
|
+
var downloadArchive = (targetDir) => {
|
|
3225
|
+
if (!commandExists("curl") || !commandExists("tar")) {
|
|
3226
|
+
return { ok: false, message: "curl or tar not found" };
|
|
3227
|
+
}
|
|
3228
|
+
const archivePath = path12.join(targetDir, "dev-browser.tar.gz");
|
|
3229
|
+
const curlResult = spawnSync4("curl", ["-L", "-o", archivePath, DEV_BROWSER_ARCHIVE], { encoding: "utf8" });
|
|
3230
|
+
if (curlResult.status !== 0) {
|
|
3231
|
+
return { ok: false, message: curlResult.stderr?.trim() || "curl failed" };
|
|
3232
|
+
}
|
|
3233
|
+
const tarResult = spawnSync4("tar", ["-xzf", archivePath, "-C", targetDir], { encoding: "utf8" });
|
|
3234
|
+
if (tarResult.status !== 0) {
|
|
3235
|
+
return { ok: false, message: tarResult.stderr?.trim() || "tar extract failed" };
|
|
3236
|
+
}
|
|
3237
|
+
return { ok: true };
|
|
3238
|
+
};
|
|
3239
|
+
var ensureDevBrowserSkill = (opts) => {
|
|
3240
|
+
if (!opts.install) {
|
|
3241
|
+
return { status: "skipped", message: "skill install disabled" };
|
|
3242
|
+
}
|
|
3243
|
+
const skillRoot = opts.targetDir || path12.join(os5.homedir(), ".claude", "skills");
|
|
3244
|
+
const targetDir = path12.join(skillRoot, "dev-browser");
|
|
3245
|
+
const markerPath = path12.join(targetDir, MANAGED_MARKER);
|
|
3246
|
+
const exists = fs10.existsSync(targetDir);
|
|
3247
|
+
const managed = exists && fs10.existsSync(markerPath);
|
|
3248
|
+
if (exists && !managed && !opts.update) {
|
|
3249
|
+
return { status: "skipped", message: "existing skill is user-managed", path: targetDir };
|
|
3250
|
+
}
|
|
3251
|
+
ensureDir2(skillRoot);
|
|
3252
|
+
const tmpDir = fs10.mkdtempSync(path12.join(os5.tmpdir(), "cc-mirror-skill-"));
|
|
3253
|
+
try {
|
|
3254
|
+
let fetchResult = cloneRepo(tmpDir);
|
|
3255
|
+
if (!fetchResult.ok) {
|
|
3256
|
+
fetchResult = downloadArchive(tmpDir);
|
|
3257
|
+
}
|
|
3258
|
+
if (!fetchResult.ok) {
|
|
3259
|
+
return { status: "failed", message: fetchResult.message || "skill fetch failed" };
|
|
3260
|
+
}
|
|
3261
|
+
const sourceDir = resolveSkillSourceDir(tmpDir);
|
|
3262
|
+
if (!sourceDir) {
|
|
3263
|
+
return { status: "failed", message: "skill source not found after download" };
|
|
3264
|
+
}
|
|
3265
|
+
if (exists) {
|
|
3266
|
+
fs10.rmSync(targetDir, { recursive: true, force: true });
|
|
3267
|
+
}
|
|
3268
|
+
copyDir(sourceDir, targetDir);
|
|
3269
|
+
fs10.writeFileSync(
|
|
3270
|
+
markerPath,
|
|
3271
|
+
JSON.stringify({ managedBy: "cc-mirror", updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
|
|
3272
|
+
);
|
|
3273
|
+
return { status: exists ? "updated" : "installed", path: targetDir };
|
|
3274
|
+
} catch (error) {
|
|
3275
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3276
|
+
return { status: "failed", message };
|
|
3277
|
+
} finally {
|
|
3278
|
+
fs10.rmSync(tmpDir, { recursive: true, force: true });
|
|
3279
|
+
}
|
|
3280
|
+
};
|
|
3281
|
+
var spawnAsync = (cmd, args) => {
|
|
3282
|
+
return new Promise((resolve) => {
|
|
3283
|
+
const child = spawn3(cmd, args, { stdio: "pipe" });
|
|
3284
|
+
let stderr = "";
|
|
3285
|
+
let stdout = "";
|
|
3286
|
+
child.stdout?.on("data", (d) => {
|
|
3287
|
+
stdout += d.toString();
|
|
3288
|
+
});
|
|
3289
|
+
child.stderr?.on("data", (d) => {
|
|
3290
|
+
stderr += d.toString();
|
|
3291
|
+
});
|
|
3292
|
+
child.on("close", (code) => {
|
|
3293
|
+
if (code === 0) resolve({ ok: true });
|
|
3294
|
+
else resolve({ ok: false, message: stderr.trim() || stdout.trim() || `${cmd} failed` });
|
|
3295
|
+
});
|
|
3296
|
+
child.on("error", (err) => resolve({ ok: false, message: err.message }));
|
|
3297
|
+
});
|
|
3298
|
+
};
|
|
3299
|
+
var cloneRepoAsync = async (targetDir) => {
|
|
3300
|
+
if (!commandExists("git")) return { ok: false, message: "git not found" };
|
|
3301
|
+
return spawnAsync("git", ["clone", "--depth", "1", DEV_BROWSER_REPO, targetDir]);
|
|
3302
|
+
};
|
|
3303
|
+
var downloadArchiveAsync = async (targetDir) => {
|
|
3304
|
+
if (!commandExists("curl") || !commandExists("tar")) {
|
|
3305
|
+
return { ok: false, message: "curl or tar not found" };
|
|
3306
|
+
}
|
|
3307
|
+
const archivePath = path12.join(targetDir, "dev-browser.tar.gz");
|
|
3308
|
+
const curlResult = await spawnAsync("curl", ["-L", "-o", archivePath, DEV_BROWSER_ARCHIVE]);
|
|
3309
|
+
if (!curlResult.ok) return curlResult;
|
|
3310
|
+
return spawnAsync("tar", ["-xzf", archivePath, "-C", targetDir]);
|
|
3311
|
+
};
|
|
3312
|
+
var ensureDevBrowserSkillAsync = async (opts) => {
|
|
3313
|
+
if (!opts.install) {
|
|
3314
|
+
return { status: "skipped", message: "skill install disabled" };
|
|
3315
|
+
}
|
|
3316
|
+
const skillRoot = opts.targetDir || path12.join(os5.homedir(), ".claude", "skills");
|
|
3317
|
+
const targetDir = path12.join(skillRoot, "dev-browser");
|
|
3318
|
+
const markerPath = path12.join(targetDir, MANAGED_MARKER);
|
|
3319
|
+
const exists = fs10.existsSync(targetDir);
|
|
3320
|
+
const managed = exists && fs10.existsSync(markerPath);
|
|
3321
|
+
if (exists && !managed && !opts.update) {
|
|
3322
|
+
return { status: "skipped", message: "existing skill is user-managed", path: targetDir };
|
|
3323
|
+
}
|
|
3324
|
+
ensureDir2(skillRoot);
|
|
3325
|
+
const tmpDir = fs10.mkdtempSync(path12.join(os5.tmpdir(), "cc-mirror-skill-"));
|
|
3326
|
+
try {
|
|
3327
|
+
let fetchResult = await cloneRepoAsync(tmpDir);
|
|
3328
|
+
if (!fetchResult.ok) {
|
|
3329
|
+
fetchResult = await downloadArchiveAsync(tmpDir);
|
|
3330
|
+
}
|
|
3331
|
+
if (!fetchResult.ok) {
|
|
3332
|
+
return { status: "failed", message: fetchResult.message || "skill fetch failed" };
|
|
3333
|
+
}
|
|
3334
|
+
const sourceDir = resolveSkillSourceDir(tmpDir);
|
|
3335
|
+
if (!sourceDir) {
|
|
3336
|
+
return { status: "failed", message: "skill source not found after download" };
|
|
3337
|
+
}
|
|
3338
|
+
if (exists) {
|
|
3339
|
+
fs10.rmSync(targetDir, { recursive: true, force: true });
|
|
3340
|
+
}
|
|
3341
|
+
copyDir(sourceDir, targetDir);
|
|
3342
|
+
fs10.writeFileSync(
|
|
3343
|
+
markerPath,
|
|
3344
|
+
JSON.stringify({ managedBy: "cc-mirror", updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
|
|
3345
|
+
);
|
|
3346
|
+
return { status: exists ? "updated" : "installed", path: targetDir };
|
|
3347
|
+
} catch (error) {
|
|
3348
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3349
|
+
return { status: "failed", message };
|
|
3350
|
+
} finally {
|
|
3351
|
+
fs10.rmSync(tmpDir, { recursive: true, force: true });
|
|
3352
|
+
}
|
|
3353
|
+
};
|
|
3354
|
+
|
|
3355
|
+
// src/core/variant-builder/steps/SkillInstallStep.ts
|
|
3356
|
+
var SkillInstallStep = class {
|
|
3357
|
+
name = "SkillInstall";
|
|
3358
|
+
execute(ctx) {
|
|
3359
|
+
const { paths, prefs, state } = ctx;
|
|
3360
|
+
if (!prefs.skillInstallEnabled) {
|
|
3361
|
+
return;
|
|
3362
|
+
}
|
|
3363
|
+
ctx.report("Installing dev-browser skill...");
|
|
3364
|
+
const skillResult = ensureDevBrowserSkill({
|
|
3365
|
+
install: true,
|
|
3366
|
+
update: prefs.skillUpdateEnabled,
|
|
3367
|
+
targetDir: path13.join(paths.configDir, "skills")
|
|
3368
|
+
});
|
|
3369
|
+
if (skillResult.status === "failed") {
|
|
3370
|
+
state.notes.push(`dev-browser skill install failed: ${skillResult.message || "unknown error"}`);
|
|
3371
|
+
} else if (skillResult.status !== "skipped") {
|
|
3372
|
+
state.notes.push(`dev-browser skill ${skillResult.status}`);
|
|
3373
|
+
}
|
|
3374
|
+
}
|
|
3375
|
+
async executeAsync(ctx) {
|
|
3376
|
+
const { paths, prefs, state } = ctx;
|
|
3377
|
+
if (!prefs.skillInstallEnabled) {
|
|
3378
|
+
return;
|
|
3379
|
+
}
|
|
3380
|
+
await ctx.report("Installing dev-browser skill...");
|
|
3381
|
+
const skillResult = await ensureDevBrowserSkillAsync({
|
|
3382
|
+
install: true,
|
|
3383
|
+
update: prefs.skillUpdateEnabled,
|
|
3384
|
+
targetDir: path13.join(paths.configDir, "skills")
|
|
3385
|
+
});
|
|
3386
|
+
if (skillResult.status === "failed") {
|
|
3387
|
+
state.notes.push(`dev-browser skill install failed: ${skillResult.message || "unknown error"}`);
|
|
3388
|
+
} else if (skillResult.status !== "skipped") {
|
|
3389
|
+
state.notes.push(`dev-browser skill ${skillResult.status}`);
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
};
|
|
3393
|
+
|
|
3394
|
+
// src/core/variant-builder/steps/FinalizeStep.ts
|
|
3395
|
+
import path14 from "node:path";
|
|
3396
|
+
var FinalizeStep = class {
|
|
3397
|
+
name = "Finalize";
|
|
3398
|
+
execute(ctx) {
|
|
3399
|
+
ctx.report("Finalizing variant...");
|
|
3400
|
+
this.finalize(ctx);
|
|
3401
|
+
}
|
|
3402
|
+
async executeAsync(ctx) {
|
|
3403
|
+
await ctx.report("Finalizing variant...");
|
|
3404
|
+
this.finalize(ctx);
|
|
3405
|
+
}
|
|
3406
|
+
finalize(ctx) {
|
|
3407
|
+
const { params, paths, prefs, state } = ctx;
|
|
3408
|
+
const meta = {
|
|
3409
|
+
name: params.name,
|
|
3410
|
+
provider: params.providerKey,
|
|
3411
|
+
baseUrl: params.baseUrl,
|
|
3412
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3413
|
+
claudeOrig: state.claudeBinary,
|
|
3414
|
+
binaryPath: state.binaryPath,
|
|
3415
|
+
configDir: paths.configDir,
|
|
3416
|
+
tweakDir: paths.tweakDir,
|
|
3417
|
+
brand: prefs.brandKey ?? void 0,
|
|
3418
|
+
promptPack: prefs.promptPackPreference,
|
|
3419
|
+
promptPackMode: prefs.promptPackModePreference,
|
|
3420
|
+
skillInstall: prefs.skillInstallEnabled,
|
|
3421
|
+
shellEnv: prefs.shellEnvEnabled,
|
|
3422
|
+
binDir: paths.resolvedBin,
|
|
3423
|
+
installType: "npm",
|
|
3424
|
+
npmDir: paths.npmDir,
|
|
3425
|
+
npmPackage: prefs.resolvedNpmPackage,
|
|
3426
|
+
npmVersion: prefs.resolvedNpmVersion
|
|
3427
|
+
};
|
|
3428
|
+
writeJson(path14.join(paths.variantDir, "variant.json"), meta);
|
|
3429
|
+
state.meta = meta;
|
|
3430
|
+
}
|
|
3431
|
+
};
|
|
3432
|
+
|
|
3433
|
+
// src/core/variant-builder/VariantBuilder.ts
|
|
3434
|
+
var normalizeNpmPackage = (value) => value && value.trim().length > 0 ? value.trim() : DEFAULT_NPM_PACKAGE;
|
|
3435
|
+
var normalizeNpmVersion = () => DEFAULT_NPM_VERSION;
|
|
3436
|
+
var shouldEnablePromptPack = (providerKey) => providerKey === "zai" || providerKey === "minimax";
|
|
3437
|
+
var defaultPromptPackMode = (providerKey) => providerKey === "zai" || providerKey === "minimax" ? "maximal" : "minimal";
|
|
3438
|
+
var shouldInstallSkills = (providerKey) => providerKey === "zai" || providerKey === "minimax";
|
|
3439
|
+
var shouldEnableShellEnv = (providerKey) => providerKey === "zai";
|
|
3440
|
+
var yieldToEventLoop = () => new Promise((resolve) => setImmediate(resolve));
|
|
3441
|
+
var VariantBuilder = class {
|
|
3442
|
+
constructor(isAsync = false) {
|
|
3443
|
+
this.isAsync = isAsync;
|
|
3444
|
+
this.steps = [
|
|
3445
|
+
new PrepareDirectoriesStep(),
|
|
3446
|
+
new InstallNpmStep(),
|
|
3447
|
+
new WriteConfigStep(),
|
|
3448
|
+
new BrandThemeStep(),
|
|
3449
|
+
new TweakccStep(),
|
|
3450
|
+
new WrapperStep(),
|
|
3451
|
+
new ShellEnvStep(),
|
|
3452
|
+
new SkillInstallStep(),
|
|
3453
|
+
new FinalizeStep()
|
|
3454
|
+
];
|
|
3455
|
+
}
|
|
3456
|
+
steps;
|
|
3457
|
+
/**
|
|
3458
|
+
* Initialize the build context from params
|
|
3459
|
+
*/
|
|
3460
|
+
initContext(params) {
|
|
3461
|
+
const provider = getProvider(params.providerKey);
|
|
3462
|
+
if (!provider) throw new Error(`Unknown provider: ${params.providerKey}`);
|
|
3463
|
+
if (!params.name) throw new Error("Variant name is required");
|
|
3464
|
+
const rootDir = params.rootDir ?? DEFAULT_ROOT;
|
|
3465
|
+
const binDir = params.binDir ?? DEFAULT_BIN_DIR;
|
|
3466
|
+
const resolvedRoot = expandTilde(rootDir) ?? rootDir;
|
|
3467
|
+
const resolvedBin = expandTilde(binDir) ?? binDir;
|
|
3468
|
+
const variantDir = path15.join(resolvedRoot, params.name);
|
|
3469
|
+
const configDir = path15.join(variantDir, "config");
|
|
3470
|
+
const tweakDir = path15.join(variantDir, "tweakcc");
|
|
3471
|
+
const wrapperPath = path15.join(resolvedBin, params.name);
|
|
3472
|
+
const npmDir = path15.join(variantDir, "npm");
|
|
3473
|
+
const paths = {
|
|
3474
|
+
resolvedRoot,
|
|
3475
|
+
resolvedBin,
|
|
3476
|
+
variantDir,
|
|
3477
|
+
configDir,
|
|
3478
|
+
tweakDir,
|
|
3479
|
+
wrapperPath,
|
|
3480
|
+
npmDir
|
|
3481
|
+
};
|
|
3482
|
+
const resolvedNpmPackage = normalizeNpmPackage(params.npmPackage);
|
|
3483
|
+
const resolvedNpmVersion = normalizeNpmVersion();
|
|
3484
|
+
const promptPackPreference = params.promptPack ?? shouldEnablePromptPack(params.providerKey);
|
|
3485
|
+
const promptPackModePreference = params.promptPackMode ?? defaultPromptPackMode(params.providerKey);
|
|
3486
|
+
const promptPackEnabled = !params.noTweak && promptPackPreference;
|
|
3487
|
+
const skillInstallEnabled = params.skillInstall ?? shouldInstallSkills(params.providerKey);
|
|
3488
|
+
const shellEnvEnabled = params.shellEnv ?? shouldEnableShellEnv(params.providerKey);
|
|
3489
|
+
const skillUpdateEnabled = Boolean(params.skillUpdate);
|
|
3490
|
+
const commandStdio = params.tweakccStdio ?? "inherit";
|
|
3491
|
+
const prefs = {
|
|
3492
|
+
resolvedNpmPackage,
|
|
3493
|
+
resolvedNpmVersion,
|
|
3494
|
+
promptPackPreference,
|
|
3495
|
+
promptPackModePreference,
|
|
3496
|
+
promptPackEnabled,
|
|
3497
|
+
skillInstallEnabled,
|
|
3498
|
+
shellEnvEnabled,
|
|
3499
|
+
skillUpdateEnabled,
|
|
3500
|
+
brandKey: null,
|
|
3501
|
+
// Will be resolved in BrandThemeStep
|
|
3502
|
+
commandStdio
|
|
3503
|
+
};
|
|
3504
|
+
const state = {
|
|
3505
|
+
binaryPath: "",
|
|
3506
|
+
claudeBinary: "",
|
|
3507
|
+
notes: [],
|
|
3508
|
+
tweakResult: null
|
|
3509
|
+
};
|
|
3510
|
+
const report = this.isAsync ? async (step) => {
|
|
3511
|
+
params.onProgress?.(step);
|
|
3512
|
+
await yieldToEventLoop();
|
|
3513
|
+
} : (step) => {
|
|
3514
|
+
params.onProgress?.(step);
|
|
3515
|
+
};
|
|
3516
|
+
return {
|
|
3517
|
+
params,
|
|
3518
|
+
provider,
|
|
3519
|
+
paths,
|
|
3520
|
+
prefs,
|
|
3521
|
+
state,
|
|
3522
|
+
report,
|
|
3523
|
+
isAsync: this.isAsync
|
|
3524
|
+
};
|
|
3525
|
+
}
|
|
3526
|
+
/**
|
|
3527
|
+
* Build a variant synchronously
|
|
3528
|
+
*/
|
|
3529
|
+
build(params) {
|
|
3530
|
+
if (this.isAsync) {
|
|
3531
|
+
throw new Error("Use buildAsync() for async builds");
|
|
3532
|
+
}
|
|
3533
|
+
const ctx = this.initContext(params);
|
|
3534
|
+
for (const step of this.steps) {
|
|
3535
|
+
step.execute(ctx);
|
|
3536
|
+
}
|
|
3537
|
+
return this.toResult(ctx);
|
|
3538
|
+
}
|
|
3539
|
+
/**
|
|
3540
|
+
* Build a variant asynchronously
|
|
3541
|
+
*/
|
|
3542
|
+
async buildAsync(params) {
|
|
3543
|
+
if (!this.isAsync) {
|
|
3544
|
+
throw new Error("Use build() for sync builds");
|
|
3545
|
+
}
|
|
3546
|
+
const ctx = this.initContext(params);
|
|
3547
|
+
for (const step of this.steps) {
|
|
3548
|
+
await step.executeAsync(ctx);
|
|
3549
|
+
}
|
|
3550
|
+
return this.toResult(ctx);
|
|
3551
|
+
}
|
|
3552
|
+
/**
|
|
3553
|
+
* Convert build context to result
|
|
3554
|
+
*/
|
|
3555
|
+
toResult(ctx) {
|
|
3556
|
+
if (!ctx.state.meta) {
|
|
3557
|
+
throw new Error("FinalizeStep did not populate meta");
|
|
3558
|
+
}
|
|
3559
|
+
return {
|
|
3560
|
+
meta: ctx.state.meta,
|
|
3561
|
+
wrapperPath: ctx.paths.wrapperPath,
|
|
3562
|
+
tweakResult: ctx.state.tweakResult,
|
|
3563
|
+
notes: ctx.state.notes.length > 0 ? ctx.state.notes : void 0
|
|
3564
|
+
};
|
|
3565
|
+
}
|
|
3566
|
+
};
|
|
3567
|
+
|
|
3568
|
+
// src/core/variant-builder/VariantUpdater.ts
|
|
3569
|
+
import path19 from "node:path";
|
|
3570
|
+
|
|
3571
|
+
// src/core/variant-builder/update-steps/InstallNpmUpdateStep.ts
|
|
3572
|
+
var InstallNpmUpdateStep = class {
|
|
3573
|
+
name = "InstallNpm";
|
|
3574
|
+
execute(ctx) {
|
|
3575
|
+
if (ctx.opts.settingsOnly) return;
|
|
3576
|
+
ctx.report(`Installing ${ctx.prefs.resolvedNpmPackage}@${ctx.prefs.resolvedNpmVersion}...`);
|
|
3577
|
+
this.install(ctx, false);
|
|
3578
|
+
}
|
|
3579
|
+
async executeAsync(ctx) {
|
|
3580
|
+
if (ctx.opts.settingsOnly) return;
|
|
3581
|
+
await ctx.report(`Installing ${ctx.prefs.resolvedNpmPackage}@${ctx.prefs.resolvedNpmVersion}...`);
|
|
3582
|
+
await this.install(ctx, true);
|
|
3583
|
+
}
|
|
3584
|
+
async install(ctx, isAsync) {
|
|
3585
|
+
const { meta, paths, prefs } = ctx;
|
|
3586
|
+
ensureDir(paths.npmDir);
|
|
3587
|
+
const installOpts = {
|
|
3588
|
+
npmDir: paths.npmDir,
|
|
3589
|
+
npmPackage: prefs.resolvedNpmPackage,
|
|
3590
|
+
npmVersion: prefs.resolvedNpmVersion,
|
|
3591
|
+
stdio: prefs.commandStdio
|
|
3592
|
+
};
|
|
3593
|
+
const install = isAsync ? await installNpmClaudeAsync(installOpts) : installNpmClaude(installOpts);
|
|
3594
|
+
meta.binaryPath = install.cliPath;
|
|
3595
|
+
meta.installType = "npm";
|
|
3596
|
+
meta.npmDir = paths.npmDir;
|
|
3597
|
+
meta.npmPackage = prefs.resolvedNpmPackage;
|
|
3598
|
+
meta.npmVersion = prefs.resolvedNpmVersion;
|
|
3599
|
+
meta.claudeOrig = `npm:${prefs.resolvedNpmPackage}@${prefs.resolvedNpmVersion}`;
|
|
3600
|
+
}
|
|
3601
|
+
};
|
|
3602
|
+
|
|
3603
|
+
// src/core/variant-builder/update-steps/ModelOverridesStep.ts
|
|
3604
|
+
var ModelOverridesStep = class {
|
|
3605
|
+
name = "ModelOverrides";
|
|
3606
|
+
execute(ctx) {
|
|
3607
|
+
this.apply(ctx);
|
|
3608
|
+
}
|
|
3609
|
+
async executeAsync(ctx) {
|
|
3610
|
+
this.apply(ctx);
|
|
3611
|
+
}
|
|
3612
|
+
apply(ctx) {
|
|
3613
|
+
const { opts, meta, state } = ctx;
|
|
3614
|
+
if (!opts.modelOverrides || Object.keys(opts.modelOverrides).length === 0) {
|
|
3615
|
+
return;
|
|
3616
|
+
}
|
|
3617
|
+
const envOverridesUpdated = ensureSettingsEnvOverrides(meta.configDir, {
|
|
3618
|
+
...opts.modelOverrides.sonnet ? { ANTHROPIC_DEFAULT_SONNET_MODEL: opts.modelOverrides.sonnet } : {},
|
|
3619
|
+
...opts.modelOverrides.opus ? { ANTHROPIC_DEFAULT_OPUS_MODEL: opts.modelOverrides.opus } : {},
|
|
3620
|
+
...opts.modelOverrides.haiku ? { ANTHROPIC_DEFAULT_HAIKU_MODEL: opts.modelOverrides.haiku } : {},
|
|
3621
|
+
...opts.modelOverrides.smallFast ? { ANTHROPIC_SMALL_FAST_MODEL: opts.modelOverrides.smallFast } : {},
|
|
3622
|
+
...opts.modelOverrides.defaultModel ? { ANTHROPIC_MODEL: opts.modelOverrides.defaultModel } : {},
|
|
3623
|
+
...opts.modelOverrides.subagentModel ? { CLAUDE_CODE_SUBAGENT_MODEL: opts.modelOverrides.subagentModel } : {}
|
|
3624
|
+
});
|
|
3625
|
+
if (envOverridesUpdated) {
|
|
3626
|
+
state.notes.push("Updated model mapping in settings.json.");
|
|
3627
|
+
}
|
|
3628
|
+
}
|
|
3629
|
+
};
|
|
3630
|
+
|
|
3631
|
+
// src/core/variant-builder/update-steps/TweakccUpdateStep.ts
|
|
3632
|
+
var TweakccUpdateStep = class {
|
|
3633
|
+
name = "Tweakcc";
|
|
3634
|
+
execute(ctx) {
|
|
3635
|
+
if (ctx.opts.noTweak) return;
|
|
3636
|
+
ctx.report("Running tweakcc patches...");
|
|
3637
|
+
this.runTweakcc(ctx, false);
|
|
3638
|
+
}
|
|
3639
|
+
async executeAsync(ctx) {
|
|
3640
|
+
if (ctx.opts.noTweak) return;
|
|
3641
|
+
await ctx.report("Running tweakcc patches...");
|
|
3642
|
+
await this.runTweakcc(ctx, true);
|
|
3643
|
+
}
|
|
3644
|
+
async runTweakcc(ctx, isAsync) {
|
|
3645
|
+
const { opts, meta, prefs, state } = ctx;
|
|
3646
|
+
ensureDir(meta.tweakDir);
|
|
3647
|
+
if (opts.brand !== void 0) {
|
|
3648
|
+
state.brandKey = resolveBrandKey(meta.provider, opts.brand);
|
|
3649
|
+
meta.brand = state.brandKey ?? void 0;
|
|
3650
|
+
}
|
|
3651
|
+
ensureTweakccConfig(meta.tweakDir, state.brandKey);
|
|
3652
|
+
const tweakResult = isAsync ? await runTweakccAsync(meta.tweakDir, meta.binaryPath, prefs.commandStdio) : runTweakcc(meta.tweakDir, meta.binaryPath, prefs.commandStdio);
|
|
3653
|
+
state.tweakResult = tweakResult;
|
|
3654
|
+
if (tweakResult.status !== 0) {
|
|
3655
|
+
const output = `${tweakResult.stderr ?? ""}
|
|
3656
|
+
${tweakResult.stdout ?? ""}`.trim();
|
|
3657
|
+
throw new Error(formatTweakccFailure(output));
|
|
3658
|
+
}
|
|
3659
|
+
if (prefs.promptPackEnabled) {
|
|
3660
|
+
if (isAsync) {
|
|
3661
|
+
await ctx.report(`Applying prompt pack (${prefs.promptPackModePreference})...`);
|
|
3662
|
+
} else {
|
|
3663
|
+
ctx.report(`Applying prompt pack (${prefs.promptPackModePreference})...`);
|
|
3664
|
+
}
|
|
3665
|
+
const packResult = applyPromptPack(meta.tweakDir, meta.provider, prefs.promptPackModePreference);
|
|
3666
|
+
if (packResult.changed) {
|
|
3667
|
+
state.notes.push(`Prompt pack applied (${packResult.mode}, ${packResult.updated.join(", ")})`);
|
|
3668
|
+
if (isAsync) {
|
|
3669
|
+
await ctx.report("Re-applying tweakcc...");
|
|
3670
|
+
} else {
|
|
3671
|
+
ctx.report("Re-applying tweakcc...");
|
|
3672
|
+
}
|
|
3673
|
+
const reapply = isAsync ? await runTweakccAsync(meta.tweakDir, meta.binaryPath, prefs.commandStdio) : runTweakcc(meta.tweakDir, meta.binaryPath, prefs.commandStdio);
|
|
3674
|
+
state.tweakResult = reapply;
|
|
3675
|
+
if (reapply.status !== 0) {
|
|
3676
|
+
const output = `${reapply.stderr ?? ""}
|
|
3677
|
+
${reapply.stdout ?? ""}`.trim();
|
|
3678
|
+
throw new Error(formatTweakccFailure(output));
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3683
|
+
};
|
|
3684
|
+
|
|
3685
|
+
// src/core/variant-builder/update-steps/WrapperUpdateStep.ts
|
|
3686
|
+
import path16 from "node:path";
|
|
3687
|
+
var WrapperUpdateStep = class {
|
|
3688
|
+
name = "Wrapper";
|
|
3689
|
+
execute(ctx) {
|
|
3690
|
+
if (ctx.opts.settingsOnly) return;
|
|
3691
|
+
ctx.report("Writing CLI wrapper...");
|
|
3692
|
+
this.writeWrapper(ctx);
|
|
3693
|
+
}
|
|
3694
|
+
async executeAsync(ctx) {
|
|
3695
|
+
if (ctx.opts.settingsOnly) return;
|
|
3696
|
+
await ctx.report("Writing CLI wrapper...");
|
|
3697
|
+
this.writeWrapper(ctx);
|
|
3698
|
+
}
|
|
3699
|
+
writeWrapper(ctx) {
|
|
3700
|
+
const { name, opts, meta } = ctx;
|
|
3701
|
+
const resolvedBin = opts.binDir ? expandTilde(opts.binDir) ?? opts.binDir : meta.binDir;
|
|
3702
|
+
if (resolvedBin) {
|
|
3703
|
+
ensureDir(resolvedBin);
|
|
3704
|
+
const wrapperPath = path16.join(resolvedBin, name);
|
|
3705
|
+
writeWrapper(wrapperPath, meta.configDir, meta.binaryPath, "node");
|
|
3706
|
+
meta.binDir = resolvedBin;
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3709
|
+
};
|
|
3710
|
+
|
|
3711
|
+
// src/core/variant-builder/update-steps/ConfigUpdateStep.ts
|
|
3712
|
+
var ConfigUpdateStep = class {
|
|
3713
|
+
name = "Config";
|
|
3714
|
+
execute(ctx) {
|
|
3715
|
+
ctx.report("Updating configuration...");
|
|
3716
|
+
this.updateConfig(ctx, false);
|
|
3717
|
+
}
|
|
3718
|
+
async executeAsync(ctx) {
|
|
3719
|
+
await ctx.report("Updating configuration...");
|
|
3720
|
+
await this.updateConfig(ctx, true);
|
|
3721
|
+
}
|
|
3722
|
+
async updateConfig(ctx, isAsync) {
|
|
3723
|
+
const { opts, meta, state } = ctx;
|
|
3724
|
+
ensureApiKeyApproval(meta.configDir);
|
|
3725
|
+
if (meta.provider === "minimax") {
|
|
3726
|
+
if (isAsync) {
|
|
3727
|
+
await ctx.report("Configuring MiniMax MCP server...");
|
|
3728
|
+
} else {
|
|
3729
|
+
ctx.report("Configuring MiniMax MCP server...");
|
|
3730
|
+
}
|
|
3731
|
+
ensureMinimaxMcpServer(meta.configDir);
|
|
3732
|
+
}
|
|
3733
|
+
if (meta.provider === "zai") {
|
|
3734
|
+
const denied = ensureZaiMcpDeny(meta.configDir);
|
|
3735
|
+
if (denied) {
|
|
3736
|
+
state.notes.push("Blocked Z.ai-injected MCP tools in settings.json.");
|
|
3737
|
+
}
|
|
3738
|
+
}
|
|
3739
|
+
const brandThemeId = !opts.noTweak && state.brandKey ? getBrandThemeId(state.brandKey) : null;
|
|
3740
|
+
const onboarding = ensureOnboardingState(meta.configDir, {
|
|
3741
|
+
themeId: brandThemeId ?? "dark",
|
|
3742
|
+
forceTheme: Boolean(brandThemeId)
|
|
3743
|
+
});
|
|
3744
|
+
const envDefaultsUpdated = ensureSettingsEnvDefaults(meta.configDir, {
|
|
3745
|
+
TWEAKCC_CONFIG_DIR: meta.tweakDir,
|
|
3746
|
+
DISABLE_AUTOUPDATER: "1",
|
|
3747
|
+
CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION: "1"
|
|
3748
|
+
});
|
|
3749
|
+
if (envDefaultsUpdated) {
|
|
3750
|
+
state.notes.push("Disabled Claude Code auto-updater (DISABLE_AUTOUPDATER=1).");
|
|
3751
|
+
}
|
|
3752
|
+
if (onboarding.themeChanged) {
|
|
3753
|
+
state.notes.push(`Default theme set to ${brandThemeId ?? "dark"}.`);
|
|
3754
|
+
}
|
|
3755
|
+
if (onboarding.onboardingChanged) {
|
|
3756
|
+
state.notes.push("Onboarding marked complete.");
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
};
|
|
3760
|
+
|
|
3761
|
+
// src/core/variant-builder/update-steps/ShellEnvUpdateStep.ts
|
|
3762
|
+
var ShellEnvUpdateStep = class {
|
|
3763
|
+
name = "ShellEnv";
|
|
3764
|
+
execute(ctx) {
|
|
3765
|
+
if (ctx.opts.settingsOnly) return;
|
|
3766
|
+
this.configure(ctx, false);
|
|
3767
|
+
}
|
|
3768
|
+
async executeAsync(ctx) {
|
|
3769
|
+
if (ctx.opts.settingsOnly) return;
|
|
3770
|
+
await this.configure(ctx, true);
|
|
3771
|
+
}
|
|
3772
|
+
async configure(ctx, isAsync) {
|
|
3773
|
+
const { opts, meta, prefs, state } = ctx;
|
|
3774
|
+
if (prefs.shellEnvEnabled && meta.provider === "zai") {
|
|
3775
|
+
if (isAsync) {
|
|
3776
|
+
await ctx.report("Configuring shell environment...");
|
|
3777
|
+
} else {
|
|
3778
|
+
ctx.report("Configuring shell environment...");
|
|
3779
|
+
}
|
|
3780
|
+
const shellResult = ensureZaiShellEnv({ configDir: meta.configDir });
|
|
3781
|
+
if (shellResult.status === "updated") {
|
|
3782
|
+
const suffix = shellResult.message ? ` (${shellResult.message})` : "";
|
|
3783
|
+
state.notes.push(`Z_AI_API_KEY written to ${shellResult.path}${suffix}`);
|
|
3784
|
+
} else if (shellResult.status === "failed") {
|
|
3785
|
+
state.notes.push(`Z_AI_API_KEY not written: ${shellResult.message || "unknown error"}`);
|
|
3786
|
+
} else if (shellResult.message) {
|
|
3787
|
+
state.notes.push(`Z_AI_API_KEY: ${shellResult.message}`);
|
|
3788
|
+
}
|
|
3789
|
+
} else if (meta.provider === "zai" && opts.shellEnv === false) {
|
|
3790
|
+
state.notes.push("Z_AI_API_KEY not written to shell profile. Set it manually in your shell rc file.");
|
|
3791
|
+
}
|
|
3792
|
+
}
|
|
3793
|
+
};
|
|
3794
|
+
|
|
3795
|
+
// src/core/variant-builder/update-steps/SkillInstallUpdateStep.ts
|
|
3796
|
+
import path17 from "node:path";
|
|
3797
|
+
var SkillInstallUpdateStep = class {
|
|
3798
|
+
name = "SkillInstall";
|
|
3799
|
+
execute(ctx) {
|
|
3800
|
+
if (ctx.opts.settingsOnly) return;
|
|
3801
|
+
if (!ctx.prefs.skillInstallEnabled) return;
|
|
3802
|
+
ctx.report("Installing dev-browser skill...");
|
|
3803
|
+
this.install(ctx, false);
|
|
3804
|
+
}
|
|
3805
|
+
async executeAsync(ctx) {
|
|
3806
|
+
if (ctx.opts.settingsOnly) return;
|
|
3807
|
+
if (!ctx.prefs.skillInstallEnabled) return;
|
|
3808
|
+
await ctx.report("Installing dev-browser skill...");
|
|
3809
|
+
await this.install(ctx, true);
|
|
3810
|
+
}
|
|
3811
|
+
async install(ctx, isAsync) {
|
|
3812
|
+
const { meta, prefs, state } = ctx;
|
|
3813
|
+
const skillOpts = {
|
|
3814
|
+
install: true,
|
|
3815
|
+
update: prefs.skillUpdateEnabled,
|
|
3816
|
+
targetDir: path17.join(meta.configDir, "skills")
|
|
3817
|
+
};
|
|
3818
|
+
const skillResult = isAsync ? await ensureDevBrowserSkillAsync(skillOpts) : ensureDevBrowserSkill(skillOpts);
|
|
3819
|
+
if (skillResult.status === "failed") {
|
|
3820
|
+
state.notes.push(`dev-browser skill install failed: ${skillResult.message || "unknown error"}`);
|
|
3821
|
+
} else if (skillResult.status !== "skipped") {
|
|
3822
|
+
state.notes.push(`dev-browser skill ${skillResult.status}`);
|
|
3823
|
+
}
|
|
3824
|
+
}
|
|
3825
|
+
};
|
|
3826
|
+
|
|
3827
|
+
// src/core/variant-builder/update-steps/FinalizeUpdateStep.ts
|
|
3828
|
+
import path18 from "node:path";
|
|
3829
|
+
var FinalizeUpdateStep = class {
|
|
3830
|
+
name = "Finalize";
|
|
3831
|
+
execute(ctx) {
|
|
3832
|
+
ctx.report("Finalizing variant...");
|
|
3833
|
+
this.finalize(ctx);
|
|
3834
|
+
}
|
|
3835
|
+
async executeAsync(ctx) {
|
|
3836
|
+
await ctx.report("Finalizing variant...");
|
|
3837
|
+
this.finalize(ctx);
|
|
3838
|
+
}
|
|
3839
|
+
finalize(ctx) {
|
|
3840
|
+
const { meta, paths, prefs } = ctx;
|
|
3841
|
+
meta.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3842
|
+
meta.promptPack = prefs.promptPackPreference;
|
|
3843
|
+
meta.promptPackMode = prefs.promptPackModePreference;
|
|
3844
|
+
meta.skillInstall = prefs.skillInstallEnabled;
|
|
3845
|
+
meta.shellEnv = prefs.shellEnvEnabled;
|
|
3846
|
+
writeJson(path18.join(paths.variantDir, "variant.json"), meta);
|
|
3847
|
+
}
|
|
3848
|
+
};
|
|
3849
|
+
|
|
3850
|
+
// src/core/variant-builder/VariantUpdater.ts
|
|
3851
|
+
var normalizeNpmPackage2 = (value) => value && value.trim().length > 0 ? value.trim() : DEFAULT_NPM_PACKAGE;
|
|
3852
|
+
var normalizeNpmVersion2 = () => DEFAULT_NPM_VERSION;
|
|
3853
|
+
var shouldEnablePromptPack2 = (providerKey) => providerKey === "zai" || providerKey === "minimax";
|
|
3854
|
+
var defaultPromptPackMode2 = (providerKey) => providerKey === "zai" || providerKey === "minimax" ? "maximal" : "minimal";
|
|
3855
|
+
var shouldInstallSkills2 = (providerKey) => providerKey === "zai" || providerKey === "minimax";
|
|
3856
|
+
var shouldEnableShellEnv2 = (providerKey) => providerKey === "zai";
|
|
3857
|
+
var yieldToEventLoop2 = () => new Promise((resolve) => setImmediate(resolve));
|
|
3858
|
+
var VariantUpdater = class {
|
|
3859
|
+
constructor(isAsync = false) {
|
|
3860
|
+
this.isAsync = isAsync;
|
|
3861
|
+
this.steps = [
|
|
3862
|
+
new InstallNpmUpdateStep(),
|
|
3863
|
+
new ModelOverridesStep(),
|
|
3864
|
+
new TweakccUpdateStep(),
|
|
3865
|
+
new WrapperUpdateStep(),
|
|
3866
|
+
new ConfigUpdateStep(),
|
|
3867
|
+
new ShellEnvUpdateStep(),
|
|
3868
|
+
new SkillInstallUpdateStep(),
|
|
3869
|
+
new FinalizeUpdateStep()
|
|
3870
|
+
];
|
|
3871
|
+
}
|
|
3872
|
+
steps;
|
|
3873
|
+
/**
|
|
3874
|
+
* Initialize the update context
|
|
3875
|
+
*/
|
|
3876
|
+
initContext(rootDir, name, opts) {
|
|
3877
|
+
const resolvedRoot = expandTilde(rootDir || DEFAULT_ROOT) ?? rootDir;
|
|
3878
|
+
const variantDir = path19.join(resolvedRoot, name);
|
|
3879
|
+
const meta = loadVariantMeta(variantDir);
|
|
3880
|
+
if (!meta) throw new Error(`Variant not found: ${name}`);
|
|
3881
|
+
const resolvedNpmPackage = normalizeNpmPackage2(opts.npmPackage ?? meta.npmPackage);
|
|
3882
|
+
const resolvedNpmVersion = normalizeNpmVersion2();
|
|
3883
|
+
const promptPackPreference = opts.promptPack ?? meta.promptPack ?? shouldEnablePromptPack2(meta.provider);
|
|
3884
|
+
const promptPackModePreference = opts.promptPackMode ?? meta.promptPackMode ?? defaultPromptPackMode2(meta.provider);
|
|
3885
|
+
const promptPackEnabled = !opts.noTweak && promptPackPreference;
|
|
3886
|
+
const skillInstallEnabled = opts.skillInstall ?? meta.skillInstall ?? shouldInstallSkills2(meta.provider);
|
|
3887
|
+
const shellEnvEnabled = opts.shellEnv ?? meta.shellEnv ?? shouldEnableShellEnv2(meta.provider);
|
|
3888
|
+
const skillUpdateEnabled = Boolean(opts.skillUpdate);
|
|
3889
|
+
const commandStdio = opts.tweakccStdio || "inherit";
|
|
3890
|
+
const paths = {
|
|
3891
|
+
resolvedRoot,
|
|
3892
|
+
resolvedBin: opts.binDir ? expandTilde(opts.binDir) ?? opts.binDir : meta.binDir,
|
|
3893
|
+
variantDir,
|
|
3894
|
+
npmDir: meta.npmDir || path19.join(variantDir, "npm")
|
|
3895
|
+
};
|
|
3896
|
+
const prefs = {
|
|
3897
|
+
resolvedNpmPackage,
|
|
3898
|
+
resolvedNpmVersion,
|
|
3899
|
+
promptPackPreference,
|
|
3900
|
+
promptPackModePreference,
|
|
3901
|
+
promptPackEnabled,
|
|
3902
|
+
skillInstallEnabled,
|
|
3903
|
+
shellEnvEnabled,
|
|
3904
|
+
skillUpdateEnabled,
|
|
3905
|
+
commandStdio
|
|
3906
|
+
};
|
|
3907
|
+
const state = {
|
|
3908
|
+
notes: [],
|
|
3909
|
+
tweakResult: null,
|
|
3910
|
+
brandKey: meta.brand ?? null
|
|
3911
|
+
};
|
|
3912
|
+
const report = this.isAsync ? async (step) => {
|
|
3913
|
+
opts.onProgress?.(step);
|
|
3914
|
+
await yieldToEventLoop2();
|
|
3915
|
+
} : (step) => {
|
|
3916
|
+
opts.onProgress?.(step);
|
|
3917
|
+
};
|
|
3918
|
+
return {
|
|
3919
|
+
name,
|
|
3920
|
+
opts,
|
|
3921
|
+
meta,
|
|
3922
|
+
paths,
|
|
3923
|
+
prefs,
|
|
3924
|
+
state,
|
|
3925
|
+
report,
|
|
3926
|
+
isAsync: this.isAsync
|
|
3927
|
+
};
|
|
3928
|
+
}
|
|
3929
|
+
/**
|
|
3930
|
+
* Update a variant synchronously
|
|
3931
|
+
*/
|
|
3932
|
+
update(rootDir, name, opts = {}) {
|
|
3933
|
+
if (this.isAsync) {
|
|
3934
|
+
throw new Error("Use updateAsync() for async updates");
|
|
3935
|
+
}
|
|
3936
|
+
const ctx = this.initContext(rootDir, name, opts);
|
|
3937
|
+
for (const step of this.steps) {
|
|
3938
|
+
step.execute(ctx);
|
|
3939
|
+
}
|
|
3940
|
+
return this.toResult(ctx);
|
|
3941
|
+
}
|
|
3942
|
+
/**
|
|
3943
|
+
* Update a variant asynchronously
|
|
3944
|
+
*/
|
|
3945
|
+
async updateAsync(rootDir, name, opts = {}) {
|
|
3946
|
+
if (!this.isAsync) {
|
|
3947
|
+
throw new Error("Use update() for sync updates");
|
|
3948
|
+
}
|
|
3949
|
+
const ctx = this.initContext(rootDir, name, opts);
|
|
3950
|
+
for (const step of this.steps) {
|
|
3951
|
+
await step.executeAsync(ctx);
|
|
3952
|
+
}
|
|
3953
|
+
return this.toResult(ctx);
|
|
3954
|
+
}
|
|
3955
|
+
/**
|
|
3956
|
+
* Convert update context to result
|
|
3957
|
+
*/
|
|
3958
|
+
toResult(ctx) {
|
|
3959
|
+
return {
|
|
3960
|
+
meta: ctx.meta,
|
|
3961
|
+
tweakResult: ctx.state.tweakResult,
|
|
3962
|
+
notes: ctx.state.notes.length > 0 ? ctx.state.notes : void 0
|
|
3963
|
+
};
|
|
3964
|
+
}
|
|
3965
|
+
};
|
|
3966
|
+
|
|
3967
|
+
// src/core/index.ts
|
|
3968
|
+
var createVariant = (params) => {
|
|
3969
|
+
return new VariantBuilder(false).build(params);
|
|
3970
|
+
};
|
|
3971
|
+
var updateVariant = (rootDir, name, opts = {}) => {
|
|
3972
|
+
return new VariantUpdater(false).update(rootDir, name, opts);
|
|
3973
|
+
};
|
|
3974
|
+
var removeVariant = (rootDir, name) => {
|
|
3975
|
+
const resolvedRoot = expandTilde(rootDir || DEFAULT_ROOT) ?? rootDir;
|
|
3976
|
+
const variantDir = path20.join(resolvedRoot, name);
|
|
3977
|
+
if (!fs11.existsSync(variantDir)) throw new Error(`Variant not found: ${name}`);
|
|
3978
|
+
fs11.rmSync(variantDir, { recursive: true, force: true });
|
|
3979
|
+
};
|
|
3980
|
+
var doctor = (rootDir, binDir) => {
|
|
3981
|
+
const resolvedRoot = expandTilde(rootDir || DEFAULT_ROOT) ?? rootDir;
|
|
3982
|
+
const resolvedBin = expandTilde(binDir || DEFAULT_BIN_DIR) ?? binDir;
|
|
3983
|
+
const variants = listVariants(resolvedRoot);
|
|
3984
|
+
return variants.map(({ name, meta }) => {
|
|
3985
|
+
const wrapperPath = path20.join(resolvedBin, name);
|
|
3986
|
+
const ok = Boolean(meta && fs11.existsSync(meta.binaryPath) && fs11.existsSync(wrapperPath));
|
|
3987
|
+
return {
|
|
3988
|
+
name,
|
|
3989
|
+
ok,
|
|
3990
|
+
binaryPath: meta?.binaryPath,
|
|
3991
|
+
wrapperPath
|
|
3992
|
+
};
|
|
3993
|
+
});
|
|
3994
|
+
};
|
|
3995
|
+
var listVariants2 = (rootDir) => listVariants(rootDir);
|
|
3996
|
+
var tweakVariant = (rootDir, name) => {
|
|
3997
|
+
const resolvedRoot = expandTilde(rootDir || DEFAULT_ROOT) ?? rootDir;
|
|
3998
|
+
const variantDir = path20.join(resolvedRoot, name);
|
|
3999
|
+
const meta = loadVariantMeta(variantDir);
|
|
4000
|
+
if (!meta) throw new Error(`Variant not found: ${name}`);
|
|
4001
|
+
ensureDir(meta.tweakDir);
|
|
4002
|
+
const brandKey = meta.brand ?? null;
|
|
4003
|
+
ensureTweakccConfig(meta.tweakDir, brandKey);
|
|
4004
|
+
const result = launchTweakccUi(meta.tweakDir, meta.binaryPath);
|
|
4005
|
+
if (result.status && result.status !== 0) {
|
|
4006
|
+
const output = `${result.stderr ?? ""}
|
|
4007
|
+
${result.stdout ?? ""}`.trim();
|
|
4008
|
+
throw new Error(formatTweakccFailure(output));
|
|
4009
|
+
}
|
|
4010
|
+
};
|
|
4011
|
+
|
|
4012
|
+
// src/cli/commands/list.ts
|
|
4013
|
+
function runListCommand({ opts }) {
|
|
4014
|
+
const rootDir = opts.root || DEFAULT_ROOT;
|
|
4015
|
+
const variants = listVariants2(rootDir);
|
|
4016
|
+
if (variants.length === 0) {
|
|
4017
|
+
console.log(`No variants found in ${rootDir}`);
|
|
4018
|
+
return;
|
|
4019
|
+
}
|
|
4020
|
+
for (const entry of variants) {
|
|
4021
|
+
console.log(entry.name);
|
|
4022
|
+
}
|
|
4023
|
+
}
|
|
4024
|
+
|
|
4025
|
+
// src/cli/doctor.ts
|
|
4026
|
+
var printDoctor = (report) => {
|
|
4027
|
+
if (report.length === 0) {
|
|
4028
|
+
console.log("No variants found.");
|
|
4029
|
+
return;
|
|
4030
|
+
}
|
|
4031
|
+
for (const item of report) {
|
|
4032
|
+
console.log(`${item.ok ? "\u2713" : "\u2717"} ${item.name}`);
|
|
4033
|
+
if (!item.ok) {
|
|
4034
|
+
console.log(` binary: ${item.binaryPath ?? "missing"}`);
|
|
4035
|
+
console.log(` wrapper: ${item.wrapperPath}`);
|
|
4036
|
+
}
|
|
4037
|
+
}
|
|
4038
|
+
};
|
|
4039
|
+
|
|
4040
|
+
// src/cli/commands/doctorCmd.ts
|
|
4041
|
+
function runDoctorCommand({ opts }) {
|
|
4042
|
+
const rootDir = opts.root || DEFAULT_ROOT;
|
|
4043
|
+
const binDir = opts["bin-dir"] || DEFAULT_BIN_DIR;
|
|
4044
|
+
const report = doctor(rootDir, binDir);
|
|
4045
|
+
printDoctor(report);
|
|
4046
|
+
}
|
|
4047
|
+
|
|
4048
|
+
// src/cli/commands/remove.ts
|
|
4049
|
+
function runRemoveCommand({ opts }) {
|
|
4050
|
+
const target = opts._ && opts._[0];
|
|
4051
|
+
if (!target) {
|
|
4052
|
+
console.error("remove requires a variant name");
|
|
4053
|
+
process.exit(1);
|
|
4054
|
+
}
|
|
4055
|
+
const rootDir = opts.root || DEFAULT_ROOT;
|
|
4056
|
+
removeVariant(rootDir, target);
|
|
4057
|
+
console.log(`Removed ${target}`);
|
|
4058
|
+
}
|
|
4059
|
+
|
|
4060
|
+
// src/cli/commands/tweak.ts
|
|
4061
|
+
function runTweakCommand({ opts }) {
|
|
4062
|
+
const target = opts._ && opts._[0];
|
|
4063
|
+
if (!target) {
|
|
4064
|
+
console.error("tweak requires a variant name");
|
|
4065
|
+
process.exit(1);
|
|
4066
|
+
}
|
|
4067
|
+
const rootDir = opts.root || DEFAULT_ROOT;
|
|
4068
|
+
tweakVariant(rootDir, target);
|
|
4069
|
+
}
|
|
4070
|
+
|
|
4071
|
+
// src/cli/commands/update.ts
|
|
4072
|
+
import path21 from "node:path";
|
|
4073
|
+
|
|
4074
|
+
// src/cli/utils/buildShareUrl.ts
|
|
4075
|
+
function buildShareUrl(providerLabel, variant, mode) {
|
|
4076
|
+
const lines = [
|
|
4077
|
+
`Just set up ${providerLabel} with cc-mirror`,
|
|
4078
|
+
mode ? `Prompt pack: ${mode}` : "Prompt pack: enabled",
|
|
4079
|
+
`CLI: ${variant}`,
|
|
4080
|
+
"Get yours: npx cc-mirror",
|
|
4081
|
+
"(Attach your TUI screenshot)"
|
|
4082
|
+
];
|
|
4083
|
+
const url = new URL("https://x.com/intent/tweet");
|
|
4084
|
+
url.searchParams.set("text", lines.join("\n"));
|
|
4085
|
+
return url.toString();
|
|
4086
|
+
}
|
|
4087
|
+
|
|
4088
|
+
// src/cli/utils/printSummary.ts
|
|
4089
|
+
function printSummary(opts) {
|
|
4090
|
+
const { action, meta, wrapperPath, notes, shareUrl } = opts;
|
|
4091
|
+
console.log(`
|
|
4092
|
+
${action}: ${meta.name}`);
|
|
4093
|
+
console.log(`Provider: ${meta.provider}`);
|
|
4094
|
+
if (meta.promptPack !== void 0) {
|
|
4095
|
+
const mode = meta.promptPackMode || "maximal";
|
|
4096
|
+
console.log(`Prompt pack: ${meta.promptPack ? `on (${mode})` : "off"}`);
|
|
4097
|
+
}
|
|
4098
|
+
if (meta.skillInstall !== void 0) {
|
|
4099
|
+
console.log(`dev-browser skill: ${meta.skillInstall ? "on" : "off"}`);
|
|
4100
|
+
}
|
|
4101
|
+
if (meta.shellEnv !== void 0 && meta.provider === "zai") {
|
|
4102
|
+
console.log(`Shell env: ${meta.shellEnv ? "write Z_AI_API_KEY" : "manual"}`);
|
|
4103
|
+
}
|
|
4104
|
+
if (wrapperPath) console.log(`Wrapper: ${wrapperPath}`);
|
|
4105
|
+
if (meta.configDir) console.log(`Config: ${meta.configDir}`);
|
|
4106
|
+
if (notes && notes.length > 0) {
|
|
4107
|
+
console.log("Notes:");
|
|
4108
|
+
for (const note of notes) console.log(`- ${note}`);
|
|
4109
|
+
}
|
|
4110
|
+
console.log("Next steps:");
|
|
4111
|
+
console.log(`- Run: ${meta.name}`);
|
|
4112
|
+
console.log(`- Update: cc-mirror update ${meta.name}`);
|
|
4113
|
+
console.log(`- Tweak: cc-mirror tweak ${meta.name}`);
|
|
4114
|
+
console.log("Help: cc-mirror help");
|
|
4115
|
+
if (shareUrl) {
|
|
4116
|
+
console.log("Share:");
|
|
4117
|
+
console.log(shareUrl);
|
|
4118
|
+
}
|
|
4119
|
+
console.log("");
|
|
4120
|
+
}
|
|
4121
|
+
|
|
4122
|
+
// src/cli/prompt.ts
|
|
4123
|
+
import readline from "node:readline";
|
|
4124
|
+
var prompt = async (question, defaultValue) => {
|
|
4125
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
4126
|
+
const suffix = defaultValue ? ` [${defaultValue}]` : "";
|
|
4127
|
+
return new Promise((resolve) => {
|
|
4128
|
+
rl.question(`${question}${suffix}: `, (answer) => {
|
|
4129
|
+
rl.close();
|
|
4130
|
+
const trimmed = answer.trim();
|
|
4131
|
+
resolve(trimmed.length > 0 ? trimmed : defaultValue ?? "");
|
|
4132
|
+
});
|
|
4133
|
+
});
|
|
4134
|
+
};
|
|
4135
|
+
|
|
4136
|
+
// src/cli/utils/requirePrompt.ts
|
|
4137
|
+
async function requirePrompt(label, value) {
|
|
4138
|
+
let next = (value ?? "").trim();
|
|
4139
|
+
while (!next) {
|
|
4140
|
+
next = (await prompt(label, value)).trim();
|
|
4141
|
+
if (!next) {
|
|
4142
|
+
console.log("Value required.");
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4145
|
+
return next;
|
|
4146
|
+
}
|
|
4147
|
+
|
|
4148
|
+
// src/cli/utils/modelOverrides.ts
|
|
4149
|
+
function getModelOverridesFromArgs(opts) {
|
|
4150
|
+
return {
|
|
4151
|
+
sonnet: typeof opts["model-sonnet"] === "string" ? opts["model-sonnet"] : void 0,
|
|
4152
|
+
opus: typeof opts["model-opus"] === "string" ? opts["model-opus"] : void 0,
|
|
4153
|
+
haiku: typeof opts["model-haiku"] === "string" ? opts["model-haiku"] : void 0,
|
|
4154
|
+
smallFast: typeof opts["model-small-fast"] === "string" ? opts["model-small-fast"] : void 0,
|
|
4155
|
+
defaultModel: typeof opts["model-default"] === "string" ? opts["model-default"] : void 0,
|
|
4156
|
+
subagentModel: typeof opts["model-subagent"] === "string" ? opts["model-subagent"] : void 0
|
|
4157
|
+
};
|
|
4158
|
+
}
|
|
4159
|
+
async function ensureModelMapping(providerKey, opts, overrides) {
|
|
4160
|
+
const provider = getProvider(providerKey);
|
|
4161
|
+
if (!provider?.requiresModelMapping) return overrides;
|
|
4162
|
+
const missing = {
|
|
4163
|
+
sonnet: (overrides.sonnet ?? "").trim().length === 0,
|
|
4164
|
+
opus: (overrides.opus ?? "").trim().length === 0,
|
|
4165
|
+
haiku: (overrides.haiku ?? "").trim().length === 0
|
|
4166
|
+
};
|
|
4167
|
+
if (opts.yes && (missing.sonnet || missing.opus || missing.haiku)) {
|
|
4168
|
+
throw new Error("OpenRouter/Local LLMs require --model-sonnet/--model-opus/--model-haiku");
|
|
4169
|
+
}
|
|
4170
|
+
if (!opts.yes) {
|
|
4171
|
+
if (missing.sonnet) overrides.sonnet = await requirePrompt("Default Sonnet model", overrides.sonnet);
|
|
4172
|
+
if (missing.opus) overrides.opus = await requirePrompt("Default Opus model", overrides.opus);
|
|
4173
|
+
if (missing.haiku) overrides.haiku = await requirePrompt("Default Haiku model", overrides.haiku);
|
|
4174
|
+
}
|
|
4175
|
+
return overrides;
|
|
4176
|
+
}
|
|
4177
|
+
function formatModelNote(overrides) {
|
|
4178
|
+
const entries = [
|
|
4179
|
+
["sonnet", overrides.sonnet],
|
|
4180
|
+
["opus", overrides.opus],
|
|
4181
|
+
["haiku", overrides.haiku]
|
|
4182
|
+
].filter(([, value]) => value && String(value).trim().length > 0);
|
|
4183
|
+
if (entries.length === 0) return null;
|
|
4184
|
+
const text = entries.map(([key, value]) => `${key}=${value}`).join(", ");
|
|
4185
|
+
return `Model mapping: ${text}`;
|
|
4186
|
+
}
|
|
4187
|
+
|
|
4188
|
+
// src/cli/utils/promptPack.ts
|
|
4189
|
+
function parsePromptPackMode(value) {
|
|
4190
|
+
if (!value) return void 0;
|
|
4191
|
+
const normalized = value.toLowerCase();
|
|
4192
|
+
if (normalized === "minimal" || normalized === "maximal") return normalized;
|
|
4193
|
+
return void 0;
|
|
4194
|
+
}
|
|
4195
|
+
|
|
4196
|
+
// src/cli/utils/extraEnv.ts
|
|
4197
|
+
function buildExtraEnv(opts) {
|
|
4198
|
+
const env = Array.isArray(opts.env) ? [...opts.env] : [];
|
|
4199
|
+
const timeout = opts["timeout-ms"];
|
|
4200
|
+
if (typeof timeout === "string" && timeout.trim().length > 0) {
|
|
4201
|
+
env.push(`API_TIMEOUT_MS=${timeout}`);
|
|
4202
|
+
}
|
|
4203
|
+
return env;
|
|
4204
|
+
}
|
|
4205
|
+
|
|
4206
|
+
// src/cli/commands/update.ts
|
|
4207
|
+
function runUpdateCommand({ opts }) {
|
|
4208
|
+
const target = opts._ && opts._[0];
|
|
4209
|
+
const rootDir = opts.root || DEFAULT_ROOT;
|
|
4210
|
+
const binDir = opts["bin-dir"] || DEFAULT_BIN_DIR;
|
|
4211
|
+
const names = target ? [target] : listVariants2(rootDir).map((entry) => entry.name);
|
|
4212
|
+
if (names.length === 0) {
|
|
4213
|
+
console.log(`No variants found in ${rootDir}`);
|
|
4214
|
+
return;
|
|
4215
|
+
}
|
|
4216
|
+
const promptPack = opts["no-prompt-pack"] ? false : void 0;
|
|
4217
|
+
const promptPackMode = parsePromptPackMode(opts["prompt-pack-mode"]);
|
|
4218
|
+
const skillInstall = opts["no-skill-install"] ? false : void 0;
|
|
4219
|
+
const skillUpdate = Boolean(opts["skill-update"]);
|
|
4220
|
+
const shellEnv = opts["no-shell-env"] ? false : opts["shell-env"] ? true : void 0;
|
|
4221
|
+
for (const name of names) {
|
|
4222
|
+
const result = updateVariant(rootDir, name, {
|
|
4223
|
+
binDir,
|
|
4224
|
+
npmPackage: opts["npm-package"],
|
|
4225
|
+
brand: opts.brand,
|
|
4226
|
+
noTweak: Boolean(opts.noTweak),
|
|
4227
|
+
promptPack,
|
|
4228
|
+
promptPackMode,
|
|
4229
|
+
skillInstall,
|
|
4230
|
+
shellEnv,
|
|
4231
|
+
skillUpdate
|
|
4232
|
+
});
|
|
4233
|
+
const wrapperPath = path21.join(binDir, name);
|
|
4234
|
+
printSummary({
|
|
4235
|
+
action: "Updated",
|
|
4236
|
+
meta: result.meta,
|
|
4237
|
+
wrapperPath,
|
|
4238
|
+
notes: result.notes
|
|
4239
|
+
});
|
|
4240
|
+
}
|
|
4241
|
+
}
|
|
4242
|
+
|
|
4243
|
+
// src/cli/commands/create.ts
|
|
4244
|
+
async function prepareCreateParams(opts) {
|
|
4245
|
+
let providerKey = opts.provider;
|
|
4246
|
+
if (!providerKey && !opts.yes) {
|
|
4247
|
+
const providers = listProviders().map((p) => p.key).join(", ");
|
|
4248
|
+
providerKey = await prompt(`Provider (${providers})`, "zai");
|
|
4249
|
+
}
|
|
4250
|
+
providerKey = providerKey || "zai";
|
|
4251
|
+
const provider = getProvider(providerKey);
|
|
4252
|
+
if (!provider) {
|
|
4253
|
+
throw new Error(`Unknown provider: ${providerKey}`);
|
|
4254
|
+
}
|
|
4255
|
+
const name = opts.name || providerKey;
|
|
4256
|
+
const baseUrl = opts["base-url"] || provider.baseUrl;
|
|
4257
|
+
const envZaiKey = providerKey === "zai" ? process.env.Z_AI_API_KEY : void 0;
|
|
4258
|
+
const envAnthropicKey = providerKey === "zai" ? process.env.ANTHROPIC_API_KEY : void 0;
|
|
4259
|
+
const hasApiKeyFlag = Boolean(opts["api-key"]);
|
|
4260
|
+
const hasZaiEnv = Boolean(envZaiKey);
|
|
4261
|
+
const apiKeyDetected = !hasApiKeyFlag && hasZaiEnv;
|
|
4262
|
+
const apiKey = opts["api-key"] || (providerKey === "zai" ? envZaiKey || envAnthropicKey || "" : "");
|
|
4263
|
+
if (apiKeyDetected && !opts.yes) {
|
|
4264
|
+
console.log("Detected Z_AI_API_KEY in environment. Using it by default.");
|
|
4265
|
+
}
|
|
4266
|
+
const brand = opts.brand || "auto";
|
|
4267
|
+
const rootDir = opts.root || DEFAULT_ROOT;
|
|
4268
|
+
const binDir = opts["bin-dir"] || DEFAULT_BIN_DIR;
|
|
4269
|
+
const npmPackage = opts["npm-package"] || DEFAULT_NPM_PACKAGE;
|
|
4270
|
+
const extraEnv = buildExtraEnv(opts);
|
|
4271
|
+
const requiresCredential = !provider.credentialOptional;
|
|
4272
|
+
const shouldPromptApiKey = !opts.yes && !hasApiKeyFlag && (providerKey === "zai" ? !hasZaiEnv : !apiKey);
|
|
4273
|
+
return {
|
|
4274
|
+
provider,
|
|
4275
|
+
providerKey,
|
|
4276
|
+
name,
|
|
4277
|
+
baseUrl,
|
|
4278
|
+
apiKey,
|
|
4279
|
+
brand,
|
|
4280
|
+
rootDir,
|
|
4281
|
+
binDir,
|
|
4282
|
+
npmPackage,
|
|
4283
|
+
extraEnv,
|
|
4284
|
+
requiresCredential,
|
|
4285
|
+
shouldPromptApiKey,
|
|
4286
|
+
hasZaiEnv
|
|
4287
|
+
};
|
|
4288
|
+
}
|
|
4289
|
+
async function handleQuickMode(opts, params) {
|
|
4290
|
+
const { provider } = params;
|
|
4291
|
+
const promptPack = opts["no-prompt-pack"] ? false : void 0;
|
|
4292
|
+
const promptPackMode = parsePromptPackMode(opts["prompt-pack-mode"]);
|
|
4293
|
+
const skillInstall = opts["no-skill-install"] ? false : void 0;
|
|
4294
|
+
const skillUpdate = Boolean(opts["skill-update"]);
|
|
4295
|
+
let shellEnv = opts["no-shell-env"] ? false : opts["shell-env"] ? true : void 0;
|
|
4296
|
+
const modelOverrides = getModelOverridesFromArgs(opts);
|
|
4297
|
+
let apiKey = params.apiKey;
|
|
4298
|
+
if (params.shouldPromptApiKey) {
|
|
4299
|
+
apiKey = params.requiresCredential ? await requirePrompt(provider.apiKeyLabel || "ANTHROPIC_API_KEY", apiKey) : await prompt(provider.apiKeyLabel || "ANTHROPIC_API_KEY", apiKey);
|
|
4300
|
+
}
|
|
4301
|
+
if (params.requiresCredential && !apiKey) {
|
|
4302
|
+
if (opts.yes) {
|
|
4303
|
+
throw new Error("Provider API key required (use --api-key)");
|
|
4304
|
+
}
|
|
4305
|
+
apiKey = await requirePrompt(provider.apiKeyLabel || "ANTHROPIC_API_KEY", apiKey);
|
|
4306
|
+
}
|
|
4307
|
+
const resolvedModelOverrides = await ensureModelMapping(params.providerKey, opts, { ...modelOverrides });
|
|
4308
|
+
if (params.providerKey === "zai" && shellEnv === void 0 && !opts.yes) {
|
|
4309
|
+
if (params.hasZaiEnv) {
|
|
4310
|
+
shellEnv = false;
|
|
4311
|
+
} else {
|
|
4312
|
+
const answer = await prompt("Write Z_AI_API_KEY to your shell profile? (yes/no)", "yes");
|
|
4313
|
+
shellEnv = answer.trim().toLowerCase().startsWith("y");
|
|
4314
|
+
}
|
|
4315
|
+
}
|
|
4316
|
+
const result = createVariant({
|
|
4317
|
+
name: params.name,
|
|
4318
|
+
providerKey: params.providerKey,
|
|
4319
|
+
baseUrl: params.baseUrl,
|
|
4320
|
+
apiKey,
|
|
4321
|
+
brand: params.brand,
|
|
4322
|
+
extraEnv: params.extraEnv,
|
|
4323
|
+
rootDir: params.rootDir,
|
|
4324
|
+
binDir: params.binDir,
|
|
4325
|
+
npmPackage: params.npmPackage,
|
|
4326
|
+
noTweak: Boolean(opts.noTweak),
|
|
4327
|
+
promptPack,
|
|
4328
|
+
promptPackMode,
|
|
4329
|
+
skillInstall,
|
|
4330
|
+
shellEnv,
|
|
4331
|
+
skillUpdate,
|
|
4332
|
+
modelOverrides: resolvedModelOverrides
|
|
4333
|
+
});
|
|
4334
|
+
const shareUrl = buildShareUrl(provider.label || params.providerKey, params.name, result.meta.promptPackMode);
|
|
4335
|
+
const modelNote = formatModelNote(resolvedModelOverrides);
|
|
4336
|
+
const notes = [...result.notes || [], ...modelNote ? [modelNote] : []];
|
|
4337
|
+
printSummary({
|
|
4338
|
+
action: "Created",
|
|
4339
|
+
meta: result.meta,
|
|
4340
|
+
wrapperPath: result.wrapperPath,
|
|
4341
|
+
notes: notes.length > 0 ? notes : void 0,
|
|
4342
|
+
shareUrl
|
|
4343
|
+
});
|
|
4344
|
+
}
|
|
4345
|
+
async function handleInteractiveMode(opts, params) {
|
|
4346
|
+
const { provider } = params;
|
|
4347
|
+
const promptPack = opts["no-prompt-pack"] ? false : void 0;
|
|
4348
|
+
const promptPackMode = parsePromptPackMode(opts["prompt-pack-mode"]);
|
|
4349
|
+
const skillInstall = opts["no-skill-install"] ? false : void 0;
|
|
4350
|
+
const skillUpdate = Boolean(opts["skill-update"]);
|
|
4351
|
+
let shellEnv = opts["no-shell-env"] ? false : opts["shell-env"] ? true : void 0;
|
|
4352
|
+
const modelOverrides = getModelOverridesFromArgs(opts);
|
|
4353
|
+
const nextName = await prompt("Variant name", params.name);
|
|
4354
|
+
const nextBase = await prompt("ANTHROPIC_BASE_URL", params.baseUrl);
|
|
4355
|
+
let nextKey = params.shouldPromptApiKey ? params.requiresCredential ? await requirePrompt(provider.apiKeyLabel || "ANTHROPIC_API_KEY", params.apiKey) : await prompt(provider.apiKeyLabel || "ANTHROPIC_API_KEY", params.apiKey) : params.apiKey;
|
|
4356
|
+
if (params.requiresCredential && !nextKey) {
|
|
4357
|
+
nextKey = await requirePrompt(provider.apiKeyLabel || "ANTHROPIC_API_KEY", params.apiKey);
|
|
4358
|
+
}
|
|
4359
|
+
const resolvedModelOverrides = await ensureModelMapping(params.providerKey, opts, { ...modelOverrides });
|
|
4360
|
+
const brandOptions = listBrandPresets().map((item) => item.key).join(", ");
|
|
4361
|
+
const brandHint = brandOptions.length > 0 ? `auto, none, ${brandOptions}` : "auto, none";
|
|
4362
|
+
const nextBrand = await prompt(`Brand preset (${brandHint})`, params.brand);
|
|
4363
|
+
const nextRoot = await prompt("Variants root directory", params.rootDir);
|
|
4364
|
+
const nextBin = await prompt("Wrapper install directory", params.binDir);
|
|
4365
|
+
const nextNpmPackage = await prompt("NPM package", params.npmPackage);
|
|
4366
|
+
const envInput = await prompt("Extra env (KEY=VALUE, comma separated)", params.extraEnv.join(","));
|
|
4367
|
+
const parsedEnv = envInput.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
4368
|
+
if (params.providerKey === "zai" && shellEnv === void 0) {
|
|
4369
|
+
if (params.hasZaiEnv) {
|
|
4370
|
+
shellEnv = false;
|
|
4371
|
+
} else {
|
|
4372
|
+
const answer = await prompt("Write Z_AI_API_KEY to your shell profile? (yes/no)", "yes");
|
|
4373
|
+
shellEnv = answer.trim().toLowerCase().startsWith("y");
|
|
4374
|
+
}
|
|
4375
|
+
}
|
|
4376
|
+
const result = createVariant({
|
|
4377
|
+
name: nextName,
|
|
4378
|
+
providerKey: params.providerKey,
|
|
4379
|
+
baseUrl: nextBase,
|
|
4380
|
+
apiKey: nextKey,
|
|
4381
|
+
brand: nextBrand,
|
|
4382
|
+
extraEnv: parsedEnv,
|
|
4383
|
+
rootDir: nextRoot,
|
|
4384
|
+
binDir: nextBin,
|
|
4385
|
+
npmPackage: nextNpmPackage,
|
|
4386
|
+
noTweak: Boolean(opts.noTweak),
|
|
4387
|
+
promptPack,
|
|
4388
|
+
promptPackMode,
|
|
4389
|
+
skillInstall,
|
|
4390
|
+
shellEnv,
|
|
4391
|
+
skillUpdate,
|
|
4392
|
+
modelOverrides: resolvedModelOverrides
|
|
4393
|
+
});
|
|
4394
|
+
const shareUrl = buildShareUrl(provider.label || params.providerKey, result.meta.name, result.meta.promptPackMode);
|
|
4395
|
+
const modelNote = formatModelNote(resolvedModelOverrides);
|
|
4396
|
+
const notes = [...result.notes || [], ...modelNote ? [modelNote] : []];
|
|
4397
|
+
printSummary({
|
|
4398
|
+
action: "Created",
|
|
4399
|
+
meta: result.meta,
|
|
4400
|
+
wrapperPath: result.wrapperPath,
|
|
4401
|
+
notes: notes.length > 0 ? notes : void 0,
|
|
4402
|
+
shareUrl
|
|
4403
|
+
});
|
|
4404
|
+
}
|
|
4405
|
+
async function handleNonInteractiveMode(opts, params) {
|
|
4406
|
+
const { provider } = params;
|
|
4407
|
+
const promptPack = opts["no-prompt-pack"] ? false : void 0;
|
|
4408
|
+
const promptPackMode = parsePromptPackMode(opts["prompt-pack-mode"]);
|
|
4409
|
+
const skillInstall = opts["no-skill-install"] ? false : void 0;
|
|
4410
|
+
const skillUpdate = Boolean(opts["skill-update"]);
|
|
4411
|
+
const shellEnv = opts["no-shell-env"] ? false : opts["shell-env"] ? true : void 0;
|
|
4412
|
+
const modelOverrides = getModelOverridesFromArgs(opts);
|
|
4413
|
+
if (params.requiresCredential && !params.apiKey) {
|
|
4414
|
+
throw new Error("Provider API key required (use --api-key)");
|
|
4415
|
+
}
|
|
4416
|
+
const resolvedModelOverrides = await ensureModelMapping(params.providerKey, opts, { ...modelOverrides });
|
|
4417
|
+
const result = createVariant({
|
|
4418
|
+
name: params.name,
|
|
4419
|
+
providerKey: params.providerKey,
|
|
4420
|
+
baseUrl: params.baseUrl,
|
|
4421
|
+
apiKey: params.apiKey,
|
|
4422
|
+
brand: params.brand,
|
|
4423
|
+
extraEnv: params.extraEnv,
|
|
4424
|
+
rootDir: params.rootDir,
|
|
4425
|
+
binDir: params.binDir,
|
|
4426
|
+
npmPackage: params.npmPackage,
|
|
4427
|
+
noTweak: Boolean(opts.noTweak),
|
|
4428
|
+
promptPack,
|
|
4429
|
+
promptPackMode,
|
|
4430
|
+
skillInstall,
|
|
4431
|
+
shellEnv,
|
|
4432
|
+
skillUpdate,
|
|
4433
|
+
modelOverrides: resolvedModelOverrides
|
|
4434
|
+
});
|
|
4435
|
+
const shareUrl = buildShareUrl(provider.label || params.providerKey, result.meta.name, result.meta.promptPackMode);
|
|
4436
|
+
const modelNote = formatModelNote(resolvedModelOverrides);
|
|
4437
|
+
const notes = [...result.notes || [], ...modelNote ? [modelNote] : []];
|
|
4438
|
+
printSummary({
|
|
4439
|
+
action: "Created",
|
|
4440
|
+
meta: result.meta,
|
|
4441
|
+
wrapperPath: result.wrapperPath,
|
|
4442
|
+
notes: notes.length > 0 ? notes : void 0,
|
|
4443
|
+
shareUrl
|
|
4444
|
+
});
|
|
4445
|
+
}
|
|
4446
|
+
async function runCreateCommand({ opts, quickMode }) {
|
|
4447
|
+
const params = await prepareCreateParams(opts);
|
|
4448
|
+
if (quickMode) {
|
|
4449
|
+
await handleQuickMode(opts, params);
|
|
4450
|
+
} else if (opts.yes) {
|
|
4451
|
+
await handleNonInteractiveMode(opts, params);
|
|
4452
|
+
} else {
|
|
4453
|
+
await handleInteractiveMode(opts, params);
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
|
|
4457
|
+
// src/cli/index.ts
|
|
4458
|
+
var main = async () => {
|
|
4459
|
+
const argv = process.argv.slice(2);
|
|
4460
|
+
if (argv.length === 0 && process.stdout.isTTY) {
|
|
4461
|
+
await runTui();
|
|
4462
|
+
return;
|
|
4463
|
+
}
|
|
4464
|
+
let cmd = argv.length > 0 && !argv[0].startsWith("-") ? argv.shift() : "create";
|
|
4465
|
+
const opts = parseArgs(argv);
|
|
4466
|
+
const quickMode = cmd === "quick" || Boolean(opts.quick || opts.simple);
|
|
4467
|
+
if (cmd === "quick") cmd = "create";
|
|
4468
|
+
if (cmd === "help" || cmd === "--help" || opts.help) {
|
|
4469
|
+
printHelp();
|
|
4470
|
+
return;
|
|
4471
|
+
}
|
|
4472
|
+
if (opts.haiku) {
|
|
4473
|
+
printHaiku();
|
|
4474
|
+
return;
|
|
4475
|
+
}
|
|
4476
|
+
if (shouldLaunchTui(cmd, opts)) {
|
|
4477
|
+
await runTui();
|
|
4478
|
+
return;
|
|
4479
|
+
}
|
|
4480
|
+
switch (cmd) {
|
|
4481
|
+
case "list":
|
|
4482
|
+
runListCommand({ opts });
|
|
4483
|
+
break;
|
|
4484
|
+
case "doctor":
|
|
4485
|
+
runDoctorCommand({ opts });
|
|
4486
|
+
break;
|
|
4487
|
+
case "update":
|
|
4488
|
+
runUpdateCommand({ opts });
|
|
4489
|
+
break;
|
|
4490
|
+
case "remove":
|
|
4491
|
+
runRemoveCommand({ opts });
|
|
4492
|
+
break;
|
|
4493
|
+
case "tweak":
|
|
4494
|
+
runTweakCommand({ opts });
|
|
4495
|
+
break;
|
|
4496
|
+
case "create":
|
|
4497
|
+
await runCreateCommand({ opts, quickMode });
|
|
4498
|
+
break;
|
|
4499
|
+
default:
|
|
4500
|
+
printHelp();
|
|
4501
|
+
}
|
|
4502
|
+
};
|
|
4503
|
+
main().catch((error) => {
|
|
4504
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
4505
|
+
process.exit(1);
|
|
4506
|
+
});
|