@grainulation/harvest 1.0.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/LICENSE +21 -0
- package/README.md +102 -0
- package/bin/harvest.js +284 -0
- package/lib/analyzer.js +88 -0
- package/lib/calibration.js +153 -0
- package/lib/dashboard.js +126 -0
- package/lib/decay.js +124 -0
- package/lib/farmer.js +107 -0
- package/lib/patterns.js +199 -0
- package/lib/report.js +125 -0
- package/lib/server.js +494 -0
- package/lib/templates.js +80 -0
- package/lib/velocity.js +177 -0
- package/package.json +51 -0
- package/public/index.html +982 -0
- package/templates/dashboard.html +1230 -0
- package/templates/retrospective.html +315 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>Harvest Retrospective</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--bg: #0c0a09;
|
|
10
|
+
--surface: #1c1917;
|
|
11
|
+
--surface-2: #292524;
|
|
12
|
+
--border: #44403c;
|
|
13
|
+
--text: #e7e5e4;
|
|
14
|
+
--text-muted: #a8a29e;
|
|
15
|
+
--accent: #f97316;
|
|
16
|
+
--accent-dim: #c2410c;
|
|
17
|
+
--green: #22c55e;
|
|
18
|
+
--red: #e11d48;
|
|
19
|
+
--yellow: #eab308;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
23
|
+
|
|
24
|
+
body {
|
|
25
|
+
background: var(--bg);
|
|
26
|
+
color: var(--text);
|
|
27
|
+
font-family: 'SF Mono', 'Fira Code', 'JetBrains Mono', monospace;
|
|
28
|
+
font-size: 14px;
|
|
29
|
+
line-height: 1.6;
|
|
30
|
+
padding: 2rem;
|
|
31
|
+
max-width: 960px;
|
|
32
|
+
margin: 0 auto;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
header {
|
|
36
|
+
border-bottom: 2px solid var(--accent);
|
|
37
|
+
padding-bottom: 1.5rem;
|
|
38
|
+
margin-bottom: 2rem;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
header h1 {
|
|
42
|
+
font-size: 1.8rem;
|
|
43
|
+
color: var(--accent);
|
|
44
|
+
font-weight: 700;
|
|
45
|
+
letter-spacing: -0.02em;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
header p {
|
|
49
|
+
color: var(--text-muted);
|
|
50
|
+
margin-top: 0.25rem;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.meta {
|
|
54
|
+
display: flex;
|
|
55
|
+
gap: 2rem;
|
|
56
|
+
margin-top: 1rem;
|
|
57
|
+
flex-wrap: wrap;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.meta-item {
|
|
61
|
+
background: var(--surface);
|
|
62
|
+
border: 1px solid var(--border);
|
|
63
|
+
border-radius: 8px;
|
|
64
|
+
padding: 1rem 1.5rem;
|
|
65
|
+
min-width: 140px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.meta-item .label {
|
|
69
|
+
color: var(--text-muted);
|
|
70
|
+
font-size: 0.75rem;
|
|
71
|
+
text-transform: uppercase;
|
|
72
|
+
letter-spacing: 0.05em;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.meta-item .value {
|
|
76
|
+
font-size: 1.5rem;
|
|
77
|
+
font-weight: 700;
|
|
78
|
+
color: var(--accent);
|
|
79
|
+
margin-top: 0.25rem;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
section {
|
|
83
|
+
background: var(--surface);
|
|
84
|
+
border: 1px solid var(--border);
|
|
85
|
+
border-radius: 8px;
|
|
86
|
+
padding: 1.5rem;
|
|
87
|
+
margin-bottom: 1.5rem;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
h2 {
|
|
91
|
+
color: var(--accent);
|
|
92
|
+
font-size: 1.1rem;
|
|
93
|
+
margin-bottom: 1rem;
|
|
94
|
+
padding-bottom: 0.5rem;
|
|
95
|
+
border-bottom: 1px solid var(--border);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
h3 {
|
|
99
|
+
color: var(--text);
|
|
100
|
+
font-size: 0.95rem;
|
|
101
|
+
margin: 1rem 0 0.5rem;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.insight {
|
|
105
|
+
background: var(--surface-2);
|
|
106
|
+
border-left: 3px solid var(--accent);
|
|
107
|
+
padding: 0.75rem 1rem;
|
|
108
|
+
margin: 1rem 0;
|
|
109
|
+
font-style: italic;
|
|
110
|
+
color: var(--text-muted);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.bar-row {
|
|
114
|
+
display: flex;
|
|
115
|
+
align-items: center;
|
|
116
|
+
margin: 0.35rem 0;
|
|
117
|
+
gap: 0.75rem;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.bar-label {
|
|
121
|
+
min-width: 110px;
|
|
122
|
+
color: var(--text-muted);
|
|
123
|
+
font-size: 0.85rem;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.bar {
|
|
127
|
+
background: linear-gradient(90deg, var(--accent), var(--accent-dim));
|
|
128
|
+
color: var(--bg);
|
|
129
|
+
padding: 0.15rem 0.5rem;
|
|
130
|
+
border-radius: 3px;
|
|
131
|
+
font-size: 0.8rem;
|
|
132
|
+
font-weight: 600;
|
|
133
|
+
min-width: 24px;
|
|
134
|
+
text-align: right;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
table {
|
|
138
|
+
width: 100%;
|
|
139
|
+
border-collapse: collapse;
|
|
140
|
+
margin: 0.5rem 0;
|
|
141
|
+
font-size: 0.85rem;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
th {
|
|
145
|
+
text-align: left;
|
|
146
|
+
color: var(--accent);
|
|
147
|
+
font-weight: 600;
|
|
148
|
+
padding: 0.5rem;
|
|
149
|
+
border-bottom: 1px solid var(--border);
|
|
150
|
+
font-size: 0.75rem;
|
|
151
|
+
text-transform: uppercase;
|
|
152
|
+
letter-spacing: 0.05em;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
td {
|
|
156
|
+
padding: 0.4rem 0.5rem;
|
|
157
|
+
border-bottom: 1px solid var(--surface-2);
|
|
158
|
+
color: var(--text-muted);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
tr:hover td {
|
|
162
|
+
color: var(--text);
|
|
163
|
+
background: var(--surface-2);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
ul {
|
|
167
|
+
list-style: none;
|
|
168
|
+
padding: 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
ul li {
|
|
172
|
+
padding: 0.5rem 0;
|
|
173
|
+
border-bottom: 1px solid var(--surface-2);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
ul li:last-child {
|
|
177
|
+
border-bottom: none;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
ul li strong {
|
|
181
|
+
color: var(--accent);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.severity-high { border-left: 3px solid var(--red); padding-left: 0.75rem; }
|
|
185
|
+
.severity-medium { border-left: 3px solid var(--yellow); padding-left: 0.75rem; }
|
|
186
|
+
.severity-low { border-left: 3px solid var(--text-muted); padding-left: 0.75rem; }
|
|
187
|
+
|
|
188
|
+
.muted { color: var(--text-muted); }
|
|
189
|
+
|
|
190
|
+
footer {
|
|
191
|
+
text-align: center;
|
|
192
|
+
color: var(--text-muted);
|
|
193
|
+
font-size: 0.75rem;
|
|
194
|
+
margin-top: 2rem;
|
|
195
|
+
padding-top: 1rem;
|
|
196
|
+
border-top: 1px solid var(--border);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
@media (max-width: 600px) {
|
|
200
|
+
body { padding: 1rem; font-size: 13px; }
|
|
201
|
+
.meta { gap: 0.75rem; }
|
|
202
|
+
.meta-item { min-width: 100px; padding: 0.75rem; }
|
|
203
|
+
.meta-item .value { font-size: 1.2rem; }
|
|
204
|
+
}
|
|
205
|
+
</style>
|
|
206
|
+
</head>
|
|
207
|
+
<body>
|
|
208
|
+
<header>
|
|
209
|
+
<h1>Harvest Retrospective</h1>
|
|
210
|
+
<p>Are your decisions getting better?</p>
|
|
211
|
+
<div class="meta">
|
|
212
|
+
<div class="meta-item">
|
|
213
|
+
<div class="label">Sprints</div>
|
|
214
|
+
<div class="value">{{SPRINT_COUNT}}</div>
|
|
215
|
+
</div>
|
|
216
|
+
<div class="meta-item">
|
|
217
|
+
<div class="label">Claims</div>
|
|
218
|
+
<div class="value">{{CLAIM_COUNT}}</div>
|
|
219
|
+
</div>
|
|
220
|
+
<div class="meta-item">
|
|
221
|
+
<div class="label">Avg/Sprint</div>
|
|
222
|
+
<div class="value">{{AVG_CLAIMS}}</div>
|
|
223
|
+
</div>
|
|
224
|
+
<div class="meta-item">
|
|
225
|
+
<div class="label">Accuracy</div>
|
|
226
|
+
<div class="value">{{ACCURACY_RATE}}</div>
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
</header>
|
|
230
|
+
|
|
231
|
+
<section>
|
|
232
|
+
<h2>Calibration</h2>
|
|
233
|
+
<p>How often were our predictions right?</p>
|
|
234
|
+
<div class="meta" style="margin-bottom:1rem">
|
|
235
|
+
<div class="meta-item">
|
|
236
|
+
<div class="label">Estimates</div>
|
|
237
|
+
<div class="value">{{ESTIMATE_COUNT}}</div>
|
|
238
|
+
</div>
|
|
239
|
+
<div class="meta-item">
|
|
240
|
+
<div class="label">Matched</div>
|
|
241
|
+
<div class="value">{{MATCHED_COUNT}}</div>
|
|
242
|
+
</div>
|
|
243
|
+
<div class="meta-item">
|
|
244
|
+
<div class="label">Unmatched</div>
|
|
245
|
+
<div class="value">{{UNMATCHED_COUNT}}</div>
|
|
246
|
+
</div>
|
|
247
|
+
</div>
|
|
248
|
+
<div class="insight">{{CALIBRATION_INSIGHT}}</div>
|
|
249
|
+
</section>
|
|
250
|
+
|
|
251
|
+
<section>
|
|
252
|
+
<h2>Claim Analysis</h2>
|
|
253
|
+
<h3>By Type</h3>
|
|
254
|
+
{{TYPE_DISTRIBUTION}}
|
|
255
|
+
<h3>By Evidence Tier</h3>
|
|
256
|
+
{{EVIDENCE_DISTRIBUTION}}
|
|
257
|
+
<h3>Weak Claims (low evidence)</h3>
|
|
258
|
+
{{WEAK_CLAIMS_TABLE}}
|
|
259
|
+
</section>
|
|
260
|
+
|
|
261
|
+
<section>
|
|
262
|
+
<h2>Decision Patterns</h2>
|
|
263
|
+
<p>{{PATTERN_COUNT}} positive patterns, {{ANTI_PATTERN_COUNT}} anti-patterns detected.</p>
|
|
264
|
+
<div class="insight">{{PATTERN_INSIGHT}}</div>
|
|
265
|
+
<h3>Good Patterns</h3>
|
|
266
|
+
{{PATTERNS_LIST}}
|
|
267
|
+
<h3>Anti-Patterns</h3>
|
|
268
|
+
{{ANTI_PATTERNS_LIST}}
|
|
269
|
+
</section>
|
|
270
|
+
|
|
271
|
+
<section>
|
|
272
|
+
<h2>Knowledge Decay</h2>
|
|
273
|
+
<div class="meta" style="margin-bottom:1rem">
|
|
274
|
+
<div class="meta-item">
|
|
275
|
+
<div class="label">Stale</div>
|
|
276
|
+
<div class="value">{{STALE_COUNT}}</div>
|
|
277
|
+
</div>
|
|
278
|
+
<div class="meta-item">
|
|
279
|
+
<div class="label">Decaying</div>
|
|
280
|
+
<div class="value">{{DECAYING_COUNT}}</div>
|
|
281
|
+
</div>
|
|
282
|
+
<div class="meta-item">
|
|
283
|
+
<div class="label">Unresolved</div>
|
|
284
|
+
<div class="value">{{UNRESOLVED_COUNT}}</div>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
<div class="insight">{{DECAY_INSIGHT}}</div>
|
|
288
|
+
{{DECAY_TABLE}}
|
|
289
|
+
</section>
|
|
290
|
+
|
|
291
|
+
<section>
|
|
292
|
+
<h2>Velocity</h2>
|
|
293
|
+
<div class="meta" style="margin-bottom:1rem">
|
|
294
|
+
<div class="meta-item">
|
|
295
|
+
<div class="label">Avg Duration</div>
|
|
296
|
+
<div class="value">{{AVG_DURATION}}</div>
|
|
297
|
+
</div>
|
|
298
|
+
<div class="meta-item">
|
|
299
|
+
<div class="label">Claims/Day</div>
|
|
300
|
+
<div class="value">{{AVG_CLAIMS_PER_DAY}}</div>
|
|
301
|
+
</div>
|
|
302
|
+
<div class="meta-item">
|
|
303
|
+
<div class="label">Stalls</div>
|
|
304
|
+
<div class="value">{{TOTAL_STALLS}}</div>
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
307
|
+
<div class="insight">{{VELOCITY_INSIGHT}}</div>
|
|
308
|
+
{{VELOCITY_TABLE}}
|
|
309
|
+
</section>
|
|
310
|
+
|
|
311
|
+
<footer>
|
|
312
|
+
Generated {{GENERATED_DATE}} by <strong>@grainulation/harvest</strong>
|
|
313
|
+
</footer>
|
|
314
|
+
</body>
|
|
315
|
+
</html>
|