@webywz/vibe-commit 0.1.12 → 0.1.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/README.md +9 -2
- package/dist/cli.js +37 -6
- package/dist/github.d.ts +32 -0
- package/dist/github.js +162 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/parse-args.d.ts +1 -0
- package/dist/parse-args.js +50 -4
- package/dist/types.d.ts +6 -0
- package/examples/github-actions.yml +49 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
</p>
|
|
18
18
|
|
|
19
19
|
Companion spirit to [diff-vibe](https://github.com/webywz/diff-vibe): commits here, pull requests there.
|
|
20
|
-
Pair walkthrough (EN/中文) and
|
|
20
|
+
Pair walkthrough (EN/中文), helper script, and CI sample: [`examples/pair-workflow.md`](./examples/pair-workflow.md) · [`examples/commit-msg.sh`](./examples/commit-msg.sh) · [`examples/github-actions.yml`](./examples/github-actions.yml) (ship in the npm tarball).
|
|
21
21
|
|
|
22
22
|
与 [diff-vibe](https://github.com/webywz/diff-vibe) 成对:这边写 commit,那边写 PR。
|
|
23
23
|
成对流程与可复制脚本见 [`examples/`](./examples/)(随 npm 包发布)。
|
|
@@ -45,6 +45,7 @@ vibe-commit # propose from staged diff
|
|
|
45
45
|
vibe-commit --vibe playful --commit # write the commit
|
|
46
46
|
vibe-commit --breaking --dry-run # force ! + BREAKING CHANGE footer
|
|
47
47
|
vibe-commit --dry-run # print only (default; wins over --commit)
|
|
48
|
+
vibe-commit --github --quiet --no-ai # Actions annotations (CI)
|
|
48
49
|
git commit -m "$(vibe-commit --dry-run)"
|
|
49
50
|
vibe-commit install # optional prepare-commit-msg hook
|
|
50
51
|
```
|
|
@@ -59,6 +60,9 @@ vibe-commit install # optional prepare-commit-msg hook
|
|
|
59
60
|
| `--no-ai` | Skip the API even if `OPENAI_API_KEY` is set · 即使有 Key 也不走 AI |
|
|
60
61
|
| `--breaking` | Force breaking (`!` + `BREAKING CHANGE:` footer = **subject**) · 强制破坏性变更(`!` + footer 文本即 **subject**) |
|
|
61
62
|
| `--json` | Machine-readable proposal · 机器可读提案 |
|
|
63
|
+
| `--github` | Emit GitHub Actions `::notice` / `::warning` / `::error` annotations; write `GITHUB_OUTPUT` + `GITHUB_STEP_SUMMARY` when set · 输出 Actions 注解,并在环境变量存在时写 Job 输出与 Summary |
|
|
64
|
+
| `--quiet` | Suppress the pretty terminal report; `--json` / `--github` still emit · 抑制漂亮终端报告 |
|
|
65
|
+
| `--max-annotations <n>` | Cap `--github` annotation lines (default: 20; invalid → UsageError) · 限制注解条数 |
|
|
62
66
|
| `install [--path]` | Install the prepare-commit-msg hook · 安装钩子 |
|
|
63
67
|
| `uninstall [--path]` | Remove the managed hook · 卸载钩子 |
|
|
64
68
|
| `-h` / `-v` | Help / version · 帮助 / 版本 |
|
|
@@ -75,7 +79,7 @@ npx --yes @webywz/vibe-commit --commit
|
|
|
75
79
|
npx --yes @webywz/diff-vibe@^0.1.8 --base main --create
|
|
76
80
|
```
|
|
77
81
|
|
|
78
|
-
Commits here · PRs there. Full walkthrough (EN/中文)
|
|
82
|
+
Commits here · PRs there. Full walkthrough (EN/中文), `commit-msg.sh`, and Actions sample live in [`examples/`](./examples/). Companion-side snippets: [diff-vibe examples](https://github.com/webywz/diff-vibe/tree/main/examples).
|
|
79
83
|
|
|
80
84
|
这边写 commit,那边写 PR。完整成对流程与脚本见 [`examples/`](./examples/)。成对仓库示例:[diff-vibe examples](https://github.com/webywz/diff-vibe/tree/main/examples)。
|
|
81
85
|
|
|
@@ -164,6 +168,8 @@ console.log(formatCommit(message));
|
|
|
164
168
|
**破坏性变更**:删公开 `export`、主版本升级、diff 里已有 footer,或传 `--breaking`。强制 `--breaking` 时 footer 用 **subject**;启发式仍可用更具体的双语原因。干跑说明原因;`--json` 可带 `breakingReason`。
|
|
165
169
|
5. Managed `prepare-commit-msg` hook via `install` / `uninstall`.
|
|
166
170
|
通过 `install` / `uninstall` 管理 `prepare-commit-msg` 钩子。
|
|
171
|
+
6. **GitHub Actions** mode: `--github` emits Checks annotations; optional `--quiet` / `--max-annotations`; writes job outputs + step summary when `GITHUB_OUTPUT` / `GITHUB_STEP_SUMMARY` are set. See [`examples/github-actions.yml`](./examples/github-actions.yml).
|
|
172
|
+
**GitHub Actions** 模式:`--github` 输出 Checks 注解;可选 `--quiet` / `--max-annotations`;环境变量存在时写 Job 输出与 Summary。示例见 [`examples/github-actions.yml`](./examples/github-actions.yml)。
|
|
167
173
|
|
|
168
174
|
---
|
|
169
175
|
|
|
@@ -173,6 +179,7 @@ console.log(formatCommit(message));
|
|
|
173
179
|
- Source · [github.com/webywz/vibe-commit](https://github.com/webywz/vibe-commit)
|
|
174
180
|
- Related · [diff-vibe](https://github.com/webywz/diff-vibe) · [prompt-diff](https://github.com/webywz/prompt-diff)
|
|
175
181
|
- Pair workflow · [examples/pair-workflow.md](./examples/pair-workflow.md)
|
|
182
|
+
- GitHub Actions · [examples/github-actions.yml](./examples/github-actions.yml)
|
|
176
183
|
- License · [MIT](./LICENSE)
|
|
177
184
|
|
|
178
185
|
```bash
|
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,7 @@ import { fileURLToPath } from "node:url";
|
|
|
5
5
|
import pc from "picocolors";
|
|
6
6
|
import { formatCommit } from "./format.js";
|
|
7
7
|
import { commitWithMessage, GitError, inspectStaged } from "./git.js";
|
|
8
|
+
import { appendGitHubJobOutput, appendGitHubStepSummary, formatGitHubAnnotations, } from "./github.js";
|
|
8
9
|
import { installHook, uninstallHook, runPrepareCommitMsg } from "./hook.js";
|
|
9
10
|
import { helpText, parseArgs, UsageError } from "./parse-args.js";
|
|
10
11
|
import { proposeMessage } from "./propose.js";
|
|
@@ -50,18 +51,48 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
50
51
|
});
|
|
51
52
|
const formatted = formatCommit(message);
|
|
52
53
|
const shouldCommit = options.commit && !options.dryRun;
|
|
54
|
+
if (options.github) {
|
|
55
|
+
const ann = formatGitHubAnnotations(message, diff, {
|
|
56
|
+
maxAnnotations: options.maxAnnotations,
|
|
57
|
+
});
|
|
58
|
+
// Keep --json stdout machine-parseable; annotations ride on stderr.
|
|
59
|
+
if (options.json)
|
|
60
|
+
process.stderr.write(ann);
|
|
61
|
+
else
|
|
62
|
+
process.stdout.write(ann);
|
|
63
|
+
try {
|
|
64
|
+
appendGitHubJobOutput(message, diff);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
process.stderr.write(`vibe-commit: GITHUB_OUTPUT skipped (${err instanceof Error ? err.message : err})\n`);
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
appendGitHubStepSummary(message, diff);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
process.stderr.write(`vibe-commit: GITHUB_STEP_SUMMARY skipped (${err instanceof Error ? err.message : err})\n`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
53
76
|
if (options.json) {
|
|
54
77
|
process.stdout.write(`${JSON.stringify({ ...message, formatted }, null, 2)}\n`);
|
|
55
78
|
}
|
|
56
|
-
else if (
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
79
|
+
else if (!options.quiet) {
|
|
80
|
+
if (options.github) {
|
|
81
|
+
process.stdout.write("::group::vibe-commit report\n");
|
|
82
|
+
}
|
|
83
|
+
if (piped) {
|
|
84
|
+
process.stdout.write(`${formatted}\n`);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
process.stdout.write(renderProposal(diff, message));
|
|
88
|
+
}
|
|
89
|
+
if (options.github) {
|
|
90
|
+
process.stdout.write("::endgroup::\n");
|
|
91
|
+
}
|
|
61
92
|
}
|
|
62
93
|
if (shouldCommit) {
|
|
63
94
|
commitWithMessage(formatted);
|
|
64
|
-
if (!piped && !options.json) {
|
|
95
|
+
if (!piped && !options.json && !options.quiet) {
|
|
65
96
|
process.stdout.write(` ${pc.green("committed")}\n\n`);
|
|
66
97
|
}
|
|
67
98
|
}
|
package/dist/github.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ProposedMessage, StagedDiff } from "./types.ts";
|
|
2
|
+
export interface GitHubFormatOptions {
|
|
3
|
+
/** Soft cap for PR annotation noise. Default 20. */
|
|
4
|
+
maxAnnotations?: number;
|
|
5
|
+
}
|
|
6
|
+
type AnnotationType = "error" | "warning" | "notice";
|
|
7
|
+
/** Escape payload text for workflow command messages. */
|
|
8
|
+
export declare function escapeData(value: string): string;
|
|
9
|
+
/** Escape workflow command property values (file, title, …). */
|
|
10
|
+
export declare function escapeProperty(value: string): string;
|
|
11
|
+
export declare function annotation(type: AnnotationType, message: string, props?: {
|
|
12
|
+
file?: string;
|
|
13
|
+
line?: number;
|
|
14
|
+
title?: string;
|
|
15
|
+
}): string;
|
|
16
|
+
/** Heuristic risk tier → annotation level (breaking / fix weigh heavier). */
|
|
17
|
+
export declare function proposalAnnotationType(proposal: ProposedMessage): AnnotationType;
|
|
18
|
+
/**
|
|
19
|
+
* Emit GitHub Actions workflow commands so PR Checks show the proposed commit.
|
|
20
|
+
* Offline / local-safe: pure string formatting, no network.
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatGitHubAnnotations(proposal: ProposedMessage, diff: StagedDiff, options?: GitHubFormatOptions): string;
|
|
23
|
+
/** Append job outputs when running inside Actions (`GITHUB_OUTPUT`). */
|
|
24
|
+
export declare function appendGitHubJobOutput(proposal: ProposedMessage, diff: StagedDiff): void;
|
|
25
|
+
/** Build a short Markdown Job Summary for Actions (no env I/O). */
|
|
26
|
+
export declare function formatGitHubStepSummary(proposal: ProposedMessage, diff: StagedDiff): string;
|
|
27
|
+
/**
|
|
28
|
+
* Append a concise Job Summary when running inside Actions (`GITHUB_STEP_SUMMARY`).
|
|
29
|
+
* No-op when the env var is unset.
|
|
30
|
+
*/
|
|
31
|
+
export declare function appendGitHubStepSummary(proposal: ProposedMessage, diff: StagedDiff): void;
|
|
32
|
+
export {};
|
package/dist/github.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { appendFileSync } from "node:fs";
|
|
2
|
+
import { formatCommit } from "./format.js";
|
|
3
|
+
/** Escape payload text for workflow command messages. */
|
|
4
|
+
export function escapeData(value) {
|
|
5
|
+
return value.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A");
|
|
6
|
+
}
|
|
7
|
+
/** Escape workflow command property values (file, title, …). */
|
|
8
|
+
export function escapeProperty(value) {
|
|
9
|
+
return escapeData(value).replace(/:/g, "%3A").replace(/,/g, "%2C");
|
|
10
|
+
}
|
|
11
|
+
export function annotation(type, message, props = {}) {
|
|
12
|
+
const parts = [];
|
|
13
|
+
if (props.file)
|
|
14
|
+
parts.push(`file=${escapeProperty(props.file)}`);
|
|
15
|
+
if (props.line !== undefined && Number.isFinite(props.line)) {
|
|
16
|
+
parts.push(`line=${Math.max(1, Math.trunc(props.line))}`);
|
|
17
|
+
}
|
|
18
|
+
if (props.title)
|
|
19
|
+
parts.push(`title=${escapeProperty(props.title)}`);
|
|
20
|
+
const meta = parts.length > 0 ? ` ${parts.join(",")}` : "";
|
|
21
|
+
return `::${type}${meta}::${escapeData(message)}`;
|
|
22
|
+
}
|
|
23
|
+
/** Heuristic risk tier → annotation level (breaking / fix weigh heavier). */
|
|
24
|
+
export function proposalAnnotationType(proposal) {
|
|
25
|
+
if (proposal.breaking)
|
|
26
|
+
return "error";
|
|
27
|
+
switch (proposal.type) {
|
|
28
|
+
case "fix":
|
|
29
|
+
return "warning";
|
|
30
|
+
case "feat":
|
|
31
|
+
case "perf":
|
|
32
|
+
case "refactor":
|
|
33
|
+
return "notice";
|
|
34
|
+
default:
|
|
35
|
+
return "notice";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function oneLine(value, max = 200) {
|
|
39
|
+
const flat = value.replace(/\s+/g, " ").trim();
|
|
40
|
+
if (flat.length <= max)
|
|
41
|
+
return flat;
|
|
42
|
+
return `${flat.slice(0, max - 1)}…`;
|
|
43
|
+
}
|
|
44
|
+
function headerLine(proposal) {
|
|
45
|
+
return formatCommit({ ...proposal, body: undefined }).split("\n")[0] ?? "";
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Emit GitHub Actions workflow commands so PR Checks show the proposed commit.
|
|
49
|
+
* Offline / local-safe: pure string formatting, no network.
|
|
50
|
+
*/
|
|
51
|
+
export function formatGitHubAnnotations(proposal, diff, options = {}) {
|
|
52
|
+
const max = options.maxAnnotations ?? 20;
|
|
53
|
+
const lines = [];
|
|
54
|
+
const push = (line) => {
|
|
55
|
+
if (lines.length < max)
|
|
56
|
+
lines.push(line);
|
|
57
|
+
};
|
|
58
|
+
const primary = diff.files[0]?.path;
|
|
59
|
+
const title = headerLine(proposal);
|
|
60
|
+
push(annotation(proposalAnnotationType(proposal), title, {
|
|
61
|
+
file: primary,
|
|
62
|
+
title: "vibe-commit · title",
|
|
63
|
+
}));
|
|
64
|
+
if (proposal.breaking) {
|
|
65
|
+
const reason = proposal.breakingReason?.trim() ||
|
|
66
|
+
"Breaking change detected in staged diff.";
|
|
67
|
+
push(annotation("error", oneLine(reason), {
|
|
68
|
+
file: primary,
|
|
69
|
+
title: "vibe-commit · breaking",
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
if (proposal.body?.trim()) {
|
|
73
|
+
push(annotation("notice", oneLine(proposal.body), {
|
|
74
|
+
file: primary,
|
|
75
|
+
title: "vibe-commit · body",
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
for (const file of diff.files) {
|
|
79
|
+
const status = file.status === "A"
|
|
80
|
+
? "add"
|
|
81
|
+
: file.status === "D"
|
|
82
|
+
? "delete"
|
|
83
|
+
: file.status === "R"
|
|
84
|
+
? "rename"
|
|
85
|
+
: "update";
|
|
86
|
+
push(annotation("notice", `${status} \`${file.path}\` (+${file.additions} −${file.deletions})`, {
|
|
87
|
+
file: file.path,
|
|
88
|
+
title: "vibe-commit · file",
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
const totals = diff.files.reduce((acc, file) => {
|
|
92
|
+
acc.add += file.additions;
|
|
93
|
+
acc.del += file.deletions;
|
|
94
|
+
return acc;
|
|
95
|
+
}, { add: 0, del: 0 });
|
|
96
|
+
push(annotation("notice", `${diff.files.length} files · +${totals.add} / −${totals.del} · engine ${proposal.engine}`, { title: "vibe-commit · meta" }));
|
|
97
|
+
return lines.length > 0 ? `${lines.join("\n")}\n` : "";
|
|
98
|
+
}
|
|
99
|
+
/** Append job outputs when running inside Actions (`GITHUB_OUTPUT`). */
|
|
100
|
+
export function appendGitHubJobOutput(proposal, diff) {
|
|
101
|
+
const path = process.env.GITHUB_OUTPUT;
|
|
102
|
+
if (!path)
|
|
103
|
+
return;
|
|
104
|
+
const body = [
|
|
105
|
+
`title=${oneLine(headerLine(proposal), 256)}`,
|
|
106
|
+
`subject=${oneLine(proposal.subject, 200)}`,
|
|
107
|
+
`type=${proposal.type}`,
|
|
108
|
+
`scope=${proposal.scope ?? ""}`,
|
|
109
|
+
`breaking=${proposal.breaking}`,
|
|
110
|
+
`engine=${proposal.engine}`,
|
|
111
|
+
`findings=${diff.files.length}`,
|
|
112
|
+
].join("\n");
|
|
113
|
+
appendFileSync(path, `${body}\n`, "utf8");
|
|
114
|
+
}
|
|
115
|
+
/** Build a short Markdown Job Summary for Actions (no env I/O). */
|
|
116
|
+
export function formatGitHubStepSummary(proposal, diff) {
|
|
117
|
+
const totals = diff.files.reduce((acc, file) => {
|
|
118
|
+
acc.add += file.additions;
|
|
119
|
+
acc.del += file.deletions;
|
|
120
|
+
return acc;
|
|
121
|
+
}, { add: 0, del: 0 });
|
|
122
|
+
const lines = [
|
|
123
|
+
"## vibe-commit",
|
|
124
|
+
"",
|
|
125
|
+
`| | |`,
|
|
126
|
+
`| --- | --- |`,
|
|
127
|
+
`| **Title** | ${headerLine(proposal)} |`,
|
|
128
|
+
`| **Type** | \`${proposal.type}\`${proposal.scope ? ` (\`${proposal.scope}\`)` : ""} |`,
|
|
129
|
+
`| **Breaking** | ${proposal.breaking} |`,
|
|
130
|
+
`| **Engine** | ${proposal.engine} |`,
|
|
131
|
+
`| **Files** | ${diff.files.length} (+${totals.add} / −${totals.del}) staged |`,
|
|
132
|
+
"",
|
|
133
|
+
];
|
|
134
|
+
if (proposal.breakingReason?.trim()) {
|
|
135
|
+
lines.push(`**Breaking:** _${oneLine(proposal.breakingReason, 280)}_`, "");
|
|
136
|
+
}
|
|
137
|
+
else if (proposal.body?.trim()) {
|
|
138
|
+
lines.push(`_${oneLine(proposal.body, 280)}_`, "");
|
|
139
|
+
}
|
|
140
|
+
const findings = [];
|
|
141
|
+
for (const file of diff.files.slice(0, 8)) {
|
|
142
|
+
findings.push(`- \`${file.path}\` (${file.status}, +${file.additions} −${file.deletions})`);
|
|
143
|
+
}
|
|
144
|
+
if (findings.length > 0) {
|
|
145
|
+
lines.push("### Staged files", "", ...findings, "");
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
lines.push("_No staged files._", "");
|
|
149
|
+
}
|
|
150
|
+
return lines.join("\n");
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Append a concise Job Summary when running inside Actions (`GITHUB_STEP_SUMMARY`).
|
|
154
|
+
* No-op when the env var is unset.
|
|
155
|
+
*/
|
|
156
|
+
export function appendGitHubStepSummary(proposal, diff) {
|
|
157
|
+
const path = process.env.GITHUB_STEP_SUMMARY;
|
|
158
|
+
if (!path)
|
|
159
|
+
return;
|
|
160
|
+
appendFileSync(path, `${formatGitHubStepSummary(proposal, diff)}\n`, "utf8");
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=github.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { inspectStaged, commitWithMessage, GitError } from "./git.ts";
|
|
|
4
4
|
export { proposeHeuristic, inferType, inferScope, inferSubject, inferBreaking, detectBreakingKind, formatBreakingReason, breakingFooterDetail, DEFAULT_BREAKING_FOOTER_DETAIL, ensureBreakingFooter, classifyPath, } from "./heuristic.ts";
|
|
5
5
|
export type { BreakingKind } from "./heuristic.ts";
|
|
6
6
|
export { parseArgs, helpText, UsageError } from "./parse-args.ts";
|
|
7
|
+
export { annotation, appendGitHubJobOutput, appendGitHubStepSummary, escapeData, escapeProperty, formatGitHubAnnotations, formatGitHubStepSummary, proposalAnnotationType, } from "./github.ts";
|
|
7
8
|
export { assembleDiff, parseUnifiedDiff } from "./parse-diff.ts";
|
|
8
9
|
export { installHook, uninstallHook, runPrepareCommitMsg, shouldSkipPrepareCommitMsg, hasNonCommentContent, HOOK_BEGIN, HOOK_END, } from "./hook.ts";
|
|
9
10
|
export { proposeMessage } from "./propose.ts";
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export { formatCommit, parseCommit, normalizeSubject } from "./format.js";
|
|
|
3
3
|
export { inspectStaged, commitWithMessage, GitError } from "./git.js";
|
|
4
4
|
export { proposeHeuristic, inferType, inferScope, inferSubject, inferBreaking, detectBreakingKind, formatBreakingReason, breakingFooterDetail, DEFAULT_BREAKING_FOOTER_DETAIL, ensureBreakingFooter, classifyPath, } from "./heuristic.js";
|
|
5
5
|
export { parseArgs, helpText, UsageError } from "./parse-args.js";
|
|
6
|
+
export { annotation, appendGitHubJobOutput, appendGitHubStepSummary, escapeData, escapeProperty, formatGitHubAnnotations, formatGitHubStepSummary, proposalAnnotationType, } from "./github.js";
|
|
6
7
|
export { assembleDiff, parseUnifiedDiff } from "./parse-diff.js";
|
|
7
8
|
export { installHook, uninstallHook, runPrepareCommitMsg, shouldSkipPrepareCommitMsg, hasNonCommentContent, HOOK_BEGIN, HOOK_END, } from "./hook.js";
|
|
8
9
|
export { proposeMessage } from "./propose.js";
|
package/dist/parse-args.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type CliOptions, type CommitType, type Vibe } from "./types.ts";
|
|
2
2
|
export declare function defaultVibeFromEnv(env?: NodeJS.ProcessEnv): Vibe;
|
|
3
3
|
export declare function parseArgs(argv: string[], env?: NodeJS.ProcessEnv): CliOptions;
|
|
4
|
+
export declare function parseMaxAnnotations(value: string | undefined): number;
|
|
4
5
|
export declare function parseType(value: string | undefined): CommitType;
|
|
5
6
|
export declare function parseVibe(value: string | undefined): Vibe;
|
|
6
7
|
export declare function sanitizeScope(value: string): string;
|
package/dist/parse-args.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { COMMIT_TYPES, VIBES, } from "./types.js";
|
|
2
2
|
const HELP = `vibe-commit — stylish conventional commits, offline-first
|
|
3
|
+
有品味的 Conventional Commits(离线优先)
|
|
3
4
|
|
|
4
|
-
Usage
|
|
5
|
+
Usage · 用法
|
|
5
6
|
vibe-commit [options]
|
|
6
7
|
vibe-commit install [--path <repo>]
|
|
7
8
|
vibe-commit uninstall [--path <repo>]
|
|
8
9
|
|
|
9
|
-
Commands
|
|
10
|
+
Commands · 命令
|
|
10
11
|
install Install a prepare-commit-msg hook in the repo
|
|
11
12
|
uninstall Remove the managed prepare-commit-msg hook
|
|
12
13
|
|
|
13
|
-
Options
|
|
14
|
+
Options · 参数
|
|
14
15
|
--commit Create the commit with the proposed message
|
|
15
16
|
--dry-run Print the message only (default)
|
|
16
17
|
--type <type> feat | fix | docs | style | refactor | perf | test | build | ci | chore
|
|
@@ -19,6 +20,11 @@ Options
|
|
|
19
20
|
--no-ai Skip AI even if OPENAI_API_KEY is set
|
|
20
21
|
--breaking Force ! + BREAKING CHANGE footer (text = subject)
|
|
21
22
|
--json Print a machine-readable proposal
|
|
23
|
+
--github Emit GitHub Actions annotations (::notice/warning/error)
|
|
24
|
+
输出 Actions 注解;有 GITHUB_OUTPUT / GITHUB_STEP_SUMMARY 时写输出与 Job Summary
|
|
25
|
+
--quiet Suppress the pretty terminal report (--json / --github still emit)
|
|
26
|
+
抑制漂亮终端报告;--json / --github 仍照常
|
|
27
|
+
--max-annotations <n> Cap GitHub annotation lines (default: 20) · 限制注解条数
|
|
22
28
|
--path <repo> Repo root for install/uninstall (default: cwd)
|
|
23
29
|
-h, --help Show help
|
|
24
30
|
-v, --version Show version
|
|
@@ -30,16 +36,28 @@ Env
|
|
|
30
36
|
VIBE / VIBE_COMMIT_VIBE Default vibe when --vibe is omitted
|
|
31
37
|
VIBE_COMMIT_HOOK_AI Set to 1 to allow AI inside the git hook (off by default)
|
|
32
38
|
|
|
39
|
+
With --github, annotations go to stdout (or stderr when combined with --json) so
|
|
40
|
+
PR Checks can surface the proposed commit title / body / staged files. Job outputs
|
|
41
|
+
title/subject/type/scope/breaking/engine/findings are written when GITHUB_OUTPUT
|
|
42
|
+
is set (findings = staged file count). A short Markdown job summary is appended when
|
|
43
|
+
GITHUB_STEP_SUMMARY is set. --quiet hides the pretty report only.
|
|
44
|
+
|
|
45
|
+
配合 --github 时注解走 stdout(与 --json 联用则走 stderr,保持 JSON 干净)。
|
|
46
|
+
有 GITHUB_OUTPUT 时写入 title/subject 等字段;有 GITHUB_STEP_SUMMARY 时追加 Job Summary。
|
|
47
|
+
--quiet 只隐藏漂亮终端报告。
|
|
48
|
+
|
|
33
49
|
Git hook
|
|
34
50
|
After \`vibe-commit install\`, plain \`git commit\` (no -m) fills an empty /
|
|
35
51
|
comment-only message file with a vibe-commit proposal. Skips merge, squash,
|
|
36
52
|
amend (source=commit), and any message that already has non-comment text.
|
|
37
53
|
|
|
38
|
-
Examples
|
|
54
|
+
Examples · 示例
|
|
39
55
|
git add -p
|
|
40
56
|
vibe-commit
|
|
41
57
|
vibe-commit --vibe playful --commit
|
|
42
58
|
vibe-commit --breaking --dry-run
|
|
59
|
+
vibe-commit --github --quiet --no-ai
|
|
60
|
+
vibe-commit --github --json --max-annotations 10
|
|
43
61
|
git commit -m "$(vibe-commit --dry-run)"
|
|
44
62
|
vibe-commit install
|
|
45
63
|
vibe-commit uninstall --path ~/projects/app
|
|
@@ -56,6 +74,9 @@ export function parseArgs(argv, env = process.env) {
|
|
|
56
74
|
vibe: defaultVibeFromEnv(env),
|
|
57
75
|
noAi: false,
|
|
58
76
|
json: false,
|
|
77
|
+
github: false,
|
|
78
|
+
quiet: false,
|
|
79
|
+
maxAnnotations: 20,
|
|
59
80
|
help: false,
|
|
60
81
|
version: false,
|
|
61
82
|
breaking: false,
|
|
@@ -96,6 +117,21 @@ export function parseArgs(argv, env = process.env) {
|
|
|
96
117
|
options.json = true;
|
|
97
118
|
continue;
|
|
98
119
|
}
|
|
120
|
+
if (arg === "--github") {
|
|
121
|
+
options.github = true;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (arg === "--quiet") {
|
|
125
|
+
options.quiet = true;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (arg === "--max-annotations" || arg.startsWith("--max-annotations=")) {
|
|
129
|
+
const value = arg.includes("=")
|
|
130
|
+
? arg.slice("--max-annotations=".length)
|
|
131
|
+
: argv[++i];
|
|
132
|
+
options.maxAnnotations = parseMaxAnnotations(value);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
99
135
|
if (arg === "--breaking") {
|
|
100
136
|
options.breaking = true;
|
|
101
137
|
continue;
|
|
@@ -160,6 +196,16 @@ function parseCommand(value) {
|
|
|
160
196
|
return null;
|
|
161
197
|
}
|
|
162
198
|
}
|
|
199
|
+
export function parseMaxAnnotations(value) {
|
|
200
|
+
const raw = value?.trim();
|
|
201
|
+
if (!raw)
|
|
202
|
+
throw new UsageError("Missing value for --max-annotations");
|
|
203
|
+
const n = Number(raw);
|
|
204
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
205
|
+
throw new UsageError("--max-annotations must be a positive integer");
|
|
206
|
+
}
|
|
207
|
+
return n;
|
|
208
|
+
}
|
|
163
209
|
export function parseType(value) {
|
|
164
210
|
const raw = value?.trim().toLowerCase();
|
|
165
211
|
if (!raw)
|
package/dist/types.d.ts
CHANGED
|
@@ -49,6 +49,12 @@ export interface CliOptions {
|
|
|
49
49
|
vibe: Vibe;
|
|
50
50
|
noAi: boolean;
|
|
51
51
|
json: boolean;
|
|
52
|
+
/** Emit GitHub Actions annotations / job outputs / step summary. */
|
|
53
|
+
github: boolean;
|
|
54
|
+
/** Suppress the pretty terminal report (--json / --github still emit). */
|
|
55
|
+
quiet: boolean;
|
|
56
|
+
/** Soft cap for --github annotation lines (default 20). */
|
|
57
|
+
maxAnnotations: number;
|
|
52
58
|
help: boolean;
|
|
53
59
|
version: boolean;
|
|
54
60
|
/** Force breaking change marker and footer. */
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Example: surface a proposed commit message as Actions annotations + job summary.
|
|
2
|
+
# Copy into your app repo as .github/workflows/vibe-commit.yml
|
|
3
|
+
# (typically on pull_request so Checks show the draft commit).
|
|
4
|
+
#
|
|
5
|
+
# 示例:把拟写的 commit message 做成 Actions 注解 + Job Summary。
|
|
6
|
+
# 复制到业务仓的 .github/workflows/vibe-commit.yml(通常挂在 pull_request 上)。
|
|
7
|
+
#
|
|
8
|
+
# Note: vibe-commit reads *staged* changes. Stage intentionally in CI, or
|
|
9
|
+
# `git add -A` / `git add -u` before the step if you want the working tree.
|
|
10
|
+
|
|
11
|
+
name: Vibe commit
|
|
12
|
+
|
|
13
|
+
on:
|
|
14
|
+
pull_request:
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
vibe-commit:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- uses: actions/setup-node@v4
|
|
23
|
+
with:
|
|
24
|
+
node-version: 20
|
|
25
|
+
|
|
26
|
+
- name: Stage working tree (demo)
|
|
27
|
+
run: git add -A
|
|
28
|
+
|
|
29
|
+
- name: Propose commit (annotations + summary)
|
|
30
|
+
id: vibe
|
|
31
|
+
run: |
|
|
32
|
+
npx --yes @webywz/vibe-commit@^0.1.14 \
|
|
33
|
+
--github \
|
|
34
|
+
--quiet \
|
|
35
|
+
--max-annotations 20 \
|
|
36
|
+
--no-ai
|
|
37
|
+
# --github → ::notice / ::warning / ::error on the PR Checks UI
|
|
38
|
+
# --quiet → suppress the pretty terminal report (annotations / summary / outputs still emit)
|
|
39
|
+
# --max-annotations → soft-cap annotation noise (default 20)
|
|
40
|
+
# When GITHUB_OUTPUT is set, also writes: title, subject, type, scope, breaking, engine, findings
|
|
41
|
+
# findings = staged file count
|
|
42
|
+
# When GITHUB_STEP_SUMMARY is set, appends a short Markdown job summary
|
|
43
|
+
|
|
44
|
+
# Optional: use job outputs from a later step
|
|
45
|
+
# - name: Echo title
|
|
46
|
+
# run: echo "proposed ${{ steps.vibe.outputs.title }} (findings=${{ steps.vibe.outputs.findings }})"
|
|
47
|
+
|
|
48
|
+
# Optional: Job Summary is written automatically when GITHUB_STEP_SUMMARY is set
|
|
49
|
+
# (Actions injects it). No extra step required.
|