@grainulation/mill 1.0.0 → 1.0.2
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 +101 -0
- package/README.md +90 -42
- package/bin/mill.js +233 -67
- package/lib/exporters/csv.js +35 -30
- package/lib/exporters/json-ld.js +19 -13
- package/lib/exporters/markdown.js +83 -44
- package/lib/exporters/pdf.js +15 -15
- package/lib/formats/bibtex.mjs +83 -0
- package/lib/formats/{changelog.js → changelog.mjs} +27 -26
- package/lib/formats/confluence-adf.mjs +312 -0
- package/lib/formats/{csv.js → csv.mjs} +41 -37
- package/lib/formats/{dot.js → dot.mjs} +45 -34
- package/lib/formats/{evidence-matrix.js → evidence-matrix.mjs} +17 -16
- package/lib/formats/executive-summary.mjs +178 -0
- package/lib/formats/github-issues.mjs +96 -0
- package/lib/formats/{graphml.js → graphml.mjs} +45 -32
- package/lib/formats/html-report.mjs +228 -0
- package/lib/formats/{jira-csv.js → jira-csv.mjs} +30 -29
- package/lib/formats/{json-ld.js → json-ld.mjs} +6 -6
- package/lib/formats/{markdown.js → markdown.mjs} +53 -36
- package/lib/formats/{ndjson.js → ndjson.mjs} +6 -6
- package/lib/formats/{obsidian.js → obsidian.mjs} +43 -35
- package/lib/formats/{opml.js → opml.mjs} +38 -28
- package/lib/formats/ris.mjs +76 -0
- package/lib/formats/{rss.js → rss.mjs} +31 -28
- package/lib/formats/{sankey.js → sankey.mjs} +16 -15
- package/lib/formats/slide-deck.mjs +288 -0
- package/lib/formats/sql.mjs +120 -0
- package/lib/formats/{static-site.js → static-site.mjs} +64 -52
- package/lib/formats/{treemap.js → treemap.mjs} +16 -15
- package/lib/formats/typescript-defs.mjs +150 -0
- package/lib/formats/{yaml.js → yaml.mjs} +58 -40
- package/lib/formats.js +16 -16
- package/lib/index.js +5 -5
- package/lib/json-ld-common.js +37 -31
- package/lib/publishers/clipboard.js +21 -19
- package/lib/publishers/static.js +27 -12
- package/lib/serve-mcp.js +158 -83
- package/lib/server.js +252 -142
- package/package.json +6 -3
- package/lib/formats/bibtex.js +0 -76
- package/lib/formats/executive-summary.js +0 -130
- package/lib/formats/github-issues.js +0 -89
- package/lib/formats/html-report.js +0 -181
- package/lib/formats/ris.js +0 -70
- package/lib/formats/slide-deck.js +0 -200
- package/lib/formats/sql.js +0 -116
- package/lib/formats/typescript-defs.js +0 -147
package/lib/formats.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
const pdf = require(
|
|
4
|
-
const csv = require(
|
|
5
|
-
const markdown = require(
|
|
6
|
-
const jsonLd = require(
|
|
7
|
-
const static_ = require(
|
|
8
|
-
const clipboard = require(
|
|
3
|
+
const pdf = require("./exporters/pdf.js");
|
|
4
|
+
const csv = require("./exporters/csv.js");
|
|
5
|
+
const markdown = require("./exporters/markdown.js");
|
|
6
|
+
const jsonLd = require("./exporters/json-ld.js");
|
|
7
|
+
const static_ = require("./publishers/static.js");
|
|
8
|
+
const clipboard = require("./publishers/clipboard.js");
|
|
9
9
|
|
|
10
10
|
const EXPORTERS = {
|
|
11
11
|
pdf,
|
|
12
12
|
csv,
|
|
13
13
|
markdown,
|
|
14
|
-
|
|
14
|
+
"json-ld": jsonLd,
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
const PUBLISHERS = {
|
|
@@ -23,16 +23,16 @@ const PUBLISHERS = {
|
|
|
23
23
|
* Detect the likely format of an input file by extension.
|
|
24
24
|
*/
|
|
25
25
|
function detectFormat(filePath) {
|
|
26
|
-
const ext = filePath.split(
|
|
26
|
+
const ext = filePath.split(".").pop().toLowerCase();
|
|
27
27
|
const map = {
|
|
28
|
-
html:
|
|
29
|
-
htm:
|
|
30
|
-
md:
|
|
31
|
-
json:
|
|
32
|
-
csv:
|
|
33
|
-
jsonld:
|
|
28
|
+
html: "html",
|
|
29
|
+
htm: "html",
|
|
30
|
+
md: "markdown",
|
|
31
|
+
json: "json",
|
|
32
|
+
csv: "csv",
|
|
33
|
+
jsonld: "json-ld",
|
|
34
34
|
};
|
|
35
|
-
return map[ext] ||
|
|
35
|
+
return map[ext] || "unknown";
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
function getExporter(name) {
|
package/lib/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
const formats = require(
|
|
3
|
+
const formats = require("./formats.js");
|
|
4
4
|
|
|
5
|
-
const name =
|
|
6
|
-
const version = require(
|
|
7
|
-
const description =
|
|
5
|
+
const name = "mill";
|
|
6
|
+
const version = require("../package.json").version;
|
|
7
|
+
const description = "Turn wheat sprint artifacts into shareable formats";
|
|
8
8
|
|
|
9
9
|
module.exports = {
|
|
10
10
|
name,
|
package/lib/json-ld-common.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* json-ld-common.js — Shared JSON-LD vocabulary for mill
|
|
@@ -11,24 +11,25 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
const CONTEXT = {
|
|
14
|
-
|
|
15
|
-
wheat:
|
|
16
|
-
claim:
|
|
17
|
-
confidence:
|
|
18
|
-
evidenceTier:
|
|
19
|
-
claimType:
|
|
20
|
-
sprintId:
|
|
14
|
+
"@vocab": "https://schema.org/",
|
|
15
|
+
wheat: "https://grainulation.com/ns/wheat#",
|
|
16
|
+
claim: "wheat:Claim",
|
|
17
|
+
confidence: "wheat:confidence",
|
|
18
|
+
evidenceTier: "wheat:evidenceTier",
|
|
19
|
+
claimType: "wheat:claimType",
|
|
20
|
+
sprintId: "wheat:sprintId",
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
function claimToJsonLd(claim) {
|
|
24
|
-
const body = claim.content || claim.text ||
|
|
25
|
-
const evidenceTier =
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
const body = claim.content || claim.text || "";
|
|
25
|
+
const evidenceTier =
|
|
26
|
+
typeof claim.evidence === "string"
|
|
27
|
+
? claim.evidence
|
|
28
|
+
: (claim.evidence?.tier ?? claim.evidence_tier ?? null);
|
|
28
29
|
|
|
29
30
|
return {
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
"@type": "claim",
|
|
32
|
+
"@id": `wheat:claim/${claim.id}`,
|
|
32
33
|
identifier: claim.id,
|
|
33
34
|
claimType: claim.type,
|
|
34
35
|
text: body,
|
|
@@ -36,36 +37,41 @@ function claimToJsonLd(claim) {
|
|
|
36
37
|
confidence: claim.confidence ?? null,
|
|
37
38
|
evidenceTier,
|
|
38
39
|
dateCreated: claim.created || claim.timestamp || null,
|
|
39
|
-
...(claim.tags?.length ? { keywords: claim.tags.join(
|
|
40
|
+
...(claim.tags?.length ? { keywords: claim.tags.join(", ") } : {}),
|
|
40
41
|
...(claim.status ? { status: claim.status } : {}),
|
|
41
42
|
};
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
function buildReport(meta, claims, certificate) {
|
|
45
46
|
return {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
name: meta.sprint || meta.question ||
|
|
50
|
-
description: meta.question ||
|
|
51
|
-
dateCreated:
|
|
52
|
-
|
|
47
|
+
"@context": CONTEXT,
|
|
48
|
+
"@type": "Report",
|
|
49
|
+
"@id": `wheat:sprint/${meta.sprint || "unknown"}`,
|
|
50
|
+
name: meta.sprint || meta.question || "Wheat Sprint Report",
|
|
51
|
+
description: meta.question || "",
|
|
52
|
+
dateCreated:
|
|
53
|
+
(certificate && certificate.compiled_at) || new Date().toISOString(),
|
|
54
|
+
...(meta.audience
|
|
55
|
+
? { audience: { "@type": "Audience", name: meta.audience } }
|
|
56
|
+
: {}),
|
|
53
57
|
hasPart: {
|
|
54
|
-
|
|
58
|
+
"@type": "ItemList",
|
|
55
59
|
numberOfItems: claims.length,
|
|
56
60
|
itemListElement: claims.map((claim, i) => ({
|
|
57
|
-
|
|
61
|
+
"@type": "ListItem",
|
|
58
62
|
position: i + 1,
|
|
59
63
|
item: claimToJsonLd(claim),
|
|
60
64
|
})),
|
|
61
65
|
},
|
|
62
|
-
...(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
...(certificate && certificate.sha256
|
|
67
|
+
? {
|
|
68
|
+
identifier: {
|
|
69
|
+
"@type": "PropertyValue",
|
|
70
|
+
name: "certificate-sha256",
|
|
71
|
+
value: certificate.sha256,
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
: {}),
|
|
69
75
|
};
|
|
70
76
|
}
|
|
71
77
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
const fs = require(
|
|
4
|
-
const path = require(
|
|
5
|
-
const { execFile } = require(
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
const { execFile } = require("node:child_process");
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Copy formatted output to system clipboard.
|
|
@@ -11,12 +11,12 @@ const { execFile } = require('node:child_process');
|
|
|
11
11
|
|
|
12
12
|
function getClipboardCommand() {
|
|
13
13
|
switch (process.platform) {
|
|
14
|
-
case
|
|
15
|
-
return { cmd:
|
|
16
|
-
case
|
|
17
|
-
return { cmd:
|
|
18
|
-
case
|
|
19
|
-
return { cmd:
|
|
14
|
+
case "darwin":
|
|
15
|
+
return { cmd: "pbcopy", args: [] };
|
|
16
|
+
case "linux":
|
|
17
|
+
return { cmd: "xclip", args: ["-selection", "clipboard"] };
|
|
18
|
+
case "win32":
|
|
19
|
+
return { cmd: "clip", args: [] };
|
|
20
20
|
default:
|
|
21
21
|
return null;
|
|
22
22
|
}
|
|
@@ -46,25 +46,27 @@ async function publishClipboard(inputPath) {
|
|
|
46
46
|
let content;
|
|
47
47
|
if (stat.isDirectory()) {
|
|
48
48
|
// If directory, list the files
|
|
49
|
-
const files = fs.readdirSync(inputPath).filter((f) => !f.startsWith(
|
|
50
|
-
content = files
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
const files = fs.readdirSync(inputPath).filter((f) => !f.startsWith("."));
|
|
50
|
+
content = files
|
|
51
|
+
.map((f) => {
|
|
52
|
+
const full = path.join(inputPath, f);
|
|
53
|
+
return fs.readFileSync(full, "utf-8");
|
|
54
|
+
})
|
|
55
|
+
.join("\n\n---\n\n");
|
|
54
56
|
} else {
|
|
55
|
-
content = fs.readFileSync(inputPath,
|
|
57
|
+
content = fs.readFileSync(inputPath, "utf-8");
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
await copyToClipboard(content);
|
|
59
61
|
|
|
60
|
-
const size = Buffer.byteLength(content,
|
|
62
|
+
const size = Buffer.byteLength(content, "utf-8");
|
|
61
63
|
return {
|
|
62
64
|
message: `Copied to clipboard (${size} bytes)`,
|
|
63
65
|
};
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
module.exports = {
|
|
67
|
-
name:
|
|
68
|
-
description:
|
|
69
|
+
name: "clipboard",
|
|
70
|
+
description: "Copy formatted output to system clipboard",
|
|
69
71
|
publish: publishClipboard,
|
|
70
72
|
};
|
package/lib/publishers/static.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
const fs = require(
|
|
4
|
-
const path = require(
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const path = require("node:path");
|
|
5
5
|
|
|
6
|
-
function esc(s) {
|
|
6
|
+
function esc(s) {
|
|
7
|
+
return String(s || "")
|
|
8
|
+
.replace(/&/g, "&")
|
|
9
|
+
.replace(/</g, "<")
|
|
10
|
+
.replace(/>/g, ">")
|
|
11
|
+
.replace(/"/g, """)
|
|
12
|
+
.replace(/'/g, "'");
|
|
13
|
+
}
|
|
7
14
|
|
|
8
15
|
/**
|
|
9
16
|
* Generate a static site from sprint output directory.
|
|
@@ -93,7 +100,7 @@ function scanDir(dir, base) {
|
|
|
93
100
|
const stat = fs.statSync(full);
|
|
94
101
|
const real = fs.realpathSync(full);
|
|
95
102
|
if (!real.startsWith(fs.realpathSync(base))) continue;
|
|
96
|
-
if (stat.isFile() && !name.startsWith(
|
|
103
|
+
if (stat.isFile() && !name.startsWith(".")) {
|
|
97
104
|
const rel = path.relative(base, full);
|
|
98
105
|
entries.push({
|
|
99
106
|
name,
|
|
@@ -102,7 +109,11 @@ function scanDir(dir, base) {
|
|
|
102
109
|
ext: path.extname(name).slice(1).toLowerCase(),
|
|
103
110
|
modified: stat.mtime,
|
|
104
111
|
});
|
|
105
|
-
} else if (
|
|
112
|
+
} else if (
|
|
113
|
+
stat.isDirectory() &&
|
|
114
|
+
!name.startsWith(".") &&
|
|
115
|
+
name !== "_site"
|
|
116
|
+
) {
|
|
106
117
|
entries.push(...scanDir(full, base));
|
|
107
118
|
}
|
|
108
119
|
}
|
|
@@ -110,7 +121,7 @@ function scanDir(dir, base) {
|
|
|
110
121
|
}
|
|
111
122
|
|
|
112
123
|
async function publishStatic(inputDir, outputDir) {
|
|
113
|
-
const outDir = outputDir || path.join(inputDir,
|
|
124
|
+
const outDir = outputDir || path.join(inputDir, "_site");
|
|
114
125
|
if (!fs.existsSync(outDir)) {
|
|
115
126
|
fs.mkdirSync(outDir, { recursive: true });
|
|
116
127
|
}
|
|
@@ -130,14 +141,18 @@ async function publishStatic(inputDir, outputDir) {
|
|
|
130
141
|
|
|
131
142
|
// Build index
|
|
132
143
|
const sprintName = path.basename(path.resolve(inputDir));
|
|
133
|
-
const cards = entries
|
|
144
|
+
const cards = entries
|
|
145
|
+
.map(
|
|
146
|
+
(e) => `
|
|
134
147
|
<div class="card">
|
|
135
148
|
<a href="${esc(e.path)}">${esc(e.name)}</a>
|
|
136
149
|
<div class="meta">${e.ext.toUpperCase()} · ${formatBytes(e.size)}</div>
|
|
137
|
-
</div
|
|
150
|
+
</div>`,
|
|
151
|
+
)
|
|
152
|
+
.join("\n");
|
|
138
153
|
|
|
139
154
|
const html = TEMPLATE(`Sprint: ${sprintName}`, cards);
|
|
140
|
-
fs.writeFileSync(path.join(outDir,
|
|
155
|
+
fs.writeFileSync(path.join(outDir, "index.html"), html, "utf-8");
|
|
141
156
|
|
|
142
157
|
return {
|
|
143
158
|
outputPath: outDir,
|
|
@@ -146,7 +161,7 @@ async function publishStatic(inputDir, outputDir) {
|
|
|
146
161
|
}
|
|
147
162
|
|
|
148
163
|
module.exports = {
|
|
149
|
-
name:
|
|
150
|
-
description:
|
|
164
|
+
name: "static",
|
|
165
|
+
description: "Generate a static site from sprint outputs",
|
|
151
166
|
publish: publishStatic,
|
|
152
167
|
};
|