@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/CHANGELOG.md +62 -0
- package/README.md +324 -0
- package/bin/robot-standards.js +64 -0
- package/dist/cli/doctor.cjs +276 -0
- package/dist/cli/doctor.cjs.map +1 -0
- package/dist/cli/doctor.d.cts +10 -0
- package/dist/cli/doctor.d.ts +10 -0
- package/dist/cli/doctor.js +241 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/init.cjs +1032 -0
- package/dist/cli/init.cjs.map +1 -0
- package/dist/cli/init.d.cts +31 -0
- package/dist/cli/init.d.ts +31 -0
- package/dist/cli/init.js +997 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/index.cjs +1280 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +86 -0
- package/dist/index.d.ts +86 -0
- package/dist/index.js +1228 -0
- package/dist/index.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,276 @@
|
|
|
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/cli/doctor.ts
|
|
31
|
+
var doctor_exports = {};
|
|
32
|
+
__export(doctor_exports, {
|
|
33
|
+
doctor: () => doctor
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(doctor_exports);
|
|
36
|
+
var import_node_path3 = require("path");
|
|
37
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
38
|
+
|
|
39
|
+
// src/utils/file.ts
|
|
40
|
+
var import_node_fs = require("fs");
|
|
41
|
+
var import_promises = require("fs/promises");
|
|
42
|
+
var import_node_path = require("path");
|
|
43
|
+
function fileExists(filePath) {
|
|
44
|
+
return (0, import_node_fs.existsSync)(filePath);
|
|
45
|
+
}
|
|
46
|
+
async function readFileContent(filePath) {
|
|
47
|
+
return await (0, import_promises.readFile)(filePath, "utf-8");
|
|
48
|
+
}
|
|
49
|
+
async function readJsonFile(filePath) {
|
|
50
|
+
const content = await readFileContent(filePath);
|
|
51
|
+
return JSON.parse(content);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/utils/git.ts
|
|
55
|
+
var import_node_fs2 = require("fs");
|
|
56
|
+
var import_node_path2 = require("path");
|
|
57
|
+
var import_execa = require("execa");
|
|
58
|
+
function isGitRepository(cwd = process.cwd()) {
|
|
59
|
+
return (0, import_node_fs2.existsSync)((0, import_node_path2.resolve)(cwd, ".git"));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/cli/doctor.ts
|
|
63
|
+
var BRAND = "#7C3AED";
|
|
64
|
+
var S = {
|
|
65
|
+
LOGO: import_chalk.default.hex(BRAND).bold("[RS]"),
|
|
66
|
+
OK: import_chalk.default.green("\u2714"),
|
|
67
|
+
FAIL: import_chalk.default.red("\u2716"),
|
|
68
|
+
WARN: import_chalk.default.yellow("\u25B2"),
|
|
69
|
+
SKIP: import_chalk.default.gray("\u25CB"),
|
|
70
|
+
LINE: import_chalk.default.gray("\u2500".repeat(48))
|
|
71
|
+
};
|
|
72
|
+
async function doctor(options = {}) {
|
|
73
|
+
const cwd = options.cwd || process.cwd();
|
|
74
|
+
console.log();
|
|
75
|
+
console.log(S.LINE);
|
|
76
|
+
console.log(
|
|
77
|
+
` ${S.LOGO} ${import_chalk.default.bold("Robot Standards")} ${import_chalk.default.gray("Doctor")}`
|
|
78
|
+
);
|
|
79
|
+
console.log(S.LINE);
|
|
80
|
+
console.log();
|
|
81
|
+
const checks = [];
|
|
82
|
+
const isGit = isGitRepository(cwd);
|
|
83
|
+
checks.push({
|
|
84
|
+
name: "Git \u4ED3\u5E93",
|
|
85
|
+
status: isGit ? "pass" : "fail",
|
|
86
|
+
message: isGit ? void 0 : "\u672A\u521D\u59CB\u5316 Git \u4ED3\u5E93\uFF0C\u8FD0\u884C git init"
|
|
87
|
+
});
|
|
88
|
+
let packageJson = {};
|
|
89
|
+
const packageJsonPath = (0, import_node_path3.resolve)(cwd, "package.json");
|
|
90
|
+
const hasPackageJson = fileExists(packageJsonPath);
|
|
91
|
+
if (hasPackageJson) {
|
|
92
|
+
try {
|
|
93
|
+
packageJson = await readJsonFile(packageJsonPath);
|
|
94
|
+
} catch {
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
checks.push({
|
|
98
|
+
name: "package.json",
|
|
99
|
+
status: "fail",
|
|
100
|
+
message: "\u7F3A\u5C11 package.json"
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
const allDeps = {
|
|
104
|
+
...packageJson.dependencies,
|
|
105
|
+
...packageJson.devDependencies
|
|
106
|
+
};
|
|
107
|
+
const hasCommitizen = !!allDeps["commitizen"];
|
|
108
|
+
const hasCommitlint = !!allDeps["@commitlint/cli"];
|
|
109
|
+
const hasHusky = !!allDeps["husky"];
|
|
110
|
+
const hasEslint = !!allDeps["eslint"];
|
|
111
|
+
const hasLintStaged = !!allDeps["lint-staged"];
|
|
112
|
+
const hasPrettier = !!allDeps["prettier"];
|
|
113
|
+
console.log(` ${import_chalk.default.bold("\u6838\u5FC3\u529F\u80FD")}`);
|
|
114
|
+
console.log();
|
|
115
|
+
if (hasHusky) {
|
|
116
|
+
const huskyDir = fileExists((0, import_node_path3.resolve)(cwd, ".husky"));
|
|
117
|
+
checks.push({
|
|
118
|
+
name: "Husky \u76EE\u5F55",
|
|
119
|
+
status: huskyDir ? "pass" : "fail",
|
|
120
|
+
message: huskyDir ? void 0 : "\u7F3A\u5C11 .husky \u76EE\u5F55"
|
|
121
|
+
});
|
|
122
|
+
const commitMsg = fileExists((0, import_node_path3.resolve)(cwd, ".husky/commit-msg"));
|
|
123
|
+
checks.push({
|
|
124
|
+
name: "commit-msg hook",
|
|
125
|
+
status: commitMsg ? "pass" : "fail",
|
|
126
|
+
message: commitMsg ? void 0 : "\u7F3A\u5C11 commit-msg hook"
|
|
127
|
+
});
|
|
128
|
+
} else {
|
|
129
|
+
checks.push({
|
|
130
|
+
name: "Husky",
|
|
131
|
+
status: "fail",
|
|
132
|
+
message: "\u672A\u5B89\u88C5 husky"
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
if (hasCommitlint) {
|
|
136
|
+
const hasConfig = fileExists((0, import_node_path3.resolve)(cwd, "commitlint.config.cjs")) || fileExists((0, import_node_path3.resolve)(cwd, "commitlint.config.js")) || fileExists((0, import_node_path3.resolve)(cwd, "commitlint.config.ts"));
|
|
137
|
+
checks.push({
|
|
138
|
+
name: "Commitlint \u914D\u7F6E",
|
|
139
|
+
status: hasConfig ? "pass" : "fail",
|
|
140
|
+
message: hasConfig ? void 0 : "\u7F3A\u5C11 commitlint.config.*"
|
|
141
|
+
});
|
|
142
|
+
} else {
|
|
143
|
+
checks.push({
|
|
144
|
+
name: "Commitlint",
|
|
145
|
+
status: "fail",
|
|
146
|
+
message: "\u672A\u5B89\u88C5 @commitlint/cli"
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
if (hasCommitizen) {
|
|
150
|
+
const hasCzConfig = fileExists((0, import_node_path3.resolve)(cwd, ".cz-config.cjs")) || fileExists((0, import_node_path3.resolve)(cwd, ".cz-config.js"));
|
|
151
|
+
checks.push({
|
|
152
|
+
name: "Commitizen \u914D\u7F6E",
|
|
153
|
+
status: hasCzConfig ? "pass" : "fail",
|
|
154
|
+
message: hasCzConfig ? void 0 : "\u7F3A\u5C11 .cz-config.*"
|
|
155
|
+
});
|
|
156
|
+
const hasCommitizenPath = !!packageJson.config?.commitizen;
|
|
157
|
+
checks.push({
|
|
158
|
+
name: "commitizen path \u914D\u7F6E",
|
|
159
|
+
status: hasCommitizenPath ? "pass" : "fail",
|
|
160
|
+
message: hasCommitizenPath ? void 0 : "package.json \u4E2D\u7F3A\u5C11 config.commitizen"
|
|
161
|
+
});
|
|
162
|
+
} else {
|
|
163
|
+
checks.push({
|
|
164
|
+
name: "Commitizen",
|
|
165
|
+
status: "fail",
|
|
166
|
+
message: "\u672A\u5B89\u88C5 commitizen"
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
const hasCzScript = !!packageJson.scripts?.cz;
|
|
170
|
+
checks.push({
|
|
171
|
+
name: "cz \u811A\u672C",
|
|
172
|
+
status: hasCzScript ? "pass" : "fail",
|
|
173
|
+
message: hasCzScript ? void 0 : "\u7F3A\u5C11 cz \u811A\u672C (bun run cz)"
|
|
174
|
+
});
|
|
175
|
+
const coreChecks = checks.slice();
|
|
176
|
+
for (const check of coreChecks) {
|
|
177
|
+
printCheck(check);
|
|
178
|
+
}
|
|
179
|
+
const extraChecks = [];
|
|
180
|
+
if (hasEslint) {
|
|
181
|
+
console.log();
|
|
182
|
+
console.log(` ${import_chalk.default.bold("\u4EE3\u7801\u68C0\u67E5")}`);
|
|
183
|
+
console.log();
|
|
184
|
+
const hasEslintConfig = fileExists((0, import_node_path3.resolve)(cwd, "eslint.config.ts")) || fileExists((0, import_node_path3.resolve)(cwd, "eslint.config.js")) || fileExists((0, import_node_path3.resolve)(cwd, "eslint.config.mjs"));
|
|
185
|
+
const eslintCheck = {
|
|
186
|
+
name: "ESLint \u914D\u7F6E",
|
|
187
|
+
status: hasEslintConfig ? "pass" : "fail",
|
|
188
|
+
message: hasEslintConfig ? void 0 : "\u7F3A\u5C11 eslint.config.*"
|
|
189
|
+
};
|
|
190
|
+
extraChecks.push(eslintCheck);
|
|
191
|
+
printCheck(eslintCheck);
|
|
192
|
+
if (hasHusky) {
|
|
193
|
+
const preCommit = fileExists((0, import_node_path3.resolve)(cwd, ".husky/pre-commit"));
|
|
194
|
+
const preCommitCheck = {
|
|
195
|
+
name: "pre-commit hook",
|
|
196
|
+
status: preCommit ? "pass" : "fail",
|
|
197
|
+
message: preCommit ? void 0 : "\u7F3A\u5C11 pre-commit hook"
|
|
198
|
+
};
|
|
199
|
+
extraChecks.push(preCommitCheck);
|
|
200
|
+
printCheck(preCommitCheck);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (hasLintStaged) {
|
|
204
|
+
const lintStagedConfig = !!packageJson["lint-staged"];
|
|
205
|
+
const lintStagedCheck = {
|
|
206
|
+
name: "lint-staged \u914D\u7F6E",
|
|
207
|
+
status: lintStagedConfig ? "pass" : "fail",
|
|
208
|
+
message: lintStagedConfig ? void 0 : "package.json \u4E2D\u7F3A\u5C11 lint-staged \u914D\u7F6E"
|
|
209
|
+
};
|
|
210
|
+
extraChecks.push(lintStagedCheck);
|
|
211
|
+
printCheck(lintStagedCheck);
|
|
212
|
+
}
|
|
213
|
+
if (hasPrettier) {
|
|
214
|
+
console.log();
|
|
215
|
+
console.log(` ${import_chalk.default.bold("\u4EE3\u7801\u683C\u5F0F\u5316")}`);
|
|
216
|
+
console.log();
|
|
217
|
+
const hasPrettierConfig = fileExists((0, import_node_path3.resolve)(cwd, ".prettierrc.cjs")) || fileExists((0, import_node_path3.resolve)(cwd, ".prettierrc.js")) || fileExists((0, import_node_path3.resolve)(cwd, ".prettierrc.json")) || fileExists((0, import_node_path3.resolve)(cwd, ".prettierrc"));
|
|
218
|
+
const prettierCheck = {
|
|
219
|
+
name: "Prettier \u914D\u7F6E",
|
|
220
|
+
status: hasPrettierConfig ? "pass" : "fail",
|
|
221
|
+
message: hasPrettierConfig ? void 0 : "\u7F3A\u5C11 .prettierrc.*"
|
|
222
|
+
};
|
|
223
|
+
extraChecks.push(prettierCheck);
|
|
224
|
+
printCheck(prettierCheck);
|
|
225
|
+
}
|
|
226
|
+
const hasEditorConfig = fileExists((0, import_node_path3.resolve)(cwd, ".editorconfig"));
|
|
227
|
+
if (hasEditorConfig) {
|
|
228
|
+
}
|
|
229
|
+
const notInstalled = [];
|
|
230
|
+
if (!hasEslint) notInstalled.push("ESLint");
|
|
231
|
+
if (!hasLintStaged) notInstalled.push("lint-staged");
|
|
232
|
+
if (!hasPrettier) notInstalled.push("Prettier");
|
|
233
|
+
if (!hasEditorConfig) notInstalled.push("EditorConfig");
|
|
234
|
+
if (notInstalled.length > 0) {
|
|
235
|
+
console.log();
|
|
236
|
+
console.log(` ${import_chalk.default.bold("\u672A\u542F\u7528\u7684\u529F\u80FD")}`);
|
|
237
|
+
console.log();
|
|
238
|
+
for (const name of notInstalled) {
|
|
239
|
+
console.log(` ${S.SKIP} ${import_chalk.default.gray(name)}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const allChecks = [...coreChecks, ...extraChecks];
|
|
243
|
+
const passedCount = allChecks.filter((c) => c.status === "pass").length;
|
|
244
|
+
const failedCount = allChecks.filter((c) => c.status === "fail").length;
|
|
245
|
+
console.log();
|
|
246
|
+
console.log(S.LINE);
|
|
247
|
+
console.log(
|
|
248
|
+
` ${import_chalk.default.bold("\u603B\u8BA1:")} ${import_chalk.default.green(`${passedCount} \u901A\u8FC7`)} ${failedCount > 0 ? import_chalk.default.red(`${failedCount} \u5931\u8D25`) : import_chalk.default.gray("0 \u5931\u8D25")}`
|
|
249
|
+
);
|
|
250
|
+
if (failedCount > 0) {
|
|
251
|
+
console.log();
|
|
252
|
+
console.log(
|
|
253
|
+
` ${S.WARN} ${import_chalk.default.yellow("\u8FD0\u884C")} ${import_chalk.default.cyan(
|
|
254
|
+
"robot-standards init"
|
|
255
|
+
)} ${import_chalk.default.yellow("\u4FEE\u590D\u95EE\u9898")}`
|
|
256
|
+
);
|
|
257
|
+
} else {
|
|
258
|
+
console.log();
|
|
259
|
+
console.log(` ${S.OK} ${import_chalk.default.green("\u6240\u6709\u68C0\u67E5\u901A\u8FC7!")}`);
|
|
260
|
+
}
|
|
261
|
+
console.log(S.LINE);
|
|
262
|
+
console.log();
|
|
263
|
+
return failedCount === 0;
|
|
264
|
+
}
|
|
265
|
+
function printCheck(check) {
|
|
266
|
+
const icon = check.status === "pass" ? S.OK : check.status === "fail" ? S.FAIL : S.SKIP;
|
|
267
|
+
console.log(` ${icon} ${check.name}`);
|
|
268
|
+
if (check.message && check.status === "fail") {
|
|
269
|
+
console.log(` ${import_chalk.default.gray(check.message)}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
273
|
+
0 && (module.exports = {
|
|
274
|
+
doctor
|
|
275
|
+
});
|
|
276
|
+
//# sourceMappingURL=doctor.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/doctor.ts","../../src/utils/file.ts","../../src/utils/git.ts"],"sourcesContent":["/*\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-13\r\n * @Description: Doctor 命令 - 智能诊断 Git 标准化配置\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\nimport { resolve } from \"node:path\";\r\nimport chalk from \"chalk\";\r\nimport { fileExists, readJsonFile } from \"../utils/file\";\r\nimport { isGitRepository } from \"../utils/git\";\r\n\r\n// ─── 品牌 & 符号 ──────────────────────────────────────────────────\r\nconst BRAND = \"#7C3AED\";\r\nconst S = {\r\n LOGO: chalk.hex(BRAND).bold(\"[RS]\"),\r\n OK: chalk.green(\"✔\"),\r\n FAIL: chalk.red(\"✖\"),\r\n WARN: chalk.yellow(\"▲\"),\r\n SKIP: chalk.gray(\"○\"),\r\n LINE: chalk.gray(\"─\".repeat(48)),\r\n};\r\n\r\nexport interface DoctorOptions {\r\n cwd?: string;\r\n}\r\n\r\ninterface CheckResult {\r\n name: string;\r\n status: \"pass\" | \"fail\" | \"skip\";\r\n message?: string;\r\n}\r\n\r\n/**\r\n * Doctor 命令主函数\r\n * 根据已安装的功能智能检测,未安装的功能只做提示不标记为失败\r\n */\r\nexport async function doctor(options: DoctorOptions = {}) {\r\n const cwd = options.cwd || process.cwd();\r\n\r\n // ── Banner ──\r\n console.log();\r\n console.log(S.LINE);\r\n console.log(\r\n ` ${S.LOGO} ${chalk.bold(\"Robot Standards\")} ${chalk.gray(\"Doctor\")}`,\r\n );\r\n console.log(S.LINE);\r\n console.log();\r\n\r\n const checks: CheckResult[] = [];\r\n\r\n // ── 1. 基础环境 ──\r\n const isGit = isGitRepository(cwd);\r\n checks.push({\r\n name: \"Git 仓库\",\r\n status: isGit ? \"pass\" : \"fail\",\r\n message: isGit ? undefined : \"未初始化 Git 仓库,运行 git init\",\r\n });\r\n\r\n // ── 2. 读取 package.json 探测已安装功能 ──\r\n let packageJson: any = {};\r\n const packageJsonPath = resolve(cwd, \"package.json\");\r\n const hasPackageJson = fileExists(packageJsonPath);\r\n\r\n if (hasPackageJson) {\r\n try {\r\n packageJson = await readJsonFile(packageJsonPath);\r\n } catch {\r\n // ignore\r\n }\r\n } else {\r\n checks.push({\r\n name: \"package.json\",\r\n status: \"fail\",\r\n message: \"缺少 package.json\",\r\n });\r\n }\r\n\r\n const allDeps = {\r\n ...packageJson.dependencies,\r\n ...packageJson.devDependencies,\r\n };\r\n\r\n // 检测已安装的功能模块\r\n const hasCommitizen = !!allDeps[\"commitizen\"];\r\n const hasCommitlint = !!allDeps[\"@commitlint/cli\"];\r\n const hasHusky = !!allDeps[\"husky\"];\r\n const hasEslint = !!allDeps[\"eslint\"];\r\n const hasLintStaged = !!allDeps[\"lint-staged\"];\r\n const hasPrettier = !!allDeps[\"prettier\"];\r\n\r\n // ── 3. 核心功能检查(始终检查) ──\r\n console.log(` ${chalk.bold(\"核心功能\")}`);\r\n console.log();\r\n\r\n // Husky\r\n if (hasHusky) {\r\n const huskyDir = fileExists(resolve(cwd, \".husky\"));\r\n checks.push({\r\n name: \"Husky 目录\",\r\n status: huskyDir ? \"pass\" : \"fail\",\r\n message: huskyDir ? undefined : \"缺少 .husky 目录\",\r\n });\r\n\r\n const commitMsg = fileExists(resolve(cwd, \".husky/commit-msg\"));\r\n checks.push({\r\n name: \"commit-msg hook\",\r\n status: commitMsg ? \"pass\" : \"fail\",\r\n message: commitMsg ? undefined : \"缺少 commit-msg hook\",\r\n });\r\n } else {\r\n checks.push({\r\n name: \"Husky\",\r\n status: \"fail\",\r\n message: \"未安装 husky\",\r\n });\r\n }\r\n\r\n // Commitlint\r\n if (hasCommitlint) {\r\n const hasConfig =\r\n fileExists(resolve(cwd, \"commitlint.config.cjs\")) ||\r\n fileExists(resolve(cwd, \"commitlint.config.js\")) ||\r\n fileExists(resolve(cwd, \"commitlint.config.ts\"));\r\n checks.push({\r\n name: \"Commitlint 配置\",\r\n status: hasConfig ? \"pass\" : \"fail\",\r\n message: hasConfig ? undefined : \"缺少 commitlint.config.*\",\r\n });\r\n } else {\r\n checks.push({\r\n name: \"Commitlint\",\r\n status: \"fail\",\r\n message: \"未安装 @commitlint/cli\",\r\n });\r\n }\r\n\r\n // Commitizen\r\n if (hasCommitizen) {\r\n const hasCzConfig =\r\n fileExists(resolve(cwd, \".cz-config.cjs\")) ||\r\n fileExists(resolve(cwd, \".cz-config.js\"));\r\n checks.push({\r\n name: \"Commitizen 配置\",\r\n status: hasCzConfig ? \"pass\" : \"fail\",\r\n message: hasCzConfig ? undefined : \"缺少 .cz-config.*\",\r\n });\r\n\r\n const hasCommitizenPath = !!packageJson.config?.commitizen;\r\n checks.push({\r\n name: \"commitizen path 配置\",\r\n status: hasCommitizenPath ? \"pass\" : \"fail\",\r\n message: hasCommitizenPath\r\n ? undefined\r\n : \"package.json 中缺少 config.commitizen\",\r\n });\r\n } else {\r\n checks.push({\r\n name: \"Commitizen\",\r\n status: \"fail\",\r\n message: \"未安装 commitizen\",\r\n });\r\n }\r\n\r\n // cz 脚本\r\n const hasCzScript = !!packageJson.scripts?.cz;\r\n checks.push({\r\n name: \"cz 脚本\",\r\n status: hasCzScript ? \"pass\" : \"fail\",\r\n message: hasCzScript ? undefined : \"缺少 cz 脚本 (bun run cz)\",\r\n });\r\n\r\n // ── 输出核心检查结果 ──\r\n const coreChecks = checks.slice();\r\n for (const check of coreChecks) {\r\n printCheck(check);\r\n }\r\n\r\n // ── 4. 附加功能检查(仅检测已安装的) ──\r\n const extraChecks: CheckResult[] = [];\r\n\r\n if (hasEslint) {\r\n console.log();\r\n console.log(` ${chalk.bold(\"代码检查\")}`);\r\n console.log();\r\n\r\n const hasEslintConfig =\r\n fileExists(resolve(cwd, \"eslint.config.ts\")) ||\r\n fileExists(resolve(cwd, \"eslint.config.js\")) ||\r\n fileExists(resolve(cwd, \"eslint.config.mjs\"));\r\n const eslintCheck: CheckResult = {\r\n name: \"ESLint 配置\",\r\n status: hasEslintConfig ? \"pass\" : \"fail\",\r\n message: hasEslintConfig ? undefined : \"缺少 eslint.config.*\",\r\n };\r\n extraChecks.push(eslintCheck);\r\n printCheck(eslintCheck);\r\n\r\n if (hasHusky) {\r\n const preCommit = fileExists(resolve(cwd, \".husky/pre-commit\"));\r\n const preCommitCheck: CheckResult = {\r\n name: \"pre-commit hook\",\r\n status: preCommit ? \"pass\" : \"fail\",\r\n message: preCommit ? undefined : \"缺少 pre-commit hook\",\r\n };\r\n extraChecks.push(preCommitCheck);\r\n printCheck(preCommitCheck);\r\n }\r\n }\r\n\r\n if (hasLintStaged) {\r\n const lintStagedConfig = !!packageJson[\"lint-staged\"];\r\n const lintStagedCheck: CheckResult = {\r\n name: \"lint-staged 配置\",\r\n status: lintStagedConfig ? \"pass\" : \"fail\",\r\n message: lintStagedConfig\r\n ? undefined\r\n : \"package.json 中缺少 lint-staged 配置\",\r\n };\r\n extraChecks.push(lintStagedCheck);\r\n printCheck(lintStagedCheck);\r\n }\r\n\r\n if (hasPrettier) {\r\n console.log();\r\n console.log(` ${chalk.bold(\"代码格式化\")}`);\r\n console.log();\r\n\r\n const hasPrettierConfig =\r\n fileExists(resolve(cwd, \".prettierrc.cjs\")) ||\r\n fileExists(resolve(cwd, \".prettierrc.js\")) ||\r\n fileExists(resolve(cwd, \".prettierrc.json\")) ||\r\n fileExists(resolve(cwd, \".prettierrc\"));\r\n const prettierCheck: CheckResult = {\r\n name: \"Prettier 配置\",\r\n status: hasPrettierConfig ? \"pass\" : \"fail\",\r\n message: hasPrettierConfig ? undefined : \"缺少 .prettierrc.*\",\r\n };\r\n extraChecks.push(prettierCheck);\r\n printCheck(prettierCheck);\r\n }\r\n\r\n // EditorConfig(不依赖 package.json,直接检测文件)\r\n const hasEditorConfig = fileExists(resolve(cwd, \".editorconfig\"));\r\n if (hasEditorConfig) {\r\n // 只在存在时标记 pass,不存在不报错(属于可选功能)\r\n }\r\n\r\n // ── 5. 未安装功能提示 ──\r\n const notInstalled: string[] = [];\r\n if (!hasEslint) notInstalled.push(\"ESLint\");\r\n if (!hasLintStaged) notInstalled.push(\"lint-staged\");\r\n if (!hasPrettier) notInstalled.push(\"Prettier\");\r\n if (!hasEditorConfig) notInstalled.push(\"EditorConfig\");\r\n\r\n if (notInstalled.length > 0) {\r\n console.log();\r\n console.log(` ${chalk.bold(\"未启用的功能\")}`);\r\n console.log();\r\n for (const name of notInstalled) {\r\n console.log(` ${S.SKIP} ${chalk.gray(name)}`);\r\n }\r\n }\r\n\r\n // ── 6. 汇总 ──\r\n const allChecks = [...coreChecks, ...extraChecks];\r\n const passedCount = allChecks.filter((c) => c.status === \"pass\").length;\r\n const failedCount = allChecks.filter((c) => c.status === \"fail\").length;\r\n\r\n console.log();\r\n console.log(S.LINE);\r\n console.log(\r\n ` ${chalk.bold(\"总计:\")} ${chalk.green(`${passedCount} 通过`)} ${\r\n failedCount > 0 ? chalk.red(`${failedCount} 失败`) : chalk.gray(\"0 失败\")\r\n }`,\r\n );\r\n\r\n if (failedCount > 0) {\r\n console.log();\r\n console.log(\r\n ` ${S.WARN} ${chalk.yellow(\"运行\")} ${chalk.cyan(\r\n \"robot-standards init\",\r\n )} ${chalk.yellow(\"修复问题\")}`,\r\n );\r\n } else {\r\n console.log();\r\n console.log(` ${S.OK} ${chalk.green(\"所有检查通过!\")}`);\r\n }\r\n\r\n console.log(S.LINE);\r\n console.log();\r\n\r\n return failedCount === 0;\r\n}\r\n\r\nfunction printCheck(check: CheckResult) {\r\n const icon =\r\n check.status === \"pass\" ? S.OK : check.status === \"fail\" ? S.FAIL : S.SKIP;\r\n console.log(` ${icon} ${check.name}`);\r\n if (check.message && check.status === \"fail\") {\r\n console.log(` ${chalk.gray(check.message)}`);\r\n }\r\n}\r\n","/*\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-13\r\n * @Description: 文件操作工具\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\nimport { existsSync } from \"node:fs\";\r\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\r\nimport { resolve, dirname } from \"node:path\";\r\n\r\n/**\r\n * 检查文件是否存在\r\n */\r\nexport function fileExists(filePath: string): boolean {\r\n return existsSync(filePath);\r\n}\r\n\r\n/**\r\n * 读取文件内容\r\n */\r\nexport async function readFileContent(filePath: string): Promise<string> {\r\n return await readFile(filePath, \"utf-8\");\r\n}\r\n\r\n/**\r\n * 写入文件内容\r\n */\r\nexport async function writeFileContent(\r\n filePath: string,\r\n content: string,\r\n): Promise<void> {\r\n const dir = dirname(filePath);\r\n if (!existsSync(dir)) {\r\n await mkdir(dir, { recursive: true });\r\n }\r\n await writeFile(filePath, content, \"utf-8\");\r\n}\r\n\r\n/**\r\n * 读取并解析 JSON 文件\r\n */\r\nexport async function readJsonFile<T = any>(filePath: string): Promise<T> {\r\n const content = await readFileContent(filePath);\r\n return JSON.parse(content) as T;\r\n}\r\n\r\n/**\r\n * 写入 JSON 文件\r\n */\r\nexport async function writeJsonFile(\r\n filePath: string,\r\n data: any,\r\n pretty: boolean = true,\r\n): Promise<void> {\r\n const content = pretty\r\n ? JSON.stringify(data, null, 2) + \"\\n\"\r\n : JSON.stringify(data);\r\n await writeFileContent(filePath, content);\r\n}\r\n\r\n/**\r\n * 更新 package.json\r\n */\r\nexport async function updatePackageJson(\r\n updates: Record<string, any>,\r\n cwd: string = process.cwd(),\r\n): Promise<void> {\r\n const packageJsonPath = resolve(cwd, \"package.json\");\r\n const packageJson = await readJsonFile(packageJsonPath);\r\n const updated = { ...packageJson, ...updates };\r\n await writeJsonFile(packageJsonPath, updated);\r\n}\r\n","/*\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-13\r\n * @Description: Git 工具函数\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\nimport { existsSync } from \"node:fs\";\r\nimport { resolve } from \"node:path\";\r\nimport { execa } from \"execa\";\r\n\r\n/**\r\n * 检查是否在 Git 仓库中\r\n */\r\nexport function isGitRepository(cwd: string = process.cwd()): boolean {\r\n return existsSync(resolve(cwd, \".git\"));\r\n}\r\n\r\n/**\r\n * 初始化 Git 仓库\r\n */\r\nexport async function initGitRepository(\r\n cwd: string = process.cwd(),\r\n): Promise<void> {\r\n if (!isGitRepository(cwd)) {\r\n await execa(\"git\", [\"init\"], { cwd });\r\n }\r\n}\r\n"],"mappings":"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","names":["import_node_path","import_node_fs","import_node_path","chalk"]}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// src/cli/doctor.ts
|
|
2
|
+
import { resolve as resolve3 } from "path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
|
|
5
|
+
// src/utils/file.ts
|
|
6
|
+
import { existsSync } from "fs";
|
|
7
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
8
|
+
import { resolve, dirname } from "path";
|
|
9
|
+
function fileExists(filePath) {
|
|
10
|
+
return existsSync(filePath);
|
|
11
|
+
}
|
|
12
|
+
async function readFileContent(filePath) {
|
|
13
|
+
return await readFile(filePath, "utf-8");
|
|
14
|
+
}
|
|
15
|
+
async function readJsonFile(filePath) {
|
|
16
|
+
const content = await readFileContent(filePath);
|
|
17
|
+
return JSON.parse(content);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/utils/git.ts
|
|
21
|
+
import { existsSync as existsSync2 } from "fs";
|
|
22
|
+
import { resolve as resolve2 } from "path";
|
|
23
|
+
import { execa } from "execa";
|
|
24
|
+
function isGitRepository(cwd = process.cwd()) {
|
|
25
|
+
return existsSync2(resolve2(cwd, ".git"));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/cli/doctor.ts
|
|
29
|
+
var BRAND = "#7C3AED";
|
|
30
|
+
var S = {
|
|
31
|
+
LOGO: chalk.hex(BRAND).bold("[RS]"),
|
|
32
|
+
OK: chalk.green("\u2714"),
|
|
33
|
+
FAIL: chalk.red("\u2716"),
|
|
34
|
+
WARN: chalk.yellow("\u25B2"),
|
|
35
|
+
SKIP: chalk.gray("\u25CB"),
|
|
36
|
+
LINE: chalk.gray("\u2500".repeat(48))
|
|
37
|
+
};
|
|
38
|
+
async function doctor(options = {}) {
|
|
39
|
+
const cwd = options.cwd || process.cwd();
|
|
40
|
+
console.log();
|
|
41
|
+
console.log(S.LINE);
|
|
42
|
+
console.log(
|
|
43
|
+
` ${S.LOGO} ${chalk.bold("Robot Standards")} ${chalk.gray("Doctor")}`
|
|
44
|
+
);
|
|
45
|
+
console.log(S.LINE);
|
|
46
|
+
console.log();
|
|
47
|
+
const checks = [];
|
|
48
|
+
const isGit = isGitRepository(cwd);
|
|
49
|
+
checks.push({
|
|
50
|
+
name: "Git \u4ED3\u5E93",
|
|
51
|
+
status: isGit ? "pass" : "fail",
|
|
52
|
+
message: isGit ? void 0 : "\u672A\u521D\u59CB\u5316 Git \u4ED3\u5E93\uFF0C\u8FD0\u884C git init"
|
|
53
|
+
});
|
|
54
|
+
let packageJson = {};
|
|
55
|
+
const packageJsonPath = resolve3(cwd, "package.json");
|
|
56
|
+
const hasPackageJson = fileExists(packageJsonPath);
|
|
57
|
+
if (hasPackageJson) {
|
|
58
|
+
try {
|
|
59
|
+
packageJson = await readJsonFile(packageJsonPath);
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
checks.push({
|
|
64
|
+
name: "package.json",
|
|
65
|
+
status: "fail",
|
|
66
|
+
message: "\u7F3A\u5C11 package.json"
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const allDeps = {
|
|
70
|
+
...packageJson.dependencies,
|
|
71
|
+
...packageJson.devDependencies
|
|
72
|
+
};
|
|
73
|
+
const hasCommitizen = !!allDeps["commitizen"];
|
|
74
|
+
const hasCommitlint = !!allDeps["@commitlint/cli"];
|
|
75
|
+
const hasHusky = !!allDeps["husky"];
|
|
76
|
+
const hasEslint = !!allDeps["eslint"];
|
|
77
|
+
const hasLintStaged = !!allDeps["lint-staged"];
|
|
78
|
+
const hasPrettier = !!allDeps["prettier"];
|
|
79
|
+
console.log(` ${chalk.bold("\u6838\u5FC3\u529F\u80FD")}`);
|
|
80
|
+
console.log();
|
|
81
|
+
if (hasHusky) {
|
|
82
|
+
const huskyDir = fileExists(resolve3(cwd, ".husky"));
|
|
83
|
+
checks.push({
|
|
84
|
+
name: "Husky \u76EE\u5F55",
|
|
85
|
+
status: huskyDir ? "pass" : "fail",
|
|
86
|
+
message: huskyDir ? void 0 : "\u7F3A\u5C11 .husky \u76EE\u5F55"
|
|
87
|
+
});
|
|
88
|
+
const commitMsg = fileExists(resolve3(cwd, ".husky/commit-msg"));
|
|
89
|
+
checks.push({
|
|
90
|
+
name: "commit-msg hook",
|
|
91
|
+
status: commitMsg ? "pass" : "fail",
|
|
92
|
+
message: commitMsg ? void 0 : "\u7F3A\u5C11 commit-msg hook"
|
|
93
|
+
});
|
|
94
|
+
} else {
|
|
95
|
+
checks.push({
|
|
96
|
+
name: "Husky",
|
|
97
|
+
status: "fail",
|
|
98
|
+
message: "\u672A\u5B89\u88C5 husky"
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (hasCommitlint) {
|
|
102
|
+
const hasConfig = fileExists(resolve3(cwd, "commitlint.config.cjs")) || fileExists(resolve3(cwd, "commitlint.config.js")) || fileExists(resolve3(cwd, "commitlint.config.ts"));
|
|
103
|
+
checks.push({
|
|
104
|
+
name: "Commitlint \u914D\u7F6E",
|
|
105
|
+
status: hasConfig ? "pass" : "fail",
|
|
106
|
+
message: hasConfig ? void 0 : "\u7F3A\u5C11 commitlint.config.*"
|
|
107
|
+
});
|
|
108
|
+
} else {
|
|
109
|
+
checks.push({
|
|
110
|
+
name: "Commitlint",
|
|
111
|
+
status: "fail",
|
|
112
|
+
message: "\u672A\u5B89\u88C5 @commitlint/cli"
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
if (hasCommitizen) {
|
|
116
|
+
const hasCzConfig = fileExists(resolve3(cwd, ".cz-config.cjs")) || fileExists(resolve3(cwd, ".cz-config.js"));
|
|
117
|
+
checks.push({
|
|
118
|
+
name: "Commitizen \u914D\u7F6E",
|
|
119
|
+
status: hasCzConfig ? "pass" : "fail",
|
|
120
|
+
message: hasCzConfig ? void 0 : "\u7F3A\u5C11 .cz-config.*"
|
|
121
|
+
});
|
|
122
|
+
const hasCommitizenPath = !!packageJson.config?.commitizen;
|
|
123
|
+
checks.push({
|
|
124
|
+
name: "commitizen path \u914D\u7F6E",
|
|
125
|
+
status: hasCommitizenPath ? "pass" : "fail",
|
|
126
|
+
message: hasCommitizenPath ? void 0 : "package.json \u4E2D\u7F3A\u5C11 config.commitizen"
|
|
127
|
+
});
|
|
128
|
+
} else {
|
|
129
|
+
checks.push({
|
|
130
|
+
name: "Commitizen",
|
|
131
|
+
status: "fail",
|
|
132
|
+
message: "\u672A\u5B89\u88C5 commitizen"
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
const hasCzScript = !!packageJson.scripts?.cz;
|
|
136
|
+
checks.push({
|
|
137
|
+
name: "cz \u811A\u672C",
|
|
138
|
+
status: hasCzScript ? "pass" : "fail",
|
|
139
|
+
message: hasCzScript ? void 0 : "\u7F3A\u5C11 cz \u811A\u672C (bun run cz)"
|
|
140
|
+
});
|
|
141
|
+
const coreChecks = checks.slice();
|
|
142
|
+
for (const check of coreChecks) {
|
|
143
|
+
printCheck(check);
|
|
144
|
+
}
|
|
145
|
+
const extraChecks = [];
|
|
146
|
+
if (hasEslint) {
|
|
147
|
+
console.log();
|
|
148
|
+
console.log(` ${chalk.bold("\u4EE3\u7801\u68C0\u67E5")}`);
|
|
149
|
+
console.log();
|
|
150
|
+
const hasEslintConfig = fileExists(resolve3(cwd, "eslint.config.ts")) || fileExists(resolve3(cwd, "eslint.config.js")) || fileExists(resolve3(cwd, "eslint.config.mjs"));
|
|
151
|
+
const eslintCheck = {
|
|
152
|
+
name: "ESLint \u914D\u7F6E",
|
|
153
|
+
status: hasEslintConfig ? "pass" : "fail",
|
|
154
|
+
message: hasEslintConfig ? void 0 : "\u7F3A\u5C11 eslint.config.*"
|
|
155
|
+
};
|
|
156
|
+
extraChecks.push(eslintCheck);
|
|
157
|
+
printCheck(eslintCheck);
|
|
158
|
+
if (hasHusky) {
|
|
159
|
+
const preCommit = fileExists(resolve3(cwd, ".husky/pre-commit"));
|
|
160
|
+
const preCommitCheck = {
|
|
161
|
+
name: "pre-commit hook",
|
|
162
|
+
status: preCommit ? "pass" : "fail",
|
|
163
|
+
message: preCommit ? void 0 : "\u7F3A\u5C11 pre-commit hook"
|
|
164
|
+
};
|
|
165
|
+
extraChecks.push(preCommitCheck);
|
|
166
|
+
printCheck(preCommitCheck);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (hasLintStaged) {
|
|
170
|
+
const lintStagedConfig = !!packageJson["lint-staged"];
|
|
171
|
+
const lintStagedCheck = {
|
|
172
|
+
name: "lint-staged \u914D\u7F6E",
|
|
173
|
+
status: lintStagedConfig ? "pass" : "fail",
|
|
174
|
+
message: lintStagedConfig ? void 0 : "package.json \u4E2D\u7F3A\u5C11 lint-staged \u914D\u7F6E"
|
|
175
|
+
};
|
|
176
|
+
extraChecks.push(lintStagedCheck);
|
|
177
|
+
printCheck(lintStagedCheck);
|
|
178
|
+
}
|
|
179
|
+
if (hasPrettier) {
|
|
180
|
+
console.log();
|
|
181
|
+
console.log(` ${chalk.bold("\u4EE3\u7801\u683C\u5F0F\u5316")}`);
|
|
182
|
+
console.log();
|
|
183
|
+
const hasPrettierConfig = fileExists(resolve3(cwd, ".prettierrc.cjs")) || fileExists(resolve3(cwd, ".prettierrc.js")) || fileExists(resolve3(cwd, ".prettierrc.json")) || fileExists(resolve3(cwd, ".prettierrc"));
|
|
184
|
+
const prettierCheck = {
|
|
185
|
+
name: "Prettier \u914D\u7F6E",
|
|
186
|
+
status: hasPrettierConfig ? "pass" : "fail",
|
|
187
|
+
message: hasPrettierConfig ? void 0 : "\u7F3A\u5C11 .prettierrc.*"
|
|
188
|
+
};
|
|
189
|
+
extraChecks.push(prettierCheck);
|
|
190
|
+
printCheck(prettierCheck);
|
|
191
|
+
}
|
|
192
|
+
const hasEditorConfig = fileExists(resolve3(cwd, ".editorconfig"));
|
|
193
|
+
if (hasEditorConfig) {
|
|
194
|
+
}
|
|
195
|
+
const notInstalled = [];
|
|
196
|
+
if (!hasEslint) notInstalled.push("ESLint");
|
|
197
|
+
if (!hasLintStaged) notInstalled.push("lint-staged");
|
|
198
|
+
if (!hasPrettier) notInstalled.push("Prettier");
|
|
199
|
+
if (!hasEditorConfig) notInstalled.push("EditorConfig");
|
|
200
|
+
if (notInstalled.length > 0) {
|
|
201
|
+
console.log();
|
|
202
|
+
console.log(` ${chalk.bold("\u672A\u542F\u7528\u7684\u529F\u80FD")}`);
|
|
203
|
+
console.log();
|
|
204
|
+
for (const name of notInstalled) {
|
|
205
|
+
console.log(` ${S.SKIP} ${chalk.gray(name)}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const allChecks = [...coreChecks, ...extraChecks];
|
|
209
|
+
const passedCount = allChecks.filter((c) => c.status === "pass").length;
|
|
210
|
+
const failedCount = allChecks.filter((c) => c.status === "fail").length;
|
|
211
|
+
console.log();
|
|
212
|
+
console.log(S.LINE);
|
|
213
|
+
console.log(
|
|
214
|
+
` ${chalk.bold("\u603B\u8BA1:")} ${chalk.green(`${passedCount} \u901A\u8FC7`)} ${failedCount > 0 ? chalk.red(`${failedCount} \u5931\u8D25`) : chalk.gray("0 \u5931\u8D25")}`
|
|
215
|
+
);
|
|
216
|
+
if (failedCount > 0) {
|
|
217
|
+
console.log();
|
|
218
|
+
console.log(
|
|
219
|
+
` ${S.WARN} ${chalk.yellow("\u8FD0\u884C")} ${chalk.cyan(
|
|
220
|
+
"robot-standards init"
|
|
221
|
+
)} ${chalk.yellow("\u4FEE\u590D\u95EE\u9898")}`
|
|
222
|
+
);
|
|
223
|
+
} else {
|
|
224
|
+
console.log();
|
|
225
|
+
console.log(` ${S.OK} ${chalk.green("\u6240\u6709\u68C0\u67E5\u901A\u8FC7!")}`);
|
|
226
|
+
}
|
|
227
|
+
console.log(S.LINE);
|
|
228
|
+
console.log();
|
|
229
|
+
return failedCount === 0;
|
|
230
|
+
}
|
|
231
|
+
function printCheck(check) {
|
|
232
|
+
const icon = check.status === "pass" ? S.OK : check.status === "fail" ? S.FAIL : S.SKIP;
|
|
233
|
+
console.log(` ${icon} ${check.name}`);
|
|
234
|
+
if (check.message && check.status === "fail") {
|
|
235
|
+
console.log(` ${chalk.gray(check.message)}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
export {
|
|
239
|
+
doctor
|
|
240
|
+
};
|
|
241
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/doctor.ts","../../src/utils/file.ts","../../src/utils/git.ts"],"sourcesContent":["/*\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-13\r\n * @Description: Doctor 命令 - 智能诊断 Git 标准化配置\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\nimport { resolve } from \"node:path\";\r\nimport chalk from \"chalk\";\r\nimport { fileExists, readJsonFile } from \"../utils/file\";\r\nimport { isGitRepository } from \"../utils/git\";\r\n\r\n// ─── 品牌 & 符号 ──────────────────────────────────────────────────\r\nconst BRAND = \"#7C3AED\";\r\nconst S = {\r\n LOGO: chalk.hex(BRAND).bold(\"[RS]\"),\r\n OK: chalk.green(\"✔\"),\r\n FAIL: chalk.red(\"✖\"),\r\n WARN: chalk.yellow(\"▲\"),\r\n SKIP: chalk.gray(\"○\"),\r\n LINE: chalk.gray(\"─\".repeat(48)),\r\n};\r\n\r\nexport interface DoctorOptions {\r\n cwd?: string;\r\n}\r\n\r\ninterface CheckResult {\r\n name: string;\r\n status: \"pass\" | \"fail\" | \"skip\";\r\n message?: string;\r\n}\r\n\r\n/**\r\n * Doctor 命令主函数\r\n * 根据已安装的功能智能检测,未安装的功能只做提示不标记为失败\r\n */\r\nexport async function doctor(options: DoctorOptions = {}) {\r\n const cwd = options.cwd || process.cwd();\r\n\r\n // ── Banner ──\r\n console.log();\r\n console.log(S.LINE);\r\n console.log(\r\n ` ${S.LOGO} ${chalk.bold(\"Robot Standards\")} ${chalk.gray(\"Doctor\")}`,\r\n );\r\n console.log(S.LINE);\r\n console.log();\r\n\r\n const checks: CheckResult[] = [];\r\n\r\n // ── 1. 基础环境 ──\r\n const isGit = isGitRepository(cwd);\r\n checks.push({\r\n name: \"Git 仓库\",\r\n status: isGit ? \"pass\" : \"fail\",\r\n message: isGit ? undefined : \"未初始化 Git 仓库,运行 git init\",\r\n });\r\n\r\n // ── 2. 读取 package.json 探测已安装功能 ──\r\n let packageJson: any = {};\r\n const packageJsonPath = resolve(cwd, \"package.json\");\r\n const hasPackageJson = fileExists(packageJsonPath);\r\n\r\n if (hasPackageJson) {\r\n try {\r\n packageJson = await readJsonFile(packageJsonPath);\r\n } catch {\r\n // ignore\r\n }\r\n } else {\r\n checks.push({\r\n name: \"package.json\",\r\n status: \"fail\",\r\n message: \"缺少 package.json\",\r\n });\r\n }\r\n\r\n const allDeps = {\r\n ...packageJson.dependencies,\r\n ...packageJson.devDependencies,\r\n };\r\n\r\n // 检测已安装的功能模块\r\n const hasCommitizen = !!allDeps[\"commitizen\"];\r\n const hasCommitlint = !!allDeps[\"@commitlint/cli\"];\r\n const hasHusky = !!allDeps[\"husky\"];\r\n const hasEslint = !!allDeps[\"eslint\"];\r\n const hasLintStaged = !!allDeps[\"lint-staged\"];\r\n const hasPrettier = !!allDeps[\"prettier\"];\r\n\r\n // ── 3. 核心功能检查(始终检查) ──\r\n console.log(` ${chalk.bold(\"核心功能\")}`);\r\n console.log();\r\n\r\n // Husky\r\n if (hasHusky) {\r\n const huskyDir = fileExists(resolve(cwd, \".husky\"));\r\n checks.push({\r\n name: \"Husky 目录\",\r\n status: huskyDir ? \"pass\" : \"fail\",\r\n message: huskyDir ? undefined : \"缺少 .husky 目录\",\r\n });\r\n\r\n const commitMsg = fileExists(resolve(cwd, \".husky/commit-msg\"));\r\n checks.push({\r\n name: \"commit-msg hook\",\r\n status: commitMsg ? \"pass\" : \"fail\",\r\n message: commitMsg ? undefined : \"缺少 commit-msg hook\",\r\n });\r\n } else {\r\n checks.push({\r\n name: \"Husky\",\r\n status: \"fail\",\r\n message: \"未安装 husky\",\r\n });\r\n }\r\n\r\n // Commitlint\r\n if (hasCommitlint) {\r\n const hasConfig =\r\n fileExists(resolve(cwd, \"commitlint.config.cjs\")) ||\r\n fileExists(resolve(cwd, \"commitlint.config.js\")) ||\r\n fileExists(resolve(cwd, \"commitlint.config.ts\"));\r\n checks.push({\r\n name: \"Commitlint 配置\",\r\n status: hasConfig ? \"pass\" : \"fail\",\r\n message: hasConfig ? undefined : \"缺少 commitlint.config.*\",\r\n });\r\n } else {\r\n checks.push({\r\n name: \"Commitlint\",\r\n status: \"fail\",\r\n message: \"未安装 @commitlint/cli\",\r\n });\r\n }\r\n\r\n // Commitizen\r\n if (hasCommitizen) {\r\n const hasCzConfig =\r\n fileExists(resolve(cwd, \".cz-config.cjs\")) ||\r\n fileExists(resolve(cwd, \".cz-config.js\"));\r\n checks.push({\r\n name: \"Commitizen 配置\",\r\n status: hasCzConfig ? \"pass\" : \"fail\",\r\n message: hasCzConfig ? undefined : \"缺少 .cz-config.*\",\r\n });\r\n\r\n const hasCommitizenPath = !!packageJson.config?.commitizen;\r\n checks.push({\r\n name: \"commitizen path 配置\",\r\n status: hasCommitizenPath ? \"pass\" : \"fail\",\r\n message: hasCommitizenPath\r\n ? undefined\r\n : \"package.json 中缺少 config.commitizen\",\r\n });\r\n } else {\r\n checks.push({\r\n name: \"Commitizen\",\r\n status: \"fail\",\r\n message: \"未安装 commitizen\",\r\n });\r\n }\r\n\r\n // cz 脚本\r\n const hasCzScript = !!packageJson.scripts?.cz;\r\n checks.push({\r\n name: \"cz 脚本\",\r\n status: hasCzScript ? \"pass\" : \"fail\",\r\n message: hasCzScript ? undefined : \"缺少 cz 脚本 (bun run cz)\",\r\n });\r\n\r\n // ── 输出核心检查结果 ──\r\n const coreChecks = checks.slice();\r\n for (const check of coreChecks) {\r\n printCheck(check);\r\n }\r\n\r\n // ── 4. 附加功能检查(仅检测已安装的) ──\r\n const extraChecks: CheckResult[] = [];\r\n\r\n if (hasEslint) {\r\n console.log();\r\n console.log(` ${chalk.bold(\"代码检查\")}`);\r\n console.log();\r\n\r\n const hasEslintConfig =\r\n fileExists(resolve(cwd, \"eslint.config.ts\")) ||\r\n fileExists(resolve(cwd, \"eslint.config.js\")) ||\r\n fileExists(resolve(cwd, \"eslint.config.mjs\"));\r\n const eslintCheck: CheckResult = {\r\n name: \"ESLint 配置\",\r\n status: hasEslintConfig ? \"pass\" : \"fail\",\r\n message: hasEslintConfig ? undefined : \"缺少 eslint.config.*\",\r\n };\r\n extraChecks.push(eslintCheck);\r\n printCheck(eslintCheck);\r\n\r\n if (hasHusky) {\r\n const preCommit = fileExists(resolve(cwd, \".husky/pre-commit\"));\r\n const preCommitCheck: CheckResult = {\r\n name: \"pre-commit hook\",\r\n status: preCommit ? \"pass\" : \"fail\",\r\n message: preCommit ? undefined : \"缺少 pre-commit hook\",\r\n };\r\n extraChecks.push(preCommitCheck);\r\n printCheck(preCommitCheck);\r\n }\r\n }\r\n\r\n if (hasLintStaged) {\r\n const lintStagedConfig = !!packageJson[\"lint-staged\"];\r\n const lintStagedCheck: CheckResult = {\r\n name: \"lint-staged 配置\",\r\n status: lintStagedConfig ? \"pass\" : \"fail\",\r\n message: lintStagedConfig\r\n ? undefined\r\n : \"package.json 中缺少 lint-staged 配置\",\r\n };\r\n extraChecks.push(lintStagedCheck);\r\n printCheck(lintStagedCheck);\r\n }\r\n\r\n if (hasPrettier) {\r\n console.log();\r\n console.log(` ${chalk.bold(\"代码格式化\")}`);\r\n console.log();\r\n\r\n const hasPrettierConfig =\r\n fileExists(resolve(cwd, \".prettierrc.cjs\")) ||\r\n fileExists(resolve(cwd, \".prettierrc.js\")) ||\r\n fileExists(resolve(cwd, \".prettierrc.json\")) ||\r\n fileExists(resolve(cwd, \".prettierrc\"));\r\n const prettierCheck: CheckResult = {\r\n name: \"Prettier 配置\",\r\n status: hasPrettierConfig ? \"pass\" : \"fail\",\r\n message: hasPrettierConfig ? undefined : \"缺少 .prettierrc.*\",\r\n };\r\n extraChecks.push(prettierCheck);\r\n printCheck(prettierCheck);\r\n }\r\n\r\n // EditorConfig(不依赖 package.json,直接检测文件)\r\n const hasEditorConfig = fileExists(resolve(cwd, \".editorconfig\"));\r\n if (hasEditorConfig) {\r\n // 只在存在时标记 pass,不存在不报错(属于可选功能)\r\n }\r\n\r\n // ── 5. 未安装功能提示 ──\r\n const notInstalled: string[] = [];\r\n if (!hasEslint) notInstalled.push(\"ESLint\");\r\n if (!hasLintStaged) notInstalled.push(\"lint-staged\");\r\n if (!hasPrettier) notInstalled.push(\"Prettier\");\r\n if (!hasEditorConfig) notInstalled.push(\"EditorConfig\");\r\n\r\n if (notInstalled.length > 0) {\r\n console.log();\r\n console.log(` ${chalk.bold(\"未启用的功能\")}`);\r\n console.log();\r\n for (const name of notInstalled) {\r\n console.log(` ${S.SKIP} ${chalk.gray(name)}`);\r\n }\r\n }\r\n\r\n // ── 6. 汇总 ──\r\n const allChecks = [...coreChecks, ...extraChecks];\r\n const passedCount = allChecks.filter((c) => c.status === \"pass\").length;\r\n const failedCount = allChecks.filter((c) => c.status === \"fail\").length;\r\n\r\n console.log();\r\n console.log(S.LINE);\r\n console.log(\r\n ` ${chalk.bold(\"总计:\")} ${chalk.green(`${passedCount} 通过`)} ${\r\n failedCount > 0 ? chalk.red(`${failedCount} 失败`) : chalk.gray(\"0 失败\")\r\n }`,\r\n );\r\n\r\n if (failedCount > 0) {\r\n console.log();\r\n console.log(\r\n ` ${S.WARN} ${chalk.yellow(\"运行\")} ${chalk.cyan(\r\n \"robot-standards init\",\r\n )} ${chalk.yellow(\"修复问题\")}`,\r\n );\r\n } else {\r\n console.log();\r\n console.log(` ${S.OK} ${chalk.green(\"所有检查通过!\")}`);\r\n }\r\n\r\n console.log(S.LINE);\r\n console.log();\r\n\r\n return failedCount === 0;\r\n}\r\n\r\nfunction printCheck(check: CheckResult) {\r\n const icon =\r\n check.status === \"pass\" ? S.OK : check.status === \"fail\" ? S.FAIL : S.SKIP;\r\n console.log(` ${icon} ${check.name}`);\r\n if (check.message && check.status === \"fail\") {\r\n console.log(` ${chalk.gray(check.message)}`);\r\n }\r\n}\r\n","/*\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-13\r\n * @Description: 文件操作工具\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\nimport { existsSync } from \"node:fs\";\r\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\r\nimport { resolve, dirname } from \"node:path\";\r\n\r\n/**\r\n * 检查文件是否存在\r\n */\r\nexport function fileExists(filePath: string): boolean {\r\n return existsSync(filePath);\r\n}\r\n\r\n/**\r\n * 读取文件内容\r\n */\r\nexport async function readFileContent(filePath: string): Promise<string> {\r\n return await readFile(filePath, \"utf-8\");\r\n}\r\n\r\n/**\r\n * 写入文件内容\r\n */\r\nexport async function writeFileContent(\r\n filePath: string,\r\n content: string,\r\n): Promise<void> {\r\n const dir = dirname(filePath);\r\n if (!existsSync(dir)) {\r\n await mkdir(dir, { recursive: true });\r\n }\r\n await writeFile(filePath, content, \"utf-8\");\r\n}\r\n\r\n/**\r\n * 读取并解析 JSON 文件\r\n */\r\nexport async function readJsonFile<T = any>(filePath: string): Promise<T> {\r\n const content = await readFileContent(filePath);\r\n return JSON.parse(content) as T;\r\n}\r\n\r\n/**\r\n * 写入 JSON 文件\r\n */\r\nexport async function writeJsonFile(\r\n filePath: string,\r\n data: any,\r\n pretty: boolean = true,\r\n): Promise<void> {\r\n const content = pretty\r\n ? JSON.stringify(data, null, 2) + \"\\n\"\r\n : JSON.stringify(data);\r\n await writeFileContent(filePath, content);\r\n}\r\n\r\n/**\r\n * 更新 package.json\r\n */\r\nexport async function updatePackageJson(\r\n updates: Record<string, any>,\r\n cwd: string = process.cwd(),\r\n): Promise<void> {\r\n const packageJsonPath = resolve(cwd, \"package.json\");\r\n const packageJson = await readJsonFile(packageJsonPath);\r\n const updated = { ...packageJson, ...updates };\r\n await writeJsonFile(packageJsonPath, updated);\r\n}\r\n","/*\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-13\r\n * @Description: Git 工具函数\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\nimport { existsSync } from \"node:fs\";\r\nimport { resolve } from \"node:path\";\r\nimport { execa } from \"execa\";\r\n\r\n/**\r\n * 检查是否在 Git 仓库中\r\n */\r\nexport function isGitRepository(cwd: string = process.cwd()): boolean {\r\n return existsSync(resolve(cwd, \".git\"));\r\n}\r\n\r\n/**\r\n * 初始化 Git 仓库\r\n */\r\nexport async function initGitRepository(\r\n cwd: string = process.cwd(),\r\n): Promise<void> {\r\n if (!isGitRepository(cwd)) {\r\n await execa(\"git\", [\"init\"], { cwd });\r\n }\r\n}\r\n"],"mappings":"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","names":["resolve","existsSync","resolve","resolve"]}
|