@unifan/pi-commit-zh 1.0.8 → 1.0.10
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/index.ts +21 -51
- package/package.json +1 -1
- package/src/git.ts +42 -3
package/index.ts
CHANGED
|
@@ -8,32 +8,27 @@ import {
|
|
|
8
8
|
pushCurrentBranch,
|
|
9
9
|
stageAll,
|
|
10
10
|
} from "./src/git.js";
|
|
11
|
-
import { COMMIT_SYSTEM_PROMPT } from "./src/prompt.
|
|
11
|
+
import { COMMIT_SYSTEM_PROMPT } from "./src/prompt.js";
|
|
12
12
|
|
|
13
13
|
interface ParsedCommitArgs {
|
|
14
|
-
yes: boolean;
|
|
15
14
|
stageAll: boolean;
|
|
16
15
|
hint?: string;
|
|
17
16
|
}
|
|
18
17
|
|
|
19
18
|
function parseArgs(raw: string): ParsedCommitArgs {
|
|
20
19
|
const tokens = raw.trim().split(/\s+/).filter(Boolean);
|
|
21
|
-
let yes = false;
|
|
22
20
|
let shouldStageAll = false;
|
|
23
21
|
const hintParts: string[] = [];
|
|
24
22
|
|
|
25
23
|
for (const t of tokens) {
|
|
26
|
-
if (t === "-
|
|
27
|
-
yes = true;
|
|
28
|
-
} else if (t === "-a" || t === "--all") {
|
|
24
|
+
if (t === "-a" || t === "--all") {
|
|
29
25
|
shouldStageAll = true;
|
|
30
|
-
} else {
|
|
26
|
+
} else if (t !== "-y" && t !== "--yes") {
|
|
31
27
|
hintParts.push(t);
|
|
32
28
|
}
|
|
33
29
|
}
|
|
34
30
|
|
|
35
31
|
return {
|
|
36
|
-
yes,
|
|
37
32
|
stageAll: shouldStageAll,
|
|
38
33
|
hint: hintParts.join(" ").trim() || undefined,
|
|
39
34
|
};
|
|
@@ -63,6 +58,7 @@ async function generateCommitMessage(
|
|
|
63
58
|
try {
|
|
64
59
|
const provider = ctx.modelRegistry.getProvider(ctx.model.provider);
|
|
65
60
|
if (provider) {
|
|
61
|
+
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(ctx.model);
|
|
66
62
|
const response = await provider
|
|
67
63
|
.streamSimple(
|
|
68
64
|
ctx.model,
|
|
@@ -76,7 +72,7 @@ async function generateCommitMessage(
|
|
|
76
72
|
},
|
|
77
73
|
],
|
|
78
74
|
},
|
|
79
|
-
{ maxTokens: 800 },
|
|
75
|
+
{ apiKey: auth?.apiKey, headers: auth?.headers, maxTokens: 800 },
|
|
80
76
|
)
|
|
81
77
|
.result();
|
|
82
78
|
|
|
@@ -86,16 +82,15 @@ async function generateCommitMessage(
|
|
|
86
82
|
.trim();
|
|
87
83
|
|
|
88
84
|
if (text) {
|
|
89
|
-
// Clean any unexpected code blocks
|
|
90
85
|
return text.replace(/^```[a-zA-Z]*\n?/, "").replace(/\n?```$/, "").trim();
|
|
91
86
|
}
|
|
92
87
|
}
|
|
93
|
-
} catch {
|
|
94
|
-
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.error("pi-commit streamSimple error:", err);
|
|
95
90
|
}
|
|
96
91
|
}
|
|
97
92
|
|
|
98
|
-
//
|
|
93
|
+
// 智能保底推断
|
|
99
94
|
const firstFile = changedFiles[0] ?? "core";
|
|
100
95
|
const scope = firstFile.split(/[/\\]/)[0] || "core";
|
|
101
96
|
return `chore(${scope}): 更新代码与相关配置\n\n- 更新了 ${changedFiles.length} 个文件`;
|
|
@@ -135,67 +130,42 @@ export default function (pi: ExtensionAPI) {
|
|
|
135
130
|
notify("正在深度分析代码改动并生成中文 Commit Message...", "info");
|
|
136
131
|
const commitMessage = await generateCommitMessage(ctx, stagedDiff || unstagedDiff, changedFiles, parsed.hint);
|
|
137
132
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (!parsed.yes && ctx.hasUI) {
|
|
141
|
-
const choice = await ctx.ui.select(
|
|
142
|
-
`✨ AI 生成的提交信息:\n\n${commitMessage}\n\n请选择操作:`,
|
|
143
|
-
[
|
|
144
|
-
{ label: "✅ 立即以此信息提交 (Commit)", value: "commit" },
|
|
145
|
-
{ label: "📝 编辑后再提交 (Edit & Commit)", value: "edit" },
|
|
146
|
-
{ label: "❌ 取消提交 (Cancel)", value: "cancel" },
|
|
147
|
-
],
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
if (!choice || choice === "cancel") {
|
|
151
|
-
notify("已取消本次提交。", "info");
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (choice === "edit") {
|
|
156
|
-
const edited = await ctx.ui.editor("编辑 Commit Message", commitMessage);
|
|
157
|
-
if (!edited || !edited.trim()) {
|
|
158
|
-
notify("提交信息为空,已取消提交。", "warning");
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
finalMessage = edited.trim();
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const commitRes = await commitWithMsg(ctx.cwd, finalMessage);
|
|
133
|
+
const commitRes = await commitWithMsg(ctx.cwd, commitMessage);
|
|
166
134
|
if (!commitRes.ok) {
|
|
167
135
|
notify(`Git 提交失败: ${commitRes.output}`, "error");
|
|
168
136
|
return;
|
|
169
137
|
}
|
|
170
138
|
|
|
171
|
-
const firstLine =
|
|
139
|
+
const firstLine = commitMessage.split("\n")[0];
|
|
172
140
|
notify(`✅ 成功提交: ${firstLine}`, "info");
|
|
173
141
|
|
|
174
142
|
let pushText = "";
|
|
175
143
|
if (andPush) {
|
|
176
144
|
notify("正在推送到远端仓库 (git push)...", "info");
|
|
177
|
-
const pushRes = await pushCurrentBranch(ctx.cwd);
|
|
145
|
+
const pushRes = await pushCurrentBranch(ctx.cwd, (msg) => notify(msg, "info"));
|
|
178
146
|
if (pushRes.ok) {
|
|
179
|
-
|
|
180
|
-
|
|
147
|
+
const successMsg = pushRes.autoRebased
|
|
148
|
+
? "🚀 远端有新提交,已自动完成变基 (pull --rebase) 并成功推送!"
|
|
149
|
+
: "🚀 成功推送到远端仓库!";
|
|
150
|
+
notify(successMsg, "info");
|
|
151
|
+
pushText = `\n\n${successMsg}`;
|
|
181
152
|
} else {
|
|
182
|
-
notify(`⚠️ 推送失败: ${pushRes.output}`, "
|
|
183
|
-
pushText = `\n\n⚠️
|
|
153
|
+
notify(`⚠️ 推送失败: ${pushRes.output}`, "error");
|
|
154
|
+
pushText = `\n\n⚠️ **推送到远端失败**:\n${pushRes.output}`;
|
|
184
155
|
}
|
|
185
156
|
}
|
|
186
157
|
|
|
187
158
|
pi.sendMessage({
|
|
188
159
|
customType: "pi-commit-result",
|
|
189
|
-
content: `### 📦 Git 提交完成\n\n\`\`\`text\n${
|
|
160
|
+
content: `### 📦 Git 提交完成\n\n\`\`\`text\n${commitMessage}\n\`\`\`${pushText}`,
|
|
190
161
|
display: true,
|
|
191
162
|
});
|
|
192
163
|
};
|
|
193
164
|
|
|
194
165
|
pi.registerCommand("commit", {
|
|
195
|
-
description: "智能 Git 提交助手:自动分析 diff 生成标准中文
|
|
166
|
+
description: "智能 Git 提交助手:自动分析 diff 生成标准中文 Commit 并直接提交 (-a 自动暂存全部修改)",
|
|
196
167
|
getArgumentCompletions: (prefix: string) => {
|
|
197
168
|
const options = [
|
|
198
|
-
{ value: "-y", label: "-y / --yes", description: "直接提交无需二次确认" },
|
|
199
169
|
{ value: "-a", label: "-a / --all", description: "自动暂存全部修改 (git add -A)" },
|
|
200
170
|
];
|
|
201
171
|
const trimmed = prefix.trimStart();
|
|
@@ -208,7 +178,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
208
178
|
});
|
|
209
179
|
|
|
210
180
|
pi.registerCommand("commit-push", {
|
|
211
|
-
description: "智能 Git 提交并推流:生成标准中文 Commit
|
|
181
|
+
description: "智能 Git 提交并推流:生成标准中文 Commit 后自动提交并执行 git push (支持自动变基重试)",
|
|
212
182
|
handler: async (args, ctx) => {
|
|
213
183
|
await handleCommitCommand(args, ctx, true);
|
|
214
184
|
},
|
package/package.json
CHANGED
package/src/git.ts
CHANGED
|
@@ -55,7 +55,46 @@ export async function commitWithMsg(cwd: string, message: string): Promise<{ ok:
|
|
|
55
55
|
return { ok: res.ok, output: res.ok ? res.stdout : res.stderr };
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
export async function pushCurrentBranch(
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
export async function pushCurrentBranch(
|
|
59
|
+
cwd: string,
|
|
60
|
+
onLog?: (msg: string) => void,
|
|
61
|
+
): Promise<{ ok: boolean; output: string; autoRebased?: boolean }> {
|
|
62
|
+
const initialPush = await runGit(cwd, ["push"]);
|
|
63
|
+
if (initialPush.ok) {
|
|
64
|
+
return { ok: true, output: initialPush.stdout || "推送成功" };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const pushError = `${initialPush.stderr} ${initialPush.stdout}`.toLowerCase();
|
|
68
|
+
const needsPull =
|
|
69
|
+
pushError.includes("fetch first") ||
|
|
70
|
+
pushError.includes("non-fast-forward") ||
|
|
71
|
+
pushError.includes("rejected") ||
|
|
72
|
+
pushError.includes("behind");
|
|
73
|
+
|
|
74
|
+
if (!needsPull) {
|
|
75
|
+
return { ok: false, output: initialPush.stderr || initialPush.stdout };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (onLog) onLog("检测到远端有新提交,正在自动执行变基拉取 (git pull --rebase)...");
|
|
79
|
+
|
|
80
|
+
const pullRebase = await runGit(cwd, ["pull", "--rebase"]);
|
|
81
|
+
if (!pullRebase.ok) {
|
|
82
|
+
const rebaseErr = `${pullRebase.stderr} ${pullRebase.stdout}`;
|
|
83
|
+
return {
|
|
84
|
+
ok: false,
|
|
85
|
+
output: `远端有新提交,尝试自动变基 (git pull --rebase) 时产生代码冲突。\n${rebaseErr}\n请手动解决冲突后执行 git rebase --continue,或执行 git rebase --abort 撤销变基。`,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (onLog) onLog("变基拉取成功(无代码冲突),正在重新推送到远端...");
|
|
90
|
+
const retryPush = await runGit(cwd, ["push"]);
|
|
91
|
+
if (retryPush.ok) {
|
|
92
|
+
return {
|
|
93
|
+
ok: true,
|
|
94
|
+
output: "远端有新提交,已自动完成 git pull --rebase 变基并成功推送到远端!",
|
|
95
|
+
autoRebased: true,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return { ok: false, output: retryPush.stderr || retryPush.stdout };
|
|
61
100
|
}
|