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
|
@@ -0,0 +1,1048 @@
|
|
|
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, f 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
|
+
import { existsSync } from 'node:fs';
|
|
14
|
+
import { rm, mkdir, copyFile as copyFile$1 } from 'node:fs/promises';
|
|
15
|
+
|
|
16
|
+
const OUTPUT_STYLES = [
|
|
17
|
+
// Custom styles (have template files) - 大神模式
|
|
18
|
+
{
|
|
19
|
+
id: "linus-mode",
|
|
20
|
+
isCustom: true,
|
|
21
|
+
filePath: "linus-mode.md"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: "uncle-bob-mode",
|
|
25
|
+
isCustom: true,
|
|
26
|
+
filePath: "uncle-bob-mode.md"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: "dhh-mode",
|
|
30
|
+
isCustom: true,
|
|
31
|
+
filePath: "dhh-mode.md"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "carmack-mode",
|
|
35
|
+
isCustom: true,
|
|
36
|
+
filePath: "carmack-mode.md"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "jobs-mode",
|
|
40
|
+
isCustom: true,
|
|
41
|
+
filePath: "jobs-mode.md"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: "evan-you-mode",
|
|
45
|
+
isCustom: true,
|
|
46
|
+
filePath: "evan-you-mode.md"
|
|
47
|
+
},
|
|
48
|
+
// Built-in styles (no template files) - Claude Code native styles
|
|
49
|
+
{
|
|
50
|
+
id: "default",
|
|
51
|
+
isCustom: false
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "explanatory",
|
|
55
|
+
isCustom: false
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "learning",
|
|
59
|
+
isCustom: false
|
|
60
|
+
}
|
|
61
|
+
];
|
|
62
|
+
const LEGACY_FILES = ["personality.md", "rules.md", "technical-guides.md", "mcp.md", "language.md"];
|
|
63
|
+
function getAvailableOutputStyles() {
|
|
64
|
+
return OUTPUT_STYLES;
|
|
65
|
+
}
|
|
66
|
+
async function copyOutputStyles(selectedStyles, lang) {
|
|
67
|
+
const outputStylesDir = join(CLAUDE_DIR, "output-styles");
|
|
68
|
+
ensureDir(outputStylesDir);
|
|
69
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
70
|
+
const distDir = dirname(dirname(currentFilePath));
|
|
71
|
+
const rootDir = dirname(distDir);
|
|
72
|
+
const templateDir = join(rootDir, "templates", "common", "output-styles", lang);
|
|
73
|
+
for (const styleId of selectedStyles) {
|
|
74
|
+
const style = OUTPUT_STYLES.find((s) => s.id === styleId);
|
|
75
|
+
if (!style || !style.isCustom || !style.filePath) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const sourcePath = join(templateDir, style.filePath);
|
|
79
|
+
const destPath = join(outputStylesDir, style.filePath);
|
|
80
|
+
if (exists(sourcePath)) {
|
|
81
|
+
copyFile(sourcePath, destPath);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function setGlobalDefaultOutputStyle(styleId) {
|
|
86
|
+
const templatePermissions = getTemplatePermissions();
|
|
87
|
+
const existingSettings = readJsonConfig(SETTINGS_FILE) || {};
|
|
88
|
+
const cleanedPermissions = mergeAndCleanPermissions(
|
|
89
|
+
templatePermissions,
|
|
90
|
+
existingSettings.permissions?.allow
|
|
91
|
+
);
|
|
92
|
+
const updatedSettings = {
|
|
93
|
+
...existingSettings,
|
|
94
|
+
outputStyle: styleId,
|
|
95
|
+
// Ensure clean permissions
|
|
96
|
+
permissions: {
|
|
97
|
+
allow: cleanedPermissions
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
if (updatedSettings.plansDirectory === null) {
|
|
101
|
+
delete updatedSettings.plansDirectory;
|
|
102
|
+
}
|
|
103
|
+
writeJsonConfig(SETTINGS_FILE, updatedSettings);
|
|
104
|
+
}
|
|
105
|
+
function getTemplatePermissions() {
|
|
106
|
+
try {
|
|
107
|
+
const { readFileSync } = require("node:fs");
|
|
108
|
+
const { fileURLToPath: fileURLToPath2 } = require("node:url");
|
|
109
|
+
const { dirname: dirname2, join: join2 } = require("pathe");
|
|
110
|
+
const currentFilePath = fileURLToPath2(import.meta.url);
|
|
111
|
+
const distDir = dirname2(dirname2(currentFilePath));
|
|
112
|
+
const rootDir = dirname2(distDir);
|
|
113
|
+
const templatePath = join2(rootDir, "templates", "claude-code", "common", "settings.json");
|
|
114
|
+
if (require("node:fs").existsSync(templatePath)) {
|
|
115
|
+
const template = JSON.parse(readFileSync(templatePath, "utf-8"));
|
|
116
|
+
return template.permissions?.allow || [];
|
|
117
|
+
}
|
|
118
|
+
} catch (_error) {
|
|
119
|
+
}
|
|
120
|
+
return [
|
|
121
|
+
"AllowEdit",
|
|
122
|
+
"AllowWrite",
|
|
123
|
+
"AllowRead",
|
|
124
|
+
"AllowExec",
|
|
125
|
+
"AllowCreateProcess",
|
|
126
|
+
"AllowKillProcess",
|
|
127
|
+
"AllowNetworkAccess",
|
|
128
|
+
"AllowFileSystemAccess",
|
|
129
|
+
"AllowShellAccess",
|
|
130
|
+
"AllowHttpAccess"
|
|
131
|
+
];
|
|
132
|
+
}
|
|
133
|
+
function hasLegacyPersonalityFiles() {
|
|
134
|
+
return LEGACY_FILES.some((filename) => exists(join(CLAUDE_DIR, filename)));
|
|
135
|
+
}
|
|
136
|
+
function cleanupLegacyPersonalityFiles() {
|
|
137
|
+
LEGACY_FILES.forEach((filename) => {
|
|
138
|
+
const filePath = join(CLAUDE_DIR, filename);
|
|
139
|
+
if (exists(filePath)) {
|
|
140
|
+
removeFile(filePath);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
async function configureOutputStyle(preselectedStyles, preselectedDefault) {
|
|
145
|
+
ensureI18nInitialized();
|
|
146
|
+
const outputStyleList = [
|
|
147
|
+
{
|
|
148
|
+
id: "default",
|
|
149
|
+
name: i18n.t("configuration:outputStyles.default.name"),
|
|
150
|
+
description: i18n.t("configuration:outputStyles.default.description")
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
id: "linus-mode",
|
|
154
|
+
name: i18n.t("configuration:outputStyles.linus-mode.name"),
|
|
155
|
+
description: i18n.t("configuration:outputStyles.linus-mode.description")
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
id: "uncle-bob-mode",
|
|
159
|
+
name: i18n.t("configuration:outputStyles.uncle-bob-mode.name"),
|
|
160
|
+
description: i18n.t("configuration:outputStyles.uncle-bob-mode.description")
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: "dhh-mode",
|
|
164
|
+
name: i18n.t("configuration:outputStyles.dhh-mode.name"),
|
|
165
|
+
description: i18n.t("configuration:outputStyles.dhh-mode.description")
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
id: "carmack-mode",
|
|
169
|
+
name: i18n.t("configuration:outputStyles.carmack-mode.name"),
|
|
170
|
+
description: i18n.t("configuration:outputStyles.carmack-mode.description")
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: "jobs-mode",
|
|
174
|
+
name: i18n.t("configuration:outputStyles.jobs-mode.name"),
|
|
175
|
+
description: i18n.t("configuration:outputStyles.jobs-mode.description")
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: "evan-you-mode",
|
|
179
|
+
name: i18n.t("configuration:outputStyles.evan-you-mode.name"),
|
|
180
|
+
description: i18n.t("configuration:outputStyles.evan-you-mode.description")
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
id: "explanatory",
|
|
184
|
+
name: i18n.t("configuration:outputStyles.explanatory.name"),
|
|
185
|
+
description: i18n.t("configuration:outputStyles.explanatory.description")
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: "learning",
|
|
189
|
+
name: i18n.t("configuration:outputStyles.learning.name"),
|
|
190
|
+
description: i18n.t("configuration:outputStyles.learning.description")
|
|
191
|
+
}
|
|
192
|
+
];
|
|
193
|
+
const availableStyles = getAvailableOutputStyles();
|
|
194
|
+
if (hasLegacyPersonalityFiles() && !preselectedStyles) {
|
|
195
|
+
console.log(ansis.yellow(`\u26A0\uFE0F ${i18n.t("configuration:legacyFilesDetected")}`));
|
|
196
|
+
const cleanupLegacy = await promptBoolean({
|
|
197
|
+
message: i18n.t("configuration:cleanupLegacyFiles"),
|
|
198
|
+
defaultValue: true
|
|
199
|
+
});
|
|
200
|
+
if (cleanupLegacy) {
|
|
201
|
+
cleanupLegacyPersonalityFiles();
|
|
202
|
+
console.log(ansis.green(`\u2714 ${i18n.t("configuration:legacyFilesRemoved")}`));
|
|
203
|
+
}
|
|
204
|
+
} else if (hasLegacyPersonalityFiles() && preselectedStyles) {
|
|
205
|
+
cleanupLegacyPersonalityFiles();
|
|
206
|
+
}
|
|
207
|
+
let selectedStyles;
|
|
208
|
+
let defaultStyle;
|
|
209
|
+
if (preselectedStyles && preselectedDefault) {
|
|
210
|
+
selectedStyles = preselectedStyles;
|
|
211
|
+
defaultStyle = preselectedDefault;
|
|
212
|
+
} else {
|
|
213
|
+
const customStyles = availableStyles.filter((style) => style.isCustom);
|
|
214
|
+
const { selectedStyles: promptedStyles } = await inquirer.prompt({
|
|
215
|
+
type: "checkbox",
|
|
216
|
+
name: "selectedStyles",
|
|
217
|
+
message: `${i18n.t("configuration:selectOutputStyles")}${i18n.t("common:multiSelectHint")}`,
|
|
218
|
+
choices: addNumbersToChoices(customStyles.map((style) => {
|
|
219
|
+
const styleInfo = outputStyleList.find((s) => s.id === style.id);
|
|
220
|
+
return {
|
|
221
|
+
name: `${styleInfo?.name || style.id} - ${ansis.gray(styleInfo?.description || "")}`,
|
|
222
|
+
value: style.id,
|
|
223
|
+
checked: true
|
|
224
|
+
// Default to all selected
|
|
225
|
+
};
|
|
226
|
+
})),
|
|
227
|
+
validate: async (input) => input.length > 0 || i18n.t("configuration:selectAtLeastOne")
|
|
228
|
+
});
|
|
229
|
+
if (!promptedStyles || promptedStyles.length === 0) {
|
|
230
|
+
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
selectedStyles = promptedStyles;
|
|
234
|
+
const { defaultStyle: promptedDefault } = await inquirer.prompt({
|
|
235
|
+
type: "list",
|
|
236
|
+
name: "defaultStyle",
|
|
237
|
+
message: i18n.t("configuration:selectDefaultOutputStyle"),
|
|
238
|
+
choices: addNumbersToChoices([
|
|
239
|
+
// Show selected custom styles first (only what user actually installed)
|
|
240
|
+
...selectedStyles.map((styleId) => {
|
|
241
|
+
const styleInfo = outputStyleList.find((s) => s.id === styleId);
|
|
242
|
+
return {
|
|
243
|
+
name: `${styleInfo?.name || styleId} - ${ansis.gray(styleInfo?.description || "")}`,
|
|
244
|
+
value: styleId,
|
|
245
|
+
short: styleInfo?.name || styleId
|
|
246
|
+
};
|
|
247
|
+
}),
|
|
248
|
+
// Then show all built-in styles (always available)
|
|
249
|
+
...availableStyles.filter((style) => !style.isCustom).map((style) => {
|
|
250
|
+
const styleInfo = outputStyleList.find((s) => s.id === style.id);
|
|
251
|
+
return {
|
|
252
|
+
name: `${styleInfo?.name || style.id} - ${ansis.gray(styleInfo?.description || "")}`,
|
|
253
|
+
value: style.id,
|
|
254
|
+
short: styleInfo?.name || style.id
|
|
255
|
+
};
|
|
256
|
+
})
|
|
257
|
+
]),
|
|
258
|
+
default: selectedStyles.includes("linus-mode") ? "linus-mode" : selectedStyles[0]
|
|
259
|
+
});
|
|
260
|
+
if (!promptedDefault) {
|
|
261
|
+
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
defaultStyle = promptedDefault;
|
|
265
|
+
}
|
|
266
|
+
await copyOutputStyles(selectedStyles, "zh-CN");
|
|
267
|
+
setGlobalDefaultOutputStyle(defaultStyle);
|
|
268
|
+
updateZcfConfig({
|
|
269
|
+
outputStyles: selectedStyles,
|
|
270
|
+
defaultOutputStyle: defaultStyle
|
|
271
|
+
});
|
|
272
|
+
console.log(ansis.green(`\u2714 ${i18n.t("configuration:outputStyleInstalled")}`));
|
|
273
|
+
console.log(ansis.gray(` ${i18n.t("configuration:selectedStyles")}: ${selectedStyles.join(", ")}`));
|
|
274
|
+
console.log(ansis.gray(` ${i18n.t("configuration:defaultStyle")}: ${defaultStyle}`));
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function validateApiKey(apiKey) {
|
|
278
|
+
if (!apiKey || apiKey.trim() === "") {
|
|
279
|
+
return {
|
|
280
|
+
isValid: false,
|
|
281
|
+
// Note: This should use i18next, but due to sync constraint in inquirer validate,
|
|
282
|
+
// we temporarily use a generic message. This will be fixed when we refactor to async validation.
|
|
283
|
+
error: "API key cannot be empty"
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
return { isValid: true };
|
|
287
|
+
}
|
|
288
|
+
function formatApiKeyDisplay(apiKey) {
|
|
289
|
+
if (!apiKey || apiKey.length < 12) {
|
|
290
|
+
return apiKey;
|
|
291
|
+
}
|
|
292
|
+
return `${apiKey.substring(0, 8)}...${apiKey.substring(apiKey.length - 4)}`;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async function configureApiCompletely(preselectedAuthType) {
|
|
296
|
+
ensureI18nInitialized();
|
|
297
|
+
let authType = preselectedAuthType;
|
|
298
|
+
if (!authType) {
|
|
299
|
+
const { authType: selectedAuthType } = await inquirer.prompt({
|
|
300
|
+
type: "list",
|
|
301
|
+
name: "authType",
|
|
302
|
+
message: i18n.t("api:configureApi"),
|
|
303
|
+
choices: addNumbersToChoices([
|
|
304
|
+
{
|
|
305
|
+
name: i18n.t("api:useOfficialLogin"),
|
|
306
|
+
value: "official",
|
|
307
|
+
short: i18n.t("api:useOfficialLogin")
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
name: `${i18n.t("api:useAuthToken")} - ${ansis.gray(i18n.t("api:authTokenDesc"))}`,
|
|
311
|
+
value: "auth_token",
|
|
312
|
+
short: i18n.t("api:useAuthToken")
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
name: `${i18n.t("api:useApiKey")} - ${ansis.gray(i18n.t("api:apiKeyDesc"))}`,
|
|
316
|
+
value: "api_key",
|
|
317
|
+
short: i18n.t("api:useApiKey")
|
|
318
|
+
}
|
|
319
|
+
])
|
|
320
|
+
});
|
|
321
|
+
if (!selectedAuthType) {
|
|
322
|
+
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
authType = selectedAuthType;
|
|
326
|
+
}
|
|
327
|
+
if (authType === "official") {
|
|
328
|
+
const success = switchToOfficialLogin();
|
|
329
|
+
if (success) {
|
|
330
|
+
return null;
|
|
331
|
+
} else {
|
|
332
|
+
console.log(ansis.red(i18n.t("api:officialLoginFailed")));
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const { url } = await inquirer.prompt({
|
|
337
|
+
type: "input",
|
|
338
|
+
name: "url",
|
|
339
|
+
message: i18n.t("api:enterApiUrl"),
|
|
340
|
+
validate: async (value) => {
|
|
341
|
+
if (!value)
|
|
342
|
+
return i18n.t("api:urlRequired");
|
|
343
|
+
try {
|
|
344
|
+
void new URL(value);
|
|
345
|
+
return true;
|
|
346
|
+
} catch {
|
|
347
|
+
return i18n.t("api:invalidUrl");
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
if (url === void 0) {
|
|
352
|
+
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
const keyMessage = authType === "auth_token" ? i18n.t("api:enterAuthToken") : i18n.t("api:enterApiKey");
|
|
356
|
+
const { key } = await inquirer.prompt({
|
|
357
|
+
type: "input",
|
|
358
|
+
name: "key",
|
|
359
|
+
message: keyMessage,
|
|
360
|
+
validate: async (value) => {
|
|
361
|
+
if (!value) {
|
|
362
|
+
return i18n.t("api:keyRequired");
|
|
363
|
+
}
|
|
364
|
+
const validation = validateApiKey(value);
|
|
365
|
+
if (!validation.isValid) {
|
|
366
|
+
return validation.error || i18n.t("api:invalidKeyFormat");
|
|
367
|
+
}
|
|
368
|
+
return true;
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
if (key === void 0) {
|
|
372
|
+
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
console.log(ansis.gray(` API Key: ${formatApiKeyDisplay(key)}`));
|
|
376
|
+
return { url, key, authType };
|
|
377
|
+
}
|
|
378
|
+
async function modifyApiConfigPartially(existingConfig) {
|
|
379
|
+
ensureI18nInitialized();
|
|
380
|
+
let currentConfig = { ...existingConfig };
|
|
381
|
+
const latestConfig = getExistingApiConfig();
|
|
382
|
+
if (latestConfig) {
|
|
383
|
+
currentConfig = latestConfig;
|
|
384
|
+
}
|
|
385
|
+
const { item } = await inquirer.prompt({
|
|
386
|
+
type: "list",
|
|
387
|
+
name: "item",
|
|
388
|
+
message: i18n.t("api:selectModifyItems"),
|
|
389
|
+
choices: addNumbersToChoices([
|
|
390
|
+
{ name: i18n.t("api:modifyApiUrl"), value: "url" },
|
|
391
|
+
{ name: i18n.t("api:modifyApiKey"), value: "key" },
|
|
392
|
+
{ name: i18n.t("api:modifyAuthType"), value: "authType" }
|
|
393
|
+
])
|
|
394
|
+
});
|
|
395
|
+
if (!item) {
|
|
396
|
+
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
if (item === "url") {
|
|
400
|
+
const { url } = await inquirer.prompt({
|
|
401
|
+
type: "input",
|
|
402
|
+
name: "url",
|
|
403
|
+
message: i18n.t("api:enterNewApiUrl").replace("{url}", currentConfig.url || i18n.t("common:none")),
|
|
404
|
+
default: currentConfig.url,
|
|
405
|
+
validate: async (value) => {
|
|
406
|
+
if (!value)
|
|
407
|
+
return i18n.t("api:urlRequired");
|
|
408
|
+
try {
|
|
409
|
+
void new URL(value);
|
|
410
|
+
return true;
|
|
411
|
+
} catch {
|
|
412
|
+
return i18n.t("api:invalidUrl");
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
if (url === void 0) {
|
|
417
|
+
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
currentConfig.url = url;
|
|
421
|
+
const savedConfig = configureApi(currentConfig);
|
|
422
|
+
if (savedConfig) {
|
|
423
|
+
console.log(ansis.green(`\u2714 ${i18n.t("api:modificationSaved")}`));
|
|
424
|
+
console.log(ansis.gray(` ${i18n.t("api:apiConfigUrl")}: ${savedConfig.url}`));
|
|
425
|
+
}
|
|
426
|
+
} else if (item === "key") {
|
|
427
|
+
const authType = currentConfig.authType || "auth_token";
|
|
428
|
+
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"));
|
|
429
|
+
const { key } = await inquirer.prompt({
|
|
430
|
+
type: "input",
|
|
431
|
+
name: "key",
|
|
432
|
+
message: keyMessage,
|
|
433
|
+
validate: async (value) => {
|
|
434
|
+
if (!value) {
|
|
435
|
+
return i18n.t("api:keyRequired");
|
|
436
|
+
}
|
|
437
|
+
const validation = validateApiKey(value);
|
|
438
|
+
if (!validation.isValid) {
|
|
439
|
+
return validation.error || i18n.t("api:invalidKeyFormat");
|
|
440
|
+
}
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
if (key === void 0) {
|
|
445
|
+
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
currentConfig.key = key;
|
|
449
|
+
const savedConfig = configureApi(currentConfig);
|
|
450
|
+
if (savedConfig) {
|
|
451
|
+
console.log(ansis.green(`\u2714 ${i18n.t("api:modificationSaved")}`));
|
|
452
|
+
console.log(ansis.gray(` ${i18n.t("api:apiConfigKey")}: ${formatApiKeyDisplay(savedConfig.key)}`));
|
|
453
|
+
}
|
|
454
|
+
} else if (item === "authType") {
|
|
455
|
+
const { authType } = await inquirer.prompt({
|
|
456
|
+
type: "list",
|
|
457
|
+
name: "authType",
|
|
458
|
+
message: i18n.t("api:selectNewAuthType").replace("{type}", currentConfig.authType || i18n.t("common:none")),
|
|
459
|
+
choices: addNumbersToChoices([
|
|
460
|
+
{ name: "Auth Token (OAuth)", value: "auth_token" },
|
|
461
|
+
{ name: "API Key", value: "api_key" }
|
|
462
|
+
]),
|
|
463
|
+
default: currentConfig.authType === "api_key" ? 1 : 0
|
|
464
|
+
});
|
|
465
|
+
if (authType === void 0) {
|
|
466
|
+
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
currentConfig.authType = authType;
|
|
470
|
+
const savedConfig = configureApi(currentConfig);
|
|
471
|
+
if (savedConfig) {
|
|
472
|
+
console.log(ansis.green(`\u2714 ${i18n.t("api:modificationSaved")}`));
|
|
473
|
+
console.log(ansis.gray(` ${i18n.t("api:apiConfigAuthType")}: ${savedConfig.authType}`));
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
async function updatePromptOnly(aiOutputLang) {
|
|
478
|
+
ensureI18nInitialized();
|
|
479
|
+
const backupDir = backupExistingConfig();
|
|
480
|
+
if (backupDir) {
|
|
481
|
+
console.log(ansis.gray(`\u2714 ${i18n.t("configuration:backupSuccess")}: ${backupDir}`));
|
|
482
|
+
}
|
|
483
|
+
if (aiOutputLang) {
|
|
484
|
+
applyAiLanguageDirective(aiOutputLang);
|
|
485
|
+
}
|
|
486
|
+
await configureOutputStyle();
|
|
487
|
+
console.log(ansis.green(`\u2714 ${i18n.t("configuration:configSuccess")} ${CLAUDE_DIR}`));
|
|
488
|
+
console.log(`
|
|
489
|
+
${ansis.green(i18n.t("common:complete"))}`);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const WORKFLOW_CONFIG_BASE = [
|
|
493
|
+
{
|
|
494
|
+
id: "interviewWorkflow",
|
|
495
|
+
defaultSelected: true,
|
|
496
|
+
order: 1,
|
|
497
|
+
commands: ["interview.md"],
|
|
498
|
+
agents: [],
|
|
499
|
+
autoInstallAgents: false,
|
|
500
|
+
category: "interview",
|
|
501
|
+
displayCategory: "planning",
|
|
502
|
+
outputDir: "interview",
|
|
503
|
+
metadata: {
|
|
504
|
+
version: "1.0.0",
|
|
505
|
+
addedDate: "2025-01",
|
|
506
|
+
tags: ["recommended", "popular"],
|
|
507
|
+
difficulty: "beginner"
|
|
508
|
+
}
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
id: "essentialTools",
|
|
512
|
+
defaultSelected: true,
|
|
513
|
+
order: 2,
|
|
514
|
+
commands: ["init-project.md", "feat.md"],
|
|
515
|
+
agents: [
|
|
516
|
+
{ id: "init-architect", filename: "init-architect.md", required: true },
|
|
517
|
+
{ id: "get-current-datetime", filename: "get-current-datetime.md", required: true },
|
|
518
|
+
{ id: "planner", filename: "planner.md", required: true },
|
|
519
|
+
{ id: "ui-ux-designer", filename: "ui-ux-designer.md", required: true }
|
|
520
|
+
],
|
|
521
|
+
autoInstallAgents: true,
|
|
522
|
+
category: "essential",
|
|
523
|
+
displayCategory: "planning",
|
|
524
|
+
outputDir: "essential",
|
|
525
|
+
metadata: {
|
|
526
|
+
version: "1.0.0",
|
|
527
|
+
addedDate: "2025-01",
|
|
528
|
+
tags: ["essential"],
|
|
529
|
+
difficulty: "beginner"
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
id: "gitWorkflow",
|
|
534
|
+
defaultSelected: true,
|
|
535
|
+
order: 3,
|
|
536
|
+
commands: ["git-commit.md", "git-rollback.md", "git-cleanBranches.md", "git-worktree.md"],
|
|
537
|
+
agents: [],
|
|
538
|
+
autoInstallAgents: false,
|
|
539
|
+
category: "git",
|
|
540
|
+
displayCategory: "versionControl",
|
|
541
|
+
outputDir: "git",
|
|
542
|
+
metadata: {
|
|
543
|
+
version: "1.0.0",
|
|
544
|
+
addedDate: "2025-01",
|
|
545
|
+
tags: ["popular"],
|
|
546
|
+
difficulty: "beginner"
|
|
547
|
+
}
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
id: "sixStepsWorkflow",
|
|
551
|
+
defaultSelected: false,
|
|
552
|
+
order: 4,
|
|
553
|
+
commands: ["workflow.md"],
|
|
554
|
+
agents: [],
|
|
555
|
+
autoInstallAgents: false,
|
|
556
|
+
category: "sixStep",
|
|
557
|
+
displayCategory: "development",
|
|
558
|
+
outputDir: "workflow",
|
|
559
|
+
metadata: {
|
|
560
|
+
version: "1.0.0",
|
|
561
|
+
addedDate: "2025-01",
|
|
562
|
+
tags: ["professional"],
|
|
563
|
+
difficulty: "intermediate"
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
id: "specFirstTDD",
|
|
568
|
+
defaultSelected: false,
|
|
569
|
+
order: 5,
|
|
570
|
+
commands: ["spec-first-tdd.md"],
|
|
571
|
+
agents: [],
|
|
572
|
+
autoInstallAgents: false,
|
|
573
|
+
category: "specFirstTDD",
|
|
574
|
+
displayCategory: "quality",
|
|
575
|
+
outputDir: "spec-first-tdd",
|
|
576
|
+
metadata: {
|
|
577
|
+
version: "1.0.0",
|
|
578
|
+
addedDate: "2025-02",
|
|
579
|
+
tags: ["professional", "new"],
|
|
580
|
+
difficulty: "advanced"
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
id: "continuousDelivery",
|
|
585
|
+
defaultSelected: false,
|
|
586
|
+
order: 6,
|
|
587
|
+
commands: ["continuous-delivery.md"],
|
|
588
|
+
agents: [],
|
|
589
|
+
autoInstallAgents: false,
|
|
590
|
+
category: "continuousDelivery",
|
|
591
|
+
displayCategory: "quality",
|
|
592
|
+
outputDir: "continuous-delivery",
|
|
593
|
+
metadata: {
|
|
594
|
+
version: "1.0.0",
|
|
595
|
+
addedDate: "2025-02",
|
|
596
|
+
tags: ["professional", "new"],
|
|
597
|
+
difficulty: "advanced"
|
|
598
|
+
}
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
id: "refactoringMaster",
|
|
602
|
+
defaultSelected: false,
|
|
603
|
+
order: 7,
|
|
604
|
+
commands: ["refactoring-master.md"],
|
|
605
|
+
agents: [],
|
|
606
|
+
autoInstallAgents: false,
|
|
607
|
+
category: "refactoringMaster",
|
|
608
|
+
displayCategory: "quality",
|
|
609
|
+
outputDir: "refactoring-master",
|
|
610
|
+
metadata: {
|
|
611
|
+
version: "1.0.0",
|
|
612
|
+
addedDate: "2025-02",
|
|
613
|
+
tags: ["professional", "new"],
|
|
614
|
+
difficulty: "advanced"
|
|
615
|
+
}
|
|
616
|
+
},
|
|
617
|
+
{
|
|
618
|
+
id: "linearMethod",
|
|
619
|
+
defaultSelected: false,
|
|
620
|
+
order: 8,
|
|
621
|
+
commands: ["linear-method.md"],
|
|
622
|
+
agents: [],
|
|
623
|
+
autoInstallAgents: false,
|
|
624
|
+
category: "linearMethod",
|
|
625
|
+
displayCategory: "planning",
|
|
626
|
+
outputDir: "linear-method",
|
|
627
|
+
metadata: {
|
|
628
|
+
version: "1.0.0",
|
|
629
|
+
addedDate: "2025-02",
|
|
630
|
+
tags: ["new"],
|
|
631
|
+
difficulty: "intermediate"
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
];
|
|
635
|
+
function getWorkflowConfigs() {
|
|
636
|
+
ensureI18nInitialized();
|
|
637
|
+
const workflowTranslations = [
|
|
638
|
+
{
|
|
639
|
+
id: "interviewWorkflow",
|
|
640
|
+
name: i18n.t("workflow:workflowOption.interviewWorkflow"),
|
|
641
|
+
description: i18n.t("workflow:workflowDescription.interviewWorkflow"),
|
|
642
|
+
stats: i18n.t("workflow:workflowStats.interviewWorkflow")
|
|
643
|
+
},
|
|
644
|
+
{
|
|
645
|
+
id: "essentialTools",
|
|
646
|
+
name: i18n.t("workflow:workflowOption.essentialTools"),
|
|
647
|
+
description: i18n.t("workflow:workflowDescription.essentialTools"),
|
|
648
|
+
stats: i18n.t("workflow:workflowStats.essentialTools")
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
id: "gitWorkflow",
|
|
652
|
+
name: i18n.t("workflow:workflowOption.gitWorkflow"),
|
|
653
|
+
description: i18n.t("workflow:workflowDescription.gitWorkflow"),
|
|
654
|
+
stats: i18n.t("workflow:workflowStats.gitWorkflow")
|
|
655
|
+
},
|
|
656
|
+
{
|
|
657
|
+
id: "sixStepsWorkflow",
|
|
658
|
+
name: i18n.t("workflow:workflowOption.sixStepsWorkflow"),
|
|
659
|
+
description: i18n.t("workflow:workflowDescription.sixStepsWorkflow"),
|
|
660
|
+
stats: i18n.t("workflow:workflowStats.sixStepsWorkflow")
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
id: "specFirstTDD",
|
|
664
|
+
name: i18n.t("workflow:workflowOption.specFirstTDD"),
|
|
665
|
+
description: i18n.t("workflow:workflowDescription.specFirstTDD"),
|
|
666
|
+
stats: i18n.t("workflow:workflowStats.specFirstTDD")
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
id: "continuousDelivery",
|
|
670
|
+
name: i18n.t("workflow:workflowOption.continuousDelivery"),
|
|
671
|
+
description: i18n.t("workflow:workflowDescription.continuousDelivery"),
|
|
672
|
+
stats: i18n.t("workflow:workflowStats.continuousDelivery")
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
id: "refactoringMaster",
|
|
676
|
+
name: i18n.t("workflow:workflowOption.refactoringMaster"),
|
|
677
|
+
description: i18n.t("workflow:workflowDescription.refactoringMaster"),
|
|
678
|
+
stats: i18n.t("workflow:workflowStats.refactoringMaster")
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
id: "linearMethod",
|
|
682
|
+
name: i18n.t("workflow:workflowOption.linearMethod"),
|
|
683
|
+
description: i18n.t("workflow:workflowDescription.linearMethod"),
|
|
684
|
+
stats: i18n.t("workflow:workflowStats.linearMethod")
|
|
685
|
+
}
|
|
686
|
+
];
|
|
687
|
+
return WORKFLOW_CONFIG_BASE.map((baseConfig) => {
|
|
688
|
+
const translation = workflowTranslations.find((t) => t.id === baseConfig.id);
|
|
689
|
+
return {
|
|
690
|
+
...baseConfig,
|
|
691
|
+
name: translation?.name || baseConfig.id,
|
|
692
|
+
description: translation?.description,
|
|
693
|
+
stats: translation?.stats
|
|
694
|
+
};
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
function getWorkflowConfig(workflowId) {
|
|
698
|
+
return getWorkflowConfigs().find((config) => config.id === workflowId);
|
|
699
|
+
}
|
|
700
|
+
function getOrderedWorkflows() {
|
|
701
|
+
return getWorkflowConfigs().sort((a, b) => a.order - b.order);
|
|
702
|
+
}
|
|
703
|
+
function getTagLabel(tag) {
|
|
704
|
+
ensureI18nInitialized();
|
|
705
|
+
const tagKeys = {
|
|
706
|
+
recommended: "workflow:tags.recommended",
|
|
707
|
+
popular: "workflow:tags.popular",
|
|
708
|
+
new: "workflow:tags.new",
|
|
709
|
+
essential: "workflow:tags.essential",
|
|
710
|
+
professional: "workflow:tags.professional"
|
|
711
|
+
};
|
|
712
|
+
return i18n.t(tagKeys[tag]);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
function migrateSettingsForTokenRetrieval() {
|
|
716
|
+
ensureI18nInitialized();
|
|
717
|
+
const result = {
|
|
718
|
+
success: false,
|
|
719
|
+
changes: [],
|
|
720
|
+
backupPath: null,
|
|
721
|
+
errors: []
|
|
722
|
+
};
|
|
723
|
+
try {
|
|
724
|
+
if (!exists(SETTINGS_FILE)) {
|
|
725
|
+
result.errors.push(i18n.t("common:fileNotFound", { file: "settings.json" }));
|
|
726
|
+
return result;
|
|
727
|
+
}
|
|
728
|
+
const settings = readJsonConfig(SETTINGS_FILE);
|
|
729
|
+
if (!settings) {
|
|
730
|
+
result.errors.push(i18n.t("common:failedToReadFile", { file: "settings.json" }));
|
|
731
|
+
return result;
|
|
732
|
+
}
|
|
733
|
+
let modified = false;
|
|
734
|
+
if (settings.env) {
|
|
735
|
+
if ("CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC" in settings.env) {
|
|
736
|
+
delete settings.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC;
|
|
737
|
+
result.changes.push("Removed CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC (was blocking token retrieval)");
|
|
738
|
+
modified = true;
|
|
739
|
+
}
|
|
740
|
+
if (settings.env.MCP_TIMEOUT) {
|
|
741
|
+
const timeout = Number.parseInt(settings.env.MCP_TIMEOUT, 10);
|
|
742
|
+
if (!Number.isNaN(timeout) && timeout > 2e4) {
|
|
743
|
+
const oldValue = settings.env.MCP_TIMEOUT;
|
|
744
|
+
settings.env.MCP_TIMEOUT = "15000";
|
|
745
|
+
result.changes.push(`Reduced MCP_TIMEOUT from ${oldValue}ms to 15000ms (was causing slow failures)`);
|
|
746
|
+
modified = true;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
if (!modified) {
|
|
751
|
+
result.success = true;
|
|
752
|
+
return result;
|
|
753
|
+
}
|
|
754
|
+
const backupPath = backupExistingConfig();
|
|
755
|
+
if (backupPath) {
|
|
756
|
+
result.backupPath = backupPath;
|
|
757
|
+
} else {
|
|
758
|
+
result.errors.push("Failed to create backup (continuing anyway)");
|
|
759
|
+
}
|
|
760
|
+
writeJsonConfig(SETTINGS_FILE, settings);
|
|
761
|
+
result.success = true;
|
|
762
|
+
return result;
|
|
763
|
+
} catch (error) {
|
|
764
|
+
result.errors.push(`Migration failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
765
|
+
return result;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
function needsMigration() {
|
|
769
|
+
try {
|
|
770
|
+
if (!exists(SETTINGS_FILE)) {
|
|
771
|
+
return false;
|
|
772
|
+
}
|
|
773
|
+
const settings = readJsonConfig(SETTINGS_FILE);
|
|
774
|
+
if (!settings || !settings.env) {
|
|
775
|
+
return false;
|
|
776
|
+
}
|
|
777
|
+
const hasProblematicVar = "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC" in settings.env;
|
|
778
|
+
const hasExcessiveTimeout = settings.env.MCP_TIMEOUT && Number.parseInt(settings.env.MCP_TIMEOUT, 10) > 2e4;
|
|
779
|
+
return Boolean(hasProblematicVar || hasExcessiveTimeout);
|
|
780
|
+
} catch {
|
|
781
|
+
return false;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
function displayMigrationResult(result) {
|
|
785
|
+
ensureI18nInitialized();
|
|
786
|
+
if (result.success) {
|
|
787
|
+
if (result.changes.length > 0) {
|
|
788
|
+
console.log(ansis.green(`
|
|
789
|
+
\u2705 ${i18n.t("common:configurationFixed")}
|
|
790
|
+
`));
|
|
791
|
+
console.log(ansis.bold("Changes made:"));
|
|
792
|
+
for (const change of result.changes) {
|
|
793
|
+
console.log(ansis.gray(` \u2022 ${change}`));
|
|
794
|
+
}
|
|
795
|
+
if (result.backupPath) {
|
|
796
|
+
console.log(ansis.gray(`
|
|
797
|
+
\u{1F4E6} Backup created: ${result.backupPath}`));
|
|
798
|
+
}
|
|
799
|
+
console.log(ansis.yellow("\n\u26A0\uFE0F Please restart Claude Code CLI for changes to take effect.\n"));
|
|
800
|
+
} else {
|
|
801
|
+
console.log(ansis.green(`
|
|
802
|
+
\u2705 ${i18n.t("common:noMigrationNeeded")}
|
|
803
|
+
`));
|
|
804
|
+
}
|
|
805
|
+
} else {
|
|
806
|
+
console.log(ansis.red(`
|
|
807
|
+
\u274C ${i18n.t("common:migrationFailed")}
|
|
808
|
+
`));
|
|
809
|
+
if (result.errors.length > 0) {
|
|
810
|
+
console.log(ansis.bold("Errors:"));
|
|
811
|
+
for (const error of result.errors) {
|
|
812
|
+
console.log(ansis.red(` \u2022 ${error}`));
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
if (result.backupPath) {
|
|
816
|
+
console.log(ansis.gray(`
|
|
817
|
+
\u{1F4E6} Backup available at: ${result.backupPath}`));
|
|
818
|
+
console.log(ansis.gray("You can restore with: cp <backup-path>/settings.json ~/.claude/settings.json\n"));
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
async function promptMigration() {
|
|
823
|
+
ensureI18nInitialized();
|
|
824
|
+
const inquirer = await import('inquirer');
|
|
825
|
+
console.log(ansis.yellow("\n\u26A0\uFE0F Problematic configuration detected!\n"));
|
|
826
|
+
console.log(ansis.gray("Your settings.json contains configurations that prevent Claude Code"));
|
|
827
|
+
console.log(ansis.gray("from retrieving token counts, causing /compact failures.\n"));
|
|
828
|
+
const { shouldMigrate } = await inquirer.default.prompt({
|
|
829
|
+
type: "confirm",
|
|
830
|
+
name: "shouldMigrate",
|
|
831
|
+
message: "Would you like to fix these issues automatically? (backup will be created)",
|
|
832
|
+
default: true
|
|
833
|
+
});
|
|
834
|
+
return shouldMigrate;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
function getRootDir() {
|
|
838
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
839
|
+
const distDir = dirname(dirname(currentFilePath));
|
|
840
|
+
return dirname(distDir);
|
|
841
|
+
}
|
|
842
|
+
const DEFAULT_CODE_TOOL_TEMPLATE = "claude-code";
|
|
843
|
+
const COMMON_TEMPLATE_CATEGORIES = ["git", "sixStep", "essential", "interview", "specFirstTDD", "continuousDelivery", "refactoringMaster", "linearMethod"];
|
|
844
|
+
function formatTags(tags) {
|
|
845
|
+
const tagColors = {
|
|
846
|
+
recommended: (text) => ansis.bgGreen.black(` ${text} `),
|
|
847
|
+
popular: (text) => ansis.bgYellow.black(` ${text} `),
|
|
848
|
+
new: (text) => ansis.bgCyan.black(` ${text} `),
|
|
849
|
+
essential: (text) => ansis.bgBlue.white(` ${text} `),
|
|
850
|
+
professional: (text) => ansis.bgMagenta.white(` ${text} `)
|
|
851
|
+
};
|
|
852
|
+
return tags.map((tag) => tagColors[tag](getTagLabel(tag))).join(" ");
|
|
853
|
+
}
|
|
854
|
+
function buildWorkflowChoice(workflow) {
|
|
855
|
+
const tags = formatTags(workflow.metadata.tags);
|
|
856
|
+
const stats = workflow.stats ? ansis.dim(workflow.stats) : "";
|
|
857
|
+
const description = workflow.description ? ansis.gray(workflow.description) : "";
|
|
858
|
+
const nameLine = `${workflow.name} ${tags}`;
|
|
859
|
+
const detailLine = stats ? ` ${stats}` : "";
|
|
860
|
+
const descLine = description ? ` ${description}` : "";
|
|
861
|
+
const displayName = [nameLine, detailLine, descLine].filter(Boolean).join("\n");
|
|
862
|
+
return {
|
|
863
|
+
name: displayName,
|
|
864
|
+
value: workflow.id,
|
|
865
|
+
checked: workflow.defaultSelected
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
async function selectAndInstallWorkflows(configLang, preselectedWorkflows) {
|
|
869
|
+
ensureI18nInitialized();
|
|
870
|
+
const workflows = getOrderedWorkflows();
|
|
871
|
+
const choices = workflows.map((workflow) => buildWorkflowChoice(workflow));
|
|
872
|
+
let selectedWorkflows;
|
|
873
|
+
if (preselectedWorkflows) {
|
|
874
|
+
selectedWorkflows = preselectedWorkflows;
|
|
875
|
+
} else {
|
|
876
|
+
console.log("");
|
|
877
|
+
console.log(ansis.bold.cyan("\u2501".repeat(60)));
|
|
878
|
+
console.log(ansis.bold.white(` \u{1F680} ${i18n.t("workflow:selectWorkflowType")}`));
|
|
879
|
+
console.log(ansis.bold.cyan("\u2501".repeat(60)));
|
|
880
|
+
console.log("");
|
|
881
|
+
const response = await inquirer.prompt({
|
|
882
|
+
type: "checkbox",
|
|
883
|
+
name: "selectedWorkflows",
|
|
884
|
+
message: i18n.t("common:multiSelectHint"),
|
|
885
|
+
choices,
|
|
886
|
+
pageSize: 15
|
|
887
|
+
});
|
|
888
|
+
selectedWorkflows = response.selectedWorkflows;
|
|
889
|
+
}
|
|
890
|
+
if (!selectedWorkflows || selectedWorkflows.length === 0) {
|
|
891
|
+
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
await cleanupOldVersionFiles();
|
|
895
|
+
for (const workflowId of selectedWorkflows) {
|
|
896
|
+
const config = getWorkflowConfig(workflowId);
|
|
897
|
+
if (config) {
|
|
898
|
+
await installWorkflowWithDependencies(config, configLang);
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
async function installWorkflowWithDependencies(config, configLang) {
|
|
903
|
+
const rootDir = getRootDir();
|
|
904
|
+
ensureI18nInitialized();
|
|
905
|
+
const result = {
|
|
906
|
+
workflow: config.id,
|
|
907
|
+
success: true,
|
|
908
|
+
installedCommands: [],
|
|
909
|
+
installedAgents: [],
|
|
910
|
+
errors: []
|
|
911
|
+
};
|
|
912
|
+
const WORKFLOW_OPTION_KEYS = {
|
|
913
|
+
essentialTools: i18n.t("workflow:workflowOption.essentialTools"),
|
|
914
|
+
sixStepsWorkflow: i18n.t("workflow:workflowOption.sixStepsWorkflow"),
|
|
915
|
+
gitWorkflow: i18n.t("workflow:workflowOption.gitWorkflow"),
|
|
916
|
+
interviewWorkflow: i18n.t("workflow:workflowOption.interviewWorkflow"),
|
|
917
|
+
specFirstTDD: i18n.t("workflow:workflowOption.specFirstTDD"),
|
|
918
|
+
continuousDelivery: i18n.t("workflow:workflowOption.continuousDelivery"),
|
|
919
|
+
refactoringMaster: i18n.t("workflow:workflowOption.refactoringMaster"),
|
|
920
|
+
linearMethod: i18n.t("workflow:workflowOption.linearMethod")
|
|
921
|
+
};
|
|
922
|
+
const workflowName = WORKFLOW_OPTION_KEYS[config.id] || config.id;
|
|
923
|
+
console.log(ansis.green(`
|
|
924
|
+
\u{1F4E6} ${i18n.t("workflow:installingWorkflow")}: ${workflowName}...`));
|
|
925
|
+
const commandsDir = join(CLAUDE_DIR, "commands", "ccjk");
|
|
926
|
+
if (!existsSync(commandsDir)) {
|
|
927
|
+
await mkdir(commandsDir, { recursive: true });
|
|
928
|
+
}
|
|
929
|
+
for (const commandFile of config.commands) {
|
|
930
|
+
const isCommonTemplate = COMMON_TEMPLATE_CATEGORIES.includes(config.category);
|
|
931
|
+
const commandSource = isCommonTemplate ? join(
|
|
932
|
+
rootDir,
|
|
933
|
+
"templates",
|
|
934
|
+
"common",
|
|
935
|
+
"workflow",
|
|
936
|
+
config.category,
|
|
937
|
+
configLang,
|
|
938
|
+
commandFile
|
|
939
|
+
) : join(
|
|
940
|
+
rootDir,
|
|
941
|
+
"templates",
|
|
942
|
+
DEFAULT_CODE_TOOL_TEMPLATE,
|
|
943
|
+
configLang,
|
|
944
|
+
"workflow",
|
|
945
|
+
config.category,
|
|
946
|
+
"commands",
|
|
947
|
+
commandFile
|
|
948
|
+
);
|
|
949
|
+
const destFileName = commandFile;
|
|
950
|
+
const commandDest = join(commandsDir, destFileName);
|
|
951
|
+
if (existsSync(commandSource)) {
|
|
952
|
+
try {
|
|
953
|
+
await copyFile$1(commandSource, commandDest);
|
|
954
|
+
result.installedCommands.push(destFileName);
|
|
955
|
+
console.log(ansis.gray(` \u2714 ${i18n.t("workflow:installedCommand")}: ccjk/${destFileName}`));
|
|
956
|
+
} catch (error) {
|
|
957
|
+
const errorMsg = `${i18n.t("workflow:failedToInstallCommand")} ${commandFile}: ${error}`;
|
|
958
|
+
result.errors?.push(errorMsg);
|
|
959
|
+
console.error(ansis.red(` \u2717 ${errorMsg}`));
|
|
960
|
+
result.success = false;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
if (config.autoInstallAgents && config.agents.length > 0) {
|
|
965
|
+
const agentsCategoryDir = join(CLAUDE_DIR, "agents", "ccjk", config.category);
|
|
966
|
+
if (!existsSync(agentsCategoryDir)) {
|
|
967
|
+
await mkdir(agentsCategoryDir, { recursive: true });
|
|
968
|
+
}
|
|
969
|
+
for (const agent of config.agents) {
|
|
970
|
+
const isCommonTemplate = COMMON_TEMPLATE_CATEGORIES.includes(config.category);
|
|
971
|
+
const agentSource = isCommonTemplate ? join(
|
|
972
|
+
rootDir,
|
|
973
|
+
"templates",
|
|
974
|
+
"common",
|
|
975
|
+
"workflow",
|
|
976
|
+
config.category,
|
|
977
|
+
configLang,
|
|
978
|
+
"agents",
|
|
979
|
+
agent.filename
|
|
980
|
+
) : join(
|
|
981
|
+
rootDir,
|
|
982
|
+
"templates",
|
|
983
|
+
DEFAULT_CODE_TOOL_TEMPLATE,
|
|
984
|
+
configLang,
|
|
985
|
+
"workflow",
|
|
986
|
+
config.category,
|
|
987
|
+
"agents",
|
|
988
|
+
agent.filename
|
|
989
|
+
);
|
|
990
|
+
const agentDest = join(agentsCategoryDir, agent.filename);
|
|
991
|
+
if (existsSync(agentSource)) {
|
|
992
|
+
try {
|
|
993
|
+
await copyFile$1(agentSource, agentDest);
|
|
994
|
+
result.installedAgents.push(agent.filename);
|
|
995
|
+
console.log(ansis.gray(` \u2714 ${i18n.t("workflow:installedAgent")}: ccjk/${config.category}/${agent.filename}`));
|
|
996
|
+
} catch (error) {
|
|
997
|
+
const errorMsg = `${i18n.t("workflow:failedToInstallAgent")} ${agent.filename}: ${error}`;
|
|
998
|
+
result.errors?.push(errorMsg);
|
|
999
|
+
console.error(ansis.red(` \u2717 ${errorMsg}`));
|
|
1000
|
+
if (agent.required) {
|
|
1001
|
+
result.success = false;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
if (result.success) {
|
|
1008
|
+
console.log(ansis.green(`\u2714 ${workflowName} ${i18n.t("workflow:workflowInstallSuccess")}`));
|
|
1009
|
+
} else {
|
|
1010
|
+
console.log(ansis.red(`\u2717 ${workflowName} ${i18n.t("workflow:workflowInstallError")}`));
|
|
1011
|
+
}
|
|
1012
|
+
return result;
|
|
1013
|
+
}
|
|
1014
|
+
async function cleanupOldVersionFiles() {
|
|
1015
|
+
ensureI18nInitialized();
|
|
1016
|
+
console.log(ansis.green(`
|
|
1017
|
+
\u{1F9F9} ${i18n.t("workflow:cleaningOldFiles")}...`));
|
|
1018
|
+
const oldCommandFiles = [
|
|
1019
|
+
join(CLAUDE_DIR, "commands", "workflow.md"),
|
|
1020
|
+
join(CLAUDE_DIR, "commands", "feat.md")
|
|
1021
|
+
];
|
|
1022
|
+
const oldAgentFiles = [
|
|
1023
|
+
join(CLAUDE_DIR, "agents", "planner.md"),
|
|
1024
|
+
join(CLAUDE_DIR, "agents", "ui-ux-designer.md")
|
|
1025
|
+
];
|
|
1026
|
+
for (const file of oldCommandFiles) {
|
|
1027
|
+
if (existsSync(file)) {
|
|
1028
|
+
try {
|
|
1029
|
+
await rm(file, { force: true });
|
|
1030
|
+
console.log(ansis.gray(` \u2714 ${i18n.t("workflow:removedOldFile")}: ${file.replace(CLAUDE_DIR, "~/.claude")}`));
|
|
1031
|
+
} catch {
|
|
1032
|
+
console.error(ansis.yellow(` \u26A0 ${i18n.t("errors:failedToRemoveFile")}: ${file.replace(CLAUDE_DIR, "~/.claude")}`));
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
for (const file of oldAgentFiles) {
|
|
1037
|
+
if (existsSync(file)) {
|
|
1038
|
+
try {
|
|
1039
|
+
await rm(file, { force: true });
|
|
1040
|
+
console.log(ansis.gray(` \u2714 ${i18n.t("workflow:removedOldFile")}: ${file.replace(CLAUDE_DIR, "~/.claude")}`));
|
|
1041
|
+
} catch {
|
|
1042
|
+
console.error(ansis.yellow(` \u26A0 ${i18n.t("errors:failedToRemoveFile")}: ${file.replace(CLAUDE_DIR, "~/.claude")}`));
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
export { WORKFLOW_CONFIG_BASE as W, migrateSettingsForTokenRetrieval as a, configureOutputStyle as b, configureApiCompletely as c, displayMigrationResult as d, formatApiKeyDisplay as f, modifyApiConfigPartially as m, needsMigration as n, promptMigration as p, selectAndInstallWorkflows as s, updatePromptOnly as u, validateApiKey as v };
|