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.
Files changed (2) hide show
  1. package/dist/index.js +380 -153
  2. 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 \u2502"));
17
- console.log(pc.cyan(" \u2502") + " \u{1F916} ccbot - Claude Code \u73AF\u5883\u914D\u7F6E " + pc.cyan("\u2502"));
18
- console.log(pc.cyan(" \u2502") + pc.dim(` \u4E00\u952E\u914D\u7F6E\u5DE5\u5177 v${version}`) + " " + pc.cyan("\u2502"));
19
- console.log(pc.cyan(" \u2502 \u2502"));
20
- 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\u256F"));
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") + pc.bold(" \u5B89\u88C5\u5B8C\u6210\uFF01") + " " + pc.cyan("\u2502"));
27
- 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\u256F"));
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.info("\u4E0B\u4E00\u6B65\uFF1A");
38
- log.dim("1. \u8FD0\u884C claude \u542F\u52A8 Claude Code");
39
- log.dim("2. \u7F16\u8F91 CLAUDE.md \u81EA\u5B9A\u4E49\u9879\u76EE\u6307\u4EE4");
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 pc7 from "picocolors";
61
+ import pc8 from "picocolors";
46
62
 
47
63
  // src/steps/detect.ts
48
64
  import * as p from "@clack/prompts";
49
- import pc2 from "picocolors";
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\u68C0\u6D4B\u73AF\u5883...");
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\u68C0\u6D4B\u5B8C\u6210");
132
- p.log.success(`Node.js ${nodeVersion}`);
133
- p.log.success(`npm v${npmVersion}`);
134
- p.log.success(os);
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
- p.log.success(`Claude Code CLI ${claudeVersion}`);
182
+ lines.push(`${pc3.green("\u2713")} Claude CLI ${claudeVersion}`);
137
183
  } else {
138
- p.log.warning("Claude Code CLI \u672A\u5B89\u88C5");
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
- p.log.warning("\u68C0\u6D4B\u5230\u654F\u611F\u73AF\u5883\u53D8\u91CF:");
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
- console.log(pc2.yellow(` ${key}=${maskValue(value)}`));
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
- import pc3 from "picocolors";
160
- function printMultiselectHint() {
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 \u5B89\u88C5",
174
- hint: env.claudeInstalled ? "\u5DF2\u5B89\u88C5\uFF0C\u5C06\u8DF3\u8FC7" : "\u672A\u5B89\u88C5"
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
- { value: "scaffold", label: "\u9879\u76EE\u914D\u7F6E\u811A\u624B\u67B6", hint: "CLAUDE.md + .claude/ \u914D\u7F6E" },
177
- { value: "installMcp", label: "MCP Servers", hint: "\u4ECE\u9884\u8BBE\u5217\u8868\u9009\u62E9\u5B89\u88C5" },
178
- { value: "installSkills", label: "Skills / Plugins", hint: "\u589E\u5F3A Claude Code \u80FD\u529B" }
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: `\u68C0\u6D4B\u5230 ${env.sensitiveEnvVars.length} \u4E2A\u654F\u611F\u53D8\u91CF`
235
+ hint: `\u53D1\u73B0 ${env.sensitiveEnvVars.length} \u4E2A\u654F\u611F\u53D8\u91CF, \u5EFA\u8BAE\u79FB\u9664`
185
236
  });
186
237
  }
187
- printMultiselectHint();
238
+ hintMultiselect();
188
239
  const selected = await p2.multiselect({
189
- message: "\u9009\u62E9\u8981\u5B89\u88C5\u7684\u7EC4\u4EF6 (\u7A7A\u683C\u5207\u6362, \u56DE\u8F66\u786E\u8BA4)",
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 CLAUDE_MD_TEMPLATE = `# Project Instructions
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
- <!-- \u5728\u6B64\u7F16\u5199\u9879\u76EE\u7EA7 Claude Code \u6307\u4EE4 -->
352
+ ## Key Files
353
+ <!-- List important file paths here -->
287
354
 
288
- ## \u9879\u76EE\u6982\u8FF0
355
+ ## Notes
356
+ <!-- Special considerations -->
357
+ `;
358
+ var CLAUDE_MD_DETAILED = `# Project Instructions
289
359
 
290
- <!-- \u63CF\u8FF0\u9879\u76EE\u7684\u76EE\u7684\u548C\u6280\u672F\u6808 -->
360
+ ## Project Overview
361
+ <!-- Describe the project purpose, goals, and tech stack in detail -->
291
362
 
292
- ## \u7F16\u7801\u89C4\u8303
363
+ ## Architecture
364
+ <!-- Describe the high-level architecture and key design decisions -->
293
365
 
294
- - \u4F7F\u7528 TypeScript
295
- - \u9075\u5FAA\u9879\u76EE\u73B0\u6709\u4EE3\u7801\u98CE\u683C
296
- - \u5148\u8BFB\u540E\u5199\uFF0C\u7406\u89E3\u4E0A\u4E0B\u6587\u518D\u4FEE\u6539
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
- ## \u91CD\u8981\u6587\u4EF6
373
+ ## Key Files
374
+ <!-- List important file paths and their purposes -->
299
375
 
300
- <!-- \u5217\u51FA\u5173\u952E\u6587\u4EF6\u8DEF\u5F84 -->
376
+ ## Dependencies
377
+ <!-- List key dependencies and their roles -->
301
378
 
302
- ## \u6CE8\u610F\u4E8B\u9879
379
+ ## Testing
380
+ <!-- Describe testing approach and how to run tests -->
303
381
 
304
- <!-- \u5217\u51FA\u9700\u8981\u7279\u522B\u6CE8\u610F\u7684\u4E8B\u9879 -->
382
+ ## Notes
383
+ <!-- Special considerations, gotchas, or important context -->
305
384
  `;
306
- var SETTINGS_TEMPLATE = {
307
- permissions: {
308
- allow: [
309
- "Read",
310
- "Glob",
311
- "Grep",
312
- "WebFetch",
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
- mcpServers: {}
394
+ permissive: {
395
+ allow: ["Read", "Glob", "Grep", "Write", "Edit", "Bash", "WebFetch", "WebSearch"],
396
+ deny: []
397
+ }
318
398
  };
319
- var CLAUDEIGNORE_TEMPLATE = `# \u5FFD\u7565\u6587\u4EF6
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 scaffold(targetDir) {
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, CLAUDE_MD_TEMPLATE);
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 r2 = writeFileSafe(settingsPath, JSON.stringify(SETTINGS_TEMPLATE, null, 2) + "\n");
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, CLAUDEIGNORE_TEMPLATE);
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
- p4.log.success(`${f.path} \u5DF2\u751F\u6210`);
497
+ lines.push(`${pc4.green("\u2713")} ${f.path}`);
347
498
  } else {
348
- p4.log.info(`${f.path} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7`);
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 pc4 from "picocolors";
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
- console.log();
423
- console.log(pc4.dim(" \u64CD\u4F5C\u6307\u5357:"));
424
- console.log(pc4.dim(" \u2191/\u2193 \u4E0A\u4E0B\u79FB\u52A8\u5149\u6807"));
425
- console.log(pc4.dim(" \u7A7A\u683C \u9009\u4E2D/\u53D6\u6D88\u9009\u4E2D\u5F53\u524D\u9879"));
426
- console.log(pc4.dim(" a \u5168\u9009/\u5168\u4E0D\u9009"));
427
- console.log(pc4.dim(" \u56DE\u8F66 \u786E\u8BA4\u9009\u62E9"));
428
- console.log();
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\u5B89\u88C5\u7684 MCP Servers (\u7A7A\u683C\u5207\u6362, \u56DE\u8F66\u786E\u8BA4)",
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
- return MCP_SERVERS.filter((s) => names.includes(s.name));
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
- p5.log.success(`${name} MCP \u5DF2\u914D\u7F6E`);
680
+ lines.push(`${pc5.green("\u2713")} ${name}`);
504
681
  }
505
682
  for (const name of failed) {
506
- p5.log.error(`${name} MCP \u914D\u7F6E\u5931\u8D25`);
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 pc5 from "picocolors";
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
- console.log();
540
- console.log(pc5.dim(" \u64CD\u4F5C\u6307\u5357:"));
541
- console.log(pc5.dim(" \u2191/\u2193 \u4E0A\u4E0B\u79FB\u52A8\u5149\u6807"));
542
- console.log(pc5.dim(" \u7A7A\u683C \u9009\u4E2D/\u53D6\u6D88\u9009\u4E2D\u5F53\u524D\u9879"));
543
- console.log(pc5.dim(" a \u5168\u9009/\u5168\u4E0D\u9009"));
544
- console.log(pc5.dim(" \u56DE\u8F66 \u786E\u8BA4\u9009\u62E9"));
545
- console.log();
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 / Plugins (\u7A7A\u683C\u5207\u6362, \u56DE\u8F66\u786E\u8BA4)",
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
- const names = selected;
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(` ${result.stderr || "\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u624B\u52A8\u5B89\u88C5"}`);
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 pc6 from "picocolors";
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
- console.log();
593
- console.log(pc6.dim(" \u64CD\u4F5C\u6307\u5357:"));
594
- console.log(pc6.dim(" \u2191/\u2193 \u4E0A\u4E0B\u79FB\u52A8\u5149\u6807"));
595
- console.log(pc6.dim(" \u7A7A\u683C \u9009\u4E2D/\u53D6\u6D88\u9009\u4E2D\u5F53\u524D\u9879"));
596
- console.log(pc6.dim(" a \u5168\u9009/\u5168\u4E0D\u9009"));
597
- console.log(pc6.dim(" \u56DE\u8F66 \u786E\u8BA4\u9009\u62E9"));
598
- console.log();
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\u654F\u611F\u73AF\u5883\u53D8\u91CF (\u7A7A\u683C\u5207\u6362, \u56DE\u8F66\u786E\u8BA4)",
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
- p7.log.success(`${key} \u5DF2\u79FB\u9664`);
816
+ lines.push(`${pc7.green("\u2713")} ${key} \u5DF2\u79FB\u9664`);
628
817
  }
629
818
  for (const key of skipped) {
630
- p7.log.warning(`${key} \u79FB\u9664\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u5904\u7406`);
819
+ lines.push(`${pc7.yellow("!")} ${key} \u9700\u624B\u52A8\u79FB\u9664`);
631
820
  }
632
821
  if (skipped.length > 0 && process.platform !== "win32") {
633
- p7.log.info("\u624B\u52A8\u79FB\u9664\u65B9\u6CD5:");
822
+ lines.push("");
823
+ lines.push(pc7.dim("\u624B\u52A8\u79FB\u9664\u65B9\u6CD5:"));
634
824
  for (const key of skipped) {
635
- console.log(pc6.dim(` \u4ECE ~/.bashrc \u6216 ~/.zshrc \u4E2D\u5220\u9664: export ${key}=...`));
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
- const mcpServers = components.installMcp ? await selectMcpServers() : [];
663
- const skills = components.installSkills ? await selectSkills() : [];
664
- const actions = [];
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
- p8.log.info("\u5373\u5C06\u6267\u884C\u4EE5\u4E0B\u64CD\u4F5C:");
675
- for (let i = 0; i < actions.length; i++) {
676
- console.log(pc7.dim(` ${i + 1}. ${actions[i]}`));
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(pc7.dim(" Y/\u56DE\u8F66 \u786E\u8BA4 | N \u53D6\u6D88"));
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\uFF1F",
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 \u5B89\u88C5",
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
- const r = await scaffold(process.cwd());
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 VERSION = "1.0.0";
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");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccbot-cli",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Claude Code 环境一键配置工具",
5
5
  "type": "module",
6
6
  "bin": {