aico-cli 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +93 -0
- package/bin/aico.mjs +2 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.mjs +1475 -0
- package/dist/index.d.mts +154 -0
- package/dist/index.d.ts +154 -0
- package/dist/index.mjs +10 -0
- package/dist/shared/aico-cli.D4gky7Vp.mjs +2322 -0
- package/package.json +57 -0
- package/templates/CLAUDE.md +5 -0
- package/templates/en/memory/mcp.md +6 -0
- package/templates/en/memory/personality.md +1 -0
- package/templates/en/memory/rules.md +45 -0
- package/templates/en/memory/technical-guides.md +97 -0
- package/templates/en/workflow/bmad/commands/bmad-init.md +103 -0
- package/templates/en/workflow/git/commands/git-cleanBranches.md +101 -0
- package/templates/en/workflow/git/commands/git-commit.md +152 -0
- package/templates/en/workflow/git/commands/git-rollback.md +89 -0
- package/templates/en/workflow/plan/agents/planner.md +116 -0
- package/templates/en/workflow/plan/agents/ui-ux-designer.md +91 -0
- package/templates/en/workflow/plan/commands/feat.md +105 -0
- package/templates/en/workflow/sixStep/commands/workflow.md +230 -0
- package/templates/settings.json +33 -0
- package/templates/zh-CN/memory/mcp.md +34 -0
- package/templates/zh-CN/memory/personality.md +1 -0
- package/templates/zh-CN/memory/rules.md +45 -0
- package/templates/zh-CN/memory/technical-guides.md +126 -0
- package/templates/zh-CN/workflow/bmad/commands/bmad-init.md +109 -0
- package/templates/zh-CN/workflow/git/commands/git-cleanBranches.md +101 -0
- package/templates/zh-CN/workflow/git/commands/git-commit.md +152 -0
- package/templates/zh-CN/workflow/git/commands/git-rollback.md +90 -0
- package/templates/zh-CN/workflow/plan/agents/planner.md +116 -0
- package/templates/zh-CN/workflow/plan/agents/ui-ux-designer.md +91 -0
- package/templates/zh-CN/workflow/plan/commands/feat.md +105 -0
- package/templates/zh-CN/workflow/sixStep/commands/workflow.md +199 -0
|
@@ -0,0 +1,2322 @@
|
|
|
1
|
+
import inquirer$1 from 'inquirer';
|
|
2
|
+
import ansis from 'ansis';
|
|
3
|
+
import { existsSync, mkdirSync, copyFileSync, writeFileSync, readdirSync, statSync, readFileSync } from 'node:fs';
|
|
4
|
+
import { join, dirname } from 'pathe';
|
|
5
|
+
import dayjs from 'dayjs';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { exec } from 'tinyexec';
|
|
8
|
+
import { rm, mkdir, copyFile as copyFile$1 } from 'node:fs/promises';
|
|
9
|
+
import { homedir, platform } from 'node:os';
|
|
10
|
+
|
|
11
|
+
class EscapeKeyPressed extends Error {
|
|
12
|
+
constructor() {
|
|
13
|
+
super("BACK_KEY_PRESSED");
|
|
14
|
+
this.name = "EscapeKeyPressed";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async function createEscapablePrompt(promptConfig) {
|
|
18
|
+
let modifiedConfig = promptConfig;
|
|
19
|
+
if (promptConfig.type === "list" && promptConfig.choices) {
|
|
20
|
+
const backChoice = {
|
|
21
|
+
name: ansis.gray("\u2190 \u8FD4\u56DE\u4E0A\u4E00\u6B65"),
|
|
22
|
+
value: "__BACK_KEY__",
|
|
23
|
+
short: "\u8FD4\u56DE\u4E0A\u4E00\u6B65"
|
|
24
|
+
};
|
|
25
|
+
modifiedConfig = {
|
|
26
|
+
...promptConfig,
|
|
27
|
+
choices: [...promptConfig.choices, new inquirer$1.Separator(), backChoice]
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (promptConfig.type === "checkbox" && promptConfig.choices) {
|
|
31
|
+
const backChoice = {
|
|
32
|
+
name: ansis.gray("\u2190 \u8FD4\u56DE\u4E0A\u4E00\u6B65"),
|
|
33
|
+
value: "__BACK_KEY__",
|
|
34
|
+
short: "\u8FD4\u56DE\u4E0A\u4E00\u6B65"
|
|
35
|
+
};
|
|
36
|
+
modifiedConfig = {
|
|
37
|
+
...promptConfig,
|
|
38
|
+
choices: [...promptConfig.choices, new inquirer$1.Separator(), backChoice],
|
|
39
|
+
message: `${promptConfig.message} ${ansis.gray(
|
|
40
|
+
'(\u9009\u62E9"\u8FD4\u56DE\u4E0A\u4E00\u6B65"\u6216\u4E0D\u9009\u62E9\u4EFB\u4F55\u9879\u76EE)'
|
|
41
|
+
)}`
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const result = await inquirer$1.prompt(modifiedConfig);
|
|
45
|
+
const resultValue = result[promptConfig.name];
|
|
46
|
+
if (resultValue === "__BACK_KEY__") {
|
|
47
|
+
throw new EscapeKeyPressed();
|
|
48
|
+
}
|
|
49
|
+
if (promptConfig.type === "checkbox" && Array.isArray(resultValue)) {
|
|
50
|
+
if (resultValue.includes("__BACK_KEY__") || resultValue.length === 0) {
|
|
51
|
+
throw new EscapeKeyPressed();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
async function executeWithEscapeSupport(processor, i18n) {
|
|
57
|
+
try {
|
|
58
|
+
await processor();
|
|
59
|
+
return true;
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (error instanceof EscapeKeyPressed) {
|
|
62
|
+
console.log(
|
|
63
|
+
ansis.yellow(`
|
|
64
|
+
${i18n.common.returnToPrevious || "\u8FD4\u56DE\u4E0A\u4E00\u6B65"}`)
|
|
65
|
+
);
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const inquirer = {
|
|
73
|
+
...inquirer$1,
|
|
74
|
+
prompt: createEscapablePrompt,
|
|
75
|
+
createPromptModule: inquirer$1.createPromptModule
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const version = "0.0.1";
|
|
79
|
+
|
|
80
|
+
const common$1 = {
|
|
81
|
+
// Basic
|
|
82
|
+
multiSelectHint: "\uFF08\u7A7A\u683C\u9009\u62E9\uFF0Ca\u5168\u9009\uFF0Ci\u53CD\u9009\uFF0C\u56DE\u8F66\u786E\u8BA4\uFF09",
|
|
83
|
+
yes: "\u662F",
|
|
84
|
+
no: "\u5426",
|
|
85
|
+
skip: "\u8DF3\u8FC7",
|
|
86
|
+
cancelled: "\u64CD\u4F5C\u5DF2\u53D6\u6D88",
|
|
87
|
+
error: "\u9519\u8BEF",
|
|
88
|
+
complete: "\u{1F389} \u914D\u7F6E\u5B8C\u6210\uFF01\u4F7F\u7528 'claude' \u547D\u4EE4\u5F00\u59CB\u4F53\u9A8C\u3002",
|
|
89
|
+
none: "\u65E0",
|
|
90
|
+
notConfigured: "\u672A\u914D\u7F6E",
|
|
91
|
+
spaceToSelectReturn: "- \u7A7A\u683C\u9009\u62E9\uFF0C\u56DE\u8F66\u63D0\u4EA4",
|
|
92
|
+
enterChoice: "\u8BF7\u8F93\u5165\u9009\u9879\uFF0C\u56DE\u8F66\u786E\u8BA4\uFF08\u4E0D\u533A\u5206\u5927\u5C0F\u5199\uFF09",
|
|
93
|
+
invalidChoice: "\u65E0\u6548\u9009\u62E9\u3002\u8BF7\u8F93\u5165\u6709\u6548\u9009\u9879\u3002",
|
|
94
|
+
goodbye: "\u{1F44B} \u611F\u8C22\u4F7F\u7528 \u667A\u80FD\u8F6F\u4EF6\u661F\u5DE5\u5382\uFF01\u518D\u89C1\uFF01",
|
|
95
|
+
returnToMenu: "\u8FD4\u56DE\u4E3B\u83DC\u5355\uFF1F",
|
|
96
|
+
back: "\u8FD4\u56DE"
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const language$1 = {
|
|
100
|
+
selectScriptLang: "\u9009\u62E9AICO\u663E\u793A\u8BED\u8A00",
|
|
101
|
+
selectConfigLang: "\u9009\u62E9 Claude Code \u914D\u7F6E\u8BED\u8A00",
|
|
102
|
+
selectAiOutputLang: "\u9009\u62E9 AI \u8F93\u51FA\u8BED\u8A00",
|
|
103
|
+
aiOutputLangHint: "AI \u5C06\u4F7F\u7528\u6B64\u8BED\u8A00\u56DE\u590D\u4F60\u7684\u95EE\u9898",
|
|
104
|
+
enterCustomLanguage: "\u8BF7\u8F93\u5165\u81EA\u5B9A\u4E49\u8BED\u8A00\uFF08\u4F8B\u5982\uFF1AJapanese, French \u7B49\uFF09",
|
|
105
|
+
languageChanged: "\u8BED\u8A00\u5DF2\u66F4\u6539",
|
|
106
|
+
configLangHint: {
|
|
107
|
+
"zh-CN": "\u4FBF\u4E8E\u4E2D\u6587\u7528\u6237\u81EA\u5B9A\u4E49",
|
|
108
|
+
en: "\u63A8\u8350\uFF0Ctoken \u6D88\u8017\u66F4\u4F4E"
|
|
109
|
+
},
|
|
110
|
+
updateConfigLangPrompt: "\u9009\u62E9\u914D\u7F6E\u8BED\u8A00",
|
|
111
|
+
updateConfigLangChoice: {
|
|
112
|
+
"zh-CN": "\u4E2D\u6587\u7248\u914D\u7F6E",
|
|
113
|
+
en: "\u82F1\u6587\u7248\u914D\u7F6E"
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const installation$1 = {
|
|
118
|
+
installPrompt: "\u68C0\u6D4B\u5230 Claude Code \u672A\u5B89\u88C5\uFF0C\u662F\u5426\u81EA\u52A8\u5B89\u88C5\uFF1F",
|
|
119
|
+
installing: "\u6B63\u5728\u5B89\u88C5 Claude Code...",
|
|
120
|
+
installSuccess: "Claude Code \u5B89\u88C5\u6210\u529F",
|
|
121
|
+
alreadyInstalled: "Claude Code \u5DF2\u5B89\u88C5",
|
|
122
|
+
installFailed: "Claude Code \u5B89\u88C5\u5931\u8D25",
|
|
123
|
+
npmNotFound: "npm \u672A\u5B89\u88C5\u3002\u8BF7\u5148\u5B89\u88C5 Node.js \u548C npm\u3002",
|
|
124
|
+
// Termux specific
|
|
125
|
+
termuxDetected: "\u68C0\u6D4B\u5230 Termux \u73AF\u5883",
|
|
126
|
+
termuxInstallHint: "\u5728 Termux \u4E2D\uFF0C\u8BF7\u5148\u8FD0\u884C: pkg install nodejs \u6216 pkg install nodejs-lts",
|
|
127
|
+
termuxPathInfo: "\u4F7F\u7528 Termux \u8DEF\u5F84: {path}",
|
|
128
|
+
termuxEnvironmentInfo: "Termux \u73AF\u5883\u901A\u8FC7 pkg \u7BA1\u7406\u5668\u63D0\u4F9B Node.js \u548C npm",
|
|
129
|
+
// Windows specific
|
|
130
|
+
windowsDetected: "\u68C0\u6D4B\u5230 Windows \u7CFB\u7EDF\uFF0C\u5C06\u81EA\u52A8\u914D\u7F6E\u517C\u5BB9\u683C\u5F0F"
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const api$1 = {
|
|
134
|
+
// Basic API configuration
|
|
135
|
+
configureApi: "\u9009\u62E9 API \u8BA4\u8BC1\u65B9\u5F0F",
|
|
136
|
+
useAuthToken: "\u4F7F\u7528 Auth Token (OAuth \u8BA4\u8BC1)",
|
|
137
|
+
authTokenDesc: "\u9002\u7528\u4E8E\u901A\u8FC7 OAuth \u6216\u6D4F\u89C8\u5668\u767B\u5F55\u83B7\u53D6\u7684\u4EE4\u724C",
|
|
138
|
+
useApiKey: "\u4F7F\u7528 API Key (\u5BC6\u94A5\u8BA4\u8BC1)",
|
|
139
|
+
apiKeyDesc: "\u9002\u7528\u4E8E\u4ECE Anthropic Console \u83B7\u53D6\u7684 API \u5BC6\u94A5",
|
|
140
|
+
useCcrProxy: "\u4F7F\u7528 CCR \u4EE3\u7406",
|
|
141
|
+
ccrProxyDesc: "\u901A\u8FC7 Claude Code Router \u4F7F\u7528\u591A\u4E2A AI \u6A21\u578B",
|
|
142
|
+
skipApi: "\u8DF3\u8FC7\uFF08\u7A0D\u540E\u624B\u52A8\u914D\u7F6E\uFF09",
|
|
143
|
+
enterApiUrl: "\u8BF7\u8F93\u5165 API URL",
|
|
144
|
+
enterAuthToken: "\u8BF7\u8F93\u5165 Auth Token",
|
|
145
|
+
enterApiKey: "\u8BF7\u8F93\u5165 API Key",
|
|
146
|
+
apiConfigSuccess: "API \u914D\u7F6E\u5B8C\u6210",
|
|
147
|
+
// API modification
|
|
148
|
+
existingApiConfig: "\u68C0\u6D4B\u5230\u5DF2\u6709 API \u914D\u7F6E\uFF1A",
|
|
149
|
+
apiConfigUrl: "URL",
|
|
150
|
+
apiConfigKey: "Key",
|
|
151
|
+
apiConfigAuthType: "\u8BA4\u8BC1\u7C7B\u578B",
|
|
152
|
+
selectApiAction: "\u8BF7\u9009\u62E9API\u5904\u7406\u64CD\u4F5C",
|
|
153
|
+
keepExistingConfig: "\u4FDD\u7559\u73B0\u6709\u914D\u7F6E",
|
|
154
|
+
modifyAllConfig: "\u4FEE\u6539\u5168\u90E8\u914D\u7F6E",
|
|
155
|
+
modifyPartialConfig: "\u4FEE\u6539\u90E8\u5206\u914D\u7F6E",
|
|
156
|
+
selectModifyItems: "\u8BF7\u9009\u62E9\u8981\u4FEE\u6539\u7684\u9879",
|
|
157
|
+
modifyApiUrl: "\u4FEE\u6539 API URL",
|
|
158
|
+
modifyApiKey: "\u4FEE\u6539 API Key",
|
|
159
|
+
modifyAuthType: "\u4FEE\u6539\u8BA4\u8BC1\u7C7B\u578B",
|
|
160
|
+
continueModification: "\u662F\u5426\u7EE7\u7EED\u4FEE\u6539\u5176\u4ED6\u914D\u7F6E\uFF1F",
|
|
161
|
+
modificationSaved: "\u914D\u7F6E\u5DF2\u4FDD\u5B58",
|
|
162
|
+
enterNewApiUrl: "\u8BF7\u8F93\u5165\u65B0\u7684 API URL\uFF08\u5F53\u524D\uFF1A{url}\uFF09",
|
|
163
|
+
enterNewApiKey: "\u8BF7\u8F93\u5165\u65B0\u7684 API Key\uFF08\u5F53\u524D\uFF1A{key}\uFF09",
|
|
164
|
+
selectNewAuthType: "\u9009\u62E9\u65B0\u7684\u8BA4\u8BC1\u7C7B\u578B\uFF08\u5F53\u524D\uFF1A{type}\uFF09",
|
|
165
|
+
// API validation
|
|
166
|
+
apiKeyValidation: {
|
|
167
|
+
empty: "API Key \u4E0D\u80FD\u4E3A\u7A7A",
|
|
168
|
+
example: "\u793A\u4F8B\u683C\u5F0F: sk-abcdef123456_789xyz"
|
|
169
|
+
},
|
|
170
|
+
urlRequired: "URL \u4E3A\u5FC5\u586B\u9879",
|
|
171
|
+
invalidUrl: "\u65E0\u6548\u7684 URL",
|
|
172
|
+
keyRequired: "\u5BC6\u94A5\u4E3A\u5FC5\u586B\u9879",
|
|
173
|
+
invalidKeyFormat: "\u65E0\u6548\u7684\u5BC6\u94A5\u683C\u5F0F"
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const configuration$1 = {
|
|
177
|
+
existingConfig: "\u68C0\u6D4B\u5230\u5DF2\u6709\u914D\u7F6E\u6587\u4EF6\uFF0C\u5982\u4F55\u5904\u7406\uFF1F",
|
|
178
|
+
backupAndOverwrite: "\u5907\u4EFD\u5E76\u8986\u76D6\u5168\u90E8",
|
|
179
|
+
updateDocsOnly: "\u4EC5\u66F4\u65B0\u5DE5\u4F5C\u6D41\u76F8\u5173md\u5E76\u5907\u4EFD\u65E7\u914D\u7F6E",
|
|
180
|
+
mergeConfig: "\u5408\u5E76\u914D\u7F6E",
|
|
181
|
+
backupSuccess: "\u5DF2\u5907\u4EFD\u6240\u6709\u914D\u7F6E\u6587\u4EF6\u5230",
|
|
182
|
+
copying: "\u6B63\u5728\u590D\u5236\u914D\u7F6E\u6587\u4EF6...",
|
|
183
|
+
configSuccess: "\u914D\u7F6E\u6587\u4EF6\u5DF2\u590D\u5236\u5230",
|
|
184
|
+
noExistingConfig: "\u672A\u627E\u5230\u73B0\u6709\u914D\u7F6E\u3002\u8BF7\u5148\u8FD0\u884C `aico`\u3002",
|
|
185
|
+
updatingPrompts: "\u6B63\u5728\u66F4\u65B0 Claude Code \u8BB0\u5FC6\u6587\u6863...",
|
|
186
|
+
// Model configuration
|
|
187
|
+
selectDefaultModel: "\u9009\u62E9\u9ED8\u8BA4\u6A21\u578B",
|
|
188
|
+
modelConfigSuccess: "\u9ED8\u8BA4\u6A21\u578B\u5DF2\u914D\u7F6E",
|
|
189
|
+
// AI memory configuration
|
|
190
|
+
selectMemoryOption: "\u9009\u62E9\u914D\u7F6E\u9009\u9879",
|
|
191
|
+
configureAiLanguage: "\u914D\u7F6E AI \u8F93\u51FA\u8BED\u8A00",
|
|
192
|
+
configureAiPersonality: "\u914D\u7F6E AI \u4E2A\u6027\u98CE\u683C",
|
|
193
|
+
aiLanguageConfigured: "AI \u8F93\u51FA\u8BED\u8A00\u5DF2\u914D\u7F6E",
|
|
194
|
+
// AI personality
|
|
195
|
+
selectAiPersonality: "\u9009\u62E9 AI \u4E2A\u6027\u98CE\u683C",
|
|
196
|
+
customPersonalityHint: "\u5B9A\u4E49\u4F60\u81EA\u5DF1\u7684\u4E2A\u6027",
|
|
197
|
+
enterCustomPersonality: "\u8BF7\u8F93\u5165\u81EA\u5B9A\u4E49\u4E2A\u6027\u63CF\u8FF0",
|
|
198
|
+
personalityConfigured: "AI \u4E2A\u6027\u5DF2\u914D\u7F6E",
|
|
199
|
+
existingPersonality: "\u68C0\u6D4B\u5230\u5DF2\u6709 AI \u4E2A\u6027\u914D\u7F6E",
|
|
200
|
+
currentPersonality: "\u5F53\u524D\u4E2A\u6027",
|
|
201
|
+
modifyPersonality: "\u662F\u5426\u4FEE\u6539 AI \u4E2A\u6027\u914D\u7F6E\uFF1F",
|
|
202
|
+
keepPersonality: "\u4FDD\u6301\u5F53\u524D\u4E2A\u6027\u914D\u7F6E",
|
|
203
|
+
directiveCannotBeEmpty: "\u6307\u4EE4\u4E0D\u80FD\u4E3A\u7A7A",
|
|
204
|
+
languageRequired: "\u8BED\u8A00\u4E3A\u5FC5\u586B\u9879",
|
|
205
|
+
// Cache
|
|
206
|
+
confirmClearCache: "\u786E\u8BA4\u6E05\u9664\u6240\u6709 AICO \u504F\u597D\u7F13\u5B58\uFF1F",
|
|
207
|
+
cacheCleared: "AICO \u7F13\u5B58\u5DF2\u6E05\u9664",
|
|
208
|
+
noCacheFound: "\u672A\u627E\u5230\u7F13\u5B58\u6587\u4EF6",
|
|
209
|
+
// Environment and permissions
|
|
210
|
+
selectEnvPermissionOption: "\u8BF7\u9009\u62E9\u914D\u7F6E\u9009\u9879",
|
|
211
|
+
importRecommendedEnv: "\u5BFC\u5165 AICO \u63A8\u8350\u73AF\u5883\u53D8\u91CF",
|
|
212
|
+
importRecommendedEnvDesc: "\u9690\u79C1\u4FDD\u62A4\u53D8\u91CF\u7B49",
|
|
213
|
+
importRecommendedPermissions: "\u5BFC\u5165 AICO \u63A8\u8350\u6743\u9650\u914D\u7F6E",
|
|
214
|
+
importRecommendedPermissionsDesc: "\u51E0\u4E4E\u5168\u90E8\u6743\u9650\uFF0C\u51CF\u5C11\u9891\u7E41\u8BF7\u6C42\u6743\u9650\uFF0C\u5371\u9669\u64CD\u4F5C\u7531\u89C4\u5219\u9650\u5236",
|
|
215
|
+
openSettingsJson: "\u6253\u5F00 settings.json \u624B\u52A8\u914D\u7F6E",
|
|
216
|
+
openSettingsJsonDesc: "\u9AD8\u7EA7\u7528\u6237\u81EA\u5B9A\u4E49",
|
|
217
|
+
envImportSuccess: "\u73AF\u5883\u53D8\u91CF\u5DF2\u5BFC\u5165",
|
|
218
|
+
permissionsImportSuccess: "\u6743\u9650\u914D\u7F6E\u5DF2\u5BFC\u5165",
|
|
219
|
+
openingSettingsJson: "\u6B63\u5728\u6253\u5F00 settings.json...",
|
|
220
|
+
// JSON config related
|
|
221
|
+
invalidConfiguration: "\u914D\u7F6E\u65E0\u6548",
|
|
222
|
+
failedToParseJson: "\u89E3\u6790 JSON \u6587\u4EF6\u5931\u8D25:",
|
|
223
|
+
failedToBackupConfig: "\u5907\u4EFD\u914D\u7F6E\u5931\u8D25",
|
|
224
|
+
failedToReadTemplateSettings: "\u8BFB\u53D6\u6A21\u677F\u8BBE\u7F6E\u5931\u8D25",
|
|
225
|
+
failedToMergeSettings: "\u5408\u5E76\u8BBE\u7F6E\u5931\u8D25",
|
|
226
|
+
preservingExistingSettings: "\u4FDD\u7559\u73B0\u6709\u8BBE\u7F6E",
|
|
227
|
+
memoryDirNotFound: "\u672A\u627E\u5230\u8BB0\u5FC6\u76EE\u5F55",
|
|
228
|
+
failedToSetOnboarding: "\u8BBE\u7F6E\u5F15\u5BFC\u6807\u5FD7\u5931\u8D25",
|
|
229
|
+
fixWindowsMcp: "\u4FEE\u590D Windows MCP \u914D\u7F6E\uFF1F"
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const mcp$1 = {
|
|
233
|
+
configureMcp: "\u662F\u5426\u914D\u7F6E MCP \u670D\u52A1\uFF1F",
|
|
234
|
+
selectMcpServices: "\u9009\u62E9\u8981\u5B89\u88C5\u7684 MCP \u670D\u52A1",
|
|
235
|
+
allServices: "\u5168\u90E8\u5B89\u88C5",
|
|
236
|
+
mcpServiceInstalled: "\u5DF2\u9009\u62E9\u7684 MCP \u670D\u52A1",
|
|
237
|
+
enterExaApiKey: "\u8BF7\u8F93\u5165 Exa API Key\uFF08\u53EF\u4ECE https://dashboard.exa.ai/api-keys \u83B7\u53D6\uFF09",
|
|
238
|
+
skipMcp: "\u8DF3\u8FC7 MCP \u914D\u7F6E",
|
|
239
|
+
mcpConfigSuccess: "MCP \u670D\u52A1\u5DF2\u914D\u7F6E",
|
|
240
|
+
mcpBackupSuccess: "\u5DF2\u5907\u4EFD\u539F\u6709 MCP \u914D\u7F6E",
|
|
241
|
+
fixWindowsMcp: "\u4FEE\u590D Windows MCP \u914D\u7F6E",
|
|
242
|
+
fixWindowsMcpDesc: "\u4FEE\u590D Windows \u5E73\u53F0 MCP \u547D\u4EE4\u914D\u7F6E\u95EE\u9898",
|
|
243
|
+
windowsMcpFixed: "Windows MCP \u914D\u7F6E\u5DF2\u4FEE\u590D",
|
|
244
|
+
configureMcpServices: "\u914D\u7F6E MCP \u670D\u52A1",
|
|
245
|
+
selectMcpOption: "\u9009\u62E9 MCP \u914D\u7F6E\u9009\u9879"
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const menu$1 = {
|
|
249
|
+
selectFunction: "\u8BF7\u9009\u62E9\u529F\u80FD",
|
|
250
|
+
menuSections: {
|
|
251
|
+
otherTools: "\u5176\u4ED6\u5DE5\u5177"
|
|
252
|
+
},
|
|
253
|
+
menuOptions: {
|
|
254
|
+
fullInit: "\u5B8C\u6574\u521D\u59CB\u5316\u914D\u7F6E",
|
|
255
|
+
importWorkflow: "\u5BFC\u5165\u5DE5\u4F5C\u6D41",
|
|
256
|
+
configureApiOrCcr: "\u914D\u7F6E API \u6216 CCR \u4EE3\u7406",
|
|
257
|
+
configureApi: "\u914D\u7F6E API",
|
|
258
|
+
configureMcp: "\u914D\u7F6E MCP",
|
|
259
|
+
configureModel: "\u914D\u7F6E\u9ED8\u8BA4\u6A21\u578B",
|
|
260
|
+
configureAiMemory: "\u914D\u7F6E Claude \u5168\u5C40\u8BB0\u5FC6",
|
|
261
|
+
configureEnvPermission: "\u5BFC\u5165\u63A8\u8350\u73AF\u5883\u53D8\u91CF\u548C\u6743\u9650\u914D\u7F6E",
|
|
262
|
+
configureCcr: "\u914D\u7F6E\u6A21\u578B\u4EE3\u7406 (CCR)",
|
|
263
|
+
ccrManagement: "CCR",
|
|
264
|
+
ccusage: "ccusage",
|
|
265
|
+
installBmad: "\u5B89\u88C5 BMad Method",
|
|
266
|
+
clearCache: "\u6E05\u9664\u504F\u597D\u7F13\u5B58",
|
|
267
|
+
changeLanguage: "\u66F4\u6539\u663E\u793A\u8BED\u8A00 / Select display language",
|
|
268
|
+
exit: "\u9000\u51FA"
|
|
269
|
+
},
|
|
270
|
+
menuDescriptions: {
|
|
271
|
+
fullInit: "\u4F1A\u4E3A\u60A8\u5B89\u88C5Claude Code\u5E76\u5BFC\u5165\u5DE5\u4F5C\u6D41\uFF0C\u4EE5\u53CA\u914D\u7F6E API \u548C\u914D\u7F6E MCP \u670D\u52A1",
|
|
272
|
+
importWorkflow: "\u4EC5\u5BFC\u5165/\u66F4\u65B0\u5DE5\u4F5C\u6D41\u76F8\u5173\u6587\u4EF6",
|
|
273
|
+
configureApiOrCcr: "\u914D\u7F6E API URL\u3001\u8BA4\u8BC1\u4FE1\u606F\u6216 CCR \u4EE3\u7406",
|
|
274
|
+
configureApi: "\u914D\u7F6E API URL \u548C\u8BA4\u8BC1\u4FE1\u606F",
|
|
275
|
+
configureMcp: "\u914D\u7F6E MCP \u670D\u52A1\uFF08\u542B Windows \u4FEE\u590D\uFF09",
|
|
276
|
+
configureModel: "\u8BBE\u7F6E\u9ED8\u8BA4\u6A21\u578B\uFF08opus/sonnet\uFF09",
|
|
277
|
+
configureAiMemory: "\u914D\u7F6E AI \u8F93\u51FA\u8BED\u8A00\u548C\u89D2\u8272\u98CE\u683C",
|
|
278
|
+
configureEnvPermission: "\u5BFC\u5165\u9690\u79C1\u4FDD\u62A4\u73AF\u5883\u53D8\u91CF\u548C\u7CFB\u7EDF\u6743\u9650\u914D\u7F6E",
|
|
279
|
+
configureCcr: "\u914D\u7F6E Claude Code Router \u4EE5\u4F7F\u7528\u591A\u4E2A AI \u6A21\u578B",
|
|
280
|
+
ccrManagement: "\u914D\u7F6E Claude Code Router \u4EE5\u4F7F\u7528\u591A\u4E2A AI \u6A21\u578B",
|
|
281
|
+
ccusage: "Claude Code \u7528\u91CF\u5206\u6790",
|
|
282
|
+
installBmad: "AI \u9A71\u52A8\u7684\u5F00\u53D1\u65B9\u6CD5\u8BBA\u6846\u67B6",
|
|
283
|
+
clearCache: "\u6E05\u9664\u504F\u597D\u8BED\u8A00\u7B49\u7F13\u5B58",
|
|
284
|
+
changeLanguage: "\u66F4\u6539\u754C\u9762\u8BED\u8A00"
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const workflow$1 = {
|
|
289
|
+
selectWorkflowType: "\u9009\u62E9\u8981\u5B89\u88C5\u7684\u5DE5\u4F5C\u6D41\u7C7B\u578B",
|
|
290
|
+
workflowOption: {
|
|
291
|
+
featPlanUx: "\u529F\u80FD\u89C4\u5212\u548C UX \u8BBE\u8BA1 (feat + planner + ui-ux-designer)",
|
|
292
|
+
sixStepsWorkflow: "\u516D\u6B65\u5DE5\u4F5C\u6D41 (workflow)",
|
|
293
|
+
bmadWorkflow: "BMAD-Method \u6269\u5C55\u5B89\u88C5\u5668 (\u652F\u6301\u654F\u6377\u5F00\u53D1\u5DE5\u4F5C\u6D41)"
|
|
294
|
+
},
|
|
295
|
+
// BMAD workflow
|
|
296
|
+
bmadInitPrompt: "\u2728 \u8BF7\u5728\u9879\u76EE\u4E2D\u8FD0\u884C /bmad-init \u547D\u4EE4\u6765\u521D\u59CB\u5316\u6216\u66F4\u65B0 BMAD-Method \u6269\u5C55",
|
|
297
|
+
bmadInstallSuccess: "\u6210\u529F\u5B89\u88C5 BMAD-Method \u5B89\u88C5\u5668",
|
|
298
|
+
// General workflow installation
|
|
299
|
+
installingWorkflow: "\u6B63\u5728\u5B89\u88C5\u5DE5\u4F5C\u6D41",
|
|
300
|
+
installedCommand: "\u5DF2\u5B89\u88C5\u547D\u4EE4",
|
|
301
|
+
installedAgent: "\u5DF2\u5B89\u88C5\u4EE3\u7406",
|
|
302
|
+
failedToInstallCommand: "\u5B89\u88C5\u547D\u4EE4\u5931\u8D25",
|
|
303
|
+
failedToInstallAgent: "\u5B89\u88C5\u4EE3\u7406\u5931\u8D25",
|
|
304
|
+
workflowInstallSuccess: "\u5DE5\u4F5C\u6D41\u5B89\u88C5\u6210\u529F",
|
|
305
|
+
workflowInstallError: "\u5DE5\u4F5C\u6D41\u5B89\u88C5\u51FA\u9519",
|
|
306
|
+
cleaningOldFiles: "\u6E05\u7406\u65E7\u7248\u672C\u6587\u4EF6",
|
|
307
|
+
removedOldFile: "\u5DF2\u5220\u9664\u65E7\u6587\u4EF6"
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
const cli$1 = {
|
|
311
|
+
runFullInit: "\u76F4\u63A5\u8FD0\u884C\u5B8C\u6574\u521D\u59CB\u5316",
|
|
312
|
+
forceOverwrite: "\u5F3A\u5236\u8986\u76D6\u73B0\u6709\u914D\u7F6E",
|
|
313
|
+
initClaudeConfig: "\u521D\u59CB\u5316 Claude Code \u914D\u7F6E",
|
|
314
|
+
updatePromptsOnly: "\u4EC5\u66F4\u65B0 Claude Code \u63D0\u793A"
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
const bmad$1 = {
|
|
318
|
+
// BMad CLI command
|
|
319
|
+
description: "\u5B89\u88C5 BMad Method \u7528\u4E8E AI \u9A71\u52A8\u7684\u5F00\u53D1",
|
|
320
|
+
directoryOption: "\u5B89\u88C5\u7684\u76EE\u6807\u76EE\u5F55",
|
|
321
|
+
forceOption: "\u5F3A\u5236\u91CD\u65B0\u5B89\u88C5\uFF0C\u5373\u4F7F\u5DF2\u5B58\u5728",
|
|
322
|
+
versionOption: "\u8981\u5B89\u88C5\u7684\u7279\u5B9A BMad \u7248\u672C",
|
|
323
|
+
// Installation messages
|
|
324
|
+
checkingExisting: "\u6B63\u5728\u68C0\u67E5\u73B0\u6709 BMad \u5B89\u88C5...",
|
|
325
|
+
alreadyInstalled: "BMad \u5DF2\u5B89\u88C5\uFF08\u7248\u672C\uFF1A{version}\uFF09",
|
|
326
|
+
existingAction: "\u9009\u62E9\u64CD\u4F5C\uFF1A",
|
|
327
|
+
actionUpdate: "\u66F4\u65B0\u5230\u6700\u65B0\u7248\u672C",
|
|
328
|
+
actionReinstall: "\u91CD\u65B0\u5B89\u88C5",
|
|
329
|
+
actionSkip: "\u8DF3\u8FC7\u5B89\u88C5",
|
|
330
|
+
installationSkipped: "\u5DF2\u8DF3\u8FC7 BMad \u5B89\u88C5",
|
|
331
|
+
installing: "\u6B63\u5728\u5B89\u88C5 BMad Method...",
|
|
332
|
+
installSuccess: "\u2705 BMad Method \u5B89\u88C5\u6210\u529F\uFF01",
|
|
333
|
+
installFailed: "\u274C BMad Method \u5B89\u88C5\u5931\u8D25",
|
|
334
|
+
installError: "\u274C BMad \u5B89\u88C5\u9519\u8BEF",
|
|
335
|
+
nextSteps: "\u4E0B\u4E00\u6B65\uFF1A\u8FDB\u5165 {directory} \u76EE\u5F55\u5F00\u59CB\u4F7F\u7528 BMad",
|
|
336
|
+
// BMad workflow messages
|
|
337
|
+
installingBmadWorkflow: "\u6B63\u5728\u5B89\u88C5 BMAD \u5DE5\u4F5C\u6D41...",
|
|
338
|
+
bmadWorkflowInstalled: "BMAD \u5DE5\u4F5C\u6D41\u5DF2\u5B89\u88C5",
|
|
339
|
+
bmadWorkflowFailed: "\u5B89\u88C5 BMAD \u5DE5\u4F5C\u6D41\u5931\u8D25",
|
|
340
|
+
// BMad agent messages
|
|
341
|
+
installingAgent: "\u6B63\u5728\u5B89\u88C5 {agent} \u4EE3\u7406...",
|
|
342
|
+
agentInstalled: "{agent} \u4EE3\u7406\u5DF2\u5B89\u88C5",
|
|
343
|
+
agentFailed: "\u5B89\u88C5 {agent} \u4EE3\u7406\u5931\u8D25",
|
|
344
|
+
// BMad user prompts
|
|
345
|
+
selectBmadOption: "\u9009\u62E9 BMAD \u9009\u9879",
|
|
346
|
+
confirmInstallBmad: "\u786E\u8BA4\u5B89\u88C5 BMAD \u5DE5\u4F5C\u6D41\uFF1F",
|
|
347
|
+
bmadInstallComplete: "BMAD \u5B89\u88C5\u5B8C\u6210",
|
|
348
|
+
// BMad log messages
|
|
349
|
+
checkingBmadDependencies: "\u68C0\u67E5 BMAD \u4F9D\u8D56...",
|
|
350
|
+
bmadDependenciesMet: "BMAD \u4F9D\u8D56\u6EE1\u8DB3",
|
|
351
|
+
bmadDependenciesMissing: "\u7F3A\u5C11 BMAD \u4F9D\u8D56\uFF1A{deps}",
|
|
352
|
+
// BMad commands
|
|
353
|
+
runningBmadCommand: "\u6267\u884C BMAD \u547D\u4EE4\uFF1A{command}",
|
|
354
|
+
bmadCommandSuccess: "BMAD \u547D\u4EE4\u6267\u884C\u6210\u529F",
|
|
355
|
+
bmadCommandFailed: "BMAD \u547D\u4EE4\u6267\u884C\u5931\u8D25\uFF1A{error}",
|
|
356
|
+
// BMad configuration
|
|
357
|
+
configuringBmad: "\u914D\u7F6E BMAD \u8BBE\u7F6E...",
|
|
358
|
+
bmadConfigured: "BMAD \u5DF2\u914D\u7F6E",
|
|
359
|
+
bmadConfigFailed: "BMAD \u914D\u7F6E\u5931\u8D25"
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
const errors$1 = {
|
|
363
|
+
// General errors
|
|
364
|
+
failedToSetOnboarding: "\u8BBE\u7F6E\u5165\u95E8\u5B8C\u6210\u6807\u5FD7\u5931\u8D25\uFF1A",
|
|
365
|
+
failedToWriteMcpConfig: "\u5199\u5165 MCP \u914D\u7F6E\u5931\u8D25\uFF1A",
|
|
366
|
+
templateDirNotFound: "\u6A21\u677F\u76EE\u5F55\u672A\u627E\u5230\uFF1A",
|
|
367
|
+
failedToReadTemplateSettings: "\u8BFB\u53D6\u6A21\u677F settings.json \u5931\u8D25\uFF1A",
|
|
368
|
+
failedToMergeSettings: "\u5408\u5E76 settings.json \u5931\u8D25\uFF1A",
|
|
369
|
+
preservingExistingSettings: "\u7531\u4E8E\u5408\u5E76\u9519\u8BEF\uFF0C\u4FDD\u7559\u73B0\u6709\u7684 settings.json",
|
|
370
|
+
// File system errors
|
|
371
|
+
failedToReadFile: "\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25\uFF1A",
|
|
372
|
+
failedToWriteFile: "\u5199\u5165\u6587\u4EF6\u5931\u8D25\uFF1A",
|
|
373
|
+
failedToCopyFile: "\u590D\u5236\u6587\u4EF6\u5931\u8D25\uFF1A",
|
|
374
|
+
failedToRemoveFile: "\u5220\u9664\u6587\u4EF6\u5931\u8D25\uFF1A",
|
|
375
|
+
failedToReadDirectory: "\u8BFB\u53D6\u76EE\u5F55\u5931\u8D25\uFF1A",
|
|
376
|
+
failedToGetStats: "\u83B7\u53D6\u6587\u4EF6\u72B6\u6001\u5931\u8D25\uFF1A",
|
|
377
|
+
sourceDirNotExist: "\u6E90\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A",
|
|
378
|
+
memoryDirNotFound: "\u8BB0\u5FC6\u76EE\u5F55\u672A\u627E\u5230\uFF1A",
|
|
379
|
+
// JSON config errors
|
|
380
|
+
invalidConfiguration: "\u914D\u7F6E\u65E0\u6548\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u503C",
|
|
381
|
+
failedToParseJson: "\u89E3\u6790 JSON \u6587\u4EF6\u5931\u8D25\uFF1A",
|
|
382
|
+
failedToBackupConfig: "\u5907\u4EFD\u914D\u7F6E\u6587\u4EF6\u5931\u8D25\uFF1A",
|
|
383
|
+
invalidEnvConfig: "\u65E0\u6548\u7684 env \u914D\u7F6E\uFF1A\u671F\u671B\u5BF9\u8C61",
|
|
384
|
+
invalidApiUrl: "\u65E0\u6548\u7684 ANTHROPIC_BASE_URL\uFF1A\u671F\u671B\u5B57\u7B26\u4E32",
|
|
385
|
+
invalidApiKey: "\u65E0\u6548\u7684 ANTHROPIC_API_KEY\uFF1A\u671F\u671B\u5B57\u7B26\u4E32",
|
|
386
|
+
invalidAuthToken: "\u65E0\u6548\u7684 ANTHROPIC_AUTH_TOKEN\uFF1A\u671F\u671B\u5B57\u7B26\u4E32",
|
|
387
|
+
invalidPermissionsConfig: "\u65E0\u6548\u7684\u6743\u9650\u914D\u7F6E\uFF1A\u671F\u671B\u5BF9\u8C61",
|
|
388
|
+
invalidPermissionsAllow: "\u65E0\u6548\u7684 permissions.allow\uFF1A\u671F\u671B\u6570\u7EC4",
|
|
389
|
+
// MCP errors
|
|
390
|
+
failedToAddOnboardingFlag: "\u6DFB\u52A0 hasCompletedOnboarding \u6807\u5FD7\u5931\u8D25\uFF1A",
|
|
391
|
+
// AI personality errors
|
|
392
|
+
failedToApplyPersonality: "\u5E94\u7528\u4E2A\u6027\u6307\u4EE4\u5931\u8D25\uFF1A"
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
const tools$1 = {
|
|
396
|
+
// CCUsage
|
|
397
|
+
runningCcusage: "\u6B63\u5728\u8FD0\u884C Claude Code \u7528\u91CF\u5206\u6790\u5DE5\u5177...",
|
|
398
|
+
ccusageDescription: "\u5206\u6790\u4EE4\u724C\u4F7F\u7528\u91CF\u548C\u6210\u672C - https://github.com/ryoppippi/ccusage",
|
|
399
|
+
selectAnalysisMode: "\u9009\u62E9\u5206\u6790\u6A21\u5F0F:",
|
|
400
|
+
ccusageModes: {
|
|
401
|
+
daily: "\u6BCF\u65E5\u4F7F\u7528\u91CF",
|
|
402
|
+
monthly: "\u6BCF\u6708\u4F7F\u7528\u91CF",
|
|
403
|
+
session: "\u4F1A\u8BDD\u7EDF\u8BA1",
|
|
404
|
+
blocks: "\u533A\u5757\u7EDF\u8BA1",
|
|
405
|
+
custom: "\u81EA\u5B9A\u4E49\u53C2\u6570"
|
|
406
|
+
},
|
|
407
|
+
enterCustomArgs: "\u8F93\u5165\u81EA\u5B9A\u4E49\u53C2\u6570 (\u4F8B\u5982: daily --json):",
|
|
408
|
+
pressEnterToContinue: "\u6309 Enter \u952E\u7EE7\u7EED...",
|
|
409
|
+
ccusageFailed: "\u8FD0\u884C ccusage \u5931\u8D25",
|
|
410
|
+
checkNetworkConnection: "\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\u5E76\u91CD\u8BD5",
|
|
411
|
+
errorDetails: "\u9519\u8BEF\u8BE6\u60C5:"
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
const ccrMessages$1 = {
|
|
415
|
+
// Installation
|
|
416
|
+
installingCcr: "\u6B63\u5728\u5B89\u88C5 Claude Code Router...",
|
|
417
|
+
ccrInstallSuccess: "Claude Code Router \u5B89\u88C5\u6210\u529F",
|
|
418
|
+
ccrInstallFailed: "\u5B89\u88C5 Claude Code Router \u5931\u8D25",
|
|
419
|
+
ccrAlreadyInstalled: "Claude Code Router \u5DF2\u5B89\u88C5",
|
|
420
|
+
// Configuration
|
|
421
|
+
configureCcr: "\u914D\u7F6E\u6A21\u578B\u4EE3\u7406 (CCR)",
|
|
422
|
+
useCcrProxy: "\u4F7F\u7528 CCR \u4EE3\u7406",
|
|
423
|
+
ccrProxyDesc: "\u901A\u8FC7 Claude Code Router \u8FDE\u63A5\u591A\u4E2A AI \u6A21\u578B",
|
|
424
|
+
fetchingPresets: "\u6B63\u5728\u83B7\u53D6\u63D0\u4F9B\u5546\u9884\u8BBE...",
|
|
425
|
+
noPresetsAvailable: "\u6CA1\u6709\u53EF\u7528\u7684\u9884\u8BBE",
|
|
426
|
+
selectCcrPreset: "\u9009\u62E9\u4E00\u4E2A\u63D0\u4F9B\u5546\u9884\u8BBE\uFF1A",
|
|
427
|
+
keyRequired: "API \u5BC6\u94A5\u4E0D\u80FD\u4E3A\u7A7A",
|
|
428
|
+
// Existing config
|
|
429
|
+
existingCcrConfig: "\u53D1\u73B0\u73B0\u6709\u7684 CCR \u914D\u7F6E",
|
|
430
|
+
overwriteCcrConfig: "\u662F\u5426\u5907\u4EFD\u73B0\u6709\u7684 CCR \u914D\u7F6E\u5E76\u91CD\u65B0\u914D\u7F6E\uFF1F",
|
|
431
|
+
keepingExistingConfig: "\u4FDD\u7559\u73B0\u6709\u914D\u7F6E",
|
|
432
|
+
backupCcrConfig: "\u6B63\u5728\u5907\u4EFD\u73B0\u6709\u7684 CCR \u914D\u7F6E...",
|
|
433
|
+
ccrBackupSuccess: "CCR \u914D\u7F6E\u5DF2\u5907\u4EFD\u5230\uFF1A{path}",
|
|
434
|
+
ccrBackupFailed: "\u5907\u4EFD CCR \u914D\u7F6E\u5931\u8D25",
|
|
435
|
+
// Model selection
|
|
436
|
+
selectDefaultModelForProvider: "\u9009\u62E9 {provider} \u7684\u9ED8\u8BA4\u6A21\u578B\uFF1A",
|
|
437
|
+
enterApiKeyForProvider: "\u8BF7\u8F93\u5165 {provider} \u7684 API \u5BC6\u94A5\uFF1A",
|
|
438
|
+
// Skip option
|
|
439
|
+
skipOption: "\u8DF3\u8FC7\uFF0C\u5728 CCR \u4E2D\u81EA\u884C\u914D\u7F6E",
|
|
440
|
+
skipConfiguring: "\u8DF3\u8FC7\u9884\u8BBE\u914D\u7F6E\uFF0C\u5C06\u521B\u5EFA\u7A7A\u914D\u7F6E\u6846\u67B6",
|
|
441
|
+
// Success/Error messages
|
|
442
|
+
ccrConfigSuccess: "CCR \u914D\u7F6E\u5DF2\u4FDD\u5B58",
|
|
443
|
+
proxyConfigSuccess: "\u4EE3\u7406\u8BBE\u7F6E\u5DF2\u914D\u7F6E",
|
|
444
|
+
ccrConfigFailed: "\u914D\u7F6E CCR \u5931\u8D25",
|
|
445
|
+
ccrSetupComplete: "CCR \u8BBE\u7F6E\u5B8C\u6210",
|
|
446
|
+
fetchPresetsError: "\u83B7\u53D6\u63D0\u4F9B\u5546\u9884\u8BBE\u5931\u8D25",
|
|
447
|
+
failedToStartCcrService: "\u542F\u52A8 CCR \u670D\u52A1\u5931\u8D25",
|
|
448
|
+
errorStartingCcrService: "\u542F\u52A8 CCR \u670D\u52A1\u65F6\u51FA\u9519",
|
|
449
|
+
// CCR service status
|
|
450
|
+
ccrRestartSuccess: "CCR \u670D\u52A1\u5DF2\u91CD\u542F",
|
|
451
|
+
ccrRestartFailed: "CCR \u670D\u52A1\u91CD\u542F\u5931\u8D25",
|
|
452
|
+
// Configuration tips
|
|
453
|
+
configTips: "\u914D\u7F6E\u63D0\u793A",
|
|
454
|
+
useClaudeCommand: "\u8BF7\u4F7F\u7528 claude \u547D\u4EE4\u542F\u52A8 Claude Code\uFF08\u800C\u975E ccr code\uFF09",
|
|
455
|
+
advancedConfigTip: "\u60A8\u53EF\u4EE5\u4F7F\u7528 ccr ui \u547D\u4EE4\u8FDB\u884C\u66F4\u9AD8\u7EA7\u7684\u914D\u7F6E",
|
|
456
|
+
manualConfigTip: "\u624B\u52A8\u4FEE\u6539\u914D\u7F6E\u6587\u4EF6\u540E\uFF0C\u8BF7\u6267\u884C ccr restart \u4F7F\u914D\u7F6E\u751F\u6548",
|
|
457
|
+
// CCR Menu
|
|
458
|
+
ccrMenuTitle: "CCR - Claude Code Router \u7BA1\u7406",
|
|
459
|
+
ccrMenuOptions: {
|
|
460
|
+
initCcr: "\u521D\u59CB\u5316 CCR",
|
|
461
|
+
startUi: "\u542F\u52A8 CCR UI",
|
|
462
|
+
checkStatus: "\u67E5\u8BE2 CCR \u72B6\u6001",
|
|
463
|
+
restart: "\u91CD\u542F CCR",
|
|
464
|
+
start: "\u542F\u52A8 CCR",
|
|
465
|
+
stop: "\u505C\u6B62 CCR",
|
|
466
|
+
back: "\u8FD4\u56DE\u4E3B\u83DC\u5355"
|
|
467
|
+
},
|
|
468
|
+
ccrMenuDescriptions: {
|
|
469
|
+
initCcr: "\u5B89\u88C5\u5E76\u914D\u7F6E CCR",
|
|
470
|
+
startUi: "\u6253\u5F00 Web \u754C\u9762\u7BA1\u7406 CCR",
|
|
471
|
+
checkStatus: "\u67E5\u770B CCR \u670D\u52A1\u8FD0\u884C\u72B6\u6001",
|
|
472
|
+
restart: "\u91CD\u542F CCR \u670D\u52A1",
|
|
473
|
+
start: "\u542F\u52A8 CCR \u670D\u52A1",
|
|
474
|
+
stop: "\u505C\u6B62 CCR \u670D\u52A1"
|
|
475
|
+
},
|
|
476
|
+
// Command execution messages
|
|
477
|
+
startingCcrUi: "\u6B63\u5728\u542F\u52A8 CCR UI...",
|
|
478
|
+
ccrUiStarted: "CCR UI \u5DF2\u542F\u52A8",
|
|
479
|
+
checkingCcrStatus: "\u6B63\u5728\u67E5\u8BE2 CCR \u72B6\u6001...",
|
|
480
|
+
ccrStatusTitle: "CCR \u72B6\u6001\u4FE1\u606F\uFF1A",
|
|
481
|
+
restartingCcr: "\u6B63\u5728\u91CD\u542F CCR...",
|
|
482
|
+
ccrRestarted: "CCR \u5DF2\u91CD\u542F",
|
|
483
|
+
startingCcr: "\u6B63\u5728\u542F\u52A8 CCR...",
|
|
484
|
+
ccrStarted: "CCR \u5DF2\u542F\u52A8",
|
|
485
|
+
stoppingCcr: "\u6B63\u5728\u505C\u6B62 CCR...",
|
|
486
|
+
ccrStopped: "CCR \u5DF2\u505C\u6B62",
|
|
487
|
+
ccrCommandFailed: "\u6267\u884C CCR \u547D\u4EE4\u5931\u8D25",
|
|
488
|
+
// Configuration check messages
|
|
489
|
+
ccrNotConfigured: "CCR \u5C1A\u672A\u914D\u7F6E\u3002\u8BF7\u5148\u521D\u59CB\u5316 CCR\u3002",
|
|
490
|
+
pleaseInitFirst: "\u8BF7\u9009\u62E9\u9009\u9879 1 \u6765\u521D\u59CB\u5316 CCR\u3002",
|
|
491
|
+
// UI API Key messages
|
|
492
|
+
ccrUiApiKey: "CCR UI \u767B\u5F55\u5BC6\u94A5",
|
|
493
|
+
ccrUiApiKeyHint: "\u4F7F\u7528\u6B64\u5BC6\u94A5\u767B\u5F55 CCR UI \u754C\u9762"
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
const zhCN = {
|
|
497
|
+
common: common$1,
|
|
498
|
+
language: language$1,
|
|
499
|
+
installation: installation$1,
|
|
500
|
+
api: api$1,
|
|
501
|
+
configuration: configuration$1,
|
|
502
|
+
mcp: mcp$1,
|
|
503
|
+
menu: menu$1,
|
|
504
|
+
workflow: workflow$1,
|
|
505
|
+
cli: cli$1,
|
|
506
|
+
bmad: bmad$1,
|
|
507
|
+
errors: errors$1,
|
|
508
|
+
tools: tools$1,
|
|
509
|
+
ccr: ccrMessages$1
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
const common = {
|
|
513
|
+
// Basic
|
|
514
|
+
multiSelectHint: " (Space to select, a to select all, i to invert, Enter to confirm)",
|
|
515
|
+
yes: "Yes",
|
|
516
|
+
no: "No",
|
|
517
|
+
skip: "Skip",
|
|
518
|
+
cancelled: "Operation cancelled",
|
|
519
|
+
error: "Error",
|
|
520
|
+
complete: "\u{1F389} Setup complete! Use 'claude' command to start.",
|
|
521
|
+
none: "None",
|
|
522
|
+
notConfigured: "Not configured",
|
|
523
|
+
spaceToSelectReturn: "- Space to select. Return to submit",
|
|
524
|
+
enterChoice: "Enter your choice and press enter (case-insensitive)",
|
|
525
|
+
invalidChoice: "Invalid choice. Please enter a valid option.",
|
|
526
|
+
goodbye: "\u{1F44B} Thanks for using AICO! Goodbye!",
|
|
527
|
+
returnToMenu: "Return to main menu?",
|
|
528
|
+
back: "Back"
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
const language = {
|
|
532
|
+
selectScriptLang: "Select AICO display language",
|
|
533
|
+
selectConfigLang: "Select Claude Code configuration language",
|
|
534
|
+
selectAiOutputLang: "Select AI output language",
|
|
535
|
+
aiOutputLangHint: "AI will respond to you in this language",
|
|
536
|
+
enterCustomLanguage: "Enter custom language (e.g., Japanese, French, etc.)",
|
|
537
|
+
languageChanged: "Language changed",
|
|
538
|
+
configLangHint: {
|
|
539
|
+
"zh-CN": "easier for Chinese users to customize",
|
|
540
|
+
en: "recommended, lower token consumption"
|
|
541
|
+
},
|
|
542
|
+
updateConfigLangPrompt: "Select configuration language",
|
|
543
|
+
updateConfigLangChoice: {
|
|
544
|
+
"zh-CN": "Chinese configuration",
|
|
545
|
+
en: "English configuration"
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
const installation = {
|
|
550
|
+
installPrompt: "Claude Code not found. Install automatically?",
|
|
551
|
+
installing: "Installing Claude Code...",
|
|
552
|
+
installSuccess: "Claude Code installed successfully",
|
|
553
|
+
alreadyInstalled: "Claude Code is already installed",
|
|
554
|
+
installFailed: "Failed to install Claude Code",
|
|
555
|
+
npmNotFound: "npm is not installed. Please install Node.js and npm first.",
|
|
556
|
+
// Termux specific
|
|
557
|
+
termuxDetected: "Termux environment detected",
|
|
558
|
+
termuxInstallHint: "In Termux, please run first: pkg install nodejs or pkg install nodejs-lts",
|
|
559
|
+
termuxPathInfo: "Using Termux path: {path}",
|
|
560
|
+
termuxEnvironmentInfo: "Termux environment provides Node.js and npm through pkg manager",
|
|
561
|
+
// Windows specific
|
|
562
|
+
windowsDetected: "Windows detected, will configure compatible format"
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
const api = {
|
|
566
|
+
// Basic API configuration
|
|
567
|
+
configureApi: "Select API authentication method",
|
|
568
|
+
useAuthToken: "Use Auth Token (OAuth authentication)",
|
|
569
|
+
authTokenDesc: "For tokens obtained via OAuth or browser login",
|
|
570
|
+
useApiKey: "Use API Key (Key authentication)",
|
|
571
|
+
apiKeyDesc: "For API keys from Anthropic Console",
|
|
572
|
+
useCcrProxy: "Use CCR Proxy",
|
|
573
|
+
ccrProxyDesc: "Use multiple AI models via Claude Code Router",
|
|
574
|
+
skipApi: "Skip (configure manually later)",
|
|
575
|
+
enterApiUrl: "Enter API URL",
|
|
576
|
+
enterAuthToken: "Enter Auth Token",
|
|
577
|
+
enterApiKey: "Enter API Key",
|
|
578
|
+
apiConfigSuccess: "API configured",
|
|
579
|
+
// API modification
|
|
580
|
+
existingApiConfig: "Existing API configuration detected:",
|
|
581
|
+
apiConfigUrl: "URL",
|
|
582
|
+
apiConfigKey: "Key",
|
|
583
|
+
apiConfigAuthType: "Auth Type",
|
|
584
|
+
selectApiAction: "Select API processing operation",
|
|
585
|
+
keepExistingConfig: "Keep existing configuration",
|
|
586
|
+
modifyAllConfig: "Modify all configuration",
|
|
587
|
+
modifyPartialConfig: "Modify partial configuration",
|
|
588
|
+
selectModifyItems: "Select items to modify",
|
|
589
|
+
modifyApiUrl: "Modify API URL",
|
|
590
|
+
modifyApiKey: "Modify API Key",
|
|
591
|
+
modifyAuthType: "Modify auth type",
|
|
592
|
+
continueModification: "Continue modifying other configurations?",
|
|
593
|
+
modificationSaved: "Configuration saved",
|
|
594
|
+
enterNewApiUrl: "Enter new API URL (current: {url})",
|
|
595
|
+
enterNewApiKey: "Enter new API Key (current: {key})",
|
|
596
|
+
selectNewAuthType: "Select new auth type (current: {type})",
|
|
597
|
+
// API validation
|
|
598
|
+
apiKeyValidation: {
|
|
599
|
+
empty: "API Key cannot be empty",
|
|
600
|
+
example: "Example format: sk-abcdef123456_789xyz"
|
|
601
|
+
},
|
|
602
|
+
urlRequired: "URL is required",
|
|
603
|
+
invalidUrl: "Invalid URL",
|
|
604
|
+
keyRequired: "Key is required",
|
|
605
|
+
invalidKeyFormat: "Invalid key format"
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
const configuration = {
|
|
609
|
+
existingConfig: "Existing config detected. How to proceed?",
|
|
610
|
+
backupAndOverwrite: "Backup and overwrite all",
|
|
611
|
+
updateDocsOnly: "Update workflow-related md files only with backup",
|
|
612
|
+
mergeConfig: "Merge config",
|
|
613
|
+
backupSuccess: "All config files backed up to",
|
|
614
|
+
copying: "Copying configuration files...",
|
|
615
|
+
configSuccess: "Config files copied to",
|
|
616
|
+
noExistingConfig: "No existing configuration found. Please run `aico` first.",
|
|
617
|
+
updatingPrompts: "Updating Claude Code memory documents...",
|
|
618
|
+
// Model configuration
|
|
619
|
+
selectDefaultModel: "Select default model",
|
|
620
|
+
modelConfigSuccess: "Default model configured",
|
|
621
|
+
// AI memory configuration
|
|
622
|
+
selectMemoryOption: "Select configuration option",
|
|
623
|
+
configureAiLanguage: "Configure AI output language",
|
|
624
|
+
configureAiPersonality: "Configure AI personality",
|
|
625
|
+
aiLanguageConfigured: "AI output language configured",
|
|
626
|
+
// AI personality
|
|
627
|
+
selectAiPersonality: "Select AI personality",
|
|
628
|
+
customPersonalityHint: "Define your own personality",
|
|
629
|
+
enterCustomPersonality: "Enter custom personality description",
|
|
630
|
+
personalityConfigured: "AI personality configured",
|
|
631
|
+
existingPersonality: "Existing AI personality configuration",
|
|
632
|
+
currentPersonality: "Current personality",
|
|
633
|
+
modifyPersonality: "Modify AI personality?",
|
|
634
|
+
keepPersonality: "Keeping existing personality",
|
|
635
|
+
directiveCannotBeEmpty: "Directive cannot be empty",
|
|
636
|
+
languageRequired: "Language is required",
|
|
637
|
+
// Cache
|
|
638
|
+
confirmClearCache: "Confirm clear all AICO preference cache?",
|
|
639
|
+
cacheCleared: "AICO cache cleared",
|
|
640
|
+
noCacheFound: "No cache file found",
|
|
641
|
+
// Environment and permissions
|
|
642
|
+
selectEnvPermissionOption: "Select configuration option",
|
|
643
|
+
importRecommendedEnv: "Import AICO recommended environment variables",
|
|
644
|
+
importRecommendedEnvDesc: "Privacy protection variables, etc.",
|
|
645
|
+
importRecommendedPermissions: "Import AICO recommended permissions",
|
|
646
|
+
importRecommendedPermissionsDesc: "Almost all permissions, reduce frequent permission requests, dangerous ops limited by rules",
|
|
647
|
+
openSettingsJson: "Open settings.json for manual configuration",
|
|
648
|
+
openSettingsJsonDesc: "Advanced user customization",
|
|
649
|
+
envImportSuccess: "Environment variables imported",
|
|
650
|
+
permissionsImportSuccess: "Permissions imported",
|
|
651
|
+
openingSettingsJson: "Opening settings.json...",
|
|
652
|
+
// JSON config related
|
|
653
|
+
invalidConfiguration: "Invalid configuration",
|
|
654
|
+
failedToParseJson: "Failed to parse JSON file:",
|
|
655
|
+
failedToBackupConfig: "Failed to backup config",
|
|
656
|
+
failedToReadTemplateSettings: "Failed to read template settings",
|
|
657
|
+
failedToMergeSettings: "Failed to merge settings",
|
|
658
|
+
preservingExistingSettings: "Preserving existing settings",
|
|
659
|
+
memoryDirNotFound: "Memory directory not found",
|
|
660
|
+
failedToSetOnboarding: "Failed to set onboarding flag",
|
|
661
|
+
fixWindowsMcp: "Fix Windows MCP configuration?"
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
const mcp = {
|
|
665
|
+
configureMcp: "Configure MCP services?",
|
|
666
|
+
selectMcpServices: "Select MCP services to install",
|
|
667
|
+
allServices: "Install all",
|
|
668
|
+
mcpServiceInstalled: "Selected MCP services",
|
|
669
|
+
enterExaApiKey: "Enter Exa API Key (get from https://dashboard.exa.ai/api-keys)",
|
|
670
|
+
skipMcp: "Skip MCP configuration",
|
|
671
|
+
mcpConfigSuccess: "MCP services configured",
|
|
672
|
+
mcpBackupSuccess: "Original MCP config backed up",
|
|
673
|
+
fixWindowsMcp: "Fix Windows MCP Configuration",
|
|
674
|
+
fixWindowsMcpDesc: "Fix Windows platform MCP command configuration issues",
|
|
675
|
+
windowsMcpFixed: "Windows MCP configuration fixed",
|
|
676
|
+
configureMcpServices: "Configure MCP Services",
|
|
677
|
+
selectMcpOption: "Select MCP configuration option"
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
const menu = {
|
|
681
|
+
selectFunction: "Select function",
|
|
682
|
+
menuSections: {
|
|
683
|
+
otherTools: "Other Tools"
|
|
684
|
+
},
|
|
685
|
+
menuOptions: {
|
|
686
|
+
fullInit: "Full initialization",
|
|
687
|
+
importWorkflow: "Import workflow",
|
|
688
|
+
configureApiOrCcr: "Configure API / CCR proxy",
|
|
689
|
+
configureApi: "Configure API",
|
|
690
|
+
configureMcp: "Configure MCP",
|
|
691
|
+
configureModel: "Configure default model",
|
|
692
|
+
configureAiMemory: "Configure Claude global memory",
|
|
693
|
+
configureEnvPermission: "Import recommended environment variables and permissions",
|
|
694
|
+
configureCcr: "Configure Model Proxy (CCR)",
|
|
695
|
+
ccrManagement: "CCR",
|
|
696
|
+
ccusage: "ccusage",
|
|
697
|
+
installBmad: "Install BMad Method",
|
|
698
|
+
clearCache: "Clear preference cache",
|
|
699
|
+
changeLanguage: "Select display language / \u66F4\u6539\u663E\u793A\u8BED\u8A00",
|
|
700
|
+
exit: "Exit"
|
|
701
|
+
},
|
|
702
|
+
menuDescriptions: {
|
|
703
|
+
fullInit: "Install Claude Code + Import workflow + Configure API or CCR proxy + Configure MCP services",
|
|
704
|
+
importWorkflow: "Import/update workflow-related files only",
|
|
705
|
+
configureApiOrCcr: "Configure API URL, authentication or CCR proxy",
|
|
706
|
+
configureApi: "Configure API URL and authentication",
|
|
707
|
+
configureMcp: "Configure MCP services (includes Windows fix)",
|
|
708
|
+
configureModel: "Set default model (opus/sonnet)",
|
|
709
|
+
configureAiMemory: "Configure AI output language and personality",
|
|
710
|
+
configureEnvPermission: "Import privacy protection environment variables and system permissions",
|
|
711
|
+
configureCcr: "Configure Claude Code Router to use multiple AI models",
|
|
712
|
+
ccrManagement: "Configure Claude Code Router to use multiple AI models",
|
|
713
|
+
ccusage: "Claude Code usage analysis",
|
|
714
|
+
installBmad: "AI-driven development methodology framework",
|
|
715
|
+
clearCache: "Clear preference language and other caches",
|
|
716
|
+
changeLanguage: "Change AICO interface language"
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
|
|
720
|
+
const workflow = {
|
|
721
|
+
selectWorkflowType: "Select workflow type to install",
|
|
722
|
+
workflowOption: {
|
|
723
|
+
featPlanUx: "Feature Planning and UX Design (feat + planner + ui-ux-designer)",
|
|
724
|
+
sixStepsWorkflow: "Six Steps Workflow (workflow)",
|
|
725
|
+
bmadWorkflow: "BMAD-Method Extension Installer (Agile Development Workflow)"
|
|
726
|
+
},
|
|
727
|
+
// BMAD workflow
|
|
728
|
+
bmadInitPrompt: "\u2728 Please run /bmad-init command in your project to initialize or update BMAD-Method extension",
|
|
729
|
+
bmadInstallSuccess: "Successfully installed BMAD-Method installer",
|
|
730
|
+
// General workflow installation
|
|
731
|
+
installingWorkflow: "Installing workflow",
|
|
732
|
+
installedCommand: "Installed command",
|
|
733
|
+
installedAgent: "Installed agent",
|
|
734
|
+
failedToInstallCommand: "Failed to install command",
|
|
735
|
+
failedToInstallAgent: "Failed to install agent",
|
|
736
|
+
workflowInstallSuccess: "workflow installed successfully",
|
|
737
|
+
workflowInstallError: "workflow installation had errors",
|
|
738
|
+
cleaningOldFiles: "Cleaning up old version files",
|
|
739
|
+
removedOldFile: "Removed old file"
|
|
740
|
+
};
|
|
741
|
+
|
|
742
|
+
const cli = {
|
|
743
|
+
runFullInit: "Run full initialization directly",
|
|
744
|
+
forceOverwrite: "Force overwrite existing configuration",
|
|
745
|
+
initClaudeConfig: "Initialize Claude Code configuration",
|
|
746
|
+
updatePromptsOnly: "Update Claude Code prompts only"
|
|
747
|
+
};
|
|
748
|
+
|
|
749
|
+
const bmad = {
|
|
750
|
+
// BMad CLI command
|
|
751
|
+
description: "Install BMad Method for AI-driven development",
|
|
752
|
+
directoryOption: "Target directory for installation",
|
|
753
|
+
forceOption: "Force reinstall even if already exists",
|
|
754
|
+
versionOption: "Specific BMad version to install",
|
|
755
|
+
// Installation messages
|
|
756
|
+
checkingExisting: "Checking for existing BMad installation...",
|
|
757
|
+
alreadyInstalled: "BMad is already installed (version: {version})",
|
|
758
|
+
existingAction: "Choose an action:",
|
|
759
|
+
actionUpdate: "Update to latest version",
|
|
760
|
+
actionReinstall: "Reinstall",
|
|
761
|
+
actionSkip: "Skip installation",
|
|
762
|
+
installationSkipped: "BMad installation skipped",
|
|
763
|
+
installing: "Installing BMad Method...",
|
|
764
|
+
installSuccess: "\u2705 BMad Method installed successfully!",
|
|
765
|
+
installFailed: "\u274C BMad Method installation failed",
|
|
766
|
+
installError: "\u274C BMad installation error",
|
|
767
|
+
nextSteps: "Next steps: Navigate to {directory} to start using BMad",
|
|
768
|
+
// BMad workflow messages
|
|
769
|
+
installingBmadWorkflow: "Installing BMAD workflow...",
|
|
770
|
+
bmadWorkflowInstalled: "BMAD workflow installed",
|
|
771
|
+
bmadWorkflowFailed: "Failed to install BMAD workflow",
|
|
772
|
+
// BMad agent messages
|
|
773
|
+
installingAgent: "Installing {agent} agent...",
|
|
774
|
+
agentInstalled: "{agent} agent installed",
|
|
775
|
+
agentFailed: "Failed to install {agent} agent",
|
|
776
|
+
// BMad user prompts
|
|
777
|
+
selectBmadOption: "Select BMAD option",
|
|
778
|
+
confirmInstallBmad: "Confirm install BMAD workflow?",
|
|
779
|
+
bmadInstallComplete: "BMAD installation complete",
|
|
780
|
+
// BMad log messages
|
|
781
|
+
checkingBmadDependencies: "Checking BMAD dependencies...",
|
|
782
|
+
bmadDependenciesMet: "BMAD dependencies met",
|
|
783
|
+
bmadDependenciesMissing: "Missing BMAD dependencies: {deps}",
|
|
784
|
+
// BMad commands
|
|
785
|
+
runningBmadCommand: "Running BMAD command: {command}",
|
|
786
|
+
bmadCommandSuccess: "BMAD command executed successfully",
|
|
787
|
+
bmadCommandFailed: "BMAD command failed: {error}",
|
|
788
|
+
// BMad configuration
|
|
789
|
+
configuringBmad: "Configuring BMAD settings...",
|
|
790
|
+
bmadConfigured: "BMAD configured",
|
|
791
|
+
bmadConfigFailed: "BMAD configuration failed"
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
const errors = {
|
|
795
|
+
// General errors
|
|
796
|
+
failedToSetOnboarding: "Failed to set onboarding completion flag:",
|
|
797
|
+
failedToWriteMcpConfig: "Failed to write MCP config:",
|
|
798
|
+
templateDirNotFound: "Template directory not found:",
|
|
799
|
+
failedToReadTemplateSettings: "Failed to read template settings.json:",
|
|
800
|
+
failedToMergeSettings: "Failed to merge settings.json:",
|
|
801
|
+
preservingExistingSettings: "Preserving existing settings.json due to merge error",
|
|
802
|
+
// File system errors
|
|
803
|
+
failedToReadFile: "Failed to read file:",
|
|
804
|
+
failedToWriteFile: "Failed to write file:",
|
|
805
|
+
failedToCopyFile: "Failed to copy file:",
|
|
806
|
+
failedToRemoveFile: "Failed to remove file:",
|
|
807
|
+
failedToReadDirectory: "Failed to read directory:",
|
|
808
|
+
failedToGetStats: "Failed to get stats for:",
|
|
809
|
+
sourceDirNotExist: "Source directory does not exist:",
|
|
810
|
+
memoryDirNotFound: "Memory directory not found:",
|
|
811
|
+
// JSON config errors
|
|
812
|
+
invalidConfiguration: "Invalid configuration, using default value",
|
|
813
|
+
failedToParseJson: "Failed to parse JSON file:",
|
|
814
|
+
failedToBackupConfig: "Failed to backup config file:",
|
|
815
|
+
invalidEnvConfig: "Invalid env configuration: expected object",
|
|
816
|
+
invalidApiUrl: "Invalid ANTHROPIC_BASE_URL: expected string",
|
|
817
|
+
invalidApiKey: "Invalid ANTHROPIC_API_KEY: expected string",
|
|
818
|
+
invalidAuthToken: "Invalid ANTHROPIC_AUTH_TOKEN: expected string",
|
|
819
|
+
invalidPermissionsConfig: "Invalid permissions configuration: expected object",
|
|
820
|
+
invalidPermissionsAllow: "Invalid permissions.allow: expected array",
|
|
821
|
+
// MCP errors
|
|
822
|
+
failedToAddOnboardingFlag: "Failed to add hasCompletedOnboarding flag:",
|
|
823
|
+
// AI personality errors
|
|
824
|
+
failedToApplyPersonality: "Failed to apply personality directive:"
|
|
825
|
+
};
|
|
826
|
+
|
|
827
|
+
const tools = {
|
|
828
|
+
// CCUsage
|
|
829
|
+
runningCcusage: "Running Claude Code usage analysis tool...",
|
|
830
|
+
ccusageDescription: "Analyze token usage and costs - https://github.com/ryoppippi/ccusage",
|
|
831
|
+
selectAnalysisMode: "Select analysis mode:",
|
|
832
|
+
ccusageModes: {
|
|
833
|
+
daily: "Daily usage",
|
|
834
|
+
monthly: "Monthly usage",
|
|
835
|
+
session: "Session statistics",
|
|
836
|
+
blocks: "Block statistics",
|
|
837
|
+
custom: "Custom parameters"
|
|
838
|
+
},
|
|
839
|
+
enterCustomArgs: "Enter custom arguments (e.g., daily --json):",
|
|
840
|
+
pressEnterToContinue: "Press Enter to continue...",
|
|
841
|
+
ccusageFailed: "Failed to run ccusage",
|
|
842
|
+
checkNetworkConnection: "Please check your network connection and try again",
|
|
843
|
+
errorDetails: "Error details:"
|
|
844
|
+
};
|
|
845
|
+
|
|
846
|
+
const ccrMessages = {
|
|
847
|
+
// Installation
|
|
848
|
+
installingCcr: "Installing Claude Code Router...",
|
|
849
|
+
ccrInstallSuccess: "Claude Code Router installed successfully",
|
|
850
|
+
ccrInstallFailed: "Failed to install Claude Code Router",
|
|
851
|
+
ccrAlreadyInstalled: "Claude Code Router is already installed",
|
|
852
|
+
// Configuration
|
|
853
|
+
configureCcr: "Configure Model Proxy (CCR)",
|
|
854
|
+
useCcrProxy: "Use CCR Proxy",
|
|
855
|
+
ccrProxyDesc: "Connect to multiple AI models via Claude Code Router",
|
|
856
|
+
fetchingPresets: "Fetching provider presets...",
|
|
857
|
+
noPresetsAvailable: "No presets available",
|
|
858
|
+
selectCcrPreset: "Select a provider preset:",
|
|
859
|
+
keyRequired: "API key is required",
|
|
860
|
+
// Existing config
|
|
861
|
+
existingCcrConfig: "Existing CCR configuration found",
|
|
862
|
+
overwriteCcrConfig: "Backup existing CCR configuration and reconfigure?",
|
|
863
|
+
keepingExistingConfig: "Keeping existing configuration",
|
|
864
|
+
backupCcrConfig: "Backing up existing CCR configuration...",
|
|
865
|
+
ccrBackupSuccess: "CCR configuration backed up to: {path}",
|
|
866
|
+
ccrBackupFailed: "Failed to backup CCR configuration",
|
|
867
|
+
// Model selection
|
|
868
|
+
selectDefaultModelForProvider: "Select default model for {provider}:",
|
|
869
|
+
enterApiKeyForProvider: "Enter API key for {provider}:",
|
|
870
|
+
// Skip option
|
|
871
|
+
skipOption: "Skip, configure in CCR manually",
|
|
872
|
+
skipConfiguring: "Skipping preset configuration, will create empty configuration framework",
|
|
873
|
+
// Success/Error messages
|
|
874
|
+
ccrConfigSuccess: "CCR configuration saved",
|
|
875
|
+
proxyConfigSuccess: "Proxy settings configured",
|
|
876
|
+
ccrConfigFailed: "Failed to configure CCR",
|
|
877
|
+
ccrSetupComplete: "CCR setup complete",
|
|
878
|
+
fetchPresetsError: "Failed to fetch provider presets",
|
|
879
|
+
failedToStartCcrService: "Failed to start CCR service",
|
|
880
|
+
errorStartingCcrService: "Error starting CCR service",
|
|
881
|
+
// CCR service status
|
|
882
|
+
ccrRestartSuccess: "CCR service restarted",
|
|
883
|
+
ccrRestartFailed: "Failed to restart CCR service",
|
|
884
|
+
// Configuration tips
|
|
885
|
+
configTips: "Configuration Tips",
|
|
886
|
+
useClaudeCommand: "Use the claude command to start Claude Code (not ccr code)",
|
|
887
|
+
advancedConfigTip: "You can use the ccr ui command for advanced configuration",
|
|
888
|
+
manualConfigTip: "After manually modifying the configuration file, run ccr restart to apply changes",
|
|
889
|
+
// CCR Menu
|
|
890
|
+
ccrMenuTitle: "CCR - Claude Code Router Management",
|
|
891
|
+
ccrMenuOptions: {
|
|
892
|
+
initCcr: "Initialize CCR",
|
|
893
|
+
startUi: "Start CCR UI",
|
|
894
|
+
checkStatus: "Check CCR Status",
|
|
895
|
+
restart: "Restart CCR",
|
|
896
|
+
start: "Start CCR",
|
|
897
|
+
stop: "Stop CCR",
|
|
898
|
+
back: "Back to Main Menu"
|
|
899
|
+
},
|
|
900
|
+
ccrMenuDescriptions: {
|
|
901
|
+
initCcr: "Install and configure CCR",
|
|
902
|
+
startUi: "Open web interface to manage CCR",
|
|
903
|
+
checkStatus: "View CCR service status",
|
|
904
|
+
restart: "Restart CCR service",
|
|
905
|
+
start: "Start CCR service",
|
|
906
|
+
stop: "Stop CCR service"
|
|
907
|
+
},
|
|
908
|
+
// Command execution messages
|
|
909
|
+
startingCcrUi: "Starting CCR UI...",
|
|
910
|
+
ccrUiStarted: "CCR UI started",
|
|
911
|
+
checkingCcrStatus: "Checking CCR status...",
|
|
912
|
+
ccrStatusTitle: "CCR Status:",
|
|
913
|
+
restartingCcr: "Restarting CCR...",
|
|
914
|
+
ccrRestarted: "CCR restarted",
|
|
915
|
+
startingCcr: "Starting CCR...",
|
|
916
|
+
ccrStarted: "CCR started",
|
|
917
|
+
stoppingCcr: "Stopping CCR...",
|
|
918
|
+
ccrStopped: "CCR stopped",
|
|
919
|
+
ccrCommandFailed: "Failed to execute CCR command",
|
|
920
|
+
// Configuration check messages
|
|
921
|
+
ccrNotConfigured: "CCR is not configured yet. Please initialize CCR first.",
|
|
922
|
+
pleaseInitFirst: "Please select option 1 to initialize CCR.",
|
|
923
|
+
// UI API Key messages
|
|
924
|
+
ccrUiApiKey: "CCR UI API Key",
|
|
925
|
+
ccrUiApiKeyHint: "Use this API key to login to CCR UI"
|
|
926
|
+
};
|
|
927
|
+
|
|
928
|
+
const en = {
|
|
929
|
+
common,
|
|
930
|
+
language,
|
|
931
|
+
installation,
|
|
932
|
+
api,
|
|
933
|
+
configuration,
|
|
934
|
+
mcp,
|
|
935
|
+
menu,
|
|
936
|
+
workflow,
|
|
937
|
+
cli,
|
|
938
|
+
bmad,
|
|
939
|
+
errors,
|
|
940
|
+
tools,
|
|
941
|
+
ccr: ccrMessages
|
|
942
|
+
};
|
|
943
|
+
|
|
944
|
+
const I18N$1 = {
|
|
945
|
+
"zh-CN": zhCN,
|
|
946
|
+
en
|
|
947
|
+
};
|
|
948
|
+
function getTranslation(lang) {
|
|
949
|
+
return I18N$1[lang];
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
const CLAUDE_DIR = join(homedir(), ".claude");
|
|
953
|
+
const SETTINGS_FILE = join(CLAUDE_DIR, "settings.json");
|
|
954
|
+
const CLAUDE_MD_FILE = join(CLAUDE_DIR, "CLAUDE.md");
|
|
955
|
+
const ClAUDE_CONFIG_FILE = join(homedir(), ".claude.json");
|
|
956
|
+
const LEGACY_AICO_CONFIG_FILE = join(homedir(), ".aico.json");
|
|
957
|
+
const AICO_CONFIG_FILE = join(CLAUDE_DIR, ".aico-config.json");
|
|
958
|
+
const SUPPORTED_LANGS = ["zh-CN", "en"];
|
|
959
|
+
const LANG_LABELS = {
|
|
960
|
+
"zh-CN": "\u7B80\u4F53\u4E2D\u6587",
|
|
961
|
+
en: "English"
|
|
962
|
+
};
|
|
963
|
+
const AI_OUTPUT_LANGUAGES = {
|
|
964
|
+
"zh-CN": {
|
|
965
|
+
label: "\u7B80\u4F53\u4E2D\u6587",
|
|
966
|
+
directive: "Always respond in Chinese-simplified"
|
|
967
|
+
},
|
|
968
|
+
en: { label: "English", directive: "Always respond in English" },
|
|
969
|
+
custom: { label: "Custom", directive: "" }
|
|
970
|
+
};
|
|
971
|
+
const I18N = I18N$1;
|
|
972
|
+
const MCP_SERVICES = [
|
|
973
|
+
{
|
|
974
|
+
id: "intention-coding",
|
|
975
|
+
name: { "zh-CN": "Intention Coding", en: "Intention Coding" },
|
|
976
|
+
description: {
|
|
977
|
+
"zh-CN": "\u667A\u80FD\u8F6F\u4EF6\u661F\u5DE5\u5382mcp\u670D\u52A1-\u667A\u80FD\u4EE3\u7801\u751F\u6210\u548C\u7F16\u7A0B\u8F85\u52A9\u5DE5\u5177",
|
|
978
|
+
en: "Intelligent code generation and programming assistance"
|
|
979
|
+
},
|
|
980
|
+
requiresApiKey: false,
|
|
981
|
+
config: {
|
|
982
|
+
type: "stdio",
|
|
983
|
+
command: "npx",
|
|
984
|
+
args: ["-y", "intention-coding"],
|
|
985
|
+
env: {}
|
|
986
|
+
}
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
id: "context7",
|
|
990
|
+
name: { "zh-CN": "Context7 \u6587\u6863\u67E5\u8BE2", en: "Context7 Docs" },
|
|
991
|
+
description: {
|
|
992
|
+
"zh-CN": "\u67E5\u8BE2\u6700\u65B0\u7684\u5E93\u6587\u6863\u548C\u4EE3\u7801\u793A\u4F8B",
|
|
993
|
+
en: "Query latest library documentation and code examples"
|
|
994
|
+
},
|
|
995
|
+
requiresApiKey: false,
|
|
996
|
+
config: {
|
|
997
|
+
type: "stdio",
|
|
998
|
+
command: "npx",
|
|
999
|
+
args: ["-y", "@upstash/context7-mcp"],
|
|
1000
|
+
env: {}
|
|
1001
|
+
}
|
|
1002
|
+
},
|
|
1003
|
+
{
|
|
1004
|
+
id: "mcp-deepwiki",
|
|
1005
|
+
name: { "zh-CN": "DeepWiki", en: "DeepWiki" },
|
|
1006
|
+
description: {
|
|
1007
|
+
"zh-CN": "\u67E5\u8BE2 GitHub \u4ED3\u5E93\u6587\u6863\u548C\u793A\u4F8B",
|
|
1008
|
+
en: "Query GitHub repository documentation and examples"
|
|
1009
|
+
},
|
|
1010
|
+
requiresApiKey: false,
|
|
1011
|
+
config: {
|
|
1012
|
+
type: "stdio",
|
|
1013
|
+
command: "npx",
|
|
1014
|
+
args: ["-y", "mcp-deepwiki@latest"],
|
|
1015
|
+
env: {}
|
|
1016
|
+
}
|
|
1017
|
+
},
|
|
1018
|
+
{
|
|
1019
|
+
id: "Playwright",
|
|
1020
|
+
name: {
|
|
1021
|
+
"zh-CN": "Playwright \u6D4F\u89C8\u5668\u63A7\u5236",
|
|
1022
|
+
en: "Playwright Browser Control"
|
|
1023
|
+
},
|
|
1024
|
+
description: {
|
|
1025
|
+
"zh-CN": "\u76F4\u63A5\u63A7\u5236\u6D4F\u89C8\u5668\u8FDB\u884C\u81EA\u52A8\u5316\u64CD\u4F5C",
|
|
1026
|
+
en: "Direct browser control for automation"
|
|
1027
|
+
},
|
|
1028
|
+
requiresApiKey: false,
|
|
1029
|
+
config: {
|
|
1030
|
+
type: "stdio",
|
|
1031
|
+
command: "npx",
|
|
1032
|
+
args: ["-y", "@playwright/mcp@latest"],
|
|
1033
|
+
env: {}
|
|
1034
|
+
}
|
|
1035
|
+
},
|
|
1036
|
+
{
|
|
1037
|
+
id: "exa",
|
|
1038
|
+
name: { "zh-CN": "Exa AI \u641C\u7D22", en: "Exa AI Search" },
|
|
1039
|
+
description: {
|
|
1040
|
+
"zh-CN": "\u4F7F\u7528 Exa AI \u8FDB\u884C\u7F51\u9875\u641C\u7D22",
|
|
1041
|
+
en: "Web search using Exa AI"
|
|
1042
|
+
},
|
|
1043
|
+
requiresApiKey: true,
|
|
1044
|
+
apiKeyPrompt: {
|
|
1045
|
+
"zh-CN": "\u8BF7\u8F93\u5165 Exa API Key\uFF08\u53EF\u4ECE https://dashboard.exa.ai/api-keys \u83B7\u53D6\uFF09",
|
|
1046
|
+
en: "Enter Exa API Key (get from https://dashboard.exa.ai/api-keys)"
|
|
1047
|
+
},
|
|
1048
|
+
apiKeyEnvVar: "EXA_API_KEY",
|
|
1049
|
+
config: {
|
|
1050
|
+
type: "stdio",
|
|
1051
|
+
command: "npx",
|
|
1052
|
+
args: ["-y", "exa-mcp-server"],
|
|
1053
|
+
env: {
|
|
1054
|
+
EXA_API_KEY: "YOUR_EXA_API_KEY"
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
];
|
|
1059
|
+
|
|
1060
|
+
function addNumbersToChoices(choices, startFrom = 1, format = (n) => `${n}. `) {
|
|
1061
|
+
let currentNumber = startFrom;
|
|
1062
|
+
return choices.map((choice) => {
|
|
1063
|
+
if (choice.disabled) {
|
|
1064
|
+
return choice;
|
|
1065
|
+
}
|
|
1066
|
+
const numbered = {
|
|
1067
|
+
...choice,
|
|
1068
|
+
name: `${format(currentNumber)}${choice.name}`
|
|
1069
|
+
};
|
|
1070
|
+
currentNumber++;
|
|
1071
|
+
return numbered;
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
class FileSystemError extends Error {
|
|
1076
|
+
constructor(message, path, cause) {
|
|
1077
|
+
super(message);
|
|
1078
|
+
this.path = path;
|
|
1079
|
+
this.cause = cause;
|
|
1080
|
+
this.name = "FileSystemError";
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
function exists(path) {
|
|
1084
|
+
return existsSync(path);
|
|
1085
|
+
}
|
|
1086
|
+
function ensureDir(path) {
|
|
1087
|
+
if (!existsSync(path)) {
|
|
1088
|
+
mkdirSync(path, { recursive: true });
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
function ensureFileDir(filePath) {
|
|
1092
|
+
const dir = dirname(filePath);
|
|
1093
|
+
ensureDir(dir);
|
|
1094
|
+
}
|
|
1095
|
+
function readFile(path, encoding = "utf-8") {
|
|
1096
|
+
try {
|
|
1097
|
+
return readFileSync(path, encoding);
|
|
1098
|
+
} catch (error) {
|
|
1099
|
+
throw new FileSystemError(
|
|
1100
|
+
`Failed to read file: ${path}`,
|
|
1101
|
+
path,
|
|
1102
|
+
error
|
|
1103
|
+
);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
function writeFile(path, content, encoding = "utf-8") {
|
|
1107
|
+
try {
|
|
1108
|
+
ensureFileDir(path);
|
|
1109
|
+
writeFileSync(path, content, encoding);
|
|
1110
|
+
} catch (error) {
|
|
1111
|
+
throw new FileSystemError(
|
|
1112
|
+
`Failed to write file: ${path}`,
|
|
1113
|
+
path,
|
|
1114
|
+
error
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
function copyFile(src, dest) {
|
|
1119
|
+
try {
|
|
1120
|
+
ensureFileDir(dest);
|
|
1121
|
+
copyFileSync(src, dest);
|
|
1122
|
+
} catch (error) {
|
|
1123
|
+
throw new FileSystemError(
|
|
1124
|
+
`Failed to copy file from ${src} to ${dest}`,
|
|
1125
|
+
src,
|
|
1126
|
+
error
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
function readDir(path) {
|
|
1131
|
+
try {
|
|
1132
|
+
return readdirSync(path);
|
|
1133
|
+
} catch (error) {
|
|
1134
|
+
throw new FileSystemError(
|
|
1135
|
+
`Failed to read directory: ${path}`,
|
|
1136
|
+
path,
|
|
1137
|
+
error
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
function getStats(path) {
|
|
1142
|
+
try {
|
|
1143
|
+
return statSync(path);
|
|
1144
|
+
} catch (error) {
|
|
1145
|
+
throw new FileSystemError(
|
|
1146
|
+
`Failed to get stats for: ${path}`,
|
|
1147
|
+
path,
|
|
1148
|
+
error
|
|
1149
|
+
);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
function copyDir(src, dest, options = {}) {
|
|
1153
|
+
const { filter, overwrite = true } = options;
|
|
1154
|
+
if (!exists(src)) {
|
|
1155
|
+
throw new FileSystemError(`Source directory does not exist: ${src}`, src);
|
|
1156
|
+
}
|
|
1157
|
+
ensureDir(dest);
|
|
1158
|
+
const entries = readDir(src);
|
|
1159
|
+
for (const entry of entries) {
|
|
1160
|
+
const srcPath = `${src}/${entry}`;
|
|
1161
|
+
const destPath = `${dest}/${entry}`;
|
|
1162
|
+
const stats = getStats(srcPath);
|
|
1163
|
+
if (filter && !filter(srcPath, stats)) {
|
|
1164
|
+
continue;
|
|
1165
|
+
}
|
|
1166
|
+
if (stats.isDirectory()) {
|
|
1167
|
+
copyDir(srcPath, destPath, options);
|
|
1168
|
+
} else {
|
|
1169
|
+
if (!overwrite && exists(destPath)) {
|
|
1170
|
+
continue;
|
|
1171
|
+
}
|
|
1172
|
+
copyFile(srcPath, destPath);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
function readJsonConfig(path, options = {}) {
|
|
1178
|
+
const { defaultValue = null, validate, sanitize } = options;
|
|
1179
|
+
if (!exists(path)) {
|
|
1180
|
+
return defaultValue;
|
|
1181
|
+
}
|
|
1182
|
+
try {
|
|
1183
|
+
const content = readFile(path);
|
|
1184
|
+
const data = JSON.parse(content);
|
|
1185
|
+
if (validate && !validate(data)) {
|
|
1186
|
+
const i18n = getTranslation(readZcfConfig()?.preferredLang || "en");
|
|
1187
|
+
console.warn(`${i18n.configuration.invalidConfiguration} (${path})`);
|
|
1188
|
+
return defaultValue;
|
|
1189
|
+
}
|
|
1190
|
+
if (sanitize) {
|
|
1191
|
+
return sanitize(data);
|
|
1192
|
+
}
|
|
1193
|
+
return data;
|
|
1194
|
+
} catch (error) {
|
|
1195
|
+
const i18n = getTranslation(readZcfConfig()?.preferredLang || "en");
|
|
1196
|
+
console.error(`${i18n.configuration.failedToParseJson} ${path}`, error);
|
|
1197
|
+
return defaultValue;
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
function writeJsonConfig(path, data, options = {}) {
|
|
1201
|
+
const { pretty = true, backup = false, backupDir } = options;
|
|
1202
|
+
if (backup && exists(path)) {
|
|
1203
|
+
backupJsonConfig(path, backupDir);
|
|
1204
|
+
}
|
|
1205
|
+
const content = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
|
|
1206
|
+
writeFile(path, content);
|
|
1207
|
+
}
|
|
1208
|
+
function backupJsonConfig(path, backupDir) {
|
|
1209
|
+
if (!exists(path)) {
|
|
1210
|
+
return null;
|
|
1211
|
+
}
|
|
1212
|
+
const timestamp = dayjs().format("YYYY-MM-DD_HH-mm-ss");
|
|
1213
|
+
const fileName = path.split("/").pop() || "config.json";
|
|
1214
|
+
const baseDir = backupDir || join(path, "..", "backup");
|
|
1215
|
+
const backupPath = join(baseDir, `${fileName}.backup_${timestamp}`);
|
|
1216
|
+
try {
|
|
1217
|
+
ensureDir(baseDir);
|
|
1218
|
+
copyFile(path, backupPath);
|
|
1219
|
+
return backupPath;
|
|
1220
|
+
} catch (error) {
|
|
1221
|
+
const i18n = getTranslation(readZcfConfig()?.preferredLang || "en");
|
|
1222
|
+
console.error(i18n.configuration.failedToBackupConfig, error);
|
|
1223
|
+
return null;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
function readZcfConfig() {
|
|
1228
|
+
let config = readJsonConfig(AICO_CONFIG_FILE);
|
|
1229
|
+
if (!config && existsSync(LEGACY_AICO_CONFIG_FILE)) {
|
|
1230
|
+
config = readJsonConfig(LEGACY_AICO_CONFIG_FILE);
|
|
1231
|
+
}
|
|
1232
|
+
return config;
|
|
1233
|
+
}
|
|
1234
|
+
async function readZcfConfigAsync() {
|
|
1235
|
+
return readZcfConfig();
|
|
1236
|
+
}
|
|
1237
|
+
function writeZcfConfig(config) {
|
|
1238
|
+
try {
|
|
1239
|
+
writeJsonConfig(AICO_CONFIG_FILE, config);
|
|
1240
|
+
} catch (error) {
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
function updateZcfConfig(updates) {
|
|
1244
|
+
const existingConfig = readZcfConfig();
|
|
1245
|
+
const newConfig = {
|
|
1246
|
+
version: updates.version || existingConfig?.version || "1.0.0",
|
|
1247
|
+
preferredLang: updates.preferredLang || existingConfig?.preferredLang || "en",
|
|
1248
|
+
aiOutputLang: updates.aiOutputLang || existingConfig?.aiOutputLang,
|
|
1249
|
+
aiPersonality: updates.aiPersonality !== void 0 ? updates.aiPersonality : existingConfig?.aiPersonality,
|
|
1250
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
1251
|
+
};
|
|
1252
|
+
writeZcfConfig(newConfig);
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
const AI_PERSONALITIES = [
|
|
1256
|
+
{
|
|
1257
|
+
id: "professional",
|
|
1258
|
+
name: { "zh-CN": "\u4E13\u4E1A\u52A9\u624B(\u9ED8\u8BA4)", en: "Professional Assistant(Default)" },
|
|
1259
|
+
directive: {
|
|
1260
|
+
"zh-CN": "\u4F60\u662F\u4E00\u540D\u7ECF\u9A8C\u4E30\u5BCC\u7684[\u4E13\u4E1A\u9886\u57DF\uFF0C\u4F8B\u5982\uFF1A\u8F6F\u4EF6\u5F00\u53D1\u5DE5\u7A0B\u5E08 / \u7CFB\u7EDF\u8BBE\u8BA1\u5E08 / \u4EE3\u7801\u67B6\u6784\u5E08]\uFF0C\u4E13\u6CE8\u4E8E\u6784\u5EFA[\u6838\u5FC3\u7279\u957F\uFF0C\u4F8B\u5982\uFF1A\u9AD8\u6027\u80FD / \u53EF\u7EF4\u62A4 / \u5065\u58EE / \u9886\u57DF\u9A71\u52A8]\u7684\u89E3\u51B3\u65B9\u6848\u3002",
|
|
1261
|
+
en: "You are an experienced [professional domain, e.g., Software Development Engineer / System Designer / Code Architect], specializing in building [core strengths, e.g., high-performance / maintainable / robust / domain-driven] solutions."
|
|
1262
|
+
}
|
|
1263
|
+
},
|
|
1264
|
+
{
|
|
1265
|
+
id: "friendly",
|
|
1266
|
+
name: { "zh-CN": "\u53CB\u597D\u52A9\u624B", en: "Friendly Assistant" },
|
|
1267
|
+
directive: {
|
|
1268
|
+
"zh-CN": "\u4F60\u662F\u4E00\u4F4D\u53CB\u597D\u3001\u8010\u5FC3\u3001\u5584\u4E8E\u89E3\u91CA\u7684\u7F16\u7A0B\u52A9\u624B\u3002\u4F1A\u7528\u901A\u4FD7\u6613\u61C2\u7684\u65B9\u5F0F\u89E3\u91CA\u590D\u6742\u6982\u5FF5\uFF0C\u5E76\u7ECF\u5E38\u7ED9\u4E88\u9F13\u52B1\u3002",
|
|
1269
|
+
en: "You are a friendly, patient, and explanatory programming assistant. You explain complex concepts in easy-to-understand ways and often provide encouragement."
|
|
1270
|
+
}
|
|
1271
|
+
},
|
|
1272
|
+
{
|
|
1273
|
+
id: "mentor",
|
|
1274
|
+
name: { "zh-CN": "\u5BFC\u5E08\u6A21\u5F0F", en: "Mentor Mode" },
|
|
1275
|
+
directive: {
|
|
1276
|
+
"zh-CN": "\u4F60\u662F\u4E00\u4F4D\u7ECF\u9A8C\u4E30\u5BCC\u7684\u7F16\u7A0B\u5BFC\u5E08\u3002\u4E0D\u4EC5\u63D0\u4F9B\u89E3\u51B3\u65B9\u6848\uFF0C\u8FD8\u4F1A\u89E3\u91CA\u80CC\u540E\u7684\u539F\u7406\uFF0C\u5F15\u5BFC\u7528\u6237\u601D\u8003\uFF0C\u57F9\u517B\u72EC\u7ACB\u89E3\u51B3\u95EE\u9898\u7684\u80FD\u529B\u3002",
|
|
1277
|
+
en: "You are an experienced programming mentor. You not only provide solutions but also explain the principles behind them, guide users to think, and cultivate their ability to solve problems independently."
|
|
1278
|
+
}
|
|
1279
|
+
},
|
|
1280
|
+
{
|
|
1281
|
+
id: "custom",
|
|
1282
|
+
name: { "zh-CN": "\u81EA\u5B9A\u4E49", en: "Custom" },
|
|
1283
|
+
directive: { "zh-CN": "", en: "" }
|
|
1284
|
+
}
|
|
1285
|
+
];
|
|
1286
|
+
function getExistingPersonality() {
|
|
1287
|
+
const config = readZcfConfig();
|
|
1288
|
+
return config?.aiPersonality || null;
|
|
1289
|
+
}
|
|
1290
|
+
function getPersonalityInfo(personalityId) {
|
|
1291
|
+
return AI_PERSONALITIES.find((p) => p.id === personalityId);
|
|
1292
|
+
}
|
|
1293
|
+
async function configureAiPersonality(scriptLang, showExisting = true) {
|
|
1294
|
+
const i18n = getTranslation(scriptLang);
|
|
1295
|
+
const existingPersonality = getExistingPersonality();
|
|
1296
|
+
if (showExisting && existingPersonality) {
|
|
1297
|
+
const personalityInfo = getPersonalityInfo(existingPersonality);
|
|
1298
|
+
if (personalityInfo) {
|
|
1299
|
+
console.log("\n" + ansis.blue(`\u2139 ${i18n.configuration.existingPersonality || "Existing AI personality configuration"}`));
|
|
1300
|
+
console.log(
|
|
1301
|
+
ansis.gray(` ${i18n.configuration.currentPersonality || "Current personality"}: ${personalityInfo.name[scriptLang]}`)
|
|
1302
|
+
);
|
|
1303
|
+
const { modify } = await inquirer.prompt({
|
|
1304
|
+
type: "confirm",
|
|
1305
|
+
name: "modify",
|
|
1306
|
+
message: i18n.configuration.modifyPersonality || "Modify AI personality?",
|
|
1307
|
+
default: false
|
|
1308
|
+
});
|
|
1309
|
+
if (!modify) {
|
|
1310
|
+
console.log(ansis.green(`\u2714 ${i18n.configuration.keepPersonality || "Keeping existing personality"}`));
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
const { personality } = await inquirer.prompt({
|
|
1316
|
+
type: "list",
|
|
1317
|
+
name: "personality",
|
|
1318
|
+
message: i18n.configuration.selectAiPersonality || "Select AI personality",
|
|
1319
|
+
choices: addNumbersToChoices(AI_PERSONALITIES.map((p) => ({
|
|
1320
|
+
name: p.id !== "custom" ? `${p.name[scriptLang]} - ${ansis.gray(p.directive[scriptLang].substring(0, 50) + "...")}` : `${p.name[scriptLang]} - ${ansis.gray(i18n.configuration.customPersonalityHint || "Define your own personality")}`,
|
|
1321
|
+
value: p.id,
|
|
1322
|
+
short: p.name[scriptLang]
|
|
1323
|
+
}))),
|
|
1324
|
+
default: existingPersonality ? AI_PERSONALITIES.findIndex((p) => p.id === existingPersonality) : 0
|
|
1325
|
+
});
|
|
1326
|
+
if (!personality) {
|
|
1327
|
+
console.log(ansis.yellow(i18n.common.cancelled));
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
let directive = "";
|
|
1331
|
+
if (personality === "custom") {
|
|
1332
|
+
const { customDirective } = await inquirer.prompt({
|
|
1333
|
+
type: "input",
|
|
1334
|
+
name: "customDirective",
|
|
1335
|
+
message: i18n.configuration.enterCustomPersonality || "Enter custom personality directive",
|
|
1336
|
+
validate: (value) => !!value || i18n.configuration.directiveCannotBeEmpty
|
|
1337
|
+
});
|
|
1338
|
+
if (!customDirective) {
|
|
1339
|
+
console.log(ansis.yellow(i18n.common.cancelled));
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
directive = customDirective;
|
|
1343
|
+
} else {
|
|
1344
|
+
const selected = AI_PERSONALITIES.find((p) => p.id === personality);
|
|
1345
|
+
if (selected) {
|
|
1346
|
+
directive = selected.directive[scriptLang];
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
await applyPersonalityDirective(directive);
|
|
1350
|
+
updateZcfConfig({ aiPersonality: personality });
|
|
1351
|
+
console.log(ansis.green(`\u2714 ${i18n.configuration.personalityConfigured || "AI personality configured"}`));
|
|
1352
|
+
}
|
|
1353
|
+
async function applyPersonalityDirective(directive) {
|
|
1354
|
+
try {
|
|
1355
|
+
const personalityFile = join(CLAUDE_DIR, "personality.md");
|
|
1356
|
+
writeFile(personalityFile, directive);
|
|
1357
|
+
} catch (error) {
|
|
1358
|
+
const lang = readZcfConfig()?.preferredLang || "en";
|
|
1359
|
+
const errorI18n = getTranslation(lang);
|
|
1360
|
+
console.error(ansis.red(errorI18n.configuration.failedToApplyPersonality || "Failed to apply personality"), error);
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
function displayBanner(subtitle) {
|
|
1365
|
+
const defaultSubtitle = "\u4E00\u952E\u914D\u7F6E\u4F60\u7684\u5F00\u53D1\u73AF\u5883";
|
|
1366
|
+
const subtitleText = subtitle || defaultSubtitle;
|
|
1367
|
+
const paddedSubtitle = subtitleText.padEnd(60, " ");
|
|
1368
|
+
console.log(
|
|
1369
|
+
ansis.cyan.bold(`
|
|
1370
|
+
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
1371
|
+
\u2551 \u2551
|
|
1372
|
+
\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2551
|
|
1373
|
+
\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557 \u2551
|
|
1374
|
+
\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2551
|
|
1375
|
+
\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2551
|
|
1376
|
+
\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2551
|
|
1377
|
+
\u2551 \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u2551
|
|
1378
|
+
\u2551 \u2551
|
|
1379
|
+
\u2551 ${ansis.white.bold("\u667A\u80FD\u8F6F\u4EF6\u661F\u5DE5\u5382")} \u2551
|
|
1380
|
+
\u2551 ${ansis.gray(paddedSubtitle)}\u2551
|
|
1381
|
+
\u2551 \u2551
|
|
1382
|
+
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
1383
|
+
`)
|
|
1384
|
+
);
|
|
1385
|
+
}
|
|
1386
|
+
function displayBannerWithInfo(subtitle) {
|
|
1387
|
+
displayBanner(subtitle);
|
|
1388
|
+
console.log(ansis.gray(` Version: ${ansis.cyan(version)}`));
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
function handleExitPromptError(error) {
|
|
1392
|
+
if (error instanceof Error && error.name === "ExitPromptError") {
|
|
1393
|
+
const zcfConfig = readZcfConfig();
|
|
1394
|
+
const defaultLang = zcfConfig?.preferredLang || "zh-CN";
|
|
1395
|
+
const i18n = getTranslation(defaultLang);
|
|
1396
|
+
console.log(ansis.cyan(`
|
|
1397
|
+
${i18n.common.goodbye}
|
|
1398
|
+
`));
|
|
1399
|
+
process.exit(0);
|
|
1400
|
+
}
|
|
1401
|
+
if (error instanceof EscapeKeyPressed) {
|
|
1402
|
+
return true;
|
|
1403
|
+
}
|
|
1404
|
+
return false;
|
|
1405
|
+
}
|
|
1406
|
+
function handleGeneralError(error, lang) {
|
|
1407
|
+
const zcfConfig = readZcfConfig();
|
|
1408
|
+
const defaultLang = lang || zcfConfig?.preferredLang || "en";
|
|
1409
|
+
const i18n = getTranslation(defaultLang);
|
|
1410
|
+
const errorMsg = i18n.common.error || "Error";
|
|
1411
|
+
console.error(ansis.red(`${errorMsg}:`), error);
|
|
1412
|
+
if (error instanceof Error) {
|
|
1413
|
+
console.error(ansis.gray(`Stack: ${error.stack}`));
|
|
1414
|
+
}
|
|
1415
|
+
process.exit(1);
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
function mergeArraysUnique(arr1, arr2) {
|
|
1419
|
+
const combined = [...arr1 || [], ...arr2 || []];
|
|
1420
|
+
return [...new Set(combined)];
|
|
1421
|
+
}
|
|
1422
|
+
function isPlainObject(value) {
|
|
1423
|
+
return value !== null && typeof value === "object" && value.constructor === Object && Object.prototype.toString.call(value) === "[object Object]";
|
|
1424
|
+
}
|
|
1425
|
+
function deepMerge(target, source, options = {}) {
|
|
1426
|
+
const { mergeArrays = false, arrayMergeStrategy = "replace" } = options;
|
|
1427
|
+
const result = { ...target };
|
|
1428
|
+
for (const key in source) {
|
|
1429
|
+
const sourceValue = source[key];
|
|
1430
|
+
const targetValue = result[key];
|
|
1431
|
+
if (sourceValue === void 0) {
|
|
1432
|
+
continue;
|
|
1433
|
+
}
|
|
1434
|
+
if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {
|
|
1435
|
+
result[key] = deepMerge(targetValue, sourceValue, options);
|
|
1436
|
+
} else if (Array.isArray(sourceValue)) {
|
|
1437
|
+
if (!mergeArrays || !Array.isArray(targetValue)) {
|
|
1438
|
+
result[key] = sourceValue;
|
|
1439
|
+
} else {
|
|
1440
|
+
switch (arrayMergeStrategy) {
|
|
1441
|
+
case "concat":
|
|
1442
|
+
result[key] = [...targetValue, ...sourceValue];
|
|
1443
|
+
break;
|
|
1444
|
+
case "unique":
|
|
1445
|
+
result[key] = mergeArraysUnique(targetValue, sourceValue);
|
|
1446
|
+
break;
|
|
1447
|
+
case "replace":
|
|
1448
|
+
default:
|
|
1449
|
+
result[key] = sourceValue;
|
|
1450
|
+
break;
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
} else {
|
|
1454
|
+
result[key] = sourceValue;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
return result;
|
|
1458
|
+
}
|
|
1459
|
+
function deepClone(obj) {
|
|
1460
|
+
if (obj === null || typeof obj !== "object") {
|
|
1461
|
+
return obj;
|
|
1462
|
+
}
|
|
1463
|
+
if (obj instanceof Date) {
|
|
1464
|
+
return new Date(obj.getTime());
|
|
1465
|
+
}
|
|
1466
|
+
if (Array.isArray(obj)) {
|
|
1467
|
+
return obj.map((item) => deepClone(item));
|
|
1468
|
+
}
|
|
1469
|
+
if (isPlainObject(obj)) {
|
|
1470
|
+
const cloned = {};
|
|
1471
|
+
for (const key in obj) {
|
|
1472
|
+
cloned[key] = deepClone(obj[key]);
|
|
1473
|
+
}
|
|
1474
|
+
return cloned;
|
|
1475
|
+
}
|
|
1476
|
+
return obj;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
function cleanupPermissions(templatePermissions, userPermissions) {
|
|
1480
|
+
const templateSet = new Set(templatePermissions);
|
|
1481
|
+
const cleanedPermissions = userPermissions.filter((permission) => {
|
|
1482
|
+
if (["mcp__.*", "mcp__*", "mcp__(*)"].includes(permission)) {
|
|
1483
|
+
return false;
|
|
1484
|
+
}
|
|
1485
|
+
for (const templatePerm of templatePermissions) {
|
|
1486
|
+
if (permission === templatePerm) {
|
|
1487
|
+
continue;
|
|
1488
|
+
}
|
|
1489
|
+
if (permission.startsWith(templatePerm)) {
|
|
1490
|
+
return false;
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
return true;
|
|
1494
|
+
});
|
|
1495
|
+
const merged = [...templateSet];
|
|
1496
|
+
for (const permission of cleanedPermissions) {
|
|
1497
|
+
if (!templateSet.has(permission)) {
|
|
1498
|
+
merged.push(permission);
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
return merged;
|
|
1502
|
+
}
|
|
1503
|
+
function mergeAndCleanPermissions(templatePermissions, userPermissions) {
|
|
1504
|
+
const template = templatePermissions || [];
|
|
1505
|
+
const user = userPermissions || [];
|
|
1506
|
+
return cleanupPermissions(template, user);
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
function getPlatform() {
|
|
1510
|
+
const p = platform();
|
|
1511
|
+
if (p === "win32") return "windows";
|
|
1512
|
+
if (p === "darwin") return "macos";
|
|
1513
|
+
return "linux";
|
|
1514
|
+
}
|
|
1515
|
+
function isTermux() {
|
|
1516
|
+
return !!(process.env.PREFIX && process.env.PREFIX.includes("com.termux")) || !!process.env.TERMUX_VERSION || existsSync("/data/data/com.termux/files/usr");
|
|
1517
|
+
}
|
|
1518
|
+
function getTermuxPrefix() {
|
|
1519
|
+
return process.env.PREFIX || "/data/data/com.termux/files/usr";
|
|
1520
|
+
}
|
|
1521
|
+
function isWindows() {
|
|
1522
|
+
return getPlatform() === "windows";
|
|
1523
|
+
}
|
|
1524
|
+
function getMcpCommand() {
|
|
1525
|
+
if (isWindows()) {
|
|
1526
|
+
return ["cmd", "/c", "npx"];
|
|
1527
|
+
}
|
|
1528
|
+
return ["npx"];
|
|
1529
|
+
}
|
|
1530
|
+
async function commandExists(command) {
|
|
1531
|
+
try {
|
|
1532
|
+
const cmd = getPlatform() === "windows" ? "where" : "which";
|
|
1533
|
+
const res = await exec(cmd, [command]);
|
|
1534
|
+
if (res.exitCode === 0) {
|
|
1535
|
+
return true;
|
|
1536
|
+
}
|
|
1537
|
+
} catch {
|
|
1538
|
+
}
|
|
1539
|
+
if (isTermux()) {
|
|
1540
|
+
const termuxPrefix = getTermuxPrefix();
|
|
1541
|
+
const possiblePaths = [
|
|
1542
|
+
`${termuxPrefix}/bin/${command}`,
|
|
1543
|
+
`${termuxPrefix}/usr/bin/${command}`,
|
|
1544
|
+
`/data/data/com.termux/files/usr/bin/${command}`
|
|
1545
|
+
];
|
|
1546
|
+
for (const path of possiblePaths) {
|
|
1547
|
+
if (existsSync(path)) {
|
|
1548
|
+
return true;
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
if (getPlatform() !== "windows") {
|
|
1553
|
+
const commonPaths = [
|
|
1554
|
+
`/usr/local/bin/${command}`,
|
|
1555
|
+
`/usr/bin/${command}`,
|
|
1556
|
+
`/bin/${command}`,
|
|
1557
|
+
`${process.env.HOME}/.local/bin/${command}`
|
|
1558
|
+
];
|
|
1559
|
+
for (const path of commonPaths) {
|
|
1560
|
+
if (existsSync(path)) {
|
|
1561
|
+
return true;
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
return false;
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
function getMcpConfigPath() {
|
|
1569
|
+
return ClAUDE_CONFIG_FILE;
|
|
1570
|
+
}
|
|
1571
|
+
function readMcpConfig() {
|
|
1572
|
+
return readJsonConfig(ClAUDE_CONFIG_FILE);
|
|
1573
|
+
}
|
|
1574
|
+
function writeMcpConfig(config) {
|
|
1575
|
+
writeJsonConfig(ClAUDE_CONFIG_FILE, config);
|
|
1576
|
+
}
|
|
1577
|
+
function backupMcpConfig() {
|
|
1578
|
+
const backupBaseDir = join(CLAUDE_DIR, "backup");
|
|
1579
|
+
return backupJsonConfig(ClAUDE_CONFIG_FILE, backupBaseDir);
|
|
1580
|
+
}
|
|
1581
|
+
function mergeMcpServers(existing, newServers) {
|
|
1582
|
+
const config = existing || { mcpServers: {} };
|
|
1583
|
+
if (!config.mcpServers) {
|
|
1584
|
+
config.mcpServers = {};
|
|
1585
|
+
}
|
|
1586
|
+
Object.assign(config.mcpServers, newServers);
|
|
1587
|
+
return config;
|
|
1588
|
+
}
|
|
1589
|
+
function applyPlatformCommand(config) {
|
|
1590
|
+
if (config.command === "npx" && isWindows()) {
|
|
1591
|
+
const mcpCmd = getMcpCommand();
|
|
1592
|
+
config.command = mcpCmd[0];
|
|
1593
|
+
config.args = [...mcpCmd.slice(1), ...config.args || []];
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
function buildMcpServerConfig(baseConfig, apiKey, placeholder = "YOUR_EXA_API_KEY", envVarName) {
|
|
1597
|
+
const config = deepClone(baseConfig);
|
|
1598
|
+
applyPlatformCommand(config);
|
|
1599
|
+
if (!apiKey) {
|
|
1600
|
+
return config;
|
|
1601
|
+
}
|
|
1602
|
+
if (envVarName && config.env) {
|
|
1603
|
+
config.env[envVarName] = apiKey;
|
|
1604
|
+
return config;
|
|
1605
|
+
}
|
|
1606
|
+
if (config.args) {
|
|
1607
|
+
config.args = config.args.map((arg) => arg.replace(placeholder, apiKey));
|
|
1608
|
+
}
|
|
1609
|
+
if (config.url) {
|
|
1610
|
+
config.url = config.url.replace(placeholder, apiKey);
|
|
1611
|
+
}
|
|
1612
|
+
return config;
|
|
1613
|
+
}
|
|
1614
|
+
function fixWindowsMcpConfig(config) {
|
|
1615
|
+
if (!isWindows() || !config.mcpServers) {
|
|
1616
|
+
return config;
|
|
1617
|
+
}
|
|
1618
|
+
const fixed = { ...config };
|
|
1619
|
+
for (const [, serverConfig] of Object.entries(fixed.mcpServers)) {
|
|
1620
|
+
if (serverConfig && typeof serverConfig === "object" && "command" in serverConfig) {
|
|
1621
|
+
applyPlatformCommand(serverConfig);
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
return fixed;
|
|
1625
|
+
}
|
|
1626
|
+
function addCompletedOnboarding() {
|
|
1627
|
+
try {
|
|
1628
|
+
let config = readMcpConfig();
|
|
1629
|
+
if (!config) {
|
|
1630
|
+
config = { mcpServers: {} };
|
|
1631
|
+
}
|
|
1632
|
+
if (config.hasCompletedOnboarding === true) {
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
config.hasCompletedOnboarding = true;
|
|
1636
|
+
writeMcpConfig(config);
|
|
1637
|
+
} catch (error) {
|
|
1638
|
+
const lang = readZcfConfig()?.preferredLang || "en";
|
|
1639
|
+
const i18n = getTranslation(lang);
|
|
1640
|
+
console.error(i18n.configuration?.failedToAddOnboardingFlag || "Failed to add onboarding flag", error);
|
|
1641
|
+
throw error;
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
function ensureClaudeDir() {
|
|
1646
|
+
ensureDir(CLAUDE_DIR);
|
|
1647
|
+
}
|
|
1648
|
+
function backupExistingConfig() {
|
|
1649
|
+
if (!exists(CLAUDE_DIR)) {
|
|
1650
|
+
return null;
|
|
1651
|
+
}
|
|
1652
|
+
const timestamp = dayjs().format("YYYY-MM-DD_HH-mm-ss");
|
|
1653
|
+
const backupBaseDir = join(CLAUDE_DIR, "backup");
|
|
1654
|
+
const backupDir = join(backupBaseDir, `backup_${timestamp}`);
|
|
1655
|
+
ensureDir(backupDir);
|
|
1656
|
+
const filter = (path) => {
|
|
1657
|
+
return !path.includes("/backup");
|
|
1658
|
+
};
|
|
1659
|
+
copyDir(CLAUDE_DIR, backupDir, { filter });
|
|
1660
|
+
return backupDir;
|
|
1661
|
+
}
|
|
1662
|
+
function copyConfigFiles(lang, onlyMd = false) {
|
|
1663
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
1664
|
+
const distDir = dirname(dirname(currentFilePath));
|
|
1665
|
+
const rootDir = dirname(distDir);
|
|
1666
|
+
const baseTemplateDir = join(rootDir, "templates");
|
|
1667
|
+
copyClaudeMemoryFiles(lang, rootDir);
|
|
1668
|
+
if (!onlyMd) {
|
|
1669
|
+
const baseSettingsPath = join(baseTemplateDir, "settings.json");
|
|
1670
|
+
const destSettingsPath = join(CLAUDE_DIR, "settings.json");
|
|
1671
|
+
if (exists(baseSettingsPath)) {
|
|
1672
|
+
mergeSettingsFile(baseSettingsPath, destSettingsPath);
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
const claudeMdSource = join(baseTemplateDir, "CLAUDE.md");
|
|
1676
|
+
const claudeMdDest = join(CLAUDE_DIR, "CLAUDE.md");
|
|
1677
|
+
if (exists(claudeMdSource)) {
|
|
1678
|
+
copyFile(claudeMdSource, claudeMdDest);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
function copyClaudeMemoryFiles(lang, rootDir) {
|
|
1682
|
+
const memorySourceDir = join(rootDir, "templates", lang, "memory");
|
|
1683
|
+
if (!exists(memorySourceDir)) {
|
|
1684
|
+
const i18n = getTranslation(lang);
|
|
1685
|
+
throw new Error(`${i18n.configuration.memoryDirNotFound || "Memory directory not found:"} ${memorySourceDir}`);
|
|
1686
|
+
}
|
|
1687
|
+
const files = readDir(memorySourceDir);
|
|
1688
|
+
files?.forEach((file) => {
|
|
1689
|
+
if (file.endsWith(".md")) {
|
|
1690
|
+
const sourcePath = join(memorySourceDir, file);
|
|
1691
|
+
const destPath = join(CLAUDE_DIR, file);
|
|
1692
|
+
copyFile(sourcePath, destPath);
|
|
1693
|
+
}
|
|
1694
|
+
});
|
|
1695
|
+
}
|
|
1696
|
+
function getDefaultSettings() {
|
|
1697
|
+
try {
|
|
1698
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
1699
|
+
const distDir = dirname(dirname(currentFilePath));
|
|
1700
|
+
const rootDir = dirname(distDir);
|
|
1701
|
+
const templateSettingsPath = join(rootDir, "templates", "settings.json");
|
|
1702
|
+
return readJsonConfig(templateSettingsPath) || {};
|
|
1703
|
+
} catch (error) {
|
|
1704
|
+
const lang = readZcfConfig()?.preferredLang || "en";
|
|
1705
|
+
const i18n = getTranslation(lang);
|
|
1706
|
+
console.error(i18n.configuration.failedToReadTemplateSettings || "Failed to read template settings", error);
|
|
1707
|
+
return {};
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
function configureApi(apiConfig) {
|
|
1711
|
+
if (!apiConfig) return null;
|
|
1712
|
+
let settings = getDefaultSettings();
|
|
1713
|
+
const existingSettings = readJsonConfig(SETTINGS_FILE);
|
|
1714
|
+
if (existingSettings) {
|
|
1715
|
+
settings = deepMerge(settings, existingSettings);
|
|
1716
|
+
}
|
|
1717
|
+
if (!settings.env) {
|
|
1718
|
+
settings.env = {};
|
|
1719
|
+
}
|
|
1720
|
+
if (apiConfig.authType === "api_key") {
|
|
1721
|
+
settings.env.ANTHROPIC_API_KEY = apiConfig.key;
|
|
1722
|
+
delete settings.env.ANTHROPIC_AUTH_TOKEN;
|
|
1723
|
+
} else if (apiConfig.authType === "auth_token") {
|
|
1724
|
+
settings.env.ANTHROPIC_AUTH_TOKEN = apiConfig.key;
|
|
1725
|
+
delete settings.env.ANTHROPIC_API_KEY;
|
|
1726
|
+
}
|
|
1727
|
+
if (apiConfig.url) {
|
|
1728
|
+
settings.env.ANTHROPIC_BASE_URL = apiConfig.url;
|
|
1729
|
+
}
|
|
1730
|
+
writeJsonConfig(SETTINGS_FILE, settings);
|
|
1731
|
+
try {
|
|
1732
|
+
addCompletedOnboarding();
|
|
1733
|
+
} catch (error) {
|
|
1734
|
+
const lang = readZcfConfig()?.preferredLang || "en";
|
|
1735
|
+
const i18n = getTranslation(lang);
|
|
1736
|
+
console.error(i18n.configuration.failedToSetOnboarding || "Failed to set onboarding flag", error);
|
|
1737
|
+
}
|
|
1738
|
+
return apiConfig;
|
|
1739
|
+
}
|
|
1740
|
+
function mergeConfigs(sourceFile, targetFile) {
|
|
1741
|
+
if (!exists(sourceFile)) return;
|
|
1742
|
+
const target = readJsonConfig(targetFile) || {};
|
|
1743
|
+
const source = readJsonConfig(sourceFile) || {};
|
|
1744
|
+
const merged = deepMerge(target, source);
|
|
1745
|
+
writeJsonConfig(targetFile, merged);
|
|
1746
|
+
}
|
|
1747
|
+
function updateDefaultModel(model) {
|
|
1748
|
+
let settings = getDefaultSettings();
|
|
1749
|
+
const existingSettings = readJsonConfig(SETTINGS_FILE);
|
|
1750
|
+
if (existingSettings) {
|
|
1751
|
+
settings = existingSettings;
|
|
1752
|
+
}
|
|
1753
|
+
settings.model = model;
|
|
1754
|
+
writeJsonConfig(SETTINGS_FILE, settings);
|
|
1755
|
+
}
|
|
1756
|
+
function mergeSettingsFile(templatePath, targetPath) {
|
|
1757
|
+
try {
|
|
1758
|
+
const templateSettings = readJsonConfig(templatePath);
|
|
1759
|
+
if (!templateSettings) {
|
|
1760
|
+
const lang = readZcfConfig()?.preferredLang || "en";
|
|
1761
|
+
const i18n = getTranslation(lang);
|
|
1762
|
+
console.error(i18n.configuration?.failedToReadTemplateSettings || "Failed to read template settings");
|
|
1763
|
+
return;
|
|
1764
|
+
}
|
|
1765
|
+
if (!exists(targetPath)) {
|
|
1766
|
+
writeJsonConfig(targetPath, templateSettings);
|
|
1767
|
+
return;
|
|
1768
|
+
}
|
|
1769
|
+
const existingSettings = readJsonConfig(targetPath) || {};
|
|
1770
|
+
const mergedEnv = {
|
|
1771
|
+
...templateSettings.env || {},
|
|
1772
|
+
// Template env vars first
|
|
1773
|
+
...existingSettings.env || {}
|
|
1774
|
+
// User's env vars override (preserving API keys, etc.)
|
|
1775
|
+
};
|
|
1776
|
+
const mergedSettings = deepMerge(templateSettings, existingSettings, {
|
|
1777
|
+
mergeArrays: true,
|
|
1778
|
+
arrayMergeStrategy: "unique"
|
|
1779
|
+
});
|
|
1780
|
+
mergedSettings.env = mergedEnv;
|
|
1781
|
+
if (mergedSettings.permissions && mergedSettings.permissions.allow) {
|
|
1782
|
+
mergedSettings.permissions.allow = mergeAndCleanPermissions(
|
|
1783
|
+
templateSettings.permissions?.allow,
|
|
1784
|
+
existingSettings.permissions?.allow
|
|
1785
|
+
);
|
|
1786
|
+
}
|
|
1787
|
+
writeJsonConfig(targetPath, mergedSettings);
|
|
1788
|
+
} catch (error) {
|
|
1789
|
+
const lang = readZcfConfig()?.preferredLang || "en";
|
|
1790
|
+
const i18n = getTranslation(lang);
|
|
1791
|
+
console.error(i18n.configuration.failedToMergeSettings || "Failed to merge settings", error);
|
|
1792
|
+
if (exists(targetPath)) {
|
|
1793
|
+
const lang2 = readZcfConfig()?.preferredLang || "en";
|
|
1794
|
+
const i18n2 = getTranslation(lang2);
|
|
1795
|
+
console.warn(i18n2.configuration.preservingExistingSettings || "Preserving existing settings");
|
|
1796
|
+
} else {
|
|
1797
|
+
copyFile(templatePath, targetPath);
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
function getExistingApiConfig() {
|
|
1802
|
+
const settings = readJsonConfig(SETTINGS_FILE);
|
|
1803
|
+
if (!settings || !settings.env) {
|
|
1804
|
+
return null;
|
|
1805
|
+
}
|
|
1806
|
+
const { ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_BASE_URL } = settings.env;
|
|
1807
|
+
if (!ANTHROPIC_BASE_URL && !ANTHROPIC_API_KEY && !ANTHROPIC_AUTH_TOKEN) {
|
|
1808
|
+
return null;
|
|
1809
|
+
}
|
|
1810
|
+
let authType;
|
|
1811
|
+
let key;
|
|
1812
|
+
if (ANTHROPIC_AUTH_TOKEN) {
|
|
1813
|
+
authType = "auth_token";
|
|
1814
|
+
key = ANTHROPIC_AUTH_TOKEN;
|
|
1815
|
+
} else if (ANTHROPIC_API_KEY) {
|
|
1816
|
+
authType = "api_key";
|
|
1817
|
+
key = ANTHROPIC_API_KEY;
|
|
1818
|
+
}
|
|
1819
|
+
return {
|
|
1820
|
+
url: ANTHROPIC_BASE_URL || "",
|
|
1821
|
+
key: key || "",
|
|
1822
|
+
authType
|
|
1823
|
+
};
|
|
1824
|
+
}
|
|
1825
|
+
function applyAiLanguageDirective(aiOutputLang) {
|
|
1826
|
+
const languageFile = join(CLAUDE_DIR, "language.md");
|
|
1827
|
+
let directive = "";
|
|
1828
|
+
if (aiOutputLang === "custom") {
|
|
1829
|
+
return;
|
|
1830
|
+
} else if (AI_OUTPUT_LANGUAGES[aiOutputLang]) {
|
|
1831
|
+
directive = AI_OUTPUT_LANGUAGES[aiOutputLang].directive;
|
|
1832
|
+
} else {
|
|
1833
|
+
directive = `Always respond in ${aiOutputLang}`;
|
|
1834
|
+
}
|
|
1835
|
+
writeFile(languageFile, directive);
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
async function isClaudeCodeInstalled() {
|
|
1839
|
+
return await commandExists("claude");
|
|
1840
|
+
}
|
|
1841
|
+
async function installClaudeCode(lang) {
|
|
1842
|
+
const i18n = getTranslation(lang);
|
|
1843
|
+
if (isTermux()) {
|
|
1844
|
+
console.log(ansis.yellow(`\u2139 ${i18n.installation.termuxDetected}`));
|
|
1845
|
+
const termuxPrefix = getTermuxPrefix();
|
|
1846
|
+
console.log(ansis.gray(i18n.installation.termuxPathInfo.replace("{path}", termuxPrefix)));
|
|
1847
|
+
console.log(ansis.gray(`Node.js: ${termuxPrefix}/bin/node`));
|
|
1848
|
+
console.log(ansis.gray(`npm: ${termuxPrefix}/bin/npm`));
|
|
1849
|
+
}
|
|
1850
|
+
console.log(i18n.installation.installing);
|
|
1851
|
+
try {
|
|
1852
|
+
await exec("npm", ["install", "-g", "@anthropic-ai/claude-code"]);
|
|
1853
|
+
console.log(`\u2714 ${i18n.installation.installSuccess}`);
|
|
1854
|
+
if (isTermux()) {
|
|
1855
|
+
console.log(ansis.gray(`
|
|
1856
|
+
Claude Code installed to: ${getTermuxPrefix()}/bin/claude`));
|
|
1857
|
+
}
|
|
1858
|
+
} catch (error) {
|
|
1859
|
+
console.error(`\u2716 ${i18n.installation.installFailed}`);
|
|
1860
|
+
if (isTermux()) {
|
|
1861
|
+
console.error(ansis.yellow(`
|
|
1862
|
+
${i18n.installation.termuxInstallHint}
|
|
1863
|
+
`));
|
|
1864
|
+
}
|
|
1865
|
+
throw error;
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
async function selectMcpServices(scriptLang) {
|
|
1870
|
+
const i18n = getTranslation(scriptLang);
|
|
1871
|
+
try {
|
|
1872
|
+
const choices = MCP_SERVICES.map((service) => ({
|
|
1873
|
+
name: `${service.name[scriptLang]} - ${ansis.gray(service.description[scriptLang])}`,
|
|
1874
|
+
value: service.id,
|
|
1875
|
+
selected: false
|
|
1876
|
+
}));
|
|
1877
|
+
const { services } = await inquirer.prompt({
|
|
1878
|
+
type: "checkbox",
|
|
1879
|
+
name: "services",
|
|
1880
|
+
message: `${i18n.mcp.selectMcpServices}${i18n.common.multiSelectHint}`,
|
|
1881
|
+
choices
|
|
1882
|
+
});
|
|
1883
|
+
return services;
|
|
1884
|
+
} catch (error) {
|
|
1885
|
+
if (error instanceof EscapeKeyPressed) {
|
|
1886
|
+
console.log(ansis.yellow(i18n.common.cancelled));
|
|
1887
|
+
return void 0;
|
|
1888
|
+
}
|
|
1889
|
+
throw error;
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
const WORKFLOW_CONFIGS = [
|
|
1894
|
+
{
|
|
1895
|
+
id: "sixStepsWorkflow",
|
|
1896
|
+
nameKey: "workflowOption.sixStepsWorkflow",
|
|
1897
|
+
descriptionKey: "workflowDescription.sixStepsWorkflow",
|
|
1898
|
+
defaultSelected: true,
|
|
1899
|
+
order: 1,
|
|
1900
|
+
commands: ["workflow.md"],
|
|
1901
|
+
agents: [],
|
|
1902
|
+
autoInstallAgents: false,
|
|
1903
|
+
category: "sixStep",
|
|
1904
|
+
outputDir: "workflow"
|
|
1905
|
+
},
|
|
1906
|
+
{
|
|
1907
|
+
id: "featPlanUx",
|
|
1908
|
+
nameKey: "workflowOption.featPlanUx",
|
|
1909
|
+
descriptionKey: "workflowDescription.featPlanUx",
|
|
1910
|
+
defaultSelected: true,
|
|
1911
|
+
order: 2,
|
|
1912
|
+
commands: ["feat.md"],
|
|
1913
|
+
agents: [
|
|
1914
|
+
{ id: "planner", filename: "planner.md", required: true },
|
|
1915
|
+
{ id: "ui-ux-designer", filename: "ui-ux-designer.md", required: true }
|
|
1916
|
+
],
|
|
1917
|
+
autoInstallAgents: true,
|
|
1918
|
+
category: "plan",
|
|
1919
|
+
outputDir: "feat"
|
|
1920
|
+
},
|
|
1921
|
+
{
|
|
1922
|
+
id: "bmadWorkflow",
|
|
1923
|
+
nameKey: "workflowOption.bmadWorkflow",
|
|
1924
|
+
descriptionKey: "workflowDescription.bmadWorkflow",
|
|
1925
|
+
defaultSelected: true,
|
|
1926
|
+
order: 3,
|
|
1927
|
+
commands: ["bmad-init.md"],
|
|
1928
|
+
agents: [],
|
|
1929
|
+
autoInstallAgents: false,
|
|
1930
|
+
category: "bmad",
|
|
1931
|
+
outputDir: "bmad"
|
|
1932
|
+
}
|
|
1933
|
+
];
|
|
1934
|
+
function getWorkflowConfig(workflowId) {
|
|
1935
|
+
return WORKFLOW_CONFIGS.find((config) => config.id === workflowId);
|
|
1936
|
+
}
|
|
1937
|
+
function getOrderedWorkflows() {
|
|
1938
|
+
return [...WORKFLOW_CONFIGS].sort((a, b) => a.order - b.order);
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
function getRootDir() {
|
|
1942
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
1943
|
+
const distDir = dirname(dirname(currentFilePath));
|
|
1944
|
+
return dirname(distDir);
|
|
1945
|
+
}
|
|
1946
|
+
async function selectAndInstallWorkflows(configLang, scriptLang) {
|
|
1947
|
+
const i18n = getTranslation(scriptLang);
|
|
1948
|
+
const workflows = getOrderedWorkflows();
|
|
1949
|
+
const choices = workflows.map((workflow) => {
|
|
1950
|
+
const nameKey = workflow.id;
|
|
1951
|
+
const name = i18n.workflow.workflowOption[nameKey] || workflow.id;
|
|
1952
|
+
return {
|
|
1953
|
+
name,
|
|
1954
|
+
value: workflow.id,
|
|
1955
|
+
checked: workflow.defaultSelected
|
|
1956
|
+
};
|
|
1957
|
+
});
|
|
1958
|
+
const { selectedWorkflows } = await inquirer.prompt({
|
|
1959
|
+
type: "checkbox",
|
|
1960
|
+
name: "selectedWorkflows",
|
|
1961
|
+
message: `${i18n.workflow.selectWorkflowType}${i18n.common.multiSelectHint}`,
|
|
1962
|
+
choices
|
|
1963
|
+
});
|
|
1964
|
+
if (!selectedWorkflows || selectedWorkflows.length === 0) {
|
|
1965
|
+
console.log(ansis.yellow(i18n.common.cancelled));
|
|
1966
|
+
return;
|
|
1967
|
+
}
|
|
1968
|
+
await cleanupOldVersionFiles(scriptLang);
|
|
1969
|
+
for (const workflowId of selectedWorkflows) {
|
|
1970
|
+
const config = getWorkflowConfig(workflowId);
|
|
1971
|
+
if (config) {
|
|
1972
|
+
await installWorkflowWithDependencies(config, configLang, scriptLang);
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
async function installWorkflowWithDependencies(config, configLang, scriptLang) {
|
|
1977
|
+
const rootDir = getRootDir();
|
|
1978
|
+
const i18n = getTranslation(scriptLang);
|
|
1979
|
+
const result = {
|
|
1980
|
+
workflow: config.id,
|
|
1981
|
+
success: true,
|
|
1982
|
+
installedCommands: [],
|
|
1983
|
+
installedAgents: [],
|
|
1984
|
+
errors: []
|
|
1985
|
+
};
|
|
1986
|
+
const workflowName = i18n.workflow.workflowOption[config.id] || config.id;
|
|
1987
|
+
console.log(ansis.cyan(`
|
|
1988
|
+
\u{1F4E6} ${i18n.workflow.installingWorkflow}: ${workflowName}...`));
|
|
1989
|
+
const commandsDir = join(CLAUDE_DIR, "commands", "aico");
|
|
1990
|
+
if (!existsSync(commandsDir)) {
|
|
1991
|
+
await mkdir(commandsDir, { recursive: true });
|
|
1992
|
+
}
|
|
1993
|
+
for (const commandFile of config.commands) {
|
|
1994
|
+
const commandSource = join(rootDir, "templates", configLang, "workflow", config.category, "commands", commandFile);
|
|
1995
|
+
const destFileName = commandFile;
|
|
1996
|
+
const commandDest = join(commandsDir, destFileName);
|
|
1997
|
+
if (existsSync(commandSource)) {
|
|
1998
|
+
try {
|
|
1999
|
+
await copyFile$1(commandSource, commandDest);
|
|
2000
|
+
result.installedCommands.push(destFileName);
|
|
2001
|
+
console.log(ansis.gray(` \u2714 ${i18n.workflow.installedCommand}: aico/${destFileName}`));
|
|
2002
|
+
} catch (error) {
|
|
2003
|
+
const errorMsg = `${i18n.workflow.failedToInstallCommand} ${commandFile}: ${error}`;
|
|
2004
|
+
result.errors?.push(errorMsg);
|
|
2005
|
+
console.error(ansis.red(` \u2717 ${errorMsg}`));
|
|
2006
|
+
result.success = false;
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
if (config.autoInstallAgents && config.agents.length > 0) {
|
|
2011
|
+
const agentsCategoryDir = join(CLAUDE_DIR, "agents", "aico", config.category);
|
|
2012
|
+
if (!existsSync(agentsCategoryDir)) {
|
|
2013
|
+
await mkdir(agentsCategoryDir, { recursive: true });
|
|
2014
|
+
}
|
|
2015
|
+
for (const agent of config.agents) {
|
|
2016
|
+
const agentSource = join(rootDir, "templates", configLang, "workflow", config.category, "agents", agent.filename);
|
|
2017
|
+
const agentDest = join(agentsCategoryDir, agent.filename);
|
|
2018
|
+
if (existsSync(agentSource)) {
|
|
2019
|
+
try {
|
|
2020
|
+
await copyFile$1(agentSource, agentDest);
|
|
2021
|
+
result.installedAgents.push(agent.filename);
|
|
2022
|
+
console.log(ansis.gray(` \u2714 ${i18n.workflow.installedAgent}: aico/${config.category}/${agent.filename}`));
|
|
2023
|
+
} catch (error) {
|
|
2024
|
+
const errorMsg = `${i18n.workflow.failedToInstallAgent} ${agent.filename}: ${error}`;
|
|
2025
|
+
result.errors?.push(errorMsg);
|
|
2026
|
+
console.error(ansis.red(` \u2717 ${errorMsg}`));
|
|
2027
|
+
if (agent.required) {
|
|
2028
|
+
result.success = false;
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
if (result.success) {
|
|
2035
|
+
console.log(ansis.green(`\u2714 ${workflowName} ${i18n.workflow.workflowInstallSuccess}`));
|
|
2036
|
+
if (config.id === "bmadWorkflow") {
|
|
2037
|
+
console.log(ansis.cyan(`
|
|
2038
|
+
${i18n.bmad.bmadInitPrompt}`));
|
|
2039
|
+
}
|
|
2040
|
+
} else {
|
|
2041
|
+
console.log(ansis.red(`\u2717 ${workflowName} ${i18n.workflow.workflowInstallError}`));
|
|
2042
|
+
}
|
|
2043
|
+
return result;
|
|
2044
|
+
}
|
|
2045
|
+
async function cleanupOldVersionFiles(scriptLang) {
|
|
2046
|
+
const i18n = getTranslation(scriptLang);
|
|
2047
|
+
console.log(ansis.cyan(`
|
|
2048
|
+
\u{1F9F9} ${i18n.workflow.cleaningOldFiles || "Cleaning up old version files"}...`));
|
|
2049
|
+
const oldCommandFiles = [
|
|
2050
|
+
join(CLAUDE_DIR, "commands", "workflow.md"),
|
|
2051
|
+
join(CLAUDE_DIR, "commands", "feat.md")
|
|
2052
|
+
];
|
|
2053
|
+
const oldAgentFiles = [
|
|
2054
|
+
join(CLAUDE_DIR, "agents", "planner.md"),
|
|
2055
|
+
join(CLAUDE_DIR, "agents", "ui-ux-designer.md")
|
|
2056
|
+
];
|
|
2057
|
+
for (const file of oldCommandFiles) {
|
|
2058
|
+
if (existsSync(file)) {
|
|
2059
|
+
try {
|
|
2060
|
+
await rm(file, { force: true });
|
|
2061
|
+
console.log(ansis.gray(` \u2714 ${i18n.workflow.removedOldFile || "Removed old file"}: ${file.replace(CLAUDE_DIR, "~/.claude")}`));
|
|
2062
|
+
} catch (error) {
|
|
2063
|
+
console.error(ansis.yellow(` \u26A0 ${i18n.workflow.failedToRemoveFile || "Failed to remove"}: ${file.replace(CLAUDE_DIR, "~/.claude")}`));
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
for (const file of oldAgentFiles) {
|
|
2068
|
+
if (existsSync(file)) {
|
|
2069
|
+
try {
|
|
2070
|
+
await rm(file, { force: true });
|
|
2071
|
+
console.log(ansis.gray(` \u2714 ${i18n.workflow.removedOldFile || "Removed old file"}: ${file.replace(CLAUDE_DIR, "~/.claude")}`));
|
|
2072
|
+
} catch (error) {
|
|
2073
|
+
console.error(ansis.yellow(` \u26A0 ${i18n.workflow.failedToRemoveFile || "Failed to remove"}: ${file.replace(CLAUDE_DIR, "~/.claude")}`));
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
async function init(options = {}) {
|
|
2080
|
+
try {
|
|
2081
|
+
if (!options.skipBanner) {
|
|
2082
|
+
displayBannerWithInfo();
|
|
2083
|
+
}
|
|
2084
|
+
const scriptLang = "zh-CN";
|
|
2085
|
+
const configLang = "zh-CN";
|
|
2086
|
+
const i18n = I18N[scriptLang];
|
|
2087
|
+
if (isTermux()) {
|
|
2088
|
+
console.log(ansis.yellow(`
|
|
2089
|
+
\u2139 ${i18n.installation.termuxDetected}`));
|
|
2090
|
+
console.log(ansis.gray(i18n.installation.termuxEnvironmentInfo));
|
|
2091
|
+
}
|
|
2092
|
+
const aiOutputLang = "zh-CN";
|
|
2093
|
+
const installed = await isClaudeCodeInstalled();
|
|
2094
|
+
if (!installed) {
|
|
2095
|
+
const { shouldInstall } = await inquirer.prompt({
|
|
2096
|
+
type: "confirm",
|
|
2097
|
+
name: "shouldInstall",
|
|
2098
|
+
message: i18n.installation.installPrompt,
|
|
2099
|
+
default: true
|
|
2100
|
+
});
|
|
2101
|
+
if (shouldInstall === void 0) {
|
|
2102
|
+
console.log(ansis.yellow(i18n.common.cancelled));
|
|
2103
|
+
process.exit(0);
|
|
2104
|
+
}
|
|
2105
|
+
if (shouldInstall) {
|
|
2106
|
+
await installClaudeCode(scriptLang);
|
|
2107
|
+
} else {
|
|
2108
|
+
console.log(ansis.yellow(i18n.common.skip));
|
|
2109
|
+
}
|
|
2110
|
+
} else {
|
|
2111
|
+
console.log(ansis.green(`\u2714 ${i18n.installation.alreadyInstalled}`));
|
|
2112
|
+
}
|
|
2113
|
+
ensureClaudeDir();
|
|
2114
|
+
let action = "new";
|
|
2115
|
+
if (existsSync(SETTINGS_FILE) && !options.force) {
|
|
2116
|
+
const { action: userAction } = await inquirer.prompt({
|
|
2117
|
+
type: "list",
|
|
2118
|
+
name: "action",
|
|
2119
|
+
message: i18n.configuration.existingConfig,
|
|
2120
|
+
choices: addNumbersToChoices([
|
|
2121
|
+
{ name: i18n.configuration.backupAndOverwrite, value: "backup" },
|
|
2122
|
+
{ name: i18n.configuration.updateDocsOnly, value: "docs-only" },
|
|
2123
|
+
{ name: i18n.configuration.mergeConfig, value: "merge" },
|
|
2124
|
+
{ name: i18n.common.skip, value: "skip" }
|
|
2125
|
+
])
|
|
2126
|
+
});
|
|
2127
|
+
if (!userAction) {
|
|
2128
|
+
console.log(ansis.yellow(i18n.common.cancelled));
|
|
2129
|
+
process.exit(0);
|
|
2130
|
+
}
|
|
2131
|
+
action = userAction;
|
|
2132
|
+
if (action === "skip") {
|
|
2133
|
+
console.log(ansis.yellow(i18n.common.skip));
|
|
2134
|
+
return;
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
let apiConfig = null;
|
|
2138
|
+
const isNewInstall = !existsSync(SETTINGS_FILE);
|
|
2139
|
+
if (action !== "docs-only" && (isNewInstall || ["backup", "merge"].includes(action))) {
|
|
2140
|
+
apiConfig = {
|
|
2141
|
+
url: "http://11.0.166.20:13456",
|
|
2142
|
+
key: "sk-4730d06849b5fea00f551bd60a0902e1",
|
|
2143
|
+
authType: "auth_token"
|
|
2144
|
+
};
|
|
2145
|
+
console.log(ansis.green(`\u2714 \u4F7F\u7528\u9884\u914D\u7F6EAPI\u4FE1\u606F`));
|
|
2146
|
+
}
|
|
2147
|
+
if (["backup", "docs-only", "merge"].includes(action)) {
|
|
2148
|
+
const backupDir = backupExistingConfig();
|
|
2149
|
+
if (backupDir) {
|
|
2150
|
+
console.log(ansis.gray(`\u2714 ${i18n.configuration.backupSuccess}: ${backupDir}`));
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
if (action === "docs-only") {
|
|
2154
|
+
copyConfigFiles(configLang, true);
|
|
2155
|
+
await selectAndInstallWorkflows(configLang, scriptLang);
|
|
2156
|
+
} else if (["backup", "merge", "new"].includes(action)) {
|
|
2157
|
+
copyConfigFiles(configLang, false);
|
|
2158
|
+
await selectAndInstallWorkflows(configLang, scriptLang);
|
|
2159
|
+
}
|
|
2160
|
+
applyAiLanguageDirective(aiOutputLang);
|
|
2161
|
+
await configureAiPersonality(scriptLang);
|
|
2162
|
+
if (apiConfig && action !== "docs-only") {
|
|
2163
|
+
const configuredApi = configureApi(apiConfig);
|
|
2164
|
+
if (configuredApi) {
|
|
2165
|
+
console.log(ansis.green(`\u2714 ${i18n.api.apiConfigSuccess}`));
|
|
2166
|
+
console.log(ansis.gray(` URL: ${configuredApi.url}`));
|
|
2167
|
+
console.log(ansis.gray(` Key: sk-***...***`));
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
if (action !== "docs-only") {
|
|
2171
|
+
const { shouldConfigureMcp } = await inquirer.prompt({
|
|
2172
|
+
type: "confirm",
|
|
2173
|
+
name: "shouldConfigureMcp",
|
|
2174
|
+
message: i18n.mcp.configureMcp,
|
|
2175
|
+
default: true
|
|
2176
|
+
});
|
|
2177
|
+
if (shouldConfigureMcp === void 0) {
|
|
2178
|
+
console.log(ansis.yellow(i18n.common.cancelled));
|
|
2179
|
+
process.exit(0);
|
|
2180
|
+
}
|
|
2181
|
+
if (shouldConfigureMcp) {
|
|
2182
|
+
if (isWindows()) {
|
|
2183
|
+
console.log(ansis.blue(`\u2139 ${i18n.installation.windowsDetected}`));
|
|
2184
|
+
}
|
|
2185
|
+
const selectedServices = await selectMcpServices(scriptLang);
|
|
2186
|
+
if (selectedServices === void 0) {
|
|
2187
|
+
process.exit(0);
|
|
2188
|
+
}
|
|
2189
|
+
if (selectedServices.length > 0) {
|
|
2190
|
+
const mcpBackupPath = backupMcpConfig();
|
|
2191
|
+
if (mcpBackupPath) {
|
|
2192
|
+
console.log(ansis.gray(`\u2714 ${i18n.mcp.mcpBackupSuccess}: ${mcpBackupPath}`));
|
|
2193
|
+
}
|
|
2194
|
+
const newServers = {};
|
|
2195
|
+
for (const serviceId of selectedServices) {
|
|
2196
|
+
const service = MCP_SERVICES.find((s) => s.id === serviceId);
|
|
2197
|
+
if (!service) continue;
|
|
2198
|
+
let config = service.config;
|
|
2199
|
+
if (service.requiresApiKey) {
|
|
2200
|
+
const { apiKey } = await inquirer.prompt({
|
|
2201
|
+
type: "input",
|
|
2202
|
+
name: "apiKey",
|
|
2203
|
+
message: service.apiKeyPrompt[scriptLang],
|
|
2204
|
+
validate: (value) => !!value || i18n.api.keyRequired
|
|
2205
|
+
});
|
|
2206
|
+
if (apiKey === void 0) {
|
|
2207
|
+
console.log(ansis.yellow(`${i18n.common.skip}: ${service.name[scriptLang]}`));
|
|
2208
|
+
continue;
|
|
2209
|
+
}
|
|
2210
|
+
if (apiKey) {
|
|
2211
|
+
config = buildMcpServerConfig(service.config, apiKey, service.apiKeyPlaceholder, service.apiKeyEnvVar);
|
|
2212
|
+
} else {
|
|
2213
|
+
continue;
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
newServers[service.id] = config;
|
|
2217
|
+
}
|
|
2218
|
+
const existingConfig = readMcpConfig();
|
|
2219
|
+
let mergedConfig = mergeMcpServers(existingConfig, newServers);
|
|
2220
|
+
mergedConfig = fixWindowsMcpConfig(mergedConfig);
|
|
2221
|
+
try {
|
|
2222
|
+
writeMcpConfig(mergedConfig);
|
|
2223
|
+
console.log(ansis.green(`\u2714 ${i18n.mcp.mcpConfigSuccess}`));
|
|
2224
|
+
} catch (error) {
|
|
2225
|
+
console.error(ansis.red(`${i18n.configuration.failedToWriteMcpConfig} ${error}`));
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
updateZcfConfig({
|
|
2231
|
+
version,
|
|
2232
|
+
preferredLang: scriptLang,
|
|
2233
|
+
aiOutputLang
|
|
2234
|
+
});
|
|
2235
|
+
console.log(ansis.green(`\u2714 ${i18n.configuration.configSuccess} ${CLAUDE_DIR}`));
|
|
2236
|
+
console.log("\n" + ansis.cyan(i18n.common.complete));
|
|
2237
|
+
} catch (error) {
|
|
2238
|
+
if (!handleExitPromptError(error)) {
|
|
2239
|
+
handleGeneralError(error, options.lang);
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
2245
|
+
function getTemplateSettings() {
|
|
2246
|
+
const templatePath = join(__dirname, "../../templates/settings.json");
|
|
2247
|
+
const content = readFileSync(templatePath, "utf-8");
|
|
2248
|
+
return JSON.parse(content);
|
|
2249
|
+
}
|
|
2250
|
+
function loadCurrentSettings() {
|
|
2251
|
+
if (!existsSync(SETTINGS_FILE)) {
|
|
2252
|
+
return {};
|
|
2253
|
+
}
|
|
2254
|
+
try {
|
|
2255
|
+
const content = readFileSync(SETTINGS_FILE, "utf-8");
|
|
2256
|
+
return JSON.parse(content);
|
|
2257
|
+
} catch {
|
|
2258
|
+
return {};
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
function saveSettings(settings) {
|
|
2262
|
+
ensureDir(CLAUDE_DIR);
|
|
2263
|
+
writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2));
|
|
2264
|
+
}
|
|
2265
|
+
async function importRecommendedEnv() {
|
|
2266
|
+
const templateSettings = getTemplateSettings();
|
|
2267
|
+
const currentSettings = loadCurrentSettings();
|
|
2268
|
+
currentSettings.env = {
|
|
2269
|
+
...currentSettings.env,
|
|
2270
|
+
...templateSettings.env
|
|
2271
|
+
};
|
|
2272
|
+
saveSettings(currentSettings);
|
|
2273
|
+
}
|
|
2274
|
+
async function importRecommendedPermissions() {
|
|
2275
|
+
const templateSettings = getTemplateSettings();
|
|
2276
|
+
const currentSettings = loadCurrentSettings();
|
|
2277
|
+
if (templateSettings.permissions && templateSettings.permissions.allow) {
|
|
2278
|
+
currentSettings.permissions = {
|
|
2279
|
+
...templateSettings.permissions,
|
|
2280
|
+
allow: mergeAndCleanPermissions(
|
|
2281
|
+
templateSettings.permissions.allow,
|
|
2282
|
+
currentSettings.permissions?.allow
|
|
2283
|
+
)
|
|
2284
|
+
};
|
|
2285
|
+
} else {
|
|
2286
|
+
currentSettings.permissions = templateSettings.permissions;
|
|
2287
|
+
}
|
|
2288
|
+
saveSettings(currentSettings);
|
|
2289
|
+
}
|
|
2290
|
+
async function openSettingsJson() {
|
|
2291
|
+
ensureDir(CLAUDE_DIR);
|
|
2292
|
+
if (!existsSync(SETTINGS_FILE)) {
|
|
2293
|
+
saveSettings({});
|
|
2294
|
+
}
|
|
2295
|
+
const platform = getPlatform();
|
|
2296
|
+
let command;
|
|
2297
|
+
switch (platform) {
|
|
2298
|
+
case "macos":
|
|
2299
|
+
command = "open";
|
|
2300
|
+
break;
|
|
2301
|
+
case "windows":
|
|
2302
|
+
command = "start";
|
|
2303
|
+
break;
|
|
2304
|
+
default:
|
|
2305
|
+
command = "xdg-open";
|
|
2306
|
+
}
|
|
2307
|
+
try {
|
|
2308
|
+
await exec(command, [SETTINGS_FILE]);
|
|
2309
|
+
} catch (error) {
|
|
2310
|
+
try {
|
|
2311
|
+
await exec("code", [SETTINGS_FILE]);
|
|
2312
|
+
} catch {
|
|
2313
|
+
try {
|
|
2314
|
+
await exec("vim", [SETTINGS_FILE]);
|
|
2315
|
+
} catch {
|
|
2316
|
+
await exec("nano", [SETTINGS_FILE]);
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
export { displayBannerWithInfo as $, AICO_CONFIG_FILE as A, writeMcpConfig as B, CLAUDE_DIR as C, backupMcpConfig as D, mergeMcpServers as E, buildMcpServerConfig as F, fixWindowsMcpConfig as G, addCompletedOnboarding as H, I18N as I, readZcfConfig as J, inquirer as K, LEGACY_AICO_CONFIG_FILE as L, MCP_SERVICES as M, addNumbersToChoices as N, updateZcfConfig as O, getTranslation as P, version as Q, configureAiPersonality as R, SETTINGS_FILE as S, readJsonConfig as T, writeJsonConfig as U, isWindows as V, selectMcpServices as W, displayBanner as X, selectAndInstallWorkflows as Y, handleExitPromptError as Z, handleGeneralError as _, importRecommendedEnv as a, readZcfConfigAsync as a0, executeWithEscapeSupport as a1, EscapeKeyPressed as a2, importRecommendedPermissions as b, commandExists as c, cleanupPermissions as d, CLAUDE_MD_FILE as e, ClAUDE_CONFIG_FILE as f, getPlatform as g, SUPPORTED_LANGS as h, init as i, LANG_LABELS as j, AI_OUTPUT_LANGUAGES as k, isClaudeCodeInstalled as l, mergeAndCleanPermissions as m, installClaudeCode as n, openSettingsJson as o, ensureClaudeDir as p, backupExistingConfig as q, copyConfigFiles as r, configureApi as s, mergeConfigs as t, updateDefaultModel as u, mergeSettingsFile as v, getExistingApiConfig as w, applyAiLanguageDirective as x, getMcpConfigPath as y, readMcpConfig as z };
|