@grainulation/barn 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.
@@ -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.
@@ -0,0 +1,97 @@
1
+ # Contributing to Barn
2
+
3
+ Thanks for considering contributing. Barn is the template engine for the grainulation ecosystem -- it turns structured data into polished HTML artifacts.
4
+
5
+ ## Quick setup
6
+
7
+ ```bash
8
+ git clone https://github.com/grainulation/barn.git
9
+ cd barn
10
+ node bin/barn.js --help
11
+ ```
12
+
13
+ No `npm install` needed -- barn has zero dependencies.
14
+
15
+ ## How to contribute
16
+
17
+ ### Report a bug
18
+
19
+ Open an issue with:
20
+
21
+ - What you expected
22
+ - What happened instead
23
+ - Your Node version (`node --version`)
24
+ - Steps to reproduce
25
+
26
+ ### Suggest a feature
27
+
28
+ Open an issue describing the use case, not just the solution. "I need X because Y" is more useful than "add X."
29
+
30
+ ### Submit a PR
31
+
32
+ 1. Fork the repo
33
+ 2. Create a branch (`git checkout -b fix/description`)
34
+ 3. Make your changes
35
+ 4. Run the tests: `node test/basic.test.js`
36
+ 5. Commit with a clear message
37
+ 6. Open a PR
38
+
39
+ ### Add a template
40
+
41
+ Templates live in `templates/`. Each template is a pair: an HTML file and a JSON schema file. To add one:
42
+
43
+ 1. Create `templates/your-template.html` and `templates/your-template.json`
44
+ 2. Follow the pattern of existing templates (use `template.schema.json` as the base schema)
45
+ 3. Ensure the HTML is self-contained (inline CSS/JS, no external dependencies)
46
+ 4. Add it to the README templates table
47
+
48
+ ## Architecture
49
+
50
+ ```
51
+ bin/barn.js CLI entrypoint -- dispatches subcommands
52
+ lib/index.js Core library -- template resolution and rendering
53
+ lib/server.js Local preview server (SSE, zero deps)
54
+ templates/ HTML + JSON schema pairs for each artifact type
55
+ public/ Web UI -- two-column template nav + preview
56
+ site/ Public website (barn.grainulation.com)
57
+ tools/ Utility scripts
58
+ test/ Node built-in test runner tests
59
+ ```
60
+
61
+ The key architectural principle: **templates are self-contained HTML with inline CSS/JS.** No external dependencies, no build step, no CDN links.
62
+
63
+ ## Code style
64
+
65
+ - Zero dependencies. If you need something, write it or use Node built-ins.
66
+ - No transpilation. Ship what you write.
67
+ - ESM imports (`import`/`export`). Node 18+ required.
68
+ - Keep functions small. If a function needs a scroll, split it.
69
+ - No emojis in code, CLI output, or templates.
70
+
71
+ ## Testing
72
+
73
+ ```bash
74
+ node test/basic.test.js
75
+ ```
76
+
77
+ Tests use Node's built-in test runner. No test framework dependencies.
78
+
79
+ ## Commit messages
80
+
81
+ Follow the existing pattern:
82
+
83
+ ```
84
+ barn: <what changed>
85
+ ```
86
+
87
+ Examples:
88
+
89
+ ```
90
+ barn: add postmortem template
91
+ barn: fix server SSE reconnection
92
+ barn: update schema validation for nested fields
93
+ ```
94
+
95
+ ## License
96
+
97
+ MIT. See LICENSE for details.
package/README.md CHANGED
@@ -1,8 +1,15 @@
1
- # barn
1
+ <p align="center">
2
+ <img src="site/wordmark.svg" alt="Barn" width="400">
3
+ </p>
2
4
 
3
- Open tools for structured research. Use with wheat, or use standalone.
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@grainulation/barn"><img src="https://img.shields.io/npm/v/@grainulation/barn" alt="npm version"></a> <a href="https://www.npmjs.com/package/@grainulation/barn"><img src="https://img.shields.io/npm/dm/@grainulation/barn" alt="npm downloads"></a> <a href="https://github.com/grainulation/barn/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="license"></a> <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/@grainulation/barn" alt="node"></a> <a href="https://github.com/grainulation/barn/actions"><img src="https://github.com/grainulation/barn/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
7
+ <a href="https://deepwiki.com/grainulation/barn"><img src="https://deepwiki.com/badge.svg" alt="Explore on DeepWiki"></a>
8
+ </p>
4
9
 
5
- Barn extracts the reusable utilities from the [wheat](https://github.com/grainulation/wheat) research sprint system into a standalone package. Zero npm dependencies -- Node built-in only.
10
+ <p align="center"><strong>Shared tools for the grainulation ecosystem.</strong></p>
11
+
12
+ Barn extracts the reusable utilities from [wheat](https://github.com/grainulation/wheat) into a standalone package. Sprint detection, manifest generation, PDF builds, and 17 HTML templates for research artifacts.
6
13
 
7
14
  ## Install
8
15
 
@@ -49,38 +56,48 @@ barn build-pdf output/brief.md
49
56
 
50
57
  ## Templates
51
58
 
52
- HTML templates for sprint artifacts. Self-contained (inline CSS/JS, no external deps), dark theme, mobile responsive.
53
-
54
- - **adr.html** -- Architecture Decision Record
55
- - **brief.html** -- Sprint brief / recommendation document
56
- - **certificate.html** -- Compilation certificate
57
- - **changelog.html** -- Sprint changelog
58
- - **comparison.html** -- Side-by-side comparison dashboard
59
- - **conflict-map.html** -- Claim conflict visualization
60
- - **dashboard.html** -- Sprint status dashboard
61
- - **email-digest.html** -- Email digest summary
62
- - **evidence-matrix.html** -- Evidence tier matrix
63
- - **explainer.html** -- Full-screen scroll-snap presentation
64
- - **handoff.html** -- Knowledge transfer document
65
- - **one-pager.html** -- Single-page executive summary
66
- - **postmortem.html** -- Sprint postmortem
67
- - **rfc.html** -- Request for Comments
68
- - **risk-register.html** -- Risk tracking register
69
- - **slide-deck.html** -- Slide deck presentation
70
- - **wiki-page.html** -- Wiki-style documentation page
71
-
72
- Copy templates into your project:
59
+ 17 self-contained HTML templates for sprint artifacts. Dark theme, inline CSS/JS, no external deps, mobile responsive.
60
+
61
+ | Template | Purpose |
62
+ | ---------------------- | -------------------------------------- |
63
+ | `adr.html` | Architecture Decision Record |
64
+ | `brief.html` | Sprint brief / recommendation document |
65
+ | `certificate.html` | Compilation certificate |
66
+ | `changelog.html` | Sprint changelog |
67
+ | `comparison.html` | Side-by-side comparison dashboard |
68
+ | `conflict-map.html` | Claim conflict visualization |
69
+ | `dashboard.html` | Sprint status dashboard |
70
+ | `email-digest.html` | Email digest summary |
71
+ | `evidence-matrix.html` | Evidence tier matrix |
72
+ | `explainer.html` | Full-screen scroll-snap presentation |
73
+ | `handoff.html` | Knowledge transfer document |
74
+ | `one-pager.html` | Single-page executive summary |
75
+ | `postmortem.html` | Sprint postmortem |
76
+ | `rfc.html` | Request for Comments |
77
+ | `risk-register.html` | Risk tracking register |
78
+ | `slide-deck.html` | Slide deck presentation |
79
+ | `wiki-page.html` | Wiki-style documentation page |
73
80
 
74
81
  ```bash
75
82
  cp node_modules/@grainulation/barn/templates/explainer.html ./output/
76
83
  ```
77
84
 
78
- ## Philosophy
85
+ ## Zero dependencies
86
+
87
+ Node built-in modules only. No npm install waterfall.
88
+
89
+ ## Part of the grainulation ecosystem
79
90
 
80
- - Zero npm dependencies. Node built-in modules only.
81
- - Git as the source of truth. No config files for state that git already knows.
82
- - Self-describing structures. New sessions understand the repo without full scans.
83
- - Works with AI search tools (Glob, Grep, Read) out of the box.
91
+ | Tool | Role |
92
+ | ------------------------------------------------------------ | ----------------------------------------------------------- |
93
+ | [wheat](https://github.com/grainulation/wheat) | Research engine -- grow structured evidence |
94
+ | [farmer](https://github.com/grainulation/farmer) | Permission dashboard -- approve AI actions in real time |
95
+ | **barn** | Shared tools -- templates, validators, sprint detection |
96
+ | [mill](https://github.com/grainulation/mill) | Format conversion -- export to PDF, CSV, slides, 24 formats |
97
+ | [silo](https://github.com/grainulation/silo) | Knowledge storage -- reusable claim libraries and packs |
98
+ | [harvest](https://github.com/grainulation/harvest) | Analytics -- cross-sprint patterns and prediction scoring |
99
+ | [orchard](https://github.com/grainulation/orchard) | Orchestration -- multi-sprint coordination and dependencies |
100
+ | [grainulation](https://github.com/grainulation/grainulation) | Unified CLI -- single entry point to the ecosystem |
84
101
 
85
102
  ## License
86
103
 
package/bin/barn.js CHANGED
@@ -14,44 +14,51 @@
14
14
  * Zero npm dependencies (Node built-in only).
15
15
  */
16
16
 
17
- import { fileURLToPath } from 'node:url';
18
- import { dirname, join } from 'node:path';
19
- import { fork } from 'node:child_process';
17
+ import { fileURLToPath } from "node:url";
18
+ import { dirname, join } from "node:path";
19
+ import { fork } from "node:child_process";
20
20
 
21
21
  const __dirname = dirname(fileURLToPath(import.meta.url));
22
- const TOOLS_DIR = join(__dirname, '..', 'tools');
22
+ const TOOLS_DIR = join(__dirname, "..", "tools");
23
23
 
24
- const LIB_DIR = join(__dirname, '..', 'lib');
24
+ const LIB_DIR = join(__dirname, "..", "lib");
25
25
 
26
26
  // ── --version / -v ───────────────────────────────────────────────────────────
27
- import { readFileSync } from 'node:fs';
27
+ import { readFileSync } from "node:fs";
28
28
 
29
29
  const args = process.argv.slice(2);
30
30
  const command = args[0];
31
31
 
32
- if (command === '--version' || command === '-v') {
33
- const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
32
+ if (command === "--version" || command === "-v") {
33
+ const pkg = JSON.parse(
34
+ readFileSync(join(__dirname, "..", "package.json"), "utf8"),
35
+ );
34
36
  console.log(pkg.version);
35
37
  process.exit(0);
36
38
  }
37
39
 
38
- const verbose = process.argv.includes('--verbose');
40
+ const verbose = process.argv.includes("--verbose");
39
41
  function vlog(...a) {
40
42
  if (!verbose) return;
41
43
  const ts = new Date().toISOString();
42
- process.stderr.write(`[${ts}] barn: ${a.join(' ')}\n`);
44
+ process.stderr.write(`[${ts}] barn: ${a.join(" ")}\n`);
43
45
  }
44
46
  export { vlog, verbose };
45
47
 
46
48
  const commands = {
47
- 'detect-sprints': 'detect-sprints.js',
48
- 'generate-manifest': 'generate-manifest.js',
49
- 'build-pdf': 'build-pdf.js',
49
+ "detect-sprints": "detect-sprints.js",
50
+ "generate-manifest": "generate-manifest.js",
51
+ "build-pdf": "build-pdf.js",
50
52
  };
51
53
 
52
- vlog('startup', `command=${command || '(none)'}`, `cwd=${process.cwd()}`);
54
+ vlog("startup", `command=${command || "(none)"}`, `cwd=${process.cwd()}`);
53
55
 
54
- if (!command || command === 'help' || command === '--help' || command === '-h') {
56
+ if (
57
+ !command ||
58
+ command === "help" ||
59
+ command === "--help" ||
60
+ command === "-h"
61
+ ) {
55
62
  console.log(`barn — open tools for structured research
56
63
 
57
64
  Usage:
@@ -81,16 +88,16 @@ https://github.com/grainulation/barn`);
81
88
  }
82
89
 
83
90
  // ── serve command (lib/server.js) ──
84
- if (command === 'serve') {
85
- const serverPath = join(LIB_DIR, 'server.js');
86
- const child = fork(serverPath, args.slice(1), { stdio: 'inherit' });
87
- child.on('exit', (code) => process.exit(code ?? 0));
88
- process.on('SIGTERM', () => child.kill('SIGTERM'));
89
- process.on('SIGINT', () => child.kill('SIGINT'));
91
+ if (command === "serve") {
92
+ const serverPath = join(LIB_DIR, "server.js");
93
+ const child = fork(serverPath, args.slice(1), { stdio: "inherit" });
94
+ child.on("exit", (code) => process.exit(code ?? 0));
95
+ process.on("SIGTERM", () => child.kill("SIGTERM"));
96
+ process.on("SIGINT", () => child.kill("SIGINT"));
90
97
  } else if (commands[command]) {
91
98
  const toolPath = join(TOOLS_DIR, commands[command]);
92
- const child = fork(toolPath, args.slice(1), { stdio: 'inherit' });
93
- child.on('exit', (code) => process.exit(code ?? 0));
99
+ const child = fork(toolPath, args.slice(1), { stdio: "inherit" });
100
+ child.on("exit", (code) => process.exit(code ?? 0));
94
101
  } else {
95
102
  console.error(`barn: unknown command: ${command}`);
96
103
  console.error(`Run "barn help" for available commands.`);
package/lib/index.js CHANGED
@@ -8,12 +8,14 @@
8
8
  * generateManifest(opts) — build wheat-manifest.json topic map (re-export)
9
9
  */
10
10
 
11
- import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';
12
- import { join, dirname } from 'node:path';
13
- import { fileURLToPath } from 'node:url';
11
+ import { readFileSync, existsSync, readdirSync, statSync } from "node:fs";
12
+ import { join, dirname } from "node:path";
13
+ import { fileURLToPath } from "node:url";
14
14
 
15
15
  const __dirname = dirname(fileURLToPath(import.meta.url));
16
- const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
16
+ const pkg = JSON.parse(
17
+ readFileSync(join(__dirname, "..", "package.json"), "utf8"),
18
+ );
17
19
 
18
20
  export const name = pkg.name;
19
21
  export const version = pkg.version;
@@ -30,64 +32,78 @@ export function loadTemplates(templatesDir) {
30
32
  if (!existsSync(templatesDir)) return templates;
31
33
 
32
34
  for (const file of readdirSync(templatesDir)) {
33
- if (!file.endsWith('.html')) continue;
35
+ if (!file.endsWith(".html")) continue;
34
36
  const filePath = join(templatesDir, file);
35
- const content = readFileSync(filePath, 'utf8');
36
- const tplName = file.replace('.html', '');
37
+ const content = readFileSync(filePath, "utf8");
38
+ const tplName = file.replace(".html", "");
37
39
 
38
40
  // Extract placeholders
39
41
  const placeholders = [...new Set(content.match(/\{\{[A-Z_]+\}\}/g) || [])];
40
42
 
41
43
  // Extract description from first comment
42
44
  const commentMatch = content.match(/<!--\s*(.*?)\s*-->/);
43
- let description = commentMatch ? commentMatch[1] : '';
45
+ let description = commentMatch ? commentMatch[1] : "";
44
46
 
45
47
  // Count lines and size
46
- const lines = content.split('\n').length;
48
+ const lines = content.split("\n").length;
47
49
  const size = statSync(filePath).size;
48
50
 
49
51
  // Detect features
50
52
  const features = [];
51
- if (content.includes('scroll-snap')) features.push('scroll-snap');
52
- if (content.includes('@media')) features.push('responsive');
53
- if (content.includes('var(--')) features.push('css-variables');
54
- if (content.includes('<table')) features.push('tables');
55
- if (content.includes('.card')) features.push('cards');
56
- if (content.includes('.slide')) features.push('slides');
53
+ if (content.includes("scroll-snap")) features.push("scroll-snap");
54
+ if (content.includes("@media")) features.push("responsive");
55
+ if (content.includes("var(--")) features.push("css-variables");
56
+ if (content.includes("<table")) features.push("tables");
57
+ if (content.includes(".card")) features.push("cards");
58
+ if (content.includes(".slide")) features.push("slides");
57
59
 
58
60
  // Merge optional template.json metadata
59
- const metaPath = join(templatesDir, tplName + '.json');
61
+ const metaPath = join(templatesDir, tplName + ".json");
60
62
  let title = tplName;
61
63
  let tags = [];
62
- let author = '';
63
- let tplVersion = '';
64
+ let author = "";
65
+ let tplVersion = "";
64
66
  let exportPresets = [];
65
67
  let seedPacks = [];
66
68
  let scaffoldConfig = null;
67
69
  if (existsSync(metaPath)) {
68
70
  try {
69
- const meta = JSON.parse(readFileSync(metaPath, 'utf8'));
71
+ const meta = JSON.parse(readFileSync(metaPath, "utf8"));
70
72
  if (meta.title) title = meta.title;
71
73
  if (meta.description) description = meta.description;
72
74
  if (Array.isArray(meta.tags)) tags = meta.tags;
73
75
  if (meta.author) author = meta.author;
74
76
  if (meta.version) tplVersion = meta.version;
75
- if (Array.isArray(meta.exportPresets)) exportPresets = meta.exportPresets;
77
+ if (Array.isArray(meta.exportPresets))
78
+ exportPresets = meta.exportPresets;
76
79
  if (Array.isArray(meta.seedPacks)) seedPacks = meta.seedPacks;
77
- if (meta.scaffoldConfig && typeof meta.scaffoldConfig === 'object') scaffoldConfig = meta.scaffoldConfig;
80
+ if (meta.scaffoldConfig && typeof meta.scaffoldConfig === "object")
81
+ scaffoldConfig = meta.scaffoldConfig;
78
82
  } catch {
79
83
  // skip malformed sidecar
80
84
  }
81
85
  }
82
86
 
83
87
  templates.push({
84
- name: tplName, file, title, placeholders, description, lines, size,
85
- features, tags, author, version: tplVersion, exportPresets, seedPacks, scaffoldConfig,
88
+ name: tplName,
89
+ file,
90
+ title,
91
+ placeholders,
92
+ description,
93
+ lines,
94
+ size,
95
+ features,
96
+ tags,
97
+ author,
98
+ version: tplVersion,
99
+ exportPresets,
100
+ seedPacks,
101
+ scaffoldConfig,
86
102
  });
87
103
  }
88
104
  return templates;
89
105
  }
90
106
 
91
107
  // Re-export tools
92
- export { detectSprints } from '../tools/detect-sprints.js';
93
- export { generateManifest } from '../tools/generate-manifest.js';
108
+ export { detectSprints } from "../tools/detect-sprints.js";
109
+ export { generateManifest } from "../tools/generate-manifest.js";