@boshu2/vibe-check 1.4.0 → 1.6.0
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/.agents/bundles/insight-mining-dashboard-research-2025-11-30.md +400 -0
- package/.agents/bundles/storage-enhancement-research-2025-11-30.md +292 -0
- package/.agents/bundles/timeline-feature-research-complete-2025-11-30.md +301 -0
- package/.agents/plans/insight-dashboard-plan-2025-11-30.md +1130 -0
- package/.agents/plans/json-storage-enhancement-plan.md +717 -0
- package/.agents/plans/storage-hardening-and-cache-plan.md +592 -0
- package/.agents/plans/test-coverage-gaps-plan.md +1117 -0
- package/.agents/plans/timeline-feature-plan.md +193 -0
- package/.agents/plans/vibe_timeline_research_findings.md +553 -0
- package/.claude/settings.local.json +1 -0
- package/.vibe-check/.gitignore +6 -0
- package/CHANGELOG.md +46 -0
- package/CLAUDE.md +24 -0
- package/CONTRIBUTING.md +227 -0
- package/README.md +200 -143
- package/claude-progress.json +200 -12
- package/claude-progress.txt +310 -0
- package/dashboard/app.js +75 -2
- package/dashboard/dashboard-data.json +653 -0
- package/dashboard/index.html +13 -0
- package/dashboard/styles.css +61 -0
- package/dist/analysis/cross-session-analysis.d.ts +68 -0
- package/dist/analysis/cross-session-analysis.d.ts.map +1 -0
- package/dist/analysis/cross-session-analysis.js +174 -0
- package/dist/analysis/cross-session-analysis.js.map +1 -0
- package/dist/analysis/index.d.ts +2 -0
- package/dist/analysis/index.d.ts.map +1 -0
- package/dist/analysis/index.js +12 -0
- package/dist/analysis/index.js.map +1 -0
- package/dist/cli.js +10 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze.d.ts +2 -0
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +105 -2
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/cache.d.ts +6 -0
- package/dist/commands/cache.d.ts.map +1 -0
- package/dist/commands/cache.js +168 -0
- package/dist/commands/cache.js.map +1 -0
- package/dist/commands/dashboard.d.ts +8 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +109 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/index.d.ts +3 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +8 -1
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/profile.d.ts.map +1 -1
- package/dist/commands/profile.js +140 -31
- package/dist/commands/profile.js.map +1 -1
- package/dist/commands/timeline.d.ts +14 -0
- package/dist/commands/timeline.d.ts.map +1 -0
- package/dist/commands/timeline.js +462 -0
- package/dist/commands/timeline.js.map +1 -0
- package/dist/gamification/badges.d.ts +29 -0
- package/dist/gamification/badges.d.ts.map +1 -0
- package/dist/gamification/badges.js +114 -0
- package/dist/gamification/badges.js.map +1 -0
- package/dist/gamification/challenges.d.ts +42 -0
- package/dist/gamification/challenges.d.ts.map +1 -0
- package/dist/gamification/challenges.js +184 -0
- package/dist/gamification/challenges.js.map +1 -0
- package/dist/gamification/hall-of-fame.d.ts +17 -0
- package/dist/gamification/hall-of-fame.d.ts.map +1 -0
- package/dist/gamification/hall-of-fame.js +64 -0
- package/dist/gamification/hall-of-fame.js.map +1 -0
- package/dist/gamification/leaderboards.d.ts +49 -0
- package/dist/gamification/leaderboards.d.ts.map +1 -0
- package/dist/gamification/leaderboards.js +179 -0
- package/dist/gamification/leaderboards.js.map +1 -0
- package/dist/gamification/share.d.ts +29 -0
- package/dist/gamification/share.d.ts.map +1 -0
- package/dist/gamification/share.js +57 -0
- package/dist/gamification/share.js.map +1 -0
- package/dist/gamification/stats.d.ts +34 -0
- package/dist/gamification/stats.d.ts.map +1 -0
- package/dist/gamification/stats.js +91 -0
- package/dist/gamification/stats.js.map +1 -0
- package/dist/gamification/streaks.d.ts +9 -1
- package/dist/gamification/streaks.d.ts.map +1 -1
- package/dist/gamification/streaks.js +37 -4
- package/dist/gamification/streaks.js.map +1 -1
- package/dist/gamification/types.d.ts +35 -0
- package/dist/gamification/types.d.ts.map +1 -1
- package/dist/gamification/types.js +11 -3
- package/dist/gamification/types.js.map +1 -1
- package/dist/gamification/xp.d.ts +6 -2
- package/dist/gamification/xp.d.ts.map +1 -1
- package/dist/gamification/xp.js +27 -5
- package/dist/gamification/xp.js.map +1 -1
- package/dist/git.d.ts +24 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +94 -0
- package/dist/git.js.map +1 -1
- package/dist/insights/generators.d.ts +44 -0
- package/dist/insights/generators.d.ts.map +1 -0
- package/dist/insights/generators.js +289 -0
- package/dist/insights/generators.js.map +1 -0
- package/dist/insights/index.d.ts +16 -0
- package/dist/insights/index.d.ts.map +1 -0
- package/dist/insights/index.js +171 -0
- package/dist/insights/index.js.map +1 -0
- package/dist/insights/types.d.ts +93 -0
- package/dist/insights/types.d.ts.map +1 -0
- package/dist/insights/types.js +6 -0
- package/dist/insights/types.js.map +1 -0
- package/dist/output/terminal.d.ts.map +1 -1
- package/dist/output/terminal.js +39 -0
- package/dist/output/terminal.js.map +1 -1
- package/dist/output/timeline-html.d.ts +6 -0
- package/dist/output/timeline-html.d.ts.map +1 -0
- package/dist/output/timeline-html.js +389 -0
- package/dist/output/timeline-html.js.map +1 -0
- package/dist/output/timeline-markdown.d.ts +6 -0
- package/dist/output/timeline-markdown.d.ts.map +1 -0
- package/dist/output/timeline-markdown.js +167 -0
- package/dist/output/timeline-markdown.js.map +1 -0
- package/dist/output/timeline.d.ts +9 -0
- package/dist/output/timeline.d.ts.map +1 -0
- package/dist/output/timeline.js +318 -0
- package/dist/output/timeline.js.map +1 -0
- package/dist/patterns/detour.d.ts +32 -0
- package/dist/patterns/detour.d.ts.map +1 -0
- package/dist/patterns/detour.js +137 -0
- package/dist/patterns/detour.js.map +1 -0
- package/dist/patterns/flow-state.d.ts +16 -0
- package/dist/patterns/flow-state.d.ts.map +1 -0
- package/dist/patterns/flow-state.js +40 -0
- package/dist/patterns/flow-state.js.map +1 -0
- package/dist/patterns/index.d.ts +8 -0
- package/dist/patterns/index.d.ts.map +1 -0
- package/dist/patterns/index.js +22 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/patterns/intervention-effectiveness.d.ts +42 -0
- package/dist/patterns/intervention-effectiveness.d.ts.map +1 -0
- package/dist/patterns/intervention-effectiveness.js +196 -0
- package/dist/patterns/intervention-effectiveness.js.map +1 -0
- package/dist/patterns/late-night.d.ts +30 -0
- package/dist/patterns/late-night.d.ts.map +1 -0
- package/dist/patterns/late-night.js +141 -0
- package/dist/patterns/late-night.js.map +1 -0
- package/dist/patterns/post-delete-sprint.d.ts +28 -0
- package/dist/patterns/post-delete-sprint.d.ts.map +1 -0
- package/dist/patterns/post-delete-sprint.js +85 -0
- package/dist/patterns/post-delete-sprint.js.map +1 -0
- package/dist/patterns/spiral-regression.d.ts +49 -0
- package/dist/patterns/spiral-regression.d.ts.map +1 -0
- package/dist/patterns/spiral-regression.js +219 -0
- package/dist/patterns/spiral-regression.js.map +1 -0
- package/dist/patterns/thrashing.d.ts +25 -0
- package/dist/patterns/thrashing.d.ts.map +1 -0
- package/dist/patterns/thrashing.js +111 -0
- package/dist/patterns/thrashing.js.map +1 -0
- package/dist/storage/atomic.d.ts +40 -0
- package/dist/storage/atomic.d.ts.map +1 -0
- package/dist/storage/atomic.js +155 -0
- package/dist/storage/atomic.js.map +1 -0
- package/dist/storage/commit-log.d.ts +35 -0
- package/dist/storage/commit-log.d.ts.map +1 -0
- package/dist/storage/commit-log.js +128 -0
- package/dist/storage/commit-log.js.map +1 -0
- package/dist/storage/index.d.ts +5 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +33 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/schema.d.ts +32 -0
- package/dist/storage/schema.d.ts.map +1 -0
- package/dist/storage/schema.js +37 -0
- package/dist/storage/schema.js.map +1 -0
- package/dist/storage/timeline-store.d.ts +117 -0
- package/dist/storage/timeline-store.d.ts.map +1 -0
- package/dist/storage/timeline-store.js +438 -0
- package/dist/storage/timeline-store.js.map +1 -0
- package/dist/types.d.ts +96 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/ARCHITECTURE.md +458 -0
- package/docs/DATA-ARCHITECTURE.md +565 -0
- package/docs/GAMIFICATION.md +564 -0
- package/docs/JSON-STORAGE-PATTERNS.md +512 -0
- package/docs/METRICS-EXPLAINED.md +394 -0
- package/docs/UNIFIED-ECOSYSTEM.md +560 -0
- package/docs/VIBE-ECOSYSTEM.md +406 -0
- package/feature-list.json +103 -1
- package/package.json +2 -1
- package/vitest.config.ts +1 -5
- package/.vibe-check/calibration.json +0 -38
- package/.vibe-check/latest.json +0 -114
- package/.vibe-check/sessions.json +0 -34
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.formatTimelineTerminal = formatTimelineTerminal;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const date_fns_1 = require("date-fns");
|
|
9
|
+
/**
|
|
10
|
+
* Format timeline for terminal output
|
|
11
|
+
*/
|
|
12
|
+
function formatTimelineTerminal(timeline, options = {}) {
|
|
13
|
+
const lines = [];
|
|
14
|
+
// Header
|
|
15
|
+
lines.push('');
|
|
16
|
+
lines.push(chalk_1.default.bold.cyan('═'.repeat(64)));
|
|
17
|
+
lines.push(chalk_1.default.bold.cyan(' VIBE-CHECK TIMELINE'));
|
|
18
|
+
const dateRange = `${(0, date_fns_1.format)(timeline.from, 'MMM d')} - ${(0, date_fns_1.format)(timeline.to, 'MMM d')} (${timeline.totalDays} days)`;
|
|
19
|
+
lines.push(chalk_1.default.bold.cyan(` ${dateRange}`));
|
|
20
|
+
lines.push(chalk_1.default.bold.cyan('═'.repeat(64)));
|
|
21
|
+
// Trend line
|
|
22
|
+
lines.push('');
|
|
23
|
+
const trendBar = buildTrendSparkline(timeline.trend);
|
|
24
|
+
const activeHours = Math.round(timeline.totalActiveMinutes / 60);
|
|
25
|
+
lines.push(` ${chalk_1.default.gray('TREND')} ${trendBar} ` +
|
|
26
|
+
chalk_1.default.gray(`Active: ~${activeHours}h Commits: ${timeline.totalCommits} Features: ${timeline.totalFeatures}`));
|
|
27
|
+
// Days
|
|
28
|
+
for (const day of timeline.days) {
|
|
29
|
+
lines.push('');
|
|
30
|
+
lines.push(formatDayHeader(day));
|
|
31
|
+
lines.push(formatDaySummary(day));
|
|
32
|
+
// Check if this day should be expanded
|
|
33
|
+
const expandValue = options.expand;
|
|
34
|
+
const shouldExpand = expandValue === true ||
|
|
35
|
+
expandValue === 'all' ||
|
|
36
|
+
expandValue === '' ||
|
|
37
|
+
expandValue === 'true' ||
|
|
38
|
+
(typeof expandValue === 'string' && day.displayDate.toLowerCase().includes(expandValue.toLowerCase()));
|
|
39
|
+
if (shouldExpand) {
|
|
40
|
+
// Show session details
|
|
41
|
+
for (const session of day.sessions) {
|
|
42
|
+
lines.push(formatSessionDetail(session));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// Show session highlights
|
|
47
|
+
for (const session of day.sessions) {
|
|
48
|
+
lines.push(formatSessionHighlight(session));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Insights section
|
|
53
|
+
const insights = generateInsights(timeline);
|
|
54
|
+
if (insights.length > 0) {
|
|
55
|
+
lines.push('');
|
|
56
|
+
lines.push(chalk_1.default.bold.cyan('═'.repeat(64)));
|
|
57
|
+
lines.push(chalk_1.default.bold.white(' INSIGHTS'));
|
|
58
|
+
lines.push('');
|
|
59
|
+
for (const insight of insights) {
|
|
60
|
+
lines.push(` ${insight}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
lines.push('');
|
|
64
|
+
lines.push(chalk_1.default.bold.cyan('═'.repeat(64)));
|
|
65
|
+
lines.push(chalk_1.default.gray(` Run with ${chalk_1.default.white('--expand')} to see session details`));
|
|
66
|
+
lines.push('');
|
|
67
|
+
return lines.join('\n');
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Build a sparkline from scores
|
|
71
|
+
*/
|
|
72
|
+
function buildTrendSparkline(scores) {
|
|
73
|
+
const bars = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'];
|
|
74
|
+
return scores
|
|
75
|
+
.map(score => {
|
|
76
|
+
if (score === null)
|
|
77
|
+
return chalk_1.default.gray('▁');
|
|
78
|
+
// Score is 0-100, map to bar index
|
|
79
|
+
const idx = Math.min(7, Math.floor(score / 12.5));
|
|
80
|
+
const bar = bars[idx];
|
|
81
|
+
if (score >= 80)
|
|
82
|
+
return chalk_1.default.green(bar);
|
|
83
|
+
if (score >= 60)
|
|
84
|
+
return chalk_1.default.blue(bar);
|
|
85
|
+
if (score >= 40)
|
|
86
|
+
return chalk_1.default.yellow(bar);
|
|
87
|
+
return chalk_1.default.red(bar);
|
|
88
|
+
})
|
|
89
|
+
.join('');
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Format day header
|
|
93
|
+
*/
|
|
94
|
+
function formatDayHeader(day) {
|
|
95
|
+
const ratingStr = formatRating(day.dayRating);
|
|
96
|
+
const ratingPercent = day.dayScore !== null ? `${day.dayScore}%` : '';
|
|
97
|
+
const trophy = day.dayRating === 'ELITE' ? ' 🏆' : '';
|
|
98
|
+
return chalk_1.default.bold(` 📅 ${day.displayDate} ${'─'.repeat(30)} ${ratingPercent} ${ratingStr}${trophy}`);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Format day summary line
|
|
102
|
+
*/
|
|
103
|
+
function formatDaySummary(day) {
|
|
104
|
+
const sessionCount = day.sessions.length;
|
|
105
|
+
const spiralText = day.spiralCount === 0
|
|
106
|
+
? chalk_1.default.green('0 spirals')
|
|
107
|
+
: chalk_1.default.yellow(`${day.spiralCount} spiral${day.spiralCount > 1 ? 's' : ''}`);
|
|
108
|
+
return chalk_1.default.gray(` ${sessionCount} session${sessionCount > 1 ? 's' : ''}, ` +
|
|
109
|
+
`${day.totalCommits} commits, ${spiralText}, ` +
|
|
110
|
+
chalk_1.default.green(`+${day.totalXp} XP`));
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Format session highlight (collapsed view)
|
|
114
|
+
*/
|
|
115
|
+
function formatSessionHighlight(session) {
|
|
116
|
+
const timeRange = `${(0, date_fns_1.format)(session.start, 'HH:mm')}-${(0, date_fns_1.format)(session.end, 'HH:mm')}`;
|
|
117
|
+
const durationStr = formatDuration(session.duration);
|
|
118
|
+
// Get main work summary
|
|
119
|
+
const featCount = session.commits.filter(c => c.type === 'feat').length;
|
|
120
|
+
const fixCount = session.commits.filter(c => c.type === 'fix').length;
|
|
121
|
+
let workSummary = '';
|
|
122
|
+
if (featCount > 0) {
|
|
123
|
+
const firstFeat = session.commits.find(c => c.type === 'feat');
|
|
124
|
+
workSummary = firstFeat ? truncate(firstFeat.subject, 35) : `${featCount} features`;
|
|
125
|
+
}
|
|
126
|
+
else if (fixCount > 0) {
|
|
127
|
+
workSummary = `${fixCount} fix${fixCount > 1 ? 'es' : ''}`;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const first = session.commits[0];
|
|
131
|
+
workSummary = truncate(first.subject, 35);
|
|
132
|
+
}
|
|
133
|
+
// Status icon
|
|
134
|
+
const icon = getSessionIcon(session);
|
|
135
|
+
return chalk_1.default.gray(` ${icon} ${workSummary} (${timeRange}, ${durationStr})`);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Format session detail (expanded view)
|
|
139
|
+
*/
|
|
140
|
+
function formatSessionDetail(session) {
|
|
141
|
+
const lines = [];
|
|
142
|
+
const timeRange = `${(0, date_fns_1.format)(session.start, 'HH:mm')}-${(0, date_fns_1.format)(session.end, 'HH:mm')}`;
|
|
143
|
+
const durationStr = formatDuration(session.duration);
|
|
144
|
+
// Session header
|
|
145
|
+
const ratingStr = formatRating(session.overall);
|
|
146
|
+
const flowIcon = session.flowState ? ' 🌊' : '';
|
|
147
|
+
lines.push(chalk_1.default.white(` ┌─ Session ${timeRange} (${durationStr}) ${ratingStr}${flowIcon}`));
|
|
148
|
+
// List commits
|
|
149
|
+
for (const commit of session.commits) {
|
|
150
|
+
const typeIcon = getTypeIcon(commit.type);
|
|
151
|
+
const spiralMark = commit.spiralDepth > 0 ? chalk_1.default.yellow(` [spiral ${commit.spiralDepth}]`) : '';
|
|
152
|
+
lines.push(chalk_1.default.gray(` │ ${typeIcon} ${truncate(commit.subject, 45)}${spiralMark}`));
|
|
153
|
+
}
|
|
154
|
+
// Session footer with metrics
|
|
155
|
+
const trustStr = `Trust: ${session.trustPassRate}%`;
|
|
156
|
+
const reworkStr = `Rework: ${Math.round(session.reworkRatio)}%`;
|
|
157
|
+
lines.push(chalk_1.default.gray(` └─ ${trustStr}, ${reworkStr}`));
|
|
158
|
+
return lines.join('\n');
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get icon for session based on its characteristics
|
|
162
|
+
*/
|
|
163
|
+
function getSessionIcon(session) {
|
|
164
|
+
if (session.flowState)
|
|
165
|
+
return '🌊';
|
|
166
|
+
if (session.spirals.length > 0)
|
|
167
|
+
return '⚠';
|
|
168
|
+
if (session.overall === 'ELITE')
|
|
169
|
+
return '✓';
|
|
170
|
+
return '○';
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Get icon for commit type
|
|
174
|
+
*/
|
|
175
|
+
function getTypeIcon(type) {
|
|
176
|
+
switch (type) {
|
|
177
|
+
case 'feat': return '●';
|
|
178
|
+
case 'fix': return '○';
|
|
179
|
+
case 'docs': return '◇';
|
|
180
|
+
case 'refactor': return '◆';
|
|
181
|
+
case 'test': return '◎';
|
|
182
|
+
default: return '○';
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Format rating with color
|
|
187
|
+
*/
|
|
188
|
+
function formatRating(rating) {
|
|
189
|
+
switch (rating) {
|
|
190
|
+
case 'ELITE': return chalk_1.default.green.bold('ELITE');
|
|
191
|
+
case 'HIGH': return chalk_1.default.blue.bold('HIGH');
|
|
192
|
+
case 'MEDIUM': return chalk_1.default.yellow.bold('MEDIUM');
|
|
193
|
+
case 'LOW': return chalk_1.default.red.bold('LOW');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Format duration in human-readable form
|
|
198
|
+
*/
|
|
199
|
+
function formatDuration(minutes) {
|
|
200
|
+
if (minutes < 60)
|
|
201
|
+
return `${minutes}m`;
|
|
202
|
+
const hours = Math.floor(minutes / 60);
|
|
203
|
+
const mins = minutes % 60;
|
|
204
|
+
return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Truncate string with ellipsis
|
|
208
|
+
*/
|
|
209
|
+
function truncate(str, maxLen) {
|
|
210
|
+
if (str.length <= maxLen)
|
|
211
|
+
return str;
|
|
212
|
+
return str.substring(0, maxLen - 1) + '…';
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Generate insights from timeline data
|
|
216
|
+
*/
|
|
217
|
+
function generateInsights(timeline) {
|
|
218
|
+
const insights = [];
|
|
219
|
+
// Post-delete sprint (Phase 2) - show first as it's the killer insight
|
|
220
|
+
if (timeline.postDeleteSprint?.detected) {
|
|
221
|
+
insights.push(chalk_1.default.magenta(`⚡ Post-delete sprint: ${timeline.postDeleteSprint.message}`));
|
|
222
|
+
}
|
|
223
|
+
// Flow states
|
|
224
|
+
if (timeline.flowStates > 0) {
|
|
225
|
+
const avgFlowDuration = timeline.sessions
|
|
226
|
+
.filter(s => s.flowState)
|
|
227
|
+
.reduce((sum, s) => sum + s.duration, 0) / timeline.flowStates;
|
|
228
|
+
insights.push(`🌊 Flow states: ${timeline.flowStates} detected (avg ${Math.round(avgFlowDuration)} min)`);
|
|
229
|
+
}
|
|
230
|
+
// Thrashing (Phase 2)
|
|
231
|
+
if (timeline.thrashing?.detected) {
|
|
232
|
+
insights.push(chalk_1.default.yellow(`🔄 Thrashing: ${timeline.thrashing.message}`));
|
|
233
|
+
// Show worst thrashing file
|
|
234
|
+
const worstFile = timeline.thrashing.files[0];
|
|
235
|
+
if (worstFile) {
|
|
236
|
+
insights.push(chalk_1.default.gray(` └─ ${truncate(worstFile.path, 40)}: ${worstFile.touchCount} edits, ${worstFile.efficiency}% efficiency`));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Phase 3: Detours (code added then deleted)
|
|
240
|
+
if (timeline.detours?.detected) {
|
|
241
|
+
insights.push(chalk_1.default.yellow(timeline.detours.message));
|
|
242
|
+
// Show top detour details
|
|
243
|
+
const topDetour = timeline.detours.detours[0];
|
|
244
|
+
if (topDetour) {
|
|
245
|
+
insights.push(chalk_1.default.gray(` └─ ${topDetour.scope}: ${topDetour.linesAdded} lines built, ${topDetour.linesDeleted} deleted`));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Phase 3: Late-night spirals
|
|
249
|
+
if (timeline.lateNightSpirals?.detected) {
|
|
250
|
+
insights.push(chalk_1.default.yellow(timeline.lateNightSpirals.message));
|
|
251
|
+
}
|
|
252
|
+
// Spirals
|
|
253
|
+
if (timeline.totalSpirals > 0) {
|
|
254
|
+
insights.push(chalk_1.default.yellow(`⚠ Debug spirals: ${timeline.totalSpirals} detected`));
|
|
255
|
+
}
|
|
256
|
+
// Productivity ratio
|
|
257
|
+
const wallClockHours = timeline.totalDays * 24;
|
|
258
|
+
const activeHours = timeline.totalActiveMinutes / 60;
|
|
259
|
+
const efficiencyPercent = Math.round((activeHours / wallClockHours) * 100);
|
|
260
|
+
insights.push(chalk_1.default.gray(`⏱ Active time: ${Math.round(activeHours)}h of ${wallClockHours}h (${efficiencyPercent}% efficiency)`));
|
|
261
|
+
// Best day
|
|
262
|
+
const bestDay = timeline.days.reduce((best, day) => (day.dayScore || 0) > (best.dayScore || 0) ? day : best);
|
|
263
|
+
if (bestDay.dayScore && bestDay.dayScore >= 80) {
|
|
264
|
+
insights.push(chalk_1.default.green(`🏆 Best day: ${bestDay.displayDate} (${bestDay.dayScore}%)`));
|
|
265
|
+
}
|
|
266
|
+
// Feature velocity
|
|
267
|
+
if (timeline.totalFeatures > 0) {
|
|
268
|
+
const featuresPerHour = timeline.totalFeatures / (timeline.totalActiveMinutes / 60);
|
|
269
|
+
insights.push(chalk_1.default.gray(`⚡ Feature velocity: ${featuresPerHour.toFixed(1)} features/hour`));
|
|
270
|
+
}
|
|
271
|
+
// Recommendation based on patterns
|
|
272
|
+
const recommendation = generateRecommendation(timeline);
|
|
273
|
+
if (recommendation) {
|
|
274
|
+
insights.push('');
|
|
275
|
+
insights.push(chalk_1.default.cyan(`💡 ${recommendation}`));
|
|
276
|
+
}
|
|
277
|
+
return insights;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Generate a recommendation based on detected patterns
|
|
281
|
+
*/
|
|
282
|
+
function generateRecommendation(timeline) {
|
|
283
|
+
// Late-night spirals - strongest signal for behavior change
|
|
284
|
+
if (timeline.lateNightSpirals?.detected && timeline.lateNightSpirals.spirals.length > 0) {
|
|
285
|
+
const totalTime = timeline.lateNightSpirals.totalDuration;
|
|
286
|
+
if (totalTime > 30) {
|
|
287
|
+
return 'Late-night debugging is rarely efficient - sleep on it and tackle with fresh eyes';
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// Detours detected - learn from experiments
|
|
291
|
+
if (timeline.detours?.detected && timeline.detours.totalTimeLost > 60) {
|
|
292
|
+
return 'Significant detour detected - try smaller experiments or spikes before committing';
|
|
293
|
+
}
|
|
294
|
+
// Post-delete sprint detected - reinforce the pattern
|
|
295
|
+
if (timeline.postDeleteSprint?.detected) {
|
|
296
|
+
return 'Trust simplification impulses - deletion often unlocks velocity';
|
|
297
|
+
}
|
|
298
|
+
// Thrashing detected - suggest stepping back
|
|
299
|
+
if (timeline.thrashing?.detected && timeline.thrashing.files.length > 2) {
|
|
300
|
+
return 'Multiple files with repeated edits - consider stepping back to design';
|
|
301
|
+
}
|
|
302
|
+
// Many spirals - suggest tracer tests
|
|
303
|
+
if (timeline.totalSpirals > 2) {
|
|
304
|
+
return 'Multiple debug spirals - try writing a tracer test before the next feature';
|
|
305
|
+
}
|
|
306
|
+
// Flow states detected - show what works
|
|
307
|
+
if (timeline.flowStates > 0) {
|
|
308
|
+
const flowSessions = timeline.sessions.filter(s => s.flowState);
|
|
309
|
+
const avgTime = flowSessions.reduce((sum, s) => {
|
|
310
|
+
const hour = s.start.getHours();
|
|
311
|
+
return sum + hour;
|
|
312
|
+
}, 0) / flowSessions.length;
|
|
313
|
+
const peakHour = Math.round(avgTime);
|
|
314
|
+
return `Flow states peak around ${peakHour}:00 - protect this time`;
|
|
315
|
+
}
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
//# sourceMappingURL=timeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["../../src/output/timeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { TimelineEvent } from '../types';
|
|
2
|
+
export interface DetourResult {
|
|
3
|
+
detected: boolean;
|
|
4
|
+
detours: Detour[];
|
|
5
|
+
totalTimeLost: number;
|
|
6
|
+
message: string;
|
|
7
|
+
}
|
|
8
|
+
export interface Detour {
|
|
9
|
+
scope: string;
|
|
10
|
+
filesAffected: string[];
|
|
11
|
+
linesAdded: number;
|
|
12
|
+
linesDeleted: number;
|
|
13
|
+
startTime: Date;
|
|
14
|
+
endTime: Date;
|
|
15
|
+
duration: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Detect detours: code added then deleted within the analysis window.
|
|
19
|
+
*
|
|
20
|
+
* Definition: Code added then deleted in same analysis window
|
|
21
|
+
* Value: Track wasted time, learn from experiments
|
|
22
|
+
*
|
|
23
|
+
* How it works:
|
|
24
|
+
* 1. Track files/scopes with significant additions
|
|
25
|
+
* 2. Look for later commits that delete from same files/scopes
|
|
26
|
+
* 3. If deletions exceed 50% of additions, it's a detour
|
|
27
|
+
*/
|
|
28
|
+
export declare function detectDetour(events: TimelineEvent[], filesPerCommit: Map<string, string[]>, lineStatsPerCommit: Map<string, {
|
|
29
|
+
additions: number;
|
|
30
|
+
deletions: number;
|
|
31
|
+
}>): DetourResult;
|
|
32
|
+
//# sourceMappingURL=detour.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detour.d.ts","sourceRoot":"","sources":["../../src/patterns/detour.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,EAAE,IAAI,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,aAAa,EAAE,EACvB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,GACxE,YAAY,CA6Gd"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectDetour = detectDetour;
|
|
4
|
+
/**
|
|
5
|
+
* Detect detours: code added then deleted within the analysis window.
|
|
6
|
+
*
|
|
7
|
+
* Definition: Code added then deleted in same analysis window
|
|
8
|
+
* Value: Track wasted time, learn from experiments
|
|
9
|
+
*
|
|
10
|
+
* How it works:
|
|
11
|
+
* 1. Track files/scopes with significant additions
|
|
12
|
+
* 2. Look for later commits that delete from same files/scopes
|
|
13
|
+
* 3. If deletions exceed 50% of additions, it's a detour
|
|
14
|
+
*/
|
|
15
|
+
function detectDetour(events, filesPerCommit, lineStatsPerCommit) {
|
|
16
|
+
const detours = [];
|
|
17
|
+
// Group commits by scope (use scope or infer from files)
|
|
18
|
+
const scopeHistory = new Map();
|
|
19
|
+
// Build history per scope
|
|
20
|
+
for (const event of events) {
|
|
21
|
+
const scope = event.scope || inferScope(event, filesPerCommit);
|
|
22
|
+
if (!scope)
|
|
23
|
+
continue;
|
|
24
|
+
const stats = lineStatsPerCommit.get(event.hash);
|
|
25
|
+
if (!stats)
|
|
26
|
+
continue;
|
|
27
|
+
if (!scopeHistory.has(scope)) {
|
|
28
|
+
scopeHistory.set(scope, {
|
|
29
|
+
additions: 0,
|
|
30
|
+
deletions: 0,
|
|
31
|
+
files: new Set(),
|
|
32
|
+
firstAddTime: event.timestamp,
|
|
33
|
+
lastDeleteTime: event.timestamp,
|
|
34
|
+
addCommits: [],
|
|
35
|
+
deleteCommits: [],
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
const history = scopeHistory.get(scope);
|
|
39
|
+
history.additions += stats.additions;
|
|
40
|
+
history.deletions += stats.deletions;
|
|
41
|
+
// Track files touched
|
|
42
|
+
const files = filesPerCommit.get(event.hash) || [];
|
|
43
|
+
for (const file of files) {
|
|
44
|
+
history.files.add(file);
|
|
45
|
+
}
|
|
46
|
+
// Track commit types
|
|
47
|
+
if (stats.additions > stats.deletions) {
|
|
48
|
+
if (history.addCommits.length === 0) {
|
|
49
|
+
history.firstAddTime = event.timestamp;
|
|
50
|
+
}
|
|
51
|
+
history.addCommits.push(event);
|
|
52
|
+
}
|
|
53
|
+
else if (stats.deletions > stats.additions * 2) {
|
|
54
|
+
// Significant deletion
|
|
55
|
+
history.lastDeleteTime = event.timestamp;
|
|
56
|
+
history.deleteCommits.push(event);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Identify detours: scopes where we added then deleted significantly
|
|
60
|
+
for (const [scope, history] of scopeHistory.entries()) {
|
|
61
|
+
// Skip if no significant additions followed by deletions
|
|
62
|
+
if (history.addCommits.length === 0 || history.deleteCommits.length === 0) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
// Check if deletions happened AFTER additions
|
|
66
|
+
const lastAdd = history.addCommits[history.addCommits.length - 1];
|
|
67
|
+
const hasDeleteAfterAdd = history.deleteCommits.some(d => d.timestamp > lastAdd.timestamp);
|
|
68
|
+
if (!hasDeleteAfterAdd)
|
|
69
|
+
continue;
|
|
70
|
+
// Detour threshold: deleted >50% of what was added
|
|
71
|
+
const netDeletionRatio = history.deletions / Math.max(history.additions, 1);
|
|
72
|
+
if (netDeletionRatio < 0.5)
|
|
73
|
+
continue;
|
|
74
|
+
// This is a detour
|
|
75
|
+
const duration = Math.round((history.lastDeleteTime.getTime() - history.firstAddTime.getTime()) / (1000 * 60));
|
|
76
|
+
detours.push({
|
|
77
|
+
scope,
|
|
78
|
+
filesAffected: Array.from(history.files),
|
|
79
|
+
linesAdded: history.additions,
|
|
80
|
+
linesDeleted: history.deletions,
|
|
81
|
+
startTime: history.firstAddTime,
|
|
82
|
+
endTime: history.lastDeleteTime,
|
|
83
|
+
duration,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
// Calculate total time lost
|
|
87
|
+
const totalTimeLost = detours.reduce((sum, d) => sum + d.duration, 0);
|
|
88
|
+
// Generate message
|
|
89
|
+
let message = '';
|
|
90
|
+
if (detours.length > 0) {
|
|
91
|
+
const topDetour = detours.sort((a, b) => b.duration - a.duration)[0];
|
|
92
|
+
message = `🚧 ${detours.length} detour${detours.length > 1 ? 's' : ''} detected: ` +
|
|
93
|
+
`${topDetour.scope} took ${formatDuration(topDetour.duration)} ` +
|
|
94
|
+
`(${topDetour.linesAdded} lines added, then ${topDetour.linesDeleted} deleted)`;
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
detected: detours.length > 0,
|
|
98
|
+
detours,
|
|
99
|
+
totalTimeLost,
|
|
100
|
+
message,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Infer scope from files touched by a commit
|
|
105
|
+
*/
|
|
106
|
+
function inferScope(event, filesPerCommit) {
|
|
107
|
+
const files = filesPerCommit.get(event.hash) || [];
|
|
108
|
+
if (files.length === 0)
|
|
109
|
+
return null;
|
|
110
|
+
// Find common directory or file pattern
|
|
111
|
+
const commonParts = files[0].split('/');
|
|
112
|
+
for (let i = 1; i < files.length; i++) {
|
|
113
|
+
const parts = files[i].split('/');
|
|
114
|
+
let j = 0;
|
|
115
|
+
while (j < commonParts.length && j < parts.length && commonParts[j] === parts[j]) {
|
|
116
|
+
j++;
|
|
117
|
+
}
|
|
118
|
+
commonParts.length = j;
|
|
119
|
+
}
|
|
120
|
+
// Return the deepest meaningful directory
|
|
121
|
+
if (commonParts.length >= 2) {
|
|
122
|
+
return commonParts.slice(0, 2).join('/');
|
|
123
|
+
}
|
|
124
|
+
return commonParts[0] || null;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Format duration for display
|
|
128
|
+
*/
|
|
129
|
+
function formatDuration(minutes) {
|
|
130
|
+
if (minutes < 60) {
|
|
131
|
+
return `${minutes}m`;
|
|
132
|
+
}
|
|
133
|
+
const hours = Math.floor(minutes / 60);
|
|
134
|
+
const mins = minutes % 60;
|
|
135
|
+
return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=detour.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detour.js","sourceRoot":"","sources":["../../src/patterns/detour.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TimelineEvent } from '../types';
|
|
2
|
+
export interface FlowStateResult {
|
|
3
|
+
detected: boolean;
|
|
4
|
+
duration: number;
|
|
5
|
+
commits: number;
|
|
6
|
+
velocity: number;
|
|
7
|
+
peakType: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Detect flow state in a session.
|
|
11
|
+
*
|
|
12
|
+
* Definition: 5+ non-fix commits, no gap >30m, duration >45m
|
|
13
|
+
* Value: Shows when you're in the zone
|
|
14
|
+
*/
|
|
15
|
+
export declare function detectFlowState(events: TimelineEvent[], sessionDuration: number): FlowStateResult;
|
|
16
|
+
//# sourceMappingURL=flow-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow-state.d.ts","sourceRoot":"","sources":["../../src/patterns/flow-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EAAE,EACvB,eAAe,EAAE,MAAM,GACtB,eAAe,CAkCjB"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectFlowState = detectFlowState;
|
|
4
|
+
/**
|
|
5
|
+
* Detect flow state in a session.
|
|
6
|
+
*
|
|
7
|
+
* Definition: 5+ non-fix commits, no gap >30m, duration >45m
|
|
8
|
+
* Value: Shows when you're in the zone
|
|
9
|
+
*/
|
|
10
|
+
function detectFlowState(events, sessionDuration) {
|
|
11
|
+
// Count non-fix commits
|
|
12
|
+
const nonFixCommits = events.filter(e => e.type !== 'fix');
|
|
13
|
+
const nonFixCount = nonFixCommits.length;
|
|
14
|
+
// Find max gap between consecutive commits
|
|
15
|
+
let maxGap = 0;
|
|
16
|
+
for (let i = 1; i < events.length; i++) {
|
|
17
|
+
maxGap = Math.max(maxGap, events[i].gapMinutes);
|
|
18
|
+
}
|
|
19
|
+
// Check flow state conditions
|
|
20
|
+
const detected = nonFixCount >= 5 && maxGap <= 30 && sessionDuration >= 45;
|
|
21
|
+
// Calculate velocity (commits per hour)
|
|
22
|
+
const velocity = sessionDuration > 0
|
|
23
|
+
? (events.length / sessionDuration) * 60
|
|
24
|
+
: 0;
|
|
25
|
+
// Find peak commit type during flow
|
|
26
|
+
const typeCounts = {};
|
|
27
|
+
for (const event of nonFixCommits) {
|
|
28
|
+
typeCounts[event.type] = (typeCounts[event.type] || 0) + 1;
|
|
29
|
+
}
|
|
30
|
+
const peakType = Object.entries(typeCounts)
|
|
31
|
+
.sort((a, b) => b[1] - a[1])[0]?.[0] || 'other';
|
|
32
|
+
return {
|
|
33
|
+
detected,
|
|
34
|
+
duration: sessionDuration,
|
|
35
|
+
commits: events.length,
|
|
36
|
+
velocity: Math.round(velocity * 10) / 10,
|
|
37
|
+
peakType,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=flow-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow-state.js","sourceRoot":"","sources":["../../src/patterns/flow-state.ts"],"names":[],"mappings":";;AAgBA,0CAqCC;AA3CD;;;;;GAKG;AACH,SAAgB,eAAe,CAC7B,MAAuB,EACvB,eAAuB;IAEvB,wBAAwB;IACxB,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;IAC3D,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC;IAEzC,2CAA2C;IAC3C,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAClD,CAAC;IAED,8BAA8B;IAC9B,MAAM,QAAQ,GAAG,WAAW,IAAI,CAAC,IAAI,MAAM,IAAI,EAAE,IAAI,eAAe,IAAI,EAAE,CAAC;IAE3E,wCAAwC;IACxC,MAAM,QAAQ,GAAG,eAAe,GAAG,CAAC;QAClC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,eAAe,CAAC,GAAG,EAAE;QACxC,CAAC,CAAC,CAAC,CAAC;IAEN,oCAAoC;IACpC,MAAM,UAAU,GAA2B,EAAE,CAAC;IAC9C,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;QAClC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC;SACxC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC;IAElD,OAAO;QACL,QAAQ;QACR,QAAQ,EAAE,eAAe;QACzB,OAAO,EAAE,MAAM,CAAC,MAAM;QACtB,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAC,GAAG,EAAE;QACxC,QAAQ;KACT,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { detectFlowState, FlowStateResult } from './flow-state';
|
|
2
|
+
export { detectPostDeleteSprint, PostDeleteSprintResult } from './post-delete-sprint';
|
|
3
|
+
export { detectThrashing, ThrashingResult, ThrashingFile } from './thrashing';
|
|
4
|
+
export { detectDetour, DetourResult, Detour } from './detour';
|
|
5
|
+
export { detectLateNightSpiral, LateNightSpiralResult, LateNightSpiral } from './late-night';
|
|
6
|
+
export { detectRegressions, analyzeRecoveryTimeTrend, getAllRecoveryTrends, RegressionAlert, RegressionAnalysis, } from './spiral-regression';
|
|
7
|
+
export { calculateEffectiveness, getRecommendation, compareInterventions, InterventionScore, EffectivenessAnalysis, } from './intervention-effectiveness';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/patterns/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC7F,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,oBAAoB,EACpB,eAAe,EACf,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,8BAA8B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compareInterventions = exports.getRecommendation = exports.calculateEffectiveness = exports.getAllRecoveryTrends = exports.analyzeRecoveryTimeTrend = exports.detectRegressions = exports.detectLateNightSpiral = exports.detectDetour = exports.detectThrashing = exports.detectPostDeleteSprint = exports.detectFlowState = void 0;
|
|
4
|
+
var flow_state_1 = require("./flow-state");
|
|
5
|
+
Object.defineProperty(exports, "detectFlowState", { enumerable: true, get: function () { return flow_state_1.detectFlowState; } });
|
|
6
|
+
var post_delete_sprint_1 = require("./post-delete-sprint");
|
|
7
|
+
Object.defineProperty(exports, "detectPostDeleteSprint", { enumerable: true, get: function () { return post_delete_sprint_1.detectPostDeleteSprint; } });
|
|
8
|
+
var thrashing_1 = require("./thrashing");
|
|
9
|
+
Object.defineProperty(exports, "detectThrashing", { enumerable: true, get: function () { return thrashing_1.detectThrashing; } });
|
|
10
|
+
var detour_1 = require("./detour");
|
|
11
|
+
Object.defineProperty(exports, "detectDetour", { enumerable: true, get: function () { return detour_1.detectDetour; } });
|
|
12
|
+
var late_night_1 = require("./late-night");
|
|
13
|
+
Object.defineProperty(exports, "detectLateNightSpiral", { enumerable: true, get: function () { return late_night_1.detectLateNightSpiral; } });
|
|
14
|
+
var spiral_regression_1 = require("./spiral-regression");
|
|
15
|
+
Object.defineProperty(exports, "detectRegressions", { enumerable: true, get: function () { return spiral_regression_1.detectRegressions; } });
|
|
16
|
+
Object.defineProperty(exports, "analyzeRecoveryTimeTrend", { enumerable: true, get: function () { return spiral_regression_1.analyzeRecoveryTimeTrend; } });
|
|
17
|
+
Object.defineProperty(exports, "getAllRecoveryTrends", { enumerable: true, get: function () { return spiral_regression_1.getAllRecoveryTrends; } });
|
|
18
|
+
var intervention_effectiveness_1 = require("./intervention-effectiveness");
|
|
19
|
+
Object.defineProperty(exports, "calculateEffectiveness", { enumerable: true, get: function () { return intervention_effectiveness_1.calculateEffectiveness; } });
|
|
20
|
+
Object.defineProperty(exports, "getRecommendation", { enumerable: true, get: function () { return intervention_effectiveness_1.getRecommendation; } });
|
|
21
|
+
Object.defineProperty(exports, "compareInterventions", { enumerable: true, get: function () { return intervention_effectiveness_1.compareInterventions; } });
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/patterns/index.ts"],"names":[],"mappings":";;;AAAA,2CAAgE;AAAvD,6GAAA,eAAe,OAAA;AACxB,2DAAsF;AAA7E,4HAAA,sBAAsB,OAAA;AAC/B,yCAA8E;AAArE,4GAAA,eAAe,OAAA;AACxB,mCAA8D;AAArD,sGAAA,YAAY,OAAA;AACrB,2CAA6F;AAApF,mHAAA,qBAAqB,OAAA;AAC9B,yDAM6B;AAL3B,sHAAA,iBAAiB,OAAA;AACjB,6HAAA,wBAAwB,OAAA;AACxB,yHAAA,oBAAoB,OAAA;AAItB,2EAMsC;AALpC,oIAAA,sBAAsB,OAAA;AACtB,+HAAA,iBAAiB,OAAA;AACjB,kIAAA,oBAAoB,OAAA"}
|