@zjex/git-workflow 0.4.7 → 0.5.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/CHANGELOG.md +6 -0
- package/README.md +44 -6
- package/dist/index.js +614 -11
- package/docs/.vitepress/cache/deps/_metadata.json +10 -10
- package/docs/.vitepress/config.ts +2 -0
- package/docs/commands/index.md +4 -0
- package/docs/commands/review.md +142 -0
- package/docs/guide/ai-review.md +159 -0
- package/docs/guide/index.md +2 -0
- package/docs/index.md +26 -3
- package/package.json +1 -1
- package/src/commands/review.ts +759 -0
- package/src/index.ts +29 -1
- package/tests/review.test.ts +1058 -0
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/chunk-2CLQ7TTZ.js +0 -9719
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/chunk-2CLQ7TTZ.js.map +0 -7
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/chunk-LE5NDSFD.js +0 -12824
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/chunk-LE5NDSFD.js.map +0 -7
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/package.json +0 -3
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vue_devtools-api.js +0 -4505
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vue_devtools-api.js.map +0 -7
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vueuse_core.js +0 -583
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vueuse_core.js.map +0 -7
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vueuse_integrations_useFocusTrap.js +0 -1352
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vueuse_integrations_useFocusTrap.js.map +0 -7
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___mark__js_src_vanilla__js.js +0 -1665
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___mark__js_src_vanilla__js.js.map +0 -7
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___minisearch.js +0 -1813
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___minisearch.js.map +0 -7
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/vue.js +0 -347
- package/docs/.vitepress/cache/deps_temp_44e2fb0f/vue.js.map +0 -7
package/dist/index.js
CHANGED
|
@@ -407,7 +407,7 @@ var init_update_notifier = __esm({
|
|
|
407
407
|
// src/index.ts
|
|
408
408
|
init_utils();
|
|
409
409
|
import { cac } from "cac";
|
|
410
|
-
import { select as
|
|
410
|
+
import { select as select11 } from "@inquirer/prompts";
|
|
411
411
|
import { ExitPromptError } from "@inquirer/core";
|
|
412
412
|
|
|
413
413
|
// src/commands/branch.ts
|
|
@@ -3602,6 +3602,589 @@ fi
|
|
|
3602
3602
|
}
|
|
3603
3603
|
}
|
|
3604
3604
|
|
|
3605
|
+
// src/commands/review.ts
|
|
3606
|
+
init_utils();
|
|
3607
|
+
import { select as select10, checkbox as checkbox2 } from "@inquirer/prompts";
|
|
3608
|
+
import ora7 from "ora";
|
|
3609
|
+
import { writeFileSync as writeFileSync5, existsSync as existsSync5, mkdirSync } from "fs";
|
|
3610
|
+
import { join as join6 } from "path";
|
|
3611
|
+
var AI_PROVIDERS2 = {
|
|
3612
|
+
github: {
|
|
3613
|
+
name: "GitHub Models",
|
|
3614
|
+
endpoint: "https://models.github.ai/inference/chat/completions",
|
|
3615
|
+
defaultModel: "gpt-4o"
|
|
3616
|
+
},
|
|
3617
|
+
openai: {
|
|
3618
|
+
name: "OpenAI",
|
|
3619
|
+
endpoint: "https://api.openai.com/v1/chat/completions",
|
|
3620
|
+
defaultModel: "gpt-4o"
|
|
3621
|
+
},
|
|
3622
|
+
claude: {
|
|
3623
|
+
name: "Claude",
|
|
3624
|
+
endpoint: "https://api.anthropic.com/v1/messages",
|
|
3625
|
+
defaultModel: "claude-3-5-sonnet-20241022"
|
|
3626
|
+
},
|
|
3627
|
+
ollama: {
|
|
3628
|
+
name: "Ollama",
|
|
3629
|
+
endpoint: "http://localhost:11434/api/generate",
|
|
3630
|
+
defaultModel: "qwen2.5-coder:14b"
|
|
3631
|
+
}
|
|
3632
|
+
};
|
|
3633
|
+
function getRecentCommits3(limit = 20) {
|
|
3634
|
+
try {
|
|
3635
|
+
const output = execOutput(
|
|
3636
|
+
`git log -${limit} --pretty=format:"%H|%h|%s|%an|%ad" --date=short`
|
|
3637
|
+
);
|
|
3638
|
+
if (!output) return [];
|
|
3639
|
+
return output.split("\n").filter(Boolean).map((line) => {
|
|
3640
|
+
const [hash, shortHash, subject, author, date] = line.split("|");
|
|
3641
|
+
return { hash, shortHash, subject, author, date };
|
|
3642
|
+
});
|
|
3643
|
+
} catch {
|
|
3644
|
+
return [];
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3647
|
+
function getStagedDiff() {
|
|
3648
|
+
try {
|
|
3649
|
+
const diff = execOutput("git diff --cached");
|
|
3650
|
+
if (diff) return diff;
|
|
3651
|
+
return execOutput("git diff") || "";
|
|
3652
|
+
} catch {
|
|
3653
|
+
return "";
|
|
3654
|
+
}
|
|
3655
|
+
}
|
|
3656
|
+
function getCommitDiff(hash) {
|
|
3657
|
+
try {
|
|
3658
|
+
return execOutput(`git show ${hash} --format="" --patch`) || "";
|
|
3659
|
+
} catch {
|
|
3660
|
+
return "";
|
|
3661
|
+
}
|
|
3662
|
+
}
|
|
3663
|
+
function getMultipleCommitsDiff(hashes) {
|
|
3664
|
+
if (hashes.length === 0) return "";
|
|
3665
|
+
if (hashes.length === 1) return getCommitDiff(hashes[0]);
|
|
3666
|
+
const oldest = hashes[hashes.length - 1];
|
|
3667
|
+
const newest = hashes[0];
|
|
3668
|
+
try {
|
|
3669
|
+
return execOutput(`git diff ${oldest}^..${newest}`) || "";
|
|
3670
|
+
} catch {
|
|
3671
|
+
return hashes.map((h) => getCommitDiff(h)).join("\n\n");
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
function parseDiff(diff) {
|
|
3675
|
+
const files = [];
|
|
3676
|
+
const fileDiffs = diff.split(/^diff --git /m).filter(Boolean);
|
|
3677
|
+
for (const fileDiff of fileDiffs) {
|
|
3678
|
+
const lines = fileDiff.split("\n");
|
|
3679
|
+
const headerMatch = lines[0]?.match(/a\/(.+) b\/(.+)/);
|
|
3680
|
+
if (!headerMatch) continue;
|
|
3681
|
+
const oldPath = headerMatch[1];
|
|
3682
|
+
const newPath = headerMatch[2];
|
|
3683
|
+
let status = "M";
|
|
3684
|
+
if (fileDiff.includes("new file mode")) status = "A";
|
|
3685
|
+
else if (fileDiff.includes("deleted file mode")) status = "D";
|
|
3686
|
+
else if (fileDiff.includes("rename from")) status = "R";
|
|
3687
|
+
files.push({
|
|
3688
|
+
oldPath,
|
|
3689
|
+
newPath,
|
|
3690
|
+
status,
|
|
3691
|
+
diff: "diff --git " + fileDiff
|
|
3692
|
+
});
|
|
3693
|
+
}
|
|
3694
|
+
return files;
|
|
3695
|
+
}
|
|
3696
|
+
function getDiffStats(diff) {
|
|
3697
|
+
const lines = diff.split("\n");
|
|
3698
|
+
let additions = 0;
|
|
3699
|
+
let deletions = 0;
|
|
3700
|
+
for (const line of lines) {
|
|
3701
|
+
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
3702
|
+
additions++;
|
|
3703
|
+
} else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
3704
|
+
deletions++;
|
|
3705
|
+
}
|
|
3706
|
+
}
|
|
3707
|
+
const files = parseDiff(diff).length;
|
|
3708
|
+
return { additions, deletions, files };
|
|
3709
|
+
}
|
|
3710
|
+
function buildSystemPrompt(language) {
|
|
3711
|
+
const isZh = language === "zh-CN";
|
|
3712
|
+
if (isZh) {
|
|
3713
|
+
return `\u4F60\u662F\u4E00\u4E2A\u8D44\u6DF1\u7684\u4EE3\u7801\u5BA1\u67E5\u4E13\u5BB6\uFF0C\u62E5\u6709\u4E30\u5BCC\u7684\u8F6F\u4EF6\u5F00\u53D1\u7ECF\u9A8C\u3002\u4F60\u7684\u4EFB\u52A1\u662F\u5BA1\u67E5 Git \u63D0\u4EA4\u4E2D\u7684\u4EE3\u7801\u53D8\u66F4\uFF0C\u63D0\u4F9B\u4E13\u4E1A\u3001\u6709\u4EF7\u503C\u3001\u6709\u5EFA\u8BBE\u6027\u7684\u5BA1\u67E5\u610F\u89C1\u3002
|
|
3714
|
+
|
|
3715
|
+
## \u5BA1\u67E5\u539F\u5219
|
|
3716
|
+
|
|
3717
|
+
1. **\u91CD\u70B9\u5173\u6CE8\u53D8\u66F4\u4EE3\u7801**\uFF1A\u53EA\u5BA1\u67E5 diff \u4E2D\u5E26 \`+\` \u6216 \`-\` \u7684\u4EE3\u7801\u884C\uFF0C\u8FD9\u4E9B\u662F\u5B9E\u9645\u7684\u53D8\u66F4\u5185\u5BB9
|
|
3718
|
+
2. **\u63D0\u4F9B\u5177\u4F53\u5EFA\u8BAE**\uFF1A\u4E0D\u8981\u6CDB\u6CDB\u800C\u8C08\uFF0C\u8981\u9488\u5BF9\u5177\u4F53\u4EE3\u7801\u884C\u7ED9\u51FA\u6539\u8FDB\u5EFA\u8BAE
|
|
3719
|
+
3. **\u533A\u5206\u95EE\u9898\u4E25\u91CD\u7A0B\u5EA6**\uFF1A\u4F7F\u7528 \u{1F534} \u4E25\u91CD\u3001\u{1F7E1} \u8B66\u544A\u3001\u{1F535} \u5EFA\u8BAE \u4E09\u4E2A\u7EA7\u522B
|
|
3720
|
+
4. **\u4EE3\u7801\u793A\u4F8B**\uFF1A\u5728\u5EFA\u8BAE\u4FEE\u6539\u65F6\uFF0C\u5C3D\u53EF\u80FD\u63D0\u4F9B\u4FEE\u6539\u540E\u7684\u4EE3\u7801\u793A\u4F8B
|
|
3721
|
+
5. **\u6B63\u9762\u53CD\u9988**\uFF1A\u5BF9\u4E8E\u5199\u5F97\u597D\u7684\u4EE3\u7801\uFF0C\u4E5F\u8981\u7ED9\u4E88\u80AF\u5B9A
|
|
3722
|
+
|
|
3723
|
+
## \u5BA1\u67E5\u7EF4\u5EA6
|
|
3724
|
+
|
|
3725
|
+
1. **\u4EE3\u7801\u8D28\u91CF**\uFF1A\u53EF\u8BFB\u6027\u3001\u53EF\u7EF4\u62A4\u6027\u3001\u4EE3\u7801\u98CE\u683C
|
|
3726
|
+
2. **\u6F5C\u5728 Bug**\uFF1A\u7A7A\u6307\u9488\u3001\u8FB9\u754C\u6761\u4EF6\u3001\u5F02\u5E38\u5904\u7406
|
|
3727
|
+
3. **\u5B89\u5168\u95EE\u9898**\uFF1ASQL \u6CE8\u5165\u3001XSS\u3001\u654F\u611F\u4FE1\u606F\u6CC4\u9732
|
|
3728
|
+
4. **\u6027\u80FD\u95EE\u9898**\uFF1A\u4E0D\u5FC5\u8981\u7684\u5FAA\u73AF\u3001\u5185\u5B58\u6CC4\u6F0F\u3001\u91CD\u590D\u8BA1\u7B97
|
|
3729
|
+
5. **\u6700\u4F73\u5B9E\u8DF5**\uFF1A\u8BBE\u8BA1\u6A21\u5F0F\u3001SOLID \u539F\u5219\u3001DRY \u539F\u5219
|
|
3730
|
+
|
|
3731
|
+
## Diff \u683C\u5F0F\u8BF4\u660E
|
|
3732
|
+
|
|
3733
|
+
- \u4EE5 \`+\` \u5F00\u5934\u7684\u884C\u662F\u65B0\u589E\u7684\u4EE3\u7801
|
|
3734
|
+
- \u4EE5 \`-\` \u5F00\u5934\u7684\u884C\u662F\u5220\u9664\u7684\u4EE3\u7801
|
|
3735
|
+
- \`@@\` \u884C\u8868\u793A\u4EE3\u7801\u4F4D\u7F6E\u4FE1\u606F\uFF0C\u683C\u5F0F\u4E3A \`@@ -\u65E7\u6587\u4EF6\u8D77\u59CB\u884C,\u884C\u6570 +\u65B0\u6587\u4EF6\u8D77\u59CB\u884C,\u884C\u6570 @@\`
|
|
3736
|
+
- \u6CA1\u6709 \`+\` \u6216 \`-\` \u524D\u7F00\u7684\u884C\u662F\u4E0A\u4E0B\u6587\u4EE3\u7801\uFF0C\u7528\u4E8E\u5E2E\u52A9\u7406\u89E3\u53D8\u66F4
|
|
3737
|
+
|
|
3738
|
+
## \u8F93\u51FA\u683C\u5F0F
|
|
3739
|
+
|
|
3740
|
+
\u8BF7\u4F7F\u7528 Markdown \u683C\u5F0F\u8F93\u51FA\u5BA1\u67E5\u62A5\u544A\uFF0C\u5305\u542B\u4EE5\u4E0B\u90E8\u5206\uFF1A
|
|
3741
|
+
|
|
3742
|
+
1. **\u6982\u8FF0**\uFF1A\u7B80\u8981\u603B\u7ED3\u672C\u6B21\u53D8\u66F4\u7684\u5185\u5BB9\u548C\u6574\u4F53\u8BC4\u4EF7
|
|
3743
|
+
2. **\u95EE\u9898\u5217\u8868**\uFF1A\u6309\u4E25\u91CD\u7A0B\u5EA6\u5217\u51FA\u53D1\u73B0\u7684\u95EE\u9898
|
|
3744
|
+
3. **\u6539\u8FDB\u5EFA\u8BAE**\uFF1A\u63D0\u4F9B\u5177\u4F53\u7684\u4EE3\u7801\u6539\u8FDB\u5EFA\u8BAE
|
|
3745
|
+
4. **\u4EAE\u70B9**\uFF1A\u6307\u51FA\u4EE3\u7801\u4E2D\u5199\u5F97\u597D\u7684\u5730\u65B9\uFF08\u5982\u679C\u6709\uFF09
|
|
3746
|
+
|
|
3747
|
+
\u6CE8\u610F\uFF1A
|
|
3748
|
+
- \u6BCF\u4E2A\u95EE\u9898\u90FD\u8981\u6307\u660E\u6587\u4EF6\u8DEF\u5F84\u548C\u884C\u53F7
|
|
3749
|
+
- \u63D0\u4F9B\u4FEE\u6539\u5EFA\u8BAE\u65F6\u8981\u7ED9\u51FA\u4EE3\u7801\u793A\u4F8B
|
|
3750
|
+
- \u5982\u679C\u4EE3\u7801\u6CA1\u6709\u660E\u663E\u95EE\u9898\uFF0C\u4E5F\u8981\u8BF4\u660E\u5BA1\u67E5\u7ED3\u8BBA`;
|
|
3751
|
+
}
|
|
3752
|
+
return `You are a senior code review expert with extensive software development experience. Your task is to review code changes in Git commits and provide professional, valuable, and constructive review feedback.
|
|
3753
|
+
|
|
3754
|
+
## Review Principles
|
|
3755
|
+
|
|
3756
|
+
1. **Focus on Changed Code**: Only review lines with \`+\` or \`-\` prefixes in the diff - these are the actual changes
|
|
3757
|
+
2. **Provide Specific Suggestions**: Don't be vague, give improvement suggestions for specific code lines
|
|
3758
|
+
3. **Categorize Issue Severity**: Use \u{1F534} Critical, \u{1F7E1} Warning, \u{1F535} Suggestion levels
|
|
3759
|
+
4. **Code Examples**: When suggesting changes, provide modified code examples whenever possible
|
|
3760
|
+
5. **Positive Feedback**: Also acknowledge well-written code
|
|
3761
|
+
|
|
3762
|
+
## Review Dimensions
|
|
3763
|
+
|
|
3764
|
+
1. **Code Quality**: Readability, maintainability, code style
|
|
3765
|
+
2. **Potential Bugs**: Null pointers, boundary conditions, exception handling
|
|
3766
|
+
3. **Security Issues**: SQL injection, XSS, sensitive data exposure
|
|
3767
|
+
4. **Performance Issues**: Unnecessary loops, memory leaks, redundant calculations
|
|
3768
|
+
5. **Best Practices**: Design patterns, SOLID principles, DRY principle
|
|
3769
|
+
|
|
3770
|
+
## Diff Format Explanation
|
|
3771
|
+
|
|
3772
|
+
- Lines starting with \`+\` are added code
|
|
3773
|
+
- Lines starting with \`-\` are deleted code
|
|
3774
|
+
- \`@@\` lines indicate code location, format: \`@@ -old_start,count +new_start,count @@\`
|
|
3775
|
+
- Lines without \`+\` or \`-\` prefix are context code to help understand changes
|
|
3776
|
+
|
|
3777
|
+
## Output Format
|
|
3778
|
+
|
|
3779
|
+
Please output the review report in Markdown format, including:
|
|
3780
|
+
|
|
3781
|
+
1. **Overview**: Brief summary of changes and overall assessment
|
|
3782
|
+
2. **Issues**: List issues by severity
|
|
3783
|
+
3. **Suggestions**: Provide specific code improvement suggestions
|
|
3784
|
+
4. **Highlights**: Point out well-written code (if any)
|
|
3785
|
+
|
|
3786
|
+
Note:
|
|
3787
|
+
- Each issue should specify file path and line number
|
|
3788
|
+
- Provide code examples when suggesting modifications
|
|
3789
|
+
- If no obvious issues, state the review conclusion`;
|
|
3790
|
+
}
|
|
3791
|
+
function buildUserPrompt(diff, commits, language) {
|
|
3792
|
+
const isZh = language === "zh-CN";
|
|
3793
|
+
const stats = getDiffStats(diff);
|
|
3794
|
+
const files = parseDiff(diff);
|
|
3795
|
+
let prompt = "";
|
|
3796
|
+
if (isZh) {
|
|
3797
|
+
prompt += `## \u53D8\u66F4\u6982\u89C8
|
|
3798
|
+
|
|
3799
|
+
`;
|
|
3800
|
+
prompt += `- \u6D89\u53CA\u6587\u4EF6: ${stats.files} \u4E2A
|
|
3801
|
+
`;
|
|
3802
|
+
prompt += `- \u65B0\u589E\u884C\u6570: +${stats.additions}
|
|
3803
|
+
`;
|
|
3804
|
+
prompt += `- \u5220\u9664\u884C\u6570: -${stats.deletions}
|
|
3805
|
+
|
|
3806
|
+
`;
|
|
3807
|
+
if (commits.length > 0) {
|
|
3808
|
+
prompt += `## \u76F8\u5173\u63D0\u4EA4
|
|
3809
|
+
|
|
3810
|
+
`;
|
|
3811
|
+
for (const commit2 of commits) {
|
|
3812
|
+
prompt += `- \`${commit2.shortHash}\` ${commit2.subject} (${commit2.author}, ${commit2.date})
|
|
3813
|
+
`;
|
|
3814
|
+
}
|
|
3815
|
+
prompt += `
|
|
3816
|
+
`;
|
|
3817
|
+
}
|
|
3818
|
+
prompt += `## \u53D8\u66F4\u6587\u4EF6\u5217\u8868
|
|
3819
|
+
|
|
3820
|
+
`;
|
|
3821
|
+
for (const file of files) {
|
|
3822
|
+
const statusIcon = file.status === "A" ? "\u{1F195}" : file.status === "D" ? "\u{1F5D1}\uFE0F" : file.status === "R" ? "\u{1F4DD}" : "\u270F\uFE0F";
|
|
3823
|
+
prompt += `- ${statusIcon} \`${file.newPath}\`
|
|
3824
|
+
`;
|
|
3825
|
+
}
|
|
3826
|
+
prompt += `
|
|
3827
|
+
`;
|
|
3828
|
+
prompt += `## Diff \u5185\u5BB9
|
|
3829
|
+
|
|
3830
|
+
\u8BF7\u4ED4\u7EC6\u5BA1\u67E5\u4EE5\u4E0B\u4EE3\u7801\u53D8\u66F4\uFF1A
|
|
3831
|
+
|
|
3832
|
+
`;
|
|
3833
|
+
} else {
|
|
3834
|
+
prompt += `## Change Overview
|
|
3835
|
+
|
|
3836
|
+
`;
|
|
3837
|
+
prompt += `- Files changed: ${stats.files}
|
|
3838
|
+
`;
|
|
3839
|
+
prompt += `- Lines added: +${stats.additions}
|
|
3840
|
+
`;
|
|
3841
|
+
prompt += `- Lines deleted: -${stats.deletions}
|
|
3842
|
+
|
|
3843
|
+
`;
|
|
3844
|
+
if (commits.length > 0) {
|
|
3845
|
+
prompt += `## Related Commits
|
|
3846
|
+
|
|
3847
|
+
`;
|
|
3848
|
+
for (const commit2 of commits) {
|
|
3849
|
+
prompt += `- \`${commit2.shortHash}\` ${commit2.subject} (${commit2.author}, ${commit2.date})
|
|
3850
|
+
`;
|
|
3851
|
+
}
|
|
3852
|
+
prompt += `
|
|
3853
|
+
`;
|
|
3854
|
+
}
|
|
3855
|
+
prompt += `## Changed Files
|
|
3856
|
+
|
|
3857
|
+
`;
|
|
3858
|
+
for (const file of files) {
|
|
3859
|
+
const statusIcon = file.status === "A" ? "\u{1F195}" : file.status === "D" ? "\u{1F5D1}\uFE0F" : file.status === "R" ? "\u{1F4DD}" : "\u270F\uFE0F";
|
|
3860
|
+
prompt += `- ${statusIcon} \`${file.newPath}\`
|
|
3861
|
+
`;
|
|
3862
|
+
}
|
|
3863
|
+
prompt += `
|
|
3864
|
+
`;
|
|
3865
|
+
prompt += `## Diff Content
|
|
3866
|
+
|
|
3867
|
+
Please carefully review the following code changes:
|
|
3868
|
+
|
|
3869
|
+
`;
|
|
3870
|
+
}
|
|
3871
|
+
for (const file of files) {
|
|
3872
|
+
prompt += `### ${file.newPath}
|
|
3873
|
+
|
|
3874
|
+
`;
|
|
3875
|
+
prompt += "```diff\n";
|
|
3876
|
+
prompt += file.diff;
|
|
3877
|
+
prompt += "\n```\n\n";
|
|
3878
|
+
}
|
|
3879
|
+
return prompt;
|
|
3880
|
+
}
|
|
3881
|
+
async function callGitHubAPI2(systemPrompt, userPrompt, apiKey, model) {
|
|
3882
|
+
const response = await fetch(AI_PROVIDERS2.github.endpoint, {
|
|
3883
|
+
method: "POST",
|
|
3884
|
+
headers: {
|
|
3885
|
+
Authorization: `Bearer ${apiKey}`,
|
|
3886
|
+
"Content-Type": "application/json"
|
|
3887
|
+
},
|
|
3888
|
+
body: JSON.stringify({
|
|
3889
|
+
model,
|
|
3890
|
+
messages: [
|
|
3891
|
+
{ role: "system", content: systemPrompt },
|
|
3892
|
+
{ role: "user", content: userPrompt }
|
|
3893
|
+
],
|
|
3894
|
+
max_tokens: 4e3,
|
|
3895
|
+
temperature: 0.3
|
|
3896
|
+
})
|
|
3897
|
+
});
|
|
3898
|
+
if (!response.ok) {
|
|
3899
|
+
const error = await response.text();
|
|
3900
|
+
throw new Error(`GitHub Models API \u9519\u8BEF: ${response.status} ${error}`);
|
|
3901
|
+
}
|
|
3902
|
+
const data = await response.json();
|
|
3903
|
+
return data.choices[0]?.message?.content?.trim() || "";
|
|
3904
|
+
}
|
|
3905
|
+
async function callOpenAIAPI2(systemPrompt, userPrompt, apiKey, model) {
|
|
3906
|
+
const response = await fetch(AI_PROVIDERS2.openai.endpoint, {
|
|
3907
|
+
method: "POST",
|
|
3908
|
+
headers: {
|
|
3909
|
+
Authorization: `Bearer ${apiKey}`,
|
|
3910
|
+
"Content-Type": "application/json"
|
|
3911
|
+
},
|
|
3912
|
+
body: JSON.stringify({
|
|
3913
|
+
model,
|
|
3914
|
+
messages: [
|
|
3915
|
+
{ role: "system", content: systemPrompt },
|
|
3916
|
+
{ role: "user", content: userPrompt }
|
|
3917
|
+
],
|
|
3918
|
+
max_tokens: 4e3,
|
|
3919
|
+
temperature: 0.3
|
|
3920
|
+
})
|
|
3921
|
+
});
|
|
3922
|
+
if (!response.ok) {
|
|
3923
|
+
const error = await response.text();
|
|
3924
|
+
throw new Error(`OpenAI API \u9519\u8BEF: ${response.status} ${error}`);
|
|
3925
|
+
}
|
|
3926
|
+
const data = await response.json();
|
|
3927
|
+
return data.choices[0]?.message?.content?.trim() || "";
|
|
3928
|
+
}
|
|
3929
|
+
async function callClaudeAPI2(systemPrompt, userPrompt, apiKey, model) {
|
|
3930
|
+
const response = await fetch(AI_PROVIDERS2.claude.endpoint, {
|
|
3931
|
+
method: "POST",
|
|
3932
|
+
headers: {
|
|
3933
|
+
"x-api-key": apiKey,
|
|
3934
|
+
"anthropic-version": "2023-06-01",
|
|
3935
|
+
"Content-Type": "application/json"
|
|
3936
|
+
},
|
|
3937
|
+
body: JSON.stringify({
|
|
3938
|
+
model,
|
|
3939
|
+
system: systemPrompt,
|
|
3940
|
+
messages: [{ role: "user", content: userPrompt }],
|
|
3941
|
+
max_tokens: 4e3,
|
|
3942
|
+
temperature: 0.3
|
|
3943
|
+
})
|
|
3944
|
+
});
|
|
3945
|
+
if (!response.ok) {
|
|
3946
|
+
const error = await response.text();
|
|
3947
|
+
throw new Error(`Claude API \u9519\u8BEF: ${response.status} ${error}`);
|
|
3948
|
+
}
|
|
3949
|
+
const data = await response.json();
|
|
3950
|
+
return data.content[0]?.text?.trim() || "";
|
|
3951
|
+
}
|
|
3952
|
+
async function callOllamaAPI2(systemPrompt, userPrompt, model) {
|
|
3953
|
+
try {
|
|
3954
|
+
const response = await fetch(AI_PROVIDERS2.ollama.endpoint, {
|
|
3955
|
+
method: "POST",
|
|
3956
|
+
headers: { "Content-Type": "application/json" },
|
|
3957
|
+
body: JSON.stringify({
|
|
3958
|
+
model,
|
|
3959
|
+
prompt: `${systemPrompt}
|
|
3960
|
+
|
|
3961
|
+
${userPrompt}`,
|
|
3962
|
+
stream: false,
|
|
3963
|
+
options: {
|
|
3964
|
+
num_predict: 4e3,
|
|
3965
|
+
temperature: 0.3
|
|
3966
|
+
}
|
|
3967
|
+
})
|
|
3968
|
+
});
|
|
3969
|
+
if (!response.ok) {
|
|
3970
|
+
throw new Error(`Ollama \u672A\u8FD0\u884C\u6216\u6A21\u578B\u672A\u5B89\u88C5`);
|
|
3971
|
+
}
|
|
3972
|
+
const data = await response.json();
|
|
3973
|
+
return data.response?.trim() || "";
|
|
3974
|
+
} catch (error) {
|
|
3975
|
+
throw new Error(
|
|
3976
|
+
`Ollama \u8FDE\u63A5\u5931\u8D25\u3002\u8BF7\u786E\u4FDD\uFF1A
|
|
3977
|
+
1. \u5DF2\u5B89\u88C5 Ollama (https://ollama.com)
|
|
3978
|
+
2. \u8FD0\u884C 'ollama serve'
|
|
3979
|
+
3. \u4E0B\u8F7D\u6A21\u578B 'ollama pull ${model}'`
|
|
3980
|
+
);
|
|
3981
|
+
}
|
|
3982
|
+
}
|
|
3983
|
+
async function callAIReview(diff, commits, config2) {
|
|
3984
|
+
const aiConfig = config2.aiCommit || {};
|
|
3985
|
+
const provider = aiConfig.provider || "github";
|
|
3986
|
+
const language = aiConfig.language || "zh-CN";
|
|
3987
|
+
const apiKey = aiConfig.apiKey || "";
|
|
3988
|
+
const providerInfo = AI_PROVIDERS2[provider];
|
|
3989
|
+
if (!providerInfo) {
|
|
3990
|
+
throw new Error(`\u4E0D\u652F\u6301\u7684 AI \u63D0\u4F9B\u5546: ${provider}`);
|
|
3991
|
+
}
|
|
3992
|
+
const model = aiConfig.model || providerInfo.defaultModel;
|
|
3993
|
+
if (provider !== "ollama" && !apiKey) {
|
|
3994
|
+
throw new Error(
|
|
3995
|
+
`${providerInfo.name} \u9700\u8981 API key\u3002\u8BF7\u8FD0\u884C 'gw init' \u914D\u7F6E\uFF0C\u6216\u5728 .gwrc.json \u4E2D\u8BBE\u7F6E aiCommit.apiKey`
|
|
3996
|
+
);
|
|
3997
|
+
}
|
|
3998
|
+
const systemPrompt = buildSystemPrompt(language);
|
|
3999
|
+
const userPrompt = buildUserPrompt(diff, commits, language);
|
|
4000
|
+
const maxLength = 3e4;
|
|
4001
|
+
const truncatedUserPrompt = userPrompt.length > maxLength ? userPrompt.slice(0, maxLength) + "\n\n[... diff \u5185\u5BB9\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD ...]" : userPrompt;
|
|
4002
|
+
switch (provider) {
|
|
4003
|
+
case "github":
|
|
4004
|
+
return callGitHubAPI2(systemPrompt, truncatedUserPrompt, apiKey, model);
|
|
4005
|
+
case "openai":
|
|
4006
|
+
return callOpenAIAPI2(systemPrompt, truncatedUserPrompt, apiKey, model);
|
|
4007
|
+
case "claude":
|
|
4008
|
+
return callClaudeAPI2(systemPrompt, truncatedUserPrompt, apiKey, model);
|
|
4009
|
+
case "ollama":
|
|
4010
|
+
return callOllamaAPI2(systemPrompt, truncatedUserPrompt, model);
|
|
4011
|
+
default:
|
|
4012
|
+
throw new Error(`\u4E0D\u652F\u6301\u7684 AI \u63D0\u4F9B\u5546: ${provider}`);
|
|
4013
|
+
}
|
|
4014
|
+
}
|
|
4015
|
+
function generateReportFile(reviewContent, commits, stats, outputPath) {
|
|
4016
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
4017
|
+
const commitInfo = commits.length > 0 ? commits.map((c) => c.shortHash).join("-") : "staged";
|
|
4018
|
+
const reviewDir = ".gw-reviews";
|
|
4019
|
+
if (!existsSync5(reviewDir)) {
|
|
4020
|
+
mkdirSync(reviewDir, { recursive: true });
|
|
4021
|
+
}
|
|
4022
|
+
const filename = outputPath || join6(reviewDir, `review-${commitInfo}-${timestamp}.md`);
|
|
4023
|
+
let report = `# \u{1F50D} \u4EE3\u7801\u5BA1\u67E5\u62A5\u544A
|
|
4024
|
+
|
|
4025
|
+
`;
|
|
4026
|
+
report += `> \u751F\u6210\u65F6\u95F4: ${(/* @__PURE__ */ new Date()).toLocaleString("zh-CN")}
|
|
4027
|
+
|
|
4028
|
+
`;
|
|
4029
|
+
report += `## \u{1F4CA} \u53D8\u66F4\u7EDF\u8BA1
|
|
4030
|
+
|
|
4031
|
+
`;
|
|
4032
|
+
report += `| \u6307\u6807 | \u6570\u503C |
|
|
4033
|
+
`;
|
|
4034
|
+
report += `|------|------|
|
|
4035
|
+
`;
|
|
4036
|
+
report += `| \u6587\u4EF6\u6570 | ${stats.files} |
|
|
4037
|
+
`;
|
|
4038
|
+
report += `| \u65B0\u589E\u884C | +${stats.additions} |
|
|
4039
|
+
`;
|
|
4040
|
+
report += `| \u5220\u9664\u884C | -${stats.deletions} |
|
|
4041
|
+
|
|
4042
|
+
`;
|
|
4043
|
+
if (commits.length > 0) {
|
|
4044
|
+
report += `## \u{1F4DD} \u5BA1\u67E5\u7684\u63D0\u4EA4
|
|
4045
|
+
|
|
4046
|
+
`;
|
|
4047
|
+
for (const commit2 of commits) {
|
|
4048
|
+
report += `- \`${commit2.shortHash}\` ${commit2.subject} - ${commit2.author} (${commit2.date})
|
|
4049
|
+
`;
|
|
4050
|
+
}
|
|
4051
|
+
report += `
|
|
4052
|
+
`;
|
|
4053
|
+
}
|
|
4054
|
+
report += `## \u{1F916} AI \u5BA1\u67E5\u7ED3\u679C
|
|
4055
|
+
|
|
4056
|
+
`;
|
|
4057
|
+
report += reviewContent;
|
|
4058
|
+
report += `
|
|
4059
|
+
|
|
4060
|
+
---
|
|
4061
|
+
|
|
4062
|
+
`;
|
|
4063
|
+
report += `*\u672C\u62A5\u544A\u7531 [git-workflow](https://github.com/iamzjt-front-end/git-workflow) \u7684 AI Review \u529F\u80FD\u751F\u6210*
|
|
4064
|
+
`;
|
|
4065
|
+
writeFileSync5(filename, report, "utf-8");
|
|
4066
|
+
return filename;
|
|
4067
|
+
}
|
|
4068
|
+
async function review(hashes, options = {}) {
|
|
4069
|
+
const config2 = loadConfig();
|
|
4070
|
+
const aiConfig = config2.aiCommit;
|
|
4071
|
+
if (!aiConfig?.apiKey && aiConfig?.provider !== "ollama") {
|
|
4072
|
+
console.log(colors.red("\u274C \u672A\u914D\u7F6E AI API Key"));
|
|
4073
|
+
console.log("");
|
|
4074
|
+
console.log(colors.dim(" \u8BF7\u5148\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u914D\u7F6E AI:"));
|
|
4075
|
+
console.log(colors.cyan(" gw init"));
|
|
4076
|
+
console.log("");
|
|
4077
|
+
return;
|
|
4078
|
+
}
|
|
4079
|
+
let diff = "";
|
|
4080
|
+
let commits = [];
|
|
4081
|
+
if (hashes && hashes.length > 0) {
|
|
4082
|
+
commits = hashes.map((hash) => {
|
|
4083
|
+
const info = execOutput(
|
|
4084
|
+
`git log -1 --pretty=format:"%H|%h|%s|%an|%ad" --date=short ${hash}`
|
|
4085
|
+
);
|
|
4086
|
+
if (!info) {
|
|
4087
|
+
console.log(colors.red(`\u274C \u627E\u4E0D\u5230 commit: ${hash}`));
|
|
4088
|
+
process.exit(1);
|
|
4089
|
+
}
|
|
4090
|
+
const [fullHash, shortHash, subject, author, date] = info.split("|");
|
|
4091
|
+
return { hash: fullHash, shortHash, subject, author, date };
|
|
4092
|
+
});
|
|
4093
|
+
diff = getMultipleCommitsDiff(hashes);
|
|
4094
|
+
} else if (options.last) {
|
|
4095
|
+
commits = getRecentCommits3(options.last);
|
|
4096
|
+
diff = getMultipleCommitsDiff(commits.map((c) => c.hash));
|
|
4097
|
+
} else if (options.staged) {
|
|
4098
|
+
diff = getStagedDiff();
|
|
4099
|
+
} else {
|
|
4100
|
+
const recentCommits = getRecentCommits3(20);
|
|
4101
|
+
const stagedDiff = getStagedDiff();
|
|
4102
|
+
const choices = [];
|
|
4103
|
+
if (stagedDiff) {
|
|
4104
|
+
choices.push({
|
|
4105
|
+
name: `\u{1F4E6} \u6682\u5B58\u533A\u7684\u66F4\u6539 (staged changes)`,
|
|
4106
|
+
value: "staged"
|
|
4107
|
+
});
|
|
4108
|
+
}
|
|
4109
|
+
choices.push(
|
|
4110
|
+
...recentCommits.map((c) => ({
|
|
4111
|
+
name: `${colors.yellow(c.shortHash)} ${c.subject} ${colors.dim(`- ${c.author} (${c.date})`)}`,
|
|
4112
|
+
value: c.hash
|
|
4113
|
+
}))
|
|
4114
|
+
);
|
|
4115
|
+
if (choices.length === 0) {
|
|
4116
|
+
console.log(colors.yellow("\u26A0\uFE0F \u6CA1\u6709\u53EF\u5BA1\u67E5\u7684\u5185\u5BB9"));
|
|
4117
|
+
return;
|
|
4118
|
+
}
|
|
4119
|
+
divider();
|
|
4120
|
+
const selected = await checkbox2({
|
|
4121
|
+
message: "\u9009\u62E9\u8981\u5BA1\u67E5\u7684\u5185\u5BB9 (\u7A7A\u683C\u9009\u62E9\uFF0C\u56DE\u8F66\u786E\u8BA4):",
|
|
4122
|
+
choices,
|
|
4123
|
+
pageSize: choices.length,
|
|
4124
|
+
// 显示所有选项,不滚动
|
|
4125
|
+
loop: false,
|
|
4126
|
+
// 到达边界时不循环
|
|
4127
|
+
theme
|
|
4128
|
+
});
|
|
4129
|
+
if (selected.length === 0) {
|
|
4130
|
+
console.log(colors.yellow("\u26A0\uFE0F \u672A\u9009\u62E9\u4EFB\u4F55\u5185\u5BB9"));
|
|
4131
|
+
return;
|
|
4132
|
+
}
|
|
4133
|
+
if (selected.includes("staged")) {
|
|
4134
|
+
diff = stagedDiff;
|
|
4135
|
+
} else {
|
|
4136
|
+
commits = recentCommits.filter((c) => selected.includes(c.hash));
|
|
4137
|
+
diff = getMultipleCommitsDiff(selected);
|
|
4138
|
+
}
|
|
4139
|
+
}
|
|
4140
|
+
if (!diff) {
|
|
4141
|
+
console.log(colors.yellow("\u26A0\uFE0F \u6CA1\u6709\u68C0\u6D4B\u5230\u4EE3\u7801\u53D8\u66F4"));
|
|
4142
|
+
return;
|
|
4143
|
+
}
|
|
4144
|
+
const stats = getDiffStats(diff);
|
|
4145
|
+
divider();
|
|
4146
|
+
console.log(colors.cyan("\u{1F4CA} \u53D8\u66F4\u7EDF\u8BA1:"));
|
|
4147
|
+
console.log(colors.dim(` \u6587\u4EF6: ${stats.files} \u4E2A`));
|
|
4148
|
+
console.log(colors.dim(` \u65B0\u589E: +${stats.additions} \u884C`));
|
|
4149
|
+
console.log(colors.dim(` \u5220\u9664: -${stats.deletions} \u884C`));
|
|
4150
|
+
divider();
|
|
4151
|
+
const spinner = ora7("\u{1F916} AI \u6B63\u5728\u5BA1\u67E5\u4EE3\u7801...").start();
|
|
4152
|
+
try {
|
|
4153
|
+
const reviewContent = await callAIReview(diff, commits, config2);
|
|
4154
|
+
spinner.succeed("AI \u5BA1\u67E5\u5B8C\u6210");
|
|
4155
|
+
const reportPath = generateReportFile(
|
|
4156
|
+
reviewContent,
|
|
4157
|
+
commits,
|
|
4158
|
+
stats,
|
|
4159
|
+
options.output
|
|
4160
|
+
);
|
|
4161
|
+
console.log("");
|
|
4162
|
+
console.log(colors.green(`\u2705 \u5BA1\u67E5\u62A5\u544A\u5DF2\u751F\u6210: ${colors.cyan(reportPath)}`));
|
|
4163
|
+
console.log("");
|
|
4164
|
+
const shouldOpen = await select10({
|
|
4165
|
+
message: "\u662F\u5426\u6253\u5F00\u5BA1\u67E5\u62A5\u544A?",
|
|
4166
|
+
choices: [
|
|
4167
|
+
{ name: "\u662F\uFF0C\u5728\u7F16\u8F91\u5668\u4E2D\u6253\u5F00", value: true },
|
|
4168
|
+
{ name: "\u5426\uFF0C\u7A0D\u540E\u67E5\u770B", value: false }
|
|
4169
|
+
],
|
|
4170
|
+
theme
|
|
4171
|
+
});
|
|
4172
|
+
if (shouldOpen) {
|
|
4173
|
+
try {
|
|
4174
|
+
const { exec: exec2 } = await import("child_process");
|
|
4175
|
+
exec2(`open "${reportPath}"`);
|
|
4176
|
+
} catch {
|
|
4177
|
+
console.log(colors.dim(` \u8BF7\u624B\u52A8\u6253\u5F00: ${reportPath}`));
|
|
4178
|
+
}
|
|
4179
|
+
}
|
|
4180
|
+
} catch (error) {
|
|
4181
|
+
spinner.fail("AI \u5BA1\u67E5\u5931\u8D25");
|
|
4182
|
+
console.log("");
|
|
4183
|
+
console.log(colors.red(`\u274C ${error.message}`));
|
|
4184
|
+
console.log("");
|
|
4185
|
+
}
|
|
4186
|
+
}
|
|
4187
|
+
|
|
3605
4188
|
// src/index.ts
|
|
3606
4189
|
process.on("uncaughtException", (err) => {
|
|
3607
4190
|
if (err instanceof ExitPromptError) {
|
|
@@ -3627,7 +4210,7 @@ process.on("SIGTERM", () => {
|
|
|
3627
4210
|
console.log("");
|
|
3628
4211
|
process.exit(0);
|
|
3629
4212
|
});
|
|
3630
|
-
var version = true ? "0.
|
|
4213
|
+
var version = true ? "0.5.0" : "0.0.0-dev";
|
|
3631
4214
|
async function mainMenu() {
|
|
3632
4215
|
console.log(
|
|
3633
4216
|
colors.green(`
|
|
@@ -3641,7 +4224,7 @@ async function mainMenu() {
|
|
|
3641
4224
|
);
|
|
3642
4225
|
console.log(colors.dim(` git-workflow v${colors.yellow(version)}
|
|
3643
4226
|
`));
|
|
3644
|
-
const action = await
|
|
4227
|
+
const action = await select11({
|
|
3645
4228
|
message: "\u9009\u62E9\u64CD\u4F5C:",
|
|
3646
4229
|
choices: [
|
|
3647
4230
|
{
|
|
@@ -3697,7 +4280,11 @@ async function mainMenu() {
|
|
|
3697
4280
|
value: "amend"
|
|
3698
4281
|
},
|
|
3699
4282
|
{
|
|
3700
|
-
name: `[e] \
|
|
4283
|
+
name: `[e] \u{1F50D} AI \u4EE3\u7801\u5BA1\u67E5 ${colors.dim("gw review")}`,
|
|
4284
|
+
value: "review"
|
|
4285
|
+
},
|
|
4286
|
+
{
|
|
4287
|
+
name: `[f] \u2699\uFE0F \u521D\u59CB\u5316\u914D\u7F6E ${colors.dim("gw init")}`,
|
|
3701
4288
|
value: "init"
|
|
3702
4289
|
},
|
|
3703
4290
|
{ name: "[0] \u2753 \u5E2E\u52A9", value: "help" },
|
|
@@ -3758,6 +4345,10 @@ async function mainMenu() {
|
|
|
3758
4345
|
checkGitRepo();
|
|
3759
4346
|
await amend();
|
|
3760
4347
|
break;
|
|
4348
|
+
case "review":
|
|
4349
|
+
checkGitRepo();
|
|
4350
|
+
await review();
|
|
4351
|
+
break;
|
|
3761
4352
|
case "init":
|
|
3762
4353
|
await init();
|
|
3763
4354
|
break;
|
|
@@ -3851,18 +4442,30 @@ cli.command("amend [hash]", "\u4FEE\u6539\u6307\u5B9A commit \u7684\u63D0\u4EA4\
|
|
|
3851
4442
|
checkGitRepo();
|
|
3852
4443
|
return amend(hash);
|
|
3853
4444
|
});
|
|
4445
|
+
cli.command("review [...hashes]", "AI \u4EE3\u7801\u5BA1\u67E5").alias("rw").option("-n, --last <number>", "\u5BA1\u67E5\u6700\u8FD1 N \u4E2A commits").option("-s, --staged", "\u5BA1\u67E5\u6682\u5B58\u533A\u7684\u66F4\u6539").option("-o, --output <path>", "\u6307\u5B9A\u8F93\u51FA\u6587\u4EF6\u8DEF\u5F84").action(async (hashes, options) => {
|
|
4446
|
+
await checkForUpdates(version, "@zjex/git-workflow");
|
|
4447
|
+
checkGitRepo();
|
|
4448
|
+
return review(
|
|
4449
|
+
hashes.length > 0 ? hashes : void 0,
|
|
4450
|
+
{
|
|
4451
|
+
last: options.last ? parseInt(options.last) : void 0,
|
|
4452
|
+
staged: options.staged,
|
|
4453
|
+
output: options.output
|
|
4454
|
+
}
|
|
4455
|
+
);
|
|
4456
|
+
});
|
|
3854
4457
|
cli.command("clean", "\u6E05\u7406\u7F13\u5B58\u548C\u4E34\u65F6\u6587\u4EF6").alias("cc").action(async () => {
|
|
3855
4458
|
const { clearUpdateCache: clearUpdateCache3 } = await Promise.resolve().then(() => (init_update_notifier(), update_notifier_exports));
|
|
3856
|
-
const { existsSync:
|
|
4459
|
+
const { existsSync: existsSync6, unlinkSync: unlinkSync4, readdirSync } = await import("fs");
|
|
3857
4460
|
const { homedir: homedir5, tmpdir: tmpdir2 } = await import("os");
|
|
3858
|
-
const { join:
|
|
3859
|
-
const { select:
|
|
4461
|
+
const { join: join7 } = await import("path");
|
|
4462
|
+
const { select: select12 } = await import("@inquirer/prompts");
|
|
3860
4463
|
let cleanedCount = 0;
|
|
3861
4464
|
let deletedGlobalConfig = false;
|
|
3862
|
-
const globalConfig =
|
|
3863
|
-
const hasGlobalConfig =
|
|
4465
|
+
const globalConfig = join7(homedir5(), ".gwrc.json");
|
|
4466
|
+
const hasGlobalConfig = existsSync6(globalConfig);
|
|
3864
4467
|
if (hasGlobalConfig) {
|
|
3865
|
-
const shouldDeleteConfig = await
|
|
4468
|
+
const shouldDeleteConfig = await select12({
|
|
3866
4469
|
message: "\u68C0\u6D4B\u5230\u5168\u5C40\u914D\u7F6E\u6587\u4EF6\uFF0C\u662F\u5426\u5220\u9664\uFF1F",
|
|
3867
4470
|
choices: [
|
|
3868
4471
|
{ name: "\u5426\uFF0C\u4FDD\u7559\u914D\u7F6E\u6587\u4EF6", value: false },
|
|
@@ -3887,7 +4490,7 @@ cli.command("clean", "\u6E05\u7406\u7F13\u5B58\u548C\u4E34\u65F6\u6587\u4EF6").a
|
|
|
3887
4490
|
const gwTmpFiles = files.filter((f) => f.startsWith(".gw-commit-msg-"));
|
|
3888
4491
|
for (const file of gwTmpFiles) {
|
|
3889
4492
|
try {
|
|
3890
|
-
unlinkSync4(
|
|
4493
|
+
unlinkSync4(join7(tmpDir, file));
|
|
3891
4494
|
cleanedCount++;
|
|
3892
4495
|
} catch {
|
|
3893
4496
|
}
|