@grainulation/harvest 1.0.0 → 1.0.1
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/CODE_OF_CONDUCT.md +25 -0
- package/CONTRIBUTING.md +87 -0
- package/README.md +43 -45
- package/lib/server.js +5 -42
- package/package.json +4 -2
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our standards
|
|
4
|
+
|
|
5
|
+
We are committed to providing a welcoming and productive environment for everyone. We expect participants to:
|
|
6
|
+
|
|
7
|
+
- Use welcoming and inclusive language
|
|
8
|
+
- Respect differing viewpoints and experiences
|
|
9
|
+
- Accept constructive criticism gracefully
|
|
10
|
+
- Focus on what is best for the community and the project
|
|
11
|
+
- Show empathy toward other participants
|
|
12
|
+
|
|
13
|
+
Unacceptable behavior includes harassment, trolling, personal attacks, and publishing others' private information without permission.
|
|
14
|
+
|
|
15
|
+
## Scope
|
|
16
|
+
|
|
17
|
+
This code of conduct applies to all project spaces -- issues, pull requests, discussions, and any public channel where someone represents the project.
|
|
18
|
+
|
|
19
|
+
## Enforcement
|
|
20
|
+
|
|
21
|
+
Instances of unacceptable behavior may be reported to the project maintainers. All complaints will be reviewed and investigated, and will result in a response deemed necessary and appropriate.
|
|
22
|
+
|
|
23
|
+
## Attribution
|
|
24
|
+
|
|
25
|
+
Adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1.
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Contributing to Harvest
|
|
2
|
+
|
|
3
|
+
Thanks for considering contributing. Harvest is the retrospective and analytics engine for the grainulation ecosystem -- it turns sprint history into insights and calibration data.
|
|
4
|
+
|
|
5
|
+
## Quick setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/grainulation/harvest.git
|
|
9
|
+
cd harvest
|
|
10
|
+
node bin/harvest.js --help
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
No `npm install` needed -- harvest has zero dependencies.
|
|
14
|
+
|
|
15
|
+
## How to contribute
|
|
16
|
+
|
|
17
|
+
### Report a bug
|
|
18
|
+
Open an issue with:
|
|
19
|
+
- What you expected
|
|
20
|
+
- What happened instead
|
|
21
|
+
- Your Node version (`node --version`)
|
|
22
|
+
- Steps to reproduce
|
|
23
|
+
|
|
24
|
+
### Suggest a feature
|
|
25
|
+
Open an issue describing the use case, not just the solution. "I need X because Y" is more useful than "add X."
|
|
26
|
+
|
|
27
|
+
### Submit a PR
|
|
28
|
+
1. Fork the repo
|
|
29
|
+
2. Create a branch (`git checkout -b fix/description`)
|
|
30
|
+
3. Make your changes
|
|
31
|
+
4. Run the tests: `node --test test/basic.test.js`
|
|
32
|
+
5. Commit with a clear message
|
|
33
|
+
6. Open a PR
|
|
34
|
+
|
|
35
|
+
## Architecture
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
bin/harvest.js CLI entrypoint -- dispatches subcommands
|
|
39
|
+
lib/analyzer.js Sprint data analysis and pattern detection
|
|
40
|
+
lib/calibration.js Prediction vs outcome scoring
|
|
41
|
+
lib/decay.js Claim staleness and evidence decay
|
|
42
|
+
lib/patterns.js Recurring pattern extraction
|
|
43
|
+
lib/report.js Report generation from analyzed data
|
|
44
|
+
lib/server.js Local preview server (SSE, zero deps)
|
|
45
|
+
lib/templates.js Template rendering for HTML output
|
|
46
|
+
lib/velocity.js Sprint velocity tracking
|
|
47
|
+
templates/ HTML templates (retrospective, etc.)
|
|
48
|
+
public/ Web UI -- retrospective dashboard
|
|
49
|
+
site/ Public website (harvest.grainulation.com)
|
|
50
|
+
test/ Node built-in test runner tests
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The key architectural principle: **harvest reads sprint artifacts (claims, compilations, git history) and produces calibrated insights.** It never modifies source data -- read-only analysis, write-only reports.
|
|
54
|
+
|
|
55
|
+
## Code style
|
|
56
|
+
|
|
57
|
+
- Zero dependencies. If you need something, write it or use Node built-ins.
|
|
58
|
+
- No transpilation. Ship what you write.
|
|
59
|
+
- ESM imports (`import`/`export`). Node 18+ required.
|
|
60
|
+
- Keep functions small. If a function needs a scroll, split it.
|
|
61
|
+
- No emojis in code, CLI output, or reports.
|
|
62
|
+
|
|
63
|
+
## Testing
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
node --test test/basic.test.js
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Tests use Node's built-in test runner. No test framework dependencies.
|
|
70
|
+
|
|
71
|
+
## Commit messages
|
|
72
|
+
|
|
73
|
+
Follow the existing pattern:
|
|
74
|
+
```
|
|
75
|
+
harvest: <what changed>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Examples:
|
|
79
|
+
```
|
|
80
|
+
harvest: add velocity trend chart
|
|
81
|
+
harvest: fix decay calculation for stale claims
|
|
82
|
+
harvest: update calibration scoring algorithm
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
MIT. See LICENSE for details.
|
package/README.md
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="site/wordmark.svg" alt="Harvest" width="400">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/@grainulation/harvest"><img src="https://img.shields.io/npm/v/@grainulation/harvest" alt="npm version"></a> <a href="https://www.npmjs.com/package/@grainulation/harvest"><img src="https://img.shields.io/npm/dm/@grainulation/harvest" alt="npm downloads"></a> <a href="https://github.com/grainulation/harvest/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@grainulation/harvest" alt="license"></a> <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/@grainulation/harvest" alt="node"></a> <a href="https://github.com/grainulation/harvest/actions"><img src="https://github.com/grainulation/harvest/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
7
|
+
</p>
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
<p align="center"><strong>Are your decisions getting better?</strong></p>
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
Harvest is the analytics layer for research sprints. It looks across sprints to find patterns, score predictions, and surface knowledge that's gone stale.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g @grainulation/harvest
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or use directly:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx @grainulation/harvest analyze ./sprints/
|
|
23
|
+
```
|
|
8
24
|
|
|
9
25
|
## What it does
|
|
10
26
|
|
|
@@ -15,21 +31,9 @@ Learn from every decision you've made.
|
|
|
15
31
|
- **Sprint velocity** -- how long do sprints take, where do they stall?
|
|
16
32
|
- **Retrospective reports** -- dark-themed HTML reports for the team
|
|
17
33
|
|
|
18
|
-
##
|
|
19
|
-
|
|
20
|
-
```sh
|
|
21
|
-
npm install @grainulation/harvest
|
|
22
|
-
```
|
|
34
|
+
## Quick start
|
|
23
35
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
```sh
|
|
27
|
-
npx @grainulation/harvest analyze ./sprints/
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Usage
|
|
31
|
-
|
|
32
|
-
```sh
|
|
36
|
+
```bash
|
|
33
37
|
# Cross-sprint claim analysis
|
|
34
38
|
harvest analyze ./sprints/
|
|
35
39
|
|
|
@@ -50,52 +54,46 @@ harvest report ./sprints/ -o retrospective.html
|
|
|
50
54
|
|
|
51
55
|
# All analyses in one pass
|
|
52
56
|
harvest trends ./sprints/ --json
|
|
57
|
+
|
|
58
|
+
# Start the live dashboard (SSE updates, dark theme)
|
|
59
|
+
harvest serve --root ./sprints/ --port 9096
|
|
60
|
+
|
|
61
|
+
# Connect to farmer for mobile monitoring
|
|
62
|
+
harvest connect farmer --url http://localhost:9094
|
|
53
63
|
```
|
|
54
64
|
|
|
55
65
|
## Data format
|
|
56
66
|
|
|
57
67
|
Harvest reads standard wheat sprint data:
|
|
58
68
|
|
|
59
|
-
- `claims.json` -- array of typed claims with `id`, `type`, `evidence`, `status`, `text`, `created
|
|
69
|
+
- `claims.json` -- array of typed claims with `id`, `type`, `evidence`, `status`, `text`, `created`
|
|
60
70
|
- `compilation.json` -- compiled sprint state (optional, enriches analysis)
|
|
61
71
|
- Git history on `claims.json` -- used for velocity and timing analysis
|
|
62
72
|
|
|
63
|
-
Point harvest at a directory containing sprint subdirectories, or at a single sprint directory
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
sprints/
|
|
67
|
-
sprint-alpha/
|
|
68
|
-
claims.json
|
|
69
|
-
compilation.json
|
|
70
|
-
sprint-beta/
|
|
71
|
-
claims.json
|
|
72
|
-
```
|
|
73
|
+
Point harvest at a directory containing sprint subdirectories, or at a single sprint directory.
|
|
73
74
|
|
|
74
75
|
## Design
|
|
75
76
|
|
|
76
|
-
- **Zero dependencies** -- Node built-in modules only (fs, path, child_process)
|
|
77
77
|
- **Reads, never writes** -- harvest is a pure analysis tool; it won't modify your sprint data
|
|
78
78
|
- **Git-aware** -- uses git log timestamps for velocity analysis when available
|
|
79
79
|
- **Composable** -- each module (analyzer, calibration, patterns, decay, velocity) works independently
|
|
80
80
|
|
|
81
|
-
##
|
|
81
|
+
## Zero dependencies
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|---|---|
|
|
85
|
-
| `constraint` | Hard requirements, non-negotiable |
|
|
86
|
-
| `factual` | Verifiable statements |
|
|
87
|
-
| `estimate` | Predictions, projections, ranges |
|
|
88
|
-
| `risk` | Potential failure modes |
|
|
89
|
-
| `recommendation` | Proposed courses of action |
|
|
90
|
-
| `feedback` | Stakeholder input |
|
|
83
|
+
Node built-in modules only.
|
|
91
84
|
|
|
92
|
-
##
|
|
85
|
+
## Part of the grainulation ecosystem
|
|
93
86
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
87
|
+
| Tool | Role |
|
|
88
|
+
|------|------|
|
|
89
|
+
| [wheat](https://github.com/grainulation/wheat) | Research engine -- grow structured evidence |
|
|
90
|
+
| [farmer](https://github.com/grainulation/farmer) | Permission dashboard -- approve AI actions in real time |
|
|
91
|
+
| [barn](https://github.com/grainulation/barn) | Shared tools -- templates, validators, sprint detection |
|
|
92
|
+
| [mill](https://github.com/grainulation/mill) | Format conversion -- export to PDF, CSV, slides, 24 formats |
|
|
93
|
+
| [silo](https://github.com/grainulation/silo) | Knowledge storage -- reusable claim libraries and packs |
|
|
94
|
+
| **harvest** | Analytics -- cross-sprint patterns and prediction scoring |
|
|
95
|
+
| [orchard](https://github.com/grainulation/orchard) | Orchestration -- multi-sprint coordination and dependencies |
|
|
96
|
+
| [grainulation](https://github.com/grainulation/grainulation) | Unified CLI -- single entry point to the ecosystem |
|
|
99
97
|
|
|
100
98
|
## License
|
|
101
99
|
|
package/lib/server.js
CHANGED
|
@@ -81,7 +81,7 @@ const { analyze } = require('./analyzer.js');
|
|
|
81
81
|
const { measureVelocity } = require('./velocity.js');
|
|
82
82
|
const { checkDecay } = require('./decay.js');
|
|
83
83
|
const { calibrate } = require('./calibration.js');
|
|
84
|
-
const {
|
|
84
|
+
const { claimsPaths } = require('./dashboard.js');
|
|
85
85
|
|
|
86
86
|
// ── Sprint discovery ─────────────────────────────────────────────────────────
|
|
87
87
|
|
|
@@ -204,38 +204,6 @@ function jsonResponse(res, code, data) {
|
|
|
204
204
|
res.end(JSON.stringify(data));
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
// ── SSE live-reload injection ────────────────────────────────────────────────
|
|
208
|
-
|
|
209
|
-
const SSE_SCRIPT = `
|
|
210
|
-
<script>
|
|
211
|
-
(function() {
|
|
212
|
-
var es, retryCount = 0;
|
|
213
|
-
var dot = document.getElementById('statusDot');
|
|
214
|
-
function connect() {
|
|
215
|
-
es = new EventSource('/events');
|
|
216
|
-
es.addEventListener('update', function() { location.reload(); });
|
|
217
|
-
es.onopen = function() {
|
|
218
|
-
retryCount = 0;
|
|
219
|
-
if (dot) dot.className = 'status-dot ok';
|
|
220
|
-
if (window._grainSetState) window._grainSetState('idle');
|
|
221
|
-
};
|
|
222
|
-
es.onerror = function() {
|
|
223
|
-
es.close();
|
|
224
|
-
if (dot) dot.className = 'status-dot';
|
|
225
|
-
if (window._grainSetState) window._grainSetState('orbit');
|
|
226
|
-
var delay = Math.min(30000, 1000 * Math.pow(2, retryCount)) + Math.random() * 1000;
|
|
227
|
-
retryCount++;
|
|
228
|
-
setTimeout(connect, delay);
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
connect();
|
|
232
|
-
})();
|
|
233
|
-
</script>`;
|
|
234
|
-
|
|
235
|
-
function injectSSE(html) {
|
|
236
|
-
return html.replace('</body>', SSE_SCRIPT + '\n</body>');
|
|
237
|
-
}
|
|
238
|
-
|
|
239
207
|
// ── HTTP server ───────────────────────────────────────────────────────────────
|
|
240
208
|
|
|
241
209
|
const server = createServer(async (req, res) => {
|
|
@@ -375,21 +343,16 @@ ${ROUTES.map(r => '<tr><td><code>'+r.method+'</code></td><td><code>'+r.path+'</c
|
|
|
375
343
|
return;
|
|
376
344
|
}
|
|
377
345
|
|
|
378
|
-
// ── Dashboard UI (
|
|
346
|
+
// ── Dashboard UI (web app from public/) ──
|
|
379
347
|
if (req.method === 'GET' && (url.pathname === '/' || url.pathname === '/index.html')) {
|
|
348
|
+
const indexPath = join(PUBLIC_DIR, 'index.html');
|
|
380
349
|
try {
|
|
381
|
-
const
|
|
382
|
-
if (sprints.length === 0) {
|
|
383
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
384
|
-
res.end('<html><body style="background:#0a0e1a;color:#e2e8f0;font-family:monospace;padding:40px"><h1>No claims.json files found</h1><p>Watching for changes...</p>' + SSE_SCRIPT + '</body></html>');
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
const html = injectSSE(buildHtml(sprints));
|
|
350
|
+
const html = readFileSync(indexPath, 'utf8');
|
|
388
351
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
389
352
|
res.end(html);
|
|
390
353
|
} catch (err) {
|
|
391
354
|
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
392
|
-
res.end('Error
|
|
355
|
+
res.end('Error reading dashboard: ' + err.message);
|
|
393
356
|
}
|
|
394
357
|
return;
|
|
395
358
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grainulation/harvest",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Analytics and retrospective layer for research sprints -- learn from every decision you've made",
|
|
5
5
|
"main": "lib/analyzer.js",
|
|
6
6
|
"exports": {
|
|
@@ -35,7 +35,9 @@
|
|
|
35
35
|
"public/",
|
|
36
36
|
"templates/",
|
|
37
37
|
"README.md",
|
|
38
|
-
"LICENSE"
|
|
38
|
+
"LICENSE",
|
|
39
|
+
"CODE_OF_CONDUCT.md",
|
|
40
|
+
"CONTRIBUTING.md"
|
|
39
41
|
],
|
|
40
42
|
"engines": {
|
|
41
43
|
"node": ">=18.0.0"
|