@zjex/git-workflow 0.3.5 → 0.3.7

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/index.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env -S node --no-warnings=ExperimentalWarning
1
+ #!/usr/bin/env -S node --disable-warning=ExperimentalWarning
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
4
  var __esm = (fn, res) => function __init() {
@@ -67,6 +67,8 @@ var init_utils = __esm({
67
67
  orange: (s) => `\x1B[38;5;208m${s}\x1B[0m`,
68
68
  lightPurple: (s) => `\x1B[38;5;141m${s}\x1B[0m`,
69
69
  white: (s) => `\x1B[37m${s}\x1B[0m`,
70
+ brightYellow: (s) => `\x1B[93m${s}\x1B[0m`,
71
+ // 亮黄色
70
72
  reset: "\x1B[0m"
71
73
  };
72
74
  TODAY = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10).replace(/-/g, "");
@@ -266,7 +268,7 @@ async function performUpdate(packageName) {
266
268
  borderStyle: "round",
267
269
  borderColor: "green",
268
270
  align: "left",
269
- width: 50
271
+ width: 40
270
272
  }
271
273
  )
272
274
  );
@@ -2561,7 +2563,7 @@ async function update(currentVersion) {
2561
2563
  borderStyle: "round",
2562
2564
  borderColor: "green",
2563
2565
  align: "left",
2564
- width: 50
2566
+ width: 40
2565
2567
  }
2566
2568
  )
2567
2569
  );
@@ -2602,57 +2604,49 @@ function parseGitLog(output) {
2602
2604
  }
2603
2605
  return commits;
2604
2606
  }
2605
- function getCommitTypeIcon(subject) {
2606
- const lowerSubject = subject.toLowerCase();
2607
- if (lowerSubject.includes("feat") || lowerSubject.includes("feature")) return "\u2728";
2608
- if (lowerSubject.includes("fix") || lowerSubject.includes("bug")) return "\u{1F41B}";
2609
- if (lowerSubject.includes("docs") || lowerSubject.includes("doc")) return "\u{1F4DA}";
2610
- if (lowerSubject.includes("style")) return "\u{1F484}";
2611
- if (lowerSubject.includes("refactor")) return "\u267B\uFE0F";
2612
- if (lowerSubject.includes("test")) return "\u{1F9EA}";
2613
- if (lowerSubject.includes("chore")) return "\u{1F527}";
2614
- if (lowerSubject.includes("perf")) return "\u26A1";
2615
- if (lowerSubject.includes("ci")) return "\u{1F477}";
2616
- if (lowerSubject.includes("build")) return "\u{1F4E6}";
2617
- if (lowerSubject.includes("revert")) return "\u23EA";
2618
- if (lowerSubject.includes("merge")) return "\u{1F500}";
2619
- if (lowerSubject.includes("release") || lowerSubject.includes("version")) return "\u{1F516}";
2620
- return "\u{1F4DD}";
2621
- }
2622
2607
  function groupCommitsByDate(commits) {
2623
2608
  const groups = /* @__PURE__ */ new Map();
2609
+ const dateOrder = [];
2624
2610
  for (const commit2 of commits) {
2625
2611
  const date = commit2.date;
2626
2612
  if (!groups.has(date)) {
2627
2613
  groups.set(date, []);
2614
+ dateOrder.push(date);
2628
2615
  }
2629
2616
  groups.get(date).push(commit2);
2630
2617
  }
2631
- return groups;
2618
+ const orderedGroups = /* @__PURE__ */ new Map();
2619
+ for (const date of dateOrder) {
2620
+ orderedGroups.set(date, groups.get(date));
2621
+ }
2622
+ return orderedGroups;
2632
2623
  }
2633
2624
  function formatRelativeTime(relativeDate) {
2634
2625
  let result = relativeDate;
2635
2626
  const timeMap = {
2636
- "second": "\u79D2",
2637
- "seconds": "\u79D2",
2638
- "minute": "\u5206\u949F",
2639
- "minutes": "\u5206\u949F",
2640
- "hour": "\u5C0F\u65F6",
2641
- "hours": "\u5C0F\u65F6",
2642
- "day": "\u5929",
2643
- "days": "\u5929",
2644
- "week": "\u5468",
2645
- "weeks": "\u5468",
2646
- "month": "\u4E2A\u6708",
2647
- "months": "\u4E2A\u6708",
2648
- "year": "\u5E74",
2649
- "years": "\u5E74",
2650
- "ago": "\u524D"
2627
+ second: "\u79D2",
2628
+ seconds: "\u79D2",
2629
+ minute: "\u5206\u949F",
2630
+ minutes: "\u5206\u949F",
2631
+ hour: "\u5C0F\u65F6",
2632
+ hours: "\u5C0F\u65F6",
2633
+ day: "\u5929",
2634
+ days: "\u5929",
2635
+ week: "\u5468",
2636
+ weeks: "\u5468",
2637
+ month: "\u4E2A\u6708",
2638
+ months: "\u4E2A\u6708",
2639
+ year: "\u5E74",
2640
+ years: "\u5E74",
2641
+ ago: "\u524D"
2651
2642
  };
2652
2643
  for (const [en, zh] of Object.entries(timeMap)) {
2653
2644
  result = result.replace(new RegExp(`\\b${en}\\b`, "g"), zh);
2654
2645
  }
2655
- result = result.replace(/(\d+)\s+(秒|分钟|小时|天|周|个月|年)\s+前/g, "$1$2\u524D");
2646
+ result = result.replace(
2647
+ /(\d+)\s+(秒|分钟|小时|天|周|个月|年)\s+前/g,
2648
+ "$1$2\u524D"
2649
+ );
2656
2650
  const match = result.match(/(\d+)(分钟|小时|天|周|个月|年)前/);
2657
2651
  if (match) {
2658
2652
  const num = parseInt(match[1]);
@@ -2699,28 +2693,25 @@ function supportsColor() {
2699
2693
  function formatTimelineStyle(commits) {
2700
2694
  const groupedCommits = groupCommitsByDate(commits);
2701
2695
  let output = "";
2702
- const sortedDates = Array.from(groupedCommits.keys()).sort(
2703
- (a, b) => new Date(b).getTime() - new Date(a).getTime()
2704
- );
2696
+ const sortedDates = Array.from(groupedCommits.keys());
2705
2697
  const useColors = supportsColor() || process.env.FORCE_COLOR;
2706
2698
  for (let dateIndex = 0; dateIndex < sortedDates.length; dateIndex++) {
2707
2699
  const date = sortedDates[dateIndex];
2708
2700
  const dateCommits = groupedCommits.get(date);
2709
2701
  const dateTitle = `\u{1F4C5} Commits on ${date}`;
2710
2702
  if (useColors) {
2711
- output += "\n" + colors.bold(colors.yellow(dateTitle)) + "\n\n";
2703
+ output += colors.bold(colors.yellow(dateTitle)) + "\n";
2712
2704
  } else {
2713
- output += "\n" + dateTitle + "\n\n";
2705
+ output += dateTitle + "\n";
2714
2706
  }
2715
2707
  for (let commitIndex = 0; commitIndex < dateCommits.length; commitIndex++) {
2716
2708
  const commit2 = dateCommits[commitIndex];
2717
- const icon = getCommitTypeIcon(commit2.subject);
2718
2709
  const { title, tasks } = parseCommitSubject(commit2.subject);
2719
2710
  const commitContent = [];
2720
2711
  if (useColors) {
2721
- commitContent.push(`${icon} ${colors.bold(colors.white(title))}`);
2712
+ commitContent.push(colors.bold(colors.white(title)));
2722
2713
  } else {
2723
- commitContent.push(`${icon} ${title}`);
2714
+ commitContent.push(title);
2724
2715
  }
2725
2716
  if (tasks.length > 0) {
2726
2717
  commitContent.push("");
@@ -2734,8 +2725,12 @@ function formatTimelineStyle(commits) {
2734
2725
  }
2735
2726
  commitContent.push("");
2736
2727
  if (useColors) {
2737
- commitContent.push(`${colors.dim("\u{1F464}")} ${colors.blue(commit2.author)} ${colors.dim("committed")} ${colors.green(formatRelativeTime(commit2.relativeDate))}`);
2738
- commitContent.push(`${colors.dim("\u{1F517}")} ${colors.orange("#" + commit2.shortHash)}`);
2728
+ commitContent.push(
2729
+ `${colors.dim("\u{1F464}")} ${colors.blue(commit2.author)} ${colors.dim(
2730
+ "committed"
2731
+ )} ${colors.green(formatRelativeTime(commit2.relativeDate))}`
2732
+ );
2733
+ commitContent.push(`${colors.dim("\u{1F517}")} ${colors.orange(commit2.hash)}`);
2739
2734
  if (commit2.refs && commit2.refs.trim()) {
2740
2735
  const refs = commit2.refs.trim();
2741
2736
  const refParts = refs.split(", ");
@@ -2751,16 +2746,24 @@ function formatTimelineStyle(commits) {
2751
2746
  }
2752
2747
  });
2753
2748
  if (branches.length > 0) {
2754
- commitContent.push(`${colors.dim("\u{1F33F}")} ${colors.lightPurple(branches.join(", "))}`);
2749
+ commitContent.push(
2750
+ `${colors.dim("\u{1F33F}")} ${colors.lightPurple(branches.join(", "))}`
2751
+ );
2755
2752
  }
2756
2753
  if (tags.length > 0) {
2757
2754
  const tagText = tags.map((tag) => `tag ${tag}`).join(", ");
2758
- commitContent.push(`${colors.dim("\u{1F516}")} ${colors.yellow(tagText)}`);
2755
+ commitContent.push(
2756
+ `${colors.dim("\u{1F516}")} ${colors.brightYellow(tagText)}`
2757
+ );
2759
2758
  }
2760
2759
  }
2761
2760
  } else {
2762
- commitContent.push(`\u{1F464} ${commit2.author} committed ${formatRelativeTime(commit2.relativeDate)}`);
2763
- commitContent.push(`\u{1F517} #${commit2.shortHash}`);
2761
+ commitContent.push(
2762
+ `\u{1F464} ${commit2.author} committed ${formatRelativeTime(
2763
+ commit2.relativeDate
2764
+ )}`
2765
+ );
2766
+ commitContent.push(`\u{1F517} ${commit2.hash}`);
2764
2767
  if (commit2.refs && commit2.refs.trim()) {
2765
2768
  const refs = commit2.refs.trim();
2766
2769
  const refParts = refs.split(", ");
@@ -2786,7 +2789,7 @@ function formatTimelineStyle(commits) {
2786
2789
  }
2787
2790
  const commitBox = boxen3(commitContent.join("\n"), {
2788
2791
  padding: { top: 0, bottom: 0, left: 1, right: 1 },
2789
- margin: { top: 0, bottom: 1, left: 0, right: 0 },
2792
+ margin: { top: 0, bottom: 0, left: 0, right: 0 },
2790
2793
  borderStyle: "round",
2791
2794
  borderColor: "gray"
2792
2795
  });
@@ -2802,11 +2805,17 @@ function startInteractivePager(content) {
2802
2805
  stdio: ["pipe", "inherit", "inherit"],
2803
2806
  env: { ...process.env, LESS: "-R -S -F -X -i" }
2804
2807
  });
2808
+ pagerProcess.stdin.on("error", (err) => {
2809
+ if (err.code !== "EPIPE") {
2810
+ console.error(err);
2811
+ }
2812
+ });
2805
2813
  pagerProcess.stdin.write(content);
2806
2814
  pagerProcess.stdin.end();
2807
2815
  pagerProcess.on("exit", () => {
2816
+ process.exit(0);
2808
2817
  });
2809
- pagerProcess.on("error", (err) => {
2818
+ pagerProcess.on("error", () => {
2810
2819
  console.log(content);
2811
2820
  });
2812
2821
  } catch (error) {
@@ -2822,9 +2831,6 @@ function executeTimelineLog(options) {
2822
2831
  if (options.until) cmd += ` --until="${options.until}"`;
2823
2832
  if (options.grep) cmd += ` --grep="${options.grep}"`;
2824
2833
  if (options.all) cmd += ` --all`;
2825
- if (options.interactive && !options.limit) {
2826
- cmd += ` -50`;
2827
- }
2828
2834
  const output = execSync8(cmd, {
2829
2835
  encoding: "utf8",
2830
2836
  stdio: "pipe",
@@ -2833,14 +2839,6 @@ function executeTimelineLog(options) {
2833
2839
  if (output.trim()) {
2834
2840
  const commits = parseGitLog(output);
2835
2841
  let fullOutput = "";
2836
- const title = `\u{1F4CA} \u5171\u663E\u793A ${commits.length} \u4E2A\u63D0\u4EA4`;
2837
- fullOutput += "\n" + boxen3(title, {
2838
- padding: { top: 0, bottom: 0, left: 2, right: 2 },
2839
- margin: { top: 0, bottom: 1, left: 0, right: 0 },
2840
- borderStyle: "double",
2841
- borderColor: "green",
2842
- textAlignment: "center"
2843
- }) + "\n";
2844
2842
  const timelineOutput = formatTimelineStyle(commits);
2845
2843
  fullOutput += timelineOutput;
2846
2844
  if (options.interactive) {
@@ -2916,7 +2914,7 @@ process.on("SIGTERM", () => {
2916
2914
  console.log("");
2917
2915
  process.exit(0);
2918
2916
  });
2919
- var version = true ? "0.3.5" : "0.0.0-dev";
2917
+ var version = true ? "0.3.7" : "0.0.0-dev";
2920
2918
  async function mainMenu() {
2921
2919
  console.log(
2922
2920
  colors.green(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zjex/git-workflow",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "🚀 极简的 Git 工作流 CLI 工具,让分支管理和版本发布变得轻松愉快",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @zjex/git-workflow - Log 命令
3
- *
3
+ *
4
4
  * 提供GitHub风格的时间线日志查看功能
5
5
  */
6
6
 
@@ -43,13 +43,13 @@ interface CommitInfo {
43
43
  */
44
44
  function parseGitLog(output: string): CommitInfo[] {
45
45
  const commits: CommitInfo[] = [];
46
- const lines = output.trim().split('\n');
47
-
46
+ const lines = output.trim().split("\n");
47
+
48
48
  for (const line of lines) {
49
49
  if (!line.trim()) continue;
50
-
50
+
51
51
  // 使用分隔符解析
52
- const parts = line.split('|');
52
+ const parts = line.split("|");
53
53
  if (parts.length >= 6) {
54
54
  commits.push({
55
55
  hash: parts[0],
@@ -58,11 +58,11 @@ function parseGitLog(output: string): CommitInfo[] {
58
58
  author: parts[3],
59
59
  date: parts[4],
60
60
  relativeDate: parts[5],
61
- refs: parts[6] || ''
61
+ refs: parts[6] || "",
62
62
  });
63
63
  }
64
64
  }
65
-
65
+
66
66
  return commits;
67
67
  }
68
68
 
@@ -71,39 +71,50 @@ function parseGitLog(output: string): CommitInfo[] {
71
71
  */
72
72
  function getCommitTypeIcon(subject: string): string {
73
73
  const lowerSubject = subject.toLowerCase();
74
-
75
- if (lowerSubject.includes('feat') || lowerSubject.includes('feature')) return '✨';
76
- if (lowerSubject.includes('fix') || lowerSubject.includes('bug')) return '🐛';
77
- if (lowerSubject.includes('docs') || lowerSubject.includes('doc')) return '📚';
78
- if (lowerSubject.includes('style')) return '💄';
79
- if (lowerSubject.includes('refactor')) return '♻️';
80
- if (lowerSubject.includes('test')) return '🧪';
81
- if (lowerSubject.includes('chore')) return '🔧';
82
- if (lowerSubject.includes('perf')) return '⚡';
83
- if (lowerSubject.includes('ci')) return '👷';
84
- if (lowerSubject.includes('build')) return '📦';
85
- if (lowerSubject.includes('revert')) return '⏪';
86
- if (lowerSubject.includes('merge')) return '🔀';
87
- if (lowerSubject.includes('release') || lowerSubject.includes('version')) return '🔖';
88
-
89
- return '📝';
74
+
75
+ if (lowerSubject.includes("feat") || lowerSubject.includes("feature"))
76
+ return "✨";
77
+ if (lowerSubject.includes("fix") || lowerSubject.includes("bug")) return "🐛";
78
+ if (lowerSubject.includes("docs") || lowerSubject.includes("doc"))
79
+ return "📚";
80
+ if (lowerSubject.includes("style")) return "💄";
81
+ if (lowerSubject.includes("refactor")) return "♻️";
82
+ if (lowerSubject.includes("test")) return "🧪";
83
+ if (lowerSubject.includes("chore")) return "🔧";
84
+ if (lowerSubject.includes("perf")) return "⚡";
85
+ if (lowerSubject.includes("ci")) return "👷";
86
+ if (lowerSubject.includes("build")) return "📦";
87
+ if (lowerSubject.includes("revert")) return "⏪";
88
+ if (lowerSubject.includes("merge")) return "🔀";
89
+ if (lowerSubject.includes("release") || lowerSubject.includes("version"))
90
+ return "🔖";
91
+
92
+ return "📝";
90
93
  }
91
94
 
92
95
  /**
93
- * 按日期分组提交
96
+ * 按日期分组提交(保持原始提交顺序)
94
97
  */
95
98
  function groupCommitsByDate(commits: CommitInfo[]): Map<string, CommitInfo[]> {
96
99
  const groups = new Map<string, CommitInfo[]>();
97
-
100
+ const dateOrder: string[] = []; // 记录日期出现的顺序
101
+
98
102
  for (const commit of commits) {
99
103
  const date = commit.date;
100
104
  if (!groups.has(date)) {
101
105
  groups.set(date, []);
106
+ dateOrder.push(date); // 按出现顺序记录日期
102
107
  }
103
108
  groups.get(date)!.push(commit);
104
109
  }
105
-
106
- return groups;
110
+
111
+ // 返回按出现顺序排列的 Map
112
+ const orderedGroups = new Map<string, CommitInfo[]>();
113
+ for (const date of dateOrder) {
114
+ orderedGroups.set(date, groups.get(date)!);
115
+ }
116
+
117
+ return orderedGroups;
107
118
  }
108
119
 
109
120
  /**
@@ -111,92 +122,101 @@ function groupCommitsByDate(commits: CommitInfo[]): Map<string, CommitInfo[]> {
111
122
  */
112
123
  function formatRelativeTime(relativeDate: string): string {
113
124
  let result = relativeDate;
114
-
125
+
115
126
  // 先替换英文单词为中文
116
127
  const timeMap: { [key: string]: string } = {
117
- 'second': '',
118
- 'seconds': '',
119
- 'minute': '分钟',
120
- 'minutes': '分钟',
121
- 'hour': '小时',
122
- 'hours': '小时',
123
- 'day': '',
124
- 'days': '',
125
- 'week': '',
126
- 'weeks': '',
127
- 'month': '个月',
128
- 'months': '个月',
129
- 'year': '',
130
- 'years': '',
131
- 'ago': ''
128
+ second: "",
129
+ seconds: "",
130
+ minute: "分钟",
131
+ minutes: "分钟",
132
+ hour: "小时",
133
+ hours: "小时",
134
+ day: "",
135
+ days: "",
136
+ week: "",
137
+ weeks: "",
138
+ month: "个月",
139
+ months: "个月",
140
+ year: "",
141
+ years: "",
142
+ ago: "",
132
143
  };
133
-
144
+
134
145
  for (const [en, zh] of Object.entries(timeMap)) {
135
- result = result.replace(new RegExp(`\\b${en}\\b`, 'g'), zh);
146
+ result = result.replace(new RegExp(`\\b${en}\\b`, "g"), zh);
136
147
  }
137
-
148
+
138
149
  // 去掉数字和单位之间的空格,以及单位和"前"之间的空格
139
150
  // 例如:"22 分钟 前" -> "22分钟前"
140
- result = result.replace(/(\d+)\s+(秒|分钟|小时|天|周|个月|年)\s+前/g, '$1$2前');
141
-
151
+ result = result.replace(
152
+ /(\d+)\s+(秒|分钟|小时|天|周|个月|年)\s+前/g,
153
+ "$1$2前"
154
+ );
155
+
142
156
  // 简化显示格式
143
157
  const match = result.match(/(\d+)(分钟|小时|天|周|个月|年)前/);
144
158
  if (match) {
145
159
  const num = parseInt(match[1]);
146
160
  const unit = match[2];
147
-
161
+
148
162
  // 超过60分钟显示小时
149
- if (unit === '分钟' && num >= 60) {
163
+ if (unit === "分钟" && num >= 60) {
150
164
  const hours = Math.floor(num / 60);
151
165
  return `${hours}小时前`;
152
166
  }
153
-
167
+
154
168
  // 超过24小时显示天数
155
- if (unit === '小时' && num >= 24) {
169
+ if (unit === "小时" && num >= 24) {
156
170
  const days = Math.floor(num / 24);
157
171
  return `${days}天前`;
158
172
  }
159
-
173
+
160
174
  // 超过7天显示周数
161
- if (unit === '' && num >= 7 && num < 30) {
175
+ if (unit === "" && num >= 7 && num < 30) {
162
176
  const weeks = Math.floor(num / 7);
163
177
  return `${weeks}周前`;
164
178
  }
165
-
179
+
166
180
  // 超过30天显示月数
167
- if (unit === '' && num >= 30) {
181
+ if (unit === "" && num >= 30) {
168
182
  const months = Math.floor(num / 30);
169
183
  return `${months}个月前`;
170
184
  }
171
-
185
+
172
186
  // 超过4周显示月数
173
- if (unit === '' && num >= 4) {
187
+ if (unit === "" && num >= 4) {
174
188
  const months = Math.floor(num / 4);
175
189
  return `${months}个月前`;
176
190
  }
177
-
191
+
178
192
  // 超过12个月显示年数
179
- if (unit === '个月' && num >= 12) {
193
+ if (unit === "个月" && num >= 12) {
180
194
  const years = Math.floor(num / 12);
181
195
  return `${years}年前`;
182
196
  }
183
197
  }
184
-
198
+
185
199
  return result;
186
200
  }
187
201
 
188
202
  /**
189
203
  * 解析提交主题,分离标题和子任务
190
204
  */
191
- function parseCommitSubject(subject: string): { title: string; tasks: string[] } {
205
+ function parseCommitSubject(subject: string): {
206
+ title: string;
207
+ tasks: string[];
208
+ } {
192
209
  // 检查是否包含 " - " 分隔的子任务
193
- if (subject.includes(' - ')) {
194
- const parts = subject.split(' - ');
210
+ if (subject.includes(" - ")) {
211
+ const parts = subject.split(" - ");
195
212
  const title = parts[0].trim();
196
- const tasks = parts.slice(1).map(task => task.trim()).filter(task => task.length > 0);
213
+ const tasks = parts
214
+ .slice(1)
215
+ .map((task) => task.trim())
216
+ .filter((task) => task.length > 0);
197
217
  return { title, tasks };
198
218
  }
199
-
219
+
200
220
  return { title: subject, tasks: [] };
201
221
  }
202
222
 
@@ -213,137 +233,146 @@ function supportsColor(): boolean {
213
233
  */
214
234
  function formatTimelineStyle(commits: CommitInfo[]): string {
215
235
  const groupedCommits = groupCommitsByDate(commits);
216
- let output = '';
217
-
218
- // 按日期倒序排列
219
- const sortedDates = Array.from(groupedCommits.keys()).sort((a, b) =>
220
- new Date(b).getTime() - new Date(a).getTime()
221
- );
222
-
236
+ let output = "";
237
+
238
+ // 保持原始提交顺序(已在 groupCommitsByDate 中按出现顺序排列)
239
+ const sortedDates = Array.from(groupedCommits.keys());
240
+
223
241
  const useColors = supportsColor() || process.env.FORCE_COLOR;
224
-
242
+
225
243
  for (let dateIndex = 0; dateIndex < sortedDates.length; dateIndex++) {
226
244
  const date = sortedDates[dateIndex];
227
245
  const dateCommits = groupedCommits.get(date)!;
228
-
246
+
229
247
  // 日期标题 - 使用黄色突出显示
230
248
  const dateTitle = `📅 Commits on ${date}`;
231
249
  if (useColors) {
232
- output += '\n' + colors.bold(colors.yellow(dateTitle)) + '\n\n';
250
+ output += colors.bold(colors.yellow(dateTitle)) + "\n";
233
251
  } else {
234
- output += '\n' + dateTitle + '\n\n';
252
+ output += dateTitle + "\n";
235
253
  }
236
-
254
+
237
255
  // 该日期下的提交
238
256
  for (let commitIndex = 0; commitIndex < dateCommits.length; commitIndex++) {
239
257
  const commit = dateCommits[commitIndex];
240
- const icon = getCommitTypeIcon(commit.subject);
241
258
  const { title, tasks } = parseCommitSubject(commit.subject);
242
-
259
+
243
260
  // 构建提交内容
244
261
  const commitContent = [];
245
-
246
- // 主标题 - 使用白色加粗
262
+
263
+ // 主标题 - 使用白色加粗,保持原始提交信息
247
264
  if (useColors) {
248
- commitContent.push(`${icon} ${colors.bold(colors.white(title))}`);
265
+ commitContent.push(colors.bold(colors.white(title)));
249
266
  } else {
250
- commitContent.push(`${icon} ${title}`);
267
+ commitContent.push(title);
251
268
  }
252
-
269
+
253
270
  // 如果有子任务,添加子任务列表
254
271
  if (tasks.length > 0) {
255
- commitContent.push(''); // 空行分隔
256
- tasks.forEach(task => {
272
+ commitContent.push(""); // 空行分隔
273
+ tasks.forEach((task) => {
257
274
  if (useColors) {
258
- commitContent.push(` ${colors.dim('')} ${colors.dim(task)}`);
275
+ commitContent.push(` ${colors.dim("")} ${colors.dim(task)}`);
259
276
  } else {
260
277
  commitContent.push(` – ${task}`);
261
278
  }
262
279
  });
263
280
  }
264
-
281
+
265
282
  // 空行分隔
266
- commitContent.push('');
267
-
283
+ commitContent.push("");
284
+
268
285
  // 作者和时间信息
269
286
  if (useColors) {
270
- commitContent.push(`${colors.dim('👤')} ${colors.blue(commit.author)} ${colors.dim('committed')} ${colors.green(formatRelativeTime(commit.relativeDate))}`);
271
- // Hash信息 - 使用橙色
272
- commitContent.push(`${colors.dim('🔗')} ${colors.orange('#' + commit.shortHash)}`);
287
+ commitContent.push(
288
+ `${colors.dim("👤")} ${colors.blue(commit.author)} ${colors.dim(
289
+ "committed"
290
+ )} ${colors.green(formatRelativeTime(commit.relativeDate))}`
291
+ );
292
+ // Hash信息 - 使用橙色,显示完整 hash
293
+ commitContent.push(`${colors.dim("🔗")} ${colors.orange(commit.hash)}`);
273
294
  // 如果有分支/标签信息 - 区分显示
274
295
  if (commit.refs && commit.refs.trim()) {
275
296
  const refs = commit.refs.trim();
276
297
  // 解析并分别显示分支和标签
277
- const refParts = refs.split(', ');
298
+ const refParts = refs.split(", ");
278
299
  const branches: string[] = [];
279
300
  const tags: string[] = [];
280
-
281
- refParts.forEach(ref => {
282
- if (ref.startsWith('tag: ')) {
283
- tags.push(ref.replace('tag: ', ''));
284
- } else if (ref.includes('/') || ref === 'HEAD') {
301
+
302
+ refParts.forEach((ref) => {
303
+ if (ref.startsWith("tag: ")) {
304
+ tags.push(ref.replace("tag: ", ""));
305
+ } else if (ref.includes("/") || ref === "HEAD") {
285
306
  branches.push(ref);
286
307
  } else {
287
308
  branches.push(ref);
288
309
  }
289
310
  });
290
-
311
+
291
312
  // 显示分支信息
292
313
  if (branches.length > 0) {
293
- commitContent.push(`${colors.dim('🌿')} ${colors.lightPurple(branches.join(', '))}`);
314
+ commitContent.push(
315
+ `${colors.dim("🌿")} ${colors.lightPurple(branches.join(", "))}`
316
+ );
294
317
  }
295
-
318
+
296
319
  // 显示标签信息
297
320
  if (tags.length > 0) {
298
- const tagText = tags.map(tag => `tag ${tag}`).join(', ');
299
- commitContent.push(`${colors.dim('🔖')} ${colors.yellow(tagText)}`);
321
+ const tagText = tags.map((tag) => `tag ${tag}`).join(", ");
322
+ commitContent.push(
323
+ `${colors.dim("🔖")} ${colors.brightYellow(tagText)}`
324
+ );
300
325
  }
301
326
  }
302
327
  } else {
303
- commitContent.push(`👤 ${commit.author} committed ${formatRelativeTime(commit.relativeDate)}`);
304
- commitContent.push(`🔗 #${commit.shortHash}`);
328
+ commitContent.push(
329
+ `👤 ${commit.author} committed ${formatRelativeTime(
330
+ commit.relativeDate
331
+ )}`
332
+ );
333
+ commitContent.push(`🔗 ${commit.hash}`);
305
334
  if (commit.refs && commit.refs.trim()) {
306
335
  const refs = commit.refs.trim();
307
336
  // 解析并分别显示分支和标签
308
- const refParts = refs.split(', ');
337
+ const refParts = refs.split(", ");
309
338
  const branches: string[] = [];
310
339
  const tags: string[] = [];
311
-
312
- refParts.forEach(ref => {
313
- if (ref.startsWith('tag: ')) {
314
- tags.push(ref.replace('tag: ', ''));
315
- } else if (ref.includes('/') || ref === 'HEAD') {
340
+
341
+ refParts.forEach((ref) => {
342
+ if (ref.startsWith("tag: ")) {
343
+ tags.push(ref.replace("tag: ", ""));
344
+ } else if (ref.includes("/") || ref === "HEAD") {
316
345
  branches.push(ref);
317
346
  } else {
318
347
  branches.push(ref);
319
348
  }
320
349
  });
321
-
350
+
322
351
  // 显示分支信息
323
352
  if (branches.length > 0) {
324
- commitContent.push(`🌿 ${branches.join(', ')}`);
353
+ commitContent.push(`🌿 ${branches.join(", ")}`);
325
354
  }
326
-
355
+
327
356
  // 显示标签信息
328
357
  if (tags.length > 0) {
329
- const tagText = tags.map(tag => `tag ${tag}`).join(', ');
358
+ const tagText = tags.map((tag) => `tag ${tag}`).join(", ");
330
359
  commitContent.push(`🔖 ${tagText}`);
331
360
  }
332
361
  }
333
362
  }
334
-
363
+
335
364
  // 使用boxen
336
- const commitBox = boxen(commitContent.join('\n'), {
365
+ const commitBox = boxen(commitContent.join("\n"), {
337
366
  padding: { top: 0, bottom: 0, left: 1, right: 1 },
338
- margin: { top: 0, bottom: 1, left: 0, right: 0 },
339
- borderStyle: 'round',
340
- borderColor: 'gray'
367
+ margin: { top: 0, bottom: 0, left: 0, right: 0 },
368
+ borderStyle: "round",
369
+ borderColor: "gray",
341
370
  });
342
-
343
- output += commitBox + '\n';
371
+
372
+ output += commitBox + "\n";
344
373
  }
345
374
  }
346
-
375
+
347
376
  return output;
348
377
  }
349
378
 
@@ -352,34 +381,42 @@ function formatTimelineStyle(commits: CommitInfo[]): string {
352
381
  */
353
382
  function startInteractivePager(content: string): void {
354
383
  // 使用系统的 less 命令作为分页器,启用颜色支持
355
- const pager = process.env.PAGER || 'less';
356
-
384
+ const pager = process.env.PAGER || "less";
385
+
357
386
  try {
358
387
  // -R: 支持ANSI颜色代码
359
388
  // -S: 不换行长行
360
389
  // -F: 如果内容少于一屏则直接退出
361
390
  // -X: 不清屏
362
391
  // -i: 忽略大小写搜索
363
- const pagerProcess = spawn(pager, ['-R', '-S', '-F', '-X', '-i'], {
364
- stdio: ['pipe', 'inherit', 'inherit'],
365
- env: { ...process.env, LESS: '-R -S -F -X -i' }
392
+ const pagerProcess = spawn(pager, ["-R", "-S", "-F", "-X", "-i"], {
393
+ stdio: ["pipe", "inherit", "inherit"],
394
+ env: { ...process.env, LESS: "-R -S -F -X -i" },
366
395
  });
367
-
396
+
397
+ // 处理 stdin 的 EPIPE 错误(当 less 提前退出时)
398
+ pagerProcess.stdin.on("error", (err: NodeJS.ErrnoException) => {
399
+ if (err.code !== "EPIPE") {
400
+ // 只忽略 EPIPE 错误,其他错误输出
401
+ console.error(err);
402
+ }
403
+ });
404
+
368
405
  // 将内容写入分页器
369
406
  pagerProcess.stdin.write(content);
370
407
  pagerProcess.stdin.end();
371
-
408
+
372
409
  // 处理分页器退出
373
- pagerProcess.on('exit', () => {
374
- // 分页器退出后不需要额外处理
410
+ pagerProcess.on("exit", () => {
411
+ // 分页器退出后正常退出程序
412
+ process.exit(0);
375
413
  });
376
-
414
+
377
415
  // 处理错误
378
- pagerProcess.on('error', (err) => {
416
+ pagerProcess.on("error", () => {
379
417
  // 如果分页器启动失败,直接输出内容
380
418
  console.log(content);
381
419
  });
382
-
383
420
  } catch (error) {
384
421
  // 如果出错,直接输出内容
385
422
  console.log(content);
@@ -393,7 +430,7 @@ function executeTimelineLog(options: LogOptions): void {
393
430
  try {
394
431
  // 构建Git命令
395
432
  let cmd = 'git log --pretty=format:"%H|%h|%s|%an|%ad|%ar|%D" --date=short';
396
-
433
+
397
434
  // 添加选项
398
435
  if (options.limit && !options.interactive) cmd += ` -${options.limit}`;
399
436
  if (options.author) cmd += ` --author="${options.author}"`;
@@ -401,53 +438,41 @@ function executeTimelineLog(options: LogOptions): void {
401
438
  if (options.until) cmd += ` --until="${options.until}"`;
402
439
  if (options.grep) cmd += ` --grep="${options.grep}"`;
403
440
  if (options.all) cmd += ` --all`;
404
-
405
- // 交互式模式默认显示更多提交
406
- if (options.interactive && !options.limit) {
407
- cmd += ` -50`; // 默认显示50个提交
408
- }
409
441
 
410
- const output = execSync(cmd, {
411
- encoding: 'utf8',
412
- stdio: 'pipe',
413
- maxBuffer: 1024 * 1024 * 10
442
+ // 交互式模式默认显示全部提交(不限制数量)
443
+
444
+ const output = execSync(cmd, {
445
+ encoding: "utf8",
446
+ stdio: "pipe",
447
+ maxBuffer: 1024 * 1024 * 10,
414
448
  });
415
449
 
416
450
  if (output.trim()) {
417
451
  const commits = parseGitLog(output);
418
-
452
+
419
453
  // 构建完整输出
420
- let fullOutput = '';
421
-
422
- // 显示标题
423
- const title = `📊 共显示 ${commits.length} 个提交`;
424
- fullOutput += '\n' + boxen(title, {
425
- padding: { top: 0, bottom: 0, left: 2, right: 2 },
426
- margin: { top: 0, bottom: 1, left: 0, right: 0 },
427
- borderStyle: 'double',
428
- borderColor: 'green',
429
- textAlignment: 'center'
430
- }) + '\n';
431
-
454
+ let fullOutput = "";
455
+
432
456
  // 显示时间线
433
457
  const timelineOutput = formatTimelineStyle(commits);
434
458
  fullOutput += timelineOutput;
435
-
459
+
436
460
  // 根据是否交互式模式选择输出方式
437
461
  if (options.interactive) {
438
462
  startInteractivePager(fullOutput);
439
463
  } else {
440
464
  console.log(fullOutput);
441
465
  }
442
-
443
466
  } else {
444
- const noCommitsMsg = '\n' + boxen('📭 没有找到匹配的提交记录', {
445
- padding: { top: 0, bottom: 0, left: 2, right: 2 },
446
- borderStyle: 'round',
447
- borderColor: 'yellow',
448
- textAlignment: 'center'
449
- });
450
-
467
+ const noCommitsMsg =
468
+ "\n" +
469
+ boxen("📭 没有找到匹配的提交记录", {
470
+ padding: { top: 0, bottom: 0, left: 2, right: 2 },
471
+ borderStyle: "round",
472
+ borderColor: "yellow",
473
+ textAlignment: "center",
474
+ });
475
+
451
476
  if (options.interactive) {
452
477
  startInteractivePager(noCommitsMsg);
453
478
  } else {
@@ -455,20 +480,22 @@ function executeTimelineLog(options: LogOptions): void {
455
480
  }
456
481
  }
457
482
  } catch (error: any) {
458
- let errorMessage = '❌ 执行失败';
483
+ let errorMessage = "❌ 执行失败";
459
484
  if (error.status === 128) {
460
- errorMessage = '❌ Git仓库错误或没有提交记录';
485
+ errorMessage = "❌ Git仓库错误或没有提交记录";
461
486
  } else {
462
487
  errorMessage = `❌ 执行失败: ${error.message}`;
463
488
  }
464
-
465
- const errorBox = '\n' + boxen(errorMessage, {
466
- padding: { top: 0, bottom: 0, left: 2, right: 2 },
467
- borderStyle: 'round',
468
- borderColor: 'red',
469
- textAlignment: 'center'
470
- });
471
-
489
+
490
+ const errorBox =
491
+ "\n" +
492
+ boxen(errorMessage, {
493
+ padding: { top: 0, bottom: 0, left: 2, right: 2 },
494
+ borderStyle: "round",
495
+ borderColor: "red",
496
+ textAlignment: "center",
497
+ });
498
+
472
499
  if (options.interactive) {
473
500
  startInteractivePager(errorBox);
474
501
  } else {
@@ -485,12 +512,12 @@ export async function log(options: LogOptions = {}): Promise<void> {
485
512
  if (options.interactive === undefined) {
486
513
  options.interactive = true;
487
514
  }
488
-
515
+
489
516
  // 交互式模式下不设置默认limit
490
517
  if (!options.interactive && !options.limit) {
491
518
  options.limit = 10;
492
519
  }
493
-
520
+
494
521
  executeTimelineLog(options);
495
522
  }
496
523
 
@@ -500,4 +527,4 @@ export async function log(options: LogOptions = {}): Promise<void> {
500
527
  export async function quickLog(limit: number = 10): Promise<void> {
501
528
  const options: LogOptions = { limit };
502
529
  executeTimelineLog(options);
503
- }
530
+ }
@@ -156,7 +156,7 @@ export async function update(currentVersion: string): Promise<void> {
156
156
  borderStyle: "round",
157
157
  borderColor: "green",
158
158
  align: "left",
159
- width: 50,
159
+ width: 40,
160
160
  }
161
161
  )
162
162
  );
package/src/index.ts CHANGED
@@ -356,11 +356,11 @@ cli
356
356
  .action(async (options: any) => {
357
357
  await checkForUpdates(version, "@zjex/git-workflow");
358
358
  checkGitRepo();
359
-
359
+
360
360
  // 构建选项对象 - 默认交互式模式
361
361
  const logOptions: any = { interactive: true };
362
362
  if (options.limit) logOptions.limit = parseInt(options.limit);
363
-
363
+
364
364
  return log(logOptions);
365
365
  });
366
366
 
@@ -270,7 +270,7 @@ async function performUpdate(packageName: string): Promise<void> {
270
270
  borderStyle: "round",
271
271
  borderColor: "green",
272
272
  align: "left",
273
- width: 50,
273
+ width: 40,
274
274
  }
275
275
  )
276
276
  );
package/src/utils.ts CHANGED
@@ -12,6 +12,7 @@ export interface Colors {
12
12
  orange: (s: string) => string;
13
13
  lightPurple: (s: string) => string;
14
14
  white: (s: string) => string;
15
+ brightYellow: (s: string) => string;
15
16
  reset: string;
16
17
  }
17
18
 
@@ -27,6 +28,7 @@ export const colors: Colors = {
27
28
  orange: (s) => `\x1b[38;5;208m${s}\x1b[0m`,
28
29
  lightPurple: (s) => `\x1b[38;5;141m${s}\x1b[0m`,
29
30
  white: (s) => `\x1b[37m${s}\x1b[0m`,
31
+ brightYellow: (s) => `\x1b[93m${s}\x1b[0m`, // 亮黄色
30
32
  reset: "\x1b[0m",
31
33
  };
32
34
 
package/tsup.config.ts CHANGED
@@ -20,7 +20,7 @@ export default defineConfig({
20
20
  "cac",
21
21
  ],
22
22
  banner: {
23
- js: "#!/usr/bin/env -S node --no-warnings=ExperimentalWarning",
23
+ js: "#!/usr/bin/env -S node --disable-warning=ExperimentalWarning",
24
24
  },
25
25
  define: {
26
26
  __VERSION__: JSON.stringify(pkg.version),