ccjk 13.3.18 → 13.3.19
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/dist/chunks/api-cli.mjs +1 -1
- package/dist/chunks/api.mjs +1 -1
- package/dist/chunks/auto-fix.mjs +4 -4
- package/dist/chunks/boost.mjs +1 -1
- package/dist/chunks/ccjk-mcp.mjs +2 -2
- package/dist/chunks/ccr.mjs +24 -20
- package/dist/chunks/check-updates.mjs +2 -1
- package/dist/chunks/claude-code-config-manager.mjs +4 -4
- package/dist/chunks/claude-code-incremental-manager.mjs +5 -5
- package/dist/chunks/claude-config.mjs +2 -2
- package/dist/chunks/claude-wrapper.mjs +1 -1
- package/dist/chunks/codex-config-switch.mjs +4 -3
- package/dist/chunks/codex-provider-manager.mjs +2 -1
- package/dist/chunks/codex.mjs +4 -332
- package/dist/chunks/config-switch.mjs +2 -1
- package/dist/chunks/config.mjs +424 -358
- package/dist/chunks/config2.mjs +358 -424
- package/dist/chunks/config3.mjs +6 -1
- package/dist/chunks/doctor.mjs +2 -2
- package/dist/chunks/features.mjs +812 -0
- package/dist/chunks/index.mjs +1 -1
- package/dist/chunks/init.mjs +43 -89
- package/dist/chunks/installer.mjs +1 -1
- package/dist/chunks/mcp-cli.mjs +18 -17
- package/dist/chunks/mcp.mjs +5 -4
- package/dist/chunks/menu-hierarchical.mjs +27 -23
- package/dist/chunks/menu.mjs +17 -791
- package/dist/chunks/onboarding-wizard.mjs +2 -2
- package/dist/chunks/package.mjs +1 -1
- package/dist/chunks/platform.mjs +1 -1
- package/dist/chunks/quick-setup.mjs +14 -11
- package/dist/chunks/slash-commands.mjs +1 -1
- package/dist/chunks/uninstall.mjs +1 -1
- package/dist/chunks/update.mjs +17 -15
- package/dist/cli.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/shared/ccjk.0aJQmVxS.mjs +336 -0
- package/dist/shared/ccjk.C3o4BXvM.mjs +444 -0
- package/dist/shared/{ccjk.DfZKjHvG.mjs → ccjk.Dgq22o6V.mjs} +2 -438
- package/dist/shared/{ccjk.KpFl2RDA.mjs → ccjk.LTONy3IS.mjs} +4 -3
- package/dist/shared/ccjk.Si-T_ccK.mjs +75 -0
- package/dist/shared/{ccjk.I6IuYdc_.mjs → ccjk.Xla_pE3y.mjs} +1 -1
- package/dist/shared/{ccjk.DZ4ehAHg.mjs → ccjk.byom1b8z.mjs} +1 -1
- package/package.json +1 -1
package/dist/chunks/config2.mjs
CHANGED
|
@@ -1,478 +1,412 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { existsSync, copyFileSync, mkdirSync } from 'node:fs';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
|
-
import process__default from 'node:process';
|
|
5
|
-
import { promisify } from 'node:util';
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
6
2
|
import a from './index2.mjs';
|
|
7
3
|
import { d as dayjs } from '../shared/ccjk.RyizuzOI.mjs';
|
|
8
4
|
import { i as inquirer } from './index3.mjs';
|
|
9
|
-
import { SETTINGS_FILE } from './constants.mjs';
|
|
5
|
+
import { CLAUDE_DIR, SETTINGS_FILE, CLAUDE_VSC_CONFIG_FILE, AI_OUTPUT_LANGUAGES } from './constants.mjs';
|
|
10
6
|
import { ensureI18nInitialized, i18n } from './index5.mjs';
|
|
11
|
-
import { s as setPrimaryApiKey,
|
|
12
|
-
import {
|
|
7
|
+
import { s as setPrimaryApiKey, c as addCompletedOnboarding, d as deepMerge } from './claude-config.mjs';
|
|
8
|
+
import { exists, ensureDir, copyDir, writeFileAtomic, copyFile } from './fs-operations.mjs';
|
|
13
9
|
import { readJsonConfig, writeJsonConfig } from './json-config.mjs';
|
|
14
|
-
import {
|
|
15
|
-
import { j as join } from '../shared/ccjk.bQ7Dh1g4.mjs';
|
|
16
|
-
import '../shared/ccjk.BAGoDD49.mjs';
|
|
17
|
-
import 'node:readline';
|
|
18
|
-
import 'stream';
|
|
19
|
-
import 'node:tty';
|
|
20
|
-
import 'node:async_hooks';
|
|
21
|
-
import '../shared/ccjk.Cjgrln_h.mjs';
|
|
22
|
-
import 'tty';
|
|
23
|
-
import 'fs';
|
|
24
|
-
import 'child_process';
|
|
25
|
-
import 'node:path';
|
|
26
|
-
import 'node:crypto';
|
|
27
|
-
import 'buffer';
|
|
28
|
-
import 'string_decoder';
|
|
29
|
-
import 'node:url';
|
|
30
|
-
import './platform.mjs';
|
|
31
|
-
import './main.mjs';
|
|
32
|
-
import 'module';
|
|
33
|
-
import 'node:stream';
|
|
34
|
-
import './fs-operations.mjs';
|
|
35
|
-
import 'node:fs/promises';
|
|
36
|
-
import '../shared/ccjk.DScm_NnL.mjs';
|
|
37
|
-
import '../shared/ccjk.DeWpAShp.mjs';
|
|
10
|
+
import { m as mergeAndCleanPermissions } from '../shared/ccjk.DScm_NnL.mjs';
|
|
11
|
+
import { j as join, d as dirname } from '../shared/ccjk.bQ7Dh1g4.mjs';
|
|
38
12
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (Array.isArray(data)) {
|
|
54
|
-
for (const provider of data) {
|
|
55
|
-
if (provider && typeof provider === "object") {
|
|
56
|
-
presets.push({
|
|
57
|
-
name: provider.name || "",
|
|
58
|
-
provider: provider.name || "",
|
|
59
|
-
baseURL: provider.api_base_url || provider.baseURL || provider.url,
|
|
60
|
-
requiresApiKey: provider.api_key === "" || provider.requiresApiKey !== false,
|
|
61
|
-
models: provider.models || [],
|
|
62
|
-
description: provider.description || provider.name || "",
|
|
63
|
-
transformer: provider.transformer
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
} else if (data && typeof data === "object") {
|
|
68
|
-
for (const [key, value] of Object.entries(data)) {
|
|
69
|
-
if (typeof value === "object" && value !== null) {
|
|
70
|
-
const provider = value;
|
|
71
|
-
presets.push({
|
|
72
|
-
name: provider.name || key,
|
|
73
|
-
provider: key,
|
|
74
|
-
baseURL: provider.api_base_url || provider.baseURL || provider.url,
|
|
75
|
-
requiresApiKey: provider.api_key === "" || provider.requiresApiKey !== false,
|
|
76
|
-
models: provider.models || [],
|
|
77
|
-
description: provider.description || "",
|
|
78
|
-
transformer: provider.transformer
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
}
|
|
13
|
+
const MODEL_ENV_KEYS = [
|
|
14
|
+
"ANTHROPIC_MODEL",
|
|
15
|
+
"ANTHROPIC_DEFAULT_HAIKU_MODEL",
|
|
16
|
+
"ANTHROPIC_DEFAULT_SONNET_MODEL",
|
|
17
|
+
"ANTHROPIC_DEFAULT_OPUS_MODEL",
|
|
18
|
+
// Deprecated but still cleaned to avoid stale values
|
|
19
|
+
"ANTHROPIC_SMALL_FAST_MODEL"
|
|
20
|
+
];
|
|
21
|
+
function clearModelEnv(env, mode = "reset") {
|
|
22
|
+
for (const key of MODEL_ENV_KEYS) {
|
|
23
|
+
if (mode === "reset" && key === "ANTHROPIC_MODEL") {
|
|
24
|
+
env[key] = "";
|
|
25
|
+
} else {
|
|
26
|
+
delete env[key];
|
|
82
27
|
}
|
|
83
|
-
return presets;
|
|
84
|
-
} catch {
|
|
85
|
-
return getFallbackPresets();
|
|
86
28
|
}
|
|
87
29
|
}
|
|
88
|
-
function getFallbackPresets() {
|
|
89
|
-
return [
|
|
90
|
-
{
|
|
91
|
-
name: "dashscope",
|
|
92
|
-
provider: "dashscope",
|
|
93
|
-
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",
|
|
94
|
-
requiresApiKey: true,
|
|
95
|
-
models: ["qwen3-coder-plus"],
|
|
96
|
-
description: "Alibaba DashScope",
|
|
97
|
-
transformer: {
|
|
98
|
-
"use": [["maxtoken", { max_tokens: 65536 }]],
|
|
99
|
-
"qwen3-coder-plus": {
|
|
100
|
-
use: ["enhancetool"]
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
name: "deepseek",
|
|
106
|
-
provider: "deepseek",
|
|
107
|
-
baseURL: "https://api.deepseek.com/chat/completions",
|
|
108
|
-
requiresApiKey: true,
|
|
109
|
-
models: ["deepseek-chat", "deepseek-reasoner"],
|
|
110
|
-
description: "DeepSeek AI models",
|
|
111
|
-
transformer: {
|
|
112
|
-
"use": ["deepseek"],
|
|
113
|
-
"deepseek-chat": {
|
|
114
|
-
use: ["tooluse"]
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
name: "gemini",
|
|
120
|
-
provider: "gemini",
|
|
121
|
-
baseURL: "https://generativelanguage.googleapis.com/v1beta/models/",
|
|
122
|
-
requiresApiKey: true,
|
|
123
|
-
models: ["gemini-2.5-flash", "gemini-2.5-pro"],
|
|
124
|
-
description: "Google Gemini models",
|
|
125
|
-
transformer: {
|
|
126
|
-
use: ["gemini"]
|
|
127
|
-
}
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
name: "modelscope",
|
|
131
|
-
provider: "modelscope",
|
|
132
|
-
baseURL: "https://api-inference.modelscope.cn/v1/chat/completions",
|
|
133
|
-
requiresApiKey: true,
|
|
134
|
-
models: ["Qwen/Qwen3-Coder-480B-A35B-Instruct", "Qwen/Qwen3-235B-A22B-Thinking-2507", "ZhipuAI/GLM-4.5"],
|
|
135
|
-
description: "ModelScope AI models",
|
|
136
|
-
transformer: {
|
|
137
|
-
"use": [["maxtoken", { max_tokens: 65536 }]],
|
|
138
|
-
"Qwen/Qwen3-Coder-480B-A35B-Instruct": {
|
|
139
|
-
use: ["enhancetool"]
|
|
140
|
-
},
|
|
141
|
-
"Qwen/Qwen3-235B-A22B-Thinking-2507": {
|
|
142
|
-
use: ["reasoning"]
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
name: "openrouter",
|
|
148
|
-
provider: "openrouter",
|
|
149
|
-
baseURL: "https://openrouter.ai/api/v1/chat/completions",
|
|
150
|
-
requiresApiKey: true,
|
|
151
|
-
models: [
|
|
152
|
-
"google/gemini-2.5-pro-preview",
|
|
153
|
-
"anthropic/claude-sonnet-4",
|
|
154
|
-
"anthropic/claude-3.5-sonnet",
|
|
155
|
-
"anthropic/claude-3.7-sonnet:thinking"
|
|
156
|
-
],
|
|
157
|
-
description: "OpenRouter API",
|
|
158
|
-
transformer: {
|
|
159
|
-
use: ["openrouter"]
|
|
160
|
-
}
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
name: "siliconflow",
|
|
164
|
-
provider: "siliconflow",
|
|
165
|
-
baseURL: "https://api.siliconflow.cn/v1/chat/completions",
|
|
166
|
-
requiresApiKey: true,
|
|
167
|
-
models: ["moonshotai/Kimi-K2-Instruct"],
|
|
168
|
-
description: "SiliconFlow AI",
|
|
169
|
-
transformer: {
|
|
170
|
-
use: [["maxtoken", { max_tokens: 16384 }]]
|
|
171
|
-
}
|
|
172
|
-
},
|
|
173
|
-
{
|
|
174
|
-
name: "volcengine",
|
|
175
|
-
provider: "volcengine",
|
|
176
|
-
baseURL: "https://ark.cn-beijing.volces.com/api/v3/chat/completions",
|
|
177
|
-
requiresApiKey: true,
|
|
178
|
-
models: ["deepseek-v3-250324", "deepseek-r1-250528"],
|
|
179
|
-
description: "Volcengine AI",
|
|
180
|
-
transformer: {
|
|
181
|
-
use: ["deepseek"]
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
];
|
|
185
|
-
}
|
|
186
30
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const CCR_CONFIG_FILE = join(CCR_CONFIG_DIR, "config.json");
|
|
190
|
-
const CCR_BACKUP_DIR = CCR_CONFIG_DIR;
|
|
191
|
-
function ensureCcrConfigDir() {
|
|
192
|
-
if (!existsSync(CCR_CONFIG_DIR)) {
|
|
193
|
-
mkdirSync(CCR_CONFIG_DIR, { recursive: true });
|
|
194
|
-
}
|
|
31
|
+
function ensureClaudeDir() {
|
|
32
|
+
ensureDir(CLAUDE_DIR);
|
|
195
33
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
try {
|
|
199
|
-
if (!existsSync(CCR_CONFIG_FILE)) {
|
|
200
|
-
return null;
|
|
201
|
-
}
|
|
202
|
-
const timestamp = `${dayjs().format("YYYY-MM-DDTHH-mm-ss-SSS")}Z`;
|
|
203
|
-
const backupFileName = `config.json.${timestamp}.bak`;
|
|
204
|
-
const backupPath = join(CCR_BACKUP_DIR, backupFileName);
|
|
205
|
-
console.log(a.green(`${i18n.t("ccr:backupCcrConfig")}`));
|
|
206
|
-
copyFileSync(CCR_CONFIG_FILE, backupPath);
|
|
207
|
-
console.log(a.green(`\u2714 ${i18n.t("ccr:ccrBackupSuccess").replace("{path}", backupPath)}`));
|
|
208
|
-
return backupPath;
|
|
209
|
-
} catch (error) {
|
|
210
|
-
console.error(a.red(`${i18n.t("ccr:ccrBackupFailed")}:`), error.message);
|
|
34
|
+
function backupExistingConfig() {
|
|
35
|
+
if (!exists(CLAUDE_DIR)) {
|
|
211
36
|
return null;
|
|
212
37
|
}
|
|
38
|
+
const timestamp = dayjs().format("YYYY-MM-DD_HH-mm-ss");
|
|
39
|
+
const backupBaseDir = join(CLAUDE_DIR, "backup");
|
|
40
|
+
const backupDir = join(backupBaseDir, `backup_${timestamp}`);
|
|
41
|
+
ensureDir(backupDir);
|
|
42
|
+
const filter = (path) => {
|
|
43
|
+
return !path.includes("/backup");
|
|
44
|
+
};
|
|
45
|
+
copyDir(CLAUDE_DIR, backupDir, { filter });
|
|
46
|
+
return backupDir;
|
|
213
47
|
}
|
|
214
|
-
function
|
|
215
|
-
|
|
216
|
-
|
|
48
|
+
function copyConfigFiles(onlyMd = false) {
|
|
49
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
50
|
+
const distDir = dirname(dirname(currentFilePath));
|
|
51
|
+
const rootDir = dirname(distDir);
|
|
52
|
+
const baseTemplateDir = join(rootDir, "templates", "claude-code");
|
|
53
|
+
if (!onlyMd) {
|
|
54
|
+
const baseSettingsPath = join(baseTemplateDir, "common", "settings.json");
|
|
55
|
+
const destSettingsPath = join(CLAUDE_DIR, "settings.json");
|
|
56
|
+
if (exists(baseSettingsPath)) {
|
|
57
|
+
mergeSettingsFile(baseSettingsPath, destSettingsPath);
|
|
58
|
+
}
|
|
217
59
|
}
|
|
218
|
-
return readJsonConfig(CCR_CONFIG_FILE);
|
|
219
|
-
}
|
|
220
|
-
function writeCcrConfig(config) {
|
|
221
|
-
ensureCcrConfigDir();
|
|
222
|
-
writeJsonConfig(CCR_CONFIG_FILE, config);
|
|
223
60
|
}
|
|
224
|
-
|
|
225
|
-
const settings = readJsonConfig(SETTINGS_FILE) || {};
|
|
226
|
-
const host = ccrConfig.HOST || "127.0.0.1";
|
|
227
|
-
const port = ccrConfig.PORT || 3456;
|
|
228
|
-
const apiKey = ccrConfig.APIKEY || "sk-ccjk-x-ccr";
|
|
229
|
-
if (!settings.env) {
|
|
230
|
-
settings.env = {};
|
|
231
|
-
}
|
|
232
|
-
delete settings.env.ANTHROPIC_AUTH_TOKEN;
|
|
233
|
-
settings.env.ANTHROPIC_BASE_URL = `http://${host}:${port}`;
|
|
234
|
-
settings.env.ANTHROPIC_API_KEY = apiKey;
|
|
235
|
-
writeJsonConfig(SETTINGS_FILE, settings);
|
|
61
|
+
function getDefaultSettings() {
|
|
236
62
|
try {
|
|
237
|
-
|
|
63
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
64
|
+
const distDir = dirname(dirname(currentFilePath));
|
|
65
|
+
const rootDir = dirname(distDir);
|
|
66
|
+
const templateSettingsPath = join(rootDir, "templates", "claude-code", "common", "settings.json");
|
|
67
|
+
return readJsonConfig(templateSettingsPath) || {};
|
|
238
68
|
} catch (error) {
|
|
239
|
-
|
|
240
|
-
|
|
69
|
+
console.error("Failed to read template settings", error);
|
|
70
|
+
return {};
|
|
241
71
|
}
|
|
242
72
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
console.log(a.green(`${i18n.t("ccr:fetchingPresets")}`));
|
|
246
|
-
const presets = await fetchProviderPresets();
|
|
247
|
-
if (!presets || presets.length === 0) {
|
|
248
|
-
console.log(a.yellow(`${i18n.t("ccr:noPresetsAvailable")}`));
|
|
73
|
+
function configureApi(apiConfig) {
|
|
74
|
+
if (!apiConfig)
|
|
249
75
|
return null;
|
|
76
|
+
const existingSettings = readJsonConfig(SETTINGS_FILE);
|
|
77
|
+
let settings;
|
|
78
|
+
if (existingSettings) {
|
|
79
|
+
settings = existingSettings;
|
|
80
|
+
} else {
|
|
81
|
+
settings = getDefaultSettings();
|
|
250
82
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
{
|
|
254
|
-
name: `1. ${i18n.t("ccr:skipOption")}`,
|
|
255
|
-
value: "skip"
|
|
256
|
-
},
|
|
257
|
-
...presets.map((p, index) => ({
|
|
258
|
-
name: `${index + 2}. ${p.name}`,
|
|
259
|
-
value: p
|
|
260
|
-
}))
|
|
261
|
-
];
|
|
262
|
-
const { preset } = await inquirer.prompt({
|
|
263
|
-
type: "list",
|
|
264
|
-
name: "preset",
|
|
265
|
-
message: i18n.t("ccr:selectCcrPreset"),
|
|
266
|
-
choices
|
|
267
|
-
});
|
|
268
|
-
return preset;
|
|
269
|
-
} catch (error) {
|
|
270
|
-
if (error.name === "ExitPromptError") {
|
|
271
|
-
console.log(a.yellow(i18n.t("common:cancelled")));
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
throw error;
|
|
83
|
+
if (!settings.env) {
|
|
84
|
+
settings.env = {};
|
|
275
85
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
api_base_url: preset.baseURL || "",
|
|
283
|
-
api_key: "",
|
|
284
|
-
models: preset.models
|
|
285
|
-
};
|
|
286
|
-
if (preset.transformer) {
|
|
287
|
-
provider.transformer = preset.transformer;
|
|
86
|
+
if (apiConfig.authType === "api_key") {
|
|
87
|
+
settings.env.ANTHROPIC_API_KEY = apiConfig.key;
|
|
88
|
+
delete settings.env.ANTHROPIC_AUTH_TOKEN;
|
|
89
|
+
} else if (apiConfig.authType === "auth_token") {
|
|
90
|
+
settings.env.ANTHROPIC_AUTH_TOKEN = apiConfig.key;
|
|
91
|
+
delete settings.env.ANTHROPIC_API_KEY;
|
|
288
92
|
}
|
|
289
|
-
if (
|
|
290
|
-
|
|
291
|
-
const { apiKey } = await inquirer.prompt({
|
|
292
|
-
type: "input",
|
|
293
|
-
name: "apiKey",
|
|
294
|
-
message: i18n.t("ccr:enterApiKeyForProvider").replace("{provider}", preset.name),
|
|
295
|
-
validate: async (value) => !!value || i18n.t("api:keyRequired")
|
|
296
|
-
});
|
|
297
|
-
provider.api_key = apiKey;
|
|
298
|
-
} catch (error) {
|
|
299
|
-
if (error.name === "ExitPromptError") {
|
|
300
|
-
throw error;
|
|
301
|
-
}
|
|
302
|
-
throw error;
|
|
303
|
-
}
|
|
304
|
-
} else {
|
|
305
|
-
provider.api_key = "sk-free";
|
|
93
|
+
if (apiConfig.url) {
|
|
94
|
+
settings.env.ANTHROPIC_BASE_URL = apiConfig.url;
|
|
306
95
|
}
|
|
307
|
-
|
|
308
|
-
if (
|
|
96
|
+
writeJsonConfig(SETTINGS_FILE, settings);
|
|
97
|
+
if (apiConfig.authType) {
|
|
309
98
|
try {
|
|
310
|
-
|
|
311
|
-
type: "list",
|
|
312
|
-
name: "model",
|
|
313
|
-
message: i18n.t("ccr:selectDefaultModelForProvider").replace("{provider}", preset.name),
|
|
314
|
-
choices: preset.models.map((m, index) => ({
|
|
315
|
-
name: `${index + 1}. ${m}`,
|
|
316
|
-
value: m
|
|
317
|
-
}))
|
|
318
|
-
});
|
|
319
|
-
defaultModel = model;
|
|
99
|
+
setPrimaryApiKey();
|
|
320
100
|
} catch (error) {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
324
|
-
throw error;
|
|
101
|
+
ensureI18nInitialized();
|
|
102
|
+
console.error(i18n.t("mcp:primaryApiKeySetFailed"), error);
|
|
325
103
|
}
|
|
326
104
|
}
|
|
327
|
-
const router = {
|
|
328
|
-
default: `${preset.name},${defaultModel}`,
|
|
329
|
-
// Use the original name
|
|
330
|
-
background: `${preset.name},${defaultModel}`,
|
|
331
|
-
think: `${preset.name},${defaultModel}`,
|
|
332
|
-
longContext: `${preset.name},${defaultModel}`,
|
|
333
|
-
longContextThreshold: 6e4,
|
|
334
|
-
webSearch: `${preset.name},${defaultModel}`
|
|
335
|
-
};
|
|
336
|
-
const config = {
|
|
337
|
-
LOG: true,
|
|
338
|
-
CLAUDE_PATH: "",
|
|
339
|
-
HOST: "127.0.0.1",
|
|
340
|
-
PORT: 3456,
|
|
341
|
-
APIKEY: "sk-ccjk-x-ccr",
|
|
342
|
-
API_TIMEOUT_MS: "600000",
|
|
343
|
-
PROXY_URL: "",
|
|
344
|
-
transformers: [],
|
|
345
|
-
Providers: [provider],
|
|
346
|
-
Router: router
|
|
347
|
-
};
|
|
348
|
-
return config;
|
|
349
|
-
}
|
|
350
|
-
async function restartAndCheckCcrStatus() {
|
|
351
|
-
ensureI18nInitialized();
|
|
352
105
|
try {
|
|
353
|
-
|
|
354
|
-
await execAsync("ccr restart");
|
|
355
|
-
console.log(a.green(`\u2714 ${i18n.t("ccr:ccrRestartSuccess")}`));
|
|
356
|
-
console.log(a.green(`${i18n.t("ccr:checkingCcrStatus")}`));
|
|
357
|
-
const { stdout } = await execAsync("ccr status");
|
|
358
|
-
console.log(a.gray(stdout));
|
|
106
|
+
addCompletedOnboarding();
|
|
359
107
|
} catch (error) {
|
|
360
|
-
console.error(
|
|
361
|
-
|
|
362
|
-
|
|
108
|
+
console.error("Failed to set onboarding flag", error);
|
|
109
|
+
}
|
|
110
|
+
const verification = readJsonConfig(SETTINGS_FILE);
|
|
111
|
+
if (verification?.env) {
|
|
112
|
+
const envKey = apiConfig.authType === "api_key" ? "ANTHROPIC_API_KEY" : "ANTHROPIC_AUTH_TOKEN";
|
|
113
|
+
if (verification.env[envKey] !== apiConfig.key) {
|
|
114
|
+
console.error(a.red("\u26A0 API config write verification failed \u2014 retrying..."));
|
|
115
|
+
const freshSettings = readJsonConfig(SETTINGS_FILE) || settings;
|
|
116
|
+
if (!freshSettings.env)
|
|
117
|
+
freshSettings.env = {};
|
|
118
|
+
if (apiConfig.authType === "api_key") {
|
|
119
|
+
freshSettings.env.ANTHROPIC_API_KEY = apiConfig.key;
|
|
120
|
+
delete freshSettings.env.ANTHROPIC_AUTH_TOKEN;
|
|
121
|
+
} else if (apiConfig.authType === "auth_token") {
|
|
122
|
+
freshSettings.env.ANTHROPIC_AUTH_TOKEN = apiConfig.key;
|
|
123
|
+
delete freshSettings.env.ANTHROPIC_API_KEY;
|
|
124
|
+
}
|
|
125
|
+
if (apiConfig.url) {
|
|
126
|
+
freshSettings.env.ANTHROPIC_BASE_URL = apiConfig.url;
|
|
127
|
+
}
|
|
128
|
+
writeJsonConfig(SETTINGS_FILE, freshSettings);
|
|
363
129
|
}
|
|
364
130
|
}
|
|
131
|
+
return apiConfig;
|
|
365
132
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
console.log(a.gray(` ${i18n.t("ccr:ccrUiApiKeyHint") || "Use this API key to login to CCR UI"}`));
|
|
376
|
-
}
|
|
377
|
-
console.log("");
|
|
378
|
-
}
|
|
379
|
-
function createDefaultCcrConfig() {
|
|
380
|
-
return {
|
|
381
|
-
LOG: false,
|
|
382
|
-
CLAUDE_PATH: "",
|
|
383
|
-
HOST: "127.0.0.1",
|
|
384
|
-
PORT: 3456,
|
|
385
|
-
APIKEY: "sk-ccjk-x-ccr",
|
|
386
|
-
API_TIMEOUT_MS: "600000",
|
|
387
|
-
PROXY_URL: "",
|
|
388
|
-
transformers: [],
|
|
389
|
-
Providers: [],
|
|
390
|
-
// Empty providers array - user configures in UI
|
|
391
|
-
Router: {}
|
|
392
|
-
// Empty router configuration - user configures in UI
|
|
133
|
+
function configureHooks(hooks) {
|
|
134
|
+
let settings = getDefaultSettings();
|
|
135
|
+
const existingSettings = readJsonConfig(SETTINGS_FILE);
|
|
136
|
+
if (existingSettings) {
|
|
137
|
+
settings = existingSettings;
|
|
138
|
+
}
|
|
139
|
+
settings.hooks = {
|
|
140
|
+
...settings.hooks || {},
|
|
141
|
+
...hooks
|
|
393
142
|
};
|
|
143
|
+
writeJsonConfig(SETTINGS_FILE, settings);
|
|
394
144
|
}
|
|
395
|
-
|
|
396
|
-
|
|
145
|
+
function mergeConfigs(sourceFile, targetFile) {
|
|
146
|
+
if (!exists(sourceFile))
|
|
147
|
+
return;
|
|
148
|
+
const target = readJsonConfig(targetFile) || {};
|
|
149
|
+
const source = readJsonConfig(sourceFile) || {};
|
|
150
|
+
const merged = deepMerge(target, source);
|
|
151
|
+
writeJsonConfig(targetFile, merged);
|
|
152
|
+
}
|
|
153
|
+
function updateCustomModel(primaryModel, haikuModel, sonnetModel, opusModel) {
|
|
154
|
+
if (!primaryModel?.trim() && !haikuModel?.trim() && !sonnetModel?.trim() && !opusModel?.trim()) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
let settings = getDefaultSettings();
|
|
158
|
+
const existingSettings = readJsonConfig(SETTINGS_FILE);
|
|
159
|
+
if (existingSettings) {
|
|
160
|
+
settings = existingSettings;
|
|
161
|
+
}
|
|
162
|
+
delete settings.model;
|
|
163
|
+
settings.env = settings.env || {};
|
|
164
|
+
clearModelEnv(settings.env, "override");
|
|
165
|
+
if (primaryModel?.trim()) {
|
|
166
|
+
settings.env.ANTHROPIC_MODEL = primaryModel.trim();
|
|
167
|
+
}
|
|
168
|
+
if (haikuModel?.trim()) {
|
|
169
|
+
settings.env.ANTHROPIC_SMALL_FAST_MODEL = haikuModel.trim();
|
|
170
|
+
settings.env.ANTHROPIC_DEFAULT_HAIKU_MODEL = haikuModel.trim();
|
|
171
|
+
}
|
|
172
|
+
if (sonnetModel?.trim())
|
|
173
|
+
settings.env.ANTHROPIC_DEFAULT_SONNET_MODEL = sonnetModel.trim();
|
|
174
|
+
if (opusModel?.trim())
|
|
175
|
+
settings.env.ANTHROPIC_DEFAULT_OPUS_MODEL = opusModel.trim();
|
|
176
|
+
writeJsonConfig(SETTINGS_FILE, settings);
|
|
177
|
+
}
|
|
178
|
+
function updateDefaultModel(model) {
|
|
179
|
+
let settings = getDefaultSettings();
|
|
180
|
+
const existingSettings = readJsonConfig(SETTINGS_FILE);
|
|
181
|
+
if (existingSettings) {
|
|
182
|
+
settings = existingSettings;
|
|
183
|
+
}
|
|
184
|
+
if (!settings.env) {
|
|
185
|
+
settings.env = {};
|
|
186
|
+
}
|
|
187
|
+
if (model !== "custom") {
|
|
188
|
+
clearModelEnv(settings.env);
|
|
189
|
+
}
|
|
190
|
+
if (model === "default" || model === "custom") {
|
|
191
|
+
delete settings.model;
|
|
192
|
+
} else {
|
|
193
|
+
settings.model = model;
|
|
194
|
+
}
|
|
195
|
+
writeJsonConfig(SETTINGS_FILE, settings);
|
|
196
|
+
}
|
|
197
|
+
function mergeSettingsFile(templatePath, targetPath) {
|
|
397
198
|
try {
|
|
398
|
-
const
|
|
399
|
-
if (
|
|
400
|
-
console.
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
199
|
+
const templateSettings = readJsonConfig(templatePath);
|
|
200
|
+
if (!templateSettings) {
|
|
201
|
+
console.error("Failed to read template settings");
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (!exists(targetPath)) {
|
|
205
|
+
copyFile(templatePath, targetPath);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const existingSettings = readJsonConfig(targetPath) || {};
|
|
209
|
+
const mergedEnv = {
|
|
210
|
+
...templateSettings.env || {},
|
|
211
|
+
// Template env vars first
|
|
212
|
+
...existingSettings.env || {}
|
|
213
|
+
// User's env vars override (preserving API keys, etc.)
|
|
214
|
+
};
|
|
215
|
+
const mergedSettings = { ...templateSettings };
|
|
216
|
+
const schemaCriticalFields = [
|
|
217
|
+
"$schema",
|
|
218
|
+
"attribution",
|
|
219
|
+
"fileSuggestion",
|
|
220
|
+
"permissions"
|
|
221
|
+
];
|
|
222
|
+
const removeNullFields = [
|
|
223
|
+
"plansDirectory",
|
|
224
|
+
"contextFiles"
|
|
225
|
+
];
|
|
226
|
+
for (const [key, value] of Object.entries(existingSettings)) {
|
|
227
|
+
if (!schemaCriticalFields.includes(key)) {
|
|
228
|
+
if (removeNullFields.includes(key) && value === null) {
|
|
229
|
+
continue;
|
|
424
230
|
}
|
|
425
|
-
|
|
231
|
+
mergedSettings[key] = value;
|
|
426
232
|
}
|
|
427
|
-
backupCcrConfig();
|
|
428
233
|
}
|
|
429
|
-
|
|
430
|
-
if (
|
|
431
|
-
|
|
234
|
+
mergedSettings.env = mergedEnv;
|
|
235
|
+
if (mergedSettings.permissions && mergedSettings.permissions.allow) {
|
|
236
|
+
mergedSettings.permissions.allow = mergeAndCleanPermissions(
|
|
237
|
+
templateSettings.permissions?.allow,
|
|
238
|
+
existingSettings.permissions?.allow
|
|
239
|
+
);
|
|
432
240
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
241
|
+
if (mergedSettings.plansDirectory === null) {
|
|
242
|
+
delete mergedSettings.plansDirectory;
|
|
243
|
+
}
|
|
244
|
+
writeJsonConfig(targetPath, mergedSettings);
|
|
245
|
+
} catch (error) {
|
|
246
|
+
console.error("Failed to merge settings", error);
|
|
247
|
+
if (exists(targetPath)) {
|
|
248
|
+
console.log("Preserving existing settings");
|
|
437
249
|
} else {
|
|
438
|
-
|
|
250
|
+
copyFile(templatePath, targetPath);
|
|
439
251
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function getExistingModelConfig() {
|
|
255
|
+
const settings = readJsonConfig(SETTINGS_FILE);
|
|
256
|
+
if (!settings) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
const hasModelEnv = MODEL_ENV_KEYS.some((key) => {
|
|
260
|
+
const value = settings.env?.[key];
|
|
261
|
+
return value !== void 0 && value !== null && value !== "";
|
|
262
|
+
});
|
|
263
|
+
if (hasModelEnv) {
|
|
264
|
+
return "custom";
|
|
265
|
+
}
|
|
266
|
+
if (!settings.model) {
|
|
267
|
+
return "default";
|
|
268
|
+
}
|
|
269
|
+
const validModels = ["opus", "sonnet", "sonnet[1m]"];
|
|
270
|
+
if (validModels.includes(settings.model)) {
|
|
271
|
+
return settings.model;
|
|
272
|
+
}
|
|
273
|
+
return "default";
|
|
274
|
+
}
|
|
275
|
+
function getExistingCustomModelConfig() {
|
|
276
|
+
const settings = readJsonConfig(SETTINGS_FILE);
|
|
277
|
+
if (!settings || !settings.env) {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
const {
|
|
281
|
+
ANTHROPIC_MODEL,
|
|
282
|
+
ANTHROPIC_SMALL_FAST_MODEL,
|
|
283
|
+
ANTHROPIC_DEFAULT_HAIKU_MODEL,
|
|
284
|
+
ANTHROPIC_DEFAULT_SONNET_MODEL,
|
|
285
|
+
ANTHROPIC_DEFAULT_OPUS_MODEL
|
|
286
|
+
} = settings.env;
|
|
287
|
+
if (!ANTHROPIC_MODEL && !ANTHROPIC_DEFAULT_HAIKU_MODEL && !ANTHROPIC_DEFAULT_SONNET_MODEL && !ANTHROPIC_DEFAULT_OPUS_MODEL) {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
return {
|
|
291
|
+
primaryModel: ANTHROPIC_MODEL,
|
|
292
|
+
haikuModel: ANTHROPIC_DEFAULT_HAIKU_MODEL || ANTHROPIC_SMALL_FAST_MODEL,
|
|
293
|
+
sonnetModel: ANTHROPIC_DEFAULT_SONNET_MODEL,
|
|
294
|
+
opusModel: ANTHROPIC_DEFAULT_OPUS_MODEL
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
function getExistingApiConfig() {
|
|
298
|
+
const settings = readJsonConfig(SETTINGS_FILE);
|
|
299
|
+
if (!settings || !settings.env) {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
const { ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_BASE_URL } = settings.env;
|
|
303
|
+
if (!ANTHROPIC_BASE_URL && !ANTHROPIC_API_KEY && !ANTHROPIC_AUTH_TOKEN) {
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
let authType;
|
|
307
|
+
let key;
|
|
308
|
+
if (ANTHROPIC_AUTH_TOKEN) {
|
|
309
|
+
authType = "auth_token";
|
|
310
|
+
key = ANTHROPIC_AUTH_TOKEN;
|
|
311
|
+
} else if (ANTHROPIC_API_KEY) {
|
|
312
|
+
authType = "api_key";
|
|
313
|
+
key = ANTHROPIC_API_KEY;
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
url: ANTHROPIC_BASE_URL || "",
|
|
317
|
+
key: key || "",
|
|
318
|
+
authType
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
function applyAiLanguageDirective(aiOutputLang) {
|
|
322
|
+
const claudeFile = join(CLAUDE_DIR, "CLAUDE.md");
|
|
323
|
+
let directive = "";
|
|
324
|
+
if (aiOutputLang === "custom") {
|
|
325
|
+
return;
|
|
326
|
+
} else if (AI_OUTPUT_LANGUAGES[aiOutputLang]) {
|
|
327
|
+
directive = AI_OUTPUT_LANGUAGES[aiOutputLang].directive;
|
|
328
|
+
} else {
|
|
329
|
+
directive = `Always respond in ${aiOutputLang}`;
|
|
330
|
+
}
|
|
331
|
+
const frontmatter = "---\nscope: user\n---";
|
|
332
|
+
writeFileAtomic(claudeFile, `${frontmatter}
|
|
333
|
+
|
|
334
|
+
${directive}`);
|
|
335
|
+
}
|
|
336
|
+
function switchToOfficialLogin() {
|
|
337
|
+
try {
|
|
338
|
+
ensureI18nInitialized();
|
|
339
|
+
const settings = readJsonConfig(SETTINGS_FILE) || {};
|
|
340
|
+
if (settings.env) {
|
|
341
|
+
delete settings.env.ANTHROPIC_BASE_URL;
|
|
342
|
+
delete settings.env.ANTHROPIC_AUTH_TOKEN;
|
|
343
|
+
delete settings.env.ANTHROPIC_API_KEY;
|
|
450
344
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
} catch (error) {
|
|
457
|
-
console.error(a.red(`${i18n.t("ccr:apiKeyApprovalFailed")}:`), error);
|
|
345
|
+
writeJsonConfig(SETTINGS_FILE, settings);
|
|
346
|
+
const vscConfig = readJsonConfig(CLAUDE_VSC_CONFIG_FILE);
|
|
347
|
+
if (vscConfig) {
|
|
348
|
+
delete vscConfig.primaryApiKey;
|
|
349
|
+
writeJsonConfig(CLAUDE_VSC_CONFIG_FILE, vscConfig);
|
|
458
350
|
}
|
|
351
|
+
console.log(i18n.t("api:officialLoginConfigured"));
|
|
459
352
|
return true;
|
|
460
353
|
} catch (error) {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
return false;
|
|
464
|
-
}
|
|
465
|
-
console.error(a.red(`${i18n.t("ccr:ccrConfigFailed")}:`), error);
|
|
354
|
+
ensureI18nInitialized();
|
|
355
|
+
console.error(i18n.t("api:officialLoginFailed"), error);
|
|
466
356
|
return false;
|
|
467
357
|
}
|
|
468
358
|
}
|
|
469
|
-
async function
|
|
359
|
+
async function promptApiConfigurationAction() {
|
|
470
360
|
ensureI18nInitialized();
|
|
471
|
-
const
|
|
472
|
-
if (
|
|
473
|
-
|
|
361
|
+
const existingConfig = getExistingApiConfig();
|
|
362
|
+
if (!existingConfig) {
|
|
363
|
+
return null;
|
|
474
364
|
}
|
|
475
|
-
|
|
365
|
+
console.log(`
|
|
366
|
+
${a.green(`\u2139 ${i18n.t("api:existingApiConfig")}`)}`);
|
|
367
|
+
console.log(a.gray(` ${i18n.t("api:apiConfigUrl")}: ${existingConfig.url || "N/A"}`));
|
|
368
|
+
console.log(a.gray(` ${i18n.t("api:apiConfigKey")}: ${existingConfig.key ? `***${existingConfig.key.slice(-4)}` : "N/A"}`));
|
|
369
|
+
console.log(a.gray(` ${i18n.t("api:apiConfigAuthType")}: ${existingConfig.authType || "N/A"}
|
|
370
|
+
`));
|
|
371
|
+
const { choice } = await inquirer.prompt({
|
|
372
|
+
type: "list",
|
|
373
|
+
name: "choice",
|
|
374
|
+
message: i18n.t("api:selectCustomConfigAction"),
|
|
375
|
+
choices: [
|
|
376
|
+
{
|
|
377
|
+
name: i18n.t("api:modifyPartialConfig"),
|
|
378
|
+
value: "modify-partial"
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
name: i18n.t("api:modifyAllConfig"),
|
|
382
|
+
value: "modify-all"
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
name: i18n.t("api:keepExistingConfig"),
|
|
386
|
+
value: "keep-existing"
|
|
387
|
+
}
|
|
388
|
+
]
|
|
389
|
+
});
|
|
390
|
+
return choice || null;
|
|
476
391
|
}
|
|
477
392
|
|
|
478
|
-
|
|
393
|
+
const config = {
|
|
394
|
+
__proto__: null,
|
|
395
|
+
applyAiLanguageDirective: applyAiLanguageDirective,
|
|
396
|
+
backupExistingConfig: backupExistingConfig,
|
|
397
|
+
configureApi: configureApi,
|
|
398
|
+
configureHooks: configureHooks,
|
|
399
|
+
copyConfigFiles: copyConfigFiles,
|
|
400
|
+
ensureClaudeDir: ensureClaudeDir,
|
|
401
|
+
getExistingApiConfig: getExistingApiConfig,
|
|
402
|
+
getExistingCustomModelConfig: getExistingCustomModelConfig,
|
|
403
|
+
getExistingModelConfig: getExistingModelConfig,
|
|
404
|
+
mergeConfigs: mergeConfigs,
|
|
405
|
+
mergeSettingsFile: mergeSettingsFile,
|
|
406
|
+
promptApiConfigurationAction: promptApiConfigurationAction,
|
|
407
|
+
switchToOfficialLogin: switchToOfficialLogin,
|
|
408
|
+
updateCustomModel: updateCustomModel,
|
|
409
|
+
updateDefaultModel: updateDefaultModel
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
export { getExistingCustomModelConfig as a, backupExistingConfig as b, copyConfigFiles as c, updateDefaultModel as d, applyAiLanguageDirective as e, getExistingApiConfig as f, getExistingModelConfig as g, configureApi as h, clearModelEnv as i, ensureClaudeDir as j, config as k, promptApiConfigurationAction as p, switchToOfficialLogin as s, updateCustomModel as u };
|