ccjk 9.6.1 → 9.8.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/dist/chunks/boost.mjs +246 -7
- package/dist/chunks/ccjk-mcp.mjs +1 -1
- package/dist/chunks/ccr.mjs +25 -28
- package/dist/chunks/check-updates.mjs +4 -3
- package/dist/chunks/claude-code-config-manager.mjs +1 -1
- package/dist/chunks/claude-code-incremental-manager.mjs +1 -1
- package/dist/chunks/claude-config.mjs +1 -1
- package/dist/chunks/codex-config-switch.mjs +3 -4
- package/dist/chunks/codex-provider-manager.mjs +1 -2
- package/dist/chunks/codex.mjs +204 -3
- package/dist/chunks/config-switch.mjs +2 -3
- package/dist/chunks/config.mjs +1 -1
- package/dist/chunks/doctor.mjs +1 -1
- package/dist/chunks/features.mjs +24 -15
- package/dist/chunks/hook-installer.mjs +44 -0
- package/dist/chunks/index3.mjs +32 -32
- package/dist/chunks/init.mjs +129 -87
- package/dist/chunks/installer2.mjs +1 -1
- package/dist/chunks/interview.mjs +1 -1
- package/dist/chunks/mcp.mjs +1058 -17
- package/dist/chunks/menu.mjs +140 -56
- package/dist/chunks/package.mjs +2 -210
- package/dist/chunks/platform.mjs +1 -1
- package/dist/chunks/quick-setup.mjs +35 -18
- package/dist/chunks/simple-config.mjs +1 -1
- package/dist/{shared/ccjk.q1koQxEE.mjs → chunks/smart-defaults.mjs} +77 -79
- package/dist/chunks/status.mjs +208 -101
- package/dist/chunks/thinking.mjs +1 -1
- package/dist/chunks/uninstall.mjs +6 -4
- package/dist/chunks/update.mjs +4 -7
- package/dist/chunks/version-checker.mjs +1 -1
- package/dist/cli.mjs +4 -80
- package/dist/index.d.mts +17 -1482
- package/dist/index.d.ts +17 -1482
- package/dist/index.mjs +12 -4191
- package/dist/shared/{ccjk.CSkyCZIM.mjs → ccjk.Bndhan7G.mjs} +4 -242
- package/dist/shared/ccjk.CeE8RLG2.mjs +62 -0
- package/dist/shared/ccjk.DKojSRzw.mjs +266 -0
- package/dist/shared/{ccjk.CItD1fpl.mjs → ccjk.DvIrK0wz.mjs} +1 -1
- package/dist/shared/ccjk.LsPZ2PYo.mjs +1048 -0
- package/package.json +1 -1
- package/dist/chunks/api-adapter.mjs +0 -180
- package/dist/chunks/cli.mjs +0 -2227
- package/dist/chunks/context-menu.mjs +0 -913
- package/dist/chunks/hooks-sync.mjs +0 -1627
- package/dist/chunks/mcp-market.mjs +0 -1077
- package/dist/chunks/mcp-server.mjs +0 -776
- package/dist/chunks/project-detector.mjs +0 -131
- package/dist/chunks/provider-registry.mjs +0 -92
- package/dist/chunks/setup-wizard.mjs +0 -362
- package/dist/chunks/tools.mjs +0 -143
- package/dist/chunks/workflows2.mjs +0 -232
- package/dist/shared/ccjk.C0pb50xH.mjs +0 -347
- package/dist/shared/ccjk.ChMkBmdL.mjs +0 -490
- package/dist/shared/ccjk.CtSfXUSh.mjs +0 -209
- package/dist/shared/ccjk.xfAjmbJp.mjs +0 -75
|
@@ -1,490 +0,0 @@
|
|
|
1
|
-
import ansis from 'ansis';
|
|
2
|
-
import inquirer from 'inquirer';
|
|
3
|
-
import { CLAUDE_DIR, SETTINGS_FILE } from '../chunks/constants.mjs';
|
|
4
|
-
import { ensureI18nInitialized, i18n } from '../chunks/index.mjs';
|
|
5
|
-
import { m as mergeAndCleanPermissions, g as getExistingApiConfig, h as configureApi, s as switchToOfficialLogin, b as backupExistingConfig, d as applyAiLanguageDirective } from '../chunks/config.mjs';
|
|
6
|
-
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import { join, dirname } from 'pathe';
|
|
8
|
-
import { updateZcfConfig } from '../chunks/ccjk-config.mjs';
|
|
9
|
-
import { exists, removeFile, ensureDir, copyFile } from '../chunks/fs-operations.mjs';
|
|
10
|
-
import { readJsonConfig, writeJsonConfig } from '../chunks/json-config.mjs';
|
|
11
|
-
import { a as addNumbersToChoices } from './ccjk.BFQ7yr5S.mjs';
|
|
12
|
-
import { p as promptBoolean } from './ccjk.DHbrGcgg.mjs';
|
|
13
|
-
|
|
14
|
-
const OUTPUT_STYLES = [
|
|
15
|
-
// Custom styles (have template files) - 大神模式
|
|
16
|
-
{
|
|
17
|
-
id: "linus-mode",
|
|
18
|
-
isCustom: true,
|
|
19
|
-
filePath: "linus-mode.md"
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
id: "uncle-bob-mode",
|
|
23
|
-
isCustom: true,
|
|
24
|
-
filePath: "uncle-bob-mode.md"
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
id: "dhh-mode",
|
|
28
|
-
isCustom: true,
|
|
29
|
-
filePath: "dhh-mode.md"
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
id: "carmack-mode",
|
|
33
|
-
isCustom: true,
|
|
34
|
-
filePath: "carmack-mode.md"
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
id: "jobs-mode",
|
|
38
|
-
isCustom: true,
|
|
39
|
-
filePath: "jobs-mode.md"
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
id: "evan-you-mode",
|
|
43
|
-
isCustom: true,
|
|
44
|
-
filePath: "evan-you-mode.md"
|
|
45
|
-
},
|
|
46
|
-
// Built-in styles (no template files) - Claude Code native styles
|
|
47
|
-
{
|
|
48
|
-
id: "default",
|
|
49
|
-
isCustom: false
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
id: "explanatory",
|
|
53
|
-
isCustom: false
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
id: "learning",
|
|
57
|
-
isCustom: false
|
|
58
|
-
}
|
|
59
|
-
];
|
|
60
|
-
const LEGACY_FILES = ["personality.md", "rules.md", "technical-guides.md", "mcp.md", "language.md"];
|
|
61
|
-
function getAvailableOutputStyles() {
|
|
62
|
-
return OUTPUT_STYLES;
|
|
63
|
-
}
|
|
64
|
-
async function copyOutputStyles(selectedStyles, lang) {
|
|
65
|
-
const outputStylesDir = join(CLAUDE_DIR, "output-styles");
|
|
66
|
-
ensureDir(outputStylesDir);
|
|
67
|
-
const currentFilePath = fileURLToPath(import.meta.url);
|
|
68
|
-
const distDir = dirname(dirname(currentFilePath));
|
|
69
|
-
const rootDir = dirname(distDir);
|
|
70
|
-
const templateDir = join(rootDir, "templates", "common", "output-styles", lang);
|
|
71
|
-
for (const styleId of selectedStyles) {
|
|
72
|
-
const style = OUTPUT_STYLES.find((s) => s.id === styleId);
|
|
73
|
-
if (!style || !style.isCustom || !style.filePath) {
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
const sourcePath = join(templateDir, style.filePath);
|
|
77
|
-
const destPath = join(outputStylesDir, style.filePath);
|
|
78
|
-
if (exists(sourcePath)) {
|
|
79
|
-
copyFile(sourcePath, destPath);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function setGlobalDefaultOutputStyle(styleId) {
|
|
84
|
-
const templatePermissions = getTemplatePermissions();
|
|
85
|
-
const existingSettings = readJsonConfig(SETTINGS_FILE) || {};
|
|
86
|
-
const cleanedPermissions = mergeAndCleanPermissions(
|
|
87
|
-
templatePermissions,
|
|
88
|
-
existingSettings.permissions?.allow
|
|
89
|
-
);
|
|
90
|
-
const updatedSettings = {
|
|
91
|
-
...existingSettings,
|
|
92
|
-
outputStyle: styleId,
|
|
93
|
-
// Ensure clean permissions
|
|
94
|
-
permissions: {
|
|
95
|
-
allow: cleanedPermissions
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
if (updatedSettings.plansDirectory === null) {
|
|
99
|
-
delete updatedSettings.plansDirectory;
|
|
100
|
-
}
|
|
101
|
-
writeJsonConfig(SETTINGS_FILE, updatedSettings);
|
|
102
|
-
}
|
|
103
|
-
function getTemplatePermissions() {
|
|
104
|
-
try {
|
|
105
|
-
const { readFileSync } = require("node:fs");
|
|
106
|
-
const { fileURLToPath: fileURLToPath2 } = require("node:url");
|
|
107
|
-
const { dirname: dirname2, join: join2 } = require("pathe");
|
|
108
|
-
const currentFilePath = fileURLToPath2(import.meta.url);
|
|
109
|
-
const distDir = dirname2(dirname2(currentFilePath));
|
|
110
|
-
const rootDir = dirname2(distDir);
|
|
111
|
-
const templatePath = join2(rootDir, "templates", "claude-code", "common", "settings.json");
|
|
112
|
-
if (require("node:fs").existsSync(templatePath)) {
|
|
113
|
-
const template = JSON.parse(readFileSync(templatePath, "utf-8"));
|
|
114
|
-
return template.permissions?.allow || [];
|
|
115
|
-
}
|
|
116
|
-
} catch (_error) {
|
|
117
|
-
}
|
|
118
|
-
return [
|
|
119
|
-
"AllowEdit",
|
|
120
|
-
"AllowWrite",
|
|
121
|
-
"AllowRead",
|
|
122
|
-
"AllowExec",
|
|
123
|
-
"AllowCreateProcess",
|
|
124
|
-
"AllowKillProcess",
|
|
125
|
-
"AllowNetworkAccess",
|
|
126
|
-
"AllowFileSystemAccess",
|
|
127
|
-
"AllowShellAccess",
|
|
128
|
-
"AllowHttpAccess"
|
|
129
|
-
];
|
|
130
|
-
}
|
|
131
|
-
function hasLegacyPersonalityFiles() {
|
|
132
|
-
return LEGACY_FILES.some((filename) => exists(join(CLAUDE_DIR, filename)));
|
|
133
|
-
}
|
|
134
|
-
function cleanupLegacyPersonalityFiles() {
|
|
135
|
-
LEGACY_FILES.forEach((filename) => {
|
|
136
|
-
const filePath = join(CLAUDE_DIR, filename);
|
|
137
|
-
if (exists(filePath)) {
|
|
138
|
-
removeFile(filePath);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
async function configureOutputStyle(preselectedStyles, preselectedDefault) {
|
|
143
|
-
ensureI18nInitialized();
|
|
144
|
-
const outputStyleList = [
|
|
145
|
-
{
|
|
146
|
-
id: "default",
|
|
147
|
-
name: i18n.t("configuration:outputStyles.default.name"),
|
|
148
|
-
description: i18n.t("configuration:outputStyles.default.description")
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
id: "linus-mode",
|
|
152
|
-
name: i18n.t("configuration:outputStyles.linus-mode.name"),
|
|
153
|
-
description: i18n.t("configuration:outputStyles.linus-mode.description")
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
id: "uncle-bob-mode",
|
|
157
|
-
name: i18n.t("configuration:outputStyles.uncle-bob-mode.name"),
|
|
158
|
-
description: i18n.t("configuration:outputStyles.uncle-bob-mode.description")
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
id: "dhh-mode",
|
|
162
|
-
name: i18n.t("configuration:outputStyles.dhh-mode.name"),
|
|
163
|
-
description: i18n.t("configuration:outputStyles.dhh-mode.description")
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
id: "carmack-mode",
|
|
167
|
-
name: i18n.t("configuration:outputStyles.carmack-mode.name"),
|
|
168
|
-
description: i18n.t("configuration:outputStyles.carmack-mode.description")
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
id: "jobs-mode",
|
|
172
|
-
name: i18n.t("configuration:outputStyles.jobs-mode.name"),
|
|
173
|
-
description: i18n.t("configuration:outputStyles.jobs-mode.description")
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
id: "evan-you-mode",
|
|
177
|
-
name: i18n.t("configuration:outputStyles.evan-you-mode.name"),
|
|
178
|
-
description: i18n.t("configuration:outputStyles.evan-you-mode.description")
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
id: "explanatory",
|
|
182
|
-
name: i18n.t("configuration:outputStyles.explanatory.name"),
|
|
183
|
-
description: i18n.t("configuration:outputStyles.explanatory.description")
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
id: "learning",
|
|
187
|
-
name: i18n.t("configuration:outputStyles.learning.name"),
|
|
188
|
-
description: i18n.t("configuration:outputStyles.learning.description")
|
|
189
|
-
}
|
|
190
|
-
];
|
|
191
|
-
const availableStyles = getAvailableOutputStyles();
|
|
192
|
-
if (hasLegacyPersonalityFiles() && !preselectedStyles) {
|
|
193
|
-
console.log(ansis.yellow(`\u26A0\uFE0F ${i18n.t("configuration:legacyFilesDetected")}`));
|
|
194
|
-
const cleanupLegacy = await promptBoolean({
|
|
195
|
-
message: i18n.t("configuration:cleanupLegacyFiles"),
|
|
196
|
-
defaultValue: true
|
|
197
|
-
});
|
|
198
|
-
if (cleanupLegacy) {
|
|
199
|
-
cleanupLegacyPersonalityFiles();
|
|
200
|
-
console.log(ansis.green(`\u2714 ${i18n.t("configuration:legacyFilesRemoved")}`));
|
|
201
|
-
}
|
|
202
|
-
} else if (hasLegacyPersonalityFiles() && preselectedStyles) {
|
|
203
|
-
cleanupLegacyPersonalityFiles();
|
|
204
|
-
}
|
|
205
|
-
let selectedStyles;
|
|
206
|
-
let defaultStyle;
|
|
207
|
-
if (preselectedStyles && preselectedDefault) {
|
|
208
|
-
selectedStyles = preselectedStyles;
|
|
209
|
-
defaultStyle = preselectedDefault;
|
|
210
|
-
} else {
|
|
211
|
-
const customStyles = availableStyles.filter((style) => style.isCustom);
|
|
212
|
-
const { selectedStyles: promptedStyles } = await inquirer.prompt({
|
|
213
|
-
type: "checkbox",
|
|
214
|
-
name: "selectedStyles",
|
|
215
|
-
message: `${i18n.t("configuration:selectOutputStyles")}${i18n.t("common:multiSelectHint")}`,
|
|
216
|
-
choices: addNumbersToChoices(customStyles.map((style) => {
|
|
217
|
-
const styleInfo = outputStyleList.find((s) => s.id === style.id);
|
|
218
|
-
return {
|
|
219
|
-
name: `${styleInfo?.name || style.id} - ${ansis.gray(styleInfo?.description || "")}`,
|
|
220
|
-
value: style.id,
|
|
221
|
-
checked: true
|
|
222
|
-
// Default to all selected
|
|
223
|
-
};
|
|
224
|
-
})),
|
|
225
|
-
validate: async (input) => input.length > 0 || i18n.t("configuration:selectAtLeastOne")
|
|
226
|
-
});
|
|
227
|
-
if (!promptedStyles || promptedStyles.length === 0) {
|
|
228
|
-
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
selectedStyles = promptedStyles;
|
|
232
|
-
const { defaultStyle: promptedDefault } = await inquirer.prompt({
|
|
233
|
-
type: "list",
|
|
234
|
-
name: "defaultStyle",
|
|
235
|
-
message: i18n.t("configuration:selectDefaultOutputStyle"),
|
|
236
|
-
choices: addNumbersToChoices([
|
|
237
|
-
// Show selected custom styles first (only what user actually installed)
|
|
238
|
-
...selectedStyles.map((styleId) => {
|
|
239
|
-
const styleInfo = outputStyleList.find((s) => s.id === styleId);
|
|
240
|
-
return {
|
|
241
|
-
name: `${styleInfo?.name || styleId} - ${ansis.gray(styleInfo?.description || "")}`,
|
|
242
|
-
value: styleId,
|
|
243
|
-
short: styleInfo?.name || styleId
|
|
244
|
-
};
|
|
245
|
-
}),
|
|
246
|
-
// Then show all built-in styles (always available)
|
|
247
|
-
...availableStyles.filter((style) => !style.isCustom).map((style) => {
|
|
248
|
-
const styleInfo = outputStyleList.find((s) => s.id === style.id);
|
|
249
|
-
return {
|
|
250
|
-
name: `${styleInfo?.name || style.id} - ${ansis.gray(styleInfo?.description || "")}`,
|
|
251
|
-
value: style.id,
|
|
252
|
-
short: styleInfo?.name || style.id
|
|
253
|
-
};
|
|
254
|
-
})
|
|
255
|
-
]),
|
|
256
|
-
default: selectedStyles.includes("linus-mode") ? "linus-mode" : selectedStyles[0]
|
|
257
|
-
});
|
|
258
|
-
if (!promptedDefault) {
|
|
259
|
-
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
defaultStyle = promptedDefault;
|
|
263
|
-
}
|
|
264
|
-
await copyOutputStyles(selectedStyles, "zh-CN");
|
|
265
|
-
setGlobalDefaultOutputStyle(defaultStyle);
|
|
266
|
-
updateZcfConfig({
|
|
267
|
-
outputStyles: selectedStyles,
|
|
268
|
-
defaultOutputStyle: defaultStyle
|
|
269
|
-
});
|
|
270
|
-
console.log(ansis.green(`\u2714 ${i18n.t("configuration:outputStyleInstalled")}`));
|
|
271
|
-
console.log(ansis.gray(` ${i18n.t("configuration:selectedStyles")}: ${selectedStyles.join(", ")}`));
|
|
272
|
-
console.log(ansis.gray(` ${i18n.t("configuration:defaultStyle")}: ${defaultStyle}`));
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function validateApiKey(apiKey) {
|
|
276
|
-
if (!apiKey || apiKey.trim() === "") {
|
|
277
|
-
return {
|
|
278
|
-
isValid: false,
|
|
279
|
-
// Note: This should use i18next, but due to sync constraint in inquirer validate,
|
|
280
|
-
// we temporarily use a generic message. This will be fixed when we refactor to async validation.
|
|
281
|
-
error: "API key cannot be empty"
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
return { isValid: true };
|
|
285
|
-
}
|
|
286
|
-
function formatApiKeyDisplay(apiKey) {
|
|
287
|
-
if (!apiKey || apiKey.length < 12) {
|
|
288
|
-
return apiKey;
|
|
289
|
-
}
|
|
290
|
-
return `${apiKey.substring(0, 8)}...${apiKey.substring(apiKey.length - 4)}`;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
async function configureApiCompletely(preselectedAuthType) {
|
|
294
|
-
ensureI18nInitialized();
|
|
295
|
-
let authType = preselectedAuthType;
|
|
296
|
-
if (!authType) {
|
|
297
|
-
const { authType: selectedAuthType } = await inquirer.prompt({
|
|
298
|
-
type: "list",
|
|
299
|
-
name: "authType",
|
|
300
|
-
message: i18n.t("api:configureApi"),
|
|
301
|
-
choices: addNumbersToChoices([
|
|
302
|
-
{
|
|
303
|
-
name: i18n.t("api:useOfficialLogin"),
|
|
304
|
-
value: "official",
|
|
305
|
-
short: i18n.t("api:useOfficialLogin")
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
name: `${i18n.t("api:useAuthToken")} - ${ansis.gray(i18n.t("api:authTokenDesc"))}`,
|
|
309
|
-
value: "auth_token",
|
|
310
|
-
short: i18n.t("api:useAuthToken")
|
|
311
|
-
},
|
|
312
|
-
{
|
|
313
|
-
name: `${i18n.t("api:useApiKey")} - ${ansis.gray(i18n.t("api:apiKeyDesc"))}`,
|
|
314
|
-
value: "api_key",
|
|
315
|
-
short: i18n.t("api:useApiKey")
|
|
316
|
-
}
|
|
317
|
-
])
|
|
318
|
-
});
|
|
319
|
-
if (!selectedAuthType) {
|
|
320
|
-
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
321
|
-
return null;
|
|
322
|
-
}
|
|
323
|
-
authType = selectedAuthType;
|
|
324
|
-
}
|
|
325
|
-
if (authType === "official") {
|
|
326
|
-
const success = switchToOfficialLogin();
|
|
327
|
-
if (success) {
|
|
328
|
-
return null;
|
|
329
|
-
} else {
|
|
330
|
-
console.log(ansis.red(i18n.t("api:officialLoginFailed")));
|
|
331
|
-
return null;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
const { url } = await inquirer.prompt({
|
|
335
|
-
type: "input",
|
|
336
|
-
name: "url",
|
|
337
|
-
message: i18n.t("api:enterApiUrl"),
|
|
338
|
-
validate: async (value) => {
|
|
339
|
-
if (!value)
|
|
340
|
-
return i18n.t("api:urlRequired");
|
|
341
|
-
try {
|
|
342
|
-
void new URL(value);
|
|
343
|
-
return true;
|
|
344
|
-
} catch {
|
|
345
|
-
return i18n.t("api:invalidUrl");
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
});
|
|
349
|
-
if (url === void 0) {
|
|
350
|
-
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
351
|
-
return null;
|
|
352
|
-
}
|
|
353
|
-
const keyMessage = authType === "auth_token" ? i18n.t("api:enterAuthToken") : i18n.t("api:enterApiKey");
|
|
354
|
-
const { key } = await inquirer.prompt({
|
|
355
|
-
type: "input",
|
|
356
|
-
name: "key",
|
|
357
|
-
message: keyMessage,
|
|
358
|
-
validate: async (value) => {
|
|
359
|
-
if (!value) {
|
|
360
|
-
return i18n.t("api:keyRequired");
|
|
361
|
-
}
|
|
362
|
-
const validation = validateApiKey(value);
|
|
363
|
-
if (!validation.isValid) {
|
|
364
|
-
return validation.error || i18n.t("api:invalidKeyFormat");
|
|
365
|
-
}
|
|
366
|
-
return true;
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
if (key === void 0) {
|
|
370
|
-
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
371
|
-
return null;
|
|
372
|
-
}
|
|
373
|
-
console.log(ansis.gray(` API Key: ${formatApiKeyDisplay(key)}`));
|
|
374
|
-
return { url, key, authType };
|
|
375
|
-
}
|
|
376
|
-
async function modifyApiConfigPartially(existingConfig) {
|
|
377
|
-
ensureI18nInitialized();
|
|
378
|
-
let currentConfig = { ...existingConfig };
|
|
379
|
-
const latestConfig = getExistingApiConfig();
|
|
380
|
-
if (latestConfig) {
|
|
381
|
-
currentConfig = latestConfig;
|
|
382
|
-
}
|
|
383
|
-
const { item } = await inquirer.prompt({
|
|
384
|
-
type: "list",
|
|
385
|
-
name: "item",
|
|
386
|
-
message: i18n.t("api:selectModifyItems"),
|
|
387
|
-
choices: addNumbersToChoices([
|
|
388
|
-
{ name: i18n.t("api:modifyApiUrl"), value: "url" },
|
|
389
|
-
{ name: i18n.t("api:modifyApiKey"), value: "key" },
|
|
390
|
-
{ name: i18n.t("api:modifyAuthType"), value: "authType" }
|
|
391
|
-
])
|
|
392
|
-
});
|
|
393
|
-
if (!item) {
|
|
394
|
-
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
if (item === "url") {
|
|
398
|
-
const { url } = await inquirer.prompt({
|
|
399
|
-
type: "input",
|
|
400
|
-
name: "url",
|
|
401
|
-
message: i18n.t("api:enterNewApiUrl").replace("{url}", currentConfig.url || i18n.t("common:none")),
|
|
402
|
-
default: currentConfig.url,
|
|
403
|
-
validate: async (value) => {
|
|
404
|
-
if (!value)
|
|
405
|
-
return i18n.t("api:urlRequired");
|
|
406
|
-
try {
|
|
407
|
-
void new URL(value);
|
|
408
|
-
return true;
|
|
409
|
-
} catch {
|
|
410
|
-
return i18n.t("api:invalidUrl");
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
});
|
|
414
|
-
if (url === void 0) {
|
|
415
|
-
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
currentConfig.url = url;
|
|
419
|
-
const savedConfig = configureApi(currentConfig);
|
|
420
|
-
if (savedConfig) {
|
|
421
|
-
console.log(ansis.green(`\u2714 ${i18n.t("api:modificationSaved")}`));
|
|
422
|
-
console.log(ansis.gray(` ${i18n.t("api:apiConfigUrl")}: ${savedConfig.url}`));
|
|
423
|
-
}
|
|
424
|
-
} else if (item === "key") {
|
|
425
|
-
const authType = currentConfig.authType || "auth_token";
|
|
426
|
-
const keyMessage = authType === "auth_token" ? i18n.t("api:enterNewApiKey").replace("{key}", currentConfig.key ? formatApiKeyDisplay(currentConfig.key) : i18n.t("common:none")) : i18n.t("api:enterNewApiKey").replace("{key}", currentConfig.key ? formatApiKeyDisplay(currentConfig.key) : i18n.t("common:none"));
|
|
427
|
-
const { key } = await inquirer.prompt({
|
|
428
|
-
type: "input",
|
|
429
|
-
name: "key",
|
|
430
|
-
message: keyMessage,
|
|
431
|
-
validate: async (value) => {
|
|
432
|
-
if (!value) {
|
|
433
|
-
return i18n.t("api:keyRequired");
|
|
434
|
-
}
|
|
435
|
-
const validation = validateApiKey(value);
|
|
436
|
-
if (!validation.isValid) {
|
|
437
|
-
return validation.error || i18n.t("api:invalidKeyFormat");
|
|
438
|
-
}
|
|
439
|
-
return true;
|
|
440
|
-
}
|
|
441
|
-
});
|
|
442
|
-
if (key === void 0) {
|
|
443
|
-
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
currentConfig.key = key;
|
|
447
|
-
const savedConfig = configureApi(currentConfig);
|
|
448
|
-
if (savedConfig) {
|
|
449
|
-
console.log(ansis.green(`\u2714 ${i18n.t("api:modificationSaved")}`));
|
|
450
|
-
console.log(ansis.gray(` ${i18n.t("api:apiConfigKey")}: ${formatApiKeyDisplay(savedConfig.key)}`));
|
|
451
|
-
}
|
|
452
|
-
} else if (item === "authType") {
|
|
453
|
-
const { authType } = await inquirer.prompt({
|
|
454
|
-
type: "list",
|
|
455
|
-
name: "authType",
|
|
456
|
-
message: i18n.t("api:selectNewAuthType").replace("{type}", currentConfig.authType || i18n.t("common:none")),
|
|
457
|
-
choices: addNumbersToChoices([
|
|
458
|
-
{ name: "Auth Token (OAuth)", value: "auth_token" },
|
|
459
|
-
{ name: "API Key", value: "api_key" }
|
|
460
|
-
]),
|
|
461
|
-
default: currentConfig.authType === "api_key" ? 1 : 0
|
|
462
|
-
});
|
|
463
|
-
if (authType === void 0) {
|
|
464
|
-
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
465
|
-
return;
|
|
466
|
-
}
|
|
467
|
-
currentConfig.authType = authType;
|
|
468
|
-
const savedConfig = configureApi(currentConfig);
|
|
469
|
-
if (savedConfig) {
|
|
470
|
-
console.log(ansis.green(`\u2714 ${i18n.t("api:modificationSaved")}`));
|
|
471
|
-
console.log(ansis.gray(` ${i18n.t("api:apiConfigAuthType")}: ${savedConfig.authType}`));
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
async function updatePromptOnly(aiOutputLang) {
|
|
476
|
-
ensureI18nInitialized();
|
|
477
|
-
const backupDir = backupExistingConfig();
|
|
478
|
-
if (backupDir) {
|
|
479
|
-
console.log(ansis.gray(`\u2714 ${i18n.t("configuration:backupSuccess")}: ${backupDir}`));
|
|
480
|
-
}
|
|
481
|
-
if (aiOutputLang) {
|
|
482
|
-
applyAiLanguageDirective(aiOutputLang);
|
|
483
|
-
}
|
|
484
|
-
await configureOutputStyle();
|
|
485
|
-
console.log(ansis.green(`\u2714 ${i18n.t("configuration:configSuccess")} ${CLAUDE_DIR}`));
|
|
486
|
-
console.log(`
|
|
487
|
-
${ansis.green(i18n.t("common:complete"))}`);
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
export { configureOutputStyle as a, configureApiCompletely as c, formatApiKeyDisplay as f, modifyApiConfigPartially as m, updatePromptOnly as u, validateApiKey as v };
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import ansis from 'ansis';
|
|
2
|
-
import inquirer from 'inquirer';
|
|
3
|
-
import 'node:child_process';
|
|
4
|
-
import { homedir } from 'node:os';
|
|
5
|
-
import 'node:process';
|
|
6
|
-
import { join } from 'pathe';
|
|
7
|
-
import { ensureI18nInitialized, i18n } from '../chunks/index.mjs';
|
|
8
|
-
|
|
9
|
-
const PLAYWRIGHT_PROFILES_DIR = join(homedir(), ".ccjk", "playwright");
|
|
10
|
-
function createPlaywrightMcpConfig(options = {}) {
|
|
11
|
-
const {
|
|
12
|
-
profile = "default",
|
|
13
|
-
headless = false,
|
|
14
|
-
browser = "chromium",
|
|
15
|
-
userDataDir
|
|
16
|
-
} = options;
|
|
17
|
-
const resolvedUserDataDir = userDataDir || join(PLAYWRIGHT_PROFILES_DIR, profile);
|
|
18
|
-
const args = ["-y", "@playwright/mcp@latest"];
|
|
19
|
-
args.push("--browser", browser);
|
|
20
|
-
args.push("--user-data-dir", resolvedUserDataDir);
|
|
21
|
-
if (headless) {
|
|
22
|
-
args.push("--headless");
|
|
23
|
-
}
|
|
24
|
-
return {
|
|
25
|
-
type: "stdio",
|
|
26
|
-
command: "npx",
|
|
27
|
-
args,
|
|
28
|
-
env: {}
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
const MCP_SERVICE_CONFIGS = [
|
|
32
|
-
// Documentation and Search Services - Universal (no GUI required)
|
|
33
|
-
{
|
|
34
|
-
id: "context7",
|
|
35
|
-
requiresApiKey: false,
|
|
36
|
-
config: {
|
|
37
|
-
type: "stdio",
|
|
38
|
-
command: "npx",
|
|
39
|
-
args: ["-y", "@upstash/context7-mcp@latest"],
|
|
40
|
-
env: {}
|
|
41
|
-
}
|
|
42
|
-
// Works on all platforms - no special requirements
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
id: "open-websearch",
|
|
46
|
-
requiresApiKey: false,
|
|
47
|
-
config: {
|
|
48
|
-
type: "stdio",
|
|
49
|
-
command: "npx",
|
|
50
|
-
args: ["-y", "open-websearch@latest"],
|
|
51
|
-
env: {
|
|
52
|
-
MODE: "stdio",
|
|
53
|
-
DEFAULT_SEARCH_ENGINE: "duckduckgo",
|
|
54
|
-
ALLOWED_SEARCH_ENGINES: "duckduckgo,bing,brave"
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
// Works on all platforms - no special requirements
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
id: "mcp-deepwiki",
|
|
61
|
-
requiresApiKey: false,
|
|
62
|
-
config: {
|
|
63
|
-
type: "stdio",
|
|
64
|
-
command: "npx",
|
|
65
|
-
args: ["-y", "mcp-deepwiki@latest"],
|
|
66
|
-
env: {}
|
|
67
|
-
}
|
|
68
|
-
// Works on all platforms - no special requirements
|
|
69
|
-
},
|
|
70
|
-
// Development Workflow Services
|
|
71
|
-
{
|
|
72
|
-
id: "spec-workflow",
|
|
73
|
-
requiresApiKey: false,
|
|
74
|
-
config: {
|
|
75
|
-
type: "stdio",
|
|
76
|
-
command: "npx",
|
|
77
|
-
args: ["-y", "@pimzino/spec-workflow-mcp@latest"],
|
|
78
|
-
env: {}
|
|
79
|
-
}
|
|
80
|
-
// Works on all platforms - no special requirements
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
id: "serena",
|
|
84
|
-
requiresApiKey: false,
|
|
85
|
-
config: {
|
|
86
|
-
type: "stdio",
|
|
87
|
-
command: "uvx",
|
|
88
|
-
args: ["--from", "git+https://github.com/oraios/serena", "serena", "start-mcp-server", "--context", "ide-assistant", "--enable-web-dashboard", "false"],
|
|
89
|
-
env: {}
|
|
90
|
-
},
|
|
91
|
-
platformRequirements: {
|
|
92
|
-
requiredCommands: ["uvx"]
|
|
93
|
-
// Requires uv/uvx to be installed
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
// Browser and Automation Services - Require GUI environment
|
|
97
|
-
{
|
|
98
|
-
id: "Playwright",
|
|
99
|
-
requiresApiKey: false,
|
|
100
|
-
config: createPlaywrightMcpConfig(),
|
|
101
|
-
// Uses default profile with chromium browser
|
|
102
|
-
platformRequirements: {
|
|
103
|
-
platforms: ["macos", "windows"],
|
|
104
|
-
// GUI required - exclude headless Linux/WSL/Termux
|
|
105
|
-
requiresGui: true
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
// Anthropic Official MCP Services - Universal
|
|
109
|
-
// Note: Removed low-value services: filesystem (buggy), puppeteer (duplicate of Playwright),
|
|
110
|
-
// memory (Claude has built-in memory), fetch (Claude has WebFetch), sequential-thinking (limited value)
|
|
111
|
-
{
|
|
112
|
-
id: "sqlite",
|
|
113
|
-
requiresApiKey: false,
|
|
114
|
-
config: {
|
|
115
|
-
type: "stdio",
|
|
116
|
-
command: "npx",
|
|
117
|
-
args: ["-y", "@anthropic-ai/mcp-server-sqlite@latest"],
|
|
118
|
-
env: {}
|
|
119
|
-
}
|
|
120
|
-
// Works on all platforms - no special requirements
|
|
121
|
-
}
|
|
122
|
-
];
|
|
123
|
-
async function getMcpServices() {
|
|
124
|
-
ensureI18nInitialized();
|
|
125
|
-
const mcpServiceList = [
|
|
126
|
-
// Documentation and Search Services
|
|
127
|
-
{
|
|
128
|
-
id: "context7",
|
|
129
|
-
name: i18n.t("mcp:services.context7.name"),
|
|
130
|
-
description: i18n.t("mcp:services.context7.description")
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
id: "open-websearch",
|
|
134
|
-
name: i18n.t("mcp:services.open-websearch.name"),
|
|
135
|
-
description: i18n.t("mcp:services.open-websearch.description")
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
id: "mcp-deepwiki",
|
|
139
|
-
name: i18n.t("mcp:services.mcp-deepwiki.name"),
|
|
140
|
-
description: i18n.t("mcp:services.mcp-deepwiki.description")
|
|
141
|
-
},
|
|
142
|
-
// Development Workflow Services
|
|
143
|
-
{
|
|
144
|
-
id: "spec-workflow",
|
|
145
|
-
name: i18n.t("mcp:services.spec-workflow.name"),
|
|
146
|
-
description: i18n.t("mcp:services.spec-workflow.description")
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
id: "serena",
|
|
150
|
-
name: i18n.t("mcp:services.serena.name"),
|
|
151
|
-
description: i18n.t("mcp:services.serena.description")
|
|
152
|
-
},
|
|
153
|
-
// Browser and Automation Services
|
|
154
|
-
{
|
|
155
|
-
id: "Playwright",
|
|
156
|
-
name: i18n.t("mcp:services.playwright.name"),
|
|
157
|
-
description: i18n.t("mcp:services.playwright.description")
|
|
158
|
-
},
|
|
159
|
-
// Anthropic Official MCP Services
|
|
160
|
-
// Note: Removed low-value services: filesystem (buggy), puppeteer (duplicate),
|
|
161
|
-
// memory (Claude built-in), fetch (Claude WebFetch), sequential-thinking (limited value)
|
|
162
|
-
{
|
|
163
|
-
id: "sqlite",
|
|
164
|
-
name: i18n.t("mcp:services.sqlite.name"),
|
|
165
|
-
description: i18n.t("mcp:services.sqlite.description")
|
|
166
|
-
}
|
|
167
|
-
];
|
|
168
|
-
return MCP_SERVICE_CONFIGS.map((config) => {
|
|
169
|
-
const serviceInfo = mcpServiceList.find((s) => s.id === config.id);
|
|
170
|
-
const service = {
|
|
171
|
-
id: config.id,
|
|
172
|
-
name: serviceInfo?.name || config.id,
|
|
173
|
-
description: serviceInfo?.description || "",
|
|
174
|
-
requiresApiKey: config.requiresApiKey,
|
|
175
|
-
config: config.config
|
|
176
|
-
};
|
|
177
|
-
if (config.apiKeyEnvVar) {
|
|
178
|
-
service.apiKeyEnvVar = config.apiKeyEnvVar;
|
|
179
|
-
}
|
|
180
|
-
return service;
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
async function getMcpService(id) {
|
|
184
|
-
const services = await getMcpServices();
|
|
185
|
-
return services.find((service) => service.id === id);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
async function selectMcpServices() {
|
|
189
|
-
ensureI18nInitialized();
|
|
190
|
-
const mcpServices = await getMcpServices();
|
|
191
|
-
const choices = mcpServices.map((service) => ({
|
|
192
|
-
name: `${service.name} - ${ansis.gray(service.description)}`,
|
|
193
|
-
value: service.id,
|
|
194
|
-
selected: false
|
|
195
|
-
}));
|
|
196
|
-
const { services } = await inquirer.prompt({
|
|
197
|
-
type: "checkbox",
|
|
198
|
-
name: "services",
|
|
199
|
-
message: `${i18n.t("mcp:selectMcpServices")}${i18n.t("common:multiSelectHint")}`,
|
|
200
|
-
choices
|
|
201
|
-
});
|
|
202
|
-
if (services === void 0) {
|
|
203
|
-
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
204
|
-
return void 0;
|
|
205
|
-
}
|
|
206
|
-
return services;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
export { MCP_SERVICE_CONFIGS as M, getMcpServices as a, getMcpService as g, selectMcpServices as s };
|