@kud/ai-conventional-commit-cli 0.3.0 → 0.4.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/README.md +55 -17
- package/dist/index.cjs +197 -55
- package/dist/index.js +485 -168
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -11,8 +11,8 @@ Manual commit messages are noisy, inconsistent, and often miss context. ai-conve
|
|
|
11
11
|
- Style fingerprinting (average title length, scope usage ratio, gitmoji ratio, top prefixes)
|
|
12
12
|
- Single (`ai-conventional-commit` / `ai-conventional-commit generate`) or multi-commit planning (`ai-conventional-commit split`)
|
|
13
13
|
- Refinement workflow (`ai-conventional-commit refine`) to iteratively tweak a prior result
|
|
14
|
-
- Gitmoji modes: `--gitmoji` (emoji + type
|
|
15
|
-
|
|
14
|
+
- Gitmoji modes: `--gitmoji[-pure]` (plain adds emoji + type, pure removes type)
|
|
15
|
+
|
|
16
16
|
- Privacy tiers governing diff detail sent to model
|
|
17
17
|
- Title normalization + guardrails (length, conventional schema, secret heuristic)
|
|
18
18
|
- Plugin system (transform + validate phases)
|
|
@@ -64,12 +64,61 @@ ai-conventional-commit split
|
|
|
64
64
|
ai-conventional-commit --gitmoji
|
|
65
65
|
# Pure gitmoji (emoji: subject)
|
|
66
66
|
ai-conventional-commit --gitmoji-pure
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
|
|
68
|
+
|
|
69
69
|
# Refine previous session’s first commit making it shorter
|
|
70
70
|
ai-conventional-commit refine --shorter
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
## Timed Output
|
|
74
|
+
|
|
75
|
+
Final success lines now include count + duration, e.g.:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
└ ✨ commit created in 850ms.
|
|
79
|
+
└ ✨ 3 commits created in 2.4s.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Durations under 100ms show raw milliseconds; otherwise one decimal second precision.
|
|
83
|
+
|
|
84
|
+
## Commands
|
|
85
|
+
|
|
86
|
+
| Command | Purpose |
|
|
87
|
+
| --------------------------------- | ------------------------------------------- |
|
|
88
|
+
| `ai-conventional-commit` | Generate single commit suggestion (default) |
|
|
89
|
+
| `ai-conventional-commit generate` | Same as root (explicit) |
|
|
90
|
+
| `ai-conventional-commit split` | Propose multiple commits (plan) |
|
|
91
|
+
| `ai-conventional-commit refine` | Refine last session result |
|
|
92
|
+
|
|
93
|
+
### Help Output
|
|
94
|
+
|
|
95
|
+
```text
|
|
96
|
+
$ ai-conventional-commit --help
|
|
97
|
+
ai-conventional-commit vX.Y.Z
|
|
98
|
+
|
|
99
|
+
Usage:
|
|
100
|
+
ai-conventional-commit [generate] [options] Generate a commit (default)
|
|
101
|
+
ai-conventional-commit split [options] Propose multiple commits
|
|
102
|
+
ai-conventional-commit refine [options] Refine last or indexed commit
|
|
103
|
+
|
|
104
|
+
Global Options:
|
|
105
|
+
-m, --model <provider/name> Override model provider/name
|
|
106
|
+
--gitmoji[-pure] Gitmoji modes (emoji + type / pure emoji only)
|
|
107
|
+
-h, --help Show this help
|
|
108
|
+
-V, --version Show version
|
|
109
|
+
|
|
110
|
+
Refine Options:
|
|
111
|
+
--shorter / --longer Adjust message length
|
|
112
|
+
--scope <scope> Add or replace scope
|
|
113
|
+
--emoji Add suitable gitmoji
|
|
114
|
+
--index <n> Select commit index
|
|
115
|
+
|
|
116
|
+
Examples:
|
|
117
|
+
ai-conventional-commit --gitmoji
|
|
118
|
+
ai-conventional-commit split --max 3
|
|
119
|
+
ai-conventional-commit refine --scope api --emoji
|
|
120
|
+
```
|
|
121
|
+
|
|
73
122
|
## Gitmoji Modes
|
|
74
123
|
|
|
75
124
|
| Mode | Example | Notes |
|
|
@@ -78,17 +127,7 @@ ai-conventional-commit refine --shorter
|
|
|
78
127
|
| gitmoji | `✨ feat: add search box` | Emoji + conventional type retained |
|
|
79
128
|
| gitmoji-pure | `✨: add search box` | Type removed, emoji acts as category |
|
|
80
129
|
|
|
81
|
-
Enable via CLI flags (`--gitmoji`
|
|
82
|
-
|
|
83
|
-
## Reasoning Depth
|
|
84
|
-
|
|
85
|
-
Controls verbosity of reasons array in the JSON returned by the model:
|
|
86
|
-
|
|
87
|
-
- low: minimal
|
|
88
|
-
- medium: balanced
|
|
89
|
-
- high: detailed, more hunk-specific references
|
|
90
|
-
|
|
91
|
-
Configured with `--reasoning` or in config (`reasoning`).
|
|
130
|
+
Enable via CLI flags (`--gitmoji` or `--gitmoji-pure`, shorthand `--gitmoji[-pure]`) or config (`gitmoji: true`, `gitmojiMode`).
|
|
92
131
|
|
|
93
132
|
## Privacy Modes
|
|
94
133
|
|
|
@@ -108,7 +147,7 @@ Uses cosmiconfig; supports JSON, YAML, etc. Example:
|
|
|
108
147
|
"privacy": "low",
|
|
109
148
|
"gitmoji": true,
|
|
110
149
|
"gitmojiMode": "gitmoji",
|
|
111
|
-
|
|
150
|
+
|
|
112
151
|
"styleSamples": 120,
|
|
113
152
|
"plugins": ["./src/sample-plugin/example-plugin.ts"],
|
|
114
153
|
"maxTokens": 512
|
|
@@ -129,7 +168,6 @@ Uses cosmiconfig; supports JSON, YAML, etc. Example:
|
|
|
129
168
|
- `AICC_DEBUG` (provider debug logs)
|
|
130
169
|
- `AICC_PRINT_LOGS` (stream model raw output)
|
|
131
170
|
- `AICC_DEBUG_PROVIDER=mock` (deterministic JSON response)
|
|
132
|
-
- `AICC_REASONING` (low|medium|high)
|
|
133
171
|
|
|
134
172
|
## Conventional Commits Enforcement
|
|
135
173
|
|
package/dist/index.cjs
CHANGED
|
@@ -27,7 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var import_clipanion = require("clipanion");
|
|
28
28
|
|
|
29
29
|
// src/workflow/generate.ts
|
|
30
|
-
var
|
|
30
|
+
var import_chalk2 = __toESM(require("chalk"), 1);
|
|
31
31
|
var import_ora = __toESM(require("ora"), 1);
|
|
32
32
|
|
|
33
33
|
// src/git.ts
|
|
@@ -218,9 +218,6 @@ var buildGenerationMessages = (opts) => {
|
|
|
218
218
|
specLines.push(
|
|
219
219
|
"Provide reasons array citing concrete diff elements: filenames, functions, tests, metrics."
|
|
220
220
|
);
|
|
221
|
-
specLines.push(
|
|
222
|
-
`Reasoning Depth: ${config.reasoning || "low"} (low=minimal concise reasons, medium=balanced detail, high=very detailed). Adjust reasons verbosity accordingly.`
|
|
223
|
-
);
|
|
224
221
|
specLines.push("Return ONLY the JSON object. No surrounding text or markdown.");
|
|
225
222
|
specLines.push("Do not add fields not listed in schema.");
|
|
226
223
|
specLines.push("Never fabricate content not present or implied by the diff.");
|
|
@@ -570,10 +567,36 @@ var formatCommitTitle = (raw, opts) => {
|
|
|
570
567
|
var import_node_fs = require("fs");
|
|
571
568
|
var import_node_path2 = require("path");
|
|
572
569
|
var import_inquirer = __toESM(require("inquirer"), 1);
|
|
570
|
+
|
|
571
|
+
// src/workflow/panel.ts
|
|
572
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
573
|
+
function buildPanel(opts) {
|
|
574
|
+
const termWidth = process.stdout.columns || 80;
|
|
575
|
+
const contentLines = opts.lines && opts.lines.length ? opts.lines : [];
|
|
576
|
+
const maxContent = Math.max(
|
|
577
|
+
opts.title ? stripAnsi(opts.title).length : 0,
|
|
578
|
+
...contentLines.map((l) => stripAnsi(l).length)
|
|
579
|
+
);
|
|
580
|
+
const innerWidth = Math.min(opts.width || maxContent, termWidth - 4);
|
|
581
|
+
const pad = (s) => {
|
|
582
|
+
const visible = stripAnsi(s).length;
|
|
583
|
+
const needed = innerWidth - visible;
|
|
584
|
+
return s + " ".repeat(Math.max(0, needed));
|
|
585
|
+
};
|
|
586
|
+
const top = "\u250C " + pad(opts.title ? import_chalk.default.bold(opts.title) : "") + " \u2510";
|
|
587
|
+
const body = contentLines.map((l) => "\u2502 " + pad(l) + " \u2502");
|
|
588
|
+
const bottom = "\u2514" + "\u2500".repeat(innerWidth + 2) + "\u2518";
|
|
589
|
+
return [top, ...body, bottom].join("\n");
|
|
590
|
+
}
|
|
591
|
+
function stripAnsi(str) {
|
|
592
|
+
return str.replace(/\u001B\[[0-9;]*m/g, "");
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// src/workflow/generate.ts
|
|
573
596
|
async function animateHeader() {
|
|
574
597
|
const text = "ai-conventional-commit";
|
|
575
598
|
if (!process.stdout.isTTY || process.env.AICC_NO_ANIMATION) {
|
|
576
|
-
console.log("\n\u250C " +
|
|
599
|
+
console.log("\n\u250C " + import_chalk2.default.bold(text));
|
|
577
600
|
return;
|
|
578
601
|
}
|
|
579
602
|
const palette = [
|
|
@@ -590,7 +613,7 @@ async function animateHeader() {
|
|
|
590
613
|
];
|
|
591
614
|
process.stdout.write("\n");
|
|
592
615
|
for (const color of palette) {
|
|
593
|
-
const frame =
|
|
616
|
+
const frame = import_chalk2.default.bold.hex(color)(text);
|
|
594
617
|
process.stdout.write("\r\u250C " + frame);
|
|
595
618
|
await new Promise((r) => setTimeout(r, 60));
|
|
596
619
|
}
|
|
@@ -606,16 +629,25 @@ async function runGenerate(config) {
|
|
|
606
629
|
console.log("No diff content detected after staging. Aborting.");
|
|
607
630
|
return;
|
|
608
631
|
}
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
)
|
|
614
|
-
|
|
615
|
-
|
|
632
|
+
const fileLines = [
|
|
633
|
+
import_chalk2.default.dim(`Detected ${files.length} staged ${files.length === 1 ? "file" : "files"}:`),
|
|
634
|
+
...files.map((f) => "\u2022 " + f.file)
|
|
635
|
+
];
|
|
636
|
+
if (process.stdout.isTTY) {
|
|
637
|
+
await animateHeader();
|
|
638
|
+
console.log(
|
|
639
|
+
buildPanel({
|
|
640
|
+
title: "Files",
|
|
641
|
+
lines: fileLines
|
|
642
|
+
})
|
|
643
|
+
);
|
|
644
|
+
} else {
|
|
645
|
+
console.log("\nFiles:");
|
|
646
|
+
fileLines.forEach((l) => console.log(" " + l));
|
|
647
|
+
}
|
|
616
648
|
const spinner = (0, import_ora.default)({ text: " Starting", spinner: "dots" }).start();
|
|
617
649
|
function setPhase(label) {
|
|
618
|
-
spinner.text = " " +
|
|
650
|
+
spinner.text = " " + import_chalk2.default.bold(label);
|
|
619
651
|
}
|
|
620
652
|
async function runStep(label, fn) {
|
|
621
653
|
setPhase(label);
|
|
@@ -652,7 +684,7 @@ async function runGenerate(config) {
|
|
|
652
684
|
async () => applyTransforms(plan.commits, plugins, { cwd: process.cwd(), env: process.env })
|
|
653
685
|
);
|
|
654
686
|
setPhase("Result found");
|
|
655
|
-
spinner.stopAndPersist({ symbol: "\u25C6", text: " " +
|
|
687
|
+
spinner.stopAndPersist({ symbol: "\u25C6", text: " " + import_chalk2.default.bold("Result found:") });
|
|
656
688
|
candidates = candidates.map((c) => ({
|
|
657
689
|
...c,
|
|
658
690
|
title: formatCommitTitle(c.title, {
|
|
@@ -661,16 +693,24 @@ async function runGenerate(config) {
|
|
|
661
693
|
})
|
|
662
694
|
}));
|
|
663
695
|
const chosen = candidates[0];
|
|
664
|
-
|
|
696
|
+
const resultLines = [import_chalk2.default.white(chosen.title)];
|
|
665
697
|
if (chosen.body) {
|
|
666
|
-
const indent = " ";
|
|
667
|
-
console.log(indent);
|
|
668
698
|
chosen.body.split("\n").forEach((line) => {
|
|
669
|
-
if (line.trim().length === 0)
|
|
670
|
-
else
|
|
699
|
+
if (line.trim().length === 0) resultLines.push("");
|
|
700
|
+
else resultLines.push(import_chalk2.default.white(line));
|
|
671
701
|
});
|
|
672
702
|
}
|
|
673
|
-
|
|
703
|
+
if (process.stdout.isTTY) {
|
|
704
|
+
console.log(
|
|
705
|
+
buildPanel({
|
|
706
|
+
title: "Result",
|
|
707
|
+
lines: resultLines
|
|
708
|
+
})
|
|
709
|
+
);
|
|
710
|
+
} else {
|
|
711
|
+
console.log("\nResult:");
|
|
712
|
+
resultLines.forEach((l) => console.log(" " + l));
|
|
713
|
+
}
|
|
674
714
|
const pluginErrors = await runValidations(chosen, plugins, {
|
|
675
715
|
cwd: process.cwd(),
|
|
676
716
|
env: process.env
|
|
@@ -678,9 +718,18 @@ async function runGenerate(config) {
|
|
|
678
718
|
const guardErrors = checkCandidate(chosen);
|
|
679
719
|
const errors = [...pluginErrors, ...guardErrors];
|
|
680
720
|
if (errors.length) {
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
721
|
+
const errorLines = ["Validation issues:", ...errors.map((e) => import_chalk2.default.red("\u2022 " + e))];
|
|
722
|
+
if (process.stdout.isTTY) {
|
|
723
|
+
console.log(
|
|
724
|
+
buildPanel({
|
|
725
|
+
title: "Checks",
|
|
726
|
+
lines: errorLines
|
|
727
|
+
})
|
|
728
|
+
);
|
|
729
|
+
} else {
|
|
730
|
+
console.log("\nValidation issues:");
|
|
731
|
+
errorLines.slice(1).forEach((l) => console.log(" " + l));
|
|
732
|
+
}
|
|
684
733
|
}
|
|
685
734
|
const yn = await selectYesNo();
|
|
686
735
|
if (!yn) {
|
|
@@ -689,7 +738,7 @@ async function runGenerate(config) {
|
|
|
689
738
|
}
|
|
690
739
|
await createCommit(chosen.title, chosen.body);
|
|
691
740
|
saveSession({ plan, chosen, mode: "single" });
|
|
692
|
-
console.log(
|
|
741
|
+
console.log(import_chalk2.default.green("Commit created."));
|
|
693
742
|
}
|
|
694
743
|
function saveSession(data) {
|
|
695
744
|
const dir = ".git/.aicc-cache";
|
|
@@ -713,7 +762,7 @@ async function selectYesNo() {
|
|
|
713
762
|
}
|
|
714
763
|
|
|
715
764
|
// src/workflow/split.ts
|
|
716
|
-
var
|
|
765
|
+
var import_chalk3 = __toESM(require("chalk"), 1);
|
|
717
766
|
|
|
718
767
|
// src/cluster.ts
|
|
719
768
|
var topLevel = (file) => file.split("/")[0] || file;
|
|
@@ -812,14 +861,14 @@ async function runSplit(config, desired) {
|
|
|
812
861
|
mode: config.gitmojiMode || "standard"
|
|
813
862
|
})
|
|
814
863
|
}));
|
|
815
|
-
console.log(
|
|
864
|
+
console.log(import_chalk3.default.cyan("\nProposed commits:"));
|
|
816
865
|
candidates.forEach((c) => {
|
|
817
|
-
console.log(
|
|
866
|
+
console.log(import_chalk3.default.yellow(`\u2022 ${c.title}`));
|
|
818
867
|
if (c.body) {
|
|
819
868
|
const indent = " ";
|
|
820
869
|
c.body.split("\n").forEach((line) => {
|
|
821
870
|
if (line.trim().length === 0) console.log(indent);
|
|
822
|
-
else console.log(indent +
|
|
871
|
+
else console.log(indent + import_chalk3.default.gray(line));
|
|
823
872
|
});
|
|
824
873
|
}
|
|
825
874
|
});
|
|
@@ -847,12 +896,12 @@ async function runSplit(config, desired) {
|
|
|
847
896
|
const guardErrors = checkCandidate(candidate);
|
|
848
897
|
const errors = [...pluginErrors, ...guardErrors];
|
|
849
898
|
if (errors.length) {
|
|
850
|
-
console.log(
|
|
899
|
+
console.log(import_chalk3.default.red("Skipping commit due to errors:"), candidate.title);
|
|
851
900
|
errors.forEach((e) => console.log(" -", e));
|
|
852
901
|
continue;
|
|
853
902
|
}
|
|
854
903
|
await createCommit(candidate.title, candidate.body);
|
|
855
|
-
console.log(
|
|
904
|
+
console.log(import_chalk3.default.green("Committed: ") + candidate.title);
|
|
856
905
|
}
|
|
857
906
|
saveSession2({ plan, chosen: candidates, mode: "split" });
|
|
858
907
|
}
|
|
@@ -863,7 +912,7 @@ function saveSession2(data) {
|
|
|
863
912
|
}
|
|
864
913
|
|
|
865
914
|
// src/workflow/refine.ts
|
|
866
|
-
var
|
|
915
|
+
var import_chalk4 = __toESM(require("chalk"), 1);
|
|
867
916
|
var import_ora2 = __toESM(require("ora"), 1);
|
|
868
917
|
var import_node_fs3 = require("fs");
|
|
869
918
|
var import_node_path4 = require("path");
|
|
@@ -939,19 +988,19 @@ async function runRefine(config, options) {
|
|
|
939
988
|
mode: config.gitmojiMode || "standard"
|
|
940
989
|
});
|
|
941
990
|
}
|
|
942
|
-
console.log(
|
|
943
|
-
console.log(
|
|
991
|
+
console.log(import_chalk4.default.cyan("\nRefined candidate:"));
|
|
992
|
+
console.log(import_chalk4.default.yellow(refined.commits[0].title));
|
|
944
993
|
if (refined.commits[0].body) {
|
|
945
994
|
const indent = " ";
|
|
946
995
|
refined.commits[0].body.split("\n").forEach((line) => {
|
|
947
996
|
if (line.trim().length === 0) console.log(indent);
|
|
948
|
-
else console.log(indent +
|
|
997
|
+
else console.log(indent + import_chalk4.default.gray(line));
|
|
949
998
|
});
|
|
950
999
|
}
|
|
951
1000
|
const accept = await prompt("Accept refined version? (Y/n) ", "y");
|
|
952
1001
|
if (!/^n/i.test(accept)) {
|
|
953
1002
|
plan.commits[index] = refined.commits[0];
|
|
954
|
-
console.log(
|
|
1003
|
+
console.log(import_chalk4.default.green("Refinement stored (not retro-committed)."));
|
|
955
1004
|
} else {
|
|
956
1005
|
console.log("Refinement discarded.");
|
|
957
1006
|
}
|
|
@@ -970,8 +1019,7 @@ var DEFAULTS = {
|
|
|
970
1019
|
maxTokens: parseInt(process.env.AICC_MAX_TOKENS || "512", 10),
|
|
971
1020
|
cacheDir: ".git/.aicc-cache",
|
|
972
1021
|
plugins: [],
|
|
973
|
-
verbose: process.env.AICC_VERBOSE === "true"
|
|
974
|
-
reasoning: process.env.AICC_REASONING || "low"
|
|
1022
|
+
verbose: process.env.AICC_VERBOSE === "true"
|
|
975
1023
|
};
|
|
976
1024
|
async function loadConfig(cwd = process.cwd()) {
|
|
977
1025
|
const explorer = (0, import_cosmiconfig.cosmiconfig)("aicc");
|
|
@@ -988,52 +1036,103 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
988
1036
|
}
|
|
989
1037
|
|
|
990
1038
|
// src/index.ts
|
|
1039
|
+
var import_module = require("module");
|
|
1040
|
+
var import_meta = {};
|
|
1041
|
+
var require2 = (0, import_module.createRequire)(import_meta.url);
|
|
1042
|
+
var pkgVersion = "0.0.0";
|
|
1043
|
+
try {
|
|
1044
|
+
const pkg = require2("../package.json");
|
|
1045
|
+
pkgVersion = pkg.version || pkgVersion;
|
|
1046
|
+
} catch {
|
|
1047
|
+
}
|
|
991
1048
|
var GenerateCommand = class extends import_clipanion.Command {
|
|
992
|
-
static paths = [[`generate`], [
|
|
1049
|
+
static paths = [[`generate`], []];
|
|
1050
|
+
static usage = import_clipanion.Command.Usage({
|
|
1051
|
+
description: "Generate a conventional commit message for staged changes (aliases: run, commit).",
|
|
1052
|
+
details: `Generates a single commit message using AI with style + guardrails.
|
|
1053
|
+
Add --gitmoji or --gitmoji-pure to enable emoji styles.`,
|
|
1054
|
+
examples: [
|
|
1055
|
+
["Generate a commit with gitmoji style", "ai-conventional-commit generate --gitmoji"]
|
|
1056
|
+
]
|
|
1057
|
+
});
|
|
993
1058
|
gitmoji = import_clipanion.Option.Boolean("--gitmoji", false, {
|
|
994
|
-
description: "Gitmoji mode: emoji
|
|
1059
|
+
description: "Gitmoji mode (vs --gitmoji-pure): emoji + type (emoji: subject)"
|
|
995
1060
|
});
|
|
996
1061
|
gitmojiPure = import_clipanion.Option.Boolean("--gitmoji-pure", false, {
|
|
997
|
-
description: "Pure gitmoji mode: emoji
|
|
1062
|
+
description: "Pure gitmoji mode (vs --gitmoji): emoji only (emoji: subject)"
|
|
1063
|
+
});
|
|
1064
|
+
model = import_clipanion.Option.String("-m,--model", {
|
|
1065
|
+
required: false,
|
|
1066
|
+
description: "Model provider/name (e.g. github-copilot/gpt-5)"
|
|
998
1067
|
});
|
|
999
|
-
reasoning = import_clipanion.Option.String("--reasoning", { required: false });
|
|
1000
1068
|
async execute() {
|
|
1001
1069
|
const config = await loadConfig();
|
|
1002
1070
|
if (this.gitmoji || this.gitmojiPure) {
|
|
1003
1071
|
config.gitmoji = true;
|
|
1004
1072
|
config.gitmojiMode = this.gitmojiPure ? "gitmoji-pure" : "gitmoji";
|
|
1005
1073
|
}
|
|
1006
|
-
if (this.
|
|
1074
|
+
if (this.model) config.model = this.model;
|
|
1007
1075
|
await runGenerate(config);
|
|
1008
1076
|
}
|
|
1009
1077
|
};
|
|
1010
1078
|
var SplitCommand = class extends import_clipanion.Command {
|
|
1011
1079
|
static paths = [[`split`]];
|
|
1080
|
+
static usage = import_clipanion.Command.Usage({
|
|
1081
|
+
description: "Propose multiple smaller conventional commits for current staged diff.",
|
|
1082
|
+
details: `Analyzes staged changes, groups them logically and suggests multiple commit messages.
|
|
1083
|
+
Use --max to limit the number of proposals.`,
|
|
1084
|
+
examples: [
|
|
1085
|
+
[
|
|
1086
|
+
"Split into at most 3 commits with gitmoji",
|
|
1087
|
+
"ai-conventional-commit split --max 3 --gitmoji"
|
|
1088
|
+
]
|
|
1089
|
+
]
|
|
1090
|
+
});
|
|
1012
1091
|
max = import_clipanion.Option.String("--max", { description: "Max proposed commits", required: false });
|
|
1013
|
-
gitmoji = import_clipanion.Option.Boolean("--gitmoji", false
|
|
1014
|
-
|
|
1015
|
-
|
|
1092
|
+
gitmoji = import_clipanion.Option.Boolean("--gitmoji", false, {
|
|
1093
|
+
description: "Gitmoji mode (vs --gitmoji-pure): emoji + type"
|
|
1094
|
+
});
|
|
1095
|
+
gitmojiPure = import_clipanion.Option.Boolean("--gitmoji-pure", false, {
|
|
1096
|
+
description: "Pure gitmoji mode (vs --gitmoji): emoji only"
|
|
1097
|
+
});
|
|
1098
|
+
model = import_clipanion.Option.String("-m,--model", {
|
|
1099
|
+
required: false,
|
|
1100
|
+
description: "Model provider/name override"
|
|
1101
|
+
});
|
|
1016
1102
|
async execute() {
|
|
1017
1103
|
const config = await loadConfig();
|
|
1018
1104
|
if (this.gitmoji || this.gitmojiPure) {
|
|
1019
1105
|
config.gitmoji = true;
|
|
1020
1106
|
config.gitmojiMode = this.gitmojiPure ? "gitmoji-pure" : "gitmoji";
|
|
1021
1107
|
}
|
|
1022
|
-
if (this.
|
|
1108
|
+
if (this.model) config.model = this.model;
|
|
1023
1109
|
await runSplit(config, this.max ? parseInt(this.max, 10) : void 0);
|
|
1024
1110
|
}
|
|
1025
1111
|
};
|
|
1026
1112
|
var RefineCommand = class extends import_clipanion.Command {
|
|
1027
1113
|
static paths = [[`refine`]];
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1114
|
+
static usage = import_clipanion.Command.Usage({
|
|
1115
|
+
description: "Refine the last (or chosen) commit message with style rules.",
|
|
1116
|
+
details: `Allows targeted improvements: shorter/longer length, inject scope, add emoji, or select a specific index when multiple commits were generated earlier.`,
|
|
1117
|
+
examples: [
|
|
1118
|
+
["Shorten the last commit message", "ai-conventional-commit refine --shorter"],
|
|
1119
|
+
["Add a scope to the last commit", "ai-conventional-commit refine --scope ui"]
|
|
1120
|
+
]
|
|
1121
|
+
});
|
|
1122
|
+
shorter = import_clipanion.Option.Boolean("--shorter", false, { description: "Make message more concise" });
|
|
1123
|
+
longer = import_clipanion.Option.Boolean("--longer", false, { description: "Expand message with detail" });
|
|
1124
|
+
scope = import_clipanion.Option.String("--scope", { description: "Override/add scope (e.g. ui, api)" });
|
|
1125
|
+
emoji = import_clipanion.Option.Boolean("--emoji", false, { description: "Add appropriate gitmoji (non-pure)" });
|
|
1126
|
+
index = import_clipanion.Option.String("--index", {
|
|
1127
|
+
description: "Select commit index if multiple were generated"
|
|
1128
|
+
});
|
|
1129
|
+
model = import_clipanion.Option.String("-m,--model", {
|
|
1130
|
+
required: false,
|
|
1131
|
+
description: "Model provider/name override"
|
|
1132
|
+
});
|
|
1034
1133
|
async execute() {
|
|
1035
1134
|
const config = await loadConfig();
|
|
1036
|
-
if (this.
|
|
1135
|
+
if (this.model) config.model = this.model;
|
|
1037
1136
|
await runRefine(config, {
|
|
1038
1137
|
shorter: this.shorter,
|
|
1039
1138
|
longer: this.longer,
|
|
@@ -1043,14 +1142,57 @@ var RefineCommand = class extends import_clipanion.Command {
|
|
|
1043
1142
|
});
|
|
1044
1143
|
}
|
|
1045
1144
|
};
|
|
1145
|
+
var HelpCommand = class extends import_clipanion.Command {
|
|
1146
|
+
static paths = [[`--help`], [`-h`]];
|
|
1147
|
+
// capture explicit help
|
|
1148
|
+
async execute() {
|
|
1149
|
+
this.context.stdout.write(globalHelp() + "\n");
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
function globalHelp() {
|
|
1153
|
+
return `ai-conventional-commit v${pkgVersion}
|
|
1154
|
+
|
|
1155
|
+
Usage:
|
|
1156
|
+
ai-conventional-commit [generate] [options] Generate a commit (default)
|
|
1157
|
+
ai-conventional-commit split [options] Propose multiple commits
|
|
1158
|
+
ai-conventional-commit refine [options] Refine last or indexed commit
|
|
1159
|
+
|
|
1160
|
+
Global Options:
|
|
1161
|
+
-m, --model <provider/name> Override model provider/name
|
|
1162
|
+
--gitmoji Gitmoji mode (emoji + type)
|
|
1163
|
+
--gitmoji-pure Gitmoji pure mode (emoji only)
|
|
1164
|
+
-h, --help Show this help
|
|
1165
|
+
-V, --version Show version
|
|
1166
|
+
|
|
1167
|
+
Refine Options:
|
|
1168
|
+
--shorter / --longer Adjust message length
|
|
1169
|
+
--scope <scope> Add or replace scope
|
|
1170
|
+
--emoji Add suitable gitmoji
|
|
1171
|
+
--index <n> Select commit index
|
|
1172
|
+
|
|
1173
|
+
Examples:
|
|
1174
|
+
ai-conventional-commit --gitmoji
|
|
1175
|
+
ai-conventional-commit split --max 3
|
|
1176
|
+
ai-conventional-commit refine --scope api --emoji
|
|
1177
|
+
`;
|
|
1178
|
+
}
|
|
1179
|
+
var VersionCommand = class extends import_clipanion.Command {
|
|
1180
|
+
static paths = [[`--version`], [`-V`]];
|
|
1181
|
+
async execute() {
|
|
1182
|
+
this.context.stdout.write(`${pkgVersion}
|
|
1183
|
+
`);
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1046
1186
|
var cli = new import_clipanion.Cli({
|
|
1047
1187
|
binaryLabel: "ai-conventional-commit",
|
|
1048
1188
|
binaryName: "ai-conventional-commit",
|
|
1049
|
-
binaryVersion:
|
|
1189
|
+
binaryVersion: pkgVersion
|
|
1050
1190
|
});
|
|
1051
1191
|
cli.register(GenerateCommand);
|
|
1052
1192
|
cli.register(SplitCommand);
|
|
1053
1193
|
cli.register(RefineCommand);
|
|
1194
|
+
cli.register(HelpCommand);
|
|
1195
|
+
cli.register(VersionCommand);
|
|
1054
1196
|
cli.runExit(process.argv.slice(2), {
|
|
1055
1197
|
stdin: process.stdin,
|
|
1056
1198
|
stdout: process.stdout,
|