@boshu2/vibe-check 1.5.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.
Files changed (147) hide show
  1. package/.agents/bundles/insight-mining-dashboard-research-2025-11-30.md +400 -0
  2. package/.agents/bundles/storage-enhancement-research-2025-11-30.md +292 -0
  3. package/.agents/bundles/timeline-feature-research-complete-2025-11-30.md +301 -0
  4. package/.agents/plans/insight-dashboard-plan-2025-11-30.md +1130 -0
  5. package/.agents/plans/json-storage-enhancement-plan.md +717 -0
  6. package/.agents/plans/storage-hardening-and-cache-plan.md +592 -0
  7. package/.agents/plans/test-coverage-gaps-plan.md +1117 -0
  8. package/.agents/plans/timeline-feature-plan.md +193 -0
  9. package/.agents/plans/vibe_timeline_research_findings.md +553 -0
  10. package/.claude/settings.local.json +1 -0
  11. package/.vibe-check/.gitignore +6 -0
  12. package/CHANGELOG.md +46 -0
  13. package/CLAUDE.md +24 -0
  14. package/CONTRIBUTING.md +227 -0
  15. package/README.md +200 -143
  16. package/claude-progress.json +191 -9
  17. package/claude-progress.txt +257 -0
  18. package/dashboard/app.js +75 -2
  19. package/dashboard/dashboard-data.json +653 -0
  20. package/dashboard/index.html +13 -0
  21. package/dashboard/styles.css +61 -0
  22. package/dist/analysis/cross-session-analysis.d.ts +68 -0
  23. package/dist/analysis/cross-session-analysis.d.ts.map +1 -0
  24. package/dist/analysis/cross-session-analysis.js +174 -0
  25. package/dist/analysis/cross-session-analysis.js.map +1 -0
  26. package/dist/analysis/index.d.ts +2 -0
  27. package/dist/analysis/index.d.ts.map +1 -0
  28. package/dist/analysis/index.js +12 -0
  29. package/dist/analysis/index.js.map +1 -0
  30. package/dist/cli.js +10 -1
  31. package/dist/cli.js.map +1 -1
  32. package/dist/commands/analyze.d.ts +2 -0
  33. package/dist/commands/analyze.d.ts.map +1 -1
  34. package/dist/commands/analyze.js +105 -2
  35. package/dist/commands/analyze.js.map +1 -1
  36. package/dist/commands/cache.d.ts +6 -0
  37. package/dist/commands/cache.d.ts.map +1 -0
  38. package/dist/commands/cache.js +168 -0
  39. package/dist/commands/cache.js.map +1 -0
  40. package/dist/commands/dashboard.d.ts +8 -0
  41. package/dist/commands/dashboard.d.ts.map +1 -0
  42. package/dist/commands/dashboard.js +109 -0
  43. package/dist/commands/dashboard.js.map +1 -0
  44. package/dist/commands/index.d.ts +3 -0
  45. package/dist/commands/index.d.ts.map +1 -1
  46. package/dist/commands/index.js +8 -1
  47. package/dist/commands/index.js.map +1 -1
  48. package/dist/commands/timeline.d.ts +14 -0
  49. package/dist/commands/timeline.d.ts.map +1 -0
  50. package/dist/commands/timeline.js +462 -0
  51. package/dist/commands/timeline.js.map +1 -0
  52. package/dist/git.d.ts +24 -0
  53. package/dist/git.d.ts.map +1 -1
  54. package/dist/git.js +94 -0
  55. package/dist/git.js.map +1 -1
  56. package/dist/insights/generators.d.ts +44 -0
  57. package/dist/insights/generators.d.ts.map +1 -0
  58. package/dist/insights/generators.js +289 -0
  59. package/dist/insights/generators.js.map +1 -0
  60. package/dist/insights/index.d.ts +16 -0
  61. package/dist/insights/index.d.ts.map +1 -0
  62. package/dist/insights/index.js +171 -0
  63. package/dist/insights/index.js.map +1 -0
  64. package/dist/insights/types.d.ts +93 -0
  65. package/dist/insights/types.d.ts.map +1 -0
  66. package/dist/insights/types.js +6 -0
  67. package/dist/insights/types.js.map +1 -0
  68. package/dist/output/timeline-html.d.ts +6 -0
  69. package/dist/output/timeline-html.d.ts.map +1 -0
  70. package/dist/output/timeline-html.js +389 -0
  71. package/dist/output/timeline-html.js.map +1 -0
  72. package/dist/output/timeline-markdown.d.ts +6 -0
  73. package/dist/output/timeline-markdown.d.ts.map +1 -0
  74. package/dist/output/timeline-markdown.js +167 -0
  75. package/dist/output/timeline-markdown.js.map +1 -0
  76. package/dist/output/timeline.d.ts +9 -0
  77. package/dist/output/timeline.d.ts.map +1 -0
  78. package/dist/output/timeline.js +318 -0
  79. package/dist/output/timeline.js.map +1 -0
  80. package/dist/patterns/detour.d.ts +32 -0
  81. package/dist/patterns/detour.d.ts.map +1 -0
  82. package/dist/patterns/detour.js +137 -0
  83. package/dist/patterns/detour.js.map +1 -0
  84. package/dist/patterns/flow-state.d.ts +16 -0
  85. package/dist/patterns/flow-state.d.ts.map +1 -0
  86. package/dist/patterns/flow-state.js +40 -0
  87. package/dist/patterns/flow-state.js.map +1 -0
  88. package/dist/patterns/index.d.ts +8 -0
  89. package/dist/patterns/index.d.ts.map +1 -0
  90. package/dist/patterns/index.js +22 -0
  91. package/dist/patterns/index.js.map +1 -0
  92. package/dist/patterns/intervention-effectiveness.d.ts +42 -0
  93. package/dist/patterns/intervention-effectiveness.d.ts.map +1 -0
  94. package/dist/patterns/intervention-effectiveness.js +196 -0
  95. package/dist/patterns/intervention-effectiveness.js.map +1 -0
  96. package/dist/patterns/late-night.d.ts +30 -0
  97. package/dist/patterns/late-night.d.ts.map +1 -0
  98. package/dist/patterns/late-night.js +141 -0
  99. package/dist/patterns/late-night.js.map +1 -0
  100. package/dist/patterns/post-delete-sprint.d.ts +28 -0
  101. package/dist/patterns/post-delete-sprint.d.ts.map +1 -0
  102. package/dist/patterns/post-delete-sprint.js +85 -0
  103. package/dist/patterns/post-delete-sprint.js.map +1 -0
  104. package/dist/patterns/spiral-regression.d.ts +49 -0
  105. package/dist/patterns/spiral-regression.d.ts.map +1 -0
  106. package/dist/patterns/spiral-regression.js +219 -0
  107. package/dist/patterns/spiral-regression.js.map +1 -0
  108. package/dist/patterns/thrashing.d.ts +25 -0
  109. package/dist/patterns/thrashing.d.ts.map +1 -0
  110. package/dist/patterns/thrashing.js +111 -0
  111. package/dist/patterns/thrashing.js.map +1 -0
  112. package/dist/storage/atomic.d.ts +40 -0
  113. package/dist/storage/atomic.d.ts.map +1 -0
  114. package/dist/storage/atomic.js +155 -0
  115. package/dist/storage/atomic.js.map +1 -0
  116. package/dist/storage/commit-log.d.ts +35 -0
  117. package/dist/storage/commit-log.d.ts.map +1 -0
  118. package/dist/storage/commit-log.js +128 -0
  119. package/dist/storage/commit-log.js.map +1 -0
  120. package/dist/storage/index.d.ts +5 -0
  121. package/dist/storage/index.d.ts.map +1 -0
  122. package/dist/storage/index.js +33 -0
  123. package/dist/storage/index.js.map +1 -0
  124. package/dist/storage/schema.d.ts +32 -0
  125. package/dist/storage/schema.d.ts.map +1 -0
  126. package/dist/storage/schema.js +37 -0
  127. package/dist/storage/schema.js.map +1 -0
  128. package/dist/storage/timeline-store.d.ts +117 -0
  129. package/dist/storage/timeline-store.d.ts.map +1 -0
  130. package/dist/storage/timeline-store.js +438 -0
  131. package/dist/storage/timeline-store.js.map +1 -0
  132. package/dist/types.d.ts +96 -0
  133. package/dist/types.d.ts.map +1 -1
  134. package/docs/ARCHITECTURE.md +458 -0
  135. package/docs/DATA-ARCHITECTURE.md +565 -0
  136. package/docs/GAMIFICATION.md +564 -0
  137. package/docs/JSON-STORAGE-PATTERNS.md +512 -0
  138. package/docs/METRICS-EXPLAINED.md +394 -0
  139. package/docs/UNIFIED-ECOSYSTEM.md +560 -0
  140. package/docs/VIBE-ECOSYSTEM.md +406 -0
  141. package/feature-list.json +48 -0
  142. package/package.json +2 -1
  143. package/vitest.config.ts +1 -5
  144. package/.vibe-check/calibration.json +0 -38
  145. package/.vibe-check/latest.json +0 -114
  146. package/.vibe-check/sessions.json +0 -44
  147. package/PLAN-ultimate-game.md +0 -1362
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectLateNightSpiral = detectLateNightSpiral;
4
+ // Late night threshold: 22:00 (10 PM)
5
+ const LATE_NIGHT_HOUR = 22;
6
+ // Early morning threshold: 06:00 (6 AM)
7
+ const EARLY_MORNING_HOUR = 6;
8
+ /**
9
+ * Detect late-night spirals: debug sessions after 22:00 with 3+ fix commits.
10
+ *
11
+ * Definition: Debug session after 22:00 with 3+ fix commits
12
+ * Value: Show that tired debugging is inefficient
13
+ *
14
+ * Enhanced: Also compare with "fresh eyes" resolution time if available
15
+ */
16
+ function detectLateNightSpiral(sessions) {
17
+ const lateNightSpirals = [];
18
+ for (const session of sessions) {
19
+ // Check if session is during late night hours
20
+ const sessionHour = session.start.getHours();
21
+ const isLateNight = sessionHour >= LATE_NIGHT_HOUR || sessionHour < EARLY_MORNING_HOUR;
22
+ if (!isLateNight)
23
+ continue;
24
+ // Check for spirals in this session
25
+ for (const spiral of session.spirals) {
26
+ // A spiral is 3+ fix commits for same component
27
+ if (spiral.commits < 3)
28
+ continue;
29
+ // Find if this component was fixed the next day
30
+ const nextDayFix = findNextDayResolution(spiral.component, session, sessions);
31
+ lateNightSpirals.push({
32
+ sessionId: session.id,
33
+ startTime: spiral.firstCommit,
34
+ endTime: spiral.lastCommit,
35
+ duration: spiral.duration,
36
+ fixCount: spiral.commits,
37
+ component: spiral.component,
38
+ resolved: !nextDayFix, // If no next-day fix, they solved it at night
39
+ nextDayResolution: nextDayFix,
40
+ });
41
+ }
42
+ // Also check for high fix density even without formal spirals
43
+ const fixCommits = session.commits.filter(c => c.type === 'fix');
44
+ if (fixCommits.length >= 3 && session.spirals.length === 0) {
45
+ // Late night session with lots of fixes but no detected spiral
46
+ // Could be a diffuse debugging session
47
+ const components = new Set(fixCommits.map(c => c.scope || 'unknown'));
48
+ for (const component of components) {
49
+ const componentFixes = fixCommits.filter(c => (c.scope || 'unknown') === component);
50
+ if (componentFixes.length >= 3) {
51
+ const duration = componentFixes.length > 1
52
+ ? Math.round((componentFixes[componentFixes.length - 1].timestamp.getTime() -
53
+ componentFixes[0].timestamp.getTime()) / (1000 * 60))
54
+ : session.duration;
55
+ lateNightSpirals.push({
56
+ sessionId: session.id,
57
+ startTime: componentFixes[0].timestamp,
58
+ endTime: componentFixes[componentFixes.length - 1].timestamp,
59
+ duration,
60
+ fixCount: componentFixes.length,
61
+ component,
62
+ resolved: true, // Assume resolved if no next-day data
63
+ });
64
+ }
65
+ }
66
+ }
67
+ }
68
+ // Calculate total duration
69
+ const totalDuration = lateNightSpirals.reduce((sum, s) => sum + s.duration, 0);
70
+ // Generate message
71
+ let message = '';
72
+ if (lateNightSpirals.length > 0) {
73
+ const withFreshEyes = lateNightSpirals.filter(s => s.nextDayResolution);
74
+ if (withFreshEyes.length > 0) {
75
+ const avgImprovement = withFreshEyes.reduce((sum, s) => sum + (s.nextDayResolution?.improvement || 0), 0) / withFreshEyes.length;
76
+ message = `🌙 ${lateNightSpirals.length} late-night spiral${lateNightSpirals.length > 1 ? 's' : ''}: ` +
77
+ `${formatDuration(totalDuration)} debugging after 10pm. ` +
78
+ `Fresh eyes solve ${Math.round(avgImprovement * 100)}% faster.`;
79
+ }
80
+ else {
81
+ message = `🌙 ${lateNightSpirals.length} late-night spiral${lateNightSpirals.length > 1 ? 's' : ''}: ` +
82
+ `${formatDuration(totalDuration)} debugging after 10pm. Consider sleeping on it!`;
83
+ }
84
+ }
85
+ return {
86
+ detected: lateNightSpirals.length > 0,
87
+ spirals: lateNightSpirals,
88
+ totalDuration,
89
+ message,
90
+ };
91
+ }
92
+ /**
93
+ * Check if the same component was fixed more quickly the next day
94
+ */
95
+ function findNextDayResolution(component, lateNightSession, allSessions) {
96
+ // Look for sessions the next day
97
+ const lateNightDate = lateNightSession.start.toDateString();
98
+ for (const session of allSessions) {
99
+ // Skip the late night session itself
100
+ if (session.id === lateNightSession.id)
101
+ continue;
102
+ // Check if this session is the next day (or later morning)
103
+ const sessionDate = session.start.toDateString();
104
+ const sessionHour = session.start.getHours();
105
+ // Must be after the late night session
106
+ if (session.start <= lateNightSession.end)
107
+ continue;
108
+ // Look for fixes to the same component
109
+ const componentFixes = session.commits.filter(c => c.type === 'fix' && (c.scope || 'unknown') === component);
110
+ if (componentFixes.length > 0) {
111
+ // Found a next-day resolution
112
+ // Calculate how long it took with fresh eyes
113
+ const freshDuration = componentFixes.length > 1
114
+ ? Math.round((componentFixes[componentFixes.length - 1].timestamp.getTime() -
115
+ componentFixes[0].timestamp.getTime()) / (1000 * 60))
116
+ : 15; // Assume 15 minutes for single-commit fixes
117
+ // Compare with late night duration
118
+ const lateNightDuration = lateNightSession.spirals.find(s => s.component === component)?.duration || 30;
119
+ const improvement = lateNightDuration > 0
120
+ ? (lateNightDuration - freshDuration) / lateNightDuration
121
+ : 0;
122
+ return {
123
+ duration: freshDuration,
124
+ improvement: Math.max(0, improvement), // Only positive improvements
125
+ };
126
+ }
127
+ }
128
+ return undefined;
129
+ }
130
+ /**
131
+ * Format duration for display
132
+ */
133
+ function formatDuration(minutes) {
134
+ if (minutes < 60) {
135
+ return `${minutes}m`;
136
+ }
137
+ const hours = Math.floor(minutes / 60);
138
+ const mins = minutes % 60;
139
+ return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
140
+ }
141
+ //# sourceMappingURL=late-night.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"late-night.js","sourceRoot":"","sources":["../../src/patterns/late-night.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { TimelineSession } from '../types';
2
+ export interface PostDeleteSprintResult {
3
+ detected: boolean;
4
+ deleteSession: {
5
+ id: string;
6
+ linesDeleted: number;
7
+ timestamp: Date;
8
+ } | null;
9
+ sprintSession: {
10
+ id: string;
11
+ features: number;
12
+ duration: number;
13
+ velocity: number;
14
+ } | null;
15
+ velocityIncrease: number;
16
+ message: string;
17
+ }
18
+ /**
19
+ * Detect post-delete sprints across sessions.
20
+ *
21
+ * Definition: Deletions > 2× additions in one session, then velocity >50% above baseline
22
+ * Value: Shows ROI of simplification
23
+ */
24
+ export declare function detectPostDeleteSprint(sessions: TimelineSession[], commitStats: Map<string, {
25
+ additions: number;
26
+ deletions: number;
27
+ }>): PostDeleteSprintResult;
28
+ //# sourceMappingURL=post-delete-sprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-delete-sprint.d.ts","sourceRoot":"","sources":["../../src/patterns/post-delete-sprint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE;QACb,EAAE,EAAE,MAAM,CAAC;QACX,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,IAAI,CAAC;KACjB,GAAG,IAAI,CAAC;IACT,aAAa,EAAE;QACb,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,IAAI,CAAC;IACT,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,eAAe,EAAE,EAC3B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,GACjE,sBAAsB,CAmFxB"}
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectPostDeleteSprint = detectPostDeleteSprint;
4
+ /**
5
+ * Detect post-delete sprints across sessions.
6
+ *
7
+ * Definition: Deletions > 2× additions in one session, then velocity >50% above baseline
8
+ * Value: Shows ROI of simplification
9
+ */
10
+ function detectPostDeleteSprint(sessions, commitStats) {
11
+ if (sessions.length < 2) {
12
+ return {
13
+ detected: false,
14
+ deleteSession: null,
15
+ sprintSession: null,
16
+ velocityIncrease: 0,
17
+ message: 'Not enough sessions to detect pattern',
18
+ };
19
+ }
20
+ // Calculate baseline velocity (features per hour across all sessions)
21
+ let totalFeatures = 0;
22
+ let totalMinutes = 0;
23
+ for (const session of sessions) {
24
+ const featCount = session.commits.filter(c => c.type === 'feat').length;
25
+ totalFeatures += featCount;
26
+ totalMinutes += session.duration;
27
+ }
28
+ const baselineVelocity = totalMinutes > 0 ? (totalFeatures / totalMinutes) * 60 : 0;
29
+ // Find sessions with heavy deletions (deletions > 2× additions)
30
+ for (let i = 0; i < sessions.length - 1; i++) {
31
+ const session = sessions[i];
32
+ // Calculate total additions/deletions for this session
33
+ let sessionAdditions = 0;
34
+ let sessionDeletions = 0;
35
+ for (const commit of session.commits) {
36
+ const stats = commitStats.get(commit.hash);
37
+ if (stats) {
38
+ sessionAdditions += stats.additions;
39
+ sessionDeletions += stats.deletions;
40
+ }
41
+ }
42
+ // Check if this is a "delete session" (deletions > 2× additions)
43
+ const isDeleteSession = sessionDeletions > sessionAdditions * 2 && sessionDeletions > 100;
44
+ if (isDeleteSession) {
45
+ // Check subsequent sessions for sprint behavior
46
+ for (let j = i + 1; j < sessions.length; j++) {
47
+ const sprintCandidate = sessions[j];
48
+ const sprintFeatures = sprintCandidate.commits.filter(c => c.type === 'feat').length;
49
+ const sprintDuration = sprintCandidate.duration;
50
+ // Calculate sprint velocity
51
+ const sprintVelocity = sprintDuration > 0 ? (sprintFeatures / sprintDuration) * 60 : 0;
52
+ // Check if sprint velocity is >50% above baseline
53
+ const velocityIncrease = baselineVelocity > 0
54
+ ? ((sprintVelocity - baselineVelocity) / baselineVelocity) * 100
55
+ : 0;
56
+ if (velocityIncrease > 50 && sprintFeatures >= 3) {
57
+ return {
58
+ detected: true,
59
+ deleteSession: {
60
+ id: session.id,
61
+ linesDeleted: sessionDeletions,
62
+ timestamp: session.start,
63
+ },
64
+ sprintSession: {
65
+ id: sprintCandidate.id,
66
+ features: sprintFeatures,
67
+ duration: sprintDuration,
68
+ velocity: Math.round(sprintVelocity * 10) / 10,
69
+ },
70
+ velocityIncrease: Math.round(velocityIncrease),
71
+ message: `${Math.round(velocityIncrease)}% faster after removing ${sessionDeletions} lines`,
72
+ };
73
+ }
74
+ }
75
+ }
76
+ }
77
+ return {
78
+ detected: false,
79
+ deleteSession: null,
80
+ sprintSession: null,
81
+ velocityIncrease: 0,
82
+ message: 'No post-delete sprint detected',
83
+ };
84
+ }
85
+ //# sourceMappingURL=post-delete-sprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-delete-sprint.js","sourceRoot":"","sources":["../../src/patterns/post-delete-sprint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Spiral Regression Detection
3
+ *
4
+ * Detects when spiral patterns re-emerge after a period of improvement.
5
+ * Uses weekly trend analysis to identify regressions.
6
+ */
7
+ import { StoredSession, TrendData } from '../storage/timeline-store';
8
+ export interface RegressionAlert {
9
+ type: 'spiral_regression' | 'recovery_time_regression';
10
+ severity: 'warning' | 'critical';
11
+ message: string;
12
+ metric: string;
13
+ currentValue: number;
14
+ baselineValue: number;
15
+ changePercent: number;
16
+ period: string;
17
+ recommendation: string;
18
+ }
19
+ export interface RegressionAnalysis {
20
+ hasRegression: boolean;
21
+ alerts: RegressionAlert[];
22
+ summary: string;
23
+ improvementStreak: number;
24
+ }
25
+ /**
26
+ * Detect spiral regressions from trend data
27
+ */
28
+ export declare function detectRegressions(trends: TrendData): RegressionAnalysis;
29
+ /**
30
+ * Analyze recovery time trends for a specific pattern
31
+ */
32
+ export declare function analyzeRecoveryTimeTrend(sessions: StoredSession[], component: string): {
33
+ improving: boolean;
34
+ trend: 'improving' | 'stable' | 'worsening';
35
+ avgRecoveryTime: number;
36
+ recentRecoveryTime: number;
37
+ samples: number;
38
+ };
39
+ /**
40
+ * Get all component recovery trends
41
+ */
42
+ export declare function getAllRecoveryTrends(sessions: StoredSession[]): Array<{
43
+ component: string;
44
+ trend: 'improving' | 'stable' | 'worsening';
45
+ avgTime: number;
46
+ recentTime: number;
47
+ samples: number;
48
+ }>;
49
+ //# sourceMappingURL=spiral-regression.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spiral-regression.d.ts","sourceRoot":"","sources":["../../src/patterns/spiral-regression.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,SAAS,EAAa,MAAM,2BAA2B,CAAC;AAEhF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,mBAAmB,GAAG,0BAA0B,CAAC;IACvD,QAAQ,EAAE,SAAS,GAAG,UAAU,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,kBAAkB,CAkDvE;AAwGD;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,aAAa,EAAE,EACzB,SAAS,EAAE,MAAM,GAChB;IACD,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC5C,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB,CAgDA;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAyBD"}
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ /**
3
+ * Spiral Regression Detection
4
+ *
5
+ * Detects when spiral patterns re-emerge after a period of improvement.
6
+ * Uses weekly trend analysis to identify regressions.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.detectRegressions = detectRegressions;
10
+ exports.analyzeRecoveryTimeTrend = analyzeRecoveryTimeTrend;
11
+ exports.getAllRecoveryTrends = getAllRecoveryTrends;
12
+ /**
13
+ * Detect spiral regressions from trend data
14
+ */
15
+ function detectRegressions(trends) {
16
+ const alerts = [];
17
+ if (trends.weekly.length < 3) {
18
+ return {
19
+ hasRegression: false,
20
+ alerts: [],
21
+ summary: 'Not enough data for regression detection (need 3+ weeks)',
22
+ improvementStreak: 0,
23
+ };
24
+ }
25
+ // Check spiral rate regression
26
+ const spiralRegression = detectSpiralRateRegression(trends.weekly);
27
+ if (spiralRegression) {
28
+ alerts.push(spiralRegression);
29
+ }
30
+ // Check flow state regression
31
+ const flowRegression = detectFlowStateRegression(trends.weekly);
32
+ if (flowRegression) {
33
+ alerts.push(flowRegression);
34
+ }
35
+ // Calculate improvement streak (weeks of improvement before current)
36
+ const improvementStreak = calculateImprovementStreak(trends.weekly);
37
+ // Generate summary
38
+ let summary;
39
+ if (alerts.length === 0) {
40
+ if (improvementStreak > 0) {
41
+ summary = `${improvementStreak}-week improvement streak. Keep it up!`;
42
+ }
43
+ else {
44
+ summary = 'No regressions detected';
45
+ }
46
+ }
47
+ else {
48
+ const critical = alerts.filter(a => a.severity === 'critical').length;
49
+ if (critical > 0) {
50
+ summary = `${critical} critical regression(s) detected - action needed`;
51
+ }
52
+ else {
53
+ summary = `${alerts.length} warning(s) - monitor closely`;
54
+ }
55
+ }
56
+ return {
57
+ hasRegression: alerts.length > 0,
58
+ alerts,
59
+ summary,
60
+ improvementStreak,
61
+ };
62
+ }
63
+ /**
64
+ * Detect if spiral rate has regressed after improvement
65
+ */
66
+ function detectSpiralRateRegression(weeks) {
67
+ if (weeks.length < 3)
68
+ return null;
69
+ // Get recent weeks (newest first in our data)
70
+ const recent = weeks.slice(-3);
71
+ const [oldest, middle, newest] = recent;
72
+ // Calculate spiral rates (spirals per session)
73
+ const oldestRate = oldest.sessions > 0 ? oldest.spirals / oldest.sessions : 0;
74
+ const middleRate = middle.sessions > 0 ? middle.spirals / middle.sessions : 0;
75
+ const newestRate = newest.sessions > 0 ? newest.spirals / newest.sessions : 0;
76
+ // Pattern: was improving (rate went down), then got worse
77
+ const wasImproving = middleRate < oldestRate;
78
+ const hasRegressed = newestRate > middleRate * 1.5; // 50% increase threshold
79
+ if (wasImproving && hasRegressed && newestRate > 0.1) {
80
+ const changePercent = Math.round((newestRate - middleRate) / Math.max(middleRate, 0.01) * 100);
81
+ return {
82
+ type: 'spiral_regression',
83
+ severity: changePercent > 100 ? 'critical' : 'warning',
84
+ message: `Spiral rate increased ${changePercent}% after previous improvement`,
85
+ metric: 'spiral_rate',
86
+ currentValue: Math.round(newestRate * 100) / 100,
87
+ baselineValue: Math.round(middleRate * 100) / 100,
88
+ changePercent,
89
+ period: `${newest.weekStart}`,
90
+ recommendation: 'Review recent commits for unfamiliar patterns. Consider adding tracer tests.',
91
+ };
92
+ }
93
+ return null;
94
+ }
95
+ /**
96
+ * Detect if flow state frequency has regressed
97
+ */
98
+ function detectFlowStateRegression(weeks) {
99
+ if (weeks.length < 3)
100
+ return null;
101
+ const recent = weeks.slice(-3);
102
+ const [oldest, middle, newest] = recent;
103
+ // Calculate flow state rates
104
+ const oldestRate = oldest.sessions > 0 ? oldest.flowStates / oldest.sessions : 0;
105
+ const middleRate = middle.sessions > 0 ? middle.flowStates / middle.sessions : 0;
106
+ const newestRate = newest.sessions > 0 ? newest.flowStates / newest.sessions : 0;
107
+ // Pattern: had good flow (high rate), then dropped significantly
108
+ const hadGoodFlow = middleRate >= 0.3; // At least 30% flow sessions
109
+ const hasRegressed = newestRate < middleRate * 0.5 && middleRate > 0; // 50% drop
110
+ if (hadGoodFlow && hasRegressed) {
111
+ const changePercent = Math.round((middleRate - newestRate) / middleRate * 100);
112
+ return {
113
+ type: 'spiral_regression',
114
+ severity: 'warning',
115
+ message: `Flow state frequency dropped ${changePercent}% this week`,
116
+ metric: 'flow_rate',
117
+ currentValue: Math.round(newestRate * 100),
118
+ baselineValue: Math.round(middleRate * 100),
119
+ changePercent: -changePercent,
120
+ period: `${newest.weekStart}`,
121
+ recommendation: 'Protect deep work time. Check for interruption patterns.',
122
+ };
123
+ }
124
+ return null;
125
+ }
126
+ /**
127
+ * Calculate consecutive weeks of improvement
128
+ */
129
+ function calculateImprovementStreak(weeks) {
130
+ if (weeks.length < 2)
131
+ return 0;
132
+ let streak = 0;
133
+ // Work backwards from second-to-last week
134
+ for (let i = weeks.length - 2; i >= 0; i--) {
135
+ const current = weeks[i];
136
+ const next = weeks[i + 1];
137
+ const currentRate = current.sessions > 0 ? current.spirals / current.sessions : 0;
138
+ const nextRate = next.sessions > 0 ? next.spirals / next.sessions : 0;
139
+ // Improvement = lower spiral rate
140
+ if (nextRate <= currentRate) {
141
+ streak++;
142
+ }
143
+ else {
144
+ break;
145
+ }
146
+ }
147
+ return streak;
148
+ }
149
+ /**
150
+ * Analyze recovery time trends for a specific pattern
151
+ */
152
+ function analyzeRecoveryTimeTrend(sessions, component) {
153
+ // Filter sessions with spirals in this component
154
+ const relevantSessions = sessions.filter(s => s.spiralComponents.includes(component));
155
+ if (relevantSessions.length < 2) {
156
+ return {
157
+ improving: false,
158
+ trend: 'stable',
159
+ avgRecoveryTime: 0,
160
+ recentRecoveryTime: 0,
161
+ samples: relevantSessions.length,
162
+ };
163
+ }
164
+ // Sort by date
165
+ const sorted = [...relevantSessions].sort((a, b) => new Date(a.start).getTime() - new Date(b.start).getTime());
166
+ // Calculate average duration (proxy for recovery time)
167
+ const allDurations = sorted.map(s => s.duration);
168
+ const avgRecoveryTime = allDurations.reduce((a, b) => a + b, 0) / allDurations.length;
169
+ // Recent average (last 3)
170
+ const recentDurations = allDurations.slice(-3);
171
+ const recentRecoveryTime = recentDurations.reduce((a, b) => a + b, 0) / recentDurations.length;
172
+ // Determine trend
173
+ const changePercent = (recentRecoveryTime - avgRecoveryTime) / avgRecoveryTime * 100;
174
+ let trend;
175
+ if (changePercent < -15) {
176
+ trend = 'improving';
177
+ }
178
+ else if (changePercent > 15) {
179
+ trend = 'worsening';
180
+ }
181
+ else {
182
+ trend = 'stable';
183
+ }
184
+ return {
185
+ improving: trend === 'improving',
186
+ trend,
187
+ avgRecoveryTime: Math.round(avgRecoveryTime),
188
+ recentRecoveryTime: Math.round(recentRecoveryTime),
189
+ samples: relevantSessions.length,
190
+ };
191
+ }
192
+ /**
193
+ * Get all component recovery trends
194
+ */
195
+ function getAllRecoveryTrends(sessions) {
196
+ // Get unique components with spirals
197
+ const components = new Set();
198
+ for (const session of sessions) {
199
+ for (const comp of session.spiralComponents) {
200
+ components.add(comp);
201
+ }
202
+ }
203
+ const trends = [];
204
+ for (const component of components) {
205
+ const analysis = analyzeRecoveryTimeTrend(sessions, component);
206
+ if (analysis.samples >= 2) {
207
+ trends.push({
208
+ component,
209
+ trend: analysis.trend,
210
+ avgTime: analysis.avgRecoveryTime,
211
+ recentTime: analysis.recentRecoveryTime,
212
+ samples: analysis.samples,
213
+ });
214
+ }
215
+ }
216
+ // Sort by sample count (most data first)
217
+ return trends.sort((a, b) => b.samples - a.samples);
218
+ }
219
+ //# sourceMappingURL=spiral-regression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spiral-regression.js","sourceRoot":"","sources":["../../src/patterns/spiral-regression.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { TimelineEvent } from '../types';
2
+ export interface ThrashingFile {
3
+ path: string;
4
+ touchCount: number;
5
+ commits: string[];
6
+ netChange: number;
7
+ efficiency: number;
8
+ }
9
+ export interface ThrashingResult {
10
+ detected: boolean;
11
+ files: ThrashingFile[];
12
+ totalThrashingMinutes: number;
13
+ message: string;
14
+ }
15
+ /**
16
+ * Detect thrashing patterns in commits.
17
+ *
18
+ * Definition: Same file touched 5+ times in 2 hours, low net change
19
+ * Value: Identify incomplete understanding
20
+ */
21
+ export declare function detectThrashing(events: TimelineEvent[], filesPerCommit: Map<string, string[]>, lineStatsPerCommit: Map<string, {
22
+ additions: number;
23
+ deletions: number;
24
+ }>): ThrashingResult;
25
+ //# sourceMappingURL=thrashing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thrashing.d.ts","sourceRoot":"","sources":["../../src/patterns/thrashing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,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,eAAe,CAoHjB"}