@zjex/git-workflow 0.2.24 → 0.3.2

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.
Files changed (99) hide show
  1. package/.github/workflows/deploy-docs.yml +68 -0
  2. package/.github/workflows/test.yml +24 -4
  3. package/.husky/pre-commit +17 -0
  4. package/README.md +72 -1066
  5. package/ROADMAP.md +275 -0
  6. package/dist/index.js +450 -99
  7. package/docs/.vitepress/cache/deps/_metadata.json +52 -0
  8. package/docs/.vitepress/cache/deps/chunk-2CLQ7TTZ.js +9719 -0
  9. package/docs/.vitepress/cache/deps/chunk-2CLQ7TTZ.js.map +7 -0
  10. package/docs/.vitepress/cache/deps/chunk-LE5NDSFD.js +12824 -0
  11. package/docs/.vitepress/cache/deps/chunk-LE5NDSFD.js.map +7 -0
  12. package/docs/.vitepress/cache/deps/package.json +3 -0
  13. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4505 -0
  14. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  15. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +583 -0
  16. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  17. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1352 -0
  18. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  19. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1665 -0
  20. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  21. package/docs/.vitepress/cache/deps/vitepress___minisearch.js +1813 -0
  22. package/docs/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
  23. package/docs/.vitepress/cache/deps/vue.js +347 -0
  24. package/docs/.vitepress/cache/deps/vue.js.map +7 -0
  25. package/docs/.vitepress/cache/deps_temp_44e2fb0f/chunk-2CLQ7TTZ.js +9719 -0
  26. package/docs/.vitepress/cache/deps_temp_44e2fb0f/chunk-2CLQ7TTZ.js.map +7 -0
  27. package/docs/.vitepress/cache/deps_temp_44e2fb0f/chunk-LE5NDSFD.js +12824 -0
  28. package/docs/.vitepress/cache/deps_temp_44e2fb0f/chunk-LE5NDSFD.js.map +7 -0
  29. package/docs/.vitepress/cache/deps_temp_44e2fb0f/package.json +3 -0
  30. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vue_devtools-api.js +4505 -0
  31. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vue_devtools-api.js.map +7 -0
  32. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vueuse_core.js +583 -0
  33. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vueuse_core.js.map +7 -0
  34. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vueuse_integrations_useFocusTrap.js +1352 -0
  35. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  36. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___mark__js_src_vanilla__js.js +1665 -0
  37. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  38. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___minisearch.js +1813 -0
  39. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___minisearch.js.map +7 -0
  40. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vue.js +347 -0
  41. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vue.js.map +7 -0
  42. package/docs/.vitepress/config.ts +167 -0
  43. package/docs/.vitepress/theme/custom.css +39 -0
  44. package/docs/.vitepress/theme/index.ts +4 -0
  45. package/docs/README.md +82 -0
  46. package/docs/commands/branch.md +468 -0
  47. package/docs/commands/commit.md +554 -0
  48. package/docs/commands/config.md +346 -0
  49. package/docs/commands/index.md +312 -0
  50. package/docs/commands/interactive.md +384 -0
  51. package/docs/commands/release.md +300 -0
  52. package/docs/commands/stash.md +309 -0
  53. package/docs/commands/tag.md +278 -0
  54. package/docs/commands/update.md +347 -0
  55. package/docs/config/ai-config.md +160 -0
  56. package/docs/config/branch-config.md +133 -0
  57. package/docs/config/commit-config.md +185 -0
  58. package/docs/config/config-file.md +776 -0
  59. package/docs/config/examples.md +279 -0
  60. package/docs/config/index.md +478 -0
  61. package/docs/features/git-wrapped.md +199 -0
  62. package/docs/guide/ai-commit.md +576 -0
  63. package/docs/guide/basic-usage.md +522 -0
  64. package/docs/guide/best-practices.md +426 -0
  65. package/docs/guide/branch-management.md +712 -0
  66. package/docs/guide/getting-started.md +294 -0
  67. package/docs/guide/index.md +168 -0
  68. package/docs/guide/installation.md +449 -0
  69. package/docs/guide/release-management.md +744 -0
  70. package/docs/guide/stash-management.md +608 -0
  71. package/docs/guide/tag-management.md +614 -0
  72. package/docs/index.md +205 -0
  73. package/docs/public/favicon.svg +21 -0
  74. package/docs/public/hero-logo.svg +43 -0
  75. package/docs/public/logo.svg +20 -0
  76. package/package.json +12 -2
  77. package/scripts/publish.js +55 -8
  78. package/scripts/publish.sh +20 -2
  79. package/scripts/release.sh +81 -3
  80. package/scripts/update-test-count.js +55 -0
  81. package/src/ai-service.ts +107 -15
  82. package/src/commands/commit.ts +4 -0
  83. package/src/commands/init.ts +18 -0
  84. package/src/commands/log.ts +503 -0
  85. package/src/config.ts +1 -0
  86. package/src/index.ts +37 -13
  87. package/src/utils.ts +10 -0
  88. package/tests/ai-service.test.ts +237 -2
  89. package/tests/init.test.ts +582 -0
  90. package/tests/log.test.ts +106 -0
  91. package/tests/release.test.ts +333 -0
  92. package/tests/setup.ts +21 -0
  93. package/tests/stash.test.ts +376 -0
  94. package/tests/update.test.ts +402 -0
  95. package/vitest.config.ts +3 -0
  96. package/zjex-logo.svg +22 -0
  97. package/zjex-optimized.svg +34 -0
  98. package/zjex.svg +1 -0
  99. package/src/commands/help.ts +0 -76
package/src/ai-service.ts CHANGED
@@ -60,11 +60,66 @@ function getGitDiff(): string {
60
60
  /**
61
61
  * 构建 AI prompt
62
62
  */
63
- function buildPrompt(diff: string, language: string): string {
63
+ function buildPrompt(diff: string, language: string, detailedDescription: boolean = false): string {
64
64
  const isZh = language === "zh-CN";
65
65
 
66
- const systemPrompt = isZh
67
- ? `你是一个专业的 Git commit message 生成助手。请根据提供的 git diff 生成符合 Conventional Commits 规范的 commit message。
66
+ if (detailedDescription) {
67
+ // 详细模式:生成包含修改点的完整 commit message
68
+ const systemPrompt = isZh
69
+ ? `你是一个专业的 Git commit message 生成助手。请根据提供的 git diff 生成符合 Conventional Commits 规范的详细 commit message。
70
+
71
+ 格式要求:
72
+ 1. 第一行:<type>(<scope>): <subject>
73
+ 2. 空行
74
+ 3. 详细描述:列出主要修改点,每个修改点一行,以 "- " 开头
75
+
76
+ 规则:
77
+ - type 必须是以下之一:feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
78
+ - scope 是可选的,表示影响范围
79
+ - subject 用中文描述,简洁明了,不超过 50 字
80
+ - 详细描述要列出 3-6 个主要修改点,每个修改点简洁明了
81
+ - 如果修改较少,可以只列出 2-3 个修改点
82
+ - 不要有其他解释或多余内容
83
+
84
+ 示例:
85
+ feat(auth): 添加用户登录功能
86
+
87
+ - 实现用户名密码登录接口
88
+ - 添加登录状态验证中间件
89
+ - 完善登录错误处理逻辑
90
+ - 更新用户认证相关文档`
91
+ : `You are a professional Git commit message generator. Generate a detailed commit message following Conventional Commits specification based on the provided git diff.
92
+
93
+ Format requirements:
94
+ 1. First line: <type>(<scope>): <subject>
95
+ 2. Empty line
96
+ 3. Detailed description: List main changes, one per line, starting with "- "
97
+
98
+ Rules:
99
+ - type must be one of: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
100
+ - scope is optional, indicates the affected area
101
+ - subject should be concise, no more than 50 characters
102
+ - Detailed description should list 3-6 main changes, each change should be concise
103
+ - If changes are minimal, list 2-3 changes
104
+ - No explanations or extra content
105
+
106
+ Example:
107
+ feat(auth): add user login functionality
108
+
109
+ - Implement username/password login API
110
+ - Add login status validation middleware
111
+ - Improve login error handling logic
112
+ - Update user authentication documentation`;
113
+
114
+ const userPrompt = isZh
115
+ ? `请根据以下 git diff 生成详细的 commit message(包含修改点列表):\n\n${diff}`
116
+ : `Generate a detailed commit message (including change list) based on the following git diff:\n\n${diff}`;
117
+
118
+ return `${systemPrompt}\n\n${userPrompt}`;
119
+ } else {
120
+ // 简洁模式:只生成标题
121
+ const systemPrompt = isZh
122
+ ? `你是一个专业的 Git commit message 生成助手。请根据提供的 git diff 生成符合 Conventional Commits 规范的 commit message。
68
123
 
69
124
  规则:
70
125
  1. 格式:<type>(<scope>): <subject>
@@ -78,7 +133,7 @@ function buildPrompt(diff: string, language: string): string {
78
133
  - feat(auth): 添加用户登录功能
79
134
  - fix(api): 修复数据获取失败的问题
80
135
  - docs(readme): 更新安装说明`
81
- : `You are a professional Git commit message generator. Generate a commit message following Conventional Commits specification based on the provided git diff.
136
+ : `You are a professional Git commit message generator. Generate a commit message following Conventional Commits specification based on the provided git diff.
82
137
 
83
138
  Rules:
84
139
  1. Format: <type>(<scope>): <subject>
@@ -93,11 +148,12 @@ Examples:
93
148
  - fix(api): resolve data fetching failure
94
149
  - docs(readme): update installation guide`;
95
150
 
96
- const userPrompt = isZh
97
- ? `请根据以下 git diff 生成 commit message:\n\n${diff}`
98
- : `Generate a commit message based on the following git diff:\n\n${diff}`;
151
+ const userPrompt = isZh
152
+ ? `请根据以下 git diff 生成 commit message:\n\n${diff}`
153
+ : `Generate a commit message based on the following git diff:\n\n${diff}`;
99
154
 
100
- return `${systemPrompt}\n\n${userPrompt}`;
155
+ return `${systemPrompt}\n\n${userPrompt}`;
156
+ }
101
157
  }
102
158
 
103
159
  /**
@@ -233,6 +289,33 @@ async function callOllamaAPI(
233
289
  }
234
290
  }
235
291
 
292
+ /**
293
+ * 清理AI生成的commit message
294
+ * 移除重复行、多余的空行和开头的特殊字符
295
+ */
296
+ function cleanAIResponse(response: string): string {
297
+ // 移除开头的特殊字符(如 ...、```、等)
298
+ let cleaned = response.replace(/^[.\s`~-]+/, '').trim();
299
+
300
+ // 移除结尾的特殊字符
301
+ cleaned = cleaned.replace(/[.\s`~-]+$/, '').trim();
302
+
303
+ const lines = cleaned.split('\n').map(line => line.trim()).filter(line => line);
304
+
305
+ // 移除重复的行
306
+ const uniqueLines = [];
307
+ const seen = new Set();
308
+
309
+ for (const line of lines) {
310
+ if (!seen.has(line)) {
311
+ seen.add(line);
312
+ uniqueLines.push(line);
313
+ }
314
+ }
315
+
316
+ return uniqueLines.join('\n');
317
+ }
318
+
236
319
  /**
237
320
  * 生成 AI commit message
238
321
  */
@@ -242,7 +325,8 @@ export async function generateAICommitMessage(
242
325
  const aiConfig = config.aiCommit || {};
243
326
  const provider = aiConfig.provider || "github";
244
327
  const language = aiConfig.language || "zh-CN";
245
- const maxTokens = aiConfig.maxTokens || 200;
328
+ const detailedDescription = aiConfig.detailedDescription !== false; // 默认启用详细描述
329
+ const maxTokens = aiConfig.maxTokens || (detailedDescription ? 400 : 200);
246
330
 
247
331
  // 获取 git diff
248
332
  const diff = getGitDiff();
@@ -251,12 +335,12 @@ export async function generateAICommitMessage(
251
335
  }
252
336
 
253
337
  // 限制 diff 长度,避免超过 token 限制
254
- const maxDiffLength = 4000;
338
+ const maxDiffLength = detailedDescription ? 6000 : 4000;
255
339
  const truncatedDiff =
256
340
  diff.length > maxDiffLength ? diff.slice(0, maxDiffLength) + "\n..." : diff;
257
341
 
258
342
  // 构建 prompt
259
- const prompt = buildPrompt(truncatedDiff, language);
343
+ const prompt = buildPrompt(truncatedDiff, language, detailedDescription);
260
344
 
261
345
  // 根据提供商调用对应的 API
262
346
  const providerInfo = AI_PROVIDERS[provider];
@@ -276,18 +360,26 @@ export async function generateAICommitMessage(
276
360
  }
277
361
 
278
362
  // 调用 API
363
+ let response: string;
279
364
  switch (provider) {
280
365
  case "github":
281
- return await callGitHubAPI(prompt, apiKey, model, maxTokens);
366
+ response = await callGitHubAPI(prompt, apiKey, model, maxTokens);
367
+ break;
282
368
  case "openai":
283
- return await callOpenAIAPI(prompt, apiKey, model, maxTokens);
369
+ response = await callOpenAIAPI(prompt, apiKey, model, maxTokens);
370
+ break;
284
371
  case "claude":
285
- return await callClaudeAPI(prompt, apiKey, model, maxTokens);
372
+ response = await callClaudeAPI(prompt, apiKey, model, maxTokens);
373
+ break;
286
374
  case "ollama":
287
- return await callOllamaAPI(prompt, model, maxTokens);
375
+ response = await callOllamaAPI(prompt, model, maxTokens);
376
+ break;
288
377
  default:
289
378
  throw new Error(`不支持的 AI 提供商: ${provider}`);
290
379
  }
380
+
381
+ // 清理AI响应,移除重复内容
382
+ return cleanAIResponse(response);
291
383
  }
292
384
 
293
385
  /**
@@ -285,6 +285,7 @@ export async function commit(): Promise<void> {
285
285
  // 显示提交信息
286
286
  const commitHash = execOutput("git rev-parse --short HEAD");
287
287
  console.log(colors.dim(`commit: ${commitHash}`));
288
+ console.log("");
288
289
  } catch (error) {
289
290
  spinner.fail("提交失败");
290
291
  console.log("");
@@ -299,6 +300,9 @@ export async function commit(): Promise<void> {
299
300
  console.log(colors.yellow("你可以手动执行以下命令:"));
300
301
  console.log(colors.cyan(` git commit -m "${message}"`));
301
302
  console.log("");
303
+
304
+ // 重新抛出错误,让调用者知道提交失败了
305
+ throw error;
302
306
  }
303
307
  }
304
308
 
@@ -266,11 +266,29 @@ export async function init(): Promise<void> {
266
266
  theme,
267
267
  });
268
268
 
269
+ const detailedDescription = await select({
270
+ message: "是否生成详细的修改点描述?",
271
+ choices: [
272
+ {
273
+ name: "是(包含修改点列表,推荐)",
274
+ value: true,
275
+ description: "如:feat(auth): 添加用户登录功能\n\n- 实现用户名密码登录接口\n- 添加登录状态验证中间件"
276
+ },
277
+ {
278
+ name: "否(仅生成标题)",
279
+ value: false,
280
+ description: "如:feat(auth): 添加用户登录功能"
281
+ },
282
+ ],
283
+ theme,
284
+ });
285
+
269
286
  config.aiCommit = {
270
287
  enabled: true,
271
288
  provider: aiProvider as "github" | "openai" | "claude" | "ollama",
272
289
  apiKey: apiKey || undefined,
273
290
  language: language as "zh-CN" | "en-US",
291
+ detailedDescription,
274
292
  };
275
293
 
276
294
  // 根据提供商设置默认模型