@robot-admin/git-standards 1.0.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.cjs ADDED
@@ -0,0 +1,1280 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ createLintStagedConfig: () => createLintStagedConfig,
34
+ detectPackageManager: () => detectPackageManager,
35
+ doctor: () => doctor,
36
+ fileExists: () => fileExists,
37
+ generateLintStagedConfig: () => generateLintStagedConfig,
38
+ getExecCommand: () => getExecCommand,
39
+ getInstallCommand: () => getInstallCommand,
40
+ getPackageManagerName: () => getPackageManagerName,
41
+ init: () => init,
42
+ initGitRepository: () => initGitRepository,
43
+ isGitRepository: () => isGitRepository,
44
+ readFileContent: () => readFileContent,
45
+ readJsonFile: () => readJsonFile,
46
+ updatePackageJson: () => updatePackageJson,
47
+ writeFileContent: () => writeFileContent,
48
+ writeJsonFile: () => writeJsonFile
49
+ });
50
+ module.exports = __toCommonJS(index_exports);
51
+
52
+ // src/configs/lint-staged.ts
53
+ function createLintStagedConfig(options = {}) {
54
+ const codePattern = options.filePatterns?.code || "src/**/*.{js,jsx,ts,tsx,vue}";
55
+ const markupPattern = options.filePatterns?.markup || "*.{json,md,yml,yaml}";
56
+ const codeCommands = [];
57
+ if (options.oxlint !== false) {
58
+ codeCommands.push("oxlint --max-warnings 0 --deny-warnings");
59
+ }
60
+ if (options.eslint !== false) {
61
+ codeCommands.push("eslint --fix --no-cache");
62
+ }
63
+ if (options.prettier !== false) {
64
+ codeCommands.push("prettier --write");
65
+ }
66
+ const config = {};
67
+ if (codeCommands.length > 0) {
68
+ config[codePattern] = codeCommands;
69
+ }
70
+ if (options.prettier !== false) {
71
+ config[markupPattern] = ["prettier --write"];
72
+ }
73
+ return config;
74
+ }
75
+ function generateLintStagedConfig(options = {}) {
76
+ return createLintStagedConfig(options);
77
+ }
78
+
79
+ // src/cli/init.ts
80
+ var import_node_path4 = require("path");
81
+ var import_node_fs4 = require("fs");
82
+ var import_chalk = __toESM(require("chalk"), 1);
83
+ var import_ora = __toESM(require("ora"), 1);
84
+ var import_execa2 = require("execa");
85
+
86
+ // src/utils/package-manager.ts
87
+ var import_node_fs = require("fs");
88
+ var import_node_path = require("path");
89
+ async function detectPackageManager(cwd = process.cwd()) {
90
+ if ((0, import_node_fs.existsSync)((0, import_node_path.resolve)(cwd, "bun.lockb")) || (0, import_node_fs.existsSync)((0, import_node_path.resolve)(cwd, "bun.lock"))) {
91
+ return "bun";
92
+ }
93
+ if ((0, import_node_fs.existsSync)((0, import_node_path.resolve)(cwd, "pnpm-lock.yaml"))) {
94
+ return "pnpm";
95
+ }
96
+ if ((0, import_node_fs.existsSync)((0, import_node_path.resolve)(cwd, "yarn.lock"))) {
97
+ return "yarn";
98
+ }
99
+ if ((0, import_node_fs.existsSync)((0, import_node_path.resolve)(cwd, "package-lock.json"))) {
100
+ return "npm";
101
+ }
102
+ return "npm";
103
+ }
104
+ function getInstallCommand(pm) {
105
+ const commands = {
106
+ npm: "npm install --save-dev",
107
+ yarn: "yarn add --dev",
108
+ pnpm: "pnpm add -D",
109
+ bun: "bun add --dev"
110
+ };
111
+ return commands[pm];
112
+ }
113
+ function getExecCommand(pm) {
114
+ const commands = {
115
+ npm: "npx --no",
116
+ yarn: "yarn",
117
+ pnpm: "pnpm dlx",
118
+ bun: "bunx"
119
+ };
120
+ return commands[pm];
121
+ }
122
+ function getPackageManagerName(pm) {
123
+ const names = {
124
+ npm: "npm",
125
+ yarn: "Yarn",
126
+ pnpm: "pnpm",
127
+ bun: "Bun"
128
+ };
129
+ return names[pm];
130
+ }
131
+
132
+ // src/utils/git.ts
133
+ var import_node_fs2 = require("fs");
134
+ var import_node_path2 = require("path");
135
+ var import_execa = require("execa");
136
+ function isGitRepository(cwd = process.cwd()) {
137
+ return (0, import_node_fs2.existsSync)((0, import_node_path2.resolve)(cwd, ".git"));
138
+ }
139
+ async function initGitRepository(cwd = process.cwd()) {
140
+ if (!isGitRepository(cwd)) {
141
+ await (0, import_execa.execa)("git", ["init"], { cwd });
142
+ }
143
+ }
144
+
145
+ // src/utils/file.ts
146
+ var import_node_fs3 = require("fs");
147
+ var import_promises = require("fs/promises");
148
+ var import_node_path3 = require("path");
149
+ function fileExists(filePath) {
150
+ return (0, import_node_fs3.existsSync)(filePath);
151
+ }
152
+ async function readFileContent(filePath) {
153
+ return await (0, import_promises.readFile)(filePath, "utf-8");
154
+ }
155
+ async function writeFileContent(filePath, content) {
156
+ const dir = (0, import_node_path3.dirname)(filePath);
157
+ if (!(0, import_node_fs3.existsSync)(dir)) {
158
+ await (0, import_promises.mkdir)(dir, { recursive: true });
159
+ }
160
+ await (0, import_promises.writeFile)(filePath, content, "utf-8");
161
+ }
162
+ async function readJsonFile(filePath) {
163
+ const content = await readFileContent(filePath);
164
+ return JSON.parse(content);
165
+ }
166
+ async function writeJsonFile(filePath, data, pretty = true) {
167
+ const content = pretty ? JSON.stringify(data, null, 2) + "\n" : JSON.stringify(data);
168
+ await writeFileContent(filePath, content);
169
+ }
170
+ async function updatePackageJson(updates, cwd = process.cwd()) {
171
+ const packageJsonPath = (0, import_node_path3.resolve)(cwd, "package.json");
172
+ const packageJson = await readJsonFile(packageJsonPath);
173
+ const updated = { ...packageJson, ...updates };
174
+ await writeJsonFile(packageJsonPath, updated);
175
+ }
176
+
177
+ // src/cli/init.ts
178
+ var BRAND = "#7C3AED";
179
+ var S = {
180
+ LOGO: import_chalk.default.hex(BRAND).bold("[RS]"),
181
+ OK: import_chalk.default.green("\u2714"),
182
+ FAIL: import_chalk.default.red("\u2716"),
183
+ WARN: import_chalk.default.yellow("\u25B2"),
184
+ STEP: import_chalk.default.hex(BRAND)("\u25C6"),
185
+ ARROW: import_chalk.default.cyan("\u25B8"),
186
+ DOT: import_chalk.default.gray("\u25CF"),
187
+ INFO: import_chalk.default.blue("\u2139"),
188
+ LINE: import_chalk.default.gray("\u2500".repeat(48))
189
+ };
190
+ var PRESETS = {
191
+ minimal: {
192
+ name: "\u6781\u7B80\u6A21\u5F0F",
193
+ desc: "\u4EC5 Git \u63D0\u4EA4\u89C4\u8303 (Commitizen + Commitlint)",
194
+ features: {
195
+ eslint: false,
196
+ lintStaged: false,
197
+ prettier: false,
198
+ oxlint: false,
199
+ editorconfig: false
200
+ }
201
+ },
202
+ standard: {
203
+ name: "\u6807\u51C6\u6A21\u5F0F",
204
+ desc: "\u63D0\u4EA4\u89C4\u8303 + \u4EE3\u7801\u8D28\u91CF\u68C0\u67E5 (+ ESLint + lint-staged)",
205
+ features: {
206
+ eslint: true,
207
+ lintStaged: true,
208
+ prettier: false,
209
+ oxlint: false,
210
+ editorconfig: true
211
+ }
212
+ },
213
+ full: {
214
+ name: "\u5B8C\u6574\u6A21\u5F0F",
215
+ desc: "\u5168\u90E8\u5DE5\u5177\u94FE (+ Prettier + Oxlint + EditorConfig)",
216
+ features: {
217
+ eslint: true,
218
+ lintStaged: true,
219
+ prettier: true,
220
+ oxlint: true,
221
+ editorconfig: true
222
+ }
223
+ }
224
+ };
225
+ async function init(options = {}) {
226
+ const cwd = options.cwd || process.cwd();
227
+ printBanner();
228
+ console.log(` ${S.STEP} ${import_chalk.default.bold("\u73AF\u5883\u68C0\u6D4B")}`);
229
+ console.log();
230
+ if (!isGitRepository(cwd)) {
231
+ const spinner = (0, import_ora.default)({
232
+ text: import_chalk.default.gray("\u521D\u59CB\u5316 Git \u4ED3\u5E93..."),
233
+ prefixText: " ",
234
+ spinner: "dots"
235
+ }).start();
236
+ await initGitRepository(cwd);
237
+ spinner.succeed(import_chalk.default.white("Git \u4ED3\u5E93\u521D\u59CB\u5316\u5B8C\u6210"));
238
+ } else {
239
+ console.log(` ${S.OK} Git \u4ED3\u5E93\u5DF2\u5C31\u7EEA`);
240
+ }
241
+ const pm = await detectPackageManager(cwd);
242
+ const pmName = getPackageManagerName(pm);
243
+ console.log(` ${S.OK} \u5305\u7BA1\u7406\u5668: ${import_chalk.default.cyan.bold(pmName)}`);
244
+ console.log();
245
+ let features;
246
+ let eslintOpts = {
247
+ framework: "vue",
248
+ typescript: true,
249
+ jsdoc: false
250
+ };
251
+ if (options.ci) {
252
+ const presetId = options.preset || "standard";
253
+ if (presetId === "custom") {
254
+ features = {
255
+ eslint: true,
256
+ lintStaged: true,
257
+ prettier: options.prettier ?? true,
258
+ oxlint: options.oxlint ?? true,
259
+ editorconfig: true
260
+ };
261
+ } else {
262
+ features = { ...PRESETS[presetId].features };
263
+ }
264
+ if (options.prettier !== void 0) features.prettier = options.prettier;
265
+ if (options.oxlint !== void 0) features.oxlint = options.oxlint;
266
+ const jsdocDefault = presetId === "full" ? true : false;
267
+ eslintOpts = {
268
+ framework: options.framework || "vue",
269
+ typescript: options.typescript ?? true,
270
+ jsdoc: options.jsdoc ?? jsdocDefault
271
+ };
272
+ console.log(
273
+ ` ${S.INFO} ${import_chalk.default.gray("CI \u6A21\u5F0F")} ${import_chalk.default.white(
274
+ "\u9884\u8BBE:"
275
+ )} ${import_chalk.default.cyan(presetId)}`
276
+ );
277
+ console.log();
278
+ } else {
279
+ const result = await interactiveSetup(options);
280
+ features = result.features;
281
+ eslintOpts = result.eslintOpts;
282
+ }
283
+ printSummary(features, eslintOpts, pmName);
284
+ if (!options.ci) {
285
+ const { confirm } = await import("@inquirer/prompts");
286
+ const proceed = await confirm({
287
+ message: import_chalk.default.white("\u786E\u8BA4\u4EE5\u4E0A\u914D\u7F6E\u5E76\u5F00\u59CB\u5B89\u88C5?"),
288
+ default: true,
289
+ theme: { prefix: ` ${S.ARROW}` }
290
+ });
291
+ if (!proceed) {
292
+ console.log();
293
+ console.log(` ${S.INFO} ${import_chalk.default.gray("\u91CD\u65B0\u9009\u62E9\u914D\u7F6E...")}`);
294
+ console.log();
295
+ const result = await interactiveSetup(options);
296
+ features = result.features;
297
+ eslintOpts = result.eslintOpts;
298
+ printSummary(features, eslintOpts, pmName);
299
+ }
300
+ }
301
+ console.log();
302
+ await installDependencies(cwd, pm, features, eslintOpts);
303
+ await generateConfigFiles(cwd, features, eslintOpts);
304
+ await setupHusky(cwd, pm, features);
305
+ await addPackageScripts(cwd, pm, features);
306
+ printCompletion(pm, features);
307
+ }
308
+ function printBanner() {
309
+ console.log();
310
+ console.log(S.LINE);
311
+ console.log(
312
+ ` ${S.LOGO} ${import_chalk.default.bold("Robot Standards")} ${import_chalk.default.gray("v1.0.0")}`
313
+ );
314
+ console.log(` ${import_chalk.default.gray("\u96F6\u914D\u7F6E \xB7 \u6A21\u5757\u5316 \xB7 Git \u5DE5\u7A0B\u5316\u6807\u51C6\u5DE5\u5177\u5305")}`);
315
+ console.log(S.LINE);
316
+ console.log();
317
+ }
318
+ async function interactiveSetup(options) {
319
+ const { select, checkbox, confirm } = await import("@inquirer/prompts");
320
+ while (true) {
321
+ console.log(` ${S.STEP} ${import_chalk.default.bold("\u9009\u62E9\u6A21\u5F0F")}`);
322
+ console.log();
323
+ const presetId = await select({
324
+ message: import_chalk.default.white("\u9009\u62E9\u9884\u8BBE\u65B9\u6848"),
325
+ choices: [
326
+ {
327
+ name: `\u6781\u7B80\u6A21\u5F0F ${import_chalk.default.gray(
328
+ "\u2500\u2500 \u4EC5\u63D0\u4EA4\u89C4\u8303 (Commitizen + Commitlint)"
329
+ )}`,
330
+ value: "minimal",
331
+ description: import_chalk.default.gray("\u9002\u5408\u53EA\u9700\u89C4\u8303\u63D0\u4EA4\u4FE1\u606F\u7684\u9879\u76EE")
332
+ },
333
+ {
334
+ name: `\u6807\u51C6\u6A21\u5F0F ${import_chalk.default.gray("\u2500\u2500 \u63D0\u4EA4\u89C4\u8303 + \u4EE3\u7801\u68C0\u67E5 (+ ESLint)")}`,
335
+ value: "standard",
336
+ description: import_chalk.default.gray("\u9002\u5408\u5927\u591A\u6570\u9879\u76EE")
337
+ },
338
+ {
339
+ name: `\u5B8C\u6574\u6A21\u5F0F ${import_chalk.default.gray(
340
+ "\u2500\u2500 \u5168\u90E8\u5DE5\u5177\u94FE (+ Prettier + Oxlint)"
341
+ )} ${import_chalk.default.hex(BRAND)("\u4E3B\u9879\u76EE(Robot_Admin)")}`,
342
+ value: "full",
343
+ description: import_chalk.default.gray("\u5168\u9762\u4EE3\u7801\u8D28\u91CF\u7BA1\u63A7")
344
+ },
345
+ {
346
+ name: `\u81EA\u5B9A\u4E49 ${import_chalk.default.gray("\u2500\u2500 \u81EA\u7531\u7EC4\u5408\u9700\u8981\u7684\u5DE5\u5177\u94FE")}`,
347
+ value: "custom",
348
+ description: import_chalk.default.gray("\u7CBE\u786E\u63A7\u5236\u6BCF\u4E2A\u529F\u80FD\u6A21\u5757")
349
+ }
350
+ ],
351
+ default: "standard",
352
+ theme: { prefix: ` ${S.ARROW}` }
353
+ });
354
+ let features;
355
+ if (presetId === "custom") {
356
+ console.log();
357
+ console.log(
358
+ ` ${S.STEP} ${import_chalk.default.bold("\u9009\u62E9\u529F\u80FD")} ${import_chalk.default.gray(
359
+ "(Git \u63D0\u4EA4\u89C4\u8303\u9ED8\u8BA4\u5305\u542B)"
360
+ )}`
361
+ );
362
+ console.log();
363
+ const selected = await checkbox({
364
+ message: import_chalk.default.white("\u9009\u62E9\u9644\u52A0\u529F\u80FD (\u7A7A\u683C\u5207\u6362, \u56DE\u8F66\u786E\u8BA4)"),
365
+ choices: [
366
+ {
367
+ name: `ESLint ${import_chalk.default.gray("\u4EE3\u7801\u8D28\u91CF\u68C0\u67E5")}`,
368
+ value: "eslint"
369
+ },
370
+ {
371
+ name: `lint-staged ${import_chalk.default.gray("\u6682\u5B58\u533A\u589E\u91CF\u68C0\u67E5")}`,
372
+ value: "lintStaged"
373
+ },
374
+ {
375
+ name: `Prettier ${import_chalk.default.gray("\u4EE3\u7801\u81EA\u52A8\u683C\u5F0F\u5316")}`,
376
+ value: "prettier"
377
+ },
378
+ {
379
+ name: `Oxlint ${import_chalk.default.gray(
380
+ "\u9AD8\u6027\u80FD Lint \u5F15\u64CE (50x faster)"
381
+ )}`,
382
+ value: "oxlint"
383
+ },
384
+ {
385
+ name: `EditorConfig ${import_chalk.default.gray("\u7F16\u8F91\u5668\u7EDF\u4E00\u914D\u7F6E")}`,
386
+ value: "editorconfig"
387
+ },
388
+ {
389
+ name: import_chalk.default.yellow("\u21A9 \u8FD4\u56DE\u4E0A\u4E00\u6B65"),
390
+ value: "__back__"
391
+ }
392
+ ],
393
+ theme: { prefix: ` ${S.ARROW}` }
394
+ });
395
+ if (selected.includes("__back__")) continue;
396
+ features = {
397
+ eslint: selected.includes("eslint"),
398
+ lintStaged: selected.includes("lintStaged"),
399
+ prettier: selected.includes("prettier"),
400
+ oxlint: selected.includes("oxlint"),
401
+ editorconfig: selected.includes("editorconfig")
402
+ };
403
+ if (features.oxlint && !features.eslint) {
404
+ console.log(
405
+ `
406
+ ${S.INFO} ${import_chalk.default.gray(
407
+ "Oxlint \u9700\u8981 ESLint \u914D\u5408\uFF0C\u5DF2\u81EA\u52A8\u542F\u7528 ESLint"
408
+ )}`
409
+ );
410
+ features.eslint = true;
411
+ }
412
+ if (features.lintStaged && !features.eslint && !features.prettier) {
413
+ console.log(
414
+ `
415
+ ${S.INFO} ${import_chalk.default.gray(
416
+ "lint-staged \u9700\u8981 ESLint \u6216 Prettier\uFF0C\u5DF2\u81EA\u52A8\u542F\u7528 ESLint"
417
+ )}`
418
+ );
419
+ features.eslint = true;
420
+ }
421
+ } else {
422
+ features = { ...PRESETS[presetId].features };
423
+ }
424
+ let eslintOpts = {
425
+ framework: "vue",
426
+ typescript: true,
427
+ jsdoc: false
428
+ };
429
+ if (features.eslint) {
430
+ console.log();
431
+ console.log(` ${S.STEP} ${import_chalk.default.bold("ESLint \u914D\u7F6E")}`);
432
+ console.log();
433
+ const framework = await select({
434
+ message: import_chalk.default.white("\u9879\u76EE\u6846\u67B6"),
435
+ choices: [
436
+ {
437
+ name: "Vue 3",
438
+ value: "vue"
439
+ },
440
+ { name: "React", value: "react" },
441
+ { name: "Vanilla JS / TS", value: "vanilla" },
442
+ {
443
+ name: import_chalk.default.yellow("\u21A9 \u8FD4\u56DE\u4E0A\u4E00\u6B65"),
444
+ value: "__back__"
445
+ }
446
+ ],
447
+ default: options.framework || "vue",
448
+ theme: { prefix: ` ${S.ARROW}` }
449
+ });
450
+ if (framework === "__back__") continue;
451
+ const typescript = await confirm({
452
+ message: import_chalk.default.white("\u4F7F\u7528 TypeScript"),
453
+ default: options.typescript ?? true,
454
+ theme: { prefix: ` ${S.ARROW}` }
455
+ });
456
+ const jsdoc = await confirm({
457
+ message: import_chalk.default.white("\u5F3A\u5236 JSDoc \u6CE8\u91CA"),
458
+ default: options.jsdoc ?? true,
459
+ theme: { prefix: ` ${S.ARROW}` }
460
+ });
461
+ eslintOpts = { framework, typescript, jsdoc };
462
+ }
463
+ return { features, eslintOpts };
464
+ }
465
+ }
466
+ function printSummary(features, eslintOpts, pmName) {
467
+ console.log();
468
+ console.log(` ${S.STEP} ${import_chalk.default.bold("\u914D\u7F6E\u6458\u8981")}`);
469
+ console.log();
470
+ console.log(
471
+ ` ${S.OK} ${import_chalk.default.white("\u6838\u5FC3")} Commitizen + Commitlint + Husky`
472
+ );
473
+ if (features.eslint) {
474
+ const fw = eslintOpts.framework === "vue" ? "Vue 3" : eslintOpts.framework === "react" ? "React" : "Vanilla";
475
+ const ts = eslintOpts.typescript ? " + TS" : "";
476
+ const jsdoc = eslintOpts.jsdoc ? " + JSDoc" : "";
477
+ console.log(
478
+ ` ${S.OK} ${import_chalk.default.white("\u68C0\u67E5")} ESLint (${fw}${ts}${jsdoc})`
479
+ );
480
+ }
481
+ if (features.lintStaged) {
482
+ console.log(` ${S.OK} ${import_chalk.default.white("\u6682\u5B58")} lint-staged`);
483
+ }
484
+ if (features.oxlint) {
485
+ console.log(
486
+ ` ${S.OK} ${import_chalk.default.white("\u52A0\u901F")} Oxlint ${import_chalk.default.gray("(50x faster)")}`
487
+ );
488
+ }
489
+ if (features.prettier) {
490
+ console.log(` ${S.OK} ${import_chalk.default.white("\u683C\u5F0F")} Prettier`);
491
+ }
492
+ if (features.editorconfig) {
493
+ console.log(` ${S.OK} ${import_chalk.default.white("\u7F16\u8F91")} EditorConfig`);
494
+ }
495
+ console.log(` ${S.DOT} ${import_chalk.default.gray("\u7BA1\u7406")} ${pmName}`);
496
+ console.log();
497
+ }
498
+ async function installDependencies(cwd, pm, features, eslintOpts) {
499
+ const spinner = (0, import_ora.default)({
500
+ text: import_chalk.default.gray("\u5206\u6790\u4F9D\u8D56..."),
501
+ prefixText: " ",
502
+ spinner: "dots"
503
+ }).start();
504
+ const deps = [
505
+ "@commitlint/cli",
506
+ "@commitlint/config-conventional",
507
+ "commitizen",
508
+ "cz-customizable",
509
+ "husky"
510
+ ];
511
+ if (features.eslint) {
512
+ deps.push("eslint");
513
+ if (eslintOpts.framework === "vue") {
514
+ deps.push("eslint-plugin-vue", "@vue/eslint-config-typescript");
515
+ }
516
+ if (eslintOpts.typescript) {
517
+ deps.push(
518
+ "@typescript-eslint/eslint-plugin",
519
+ "@typescript-eslint/parser"
520
+ );
521
+ }
522
+ if (eslintOpts.jsdoc) {
523
+ deps.push("eslint-plugin-jsdoc");
524
+ }
525
+ }
526
+ if (features.lintStaged) {
527
+ deps.push("lint-staged");
528
+ }
529
+ if (features.oxlint) {
530
+ deps.push("oxlint", "eslint-plugin-oxlint");
531
+ }
532
+ if (features.prettier) {
533
+ deps.push("prettier");
534
+ if (features.eslint && eslintOpts.framework === "vue") {
535
+ deps.push("@vue/eslint-config-prettier");
536
+ }
537
+ }
538
+ spinner.text = import_chalk.default.gray(`\u5B89\u88C5 ${deps.length} \u4E2A\u4F9D\u8D56...`);
539
+ try {
540
+ const installCmd = getInstallCommand(pm);
541
+ await (0, import_execa2.execa)(
542
+ installCmd.split(" ")[0],
543
+ [...installCmd.split(" ").slice(1), ...deps],
544
+ { cwd, stdio: "pipe" }
545
+ );
546
+ spinner.succeed(
547
+ import_chalk.default.white("\u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210 ") + import_chalk.default.gray(`(${deps.length} packages)`)
548
+ );
549
+ } catch (error) {
550
+ spinner.fail(import_chalk.default.red("\u4F9D\u8D56\u5B89\u88C5\u5931\u8D25"));
551
+ throw error;
552
+ }
553
+ }
554
+ async function generateConfigFiles(cwd, features, eslintOpts) {
555
+ const spinner = (0, import_ora.default)({
556
+ text: import_chalk.default.gray("\u751F\u6210\u914D\u7F6E\u6587\u4EF6..."),
557
+ prefixText: " ",
558
+ spinner: "dots"
559
+ }).start();
560
+ const generated = [];
561
+ try {
562
+ const czConfig = `/*
563
+ * Commitizen \u81EA\u5B9A\u4E49\u914D\u7F6E (cz-customizable)
564
+ * @generated by @robot-admin/git-standards
565
+ *
566
+ * \u76F4\u63A5\u4FEE\u6539\u6B64\u6587\u4EF6\u5373\u53EF\u81EA\u5B9A\u4E49\u63D0\u4EA4\u89C4\u8303
567
+ */
568
+ module.exports = {
569
+ scopes: [],
570
+ allowEmptyScopes: false,
571
+ allowCustomScopes: true,
572
+
573
+ types: [
574
+ { value: 'wip', name: 'wip: \u{1F6A7} \u5F00\u53D1\u4E2D' },
575
+ { value: 'feat', name: 'feat: \u{1F3AF} \u65B0\u529F\u80FD' },
576
+ { value: 'fix', name: 'fix: \u{1F41B} Bug \u4FEE\u590D' },
577
+ { value: 'perf', name: 'perf: \u26A1\uFE0F \u6027\u80FD\u4F18\u5316' },
578
+ { value: 'deps', name: 'deps: \u{1F4E6} \u4F9D\u8D56\u66F4\u65B0' },
579
+ { value: 'refactor', name: 'refactor: \u267B\uFE0F \u91CD\u6784' },
580
+ { value: 'docs', name: 'docs: \u{1F4DA} \u6587\u6863\u53D8\u66F4' },
581
+ { value: 'test', name: 'test: \u{1F50E} \u6D4B\u8BD5\u76F8\u5173' },
582
+ { value: 'style', name: 'style: \u{1F484} \u4EE3\u7801\u6837\u5F0F' },
583
+ { value: 'build', name: 'build: \u{1F9F3} \u6784\u5EFA/\u6253\u5305' },
584
+ { value: 'chore', name: 'chore: \u{1F527} \u5176\u4ED6\u6742\u9879' },
585
+ { value: 'revert', name: 'revert: \u{1F519} \u56DE\u9000' },
586
+ ],
587
+
588
+ messages: {
589
+ type: '\u8BF7\u9009\u62E9\u63D0\u4EA4\u7C7B\u578B:',
590
+ customScope: '\u8BF7\u8F93\u5165\u4FEE\u6539\u8303\u56F4(\u5FC5\u586B\uFF0C\u683C\u5F0F\u5982\uFF1A\u6A21\u5757/\u5B50\u6A21\u5757):',
591
+ subject: '\u8BF7\u7B80\u8981\u63CF\u8FF0\u63D0\u4EA4(\u5FC5\u586B\uFF0C\u4E0D\u52A0\u53E5\u53F7):',
592
+ body: '\u8BF7\u8F93\u5165\u66F4\u8BE6\u7EC6\u7684\u8BF4\u660E(\u53EF\u9009):\\n',
593
+ footer: 'Footer(\u53EF\u9009): \u4F8B\u5982 "Closes #123" \u6216 "Release-As: 1.3.1"\\n',
594
+ confirmCommit: '\u786E\u8BA4\u63D0\u4EA4\u4EE5\u4E0A\u5185\u5BB9\uFF1F(y/n/e/h)',
595
+ },
596
+
597
+ skipQuestions: ['body'],
598
+
599
+ allowBreakingChanges: ['feat', 'fix', 'refactor'],
600
+ breakingPrefix: 'BREAKING CHANGE:',
601
+
602
+ subjectLimit: 88,
603
+ }
604
+ `;
605
+ await writeFileContent((0, import_node_path4.resolve)(cwd, ".cz-config.js"), czConfig);
606
+ generated.push(".cz-config.js");
607
+ const commitlintConfig = `/*
608
+ * Commitlint \u914D\u7F6E
609
+ * @generated by @robot-admin/git-standards
610
+ *
611
+ * \u76F4\u63A5\u4FEE\u6539\u6B64\u6587\u4EF6\u5373\u53EF\u81EA\u5B9A\u4E49\u63D0\u4EA4\u6821\u9A8C\u89C4\u5219
612
+ */
613
+ module.exports = {
614
+ extends: ['@commitlint/config-conventional'],
615
+ rules: {
616
+ 'type-enum': [
617
+ 2,
618
+ 'always',
619
+ [
620
+ 'wip', 'feat', 'fix', 'docs', 'style', 'refactor',
621
+ 'perf', 'test', 'chore', 'revert', 'build', 'deps',
622
+ ],
623
+ ],
624
+ 'subject-case': [0],
625
+ },
626
+ }
627
+ `;
628
+ await writeFileContent(
629
+ (0, import_node_path4.resolve)(cwd, "commitlint.config.js"),
630
+ commitlintConfig
631
+ );
632
+ generated.push("commitlint.config.js");
633
+ if (features.prettier) {
634
+ const prettierConfig = `/*
635
+ * Prettier \u914D\u7F6E
636
+ * @generated by @robot-admin/git-standards
637
+ *
638
+ * \u76F4\u63A5\u4FEE\u6539\u6B64\u6587\u4EF6\u5373\u53EF\u81EA\u5B9A\u4E49\u683C\u5F0F\u5316\u89C4\u5219
639
+ */
640
+ module.exports = {
641
+ $schema: 'https://json.schemastore.org/prettierrc',
642
+ semi: false,
643
+ singleQuote: true,
644
+ printWidth: 80,
645
+ tabWidth: 2,
646
+ quoteProps: 'as-needed',
647
+ trailingComma: 'es5',
648
+ bracketSpacing: true,
649
+ jsxSingleQuote: true,
650
+ arrowParens: 'avoid',
651
+ endOfLine: 'auto',
652
+ htmlWhitespaceSensitivity: 'strict',
653
+ vueIndentScriptAndStyle: true,
654
+ singleAttributePerLine: true,
655
+ }
656
+ `;
657
+ await writeFileContent((0, import_node_path4.resolve)(cwd, ".prettierrc.js"), prettierConfig);
658
+ generated.push(".prettierrc.js");
659
+ }
660
+ if (features.eslint) {
661
+ const hasOxlint = features.oxlint;
662
+ const hasPrettier = features.prettier;
663
+ const hasJsdoc = eslintOpts.jsdoc;
664
+ const isVue = eslintOpts.framework === "vue";
665
+ const isTs = eslintOpts.typescript;
666
+ const importLines = [];
667
+ if (isVue) importLines.push("import pluginVue from 'eslint-plugin-vue'");
668
+ if (isVue && isTs) {
669
+ importLines.push(
670
+ "import {\n defineConfigWithVueTs,\n vueTsConfigs,\n} from '@vue/eslint-config-typescript'"
671
+ );
672
+ }
673
+ if (hasOxlint)
674
+ importLines.push("import oxlint from 'eslint-plugin-oxlint'");
675
+ if (hasPrettier && isVue) {
676
+ importLines.push(
677
+ "import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'"
678
+ );
679
+ }
680
+ if (hasJsdoc)
681
+ importLines.push("import jsdocPlugin from 'eslint-plugin-jsdoc'");
682
+ const fileExts = isTs ? "js,ts,mts,tsx,vue" : "js,jsx,vue";
683
+ const vue2DeprecationRules = isVue ? `
684
+ //! \u4E3B\u52A8\u7981\u6B62 Vue 2 \u5199\u6CD5
685
+ 'vue/no-deprecated-props-default-this': 'error',
686
+ 'vue/no-deprecated-events-api': 'error',
687
+ 'vue/no-deprecated-filter': 'error',
688
+ 'vue/no-deprecated-functional-template': 'error',
689
+ ` : "";
690
+ const vueComponentRules = isVue ? `
691
+ // Vue \u89C4\u8303
692
+ //! PascalCase \u547D\u540D\u89C4\u8303
693
+ 'vue/component-name-in-template-casing': [
694
+ 'error',
695
+ 'PascalCase',
696
+ {
697
+ registeredComponentsOnly: false,
698
+ ignores: [
699
+ 'router-view',
700
+ 'router-link',
701
+ 'transition',
702
+ 'draggable',
703
+ '/^icon-/i',
704
+ '/^C_/',
705
+ '/^c_/',
706
+ 'v-md-editor',
707
+ ],
708
+ },
709
+ ],
710
+ 'vue/multi-word-component-names': [
711
+ 'error',
712
+ {
713
+ ignores: ['index'],
714
+ },
715
+ ],
716
+ //! \u7981\u6B62\u5728\u6A21\u677F\u4E2D\u6CE8\u518C\u4F46\u672A\u4F7F\u7528\u7684\u7EC4\u4EF6
717
+ 'vue/no-unused-components': 'error',
718
+ ${vue2DeprecationRules}` : "";
719
+ const jsdocBlock = hasJsdoc ? `
720
+ //MARK: \u81EA\u5B9A\u4E49\u89C4\u5219\u7EC4\uFF08\u4F18\u5148\u7EA7\u6700\u9AD8\uFF09
721
+ {
722
+ plugins: {
723
+ jsdoc: jsdocPlugin,
724
+ },
725
+ rules: {
726
+ //! JSDoc \u6CE8\u91CA\u89C4\u5219
727
+ 'jsdoc/require-jsdoc': [
728
+ 'error',
729
+ {
730
+ require: {
731
+ FunctionDeclaration: true,
732
+ MethodDefinition: true,
733
+ ClassDeclaration: true,
734
+ ArrowFunctionExpression: false,
735
+ FunctionExpression: true,
736
+ },
737
+ contexts: [
738
+ 'FunctionDeclaration',
739
+ 'ClassDeclaration',
740
+ 'ClassProperty',
741
+ 'MethodDefinition',
742
+ 'FunctionExpression',
743
+ ],
744
+ checkConstructors: true,
745
+ checkGetters: true,
746
+ checkSetters: true,
747
+ },
748
+ ],
749
+ ` : `
750
+ // \u81EA\u5B9A\u4E49\u89C4\u5219\u7EC4
751
+ {
752
+ rules: {
753
+ `;
754
+ const fileTypeOverrides = isTs ? `
755
+ //MARK: \u6587\u4EF6\u7C7B\u578B\u8986\u76D6\u89C4\u5219
756
+
757
+ //! \u53D8\u91CF\u4F7F\u7528\u89C4\u5219
758
+ {
759
+ files: ['**/*.js'],
760
+ rules: {
761
+ 'no-unused-vars': 'error',
762
+ '@typescript-eslint/no-unused-vars': 'off',
763
+ },
764
+ },
765
+ {
766
+ files: ['**/*.{ts,mts,tsx,vue}'],
767
+ rules: {
768
+ 'no-unused-vars': 'off',
769
+ '@typescript-eslint/no-unused-vars': 'error',
770
+ },
771
+ },
772
+ ` : "";
773
+ const jsdocWhitelist = hasJsdoc ? `
774
+ //MARK: JSDoc \u767D\u540D\u5355\u8986\u76D6\u89C4\u5219
775
+ {
776
+ files: [
777
+ 'src/router/**/*.ts',
778
+ 'src/stores/**/*.ts',
779
+ 'src/views/**/components/*.vue',
780
+ ],
781
+ rules: {
782
+ 'jsdoc/require-jsdoc': 'off',
783
+ '@typescript-eslint/require-jsdoc': 'off',
784
+ },
785
+ },
786
+ ` : "";
787
+ const ignoreAssets = `
788
+ //MARK: ESLINT \u767D\u540D\u5355\u914D\u7F6E\u7EC4
789
+ {
790
+ name: 'app/ignore-assets',
791
+ ignores: [
792
+ 'src/assets/images/**/*',
793
+ '**/*.d.ts',
794
+ '**/auto-imports.d.ts',
795
+ 'src/views/**/components/*.vue',
796
+ 'scripts/**/*',
797
+ ],
798
+ },
799
+ `;
800
+ const tsRules = isTs ? `
801
+ //! \u5173\u95ED\u4E0E oxlint \u91CD\u590D\u7684 ESLint \u89C4\u5219
802
+ 'no-undef': 'off',
803
+
804
+ //! \u5F15\u53F7\u89C4\u8303
805
+ '@typescript-eslint/quotes': ['error', 'single'],${isVue ? "\n 'vue/html-quotes': ['error', 'double']," : ""}
806
+
807
+ //! TypeScript \u5B89\u5168
808
+ '@typescript-eslint/no-explicit-any': 'off',
809
+ '@typescript-eslint/ban-ts-comment': [
810
+ 'error',
811
+ {
812
+ 'ts-ignore': 'allow-with-description',
813
+ },
814
+ ],
815
+
816
+ //! \u8868\u8FBE\u5F0F\u89C4\u8303
817
+ '@typescript-eslint/no-unused-expressions': [
818
+ 'error',
819
+ {
820
+ allowShortCircuit: true,
821
+ allowTernary: false,
822
+ allowTaggedTemplates: false,
823
+ enforceForJSX: true,
824
+ },
825
+ ],
826
+ ` : "";
827
+ const useWrapper = isVue && isTs;
828
+ const wrapperStart = useWrapper ? "export default defineConfigWithVueTs(" : "export default [";
829
+ const wrapperEnd = useWrapper ? ")" : "]";
830
+ const oxlintLine = hasOxlint ? "\n ...oxlint.configs['flat/recommended'], // \u9AD8\u6027\u80FD\u57FA\u7840\u6821\u9A8C\n" : "";
831
+ const vueLine = isVue ? `
832
+ //! \u5FFD\u7565\u8F6C\u4E49\u5B57\u7B26
833
+ {
834
+ rules: {
835
+ 'no-useless-escape': 'off',
836
+ },
837
+ },
838
+
839
+ pluginVue.configs['flat/essential'], // Vue \u4E13\u7528\u89C4\u5219` : "";
840
+ const tsLine = isVue && isTs ? "\n vueTsConfigs.recommended, // TS \u4E13\u7528\u89C4\u5219" : "";
841
+ const skipLine = hasPrettier && isVue ? "\n skipFormatting" : "";
842
+ const eslintConfig = `/*
843
+ * ESLint Flat Config
844
+ * @generated by @robot-admin/git-standards
845
+ *
846
+ * \u76F4\u63A5\u4FEE\u6539\u6B64\u6587\u4EF6\u5373\u53EF\u81EA\u5B9A\u4E49 ESLint \u89C4\u5219
847
+ */
848
+ ${importLines.join("\n")}
849
+
850
+ ${wrapperStart}
851
+ //MARK: \u57FA\u7840\u914D\u7F6E\u7EC4
852
+ {
853
+ name: 'app/files-to-lint',
854
+ files: ['**/*.{${fileExts}}'],
855
+ },
856
+
857
+ {
858
+ name: 'app/files-to-ignore',
859
+ ignores: [
860
+ '**/dist/**',
861
+ '**/dist-ssr/**',
862
+ '**/coverage/**',
863
+ ],
864
+ },
865
+
866
+ //MARK: \u6838\u5FC3\u89C4\u5219\u7EC4\uFF08\u6309\u4F18\u5148\u7EA7\u6392\u5E8F\uFF09
867
+ ${oxlintLine}${vueLine}${tsLine}
868
+ ${fileTypeOverrides}
869
+ ${jsdocBlock}${tsRules}
870
+ //! \u4EE3\u7801\u590D\u6742\u5EA6
871
+ 'max-depth': ['error', 4],
872
+ complexity: ['warn', 10],
873
+
874
+ //! \u5F02\u6B65\u4EE3\u7801\u89C4\u8303
875
+ 'no-await-in-loop': 'error',
876
+ ${vueComponentRules}
877
+ //MARK: \u683C\u5F0F\u89C4\u8303
878
+ 'no-irregular-whitespace': 'error',
879
+ 'no-multi-spaces': 'error',
880
+ 'space-infix-ops': 'error',
881
+ 'array-bracket-spacing': ['error', 'never'],
882
+ 'arrow-spacing': ['error', { before: true, after: true }],
883
+ 'max-params': ['warn', 6],
884
+ 'no-eval': 'error',
885
+ 'prefer-const': 'warn',
886
+ 'no-var': 'warn',
887
+ 'prefer-destructuring': [
888
+ 1,
889
+ { object: true, array: false },
890
+ ],
891
+ 'no-duplicate-imports': 'error',
892
+ },
893
+ },
894
+ ${ignoreAssets}${jsdocWhitelist}${skipLine}
895
+ ${wrapperEnd}
896
+ `;
897
+ await writeFileContent((0, import_node_path4.resolve)(cwd, "eslint.config.ts"), eslintConfig);
898
+ generated.push("eslint.config.ts");
899
+ }
900
+ if (features.editorconfig) {
901
+ const editorConfig = `# EditorConfig - \u7F16\u8F91\u5668\u7EDF\u4E00\u914D\u7F6E
902
+ # @generated by @robot-admin/git-standards
903
+ # \u53C2\u8003: https://editorconfig.org
904
+
905
+ root = true
906
+
907
+ [*]
908
+ charset = utf-8
909
+ indent_style = space
910
+ indent_size = 2
911
+ end_of_line = lf
912
+ insert_final_newline = true
913
+ trim_trailing_whitespace = true
914
+
915
+ [*.md]
916
+ trim_trailing_whitespace = false
917
+
918
+ [*.{yml,yaml}]
919
+ indent_size = 2
920
+
921
+ [Makefile]
922
+ indent_style = tab
923
+ `;
924
+ await writeFileContent((0, import_node_path4.resolve)(cwd, ".editorconfig"), editorConfig);
925
+ generated.push(".editorconfig");
926
+ }
927
+ spinner.succeed(
928
+ import_chalk.default.white("\u914D\u7F6E\u6587\u4EF6\u751F\u6210\u5B8C\u6210 ") + import_chalk.default.gray(`(${generated.join(", ")})`)
929
+ );
930
+ } catch (error) {
931
+ spinner.fail(import_chalk.default.red("\u914D\u7F6E\u6587\u4EF6\u751F\u6210\u5931\u8D25"));
932
+ throw error;
933
+ }
934
+ }
935
+ async function setupHusky(cwd, pm, features) {
936
+ const spinner = (0, import_ora.default)({
937
+ text: import_chalk.default.gray("\u521D\u59CB\u5316 Husky..."),
938
+ prefixText: " ",
939
+ spinner: "dots"
940
+ }).start();
941
+ try {
942
+ const execCmd = getExecCommand(pm);
943
+ await (0, import_execa2.execa)(execCmd, ["husky", "init"], { cwd, stdio: "pipe" });
944
+ const legacyDir = (0, import_node_path4.resolve)(cwd, ".husky/_");
945
+ if ((0, import_node_fs4.existsSync)(legacyDir)) {
946
+ (0, import_node_fs4.rmSync)(legacyDir, { recursive: true, force: true });
947
+ }
948
+ const commitMsg = `${execCmd} --no-install commitlint --edit "$1"
949
+ `;
950
+ await writeFileContent((0, import_node_path4.resolve)(cwd, ".husky/commit-msg"), commitMsg);
951
+ const hooks = ["commit-msg"];
952
+ const needsPreCommit = features.eslint || features.lintStaged || features.oxlint;
953
+ if (needsPreCommit) {
954
+ const cmds = [];
955
+ if (features.oxlint) {
956
+ cmds.push(`${execCmd} oxlint --max-warnings 0`);
957
+ }
958
+ if (features.lintStaged) {
959
+ cmds.push(`${execCmd} lint-staged`);
960
+ } else if (features.eslint) {
961
+ cmds.push(`${execCmd} eslint . --fix`);
962
+ }
963
+ await writeFileContent(
964
+ (0, import_node_path4.resolve)(cwd, ".husky/pre-commit"),
965
+ cmds.join("\n") + "\n"
966
+ );
967
+ hooks.push("pre-commit");
968
+ } else {
969
+ const defaultPreCommit = (0, import_node_path4.resolve)(cwd, ".husky/pre-commit");
970
+ if ((0, import_node_fs4.existsSync)(defaultPreCommit)) {
971
+ (0, import_node_fs4.unlinkSync)(defaultPreCommit);
972
+ }
973
+ }
974
+ spinner.succeed(
975
+ import_chalk.default.white("Husky \u521D\u59CB\u5316\u5B8C\u6210 ") + import_chalk.default.gray(`(${hooks.join(", ")})`)
976
+ );
977
+ } catch (error) {
978
+ spinner.fail(import_chalk.default.red("Husky \u521D\u59CB\u5316\u5931\u8D25"));
979
+ throw error;
980
+ }
981
+ }
982
+ async function addPackageScripts(cwd, pm, features) {
983
+ const spinner = (0, import_ora.default)({
984
+ text: import_chalk.default.gray("\u66F4\u65B0 package.json..."),
985
+ prefixText: " ",
986
+ spinner: "dots"
987
+ }).start();
988
+ try {
989
+ const packageJsonPath = (0, import_node_path4.resolve)(cwd, "package.json");
990
+ const packageJson = await readJsonFile(packageJsonPath);
991
+ const scripts = packageJson.scripts || {};
992
+ scripts.cz = "git-cz";
993
+ scripts.prepare = "husky";
994
+ if (features.eslint) {
995
+ scripts.lint = features.oxlint ? "oxlint . --fix -D correctness --ignore-path .gitignore && eslint . --fix" : "eslint . --fix";
996
+ }
997
+ if (features.prettier) {
998
+ scripts.format = "prettier --write src/";
999
+ }
1000
+ const czConfig = {
1001
+ commitizen: { path: "node_modules/cz-customizable" }
1002
+ };
1003
+ const updates = { scripts, config: czConfig };
1004
+ if (features.lintStaged) {
1005
+ updates["lint-staged"] = generateLintStagedConfig({
1006
+ eslint: features.eslint,
1007
+ oxlint: features.oxlint,
1008
+ prettier: features.prettier
1009
+ });
1010
+ }
1011
+ await updatePackageJson(updates, cwd);
1012
+ const parts = ["scripts"];
1013
+ if (features.lintStaged) parts.push("lint-staged");
1014
+ spinner.succeed(
1015
+ import_chalk.default.white("package.json \u66F4\u65B0\u5B8C\u6210 ") + import_chalk.default.gray(`(${parts.join(" + ")})`)
1016
+ );
1017
+ } catch (error) {
1018
+ spinner.fail(import_chalk.default.red("package.json \u66F4\u65B0\u5931\u8D25"));
1019
+ throw error;
1020
+ }
1021
+ }
1022
+ function printCompletion(pm, features) {
1023
+ console.log();
1024
+ console.log(S.LINE);
1025
+ console.log(` ${S.OK} ${import_chalk.default.green.bold("\u521D\u59CB\u5316\u5B8C\u6210!")}`);
1026
+ console.log(S.LINE);
1027
+ console.log();
1028
+ console.log(` ${import_chalk.default.bold("\u5FEB\u901F\u5F00\u59CB:")}`);
1029
+ console.log();
1030
+ console.log(` ${S.DOT} \u63D0\u4EA4\u4EE3\u7801 ${import_chalk.default.cyan(`${pm} run cz`)}`);
1031
+ if (features.eslint) {
1032
+ console.log(` ${S.DOT} \u68C0\u67E5\u4EE3\u7801 ${import_chalk.default.cyan(`${pm} run lint`)}`);
1033
+ }
1034
+ if (features.prettier) {
1035
+ console.log(` ${S.DOT} \u683C\u5F0F\u5316 ${import_chalk.default.cyan(`${pm} run format`)}`);
1036
+ }
1037
+ console.log();
1038
+ console.log(
1039
+ ` ${S.INFO} ${import_chalk.default.gray("\u5168\u5C40\u5B89\u88C5 commitizen \u540E\u53EF\u76F4\u63A5\u4F7F\u7528 git cz \u63D0\u4EA4")}`
1040
+ );
1041
+ console.log(` ${S.DOT} ${import_chalk.default.gray(`npm install -g commitizen`)}`);
1042
+ console.log();
1043
+ console.log(
1044
+ ` ${S.INFO} ${import_chalk.default.gray("\u6240\u6709\u914D\u7F6E\u6587\u4EF6\u5747\u652F\u6301\u8986\u76D6\u6269\u5C55\uFF0C\u8BE6\u89C1 README.md")}`
1045
+ );
1046
+ console.log();
1047
+ }
1048
+
1049
+ // src/cli/doctor.ts
1050
+ var import_node_path5 = require("path");
1051
+ var import_chalk2 = __toESM(require("chalk"), 1);
1052
+ var BRAND2 = "#7C3AED";
1053
+ var S2 = {
1054
+ LOGO: import_chalk2.default.hex(BRAND2).bold("[RS]"),
1055
+ OK: import_chalk2.default.green("\u2714"),
1056
+ FAIL: import_chalk2.default.red("\u2716"),
1057
+ WARN: import_chalk2.default.yellow("\u25B2"),
1058
+ SKIP: import_chalk2.default.gray("\u25CB"),
1059
+ LINE: import_chalk2.default.gray("\u2500".repeat(48))
1060
+ };
1061
+ async function doctor(options = {}) {
1062
+ const cwd = options.cwd || process.cwd();
1063
+ console.log();
1064
+ console.log(S2.LINE);
1065
+ console.log(
1066
+ ` ${S2.LOGO} ${import_chalk2.default.bold("Robot Standards")} ${import_chalk2.default.gray("Doctor")}`
1067
+ );
1068
+ console.log(S2.LINE);
1069
+ console.log();
1070
+ const checks = [];
1071
+ const isGit = isGitRepository(cwd);
1072
+ checks.push({
1073
+ name: "Git \u4ED3\u5E93",
1074
+ status: isGit ? "pass" : "fail",
1075
+ message: isGit ? void 0 : "\u672A\u521D\u59CB\u5316 Git \u4ED3\u5E93\uFF0C\u8FD0\u884C git init"
1076
+ });
1077
+ let packageJson = {};
1078
+ const packageJsonPath = (0, import_node_path5.resolve)(cwd, "package.json");
1079
+ const hasPackageJson = fileExists(packageJsonPath);
1080
+ if (hasPackageJson) {
1081
+ try {
1082
+ packageJson = await readJsonFile(packageJsonPath);
1083
+ } catch {
1084
+ }
1085
+ } else {
1086
+ checks.push({
1087
+ name: "package.json",
1088
+ status: "fail",
1089
+ message: "\u7F3A\u5C11 package.json"
1090
+ });
1091
+ }
1092
+ const allDeps = {
1093
+ ...packageJson.dependencies,
1094
+ ...packageJson.devDependencies
1095
+ };
1096
+ const hasCommitizen = !!allDeps["commitizen"];
1097
+ const hasCommitlint = !!allDeps["@commitlint/cli"];
1098
+ const hasHusky = !!allDeps["husky"];
1099
+ const hasEslint = !!allDeps["eslint"];
1100
+ const hasLintStaged = !!allDeps["lint-staged"];
1101
+ const hasPrettier = !!allDeps["prettier"];
1102
+ console.log(` ${import_chalk2.default.bold("\u6838\u5FC3\u529F\u80FD")}`);
1103
+ console.log();
1104
+ if (hasHusky) {
1105
+ const huskyDir = fileExists((0, import_node_path5.resolve)(cwd, ".husky"));
1106
+ checks.push({
1107
+ name: "Husky \u76EE\u5F55",
1108
+ status: huskyDir ? "pass" : "fail",
1109
+ message: huskyDir ? void 0 : "\u7F3A\u5C11 .husky \u76EE\u5F55"
1110
+ });
1111
+ const commitMsg = fileExists((0, import_node_path5.resolve)(cwd, ".husky/commit-msg"));
1112
+ checks.push({
1113
+ name: "commit-msg hook",
1114
+ status: commitMsg ? "pass" : "fail",
1115
+ message: commitMsg ? void 0 : "\u7F3A\u5C11 commit-msg hook"
1116
+ });
1117
+ } else {
1118
+ checks.push({
1119
+ name: "Husky",
1120
+ status: "fail",
1121
+ message: "\u672A\u5B89\u88C5 husky"
1122
+ });
1123
+ }
1124
+ if (hasCommitlint) {
1125
+ const hasConfig = fileExists((0, import_node_path5.resolve)(cwd, "commitlint.config.cjs")) || fileExists((0, import_node_path5.resolve)(cwd, "commitlint.config.js")) || fileExists((0, import_node_path5.resolve)(cwd, "commitlint.config.ts"));
1126
+ checks.push({
1127
+ name: "Commitlint \u914D\u7F6E",
1128
+ status: hasConfig ? "pass" : "fail",
1129
+ message: hasConfig ? void 0 : "\u7F3A\u5C11 commitlint.config.*"
1130
+ });
1131
+ } else {
1132
+ checks.push({
1133
+ name: "Commitlint",
1134
+ status: "fail",
1135
+ message: "\u672A\u5B89\u88C5 @commitlint/cli"
1136
+ });
1137
+ }
1138
+ if (hasCommitizen) {
1139
+ const hasCzConfig = fileExists((0, import_node_path5.resolve)(cwd, ".cz-config.cjs")) || fileExists((0, import_node_path5.resolve)(cwd, ".cz-config.js"));
1140
+ checks.push({
1141
+ name: "Commitizen \u914D\u7F6E",
1142
+ status: hasCzConfig ? "pass" : "fail",
1143
+ message: hasCzConfig ? void 0 : "\u7F3A\u5C11 .cz-config.*"
1144
+ });
1145
+ const hasCommitizenPath = !!packageJson.config?.commitizen;
1146
+ checks.push({
1147
+ name: "commitizen path \u914D\u7F6E",
1148
+ status: hasCommitizenPath ? "pass" : "fail",
1149
+ message: hasCommitizenPath ? void 0 : "package.json \u4E2D\u7F3A\u5C11 config.commitizen"
1150
+ });
1151
+ } else {
1152
+ checks.push({
1153
+ name: "Commitizen",
1154
+ status: "fail",
1155
+ message: "\u672A\u5B89\u88C5 commitizen"
1156
+ });
1157
+ }
1158
+ const hasCzScript = !!packageJson.scripts?.cz;
1159
+ checks.push({
1160
+ name: "cz \u811A\u672C",
1161
+ status: hasCzScript ? "pass" : "fail",
1162
+ message: hasCzScript ? void 0 : "\u7F3A\u5C11 cz \u811A\u672C (bun run cz)"
1163
+ });
1164
+ const coreChecks = checks.slice();
1165
+ for (const check of coreChecks) {
1166
+ printCheck(check);
1167
+ }
1168
+ const extraChecks = [];
1169
+ if (hasEslint) {
1170
+ console.log();
1171
+ console.log(` ${import_chalk2.default.bold("\u4EE3\u7801\u68C0\u67E5")}`);
1172
+ console.log();
1173
+ const hasEslintConfig = fileExists((0, import_node_path5.resolve)(cwd, "eslint.config.ts")) || fileExists((0, import_node_path5.resolve)(cwd, "eslint.config.js")) || fileExists((0, import_node_path5.resolve)(cwd, "eslint.config.mjs"));
1174
+ const eslintCheck = {
1175
+ name: "ESLint \u914D\u7F6E",
1176
+ status: hasEslintConfig ? "pass" : "fail",
1177
+ message: hasEslintConfig ? void 0 : "\u7F3A\u5C11 eslint.config.*"
1178
+ };
1179
+ extraChecks.push(eslintCheck);
1180
+ printCheck(eslintCheck);
1181
+ if (hasHusky) {
1182
+ const preCommit = fileExists((0, import_node_path5.resolve)(cwd, ".husky/pre-commit"));
1183
+ const preCommitCheck = {
1184
+ name: "pre-commit hook",
1185
+ status: preCommit ? "pass" : "fail",
1186
+ message: preCommit ? void 0 : "\u7F3A\u5C11 pre-commit hook"
1187
+ };
1188
+ extraChecks.push(preCommitCheck);
1189
+ printCheck(preCommitCheck);
1190
+ }
1191
+ }
1192
+ if (hasLintStaged) {
1193
+ const lintStagedConfig = !!packageJson["lint-staged"];
1194
+ const lintStagedCheck = {
1195
+ name: "lint-staged \u914D\u7F6E",
1196
+ status: lintStagedConfig ? "pass" : "fail",
1197
+ message: lintStagedConfig ? void 0 : "package.json \u4E2D\u7F3A\u5C11 lint-staged \u914D\u7F6E"
1198
+ };
1199
+ extraChecks.push(lintStagedCheck);
1200
+ printCheck(lintStagedCheck);
1201
+ }
1202
+ if (hasPrettier) {
1203
+ console.log();
1204
+ console.log(` ${import_chalk2.default.bold("\u4EE3\u7801\u683C\u5F0F\u5316")}`);
1205
+ console.log();
1206
+ const hasPrettierConfig = fileExists((0, import_node_path5.resolve)(cwd, ".prettierrc.cjs")) || fileExists((0, import_node_path5.resolve)(cwd, ".prettierrc.js")) || fileExists((0, import_node_path5.resolve)(cwd, ".prettierrc.json")) || fileExists((0, import_node_path5.resolve)(cwd, ".prettierrc"));
1207
+ const prettierCheck = {
1208
+ name: "Prettier \u914D\u7F6E",
1209
+ status: hasPrettierConfig ? "pass" : "fail",
1210
+ message: hasPrettierConfig ? void 0 : "\u7F3A\u5C11 .prettierrc.*"
1211
+ };
1212
+ extraChecks.push(prettierCheck);
1213
+ printCheck(prettierCheck);
1214
+ }
1215
+ const hasEditorConfig = fileExists((0, import_node_path5.resolve)(cwd, ".editorconfig"));
1216
+ if (hasEditorConfig) {
1217
+ }
1218
+ const notInstalled = [];
1219
+ if (!hasEslint) notInstalled.push("ESLint");
1220
+ if (!hasLintStaged) notInstalled.push("lint-staged");
1221
+ if (!hasPrettier) notInstalled.push("Prettier");
1222
+ if (!hasEditorConfig) notInstalled.push("EditorConfig");
1223
+ if (notInstalled.length > 0) {
1224
+ console.log();
1225
+ console.log(` ${import_chalk2.default.bold("\u672A\u542F\u7528\u7684\u529F\u80FD")}`);
1226
+ console.log();
1227
+ for (const name of notInstalled) {
1228
+ console.log(` ${S2.SKIP} ${import_chalk2.default.gray(name)}`);
1229
+ }
1230
+ }
1231
+ const allChecks = [...coreChecks, ...extraChecks];
1232
+ const passedCount = allChecks.filter((c) => c.status === "pass").length;
1233
+ const failedCount = allChecks.filter((c) => c.status === "fail").length;
1234
+ console.log();
1235
+ console.log(S2.LINE);
1236
+ console.log(
1237
+ ` ${import_chalk2.default.bold("\u603B\u8BA1:")} ${import_chalk2.default.green(`${passedCount} \u901A\u8FC7`)} ${failedCount > 0 ? import_chalk2.default.red(`${failedCount} \u5931\u8D25`) : import_chalk2.default.gray("0 \u5931\u8D25")}`
1238
+ );
1239
+ if (failedCount > 0) {
1240
+ console.log();
1241
+ console.log(
1242
+ ` ${S2.WARN} ${import_chalk2.default.yellow("\u8FD0\u884C")} ${import_chalk2.default.cyan(
1243
+ "robot-standards init"
1244
+ )} ${import_chalk2.default.yellow("\u4FEE\u590D\u95EE\u9898")}`
1245
+ );
1246
+ } else {
1247
+ console.log();
1248
+ console.log(` ${S2.OK} ${import_chalk2.default.green("\u6240\u6709\u68C0\u67E5\u901A\u8FC7!")}`);
1249
+ }
1250
+ console.log(S2.LINE);
1251
+ console.log();
1252
+ return failedCount === 0;
1253
+ }
1254
+ function printCheck(check) {
1255
+ const icon = check.status === "pass" ? S2.OK : check.status === "fail" ? S2.FAIL : S2.SKIP;
1256
+ console.log(` ${icon} ${check.name}`);
1257
+ if (check.message && check.status === "fail") {
1258
+ console.log(` ${import_chalk2.default.gray(check.message)}`);
1259
+ }
1260
+ }
1261
+ // Annotate the CommonJS export names for ESM import in node:
1262
+ 0 && (module.exports = {
1263
+ createLintStagedConfig,
1264
+ detectPackageManager,
1265
+ doctor,
1266
+ fileExists,
1267
+ generateLintStagedConfig,
1268
+ getExecCommand,
1269
+ getInstallCommand,
1270
+ getPackageManagerName,
1271
+ init,
1272
+ initGitRepository,
1273
+ isGitRepository,
1274
+ readFileContent,
1275
+ readJsonFile,
1276
+ updatePackageJson,
1277
+ writeFileContent,
1278
+ writeJsonFile
1279
+ });
1280
+ //# sourceMappingURL=index.cjs.map