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,146 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildTeamSection = buildTeamSection;
4
+ /**
5
+ * Builds the HTML section for team analysis visualization
6
+ */
7
+ function buildTeamSection(analysis) {
8
+ if (!analysis || analysis.members.length === 0) {
9
+ return '<p class="no-data">No team data available</p>';
10
+ }
11
+ const { teamMetrics, memberBreakdown, loadDistribution } = analysis;
12
+ // Build summary cards
13
+ const summaryHtml = buildSummaryCards(teamMetrics, analysis.members.length);
14
+ // Build load distribution indicator
15
+ const loadDistHtml = buildLoadDistribution(loadDistribution);
16
+ // Build member breakdown
17
+ const membersHtml = buildMemberList(memberBreakdown);
18
+ // Build insights
19
+ const insightsHtml = buildInsights(loadDistribution.insights);
20
+ return `
21
+ <div class="team-section">
22
+ ${summaryHtml}
23
+ ${loadDistHtml}
24
+ ${membersHtml}
25
+ ${insightsHtml}
26
+ </div>
27
+ `;
28
+ }
29
+ function buildSummaryCards(metrics, memberCount) {
30
+ return `
31
+ <div class="team-summary">
32
+ <div class="team-stat-card">
33
+ <span class="stat-value">${metrics.totalCommits.toLocaleString()}</span>
34
+ <span class="stat-label">Total Commits</span>
35
+ </div>
36
+ <div class="team-stat-card">
37
+ <span class="stat-value">${memberCount}</span>
38
+ <span class="stat-label">Team Members</span>
39
+ </div>
40
+ <div class="team-stat-card">
41
+ <span class="stat-value">${metrics.commitsPerMember.toFixed(1)}</span>
42
+ <span class="stat-label">Commits/Member</span>
43
+ </div>
44
+ <div class="team-stat-card">
45
+ <span class="stat-value">${metrics.activeDays}</span>
46
+ <span class="stat-label">Active Days</span>
47
+ </div>
48
+ <div class="team-stat-card">
49
+ <span class="stat-value">${metrics.qualityScore.toFixed(1)}</span>
50
+ <span class="stat-label">Avg Quality</span>
51
+ </div>
52
+ </div>
53
+ `;
54
+ }
55
+ function buildLoadDistribution(loadDist) {
56
+ const gini = loadDist.giniCoefficient;
57
+ const percentage = Math.round(gini * 100);
58
+ // Color based on assessment
59
+ let colorClass = 'balanced';
60
+ let statusIcon = '✅';
61
+ if (loadDist.assessment === 'moderate-imbalance') {
62
+ colorClass = 'moderate';
63
+ statusIcon = '⚠️';
64
+ }
65
+ else if (loadDist.assessment === 'high-imbalance') {
66
+ colorClass = 'imbalanced';
67
+ statusIcon = '🚨';
68
+ }
69
+ const assessmentLabel = loadDist.assessment.replace('-', ' ').replace(/\b\w/g, c => c.toUpperCase());
70
+ return `
71
+ <div class="load-distribution">
72
+ <h3>Load Distribution</h3>
73
+ <div class="gini-container">
74
+ <div class="gini-bar-bg">
75
+ <div class="gini-bar ${colorClass}" style="width: ${percentage}%"></div>
76
+ </div>
77
+ <div class="gini-info">
78
+ <span class="gini-value">Gini: ${gini.toFixed(2)}</span>
79
+ <span class="gini-assessment ${colorClass}">${statusIcon} ${assessmentLabel}</span>
80
+ </div>
81
+ </div>
82
+ <p class="gini-explanation">
83
+ ${gini < 0.3 ? 'Work is evenly distributed across the team.' :
84
+ gini < 0.5 ? 'Some team members are contributing more than others.' :
85
+ 'Work is concentrated among a few contributors. Consider redistributing.'}
86
+ </p>
87
+ </div>
88
+ `;
89
+ }
90
+ function buildMemberList(members) {
91
+ // Sort by commits descending
92
+ const sorted = [...members].sort((a, b) => b.commits - a.commits);
93
+ const maxCommits = sorted[0]?.commits || 1;
94
+ const membersHtml = sorted.map((member, index) => {
95
+ const barWidth = (member.commits / maxCommits) * 100;
96
+ const rankBadge = index === 0 ? '👑' : index < 3 ? '⭐' : '';
97
+ return `
98
+ <div class="member-card">
99
+ <div class="member-rank">${index + 1}</div>
100
+ <div class="member-info">
101
+ <div class="member-name">${rankBadge} ${escapeHtml(member.author)}</div>
102
+ <div class="member-areas">${member.topAreas.slice(0, 3).map(a => `<span class="area-tag">${escapeHtml(a)}</span>`).join('')}</div>
103
+ </div>
104
+ <div class="member-bar-container">
105
+ <div class="member-bar" style="width: ${barWidth}%"></div>
106
+ </div>
107
+ <div class="member-stats">
108
+ <span class="member-commits">${member.commits}</span>
109
+ <span class="member-percentage">(${member.percentage.toFixed(1)}%)</span>
110
+ </div>
111
+ <div class="member-quality" title="Commit quality score">
112
+ <span class="quality-badge">${member.qualityScore.toFixed(1)}</span>
113
+ </div>
114
+ </div>
115
+ `;
116
+ }).join('');
117
+ return `
118
+ <div class="member-breakdown">
119
+ <h3>Team Members</h3>
120
+ <div class="member-list">
121
+ ${membersHtml}
122
+ </div>
123
+ </div>
124
+ `;
125
+ }
126
+ function buildInsights(insights) {
127
+ if (!insights || insights.length === 0) {
128
+ return '';
129
+ }
130
+ return `
131
+ <div class="team-insights">
132
+ <h3>Insights</h3>
133
+ <ul class="insights-list">
134
+ ${insights.map(insight => `<li class="insight-item">💡 ${escapeHtml(insight)}</li>`).join('')}
135
+ </ul>
136
+ </div>
137
+ `;
138
+ }
139
+ function escapeHtml(str) {
140
+ return str
141
+ .replace(/&/g, '&amp;')
142
+ .replace(/</g, '&lt;')
143
+ .replace(/>/g, '&gt;')
144
+ .replace(/"/g, '&quot;')
145
+ .replace(/'/g, '&#39;');
146
+ }
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildVelocitySection = buildVelocitySection;
4
+ const date_fns_1 = require("date-fns");
5
+ function buildVelocitySection(velocity) {
6
+ if (velocity.timeline.length === 0) {
7
+ return `
8
+ <div class="velocity-section">
9
+ <h2>📈 Velocity Analysis</h2>
10
+ <div class="empty-state">No velocity data available</div>
11
+ </div>
12
+ `;
13
+ }
14
+ const chartHtml = buildVelocityChart(velocity);
15
+ const statsHtml = buildVelocityStats(velocity);
16
+ const anomaliesHtml = buildAnomaliesList(velocity.anomalies);
17
+ return `
18
+ <div class="velocity-section">
19
+ <h2>📈 Velocity Analysis</h2>
20
+
21
+ ${statsHtml}
22
+
23
+ <div class="velocity-chart-container">
24
+ <h3>Commits Per Week</h3>
25
+ ${chartHtml}
26
+ </div>
27
+
28
+ ${anomaliesHtml}
29
+ </div>
30
+ `;
31
+ }
32
+ function buildVelocityStats(velocity) {
33
+ const trendEmoji = velocity.overallTrend === 'increasing' ? '📈' :
34
+ velocity.overallTrend === 'decreasing' ? '📉' :
35
+ velocity.overallTrend === 'volatile' ? '📊' : '➡️';
36
+ const trendClass = velocity.overallTrend === 'increasing' ? 'positive' :
37
+ velocity.overallTrend === 'decreasing' ? 'negative' : 'neutral';
38
+ const trendSign = velocity.trendPercentage >= 0 ? '+' : '';
39
+ return `
40
+ <div class="velocity-stats">
41
+ <div class="velocity-stat-card">
42
+ <div class="stat-icon">${trendEmoji}</div>
43
+ <div class="stat-info">
44
+ <div class="stat-label">Overall Trend</div>
45
+ <div class="stat-value ${trendClass}">${velocity.overallTrend}</div>
46
+ <div class="stat-detail">${trendSign}${velocity.trendPercentage}% over period</div>
47
+ </div>
48
+ </div>
49
+ <div class="velocity-stat-card">
50
+ <div class="stat-icon">📊</div>
51
+ <div class="stat-info">
52
+ <div class="stat-label">Average</div>
53
+ <div class="stat-value">${velocity.averageCommitsPerWeek}</div>
54
+ <div class="stat-detail">commits/week</div>
55
+ </div>
56
+ </div>
57
+ <div class="velocity-stat-card">
58
+ <div class="stat-icon">🚀</div>
59
+ <div class="stat-info">
60
+ <div class="stat-label">Peak Week</div>
61
+ <div class="stat-value">${velocity.peakWeek.commits}</div>
62
+ <div class="stat-detail">${(0, date_fns_1.format)(velocity.peakWeek.weekStart, 'MMM d, yyyy')}</div>
63
+ </div>
64
+ </div>
65
+ <div class="velocity-stat-card">
66
+ <div class="stat-icon">🐢</div>
67
+ <div class="stat-info">
68
+ <div class="stat-label">Lowest Week</div>
69
+ <div class="stat-value">${velocity.lowestWeek.commits}</div>
70
+ <div class="stat-detail">${(0, date_fns_1.format)(velocity.lowestWeek.weekStart, 'MMM d, yyyy')}</div>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ `;
75
+ }
76
+ function buildVelocityChart(velocity) {
77
+ const timeline = velocity.timeline;
78
+ const maxCommits = Math.max(...timeline.map(d => d.commits), 1);
79
+ const chartWidth = 800;
80
+ const chartHeight = 200;
81
+ const padding = { top: 20, right: 20, bottom: 40, left: 50 };
82
+ const innerWidth = chartWidth - padding.left - padding.right;
83
+ const innerHeight = chartHeight - padding.top - padding.bottom;
84
+ // Build SVG path for commits
85
+ const xScale = (i) => padding.left + (i / (timeline.length - 1 || 1)) * innerWidth;
86
+ const yScale = (v) => padding.top + innerHeight - (v / maxCommits) * innerHeight;
87
+ // Commits line
88
+ const commitsPath = timeline.map((d, i) => `${i === 0 ? 'M' : 'L'} ${xScale(i)} ${yScale(d.commits)}`).join(' ');
89
+ // Rolling average line
90
+ const avgPath = timeline.map((d, i) => `${i === 0 ? 'M' : 'L'} ${xScale(i)} ${yScale(d.rollingAverage)}`).join(' ');
91
+ // Area fill under commits line
92
+ const areaPath = `${commitsPath} L ${xScale(timeline.length - 1)} ${yScale(0)} L ${xScale(0)} ${yScale(0)} Z`;
93
+ // Find anomaly positions
94
+ const anomalyMarkers = velocity.anomalies.map(anomaly => {
95
+ const idx = timeline.findIndex(d => (0, date_fns_1.format)(d.weekStart, 'yyyy-MM-dd') === (0, date_fns_1.format)(anomaly.weekStart, 'yyyy-MM-dd'));
96
+ if (idx === -1)
97
+ return '';
98
+ const x = xScale(idx);
99
+ const y = yScale(timeline[idx].commits);
100
+ const color = anomaly.type === 'drop' ? '#ff6b6b' : anomaly.type === 'spike' ? '#ffa94d' : '#868e96';
101
+ return `<circle cx="${x}" cy="${y}" r="6" fill="${color}" class="anomaly-marker" data-type="${anomaly.type}" data-severity="${anomaly.severity}"/>`;
102
+ }).join('');
103
+ // X-axis labels (show every nth label to avoid crowding)
104
+ const labelInterval = Math.max(1, Math.floor(timeline.length / 8));
105
+ const xLabels = timeline.map((d, i) => {
106
+ if (i % labelInterval !== 0 && i !== timeline.length - 1)
107
+ return '';
108
+ return `<text x="${xScale(i)}" y="${chartHeight - 10}" text-anchor="middle" class="axis-label">${(0, date_fns_1.format)(d.weekStart, 'MMM d')}</text>`;
109
+ }).join('');
110
+ // Y-axis labels
111
+ const yTicks = [0, Math.round(maxCommits / 2), maxCommits];
112
+ const yLabels = yTicks.map(v => `<text x="${padding.left - 10}" y="${yScale(v) + 4}" text-anchor="end" class="axis-label">${v}</text>`).join('');
113
+ // Grid lines
114
+ const gridLines = yTicks.map(v => `<line x1="${padding.left}" y1="${yScale(v)}" x2="${chartWidth - padding.right}" y2="${yScale(v)}" class="grid-line"/>`).join('');
115
+ return `
116
+ <svg class="velocity-chart" viewBox="0 0 ${chartWidth} ${chartHeight}" preserveAspectRatio="xMidYMid meet">
117
+ <defs>
118
+ <linearGradient id="areaGradient" x1="0%" y1="0%" x2="0%" y2="100%">
119
+ <stop offset="0%" style="stop-color:var(--accent-color);stop-opacity:0.3"/>
120
+ <stop offset="100%" style="stop-color:var(--accent-color);stop-opacity:0.05"/>
121
+ </linearGradient>
122
+ </defs>
123
+
124
+ <!-- Grid -->
125
+ ${gridLines}
126
+
127
+ <!-- Area fill -->
128
+ <path d="${areaPath}" fill="url(#areaGradient)" class="area-fill"/>
129
+
130
+ <!-- Commits line -->
131
+ <path d="${commitsPath}" fill="none" stroke="var(--accent-color)" stroke-width="2" class="commits-line"/>
132
+
133
+ <!-- Rolling average line -->
134
+ <path d="${avgPath}" fill="none" stroke="#ff922b" stroke-width="3" stroke-dasharray="6,4" class="avg-line"/>
135
+
136
+ <!-- Anomaly markers -->
137
+ ${anomalyMarkers}
138
+
139
+ <!-- Axes labels -->
140
+ ${xLabels}
141
+ ${yLabels}
142
+
143
+ <!-- Legend -->
144
+ <g transform="translate(${chartWidth - 150}, 10)">
145
+ <line x1="0" y1="5" x2="20" y2="5" stroke="var(--accent-color)" stroke-width="2"/>
146
+ <text x="25" y="9" class="legend-label">Commits</text>
147
+ <line x1="0" y1="20" x2="20" y2="20" stroke="#ff922b" stroke-width="3" stroke-dasharray="6,4"/>
148
+ <text x="25" y="24" class="legend-label">Rolling Avg</text>
149
+ </g>
150
+ </svg>
151
+ `;
152
+ }
153
+ function buildAnomaliesList(anomalies) {
154
+ if (anomalies.length === 0) {
155
+ return '';
156
+ }
157
+ const criticalAnomalies = anomalies.filter(a => a.severity === 'critical' || a.severity === 'significant');
158
+ if (criticalAnomalies.length === 0) {
159
+ return '';
160
+ }
161
+ const anomalyItems = criticalAnomalies.slice(0, 5).map(anomaly => {
162
+ const typeEmoji = anomaly.type === 'drop' ? '📉' : anomaly.type === 'spike' ? '📈' : '🚫';
163
+ const severityClass = anomaly.severity === 'critical' ? 'critical' : 'warning';
164
+ const dateStr = (0, date_fns_1.format)(anomaly.weekStart, 'MMM d, yyyy');
165
+ return `
166
+ <div class="anomaly-item ${severityClass}">
167
+ <span class="anomaly-icon">${typeEmoji}</span>
168
+ <div class="anomaly-info">
169
+ <div class="anomaly-header">
170
+ <span class="anomaly-type">${anomaly.type}</span>
171
+ <span class="anomaly-date">${dateStr}</span>
172
+ <span class="anomaly-change">${anomaly.percentageChange >= 0 ? '+' : ''}${anomaly.percentageChange}%</span>
173
+ </div>
174
+ <div class="anomaly-causes">
175
+ Possible: ${anomaly.possibleCauses.slice(0, 2).join(', ')}
176
+ </div>
177
+ </div>
178
+ </div>
179
+ `;
180
+ }).join('');
181
+ return `
182
+ <div class="anomalies-section">
183
+ <h3>⚠️ Detected Anomalies</h3>
184
+ <div class="anomalies-list">
185
+ ${anomalyItems}
186
+ </div>
187
+ </div>
188
+ `;
189
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /**
3
+ * Types for HTML generation pipeline.
4
+ *
5
+ * @module generators/html/types
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ /**
3
+ * Analysis runner - executes all analyzers with shared context.
4
+ *
5
+ * @module generators/html/utils/analysisRunner
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.runAllAnalyzers = runAllAnalyzers;
9
+ const streaks_1 = require("../../../features/streaks");
10
+ const time_patterns_1 = require("../../../features/time-patterns");
11
+ const commitQualityAnalyzer_1 = require("../../../utils/commitQualityAnalyzer");
12
+ const fileHotspotAnalyzer_1 = require("../../../utils/fileHotspotAnalyzer");
13
+ const impactAnalyzer_1 = require("../../../utils/impactAnalyzer");
14
+ const knowledgeDistributionAnalyzer_1 = require("../../../utils/knowledgeDistributionAnalyzer");
15
+ const achievements_1 = require("../../../features/achievements");
16
+ const commitMapBuilder_1 = require("./commitMapBuilder");
17
+ /**
18
+ * Run all analyzers for the given context.
19
+ *
20
+ * @param context - The HTML generation context
21
+ * @param skipBodyCheck - Whether to skip commit body validation
22
+ * @param deepAnalysis - Whether to enable deep analysis
23
+ * @param leadDevFeatures - Pre-computed strategic insights (optional)
24
+ * @returns Analysis results for all views
25
+ */
26
+ function runAllAnalyzers(context, skipBodyCheck = false, deepAnalysis = false, leadDevFeatures) {
27
+ const { filteredCommits, personalCommits, dateRange, repoInfo } = context;
28
+ const { start: startDate, end: endDate } = dateRange;
29
+ // Create commit maps for overall
30
+ const { commitMap, commitDetailsMap } = (0, commitMapBuilder_1.createCommitMaps)(filteredCommits, startDate, endDate);
31
+ const totalCommits = Array.from(commitMap.values()).reduce((sum, count) => sum + count, 0);
32
+ // Create commit maps for personal
33
+ const { commitMap: personalCommitMap, commitDetailsMap: personalCommitDetailsMap } = (0, commitMapBuilder_1.createCommitMaps)(personalCommits, startDate, endDate);
34
+ const totalPersonalCommits = Array.from(personalCommitMap.values()).reduce((sum, count) => sum + count, 0);
35
+ // Run overall analyzers
36
+ const streakData = (0, streaks_1.calculateStreaks)(filteredCommits, startDate, endDate);
37
+ const timePattern = (0, time_patterns_1.analyzeTimePatterns)(filteredCommits, startDate, endDate);
38
+ const commitQuality = (0, commitQualityAnalyzer_1.analyzeCommitQuality)(filteredCommits, { skipBodyCheck });
39
+ // Run personal analyzers
40
+ const personalStreakData = (0, streaks_1.calculateStreaks)(personalCommits, startDate, endDate);
41
+ const personalTimePattern = (0, time_patterns_1.analyzeTimePatterns)(personalCommits, startDate, endDate);
42
+ const personalCommitQuality = (0, commitQualityAnalyzer_1.analyzeCommitQuality)(personalCommits, { skipBodyCheck });
43
+ // Run enterprise insight analyzers
44
+ const fileHotspots = (0, fileHotspotAnalyzer_1.analyzeFileHotspots)(repoInfo.path, startDate, endDate);
45
+ const impactAnalysis = (0, impactAnalyzer_1.analyzeImpact)(filteredCommits);
46
+ const knowledgeDistribution = (0, knowledgeDistributionAnalyzer_1.analyzeKnowledgeDistribution)(filteredCommits, repoInfo.path, deepAnalysis);
47
+ // Build analysis data for achievements
48
+ const overallAnalysisData = {
49
+ commits: filteredCommits,
50
+ totalCommits,
51
+ streakData,
52
+ timePattern,
53
+ commitQuality,
54
+ fileHotspots,
55
+ dateRange: { start: startDate, end: endDate }
56
+ };
57
+ const personalAnalysisData = {
58
+ commits: personalCommits,
59
+ totalCommits: totalPersonalCommits,
60
+ streakData: personalStreakData,
61
+ timePattern: personalTimePattern,
62
+ commitQuality: personalCommitQuality,
63
+ fileHotspots,
64
+ dateRange: { start: startDate, end: endDate }
65
+ };
66
+ // Check achievements
67
+ const achievementProgress = (0, achievements_1.checkAchievements)(overallAnalysisData);
68
+ const personalAchievementProgress = (0, achievements_1.checkAchievements)(personalAnalysisData);
69
+ return {
70
+ overall: {
71
+ commitMap,
72
+ commitDetailsMap,
73
+ totalCommits,
74
+ streakData,
75
+ timePattern,
76
+ commitQuality,
77
+ achievementProgress,
78
+ },
79
+ personal: {
80
+ commitMap: personalCommitMap,
81
+ commitDetailsMap: personalCommitDetailsMap,
82
+ totalCommits: totalPersonalCommits,
83
+ streakData: personalStreakData,
84
+ timePattern: personalTimePattern,
85
+ commitQuality: personalCommitQuality,
86
+ achievementProgress: personalAchievementProgress,
87
+ },
88
+ fileHotspots,
89
+ impactAnalysis,
90
+ knowledgeDistribution,
91
+ leadDev: leadDevFeatures,
92
+ };
93
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ /**
3
+ * Shared utility for building consistent stat cards across templates
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.buildStatCard = buildStatCard;
7
+ exports.buildStatGrid = buildStatGrid;
8
+ exports.buildCardSection = buildCardSection;
9
+ /**
10
+ * Builds a single stat card with consistent styling
11
+ */
12
+ function buildStatCard(options) {
13
+ const { icon, value, label, detail, className = '', valueClass = '' } = options;
14
+ return `
15
+ <div class="stat-card-base ${className}">
16
+ ${icon ? `<div class="stat-icon">${icon}</div>` : ''}
17
+ <div class="stat-info">
18
+ <div class="stat-label">${label}</div>
19
+ <div class="stat-value ${valueClass}">${value}</div>
20
+ ${detail ? `<div class="stat-detail">${detail}</div>` : ''}
21
+ </div>
22
+ </div>
23
+ `;
24
+ }
25
+ /**
26
+ * Builds a grid of stat cards
27
+ */
28
+ function buildStatGrid(options) {
29
+ return `
30
+ <div class="stat-grid ${options.className || ''}">
31
+ ${options.cards.map(card => buildStatCard(card)).join('')}
32
+ </div>
33
+ `;
34
+ }
35
+ /**
36
+ * Builds a card section with title and content
37
+ */
38
+ function buildCardSection(options) {
39
+ const { title, content, className = '', icon } = options;
40
+ const titleContent = icon ? `${icon} ${title}` : title;
41
+ return `
42
+ <div class="card-section ${className}">
43
+ <h3>${titleContent}</h3>
44
+ ${content}
45
+ </div>
46
+ `;
47
+ }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ /**
3
+ * Context builder for HTML generation.
4
+ *
5
+ * @module generators/html/utils/contextBuilder
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.buildHtmlContext = buildHtmlContext;
9
+ const dateRangeCalculator_1 = require("./dateRangeCalculator");
10
+ const developerStatsCalculator_1 = require("./developerStatsCalculator");
11
+ /**
12
+ * Build the HTML generation context from options.
13
+ *
14
+ * @param options - Generation options
15
+ * @returns Fully populated context for HTML generation
16
+ */
17
+ function buildHtmlContext(options) {
18
+ const { commits, repoPath, repoName, repoUrl, year = new Date().getFullYear(), monthsToShow = 12, allTime = false, } = options;
19
+ // Get current git user
20
+ const { getCurrentGitUser } = require('../../../utils/gitParser');
21
+ const currentUser = getCurrentGitUser(repoPath);
22
+ // Calculate date ranges
23
+ const dateRanges = allTime
24
+ ? (0, dateRangeCalculator_1.calculateDateRangesFromCommits)(commits)
25
+ : (0, dateRangeCalculator_1.calculateDateRanges)(year, monthsToShow);
26
+ const { startDate, endDate, weekStartDate, weekEndDate } = dateRanges;
27
+ // Filter commits to date range
28
+ const filteredCommits = commits.filter(commit => {
29
+ const commitDate = new Date(commit.date);
30
+ return commitDate >= startDate && commitDate <= endDate;
31
+ });
32
+ // Filter personal commits
33
+ const personalCommits = filteredCommits.filter(c => c.author === currentUser);
34
+ // Calculate developer stats
35
+ const developerStats = (0, developerStatsCalculator_1.calculateDeveloperStats)(filteredCommits, startDate, endDate);
36
+ return {
37
+ options,
38
+ repoInfo: {
39
+ name: repoName,
40
+ url: repoUrl,
41
+ path: repoPath,
42
+ },
43
+ currentUser,
44
+ dateRange: {
45
+ start: startDate,
46
+ end: endDate,
47
+ weekStart: weekStartDate,
48
+ weekEnd: weekEndDate,
49
+ },
50
+ filteredCommits,
51
+ personalCommits,
52
+ developerStats,
53
+ };
54
+ }