repo-wrapped 0.0.7 → 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 (172) 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 +56 -56
  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 +8 -3
  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 +108 -48
  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/executiveSummarySection.js +0 -4
  97. package/dist/generators/html/templates/impactSection.js +8 -6
  98. package/dist/generators/html/templates/knowledgeSection.js +16 -2
  99. package/dist/generators/html/templates/velocitySection.js +2 -2
  100. package/dist/generators/html/types.js +7 -0
  101. package/dist/generators/html/utils/analysisRunner.js +93 -0
  102. package/dist/generators/html/utils/cardBuilder.js +47 -0
  103. package/dist/generators/html/utils/contextBuilder.js +54 -0
  104. package/dist/generators/html/utils/htmlDocumentBuilder.js +396 -0
  105. package/dist/generators/html/utils/kpiBuilder.js +76 -0
  106. package/dist/generators/html/utils/sectionWrapper.js +71 -0
  107. package/dist/generators/html/utils/styleLoader.js +2 -2
  108. package/dist/html/analysisRunner.js +93 -0
  109. package/dist/html/htmlDocumentBuilder.js +396 -0
  110. package/dist/html/index.js +29 -0
  111. package/dist/html/shared/colorUtils.js +61 -0
  112. package/dist/html/shared/commitMapBuilder.js +23 -0
  113. package/dist/html/shared/components/cardBuilder.js +47 -0
  114. package/dist/html/shared/components/index.js +18 -0
  115. package/dist/html/shared/components/kpiBuilder.js +76 -0
  116. package/dist/html/shared/components/sectionWrapper.js +71 -0
  117. package/dist/html/shared/contextBuilder.js +54 -0
  118. package/dist/html/shared/dateRangeCalculator.js +56 -0
  119. package/dist/html/shared/developerStatsCalculator.js +28 -0
  120. package/dist/html/shared/index.js +39 -0
  121. package/dist/html/shared/scriptLoader.js +15 -0
  122. package/dist/html/shared/scripts/export.js +125 -0
  123. package/dist/html/shared/scripts/knowledge.js +137 -0
  124. package/dist/html/shared/scripts/modal.js +68 -0
  125. package/dist/html/shared/scripts/navigation.js +156 -0
  126. package/dist/html/shared/scripts/tabs.js +18 -0
  127. package/dist/html/shared/scripts/tooltip.js +21 -0
  128. package/dist/html/shared/styleLoader.js +18 -0
  129. package/dist/html/shared/styles/achievements.css +387 -0
  130. package/dist/html/shared/styles/base.css +822 -0
  131. package/dist/html/shared/styles/components.css +1511 -0
  132. package/dist/html/shared/styles/knowledge.css +242 -0
  133. package/dist/html/shared/styles/strategic-insights.css +1337 -0
  134. package/dist/html/shared/weekGrouper.js +27 -0
  135. package/dist/html/types.js +7 -0
  136. package/dist/index.js +39 -39
  137. package/dist/test/helpers/commitFactory.js +166 -0
  138. package/dist/test/helpers/dateUtils.js +101 -0
  139. package/dist/test/helpers/index.js +29 -0
  140. package/dist/test/setup.js +17 -0
  141. package/dist/test/smoke.test.js +94 -0
  142. package/dist/types/achievements.js +7 -0
  143. package/dist/types/analysis.js +7 -0
  144. package/dist/types/core.js +7 -0
  145. package/dist/types/index.js +38 -0
  146. package/dist/types/options.js +7 -0
  147. package/dist/types/shared.js +7 -0
  148. package/dist/types/strategic.js +7 -0
  149. package/dist/types/summary.js +7 -0
  150. package/dist/utils/achievementDefinitions.js +22 -22
  151. package/dist/utils/analyzerContextBuilder.js +124 -0
  152. package/dist/utils/commitQualityAnalyzer.js +13 -2
  153. package/dist/utils/emptyResults.js +95 -0
  154. package/dist/utils/fileHotspotAnalyzer.js +4 -12
  155. package/dist/utils/gapAnalyzer.js +26 -28
  156. package/dist/utils/gitParser.test.js +363 -0
  157. package/dist/utils/htmlGenerator.js +62 -466
  158. package/dist/utils/impactAnalyzer.js +20 -19
  159. package/dist/utils/knowledgeDistributionAnalyzer.js +32 -27
  160. package/dist/utils/matrixGenerator.js +13 -13
  161. package/dist/utils/rangeComparisonAnalyzer.js +2 -2
  162. package/dist/utils/streakCalculator.js +77 -27
  163. package/dist/utils/teamAnalyzer.js +20 -1
  164. package/dist/utils/timePatternAnalyzer.js +18 -3
  165. package/dist/utils/velocityAnalyzer.js +23 -18
  166. package/dist/utils/wrappedGenerator.js +8 -8
  167. package/package.json +74 -64
  168. package/vitest.config.ts +46 -0
  169. package/SPECS.md +0 -490
  170. package/dist/cli.js +0 -24
  171. package/dist/commands/index.js +0 -24
  172. package/test-team.txt +0 -2
@@ -59,10 +59,10 @@ exports.ACHIEVEMENTS = [
59
59
  id: 'champion',
60
60
  name: 'Champion',
61
61
  emoji: '🏆',
62
- description: 'Reached 500 commits',
62
+ description: 'Reached 200 commits',
63
63
  category: 'milestone',
64
- tier: 'platinum',
65
- criteria: { type: 'commit-count', threshold: 500, comparator: '>=' },
64
+ tier: 'gold',
65
+ criteria: { type: 'commit-count', threshold: 200, comparator: '>=' },
66
66
  progress: 0,
67
67
  isUnlocked: false,
68
68
  isSecret: false
@@ -71,10 +71,10 @@ exports.ACHIEVEMENTS = [
71
71
  id: 'master',
72
72
  name: 'Master',
73
73
  emoji: '💫',
74
- description: 'Reached 1000 commits',
74
+ description: 'Reached 300 commits',
75
75
  category: 'milestone',
76
76
  tier: 'platinum',
77
- criteria: { type: 'commit-count', threshold: 1000, comparator: '>=' },
77
+ criteria: { type: 'commit-count', threshold: 300, comparator: '>=' },
78
78
  progress: 0,
79
79
  isUnlocked: false,
80
80
  isSecret: false
@@ -83,10 +83,10 @@ exports.ACHIEVEMENTS = [
83
83
  id: 'legend',
84
84
  name: 'Legend',
85
85
  emoji: '🌟',
86
- description: 'Reached 5000 commits',
86
+ description: 'Reached 500 commits',
87
87
  category: 'milestone',
88
88
  tier: 'legendary',
89
- criteria: { type: 'commit-count', threshold: 5000, comparator: '>=' },
89
+ criteria: { type: 'commit-count', threshold: 500, comparator: '>=' },
90
90
  progress: 0,
91
91
  isUnlocked: false,
92
92
  isSecret: false
@@ -98,7 +98,7 @@ exports.ACHIEVEMENTS = [
98
98
  id: 'consistency',
99
99
  name: 'Consistency',
100
100
  emoji: '📅',
101
- description: 'Maintained a 3-day commit streak',
101
+ description: 'Maintained a 3-day business day streak',
102
102
  category: 'time',
103
103
  tier: 'bronze',
104
104
  criteria: { type: 'streak', threshold: 3, comparator: '>=' },
@@ -110,10 +110,10 @@ exports.ACHIEVEMENTS = [
110
110
  id: 'week-warrior',
111
111
  name: 'Week Warrior',
112
112
  emoji: '⚡',
113
- description: 'Maintained a 7-day commit streak',
113
+ description: 'Maintained a 5-day business day streak (full week)',
114
114
  category: 'time',
115
115
  tier: 'silver',
116
- criteria: { type: 'streak', threshold: 7, comparator: '>=' },
116
+ criteria: { type: 'streak', threshold: 5, comparator: '>=' },
117
117
  progress: 0,
118
118
  isUnlocked: false,
119
119
  isSecret: false
@@ -122,10 +122,10 @@ exports.ACHIEVEMENTS = [
122
122
  id: 'streak-on-fire',
123
123
  name: 'Streak On Fire',
124
124
  emoji: '🔥',
125
- description: 'Maintained a 14-day commit streak',
125
+ description: 'Maintained a 10-day business day streak (2 weeks)',
126
126
  category: 'time',
127
127
  tier: 'gold',
128
- criteria: { type: 'streak', threshold: 14, comparator: '>=' },
128
+ criteria: { type: 'streak', threshold: 10, comparator: '>=' },
129
129
  progress: 0,
130
130
  isUnlocked: false,
131
131
  isSecret: false
@@ -134,10 +134,10 @@ exports.ACHIEVEMENTS = [
134
134
  id: 'unstoppable',
135
135
  name: 'Unstoppable',
136
136
  emoji: '💪',
137
- description: 'Maintained a 30-day commit streak',
137
+ description: 'Maintained a 20-day business day streak (1 month)',
138
138
  category: 'time',
139
139
  tier: 'platinum',
140
- criteria: { type: 'streak', threshold: 30, comparator: '>=' },
140
+ criteria: { type: 'streak', threshold: 20, comparator: '>=' },
141
141
  progress: 0,
142
142
  isUnlocked: false,
143
143
  isSecret: false
@@ -146,10 +146,10 @@ exports.ACHIEVEMENTS = [
146
146
  id: 'iron-will',
147
147
  name: 'Iron Will',
148
148
  emoji: '🦾',
149
- description: 'Maintained a 60-day commit streak',
149
+ description: 'Maintained a 40-day business day streak (2 months)',
150
150
  category: 'time',
151
151
  tier: 'platinum',
152
- criteria: { type: 'streak', threshold: 60, comparator: '>=' },
152
+ criteria: { type: 'streak', threshold: 40, comparator: '>=' },
153
153
  progress: 0,
154
154
  isUnlocked: false,
155
155
  isSecret: false
@@ -158,10 +158,10 @@ exports.ACHIEVEMENTS = [
158
158
  id: 'code-machine',
159
159
  name: 'Code Machine',
160
160
  emoji: '👾',
161
- description: 'Maintained a 100-day commit streak',
161
+ description: 'Maintained a 60-day business day streak (3 months)',
162
162
  category: 'time',
163
163
  tier: 'legendary',
164
- criteria: { type: 'streak', threshold: 100, comparator: '>=' },
164
+ criteria: { type: 'streak', threshold: 60, comparator: '>=' },
165
165
  progress: 0,
166
166
  isUnlocked: false,
167
167
  isSecret: false
@@ -230,7 +230,7 @@ exports.ACHIEVEMENTS = [
230
230
  id: 'early-bird',
231
231
  name: 'Early Bird',
232
232
  emoji: '🌅',
233
- description: '50+ commits before 9am',
233
+ description: '20+ commits before 9am',
234
234
  category: 'time',
235
235
  tier: 'silver',
236
236
  criteria: {
@@ -240,7 +240,7 @@ exports.ACHIEVEMENTS = [
240
240
  const hour = new Date(c.date).getHours();
241
241
  return hour >= 5 && hour < 9;
242
242
  }).length;
243
- return earlyCommits >= 50;
243
+ return earlyCommits >= 20;
244
244
  }
245
245
  },
246
246
  progress: 0,
@@ -251,7 +251,7 @@ exports.ACHIEVEMENTS = [
251
251
  id: 'night-owl',
252
252
  name: 'Night Owl',
253
253
  emoji: '🦉',
254
- description: '50+ commits after 9pm',
254
+ description: '20+ commits after 9pm',
255
255
  category: 'time',
256
256
  tier: 'silver',
257
257
  criteria: {
@@ -261,7 +261,7 @@ exports.ACHIEVEMENTS = [
261
261
  const hour = new Date(c.date).getHours();
262
262
  return hour >= 21 || hour < 5;
263
263
  }).length;
264
- return lateCommits >= 50;
264
+ return lateCommits >= 20;
265
265
  }
266
266
  },
267
267
  progress: 0,
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ /**
3
+ * Utility functions for building and working with AnalyzerContext.
4
+ *
5
+ * @module analyzerContextBuilder
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.isAnalyzerContext = isAnalyzerContext;
9
+ exports.buildContext = buildContext;
10
+ exports.getOption = getOption;
11
+ exports.computeFileChanges = computeFileChanges;
12
+ exports.withOptions = withOptions;
13
+ /**
14
+ * Type guard to check if an argument is an AnalyzerContext.
15
+ *
16
+ * @param arg - Value to check
17
+ * @returns True if the argument is an AnalyzerContext
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * function analyze(arg1: CommitData[] | AnalyzerContext, ...rest: unknown[]) {
22
+ * if (isAnalyzerContext(arg1)) {
23
+ * // Use arg1.commits, arg1.dateRange, etc.
24
+ * } else {
25
+ * // Use positional parameters
26
+ * }
27
+ * }
28
+ * ```
29
+ */
30
+ function isAnalyzerContext(arg) {
31
+ return (typeof arg === 'object' &&
32
+ arg !== null &&
33
+ 'commits' in arg &&
34
+ 'dateRange' in arg &&
35
+ typeof arg.dateRange === 'object' &&
36
+ arg.dateRange !== null &&
37
+ 'start' in arg.dateRange &&
38
+ 'end' in arg.dateRange);
39
+ }
40
+ /**
41
+ * Build an AnalyzerContext from individual parameters.
42
+ *
43
+ * @param commits - Array of commits to analyze
44
+ * @param startDate - Start of the analysis period
45
+ * @param endDate - End of the analysis period
46
+ * @param repoPath - Path to the repository (optional)
47
+ * @param options - Additional analyzer options (optional)
48
+ * @returns A fully constructed AnalyzerContext
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const ctx = buildContext(commits, startDate, endDate, '/path/to/repo', { windowWeeks: 8 });
53
+ * const velocity = analyzeVelocity(ctx);
54
+ * ```
55
+ */
56
+ function buildContext(commits, startDate, endDate, repoPath = '', options) {
57
+ return {
58
+ commits,
59
+ dateRange: {
60
+ start: startDate,
61
+ end: endDate,
62
+ },
63
+ repoPath,
64
+ options,
65
+ };
66
+ }
67
+ /**
68
+ * Get an option value from context with a default fallback.
69
+ *
70
+ * @param ctx - The analyzer context
71
+ * @param key - The option key to retrieve
72
+ * @param defaultValue - Default value if option is not set
73
+ * @returns The option value or the default
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * const windowWeeks = getOption(ctx, 'windowWeeks', 4);
78
+ * const thresholdDays = getOption(ctx, 'thresholdDays', 3);
79
+ * ```
80
+ */
81
+ function getOption(ctx, key, defaultValue) {
82
+ return ctx.options?.[key] ?? defaultValue;
83
+ }
84
+ /**
85
+ * Compute file change data from commits (cached).
86
+ *
87
+ * This is an expensive operation that should only be done once
88
+ * and then shared across analyzers via the context.
89
+ *
90
+ * @param _repoPath - Path to the git repository
91
+ * @param _commits - Commits to analyze for file changes
92
+ * @returns Map of file paths to change data
93
+ *
94
+ * @remarks
95
+ * This is a placeholder for future implementation.
96
+ * Currently returns an empty map.
97
+ */
98
+ function computeFileChanges(_repoPath, _commits) {
99
+ // TODO: Implement git log --name-only parsing
100
+ // This would be called once and shared across impact/knowledge analyzers
101
+ return new Map();
102
+ }
103
+ /**
104
+ * Clone a context with merged options.
105
+ *
106
+ * @param ctx - Original context
107
+ * @param additionalOptions - Options to merge
108
+ * @returns New context with merged options
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * const velocityCtx = withOptions(ctx, { windowWeeks: 8 });
113
+ * const gapCtx = withOptions(ctx, { thresholdDays: 5, excludeWeekends: true });
114
+ * ```
115
+ */
116
+ function withOptions(ctx, additionalOptions) {
117
+ return {
118
+ ...ctx,
119
+ options: {
120
+ ...ctx.options,
121
+ ...additionalOptions,
122
+ },
123
+ };
124
+ }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.analyzeCommitQuality = analyzeCommitQuality;
4
4
  exports.getQualityRating = getQualityRating;
5
5
  exports.getQualityLevel = getQualityLevel;
6
+ const analyzerContextBuilder_1 = require("./analyzerContextBuilder");
6
7
  const CONVENTIONAL_COMMIT_REGEX = /^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?!?:\s.+/;
7
8
  const CODE_HYGIENE_PATTERNS = {
8
9
  quickFix: /fix(ed)?\s+(typo|spelling|grammar)/i,
@@ -24,8 +25,18 @@ const IMPERATIVE_STARTERS = [
24
25
  'improve', 'optimize', 'enhance', 'change', 'move', 'rename', 'extract',
25
26
  'merge', 'bump', 'revert', 'document', 'test', 'upgrade', 'downgrade'
26
27
  ];
27
- function analyzeCommitQuality(commits, options = {}) {
28
- const { skipBodyCheck = false } = options;
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
+ }
29
40
  if (commits.length === 0) {
30
41
  return getEmptyQuality();
31
42
  }
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ /**
3
+ * Centralized empty result factories for all analyzers
4
+ * Provides consistent default values when there's no data to analyze
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.getEmptyImpactAnalysis = getEmptyImpactAnalysis;
8
+ exports.getEmptyVelocityAnalysis = getEmptyVelocityAnalysis;
9
+ exports.getEmptyGapAnalysis = getEmptyGapAnalysis;
10
+ exports.getEmptyKnowledgeDistribution = getEmptyKnowledgeDistribution;
11
+ exports.getEmptyFileHotspotAnalysis = getEmptyFileHotspotAnalysis;
12
+ const date_fns_1 = require("date-fns");
13
+ /**
14
+ * Creates an empty impact analysis result
15
+ */
16
+ function getEmptyImpactAnalysis() {
17
+ return {
18
+ overallScore: 0,
19
+ scoreBreakdown: {
20
+ coreContributions: 0,
21
+ featureWork: 0,
22
+ maintenanceWork: 0,
23
+ documentationWork: 0,
24
+ },
25
+ topImpactFiles: [],
26
+ impactTrend: 'stable',
27
+ insights: ['No commit data available for analysis']
28
+ };
29
+ }
30
+ /**
31
+ * Creates an empty velocity analysis result
32
+ */
33
+ function getEmptyVelocityAnalysis() {
34
+ return {
35
+ timeline: [],
36
+ overallTrend: 'stable',
37
+ trendPercentage: 0,
38
+ averageCommitsPerWeek: 0,
39
+ peakWeek: { weekStart: new Date(), commits: 0 },
40
+ lowestWeek: { weekStart: new Date(), commits: 0 },
41
+ anomalies: [],
42
+ };
43
+ }
44
+ /**
45
+ * Creates an empty gap analysis result
46
+ */
47
+ function getEmptyGapAnalysis(startDate, endDate) {
48
+ const totalDays = (0, date_fns_1.differenceInDays)(endDate, startDate) + 1;
49
+ return {
50
+ gaps: [{
51
+ start: startDate,
52
+ end: endDate,
53
+ durationDays: totalDays,
54
+ commitBefore: null,
55
+ commitAfter: null,
56
+ possibleType: 'blocker',
57
+ }],
58
+ totalGapDays: totalDays,
59
+ percentageOfPeriodInGaps: 100,
60
+ longestGap: null,
61
+ averageGapLength: totalDays,
62
+ gapFrequency: 0,
63
+ patterns: [],
64
+ riskLevel: 'critical',
65
+ riskFactors: ['No commits found in the analysis period'],
66
+ };
67
+ }
68
+ /**
69
+ * Creates an empty knowledge distribution result
70
+ */
71
+ function getEmptyKnowledgeDistribution() {
72
+ return {
73
+ directories: [],
74
+ busFactorRisk: {
75
+ overall: 0,
76
+ level: 'low',
77
+ criticalPaths: []
78
+ },
79
+ knowledgeSilos: [],
80
+ sharedKnowledge: [],
81
+ recommendations: ['No commit data available for analysis']
82
+ };
83
+ }
84
+ /**
85
+ * Creates an empty file hotspot analysis result
86
+ */
87
+ function getEmptyFileHotspotAnalysis() {
88
+ return {
89
+ topFiles: [],
90
+ topDirectories: [],
91
+ technicalDebt: [],
92
+ ownershipRisks: [],
93
+ totalFilesAnalyzed: 0
94
+ };
95
+ }
@@ -4,6 +4,7 @@ exports.analyzeFileHotspots = analyzeFileHotspots;
4
4
  exports.getRiskLevelColor = getRiskLevelColor;
5
5
  exports.getOwnershipIcon = getOwnershipIcon;
6
6
  const child_process_1 = require("child_process");
7
+ const emptyResults_1 = require("./emptyResults");
7
8
  function analyzeFileHotspots(repoPath, startDate, endDate) {
8
9
  try {
9
10
  // Get file changes with author info from git log
@@ -15,10 +16,10 @@ function analyzeFileHotspots(repoPath, startDate, endDate) {
15
16
  }
16
17
  catch (gitError) {
17
18
  // Git command failed, likely not in a git repo or no commits in range
18
- return getEmptyAnalysis();
19
+ return (0, emptyResults_1.getEmptyFileHotspotAnalysis)();
19
20
  }
20
21
  if (!gitLog) {
21
- return getEmptyAnalysis();
22
+ return (0, emptyResults_1.getEmptyFileHotspotAnalysis)();
22
23
  }
23
24
  // Parse git log output
24
25
  const fileMap = new Map();
@@ -91,7 +92,7 @@ function analyzeFileHotspots(repoPath, startDate, endDate) {
91
92
  }
92
93
  catch (error) {
93
94
  console.error('Error analyzing file hotspots:', error);
94
- return getEmptyAnalysis();
95
+ return (0, emptyResults_1.getEmptyFileHotspotAnalysis)();
95
96
  }
96
97
  }
97
98
  function shouldIgnoreFile(path) {
@@ -241,15 +242,6 @@ function analyzeOwnership(files) {
241
242
  .sort((a, b) => b.busFactorRisk - a.busFactorRisk)
242
243
  .slice(0, 10);
243
244
  }
244
- function getEmptyAnalysis() {
245
- return {
246
- topFiles: [],
247
- topDirectories: [],
248
- technicalDebt: [],
249
- ownershipRisks: [],
250
- totalFilesAnalyzed: 0
251
- };
252
- }
253
245
  function getRiskLevelColor(level) {
254
246
  switch (level) {
255
247
  case 'critical': return '🔴';
@@ -3,20 +3,39 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.analyzeGaps = analyzeGaps;
4
4
  exports.formatGapInsights = formatGapInsights;
5
5
  const date_fns_1 = require("date-fns");
6
- /**
7
- * Analyzes gaps in activity to identify blockers and disruptions
8
- */
9
- function analyzeGaps(commits, startDate, endDate, thresholdDays = 3, excludeWeekends = false) {
6
+ const emptyResults_1 = require("./emptyResults");
7
+ const analyzerContextBuilder_1 = require("./analyzerContextBuilder");
8
+ function analyzeGaps(ctxOrCommits, startDate, endDate, thresholdDays = 3, excludeWeekends = false) {
9
+ // Normalize to internal variables
10
+ let commits;
11
+ let start;
12
+ let end;
13
+ let threshold;
14
+ let skipWeekends;
15
+ if ((0, analyzerContextBuilder_1.isAnalyzerContext)(ctxOrCommits)) {
16
+ commits = ctxOrCommits.commits;
17
+ start = ctxOrCommits.dateRange.start;
18
+ end = ctxOrCommits.dateRange.end;
19
+ threshold = (0, analyzerContextBuilder_1.getOption)(ctxOrCommits, 'thresholdDays', 3);
20
+ skipWeekends = (0, analyzerContextBuilder_1.getOption)(ctxOrCommits, 'excludeWeekends', false);
21
+ }
22
+ else {
23
+ commits = ctxOrCommits;
24
+ start = startDate;
25
+ end = endDate;
26
+ threshold = thresholdDays;
27
+ skipWeekends = excludeWeekends;
28
+ }
10
29
  if (commits.length === 0) {
11
- return getEmptyGapAnalysis(startDate, endDate);
30
+ return (0, emptyResults_1.getEmptyGapAnalysis)(start, end);
12
31
  }
13
32
  // Sort commits by date
14
33
  const sortedCommits = [...commits].sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
15
34
  // Find all gaps
16
- const gaps = findGaps(sortedCommits, startDate, endDate, thresholdDays, excludeWeekends);
35
+ const gaps = findGaps(sortedCommits, start, end, threshold, skipWeekends);
17
36
  // Calculate statistics
18
37
  const totalGapDays = gaps.reduce((sum, gap) => sum + gap.durationDays, 0);
19
- const totalPeriodDays = (0, date_fns_1.differenceInDays)(endDate, startDate) + 1;
38
+ const totalPeriodDays = (0, date_fns_1.differenceInDays)(end, start) + 1;
20
39
  const percentageOfPeriodInGaps = totalPeriodDays > 0
21
40
  ? Math.round((totalGapDays / totalPeriodDays) * 1000) / 10
22
41
  : 0;
@@ -245,27 +264,6 @@ function assessGapRisk(gaps, percentageInGaps, longestGap) {
245
264
  }
246
265
  return { riskLevel, riskFactors };
247
266
  }
248
- function getEmptyGapAnalysis(startDate, endDate) {
249
- const totalDays = (0, date_fns_1.differenceInDays)(endDate, startDate) + 1;
250
- return {
251
- gaps: [{
252
- start: startDate,
253
- end: endDate,
254
- durationDays: totalDays,
255
- commitBefore: null,
256
- commitAfter: null,
257
- possibleType: 'blocker',
258
- }],
259
- totalGapDays: totalDays,
260
- percentageOfPeriodInGaps: 100,
261
- longestGap: null,
262
- averageGapLength: totalDays,
263
- gapFrequency: 0,
264
- patterns: [],
265
- riskLevel: 'critical',
266
- riskFactors: ['No commits found in the analysis period'],
267
- };
268
- }
269
267
  /**
270
268
  * Format gap analysis for display
271
269
  */