git-fish-log 1.0.9 → 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.
@@ -48,6 +48,14 @@ npm link
48
48
  * `host`: 可选。私有部署的 GitLab 域名(如 `https://gitlab.mycompany.com`),缺省默认使用 `https://gitlab.com`。
49
49
  * `name`: 可选。给该数据源指定的别名(如 `my-company`),缺省时自动使用 host 域名作为别名。若别名已存在则会覆盖更新。
50
50
 
51
+ ## 🆕 v1.0.10 更新内容
52
+
53
+ - **月报新增爆肝王 & 摸鱼王排行榜**:与周报一致的计算法则,从当月数据中找出摸鱼指数最低(最努力)和最高(最会摸鱼)的日子,多日并列时一起显示。统计时自动排除周末与法定节假日(调休上班日不算休息日),但如果休息日有提交记录则视为加班纳入统计。
54
+ - **月报新增摸鱼指数均值(除休息日)**:基于排除无提交休息日后的数据重新计算月均摸鱼指数,更准确反映实际工作日的摸鱼水平。同时月报锐评的阈值判断也同步改为基于此调整后均值,避免被周末/节假日的 95 分拉高。
55
+ - **周报「最努力的日子」排除周末**:周末的提交记录统一归类到「最痛苦的日子」,不再同时出现在「最努力」中,逻辑更合理。
56
+ - **周报项目名称始终显示**:去掉了 `-P` 条件限制,每日提交详情中的项目名称默认直接展示。
57
+ - **修复月报 `isWeekend` 参数**:`analyzeMonthly` 原来写死 `false`,导致周末的摸鱼指数计算缺少 +5 工作分加成,现已根据实际日期正确计算。
58
+
51
59
  ## 🆕 v1.0.9 更新内容
52
60
 
53
61
  - **月报新增节假日与调休标记**:每日摸鱼指数概览中,法定节假日日期后追加绿色圆点 `•`,法定调休上班日(周末补班)追加红色叹号 `!`,一眼分辨哪天是假日、哪天在还债。内置 2025-2026 年中国法定节假日数据,周末自动识别。
@@ -122,6 +130,10 @@ fish -m
122
130
  6月22日 6月23日 6月24日 6月25日 6月26日 6月27日 6月28日
123
131
  95% 51% 95% 95% 78% 95% 95%
124
132
 
133
+ 🏆 爆肝王:6月11日 | 🐟 摸鱼指数:38%
134
+ ☕ 摸鱼王:6月26日 | 🐟 摸鱼指数:78%
135
+ --------------------------------------------------
136
+ 📊 本月均值:🐟 摸鱼指数 60%
125
137
  --------------------------------------------------
126
138
  🤖 锐评:
127
139
  本月 Feat 占比高达 62%。新功能一项接一项,开发火力全开,业务线因你而飞速前进!
package/README.md CHANGED
@@ -33,6 +33,14 @@
33
33
  * `host`: 可选。私有部署的 GitLab 域名(如 `https://gitlab.mycompany.com`),缺省默认使用 `https://gitlab.com`。
34
34
  * `name`: 可选。给该数据源指定的别名(如 `my-company`),缺省时自动使用 host 域名作为别名。若别名已存在则会覆盖更新。
35
35
 
36
+ ## 🆕 v1.0.10 更新内容
37
+
38
+ - **月报新增爆肝王 & 摸鱼王排行榜**:与周报一致的计算法则,从当月数据中找出摸鱼指数最低(最努力)和最高(最会摸鱼)的日子,多日并列时一起显示。统计时自动排除周末与法定节假日(调休上班日不算休息日),但如果休息日有提交记录则视为加班纳入统计。
39
+ - **月报新增摸鱼指数均值(除休息日)**:基于排除无提交休息日后的数据重新计算月均摸鱼指数,更准确反映实际工作日的摸鱼水平。同时月报锐评的阈值判断也同步改为基于此调整后均值,避免被周末/节假日的 95 分拉高。
40
+ - **周报「最努力的日子」排除周末**:周末的提交记录统一归类到「最痛苦的日子」,不再同时出现在「最努力」中,逻辑更合理。
41
+ - **周报项目名称始终显示**:去掉了 `-P` 条件限制,每日提交详情中的项目名称默认直接展示。
42
+ - **修复月报 `isWeekend` 参数**:`analyzeMonthly` 原来写死 `false`,导致周末的摸鱼指数计算缺少 +5 工作分加成,现已根据实际日期正确计算。
43
+
36
44
  ## 🆕 v1.0.9 更新内容
37
45
 
38
46
  - **月报新增节假日与调休标记**:每日摸鱼指数概览中,法定节假日日期后追加绿色圆点 `•`,法定调休上班日(周末补班)追加红色叹号 `!`,一眼分辨哪天是假日、哪天在还债。内置 2025-2026 年中国法定节假日数据,周末自动识别。
@@ -108,8 +116,10 @@ fish -m
108
116
  5月25日 5月26日 5月27日 5月28日 5月29日 5月30日 5月31日
109
117
  61% 28% 35% 34% 20% 90% 90%
110
118
 
111
- 🔥 爆肝王: 5月9日 摸鱼指数 19% 🔥 爆肝战神 🧱 勤恳搬砖人
112
-
119
+ 🏆 爆肝王:5月9日 | 🐟 摸鱼指数:19%
120
+ ☕ 摸鱼王:5月26日 | 🐟 摸鱼指数:28%
121
+ --------------------------------------------------
122
+ 📊 本月均值:🐟 摸鱼指数 49%
113
123
  --------------------------------------------------
114
124
  🤖 锐评:
115
125
  本月 Feat 占比高达 62%。新功能一项接一项,开发火力全开,业务线因你而飞速前进!
package/dist/index.js CHANGED
@@ -791,7 +791,9 @@ async function analyzeMonthly(projectPaths, now = /* @__PURE__ */ new Date(), so
791
791
  for (let d = 1; d <= maxDay; d++) {
792
792
  const dateStr = `${since.getFullYear()}-${since.getMonth() + 1}-${d}`;
793
793
  const dayCommits = commitsByDateStr[dateStr] || [];
794
- const indices = calculateDayIndices(dayCommits, false);
794
+ const dayDate = new Date(since.getFullYear(), since.getMonth(), d);
795
+ const isWeekend = dayDate.getDay() === 0 || dayDate.getDay() === 6;
796
+ const indices = calculateDayIndices(dayCommits, isWeekend);
795
797
  totalFish += indices.fish;
796
798
  totalHardworking += indices.hardworking;
797
799
  totalNightOwl += indices.nightOwl;
@@ -986,16 +988,17 @@ function getAICritic(weeklyStats) {
986
988
  }
987
989
  return parts.join("\n\n");
988
990
  }
989
- function getAICriticForMonth(monthlyStats) {
991
+ function getAICriticForMonth(monthlyStats, adjustedFish) {
990
992
  const parts = [];
991
993
  if (monthlyStats.ghostCommitsCount > 3) {
992
994
  parts.push(getRandomItem(GHOST_CRITIQUES));
993
995
  }
996
+ const fish = adjustedFish ?? monthlyStats.averageFish;
994
997
  if (monthlyStats.totalCommits === 0) {
995
998
  parts.push("\u672C\u6708\u63D0\u4EA4\u6B21\u6570\u4E3A 0\uFF01\u4F60\u6210\u529F\u5730\u5728\u516C\u53F8\u84B8\u53D1\u4E86\u4E00\u4E2A\u6708\uFF0C\u62FF\u5230\u4E86\u5168\u989D\u5DE5\u8D44\u3002\u5EFA\u8BAE\u4F60\u4E0B\u4E2A\u6708\u7EE7\u7EED\u4FDD\u6301\u4F4E\u8C03\uFF0C\u4E0D\u8981\u8BA9 HR \u6CE8\u610F\u5230\u4F60\u3002");
996
- } else if (monthlyStats.averageFish >= 70) {
999
+ } else if (fish >= 70) {
997
1000
  parts.push(getRandomItem(SLACK_HIGH_CRITIQUES));
998
- } else if (monthlyStats.averageFish <= 35) {
1001
+ } else if (fish <= 35) {
999
1002
  parts.push(getRandomItem(SLACK_LOW_CRITIQUES));
1000
1003
  }
1001
1004
  if (parts.length === 0) {
@@ -1130,6 +1133,14 @@ function isCompensatoryWorkday(date) {
1130
1133
  const key = formatDateKey(date);
1131
1134
  return holiday_in_law[key]?.type === "workday";
1132
1135
  }
1136
+ function isRestDay(date) {
1137
+ if (isHoliday(date)) return true;
1138
+ const dayOfWeek = date.getDay();
1139
+ if (dayOfWeek === 0 || dayOfWeek === 6) {
1140
+ return !isCompensatoryWorkday(date);
1141
+ }
1142
+ return false;
1143
+ }
1133
1144
 
1134
1145
  // src/index.ts
1135
1146
  var program = new Command();
@@ -1413,7 +1424,7 @@ async function runWeeklyReport(weeksAgo, source, showProjects = false) {
1413
1424
  if (isFuture && day.commitsCount === 0) {
1414
1425
  console.log(` ${day.dayName}\uFF1A${chalk.gray("\u672A\u5230")}`);
1415
1426
  } else {
1416
- const projStr = day.projects.length > 0 ? ` | ${day.projects.length}\u4E2A\u9879\u76EE${showProjects ? ` (${day.projects.join(", ")})` : ""}` : "";
1427
+ const projStr = day.projects.length > 0 ? ` | ${day.projects.length}\u4E2A\u9879\u76EE (${day.projects.join(", ")})` : "";
1417
1428
  const commitStr = day.commitsCount > 0 ? chalk.white.bold(`${day.commitsCount} \u6B21`) : "0 \u6B21";
1418
1429
  const indices = [];
1419
1430
  if (isWeekend) {
@@ -1438,16 +1449,14 @@ async function runWeeklyReport(weeksAgo, source, showProjects = false) {
1438
1449
  console.log("\n" + chalk.gray("-".repeat(50)));
1439
1450
  if (stats.totalCommits > 0) {
1440
1451
  const activeDays = stats.days.filter((_, idx) => idx <= currentDayOfWeek);
1441
- const workingDays = activeDays.filter((d) => d.commitsCount > 0);
1452
+ const workingDays = activeDays.filter((d) => d.commitsCount > 0 && d.dayName !== "\u5468\u516D" && d.dayName !== "\u5468\u65E5");
1442
1453
  if (workingDays.length > 0) {
1443
1454
  const minFish = Math.min(...workingDays.map((d) => d.fish));
1444
1455
  const mostProductiveDays = workingDays.filter((d) => d.fish === minFish);
1445
1456
  if (minFish <= 40 && mostProductiveDays.length > 0) {
1446
1457
  const names = mostProductiveDays.map((d) => d.dayName).join("\u3001");
1447
1458
  const sample = mostProductiveDays[0];
1448
- const isWeekend = sample.dayName === "\u5468\u516D" || sample.dayName === "\u5468\u65E5";
1449
- const label = isWeekend ? "\u{1F4BC} \u52A0\u73ED\u6307\u6570" : "\u{1F41F} \u6478\u9C7C\u6307\u6570";
1450
- console.log(`\u{1F3C6} ${chalk.red.bold("\u6700\u52AA\u529B\u7684\u65E5\u5B50")}\uFF1A${names} | ${label}\uFF1A${sample.fish}%`);
1459
+ console.log(`\u{1F3C6} ${chalk.red.bold("\u6700\u52AA\u529B\u7684\u65E5\u5B50")}\uFF1A${names} | \u{1F41F} \u6478\u9C7C\u6307\u6570\uFF1A${sample.fish}%`);
1451
1460
  }
1452
1461
  }
1453
1462
  const weekdayDays = activeDays.filter((d) => d.dayName !== "\u5468\u516D" && d.dayName !== "\u5468\u65E5");
@@ -1565,9 +1574,42 @@ async function runMonthlyReport(monthsAgo, source) {
1565
1574
  console.log(` ${l}`);
1566
1575
  }
1567
1576
  }
1568
- console.log("\n" + chalk.gray("-".repeat(50)));
1577
+ let adjustedAvgFish;
1578
+ if (stats.dailyIndices && stats.dailyIndices.length > 0) {
1579
+ const activeDailyIndices = stats.dailyIndices.filter((d) => {
1580
+ const dateObj = new Date(targetDate.getFullYear(), targetDate.getMonth(), d.day);
1581
+ if (isRestDay(dateObj) && d.commitsCount === 0) return false;
1582
+ return true;
1583
+ });
1584
+ if (activeDailyIndices.length > 0) {
1585
+ const minFish = Math.min(...activeDailyIndices.map((d) => d.fish));
1586
+ const mostProductive = activeDailyIndices.filter((d) => d.fish === minFish);
1587
+ if (minFish <= 40 && mostProductive.length > 0) {
1588
+ const names = mostProductive.map((d) => `${d.day}\u65E5`).join("\u3001");
1589
+ const monthLabel = `${targetDate.getMonth() + 1}\u6708`;
1590
+ console.log(`
1591
+ \u{1F3C6} ${chalk.red.bold("\u7206\u809D\u738B")}\uFF1A${monthLabel}${names} | \u{1F41F} \u6478\u9C7C\u6307\u6570\uFF1A${minFish}%`);
1592
+ }
1593
+ const maxFish = Math.max(...activeDailyIndices.map((d) => d.fish));
1594
+ const mostSlacky = activeDailyIndices.filter((d) => d.fish === maxFish);
1595
+ const filteredSlacky = mostSlacky.filter(
1596
+ (d) => d.fish !== minFish || activeDailyIndices.length === 0
1597
+ );
1598
+ if (maxFish >= 70 && filteredSlacky.length > 0) {
1599
+ const names = filteredSlacky.map((d) => `${d.day}\u65E5`).join("\u3001");
1600
+ const monthLabel = `${targetDate.getMonth() + 1}\u6708`;
1601
+ console.log(`\u2615 ${chalk.green.bold("\u6478\u9C7C\u738B")}\uFF1A${monthLabel}${names} | \u{1F41F} \u6478\u9C7C\u6307\u6570\uFF1A${maxFish}%`);
1602
+ }
1603
+ adjustedAvgFish = Math.round(
1604
+ activeDailyIndices.reduce((sum, d) => sum + d.fish, 0) / activeDailyIndices.length
1605
+ );
1606
+ console.log("" + chalk.gray("-".repeat(50)));
1607
+ console.log(chalk.cyan.bold(`\u{1F4CA} \u672C\u6708\u5747\u503C\uFF1A\u{1F41F} \u6478\u9C7C\u6307\u6570 ${adjustedAvgFish}%`));
1608
+ }
1609
+ }
1610
+ console.log(chalk.gray("-".repeat(50)));
1569
1611
  console.log(`\u{1F916} ${chalk.magenta.bold("\u9510\u8BC4")}\uFF1A`);
1570
- console.log(chalk.white(getAICriticForMonth(stats)));
1612
+ console.log(chalk.white(getAICriticForMonth(stats, adjustedAvgFish)));
1571
1613
  console.log("");
1572
1614
  }
1573
1615
  async function runProjectReport(weeksAgo, source, isMonth = false) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-fish-log",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "description": "🐟 Git 摸鱼 & 爆肝分析器 CLI — 给你的提交记录生成摸鱼指数和锐评",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",