@kud/ai-conventional-commit-cli 3.0.3 → 3.1.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/dist/chunk-6WHDHBGN.js +128 -0
- package/dist/chunk-W7OC77AV.js +649 -0
- package/dist/chunk-YRVQGOVW.js +649 -0
- package/dist/config-JEYG4CTJ.js +12 -0
- package/dist/index.js +8 -8
- package/dist/reword-2ASH5EH5.js +212 -0
- package/dist/reword-PEOUOAT7.js +212 -0
- package/package.json +1 -1
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-6WHDHBGN.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-YRVQGOVW.js";
|
|
20
20
|
|
|
21
21
|
// src/index.ts
|
|
22
22
|
import { Cli, Command, Option } from "clipanion";
|
|
@@ -866,7 +866,7 @@ var ModelsCommand = class extends Command {
|
|
|
866
866
|
});
|
|
867
867
|
async execute() {
|
|
868
868
|
if (this.current) {
|
|
869
|
-
const { loadConfigDetailed } = await import("./config-
|
|
869
|
+
const { loadConfigDetailed } = await import("./config-JEYG4CTJ.js");
|
|
870
870
|
const { config } = await loadConfigDetailed();
|
|
871
871
|
this.context.stdout.write(`${config.model} (source: ${config._sources.model})
|
|
872
872
|
`);
|
|
@@ -906,7 +906,7 @@ var ModelsCommand = class extends Command {
|
|
|
906
906
|
this.context.stdout.write(model + "\n");
|
|
907
907
|
if (this.save) {
|
|
908
908
|
try {
|
|
909
|
-
const { saveGlobalConfig } = await import("./config-
|
|
909
|
+
const { saveGlobalConfig } = await import("./config-JEYG4CTJ.js");
|
|
910
910
|
const path = saveGlobalConfig({ model });
|
|
911
911
|
this.context.stdout.write(`Saved as default model in ${path}
|
|
912
912
|
`);
|
|
@@ -941,7 +941,7 @@ var ConfigShowCommand = class extends Command {
|
|
|
941
941
|
});
|
|
942
942
|
json = Option.Boolean("--json", false, { description: "Output JSON including _sources" });
|
|
943
943
|
async execute() {
|
|
944
|
-
const { loadConfigDetailed } = await import("./config-
|
|
944
|
+
const { loadConfigDetailed } = await import("./config-JEYG4CTJ.js");
|
|
945
945
|
const { config, raw } = await loadConfigDetailed();
|
|
946
946
|
if (this.json) {
|
|
947
947
|
this.context.stdout.write(JSON.stringify({ config, raw }, null, 2) + "\n");
|
|
@@ -966,7 +966,7 @@ var ConfigGetCommand = class extends Command {
|
|
|
966
966
|
key = Option.String();
|
|
967
967
|
withSource = Option.Boolean("--with-source", false, { description: "Append source label" });
|
|
968
968
|
async execute() {
|
|
969
|
-
const { loadConfigDetailed } = await import("./config-
|
|
969
|
+
const { loadConfigDetailed } = await import("./config-JEYG4CTJ.js");
|
|
970
970
|
const { config } = await loadConfigDetailed();
|
|
971
971
|
const key = this.key;
|
|
972
972
|
if (!(key in config)) {
|
|
@@ -1023,7 +1023,7 @@ var ConfigSetCommand = class extends Command {
|
|
|
1023
1023
|
} catch {
|
|
1024
1024
|
}
|
|
1025
1025
|
}
|
|
1026
|
-
const { saveGlobalConfig } = await import("./config-
|
|
1026
|
+
const { saveGlobalConfig } = await import("./config-JEYG4CTJ.js");
|
|
1027
1027
|
const path = saveGlobalConfig({ [this.key]: parsed });
|
|
1028
1028
|
this.context.stdout.write(`Saved ${this.key} to ${path}
|
|
1029
1029
|
`);
|
|
@@ -1047,7 +1047,7 @@ var RewordCommand = class extends Command {
|
|
|
1047
1047
|
description: "Auto-confirm commit without prompting"
|
|
1048
1048
|
});
|
|
1049
1049
|
async execute() {
|
|
1050
|
-
const { runReword } = await import("./reword-
|
|
1050
|
+
const { runReword } = await import("./reword-2ASH5EH5.js");
|
|
1051
1051
|
const config = await loadConfig();
|
|
1052
1052
|
if (this.style) config.style = this.style;
|
|
1053
1053
|
if (this.model) config.model = this.model;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OpenCodeProvider,
|
|
3
|
+
abortMessage,
|
|
4
|
+
animateHeaderBase,
|
|
5
|
+
borderLine,
|
|
6
|
+
buildRefineMessages,
|
|
7
|
+
createPhasedSpinner,
|
|
8
|
+
extractJSON,
|
|
9
|
+
finalSuccess,
|
|
10
|
+
formatCommitTitle,
|
|
11
|
+
renderCommitBlock,
|
|
12
|
+
sectionTitle
|
|
13
|
+
} from "./chunk-YRVQGOVW.js";
|
|
14
|
+
|
|
15
|
+
// src/workflow/reword.ts
|
|
16
|
+
import chalk from "chalk";
|
|
17
|
+
import ora from "ora";
|
|
18
|
+
import inquirer from "inquirer";
|
|
19
|
+
import { simpleGit } from "simple-git";
|
|
20
|
+
var git = simpleGit();
|
|
21
|
+
async function getCommitMessage(hash) {
|
|
22
|
+
try {
|
|
23
|
+
const raw = await git.show([`${hash}`, "--quiet", "--format=%P%n%B"]);
|
|
24
|
+
const lines = raw.split("\n");
|
|
25
|
+
const parentsLine = lines.shift() || "";
|
|
26
|
+
const parents = parentsLine.trim().length ? parentsLine.trim().split(/\s+/) : [];
|
|
27
|
+
const message = lines.join("\n").trim();
|
|
28
|
+
if (!message) return null;
|
|
29
|
+
const [first, ...rest] = message.split("\n");
|
|
30
|
+
const body = rest.join("\n").trim() || void 0;
|
|
31
|
+
return { title: first, body, parents };
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function isAncestor(ancestor, head) {
|
|
37
|
+
try {
|
|
38
|
+
const mb = (await git.raw(["merge-base", ancestor, head])).trim();
|
|
39
|
+
const anc = (await git.revparse([ancestor])).trim();
|
|
40
|
+
return mb === anc;
|
|
41
|
+
} catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function runReword(config, hash) {
|
|
46
|
+
const startedAt = Date.now();
|
|
47
|
+
const commit = await getCommitMessage(hash);
|
|
48
|
+
if (!commit) {
|
|
49
|
+
console.log(`Commit not found: ${hash}`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (commit.parents.length > 1) {
|
|
53
|
+
console.log("Refusing to reword a merge commit (multiple parents).");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (process.stdout.isTTY) {
|
|
57
|
+
await animateHeaderBase("ai-conventional-commit", config.model);
|
|
58
|
+
borderLine();
|
|
59
|
+
}
|
|
60
|
+
sectionTitle("Original commit");
|
|
61
|
+
borderLine(chalk.yellow(commit.title));
|
|
62
|
+
if (commit.body) {
|
|
63
|
+
commit.body.split("\n").forEach((l) => l.trim().length ? borderLine(l) : borderLine());
|
|
64
|
+
}
|
|
65
|
+
borderLine();
|
|
66
|
+
const instructions = [
|
|
67
|
+
"Improve clarity & conformity to Conventional Commits while preserving meaning."
|
|
68
|
+
];
|
|
69
|
+
const syntheticPlan = {
|
|
70
|
+
commits: [
|
|
71
|
+
{
|
|
72
|
+
title: commit.title,
|
|
73
|
+
body: commit.body,
|
|
74
|
+
score: 0,
|
|
75
|
+
reasons: []
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
};
|
|
79
|
+
const provider = new OpenCodeProvider(config.model);
|
|
80
|
+
const phased = createPhasedSpinner(ora);
|
|
81
|
+
let refined = null;
|
|
82
|
+
try {
|
|
83
|
+
phased.phase("Preparing prompt");
|
|
84
|
+
const messages = buildRefineMessages({
|
|
85
|
+
originalPlan: syntheticPlan,
|
|
86
|
+
index: 0,
|
|
87
|
+
instructions,
|
|
88
|
+
config
|
|
89
|
+
});
|
|
90
|
+
phased.phase("Calling model");
|
|
91
|
+
const raw = await provider.chat(messages, { maxTokens: config.maxTokens });
|
|
92
|
+
phased.phase("Parsing response");
|
|
93
|
+
refined = await extractJSON(raw);
|
|
94
|
+
} catch (e) {
|
|
95
|
+
phased.spinner.fail("Reword failed: " + (e?.message || e));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
phased.stop();
|
|
99
|
+
if (!refined || !refined.commits.length) {
|
|
100
|
+
console.log("No refined commit produced.");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const candidate = refined.commits[0];
|
|
104
|
+
candidate.title = formatCommitTitle(candidate.title, {
|
|
105
|
+
allowGitmoji: config.style === "gitmoji" || config.style === "gitmoji-pure",
|
|
106
|
+
mode: config.style
|
|
107
|
+
});
|
|
108
|
+
sectionTitle("Proposed commit");
|
|
109
|
+
renderCommitBlock({
|
|
110
|
+
title: chalk.yellow(candidate.title),
|
|
111
|
+
body: candidate.body,
|
|
112
|
+
hideMessageLabel: true
|
|
113
|
+
});
|
|
114
|
+
borderLine();
|
|
115
|
+
const resolvedHash = (await git.revparse([hash])).trim();
|
|
116
|
+
const headHash = (await git.revparse(["HEAD"])).trim();
|
|
117
|
+
const isHead = headHash === resolvedHash || headHash.startsWith(resolvedHash);
|
|
118
|
+
const ok = config.yes || (await inquirer.prompt([
|
|
119
|
+
{
|
|
120
|
+
type: "list",
|
|
121
|
+
name: "ok",
|
|
122
|
+
message: isHead ? "Amend HEAD with this message?" : "Apply rewrite (history will change)?",
|
|
123
|
+
choices: [
|
|
124
|
+
{ name: "Yes", value: true },
|
|
125
|
+
{ name: "No", value: false }
|
|
126
|
+
],
|
|
127
|
+
default: 0
|
|
128
|
+
}
|
|
129
|
+
])).ok;
|
|
130
|
+
if (!ok) {
|
|
131
|
+
borderLine();
|
|
132
|
+
abortMessage();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const full = candidate.body ? `${candidate.title}
|
|
136
|
+
|
|
137
|
+
${candidate.body}` : candidate.title;
|
|
138
|
+
if (isHead) {
|
|
139
|
+
try {
|
|
140
|
+
await git.commit(full, { "--amend": null });
|
|
141
|
+
} catch (e) {
|
|
142
|
+
borderLine("Failed to amend HEAD: " + (e?.message || e));
|
|
143
|
+
borderLine();
|
|
144
|
+
abortMessage();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
borderLine();
|
|
148
|
+
finalSuccess({ count: 1, startedAt });
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const ancestorOk = await isAncestor(resolvedHash, headHash);
|
|
152
|
+
if (!ancestorOk) {
|
|
153
|
+
borderLine("Selected commit is not an ancestor of HEAD.");
|
|
154
|
+
borderLine("Cannot safely rewrite automatically.");
|
|
155
|
+
borderLine();
|
|
156
|
+
abortMessage();
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
let mergesRange = "";
|
|
160
|
+
try {
|
|
161
|
+
mergesRange = (await git.raw(["rev-list", "--merges", `${resolvedHash}..HEAD`])).trim();
|
|
162
|
+
} catch {
|
|
163
|
+
}
|
|
164
|
+
if (mergesRange) {
|
|
165
|
+
sectionTitle("Unsafe automatic rewrite");
|
|
166
|
+
borderLine("Merge commits detected between target and HEAD.");
|
|
167
|
+
borderLine("Falling back to manual instructions (preserving previous behavior).");
|
|
168
|
+
borderLine();
|
|
169
|
+
sectionTitle("Apply manually");
|
|
170
|
+
borderLine(`1. git rebase -i ${resolvedHash}~1 --reword`);
|
|
171
|
+
borderLine("2. Mark the line as reword if needed.");
|
|
172
|
+
borderLine("3. Replace the message with:");
|
|
173
|
+
borderLine();
|
|
174
|
+
borderLine(candidate.title);
|
|
175
|
+
if (candidate.body) candidate.body.split("\n").forEach((l) => borderLine(l || void 0));
|
|
176
|
+
borderLine();
|
|
177
|
+
abortMessage();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
const tree = (await git.raw(["show", "-s", "--format=%T", resolvedHash])).trim();
|
|
182
|
+
const parent = commit.parents[0];
|
|
183
|
+
const args = ["commit-tree", tree];
|
|
184
|
+
if (parent) args.push("-p", parent);
|
|
185
|
+
args.push("-m", full);
|
|
186
|
+
const newHash = (await git.raw(args)).trim();
|
|
187
|
+
const currentBranch = (await git.revparse(["--abbrev-ref", "HEAD"])).trim();
|
|
188
|
+
const rebaseTarget = currentBranch === "HEAD" ? "HEAD" : currentBranch;
|
|
189
|
+
await git.raw(["rebase", "--onto", newHash, resolvedHash, rebaseTarget]);
|
|
190
|
+
const afterBranch = (await git.revparse(["--abbrev-ref", "HEAD"])).trim();
|
|
191
|
+
if (afterBranch === "HEAD" && rebaseTarget !== "HEAD") {
|
|
192
|
+
try {
|
|
193
|
+
await git.checkout([rebaseTarget]);
|
|
194
|
+
} catch {
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
sectionTitle("Updated commit");
|
|
198
|
+
borderLine(`Rewrote ${resolvedHash.slice(0, 7)} \u2192 ${newHash.slice(0, 7)}`);
|
|
199
|
+
renderCommitBlock({ title: candidate.title, body: candidate.body, hideMessageLabel: true });
|
|
200
|
+
borderLine();
|
|
201
|
+
finalSuccess({ count: 1, startedAt });
|
|
202
|
+
} catch (e) {
|
|
203
|
+
borderLine("Automatic rewrite failed: " + (e?.message || e));
|
|
204
|
+
borderLine("If a rebase is in progress, resolve conflicts then run: git rebase --continue");
|
|
205
|
+
borderLine("Or abort with: git rebase --abort");
|
|
206
|
+
borderLine();
|
|
207
|
+
abortMessage();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
export {
|
|
211
|
+
runReword
|
|
212
|
+
};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OpenCodeProvider,
|
|
3
|
+
abortMessage,
|
|
4
|
+
animateHeaderBase,
|
|
5
|
+
borderLine,
|
|
6
|
+
buildRefineMessages,
|
|
7
|
+
createPhasedSpinner,
|
|
8
|
+
extractJSON,
|
|
9
|
+
finalSuccess,
|
|
10
|
+
formatCommitTitle,
|
|
11
|
+
renderCommitBlock,
|
|
12
|
+
sectionTitle
|
|
13
|
+
} from "./chunk-W7OC77AV.js";
|
|
14
|
+
|
|
15
|
+
// src/workflow/reword.ts
|
|
16
|
+
import chalk from "chalk";
|
|
17
|
+
import ora from "ora";
|
|
18
|
+
import inquirer from "inquirer";
|
|
19
|
+
import { simpleGit } from "simple-git";
|
|
20
|
+
var git = simpleGit();
|
|
21
|
+
async function getCommitMessage(hash) {
|
|
22
|
+
try {
|
|
23
|
+
const raw = await git.show([`${hash}`, "--quiet", "--format=%P%n%B"]);
|
|
24
|
+
const lines = raw.split("\n");
|
|
25
|
+
const parentsLine = lines.shift() || "";
|
|
26
|
+
const parents = parentsLine.trim().length ? parentsLine.trim().split(/\s+/) : [];
|
|
27
|
+
const message = lines.join("\n").trim();
|
|
28
|
+
if (!message) return null;
|
|
29
|
+
const [first, ...rest] = message.split("\n");
|
|
30
|
+
const body = rest.join("\n").trim() || void 0;
|
|
31
|
+
return { title: first, body, parents };
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function isAncestor(ancestor, head) {
|
|
37
|
+
try {
|
|
38
|
+
const mb = (await git.raw(["merge-base", ancestor, head])).trim();
|
|
39
|
+
const anc = (await git.revparse([ancestor])).trim();
|
|
40
|
+
return mb === anc;
|
|
41
|
+
} catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function runReword(config, hash) {
|
|
46
|
+
const startedAt = Date.now();
|
|
47
|
+
const commit = await getCommitMessage(hash);
|
|
48
|
+
if (!commit) {
|
|
49
|
+
console.log(`Commit not found: ${hash}`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (commit.parents.length > 1) {
|
|
53
|
+
console.log("Refusing to reword a merge commit (multiple parents).");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (process.stdout.isTTY) {
|
|
57
|
+
await animateHeaderBase("ai-conventional-commit", config.model);
|
|
58
|
+
borderLine();
|
|
59
|
+
}
|
|
60
|
+
sectionTitle("Original commit");
|
|
61
|
+
borderLine(chalk.yellow(commit.title));
|
|
62
|
+
if (commit.body) {
|
|
63
|
+
commit.body.split("\n").forEach((l) => l.trim().length ? borderLine(l) : borderLine());
|
|
64
|
+
}
|
|
65
|
+
borderLine();
|
|
66
|
+
const instructions = [
|
|
67
|
+
"Improve clarity & conformity to Conventional Commits while preserving meaning."
|
|
68
|
+
];
|
|
69
|
+
const syntheticPlan = {
|
|
70
|
+
commits: [
|
|
71
|
+
{
|
|
72
|
+
title: commit.title,
|
|
73
|
+
body: commit.body,
|
|
74
|
+
score: 0,
|
|
75
|
+
reasons: []
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
};
|
|
79
|
+
const provider = new OpenCodeProvider(config.model);
|
|
80
|
+
const phased = createPhasedSpinner(ora);
|
|
81
|
+
let refined = null;
|
|
82
|
+
try {
|
|
83
|
+
phased.phase("Preparing prompt");
|
|
84
|
+
const messages = buildRefineMessages({
|
|
85
|
+
originalPlan: syntheticPlan,
|
|
86
|
+
index: 0,
|
|
87
|
+
instructions,
|
|
88
|
+
config
|
|
89
|
+
});
|
|
90
|
+
phased.phase("Calling model");
|
|
91
|
+
const raw = await provider.chat(messages, { maxTokens: config.maxTokens });
|
|
92
|
+
phased.phase("Parsing response");
|
|
93
|
+
refined = await extractJSON(raw);
|
|
94
|
+
} catch (e) {
|
|
95
|
+
phased.spinner.fail("Reword failed: " + (e?.message || e));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
phased.stop();
|
|
99
|
+
if (!refined || !refined.commits.length) {
|
|
100
|
+
console.log("No refined commit produced.");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const candidate = refined.commits[0];
|
|
104
|
+
candidate.title = formatCommitTitle(candidate.title, {
|
|
105
|
+
allowGitmoji: config.style === "gitmoji" || config.style === "gitmoji-pure",
|
|
106
|
+
mode: config.style
|
|
107
|
+
});
|
|
108
|
+
sectionTitle("Proposed commit");
|
|
109
|
+
renderCommitBlock({
|
|
110
|
+
title: chalk.yellow(candidate.title),
|
|
111
|
+
body: candidate.body,
|
|
112
|
+
hideMessageLabel: true
|
|
113
|
+
});
|
|
114
|
+
borderLine();
|
|
115
|
+
const resolvedHash = (await git.revparse([hash])).trim();
|
|
116
|
+
const headHash = (await git.revparse(["HEAD"])).trim();
|
|
117
|
+
const isHead = headHash === resolvedHash || headHash.startsWith(resolvedHash);
|
|
118
|
+
const ok = config.yes || (await inquirer.prompt([
|
|
119
|
+
{
|
|
120
|
+
type: "list",
|
|
121
|
+
name: "ok",
|
|
122
|
+
message: isHead ? "Amend HEAD with this message?" : "Apply rewrite (history will change)?",
|
|
123
|
+
choices: [
|
|
124
|
+
{ name: "Yes", value: true },
|
|
125
|
+
{ name: "No", value: false }
|
|
126
|
+
],
|
|
127
|
+
default: 0
|
|
128
|
+
}
|
|
129
|
+
])).ok;
|
|
130
|
+
if (!ok) {
|
|
131
|
+
borderLine();
|
|
132
|
+
abortMessage();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const full = candidate.body ? `${candidate.title}
|
|
136
|
+
|
|
137
|
+
${candidate.body}` : candidate.title;
|
|
138
|
+
if (isHead) {
|
|
139
|
+
try {
|
|
140
|
+
await git.commit(full, { "--amend": null });
|
|
141
|
+
} catch (e) {
|
|
142
|
+
borderLine("Failed to amend HEAD: " + (e?.message || e));
|
|
143
|
+
borderLine();
|
|
144
|
+
abortMessage();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
borderLine();
|
|
148
|
+
finalSuccess({ count: 1, startedAt });
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const ancestorOk = await isAncestor(resolvedHash, headHash);
|
|
152
|
+
if (!ancestorOk) {
|
|
153
|
+
borderLine("Selected commit is not an ancestor of HEAD.");
|
|
154
|
+
borderLine("Cannot safely rewrite automatically.");
|
|
155
|
+
borderLine();
|
|
156
|
+
abortMessage();
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
let mergesRange = "";
|
|
160
|
+
try {
|
|
161
|
+
mergesRange = (await git.raw(["rev-list", "--merges", `${resolvedHash}..HEAD`])).trim();
|
|
162
|
+
} catch {
|
|
163
|
+
}
|
|
164
|
+
if (mergesRange) {
|
|
165
|
+
sectionTitle("Unsafe automatic rewrite");
|
|
166
|
+
borderLine("Merge commits detected between target and HEAD.");
|
|
167
|
+
borderLine("Falling back to manual instructions (preserving previous behavior).");
|
|
168
|
+
borderLine();
|
|
169
|
+
sectionTitle("Apply manually");
|
|
170
|
+
borderLine(`1. git rebase -i ${resolvedHash}~1 --reword`);
|
|
171
|
+
borderLine("2. Mark the line as reword if needed.");
|
|
172
|
+
borderLine("3. Replace the message with:");
|
|
173
|
+
borderLine();
|
|
174
|
+
borderLine(candidate.title);
|
|
175
|
+
if (candidate.body) candidate.body.split("\n").forEach((l) => borderLine(l || void 0));
|
|
176
|
+
borderLine();
|
|
177
|
+
abortMessage();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
const tree = (await git.raw(["show", "-s", "--format=%T", resolvedHash])).trim();
|
|
182
|
+
const parent = commit.parents[0];
|
|
183
|
+
const args = ["commit-tree", tree];
|
|
184
|
+
if (parent) args.push("-p", parent);
|
|
185
|
+
args.push("-m", full);
|
|
186
|
+
const newHash = (await git.raw(args)).trim();
|
|
187
|
+
const currentBranch = (await git.revparse(["--abbrev-ref", "HEAD"])).trim();
|
|
188
|
+
const rebaseTarget = currentBranch === "HEAD" ? "HEAD" : currentBranch;
|
|
189
|
+
await git.raw(["rebase", "--onto", newHash, resolvedHash, rebaseTarget]);
|
|
190
|
+
const afterBranch = (await git.revparse(["--abbrev-ref", "HEAD"])).trim();
|
|
191
|
+
if (afterBranch === "HEAD" && rebaseTarget !== "HEAD") {
|
|
192
|
+
try {
|
|
193
|
+
await git.checkout([rebaseTarget]);
|
|
194
|
+
} catch {
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
sectionTitle("Updated commit");
|
|
198
|
+
borderLine(`Rewrote ${resolvedHash.slice(0, 7)} \u2192 ${newHash.slice(0, 7)}`);
|
|
199
|
+
renderCommitBlock({ title: candidate.title, body: candidate.body, hideMessageLabel: true });
|
|
200
|
+
borderLine();
|
|
201
|
+
finalSuccess({ count: 1, startedAt });
|
|
202
|
+
} catch (e) {
|
|
203
|
+
borderLine("Automatic rewrite failed: " + (e?.message || e));
|
|
204
|
+
borderLine("If a rebase is in progress, resolve conflicts then run: git rebase --continue");
|
|
205
|
+
borderLine("Or abort with: git rebase --abort");
|
|
206
|
+
borderLine();
|
|
207
|
+
abortMessage();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
export {
|
|
211
|
+
runReword
|
|
212
|
+
};
|
package/package.json
CHANGED