ccbot-cli 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +380 -153
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { createRequire } from "module";
|
|
5
|
+
|
|
3
6
|
// src/utils/logger.ts
|
|
4
7
|
import pc from "picocolors";
|
|
5
8
|
var log = {
|
|
@@ -12,19 +15,30 @@ var log = {
|
|
|
12
15
|
};
|
|
13
16
|
function banner(version) {
|
|
14
17
|
console.log();
|
|
15
|
-
console.log(pc.cyan(" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E"));
|
|
16
|
-
console.log(pc.cyan(" \u2502
|
|
17
|
-
console.log(pc.cyan(" \u2502") + " \u{1F916} ccbot - Claude Code \u73AF\u5883\u914D\u7F6E
|
|
18
|
-
console.log(pc.cyan(" \u2502") + pc.dim(`
|
|
19
|
-
console.log(pc.cyan(" \u2502
|
|
20
|
-
console.log(pc.cyan(" \
|
|
18
|
+
console.log(pc.cyan(" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E"));
|
|
19
|
+
console.log(pc.cyan(" \u2502 \u2502"));
|
|
20
|
+
console.log(pc.cyan(" \u2502") + " \u{1F916} ccbot - Claude Code \u73AF\u5883\u4E00\u952E\u914D\u7F6E " + pc.cyan("\u2502"));
|
|
21
|
+
console.log(pc.cyan(" \u2502") + pc.dim(` v${version}`) + " " + pc.cyan("\u2502"));
|
|
22
|
+
console.log(pc.cyan(" \u2502 \u2502"));
|
|
23
|
+
console.log(pc.cyan(" \u2502") + pc.dim(" \u81EA\u52A8\u68C0\u6D4B\u73AF\u5883 \xB7 \u5B89\u88C5CLI \xB7 \u914D\u7F6EMCP ") + pc.cyan("\u2502"));
|
|
24
|
+
console.log(pc.cyan(" \u2502") + pc.dim(" \u5B89\u88C5Skills \xB7 \u751F\u6210\u914D\u7F6E \xB7 \u6E05\u7406\u53D8\u91CF ") + pc.cyan("\u2502"));
|
|
25
|
+
console.log(pc.cyan(" \u2502 \u2502"));
|
|
26
|
+
console.log(pc.cyan(" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F"));
|
|
21
27
|
console.log();
|
|
22
28
|
}
|
|
23
29
|
function summary(items) {
|
|
30
|
+
const okCount = items.filter((i) => i.ok).length;
|
|
31
|
+
const failCount = items.filter((i) => !i.ok).length;
|
|
24
32
|
console.log();
|
|
25
|
-
console.log(pc.cyan(" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E"));
|
|
26
|
-
console.log(pc.cyan(" \u2502
|
|
27
|
-
|
|
33
|
+
console.log(pc.cyan(" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E"));
|
|
34
|
+
console.log(pc.cyan(" \u2502 \u2502"));
|
|
35
|
+
if (failCount === 0) {
|
|
36
|
+
console.log(pc.cyan(" \u2502") + pc.green(pc.bold(" \u2713 \u5168\u90E8\u5B89\u88C5\u6210\u529F\uFF01")) + " " + pc.cyan("\u2502"));
|
|
37
|
+
} else {
|
|
38
|
+
console.log(pc.cyan(" \u2502") + pc.yellow(pc.bold(` \u26A0 \u5B8C\u6210 ${okCount} \u9879\uFF0C${failCount} \u9879\u9700\u6CE8\u610F`)) + " " + pc.cyan("\u2502"));
|
|
39
|
+
}
|
|
40
|
+
console.log(pc.cyan(" \u2502 \u2502"));
|
|
41
|
+
console.log(pc.cyan(" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F"));
|
|
28
42
|
console.log();
|
|
29
43
|
for (const item of items) {
|
|
30
44
|
if (item.ok) {
|
|
@@ -34,19 +48,21 @@ function summary(items) {
|
|
|
34
48
|
}
|
|
35
49
|
}
|
|
36
50
|
console.log();
|
|
37
|
-
log.
|
|
38
|
-
log.
|
|
39
|
-
log.
|
|
51
|
+
console.log(pc.cyan(" \u250C ") + pc.bold("\u4E0B\u4E00\u6B65"));
|
|
52
|
+
console.log(pc.cyan(" \u2502 ") + "1. \u8FD0\u884C " + pc.green("claude") + " \u542F\u52A8 Claude Code");
|
|
53
|
+
console.log(pc.cyan(" \u2502 ") + "2. \u7F16\u8F91 " + pc.green("CLAUDE.md") + " \u81EA\u5B9A\u4E49\u9879\u76EE\u6307\u4EE4");
|
|
54
|
+
console.log(pc.cyan(" \u2502 ") + "3. \u67E5\u770B " + pc.green(".claude/settings.json") + " \u786E\u8BA4 MCP \u914D\u7F6E");
|
|
55
|
+
console.log(pc.cyan(" \u2514"));
|
|
40
56
|
console.log();
|
|
41
57
|
}
|
|
42
58
|
|
|
43
59
|
// src/cli.ts
|
|
44
60
|
import * as p8 from "@clack/prompts";
|
|
45
|
-
import
|
|
61
|
+
import pc8 from "picocolors";
|
|
46
62
|
|
|
47
63
|
// src/steps/detect.ts
|
|
48
64
|
import * as p from "@clack/prompts";
|
|
49
|
-
import
|
|
65
|
+
import pc3 from "picocolors";
|
|
50
66
|
|
|
51
67
|
// src/utils/exec.ts
|
|
52
68
|
import { execa } from "execa";
|
|
@@ -74,6 +90,34 @@ async function npmInstallGlobal(pkg) {
|
|
|
74
90
|
return run("npm", ["install", "-g", pkg]);
|
|
75
91
|
}
|
|
76
92
|
|
|
93
|
+
// src/utils/hints.ts
|
|
94
|
+
import pc2 from "picocolors";
|
|
95
|
+
function hintMultiselect() {
|
|
96
|
+
console.log();
|
|
97
|
+
console.log(pc2.cyan(" \u250C ") + pc2.bold("\u64CD\u4F5C\u6307\u5357"));
|
|
98
|
+
console.log(pc2.cyan(" \u2502 ") + pc2.dim("\u2191\u2193") + " \u79FB\u52A8\u5149\u6807 " + pc2.dim("\u7A7A\u683C") + " \u9009\u4E2D/\u53D6\u6D88");
|
|
99
|
+
console.log(pc2.cyan(" \u2502 ") + pc2.dim("a") + " \u5168\u9009/\u5168\u4E0D\u9009 " + pc2.dim("\u56DE\u8F66") + " \u786E\u8BA4\u63D0\u4EA4");
|
|
100
|
+
console.log(pc2.cyan(" \u2514"));
|
|
101
|
+
console.log();
|
|
102
|
+
}
|
|
103
|
+
function hintSelect() {
|
|
104
|
+
console.log();
|
|
105
|
+
console.log(pc2.cyan(" \u250C ") + pc2.bold("\u64CD\u4F5C\u6307\u5357"));
|
|
106
|
+
console.log(pc2.cyan(" \u2502 ") + pc2.dim("\u2191\u2193") + " \u79FB\u52A8\u5149\u6807 " + pc2.dim("\u56DE\u8F66") + " \u786E\u8BA4\u9009\u62E9");
|
|
107
|
+
console.log(pc2.cyan(" \u2514"));
|
|
108
|
+
console.log();
|
|
109
|
+
}
|
|
110
|
+
function hintConfirm() {
|
|
111
|
+
console.log(pc2.dim(" Y/\u56DE\u8F66 \u786E\u8BA4 \u2502 N \u53D6\u6D88"));
|
|
112
|
+
}
|
|
113
|
+
function stepHeader(current, total, title) {
|
|
114
|
+
console.log();
|
|
115
|
+
console.log(
|
|
116
|
+
pc2.cyan(" \u2501\u2501\u2501 ") + pc2.bold(`\u6B65\u9AA4 ${current}/${total}`) + pc2.cyan(" \u2501 ") + pc2.white(title) + pc2.cyan(" \u2501\u2501\u2501")
|
|
117
|
+
);
|
|
118
|
+
console.log();
|
|
119
|
+
}
|
|
120
|
+
|
|
77
121
|
// src/steps/detect.ts
|
|
78
122
|
var SENSITIVE_PATTERNS = [
|
|
79
123
|
/^ANTHROPIC_API_KEY$/i,
|
|
@@ -109,9 +153,10 @@ function scanSensitiveEnvVars() {
|
|
|
109
153
|
}
|
|
110
154
|
return found;
|
|
111
155
|
}
|
|
112
|
-
async function detect() {
|
|
156
|
+
async function detect(totalSteps) {
|
|
157
|
+
stepHeader(1, totalSteps, "\u73AF\u5883\u68C0\u6D4B");
|
|
113
158
|
const s = p.spinner();
|
|
114
|
-
s.start("\u6B63\u5728\
|
|
159
|
+
s.start("\u6B63\u5728\u626B\u63CF\u7CFB\u7EDF\u73AF\u5883...");
|
|
115
160
|
const nodeVersion = process.version;
|
|
116
161
|
const npmResult = await run("npm", ["--version"]);
|
|
117
162
|
const npmVersion = npmResult.stdout.trim();
|
|
@@ -128,21 +173,24 @@ async function detect() {
|
|
|
128
173
|
claudeVersion = result.stdout.trim();
|
|
129
174
|
}
|
|
130
175
|
const sensitiveEnvVars = scanSensitiveEnvVars();
|
|
131
|
-
s.stop("\u73AF\u5883\
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
176
|
+
s.stop("\u73AF\u5883\u626B\u63CF\u5B8C\u6210");
|
|
177
|
+
const lines = [];
|
|
178
|
+
lines.push(`${pc3.green("\u2713")} Node.js ${nodeVersion}`);
|
|
179
|
+
lines.push(`${pc3.green("\u2713")} npm v${npmVersion}`);
|
|
180
|
+
lines.push(`${pc3.green("\u2713")} \u7CFB\u7EDF ${os}`);
|
|
135
181
|
if (claudeInstalled) {
|
|
136
|
-
|
|
182
|
+
lines.push(`${pc3.green("\u2713")} Claude CLI ${claudeVersion}`);
|
|
137
183
|
} else {
|
|
138
|
-
|
|
184
|
+
lines.push(`${pc3.yellow("\u2717")} Claude CLI \u672A\u5B89\u88C5 (\u5C06\u5728\u540E\u7EED\u6B65\u9AA4\u5B89\u88C5)`);
|
|
139
185
|
}
|
|
140
186
|
if (sensitiveEnvVars.length > 0) {
|
|
141
|
-
|
|
187
|
+
lines.push("");
|
|
188
|
+
lines.push(`${pc3.yellow("\u26A0")} \u68C0\u6D4B\u5230 ${sensitiveEnvVars.length} \u4E2A\u654F\u611F\u73AF\u5883\u53D8\u91CF:`);
|
|
142
189
|
for (const { key, value } of sensitiveEnvVars) {
|
|
143
|
-
|
|
190
|
+
lines.push(` ${pc3.yellow("\xB7")} ${key} = ${pc3.dim(maskValue(value))}`);
|
|
144
191
|
}
|
|
145
192
|
}
|
|
193
|
+
p.note(lines.join("\n"), "\u73AF\u5883\u4FE1\u606F");
|
|
146
194
|
return {
|
|
147
195
|
nodeVersion,
|
|
148
196
|
npmVersion,
|
|
@@ -156,43 +204,46 @@ async function detect() {
|
|
|
156
204
|
|
|
157
205
|
// src/steps/select.ts
|
|
158
206
|
import * as p2 from "@clack/prompts";
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
console.log();
|
|
162
|
-
console.log(pc3.dim(" \u64CD\u4F5C\u6307\u5357:"));
|
|
163
|
-
console.log(pc3.dim(" \u2191/\u2193 \u4E0A\u4E0B\u79FB\u52A8\u5149\u6807"));
|
|
164
|
-
console.log(pc3.dim(" \u7A7A\u683C \u9009\u4E2D/\u53D6\u6D88\u9009\u4E2D\u5F53\u524D\u9879"));
|
|
165
|
-
console.log(pc3.dim(" a \u5168\u9009/\u5168\u4E0D\u9009"));
|
|
166
|
-
console.log(pc3.dim(" \u56DE\u8F66 \u786E\u8BA4\u9009\u62E9"));
|
|
167
|
-
console.log();
|
|
168
|
-
}
|
|
169
|
-
async function selectComponents(env) {
|
|
207
|
+
async function selectComponents(env, totalSteps) {
|
|
208
|
+
stepHeader(2, totalSteps, "\u9009\u62E9\u5B89\u88C5\u7EC4\u4EF6");
|
|
170
209
|
const options = [
|
|
171
210
|
{
|
|
172
211
|
value: "installCli",
|
|
173
|
-
label: "Claude Code CLI
|
|
174
|
-
hint: env.claudeInstalled ?
|
|
212
|
+
label: "Claude Code CLI",
|
|
213
|
+
hint: env.claudeInstalled ? `\u5DF2\u5B89\u88C5 ${env.claudeVersion ?? ""}, \u5C06\u8DF3\u8FC7` : "\u5168\u5C40\u5B89\u88C5 @anthropic-ai/claude-code"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
value: "scaffold",
|
|
217
|
+
label: "\u9879\u76EE\u914D\u7F6E\u6587\u4EF6",
|
|
218
|
+
hint: "\u751F\u6210 CLAUDE.md / .claude/ / .claudeignore"
|
|
175
219
|
},
|
|
176
|
-
{
|
|
177
|
-
|
|
178
|
-
|
|
220
|
+
{
|
|
221
|
+
value: "installMcp",
|
|
222
|
+
label: "MCP Servers",
|
|
223
|
+
hint: "\u914D\u7F6E AI \u5DE5\u5177\u670D\u52A1 (\u6D4F\u89C8\u5668/\u641C\u7D22/\u6587\u6863\u7B49)"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
value: "installSkills",
|
|
227
|
+
label: "Skills / Plugins",
|
|
228
|
+
hint: "\u589E\u5F3A Claude Code \u5DE5\u4F5C\u6D41\u80FD\u529B"
|
|
229
|
+
}
|
|
179
230
|
];
|
|
180
231
|
if (env.sensitiveEnvVars.length > 0) {
|
|
181
232
|
options.push({
|
|
182
233
|
value: "cleanEnv",
|
|
183
234
|
label: "\u73AF\u5883\u53D8\u91CF\u6E05\u7406",
|
|
184
|
-
hint: `\
|
|
235
|
+
hint: `\u53D1\u73B0 ${env.sensitiveEnvVars.length} \u4E2A\u654F\u611F\u53D8\u91CF, \u5EFA\u8BAE\u79FB\u9664`
|
|
185
236
|
});
|
|
186
237
|
}
|
|
187
|
-
|
|
238
|
+
hintMultiselect();
|
|
188
239
|
const selected = await p2.multiselect({
|
|
189
|
-
message: "\u9009\u62E9\u8981\u5B89\u88C5\u7684\u7EC4\u4EF6
|
|
240
|
+
message: "\u9009\u62E9\u8981\u5B89\u88C5\u7684\u7EC4\u4EF6",
|
|
190
241
|
options,
|
|
191
242
|
initialValues: options.map((o) => o.value),
|
|
192
243
|
required: true
|
|
193
244
|
});
|
|
194
245
|
if (p2.isCancel(selected)) {
|
|
195
|
-
p2.cancel("\u5DF2\u53D6\u6D88");
|
|
246
|
+
p2.cancel("\u5DF2\u53D6\u6D88\u64CD\u4F5C");
|
|
196
247
|
process.exit(0);
|
|
197
248
|
}
|
|
198
249
|
const values = selected;
|
|
@@ -234,6 +285,7 @@ async function installCli(alreadyInstalled) {
|
|
|
234
285
|
|
|
235
286
|
// src/steps/scaffold.ts
|
|
236
287
|
import * as p4 from "@clack/prompts";
|
|
288
|
+
import pc4 from "picocolors";
|
|
237
289
|
import { join as join2 } from "path";
|
|
238
290
|
|
|
239
291
|
// src/utils/fs.ts
|
|
@@ -281,79 +333,179 @@ function deepMerge(target, source) {
|
|
|
281
333
|
}
|
|
282
334
|
|
|
283
335
|
// src/steps/scaffold.ts
|
|
284
|
-
var
|
|
336
|
+
var CLAUDE_MD_MINIMAL = `# Project Instructions
|
|
337
|
+
|
|
338
|
+
- Follow existing code style
|
|
339
|
+
- Read before write
|
|
340
|
+
- Keep changes minimal
|
|
341
|
+
`;
|
|
342
|
+
var CLAUDE_MD_STANDARD = `# Project Instructions
|
|
343
|
+
|
|
344
|
+
## Overview
|
|
345
|
+
<!-- Describe your project purpose and tech stack -->
|
|
346
|
+
|
|
347
|
+
## Coding Standards
|
|
348
|
+
- Follow existing code patterns and style
|
|
349
|
+
- Read and understand context before modifying
|
|
350
|
+
- Keep changes focused and minimal
|
|
285
351
|
|
|
286
|
-
|
|
352
|
+
## Key Files
|
|
353
|
+
<!-- List important file paths here -->
|
|
287
354
|
|
|
288
|
-
##
|
|
355
|
+
## Notes
|
|
356
|
+
<!-- Special considerations -->
|
|
357
|
+
`;
|
|
358
|
+
var CLAUDE_MD_DETAILED = `# Project Instructions
|
|
289
359
|
|
|
290
|
-
|
|
360
|
+
## Project Overview
|
|
361
|
+
<!-- Describe the project purpose, goals, and tech stack in detail -->
|
|
291
362
|
|
|
292
|
-
##
|
|
363
|
+
## Architecture
|
|
364
|
+
<!-- Describe the high-level architecture and key design decisions -->
|
|
293
365
|
|
|
294
|
-
|
|
295
|
-
-
|
|
296
|
-
-
|
|
366
|
+
## Coding Standards
|
|
367
|
+
- Follow existing code patterns and style
|
|
368
|
+
- Read and understand context before modifying files
|
|
369
|
+
- Keep changes focused and minimal
|
|
370
|
+
- Write clear commit messages
|
|
371
|
+
- Add comments for complex logic
|
|
297
372
|
|
|
298
|
-
##
|
|
373
|
+
## Key Files
|
|
374
|
+
<!-- List important file paths and their purposes -->
|
|
299
375
|
|
|
300
|
-
|
|
376
|
+
## Dependencies
|
|
377
|
+
<!-- List key dependencies and their roles -->
|
|
301
378
|
|
|
302
|
-
##
|
|
379
|
+
## Testing
|
|
380
|
+
<!-- Describe testing approach and how to run tests -->
|
|
303
381
|
|
|
304
|
-
|
|
382
|
+
## Notes
|
|
383
|
+
<!-- Special considerations, gotchas, or important context -->
|
|
305
384
|
`;
|
|
306
|
-
var
|
|
307
|
-
|
|
308
|
-
allow: [
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
"WebSearch"
|
|
314
|
-
],
|
|
385
|
+
var PERMISSIONS = {
|
|
386
|
+
strict: {
|
|
387
|
+
allow: ["Read", "Glob", "Grep"],
|
|
388
|
+
deny: ["Bash", "Write", "Edit"]
|
|
389
|
+
},
|
|
390
|
+
normal: {
|
|
391
|
+
allow: ["Read", "Glob", "Grep", "WebFetch", "WebSearch"],
|
|
315
392
|
deny: []
|
|
316
393
|
},
|
|
317
|
-
|
|
394
|
+
permissive: {
|
|
395
|
+
allow: ["Read", "Glob", "Grep", "Write", "Edit", "Bash", "WebFetch", "WebSearch"],
|
|
396
|
+
deny: []
|
|
397
|
+
}
|
|
318
398
|
};
|
|
319
|
-
var
|
|
399
|
+
var CLAUDEIGNORE = `# Ignore patterns for Claude Code
|
|
320
400
|
node_modules/
|
|
321
401
|
dist/
|
|
402
|
+
build/
|
|
322
403
|
.env
|
|
323
404
|
.env.*
|
|
324
405
|
*.log
|
|
325
406
|
.DS_Store
|
|
326
407
|
coverage/
|
|
408
|
+
.git/
|
|
327
409
|
`;
|
|
328
|
-
async function
|
|
410
|
+
async function scaffoldConfig(totalSteps) {
|
|
411
|
+
stepHeader(3, totalSteps, "\u914D\u7F6E\u811A\u624B\u67B6");
|
|
412
|
+
hintSelect();
|
|
413
|
+
const style = await p4.select({
|
|
414
|
+
message: "CLAUDE.md \u6A21\u677F\u98CE\u683C",
|
|
415
|
+
options: [
|
|
416
|
+
{
|
|
417
|
+
value: "minimal",
|
|
418
|
+
label: "\u6781\u7B80",
|
|
419
|
+
hint: "\u51E0\u884C\u6838\u5FC3\u89C4\u5219, \u9002\u5408\u5C0F\u9879\u76EE"
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
value: "standard",
|
|
423
|
+
label: "\u6807\u51C6 (\u63A8\u8350)",
|
|
424
|
+
hint: "\u5E38\u7528\u5206\u533A\u6A21\u677F, \u9002\u5408\u5927\u591A\u6570\u9879\u76EE"
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
value: "detailed",
|
|
428
|
+
label: "\u8BE6\u7EC6",
|
|
429
|
+
hint: "\u5B8C\u6574\u5206\u533A\u542B\u67B6\u6784/\u6D4B\u8BD5/\u4F9D\u8D56, \u9002\u5408\u5927\u578B\u9879\u76EE"
|
|
430
|
+
}
|
|
431
|
+
],
|
|
432
|
+
initialValue: "standard"
|
|
433
|
+
});
|
|
434
|
+
if (p4.isCancel(style)) {
|
|
435
|
+
p4.cancel("\u5DF2\u53D6\u6D88\u64CD\u4F5C");
|
|
436
|
+
process.exit(0);
|
|
437
|
+
}
|
|
438
|
+
hintSelect();
|
|
439
|
+
const permission = await p4.select({
|
|
440
|
+
message: "Claude Code \u6743\u9650\u7EA7\u522B",
|
|
441
|
+
options: [
|
|
442
|
+
{
|
|
443
|
+
value: "strict",
|
|
444
|
+
label: "\u4E25\u683C",
|
|
445
|
+
hint: "\u53EA\u8BFB, \u7981\u6B62\u5199\u5165\u548C\u6267\u884C\u547D\u4EE4"
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
value: "normal",
|
|
449
|
+
label: "\u6807\u51C6 (\u63A8\u8350)",
|
|
450
|
+
hint: "\u8BFB\u53D6+\u641C\u7D22+\u7F51\u7EDC, \u5199\u5165\u9700\u786E\u8BA4"
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
value: "permissive",
|
|
454
|
+
label: "\u5BBD\u677E",
|
|
455
|
+
hint: "\u8BFB\u5199+\u6267\u884C+\u7F51\u7EDC, \u5168\u90E8\u81EA\u52A8\u5141\u8BB8"
|
|
456
|
+
}
|
|
457
|
+
],
|
|
458
|
+
initialValue: "normal"
|
|
459
|
+
});
|
|
460
|
+
if (p4.isCancel(permission)) {
|
|
461
|
+
p4.cancel("\u5DF2\u53D6\u6D88\u64CD\u4F5C");
|
|
462
|
+
process.exit(0);
|
|
463
|
+
}
|
|
464
|
+
return {
|
|
465
|
+
style,
|
|
466
|
+
permission
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
async function scaffold(targetDir, options) {
|
|
329
470
|
const s = p4.spinner();
|
|
330
471
|
s.start("\u6B63\u5728\u751F\u6210\u914D\u7F6E\u6587\u4EF6...");
|
|
331
472
|
const files = [];
|
|
473
|
+
const templates = {
|
|
474
|
+
minimal: CLAUDE_MD_MINIMAL,
|
|
475
|
+
standard: CLAUDE_MD_STANDARD,
|
|
476
|
+
detailed: CLAUDE_MD_DETAILED
|
|
477
|
+
};
|
|
332
478
|
const claudeMdPath = join2(targetDir, "CLAUDE.md");
|
|
333
|
-
const r1 = writeFileSafe(claudeMdPath,
|
|
479
|
+
const r1 = writeFileSafe(claudeMdPath, templates[options.style]);
|
|
334
480
|
files.push({ path: "CLAUDE.md", written: r1.written });
|
|
335
481
|
const claudeDir = join2(targetDir, ".claude");
|
|
336
482
|
ensureDir(claudeDir);
|
|
337
483
|
const settingsPath = join2(claudeDir, "settings.json");
|
|
338
|
-
const
|
|
484
|
+
const settingsData = {
|
|
485
|
+
permissions: PERMISSIONS[options.permission],
|
|
486
|
+
mcpServers: {}
|
|
487
|
+
};
|
|
488
|
+
const r2 = writeFileSafe(settingsPath, JSON.stringify(settingsData, null, 2) + "\n");
|
|
339
489
|
files.push({ path: ".claude/settings.json", written: r2.written });
|
|
340
490
|
const ignorePath = join2(targetDir, ".claudeignore");
|
|
341
|
-
const r3 = writeFileSafe(ignorePath,
|
|
491
|
+
const r3 = writeFileSafe(ignorePath, CLAUDEIGNORE);
|
|
342
492
|
files.push({ path: ".claudeignore", written: r3.written });
|
|
343
493
|
s.stop("\u914D\u7F6E\u6587\u4EF6\u751F\u6210\u5B8C\u6210");
|
|
494
|
+
const lines = [];
|
|
344
495
|
for (const f of files) {
|
|
345
496
|
if (f.written) {
|
|
346
|
-
|
|
497
|
+
lines.push(`${pc4.green("\u2713")} ${f.path}`);
|
|
347
498
|
} else {
|
|
348
|
-
|
|
499
|
+
lines.push(`${pc4.yellow("\u2192")} ${f.path} (\u5DF2\u5B58\u5728, \u8DF3\u8FC7)`);
|
|
349
500
|
}
|
|
350
501
|
}
|
|
502
|
+
p4.note(lines.join("\n"), "\u751F\u6210\u7684\u6587\u4EF6");
|
|
351
503
|
return { files };
|
|
352
504
|
}
|
|
353
505
|
|
|
354
506
|
// src/steps/install-mcp.ts
|
|
355
507
|
import * as p5 from "@clack/prompts";
|
|
356
|
-
import
|
|
508
|
+
import pc5 from "picocolors";
|
|
357
509
|
import { join as join3 } from "path";
|
|
358
510
|
import { homedir } from "os";
|
|
359
511
|
|
|
@@ -418,19 +570,23 @@ var MCP_SERVERS = [
|
|
|
418
570
|
];
|
|
419
571
|
|
|
420
572
|
// src/steps/install-mcp.ts
|
|
421
|
-
async function selectMcpServers() {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
573
|
+
async function selectMcpServers(totalSteps) {
|
|
574
|
+
stepHeader(4, totalSteps, "MCP Servers \u914D\u7F6E");
|
|
575
|
+
p5.note(
|
|
576
|
+
[
|
|
577
|
+
"MCP (Model Context Protocol) \u8BA9 Claude Code \u80FD\u8C03\u7528\u5916\u90E8\u5DE5\u5177",
|
|
578
|
+
"",
|
|
579
|
+
"\u4F8B\u5982: \u6D4F\u89C8\u5668\u64CD\u4F5C\u3001\u6587\u4EF6\u641C\u7D22\u3001\u7F51\u9875\u641C\u7D22\u3001\u6587\u6863\u67E5\u8BE2\u7B49",
|
|
580
|
+
"\u5B89\u88C5\u540E\u4F1A\u5199\u5165 .claude/settings.json, \u65E0\u9700\u5168\u5C40\u5B89\u88C5"
|
|
581
|
+
].join("\n"),
|
|
582
|
+
"\u4EC0\u4E48\u662F MCP Servers?"
|
|
583
|
+
);
|
|
584
|
+
hintMultiselect();
|
|
429
585
|
const selected = await p5.multiselect({
|
|
430
|
-
message: "\u9009\u62E9\u8981\
|
|
586
|
+
message: "\u9009\u62E9\u8981\u914D\u7F6E\u7684 MCP Servers",
|
|
431
587
|
options: MCP_SERVERS.map((s) => ({
|
|
432
588
|
value: s.name,
|
|
433
|
-
label: s.name
|
|
589
|
+
label: `${s.name}`,
|
|
434
590
|
hint: s.description
|
|
435
591
|
})),
|
|
436
592
|
initialValues: MCP_SERVERS.map((s) => s.name),
|
|
@@ -440,7 +596,35 @@ async function selectMcpServers() {
|
|
|
440
596
|
return [];
|
|
441
597
|
}
|
|
442
598
|
const names = selected;
|
|
443
|
-
|
|
599
|
+
const servers = MCP_SERVERS.filter((s) => names.includes(s.name));
|
|
600
|
+
const addCustom = await p5.confirm({
|
|
601
|
+
message: "\u662F\u5426\u6DFB\u52A0\u81EA\u5B9A\u4E49 MCP Server (npm \u5305)?",
|
|
602
|
+
initialValue: false
|
|
603
|
+
});
|
|
604
|
+
if (!p5.isCancel(addCustom) && addCustom) {
|
|
605
|
+
const customInput = await p5.text({
|
|
606
|
+
message: "\u8F93\u5165 npm \u5305\u540D (\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694)",
|
|
607
|
+
placeholder: "\u4F8B\u5982: @anthropic-ai/mcp-xxx, my-mcp-server",
|
|
608
|
+
validate: (val) => {
|
|
609
|
+
if (!val.trim()) return "\u8BF7\u8F93\u5165\u81F3\u5C11\u4E00\u4E2A\u5305\u540D";
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
if (!p5.isCancel(customInput) && customInput) {
|
|
613
|
+
const customPkgs = customInput.split(",").map((s) => s.trim()).filter(Boolean);
|
|
614
|
+
for (const pkg of customPkgs) {
|
|
615
|
+
const name = pkg.split("/").pop()?.replace(/^mcp-/, "") ?? pkg;
|
|
616
|
+
servers.push({
|
|
617
|
+
name,
|
|
618
|
+
package: pkg,
|
|
619
|
+
description: `\u81EA\u5B9A\u4E49: ${pkg}`,
|
|
620
|
+
scope: "user",
|
|
621
|
+
command: "npx",
|
|
622
|
+
args: ["-y", pkg]
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
return servers;
|
|
444
628
|
}
|
|
445
629
|
async function installMcp(servers) {
|
|
446
630
|
if (servers.length === 0) {
|
|
@@ -466,13 +650,9 @@ async function installMcp(servers) {
|
|
|
466
650
|
}
|
|
467
651
|
try {
|
|
468
652
|
mergeJsonFile(userSettingsPath, { mcpServers: mcpConfig });
|
|
469
|
-
for (const sv of userServers)
|
|
470
|
-
installed.push(sv.name);
|
|
471
|
-
}
|
|
653
|
+
for (const sv of userServers) installed.push(sv.name);
|
|
472
654
|
} catch {
|
|
473
|
-
for (const sv of userServers)
|
|
474
|
-
failed.push(sv.name);
|
|
475
|
-
}
|
|
655
|
+
for (const sv of userServers) failed.push(sv.name);
|
|
476
656
|
}
|
|
477
657
|
}
|
|
478
658
|
if (projectServers.length > 0) {
|
|
@@ -489,28 +669,28 @@ async function installMcp(servers) {
|
|
|
489
669
|
}
|
|
490
670
|
try {
|
|
491
671
|
mergeJsonFile(projectSettingsPath, { mcpServers: mcpConfig });
|
|
492
|
-
for (const sv of projectServers)
|
|
493
|
-
installed.push(sv.name);
|
|
494
|
-
}
|
|
672
|
+
for (const sv of projectServers) installed.push(sv.name);
|
|
495
673
|
} catch {
|
|
496
|
-
for (const sv of projectServers)
|
|
497
|
-
failed.push(sv.name);
|
|
498
|
-
}
|
|
674
|
+
for (const sv of projectServers) failed.push(sv.name);
|
|
499
675
|
}
|
|
500
676
|
}
|
|
501
677
|
s.stop("MCP Servers \u914D\u7F6E\u5B8C\u6210");
|
|
678
|
+
const lines = [];
|
|
502
679
|
for (const name of installed) {
|
|
503
|
-
|
|
680
|
+
lines.push(`${pc5.green("\u2713")} ${name}`);
|
|
504
681
|
}
|
|
505
682
|
for (const name of failed) {
|
|
506
|
-
|
|
683
|
+
lines.push(`${pc5.red("\u2717")} ${name} (\u914D\u7F6E\u5931\u8D25)`);
|
|
684
|
+
}
|
|
685
|
+
if (lines.length > 0) {
|
|
686
|
+
p5.note(lines.join("\n"), "MCP \u914D\u7F6E\u7ED3\u679C");
|
|
507
687
|
}
|
|
508
688
|
return { installed, failed };
|
|
509
689
|
}
|
|
510
690
|
|
|
511
691
|
// src/steps/install-skills.ts
|
|
512
692
|
import * as p6 from "@clack/prompts";
|
|
513
|
-
import
|
|
693
|
+
import pc6 from "picocolors";
|
|
514
694
|
|
|
515
695
|
// src/registry/skills.ts
|
|
516
696
|
var SKILLS = [
|
|
@@ -535,16 +715,20 @@ var SKILLS = [
|
|
|
535
715
|
];
|
|
536
716
|
|
|
537
717
|
// src/steps/install-skills.ts
|
|
538
|
-
async function selectSkills() {
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
718
|
+
async function selectSkills(totalSteps) {
|
|
719
|
+
stepHeader(5, totalSteps, "Skills / Plugins \u914D\u7F6E");
|
|
720
|
+
p6.note(
|
|
721
|
+
[
|
|
722
|
+
"Skills \u4E3A Claude Code \u6DFB\u52A0\u4E13\u4E1A\u5DE5\u4F5C\u6D41\u80FD\u529B",
|
|
723
|
+
"",
|
|
724
|
+
"\u4F8B\u5982: TDD\u5F00\u53D1\u6D41\u7A0B\u3001\u4EE3\u7801\u5BA1\u67E5\u3001\u5934\u8111\u98CE\u66B4\u3001\u89C4\u8303\u5316\u5F00\u53D1\u7B49",
|
|
725
|
+
"\u5B89\u88C5\u540E\u901A\u8FC7 /skill-name \u547D\u4EE4\u8C03\u7528"
|
|
726
|
+
].join("\n"),
|
|
727
|
+
"\u4EC0\u4E48\u662F Skills?"
|
|
728
|
+
);
|
|
729
|
+
hintMultiselect();
|
|
546
730
|
const selected = await p6.multiselect({
|
|
547
|
-
message: "\u9009\u62E9\u8981\u5B89\u88C5\u7684 Skills
|
|
731
|
+
message: "\u9009\u62E9\u8981\u5B89\u88C5\u7684 Skills",
|
|
548
732
|
options: SKILLS.map((s) => ({
|
|
549
733
|
value: s.name,
|
|
550
734
|
label: s.name,
|
|
@@ -556,27 +740,26 @@ async function selectSkills() {
|
|
|
556
740
|
if (p6.isCancel(selected)) {
|
|
557
741
|
return [];
|
|
558
742
|
}
|
|
559
|
-
|
|
560
|
-
return SKILLS.filter((s) => names.includes(s.name));
|
|
743
|
+
return SKILLS.filter((s) => selected.includes(s.name));
|
|
561
744
|
}
|
|
562
745
|
async function installSkills(skills) {
|
|
563
746
|
if (skills.length === 0) {
|
|
564
747
|
return { installed: [], failed: [] };
|
|
565
748
|
}
|
|
566
|
-
const s = p6.spinner();
|
|
567
749
|
const installed = [];
|
|
568
750
|
const failed = [];
|
|
569
751
|
for (const skill of skills) {
|
|
752
|
+
const s = p6.spinner();
|
|
570
753
|
s.start(`\u6B63\u5728\u5B89\u88C5 ${skill.name}...`);
|
|
571
754
|
const [cmd, ...args] = skill.installCmd;
|
|
572
755
|
const result = await run(cmd, args);
|
|
573
756
|
if (result.exitCode === 0) {
|
|
574
757
|
installed.push(skill.name);
|
|
575
|
-
s.stop(`${skill.name} \u5B89\u88C5\u5B8C\u6210`);
|
|
758
|
+
s.stop(`${pc6.green("\u2713")} ${skill.name} \u5B89\u88C5\u5B8C\u6210`);
|
|
576
759
|
} else {
|
|
577
760
|
failed.push(skill.name);
|
|
578
|
-
s.stop(`${skill.name} \u5B89\u88C5\u5931\u8D25`);
|
|
579
|
-
p6.log.warning(`
|
|
761
|
+
s.stop(`${pc6.red("\u2717")} ${skill.name} \u5B89\u88C5\u5931\u8D25`);
|
|
762
|
+
p6.log.warning(` \u624B\u52A8\u5B89\u88C5: ${skill.installCmd.join(" ")}`);
|
|
580
763
|
}
|
|
581
764
|
}
|
|
582
765
|
return { installed, failed };
|
|
@@ -584,20 +767,24 @@ async function installSkills(skills) {
|
|
|
584
767
|
|
|
585
768
|
// src/steps/clean-env.ts
|
|
586
769
|
import * as p7 from "@clack/prompts";
|
|
587
|
-
import
|
|
588
|
-
async function cleanEnv(sensitiveVars) {
|
|
770
|
+
import pc7 from "picocolors";
|
|
771
|
+
async function cleanEnv(sensitiveVars, totalSteps) {
|
|
589
772
|
if (sensitiveVars.length === 0) {
|
|
590
773
|
return { removed: [], skipped: [] };
|
|
591
774
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
775
|
+
stepHeader(6, totalSteps, "\u73AF\u5883\u53D8\u91CF\u6E05\u7406");
|
|
776
|
+
p7.note(
|
|
777
|
+
[
|
|
778
|
+
"\u4EE5\u4E0B\u73AF\u5883\u53D8\u91CF\u5305\u542B\u654F\u611F\u4FE1\u606F (API\u5BC6\u94A5/Token)",
|
|
779
|
+
"\u5C06\u5B83\u4EEC\u5B58\u50A8\u5728\u7CFB\u7EDF\u73AF\u5883\u53D8\u91CF\u4E2D\u5B58\u5728\u6CC4\u9732\u98CE\u9669",
|
|
780
|
+
"",
|
|
781
|
+
"\u5EFA\u8BAE: \u79FB\u9664\u540E\u6539\u7528 Claude Code \u5185\u7F6E\u7684\u5BC6\u94A5\u7BA1\u7406"
|
|
782
|
+
].join("\n"),
|
|
783
|
+
"\u4E3A\u4EC0\u4E48\u8981\u6E05\u7406?"
|
|
784
|
+
);
|
|
785
|
+
hintMultiselect();
|
|
599
786
|
const selected = await p7.multiselect({
|
|
600
|
-
message: "\u9009\u62E9\u8981\u79FB\u9664\u7684\
|
|
787
|
+
message: "\u9009\u62E9\u8981\u79FB\u9664\u7684\u73AF\u5883\u53D8\u91CF (\u4E0D\u9009\u5219\u5168\u90E8\u4FDD\u7559)",
|
|
601
788
|
options: sensitiveVars.map((v) => ({
|
|
602
789
|
value: v.key,
|
|
603
790
|
label: v.key,
|
|
@@ -607,6 +794,7 @@ async function cleanEnv(sensitiveVars) {
|
|
|
607
794
|
required: false
|
|
608
795
|
});
|
|
609
796
|
if (p7.isCancel(selected) || selected.length === 0) {
|
|
797
|
+
p7.log.info("\u8DF3\u8FC7\u73AF\u5883\u53D8\u91CF\u6E05\u7406");
|
|
610
798
|
return { removed: [], skipped: sensitiveVars.map((v) => v.key) };
|
|
611
799
|
}
|
|
612
800
|
const toRemove = selected;
|
|
@@ -623,18 +811,23 @@ async function cleanEnv(sensitiveVars) {
|
|
|
623
811
|
}
|
|
624
812
|
}
|
|
625
813
|
s.stop("\u73AF\u5883\u53D8\u91CF\u6E05\u7406\u5B8C\u6210");
|
|
814
|
+
const lines = [];
|
|
626
815
|
for (const key of removed) {
|
|
627
|
-
|
|
816
|
+
lines.push(`${pc7.green("\u2713")} ${key} \u5DF2\u79FB\u9664`);
|
|
628
817
|
}
|
|
629
818
|
for (const key of skipped) {
|
|
630
|
-
|
|
819
|
+
lines.push(`${pc7.yellow("!")} ${key} \u9700\u624B\u52A8\u79FB\u9664`);
|
|
631
820
|
}
|
|
632
821
|
if (skipped.length > 0 && process.platform !== "win32") {
|
|
633
|
-
|
|
822
|
+
lines.push("");
|
|
823
|
+
lines.push(pc7.dim("\u624B\u52A8\u79FB\u9664\u65B9\u6CD5:"));
|
|
634
824
|
for (const key of skipped) {
|
|
635
|
-
|
|
825
|
+
lines.push(pc7.dim(` \u4ECE ~/.bashrc \u6216 ~/.zshrc \u5220\u9664: export ${key}=...`));
|
|
636
826
|
}
|
|
637
827
|
}
|
|
828
|
+
if (lines.length > 0) {
|
|
829
|
+
p7.note(lines.join("\n"), "\u6E05\u7406\u7ED3\u679C");
|
|
830
|
+
}
|
|
638
831
|
return { removed, skipped };
|
|
639
832
|
}
|
|
640
833
|
async function removeEnvVar(key) {
|
|
@@ -655,46 +848,79 @@ function maskValue2(val) {
|
|
|
655
848
|
}
|
|
656
849
|
|
|
657
850
|
// src/cli.ts
|
|
851
|
+
var TOTAL_STEPS = 7;
|
|
658
852
|
async function runCli() {
|
|
659
853
|
const results = [];
|
|
660
|
-
const env = await detect();
|
|
661
|
-
const components = await selectComponents(env);
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
if (components.installCli && !env.claudeInstalled) actions.push("\u5B89\u88C5 Claude Code CLI");
|
|
666
|
-
if (components.scaffold) actions.push("\u751F\u6210 CLAUDE.md + .claude/ \u914D\u7F6E");
|
|
667
|
-
if (mcpServers.length > 0) actions.push(`\u5B89\u88C5 ${mcpServers.length} \u4E2A MCP Servers`);
|
|
668
|
-
if (skills.length > 0) actions.push(`\u5B89\u88C5 ${skills.length} \u4E2A Skills`);
|
|
669
|
-
if (components.cleanEnv) actions.push(`\u6E05\u7406 ${env.sensitiveEnvVars.length} \u4E2A\u654F\u611F\u73AF\u5883\u53D8\u91CF`);
|
|
670
|
-
if (actions.length === 0) {
|
|
671
|
-
p8.log.info("\u6CA1\u6709\u9009\u62E9\u4EFB\u4F55\u64CD\u4F5C\uFF0C\u9000\u51FA");
|
|
672
|
-
return;
|
|
854
|
+
const env = await detect(TOTAL_STEPS);
|
|
855
|
+
const components = await selectComponents(env, TOTAL_STEPS);
|
|
856
|
+
let scaffoldOpts = null;
|
|
857
|
+
if (components.scaffold) {
|
|
858
|
+
scaffoldOpts = await scaffoldConfig(TOTAL_STEPS);
|
|
673
859
|
}
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
860
|
+
let mcpServers = [];
|
|
861
|
+
if (components.installMcp) {
|
|
862
|
+
mcpServers = await selectMcpServers(TOTAL_STEPS);
|
|
863
|
+
}
|
|
864
|
+
let skills = [];
|
|
865
|
+
if (components.installSkills) {
|
|
866
|
+
skills = await selectSkills(TOTAL_STEPS);
|
|
677
867
|
}
|
|
678
868
|
console.log();
|
|
679
|
-
console.log(
|
|
869
|
+
console.log(
|
|
870
|
+
pc8.cyan(" \u2501\u2501\u2501 ") + pc8.bold(`\u6B65\u9AA4 6/${TOTAL_STEPS}`) + pc8.cyan(" \u2501 ") + pc8.white("\u786E\u8BA4\u6267\u884C") + pc8.cyan(" \u2501\u2501\u2501")
|
|
871
|
+
);
|
|
680
872
|
console.log();
|
|
873
|
+
const actionLines = [];
|
|
874
|
+
let actionNum = 1;
|
|
875
|
+
if (components.installCli && !env.claudeInstalled) {
|
|
876
|
+
actionLines.push(`${actionNum++}. \u5B89\u88C5 Claude Code CLI`);
|
|
877
|
+
}
|
|
878
|
+
if (components.scaffold && scaffoldOpts) {
|
|
879
|
+
actionLines.push(`${actionNum++}. \u751F\u6210\u914D\u7F6E\u6587\u4EF6 (${scaffoldOpts.style}\u6A21\u677F, ${scaffoldOpts.permission}\u6743\u9650)`);
|
|
880
|
+
}
|
|
881
|
+
if (mcpServers.length > 0) {
|
|
882
|
+
actionLines.push(`${actionNum++}. \u914D\u7F6E ${mcpServers.length} \u4E2A MCP Servers`);
|
|
883
|
+
for (const s of mcpServers) {
|
|
884
|
+
actionLines.push(` \xB7 ${s.name} - ${s.description}`);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
if (skills.length > 0) {
|
|
888
|
+
actionLines.push(`${actionNum++}. \u5B89\u88C5 ${skills.length} \u4E2A Skills`);
|
|
889
|
+
for (const s of skills) {
|
|
890
|
+
actionLines.push(` \xB7 ${s.name}`);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
if (components.cleanEnv && env.sensitiveEnvVars.length > 0) {
|
|
894
|
+
actionLines.push(`${actionNum++}. \u6E05\u7406 ${env.sensitiveEnvVars.length} \u4E2A\u654F\u611F\u73AF\u5883\u53D8\u91CF`);
|
|
895
|
+
}
|
|
896
|
+
if (actionLines.length === 0) {
|
|
897
|
+
p8.log.info("\u6CA1\u6709\u9009\u62E9\u4EFB\u4F55\u64CD\u4F5C");
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
p8.note(actionLines.join("\n"), "\u5373\u5C06\u6267\u884C\u4EE5\u4E0B\u64CD\u4F5C");
|
|
901
|
+
hintConfirm();
|
|
681
902
|
const confirmed = await p8.confirm({
|
|
682
|
-
message: "\u786E\u8BA4\u6267\u884C\
|
|
903
|
+
message: "\u786E\u8BA4\u6267\u884C\u4EE5\u4E0A\u6240\u6709\u64CD\u4F5C?",
|
|
683
904
|
initialValue: true
|
|
684
905
|
});
|
|
685
906
|
if (p8.isCancel(confirmed) || !confirmed) {
|
|
686
|
-
p8.cancel("\u5DF2\u53D6\u6D88");
|
|
907
|
+
p8.cancel("\u5DF2\u53D6\u6D88\u64CD\u4F5C");
|
|
687
908
|
process.exit(0);
|
|
688
909
|
}
|
|
910
|
+
console.log();
|
|
911
|
+
console.log(
|
|
912
|
+
pc8.cyan(" \u2501\u2501\u2501 ") + pc8.bold(`\u6B65\u9AA4 7/${TOTAL_STEPS}`) + pc8.cyan(" \u2501 ") + pc8.white("\u6267\u884C\u5B89\u88C5") + pc8.cyan(" \u2501\u2501\u2501")
|
|
913
|
+
);
|
|
914
|
+
console.log();
|
|
689
915
|
if (components.installCli) {
|
|
690
916
|
const r = await installCli(env.claudeInstalled);
|
|
691
917
|
results.push({
|
|
692
|
-
label: r.skipped ? "Claude Code CLI (\u5DF2\u5B89\u88C5)" : "Claude Code CLI
|
|
918
|
+
label: r.skipped ? "Claude Code CLI (\u5DF2\u5B89\u88C5)" : "Claude Code CLI",
|
|
693
919
|
ok: r.success
|
|
694
920
|
});
|
|
695
921
|
}
|
|
696
|
-
if (components.scaffold) {
|
|
697
|
-
|
|
922
|
+
if (components.scaffold && scaffoldOpts) {
|
|
923
|
+
await scaffold(process.cwd(), scaffoldOpts);
|
|
698
924
|
results.push({ label: "\u914D\u7F6E\u6587\u4EF6\u751F\u6210", ok: true });
|
|
699
925
|
}
|
|
700
926
|
if (mcpServers.length > 0) {
|
|
@@ -716,7 +942,7 @@ async function runCli() {
|
|
|
716
942
|
}
|
|
717
943
|
}
|
|
718
944
|
if (components.cleanEnv) {
|
|
719
|
-
const r = await cleanEnv(env.sensitiveEnvVars);
|
|
945
|
+
const r = await cleanEnv(env.sensitiveEnvVars, TOTAL_STEPS);
|
|
720
946
|
for (const key of r.removed) {
|
|
721
947
|
results.push({ label: `${key} \u5DF2\u79FB\u9664`, ok: true });
|
|
722
948
|
}
|
|
@@ -729,7 +955,8 @@ async function runCli() {
|
|
|
729
955
|
|
|
730
956
|
// src/index.ts
|
|
731
957
|
import * as p9 from "@clack/prompts";
|
|
732
|
-
var
|
|
958
|
+
var require2 = createRequire(import.meta.url);
|
|
959
|
+
var { version: VERSION } = require2("../package.json");
|
|
733
960
|
async function main() {
|
|
734
961
|
banner(VERSION);
|
|
735
962
|
p9.intro("\u5F00\u59CB\u914D\u7F6E Claude Code \u73AF\u5883");
|