@kyubiware/commit-mint 0.9.4 → 0.10.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 +2 -1
- package/dist/bin.mjs +46 -14
- package/dist/bin.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -72,6 +72,7 @@ cmint # interactive cli for committing changes
|
|
|
72
72
|
```bash
|
|
73
73
|
cmint # interactive: stage → checks → review → commit
|
|
74
74
|
cmint -a # auto-group, generate messages, commit everything
|
|
75
|
+
cmint -a 3 # auto-group into exactly 3 commits
|
|
75
76
|
cmint -s # stage all tracked files in single commit, skip staging menu
|
|
76
77
|
cmint config # edit provider, model, locale, etc.
|
|
77
78
|
cmint update # update cmint to the latest published version
|
|
@@ -185,7 +186,7 @@ single raw-stderr entry.
|
|
|
185
186
|
|
|
186
187
|
| Flag | Description |
|
|
187
188
|
|---|---|
|
|
188
|
-
| `-a`, `--auto` | Auto-
|
|
189
|
+
| `-a`, `--auto [N]` | Auto-group files into N commits (default: LLM decides). Use `-a 0` or `-a` for AI-determined groups |
|
|
189
190
|
| `-m`, `--message <msg>` | Use your own message instead of AI generation |
|
|
190
191
|
| `-H`, `--hint <hint>` | Context hint to the AI (e.g. `"refactor only"`) |
|
|
191
192
|
| `-r`, `--retry` | Retry last failed commit (uses cached message) |
|
package/dist/bin.mjs
CHANGED
|
@@ -33,7 +33,7 @@ var __exportAll = (all, no_symbols) => {
|
|
|
33
33
|
//#region package.json
|
|
34
34
|
var package_default = {
|
|
35
35
|
name: "@kyubiware/commit-mint",
|
|
36
|
-
version: "0.
|
|
36
|
+
version: "0.10.0",
|
|
37
37
|
description: "🌿 AI-powered git commit tool — auto-group changed files, generate messages, run pre-commit checks",
|
|
38
38
|
type: "module",
|
|
39
39
|
bin: { "cmint": "./dist/bin.mjs" },
|
|
@@ -1727,8 +1727,8 @@ function statusIndicator(status) {
|
|
|
1727
1727
|
function buildFileSummary(files) {
|
|
1728
1728
|
return files.map((f) => `${f.path} (${statusIndicator(f.status)})`).join("\n");
|
|
1729
1729
|
}
|
|
1730
|
-
function buildGroupingSystemPrompt() {
|
|
1731
|
-
|
|
1730
|
+
function buildGroupingSystemPrompt(groupCount) {
|
|
1731
|
+
const lines = [
|
|
1732
1732
|
"You are analyzing changed files in a git repository. Group them into logical commits based on what changed and why. Each group should be a coherent unit of work.",
|
|
1733
1733
|
"",
|
|
1734
1734
|
"Rules:",
|
|
@@ -1745,7 +1745,9 @@ function buildGroupingSystemPrompt() {
|
|
|
1745
1745
|
"files: array of exact file paths from the input",
|
|
1746
1746
|
"",
|
|
1747
1747
|
"Output ONLY valid JSON. No markdown fences, no explanation."
|
|
1748
|
-
]
|
|
1748
|
+
];
|
|
1749
|
+
if (groupCount && groupCount > 0) lines.unshift(`Create exactly ${groupCount} groups.`);
|
|
1750
|
+
return lines.join("\n");
|
|
1749
1751
|
}
|
|
1750
1752
|
function buildGroupingUserPrompt(summary) {
|
|
1751
1753
|
return [
|
|
@@ -1778,7 +1780,24 @@ function buildRetryGroupingPrompt() {
|
|
|
1778
1780
|
"Output ONLY valid JSON. No markdown fences, no explanation."
|
|
1779
1781
|
].join("\n");
|
|
1780
1782
|
}
|
|
1781
|
-
|
|
1783
|
+
/**
|
|
1784
|
+
* When a specific group count is requested but there are fewer included files
|
|
1785
|
+
* than groups, create one-file-per-group groups without calling the AI.
|
|
1786
|
+
* Returns null when the pre-condition is not met.
|
|
1787
|
+
*/
|
|
1788
|
+
function createPerFileGroups(files, groupCount, excluded) {
|
|
1789
|
+
if (!(groupCount && groupCount > 0 && files.length < groupCount)) return null;
|
|
1790
|
+
debug("generateGroups: %d files < %d requested groups, creating per-file groups", files.length, groupCount);
|
|
1791
|
+
return {
|
|
1792
|
+
groups: files.map((f) => ({
|
|
1793
|
+
name: f.path.split("/").pop() || f.path,
|
|
1794
|
+
description: `Changes to ${f.path}`,
|
|
1795
|
+
files: [f.path]
|
|
1796
|
+
})),
|
|
1797
|
+
excluded
|
|
1798
|
+
};
|
|
1799
|
+
}
|
|
1800
|
+
async function generateGroups(files, apiKey, model, timeout, provider, proxy, groupCount) {
|
|
1782
1801
|
debug("generateGroups: %d files, model=%s", files.length, model ?? "default");
|
|
1783
1802
|
const { included, excluded } = filterExcludedFiles(files);
|
|
1784
1803
|
if (included.length === 0) {
|
|
@@ -1788,8 +1807,10 @@ async function generateGroups(files, apiKey, model, timeout, provider, proxy) {
|
|
|
1788
1807
|
excluded
|
|
1789
1808
|
};
|
|
1790
1809
|
}
|
|
1810
|
+
const perFile = createPerFileGroups(included, groupCount, excluded);
|
|
1811
|
+
if (perFile) return perFile;
|
|
1791
1812
|
const summary = buildFileSummary(included);
|
|
1792
|
-
const systemPrompt = buildGroupingSystemPrompt();
|
|
1813
|
+
const systemPrompt = buildGroupingSystemPrompt(groupCount);
|
|
1793
1814
|
const userPrompt = buildGroupingUserPrompt(summary);
|
|
1794
1815
|
debug("File summary:\n%s", summary);
|
|
1795
1816
|
debug("User prompt length: %d chars", userPrompt.length);
|
|
@@ -2705,13 +2726,14 @@ async function runAutoGroupFlow(changedFiles, flags) {
|
|
|
2705
2726
|
await setConfigValue(configKey, String(key).trim());
|
|
2706
2727
|
debug("API key saved to config");
|
|
2707
2728
|
}
|
|
2729
|
+
const groupCount = typeof flags.auto === "number" ? flags.auto : 0;
|
|
2708
2730
|
const s = spinner();
|
|
2709
2731
|
s.start("Analyzing files...");
|
|
2710
|
-
const validatedGroups = validateGroups((await generateGroups(included, await getProviderApiKey(provider), getModelForProvider(config, provider, PROVIDER_CONFIGS[provider].defaultModel), config.timeout ? parseInt(config.timeout, 10) : void 0, provider, config.proxy)).groups, included);
|
|
2732
|
+
const validatedGroups = validateGroups((await generateGroups(included, await getProviderApiKey(provider), getModelForProvider(config, provider, PROVIDER_CONFIGS[provider].defaultModel), config.timeout ? parseInt(config.timeout, 10) : void 0, provider, config.proxy, groupCount)).groups, included);
|
|
2711
2733
|
s.stop("Files analyzed");
|
|
2712
2734
|
showGroupedFiles(validatedGroups, included);
|
|
2713
2735
|
const autoAccept = await getAutoAccept();
|
|
2714
|
-
const skipPrompts = flags.auto || autoAccept;
|
|
2736
|
+
const skipPrompts = flags.auto !== false || autoAccept;
|
|
2715
2737
|
if (skipPrompts) debug("Skipping grouping confirmation (auto=%s autoAccept=%s)", flags.auto, autoAccept);
|
|
2716
2738
|
else if (!await showGroupingConfirmation(validatedGroups, excluded)) {
|
|
2717
2739
|
outro(dim("Cancelled."));
|
|
@@ -3734,11 +3756,13 @@ function buildMultiSelectRender(message, options, output) {
|
|
|
3734
3756
|
return `${header}\n${dim(S_BAR_END)} ${cancelled}`;
|
|
3735
3757
|
}
|
|
3736
3758
|
default: {
|
|
3759
|
+
const stdio = output ?? process.stdout;
|
|
3760
|
+
const termRows = ("rows" in stdio ? stdio.rows : void 0) ?? 24;
|
|
3737
3761
|
const lines = limitOptions({
|
|
3738
3762
|
cursor,
|
|
3739
3763
|
options,
|
|
3740
3764
|
style: (opt, active) => renderCheckboxOption(opt.label, value.includes(opt.value), active),
|
|
3741
|
-
maxItems:
|
|
3765
|
+
maxItems: Math.min(options.length, Math.max(5, termRows - 3)),
|
|
3742
3766
|
output: output ?? process.stdout
|
|
3743
3767
|
}).map((line) => `${dim(S_BAR)} ${line}`);
|
|
3744
3768
|
const hintLine = "↑/↓ navigate · space select · enter confirm · A select all · N select none";
|
|
@@ -3863,11 +3887,14 @@ function buildPromptRenderer(opts, state) {
|
|
|
3863
3887
|
return `${header}\n${dim(S_BAR)} ${styleText(["strikethrough", "dim"], text)}\n${dim(S_BAR_END)}`;
|
|
3864
3888
|
}
|
|
3865
3889
|
default: {
|
|
3890
|
+
const stdio = opts.output ?? process.stdout;
|
|
3891
|
+
const termRows = ("rows" in stdio ? stdio.rows : void 0) ?? 24;
|
|
3892
|
+
const dynamicMax = Math.min(optionList.length, Math.max(5, termRows - 5));
|
|
3866
3893
|
const lines = limitOptions({
|
|
3867
3894
|
cursor: this.cursor,
|
|
3868
3895
|
options: optionList,
|
|
3869
3896
|
style: (opt, active) => renderOption(opt, active),
|
|
3870
|
-
maxItems:
|
|
3897
|
+
maxItems: dynamicMax,
|
|
3871
3898
|
output: opts.output ?? process.stdout
|
|
3872
3899
|
}).map((line) => `${dim(S_BAR)} ${line}`);
|
|
3873
3900
|
const hotkeysHint = toggleList.map((t) => `\`${t.hotkey}\` toggle ${t.label.toLowerCase()}`).join(" • ");
|
|
@@ -4096,7 +4123,7 @@ async function commitCommand(flags, version) {
|
|
|
4096
4123
|
if (flags.single) {
|
|
4097
4124
|
debug("Single-commit mode: staging all files");
|
|
4098
4125
|
await stageAll();
|
|
4099
|
-
} else if (flags.auto) {
|
|
4126
|
+
} else if (flags.auto !== false) {
|
|
4100
4127
|
if (flags.message) {
|
|
4101
4128
|
outro(red("--message flag is not compatible with auto-group mode."));
|
|
4102
4129
|
return;
|
|
@@ -4398,9 +4425,10 @@ async function agentCommand(flags) {
|
|
|
4398
4425
|
}
|
|
4399
4426
|
const model = getModelForProvider(config, provider, PROVIDER_CONFIGS[provider].defaultModel);
|
|
4400
4427
|
const timeout = config.timeout ? parseInt(config.timeout, 10) : void 0;
|
|
4428
|
+
const groupCount = typeof flags.auto === "number" ? flags.auto : 0;
|
|
4401
4429
|
let groups;
|
|
4402
4430
|
try {
|
|
4403
|
-
groups = validateGroups((await generateGroups(included, apiKey, model, timeout, provider, config.proxy)).groups, included);
|
|
4431
|
+
groups = validateGroups((await generateGroups(included, apiKey, model, timeout, provider, config.proxy, groupCount)).groups, included);
|
|
4404
4432
|
} catch (err) {
|
|
4405
4433
|
process.exitCode = EXIT_CODES.AI;
|
|
4406
4434
|
writeAgentResult({
|
|
@@ -4862,8 +4890,12 @@ cli({
|
|
|
4862
4890
|
default: false
|
|
4863
4891
|
},
|
|
4864
4892
|
auto: {
|
|
4865
|
-
type:
|
|
4866
|
-
|
|
4893
|
+
type: (raw) => {
|
|
4894
|
+
if (raw === "") return true;
|
|
4895
|
+
const n = Number(raw);
|
|
4896
|
+
return Number.isNaN(n) ? true : n;
|
|
4897
|
+
},
|
|
4898
|
+
description: "Auto-group files into commits. Use -a <N> to request N groups (0 = LLM decides)",
|
|
4867
4899
|
alias: "a",
|
|
4868
4900
|
default: false
|
|
4869
4901
|
},
|