@kud/ai-conventional-commit-cli 1.1.0 → 2.0.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 +8 -12
- package/dist/{chunk-YIXP5EWA.js → chunk-ECRGQKAX.js} +105 -80
- package/dist/{chunk-H4W6AMGZ.js → chunk-EHJXGWTJ.js} +89 -76
- package/dist/{chunk-F3BOAVBY.js → chunk-U7UVALKR.js} +1 -1
- package/dist/{config-C3S4LWLD.js → config-AZDENPAB.js} +1 -1
- package/dist/index.cjs +1200 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.js +8 -8
- package/dist/{reword-IN2D2J4H.js → reword-4VB7EOET.js} +3 -3
- package/dist/{reword-Q7MES34W.js → reword-BKQ7K33J.js} +3 -3
- package/package.json +2 -1
- package/dist/chunk-HJR5M6U7.js +0 -120
- package/dist/config-RHGCFLHQ.js +0 -12
- package/dist/reword-CZDYMQEV.js +0 -150
- package/dist/reword-FE5N4MGV.js +0 -150
- package/dist/reword-VRH7B6BE.js +0 -205
- package/dist/reword-WFCNTOEU.js +0 -203
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
loadConfig
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-U7UVALKR.js";
|
|
5
5
|
import {
|
|
6
6
|
OpenCodeProvider,
|
|
7
7
|
abortMessage,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
formatCommitTitle,
|
|
17
17
|
renderCommitBlock,
|
|
18
18
|
sectionTitle
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-ECRGQKAX.js";
|
|
20
20
|
|
|
21
21
|
// src/index.ts
|
|
22
22
|
import { Cli, Command, Option } from "clipanion";
|
|
@@ -873,7 +873,7 @@ var ModelsCommand = class extends Command {
|
|
|
873
873
|
});
|
|
874
874
|
async execute() {
|
|
875
875
|
if (this.current) {
|
|
876
|
-
const { loadConfigDetailed } = await import("./config-
|
|
876
|
+
const { loadConfigDetailed } = await import("./config-AZDENPAB.js");
|
|
877
877
|
const { config } = await loadConfigDetailed();
|
|
878
878
|
this.context.stdout.write(`${config.model} (source: ${config._sources.model})
|
|
879
879
|
`);
|
|
@@ -917,7 +917,7 @@ var ModelsCommand = class extends Command {
|
|
|
917
917
|
this.context.stdout.write(model + "\n");
|
|
918
918
|
if (this.save) {
|
|
919
919
|
try {
|
|
920
|
-
const { saveGlobalConfig } = await import("./config-
|
|
920
|
+
const { saveGlobalConfig } = await import("./config-AZDENPAB.js");
|
|
921
921
|
const path = saveGlobalConfig({ model });
|
|
922
922
|
this.context.stdout.write(`Saved as default model in ${path}
|
|
923
923
|
`);
|
|
@@ -952,7 +952,7 @@ var ConfigShowCommand = class extends Command {
|
|
|
952
952
|
});
|
|
953
953
|
json = Option.Boolean("--json", false, { description: "Output JSON including _sources" });
|
|
954
954
|
async execute() {
|
|
955
|
-
const { loadConfigDetailed } = await import("./config-
|
|
955
|
+
const { loadConfigDetailed } = await import("./config-AZDENPAB.js");
|
|
956
956
|
const { config, raw } = await loadConfigDetailed();
|
|
957
957
|
if (this.json) {
|
|
958
958
|
this.context.stdout.write(JSON.stringify({ config, raw }, null, 2) + "\n");
|
|
@@ -977,7 +977,7 @@ var ConfigGetCommand = class extends Command {
|
|
|
977
977
|
key = Option.String();
|
|
978
978
|
withSource = Option.Boolean("--with-source", false, { description: "Append source label" });
|
|
979
979
|
async execute() {
|
|
980
|
-
const { loadConfigDetailed } = await import("./config-
|
|
980
|
+
const { loadConfigDetailed } = await import("./config-AZDENPAB.js");
|
|
981
981
|
const { config } = await loadConfigDetailed();
|
|
982
982
|
const key = this.key;
|
|
983
983
|
if (!(key in config)) {
|
|
@@ -1026,7 +1026,7 @@ var ConfigSetCommand = class extends Command {
|
|
|
1026
1026
|
} catch {
|
|
1027
1027
|
}
|
|
1028
1028
|
}
|
|
1029
|
-
const { saveGlobalConfig } = await import("./config-
|
|
1029
|
+
const { saveGlobalConfig } = await import("./config-AZDENPAB.js");
|
|
1030
1030
|
const path = saveGlobalConfig({ [this.key]: parsed });
|
|
1031
1031
|
this.context.stdout.write(`Saved ${this.key} to ${path}
|
|
1032
1032
|
`);
|
|
@@ -1050,7 +1050,7 @@ var RewordCommand = class extends Command {
|
|
|
1050
1050
|
description: "Auto-confirm commit without prompting"
|
|
1051
1051
|
});
|
|
1052
1052
|
async execute() {
|
|
1053
|
-
const { runReword } = await import("./reword-
|
|
1053
|
+
const { runReword } = await import("./reword-4VB7EOET.js");
|
|
1054
1054
|
const config = await loadConfig();
|
|
1055
1055
|
if (this.style) config.style = this.style;
|
|
1056
1056
|
if (this.model) config.model = this.model;
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
formatCommitTitle,
|
|
11
11
|
renderCommitBlock,
|
|
12
12
|
sectionTitle
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-ECRGQKAX.js";
|
|
14
14
|
|
|
15
15
|
// src/workflow/reword.ts
|
|
16
16
|
import chalk from "chalk";
|
|
@@ -115,7 +115,7 @@ async function runReword(config, hash) {
|
|
|
115
115
|
const resolvedHash = (await git.revparse([hash])).trim();
|
|
116
116
|
const headHash = (await git.revparse(["HEAD"])).trim();
|
|
117
117
|
const isHead = headHash === resolvedHash || headHash.startsWith(resolvedHash);
|
|
118
|
-
const
|
|
118
|
+
const ok = config.yes || (await inquirer.prompt([
|
|
119
119
|
{
|
|
120
120
|
type: "list",
|
|
121
121
|
name: "ok",
|
|
@@ -126,7 +126,7 @@ async function runReword(config, hash) {
|
|
|
126
126
|
],
|
|
127
127
|
default: 0
|
|
128
128
|
}
|
|
129
|
-
]);
|
|
129
|
+
])).ok;
|
|
130
130
|
if (!ok) {
|
|
131
131
|
borderLine();
|
|
132
132
|
abortMessage();
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
formatCommitTitle,
|
|
11
11
|
renderCommitBlock,
|
|
12
12
|
sectionTitle
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-EHJXGWTJ.js";
|
|
14
14
|
|
|
15
15
|
// src/workflow/reword.ts
|
|
16
16
|
import chalk from "chalk";
|
|
@@ -115,7 +115,7 @@ async function runReword(config, hash) {
|
|
|
115
115
|
const resolvedHash = (await git.revparse([hash])).trim();
|
|
116
116
|
const headHash = (await git.revparse(["HEAD"])).trim();
|
|
117
117
|
const isHead = headHash === resolvedHash || headHash.startsWith(resolvedHash);
|
|
118
|
-
const
|
|
118
|
+
const ok = config.yes || (await inquirer.prompt([
|
|
119
119
|
{
|
|
120
120
|
type: "list",
|
|
121
121
|
name: "ok",
|
|
@@ -126,7 +126,7 @@ async function runReword(config, hash) {
|
|
|
126
126
|
],
|
|
127
127
|
default: 0
|
|
128
128
|
}
|
|
129
|
-
]);
|
|
129
|
+
])).ok;
|
|
130
130
|
if (!ok) {
|
|
131
131
|
borderLine();
|
|
132
132
|
abortMessage();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kud/ai-conventional-commit-cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Opinionated, style-aware AI assistant for crafting and splitting git commits (opencode-based, provider-agnostic).",
|
|
6
6
|
"bin": {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@commitlint/config-conventional": "^20.0.0",
|
|
26
26
|
"@inquirer/prompts": "8.0.1",
|
|
27
|
+
"@opencode-ai/sdk": "1.3.3",
|
|
27
28
|
"chalk": "^5.6.2",
|
|
28
29
|
"clipanion": "^3.2.1",
|
|
29
30
|
"cosmiconfig": "^9.0.0",
|
package/dist/chunk-HJR5M6U7.js
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
// src/config.ts
|
|
2
|
-
import { cosmiconfig } from "cosmiconfig";
|
|
3
|
-
import { resolve, dirname, join } from "path";
|
|
4
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
5
|
-
import { homedir } from "os";
|
|
6
|
-
var DEFAULTS = {
|
|
7
|
-
model: process.env.AICC_MODEL || "github-copilot/gpt-4.1",
|
|
8
|
-
privacy: process.env.AICC_PRIVACY || "low",
|
|
9
|
-
style: process.env.AICC_STYLE || "standard",
|
|
10
|
-
styleSamples: parseInt(process.env.AICC_STYLE_SAMPLES || "120", 10),
|
|
11
|
-
maxTokens: parseInt(process.env.AICC_MAX_TOKENS || "512", 10),
|
|
12
|
-
maxFileLines: parseInt(process.env.AICC_MAX_FILE_LINES || "1000", 10),
|
|
13
|
-
skipFilePatterns: [
|
|
14
|
-
"**/package-lock.json",
|
|
15
|
-
"**/yarn.lock",
|
|
16
|
-
"**/pnpm-lock.yaml",
|
|
17
|
-
"**/bun.lockb",
|
|
18
|
-
"**/composer.lock",
|
|
19
|
-
"**/Gemfile.lock",
|
|
20
|
-
"**/Cargo.lock",
|
|
21
|
-
"**/poetry.lock",
|
|
22
|
-
"**/*.d.ts",
|
|
23
|
-
"**/dist/**",
|
|
24
|
-
"**/build/**",
|
|
25
|
-
"**/.next/**",
|
|
26
|
-
"**/out/**",
|
|
27
|
-
"**/coverage/**",
|
|
28
|
-
"**/*.min.js",
|
|
29
|
-
"**/*.min.css",
|
|
30
|
-
"**/*.map"
|
|
31
|
-
],
|
|
32
|
-
cacheDir: ".git/.aicc-cache",
|
|
33
|
-
plugins: [],
|
|
34
|
-
verbose: process.env.AICC_VERBOSE === "true"
|
|
35
|
-
};
|
|
36
|
-
function getGlobalConfigPath() {
|
|
37
|
-
const base = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
38
|
-
return resolve(base, "ai-conventional-commit-cli", "aicc.json");
|
|
39
|
-
}
|
|
40
|
-
function saveGlobalConfig(partial) {
|
|
41
|
-
const filePath = getGlobalConfigPath();
|
|
42
|
-
const dir = dirname(filePath);
|
|
43
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
44
|
-
let existing = {};
|
|
45
|
-
if (existsSync(filePath)) {
|
|
46
|
-
try {
|
|
47
|
-
existing = JSON.parse(readFileSync(filePath, "utf8")) || {};
|
|
48
|
-
} catch (e) {
|
|
49
|
-
if (process.env.AICC_VERBOSE === "true") {
|
|
50
|
-
console.error("[ai-cc] Failed to parse existing global config, overwriting.");
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
const merged = { ...existing, ...partial };
|
|
55
|
-
writeFileSync(filePath, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
56
|
-
return filePath;
|
|
57
|
-
}
|
|
58
|
-
async function loadConfig(cwd = process.cwd()) {
|
|
59
|
-
return (await loadConfigDetailed(cwd)).config;
|
|
60
|
-
}
|
|
61
|
-
async function loadConfigDetailed(cwd = process.cwd()) {
|
|
62
|
-
let globalCfg = {};
|
|
63
|
-
const globalPath = getGlobalConfigPath();
|
|
64
|
-
if (existsSync(globalPath)) {
|
|
65
|
-
try {
|
|
66
|
-
globalCfg = JSON.parse(readFileSync(globalPath, "utf8")) || {};
|
|
67
|
-
} catch (e) {
|
|
68
|
-
if (process.env.AICC_VERBOSE === "true") {
|
|
69
|
-
console.error("[ai-cc] Failed to parse global config, ignoring.");
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
const explorer = cosmiconfig("aicc");
|
|
74
|
-
const result = await explorer.search(cwd);
|
|
75
|
-
const projectCfg = result?.config || {};
|
|
76
|
-
const envCfg = {};
|
|
77
|
-
if (process.env.AICC_MODEL) envCfg.model = process.env.AICC_MODEL;
|
|
78
|
-
if (process.env.AICC_PRIVACY) envCfg.privacy = process.env.AICC_PRIVACY;
|
|
79
|
-
if (process.env.AICC_STYLE) envCfg.style = process.env.AICC_STYLE;
|
|
80
|
-
if (process.env.AICC_STYLE_SAMPLES)
|
|
81
|
-
envCfg.styleSamples = parseInt(process.env.AICC_STYLE_SAMPLES, 10);
|
|
82
|
-
if (process.env.AICC_MAX_TOKENS) envCfg.maxTokens = parseInt(process.env.AICC_MAX_TOKENS, 10);
|
|
83
|
-
if (process.env.AICC_MAX_FILE_LINES)
|
|
84
|
-
envCfg.maxFileLines = parseInt(process.env.AICC_MAX_FILE_LINES, 10);
|
|
85
|
-
if (process.env.AICC_VERBOSE) envCfg.verbose = process.env.AICC_VERBOSE === "true";
|
|
86
|
-
const merged = {
|
|
87
|
-
...DEFAULTS,
|
|
88
|
-
...globalCfg,
|
|
89
|
-
...projectCfg,
|
|
90
|
-
...envCfg
|
|
91
|
-
};
|
|
92
|
-
merged.plugins = (merged.plugins || []).filter((p) => {
|
|
93
|
-
const abs = resolve(cwd, p);
|
|
94
|
-
return existsSync(abs);
|
|
95
|
-
});
|
|
96
|
-
if (!merged.skipFilePatterns) {
|
|
97
|
-
merged.skipFilePatterns = DEFAULTS.skipFilePatterns;
|
|
98
|
-
}
|
|
99
|
-
const sources = Object.keys(merged).reduce((acc, key) => {
|
|
100
|
-
const k = key;
|
|
101
|
-
let src = "default";
|
|
102
|
-
if (k in globalCfg) src = "global";
|
|
103
|
-
if (k in projectCfg) src = "project";
|
|
104
|
-
if (k in envCfg) src = "env";
|
|
105
|
-
acc[k] = src;
|
|
106
|
-
return acc;
|
|
107
|
-
}, {});
|
|
108
|
-
const withMeta = Object.assign(merged, { _sources: sources });
|
|
109
|
-
return {
|
|
110
|
-
config: withMeta,
|
|
111
|
-
raw: { defaults: DEFAULTS, global: globalCfg, project: projectCfg, env: envCfg }
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export {
|
|
116
|
-
getGlobalConfigPath,
|
|
117
|
-
saveGlobalConfig,
|
|
118
|
-
loadConfig,
|
|
119
|
-
loadConfigDetailed
|
|
120
|
-
};
|
package/dist/config-RHGCFLHQ.js
DELETED
package/dist/reword-CZDYMQEV.js
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
OpenCodeProvider,
|
|
3
|
-
animateHeaderBase,
|
|
4
|
-
borderLine,
|
|
5
|
-
buildRefineMessages,
|
|
6
|
-
extractJSON,
|
|
7
|
-
formatCommitTitle,
|
|
8
|
-
renderCommitBlock,
|
|
9
|
-
sectionTitle
|
|
10
|
-
} from "./chunk-YIXP5EWA.js";
|
|
11
|
-
|
|
12
|
-
// src/workflow/reword.ts
|
|
13
|
-
import chalk from "chalk";
|
|
14
|
-
import ora from "ora";
|
|
15
|
-
import inquirer from "inquirer";
|
|
16
|
-
import { simpleGit } from "simple-git";
|
|
17
|
-
var git = simpleGit();
|
|
18
|
-
async function getCommitMessage(hash) {
|
|
19
|
-
try {
|
|
20
|
-
const raw = await git.show([`${hash}`, "--quiet", "--format=%P%n%B"]);
|
|
21
|
-
const lines = raw.split("\n");
|
|
22
|
-
const parentsLine = lines.shift() || "";
|
|
23
|
-
const parents = parentsLine.trim().length ? parentsLine.trim().split(/\s+/) : [];
|
|
24
|
-
const message = lines.join("\n").trim();
|
|
25
|
-
if (!message) return null;
|
|
26
|
-
const [first, ...rest] = message.split("\n");
|
|
27
|
-
const body = rest.join("\n").trim() || void 0;
|
|
28
|
-
return { title: first, body, parents };
|
|
29
|
-
} catch {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
async function runReword(config, hash) {
|
|
34
|
-
const startedAt = Date.now();
|
|
35
|
-
const commit = await getCommitMessage(hash);
|
|
36
|
-
if (!commit) {
|
|
37
|
-
console.log(`Commit not found: ${hash}`);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
if (commit.parents.length > 1) {
|
|
41
|
-
console.log("Refusing to reword a merge commit (multiple parents).");
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
if (process.stdout.isTTY) {
|
|
45
|
-
await animateHeaderBase("ai-conventional-commit", config.model);
|
|
46
|
-
borderLine();
|
|
47
|
-
}
|
|
48
|
-
sectionTitle("Original commit");
|
|
49
|
-
borderLine(chalk.yellow(commit.title));
|
|
50
|
-
if (commit.body) {
|
|
51
|
-
commit.body.split("\n").forEach((l) => l.trim().length ? borderLine(l) : borderLine());
|
|
52
|
-
}
|
|
53
|
-
borderLine();
|
|
54
|
-
const instructions = [
|
|
55
|
-
"Improve clarity & conformity to Conventional Commits while preserving meaning."
|
|
56
|
-
];
|
|
57
|
-
const syntheticPlan = {
|
|
58
|
-
commits: [
|
|
59
|
-
{
|
|
60
|
-
title: commit.title,
|
|
61
|
-
body: commit.body,
|
|
62
|
-
score: 0,
|
|
63
|
-
reasons: []
|
|
64
|
-
}
|
|
65
|
-
]
|
|
66
|
-
};
|
|
67
|
-
const provider = new OpenCodeProvider(config.model);
|
|
68
|
-
const spinner = ora({ text: "Calling model", spinner: "dots" }).start();
|
|
69
|
-
let refined = null;
|
|
70
|
-
try {
|
|
71
|
-
const messages = buildRefineMessages({
|
|
72
|
-
originalPlan: syntheticPlan,
|
|
73
|
-
index: 0,
|
|
74
|
-
instructions,
|
|
75
|
-
config
|
|
76
|
-
});
|
|
77
|
-
const raw = await provider.chat(messages, { maxTokens: config.maxTokens });
|
|
78
|
-
refined = await extractJSON(raw);
|
|
79
|
-
} catch (e) {
|
|
80
|
-
spinner.fail("Model call failed: " + (e?.message || e));
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
spinner.stop();
|
|
84
|
-
if (!refined || !refined.commits.length) {
|
|
85
|
-
console.log("No refined commit produced.");
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
const candidate = refined.commits[0];
|
|
89
|
-
candidate.title = formatCommitTitle(candidate.title, {
|
|
90
|
-
allowGitmoji: config.style === "gitmoji" || config.style === "gitmoji-pure",
|
|
91
|
-
mode: config.style
|
|
92
|
-
});
|
|
93
|
-
sectionTitle("Proposed commit");
|
|
94
|
-
renderCommitBlock({
|
|
95
|
-
title: chalk.yellow(candidate.title),
|
|
96
|
-
body: candidate.body,
|
|
97
|
-
hideMessageLabel: true
|
|
98
|
-
});
|
|
99
|
-
borderLine();
|
|
100
|
-
const isHead = (await git.revparse(["HEAD"])).startsWith(hash) || await git.revparse([hash]) === await git.revparse(["HEAD"]);
|
|
101
|
-
const { ok } = await inquirer.prompt([
|
|
102
|
-
{
|
|
103
|
-
type: "list",
|
|
104
|
-
name: "ok",
|
|
105
|
-
message: isHead ? "Amend HEAD with this message?" : "Use this new message (show rebase instructions)?",
|
|
106
|
-
choices: [
|
|
107
|
-
{ name: "Yes", value: true },
|
|
108
|
-
{ name: "No", value: false }
|
|
109
|
-
],
|
|
110
|
-
default: 0
|
|
111
|
-
}
|
|
112
|
-
]);
|
|
113
|
-
if (!ok) {
|
|
114
|
-
borderLine("Aborted.");
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
if (isHead) {
|
|
118
|
-
const full = candidate.body ? `${candidate.title}
|
|
119
|
-
|
|
120
|
-
${candidate.body}` : candidate.title;
|
|
121
|
-
try {
|
|
122
|
-
await git.commit(full, { "--amend": null });
|
|
123
|
-
borderLine("Amended HEAD.");
|
|
124
|
-
} catch (e) {
|
|
125
|
-
borderLine("Failed to amend: " + (e?.message || e));
|
|
126
|
-
}
|
|
127
|
-
} else {
|
|
128
|
-
const full = candidate.body ? `${candidate.title}
|
|
129
|
-
|
|
130
|
-
${candidate.body}` : candidate.title;
|
|
131
|
-
sectionTitle("Apply manually");
|
|
132
|
-
borderLine("Interactive rebase steps:");
|
|
133
|
-
borderLine(`1. git rebase -i ${hash}~1 --reword`);
|
|
134
|
-
borderLine(
|
|
135
|
-
"2. In the editor, ensure the line for the commit is kept as reword (or change pick \u2192 reword)."
|
|
136
|
-
);
|
|
137
|
-
borderLine("3. When prompted, replace the message with below:");
|
|
138
|
-
borderLine();
|
|
139
|
-
borderLine(candidate.title);
|
|
140
|
-
if (candidate.body) {
|
|
141
|
-
candidate.body.split("\n").forEach((l) => l.trim().length ? borderLine(l) : borderLine());
|
|
142
|
-
}
|
|
143
|
-
borderLine();
|
|
144
|
-
}
|
|
145
|
-
const elapsed = ((Date.now() - startedAt) / 1e3).toFixed(1) + "s";
|
|
146
|
-
borderLine(`Done in ${elapsed}.`);
|
|
147
|
-
}
|
|
148
|
-
export {
|
|
149
|
-
runReword
|
|
150
|
-
};
|
package/dist/reword-FE5N4MGV.js
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
OpenCodeProvider,
|
|
3
|
-
animateHeaderBase,
|
|
4
|
-
borderLine,
|
|
5
|
-
buildRefineMessages,
|
|
6
|
-
extractJSON,
|
|
7
|
-
formatCommitTitle,
|
|
8
|
-
renderCommitBlock,
|
|
9
|
-
sectionTitle
|
|
10
|
-
} from "./chunk-H4W6AMGZ.js";
|
|
11
|
-
|
|
12
|
-
// src/workflow/reword.ts
|
|
13
|
-
import chalk from "chalk";
|
|
14
|
-
import ora from "ora";
|
|
15
|
-
import inquirer from "inquirer";
|
|
16
|
-
import { simpleGit } from "simple-git";
|
|
17
|
-
var git = simpleGit();
|
|
18
|
-
async function getCommitMessage(hash) {
|
|
19
|
-
try {
|
|
20
|
-
const raw = await git.show([`${hash}`, "--quiet", "--format=%P%n%B"]);
|
|
21
|
-
const lines = raw.split("\n");
|
|
22
|
-
const parentsLine = lines.shift() || "";
|
|
23
|
-
const parents = parentsLine.trim().length ? parentsLine.trim().split(/\s+/) : [];
|
|
24
|
-
const message = lines.join("\n").trim();
|
|
25
|
-
if (!message) return null;
|
|
26
|
-
const [first, ...rest] = message.split("\n");
|
|
27
|
-
const body = rest.join("\n").trim() || void 0;
|
|
28
|
-
return { title: first, body, parents };
|
|
29
|
-
} catch {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
async function runReword(config, hash) {
|
|
34
|
-
const startedAt = Date.now();
|
|
35
|
-
const commit = await getCommitMessage(hash);
|
|
36
|
-
if (!commit) {
|
|
37
|
-
console.log(`Commit not found: ${hash}`);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
if (commit.parents.length > 1) {
|
|
41
|
-
console.log("Refusing to reword a merge commit (multiple parents).");
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
if (process.stdout.isTTY) {
|
|
45
|
-
await animateHeaderBase("ai-conventional-commit", config.model);
|
|
46
|
-
borderLine();
|
|
47
|
-
}
|
|
48
|
-
sectionTitle("Original commit");
|
|
49
|
-
borderLine(chalk.yellow(commit.title));
|
|
50
|
-
if (commit.body) {
|
|
51
|
-
commit.body.split("\n").forEach((l) => l.trim().length ? borderLine(l) : borderLine());
|
|
52
|
-
}
|
|
53
|
-
borderLine();
|
|
54
|
-
const instructions = [
|
|
55
|
-
"Improve clarity & conformity to Conventional Commits while preserving meaning."
|
|
56
|
-
];
|
|
57
|
-
const syntheticPlan = {
|
|
58
|
-
commits: [
|
|
59
|
-
{
|
|
60
|
-
title: commit.title,
|
|
61
|
-
body: commit.body,
|
|
62
|
-
score: 0,
|
|
63
|
-
reasons: []
|
|
64
|
-
}
|
|
65
|
-
]
|
|
66
|
-
};
|
|
67
|
-
const provider = new OpenCodeProvider(config.model);
|
|
68
|
-
const spinner = ora({ text: "Calling model", spinner: "dots" }).start();
|
|
69
|
-
let refined = null;
|
|
70
|
-
try {
|
|
71
|
-
const messages = buildRefineMessages({
|
|
72
|
-
originalPlan: syntheticPlan,
|
|
73
|
-
index: 0,
|
|
74
|
-
instructions,
|
|
75
|
-
config
|
|
76
|
-
});
|
|
77
|
-
const raw = await provider.chat(messages, { maxTokens: config.maxTokens });
|
|
78
|
-
refined = await extractJSON(raw);
|
|
79
|
-
} catch (e) {
|
|
80
|
-
spinner.fail("Model call failed: " + (e?.message || e));
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
spinner.stop();
|
|
84
|
-
if (!refined || !refined.commits.length) {
|
|
85
|
-
console.log("No refined commit produced.");
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
const candidate = refined.commits[0];
|
|
89
|
-
candidate.title = formatCommitTitle(candidate.title, {
|
|
90
|
-
allowGitmoji: config.style === "gitmoji" || config.style === "gitmoji-pure",
|
|
91
|
-
mode: config.style
|
|
92
|
-
});
|
|
93
|
-
sectionTitle("Proposed commit");
|
|
94
|
-
renderCommitBlock({
|
|
95
|
-
title: chalk.yellow(candidate.title),
|
|
96
|
-
body: candidate.body,
|
|
97
|
-
hideMessageLabel: true
|
|
98
|
-
});
|
|
99
|
-
borderLine();
|
|
100
|
-
const isHead = (await git.revparse(["HEAD"])).startsWith(hash) || await git.revparse([hash]) === await git.revparse(["HEAD"]);
|
|
101
|
-
const { ok } = await inquirer.prompt([
|
|
102
|
-
{
|
|
103
|
-
type: "list",
|
|
104
|
-
name: "ok",
|
|
105
|
-
message: isHead ? "Amend HEAD with this message?" : "Use this new message (show rebase instructions)?",
|
|
106
|
-
choices: [
|
|
107
|
-
{ name: "Yes", value: true },
|
|
108
|
-
{ name: "No", value: false }
|
|
109
|
-
],
|
|
110
|
-
default: 0
|
|
111
|
-
}
|
|
112
|
-
]);
|
|
113
|
-
if (!ok) {
|
|
114
|
-
borderLine("Aborted.");
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
if (isHead) {
|
|
118
|
-
const full = candidate.body ? `${candidate.title}
|
|
119
|
-
|
|
120
|
-
${candidate.body}` : candidate.title;
|
|
121
|
-
try {
|
|
122
|
-
await git.commit(full, { "--amend": null });
|
|
123
|
-
borderLine("Amended HEAD.");
|
|
124
|
-
} catch (e) {
|
|
125
|
-
borderLine("Failed to amend: " + (e?.message || e));
|
|
126
|
-
}
|
|
127
|
-
} else {
|
|
128
|
-
const full = candidate.body ? `${candidate.title}
|
|
129
|
-
|
|
130
|
-
${candidate.body}` : candidate.title;
|
|
131
|
-
sectionTitle("Apply manually");
|
|
132
|
-
borderLine("Interactive rebase steps:");
|
|
133
|
-
borderLine(`1. git rebase -i ${hash}~1 --reword`);
|
|
134
|
-
borderLine(
|
|
135
|
-
"2. In the editor, ensure the line for the commit is kept as reword (or change pick \u2192 reword)."
|
|
136
|
-
);
|
|
137
|
-
borderLine("3. When prompted, replace the message with below:");
|
|
138
|
-
borderLine();
|
|
139
|
-
borderLine(candidate.title);
|
|
140
|
-
if (candidate.body) {
|
|
141
|
-
candidate.body.split("\n").forEach((l) => l.trim().length ? borderLine(l) : borderLine());
|
|
142
|
-
}
|
|
143
|
-
borderLine();
|
|
144
|
-
}
|
|
145
|
-
const elapsed = ((Date.now() - startedAt) / 1e3).toFixed(1) + "s";
|
|
146
|
-
borderLine(`Done in ${elapsed}.`);
|
|
147
|
-
}
|
|
148
|
-
export {
|
|
149
|
-
runReword
|
|
150
|
-
};
|