repo-wrapped 0.0.6 → 0.0.9

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 (176) hide show
  1. package/.github/agents/complete.agent.md +257 -0
  2. package/.github/agents/feature-scaffold.agent.md +248 -0
  3. package/.github/agents/jsdoc.agent.md +243 -0
  4. package/.github/agents/plan.agent.md +202 -0
  5. package/.github/agents/spec-writer.agent.md +169 -0
  6. package/.github/agents/test-writer.agent.md +169 -0
  7. package/.stylelintrc.json +27 -0
  8. package/README.md +94 -94
  9. package/coverage/base.css +224 -0
  10. package/coverage/block-navigation.js +87 -0
  11. package/coverage/favicon.png +0 -0
  12. package/coverage/index.html +446 -0
  13. package/coverage/lcov-report/base.css +224 -0
  14. package/coverage/lcov-report/block-navigation.js +87 -0
  15. package/coverage/lcov-report/favicon.png +0 -0
  16. package/coverage/lcov-report/index.html +446 -0
  17. package/coverage/lcov-report/prettify.css +1 -0
  18. package/coverage/lcov-report/prettify.js +2 -0
  19. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  20. package/coverage/lcov-report/sorter.js +210 -0
  21. package/coverage/lcov.info +7039 -0
  22. package/coverage/prettify.css +1 -0
  23. package/coverage/prettify.js +2 -0
  24. package/coverage/sort-arrow-sprite.png +0 -0
  25. package/coverage/sorter.js +210 -0
  26. package/dist/commands/generate.js +262 -5
  27. package/dist/config/defaults.js +158 -0
  28. package/dist/config/index.js +10 -0
  29. package/dist/features/achievements/data/achievements.json +284 -0
  30. package/dist/features/achievements/engine.js +140 -0
  31. package/dist/features/achievements/evaluators.js +246 -0
  32. package/dist/features/achievements/helpers.js +58 -0
  33. package/dist/features/achievements/index.js +57 -0
  34. package/dist/features/achievements/loader.js +88 -0
  35. package/dist/features/achievements/template.js +155 -0
  36. package/dist/features/achievements/types.js +7 -0
  37. package/dist/features/commit-quality/analyzer.js +378 -0
  38. package/dist/features/commit-quality/analyzer.test.js +484 -0
  39. package/dist/features/commit-quality/index.js +28 -0
  40. package/dist/features/commit-quality/template.js +114 -0
  41. package/dist/features/commit-quality/types.js +2 -0
  42. package/dist/features/comparison/analyzer.js +222 -0
  43. package/dist/features/comparison/index.js +28 -0
  44. package/dist/features/comparison/template.js +119 -0
  45. package/dist/features/comparison/types.js +2 -0
  46. package/dist/features/contribution-graph/index.js +9 -0
  47. package/dist/features/contribution-graph/template.js +89 -0
  48. package/dist/features/events/index.js +31 -0
  49. package/dist/features/events/parser.js +253 -0
  50. package/dist/features/events/template.js +113 -0
  51. package/dist/features/events/types.js +2 -0
  52. package/dist/features/executive-summary/generator.js +275 -0
  53. package/dist/features/executive-summary/index.js +27 -0
  54. package/dist/features/executive-summary/template.js +80 -0
  55. package/dist/features/executive-summary/types.js +2 -0
  56. package/dist/features/gaps/analyzer.js +298 -0
  57. package/dist/features/gaps/analyzer.test.js +517 -0
  58. package/dist/features/gaps/index.js +27 -0
  59. package/dist/features/gaps/template.js +190 -0
  60. package/dist/features/gaps/types.js +2 -0
  61. package/dist/features/impact/analyzer.js +248 -0
  62. package/dist/features/impact/index.js +26 -0
  63. package/dist/features/impact/template.js +118 -0
  64. package/dist/features/impact/types.js +2 -0
  65. package/dist/features/index.js +40 -0
  66. package/dist/features/knowledge/analyzer.js +385 -0
  67. package/dist/features/knowledge/index.js +26 -0
  68. package/dist/features/knowledge/template.js +239 -0
  69. package/dist/features/knowledge/types.js +2 -0
  70. package/dist/features/streaks/calculator.js +184 -0
  71. package/dist/features/streaks/calculator.test.js +366 -0
  72. package/dist/features/streaks/index.js +36 -0
  73. package/dist/features/streaks/template.js +41 -0
  74. package/dist/features/streaks/types.js +9 -0
  75. package/dist/features/team/analyzer.js +316 -0
  76. package/dist/features/team/index.js +30 -0
  77. package/dist/features/team/template.js +146 -0
  78. package/dist/features/team/types.js +2 -0
  79. package/dist/features/time-patterns/analyzer.js +319 -0
  80. package/dist/features/time-patterns/analyzer.test.js +278 -0
  81. package/dist/features/time-patterns/index.js +37 -0
  82. package/dist/features/time-patterns/template.js +109 -0
  83. package/dist/features/time-patterns/types.js +9 -0
  84. package/dist/features/velocity/analyzer.js +257 -0
  85. package/dist/features/velocity/analyzer.test.js +383 -0
  86. package/dist/features/velocity/index.js +27 -0
  87. package/dist/features/velocity/template.js +189 -0
  88. package/dist/features/velocity/types.js +2 -0
  89. package/dist/generators/html/scripts/knowledge.js +17 -0
  90. package/dist/generators/html/styles/base.css +10 -6
  91. package/dist/generators/html/styles/components.css +121 -1
  92. package/dist/generators/html/styles/knowledge.css +21 -0
  93. package/dist/generators/html/styles/leaddev.css +1335 -0
  94. package/dist/generators/html/styles/strategic-insights.css +1337 -0
  95. package/dist/generators/html/templates/commitQualitySection.js +28 -2
  96. package/dist/generators/html/templates/comparisonSection.js +119 -0
  97. package/dist/generators/html/templates/eventsSection.js +113 -0
  98. package/dist/generators/html/templates/executiveSummarySection.js +80 -0
  99. package/dist/generators/html/templates/gapSection.js +190 -0
  100. package/dist/generators/html/templates/impactSection.js +8 -6
  101. package/dist/generators/html/templates/knowledgeSection.js +16 -2
  102. package/dist/generators/html/templates/teamSection.js +146 -0
  103. package/dist/generators/html/templates/velocitySection.js +189 -0
  104. package/dist/generators/html/types.js +7 -0
  105. package/dist/generators/html/utils/analysisRunner.js +93 -0
  106. package/dist/generators/html/utils/cardBuilder.js +47 -0
  107. package/dist/generators/html/utils/contextBuilder.js +54 -0
  108. package/dist/generators/html/utils/htmlDocumentBuilder.js +396 -0
  109. package/dist/generators/html/utils/kpiBuilder.js +76 -0
  110. package/dist/generators/html/utils/sectionWrapper.js +71 -0
  111. package/dist/generators/html/utils/styleLoader.js +2 -1
  112. package/dist/html/analysisRunner.js +93 -0
  113. package/dist/html/htmlDocumentBuilder.js +396 -0
  114. package/dist/html/index.js +29 -0
  115. package/dist/html/shared/colorUtils.js +61 -0
  116. package/dist/html/shared/commitMapBuilder.js +23 -0
  117. package/dist/html/shared/components/cardBuilder.js +47 -0
  118. package/dist/html/shared/components/index.js +18 -0
  119. package/dist/html/shared/components/kpiBuilder.js +76 -0
  120. package/dist/html/shared/components/sectionWrapper.js +71 -0
  121. package/dist/html/shared/contextBuilder.js +54 -0
  122. package/dist/html/shared/dateRangeCalculator.js +56 -0
  123. package/dist/html/shared/developerStatsCalculator.js +28 -0
  124. package/dist/html/shared/index.js +39 -0
  125. package/dist/html/shared/scriptLoader.js +15 -0
  126. package/dist/html/shared/scripts/export.js +125 -0
  127. package/dist/html/shared/scripts/knowledge.js +137 -0
  128. package/dist/html/shared/scripts/modal.js +68 -0
  129. package/dist/html/shared/scripts/navigation.js +156 -0
  130. package/dist/html/shared/scripts/tabs.js +18 -0
  131. package/dist/html/shared/scripts/tooltip.js +21 -0
  132. package/dist/html/shared/styleLoader.js +18 -0
  133. package/dist/html/shared/styles/achievements.css +387 -0
  134. package/dist/html/shared/styles/base.css +822 -0
  135. package/dist/html/shared/styles/components.css +1511 -0
  136. package/dist/html/shared/styles/knowledge.css +242 -0
  137. package/dist/html/shared/styles/strategic-insights.css +1337 -0
  138. package/dist/html/shared/weekGrouper.js +27 -0
  139. package/dist/html/types.js +7 -0
  140. package/dist/index.js +54 -21
  141. package/dist/test/helpers/commitFactory.js +166 -0
  142. package/dist/test/helpers/dateUtils.js +101 -0
  143. package/dist/test/helpers/index.js +29 -0
  144. package/dist/test/setup.js +17 -0
  145. package/dist/test/smoke.test.js +94 -0
  146. package/dist/types/achievements.js +7 -0
  147. package/dist/types/analysis.js +7 -0
  148. package/dist/types/core.js +7 -0
  149. package/dist/types/index.js +38 -0
  150. package/dist/types/options.js +7 -0
  151. package/dist/types/shared.js +7 -0
  152. package/dist/types/strategic.js +7 -0
  153. package/dist/types/summary.js +7 -0
  154. package/dist/utils/achievementDefinitions.js +22 -22
  155. package/dist/utils/analyzerContextBuilder.js +124 -0
  156. package/dist/utils/commitQualityAnalyzer.js +13 -2
  157. package/dist/utils/emptyResults.js +95 -0
  158. package/dist/utils/eventAnnotationParser.js +253 -0
  159. package/dist/utils/executiveSummaryGenerator.js +275 -0
  160. package/dist/utils/fileHotspotAnalyzer.js +4 -12
  161. package/dist/utils/gapAnalyzer.js +298 -0
  162. package/dist/utils/gitParser.test.js +363 -0
  163. package/dist/utils/htmlGenerator.js +126 -450
  164. package/dist/utils/impactAnalyzer.js +20 -19
  165. package/dist/utils/knowledgeDistributionAnalyzer.js +32 -27
  166. package/dist/utils/matrixGenerator.js +13 -13
  167. package/dist/utils/rangeComparisonAnalyzer.js +222 -0
  168. package/dist/utils/streakCalculator.js +77 -27
  169. package/dist/utils/teamAnalyzer.js +316 -0
  170. package/dist/utils/timePatternAnalyzer.js +18 -3
  171. package/dist/utils/velocityAnalyzer.js +257 -0
  172. package/dist/utils/wrappedGenerator.js +8 -8
  173. package/package.json +74 -55
  174. package/vitest.config.ts +46 -0
  175. package/dist/cli.js +0 -24
  176. package/dist/commands/index.js +0 -24
@@ -0,0 +1,378 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.analyzeCommitQuality = analyzeCommitQuality;
4
+ exports.getQualityRating = getQualityRating;
5
+ exports.getQualityLevel = getQualityLevel;
6
+ const analyzerContextBuilder_1 = require("../../utils/analyzerContextBuilder");
7
+ const CONVENTIONAL_COMMIT_REGEX = /^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?!?:\s.+/;
8
+ const CODE_HYGIENE_PATTERNS = {
9
+ quickFix: /fix(ed)?\s+(typo|spelling|grammar)/i,
10
+ workInProgress: /\bwip\b|work in progress/i,
11
+ oops: /oops|whoops|my bad/i,
12
+ profanity: /\b(damn|shit|fuck|crap)\b/i,
13
+ vague: /^(test|testing|fix|update|change|refactor)s?$/i,
14
+ singleChar: /^.$/
15
+ };
16
+ const ISSUE_PATTERNS = [
17
+ /#\d+/, // GitHub: #123
18
+ /[A-Z]+-\d+/, // JIRA: PROJ-123
19
+ /closes?\s+#\d+/i, // Closes #123
20
+ /fixes?\s+#\d+/i, // Fixes #123
21
+ /resolves?\s+#\d+/i // Resolves #123
22
+ ];
23
+ const IMPERATIVE_STARTERS = [
24
+ 'add', 'fix', 'update', 'remove', 'delete', 'create', 'implement', 'refactor',
25
+ 'improve', 'optimize', 'enhance', 'change', 'move', 'rename', 'extract',
26
+ 'merge', 'bump', 'revert', 'document', 'test', 'upgrade', 'downgrade'
27
+ ];
28
+ function analyzeCommitQuality(ctxOrCommits, options = {}) {
29
+ // Normalize to internal variables
30
+ let commits;
31
+ let skipBodyCheck;
32
+ if ((0, analyzerContextBuilder_1.isAnalyzerContext)(ctxOrCommits)) {
33
+ commits = ctxOrCommits.commits;
34
+ skipBodyCheck = (0, analyzerContextBuilder_1.getOption)(ctxOrCommits, 'skipBodyCheck', false);
35
+ }
36
+ else {
37
+ commits = ctxOrCommits;
38
+ skipBodyCheck = options.skipBodyCheck ?? false;
39
+ }
40
+ if (commits.length === 0) {
41
+ return getEmptyQuality();
42
+ }
43
+ let totalSubjectLength = 0;
44
+ let tooShort = 0;
45
+ let tooLong = 0;
46
+ let withPeriod = 0;
47
+ let imperativeMood = 0;
48
+ let withBody = 0;
49
+ let totalBodyLength = 0;
50
+ let wellFormattedBody = 0;
51
+ let conventionalCount = 0;
52
+ let withIssueRef = 0;
53
+ let totalIssueRefs = 0;
54
+ const typeMap = new Map();
55
+ const scopeSet = new Set();
56
+ let breakingChanges = 0;
57
+ // Code hygiene metrics
58
+ let quickFix = 0;
59
+ let workInProgress = 0;
60
+ let oops = 0;
61
+ let profanity = 0;
62
+ let vague = 0;
63
+ let singleChar = 0;
64
+ commits.forEach(commit => {
65
+ const lines = commit.message.split('\n').map(l => l.trim()).filter(l => l);
66
+ const subject = lines[0] || '';
67
+ const body = lines.slice(1).join('\n').trim();
68
+ // Subject analysis
69
+ totalSubjectLength += subject.length;
70
+ if (subject.length < 10)
71
+ tooShort++;
72
+ if (subject.length > 72)
73
+ tooLong++;
74
+ if (subject.endsWith('.'))
75
+ withPeriod++;
76
+ if (startsWithImperative(subject))
77
+ imperativeMood++;
78
+ // Body analysis
79
+ if (body.length > 20) {
80
+ withBody++;
81
+ totalBodyLength += body.length;
82
+ if (isWellFormatted(body))
83
+ wellFormattedBody++;
84
+ }
85
+ // Conventional commits
86
+ const conventionalMatch = subject.match(CONVENTIONAL_COMMIT_REGEX);
87
+ if (conventionalMatch) {
88
+ conventionalCount++;
89
+ const type = conventionalMatch[1];
90
+ typeMap.set(type, (typeMap.get(type) || 0) + 1);
91
+ const scope = conventionalMatch[2];
92
+ if (scope) {
93
+ scopeSet.add(scope.replace(/[()]/g, ''));
94
+ }
95
+ if (conventionalMatch[0].includes('!') || body.toLowerCase().includes('breaking change')) {
96
+ breakingChanges++;
97
+ }
98
+ }
99
+ // Issue references
100
+ const issueRefs = countIssueReferences(commit.message);
101
+ if (issueRefs > 0) {
102
+ withIssueRef++;
103
+ totalIssueRefs += issueRefs;
104
+ }
105
+ // Code hygiene patterns
106
+ if (CODE_HYGIENE_PATTERNS.quickFix.test(commit.message))
107
+ quickFix++;
108
+ if (CODE_HYGIENE_PATTERNS.workInProgress.test(commit.message))
109
+ workInProgress++;
110
+ if (CODE_HYGIENE_PATTERNS.oops.test(commit.message))
111
+ oops++;
112
+ if (CODE_HYGIENE_PATTERNS.profanity.test(commit.message))
113
+ profanity++;
114
+ if (CODE_HYGIENE_PATTERNS.vague.test(subject))
115
+ vague++;
116
+ if (CODE_HYGIENE_PATTERNS.singleChar.test(subject))
117
+ singleChar++;
118
+ });
119
+ // Calculate scores
120
+ const avgSubjectLength = totalSubjectLength / commits.length;
121
+ const subjectScore = calculateSubjectScore(avgSubjectLength, tooShort, tooLong, withPeriod, imperativeMood, commits.length);
122
+ const avgBodyLength = withBody > 0 ? totalBodyLength / withBody : 0;
123
+ const bodyScore = skipBodyCheck ? 10 : calculateBodyScore(withBody, wellFormattedBody, commits.length);
124
+ const conventionAdherence = (conventionalCount / commits.length) * 100;
125
+ const conventionScore = (conventionAdherence / 10);
126
+ const issueRefScore = (withIssueRef / commits.length) * 10;
127
+ const overallScore = (subjectScore + bodyScore + conventionScore + issueRefScore) / 4;
128
+ // Type distribution
129
+ const typeDistribution = {
130
+ features: typeMap.get('feat') || 0,
131
+ fixes: typeMap.get('fix') || 0,
132
+ docs: typeMap.get('docs') || 0,
133
+ refactors: typeMap.get('refactor') || 0,
134
+ tests: typeMap.get('test') || 0,
135
+ chores: typeMap.get('chore') || 0,
136
+ other: commits.length - conventionalCount
137
+ };
138
+ // Generate improvements
139
+ const improvements = generateRecommendations({
140
+ totalCommits: commits.length,
141
+ withBody,
142
+ conventionAdherence,
143
+ tooLong,
144
+ withIssueRef,
145
+ typeDistribution,
146
+ skipBodyCheck
147
+ });
148
+ return {
149
+ overallScore,
150
+ totalCommits: commits.length,
151
+ subjectQuality: {
152
+ score: subjectScore,
153
+ avgLength: Math.round(avgSubjectLength),
154
+ tooShort,
155
+ tooLong,
156
+ withPeriod,
157
+ imperativeMood
158
+ },
159
+ bodyQuality: {
160
+ score: bodyScore,
161
+ withBody,
162
+ avgBodyLength: Math.round(avgBodyLength),
163
+ wellFormatted: wellFormattedBody
164
+ },
165
+ conventionalCommits: {
166
+ adherence: conventionAdherence,
167
+ types: Object.fromEntries(typeMap),
168
+ scopes: Array.from(scopeSet),
169
+ breakingChanges
170
+ },
171
+ issueReferences: {
172
+ withReferences: withIssueRef,
173
+ patterns: extractIssuePatterns(commits),
174
+ avgReferencesPerCommit: totalIssueRefs / commits.length
175
+ },
176
+ codeHygiene: {
177
+ quickFixes: quickFix,
178
+ workInProgress,
179
+ oops,
180
+ profanity,
181
+ vague,
182
+ singleChar
183
+ },
184
+ typeDistribution,
185
+ improvements
186
+ };
187
+ }
188
+ function startsWithImperative(subject) {
189
+ const firstWord = subject.toLowerCase().split(/[\s:(]/)[0];
190
+ // Check conventional commit prefix
191
+ if (CONVENTIONAL_COMMIT_REGEX.test(subject)) {
192
+ const afterColon = subject.split(':')[1]?.trim().toLowerCase();
193
+ if (afterColon) {
194
+ const afterColonFirstWord = afterColon.split(/[\s:(]/)[0];
195
+ return IMPERATIVE_STARTERS.includes(afterColonFirstWord);
196
+ }
197
+ }
198
+ return IMPERATIVE_STARTERS.includes(firstWord);
199
+ }
200
+ function isWellFormatted(body) {
201
+ const lines = body.split('\n');
202
+ // Check if most lines are under 80 characters
203
+ const longLines = lines.filter(l => l.length > 80).length;
204
+ const wellFormattedRatio = 1 - (longLines / lines.length);
205
+ // Check for proper paragraphs (blank lines between sections)
206
+ const hasProperParagraphs = body.includes('\n\n');
207
+ return wellFormattedRatio >= 0.8 || hasProperParagraphs;
208
+ }
209
+ function countIssueReferences(message) {
210
+ let count = 0;
211
+ ISSUE_PATTERNS.forEach(pattern => {
212
+ const matches = message.match(new RegExp(pattern, 'g'));
213
+ if (matches)
214
+ count += matches.length;
215
+ });
216
+ return count;
217
+ }
218
+ function extractIssuePatterns(commits) {
219
+ const patterns = new Set();
220
+ commits.forEach(commit => {
221
+ ISSUE_PATTERNS.forEach(pattern => {
222
+ const matches = commit.message.match(new RegExp(pattern, 'g'));
223
+ if (matches) {
224
+ matches.forEach(match => patterns.add(match));
225
+ }
226
+ });
227
+ });
228
+ return Array.from(patterns).slice(0, 10); // Return top 10 patterns
229
+ }
230
+ function calculateSubjectScore(avgLength, tooShort, tooLong, withPeriod, imperativeMood, total) {
231
+ let score = 10;
232
+ // Length penalty
233
+ if (avgLength < 20)
234
+ score -= 1;
235
+ if (avgLength > 60)
236
+ score -= 1;
237
+ // Too short/long penalty
238
+ const tooShortRatio = tooShort / total;
239
+ const tooLongRatio = tooLong / total;
240
+ score -= tooShortRatio * 2;
241
+ score -= tooLongRatio * 2;
242
+ // Period penalty
243
+ const periodRatio = withPeriod / total;
244
+ score -= periodRatio * 1;
245
+ // Imperative mood bonus
246
+ const imperativeRatio = imperativeMood / total;
247
+ if (imperativeRatio < 0.5)
248
+ score -= 2;
249
+ else if (imperativeRatio < 0.7)
250
+ score -= 1;
251
+ return Math.max(0, Math.min(10, score));
252
+ }
253
+ function calculateBodyScore(withBody, wellFormatted, total) {
254
+ const bodyRatio = withBody / total;
255
+ const formattedRatio = withBody > 0 ? wellFormatted / withBody : 0;
256
+ let score = 0;
257
+ // Body presence (up to 6 points)
258
+ score += bodyRatio * 6;
259
+ // Formatting quality (up to 4 points)
260
+ score += formattedRatio * 4;
261
+ return Math.max(0, Math.min(10, score));
262
+ }
263
+ function generateRecommendations(data) {
264
+ const tips = [];
265
+ // Body recommendations (skip if body check is disabled)
266
+ if (!data.skipBodyCheck) {
267
+ const bodyRatio = data.withBody / data.totalCommits;
268
+ if (bodyRatio < 0.3) {
269
+ tips.push('Add commit bodies to explain "why" not just "what"');
270
+ }
271
+ else if (bodyRatio < 0.5) {
272
+ tips.push('Try adding more detailed commit descriptions');
273
+ }
274
+ }
275
+ // Convention recommendations
276
+ if (data.conventionAdherence < 50) {
277
+ tips.push('Consider adopting Conventional Commits format');
278
+ }
279
+ else if (data.conventionAdherence < 70) {
280
+ tips.push('Increase conventional commit usage for better changelog generation');
281
+ }
282
+ // Length recommendations
283
+ if (data.tooLong > data.totalCommits * 0.1) {
284
+ tips.push('Keep subject lines under 72 characters');
285
+ }
286
+ // Issue reference recommendations
287
+ const issueRefRatio = data.withIssueRef / data.totalCommits;
288
+ if (issueRefRatio < 0.3) {
289
+ tips.push('Link commits to issues/tickets for better traceability');
290
+ }
291
+ // Test recommendations
292
+ const testRatio = data.typeDistribution.tests / data.totalCommits;
293
+ if (testRatio < 0.05) {
294
+ tips.push('Add more test commits - aim for 10-15% test coverage');
295
+ }
296
+ // Refactor recommendations
297
+ const refactorRatio = data.typeDistribution.refactors / data.totalCommits;
298
+ if (refactorRatio < 0.05) {
299
+ tips.push('Schedule regular refactoring - aim for 10-15% refactor commits');
300
+ }
301
+ // Balance recommendations
302
+ const featureFixRatio = data.typeDistribution.features / (data.typeDistribution.fixes || 1);
303
+ if (featureFixRatio > 3) {
304
+ tips.push('High feature/fix ratio - consider addressing technical debt');
305
+ }
306
+ return tips;
307
+ }
308
+ function getEmptyQuality() {
309
+ return {
310
+ overallScore: 0,
311
+ totalCommits: 0,
312
+ subjectQuality: {
313
+ score: 0,
314
+ avgLength: 0,
315
+ tooShort: 0,
316
+ tooLong: 0,
317
+ withPeriod: 0,
318
+ imperativeMood: 0
319
+ },
320
+ bodyQuality: {
321
+ score: 0,
322
+ withBody: 0,
323
+ avgBodyLength: 0,
324
+ wellFormatted: 0
325
+ },
326
+ conventionalCommits: {
327
+ adherence: 0,
328
+ types: {},
329
+ scopes: [],
330
+ breakingChanges: 0
331
+ },
332
+ issueReferences: {
333
+ withReferences: 0,
334
+ patterns: [],
335
+ avgReferencesPerCommit: 0
336
+ },
337
+ codeHygiene: {
338
+ quickFixes: 0,
339
+ workInProgress: 0,
340
+ oops: 0,
341
+ profanity: 0,
342
+ vague: 0,
343
+ singleChar: 0
344
+ },
345
+ typeDistribution: {
346
+ features: 0,
347
+ fixes: 0,
348
+ docs: 0,
349
+ refactors: 0,
350
+ tests: 0,
351
+ chores: 0,
352
+ other: 0
353
+ },
354
+ improvements: []
355
+ };
356
+ }
357
+ function getQualityRating(score) {
358
+ if (score >= 9)
359
+ return '⭐⭐⭐⭐⭐';
360
+ if (score >= 7.5)
361
+ return '⭐⭐⭐⭐';
362
+ if (score >= 6)
363
+ return '⭐⭐⭐';
364
+ if (score >= 4)
365
+ return '⭐⭐';
366
+ return '⭐';
367
+ }
368
+ function getQualityLevel(score) {
369
+ if (score >= 9)
370
+ return 'Excellent';
371
+ if (score >= 7.5)
372
+ return 'Good';
373
+ if (score >= 6)
374
+ return 'Fair';
375
+ if (score >= 4)
376
+ return 'Needs Improvement';
377
+ return 'Poor';
378
+ }