@pubinfo-nightly/commitlint 2025.11.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 PUBINFO 腾龙框架
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @pubinfo/commitlint
2
+
3
+ > Pubinfo 项目的统一 Commit 规范工具与可共享配置。集成 commitlint + cz-git(交互式提交)+ 自定义范围/类型生成逻辑,提供一致、可维护、带中文指引的提交体验。
package/bin/commit.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { runMain } from '../dist/run.js';
3
+
4
+ runMain();
@@ -0,0 +1,43 @@
1
+ import { UserConfig } from "@commitlint/types";
2
+
3
+ //#region src/config/index.d.ts
4
+ declare const commitPreset: UserConfig & {
5
+ prompt?: any;
6
+ };
7
+ declare function loadCommitConfig(): UserConfig & {
8
+ prompt?: any;
9
+ };
10
+ //#endregion
11
+ //#region src/config/commitlint.d.ts
12
+ declare function isCommitlintEnabled(): Promise<boolean>;
13
+ //#endregion
14
+ //#region src/init/cz.config.d.ts
15
+ declare function createCzConfig(cwd?: string): boolean;
16
+ declare function runCzConfig(czConfigPath: string, cwd?: string): boolean;
17
+ //#endregion
18
+ //#region src/init/git.message.d.ts
19
+ declare function createGitMessage(rootPath?: string): boolean;
20
+ declare function runGitMessage(rootPath?: string): boolean;
21
+ //#endregion
22
+ //#region src/init/simple.git.hook.d.ts
23
+ declare function runSimpleGitHooks(script?: string, cwd?: string, enabled?: boolean): boolean;
24
+ declare function runNpx(cwd?: string): boolean;
25
+ declare function configureGitHooksPath(enabled?: boolean, cwd?: string): boolean;
26
+ //#endregion
27
+ //#region src/prompt/index.d.ts
28
+ interface PromptResult {
29
+ raw: string;
30
+ }
31
+ declare function runPrompt(): Promise<PromptResult | null>;
32
+ //#endregion
33
+ //#region src/utils/git.d.ts
34
+ /**
35
+ * 判断当前工作目录是否处在 Git 仓库内。
36
+ */
37
+ declare function isInsideGitRepo(): boolean;
38
+ //#endregion
39
+ //#region src/utils/lint.message.d.ts
40
+ declare function lintMessage(message: string): Promise<boolean>;
41
+ declare function lintAndReturn(message: string): Promise<string>;
42
+ //#endregion
43
+ export { commitPreset, configureGitHooksPath, createCzConfig, createGitMessage, isCommitlintEnabled, isInsideGitRepo, lintAndReturn, lintMessage, loadCommitConfig, runCzConfig, runGitMessage, runNpx, runPrompt, runSimpleGitHooks };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { a as configureGitHooksPath, c as createGitMessage, d as runCzConfig, f as isCommitlintEnabled, i as runPrompt, l as runGitMessage, m as loadCommitConfig, n as lintMessage, o as runNpx, p as commitPreset, r as isInsideGitRepo, s as runSimpleGitHooks, t as lintAndReturn, u as createCzConfig } from "./lint.message.js";
2
+
3
+ export { commitPreset, configureGitHooksPath, createCzConfig, createGitMessage, isCommitlintEnabled, isInsideGitRepo, lintAndReturn, lintMessage, loadCommitConfig, runCzConfig, runGitMessage, runNpx, runPrompt, runSimpleGitHooks };
@@ -0,0 +1,467 @@
1
+ import { createRequire } from "node:module";
2
+ import { execSync, spawn } from "node:child_process";
3
+ import { loadConfig } from "unconfig";
4
+ import { join, resolve } from "node:path";
5
+ import process from "node:process";
6
+ import CZGPackage from "czg/package.json" with { type: "json" };
7
+ import fs from "fs-extra";
8
+ import fs$1 from "node:fs";
9
+
10
+ //#region src/config/index.ts
11
+ const notWip = [
12
+ "main",
13
+ "master",
14
+ "dev",
15
+ "test",
16
+ "release"
17
+ ];
18
+ function isMainBranch() {
19
+ try {
20
+ try {
21
+ const currentBranch = execSync("git branch --show-current", { encoding: "utf8" }).trim();
22
+ if (currentBranch) return notWip.includes(currentBranch);
23
+ } catch {
24
+ try {
25
+ const currentBranch = execSync("git symbolic-ref --short HEAD", { encoding: "utf8" }).trim();
26
+ return notWip.includes(currentBranch);
27
+ } catch {
28
+ return false;
29
+ }
30
+ }
31
+ } catch {
32
+ return false;
33
+ }
34
+ return false;
35
+ }
36
+ function generateCommitTypes() {
37
+ const allTypes = [
38
+ "feat",
39
+ "fix",
40
+ "docs",
41
+ "style",
42
+ "refactor",
43
+ "perf",
44
+ "test",
45
+ "build",
46
+ "ci",
47
+ "chore",
48
+ "revert",
49
+ "types",
50
+ "release",
51
+ "init",
52
+ "wip"
53
+ ];
54
+ if (isMainBranch()) return allTypes.filter((type) => type !== "wip");
55
+ return allTypes;
56
+ }
57
+ function generateCzGitTypes() {
58
+ const all = [
59
+ {
60
+ value: "feat",
61
+ name: "feat: ✨ 新功能",
62
+ emoji: ":sparkles:"
63
+ },
64
+ {
65
+ value: "fix",
66
+ name: "fix: 🐛 修复缺陷",
67
+ emoji: ":bug:"
68
+ },
69
+ {
70
+ value: "types",
71
+ name: "types: 🎨 类型相关",
72
+ emoji: ":art:"
73
+ },
74
+ {
75
+ value: "docs",
76
+ name: "docs: 📝 文档更新",
77
+ emoji: ":memo:"
78
+ },
79
+ {
80
+ value: "style",
81
+ name: "style: 💄 代码格式",
82
+ emoji: ":lipstick:"
83
+ },
84
+ {
85
+ value: "refactor",
86
+ name: "refactor: ♻️ 代码重构",
87
+ emoji: ":recycle:"
88
+ },
89
+ {
90
+ value: "perf",
91
+ name: "perf: ⚡️ 性能提升",
92
+ emoji: ":zap:"
93
+ },
94
+ {
95
+ value: "test",
96
+ name: "test: ✅ 测试相关",
97
+ emoji: ":white_check_mark:"
98
+ },
99
+ {
100
+ value: "build",
101
+ name: "build: 📦️ 构建相关",
102
+ emoji: ":package:"
103
+ },
104
+ {
105
+ value: "release",
106
+ name: "release: 🔖 版本提升",
107
+ emoji: ":bookmark:"
108
+ },
109
+ {
110
+ value: "ci",
111
+ name: "ci: 🎡 持续集成",
112
+ emoji: ":ferris_wheel:"
113
+ },
114
+ {
115
+ value: "revert",
116
+ name: "revert: ⏪️ 回退代码",
117
+ emoji: ":rewind:"
118
+ },
119
+ {
120
+ value: "chore",
121
+ name: "chore: 🔨 其他修改",
122
+ emoji: ":hammer:"
123
+ },
124
+ {
125
+ value: "init",
126
+ name: "init: 🎉 初始化",
127
+ emoji: ":tada:"
128
+ },
129
+ {
130
+ value: "wip",
131
+ name: "wip: 🚧 工作进行中",
132
+ emoji: ":construction:"
133
+ }
134
+ ];
135
+ if (isMainBranch()) return all.filter((t) => t.value !== "wip");
136
+ return all;
137
+ }
138
+ const commitPreset = {
139
+ extends: ["@commitlint/config-conventional"],
140
+ rules: {
141
+ "scope-enum": [0],
142
+ "type-enum": [
143
+ 2,
144
+ "always",
145
+ generateCommitTypes()
146
+ ],
147
+ "type-empty": [2, "never"],
148
+ "type-case": [
149
+ 2,
150
+ "always",
151
+ "lower-case"
152
+ ],
153
+ "subject-empty": [2, "never"],
154
+ "subject-full-stop": [
155
+ 2,
156
+ "never",
157
+ "."
158
+ ],
159
+ "subject-case": [
160
+ 2,
161
+ "never",
162
+ [
163
+ "sentence-case",
164
+ "start-case",
165
+ "pascal-case",
166
+ "upper-case"
167
+ ]
168
+ ],
169
+ "header-max-length": [
170
+ 2,
171
+ "always",
172
+ 100
173
+ ],
174
+ "body-leading-blank": [1, "always"],
175
+ "footer-leading-blank": [1, "always"]
176
+ },
177
+ prompt: {
178
+ alias: { fd: "docs: fix typos" },
179
+ messages: {
180
+ scope: "选择一个提交范围 (可回车跳过):",
181
+ customScope: "请输入自定义的提交范围 :",
182
+ type: "选择你要提交的类型 :",
183
+ subject: "填写简短精炼的变更描述 :\n",
184
+ body: "填写更加详细的变更描述(可选)。使用 \"|\" 换行 :\n",
185
+ breaking: "列举非兼容性重大的变更(可选)。使用 \"|\" 换行 :\n",
186
+ footerPrefixsSelect: "选择关联issue前缀(可选):",
187
+ customFooterPrefixs: "输入自定义issue前缀 :",
188
+ footer: "列举关联issue (可选) 例如: #31, #I3244 :\n",
189
+ confirmCommit: "是否提交或修改commit ?"
190
+ },
191
+ types: generateCzGitTypes(),
192
+ useEmoji: false,
193
+ emojiAlign: "center",
194
+ themeColorCode: "",
195
+ enableMultipleScopes: true,
196
+ skipQuestions: ["scope"],
197
+ defaultScope: "___CUSTOM___:",
198
+ customScopesAlign: "bottom",
199
+ customScopesAlias: "custom",
200
+ emptyScopesAlias: "empty",
201
+ upperCaseSubject: false,
202
+ markBreakingChangeMode: true,
203
+ allowBreakingChanges: ["feat", "fix"],
204
+ breaklineNumber: 100,
205
+ breaklineChar: "|",
206
+ issuePrefixs: [{
207
+ value: "link",
208
+ name: "link: 链接 ISSUES 进行中"
209
+ }, {
210
+ value: "closed",
211
+ name: "closed: 标记 ISSUES 已完成"
212
+ }],
213
+ customIssuePrefixsAlign: "top",
214
+ emptyIssuePrefixsAlias: "skip",
215
+ customIssuePrefixsAlias: "custom",
216
+ allowCustomIssuePrefixs: true,
217
+ allowEmptyIssuePrefixs: true,
218
+ confirmColorize: true,
219
+ maxHeaderLength: Number.POSITIVE_INFINITY,
220
+ maxSubjectLength: Number.POSITIVE_INFINITY,
221
+ minSubjectLength: 0,
222
+ scopeOverrides: void 0,
223
+ defaultBody: "",
224
+ defaultIssues: "",
225
+ defaultSubject: ""
226
+ }
227
+ };
228
+ function loadCommitConfig() {
229
+ return commitPreset;
230
+ }
231
+
232
+ //#endregion
233
+ //#region src/config/commitlint.ts
234
+ let cachedState;
235
+ function resolveCommitlintEnabled(value) {
236
+ if (typeof value === "boolean") return value;
237
+ if (value && typeof value === "object") {
238
+ if (typeof value.enabled === "boolean") return value.enabled;
239
+ if (typeof value.disable === "boolean") return !value.disable;
240
+ }
241
+ }
242
+ async function isCommitlintEnabled() {
243
+ if (typeof cachedState === "boolean") return cachedState;
244
+ try {
245
+ const resolved = resolveCommitlintEnabled((await loadConfig({
246
+ sources: [{ files: "pubinfo.config" }],
247
+ merge: false
248
+ }))?.config?.commitlint);
249
+ cachedState = typeof resolved === "boolean" ? resolved : true;
250
+ } catch {
251
+ cachedState = true;
252
+ }
253
+ return cachedState;
254
+ }
255
+
256
+ //#endregion
257
+ //#region src/init/cz.config.ts
258
+ function createCzConfig(cwd = process.cwd()) {
259
+ const target = resolve(cwd, "cz.config.cjs");
260
+ if (fs.existsSync(target)) fs.unlinkSync(target);
261
+ try {
262
+ const cfg = {
263
+ $schema: `https://raw.githubusercontent.com/Zhengqbbb/cz-git/refs/tags/v${CZGPackage.version}/docs/public/schema/cz-git.json`,
264
+ ...commitPreset.prompt,
265
+ types: commitPreset.prompt?.types?.map((t) => ({
266
+ value: t.value,
267
+ name: t.name,
268
+ emoji: t.emoji
269
+ })),
270
+ scopes: commitPreset.prompt?.scopes
271
+ };
272
+ const content = `module.exports = ${JSON.stringify(cfg, null, 2)}\n`;
273
+ fs.writeFileSync(target, content, "utf8");
274
+ return true;
275
+ } catch {
276
+ return false;
277
+ }
278
+ }
279
+ function runCzConfig(czConfigPath, cwd = process.cwd()) {
280
+ const packagePath = resolve(cwd, "package.json");
281
+ if (!fs.existsSync(packagePath)) return false;
282
+ try {
283
+ const raw = fs.readFileSync(packagePath, "utf8");
284
+ const json = JSON.parse(raw);
285
+ const desiredPath = "node_modules/cz-git";
286
+ const desiredCzConfig = czConfigPath;
287
+ json.config = json.config || {};
288
+ json.config.commitizen = json.config.commitizen || {};
289
+ let changed = false;
290
+ if (json.config.commitizen.path !== desiredPath) {
291
+ json.config.commitizen.path = desiredPath;
292
+ changed = true;
293
+ }
294
+ const currentCz = json.config.commitizen.czConfig;
295
+ const normalize = (p) => p ? p.replace(/^\.\/?/, "") : p;
296
+ const isOldRoot = normalize(currentCz) === "cz.config.cjs" || normalize(currentCz) === "cz.config.js";
297
+ if (!currentCz || isOldRoot || normalize(currentCz) === "cz.config.mjs") {
298
+ if (currentCz !== desiredCzConfig) {
299
+ json.config.commitizen.czConfig = desiredCzConfig;
300
+ changed = true;
301
+ }
302
+ }
303
+ if (!changed) return false;
304
+ fs.writeFileSync(packagePath, `${JSON.stringify(json, null, 2)}\n`, "utf8");
305
+ return true;
306
+ } catch {
307
+ return false;
308
+ }
309
+ }
310
+
311
+ //#endregion
312
+ //#region src/init/git.message.ts
313
+ function createGitMessage(rootPath = process.cwd()) {
314
+ const target = resolve(rootPath, ".gitmessage");
315
+ if (fs.existsSync(target)) fs.unlinkSync(target);
316
+ const tpl = `# Commit Message 模板 (首行: <type>(<scope>): <subject>)\n# 可用类型: ${(commitPreset.prompt?.types || []).map((t) => t.value).join(", ")}\n# 可用范围: ${(commitPreset.prompt?.scopes || []).join(", ")}\n# 示例: feat(core): add http client abstraction\n# 空行后可写入 body, 使用 | 换行 (交互模式会自动处理)\n`;
317
+ fs.writeFileSync(target, tpl, "utf8");
318
+ return true;
319
+ }
320
+ function runGitMessage(rootPath = process.cwd()) {
321
+ try {
322
+ if (execSync("git config --get commit.template", {
323
+ cwd: rootPath,
324
+ stdio: "pipe"
325
+ }).toString().trim()) return false;
326
+ } catch {}
327
+ try {
328
+ execSync("git config commit.template .gitmessage", {
329
+ cwd: rootPath,
330
+ stdio: "ignore"
331
+ });
332
+ return true;
333
+ } catch {
334
+ return false;
335
+ }
336
+ }
337
+
338
+ //#endregion
339
+ //#region src/init/simple.git.hook.ts
340
+ function runSimpleGitHooks(script = "pubinfo-commit", cwd = process.cwd(), enabled = true) {
341
+ if (!enabled) return false;
342
+ const pkgPath = resolve(cwd, "package.json");
343
+ if (!fs.existsSync(pkgPath)) return false;
344
+ try {
345
+ const raw = fs.readFileSync(pkgPath, "utf8");
346
+ const json = JSON.parse(raw);
347
+ const hooks = json["simple-git-hooks"] || {};
348
+ const desiredPre = "pnpm lint-staged";
349
+ const desiredCommitMsg = `pnpm exec ${script} --edit $1`;
350
+ json["simple-git-hooks"] = hooks;
351
+ if (hooks["pre-commit"] !== desiredPre) hooks["pre-commit"] = desiredPre;
352
+ if (hooks["commit-msg"] !== desiredCommitMsg) hooks["commit-msg"] = desiredCommitMsg;
353
+ json["simple-git-hooks"] = hooks;
354
+ fs.writeFileSync(pkgPath, `${JSON.stringify(json, null, 2)}\n`, "utf8");
355
+ return true;
356
+ } catch {
357
+ return false;
358
+ }
359
+ }
360
+ function runNpx(cwd = process.cwd()) {
361
+ try {
362
+ execSync("npx simple-git-hooks", {
363
+ cwd,
364
+ stdio: "ignore"
365
+ });
366
+ return true;
367
+ } catch {
368
+ return false;
369
+ }
370
+ }
371
+ function configureGitHooksPath(enabled = true, cwd = process.cwd()) {
372
+ try {
373
+ if (enabled) {
374
+ execSync("git config --unset core.hooksPath", {
375
+ cwd,
376
+ stdio: "ignore"
377
+ });
378
+ return true;
379
+ }
380
+ execSync("git config core.hooksPath /dev/null", {
381
+ cwd,
382
+ stdio: "ignore"
383
+ });
384
+ return true;
385
+ } catch {
386
+ return enabled;
387
+ }
388
+ }
389
+
390
+ //#endregion
391
+ //#region src/prompt/index.ts
392
+ async function runPrompt() {
393
+ try {
394
+ const require = createRequire(import.meta.url);
395
+ try {
396
+ const czg = require("czg");
397
+ if (czg && typeof czg.default === "function") {
398
+ const api = await czg.default({ emoji: false });
399
+ if (api && api.raw) return { raw: api.raw };
400
+ }
401
+ } catch {}
402
+ const binDir = resolve(process.cwd(), "node_modules/.bin");
403
+ const isWin = process.platform === "win32";
404
+ const czgBin = (isWin ? [
405
+ join(binDir, "czg.cmd"),
406
+ join(binDir, "czg.ps1"),
407
+ join(binDir, "czg")
408
+ ] : [join(binDir, "czg")]).find((p) => fs$1.existsSync(p));
409
+ if (czgBin) {
410
+ await new Promise((res) => {
411
+ const child = spawn(czgBin, [], {
412
+ stdio: "inherit",
413
+ shell: isWin
414
+ });
415
+ child.on("exit", () => res());
416
+ child.on("error", () => res());
417
+ });
418
+ const msgPath = resolve(process.cwd(), ".git/COMMIT_EDITMSG");
419
+ if (fs$1.existsSync(msgPath)) return { raw: fs$1.readFileSync(msgPath, "utf8").trim() };
420
+ }
421
+ return null;
422
+ } catch {
423
+ return null;
424
+ }
425
+ }
426
+
427
+ //#endregion
428
+ //#region src/utils/git.ts
429
+ /**
430
+ * 判断当前工作目录是否处在 Git 仓库内。
431
+ */
432
+ function isInsideGitRepo() {
433
+ try {
434
+ const out = execSync("git rev-parse --is-inside-work-tree", { stdio: [
435
+ "ignore",
436
+ "pipe",
437
+ "ignore"
438
+ ] });
439
+ return String(out).trim() === "true";
440
+ } catch {
441
+ return false;
442
+ }
443
+ }
444
+
445
+ //#endregion
446
+ //#region src/utils/lint.message.ts
447
+ async function lintMessage(message) {
448
+ if (!await isCommitlintEnabled()) return true;
449
+ try {
450
+ const result = await (await import("@commitlint/lint")).default(message, commitPreset.rules, commitPreset);
451
+ if (!result.valid) {
452
+ console.error("✖ Commit message failed lint:\n");
453
+ for (const err of result.errors) console.error(` • ${err.message}`);
454
+ process.exit(1);
455
+ }
456
+ } catch (e) {
457
+ console.error("[pubinfo-commit] lint failed to run:", e);
458
+ }
459
+ return true;
460
+ }
461
+ async function lintAndReturn(message) {
462
+ await lintMessage(message);
463
+ return message;
464
+ }
465
+
466
+ //#endregion
467
+ export { configureGitHooksPath as a, createGitMessage as c, runCzConfig as d, isCommitlintEnabled as f, runPrompt as i, runGitMessage as l, loadCommitConfig as m, lintMessage as n, runNpx as o, commitPreset as p, isInsideGitRepo as r, runSimpleGitHooks as s, lintAndReturn as t, createCzConfig as u };
package/dist/run.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ //#region src/run.d.ts
2
+ declare function runMain(): Promise<void>;
3
+ //#endregion
4
+ export { runMain };
package/dist/run.js ADDED
@@ -0,0 +1,122 @@
1
+ import { a as configureGitHooksPath, c as createGitMessage, d as runCzConfig, f as isCommitlintEnabled, i as runPrompt, l as runGitMessage, n as lintMessage, o as runNpx, r as isInsideGitRepo, s as runSimpleGitHooks, u as createCzConfig } from "./lint.message.js";
2
+ import { spawnSync } from "node:child_process";
3
+ import process from "node:process";
4
+ import fs from "node:fs";
5
+ import { defineCommand, runMain as runMain$1 } from "citty";
6
+
7
+ //#region package.json
8
+ var name = "@pubinfo-nightly/commitlint";
9
+ var version = "2.1.3";
10
+ var description = "commitlint config for Pubinfo projects";
11
+
12
+ //#endregion
13
+ //#region src/cli.ts
14
+ function isGitRepository() {
15
+ try {
16
+ return spawnSync("git", ["rev-parse", "--is-inside-work-tree"], { stdio: "ignore" }).status === 0;
17
+ } catch {
18
+ return false;
19
+ }
20
+ }
21
+ /**
22
+ * 本文件提供 `pubinfo-commit` 可执行入口(由 package.json bin 指向)。
23
+ * 作用:
24
+ * 1. 在交互模式下通过 cz-git 生成符合约定式规范的提交信息(中文提示)。
25
+ * 2. 在 `commit-msg` 钩子中以 `--edit` 方式读取 Git 临时文件并进行 lint 校验。
26
+ * 3. 通过 `--init` 一键生成交互配置、提交模板与 hook 配置。
27
+ *
28
+ * 注意:不直接调用 `git commit`,保持透明度,让调用方自主执行提交动作。
29
+ */
30
+ const main = defineCommand({
31
+ meta: {
32
+ name,
33
+ version,
34
+ description
35
+ },
36
+ args: {
37
+ edit: {
38
+ type: "string",
39
+ description: "Git 钩子传入的 commit message 文件路径 (--edit $1)"
40
+ },
41
+ init: {
42
+ type: "boolean",
43
+ description: "初始化 commit 环境 (模板 / cz / git hooks)"
44
+ }
45
+ },
46
+ run: async ({ args }) => {
47
+ if (!isGitRepository()) console.error("[pubinfo-commit] 未检测到 Git 仓库。请在已初始化的 Git 项目中运行,或执行 `git init` 后重试。");
48
+ else {
49
+ const { edit, init } = args;
50
+ const enabled = await isCommitlintEnabled();
51
+ if (!isInsideGitRepo()) {
52
+ console.error("[pubinfo-commit] 未检测到 Git 仓库。请在已初始化的 Git 项目中运行,或执行 `git init` 后重试。");
53
+ return;
54
+ }
55
+ if (init) {
56
+ const cwd = process.cwd();
57
+ if (!enabled) {
58
+ const removedDefault = runSimpleGitHooks("pubinfo-commit", cwd, false);
59
+ const removedCli = runSimpleGitHooks("pubinfo-nightly commit", cwd, false);
60
+ const disabledHooks = configureGitHooksPath(false, cwd);
61
+ if (removedDefault || removedCli || disabledHooks) console.log("[pubinfo-commit] 检测到 pubinfo.config 中已关闭 commitlint,已停用 git hooks。");
62
+ else console.log("[pubinfo-commit] 检测到 pubinfo.config 中已关闭 commitlint,跳过初始化。");
63
+ return;
64
+ }
65
+ configureGitHooksPath(true, cwd);
66
+ const pubinfoDir = `${cwd}/.pubinfo`;
67
+ if (!fs.existsSync(pubinfoDir)) fs.mkdirSync(pubinfoDir);
68
+ const gitMessageStatus = createGitMessage();
69
+ const czConfigStatus = createCzConfig(pubinfoDir);
70
+ const gitHookStatus = runGitMessage();
71
+ const simpleGitHooks = runSimpleGitHooks();
72
+ const czConfig = runCzConfig(".pubinfo/cz.config.cjs");
73
+ const npxStatus = runNpx();
74
+ console.log("[pubinfo-commit] 初始化结果:");
75
+ console.log(`- cz.config.cjs: ${czConfigStatus ? "已创建" : "已存在"}`);
76
+ console.log(`- .gitmessage: ${gitMessageStatus ? "已创建" : "已存在"}`);
77
+ console.log(`- Git hooks: ${gitHookStatus ? "已写入" : "已存在"}`);
78
+ console.log(`- package.json 配置 cz-git: ${czConfig ? "已写入" : "已存在"}`);
79
+ console.log(`- package.json 配置 simple-git-hooks: ${simpleGitHooks ? "已写入" : "已存在"}`);
80
+ console.log(`- npx simple-git-hooks 安装: ${npxStatus ? "成功" : "失败,请手动安装"}`);
81
+ return;
82
+ }
83
+ if (edit) {
84
+ if (!enabled) {
85
+ configureGitHooksPath(false, process.cwd());
86
+ return;
87
+ }
88
+ try {
89
+ const raw = fs.readFileSync(String(edit), "utf8").trim();
90
+ if (!raw) {
91
+ console.error("[pubinfo-commit] 空的 commit message 文件");
92
+ return;
93
+ }
94
+ await lintMessage(raw);
95
+ } catch (e) {
96
+ console.error("[pubinfo-commit] 读取 --edit 文件失败", e);
97
+ }
98
+ return;
99
+ }
100
+ if (!enabled) {
101
+ console.log("[pubinfo-commit] commitlint 已关闭,交互模式不可用。");
102
+ configureGitHooksPath(false, process.cwd());
103
+ return;
104
+ }
105
+ const result = await runPrompt();
106
+ if (!result) {
107
+ console.error("[pubinfo-commit] 未找到 cz-git 或交互被中断");
108
+ return;
109
+ }
110
+ await lintMessage(result.raw);
111
+ }
112
+ }
113
+ });
114
+
115
+ //#endregion
116
+ //#region src/run.ts
117
+ function runMain() {
118
+ return runMain$1(main);
119
+ }
120
+
121
+ //#endregion
122
+ export { runMain };
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@pubinfo-nightly/commitlint",
3
+ "type": "module",
4
+ "version": "2025.11.14",
5
+ "description": "commitlint config for Pubinfo projects",
6
+ "exports": {
7
+ ".": "./dist/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "module": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "typesVersions": {
13
+ "*": {
14
+ "*": [
15
+ "./dist/*",
16
+ "./*"
17
+ ]
18
+ }
19
+ },
20
+ "bin": {
21
+ "pubinfo-commit": "./bin/commit.js"
22
+ },
23
+ "files": [
24
+ "bin",
25
+ "dist"
26
+ ],
27
+ "engines": {
28
+ "node": "^20.19.0 || >=22.12.0"
29
+ },
30
+ "dependencies": {
31
+ "@commitlint/config-conventional": "^19.8.1",
32
+ "@commitlint/lint": "^19.8.1",
33
+ "@commitlint/load": "^19.8.1",
34
+ "citty": "^0.1.6",
35
+ "czg": "^1.12.0",
36
+ "fs-extra": "^11.3.0",
37
+ "unconfig": "^7.3.3"
38
+ },
39
+ "scripts": {
40
+ "build": "tsdown",
41
+ "stub": "tsdown --watch"
42
+ }
43
+ }