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.
- package/.github/agents/complete.agent.md +257 -0
- package/.github/agents/feature-scaffold.agent.md +248 -0
- package/.github/agents/jsdoc.agent.md +243 -0
- package/.github/agents/plan.agent.md +202 -0
- package/.github/agents/spec-writer.agent.md +169 -0
- package/.github/agents/test-writer.agent.md +169 -0
- package/.stylelintrc.json +27 -0
- package/README.md +94 -94
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +446 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +446 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov.info +7039 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dist/commands/generate.js +56 -56
- package/dist/config/defaults.js +158 -0
- package/dist/config/index.js +10 -0
- package/dist/features/achievements/data/achievements.json +284 -0
- package/dist/features/achievements/engine.js +140 -0
- package/dist/features/achievements/evaluators.js +246 -0
- package/dist/features/achievements/helpers.js +58 -0
- package/dist/features/achievements/index.js +57 -0
- package/dist/features/achievements/loader.js +88 -0
- package/dist/features/achievements/template.js +155 -0
- package/dist/features/achievements/types.js +7 -0
- package/dist/features/commit-quality/analyzer.js +378 -0
- package/dist/features/commit-quality/analyzer.test.js +484 -0
- package/dist/features/commit-quality/index.js +28 -0
- package/dist/features/commit-quality/template.js +114 -0
- package/dist/features/commit-quality/types.js +2 -0
- package/dist/features/comparison/analyzer.js +222 -0
- package/dist/features/comparison/index.js +28 -0
- package/dist/features/comparison/template.js +119 -0
- package/dist/features/comparison/types.js +2 -0
- package/dist/features/contribution-graph/index.js +9 -0
- package/dist/features/contribution-graph/template.js +89 -0
- package/dist/features/events/index.js +31 -0
- package/dist/features/events/parser.js +253 -0
- package/dist/features/events/template.js +113 -0
- package/dist/features/events/types.js +2 -0
- package/dist/features/executive-summary/generator.js +275 -0
- package/dist/features/executive-summary/index.js +27 -0
- package/dist/features/executive-summary/template.js +80 -0
- package/dist/features/executive-summary/types.js +2 -0
- package/dist/features/gaps/analyzer.js +298 -0
- package/dist/features/gaps/analyzer.test.js +517 -0
- package/dist/features/gaps/index.js +27 -0
- package/dist/features/gaps/template.js +190 -0
- package/dist/features/gaps/types.js +2 -0
- package/dist/features/impact/analyzer.js +248 -0
- package/dist/features/impact/index.js +26 -0
- package/dist/features/impact/template.js +118 -0
- package/dist/features/impact/types.js +2 -0
- package/dist/features/index.js +40 -0
- package/dist/features/knowledge/analyzer.js +385 -0
- package/dist/features/knowledge/index.js +26 -0
- package/dist/features/knowledge/template.js +239 -0
- package/dist/features/knowledge/types.js +2 -0
- package/dist/features/streaks/calculator.js +184 -0
- package/dist/features/streaks/calculator.test.js +366 -0
- package/dist/features/streaks/index.js +36 -0
- package/dist/features/streaks/template.js +41 -0
- package/dist/features/streaks/types.js +9 -0
- package/dist/features/team/analyzer.js +316 -0
- package/dist/features/team/index.js +30 -0
- package/dist/features/team/template.js +146 -0
- package/dist/features/team/types.js +2 -0
- package/dist/features/time-patterns/analyzer.js +319 -0
- package/dist/features/time-patterns/analyzer.test.js +278 -0
- package/dist/features/time-patterns/index.js +37 -0
- package/dist/features/time-patterns/template.js +109 -0
- package/dist/features/time-patterns/types.js +9 -0
- package/dist/features/velocity/analyzer.js +257 -0
- package/dist/features/velocity/analyzer.test.js +383 -0
- package/dist/features/velocity/index.js +27 -0
- package/dist/features/velocity/template.js +189 -0
- package/dist/features/velocity/types.js +2 -0
- package/dist/generators/html/scripts/knowledge.js +17 -0
- package/dist/generators/html/styles/base.css +8 -3
- package/dist/generators/html/styles/components.css +121 -1
- package/dist/generators/html/styles/knowledge.css +21 -0
- package/dist/generators/html/styles/leaddev.css +108 -48
- package/dist/generators/html/styles/strategic-insights.css +1337 -0
- package/dist/generators/html/templates/commitQualitySection.js +28 -2
- package/dist/generators/html/templates/executiveSummarySection.js +0 -4
- package/dist/generators/html/templates/impactSection.js +8 -6
- package/dist/generators/html/templates/knowledgeSection.js +16 -2
- package/dist/generators/html/templates/velocitySection.js +2 -2
- package/dist/generators/html/types.js +7 -0
- package/dist/generators/html/utils/analysisRunner.js +93 -0
- package/dist/generators/html/utils/cardBuilder.js +47 -0
- package/dist/generators/html/utils/contextBuilder.js +54 -0
- package/dist/generators/html/utils/htmlDocumentBuilder.js +396 -0
- package/dist/generators/html/utils/kpiBuilder.js +76 -0
- package/dist/generators/html/utils/sectionWrapper.js +71 -0
- package/dist/generators/html/utils/styleLoader.js +2 -2
- package/dist/html/analysisRunner.js +93 -0
- package/dist/html/htmlDocumentBuilder.js +396 -0
- package/dist/html/index.js +29 -0
- package/dist/html/shared/colorUtils.js +61 -0
- package/dist/html/shared/commitMapBuilder.js +23 -0
- package/dist/html/shared/components/cardBuilder.js +47 -0
- package/dist/html/shared/components/index.js +18 -0
- package/dist/html/shared/components/kpiBuilder.js +76 -0
- package/dist/html/shared/components/sectionWrapper.js +71 -0
- package/dist/html/shared/contextBuilder.js +54 -0
- package/dist/html/shared/dateRangeCalculator.js +56 -0
- package/dist/html/shared/developerStatsCalculator.js +28 -0
- package/dist/html/shared/index.js +39 -0
- package/dist/html/shared/scriptLoader.js +15 -0
- package/dist/html/shared/scripts/export.js +125 -0
- package/dist/html/shared/scripts/knowledge.js +137 -0
- package/dist/html/shared/scripts/modal.js +68 -0
- package/dist/html/shared/scripts/navigation.js +156 -0
- package/dist/html/shared/scripts/tabs.js +18 -0
- package/dist/html/shared/scripts/tooltip.js +21 -0
- package/dist/html/shared/styleLoader.js +18 -0
- package/dist/html/shared/styles/achievements.css +387 -0
- package/dist/html/shared/styles/base.css +822 -0
- package/dist/html/shared/styles/components.css +1511 -0
- package/dist/html/shared/styles/knowledge.css +242 -0
- package/dist/html/shared/styles/strategic-insights.css +1337 -0
- package/dist/html/shared/weekGrouper.js +27 -0
- package/dist/html/types.js +7 -0
- package/dist/index.js +39 -39
- package/dist/test/helpers/commitFactory.js +166 -0
- package/dist/test/helpers/dateUtils.js +101 -0
- package/dist/test/helpers/index.js +29 -0
- package/dist/test/setup.js +17 -0
- package/dist/test/smoke.test.js +94 -0
- package/dist/types/achievements.js +7 -0
- package/dist/types/analysis.js +7 -0
- package/dist/types/core.js +7 -0
- package/dist/types/index.js +38 -0
- package/dist/types/options.js +7 -0
- package/dist/types/shared.js +7 -0
- package/dist/types/strategic.js +7 -0
- package/dist/types/summary.js +7 -0
- package/dist/utils/achievementDefinitions.js +22 -22
- package/dist/utils/analyzerContextBuilder.js +124 -0
- package/dist/utils/commitQualityAnalyzer.js +13 -2
- package/dist/utils/emptyResults.js +95 -0
- package/dist/utils/fileHotspotAnalyzer.js +4 -12
- package/dist/utils/gapAnalyzer.js +26 -28
- package/dist/utils/gitParser.test.js +363 -0
- package/dist/utils/htmlGenerator.js +62 -466
- package/dist/utils/impactAnalyzer.js +20 -19
- package/dist/utils/knowledgeDistributionAnalyzer.js +32 -27
- package/dist/utils/matrixGenerator.js +13 -13
- package/dist/utils/rangeComparisonAnalyzer.js +2 -2
- package/dist/utils/streakCalculator.js +77 -27
- package/dist/utils/teamAnalyzer.js +20 -1
- package/dist/utils/timePatternAnalyzer.js +18 -3
- package/dist/utils/velocityAnalyzer.js +23 -18
- package/dist/utils/wrappedGenerator.js +8 -8
- package/package.json +74 -64
- package/vitest.config.ts +46 -0
- package/SPECS.md +0 -490
- package/dist/cli.js +0 -24
- package/dist/commands/index.js +0 -24
- package/test-team.txt +0 -2
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadEventsFile = loadEventsFile;
|
|
37
|
+
exports.parseEventsInline = parseEventsInline;
|
|
38
|
+
exports.correlateEventsWithMetrics = correlateEventsWithMetrics;
|
|
39
|
+
exports.getEventTypeEmoji = getEventTypeEmoji;
|
|
40
|
+
exports.getEventTypeColor = getEventTypeColor;
|
|
41
|
+
exports.formatEventsInsights = formatEventsInsights;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const date_fns_1 = require("date-fns");
|
|
44
|
+
const commit_quality_1 = require("../commit-quality");
|
|
45
|
+
/**
|
|
46
|
+
* Load events from a JSON file
|
|
47
|
+
*/
|
|
48
|
+
function loadEventsFile(filePath) {
|
|
49
|
+
try {
|
|
50
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
51
|
+
const parsed = JSON.parse(content);
|
|
52
|
+
// Validate and transform
|
|
53
|
+
const events = (parsed.events || []).map((event) => ({
|
|
54
|
+
date: new Date(event.date),
|
|
55
|
+
label: event.label,
|
|
56
|
+
type: validateEventType(event.type),
|
|
57
|
+
description: event.description,
|
|
58
|
+
}));
|
|
59
|
+
return { events };
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (error.code === 'ENOENT') {
|
|
63
|
+
throw new Error(`Events file not found: ${filePath}`);
|
|
64
|
+
}
|
|
65
|
+
throw new Error(`Failed to parse events file: ${error.message}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Parse inline events JSON
|
|
70
|
+
*/
|
|
71
|
+
function parseEventsInline(jsonStr) {
|
|
72
|
+
try {
|
|
73
|
+
const parsed = JSON.parse(jsonStr);
|
|
74
|
+
const events = (parsed.events || [parsed]).map((event) => ({
|
|
75
|
+
date: new Date(event.date),
|
|
76
|
+
label: event.label,
|
|
77
|
+
type: validateEventType(event.type),
|
|
78
|
+
description: event.description,
|
|
79
|
+
}));
|
|
80
|
+
return { events };
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
throw new Error(`Failed to parse inline events JSON: ${error.message}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function validateEventType(type) {
|
|
87
|
+
const validTypes = ['disruption', 'attrition', 'growth', 'release', 'incident', 'external', 'custom'];
|
|
88
|
+
if (validTypes.includes(type)) {
|
|
89
|
+
return type;
|
|
90
|
+
}
|
|
91
|
+
return 'custom';
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Calculate correlation between events and metrics changes
|
|
95
|
+
*/
|
|
96
|
+
function correlateEventsWithMetrics(events, commits, windowDays = 14, skipBodyCheck = true) {
|
|
97
|
+
return events.map(event => ({
|
|
98
|
+
...event,
|
|
99
|
+
correlation: calculateEventCorrelation(event, commits, windowDays, skipBodyCheck),
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
function calculateEventCorrelation(event, commits, windowDays, skipBodyCheck) {
|
|
103
|
+
const eventDate = event.date;
|
|
104
|
+
// Before period
|
|
105
|
+
const beforeStart = (0, date_fns_1.subDays)(eventDate, windowDays);
|
|
106
|
+
const beforeEnd = (0, date_fns_1.subDays)(eventDate, 1);
|
|
107
|
+
const beforeCommits = commits.filter(c => {
|
|
108
|
+
const d = new Date(c.date);
|
|
109
|
+
return d >= beforeStart && d <= beforeEnd;
|
|
110
|
+
});
|
|
111
|
+
// After period
|
|
112
|
+
const afterStart = (0, date_fns_1.addDays)(eventDate, 1);
|
|
113
|
+
const afterEnd = (0, date_fns_1.addDays)(eventDate, windowDays);
|
|
114
|
+
const afterCommits = commits.filter(c => {
|
|
115
|
+
const d = new Date(c.date);
|
|
116
|
+
return d >= afterStart && d <= afterEnd;
|
|
117
|
+
});
|
|
118
|
+
const metricsBefore = calculatePeriodMetrics(beforeCommits, beforeStart, beforeEnd, skipBodyCheck);
|
|
119
|
+
const metricsAfter = calculatePeriodMetrics(afterCommits, afterStart, afterEnd, skipBodyCheck);
|
|
120
|
+
// Calculate changes
|
|
121
|
+
const velocityChange = calculatePercentageChange(metricsBefore.commitsPerWeek ?? 0, metricsAfter.commitsPerWeek ?? 0);
|
|
122
|
+
const qualityChange = calculatePercentageChange(metricsBefore.qualityScore ?? 0, metricsAfter.qualityScore ?? 0);
|
|
123
|
+
const activeAuthorsChange = (metricsAfter.totalAuthors ?? 0) - (metricsBefore.totalAuthors ?? 0);
|
|
124
|
+
// Generate assessment
|
|
125
|
+
const assessment = generateAssessment(event, velocityChange, qualityChange, activeAuthorsChange);
|
|
126
|
+
return {
|
|
127
|
+
metricsBefore,
|
|
128
|
+
metricsAfter,
|
|
129
|
+
impact: {
|
|
130
|
+
velocityChange,
|
|
131
|
+
qualityChange,
|
|
132
|
+
activeAuthorsChange,
|
|
133
|
+
},
|
|
134
|
+
assessment,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function calculatePeriodMetrics(commits, startDate, endDate, skipBodyCheck) {
|
|
138
|
+
const days = (0, date_fns_1.differenceInDays)(endDate, startDate) + 1;
|
|
139
|
+
const weeks = Math.max(1, days / 7);
|
|
140
|
+
const totalCommits = commits.length;
|
|
141
|
+
const commitsPerWeek = Math.round((totalCommits / weeks) * 10) / 10;
|
|
142
|
+
const totalAuthors = new Set(commits.map(c => c.author)).size;
|
|
143
|
+
const qualityResult = commits.length > 0
|
|
144
|
+
? (0, commit_quality_1.analyzeCommitQuality)(commits, { skipBodyCheck })
|
|
145
|
+
: { overallScore: 0 };
|
|
146
|
+
return {
|
|
147
|
+
totalCommits,
|
|
148
|
+
commitsPerWeek,
|
|
149
|
+
totalAuthors,
|
|
150
|
+
qualityScore: Math.round(qualityResult.overallScore * 10) / 10,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function calculatePercentageChange(before, after) {
|
|
154
|
+
if (before === 0) {
|
|
155
|
+
return after > 0 ? 100 : 0;
|
|
156
|
+
}
|
|
157
|
+
return Math.round(((after - before) / before) * 1000) / 10;
|
|
158
|
+
}
|
|
159
|
+
function generateAssessment(event, velocityChange, qualityChange, authorChange) {
|
|
160
|
+
const parts = [];
|
|
161
|
+
const eventLabel = `"${event.label}"`;
|
|
162
|
+
if (velocityChange <= -30) {
|
|
163
|
+
parts.push(`velocity dropped ${Math.abs(velocityChange)}%`);
|
|
164
|
+
}
|
|
165
|
+
else if (velocityChange >= 30) {
|
|
166
|
+
parts.push(`velocity increased ${velocityChange}%`);
|
|
167
|
+
}
|
|
168
|
+
if (qualityChange <= -20) {
|
|
169
|
+
parts.push(`quality decreased ${Math.abs(qualityChange)}%`);
|
|
170
|
+
}
|
|
171
|
+
else if (qualityChange >= 20) {
|
|
172
|
+
parts.push(`quality improved ${qualityChange}%`);
|
|
173
|
+
}
|
|
174
|
+
if (authorChange < 0) {
|
|
175
|
+
parts.push(`${Math.abs(authorChange)} fewer active contributor(s)`);
|
|
176
|
+
}
|
|
177
|
+
else if (authorChange > 0) {
|
|
178
|
+
parts.push(`${authorChange} more active contributor(s)`);
|
|
179
|
+
}
|
|
180
|
+
if (parts.length === 0) {
|
|
181
|
+
return `No significant metric changes detected after ${eventLabel}`;
|
|
182
|
+
}
|
|
183
|
+
return `After ${eventLabel}: ${parts.join(', ')}`;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Get emoji for event type
|
|
187
|
+
*/
|
|
188
|
+
function getEventTypeEmoji(type) {
|
|
189
|
+
const emojis = {
|
|
190
|
+
disruption: '⚡',
|
|
191
|
+
attrition: '👋',
|
|
192
|
+
growth: '🌱',
|
|
193
|
+
release: '🚀',
|
|
194
|
+
incident: '🔥',
|
|
195
|
+
external: '📅',
|
|
196
|
+
custom: '📌',
|
|
197
|
+
};
|
|
198
|
+
return emojis[type] || '📌';
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Get color for event type (for HTML)
|
|
202
|
+
*/
|
|
203
|
+
function getEventTypeColor(type) {
|
|
204
|
+
const colors = {
|
|
205
|
+
disruption: '#ff6b6b',
|
|
206
|
+
attrition: '#ffa94d',
|
|
207
|
+
growth: '#69db7c',
|
|
208
|
+
release: '#4dabf7',
|
|
209
|
+
incident: '#ff8787',
|
|
210
|
+
external: '#868e96',
|
|
211
|
+
custom: '#9775fa',
|
|
212
|
+
};
|
|
213
|
+
return colors[type] || '#9775fa';
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Format events for display
|
|
217
|
+
*/
|
|
218
|
+
function formatEventsInsights(events) {
|
|
219
|
+
const insights = [];
|
|
220
|
+
if (events.length === 0) {
|
|
221
|
+
return ['No events annotated'];
|
|
222
|
+
}
|
|
223
|
+
insights.push(`📅 ${events.length} Event(s) Annotated`);
|
|
224
|
+
insights.push('');
|
|
225
|
+
// Sort by date
|
|
226
|
+
const sortedEvents = [...events].sort((a, b) => a.date.getTime() - b.date.getTime());
|
|
227
|
+
for (const event of sortedEvents) {
|
|
228
|
+
const emoji = getEventTypeEmoji(event.type);
|
|
229
|
+
const dateStr = (0, date_fns_1.format)(event.date, 'MMM d, yyyy');
|
|
230
|
+
insights.push(`${emoji} ${dateStr}: ${event.label}`);
|
|
231
|
+
if (event.description) {
|
|
232
|
+
insights.push(` ${event.description}`);
|
|
233
|
+
}
|
|
234
|
+
if (event.correlation) {
|
|
235
|
+
const { impact } = event.correlation;
|
|
236
|
+
const impactParts = [];
|
|
237
|
+
if (Math.abs(impact.velocityChange) >= 10) {
|
|
238
|
+
impactParts.push(`velocity ${impact.velocityChange >= 0 ? '+' : ''}${impact.velocityChange}%`);
|
|
239
|
+
}
|
|
240
|
+
if (Math.abs(impact.qualityChange) >= 10) {
|
|
241
|
+
impactParts.push(`quality ${impact.qualityChange >= 0 ? '+' : ''}${impact.qualityChange}%`);
|
|
242
|
+
}
|
|
243
|
+
if (impact.activeAuthorsChange !== 0) {
|
|
244
|
+
impactParts.push(`${impact.activeAuthorsChange >= 0 ? '+' : ''}${impact.activeAuthorsChange} contributors`);
|
|
245
|
+
}
|
|
246
|
+
if (impactParts.length > 0) {
|
|
247
|
+
insights.push(` 📊 Impact: ${impactParts.join(', ')}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
insights.push('');
|
|
251
|
+
}
|
|
252
|
+
return insights;
|
|
253
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildEventsSection = buildEventsSection;
|
|
4
|
+
const date_fns_1 = require("date-fns");
|
|
5
|
+
const EVENT_ICONS = {
|
|
6
|
+
disruption: '⚠️',
|
|
7
|
+
attrition: '👋',
|
|
8
|
+
growth: '🌱',
|
|
9
|
+
release: '🚀',
|
|
10
|
+
incident: '🔥',
|
|
11
|
+
external: '📅',
|
|
12
|
+
custom: '📌'
|
|
13
|
+
};
|
|
14
|
+
const EVENT_COLORS = {
|
|
15
|
+
disruption: '#f59e0b',
|
|
16
|
+
attrition: '#ef4444',
|
|
17
|
+
growth: '#10b981',
|
|
18
|
+
release: '#3b82f6',
|
|
19
|
+
incident: '#dc2626',
|
|
20
|
+
external: '#6b7280',
|
|
21
|
+
custom: '#8b5cf6'
|
|
22
|
+
};
|
|
23
|
+
function buildEventsSection(events) {
|
|
24
|
+
if (!events || events.length === 0) {
|
|
25
|
+
return '<p class="no-data">No events annotated</p>';
|
|
26
|
+
}
|
|
27
|
+
const sortedEvents = [...events].sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
|
|
28
|
+
return `
|
|
29
|
+
<div class="events-section">
|
|
30
|
+
<!-- Event Legend -->
|
|
31
|
+
<div class="events-legend">
|
|
32
|
+
${Object.entries(EVENT_ICONS).map(([type, icon]) => `
|
|
33
|
+
<span class="legend-item">
|
|
34
|
+
<span class="event-icon">${icon}</span>
|
|
35
|
+
<span class="legend-label">${type}</span>
|
|
36
|
+
</span>
|
|
37
|
+
`).join('')}
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<!-- Event Stats Summary -->
|
|
41
|
+
<div class="events-summary">
|
|
42
|
+
<div class="summary-stat">
|
|
43
|
+
<span class="stat-value">${events.length}</span>
|
|
44
|
+
<span class="stat-label">Total Events</span>
|
|
45
|
+
</div>
|
|
46
|
+
${buildEventTypeCounts(events)}
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<!-- Events Timeline -->
|
|
50
|
+
<div class="events-timeline">
|
|
51
|
+
${sortedEvents.map(event => buildEventCard(event)).join('')}
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
`;
|
|
55
|
+
}
|
|
56
|
+
function buildEventTypeCounts(events) {
|
|
57
|
+
const counts = events.reduce((acc, e) => {
|
|
58
|
+
acc[e.type] = (acc[e.type] || 0) + 1;
|
|
59
|
+
return acc;
|
|
60
|
+
}, {});
|
|
61
|
+
const topTypes = Object.entries(counts)
|
|
62
|
+
.sort((a, b) => b[1] - a[1])
|
|
63
|
+
.slice(0, 3);
|
|
64
|
+
return topTypes.map(([type, count]) => `
|
|
65
|
+
<div class="summary-stat">
|
|
66
|
+
<span class="stat-value">${EVENT_ICONS[type] || '📌'} ${count}</span>
|
|
67
|
+
<span class="stat-label">${type}</span>
|
|
68
|
+
</div>
|
|
69
|
+
`).join('');
|
|
70
|
+
}
|
|
71
|
+
function buildEventCard(event) {
|
|
72
|
+
const icon = EVENT_ICONS[event.type] || '📌';
|
|
73
|
+
const color = EVENT_COLORS[event.type] || '#6b7280';
|
|
74
|
+
const dateStr = (0, date_fns_1.format)(new Date(event.date), 'MMM d, yyyy');
|
|
75
|
+
let correlationHtml = '';
|
|
76
|
+
if (event.correlation) {
|
|
77
|
+
const { velocityChange, qualityChange, activeAuthorsChange } = event.correlation.impact;
|
|
78
|
+
correlationHtml = `
|
|
79
|
+
<div class="event-correlation">
|
|
80
|
+
<div class="correlation-metrics">
|
|
81
|
+
<div class="correlation-metric ${velocityChange >= 0 ? 'positive' : 'negative'}">
|
|
82
|
+
<span class="metric-label">Velocity</span>
|
|
83
|
+
<span class="metric-value">${velocityChange >= 0 ? '+' : ''}${velocityChange.toFixed(0)}%</span>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="correlation-metric ${qualityChange >= 0 ? 'positive' : 'negative'}">
|
|
86
|
+
<span class="metric-label">Quality</span>
|
|
87
|
+
<span class="metric-value">${qualityChange >= 0 ? '+' : ''}${qualityChange.toFixed(1)}</span>
|
|
88
|
+
</div>
|
|
89
|
+
<div class="correlation-metric ${activeAuthorsChange >= 0 ? 'positive' : 'negative'}">
|
|
90
|
+
<span class="metric-label">Contributors</span>
|
|
91
|
+
<span class="metric-value">${activeAuthorsChange >= 0 ? '+' : ''}${activeAuthorsChange}</span>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
<div class="correlation-assessment">
|
|
95
|
+
<span class="assessment-icon">💡</span>
|
|
96
|
+
${event.correlation.assessment}
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
`;
|
|
100
|
+
}
|
|
101
|
+
return `
|
|
102
|
+
<div class="event-card" style="--event-color: ${color}">
|
|
103
|
+
<div class="event-header">
|
|
104
|
+
<span class="event-icon">${icon}</span>
|
|
105
|
+
<span class="event-date">${dateStr}</span>
|
|
106
|
+
<span class="event-type-badge">${event.type}</span>
|
|
107
|
+
</div>
|
|
108
|
+
<div class="event-label">${event.label}</div>
|
|
109
|
+
${event.description ? `<div class="event-description">${event.description}</div>` : ''}
|
|
110
|
+
${correlationHtml}
|
|
111
|
+
</div>
|
|
112
|
+
`;
|
|
113
|
+
}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateExecutiveSummary = generateExecutiveSummary;
|
|
4
|
+
exports.formatExecutiveSummary = formatExecutiveSummary;
|
|
5
|
+
const date_fns_1 = require("date-fns");
|
|
6
|
+
/**
|
|
7
|
+
* Generates an executive summary with KPIs, insights, and risks
|
|
8
|
+
*/
|
|
9
|
+
function generateExecutiveSummary(input) {
|
|
10
|
+
const { commits, startDate, endDate, repoName, streakData, timePattern, commitQuality, knowledgeDistribution, velocityAnalysis, gapAnalysis, } = input;
|
|
11
|
+
const kpis = generateKPIs(commits, startDate, endDate, streakData, commitQuality, velocityAnalysis);
|
|
12
|
+
const keyInsights = generateKeyInsights(commits, streakData, timePattern, commitQuality, velocityAnalysis, gapAnalysis);
|
|
13
|
+
const risks = assessRisks(knowledgeDistribution, gapAnalysis, commitQuality, timePattern);
|
|
14
|
+
const recommendations = generateRecommendations(risks, keyInsights, commitQuality);
|
|
15
|
+
return {
|
|
16
|
+
generatedAt: new Date(),
|
|
17
|
+
period: { start: startDate, end: endDate },
|
|
18
|
+
repoName,
|
|
19
|
+
kpis,
|
|
20
|
+
keyInsights,
|
|
21
|
+
risks,
|
|
22
|
+
recommendations,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function generateKPIs(commits, startDate, endDate, streakData, commitQuality, velocityAnalysis) {
|
|
26
|
+
const kpis = [];
|
|
27
|
+
const totalDays = Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)) + 1;
|
|
28
|
+
const totalWeeks = Math.max(1, Math.ceil(totalDays / 7));
|
|
29
|
+
// 1. Velocity KPI
|
|
30
|
+
const commitsPerWeek = Math.round((commits.length / totalWeeks) * 10) / 10;
|
|
31
|
+
const velocityTrend = velocityAnalysis?.overallTrend || 'stable';
|
|
32
|
+
const velocityTrendPct = velocityAnalysis?.trendPercentage || 0;
|
|
33
|
+
kpis.push({
|
|
34
|
+
name: 'Velocity',
|
|
35
|
+
value: `${commitsPerWeek}/week`,
|
|
36
|
+
trend: velocityTrend === 'increasing' ? 'up' : velocityTrend === 'decreasing' ? 'down' : 'stable',
|
|
37
|
+
trendValue: `${velocityTrendPct >= 0 ? '+' : ''}${velocityTrendPct}%`,
|
|
38
|
+
status: commitsPerWeek >= 10 ? 'green' : commitsPerWeek >= 5 ? 'yellow' : 'red',
|
|
39
|
+
benchmark: 'vs start of period',
|
|
40
|
+
});
|
|
41
|
+
// 2. Quality Score KPI
|
|
42
|
+
const qualityScore = Math.round(commitQuality.overallScore * 10) / 10;
|
|
43
|
+
kpis.push({
|
|
44
|
+
name: 'Quality Score',
|
|
45
|
+
value: `${qualityScore}/10`,
|
|
46
|
+
trend: qualityScore >= 7 ? 'up' : qualityScore >= 5 ? 'stable' : 'down',
|
|
47
|
+
trendValue: qualityScore >= 7 ? 'Good' : qualityScore >= 5 ? 'Fair' : 'Needs work',
|
|
48
|
+
status: qualityScore >= 7 ? 'green' : qualityScore >= 5 ? 'yellow' : 'red',
|
|
49
|
+
});
|
|
50
|
+
// 3. Active Contributors
|
|
51
|
+
const uniqueAuthors = new Set(commits.map(c => c.author)).size;
|
|
52
|
+
kpis.push({
|
|
53
|
+
name: 'Active Contributors',
|
|
54
|
+
value: uniqueAuthors,
|
|
55
|
+
trend: 'stable',
|
|
56
|
+
trendValue: `${uniqueAuthors} developer${uniqueAuthors !== 1 ? 's' : ''}`,
|
|
57
|
+
status: uniqueAuthors >= 3 ? 'green' : uniqueAuthors >= 2 ? 'yellow' : 'red',
|
|
58
|
+
});
|
|
59
|
+
// 4. Consistency
|
|
60
|
+
const consistencyPct = Math.round(streakData.activeDayPercentage);
|
|
61
|
+
kpis.push({
|
|
62
|
+
name: 'Consistency',
|
|
63
|
+
value: `${consistencyPct}%`,
|
|
64
|
+
trend: consistencyPct >= 50 ? 'up' : consistencyPct >= 30 ? 'stable' : 'down',
|
|
65
|
+
trendValue: `${streakData.totalActiveDays}/${totalDays} days active`,
|
|
66
|
+
status: consistencyPct >= 50 ? 'green' : consistencyPct >= 30 ? 'yellow' : 'red',
|
|
67
|
+
});
|
|
68
|
+
// 5. Longest Streak
|
|
69
|
+
kpis.push({
|
|
70
|
+
name: 'Best Streak',
|
|
71
|
+
value: `${streakData.longestStreak.days} days`,
|
|
72
|
+
trend: streakData.longestStreak.days >= 7 ? 'up' : 'stable',
|
|
73
|
+
trendValue: streakData.currentStreak.isActive ? 'Current active' : 'Historical',
|
|
74
|
+
status: streakData.longestStreak.days >= 14 ? 'green' : streakData.longestStreak.days >= 7 ? 'yellow' : 'red',
|
|
75
|
+
});
|
|
76
|
+
return kpis;
|
|
77
|
+
}
|
|
78
|
+
function generateKeyInsights(commits, streakData, timePattern, commitQuality, velocityAnalysis, gapAnalysis) {
|
|
79
|
+
const insights = [];
|
|
80
|
+
// Velocity insight
|
|
81
|
+
if (velocityAnalysis) {
|
|
82
|
+
if (velocityAnalysis.overallTrend === 'decreasing' && velocityAnalysis.trendPercentage <= -20) {
|
|
83
|
+
insights.push({
|
|
84
|
+
type: 'negative',
|
|
85
|
+
insight: `Velocity has decreased ${Math.abs(velocityAnalysis.trendPercentage)}% over this period`,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
else if (velocityAnalysis.overallTrend === 'increasing' && velocityAnalysis.trendPercentage >= 20) {
|
|
89
|
+
insights.push({
|
|
90
|
+
type: 'positive',
|
|
91
|
+
insight: `Velocity has increased ${velocityAnalysis.trendPercentage}% over this period`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
// Anomalies
|
|
95
|
+
const criticalAnomalies = velocityAnalysis.anomalies.filter(a => a.severity === 'critical');
|
|
96
|
+
if (criticalAnomalies.length >= 2) {
|
|
97
|
+
insights.push({
|
|
98
|
+
type: 'negative',
|
|
99
|
+
insight: `${criticalAnomalies.length} critical productivity drops detected - potential blockers or disruptions`,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Gap insight
|
|
104
|
+
if (gapAnalysis && gapAnalysis.gaps.length > 0) {
|
|
105
|
+
if (gapAnalysis.riskLevel === 'critical' || gapAnalysis.riskLevel === 'high') {
|
|
106
|
+
insights.push({
|
|
107
|
+
type: 'negative',
|
|
108
|
+
insight: `${gapAnalysis.totalGapDays} days lost to activity gaps (${gapAnalysis.percentageOfPeriodInGaps}% of period)`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Quality insight
|
|
113
|
+
if (commitQuality.overallScore >= 8) {
|
|
114
|
+
insights.push({
|
|
115
|
+
type: 'positive',
|
|
116
|
+
insight: 'Excellent commit quality with clear, well-structured messages',
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
else if (commitQuality.overallScore < 5) {
|
|
120
|
+
insights.push({
|
|
121
|
+
type: 'negative',
|
|
122
|
+
insight: `Commit quality score of ${Math.round(commitQuality.overallScore * 10) / 10}/10 indicates room for improvement`,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
// Burnout insight
|
|
126
|
+
if (timePattern.burnoutRisk.level === 'high') {
|
|
127
|
+
insights.push({
|
|
128
|
+
type: 'negative',
|
|
129
|
+
insight: 'High burnout risk indicators detected (late nights, irregular hours)',
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
// Consistency insight
|
|
133
|
+
if (streakData.activeDayPercentage >= 60) {
|
|
134
|
+
insights.push({
|
|
135
|
+
type: 'positive',
|
|
136
|
+
insight: `Strong consistency with ${Math.round(streakData.activeDayPercentage)}% of days active`,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// Conventional commits
|
|
140
|
+
if (commitQuality.conventionalCommits.adherence >= 80) {
|
|
141
|
+
insights.push({
|
|
142
|
+
type: 'positive',
|
|
143
|
+
insight: `${Math.round(commitQuality.conventionalCommits.adherence)}% conventional commit adherence enables better automation`,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
// Ensure we have at least 3 insights
|
|
147
|
+
if (insights.length < 3) {
|
|
148
|
+
insights.push({
|
|
149
|
+
type: 'neutral',
|
|
150
|
+
insight: `${commits.length} commits analyzed across ${streakData.totalActiveDays} active days`,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return insights.slice(0, 5);
|
|
154
|
+
}
|
|
155
|
+
function assessRisks(knowledgeDistribution, gapAnalysis, commitQuality, timePattern) {
|
|
156
|
+
const risks = [];
|
|
157
|
+
// Bus factor risk
|
|
158
|
+
if (knowledgeDistribution) {
|
|
159
|
+
const busFactorLevel = knowledgeDistribution.busFactorRisk.level;
|
|
160
|
+
if (busFactorLevel === 'critical' || busFactorLevel === 'high') {
|
|
161
|
+
risks.push({
|
|
162
|
+
category: 'Knowledge Distribution',
|
|
163
|
+
level: busFactorLevel === 'critical' ? 'high' : 'medium',
|
|
164
|
+
description: `Bus factor risk: ${knowledgeDistribution.knowledgeSilos.length} areas have single-owner knowledge`,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// Gap/blocker risk
|
|
169
|
+
if (gapAnalysis && gapAnalysis.riskLevel !== 'low') {
|
|
170
|
+
risks.push({
|
|
171
|
+
category: 'Productivity',
|
|
172
|
+
level: gapAnalysis.riskLevel === 'critical' ? 'high' : gapAnalysis.riskLevel,
|
|
173
|
+
description: `${gapAnalysis.gaps.length} activity gaps totaling ${gapAnalysis.totalGapDays} days of lost productivity`,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
// Quality risk
|
|
177
|
+
if (commitQuality && commitQuality.overallScore < 5) {
|
|
178
|
+
risks.push({
|
|
179
|
+
category: 'Code Quality',
|
|
180
|
+
level: commitQuality.overallScore < 3 ? 'high' : 'medium',
|
|
181
|
+
description: 'Low commit quality may indicate rushed work or unclear requirements',
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
// Burnout risk
|
|
185
|
+
if (timePattern && timePattern.burnoutRisk.level === 'high') {
|
|
186
|
+
risks.push({
|
|
187
|
+
category: 'Team Health',
|
|
188
|
+
level: 'medium',
|
|
189
|
+
description: `Burnout indicators: ${timePattern.burnoutRisk.indicators.slice(0, 2).join(', ')}`,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
// Sort by level
|
|
193
|
+
const levelOrder = { high: 0, medium: 1, low: 2 };
|
|
194
|
+
risks.sort((a, b) => levelOrder[a.level] - levelOrder[b.level]);
|
|
195
|
+
return risks;
|
|
196
|
+
}
|
|
197
|
+
function generateRecommendations(risks, insights, commitQuality) {
|
|
198
|
+
const recommendations = [];
|
|
199
|
+
// Based on risks
|
|
200
|
+
for (const risk of risks) {
|
|
201
|
+
if (risk.category === 'Knowledge Distribution') {
|
|
202
|
+
recommendations.push('Schedule knowledge sharing sessions to reduce bus factor risk');
|
|
203
|
+
}
|
|
204
|
+
else if (risk.category === 'Productivity') {
|
|
205
|
+
recommendations.push('Investigate root causes of activity gaps - potential blockers or process issues');
|
|
206
|
+
}
|
|
207
|
+
else if (risk.category === 'Code Quality') {
|
|
208
|
+
recommendations.push('Implement commit message guidelines and consider pre-commit hooks');
|
|
209
|
+
}
|
|
210
|
+
else if (risk.category === 'Team Health') {
|
|
211
|
+
recommendations.push('Review workload distribution and consider work-life balance initiatives');
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// Quality-based recommendations
|
|
215
|
+
if (commitQuality.conventionalCommits.adherence < 50) {
|
|
216
|
+
recommendations.push('Adopt conventional commits standard for better changelog generation');
|
|
217
|
+
}
|
|
218
|
+
if (commitQuality.codeHygiene.workInProgress > commitQuality.totalCommits * 0.1) {
|
|
219
|
+
recommendations.push('Reduce WIP commits by encouraging atomic, complete changes');
|
|
220
|
+
}
|
|
221
|
+
// Ensure we have at least one recommendation
|
|
222
|
+
if (recommendations.length === 0) {
|
|
223
|
+
recommendations.push('Continue current practices - metrics are within healthy ranges');
|
|
224
|
+
}
|
|
225
|
+
return [...new Set(recommendations)].slice(0, 4);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Format executive summary for terminal display
|
|
229
|
+
*/
|
|
230
|
+
function formatExecutiveSummary(summary) {
|
|
231
|
+
const lines = [];
|
|
232
|
+
lines.push('═══════════════════════════════════════════════════════════════');
|
|
233
|
+
lines.push(` 📊 EXECUTIVE SUMMARY: ${summary.repoName}`);
|
|
234
|
+
lines.push(` Period: ${(0, date_fns_1.format)(summary.period.start, 'MMM d, yyyy')} - ${(0, date_fns_1.format)(summary.period.end, 'MMM d, yyyy')}`);
|
|
235
|
+
lines.push('═══════════════════════════════════════════════════════════════');
|
|
236
|
+
lines.push('');
|
|
237
|
+
// KPIs
|
|
238
|
+
lines.push('📈 KEY PERFORMANCE INDICATORS');
|
|
239
|
+
lines.push('───────────────────────────────────────────────────────────────');
|
|
240
|
+
for (const kpi of summary.kpis) {
|
|
241
|
+
const statusEmoji = kpi.status === 'green' ? '🟢' : kpi.status === 'yellow' ? '🟡' : '🔴';
|
|
242
|
+
const trendEmoji = kpi.trend === 'up' ? '↑' : kpi.trend === 'down' ? '↓' : '→';
|
|
243
|
+
lines.push(` ${statusEmoji} ${kpi.name}: ${kpi.value} ${trendEmoji} ${kpi.trendValue}`);
|
|
244
|
+
}
|
|
245
|
+
lines.push('');
|
|
246
|
+
// Key Insights
|
|
247
|
+
lines.push('💡 KEY INSIGHTS');
|
|
248
|
+
lines.push('───────────────────────────────────────────────────────────────');
|
|
249
|
+
for (const insight of summary.keyInsights) {
|
|
250
|
+
const emoji = insight.type === 'positive' ? '✅' : insight.type === 'negative' ? '⚠️' : 'ℹ️';
|
|
251
|
+
lines.push(` ${emoji} ${insight.insight}`);
|
|
252
|
+
}
|
|
253
|
+
lines.push('');
|
|
254
|
+
// Risks
|
|
255
|
+
if (summary.risks.length > 0) {
|
|
256
|
+
lines.push('🚨 RISK ASSESSMENT');
|
|
257
|
+
lines.push('───────────────────────────────────────────────────────────────');
|
|
258
|
+
for (const risk of summary.risks) {
|
|
259
|
+
const levelEmoji = risk.level === 'high' ? '🔴' : risk.level === 'medium' ? '🟡' : '🟢';
|
|
260
|
+
lines.push(` ${levelEmoji} [${risk.level.toUpperCase()}] ${risk.category}: ${risk.description}`);
|
|
261
|
+
}
|
|
262
|
+
lines.push('');
|
|
263
|
+
}
|
|
264
|
+
// Recommendations
|
|
265
|
+
lines.push('📋 RECOMMENDATIONS');
|
|
266
|
+
lines.push('───────────────────────────────────────────────────────────────');
|
|
267
|
+
for (let i = 0; i < summary.recommendations.length; i++) {
|
|
268
|
+
lines.push(` ${i + 1}. ${summary.recommendations[i]}`);
|
|
269
|
+
}
|
|
270
|
+
lines.push('');
|
|
271
|
+
lines.push('═══════════════════════════════════════════════════════════════');
|
|
272
|
+
lines.push(` Generated: ${(0, date_fns_1.format)(summary.generatedAt, 'MMM d, yyyy HH:mm')}`);
|
|
273
|
+
lines.push('═══════════════════════════════════════════════════════════════');
|
|
274
|
+
return lines;
|
|
275
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.buildExecutiveSummarySection = exports.formatExecutiveSummary = exports.generateExecutiveSummary = void 0;
|
|
18
|
+
/**
|
|
19
|
+
* Executive Summary Feature
|
|
20
|
+
* @module features/executive-summary
|
|
21
|
+
*/
|
|
22
|
+
__exportStar(require("./types"), exports);
|
|
23
|
+
var generator_1 = require("./generator");
|
|
24
|
+
Object.defineProperty(exports, "generateExecutiveSummary", { enumerable: true, get: function () { return generator_1.generateExecutiveSummary; } });
|
|
25
|
+
Object.defineProperty(exports, "formatExecutiveSummary", { enumerable: true, get: function () { return generator_1.formatExecutiveSummary; } });
|
|
26
|
+
var template_1 = require("./template");
|
|
27
|
+
Object.defineProperty(exports, "buildExecutiveSummarySection", { enumerable: true, get: function () { return template_1.buildExecutiveSummarySection; } });
|