@kud/ai-conventional-commit-cli 0.2.0 → 0.3.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 +1 -7
- package/dist/index.cjs +43 -14
- package/dist/index.js +43 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Opinionated, style-aware AI assistant for crafting, splitting, and refining git commit messages via the local `opencode` CLI. Uses your installed `opencode` models (default `github-copilot/gpt-5`).
|
|
4
4
|
|
|
5
|
-
Formerly referenced as `aicc` in examples. The canonical command name is now `ai-conventional-commit`.
|
|
6
|
-
|
|
7
5
|
## Why
|
|
8
6
|
|
|
9
7
|
Manual commit messages are noisy, inconsistent, and often miss context. ai-conventional-commit inspects your staged diff, learns your repo's commit style, and produces Conventional Commit messages (single or split) with explanations—optionally decorated with gitmoji.
|
|
@@ -33,14 +31,12 @@ ai-conventional-commit --help
|
|
|
33
31
|
|
|
34
32
|
### Optional Alias (Short Name)
|
|
35
33
|
|
|
36
|
-
If you prefer
|
|
34
|
+
If you prefer a shorter alias, add this to your shell profile:
|
|
37
35
|
|
|
38
36
|
```bash
|
|
39
37
|
alias aicc='ai-conventional-commit'
|
|
40
38
|
```
|
|
41
39
|
|
|
42
|
-
After that you can type `aicc` instead of the full command. All subsequent examples use the full name for clarity.
|
|
43
|
-
|
|
44
40
|
## Publishing
|
|
45
41
|
|
|
46
42
|
A build is automatically produced on `npm publish` via the `prepublishOnly` script so you can simply bump the version and run:
|
|
@@ -55,8 +51,6 @@ Only `dist`, `README.md`, and `LICENSE` are included in the published package (s
|
|
|
55
51
|
npm publish --dry-run
|
|
56
52
|
```
|
|
57
53
|
|
|
58
|
-
The shorter `aicc` binary has been removed from the package itself; create a local alias if you still prefer it.
|
|
59
|
-
|
|
60
54
|
## Quick Start
|
|
61
55
|
|
|
62
56
|
```bash
|
package/dist/index.cjs
CHANGED
|
@@ -296,7 +296,7 @@ var OpenCodeProvider = class {
|
|
|
296
296
|
Context:
|
|
297
297
|
${userAggregate}`;
|
|
298
298
|
if (mockMode) {
|
|
299
|
-
if (debug) console.error("[
|
|
299
|
+
if (debug) console.error("[ai-cc][mock] Returning deterministic mock response");
|
|
300
300
|
return JSON.stringify({
|
|
301
301
|
commits: [
|
|
302
302
|
{
|
|
@@ -327,7 +327,7 @@ ${userAggregate}`;
|
|
|
327
327
|
const elapsed = Date.now() - start;
|
|
328
328
|
if (debug) {
|
|
329
329
|
console.error(
|
|
330
|
-
`[
|
|
330
|
+
`[ai-cc][provider] model=${this.model} elapsedMs=${elapsed} promptChars=${fullPrompt.length} bytesOut=${value.length}`
|
|
331
331
|
);
|
|
332
332
|
}
|
|
333
333
|
resolve3(value);
|
|
@@ -340,7 +340,7 @@ ${userAggregate}`;
|
|
|
340
340
|
const candidate = acc.slice(first, last + 1).trim();
|
|
341
341
|
try {
|
|
342
342
|
JSON.parse(candidate);
|
|
343
|
-
if (debug) console.error("[
|
|
343
|
+
if (debug) console.error("[ai-cc][provider] eager JSON detected, terminating process");
|
|
344
344
|
subprocess.kill("SIGTERM");
|
|
345
345
|
finish(candidate);
|
|
346
346
|
} catch {
|
|
@@ -353,7 +353,7 @@ ${userAggregate}`;
|
|
|
353
353
|
tryEager();
|
|
354
354
|
});
|
|
355
355
|
subprocess.stderr?.on("data", (chunk) => {
|
|
356
|
-
if (debug) console.error("[
|
|
356
|
+
if (debug) console.error("[ai-cc][provider][stderr]", chunk.toString().trim());
|
|
357
357
|
});
|
|
358
358
|
subprocess.then(({ stdout }) => {
|
|
359
359
|
if (!resolved) finish(stdout);
|
|
@@ -365,7 +365,7 @@ ${userAggregate}`;
|
|
|
365
365
|
new Error(`Model call timed out after ${timeoutMs}ms (elapsed=${elapsed}ms)`)
|
|
366
366
|
);
|
|
367
367
|
}
|
|
368
|
-
if (debug) console.error("[
|
|
368
|
+
if (debug) console.error("[ai-cc][provider] failure", e.stderr || e.message);
|
|
369
369
|
reject(new Error(e.stderr || e.message || "opencode invocation failed"));
|
|
370
370
|
});
|
|
371
371
|
});
|
|
@@ -570,6 +570,32 @@ var formatCommitTitle = (raw, opts) => {
|
|
|
570
570
|
var import_node_fs = require("fs");
|
|
571
571
|
var import_node_path2 = require("path");
|
|
572
572
|
var import_inquirer = __toESM(require("inquirer"), 1);
|
|
573
|
+
async function animateHeader() {
|
|
574
|
+
const text = "ai-conventional-commit";
|
|
575
|
+
if (!process.stdout.isTTY || process.env.AICC_NO_ANIMATION) {
|
|
576
|
+
console.log("\n\u250C " + import_chalk.default.bold(text));
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
const palette = [
|
|
580
|
+
"#3a0d6d",
|
|
581
|
+
"#5a1ea3",
|
|
582
|
+
"#7a32d6",
|
|
583
|
+
"#9a4dff",
|
|
584
|
+
"#b267ff",
|
|
585
|
+
"#c37dff",
|
|
586
|
+
"#b267ff",
|
|
587
|
+
"#9a4dff",
|
|
588
|
+
"#7a32d6",
|
|
589
|
+
"#5a1ea3"
|
|
590
|
+
];
|
|
591
|
+
process.stdout.write("\n");
|
|
592
|
+
for (const color of palette) {
|
|
593
|
+
const frame = import_chalk.default.bold.hex(color)(text);
|
|
594
|
+
process.stdout.write("\r\u250C " + frame);
|
|
595
|
+
await new Promise((r) => setTimeout(r, 60));
|
|
596
|
+
}
|
|
597
|
+
process.stdout.write("\n");
|
|
598
|
+
}
|
|
573
599
|
async function runGenerate(config) {
|
|
574
600
|
if (!await ensureStagedChanges()) {
|
|
575
601
|
console.log("No staged changes.");
|
|
@@ -580,10 +606,12 @@ async function runGenerate(config) {
|
|
|
580
606
|
console.log("No diff content detected after staging. Aborting.");
|
|
581
607
|
return;
|
|
582
608
|
}
|
|
583
|
-
|
|
609
|
+
await animateHeader();
|
|
584
610
|
console.log("\u2502");
|
|
585
|
-
console.log(
|
|
586
|
-
|
|
611
|
+
console.log(
|
|
612
|
+
`\u25C6 ${import_chalk.default.bold(`Detected ${files.length} staged ${files.length === 1 ? "file" : "files"}:`)}`
|
|
613
|
+
);
|
|
614
|
+
for (const f of files) console.log(" \u2022 " + f.file);
|
|
587
615
|
console.log("\u2502");
|
|
588
616
|
const spinner = (0, import_ora.default)({ text: " Starting", spinner: "dots" }).start();
|
|
589
617
|
function setPhase(label) {
|
|
@@ -633,12 +661,13 @@ async function runGenerate(config) {
|
|
|
633
661
|
})
|
|
634
662
|
}));
|
|
635
663
|
const chosen = candidates[0];
|
|
636
|
-
console.log(" " + import_chalk.default.
|
|
664
|
+
console.log(" " + import_chalk.default.white(chosen.title));
|
|
637
665
|
if (chosen.body) {
|
|
638
666
|
const indent = " ";
|
|
667
|
+
console.log(indent);
|
|
639
668
|
chosen.body.split("\n").forEach((line) => {
|
|
640
669
|
if (line.trim().length === 0) console.log(indent);
|
|
641
|
-
else console.log(indent + import_chalk.default.
|
|
670
|
+
else console.log(indent + import_chalk.default.white(line));
|
|
642
671
|
});
|
|
643
672
|
}
|
|
644
673
|
console.log("\u2502");
|
|
@@ -674,8 +703,8 @@ async function selectYesNo() {
|
|
|
674
703
|
name: "choice",
|
|
675
704
|
message: " Use this commit message?",
|
|
676
705
|
choices: [
|
|
677
|
-
{ name: "
|
|
678
|
-
{ name: "
|
|
706
|
+
{ name: "Yes", value: true },
|
|
707
|
+
{ name: "No", value: false }
|
|
679
708
|
],
|
|
680
709
|
default: 0
|
|
681
710
|
}
|
|
@@ -1015,8 +1044,8 @@ var RefineCommand = class extends import_clipanion.Command {
|
|
|
1015
1044
|
}
|
|
1016
1045
|
};
|
|
1017
1046
|
var cli = new import_clipanion.Cli({
|
|
1018
|
-
binaryLabel: "
|
|
1019
|
-
binaryName: "
|
|
1047
|
+
binaryLabel: "ai-conventional-commit",
|
|
1048
|
+
binaryName: "ai-conventional-commit",
|
|
1020
1049
|
binaryVersion: "0.1.0"
|
|
1021
1050
|
});
|
|
1022
1051
|
cli.register(GenerateCommand);
|
package/dist/index.js
CHANGED
|
@@ -273,7 +273,7 @@ var OpenCodeProvider = class {
|
|
|
273
273
|
Context:
|
|
274
274
|
${userAggregate}`;
|
|
275
275
|
if (mockMode) {
|
|
276
|
-
if (debug) console.error("[
|
|
276
|
+
if (debug) console.error("[ai-cc][mock] Returning deterministic mock response");
|
|
277
277
|
return JSON.stringify({
|
|
278
278
|
commits: [
|
|
279
279
|
{
|
|
@@ -304,7 +304,7 @@ ${userAggregate}`;
|
|
|
304
304
|
const elapsed = Date.now() - start;
|
|
305
305
|
if (debug) {
|
|
306
306
|
console.error(
|
|
307
|
-
`[
|
|
307
|
+
`[ai-cc][provider] model=${this.model} elapsedMs=${elapsed} promptChars=${fullPrompt.length} bytesOut=${value.length}`
|
|
308
308
|
);
|
|
309
309
|
}
|
|
310
310
|
resolve3(value);
|
|
@@ -317,7 +317,7 @@ ${userAggregate}`;
|
|
|
317
317
|
const candidate = acc.slice(first, last + 1).trim();
|
|
318
318
|
try {
|
|
319
319
|
JSON.parse(candidate);
|
|
320
|
-
if (debug) console.error("[
|
|
320
|
+
if (debug) console.error("[ai-cc][provider] eager JSON detected, terminating process");
|
|
321
321
|
subprocess.kill("SIGTERM");
|
|
322
322
|
finish(candidate);
|
|
323
323
|
} catch {
|
|
@@ -330,7 +330,7 @@ ${userAggregate}`;
|
|
|
330
330
|
tryEager();
|
|
331
331
|
});
|
|
332
332
|
subprocess.stderr?.on("data", (chunk) => {
|
|
333
|
-
if (debug) console.error("[
|
|
333
|
+
if (debug) console.error("[ai-cc][provider][stderr]", chunk.toString().trim());
|
|
334
334
|
});
|
|
335
335
|
subprocess.then(({ stdout }) => {
|
|
336
336
|
if (!resolved) finish(stdout);
|
|
@@ -342,7 +342,7 @@ ${userAggregate}`;
|
|
|
342
342
|
new Error(`Model call timed out after ${timeoutMs}ms (elapsed=${elapsed}ms)`)
|
|
343
343
|
);
|
|
344
344
|
}
|
|
345
|
-
if (debug) console.error("[
|
|
345
|
+
if (debug) console.error("[ai-cc][provider] failure", e.stderr || e.message);
|
|
346
346
|
reject(new Error(e.stderr || e.message || "opencode invocation failed"));
|
|
347
347
|
});
|
|
348
348
|
});
|
|
@@ -547,6 +547,32 @@ var formatCommitTitle = (raw, opts) => {
|
|
|
547
547
|
import { writeFileSync, mkdirSync, existsSync } from "fs";
|
|
548
548
|
import { join } from "path";
|
|
549
549
|
import inquirer from "inquirer";
|
|
550
|
+
async function animateHeader() {
|
|
551
|
+
const text = "ai-conventional-commit";
|
|
552
|
+
if (!process.stdout.isTTY || process.env.AICC_NO_ANIMATION) {
|
|
553
|
+
console.log("\n\u250C " + chalk.bold(text));
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
const palette = [
|
|
557
|
+
"#3a0d6d",
|
|
558
|
+
"#5a1ea3",
|
|
559
|
+
"#7a32d6",
|
|
560
|
+
"#9a4dff",
|
|
561
|
+
"#b267ff",
|
|
562
|
+
"#c37dff",
|
|
563
|
+
"#b267ff",
|
|
564
|
+
"#9a4dff",
|
|
565
|
+
"#7a32d6",
|
|
566
|
+
"#5a1ea3"
|
|
567
|
+
];
|
|
568
|
+
process.stdout.write("\n");
|
|
569
|
+
for (const color of palette) {
|
|
570
|
+
const frame = chalk.bold.hex(color)(text);
|
|
571
|
+
process.stdout.write("\r\u250C " + frame);
|
|
572
|
+
await new Promise((r) => setTimeout(r, 60));
|
|
573
|
+
}
|
|
574
|
+
process.stdout.write("\n");
|
|
575
|
+
}
|
|
550
576
|
async function runGenerate(config) {
|
|
551
577
|
if (!await ensureStagedChanges()) {
|
|
552
578
|
console.log("No staged changes.");
|
|
@@ -557,10 +583,12 @@ async function runGenerate(config) {
|
|
|
557
583
|
console.log("No diff content detected after staging. Aborting.");
|
|
558
584
|
return;
|
|
559
585
|
}
|
|
560
|
-
|
|
586
|
+
await animateHeader();
|
|
561
587
|
console.log("\u2502");
|
|
562
|
-
console.log(
|
|
563
|
-
|
|
588
|
+
console.log(
|
|
589
|
+
`\u25C6 ${chalk.bold(`Detected ${files.length} staged ${files.length === 1 ? "file" : "files"}:`)}`
|
|
590
|
+
);
|
|
591
|
+
for (const f of files) console.log(" \u2022 " + f.file);
|
|
564
592
|
console.log("\u2502");
|
|
565
593
|
const spinner = ora({ text: " Starting", spinner: "dots" }).start();
|
|
566
594
|
function setPhase(label) {
|
|
@@ -610,12 +638,13 @@ async function runGenerate(config) {
|
|
|
610
638
|
})
|
|
611
639
|
}));
|
|
612
640
|
const chosen = candidates[0];
|
|
613
|
-
console.log(" " + chalk.
|
|
641
|
+
console.log(" " + chalk.white(chosen.title));
|
|
614
642
|
if (chosen.body) {
|
|
615
643
|
const indent = " ";
|
|
644
|
+
console.log(indent);
|
|
616
645
|
chosen.body.split("\n").forEach((line) => {
|
|
617
646
|
if (line.trim().length === 0) console.log(indent);
|
|
618
|
-
else console.log(indent + chalk.
|
|
647
|
+
else console.log(indent + chalk.white(line));
|
|
619
648
|
});
|
|
620
649
|
}
|
|
621
650
|
console.log("\u2502");
|
|
@@ -651,8 +680,8 @@ async function selectYesNo() {
|
|
|
651
680
|
name: "choice",
|
|
652
681
|
message: " Use this commit message?",
|
|
653
682
|
choices: [
|
|
654
|
-
{ name: "
|
|
655
|
-
{ name: "
|
|
683
|
+
{ name: "Yes", value: true },
|
|
684
|
+
{ name: "No", value: false }
|
|
656
685
|
],
|
|
657
686
|
default: 0
|
|
658
687
|
}
|
|
@@ -992,8 +1021,8 @@ var RefineCommand = class extends Command {
|
|
|
992
1021
|
}
|
|
993
1022
|
};
|
|
994
1023
|
var cli = new Cli({
|
|
995
|
-
binaryLabel: "
|
|
996
|
-
binaryName: "
|
|
1024
|
+
binaryLabel: "ai-conventional-commit",
|
|
1025
|
+
binaryName: "ai-conventional-commit",
|
|
997
1026
|
binaryVersion: "0.1.0"
|
|
998
1027
|
});
|
|
999
1028
|
cli.register(GenerateCommand);
|
package/package.json
CHANGED