@grainulation/orchard 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 +90 -0
- package/README.md +46 -56
- 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,90 @@
|
|
|
1
|
+
# Contributing to Orchard
|
|
2
|
+
|
|
3
|
+
Thanks for considering contributing. Orchard is the multi-sprint planner for the grainulation ecosystem -- it tracks dependencies, assignments, and timelines across concurrent sprints.
|
|
4
|
+
|
|
5
|
+
## Quick setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/grainulation/orchard.git
|
|
9
|
+
cd orchard
|
|
10
|
+
node bin/orchard.js --help
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
No `npm install` needed -- orchard 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/basic.test.js`
|
|
32
|
+
5. Commit with a clear message
|
|
33
|
+
6. Open a PR
|
|
34
|
+
|
|
35
|
+
## Architecture
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
bin/orchard.js CLI entrypoint -- dispatches subcommands
|
|
39
|
+
lib/scanner.js Auto-detects active sprints in a workspace
|
|
40
|
+
lib/planner.js Sprint planning and scheduling logic
|
|
41
|
+
lib/tracker.js Progress tracking across sprints
|
|
42
|
+
lib/dependencies.js Cross-sprint dependency resolution
|
|
43
|
+
lib/conflicts.js Conflict detection between parallel sprints
|
|
44
|
+
lib/assignments.js Work assignment and load balancing
|
|
45
|
+
lib/timeline.js Timeline generation and critical path
|
|
46
|
+
lib/sync.js State synchronization across sprint repos
|
|
47
|
+
lib/export.js Export planner data to various formats
|
|
48
|
+
lib/dashboard.js Dashboard data aggregation
|
|
49
|
+
lib/server.js Local preview server (SSE, zero deps)
|
|
50
|
+
templates/ HTML templates (orchard-dashboard, etc.)
|
|
51
|
+
public/ Web UI -- multi-sprint planning dashboard
|
|
52
|
+
site/ Public website (orchard.grainulation.com)
|
|
53
|
+
test/ Node built-in test runner tests
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The key architectural principle: **orchard operates above individual sprints.** It scans for active wheat sprints, detects dependencies and conflicts between them, and provides a unified planning view. It reads sprint data but never modifies it directly.
|
|
57
|
+
|
|
58
|
+
## Code style
|
|
59
|
+
|
|
60
|
+
- Zero dependencies. If you need something, write it or use Node built-ins.
|
|
61
|
+
- No transpilation. Ship what you write.
|
|
62
|
+
- ESM imports (`import`/`export`). Node 18+ required.
|
|
63
|
+
- Keep functions small. If a function needs a scroll, split it.
|
|
64
|
+
- No emojis in code, CLI output, or dashboards.
|
|
65
|
+
|
|
66
|
+
## Testing
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
node test/basic.test.js
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Tests use Node's built-in test runner. No test framework dependencies.
|
|
73
|
+
|
|
74
|
+
## Commit messages
|
|
75
|
+
|
|
76
|
+
Follow the existing pattern:
|
|
77
|
+
```
|
|
78
|
+
orchard: <what changed>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Examples:
|
|
82
|
+
```
|
|
83
|
+
orchard: add cross-sprint dependency graph
|
|
84
|
+
orchard: fix timeline calculation for overlapping sprints
|
|
85
|
+
orchard: update scanner to detect archived sprints
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT. See LICENSE for details.
|
package/README.md
CHANGED
|
@@ -1,28 +1,30 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="site/wordmark.svg" alt="Orchard" width="400">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
>
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/@grainulation/orchard"><img src="https://img.shields.io/npm/v/@grainulation/orchard" alt="npm version"></a> <a href="https://www.npmjs.com/package/@grainulation/orchard"><img src="https://img.shields.io/npm/dm/@grainulation/orchard" alt="npm downloads"></a> <a href="https://github.com/grainulation/orchard/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@grainulation/orchard" alt="license"></a> <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/@grainulation/orchard" alt="node"></a> <a href="https://github.com/grainulation/orchard/actions"><img src="https://github.com/grainulation/orchard/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
7
|
+
</p>
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
<p align="center"><strong>Multi-sprint orchestration and dependency tracking.</strong></p>
|
|
10
|
+
|
|
11
|
+
12 sprints running. One command to see them all. Orchard coordinates parallel research across teams with dependency graphs, conflict detection, and unified dashboards.
|
|
6
12
|
|
|
7
13
|
## Install
|
|
8
14
|
|
|
9
15
|
```bash
|
|
10
|
-
|
|
16
|
+
npm install -g @grainulation/orchard
|
|
11
17
|
```
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
Or use directly:
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
- **Resource allocation** -- distribute research bandwidth
|
|
19
|
-
- **Cross-sprint conflict detection** -- when two sprints reach opposing conclusions
|
|
20
|
-
- **Unified status dashboard** across all active sprints
|
|
21
|
-
- **Sprint scheduling and deadline tracking**
|
|
21
|
+
```bash
|
|
22
|
+
npx @grainulation/orchard status
|
|
23
|
+
```
|
|
22
24
|
|
|
23
25
|
## Quick start
|
|
24
26
|
|
|
25
|
-
Create
|
|
27
|
+
Create `orchard.json` in your project root:
|
|
26
28
|
|
|
27
29
|
```json
|
|
28
30
|
{
|
|
@@ -50,68 +52,56 @@ Create a `orchard.json` in your project root:
|
|
|
50
52
|
Then:
|
|
51
53
|
|
|
52
54
|
```bash
|
|
53
|
-
#
|
|
54
|
-
orchard
|
|
55
|
-
|
|
56
|
-
#
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
# Assign someone to a sprint
|
|
60
|
-
orchard assign ./sprints/data-migration carol
|
|
55
|
+
orchard plan # Show the dependency graph
|
|
56
|
+
orchard status # Check status of all sprints
|
|
57
|
+
orchard sync # Sync status from sprint directories
|
|
58
|
+
orchard dashboard # Generate unified HTML dashboard
|
|
59
|
+
```
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
orchard sync
|
|
61
|
+
## What it does
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
- **Sprint dependency graphs** -- "sprint B needs sprint A's results first"
|
|
64
|
+
- **Cross-sprint conflict detection** -- when two sprints reach opposing conclusions
|
|
65
|
+
- **Team assignment** -- who's running which sprint
|
|
66
|
+
- **Unified status dashboard** across all active sprints
|
|
67
|
+
- **Sprint scheduling and deadline tracking**
|
|
68
|
+
- **Topological sort** -- determines execution order, flags cycles
|
|
68
69
|
|
|
69
|
-
##
|
|
70
|
+
## CLI
|
|
70
71
|
|
|
71
72
|
| Command | Description |
|
|
72
73
|
|---------|-------------|
|
|
73
|
-
| `orchard plan` | Show sprint dependency graph
|
|
74
|
+
| `orchard plan` | Show sprint dependency graph |
|
|
74
75
|
| `orchard status` | Show status of all tracked sprints |
|
|
75
76
|
| `orchard assign <path> <person>` | Assign a person to a sprint |
|
|
76
|
-
| `orchard sync` | Sync sprint states from
|
|
77
|
+
| `orchard sync` | Sync sprint states from directories |
|
|
77
78
|
| `orchard dashboard [outfile]` | Generate unified HTML dashboard |
|
|
78
|
-
| `orchard init` | Initialize orchard.json
|
|
79
|
+
| `orchard init` | Initialize orchard.json |
|
|
79
80
|
| `orchard serve` | Start the portfolio dashboard web server |
|
|
80
|
-
| `orchard help` | Show help |
|
|
81
81
|
|
|
82
|
-
##
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
{
|
|
86
|
-
sprints: Array<{
|
|
87
|
-
path: string; // Relative path to sprint directory
|
|
88
|
-
question: string; // The research question
|
|
89
|
-
depends_on: string[]; // Paths of prerequisite sprints
|
|
90
|
-
assigned_to: string; // Person responsible
|
|
91
|
-
deadline: string; // ISO date string
|
|
92
|
-
status: string; // active | done | blocked | not-started
|
|
93
|
-
}>
|
|
94
|
-
}
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## How it works
|
|
98
|
-
|
|
99
|
-
Orchard reads `orchard.json` for the sprint graph, then scans each sprint directory for `claims.json` and `compilation.json` to determine actual state. It detects conflicts by comparing claims across sprints that share tags.
|
|
100
|
-
|
|
101
|
-
### Conflict detection
|
|
82
|
+
## Conflict detection
|
|
102
83
|
|
|
103
84
|
Orchard flags two types of cross-sprint conflicts:
|
|
104
85
|
|
|
105
|
-
1. **Opposing recommendations** -- two sprints make recommendations on the same topic that
|
|
86
|
+
1. **Opposing recommendations** -- two sprints make recommendations on the same topic that contradict
|
|
106
87
|
2. **Constraint-recommendation tension** -- one sprint's constraints conflict with another's recommendations
|
|
107
88
|
|
|
108
|
-
|
|
89
|
+
## Zero dependencies
|
|
109
90
|
|
|
110
|
-
|
|
91
|
+
Node built-in modules only.
|
|
111
92
|
|
|
112
|
-
##
|
|
93
|
+
## Part of the grainulation ecosystem
|
|
113
94
|
|
|
114
|
-
|
|
95
|
+
| Tool | Role |
|
|
96
|
+
|------|------|
|
|
97
|
+
| [wheat](https://github.com/grainulation/wheat) | Research engine -- grow structured evidence |
|
|
98
|
+
| [farmer](https://github.com/grainulation/farmer) | Permission dashboard -- approve AI actions in real time |
|
|
99
|
+
| [barn](https://github.com/grainulation/barn) | Shared tools -- templates, validators, sprint detection |
|
|
100
|
+
| [mill](https://github.com/grainulation/mill) | Format conversion -- export to PDF, CSV, slides, 24 formats |
|
|
101
|
+
| [silo](https://github.com/grainulation/silo) | Knowledge storage -- reusable claim libraries and packs |
|
|
102
|
+
| [harvest](https://github.com/grainulation/harvest) | Analytics -- cross-sprint patterns and prediction scoring |
|
|
103
|
+
| **orchard** | Orchestration -- multi-sprint coordination and dependencies |
|
|
104
|
+
| [grainulation](https://github.com/grainulation/grainulation) | Unified CLI -- single entry point to the ecosystem |
|
|
115
105
|
|
|
116
106
|
## License
|
|
117
107
|
|
package/lib/server.js
CHANGED
|
@@ -80,7 +80,7 @@ const ROUTES = [
|
|
|
80
80
|
|
|
81
81
|
// ── Load existing CJS modules via createRequire ──────────────────────────────
|
|
82
82
|
|
|
83
|
-
const {
|
|
83
|
+
const { claimsPaths } = require('./dashboard.js');
|
|
84
84
|
|
|
85
85
|
// ── State ─────────────────────────────────────────────────────────────────────
|
|
86
86
|
|
|
@@ -474,38 +474,6 @@ function readBody(req) {
|
|
|
474
474
|
});
|
|
475
475
|
}
|
|
476
476
|
|
|
477
|
-
// ── SSE live-reload injection ────────────────────────────────────────────────
|
|
478
|
-
|
|
479
|
-
const SSE_SCRIPT = `
|
|
480
|
-
<script>
|
|
481
|
-
(function() {
|
|
482
|
-
var es, retryCount = 0;
|
|
483
|
-
var dot = document.getElementById('statusDot');
|
|
484
|
-
function connect() {
|
|
485
|
-
es = new EventSource('/events');
|
|
486
|
-
es.addEventListener('update', function() { location.reload(); });
|
|
487
|
-
es.onopen = function() {
|
|
488
|
-
retryCount = 0;
|
|
489
|
-
if (dot) dot.className = 'status-dot ok';
|
|
490
|
-
if (window._grainSetState) window._grainSetState('idle');
|
|
491
|
-
};
|
|
492
|
-
es.onerror = function() {
|
|
493
|
-
es.close();
|
|
494
|
-
if (dot) dot.className = 'status-dot';
|
|
495
|
-
if (window._grainSetState) window._grainSetState('orbit');
|
|
496
|
-
var delay = Math.min(30000, 1000 * Math.pow(2, retryCount)) + Math.random() * 1000;
|
|
497
|
-
retryCount++;
|
|
498
|
-
setTimeout(connect, delay);
|
|
499
|
-
};
|
|
500
|
-
}
|
|
501
|
-
connect();
|
|
502
|
-
})();
|
|
503
|
-
</script>`;
|
|
504
|
-
|
|
505
|
-
function injectSSE(html) {
|
|
506
|
-
return html.replace('</body>', SSE_SCRIPT + '\n</body>');
|
|
507
|
-
}
|
|
508
|
-
|
|
509
477
|
// ── HTTP server ───────────────────────────────────────────────────────────────
|
|
510
478
|
|
|
511
479
|
const server = createServer(async (req, res) => {
|
|
@@ -589,21 +557,16 @@ ${ROUTES.map(r => '<tr><td><code>'+r.method+'</code></td><td><code>'+r.path+'</c
|
|
|
589
557
|
return;
|
|
590
558
|
}
|
|
591
559
|
|
|
592
|
-
// ── Dashboard UI (
|
|
560
|
+
// ── Dashboard UI (web app from public/) ──
|
|
593
561
|
if (req.method === 'GET' && (url.pathname === '/' || url.pathname === '/index.html')) {
|
|
562
|
+
const indexPath = join(PUBLIC_DIR, 'index.html');
|
|
594
563
|
try {
|
|
595
|
-
const
|
|
596
|
-
if (graphData.sprints.length === 0) {
|
|
597
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
598
|
-
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>');
|
|
599
|
-
return;
|
|
600
|
-
}
|
|
601
|
-
const html = injectSSE(buildHtml(graphData));
|
|
564
|
+
const html = readFileSync(indexPath, 'utf8');
|
|
602
565
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
603
566
|
res.end(html);
|
|
604
567
|
} catch (err) {
|
|
605
568
|
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
606
|
-
res.end('Error
|
|
569
|
+
res.end('Error reading dashboard: ' + err.message);
|
|
607
570
|
}
|
|
608
571
|
return;
|
|
609
572
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grainulation/orchard",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Multi-sprint research orchestrator \u2014 coordinate parallel research across teams",
|
|
5
5
|
"main": "lib/planner.js",
|
|
6
6
|
"exports": {
|
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
"public/",
|
|
21
21
|
"templates/",
|
|
22
22
|
"README.md",
|
|
23
|
-
"LICENSE"
|
|
23
|
+
"LICENSE",
|
|
24
|
+
"CODE_OF_CONDUCT.md",
|
|
25
|
+
"CONTRIBUTING.md"
|
|
24
26
|
],
|
|
25
27
|
"scripts": {
|
|
26
28
|
"test": "node test/basic.test.js",
|